*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { height: 100%; }
body {
  font-family: var(--font-sans);
  color: var(--black);
  background: var(--white);
  overflow: hidden;               /* the engine owns scrolling */
  height: 100vh;
  -webkit-font-smoothing: antialiased;
}
body.footer-mode { overflow: hidden; } /* engine still owns scroll in footer */

h1, h2, h3, p { margin: 0; font-weight: 400; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; border: 0; background: none; cursor: pointer; padding: 0; }
ul { margin: 0; padding: 0; list-style: none; }

.headline { font-size: var(--fs-h2); line-height: var(--lh-tight); letter-spacing: var(--ls-tight); }
.body-copy { font-size: var(--fs-body); line-height: 1.35; }
.fine-print { font-size: var(--fs-fine); color: inherit; }

/* pills */
.pill {
  display: inline-flex; align-items: center; gap: 0.5em;
  height: var(--pill-h); padding: 0 1.5vw;
  border-radius: 999px; font-size: var(--fs-nav); font-weight: 500;
  white-space: nowrap;
}
.cta {
  display: inline-flex; align-items: center; gap: 0.5em;
  border-radius: 100px; font-size: var(--fs-cta);
  padding: 0.97vw 1.38vw; width: fit-content;
}
.cta-solid-white { background: var(--white); color: var(--black); }
.cta-outline { background: transparent; color: var(--black); border: 1px solid var(--black); }
.cta-solid-green { background: var(--green); color: var(--black); }

/* deck sections */
#scroll-root { position: fixed; inset: 0; }
.deck-section {
  position: absolute; inset: 0;
  visibility: hidden;
  --p: 0; /* local progress 0..1, set by engine */

  /* --- boundary exit -------------------------------------------------------
     The engine crossfades two sections over 35% of a viewport, and at the
     middle of that window BOTH sit near 60% opacity. Two headlines in the same
     spot at 60% read as interleaved ghost text, so the outgoing section's copy
     leaves early instead of riding the crossfade down.

     `--out` runs 0 -> 1 across the FIRST 40% of the exit crossfade. Derivation:
     the window is half a crossfade wide on each side of the boundary, i.e.
     h = 0.175 / --sec-len in local progress, so
        out = (p - 1 + h) / (0.8h) = (p - 1) * 1.25/h + 1.25
     and 1.25/h = 7.142857 * --sec-len. It is a pure function of --p, so
     scrubbing back brings the copy home exactly.

     --sec-len is written by each section module in mount() from the same
     constant it registers as `length`. The default of 1 is only a safety net. */
  --sec-len: 1;
  --out-k: calc(7.142857 * var(--sec-len));
  --out: clamp(0, (var(--p) - 1) * var(--out-k) + 1.25, 1);
  --out-lift: 6vh;
}
.deck-section.active { visibility: visible; }

/* The lift rides the independent `translate` property, not `transform`, so it
   composes with the per-section parallax instead of replacing it. Sections that
   write these properties on a column themselves (02-plus: opacity, 05-tags:
   translate) fold --out into their own value — see those files. */
.deck-section .col-left,
.deck-section .col-right,
.deck-section .footnote {
  translate: 0 calc(var(--out) * var(--out-lift) * -1);
}
.deck-section .col-left,
.deck-section .col-right {
  opacity: calc(1 - var(--out));
}

/* Footnotes are the one place where the exit and the ENTRANCE want the same
   property: several sections put `footnote` and `enter-item` on the same link,
   and .enter-item transitions opacity over .6s — far too slow to track a scrub
   through a ~0.1s crossfade. `filter: opacity()` is a second, untransitioned
   channel that simply multiplies with whatever opacity the element already has
   (entrance, hover), so neither effect has to know about the other. */
.deck-section .footnote {
  filter: opacity(calc(1 - var(--out)));
}

/* three-column section template */
.col-left {
  position: absolute; left: var(--content-margin); top: 50%;
  transform: translateY(-50%); width: 26vw; z-index: 3;
}
.col-right {
  position: absolute; right: var(--content-margin); top: 50%;
  transform: translateY(-50%); width: 24vw; z-index: 3;
  display: flex; flex-direction: column; gap: 1.9vw; align-items: flex-start;
}
.footnote {
  position: absolute; left: var(--content-margin); bottom: 2.2vw;
  font-size: var(--fs-fine); text-decoration: underline; z-index: 3;
}

/* entrance animation helper: engine toggles .entered on section activation */
.enter-item { opacity: 0; transform: translateY(var(--enter-shift)); transition: opacity .6s var(--ease-out), transform .6s var(--ease-out); }
.entered .enter-item { opacity: 1; transform: none; }
.entered .enter-item:nth-child(2) { transition-delay: .06s; }
.entered .enter-item:nth-child(3) { transition-delay: .12s; }
.entered .enter-item:nth-child(4) { transition-delay: .18s; }

@media (prefers-reduced-motion: reduce) {
  .enter-item { transition: none; }
  /* keep the early fade — it is what stops the ghosting — but drop the travel */
  .deck-section { --out-lift: 0px; }
}

@media (max-width: 768px) {
  .col-left { width: 80vw; top: 12vh; transform: none; }
  .col-right { width: 80vw; left: var(--content-margin); right: auto; top: auto; bottom: 8vh; transform: none; }

  /* Touch targets. The footnote is 12px type, so its own box is ~14px tall —
     well under the 40px a thumb needs. The padding grows the hit area and the
     equal negative margin takes it back out of the layout, so the words do not
     move: an absolutely positioned footnote keeps its `bottom`, and an
     inline-block link inside one keeps its line box. */
  .deck-section a.footnote,
  .deck-section .footnote > a {
    padding-block: 14px;
    margin-block: -14px;
  }
}
