/* global React */ const { useState, useEffect, useRef, useMemo } = React; /* ============================================================ GÊNESIS — Logo component (G with diagonal slash) Recreated faithfully from the brand manual. ============================================================ */ function GenesisLogo({ size = 36, variant = "full", color }) { if (variant === "full") { return ( Gênesis S/A — Governança com Inteligência Operacional ); } if (variant === "icon") { return ( Gênesis S/A ); } const fg = color || "currentColor"; return ( ); } /* Decorative slash motif — appears in section corners */ function SlashMotif({ opacity = 0.06 }) { return ( ); } /* ============================================================ Reveal-on-scroll wrapper ============================================================ */ function Reveal({ children, stagger = 0, as: Tag = "div", className = "", ...rest }) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver( (entries) => entries.forEach((e) => e.isIntersecting && el.classList.add("in")), { threshold: 0.12, rootMargin: "0px 0px -40px 0px" } ); io.observe(el); return () => io.disconnect(); }, []); return ( {children} ); } /* ============================================================ Rotating word (hero) ============================================================ */ function RotatingWord({ words, interval = 2400 }) { const [i, setI] = useState(0); useEffect(() => { const t = setInterval(() => setI((x) => (x + 1) % words.length), interval); return () => clearInterval(t); }, [words.length, interval]); return ( {words[i]} ); } /* ============================================================ Eyebrow + structured section header ============================================================ */ function Eyebrow({ children, number }) { return (
{number && ( {number} )}
); } /* ============================================================ COUNT UP — número que sobe quando entra na tela ============================================================ */ function CountUp({ value, suffix = "", prefix = "", dur = 1400, decimals = 0 }) { const [n, setN] = React.useState(0); const ref = React.useRef(null); const done = React.useRef(false); React.useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver((entries) => { if (!entries[0].isIntersecting || done.current) return; done.current = true; const t0 = performance.now(); const tick = (now) => { const t = Math.min((now - t0) / dur, 1); const e = 1 - Math.pow(1 - t, 3); setN(value * e); if (t < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }, { threshold: 0.4 }); io.observe(el); return () => io.disconnect(); }, [value, dur]); const shown = decimals > 0 ? n.toFixed(decimals) : Math.round(n).toLocaleString("pt-BR"); return {prefix}{shown}{suffix}; } /* Number badge — for "01 / 06" style */ function StepBadge({ n }) { return (
{n}
); } Object.assign(window, { GenesisLogo, SlashMotif, Reveal, RotatingWord, Eyebrow, StepBadge, CountUp });