// Shared primitives const { useState, useEffect, useRef, useMemo } = React; // Icons (simple, minimal SVGs) const Icon = { Drop: (p) => , Clock: (p) => , Shield: (p) => , Coin: (p) => , Spark: (p) => , Chart: (p) => , Key: (p) => , Play: (p) => , Arrow: (p) => , Plus: (p) => , Phone: (p) => , Whats: (p) => , Mail: (p) => }; // animated counter function useCountUp(target, duration = 1200, trigger = true) { const [val, setVal] = useState(0); useEffect(() => { if (!trigger) return; let start = null; const step = (ts) => { if (!start) start = ts; const p = Math.min(1, (ts - start) / duration); const eased = 1 - Math.pow(1 - p, 3); setVal(target * eased); if (p < 1) requestAnimationFrame(step); }; requestAnimationFrame(step); }, [target, trigger, duration]); return val; } function useReveal() { const ref = useRef(null); const [visible, setVisible] = useState(false); useEffect(() => { if (!ref.current) return; const obs = new IntersectionObserver( (entries) => { if (entries[0].isIntersecting) { setVisible(true); obs.disconnect(); } }, { threshold: 0.15 } ); obs.observe(ref.current); return () => obs.disconnect(); }, []); return [ref, visible]; } function formatBRL(n) { return n.toLocaleString('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 0 }); } Object.assign(window, { Icon, useCountUp, useReveal, formatBRL });