// Reveal wrapper using IntersectionObserver — fade + rise on enter.
function Reveal({ children, delay = 0, style = {}, as = 'div' }) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setSeen(true); io.disconnect(); }
    }, { rootMargin: '-12% 0px' });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const Tag = as;
  return (
    <Tag ref={ref} className={'reveal' + (seen ? ' in' : '')}
      style={{ ...style, transitionDelay: `${delay}s` }}>
      {children}
    </Tag>
  );
}

// Animated counter — counts 0→value on enter.
function Counter({ value, suffix = '', duration = 1200 }) {
  const ref = React.useRef(null);
  const [n, setN] = React.useState(0);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (!e.isIntersecting) return;
      io.disconnect();
      const start = performance.now();
      const tick = t => {
        const p = Math.min(1, (t - start) / duration);
        const eased = 1 - Math.pow(1 - p, 3);
        setN(Math.round(eased * value));
        if (p < 1) requestAnimationFrame(tick);
      };
      requestAnimationFrame(tick);
    }, { rootMargin: '-10% 0px' });
    io.observe(el);
    return () => io.disconnect();
  }, [value]);
  return <span ref={ref}>{n}<span style={{ fontStyle: 'italic', color: 'var(--brand-300)' }}>{suffix}</span></span>;
}

window.Reveal = Reveal;
window.Counter = Counter;
