/* motion.css — one-shot, gated motion for a static launch page.
   Reads tokens from tokens.css. Requires motion.js (adds .js to <html>,
   runs the observer). Rules:
   - every hidden initial state sits behind `.js`, so the page is complete with JS off;
   - only transform / opacity / stroke-dashoffset animate;
   - nothing loops; every effect is one-shot;
   - `prefers-reduced-motion: reduce` removes all of it;
   - decorative motion (rise, scribble, parallax) is off below --motion-min-width.
   Ported techniques (source: optifly-src/TEARDOWN.md §9, files cited inline):
   1 hero load choreography  2 scroll reveal + stagger  3 scribble ring
   7 scroll-driven micro-parallax  8 retracting underline  10 word-split heading */

/* ---------- 1. Hero load choreography (Hero.astro:83-105) ----------
   Mark the hero's elements in order:  .rise  .rise.rise-lead  .rise.rise-actions
   (or set --rise-delay inline). Delays 0 / 600 / 700 ms, backwards fill. */
@keyframes tk-rise {
  from { opacity: 0; transform: translateY(var(--rise-distance, 24px)); }
}
@media (min-width: 760px) and (prefers-reduced-motion: no-preference) {
  .js .rise {
    animation: tk-rise var(--rise-duration, 1.3s) var(--ease-out-cubic) var(--rise-delay, 0ms) backwards;
  }
  .js .rise-lead    { --rise-delay: var(--rise-delay-lead, 600ms); }
  .js .rise-actions { --rise-delay: var(--rise-delay-actions, 700ms); }
}

/* ---------- 2. One-shot scroll reveal with sibling stagger (global.css:405-417, index.astro:61-81) ----------
   Add .reveal to any element. For staggered siblings set style="--i: n" on each;
   delay = --i × --reveal-step. motion.js adds .is-visible once at 88% of viewport. */
.js .reveal {
  opacity: 0;
  transform: translateY(var(--reveal-distance, 8px));
  transition:
    opacity var(--reveal-duration, 600ms) var(--ease-out-cubic),
    transform var(--reveal-duration, 600ms) var(--ease-out-cubic);
  transition-delay: var(--reveal-delay, calc(var(--i, 0) * var(--reveal-step, 70ms)));
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* ---------- 3. Scribble ring around one word (System.astro:69-80, 118-152) ----------
   <em class="scribble">once<svg viewBox="0 0 800 350" preserveAspectRatio="none" aria-hidden="true">
     <path pathLength="1" d="…"/></svg></em>
   Put data-reveal on an ancestor (motion.js marks it .is-visible); the ring draws then.
   Default path (a loose hand-drawn loop) is in the README. */
.scribble { position: relative; padding: 0 0.04em; font-style: inherit; }
.scribble svg {
  position: absolute; top: 4%; left: -10%; z-index: -1;
  width: 120%; height: 100%; max-width: none; overflow: visible;
  pointer-events: none;
}
.scribble path {
  fill: none;
  stroke: var(--accent);
  stroke-width: var(--scribble-width, 14);
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
}
@media (min-width: 760px) and (prefers-reduced-motion: no-preference) {
  .js [data-reveal]:not(.is-visible) .scribble path { stroke-dashoffset: 1; }
  .js [data-reveal].is-visible .scribble path {
    transition: stroke-dashoffset var(--scribble-duration, 1.5s) var(--ease-draw);
    transition-delay: var(--scribble-delay, 0ms);
  }
}

/* ---------- 7. Scroll-driven micro-parallax (global.css:372-403) ----------
   Wrapper gets .parallax-host (the timeline), the moving child gets .parallax.
   Longhands + a separate animation-timeline rule so minifiers do not merge it away.
   Zero JS; only where the browser supports view(). One element per page. */
@keyframes tk-parallax {
  from { transform: translateY(0); }
  to   { transform: translateY(calc(var(--parallax-travel, 24px) * -1)); }
}
@supports (animation-timeline: view()) {
  @media (min-width: 1000px) and (prefers-reduced-motion: no-preference) {
    .parallax-host { view-timeline-name: --tk-view; }
    .parallax {
      animation-name: tk-parallax;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-duration: 1ms; /* ignored by a scroll timeline; keeps validators quiet */
    }
    .parallax-host .parallax { animation-timeline: --tk-view; }
  }
}

/* ---------- 8. Retracting hairline underline (Footer.astro:102-118) ----------
   Add .ul to a link. The 1px rule retracts to the right on hover, redraws from the left. */
.ul {
  position: relative;
  text-decoration: none;
}
.ul::after {
  content: "";
  position: absolute; right: 0; bottom: -1px; left: 0; height: 1px;
  background: currentColor;
  transform-origin: left;
  transition: transform 0.45s cubic-bezier(0.15, 0.75, 0.5, 1);
}
.ul:hover::after, .ul:focus-visible::after {
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.4s cubic-bezier(0.23, 0.46, 0.4, 1);
}

/* ---------- 10. Word-split heading reveal (SectionIntro.astro:26-51, global.css:419-443) ----------
   <h2 data-split data-reveal="bottom">The deal, in full</h2>
   motion.js wraps each word in .split-word > .split-word-inner with --i.
   The .1em padding guard keeps descenders from clipping. */
.split-word {
  display: inline-block;
  margin-bottom: -0.1em;
  padding-bottom: 0.1em;
  overflow: hidden;
  vertical-align: top;
}
.split-word-inner { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .js [data-reveal="bottom"]:not(.is-visible) .split-word-inner {
    opacity: 0;
    transform: translateY(1.1em);
  }
  .js [data-reveal="bottom"].is-visible .split-word-inner {
    transition:
      opacity var(--split-duration, 0.9s) var(--ease-split),
      transform var(--split-duration, 0.9s) var(--ease-split);
    transition-delay: calc(var(--i, 0) * var(--split-step, 40ms));
  }
}

/* ---------- reduced motion: everything static ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .js .rise { animation: none; }
  .scribble path { stroke-dashoffset: 0 !important; transition: none !important; }
  .split-word-inner { opacity: 1 !important; transform: none !important; transition: none !important; }
  .parallax { animation: none !important; }
  .ul::after { transition: none; }
}
