/* ---- self-hosted webfonts ----
   Previously these came from fonts.googleapis.com, which cost a DNS+TLS
   round trip for the CSS and another for each file before any text could
   paint in its real face. Serving them from our own origin removes both.
   font-display: swap keeps text readable during the swap, and the fallback
   metrics below are overridden to match so that swap does not shift layout. */

@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/press-start-2p-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/press-start-2p-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'VT323';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/vt323-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'VT323';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/vt323-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Metric-matched fallbacks. Both faces are monospace, so overriding the
   fallback's metrics to match keeps every line box the same size before and
   after the swap -- otherwise the pixel faces, whose proportions are nothing
   like a system font, visibly reflow the whole UI on load. */
@font-face {
  font-family: 'Press Start 2P Fallback';
  src: local('Courier New'), local('Consolas'), local('monospace');
  size-adjust: 128%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'VT323 Fallback';
  src: local('Courier New'), local('Consolas'), local('monospace');
  size-adjust: 82%;
  ascent-override: 96%;
  descent-override: 24%;
  line-gap-override: 0%;
}

/* ============ TypeAway — Pixel Travel Hub ============ */
:root {
  --sky: #7ec8e3;
  --sky-deep: #4a9fd8;
  --navy: #1e3050;
  --navy-2: #2a4266;
  --cream: #f5eeda;
  --cream-2: #e8ddbf;
  --teal: #2fa89a;
  --coral: #ff6f61;
  --yellow: #f7c948;
  --green: #2e7d32;          /* AA-passing CTA green */
  --green-accent: #4caf50;   /* accents on dark bg only */
  --red: #e04444;
  --purple: #7c4dbc;
  --gold: #c9a227;
  --burgundy: #6b2233;
  --px-border: 3px;
  --font-pixel: 'Press Start 2P', 'Press Start 2P Fallback', monospace;
  --font-lcd: 'VT323', 'VT323 Fallback', monospace;

  /* ---- shared design tokens (Retro Pixel Airport OS) ---- */
  --ink: #101a2e;              /* darkest outline */
  --navy-3: #16233c;           /* recessed surfaces */
  --panel-line: #35486e;
  --paper: #fdf8ec;            /* ticket / boarding pass */
  --paper-edge: #d4c69e;
  --sky-glass: #8fd0e8;        /* terminal windows */
  --floor: #9aa48c;

  --bd-1: 2px;                 /* thin outline  */
  --bd-2: 3px;                 /* standard outline */
  --bd-3: 4px;                 /* chrome / frame outline */

  /* firm pixel offset shadows (blur 0) */
  --px-sh-1: 3px 3px 0 rgba(16,26,46,.45);
  --px-sh-2: 5px 5px 0 rgba(16,26,46,.5);
  --px-sh-3: 0 8px 0 rgba(16,26,46,.4);
  /* top-left light source bevel */
  --bevel-light: inset 3px 3px 0 rgba(255,255,255,.45);
  --bevel-dark: inset -3px -3px 0 rgba(16,26,46,.25);
  /* design tokens */
  --radius-sm: 4px;
  --radius: 8px;
  --radius-lg: 12px;
  --shadow-1: 0 4px 0 rgba(0,0,0,.35);
  --shadow-2: 0 8px 0 rgba(0,0,0,.35);
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 40px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  background: #14213d;
  font-family: var(--font-pixel);
  color: var(--navy);
  line-height: 1.6;
  image-rendering: pixelated;
  overflow: hidden;
}

/* The stage. Everything below is authored in DESIGN px against 1280x800;
   --ui-zoom (set from js/game.js) maps that stage onto the actual window.
   Width and height are divided by the zoom so that, once scaled back up, the
   stage lands on exactly the viewport -- otherwise it would overflow by the
   zoom factor. Any vh/dvh INSIDE this box is viewport-relative, not design-px,
   so each one is divided by --ui-zoom to keep meaning what it says. */
#app {
  width: calc(100vw / var(--ui-zoom, 1));
  height: calc(100dvh / var(--ui-zoom, 1));
  zoom: var(--ui-zoom, 1);
  position: relative;
}

/* The bar sits above the screen stack rather than inside any one screen, so
   the screens start below it. In-game the bar is removed from the flow
   entirely and the screen reclaims the full height -- the map needs it, and
   the gameplay HUD already owns that edge. */
#app { display: flex; flex-direction: column; }
.screen-stack { position: relative; flex: 1 1 auto; min-height: 0; }
body.in-game .airport-topbar { display: none; }

.screen {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  overflow: hidden auto;
}
.screen.active { display: flex; animation: screenIn .28s ease-out; }
@keyframes screenIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
#screen-game { overflow: hidden; }

/* ---------- shared ---------- */
.panel {
  background: var(--cream);
  border: var(--px-border) solid var(--navy);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-1);
}

.btn {
  font-family: var(--font-pixel);
  font-size: 13px;
  line-height: 1.2;
  padding: var(--s3) 20px;
  border: var(--px-border) solid var(--navy);
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--navy);
  background: var(--cream);
  box-shadow: var(--shadow-1);
  transition: transform .06s;
}
.btn:hover { transform: translateY(-2px); filter: brightness(1.05); }
.btn:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(0,0,0,.4); }
.btn-big { font-size: 16px; padding: var(--s4) 34px; }
.btn-primary { background: var(--yellow); }
.btn-secondary { background: var(--cream-2); }
.btn-success {
  background: var(--green); color: #fff;
  box-shadow: inset 0 3px 0 rgba(255,255,255,.25), var(--shadow-1);
}

/* keyboard focus — coral ring everywhere */
/* Focus WE moved, not the player -- no ring. The class is dropped again on the
   first keydown or blur, so the moment the player actually takes over the
   keyboard the ring comes straight back.
   The class is doubled on purpose: every rule below is (0,2,0) and sits later
   in the file, so a single .autofocused would tie on specificity and lose on
   source order -- which is exactly what put a coral ring around the autofocused
   NEXT DESTINATION sign. (0,3,0) wins no matter where a new focus rule lands. */
.autofocused.autofocused:focus-visible { outline: none; }
.btn:focus-visible, .country-tile:focus-visible,
.gate:focus-visible, .trip-card:focus-visible, .search-bar:focus-visible,
.exit-sign:focus-visible, .hud-exit:focus-visible {
  outline: 3px solid var(--coral);
  outline-offset: 3px;
}
.type-input:focus {
  border-color: var(--yellow);
  box-shadow: 0 0 0 3px rgba(247,201,72,.45);
  outline: none;
}

@keyframes idlePulse { 50% { transform: scale(1.04); } }

.screen-heading {
  font-size: 22px;
  line-height: 1.3;
  color: var(--cream);
  text-shadow: 2px 2px 0 rgba(0,0,0,.5);
  margin: var(--s5) 0 var(--s4);
  letter-spacing: 2px;
}
.banner-heading {
  background: var(--navy);
  border: var(--px-border) solid var(--yellow);
  color: var(--yellow);
  padding: 14px 40px;
  border-radius: var(--radius-sm);
}

.hidden { display: none !important; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* ---------- ad slots ---------- */
.ad-slot { width: 240px; padding: var(--s3); text-align: center; }
.ad-label {
  font-size: 10px;
  color: #6b6250;
  letter-spacing: 1px;
  margin-bottom: var(--s2);
}
.ad-chip {
  display: inline-block;
  background: var(--cream);
  border: 2px solid var(--navy);
  border-radius: var(--radius-sm);
  color: #6b6250;
  font-size: 10px;
  letter-spacing: 1px;
  padding: var(--s1) 10px;
  margin-bottom: var(--s2);
}
.ad-emoji { font-size: 40px; margin: var(--s2) 0; }
.ad-title { font-size: 11px; line-height: 1.6; }
.ad-sub { font-family: var(--font-lcd); font-size: 18px; color: #1d7a6e; margin-top: var(--s1); }

/* ---------- toast ---------- */
/* on the gameplay screen the toast must clear the typing bar */
body.in-game .toast { bottom: 160px; }
.toast {
  position: fixed;
  bottom: 26px; left: 50%;
  transform: translateX(-50%);
  background: var(--navy);
  color: var(--yellow);
  border: var(--px-border) solid #101a2e;
  border-radius: var(--radius-sm);
  font-size: 11px;
  padding: var(--s3) 20px;
  z-index: 100;
  box-shadow: var(--shadow-1);
  animation: toastIn .25s ease-out;
}
@keyframes toastIn { from { transform: translate(-50%, 120%); } }

/* ============ SCREEN 1: START — AIRPORT CHECK-IN CONCOURSE ============
   Depth planes, lightest/flattest furthest away:
   P0 outside sky · P1 far interior · P2 midground (only plane with full
   saturation — the kiosk) · P3 foreground silhouettes.
   Architecture uses square corners + hard gradient stops only. No emoji. */
#screen-start { background: var(--navy); justify-content: flex-start; }

.terminal-bg { position: absolute; inset: 0; min-height: 100%; overflow: hidden; pointer-events: none; }

/* --- P0: outside --- */
.tb-sky {
  position: absolute; inset: 0 0 34% 0;
  background: linear-gradient(#cfeaf7 0 38%, #b3ddf0 38% 62%, #9ed3ea 62% 82%, #cfe0dd 82% 100%);
}
.tb-cloud {
  position: absolute;
  height: 12px; width: 46px;
  background: rgba(255,255,255,.9);
  box-shadow: 16px -8px 0 -2px rgba(255,255,255,.9), 34px 2px 0 -3px rgba(255,255,255,.9);
}
.tb-cloud.c1 { top: 12%; left: -10%; animation: drift 96s linear infinite; }
.tb-cloud.c2 { top: 22%; left: -30%; transform: scale(1.5); opacity: .7; animation: drift 140s linear infinite; }
@keyframes drift { to { transform: translateX(140vw); } }
.tb-cloud.c2 { animation-name: drift2; }
@keyframes drift2 { to { transform: translateX(140vw) scale(1.5); } }
.tb-hills {
  position: absolute; bottom: 34%; height: 7%; width: 100%;
  background:
    repeating-linear-gradient(90deg,
      transparent 0 40px, rgba(30,48,80,.10) 40px 68px,
      transparent 68px 132px, rgba(30,48,80,.14) 132px 152px);
}
.tb-runway {
  position: absolute; bottom: 34%; height: 3%; width: 100%;
  background: linear-gradient(#b9bfc9 0 55%, #9aa2ad 55% 100%);
  border-top: 2px solid rgba(30,48,80,.25);
}
/* CSS plane silhouette (no emoji) */
.tb-flyby {
  position: absolute; top: 15%; left: -10%;
  width: 26px; height: 6px;
  background: rgba(255,255,255,.95);
  clip-path: polygon(0 40%, 62% 0, 78% 40%, 100% 46%, 78% 60%, 62% 100%, 0 60%);
  box-shadow: -12px 0 0 -2px rgba(255,255,255,.5);
  animation: flyby 34s linear infinite;
}
@keyframes flyby { to { transform: translateX(130vw) translateY(-18px); } }

/* --- P1: curtain wall (the outside is seen THROUGH this) --- */
.tb-curtain {
  position: absolute; inset: 0 0 34% 0;
  background:
    /* glass reflection streaks */
    repeating-linear-gradient(112deg,
      transparent 0 60px, rgba(245,238,218,.10) 60px 76px,
      transparent 76px 132px, rgba(245,238,218,.06) 132px 140px),
    /* horizontal transoms */
    linear-gradient(rgba(16,26,46,.5) 0 5px, transparent 5px) 0 32% / 100% 100% no-repeat,
    linear-gradient(rgba(16,26,46,.5) 0 5px, transparent 5px) 0 66% / 100% 100% no-repeat,
    /* vertical mullions: heavy post every 3rd bay */
    repeating-linear-gradient(90deg,
      rgba(16,26,46,.72) 0 7px, transparent 7px 112px),
    repeating-linear-gradient(90deg,
      rgba(16,26,46,.85) 0 11px, transparent 11px 336px);
  border-bottom: 7px solid var(--ink);
}
/* wall base so the sky sits behind a wall, not butting into the floor */
.tb-wallbase {
  position: absolute; bottom: 34%; height: 3.2%; width: 100%;
  background: linear-gradient(#5c6a86, #3d4a66);
  border-bottom: 4px solid var(--ink);
  box-shadow: 0 4px 0 rgba(16,26,46,.35);
}

/* --- ceiling soffit + recessed light strip (the scene's light source) --- */
.tb-soffit {
  position: absolute; top: 0; height: 9%; width: 100%;
  display: flex; align-items: flex-end; justify-content: space-around;
  padding-bottom: 4px;
  background:
    repeating-linear-gradient(90deg, rgba(16,26,46,.55) 0 4px, transparent 4px 58px),
    linear-gradient(#1a2740 0 62%, #16233c 62% 100%);
  border-bottom: 4px solid var(--ink);
  box-shadow: 0 6px 0 rgba(16,26,46,.4);
}
.tb-soffit i {
  width: 68px; height: 7px;
  background: linear-gradient(var(--cream) 0 60%, #e8d99f 60% 100%);
  box-shadow: 0 8px 22px 5px rgba(247,201,72,.28);
}

/* --- P1/P2: support columns with cylinder shading --- */
.tb-col {
  position: absolute; top: 9%; bottom: 26%;
  width: 40px;
  background: linear-gradient(90deg,
    #55637f 0 4px,      /* reflected light edge */
    #35415c 4px 12px,   /* core shadow, held in from the edge */
    #6a7893 12px 24px,  /* midtone */
    #8b98b0 24px 32px,  /* light */
    #a8b3c8 32px 40px); /* highlight */
  border-left: 3px solid var(--ink);
  border-right: 3px solid var(--ink);
}
.tb-col.left { left: 11%; }
.tb-col.right { right: 11%; }
.tb-col::after {          /* capital where column meets the soffit */
  content: ""; position: absolute; top: -8px; left: -7px; right: -7px; height: 10px;
  background: linear-gradient(#8b98b0, #55637f);
  border: 3px solid var(--ink);
}

/* --- P2: perspective floor --- */
.tb-floor {
  position: absolute; inset: 66% 0 0 0;
  overflow: hidden;
  background: linear-gradient(180deg, rgba(16,26,46,.42) 0, rgba(16,26,46,0) 26%), #aab1bd;
}
/* tile grid laid onto the floor plane with a GPU perspective transform
   (a conic gradient here rasterises hundreds of wedges and stalls paint) */
.tb-floor::after {
  content: "";
  position: absolute; inset: -70% -40% -10% -40%;
  background:
    repeating-linear-gradient(90deg, rgba(16,26,46,.17) 0 2px, transparent 2px 96px),
    repeating-linear-gradient(0deg, rgba(16,26,46,.13) 0 2px, transparent 2px 76px);
  transform: perspective(320px) rotateX(63deg);
  transform-origin: 50% 100%;
}
.tb-floor::before {       /* near-floor sheen band */
  content: ""; position: absolute; inset: auto 0 0 0; height: 34%;
  background: linear-gradient(transparent, rgba(207,234,247,.22));
}
/* warm pool of light under the kiosk — banded, not a soft blur */
.tb-lightpool {
  position: absolute; left: 50%; bottom: 6%;
  width: 620px; height: 150px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at 50% 50%,
    rgba(247,201,72,.30) 0 32%,
    rgba(247,201,72,.18) 32% 56%,
    rgba(247,201,72,.09) 56% 78%,
    transparent 78%);
}

/* --- P3: passenger silhouettes (pure CSS, no emoji) --- */
.tb-figure {
  position: absolute;
  width: 15px; height: 26px;
  background: var(--ink);
  border-radius: 7px 7px 1px 1px;
  box-shadow:
    -4px 22px 0 -5px var(--ink),   /* left leg */
    4px 24px 0 -5px var(--ink);    /* right leg */
}
.tb-figure::before {               /* head */
  content: ""; position: absolute; top: -13px; left: 50%;
  width: 11px; height: 11px; margin-left: -5.5px;
  border-radius: 50%; background: var(--ink);
}
.tb-figure::after {                /* contact shadow */
  content: ""; position: absolute; left: -9px; bottom: -34px;
  width: 33px; height: 8px; border-radius: 50%;
  background: rgba(16,26,46,.3);
}
.tb-figure .tb-bag {               /* roller bag */
  position: absolute; right: -13px; bottom: -26px;
  width: 11px; height: 15px;
  background: #2c4570;
  border: 2px solid var(--ink);
}
.tb-figure .tb-bag::before {
  content: ""; position: absolute; top: -9px; left: 3px;
  width: 3px; height: 9px; background: var(--ink);
}
.tb-figure.far  { bottom: 31%; left: 22%; transform: scale(.55); opacity: .34; }
.tb-figure.mid  { bottom: 25%; left: 32%; transform: scale(.8);  opacity: .5; animation: stroll 52s linear infinite; }
/* a small queue waiting at the kiosk — reads as an airport, stays out of the way */
.tb-figure.queue { opacity: .45; }
.tb-figure.queue.a { bottom: 20%; left: 40%; transform: scale(.72); }
.tb-figure.queue.b { bottom: 18%; right: 39%; transform: scale(.78); }
@keyframes stroll { to { transform: scale(.8) translateX(520px); } }

/* screen-level grade: pushes the background back, frames the kiosk */
.tb-vignette {
  position: absolute; inset: 0;
  box-shadow: inset 0 0 150px 46px rgba(16,26,46,.4);
}

/* --- AirportTopBar: doubles as the ceiling fascia --- */
.airport-topbar {
  position: relative; z-index: 3;
  width: 100%;
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--s3);
  flex: 0 0 auto;
  padding: var(--s2) var(--s4);
  background: linear-gradient(#101a2e, #16233c);
  border-bottom: var(--bd-3) solid var(--ink);
}
.atb-left { display: flex; align-items: center; gap: var(--s3); }
.atb-logo { font-size: 11px; color: var(--yellow); letter-spacing: 1px; }
.atb-divider { width: 2px; height: 15px; background: var(--panel-line); }
.atb-player { font-size: 10px; color: #d5deec; }
.atb-player b { color: #6fd8c8; }
.atb-right { display: flex; gap: var(--s1); }
.atb-btn {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-pixel); font-size: 10px; letter-spacing: 1px;
  color: var(--cream);
  background: #22375c;
  border: 2px solid var(--panel-line);
  border-radius: var(--radius-sm);
  padding: 8px 11px;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(0,0,0,.45);
}
.atb-btn:hover { color: var(--navy); background: var(--yellow); border-color: var(--navy); }
.atb-btn:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }

/* --- the hero logo --- */
.title-block { position: relative; z-index: 2; text-align: center; margin: var(--s5) 0 var(--s4); }
.game-title {
  font-size: clamp(38px, 5.4vw, 64px);
  line-height: 1.1;
  letter-spacing: 4px;
  color: var(--yellow);
  text-shadow:
    -4px 0 0 var(--ink), 4px 0 0 var(--ink), 0 -4px 0 var(--ink), 0 4px 0 var(--ink),
    -4px -4px 0 var(--ink), 4px -4px 0 var(--ink), -4px 4px 0 var(--ink), 4px 4px 0 var(--ink),
    8px 10px 0 rgba(16,26,46,.45);
}
.subtitle-ribbon {
  display: inline-block;
  margin-top: 14px;
  padding: 10px 38px;
  font-size: 12px;
  letter-spacing: 3px;
  color: var(--cream);
  background: var(--navy);
  border: var(--bd-2) solid var(--ink);
  box-shadow: 0 5px 0 rgba(16,26,46,.5);
  clip-path: polygon(14px 0, calc(100% - 14px) 0, 100% 50%, calc(100% - 14px) 100%, 14px 100%, 0 50%);
}

/* --- LAYER 2/3: kiosk focal point, flanks pinned outward --- */
.start-main {
  position: relative; z-index: 2;
  flex: 1;
  width: 100%;
  display: grid;
  grid-template-columns: minmax(230px, 1fr) auto minmax(230px, 1fr);
  justify-items: center;
  align-items: end;                 /* everything stands ON the floor */
  gap: var(--s4);
  padding: 0 clamp(16px, 5vw, 72px) 8%;
}

/* DepartureBoard — hung from the ceiling */
.departure-board {
  position: relative;
  justify-self: start;
  width: clamp(240px, 21vw, 300px);
  background: #14202e;
  border: var(--bd-3) solid #0b1420;
  border-radius: var(--radius-sm);
  padding: var(--s3);
  color: #ffd75e;
  box-shadow: var(--bevel-light), var(--px-sh-2);
}
.departure-board::before {          /* drop rods to the ceiling */
  content: ""; position: absolute; top: -60px; left: 22px; right: 22px; height: 60px;
  background:
    linear-gradient(90deg, transparent 0 6px, #6a7893 6px 10px, transparent 10px) left / 50% 100% no-repeat,
    linear-gradient(90deg, transparent 0 calc(100% - 10px), #6a7893 calc(100% - 10px) calc(100% - 6px), transparent) right / 50% 100% no-repeat;
}
.board-title { font-size: 11px; color: #fff; letter-spacing: 2px; margin-bottom: var(--s2); }
#departure-table { width: 100%; table-layout: fixed; font-family: var(--font-lcd); font-size: 20px; border-collapse: collapse; }
#departure-table td {
  padding: 3px 5px;
  border-bottom: 2px solid #0b1420;
  background: linear-gradient(#1b2a3c 0 49%, #16222f 51%);
  text-shadow: 0 0 4px rgba(255,215,94,.4);
  font-variant-numeric: tabular-nums;
  overflow: hidden; white-space: nowrap;
}
#departure-table td:nth-child(1) { width: 38%; }
#departure-table td:nth-child(2) { width: 18%; color: #9fd8ee; }
#departure-table td:nth-child(3) { width: 20%; text-align: right; }
#departure-table td:nth-child(4) { width: 24%; text-align: right; }
#departure-table .ontime { color: #56d364; text-shadow: 0 0 4px rgba(86,211,100,.4); }
#departure-table tr.rec td { background: linear-gradient(#2a3f2a 0 49%, #223522 51%); color: var(--yellow); }
#departure-table tr.rec td:first-child::before { content: "\25B6 "; color: var(--yellow); }
#departure-table .flip { animation: flipCell .45s steps(3) both; }
@keyframes flipCell { from { transform: rotateX(90deg); } }
.board-foot { margin-top: var(--s2); font-size: 9px; letter-spacing: 1px; color: var(--yellow); text-align: right; }

/* CheckInKiosk — the focal point, standing on the floor */
.kiosk {
  position: relative;
  width: clamp(380px, 32vw, 460px);
  background: linear-gradient(180deg, #fbf5e3 0 8px, var(--cream-2) 8px calc(100% - 10px), #d8cca6 0);
  border: var(--bd-3) solid var(--navy);
  border-radius: 12px 12px 3px 3px;
  padding: var(--s4);
  margin-bottom: 34px;
  box-shadow: var(--bevel-light), var(--bevel-dark), 0 12px 0 rgba(16,26,46,.4);
}
.kiosk::after {            /* plinth, flush with the body */
  content: ""; position: absolute; left: 8%; right: 8%; bottom: -30px;
  height: 30px;
  background: linear-gradient(90deg, #6b6250 0 6px, #8f866c 6px calc(100% - 6px), #5e5647 calc(100% - 6px));
  border: var(--bd-3) solid var(--navy); border-top: none;
  border-radius: 0 0 4px 4px;
}
.kiosk::before {           /* contact shadow touching the plinth */
  content: ""; position: absolute; left: 0; right: 0; bottom: -38px;
  height: 16px; border-radius: 50%;
  background: rgba(16,26,46,.34); z-index: -1;
}
.kiosk-head { font-size: 10px; letter-spacing: 2px; color: #7a705a; text-align: center; margin-bottom: var(--s2); }
.kiosk-screen {
  position: relative; overflow: hidden;
  background: radial-gradient(120% 90% at 50% 30%, var(--navy-2) 0%, var(--navy) 70%);
  border: 6px solid var(--ink);
  border-radius: var(--radius-sm);
  padding: var(--s5) var(--s4) var(--s4);
  text-align: center;
  box-shadow: inset 0 5px 0 rgba(0,0,0,.5), inset 0 -2px 0 rgba(126,200,227,.15), 0 0 22px rgba(47,168,154,.32);
}
.kiosk-screen::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(255,255,255,.05) 0 2px, transparent 2px 4px);
}
.kiosk-msg {
  font-size: 17px; line-height: 1.9; color: #fff;
  text-shadow: 0 0 10px rgba(126,200,227,.6);
  animation: kioskGlow 3.2s ease-in-out infinite;
}
@keyframes kioskGlow { 50% { text-shadow: 0 0 16px rgba(126,200,227,.9); } }
.kiosk-route {
  display: flex; align-items: center; justify-content: center; gap: var(--s2);
  font-family: var(--font-lcd); font-size: 21px;
  color: #bfe4f2;
  margin: var(--s3) 0 var(--s4);
}
.kiosk-route i { color: #5b7196; font-style: normal; }
.kiosk-route .kr-diff { color: #8fecb8; }
.kiosk-screen .btn { position: relative; z-index: 1; }
/* attract loop on the one primary action: a gentle lift plus an expanding
   ring. transform/opacity only, and it stops the moment you interact. */
#btn-get-ticket { animation: ctaLift 2.2s ease-in-out infinite; }
#btn-get-ticket::after {
  content: "";
  position: absolute; inset: -6px;
  border: 3px solid var(--yellow);
  border-radius: 8px;
  opacity: 0;
  pointer-events: none;
  animation: ctaRing 2.2s ease-out infinite;
}
@keyframes ctaLift { 50% { transform: translateY(-4px); } }
@keyframes ctaRing {
  0%   { opacity: .85; transform: scale(1); }
  70%, 100% { opacity: 0; transform: scale(1.3); }
}
#btn-get-ticket:hover, #btn-get-ticket:focus-visible { animation: none; }
#btn-get-ticket:hover::after, #btn-get-ticket:focus-visible::after { animation: none; opacity: 0; }
.kbd-hint { margin-top: var(--s3); font-size: 10px; letter-spacing: 1px; color: #b9c6dc; }
.kbd-hint kbd {
  font-family: var(--font-pixel); font-size: 10px;
  background: var(--navy-3); color: var(--cream);
  border: 2px solid var(--panel-line); border-radius: 3px;
  padding: 3px 6px; margin-right: 5px;
}
.kiosk-hw { display: flex; gap: var(--s2); align-items: center; justify-content: flex-end; margin-top: var(--s3); }
.hw-reader { width: 46px; height: 13px; background: #22293a; border: 2px solid var(--ink); box-shadow: inset 0 3px 0 rgba(0,0,0,.5); }
.hw-scale {
  font-size: 9px; letter-spacing: 1px; color: #7a705a;
  border: 2px solid #b8ab8a; border-radius: 3px; padding: 3px 6px;
}
.hw-led { width: 9px; height: 9px; border-radius: 50%; background: var(--green-accent); box-shadow: 0 0 6px var(--green-accent); animation: ledBlink 1.4s steps(2) infinite; }
@keyframes ledBlink { 50% { opacity: .25; box-shadow: none; } }

/* SponsoredTravelBoard — hung from a truss, same top edge as the departures */
.billboard {
  position: relative;
  justify-self: end;
  width: clamp(240px, 21vw, 300px);
  background: var(--ink);
  border: var(--bd-3) solid #000;
  border-radius: var(--radius-sm);
  padding: var(--s2);
  box-shadow: var(--px-sh-2);
}
.billboard::before {                /* single truss to the ceiling */
  content: ""; position: absolute; top: -60px; left: 50%; margin-left: -5px;
  width: 10px; height: 60px; background: #6a7893;
}
.bb-label { font-size: 9px; letter-spacing: 2px; color: #b9c6dc; text-align: center; margin-bottom: var(--s1); }
.bb-screen {
  background: linear-gradient(#1b2a3c, #16222f);
  border: 2px solid var(--panel-line);
  border-radius: 3px;
  padding: var(--s3) var(--s2);
  text-align: center;
}
.bb-art { font-size: 36px; }
.bb-title { font-size: 10px; color: var(--cream); margin-top: var(--s2); line-height: 1.6; }
.bb-sub { font-family: var(--font-lcd); font-size: 18px; color: #6fd8c8; }

/* terminal footer band */
.start-footer {
  position: relative; z-index: 3;
  flex: 0 0 auto;
  width: 100%; margin-top: auto;
  display: flex; gap: var(--s3); justify-content: center; align-items: center;
  min-height: 26px;
  background: rgba(16,26,46,.82);
  border-top: 2px solid var(--ink);
  font-size: 10px; color: #b9c6dc;
}
.start-footer a { color: #6fd8c8; text-decoration: underline; }

/* ============ SCREEN 2: DESTINATION — FLIGHT PLANNER ============ */
#screen-destination { background: linear-gradient(#2b4368, var(--navy)); justify-content: center; }
.planner {
  width: min(1180px, 96vw);
  margin: var(--s4) auto;
  display: flex; flex-direction: column;
  background: var(--navy-3);
  border: var(--bd-3) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--px-sh-3);
  overflow: hidden;
  /* Fit the window. The two panels inside were sized from their own content --
     a 250px floor under the route map, a 380px cap on the country grid -- which
     on a maximised window added up to more than the screen and pushed the
     boarding pass below the fold. The panel is capped to the screen instead and
     the space is handed down: the map and the grid take what is actually there,
     and the grid (which already scrolls) absorbs whatever is left over. */
  max-height: calc(100% - var(--s4) * 2);
  /* .screen is a flex column, so this is a flex item and would shrink. Normally
     min-height:auto stops an item collapsing under its own content -- but that
     automatic minimum resolves to ZERO as soon as the item has overflow other
     than visible, which the rounded corners above need. The result was the
     panel being squashed and then clipping its own footer: the boarding pass
     and the MULTIPLAYER switch were cut off with no scrollbar to reach them,
     because the squashed item still fitted the screen. Refusing to shrink puts
     the height back and lets .screen scroll instead. */
  flex-shrink: 0;
}
.planner-head {
  overflow: visible;
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--s4); flex-wrap: wrap;
  background: var(--ink);
  padding: var(--s3) var(--s4);
  border-bottom: var(--bd-2) solid #000;
}
.ph-title { font-size: 18px; color: var(--yellow); letter-spacing: 2px; }
.ph-steps { list-style: none; display: flex; gap: var(--s3); margin-top: var(--s2); }
.ph-steps .step {
  display: flex; align-items: center; gap: 5px;
  font-size: 8px; letter-spacing: 1px; color: #7d8aa3;
}
.ph-steps .step b {
  display: grid; place-items: center;
  width: 16px; height: 16px;
  background: var(--navy-3); color: #7d8aa3;
  border: 2px solid var(--panel-line); border-radius: 50%;
  font-size: 7px;
}
.ph-steps .step.is-active { color: var(--cream); }
.ph-steps .step.is-active b { background: var(--yellow); color: var(--navy); border-color: var(--navy); }
.ph-steps .step.is-done b { background: var(--green); color: #fff; border-color: var(--navy); }
.route-codes { display: flex; align-items: stretch; gap: var(--s3); }
.route-codes > * { align-self: stretch; }
.rc-chip {
  position: relative;          /* anchors the "PICK ME" cue */
  display: grid;
  justify-items: center;
  gap: 3px;
  font-family: var(--font-pixel);
  background: var(--navy-3);
  border: var(--bd-2) solid var(--panel-line);
  border-radius: var(--radius-sm);
  padding: var(--s2) var(--s4);
  min-width: 172px;
  cursor: pointer;
  transition: transform .08s steps(2);
}
.rc-chip:hover { transform: translateY(-2px); }
.rc-chip:focus-visible { outline: 3px solid var(--coral); outline-offset: 3px; }
.rc-label { font-size: 7px; letter-spacing: 2px; color: #8fa3c4; }
.rc-main { display: flex; align-items: center; gap: var(--s2); }
.rc-flag { font-size: 22px; line-height: 1; }
.rc-name { font-size: 15px; letter-spacing: 1px; color: var(--cream); }
.rc-code { font-family: var(--font-lcd); font-size: 15px; letter-spacing: 3px; color: #8fa3c4; }
/* the endpoint you are currently choosing */
.rc-chip.is-active {
  border-color: var(--yellow);
  background: #22375c;
  box-shadow: 0 0 0 3px rgba(247,201,72,.22);
}
.rc-chip.is-active .rc-label { color: var(--yellow); }
.rc-chip.is-active .rc-name { color: var(--yellow); }
.rc-arrow { color: var(--teal); font-size: 20px; }

.planner-body {
  display: grid;
  grid-template-columns: minmax(0, 57fr) minmax(0, 43fr);
  gap: var(--s3);
  padding: var(--s3);
  /* takes the height left over by the header and the footer, and may shrink */
  flex: 1 1 auto;
  min-height: 0;
}
.route-map {
  min-height: 0;                  /* the canvas inside flexes; do not floor it */
  background: #1d3557;
  border: var(--bd-2) solid var(--ink);
  border-radius: var(--radius-sm);
  padding: var(--s2);
  display: flex; flex-direction: column;
}
.rm-head {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 8px; letter-spacing: 1px; color: #8fa3c4; margin-bottom: var(--s2);
}
#rm-canvas {
  display: block; width: 100%; flex: 1; min-height: 190px;
  background: #2a5d8f; border: 2px solid var(--ink); border-radius: 3px;
}
.rm-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s2); margin-top: var(--s2); }
.rm-stat {
  background: var(--navy-3); border: 2px solid var(--ink); border-radius: 3px;
  padding: var(--s2); text-align: center;
}
.rm-stat span { display: block; font-size: 7px; letter-spacing: 1px; color: #7d8aa3; }
.rm-stat b { font-family: var(--font-lcd); font-size: 19px; color: var(--cream); }

.dest-browser { display: flex; flex-direction: column; gap: var(--s2); min-width: 0; min-height: 0; }
.search-bar {
  width: 100%;
  font-family: var(--font-pixel); font-size: 11px;
  padding: var(--s3);
  background: var(--cream);
  border: var(--bd-2) solid var(--ink);
  border-radius: var(--radius-sm);
}
.filters { display: flex; gap: var(--s1); flex-wrap: wrap; }
.filter-btn {
  font-family: var(--font-pixel); font-size: 8px;
  color: #a8b8d4; background: var(--navy-3);
  border: 2px solid var(--panel-line); border-radius: var(--radius-sm);
  padding: 6px 9px; cursor: pointer;
}
.filter-btn:hover { color: var(--cream); }
.filter-btn.is-active { background: var(--yellow); color: var(--navy); border-color: var(--navy); }
.filter-btn:focus-visible, .search-bar:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }
.country-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s2);
  /* fills whatever the column has left rather than a fixed 296px, so the
     planner as a whole can fit the window; it scrolls internally as before */
  flex: 1 1 auto; min-height: 132px; overflow-y: auto; padding-right: 4px;
  scrollbar-color: var(--panel-line) var(--navy-3); scrollbar-width: thin;
}
.country-grid::-webkit-scrollbar { width: 8px; }
.country-grid::-webkit-scrollbar-track { background: var(--navy-3); }
.country-grid::-webkit-scrollbar-thumb { background: var(--panel-line); border-radius: 4px; }
.grid-empty {
  grid-column: 1 / -1; font-family: var(--font-lcd); font-size: 20px;
  color: #8fa3c4; text-align: center; padding: var(--s5) 0;
}
/* A destination tile is a FLAG and a NAME. Twelve tiles each carrying five
   facts turned the grid into a wall of small print, so the supporting detail
   (continent, airport code, difficulty, stops, personal best) is held back
   until the tile is hovered or focused. */
.country-tile {
  position: relative;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  min-height: 92px;
  font-family: var(--font-pixel);
  text-align: center;
  background: var(--cream);
  border: var(--bd-2) solid var(--navy);
  border-radius: 6px;
  padding: var(--s3) var(--s2);
  cursor: pointer;
  box-shadow: var(--px-sh-1);
  transition: transform .08s steps(2);
  overflow: hidden;
}
.country-tile:hover { transform: translateY(-2px); }
.country-tile:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }
.tile-flag {
  line-height: 1;
}
.tile-name {
  font-size: 9px; letter-spacing: 1px; color: var(--navy);
  word-break: break-word;
}

/* the detail drawer: slides up from the tile's bottom edge on hover/focus */
.tile-hover {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; flex-direction: column; gap: 1px;
  padding: 4px 5px 5px;
  background: var(--navy);
  border-top: 2px solid var(--ink);
  transform: translateY(101%);
  transition: transform .14s ease-out;
  pointer-events: none;
}
.country-tile:hover .tile-hover,
.country-tile:focus-visible .tile-hover { transform: translateY(0); }
.th-cont { font-size: 8px; letter-spacing: 1px; color: var(--yellow); }
.th-meta { font-family: var(--font-lcd); font-size: 13px; color: #b9cbe6; letter-spacing: .5px; }

.country-tile.selected {
  border-color: var(--coral); border-width: var(--bd-3);
  background: #fffbe8;
  box-shadow: var(--px-sh-1), inset 0 0 0 2px #fff;
  padding-top: 26px;              /* clears the ACTIVE ribbon */
}
.tile-active-tag { display: none; }
.country-tile.selected .tile-active-tag {
  display: block;
  position: absolute;
  top: 0; left: 0; right: 0;
  font-size: 6px; letter-spacing: 1px;
  background: var(--coral); color: #fff;
  border-bottom: 2px solid var(--navy);
  padding: 3px 4px;
  text-align: center;
}
.country-tile.is-origin { border-color: var(--teal); }
.tile-badge {
  position: absolute; top: 3px; right: 4px;
  font-size: 6px; letter-spacing: 1px;
  padding: 2px 5px; border-radius: 3px;
  border: 2px solid var(--navy);
  z-index: 2;
}
.badge-from { background: var(--teal); color: #fff; }

.planner-foot {
  display: grid;
  grid-template-columns: auto minmax(420px, 1fr) auto;
  gap: var(--s3);
  align-items: center;
  background: var(--ink);
  padding: var(--s3) var(--s4);
  border-top: var(--bd-2) solid #000;
}
/* The planner shows the SAME BoardingPass component, compacted to fit
   the footer strip (no slot animation, full border, denser type). */
.bp-compact {
  align-self: center;
  justify-self: center;
  width: 100%;
  max-width: 468px;              /* match the ticket screen's proportions */
  grid-template-columns: minmax(0, 1fr) 104px;
  border: var(--bd-2) solid var(--navy);
  border-bottom: var(--bd-2) solid var(--navy);
  border-radius: var(--radius-sm);
  animation: none;
  box-shadow: var(--px-sh-1);
}
.bp-compact .bp-main { padding: 0 var(--s2) var(--s2); }
.bp-compact .bp-band {
  margin: 0 calc(-1 * var(--s2)) var(--s2);
  padding: 5px var(--s2);
  font-size: 8px;
  border-radius: 3px 0 0 0;
}
.bp-compact .bp-doclabel { font-size: 6px; padding: 2px 4px; }
.bp-compact .bp-route { margin: 4px 0 6px; gap: 8px; }
.bp-compact .bp-code { font-size: 16px; }
.bp-compact .bp-city { font-size: 13px; }
.bp-compact .bp-path { font-size: 12px; }
.bp-compact .bp-fields { grid-template-columns: repeat(3, 1fr); gap: 5px var(--s3); margin: 5px 0; }
.bp-compact .bp-field .lbl { font-size: 6px; }
.bp-compact .bp-field .val { font-size: 15px; }
.bp-compact .bp-sponsor { font-size: 12px; padding-top: 2px; }
.bp-compact .bp-stub { padding: 6px; gap: 3px; }
.bp-compact .stub-code { font-size: 10px; }
.bp-compact .bp-art { width: 46px; height: 30px; font-size: 20px; }
.bp-compact .bp-barcode { height: 20px; }
.bp-compact .stub-serial { font-size: 11px; }
.bp-compact .bp-notch { display: none; }

.btn-tertiary {
  background: rgba(16,26,46,.82); color: var(--cream);
  border: 2px solid var(--panel-line);
  box-shadow: none;
  font-size: 10px;
}
.btn-tertiary:hover { color: #fff; background: var(--ink); border-color: var(--cream); }

/* ============ SCREEN 3: TICKET ============ */
#screen-ticket { background: linear-gradient(#3c5a80, var(--navy)); justify-content: center; }
.ticket-machine-big {
  width: min(560px, 92vw);
  background: linear-gradient(180deg, #f2ead2 0 8px, var(--cream-2) 8px calc(100% - 10px), #d8cca6 0);
  border: 4px solid #101a2e;
  border-radius: var(--radius-lg);
  padding: var(--s5);
  margin: var(--s5) 0;
  text-align: center;
  box-shadow:
    inset 4px 4px 0 rgba(255,255,255,.5),
    inset -4px -4px 0 rgba(30,48,80,.18),
    var(--shadow-2);
}
.machine-display-lcd {
  position: relative;
  overflow: hidden;
  background: radial-gradient(120% 100% at 50% 30%, #123527 0%, #10241c 70%);
  border: 3px solid #0a1a12;
  border-radius: var(--radius-sm);
  padding: var(--s4);
  margin-bottom: var(--s4);
  box-shadow: inset 0 5px 0 rgba(0,0,0,.5), 0 0 14px rgba(86,211,100,.25);
}
.machine-display-lcd::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(255,255,255,.05) 0 2px, transparent 2px 4px);
}
.lcd-text { font-family: var(--font-lcd); font-size: 34px; color: #56d364; text-shadow: 0 0 8px rgba(86,211,100,.55); }
.lcd-plane { display: inline-block; animation: bob 1.2s infinite alternate; }
@keyframes bob { to { transform: translateY(-5px); } }

.ticket-slot-area {
  position: relative;
  background: linear-gradient(#2c3346, #3a4256);
  border: 4px solid #101a2e;
  border-radius: var(--radius-sm);
  padding: 0 30px;
  overflow: hidden;
  box-shadow: inset 0 12px 14px rgba(0,0,0,.55);
}
/* printer slot lip the pass emerges from */
.slot-lip {
  height: 10px;
  margin: 0 -30px 16px;
  background: #0d1626;
  border-bottom: 2px solid #4a5670;
}
/* ---- boarding pass: main body + tear-off stub ---- */
.boarding-pass {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 118px;
  background: #fdf8ec;
  border: 3px solid var(--navy);
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  text-align: left;
  animation: printout 1.4s ease-out;
}
/* paper drops in from above the slot and settles with a light sway */
@keyframes printout {
  0%   { transform: translateY(-150%) rotate(-3deg); opacity: 0; }
  15%  { opacity: 1; }
  60%  { transform: translateY(6%) rotate(1.5deg); }
  80%  { transform: translateY(-2%) rotate(-1deg); }
  100% { transform: translateY(0) rotate(0deg); opacity: 1; }
}
.bp-main { padding: 0 14px 10px; min-width: 0; }
.bp-band {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: var(--teal);
  color: #fff;
  margin: 0 -14px 12px;
  padding: 10px 14px;
  border-bottom: 3px solid var(--navy);
  border-radius: 5px 0 0 0;
  font-size: 11px;
  text-shadow: 1px 1px 0 rgba(0,0,0,.35);
}
.bp-doclabel {
  font-size: 7px;
  letter-spacing: 2px;
  background: var(--navy);
  color: var(--yellow);
  padding: 4px 6px;
  border-radius: 2px;
  text-shadow: none;
}
/* hero route: HOME ✈ JPN */
.bp-route { display: flex; align-items: center; gap: 10px; margin: var(--s2) 0 var(--s3); }
.bp-endpoint { display: flex; flex-direction: column; }
.bp-code { font-family: var(--font-pixel); font-size: 24px; line-height: 1.1; color: var(--navy); }
.bp-city { font-family: var(--font-lcd); font-size: 16px; color: #8a7f66; }
.bp-path {
  flex: 1;
  align-self: center;
  text-align: center;
  color: var(--teal);
  font-size: 16px;
  background: repeating-linear-gradient(90deg, rgba(30,48,80,.5) 0 6px, transparent 6px 12px)
              center / 100% 2px no-repeat;
}
/* label-over-value columns (SEAT/GATE/GROUP convention) */
.bp-fields {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s2);
  margin: var(--s2) 0;
}
.bp-field .lbl {
  font-family: var(--font-pixel);
  font-size: 7px;
  letter-spacing: 1px;
  color: #8a7f66;
  display: block;
  margin-bottom: 2px;
}
.bp-field .val { font-family: var(--font-lcd); font-size: 21px; line-height: 1; color: var(--navy); }
/* tear-off stub with perforation + punched notches */
.bp-stub {
  border-left: 3px dashed rgba(30,48,80,.55);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s2);
}
.stub-code { font-family: var(--font-pixel); font-size: 12px; text-align: center; color: var(--navy); }
.stub-serial { font-family: var(--font-lcd); font-size: 13px; color: #8a7f66; }
.bp-art {
  width: 74px; height: 60px;
  display: flex; align-items: center; justify-content: center;
  font-size: 38px;
  border: 2px solid var(--navy);
  border-radius: var(--radius-sm);
}
.bp-barcode {
  width: 100%;
  height: 44px;
  background: repeating-linear-gradient(90deg,
    #1e3050 0 2px, transparent 2px 4px, #1e3050 4px 9px, transparent 9px 11px,
    #1e3050 11px 12px, transparent 12px 16px, #1e3050 16px 19px, transparent 19px 22px,
    #1e3050 22px 25px, transparent 25px 27px);
}
.bp-notch {
  position: absolute;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: #2c3346;
  border: 3px solid var(--navy);
  right: 118px;
  transform: translateX(50%);
}
.bp-notch.top { top: -11px; }
.bp-notch.bot { bottom: -8px; }
.bp-sponsor {
  font-family: var(--font-lcd);
  font-size: 15px;
  color: #8a7f66;
  text-align: center;
  padding-top: 4px;
}
#btn-take-ticket { margin-top: var(--s4); }

/* ============ SCREEN 4: TERMINAL ============ */
#screen-terminal { background: linear-gradient(#8fd0e8 0%, #bcd9c7 70%, #a4b895 100%); justify-content: center; gap: var(--s4); }
.ticket-summary { display: flex; gap: 30px; font-size: 11px; padding: var(--s3) var(--s5); }
.gates { display: flex; gap: 30px; align-items: flex-end; }
.gate {
  width: 230px;
  cursor: pointer;
  text-align: center;
  transition: transform .12s steps(2);
  font-family: var(--font-pixel);
  background: none;
  border: none;
  padding: 0;
  display: block;
}
.gate:hover:not(:disabled) { transform: translateY(-4px); }
/* illuminated lightbox sign hung from a bracket */
.gate-sign {
  position: relative;
  display: block;
  background: #101a2e;
  color: var(--yellow);
  font-size: 12px;
  padding: 10px;
  margin: 14px 34px 8px;
  border: 3px solid #000;
  border-radius: var(--radius-sm);
  text-shadow: 0 0 6px rgba(247,201,72,.8);
  box-shadow: inset 0 3px 0 rgba(255,255,255,.12), 0 8px 14px -4px rgba(247,201,72,.3);
}
.gate-sign::before {
  content: "";
  position: absolute;
  top: -14px; left: 50%;
  transform: translateX(-50%);
  width: 8px; height: 14px;
  background: #22293a;
  border: 2px solid #101a2e;
}
/* wall panel with top-left light bevel */
.gate-body {
  display: block;
  border: var(--px-border) solid #101a2e;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  padding: var(--s4) 14px var(--s3);
  color: #fff;
  text-shadow: 1px 1px 0 rgba(0,0,0,.45);
  box-shadow:
    inset 4px 4px 0 rgba(255,255,255,.18),
    inset -4px -4px 0 rgba(0,0,0,.28);
}
.gate-solo .gate-body { background: #3466a8; }
.gate-multi .gate-body { background: #2e8b57; }
.gate-private .gate-body { background: var(--purple); }
.gate-title { display: block; font-size: 15px; }
/* arched doorway: dark corridor with a warm glow — "enterable" */
.gate-doorway {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 108px;
  margin: var(--s3) 22px 0;
  border: 4px solid #101a2e;
  border-bottom: none;
  border-radius: 110px 110px 0 0;
  background:
    radial-gradient(80% 70% at 50% 45%, rgba(247,201,72,.32) 0%, rgba(16,26,46,.92) 75%),
    linear-gradient(#16233c, #0d1626);
  box-shadow: inset 0 0 24px rgba(0,0,0,.7);
}
.gate:hover:not(:disabled) .gate-doorway {
  background:
    radial-gradient(80% 70% at 50% 45%, rgba(247,201,72,.5) 0%, rgba(16,26,46,.85) 78%),
    linear-gradient(#16233c, #0d1626);
}
.gate-icon { font-size: 34px; }
.gate-desc { display: block; font-family: var(--font-lcd); font-size: 19px; line-height: 1.3; text-shadow: none; margin-top: var(--s3); }
/* departure-status lamps */
.gate-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 9px;
  margin-top: var(--s2);
  padding: 4px 8px;
  background: #101a2e;
  border-radius: 3px;
  text-shadow: none;
}
.gate-status::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
}
.gate-status.boarding { color: #56d364; }
.gate-status.boarding::before {
  background: #56d364;
  box-shadow: 0 0 6px #56d364;
  animation: ledBlink 1.2s steps(2) infinite;
}
.gate-status.closed { color: #ff8f85; }
.gate-status.closed::before { background: var(--red); }
/* locked gates: roller shutter pulled down over the doorway */
.gate:disabled { cursor: not-allowed; }
.gate:disabled .gate-doorway {
  background: repeating-linear-gradient(0deg, #4a5670 0 10px, #3a4256 10px 14px);
  box-shadow: inset 0 6px 10px rgba(0,0,0,.5);
}
.gate:disabled .gate-icon { opacity: .5; }
/* floor band + wayfinding stripe leading into the gate */
.gate-floor {
  display: block;
  position: relative;
  height: 40px;
  background: linear-gradient(#9aa48c, #8e9880);
  border: 3px solid #6f7a62;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  overflow: hidden;
}
.gate-floor::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 64px;
  transform: translateX(-50%);
  background: repeating-linear-gradient(0deg, var(--yellow) 0 10px, transparent 10px 20px);
  clip-path: polygon(32% 0, 68% 0, 100% 100%, 0 100%);
  opacity: .8;
}
.gate:disabled .gate-floor::before { opacity: .25; }
.gate:hover:not(:disabled) .gate-floor::before { animation: stripFlow .6s linear infinite; }
/* small 64px element — background-position animation is cheap here */
@keyframes stripFlow { to { background-position: 0 -20px; } }

/* ============ SCREEN 7: GAMEPLAY ============ */
#screen-game { background: #0e1c33; }
.game-viewport { position: relative; flex: 1; width: 100%; min-height: calc(42dvh / var(--ui-zoom, 1)); overflow: hidden; }
/* rest frame: screen-fixed, never pans with the map. Gives the eye something
   stationary to hold on to while the world moves, which is what actually
   settles the stomach -- unlike slowing the camera down, it costs no motion. */
.game-viewport::after {
  content: "";
  position: absolute; inset: 0;
  border: 3px solid var(--ink);
  pointer-events: none;
  z-index: 6;
}
#map-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

.turbulence-msg {
  position: absolute;
  top: 18%; left: 50%;
  transform: translate(-50%,-50%);
  font-size: 22px;
  color: var(--yellow);
  text-shadow: 2px 2px 0 var(--red), 4px 4px 0 rgba(0,0,0,.5);
  z-index: 12;
  pointer-events: none;
}
.turbulence-msg.show { animation: turbIn .35s ease-out; }
@keyframes turbIn {
  0% { transform: translate(-50%,-50%) scale(.6); }
  30% { transform: translate(-50%,-50%) scale(1.15) rotate(-2deg); }
  60% { transform: translate(-50%,-50%) rotate(2deg); }
  100% { transform: translate(-50%,-50%); }
}
/* ---- CPU difficulty ----
   Three fixed speeds rather than a vague label, because the number is the
   thing a typist can actually judge themselves against. Rides with the
   multiplayer switch and hides when it is off, where it would mean nothing. */
.cpu-level {
  display: flex; align-items: stretch; gap: 4px;
  width: min(420px, 92vw);
  padding: 5px;
  background: var(--navy-3);
  border: var(--bd-3) solid var(--panel-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--px-sh-1);
}
.cpu-level.hidden { display: none; }
.cl-label {
  display: flex; align-items: center;
  font-family: var(--font-pixel); font-size: 9px; letter-spacing: 2px;
  color: #8fa3c4; padding: 0 var(--s2);
}
.cl-opt {
  flex: 1 1 0;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  font-family: var(--font-pixel); font-size: 8px; letter-spacing: 1px;
  color: #8fa3c4;
  background: #101a2e;
  border: var(--bd-2) solid var(--ink);
  border-radius: 3px;
  padding: 5px 2px;
  cursor: pointer;
  transition: transform .06s steps(2);
}
.cl-opt b { font-family: var(--font-lcd); font-size: 16px; letter-spacing: 0; }
.cl-opt:hover { color: var(--cream); }
.cl-opt.is-on {
  background: var(--yellow); color: var(--ink);
  box-shadow: inset 0 0 0 2px rgba(16,26,46,.35);
}
.cl-opt:active { transform: translateY(1px); }
.cl-opt:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }

/* ===================== COMBO =====================
   Two objects, deliberately. A CALM readout in the HUD that never animates
   while a word is being typed, and a LOUD one-shot ping that only ever fires
   in the gap between words. Anything that moves next to text you are actively
   reading costs you accuracy, so all the noise is pushed into the gap.

   Escalation is carried by the OUTLINE, because both project faces ship a
   single weight -- there is no bolder cut to step up to. --o is the ring
   radius; --od MUST be --o / sqrt(2), or the four diagonals land 41% further
   out than the cardinals and the ring visibly bulges on round glyphs (O, G,
   C, S). CSS has no portable sqrt(), so both numbers are authored per tier.
   Hard offsets only, zero blur: a glow would soft-edge the counter and make it
   compete with the word for "which text here is the sharp one". */
.combo-ink {
  text-shadow:
    calc(-1*var(--o)) 0 0 var(--oc),  var(--o) 0 0 var(--oc),
    0 calc(-1*var(--o)) 0 var(--oc),  0 var(--o) 0 var(--oc),
    calc(-1*var(--od)) calc(-1*var(--od)) 0 var(--oc),
    var(--od) calc(-1*var(--od)) 0 var(--oc),
    calc(-1*var(--od)) var(--od) 0 var(--oc),
    var(--od) var(--od) 0 var(--oc),
    0 var(--dy) 0 rgba(10,16,48,.8);
}
.ct-1 { --o: 3px; --od: 2.12px; --oc: var(--navy); --dy: 4px; color: var(--teal);   }
.ct-2 { --o: 4px; --od: 2.83px; --oc: var(--navy); --dy: 5px; color: var(--yellow); }
.ct-3 { --o: 5px; --od: 3.54px; --oc: var(--ink);  --dy: 6px; color: var(--coral);  }
.ct-4 { --o: 6px; --od: 4.24px; --oc: var(--coral); --dy: 7px; color: var(--cream); }
/* Top tier gets a SILHOUETTE change, not just another colour: cream fill,
   coral inner ring, ink outer keyline at R+3. Only the ping wears it -- the
   ping floats over the map and has to survive both the dark ocean and the
   light landmasses, whereas the HUD counter already sits in a bordered box on
   a dark panel and a second ring there just fills the box in. */
.combo-ping.ct-4 {
  text-shadow:
    calc(-1*var(--o)) 0 0 var(--oc),  var(--o) 0 0 var(--oc),
    0 calc(-1*var(--o)) 0 var(--oc),  0 var(--o) 0 var(--oc),
    calc(-1*var(--od)) calc(-1*var(--od)) 0 var(--oc),
    var(--od) calc(-1*var(--od)) 0 var(--oc),
    calc(-1*var(--od)) var(--od) 0 var(--oc),
    var(--od) var(--od) 0 var(--oc),
    -9px 0 0 var(--ink),  9px 0 0 var(--ink),
    0 -9px 0 var(--ink),  0 9px 0 var(--ink),
    -6.36px -6.36px 0 var(--ink),  6.36px -6.36px 0 var(--ink),
    -6.36px 6.36px 0 var(--ink),   6.36px 6.36px 0 var(--ink),
    0 var(--dy) 0 rgba(10,16,48,.8);
}

/* ---- the persistent readout ----
   visibility, not display: the stat box keeps its width, so the counter
   appearing at combo 3 cannot resize .hud-perf and shove the typing panel
   sideways mid-word. Below tier 1 it shows nothing at all -- a permanent "x0"
   spends the escalation before the run has started. */
#stat-combo {
  visibility: hidden;
  transform-origin: center;
  transition: color .18s linear, transform .18s steps(3, jump-end);
  /* one ring width at every tier. The box is 88px wide and the digits are
     30px tall; a 6px ring at the top tier closes up the counters of the 0 and
     the loops of the 8 and the number stops being a number. Colour and the
     one scale step carry the tier here -- the outline escalation is the
     ping's job, and the ping has a whole map to be loud on. */
  --o: 3px; --od: 2.12px; --dy: 4px;
}
#stat-combo.on   { visibility: visible; }
#stat-combo.ct-1 { transform: scale(1.00); }
#stat-combo.ct-2 { transform: scale(1.07); }
#stat-combo.ct-3 { transform: scale(1.16); }
#stat-combo.ct-4 { transform: scale(1.26); }
#stat-combo.combo-break { color: #8fa3c4 !important; }

/* ---- the one-shot ping, just above the typing panel ----
   Hard against the LEFT edge. The word itself is centred, so a centred ping
   would land in the exact column being read; the right edge is where the
   "TYPE 2 MORE!" sticker already lives, and two rotated pixel labels on top of
   each other is unreadable. Left is the only free corner, and from there the
   ping is fully visible peripherally without ever covering a letter. */
.combo-ping {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 10px;
  font-family: var(--font-pixel);
  font-size: 14px;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  z-index: 14;
  opacity: 0;
  transform-origin: 0 100%;
}
/* 1.5s total: stamp in over 3 frames, hold, then rise and fade. The stepped
   entry is what keeps a DOM animation reading as sprite animation against 3px
   hard outlines; the EXIT is linear, because stepped opacity is flicker. */
.combo-ping.show {
  animation:
    cpIn  .12s steps(3, jump-end) both,
    cpOut .30s ease-in 1.2s both;
}
.combo-ping.p1 { --s: 1.00; } .combo-ping.p2 { --s: 1.08; }
.combo-ping.p3 { --s: 1.18; } .combo-ping.p4 { --s: 1.30; }
.combo-ping.tierup { --s: 1.40; }
@keyframes cpIn {
  from { opacity: 0; transform: translateY(6px) scale(calc(var(--s) * .82)); }
  to   { opacity: 1; transform: translateY(0)   scale(var(--s)); }
}
@keyframes cpOut {
  from { opacity: 1; transform: translateY(0)    scale(var(--s)); }
  to   { opacity: 0; transform: translateY(-8px) scale(var(--s)); }
}
.combo-ping.fading { animation: none; opacity: 0; transition: opacity .22s linear; }

/* big center leg flash: stamp-in huge → settle, hold, dissipate (~700ms).
   Upper third so the map focal point stays clear; 8-dir text-shadow outline
   (crisper on pixel fonts than -webkit-text-stroke). */
.leg-flash {
  position: absolute;
  left: 50%; top: 30%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 13;
  font-size: clamp(34px, 6vw, 52px);
  line-height: 1;
  white-space: nowrap;
  --o: 4px; --oc: var(--navy);
  text-shadow:
    calc(-1*var(--o)) 0 0 var(--oc), var(--o) 0 0 var(--oc),
    0 calc(-1*var(--o)) 0 var(--oc), 0 var(--o) 0 var(--oc),
    calc(-1*var(--o)) calc(-1*var(--o)) 0 var(--oc),
    var(--o) calc(-1*var(--o)) 0 var(--oc),
    calc(-1*var(--o)) var(--o) 0 var(--oc),
    var(--o) var(--o) 0 var(--oc),
    0 7px 0 rgba(10,16,48,.8);
  animation:
    flashIn .15s cubic-bezier(.22, 1.4, .36, 1) both,
    flashOut .25s ease-in .45s both;
}
.leg-flash.flash-2 { color: #ffd93b; }
.leg-flash.flash-1 { color: #ff5a4e; }
@keyframes flashIn {
  0% { opacity: 0; transform: translate(-50%,-50%) scale(2.8); }
  60% { opacity: 1; transform: translate(-50%,-50%) scale(.92); }
  100% { opacity: 1; transform: translate(-50%,-50%) scale(1); }
}
@keyframes flashOut {
  0% { opacity: 1; letter-spacing: normal; transform: translate(-50%,-50%) scale(1); }
  100% { opacity: 0; letter-spacing: .12em; transform: translate(-50%,-56%) scale(1.12); }
}

.hull-vignette {
  position: absolute; inset: 0;
  pointer-events: none;
  box-shadow: inset 0 0 90px 30px rgba(224,68,68,.45);
  animation: vignettePulse 1.1s ease-in-out infinite;
  z-index: 5;
}
@keyframes vignettePulse { 50% { opacity: .45; } }

.hud-top {
  position: absolute;
  top: var(--s3); left: var(--s3); right: var(--s3);
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  pointer-events: none;
  z-index: 7;
}
.hud-left { display: flex; gap: var(--s4); align-items: center; }
.hud-mode {
  background: var(--navy);
  color: #fff;
  border: var(--px-border) solid #101a2e;
  border-radius: var(--radius-sm);
  font-size: 11px;
  padding: 10px 16px;
  box-shadow: var(--shadow-1);
}
.hud-exit {
  pointer-events: auto;
  font-family: var(--font-pixel);
  font-size: 10px;
  background: rgba(20,32,46,.85);
  color: #ffb0a8;
  border: 2px solid var(--red);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  cursor: pointer;
}
.hud-exit:hover { background: var(--red); color: #fff; }
.hud-exit.armed {
  background: var(--red);
  color: #fff;
  animation: idlePulse .8s ease-in-out infinite;
}
.route-panel {
  width: 210px;
  padding: 10px;
  background: rgba(20,32,46,.92);
  border: var(--px-border) solid #101a2e;
  border-radius: var(--radius-sm);
  color: var(--cream);
  box-shadow: var(--shadow-1);
  max-height: calc(46vh / var(--ui-zoom, 1));
  overflow: hidden;
}
.route-title { font-size: 10px; line-height: 1.3; color: var(--yellow); margin-bottom: var(--s2); letter-spacing: 1px; }
#route-list { list-style: none; font-family: var(--font-lcd); font-size: 19px; line-height: 1.35; }
#route-list .done { color: #56d364; }
#route-list .current { color: var(--yellow); }
#route-list .todo { color: #8896ad; }

/* ---- rotated urgency sticker over the target word ----
   escalation = color ramp yellow→coral→red + marching-ants speed + glow;
   FINAL type is the flashiest (racing-game FINAL LAP convention) */
/* structure: outer = rotated striped "ants" plate (frame), inner .stk-in =
   solid body with the text. Real nesting avoids the z-index:-1 pseudo trap
   (negative-z children paint ABOVE their stacking-context root's background) */
.type-sticker {
  position: absolute;
  /* Anchored ABOVE the panel, not into it. Pinned by its top edge, the box
     grew downward when the count badge was added beside it and the word grew,
     and on a short window it ended up sitting on top of the country name --
     covering the one thing on screen that has to stay readable. Hanging it
     from the bottom means it can only ever grow upward, into empty map. The
     small overlap of the panel's top border is deliberate: it is what makes it
     read as stuck on rather than floating. */
  bottom: 100%; right: 6%;
  z-index: 3;
  padding: 4px;                       /* visible marching-ants frame width */
  border-radius: var(--radius-sm);
  background: repeating-linear-gradient(45deg, var(--ant-a, transparent) 0 8px, var(--ant-b, transparent) 8px 16px);
  box-shadow: 3px 3px 0 rgba(30,48,80,.35);
  white-space: nowrap;
  transform: rotate(var(--rot, -8deg)) scale(var(--stk-scale, 1));
  animation: stampIn .28s cubic-bezier(.2,1.4,.4,1) both,
             antsMarch var(--ant-speed, 1.2s) steps(8) infinite;
}
/* The count, pulled out of the sentence. Buried mid-strip as "TYPE 2 MORE!"
   the digit was the smallest thing on the busiest element -- and it is the
   only part the player actually has to read. It hangs off the plate's leading
   edge instead: its own badge, several times the type size, so it registers
   without being read. Sitting OUTSIDE the plate is the point; inside, it would
   just be a bigger word in the same box. */
.stk-num {
  position: absolute;
  right: calc(100% - 6px);          /* overlaps the plate's left edge slightly */
  top: 50%;
  z-index: 4;
  font-family: var(--font-pixel);
  font-size: 26px;
  line-height: 1;
  padding: 4px 7px;
  color: var(--num-ink, var(--ink));
  background: var(--num-bg, var(--yellow));
  border: 3px solid var(--ink);
  border-radius: 4px;
  box-shadow: 3px 3px 0 rgba(10,16,46,.45);
  transform: translateY(-50%) rotate(var(--num-rot, 6deg)) scale(var(--num-scale, 1));
  transform-origin: 100% 50%;
  animation: numPop .3s cubic-bezier(.2,1.5,.4,1) both;
}
.stk-num:empty { display: none; }   /* single-type hop has no count to show */
@keyframes numPop {
  0%   { opacity: 0; transform: translateY(-50%) rotate(var(--num-rot,6deg)) scale(2.1); }
  60%  { opacity: 1; transform: translateY(-50%) rotate(var(--num-rot,6deg)) scale(.9); }
  100% { opacity: 1; transform: translateY(-50%) rotate(var(--num-rot,6deg)) scale(var(--num-scale,1)); }
}
.stk-in {
  display: block;
  font-size: 11px;
  line-height: 1;
  padding: 7px 10px;
  background: var(--stk-bg, var(--yellow));
  color: var(--stk-ink, var(--navy));
  border: 3px solid var(--navy);
  border-radius: 3px;
}
@keyframes stampIn {
  0% { transform: rotate(var(--rot,-8deg)) scale(var(--stamp-from, 1.6)); opacity: 0; }
  60% { transform: rotate(var(--rot,-8deg)) scale(.88); opacity: 1; }
  80% { transform: rotate(var(--rot,-8deg)) scale(1.05); }
  100% { transform: rotate(var(--rot,-8deg)) scale(var(--stk-scale, 1)); }
}
@keyframes antsMarch { to { background-position: 16px 0; } }
/* tier 0 — single-type hop: plain yellow, no loops */
.type-sticker.tier-0 { --stk-bg: var(--yellow); --stk-ink: var(--navy); --rot: -8deg; }
/* the badge runs its own escalation, louder than the plate's */
.type-sticker.tier-3 { --num-bg: var(--yellow); --num-ink: var(--ink);  --num-rot: 6deg;  --num-scale: 1; }
.type-sticker.tier-2 { --num-bg: var(--cream);  --num-ink: #c4473a;     --num-rot: -7deg; --num-scale: 1.15; }
.type-sticker.tier-1 {
  --num-bg: var(--yellow); --num-ink: #b3271b; --num-rot: 8deg; --num-scale: 1.32;
}
/* last one: the badge keeps pulsing after it lands, so the final type reads as
   urgent from the corner of the eye without another element being added */
.type-sticker.tier-1 .stk-num {
  animation: numPop .3s cubic-bezier(.2,1.5,.4,1) both,
             numBeat .6s steps(2, jump-none) .3s infinite;
}
@keyframes numBeat {
  0%, 100% { transform: translateY(-50%) rotate(var(--num-rot,8deg)) scale(var(--num-scale,1.32)); }
  50%      { transform: translateY(-50%) rotate(var(--num-rot,8deg)) scale(calc(var(--num-scale,1.32) * 1.14)); }
}

/* tier 3 — yellow + slow navy/cream ants */
.type-sticker.tier-3 {
  --stk-bg: var(--yellow); --stk-ink: var(--navy);
  --rot: -8deg; --ant-a: #1e3050; --ant-b: #f5eeda; --ant-speed: 1.2s;
}
/* tier 2 — TYPE 2 MORE!: coral, angle flips, faster ants */
.type-sticker.tier-2 {
  --stk-bg: var(--coral); --stk-ink: var(--cream);
  --rot: 6deg; --stk-scale: 1.06; --stamp-from: 1.8;
  --ant-a: #ff6f61; --ant-b: #1e3050; --ant-speed: .8s;
}
/* tier 1 — TYPE ONCE MORE!: red, fastest ants + glow pulse + retro wiggle */
.type-sticker.tier-1 {
  --stk-bg: var(--red); --stk-ink: var(--cream);
  --rot: -10deg; --stk-scale: 1.12; --stamp-from: 2.2;
  --ant-a: #f7c948; --ant-b: #f5eeda; --ant-speed: .5s;
  animation: stampIn .3s cubic-bezier(.2,1.4,.4,1) both,
             antsMarch .5s steps(8) infinite,
             stickerWiggle 1.1s steps(2, jump-none) .3s infinite;
}
.type-sticker.tier-1::after {
  content: "";
  position: absolute;
  inset: -8px;
  z-index: -1;
  border-radius: var(--radius-sm);
  box-shadow: 0 0 0 4px rgba(224,68,68,.55), 0 0 18px 6px rgba(247,201,72,.45);
  animation: glowPulse 1.1s steps(2, jump-none) infinite;  /* ~0.9Hz, WCAG-safe */
}
@keyframes glowPulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@keyframes stickerWiggle {
  0%, 100% { transform: rotate(-10deg) scale(1.12); }
  50% { transform: rotate(-6deg) scale(1.12); }
}

/* ---- travelling ticker tapes (airport-belt marquee, flight only) ----
   seamless loop: two identical copies + translateX(-50%); leftward flow =
   forward travel; ~40px/s readable crawl */

/* welcome banner — top-center rectangle in the arrival country's tone.
   Racing-game lap-banner pattern: brief, non-blocking, clears the map center */
.welcome-banner {
  position: absolute;
  top: 54px; left: 50%;
  transform: translateX(-50%);
  min-width: min(460px, calc(100vw - 32px));
  max-width: min(700px, calc(100vw - 32px));
  text-align: center;
  background: var(--cream);
  border: 4px solid var(--navy);
  border-radius: var(--radius);
  padding: var(--s4) var(--s7);
  z-index: 11;
  box-shadow: var(--shadow-2);
  animation: bannerIn .45s cubic-bezier(.34,1.3,.64,1);
  color: var(--navy);
}
@keyframes bannerIn {
  from { transform: translateX(-50%) translateY(-140%) scale(.9); opacity: 0; }
}
.welcome-banner.leaving {
  opacity: 0;
  transform: translateX(-50%) translateY(-16px);
  transition: opacity .25s ease-in, transform .25s ease-in;
}
.wb-kicker { font-size: 10px; letter-spacing: 3px; margin-bottom: var(--s2); }
.wb-title { font-size: 24px; line-height: 1.3; }
.wb-native { font-size: 18px; line-height: 1.6; margin-top: var(--s2); font-family: sans-serif; font-weight: 700; }
.wb-line { font-family: var(--font-lcd); font-size: 22px; line-height: 1.1; color: #5c5342; margin-top: var(--s2); }


.howto-overlay {
  position: absolute; inset: 0;
  background: rgba(14,28,51,.72);
  display: flex; align-items: center; justify-content: center;
  z-index: 20;
}
.howto-card {
  background: var(--cream);
  border: 4px solid var(--navy);
  border-radius: var(--radius-lg);
  padding: var(--s5) var(--s6);
  text-align: center;
  box-shadow: var(--shadow-2);
  max-width: 420px;
}
.howto-title { font-size: 15px; margin-bottom: var(--s4); }
.howto-card p { font-family: var(--font-lcd); font-size: 24px; line-height: 1.3; margin: var(--s2) 0; }
.howto-heart { color: var(--coral); }
.howto-card .btn { margin-top: var(--s4); }

.refocus-hint {
  position: absolute;
  bottom: 14px; left: 50%;
  transform: translateX(-50%);
  background: var(--yellow);
  color: var(--navy);
  border: var(--px-border) solid var(--navy);
  border-radius: var(--radius-sm);
  font-size: 11px;
  padding: 10px 16px;
  z-index: 9;
  animation: hintPulse 1.6s ease-in-out infinite;
  pointer-events: none;
}
/* keyframe transforms replace the base transform — keep the -50% centering */
@keyframes hintPulse { 50% { transform: translateX(-50%) scale(1.04); } }

.map-brand {
  position: absolute;
  left: var(--s3); bottom: var(--s3);
  z-index: 4;
  background: rgba(20,32,46,.85);
  border: 2px solid #101a2e;
  border-radius: var(--radius-sm);
  color: #7d8aa3;
  font-size: 8px;
  letter-spacing: 1px;
  padding: var(--s2) var(--s3);
  pointer-events: none;
}

/* 3-zone HUD bar: perf stats LEFT · typing focal point CENTER · queue + status RIGHT.
   DOM order matches visual order (WCAG 1.3.2). */
.game-bottom-bar {
  position: relative;
  width: 100%;
  background: var(--navy);
  border-top: 4px solid #101a2e;
  display: grid;
  grid-template-columns: 1fr minmax(360px, 560px) 1fr;
  align-items: stretch;
  gap: var(--s4);
  padding: calc(var(--s3) + 5px) var(--s4) var(--s3);
  z-index: 8;
}
.bar-progress {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 5px;
  background: #0d1626;
}
.bar-progress .progress-fill { height: 100%; width: 0%; background: var(--yellow); transition: width .4s; }
.hud-perf {
  display: flex;
  gap: var(--s2);
  align-items: stretch;
  justify-content: flex-end;   /* COMBO (most-glanced) sits nearest the focal center */
  min-width: 0;
}
.hud-right {
  display: flex;
  gap: var(--s2);
  align-items: stretch;
  min-width: 0;
}
/* hull + progress never give way -- losing sight of the hull is losing sight
   of whether the run is about to end */
.hud-status { display: flex; gap: var(--s2); align-items: stretch; margin-left: auto; flex: 0 0 auto; }
.stat-box {
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  color: var(--cream);
  min-width: 88px;
  background: #16233c;
  border: 3px solid #0d1626;
  border-radius: var(--radius-sm);
  padding: var(--s2) var(--s3);
}
.stat-label { font-size: 9px; line-height: 1.3; color: #a8b8d4; margin-bottom: var(--s1); letter-spacing: 1px; }
/* Glanced between words, never read during one -- so it sits below the word
   in the hierarchy rather than above it, which is how it used to render. */
.stat-value { font-family: var(--font-lcd); font-size: 19px; line-height: 1.05; }
.type-center {
  position: relative;   /* anchor for the rotated urgency sticker */
  background: #16233c;
  border: 3px solid #0d1626;
  border-radius: var(--radius-sm);
  padding: var(--s2) 26px;
  text-align: center;
}
/* Stays in the flow. Pulling it out lifted the word board into the urgency
   sticker that hangs off the panel's top edge, and the sticker then covered
   the word on short windows -- and it bought only a fifth of a degree of the
   gaze distance, which the camera framing handles far better anyway. */
.current-word-label { font-size: 9px; color: #a8b8d4; letter-spacing: 2px; }
/* ---- the word board ----
   A dark departure-board panel. Letters you have not reached yet are drawn as
   OUTLINES only, so the word is legible without competing with the ones you
   have typed; each correct letter lights yellow as you hit it, and a wrong key
   flashes that slot red. The player can see their own progress along the word
   at a glance, which a single flat-coloured string could never show. */
.word-board {
  position: relative;
  margin: 8px 0;
  padding: 10px 16px;
  background: #05070d;
  border: var(--bd-3) solid var(--ink);
  border-radius: var(--radius-sm);
  box-shadow: inset 0 0 0 2px #1b2233, var(--px-sh-1);
  overflow: hidden;
}
.word-board::after {                     /* scanlines: a lit display, not paint */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(180deg,
              rgba(255,255,255,.05) 0 1px, transparent 1px 3px);
}
/* The word the player has to read, under time pressure, after their eye comes
   back from the map. It was 24px while the WPM counter beside it was 27 -- the
   telemetry was physically larger than the thing the whole screen is about.
   Reading research puts peak speed at an x-height of roughly a fifth of a
   degree and keeps it flat for a long way above that, and a target you land on
   after a big saccade needs more margin than one sitting under your nose, so
   this goes to the upper end rather than the minimum. */
.current-word {
  position: relative; z-index: 1;
  /* --word-base is the size for a SHORT name; --wscale (set per word from
     game.js) shrinks it for the long ones so they still fit on one line. */
  font-size: calc(var(--word-base, 40px) * var(--wscale, 1));
  line-height: 1.2;
  margin: 0; letter-spacing: calc(4px * var(--wscale, 1));
}
/* Unlit: the glyph is hollow. -webkit-text-stroke draws the outline and a
   transparent fill removes the body, which is the only way to get a true
   outline face out of a bitmap font. */
.current-word span {
  color: transparent;
  -webkit-text-stroke: 1px #6d7fa0;
  transition: color .05s steps(1);
}
.current-word span.lit {                 /* typed correctly */
  color: var(--yellow);
  -webkit-text-stroke: 1px var(--yellow);
  text-shadow: 0 0 9px rgba(247, 201, 72, .55);
}
.current-word span.bad {                 /* wrong key just now */
  color: var(--red);
  -webkit-text-stroke: 1px var(--red);
  text-shadow: 0 0 9px rgba(224, 68, 68, .6);
  animation: badPulse .26s steps(2) 1;
}
@keyframes badPulse { 50% { opacity: .45; } }
.current-word.word-error { animation: wordShake .3s; }
@keyframes wordShake {
  25% { transform: translateX(-5px); }
  50% { transform: translateX(5px); }
  75% { transform: translateX(-3px); }
}

/* the switch sits above the print button, sized to match it */
.print-stack {
  display: flex; flex-direction: column; align-items: stretch; gap: var(--s2);
}
.print-stack .mp-toggle { width: 100%; }
.type-input {
  width: 100%;
  font-family: var(--font-pixel);
  font-size: 14px;
  padding: 10px;
  border: 3px solid var(--navy);
  border-radius: var(--radius-sm);
  text-align: center;
  text-transform: uppercase;
  transition: box-shadow .15s, border-color .15s;
}
.type-input.locked { opacity: .55; }
.type-input::placeholder { font-size: 10px; letter-spacing: 1px; color: #7d8aa3; }
/* UP NEXT: one boxed queue (same shell as stat tiles) with ghost chips fading
   into the future — reads as content, not metrics */
/* The reading queue is the one part of the bar that may be squeezed. A flex
   item defaults to min-width:auto, so with a route full of long names
   ("SOUTH AFRICA", "DOMINICAN REPUBLIC") this refused to go below its content
   and shoved the hull hearts off the right edge instead. It gives way first
   because it degrades gracefully: the chips are ordered nearest-first and fade
   out with distance, so what gets clipped is the farthest, faintest stop --
   never the country being typed, and never the hull. */
.up-next {
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  color: var(--cream);
  background: #16233c;
  border: 3px solid #0d1626;
  border-radius: var(--radius-sm);
  padding: var(--s2) var(--s3);
  min-width: 0;
}
.up-next .up-next-words {
  display: flex; flex-direction: row; gap: var(--s2);
  overflow: hidden;
  /* Centred while it fits. `safe` is what makes the overflow clip off the FAR
     end instead of both ends -- plain `center` was cutting the first chip in
     half, and the first chip is the stop you fly to next. Older engines fall
     back to the plain value above. */
  justify-content: center;
  justify-content: safe center;
}
.up-next-words span {
  background: transparent;
  color: var(--cream);
  font-size: 10px;
  padding: var(--s1) var(--s2);
  border: 2px solid #35486e;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.up-next-words span:nth-child(1) { opacity: 1; }
.up-next-words span:nth-child(2) { opacity: .65; }
.up-next-words span:nth-child(3) { opacity: .4; }
.up-next-words .final {
  border-style: dashed;
  color: var(--yellow);
  opacity: 1 !important;
}
.danger-box .stat-value { font-size: 24px; letter-spacing: 2px; }
.hearts-full { color: var(--coral); }
.hearts-empty { color: #6b7d9c; }
.danger-box.critical { animation: criticalPulse .9s ease-in-out infinite; border-color: var(--red); }
@keyframes criticalPulse { 50% { box-shadow: 0 0 14px 2px rgba(224,68,68,.8); } }

/* ============ CRASH / NEWS ============ */
#screen-crash { background: #1a1a24; justify-content: center; }
.tv-frame {
  width: min(760px, 94vw);
  background: #2c2c38;
  border: 6px solid #111;
  border-radius: 14px;
  padding: var(--s5) var(--s5) var(--s4);
  margin: var(--s5) 0;
  text-align: center;
  box-shadow: 0 12px 0 rgba(0,0,0,.5);
}
.tv-screen {
  background: #0d1626;
  border: 4px solid #000;
  border-radius: var(--radius);
  overflow: hidden;
  position: relative;
}
.tv-screen::after {
  content: "";
  position: absolute; inset: 0;
  background: repeating-linear-gradient(0deg, rgba(255,255,255,.03) 0 2px, transparent 2px 4px);
  pointer-events: none;
}
.breaking-banner {
  background: var(--red);
  color: #fff;
  font-size: 14px;
  padding: var(--s3);
  text-align: left;
  animation: blink 1s steps(2) infinite;
}
@keyframes blink { 50% { filter: brightness(1.35); } }
.news-headline {
  color: #fff;
  font-size: 15px;
  line-height: 1.8;
  padding: 20px 30px 6px;
}
.news-scene { position: relative; height: 150px; }
.crash-plane {
  position: absolute; top: 10px; left: 30%;
  font-size: 42px; color: #ddd;
  animation: falldown 2.2s ease-in infinite;
}
@keyframes falldown {
  0% { transform: translate(0,0) rotate(20deg); opacity: 1; }
  80% { transform: translate(120px,90px) rotate(65deg); opacity: 1; }
  100% { transform: translate(130px,100px) rotate(70deg); opacity: 0; }
}
.crash-smoke { position: absolute; top: 0; left: 26%; font-size: 26px; opacity: .8; }
.ocean-waves { position: absolute; bottom: 8px; width: 100%; color: var(--sky-deep); font-size: 20px; letter-spacing: 4px; }
.news-ticker {
  background: #111c2e;
  border-top: 3px solid var(--red);
  overflow: hidden;
  white-space: nowrap;
}
.ticker-inner {
  display: inline-block;
  color: var(--yellow);
  font-family: var(--font-lcd);
  font-size: 22px;
  padding: var(--s2) 0;
  animation: ticker 14s linear infinite;
}
@keyframes ticker { from { transform: translateX(100%); } to { transform: translateX(-100%); } }
.crash-sponsor { margin-top: var(--s3); background: #3a3a48; color: #b8b8c8; border-color: #111; }
.tv-buttons { display: flex; gap: var(--s4); justify-content: center; margin-top: var(--s3); flex-wrap: wrap; }

/* ============ SCREEN 8: RESULT — ARRIVAL GATE & FLIGHT REPORT ============ */
#screen-result { background: var(--navy); justify-content: flex-start; }
.arrival-bg { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.ag-sky { position: absolute; inset: 0 0 42% 0; background: linear-gradient(#9fd8ee 0%, var(--sky-glass) 60%, #cfe0e8 100%); }
.ag-mullions {
  position: absolute; inset: 0 0 42% 0;
  background: repeating-linear-gradient(90deg, rgba(30,48,80,.26) 0 6px, transparent 6px 190px);
  border-bottom: 6px solid rgba(30,48,80,.35);
}
.ag-floor {
  position: absolute; inset: 58% 0 0 0;
  background: repeating-linear-gradient(90deg, #8e9880 0 70px, #9aa48c 70px 140px);
  border-top: var(--bd-3) solid #6f7a62;
}

/* flip-board arrival hero */
.arrival-board {
  position: relative; z-index: 2;
  margin-top: var(--s3);
  background: var(--ink);
  border: var(--bd-3) solid #000;
  border-radius: var(--radius-sm);
  padding: var(--s3) var(--s6);
  box-shadow: var(--px-sh-3);
  text-align: center;
}
.ab-main { display: flex; align-items: baseline; gap: var(--s3); justify-content: center; flex-wrap: wrap; }
.ab-lbl { font-size: 10px; letter-spacing: 3px; color: #8fa3c4; }
.ab-country {
  font-size: clamp(24px, 4vw, 38px);
  color: var(--yellow);
  text-shadow: 0 0 10px rgba(247,201,72,.55);
  animation: flipIn .5s steps(4) both;
}
@keyframes flipIn { from { transform: rotateX(90deg); opacity: 0; } }
.ab-sub { display: flex; gap: var(--s4); justify-content: center; margin-top: var(--s2); font-size: 10px; flex-wrap: wrap; }
.ab-status { color: #56d364; }
.ab-route { color: var(--cream); letter-spacing: 2px; }

/* body: the report is the hero, the exit gantry hangs beside it. Two columns
   so the dashboard and the way out read as one composition; the report keeps
   the larger track, the gantry a narrower one at its side. align-items:start
   anchors the gantry at the top, the way a hung sign hangs from the ceiling
   rather than floating in the middle of the card's height. */
.result-body {
  position: relative; z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 560px) minmax(272px, 320px);
  justify-content: center;
  gap: var(--s5);
  width: min(960px, 94vw);
  margin-top: var(--s4);
  align-items: start;
}
.flight-report {
  background: var(--paper);
  border: var(--bd-3) solid var(--navy);
  border-radius: var(--radius);
  box-shadow: var(--px-sh-2);
  overflow: hidden;
}
.fr-head {
  display: flex; justify-content: space-between; align-items: center;
  background: var(--teal);
  /* ink, not white: white on this teal measures 2.9:1 and fails AA */
  color: var(--ink);
  padding: var(--s2) var(--s3);
  font-size: 10px;
  border-bottom: var(--bd-2) solid var(--navy);
}

/* ---- verdict strip ----
   The one line that says whether the run was worth flying. Always present, so
   the panel never has a hole where the personal-best ribbon used to be. */
.fr-verdict {
  display: flex; align-items: center; gap: var(--s3);
  padding: 6px var(--s3);
  background: var(--navy);
  border-bottom: var(--bd-2) solid var(--ink);
}
.fr-verdict[data-tone="pb"]   { background: #6a2740; }
.fr-verdict[data-tone="near"] { background: var(--navy-3); }
.fr-grade {
  flex: 0 0 auto; width: 30px; height: 30px;
  display: grid; place-items: center;
  font-size: 15px; color: var(--ink); background: var(--yellow);
  border: var(--bd-2) solid var(--ink);
  box-shadow: var(--px-sh-1);
  transform: rotate(-5deg);
}
.fr-verdict[data-tone="pb"] .fr-grade { animation: frStamp .4s steps(5) both; }
@keyframes frStamp {
  from { transform: rotate(-5deg) scale(3.2); opacity: 0; }
  to   { transform: rotate(-5deg) scale(1); opacity: 1; }
}
.fr-verdict-txt { font-size: 9px; letter-spacing: 1px; color: var(--cream); line-height: 1.5; }
.fr-verdict-txt b { color: var(--yellow); }
.fr-verdict[data-tone="near"] .fr-verdict-txt b { color: var(--coral); }

/* ---- co-heroes ----
   Accuracy used to render at a third of WPM's size, which inverts every piece
   of typing-coaching advice there is. Same size, one perforation between. */
.fr-hero {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3);
  padding: var(--s3) var(--s3) var(--s2);
}
.fr-h { position: relative; text-align: center; }
.fr-h + .fr-h::before {           /* one boarding pass, torn once */
  content: ""; position: absolute; left: calc(var(--s3) / -2 - 1px); top: 4px; bottom: 4px;
  width: 3px;
  background: repeating-linear-gradient(var(--paper-edge) 0 5px, transparent 5px 10px);
}
.fr-h-val {
  display: block; font-family: var(--font-lcd);
  font-size: 66px; line-height: .84; color: var(--navy);
  font-variant-numeric: tabular-nums;   /* stops the count-up jittering width */
}
.fr-h-val i { font-style: normal; font-size: 30px; }
.fr-h-lbl { display: block; font-size: 8px; letter-spacing: 2px; color: #6b6250; margin-top: 5px; }
.fr-h-sub {
  display: block; font-family: var(--font-lcd); font-size: 15px;
  line-height: 1.1; color: #6b6250; margin-top: 2px; min-height: 17px;
}

/* ---- leg tape ----
   One bar per country typed. Dark on purpose, and not for taste: teal bars on
   the cream paper measure 2.35:1 and fail the 3:1 floor for non-text; on this
   near-black they clear 6:1. */
.fr-tape { padding: 0 var(--s3) var(--s2); }
.fr-tape-track {
  display: flex; align-items: flex-end; gap: 2px;
  height: 30px; padding: 3px;
  background: #0d1626;
  border: var(--bd-2) solid var(--ink);
}
.fr-tape-track i { flex: 1 1 0; min-width: 2px; min-height: 3px; background: #56d364; }
.fr-tape-track i.bad  { background: var(--coral); }   /* this leg cost hull */
.fr-tape-track i.slow { background: var(--yellow); }  /* slowest leg */
.fr-tape-note {
  display: flex; justify-content: space-between; gap: var(--s2);
  font-size: 7px; letter-spacing: 1px; color: #6b6250; margin-top: 4px;
}
.fr-tape-note b { color: var(--navy); font-size: 8px; }

.fr-support {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s2);
  padding: 0 var(--s3) var(--s2);
}
.fr-t { text-align: center; border: 2px dashed var(--paper-edge); border-radius: var(--radius-sm); padding: 5px 4px; }
.fr-t span { display: block; font-size: 7px; letter-spacing: 1px; color: #6b6250; }
.fr-t b { font-family: var(--font-lcd); font-size: 22px; line-height: 1.05; color: var(--navy); }
.fr-foot {
  display: flex; justify-content: center; align-items: center; gap: var(--s2);
  background: var(--cream-2); border-top: var(--bd-2) dashed var(--navy);
  padding: 6px var(--s3); font-size: 8px; color: #6b6250;
}
.fr-foot b { font-size: 8px; color: var(--navy); letter-spacing: 1px; white-space: nowrap; overflow: hidden; }

/* action hierarchy */
/* ---- the sign gantry ----
   Four boards on one ceiling drop, each hanging off the one above by a short
   link. Only the column sways; the signs are rigid on it, which is how a real
   stack behaves and keeps the text steady enough to read. */
.sign-column {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center;
  width: 100%;                    /* the grid track sizes it now */
  transform-origin: 50% 0;
  animation: signSway 4.5s ease-in-out infinite;
}
.sc-drop { width: 100%; height: 22px; }
/* the short link between two boards */
.sc-link { position: relative; display: block; width: 100%; height: 12px; }
.sc-link i {
  position: absolute; top: -1px; width: 3px; height: 14px;
  background: linear-gradient(#8794ab, #5d6879);
  border-left: 1px solid var(--ink); border-right: 1px solid var(--ink);
}
.sc-link i:first-child { left: 26%; }
.sc-link i:last-child { right: 26%; }

/* on the gantry a sign is a plate only -- the column owns the rods and sway */
.sign-column .exit-sign {
  display: block; width: 100%;
  animation: none;
  align-self: stretch;
}
.sign-column .xs-plate { width: 100%; justify-content: center; }
.sign-column .xs-text { text-align: center; }
/* one lit board: three flashing signs would compete, and the point of the
   treatment is that the eye lands on the primary */
.sign-column .exit-sign:not(.xs-primary) .xs-plate::before { display: none; }
.sign-column .exit-sign:not(.xs-primary) .xs-arrow,
.sign-column .exit-sign:not(.xs-primary) .xs-text {
  color: #9fb4d4; text-shadow: none;
}
.sign-column .exit-sign:not(.xs-primary):hover .xs-arrow,
.sign-column .exit-sign:not(.xs-primary):hover .xs-text { color: var(--cream); }
.xs-primary .xs-arrow, .xs-primary .xs-text { color: var(--yellow); }
.exit-sign.is-waiting .xs-text { color: var(--yellow); }

/* ============ AIRPORT SHUTTLE (result footer) ============
   An automated people mover pulls in along the bottom edge and brakes.
   Head car door = RETURN TO AIRPORT; trailing car = sponsor ad wrap. */
.shuttle-strip {
  position: relative; z-index: 2;
  width: 100%;
  margin-top: auto;              /* the shuttle docks at the bottom edge */
  padding-top: var(--s2);
  overflow: hidden;              /* it slides in from off-screen right */
  /* Same trap as .planner: overflow:hidden drops this flex item's automatic
     minimum size to zero, so on a short window it was squashed to about two
     thirds of its height and clipped its own train -- bogies and all -- with
     the screen reporting nothing to scroll. The overflow has to stay (the
     train arrives from off-screen right), so the shrink is what goes. */
  flex-shrink: 0;
}
.shuttle-train {
  position: relative;
  display: flex; align-items: stretch; gap: 0;
  width: min(1080px, 96vw);
  min-height: 190px;
  margin: 0 auto;
  padding-bottom: 24px;          /* room for the bogies to hang */
  transform: translateX(120vw);  /* parked off-screen until .is-in */
}
.shuttle-train.is-in { animation: shuttleIn 1.1s ease-out .4s both; }
@keyframes shuttleIn {
  0%   { transform: translateX(120vw); }
  74%  { transform: translateX(-18px); }  /* brakes hard… */
  88%  { transform: translateX(6px); }    /* …rocks back on its suspension */
  100% { transform: translateX(0); }
}

/* car shells: cream body, teal beltline stripe, navy outline */
.car {
  position: relative;
  display: flex; flex-direction: column; gap: 6px;
  background: linear-gradient(#fdf8ec 0 12%, #f0e8d2 12% 78%, var(--teal, #2f8f86) 78% 90%, #d9d2bd 90% 100%);
  border: var(--bd-3) solid var(--ink);
  border-radius: 10px 10px 5px 5px;
  box-shadow: var(--px-sh-2);
  padding: 10px 12px 14px;
}
.car-ads { flex: 1 1 auto; min-width: 0; }

/* LED destination sign, matching the departure-board green */
.car-sign {
  font-family: var(--font-lcd); font-size: 19px; letter-spacing: 1px;
  color: #56d364; text-align: center;
  background: #0d1626;
  border: var(--bd-2) solid var(--ink); border-radius: 3px;
  padding: 2px 6px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
/* ---------------- head car: airport people mover ----------------
   The cars are FLUSH, not spaced. A 10px gap between them read as two objects
   parked nose to tail; with the gap closed and the head car's right border
   dropped, the ads car's left border becomes the single division line between
   coupled cars, and the cream body and teal beltline run straight through it.
   That continuity is the whole reason it reads as a train.

   The front is a windscreen, not a screen bolted to a box. The previous build
   framed a near-full-width pane in a pale collar, which at this size looked
   like a television: the glass sits FORWARD and UPPER, leaving solid bodywork
   behind and beneath it. */
.car-head {
  flex: 0 0 208px;
  border-radius: 26px 0 0 6px;   /* blunt APM prow; square where it couples */
  border-right: 0;               /* the ads car's left border is the division */
}
.car-ads { border-radius: 0 10px 5px 0; }

/* Raked windscreen, hugging the prow. Its front corner echoes the shell's
   radius so the glass looks let INTO the nose rather than stuck on it. */
.cab-glass {
  position: absolute;
  left: 13px; top: 17%;
  width: 78px; height: 40%;
  background: linear-gradient(
    #6fb3d2 0 26%,
    #d6effc 26% 40%,             /* one hard highlight band, touching neither
                                    edge -- the whole pixel-art glass trick */
    #6fb3d2 40% 100%);
  border: var(--bd-2) solid var(--ink);
  border-radius: 15px 4px 4px 4px;
  z-index: 2;
}

/* Slim lamp low on the prow. APMs use slots, not the twin round lamps of a
   diesel; no glow, because a blur beside 3px hard ink reads as a fault. */
.cab-lamp {
  position: absolute;
  left: 10px; bottom: 13%;
  width: 19px; height: 9px;
  background: var(--yellow);
  border: var(--bd-2) solid var(--ink);
  border-radius: 2px;
  z-index: 3;
}

/* sponsor panels sit in the window band of the ad car */
.car-ads .trip-cards { display: flex; gap: 8px; flex: 1; min-height: 0; }
.trip-card {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px;
  font-family: var(--font-pixel); font-size: 9px; line-height: 1.7;
  background: var(--paper);
  border: var(--bd-2) solid var(--navy);
  border-radius: 4px;
  padding: 4px 6px;
  cursor: pointer;
  transition: transform .06s;
}
.trip-card:hover { transform: translateY(-2px); filter: brightness(1.05); }
.trip-card .t-emoji { font-size: 26px; }
.trip-card .t-deal { font-family: var(--font-lcd); font-size: 17px; color: #c4473a; }

/* running gear + guideway the train rides on */
/* ---- running gear: one truck pair per car ----
   Inset from both ends with daylight between them, skirt left as an unbroken
   line. Wheels at the extreme ends with arches cut into the body is the BUS
   tell; a gap under the middle is the RAIL tell. This was one train-wide strip
   before, which put a truck under the nose overhang and none under the cab's
   rear corner -- the head car looked like it was tipping forward. */
.car-bogies {
  position: absolute;
  left: 13%; right: 13%; bottom: -17px;
  display: flex; justify-content: space-between;
  z-index: 0;
}
.car-bogies i {
  position: relative;
  width: 52px; height: 14px;
  background: #2a3040;
  border: var(--bd-2) solid var(--ink); border-top: 0;
  border-radius: 0 0 6px 6px;
}
.car-bogies i::before, .car-bogies i::after {
  content: ""; position: absolute; bottom: -7px;
  width: 19px; height: 19px; border-radius: 50%;
  /* squat rubber tyre with a light hub -- hard-stop radial keeps it a flat
     two-colour fill rather than a photographic sphere */
  background: radial-gradient(circle, #cdc6b1 0 34%, #2a3040 34% 100%);
  border: var(--bd-2) solid var(--ink);
}
.car-bogies i::before { left: 3px; }
.car-bogies i::after { right: 3px; }
.shuttle-guideway {
  height: 16px;
  background: linear-gradient(#8a94a8 0 45%, #5c667a 45% 100%);
  border-top: var(--bd-2) solid var(--ink);
  box-shadow: inset 0 3px 0 rgba(255,255,255,.18);
}

/* ---------- large desktop (1600px+): scale the layouts up ---------- */
@media (min-width: 1600px) {
  .planner { width: min(1440px, 92vw); }
  /* no fixed bumps here any more -- the panel flexes, so a bigger window
     simply gives the map and the grid more room on its own */
  /* a touch wider so the report can breathe, but the columns stay capped so
     the report never balloons away from the gantry beside it */
  .result-body { width: min(1040px, 90vw); grid-template-columns: minmax(0, 600px) minmax(300px, 340px); }
  .kiosk { width: 500px; }
  /* flanks stay equal so the composition balances */
  .departure-board, .billboard { width: 320px; }
  .arrival-board { padding: var(--s4) var(--s7); }
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .clouds::before, .clouds::after, .breaking-banner, .lcd-plane,
  .ticker-inner, .crash-plane, .refocus-hint,
  .hull-vignette, .danger-box.critical, .welcome-banner,
  .turbulence-msg.show, .hud-exit.armed,
  .type-sticker, .type-sticker::before, .type-sticker::after,
 .hw-led, .gate-status.boarding::before,
  .gate-floor::before { animation: none !important; }
  .type-sticker.tier-1::after { opacity: 1; }
  .leg-flash { animation: none; }              /* still shows, JS hides it */
  .shuttle-train.is-in { animation: none; transform: none; }
  /* the race strip must stay readable, so lanes keep their positions but
     stop animating; the countdown still shows, it just does not pop */
  .race-count, .rank-toast, .rb-row { animation: none; }
  .lane-plane { transition: none; }
  .lane.is-final .lane-dot.end { animation: none; }
  /* the sway now lives on the whole gantry, not the individual signs */
  .exit-sign, .sign-column { animation: none; }
  .mp-toggle:not(.is-on) { animation: none; box-shadow: var(--px-sh-1), 0 0 0 4px rgba(247,201,72,.4); }
  .mp-toggle.is-on .mpt-led { animation: none; }
  .mpt-switch i { transition: none; }
  .mp-toggle::before, .mp-toggle::after { animation: none; }
  .lobby-card.is-host { animation: none; }
  .btn.is-waiting { animation: none; color: var(--yellow); }
  .rbw-spin { animation: none; opacity: 1; }
  .current-word.word-in { animation: none; }
  /* HAZARD RUN: the words still fall -- that IS the game -- but every piece of
     decoration around them stops, and hazard.js pins the whole run to the easy
     end of the difficulty curve so the falling is the only motion left. */
  .hz-plate, .hz-summary, .hz-scrim, .hz-brief, .hz-count.pop { animation: none !important; }
  .hz-timer.is-final .hz-cell:not(.spent) { animation: none; background: var(--coral); }
  /* the ping still shows and is still readable -- it just does not move */
  .combo-ping.show { animation: none; opacity: 1; transform: scale(var(--s)); }
  #stat-combo { transition: color .18s linear; }
  .xs-plate::before { animation: none; opacity: .35; }
  .xs-arrow { animation: none; opacity: 1; }
  .screen.active { animation: none; }
}

/* ---------- small screens ---------- */
@media (max-width: 900px) {
  .start-main { display: flex; flex-direction: column; gap: var(--s4); }
  .departure-board { display: none; }
  .ad-slot {
    width: min(420px, 92vw);
    display: flex; align-items: center; gap: var(--s3);
    text-align: left;
  }
  .ad-slot .ad-body { display: flex; align-items: center; gap: var(--s3); }
  .ad-emoji { font-size: 28px; margin: 0; }
  .gates { flex-direction: column; gap: 14px; }
  .gate { width: 300px; }
  .country-grid { grid-template-columns: repeat(3, 1fr); max-height: calc(38vh / var(--ui-zoom, 1)); }
  .passport-spread { grid-template-columns: 1fr; }
  .planner-foot { grid-template-columns: 1fr; justify-items: center; }
  .print-stack { width: min(420px, 100%); }
  /* Stacked, the switch is sandwiched between the boarding pass and PRINT
     with no room for a floating bubble on either side. Rather than fight for
     space that does not exist, the prompt moves INSIDE the switch: same words,
     no overlap possible. */
  .mp-toggle::after { display: none; }
  .mp-toggle:not(.is-on)::before {
    position: static; transform: none;
    display: block; order: 3; margin-left: auto;
    white-space: normal; max-width: 108px;
    text-align: center; line-height: 1.4;
    animation: none;
  }
  /* the label must not eat the free space here, or the prompt ends up jammed
     against it in the middle of the row instead of sitting beside the switch
     it is telling you to press */
  .mp-toggle:not(.is-on) .mpt-label { flex: 0 0 auto; }
  .mp-toggle .mpt-switch { order: 4; }
  .passport-spread::before { display: none; }
  .gate-nav { flex-wrap: wrap; justify-content: center; }
  .car-head { flex-basis: 150px; }
  .cab-glass { left: 10px; width: 56px; border-radius: 11px 3px 3px 3px; }
  .car-bogies i { width: 42px; }
  .shuttle-train { min-height: 150px; }
  .trip-card .t-deal { display: none; }
  /* narrow: stack the HUD — typing zone first (dominant), clusters below */
  .game-bottom-bar { display: flex; flex-direction: column; gap: var(--s2); }
  .type-center { order: -1; width: 100%; }
  .hud-perf, .hud-right { justify-content: center; }
  .hud-status { margin-left: 0; }
  .welcome-banner { max-width: calc(100vw - 24px); }
  .game-title { font-size: 34px; }
}
@media (max-width: 480px) {
  .country-grid { grid-template-columns: repeat(2, 1fr); }
}

/* short viewports: compact the gameplay bottom bar so the map keeps room */
@media (max-height: 760px) {
  .game-bottom-bar { padding: calc(var(--s2) + 5px) var(--s3) var(--s2); gap: var(--s2); }
  .stat-box { min-width: 74px; padding: 4px var(--s2); }
  .stat-value { font-size: 17px; }
  .current-word { --word-base: 30px; }
  .word-board { margin: 5px 0; padding: 7px 12px; }
  .type-center { padding: var(--s1) var(--s4); }
  .game-bottom-bar { grid-template-columns: 1fr minmax(300px, 460px) 1fr; }
  .type-input { font-size: 12px; padding: 8px; }
  /* keep UP NEXT (hiding it saved no height) — just compact the chips */
  .up-next { padding: 4px var(--s2); }
  .up-next-words span { font-size: 9px; padding: 2px 6px; }
  .danger-box .stat-value { font-size: 20px; }
  .route-panel { width: 170px; }
  #route-list { font-size: 16px; }
  .welcome-banner { top: 56px; padding: var(--s2) var(--s4); }
  .wb-title { font-size: 15px; }
  .wb-native { font-size: 12px; }
}


/* ============ MULTIPLAYER ============
   Lane order is FIXED for the whole race and the local player is pinned to
   the top lane. Rank is read from where the plane sits on its track, never
   from row order -- reflowing rows mid-race costs players their own row. */

/* ---- gate lounge (screen 5) ---- */
.lobby-board {
  width: min(760px, 92vw);
  background: var(--ink);
  border: var(--bd-3) solid #000;
  border-radius: var(--radius-sm);
  box-shadow: var(--px-sh-2);
  padding: var(--s3) var(--s4);
  margin-bottom: var(--s3);
}
.lb-row { display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap; }
.lb-k { font-size: 8px; letter-spacing: 2px; color: #8fa3c4; }
.lb-v { font-family: var(--font-lcd); font-size: 26px; color: var(--yellow); letter-spacing: 2px; }
.lb-status { color: #56d364; font-size: 20px; }
.lb-sub { margin-top: 4px; font-size: 9px; color: #8fa3c4; letter-spacing: 1px; }

.lobby-cards {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--s3); width: min(920px, 94vw);
}
.lobby-card {
  position: relative;
  background: var(--navy-3);
  border: var(--bd-3) solid var(--ink);
  border-radius: var(--radius-sm);
  box-shadow: var(--px-sh-1);
  padding: var(--s3) var(--s2);
  text-align: center;
  opacity: .55;
}
.lobby-card.filled { opacity: 1; background: var(--paper); }
.lobby-card.filled .lc-seat, .lobby-card.filled .lc-name { color: var(--navy); }
.lobby-card.is-you { outline: 3px solid var(--yellow); outline-offset: 2px; }
/* The captain decides when the flight departs, so their card is marked --
   otherwise a guest cannot tell who they are waiting on. */
.lobby-card.is-host {
  border-color: var(--yellow);
  box-shadow: var(--px-sh-1), 0 0 0 3px rgba(247, 201, 72, .45);
  animation: hostGlow 1.9s ease-in-out infinite;
}
@keyframes hostGlow {
  0%, 100% { box-shadow: var(--px-sh-1), 0 0 0 3px rgba(247, 201, 72, .45); }
  50%      { box-shadow: var(--px-sh-1), 0 0 0 7px rgba(247, 201, 72, .12); }
}
.lobby-card.is-host .lc-tag { background: var(--yellow); color: var(--ink); }
.lobby-card.is-host::before {
  content: "★"; position: absolute; top: -11px; left: 50%;
  transform: translateX(-50%);
  font-size: 13px; color: var(--yellow);
  text-shadow: 0 0 6px rgba(247, 201, 72, .8);
}
.lc-air {
  font-size: 7px; letter-spacing: 1px; padding: 4px 2px; margin: -12px -8px var(--s2);
  background: var(--livery); color: var(--ink);
  border-bottom: var(--bd-2) solid var(--ink);
}
.lc-seat { font-size: 8px; letter-spacing: 1px; color: #8fa3c4; }
.lc-name { font-size: 10px; margin: 6px 0; color: #cfe0e8; word-break: break-all; }
.lc-name i { color: #7d8ba6; font-style: normal; }
.lc-tag {
  display: inline-block; font-size: 7px; letter-spacing: 1px;
  padding: 2px 6px; border: 2px solid var(--ink); border-radius: 3px;
  background: var(--tail); color: #fff;
}
.lobby-card:not(.filled) .lc-tag { background: transparent; color: #7d8ba6; border-color: #3b4a63; }
.lobby-hint { font-size: 9px; color: #8fa3c4; margin: var(--s3) 0; letter-spacing: 1px; }
.lobby-actions { display: flex; gap: var(--s3); flex-wrap: wrap; justify-content: center; }

/* ---- top race strip (in game) ---- */
.race-strip {
  position: absolute; left: 0; right: 0; top: 0; z-index: 6;
  background: rgba(16, 26, 46, .92);
  border-bottom: var(--bd-3) solid var(--ink);
  padding: 8px 10px;
}
.race-lanes { display: flex; flex-direction: column; gap: 3px; }
.lane {
  display: grid; grid-template-columns: 104px 1fr 46px;
  align-items: center; gap: 8px; height: 22px;
  padding: 0 4px; border-radius: 3px;
}
.lane.is-you { background: rgba(247, 201, 72, .16); box-shadow: inset 0 0 0 2px rgba(247,201,72,.5); }
.lane-name {
  display: flex; align-items: center; gap: 4px;
  font-family: var(--font-lcd); font-size: 15px; letter-spacing: 1px;
  color: var(--livery);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.you-chip, .cpu-chip {
  flex: 0 0 auto; font-family: var(--font-pixel); font-size: 6px; letter-spacing: 1px;
  padding: 2px 3px; border-radius: 2px;
}
.you-chip { background: var(--yellow); color: var(--ink); }
.cpu-chip { background: #3b4a63; color: #c3cfe2; }

.lane-track {
  position: relative; height: 100%;
  display: flex; align-items: center;
}
.lane-track::before {                       /* the airway */
  content: ""; position: absolute; left: 8px; right: 8px; height: 0;
  border-top: 2px dashed rgba(255, 255, 255, .45);
}
.lane.is-you .lane-track::before { border-top-color: rgba(247, 201, 72, .7); }
.lane-dot {
  position: absolute; width: 7px; height: 7px; border-radius: 50%;
  background: #8fa3c4; border: 2px solid var(--ink);
}
.lane-dot.start { left: 0; }
.lane-dot.end { right: 0; background: var(--coral); }
.lane.is-final .lane-dot.end { background: var(--yellow); animation: gateGlow .7s steps(2) infinite; }
@keyframes gateGlow { 50% { transform: scale(1.45); } }
.lane-plane {
  position: absolute; left: 0; top: 50%;
  transform: translate(-50%, -50%);
  font-size: 14px; font-style: normal; line-height: 1;
  color: var(--livery);
  text-shadow: 1px 1px 0 var(--ink), -1px 1px 0 var(--ink), 1px -1px 0 var(--ink), -1px -1px 0 var(--ink);
  transition: left .25s linear;             /* one typed word = one glide */
}
.lane-stat {
  font-family: var(--font-pixel); font-size: 9px; text-align: right;
  color: #cfe0e8;
}
.lane.is-done .lane-stat { color: var(--yellow); }
.lane.is-out { opacity: .45; }
.lane.is-out .lane-stat { color: var(--red); }

/* the strip pushes the existing HUD clear of the lanes */
body.mp-on .hud-top { top: 122px; }

/* ---- countdown + rank toast ---- */
/* The map behind this is busy and high-contrast, so the numeral sits on a
   solid plate instead of trying to survive on a text shadow. */
.race-count {
  position: absolute; left: 50%; top: 42%; z-index: 9;
  transform: translate(-50%, -50%);
  min-width: 132px; text-align: center;
  font-family: var(--font-pixel); font-size: 62px; line-height: 1;
  color: var(--yellow);
  background: rgba(16, 26, 46, .93);
  border: var(--bd-3) solid var(--yellow);
  border-radius: var(--radius);
  padding: 20px 26px 24px;
  box-shadow: var(--px-sh-2);
  pointer-events: none;
  animation: countPop .4s cubic-bezier(.2, 1.5, .4, 1) both;
}
@keyframes countPop { from { transform: translate(-50%, -50%) scale(1.5); opacity: 0; } }
.rank-toast {
  position: absolute; right: 14px; top: 132px; z-index: 8;
  font-family: var(--font-pixel); font-size: 12px;
  background: var(--yellow); color: var(--ink);
  border: var(--bd-3) solid var(--ink); border-radius: var(--radius-sm);
  padding: 7px 12px; box-shadow: var(--px-sh-1);
  pointer-events: none;
  animation: rankIn .25s ease-out both;
}
@keyframes rankIn { from { transform: translateX(30px); opacity: 0; } }

/* ---- final standings (result screen) ---- */
.race-board {
  position: relative; z-index: 2;
  width: min(620px, 94vw);
  background: var(--ink);
  border: var(--bd-3) solid #000;
  border-radius: var(--radius-sm);
  box-shadow: var(--px-sh-2);
  padding: var(--s3);
  margin-top: var(--s3);
}
.rb-head {
  font-size: 9px; letter-spacing: 2px; color: #8fa3c4;
  text-align: center; margin-bottom: var(--s2);
}
.rb-list { list-style: none; display: flex; flex-direction: column; gap: 4px; }
.rb-row {
  display: grid; grid-template-columns: 26px 30px 1fr auto;
  align-items: center; gap: var(--s2);
  background: var(--navy-3);
  border: var(--bd-2) solid var(--panel-line);
  border-left: 6px solid var(--livery);
  border-radius: 3px;
  padding: 6px var(--s2);
  animation: rbStamp .34s cubic-bezier(.7, 0, .6, 1) both;
}
@keyframes rbStamp { from { transform: scale(1.5); opacity: 0; } }
.rb-row.is-you { background: #24365a; border-color: var(--yellow); }
.rb-rank { font-family: var(--font-lcd); font-size: 24px; color: var(--yellow); text-align: center; }
.rb-air {
  font-family: var(--font-pixel); font-size: 8px; text-align: center;
  background: var(--livery); color: var(--ink);
  border: 2px solid var(--ink); border-radius: 2px; padding: 3px 0;
}
.rb-name {
  display: flex; align-items: center; gap: 5px;
  font-size: 10px; color: #e8eef8;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rb-detail { font-family: var(--font-lcd); font-size: 17px; color: #9fb4d4; }

/* ---- narrow screens ---- */
@media (max-width: 900px) {
  .lobby-cards { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 620px) {
  /* four full lanes do not fit; keep the player's own lane and compress the
     rest to a leader-gap readout rather than shrinking everything */
  .lane { grid-template-columns: 68px 1fr 34px; font-size: 8px; }
  .lane-name { font-size: 12px; }
  .lane:not(.is-you) .lane-stat { display: none; }
  .lane:not(.is-you) { height: 16px; }
  /* below ~10px, fine detail stops reading as detail and starts reading as
     dirt on the silhouette; two 3px outlines closer than 8px fuse into a blob */
  /* under ~10px, detail stops reading as detail and starts reading as dirt on
     the silhouette, so the cab keeps glass + lamp only */
  .car-head { flex-basis: 96px; border-radius: 18px 0 0 4px; }
  .cab-glass { left: 8px; width: 44px; height: 38%; border-radius: 9px 3px 3px 3px; }
  .cab-lamp { width: 14px; height: 7px; }
  .car-bogies { left: 9%; right: 9%; }
  .car-bogies i { width: 32px; height: 12px; }
  .car-bogies i::before, .car-bogies i::after { width: 16px; height: 16px; bottom: -6px; }
  .race-count { font-size: 54px; }
  .rb-row { grid-template-columns: 22px 26px 1fr; }
  .rb-detail { grid-column: 1 / -1; text-align: right; }
}


/* ---- airport information board ----
   The prose stays permanently visible: hiding it behind an expandable
   section would forfeit "read more" deep links per Google's snippet docs.
   Only the FAQ moves into the dialog, and that dialog is in the HTML from
   the start -- revealed by a class toggle, never injected on click. */
.info-board {
  position: relative; z-index: 3;
  flex: 0 0 auto;                /* .screen is a flex column: never squash */
  width: min(780px, 92vw);
  margin: var(--s4) auto var(--s4);
  background: #05070d;
  border: var(--bd-3) solid var(--ink);
  border-radius: var(--radius-sm);
  box-shadow: var(--px-sh-2), inset 0 0 0 2px #1b2233;
  overflow: hidden;
}
.ib-head {
  display: flex; align-items: center; justify-content: center; gap: var(--s3);
  background: #10182b;
  border-bottom: var(--bd-2) solid var(--ink);
  padding: 7px var(--s3);
}
.ib-kicker {
  font-family: var(--font-pixel); font-size: 8px; letter-spacing: 3px;
  color: var(--yellow);
}
.ib-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--yellow); box-shadow: 0 0 7px rgba(247, 201, 72, .8);
}
.ib-body {
  position: relative;
  padding: var(--s4);
  color: #cfdcef;
  font-family: var(--font-lcd);
  font-size: 19px; line-height: 1.5;
}
.ib-body::after {                        /* board scanlines */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(180deg,
              rgba(255,255,255,.045) 0 1px, transparent 1px 3px);
}
.info-board h2 {
  font-family: var(--font-pixel); font-size: 12px; line-height: 1.7;
  color: var(--yellow); margin-bottom: var(--s3);
  text-shadow: 0 0 8px rgba(247, 201, 72, .45);
}
.info-board h3 {
  font-family: var(--font-pixel); font-size: 9px; letter-spacing: 1px;
  color: var(--teal); margin: var(--s3) 0 var(--s2);
}
.info-board p { margin-bottom: var(--s2); }
.info-board b { color: #fff; }
.ag-steps { margin: 0 0 var(--s2) 1.4em; }
.ag-steps li { margin-bottom: 4px; }
.ib-more {
  position: relative; z-index: 1;
  margin-top: var(--s3);
  font-family: var(--font-pixel); font-size: 9px; letter-spacing: 1px;
  color: var(--ink); background: var(--yellow);
  border: var(--bd-2) solid var(--ink); border-radius: 3px;
  padding: 8px 14px; cursor: pointer;
  box-shadow: var(--px-sh-1);
}
.ib-more:hover { filter: brightness(1.08); }

/* ---- the FAQ dialog ---- */
.info-dialog {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(5, 7, 13, .78);
  padding: var(--s4);
}
.info-dialog.hidden { display: none; }
.id-card {
  width: min(640px, 94vw); max-height: calc(82vh / var(--ui-zoom, 1)); overflow-y: auto;
  background: #05070d;
  border: var(--bd-3) solid var(--yellow);
  border-radius: var(--radius-sm);
  box-shadow: var(--px-sh-2);
  color: #cfdcef; font-family: var(--font-lcd); font-size: 19px; line-height: 1.5;
}
.id-head {
  position: sticky; top: 0;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
  background: #10182b; border-bottom: var(--bd-2) solid var(--ink);
  padding: var(--s3);
}
.id-head h3 {
  font-family: var(--font-pixel); font-size: 10px; letter-spacing: 2px;
  color: var(--yellow);
}
.id-close {
  font-family: var(--font-pixel); font-size: 11px;
  color: var(--ink); background: var(--yellow);
  border: 2px solid var(--ink); border-radius: 3px;
  width: 28px; height: 28px; cursor: pointer;
}
.ag-faq { padding: var(--s4); }
.ag-faq dt { color: var(--yellow); margin-top: var(--s2); }
.ag-faq dd { margin: 2px 0 0 0; }
@media (max-width: 620px) {
  .ib-body, .id-card { font-size: 17px; }
  .ib-body { padding: var(--s3); }
  .info-board h2 { font-size: 10px; }
}




/* ---- RETURN TO AIRPORT as suspended wayfinding ----
   It used to be a door on the shuttle, which buried the one control that
   leaves the screen. Airports hang this kind of sign from the ceiling, so
   this one hangs too -- from two drop rods, beside the flight report. */
.exit-sign {
  position: relative;
  align-self: start;
  justify-self: center;
  margin-top: 0;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  font-family: var(--font-pixel);
  transform-origin: 50% 0;
  animation: signSway 4.5s ease-in-out infinite;
}
@keyframes signSway {
  0%, 100% { transform: rotate(-1.1deg); }
  50%      { transform: rotate(1.1deg); }
}
.xs-rods { display: block; height: 26px; position: relative; }
.xs-rods i {
  position: absolute; top: 0; width: 3px; height: 26px;
  background: linear-gradient(#8794ab, #5d6879);
  border-left: 1px solid var(--ink); border-right: 1px solid var(--ink);
}
.xs-rods i:first-child { left: 22%; }
.xs-rods i:last-child { right: 22%; }
/* An illuminated board, not a painted plate: black panel, amber LED type,
   and a faint scanline so it reads as a lit display rather than a sticker. */
.xs-plate {
  position: relative;
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s4);
  background: #05070d;
  border: var(--bd-3) solid var(--ink);
  border-radius: 4px;
  box-shadow: var(--px-sh-2), inset 0 0 0 2px #1b2233;
  overflow: hidden;
}
.xs-plate::after {                       /* scanlines across the display */
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background: repeating-linear-gradient(180deg,
              rgba(255,255,255,.06) 0 1px, transparent 1px 3px);
}
/* The flash. A lit sign is brightened by a blend layer rather than by
   animating colour or box-shadow: opacity is the only property here that
   stays on the compositor, and steps() keeps the blink hard-edged instead of
   fading like a dimmer. The type itself never dims, so the sign is readable
   through the whole cycle. */
.xs-plate::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: rgba(247, 201, 72, .26);
  mix-blend-mode: screen;
  opacity: 0;
  animation: signFlash 1.5s steps(1) infinite;
}
@keyframes signFlash {          /* two quick strikes, then a rest */
  0%, 52%   { opacity: 0; }
  56%, 64%  { opacity: 1; }
  68%       { opacity: .12; }
  72%, 80%  { opacity: 1; }
  84%, 100% { opacity: 0; }
}
.xs-arrow {
  position: relative; z-index: 3;
  font-size: 24px; line-height: 1; color: var(--yellow);
  text-shadow: 0 0 8px rgba(247, 201, 72, .75);
  animation: arrowBlink 1.5s steps(1) infinite;   /* chases the flash */
}
@keyframes arrowBlink {
  0%, 50%   { opacity: .42; }
  54%, 100% { opacity: 1; }
}
.xs-text {
  position: relative; z-index: 3;
  font-size: 10px; line-height: 1.8; letter-spacing: 1px;
  color: var(--yellow); text-align: left;
  text-shadow: 0 0 7px rgba(247, 201, 72, .6);
}
.exit-sign:hover .xs-arrow, .exit-sign:hover .xs-text { color: #fff6d0; }
.exit-sign:hover .xs-plate { box-shadow: var(--px-sh-2), inset 0 0 0 2px #33405c, 0 0 14px rgba(247,201,72,.35); }
.exit-sign:active .xs-plate { transform: translateY(2px); }
.exit-sign:focus-visible { outline: 3px solid var(--coral); outline-offset: 4px; }

/* Below the two-column width the gantry drops under the report and both
   columns centre. The gantry is capped so it does not stretch to the full
   width of a phone; the report card keeps the sway metaphor intact. */
@media (max-width: 900px) {
  .result-body {
    grid-template-columns: minmax(0, 460px);
    gap: var(--s4);
    width: min(460px, 94vw);
  }
  /* The report keeps the default justify-self:stretch so it FILLS the column
     (without justify-items:center it would otherwise shrink to its content and
     end up narrower than the gantry). Only the narrower gantry is centred. */
  .sign-column { width: min(360px, 92vw); justify-self: center; }
}


/* ============ FLAGS ============
   Real flag artwork from Wikimedia Commons (every file verified public
   domain), served locally. These replace a set of CSS approximations: those
   were legible but not accurate, and accuracy matters when the flag IS the
   label. Emoji flags are not an option -- Windows ships no glyphs for them,
   so a large share of players saw the bare country code instead. */
.pxflag {
  display: inline-block;
  width: 1.5em; height: 1em;
  border: 2px solid var(--ink);
  border-radius: 2px;
  box-shadow: 2px 2px 0 rgba(16, 26, 46, .35);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  vertical-align: middle;
  flex: 0 0 auto;
  image-rendering: auto;         /* photographic source: do NOT pixelate */
}
.flag-japan { background-image: url('../flags/japan.png'); }
.flag-france { background-image: url('../flags/france.png'); }
.flag-brazil { background-image: url('../flags/brazil.png'); }
.flag-canada { background-image: url('../flags/canada.png'); }
.flag-egypt { background-image: url('../flags/egypt.png'); }
.flag-italy { background-image: url('../flags/italy.png'); }
.flag-india { background-image: url('../flags/india.png'); }
.flag-korea { background-image: url('../flags/korea.png'); }
.flag-australia { background-image: url('../flags/australia.png'); }
.flag-mexico { background-image: url('../flags/mexico.png'); }
.flag-greece { background-image: url('../flags/greece.png'); }
.flag-kenya { background-image: url('../flags/kenya.png'); }
.flag-usa { background-image: url('../flags/usa.png'); }
.flag-costarica { background-image: url('../flags/costarica.png'); }
.flag-dominicanrepublic { background-image: url('../flags/dominicanrepublic.png'); }
.flag-colombia { background-image: url('../flags/colombia.png'); }
.flag-peru { background-image: url('../flags/peru.png'); }
.flag-argentina { background-image: url('../flags/argentina.png'); }
.flag-southafrica { background-image: url('../flags/southafrica.png'); }
.flag-morocco { background-image: url('../flags/morocco.png'); }
.flag-portugal { background-image: url('../flags/portugal.png'); }
.flag-spain { background-image: url('../flags/spain.png'); }
.flag-uk { background-image: url('../flags/uk.png'); }
.flag-germany { background-image: url('../flags/germany.png'); }
.flag-turkey { background-image: url('../flags/turkey.png'); }
.flag-uae { background-image: url('../flags/uae.png'); }
.flag-china { background-image: url('../flags/china.png'); }
.flag-thailand { background-image: url('../flags/thailand.png'); }
.flag-vietnam { background-image: url('../flags/vietnam.png'); }
.flag-singapore { background-image: url('../flags/singapore.png'); }
.flag-indonesia { background-image: url('../flags/indonesia.png'); }
.flag-newzealand { background-image: url('../flags/newzealand.png'); }

.tile-flag.pxflag { font-size: 30px; }
.rc-flag.pxflag { font-size: 18px; }

/* ---- sponsor slots (js/ads.js) ----
   A slot looks the same sold or unsold; only its behaviour changes. Sold
   slots become real links, so they need the anchor reset. */
.bb-body { display: contents; color: inherit; text-decoration: none; }
.mb-body, .cs-body, .bp-sponsor-in { display: inline; color: inherit; text-decoration: none; }
a.trip-card { text-decoration: none; }
a.bb-body, a.mb-body, a.cs-body, a.bp-sponsor-in { cursor: pointer; }
a.bb-body:hover, a.mb-body:hover, a.cs-body:hover, a.bp-sponsor-in:hover { text-decoration: underline; }
.ad-img {
  display: block; max-width: 100%; max-height: 100%;
  object-fit: contain; image-rendering: auto;
}
.bb-art.ad-img { height: 46px; margin: 0 auto; }
.t-emoji.ad-img { height: 26px; margin: 0 auto; }


/* ============ MULTIPLAYER ARMING + PRIVATE FLIGHTS ============ */

/* The toggle sits ahead of FROM because it changes what FROM even means: with
   it on the route is fixed and the endpoints stop being editable. It is a
   switch, not a button, so it always shows which of the two states it is in
   rather than only what pressing it would do. */
.mp-toggle {
  position: relative;
  display: flex; align-items: center; gap: var(--s3);
  font-family: var(--font-pixel);
  background: var(--navy-3);
  border: var(--bd-3) solid var(--panel-line);
  border-radius: var(--radius-sm);
  /* same vertical padding as .rc-chip so the switch and the endpoints read as
     one row of controls rather than a control bolted beside two others */
  padding: var(--s2) var(--s4);
  cursor: pointer;
  box-shadow: var(--px-sh-1);
  transition: transform .08s steps(2);
}

/* A speech bubble, because the switch is the one control on this screen whose
   purpose is not self-evident from its label. It leaves with the OFF state --
   once multiplayer is armed the prompt has done its job. */
.mp-toggle::before {
  content: "ENABLE TO PLAY MULTIPLAYER GAMES!";
  position: absolute; left: 50%; bottom: calc(100% + 11px);
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: 7px; letter-spacing: 1px; line-height: 1;
  background: var(--yellow); color: var(--ink);
  border: var(--bd-2) solid var(--ink); border-radius: 3px;
  padding: 6px 9px;
  box-shadow: var(--px-sh-1);
  pointer-events: none;
  animation: bubbleBob 1.6s ease-in-out infinite alternate;
}
.mp-toggle::after {                       /* the bubble's tail */
  content: ""; position: absolute; left: 50%; bottom: calc(100% + 4px);
  transform: translateX(-50%);
  width: 8px; height: 8px;
  background: var(--yellow);
  border-right: var(--bd-2) solid var(--ink);
  border-bottom: var(--bd-2) solid var(--ink);
  rotate: 45deg;
  pointer-events: none;
  animation: bubbleBob 1.6s ease-in-out infinite alternate;
}
@keyframes bubbleBob { to { translate: 0 -3px; } }
.mp-toggle.is-on::before, .mp-toggle.is-on::after { display: none; }
.mp-toggle:hover { transform: translateY(-2px); }
.mp-toggle:focus-visible { outline: 3px solid var(--coral); outline-offset: 3px; }

/* OFF state pulses to draw the eye, because nothing else on this screen tells
   you multiplayer exists. ON stops pulsing -- an armed switch that keeps
   flashing reads as an unfinished action. */
.mp-toggle:not(.is-on) { animation: mptCall 1.8s ease-in-out infinite; }
@keyframes mptCall {
  0%, 100% { box-shadow: var(--px-sh-1), 0 0 0 0 rgba(247, 201, 72, .5); }
  55%      { box-shadow: var(--px-sh-1), 0 0 0 8px rgba(247, 201, 72, 0); }
}
.mp-toggle.is-on {
  background: var(--yellow);
  border-color: var(--ink);
  animation: none;
}

.mpt-led {
  width: 10px; height: 10px; border-radius: 50%;
  background: #46536e; border: 2px solid var(--ink);
  flex: 0 0 auto;
}
.mp-toggle.is-on .mpt-led {
  background: #56d364;
  animation: mptBlink 1s steps(2) infinite;   /* a live channel, not a label */
}
@keyframes mptBlink { 50% { opacity: .3; } }

/* One word, sized to fill the button so the switch is pushed to the right
   edge. The state is still announced to screen readers through the
   visually-hidden #mpt-state; sighted users read it off the switch itself. */
.mpt-label {
  flex: 1 1 auto;
  font-size: 15px; letter-spacing: 2px; text-align: left;
  color: var(--cream);
}
.mp-toggle.is-on .mpt-label { color: var(--ink); }

/* the physical switch: the knob slides, which is the state read at a glance */
.mpt-switch {
  position: relative; flex: 0 0 auto;
  width: 34px; height: 18px;
  background: #10182b;
  border: var(--bd-2) solid var(--ink);
  border-radius: 3px;
}
.mpt-switch i {
  position: absolute; top: 1px; left: 1px;
  width: 13px; height: 12px;
  background: #8fa3c4; border: 2px solid var(--ink);
  transition: transform .12s steps(3);
}
.mp-toggle.is-on .mpt-switch i { transform: translateX(15px); background: #56d364; }

/* endpoints are read-only once the tour is armed */
.rc-chip.is-locked { opacity: .62; pointer-events: none; }

/* ---- the tour read-out that replaces the destination browser ---- */
.tour-panel { display: flex; flex-direction: column; gap: var(--s2); min-height: 0; }
.tp-head { display: flex; align-items: center; gap: var(--s2); }
.tp-badge {
  font-family: var(--font-pixel); font-size: 8px; letter-spacing: 2px;
  background: var(--yellow); color: var(--ink);
  border: var(--bd-2) solid var(--ink); border-radius: 3px;
  padding: 4px 7px;
}
.tp-sub { font-size: 8px; letter-spacing: 1px; color: #8fa3c4; }

.tp-route {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  grid-template-areas: "from arrow to" "hint hint hint";
  align-items: center; gap: 4px var(--s2);
  font-family: var(--font-pixel);
  background: var(--navy-3);
  border: var(--bd-3) solid var(--yellow);
  border-radius: var(--radius-sm);
  padding: var(--s3);
  cursor: pointer;
  box-shadow: var(--px-sh-1);
}
.tp-from { grid-area: from; font-size: 12px; color: var(--cream); text-align: right; }
.tp-arrow { grid-area: arrow; font-size: 15px; color: var(--yellow); }
.tp-to { grid-area: to; font-size: 12px; color: var(--cream); text-align: left; }
.tp-hint { grid-area: hint; font-size: 7px; letter-spacing: 1px; color: #8fa3c4; text-align: center; }
.tp-route:hover { filter: brightness(1.1); }
.tp-route:focus-visible { outline: 3px solid var(--coral); outline-offset: 3px; }

.tp-stops {
  list-style: none; overflow-y: auto; min-height: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
  padding-right: 4px;
}
.tp-stops li {
  display: flex; align-items: center; gap: 6px;
  background: var(--cream);
  border: var(--bd-2) solid var(--navy);
  border-radius: 3px;
  padding: 4px 6px;
  font-family: var(--font-pixel); font-size: 8px; color: var(--navy);
}
.tp-stops li b {
  font-family: var(--font-lcd); font-size: 15px; color: var(--coral);
  min-width: 15px; text-align: right;
}
.tp-stops .pxflag { font-size: 13px; }

/* ---- private flight: create or join ---- */
.pv-choices {
  display: flex; gap: var(--s4); flex-wrap: wrap; justify-content: center;
  margin-bottom: var(--s4);
}
.pv-card {
  display: flex; flex-direction: column; align-items: center; gap: var(--s2);
  width: 250px; padding: var(--s4) var(--s3);
  font-family: var(--font-pixel);
  background: var(--navy-3);
  border: var(--bd-3) solid var(--panel-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--px-sh-2);
  cursor: pointer;
  transition: transform .08s steps(2);
}
.pv-card:hover { transform: translateY(-3px); border-color: var(--yellow); }
.pv-card:focus-visible { outline: 3px solid var(--coral); outline-offset: 3px; }
.pv-icon { font-size: 26px; color: var(--yellow); }
.pv-title { font-size: 11px; letter-spacing: 1px; color: var(--cream); }
.pv-desc { font-family: var(--font-lcd); font-size: 16px; color: #9fb4d4; text-align: center; }

.pv-join {
  display: flex; flex-direction: column; align-items: center; gap: var(--s2);
  margin-bottom: var(--s4);
}
.pv-label { font-family: var(--font-pixel); font-size: 9px; letter-spacing: 2px; color: #8fa3c4; }
.pv-entry {
  display: flex; align-items: stretch;
  border: var(--bd-3) solid var(--ink); border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: var(--px-sh-1);
}
.pv-prefix {
  display: flex; align-items: center; padding: 0 var(--s3);
  font-family: var(--font-pixel); font-size: 14px;
  background: var(--yellow); color: var(--ink);
}
.pv-input {
  width: 128px; padding: var(--s2) var(--s3);
  font-family: var(--font-lcd); font-size: 34px; letter-spacing: 6px;
  text-align: center;
  background: #05070d; color: var(--yellow);
  border: 0; outline: none;
}
.pv-error { font-family: var(--font-lcd); font-size: 17px; color: var(--coral); min-height: 20px; }

/* ---- the flight number, shared ---- */
.lb-share { display: flex; align-items: center; gap: var(--s3); margin-top: 6px; }
.lb-share-k { font-size: 8px; letter-spacing: 2px; color: #8fa3c4; }
.lb-copy {
  font-family: var(--font-pixel); font-size: 8px; letter-spacing: 1px;
  background: var(--yellow); color: var(--ink);
  border: var(--bd-2) solid var(--ink); border-radius: 3px;
  padding: 5px 9px; cursor: pointer;
}
.lb-copy:hover { filter: brightness(1.1); }
.lb-copy:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }

@media (max-width: 620px) {
  .mp-toggle { width: 100%; }
  .tp-stops { grid-template-columns: 1fr; }
  .pv-card { width: 100%; }
}

/* Waiting on the rest of the field: the control reports the count instead of
   going dead, so it is obvious the press registered. */
.btn.is-waiting {
  background: var(--navy-3); color: #9fb4d4;
  border-color: var(--panel-line);
  cursor: default;
  animation: waitPulse 1.4s ease-in-out infinite;
}
@keyframes waitPulse { 50% { color: var(--yellow); } }

/* ---- standings, while the field is still flying ---- */
.rb-waiting {
  display: flex; align-items: center; justify-content: center; gap: var(--s3);
  padding: var(--s4) var(--s3);
}
.rb-waiting.hidden { display: none; }
.rbw-spin {
  font-size: 20px; color: var(--yellow);
  animation: rbwFly 1.6s linear infinite;
}
@keyframes rbwFly {
  0%   { transform: translateX(-14px); opacity: 0; }
  20%  { opacity: 1; }
  80%  { opacity: 1; }
  100% { transform: translateX(14px); opacity: 0; }
}
.rbw-text {
  font-family: var(--font-lcd); font-size: 20px; letter-spacing: 1px;
  color: #9fb4d4;
}

.word-stack { display: flex; flex-direction: column; align-items: center; }

/* A new word arrives on the board rather than appearing: it drops in from the
   destination side and settles. Transform and opacity only, so it stays on the
   compositor and cannot cost a frame of typing latency. */
.current-word.word-in { animation: wordIn .22s cubic-bezier(.2, .9, .3, 1) both; }
@keyframes wordIn {
  from { transform: translateX(14px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* ============ HAZARD RUN ============
   One stylesheet, three hazards: data-hz swaps two custom properties and
   nothing else, so JS only ever flips the attribute. The overlay sits inside
   #app, so it inherits the stage zoom like everything else.

   It covers the bottom bar on purpose. The whole point of this mode is that the
   words are NOT the ones in the typing panel, and hiding that panel is what
   makes it unambiguous which input is live. */
.hazard-mode { position: absolute; inset: 0; z-index: 40; display: block; }
.hazard-mode.hidden { display: none !important; }
.hazard-mode[data-hz="volcano"]    { --hz-key: var(--coral);  }
.hazard-mode[data-hz="hurricane"]  { --hz-key: var(--teal);   }
.hazard-mode[data-hz="turbulence"] { --hz-key: var(--yellow); }

.hz-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* the same screen-fixed rest frame the map uses -- something stationary to hold
   on to while the field moves */
.hazard-mode::after {
  content: ""; position: absolute; inset: 0;
  border: 4px solid var(--ink); pointer-events: none;
}
.hz-chrome { position: absolute; inset: 0; pointer-events: none; }

/* the scrim dims the map for the first beat, before the overlay takes over */
.hz-scrim {
  position: absolute; inset: 0; z-index: 30;
  background: rgba(10, 16, 46, .72);
  pointer-events: none;
  animation: hzScrim .22s steps(4) both;
}
.hz-scrim.hidden { display: none; }
@keyframes hzScrim { from { opacity: 0; } }

.hz-plate {
  position: absolute; top: 14px; left: 50%;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  background: var(--hz-key); color: var(--ink);
  border: 4px solid var(--ink); border-radius: var(--radius-sm);
  padding: 8px var(--s5);
  box-shadow: var(--px-sh-2);
  animation: hzSlam .44s steps(3) both;
}
@keyframes hzSlam {
  from { transform: translateX(-50%) translateY(-160%); }
  to   { transform: translateX(-50%) translateY(0); }
}
.hz-plate.is-good { background: var(--teal); }
.hz-plate.is-bad  { background: var(--coral); }
.hz-title { font-size: 26px; letter-spacing: 3px; }
.hz-sub   { font-family: var(--font-lcd); font-size: 20px; color: var(--navy); }

/* 30 cells, one per second, extinguishing left to right. Discrete by nature,
   which reads as pixel art where a smooth bar would not. */
.hz-timer {
  position: absolute; top: 116px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: var(--s3);
}
.hz-cells { display: flex; gap: 5px; }
.hz-cell {
  width: 26px; height: 20px; display: block;
  background: var(--cream); border: 3px solid var(--ink);
}
.hz-cell.spent { background: #2b3552; }
.hz-timer.is-final .hz-cell:not(.spent) { animation: hzFlash .5s steps(2) infinite; }
@keyframes hzFlash { 50% { background: var(--coral); } }
.hz-clock { font-family: var(--font-lcd); font-size: 26px; color: var(--cream); }

/* ---- the briefing card ----
   One card, one click. The scene runs behind it, but nothing spawns and the
   clock holds until OKAY -- a mode this different from the route game should
   never start itself while the player is still reading what it is. */
.hz-brief {
  position: absolute; left: 50%; top: 44%; transform: translate(-50%, -50%);
  width: min(560px, 84%);
  background: var(--navy); border: 4px solid var(--ink);
  border-radius: var(--radius-sm); box-shadow: var(--px-sh-3);
  padding: var(--s4) var(--s5) var(--s5);
  text-align: center;
  pointer-events: auto;               /* .hz-chrome is pointer-events: none */
  animation: hzSum .3s steps(3) both;
}
.hz-brief.hidden { display: none; }
.hz-brief-title {
  font-size: 20px; letter-spacing: 2px; color: var(--hz-key);
  margin-bottom: var(--s3);
}
.hz-brief-lines {
  list-style: none; margin: 0 0 var(--s4); padding: 0;
  font-family: var(--font-lcd); font-size: 21px; line-height: 1.65;
  color: var(--cream);
}

/* the 3-2-1, stamped in the same voice as the race countdown */
.hz-count {
  position: absolute; left: 50%; top: 40%; transform: translate(-50%, -50%);
  font-size: 96px; line-height: 1; color: var(--cream);
  --o: 5px; --oc: var(--ink);
  text-shadow:
    calc(-1*var(--o)) 0 0 var(--oc), var(--o) 0 0 var(--oc),
    0 calc(-1*var(--o)) 0 var(--oc), 0 var(--o) 0 var(--oc),
    calc(-1*var(--o)) calc(-1*var(--o)) 0 var(--oc),
    var(--o) calc(-1*var(--o)) 0 var(--oc),
    calc(-1*var(--o)) var(--o) 0 var(--oc),
    var(--o) var(--o) 0 var(--oc);
  pointer-events: none;
}
.hz-count.hidden { display: none; }
.hz-count.pop { animation: hzCountPop .45s steps(3) both; }
@keyframes hzCountPop {
  from { transform: translate(-50%, -50%) scale(2.0); opacity: 0; }
  to   { transform: translate(-50%, -50%) scale(1); opacity: 1; }
}

.hz-summary {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  min-width: 420px;
  background: var(--navy); border: 4px solid var(--ink);
  border-radius: var(--radius-sm); box-shadow: var(--px-sh-3);
  padding: var(--s4) var(--s5); text-align: center;
  animation: hzSum .3s steps(3) both;
}
.hz-summary.hidden { display: none; }
@keyframes hzSum { from { transform: translate(-50%, -40%); opacity: 0; } }
.hz-sum-verdict { font-size: 20px; color: var(--hz-key); letter-spacing: 2px; margin-bottom: var(--s3); }
.hz-sum-rows { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2) var(--s4); margin: 0 0 var(--s3); }
.hz-sum-rows div { display: flex; justify-content: space-between; gap: var(--s2); }
.hz-sum-rows dt { font-size: 8px; letter-spacing: 1px; color: #8fa3c4; }
.hz-sum-rows dd { margin: 0; font-family: var(--font-lcd); font-size: 20px; color: var(--cream); }
.hz-sum-bonus b { font-size: 12px; color: var(--yellow); }
.hz-sum-bonus b.bad { color: var(--coral); }

/* ---- the hazard typing box ----
   Deliberately the same shape as the route game's panel, parked along the
   bottom edge where that panel lives, so the muscle memory carries over: the
   place you type is the place you always type. */
.hz-type {
  position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%);
  width: min(560px, 74%);
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  pointer-events: auto;
}
.hz-type-lbl {
  font-size: 9px; letter-spacing: 2px; color: var(--cream);
  text-align: center; text-shadow: 2px 2px 0 var(--ink);
}
.hz-input {
  width: 100%;
  font-family: var(--font-pixel); font-size: 20px; letter-spacing: 3px;
  text-align: center; text-transform: uppercase;
  color: var(--ink); background: var(--cream);
  border: 4px solid var(--ink); border-radius: var(--radius-sm);
  padding: 10px var(--s3);
  box-shadow: var(--px-sh-2);
  caret-color: var(--coral);
}
.hz-input:focus { outline: none; border-color: var(--hz-key); }
/* a keystroke that could not lead to any live word is rejected, and says so */
.hz-input.is-bad { animation: hzBad .16s steps(2) 2; }
@keyframes hzBad { 50% { background: var(--red); color: var(--cream); } }

/* hazard pips in the route list -- a camera-independent channel, so the warning
   survives the country being off-screen entirely */
.rl-hz {
  display: inline-block; width: 9px; height: 9px; margin-left: 5px;
  border: 2px solid var(--ink); transform: rotate(45deg); vertical-align: middle;
}
.rl-hz.hz-volcano    { background: var(--coral); }
.rl-hz.hz-hurricane  { background: var(--teal); }
.rl-hz.hz-turbulence { background: var(--yellow); }
