/* global React */ const { useState, useRef, useEffect } = React; /* ---------- Reveal: subtle fade-up on scroll ---------- */ function Reveal({ children, as = 'div', delay = 0, className = '', style = {} }) { const ref = useRef(null); const [seen, setSeen] = useState(false); useEffect(() => { const el = ref.current; if (!el) return; let done = false; const reveal = () => { if (!done) { done = true; setSeen(true); } }; const check = () => { const r = el.getBoundingClientRect(); const vh = window.innerHeight || document.documentElement.clientHeight || 800; if (r.top < vh * 0.95 && r.bottom > -40) { reveal(); return true; } return false; }; // Synchronous check — reveals anything already in view immediately, // independent of rAF/IntersectionObserver (which can be throttled). check(); let io; if ('IntersectionObserver' in window) { io = new IntersectionObserver( (entries) => entries.forEach((e) => { if (e.isIntersecting) reveal(); }), { threshold: 0.1, rootMargin: '0px 0px -6% 0px' } ); io.observe(el); } const onScroll = () => check(); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); return () => { if (io) io.disconnect(); window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); }; }, []); const Tag = as; return ( {children} ); } /* ---------- Symbol image ---------- */ function Sym({ tone = 'gold', style = {}, className = '' }) { const src = tone === 'gold' ? 'assets/symbol-gold.png' : tone === 'blue' ? 'assets/symbol-blue.png' : 'assets/symbol-paper.png'; return ; } /* ---------- Section mark: alterna entre A (só símbolo) e B (filete + símbolo) ---------- */ function SectionMark({ onBlue = false }) { return (
); } /* ---------- Eyebrow ---------- */ function Eyebrow({ children, onBlue = false, mark = true }) { return (

{mark && } {children}

); } /* ---------- Button ---------- */ function Btn({ children, variant = 'solid', href = '#contato', lg = false, onBlue = false, arrow = true, newTab = false }) { let cls = 'btn '; if (variant === 'solid') cls += 'btn-solid'; else if (variant === 'gold') cls += 'btn-gold'; else cls += onBlue ? 'btn-ghost btn-ghost--on-blue' : 'btn-ghost'; if (lg) cls += ' btn-lg'; const tab = newTab ? { target: '_blank', rel: 'noopener' } : {}; return ( {children} {arrow && } ); } /* ---------- Placeholder image slot ---------- */ function Placeholder({ label, blue = false, style = {}, className = '' }) { return (
{label}
); } /* ---------- Accordion ---------- */ function Accordion({ items, onBlue = false, defaultOpen = -1 }) { const [open, setOpen] = useState(defaultOpen); return (
{items.map((it, i) => { const isOpen = open === i; return (
{it.a}
); })}
); } function AccBody({ open, children }) { const ref = useRef(null); const [h, setH] = useState(0); useEffect(() => { if (ref.current) setH(ref.current.scrollHeight); }, [children]); return (
{children}
); } Object.assign(window, { Reveal, Sym, SectionMark, Eyebrow, Btn, Placeholder, Accordion });