/* Entrada — the scrubbed hero.
   Structure: a tall .hero__track supplies scroll distance; .hero__stage pins
   inside it with position:sticky (native scroll only — no smooth-scroll
   library, which is what keeps sticky honest on iOS Safari).

   Copy is organised as *beats*: stacked blocks occupying the same space that
   arrive and leave as the camera travels. They are absolutely positioned, so
   an unarrived beat reserves no layout — no dead space at load, no CLS. */

.hero {
  position: relative;
  background: var(--bg-0);
}

.hero__track {
  /* Scroll distance for the flight. Shorter on mobile: a phone user pays for
     every swipe, so the same frames play out over 240vh instead of 340. */
  height: 240vh;
}

.hero__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  min-height: 560px;
  overflow: hidden;
}

/* --- The panel: a 9:16 film frame ---------------------------------------- */

.hero__panel {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* First paint is never a dark hole: a blurred still of frame 0, inlined in
     the HTML as a 338-byte data URI, so it costs no request and paints with
     the document. */
  background: var(--bg-0) center / cover no-repeat;
  background-image: var(--lqip);
  /* Own compositing layer: the canvas repaints every frame and must not
     invalidate the copy above it. */
  will-change: transform;
  transform: translate3d(0, 0, 0);
  /* Slow push-in across the flight, written by JS. Composites with the
     `translate` used for centring on desktop. */
  scale: var(--push, 1);
}

.hero__canvas {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The LQIP lives on the panel behind (see .hero__panel), so the canvas can
     cross-fade over it once frame 0 has decoded. */
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-camera);
}

.hero.is-ready .hero__canvas { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .hero__canvas { opacity: 1; transition: none; }
}

.hero__vignette,
.hero__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.hero__vignette {
  background:
    radial-gradient(120% 85% at 50% 42%, transparent 40%, rgba(6, 8, 10, 0.75) 100%);
}

/* On a phone the copy sits *on* the frame, and frame 0 is a bright interior —
   so the scrim has to be heavy enough that the hook is legible in the first
   second regardless of which frame is showing. It is weighted to the bottom
   half, which leaves the architecture in the top half clean. */
.hero__scrim {
  background: linear-gradient(
    to top,
    rgba(6, 8, 10, 0.97) 0%,
    rgba(6, 8, 10, 0.94) 38%,
    rgba(6, 8, 10, 0.80) 52%,
    rgba(6, 8, 10, 0.42) 64%,
    rgba(6, 8, 10, 0.12) 78%,
    transparent 90%
  );
}

/* Film grain. A 96px tile stepped by transform — no per-frame filter, which
   is what normally makes grain expensive. */
.hero__grain {
  position: absolute;
  inset: -50%;
  pointer-events: none;
  background-image: url("../assets/hero/grain.png");
  opacity: 0.14;
  mix-blend-mode: overlay;
  animation: grain 1.2s steps(6) infinite;
}

@keyframes grain {
  0%   { transform: translate3d(0, 0, 0); }
  16%  { transform: translate3d(-3%, 2%, 0); }
  33%  { transform: translate3d(2%, -3%, 0); }
  50%  { transform: translate3d(-2%, -2%, 0); }
  66%  { transform: translate3d(3%, 1%, 0); }
  83%  { transform: translate3d(-1%, 3%, 0); }
  100% { transform: translate3d(0, 0, 0); }
}

/* --- Copy: the beat stack ------------------------------------------------ */

.hero__copy {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;   /* re-enabled on the live beat only */
}

.hero__beat {
  position: absolute;
  left: 50%;
  bottom: 0;
  translate: -50% 0;
  width: 100%;
  max-width: var(--measure);
  /* Always reserve the dock's height, docked or not, so copy never jumps when
     the dock arrives and never sits under it once it has. */
  padding: 0 var(--gutter) calc(var(--cta-dock-h) + clamp(14px, 3vh, 26px));

  /* --a (alpha) and --y (px) are written by JS from scroll progress.
     Motion is always transform + opacity together, never opacity alone. */
  opacity: var(--a, 1);
  transform: translate3d(0, calc(var(--y, 0) * 1px), 0);
  will-change: transform, opacity;
}

.hero__beat.is-live { pointer-events: auto; }

/* Below 900px the copy sits directly on the frame, so each beat carries its
   own backing wash. Anchoring it to the beat box (rather than pushing the
   page-level scrim higher) buys legibility for the small gold eyebrow without
   blacking out another 15% of the image. Fades in with the beat. */
@media (max-width: 899px) {
  .hero__beat::before {
    content: "";
    position: absolute;
    inset: -150px calc(var(--gutter) * -1) 0;
    z-index: -1;
    pointer-events: none;
    /* Holds strength to ~88% so the eyebrow — the smallest, lowest-contrast
       type in the beat — is still inside the dark zone, then releases. */
    background: linear-gradient(
      to top,
      rgba(6, 8, 10, 0.66) 0%,
      rgba(6, 8, 10, 0.64) 70%,
      rgba(6, 8, 10, 0.50) 88%,
      transparent 100%
    );
  }
}

/* Children lag the beat slightly, so a beat *assembles* rather than sliding
   in as one rigid card. 60–70ms apart, never more. */
.hero__beat > * {
  transform: translate3d(0, calc(var(--y, 0) * var(--lag, 0) * 0.35px), 0);
}
.hero__beat > :nth-child(1) { --lag: 0; }
.hero__beat > :nth-child(2) { --lag: 1; }
.hero__beat > :nth-child(3) { --lag: 2; }
.hero__beat > :nth-child(4) { --lag: 3; }
.hero__beat > :nth-child(5) { --lag: 4; }

.hero__eyebrow { margin-bottom: 16px; }

/* The hook. Painted at full opacity at frame zero, never animated in. This is
   the LCP element — it survives a one-second bounce. */
.hero__h1 {
  max-width: 14ch;
  margin-bottom: 20px;
}

/* The italic carries the turn in every headline: the first half states the
   problem in roman, the second half answers it in gold italic. */
.hero__h1 em { font-style: italic; color: var(--gold); }

.hero__display {
  font-family: var(--font-display);
  font-size: var(--t-display);
  font-weight: 300;
  line-height: 1.06;
  letter-spacing: var(--track-display);
  max-width: 17ch;
  margin-bottom: 20px;
  text-wrap: balance;
}
.hero__display em { font-style: italic; color: var(--gold); }

.hero__lede {
  font-family: var(--font-display);
  color: var(--ink-dim);
  font-size: var(--t-lede);
  line-height: 1.4;
  letter-spacing: 0;
  max-width: 40ch;
  margin-bottom: 24px;
}

.hero__proof {
  display: flex;
  flex-direction: column;
  gap: 11px;
  margin-bottom: 24px;
  list-style: none;
  color: var(--muted);
  font-size: var(--t-body);
  max-width: 46ch;
}

.hero__proof li {
  display: flex;
  align-items: baseline;
  gap: 12px;
}

.hero__proof li::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--gold);
  flex: none;
  translate: 0 -3px;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

.hero__note {
  margin-top: 14px;
  color: var(--muted);
  font-size: var(--t-micro);
}

/* Phones: one full-width primary, and the secondary demoted to a quiet link.
   Two stacked gold-weight buttons cost ~110px of the only screen that
   matters and make the visitor choose between them. */
@media (max-width: 559px) {
  .hero__h1 { font-size: clamp(35px, 8.6vw, 66px); margin-bottom: 16px; }
  /* Shorter copy block = the whole beat sits inside the dark zone of the
     scrim, which is what keeps gold legible over a bright frame. */
  .hero__lede { font-size: 16px; line-height: 1.4; margin-bottom: 20px; }
  .hero__display { font-size: clamp(30px, 7.8vw, 54px); }
  .hero__proof { font-size: 15px; gap: 9px; }

  .hero__actions { flex-direction: column; align-items: stretch; gap: 6px; }
  .hero__actions .btn { width: 100%; }

  .hero__actions .btn-ghost {
    border: none;
    background: none;
    min-height: 44px;
    padding: 10px 0;
    color: var(--muted);
    font-weight: 400;
    text-decoration: underline;
    text-underline-offset: 4px;
    text-decoration-color: var(--line);
  }
  .hero__actions .btn-ghost:hover { color: var(--gold); }
}

/* --- Progress rail --------------------------------------------------------
   A hairline that fills as the flight advances. It is the only affordance
   telling you the hero is a controllable camera rather than a stuck page. */

.hero__rail {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: 0;
  z-index: 3;
  height: 1px;
  background: var(--line);
  pointer-events: none;
}

.hero__rail::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  background: linear-gradient(to right, var(--gold-dim), var(--gold));
  transform-origin: 0 50%;
  scale: var(--p, 0) 1;
}

.hero__cue {
  position: absolute;
  left: 50%;
  bottom: 14px;
  z-index: 3;
  translate: -50% 0;
  width: 1px;
  height: 40px;
  background: linear-gradient(to bottom, transparent, var(--gold-dim));
  opacity: var(--cue, 1);
  pointer-events: none;
}

.hero__cue::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, transparent, var(--gold));
  animation: cue 2.4s var(--ease-camera) infinite;
}

@keyframes cue {
  0%, 100% { transform: translateY(-100%); opacity: 0; }
  40%      { opacity: 1; }
  70%      { transform: translateY(100%); opacity: 0; }
}

/* --- Desktop: type beside the frame, not on top of it -------------------- */

@media (min-width: 900px) {
  .hero__track { height: 340vh; }

  /* The panel stops being full-bleed and becomes an actual 9:16 film frame
     floating right of the type. A vertical source is never cropped into a
     horizontal hole — the frame keeps the aspect the footage was shot in. */
  .hero__panel {
    inset: auto;
    right: max(var(--gutter), calc(50vw - (var(--measure) / 2)));
    top: 50%;
    translate: 0 -50%;
    width: min(29vw, 372px);
    height: min(76vh, 660px);
    border: 1px solid var(--line);
    border-radius: 4px;
    box-shadow:
      0 40px 120px -30px rgba(0, 0, 0, 0.9),
      0 0 0 1px rgba(201, 162, 39, 0.05);
  }

  /* No copy sits on the panel at this width, so the scrim stops being a
     legibility device and becomes a grounding shadow only. */
  .hero__scrim {
    background: linear-gradient(to top, rgba(6, 8, 10, 0.42) 0%, transparent 24%);
  }

  .hero__beat {
    bottom: auto;
    top: 50%;
    translate: -50% -50%;
    padding-bottom: 0;
    /* Leave the right third to the panel. */
    padding-right: min(40vw, 470px);
  }

  .hero__h1 { max-width: 12ch; }
  .hero__display { max-width: 15ch; }
  .hero__cue { left: var(--gutter); translate: 0 0; }
}

@media (min-width: 1400px) {
  .hero__panel { width: 396px; }
}

/* --- Reduced motion: a genuinely good static hero -------------------------
   Same content, same order, same hierarchy. Every beat is simply present, the
   flight becomes a still, nothing moves. */

@media (prefers-reduced-motion: reduce) {
  .hero__track { height: auto; }

  .hero__stage {
    position: static;
    height: auto;
    min-height: 0;
    overflow: visible;
    padding: clamp(88px, 12vh, 150px) 0 clamp(40px, 7vh, 80px);
  }

  .hero__copy {
    position: static;
    pointer-events: auto;
    display: flex;
    flex-direction: column;
    gap: clamp(56px, 9vh, 96px);
  }

  .hero__beat,
  .hero__beat > * {
    position: static;
    translate: none;
    transform: none;
    opacity: 1;
    max-width: var(--measure);
    margin-inline: auto;
    padding-bottom: 0;
  }
  .hero__beat > * { margin-inline: 0; }

  .hero__grain { animation: none; }
  .hero__cue,
  .hero__rail { display: none; }

  .hero__panel {
    position: relative;
    inset: auto;
    translate: none;
    scale: none;
    width: min(72vw, 290px);
    height: auto;
    aspect-ratio: 9 / 16;
    margin: 44px auto 0;
    border: 1px solid var(--line);
    border-radius: 4px;
  }

  .hero__scrim { background: none; }

  @media (min-width: 900px) {
    /* Same left-type / right-frame relationship as the animated hero, just
       without the pin. The stage becomes the measure container so the panel
       cannot bleed past the gutter. */
    .hero__stage {
      display: flex;
      align-items: center;
      gap: clamp(40px, 5vw, 76px);
      max-width: var(--measure);
      margin-inline: auto;
      padding-inline: var(--gutter);
    }
    .hero__copy { flex: 1; min-width: 0; }
    .hero__beat { max-width: none; padding-inline: 0; }
    .hero__panel { order: 2; flex: none; width: 330px; margin: 0; }
  }
}
