/* app.jsx — main composition + hash routing */ function App() { const bookingRef = useRef(null); const [route, setRoute] = useState(getRoute()); // Listen for hash changes (article navigation, back/forward). useEffect(() => { const onHash = () => setRoute(getRoute()); window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); // When we land back on the home page, honor any pending scroll target // (set when a nav/section link was clicked from a subpage). useEffect(() => { if (route.name !== "home") return; let pending = null; try { pending = sessionStorage.getItem("vd_scrollTo"); } catch (e) {} if (!pending) return; try { sessionStorage.removeItem("vd_scrollTo"); } catch (e) {} setTimeout(() => { if (pending === "#top") { window.scrollTo({ top: 0, behavior: "smooth" }); return; } const el = document.querySelector(pending); if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 80, behavior: "smooth" }); }, 90); }, [route]); // Navigate from a subpage back to a section on the landing page. const goHome = useCallback((hash) => { try { if (hash) sessionStorage.setItem("vd_scrollTo", hash); } catch (e) {} if (window.location.hash) window.location.hash = ""; else setRoute({ name: "home" }); }, []); const onBookClick = useCallback(() => { const el = document.getElementById("contacto"); if (el) { window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 60, behavior: "smooth" }); } else { // We're on a subpage: return home, then scroll to contact. goHome("#contacto"); } }, [goHome]); if (route.name === "article") { const article = findArticle(route.slug); if (article) { return (