// Site motion — small, opinionated motion primitives shared across pages.
//
//  - <FadeUp>: IntersectionObserver-triggered fade + translate-up. Use to
//    reveal sections as the user scrolls past them. Stagger via the `delay`
//    prop on adjacent siblings if needed.
//  - <FocusPull>: logo-only animation that runs once on page load. The blur
//    resolves and the wordmark snaps to focus — the brand motion concept
//    from the brand sheet.
//  - useTilt(): micro hover-tilt for cards. Returns event handlers + style.

const { useEffect, useRef, useState } = React;

// One-time CSS injection for motion (keyframes + transition rules).
if (typeof document !== 'undefined' && !document.getElementById('hf-motion-styles')) {
  const s = document.createElement('style');
  s.id = 'hf-motion-styles';
  s.textContent = `
    .hf-fadeup { opacity: 0; transform: translateY(18px); transition: opacity .7s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.2,.7,.2,1); will-change: opacity, transform; }
    .hf-fadeup.is-in { opacity: 1; transform: none; }

    @keyframes hf-focus-pull {
      0%   { filter: blur(6px); opacity: 0; transform: translateX(-10px); }
      60%  { filter: blur(2px); opacity: .85; transform: translateX(-2px); }
      100% { filter: blur(0);   opacity: 1; transform: none; }
    }
    .hf-focuspull { animation: hf-focus-pull 480ms cubic-bezier(.2,.7,.2,1) both; }

    /* Dot inside the wordmark: comes in slightly behind the type, lands hot */
    @keyframes hf-dot-snap {
      0%   { transform: scale(0); opacity: 0; }
      60%  { transform: scale(0); opacity: 0; }
      75%  { transform: scale(1.3); opacity: 1; }
      100% { transform: scale(1); opacity: 1; }
    }
    .hf-dot-snap { animation: hf-dot-snap 680ms cubic-bezier(.2,.7,.2,1) both; transform-origin: center; }

    /* Card hover lift used by service cards and similar */
    .hf-lift { transition: transform .25s cubic-bezier(.2,.7,.2,1), box-shadow .25s, background .2s, border-color .2s; }
    .hf-lift:hover { transform: translateY(-3px); }

    /* Underline-reveal links */
    .hf-ulink { position: relative; display: inline-flex; align-items: center; gap: 8px; }
    .hf-ulink::after {
      content: ''; position: absolute; left: 0; right: 0; bottom: -3px; height: 1.5px;
      background: var(--ember);
      transform: scaleX(0); transform-origin: left;
      transition: transform .35s cubic-bezier(.2,.7,.2,1);
    }
    .hf-ulink:hover::after { transform: scaleX(1); }

    /* Button micro-press */
    .hf-btn { transition: transform .12s ease-out, background .15s, color .15s, box-shadow .2s; }
    .hf-btn:hover { transform: translateY(-1px); }
    .hf-btn:active { transform: translateY(0); }

    /* Pulse for active "now booking" pip and active step dots */
    @keyframes hf-pulse {
      0%, 100% { box-shadow: 0 0 0 0 rgba(194,97,31,0.55); }
      50%      { box-shadow: 0 0 0 6px rgba(194,97,31,0); }
    }
    .hf-pulse { animation: hf-pulse 2.4s ease-out infinite; }

    /* Marquee for client/trust strip — paused on hover so reading works */
    @keyframes hf-marquee {
      0%   { transform: translateX(0); }
      100% { transform: translateX(-50%); }
    }
    .hf-marquee-track { animation: hf-marquee 38s linear infinite; will-change: transform; }
    .hf-marquee-track:hover { animation-play-state: paused; }
  `;
  document.head.appendChild(s);
}

function FadeUp({ children, delay = 0, as: As = 'div', style = {}, threshold = 0.15, ...rest }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    // Defensive: if IntersectionObserver isn't available, just show.
    if (typeof IntersectionObserver === 'undefined') { setSeen(true); return; }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
    }, { threshold, rootMargin: '0px 0px -80px 0px' });
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  return (
    <As ref={ref}
        className={'hf-fadeup' + (seen ? ' is-in' : '')}
        style={{ ...style, transitionDelay: `${delay}ms` }}
        {...rest}>
      {children}
    </As>
  );
}

// FocusPull wraps a logo (or any element) and plays the focus-pull animation
// once on mount. Use on the topnav logo to brand the page load.
function FocusPull({ children, style = {} }) {
  return <span className="hf-focuspull" style={style}>{children}</span>;
}

// useIsMobile — reactive hook returning true when viewport is below the
// mobile breakpoint. Drives JSX-level structural choices (grids, nav).
function useIsMobile(breakpoint = 760) {
  const [m, setM] = useState(() =>
    typeof window !== 'undefined' && window.innerWidth < breakpoint
  );
  useEffect(() => {
    if (typeof window === 'undefined' || !window.matchMedia) return;
    const mq = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);
    const onChange = () => setM(mq.matches);
    onChange();
    if (mq.addEventListener) mq.addEventListener('change', onChange);
    else if (mq.addListener) mq.addListener(onChange);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener('change', onChange);
      else if (mq.removeListener) mq.removeListener(onChange);
    };
  }, [breakpoint]);
  return m;
}

// Subtle tilt on mouse-move for hero/feature cards. Negligible by default
// (max ±4 degrees) — never gimmicky.
function useTilt(strength = 4) {
  const ref = useRef(null);
  const [t, setT] = useState({ rx: 0, ry: 0 });
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const px = (e.clientX - r.left) / r.width - 0.5;
      const py = (e.clientY - r.top) / r.height - 0.5;
      setT({ rx: -py * strength, ry: px * strength });
    };
    const onLeave = () => setT({ rx: 0, ry: 0 });
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => { el.removeEventListener('mousemove', onMove); el.removeEventListener('mouseleave', onLeave); };
  }, [strength]);
  return {
    ref,
    style: {
      transform: `perspective(1200px) rotateX(${t.rx}deg) rotateY(${t.ry}deg)`,
      transition: 'transform .18s cubic-bezier(.2,.7,.2,1)',
      transformStyle: 'preserve-3d',
    },
  };
}

Object.assign(window, { FadeUp, FocusPull, useTilt, useIsMobile });
