diff --git a/src/pages/index.astro b/src/pages/index.astro index 298e747..03994dc 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1249,6 +1249,59 @@ const canonical = new URL('/', Astro.site); activateTechnology(0); + /* The fixed shell deliberately keeps the masthead and footer outside main's + scrollport. Forward gestures that begin there (or in the shell gutter) into + main, so the story responds everywhere instead of only between the rules. */ + if (scrollRoot) { + const scrollMainBy = (event: WheelEvent) => { + const multiplier = event.deltaMode === WheelEvent.DOM_DELTA_LINE + ? 16 + : event.deltaMode === WheelEvent.DOM_DELTA_PAGE + ? scrollRoot.clientHeight + : 1; + scrollRoot.scrollBy({ top: event.deltaY * multiplier, behavior: 'auto' }); + }; + + document.addEventListener( + 'wheel', + (event) => { + if (scrollRoot.contains(event.target as Node) || event.deltaY === 0) return; + + event.preventDefault(); + scrollMainBy(event); + }, + { capture: true, passive: false }, + ); + + let touchY: number | null = null; + + document.addEventListener( + 'touchstart', + (event) => { + touchY = scrollRoot.contains(event.target as Node) + ? null + : event.touches[0]?.clientY ?? null; + }, + { capture: true, passive: true }, + ); + + document.addEventListener( + 'touchmove', + (event) => { + const nextTouchY = event.touches[0]?.clientY; + if (touchY === null || nextTouchY === undefined) return; + + event.preventDefault(); + scrollRoot.scrollBy({ top: touchY - nextTouchY, behavior: 'auto' }); + touchY = nextTouchY; + }, + { capture: true, passive: false }, + ); + + document.addEventListener('touchend', () => { touchY = null; }, { capture: true, passive: true }); + document.addEventListener('touchcancel', () => { touchY = null; }, { capture: true, passive: true }); + } + const stepObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { @@ -1257,7 +1310,9 @@ const canonical = new URL('/', Astro.site); if (Number.isInteger(index)) activateTechnology(index); }); }, - { root: scrollRoot, rootMargin: '-45% 0px -45% 0px' }, + /* A wider center band advances the next card earlier, reducing the scroll + distance between beats without changing the sticky composition. */ + { root: scrollRoot, rootMargin: '-38% 0px -38% 0px' }, ); steps.forEach((step) => stepObserver.observe(step));