/* ==========================================================================
   motion.css: the reveal layer. Companion to assets/js/motion.js.
   Reads only the motion tokens in tokens.css (--ease-out, --dur-fast,
   --dur-slow, --stagger). Atmosphere (grain, progress filament), button and
   card feedback live in polish.css.

   Every rule that hides or moves content is gated on html.motion-ready,
   which motion.js adds only when JavaScript runs AND the visitor has not
   asked for reduced motion. Without it nothing here applies, so crawlers,
   no-JS readers and reduced-motion readers see every word at full opacity.
   Only transform and opacity are animated.
   ========================================================================== */

/* Section reveals. Sibling stagger comes from data-motion-delay (ms). */
html.motion-ready [data-motion] {
  opacity: 0;
  transform: translate3d(0, 16px, 0);
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}

html.motion-ready [data-motion].is-revealed {
  opacity: 1;
  transform: none;
}

/* Hero headline: per-word rise, transform only. The words are never made
   transparent, so the largest text on the page paints on the first frame and
   the rise is a settle, not a reveal. motion.js wraps each word in .mword. */
html.motion-ready [data-motion="words"] {
  opacity: 1;
  transform: none;
}

html.motion-ready [data-motion="words"] .mword {
  display: inline-block;
  transform: translate3d(0, 0.35em, 0);
  transition: transform var(--dur-slow) var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}

html.motion-ready [data-motion="words"].is-revealed .mword {
  transform: none;
}

/* 404: the one gesture is the caret. */
@media (prefers-reduced-motion: no-preference) {
  .error-caret {
    animation: error-caret 1s steps(1, end) infinite;
  }
}

@keyframes error-caret {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

/* Deep-link acknowledgement, scroll chrome and view transitions are in
   polish.css. Under reduced motion the motion-ready class is never added,
   and this belt-and-braces block flattens anything that slips through. */
@media (prefers-reduced-motion: reduce) {
  html.motion-ready [data-motion],
  html.motion-ready [data-motion="words"] .mword {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
