/* ============================================================
   SIDEREAL — conjunction assessment
   Visual world: a darkened operations room at 3am. Deep vacuum
   navy, one cold instrument blue, one hazard orange that appears
   only where something is closing on you. Serif for the human
   voice, mono for anything a machine measured.

   Motion contract: nothing here is hidden by CSS alone. The
   `.js-motion` class (set by main.js only when motion is wanted
   AND supported) gates every hidden-start state, so no-JS and
   reduced-motion users receive a complete, visible page.
   ============================================================ */

/* ---------- 1. TOKENS ---------- */
:root {
  /* Vacuum — the substrate, cold end of the story */
  --void-900: #05070c;
  --void-850: #07090f;
  --void-800: #0b0f18;
  --void-700: #121826;
  --void-600: #1b2334;
  --void-500: #2b3648;
  --void-400: #45536b;
  --void-300: #6d7d96;
  --void-200: #9daabe;
  --void-100: #d3dae5;
  --void-000: #f2f5f9;

  /* Instrument blue — tracked, known, nominal */
  --cyan:      #6fb6ff;
  --cyan-dim:  #2e6ba8;
  --cyan-glow: rgba(111, 182, 255, 0.16);

  /* Hazard — closing, urgent, the thing to act on */
  --alert:     #ff5c38;
  --alert-dim: #9c2f18;
  --alert-glow: rgba(255, 92, 56, 0.2);

  /* Resolution — warmth the page earns only after the turn */
  --warm:      #ffc46b;
  --warm-deep: #b8792a;
  --safe:      #57d9a3;

  --rule:        rgba(255, 255, 255, 0.08);
  --rule-strong: rgba(255, 255, 255, 0.15);

  --bg: var(--void-850);
  --fg: var(--void-100);

  --font-serif: "Instrument Serif", "Iowan Old Style", Georgia, serif;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --gut: clamp(1.25rem, 4vw, 3.5rem);
  --band: clamp(5rem, 12vh, 10rem);
  --maxw: 1320px;

  /* Named curves. Each is chosen for what it moves. */
  --ease-glide: cubic-bezier(0.16, 1, 0.3, 1);      /* heavy, decelerating — mass */
  --ease-snap:  cubic-bezier(0.34, 1.4, 0.44, 1);   /* slight overshoot — UI, alerts */
  --ease-mech:  cubic-bezier(0.65, 0, 0.35, 1);     /* symmetric — instruments */
}

/* ---------- 2. RESET ---------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3 { margin: 0; font-weight: 400; text-wrap: balance; }
p, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, svg, canvas { display: block; max-width: 100%; }
a { color: inherit; }

::selection { background: var(--cyan); color: var(--void-900); }

:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 3px;
  border-radius: 2px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; top: -100%; left: 1rem; z-index: 200;
  padding: 0.7rem 1.1rem;
  background: var(--cyan); color: var(--void-900);
  font: 600 0.85rem/1 var(--font-sans);
  border-radius: 4px; text-decoration: none;
}
.skip-link:focus { top: 1rem; }

/* ---------- 3. SHARED ATOMS ---------- */
.eyebrow {
  display: flex; align-items: center; gap: 0.6rem;
  font: 500 0.72rem/1.4 var(--font-mono);
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--void-300);
}

.pip {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 0 0 var(--cyan-glow);
  animation: pulse 3.4s var(--ease-mech) infinite;
  flex: none;
}
.pip--alert { background: var(--alert); box-shadow: 0 0 0 0 var(--alert-glow); }

@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--cyan-glow); }
  50%      { box-shadow: 0 0 0 7px rgba(111, 182, 255, 0); }
}

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.5rem;
  background: var(--cyan); color: var(--void-900);
  font: 600 0.9rem/1 var(--font-sans);
  letter-spacing: -0.01em;
  border: 1px solid var(--cyan); border-radius: 3px;
  text-decoration: none; cursor: pointer;
  transition: transform 0.4s var(--ease-snap),
              background-color 0.3s var(--ease-mech),
              box-shadow 0.4s var(--ease-glide);
}
.btn:hover {
  background: #8fc7ff;
  transform: translateY(-2px);
  box-shadow: 0 10px 30px -12px var(--cyan-glow);
}
.btn:active { transform: translateY(0); }

.btn--ghost {
  background: transparent; color: var(--void-100);
  border-color: var(--rule-strong);
}
.btn--ghost:hover {
  background: rgba(111, 182, 255, 0.07);
  border-color: var(--cyan-dim);
  box-shadow: none;
}
.btn--sm { padding: 0.6rem 1.05rem; font-size: 0.82rem; }
.btn--lg { padding: 1.05rem 2rem; font-size: 1rem; }

.sec-head { max-width: 44rem; margin-bottom: clamp(2.5rem, 6vw, 4.5rem); }
.sec-h {
  margin-top: 1rem;
  font-family: var(--font-serif);
  font-size: clamp(2.1rem, 1.3rem + 3.6vw, 4rem);
  line-height: 1.04;
  letter-spacing: -0.02em;
}

/* ---------- 4. SCROLL PROGRESS ---------- */
.prog {
  position: fixed; inset: 0 0 auto 0; z-index: 120;
  height: 2px; background: rgba(255, 255, 255, 0.05);
  pointer-events: none;
}
.prog__fill {
  display: block; height: 100%; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--cyan-dim), var(--cyan) 60%, var(--warm));
  will-change: transform;
}

/* ---------- 5. NAV ---------- */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background-color 0.5s var(--ease-mech),
              border-color 0.5s var(--ease-mech),
              backdrop-filter 0.5s var(--ease-mech);
}
.nav.is-stuck {
  background: rgba(7, 9, 15, 0.82);
  backdrop-filter: blur(14px) saturate(1.2);
  border-bottom-color: var(--rule);
}

.nav__in {
  display: flex; align-items: center; gap: clamp(1rem, 3vw, 2.5rem);
  max-width: var(--maxw); margin: 0 auto;
  padding: 0.85rem var(--gut);
}

.brand {
  display: inline-flex; align-items: center; gap: 0.6rem;
  text-decoration: none; color: var(--void-000);
  flex: none;
}
.brand__mark { width: 26px; height: 26px; color: var(--cyan); }
.brand__bogey { transition: opacity 0.4s var(--ease-mech); }
.brand__word {
  font: 700 0.92rem/1 var(--font-sans);
  letter-spacing: 0.18em;
}

.nav__links {
  display: flex; gap: 1.6rem;
  margin-left: auto;
}
.nav__link {
  font: 500 0.85rem/1 var(--font-sans);
  color: var(--void-200); text-decoration: none;
  position: relative; padding-block: 0.35rem;
  transition: color 0.3s var(--ease-mech);
}
.nav__link::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px; background: var(--cyan);
  transform: scaleX(0); transform-origin: 100% 50%;
  transition: transform 0.45s var(--ease-glide);
}
.nav__link:hover { color: var(--void-000); }
.nav__link:hover::after { transform: scaleX(1); transform-origin: 0 50%; }

.nav__stat {
  display: flex; align-items: center; gap: 0.5rem;
  font: 400 0.74rem/1 var(--font-mono);
  color: var(--void-300);
  white-space: nowrap;
}
.nav__stat span:last-child { font-variant-numeric: tabular-nums; }

@media (max-width: 1080px) {
  .nav__links, .nav__stat { display: none; }
  .nav__cta { margin-left: auto; }
}

/* ---------- 6. HERO ----------
   Beat 1: the visitor believes space is empty and this is paranoia. */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex; align-items: center;
  padding: clamp(7rem, 16vh, 11rem) var(--gut) clamp(4rem, 9vh, 7rem);
  overflow: hidden;
}

.hero__field { position: absolute; inset: 0; z-index: 0; }

/* The photograph. Pushed far down in luminance and desaturated toward the
   page's blue so it reads as the environment the instruments are pointed
   at, never as a stock hero image. Anchored right so the bright limb sits
   opposite the text column. */
.hero__photo { position: absolute; inset: 0; }
.hero__photo img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 68% 78%;
  filter: brightness(0.78) saturate(0.7) contrast(1.12);
}

#starfield { position: absolute; inset: 0; width: 100%; height: 100%; }

.hero__field::after {
  /* Scrim: guarantees the text column is on near-flat ground regardless of
     what the photo is doing behind it. The left stop is opaque, so type
     never renders over unmodified photography. */
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(100deg,
      var(--void-850) 0%,
      rgba(7, 9, 15, 0.94) 30%,
      rgba(7, 9, 15, 0.6) 52%,
      rgba(7, 9, 15, 0.18) 76%,
      rgba(7, 9, 15, 0.3) 100%),
    radial-gradient(115% 80% at 20% 42%, transparent 0%, rgba(7, 9, 15, 0.6) 78%),
    linear-gradient(180deg, rgba(7, 9, 15, 0.6) 0%, transparent 22%,
      transparent 58%, var(--void-850) 100%);
}

/* Narrow screens: the text column spans the full width, so the scrim has to
   become an almost solid ground rather than a side-lit one. */
@media (max-width: 760px) {
  .hero__photo img { object-position: 62% 38%; filter: brightness(0.3) saturate(0.5); }
  .hero__field::after {
    background:
      linear-gradient(180deg, rgba(7, 9, 15, 0.86) 0%, rgba(7, 9, 15, 0.9) 45%,
        var(--void-850) 88%);
  }
}

.hero__in {
  position: relative; z-index: 1;
  width: 100%; max-width: var(--maxw); margin: 0 auto;
}

.hero__h {
  margin: 1.4rem 0 0;
  font-family: var(--font-serif);
  font-size: clamp(3rem, 1.2rem + 8.6vw, 8.5rem);
  line-height: 0.94;
  letter-spacing: -0.035em;
}
.hero__line { display: block; }
.hero__line--em {
  font-style: italic;
  color: var(--void-300);
}
/* The one hazard accent in the hero: the word that carries the threat. */
/* A tracked object, not a bullet: small, ringed, instrument-scaled.
   It reads as the same class of mark as the hazards in the starfield. */
.hero__line--em::after {
  content: ""; display: inline-block;
  /* Absolute, instrument-scale size: it must read as the same class of
     mark as the tracked hazards in the starfield, not as a bullet that
     grows with the display type. */
  width: 11px; height: 11px; margin-left: 0.28em;
  border-radius: 50%; background: var(--alert);
  vertical-align: 0.42em;
  box-shadow:
    0 0 0 4px rgba(255, 92, 56, 0.16),
    0 0 22px rgba(255, 92, 56, 0.5);
}

.hero__sub {
  max-width: 40rem; margin-top: 1.8rem;
  font-size: clamp(1.05rem, 0.98rem + 0.34vw, 1.28rem);
  color: var(--void-200);
  text-wrap: pretty;
}

.hero__acts {
  display: flex; flex-wrap: wrap; gap: 0.8rem;
  margin-top: 2.4rem;
}

/* The motif readout */
.readout {
  margin: clamp(3rem, 7vh, 5rem) 0 0;
  padding-top: 1.6rem;
  border-top: 1px solid var(--rule);
  max-width: 38rem;
}
.readout__cap {
  font: 400 0.7rem/1.5 var(--font-mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--void-400);
}
.readout__num {
  display: flex; align-items: baseline; gap: 0.2em;
  margin-top: 0.5rem;
  font-family: var(--font-mono); font-weight: 700;
  font-size: clamp(2.6rem, 1.4rem + 5vw, 5rem);
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--alert);
  font-variant-numeric: tabular-nums;
}
.readout__unit {
  font-size: 0.28em; font-weight: 500;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--void-300);
}
.readout__note {
  max-width: 30rem; margin-top: 0.9rem;
  font-size: 0.92rem; color: var(--void-300);
}

.hero__cue {
  position: absolute; left: 50%; bottom: 1.8rem; z-index: 1;
  transform: translateX(-50%);
  font: 400 0.68rem/1 var(--font-mono);
  letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--void-400);
  transition: opacity 0.5s var(--ease-mech);
}
.hero__cue span { display: block; animation: cue 2.6s var(--ease-mech) infinite; }
@keyframes cue {
  0%, 100% { transform: translateY(0); opacity: 0.55; }
  50%      { transform: translateY(6px); opacity: 1; }
}
.hero__cue.is-gone { opacity: 0; }

/* ---------- 7. THE EVENT (pinned stage) ----------
   Beat 2: the climax. The page's busiest, densest moment.
   Height is set in JS so the pin duration is deliberate, not
   an accident of content length. */
.event {
  position: relative;
  background:
    linear-gradient(180deg, var(--void-850) 0%, var(--void-900) 30%, var(--void-900) 100%);
}

.event__sticky {
  position: sticky; top: 0;
  min-height: 100svh;
  display: flex; align-items: center;
  /* Symmetric block padding so the frame optically centres in the pin
     rather than hanging from the top with a pool of space beneath it. */
  padding: clamp(4.5rem, 10vh, 6.5rem) var(--gut);
  overflow: hidden;
}

.event__frame { width: 100%; max-width: var(--maxw); margin: 0 auto; }

.event__head { margin-bottom: clamp(1.5rem, 4vh, 3rem); }
.event__h {
  font-family: var(--font-serif);
  font-size: clamp(1.9rem, 1.2rem + 3vw, 3.4rem);
  line-height: 1.02; letter-spacing: -0.025em;
}
.event__hint {
  margin-top: 0.5rem;
  font: 400 0.72rem/1.5 var(--font-mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--void-400);
}

/* The stage: two objects on one track, closing. */
.stage {
  position: relative;
  height: clamp(150px, 24vh, 250px);
  border: 1px solid var(--rule);
  border-radius: 4px;
  background:
    radial-gradient(120% 140% at 50% 50%, rgba(19, 26, 40, 0.9), rgba(8, 11, 18, 0.95));
  overflow: hidden;
}
/* Range ticks along the baseline — the stage reads as a measuring
   instrument rather than a decorative band. */
.stage::after {
  content: ""; position: absolute;
  left: 0; right: 0; top: calc(50% + 12px); height: 7px;
  background: repeating-linear-gradient(90deg,
              var(--void-500) 0 1px, transparent 1px 64px);
  opacity: 0.55;
  pointer-events: none;
}

.stage__grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, var(--rule) 1px, transparent 1px),
    linear-gradient(to bottom, var(--rule) 1px, transparent 1px);
  background-size: 56px 56px;
  opacity: 0.5;
  /* Parallaxed gently in JS — restrained, never colliding with type */
  will-change: transform;
}

/* Uncertainty cone: wide and vague at T−72, tight at closest approach. */
.stage__cone {
  position: absolute; top: 50%; left: 50%;
  width: 56%; height: 118%;
  transform: translate(-50%, -50%) scaleX(1);
  background: radial-gradient(50% 50% at 50% 50%,
              rgba(255, 92, 56, 0.34) 0%,
              rgba(255, 92, 56, 0.13) 45%,
              transparent 76%);
  will-change: transform, opacity;
}

.stage__track {
  position: absolute; top: 50%; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--rule-strong) 12%,
              var(--rule-strong) 88%, transparent);
  transform: translateY(-50%);
}

.stage__obj {
  position: absolute; top: 50%;
  width: 13px; height: 13px; border-radius: 50%;
  transform: translate(-50%, -50%);
  will-change: left;
}
.stage__obj--own {
  background: var(--cyan);
  box-shadow: 0 0 0 5px rgba(111, 182, 255, 0.14), 0 0 26px var(--cyan-glow);
  left: 8%;
}
.stage__obj--bogey {
  background: var(--alert);
  box-shadow: 0 0 0 5px rgba(255, 92, 56, 0.14), 0 0 26px var(--alert-glow);
  left: 92%;
}

/* The measured gap between them — a literal ruler. */
.stage__gap {
  position: absolute; top: 50%;
  height: 1px; left: 8%; width: 84%;
  transform: translateY(-50%);
  background: repeating-linear-gradient(90deg,
              var(--void-400) 0 4px, transparent 4px 9px);
  opacity: 0.7;
  will-change: left, width;
}

/* Climax escalation: past the manoeuvre threshold the whole stage
   tightens — the frame charges hazard, the grid dims out of the way,
   and the two objects gain a halo. Applied by JS at the same moment
   the number goes hot, so colour, light and data agree. */
.stage { transition: border-color 0.7s var(--ease-mech); }
.event.is-critical .stage { border-color: rgba(255, 92, 56, 0.45); }

/* The alarm wash is a pre-composited overlay whose OPACITY animates —
   transitioning box-shadow here repainted the full stage surface and
   cost ~50ms frames at the threshold crossing. */
.stage__grid { transition: opacity 0.7s var(--ease-mech); }
.event.is-critical .stage__grid { opacity: 0.22; }

.stage::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  border-radius: inherit;
  background: radial-gradient(120% 140% at 50% 50%,
              rgba(255, 92, 56, 0.10), transparent 70%);
  opacity: 0;
  transition: opacity 0.7s var(--ease-mech);
  pointer-events: none;
  will-change: opacity;
}
.event.is-critical .stage::before { opacity: 1; }

/* Object halos: a static ring plus a separate scaled glow layer, so the
   escalation animates transform/opacity only. */
.stage__obj::before {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 46px; height: 46px; margin: -23px 0 0 -23px;
  border-radius: 50%;
  opacity: 0; transform: scale(0.55);
  transition: opacity 0.7s var(--ease-mech), transform 0.7s var(--ease-glide);
  pointer-events: none;
  will-change: opacity, transform;
}
.stage__obj--own::before {
  background: radial-gradient(circle, rgba(111, 182, 255, 0.4), transparent 66%);
}
.stage__obj--bogey::before {
  background: radial-gradient(circle, rgba(255, 92, 56, 0.55), transparent 66%);
}
.event.is-critical .stage__obj::before { opacity: 1; transform: scale(1); }
.event__label { transition: color 0.7s var(--ease-mech); }
.event.is-critical .event__label { color: var(--alert); }

.event__readout {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0.6rem clamp(1rem, 3vw, 2.4rem);
  margin-top: clamp(1.2rem, 3vh, 2rem);
  padding-bottom: clamp(1.2rem, 3vh, 2rem);
  border-bottom: 1px solid var(--rule);
}
.event__label {
  font: 400 0.7rem/1 var(--font-mono);
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--void-400);
}
.event__num {
  display: flex; align-items: baseline; gap: 0.2em;
  font-family: var(--font-mono); font-weight: 700;
  font-size: clamp(2rem, 1.2rem + 3.4vw, 3.8rem);
  line-height: 1; letter-spacing: -0.04em;
  color: var(--cyan);
  font-variant-numeric: tabular-nums;
  transition: color 0.6s var(--ease-mech);
}
/* Colour is state, not decoration: the number goes hazard when Pc does. */
.event__num.is-hot { color: var(--alert); }

.event__prob {
  margin-left: auto;
  font: 500 0.85rem/1 var(--font-mono);
  color: var(--void-300);
  font-variant-numeric: tabular-nums;
}
.event__prob sub { font-size: 0.72em; }

/* Beats: exactly one visible, cross-faded. A cut, not a scrub. */
/* Height is reserved for the tallest beat so the layout never jumps as
   beats cut over — but only just enough, so the climax doesn't sit on
   top of a pool of dead space. */
.beats {
  position: relative;
  margin-top: clamp(1.2rem, 3vh, 1.8rem);
}
.js-motion .beats { min-height: clamp(7rem, 12vh, 8.5rem); }
/* DEFAULT (no JS): beats are an ordinary stacked, fully-visible list.
   The absolutely-positioned cross-fade below is opted into only under
   .js-motion, so a page with scripting off is never left with four of
   five beats invisible. */
.beat {
  display: grid;
  grid-template-columns: minmax(0, 6rem) minmax(0, 11rem) minmax(0, 34rem);
  gap: clamp(1rem, 3vw, 2.5rem);
  align-items: start;
  padding: 1.4rem 0;
  border-top: 1px solid var(--rule);
}
.js-motion .beat {
  position: absolute; inset: 0;
  grid-template-columns: minmax(0, 7rem) minmax(0, 46rem);
  padding: 0; border-top: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(14px);
  transition: opacity 0.45s var(--ease-mech),
              transform 0.55s var(--ease-glide),
              visibility 0s linear 0.45s;
}
.js-motion .beat.is-on {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.45s var(--ease-mech),
              transform 0.55s var(--ease-glide),
              visibility 0s;
}
.beat__t {
  font: 700 0.9rem/1.4 var(--font-mono);
  letter-spacing: 0.02em;
  color: var(--alert);
  font-variant-numeric: tabular-nums;
}
.beat__c {
  font-size: clamp(0.98rem, 0.93rem + 0.25vw, 1.16rem);
  color: var(--void-200);
  text-wrap: pretty;
}
.beat__c strong { color: var(--void-000); font-weight: 600; }

/* Reduced-motion / no-JS: the pin never engages, so the beats must
   stack as an ordinary readable list. */
.event--static .event__sticky { position: static; min-height: 0; }
.event--static .beats { min-height: 0; gap: 0; }
/* .event--static reuses the default stacked beat layout above; it only
   needs to release the pin. */
:root:not(.js-motion) .stage__cone { opacity: 0.5; }

/* Static build: each beat carries its own measured figure, so the
   timeline still tells the falling-distance story without the scrub. */
.js-motion .beat__m { display: none; }
.beat__m {
  display: block;
  font: 700 1.05rem/1.4 var(--font-mono);
  letter-spacing: -0.02em;
  color: var(--cyan);
  font-variant-numeric: tabular-nums;
}
.beat__m span {
  display: block;
  font: 400 0.68rem/1.5 var(--font-mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--void-400);
}
.beat:nth-child(4) .beat__m,
.beat:nth-child(5) .beat__m { color: var(--alert); }

/* The live readout is a scrubbed instrument; with no scrub it becomes a
   summary of the event's end state, and says so. */
:root:not(.js-motion) .event__label::after { content: " at closest approach"; }
/* No scrub means no JS-driven hot state, so the static end-state figure
   must carry the hazard colour on its own. */
:root:not(.js-motion) .event__num { color: var(--alert); }
/* Give the figure column room so the probability never wraps mid-number. */
.beat__m span { white-space: nowrap; }

@media (max-width: 720px) {
  .beat { grid-template-columns: 1fr; gap: 0.4rem; }
  .beats { min-height: clamp(11rem, 26vh, 14rem); }
  .event__prob { margin-left: 0; width: 100%; }
}

/* ---------- 7b. INTERLUDE ----------
   A held frame between the climax and the turn. Deliberately short — it is
   a breath, not a section — and carries no body text, so the photograph is
   never behind anything that must be read. */
.interlude {
  position: relative;
  height: clamp(190px, 34vh, 380px);
  overflow: hidden;
  background: var(--void-900);
  border-block: 1px solid var(--rule);
}
/* <picture> is inline by default, which left the image 2px short of the
   band and added descender space. Make it a real block box. */
.interlude picture {
  position: absolute; inset: 0;
  display: block;
}
.interlude img {
  /* Oversized on purpose: the parallax drifts the image within the band,
     and the extra height is the margin that keeps an edge from ever
     entering frame. Height and offset are paired with the drift range
     in main.js (36% of band height, so ±18%). */
  position: absolute;
  left: 0; width: 100%;
  top: -22%; height: 144%;
  object-fit: cover;
  object-position: 50% 46%;
  filter: brightness(0.72) saturate(0.62) contrast(1.1);
}
/* Top and bottom feather so the band dissolves into the sections either
   side rather than sitting in the page like a pasted-in rectangle. */
.interlude::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(180deg, var(--void-900) 0%, transparent 26%,
      transparent 62%, rgba(11, 15, 24, 0.9) 92%, var(--void-800) 100%),
    radial-gradient(90% 120% at 50% 50%, transparent 40%, rgba(5, 7, 12, 0.55) 100%);
  pointer-events: none;
}
.interlude__cap {
  position: absolute; left: var(--gut); bottom: clamp(0.9rem, 2.4vh, 1.6rem);
  z-index: 1;
  font: 400 0.68rem/1.5 var(--font-mono);
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--void-300);
}
.interlude__cap span {
  border-left: 1px solid var(--cyan-dim);
  padding-left: 0.7rem;
}

/* Scrubbed parallax: the photo drifts slower than the page, which is what
   makes the band read as a window rather than a picture. Transform only. */
.js-motion .interlude img { will-change: transform; }

@media (max-width: 760px) {
  .interlude { height: clamp(150px, 26vh, 220px); }
  .interlude__cap { font-size: 0.62rem; letter-spacing: 0.12em; }
}

/* ---------- 8. THE TURN ----------
   Beat 3: the pivot. Palette warms from here on.
   Words resolve individually — the only word-level motion on the
   page, reserved for the one sentence that carries the thesis. */
.turn {
  background: linear-gradient(180deg, var(--void-900), var(--void-800));
  padding: clamp(7rem, 20vh, 14rem) var(--gut);
}
.turn__in { max-width: 58rem; margin: 0 auto; }

.turn__h {
  font-family: var(--font-serif);
  font-size: clamp(2.2rem, 1.1rem + 5vw, 5.2rem);
  line-height: 1.02; letter-spacing: -0.03em;
}
.turn__h em {
  display: block; margin-top: 0.15em;
  font-style: italic;
  color: var(--warm);
}
.turn__h [data-word] { display: inline-block; }

.turn__sub {
  max-width: 38rem; margin-top: 2.2rem;
  font-size: clamp(1.02rem, 0.97rem + 0.3vw, 1.2rem);
  color: var(--void-200);
  text-wrap: pretty;
}

/* ---------- 9. METHOD ----------
   Beat 4: density rises. Tighter type, tabular data, more rules. */
.method {
  background: var(--void-800);
  padding: var(--band) var(--gut);
  border-top: 1px solid var(--rule);
}
.method__in { max-width: var(--maxw); margin: 0 auto; }

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
}
.card {
  padding: clamp(1.6rem, 3.5vw, 2.6rem);
  background: var(--void-800);
  transition: background-color 0.5s var(--ease-mech);
}
.card:hover { background: var(--void-700); }

.card__idx {
  font: 500 0.72rem/1 var(--font-mono);
  letter-spacing: 0.16em;
  color: var(--cyan-dim);
}
.card__h {
  margin: 1.1rem 0 0.9rem;
  font-family: var(--font-serif);
  font-size: clamp(1.35rem, 1.1rem + 0.9vw, 1.85rem);
  line-height: 1.12; letter-spacing: -0.015em;
}
.card__c {
  font-size: 0.95rem; color: var(--void-300);
  text-wrap: pretty;
}
.card__stat {
  margin-top: 1.6rem; padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
  font: 400 0.78rem/1.5 var(--font-mono);
  color: var(--void-400);
}
.card__stat span {
  display: block;
  font-size: 1.5rem; font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--warm);
  font-variant-numeric: tabular-nums;
}

/* ---------- 10. FLEET (horizontal filmstrip) ----------
   Beat 5: the calm after. Scrolls sideways as the page scrolls down. */
.fleet {
  position: relative;
  background: var(--void-800);
  border-top: 1px solid var(--rule);
}
.fleet__sticky {
  position: sticky; top: 0;
  height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  gap: clamp(1.5rem, 4vh, 3rem);
  overflow: hidden;
  /* Top padding clears the fixed nav; the flex centring does the rest,
     so the deck sits on the optical centre of the pin. */
  padding-block: clamp(3.5rem, 8vh, 5rem) 0;
}
.fleet__head {
  max-width: var(--maxw);
  width: 100%;
  margin: 0 auto;
  padding-inline: var(--gut);
}
.fleet__hint {
  margin-top: 0.7rem;
  font: 400 0.75rem/1.5 var(--font-mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--void-400);
}

.strip__vp { overflow: hidden; }
.strip {
  display: flex;
  gap: clamp(0.9rem, 2vw, 1.6rem);
  padding-inline: var(--gut);
  will-change: transform;
}
.frame {
  flex: none;
  width: clamp(15rem, 26vw, 21rem);
  padding: clamp(1.4rem, 2.6vw, 2rem);
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--void-700);
  transition: border-color 0.5s var(--ease-mech);
}
.frame__day {
  font: 500 0.72rem/1 var(--font-mono);
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--void-400);
}
.frame__n {
  margin-top: 1.4rem;
  font: 700 clamp(2.6rem, 2rem + 2.2vw, 4rem)/0.95 var(--font-mono);
  letter-spacing: -0.045em;
  color: var(--void-100);
  font-variant-numeric: tabular-nums;
}
.frame__l {
  margin-top: 0.4rem;
  font: 400 0.78rem/1.4 var(--font-mono);
  letter-spacing: 0.06em;
  color: var(--void-300);
}
.frame__c {
  margin-top: 1.2rem; padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
  font-size: 0.88rem; color: var(--void-300);
  text-wrap: pretty;
}
.frame--warn { border-color: rgba(255, 92, 56, 0.4); background: #16121a; }
.frame--warn .frame__n { color: var(--alert); }
.frame--warn .frame__day { color: var(--alert); }
.frame--sum { border-color: rgba(255, 196, 107, 0.4); background: #171307; }
.frame--sum .frame__n { color: var(--warm); }
.frame--sum .frame__day { color: var(--warm); }

/* Mobile & reduced-motion: a real horizontal swipe deck, not a
   disabled feature. Touch physics do the work instead of scroll. */
.fleet--swipe .fleet__sticky {
  position: static; height: auto;
}
.fleet--swipe .strip__vp {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding-block: 0.5rem;
  scrollbar-width: thin;
  scrollbar-color: var(--void-500) transparent;
}
.fleet--swipe .strip { transform: none !important; }
.fleet--swipe .frame { scroll-snap-align: center; }

/* ---------- 11. PAYOFF ----------
   Beat 6: the motif resolves. Same readout, opposite outcome. */
.payoff {
  background: linear-gradient(180deg, var(--void-800), var(--void-850));
  padding: clamp(7rem, 20vh, 14rem) var(--gut);
  border-top: 1px solid var(--rule);
}
.payoff__in { max-width: var(--maxw); margin: 0 auto; }

.readout--big { max-width: 46rem; border-top-color: var(--rule-strong); }
.readout--big .readout__num {
  font-size: clamp(3.4rem, 1.6rem + 8vw, 8rem);
  color: var(--alert);
  text-shadow: 0 0 60px rgba(255, 92, 56, 0.28);
  transition: color 0.9s var(--ease-mech),
              text-shadow 0.9s var(--ease-mech);
}
/* The turn: the figure clears the danger band and stops being an alarm.
   Colour, glow and the struck-through "before" value all resolve at once. */
.readout--big.is-resolved .readout__num {
  color: var(--safe);
  text-shadow: 0 0 70px rgba(87, 217, 163, 0.3);
}

/* The original 0.412 stays on screen, struck through — the payoff only
   means something next to the number it replaced. */
.readout--big .readout__num::after {
  content: "was 0.412 km";
  /* Sits inline after the unit, on the number's own baseline — placing
     it above collided with the figcaption. */
  align-self: center;
  margin-left: 0.7em;
  font-family: var(--font-mono);
  font-size: 0.17em; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase;
  white-space: nowrap;
  color: var(--void-400);
  text-decoration: line-through;
  text-decoration-color: var(--alert);
  text-decoration-thickness: 1px;
  text-shadow: none;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.7s var(--ease-mech) 0.15s,
              transform 0.8s var(--ease-glide) 0.15s;
}
.readout--big.is-resolved .readout__num::after {
  opacity: 1; transform: none;
}
:root:not(.js-motion) .readout--big .readout__num::after {
  opacity: 1; transform: none;
}
.readout--big .readout__note {
  max-width: 34rem;
  font-size: clamp(1rem, 0.95rem + 0.28vw, 1.18rem);
}
.readout__note--win {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.8s var(--ease-mech) 0.35s,
              transform 0.9s var(--ease-glide) 0.35s;
}
/* Only hidden once JS confirms it will reveal it. */
:root:not(.js-motion) .readout__note--win { opacity: 1; transform: none; }
.readout--big.is-resolved .readout__note--win { opacity: 1; transform: none; }

/* ---------- 12. PRICING ---------- */
.pricing {
  background: var(--void-850);
  padding: var(--band) var(--gut);
  border-top: 1px solid var(--rule);
}
.pricing__in { max-width: var(--maxw); margin: 0 auto; }

.plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  align-items: start;
}
.plan {
  position: relative;
  display: flex; flex-direction: column;
  padding: clamp(1.6rem, 3vw, 2.4rem);
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--void-800);
}
.plan--feat {
  border-color: var(--cyan-dim);
  background: linear-gradient(180deg, rgba(111, 182, 255, 0.06), var(--void-800) 40%);
}
.plan__flag {
  position: absolute; top: -0.7rem; left: clamp(1.6rem, 3vw, 2.4rem);
  padding: 0.25rem 0.6rem;
  background: var(--cyan); color: var(--void-900);
  font: 600 0.65rem/1.4 var(--font-mono);
  letter-spacing: 0.12em; text-transform: uppercase;
  border-radius: 2px;
}
.plan__h {
  font-family: var(--font-serif);
  font-size: 1.5rem; letter-spacing: -0.015em;
}
.plan__p {
  margin: 0.9rem 0 0;
  font: 700 clamp(2rem, 1.6rem + 1.4vw, 2.7rem)/1 var(--font-mono);
  letter-spacing: -0.04em;
  color: var(--void-000);
  font-variant-numeric: tabular-nums;
}
.plan__cur { font-size: 0.5em; vertical-align: 0.55em; color: var(--void-300); }
.plan__per {
  display: block; margin-top: 0.45rem;
  font: 400 0.72rem/1.4 var(--font-mono);
  letter-spacing: 0.06em;
  color: var(--void-400);
}
.plan__c {
  margin-top: 1.1rem;
  font-size: 0.9rem; color: var(--void-300);
  text-wrap: pretty;
}
.plan__list {
  margin: 1.4rem 0 0; padding-top: 1.2rem;
  border-top: 1px solid var(--rule);
  display: grid; gap: 0.6rem;
  font-size: 0.88rem; color: var(--void-200);
}
.plan__list li {
  display: grid; grid-template-columns: 1rem 1fr; gap: 0.5rem;
}
.plan__list li::before {
  content: "+";
  font: 500 0.85rem/1.5 var(--font-mono);
  color: var(--cyan-dim);
}
.plan__cta { margin-top: auto; padding-top: 0; }
.plan .plan__cta { margin-top: 1.8rem; }

/* ---------- 13. BRIEF (CTA) ---------- */
.brief {
  background: var(--void-900);
  padding: var(--band) var(--gut);
  border-top: 1px solid var(--rule);
}
.brief__in { max-width: 44rem; margin: 0 auto; text-align: center; }
.brief__h {
  font-family: var(--font-serif);
  font-size: clamp(2.2rem, 1.3rem + 4vw, 4.4rem);
  line-height: 1.02; letter-spacing: -0.03em;
}
.brief__c {
  margin: 1.4rem auto 0; max-width: 36rem;
  color: var(--void-300);
  text-wrap: pretty;
}

.brief__form {
  display: grid; gap: 1rem;
  margin-top: 2.6rem;
  text-align: left;
}
@media (min-width: 640px) {
  .brief__form {
    grid-template-columns: 1fr 10rem auto;
    align-items: end;
  }
  .brief__note { grid-column: 1 / -1; }
}
.field { display: grid; gap: 0.45rem; }
.field__l {
  font: 500 0.72rem/1 var(--font-mono);
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--void-400);
}
.field__i {
  padding: 0.85rem 1rem;
  background: var(--void-800);
  border: 1px solid var(--rule-strong);
  border-radius: 3px;
  color: var(--void-000);
  font: 400 0.95rem/1.4 var(--font-sans);
  transition: border-color 0.3s var(--ease-mech), background-color 0.3s var(--ease-mech);
}
.field__i::placeholder { color: var(--void-400); }
.field__i:focus { border-color: var(--cyan); background: var(--void-700); }
.field__i:user-invalid { border-color: var(--alert); }

.brief__note {
  margin-top: 0.4rem;
  font: 400 0.78rem/1.5 var(--font-mono);
  color: var(--void-400);
  text-align: center;
}
.brief__note.is-ok { color: var(--safe); }
.brief__note.is-err { color: var(--alert); }

/* ---------- 14. FOOTER ---------- */
.foot {
  background: var(--void-900);
  border-top: 1px solid var(--rule);
  padding: clamp(3rem, 8vh, 5rem) var(--gut);
}
.foot__in { max-width: var(--maxw); margin: 0 auto; }
.foot__brand {
  font: 700 0.9rem/1 var(--font-sans);
  letter-spacing: 0.2em;
  color: var(--void-100);
}
.foot__c {
  max-width: 30rem; margin-top: 0.9rem;
  font-size: 0.88rem; color: var(--void-400);
}
.foot__nav {
  display: flex; flex-wrap: wrap; gap: 1.4rem;
  margin-top: 1.8rem; padding-top: 1.6rem;
  border-top: 1px solid var(--rule);
  font-size: 0.85rem;
}
.foot__nav a { color: var(--void-300); text-decoration: none; }
.foot__nav a:hover { color: var(--cyan); }
.foot__fine {
  max-width: 38rem; margin-top: 1.6rem;
  font: 400 0.74rem/1.6 var(--font-mono);
  color: var(--void-500);
}

/* ---------- 15. REVEAL PRIMITIVES ----------
   Every hidden state is gated behind .js-motion on <html>, which
   main.js sets only when it will actually run the animation.
   Reduced-motion and no-JS therefore never see a hidden element. */
.js-motion [data-lift] {
  opacity: 0;
  transform: translateY(22px);
}
.js-motion [data-lift].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.75s var(--ease-mech),
              transform 0.95s var(--ease-glide);
  transition-delay: calc(var(--d, 0) * 90ms);
}

/* Cards rise with a touch of scale — heavier objects, slower curve. */
.js-motion [data-card] {
  opacity: 0;
  transform: translateY(30px) scale(0.985);
}
.js-motion [data-card].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.7s var(--ease-mech),
              transform 1s var(--ease-glide);
  transition-delay: calc(var(--d, 0) * 110ms);
}

/* Word-level reveal, used once, on the thesis line only. */
.js-motion [data-word] {
  opacity: 0;
  transform: translateY(0.42em) rotate(1.2deg);
}
.js-motion [data-word].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.6s var(--ease-mech),
              transform 0.85s var(--ease-glide);
  transition-delay: calc(var(--d, 0) * 55ms);
}

/* ---------- 16. REDUCED MOTION ----------
   Belt and braces: even if .js-motion were set, kill the movement
   and leave everything in its final, visible state. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .js-motion [data-lift],
  .js-motion [data-card],
  .js-motion [data-word],
  .readout__note--win {
    opacity: 1 !important;
    transform: none !important;
  }
  .hero__cue { display: none; }
  .prog { display: none; }
}
