// Reveal, Eyebrow, useCountUp, ScrollToTop, useHashRoute.
(function () {
  const { useState, useEffect, useRef, useCallback } = React;

  function Reveal({ children, delay = 0, as: Tag = 'div', className = '', style, ...rest }) {
    const ref = useRef(null);
    const [shown, setShown] = useState(false);
    useEffect(() => {
      const el = ref.current;
      if (!el) return;
      const io = new IntersectionObserver(([e]) => {
        if (e.isIntersecting) { setShown(true); io.disconnect(); }
      }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
      io.observe(el);
      return () => io.disconnect();
    }, []);
    return (
      <Tag
        ref={ref}
        className={`gr-reveal ${shown ? 'is-visible' : ''} ${className}`.trim()}
        style={{ transitionDelay: delay ? `${delay}ms` : undefined, ...style }}
        {...rest}
      >
        {children}
      </Tag>
    );
  }

  function useCountUp(target, duration = 900) {
    const ref = useRef(null);
    const [val, setVal] = useState(0);
    useEffect(() => {
      const el = ref.current;
      if (!el) return;
      const io = new IntersectionObserver(([e]) => {
        if (e.isIntersecting) {
          const start = performance.now();
          const tick = (t) => {
            const p = Math.min(1, (t - start) / duration);
            const eased = 1 - Math.pow(1 - p, 3);
            setVal(Math.round(eased * target));
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
          io.disconnect();
        }
      }, { threshold: 0.5 });
      io.observe(el);
      return () => io.disconnect();
    }, [target, duration]);
    return [ref, val];
  }

  function Eyebrow({ children, color = 'var(--color-green)', style }) {
    return (
      <div
        style={{
          fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 500,
          letterSpacing: '0.2em', textTransform: 'uppercase', color,
          marginBottom: 16, display: 'inline-flex', alignItems: 'center', gap: 10,
          ...style,
        }}
      >
        <span style={{ width: 24, height: 1, background: color, display: 'inline-block' }} />
        {children}
      </div>
    );
  }

  // Simple hash router. Returns [route, setRoute].
  function useHashRoute() {
    const get = () => {
      const h = window.location.hash.replace(/^#/, '');
      return h || '/';
    };
    const [route, setRoute] = useState(get());
    useEffect(() => {
      const onHash = () => setRoute(get());
      window.addEventListener('hashchange', onHash);
      return () => window.removeEventListener('hashchange', onHash);
    }, []);
    const go = useCallback((path) => {
      if (window.location.hash !== '#' + path) {
        window.location.hash = path;
      }
      // Scroll to top on every navigation (covers same-page clicks too).
      window.scrollTo({ top: 0, left: 0, behavior: 'instant' in window ? 'instant' : 'auto' });
    }, []);
    // Auto scroll-to-top whenever route changes.
    useEffect(() => {
      window.scrollTo({ top: 0, left: 0, behavior: 'instant' in window ? 'instant' : 'auto' });
    }, [route]);
    return [route, go];
  }

  // <Link> — anchor that updates hash without reload.
  function Link({ to, onClick, children, ...rest }) {
    const handle = (e) => {
      e.preventDefault();
      if (onClick) onClick(e);
      window.location.hash = to;
      window.scrollTo({ top: 0, left: 0, behavior: 'instant' in window ? 'instant' : 'auto' });
    };
    return (
      <a href={'#' + to} onClick={handle} {...rest}>
        {children}
      </a>
    );
  }

  window.GR = Object.assign(window.GR || {}, {
    Reveal, useCountUp, Eyebrow, useHashRoute, Link,
  });
})();
