Index: src/assets/css/style.css
===================================================================
--- src/assets/css/style.css	(revision fd8faf581c665d69b41dd6f5262d74bf432c0e1b)
+++ src/assets/css/style.css	(revision 19e28cedce7ba0de89244415d0c1f285866cd75a)
@@ -2457,19 +2457,13 @@
 }
 
-/* Snappen doet de SCROLLCONTAINER, en dat is het document -- niet .read-stream,
-   die heeft overflow: visible en scrollt zelf niet. Proximity en geen mandatory:
-   in een bericht dat langer is dan het scherm moet je rustig door kunnen lezen. */
-html:has(body.on-home[data-feed-view="reader"]) {
-    scroll-snap-type: y proximity;
-    /* GEEN scroll-behavior:smooth hier. Dat maakte elke beweging op deze
-       scroller traag, ook het snappen zelf -- en een snap moet vlot zijn
-       (Robin, 20-8: "vlot maar geanimeerd, mag niet te lang duren"). De browser
-       animeert een snap uit zichzelf al, en korter dan zijn smooth-scroll.
-       De terug-naar-boven-knop vraagt zijn animatie expliciet aan in
-       mod/read.js, dus die blijft vloeiend. */
-}
-/* En de browser niet óók laten compenseren als Load more er berichten bij zet:
-   Chrome en Firefox schuiven bij invoegen zelf mee (scroll anchoring), en dat
-   vecht met het snappen. */
+/* GEWOON SCROLLEN (Robin, 30-9: "Reader view normaal scrollen, Lenis mag
+   helemaal uit klonkt"). Hier stond scroll-snap-type op het document, en Lenis
+   deed het snappen erbovenop. Er snapt niets meer: de reader scrolt zoals elke
+   andere pagina. De .read-anker-punten hieronder staan er nog, maar zonder
+   snap-container doen ze niets. Terug willen? Zie de vault, "Klonkt Reader
+   Scroll": native snappen had bekende nadelen, en die staan daar. */
+/* Scroll anchoring uit: als Load more er berichten bij zet, schuiven Chrome en
+   Firefox anders zelf mee. Stond er voor het snappen, maar ook zonder snappen
+   hoort wat je leest niet te verspringen. */
 html:has(body.on-home[data-feed-view="reader"]),
 .feed-reader .read-stream { overflow-anchor: none; }
@@ -2561,6 +2555,7 @@
    zichtbare scherm soms de GROTE viewport, en dan komt svh net tekort.
    Zichtbaar kost dit niets: berichten hebben geen kader, alleen een scheidings-
-   lijn erboven, dus het laatste bericht krijgt hooguit witruimte eronder. */
-.feed-reader .read-post:last-child { min-height: 100lvh; }
+   lijn erboven, dus het laatste bericht krijgt hooguit witruimte eronder.
+   SINDS 30-9 WEG: zonder snappen hoeft die bovenkant nergens meer heen, en dan is
+   de volle schermhoogte alleen nog een leeg scherm aan het eind van de stroom. */
 
 /* ELK BERICHT EEN EIGEN SCHERM, als de site dat wil (Instellingen -> Weergave).
@@ -2575,14 +2570,9 @@
    Op desktop blijft het een keuze, want daar lees je in een kolom naast veel
    witruimte en is een doorlopende stroom vaak prettiger. */
-@media (hover: none) and (pointer: coarse) {
-    /* Op mobiel draait Lezen in paginamodus (body.is-paged), en die zet hieronder
-       een vaste hoogte. Deze regel is de terugval voor het moment vóór de module
-       geladen is, zodat de berichten niet eerst als losse stroom in beeld
-       springen. */
-    .feed-reader .read-post { min-height: 100svh; }
-/* Geen native snap op mobiel: dat doet lenis/snap, met een instelbare vangzone
-       en duur. Twee snapsystemen op dezelfde scroller vechten. */
-    html:has(body.on-home[data-feed-view="reader"]) { scroll-snap-type: none; }
-}
+/* SINDS 30-9 NIET MEER OP MOBIEL AFGEDWONGEN. Een scherm per bericht hoorde bij
+   vegen van bericht naar bericht, en dat vegen was het snappen. Zonder snappen
+   gaf het onder een kort bericht een leeg scherm -- dezelfde leegte waar Robin
+   op 20-8 op desktop over viel. De instelling hierboven geldt nu overal: wie een
+   scherm per bericht wil, zet hem aan. */
 
 /* -------- PAGINAMODUS --------
@@ -2590,9 +2580,9 @@
    berichten ga je met knoppen. Daarmee doet het scrollgevoel er niet meer toe:
    geen momentum om na te bouwen en geen snap die vangt.
-   De stroom zelf vangt geen vingers meer -- dat regelt lenis.stop() in
-   mod/read.js -- en data-lenis-prevent op het paneel houdt de scroll BINNEN een
-   bericht ongemoeid (die controle staat in Lenis vóór de gestopt-controle).
+   De stroom zelf scrolt niet: dat deed lenis.stop(), en sinds Lenis weg is
+   (30-9) de regel hieronder op het document. Het paneel scrolt zelf.
    Geldt waar een bericht een eigen scherm heeft: op mobiel altijd, op desktop
    als de site dat zo instelt. */
+html:has(body.is-paged) { overflow: hidden; }
 body.is-paged .feed-reader .read-post {
     height: 100svh;
@@ -2801,5 +2791,4 @@
 @media (prefers-reduced-motion: reduce) {
     html:has(body.on-home[data-feed-view="reader"]) {
-        scroll-snap-type: none;
         scroll-behavior: auto;
     }
Index: src/assets/js/mod/read.js
===================================================================
--- src/assets/js/mod/read.js	(revision fd8faf581c665d69b41dd6f5262d74bf432c0e1b)
+++ src/assets/js/mod/read.js	(revision 19e28cedce7ba0de89244415d0c1f285866cd75a)
@@ -7,18 +7,12 @@
  * weg, en dat is winst: Lezen is nu een WEERGAVE van de feed
  * (body[data-feed-view="reader"]), naast Tijdlijn en Grid. De feed levert de
- * berichten al, "meer laden" vult al aan, en het snappen naar berichtgrenzen
- * doet CSS.
- *
- * HET SNAPPEN STAAT HIER MET OPZET NIET IN. Ik heb dat een ronde lang wel
- * geprobeerd -- richting bijhouden, een vangzone uitrekenen, per scroll-event
- * het snappunt verzetten -- en dat is de verkeerde laag. Robins bezwaar (20-8):
- * "scroll-snap op het element is iets anders dan touch events,
- * requestAnimationFrame etc. dan gaan we te veel van de view doen." Klopt, en
- * het vocht ook met de browser: de scroll-events bevatten OOK de bewegingen van
- * zijn eigen snap-animatie, dus de richting die je eruit afleidt is niet die van
- * de gebruiker.
- *
- * Wat er nodig was, was een regel minder in de CSS en niet honderd erbij hier:
- * zie style.css bij .feed-reader .read-post.
+ * berichten al en "meer laden" vult al aan.
+ *
+ * GEWOON SCROLLEN (Robin, 30-9: "Reader view normaal scrollen, Lenis mag helemaal
+ * uit klonkt"). Hier stond Lenis: op desktop voor zacht scrollen en snappen naar
+ * de bovenkant van een bericht, op mobiel nam hij de vinger over en bootsten we
+ * het snappen na. Dat is er allemaal uit. De browser scrolt, zoals op elke andere
+ * pagina, en er snapt niets meer. Waarom snappen niet native terugkwam, en hoe
+ * dat alsnog zou kunnen, staat in de vault onder "Klonkt Reader Scroll".
  *
  * De titel en de voetlink in read-article.ejs zijn echte <a>'s en doen het werk
@@ -31,42 +25,22 @@
  */
 
-// VENDOR_V komt uit lib.js: een nummer voor de hele vendormap (shaer-724),
-// zodat 'ophogen als de bibliotheek wijzigt' op een plek staat.
-import { VENDOR_V } from './lib.js';
+const OP_TOUCH = window.matchMedia('(hover: none) and (pointer: coarse)');
 
 // ── Paginamodus ─────────────────────────────────────────────────────────────
-/**
- * Elk bericht een paneel dat zelf scrollt; tussen berichten ga je met knoppen.
- *
- * Robins voorstel (20-8) nadat het namaken van iOS-momentum niet lukte, en dat
- * is de winst: in dit model DOET het scrollgevoel er niet toe. Er is geen
- * momentum om na te bouwen en geen snap die vangt.
- *
- * Hoe het werkt:
- *  - lenis.stop() zet het scrollen van de STROOM stil. Lenis vangt dan wiel en
- *    vinger af (hij preventDefault't in onVirtualScroll), dus je kunt niet meer
- *    tussen berichten door scrollen.
- *  - data-lenis-prevent op elk paneel houdt de scroll BINNEN een bericht
- *    ongemoeid. Dat werkt ook terwijl Lenis gestopt is, want die controle staat
- *    in zijn bron vóór de gestopt-controle. Nagekeken in de dist, niet gehoopt.
- *  - Bewegen tussen panelen gaat met lenis.scrollTo(..., { force: true }), want
- *    force is precies de uitzondering die een gestopte Lenis toch laat scrollen.
- *
- * Geldt waar een bericht een eigen scherm heeft: op mobiel altijd, op desktop
- * als de site dat instelt (reader_full_page). Buiten die modus verandert er
- * niets -- dan is Lenis gewoon aan en scrol je vrij.
- */
 /**
  * PAGINAMODUS STAAT UIT -- maar de code blijft staan (Robin, 20-8: "weghalen
  * maar bewaren, voor als ik het later weer wil").
  *
- * Wat het is: elk bericht een paneel van een scherm dat zelf scrolt, met twee
- * balken om ertussen te navigeren en de stroomscroll vastgezet. Gebouwd omdat
- * het namaken van iOS-momentum niet lukte; in dit model doet het scrollgevoel er
- * namelijk niet toe. Mobiel is nu terug op systeemscroll met snap, en dat is wat
- * er ook stond voordat we dit probeerden.
+ * Wat het is: elk bericht een paneel van een scherm dat zelf scrollt, met twee
+ * balken om ertussen te navigeren. Gebouwd omdat het namaken van iOS-momentum
+ * niet lukte; in dit model doet het scrollgevoel er namelijk niet toe.
+ *
+ * Sinds Lenis weg is (30-9) zet de CSS de stroom vast in plaats van lenis.stop()
+ * (html:has(body.is-paged) in style.css), en gaan de balken met native
+ * scrollIntoView. Niet uitgeprobeerd sinds die omzetting, want de modus staat
+ * uit: wie hem aanzet, kijkt dat eerst na.
  *
  * Aanzetten: deze constante op true. Dan komen de balken terug (CSS hangt aan
- * body.is-paged), stopt Lenis de stroomscroll en scrollen de panelen zelf.
+ * body.is-paged) en scrollen de panelen zelf.
  */
 const PAGINAMODUS = false;
@@ -93,6 +67,5 @@
   const doel = P[Math.max(0, Math.min(P.length - 1, i))];
   if (!doel) return;
-  if (lenis) lenis.scrollTo(doel, { force: true });
-  else doel.scrollIntoView({ behavior: 'smooth', block: 'start' });
+  doel.scrollIntoView({ behavior: 'smooth', block: 'start' });
   setTimeout(zetBalken, 80);
 }
@@ -101,14 +74,13 @@
  * Omhoog vanaf het EERSTE bericht brengt je naar de header.
  *
- * In paginamodus staat Lenis stil, dus de pagina scrolt niet meer met je vinger
- * -- en dan is alles boven het eerste bericht onbereikbaar. Robin liep daar
- * tegenaan (20-8): "ik kan niet meer terug scrollen naar de header". De
- * omhoog-knop is daar de enige weg naartoe, dus die krijgt er een trede bij.
+ * In paginamodus scrolt de stroom niet met je vinger, dus dan is alles boven het
+ * eerste bericht onbereikbaar. Robin liep daar tegenaan (20-8): "ik kan niet
+ * meer terug scrollen naar de header". De omhoog-knop is daar de enige weg
+ * naartoe, dus die krijgt er een trede bij.
  */
 function gaOmhoog() {
   const i = huidigIndex();
   if (i > 0) { gaNaar(i - 1); return; }
-  if (lenis) lenis.scrollTo(0, { force: true });
-  else window.scrollTo({ top: 0, behavior: 'smooth' });
+  window.scrollTo({ top: 0, behavior: 'smooth' });
 }
 
@@ -162,16 +134,10 @@
 
 function pasPaginaModusToe() {
-  const aan = paginaModus();
-  document.body.classList.toggle('is-paged', aan);
-  panelen().forEach((a) => {
-    if (aan) a.setAttribute('data-lenis-prevent', '');
-    else a.removeAttribute('data-lenis-prevent');
-  });
-  if (lenis) { if (aan) lenis.stop(); else lenis.start(); }
+  document.body.classList.toggle('is-paged', paginaModus());
   zetBalken();
 }
 
 /**
- * Terug naar boven, en bewust NIET window.scrollTo(0).
+ * Terug naar boven, en bewust NIET meteen window.scrollTo(0).
  *
  * In een stroom wil je terug naar het BEGIN VAN DIT BERICHT als je halverwege een
@@ -220,387 +186,18 @@
 }
 
-/**
- * Omhoog scrollen blijft VRIJ (Robin, 20-8).
- *
- * Snappen hoort bij doorlezen; ga je terug, dan zoek je iets en bepaal je zelf
- * waar je stopt. CSS kent geen richtingsgevoelig snappen, dus dat ene stukje
- * moet hier -- maar dan ook niet meer dan dat: we zetten de CSS-functie aan of
- * uit op de scroller. Geen vangzones, geen snappunten per bericht, geen
- * scrollpositie-boekhouding.
- *
- * DE RICHTING KOMT UIT DE INVOER, niet uit scroll-events. Gemeten op dev: die
- * events bevatten ook de bewegingen van de browser zelf -- zijn snap-animatie en
- * de rubber-band -- en die gaan soms omhoog. Wie daaruit de richting afleidt,
- * leest de browser en niet de gebruiker.
- *
- * EN ER WORDT ALLEEN GESCHAKELD BIJ STILSTAND. Dat is de tweede les, en die
- * kostte een ronde. Eerst zette dit de schakelaar om bij ELK wiel-event en ELKE
- * vingerbeweging, dus binnen een veeg klapte hij meerdere keren heen en weer.
- * De browser raadpleegt scroll-snap-type alleen aan het eind van een gebaar of
- * van de uitloop, en of je daar net vóór of net ná zit bepaalt dan of er
- * gesnapt wordt. Gemeten (Robins melding "soms triggert het terwijl we nog aan
- * het doorscrollen zijn"):
- *
- *     snappen UIT, beweging naar 1459 loopt
- *     -> halverwege snappen AAN gezet
- *     -> eindigt op 1459, NIET op een berichtgrens
- *
- * Bij stilstand omzetten is wel onschuldig: dezelfde proef gaf 0px sprong.
- * Vandaar: richting bepalen bij het BEGIN van een gebaar, en daarna niets meer
- * aanraken tot de scroll echt stil is.
- *
- * Wat je daarvoor inlevert: binnen een veeg ligt de stand vast. Draai je
- * halverwege om zonder los te laten, dan geldt de stand van dat gebaar nog. Een
- * besluit per gebaar is voorspelbaar; het omklappen halverwege was het probleem.
- */
-const RUST_MS = 120;
-
-let bezig = false;          // loopt er een gebaar of een uitloop?
-let ooitGescrold = false;   // snappen begint UIT, zie zetSnappen()
-let rustTimer = null;
-
-/**
- * LENIS, en alleen op desktop.
- *
- * Op touch doet Lenis van zichzelf niets (syncTouch staat standaard uit) en is
- * het systeem-scrollen al soepel -- daar blijft de native CSS-snap staan die
- * hierboven beschreven is. Robins keuze (20-8): "enkel voor desktop, dat is
- * prima, logisch dat het niet op mobiel kan".
- *
- * WAAROM LENIS HIER STAAT, en dat is niet het vloeiende scrollen: de DUUR van
- * een snap is met native scroll-snap niet in te stellen -- die zit in de browser.
- * Lenis' snap-pakket wel: duration, easing, distanceThreshold en debounce zijn
- * allemaal van ons. Dat was de aanleiding.
- *
- * Het vloeiende scrollen (smoothWheel) kwam er daarna bij, en dat is de kant die
- * OPPASSEN vraagt. Een Mac-trackpad heeft zijn EIGEN momentum, en Lenis'
- * demping komt daar bovenop -- dubbel gedempt voelt drijverig. Vandaar lerp 0.2
- * in plaats van de standaard 0.1. Robin vond dat op 20-8 nog steeds te zweverig,
- * dus dat getal is nog niet uit; zie de opmerking bij de instellingen.
- *
- * De stand met `smoothWheel: false` werkte ook, en dan doet Lenis alleen de
- * snap. Dat is de terugvalpositie als het vloeiende scrollen niet bevalt.
- *
- * lenis/snap haakt alleen in op lenis.on('scroll') en roept lenis.scrollTo aan
- * (nagekeken in de dist), dus die opzet werkt.
- */
-const OP_DESKTOP = window.matchMedia('(hover: hover) and (pointer: fine)');
-// PROEF (20-8): Lenis ook op touch. Robin meldde op mobiel drie dingen -- de
-// header niet zichtbaar bij laden, snappen dat soms te ver gaat, en horizontaal
-// kunnen scrollen. De eerste twee komen van de NATIVE snap: die vangt al bij het
-// laden, en zijn uitloop vliegt bij een flick over een grens heen. Lenis zet de
-// native snap uit en doet het zelf, dus die twee kunnen ermee verdwijnen.
-//
-// De prijs is echt: syncTouch betekent dat Lenis het VINGERSCROLLEN overneemt
-// van iOS -- momentum, rubber-band en het wegschuiven van de adresbalk worden
-// dan een benadering in JavaScript. De makers waarschuwen daar zelf voor op
-// iOS < 16. Dit staat er dus als proef, niet als besluit: voelt het niet goed,
-// dan is OP_TOUCH weer false zetten de hele terugweg.
-const OP_TOUCH = window.matchMedia('(hover: none) and (pointer: coarse)');
-// VENDOR_V komt uit lib.js: een nummer voor de hele vendormap (shaer-724).
-
-let lenis = null;
-let snap = null;
-
-async function startLenis() {
-  // DESKTOP EN TOUCH ALLEBEI. Er heeft hier een tijd gestaan dat mobiel terug was
-  // op de systeemscroll; dat klopte niet meer met de regel hieronder, die
-  // syncTouch juist AANzet op touch. Reden dat Lenis ook op de telefoon meedraait:
-  // zijn snap heeft zijn scroll-gebeurtenissen nodig om te kunnen timen.
-  if (lenis || !(OP_DESKTOP.matches || OP_TOUCH.matches)) return;
-  const [L, S] = await Promise.all([
-    import(`/assets/vendor/lenis.mjs?v=${VENDOR_V}`),
-    import(`/assets/vendor/lenis-snap.mjs?v=${VENDOR_V}`),
-  ]);
-  lenis = new L.default({
-    /**
-     * Wat Lenis MET RUST LAAT.
-     *
-     * In paginamodus staat Lenis stil en scrolt alleen het paneel van het
-     * bericht zelf. Dat regelde ik eerst met een data-lenis-prevent-attribuut
-     * dat de module op elk paneel zette -- maar dan hangt het scrollen af van of
-     * dat attribuut op tijd en op elk (ook later bijgeladen) paneel staat, en
-     * Robin kon binnen een lang bericht niet scrollen.
-     *
-     * Deze functie stelt dezelfde vraag zonder die afhankelijkheid: is dit een
-     * bericht-paneel? Dan bemoeit Lenis zich er niet mee en scrolt de browser
-     * het zelf -- wat op een telefoon precies is wat je wilt, want dat is de
-     * systeemscroll.
-     */
-    prevent: (node) => !!(node && node.classList
-      && node.classList.contains('read-post')
-      && document.body.classList.contains('is-paged')),
-    // Lenis tekent de scrollbeweging zelf, maar STEVIG GEDEMPT (lerp 0.2 in
-    // plaats van de standaard 0.1). Reden: een muiswiel scrollt in schokken en
-    // heeft die demping nodig; een Mac-trackpad heeft zijn EIGEN momentum en
-    // krijgt er dan een tweede overheen -- dat is precies het drijverige gevoel
-    // waar Robin voor waarschuwde. Hoger betekent korter naijlen, dus dit is de
-    // middenweg: de schokjes weg, de nasleep kort.
-    // Staat het toch te zweven, dan is lerp omhoog (richting 1) of terug naar
-    // smoothWheel:false de knop -- die stand werkte ook, met alleen de snap.
-    smoothWheel: true,
-    lerp: 0.2,
-    // Alleen op touch overneemt hij het vingerscrollen; op desktop hoeft dat niet.
-    syncTouch: OP_TOUCH.matches,
-    // Twee touch-knoppen, en ze doen echt iets anders. Lenis rekent bij het
-    // LOSLATEN eenmalig een doel uit -- afstand = snelheid^touchInertiaExponent
-    // -- en kruipt daar dan naartoe met syncTouchLerp.
-    //
-    //   touchInertiaExponent  hoe VER de flick draagt   (standaard 1.7)
-    //   syncTouchLerp         hoe hard hij REMT         (standaard 0.075)
-    //
-    // Let op: `touchInertiaMultiplier` bestaat NIET in 1.3.26. Lenis slikt
-    // onbekende opties zonder fout, dus zo'n regel lijkt te werken en doet niets.
-    // Controleer een optienaam in src/assets/vendor/lenis.mjs voor je hem zet.
-    //
-    // Robin wilde langer en sneller uitrollen zonder remgevoel, dus de exponent
-    // gaat omhoog (een stevige flick draagt daarmee ruim vier tot zes keer zo
-    // ver) en de lerp gaat juist boven de standaard: hij legt die afstand vlot
-    // af in plaats van er stroperig naartoe te kruipen.
-    ...(OP_TOUCH.matches ? { syncTouchLerp: 0.09, touchInertiaExponent: 2.2 } : {}),
-    autoRaf: true,
-  });
-  snap = new S.default(lenis, {
-    type: 'proximity',
-    // DE VANGZONE, en dit is HET getal om aan te draaien. Ooit 12%, toen 55%
-    // (20-8: eerder vangen, boven de reacties), en 20-8 terug naar 12% -- want
-    // sinds het snappen alleen nog vooruit werkt, voelde die brede zone als
-    // trekken tijdens het lezen. 12% is ~110 pixels op een venster van 910: hij
-    // vangt pas vlak vóór de lijn.
-    // Houd dit gelijk aan vangZone() hieronder: deze drempel bepaalt of
-    // lenis/snap überhaupt aanklopt, die andere of wij het doorlaten. Zet je
-    // deze lager dan die, dan komt onze regel nooit aan bod.
-    distanceThreshold: '12%',
-    // Hoe lang na de laatste scrollbeweging hij mag vangen. De standaard is 500
-    // en dat voelt als te laat. Op touch nog korter dan op desktop, want daar
-    // eindigt een veeg in een lange, trage staart -- en juist dan wil je dat de
-    // snap er snel bij is in plaats van te wachten tot de laatste pixel stil ligt.
-    //
-    // LET OP DE SPANNING: een vloeiendere uitloop (lagere syncTouchLerp) maakt
-    // die staart langer, en stelt de snap dus uit. Deze twee getallen houden
-    // elkaar in evenwicht; draai je aan de een, kijk dan ook naar de ander.
-    // OP TOUCH JUIST LANG, en dat is het omgekeerde van wat ik vorige ronde deed.
-    // Tussen je vinger loslaten en het op gang komen van de uitloop zit een korte
-    // stilte in de scrollbeweging. Met 25ms viel de snap precies in dat gat: hij
-    // greep op het moment van loslaten en knipte de veeg af -- wat aanvoelt als
-    // "stroef bij het loslaten", en het werd er dan ook erger van. 200ms laat de
-    // uitloop eerst zijn werk doen.
-    // Met een iOS-achtige uitloop duurt de staart lang; te kort wachten laat de
-    // snap midden in de vlucht ingrijpen. 150ms laat hem uitrollen en vangt dan.
-    debounce: OP_TOUCH.matches ? 150 : 60,
-    // Op touch korter: een telefoon vraagt om directer antwoord dan een muis, en
-    // de snap komt daar aan het eind van een lange uitloop -- dan mag hij kort.
-    duration: OP_TOUCH.matches ? 0.18 : 0.4,
-    // Vlot weg, dan steeds langzamer aankomen (Robin, 20-8). easeOutQuart: op de
-    // helft van de tijd is 94% van de weg af, en de rest dempt zacht uit.
-    // Bewust NIET Lenis' standaard easeOutExpo -- die schiet weg en kruipt dan
-    // zo lang na dat het lijkt of hij niet afmaakt.
-    easing: (t) => 1 - Math.pow(1 - t, 4),
-  });
-  // Het snappunt is de bovenkant van elk bericht -- ook van het laatste. Dat
-  // deed eerder niet mee omdat zijn bovenkant onbereikbaar was; sinds het
-  // laatste bericht in CSS een volle schermhoogte krijgt, kan hij wel.
-  const berichten = [...document.querySelectorAll('.feed-reader .read-post')];
-  berichten.forEach((a) => snap.addElement(a, { align: 'start' }));
-
-  // ALLEEN VOORUIT VANGEN. Dit hoort bij de ruime zone hierboven en is niet
-  // optioneel: lenis/snap kiest het DICHTSTBIJZIJNDE punt en zijn drempel geldt
-  // naar twee kanten. Scroll je een lang bericht in en stop je 300 pixels onder
-  // de bovenkant, dan is die bovenkant het dichtstbij -- en met een zone van 400
-  // wordt je teruggetrokken. Dat is precies de klacht "ik kan niet scrollen
-  // binnen een lang bericht", en met de oude zone van 86 pixels viel het alleen
-  // niet op.
-  //
-  // Dus: een doel ACHTER je slaan we over. Ligt er een punt voor je binnen de
-  // zone, dan gaan we daarheen; anders gebeurt er niets en scrol je vrij door.
-  // Zo verruimt de zone alleen de kant waar hij bedoeld is.
-  //
-  // Waarom niet gewoon de drempel? Omdat lenis/snap alleen de dichtstbijzijnde
-  // kandidaat beoordeelt: zonder deze omleiding houdt de zone vooruit op bij de
-  // helft van de afstand tussen twee berichten, hoe groot je de drempel ook zet.
-  //
-  // DE REGEL, in Robins woorden (20-8): "enkel bij downscrollen, aan de
-  // onderkant van elke post, snappen naar de lijn tussen de posts" -- en geen
-  // snap op een bericht dat al voorbij is gescrold. Drie voorwaarden dus:
-  //   1. de laatste echte beweging ging omlaag,
-  //   2. het doel ligt VOOR je (een punt achter je slaan we over),
-  //   3. het ligt binnen de vangzone -- die begint rond de voet van het bericht.
-  // Het doel zelf blijft de bovenkant van het volgende bericht: dat IS de lijn
-  // ertussen, en dat is het essentiële.
-  //
-  // DE ZONE IS EEN GETAL, geen '55%'. Die string kwam ongewijzigd uit de opties
-  // en werd hier met een getal vergeleken -- altijd onwaar, dus deze terugval
-  // heeft nooit gewerkt en alleen het doel dat lenis zelf koos kwam erdoor.
-  const vangZone = () => 0.12 * window.innerHeight;   // gelijk aan distanceThreshold hierboven
-  // Lenis' eigen `direction` is het teken van de snelheid, en die is bij het
-  // afvuren van de (gedebouncede) snap alweer nul. Daarom onthouden we de
-  // laatste richting die er echt was.
-  let laatsteRichtingOmlaag = true;
-  lenis.on('scroll', () => {
-    if (Math.abs(lenis.velocity) > 0.05) laatsteRichtingOmlaag = lenis.velocity > 0;
-  });
-  const echtGaNaar = snap.goTo.bind(snap);
-  snap.goTo = (index) => {
-    if (!laatsteRichtingOmlaag) return;   // omhoog: nooit vangen
-    const punten = snap.computeSnaps();   // zelfde volgorde als goTo intern gebruikt
-    const nu = lenis.scroll;
-    let vooruit = -1;
-    punten.forEach((punt, i) => {
-      if (punt.value > nu + 2 && (vooruit < 0 || punt.value < punten[vooruit].value)) vooruit = i;
-    });
-    if (vooruit < 0) return;              // niets meer voor je: vrij uitscrollen
-    if (punten[vooruit].value - nu <= vangZone()) echtGaNaar(vooruit);
-  };
-
-  // OP TOUCH DOET DE MODULE-EIGEN TRIGGER HET NIET, en dat is meetbaar in de
-  // vendor-bron, geen vermoeden. Drie feiten op een rij:
-  //
-  //   1. lenis geeft 'virtual-scroll' door met de RUWE vingerdelta, VOOR hij
-  //      de uitloop uitrekent (teken * |snelheid|^touchInertiaExponent).
-  //   2. lenis-snap negeert elke touchmove en beoordeelt dus EEN keer per
-  //      gebaar, op touchend, met `scroll + rawDelta` -- de plek waar je
-  //      vinger LOSLIET.
-  //   3. de uitloop draagt daarna nog honderden pixels verder.
-  //
-  // De snapbeslissing valt dus op een positie die de scroll meteen verlaat.
-  // Op desktop klopt dezelfde som wel: wieldelta's zijn klein en de
-  // smoothWheel-uitloop is kort, dus voorspelling en landing liggen bijeen.
-  // Vandaar: op touch de module-trigger eraf en zelf beoordelen tegen
-  // lenis.targetScroll -- die wordt synchroon bij touchend gezet en IS het
-  // exacte landingspunt van de uitloop.
-  if (OP_TOUCH.matches) {
-    // Hoe lang het richten naar de lijn duurt, in seconden. De ene knop voor
-    // "snapperiger": 0.18 is direct, 0.3 is landen, 0.5 is zweven.
-    const SNAP_DUUR = 0.22;
-    lenis.off('virtual-scroll', snap.onSnapDebounced);
-    let raakTimer = null;
-    let vertrek = 0;   // scrollpositie bij loslaten: punten daarachter zijn
-                       // de bovenkant van het HUIDIGE bericht, nooit grijpen
-    lenis.on('virtual-scroll', (e) => {
-      const soort = e.event && e.event.type;
-      if (soort === 'touchstart' || soort === 'touchmove') { clearTimeout(raakTimer); return; }
-      if (soort !== 'touchend') return;
-      vertrek = lenis.scroll;
-      clearTimeout(raakTimer);
-      // TIMEOUT 0, geen 150ms. Dit event komt binnen VOOR lenis zelf de
-      // touchend verwerkt (de emit staat in de bron boven de verwerking), dus
-      // targetScroll is hier nog het oude doel. Een tik later is de uitloop
-      // gestart en staat targetScroll op de echte landing -- en dan sturen we
-      // hem meteen bij, in plaats van de uitloop 150ms te laten lopen en er
-      // dan een aparte snap-animatie overheen te zetten.
-      raakTimer = setTimeout(() => {
-        if (!laatsteRichtingOmlaag || snap.isStopped) return;
-        const doel = lenis.targetScroll;   // de echte landing, niet de raakdelta
-        const punten = snap.computeSnaps();
-        // De EERSTE grens voorbij het loslaatpunt, niet de dichtstbijzijnde bij
-        // de landing. Robins regel (24-8): wordt het target voorbijgescrolld,
-        // dan landen we alsnog OP het target. De zone werkt dus alleen aan de
-        // korte kant -- kom je er niet eens bij in de buurt, dan lees je gewoon
-        // binnen een lang bericht en blijft alles vrij. Eroverheen, hoe ver
-        // ook, betekent grijpen. Een harde veeg komt daarmee altijd precies
-        // een bericht verder, nooit twee: dat is het bladeren.
-        let eerste = -1;
-        punten.forEach((punt, i) => {
-          if (punt.value > vertrek + 2 && (eerste < 0 || punt.value < punten[eerste].value)) eerste = i;
-        });
-        if (eerste < 0) return;            // niets meer voor je: vrij uitscrollen
-        // HET RICHTEN IS DE SNAP (Robins regel, 24-8): de lopende uitloop
-        // krijgt het nieuwe doel, er komt geen tweede animatie overheen.
-        //
-        // MET EEN VASTE DUUR, niet met de lerp van de uitloop. Die lerp-vorm
-        // (0.09) is boterzacht maar heeft een exponentiele staart van ruim een
-        // halve seconde -- Robin wilde het korter en beslister (24-8). Een
-        // duur eindigt ECHT, op een instelbaar moment, zoals iOS-paging: vlot
-        // weg, stevig landen. Zelfde easing-familie als de desktop-snap.
-        // SNAP_DUUR is de enige knop: korter is snapperiger, langer is zachter.
-        if (doel >= punten[eerste].value - vangZone()) {
-          lenis.scrollTo(punten[eerste].value, {
-            duration: SNAP_DUUR,
-            easing: (t) => 1 - Math.pow(1 - t, 4),
-            force: true,
-            userData: { initiator: 'snap' },
-          });
-        }
-      }, 0);
-    });
-  }
-
-  // Native snappen uit: twee mechanismen op dezelfde scroller vechten.
-  document.documentElement.style.scrollSnapType = 'none';
-}
-
-function stopLenis() {
-  if (snap) { snap.destroy(); snap = null; }
-  if (lenis) { lenis.destroy(); lenis = null; }
-  document.documentElement.style.scrollSnapType = '';
-}
-
-/**
- * Omhoog niet snappen. Met Lenis is dat snap.stop()/start(); zonder Lenis (dus
- * op touch) zetten we de CSS-eigenschap om, precies zoals hiervoor.
- */
-function zetSnappen(aan) {
-  if (snap) { if (aan) snap.start(); else snap.stop(); return; }
-  // Zonder Lenis (mobiel) zetten we de CSS-eigenschap om. Hij staat bij het
-  // laden UIT -- dat is de standaardstand van deze variabele -- zodat de browser
-  // niet meteen naar het eerste bericht springt en de header wegvalt. Pas je
-  // eerste gebaar naar beneden zet hem aan.
-  const el = document.documentElement;
-  const wil = aan ? '' : 'none';
-  if (el.style.scrollSnapType !== wil) el.style.scrollSnapType = wil;
-}
-
-/** Een richting geldt alleen als er NIETS beweegt. Anders negeren we hem. */
-function nieuwGebaar(naarBeneden) {
-  if (bezig) return;
-  bezig = true;
-  zetSnappen(naarBeneden);
-}
-
-/**
- * Het gebaar is pas voorbij als de SCROLL stil is, niet als de vinger loslaat:
- * op iOS loopt de uitloop daarna nog door. `scrollend` zegt dat precies, maar
- * bestaat niet overal (Chrome 114+, Safari 17+) -- vandaar ook de timer.
- */
-function rustNu() { bezig = false; }
-function planRust() {
-  clearTimeout(rustTimer);
-  rustTimer = setTimeout(rustNu, RUST_MS);
-}
-
-function opWiel(e) { if (Math.abs(e.deltaY) > 1) nieuwGebaar(e.deltaY > 0); }
-let raakY = 0;
-function opRaakStart(e) { if (e.touches && e.touches[0]) raakY = e.touches[0].clientY; }
-function opRaakBeweeg(e) {
-  if (!e.touches || !e.touches[0]) return;
-  const y = e.touches[0].clientY;
-  // Vinger omhoog = inhoud omlaag. Drie pixels speling tegen de trilling van een
-  // duim die stilstaat.
-  if (Math.abs(y - raakY) > 3) { nieuwGebaar(y < raakY); raakY = y; }
-}
-function opToets(e) {
-  if (['ArrowDown', 'PageDown', 'End', ' ', 'Spacebar'].indexOf(e.key) >= 0) nieuwGebaar(true);
-  else if (['ArrowUp', 'PageUp', 'Home'].indexOf(e.key) >= 0) nieuwGebaar(false);
-}
-
 let knop = null;
 let opScroll = null;
 
 export function init() {
-  // EERST OPRUIMEN, en pas daarna terugvallen als er geen leesstroom is.
-  //
-  // Dit stond andersom, en dat brak het scrollen op de HELE site: navigeerde je
-  // van Lezen naar het beheer, dan viel init() bij de ontbrekende leesstroom
-  // meteen terug -- en bleef Lenis leven EN gestopt (lenis.stop() vangt wiel en
-  // vinger af). Daarna scrolde niets meer, ook niet op pagina's die met Lezen
-  // niets te maken hebben. Robins melding (20-8): "scrollen werkt nu nergens ook
-  // niet in admin panels".
-  //
-  // Opruimen hoort dus bij het VERLATEN van de weergave, niet bij het opzetten
-  // ervan. init() draait bij elke paginawissel, dus dit is de plek.
-  stopLenis();
+  // EERST OPRUIMEN, en pas daarna terugvallen als er geen leesstroom is. init()
+  // draait bij elke paginawissel, en wat de leesweergave aanzette hoort weg te
+  // zijn zodra je hem verlaat -- ook op pagina's die met Lezen niets te maken
+  // hebben (Robins melding van 20-8, toen dat misging: "scrollen werkt nu nergens
+  // ook niet in admin panels").
   document.body.classList.remove('is-paged');
-  document.querySelectorAll('[data-lenis-prevent].read-post')
-    .forEach((a) => a.removeAttribute('data-lenis-prevent'));
+  // Een tabblad dat nog met de vorige versie van deze module is geopend, heeft
+  // het native snappen inline uitgezet. Na een htmx-wissel naar deze versie hoort
+  // daar niets van over te blijven.
+  document.documentElement.style.scrollSnapType = '';
 
   const s = document.getElementById('read-stream');
@@ -625,25 +222,12 @@
   if (opScroll) {
     window.removeEventListener('scroll', opScroll);
-    window.removeEventListener('scrollend', rustNu);
     window.removeEventListener('resize', opScroll);
-    window.removeEventListener('wheel', opWiel);
-    window.removeEventListener('touchstart', opRaakStart);
-    window.removeEventListener('touchmove', opRaakBeweeg);
-    window.removeEventListener('keydown', opToets);
   }
-  // Elke scroll -- van een vinger of van de browser zelf -- houdt het gebaar
-  // levend; pas als het stil blijft mag een nieuwe richting gelden.
   opScroll = () => {
     if (knop) toonKnop(knop);
-    planRust();
     if (document.body.classList.contains('is-paged')) zetBalken();
   };
   window.addEventListener('scroll', opScroll, { passive: true });
-  window.addEventListener('scrollend', rustNu);
   window.addEventListener('resize', opScroll, { passive: true });
-  window.addEventListener('wheel', opWiel, { passive: true });
-  window.addEventListener('touchstart', opRaakStart, { passive: true });
-  window.addEventListener('touchmove', opRaakBeweeg, { passive: true });
-  window.addEventListener('keydown', opToets);
 
   const balkBoven = document.getElementById('read-prev');
@@ -652,11 +236,5 @@
   if (balkOnder) balkOnder.onclick = () => gaNaar(huidigIndex() + 1);
 
-  // Alleen in de leesweergave, en alleen op desktop. Bij elke init() opnieuw
-  // beoordelen: van Grid naar Lezen schakelen hoort hem aan te zetten, en
-  // wegnavigeren hoort hem op te ruimen.
-  if (document.body.dataset.feedView === 'reader') startLenis().then(pasPaginaModusToe);
-  else pasPaginaModusToe();
-
-
+  pasPaginaModusToe();
 }
 
Index: src/assets/vendor/lenis-snap.mjs
===================================================================
--- src/assets/vendor/lenis-snap.mjs	(revision fd8faf581c665d69b41dd6f5262d74bf432c0e1b)
+++ 	(revision )
@@ -1,334 +1,0 @@
-//#region packages/snap/src/debounce.ts
-function debounce(callback, delay) {
-	let timer;
-	return function(...args) {
-		clearTimeout(timer);
-		timer = setTimeout(() => {
-			timer = void 0;
-			callback.apply(this, args);
-		}, delay);
-	};
-}
-//#endregion
-//#region packages/snap/src/element.ts
-function removeParentSticky(element) {
-	if (getComputedStyle(element).position === "sticky") {
-		element.style.setProperty("position", "static");
-		element.dataset.sticky = "true";
-	}
-	if (element.offsetParent) removeParentSticky(element.offsetParent);
-}
-function addParentSticky(element) {
-	if (element?.dataset?.sticky === "true") {
-		element.style.removeProperty("position");
-		delete element.dataset.sticky;
-	}
-	if (element.offsetParent) addParentSticky(element.offsetParent);
-}
-function offsetTop(element, accumulator = 0) {
-	const top = accumulator + element.offsetTop;
-	if (element.offsetParent) return offsetTop(element.offsetParent, top);
-	return top;
-}
-function offsetLeft(element, accumulator = 0) {
-	const left = accumulator + element.offsetLeft;
-	if (element.offsetParent) return offsetLeft(element.offsetParent, left);
-	return left;
-}
-function scrollTop(element, accumulator = 0) {
-	const top = accumulator + element.scrollTop;
-	if (element.offsetParent) return scrollTop(element.offsetParent, top);
-	return top + window.scrollY;
-}
-function scrollLeft(element, accumulator = 0) {
-	const left = accumulator + element.scrollLeft;
-	if (element.offsetParent) return scrollLeft(element.offsetParent, left);
-	return left + window.scrollX;
-}
-var SnapElement = class {
-	element;
-	options;
-	align;
-	rect = {};
-	wrapperResizeObserver;
-	resizeObserver;
-	debouncedWrapperResize;
-	constructor(element, { align = ["start"], ignoreSticky = true, ignoreTransform = false } = {}) {
-		this.element = element;
-		this.options = {
-			align,
-			ignoreSticky,
-			ignoreTransform
-		};
-		this.align = [align].flat();
-		this.debouncedWrapperResize = debounce(this.onWrapperResize, 500);
-		this.wrapperResizeObserver = new ResizeObserver(this.debouncedWrapperResize);
-		this.wrapperResizeObserver.observe(document.body);
-		this.onWrapperResize();
-		this.resizeObserver = new ResizeObserver(this.onResize);
-		this.resizeObserver.observe(this.element);
-		this.setRect({
-			width: this.element.offsetWidth,
-			height: this.element.offsetHeight
-		});
-	}
-	destroy() {
-		this.wrapperResizeObserver.disconnect();
-		this.resizeObserver.disconnect();
-	}
-	setRect({ top, left, width, height, element } = {}) {
-		top = top ?? this.rect.top;
-		left = left ?? this.rect.left;
-		width = width ?? this.rect.width;
-		height = height ?? this.rect.height;
-		element = element ?? this.rect.element;
-		if (top === this.rect.top && left === this.rect.left && width === this.rect.width && height === this.rect.height && element === this.rect.element) return;
-		this.rect.top = top;
-		this.rect.y = top;
-		this.rect.width = width;
-		this.rect.height = height;
-		this.rect.left = left;
-		this.rect.x = left;
-		this.rect.bottom = top + height;
-		this.rect.right = left + width;
-	}
-	onWrapperResize = () => {
-		let top;
-		let left;
-		if (this.options.ignoreSticky) removeParentSticky(this.element);
-		if (this.options.ignoreTransform) {
-			top = offsetTop(this.element);
-			left = offsetLeft(this.element);
-		} else {
-			const rect = this.element.getBoundingClientRect();
-			top = rect.top + scrollTop(this.element);
-			left = rect.left + scrollLeft(this.element);
-		}
-		if (this.options.ignoreSticky) addParentSticky(this.element);
-		this.setRect({
-			top,
-			left
-		});
-	};
-	onResize = ([entry]) => {
-		if (!entry?.borderBoxSize[0]) return;
-		const width = entry.borderBoxSize[0].inlineSize;
-		const height = entry.borderBoxSize[0].blockSize;
-		this.setRect({
-			width,
-			height
-		});
-	};
-};
-//#endregion
-//#region packages/snap/src/uid.ts
-let index = 0;
-function uid() {
-	return index++;
-}
-//#endregion
-//#region packages/snap/src/snap.ts
-/**
-* Snap class to handle the snap functionality
-*
-* @example
-* const snap = new Snap(lenis, {
-*   type: 'mandatory', // 'mandatory', 'proximity' or 'lock'
-*   onSnapStart: (snap) => {
-*     console.log('onSnapStart', snap)
-*   },
-*   onSnapComplete: (snap) => {
-*     console.log('onSnapComplete', snap)
-*   },
-* })
-*
-* snap.add(500) // snap at 500px
-*
-* const removeSnap = snap.add(500)
-*
-* if (someCondition) {
-*   removeSnap()
-* }
-*/
-var Snap = class {
-	options;
-	elements = /* @__PURE__ */ new Map();
-	snaps = /* @__PURE__ */ new Map();
-	viewport = {
-		width: window.innerWidth,
-		height: window.innerHeight
-	};
-	isStopped = false;
-	onSnapDebounced;
-	currentSnapIndex;
-	constructor(lenis, { type = "proximity", lerp, easing, duration, distanceThreshold = "50%", debounce: debounceDelay = 500, onSnapStart, onSnapComplete } = {}) {
-		this.lenis = lenis;
-		if (!window.lenis) window.lenis = {};
-		window.lenis.snap = true;
-		this.options = {
-			type,
-			lerp,
-			easing,
-			duration,
-			distanceThreshold,
-			debounce: debounceDelay,
-			onSnapStart,
-			onSnapComplete
-		};
-		this.onWindowResize();
-		window.addEventListener("resize", this.onWindowResize);
-		this.onSnapDebounced = debounce(this.onSnap, this.options.debounce);
-		this.lenis.on("virtual-scroll", this.onSnapDebounced);
-	}
-	/**
-	* Destroy the snap instance
-	*/
-	destroy() {
-		this.lenis.off("virtual-scroll", this.onSnapDebounced);
-		window.removeEventListener("resize", this.onWindowResize);
-		this.elements.forEach((element) => {
-			element.destroy();
-		});
-	}
-	/**
-	* Start the snap after it has been stopped
-	*/
-	start() {
-		this.isStopped = false;
-	}
-	/**
-	* Stop the snap
-	*/
-	stop() {
-		this.isStopped = true;
-	}
-	/**
-	* Add a snap to the snap instance
-	*
-	* @param value The value to snap to
-	* @param userData User data that will be forwarded through the snap event
-	* @returns Unsubscribe function
-	*/
-	add(value) {
-		const id = uid();
-		this.snaps.set(id, { value });
-		return () => this.snaps.delete(id);
-	}
-	/**
-	* Add an element to the snap instance
-	*
-	* @param element The element to add
-	* @param options The options for the element
-	* @returns Unsubscribe function
-	*/
-	addElement(element, options = {}) {
-		const id = uid();
-		this.elements.set(id, new SnapElement(element, options));
-		return () => this.elements.delete(id);
-	}
-	addElements(elements, options = {}) {
-		const map = [...elements].map((element) => this.addElement(element, options));
-		return () => {
-			map.forEach((remove) => {
-				remove();
-			});
-		};
-	}
-	onWindowResize = () => {
-		this.viewport.width = window.innerWidth;
-		this.viewport.height = window.innerHeight;
-	};
-	computeSnaps = () => {
-		const { isHorizontal } = this.lenis;
-		let snaps = [...this.snaps.values()];
-		this.elements.forEach(({ rect, align }) => {
-			let value;
-			align.forEach((align) => {
-				if (align === "start") value = rect.top;
-				else if (align === "center") value = isHorizontal ? rect.left + rect.width / 2 - this.viewport.width / 2 : rect.top + rect.height / 2 - this.viewport.height / 2;
-				else if (align === "end") value = isHorizontal ? rect.left + rect.width - this.viewport.width : rect.top + rect.height - this.viewport.height;
-				if (typeof value === "number") snaps.push({ value: Math.ceil(value) });
-			});
-		});
-		snaps = snaps.sort((a, b) => Math.abs(a.value) - Math.abs(b.value));
-		return snaps;
-	};
-	previous() {
-		this.goTo((this.currentSnapIndex ?? 0) - 1);
-	}
-	next() {
-		this.goTo((this.currentSnapIndex ?? 0) + 1);
-	}
-	goTo(index) {
-		const snaps = this.computeSnaps();
-		if (snaps.length === 0) return;
-		this.currentSnapIndex = Math.max(0, Math.min(index, snaps.length - 1));
-		const currentSnap = snaps[this.currentSnapIndex];
-		if (currentSnap === void 0) return;
-		this.lenis.scrollTo(currentSnap.value, {
-			duration: this.options.duration,
-			easing: this.options.easing,
-			lerp: this.options.lerp,
-			lock: this.options.type === "lock",
-			userData: { initiator: "snap" },
-			onStart: () => {
-				this.options.onSnapStart?.({
-					index: this.currentSnapIndex,
-					...currentSnap
-				});
-			},
-			onComplete: () => {
-				this.options.onSnapComplete?.({
-					index: this.currentSnapIndex,
-					...currentSnap
-				});
-			}
-		});
-	}
-	get distanceThreshold() {
-		let distanceThreshold = Number.POSITIVE_INFINITY;
-		if (this.options.type === "mandatory") return Number.POSITIVE_INFINITY;
-		const { isHorizontal } = this.lenis;
-		const axis = isHorizontal ? "width" : "height";
-		if (typeof this.options.distanceThreshold === "string" && this.options.distanceThreshold.endsWith("%")) distanceThreshold = Number(this.options.distanceThreshold.replace("%", "")) / 100 * this.viewport[axis];
-		else if (typeof this.options.distanceThreshold === "number") distanceThreshold = this.options.distanceThreshold;
-		else distanceThreshold = this.viewport[axis];
-		return distanceThreshold;
-	}
-	onSnap = (e) => {
-		if (this.isStopped) return;
-		if (e.event.type === "touchmove") return;
-		if (this.options.type === "lock" && this.lenis.userData?.initiator === "snap") return;
-		let { scroll, isHorizontal } = this.lenis;
-		const delta = isHorizontal ? e.deltaX : e.deltaY;
-		scroll = Math.ceil(this.lenis.scroll + delta);
-		const snaps = this.computeSnaps();
-		if (snaps.length === 0) return;
-		let snapIndex;
-		const prevSnapIndex = snaps.findLastIndex(({ value }) => value < scroll);
-		const nextSnapIndex = snaps.findIndex(({ value }) => value > scroll);
-		if (this.options.type === "lock") {
-			if (delta > 0) snapIndex = nextSnapIndex;
-			else if (delta < 0) snapIndex = prevSnapIndex;
-		} else {
-			const prevSnap = snaps[prevSnapIndex];
-			const distanceToPrevSnap = prevSnap ? Math.abs(scroll - prevSnap.value) : Number.POSITIVE_INFINITY;
-			const nextSnap = snaps[nextSnapIndex];
-			snapIndex = distanceToPrevSnap < (nextSnap ? Math.abs(scroll - nextSnap.value) : Number.POSITIVE_INFINITY) ? prevSnapIndex : nextSnapIndex;
-		}
-		if (snapIndex === void 0) return;
-		if (snapIndex === -1) return;
-		snapIndex = Math.max(0, Math.min(snapIndex, snaps.length - 1));
-		const snap = snaps[snapIndex];
-		if (Math.abs(scroll - snap.value) <= this.distanceThreshold) this.goTo(snapIndex);
-	};
-	resize() {
-		this.elements.forEach((element) => {
-			element.onWrapperResize();
-		});
-	}
-};
-//#endregion
-export { Snap as default };
-
-//# sourceMappingURL=lenis-snap.mjs.map
Index: src/assets/vendor/lenis.mjs
===================================================================
--- src/assets/vendor/lenis.mjs	(revision fd8faf581c665d69b41dd6f5262d74bf432c0e1b)
+++ 	(revision )
@@ -1,1057 +1,0 @@
-//#region package.json
-var version = "1.3.26";
-//#endregion
-//#region packages/core/src/maths.ts
-/**
-* Clamp a value between a minimum and maximum value
-*
-* @param min Minimum value
-* @param input Value to clamp
-* @param max Maximum value
-* @returns Clamped value
-*/
-function clamp(min, input, max) {
-	return Math.max(min, Math.min(input, max));
-}
-/**
-*  Linearly interpolate between two values using an amount (0 <= t <= 1)
-*
-* @param x First value
-* @param y Second value
-* @param t Amount to interpolate (0 <= t <= 1)
-* @returns Interpolated value
-*/
-function lerp(x, y, t) {
-	return (1 - t) * x + t * y;
-}
-/**
-* Damp a value over time using a damping factor
-* {@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}
-*
-* @param x Initial value
-* @param y Target value
-* @param lambda Damping factor
-* @param dt Time elapsed since the last update
-* @returns Damped value
-*/
-function damp(x, y, lambda, deltaTime) {
-	return lerp(x, y, 1 - Math.exp(-lambda * deltaTime));
-}
-/**
-* Calculate the modulo of the dividend and divisor while keeping the result within the same sign as the divisor
-* {@link https://anguscroll.com/just/just-modulo}
-*
-* @param n Dividend
-* @param d Divisor
-* @returns Modulo
-*/
-function modulo(n, d) {
-	return (n % d + d) % d;
-}
-//#endregion
-//#region packages/core/src/animate.ts
-/**
-* Animate class to handle value animations with lerping or easing
-*
-* @example
-* const animate = new Animate()
-* animate.fromTo(0, 100, { duration: 1, easing: (t) => t })
-* animate.advance(0.5) // 50
-*/
-var Animate = class {
-	isRunning = false;
-	value = 0;
-	from = 0;
-	to = 0;
-	currentTime = 0;
-	lerp;
-	duration;
-	easing;
-	onUpdate;
-	/**
-	* Advance the animation by the given delta time
-	*
-	* @param deltaTime - The time in seconds to advance the animation
-	*/
-	advance(deltaTime) {
-		if (!this.isRunning) return;
-		let completed = false;
-		if (this.duration && this.easing) {
-			this.currentTime += deltaTime;
-			const linearProgress = clamp(0, this.currentTime / this.duration, 1);
-			completed = linearProgress >= 1;
-			const easedProgress = completed ? 1 : this.easing(linearProgress);
-			this.value = this.from + (this.to - this.from) * easedProgress;
-		} else if (this.lerp) {
-			this.value = damp(this.value, this.to, this.lerp * 60, deltaTime);
-			if (Math.round(this.value) === Math.round(this.to)) {
-				this.value = this.to;
-				completed = true;
-			}
-		} else {
-			this.value = this.to;
-			completed = true;
-		}
-		if (completed) this.stop();
-		this.onUpdate?.(this.value, completed);
-	}
-	/** Stop the animation */
-	stop() {
-		this.isRunning = false;
-	}
-	/**
-	* Set up the animation from a starting value to an ending value
-	* with optional parameters for lerping, duration, easing, and onUpdate callback
-	*
-	* @param from - The starting value
-	* @param to - The ending value
-	* @param options - Options for the animation
-	*/
-	fromTo(from, to, { lerp, duration, easing, onStart, onUpdate }) {
-		this.from = this.value = from;
-		this.to = to;
-		this.lerp = lerp;
-		this.duration = duration;
-		this.easing = easing;
-		this.currentTime = 0;
-		this.isRunning = true;
-		onStart?.();
-		this.onUpdate = onUpdate;
-	}
-};
-//#endregion
-//#region packages/core/src/debounce.ts
-function debounce(callback, delay) {
-	let timer;
-	return function(...args) {
-		clearTimeout(timer);
-		timer = setTimeout(() => {
-			timer = void 0;
-			callback.apply(this, args);
-		}, delay);
-	};
-}
-//#endregion
-//#region packages/core/src/dimensions.ts
-/**
-* Dimensions class to handle the size of the content and wrapper
-*
-* @example
-* const dimensions = new Dimensions(wrapper, content)
-* dimensions.on('resize', (e) => {
-*   console.log(e.width, e.height)
-* })
-*/
-var Dimensions = class {
-	width = 0;
-	height = 0;
-	scrollHeight = 0;
-	scrollWidth = 0;
-	debouncedResize;
-	wrapperResizeObserver;
-	contentResizeObserver;
-	constructor(wrapper, content, { autoResize = true, debounce: debounceValue = 250 } = {}) {
-		this.wrapper = wrapper;
-		this.content = content;
-		if (autoResize) {
-			this.debouncedResize = debounce(this.resize, debounceValue);
-			if (this.wrapper instanceof Window) window.addEventListener("resize", this.debouncedResize);
-			else {
-				this.wrapperResizeObserver = new ResizeObserver(this.debouncedResize);
-				this.wrapperResizeObserver.observe(this.wrapper);
-			}
-			this.contentResizeObserver = new ResizeObserver(this.debouncedResize);
-			this.contentResizeObserver.observe(this.content);
-		}
-		this.resize();
-	}
-	destroy() {
-		this.wrapperResizeObserver?.disconnect();
-		this.contentResizeObserver?.disconnect();
-		if (this.wrapper === window && this.debouncedResize) window.removeEventListener("resize", this.debouncedResize);
-	}
-	resize = () => {
-		this.onWrapperResize();
-		this.onContentResize();
-	};
-	onWrapperResize = () => {
-		if (this.wrapper instanceof Window) {
-			this.width = window.innerWidth;
-			this.height = window.innerHeight;
-		} else {
-			this.width = this.wrapper.clientWidth;
-			this.height = this.wrapper.clientHeight;
-		}
-	};
-	onContentResize = () => {
-		if (this.wrapper instanceof Window) {
-			this.scrollHeight = this.content.scrollHeight;
-			this.scrollWidth = this.content.scrollWidth;
-		} else {
-			this.scrollHeight = this.wrapper.scrollHeight;
-			this.scrollWidth = this.wrapper.scrollWidth;
-		}
-	};
-	get limit() {
-		return {
-			x: this.scrollWidth - this.width,
-			y: this.scrollHeight - this.height
-		};
-	}
-};
-//#endregion
-//#region packages/core/src/emitter.ts
-/**
-* Emitter class to handle events
-* @example
-* const emitter = new Emitter()
-* emitter.on('event', (data) => {
-*   console.log(data)
-* })
-* emitter.emit('event', 'data')
-*/
-var Emitter = class {
-	events = {};
-	/**
-	* Emit an event with the given data
-	* @param event Event name
-	* @param args Data to pass to the event handlers
-	*/
-	emit(event, ...args) {
-		const callbacks = this.events[event] || [];
-		for (let i = 0, length = callbacks.length; i < length; i++) callbacks[i]?.(...args);
-	}
-	/**
-	* Add a callback to the event
-	* @param event Event name
-	* @param cb Callback function
-	* @returns Unsubscribe function
-	*/
-	on(event, cb) {
-		if (this.events[event]) this.events[event].push(cb);
-		else this.events[event] = [cb];
-		return () => {
-			this.events[event] = this.events[event]?.filter((i) => cb !== i);
-		};
-	}
-	/**
-	* Remove a callback from the event
-	* @param event Event name
-	* @param callback Callback function
-	*/
-	off(event, callback) {
-		this.events[event] = this.events[event]?.filter((i) => callback !== i);
-	}
-	/**
-	* Remove all event listeners and clean up
-	*/
-	destroy() {
-		this.events = {};
-	}
-};
-//#endregion
-//#region packages/core/src/virtual-scroll.ts
-const LINE_HEIGHT = 100 / 6;
-const listenerOptions = { passive: false };
-function getDeltaMultiplier(deltaMode, size) {
-	if (deltaMode === 1) return LINE_HEIGHT;
-	if (deltaMode === 2) return size;
-	return 1;
-}
-var VirtualScroll = class {
-	touchStart = {
-		x: 0,
-		y: 0
-	};
-	lastDelta = {
-		x: 0,
-		y: 0
-	};
-	window = {
-		width: 0,
-		height: 0
-	};
-	emitter = new Emitter();
-	constructor(element, options = {
-		wheelMultiplier: 1,
-		touchMultiplier: 1
-	}) {
-		this.element = element;
-		this.options = options;
-		window.addEventListener("resize", this.onWindowResize);
-		this.onWindowResize();
-		this.element.addEventListener("wheel", this.onWheel, listenerOptions);
-		this.element.addEventListener("touchstart", this.onTouchStart, listenerOptions);
-		this.element.addEventListener("touchmove", this.onTouchMove, listenerOptions);
-		this.element.addEventListener("touchend", this.onTouchEnd, listenerOptions);
-	}
-	/**
-	* Add an event listener for the given event and callback
-	*
-	* @param event Event name
-	* @param callback Callback function
-	*/
-	on(event, callback) {
-		return this.emitter.on(event, callback);
-	}
-	/** Remove all event listeners and clean up */
-	destroy() {
-		this.emitter.destroy();
-		window.removeEventListener("resize", this.onWindowResize);
-		this.element.removeEventListener("wheel", this.onWheel, listenerOptions);
-		this.element.removeEventListener("touchstart", this.onTouchStart, listenerOptions);
-		this.element.removeEventListener("touchmove", this.onTouchMove, listenerOptions);
-		this.element.removeEventListener("touchend", this.onTouchEnd, listenerOptions);
-	}
-	/**
-	* Event handler for 'touchstart' event
-	*
-	* @param event Touch event
-	*/
-	onTouchStart = (event) => {
-		const { clientX, clientY } = event.targetTouches ? event.targetTouches[0] : event;
-		this.touchStart.x = clientX;
-		this.touchStart.y = clientY;
-		this.lastDelta = {
-			x: 0,
-			y: 0
-		};
-		this.emitter.emit("scroll", {
-			deltaX: 0,
-			deltaY: 0,
-			event
-		});
-	};
-	/** Event handler for 'touchmove' event */
-	onTouchMove = (event) => {
-		const { clientX, clientY } = event.targetTouches ? event.targetTouches[0] : event;
-		const deltaX = -(clientX - this.touchStart.x) * this.options.touchMultiplier;
-		const deltaY = -(clientY - this.touchStart.y) * this.options.touchMultiplier;
-		this.touchStart.x = clientX;
-		this.touchStart.y = clientY;
-		this.lastDelta = {
-			x: deltaX,
-			y: deltaY
-		};
-		this.emitter.emit("scroll", {
-			deltaX,
-			deltaY,
-			event
-		});
-	};
-	onTouchEnd = (event) => {
-		this.emitter.emit("scroll", {
-			deltaX: this.lastDelta.x,
-			deltaY: this.lastDelta.y,
-			event
-		});
-	};
-	/** Event handler for 'wheel' event */
-	onWheel = (event) => {
-		let { deltaX, deltaY, deltaMode } = event;
-		const multiplierX = getDeltaMultiplier(deltaMode, this.window.width);
-		const multiplierY = getDeltaMultiplier(deltaMode, this.window.height);
-		deltaX *= multiplierX;
-		deltaY *= multiplierY;
-		deltaX *= this.options.wheelMultiplier;
-		deltaY *= this.options.wheelMultiplier;
-		this.emitter.emit("scroll", {
-			deltaX,
-			deltaY,
-			event
-		});
-	};
-	onWindowResize = () => {
-		this.window = {
-			width: window.innerWidth,
-			height: window.innerHeight
-		};
-	};
-};
-//#endregion
-//#region packages/core/src/lenis.ts
-const defaultEasing = (t) => Math.min(1, 1.001 - 2 ** (-10 * t));
-var Lenis = class {
-	_isScrolling = false;
-	_isStopped = false;
-	_isLocked = false;
-	_preventNextNativeScrollEvent = false;
-	_resetVelocityTimeout = null;
-	_rafId = null;
-	_isDraggingSelection = false;
-	reducedMotionMediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
-	/**
-	* Whether or not the user is touching the screen
-	*/
-	isTouching;
-	/**
-	* Whether or not the device is running iOS
-	*/
-	isIos;
-	/**
-	* The time in ms since the lenis instance was created
-	*/
-	time = 0;
-	/**
-	* User data that will be forwarded through the scroll event
-	*
-	* @example
-	* lenis.scrollTo(100, {
-	*   userData: {
-	*     foo: 'bar'
-	*   }
-	* })
-	*/
-	userData = {};
-	/**
-	* The last velocity of the scroll
-	*/
-	lastVelocity = 0;
-	/**
-	* The current velocity of the scroll
-	*/
-	velocity = 0;
-	/**
-	* The direction of the scroll
-	*/
-	direction = 0;
-	/**
-	* The options passed to the lenis instance
-	*/
-	options;
-	/**
-	* The target scroll value
-	*/
-	targetScroll;
-	/**
-	* The animated scroll value
-	*/
-	animatedScroll;
-	animate = new Animate();
-	emitter = new Emitter();
-	dimensions;
-	virtualScroll;
-	constructor({ wrapper = window, content = document.documentElement, eventsTarget = wrapper, smoothWheel = true, syncTouch = false, syncTouchLerp = .075, touchInertiaExponent = 1.7, duration, easing, lerp = .1, infinite = false, orientation = "vertical", gestureOrientation = orientation === "horizontal" ? "both" : "vertical", touchMultiplier = 1, wheelMultiplier = 1, autoResize = true, prevent, virtualScroll, overscroll = true, autoRaf = false, anchors = false, autoToggle = false, allowNestedScroll = false, __experimental__naiveDimensions = false, naiveDimensions = __experimental__naiveDimensions, stopInertiaOnNavigate = false, respectReducedMotion = true } = {}) {
-		window.lenisVersion = version;
-		if (!window.lenis) window.lenis = {};
-		window.lenis.version = version;
-		if (orientation === "horizontal") window.lenis.horizontal = true;
-		if (syncTouch === true) window.lenis.touch = true;
-		this.isIos = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
-		if (!wrapper || wrapper === document.documentElement) wrapper = window;
-		if (typeof duration === "number" && typeof easing !== "function") easing = defaultEasing;
-		else if (typeof easing === "function" && typeof duration !== "number") duration = 1;
-		this.options = {
-			wrapper,
-			content,
-			eventsTarget,
-			smoothWheel,
-			syncTouch,
-			syncTouchLerp,
-			touchInertiaExponent,
-			duration,
-			easing,
-			lerp,
-			infinite,
-			gestureOrientation,
-			orientation,
-			touchMultiplier,
-			wheelMultiplier,
-			autoResize,
-			prevent,
-			virtualScroll,
-			overscroll,
-			autoRaf,
-			anchors,
-			autoToggle,
-			allowNestedScroll,
-			naiveDimensions,
-			stopInertiaOnNavigate,
-			respectReducedMotion
-		};
-		this.dimensions = new Dimensions(wrapper, content, { autoResize });
-		this.updateClassName();
-		this.targetScroll = this.animatedScroll = this.actualScroll;
-		this.options.wrapper.addEventListener("scroll", this.onNativeScroll);
-		this.options.wrapper.addEventListener("scrollend", this.onScrollEnd, { capture: true });
-		if (this.options.anchors || this.options.stopInertiaOnNavigate) this.options.wrapper.addEventListener("click", this.onClick);
-		this.options.wrapper.addEventListener("pointerdown", this.onPointerDown);
-		this.virtualScroll = new VirtualScroll(eventsTarget, {
-			touchMultiplier,
-			wheelMultiplier
-		});
-		this.virtualScroll.on("scroll", this.onVirtualScroll);
-		if (this.options.autoToggle) {
-			this.checkOverflow();
-			this.rootElement.addEventListener("transitionend", this.onTransitionEnd);
-		}
-		if (this.options.autoRaf) this._rafId = requestAnimationFrame(this.raf);
-	}
-	/**
-	* Destroy the lenis instance, remove all event listeners and clean up the class name
-	*/
-	destroy() {
-		this.emitter.destroy();
-		this.options.wrapper.removeEventListener("scroll", this.onNativeScroll);
-		this.options.wrapper.removeEventListener("scrollend", this.onScrollEnd, { capture: true });
-		this.options.wrapper.removeEventListener("pointerdown", this.onPointerDown);
-		if (this.options.anchors || this.options.stopInertiaOnNavigate) this.options.wrapper.removeEventListener("click", this.onClick);
-		this.virtualScroll.destroy();
-		this.dimensions.destroy();
-		this.cleanUpClassName();
-		if (this._rafId) cancelAnimationFrame(this._rafId);
-	}
-	on(event, callback) {
-		return this.emitter.on(event, callback);
-	}
-	off(event, callback) {
-		return this.emitter.off(event, callback);
-	}
-	onScrollEnd = (e) => {
-		if (!(e instanceof CustomEvent)) {
-			if (this.isScrolling === "smooth" || this.isScrolling === false) e.stopPropagation();
-		}
-	};
-	dispatchScrollendEvent = () => {
-		this.options.wrapper.dispatchEvent(new CustomEvent("scrollend", {
-			bubbles: this.options.wrapper === window,
-			detail: { lenisScrollEnd: true }
-		}));
-	};
-	get overflow() {
-		const property = this.isHorizontal ? "overflow-x" : "overflow-y";
-		return getComputedStyle(this.rootElement)[property];
-	}
-	checkOverflow() {
-		if (["hidden", "clip"].includes(this.overflow)) this.internalStop();
-		else this.internalStart();
-	}
-	onTransitionEnd = (event) => {
-		if (event.propertyName?.includes("overflow") && event.target === this.rootElement) this.checkOverflow();
-	};
-	setScroll(scroll) {
-		if (this.isHorizontal) this.options.wrapper.scrollTo({
-			left: scroll,
-			behavior: "instant"
-		});
-		else this.options.wrapper.scrollTo({
-			top: scroll,
-			behavior: "instant"
-		});
-	}
-	onClick = (event) => {
-		const linkElementsUrls = event.composedPath().filter((node) => node instanceof HTMLAnchorElement && node.href).map((element) => new URL(element.href));
-		const currentUrl = new URL(window.location.href);
-		if (this.options.anchors) {
-			const anchorElementUrl = linkElementsUrls.find((targetUrl) => currentUrl.host === targetUrl.host && currentUrl.pathname === targetUrl.pathname && targetUrl.hash);
-			if (anchorElementUrl) {
-				const options = typeof this.options.anchors === "object" && this.options.anchors ? this.options.anchors : void 0;
-				const target = decodeURIComponent(anchorElementUrl.hash);
-				this.scrollTo(target, options);
-				return;
-			}
-		}
-		if (this.options.stopInertiaOnNavigate) {
-			if (linkElementsUrls.some((targetUrl) => currentUrl.host === targetUrl.host && currentUrl.pathname !== targetUrl.pathname)) {
-				this.reset();
-				return;
-			}
-		}
-	};
-	onPointerDown = (event) => {
-		if (event.button === 1) this.reset();
-	};
-	isTouchOnSelectionHandle(event) {
-		const selection = window.getSelection();
-		if (!selection || selection.isCollapsed || selection.rangeCount === 0) return false;
-		const touch = event.targetTouches[0] ?? event.changedTouches[0];
-		if (!touch) return false;
-		const rects = selection.getRangeAt(0).getClientRects();
-		if (rects.length === 0) return false;
-		const first = rects[0];
-		const last = rects[rects.length - 1];
-		const HANDLE_RADIUS = 40;
-		const nearStart = Math.hypot(touch.clientX - first.left, touch.clientY - first.top) <= HANDLE_RADIUS;
-		const nearEnd = Math.hypot(touch.clientX - last.right, touch.clientY - last.bottom) <= HANDLE_RADIUS;
-		return nearStart || nearEnd;
-	}
-	onVirtualScroll = (data) => {
-		if (typeof this.options.virtualScroll === "function" && this.options.virtualScroll(data) === false) return;
-		const { deltaX, deltaY, event } = data;
-		this.emitter.emit("virtual-scroll", {
-			deltaX,
-			deltaY,
-			event
-		});
-		if (event.ctrlKey) return;
-		if (event.lenisStopPropagation) return;
-		const isTouch = event.type.includes("touch");
-		const isWheel = event.type.includes("wheel");
-		if (isTouch && this.isIos) {
-			if (event.type === "touchstart") this._isDraggingSelection = this.isTouchOnSelectionHandle(event);
-			if (this._isDraggingSelection) {
-				if (event.type === "touchend") this._isDraggingSelection = false;
-				return;
-			}
-		}
-		this.isTouching = event.type === "touchstart" || event.type === "touchmove";
-		const isClickOrTap = deltaX === 0 && deltaY === 0;
-		if (this.options.syncTouch && isTouch && event.type === "touchstart" && isClickOrTap && !this.isStopped && !this.isLocked) {
-			this.reset();
-			return;
-		}
-		const isUnknownGesture = this.options.gestureOrientation === "vertical" && deltaY === 0 || this.options.gestureOrientation === "horizontal" && deltaX === 0;
-		if (isClickOrTap || isUnknownGesture) return;
-		let composedPath = event.composedPath();
-		composedPath = composedPath.slice(0, composedPath.indexOf(this.rootElement));
-		const prevent = this.options.prevent;
-		const gestureOrientation = Math.abs(deltaX) >= Math.abs(deltaY) ? "horizontal" : "vertical";
-		if (composedPath.find((node) => node instanceof HTMLElement && (typeof prevent === "function" && prevent?.(node) || node.hasAttribute?.("data-lenis-prevent") || gestureOrientation === "vertical" && node.hasAttribute?.("data-lenis-prevent-vertical") || gestureOrientation === "horizontal" && node.hasAttribute?.("data-lenis-prevent-horizontal") || isTouch && node.hasAttribute?.("data-lenis-prevent-touch") || isWheel && node.hasAttribute?.("data-lenis-prevent-wheel") || this.options.allowNestedScroll && this.hasNestedScroll(node, {
-			deltaX,
-			deltaY
-		})))) return;
-		if (this.isStopped || this.isLocked) {
-			if (event.cancelable) event.preventDefault();
-			return;
-		}
-		if (!(this.options.syncTouch && isTouch || this.options.smoothWheel && isWheel)) {
-			this.isScrolling = "native";
-			this.animate.stop();
-			event.lenisStopPropagation = true;
-			return;
-		}
-		let delta = deltaY;
-		if (this.options.gestureOrientation === "both") delta = Math.abs(deltaY) > Math.abs(deltaX) ? deltaY : deltaX;
-		else if (this.options.gestureOrientation === "horizontal") delta = deltaX;
-		if (!this.options.overscroll || this.options.infinite || this.options.wrapper !== window && this.limit > 0 && (this.animatedScroll > 0 && this.animatedScroll < this.limit || this.animatedScroll === 0 && deltaY > 0 || this.animatedScroll === this.limit && deltaY < 0)) event.lenisStopPropagation = true;
-		if (event.cancelable) event.preventDefault();
-		const isSyncTouch = isTouch && this.options.syncTouch;
-		const hasTouchInertia = isTouch && event.type === "touchend";
-		if (hasTouchInertia) delta = Math.sign(delta) * Math.abs(this.velocity) ** this.options.touchInertiaExponent;
-		this.scrollTo(this.targetScroll + delta, {
-			programmatic: false,
-			...isSyncTouch ? { lerp: hasTouchInertia ? this.options.syncTouchLerp : 1 } : {
-				lerp: this.options.lerp,
-				duration: this.options.duration,
-				easing: this.options.easing
-			}
-		});
-	};
-	/**
-	* Force lenis to recalculate the dimensions
-	*/
-	resize() {
-		this.dimensions.resize();
-		this.animatedScroll = this.targetScroll = this.actualScroll;
-		this.emit();
-	}
-	emit() {
-		this.emitter.emit("scroll", this);
-	}
-	onNativeScroll = () => {
-		if (this._resetVelocityTimeout !== null) {
-			clearTimeout(this._resetVelocityTimeout);
-			this._resetVelocityTimeout = null;
-		}
-		if (this._preventNextNativeScrollEvent) {
-			this._preventNextNativeScrollEvent = false;
-			return;
-		}
-		if (this.isScrolling === false || this.isScrolling === "native") {
-			const lastScroll = this.animatedScroll;
-			this.animatedScroll = this.targetScroll = this.actualScroll;
-			this.lastVelocity = this.velocity;
-			this.velocity = this.animatedScroll - lastScroll;
-			this.direction = Math.sign(this.animatedScroll - lastScroll);
-			if (!this.isStopped) this.isScrolling = "native";
-			this.emit();
-			if (this.velocity !== 0) this._resetVelocityTimeout = setTimeout(() => {
-				this.lastVelocity = this.velocity;
-				this.velocity = 0;
-				this.isScrolling = false;
-				this.emit();
-			}, 400);
-		}
-	};
-	reset() {
-		this.isLocked = false;
-		this.isScrolling = false;
-		this.animatedScroll = this.targetScroll = this.actualScroll;
-		this.lastVelocity = this.velocity = 0;
-		this.animate.stop();
-	}
-	/**
-	* Start lenis scroll after it has been stopped
-	*/
-	start() {
-		if (!this.isStopped) return;
-		if (this.options.autoToggle) {
-			this.rootElement.style.removeProperty("overflow");
-			return;
-		}
-		this.internalStart();
-	}
-	internalStart() {
-		if (!this.isStopped) return;
-		this.reset();
-		this.isStopped = false;
-		this.emit();
-	}
-	/**
-	* Stop lenis scroll
-	*/
-	stop() {
-		if (this.isStopped) return;
-		if (this.options.autoToggle) {
-			this.rootElement.style.setProperty("overflow", "clip");
-			return;
-		}
-		this.internalStop();
-	}
-	internalStop() {
-		if (this.isStopped) return;
-		this.reset();
-		this.isStopped = true;
-		this.emit();
-	}
-	/**
-	* RequestAnimationFrame for lenis
-	*
-	* @param time The time in ms from an external clock like `requestAnimationFrame` or Tempus
-	*/
-	raf = (time) => {
-		const deltaTime = time - (this.time || time);
-		this.time = time;
-		this.animate.advance(deltaTime * .001);
-		if (this.options.autoRaf) this._rafId = requestAnimationFrame(this.raf);
-	};
-	/**
-	* Scroll to a target value
-	*
-	* @param target The target value to scroll to
-	* @param options The options for the scroll
-	*
-	* @example
-	* lenis.scrollTo(100, {
-	*   offset: 100,
-	*   duration: 1,
-	*   easing: (t) => 1 - Math.cos((t * Math.PI) / 2),
-	*   lerp: 0.1,
-	*   onStart: () => {
-	*     console.log('onStart')
-	*   },
-	*   onComplete: () => {
-	*     console.log('onComplete')
-	*   },
-	* })
-	*/
-	scrollTo(_target, { offset = 0, immediate = false, lock = false, programmatic = true, lerp = programmatic ? this.options.lerp : void 0, duration = programmatic ? this.options.duration : void 0, easing = programmatic ? this.options.easing : void 0, onStart, onComplete, force = false, userData } = {}) {
-		if (this.prefersReducedMotion) if (programmatic) immediate = true;
-		else {
-			lerp = 1;
-			duration = void 0;
-			easing = void 0;
-		}
-		if ((this.isStopped || this.isLocked) && !force) return;
-		let target = _target;
-		let adjustedOffset = offset;
-		if (typeof target === "string" && [
-			"top",
-			"left",
-			"start",
-			"#"
-		].includes(target)) target = 0;
-		else if (typeof target === "string" && [
-			"bottom",
-			"right",
-			"end"
-		].includes(target)) target = this.limit;
-		else {
-			let node = null;
-			if (typeof target === "string") {
-				node = target.startsWith("#") ? document.getElementById(target.slice(1)) : document.querySelector(target);
-				if (!node) if (target === "#top") target = 0;
-				else console.warn("Lenis: Target not found", target);
-			} else if (target instanceof HTMLElement && target?.nodeType) node = target;
-			if (node) {
-				if (this.options.wrapper !== window) {
-					const wrapperRect = this.rootElement.getBoundingClientRect();
-					adjustedOffset -= this.isHorizontal ? wrapperRect.left : wrapperRect.top;
-				}
-				const rect = node.getBoundingClientRect();
-				const targetStyle = getComputedStyle(node);
-				const scrollMargin = this.isHorizontal ? Number.parseFloat(targetStyle.scrollMarginLeft) : Number.parseFloat(targetStyle.scrollMarginTop);
-				const containerStyle = getComputedStyle(this.rootElement);
-				const scrollPadding = this.isHorizontal ? Number.parseFloat(containerStyle.scrollPaddingLeft) : Number.parseFloat(containerStyle.scrollPaddingTop);
-				target = (this.isHorizontal ? rect.left : rect.top) + this.animatedScroll - (Number.isNaN(scrollMargin) ? 0 : scrollMargin) - (Number.isNaN(scrollPadding) ? 0 : scrollPadding);
-			}
-		}
-		if (typeof target !== "number") return;
-		target += adjustedOffset;
-		if (this.options.infinite) {
-			if (programmatic) {
-				this.targetScroll = this.animatedScroll = this.scroll;
-				const distance = target - this.animatedScroll;
-				if (distance > this.limit / 2) target -= this.limit;
-				else if (distance < -this.limit / 2) target += this.limit;
-			}
-		} else target = clamp(0, target, this.limit);
-		if (target === this.targetScroll) {
-			onStart?.(this);
-			onComplete?.(this);
-			return;
-		}
-		this.userData = userData ?? {};
-		if (immediate) {
-			this.animatedScroll = this.targetScroll = target;
-			this.setScroll(this.scroll);
-			this.reset();
-			this.preventNextNativeScrollEvent();
-			this.emit();
-			onComplete?.(this);
-			this.userData = {};
-			requestAnimationFrame(() => {
-				this.dispatchScrollendEvent();
-			});
-			return;
-		}
-		if (!programmatic) this.targetScroll = target;
-		if (typeof duration === "number" && typeof easing !== "function") easing = defaultEasing;
-		else if (typeof easing === "function" && typeof duration !== "number") duration = 1;
-		this.animate.fromTo(this.animatedScroll, target, {
-			duration,
-			easing,
-			lerp,
-			onStart: () => {
-				if (lock) this.isLocked = true;
-				this.isScrolling = "smooth";
-				onStart?.(this);
-			},
-			onUpdate: (value, completed) => {
-				this.isScrolling = "smooth";
-				this.lastVelocity = this.velocity;
-				this.velocity = value - this.animatedScroll;
-				this.direction = Math.sign(this.velocity);
-				this.animatedScroll = value;
-				this.setScroll(this.scroll);
-				if (programmatic) this.targetScroll = value;
-				if (!completed) this.emit();
-				if (completed) {
-					this.reset();
-					this.emit();
-					onComplete?.(this);
-					this.userData = {};
-					requestAnimationFrame(() => {
-						this.dispatchScrollendEvent();
-					});
-					this.preventNextNativeScrollEvent();
-				}
-			}
-		});
-	}
-	preventNextNativeScrollEvent() {
-		this._preventNextNativeScrollEvent = true;
-		requestAnimationFrame(() => {
-			this._preventNextNativeScrollEvent = false;
-		});
-	}
-	hasNestedScroll(node, { deltaX, deltaY }) {
-		const time = Date.now();
-		if (!node._lenis) node._lenis = {};
-		const cache = node._lenis;
-		let hasOverflowX;
-		let hasOverflowY;
-		let isScrollableX;
-		let isScrollableY;
-		let hasOverscrollBehaviorX;
-		let hasOverscrollBehaviorY;
-		let scrollWidth;
-		let scrollHeight;
-		let clientWidth;
-		let clientHeight;
-		if (time - (cache.time ?? 0) > 2e3) {
-			cache.time = Date.now();
-			const computedStyle = window.getComputedStyle(node);
-			cache.computedStyle = computedStyle;
-			hasOverflowX = [
-				"auto",
-				"overlay",
-				"scroll"
-			].includes(computedStyle.overflowX);
-			hasOverflowY = [
-				"auto",
-				"overlay",
-				"scroll"
-			].includes(computedStyle.overflowY);
-			hasOverscrollBehaviorX = ["auto"].includes(computedStyle.overscrollBehaviorX);
-			hasOverscrollBehaviorY = ["auto"].includes(computedStyle.overscrollBehaviorY);
-			cache.hasOverflowX = hasOverflowX;
-			cache.hasOverflowY = hasOverflowY;
-			if (!(hasOverflowX || hasOverflowY)) return false;
-			scrollWidth = node.scrollWidth;
-			scrollHeight = node.scrollHeight;
-			clientWidth = node.clientWidth;
-			clientHeight = node.clientHeight;
-			isScrollableX = scrollWidth > clientWidth;
-			isScrollableY = scrollHeight > clientHeight;
-			cache.isScrollableX = isScrollableX;
-			cache.isScrollableY = isScrollableY;
-			cache.scrollWidth = scrollWidth;
-			cache.scrollHeight = scrollHeight;
-			cache.clientWidth = clientWidth;
-			cache.clientHeight = clientHeight;
-			cache.hasOverscrollBehaviorX = hasOverscrollBehaviorX;
-			cache.hasOverscrollBehaviorY = hasOverscrollBehaviorY;
-		} else {
-			isScrollableX = cache.isScrollableX;
-			isScrollableY = cache.isScrollableY;
-			hasOverflowX = cache.hasOverflowX;
-			hasOverflowY = cache.hasOverflowY;
-			scrollWidth = cache.scrollWidth;
-			scrollHeight = cache.scrollHeight;
-			clientWidth = cache.clientWidth;
-			clientHeight = cache.clientHeight;
-			hasOverscrollBehaviorX = cache.hasOverscrollBehaviorX;
-			hasOverscrollBehaviorY = cache.hasOverscrollBehaviorY;
-		}
-		if (!(hasOverflowX && isScrollableX || hasOverflowY && isScrollableY)) return false;
-		const orientation = Math.abs(deltaX) >= Math.abs(deltaY) ? "horizontal" : "vertical";
-		let scroll;
-		let maxScroll;
-		let delta;
-		let hasOverflow;
-		let isScrollable;
-		let hasOverscrollBehavior;
-		if (orientation === "horizontal") {
-			scroll = Math.round(node.scrollLeft);
-			maxScroll = scrollWidth - clientWidth;
-			delta = deltaX;
-			hasOverflow = hasOverflowX;
-			isScrollable = isScrollableX;
-			hasOverscrollBehavior = hasOverscrollBehaviorX;
-		} else if (orientation === "vertical") {
-			scroll = Math.round(node.scrollTop);
-			maxScroll = scrollHeight - clientHeight;
-			delta = deltaY;
-			hasOverflow = hasOverflowY;
-			isScrollable = isScrollableY;
-			hasOverscrollBehavior = hasOverscrollBehaviorY;
-		} else return false;
-		if (!hasOverscrollBehavior && (scroll >= maxScroll || scroll <= 0)) return true;
-		return (delta > 0 ? scroll < maxScroll : scroll > 0) && hasOverflow && isScrollable;
-	}
-	/**
-	* The root element on which lenis is instanced
-	*/
-	get rootElement() {
-		return this.options.wrapper === window ? document.documentElement : this.options.wrapper;
-	}
-	/**
-	* The limit which is the maximum scroll value
-	*/
-	get limit() {
-		if (this.options.naiveDimensions) {
-			if (this.isHorizontal) return this.rootElement.scrollWidth - this.rootElement.clientWidth;
-			return this.rootElement.scrollHeight - this.rootElement.clientHeight;
-		}
-		return this.dimensions.limit[this.isHorizontal ? "x" : "y"];
-	}
-	/**
-	* Whether or not the scroll is horizontal
-	*/
-	get isHorizontal() {
-		return this.options.orientation === "horizontal";
-	}
-	/**
-	* The actual scroll value
-	*/
-	get actualScroll() {
-		const wrapper = this.options.wrapper;
-		return this.isHorizontal ? wrapper.scrollX ?? wrapper.scrollLeft : wrapper.scrollY ?? wrapper.scrollTop;
-	}
-	/**
-	* The current scroll value
-	*/
-	get scroll() {
-		return this.options.infinite ? modulo(this.animatedScroll, this.limit) : this.animatedScroll;
-	}
-	/**
-	* The progress of the scroll relative to the limit
-	*/
-	get progress() {
-		return this.limit === 0 ? 1 : this.scroll / this.limit;
-	}
-	/**
-	* Current scroll state
-	*/
-	get isScrolling() {
-		return this._isScrolling;
-	}
-	set isScrolling(value) {
-		if (this._isScrolling !== value) {
-			this._isScrolling = value;
-			this.updateClassName();
-		}
-	}
-	/**
-	* Check if lenis is stopped
-	*/
-	get isStopped() {
-		return this._isStopped;
-	}
-	set isStopped(value) {
-		if (this._isStopped !== value) {
-			this._isStopped = value;
-			this.updateClassName();
-		}
-	}
-	/**
-	* Check if lenis is locked
-	*/
-	get isLocked() {
-		return this._isLocked;
-	}
-	set isLocked(value) {
-		if (this._isLocked !== value) {
-			this._isLocked = value;
-			this.updateClassName();
-		}
-	}
-	/**
-	* Check if lenis is smooth scrolling
-	*/
-	get isSmooth() {
-		return this.isScrolling === "smooth";
-	}
-	/**
-	* Whether the user prefers reduced motion and lenis is honoring it (see `respectReducedMotion` option)
-	*/
-	get prefersReducedMotion() {
-		return this.options.respectReducedMotion && this.reducedMotionMediaQuery.matches;
-	}
-	/**
-	* The class name applied to the wrapper element
-	*/
-	get className() {
-		let className = "lenis";
-		if (this.options.autoToggle) className += " lenis-autoToggle";
-		if (this.isStopped) className += " lenis-stopped";
-		if (this.isLocked) className += " lenis-locked";
-		if (this.isScrolling) className += " lenis-scrolling";
-		if (this.isScrolling === "smooth") className += " lenis-smooth";
-		return className;
-	}
-	updateClassName() {
-		this.cleanUpClassName();
-		this.className.split(" ").forEach((className) => {
-			this.rootElement.classList.add(className);
-		});
-	}
-	cleanUpClassName() {
-		for (const className of Array.from(this.rootElement.classList)) if (className === "lenis" || className.startsWith("lenis-")) this.rootElement.classList.remove(className);
-	}
-};
-//#endregion
-export { Lenis as default };
-
-//# sourceMappingURL=lenis.mjs.map
