/* app.jsx — root: language, hash routing, active-section tracking. Loaded last. */ const { useState: aS, useEffect: aE, useCallback: aC } = React; function parseHash() { const h = (window.location.hash || "").replace(/^#\/?/, ""); const m = h.match(/^project\/(.+)$/); return m ? { page: "project", id: decodeURIComponent(m[1]) } : { page: "home" }; } function App() { const [lang, setLang] = aS(() => localStorage.getItem("olv-lang") || "en"); const [route, setRoute] = aS(parseHash); const [activeId, setActiveId] = aS("home"); aE(() => { localStorage.setItem("olv-lang", lang); document.documentElement.lang = lang; }, [lang]); aE(() => { const onHash = () => setRoute(parseHash()); window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); /* active-section tracking on home */ aE(() => { if (route.page !== "home") return; const ids = ["home", "why", "portfolio", "about", "contact"]; const secMap = { stages: "why", pillars: "why" }; const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { let id = e.target.id; id = secMap[id] || id; if (ids.includes(id)) setActiveId(id); } }); }, { rootMargin: "-45% 0px -50% 0px", threshold: 0 }); ["home", "why", "stages", "pillars", "portfolio", "about", "contact"] .map((i) => document.getElementById(i)).filter(Boolean).forEach((el) => io.observe(el)); return () => io.disconnect(); }, [route.page]); const openProject = aC((id) => { window.location.hash = "#/project/" + encodeURIComponent(id); }, []); const backToPortfolio = aC(() => { window.location.hash = ""; setTimeout(() => window.scrollToId("portfolio"), 60); }, []); const navigate = aC((sectionId) => { if (route.page !== "home") { window.location.hash = ""; setTimeout(() => window.scrollToId(sectionId), 80); } else { window.scrollToId(sectionId); } }, [route.page]); /* audience card → jump to portfolio pre-filtered by category */ const pickCat = aC((cat) => { const doIt = () => { window.dispatchEvent(new CustomEvent("olv-filter-cat", { detail: cat })); setTimeout(() => window.scrollToId("portfolio"), 60); }; if (route.page !== "home") { window.location.hash = ""; setTimeout(doIt, 120); } else doIt(); }, [route.page]); return (