/* choreo.css — the styling the scroll choreography needs, and nothing else.

   ONE RULE GOVERNS THIS WHOLE FILE.

   Every selector here describes the FINISHED state. Nothing starts hidden,
   offset, scaled or clipped in CSS. The starting values are set at run time by
   choreo.js, which only runs when GSAP has loaded and the reader has not asked
   for reduced motion.

   That ordering is the accessibility guarantee, and it is the opposite of the
   usual one. If the script fails, the bundle 404s, the browser is old, or
   motion is switched off, the page renders as a finished, readable document
   rather than as a stack of invisible elements waiting for an animation that
   is never coming. There is no `opacity: 0` anywhere in this file, and adding
   one would quietly make the site depend on JavaScript to be legible. */

/* ───────────────────────────────────────────────── 1. kinetic typography */

/* The hero headline stops being one block. The words are separate elements so
   they can be scaled and moved independently, but they are still ordinary
   inline text in the same order, so the h1 reads exactly as it did to a screen
   reader or a crawler. */
.t-hero[data-kinetic] { display: block; }
.t-hero[data-kinetic] .k-w {
  display: inline-block;
  /* Transforms happen around the word's own left edge so a scaling word grows
     into the line rather than drifting off it. */
  transform-origin: 0% 60%;
  will-change: transform;
}

/* ─────────────────────────────────────────────────── 2. giant statements */

/* A statement is the page's strongest sentence given most of a viewport. It is
   the same words that were in the paragraph before, lifted out so the
   typography can carry them, not new copy. */
.statement {
  margin: 0;
  font-family: var(--f-display, inherit);
  font-weight: 600;
  letter-spacing: -.035em;
  line-height: 1.04;
  text-wrap: balance;
  /* SIZED DOWN FROM 104px.

     At 7.6vw this ran to four lines of very large type on a desktop, and a
     sentence broken across four lines stops being one statement and becomes a
     list. It is still comfortably the largest type on the page, which is the
     job; it no longer has to shout to do it. */
  font-size: clamp(24px, 3.9vw, 52px);
  max-width: 21ch;
}
.statement .s-w { display: inline-block; transform-origin: 0% 70%; will-change: transform; }
/* The three negations carry different weight, which is what stops it reading
   as one long shout. */
.statement .s-soft { color: var(--muted); }
.statement .s-hard { color: var(--ink); }

.statement-block {
  /* Room to stand apart from the paragraphs either side, without the empty
     half-screen the full-viewport version left above and below it. */
  min-height: min(46vh, 400px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(40px, 9vh, 110px) 0;
  /* clip, never hidden: an ancestor with overflow-x:hidden silently kills
     position:sticky anywhere inside it, and there are pins below. */
  overflow-x: clip;
}

/* ───────────────────────────────────────────── 3. the pinned demo (#how) */

/* The pin needs a tall track and a viewport-height stage. Both are set here so
   the section still reads correctly with no JavaScript: without the pin it is
   simply a tall section with the mechanism at the top, which is what it was
   before any of this. */
.pin-track { position: relative; overflow-x: clip; }
.pin-stage { position: relative; }

/* While the section is pinned it owns the whole viewport, so its content is
   centred in it. Without this the heading, the beat and the mechanism sit in
   the upper two thirds and the bottom third is dead space that the reader
   stares at for four states. Only applied when the choreography is actually
   running, because unpinned this would stretch an ordinary section for no
   reason. */
.is-choreographed .pin-stage {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* The section's own vertical padding sits OUTSIDE that 100vh, which made the
   pinned element taller than the viewport and left a band of empty surface
   above the heading for the whole sequence. While pinned the stage provides
   the spacing instead. */
.is-choreographed { padding-block: 0; }

@media (min-width: 861px) {
  /* The two-column pinned layout: instruction anchored left, product right.
     The mechanism comes FIRST in the document, because that is the order the
     section has always had and the order it keeps with no JavaScript and on a
     phone. `order` moves it to the right column without moving it in the
     markup, so the reading order and the visual order can differ where that
     is the better answer for each. */
  .how-pinned {
    display: grid;
    grid-template-columns: minmax(280px, 0.86fr) 1.14fr;
    gap: clamp(32px, 5vw, 72px);
    align-items: center;
  }
  .how-pinned .how-copy { order: 1; }
  .how-pinned .how-demo { order: 2; }
}
/* Below the pin width the two simply stack in document order. */
.how-copy { min-width: 0; }
.how-demo { min-width: 0; }

/* The state counter that sits with the anchored heading. */
.state-mark {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-variant-numeric: tabular-nums;
}
.state-mark .sm-n {
  font-size: clamp(40px, 6vw, 74px);
  font-weight: 700;
  letter-spacing: -.05em;
  line-height: 1;
  color: var(--ink);
}
.state-mark .sm-of { font-size: 13px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); }

/* When the demo is pinned the four beats stop being a four-column grid and
   become a stack, because only one of them is the current state. The grid is
   restored for everyone who does not get the pin. */
.is-choreographed .flow { grid-template-columns: 1fr; }
.is-choreographed .flow-item {
  border-left: 0;
  padding: 0;
  /* Each beat occupies the same space, so advancing a state does not move the
     layout under the reader. */
  grid-area: 1 / 1;
}
.is-choreographed .flow-item.dim { opacity: 0; pointer-events: none; }
.is-choreographed .flow-item .flow-n { margin-bottom: 14px; }
.is-choreographed .flow { display: grid; min-height: 190px; }

}

/* ────────────────────────────────────────────────── 5. spatial elements */

/* Cards that will be scattered and then converge. The final layout is the
   ordinary document layout; choreo.js moves them away from it and brings them
   back, so the resting state is the real one. */
[data-spatial] { will-change: transform; }

/* The markets table converges via Flip, which measures real positions. It
   needs a containing block that does not clip mid-flight. */
#markets { overflow-x: clip; }

/* ──────────────────────────────────────────────────────── 6. pop-ins */

/* Small things arrive physically rather than fading. The keyframes are here so
   a pop can be triggered by adding a class from anywhere, including from CSS
   driven interactions that never touch GSAP. */
@keyframes pop-in {
  0%   { transform: scale(.88); }
  62%  { transform: scale(1.03); }
  100% { transform: scale(1); }
}
.pop {
  animation: pop-in .34s cubic-bezier(.2, .9, .25, 1) both;
  transform-origin: 50% 70%;
}
/* Staggering by index without a timeline, for groups that arrive together. */
.pop-1 { animation-delay: .04s; }
.pop-2 { animation-delay: .08s; }
.pop-3 { animation-delay: .12s; }

/* ──────────────────────────────────────────────────────── 7. stillness */

/* The answers section is deliberately the quiet one. Nothing here moves on
   scroll; this only stops the section inheriting a pin's clipping context. */
#answers { overflow-x: clip; }

/* ─────────────────────────────────────────────────────── reduced motion */

/* choreo.js does not run at all under reduced motion, so there is nothing to
   switch off. These two rules cover the styling that exists regardless: the
   pop keyframes, which CSS can trigger on its own, and the statement, which
   stays large because size is typography rather than motion. */
@media (prefers-reduced-motion: reduce) {
  .pop { animation: none; }
  .statement-block { min-height: 0; padding: clamp(24px, 5vh, 56px) 0; }
}
