/* ---------------------------------------------------------------------------
   Motion for the product page.

   Everything here is gated on `html.motion`, which only the script adds, and only
   when the visitor has not asked for less motion. Without the script -- or with
   `prefers-reduced-motion: reduce`, or if the file 404s -- none of these rules
   match, and the page is exactly the page it was before: every element visible, in
   its final position, with no transition anywhere. That is the whole point of
   writing it this way. A reveal animation whose un-run state is "hidden" turns a
   failed script into a blank page, and this site has no way to notice that from the
   outside -- the checks here look at images, not at CSS.

   Kept out of the page's inline <style> so the motion can be read, reviewed and
   removed in one place. Loaded after it, so the same-specificity rules below win.
   --------------------------------------------------------------------------- */

/* ------------------------------------------------------------ scroll reveal */
html.motion .reveal {
  opacity: 0;
  transform: translateY(26px);
}
html.motion .reveal.is-in {
  opacity: 1;
  transform: none;
  transition:
    opacity .72s cubic-bezier(.22,.68,.24,1) var(--d, 0ms),
    transform .72s cubic-bezier(.22,.68,.24,1) var(--d, 0ms);
}

/* ------------------------------------------------------- layered depth drift */
/* The screenshots float at different rates as the page moves, and the hero's own
   lines drift a few pixels apart from each other. The amplitude is deliberately
   small -- 8 to 22 pixels. This is the version of parallax that reads as depth
   rather than as an effect: you feel it on the way past and never have to wait for
   it. Big travel is what makes a page feel seasick, and it is also what makes text
   hard to read while it moves.

   Applied through `translate3d` on its own, never alongside opacity, so text stays
   at full contrast for the whole of the movement. */
html.motion .drift,
html.motion .reveal.is-in.drift {
  transition: none;              /* transform is driven per frame, not by CSS */
  will-change: transform;
}

/* ------------------------------------------------------- the stepped walkthrough */
.walk-grid {
  display: grid;
  grid-template-columns: minmax(240px, 340px) 1fr;
  gap: 54px;
  align-items: start;
}
.walk-stage { position: sticky; top: 92px; }
.walk-rail {
  height: 3px; border-radius: 2px; overflow: hidden;
  background: var(--line); margin-top: 26px;
}
.walk-fill {
  display: block; height: 100%; width: 0;
  background: var(--accent); border-radius: 2px;
  transition: width .35s cubic-bezier(.22,.68,.24,1);
}
.walk-count {
  display: block; margin-top: 12px; font-size: 13px; color: var(--soft);
  font-variant-numeric: tabular-nums;
}
.walk-items { display: grid; gap: 20px; }
.walk-items > .card {
  display: flex; flex-direction: column; justify-content: center;
  min-height: 46vh;
  transition: border-color .35s, box-shadow .35s, transform .35s;
}
.walk-items > .card.is-active {
  border-color: #c7daff;
  box-shadow: 0 10px 30px rgba(47,109,246,.09);
  transform: translateY(-2px);
}
.walk-items > .card .ic { transition: background .35s, color .35s; }
.walk-items > .card.is-active .ic { background: var(--accent); color: #fff; }

@media (max-width: 1000px) {
  .walk-grid { grid-template-columns: 1fr; gap: 26px; }
  .walk-stage { position: static; }
  .walk-items > .card { min-height: 0; }
  .walk-rail { display: none; }
  .walk-count { display: none; }
}

/* --------------------------------------------------------- reading progress */
.nav-progress {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  background: var(--accent); transform: scaleX(0); transform-origin: 0 50%;
  opacity: .85;
}

/* ------------------------------------------------------------ reduced motion */
/* Belt and braces. The script already declines to add `html.motion`, so this should
   never have anything to undo -- but a stylesheet is the one place where "less
   motion" can be honoured no matter what the script decided, including when the
   preference changes after load. Nothing may animate, and nothing may stay hidden
   waiting for an animation that will not run. */
@media (prefers-reduced-motion: reduce) {
  html.motion .reveal,
  html.motion .reveal.is-in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  html.motion .drift { transform: none !important; will-change: auto; }
  .walk-fill { transition: none; }
  .walk-items > .card { transition: none; }
  .walk-items > .card.is-active { transform: none; }
}
