/* =========================================================================
   Design Warehouse — motion.css
   Every move the site makes: line-mask reveals, rise-and-fade, scroll-lit
   prose, parallax, counters and the marquee. Anything hidden by default is
   scoped under `html.js`, so the page stays fully readable with JavaScript
   disabled.
   ========================================================================= */

/* ----------------------------------------------------------------
   LINE MASK REVEAL
   Each line sits in its own mask and slides up.

   The mask needs vertical slack, because these headings run at a
   line-height (0.92) that is smaller than the font's own ink box — so
   ascenders and descenders genuinely overflow the line box and a plain
   overflow:hidden would shave them off. Padding buys the slack and a
   matching negative margin gives it back, which only works if the
   headings are flex columns, since sibling margins would otherwise
   collapse and undo the compensation. Hence .lines.
   ---------------------------------------------------------------- */
.lines {
  display: flex;
  flex-direction: column;
}

.line {
  display: block;
  flex: 0 0 auto;
  overflow: hidden;
  padding: 0.14em 0 0.2em;
  margin: -0.14em 0 -0.2em;
}

.line__inner {
  display: block;
  transition: transform 1000ms var(--ease-out-expo);
  transition-delay: calc(var(--i, 0) * var(--stagger-line));
}

/* 135% clears the mask at every line-height in use while keeping the
   travel short enough that the reveal still reads as a lift, not a slide. */
.js .line__inner { transform: translateY(135%); }
.js .is-in .line__inner { transform: translateY(0); }

/* ----------------------------------------------------------------
   RISE + FADE
   Descendants of a revealed group stagger in source order.
   ---------------------------------------------------------------- */
.rise {
  transition: opacity var(--dur-3) var(--ease-out-quart),
              transform var(--dur-3) var(--ease-out-expo);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}

.js .rise {
  opacity: 0;
  transform: translateY(26px);
}

.js .is-in > .rise,
.js .rise.is-in {
  opacity: 1;
  transform: none;
}

/* A softer variant for large blocks that shouldn't travel far. */
.js .rise--soft { transform: translateY(12px); }

/* Hairline rules that draw themselves in. */
.js .rule-rise {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1100ms var(--ease-out-expo);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}
.js .is-in > .rule-rise { transform: scaleX(1); }

/* ----------------------------------------------------------------
   SCROLL-LIT PROSE
   JS splits the paragraph into word spans; the scroll position
   decides how many of them are lit.
   ---------------------------------------------------------------- */
.lit .w {
  display: inline-block;
  opacity: 0.16;
  transition: opacity 280ms linear;
}

.lit .w.on { opacity: 1; }

/* ----------------------------------------------------------------
   LINE-ART SKETCHING ITSELF
   `.d` marks a stroke that participates. `pathLength="1"` normalises
   every path so one CSS rule draws them all without measurement.

   No element carries `.draw` or `.d` any more — the front page's line
   art is static now that the imagery is photographic. The rules are
   kept because the index-row icons are one class away from animating
   again, and the reduced-motion block below already disarms them.
   ---------------------------------------------------------------- */
.js .draw .d {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1500ms var(--ease-out-quart);
  transition-delay: calc(var(--i, 0) * 95ms);
}

.js .draw.is-in .d,
.js .is-in .draw .d { stroke-dashoffset: 0; }

/* ----------------------------------------------------------------
   PARALLAX
   JS writes --py each frame; the transform stays on the compositor.
   ---------------------------------------------------------------- */
[data-parallax] {
  transform: translate3d(0, var(--py, 0px), 0);
  will-change: transform;
}

/* ----------------------------------------------------------------
   COUNTERS
   ---------------------------------------------------------------- */
.counter { display: inline-block; }

/* Let the digits settle rather than snap. */
.js .counter { opacity: 0; transition: opacity 400ms linear; }
.js .is-in .counter,
.js .counter.is-in { opacity: 1; }

/* ----------------------------------------------------------------
   HOVER LIFT for interactive plates
   ---------------------------------------------------------------- */
.lift {
  transition: transform 700ms var(--ease-out-expo);
}
.lift:hover { transform: translateY(-6px); }

/* ----------------------------------------------------------------
   REDUCED MOTION — land every element on its final state.
   ---------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .js .line__inner { transform: none; }
  .js .rise { opacity: 1; transform: none; }
  .js .rule-rise { transform: scaleX(1); }
  .js .draw .d { stroke-dashoffset: 0; }
  .js .counter { opacity: 1; }
  .lit .w { opacity: 1; }

  [data-parallax] { transform: none; will-change: auto; }

  .marquee__track { animation: none; }
  .scroll-cue__line::after { animation: none; opacity: 0.5; }

  /* Must out-specify `.js .curtain { display: grid }` in layout.css. */
  .js .curtain,
  .curtain { display: none; }
  body.is-loading { overflow: auto; }

  .hero__glow { display: none; }
}
