/* ==========================================================================
   FANG FUTURES — motion
   Mirrors the "08 Motion" page of the Figma library, pattern for pattern.

   The rule: motion is the interface responding, never the interface
   performing. Confident and quick. If you are reaching past --dur-slow,
   you are animating the wrong property.
   ========================================================================== */

/* --- the observer every entrance pattern depends on ----------------------
   Add data-motion to any element; it gets .in when it first enters view.
   One observer, one class, no per-component JS.

   document.querySelectorAll('[data-motion]').forEach(el => io.observe(el));
   const io = new IntersectionObserver(es => es.forEach(e => {
     if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); }
   }), { rootMargin: '0px 0px -10% 0px' });
   -------------------------------------------------------------------------- */

/* 1 · Entrance — rise and settle -------------------------------------------
   The default. Everything that arrives, arrives this way.                   */
[data-motion="rise"]              { opacity:0; transform:translateY(24px); }
[data-motion="rise"].in           { opacity:1; transform:none;
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out); }
/* stagger siblings — 60ms apart, never more than ~6 or it reads as a queue */
[data-motion="rise"]:nth-child(2).in { transition-delay:60ms; }
[data-motion="rise"]:nth-child(3).in { transition-delay:120ms; }
[data-motion="rise"]:nth-child(4).in { transition-delay:180ms; }
[data-motion="rise"]:nth-child(5).in { transition-delay:240ms; }
[data-motion="rise"]:nth-child(6).in { transition-delay:300ms; }

/* 2 · Colour flood — wipe in ------------------------------------------------
   The band arrives; the type inside does NOT move. Moving both reads cheap. */
[data-motion="flood"]             { clip-path: inset(0 100% 0 0); }
[data-motion="flood"].in          { clip-path: inset(0);
  transition: clip-path var(--dur-slow) var(--ease-out); }

/* 3 · Poster type — line reveal --------------------------------------------
   Wrap each line in .line-mask > .line. Masked, not faded — the poster
   voice should feel struck, not dissolved.                                  */
.line-mask                        { overflow:hidden; display:block; }
.line-mask .line                  { display:block; transform:translateY(100%); }
.in .line-mask .line,
.line-mask.in .line               { transform:none;
  transition: transform var(--dur-slow) var(--ease-out); }
.line-mask:nth-child(2) .line     { transition-delay:80ms; }
.line-mask:nth-child(3) .line     { transition-delay:160ms; }

/* 4 · Accent rule — draw ----------------------------------------------------
   Lands just after the heading it belongs to, never with it.                */
.rule-accent                      { width:0; height:4px; background:var(--accent-2); border:0; }
.in .rule-accent,
.rule-accent.in                   { width:56px;
  transition: width var(--dur-base) var(--ease-out) 120ms; }

/* 5 · Button — fill and arrow ----------------------------------------------- */
.btn                              { transition: background var(--dur-fast) var(--ease-standard),
                                                color var(--dur-fast) var(--ease-standard); }
.btn .arrow                       { transition: transform var(--dur-fast) var(--ease-standard); }
.btn:hover .arrow,
.btn:focus-visible .arrow         { transform: translateX(4px); }

/* 6 · Nav — hide on scroll down --------------------------------------------- */
.nav                              { transition: transform var(--dur-base) var(--ease-standard); }
.nav[data-hidden]                 { transform: translateY(-100%); }

/* 7 · Frame — draw in -------------------------------------------------------
   Scale + fade the pseudo-element. NEVER animate border-width: it repaints
   the whole box every frame.                                                */
.framed-inset::after              { opacity:0; transform:scale(.98); }
.framed-inset.in::after           { opacity:1; transform:none;
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out); }

/* 8 · Stat numeral — count up ------------------------------------------------
   JS, because CSS cannot count. Tabular numerals so nothing reflows.
   Honour reduced motion by printing the target immediately.

   function countUp(el, target, ms = 800) {
     if (matchMedia('(prefers-reduced-motion: reduce)').matches) {
       el.textContent = target; return;
     }
     const t0 = performance.now();
     const step = now => {
       const p = Math.min((now - t0) / ms, 1);
       el.textContent = Math.round(p * target);
       if (p < 1) requestAnimationFrame(step);
     };
     requestAnimationFrame(step);
   }
   -------------------------------------------------------------------------- */
.stat-num                         { font-variant-numeric: tabular-nums; }

/* --- NON-NEGOTIABLE --------------------------------------------------------
   Every pattern above collapses. Motion is an enhancement in this system,
   never a dependency: nothing may become unreadable or unreachable without it.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  [data-motion] { opacity:1 !important; transform:none !important; clip-path:none !important; }
  .rule-accent  { width:56px !important; }
}
