/* HTD Motion Layer — reusable animation hooks (respect prefers-reduced-motion) */
(function () {
  const { useState, useEffect, useRef } = React;
  const reduced = typeof window !== 'undefined' && window.matchMedia &&
    window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  const easeOut = t => 1 - Math.pow(1 - t, 3);

  // animate a number from `from` → `to`. Second arg may be a duration (ms) or an options object.
  function useCountUp(to, opts) {
    if (typeof opts === 'number') opts = { dur: opts };
    const { from = 0, dur = 900, delay = 120, decimals = 0 } = opts || {};
    const [val, setVal] = useState(reduced ? to : from);
    useEffect(() => {
      if (reduced) { setVal(to); return; }
      let raf, start;
      const t0 = performance.now() + delay;
      const step = (now) => {
        if (now < t0) { raf = requestAnimationFrame(step); return; }
        if (start == null) start = now;
        const p = Math.min(1, (now - t0) / dur);
        const v = from + (to - from) * easeOut(p);
        setVal(decimals ? +v.toFixed(decimals) : Math.round(v));
        if (p < 1) raf = requestAnimationFrame(step);
      };
      raf = requestAnimationFrame(step);
      // safety: if rAF is throttled (background/capture), force the final value
      const settle = setTimeout(() => setVal(to), delay + dur + 120);
      return () => { cancelAnimationFrame(raf); clearTimeout(settle); };
    }, [to]);
    return val;
  }

  // 0 → 1 progress ramp (drive draws, sweeps); restarts when `key` changes
  function useRamp({ dur = 900, delay = 100, key = 0 } = {}) {
    const [p, setP] = useState(reduced ? 1 : 0);
    useEffect(() => {
      if (reduced) { setP(1); return; }
      setP(0);
      let raf, t0 = performance.now() + delay;
      const step = (now) => {
        const e = Math.max(0, now - t0);
        const v = Math.min(1, e / dur);
        setP(easeOut(v));
        if (v < 1) raf = requestAnimationFrame(step);
      };
      raf = requestAnimationFrame(step);
      const settle = setTimeout(() => setP(1), delay + dur + 120);
      return () => { cancelAnimationFrame(raf); clearTimeout(settle); };
    }, [key]);
    return p;
  }

  // fire `on` → true shortly after mount (one-shot gate for CSS transitions)
  function useArm(delay = 60) {
    const [on, setOn] = useState(reduced);
    useEffect(() => { if (reduced) return; const t = setTimeout(() => setOn(true), delay); return () => clearTimeout(t); }, []);
    return reduced ? true : on;
  }

  window.HTDMotion = { useCountUp, useRamp, useArm, reduced, easeOut };
})();
