/* Shared primitives + hooks */
const { useState, useEffect, useRef, useMemo, useLayoutEffect, useCallback } = React;

/* --- Reveal on scroll --- */
function Reveal({ children, className = '', delay = 0, as: As = 'div' }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let revealed = false;
    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    const show = () => {
      if (revealed) return;
      revealed = true;
      // The CSS handles the optional entrance flourish via a keyframe
      // animation tied to .in. Base .reveal is visible by default — no
      // animation timeline can ever leave the page hidden.
      el.classList.add('in');
    };
    // If already in viewport on mount, reveal after delay
    const r = el.getBoundingClientRect();
    const vh = window.innerHeight || document.documentElement.clientHeight;
    if (r.top < vh && r.bottom > 0) {
      const t = setTimeout(show, delay);
      return () => clearTimeout(t);
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          setTimeout(show, delay);
          io.unobserve(e.target);
        }
      });
    }, { rootMargin: '0px 0px -8% 0px', threshold: 0.05 });
    io.observe(el);
    // Safety-net: never let content stay hidden longer than 1.2s
    const safety = setTimeout(show, 1200 + delay);
    return () => { io.disconnect(); clearTimeout(safety); };
  }, [delay]);
  return <As ref={ref} className={`reveal ${className}`}>{children}</As>;
}

/* --- Animated count-up (when scrolled into view) --- */
function CountUp({ to = 100, suffix = '', prefix = '', duration = 1600, decimals = 0, className = '' }) {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  const started = useRef(false);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          const start = performance.now();
          const tick = (now) => {
            const p = Math.min(1, (now - start) / duration);
            const eased = 1 - Math.pow(1 - p, 3);
            setVal(to * eased);
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    return () => io.disconnect();
  }, [to, duration]);
  const display = decimals ? val.toFixed(decimals) : Math.round(val).toString();
  return <span ref={ref} className={className}>{prefix}{display}{suffix}</span>;
}

/* --- Magnetic button wrapper --- */
function Magnetic({ children, strength = 14, className = '' }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf = 0; let cx = 0, cy = 0;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const x = e.clientX - (r.left + r.width / 2);
      const y = e.clientY - (r.top + r.height / 2);
      cx += (x / r.width * strength - cx) * 0.2;
      cy += (y / r.height * strength - cy) * 0.2;
      el.style.transform = `translate(${cx}px, ${cy}px)`;
    };
    const onLeave = () => { el.style.transform = ''; };
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => { el.removeEventListener('mousemove', onMove); el.removeEventListener('mouseleave', onLeave); cancelAnimationFrame(raf); };
  }, [strength]);
  return <span ref={ref} className={`inline-block will-change-transform ${className}`}>{children}</span>;
}

/* --- Section wrapper --- */
function Section({ id, dark = true, className = '', children, label }) {
  return (
    <section id={id} className={`relative ${className}`}>
      {label && (
        <div className={`absolute left-1/2 -translate-x-1/2 top-6 text-[10px] tracking-[0.32em] font-mono uppercase ${dark ? 'text-paper-300/40' : 'text-ink-900/40'}`}>{label}</div>
      )}
      {children}
    </section>
  );
}

/* --- Mini chip / badge --- */
function Chip({ children, tone = 'violet', className = '' }) {
  const tones = {
    violet: 'bg-violet-600/10 text-violet-500 border-violet-600/20',
    cyan: 'bg-cy-400/10 text-cy-400 border-cy-400/20',
    magenta: 'bg-mag-400/10 text-mag-400 border-mag-400/20',
    ink: 'bg-ink-700/50 text-paper-100 border-ink-600/60',
    light: 'bg-ink-900/5 text-ink-900 border-ink-900/10',
  };
  return (
    <span className={`inline-flex items-center gap-2 px-3 py-1 rounded-full text-[11px] font-medium tracking-tight border ${tones[tone]} ${className}`}>
      {children}
    </span>
  );
}

/* --- Logo --- */
function Logo({ className = '', dark = true, size = 38, hideText = false, textClass = '' }) {
  return (
    <a href="#top" className={`inline-flex items-center gap-2.5 group ${className}`}>
      <span className="relative inline-flex items-center justify-center transition-transform group-hover:scale-105" style={{ width: size, height: size }}>
        <span className="absolute inset-0 rounded-full bg-violet-600/20 blur-md group-hover:bg-violet-600/40 transition-colors"></span>
        <img src={window.__resources.flowoLogo} alt="Flowo" className="relative w-full h-full object-contain" style={{ filter: 'drop-shadow(0 2px 12px rgba(124,58,237,0.45))' }} />
      </span>
      {!hideText && (
        <span className={`font-display font-semibold tracking-tight ${dark ? 'text-paper-50' : 'text-ink-900'} ${textClass || 'text-[22px] sm:text-[26px] md:text-[28px] leading-none'}`}>Flowo</span>
      )}
    </a>
  );
}

/* --- Logo mark only --- */
function LogoMark({ size = 38, className = '', glow = true }) {
  return (
    <span className={`relative inline-flex items-center justify-center ${className}`} style={{ width: size, height: size }}>
      {glow && <span className="absolute inset-0 rounded-full bg-violet-600/25 blur-md"></span>}
      <img src={window.__resources.flowoLogo} alt="" aria-hidden="true" className="relative w-full h-full object-contain" style={{ filter: glow ? 'drop-shadow(0 2px 10px rgba(124,58,237,0.5))' : 'none' }} />
    </span>
  );
}

/* --- Section heading helper --- */
function SectionEyebrow({ children, dark = true, className = '' }) {
  return (
    <div className={`inline-flex items-center gap-2 font-mono text-[10px] tracking-[0.28em] uppercase ${dark ? 'text-paper-300/70' : 'text-ink-900/60'} ${className}`}>
      <span className={`w-6 h-px ${dark ? 'bg-paper-300/40' : 'bg-ink-900/30'}`}></span>
      {children}
    </div>
  );
}

/* --- Tiny arrow icon --- */
const ArrowRight = ({ className = '' }) => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" className={className}>
    <path d="M5 12h14M13 5l7 7-7 7" />
  </svg>
);

const Icon = {
  Arrow: ArrowRight,
  Check: ({ className = '' }) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><path d="M20 6L9 17l-5-5" /></svg>
  ),
  Plus: ({ className = '' }) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" className={className}><path d="M12 5v14M5 12h14" /></svg>
  ),
  Minus: ({ className = '' }) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" className={className}><path d="M5 12h14" /></svg>
  ),
  Spark: ({ className = '' }) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" className={className}><path d="M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M5.6 18.4l2.8-2.8M15.6 8.4l2.8-2.8" /></svg>
  ),
};

/* expose */
Object.assign(window, { Reveal, CountUp, Magnetic, Section, Chip, Logo, LogoMark, SectionEyebrow, Icon });
