Index: src/assets/js/mod/post-edit.js
===================================================================
--- src/assets/js/mod/post-edit.js	(revision fb9a8adb168b27c6c9889fd210cf584eaabbc3a2)
+++ src/assets/js/mod/post-edit.js	(revision 4b5db37be989c52df56e680e3acb98ee0cd84ac0)
@@ -5,7 +5,23 @@
 // het houdt een apostrof in een vertaling uit de HTML die hier geplakt wordt.
 
-import { pageData, esc } from './lib.js';
-
-const T = pageData();
+import { pageData, esc, makeSweeper } from './lib.js';
+
+// De oude inline scripts draaiden bij ELKE render; een module draait zijn
+// top-level een keer per sessie. Vandaar init(): de bootstrap roept hem aan
+// bij elke paginawissel waarop deze module actief is, en de veger haalt eerst
+// de document/window-listeners van de vorige pagina weg -- die overleven de
+// swap, met closures naar elementen die al verdwenen zijn (shaer-5s1).
+const doc = makeSweeper();
+let T = {};
+let _barObserver = null;
+
+export function init() {
+  doc.sweep();
+  if (_barObserver) { _barObserver.disconnect(); _barObserver = null; }
+  T = pageData();
+  run();
+}
+
+function run() {
 
           (function () {
@@ -631,9 +647,9 @@
   }
   function toggleFullscreen() { if (isFs()) closeFs(); else openFs(); }
-  window.addEventListener('popstate', function () { if (isFs()) applyFs(false); });
+  doc.on(window, 'popstate', function () { if (isFs()) applyFs(false); });
   if (fsBtn) fsBtn.addEventListener('click', toggleFullscreen);
   var fsDoneBtn = document.getElementById('pe-fs-done');
   if (fsDoneBtn) fsDoneBtn.addEventListener('click', closeFs);
-  document.addEventListener('keydown', (e) => {
+  doc.on(document, 'keydown', (e) => {
     if (e.key === 'Escape' && isFs()) { e.preventDefault(); closeFs(); }
   });
@@ -663,5 +679,5 @@
     if (bqBtn) bqBtn.classList.toggle('is-active', !!blockquoteAncestor());
   }
-  document.addEventListener('selectionchange', () => {
+  doc.on(document, 'selectionchange', () => {
     if (document.activeElement === editor) updateToolbarState();
   });
@@ -884,5 +900,5 @@
       }
     });
-    document.addEventListener('keydown', (e) => {
+    doc.on(document, 'keydown', (e) => {
       if (!trackPicker.hidden && e.key === 'Escape') {
         e.preventDefault();
@@ -1092,7 +1108,9 @@
   }
   position();
-  window.addEventListener('resize', position);
-  if (vv) { vv.addEventListener('resize', position); vv.addEventListener('scroll', position); }
-  // has-audio-player is toggled via a body class → observe it.
-  try { new MutationObserver(position).observe(document.body, { attributes: true, attributeFilter: ['class'] }); } catch (_) {}
+  doc.on(window, 'resize', position);
+  if (vv) { doc.on(vv, 'resize', position); doc.on(vv, 'scroll', position); }
+  // has-audio-player is toggled via a body class → observe it. De observer
+  // overleeft de swap net als de listeners; init() disconnect de vorige.
+  try { _barObserver = new MutationObserver(position); _barObserver.observe(document.body, { attributes: true, attributeFilter: ['class'] }); } catch (_) {}
 })();
+}
