/* Tenshin Arts — marketing pages (home + games). Extracted from index.html so the
   home page and the games page share one stylesheet. Auth/app pages use app.css. */
  /* ── SLATE (2026-07-25) ────────────────────────────────────────────────────
     The warm ivory/coral system was replaced with a cool neutral + indigo one at
     Dr. Ray's pick, chosen from a five-way preview rather than argued about.

     The token NAMES changed with it, on purpose: they used to be `--coral` and
     `--teal`, and a token called coral that renders indigo is a trap for whoever
     reads this next. They are `--accent` / `--support` now, so the name says the
     JOB and the value says the hue.

     Measured on this paper, not assumed (WCAG AA needs 4.5 for body text):
       heading 16.2  ·  muted text 5.6  ·  links 6.9  ·  button label 6.9
     The bright pair (--accent / --support) stays display-only — large headings,
     fills, lamps, focus rings. Anything small or text-on-colour uses -deep. */
  :root{
    --paper:#F6F7F9;
    --paper-2:#ECEFF3;
    --paper-3:#F1F4F8;
    --ink:#171A21;
    --ink-soft:#5D6472;
    --accent:#5567E0;          /* display only */
    --support:#2A93A0;         /* display only */
    --warn:#B4741A;
    /* AA-contrast siblings: text-on-colour + small text on paper */
    --accent-deep:#3A49B8;     /* white 7.4:1 · paper 6.93 */
    --accent-lift:#93A0F5;     /* the ON-DARK sibling — ink-900 7.53:1 */
    --support-deep:#166B75;    /* white 6.5:1 · paper 6.1 */
    --line:rgba(23,26,33,.14);
    /* --- deepened tones for the living worlds --- */
    --ink-900:#12141A;
    --display:"Fraunces",Georgia,serif;
    --body:"Figtree",system-ui,sans-serif;
    --stage:1760px;   /* wide live stages use the whole monitor */
    --prose:1180px;   /* quieter narrative sections */
  }
  *{box-sizing:border-box}
  html{scroll-behavior:smooth}
  @media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
  body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--body);
    font-size:1.0625rem;line-height:1.65;-webkit-font-smoothing:antialiased;overflow-x:clip;
    /* THE UNIT SILHOUETTE — rounded top, near-square base: the shape reads as a
       thing STANDING on the floor, not a pill floating on it. Lifted straight
       off `.cab` so the hall and the page around it share one silhouette.
       ⚠ Deliberately NOT in :root — that block must stay byte-identical to
       app.css, and the auth/app pages do not carry this vocabulary. */
    --r-unit:14px 14px 4px 4px}
  a{color:var(--accent-deep)}
  ::selection{background:var(--accent);color:#fff}
  img{max-width:100%}

  /* full-bleed band + inner shells */
  .band{width:100%;position:relative}
  .shell{width:100%;max-width:var(--stage);margin:0 auto;
    padding-left:clamp(1.25rem,4vw,3.5rem);padding-right:clamp(1.25rem,4vw,3.5rem)}
  .shell.prose{max-width:var(--prose)}

  /* Section labels wear the cabinet's COIN SLOT (`.cab-coin .slot`) — the same
     mark, so a section header and a machine's coin line read as one system.
     `currentColor` on purpose: the dark realms band recolours .eyebrow to
     --accent-lift and the slot follows without a second rule. */
  .eyebrow{font-family:var(--body);font-weight:600;font-size:.76rem;letter-spacing:.18em;
    text-transform:uppercase;color:var(--support-deep);margin:0 0 1rem;
    display:flex;align-items:center;gap:.7rem}
  /* Solid, not the topper's .55 — `.cab-coin .slot` is a solid bar, and .55 of a
     mid-teal on paper disappears. The light BAR is lit (translucent); the coin
     SLOT is milled metal (solid). Two devices, two treatments, on purpose. */
  .eyebrow::before{content:"";width:22px;height:3px;border-radius:2px;
    background:currentColor;flex:none}
  :focus-visible{outline:3px solid var(--support);outline-offset:2px}

  /* ── THE UNIT (site-wide, 2026-07-26) ──────────────────────────────────────
     The hall shipped a machine vocabulary and then stopped at the card grid:
     every other surface on the page was pillowy 16–18px paper, so the page ran
     two design languages at once. These are not new devices — they are the
     cabinet's own `.cab` silhouette and `.cab-top::after` light bar, promoted
     to site level and applied to the surfaces the hall pass didn't reach.

     ★ The rule that makes it structural, not decorative: a UNIT is a surface
     you can act on or read a standing from. Prose does not get a light bar.

     Decorative only — `::before` carries no content and every unit's text
     contrast is unchanged from what was measured on 2026-07-25. */
  .unit,.pillar,.name-card,.way,.realm{border-radius:var(--r-unit);
    position:relative;overflow:hidden}
  .unit::before,.pillar::before,.name-card::before,.way::before,.realm::before{
    content:"";position:absolute;left:1.1rem;right:1.1rem;top:0;height:3px;
    border-radius:0 0 2px 2px;background:var(--acc,var(--accent));opacity:.55;
    pointer-events:none}
  /* on the dark realms band the bright --accent goes muddy against --ink-900 */
  .realm::before{background:var(--accent-lift)}

  /* --- the broadcast/data voice: tracked small-caps figtree, tabular --- */
  .mono{font-family:var(--body);font-weight:700;letter-spacing:.14em;text-transform:uppercase;
    font-variant-numeric:tabular-nums;font-size:.72rem}

  .btn{display:inline-block;font-family:var(--body);font-weight:600;font-size:1rem;text-decoration:none;
    padding:.85rem 1.7rem;border-radius:12px;transition:transform .14s,background .2s,color .2s,border-color .2s}
  .btn:active{transform:translateY(1px)}
  .btn-accent{background:var(--accent-deep);color:#fff}
  .btn-accent:hover,.btn-accent:focus-visible{background:#2E3A94}
  .btn-line{border:1.5px solid var(--line);color:var(--ink)}
  .btn-line:hover,.btn-line:focus-visible{border-color:var(--ink)}

  /* header */
  header{position:sticky;top:0;z-index:60;background:var(--paper);
    border-bottom:1px solid var(--line)}
  .nav{display:flex;align-items:center;justify-content:space-between;height:72px;
    max-width:var(--stage);margin:0 auto;padding-left:clamp(1.25rem,4vw,3.5rem);padding-right:clamp(1.25rem,4vw,3.5rem)}
  .brand{font-family:var(--display);font-weight:600;font-size:1.35rem;color:var(--ink);text-decoration:none;
    display:inline-flex;align-items:center;gap:.6rem}
  .brand .beacon{width:9px;height:9px;border-radius:50%;background:var(--accent);flex:none;
    box-shadow:0 0 0 0 rgba(85,103,224,.55);animation:pulse 1.9s ease-out infinite}
  /* ⚠ TAP TARGETS — WCAG 2.5.8 wants 24x24 (2026-07-26). An inline <a> with no padding has a hit
     box the size of its GLYPHS, so these read at ~18px however roomy the bar looks. Type size is
     UNCHANGED; only the hit box grows, and the .3rem it costs horizontally is taken straight back
     out of the flex `gap` (2 -> 1.7rem) so the spacing is identical to the pixel. The bar is a
     fixed 72px centred row, so the vertical growth is absorbed by the bar's own padding.
     `a.cta` keeps its own larger padding — the rule below it is more specific and still wins. */
  .nav .links{display:flex;align-items:center;gap:1.7rem}
  .nav .links a{display:inline-flex;align-items:center;min-height:24px;padding:.3rem .15rem;
    font-family:var(--body);font-weight:500;font-size:.95rem;text-decoration:none;color:var(--ink-soft);transition:color .2s}
  .nav .links a:hover{color:var(--ink)}
  /* `a.cta` and not `.cta` — the rule above is `.nav .links a` (0,2,1), so a bare
     `.nav .cta` (0,2,0) loses and the label falls back to muted ink ON the filled
     button, which is unreadable. Match the element too, or lose to the sibling. */
  .nav .links a.cta{background:var(--accent-deep);color:#fff;padding:.55rem 1.25rem;
    border-radius:12px;font-weight:600}
  .nav .links a.cta:hover{background:#2E3A94;color:#fff}
  @media (max-width:860px){.nav .links a.hide-sm{display:none}}

  @keyframes pulse{0%{box-shadow:0 0 0 0 rgba(85,103,224,.5)}70%{box-shadow:0 0 0 8px rgba(85,103,224,0)}
    100%{box-shadow:0 0 0 0 rgba(85,103,224,0)}}

  /* ============================================================= HERO */
  .hero{position:relative;overflow:hidden;padding-top:clamp(3rem,6vw,5rem);padding-bottom:clamp(2.5rem,5vw,4rem)}
  .hero>*{position:relative;z-index:1}
  .hero-grid{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(1.5rem,4vw,3.5rem);align-items:end}
  .hero h1{font-family:var(--display);font-weight:600;line-height:.98;letter-spacing:-.02em;
    font-size:clamp(2.8rem,7vw,5.6rem);margin:.6rem 0 0;font-optical-sizing:auto}
  .hero h1 em{font-style:normal;font-weight:700;color:var(--accent)}
  .hero .sub{font-size:clamp(1.08rem,1.7vw,1.32rem);color:var(--ink-soft);max-width:46ch;margin:1.5rem 0 0}
  .hero .actions{display:flex;flex-wrap:wrap;gap:.9rem;margin-top:2rem}
  .hero-note{font-size:.92rem;color:var(--ink-soft);margin:1.15rem 0 0;max-width:52ch}

  /* hero control wall — four live channels previewing the stages below */
  .wall{border:1px solid var(--line);border-radius:var(--r-unit);background:#fff;overflow:hidden;
    box-shadow:0 20px 50px rgba(24,20,27,.10)}
  .wall-top{display:flex;align-items:center;justify-content:space-between;gap:.6rem;
    padding:.7rem 1rem;background:var(--ink-900);color:var(--paper)}
  .wall-top .mono{color:rgba(246,247,249,.72)}
  .wall-top .rec{display:inline-flex;align-items:center;gap:.5rem;color:#fff}
  .wall-top .rec i{width:8px;height:8px;border-radius:50%;background:var(--accent);
    box-shadow:0 0 0 0 rgba(85,103,224,.6);animation:pulse 1.6s ease-out infinite}
  .channels{display:grid;grid-template-columns:1fr 1fr}
  .channel{padding:1rem 1.1rem;border-top:1px solid var(--line);position:relative;
    text-decoration:none;color:var(--ink);display:block;transition:background .2s}
  .channel:nth-child(odd){border-right:1px solid var(--line)}
  .channel:hover{background:var(--paper-3)}
  .channel .cn{font-family:var(--display);font-weight:600;font-size:1.02rem;line-height:1.15;letter-spacing:-.01em}
  .channel .cs{display:flex;align-items:center;gap:.45rem;margin-top:.5rem}
  .channel .cs .dot{width:7px;height:7px;border-radius:50%;background:var(--acc,var(--accent));flex:none}
  .channel .cs .mono{color:var(--ink-soft)}
  /* tiny signal bars = liveness, decorative */
  /* static equaliser glyph — a liveness mark, not fake real-time telemetry */
  .bars{display:inline-flex;align-items:flex-end;gap:2px;height:12px;margin-left:auto}
  .bars i{width:3px;background:var(--acc,var(--accent));border-radius:1px;height:55%}
  .bars i:nth-child(1){height:35%}
  .bars i:nth-child(2){height:80%}
  .bars i:nth-child(3){height:55%}
  .bars i:nth-child(4){height:100%}
  .channel.w-freight{--acc:#D9922B} .channel.w-ashen{--acc:#E2663F}
  .channel.w-union{--acc:#2E7D74}  .channel.w-fading{--acc:#3fb98f}
  .channel.w-vested{--acc:#2e6d4e} .channel.w-nullroute{--acc:#3457c9}
  .channel.w-progeny{--acc:#7a4bb8} .channel.w-epoch{--acc:#4A5A70}
  /* the three arcade titles */
  .channel.w-clearance{--acc:#1F6F8B} .channel.w-emberdown{--acc:#8E2749}
  .channel.w-corpus{--acc:#96307D}
  /* These three were on the wall with no accent — they fell back to --accent, so three
     different worlds shared one indigo dot. Same hues as their cabinets below. */
  .channel.w-asymptote{--acc:#407016} .channel.w-titer{--acc:#752885}
  .channel.w-continuousyield{--acc:#1F7A3D}
  /* A world with no agent on it yet. The wall header claims "Live · 24/7", so a row that
     is not live has to LOOK not-live — muted bars, hollow dot. Drop .soon when it ships. */
  .channel.soon .cs .dot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--acc,var(--accent))}
  .channel.soon .bars i{opacity:.34}
  .channel.soon .cs .mono{font-style:italic}

  @media (max-width:920px){.hero-grid{grid-template-columns:1fr;gap:2.2rem}}
  @media (max-width:460px){.channels{grid-template-columns:1fr}.channel:nth-child(odd){border-right:0}}

  /* ============================================================= LIVING WORLDS */
  .worlds-intro{padding-top:clamp(2.5rem,5vw,4rem);padding-bottom:.5rem}
  .worlds-intro .h2{font-family:var(--display);font-weight:600;line-height:1.04;letter-spacing:-.015em;
    font-size:clamp(1.9rem,4vw,2.9rem);margin:.3rem 0 .6rem;max-width:20ch}
  .worlds-intro p{color:var(--ink-soft);font-size:1.1rem;max-width:60ch;margin:0}

  /* one live stage per world */
  /* THREE games per row (2026-07-24). The catalogue is eight games and growing; at two per
     row the page was a long scroll of huge live feeds and nobody reached the bottom of it.
     Three narrows each stage enough to read the whole shelf at a glance, and the step-downs
     below keep a card from ever being too narrow to show its feed:
       >=1280px  3 up   — the full shelf
       >=820px   2 up   — laptops; three would squeeze the 16:10 embed
       <820px    1 up   — phones/tablets, stacked as before */
  .stages{display:grid;grid-template-columns:repeat(3,1fr)}
  @media(max-width:1280px){.stages{grid-template-columns:repeat(2,1fr)}}
  @media(max-width:820px){.stages{grid-template-columns:1fr}}
  /* At three up a stage is ~a third as wide, so the heading block must stop trying to sit
     beside its buttons — it wrapped to a cramped two-line title next to a stray CTA. */
  @media(min-width:1281px){
    .stages .stage-head{display:block}
    .stages .stage-cta{margin-top:1rem}
  }
  .stage{padding-top:clamp(2.6rem,5vw,4.5rem);padding-bottom:clamp(2.6rem,5vw,4.5rem);
    position:relative;overflow:hidden;color:var(--fg)}
  /* ⚠ INK, not fill. --acc-mark is the AA-safe sibling where the bright accent
     fails as text (Fading Wilds' mint measures 1.97:1 on paper); every other
     cabinet falls back to --acc, which already passes. The token existed for
     exactly this and was wired to nothing for weeks. */
  .stage .eyebrow{color:var(--acc-mark,var(--acc))}
  .stage-head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;
    gap:1rem 2rem;margin-bottom:1.6rem}
  .stage-head .lead-wrap{max-width:60ch}
  .stage-title{font-family:var(--display);font-weight:600;line-height:1;letter-spacing:-.02em;
    font-size:clamp(2.1rem,4.6vw,3.6rem);margin:.25rem 0 .7rem;color:var(--fg)}
  .stage-title .tm-mark{font-size:.42em;vertical-align:super;font-weight:600;letter-spacing:0;opacity:.7}
  .stage-lead{font-size:1.08rem;color:var(--fg-soft);margin:0;max-width:60ch}
  .stage-cta{display:flex;gap:.7rem;flex-wrap:wrap;flex:none}
  .stage .btn-play{background:var(--acc);color:var(--acc-ink,#fff)}
  .stage .btn-play:hover,.stage .btn-play:focus-visible{filter:brightness(1.08)}
  .stage .btn-watch{border:1.5px solid var(--fg-line);color:var(--fg)}
  .stage .btn-watch:hover,.stage .btn-watch:focus-visible{border-color:var(--fg);background:var(--fg-wash)}

  /* the monitor: the live iframe, given the whole screen */
  .mon{position:relative;border-radius:16px;overflow:hidden;background:#04050a;
    border:1px solid var(--bezel);box-shadow:0 30px 70px rgba(0,0,0,.28),inset 0 0 0 1px rgba(255,255,255,.04)}
  /* gate-47: no re-drawn monitor chrome. The live iframe stands as a framed figure;
     liveness lives in the per-stage eyebrow + caption, not a fake bezel bar. */
  /* The live embeds are 16:10 cards. A full-bleed 64vh box left them filling the width
     with a tall dead strip below — so give the frame the embed's own 16:10 shape and cap
     its width. It scales down a bit and the game fills the screen, no empty space. */
  .mon-screen{position:relative;width:100%;max-width:1120px;margin-inline:auto;
    aspect-ratio:16/10;max-height:72vh;background:#04050a}
  /* a stage for a world that is built but not yet serving — same frame, honest content */
  .mon-soon{display:grid;place-items:center;text-align:center;padding:1.5rem}
  .mon-soon .soon-inner{max-width:44ch}
  .mon-soon .mono{color:var(--accent);display:block;margin-bottom:.6rem}
  .mon-soon p{color:rgba(246,247,249,.72);margin:0}
  .mon-screen iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
  /* corner registration ticks + faint vignette — instrument feel, never blocks the game */
  .mon-screen::before,.mon-screen::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:2}
  .mon-screen::before{
    background:
      linear-gradient(var(--acc),var(--acc)) left 12px top 12px/16px 2px no-repeat,
      linear-gradient(var(--acc),var(--acc)) left 12px top 12px/2px 16px no-repeat,
      linear-gradient(var(--acc),var(--acc)) right 12px top 12px/16px 2px no-repeat,
      linear-gradient(var(--acc),var(--acc)) right 12px top 12px/2px 16px no-repeat,
      linear-gradient(var(--acc),var(--acc)) left 12px bottom 12px/16px 2px no-repeat,
      linear-gradient(var(--acc),var(--acc)) left 12px bottom 12px/2px 16px no-repeat,
      linear-gradient(var(--acc),var(--acc)) right 12px bottom 12px/16px 2px no-repeat,
      linear-gradient(var(--acc),var(--acc)) right 12px bottom 12px/2px 16px no-repeat;
    opacity:.55}
  .mon-screen::after{box-shadow:inset 0 0 120px rgba(0,0,0,.45);border-radius:0}
  .mon-foot{display:flex;flex-wrap:wrap;align-items:center;gap:.9rem 1.4rem;
    padding:1rem 1.1rem;background:var(--chrome);border-top:1px solid var(--bezel)}
  .mon-foot p{margin:0;color:var(--chrome-mut);font-size:.96rem;line-height:1.5;max-width:74ch}
  .mon-foot p b{color:var(--chrome-fg);font-weight:700}
  .mon-foot p i{font-style:normal;font-weight:700;color:var(--acc-mark,var(--acc))}
  .mon-foot .spacer{flex:1}

  /* per-world atmospheres --------------------------------------- */
  /* Freight Mogul — road-night dispatch */
  .w1{background:radial-gradient(140% 120% at 85% 0%,#22303b 0%,#141b22 55%,#0e141a 100%);
    --fg:#f3efe6;--fg-soft:#c3ccce;--fg-line:rgba(243,239,230,.28);--fg-wash:rgba(243,239,230,.06);
    --acc:#D9922B;--acc-ink:#20160a;--acc-glow:rgba(217,146,43,.55);
    --bezel:rgba(243,239,230,.14);--chrome:#0d1319;--chrome-fg:#f3efe6;--chrome-mut:#9fb0b3}
  /* dashed teal highway line drifting across the top */
  .w1::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;pointer-events:none;
    background:repeating-linear-gradient(90deg,var(--support) 0 22px,transparent 22px 46px);
    opacity:.5;animation:road 2.4s linear infinite}
  @keyframes road{to{background-position:46px 0}}

  /* Legend of the Ashen Dragon — ash-dark ember fantasy (the dramatic one) */
  .w2{background:radial-gradient(120% 130% at 50% 120%,#3a1410 0%,#1a0d12 45%,#0b070c 100%);
    --fg:#f4e9df;--fg-soft:#cbb6ac;--fg-line:rgba(244,233,223,.24);--fg-wash:rgba(244,233,223,.06);
    --acc:#C9491F;--acc-ink:#fff;--acc-glow:rgba(226,102,63,.6);   /* white 4.71:1 */
    --bezel:rgba(244,233,223,.13);--chrome:#140a0d;--chrome-fg:#f4e9df;--chrome-mut:#b79a90}
  /* rising embers */
  .embers{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:0}
  .embers i{position:absolute;bottom:-12px;width:3px;height:3px;border-radius:50%;
    background:var(--warn);box-shadow:0 0 8px 2px rgba(244,183,64,.55);opacity:0;
    animation:ember 7s linear infinite}
  @keyframes ember{0%{transform:translateY(0) translateX(0);opacity:0}
    12%{opacity:.9}80%{opacity:.7}100%{transform:translateY(-70vh) translateX(24px);opacity:0}}

  /* A More Perfect Union — civic parchment (the light, restrained one) */
  .w3{background:linear-gradient(180deg,#f3e7d1 0%,#efe1c8 100%);
    --fg:#2b3640;--fg-soft:#5a6a74;--fg-line:rgba(43,54,64,.22);--fg-wash:rgba(43,54,64,.05);
    --acc:#2E7D74;--acc-ink:#fff;--acc-glow:rgba(46,125,116,.5);
    --bezel:rgba(43,54,64,.22);--chrome:#e7d7ba;--chrome-fg:#2b3640;--chrome-mut:#6b7680}
  /* engraved civic hairlines top + bottom */
  .w3::before,.w3::after{content:"";position:absolute;left:0;right:0;height:0;pointer-events:none;
    border-top:1px solid rgba(43,54,64,.18);box-shadow:0 3px 0 -1px rgba(43,54,64,.10)}
  .w3::before{top:14px}.w3::after{bottom:14px}

  /* Fading Wilds — forest-dusk procgen wilds */
  .w4{background:radial-gradient(130% 120% at 20% 0%,#123a34 0%,#0d211d 55%,#08130f 100%);
    --fg:#e9f2ec;--fg-soft:#aec7bb;--fg-line:rgba(233,242,236,.24);--fg-wash:rgba(233,242,236,.06);
    --acc:#41c896;--acc-ink:#06231a;--acc-glow:rgba(65,200,150,.5);
    --bezel:rgba(233,242,236,.13);--chrome:#0b1a16;--chrome-fg:#e9f2ec;--chrome-mut:#8fb3a3}
  /* drifting fireflies */
  .flies{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:0}
  .flies i{position:absolute;width:3px;height:3px;border-radius:50%;background:var(--warn);
    box-shadow:0 0 7px 2px rgba(244,183,64,.5);opacity:0;animation:fly 9s ease-in-out infinite}
  @keyframes fly{0%{transform:translate(0,0);opacity:0}20%{opacity:.85}
    50%{transform:translate(30px,-26px);opacity:.5}80%{opacity:.7}
    100%{transform:translate(-10px,-48px);opacity:0}}

  /* Vested — statement paper / ledger green (the passbook) */
  .w5{background:linear-gradient(180deg,#ece7da 0%,#e6e0d0 100%);
    --fg:#1b2a23;--fg-soft:#5c685c;--fg-line:rgba(27,42,35,.20);--fg-wash:rgba(27,42,35,.05);
    --acc:#2e6d4e;--acc-ink:#f6f1e6;--acc-glow:rgba(46,109,78,.45);
    --bezel:rgba(27,42,35,.20);--chrome:#e2dccb;--chrome-fg:#1b2a23;--chrome-mut:#6b7568}
  /* dashed ledger ruling along the top edge */
  .w5::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;pointer-events:none;
    background:repeating-linear-gradient(90deg,var(--acc) 0 14px,transparent 14px 22px);opacity:.5}

  /* Nullroute — dark net / terminal cyber */
  .w6{background:radial-gradient(130% 120% at 80% 0%,#141a2e 0%,#0d1120 55%,#080a14 100%);
    --fg:#e7ecf5;--fg-soft:#aab6cf;--fg-line:rgba(231,236,245,.24);--fg-wash:rgba(231,236,245,.06);
    --acc:#6b8cff;--acc-ink:#0a0d18;--acc-glow:rgba(107,140,255,.5);
    --bezel:rgba(231,236,245,.13);--chrome:#0e1322;--chrome-fg:#e7ecf5;--chrome-mut:#8898b8}
  /* scanning packet line along the top edge */
  .w6::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;pointer-events:none;
    background:repeating-linear-gradient(90deg,var(--acc) 0 10px,transparent 10px 20px);opacity:.5}

  /* Progeny — the fluorescence lab. Added 2026-07-25: the stage markup shipped as
     `.w7` when Progeny went live, but no `.w7` block existed, so the band inherited
     nothing — dark screen, dark text on it, and an invisible "Play free". A stage
     without its palette does not fall back to something readable; it falls back to
     nothing. Adding a game to /games means adding its band here too. */
  .w7{background:radial-gradient(130% 120% at 25% 0%,#1b1030 0%,#120a20 55%,#090512 100%);
    --fg:#efe9fb;--fg-soft:#bcb0d6;--fg-line:rgba(239,233,251,.24);--fg-wash:rgba(239,233,251,.06);
    --acc:#a06bff;--acc-ink:#12081f;--acc-glow:rgba(160,107,255,.5);
    --bezel:rgba(239,233,251,.13);--chrome:#150c26;--chrome-fg:#efe9fb;--chrome-mut:#a494c4}
  /* a slow stain creeping across the top edge — the specimen under the lamp */
  .w7::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;pointer-events:none;
    background:linear-gradient(90deg,transparent,var(--acc),transparent);opacity:.55}

  /* Epoch & Entropy — wet asphalt under a sodium lamp. Amber is the only warm
     accent on /games, which is the point: every other band is cool or cream, so
     the noir card reads as its own place. Added with its markup, per the .w7
     lesson above — a stage without its palette falls back to nothing. */
  .w8{background:radial-gradient(135% 125% at 78% 0%,#1c2430 0%,#121822 55%,#0d1117 100%);
    --fg:#e8ecf2;--fg-soft:#a2acbd;--fg-line:rgba(232,236,242,.24);--fg-wash:rgba(232,236,242,.06);
    --acc:#e8a33d;--acc-ink:#1a1206;--acc-glow:rgba(232,163,61,.45);
    --bezel:rgba(232,236,242,.13);--chrome:#111721;--chrome-fg:#e8ecf2;--chrome-mut:#93a0b4}
  .w8::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;pointer-events:none;
    background:linear-gradient(90deg,transparent,var(--acc),transparent);opacity:.5}


  /* The three arcade titles. Each palette lands WITH its markup — the .w7 lesson
     above: a stage without its palette falls back to nothing, not to something
     readable. Accents match their world card so a game is one colour everywhere. */
  .w9{background:radial-gradient(135% 125% at 78% 0%,#132630 0%,#0f1c22 55%,#0b1519 100%);
    --fg:#e6eef2;--fg-soft:#9db2bd;--fg-line:rgba(255,255,255,.22);--fg-wash:rgba(255,255,255,.06);
    --acc:#1F6F8B;--acc-ink:#ffffff;--acc-glow:rgba(31,111,139,.45);
    --bezel:rgba(255,255,255,.13);--chrome:#0b1519;--chrome-fg:#e6eef2;--chrome-mut:#9db2bd}
  .w9::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;
    pointer-events:none;background:linear-gradient(90deg,transparent,var(--acc),transparent);opacity:.5}
  .w10{background:radial-gradient(135% 125% at 78% 0%,#2a161f 0%,#1d1016 55%,#150b10 100%);
    --fg:#f2e6ea;--fg-soft:#c2a3ad;--fg-line:rgba(255,255,255,.22);--fg-wash:rgba(255,255,255,.06);
    --acc:#8E2749;--acc-ink:#ffffff;--acc-glow:rgba(142,39,73,.45);
    --bezel:rgba(255,255,255,.13);--chrome:#150b10;--chrome-fg:#f2e6ea;--chrome-mut:#c2a3ad}
  .w10::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;
    pointer-events:none;background:linear-gradient(90deg,transparent,var(--acc),transparent);opacity:.5}
  .w11{background:radial-gradient(135% 125% at 78% 0%,#28162c 0%,#1c1020 55%,#140b17 100%);
    --fg:#f3e8f2;--fg-soft:#c0a4bd;--fg-line:rgba(255,255,255,.22);--fg-wash:rgba(255,255,255,.06);
    --acc:#96307D;--acc-ink:#ffffff;--acc-glow:rgba(150,48,125,.45);
    --bezel:rgba(255,255,255,.13);--chrome:#140b17;--chrome-fg:#f3e8f2;--chrome-mut:#c0a4bd}
  .w11::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;
    pointer-events:none;background:linear-gradient(90deg,transparent,var(--acc),transparent);opacity:.5}


  /* ═══ THE HALL — games as cabinets, three columns ═══════════════════════════
     Modern industrial, NOT retro pastiche: no scanlines, no woodgrain, no
     imitation of anyone's cabinet art. Flat planes, precise radii, one top-light,
     one accent per unit. Pure CSS — no images, so nothing is fetched and the whole
     hall re-skins from tokens.
     The FRAME TELLS YOU WHAT KIND OF GAME IT IS before you read a word: the control
     panel differs by type (arcade / workstation / console) while the silhouette
     stays constant, so the hall reads as a hall instead of fragmenting. */
  .hall{display:grid;gap:clamp(1rem,2.2vw,1.9rem);
    grid-template-columns:repeat(3,minmax(0,1fr))}
  @media(max-width:1080px){.hall{grid-template-columns:repeat(2,minmax(0,1fr))}}
  @media(max-width:680px){.hall{grid-template-columns:minmax(0,1fr)}}

  .cab{--cab:#1B1F27;--cab-2:#141821;--cab-3:#0F131A;
    display:flex;flex-direction:column;min-width:0;
    background:linear-gradient(180deg,#232833 0%,var(--cab) 18%,var(--cab-2) 100%);
    border-radius:16px 16px 6px 6px;overflow:hidden;
    box-shadow:0 18px 40px rgba(15,19,26,.28),0 2px 0 rgba(255,255,255,.06) inset}

  /* topper — the light box above the marquee. Height belongs to the CABINET BODY,
     not to a stretched screen: a monitor stays 4:3, so a taller silhouette comes
     from the topper and the pedestal, the way the real object does. */
  .cab-top{height:34px;background:linear-gradient(180deg,#2C323E 0%,#222732 100%);
    border-bottom:1px solid rgba(0,0,0,.35);position:relative}
  .cab-top::after{content:"";position:absolute;left:1rem;right:1rem;bottom:6px;height:3px;
    border-radius:2px;background:var(--acc,var(--accent));opacity:.55}

  /* pedestal — kick plate under the coin line, the rest of the height */
  .cab-base{height:52px;background:linear-gradient(180deg,#12161D 0%,#0B0E13 100%);
    border-top:1px solid rgba(255,255,255,.05);position:relative}
  .cab-base::after{content:"";position:absolute;left:14%;right:14%;top:14px;height:2px;
    border-radius:2px;background:rgba(255,255,255,.06)}

  /* marquee — backlit panel. --acc/--acc-ink are the SAME pair the play button
     uses, so its contrast is already verified per game. */
  .cab-marquee{background:var(--acc,var(--accent));color:var(--acc-ink,#fff);
    padding:.85rem 1rem;display:flex;align-items:baseline;gap:.5rem;min-width:0}
  .cab-marquee .mk{font-family:var(--display);font-weight:600;font-size:.82rem;
    letter-spacing:.14em;opacity:.72;flex:none}
  .cab-marquee h3{font-family:var(--display);font-weight:600;margin:0;
    font-size:1.02rem;line-height:1.15;letter-spacing:-.005em;
    overflow-wrap:anywhere;min-width:0}
  .cab-marquee .tm-mark{opacity:.6}

  /* screen — inset glass */
  /* A cabinet is TALL. The screen carries a real 4:3 monitor aspect and the body
     grows from there, so the silhouette reads as a standing machine rather than a
     wide card with a coloured hat. */
  .cab-screen{background:var(--cab-3);color:#C9D1DC;padding:1.15rem 1.1rem 1.3rem;
    flex:1;min-height:15rem;display:flex;flex-direction:column;justify-content:center;
    box-shadow:0 2px 12px rgba(0,0,0,.5) inset;border-top:1px solid rgba(255,255,255,.07)}
  /* live variant — the monitor IS the feed, so the glass gets the aspect and no padding */
  .cab-screen.is-live{padding:0;min-height:0;aspect-ratio:4/3;position:relative;overflow:hidden}
  .cab-screen.is-live iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
  /* spec plate — the copy strip under the glass, like the info card on a real cabinet */
  .cab-plate{background:#171C25;color:#AAB4C2;padding:.85rem 1.1rem;font-size:.88rem;
    line-height:1.5;border-top:1px solid rgba(255,255,255,.06)}
  .cab-plate p{margin:0}
  .cab-screen p{margin:0;font-size:.92rem;line-height:1.55}
  .cab-state{display:inline-block;font-family:var(--body);font-weight:700;
    font-size:.62rem;letter-spacing:.16em;text-transform:uppercase;
    color:var(--acc-lift,#fff);border:1px solid currentColor;border-radius:3px;
    padding:.15rem .4rem;margin:0 0 .55rem}

  /* control panel — the type tell */
  .cab-panel{background:linear-gradient(180deg,#252B36 0%,#1D222B 100%);
    padding:.7rem 1rem;display:flex;align-items:center;gap:.75rem;flex-wrap:wrap;
    border-top:1px solid rgba(255,255,255,.06)}
  .ctl{display:flex;align-items:center;gap:.34rem;flex:none}
  .ctl i{display:block;border-radius:50%;background:#39404E;
    box-shadow:0 1px 0 rgba(255,255,255,.10) inset}
  .ctl i.b{width:9px;height:9px}
  .ctl i.lit{background:var(--acc,var(--accent))}
  .ctl .stick{width:7px;height:16px;border-radius:4px;background:#39404E;
    box-shadow:0 1px 0 rgba(255,255,255,.10) inset}
  .ctl .pad{width:16px;height:16px;border-radius:3px;background:#39404E;
    box-shadow:0 1px 0 rgba(255,255,255,.10) inset}
  .ctl .keys{display:flex;gap:2px}
  .ctl .keys i{width:5px;height:9px;border-radius:1.5px}
  .cab-panel .go{margin-left:auto;font-family:var(--body);font-weight:600;
    font-size:.82rem;text-decoration:none;border-radius:8px;padding:.38rem .85rem;
    background:var(--acc,var(--accent));color:var(--acc-ink,#fff);
    transition:filter .18s}
  .cab-panel .go:hover,.cab-panel .go:focus-visible{filter:brightness(1.1)}
  .cab-panel .go:active{transform:translateY(1px)}
  /* 2.5.8: `Watch` sat at ~16px next to a 28px `Play free`. It is a chrome control on every lit
     cabinet, so it gets a 24px box. Free vertically — `.go` already sets the panel's height. */
  .cab-panel .watch{display:inline-flex;align-items:center;min-height:24px;padding:.25rem 0;
    font-family:var(--body);font-weight:600;font-size:.82rem;
    text-decoration:none;color:#AEB8C6;border-bottom:1px solid rgba(174,184,198,.4)}
  .cab-panel .watch:hover,.cab-panel .watch:focus-visible{color:#fff;border-color:#fff}
  .cab-panel .soon{font-family:var(--body);font-weight:700;font-size:.66rem;
    letter-spacing:.14em;text-transform:uppercase;color:#8E99A9;margin-left:auto}
  .cab :focus-visible{outline:3px solid #fff;outline-offset:2px}

  /* coin line — FREE PLAY is the truthful arcade word for a nonprofit's games */
  .cab-coin{background:var(--cab-3);padding:.5rem 1rem;display:flex;
    align-items:center;justify-content:space-between;gap:.6rem;
    font-family:var(--body);font-weight:700;font-size:.6rem;letter-spacing:.2em;
    text-transform:uppercase;color:#77839A;border-top:1px solid rgba(255,255,255,.05)}
  .cab-coin .slot{width:22px;height:3px;border-radius:2px;background:#2C333F;flex:none}

  /* Status chip for a game that is not playable yet. Deliberately NOT an <a> and
     NOT .btn — a button that goes nowhere is worse than no button. (It goes somewhere now:
     the WIP placeholder. Still not .btn — the destination is a notice, not a game.) */
  .stage-soon{display:inline-flex;align-items:center;gap:.5rem;
    font-family:var(--body);font-weight:600;font-size:.8rem;letter-spacing:.1em;
    text-transform:uppercase;color:var(--fg-soft);
    border:1.5px dashed var(--fg-line);border-radius:999px;padding:.62rem 1.1rem}
  .stage-soon::before{content:"";width:.5rem;height:.5rem;border-radius:50%;
    background:var(--acc);box-shadow:0 0 0 3px var(--acc-glow);flex:none}
  a.stage-soon{text-decoration:none}
  a.stage-soon:hover,a.stage-soon:focus-visible{color:var(--fg);border-color:var(--fg-soft)}

  .stage>.shell{position:relative;z-index:1}

  /* ============================================================= REALMS (kept script) */
  .realms-band{background:var(--ink-900);color:var(--paper);
    padding-top:clamp(3.2rem,6vw,5rem);padding-bottom:clamp(3.2rem,6vw,5rem)}
  .realms-band .eyebrow{color:var(--accent-lift)}
  .realms-band .h2{font-family:var(--display);font-weight:600;line-height:1.04;letter-spacing:-.01em;
    font-size:clamp(2rem,4vw,3rem);margin:.2rem 0 .7rem;color:var(--paper)}
  .realms-band .lead{color:rgba(246,247,249,.72);font-size:1.08rem;max-width:64ch;margin:0}
  .sec-head{margin-bottom:2.4rem;max-width:60ch}
  /* FOUR ACROSS, MAX. `auto-fit` had no ceiling, so a wide screen packed five and
     left one orphan card alone on row two. It also squeezed "Legend of the Ashen
     Dragon" onto two lines. Explicit steps instead of a minmax floor — the cap is
     the point, and auto-fit cannot express one. */
  .realms{display:grid;gap:1.3rem;margin:2.4rem 0 0;grid-template-columns:repeat(2,1fr)}
  @media (max-width:700px) {.realms{grid-template-columns:1fr}}
  @media (min-width:1020px){.realms{grid-template-columns:repeat(3,1fr)}}
  @media (min-width:1320px){.realms{grid-template-columns:repeat(4,1fr)}}
  .realm{background:rgba(246,247,249,.04);border:1px solid rgba(246,247,249,.14);
    padding:1.3rem 1.4rem}
  .realm-top{display:flex;align-items:baseline;justify-content:space-between;gap:.6rem;
    margin-bottom:.9rem;padding-bottom:.7rem;border-bottom:1px solid rgba(246,247,249,.14)}
  .realm-name{font-family:var(--display);font-weight:600;font-size:1.12rem;color:var(--paper);
    text-decoration:none;line-height:1.15}
  .realm-name:hover{color:var(--accent-lift)}
  .realm-season{font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
    color:var(--support);white-space:nowrap;flex:none}
  .realm ol{list-style:none;margin:0;padding:0;display:grid;gap:.5rem}
  .realm li{display:grid;grid-template-columns:1.5rem 1fr auto;gap:.6rem;align-items:baseline;
    font-size:.96rem}
  .realm .rk{color:rgba(246,247,249,.6);font-weight:700;font-variant-numeric:tabular-nums;text-align:right}
  .realm li:first-child .rk{color:var(--accent-lift)}
  .realm .who{color:var(--paper);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .realm .stat{color:rgba(246,247,249,.62);font-size:.84rem;font-variant-numeric:tabular-nums;
    white-space:nowrap;text-align:right}
  .realms-empty{color:rgba(246,247,249,.6);font-size:.98rem;margin:1.6rem 0 0}

  /* ============================================================= NARRATIVE (2nd act) */
  section.narr{padding-top:clamp(3.4rem,7vw,6rem);padding-bottom:clamp(3.4rem,7vw,6rem)}
  .band-blush{background:var(--paper-2)}
  .h2{font-family:var(--display);font-weight:600;line-height:1.04;letter-spacing:-.01em;
    font-size:clamp(2rem,4.5vw,3.1rem);margin:0}

  /* ethos */
  /* .eyebrow is flex now (it carries the slot mark), so text-align no longer
     centres it — the flex box does. */
  .ethos{text-align:center}
  .ethos .eyebrow{justify-content:center}
  .ethos-inner{max-width:760px;margin:0 auto}
  .ethos-head{font-family:var(--display);font-weight:600;letter-spacing:-.015em;line-height:1.05;
    font-size:clamp(2.3rem,6vw,4rem);margin:.3rem 0 1.3rem;color:var(--ink)}
  .ethos-head em{font-style:normal;font-weight:700;color:var(--accent)}
  .ethos-lead{font-size:clamp(1.1rem,1.8vw,1.3rem);color:var(--ink-soft);max-width:48ch;margin:0 auto 2.8rem}
  .ethos-pair{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;text-align:left}
  .pillar{background:var(--paper-3);padding:clamp(1.5rem,3vw,2rem)}
  .pillar h3{font-family:var(--display);font-weight:600;font-size:1.5rem;margin:0 0 .5rem;color:var(--ink)}
  .pillar p{margin:0;color:var(--ink-soft);font-size:1rem}
  @media (max-width:640px){.ethos-pair{grid-template-columns:1fr;gap:1.1rem}}

  .sec-head2{margin-bottom:2.4rem;max-width:34ch}
  .sec-head2 .h2{margin-top:.2rem}

  /* the name */
  .name-intro{font-size:1.12rem;color:var(--ink-soft);max-width:58ch;margin:-1.4rem 0 2.4rem}
  .name-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem}
  .name-card{background:var(--paper-2);padding:clamp(1.6rem,3vw,2.4rem)}
  .name-card .chars{font-family:"Noto Serif JP",var(--display),serif;font-weight:600;
    font-size:clamp(3rem,8vw,4.6rem);line-height:1;color:var(--accent);margin:0}
  .name-card .reading{font-weight:600;font-size:.76rem;letter-spacing:.22em;text-transform:uppercase;color:var(--ink-soft);margin:.9rem 0 .5rem}
  .name-card h3{font-family:var(--display);font-weight:600;font-size:1.5rem;color:var(--ink);margin:0 0 .6rem}
  .name-card>p:last-child{margin:0;color:var(--ink-soft)}
  @media (max-width:720px){.name-grid{grid-template-columns:1fr}}

  /* support / steps */
  .steps{display:grid;grid-template-columns:repeat(3,1fr);gap:2rem}
  /* the training columns were already a light bar in all but name — same 3px
     and the same .55, so they stop being a third treatment */
  .step{border-top:3px solid color-mix(in srgb,var(--accent) 55%,var(--paper));
    padding-top:1.1rem}
  .step h3{font-family:var(--display);font-weight:600;font-size:1.25rem;margin:.5rem 0 .5rem}
  .step p{margin:0;color:var(--ink-soft);font-size:.99rem}
  @media (max-width:720px){.steps{grid-template-columns:1fr;gap:1.7rem}}

  /* give — support, recut off the 3-up card grid into hairline-ruled rows so the
     page doesn't stamp the same 3-column template three times (M4). */
  .give{margin:0;display:grid}
  .give>div{display:grid;grid-template-columns:minmax(0,17ch) 1fr;gap:.4rem 2.4rem;
    padding:1.5rem 0;border-top:1px solid var(--line);align-items:baseline}
  .give>div:last-child{border-bottom:1px solid var(--line)}
  .give dt{font-family:var(--display);font-weight:600;font-size:1.25rem;color:var(--ink);margin:0}
  .give dd{margin:0;color:var(--ink-soft);font-size:1rem}
  @media (max-width:640px){.give>div{grid-template-columns:1fr;gap:.35rem;padding:1.2rem 0}}

  /* involved */
  .ways{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem}
  .way{background:var(--paper);border:1px solid var(--line);padding:clamp(1.5rem,3vw,2rem);display:flex;flex-direction:column}
  .way h3{font-family:var(--display);font-weight:600;font-size:1.3rem;margin:0 0 .55rem}
  .way p{margin:0 0 1.5rem;color:var(--ink-soft);font-size:.98rem;flex:1}
  .way a{align-self:flex-start;font-weight:600;color:var(--accent-deep);text-decoration:none;border-bottom:2px solid transparent;padding-bottom:2px;transition:border-color .2s}
  .way a:hover{border-color:var(--accent)}
  .soon-note{font-weight:600;font-size:.82rem;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-soft)}
  @media (max-width:720px){.ways{grid-template-columns:1fr}}

  /* ── footer ────────────────────────────────────────────────────────────────
     Was a two-column flex: brand left, a right-aligned `.meta` stack right, and
     an empty middle on anything wider than a laptop — the trademark sentence
     squeezed into a 52ch gutter while half the band sat unused. It is a grid
     now: identity · worlds · site, across the full --stage width, with the legal
     line running the whole width underneath instead of hiding in a column.

     Measured on --ink (#171A21), not assumed (AA needs 4.5 for body text):
       brand/headings  --paper  16.24  ·  links  --accent-lift  7.12
       muted + the trademark line  #AAACB0 (the mix below)  7.66
     --foot-muted is scoped to the footer on purpose — it is a derived shade of
     --paper, not a new palette entry, so the shared :root block stays identical
     to app.css. If color-mix ever fails the colour is invalid and inherits
     --paper (16.24), so the degraded state is still AA. */
  /* The footer is the page's PEDESTAL — `.cab-base`, at site scale. The page
     ends the way every machine on it ends: a dark kick plate with one rule
     across it, so the whole document stands on the floor instead of stopping. */
  footer{background:var(--ink);color:var(--paper);padding:clamp(2.6rem,5vw,3.8rem) 0 1.9rem;
    position:relative;
    --foot-muted:color-mix(in srgb,var(--paper) 66%,var(--ink));
    --foot-rule:color-mix(in srgb,var(--paper) 18%,var(--ink))}
  /* footer has no horizontal padding (the .shell inside carries it), so this
     spans the band on its own — no -100vw bleed hack needed. The negative
     bottom margin eats footer's own 1.9rem so the plate sits on the edge. */
  footer::after{content:"";display:block;height:52px;margin:1.9rem 0 -1.9rem;
    background:var(--ink-900);border-top:1px solid var(--foot-rule);
    box-shadow:0 14px 0 -11px rgba(255,255,255,.06) inset}
  .foot{display:grid;grid-template-columns:minmax(15rem,1fr) minmax(0,2.1fr) minmax(9rem,.7fr);
    gap:clamp(1.8rem,3.5vw,3.5rem);align-items:start}
  .foot .brand{color:var(--paper);font-size:1.45rem}
  .foot-tag{font-family:var(--display);font-style:italic;font-size:1.05rem;color:var(--accent-lift);margin:.4rem 0 0}
  .foot-where{margin:1rem 0 0;font-size:.9rem;color:var(--foot-muted)}
  .foot h2{font-family:var(--body);font-weight:700;font-size:.72rem;letter-spacing:.16em;
    text-transform:uppercase;color:var(--paper);margin:0 0 1rem}
  .foot ul{list-style:none;margin:0;padding:0}
  /* WCAG 2.5.8 (24x24): these are nav links in a list, not links in a sentence, so the inline
     exception does not cover them. The row is 24px now and the 3px it gained comes back out of
     the margin (.5 -> .3rem), so the column pitch is within half a pixel of what it was.
     ⚠ app.css carries the same two rules — keep them in step. */
  .foot li{margin:0 0 .3rem;font-size:.92rem;line-height:1.45;min-height:24px;display:flex;align-items:center}
  .foot li a{display:flex;align-items:center;min-height:24px}
  .foot-games{columns:3;column-gap:clamp(1rem,2.2vw,2.4rem)}
  .foot-games li{break-inside:avoid}
  .foot a:not(.brand){color:var(--accent-lift);text-decoration:none}
  .foot a:not(.brand):hover{text-decoration:underline}
  .foot .soon{color:var(--foot-muted)}
  /* the three unreleased marks: named, never dressed as a link you can play */
  .foot .soon i{font-style:normal;font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;
    white-space:nowrap;margin-left:.4rem}
  .foot-base{margin-top:clamp(2rem,4vw,3rem);padding-top:1.4rem;border-top:1px solid var(--foot-rule)}
  .foot-base p{margin:0;font-size:.85rem;color:var(--foot-muted)}
  .foot-base a{color:var(--accent-lift);text-decoration:none}
  .foot-base a:hover{text-decoration:underline}
  .foot .tm{display:block;margin-top:.7rem;font-size:.78rem}
  footer :focus-visible{outline:3px solid var(--accent-lift);outline-offset:3px;border-radius:2px}
  /* 1080: the brand takes the full first row, worlds + site share the second.
     560: one column — long world names in two columns wrap to three lines each. */
  @media (max-width:1080px){
    .foot{grid-template-columns:1fr minmax(9rem,.55fr)}
    .foot-brandcol{grid-column:1/-1}
    .foot-games{columns:2}
  }
  @media (max-width:560px){
    .foot{grid-template-columns:1fr;gap:1.9rem}
    .foot-games{columns:1}
  }
  .tm-mark{font-size:.5em;vertical-align:super;font-weight:600;letter-spacing:0}

  .reveal{opacity:0;transform:translateY(16px);transition:opacity .7s ease,transform .7s ease}
  .reveal.in{opacity:1;transform:none}

  /* ---- reduced motion: still, but fully legible ---- */
  @media (prefers-reduced-motion:reduce){
    .reveal{opacity:1;transform:none;transition:none}
    .w1::before,.brand .beacon,.wall-top .rec i,.embers i,.flies i{animation:none!important}
    .embers,.flies{display:none}
  }

  /* ============================================================= WORLD CARDS (home) */
  /* Compact "mention + describe" of the four games; the full live stages live on /games. */
  .worlds-cards{padding-top:0;padding-bottom:clamp(1rem,3vw,2rem)}
  .worlds-more{margin:1.9rem 0 0}
  /* ⚠ `.wcards` / `.wcard` / `.wsoon` / `.wlinks` / `.wplay` / `.wwatch` were
     deleted 2026-07-26 — the cabinets replaced them in `c8d02c0` and the old
     rules stayed behind with zero HTML using them. The per-world accents below
     survived because `.cab.w-*` shares the selector; only the dead half went. */
  /* per-world accents (reused from the hero channels) */
  .cab.w-freight{--acc:#9E6210;--acc-ink:#fff}   /* white 4.99:1 */
  .cab.w-ashen{--acc:#B3441F}
  .cab.w-union{--acc:#2E7D74}
  /* ⚠ the mint is a FILL colour — as ink on paper it measured 1.97:1, far under AA.
     --acc-mark carries the readable sibling; --acc keeps the bright button. */
  .cab.w-fading{--acc:#41c896;--acc-ink:#06231a;--acc-mark:#1E7A57}
  .cab.w-vested{--acc:#2e6d4e;--acc-ink:#f6f1e6}
  .cab.w-nullroute{--acc:#3457c9;--acc-ink:#fff}
  .cab.w-progeny{--acc:#7a4bb8;--acc-ink:#fff}
  /* Epoch & Entropy — slate, deliberately the quietest accent on the row. The
     amber slot is taken (w-freight), and a card with nothing to click should not
     shout louder than the seven you can actually play. */
  .cab.w-epoch{--acc:#4A5A70;--acc-ink:#fff}
  .cab.w-clearance{--acc:#1F6F8B;--acc-ink:#fff}
  .cab.w-emberdown{--acc:#8E2749;--acc-ink:#fff}
  .cab.w-corpus{--acc:#96307D;--acc-ink:#fff}
  /* Added 2026-07-26 with the two games that had been built and registered nowhere. Hues were
     CHOSEN BY GAP, not by taste: the eleven accents above leave a 116° hole between freight (35°)
     and vested (150°) and a 49° one between progeny (266°) and corpus (315°), so these sit at 92°
     and 290° — the two emptiest places on a wheel that is genuinely full at thirteen games.
     Measured on this paper, not assumed:
       asymptote  white 5.92:1 · paper 5.52:1      titer  white 8.76:1 · paper 8.17:1 */
  .cab.w-asymptote{--acc:#407016;--acc-ink:#fff}
  .cab.w-titer{--acc:#752885;--acc-ink:#fff}
  /* Continuous Yield, added 2026-07-26 — same gap rule. With asymptote at 92° and vested at
     150°, 120° is the last wide hole left; white 5.38:1 · paper 5.02:1. */
  .cab.w-continuousyield{--acc:#1F7A3D;--acc-ink:#fff}
