/* ==================================================================
   NOWHERE CENTRAL — surface
   ================================================================== */

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

html, body { height: 100%; }

/* `clip`, not `hidden`: hidden would turn body into its own horizontal
   scroll container and the fixed cursor would drag the page sideways. */
html { overflow-x: clip; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  line-height: 1.65;
  /* deliberately NOT -webkit-font-smoothing: antialiased — on a dark
     ground it thins every stroke, which is the last thing a Didone needs */
  text-rendering: optimizeLegibility;
  overflow-x: clip;
  cursor: none;
}

body.no-custom-cursor { cursor: auto; }

h1, h2, h3, p, figure, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
/* cursor:none has to be declared here, not left to inherit from body:
   the UA sheet sets `cursor: pointer` directly on any link, and a
   direct declaration beats an inherited one, so the OS hand was drawn
   on top of the custom cursor on every link. */
a { color: inherit; text-decoration: none; cursor: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: none; }

/* ------------------------------------------------------------------
   Scrollbar — dressed to match the station, not the OS

   A slim rail on a near-black track, a muted bar that warms to the
   sodium accent when grabbed. Firefox reads the two-value form; the
   ::-webkit- rules paint the same thing in Chrome and Safari. */
html {
  scrollbar-width: thin;
  scrollbar-color: var(--ink-600) var(--ink-950);
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--ink-950); }
::-webkit-scrollbar-thumb {
  background: var(--ink-600);
  border-radius: var(--r-full);
  border: 2px solid var(--ink-950);   /* insets the bar off the track edges */
}
::-webkit-scrollbar-thumb:hover { background: var(--accent); }
::-webkit-scrollbar-corner { background: var(--ink-950); }

::selection { background: var(--accent); color: var(--ink-1000); }

/* Every use of the display serif shares one weight. Playfair carries a
   wght axis only, so that is the single dial. No shadow, no stroke. */
.hero-title,
.board-head h2,
.sec-x-head h2,
.sec-t-head h2,
.sec-x-prose .drop,
#arr-name,
#arr-strap,
#nightclock .nc-time {
  font-variation-settings: 'wght' var(--display-wght);
}

:focus-visible {
  outline: 1px solid var(--focus);
  outline-offset: 3px;
}

/* ------------------------------------------------------------------
   0. Chrome — canvas, scrim, cursor, grain
------------------------------------------------------------------ */

#gl {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
}

/* Static fallback when WebGL2 is unavailable */
.no-gl #gl { display: none; }
.no-gl body,
body.no-gl {
  background:
    radial-gradient(120% 80% at 50% 110%, #14202b 0%, transparent 60%),
    radial-gradient(80% 60% at 20% 0%, #1a1408 0%, transparent 55%),
    var(--ink-1000);
}

/* The reading scrim used to be a fixed full-screen gradient sitting on
   top of the canvas. The compositor had to blend it over every animated
   frame; it is now part of the concourse shader and costs nothing. */

#cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 90;
  pointer-events: none;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  will-change: transform;
}
/* plain colour, not mix-blend-mode — a blend mode over a live canvas
   forces a full re-composite of the frame behind it */
#cursor::before,
#cursor::after {
  content: '';
  position: absolute;
  background: var(--accent);
  transition: transform var(--d-fast) var(--ease-out);
}
#cursor::before { left: 50%; top: 0; width: 1px; height: 100%; transform: translateX(-50%) scaleY(0.42); }
#cursor::after { top: 50%; left: 0; height: 1px; width: 100%; transform: translateY(-50%) scaleX(0.42); }
#cursor.hot::before { transform: translateX(-50%) scaleY(1); }
#cursor.hot::after { transform: translateY(-50%) scaleX(1); }
#cursor .ring {
  position: absolute;
  inset: 0;
  border: 1px solid var(--accent);
  border-radius: 50%;
  opacity: 0;
  transform: scale(0.4);
  transition: opacity var(--d-fast) var(--ease-out), transform var(--d-fast) var(--ease-back);
}
#cursor.hot .ring { opacity: 0.75; transform: scale(1); }

/* ------------------------------------------------------------------
   1. Layout primitives
------------------------------------------------------------------ */

/* Render only what is on screen. The board alone is ~2000 elements, and
   without this the browser lays out and paints every section on every
   frame that touches them, whether or not any of it is visible.

   `contain-intrinsic-size: auto <n>` makes the browser remember each
   section's real height once it has been rendered, so the scrollbar
   does not jump the first time a section is skipped. The hero is
   deliberately excluded — it is on screen at load, and containing it
   would only add work. */
.board-section,
.sec-x,
.sec-t {
  content-visibility: auto;
  contain-intrinsic-size: auto 900px;
}


.stage {
  position: relative;
  z-index: 2;
}

.wrap {
  width: 100%;
  max-width: 1560px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-dim);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.eyebrow::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--border-strong), transparent);
}

.rule {
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong) 12%, var(--border-strong) 88%, transparent);
  border: 0;
  margin: 0;
}

/* ------------------------------------------------------------------
   2. Boot veil
------------------------------------------------------------------ */

.veil {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: var(--ink-1000);

  /* On a phone the boot log is taller than the screen. With grid
     place-items:center and no overflow rule the surplus rendered
     *outside* this fixed box, straight over the page — the footnotes and
     the hero heading bled in below, and the top line was clipped.

     Flex column + `margin:auto` on the child is the safe-centre idiom:
     centred when it fits, and when it doesn't the box scrolls its own
     content instead of spilling it, with neither end ever cut off. */
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.veil > * { margin-block: auto; }

/* While the terminal veil is up the document does not move. This stops
   the page scrolling out from behind the fixed veil on mobile, where a
   scroll would otherwise collapse the address bar and reveal the board.
   The veil itself still scrolls its own content on a short screen. */
html.boot-lock,
html.boot-lock body {
  overflow: hidden;
  height: 100%;
  overscroll-behavior: none;
}

#boot {
  z-index: 80;
  transition: opacity 900ms var(--ease-std), visibility 900ms;
}
#boot.gone { opacity: 0; visibility: hidden; pointer-events: none; }

.boot-inner {
  width: min(760px, 88vw);
  text-align: center;
}

.boot-mark {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  color: var(--text-dim);
  text-transform: uppercase;
  margin-bottom: var(--sp-7);
}

/* the threshold: audio cannot start until a gesture, so the terminal
   waits behind one rather than typing itself out in silence */
.boot-begin {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 11.2em;
  margin-bottom: var(--sp-7);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
  transition: color var(--d-fast) var(--ease-std);
}
.boot-begin:hover { color: var(--accent); }
.boot-begin.gone { display: none; }
.boot-begin .caret {
  width: 9px;
  height: 1.05em;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
  animation: caretblink 1.05s steps(1) infinite;
}
@keyframes caretblink { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }

.boot-log {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 2.1;
  color: var(--bone-300);
  text-align: left;
  min-height: 11.2em;
  margin-bottom: var(--sp-7);
  padding-left: var(--sp-4);
  border-left: 1px solid var(--border);
}
/* before the first keystroke the log holds no space; the begin prompt
   stands in for it, so the panel does not reserve two blocks at once */
.boot-log:empty { min-height: 0; margin: 0; padding: 0; border: 0; }
.boot-log b { color: var(--accent); font-weight: 400; }
.boot-log .dim { color: var(--text-dim); }

.boot-cta {
  --pad: var(--sp-4);
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-7);
  border: 1px solid var(--border-strong);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--d-slow) var(--ease-out), transform var(--d-slow) var(--ease-out),
    background-color var(--d-fast) var(--ease-std), border-color var(--d-fast) var(--ease-std);
}
.boot-cta.in { opacity: 1; transform: none; }
.boot-cta:hover { background: var(--accent-ghost); border-color: var(--accent); color: var(--accent); }
.boot-cta:active { transform: scale(0.985); }
.boot-cta .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
  animation: pulse 2.2s var(--ease-std) infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

.boot-foot {
  margin-top: var(--sp-6);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.12em;
  color: var(--text-dim);
}

/* An advisory, not another keyboard hint — it has to read before the
   visitor decides, so it sits above the shortcut list and carries the
   accent. Still quiet: this is a boot screen at two in the morning. */
.boot-note {
  color: var(--accent);
  opacity: 0.85;
  /* Tighter tracking than the hints so it stays on one line — wrapping
     doubles the block height on top of the type size and reads far
     larger than the number suggests. */
  font-size: 14px;
  letter-spacing: 0.06em;
  text-wrap: balance;
}
.boot-note::before {
  content: '◈';
  margin-right: 0.7em;
  opacity: 0.7;
}

/* ------------------------------------------------------------------
   3. Top bar
------------------------------------------------------------------ */

/* ------------------------------------------------------------------
   Top bar

   Was a row of bordered pills — the boxed-button look that dates a
   header faster than anything else in it. Now the chrome is gone and
   the structure does the work instead: a three-column grid so the nav
   is optically centred rather than pushed there by flex, hairline
   dividers between zones, and state carried by a marker and a colour
   rather than by a box around the label.
------------------------------------------------------------------ */
.topbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-6);
  padding: var(--sp-4) var(--gutter);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
  /* a gradient, not a backdrop-filter: blurring a live canvas every
     frame is one of the most expensive things a page can ask for */
  background: linear-gradient(180deg, rgba(5,7,10,0.92) 0%, rgba(5,7,10,0.62) 62%, rgba(5,7,10,0) 100%);
  transition: opacity var(--d-slow) var(--ease-std),
              background var(--d-med) var(--ease-std);
}
/* Over the hero a feathered scrim is right — there is nothing behind it
   but picture. Over the sections there is body copy, and a half-there
   gradient let the prose read straight through the nav. Once the page
   has scrolled, the bar stops being a veil and becomes a surface. */
.topbar.stuck {
  background: linear-gradient(180deg, rgba(5,7,10,0.98) 0%, rgba(5,7,10,0.96) 70%, rgba(5,7,10,0.9) 100%);
}
/* the hairline arrives on scroll instead of a permanent border */
.topbar::after {
  content: '';
  position: absolute; left: var(--gutter); right: var(--gutter); bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong) 18%, var(--border-strong) 82%, transparent);
  opacity: 0;
  transition: opacity var(--d-med) var(--ease-std);
}
.topbar.stuck::after { opacity: 1; }

.topbar .brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  color: var(--text);
  letter-spacing: var(--tracking-wider);
}
/* the N monogram — the logo mark, in the sodium accent */
.topbar .brand .glyph {
  display: inline-flex;
  align-items: center;
  color: var(--accent);
}
/* slim and tall, not wide; centred on the wordmark's cap height */
.topbar .brand .glyph svg { height: 15px; width: auto; display: block; }
.topbar .brand .glyph svg path {
  fill: none;
  stroke: currentColor;
  stroke-width: 3.1;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* --- nav: the underline is the only decoration ------------------- */
/* Absolutely centred, not grid-centred. `1fr auto 1fr` looks like it
   centres, but 1fr is minmax(auto, 1fr) — the wider side zone forces its
   column out and drags the nav off axis by however much the two sides
   differ. Taking it out of flow makes it exact regardless. */
.topbar .center {
  display: flex;
  gap: var(--sp-6);
  position: absolute;
  /* Centred on the topbar, not the viewport. `left: 50%` measures against
     the viewport including the scrollbar, which throws the nav off by
     half the scrollbar's width — 8px here, and visible once you know. */
  left: 0; right: 0;
  justify-content: center;
  pointer-events: none;
}
.topbar .center a { pointer-events: auto; }
.topbar .center a {
  position: relative;
  padding-block: 2px;
  color: var(--text-muted);
  transition: color var(--d-fast) var(--ease-std);
}
.topbar .center a::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: -2px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--d-med) var(--ease-out);
}
.topbar .center a:hover { color: var(--text); }
.topbar .center a:hover::after { transform: scaleX(1); transform-origin: left; }

/* --- right zone: divided, not boxed ------------------------------ */
/* The dividers used to be padding-left on each item, which left every
   item padded on one side only — so the hover and focus shapes were
   lopsided, and the last one ran flush into the gutter with nothing on
   its right. Each item now carries its own symmetric padding and the
   row is pulled back by that same amount, so the boxes breathe evenly
   while the text still lines up with the gutter. */
/* ------------------------------------------------------------------
   Floating controls

   Three recognisable glyphs and a clock, riding above every surface in
   the top-right — the home board and the immersive service pages
   alike, so the audio is reachable without going back. No words: a
   speaker, a moon and a set of bars carry their own meaning, and the
   page is meant to be listened to, not read. They sit on a faint
   blurred tile only so they survive over a bright frame. */
#controls {
  position: fixed;
  top: 0; right: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: var(--sp-3) var(--gutter);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--d-slow) var(--ease-std);
}
/* shown once through the gate; the boot veil (z-80) covers it before */
body.ready #controls { opacity: 1; pointer-events: auto; }
/* night service owns the right edge — its rail carries its own volume
   and close, so the corner cluster stands down and stops colliding
   with the rail's top */
body.night #controls { opacity: 0; pointer-events: none; }

#clock {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.16em;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  padding-right: var(--sp-3);
  margin-right: var(--sp-2);
  border-right: 1px solid var(--border);
}
#clock .ms { color: var(--accent); opacity: 0.75; }

.ctl {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px; height: 38px;
  border-radius: var(--r-full);
  color: var(--text-muted);
  transition: color var(--d-fast) var(--ease-std),
              background var(--d-fast) var(--ease-std);
}
.ctl svg { width: 20px; height: 20px; display: block; }
.ctl svg [fill='none'] { stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.ctl svg :not([fill='none']) { fill: currentColor; }
.ctl:hover { color: var(--text); background: rgba(242, 239, 230, 0.06); }

/* sound: waves when on, a slash when off */
.ctl .slash { stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
#sound-btn .wave { opacity: 0; transition: opacity var(--d-fast) var(--ease-std); }
#sound-btn .slash { opacity: 1; }
#sound-btn.on { color: var(--accent); }
#sound-btn.on .wave { opacity: 1; }
#sound-btn.on .slash { opacity: 0; }

/* night + quality: accent when engaged */
#night-btn { transition: transform var(--d-med) var(--ease-out), color var(--d-fast) var(--ease-std); }
#night-btn[aria-pressed='true'] { color: var(--accent); }
#quality-btn:active { transform: scale(0.92); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* The nav is out of flow, so nothing stops it running under the clock.
   Brand + links + controls need ~1150px to coexist; below that the
   links go rather than collide. */
@media (max-width: 1150px) {
  .topbar .center { display: none; }
}

/* ------------------------------------------------------------------
   4. Hero
------------------------------------------------------------------ */

/* ------------------------------------------------------------------
   Hero — picture behind, type in front

   There used to be a third plane: a masked slice of the same image
   laid over the word, so the type sat inside the picture. It read as
   the title fading out halfway down, which is not a look worth the
   letterforms it eats. The word is solid now; depth is the grade and
   the wash, not something covering the type.
------------------------------------------------------------------ */
.hero {
  position: relative;
  isolation: isolate;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto auto;
  align-content: center;
  overflow: hidden;
  padding-block: var(--sp-9) var(--sp-6);
}

/* --- plane 1: the picture ---------------------------------------- */
.hero-plate { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.hero-back {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 68% 42%;
  /* graded light: the picture is the composition here, not a texture.
     It used to be crushed to a ground and there was nothing left to
     look at. */
  filter: contrast(1.05) brightness(0.94) saturate(1.02);
  transform: scale(1.04);
}
/* The wash is now only a seat for the type — enough to stop the copy
   floating loose on a busy frame, nowhere near enough to hide it. Text
   legibility is carried by the text's own colour, not by drowning the
   picture; if something reads badly, brighten the type, not this. */
.hero-wash {
  position: absolute; inset: 0;
  background:
    linear-gradient(100deg, rgba(5,7,10,0.62) 0%, rgba(5,7,10,0.30) 34%,
                    rgba(5,7,10,0) 62%, rgba(5,7,10,0.16) 100%),
    linear-gradient(180deg, rgba(5,7,10,0.44) 0%, transparent 22%,
                    transparent 52%, rgba(5,7,10,0.26) 78%,
                    rgba(5,7,10,0.52) 94%, rgba(5,7,10,0.62) 100%);
}

/* --- the measured rule: four hairlines, editorial scaffolding ----- */
.hero-rule {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  display: grid; grid-template-columns: repeat(4, 1fr);
}
.hero-rule i { border-left: 1px solid rgba(255,255,255,0.035); }
.hero-rule i:first-child { border-left: 0; }

/* --- plane 2: the type ------------------------------------------- */
.hero-inner { position: relative; z-index: 2; align-self: center; }

.hero-kicker {
  display: flex; align-items: center; gap: var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--sp-5);
}
.hero-kicker i { font-style: normal; opacity: 0.8; }

.hero-title {
  font-family: var(--font-display);
  --display-wght: 520;
  font-size: clamp(3rem, 10.5vw, 9.5rem);
  line-height: 0.86;
  letter-spacing: -0.045em;    /* display type wants far tighter tracking */
  margin: 0;
}
.hero-title .ln { display: block; overflow: hidden; }
.hero-title .ln > span {
  display: block;
  transform: translateY(105%);
  transition: transform 1200ms var(--ease-out);
}
.hero-title .ln:nth-child(2) > span { transition-delay: 110ms; }
.ready .hero-title .ln > span { transform: none; }
.hero-title em {
  font-style: italic;
  color: var(--accent);
  --display-wght: 540;
  margin-left: 0.06em;
}

/* The lower band. Bounded to the hero so its gradient stops mean
   something, and stacked above the picture but below the copy. */
.hero::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 40%;
  z-index: 1;                  /* under the type: it seats the foot, it
                                  does not wash over the word */
  pointer-events: none;
  background: linear-gradient(180deg,
    transparent 0%, rgba(5,7,10,0.16) 40%, rgba(5,7,10,0.42) 70%, rgba(5,7,10,0.62) 92%);
}

/* --- the foot: lede left, figures right -------------------------- */
.hero-foot {
  position: relative; z-index: 4;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: var(--sp-7);
  border-top: 1px solid var(--border);
  padding-top: var(--sp-4);
  margin-top: var(--sp-7);
}
.hero-lede {
  max-width: 44ch;
  color: var(--text-muted);
  font-size: var(--fs-base);
}
.hero-lede strong { color: var(--text); font-weight: 500; }

.hero-stats { display: flex; gap: var(--sp-7); margin: 0; }
.hero-stats div { text-align: right; }
.hero-stats dt {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: var(--sp-1);
}
.hero-stats dd {
  margin: 0;
  font-family: var(--font-display);
  --display-wght: 500;
  font-size: var(--fs-2xl);
  line-height: 1;
  color: var(--text);
}

@media (max-width: 900px) {
  .hero-rule { grid-template-columns: repeat(2, 1fr); }
  .hero-foot { grid-template-columns: 1fr; }
  .hero-stats { justify-content: space-between; gap: var(--sp-4); }
  .hero-stats div { text-align: left; }
}

}

.scroll-hint {
  margin-top: var(--sp-8);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-dim);
}
.scroll-hint .line {
  width: 64px; height: 1px; background: var(--border-strong); position: relative; overflow: hidden;
}
.scroll-hint .line::after {
  content: ''; position: absolute; inset: 0; background: var(--accent);
  transform: translateX(-100%); animation: slide 2.6s var(--ease-std) infinite;
}
@keyframes slide { 0% { transform: translateX(-100%); } 60%, 100% { transform: translateX(100%); } }

/* ------------------------------------------------------------------
   5. The board
------------------------------------------------------------------ */

.board-section { padding-block: var(--sp-9) var(--sp-10); }

.board-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-5);
  margin-bottom: var(--sp-6);
  flex-wrap: wrap;
}
.board-head h2 {
  font-family: var(--font-display);
  --display-wght: 500;
  font-size: var(--fs-2xl);
  line-height: 1;
  letter-spacing: -0.01em;
}
.board-head .note {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-dim);
}

.board-shell {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background:
    linear-gradient(180deg, rgba(20, 26, 35, 0.94), rgba(7, 10, 14, 0.97));
  box-shadow: var(--e-2);
  overflow: hidden;
}

/* lamp bar above the board */
.board-shell::before {
  content: '';
  position: absolute;
  top: 0; left: 8%; right: 8%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: 0.5;
}
.board-shell::after {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; height: 160px;
  background: radial-gradient(60% 100% at 50% 0%, rgba(255, 179, 71, 0.09), transparent 70%);
  pointer-events: none;
}

/* ==================================================================
   THE REEL — what an arrival was carrying

   The vignette and the scanlines are children of .reel-stage, which
   is locked to 16:9. They therefore track the picture and not the
   window, which is the whole reason the stage exists as its own box
   rather than the media filling the panel directly.
   ================================================================== */
/* Entered, not opened — same shape as #arrival, one z-layer above it.
   visibility (not display) so it can cross-fade, and so it is never a
   full-screen click trap while closed. */
.reel {
  position: fixed;
  inset: 0;
  z-index: 52;
  display: block;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--d-slow) var(--ease-std), visibility var(--d-slow);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.reel.open { opacity: 1; visibility: visible; }

/* the screen you walked into: black room, one lit rectangle */
.reel-bg {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: #000;
  pointer-events: none;
}
.reel.open .reel-bg { pointer-events: auto; }

/* a bed for the type, exactly as #arrival does over a world */
.reel-inner {
  position: relative;
  min-height: 100svh;
  width: 100%;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: var(--sp-8) var(--gutter) var(--sp-6);
  max-width: 1560px;
  margin: 0 auto;
  pointer-events: none;
}
/* The type bed is a fixed ::before, so the chrome has to be positioned
   to sit on top of it rather than under it. */
.reel-inner > * { pointer-events: auto; position: relative; z-index: 1; }
.reel-inner::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(102deg, rgba(5, 7, 10, 0.88) 0%, rgba(5, 7, 10, 0.62) 34%,
      rgba(5, 7, 10, 0.16) 62%, rgba(5, 7, 10, 0.44) 100%),
    linear-gradient(180deg, rgba(5, 7, 10, 0.70) 0%, transparent 24%, transparent 72%, rgba(5, 7, 10, 0.78) 100%);
}
.reel-body { position: relative; align-self: center; max-width: 46ch; }
.reel-body h2 { margin: 0 0 var(--sp-3); font-size: clamp(1.8rem, 5vw, 3.4rem); }
.reel-body p  { margin: 0 0 var(--sp-3); color: var(--text-dim); }
.reel-line    { color: var(--accent) !important; font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--tracking-wide); }

/* ------------------------------------------------------------------
   The service pages step back — but not to nothing

   These are the immersive surfaces: a moving world or a still frame
   with a music bed, meant to be looked at and listened to. The wall of
   copy is gone — the paragraph of prose, the timetable advisory, the
   conditions panel, the ref in the corner, the section labels. What
   stays is a composed trio: a small code eyebrow, the destination
   name, and one atmospheric line — enough to sit as a designed block
   rather than a lone word floating in an empty frame. Reversible: the
   rest is hidden, not deleted, so the authored voice survives.
------------------------------------------------------------------ */
#reel-line, #reel-ref,
#arr-prose, .arr-panel, #arr-advisory, #arr-ref,
.reel .arr-foot > span:not(.kbd-hint):first-child,
#arrival .arr-foot > span:not(.kbd-hint):first-child {
  display: none;
}
.reel-body, .arr-stagger { max-width: 34ch; }
/* a finger drag on these surfaces feeds the parallax rather than being
   taken as a scroll or zoom gesture — taps still register */
.reel-stage, #arrival { touch-action: none; }

/* Full bleed. An earlier version locked this to the largest 16:9 box the
   viewport would hold, which pillarboxed every window wider than 16:9.
   The media is object-fit: cover, so it fills any shape and the vignette
   rides the picture either way. */
.reel-stage {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #000;
}
.reel-media { position: absolute; inset: 0; }
.reel-media > * {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scale(1.08);          /* headroom so the parallax never shows an edge */
  will-change: transform;
}

/* vignette, sized to the 16:9 box */
.reel-vig {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 100% at 50% 50%, transparent 38%, rgba(0,0,0,0.34) 72%, rgba(0,0,0,0.82) 100%),
    linear-gradient(180deg, rgba(0,0,0,0.30), transparent 22%, transparent 74%, rgba(0,0,0,0.46));
}

/* Plain alpha, not mix-blend-mode: a blend mode over live video forces
   a full re-composite of every decoded frame — the same reason #cursor
   uses a flat colour over the canvas. On footage this dark the two are
   visually indistinguishable. */
.reel-scan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background: repeating-linear-gradient(
    180deg, rgba(0,0,0,0.26) 0 1px, transparent 1px 3px);
}

/* --- the tape treatment, only on the two stills that ask for it --- */
.reel-stage.tape .reel-scan { opacity: 0.5; }
.reel-stage.tape .reel-media { animation: reel-flicker 5.7s steps(1, end) infinite; }
@keyframes reel-flicker {
  0%,  100% { filter: brightness(1)     saturate(1);    }
  17%       { filter: brightness(1.035) saturate(0.97); }
  19%       { filter: brightness(0.975) saturate(1.02); }
  46%       { filter: brightness(1.02)  saturate(1);    }
  47%       { filter: brightness(0.99)  saturate(0.99); }
  73%       { filter: brightness(1.045) saturate(0.98); }
  75%       { filter: brightness(0.985) saturate(1.01); }
}

@media (prefers-reduced-motion: reduce) {
  .reel { transition: none; }
  .reel-media > * { transform: none; }
  .reel-stage.tape .reel-media { animation: none; }
}

/* --- board tabs ---------------------------------------------------
   Two boards, one shell. The underline slides rather than cuts, so
   the switch reads as the same board changing its mind rather than
   two boards swapping places. */
.board-tabs {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  max-width: 22rem;
  margin: var(--sp-5) var(--sp-5) 0;
  border-bottom: 1px solid var(--border);
}
.board-tab {
  appearance: none;
  background: none;
  border: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-dim);
  padding: var(--sp-2) var(--sp-3) var(--sp-3);
  transition: color var(--d-med) ease, opacity var(--d-med) ease;
}
.board-tab:hover { color: var(--text); }
.board-tab.on { color: var(--accent); }
.board-tab:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
.board-tabs-ink {
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 50%;
  height: 1px;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
  transition: transform var(--d-med) cubic-bezier(0.22, 1, 0.36, 1);
}

/* Nothing on the arrivals board is going anywhere, so the row does not
   pretend it might: no lift on hover, and the marker stays cold. */
.board-row.arr::before { background: var(--ink-600); }
.board-row.arr:hover::before { height: 44%; }
.board-row.arr .idx { opacity: 0.55; }
.board-row.arr:hover .idx { color: var(--text-dim); }
.board-row.arr [data-role='status'],
.board-row.arr [data-role='plat'] { opacity: 0.72; }

@media (prefers-reduced-motion: reduce) {
  .board-tabs-ink { transition: none; }
}

.board-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  scrollbar-color: var(--ink-600) transparent;
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
}
.board-scroll::-webkit-scrollbar { height: 6px; }
.board-scroll::-webkit-scrollbar-thumb { background: var(--ink-600); border-radius: var(--r-full); }

.board-grid { min-width: max-content; }

.board-colhead,
.board-row {
  display: grid;
  grid-template-columns: auto auto auto auto auto;
  gap: var(--sp-5);
  align-items: center;
}

.board-colhead {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 0 var(--sp-3) var(--sp-3);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-3);
}

.board-row {
  position: relative;
  width: 100%;
  text-align: left;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  /* No background-color here. Each row holds ~300 flap elements, and
     tinting the row itself repaints that whole subtree on every hover —
     which is what made the pointer feel heavy over the board. The tint
     is an ::after layer animated on opacity instead, which the
     compositor handles without repainting any children. */
  transition: opacity var(--d-med) var(--ease-std),
    transform var(--d-med) var(--ease-out), filter var(--d-med) var(--ease-std);
}
.board-row + .board-row { margin-top: var(--flap-gap); }
.board-row::before {
  content: '';
  position: absolute;
  left: 0; top: 50%;
  width: 2px; height: 0;
  background: var(--accent);
  box-shadow: 0 0 14px var(--accent);
  transform: translateY(-50%);
  transition: height var(--d-fast) var(--ease-out);
}
.board-row::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;                       /* behind the flaps, above the shell */
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.035);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--d-fast) var(--ease-std);
}
.board-row:hover::after { opacity: 1; }
.board-row:hover::before { height: 72%; }

/* header cells must match the flap runs exactly: n cells + (n-1) 1px gaps */
.board-colhead span { display: block; overflow: hidden; white-space: nowrap; }
.board-colhead i { font-style: normal; }
.board-colhead .sm { display: none; }
.w-idx { width: 2.5em; }
.w-time { width: calc(var(--flap-w) * 5 + 4px); }
.w-dest { width: calc(var(--flap-w) * 16 + 15px); }
.w-plat { width: calc(var(--flap-w) * 2 + 1px); }
.w-status { width: calc(var(--flap-w) * 9 + 8px); }

.board-row .idx {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-dim);
  letter-spacing: 0.1em;
  width: 2.5em;
  transition: color var(--d-fast);
}
.board-row:hover .idx { color: var(--accent); }

/* departure choreography */
.board-shell.departing .board-row { opacity: 0.12; filter: blur(2px); transform: scale(0.985); }
.board-shell.departing .board-row.chosen { opacity: 1; filter: none; transform: scale(1.015); }
.board-shell.departing .board-row.chosen::before { height: 100%; }
.board-shell.departing .board-colhead { opacity: 0.15; transition: opacity var(--d-med); }

.board-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-dim);
  background: rgba(0, 0, 0, 0.35);
}
#notice-line {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--bone-400);
  transition: opacity var(--d-med) var(--ease-std);
}
#notice-line.swap { opacity: 0; }

/* ---- split-flap cell -------------------------------------------- */

.flapline { display: flex; gap: 1px; }
.flapline.pad { padding-inline: 0; }

.cell {
  position: relative;
  width: var(--flap-w);
  height: var(--flap-h);
  perspective: 220px;
  flex: none;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: calc(var(--flap-h) * 0.6);
  color: var(--flap-ink);
  border-radius: var(--r-xs);
  background: var(--ink-1000);
}

/* No backface-visibility here on purpose: it promotes every half to its
   own compositor layer, and 192 cells x 4 halves is 768 layers. The
   leaves are display:none when idle, which does the same job for free. */
.cell .half {
  position: absolute;
  left: 0;
  width: 100%;
  height: 50%;
  overflow: hidden;
  background: var(--flap-bg);
}
.cell .half > span {
  position: absolute;
  left: 0;
  width: 100%;
  height: var(--flap-h);
  line-height: var(--flap-h);
  text-align: center;
  display: block;
  letter-spacing: 0;
}
.cell .t { top: 0; border-radius: var(--r-xs) var(--r-xs) 0 0; background: linear-gradient(180deg, var(--flap-bg-hi), var(--flap-bg)); }
.cell .t > span { top: 0; }
.cell .b { bottom: 0; border-radius: 0 0 var(--r-xs) var(--r-xs); background: linear-gradient(180deg, var(--flap-bg), #0f1319); box-shadow: inset 0 1px 0 var(--flap-seam); }
.cell .b > span { top: calc(var(--flap-h) * -0.5); }

.cell .leaf { display: none; z-index: 3; }
.cell .leaf.on { display: block; }
.cell .leaf-f { transform-origin: 50% 100%; }
.cell .leaf-b { transform-origin: 50% 0%; }

/* subtle mechanical sheen */
.cell::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--r-xs);
  pointer-events: none;
  z-index: 4;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent 40%, transparent 60%, rgba(0, 0, 0, 0.28));
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.6);
}

/* accent tinting per column role */
.flapline[data-role='dest'] .cell { color: var(--bone-100); }
.flapline[data-role='time'] .cell { color: var(--accent); }
.flapline[data-role='plat'] .cell { color: var(--bone-200); }
.flapline[data-role='status'] .cell {
  color: var(--petrol-300);
  font-size: calc(var(--flap-h) * 0.52);
  /* just a whisper of glow — the colour carries it, like the time does */
  text-shadow: 0 0 3px rgba(52, 210, 230, 0.3);
}

/* ------------------------------------------------------------------
   6. Editorial sections
------------------------------------------------------------------ */

/* ------------------------------------------------------------------
   Sections below the board

   Both used to be the same two-column .split — same shape, same
   rhythm, twice. Reading them back to back felt like one section
   printed twice.

   They now differ on purpose. 02 is pictorial: full-bleed image, an
   oversized numeral bled off the edge, prose set narrow and offset.
   03 is purely typographic — no image at all — so the page alternates
   instead of repeating. The contrast between them is the rhythm.
------------------------------------------------------------------ */
.sec-x, .sec-t {
  position: relative;
  padding-block: var(--sp-10) var(--sp-9);
  overflow: hidden;
}

/* the numeral is scenery, not a label: huge, dim, half off the page */
.sec-num {
  position: absolute;
  top: var(--sp-6);
  right: -0.08em;
  font-family: var(--font-display);
  --display-wght: 400;
  font-size: clamp(9rem, 26vw, 26rem);
  line-height: 0.72;
  letter-spacing: -0.06em;
  color: var(--text);
  opacity: 0.035;
  pointer-events: none;
  user-select: none;
}

.sec-x-head, .sec-t-head { position: relative; z-index: 1; }
.sec-x-head { margin-bottom: var(--sp-8); }

/* The section heading is the display serif at reading-poster size. The
   measure is capped on the h2 itself, not on the head — capping the
   head collapses the whole block to a narrow centred column, because
   it is also a .wrap and inherits its auto margins. */
.sec-x-head h2, .sec-t-head h2 {
  font-family: var(--font-display);
  --display-wght: 500;
  font-size: var(--fs-3xl);
  line-height: 1.02;
  letter-spacing: -0.025em;
  max-width: 17ch;
  margin-top: var(--sp-4);
  color: var(--text);
}
.sec-x-head h2 em,
.sec-t-head h2 em { font-style: italic; color: var(--accent); --display-wght: 520; }

/* --- 02: picture left, prose offset right ------------------------ */
.sec-x-body {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  align-items: end;
  gap: var(--sp-8);
  margin-bottom: var(--sp-9);
}
/* the figure bleeds off the left edge — a full-width container inside a
   wrapped page is what stops the section reading as a document column */
.sec-x-fig {
  position: relative;
  margin: 0 0 0 calc(var(--gutter) * -1);
}
.sec-x-fig img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  filter: grayscale(0.4) contrast(1.1) brightness(0.72);
}
/* a hairline frame, offset — the detail that reads as considered */
.sec-x-fig::after {
  content: '';
  position: absolute;
  inset: var(--sp-4) calc(var(--sp-4) * -1) calc(var(--sp-4) * -1) var(--sp-4);
  border: 1px solid var(--border);
  pointer-events: none;
}
.sec-x-fig figcaption {
  /* the picture bleeds out through the gutter, the caption does not —
     it belongs to the page column, not to the edge of the screen */
  padding-left: var(--gutter);
  margin-top: var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-dim);
}
/* The grid column is the measure. A 46ch cap plus a gutter of padding
   left the copy stopping ~230px short of the page edge, which read as
   a hole in the layout rather than as a margin. */
.sec-x-prose { max-width: none; }
.sec-x-prose p {
  color: var(--text-muted);
  font-size: var(--fs-lg);
  line-height: 1.72;
}
.sec-x-prose p + p { margin-top: var(--sp-5); }
.sec-x-prose em { font-style: italic; color: var(--text); }
/* the drop cap: display serif, three lines deep, optically kerned in */
.sec-x-prose .drop {
  float: left;
  font-family: var(--font-display);
  --display-wght: 500;
  font-size: 3.6em;
  line-height: 0.78;
  padding: 0.06em 0.12em 0 0;
  color: var(--text);
}

/* --- the figures: a band of display numerals, not a definition list */
.figures {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-6);
  border-top: 1px solid var(--border);
  padding-top: var(--sp-5);
  /* margin-block only: this is also a .wrap, and a blanket `margin: 0`
     kills the auto inline margins that centre the page column. */
  margin-block: 0;
}
.figures div { display: flex; flex-direction: column; gap: var(--sp-2); }
.figures dt {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--accent);
}
.figures dd {
  margin: 0;
  font-family: var(--font-display);
  --display-wght: 440;
  font-size: clamp(2.6rem, 6vw, 4.6rem);
  line-height: 0.9;
  letter-spacing: -0.03em;
  color: var(--text);
}
.figures small { color: var(--text-dim); font-size: var(--fs-2xs); }

/* --- 03: typographic, head split against an aside ---------------- */
.sec-t-head {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr);
  align-items: end;
  gap: var(--sp-8);
  margin-bottom: var(--sp-7);
}
.sec-t-aside p { color: var(--text-muted); max-width: 38ch; }
.sec-t-aside .lf-invite { margin-top: var(--sp-4); }

@media (max-width: 900px) {
  .sec-x-body, .sec-t-head { grid-template-columns: 1fr; }
  .sec-x-fig { margin-left: calc(var(--gutter) * -1); margin-right: calc(var(--gutter) * -1); }
  .sec-x-fig::after { display: none; }
  .sec-x-fig figcaption { padding-left: var(--gutter); }
  .figures { grid-template-columns: repeat(2, 1fr); gap: var(--sp-5); }
  .sec-num { font-size: clamp(7rem, 34vw, 14rem); opacity: 0.045; }
}

.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 900ms var(--ease-out), transform 900ms var(--ease-out);
}
.reveal.in { opacity: 1; transform: none; }

/* lost & found */
.lf-list { border-top: 1px solid var(--border); }
.lf-row {
  display: grid;
  grid-template-columns: 9.5em minmax(0, 1fr) 1.6em;
  gap: var(--sp-4);
  align-items: baseline;
  padding: var(--sp-4) var(--sp-2);
  border-bottom: 1px solid var(--border);
  transition: background-color var(--d-fast) var(--ease-std), padding-left var(--d-fast) var(--ease-out);
}
.lf-row:hover { background: rgba(255, 255, 255, 0.03); padding-left: var(--sp-4); }
.lf-row .ref {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  color: var(--accent);
}
.lf-row .desc { color: var(--bone-300); font-size: var(--fs-base); }
.lf-row .arrow { color: var(--text-dim); opacity: 0; transform: translateX(-6px); transition: all var(--d-fast) var(--ease-out); }
.lf-row:hover .arrow { opacity: 1; transform: none; }
@media (max-width: 620px) {
  .lf-row { grid-template-columns: 1fr; gap: var(--sp-1); }
  .lf-row .arrow { display: none; }
}

/* footer */
.site-foot {
  padding-block: var(--sp-8) var(--sp-7);
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-dim);
}
.site-foot a:hover { color: var(--accent); }
.site-foot strong { color: var(--accent); font-weight: 400; }

/* ------------------------------------------------------------------
   7. Arrival
------------------------------------------------------------------ */

#arrival {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: block;
  background: transparent;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--d-slow) var(--ease-std), visibility var(--d-slow);
  overflow-y: auto;
  overscroll-behavior: contain;
}
#arrival.open { opacity: 1; visibility: visible; }

/* A bed for the type. Every world is a different brightness, so the
   text gets its own guaranteed contrast rather than trusting the sky. */
#arrival::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(102deg, rgba(5, 7, 10, 0.9) 0%, rgba(5, 7, 10, 0.74) 34%,
      rgba(5, 7, 10, 0.3) 62%, rgba(5, 7, 10, 0.55) 100%),
    linear-gradient(180deg, rgba(5, 7, 10, 0.75) 0%, transparent 22%, transparent 74%, rgba(5, 7, 10, 0.8) 100%);
}

.arr-inner {
  position: relative;
  min-height: 100svh;
  width: 100%;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: var(--sp-8) var(--gutter) var(--sp-6);
  max-width: 1560px;
  margin-inline: auto;
}

/* The concourse steps aside while you are away. `visibility` flips at
   the end of the fade, which takes the whole document out of paint and
   compositing instead of leaving it there at zero opacity. */
.stage {
  transition: opacity var(--d-slow) var(--ease-std), visibility var(--d-slow);
}
body.away .stage {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
body.away .topbar { opacity: 0; pointer-events: none; }

.arr-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-muted);
}
.arr-back {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 8px 14px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  transition: all var(--d-fast) var(--ease-std);
}
.arr-back:hover { color: var(--accent); border-color: var(--accent); background: var(--accent-ghost); }

.arr-body {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(300px, 0.75fr);
  gap: var(--sp-8);
  align-content: center;
  padding: var(--sp-8) 0;
}
@media (max-width: 980px) {
  .arr-body { grid-template-columns: 1fr; gap: var(--sp-6); }
  .arr-panel { max-width: 540px; }
}

.arr-code {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  color: var(--accent);
  margin-bottom: var(--sp-4);
}
#arr-name {
  font-family: var(--font-display);
  --display-wght: 500;
  font-size: var(--fs-3xl);
  line-height: 0.92;
  letter-spacing: -0.02em;
  margin-bottom: var(--sp-5);
  text-wrap: balance;
}
#arr-strap {
  font-family: var(--font-display);
  font-style: italic;
  --display-wght: 500;
  font-size: var(--fs-xl);
  color: var(--accent);
  margin-bottom: var(--sp-5);
  max-width: 24ch;
  line-height: 1.25;
}
#arr-prose {
  color: var(--bone-200);
  max-width: 54ch;
  font-size: var(--fs-lg);
  line-height: 1.75;
  text-shadow: 0 1px 24px rgba(0, 0, 0, 0.9);
}

.arr-panel {
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: linear-gradient(180deg, rgba(9, 12, 17, 0.93), rgba(5, 7, 10, 0.96));
  box-shadow: var(--e-2);
  overflow: hidden;
  align-self: start;
}
.arr-panel h3 {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 400;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-dim);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
}
#arr-cond { padding: var(--sp-2) 0; }
#arr-cond .crow {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  opacity: 0;
  transform: translateX(12px);
}
#arr-cond .crow.in { opacity: 1; transform: none; transition: opacity 420ms var(--ease-out), transform 420ms var(--ease-out); }
#arr-cond .k {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  color: var(--text-muted);
}
#arr-cond .k i { display: block; font-style: normal; color: var(--text-dim); letter-spacing: 0.06em; text-transform: none; font-size: var(--fs-2xs); opacity: 0.75; margin-top: 2px; }
#arr-cond .v {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  color: var(--text);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.arr-advisory {
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--accent-ghost);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  line-height: 1.8;
  color: var(--sodium-400);
  letter-spacing: 0.06em;
}

.arr-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-dim);
}
.arr-nav { display: flex; gap: var(--sp-2); }
.arr-nav button {
  padding: 7px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  letter-spacing: var(--tracking-wide);
  transition: all var(--d-fast) var(--ease-std);
}
.arr-nav button:hover { color: var(--accent); border-color: var(--accent); }
.arr-nav button[aria-current='true'] { color: var(--ink-1000); background: var(--accent); border-color: var(--accent); }

/* stagger-in for arrival text */
.arr-stagger > * { opacity: 0; transform: translateY(18px); }
#arrival.open .arr-stagger > * { animation: rise 700ms var(--ease-out) forwards; }
#arrival.open .arr-stagger > *:nth-child(1) { animation-delay: 120ms; }
#arrival.open .arr-stagger > *:nth-child(2) { animation-delay: 200ms; }
#arrival.open .arr-stagger > *:nth-child(3) { animation-delay: 280ms; }
#arrival.open .arr-stagger > *:nth-child(4) { animation-delay: 360ms; }
@keyframes rise { to { opacity: 1; transform: none; } }

/* ------------------------------------------------------------------
   8. Announcement (PA) toast
------------------------------------------------------------------ */

#pa {
  position: fixed;
  left: 50%;
  bottom: var(--sp-6);
  transform: translate(-50%, 20px);
  z-index: 70;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  max-width: min(760px, 90vw);
  padding: var(--sp-3) var(--sp-5);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-full);
  background: rgba(5, 7, 10, 0.95);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
  color: var(--bone-200);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--d-med) var(--ease-std), transform var(--d-med) var(--ease-out);
}
#pa.show { opacity: 1; transform: translate(-50%, 0); }
#pa .spk {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
  flex: none;
  animation: pulse 1.1s var(--ease-std) infinite;
}
#pa .txt { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* ------------------------------------------------------------------
   8a. The quiet room — a scene, and as little else as possible

   The canvas is already fixed and full-bleed, so this overlay carries
   no background of its own. It is only the handful of words around
   the edge, and even those take themselves away.
------------------------------------------------------------------ */

#quiet {
  position: fixed;
  inset: 0;
  z-index: 52;
  opacity: 0;
  visibility: hidden;
  transition: opacity 1400ms var(--ease-std), visibility 1400ms;
}
#quiet.open { opacity: 1; visibility: visible; }

.q-chrome {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: var(--sp-6) var(--gutter) var(--sp-6);
  /* three and a half seconds, so it leaves without you noticing */
  transition: opacity 3500ms var(--ease-std);
}
body.q-still .q-chrome { opacity: 0; pointer-events: none; }

.q-top {
  grid-row: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-muted);
}
#q-back {
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  letter-spacing: var(--tracking-wide);
  transition: all var(--d-fast) var(--ease-std);
}
#q-back:hover { color: var(--accent); border-color: var(--accent); }
.q-ref { color: var(--accent); }

.q-bottom {
  grid-row: 3;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-6);
  flex-wrap: wrap;
}
.q-text { max-width: 46ch; }
.q-text h2 {
  font-family: var(--font-display);
  --display-wght: 480;
  font-size: var(--fs-xl);
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin-bottom: var(--sp-2);
}
.q-text p {
  color: var(--bone-300);
  font-size: var(--fs-sm);
  line-height: 1.75;
}
.q-acts { display: flex; gap: var(--sp-2); }
.q-btn {
  padding: 9px 16px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
  transition: all var(--d-fast) var(--ease-std);
}
.q-btn:hover { color: var(--accent); border-color: var(--accent); }

.q-hint {
  grid-row: 2;
  align-self: end;
  justify-self: center;
  margin-bottom: var(--sp-6);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-dim);
  opacity: 0;
  animation: qhint 9s var(--ease-std) 2s forwards;
}
@keyframes qhint {
  0% { opacity: 0; }
  18%, 62% { opacity: 1; }
  100% { opacity: 0; }
}

@media (max-width: 700px) {
  .q-bottom { flex-direction: column; align-items: stretch; }
  .q-acts { justify-content: stretch; }
  .q-btn { flex: 1; text-align: center; }
}

/* ------------------------------------------------------------------
   8b. The counter — lost property as a place to put things down
------------------------------------------------------------------ */

.lf-invite {
  margin-top: var(--sp-5);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--accent);
}

.lf-row {
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
}
.lf-row:hover .desc { color: var(--text); }
.lf-row .arrow { transition: opacity var(--d-fast) var(--ease-out), transform var(--d-fast) var(--ease-out); }

.lf-heldhead {
  margin-top: var(--sp-7);
  padding-bottom: var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--accent);
  display: flex;
  justify-content: space-between;
}
.lf-held .ref { color: var(--bone-300); }
.lf-held .desc { color: var(--text); }
.lf-held .when {
  display: block;
  margin-top: 4px;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  color: var(--text-dim);
  text-transform: uppercase;
}

#counter {
  position: fixed;
  inset: 0;
  z-index: 78;
  display: grid;
  place-items: center;
  padding: var(--sp-5);
  background: rgba(3, 4, 6, 0.86);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--d-med) var(--ease-std), visibility var(--d-med);
}
#counter.open { opacity: 1; visibility: visible; }

.ctr-card {
  position: relative;
  width: min(600px, 100%);
  max-height: 88svh;
  overflow-y: auto;
  padding: var(--sp-7);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: linear-gradient(180deg, rgba(13, 17, 24, 0.99), rgba(6, 8, 12, 0.99));
  box-shadow: var(--e-2);
  transform: translateY(14px) scale(0.985);
  transition: transform 420ms var(--ease-out);
}
#counter.open .ctr-card { transform: none; }

#ctr-close {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  padding: 4px 8px;
  border-radius: var(--r-sm);
  transition: color var(--d-fast);
}
#ctr-close:hover { color: var(--accent); }

.ctr-ref {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  color: var(--accent);
  margin-bottom: var(--sp-3);
}
.ctr-item { color: var(--text); font-size: var(--fs-lg); }
.ctr-note {
  margin-top: var(--sp-3);
  margin-bottom: var(--sp-5);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  line-height: 1.75;
  max-width: 46ch;
}

.ctr-prompt {
  margin-top: var(--sp-6);
  font-family: var(--font-display);
  --display-wght: 500;
  font-size: var(--fs-xl);
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.ctr-lede {
  margin-top: var(--sp-3);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  line-height: 1.75;
  max-width: 50ch;
}

#ctr-text {
  display: block;
  width: 100%;
  margin-top: var(--sp-5);
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: rgba(0, 0, 0, 0.4);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  line-height: 1.7;
  resize: vertical;
  cursor: none;
}
#ctr-text::placeholder { color: var(--text-dim); }
#ctr-text:focus { outline: none; border-color: var(--accent); }

.ctr-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-top: var(--sp-4);
  flex-wrap: wrap;
}
.ctr-count {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.ctr-btn {
  padding: var(--sp-3) var(--sp-6);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  transition: all var(--d-fast) var(--ease-std);
}
.ctr-btn:hover:not(:disabled) { color: var(--ink-1000); background: var(--accent); border-color: var(--accent); }
.ctr-btn:disabled { opacity: 0.35; }

.ctr-receipt {
  margin-top: var(--sp-5);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 1.9;
  color: var(--accent);
  letter-spacing: 0.06em;
}

@media (max-width: 620px) {
  .ctr-card { padding: var(--sp-5); }
}

/* ------------------------------------------------------------------
   9. Night service
------------------------------------------------------------------ */

#nightfall {
  position: fixed;
  inset: 0;
  z-index: 45;
  background: #000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 2600ms var(--ease-std);
}
body.dim-1 #nightfall { opacity: 0.62; }
body.dim-2 #nightfall { opacity: 0.945; }

/* the whole document steps back as the night deepens */
body.night .stage,
body.night .topbar { transition: opacity 2400ms var(--ease-std); }
body.dim-1 .stage { opacity: 0.5; }
body.dim-1 .topbar { opacity: 0.25; }
body.dim-2 .stage,
body.dim-2 .topbar { opacity: 0; }

#nightclock {
  position: fixed;
  z-index: 46;
  inset: auto auto var(--sp-9) var(--gutter);
  display: grid;
  gap: var(--sp-2);
  opacity: 0;
  pointer-events: none;
  transition: opacity 2600ms var(--ease-std);
}
body.dim-2 #nightclock { opacity: 1; }
#nightclock .nc-time {
  font-family: var(--font-display);
  font-size: clamp(3rem, 9vw, 7rem);
  line-height: 0.9;
  color: #2a2118;
  font-variant-numeric: tabular-nums;
}
#nightclock .nc-where,
#nightclock .nc-timer {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: #1b1712;
}

/* ---- the rail ----------------------------------------------------
   Not a dialog but a platform edge: a narrow strip flush to the right
   of the window, everything on it running vertically.
------------------------------------------------------------------ */

#night {
  position: fixed;
  /* above the destination surfaces (z-50) so night service can be
     opened and driven from inside a world, not just the concourse */
  z-index: 55;
  top: 0;
  right: 0;
  bottom: 0;
  width: 92px;
  border-left: 1px solid var(--border-strong);
  background: linear-gradient(180deg, rgba(9, 12, 17, 0.96), rgba(5, 7, 10, 0.985));
  box-shadow: -24px 0 60px -30px rgba(0, 0, 0, 1);
  opacity: 0;
  visibility: hidden;
  transform: translateX(100%);
  transition: opacity var(--d-med) var(--ease-out), transform 520ms var(--ease-out),
    visibility var(--d-med);
}
#night.open { opacity: 1; visibility: visible; transform: none; }

/* the page steps aside for the rail instead of being covered by it */
.stage, .topbar { transition: padding-right var(--d-med) var(--ease-out); }
body.night .stage { padding-right: 92px; }
body.night .topbar { padding-right: calc(var(--gutter) + 92px); }
/* the rail takes the width the labels were using */
.topbar .brand, .tb-btn { white-space: nowrap; }
body.night .tb-label, body.night #sound-label { display: none; }
body.night .topbar .center { display: none; }
body.dim-1 #night, body.dim-2 #night { opacity: 0; visibility: hidden; }

/* the night draining away, bottom to top */
.nr-drain {
  position: absolute;
  inset: 0 auto 0 -1px;
  width: 2px;
  background: rgba(255, 179, 71, 0.10);
  overflow: hidden;
}
#nr-fill {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 0;
  background: linear-gradient(180deg, transparent, var(--accent));
  box-shadow: 0 0 12px rgba(255, 179, 71, 0.6);
  transition: height 1s linear;
}

.nr-inner {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-5);
  padding: var(--sp-4) 0 var(--sp-5);
  overflow: hidden;
}

.nr-top {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
}
.nr-moon { color: var(--accent); font-size: var(--fs-lg); line-height: 1; }
#night-close {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-dim);
  padding: 3px 7px;
  border-radius: var(--r-sm);
  transition: color var(--d-fast);
}
#night-close:hover { color: var(--accent); }

.nr-title {
  writing-mode: vertical-rl;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}

.nr-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
  width: 56px;
}
.nr-label {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.chips { display: flex; flex-direction: column; gap: 4px; width: 100%; }
.chips button {
  padding: 6px 0;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.06em;
  color: var(--text-muted);
  transition: all var(--d-fast) var(--ease-std);
}
.chips button:hover { color: var(--accent); border-color: var(--accent); }
.chips button[aria-pressed='true'] {
  color: var(--ink-1000);
  background: var(--accent);
  border-color: var(--accent);
}

.nr-status {
  margin-top: auto;
  writing-mode: vertical-rl;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------
   10. Small screens — the board becomes something you pan
------------------------------------------------------------------ */

@media (max-width: 760px) {
  :root {
    --flap-w: 9px;
    --flap-h: 15px;
  }
  .board-colhead,
  .board-row { gap: var(--sp-3); }
  .w-time { width: calc(var(--flap-w) * 5 + 4px); }
  .w-dest { width: calc(var(--flap-w) * 16 + 15px); }
  .w-plat { width: calc(var(--flap-w) * 2 + 1px); }
  .w-status { width: calc(var(--flap-w) * 9 + 8px); }
  .board-scroll { padding: var(--sp-4) var(--sp-4) var(--sp-3); }
  .board-row .idx, .w-idx { width: 2em; }
  .board-colhead { letter-spacing: 0.12em; }
  .board-colhead .lg { display: none; }
  .board-colhead .sm { display: inline; }
  .board-head { align-items: flex-start; }
  .board-foot { flex-direction: column; align-items: flex-start; gap: var(--sp-1); }
  .hero { min-height: 92svh; }
  .hero-title { line-height: 0.9; }
  /* portrait cover-crops the picture hard; centre the subject rather
     than favouring the desktop framing, which pushed it off one side */
  .hero-back, .hero-fore { object-position: 50% 42%; }
  /* the clock is the widest thing in the corner cluster and the least
     load-bearing — dropping it leaves just the three glyphs */
  #clock { display: none; }
  /* the controls sit tighter to the corner on a phone */
  #controls { padding: var(--sp-2) var(--sp-4); }
  .ctl { width: 34px; height: 34px; }

  /* --- arrival detail, narrow ------------------------------------- */
  /* The top row put the back button and the service ref on one line
     with space-between; a real ref ("MDR · PLATFORM 1") is wider than
     the placeholder and ran off the edge. It wraps now, and the ref
     takes its own line under the button. */
  .arr-top { flex-wrap: wrap; gap: var(--sp-3); }
  #arr-ref, #reel-ref { width: 100%; }
  #arr-name, #reel-title { font-size: var(--fs-2xl); }
  /* mono advisory copy can carry long unbroken tokens; let them break
     rather than push the box past the screen */
  .arr-advisory { overflow-wrap: anywhere; }
  /* the onward-service chips wrap instead of running off to the right */
  .arr-nav { flex-wrap: wrap; }
  #night { width: 74px; }
  body.night .stage { padding-right: 74px; }
  body.night .topbar { padding-right: calc(var(--gutter) + 74px); }
  .nr-block { width: 46px; }
  .nr-inner { gap: var(--sp-4); }
  #nightclock { inset: auto auto var(--sp-8) var(--sp-4); }
  .arr-inner { padding-top: var(--sp-7); }
  .arr-foot { flex-direction: column; align-items: flex-start; }
  #arr-strap { max-width: none; }
}

/* a hint that the board can be dragged sideways */
@media (max-width: 760px) {
  .board-shell .board-scroll { -webkit-overflow-scrolling: touch; }
  .board-shell::after { height: 100px; }
}

/* ------------------------------------------------------------------
   11. Reduced motion
------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .hero-title .ln > span { transform: none; }
  .reveal { opacity: 1; transform: none; }
  .arr-stagger > * { opacity: 1; transform: none; }
  body { cursor: auto; }
  #cursor { display: none; }
}

@media (hover: none) {
  body, button { cursor: auto; }
  #cursor { display: none; }
}

/* ------------------------------------------------------------------
   Touch devices: keyboard vocabulary out, touch vocabulary in

   `pointer: coarse` is the finger. None of the shortcut copy means
   anything to it — there is no Esc, no number row, no Q — so every
   keyboard hint is hidden and the one touch equivalent is shown. The
   `.touch-hint` is display:none everywhere else so it never doubles up
   with the keyboard line on a desktop. */
.touch-hint { display: none; }

@media (pointer: coarse) {
  .kbd-hint { display: none !important; }
  .touch-hint { display: inline; }
  /* the site now works here, so it no longer tells you to leave */
  .boot-note { display: none; }
}
