/* ==========================================================================
   hero.css — the interactive 3D hero and the two-track entry beneath it.
   ========================================================================== */

.hero {
  position: relative;
  min-height: min(94vh, 940px);
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding-block: clamp(56px, 7vw, 96px) clamp(24px, 3vw, 40px);
  overflow: clip;
}

/* --- Stage ------------------------------------------------------------- */
/* The scrubber and node readout are absolutely placed against the hero's
   bottom edge, so a hero that carries them reserves flow space for them —
   without it they land on the CTA row on shorter windows. */
.hero:has(.scrub), .hero:has(.readout), .hero:has(.tiers) { padding-bottom: 190px; }
.hero__stage { position: absolute; inset: 0; z-index: 0; }
.hero__canvas { width: 100%; height: 100%; display: block; cursor: grab; touch-action: none; }
.hero__canvas:active { cursor: grabbing; }
.hero__stage::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 80% at 50% 110%, transparent 30%, rgba(5,9,18,0.65) 100%),
    linear-gradient(180deg, rgba(5,9,18,0.55) 0%, transparent 32%, transparent 62%, rgba(5,9,18,0.9) 100%);
}

/* --- HUD overlay ------------------------------------------------------- */
/* Readout of what the scene is currently showing, updated from the same
   animation frame that renders the canvas so the numbers never drift ahead of
   (or behind) the visual. It reports the mode the cards below it select, so it
   shares their rail and their width — on the left it sat over the headline.
   pointer-events: none so it never intercepts drag on the canvas beneath. */
.hero__rail {
  position: absolute;
  z-index: 3;
  top: clamp(24px, 5vw, 64px);
  right: var(--gutter);
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  width: min(300px, 42vw);
}
.hud {
  position: static;
  width: 100%;
  display: grid;
  gap: 4px var(--s-4);
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--glass-stroke-1);
  border-radius: var(--r-md);
  background: rgba(8,13,26,0.5);
  backdrop-filter: blur(var(--glass-blur-md));
  -webkit-backdrop-filter: blur(var(--glass-blur-md));
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  pointer-events: none;
  /* Wide enough to host "Coverage" / altitudes like "1,234 m" without the
     value track collapsing back into the key column. */
  min-width: 240px;
}
.hud__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-4);
  min-width: 0;
}
.hud__row--mode .hud__v { color: var(--accent); }
.hud__k { color: var(--fg-4); font-size: 9.5px; letter-spacing: 0.18em; white-space: nowrap; }
.hud__v { color: var(--fg-1); font-size: 11.5px; font-feature-settings: "tnum" 1, "lnum" 1; white-space: nowrap; text-align: right; }

/* Loading state before WebGL takes over. */
.hero__stage[data-ready="false"] .hero__boot { opacity: 1; }

/* No-WebGL fallback. When three.js can't load (blocked CDN, no GL context) the
   canvas is an empty void, so the stage paints its own contour-topo backdrop —
   the same mint-on-night reading as the shader's 01 layer, held still. */
.hero__stage[data-ready="failed"] .hero__canvas { display: none; }
.hero__stage[data-ready="failed"] {
  background-color: #050912;
  background-image:
    repeating-radial-gradient(closest-side at 42% 68%,
      rgba(52,230,154,0.24) 0 1px, transparent 1px 26px),
    repeating-radial-gradient(closest-side at 74% 44%,
      rgba(52,230,154,0.15) 0 1px, transparent 1px 34px),
    radial-gradient(120% 90% at 40% 78%, rgba(52,230,154,0.16) 0%, transparent 58%),
    radial-gradient(90% 70% at 78% 30%, rgba(74,178,255,0.14) 0%, transparent 62%),
    linear-gradient(180deg, #071023 0%, #050912 70%);
  background-size: 190% 150%, 150% 130%, auto, auto, auto;
  background-position: 30% 80%, 76% 36%, center, center, center;
}
.hero__stage[data-ready="failed"] .hero__boot { opacity: 0; }

/* The three modes stay switchable without WebGL: each paints its own still
   backdrop, so pressing a card still changes the hero. The buttons are NEVER
   disabled — a dead control row reads as a broken page. */
.hero__stage[data-ready="failed"][data-mode="1"] {
  background-image:
    radial-gradient(circle at 50% 50%, rgba(255,138,31,0.85) 0 4px, transparent 5px),
    radial-gradient(circle at 34% 61%, rgba(52,230,154,0.85) 0 4px, transparent 5px),
    radial-gradient(circle at 62% 37%, rgba(142,214,255,0.85) 0 4px, transparent 5px),
    radial-gradient(circle at 71% 66%, rgba(94,245,173,0.85) 0 4px, transparent 5px),
    radial-gradient(circle at 20% 30%, rgba(216,120,255,0.85) 0 4px, transparent 5px),
    repeating-radial-gradient(closest-side at 42% 68%,
      rgba(52,230,154,0.10) 0 1px, transparent 1px 26px),
    linear-gradient(180deg, #071023 0%, #050912 70%);
  background-size: auto, auto, auto, auto, auto, 190% 150%, auto;
  background-position: center, center, center, center, center, 30% 80%, center;
}
.hero__stage[data-ready="failed"][data-mode="2"] {
  background-image:
    repeating-radial-gradient(circle at 50% 54%,
      rgba(74,178,255,0.20) 0 1px, transparent 1px 58px),
    radial-gradient(circle at 50% 54%, rgba(52,230,154,0.16) 0 22%, transparent 24%),
    radial-gradient(circle at 50% 54%, rgba(255,138,31,0.10) 0 46%, transparent 48%),
    linear-gradient(180deg, #071023 0%, #050912 70%);
  background-size: auto, auto, auto, auto;
  background-position: center, center, center, center;
}

/* Without the scene the scrubber has nothing to drive, and the readout has no
   node to report on. Both go; the note explains why. */
.hero:has(.hero__stage[data-ready="failed"]) .scrub,
.hero:has(.hero__stage[data-ready="failed"]) .readout,
.hero:has(.hero__stage[data-ready="failed"]) .tiers { display: none; }
.hero__degraded { display: none; }
.hero:has(.hero__stage[data-ready="failed"]) .hero__degraded {
  display: block;
  position: absolute;
  z-index: 3;
  left: var(--gutter);
  bottom: var(--s-6);
  max-width: 420px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  line-height: 1.6;
  color: var(--fg-4);
}
.hero__boot {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-4) var(--ease-out);
  font-family: var(--font-mono);
  font-size: var(--t-overline);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--fg-4);
}

/* --- Copy ------------------------------------------------------------- */
.hero__inner { position: relative; z-index: 2; width: 100%; }
.hero__copy { max-width: 21ch; }
.hero__title { margin-bottom: var(--s-6); }
.hero__title .accent-italic { display: block; }
.hero__lede { max-width: 46ch; color: var(--fg-2); margin-bottom: var(--s-8); }

/* --- Mode switch: the three views of the same terrain ----------------- */
/* Positioned by .hero__rail, which it shares with the HUD. */
.modes {
  position: static;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.mode {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: 12px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--glass-stroke-1);
  background: rgba(8,13,26,0.5);
  backdrop-filter: blur(var(--glass-blur-md)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur-md)) saturate(var(--glass-saturate));
  text-align: left;
  transition: border-color var(--dur-2) var(--ease-out), background var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
}
.mode:hover { background: rgba(8,13,26,0.72); border-color: var(--glass-stroke-2); transform: translateX(-3px); }
.mode[aria-pressed="true"] { border-color: var(--accent); background: rgba(8,13,26,0.82); box-shadow: 0 0 0 1px var(--accent), 0 8px 32px var(--accent-glow); }
.mode__idx { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em; color: var(--fg-4); padding-top: 3px; }
.mode[aria-pressed="true"] .mode__idx { color: var(--accent); }
.mode__body { min-width: 0; }
.mode__name { display: block; font-family: var(--font-ui); font-size: 13.5px; font-weight: 500; color: var(--fg-1); }
.mode__desc { display: block; font-size: 11.5px; line-height: 1.4; color: var(--fg-4); margin-top: 2px; }

/* --- Layer scrubber (terrain mode) ------------------------------------ */
/* Vertical layer slider that sits to the left of the three mode buttons.
   The track is rotated -90deg inside its flex slot so the cross-fade slider
   runs top-to-bottom across the same vertical span as the mode stack. */
.scrub {
  position: absolute;
  z-index: 3;
  top: clamp(24px, 5vw, 64px);
  /* Immediately left of the rail (HUD + mode cards). The 18px gap mirrors the
     rail's internal gap so the whole right side reads as one control stack. */
  right: calc(var(--gutter) + min(300px, 42vw) + 18px);
  width: 56px;
  height: clamp(220px, 28vh, 320px);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: var(--s-4) var(--s-2);
  border-radius: var(--r-md);
  border: 1px solid var(--glass-stroke-1);
  background: rgba(8,13,26,0.55);
  backdrop-filter: blur(var(--glass-blur-md));
  -webkit-backdrop-filter: blur(var(--glass-blur-md));
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}
.scrub[hidden] { display: none; }
.scrub__head { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 4px; margin-bottom: var(--s-3); }
.scrub__now { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); writing-mode: vertical-rl; transform: rotate(180deg); white-space: nowrap; }
.scrub__hint { font-size: 10px; color: var(--fg-4); line-height: 1.3; }

/* The input is laid out horizontally and rotated into a vertical track.
   -webkit-appearance: slider-vertical would be the native path but is not
   consistently honored across browsers; rotating a horizontal range is. */
.scrub__slot {
  flex: 1 1 auto;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 140px;
  /* The slot owns the drag (see hero.js); touch-action keeps a vertical drag
     from being claimed by the page scroller before it reaches us. */
  cursor: ns-resize;
  touch-action: none;
}
.scrub__input {
  -webkit-appearance: none;
  appearance: none;
  width: 200px;     /* visual height after rotation */
  height: 22px;     /* visual width after rotation */
  background: none;
  transform: rotate(-90deg);
  transform-origin: center;
  cursor: ns-resize;
  /* The rotated element still renders the track and thumb, but the slot
     handles pointing. Keyboard focus and the value are unaffected. */
  pointer-events: none;
}
.scrub__input::-webkit-slider-runnable-track { height: 3px; border-radius: 2px; background: linear-gradient(180deg, var(--accent), var(--azure-400), #8ed6ff, var(--fg-3)); }
.scrub__input::-moz-range-track { height: 3px; border-radius: 2px; background: linear-gradient(180deg, var(--accent), var(--azure-400), #8ed6ff, var(--fg-3)); }
.scrub__input::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; margin-top: -6.5px; border-radius: 50%; background: var(--fg-1); border: 3px solid var(--night-950); box-shadow: 0 0 0 1px var(--accent), 0 0 14px var(--accent-glow); }
.scrub__input::-moz-range-thumb { width: 16px; height: 16px; border-radius: 50%; background: var(--fg-1); border: 3px solid var(--night-950); box-shadow: 0 0 0 1px var(--accent), 0 0 14px var(--accent-glow); }

.scrub__ticks { display: flex; flex-direction: column; align-items: center; gap: 4px; margin-top: var(--s-3); }
.scrub__tick { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-4); transition: color var(--dur-2) var(--ease-out); white-space: nowrap; }
.scrub__tick[data-on="true"] { color: var(--fg-1); }

/* --- Node readout (convoy mode) -------------------------------------- */
.readout {
  position: absolute;
  z-index: 3;
  left: var(--gutter);
  bottom: var(--s-6);
  width: min(320px, 76vw);
  padding: var(--s-5);
  border-radius: var(--r-md);
  border: 1px solid var(--glass-stroke-2);
  background: rgba(8,13,26,0.72);
  backdrop-filter: blur(var(--glass-blur-lg));
  -webkit-backdrop-filter: blur(var(--glass-blur-lg));
  box-shadow: var(--shadow-3);
}
.readout[hidden] { display: none; }
.readout__head { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-4); }
.readout__name { font-family: var(--font-display); font-size: var(--t-h6); font-weight: 700; }
.readout__rows { display: grid; grid-template-columns: auto 1fr; gap: 7px var(--s-5); font-family: var(--font-mono); font-size: 11.5px; }
.readout__rows dt { color: var(--fg-4); letter-spacing: 0.1em; text-transform: uppercase; font-size: 10px; padding-top: 1px; }
.readout__rows dd { margin: 0; color: var(--fg-1); }
.readout__rows dd em { font-style: normal; color: var(--accent); }
.readout__hint { margin-top: var(--s-4); padding-top: var(--s-3); border-top: 1px solid var(--fg-5); font-size: 11px; color: var(--fg-4); }

/* --- Tier panel (coverage-fallback mode) ------------------------------ */
/* The mode's whole point is the handover, so the handover has to be legible:
   three rows, the live one lit. Without this the mode rendered rings onto a
   dimmed terrain and reported its tier into the hidden scrubber. */
.tiers {
  position: absolute;
  z-index: 3;
  left: var(--gutter);
  bottom: var(--s-6);
  width: min(360px, 80vw);
  padding: var(--s-5);
  border-radius: var(--r-md);
  border: 1px solid var(--glass-stroke-2);
  background: rgba(8,13,26,0.72);
  backdrop-filter: blur(var(--glass-blur-lg));
  -webkit-backdrop-filter: blur(var(--glass-blur-lg));
  box-shadow: var(--shadow-3);
}
.tiers[hidden] { display: none; }
.tiers__head {
  font-family: var(--font-mono);
  font-size: var(--t-overline);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fg-4);
  margin-bottom: var(--s-4);
}
.tiers__row {
  display: grid;
  grid-template-columns: 10px 1fr;
  gap: 2px var(--s-3);
  padding: 7px 0;
  opacity: 0.42;
  transition: opacity var(--dur-2) var(--ease-out);
}
.tiers__row[data-on="true"] { opacity: 1; }
.tiers__dot {
  grid-row: 1 / 3;
  width: 8px; height: 8px;
  margin-top: 5px;
  border-radius: 50%;
  background: var(--fg-3);
  transition: background var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
.tiers__row[data-tier="0"][data-on="true"] .tiers__dot { background: var(--azure-400); box-shadow: 0 0 12px var(--azure-400); }
.tiers__row[data-tier="1"][data-on="true"] .tiers__dot { background: #7fc7e8; box-shadow: 0 0 12px #7fc7e8; }
.tiers__row[data-tier="2"][data-on="true"] .tiers__dot { background: #8ed6ff; box-shadow: 0 0 12px #8ed6ff; }
.tiers__name { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-1); }
.tiers__note { font-size: 11.5px; line-height: 1.45; color: var(--fg-4); }

/* --- Live telemetry strip along the bottom of the hero ---------------- */
.hero__strip {
  position: relative;
  z-index: 2;
  margin-top: clamp(32px, 5vw, 64px);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-8);
  padding-top: var(--s-5);
  border-top: 1px solid var(--fg-5);
}
.hero__metric { display: flex; align-items: baseline; gap: var(--s-3); }
.hero__metric-v { font-family: var(--font-mono); font-size: 19px; font-weight: 500; color: var(--fg-1); letter-spacing: -0.02em; }
.hero__metric-v em { font-style: normal; color: var(--accent); }
.hero__metric-l { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--fg-4); }

/* --- Two-track entry -------------------------------------------------- */
.tracks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(16px, 2vw, 28px); }
.track {
  --accent: var(--mint-400);
  --accent-soft: var(--mint-200);
  --accent-glow: var(--mint-glow);
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 3vw, 44px);
  border-radius: var(--r-xl);
  border: 1px solid var(--glass-stroke-2);
  background: var(--glass-tint-1);
  backdrop-filter: blur(var(--glass-blur-md)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur-md)) saturate(var(--glass-saturate));
  box-shadow: var(--shadow-2), var(--glass-inner-lift);
  overflow: clip;
  transition: background var(--dur-3) var(--ease-out), border-color var(--dur-3) var(--ease-out), box-shadow var(--dur-3) var(--ease-out);
}
.track--pro { --accent: var(--amber-400); --accent-soft: var(--amber-200); --accent-glow: rgba(255,138,31,0.5); }
.track:hover { background: var(--glass-tint-2); border-color: var(--glass-stroke-3); box-shadow: var(--shadow-3), var(--glass-inner-lift); }
.track::before {
  content: "";
  position: absolute;
  inset: -40% -10% auto -10%;
  height: 70%;
  z-index: -1;
  opacity: 0.5;
  background: radial-gradient(60% 100% at 50% 100%, var(--accent-glow), transparent 70%);
}
.track__eyebrow { color: var(--accent); }
.track__title { margin: var(--s-4) 0 var(--s-4); }
.track__text { color: var(--fg-3); font-size: var(--t-body-sm); margin-bottom: var(--s-6); }
.track__list { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 2px var(--s-4); margin-bottom: var(--s-8); }
.track__item { display: flex; align-items: center; gap: var(--s-2); padding: 6px 0; font-size: 13.5px; color: var(--fg-2); }
.track__item:hover { color: var(--accent); }
.track__item::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); flex: none; opacity: 0.7; }
.track__cta { margin-top: auto; }

/* Between 820 and 1080 the docked composition still fits — it just needs less
   room for the mode rail and the scrubber so the copy column keeps its measure. */
@media (max-width: 1080px) and (min-width: 821px) {
  .hero__rail { width: min(262px, 32vw); top: clamp(20px, 4vw, 48px); }
  .scrub { right: calc(var(--gutter) + min(262px, 32vw) + 14px); }
  .mode { padding: 10px 12px; }
  .mode__desc { font-size: 11px; }
  .scrub { right: calc(var(--gutter) + min(238px, 30vw) + 18px); height: clamp(200px, 26vh, 280px); }
  .hero__copy { max-width: 17ch; }
  .hero__lede { max-width: 40ch; }
}

/* --- Mobile: the hero unstacks into one column ------------------------- */
/* Nothing is docked at this width, so the composition is re-read as a
   narrative: the headline lands first, the terrain second, and the lede sits
   directly above the mode cards it describes. `display: contents` on the inner
   wrapper promotes the copy, buttons and metric strip to flex items of the
   hero so they can be ordered against the stage and the controls; each then
   carries the gutter the wrapper used to provide. */
@media (max-width: 820px) {
  .hero,
  .hero:has(.scrub),
  .hero:has(.readout),
  .hero:has(.tiers) {
    min-height: 0;
    justify-content: flex-start;
    padding-block: clamp(20px, 6vw, 40px) clamp(24px, 3vw, 40px);
  }
  .hero__inner { display: contents; }

  .hero__copy      { order: 1; }
  .hero__stage     { order: 2; }
  .hero__lede      { order: 3; }
  .hero__rail      { position: static; display: contents; }
  .hud             { order: 4; }
  .modes           { order: 4; }
  .scrub           { order: 5; }
  .readout         { order: 5; }
  .tiers           { order: 5; }
  .hero__degraded  { order: 5; }
  .hero__inner .btn-row { order: 6; }
  .hero__strip     { order: 7; }

  .hero__copy,
  .hero__lede,
  .hero__inner .btn-row,
  .hero__strip,
  .modes,
  .scrub,
  .readout,
  .tiers {
    padding-inline: var(--gutter);
  }

  .hero__copy { max-width: none; margin-bottom: 0; }
  .hero__title { margin-bottom: 0; }
  .hero__lede {
    max-width: none;
    font-size: var(--t-body-sm);
    line-height: 1.55;
    color: var(--fg-3);
    margin-bottom: var(--s-4);
  }

  .hero__stage {
    position: relative;
    inset: auto;
    height: min(46vh, 400px);
    margin-block: var(--s-6);
  }

  .modes {
    position: static;
    width: auto;
    flex-direction: row;
    overflow-x: auto;
    scroll-padding-inline: var(--gutter);
    margin-bottom: var(--s-6);
  }
  .mode { flex: 1 0 200px; }
  .mode:hover { transform: none; }

  /* On mobile the vertical slider unsticks too: it drops back into the
     document flow as a wide horizontal bar so the cross-fade is still
     thumbable on a touch surface. */
  .scrub, .readout, .tiers {
    position: static;
    left: auto; right: auto; bottom: auto;
    top: auto;
    width: auto;
    max-width: none;
    margin-bottom: var(--s-5);
  }
  .scrub { right: auto; height: auto; flex-direction: column; padding: var(--s-4) var(--s-5); }
  .scrub__head { flex-direction: row; align-items: baseline; justify-content: space-between; text-align: left; }
  .scrub__now { writing-mode: horizontal-tb; transform: none; }
  .scrub__slot { min-height: 0; height: 28px; }
  .scrub__input { transform: none; width: 100%; }
  .scrub__slot { cursor: ew-resize; }
  .scrub__ticks { flex-direction: row; justify-content: space-between; }
  .scrub__hint { display: none; }

  .hud { position: static; left: auto; top: auto; min-width: 0; margin-bottom: var(--s-5); padding: var(--s-3) var(--s-4); }
  .hero__copy, .hero__lede, .hero__inner .btn-row, .hero__strip, .modes, .scrub, .readout, .tiers, .hud {
    padding-inline: var(--gutter);
  }
  .hero:has(.hero__stage[data-ready="failed"]) .hero__degraded {
    position: static;
    left: auto;
    bottom: auto;
    max-width: none;
    padding-inline: var(--gutter);
    margin-bottom: var(--s-5);
  }
}
@media (max-width: 720px) {
  .tracks { grid-template-columns: minmax(0, 1fr); }
}
