/* ALPHARADAR — scroll-scrubbed camera flight.

   The flight is an image sequence painted to a canvas, one real frame per
   scroll position. Seeking a <video> instead costs a decode per scroll event,
   so the picture arrives late and in jumps — that is what makes scrubbed video
   read as still images swapping rather than a moving camera. */

#flight-stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: #05080F;
  overflow: hidden;
}
#flight-canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

/* Released once the hero is past, or the fixed backdrop covers the whole page
   and nothing below is reachable. */
#flight-stage.is-released { visibility: hidden; pointer-events: none; }

/* Scroll length of the flight. Long, so the camera reads slow and cinematic
   rather than racing past. */
#flight-scroll { height: 760svh; pointer-events: none; }

/* ---- hero copy --------------------------------------------------------
   The flight is the landing page, not a backdrop for a headline. The copy
   shows briefly at the very top, clears out of the way for the whole flight,
   and returns at the end so the CTA and capital widget are usable.

   !important: the section carries an inline `position:relative;
   min-height:100svh` and inline styles beat stylesheets — without this the
   hero never pins, it scrolls away and is un-clickable where it appears. */
#top.hero-overlay {
  position: fixed !important;
  inset: 0;
  z-index: 20;
  min-height: 0 !important;
  overflow: hidden;
  will-change: opacity;
}
#top.hero-overlay.is-released { visibility: hidden; pointer-events: none; }

/* The inherited scrim was built for a near-black backdrop and flattens the
   flight to nothing. Keep it light — just enough to hold the type. */
#top.hero-overlay .hero-scrim-a { opacity: .35; }
#top.hero-overlay .hero-scrim-b {
  background: linear-gradient(180deg, rgba(8,12,22,0.62) 0%, rgba(8,12,22,0.20) 42%, rgba(8,12,22,0.72) 100%) !important;
}
#top.hero-overlay .hero-rings { opacity: .14 !important; }

/* NOTE: deliberately no prefers-reduced-motion override here.
   A scroll-scrubbed sequence has no self-running animation — it moves only as
   far as the visitor scrolls it, and stops the instant they stop. Collapsing
   the spacer under reduced-motion killed the flight outright (scrollLen 1) on
   any machine with Windows animation effects switched off. The JS drops the
   easing instead, so the frame tracks scroll exactly with nothing in motion
   that the visitor did not drive. */


/* ---- narrative captions ------------------------------------------------
   One beat at a time, left-aligned against a soft scrim so the type stays
   legible over the brightest frames (the convergence) without flattening the
   image. Same type system as the rest of the page. */
#flight-copy {
  position: fixed;
  inset: 0;
  z-index: 10;
  pointer-events: none;
}
#flight-copy::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, rgba(5,8,15,0.80) 0%, rgba(5,8,15,0.42) 34%, rgba(5,8,15,0) 62%);
  opacity: 0;
  transition: opacity .45s ease;
}
#flight-copy.has-beat::before { opacity: 1; }

.fc {
  position: absolute;
  left: clamp(24px, 7vw, 132px);
  top: 50%;
  margin: 0;
  max-width: min(46ch, 44vw);
  opacity: 0;
  transform: translateY(calc(-50% + 26px));
  will-change: opacity, transform;
}
.fc span {
  display: block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: #5FD3F3;
  margin-bottom: 18px;
}
.fc p {
  margin: 0;
  font-weight: 200;
  font-size: clamp(30px, 4.2vw, 62px);
  line-height: 1.06;
  letter-spacing: -0.03em;
  color: #E9EFF8;
  text-wrap: balance;
}

@media (max-width: 900px) {
  .fc { max-width: 78vw; left: 24px; }
  #flight-copy::before {
    background: linear-gradient(180deg, rgba(5,8,15,0.30) 0%, rgba(5,8,15,0.72) 55%, rgba(5,8,15,0.82) 100%);
  }
}


/* ---- opening vs return -------------------------------------------------
   The opening frame carries one idea: badge, headline, one action. The
   latency readout, the second CTA and the capital widget are held back for
   the return at the end of the flight, where a visitor who has just watched
   the story is far likelier to use them. */
.hero-extra {
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
  transition: opacity .5s ease, transform .5s ease;
}
#top.is-return .hero-extra {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* ---- scroll affordance -------------------------------------------------
   No text (the copy rule holds) — a travelling line that says "this scrolls". */
#scroll-cue {
  position: absolute;
  left: 50%;
  bottom: clamp(22px, 4vh, 46px);
  z-index: 3;
  width: 1px;
  height: 54px;
  margin-left: -0.5px;
  background: rgba(233,239,248,0.16);
  overflow: hidden;
  transition: opacity .4s ease;
}
#scroll-cue i {
  position: absolute;
  left: 0; top: -60%;
  width: 100%; height: 60%;
  background: linear-gradient(180deg, rgba(95,211,243,0) 0%, #5FD3F3 100%);
  animation: cue 2.1s cubic-bezier(.6,0,.35,1) infinite;
}
@keyframes cue {
  0%   { transform: translateY(0); opacity: 0; }
  22%  { opacity: 1; }
  75%  { opacity: 1; }
  100% { transform: translateY(266%); opacity: 0; }
}
#top.is-return #scroll-cue { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  /* keep the affordance, drop the travel */
  #scroll-cue i { animation: none; top: 40%; opacity: .9; }
}


/* ---- fixes to the opening / return states ------------------------------ */

/* The secondary CTA must leave the FLEX ROW at the top, not just go
   transparent — an invisible-but-present button pushed the primary 93px
   off centre. */
#top:not(.is-return) a.hero-extra { display: none; }

/* On the return the hero carries everything again: 871px of content in a
   950px viewport overflowed its own padding and pushed the badge up under
   the fixed header. Tighten the vertical rhythm for that state only. */
#top.is-return .hero-flanks { margin-top: 24px !important; }
#top.is-return .hero-sub    { margin-top: 18px !important; }
#top.is-return .hero-cta    { margin-top: 22px !important; }
#top.is-return .hero-extra[style*="margin-top:22px"] { margin-top: 14px !important; }
#top.is-return .hero-inner > div[style*="max-width:560px"] { margin-top: 26px !important; }

/* Safety net for short viewports: scale the block to fit rather than clip it.
   Set from JS, which is the only place that knows the measured height. */
.hero-inner { transform-origin: center center; }

/* The ascent frames are the brightest in the flight and the hero returns over
   them — at the default scrim the subhead was unreadable against the beam. */
#top.is-return .hero-scrim-a { opacity: .5; }
#top.is-return .hero-scrim-b {
  background:
    radial-gradient(58% 46% at 50% 46%, rgba(5,8,15,0.72), rgba(5,8,15,0) 72%),
    linear-gradient(180deg, rgba(8,12,22,0.84) 0%, rgba(8,12,22,0.62) 45%, rgba(8,12,22,0.92) 100%) !important;
}


/* ---- two headlines ------------------------------------------------------
   The opening states the philosophy a trader recognises; the return states
   the promise, as the page hands over to the static content. */
.h-return { display: none; }
#top.is-return .h-open   { display: none; }
#top.is-return .h-return { display: inline; }

/* The opening carries no action at all. A button above the fold competes with
   the flight, and clicking it would skip the whole thing — the nav keeps
   "Get started" available for anyone who will not scroll. */
#top:not(.is-return) .hero-cta { display: none; }


/* The light column runs straight through the opening subhead too — same
   problem as the return, milder. A soft radial behind the type block only,
   so the rest of the frame keeps its contrast. */
#top:not(.is-return) .hero-scrim-b {
  background:
    radial-gradient(52% 30% at 50% 30%, rgba(5,8,15,0.58), rgba(5,8,15,0) 72%),
    linear-gradient(180deg, rgba(8,12,22,0.62) 0%, rgba(8,12,22,0.20) 42%, rgba(8,12,22,0.72) 100%) !important;
}
