/* ============================================================
   Cosmic stage: sticky, pinned, driven by --progress
   ============================================================ */

.stage {
  position: sticky;
  top: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  z-index: 1;
  isolation: isolate;
  pointer-events: none;
  background: #000;
}

/* Sky: full-bleed gradient, colour set live via JS */
.sky {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    var(--sky-top, #05070f) 0%,
    var(--sky-mid, #0a0f1f) 55%,
    var(--sky-bottom, #1a1a24) 100%
  );
  transition: background 200ms linear;
  will-change: background;
}

/* Warm horizon glow — strongest at launchpad, fades as we climb.
   Two stacked layers:
     1) A hot orange/magenta rim right at ground level (pre-dawn ignition glow)
     2) A cool violet/indigo atmospheric-scattering band just above it */
.sky::after {
  content: "";
  position: absolute;
  inset: auto 0 -10% 0;
  height: 70%;
  background:
    radial-gradient(
      ellipse at 50% 100%,
      rgba(255, 110, 35, calc(0.55 * var(--launchpad-opacity, 1))) 0%,
      rgba(235, 60, 30, calc(0.22 * var(--launchpad-opacity, 1))) 18%,
      rgba(150, 40, 60, calc(0.10 * var(--launchpad-opacity, 1))) 34%,
      transparent 58%
    ),
    radial-gradient(
      ellipse at 50% 92%,
      rgba(85, 80, 180, calc(0.18 * var(--launchpad-opacity, 1))) 20%,
      rgba(40, 50, 120, calc(0.10 * var(--launchpad-opacity, 1))) 40%,
      transparent 70%
    );
  pointer-events: none;
}

/* Starfield canvas (stars drawn by stage.js) */
.starfield {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: var(--stars-opacity, 0);
  transition: opacity 260ms linear;
  mix-blend-mode: screen;
}

/* Earth: a giant circle placed below the viewport. As progress increases, it
   rises (the reader climbs) and then recedes (the reader leaves orbit). */
.earth {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 240vh;
  height: 240vh;
  transform: translate(-50%, -50%) translateY(var(--earth-y, 280vh))
    scale(var(--earth-scale, 1.2));
  transform-origin: 50% 50%;
  will-change: transform;
  filter: drop-shadow(0 -30px 80px rgba(58, 140, 255, 0.12));
}

.earth-land {
  transform-origin: 0 0;
  animation: earthSpin 420s linear infinite;
}
@keyframes earthSpin {
  to {
    transform: rotate(360deg);
  }
}

/* Orbital rings — share Earth's transform so they always hug the planet */
.orbits {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 240vh;
  height: 240vh;
  transform: translate(-50%, -50%) translateY(var(--earth-y, 280vh))
    scale(var(--earth-scale, 1.2));
  transform-origin: 50% 50%;
  opacity: var(--orbits-opacity, 0);
  transition: opacity 300ms linear;
  pointer-events: none;
}
.orbit {
  stroke: rgba(125, 249, 255, 0.32);
  stroke-width: 2.2;
  stroke-dasharray: 6 10;
  fill: none;
}
.orbit-1 {
  stroke-dasharray: 4 8;
  stroke: rgba(125, 249, 255, 0.45);
}
.orbit-2 {
  stroke-dasharray: 6 10;
}
.orbit-3 {
  stroke-dasharray: 2 14;
  stroke: rgba(255, 255, 255, 0.22);
}
.orbit-4 {
  stroke-dasharray: 1 16;
  stroke: rgba(255, 107, 43, 0.32);
}

/* Satellites injected by the actors scene */
.sats circle {
  transition: opacity 200ms linear;
}

/* Rocket: scales up, translates up, sways subtly */
.rocket {
  /* Size the rocket and anchor it by its *engine nozzle* so it never floats.
     viewBox is `-80 -220 160 500`; the nozzle exit sits at y=140. That
     puts the nozzle 140 units from the viewBox bottom (y=280), i.e. 28%
     up from the SVG element's bottom edge (140/500 = 0.28) and 72% down
     from its top (360/500 = 0.72). The SVG's intrinsic aspect ratio is
     500/160 = 3.125, so the nozzle-to-SVG-bottom distance in pixels is
     0.28 × 3.125 × width ≈ 0.875 × width. To park the nozzle exactly on
     the pad (`bottom: 8vh`), the SVG element's bottom must sit at
     `bottom: 8vh − 0.875 × width`. The flame then naturally hangs just
     below pad level — straight into the flame trench. */
  --rocket-width: clamp(170px, 20vw, 290px);
  position: absolute;
  left: 50%;
  bottom: calc(8vh - 0.875 * var(--rocket-width));
  width: var(--rocket-width);
  height: auto;
  transform: translate3d(
      calc(-50% + var(--rocket-x, 0px)),
      var(--rocket-y, 0px),
      0
    )
    scale(var(--rocket-scale, 1)) rotate(var(--rocket-rot, 0deg));
  /* Scale around the nozzle (72% down from the top of the SVG element)
     so shrinking/growing the rocket doesn't lift it off the pad. */
  transform-origin: 50% 72%;
  filter:
    drop-shadow(0 0 60px rgba(255, 107, 43, calc(0.8 * var(--thrust, 0))))
    drop-shadow(0 0 16px rgba(255, 180, 80, calc(0.4 * var(--thrust, 0))))
    drop-shadow(0 14px 36px rgba(0, 0, 0, 0.45));
  will-change: transform;
  opacity: calc(var(--rocket-opacity, 1) * (1 - var(--cluster-mix, 0)));
  transition: opacity 320ms var(--ease-out);
}

/* Subtle hull shake tied to --rocket-shake (0..1) */
.rocket {
  animation: rocketShake 100ms linear infinite;
  animation-play-state: paused;
}
.rocket[data-shaking="1"] {
  animation-play-state: running;
}
@keyframes rocketShake {
  0% {
    filter: drop-shadow(0 12px 30px rgba(255, 107, 43, 0.35))
      translate3d(0, 0, 0);
  }
  50% {
    filter: drop-shadow(0 12px 34px rgba(255, 107, 43, 0.5))
      translate3d(0.6px, -0.6px, 0);
  }
  100% {
    filter: drop-shadow(0 12px 30px rgba(255, 107, 43, 0.35))
      translate3d(-0.6px, 0.6px, 0);
  }
}

/* -------------------- Rocket exhaust plume -------------------- */
/* The flame is a multi-layered SVG group. Each layer flickers on its own
   rhythm; the whole group scales with --thrust so it surges on ignition. */
.rocket-flame {
  transform-origin: 0px 135px;
  transform: scaleY(calc(var(--thrust, 0) * 1.2)) scaleX(calc(0.6 + 0.5 * var(--thrust, 0)));
  opacity: var(--thrust, 0);
  transition: opacity 120ms linear;
}
.plume-smoke {
  animation: plumeDrift 2.2s ease-in-out infinite;
  transform-origin: 0 140px;
}
.plume-outer {
  animation: flicker 140ms steps(2) infinite, plumePulse 900ms ease-in-out infinite;
  transform-origin: 0 135px;
  mix-blend-mode: screen;
}
.plume-mid {
  animation: flicker 110ms steps(2) infinite reverse, plumePulse 700ms ease-in-out infinite;
  transform-origin: 0 135px;
  mix-blend-mode: screen;
}
.plume-core {
  animation: flickerFast 90ms steps(2) infinite, plumePulse 500ms ease-in-out infinite;
  transform-origin: 0 135px;
  mix-blend-mode: screen;
}
.plume-diamonds {
  animation: diamondsPulse 260ms ease-in-out infinite;
  transform-origin: 0 135px;
}
.bell-halo {
  opacity: calc(var(--thrust, 0) * 0.9);
  animation: bellPulse 380ms ease-in-out infinite;
  transform-origin: 0 138px;
}
@keyframes flicker {
  0%, 100% { transform: scaleX(1) scaleY(1); }
  50%      { transform: scaleX(1.06) scaleY(0.97); }
}
@keyframes flickerFast {
  0%, 100% { transform: scaleX(1) scaleY(1); }
  50%      { transform: scaleX(0.94) scaleY(1.05); }
}
@keyframes plumePulse {
  0%, 100% { opacity: 0.92; }
  50%      { opacity: 1; }
}
@keyframes diamondsPulse {
  0%, 100% { opacity: 0.7; transform: translateY(0); }
  50%      { opacity: 1;   transform: translateY(-2px); }
}
@keyframes plumeDrift {
  0%, 100% { transform: translateY(0) scaleY(1);   opacity: 0.85; }
  50%      { transform: translateY(6px) scaleY(1.08); opacity: 0.55; }
}
@keyframes bellPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.15); }
}

/* -------------------- Satellite cluster (> 1000 km) -------------------- */
.cluster {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(260px, 34vw, 520px);
  height: auto;
  transform: translate3d(
      calc(-50% + var(--rocket-x, 0px)),
      calc(-50% + var(--cluster-y, 0px)),
      0
    )
    scale(var(--cluster-scale, 1)) rotate(var(--cluster-rot, 0deg));
  transform-origin: 50% 50%;
  opacity: var(--cluster-mix, 0);
  filter:
    drop-shadow(0 0 40px rgba(125, 249, 255, calc(0.25 * var(--cluster-mix, 0))))
    drop-shadow(0 10px 40px rgba(0, 0, 0, 0.5));
  pointer-events: none;
  transition: opacity 600ms var(--ease-out);
  will-change: transform, opacity;
}
/* Slow hub breathing rotation so the cluster feels alive */
.sat-hub {
  animation: hubSpin 60s linear infinite;
  transform-origin: 0 0;
}
.sat-wings {
  animation: wingsFlex 8s ease-in-out infinite;
  transform-origin: 0 0;
}
@keyframes hubSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@keyframes wingsFlex {
  0%, 100% { transform: scaleX(1); }
  50%      { transform: scaleX(0.995); }
}

/* Companion satellites drift gently on their own orbits */
.sat-a { animation: satDriftA 14s ease-in-out infinite; }
.sat-b { animation: satDriftB 17s ease-in-out infinite; }
.sat-c { animation: satDriftC 15s ease-in-out infinite; }
.sat-d { animation: satDriftD 18s ease-in-out infinite; }
@keyframes satDriftA {
  0%, 100% { transform: translate(-150px, -95px) rotate(0deg); }
  50%      { transform: translate(-160px, -105px) rotate(4deg); }
}
@keyframes satDriftB {
  0%, 100% { transform: translate(155px, -70px) rotate(0deg); }
  50%      { transform: translate(165px, -60px) rotate(-3deg); }
}
@keyframes satDriftC {
  0%, 100% { transform: translate(130px, 105px) rotate(0deg); }
  50%      { transform: translate(120px, 115px) rotate(3deg); }
}
@keyframes satDriftD {
  0%, 100% { transform: translate(-135px, 95px) rotate(0deg); }
  50%      { transform: translate(-145px, 85px) rotate(-4deg); }
}

/* Data-link pulses: dashes flow along each link */
.cluster-links line {
  stroke-dashoffset: 0;
  animation: linkFlow 2s linear infinite;
}
.cluster-links .link-2 { animation-duration: 2.6s; }
.cluster-links .link-3 { animation-duration: 2.3s; }
.cluster-links .link-4 { animation-duration: 3.1s; }
@keyframes linkFlow {
  to { stroke-dashoffset: -14; }
}

/* Rack data bars shimmer */
.sat-hub rect[fill="url(#rackGlow)"] {
  animation: rackShimmer 3s ease-in-out infinite;
}
.sat-hub rect[fill="url(#rackGlow)"]:nth-of-type(2n) { animation-delay: 0.4s; }
.sat-hub rect[fill="url(#rackGlow)"]:nth-of-type(3n) { animation-delay: 0.9s; }
@keyframes rackShimmer {
  0%, 100% { opacity: 0.5; }
  50%      { opacity: 0.95; }
}

/* LED blinks */
.led-1 { animation: ledBlink 1.8s ease-in-out infinite; }
.led-2 { animation: ledBlink 1.4s ease-in-out infinite 0.6s; }
@keyframes ledBlink {
  0%, 40%, 100% { opacity: 0.4; }
  45%, 60%      { opacity: 1; }
}

/* -------------------- Launchpad scene -------------------- */
/* The pad is split in two layers that both fade together via --launchpad-opacity:
     .launchpad-bg  – horizon, mountains, ground, pad disc, service tower.
                      Painted BEFORE the rocket so the body shows cleanly.
     .launchpad-fg  – umbilical arms, hold-down clamps, vapour.
                      Painted AFTER the rocket so the arms visibly latch onto it
                      and swing away at release (--pad-release drives retraction).
*/
.launchpad {
  position: absolute;
  inset: auto 0 0 0;
  height: 52vh;
  opacity: var(--launchpad-opacity, 1);
  transition: opacity 500ms var(--ease-out);
  pointer-events: none;
  will-change: opacity, transform;
}
.launchpad-bg {
  /* Subtle sink as it fades so the ground feels like it's falling behind */
  transform: translateY(calc((1 - var(--launchpad-opacity, 1)) * 22px));
}
.launchpad-fg {
  /* The foreground does NOT sink — it stays with the rocket until release */
  transform: none;
}

/* Warm pre-dawn glow layered over the pad (adds atmosphere) */
.launchpad-bg::before {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 100%;
  background:
    radial-gradient(
      ellipse at 50% 100%,
      rgba(255, 120, 40, 0.18) 0%,
      rgba(180, 80, 30, 0.08) 30%,
      transparent 65%
    ),
    linear-gradient(
      to bottom,
      rgba(8, 10, 18, 0) 0%,
      rgba(12, 14, 22, 0.55) 35%,
      rgba(10, 12, 18, 0.92) 70%,
      #05070c 100%
    );
  pointer-events: none;
}

/* Ground plane: subtle concrete texture + horizon rim light */
.launchpad-bg::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  bottom: 0;
  height: 14vh;
  background:
    linear-gradient(
      to bottom,
      rgba(22, 20, 24, 0) 0%,
      rgba(24, 22, 28, 0.55) 35%,
      #0a0a12 100%
    );
  box-shadow: inset 0 1px 0 rgba(255, 120, 40, 0.18);
}

/* Distant mountain silhouettes along the horizon */
.pad-mountains {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 14vh;
  width: 100%;
  height: 12vh;
  opacity: 0.95;
  pointer-events: none;
}

/* Tiny distant lights on the horizon (beacons / airfields / other infrastructure) */
.pad-horizon-lights {
  position: absolute;
  left: 0; right: 0;
  bottom: 15vh;
  height: 4px;
  pointer-events: none;
}
.pad-horizon-lights span {
  position: absolute;
  top: 0;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: #ffc89a;
  box-shadow: 0 0 6px rgba(255, 180, 100, 0.8);
  animation: horizonBlink 3.2s ease-in-out infinite;
}
.pad-horizon-lights span:nth-child(2n) { animation-delay: 1s; background: #ff9058; }
.pad-horizon-lights span:nth-child(3n) { animation-delay: 2s; }
@keyframes horizonBlink {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 1; }
}

/* Concrete pad disc under the rocket.
   Intentionally short and thin so it never covers the rocket body — think
   "the rocket is STANDING on this disc" rather than "the disc is wrapped
   around the rocket". Sits at pad level (8vh) with a thin rim light. */
.pad-base {
  position: absolute;
  left: calc(50% + var(--pad-tower-x, 0px));
  bottom: calc(8vh - 6px);
  width: clamp(180px, 22vw, 340px);
  height: clamp(12px, 1.5vw, 22px);
  transform: translateX(-50%);
  background:
    radial-gradient(
      ellipse at 50% 50%,
      #2a2d36 0%,
      #15171e 50%,
      #0a0c12 80%,
      transparent 100%
    );
  border-radius: 50%;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    inset 0 -1px 0 rgba(255, 120, 40, 0.25),
    0 0 40px rgba(255, 120, 40, calc(0.3 * var(--thrust, 0)));
}

/* Flame trench: a dark glowing slot in the pad disc that lights up on ignition */
.pad-trench {
  position: absolute;
  left: calc(50% + var(--pad-tower-x, 0px));
  bottom: calc(8vh - 10px);
  width: clamp(40px, 5vw, 70px);
  height: 10px;
  transform: translateX(-50%);
  background:
    radial-gradient(
      ellipse at 50% 50%,
      rgba(255, 200, 120, calc(0.95 * var(--thrust, 0))) 0%,
      rgba(255, 110, 40, calc(0.7 * var(--thrust, 0))) 40%,
      rgba(12, 10, 16, 0.9) 80%
    );
  border-radius: 50%;
  filter: blur(0.5px);
  box-shadow: 0 0 30px rgba(255, 120, 40, calc(0.8 * var(--thrust, 0)));
}

/* Service tower / gantry (SVG) */
.pad-tower {
  position: absolute;
  left: calc(50% + var(--pad-tower-x, 0px) + clamp(80px, 9vw, 140px));
  bottom: 8vh;
  width: clamp(80px, 9vw, 140px);
  height: clamp(180px, 28vh, 320px);
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.55));
}

/* Red aviation warning beacon on top of the tower */
.tower-beacon {
  animation: beacon 1.8s ease-in-out infinite;
  filter: drop-shadow(0 0 4px #ff3b20);
}
@keyframes beacon {
  0%, 30%, 100% { opacity: 0.25; }
  40%, 55%      { opacity: 1; }
}

/* Amber work lights along the gantry — slow pulse, staggered */
.tower-lamp {
  filter: drop-shadow(0 0 3px #ffb37a);
  animation: lampPulse 4s ease-in-out infinite;
}
.lamp-a { animation-delay: 0s; }
.lamp-b { animation-delay: 0.6s; }
.lamp-c { animation-delay: 1.2s; }
.lamp-d { animation-delay: 1.8s; }
.lamp-e { animation-delay: 2.4s; }
@keyframes lampPulse {
  0%, 100% { opacity: 0.65; }
  50%      { opacity: 1; }
}

/* -------------------- Umbilical service arms -------------------- */
/* Three steel pipes reach from the service tower and visibly latch onto the
   rocket body. At release (--pad-release 0 → 1) they swing upward around
   their tower-side pivot and detach — a cinematic "T‑0" moment.

   Geometry: the tower's inner edge sits at approximately
     `50% + pad-tower-x + clamp(70px, 8vw, 105px)`
   (inner edge = tower center − half its width). The arms' anchor lives at
   that x, and each arm extends leftward to reach the rocket body. */
.pad-umbilicals {
  position: absolute;
  /* Anchor at the tower CENTER (= tower-left + half tower-width). Because
     the tower's internal SVG uses preserveAspectRatio and may have padding
     on the sides, anchoring at the centre guarantees each arm *passes
     through* the lattice and visually emerges from it. */
  left: calc(
    50% + var(--pad-tower-x, 0px)
      + clamp(80px, 9vw, 140px)           /* tower left edge offset from rocket */
      + clamp(40px, 4.5vw, 70px)          /* half the tower width → centre */
  );
  bottom: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

/* Each arm is a thin horizontal bar. It grows leftward from its
   right-edge pivot, so transform: rotate() swings the free (rocket) end
   upward on release. */
.umbilical {
  position: absolute;
  right: 0;
  display: block;
  height: 3px;
  background: linear-gradient(
    to left,
    #353b48 0%,
    #2a3040 40%,
    #1b2030 100%
  );
  border-radius: 2px;
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.6),
    inset 0 0.5px 0 rgba(255, 255, 255, 0.08);
  transform-origin: 100% 50%;
  transform: rotate(calc(var(--pad-release, 0) * -62deg));
  transition: transform 700ms var(--ease-spring);
  /* Arms live at heights where they can convincingly touch the hull */
  width: calc(var(--arm-reach, 100px));
}
.umbilical::before {
  /* a faint second line below each pipe = bundled fuel/fluid lines */
  content: "";
  position: absolute;
  right: 2px;
  left: 10%;
  top: 4px;
  height: 1px;
  background: rgba(130, 140, 160, 0.55);
}
.umbilical-head {
  /* The "latch plate" that actually touches the rocket hull */
  position: absolute;
  left: -3px;
  top: -3px;
  width: 8px;
  height: 9px;
  background: linear-gradient(to bottom, #4a5060, #2a2f3a);
  border-radius: 1.5px;
  box-shadow:
    0 0 4px rgba(125, 249, 255, calc(0.55 * (1 - var(--pad-release, 0)))),
    0 1px 2px rgba(0, 0, 0, 0.5);
}

/* Three arms at varying heights and reaches. Heights are chosen so
   each arm intersects the rocket HULL (not the nose or engine bell)
   when the rocket is at its initial scaled size. */
/* Arm length spans from the tower centre all the way to the rocket hull.
   Rocket-to-tower-centre distance = clamp(80,9vw,140) + clamp(40,4.5vw,70)
   ≈ 1.5× the tower-offset clamp. Subtract a few px so the latch head lands
   just ON the hull (fg layer draws it on top of the rocket). */
.umbilical-top {
  bottom: calc(8vh + clamp(140px, 17vw, 230px));
  --arm-reach: calc(
    clamp(80px, 9vw, 140px) + clamp(40px, 4.5vw, 70px) - 10px
  );
}
.umbilical-mid {
  bottom: calc(8vh + clamp(85px, 10vw, 145px));
  --arm-reach: calc(
    clamp(80px, 9vw, 140px) + clamp(40px, 4.5vw, 70px) - 6px
  );
}
.umbilical-low {
  bottom: calc(8vh + clamp(38px, 4.5vw, 70px));
  --arm-reach: calc(
    clamp(80px, 9vw, 140px) + clamp(40px, 4.5vw, 70px) - 4px
  );
}

/* Slightly different retract angles per arm for a staggered, organic feel */
.umbilical-top { transition-delay: 60ms; transform: rotate(calc(var(--pad-release, 0) * -72deg)); }
.umbilical-mid { transition-delay: 0ms;  transform: rotate(calc(var(--pad-release, 0) * -58deg)); }
.umbilical-low { transition-delay: 120ms;transform: rotate(calc(var(--pad-release, 0) * -82deg)); }

/* -------------------- Hold-down clamps -------------------- */
/* Two heavier struts gripping the lower hull. They retract (drop) on release. */
.pad-clamps {
  position: absolute;
  left: calc(50% + var(--rocket-x, 0px));
  bottom: calc(8vh - 2px);
  width: 52px;
  height: 26px;
  transform: translateX(-50%);
  pointer-events: none;
}
.clamp {
  position: absolute;
  bottom: 0;
  width: 5px;
  height: 22px;
  background:
    linear-gradient(to top, #1a1e28 0%, #3a4050 60%, #2a2f3a 100%);
  border-radius: 1px;
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.7),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
  transform-origin: 50% 100%;
  transition: transform 500ms var(--ease-spring);
}
.clamp::after {
  /* a small "pad" at the top where the clamp meets the rocket */
  content: "";
  position: absolute;
  top: -2px;
  left: -3px;
  width: 11px;
  height: 4px;
  background: #4a5060;
  border-radius: 1px;
}
.clamp-l {
  left: 6px;
  transform:
    rotate(calc(-14deg + var(--pad-release, 0) * -32deg))
    translateY(calc(var(--pad-release, 0) * 6px));
}
.clamp-r {
  right: 6px;
  transform:
    rotate(calc(14deg + var(--pad-release, 0) * 32deg))
    translateY(calc(var(--pad-release, 0) * 6px));
}

/* -------------------- Cryogenic vapour -------------------- */
/* Pre-ignition venting from the rocket flanks. Fades out once
   engines light up (thrust > 0) AND once release begins. */
.pad-vapor {
  position: absolute;
  left: calc(50% + var(--rocket-x, 0px));
  bottom: calc(8vh + 8px);
  width: 180px;
  height: 80px;
  transform: translateX(-50%);
  pointer-events: none;
  opacity: calc(max(0, 1 - var(--thrust, 0) - var(--pad-release, 0) * 0.6));
  transition: opacity 400ms linear;
}
.vapor {
  position: absolute;
  bottom: 0;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(220, 230, 245, 0.55) 0%,
    rgba(200, 210, 230, 0.25) 40%,
    rgba(180, 195, 220, 0) 75%
  );
  filter: blur(2px);
  animation: vaporRise 4.5s ease-out infinite;
}
.vapor.v1 { left: 10%;  animation-delay: 0s;    transform: scale(0.9); }
.vapor.v2 { left: 34%;  animation-delay: 1.1s;  transform: scale(1.1); }
.vapor.v3 { left: 58%;  animation-delay: 2.2s;  transform: scale(1);   }
.vapor.v4 { left: 78%;  animation-delay: 3.3s;  transform: scale(0.85);}
@keyframes vaporRise {
  0%   { transform: translateY(0)     scale(0.8); opacity: 0; }
  20%  { opacity: 0.7; }
  100% { transform: translateY(-60px) scale(1.6); opacity: 0; }
}

/* Altitude HUD — top-right, floats above all scene content */
.hud {
  position: fixed;
  z-index: 20;
  top: clamp(1rem, 2.4vw, 2rem);
  right: clamp(1rem, 3vw, 2.4rem);
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.85rem;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--panel);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  color: var(--cyan);
  text-transform: uppercase;
  pointer-events: auto;
}
.hud-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--ignition);
  box-shadow: 0 0 10px var(--ignition);
  animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.55; transform: scale(0.75); }
}

/* Scroll hint (visible only during liftoff) */
.scroll-hint {
  position: relative;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin-top: clamp(5rem, 16vh, 12rem);
  padding-top: 1.4rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-dim);
  opacity: var(--hint-opacity, 1);
  transition: opacity 600ms var(--ease-out);
  pointer-events: none;
  align-self: center; /* center in the flex column even on left-aligned wide layout */
}
.scroll-hint-arrow {
  font-family: var(--sans);
  font-size: 1.2rem;
  animation: bob 1.6s ease-in-out infinite;
}
@keyframes bob {
  0%, 100% { transform: translateY(0); opacity: 0.6; }
  50% { transform: translateY(4px); opacity: 1; }
}

@media (max-width: 720px) {
  .rocket {
    --rocket-width: 90px;
  }
  .hud {
    font-size: 0.7rem;
    padding: 0.4rem 0.7rem;
  }
}
