// Main app — wires sections, Tweaks panel, theme switching, and scroll reveal. const { useState, useEffect, useRef } = React; // Reveal-on-scroll: any element with .reveal fades up once visible. function useRevealOnScroll() { useEffect(() => { const els = document.querySelectorAll(".reveal:not(.is-in)"); if (!els.length) return; const io = new IntersectionObserver( (entries) => { entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("is-in"); io.unobserve(e.target); } }); }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" } ); els.forEach((el) => io.observe(el)); return () => io.disconnect(); }); } // Subtle parallax on hero photo + section labels (scroll-driven). function useScrollParallax() { useEffect(() => { let raf = 0; const onScroll = () => { if (raf) return; raf = requestAnimationFrame(() => { const y = window.scrollY; document.querySelectorAll("[data-parallax]").forEach((el) => { const speed = parseFloat(el.dataset.parallax || "0.05"); el.style.transform = `translate3d(0, ${(-y * speed).toFixed(1)}px, 0)`; }); raf = 0; }); }; onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); } // Top progress bar — slim line tracking page scroll. function ScrollProgress() { const ref = useRef(null); useEffect(() => { const onScroll = () => { const h = document.documentElement.scrollHeight - window.innerHeight; const p = h > 0 ? window.scrollY / h : 0; if (ref.current) ref.current.style.transform = `scaleX(${p})`; }; onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); return
; } // Top nav — minimal, sticky. function TopNav() { return (
Carlos Bezerra
Diagnóstico Patrimonial