/* 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 (
);
}
Object.assign(window, { Reveal, Sym, SectionMark, Eyebrow, Btn, Placeholder, Accordion });