/* =========================================================================
   motion.css - calm, premium motion for the whole page.

   Rules this file keeps (so the settled layout never changes):
   - Only opacity, clip-path and the individual translate / scale / rotate
     properties are animated. Those compose with each element's own
     `transform` (rotate(-90deg) labels, translateX(-50%) logo...) instead
     of replacing it.
   - Keyframes hold only the start state (plus an explicit identity end for
     clip-path/translate/scale) and use fill "backwards": when an animation
     ends, the element is back on its own CSS, pixel for pixel.
   - Everything lives inside prefers-reduced-motion: no-preference. With
     reduced motion (or without JS) nothing moves and nothing is hidden.
   - Scroll reveals are driven by js/main.js (initReveal): it tags elements
     with .reveal + data-m="<variant>" + --m-d (delay), and adds .in-view.
   ========================================================================= */

:root {
  --m-ease: cubic-bezier(.22, 1, .36, 1);        /* soft ease-out, no overshoot */
  --m-ease-io: cubic-bezier(.45, 0, .25, 1);
}

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

  /* ---------------------------------------------------------------------
     1) SCROLL REVEALS - variants selected by data-m
     --------------------------------------------------------------------- */
  .js .reveal.in-view {
    animation: m-rise var(--m-dur, 900ms) var(--m-ease) var(--m-d, 0ms) backwards;
  }
  .js .reveal.in-view[data-m="fade"]       { animation-name: m-fade;   --m-dur: 1100ms; }
  .js .reveal.in-view[data-m="zoom"]       { animation-name: m-zoom;   --m-dur: 1300ms; }
  .js .reveal.in-view[data-m="unveil"]     { animation-name: m-unveil; --m-dur: 1300ms; }
  .js .reveal.in-view[data-m="slide-x"]    { animation-name: m-slide-x;    --m-dur: 1400ms; }
  .js .reveal.in-view[data-m="slide-up"]   { animation-name: m-slide-up;   --m-dur: 1400ms; }
  .js .reveal.in-view[data-m="slide-down"] { animation-name: m-slide-down; --m-dur: 1400ms; }
  .js .reveal.in-view[data-m="pop"]        { animation-name: m-pop;    --m-dur: 800ms; }

  /* ---------------------------------------------------------------------
     2) HERO - staggered entrance on load (CSS only, visible at first paint)
     --------------------------------------------------------------------- */
  .js #home .hero__panel   { animation: m-panel 1100ms var(--m-ease) 0ms backwards; }
  .js #home .hero__arc--light { animation: m-arc-l 1600ms var(--m-ease) 200ms backwards; }
  .js #home .hero__arc--dark  { animation: m-arc-d 1600ms var(--m-ease) 300ms backwards; }
  .js #home .hero__oval    { animation: m-rise 1100ms var(--m-ease) 250ms backwards; --m-y: 18px; }
  .js #home .hero__img     { animation: m-zoom-in 1900ms var(--m-ease) 250ms backwards; }
  .js #home .hero__ring    { animation: m-ring 1300ms var(--m-ease-io) 550ms backwards; }
  .js #home .hero__title   { animation: m-rise 1000ms var(--m-ease) 750ms backwards; --m-y: 16px; }
  .js #home .hero__subtitle{ animation: m-rise 1000ms var(--m-ease) 900ms backwards; --m-y: 14px; }
  .js #home .hero__sparkle--r {
    animation: m-sparkle-in 900ms var(--m-ease) 1100ms backwards,
               m-twinkle 7s var(--m-ease-io) 2000ms infinite;
  }
  .js #home .hero__sparkle--l {
    animation: m-sparkle-in 900ms var(--m-ease) 1250ms backwards,
               m-twinkle 8s var(--m-ease-io) 2600ms infinite;
  }
  .js #home .hero__social-item { animation: m-rise 800ms var(--m-ease) 1150ms backwards; --m-y: 10px; }
  .js #home .hero__social-item:nth-child(2) { animation-delay: 1250ms; }
  .js #home .hero__social-item:nth-child(3) { animation-delay: 1350ms; }
  .js #home .hero__vlabel  { animation: m-fade 1200ms var(--m-ease) 1300ms backwards; }

  /* header items fade down softly */
  .js #site-header .site-header__brand  { animation: m-drop 900ms var(--m-ease) 300ms backwards; }
  .js #site-header .site-header__cta    { animation: m-drop 900ms var(--m-ease) 420ms backwards; }
  .js #site-header .site-header__toggle { animation: m-drop 900ms var(--m-ease) 480ms backwards; }

  /* entrance finished (js/main.js adds .m-done): back to plain CSS */
  .js .reveal.in-view.m-done,
  .js #home .m-done,
  .js #site-header .m-done { animation: none; }
  .js #home .hero__sparkle--r.m-done { animation: m-twinkle 7s var(--m-ease-io) 900ms infinite; }
  .js #home .hero__sparkle--l.m-done { animation: m-twinkle 8s var(--m-ease-io) 1500ms infinite; }

  /* ---------------------------------------------------------------------
     3) AMBIENT - sparkles breathe very slowly (opacity + a few degrees)
     --------------------------------------------------------------------- */
  .js #faq .faq__sparkle--1 { animation: m-twinkle 8s var(--m-ease-io) 1s infinite; }
  .js #faq .faq__sparkle--2 { animation: m-twinkle 7s var(--m-ease-io) 3s infinite; }
  .js #site-footer .footer__sparkle--a { animation: m-twinkle 8s var(--m-ease-io) 1s infinite; }
  .js #site-footer .footer__sparkle--b { animation: m-twinkle 7s var(--m-ease-io) 3.5s infinite; }

  /* ---------------------------------------------------------------------
     4) "WHY" CARDS - quick, soft switch (popups.js toggles [hidden])
     --------------------------------------------------------------------- */
  .js #why .why-popup { animation: m-card 380ms var(--m-ease) both; }

  /* ---------------------------------------------------------------------
     4b) HAIRLINES - drawn by the scroll itself (js/main.js initLines).
     The line grows while it passes through the viewport: it starts when its
     top edge reaches 75% of the viewport height and its growing tip stays on
     that 75% line, so a long vertical line is drawn exactly as fast as the
     page scrolls and continues from one line into the next (why-works ->
     process). Short / horizontal lines get at least 30vh of scroll (75% ->
     45%). Only `scale` is animated, from the line's start edge:
       .m-line--y  from the top, .m-line--xl from the left, .m-line--xr from the right.
     Where CSS scroll-driven animations exist the browser runs it on the
     root scroll timeline; main.js only feeds the line's page offset
     (--m-top) and height (--m-h). view() is not used because the sections
     are overflow:hidden, which makes each of them the nearest "scroller".
     Elsewhere main.js sets --m-p (0..1) on scroll (rAF-throttled).
     Once a line is fully drawn main.js removes the classes: it is back on
     its own CSS, pixel for pixel, and stays drawn.
     --------------------------------------------------------------------- */
  .js .m-line--y  { transform-origin: 0 0; }
  .js .m-line--xl { transform-origin: 0 50%; }
  .js .m-line--xr { transform-origin: 100% 50%; }
  /* the two slanted lines rotate via `transform`; move that rotation to
     `rotate` so the scale is applied along the slanted line, not the page */
  @media (min-width: 1280px) {
    .js .m-line.why-works__line,
    .js .m-line.process__line--v-long { rotate: .5417deg; transform: none; }
  }

  .js .m-line--js.m-line--y           { scale: 1 var(--m-p, 0); }
  .js .m-line--js:is(.m-line--xl, .m-line--xr) { scale: var(--m-p, 0) 1; }

  @supports (animation-timeline: scroll()) {
    .js .m-line--sd {
      animation: m-line-y linear both;
      animation-timeline: scroll(root block);
      animation-range:
        calc(var(--m-top, 0px) - 75vh)
        calc(var(--m-top, 0px) - 75vh + max(var(--m-h, 0px), 30vh));
    }
    .js .m-line--sd:is(.m-line--xl, .m-line--xr) { animation-name: m-line-x; }
  }

  /* ---------------------------------------------------------------------
     5) IMAGE HOVER - a slow zoom that stays inside the image's own shape.
     scale 1.04 is paired with a clip-path inset of (1 - 1/1.04) / 2 =
     1.923% (and radii / 1.04), so the visible outline never moves.
     --------------------------------------------------------------------- */
  @media (hover: hover) {
    #faq .faq__photo,
    #process .process__stadium {
      transition: scale 1.1s var(--m-ease), clip-path 1.1s var(--m-ease);
    }
    #faq .faq__photo--tl     { clip-path: inset(0 round calc(100 / 610 * 100cqw) 0 0 0); }
    #faq .faq__photo--tr     { clip-path: inset(0 round 0 calc(100 / 610 * 100cqw) 0 0); }
    #faq .faq__photo--bottom { clip-path: inset(0 round 0 0 calc(100 / 610 * 100cqw) calc(100 / 610 * 100cqw)); }
    #faq .faq__photo--tl:hover     { scale: 1.04; clip-path: inset(1.923% round calc(100 / 610 * 100cqw / 1.04) 0 0 0); }
    #faq .faq__photo--tr:hover     { scale: 1.04; clip-path: inset(1.923% round 0 calc(100 / 610 * 100cqw / 1.04) 0 0); }
    #faq .faq__photo--bottom:hover { scale: 1.04; clip-path: inset(1.923% round 0 0 calc(100 / 610 * 100cqw / 1.04) calc(100 / 610 * 100cqw / 1.04)); }

    /* stadium photo: painted round left end on white, so the clip follows it */
    #process .process__stadium       { clip-path: inset(0 round 999px 0 0 999px); }
    #process .process__stadium:hover { scale: 1.04; clip-path: inset(1.923% round 999px 0 0 999px); }
  }
}

/* -------------------------------------------------------------------------
   KEYFRAMES (only used inside the no-preference block above)
   ------------------------------------------------------------------------- */
@keyframes m-rise      { from { opacity: 0; translate: 0 var(--m-y, 22px); } to { translate: 0 0; } }
@keyframes m-drop      { from { opacity: 0; translate: 0 -10px; } to { translate: 0 0; } }
@keyframes m-fade      { from { opacity: 0; } }
@keyframes m-zoom      { from { opacity: 0; scale: 1.05; } to { scale: 1; } }
@keyframes m-zoom-in   { from { scale: 1.04; } to { scale: 1; } }
@keyframes m-unveil {
  from { opacity: 0; clip-path: inset(100% 0 0 0); scale: 1.04; }
  to   { clip-path: inset(0 0 0 0); scale: 1; }
}
/* hairlines (scroll-linked, see 4b) */
@keyframes m-line-y    { from { scale: 1 0; } to { scale: 1 1; } }
@keyframes m-line-x    { from { scale: 0 1; } to { scale: 1 1; } }
/* big Malfin words: a slow glide (always from inside the page, never outward) */
@keyframes m-slide-x    { from { opacity: 0; translate: 36px 0; } to { translate: 0 0; } }
@keyframes m-slide-up   { from { opacity: 0; translate: 0 36px; } to { translate: 0 0; } }
@keyframes m-slide-down { from { opacity: 0; translate: 0 -36px; } to { translate: 0 0; } }
@keyframes m-pop       { from { opacity: 0; scale: .86; } to { scale: 1; } }

/* hero pieces */
@keyframes m-panel     { from { opacity: 0; translate: -24px 0; } to { translate: 0 0; } }
@keyframes m-arc-l     { from { opacity: 0; rotate: -8deg; } to { rotate: 0deg; } }
@keyframes m-arc-d     { from { opacity: 0; rotate: 8deg; } to { rotate: 0deg; } }
/* the stadium ring is revealed bottom -> top, like a line being drawn */
@keyframes m-ring      { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes m-sparkle-in { from { opacity: 0; scale: .4; rotate: -45deg; } to { scale: 1; rotate: 0deg; } }
@keyframes m-twinkle {
  0%, 100% { opacity: 1; rotate: 0deg; }
  50%      { opacity: .6; rotate: 12deg; }
}
@keyframes m-card      { from { opacity: 0; scale: .98; } to { opacity: 1; scale: 1; } }
