/* =============================================================
   Cinematic Airport — global styles
   Minimal, full-bleed canvas with a filmic overlay UI.
   ============================================================= */

:root {
  --bg: #05080d;
  --fg: #eaf2ff;
  --accent: #46c6ff;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--fg);
  font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* The WebGL canvas fills the viewport. */
#scene {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

/* ---- Cinematic letterbox bars ---- */
.letterbox {
  position: fixed;
  left: 0;
  width: 100%;
  height: 7vh;
  background: #000;
  z-index: 5;
  pointer-events: none;
}
.letterbox.top { top: 0; }
.letterbox.bottom { bottom: 0; }

/* ---- Heads-up title overlay ---- */
#hud {
  position: fixed;
  left: clamp(16px, 4vw, 60px);
  top: calc(7vh + clamp(14px, 3vh, 28px)); /* just below the top letterbox */
  z-index: 6;
  pointer-events: none;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.6);
  animation: rise 1.6s cubic-bezier(0.16, 1, 0.3, 1) 0.4s both;
}
#hud h1 {
  font-size: clamp(28px, 6vw, 64px);
  font-weight: 800;
  letter-spacing: 0.14em;
  line-height: 1;
}
#hud h1 span { color: var(--accent); }
#hud p {
  margin-top: 10px;
  font-size: clamp(12px, 1.6vw, 15px);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  opacity: 0.7;
}

@keyframes rise {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- Control legend (bottom-left) ---- */
#legend {
  position: fixed;
  left: clamp(16px, 4vw, 60px);
  bottom: clamp(66px, 11vh, 96px);
  z-index: 6;
  display: grid;
  gap: 7px;
  font-size: 13px;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.7);
  animation: rise 1.4s cubic-bezier(0.16, 1, 0.3, 1) 0.5s both;
  /* Without a cap, the long "hint" row (the loose sentence at the bottom)
     forces the WHOLE grid column to its own one-line width (~683px at this
     font size), which reaches into #readout's corner at ordinary desktop
     widths — see CLAUDE.md open item 8. This just lets that one sentence
     wrap; the short kbd rows were never near this width anyway. */
  max-width: clamp(200px, calc(100vw - 900px), 380px);
}
#legend .row { display: flex; align-items: center; gap: 6px; }
#legend .row span { margin-left: 4px; opacity: 0.85; letter-spacing: 0.04em; }
#legend .hint { opacity: 0.6; font-style: italic; margin-top: 2px; }
#legend kbd {
  min-width: 22px;
  padding: 2px 6px;
  text-align: center;
  font: 600 12px/1.4 "Segoe UI", system-ui, sans-serif;
  color: #eaf2ff;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 5px;
  backdrop-filter: blur(4px);
}

/* ---- Instrument readout (bottom-right) ---- */
#readout {
  position: fixed;
  right: clamp(16px, 4vw, 60px);
  bottom: clamp(66px, 11vh, 96px);
  z-index: 6;
  display: flex;
  align-items: flex-end;
  gap: 20px;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.7);
  animation: rise 1.4s cubic-bezier(0.16, 1, 0.3, 1) 0.5s both;
}
#readout .gauge { text-align: center; }
#readout .gauge b {
  display: block;
  font-size: clamp(22px, 4vw, 34px);
  font-weight: 800;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  transition: color 0.15s ease;
}

/* Brief flash on a firm-but-survivable touchdown. */
#readout.hard-landing .gauge b { color: #ff5a2b; }
#readout .gauge small,
#readout .thr small {
  font-size: 12px;
  letter-spacing: 0.2em;
  opacity: 0.7;
}
#readout .thr { display: grid; gap: 6px; }
#readout .thr-bar {
  position: relative;
  width: 90px;
  height: 6px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.16);
}
#readout .thr-bar span {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: 6px;
  background: linear-gradient(90deg, #46c6ff, #ffd36a);
  transition: background-color 0.15s ease;
}
/* ---- Collective / throttle ----------------------------------------------
   Players could not tell where the throttle was: it used to be a third 90x6
   bar, identical in shape to FUEL and HULL, with no number and a 2px hairline
   for the hover point. Now it is a READABLE NUMBER beside a VERTICAL column —
   vertical because W/S is up-down, so the control and the readout agree. The
   number is the primary readout (works without colour, so the colour-blind
   aid needs nothing extra); the column gives the at-a-glance position.
   Number and column sit SIDE BY SIDE on purpose: stacking them would grow the
   gauge row, and the minimap's offset (--readout-h) is keyed to that height. */
#readout .thr-col {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}
#readout .thr-num { text-align: right; }
#readout .thr-num b {
  display: block;
  font-size: clamp(22px, 4vw, 34px);
  font-weight: 800;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  transition: color 0.15s ease;
}
#readout .thr-num small {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  letter-spacing: 0.2em;
  opacity: 0.7;
}
#readout .thr-track {
  position: relative;
  width: 12px;
  height: 56px;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.16);
  overflow: hidden;
}
/* Fills from the BOTTOM up, like a real collective lever. */
#readout .thr-track span {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 0%;
  border-radius: 7px;
  background: linear-gradient(180deg, #7fdcff, #2f9dd4);
}
/* The hover point (thrust == gravity) is a BAND, not a hairline: the whole
   zone that holds a steady hover, with a brighter line at its centre. */
#readout .thr-hover-band {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 41.5%;
  height: 8%;
  background: rgba(255, 255, 255, 0.18);
  border-top: 1px solid rgba(255, 255, 255, 0.5);
  border-bottom: 1px solid rgba(255, 255, 255, 0.5);
  pointer-events: none;
}
/* Quarter marks, so the eye can judge the setting without reading the number. */
#readout .thr-tick {
  position: absolute;
  right: 0;
  width: 5px;
  height: 1px;
  background: rgba(255, 255, 255, 0.35);
  pointer-events: none;
}
/* Near-hover feedback: BOTH the number and the column turn teal, so a steady
   hover is learnable from either one. */
#readout .thr-col.near-hover .thr-track span {
  background: linear-gradient(180deg, #5cf0da, #21b9a2);
}
#readout .thr-col.near-hover .thr-num b { color: #5cf0da; }

/* Danger sink-rate warning on the altitude gauge. */
#hud-alt.sink-warning {
  color: #ff5a2b;
  animation: engine-blink 0.5s steps(1) infinite;
}

/* FUEL: amber→red. Needs the #readout prefix + the element, same as the HULL
   rules below — a bare `#hud-fuel-fill` id is only (1,0,0) and LOSES to the
   base `#readout .thr-bar span` blue→gold gradient at (1,1,1), so the fuel bar
   silently rendered blue→gold instead of amber. */
#readout .thr-bar span#hud-fuel-fill {
  background: linear-gradient(90deg, #ffb050, #ff5a2b);
}
.thr-bar.low-fuel span { animation: engine-blink 0.6s steps(1) infinite; }

/* HULL ("helicopter life"): healthy green→lime; turns red + blinks when low;
   a quick white flash on the frame an impact lands. The selectors carry the
   #hud-hull-fill id AND the #readout prefix so they out-specify the base
   `#readout .thr-bar span` blue→gold gradient (1,1,1); the low state adds the
   .low-hull class so it in turn beats the healthy rule. */
#hud-hull-fill { transition: width 0.15s linear; }
#readout .thr-bar span#hud-hull-fill {
  background: linear-gradient(90deg, #3ad16a, #9be24a);
}
#readout .thr-bar.low-hull span#hud-hull-fill {
  background: linear-gradient(90deg, #ff4d4d, #ff8a2b);
}
.thr-bar.low-hull span { animation: engine-blink 0.6s steps(1) infinite; }
.thr-bar.hull-hit { box-shadow: 0 0 8px 2px rgba(255, 255, 255, 0.85); }
@media (prefers-reduced-motion: reduce) {
  .thr-bar.low-fuel span, .thr-bar.low-hull span { animation: none; }
}

/* ---- Mobile throttle buttons (hidden on desktop) ---- */
#touch-throttle {
  position: fixed;
  right: calc(clamp(16px, 4vw, 40px) + env(safe-area-inset-right, 0px));
  bottom: calc(clamp(120px, 24vh, 220px) + env(safe-area-inset-bottom, 0px));
  z-index: 7;
  display: none;
  flex-direction: column;
  gap: 12px;
}
#touch-throttle button {
  width: 62px;
  height: 62px;
  font-size: 30px;
  color: #eaf2ff;
  background: rgba(10, 20, 32, 0.5);
  border: 1.5px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  backdrop-filter: blur(6px);
  touch-action: none;
  user-select: none;
}
#touch-throttle button:active { background: rgba(70, 198, 255, 0.4); }

/* Yaw pad (bottom-left) + engine/reset actions (above it). */
#touch-yaw {
  position: fixed;
  left: calc(clamp(16px, 4vw, 40px) + env(safe-area-inset-left, 0px));
  bottom: calc(clamp(120px, 24vh, 220px) + env(safe-area-inset-bottom, 0px));
  z-index: 7;
  display: none;
  flex-direction: row;
  gap: 12px;
}
#touch-actions {
  position: fixed;
  left: calc(clamp(16px, 4vw, 40px) + env(safe-area-inset-left, 0px));
  bottom: calc(clamp(200px, 40vh, 320px) + env(safe-area-inset-bottom, 0px));
  z-index: 7;
  display: none;
  flex-direction: row;
  gap: 12px;
}
#touch-yaw button,
#touch-actions button {
  width: 62px;
  height: 62px;
  font-size: 26px;
  color: #eaf2ff;
  background: rgba(10, 20, 32, 0.5);
  border: 1.5px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  backdrop-filter: blur(6px);
  touch-action: none;
  user-select: none;
}
#touch-actions #btn-engine { font-size: 30px; }
#touch-actions #btn-reset { font-size: 20px; }
/* Winch button (item 52): only exists while a hoist is engaged, and it is a
   HOLD control, so it gets the mission's own cyan and a clear held state —
   on touch there is no key to feel, and "am I actually winching" has to be
   readable from the button itself. `display` is overridden inside the
   coarse-pointer block below, which is what makes it touch-only. */
#touch-actions #btn-winch { display: none; border-color: rgba(127, 227, 255, 0.75); }
#touch-actions #btn-winch:active { background: rgba(127, 227, 255, 0.55); }
#touch-yaw button:active,
#touch-actions button:active { background: rgba(70, 198, 255, 0.4); }

/* Show touch controls / hide keyboard legend on coarse-pointer devices. */
@media (hover: none) and (pointer: coarse) {
  #touch-throttle,
  #touch-yaw,
  #touch-actions { display: flex; }
  #touch-cyclic { display: block; }
  #legend .row:not(.hint) { display: none; }
  body.hoist-on #touch-actions #btn-winch { display: block; }
}

/* ---- Engine-off warning ---- */
#engine-status {
  position: fixed;
  top: calc(7vh + clamp(14px, 3vh, 28px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 7;
  padding: 7px 16px;
  font-size: clamp(13px, 2vw, 17px);
  font-weight: 800;
  letter-spacing: 0.18em;
  color: #ff5a2b;
  background: rgba(20, 6, 2, 0.5);
  border: 1px solid rgba(255, 90, 43, 0.6);
  border-radius: 8px;
  backdrop-filter: blur(4px);
  pointer-events: none;
  display: none;
  /* Keep it to ONE line: #waypoint is stacked directly underneath at a fixed
     offset, so a wrapping banner would grow down and cover the compass. */
  white-space: nowrap;
  animation: engine-blink 0.7s steps(1) infinite;
}
#engine-status.show { display: block; }
@keyframes engine-blink { 50% { opacity: 0.35; } }

/* Round minimap (radar) — bottom-right, STACKED ABOVE the #readout gauges.
   Both used to sit at nearly the same `bottom` in the same corner, so the
   circle covered the last item in the gauge row — the HULL bar (measured:
   141x27px of overlap at 1280x720, 106x33 on a 812x375 phone in landscape).
   The gauges did not move (a throttle redesign is still to come); the map
   rises above them by the gauge-row height + a gap. --readout-h is the
   gauge row's real height: it is a stable two-line block, so a constant is
   enough — if that row ever grows, bump this ONE value.
   The size is also height-aware (min(15vw, 24vh)): on a short landscape
   phone a 15vw circle would climb into the mode buttons at the top-right,
   so it shrinks itself instead. */
#minimap {
  --readout-h: 62px;
  position: fixed;
  right: calc(clamp(12px, 2vw, 22px) + env(safe-area-inset-right, 0px));
  bottom: calc(
    clamp(64px, 12vh, 96px) + var(--readout-h) + 12px +
    env(safe-area-inset-bottom, 0px)
  );
  width: clamp(96px, min(15vw, 24vh), 170px);
  height: clamp(96px, min(15vw, 24vh), 170px);
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
  pointer-events: none;
  z-index: 6;
}

/* ---- Docking view (open item 26) ----------------------------------------
   A SECOND map, sitting immediately left of the minimap in the same band, so
   the two read as a pair: wide map = which way, docking map = where exactly.
   Same size and shape as the minimap, and the offsets are written as the
   minimap's own `right` + its own `width` + a gap, so the two can never drift
   apart if that size is ever retuned — change it in one place and this
   follows.
   It is always in the layout and only fades its OPACITY (never display), so
   the transition can actually run — `display: none` would make the fade-in
   jump. It draws nothing while faded out (see _updateDockingMap). */
#docking-map {
  --readout-h: 62px;
  --map-size: clamp(96px, min(15vw, 24vh), 170px);
  --map-gap: 12px;
  position: fixed;
  right: calc(
    clamp(12px, 2vw, 22px) + var(--map-size) + var(--map-gap) +
    env(safe-area-inset-right, 0px)
  );
  bottom: calc(
    clamp(64px, 12vh, 96px) + var(--readout-h) + 12px +
    env(safe-area-inset-bottom, 0px)
  );
  width: var(--map-size);
  height: var(--map-size);
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
  pointer-events: none;
  z-index: 6;
  opacity: 0;
  transition: opacity 0.28s ease;
}
#docking-map.show { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  #docking-map { transition: none; }
}

/* Winch height gauge — sits immediately LEFT of the docking map (i.e. two map
   slots in from the right edge), taller than it and narrow, so it reads as an
   instrument rather than as part of the map. Deliberately NOT round: the docking
   disc answers "where am I", this answers "how high am I", and making them look
   different is most of what stops them being confused for each other. It mirrors
   the map's own --map-size/--map-gap so the two always stay adjacent, including
   inside the three media queries below that move the map. */
#hoist-alt {
  --readout-h: 62px;
  --map-size: clamp(96px, min(15vw, 24vh), 170px);
  --map-gap: 12px;
  position: fixed;
  right: calc(
    clamp(12px, 2vw, 22px) + 2 * (var(--map-size) + var(--map-gap)) +
    env(safe-area-inset-right, 0px)
  );
  bottom: calc(
    clamp(64px, 12vh, 96px) + var(--readout-h) + 12px +
    env(safe-area-inset-bottom, 0px)
  );
  /* Kept in the 132x360 backing's own ratio (0.3667) so nothing is stretched;
     scaled up from a first pass at 0.42 because on screen the labels were still
     small — this instrument only exists to be read at a glance. */
  width: calc(var(--map-size) * 0.5);
  height: calc(var(--map-size) * 1.364);
  pointer-events: none;
  z-index: 6;
  opacity: 0;
  transition: opacity 0.28s ease;
}
#hoist-alt.show { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  #hoist-alt { transition: none; }
}

/* Sound on/off indicator (toggle with M). */
#sound-status {
  position: fixed;
  right: calc(clamp(12px, 2vw, 22px) + env(safe-area-inset-right, 0px));
  top: calc(7vh + clamp(14px, 3vh, 28px) + env(safe-area-inset-top, 0px));
  z-index: 7;
  font-size: clamp(16px, 2.4vw, 22px);
  line-height: 1;
  padding: 6px 8px;
  border-radius: 8px;
  background: rgba(8, 16, 24, 0.4);
  backdrop-filter: blur(4px);
  cursor: pointer;
  user-select: none;
  touch-action: manipulation;
}

/* Tail-rotor damage pill (Tier-3 damage model): amber, steadier blink than
   the engine warning — you're wounded, not falling. Sits just left of the
   centred engine banner so both can show at once without overlap. */
#damage-status {
  position: fixed;
  top: calc(7vh + clamp(14px, 3vh, 28px));
  left: calc(50% - clamp(120px, 18vw, 190px));
  transform: translateX(-100%);
  z-index: 7;
  padding: 7px 14px;
  font-size: clamp(12px, 1.8vw, 15px);
  font-weight: 800;
  letter-spacing: 0.16em;
  color: #ffb037;
  background: rgba(24, 14, 2, 0.55);
  border: 1px solid rgba(255, 176, 55, 0.55);
  border-radius: 8px;
  backdrop-filter: blur(4px);
  pointer-events: none;
  display: none;
  white-space: nowrap;
  animation: engine-blink 1.4s steps(1) infinite;
}
#damage-status.show { display: block; }

/* Special-mission objective banner (C3) — a calm info line (NOT an alarm),
   top-centre, out of the way of the damage warning. */
#special-banner {
  position: fixed;
  top: calc(7vh + clamp(14px, 3vh, 28px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 7;
  padding: 7px 16px;
  font-size: clamp(12px, 1.8vw, 15px);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #cfeeff;
  background: rgba(6, 20, 30, 0.6);
  border: 1px solid rgba(120, 200, 255, 0.45);
  border-radius: 999px;
  backdrop-filter: blur(4px);
  pointer-events: none;
  display: none;
  white-space: nowrap;
  max-width: 92vw;
  overflow: hidden;
  text-overflow: ellipsis;
}
#special-banner.show { display: block; }
/* If the tail-rotor warning is also showing, nudge the banner down so they
   don't overlap at the top-centre. */
#damage-status.show ~ #special-banner.show { top: calc(7vh + clamp(52px, 8vh, 74px)); }

/* Storm-mode indicator (open item 31) — same calm top-centre pill language
   as #special-banner, but a cool grey/blue so it reads as "weather", not an
   alarm or an objective. Stacks below whichever of damage-status/special-
   banner are also showing (same nudge convention as special-banner's own
   damage-status nudge above). */
#storm-banner {
  position: fixed;
  top: calc(7vh + clamp(14px, 3vh, 28px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 7;
  padding: 7px 16px;
  font-size: clamp(12px, 1.8vw, 15px);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #dfe6ec;
  background: rgba(30, 36, 44, 0.62);
  border: 1px solid rgba(180, 195, 210, 0.4);
  border-radius: 999px;
  backdrop-filter: blur(4px);
  pointer-events: none;
  display: none;
  white-space: nowrap;
}
#storm-banner.show { display: block; }
#damage-status.show ~ #storm-banner.show,
#special-banner.show ~ #storm-banner.show { top: calc(7vh + clamp(52px, 8vh, 74px)); }
#damage-status.show ~ #special-banner.show ~ #storm-banner.show { top: calc(7vh + clamp(90px, 13vh, 120px)); }

/* Calm "ready to start" prompt on the pad — not an alarm. */
#engine-status.ready {
  color: #37e0c8;
  background: rgba(2, 20, 18, 0.5);
  border-color: rgba(55, 224, 200, 0.55);
  animation: none;
}

/* ---- Crash banner ---- */
#crash-msg {
  position: fixed;
  inset: 0;
  z-index: 8;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease;
  background: radial-gradient(circle at 50% 45%, rgba(120, 20, 0, 0.28), transparent 60%);
}
#crash-msg.show { opacity: 1; }
#crash-msg .big {
  font-size: clamp(44px, 12vw, 130px);
  font-weight: 900;
  letter-spacing: 0.1em;
  color: #ff5a2b;
  text-shadow: 0 4px 40px rgba(255, 60, 0, 0.7), 0 2px 10px rgba(0, 0, 0, 0.8);
  animation: crash-pop 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
}
#crash-msg .cause {
  font-size: clamp(13px, 2.2vw, 18px);
  letter-spacing: 0.1em;
  color: var(--accent);
  opacity: 0.9;
  animation: rise 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.15s both;
}
#crash-msg .sub {
  font-size: clamp(12px, 2vw, 16px);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  opacity: 0.85;
}
#crash-msg .sub kbd {
  padding: 2px 7px;
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.12);
}
@keyframes crash-pop {
  from { transform: scale(1.5); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}

/* ---- Loading screen ---- */
#loader {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #05080d; /* fallback beneath .loader-sky, e.g. no-CSS-gradient edge case */
  transition: opacity 0.8s ease;
}
#loader.hidden { opacity: 0; pointer-events: none; }

/* Golden-hour sky, drifting clouds, mountain silhouette, a bobbing
   helicopter — all CSS/DOM, no image assets, echoing the game's own look
   instead of a plain spinner. Painted behind .loader-inner purely by DOM
   order (all position:absolute, z-index left auto). */
.loader-sky {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 70% 45% at 50% 78%, rgba(255, 200, 130, 0.55), rgba(255, 200, 130, 0) 70%),
    linear-gradient(to bottom, #1a2a52 0%, #3d3f7a 22%, #a8567a 45%, #e8804f 62%, #f5b569 78%, #2a1830 100%);
}
.loader-cloud {
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 236, 214, 0.22);
  filter: blur(14px);
  animation: loader-drift linear infinite;
}
.loader-cloud.c1 { width: 220px; height: 46px; top: 22%; left: -240px; animation-duration: 26s; }
.loader-cloud.c2 { width: 160px; height: 34px; top: 34%; left: -200px; animation-duration: 34s; animation-delay: -9s; opacity: 0.75; }
.loader-cloud.c3 { width: 280px; height: 52px; top: 15%; left: -320px; animation-duration: 42s; animation-delay: -20s; opacity: 0.6; }
@keyframes loader-drift {
  from { transform: translateX(0); }
  to { transform: translateX(calc(100vw + 320px)); }
}
.loader-mountains {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 22vh;
  background: #140d1c;
  clip-path: polygon(
    0% 100%, 0% 62%, 8% 48%, 15% 68%, 24% 30%, 33% 58%, 41% 40%,
    50% 66%, 58% 22%, 67% 52%, 76% 36%, 85% 60%, 93% 44%, 100% 58%, 100% 100%
  );
  opacity: 0.92;
}
.loader-heli {
  position: absolute;
  top: 40%;
  left: 20%;
  font-size: clamp(22px, 3vw, 32px);
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.4));
  animation: loader-heli-bob 4.5s ease-in-out infinite;
}
@keyframes loader-heli-bob {
  0%, 100% { transform: translate(0, 0) rotate(-2deg); }
  50% { transform: translate(18px, -10px) rotate(2deg); }
}

.loader-inner { position: relative; text-align: center; }

/* Rotating tips — pure CSS keyframe cycling across N stacked lines, no JS.
   Each tip gets an equal slice of one shared cycle via a negative
   animation-delay offsetting where in the loop it starts. */
#loader-tips {
  position: relative;
  width: min(86vw, 420px);
  height: 34px;
  margin: 18px auto 0;
}
#loader-tips .tip {
  position: absolute;
  inset: 0;
  margin: 0;
  font-size: 12.5px;
  line-height: 1.4;
  color: rgba(234, 242, 255, 0.82);
  opacity: 0; /* the static pre-animation style — shown during each tip's positive delay */
  animation: loader-tip-cycle 24s ease-in-out infinite;
}
/* Positive delays, staggered by one 4s slot each (24s / 6 tips). Each tip's
   own animation only STARTS at its delay, so it sits at its static opacity:0
   until then — the SAME 0%-16.7% "visible" window in every tip's keyframe
   lands at a different real-world 4s slot purely from the delay offset. */
#loader-tips .tip:nth-child(1) { animation-delay: 0s; }
#loader-tips .tip:nth-child(2) { animation-delay: 4s; }
#loader-tips .tip:nth-child(3) { animation-delay: 8s; }
#loader-tips .tip:nth-child(4) { animation-delay: 12s; }
#loader-tips .tip:nth-child(5) { animation-delay: 16s; }
#loader-tips .tip:nth-child(6) { animation-delay: 20s; }
@keyframes loader-tip-cycle {
  0% { opacity: 0; }
  3% { opacity: 1; }
  13% { opacity: 1; }
  16.7% { opacity: 0; }
  100% { opacity: 0; }
}

.spinner {
  width: 46px;
  height: 46px;
  margin: 0 auto 22px;
  border: 3px solid rgba(255, 255, 255, 0.12);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.loader-label {
  font-size: 12px;
  letter-spacing: 0.34em;
  opacity: 0.8;
  margin-bottom: 14px;
}
.loader-bar {
  width: 220px;
  height: 3px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
.loader-bar span {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 0.3s ease;
}

#hud-mission {
  margin-top: 6px;
  font-size: clamp(12px, 1.4vw, 13px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.65;
}
#hud-mission b { color: var(--accent); font-weight: 800; }
#hud-ring {
  margin-top: 4px;
  font-size: clamp(12px, 1.4vw, 13px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.65;
}
#hud-ring b { color: #ffe066; font-weight: 800; }

/* ---- In-game clock (top-left, under the mission lines) ----
   Deliberately NOT bottom-right: that corner already has the gauges and the
   minimap fighting for room (see the known HULL/minimap overlap). The tint
   shifts with the part of the day, so the colour alone half-tells the time. */
#hud-clock {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  margin-top: 10px;
  padding: 4px 11px;
  border-radius: 999px;
  background: rgba(8, 16, 24, 0.36);
  border: 1px solid rgba(255, 255, 255, 0.16);
  backdrop-filter: blur(4px);
  /* Set per phase from main.js via a CSS custom property. */
  color: var(--clock-tint, #ffd7a0);
  transition: color 0.6s linear, border-color 0.6s linear;
  border-color: color-mix(in srgb, var(--clock-tint, #ffd7a0) 34%, transparent);
}
#clock-icon { font-size: 14px; }
#clock-time {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}
#clock-phase {
  font-size: 12px;
  opacity: 0.8;
  letter-spacing: 0.02em;
}
/* Only shown when the day/night cycle is switched off in Settings — otherwise
   a clock that never moves reads as broken. */
#clock-frozen {
  display: none;
  font-style: normal;
  font-size: 10px;
  letter-spacing: 0.08em;
  opacity: 0.55;
}
#hud-clock.frozen #clock-frozen { display: inline; }
#hud-ring kbd {
  padding: 1px 5px;
  font: 700 11px/1.4 "Segoe UI", system-ui, sans-serif;
  color: #eaf2ff;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 4px;
}

/* ---- Waypoint compass ---- */
#waypoint {
  position: fixed;
  left: 50%;
  /* Sits BELOW #engine-status, which is centred at the same top offset and
     has a higher z-index — before this, the "PRESS E TO START" / "ENGINE OFF"
     banner covered the compass completely (and the engine now starts off, so
     that banner is showing the moment you load in). */
  top: calc(7vh + clamp(14px, 3vh, 28px) + 46px);
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  pointer-events: none;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.7);
}
#waypoint-label {
  font-size: 12px;
  /* Was 0.2em, which is a Latin-caps convention — Bangla conjuncts read as
     broken apart at that tracking, so the label sets solid now that it names
     the pad in Bangla. */
  letter-spacing: normal;
  opacity: 0.85;
}
/* Same blue/orange pair as the minimap, docking view and the tutorial card's
   "তোমার কাজ" brief, so every place that mentions a pad agrees on its colour. */
#waypoint-label.to-pickup { color: #46c6ff; }
#waypoint-label.to-dropoff { color: #ff8a46; }

/* First-flight emphasis (open item 26): a slow breathing pulse on the whole
   compass while the guided first flight is running, drawing a new player's eye
   to the one element that answers "where do I go". main.js removes the class
   for good once onboarding completes, and never adds it when the reduce-motion
   setting is on. Opacity/scale only — no layout property — so it can't cost a
   reflow per frame. */
#waypoint.first-flight {
  animation: waypoint-coach 2.4s ease-in-out infinite;
}
@keyframes waypoint-coach {
  0%, 100% { opacity: 0.85; transform: translateX(-50%) scale(1); }
  50% { opacity: 1; transform: translateX(-50%) scale(1.09); }
}
/* The OS-level preference, alongside the in-game reduce-motion toggle. */
@media (prefers-reduced-motion: reduce) {
  #waypoint.first-flight { animation: none; }
}
#waypoint-arrow {
  width: 26px;
  height: 26px;
  color: var(--accent);
  fill: currentColor;
  /* Spin about the arrow's own centre, not a corner. */
  transform-origin: 50% 50%;
  transition: transform 0.1s linear;
  /* text-shadow doesn't apply to SVG fills — use a real drop shadow so the
     arrow stays readable against a bright sky. */
  filter: drop-shadow(0 1px 5px rgba(0, 0, 0, 0.8));
}
#waypoint-dist {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}

/* ---- Patient heartbeat bar (রোগী cargo runs only) ---- */
#heartbeat {
  position: fixed;
  left: 50%;
  /* Just under the waypoint compass block. */
  top: calc(7vh + clamp(14px, 3vh, 28px) + 46px + 96px);
  transform: translateX(-50%);
  z-index: 6;
  display: none;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(10, 16, 22, 0.55);
  border: 1px solid rgba(255, 107, 129, 0.45);
  backdrop-filter: blur(4px);
}
#heartbeat.show { display: flex; }

/* Full-screen max-altitude danger warning — a pulsing red vignette hugging
   the screen edges. pointer-events:none so it never blocks input; opacity
   transition (not display) so it fades in/out instead of popping. */
#alt-danger {
  position: fixed;
  inset: 0;
  z-index: 16;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
  box-shadow: inset 0 0 min(18vw, 220px) min(6vw, 70px) rgba(200, 20, 20, 0.65);
}
#alt-danger.show {
  opacity: 1;
  animation: alt-danger-pulse 1.1s ease-in-out infinite;
}
@keyframes alt-danger-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}

/* Countdown-to-destruction panel — pairs with #alt-danger, shown/hidden the
   same way (state.altWarn). The vignette says "dangerous"; this says
   exactly how long there is to react. */
#alt-timer {
  position: fixed;
  top: calc(7vh + clamp(14px, 3vh, 28px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 17;
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px 18px;
  border-radius: 10px;
  background: rgba(20, 6, 6, 0.55);
  border: 1px solid rgba(255, 90, 90, 0.55);
  backdrop-filter: blur(4px);
  pointer-events: none;
}
#alt-timer.show { display: flex; }
#alt-timer-label {
  font: 700 12px/1 "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.04em;
  color: #ffb3b3;
}
#alt-timer-secs {
  font: 800 26px/1 "Segoe UI", system-ui, sans-serif;
  color: #ff4b4b;
}
#alt-timer-track {
  width: 160px;
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.15);
  overflow: hidden;
}
#alt-timer-fill {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, #ff4b4b, #ffae42);
  transition: width 0.1s linear;
}
#hb-icon {
  color: #ff6b81;
  font-size: 15px;
  animation: hb-pulse 0.9s ease-in-out infinite;
}
#heartbeat.critical #hb-icon { animation-duration: 0.45s; }
@keyframes hb-pulse {
  0%, 100% { transform: scale(1); }
  35% { transform: scale(1.35); }
}
#hb-track {
  width: 120px;
  height: 7px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
#hb-fill {
  width: 100%;
  height: 100%;
  border-radius: 999px;
  background: #ff6b81;
  transition: width 0.25s linear;
}
#heartbeat.critical #hb-fill { background: #ff3050; }
#hb-label {
  font-size: 12px;
  font-weight: 700;
  color: #ffd7dd;
}

/* ---- Toasts (landing quality, pickup/delivery/best) ---- */
#toast {
  position: fixed;
  left: 50%;
  top: 30%;
  transform: translate(-50%, -50%);
  z-index: 9;
  padding: 10px 22px;
  font-size: clamp(14px, 2.4vw, 20px);
  font-weight: 800;
  /* Small tracking only — 0.16em fanned Bangla conjuncts/matras apart and
     read as broken; English caps still look fine at this. */
  letter-spacing: 0.02em;
  color: var(--accent);
  background: rgba(8, 16, 24, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 10px;
  backdrop-filter: blur(4px);
  max-width: min(88vw, 620px);
  text-align: center;
  line-height: 1.5;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
#toast.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* ---- Delivery report card (A2) ---- */
#report-card {
  position: fixed;
  left: 50%;
  top: 52%;
  transform: translate(-50%, -46%) scale(0.96);
  z-index: 12; /* over the HUD, under the pause/leaderboard overlays */
  min-width: 240px;
  max-width: min(86vw, 320px);
  padding: 16px 22px 18px;
  border-radius: 14px;
  background: rgba(9, 18, 28, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(6px);
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
}
#report-card.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }
#report-card .rc-stars { font-size: 26px; letter-spacing: 0.12em; line-height: 1; }
#report-card .rc-title {
  margin: 8px 0 2px;
  font-size: 17px;
  letter-spacing: 0.04em;
  color: var(--accent);
}
#report-card .rc-sub { font-size: 11.5px; opacity: 0.55; letter-spacing: 0.08em; }
#report-card .rc-rows {
  margin-top: 12px;
  display: grid;
  gap: 6px;
  font-size: 13.5px;
}
#report-card .rc-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 5px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
#report-card .rc-row:last-child { border-bottom: none; padding-bottom: 0; }
#report-card .rc-row span { opacity: 0.8; }
#report-card .rc-row b { color: #eaf2ff; font-weight: 700; }

/* ---- Story chapter card (C1) ---- */
#chapter-card {
  position: fixed;
  inset: 0;
  z-index: 21; /* above the pause menu (20), so it can be opened from there */
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(2, 6, 12, 0.66);
  backdrop-filter: blur(4px);
}
#chapter-card.show { display: flex; }
.chapter-inner {
  max-width: min(92vw, 540px);
  max-height: 86vh;
  overflow-y: auto;
  padding: 28px 34px 26px;
  border-radius: 14px;
  background: #0d1a28;
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.chapter-kicker {
  font-size: 12px;
  letter-spacing: 0.28em;
  opacity: 0.55;
  margin-bottom: 8px;
}
#chapter-title {
  font-size: 20px;
  line-height: 1.3;
  color: var(--accent);
  margin: 0 0 16px;
}
#chapter-body p {
  margin: 0 0 13px;
  font-size: 14.5px;
  line-height: 1.75;
  opacity: 0.92;
}
/* A quoted note (Rahmat's chit, Diya's line) — set apart, warm. */
#chapter-body p.quote {
  font-style: italic;
  color: #d6a860;
  border-left: 3px solid rgba(214, 168, 96, 0.5);
  padding-left: 12px;
}
#chapter-close {
  display: block;
  margin: 20px 0 0 auto;
  padding: 9px 22px;
  font: 700 13px/1 "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.1em;
  color: #05080d;
  background: var(--accent);
  border: none;
  border-radius: 7px;
  cursor: pointer;
}

/* Pause-menu story list (C1) */
.pause-story {
  margin-top: 22px;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  padding-top: 16px;
}
.pause-story h3 {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0 0 12px;
  color: rgba(234, 242, 255, 0.5);
}
.pause-story h3 span { opacity: 0.55; font-weight: 400; margin-left: 4px; text-transform: none; letter-spacing: normal; }
.pause-community {
  margin-top: 22px;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  padding-top: 16px;
}
.pause-community h3 {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0 0 10px;
  color: rgba(234, 242, 255, 0.5);
}
.pause-community h3 span { opacity: 0.55; font-weight: 400; margin-left: 4px; text-transform: none; letter-spacing: normal; }
.story-grid { display: grid; gap: 6px; }
.story-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 11px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 2px;
  font-size: 12px;
  color: rgba(234, 242, 255, 0.75);
  opacity: 0.4; /* locked */
}
.story-item.unlocked {
  opacity: 1;
  cursor: pointer;
  border-color: rgba(214, 168, 96, 0.28);
}
.story-item.unlocked:hover { background: rgba(214, 168, 96, 0.08); }
.story-item .si-title { flex: 1 1 auto; min-width: 0; }
.story-item.unlocked .si-title { color: var(--accent); }
.story-item .si-lock { font-size: 10.5px; opacity: 0.6; flex: 0 0 auto; }

/* ---- Camera-mode + dev buttons ----
   ONE flex row, right-anchored as a group, instead of three buttons each
   pinned at its own hand-picked `right:` offset. The old offsets assumed a
   ~100px button width; "CINEMATIC" alone renders wider than that, so the
   fixed gaps clipped at ordinary desktop widths (see CLAUDE.md open item 8).
   A flex row sizes to each button's REAL width, so this can't clip again. */
#camera-buttons {
  position: fixed;
  right: calc(clamp(96px, 16vw, 130px) + env(safe-area-inset-right, 0px));
  top: calc(7vh + clamp(14px, 3vh, 28px) + env(safe-area-inset-top, 0px));
  z-index: 7;
  display: flex;
  gap: 8px;
}
#camera-buttons button {
  padding: 6px 12px;
  font: 700 12px/1 "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.08em;
  color: #eaf2ff;
  background: rgba(8, 16, 24, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 8px;
  backdrop-filter: blur(4px);
  cursor: pointer;
  white-space: nowrap;
}
#btn-cinematic.active,
#btn-cockpit.active {
  color: #05080d;
  background: var(--accent);
  border-color: var(--accent);
}
#btn-dev.active {
  color: #05080d;
  background: #7dffb3;
  border-color: #7dffb3;
}

/* Mode buttons (T/N/B/G/L) — a wrapping flex row UNDER the camera buttons.
   A row rather than more hand-positioned `right:` offsets like the three
   above: five more of those would collide on a phone, and this set has to
   work on touch above all (it's the only way to reach these modes there). */
#mode-buttons {
  position: fixed;
  right: calc(clamp(96px, 16vw, 130px) + env(safe-area-inset-right, 0px));
  top: calc(7vh + clamp(14px, 3vh, 28px) + 34px + env(safe-area-inset-top, 0px));
  z-index: 7;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 6px;
  max-width: min(52vw, 380px);
}
#mode-buttons button {
  padding: 6px 10px;
  font: 700 11px/1 "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.06em;
  color: #eaf2ff;
  background: rgba(8, 16, 24, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 8px;
  backdrop-filter: blur(4px);
  cursor: pointer;
  white-space: nowrap;
}
#mode-buttons button.active {
  color: #05080d;
  background: var(--accent);
  border-color: var(--accent);
}
/* Locked modes (night/storm before their delivery milestone) read as dimmed,
   but stay tappable — pressing one toasts how many deliveries remain, which
   is the intended "goal, not a wall" feedback. */
#mode-buttons button.locked {
  opacity: 0.45;
}
/* Touch devices get bigger hit targets (44px is the usual minimum). */
@media (pointer: coarse) {
  #mode-buttons button {
    padding: 11px 13px;
    font-size: 12px;
  }
  #mode-buttons { gap: 8px; max-width: min(64vw, 420px); }
}

/* ---- Developer overlay (stats + raw state) ---- */
#dev-panel {
  position: fixed;
  left: clamp(16px, 4vw, 60px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 7;
  display: none;
  flex-direction: column;
  gap: 8px;
  padding: 12px 16px;
  min-width: 260px;
  max-width: min(420px, 92vw); /* was unbounded — the long #dev-help line
    stretched the whole panel wide with nothing to wrap against */
  background: rgba(6, 10, 16, 0.72);
  border: 1px solid rgba(125, 255, 179, 0.35);
  border-radius: 10px;
  backdrop-filter: blur(6px);
  color: #d8ffe9;
  font: 500 12px/1.5 "Consolas", "SF Mono", monospace;
  pointer-events: none;
}
#dev-panel.show { display: flex; }

/* Dev "clear view": the free-fly camera exists to LOOK at the world, and the
   full gameplay HUD sits right on top of it (title, key legend, gauges, radar,
   mode/camera buttons). While dev mode is on, hide the PLAYER-facing chrome and
   keep only the dev panel. `!important` because several of these are shown by
   their own `.show`/state classes, which would otherwise win. Toggle with H.

   The opening intro (item 45) hides the exact same list, so the selector takes
   BOTH classes rather than the list being duplicated. It is only the CSS half
   that is shared: dev mode also strips fog and clouds (World.setClearView),
   which the intro must NOT do — that atmosphere is most of what the sequence
   is there to show. See main.js _setIntroChrome(). */
body:is(.dev-clean, .intro-play) #hud,
body:is(.dev-clean, .intro-play) #legend,
body:is(.dev-clean, .intro-play) #readout,
body:is(.dev-clean, .intro-play) #minimap,
body:is(.dev-clean, .intro-play) #docking-map,
body:is(.dev-clean, .intro-play) #hoist-alt,
body:is(.dev-clean, .intro-play) #waypoint,
body:is(.dev-clean, .intro-play) #mode-buttons,
body:is(.dev-clean, .intro-play) #heartbeat,
body:is(.dev-clean, .intro-play) #damage-status,
body:is(.dev-clean, .intro-play) #special-banner,
body:is(.dev-clean, .intro-play) #storm-banner,
body:is(.dev-clean, .intro-play) #report-card,
body:is(.dev-clean, .intro-play) #toast,
body:is(.dev-clean, .intro-play) #help-reopen,
body:is(.dev-clean, .intro-play) #sound-status,
body:is(.dev-clean, .intro-play) #cinematic-label,
body:is(.dev-clean, .intro-play) #btn-cinematic,
body:is(.dev-clean, .intro-play) #btn-cockpit,
body:is(.dev-clean, .intro-play) #touch-throttle,
body:is(.dev-clean, .intro-play) #touch-yaw,
body:is(.dev-clean, .intro-play) #touch-actions,
body:is(.dev-clean, .intro-play) #touch-cyclic { display: none !important; }
#dev-stats { color: #7dffb3; font-weight: 700; letter-spacing: 0.04em; }
#dev-state { margin: 0; white-space: pre-wrap; }
#dev-help { opacity: 0.6; font-size: 10.5px; letter-spacing: 0.02em; }

/* #dev-panel itself is pointer-events:none (it sits over the game world and
   must never block flight input) — these buttons need their own pointer-events
   to stay clickable. */
#dev-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  pointer-events: auto;
}
#dev-controls button,
.dev-time-group button {
  font: 700 10.5px/1 "Consolas", "SF Mono", monospace;
  letter-spacing: 0.03em;
  padding: 5px 8px;
  border-radius: 6px;
  border: 1px solid rgba(125, 255, 179, 0.35);
  background: rgba(20, 28, 24, 0.7);
  color: #d8ffe9;
  cursor: pointer;
}
#dev-controls button.active { background: #2e8f66; border-color: #7dffb3; color: #06140c; }
.dev-time-group { display: flex; gap: 4px; }
.dev-time-group button { padding: 5px 6px; }
.dev-time-slider-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  pointer-events: auto;
}
.dev-time-slider-row input[type="range"] { flex: 1; accent-color: #7dffb3; }
#dev-time-readout { min-width: 44px; font-weight: 700; }

#cinematic-label {
  position: fixed;
  left: 50%;
  bottom: clamp(66px, 11vh, 96px);
  transform: translateX(-50%);
  z-index: 6;
  padding: 5px 14px;
  font: 700 12px/1 "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.2em;
  color: var(--fg);
  background: rgba(8, 16, 24, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 20px;
  backdrop-filter: blur(4px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
#cinematic-label.show { opacity: 1; }

/* ---- Getting-started card ---- */
#help-reopen {
  position: fixed;
  right: calc(clamp(52px, 8vw, 66px) + env(safe-area-inset-right, 0px));
  top: calc(7vh + clamp(14px, 3vh, 28px) + env(safe-area-inset-top, 0px));
  z-index: 7;
  width: 30px;
  height: 30px;
  font: 700 15px/1 "Segoe UI", system-ui, sans-serif;
  color: #eaf2ff;
  background: rgba(8, 16, 24, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  backdrop-filter: blur(4px);
  cursor: pointer;
}

/* ---- Clean view toggle ---- */
#clean-view-btn {
  position: fixed;
  right: calc(clamp(92px, 14vw, 106px) + env(safe-area-inset-right, 0px));
  top: calc(7vh + clamp(14px, 3vh, 28px) + env(safe-area-inset-top, 0px));
  z-index: 7;
  width: 30px;
  height: 30px;
  font-size: 15px;
  color: #eaf2ff;
  background: rgba(8, 16, 24, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  backdrop-filter: blur(4px);
  cursor: pointer;
  /* Stays visible even in clean view — it's the only way back. */
}
#clean-view-btn.active {
  color: #05080d;
  background: var(--accent);
  border-color: var(--accent);
}
/* Player-facing "clean view" — hide the INFORMATIONAL HUD clutter, but never
   flight-safety feedback (crash banner, altitude danger, radio toasts) or
   the touch flight controls (needed to actually fly on a touch device). */
body.clean-view #hud,
body.clean-view #legend,
body.clean-view #readout,
body.clean-view #minimap,
body.clean-view #docking-map,
body.clean-view #hoist-alt,
body.clean-view #waypoint,
body.clean-view #mode-buttons,
body.clean-view #heartbeat,
body.clean-view #damage-status,
body.clean-view #special-banner,
body.clean-view #storm-banner,
body.clean-view #report-card,
body.clean-view #help-reopen,
body.clean-view #sound-status,
body.clean-view #cinematic-label,
body.clean-view #camera-buttons { display: none !important; }

/* ---- Local leaderboards (toggle with L) ---- */
#leaderboard {
  position: fixed;
  inset: 0;
  z-index: 18; /* under the tutorial card, over everything else */
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(2, 6, 12, 0.55);
  backdrop-filter: blur(3px);
}
#leaderboard.show { display: flex; }
.lb-inner {
  max-width: min(92vw, 560px);
  padding: 26px 32px;
  border-radius: 14px;
  background: #0d1a28;
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.lb-inner h2 {
  font-size: 19px;
  letter-spacing: 0.2em;
  margin: 0 0 14px;
  color: var(--accent);
}
.lb-cols {
  display: flex;
  gap: 28px;
  flex-wrap: wrap; /* stacks on narrow/portrait screens */
}
.lb-col { flex: 1 1 200px; }
.lb-col h3 {
  font-size: 13.5px;
  margin: 0 0 8px;
  opacity: 0.9;
}
.lb-col ol {
  margin: 0;
  padding-left: 22px;
  font-size: 14px;
  line-height: 1.9;
}
.lb-col ol li small { opacity: 0.5; margin-left: 6px; font-size: 11px; }
.lb-col ol li.empty { list-style: none; margin-left: -22px; opacity: 0.6; }
.lb-hint {
  margin-top: 16px;
  font-size: 12px;
  opacity: 0.6;
}

/* ---- Dev-mode task list popup (item 74) ---- */
#dev-task-popup {
  position: fixed;
  inset: 0;
  z-index: 18;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(2, 6, 12, 0.55);
  backdrop-filter: blur(3px);
}
#dev-task-popup.show { display: flex; }
.dtp-inner {
  max-width: min(92vw, 640px);
  max-height: 80vh;
  overflow-y: auto;
  padding: 26px 32px;
  border-radius: 14px;
  background: #0d1a28;
  border: 1px solid rgba(125, 255, 179, 0.35);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  color: #d8ffe9;
  font: 500 13px/1.6 "Consolas", "SF Mono", monospace;
}
.dtp-inner h2 {
  font-size: 17px;
  letter-spacing: 0.08em;
  margin: 0 0 14px;
  color: var(--accent);
}
.dtp-inner h2 small { font-size: 11px; opacity: 0.6; letter-spacing: 0.02em; }
#dtp-list { margin: 0; padding-left: 22px; }
#dtp-list li { margin-bottom: 8px; }
#dtp-list li b { color: #7dffb3; }
#dtp-list li.dtp-empty { list-style: none; margin-left: -22px; opacity: 0.6; }
.dtp-hint { margin-top: 16px; font-size: 11px; opacity: 0.55; }

#tutorial-card {
  position: fixed;
  inset: 0;
  z-index: 19;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(2, 6, 12, 0.55);
  backdrop-filter: blur(3px);
  transition: opacity 0.3s ease;
}
#tutorial-card.hidden { opacity: 0; pointer-events: none; }
.tutorial-inner {
  max-width: min(90vw, 460px);
  /* The card is taller than a 720p viewport once the prologue, the "তোমার কাজ"
     brief and the controls list are all stacked — without this it overflowed
     off the top and clipped its own bottom buttons. Cap it and let it scroll
     rather than dropping content. */
  max-height: 92vh;
  overflow-y: auto;
  padding: 28px 32px;
  border-radius: 14px;
  background: #0d1a28;
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
/* Story prologue at the top of the tutorial card. */
.tutorial-inner .prologue {
  margin-bottom: 18px;
  padding-bottom: 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 13.5px;
  line-height: 1.7;
  opacity: 0.92;
}
.tutorial-inner .prologue p { margin: 0 0 8px; }
.tutorial-inner .prologue b { color: var(--accent); }
.tutorial-inner .prologue .note {
  font-style: italic;
  color: #d6a860;
  border-left: 3px solid rgba(214, 168, 96, 0.5);
  padding-left: 10px;
}

/* "তোমার কাজ" brief — sits between the story prologue and the controls list,
   so a new player reads WHAT to do before HOW to do it (open item 26). */
.tutorial-inner .objective-brief {
  margin-bottom: 18px;
  padding-bottom: 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 13.5px;
  line-height: 1.7;
  opacity: 0.94;
}
.tutorial-inner .objective-brief h3 {
  font-size: 14px;
  letter-spacing: 0.1em;
  color: var(--accent);
  margin: 0 0 8px;
}
.tutorial-inner .objective-brief p { margin: 0 0 8px; }
.tutorial-inner .objective-brief p:last-child { margin-bottom: 0; }
/* Same blue/orange pair the minimap and docking view already use for the two
   pads, so the words match what the player is looking at. */
.tutorial-inner .objective-brief .pad-pickup { color: #46c6ff; }
.tutorial-inner .objective-brief .pad-drop { color: #ff8a46; }
.tutorial-inner .objective-brief .hint {
  font-size: 12.5px;
  opacity: 0.8;
}

.tutorial-inner h2 {
  font-size: 20px;
  letter-spacing: 0.18em;
  color: var(--accent);
  margin-bottom: 16px;
}
.tutorial-inner ol {
  margin: 0 0 22px 20px;
  display: grid;
  gap: 10px;
  font-size: 14px;
  line-height: 1.5;
  opacity: 0.9;
}
.tutorial-inner kbd {
  padding: 2px 6px;
  margin: 0 2px;
  font: 600 12px/1.4 "Segoe UI", system-ui, sans-serif;
  color: #eaf2ff;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 5px;
}
#tutorial-close {
  display: block;
  margin-left: auto;
  padding: 8px 20px;
  font: 700 13px/1 "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.12em;
  color: #05080d;
  background: var(--accent);
  border: none;
  border-radius: 7px;
  cursor: pointer;
}
/* Reset-progress: quiet and low-key (destructive, not a primary action) —
   a muted outline that warms to a warning red on hover/confirm. */
#reset-progress {
  display: block;
  margin: 14px auto 0;
  padding: 6px 14px;
  font: 600 11px/1.3 "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.5);
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 6px;
  cursor: pointer;
  text-align: center;
}
#reset-progress:hover {
  color: #ffd9d0;
  border-color: rgba(255, 90, 43, 0.7);
  background: rgba(255, 90, 43, 0.12);
}
#reset-progress.confirm {
  color: #05080d;
  background: #ff5a2b;
  border-color: #ff5a2b;
}

/* ---- Pause + Settings screen ---- */
#pause-menu {
  position: fixed;
  inset: 0;
  z-index: 20; /* above the leaderboard (18) and tutorial card (19) */
  display: none;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, rgba(4, 5, 7, 0.72) 0%, rgba(2, 3, 4, 0.9) 100%);
  backdrop-filter: blur(6px) saturate(0.9);
}
#pause-menu.show { display: flex; }
/* Muted, near-neutral panel — deliberately NOT the blue-tinted HUD chrome,
   sharp corners and a hairline top edge instead of a heavy border/glow. */
.pause-inner {
  --pm-line: rgba(255, 255, 255, 0.09);
  --pm-text-dim: rgba(234, 242, 255, 0.5);
  max-width: min(92vw, 600px);
  max-height: 88vh;
  overflow-y: auto;
  padding: 30px 34px;
  border-radius: 3px;
  background: linear-gradient(180deg, #16181c 0%, #101215 100%);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.65);
}
.pause-inner h2 {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.32em;
  margin: 0 0 24px;
  color: var(--pm-text-dim);
  text-transform: uppercase;
}
.pause-inner h2 i {
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.28em;
  opacity: 0.5;
  font-size: 12px;
}
.pause-icon {
  position: relative;
  display: inline-block;
  width: 12px;
  height: 13px;
  color: transparent;
}
.pause-icon::before,
.pause-icon::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--accent);
}
.pause-icon::before { left: 0; }
.pause-icon::after { right: 0; }
.pause-cols {
  display: flex;
  gap: 28px;
  flex-wrap: wrap; /* stacks on narrow / portrait screens */
}
.pause-obj,
.pause-set { flex: 1 1 220px; }
.pause-obj h3,
.pause-set h3 {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0 0 14px;
  color: var(--pm-text-dim);
}
.pause-obj p { margin: 0 0 14px; font-size: 13.5px; line-height: 1.5; color: rgba(234, 242, 255, 0.82); }
.pause-obj ul {
  margin: 0 0 14px;
  padding: 0;
  list-style: none;
  font-size: 13px;
  line-height: 2.1;
}
.pause-obj ul li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  color: rgba(234, 242, 255, 0.62);
  border-bottom: 1px solid var(--pm-line);
}
.pause-obj ul li b { color: var(--fg); font-weight: 600; }
.pause-next {
  font-size: 12.5px !important;
  color: rgba(234, 242, 255, 0.72);
  border-left: 2px solid var(--accent);
  padding-left: 10px;
}
.set-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 15px;
  font-size: 13px;
  color: rgba(234, 242, 255, 0.82);
}
/* Settings-row icons are functional shorthand, not decoration — kept small
   and desaturated so they read as UI glyphs, not colourful emoji. */
.set-row span {
  display: flex;
  align-items: center;
  gap: 8px;
  filter: saturate(0.55) brightness(0.92); /* tones down the leading emoji glyph */
}
.set-row input[type="range"] { flex: 1 1 auto; max-width: 130px; accent-color: var(--accent); }

/* Custom checkbox → a minimal sliding switch, no native browser chrome. */
.set-row input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  width: 34px;
  height: 18px;
  flex: 0 0 auto;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.set-row input[type="checkbox"]::after {
  content: "";
  position: absolute;
  top: 1px;
  left: 1px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: rgba(234, 242, 255, 0.6);
  transition: transform 0.15s ease, background 0.15s ease;
}
.set-row input[type="checkbox"]:checked {
  background: rgba(70, 198, 255, 0.22);
  border-color: rgba(70, 198, 255, 0.55);
}
.set-row input[type="checkbox"]:checked::after {
  transform: translateX(16px);
  background: var(--accent);
}

/* Custom select — flat, sharp corners, thin caret, no native OS chrome. */
.set-row select {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  padding: 6px 26px 6px 10px;
  font: 500 12px/1.3 "Segoe UI", system-ui, sans-serif;
  color: var(--fg);
  background: rgba(255, 255, 255, 0.05) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='6' viewBox='0 0 9 6'%3E%3Cpath d='M1 1l3.5 3.5L8 1' stroke='%2390a4b8' stroke-width='1.3' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 9px center;
  border: 1px solid var(--pm-line);
  border-radius: 2px;
  cursor: pointer;
}
.set-row select:hover { border-color: rgba(255, 255, 255, 0.28); }
.set-row select option { color: #05080d; }
.set-group {
  margin: 18px 0 12px;
  padding-top: 14px;
  border-top: 1px solid var(--pm-line);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(234, 242, 255, 0.38);
}
.set-soon { font-size: 11.5px; opacity: 0.5; margin: 4px 0 0; font-style: italic; }
.pause-firsts {
  margin-top: 22px;
  border-top: 1px solid var(--pm-line);
  padding-top: 16px;
}
.pause-firsts h3 {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0 0 14px;
  color: var(--pm-text-dim);
}
.pause-firsts h3 span { opacity: 0.55; font-weight: 400; margin-left: 4px; text-transform: none; letter-spacing: normal; }
.firsts-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px 18px;
}
.first-item {
  display: flex;
  align-items: center;
  gap: 9px;
  opacity: 0.38; /* locked: dimmed but readable — the goal stays visible */
}
.first-item.got { opacity: 1; }
.first-item .fi-icon {
  font-size: 15px;
  flex: 0 0 auto;
  width: 22px;
  text-align: center;
  filter: saturate(0.6) brightness(0.9);
}
.first-item .fi-text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.first-item .fi-text b { font-size: 12px; font-weight: 500; color: rgba(234, 242, 255, 0.85); }
.first-item.got .fi-text b { color: var(--accent); }
.first-item .fi-text small { font-size: 10.5px; opacity: 0.55; }

.pause-controls {
  margin-top: 22px;
  border-top: 1px solid var(--pm-line);
  padding-top: 16px;
}
.pause-controls summary {
  cursor: pointer;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--pm-text-dim);
}
.pause-controls summary i { font-style: normal; text-transform: none; letter-spacing: 0.06em; opacity: 0.6; margin-left: 4px; }
.pc-grid {
  margin-top: 14px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 24px;
  font-size: 12px;
  color: rgba(234, 242, 255, 0.7);
}
.pause-controls kbd {
  padding: 2px 6px;
  margin: 0 2px;
  font: 600 10.5px/1.4 "Segoe UI", system-ui, sans-serif;
  color: rgba(234, 242, 255, 0.85);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--pm-line);
  border-radius: 2px;
}
.credits-list {
  margin-top: 14px;
  max-height: 220px;
  overflow-y: auto;
  font-size: 11.5px;
  line-height: 1.6;
  color: rgba(234, 242, 255, 0.6);
}
.credits-list p {
  margin: 0 0 7px;
}
.credits-list b {
  color: rgba(234, 242, 255, 0.9);
  font-weight: 500;
}
.credits-hint {
  margin-top: 10px !important;
  opacity: 0.5;
  font-size: 11px;
}
/* Resume: outlined by default, fills with the accent only on hover/focus —
   a restrained primary action instead of a permanently glowing pill. */
#pause-resume {
  display: block;
  width: 100%;
  margin: 26px 0 0;
  padding: 13px 20px;
  font: 600 12px/1 "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg);
  background: transparent;
  border: 1px solid rgba(70, 198, 255, 0.5);
  border-radius: 2px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
#pause-resume i { font-style: normal; opacity: 0.65; margin-left: 6px; }
#pause-resume:hover,
#pause-resume:focus-visible {
  background: var(--accent);
  color: #05080d;
}
#pause-resume:hover i,
#pause-resume:focus-visible i { opacity: 0.65; }
.pause-hint {
  margin-top: 16px;
  text-align: center;
  font-size: 11px;
  opacity: 0.45;
}
.copyright-notice {
  margin-top: 8px;
  text-align: center;
  font-size: 10px;
  letter-spacing: 0.02em;
  opacity: 0.32;
  user-select: none;
}
.pause-hint kbd {
  padding: 2px 6px;
  margin: 0 2px;
  font: 600 10.5px/1.4 "Segoe UI", system-ui, sans-serif;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--pm-line);
  border-radius: 2px;
}

/* ---- On-screen cyclic (pitch/bank) thumbpad ---- */
#touch-cyclic {
  position: fixed;
  left: 50%;
  bottom: calc(clamp(20px, 5vh, 40px) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 7;
  display: none;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  background: rgba(10, 20, 32, 0.35);
  border: 1.5px solid rgba(255, 255, 255, 0.28);
  touch-action: none;
}
#cyclic-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 46px;
  height: 46px;
  margin-left: -23px;
  margin-top: -23px;
  border-radius: 50%;
  background: rgba(70, 198, 255, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.4);
  pointer-events: none;
}

/* Slightly tighter chrome on small screens. */
@media (max-width: 600px) {
  .letterbox { height: 5vh; }
}

/* On narrow screens the bottom-left legend and bottom-right gauges
   would collide — move the gauges up to the top-right, and shrink
   both the title and gauges so they share the top row without
   overlapping.

   ⚠️ The touch clause is NOT redundant. A phone can report a viewport far
   wider than it is (a browser in "desktop site" mode ignores the viewport
   meta and lays out at ~980px). Then every max-width rule here stayed OFF
   while the `pointer: coarse` rules stayed ON — desktop layout underneath
   the touch controls, which is exactly the pile-up a user reported from a
   real phone: measured 343x62 of the legend sitting on the gauges, 128x62
   of the throttle buttons on the minimap, and the mode buttons on the
   title. So the compact layout keys off "is this a touch screen", not just
   "is this narrow". */
@media (max-width: 720px), (hover: none) and (pointer: coarse) {
  #readout {
    top: calc(7vh + clamp(14px, 3vh, 28px));
    bottom: auto;
    gap: 10px;
    max-width: 44vw;
  }
  #readout {
    /* The row must never run off the right edge on a small screen: it is
       nowrap by default and its content is wider than 44vw. */
    flex-wrap: wrap;
    justify-content: flex-end;
    row-gap: 6px;
  }
  #readout .gauge b { font-size: 18px; }
  #readout .gauge small,
  #readout .thr small,
  #readout .thr-num small { font-size: 12px; letter-spacing: 0.1em; }
  #readout .thr-bar { width: 58px; }
  #readout .thr-num b { font-size: 18px; }
  #readout .thr-track { width: 10px; height: 38px; }

  /* The gauges just moved to the top-right, so the corner below is free
     again — drop the minimap back down to its own margin. */
  #minimap {
    bottom: calc(clamp(64px, 12vh, 96px) + env(safe-area-inset-bottom, 0px));
  }

  /* A narrow window cannot fit two maps side by side: at 393px wide the pair
     spans ~216px and the left one lands on the keyboard legend (measured 39x96
     of overlap). So on narrow screens the docking map STACKS above the minimap
     in the same right-hand column — the legend never reaches that column, and
     the gauges have moved to the top-right in this very block, so the band
     above the map is free. Touch LANDSCAPE puts it back beside the minimap
     (see the coarse block below): stacking there hits the throttle buttons
     instead, so the two cases genuinely want opposite answers. */
  #docking-map {
    right: calc(clamp(12px, 2vw, 22px) + env(safe-area-inset-right, 0px));
    bottom: calc(
      clamp(64px, 12vh, 96px) + var(--map-size) + var(--map-gap) +
      env(safe-area-inset-bottom, 0px)
    );
  }
  /* The map stacked ABOVE the minimap here, so the gauge takes the slot beside
     it rather than two slots in from the edge. */
  #hoist-alt {
    right: calc(
      clamp(12px, 2vw, 22px) + var(--map-size) + var(--map-gap) +
      env(safe-area-inset-right, 0px)
    );
    bottom: calc(
      clamp(64px, 12vh, 96px) + var(--map-size) + var(--map-gap) +
      env(safe-area-inset-bottom, 0px)
    );
  }

  #hud { max-width: 44vw; }
  #hud h1 { font-size: clamp(20px, 7vw, 34px); }
  #hud p { display: none; }

  #legend { font-size: 12px; }

  /* #camera-buttons is a flex row now (see the shared rule above), so the old
     per-button fixed `right` offsets that used to clip on a narrow window are
     gone entirely — the group just sizes to its real content. Only the
     smaller touch-friendly padding/font need to survive here. */
  #camera-buttons button {
    padding: 5px 8px;
    font-size: 11px;
    letter-spacing: 0.04em;
  }
}

/* ---- Touch layout: give the on-screen controls their own room -------------
   These only make sense where the touch controls are actually shown, so they
   key off the same query that reveals them. */
@media (hover: none) and (pointer: coarse) {
  /* The legend is a list of KEYBOARD shortcuts — there is no keyboard here,
     and it was the biggest offender in the pile-up (343x62 across the
     gauges). The onboarding radio lines still teach the touch controls. */
  #legend { display: none; }

  /* ...which frees the bottom-left, and the gauges need it: on a touch screen
     the top-right band belongs to the camera row, the mode row and the
     sound/help icons, and the gauges landed on top of all three (measured
     260x40, 121x26, 30x30). So they take the corner the legend just vacated,
     under the engine/reset buttons and left of the cyclic pad. */
  #readout {
    top: auto;
    bottom: calc(clamp(12px, 3vh, 24px) + env(safe-area-inset-bottom, 0px));
    left: calc(clamp(16px, 4vw, 40px) + env(safe-area-inset-left, 0px));
    right: auto;
    /* Must stop short of the centred cyclic pad, which starts at 50% - 55px —
       on a narrow screen that is the binding limit, not the 36vw one. */
    max-width: min(36vw, calc(50% - 72px), 320px);
    justify-content: flex-start;
  }

  /* The +/- throttle buttons own the right edge, so the map tucks into the
     corner BELOW them instead of underneath them (measured 128x62 of
     overlap), and shrinks so it never reaches back up into them. */
  #minimap {
    bottom: calc(clamp(12px, 3vh, 24px) + env(safe-area-inset-bottom, 0px));
    width: clamp(78px, min(13vw, 20vh), 120px);
    height: clamp(78px, min(13vw, 20vh), 120px);
  }

  /* Only --map-size needs restating: the `right` offset is written in terms of
     it, so the docking map both shrinks AND re-tucks beside the smaller
     minimap from this one line. */
  #docking-map {
    --map-size: clamp(78px, min(13vw, 20vh), 120px);
    --map-gap: 10px;
    /* Back BESIDE the minimap, undoing the narrow-screen stacking above: with
       the throttle buttons owning the right edge, a stacked map lands on them
       (measured 62x56 at 812x375), while beside is clear. */
    right: calc(
      clamp(12px, 2vw, 22px) + var(--map-size) + var(--map-gap) +
      env(safe-area-inset-right, 0px)
    );
    bottom: calc(clamp(12px, 3vh, 24px) + env(safe-area-inset-bottom, 0px));
  }
  #hoist-alt {
    --map-size: clamp(78px, min(13vw, 20vh), 120px);
    --map-gap: 10px;
    right: calc(
      clamp(12px, 2vw, 22px) + 2 * (var(--map-size) + var(--map-gap)) +
      env(safe-area-inset-right, 0px)
    );
    bottom: calc(clamp(12px, 3vh, 24px) + env(safe-area-inset-bottom, 0px));
  }
}

/* ---- Touch PORTRAIT: a supported layout, not a rejected one ---------------
   Portrait is how people hold a phone, so it has to work rather than be
   refused. It is a different problem from landscape: plenty of height, very
   little width, and the button rows wrap into tall stacks that landed on the
   title, the clock and the gauges (measured at 393x851: gauges ↔ cyclic 15x104,
   title ↔ mode buttons 140x34, clock ↔ mode buttons 115x30).
   The LOWER half of a portrait phone is entirely spoken for — engine/reset and
   yaw on the left, throttle on the right, the cyclic pad centred at the bottom —
   so the readouts are stacked DOWN THE TOP HALF instead, in bands, each anchored
   to the top so they cannot drift into the controls as the screen gets taller. */
@media (hover: none) and (pointer: coarse) and (orientation: portrait) {
  /* Band 1 is the title + clock (already there). Band 2: camera row — the
     general touch/narrow block above already shrinks these buttons; portrait
     only needs to drop the whole group below the taller title. */
  #camera-buttons {
    top: calc(7vh + clamp(100px, 13vh, 124px) + env(safe-area-inset-top, 0px));
  }
  /* Band 3: the mode row, wide enough to wrap into 2 rows, not 3. */
  #mode-buttons {
    top: calc(7vh + clamp(130px, 16vh, 178px) + env(safe-area-inset-top, 0px));
    /* Must not reach the right-hand column the map sits in on a wide screen. */
    max-width: min(80vw, 420px);
  }
  /* The map needs NO portrait override: the touch rule already parks it in the
     bottom-right corner below the throttle buttons, and in portrait the cyclic
     pad is centred far enough left to clear it. Tried a top-half band for it
     first — it fought the mode row on wide screens and the gauges on short
     ones, and the corner turned out to be free anyway. */

  /* The docking map DOES need a portrait override, unlike the minimap. Beside
     the minimap is fine in landscape but not here: portrait is narrow, so one
     map-width further left lands on the centred cyclic pad. STACKING it above
     the minimap was tried next and is worse — it runs straight into the
     throttle buttons (measured 62x56 of overlap), and the gap between the
     gauges band and that button stack is only ~60px on a real phone, so
     nothing map-sized fits there either.
     What IS free is the OPPOSITE bottom corner: the same "below the control
     clusters" band the minimap already occupies on the right, mirrored. The
     yaw pad and engine/reset buttons sit well above it and the cyclic pad is
     centred far enough right to clear it. */
  #docking-map {
    right: auto;
    left: calc(clamp(12px, 2vw, 22px) + env(safe-area-inset-left, 0px));
    bottom: calc(clamp(12px, 3vh, 24px) + env(safe-area-inset-bottom, 0px));
  }
  /* Portrait puts the map on the LEFT edge, so the gauge goes to its right. */
  #hoist-alt {
    right: auto;
    left: calc(
      clamp(12px, 2vw, 22px) + var(--map-size) + var(--map-gap) +
      env(safe-area-inset-left, 0px)
    );
    bottom: calc(clamp(12px, 3vh, 24px) + env(safe-area-inset-bottom, 0px));
  }

  /* Band 4: the gauges, centred and full width — there is no cyclic pad up
     here, so they need none of the narrow caps the landscape layout uses. */
  #readout {
    top: calc(7vh + clamp(230px, 32vh, 330px) + env(safe-area-inset-top, 0px));
    bottom: auto;
    /* Centred with auto margins, NOT `left: 50%` — with left:50% the containing
       block starts at the middle, so the available width is only half the
       screen and the six readouts wrapped into a tall block. */
    left: 0;
    right: 0;
    width: fit-content;
    margin-inline: auto;
    max-width: min(94vw, 480px);
    justify-content: center;
  }
}

/* Respect motion sensitivity: kill the infinite blinking warnings (engine
   status, sink-rate) without losing the state cue itself (still red/coloured). */
/* The old full-screen "rotate your device" wall lived here. It is gone: forcing
   the player to turn their phone is pressure, and portrait is how people hold a
   phone, so portrait is a supported layout now (see the portrait block above).
   The suggestion is a one-time toast from main.js — it fades by itself, blocks
   no input, and costs no layout. */

@media (prefers-reduced-motion: reduce) {
  #engine-status,
  #hud-alt.sink-warning {
    animation: none;
  }
}

/* ---- Opening story intro (item 45) --------------------------------------
   A camera-only sequence: no cards, no panels — just the world, a subtitle
   line, and a skip hint. `pointer-events: none` throughout, because the skip
   is bound to ANY key or click on the canvas (js/main.js) and this overlay
   must never be the thing that swallows it.

   The soft top/bottom shading is deliberately a gradient rather than hard
   letterbox bars: bars would crop the ruined city's rooflines out of shots 1
   and 2, which are the whole reason this sequence exists. */
#intro-overlay {
  position: fixed;
  inset: 0;
  z-index: 22; /* above the chapter card (21) — the intro precedes everything */
  display: none;
  pointer-events: none;
}
body.intro-play #intro-overlay { display: block; }
#intro-overlay::before,
#intro-overlay::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 18vh;
  pointer-events: none;
}
#intro-overlay::before {
  top: 0;
  background: linear-gradient(to bottom, rgba(2, 5, 10, 0.72), rgba(2, 5, 10, 0));
}
#intro-overlay::after {
  bottom: 0;
  background: linear-gradient(to top, rgba(2, 5, 10, 0.82), rgba(2, 5, 10, 0));
}
/* Three more elements the shared dev-clean list deliberately does NOT hide, and
   the intro must: the engine prompt (the player cannot fly yet, so "PRESS E TO
   START ENGINE" over the story is just wrong), and the DEV / clean-view buttons
   — dev mode keeps those two on purpose, since they are how you leave it. */
body.intro-play #engine-status,
body.intro-play #camera-buttons,
body.intro-play #clean-view-btn { display: none !important; }

#intro-sub {
  position: absolute;
  left: 50%;
  bottom: 13vh;
  transform: translateX(-50%);
  width: min(88vw, 760px);
  text-align: center;
  font-size: clamp(16px, 2.4vw, 25px);
  line-height: 1.6;
  color: #f2f6fb;
  /* Read over ANY frame — a bright dusk sky in shot 3, near-black ruins in
     shot 2 — without a panel behind it. */
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.95), 0 0 3px rgba(0, 0, 0, 0.9);
  opacity: 0; /* driven per frame from IntroSequence.lineAlpha */
}
#intro-skip {
  position: absolute;
  right: 22px;
  bottom: 20px;
  font-size: 12px;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.5);
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.9);
}
@media (max-width: 720px) {
  #intro-skip { right: 14px; bottom: 14px; font-size: 11px; }
  #intro-sub { bottom: 16vh; }
}
