/* Loopmore.ai: the shared motion layer. Loaded after site-extra.css on every page.
   Works with assets/js/motion.js. Documented in docs/motion-api.md.
   Rules from DESIGN.md: calm and exact, one moving idea at a time, ease-out, 150 ms hover,
   250 ms panels, every scroll effect done by the time its section is fully in view,
   reduced motion shows end states at once. Tokens only; no raw colors.

   Hidden start states apply only under html.js-motion, which motion.js sets.
   If the script never runs, everything shows in its final state. */

:root {
  --m-ease: cubic-bezier(.16, 1, .3, 1);   /* confident arrival, no overshoot */
  --m-rise: 24px;
  --m-reveal: 700ms;
  --m-step: 80ms;                           /* stagger step; matches the m-rv-2..4 rhythm */
}

@keyframes m-reveal-rise { from { opacity: 0; transform: translateY(var(--m-rise)); } to { opacity: 1; transform: none; } }
@keyframes m-reveal-fade { from { opacity: 0; } to { opacity: 1; } }

/* ---------- 1. Hero: the work panel's job rotation starts after the loop field's dot lands (2.85 s) ---------- */
.w-hero .w-live .w-job--1, .w-hero .w-live .w-job--1 .w-live__bar > span, .w-hero .w-live .w-job--1 .w-live__run,
.w-hero .w-live .w-job--1 .w-live__done, .w-hero .w-live .w-job--1 .lm-icon--loop { animation-delay: 2.85s; }
.w-hero .w-live .w-job--2, .w-hero .w-live .w-job--2 .w-live__bar > span, .w-hero .w-live .w-job--2 .w-live__run,
.w-hero .w-live .w-job--2 .w-live__done, .w-hero .w-live .w-job--2 .lm-icon--loop { animation-delay: 6.85s; }
.w-hero .w-live .w-job--3, .w-hero .w-live .w-job--3 .w-live__bar > span, .w-hero .w-live .w-job--3 .w-live__run,
.w-hero .w-live .w-job--3 .w-live__done, .w-hero .w-live .w-job--3 .lm-icon--loop { animation-delay: 10.85s; }

@media (prefers-reduced-motion: no-preference) {

  /* ---------- 2. data-reveal: one-shot rise (or fade) when the element scrolls into view ---------- */
  .js-motion [data-reveal] { animation: m-reveal-rise var(--m-reveal) var(--m-ease) both paused; animation-delay: calc(var(--m-i, 0) * var(--m-step)); }
  .js-motion [data-reveal="fade"] { animation-name: m-reveal-fade; }
  .js-motion [data-reveal-delay="1"] { --m-i: 1; }
  .js-motion [data-reveal-delay="2"] { --m-i: 2; }
  .js-motion [data-reveal-delay="3"] { --m-i: 3; }
  .js-motion [data-reveal-delay="4"] { --m-i: 4; }
  .js-motion [data-reveal].is-in { animation-play-state: running; }
  .js-motion [data-reveal].is-done { animation: none; }

  /* ---------- 3. Fallback for browsers without scroll-driven animations (Safari < 26, Firefox) ----------
     motion.js sets html.m-fb only when CSS.supports('animation-timeline: view()') is false
     (or when the page is opened with ?motion=fallback for testing). The site.css keyframes are reused,
     run once on a clock instead of on the scroll position. */
  .m-fb .m-rv { animation: m-rise var(--m-reveal) var(--m-ease) both paused; }
  .m-fb .m-rv-2 { animation-delay: calc(var(--m-step) * 1); }
  .m-fb .m-rv-3 { animation-delay: calc(var(--m-step) * 2); }
  .m-fb .m-rv-4 { animation-delay: calc(var(--m-step) * 3); }
  .m-fb .m-zoom { animation: m-zoom 1.2s var(--m-ease) both paused; }
  .m-fb .m-fill { animation: m-fill 1.4s cubic-bezier(.4, 0, .2, 1) both paused; }
  .m-fb .w-track__fill { animation: w-track-fill .9s var(--m-ease) both paused; }
  .m-fb .w-track__dot { animation: w-track-dot .9s var(--m-ease) both paused; }
  .m-fb .w-track__dot--3 { animation-name: w-track-dot-3; }
  .m-fb .w-phase__bar--now > span { animation: w-phase-now .9s var(--m-ease) both paused; }
  .m-fb .w-drop { animation: w-drop .7s cubic-bezier(.2, .7, .2, 1) .25s both paused; }
  .m-fb .w-vsteps__seg { animation: w-seg .7s var(--m-ease) both paused; }
  .m-fb .w-vsteps__node--end { animation: w-node-land .5s cubic-bezier(.2, .7, .2, 1) .3s both paused; }
  .m-fb .w-open-o .lm-logo__dot { animation: w-o-land .8s cubic-bezier(.2, .7, .2, 1) .2s both paused; }
  /* Clear the scroll ranges site.css sets, so a forced fallback in Chrome runs on the clock */
  .m-fb .m-rv, .m-fb .m-zoom, .m-fb .m-fill, .m-fb .w-track__fill, .m-fb .w-track__dot, .m-fb .w-phase__bar--now > span,
  .m-fb .w-drop, .m-fb .w-vsteps__seg, .m-fb .w-vsteps__node--end, .m-fb .w-open-o .lm-logo__dot { animation-range: normal; }
  .m-fb .is-in, .m-fb .w-open-o .lm-logo__dot.is-in, .m-fb .w-phase__bar--now > span.is-in { animation-play-state: running; }
  .m-fb .is-done, .m-fb .w-open-o .lm-logo__dot.is-done, .m-fb .w-phase__bar--now > span.is-done { animation: none; }

  /* ---------- 4. Link cards: edge darkens and the card lifts 2 px in 150 ms ---------- */
  @media (hover: hover) {
    a.w-card:hover, .w-card--link:hover { transform: translateY(-2px); }
  }
}

/* Link cards (any width): the hover edge, with or without motion */
a.w-card, .w-card--link { display: block; color: inherit; text-decoration: none; transition: border-color .15s ease-out, transform .15s ease-out; }
a.w-card:hover, .w-card--link:hover { border-color: var(--line-control); }
a.w-card:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Count-up numbers: a screen-reader copy of the final value sits beside the animated digits */
.m-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
[data-count-to] > [aria-hidden="true"] { display: inline-block; }

@media print {
  .js-motion [data-reveal], .m-fb .m-rv, .m-fb .m-zoom, .m-fb .m-fill { animation: none !important; }
}
