// motion.jsx — motion primitives: number ticker, stagger, page transitions

// Animated number that counts up smoothly to value
function NumberTicker({ value, duration = 700, className, style, prefix = '', suffix = '' }) {
  const [display, setDisplay] = React.useState(value);
  const lastRef = React.useRef(value);
  const rafRef = React.useRef(null);

  React.useEffect(() => {
    const from = lastRef.current;
    const to = value;
    if (from === to) return;
    const start = performance.now();
    const tick = (now) => {
      const t = Math.min(1, (now - start) / duration);
      // easeOutCubic
      const eased = 1 - Math.pow(1 - t, 3);
      const cur = Math.round(from + (to - from) * eased);
      setDisplay(cur);
      if (t < 1) rafRef.current = requestAnimationFrame(tick);
      else lastRef.current = to;
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, [value, duration]);

  return <span className={className} style={style}>{prefix}{display}{suffix}</span>;
}

// Page transition wrapper
function PageTransition({ id, children }) {
  return (
    <div key={id} className="page-trans" data-screen-label="page-content">
      {children}
    </div>
  );
}

// Inject motion CSS
const __MOTION_CSS = `
@keyframes page-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.page-trans { animation: page-in 320ms cubic-bezier(0.22, 1, 0.36, 1); }

@keyframes hop {
  0% { transform: translateY(0); }
  40% { transform: translateY(-16px); }
  100% { transform: translateY(0); }
}
.hop { animation: hop 480ms cubic-bezier(0.34, 1.56, 0.64, 1); }

@keyframes ripple {
  from { transform: scale(0); opacity: 0.6; }
  to   { transform: scale(2.4); opacity: 0; }
}
.ripple-on-click { position: relative; overflow: hidden; }
.ripple-on-click::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(circle at var(--rx, 50%) var(--ry, 50%), currentColor 0%, transparent 70%);
  opacity: 0;
  pointer-events: none;
}
.ripple-on-click[data-rippling="1"]::after {
  animation: ripple 600ms ease-out;
}

@keyframes wheel-pt-in {
  from { transform: translateY(0) scale(0); opacity: 0; }
  to   { transform: translateY(0) scale(1); opacity: 1; }
}
.wheel-pt-in { animation: wheel-pt-in 460ms cubic-bezier(0.34, 1.56, 0.64, 1) both; }
.wheel-axis-in { animation: page-in 460ms ease-out both; }

@keyframes glow-pulse-once {
  0% { box-shadow: 0 0 0 var(--accent); }
  50% { box-shadow: 0 0 calc(28px * var(--glow-mult)) var(--accent-ring); }
  100% { box-shadow: 0 0 0 var(--accent); }
}
.glow-pulse { animation: glow-pulse-once 800ms ease-out; }

@keyframes shake-x {
  0%, 100% { transform: translateX(0); }
  25%, 75% { transform: translateX(-3px); }
  50% { transform: translateX(3px); }
}
.shake { animation: shake-x 360ms ease-in-out; }
`;
if (typeof document !== 'undefined' && !document.getElementById('motion-css')) {
  const s = document.createElement('style');
  s.id = 'motion-css';
  s.textContent = __MOTION_CSS;
  document.head.appendChild(s);
}

Object.assign(window, { NumberTicker, PageTransition });
