// 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 });