/* THIS SHEET IS NOT RENDER-BLOCKING (index.html loads it media="print" and promotes it
   after the first frame). Nothing it styles is on screen at t=0 — the story beats, the
   playback controls and the content overlay all arrive seconds later.
   ⚠ The wordmark and the size tiers it depends on (--sp, --brand-font,
   --brand-lock-inset) are therefore authored INLINE in index.html <head>. Adding a
   .brand-land / .brand-max rule here would apply a frame or more late, so put brand
   geometry there, not here. Late-stage brand STATES (.brand-locked, .map-open,
   handoff) are fine below: they never run before this sheet is live. */
:root {
  --glass: rgba(8, 13, 20, .8);
  --glass-strong: rgba(8, 14, 22, .95);
  --line: rgba(243, 246, 248, .16);
  --shadow: 0 28px 80px rgba(0, 0, 0, .42);
}

.map-live .maplibregl-canvas { cursor: grab; }
.map-live .maplibregl-canvas:active { cursor: grabbing; }
html.intro-running #app #map { background: #000; }
.maplibregl-ctrl-attrib { background: rgba(0, 0, 0, .72) !important; color: var(--ink); }
.maplibregl-ctrl-attrib a { color: var(--ink) !important; }

/* No cinematic = no motion. Set before first paint whenever sequencePlan() says the show
   is off — browser Back, reduced motion, or a non-root URL. (There is no "already seen
   it" case any more: opening "/" always plays. James 2026-07-27.)

   This kills TRANSITIONS, and every element below reaches its visible state through a
   class, never through a transition's end value — so switching motion off SNAPS things
   into place rather than hiding them. The one that is easy to get wrong:
     #map                    `.planet-reveal` carries an 8s transform transition (in
                             index.html's inline <style>) that is INDEPENDENT of the
                             camera flight. Without this rule the non-animated path
                             still slid a slab of map up behind a finished story.
   The wordmark needs no special care here: its resting state is visible, so killing
   its animation shows it (index.html <head>). */
html.instant-reveal #map,
html.instant-reveal .brand-stage,
html.instant-reveal .brand-stage h1,
html.instant-reveal .brand-land,
html.instant-reveal .brand-max,
html.instant-reveal .story-stage,
html.instant-reveal .story-beat,
html.instant-reveal .story-controls { transition: none !important; animation: none !important; }

/* Brand GEOMETRY (.brand-stage, its h1, .brand-land, .brand-max and the entrance
   keyframes) is authored inline in index.html <head> so the wordmark paints and starts
   moving on the first frame. Only the LATE states — everything below, which fires at
   brandMs (2.6 s) or later — belong in this sheet. */
.brand-locked .brand-stage { transform: none; }
.brand-locked .brand-stage h1 {
  translate: 0 var(--brand-lock-inset);
  scale: .84;
  animation: brand-impact .52s cubic-bezier(.2,.8,.2,1);
}
@keyframes brand-impact { 45% { transform: scale(1.025); filter: brightness(1.4); } }
html.map-open .brand-stage { opacity: 0; transform: translate3d(0, -120vh, 0) scale(.52); }

/* Welcome starts inside the real app's Map Focus layout. Chrome begins just beyond
   its permanent edge, then arrives in readable groups instead of one large pop.
   Individual `translate` leaves each app owner's transform rules untouched. */
html.app-shell-mounted #app .app-header,
html.app-shell-mounted #app .cam,
html.app-shell-mounted #app .feature-drawer-rail,
html.app-shell-mounted #app .maplibregl-control-container,
html.app-shell-mounted #storage-overlay {
  opacity: 0;
  transition: opacity .36s ease, translate .64s cubic-bezier(.16,.82,.18,1);
}

/* Welcome SEALS app chrome until each piece has entered — and then stops asserting
   anything, rather than asserting `pointer-events: auto` back.
   THIS MATTERS: `.feature-drawer-rail` is a FULL-BLEED container (left:0;right:0, the whole viewport
   under the header). Its owner, rail.css, sets `pointer-events: none` on it precisely so
   only the visible tabs and cards are hit-testable and the map keeps the rest. Welcome's
   old release rule forced `auto` back on with a far higher specificity, turning the rail
   into a viewport-sized click shield: after EVERY handoff the map stopped accepting the
   mouse. Measured: the rail at 2520x1714 with pointer-events:auto, swallowing the map centre.
   A temporary lock must expire, never flip to the opposite assertion — the owner's own
   rule is the value to fall back to. (Map Focus re-seals chrome with `inert`, which is
   map-focus.js's job, so nothing here needs a .map-focus guard any more.) */
html.app-shell-mounted:not(.app-shell-ready) #app .app-header,
html.app-shell-mounted:not(.app-shell-ready) #app .cam,
html.app-shell-mounted:not(.app-shell-ready) #app .feature-drawer-rail,
html.app-shell-mounted:not(.app-shell-ready) #app .maplibregl-control-container,
html.app-shell-mounted:not(.app-shell-ready) #storage-overlay,
html.app-shell-ready:not(.app-enter-header) #app .app-header,
html.app-shell-ready:not(.app-enter-camera) #app .cam,
html.app-shell-ready:not(.app-enter-rail) #app .feature-drawer-rail,
html.app-shell-ready:not(.app-enter-map-controls) #app .maplibregl-control-container,
html.app-shell-ready:not(.app-entered) #storage-overlay { pointer-events: none; }
html.app-shell-mounted #app .app-header { translate: 0 -64px; }
html.app-shell-mounted #app .cam { translate: -52px 0; }
html.app-shell-mounted #app .feature-drawer-rail { translate: 64px 0; }
html.app-shell-mounted #app .maplibregl-control-container { translate: 0 -24px; }

/* The app-owned map remains full-screen until Map Focus exits. */
html.map-focus.app-shell-mounted #app {
  position: fixed;
  inset: 0;
  z-index: 2;
  display: block;
}
html.map-focus.app-shell-mounted #app .layout,
html.map-focus.app-shell-mounted #app .map-pane {
  position: absolute;
  inset: 0;
  display: block;
}
html:not(.map-focus).app-shell-mounted.app-enter-header #app .app-header,
html:not(.map-focus).app-shell-mounted.app-enter-camera #app .cam,
html:not(.map-focus).app-shell-mounted.app-enter-map-controls #app .maplibregl-control-container,
html:not(.map-focus).app-shell-mounted.app-enter-rail #app .feature-drawer-rail,
html:not(.map-focus).app-shell-mounted.app-entered #storage-overlay {
  opacity: 1;
  translate: 0 0;
}
html.welcome-handoff-loading .enter-map { pointer-events: none; }
/* The moment the visitor asks for the map, the splash stops intercepting the mouse.
   `welcome-handoff-loading` is set synchronously by openMap(), so this does NOT depend on
   the handoff completing — which matters, because .story-stage becomes interactive under
   `.map-settled` and only stopped under `.map-open`. Skip intro sets map-settled and then
   goes straight to the handoff, so an invisible (opacity:0) .story-shell was left sitting
   over the bottom ~40% of the map eating every click. Nothing the visitor cannot see is
   allowed to take input. */
html.welcome-handoff-loading .story-stage,
html.welcome-handoff-loading .brand-stage { pointer-events: none; }
html.welcome-handoff-active .brand-stage h1,
html.welcome-handoff-active .beat-world,
html.welcome-handoff-active .beat-modes,
html.welcome-handoff-active .beat-finale { will-change: translate, opacity; }
html.welcome-handoff-active .story-controls { opacity: 0; pointer-events: none; }

.story-stage {
  min-height: min(48svh, 540px);
  transform: none;
  transition: transform 1.05s cubic-bezier(.2,.78,.18,1), opacity .72s ease;
  background: linear-gradient(0deg, rgba(0, 0, 0, .96) 0%, rgba(0, 0, 0, .76) 54%, transparent 100%);
}
html.map-open .story-stage {
  opacity: 0;
  transform: translate3d(0, 110%, 0);
  pointer-events: none;
}
.story-shell {
  position: relative;
  width: min(92vw, 1740px);
  height: min(46svh, 520px);
  margin: 0 auto;
}
.story-beat {
  position: absolute;
  inset: auto 0 0;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 20px 0 72px;
  opacity: 0;
  visibility: hidden;
  transform: translate3d(0, 48px, 0);
  filter: blur(10px);
  transition: transform .8s cubic-bezier(.16,.82,.18,1), opacity .58s ease, filter .58s ease, visibility 0s linear .8s;
}
.story-beat.is-active {
  opacity: 1;
  visibility: visible;
  transform: translate3d(0, 0, 0);
  filter: none;
  transition-delay: 0s;
}
.story-beat.is-past { transform: translate3d(0, -24px, 0) scale(.97); }
.story-beat h2 { margin: 0; font-size: clamp(calc(66px * var(--sp)), 7.8vw, 150px); line-height: .8; letter-spacing: -.075em; text-wrap: balance; }
.story-beat > p:last-child { max-width: 880px; margin: 24px 0 0; color: #c0cad3; font-size: clamp(18px, 1.35vw, 26px); line-height: 1.45; }

.beat-plain { transform: scale(.68) rotateX(12deg); transform-origin: 50% 100%; }
.beat-plain.is-active { transform: none; }
.plain-claims { display: flex; align-items: center; flex-wrap: wrap; gap: clamp(14px, 2vw, 42px); }
.plain-claims strong { font-size: clamp(calc(38px * var(--sp)), 4.6vw, 88px); line-height: .9; letter-spacing: -.055em; }
.plain-claims strong:not(:last-child)::after { content: "·"; margin-left: clamp(14px, 2vw, 42px); color: rgba(255,255,255,.28); }
.beat-plain .plain-claims strong, .beat-plain h2 { opacity: 0; }
.beat-plain.is-active .plain-claims strong, .beat-plain.is-active h2 { animation: claim-pop .72s cubic-bezier(.16,.9,.18,1) both; }
.beat-plain.is-active .plain-claims strong:nth-child(2) { animation-delay: .14s; }
.beat-plain.is-active .plain-claims strong:nth-child(3) { animation-delay: .28s; }
.beat-plain.is-active h2 { animation-delay: .43s; }
@keyframes claim-pop { from { opacity: 0; transform: scale(.5) rotate(-5deg); } to { opacity: 1; transform: none; } }
.poop-claim { display: inline-flex; align-items: center; }
.poop-claim span { display: inline-block; margin-left: .1em; font-size: 1.55em; filter: drop-shadow(0 12px 16px rgba(0,0,0,.65)); transform: rotate(-8deg); }
.beat-plain h2 { margin-top: 17px; color: #67dfa8; word-spacing: .1em; }

.beat-world { transform: none; }
.feature-heading { margin-bottom: clamp(18px, 2vh, 28px) !important; color: #f4f7fa; font-size: clamp(calc(58px * var(--sp)), 5.75vw, 74px) !important; line-height: .9 !important; }
.feature-heading-line { display: inline-flex; align-items: baseline; gap: .14em; white-space: nowrap; transform-origin: 50% 50%; }
.feature-heading-world { color: #f4f7fa; }
.feature-heading-layer { display: inline-block; margin-block: -.1em; padding-block: .1em; color: transparent; background: linear-gradient(102deg, #b5e3ff, #91ffcd 56%, #ffdc92); background-clip: text; -webkit-background-clip: text; text-shadow: none; }
.activity-mesh {
  position: relative;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  grid-auto-rows: minmax(calc(145px * var(--sp)), 1fr);
  align-items: center;
  gap: 18px 36px;
  width: 100%;
  min-height: calc(510px * var(--sp));
  padding: 4px 0 12px;
}
.activity-mesh::before {
  content: "";
  position: absolute;
  inset: -8% -4%;
  background: radial-gradient(ellipse, rgba(2,7,12,.66), rgba(2,7,12,.3) 54%, transparent 74%);
  filter: blur(12px);
  pointer-events: none;
}
.activity-links { position: absolute; z-index: 0; inset: 0; width: 100%; height: 100%; overflow: visible; fill: none; stroke: rgba(190,222,237,.2); stroke-width: 1.3; stroke-dasharray: 1500; stroke-dashoffset: 1500; filter: drop-shadow(0 0 5px rgba(76,166,255,.28)); pointer-events: none; }
.activity-node {
  --activity-tone: #76bdff;
  --activity-x: 0px;
  --activity-y: 0px;
  --activity-r: 0deg;
  --activity-scale: 1;
  position: relative;
  z-index: 1;
  justify-self: center;
  display: grid;
  justify-items: center;
  gap: 5px;
  opacity: 0;
  transform: translate3d(var(--fly-x, -45vw), var(--fly-y, -24vh), 0) rotate(var(--fly-r, -28deg)) scale(1.65);
}
.activity-orb { display: grid; place-items: center; width: clamp(calc(104px * var(--sp)), 8.2vw, 132px); aspect-ratio: 1; border: 1px solid color-mix(in srgb, var(--activity-tone) 72%, rgba(255,255,255,.7)); border-radius: 50%; font-size: clamp(calc(64px * var(--sp)), 5.5vw, 88px); line-height: 1; background: radial-gradient(circle at 35% 27%, rgba(255,255,255,.98) 0 12%, rgba(249,252,253,.9) 33%, color-mix(in srgb, var(--activity-tone) 28%, rgba(235,242,246,.86)) 63%, rgba(14,22,29,.88) 100%); box-shadow: inset 0 0 32px rgba(255,255,255,.34), inset 0 -12px 28px color-mix(in srgb, var(--activity-tone) 30%, transparent), 0 0 34px color-mix(in srgb, var(--activity-tone) 55%, transparent), 0 20px 34px rgba(0,0,0,.4); filter: drop-shadow(0 7px 9px rgba(0,0,0,.52)) saturate(1.1); }
.activity-node strong { padding: 5px 12px 6px; border: 1px solid color-mix(in srgb, var(--activity-tone) 32%, transparent); border-radius: 999px; color: #f4f7fa; background: rgba(3,9,14,.72); box-shadow: 0 6px 18px rgba(0,0,0,.28); font-size: clamp(15px, 1.25vw, 21px); line-height: 1; letter-spacing: -.02em; }
.activity-node:nth-of-type(1) { --activity-tone:#76bdff; --fly-x:-48vw; --fly-y:-22vh; --fly-r:-30deg; --activity-x:-14px; --activity-y:8px; --activity-scale:1.08; --activity-delay:.08s; }
.activity-node:nth-of-type(2) { --activity-tone:#49d7e5; --fly-x:15vw; --fly-y:-48vh; --fly-r:24deg; --activity-x:12px; --activity-y:-18px; --activity-scale:.86; --activity-delay:.24s; }
.activity-node:nth-of-type(3) { --activity-tone:#f2a74c; --fly-x:55vw; --fly-y:-20vh; --fly-r:38deg; --activity-x:-12px; --activity-y:8px; --activity-scale:1; --activity-delay:.4s; }
.activity-node:nth-of-type(4) { --activity-tone:#67dfa8; --fly-x:-62vw; --fly-y:8vh; --fly-r:-26deg; --activity-x:15px; --activity-y:-16px; --activity-scale:1.12; --activity-delay:.56s; }
.activity-node:nth-of-type(5) { --activity-tone:#57d5da; --fly-x:68vw; --fly-y:11vh; --fly-r:32deg; --activity-x:-9px; --activity-y:12px; --activity-scale:.88; --activity-delay:.72s; }
.activity-node:nth-of-type(6) { --activity-tone:#f4b958; --fly-x:22vw; --fly-y:-50vh; --fly-r:-18deg; --activity-x:11px; --activity-y:-8px; --activity-scale:1.03; --activity-delay:.88s; }
.activity-node:nth-of-type(7) { --activity-tone:#ef8b61; --fly-x:-56vw; --fly-y:36vh; --fly-r:28deg; --activity-x:12px; --activity-y:7px; --activity-scale:.9; --activity-delay:1.04s; }
.activity-node:nth-of-type(8) { --activity-tone:#f0bf65; --fly-x:-10vw; --fly-y:52vh; --fly-r:-38deg; --activity-x:-15px; --activity-y:-6px; --activity-scale:1.12; --activity-delay:1.2s; }
.activity-node:nth-of-type(9) { --activity-tone:#67dfa8; --fly-x:48vw; --fly-y:42vh; --fly-r:34deg; --activity-x:10px; --activity-y:8px; --activity-scale:.92; --activity-delay:1.36s; }
.activity-node:nth-of-type(10) { --activity-tone:#8cb8ff; --fly-x:63vw; --fly-y:22vh; --fly-r:-25deg; --activity-x:-12px; --activity-y:-5px; --activity-scale:1.08; --activity-delay:1.52s; }
.activity-node:nth-of-type(11) { --activity-tone:#ef8b61; --fly-x:-30vw; --fly-y:50vh; --fly-r:20deg; --activity-x:14px; --activity-y:8px; --activity-scale:.88; --activity-delay:1.68s; }
.activity-node:nth-of-type(12) { --activity-tone:#d893ff; --fly-x:40vw; --fly-y:55vh; --fly-r:-34deg; --activity-x:-13px; --activity-y:-10px; --activity-scale:1.05; --activity-delay:1.84s; }
.activity-node:nth-of-type(13) { --activity-tone:#d893ff; --fly-x:-58vw; --fly-y:46vh; --fly-r:29deg; --activity-x:10px; --activity-y:10px; --activity-scale:.92; --activity-delay:2s; }
.activity-node:nth-of-type(14) { --activity-tone:#f4b958; --fly-x:8vw; --fly-y:58vh; --fly-r:-22deg; --activity-x:-8px; --activity-y:-8px; --activity-scale:1.06; --activity-delay:2.16s; }
.activity-node:nth-of-type(15) { --activity-tone:#58c7ff; --fly-x:60vw; --fly-y:48vh; --fly-r:36deg; --activity-x:13px; --activity-y:9px; --activity-scale:.96; --activity-delay:2.32s; }
.beat-world.is-active .activity-node { animation: activity-node-land .95s cubic-bezier(.12,.82,.16,1.08) both; animation-delay: var(--activity-delay); }
.beat-world.is-active .activity-links { animation: activity-mesh-draw 2.2s .65s ease forwards; }
@keyframes activity-node-land { 72% { opacity: 1; } 100% { opacity: 1; transform: translate3d(var(--activity-x), var(--activity-y), 0) rotate(var(--activity-r)) scale(var(--activity-scale)); } }
@keyframes activity-mesh-draw { to { stroke-dashoffset: 0; } }

html.features-pinned .beat-world.is-past .activity-node { opacity: 1; transform: translate3d(var(--activity-x), var(--activity-y), 0) rotate(var(--activity-r)) scale(var(--activity-scale)); }
html.features-pinned .beat-world.is-past .activity-links { stroke-dashoffset: 0; }
html.features-pinned .beat-finale { align-items: center; text-align: center; }
html.features-pinned .beat-finale h2 { font-size: clamp(calc(82px * var(--sp)), 8vw, 138px); }

.beat-contribute { transform: translate3d(-82vw, 0, 0) skewX(-10deg); }
.beat-contribute.is-active { transform: none; }
.beat-contribute h2 { color: #f4f7fa; }
.beat-contribute h2::after { content: " ADD YOURS."; color: #f4b958; }

.beat-modes { transform: none; }
.mode-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 1.5vw, 28px); perspective: 1200px; }
.mode-card { --mode-color: #76bdff; position: relative; min-height: clamp(calc(150px * var(--sp)), 17vh, 210px); display: grid; grid-template-columns: minmax(0, .9fr) minmax(120px, 1.1fr); align-items: center; overflow: hidden; padding: clamp(18px, 2vw, 30px); border: 1px solid color-mix(in srgb, var(--mode-color) 32%, transparent); border-radius: 20px; opacity: 0; background: linear-gradient(135deg, color-mix(in srgb, var(--mode-color) 14%, rgba(4,9,15,.88)), rgba(4,9,15,.8) 58%); box-shadow: inset 0 1px rgba(255,255,255,.09), 0 22px 55px rgba(0,0,0,.32); backdrop-filter: blur(16px); transform: translate3d(-40px, 60px, 0) rotateY(9deg); }
.mode-card::before { content: ""; position: absolute; inset: -50%; background: radial-gradient(circle, color-mix(in srgb, var(--mode-color) 18%, transparent), transparent 58%); transform: translate3d(35%, -20%, 0); pointer-events: none; }
.mode-card:nth-child(2) { --mode-color: #67dfa8; transform: translate3d(0, -70px, 0) rotateX(-10deg) scale(.84); }
.mode-card:nth-child(3) { --mode-color: #f4b958; transform: translate3d(60px, 55px, 0) rotateY(-9deg); }
.beat-modes.is-active .mode-card { animation: mode-card-land .9s cubic-bezier(.16,.84,.18,1) both; }
.beat-modes.is-active .mode-card:nth-child(2) { animation-delay: .16s; }
.beat-modes.is-active .mode-card:nth-child(3) { animation-delay: .32s; }
@keyframes mode-card-land { to { opacity: 1; transform: none; } }
.mode-copy { position: relative; z-index: 2; display: flex; flex-direction: column; gap: 15px; }
.mode-grid b { color: var(--mode-color); font-size: clamp(25px, 2.3vw, 44px); }
.mode-grid strong { font-size: clamp(24px, 2.3vw, 44px); line-height: .94; letter-spacing: -.045em; }
.mode-graphic { position: relative; z-index: 2; width: 100%; max-height: 130px; overflow: visible; color: var(--mode-color); fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.mode-map-grid { opacity: .2; stroke-width: 1; }
.mode-route { stroke-width: 6; stroke-dasharray: 220; stroke-dashoffset: 220; filter: drop-shadow(0 0 7px currentColor); }
.mode-route-points { fill: #071019; stroke-width: 4; opacity: 0; }
.mode-contours { opacity: .3; stroke-width: 2; }
.mode-mountain-back { fill: color-mix(in srgb, var(--mode-color) 12%, transparent); opacity: .5; stroke-width: 2; }
.mode-mountain { fill: color-mix(in srgb, var(--mode-color) 22%, transparent); stroke-width: 4; filter: drop-shadow(0 0 7px currentColor); }
.mode-ridge { opacity: .8; stroke-width: 2; }
.mode-orbit { opacity: .55; stroke-width: 2; }
.mode-crosshair { stroke-width: 3; }
.mode-scan { fill: color-mix(in srgb, var(--mode-color) 24%, transparent); stroke: none; transform-origin: 98px 60px; opacity: 0; }
.mode-pixel { fill: currentColor; stroke: none; filter: drop-shadow(0 0 9px currentColor); opacity: 0; }
.beat-modes.is-active .mode-route { animation: mode-route-draw 1.35s .7s cubic-bezier(.2,.7,.2,1) forwards; }
.beat-modes.is-active .mode-route-points { animation: mode-graphic-pop .45s 1.6s ease forwards; }
.beat-modes.is-active .mode-mountain { animation: mode-mountain-rise 1s .85s cubic-bezier(.16,.84,.18,1) both; transform-origin: 50% 100%; }
.beat-modes.is-active .mode-scan { animation: mode-scan 1.8s .95s cubic-bezier(.2,.7,.2,1) forwards; }
.beat-modes.is-active .mode-pixel { animation: mode-graphic-pop .45s 1.7s ease forwards; }
@keyframes mode-route-draw { to { stroke-dashoffset: 0; } }
@keyframes mode-graphic-pop { to { opacity: 1; } }
@keyframes mode-mountain-rise { from { opacity: 0; transform: scaleY(.2); } }
@keyframes mode-scan { 0% { opacity: 0; transform: rotate(-90deg); } 20% { opacity: 1; } 100% { opacity: .7; transform: rotate(230deg); } }

.beat-finale { padding-bottom: 72px; transform: scale(calc(1 + .28 * var(--sp))); transform-origin: 0 100%; }
.beat-finale.is-active { transform: none; }
.beat-finale h2 { font-size: clamp(calc(70px * var(--sp)), 8vw, 154px); }
.beat-finale h2 span { display: inline-block; color: transparent; background: linear-gradient(102deg, #76bdff, #67dfa8 56%, #f4b958); background-clip: text; -webkit-background-clip: text; font-size: 1.16em; transform: scaleX(1.18); transform-origin: 50% 50%; }
.beat-finale > p:last-of-type { margin-top: 18px; }
/* THE call to action. Lives at BODY level (index.html), not inside .beat-finale, and it
   rests BELOW the viewport centre; `html.finale-active` lifts it in. James 2026-08-11:
   "appears at the bottom, then jumps to the middle — animate it to the middle instead."
   It was jumping because `position: fixed` only means "the viewport" while NO ancestor is
   transformed or filtered, and .story-beat is both: a scale easing to none over .8s and a
   blur(10px) easing to none over .58s. Until those land the beat is the containing block,
   so `inset: 50%/50%` centred the button on the animating beat box (measured x1364 on a
   1280 viewport); the frame they hit `none`, the containing block became the viewport and
   the button teleported. No rule inside that subtree can fix it — a transition TO
   `transform: none` still passes through transformed values, which is why three attempts
   at overriding .beat-finale did nothing. Moving the element out is the whole fix. */
.final-actions {
  position: fixed;
  z-index: 5;                          /* over .story-stage (4), under .intro-tools (6) */
  inset: 50% auto auto 50%;
  margin: 0;
  /* `display: flex` is asserted rather than inherited: the phone rule below turns this
     into a 2-column grid for the (currently commented-out) support link, which left the
     lone button sitting in the left half of a centred box. */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  opacity: 0;
  pointer-events: none;
  transform: translate3d(-50%, calc(-50% + 26svh), 0) scale(.86);
  transition: opacity .46s ease, transform .78s cubic-bezier(.16,.86,.18,1);
}
.final-actions a { min-height: 58px; display: inline-flex; align-items: center; justify-content: center; padding: 0 25px; border-radius: 999px; font-size: 17px; font-weight: 800; text-decoration: none; }
.enter-map { color: #03100a; background: #f3f6f8; box-shadow: 0 16px 44px rgba(0,0,0,.38); }
.support-map { color: #f3f6f8; border: 1px solid rgba(255,255,255,.24); background: rgba(255,255,255,.07); }
html.features-pinned .beat-finale > p:last-of-type { max-width: none; margin-top: 22px; font-size: clamp(19px, 1.35vw, 25px); text-align: center; }
/* ONE panel holds every splash control. It sits BELOW the wordmark band rather than in
   the top corner, because --brand-band is where LANDMAX's ink ends — above that line
   there is no room for a two-row panel at any viewport. Rows stack, so the panel never
   competes with the wordmark for width. */
.intro-tools {
  position: fixed;
  z-index: 6;
  top: calc(var(--brand-band) + 12px);
  right: max(16px, env(safe-area-inset-right));
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 5px;
  border: 1px solid rgba(255,255,255,.15);
  border-radius: 26px;
  background: rgba(5,10,16,.76);
  box-shadow: 0 12px 36px rgba(0,0,0,.38);
  backdrop-filter: blur(16px);
  transition: opacity .45s ease;
}
/* Rows are bare — .intro-tools owns the one surface. */
.intro-tools-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
}
.reset-site,
.skip-intro {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  font: 700 14px/1 var(--font);
  cursor: pointer;
  transition: opacity .45s ease, background .2s ease, color .2s ease;
}
/* Skip is what most visitors reach for, so it carries the brighter ink; Reset is the
   rare, deliberate escape hatch and stays quiet at the outboard edge. */
.reset-site { color: #aab7c2; }
.skip-intro { color: #f3f6f8; }
.skip-intro span { font-size: 16px; }
.reset-site:hover,
.skip-intro:hover { color: #fff; background: rgba(255,255,255,.1); }
.reset-site:disabled { cursor: progress; color: var(--ink-dim); background: transparent; }
/* Hairline between the segments, drawn by the pair rather than by either button, and
   only once Skip is actually there to be divided from. */
html.map-built .skip-intro::before {
  content: "";
  position: absolute;
  top: 50%;
  left: -1px;
  width: 1px;
  height: 20px;
  translate: 0 -50%;
  background: rgba(255,255,255,.14);
}
/* Reset is the escape hatch from a broken cached shell, so it is never gated on the
   map having built. Skip has nothing to skip to until then. */
.skip-intro { opacity: 0; pointer-events: none; }
html.map-built .skip-intro { opacity: 1; pointer-events: auto; }
html.map-open .intro-tools,
html.welcome-handoff-loading .intro-tools,
html.content-open .intro-tools { opacity: 0; pointer-events: none; transition: opacity .45s ease; }
/* Hiding the CLUSTER is not enough. `pointer-events: none` on a parent is undone by any
   descendant that asserts `auto`, and both of these do (.skip-intro on map-built,
   .story-controls on map-settled) — so a faded-out control would still swallow clicks
   over the live map. Nothing the visitor cannot see is allowed to take input. */
html.map-open .skip-intro,
html.map-open .story-controls,
html.welcome-handoff-loading .skip-intro,
html.welcome-handoff-loading .story-controls,
html.content-open .skip-intro,
html.content-open .story-controls { pointer-events: none; }

/* Playback is the panel's second row (James 2026-08-04: "the layout is vertically
   challenged, so move the play controls to join the other controls in the top right").
   It used to be fixed at bottom-centre, where at viewport heights around 1050 px the
   finale's Open map button overflowed its grid row straight onto it.
   There is nothing to play until the map settles, so the row COLLAPSES rather than
   fading in place — the panel grows to meet it instead of reserving an empty strip. */
.story-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 0;
  margin-top: 0;
  border-top: 1px solid transparent;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  transition: height .5s cubic-bezier(.16,.82,.18,1), margin-top .5s cubic-bezier(.16,.82,.18,1),
              padding-top .5s cubic-bezier(.16,.82,.18,1), opacity .4s ease .1s, border-color .4s ease;
}
/* 44 = the 38px button row + 5px padding + the 1px rule (border-box). */
.map-settled .story-controls {
  height: 44px;
  margin-top: 5px;
  padding-top: 5px;
  border-top-color: rgba(255,255,255,.14);
  opacity: 1;
  pointer-events: auto;
}

html.app-shell-mounted #map {
  position: absolute;
  inset: 0;
  z-index: auto;
  opacity: 1;
  transform: none;
  will-change: auto;
}
.story-controls button { width: 38px; height: 38px; display: grid; place-items: center; border: 0; border-radius: 50%; padding: 0; color: #dfe8ee; background: transparent; font: 800 23px/1 var(--font); cursor: pointer; }
.story-controls button:hover { color: #fff; background: rgba(255,255,255,.1); }
.story-controls .story-play { color: #07110b; background: #f3f6f8; font-size: 16px; }
.story-controls .story-play:hover { color: #07110b; background: #fff; }
.story-controls output { min-width: 58px; padding: 0 10px 0 6px; color: #aab7c2; font: 750 13px/1 ui-monospace, SFMono-Regular, Menlo, monospace; text-align: center; }
a:focus-visible, button:focus-visible { outline: 3px solid var(--blue); outline-offset: 4px; }

/* About + Docs stay inside the living world. The standalone Astro URLs remain
   the no-JS/direct-entry fallback; these sheets own in-shell navigation. */
.content-overlay {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  justify-items: end;
  pointer-events: none;
}
.content-overlay[hidden] { display: none; }
.content-scrim {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background:
    radial-gradient(circle at 24% 45%, rgba(76, 166, 255, .08), transparent 34%),
    rgba(3, 9, 5, .18);
  opacity: 0;
  backdrop-filter: blur(0);
  transition: opacity .42s ease, backdrop-filter .42s ease;
  cursor: w-resize;
}
.content-sheet {
  --content-width: min(68vw, 1180px);
  --content-progress: 0%;
  position: relative;
  width: var(--content-width);
  min-width: min(620px, 94vw);
  height: 100%;
  overflow: hidden;
  border-left: 1px solid rgba(231, 240, 233, .16);
  background:
    linear-gradient(135deg, rgba(30, 67, 45, .22), transparent 25%),
    rgba(8, 21, 13, .91);
  box-shadow: -38px 0 120px rgba(0, 0, 0, .52);
  backdrop-filter: blur(30px) saturate(1.18);
  transform: translate3d(104%, 0, 0);
  transition: transform .62s cubic-bezier(.18, .82, .18, 1);
  isolation: isolate;
}
.content-overlay.is-open { pointer-events: auto; }
html.content-open .story-stage { opacity: 0; pointer-events: none; transition-duration: .32s; }
.content-overlay.is-open .content-scrim { opacity: 1; backdrop-filter: blur(2px) saturate(.88); }
.content-overlay.is-open .content-sheet { transform: translate3d(0, 0, 0); }
.content-sheet::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(rgba(231,240,233,.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(231,240,233,.025) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: linear-gradient(90deg, #000, transparent 78%);
}
.content-resizer {
  position: absolute;
  z-index: 5;
  inset: 0 auto 0 -10px;
  width: 20px;
  border: 0;
  padding: 0;
  background: transparent;
  cursor: ew-resize;
  touch-action: none;
}
.content-resizer::after {
  content: "";
  position: absolute;
  top: 45%;
  left: 8px;
  width: 3px;
  height: 74px;
  border-radius: 3px;
  background: rgba(231, 240, 233, .25);
  box-shadow: 0 0 0 1px rgba(3, 9, 5, .45);
  transition: background .2s ease, height .2s ease;
}
.content-resizer:hover::after, .content-resizer:focus-visible::after { height: 96px; background: var(--green); }
.content-progress {
  position: absolute;
  z-index: 6;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: rgba(231,240,233,.08);
}
.content-progress i { display: block; width: var(--content-progress); height: 100%; background: linear-gradient(90deg, var(--blue), var(--green), var(--amber)); transition: width .08s linear; }
.content-toolbar {
  position: absolute;
  z-index: 4;
  inset: 0 0 auto 0;
  min-height: 86px;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: clamp(20px, 2vw, 40px);
  padding: 16px clamp(28px, 3.4vw, 64px);
  border-bottom: 1px solid rgba(231, 240, 233, .1);
  background: rgba(8, 21, 13, .72);
  backdrop-filter: blur(22px);
}
.content-brand { display: flex; align-items: center; gap: 10px; color: var(--ink); text-decoration: none; font-size: 20px; font-weight: 780; }
.content-brand svg { width: 29px; height: 29px; }
.content-section-nav { display: flex; justify-content: center; gap: 6px; }
.content-section-link { min-width: 88px; padding: 9px 15px; border-radius: 999px; color: var(--ink-dim); text-align: center; text-decoration: none; font-size: 15px; font-weight: 720; }
.content-section-link:hover, .content-section-link:focus-visible { color: var(--ink); }
.content-section-link[aria-current="page"] { color: var(--ink); background: rgba(231, 240, 233, .09); box-shadow: inset 0 0 0 1px rgba(231,240,233,.11); }
.content-close { display: flex; align-items: center; gap: 12px; min-height: 42px; border: 0; padding: 0; color: var(--ink-dim); background: transparent; font: inherit; font-size: 15px; font-weight: 700; cursor: pointer; }
.content-close:hover, .content-close:focus-visible { color: var(--ink); }
.content-close i { position: relative; width: 38px; height: 38px; border: 1px solid rgba(231,240,233,.16); border-radius: 50%; background: rgba(231,240,233,.04); }
.content-close i::before, .content-close i::after { content: ""; position: absolute; top: 18px; left: 11px; width: 15px; height: 2px; border-radius: 2px; background: currentColor; transform: rotate(45deg); }
.content-close i::after { transform: rotate(-45deg); }
.content-scroll { height: 100%; overflow: auto; overscroll-behavior: contain; scrollbar-color: rgba(91,208,139,.55) transparent; }
.content-body { width: min(100% - clamp(calc(56px * var(--sp)), 8vw, 132px), 1040px); margin: 0 auto; padding: clamp(calc(150px * var(--sp)), 15vh, 210px) 0 clamp(calc(92px * var(--sp)), 10vh, 150px); }
.content-hero { max-width: 900px; }
.content-hero, .content-proof-grid, .content-chapters, .content-closing { animation: content-rise .7s cubic-bezier(.18,.82,.18,1) both; }
.content-proof-grid { animation-delay: .06s; }
.content-chapters { animation-delay: .11s; }
.content-closing { animation-delay: .14s; }
@keyframes content-rise { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: translateY(0); } }
.content-meta { display: flex; align-items: center; gap: 18px; margin-bottom: 24px; }
.content-index { width: 52px; height: 30px; display: grid; place-items: center; border: 1px solid rgba(91,208,139,.34); border-radius: 999px; color: var(--green); font: 780 14px/1 ui-monospace, SFMono-Regular, Menlo, monospace; }
.content-kicker { color: var(--green); font-size: clamp(14px, .9vw, 17px); font-weight: 820; letter-spacing: .18em; }
.content-hero h2 { max-width: 920px; margin: 0; font-size: clamp(calc(58px * var(--sp)), 5.2vw, 104px); line-height: .94; letter-spacing: -.058em; text-wrap: balance; }
.content-hero h2:focus { outline: none; }
.content-lede { max-width: 850px; margin: 34px 0 0; color: #c4d4ca; font-size: clamp(21px, 1.55vw, 30px); line-height: 1.45; text-wrap: balance; }
.content-proof-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 15px; margin: clamp(calc(62px * var(--sp)), 8vh, 100px) 0 clamp(calc(90px * var(--sp)), 12vh, 150px); }
.content-proof { position: relative; min-height: calc(290px * var(--sp)); overflow: hidden; padding: clamp(22px, 2vw, 31px); border: 1px solid rgba(231,240,233,.13); border-radius: 20px; background: rgba(231,240,233,.045); }
.content-proof::after { content: ""; position: absolute; inset: auto -30% -48% 20%; height: 70%; border-radius: 50%; filter: blur(44px); opacity: .18; }
.content-proof.tone-blue::after { background: var(--blue); }
.content-proof.tone-green::after { background: var(--green); }
.content-proof.tone-amber::after { background: var(--amber); }
.proof-mark { position: relative; z-index: 2; color: var(--ink-dim); font-size: 12px; font-weight: 830; letter-spacing: .14em; }
.proof-graphic { position: relative; z-index: 2; width: 82px; height: 64px; margin: 25px 0 30px; }
.proof-graphic i { position: absolute; display: block; border: 1px solid currentColor; opacity: .7; }
.proof-graphic i:nth-child(1) { inset: 4px 16px 4px 16px; border-radius: 50%; }
.proof-graphic i:nth-child(2) { inset: 11px 4px 11px 4px; border-radius: 50%; }
.proof-graphic i:nth-child(3) { left: 40px; top: 0; width: 1px; height: 64px; border-width: 0 0 0 1px; transform: rotate(28deg); }
.proof-graphic i:nth-child(4) { left: 4px; top: 31px; width: 74px; height: 1px; border-width: 1px 0 0; transform: rotate(-8deg); }
.proof-graphic[data-tone="blue"] { color: var(--blue); }
.proof-graphic[data-tone="green"] { color: var(--green); }
.proof-graphic[data-tone="amber"] { color: var(--amber); }
.content-proof h3 { position: relative; z-index: 2; margin: 0 0 10px; font-size: clamp(20px, 1.3vw, 25px); letter-spacing: -.02em; }
.content-proof p { position: relative; z-index: 2; margin: 0; color: var(--ink-dim); font-size: 16px; line-height: 1.52; }
.content-chapters { border-top: 1px solid rgba(231,240,233,.12); }
.content-chapter { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: clamp(28px, 4vw, 66px); padding: clamp(calc(56px * var(--sp)), 7vh, 88px) 0; border-bottom: 1px solid rgba(231,240,233,.12); }
.chapter-number { color: var(--green); font: 760 14px/1 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .08em; padding-top: 9px; }
.chapter-copy { max-width: 780px; }
.chapter-copy h3 { margin: 0 0 25px; font-size: clamp(32px, 2.5vw, 50px); line-height: 1.04; letter-spacing: -.04em; }
.chapter-copy p { margin: 0 0 19px; color: #bdcec3; font-size: clamp(18px, 1.2vw, 22px); line-height: 1.65; }
.chapter-links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 28px; }
.chapter-links a { padding: 10px 15px; border: 1px solid rgba(231,240,233,.14); border-radius: 999px; color: var(--ink); background: rgba(231,240,233,.05); text-decoration: none; font-size: 15px; font-weight: 700; }
.chapter-links a:hover, .chapter-links a:focus-visible { border-color: var(--green); background: rgba(91,208,139,.1); }
.content-closing { padding: clamp(calc(90px * var(--sp)), 12vh, 150px) 0 20px; }
.content-closing blockquote { max-width: 880px; margin: 0; color: var(--ink); font-size: clamp(calc(42px * var(--sp)), 4vw, 78px); font-weight: 760; line-height: 1.02; letter-spacing: -.05em; text-wrap: balance; }
.content-closing blockquote::before { content: "“"; display: block; height: 40px; color: var(--green); font-size: 80px; line-height: 1; }
.content-actions { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 50px; }
.content-actions a { min-height: 56px; display: inline-flex; align-items: center; justify-content: center; padding: 0 24px; border-radius: 12px; text-decoration: none; font-size: 17px; font-weight: 760; }
.content-primary { color: #07110b; background: var(--ink); }
.content-primary:hover, .content-primary:focus-visible { background: #fff; transform: translateY(-1px); }
.content-secondary { color: var(--ink); border: 1px solid rgba(231,240,233,.17); background: rgba(231,240,233,.05); }

@media (max-width: 1000px) {
  .story-stage { min-height: min(54svh, 510px); }
  .story-shell { height: min(52svh, 490px); }
  .story-beat h2 { font-size: clamp(calc(58px * var(--sp)), 10vw, 105px); }
  .plain-claims strong { font-size: clamp(30px, 5.7vw, 58px); }
  .content-sheet { --content-width: calc(100vw - 28px); min-width: 0; }
  .content-resizer { display: none; }
  .content-proof-grid { grid-template-columns: 1fr; }
  .content-proof { min-height: 220px; }
  .content-proof-grid .proof-graphic { position: absolute; top: 35px; right: 28px; opacity: .55; }
}

@media (max-width: 620px) {
  .brand-locked .brand-stage h1 { scale: .92; }
  .story-stage { min-height: 60svh; }
  .story-shell { width: calc(100vw - 28px); height: 58svh; }
  .story-beat { padding-bottom: 62px; }
  .story-beat h2 { font-size: clamp(calc(53px * var(--sp)), 17vw, 78px); line-height: .86; }
  .story-beat > p:last-child { margin-top: 16px; font-size: 17px; }
  .plain-claims { align-items: flex-start; flex-direction: column; gap: 5px; }
  .plain-claims strong { font-size: clamp(32px, 10.5vw, 48px); }
  .plain-claims strong:not(:last-child)::after { content: none; }
  .poop-claim span { position: absolute; right: 2vw; bottom: 1vh; font-size: 3.25em; opacity: .92; }
  .beat-plain h2 { margin-top: 12px; }
  .feature-heading { margin-bottom: 8px !important; font-size: clamp(29px, 8.6vw, 38px) !important; }
  .beat-contribute h2::after { display: block; margin-top: .08em; }
  .mode-grid { grid-template-columns: 1fr; gap: 6px; }
  .mode-card { min-height: 66px; grid-template-columns: minmax(0, 1fr) 98px; padding: 9px 14px; border-radius: 13px; }
  .mode-copy { gap: 3px; }
  .mode-graphic { max-height: 62px; }
  .mode-grid b { font-size: 22px; }
  .mode-grid strong { font-size: 25px; }
  .beat-finale h2 { font-size: clamp(calc(58px * var(--sp)), 18vw, 80px); }
  .beat-finale > p:last-of-type { max-width: 330px; font-size: 16px; }
  .final-actions a { min-height: 48px; padding: 0 14px; font-size: 14px; }
  .story-controls button { width: 36px; height: 36px; font-size: 22px; }
  .story-controls output { min-width: 44px; padding-right: 6px; font-size: 12px; }
  .content-sheet { --content-width: 100vw; border-left: 0; }
  .content-toolbar { min-height: 72px; grid-template-columns: auto 1fr auto; gap: 10px; padding: 12px 17px; }
  .content-brand span, .content-close span { display: none; }
  .content-section-nav { justify-content: end; }
  .content-section-link { min-width: 65px; padding: 8px 10px; font-size: 14px; }
  .content-close i { width: 36px; height: 36px; }
  .content-body { width: calc(100% - 36px); padding: 116px 0 80px; }
  .content-hero h2 { font-size: clamp(calc(48px * var(--sp)), 14vw, 68px); }
  .content-lede { font-size: 20px; }
  .content-proof-grid { margin: 54px 0 78px; }
  .content-proof { min-height: 230px; padding: 22px; }
  .content-proof-grid .proof-graphic { position: relative; top: auto; right: auto; margin: 20px 0 24px; }
  .content-chapter { grid-template-columns: 42px minmax(0, 1fr); gap: 12px; padding: 48px 0; }
  .chapter-copy h3 { font-size: 32px; }
  .chapter-copy p { font-size: 17px; line-height: 1.58; }
  .content-closing blockquote { font-size: 42px; }
  .content-actions { display: grid; }
  .content-actions a { width: 100%; }
}

/* The finished story is one responsive stage. The brand owns the reserved top
   band; the showcase, modes, and finale own real grid rows beneath it. Nothing
   is positioned relative to an unrelated viewport edge, and the activity art
   sizes from its actual container rather than height-specific scale patches. */
html.features-pinned .story-stage {
  inset: 0;
  min-height: 100svh;
  background: linear-gradient(0deg, rgba(0,0,0,.96) 0%, rgba(0,0,0,.68) 31%, rgba(0,0,0,.16) 64%, transparent 82%);
}
html.features-pinned .story-shell {
  /* --brand-band (index.html <head>) is the height the locked wordmark owns; the top
     of the showcase is simply the bottom of that band. The control band is now only
     breathing room — the playback pill moved to the top-right cluster, so the stage no
     longer has to reserve a pill's worth of height at the bottom. */
  --showcase-brand-band: var(--brand-band);
  --showcase-control-band: max(26px, 2.6svh);
  --showcase-gap: clamp(8px, 1.2svh, 20px);
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr) clamp(140px, 17svh, 210px) 0;
  gap: var(--showcase-gap);
  width: 100%;
  height: 100%;
  margin: 0;
  padding: var(--showcase-brand-band) clamp(12px, 4vw, 64px) var(--showcase-control-band);
  transition: grid-template-rows .8s cubic-bezier(.16,.82,.18,1);
}
html.finale-active .story-shell {
  grid-template-rows: minmax(0, 1fr) clamp(calc(78px * var(--sp)), 10.5svh, 150px) clamp(calc(210px * var(--sp)), 24svh, 320px);
}
html.features-pinned .story-beat {
  grid-column: 1;
  position: relative;
  inset: auto;
  width: min(100%, 1680px);
  min-height: 0;
  height: 100%;
  margin-inline: auto;
  padding: 0;
  transform: none;
}
html.features-pinned .beat-world,
html.features-pinned .beat-world.is-active,
html.features-pinned .beat-world.is-past {
  grid-row: 1;
  width: min(100%, 1440px);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  gap: clamp(8px, 1.2cqh, 18px);
  border: 0;
  border-radius: 0;
  opacity: 1;
  visibility: visible;
  background: transparent;
  box-shadow: none;
  backdrop-filter: none;
  filter: none;
  container-type: size;
}
html.features-pinned .feature-heading {
  grid-column: 1;
  grid-row: 1;
  position: relative;
  inset: auto;
  margin: 0 !important;
  font-size: clamp(38px, min(6vw, 23cqh), 96px) !important;
  line-height: .9 !important;
  text-align: center;
  text-shadow: 0 6px 24px rgba(0,0,0,.86);
}
html.features-pinned .feature-heading-line {
  display: inline-flex;
  max-width: 100%;
  transform: none;
}
html.features-pinned .activity-mesh {
  grid-column: 1;
  grid-row: 2;
  grid-auto-rows: minmax(0, 1fr);
  min-height: 0;
  height: 100%;
  gap: clamp(4px, 1.3cqh, 18px) clamp(8px, 2vw, 36px);
  padding: 0;
}
html.features-pinned .activity-orb {
  width: clamp(calc(56px * var(--sp)), min(8.4vw, 19cqh), 132px);
  font-size: clamp(calc(39px * var(--sp)), min(5.5vw, 17cqh), 88px);
}
html.features-pinned .activity-node { gap: clamp(2px, .5cqh, 5px); }
html.features-pinned .activity-node strong {
  padding: clamp(3px, .45cqh, 5px) clamp(7px, .8vw, 12px) clamp(4px, .55cqh, 6px);
  font-size: clamp(13px, min(1.25vw, 4cqh), 21px);
}
html.features-pinned .beat-contribute,
html.features-pinned .beat-modes,
html.features-pinned .beat-plain { grid-row: 2; }
html.features-pinned .beat-finale { grid-row: 3; }
html.features-pinned .story-beat:not(.beat-world) { justify-content: center; }
html.features-pinned .story-beat:not(.beat-world) h2 { font-size: clamp(calc(58px * var(--sp)), 6.5vw, 112px); }

html.modes-pinned .beat-modes,
html.modes-pinned .beat-modes.is-active,
html.modes-pinned .beat-modes.is-past {
  opacity: 1;
  visibility: visible;
  filter: none;
}
html.modes-pinned .beat-modes.is-past .mode-card {
  opacity: 1;
  transform: none;
  animation: none;
}
html.modes-pinned .beat-modes.is-past .mode-route { stroke-dashoffset: 0; }
html.modes-pinned .beat-modes.is-past .mode-route-points,
html.modes-pinned .beat-modes.is-past .mode-pixel { opacity: 1; }
html.modes-pinned .beat-modes.is-past .mode-mountain { opacity: 1; transform: none; }
html.modes-pinned .beat-modes.is-past .mode-scan { opacity: .7; transform: rotate(230deg); }

html.features-pinned .beat-modes .mode-grid { height: 100%; }
html.features-pinned .beat-modes .mode-card {
  height: 100%;
  min-height: 0;
}
html.finale-active .beat-modes .mode-card {
  padding: clamp(8px, 1svh, 12px) clamp(10px, 1.4vw, 22px);
  border-radius: 16px;
  grid-template-columns: minmax(0, 1.05fr) minmax(72px, .95fr);
}
html.finale-active .beat-modes .mode-copy { gap: clamp(2px, .5svh, 6px); }
html.finale-active .beat-modes .mode-grid b { font-size: clamp(17px, min(1.7vw, 2.5svh), 30px); }
html.finale-active .beat-modes .mode-grid strong { font-size: clamp(17px, min(1.85vw, 2.7svh), 32px); }
html.finale-active .beat-modes .mode-graphic { max-height: min(72px, 8svh); }
html.finale-active .beat-finale,
html.finale-active .beat-finale.is-active {
  width: min(92vw, 1100px);
  justify-content: center;
  opacity: 1;
  visibility: visible;
  filter: none;
}
html.finale-active .beat-finale h2 { font-size: clamp(calc(54px * var(--sp)), min(6.2vw, 10svh), 106px); }
html.finale-active .beat-finale > p:last-of-type { margin-top: 10px; font-size: clamp(15px, 1.15vw, 20px); }

/* THE call to action arrives. James 2026-08-04: "The Open map button should appear in the
   center, larger and overtop the existing center content (the activity circles)."
   Centred on the VIEWPORT rather than on the constellation because no rule can read
   another element's box — measured, viewport centre lands inside the mesh at every size
   from 1280x800 up. The rise is a TRANSITION off the resting state in the base rule, not
   a keyframe: transitions interrupt cleanly if the visitor clicks Skip mid-lift, and the
   reduced-motion `transition-duration: .001ms` sweep at the foot of this sheet turns the
   whole thing into a cut for free. */
html.finale-active .final-actions {
  opacity: 1;
  pointer-events: auto;
  transform: translate3d(-50%, -50%, 0) scale(1);
}
/* Nothing outruns the button leaving: it is no longer inside .story-stage, so it does not
   ride the stage's slide-out and needs its own exit. */
html.map-open .final-actions,
html.content-open .final-actions { opacity: 0; pointer-events: none; }
/* The scrim rides WITH the button instead of covering the stage, so the constellation
   stays visible around it. `.final-actions` is transformed, so it already owns a
   stacking context and z-index:-1 sits behind the button without escaping it. */
html.finale-active .final-actions::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -190% -70%;
  background: radial-gradient(ellipse, rgba(2,7,12,.94), rgba(2,7,12,.62) 44%, transparent 72%);
  pointer-events: none;
}
html.finale-active .enter-map {
  min-height: clamp(64px, 7.5svh, 92px);
  padding: 0 clamp(34px, 3.4vw, 62px);
  font-size: clamp(21px, 1.7vw, 32px);
  letter-spacing: -.015em;
  box-shadow: 0 0 0 1px rgba(255,255,255,.55), 0 26px 70px rgba(0,0,0,.62), 0 0 90px rgba(118,189,255,.4);
}
html.finale-active .enter-map:hover { background: #fff; }
/* The content behind the call to action steps back. DIMMED, not blurred: a blur over a
   region this size is exactly the cost that hurt the old iMac which reported this bug
   ([[topics/app-v4-performance]]), and opacity is composited for free. The .is-past
   selectors match the specificity of the features-pinned/modes-pinned rules that pin
   these beats visible, and win by coming later. */
html.finale-active .beat-world.is-past,
html.finale-active .beat-modes.is-past {
  opacity: .3;
  transition: opacity .55s ease;
}

@media (max-aspect-ratio: 6 / 5) {
  /* Narrow/tall finales have denser rows, so the decorative constellation
     offsets yield to the grid cells instead of reducing the whole showcase. */
  html.finale-active .activity-node {
    --activity-y: 0px;
    --activity-scale: 1;
  }
}

/* Short landscape is the one desktop composition change: finale beside the
   constellation, modes below. Every region remains a real grid area. */
@media (min-width: 800px) and (max-height: 900px) and (min-aspect-ratio: 6 / 5) {
  html.finale-active .story-shell {
    grid-template-columns: minmax(0, 1fr) clamp(300px, 29vw, 430px);
    grid-template-rows: minmax(0, 1fr) clamp(calc(78px * var(--sp)), 10.5svh, 100px);
    column-gap: clamp(14px, 1.6vw, 24px);
  }
  html.finale-active .beat-world { grid-column: 1; grid-row: 1; }
  html.finale-active .beat-modes { grid-column: 1 / 3; grid-row: 2; }
  html.finale-active .story-shell > .beat-finale {
    grid-column: 2;
    grid-row: 1;
    width: auto;
    min-width: 0;
    margin-inline: 0;
    justify-self: stretch;
    /* This is the ONE composition where something of ours shares row 1's right edge with
       the playback pill, so it starts below it (pill = 48px + gap). Measured at 1280x800:
       without this the finale heading ran under the controls. */
    padding-top: 58px;
  }
  html.finale-active .beat-finale h2 { font-size: clamp(calc(58px * var(--sp)), min(5.5vw, 10svh), 84px); }
}

/* Phones keep the same stage contract, with a four-column constellation and
   compact mode summaries; no viewport-specific absolute coordinates. */
@media (max-width: 620px) {
  html.features-pinned .story-shell {
    /* --brand-band under-reserves at phone font sizes (the wordmark's ink overflows a
       very short line box by proportionally more), and playback stays at the bottom
       here, so the control band keeps its full height. */
    --showcase-brand-band: max(100px, var(--brand-band));
    --showcase-control-band: 72px;
    grid-template-rows: minmax(0, 1fr) clamp(calc(210px * var(--sp)), 28svh, 250px) 0;
    padding-inline: 12px;
  }
  html.finale-active .story-shell { grid-template-rows: minmax(0, 1fr) 68px clamp(calc(184px * var(--sp)), 23svh, 220px); }
  html.features-pinned .activity-mesh { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2px; }
  html.features-pinned .activity-links { display: none; }
  html.features-pinned .activity-node { --activity-x:0px; --activity-y:0px; --activity-r:0deg; --activity-scale:1; gap: 1px; }
  html.features-pinned .activity-orb { width: clamp(calc(48px * var(--sp)), min(15vw, 20cqh), 62px); font-size: clamp(34px, min(10vw, 14cqh), 44px); }
  html.features-pinned .activity-node strong { padding: 3px 6px 4px; font-size: 12px; }
  html.finale-active .beat-modes .mode-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 5px; }
  html.finale-active .beat-modes .mode-card { display: block; padding: 9px; }
  html.finale-active .beat-modes .mode-copy { gap: 2px; }
  html.finale-active .beat-modes .mode-grid b { font-size: 15px; }
  html.finale-active .beat-modes .mode-grid strong { font-size: 15px; }
  html.finale-active .beat-modes .mode-graphic { display: none; }
  html.finale-active .beat-finale h2 { font-size: clamp(calc(50px * var(--sp)), 15vw, 66px); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
  /* The wordmark's own reduced-motion rule lives inline in index.html <head>, where it
     can apply on the first frame instead of one stylesheet later. */
  #map, .story-beat { transform: none; filter: none; }
}
