/* ============================================================================
   worlds.css — the three illustrated "world" themes
   ----------------------------------------------------------------------------
   Load AFTER theme.css. Every token is scoped to html[data-world="..."], which
   is set by the no-flash snippet in each page's <head> and by worlds.js.

   Three worlds:
     highland  sage/teal hill, amber accents   (default)
     dunes     warm sand + ink + amber
     island    bright green floating diorama

   Image paths are relative to THIS FILE (repo root), so they resolve correctly
   from any page depth without per-page rewriting.

   Palette notes — do not "simplify" these to plain --amber:
     text-on-cream amber is --amber-text #926311 (4.93:1); plain --amber #e8a838
     is 1.96:1 and fails. Focus rings use --focus-ring #a86f10 (4.00:1).
   ========================================================================= */

/* ── shared world tokens (overridden per world below) ───────────────────── */
html[data-world] {
  --w-accent: var(--amber);
  --w-accent-text: var(--amber-text);
  --w-band: var(--ink);
  --w-win-bg: rgba(250, 248, 244, 0.88);
  --w-win-radius: 16px;
  --w-win-border: 1px solid rgba(15, 27, 45, 0.14);
  --w-win-shadow: 0 30px 80px -20px rgba(15, 27, 45, 0.45);
  --w-rail-bg: rgba(250, 248, 244, 0.55);
  --w-panel-border: 3px solid var(--amber);
  --w-btn-radius: 8px;
  --w-cta-shadow: none;
  --w-scrim: rgba(250, 248, 244, 0.86);
  --w-scrim-showcase: rgba(250, 248, 244, 0.18);
}

html[data-world="highland"] {
  --w-image: url("worlds/world-highland.webp");
  --w-fallback: #b9cdd4;
  --w-band: #2c5750;
  --w-win-bg: rgba(244, 241, 235, 0.82);
  --w-win-radius: 20px;
  --w-win-border: 1px solid rgba(255, 255, 255, 0.55);
  --w-win-shadow: 0 36px 90px -24px rgba(12, 34, 40, 0.55);
  --w-rail-bg: rgba(255, 255, 255, 0.44);
  /* #3a7d7e is the slide palette's --teal. That token is defined inside the
     decks, not in theme.css, so it is written out literally here rather than
     referenced as var(--teal) — which would silently fall back on every page. */
  --w-panel-border: 3px solid #3a7d7e;
  --w-btn-radius: 999px;
  --w-scrim: rgba(247, 249, 249, 0.87);
  --w-scrim-showcase: rgba(233, 241, 243, 0.16);
}

html[data-world="dunes"] {
  --w-image: url("worlds/world-dunes.webp");
  --w-fallback: #f3e6cf;
  --w-band: var(--ink);
  --w-win-bg: rgba(250, 248, 244, 0.88);
  --w-win-radius: 16px;
  --w-win-border: 1px solid rgba(15, 27, 45, 0.14);
  --w-rail-bg: rgba(250, 248, 244, 0.58);
  --w-panel-border: 3px solid var(--amber);
  --w-btn-radius: 8px;
  --w-scrim: rgba(250, 248, 244, 0.88);
  --w-scrim-showcase: rgba(250, 246, 238, 0.2);
}

html[data-world="island"] {
  --w-image: url("worlds/world-island.webp");
  --w-fallback: #e7f0f4;
  --w-accent: #e8590c;
  --w-accent-text: #a13c05;
  --w-band: var(--ink);
  --w-win-bg: rgba(255, 255, 255, 0.94);
  --w-win-radius: 0px;
  --w-win-border: 2px solid var(--ink);
  --w-win-shadow: 6px 6px 0 0 rgba(15, 27, 45, 0.85);
  --w-rail-bg: rgba(255, 255, 255, 0.64);
  --w-panel-border: 4px solid #e8590c;
  --w-btn-radius: 0px;
  --w-cta-shadow: 3px 3px 0 0 var(--ink);
  --w-scrim: rgba(252, 253, 254, 0.88);
  --w-scrim-showcase: rgba(231, 240, 244, 0.14);
}

/* ── the world itself ───────────────────────────────────────────────────────
   Painted as the body background (the page canvas), with .world-scrim — a
   z-index:-1 fixed layer injected by worlds.js — floated above it so body text
   stays readable. Painting order guarantees the scrim sits above the canvas
   background and below all in-flow content, so no content needs a z-index. */
html[data-world] body {
  background: var(--w-fallback) var(--w-image) center top / cover no-repeat fixed;
}

.world-scrim {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--w-scrim);
}

/* On the landing page the content sits inside an opaque window, so the world
   is allowed to show through much more strongly. */
body.world-showcase .world-scrim { background: var(--w-scrim-showcase); }

/* ── world picker ──────────────────────────────────────────────────────────
   Injected by worlds.js. On the landing page it is appended into the right
   rail; everywhere else it renders as a fixed control in the corner. */
.wp {
  position: relative;
  font-family: var(--font-body, system-ui, sans-serif);
}
.wp--float {
  position: fixed;
  inset-inline-end: 1rem;
  inset-block-end: 1rem;
  z-index: 50;
}

.wp-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.28rem;
  width: 74px;
  padding: 0.6rem 0.25rem;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  border-radius: 10px;
  transition: background 0.18s cubic-bezier(0.4, 0, 0.2, 1),
              transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}
.wp-btn:hover { background: rgba(255, 255, 255, 0.72); transform: translateY(-2px); }
.wp-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.wp-btn svg { width: 25px; height: 25px; }
.wp-btn span {
  font-size: 0.63rem;
  line-height: 1.15;
  font-weight: 600;
  text-align: center;
}

/* the floating variant is a compact round button, not a rail tile */
.wp--float .wp-btn {
  width: 44px;
  height: 44px;
  padding: 0;
  justify-content: center;
  border-radius: 50%;
  background: var(--w-rail-bg);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: var(--w-win-border);
}
.wp--float .wp-btn span { display: none; }

.wp-panel {
  position: absolute;
  inset-block-end: calc(100% + 0.5rem);
  inset-inline-end: 0;
  display: flex;
  gap: 0.5rem;
  padding: 0.6rem;
  background: var(--w-win-bg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: var(--w-win-border);
  border-radius: var(--w-win-radius);
  box-shadow: var(--w-win-shadow);
  z-index: 55;
}
.wp-panel[hidden] { display: none; }

/* inside a vertical rail the panel opens to the side instead of above */
.rail--right .wp-panel {
  inset-block-end: auto;
  inset-inline-end: calc(100% + 0.5rem);
  top: 0;
}

.wp-swatch {
  width: 62px;
  height: 44px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: calc(var(--w-win-radius) / 2);
  cursor: pointer;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}
.wp-swatch:hover { transform: translateY(-2px); }
.wp-swatch:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.wp-swatch[aria-pressed="true"] { border-color: var(--w-accent); }

.wp-swatch--highland { background-image: url("worlds/world-highland.webp"); }
.wp-swatch--dunes    { background-image: url("worlds/world-dunes.webp"); }
.wp-swatch--island   { background-image: url("worlds/world-island.webp"); }

/* ── readable surfaces on themed content pages ─────────────────────────────
   Course index pages keep their own layout; they only need their large flat
   surfaces to stop being fully opaque cream so the world reads through. */
html[data-world] body:not(.world-showcase) .footer {
  background: color-mix(in srgb, var(--paper) 88%, transparent);
}

/* ── reduced motion ────────────────────────────────────────────────────────
   A fixed background attachment is a motion effect on scroll for some users,
   and every transition above is decorative. */
@media (prefers-reduced-motion: reduce) {
  html[data-world] body { background-attachment: scroll; }
  .wp-btn,
  .wp-swatch {
    transition-duration: 0.01ms !important;
  }
  .wp-btn:hover,
  .wp-swatch:hover { transform: none; }
}

/* ── mobile ────────────────────────────────────────────────────────────────
   A fixed cover background is expensive and janky on mobile Safari. */
@media (max-width: 768px) {
  html[data-world] body { background-attachment: scroll; }
}
