/* ═══════════════════════════════════════════════════════════════════════
   Motion.
   One reveal vocabulary for the whole site: a long, soft rise out of blur.
   Elements declare their intent in markup (data-reveal) and are unlocked by
   JS; without JS they are simply visible, which is the correct fallback.
   ═══════════════════════════════════════════════════════════════════════ */

/* Only arm the hidden state once JS has confirmed it can un-arm it. */
.js-motion [data-reveal] {
  opacity: 0;
  filter: blur(8px);
  transform: translate3d(0, 22px, 0);
  transition: opacity var(--dur-reveal) var(--ease-out),
    filter var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

/* No `will-change` here on purpose. There are three dozen of these on the
   page and promoting them all at once costs more in layer memory than the
   compositor hint ever returns — enough to stall the renderer outright. */
.js-motion [data-reveal].is-revealed {
  opacity: 1;
  filter: blur(0);
  transform: translate3d(0, 0, 0);
}

/* A heavier settle for the hero — more blur, more travel, more time.
   And a gentler curve than the rest of the page uses. `--ease-out` is weighted
   hard to the front: over half its travel is spent in the first tenth of the
   duration, which on a 1500ms reveal means the element has effectively arrived
   in 150ms and then creeps. That snap is fine for a card entering on scroll,
   but the hero is the first motion anyone sees and it should not appear to
   have been thrown into place. */
.js-motion [data-reveal="hero"] {
  filter: blur(14px);
  transform: translate3d(0, 30px, 0);
  transition-duration: 1500ms;
  transition-timing-function: cubic-bezier(0.25, 0.6, 0.25, 1);
}

/* Figures rise without blur; blurring a photographic surface reads as a
   loading state rather than a reveal. */
.js-motion [data-reveal="figure"] {
  filter: none;
  transform: translate3d(0, 40px, 0);
  transition-duration: 1300ms;
}

/* ── Reduced motion ─────────────────────────────────────────────────────
   Everything arrives already composed. The sky stops drifting, the window
   stops opening, and nothing is lost but the movement. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .js-motion [data-reveal],
  .js-motion [data-reveal].is-revealed {
    opacity: 1;
    filter: none;
    transform: none;
    transition: none;
  }

  /* The process rules are drawn by a scaled pseudo-element, and the hand-off
     rule under "Where are you headed?" the same way; with motion off they are
     just rules. */
  .js-motion .step::before,
  .js-motion .step:last-child::after,
  .js-motion .dest__rule {
    transform: none;
    transition: none;
  }

  .btn::before {
    transition-duration: 1ms;
  }
}
