(function () { 'use strict'; var PAGE_COUNT = 10; var scrollEl = null; var railEl = null; var currentPage = 1; function pageEl(n) { return document.getElementById('landing-page-' + n); } function setActivePage(n, opts) { n = Math.max(1, Math.min(PAGE_COUNT, n | 0)); currentPage = n; var page = pageEl(n); if (page && scrollEl) { if (!opts || !opts.skipScroll) { page.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } document.querySelectorAll('.landing-rail-dot').forEach(function (dot) { var p = Number(dot.getAttribute('data-page')); dot.classList.toggle('is-active', p === n); dot.setAttribute('aria-current', p === n ? 'true' : 'false'); }); document.querySelectorAll('[data-goto-page]').forEach(function (el) { var p = Number(el.getAttribute('data-goto-page')); el.classList.toggle('is-active', p === n); }); if (window.history && window.history.replaceState) { var url = new URL(window.location.href); if (n <= 1) { url.searchParams.delete('page'); } else { url.searchParams.set('page', String(n)); } window.history.replaceState({ page: n }, '', url.toString()); } } function pageFromScroll() { if (!scrollEl) return 1; var mid = scrollEl.scrollTop + scrollEl.clientHeight * 0.4; var best = 1; var bestDist = Infinity; for (var i = 1; i <= PAGE_COUNT; i++) { var el = pageEl(i); if (!el) continue; var dist = Math.abs(el.offsetTop - mid); if (dist < bestDist) { bestDist = dist; best = i; } } return best; } function bindScrollSync() { if (!scrollEl) return; var ticking = false; scrollEl.addEventListener('scroll', function () { if (ticking) return; ticking = true; requestAnimationFrame(function () { ticking = false; var p = pageFromScroll(); if (p !== currentPage) { setActivePage(p, { skipScroll: true }); } }); }, { passive: true }); } function bindRail() { railEl = document.getElementById('landing-rail'); var handle = document.getElementById('landing-rail-handle'); if (handle && railEl) { handle.addEventListener('mouseenter', function () { railEl.classList.add('is-visible'); }); handle.addEventListener('focus', function () { railEl.classList.add('is-visible'); }); var dragY = 0; handle.addEventListener('pointerdown', function (ev) { dragY = ev.clientY; handle.setPointerCapture(ev.pointerId); railEl.classList.add('is-visible'); }); handle.addEventListener('pointermove', function (ev) { if (!handle.hasPointerCapture(ev.pointerId)) return; var dy = ev.clientY - dragY; if (Math.abs(dy) > 40) { setActivePage(currentPage + (dy > 0 ? 1 : -1)); dragY = ev.clientY; } }); } document.querySelectorAll('.landing-rail-dot').forEach(function (dot) { dot.addEventListener('click', function () { setActivePage(Number(dot.getAttribute('data-page'))); }); }); } function bindGotoLinks() { document.body.addEventListener('click', function (ev) { var t = ev.target.closest('[data-goto-page]'); if (!t) return; if (t.tagName === 'A' && t.getAttribute('href') === '#') { ev.preventDefault(); } setActivePage(Number(t.getAttribute('data-goto-page'))); }); } function bindLeftNav() { /* nav_shell.js handles #landing-nav-pane / #landing-nav-handle */ } function initFromUrl() { var params = new URLSearchParams(window.location.search); var p = parseInt(params.get('page') || '1', 10); if (p >= 1 && p <= PAGE_COUNT) { setTimeout(function () { setActivePage(p); }, 80); } else { setActivePage(1, { skipScroll: true }); } } function init() { scrollEl = document.getElementById('landing-scroll'); bindScrollSync(); bindRail(); bindGotoLinks(); bindLeftNav(); initFromUrl(); window.addEventListener('keydown', function (ev) { if (ev.target && /input|textarea|select/i.test(ev.target.tagName)) return; if (ev.key === 'PageDown' || ev.key === 'ArrowDown') { ev.preventDefault(); setActivePage(currentPage + 1); } else if (ev.key === 'PageUp' || ev.key === 'ArrowUp') { ev.preventDefault(); setActivePage(currentPage - 1); } }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } window.LandingNav = { goTo: setActivePage }; })();