/* ========== App root ========== */ function App() { const [introGone, setIntroGone] = React.useState(false); const [active, setActive] = React.useState("top"); const [silencioP, setSilencioP] = React.useState(0); // 0 = at nav header, 1 = at footer corner const [silencioVisible, setSilencioVisible] = React.useState(false); const onNav = (id) => { const el = document.getElementById(id); if (el) el.scrollIntoView({ behavior: "smooth", block: "start" }); }; React.useEffect(() => { const sections = ["top","nosotros","servicios","proyectos","prensa","contacto"]; const onScroll = () => { const y = window.scrollY + 200; for (let i = sections.length - 1; i >= 0; i--) { const el = document.getElementById(sections[i]); if (el && el.offsetTop <= y) { setActive(sections[i]); break; } } // progress: 0 until second section, 1 once we've scrolled ~60vh past it const secondRow = document.getElementById("nosotros"); const startY = secondRow ? secondRow.offsetTop : 0; setSilencioVisible(window.scrollY >= startY); const threshold = window.innerHeight * 0.55; const p = Math.max(0, Math.min(1, (window.scrollY - startY) / threshold)); // ease for a softer settle const eased = p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2; setSilencioP(eased); }; window.addEventListener("scroll", onScroll); onScroll(); return () => window.removeEventListener("scroll", onScroll); }, []); React.useEffect(() => { const els = document.querySelectorAll(".reveal"); const io = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) e.target.classList.add("in"); }); }, { threshold: 0.15 }); els.forEach(el => io.observe(el)); return () => io.disconnect(); }, []); const tweaks = useTweaks({ accent: "#8a6b3a", background: "ivory", density: "relaxed", }); React.useEffect(() => { const root = document.documentElement; root.style.setProperty("--accent", tweaks.accent); root.style.setProperty("--accent-deep", tweaks.accent); const bgMap = { ivory: { bg: "#f5f1ea", warm: "#ede6da", deep: "#e3dccd" }, bone: { bg: "#eeeae1", warm: "#e6e0d3", deep: "#d9d2c1" }, champagne: { bg: "#f2ebde", warm: "#ebe2d1", deep: "#ddd1b9" }, }; const m = bgMap[tweaks.background] || bgMap.ivory; root.style.setProperty("--ivory", m.bg); root.style.setProperty("--ivory-warm", m.warm); root.style.setProperty("--ivory-deep", m.deep); root.style.setProperty("--gutter", tweaks.density === "tight" ? "clamp(16px, 3vw, 44px)" : "clamp(20px, 4vw, 72px)"); }, [tweaks.accent, tweaks.background, tweaks.density]); return ( <> {!introGone && setIntroGone(true)} />}