// Root app shell const { useState: useStateA, useEffect: useEffectA } = React; function App() { const [page, setPage] = useStateA('home'); const [bookingState, setBookingState] = useStateA({ pickup: 'Klang HQ', start: null, end: null, travellers: 2, }); const [toast, setToast] = useStateA(null); const goTo = (p) => { setPage(p); window.scrollTo({ top: 0, behavior: 'instant' }); }; // Scroll-reveal: fade-up sections as they enter the viewport useEffectA(() => { if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; let obs; let raf; const setup = () => { const targets = document.querySelectorAll( 'section:not(.hero-clean):not(.nav-section), .boarding' ); if (!targets.length) { raf = requestAnimationFrame(setup); return; } obs = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('is-revealed'); obs.unobserve(e.target); } }); }, { threshold: 0.08, rootMargin: '0px 0px -30px 0px' }); targets.forEach(t => { t.classList.add('reveal-on-scroll'); obs.observe(t); }); }; raf = requestAnimationFrame(setup); return () => { cancelAnimationFrame(raf); if (obs) obs.disconnect(); }; }, [page]); return ( <>