/* ==================================================================
   Base — tokens, reset, elements, links, helpers
   ================================================================== */

:root {
  /* --- type --- */
  --font-display: 'Sud', Georgia, 'Times New Roman', serif;
  --font-body: 'Overpass', system-ui, -apple-system, sans-serif;
  --font-runes: 'Bazaar Runes', var(--font-display);
  --font-numbers: 'Bazaar Numbers', var(--font-body);

  --measure: 68ch;
  --leading: 1.6;
  --leading-tight: 1.08;

  /* --- scale (fluid) --- */
  /* Every size on the site comes from here. A page that wants bigger text
     raises the token, so the whole site moves with it; a page sheet that
     writes its own number has quietly left the scale behind and will not
     follow. The few exceptions are named where they sit, with the reason.

     Set generously: this is a game site read at a distance on big screens. */
  --size-body: 1.1875rem;
  --size-lead: 1.45rem; /* large body: intros, showcase + card copy */
  --size-display: clamp(3rem, 1.4rem + 7.5vw, 6.5rem); /* page-opening names */
  --size-h1: clamp(3rem, 1.7rem + 6vw, 5.5rem);
  --size-h2: clamp(2.1rem, 1.4rem + 2.8vw, 3.3rem);
  --size-h3: clamp(1.5rem, 1.2rem + 1.1vw, 1.9rem);
  --size-h4: 1.3rem; /* the step below h3, inside long prose */
  --size-small: 1.0625rem;
  --size-eyebrow: 1.0625rem;
  --size-ui: 1.0625rem; /* chrome: nav chips, pills, buttons in the bar */

  /* --- space --- */
  --space-1: 0.5rem;
  --space-2: 1rem;
  --space-3: 1.75rem;
  --space-4: 3rem;
  --space-5: 5rem;
  --flow: 1.4rem;

  /* --- shape & motion --- */
  --radius: 10px;
  --page-max: 72rem;
  --header-h: 7rem;
  --ease: cubic-bezier(0.2, 0.65, 0.3, 1);
  --transition: 160ms var(--ease);

  /* --- brand palette (raw) --- */
  --gold-400: #ffb454;
  --gold-500: #ff9c1c;
  --gold-600: #e07d10;
  --ember: #f85d12;
  --legendary: #ff395a;
  --diamond: #abf2f3;

  --night-950: #14110c;
  --night-900: #1b1610;
  --night-850: #241d14;
  --night-700: #382d1f;

  --parchment-100: #f5ecdc;
  --parchment-300: #d7c5a6;
  --parchment-500: #a5977e;

  /* Legacy chrome palette, copied from the old site's navbar and banners. */
  --brown-475: #443027;
  --tan-500: #e4b181;
  --tan-700: #f0cead;

  /* --- semantic (dark theme) --- */
  color-scheme: dark;
  --color-bg: var(--night-950);
  --color-surface: var(--night-900);
  --color-elevated: var(--night-850);
  --color-text: var(--parchment-100);
  --color-muted: var(--parchment-500);
  --color-rule: var(--night-700);
  --color-accent: var(--gold-500);
  --color-accent-strong: var(--gold-400);
  --color-on-accent: #2a1c07;
}

/* Sud carries the headings everywhere it can, which is every Latin locale the
   site plans to serve but one: it has no dotless i (U+0131), so Turkish would
   lose a letter that turns up in almost every other word. Fraunces has it and
   the rest of the alphabet, so Turkish takes Fraunces for the whole page.

   The swap has to happen per locale, not per glyph. Listing both faces on one
   stack looks like it would cover this, but the browser falls back a
   character at a time: 'ı' would come out of a high-contrast serif with a
   geometric sans on either side of it, inside the same word.

   Chinese and Korean are a different problem -- no face here has their
   scripts at all -- and want a family of their own when they land. */
:root:lang(tr) {
  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
}

/* The header is a two-row bar on desktop and a single collapsed bar on
   narrow screens; everything offset by it shares this value. */
@media (max-width: 64rem) {
  :root {
    --header-h: 3.5rem;
  }
}

/* --- base --- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  font-size: 100%;
  scroll-behavior: smooth;
  /* Decoration hangs off the edge of the page on purpose, but must not drag
     a horizontal scrollbar with it.

     `clip` and not `hidden`: hidden makes this a scroll container and the
     sticky header stops sticking. On the root and not the body, since
     overflow on the body only reaches the viewport while the root's own is
     visible. Anything genuinely too wide -- the standings table -- scrolls
     inside its own box instead. */
  overflow-x: clip;
}

body {
  margin: 0;
  min-height: 100vh;
  /* A warm, lantern-lit atmosphere: gold from above, embers from below,
     settling into the night. Keeps the flat pages from feeling cold. */
  background:
    radial-gradient(
      130% 90% at 50% -10%,
      color-mix(in srgb, var(--gold-500) 9%, transparent),
      transparent 55%
    ),
    radial-gradient(
      120% 70% at 50% 112%,
      color-mix(in srgb, var(--ember) 7%, transparent),
      transparent 55%
    ),
    var(--color-bg);
  background-attachment: fixed;
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--size-body);
  line-height: var(--leading);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* --- headings & flow --- */
h1,
h2,
h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: var(--leading-tight);
  text-wrap: balance;
}

h1 {
  font-size: var(--size-h1);
  letter-spacing: -0.015em;
}

h2 {
  font-size: var(--size-h2);
  letter-spacing: -0.01em;
}

h3 {
  font-size: var(--size-h3);
}

p {
  margin: 0 0 var(--flow);
  text-wrap: pretty;
}

/* --- links --- */
a {
  color: var(--color-accent);
  text-decoration-line: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--color-accent) 45%, transparent);
  transition:
    color var(--transition),
    text-decoration-color var(--transition);
}

a:hover {
  color: var(--color-accent-strong);
  text-decoration-color: currentColor;
}

a:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

/* --- brand + numeric type helpers --- */
/* Illegible by design: whatever this sets is decoration, and its meaning has
   to be carried by something a reader can actually read. Always aria-hidden. */
.runes {
  font-family: var(--font-runes);
  font-weight: 400;
}

/* The gold diamond that parts one section from the next -- the same motif the
   arches in the bazaar art are trimmed with. Cut from the rune face, whose
   '*' is a drawn lozenge, narrower and finer than a rotated square. Page
   sheets set the spacing around it and nothing else. */
.mark {
  display: block;
  margin-inline: auto;
  color: var(--color-accent);
  font-family: var(--font-runes);
  font-size: 1.4rem;
  line-height: 1;
  text-align: center;
  text-shadow: 0 0 12px color-mix(in srgb, var(--color-accent) 55%, transparent);
}

/* In the content layer rather than the markup: the spans that carry this are
   empty and aria-hidden, and a punctuation character sitting in the DOM is a
   thing that gets read out, selected and copied for no reason. */
.mark::before {
  content: '*';
}

.numeric {
  font-family: var(--font-numbers);
  font-variant-numeric: tabular-nums;
}

::selection {
  background: color-mix(in srgb, var(--color-accent) 25%, transparent);
}

/* --- layout container --- */
.wrap {
  width: min(var(--page-max), 100% - 2.5rem);
  margin-inline: auto;
}

/* The way past the header's links. Out of the way until it is tabbed to,
   then it drops into the top-left corner as a plain, solid chip -- it has to
   be legible over whatever art the page opens with, so it brings its own
   background rather than trusting the one behind it. */
.skip {
  position: fixed;
  top: var(--space-1);
  left: var(--space-1);
  z-index: 100;
  padding: 0.7rem 1.25rem;
  border-radius: var(--radius);
  background: var(--color-accent);
  color: var(--color-on-accent);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(calc(-100% - var(--space-2)));
  transition: transform var(--transition);
}

.skip:focus-visible {
  transform: translateY(0);
  outline: 2px solid var(--color-text);
  outline-offset: 2px;
}

/* Focus moves here from the skip link, and the ring that would draw around
   the whole page says nothing a reader needs. */
main:focus {
  outline: none;
}

/* Visually hidden, but kept for the document outline and assistive tech. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- scroll reveal --- */

/* Sections lift and fade as they come into view -- the one bit of motion the
   legacy site had everywhere and this one had nowhere.

   Driven by the scroll position rather than a timer, so there is no observer
   and no script: `view()` ties the animation's progress to where the element
   sits in the viewport, which also means scrolling back up plays it in
   reverse instead of leaving a trail of things that already fired.

   Both gates matter. Without `@supports`, a browser that does not know
   `animation-timeline` would run this as an ordinary animation on load --
   or, worse, hold the `from` state and leave the page blank -- so where it
   is unsupported nothing is declared at all and sections simply are where
   they are. And `no-preference` rather than an override inside the
   reduced-motion block, so asking for less motion means the animation is
   never defined in the first place. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .reveal {
      animation: reveal linear both;
      animation-timeline: view();
      /* Against `entry` at both ends, so the distance travelled does not
         depend on how tall the section is: a full-height showcase and a
         two-line banner resolve over the same stretch of scrolling. */
      animation-range: entry 15% entry 70%;
    }
  }
}

@keyframes reveal {
  from {
    opacity: 0;
    transform: translateY(1.25rem);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* --- reduced motion --- */
/* Every transition runs off the --transition token, so zeroing it here halts
   all motion in one place -- no per-rule overrides, no keyframes to disable. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --transition: 0s;
    scroll-behavior: auto;
  }
}

/* ==================================================================
   Buttons
   ================================================================== */

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);

  &.center {
    justify-content: center;
  }
}

.btn {
  display: inline-flex;
  align-items: center;
  padding: 0.7rem 1.5rem;
  border-radius: var(--radius);
  font-weight: 600;
  text-decoration: none;
  transition:
    box-shadow var(--transition),
    border-color var(--transition),
    transform var(--transition),
    color var(--transition);

  &:active {
    transform: translateY(1px);
  }

  /* Tactile gold CTA: a lit gradient, a top gloss, and a warm glow. */
  &.primary {
    background: linear-gradient(180deg, var(--gold-400), var(--gold-600));
    border: 1px solid color-mix(in srgb, var(--gold-600) 65%, #000);
    color: var(--color-on-accent);
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, #fff 45%, transparent),
      0 2px 10px color-mix(in srgb, var(--gold-500) 28%, transparent);
  }

  &.primary:hover {
    background: linear-gradient(180deg, var(--gold-400), var(--gold-500));
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, #fff 55%, transparent),
      0 4px 20px color-mix(in srgb, var(--gold-500) 45%, transparent);
  }

  &.ghost {
    border: 1px solid var(--color-rule);
    color: var(--color-text);
  }

  &.ghost:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
    background: color-mix(in srgb, var(--gold-500) 8%, transparent);
  }
}

/* ==================================================================
   Spine stage
   ================================================================== */

/* An animated character (Spine WebGL) with an optional skin switcher below.
   The canvas fades in once its first frame paints; each thumbnail swaps the
   skin. Page-specific sizing (aspect ratio, shadow) lives in the page sheet. */
.spine-stage {
  display: grid;
  justify-items: center;
  gap: var(--space-3);

  /* The layout box every stage is measured against, poster or not. Where
     there is a poster it also gives the still and the canvas one box to
     share, so switching between them never reflows. Page sheets size this,
     never the canvas -- the canvas is deliberately bigger than it. */
  .frame {
    position: relative;
    width: 100%;
  }

  .frame .poster {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }

  /* The canvas is drawn larger than the frame it sits in, so a composition
     that runs past the portrait box spills into the gutter instead of being
     sliced off at the edge. The frame stays the layout box, and stays what
     every framing number in data/skins is measured against -- this only adds
     room to draw in. The controller reads --bleed back out to know how much
     of its buffer is spill (see scripts/spine-stage), so this one declaration
     is the whole setting. Nothing between here and the page clips, and the
     canvas takes no pointer events, so spilled art cannot cover a link. */
  .frame canvas {
    --bleed: 0.25;
    position: absolute;
    inset: calc(var(--bleed) * -100%);
    width: calc(100% + var(--bleed) * 200%);
    height: calc(100% + var(--bleed) * 200%);
    pointer-events: none;
  }

  .poster {
    object-fit: contain;
    border-radius: var(--radius);
  }

  .poster[hidden] {
    display: none;
  }

  canvas {
    display: block;
    width: 100%;
    opacity: 0;
    transition: opacity 0.5s var(--ease);
  }

  canvas.ready {
    opacity: 1;
  }

  .skins {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-1);
  }

  /* Each option wears the legacy frame set: a plate under the portrait and
     a rim over it — bronze at rest, gold when chosen (swapped off
     aria-pressed). Unselected options sit dimmed, as the old site had them. */
  .skin {
    display: grid;
    width: 4.5rem;
    height: 4.5rem;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: pointer;
    opacity: 0.5;
    transition:
      opacity var(--transition),
      transform var(--transition);

    img {
      grid-area: 1 / 1;
      display: block;
      width: 100%;
      height: 100%;
    }

    /* The tile is square because the frame around it is, not because the
       picture in it happens to be: skin thumbnails are square already, but
       the static-portrait option shows the hero's full portrait, which is
       taller than it is wide. So the ratio is stated here and the art fills
       it, anchored at the top so a crop loses feet rather than a face. */
    .thumb {
      width: 84%;
      height: auto;
      aspect-ratio: 1;
      place-self: center;
      object-fit: cover;
      object-position: top;
    }

    .rim {
      transition: opacity var(--transition);
    }

    .rim.selected {
      opacity: 0;
    }

    &:hover {
      opacity: 1;
      transform: translateY(-2px);
    }

    &[aria-pressed='true'] {
      opacity: 1;
    }

    &[aria-pressed='true'] .rim.selected {
      opacity: 1;
    }

    &[aria-pressed='true'] .rim.deselected {
      opacity: 0;
    }

    &:focus-visible {
      outline: 2px solid var(--color-accent);
      outline-offset: 2px;
    }
  }
}

/* ==================================================================
   Plaque
   ================================================================== */

/* A framed parchment 'notice board' — the site's warm content container:
   a gold-tinted edge, an inset hairline, padding, and a soft lift. */
.plaque {
  padding: clamp(var(--space-4), 5vw, var(--space-5));
  border: 1px solid color-mix(in srgb, var(--parchment-300) 32%, transparent);
  border-radius: var(--radius);
  background:
    radial-gradient(
      90% 60% at 50% 0%,
      color-mix(in srgb, var(--gold-500) 7%, transparent),
      transparent 70%
    ),
    color-mix(in srgb, var(--night-900) 62%, transparent);
  box-shadow:
    inset 0 0 0 4px color-mix(in srgb, var(--night-950) 45%, transparent),
    0 20px 50px color-mix(in srgb, var(--night-950) 40%, transparent);
}

/* ==================================================================
   Header
   ================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--header-h);
  /* The legacy smoky navbar art, darkened for text legibility. */
  background:
    linear-gradient(
      180deg,
      color-mix(in srgb, var(--night-950) 34%, transparent),
      color-mix(in srgb, var(--night-950) 72%, transparent)
    ),
    url(/images/nav-smoke.webp) center / cover no-repeat,
    var(--color-bg);

  /* A torn brown pagebreak hangs off the bottom edge, a legacy signature. */
  &::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 12px;
    background: url(/images/pagebreak.webp) center top / 100% 100% no-repeat;
    pointer-events: none;
  }

  /* Legacy anatomy: the logo sits left of a vertical rule, and two stacked
     rows fill the rest -- a utility row above, the main links below. */
  .inner {
    display: flex;
    align-items: stretch;
    height: 100%;
  }

  .brand {
    display: flex;
    align-items: center;
    margin-inline: 1.25rem;
    transition: transform var(--transition);
  }

  .brand:hover {
    transform: scale(1.06);
  }

  .brand img {
    display: block;
    height: 4.25rem;
    width: auto;
  }

  .rows {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    border-left: 1px solid var(--brown-475);
  }

  .row {
    display: flex;
    align-items: center;
    height: 3.5rem;
    padding-inline: 0.5rem 1.5rem;
  }

  .row.main {
    border-top: 1px solid var(--brown-475);
  }

  /* Chip links, straight from the legacy bar: tan at rest, a brown chip
     with gold text under the pointer or on the current page. */
  .quick,
  .links {
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .quick a,
  .links a,
  .locales summary {
    display: flex;
    align-items: center;
    height: 2.25rem;
    padding-inline: 0.95rem;
    border-radius: var(--radius);
    color: var(--tan-500);
    font-size: var(--size-ui);
    text-decoration: none;
    white-space: nowrap;
    transition:
      background-color var(--transition),
      color var(--transition);
  }

  .quick a:hover,
  .quick a.is-active,
  .links a:hover,
  .links a.is-active,
  .locales summary:hover {
    background-color: var(--brown-475);
    color: var(--color-accent);
  }

  .utility {
    justify-content: flex-end;
    gap: 0.4rem;
  }

  /* The account pair, outlined like the legacy Log In / Sign Up. */
  .pill {
    display: flex;
    align-items: center;
    height: 2.25rem;
    padding-inline: 1.25rem;
    border-radius: var(--radius);
    font-size: var(--size-ui);
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
    transition:
      background-color var(--transition),
      color var(--transition);
  }

  .pill.login {
    border: 1px solid var(--tan-500);
    color: var(--tan-500);
  }

  .pill.login:hover {
    background-color: var(--tan-500);
    color: var(--night-950);
  }

  .pill.signup {
    border: 1px solid var(--color-accent);
    color: var(--color-accent);
  }

  .pill.signup:hover {
    background-color: var(--color-accent);
    color: var(--color-on-accent);
  }

  /* The language dropdown holds the bar's right edge: a plain <details>,
     its panel dropping below the row, so it costs no JavaScript. */
  .locales {
    position: relative;
  }

  .locales summary {
    gap: 0.5rem;
    cursor: pointer;
    list-style: none;
  }

  .locales summary::-webkit-details-marker {
    display: none;
  }

  .locales .chevron {
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 6px solid currentColor;
    transition: transform var(--transition);
  }

  .locales[open] summary {
    background-color: var(--brown-475);
    color: var(--color-accent);
  }

  .locales[open] .chevron {
    transform: rotate(180deg);
  }

  .locales ul {
    position: absolute;
    right: 0;
    top: calc(100% + 0.6rem);
    z-index: 60;
    min-width: max-content;
    margin: 0;
    padding: 0.4rem;
    list-style: none;
    background: var(--color-elevated);
    border: 1px solid var(--brown-475);
    border-radius: var(--radius);
    box-shadow: 0 18px 40px color-mix(in srgb, var(--night-950) 70%, transparent);
  }

  .locales ul a {
    display: flex;
    padding: 0.5rem 1.1rem;
    border-radius: 8px;
    color: var(--tan-500);
    text-decoration: none;
    white-space: nowrap;
    transition:
      background-color var(--transition),
      color var(--transition);
  }

  .locales ul a:hover {
    background-color: var(--brown-475);
    color: var(--color-accent);
  }

  .locales ul a.is-active {
    color: var(--color-accent);
  }

  .main .nav {
    min-width: 0;
  }

  .pills {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-left: var(--space-3);
  }

  /* The two solid pills the legacy bar ends its links with: gold to play,
     tan for the merch store. */
  .cta,
  .merch {
    display: inline-flex;
    align-items: center;
    height: 2.25rem;
    padding-inline: 1.25rem;
    border-radius: var(--radius);
    font-size: var(--size-ui);
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
    transition:
      background-color var(--transition),
      box-shadow var(--transition),
      color var(--transition);
  }

  .cta {
    background: linear-gradient(180deg, var(--gold-400), var(--gold-600));
    border: 1px solid color-mix(in srgb, var(--gold-600) 65%, #000);
    color: var(--color-on-accent);
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, #fff 40%, transparent),
      0 2px 8px color-mix(in srgb, var(--gold-500) 24%, transparent);
  }

  .cta:hover {
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, #fff 52%, transparent),
      0 4px 16px color-mix(in srgb, var(--gold-500) 42%, transparent);
  }

  .merch {
    background-color: var(--tan-500);
    border: 1px solid color-mix(in srgb, var(--tan-500) 65%, #000);
    color: var(--night-950);
  }

  .merch:hover {
    background-color: var(--color-accent);
    color: var(--color-on-accent);
  }

  .socials {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 0 0 0 auto;
    padding: 0;
    list-style: none;
  }

  .socials li {
    display: flex;
  }

  .socials a {
    display: flex;
    align-items: center;
    color: var(--tan-500);
    transition:
      color var(--transition),
      transform var(--transition);
  }

  /* The legacy icons grew a touch under the pointer; keep that. */
  .socials a:hover {
    color: var(--color-accent);
    transform: scale(1.15);
  }

  .socials svg {
    display: block;
    width: 24px;
    height: 24px;
    fill: currentColor;
  }

  /* Mobile: a hidden checkbox toggles the rows into a dropdown, no JS. */
  .toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
  }

  .burger {
    display: none;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    padding: 0.5rem;
    margin-right: 0.75rem;
    cursor: pointer;
  }

  .burger span {
    width: 24px;
    height: 2px;
    background: var(--color-text);
    border-radius: 2px;
  }

  .toggle:focus-visible + .burger {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
    border-radius: 4px;
  }

  /* Socials step aside first, like the legacy bar at mid widths. Eight nav
     chips at the UI size want about 656px, and 1280 is a common laptop
     width, so the socials have to give up their 214px before it or the last
     chip is clipped under the Play pill. */
  @media (max-width: 82rem) {
    .socials {
      display: none;
    }
  }

  @media (max-width: 64rem) {
    /* One slim bar: brand left, burger right; the rows drop into a panel,
       main links first and the utility row after (the legacy mobile order). */
    .inner {
      justify-content: space-between;
    }

    .brand img {
      height: 2.5rem;
    }

    .burger {
      display: inline-flex;
    }

    .rows {
      position: absolute;
      inset: var(--header-h) 0 auto 0;
      display: none;
      flex-direction: column-reverse;
      gap: var(--space-3);
      padding: var(--space-3) 1.25rem var(--space-4);
      border-left: 0;
      background: var(--color-surface);
      border-bottom: 0.5px solid var(--color-rule);
      max-height: calc(100vh - var(--header-h));
      overflow-y: auto;
    }

    .toggle:checked ~ .rows {
      display: flex;
    }

    .row {
      height: auto;
      padding: 0;
    }

    .row.main {
      border-top: 0;
      flex-direction: column;
      align-items: stretch;
      gap: var(--space-3);
    }

    .nav {
      width: 100%;
    }

    .links {
      flex-direction: column;
      align-items: stretch;
    }

    /* Full-width rows in the dropdown rather than chips in a bar, so they
       take the larger step -- easier to read, and easier to hit. */
    .links a {
      justify-content: center;
      height: auto;
      padding: 0.85rem 0;
      border-radius: 0;
      border-bottom: 0.5px solid var(--color-rule);
      font-size: var(--size-lead);
    }

    .links a:hover,
    .links a.is-active {
      background-color: transparent;
    }

    .pills {
      justify-content: center;
      margin-left: 0;
    }

    .utility {
      flex-wrap: wrap;
      justify-content: center;
      gap: 0.75rem;
    }

    .socials {
      display: flex;
      justify-content: center;
      margin-left: 0;
    }

    .socials svg {
      width: 30px;
      height: 30px;
    }

    /* The language panel unfolds in place inside the dropdown. */
    .locales ul {
      position: static;
      margin-top: 0.4rem;
      box-shadow: none;
    }
  }
}

/* ==================================================================
   Footer
   ================================================================== */

.site-footer {
  position: relative;
  margin-top: var(--space-5);
  background:
    radial-gradient(
      90% 130% at 50% 0%,
      color-mix(in srgb, var(--ember) 9%, transparent),
      transparent 55%
    ),
    linear-gradient(180deg, var(--night-850), var(--night-950));
  padding-block: var(--space-5) var(--space-4);
  color: var(--color-muted);

  /* The legacy molten rail, reused as the footer's glowing top edge. */
  &::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 18px;
    background: url(/images/footer-ember.webp) top center / 100% auto no-repeat;
    pointer-events: none;
  }

  .top {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: var(--space-4);
  }

  .logo img {
    display: block;
    height: 3.5rem;
    width: auto;
  }

  .follow {
    margin: var(--space-2) 0 var(--space-3);
    font-size: var(--size-lead);
  }

  .socials {
    display: flex;
    gap: 14px;
    margin: 0;
    padding: 0;
    list-style: none;

    a {
      display: inline-flex;
      color: var(--color-muted);
      transition: color var(--transition);
    }

    a:hover {
      color: var(--color-accent);
    }

    svg {
      width: 24px;
      height: 24px;
      fill: currentColor;
    }
  }

  .cols {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-3);
  }

  .col h2 {
    margin: 0 0 var(--space-2);
    font-family: var(--font-body);
    font-size: var(--size-eyebrow);
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--parchment-300);
  }

  .col ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .col li {
    margin-block: 0.5rem;
  }

  .col a,
  .legal a,
  .locales a {
    color: var(--color-muted);
    font-size: var(--size-small);
    text-decoration: none;
    transition: color var(--transition);
  }

  .col a:hover,
  .legal a:hover,
  .locales a:hover {
    color: var(--color-text);
  }

  .locales a.is-active {
    color: var(--color-text);
  }

  .bottom {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-3);
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 0.5px solid var(--color-rule);
  }

  .copyright {
    margin: 0;
    font-size: var(--size-small);
  }

  .legal,
  .locales {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--size-small);
  }

  @media (max-width: 48rem) {
    .top {
      grid-template-columns: 1fr;
      gap: var(--space-4);
    }

    .bottom {
      flex-direction: column;
      align-items: flex-start;
    }
  }
}

/* ==================================================================
   Lightbox
   ------------------------------------------------------------------
   The preview overlay shared by the fan kit and the media kit, and by the
   watch shelf's films. It lives here rather than in either page sheet
   because two pages use it; the pages contribute only their tiles.

   Nearly all of the behaviour is the browser's. `showModal()` puts the
   dialog in the top layer, so it sits above the sticky header without
   anything here naming a z-index, and renders ::backdrop for the page
   behind. What is left to style is the picture, the caption and four
   controls.
   ================================================================== */

.lightbox {
  /* A dialog is width-fit and centred by margin: auto by default, which
     would size the box to the picture and leave the arrows wherever that
     put them. This fills the viewport instead, and the picture centres
     inside it -- so a control sits in the same place for every asset,
     whether it is a 1500x500 banner or a square avatar. */
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  margin: 0;
  padding: var(--space-3);
  border: 0;
  background: transparent;
  color: var(--color-text);

  &::backdrop {
    background: rgb(10 8 5 / 0.88);
  }

  &:not([open]) {
    display: none;
  }

  .frame {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: center;
    justify-content: center;
    height: 100%;
    margin: 0;
  }

  .stage {
    display: flex;
    align-items: center;
    justify-content: center;
    /* Sized to the picture, not to the space a picture might have wanted:
       the caption belongs to the picture and has to follow it. Holding the
       leftover height instead centres a short picture in a tall box and
       strands its caption a long way underneath. */
    min-height: 0;
    width: 100%;
  }

  img {
    /* The intrinsic width and height are on the element, so the box holds
       the right shape while the full-size file is still arriving. */
    max-width: 100%;
    /* Measured off the viewport rather than the parent: the stage is
       shrink-to-fit now, and a percentage height against an auto-height
       parent resolves to nothing at all. The reserve is what the frame
       keeps around it -- the dialog's padding, the gap, and room for a
       caption that runs to two lines. Same shape as the iframe rule below.
       dvh, so a phone's collapsing address bar is accounted for. */
    max-height: calc(100dvh - 9rem);
    width: auto;
    height: auto;
    object-fit: contain;
    border-radius: var(--radius);
    box-shadow: 0 1.5rem 4rem rgb(0 0 0 / 0.6);
  }

  iframe {
    /* A player has no intrinsic size to contain; it takes the largest 16:9
       box that fits the stage in both directions. */
    width: min(100%, calc((100dvh - 12rem) * 16 / 9));
    aspect-ratio: 16 / 9;
    max-height: 100%;
    border: 0;
    border-radius: var(--radius);
    background: #000;
    box-shadow: 0 1.5rem 4rem rgb(0 0 0 / 0.6);
  }

  .caption {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    align-items: baseline;
    justify-content: center;
    text-align: center;
  }

  .name {
    font-family: var(--font-display);
    font-size: var(--size-h3);
    line-height: var(--leading-tight);
  }

  .count {
    font-size: var(--size-small);
    color: var(--color-muted);
  }

  /* --- the controls --- */

  .close,
  .step {
    position: fixed;
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    padding: 0;
    border: 0.5px solid var(--color-rule);
    border-radius: 50%;
    background: rgb(36 29 20 / 0.85);
    color: var(--color-text);
    cursor: pointer;
    transition:
      border-color var(--transition),
      background var(--transition);

    &:hover {
      border-color: var(--color-accent);
      background: var(--color-elevated);
    }

    svg {
      width: 1.4rem;
      height: 1.4rem;
    }
  }

  .close {
    top: var(--space-3);
    right: var(--space-3);
  }

  .step {
    top: 50%;
    translate: 0 -50%;
  }

  .prev {
    left: var(--space-3);
    rotate: 180deg;
  }

  .next {
    right: var(--space-3);
  }

  /* A shelf of one has nowhere to step. The buttons go rather than grey out:
     a control that cannot be used is still a tab stop. */
  &.is-alone .step {
    display: none;
  }

  @media (max-width: 48rem) {
    padding: var(--space-2);

    /* Arrows either side of a picture that is already the width of the
       screen would sit on top of it. They go under it instead. */
    .step {
      top: auto;
      bottom: var(--space-2);
      translate: none;
    }

    .prev {
      left: var(--space-2);
    }

    .next {
      right: var(--space-2);
    }

    .frame {
      padding-bottom: 3.5rem;
    }

    /* The arrows sit under the picture here and the frame keeps a row for
       them, so the ceiling comes down by that row as well. */
    img {
      max-height: calc(100dvh - 12.5rem);
    }
  }
}
