Index: src/assets/css/audio.css
===================================================================
--- src/assets/css/audio.css	(revision 2165b6d3d57ceaa8b5d1f70491868482149470cf)
+++ src/assets/css/audio.css	(revision 7bc636b391c66ac399c33e54f7173a022c6a3cbd)
@@ -1,3 +1,3 @@
-/* Klonkt — Audio CSS
+/* PrutCMS v10 — Audio CSS
    Two pieces:
      1. .post-audio-track — the play-button block inserted by [[track:id]] shortcode
@@ -73,52 +73,4 @@
   text-overflow: ellipsis;
 }
-/* Eigenaar/credit · licentie — subtiele regel onder de track. */
-.post-audio-track .pat-credit {
-  font-size: 0.72rem;
-  color: var(--ink-faint, var(--ink-soft));
-  margin-top: 0.1rem;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-/* "Open in" Spotify/YouTube/SoundCloud — kleine brand-iconen per track. */
-.pat-links {
-  display: inline-flex; align-items: center; gap: 0.1rem;
-  flex: 0 0 auto;
-}
-/* Single + album-rij (.post-audio-track is flex) → duw de links naar rechts. */
-.post-audio-track .pat-links { margin-left: auto; padding-right: 0.5rem; }
-/* Playlist-rij: de li flex maken zodat de links naast de afspeel-rij passen. */
-.post-album-track-compact { display: flex; align-items: center; }
-.post-album-track-compact .pat-row { flex: 1 1 auto; min-width: 0; }
-.post-album-track-compact .pat-links { padding-right: 0.6rem; }
-.pat-link {
-  display: inline-flex; align-items: center; justify-content: center;
-  width: 26px; height: 26px;
-  opacity: 0.75;
-  transition: opacity 120ms, transform 120ms;
-}
-.pat-link svg { width: 17px; height: 17px; }
-.pat-link:hover { opacity: 1; transform: scale(1.12); }
-.pat-link--spotify    { color: #1DB954; }
-.pat-link--youtube    { color: #FF0000; }
-.pat-link--soundcloud { color: #FF5500; }
-
-/* Link-only tracks (geen audiobestand): plek van de afspeelknop = stil muziek-icoon. */
-.pat-noplay {
-  display: inline-flex; align-items: center; justify-content: center;
-  flex: 0 0 38px; width: 38px; align-self: center;
-  color: var(--ink-faint, #a8a29e);
-}
-.pat-noplay svg { width: 18px; height: 18px; }
-/* Cover-thumbnail op een link-only track (i.p.v. het muzieknootje). */
-.pat-noplay--cover {
-  width: 64px; height: 64px; flex: 0 0 64px;
-  border-radius: 8px;
-  background-size: cover; background-position: center;
-  margin: 0 .5rem 0 0;
-}
-.pat-row.pat-static { cursor: default; }
 
 /* ============================================================
@@ -151,13 +103,4 @@
   }
 }
-/* Het auth/login-focusscherm rendert GEEN bottom-tab (zie shell.ejs), maar de body
-   houdt wel de has-bottom-tab-class → zonder dit zou de mini-player 56px boven de
-   onderrand zweven boven een niet-bestaande tab. Reset naar bottom:0 (alle breedtes;
-   op desktop is 't sowieso al 0). Robuuste class-selector — geen :has() in deze
-   kritieke regel. */
-body.on-auth .audio-player {
-  bottom: 0;
-  padding-bottom: env(safe-area-inset-bottom, 0);
-}
 [data-theme="dark"] .audio-player {
   background: color-mix(in srgb, var(--paper, #1a1a1a) 92%, #fff);
@@ -168,18 +111,4 @@
   opacity: 0;
   pointer-events: none;
-}
-
-/* Browser-autoplay-policy heeft de auto-advance gestopt — typisch
-   na 3-4 tracks op iOS Safari. Visuele hint dat user op play moet
-   tappen om door te gaan (PCMS v10.1, audio-player.js). */
-.audio-player.audio-needs-tap .audio-btn-play {
-  animation: audio-pulse-tap 1.2s ease-in-out infinite;
-  background: rgba(255, 165, 0, 0.18);
-  border-color: orange;
-  color: orange;
-}
-@keyframes audio-pulse-tap {
-  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 165, 0, 0.5); }
-  50%      { box-shadow: 0 0 0 8px rgba(255, 165, 0, 0); }
 }
 .audio-player-inner {
@@ -205,10 +134,4 @@
 .audio-player-expand-trigger:hover {
   background: color-mix(in srgb, var(--ink, #000) 6%, transparent);
-}
-/* DESKTOP (≥1200px): geen full player — de expand-trigger opent niets (JS),
-   dus 'm niet als klikbaar laten ogen. */
-@media (min-width: 1200px) {
-  .audio-player-expand-trigger { cursor: default; }
-  .audio-player-expand-trigger:hover { background: none; }
 }
 
@@ -413,6 +336,6 @@
 body.audio-sheet-locked { overflow: hidden; }
 
-/* TELEFOON (<768px): full-width sheet, slide up from bottom */
-@media (max-width: 767.98px) {
+/* MOBILE (<720px): full-width sheet, slide up from bottom */
+@media (max-width: 719.98px) {
   .audio-sheet-panel {
     /* Real full-screen, edge-to-edge, no rounded corners or shadow */
@@ -434,6 +357,22 @@
 }
 
-/* (De grote tablet/auto-variant staat onderaan deze sectie — NÁ de basis cover/
-   info/controls-regels — anders overschrijft de basis die overrides.) */
+/* DESKTOP (≥720px): 480px wide, horizontally centered (v9 design intent).
+   We MUST set width here because v9's style.css sets width:480px and
+   we don't want left/right:0 stretching to override it.
+   The -50% horizontal centering is preserved during drag by composing
+   --pcms-drag-y into the existing translate(-50%, ...) transform. */
+@media (min-width: 720px) {
+  .audio-sheet-panel {
+    left: 50%;
+    right: auto;
+    width: 480px;
+    transform: translate(-50%, 100%);
+    border-top-left-radius: 20px;
+    border-top-right-radius: 20px;
+  }
+  .audio-sheet.is-open .audio-sheet-panel {
+    transform: translate(-50%, var(--pcms-drag-y, 0px));
+  }
+}
 
 .audio-sheet-panel.is-dragging {
@@ -583,48 +522,4 @@
 }
 
-/* TABLET / AUTO (768–1199px): grote, landscape, knop-vriendelijke full-player
-   voor tablets + een tablet-in-de-auto. Bewust full-screen + grote touch-targets.
-   STAAT BEWUST NA de basis-sheet-regels hierboven, anders overschrijft de basis
-   deze overrides (cascade-volgorde). Desktop (≥1200px) opent de full player NIET
-   (afgehandeld in audio-player.js), dus daar is geen sheet-styling nodig. */
-@media (min-width: 768px) and (max-width: 1199.98px) {
-  .audio-sheet-panel {
-    inset: 0; left: 0; right: 0; width: auto;
-    max-height: none;
-    border-radius: 0;
-    box-shadow: none;
-    transform: translateY(100%);
-    padding: clamp(2rem, 5vh, 4rem) clamp(2rem, 6vw, 5rem);
-    gap: clamp(1.25rem, 3vh, 2.5rem);
-    /* 'safe center': verticaal centreren als alles past, maar bovenaan uitlijnen
-       (geen clip) zodra cover + queue hoger zijn dan het scherm — anders wordt de
-       cover boven de viewport geduwd en is 'ie niet te scrollen. */
-    justify-content: safe center;
-    align-items: center;
-  }
-  .audio-sheet.is-open .audio-sheet-panel { transform: translateY(var(--pcms-drag-y, 0px)); }
-
-  .audio-sheet-drag-zone { align-items: center; width: 100%; margin: 0; padding: 0; }
-  .audio-sheet-cover { width: min(48vh, 460px); max-width: none; border-radius: 20px; }
-  .audio-sheet-cover svg { width: 26%; height: 26%; }
-  .audio-sheet-info { width: 100%; max-width: 660px; }
-  .audio-sheet-title  { font-size: clamp(2rem, 4vw, 3rem); }
-  .audio-sheet-artist { font-size: clamp(1.1rem, 2vw, 1.5rem); margin-top: .5rem; }
-  .audio-sheet-album  { font-size: 1rem; margin-top: .25rem; }
-  .audio-sheet-progress { width: 100%; max-width: 660px; gap: 1.25rem; }
-  .audio-sheet-progress .audio-time { font-size: 1.05rem; min-width: 3.2em; }
-  .audio-sheet-controls { gap: clamp(1.5rem, 5vw, 3.5rem); }
-  .audio-sheet-btn { width: 76px; height: 76px; }
-  .audio-sheet-btn svg { width: 34px; height: 34px; }
-  .audio-sheet-play { width: 108px; height: 108px; }
-  .audio-sheet-play svg { width: 46px; height: 46px; }
-  /* Queue dezelfde breedte als info/progress (anders krimpt 'ie door
-     align-items:center tot z'n inhoud = smal), + grotere rijen voor touch. */
-  .audio-sheet-queue { width: 100%; max-width: 660px; }
-  .audio-sheet-queue-label { font-size: 0.95rem; }
-  .audio-sheet-queue-item { padding: 0.7rem 0.7rem; gap: 0.6rem; font-size: 1.05rem; }
-  .audio-sheet-queue-item .aqi-artist { font-size: 0.95rem; }
-}
-
 /* ============================================================
    External-link variant ([[link:url]])
Index: src/assets/css/embed.css
===================================================================
--- src/assets/css/embed.css	(revision 2165b6d3d57ceaa8b5d1f70491868482149470cf)
+++ 	(revision )
@@ -1,284 +1,0 @@
-/* ============================================================
- * embed.css — eigen, in-huisstijl media-embeds (embed-player.js)
- * YouTube/SoundCloud = volledig eigen controls; Spotify = onze frame + hun UI.
- * Gebruikt de site-tokens (--paper/--ink/--accent/--rule/--radius) → past zich
- * automatisch aan elk thema (light/dark/varianten) aan.
- * ============================================================ */
-
-.folio-embed.pcms-embed-card {
-  margin: 2rem 0;
-  border: 1px solid var(--rule, #e8e2d5);
-  border-radius: var(--radius, 8px);
-  background: var(--paper-2, #f2ede0);
-  overflow: hidden;
-  position: relative;
-}
-
-/* Placeholder vóór embed-player.js de kaart opbouwt (of als JS uitstaat). */
-.pcms-embed-card.pcms-embed-loading {
-  min-height: 64px;
-}
-/* Fallback-tekst zolang JS de kaart nog niet heeft opgebouwd (of als JS uitstaat).
- * buildCard() haalt .pcms-embed-loading weg → deze ::after verdwijnt vanzelf. */
-.pcms-embed-card.pcms-embed-loading::after {
-  content: "Speler laden\2026";
-  display: block;
-  padding: 1.25rem 1.5rem;
-  color: var(--ink-faint, #a8a29e);
-  font-size: .85rem;
-  font-family: var(--font-mono, monospace);
-}
-
-/* ---- Video-stage (YouTube): 16:9 ---- */
-.pcms-embed-stage {
-  position: relative;
-  width: 100%;
-  aspect-ratio: 16 / 9;
-  background: #000;
-}
-.pcms-embed-stage .pcms-embed-mount,
-.pcms-embed-stage iframe {
-  position: absolute;
-  inset: 0;
-  width: 100% !important;
-  height: 100% !important;
-  border: 0;
-}
-.pcms-embed-poster {
-  position: absolute;
-  inset: 0;
-  width: 100%;
-  height: 100%;
-  border: 0;
-  padding: 0;
-  cursor: pointer;
-  background-size: cover;
-  background-position: center;
-  background-color: #000;
-  display: grid;
-  place-items: center;
-  transition: opacity var(--transition, 180ms);
-}
-.pcms-embed-card.is-mounted .pcms-embed-poster { display: none; }
-
-/* ---- Audio-layout (SoundCloud / Spotify-facade) ---- */
-.pcms-embed-audio {
-  display: flex;
-  align-items: stretch;
-  gap: 0;
-  min-height: 96px;
-}
-.pcms-embed-art {
-  flex: 0 0 96px;
-  width: 96px;
-  height: 96px;
-  border: 0;
-  padding: 0;
-  cursor: pointer;
-  background: var(--paper, #faf8f3) center / cover no-repeat;
-  display: grid;
-  place-items: center;
-  color: var(--ink, #1a1a1a);
-}
-.pcms-embed-art.has-art .pcms-embed-bigplay {
-  background: rgba(0,0,0,.45);
-  border-radius: 50%;
-}
-.pcms-embed-info {
-  flex: 1 1 auto;
-  min-width: 0;
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  gap: .2rem;
-  padding: .75rem 1rem;
-}
-.pcms-embed-info .pcms-embed-title {
-  font-weight: 600;
-  font-size: .95rem;
-  color: var(--ink, #1a1a1a);
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-.pcms-embed-info .pcms-embed-sub {
-  font-size: .8rem;
-  color: var(--ink-muted, #6b6560);
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-/* SoundCloud-iframe: functioneel maar onzichtbaar (we sturen via de Widget-API
- * en tonen onze eigen balk). Off-screen i.p.v. display:none zodat de widget
- * betrouwbaar initialiseert + audio blijft spelen. */
-.pcms-embed-card--soundcloud .pcms-embed-mount {
-  position: absolute;
-  left: -99999px;
-  top: 0;
-  width: 320px;
-  height: 60px;
-  opacity: 0;
-  pointer-events: none;
-}
-
-/* Spotify: hun iframe IS de speler → tonen. Onze facade (art+info) verdwijnt
- * zodra de controller gemount is. */
-.pcms-embed-card--spotify .pcms-embed-mount { display: block; width: 100%; }
-.pcms-embed-card--spotify .pcms-embed-mount iframe {
-  width: 100% !important;
-  border: 0;
-  display: block;
-}
-.pcms-embed-card--spotify.is-mounted .pcms-embed-art,
-.pcms-embed-card--spotify.is-mounted .pcms-embed-info { display: none; }
-.pcms-embed-card--spotify:not(.is-mounted) .pcms-embed-mount { display: none; }
-
-/* Spotify in een nette witte box (Robin 2026-06-15): witte rand + rounded +
- * schaduw. Hogere specificity (.folio-embed.pcms-embed-card--spotify) zodat dit
- * de generieke .folio-embed.pcms-embed-card-basis (gelijke specificity) wint —
- * staat ook later in het bestand. */
-.folio-embed.pcms-embed-card--spotify {
-  border: 3px solid #ffffff;          /* witte rand blijft */
-  border-radius: 16px;
-  box-shadow: 0 4px 18px rgba(0, 0, 0, .18);
-  /* bg + overflow:hidden erven van de basis-kaart → de binnenste box krijgt
-   * weer de thema-kleur (var(--paper-2)) i.p.v. wit; facade-tekst gebruikt de
-   * gewone thema-tokens en blijft dus leesbaar. */
-}
-
-/* ---- Grote play-knop (poster/art) ---- */
-.pcms-embed-bigplay {
-  width: 64px;
-  height: 64px;
-  display: grid;
-  place-items: center;
-  border-radius: 50%;
-  background: var(--accent, #c2410c);
-  color: #fff;
-  box-shadow: 0 4px 16px rgba(0,0,0,.35);
-  transition: transform var(--transition, 180ms);
-}
-.pcms-embed-art .pcms-embed-bigplay { width: 44px; height: 44px; }
-.pcms-embed-bigplay svg { width: 42%; height: 42%; }
-.pcms-embed-poster:hover .pcms-embed-bigplay,
-.pcms-embed-art:hover .pcms-embed-bigplay { transform: scale(1.08); }
-
-/* ---- Onze controlebalk (YouTube/SoundCloud) ---- */
-.pcms-embed-bar {
-  display: flex;
-  align-items: center;
-  gap: .65rem;
-  padding: .55rem .75rem;
-  border-top: 1px solid var(--rule, #e8e2d5);
-  background: var(--paper, #faf8f3);
-}
-.pcms-embed-pp {
-  flex: 0 0 auto;
-  width: 38px;
-  height: 38px;
-  border: 0;
-  border-radius: 50%;
-  cursor: pointer;
-  background: var(--accent, #c2410c);
-  color: #fff;
-  display: grid;
-  place-items: center;
-}
-.pcms-embed-pp svg { width: 18px; height: 18px; }
-.pcms-embed-cur, .pcms-embed-dur {
-  flex: 0 0 auto;
-  font-size: .75rem;
-  color: var(--ink-muted, #6b6560);
-  font-variant-numeric: tabular-nums;
-  min-width: 2.6em;
-  text-align: center;
-}
-/* Volume: mute-knop + compacte schuif (alleen YT/SC — eigen controls). */
-.pcms-embed-mute {
-  flex: 0 0 auto;
-  width: 28px; height: 28px;
-  border: 0; background: none; padding: 0;
-  color: var(--ink-muted, #6b6560);
-  cursor: pointer;
-  display: grid; place-items: center;
-}
-.pcms-embed-mute svg { width: 18px; height: 18px; }
-.pcms-embed-vol {
-  flex: 0 0 auto;
-  width: 64px;
-  cursor: pointer;
-  accent-color: var(--accent, #c2410c);
-}
-@media (max-width: 480px) {
-  /* Smal scherm: schuif weg, alleen de mute-knop houden (ruimte). */
-  .pcms-embed-vol { display: none; }
-}
-.pcms-embed-seek {
-  position: relative;
-  flex: 1 1 auto;
-  height: 16px;
-  cursor: pointer;
-}
-.pcms-embed-seek::before {
-  content: "";
-  position: absolute;
-  left: 0; right: 0; top: 50%;
-  transform: translateY(-50%);
-  height: 4px;
-  border-radius: 2px;
-  background: var(--rule-2, #d4ccb8);
-}
-.pcms-embed-seek-fill {
-  position: absolute;
-  left: 0; top: 50%;
-  transform: translateY(-50%);
-  height: 4px;
-  width: 0%;
-  border-radius: 2px;
-  background: var(--accent, #c2410c);
-  pointer-events: none;
-  z-index: 1;
-}
-.pcms-embed-badge {
-  flex: 0 0 auto;
-  font-size: .68rem;
-  letter-spacing: .04em;
-  text-transform: uppercase;
-  color: var(--ink-faint, #a8a29e);
-  text-decoration: none;
-}
-.pcms-embed-badge:hover { color: var(--accent, #c2410c); }
-
-/* Provider-accent op de badge */
-.pcms-embed-card--youtube .pcms-embed-badge { color: #ff0033; }
-.pcms-embed-card--soundcloud .pcms-embed-badge { color: #ff5500; }
-
-/* ---- Spotify-frame-badge (geen eigen balk) ---- */
-.pcms-embed-frame-badge {
-  padding: .4rem .75rem;
-  border-top: 1px solid var(--rule, #e8e2d5);
-  background: var(--paper, #faf8f3);
-  font-size: .68rem;
-  letter-spacing: .04em;
-  text-transform: uppercase;
-}
-.pcms-embed-frame-badge a { color: #1db954; text-decoration: none; }
-.pcms-embed-frame-badge a:hover { text-decoration: underline; }
-.pcms-embed-card--spotify.is-mounted .pcms-embed-frame-badge { display: none; }
-
-/* ---- Busy / error ---- */
-.pcms-embed-card.pcms-embed-busy { cursor: progress; }
-.pcms-embed-card.pcms-embed-error .pcms-embed-sub { color: #c0392b; }
-
-.pcms-embed-bigplay,
-.pcms-embed-pp,
-.pcms-embed-poster { -webkit-tap-highlight-color: transparent; }
-
-/* ---- Mobile / touch: plain platform iframe instead of the JS-mounted card.
-   padding-ratio reserves height on every browser (incl. old iOS Safari). ---- */
-.pcms-embed-plain { background: transparent; box-shadow: none; }
-.pcms-embed-ratio { position: relative; width: 100%; padding-bottom: 56.25%; height: 0; }
-.pcms-embed-ratio iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; border-radius: 10px; }
-.pcms-embed-plain-frame { width: 100%; border: 0; display: block; border-radius: 10px; }
-.pcms-embed-plain-link { display: inline-block; padding: .5rem .9rem; }
Index: src/assets/css/guardian.css
===================================================================
--- src/assets/css/guardian.css	(revision 2165b6d3d57ceaa8b5d1f70491868482149470cf)
+++ 	(revision )
@@ -1,293 +1,0 @@
-/* Guardian PWA (FEP-633c): its own calm, dark surface; the buoy orange is
-   the accent. Standalone: this page never inherits the site theme. */
-:root {
-  --bg: #141a24;
-  --card: #1e2632;
-  --ink: #e8ecf2;
-  --sub: #93a0b4;
-  --line: #2c3646;
-  --accent: #ff6b35;
-  --ok: #4caf7d;
-  --danger: #e05a5a;   /* alleen voor onomkeerbare stappen, zoals een ward loslaten */
-}
-* { box-sizing: border-box; }
-body {
-  margin: 0;
-  background: var(--bg);
-  color: var(--ink);
-  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
-  padding-bottom: 48px;
-}
-.g-head {
-  display: flex;
-  align-items: center;
-  gap: 12px;
-  padding: 16px;
-  background: var(--card);
-  border-bottom: 1px solid var(--line);
-  position: sticky;
-  top: 0;
-  z-index: 2;
-}
-.g-head-txt { flex: 1; }
-.g-head h1 { font-size: 1.15rem; margin: 0; }
-.g-head .g-sub { margin: 0; color: var(--sub); font-size: .78rem; }
-.g-buoy { font-size: 1.7rem; }
-.g-me { color: var(--sub); font-size: .85rem; }
-#site-picker {
-  background: var(--bg); color: var(--ink);
-  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px;
-}
-main { max-width: 640px; margin: 0 auto; padding: 8px 16px; }
-
-section { padding: 18px 0; border-bottom: 1px solid var(--line); }
-section:last-child { border-bottom: 0; }
-.g-sec-head { display: flex; align-items: center; gap: 8px; }
-.g-sec-head h2 { font-size: 1.02rem; margin: 0; }
-.g-badge {
-  background: var(--accent); color: #fff; font-size: .72rem; font-weight: 700;
-  min-width: 20px; text-align: center; border-radius: 10px; padding: 1px 7px;
-}
-.g-sec-sub { color: var(--sub); font-size: .84rem; margin: 4px 0 12px; }
-.g-empty { color: var(--sub); font-size: .9rem; margin: 6px 0 0; }
-.g-msg { font-size: .85rem; color: var(--ok); margin: 8px 0 0; }
-.g-msg.err { color: #ff7a7a; }
-.g-list { display: flex; flex-direction: column; gap: 8px; }
-
-.g-card { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; }
-.g-card.help { border-left: 3px solid var(--accent); }
-.g-card .row { display: flex; align-items: center; gap: 10px; }
-.g-card .row .grow { flex: 1; min-width: 0; }
-.g-card .who { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
-.g-card .when { color: var(--sub); font-size: .76rem; white-space: nowrap; }
-.g-card .body { margin-top: 8px; font-size: .92rem; overflow-wrap: anywhere; }
-.g-card .body img { max-width: 100%; border-radius: 8px; margin-top: 6px; }
-.g-link { display: inline-block; margin-top: 8px; color: var(--accent); font-size: .82rem; text-decoration: none; }
-
-.tag { font-size: .72rem; font-weight: 600; padding: 3px 9px; border-radius: 20px; white-space: nowrap; }
-.tag.wait { background: #3a2f1a; color: #e8b04b; }
-.tag.ok { background: #17301f; color: var(--ok); }
-.tag.co { background: #2a1f3a; color: #c39bff; }
-
-#adopt-form { display: flex; gap: 8px; }
-#adopt-form input {
-  flex: 1; min-width: 0;
-  background: var(--bg); color: var(--ink);
-  border: 1px solid var(--line); border-radius: 10px; padding: 11px 12px;
-}
-button {
-  background: var(--accent); color: #fff; border: 0;
-  border-radius: 10px; padding: 11px 18px; font-weight: 600; cursor: pointer;
-}
-button:disabled { opacity: .5; cursor: default; }
-button.quiet { background: transparent; color: var(--sub); border: 1px solid var(--line); font-weight: 500; }
-button.quiet.is-on { color: var(--ok); border-color: var(--ok); }
-button.small { padding: 6px 12px; font-size: .82rem; }
-
-/* Wards' corner (v2 meekijken) */
-.g-card.feed .g-when { color: var(--muted, #888); font-size: .8em; margin-left: auto; }
-.g-card.feed .feed-body { margin-top: 6px; line-height: 1.4; }
-.g-card.feed .feed-body img { max-width: 100%; border-radius: 8px; }
-
-/* ── The body of a post ────────────────────────────────────────────────────
-   The 🛟 card shows a real post, so it is rendered by the same partial de
-   Krant and Berichten use (partials/note-body). These are that partial's
-   classes, in the PWA's own colours: the dashboard is standalone and does not
-   load the site's stylesheet. */
-.g-note .tl-content { line-height: 1.5; overflow-wrap: anywhere; }
-.g-note .tl-content p { margin: .35rem 0; }
-.g-note .tl-content p:first-child { margin-top: 0; }
-.g-note .tl-content p:last-child { margin-bottom: 0; }
-.g-note .tl-content a { color: var(--accent); }
-.g-note img.emoji { height: 1.25em; width: auto; margin: 0 .05em; vertical-align: -.2em;
-  display: inline-block; border-radius: 0; background: none; }
-
-/* Quote card and link preview: one card, two origins. */
-.g-note .tl-quote { margin: 8px 0 0; padding: 8px 10px; border-radius: 10px;
-  border: 1px solid var(--line); background: var(--card-2, rgba(128,128,128,.07)); }
-.g-note .tl-quote-head { display: flex; align-items: center; gap: 6px; margin: 0 0 4px; min-width: 0; }
-.g-note .tl-quote-avatar { flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%; object-fit: cover; }
-.g-note .tl-quote-name { font-weight: 600; font-size: .82rem; white-space: nowrap; }
-.g-note .tl-quote-handle { color: var(--sub); font-size: .76rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
-.g-note .tl-quote-body { color: var(--sub); font-size: .88rem; line-height: 1.45; max-height: 14em; overflow: hidden; }
-.g-note .tl-quote-media { display: block; margin: 6px 0 0; }
-
-/* The capture a 🛟 usually carries. */
-.g-note .tl-media { display: flex; flex-direction: column; gap: 6px; margin: 8px 0 0; }
-.g-note .tl-media-img { display: block; border-radius: 10px; overflow: hidden; }
-.g-note .tl-media-img img { width: 100%; height: auto; display: block; background: #fff; }
-.g-note .tl-media-video, .g-note .tl-media-audio { width: 100%; margin: 8px 0 0; border-radius: 10px; display: block; }
-.g-note .tl-media-video { max-height: 320px; background: #000; }
-
-/* ── Paneel per ward ───────────────────────────────────────────────────────
-   Een guardian denkt per kind, niet per functie: achter de regel van een kind
-   zit alles over dat kind. De regel zelf draagt de tellers, zodat een dicht
-   paneel nooit iets verbergt dat een antwoord nodig heeft. */
-.g-card.ward > .row { gap: 8px; }
-.g-panel { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
-/* HIDDEN MOET ALTIJD WINNEN, van elke display-regel hierboven of hieronder.
-   Dit stond eerst alleen op .g-panel, en toen de poortenlijst `display: grid`
-   kreeg klapte die niet meer dicht -- Barts melding (9-8): "die is er onderuit
-   gekomen". Ook het geschiedenislogje deelde die klasse en stond dus permanent
-   open.
-
-   Een auteursregel slaat de browserstijl `[hidden] { display: none }` ongeacht
-   specificiteit, dus elke nieuwe `display:` in dit bestand zou de fout opnieuw
-   maken. Dit is de zeldzame plek waar !important het juiste gereedschap is: de
-   regel hoort per definitie boven alles te staan. */
-[hidden] { display: none !important; }
-.g-panel-sec + .g-panel-sec { margin-top: 16px; }
-.g-panel-sec h3 { margin: 0 0 6px; font-size: .82rem; font-weight: 600; letter-spacing: .03em;
-  text-transform: uppercase; color: var(--sub); }
-.g-panel-sec .g-card { background: transparent; border-color: var(--line); }
-.g-panel-sec .g-card + .g-card { margin-top: 6px; }
-.g-panel-sec .row { flex-wrap: wrap; }
-.g-empty.small { margin: 0; font-size: .85rem; }
-.tag.help { color: var(--accent); border-color: var(--accent); }
-
-/* Loslaten van een ward: geen browser-confirm maar een stap in het paneel, met
-   de gevolgen erbij. Rustig van kleur; het is een besluit, geen alarm. */
-.g-warn { margin-top: 10px; padding: 12px 14px; border-radius: 10px;
-  border: 1px solid var(--danger); background: color-mix(in srgb, var(--danger) 8%, transparent); }
-.g-warn strong { display: block; margin-bottom: 6px; }
-.g-warn p { margin: 0 0 8px; font-size: .88rem; line-height: 1.45; color: var(--sub); }
-.g-warn p.grave { color: var(--ink); font-weight: 500; }
-.g-warn .row { margin-top: 10px; gap: 8px; }
-button.danger { background: var(--danger); color: #fff; border-color: var(--danger); }
-
-/* ── Beschikbaarheid (FEP-633c 3.6) ────────────────────────────────────────
-   De buddy-list-stip op de verantwoordelijkheids-as: groen beschikbaar, geel
-   afwezig-verklaard met een einde, grijs slapend-geconstateerd (een antwoord
-   herstelt alles). Labels zijn UI; de draad houdt de spec-termen. */
-.g-avdot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }
-.g-avdot.is-active { background: var(--ok); }
-.g-avdot.is-away { background: #e0a83a; }
-.g-avdot.is-dormant { background: #8a93a3; }
-.g-avlabel { color: var(--sub); font-size: .8rem; white-space: nowrap; }
-.row.g-guard { gap: 8px; margin-top: 6px; }
-/* The status of a proposal this guardian sent (5.6): one quiet line per
-   feature. The colour says the state before the words do. */
-.g-prop { margin: 6px 0 0; color: var(--sub); }
-.g-prop-accepted { color: var(--ok); }
-.g-prop-rejected, .g-prop-expired { color: var(--danger); }
-.g-away-row { display: flex; gap: 8px; }
-.g-card.lapse { border-left: 3px solid #8a93a3; }
-.g-card.lapse .row { margin-top: 8px; gap: 8px; }
-
-/* Een voorgestelde gated setting (FEP-633c 5.6) van een mede-guardian. */
-.g-card.gated { border-left: 3px solid var(--accent); }
-.g-card.gated .row { margin-top: 8px; gap: 8px; }
-
-/* Het gate-paneel per ward (shaer-ahy.1). Een rij per gate, met het soort en de
-   drempel erbij. Bewust rustig: dit is een overzicht om te LEZEN, en pas daarna
-   een plek om iets voor te stellen. */
-.g-gate { padding: .5rem 0; border-top: 1px solid var(--g-line, rgba(0,0,0,.08)); }
-.g-gate:first-of-type { border-top: 0; }
-.g-gate-head { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
-.g-gate-name { font-weight: 600; }
-/* Het soort is een fluistering, geen kop: het hoort erbij te staan zonder de
-   naam van de gate te overstemmen. */
-.g-gate-kind { font-size: .78em; opacity: .65; }
-.g-gate-meta { display: flex; gap: .75rem; flex-wrap: wrap; margin-top: .15rem; }
-.g-gate-meta .g-dim { opacity: .55; }
-/* Onomkeerbaar krijgt gewicht, want dat is het enige in dit paneel dat je niet
-   kunt terugdraaien. */
-.g-gate-warn { font-weight: 600; }
-.g-gate-wait { font-weight: 600; }
-
-/* De gedeelde staat van een hulpvraag (shaer-lgo). Rustig: dit is geen alarm,
-   het moet alleen onmogelijk te missen zijn wie er al op af is. */
-.g-help-state { margin-top: .5rem; }
-.g-help-pick { font-size: .9em; }
-.g-help-age { opacity: .6; }        /* oud, maar niet weg */
-.g-help-done { font-weight: 600; }
-.g-confirm { margin-top: .5rem; }
-
-/* Het archief van afgehandelde hulpvragen: aanwezig, niet in de weg. */
-.g-help-archive { margin-top: .5rem; opacity: .75; }
-
-/* De geschiedenis onderaan een wardpaneel: aanwezig, duidelijk afgesloten, en
-   visueel losgemaakt van wat nog wacht. */
-.g-panel-history { border-top: 2px solid var(--g-line, rgba(0,0,0,.12)); margin-top: 1rem; opacity: .8; }
-
-/* ── Het poortenpaneel als cockpit (shaer-ahy.1, Barts richting 8-8) ──
-   Elke gate is een toets zoals op een aircopaneel: lampje links, naam erop,
-   en een klein verzonken statusveld met de stand als tekst. Het lampje en het
-   veld zeggen hetzelfde in twee vormen -- kleur alleen is geen antwoord. */
-.g-gates { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: .5rem; margin: .35rem 0; }
-.g-sw-wrap { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
-.g-sw {
-  display: flex; flex-direction: column; align-items: stretch; gap: .3rem;
-  text-align: left; padding: .5rem .6rem; border-radius: 10px;
-  border: 1px solid var(--g-line, rgba(0,0,0,.18));
-  background: var(--g-key, linear-gradient(180deg, rgba(255,255,255,.9), rgba(0,0,0,.04)));
-  box-shadow: inset 0 1px 0 rgba(255,255,255,.6), 0 1px 2px rgba(0,0,0,.12);
-  cursor: pointer; font: inherit;
-  /* Expliciet, niet geerfd (Barts aanwijzing, 8-8): de paginakleur zakte weg
-     in het toetsvlak. Het opschrift is het donkerste op de toets. */
-  color: var(--g-key-ink, #1b1e22);
-}
-.g-sw:active:not([disabled]) { box-shadow: inset 0 1px 3px rgba(0,0,0,.25); transform: translateY(1px); }
-/* Niet verstelbaar is niet kapot: de toets drukt niet in, de stand blijft leesbaar. */
-.g-sw[disabled] { cursor: default; opacity: .8; }
-.g-sw-head { display: flex; align-items: center; gap: .45em; min-width: 0; }
-.g-sw-name { font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
-
-/* Het lampje. Aan gloeit, uit is dof, onbeslist is een open kringetje (geen
-   besluit is de afwezigheid van een), wachten knippert -- de enige stand die
-   vanzelf verandert, dus de enige die om je blik mag vragen -- en gepland is
-   een lege fitting: een poort die nog niet bestaat is geen dichte deur. */
-.g-sw-lamp { flex: none; width: .6em; height: .6em; border-radius: 50%; box-shadow: inset 0 0 2px rgba(0,0,0,.35); }
-.g-lamp-on { background: var(--g-lamp-on, #2f9e5f); box-shadow: 0 0 6px 1px rgba(47,158,95,.55); }
-.g-lamp-off { background: var(--g-lamp-off, #7a8087); }
-.g-lamp-undecided { background: transparent; border: 1px dashed currentColor; opacity: .55; box-shadow: none; }
-.g-lamp-waiting { background: var(--g-warn, #b8860b); animation: g-lamp-pulse 1.4s ease-in-out infinite; }
-.g-lamp-planned { background: transparent; border: 1px dotted currentColor; opacity: .4; box-shadow: none; }
-@keyframes g-lamp-pulse { 50% { opacity: .3; } }
-@media (prefers-reduced-motion: reduce) { .g-lamp-waiting { animation: none; } }
-
-/* In het donker geen lichte toetsen: de site heeft een echt donker thema
-   (style.css), en een wit-op-lichtgrijs paneel is daar onleesbaar. Zelfde
-   vorm, andere verf; de vars blijven overschrijfbaar. */
-@media (prefers-color-scheme: dark) {
-  .g-sw {
-    background: var(--g-key, linear-gradient(180deg, rgba(255,255,255,.10), rgba(0,0,0,.25)));
-    box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 1px 2px rgba(0,0,0,.5);
-    color: var(--g-key-ink, rgba(255,255,255,.95));
-  }
-  .g-sw-state { background: var(--g-lcd, rgba(0,0,0,.4)); }
-}
-
-/* Het statusveld: verzonken venstertje, vaste letter, zoals de temperatuur op
-   het aircopaneel. */
-.g-sw-state {
-  align-self: flex-start; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
-  font-size: .74em; padding: .1em .5em; border-radius: 4px;
-  border: 1px solid var(--g-line, rgba(0,0,0,.18));
-  background: var(--g-lcd, rgba(0,0,0,.07));
-  box-shadow: inset 0 1px 2px rgba(0,0,0,.12);
-  /* Het oplichtende display van de toets: de stand in de accentkleur van het
-     huis (Barts aanwijzing, 8-8), zoals de cijfers op het aircopaneel. */
-  color: var(--accent, #6b8f71);
-  font-weight: 600;
-}
-.g-sw-meta { display: flex; flex-wrap: wrap; gap: .3em .7em; opacity: .7; font-size: .82em; }
-
-/* De poortenlijst blijft ingeklapt tot je hem opent. Met twaalf toetsen duwt
-   een open paneel alles eronder van het scherm. */
-.g-gates-toggle { display: block; width: 100%; text-align: left; margin: .25rem 0; }
-
-/* De waarschuwing bij een gate-voorstel (shaer-nf9). Geen rode paniekbalk: dit
-   moet gelezen worden, niet weggeklikt. Een rand links, zoals een citaat. */
-.g-warn { margin: .5rem 0; padding: .4rem 0 .4rem .7rem; border-left: 3px solid var(--g-warn, #b8860b); }
-.g-warn p { margin: 0 0 .25rem; }
-.g-warn p:last-child { margin-bottom: 0; }
-.g-confirm .g-warn { border-left: 0; padding-left: 0; }
-
-/* De vraag van het kind zelf (shaer-8ru). Het enige op een poortrij dat van het
-   kind komt, dus niet grijs weggeschreven tussen de drempels. */
-.g-gate-asked { margin: .2rem 0 0; color: var(--g-asked, #7a5ea8); font-weight: 600; }
-
-/* "Jouw antwoord beslist dit" (shaer-8vt). Zwaarder dan de rest van de
-   waarschuwing: dit is het verschil tussen meedoen en beslissen. */
-.g-decisive { font-weight: 700; color: var(--g-decisive, #a33); }
Index: src/assets/css/reply-editor.css
===================================================================
--- src/assets/css/reply-editor.css	(revision 2165b6d3d57ceaa8b5d1f70491868482149470cf)
+++ 	(revision )
@@ -1,120 +1,0 @@
-/* Rich reply editor (partials/reply-editor.ejs + js/reply-editor.js).
-   Styled as a small sibling of the post editor (pe-*): same 32px icon buttons,
-   same accent-active state, same framed feel, scaled down for a reply. */
-
-/* !important: site CSS gives forms inside comment threads `display: contents`,
-   which collapses the form to a 0x0 non-box — flex layout AND the fixed
-   full-screen overlay silently break. This component must own its box. */
-.re-form[data-re] { display: flex !important; flex-direction: column; gap: .5rem; }
-
-/* ── Toolbar (matches .pe-toolbar) ─────────────────────────────────────── */
-.re-toolbar { display: flex; align-items: center; gap: .1rem; flex-wrap: wrap; }
-.re-toolbar button {
-  display: inline-flex; align-items: center; justify-content: center;
-  width: 32px; height: 32px; padding: 0;
-  background: transparent; border: 1px solid transparent; border-radius: 6px;
-  color: var(--ink, currentColor); cursor: pointer;
-  touch-action: manipulation; -webkit-user-select: none; user-select: none;
-  -webkit-tap-highlight-color: transparent;
-  transition: background .15s ease, color .15s ease, border-color .15s ease;
-}
-.re-toolbar button svg { width: 16px; height: 16px; }
-@media (hover: hover) {
-  .re-toolbar button:hover { background: var(--paper-2, color-mix(in srgb, var(--ink, #000) 8%, transparent)); color: var(--accent, #06c); }
-}
-.re-toolbar button:active { transform: scale(.94); }
-.re-toolbar button.is-active { background: var(--accent, #06c); color: #fff; border-color: var(--accent, #06c); }
-.re-toolbar button.is-active svg { color: #fff; }
-.re-toolbar-sep { width: 1px; height: 18px; background: var(--rule, color-mix(in srgb, var(--ink, #000) 16%, transparent)); margin: 0 .3rem; flex-shrink: 0; }
-
-/* ── Editor box (matches .pe-editor) ───────────────────────────────────── */
-.re-editor {
-  min-height: 4rem; padding: .6rem .75rem; border-radius: 10px;
-  border: 1px solid var(--rule, color-mix(in srgb, var(--ink, #000) 16%, transparent));
-  background: var(--paper, transparent); color: inherit;
-  overflow-wrap: anywhere; outline: none; line-height: 1.5;
-  transition: border-color .15s ease, box-shadow .15s ease;
-}
-.re-editor:focus {
-  border-color: var(--accent, #06c);
-  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #06c) 18%, transparent);
-}
-.re-editor:empty::before { content: attr(data-ph); color: color-mix(in srgb, var(--ink, #000) 40%, transparent); pointer-events: none; }
-.re-editor p { margin: 0 0 .5rem; }
-.re-editor p:last-child { margin-bottom: 0; }
-.re-editor ul, .re-editor ol { margin: .4rem 0; padding-left: 1.4rem; }
-.re-editor blockquote {
-  margin: .4rem 0; padding: .1rem 0 .1rem .75rem;
-  border-left: 3px solid color-mix(in srgb, var(--ink, #000) 22%, transparent);
-  color: color-mix(in srgb, var(--ink, #000) 78%, transparent);
-}
-.re-editor a { color: var(--accent, #06c); }
-.re-editor.re-drop { border-color: var(--accent, #06c); border-style: dashed; background: color-mix(in srgb, var(--accent, #06c) 6%, transparent); }
-
-/* ── Footer: language + send ───────────────────────────────────────────── */
-.re-foot { display: flex; align-items: center; gap: .6rem; }
-.re-foot .re-send { margin-left: auto; }
-.re-lang {
-  font: inherit; font-size: .82rem; padding: .32rem .5rem; border-radius: 8px;
-  border: 1px solid var(--rule, color-mix(in srgb, var(--ink, #000) 16%, transparent));
-  background: transparent; color: inherit; max-width: 11rem;
-}
-
-/* ── Mentions bar (u02): removable partner chips ───────────────────────── */
-.re-mentions { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; }
-.re-mentions-label { font-size: .76rem; text-transform: uppercase; letter-spacing: .03em; color: color-mix(in srgb, var(--ink, #000) 50%, transparent); }
-.re-mention {
-  display: inline-flex; align-items: center; gap: .1rem;
-  padding: .12rem .2rem .12rem .5rem; border-radius: 999px; font-size: .78rem; line-height: 1.5;
-  background: color-mix(in srgb, var(--accent, #06c) 12%, transparent);
-  border: 1px solid color-mix(in srgb, var(--accent, #06c) 28%, transparent);
-  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
-}
-.re-mention-del { display: inline-flex; align-items: center; justify-content: center; width: 1.2rem; height: 1.2rem; border: none; background: none; color: inherit; opacity: .65; font-size: 1rem; line-height: 1; cursor: pointer; }
-.re-mention-del:hover { opacity: 1; }
-
-/* ── Media attachment chips (while composing) ──────────────────────────── */
-.re-attachments { display: flex; flex-wrap: wrap; gap: .4rem; }
-.re-att {
-  display: inline-flex; align-items: center; gap: .4rem;
-  padding: .25rem .3rem .25rem .5rem; border-radius: 10px; font-size: .78rem;
-  background: var(--paper-2, color-mix(in srgb, var(--ink, #000) 7%, transparent));
-  border: 1px solid var(--rule, color-mix(in srgb, var(--ink, #000) 12%, transparent));
-  max-width: 100%; overflow: hidden;
-}
-.re-att img { width: 40px; height: 40px; object-fit: cover; border-radius: 7px; display: block; }
-.re-att-del { display: inline-flex; align-items: center; justify-content: center; width: 1.3rem; height: 1.3rem; border: none; background: none; color: inherit; opacity: .65; font-size: 1.05rem; line-height: 1; cursor: pointer; }
-.re-att-del:hover { opacity: 1; }
-.re-att-busy { opacity: .7; }
-.re-att-err { background: color-mix(in srgb, #c00 16%, transparent); border-color: color-mix(in srgb, #c00 35%, transparent); }
-
-/* ── Media on a sent reply in the thread (fedi-node) ───────────────────── */
-.re-reply-media { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .5rem; }
-.re-reply-media img { max-width: min(260px, 100%); max-height: 260px; border-radius: 12px; display: block; }
-.re-reply-media audio { max-width: 100%; }
-.re-reply-media video { max-width: min(320px, 100%); border-radius: 12px; }
-
-/* ── Full-screen compose (mobile). JS toggles .re-full on the form. ────── */
-.re-head { display: flex; align-items: center; gap: .6rem; padding-bottom: .2rem; border-bottom: 1px solid var(--rule, color-mix(in srgb, var(--ink, #000) 12%, transparent)); }
-.re-head-title { flex: 1; text-align: center; font-size: .95rem; font-weight: 600; }
-.re-cancel { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border: none; background: none; color: inherit; font-size: 1.5rem; line-height: 1; cursor: pointer; border-radius: 8px; }
-@media (hover: hover) { .re-cancel:hover { background: var(--paper-2, color-mix(in srgb, var(--ink, #000) 8%, transparent)); } }
-
-.re-form.re-full {
-  /* Above the bottom tab bar (1050) and the profile/audio sheets (1100). */
-  position: fixed; inset: 0; z-index: 1200;
-  background: var(--paper, #fff); padding: .8rem .9rem; gap: .55rem;
-  padding-top: calc(.8rem + env(safe-area-inset-top));
-  padding-bottom: calc(.8rem + env(safe-area-inset-bottom));
-}
-.re-form.re-full .re-head { order: -1; }   /* the top bar stays topmost, above the mentions bar */
-.re-form.re-full .re-editor { flex: 1; min-height: 0; overflow-y: auto; border: none; box-shadow: none; padding: .4rem .1rem; }
-.re-form.re-full .re-editor:focus { border: none; box-shadow: none; }
-.re-form.re-full .re-send { display: none; }         /* send lives in the top bar */
-/* ... EN ANDERSOM. Die regel hierboven stond er wel, deze niet: buiten
-   fullscreen bleven allebei de knoppen staan, dus twee keer Verzenden onder
-   elkaar. .re-send-top had helemaal geen CSS -- hij werd nooit verborgen.
-   Een knop hoort in de bovenbalk OF in de voet, nooit in allebei. */
-.re-form:not(.re-full) .re-send-top { display: none; }
-.re-form.re-full .re-foot { justify-content: flex-start; }
-html.re-lock, html.re-lock body { overflow: hidden; }
Index: src/assets/css/style.css
===================================================================
--- src/assets/css/style.css	(revision 2165b6d3d57ceaa8b5d1f70491868482149470cf)
+++ src/assets/css/style.css	(revision 7bc636b391c66ac399c33e54f7173a022c6a3cbd)
@@ -54,5 +54,5 @@
 }
 
-/* Klonkt publieke stijl — editorial-ish, geen emoji-UI */
+/* PrutCMS publieke stijl — editorial-ish, geen emoji-UI */
 
 :root {
@@ -63,23 +63,6 @@
     --radius: 8px; --transition: 180ms cubic-bezier(.4,0,.2,1);
     --safe-top: env(safe-area-inset-top, 0); --safe-bot: env(safe-area-inset-bottom, 0);
-    /* iOS top inset: starts from env(), but a tiny boot script overrides it with a
-       real/measured value (env() resolves to 0 in some iOS standalone states). */
-    --ios-safe-top: env(safe-area-inset-top, 0px);
     color-scheme: light dark;
 }
-
-/* Native controls (datum/tijd-picker, scrollbars) het SITE-thema laten volgen i.p.v.
-   de OS-voorkeur, en de datum/tijd-velden de site-accentkleur geven. Zo staat de
-   ingebouwde kalender-popup in dark + accent (de popup zelf is een browser-widget,
-   dus fonts/randen blijven van de browser). */
-[data-theme="dark"] { color-scheme: dark; }
-[data-theme="light"] { color-scheme: light; }
-input[type="date"], input[type="time"], input[type="datetime-local"] { accent-color: var(--accent, #6b8f71); }
-input[type="date"]::-webkit-calendar-picker-indicator,
-input[type="time"]::-webkit-calendar-picker-indicator,
-input[type="datetime-local"]::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .7; }
-input[type="date"]:hover::-webkit-calendar-picker-indicator,
-input[type="time"]:hover::-webkit-calendar-picker-indicator,
-input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator { opacity: 1; }
 
 /* ============================================================
@@ -112,23 +95,4 @@
 }
 
-/* ── KLONKT ── merk-standaard: clean wit → bijna-zwart (neutraal, gouden accent) ── */
-[data-palette="klonkt"] {
-    --paper: #ffffff; --paper-2: #f4f4f5;
-    --ink: #09090b; --ink-soft: #27272a; --ink-muted: #52525b; --ink-faint: #a1a1aa;
-    --rule: #e4e4e7; --rule-2: #d4d4d8;
-}
-@media (prefers-color-scheme: dark) {
-    [data-palette="klonkt"]:not([data-theme="light"]) {
-        --paper: #0a0a0a; --paper-2: #18181b;
-        --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a;
-        --rule: #27272a; --rule-2: #3f3f46;
-    }
-}
-[data-theme="dark"][data-palette="klonkt"] {
-    --paper: #0a0a0a; --paper-2: #18181b;
-    --ink: #fafafa; --ink-soft: #d4d4d8; --ink-muted: #a1a1aa; --ink-faint: #71717a;
-    --rule: #27272a; --rule-2: #3f3f46;
-}
-
 /* ── PAPER ── minimalistisch wit → zwart ── */
 [data-palette="paper"] {
@@ -150,4 +114,22 @@
 }
 
+/* ── OCEAN ── koel blauw-grijs → diep navy ── */
+[data-palette="ocean"] {
+    --paper: #f0f6fb; --paper-2: #dce9f4;
+    --ink: #0f1e2e; --ink-soft: #1e3a52; --ink-muted: #475569; --ink-faint: #94a3b8;
+    --rule: #c7d9ea; --rule-2: #a8c0d6;
+}
+@media (prefers-color-scheme: dark) {
+    [data-palette="ocean"]:not([data-theme="light"]) {
+        --paper: #0a1929; --paper-2: #152a3f;
+        --ink: #e0f2fe; --ink-soft: #bfdbfe; --ink-muted: #93c5fd; --ink-faint: #64748b;
+        --rule: #1e3a52; --rule-2: #2a4a68;
+    }
+}
+[data-theme="dark"][data-palette="ocean"] {
+    --paper: #0a1929; --paper-2: #152a3f;
+    --ink: #e0f2fe; --ink-soft: #bfdbfe; --ink-muted: #93c5fd; --ink-faint: #64748b;
+    --rule: #1e3a52; --rule-2: #2a4a68;
+}
 
 /* ── FOREST ── olijfgroen → donker bos ── */
@@ -227,155 +209,21 @@
 }
 
-/* ── SAND ── warm papier (subtiel, niet fel geel) → warm donker ── (key blijft 'cream') */
+/* ── CREAM ── warm papier → caramel-donker ── */
 [data-palette="cream"] {
-    --paper: #f7f3ec; --paper-2: #ece5d8;
-    --ink: #232019; --ink-soft: #43392c; --ink-muted: #6f6149; --ink-faint: #a3957c;
-    --rule: #ddd3c0; --rule-2: #c9bca3;
+    --paper: #fefaf0; --paper-2: #f5ebd5;
+    --ink: #2a1f0f; --ink-soft: #4a3820; --ink-muted: #786140; --ink-faint: #ad9068;
+    --rule: #e8d9b0; --rule-2: #d1bc8a;
 }
 @media (prefers-color-scheme: dark) {
     [data-palette="cream"]:not([data-theme="light"]) {
-        --paper: #14120d; --paper-2: #221e15;
-        --ink: #efe9dd; --ink-soft: #d0c6b2; --ink-muted: #a3957c; --ink-faint: #6f6149;
-        --rule: #322c20; --rule-2: #463d2c;
+        --paper: #1a1208; --paper-2: #2e2012;
+        --ink: #fef3d6; --ink-soft: #e0cfa0; --ink-muted: #b0996b; --ink-faint: #7a6848;
+        --rule: #3d2c16; --rule-2: #523d1f;
     }
 }
 [data-theme="dark"][data-palette="cream"] {
-    --paper: #14120d; --paper-2: #221e15;
-    --ink: #efe9dd; --ink-soft: #d0c6b2; --ink-muted: #a3957c; --ink-faint: #6f6149;
-    --rule: #322c20; --rule-2: #463d2c;
-}
-
-/* ── OCEAN ── helder blauw → diep oceaanblauw ── */
-[data-palette="ocean"] {
-    --paper: #eef4fb; --paper-2: #d8e6f7;
-    --ink: #0f2942; --ink-soft: #1d4368; --ink-muted: #4a6e90; --ink-faint: #87a3c0;
-    --rule: #c2d8ee; --rule-2: #a3c2e0;
-}
-@media (prefers-color-scheme: dark) {
-    [data-palette="ocean"]:not([data-theme="light"]) {
-        --paper: #081726; --paper-2: #102a42;
-        --ink: #d6e8fb; --ink-soft: #aecbe8; --ink-muted: #7e9fc0; --ink-faint: #547390;
-        --rule: #1d3a56; --rule-2: #2a4d6e;
-    }
-}
-[data-theme="dark"][data-palette="ocean"] {
-    --paper: #081726; --paper-2: #102a42;
-    --ink: #d6e8fb; --ink-soft: #aecbe8; --ink-muted: #7e9fc0; --ink-faint: #547390;
-    --rule: #1d3a56; --rule-2: #2a4d6e;
-}
-
-/* ── TEAL ── mint-turquoise → diep teal ── */
-[data-palette="teal"] {
-    --paper: #ecf7f5; --paper-2: #cfe9e4;
-    --ink: #0c2e2a; --ink-soft: #194a44; --ink-muted: #467168; --ink-faint: #84aaa2;
-    --rule: #bce0d9; --rule-2: #9bcbc1;
-}
-@media (prefers-color-scheme: dark) {
-    [data-palette="teal"]:not([data-theme="light"]) {
-        --paper: #06201d; --paper-2: #0e332e;
-        --ink: #d4f2ec; --ink-soft: #aad9d0; --ink-muted: #7aaaa0; --ink-faint: #517a72;
-        --rule: #1a4a42; --rule-2: #275e54;
-    }
-}
-[data-theme="dark"][data-palette="teal"] {
-    --paper: #06201d; --paper-2: #0e332e;
-    --ink: #d4f2ec; --ink-soft: #aad9d0; --ink-muted: #7aaaa0; --ink-faint: #517a72;
-    --rule: #1a4a42; --rule-2: #275e54;
-}
-
-/* ── CANDY ── zacht roze-rood → diep kersenrood ── */
-[data-palette="candy"] {
-    --paper: #fdf1f3; --paper-2: #f8d8de;
-    --ink: #3a1018; --ink-soft: #5e1f2a; --ink-muted: #8e4450; --ink-faint: #c2868f;
-    --rule: #f0c5cd; --rule-2: #e3a0ab;
-}
-@media (prefers-color-scheme: dark) {
-    [data-palette="candy"]:not([data-theme="light"]) {
-        --paper: #220810; --paper-2: #3a121d;
-        --ink: #fde0e6; --ink-soft: #f5b8c4; --ink-muted: #cd8b98; --ink-faint: #8e5f6a;
-        --rule: #4d1a28; --rule-2: #632536;
-    }
-}
-[data-theme="dark"][data-palette="candy"] {
-    --paper: #220810; --paper-2: #3a121d;
-    --ink: #fde0e6; --ink-soft: #f5b8c4; --ink-muted: #cd8b98; --ink-faint: #8e5f6a;
-    --rule: #4d1a28; --rule-2: #632536;
-}
-
-/* ── AMBER ── warm honing → diep amber ── */
-[data-palette="amber"] {
-    --paper: #fdf6e9; --paper-2: #f7e6c2;
-    --ink: #3a2a0c; --ink-soft: #5e451a; --ink-muted: #8e7340; --ink-faint: #c2a877;
-    --rule: #f0dca8; --rule-2: #e3c581;
-}
-@media (prefers-color-scheme: dark) {
-    [data-palette="amber"]:not([data-theme="light"]) {
-        --paper: #221a08; --paper-2: #3a2c12;
-        --ink: #fdeecb; --ink-soft: #f0d49a; --ink-muted: #c2a877; --ink-faint: #8e7340;
-        --rule: #4d3a16; --rule-2: #634d20;
-    }
-}
-[data-theme="dark"][data-palette="amber"] {
-    --paper: #221a08; --paper-2: #3a2c12;
-    --ink: #fdeecb; --ink-soft: #f0d49a; --ink-muted: #c2a877; --ink-faint: #8e7340;
-    --rule: #4d3a16; --rule-2: #634d20;
-}
-
-/* ── ROSE ── zacht roze → wijnrood ── */
-[data-palette="rose"] {
-    --paper: #fdf2f4; --paper-2: #f8dde3;
-    --ink: #2e1419; --ink-soft: #4d242c; --ink-muted: #7a4651; --ink-faint: #b3838d;
-    --rule: #f0c9d1; --rule-2: #e0a3af;
-}
-@media (prefers-color-scheme: dark) {
-    [data-palette="rose"]:not([data-theme="light"]) {
-        --paper: #1f0a0f; --paper-2: #33141c;
-        --ink: #fce4ea; --ink-soft: #f0bcc8; --ink-muted: #c98f9d; --ink-faint: #8a6470;
-        --rule: #4a1f2c; --rule-2: #5e2d3a;
-    }
-}
-[data-theme="dark"][data-palette="rose"] {
-    --paper: #1f0a0f; --paper-2: #33141c;
-    --ink: #fce4ea; --ink-soft: #f0bcc8; --ink-muted: #c98f9d; --ink-faint: #8a6470;
-    --rule: #4a1f2c; --rule-2: #5e2d3a;
-}
-
-
-/* ── TERRACOTTA ── warme klei → diep brick ── (key blijft 'mint' voor DB-compat) */
-[data-palette="mint"] {
-    --paper: #faf2ee; --paper-2: #f2ddd0;
-    --ink: #2e1a12; --ink-soft: #4a2c1e; --ink-muted: #7a5544; --ink-faint: #b3917e;
-    --rule: #eccdbb; --rule-2: #ddb49d;
-}
-@media (prefers-color-scheme: dark) {
-    [data-palette="mint"]:not([data-theme="light"]) {
-        --paper: #1f120c; --paper-2: #2e1c13;
-        --ink: #f7e6da; --ink-soft: #e0c3b0; --ink-muted: #b3917c; --ink-faint: #7a5544;
-        --rule: #4a2c1e; --rule-2: #5e3a28;
-    }
-}
-[data-theme="dark"][data-palette="mint"] {
-    --paper: #1f120c; --paper-2: #2e1c13;
-    --ink: #f7e6da; --ink-soft: #e0c3b0; --ink-muted: #b3917c; --ink-faint: #7a5544;
-    --rule: #4a2c1e; --rule-2: #5e3a28;
-}
-
-/* ── LILAC ── zacht lila → donker violet ── */
-[data-palette="lilac"] {
-    --paper: #faf4fb; --paper-2: #f0e0f3;
-    --ink: #2a1830; --ink-soft: #46294f; --ink-muted: #7a5685; --ink-faint: #b393bd;
-    --rule: #e6cdec; --rule-2: #d4abdd;
-}
-@media (prefers-color-scheme: dark) {
-    [data-palette="lilac"]:not([data-theme="light"]) {
-        --paper: #170a1c; --paper-2: #281433;
-        --ink: #f3e2f7; --ink-soft: #dabce4; --ink-muted: #b088c0; --ink-faint: #7a5a88;
-        --rule: #3d1f4a; --rule-2: #4f2b5e;
-    }
-}
-[data-theme="dark"][data-palette="lilac"] {
-    --paper: #170a1c; --paper-2: #281433;
-    --ink: #f3e2f7; --ink-soft: #dabce4; --ink-muted: #b088c0; --ink-faint: #7a5a88;
-    --rule: #3d1f4a; --rule-2: #4f2b5e;
+    --paper: #1a1208; --paper-2: #2e2012;
+    --ink: #fef3d6; --ink-soft: #e0cfa0; --ink-muted: #b0996b; --ink-faint: #7a6848;
+    --rule: #3d2c16; --rule-2: #523d1f;
 }
 
@@ -385,41 +233,9 @@
 
 * { box-sizing: border-box; }
-html {
-    -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent;
-    overscroll-behavior-y: none;
-    /* Horizontaal clippen op ROOT-niveau: dit propageert naar de viewport (geen
-       horizontale scroll) ZONDER position:fixed te breken — html is sowieso de
-       document-scroller. De body mag GEEN overflow-x krijgen, want dan zou die een
-       tweede scroll-container worden en zou de fixed bottom-tab meeschuiven. */
-    overflow-x: hidden;
-}
+html { -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; overscroll-behavior-y: none; }
 body {
     margin: 0;
-}
-
-/* ── Thema-scrollbar: slank, afgerond, subtiel — vervangt de standaard chunky
-   browser-scrollbar (met pijltjes) die niet bij het donkere thema past.
-   Werkt op de pagina én op interne scrollers (queue, chat-thread, dropdowns). ── */
-* {
-    scrollbar-width: thin;
-    scrollbar-color: color-mix(in srgb, var(--ink) 28%, transparent) transparent;
-}
-::-webkit-scrollbar { width: 10px; height: 10px; }
-::-webkit-scrollbar-track { background: transparent; }
-::-webkit-scrollbar-thumb {
-    background-color: color-mix(in srgb, var(--ink) 24%, transparent);
-    border-radius: 999px;
-    border: 2px solid transparent;   /* transparante rand → optisch slanker (≈6px) */
-    background-clip: content-box;
-}
-::-webkit-scrollbar-thumb:hover {
-    background-color: color-mix(in srgb, var(--accent) 60%, var(--ink));
-}
-::-webkit-scrollbar-corner { background: transparent; }
-
-/* Login/auth = focus-scherm. Bij htmx-navigatie naar login blijft de bottom-tab
-   uit de vorige pagina in de DOM staan → hier verbergen zodat het login-scherm
-   net zo "kaal" is als bij een full-load (waar de tab niet eens gerenderd wordt). */
-body.on-auth .bottom-tab { display: none; }
+    overflow-x: hidden;
+}
 body:not(.admin) {
     min-height: 100dvh;
@@ -436,13 +252,7 @@
 body:not(.admin)::before {
     content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
-    /* Per-palette achtergrond-gradient: opgebouwd uit de palette's EIGEN --paper/--paper-2
-       (diagonale verloop) + een zachte accent-glow erbovenop. Werkt automatisch voor elk
-       palet, light én dark — geen per-palette regels nodig. */
-    background: radial-gradient(ellipse at top, color-mix(in srgb, var(--accent) 6%, transparent), transparent 60%),
-                radial-gradient(ellipse at bottom right, color-mix(in srgb, var(--accent) 7%, transparent), transparent 55%),
-                linear-gradient(160deg, var(--paper) 0%, var(--paper-2) 100%);
-}
-/* Klonkt-palet gebruikt nu (net als de andere paletten) de generieke accent-glow
-   hierboven → de achtergrond-gradient volgt de gekozen accentkleur. */
+    background: radial-gradient(ellipse at top, color-mix(in srgb, var(--accent) 3%, transparent), transparent 60%),
+                radial-gradient(ellipse at bottom right, color-mix(in srgb, var(--accent) 4%, transparent), transparent 55%);
+}
 ::selection { background: var(--accent-tint); color: var(--accent); }
 
@@ -454,10 +264,4 @@
 a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--rule-2); text-underline-offset: 3px; transition: color var(--transition), text-decoration-color var(--transition); }
 a:hover { color: var(--accent); text-decoration-color: var(--accent); }
-/* Knop-ankers houden hun eigen tekstkleur bij hover. Zonder dit overschrijft de
-   globale a:hover{color:accent} de knop-tekst → die wordt dezelfde kleur als de
-   accent-achtergrond en valt weg (vooral op sites met een felle accent). */
-a.btn:hover, a.epk-btn:hover { color: var(--ink); }
-a.btn-primary:hover, a.btn-danger:hover, a.btn-success:hover, a.button:hover,
-a.epk-btn-primary:hover, a.dls-btn:hover, a.sh-tix:hover, a.dl-go:hover { color: #fff; text-decoration-color: currentColor; }
 a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; text-decoration: none; }
 blockquote { margin: 2em 0; padding: .25em 0 .25em 1.25em; border-left: 2px solid var(--accent); font-family: var(--font-display); font-style: italic; font-size: 1.15em; color: var(--ink-soft); }
@@ -476,9 +280,4 @@
 .container { max-width: 42rem; margin-inline: auto; padding-inline: clamp(1.25rem, 4vw, 2rem); }
 
-/* Post-/leesbreedte. Globaal + hogere specificity (.container.post-page) zodat 'ie
-   de responsive .container-breakpoints (56/72rem) overal overrult — posts én de
-   downloads-pagina krijgen zo exact dezelfde 720px-breedte. */
-.container.post-page { max-width: 720px; margin: 0.5rem auto 2rem; padding: 0 1rem; }
-
 /* Laptop / Full HD — 1440px viewport of groter */
 @media (min-width: 1440px) {
@@ -510,9 +309,7 @@
 .masthead {
     border-bottom: 1px solid var(--rule);
-    padding: calc(1rem + var(--ios-safe-top, 0px)) 0 1rem;
-    /* GEEN backdrop-filter hier: een voorouder met backdrop-filter blokkeert de
-       frosted blur van het user-menu-dropdown eronder. Masthead is toch bijna
-       dekkend, dus solide bg i.p.v. blur. */
-    background: color-mix(in srgb, var(--paper) 94%, transparent);
+    padding: calc(1rem + var(--safe-top)) 0 1rem;
+    background: color-mix(in srgb, var(--paper) 88%, transparent);
+    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
     position: sticky; top: 0; z-index: 20;
 }
@@ -559,24 +356,4 @@
 
 .empty { text-align: center; padding: 4rem 1rem; }
-/* Moved account (FEP-7628 slice 3): the signpost above the feed. Loud on
-   purpose — a visitor must not read a stale timeline thinking it is current. */
-.moved-banner {
-    text-align: center;
-    margin: 1.5rem 0 2rem;
-    padding: 1.75rem 1.25rem;
-    border: 2px solid var(--accent, #e8b04b);
-    border-radius: var(--radius, 10px);
-    background: color-mix(in srgb, var(--accent, #e8b04b) 10%, var(--paper-2, var(--paper)));
-}
-.moved-banner-lead { margin: 0 0 .5rem; font-size: 1rem; opacity: .85; }
-.moved-banner-link {
-    display: inline-block;
-    font-family: var(--font-display);
-    font-size: clamp(1.5rem, 5vw, 2.4rem);
-    font-weight: 700;
-    line-height: 1.15;
-    overflow-wrap: anywhere;
-}
-.moved-banner-hint { margin: .75rem 0 0; font-size: .85rem; color: var(--ink-soft); }
 .empty h1 { font-size: 2rem; }
 .empty p { color: var(--ink-muted); }
@@ -584,6 +361,5 @@
 /* Embeds */
 .pcms-embed, .folio-embed { margin: 2rem 0; }
-.pcms-embed iframe, .pcms-embed video, .pcms-embed audio,
-.folio-embed iframe, .folio-embed video, .folio-embed audio { width: 100%; display: block; border: 0; border-radius: var(--radius); }
+.pcms-embed iframe, .folio-embed iframe { width: 100%; display: block; border: 0; border-radius: var(--radius); }
 
 /* Article footer */
@@ -692,5 +468,5 @@
 
 /* Footer */
-.site-footer { padding: 2rem 0 calc(2rem + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--rule); margin-top: 4rem; font-family: var(--font-ui); font-size: .85rem; color: var(--ink-muted); }
+.site-footer { padding: 2rem 0 calc(2rem + var(--safe-bot)); border-top: 1px solid var(--rule); margin-top: 4rem; font-family: var(--font-ui); font-size: .85rem; color: var(--ink-muted); }
 .site-footer-inner { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem; align-items: center; }
 .site-footer a { color: var(--ink-muted); text-decoration-color: var(--rule); }
@@ -721,7 +497,7 @@
     display: block;
     width: 100%;
-    height: auto;        /* volledige (niet-bijgesneden) hoogte */
-    /* geen max-height/object-fit: cover meer → de hele afbeelding toont,
-       volle containerbreedte, zijkanten gerespecteerd. */
+    height: auto;
+    max-height: 50vh;
+    object-fit: cover;
 }
 .post-title { font-size: clamp(1.6rem, 4vw, 2.6rem); line-height: 1.15; margin: 0 0 .5rem; letter-spacing: -.02em; }
@@ -783,33 +559,4 @@
 .post-image--right img { margin-left: auto; margin-right: 0; }
 
-/* Afbeeldingen in de post-tekst vullen ALTIJD de containerbreedte en houden hun
-   natuurlijke (niet-bijgesneden) hoogte — geen vaste hoogte / geen crop. */
-.post-content img {
-    display: block;
-    width: 100%;
-    max-width: 100%;
-    height: auto;
-    border-radius: 6px;
-    margin: 1.4em auto;
-}
-
-/* Video in de post-tekst (C2S-uploads uit Shaer): dezelfde maatvoering als
-   afbeeldingen, plus een plafond. Zonder deze regel rendert een <video> op
-   zijn natuurlijke maat en duwt een portret-video de hele kolom vol; met
-   object-fit blijft het beeld heel binnen het kader. Geldt ook voor de
-   Krant/Berichten (tl-content), waar dezelfde content langskomt. */
-.post-content video, .tl-content video {
-    display: block;
-    width: 100%;
-    max-width: 100%;
-    max-height: min(70vh, 540px);
-    height: auto;
-    object-fit: contain;
-    background: #000;
-    border-radius: 6px;
-    margin: 1.4em auto;
-}
-.post-content audio, .tl-content audio { width: 100%; display: block; margin: 1em auto; }
-
 /* Mini-player + bottom-tab clearance: applied to .pcms-main so the footer
    is NOT pushed below the viewport bottom. The bars are position:fixed so
@@ -819,25 +566,4 @@
 .pcms-main { padding-bottom: 5.5rem; }
 body.has-audio-player .pcms-main { padding-bottom: 5.5rem; }
-
-/* Mobiel toetsenbord open (body.kb-open, gezet via visualViewport in shell.ejs):
-   verberg de vaste onderbalken — anders zweven de bottom-tab + mini-speler boven
-   het toetsenbord of overlappen ze het invoerveld. Ze komen terug zodra het
-   toetsenbord sluit. De extra clearance onderaan is dan ook niet meer nodig. */
-body.kb-open .bottom-tab,
-body.kb-open .audio-player { display: none !important; }
-body.kb-open .pcms-main { padding-bottom: 1rem; }
-
-/* Mobiel & tablet (touch): scrollbalken verbergen — scrollen blijft werken, alleen
-   de balk-UI is weg (geen verwarrende/dubbele balken). */
-@media (pointer: coarse) {
-  * { scrollbar-width: none; -ms-overflow-style: none; }
-  *::-webkit-scrollbar { width: 0; height: 0; display: none; }
-}
-
-/* Afbeeldingen lastiger op te slaan (frictie, geen echte beveiliging): geen
-   sleep-naar-bureaublad, geen iOS long-press-bewaarmenu. Rechtsklik wordt in JS
-   geblokkeerd (zie shell.ejs). Covers/hero zijn al CSS-achtergronden = niet via
-   "afbeelding opslaan" te pakken. */
-img { -webkit-user-drag: none; -khtml-user-drag: none; -moz-user-drag: none; user-drag: none; -webkit-touch-callout: none; }
 
 /* ============================================================
@@ -1172,7 +898,8 @@
     }
 
-    /* v9.3 — horizontaal clippen gebeurt nu globaal op html (zie de html-regel
-       bovenaan). Hier bewust NIETS op body zetten: body als scroll-container zou
-       de fixed bottom-tab op mobiel laten meeschuiven. */
+    /* v9.3 — Forceer niets schuift horizontaal weg */
+    body, html {
+        overflow-x: hidden;
+    }
 }
 
@@ -1662,5 +1389,5 @@
         border-top-right-radius: 0;
         box-shadow: none;
-        padding-top: calc(.75rem + var(--ios-safe-top, 0px));
+        padding-top: calc(.75rem + env(safe-area-inset-top, 0px));
         padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
     }
@@ -1686,39 +1413,6 @@
     .pagination-item { width: 100%; }
 }
-
-/* Taal-keuze in de header-nav (NL/EN/DE) — eigen gestylede dropdown. */
-.lang-menu { position: relative; }
-.lang-menu > summary {
-    list-style: none; cursor: pointer;
-    display: inline-flex; align-items: center; gap: .3rem;
-    padding: .35rem .55rem; border-radius: 999px;
-    border: 1px solid var(--rule); background: transparent; color: var(--ink);
-}
-.lang-menu > summary::-webkit-details-marker { display: none; }
-.lang-menu > summary:hover { border-color: var(--accent); }
-.lang-toggle .lang-code { font-size: .8rem; font-weight: 700; letter-spacing: .02em; }
-.lang-toggle .icon { width: 16px; height: 16px; opacity: .8; }
-.lang-caret { width: 12px; height: 12px; opacity: .7; transition: transform .15s; }
-.lang-menu[open] .lang-caret { transform: rotate(180deg); }
-.lang-dropdown {
-    position: absolute; top: calc(100% + 8px); right: 0;
-    min-width: 170px; z-index: 60;
-    background: var(--paper); border: 1px solid var(--rule);
-    border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.22);
-    padding: .35rem; display: flex; flex-direction: column;
-}
-.lang-item {
-    display: flex; align-items: center; gap: .6rem;
-    padding: .5rem .65rem; border-radius: 8px;
-    color: var(--ink); text-decoration: none; font-size: .9rem;
-}
-.lang-item:hover { background: var(--paper-2); }
-.lang-item.is-active { color: var(--accent); font-weight: 600; }
-.lang-item-code {
-    font-size: .7rem; font-weight: 700; opacity: .6;
-    min-width: 1.6em;
-}
 @media (max-width: 400px) {
-    .masthead { padding: calc(.5rem + var(--ios-safe-top, 0px)) 0 .5rem; }
+    .masthead { padding: calc(.5rem + var(--safe-top)) 0 .5rem; }
     .masthead-inner { gap: .25rem; }
     .site-title { font-size: 1.05rem; }
@@ -1971,18 +1665,10 @@
     overflow: hidden;
     border-radius: var(--radius);
-    /* Accent-gradient placeholder while the cover image loads (image fades in over it). */
-    background-image: linear-gradient(135deg,
-        color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
-        color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
-}
-.post-list-cover img, .post-list-cover video {
+}
+.post-list-cover img {
     width: 100%; height: 100%;
-    object-fit: cover;                 /* fill the square, keep aspect, crop the overflow, centered */
-    object-position: center;
+    object-fit: cover;
     display: block;
-    background-color: #fff;            /* transparent logos sit on white once loaded */
-    transition: opacity .4s ease;
-}
-.post-list-cover img.is-loading { opacity: 0; }
+}
 .post-list-body { display: flex; flex-direction: column; gap: .35rem; }
 .post-list-meta {
@@ -2254,6 +1940,5 @@
 }
 .profile-links li { margin: 0; }
-.profile-links a,
-.profile-links .profile-fedi-link {
+.profile-links a {
     display: inline-flex;
     align-items: center;
@@ -2267,6 +1952,5 @@
     transition: background .15s, color .15s;
 }
-.profile-links a:hover,
-.profile-links .profile-fedi-link:hover {
+.profile-links a:hover {
     background: color-mix(in srgb, var(--accent) 15%, transparent);
     color: var(--accent);
@@ -2341,6 +2025,5 @@
     background: var(--paper);
     /* Bottom margin gives breathing room between the switcher bar and the
-       first post. margin-top staat in shared-styles.ejs (de winnende inline
-       <style>) — symmetrisch op 1.5rem. */
+       first post — without it the feed sits flush against the bar. */
     margin-bottom: 1.5rem;
 }
@@ -2372,27 +2055,18 @@
     border-color: var(--ink-muted);
 }
-/* Uitgeschakeld (Lezen in de cirkel) wint van :hover -- anders licht een knop
-   op die je niet kunt indrukken, en dat is precies de verkeerde belofte. */
-.view-switch-btn[disabled],
-.view-switch-btn[disabled]:hover {
-    opacity: .38;
-    cursor: not-allowed;
-    color: var(--ink-muted);
-    border-color: var(--rule);
-}
-/* Actieve state: puur afgeleid van body[data-feed-view]. Geen .is-active class meer.
-   Niet op de Archive-pagina: daar is geen "huidige" timeline/grid-keuze, dus beide
-   knoppen blijven neutraal (grijs). */
-/* Actieve Tijdlijn/Grid-state wordt nu gestuurd via [aria-selected="true"] (gezet
-   door syncAria, die óók op htmx:afterSettle draait) i.p.v. body[data-feed-view].
-   Reden: body-class/attribuut-CSS pakte niet betrouwbaar na een htmx-OOB-swap;
-   een element-attribuut wel. De witte active-regel staat in shared-styles. */
+/* Actieve state: puur afgeleid van body[data-feed-view]. Geen .is-active class meer. */
+body[data-feed-view="timeline"] .view-switch-btn[data-view="timeline"],
+body[data-feed-view="grid"] .view-switch-btn[data-view="grid"] {
+    background: var(--ink);
+    color: var(--paper);
+    border-color: var(--ink);
+}
 .view-switch-btn .icon { width: 1rem; height: 1rem; }
 
 /* -------- FEED TOGGLE VIA BODY --------
-   Grid-modus werkt op de feed (home, cirkel). Het ARCHIEF negeert de grid-keuze
-   bewust: dat is altijd de chronologische jaar/maand-lijst (de switcher is daar
-   grijs en springt bij klik terug naar de feed). Post-pagina's tonen de
-   feed-timeline article sowieso altijd. Alle andere body-classes negeren
+   Grid-modus werkt op elke feed-pagina (home, archive). Op een post-pagina
+   is de feed-timeline article juist het hoofdonderwerp — daar moet 'ie
+   altijd zichtbaar zijn, dus de grid-toggle slaat alleen aan op
+   feed-pagina's (.on-home, .on-archive). Andere body-classes negeren de
    data-feed-view en houden timeline visible. */
 body.on-home[data-feed-view="grid"]    .feed-timeline,
@@ -2400,409 +2074,12 @@
 body.on-home[data-feed-view="grid"]    .related-posts,
 body.on-home[data-feed-view="grid"]    .article-footer,
-body.on-cirkel[data-feed-view="grid"]  .feed-timeline {
+body.on-archive[data-feed-view="grid"] .feed-timeline,
+body.on-archive[data-feed-view="grid"] .pagination {
     display: none !important;
 }
-/* Grid-sectie alleen zichtbaar op de feed in grid-mode (NIET op archief) */
+/* Grid-sectie alleen zichtbaar op feed-pagina's in grid-mode */
 .feed-grid { display: none; }
 body.on-home[data-feed-view="grid"]    .feed-grid,
-body.on-cirkel[data-feed-view="grid"]  .feed-grid { display: block; }
-
-/* -------- LEESWEERGAVE (data-feed-view="reader") --------
-   Dezelfde berichten als de tijdlijn, maar heel: één per scherm, grenzen door
-   scroll-snapping. GEEN eigen route en geen eigen shell -- de balken blijven
-   staan, want je bent nog op de feed en moet terug kunnen schakelen.
-   Pagina's zonder .feed-reader (cirkel, archief, post) negeren de keuze en
-   houden hun tijdlijn: er is hieronder simpelweg geen regel die die daar
-   verbergt. Zo is Lezen nooit een leeg scherm. */
-.feed-reader { display: none; }
-body.on-home[data-feed-view="reader"] .feed-reader { display: block; }
-/* :has(.feed-reader) is hier de LEGE STAAT, niet een truc. Zonder berichten
-   rendert de leessectie niet, en dan mag de tijdlijn niet verborgen worden --
-   want dáár staat "nog niets geschreven" met de knop om te beginnen. Zonder deze
-   voorwaarde is Lezen op een verse site een wit scherm. Hetzelfde geldt voor
-   feeds die (nog) geen leessectie hebben. */
-body.on-home[data-feed-view="reader"]:has(.feed-reader) .feed-timeline,
-body.on-home[data-feed-view="reader"]:has(.feed-reader) .feed-grid,
-body.on-home[data-feed-view="reader"]:has(.feed-reader) .pagination,
-body.on-home[data-feed-view="reader"]:has(.feed-reader) .related-posts,
-body.on-home[data-feed-view="reader"]:has(.feed-reader) .article-footer {
-    display: none !important;
-}
-
-/* -------- AUTO (data-feed-view="auto") --------
-   Lezen op mobiel, Tijdlijn op desktop. GEEN JavaScript: de CSS kiest, dus geen
-   resize-afhandeling en geen flikkering waarin je eerst de verkeerde weergave
-   ziet. De tijdlijn is de terugval, dus boven de grens hoeft hier niets te
-   staan -- die is vanzelf al zichtbaar.
-   De :has(.feed-reader)-voorwaarde staat er om dezelfde reden als hierboven:
-   zonder berichten is er geen leessectie, en dan moet de tijdlijn blijven staan
-   met "nog niets geschreven" erin. */
-@media (max-width: 767px) {
-    body.on-home[data-feed-view="auto"] .feed-reader { display: block; }
-    body.on-home[data-feed-view="auto"]:has(.feed-reader) .feed-timeline,
-    body.on-home[data-feed-view="auto"]:has(.feed-reader) .feed-grid,
-    body.on-home[data-feed-view="auto"]:has(.feed-reader) .pagination,
-    body.on-home[data-feed-view="auto"]:has(.feed-reader) .related-posts,
-    body.on-home[data-feed-view="auto"]:has(.feed-reader) .article-footer {
-        display: none !important;
-    }
-}
-/* In de auto-stand staan BEIDE knoppen in de HTML en laat de mediaquery er een
-   zien. Zo verspringt de naam van de knop niet terwijl je ernaar kijkt, en is er
-   geen JavaScript nodig dat op resize moet luisteren. */
-.view-switch-btn.vs-alleen-mobiel { display: none; }
-@media (max-width: 767px) {
-    .view-switch-btn.vs-alleen-mobiel { display: inline-flex; }
-    .view-switch-btn.vs-alleen-desktop { display: none; }
-}
-
-/* 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. */
-html:has(body.on-home[data-feed-view="reader"]),
-.feed-reader .read-stream { overflow-anchor: none; }
-
-.feed-reader .read-post {
-    /* Snap naar de BOVENkant van een bericht, zacht (proximity op html) en nooit
-       dwingend (stop: normal). Een korte post vult het scherm, zodat hij niet als
-       snipper tussen twee lijnen hangt.
-       De uitzondering staat NIET hier maar in mod/read.js: een bericht dat langer
-       is dan het scherm krijgt scroll-snap-align:none, anders trekt de browser je
-       tijdens het lezen terug naar zijn bovenrand en lijkt het of het scrollen
-       stopt. "Past het op het scherm?" is een vraag over gemeten hoogte, en die
-       kan CSS niet stellen. */
-    /* Je LANDT op de bovenkant van een bericht -- dat is wat "snap to post"
-       hoort te betekenen. (align:end probeerde ik ook; dan land je op de
-       ONDERKANT van het vorige bericht, en bij een lang bericht zie je dus zijn
-       laatste schermvol in plaats van de kop van het volgende.)
-       Wanneer die bovenkant een snappunt IS, staat in mod/read.js: alleen zolang
-       je er nog niet voorbij bent. Eenmaal in een bericht snapt er niets meer,
-       ook niet naar zijn eigen bovenrand -- anders trekt proximity je terug
-       zodra je een paar regels verder leest. */
-    /* Het snappunt zit op .read-anker hierna, niet hier. Zie de toelichting
-       daar: een snapgebied groter dan het scherm heeft een BEREIK aan geldige
-       posities, en de bovenste daarvan zet het volgende bericht op de onderrand. */
-    scroll-snap-align: none;
-    scroll-snap-stop: normal;
-    /* GEEN min-height meer. Die rekte elk bericht tot een vol scherm, en bij een
-       kort bericht leverde dat een halve pagina leegte op onder "Replies and
-       reactions" -- je zat naar niets te kijken en moest verder scrollen om te
-       ontdekken dat er nog iets kwam. Robins vondst (20-8), met een
-       schermafbeelding erbij.
-       Zonder die hoogte is de stroom gewoon bericht na bericht: je ziet het
-       volgende meteen onder het vorige beginnen. Het snappen doet nog steeds
-       zijn werk aan de grens -- dat hangt aan scroll-snap-align en niet aan de
-       hoogte -- dus de streep lijnt nog altijd uit met de bovenkant van het
-       volgende bericht. */
-    max-width: 46rem;
-    margin: 0 auto;
-    /* De onderrand loopt achter de vaste tabbalk door; deze padding houdt de
-       TEKST erboven. De BOVENmarge is verdubbeld (Robin, 20-8: 2rem -> 4rem):
-       na een snap staat de scheidingslijn op de bovenrand, en de tekst
-       daaronder krijgt meer lucht. MOET GELIJK BLIJVEN aan scroll-margin-top
-       op .read-anker hieronder -- lopen die uit elkaar, dan landt de lijn niet
-       meer precies op de bovenrand. */
-    padding: 4rem 1.2rem 4rem;
-    box-sizing: border-box;
-}
-/* ONDERIN GEBEURT ER NIETS (Robin, 20-8: "enkel de bovenkant mag snappen, niet
-   de onderkant; onderin mag er niks met de zone gebeuren").
-   Het laatste bericht heeft een snappunt dat de browser NIET KAN BEREIKEN: er
-   zit niet genoeg pagina onder om zijn bovenkant naar de bovenrand te brengen.
-   Gemeten op dev: snappunt 2548, maar de scroll gaat maar tot 2356. De spec
-   laat de browser dan naar de dichtstbijzijnde BEREIKBARE positie snappen, en
-   dat is de bodem -- waardoor het laatste bericht ergens middenin het scherm
-   blijft hangen en het lijkt of er aan de onderkant wordt uitgelijnd.
-   Zonder snappunt scrolt dat laatste stuk gewoon vrij uit tot het einde. */
-/* HET SNAPPUNT. Nul hoog, dus precies EEN geldige positie: deze bovenrand aan de
-   bovenrand van het scherm. Zat de uitlijning op het artikel zelf, dan gold voor
-   elk bericht dat hoger is dan het scherm een heel BEREIK aan geldige posities
-   (spec: een snapgebied groter dan de snapport mag overal staan waar het de
-   snapport nog vult). Gemeten op dev: bericht van 1009px op een scherm van 812
-   -> geldig van 700 tot 897, en op 867 bleef hij dus gewoon staan. Die bovenste
-   stand, 897, is de onderkant van dat bericht op de onderrand -- oftewel de
-   bovenkant van het VOLGENDE bericht op de onderrand. Dat is wat er onderin
-   leek te snappen, en het kwam van de browser en niet uit onze code. */
-.feed-reader .read-anker {
-    display: block;
-    height: 0;
-    scroll-snap-align: start;
-    /* Het anker staat BINNEN de padding van het artikel, dus een padding-top
-       onder de streep. Zonder deze correctie landt de snap net zoveel te laag
-       en staat de scheidingslijn boven beeld -- gemeten: 733 waar 700 hoort.
-       scroll-margin verschuift alleen het SNAPPUNT en niet de opmaak, dus het
-       anker blijft waar het staat en de uitlijning klopt met de lijn.
-       GELIJK aan de padding-top van .read-post hierboven; die ging 20-8 van
-       2rem naar 4rem, dus deze ook. */
-    scroll-margin-top: 4rem;
-}
-/* HET LAATSTE BERICHT SNAPT OOK (Robin, 20-8). Dat kon eerst niet: zijn
-   bovenkant was onbereikbaar -- er zat te weinig pagina onder om hem naar de
-   bovenrand te brengen (gemeten: snappunt 2548, maxScroll 2356), en de browser
-   viel dan terug op de dichtstbijzijnde bereikbare positie: de bodem. Het
-   snappunt weghalen was de vorige oplossing; dit is de echte.
-   Een volle schermhoogte op het LAATSTE bericht maakt die bovenkant precies
-   bereikbaar. Korter dan het scherm: het bericht wordt even hoog en het snappunt
-   valt exact op maxScroll. Langer dan het scherm: dan was het al haalbaar en
-   doet min-height niets.
-   100lvh en niet 100svh: op een telefoon met een verdwijnende adresbalk is het
-   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; }
-
-/* ELK BERICHT EEN EIGEN SCHERM, als de site dat wil (Instellingen -> Weergave).
-   Aan: een kort bericht vult het scherm en je ziet het volgende pas na een snap.
-   Uit (standaard): de stroom is bericht na bericht, zonder lege ruimte eronder.
-   Dit stond eerst vast op AAN, is toen vast op UIT gezet omdat een kort bericht
-   een halve pagina leegte gaf onder "Replies and reactions", en is nu een keuze
-   -- want welke van de twee prettiger leest hangt af van wat je schrijft. */
-body[data-reader-pages="1"] .feed-reader .read-post { min-height: 100svh; }
-/* OP MOBIEL ALTIJD, wat de instelling ook zegt (Robin, 20-8). Op een telefoon is
-   een bericht per scherm de vorm die werkt -- je veegt van bericht naar bericht.
-   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; }
-}
-
-/* -------- PAGINAMODUS --------
-   Elk bericht is een paneel van precies een scherm dat ZELF scrollt; tussen
-   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).
-   Geldt waar een bericht een eigen scherm heeft: op mobiel altijd, op desktop
-   als de site dat zo instelt. */
-body.is-paged .feed-reader .read-post {
-    height: 100svh;
-    min-height: 0;
-    overflow-y: auto;
-    overscroll-behavior: contain;   /* raakt het einde, dan niet doorschuiven */
-    scroll-snap-align: none;
-    /* Ruimte voor de twee balken, zodat er nooit tekst onder een knop verdwijnt.
-       Het verloop laat een regel wel zacht wegvagen, maar wat je moet KUNNEN
-       lezen hoort er niet achter te komen -- vandaar padding en niet alleen die
-       fade. --read-balk staat hieronder bij .read-nav, zodat de twee niet uit
-       elkaar kunnen lopen. */
-    padding-top: calc(var(--read-balk) + .5rem);
-    padding-bottom: calc(var(--read-balk) + .5rem);
-    /* BOVENAAN beginnen, niet gecentreerd. Ik had de inhoud een ronde lang
-       verticaal gecentreerd om het gat onder een kort bericht te verdelen, maar
-       dan hangt zo'n bericht halverwege het scherm en begint niet elk paneel op
-       dezelfde plek -- dat leest onrustig. Robin ving het (20-8). Elk bericht
-       begint nu bovenaan, en de ruimte die overblijft valt onderaan. */
-}
-body.is-paged .feed-reader .read-anker { scroll-snap-align: none; }
-
-/* DE DYNAMIC ISLAND, en met opzet alleen op iOS (Robin, 20-8: "op android is het
-   een ander verhaal").
-   In paginamodus vult een bericht precies het scherm, dus de eerste regel komt
-   bovenaan -- en op een iPhone ligt daar de island of de notch overheen.
-   env(safe-area-inset-top) geeft daar de vrije ruimte; viewport-fit=cover staat
-   al in de viewport-meta, dus die waarde is echt.
-   De @supports-regel is de iOS-Safari-toets: -webkit-touch-callout bestaat alleen
-   daar. Op Android is env() vaak 0 of betekent het iets anders (camera-uitsparing,
-   statusbalk die al meegerekend is), en dan zou dit een gat bovenin maken dat er
-   niet hoort. Vandaar afgeschermd in plaats van env() overal toepassen.
-   De hoogte krimpt mee, anders duwt de padding het paneel groter dan het scherm
-   en krijg je alsnog scroll tussen de berichten. */
-@supports (-webkit-touch-callout: none) {
-    body.is-paged .feed-reader .read-post {
-        padding-top: calc(var(--read-balk) + .5rem + env(safe-area-inset-top, 0px));
-        height: calc(100svh - env(safe-area-inset-top, 0px));
-    }
-    /* De bovenbalk houdt zijn knop al vrij van de island via padding-top
-       hierboven; hier hoeft niets extra's meer. */
-}
-
-/* De knop onderaan een bericht: naar het volgende. */
-
-
-/* Omhoog en omlaag: twee balken, boven en onder, die BLIJVEN staan terwijl je in
-   een bericht scrolt (Robin, 20-8). Het verloop van paginakleur naar doorzichtig
-   laat de tekst eronderdoor wegvagen -- zonder dat zou een regel halverwege hard
-   achter de knop verdwijnen en oogt het als een afgeknipte pagina.
-   De BALK vangt geen aanrakingen (pointer-events: none), alleen de knop zelf --
-   anders zou een strook van 5rem boven- en onderaan je scroll opeten. */
-/* TWEE BALKEN over de volle breedte, boven en onder. Eerder waren dit losse
-   cirkels (te rommelig naast de tabbalk en de speler) en daarna onzichtbare
-   tikzones -- maar die werkten niet, omdat de onderste strook onder de
-   mini-speler en de tabbalk ligt en die de tik opvangen. Een balk met een eigen
-   z-index kan daar wel overheen.
-   Slank gehouden: ze eten hooguit 2.6rem aan elke kant, en het paneel houdt daar
-   al ruimte voor vrij. */
-:root { --read-balk: 2.6rem; }
-.read-bar {
-    position: fixed; left: 0; right: 0; z-index: 1060;   /* boven tabbalk (1050) */
-    display: flex; align-items: center;
-    /* Pijlen LINKS in de balk, niet gecentreerd (Robin, 20-8). */
-    justify-content: flex-start;
-    padding-left: max(1.1rem, env(safe-area-inset-left, 0px));
-    box-sizing: border-box;
-    height: var(--read-balk);
-    border: 0;
-    border-top: 1px solid transparent;
-    background: color-mix(in srgb, var(--paper) 90%, var(--ink));
-    backdrop-filter: blur(14px) saturate(140%);
-    -webkit-backdrop-filter: blur(14px) saturate(140%);
-    color: var(--ink);
-    cursor: pointer;
-    transition: opacity .15s ease;
-}
-.read-bar--top {
-    top: 0;
-    height: calc(var(--read-balk) + env(safe-area-inset-top, 0px));
-    padding-top: env(safe-area-inset-top, 0px);
-    border-bottom: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
-}
-.read-bar--bottom {
-    /* De waarde komt uit mod/read.js: die meet hoe hoog de tabbalk en de
-       mini-speler werkelijk staan. Geraden rem-waarden lieten hem zweven -- een
-       kier boven de speler, of er half achter. Dit is de terugval voor de eerste
-       frame en voor als de module niet laadt. */
-    bottom: 0;
-    border-top: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
-}
-.read-bar:active { background: color-mix(in srgb, var(--paper) 78%, var(--ink)); }
-.read-bar[hidden], body:not(.is-paged) .read-bar { display: none; }
-
-/* Een lijn tussen twee berichten: zonder grens is een stroom een lange brij. */
-.feed-reader .read-post + .read-post { border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent); }
-
-/* De cover vult de leeskolom. Eigen regel, niet .post-cover hergebruikt: die
-   heeft een marge van 2rem die hier tegen de scroll-snap aan duwt.
-   De hoogtebegrenzing is er met opzet. Een paneel is min-height:100svh en snapt,
-   dus een staande foto op volle breedte zou de titel en de eerste alinea onder
-   de vouw duwen -- dan begint elk bericht met een plaat waar je langs moet
-   scrollen om te zien wat het IS. */
-.feed-reader .read-cover {
-    /* Volle kolombreedte: de afbeelding erin neemt die breedte, dus de figure
-       hoeft niet meer om het beeld te krimpen. */
-    width: 100%;
-    margin: 0 0 1.2rem;
-    border-radius: 10px;
-    overflow: hidden;
-}
-.feed-reader .read-cover img,
-.feed-reader .read-cover video {
-    display: block;
-    /* Neemt de VOLLE kolombreedte, met de verhouding intact (object-fit
-       weggelaten, dus geen bijsnijden). Een cover die van zichzelf kleiner is
-       wordt netjes tot de kolom opgeschaald in plaats van als postzegeltje te
-       blijven staan -- dat was te klein. De hoogtegrens houdt een staande foto
-       nog binnen de perken zodat titel + eerste alinea boven de vouw blijven;
-       hij krimpt dan mee in plaats van bijgesneden te worden. */
-    display: block;
-    width: 100%;
-    height: auto;
-    max-height: 70svh;
-    object-fit: contain;
-    /* Een logo met doorzichtige achtergrond zweeft anders op de paginakleur;
-       dezelfde keuze als bij .post-list-cover in de tijdlijn. */
-    background-color: #fff;
-}
-
-.feed-reader .read-head { padding-bottom: .5rem; }
-.feed-reader .read-title { font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1.15; margin: 0 0 .3rem; }
-/* Het pin-icoon voor de titel: meeschalend met de kop, maar duidelijk kleiner --
-   het is een markering en geen deel van de titel. */
-.feed-reader .read-pin {
-    display: inline-block;
-    vertical-align: baseline;
-    width: .62em; height: .62em;
-    margin-right: .35em;
-    color: var(--ink-muted);
-}
-.feed-reader .read-pin svg { width: 100%; height: 100%; display: block; }
-/* De titel is een link, maar mag er niet als een link uitzien: dit is een
-   leesscherm, geen index. */
-.feed-reader .read-title a { color: inherit; text-decoration: none; }
-.feed-reader .read-title a:hover,
-.feed-reader .read-title a:focus-visible { text-decoration: underline; }
-.feed-reader .read-when { font-size: .85rem; opacity: .6; margin: 0; }
-
-.feed-reader .read-foot { margin-top: 2rem; }
-.feed-reader .read-open {
-    display: inline-block; font-size: .9rem; opacity: .75;
-    text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px;
-}
-.feed-reader .read-open:hover,
-.feed-reader .read-open:focus-visible { opacity: 1; }
-
-/* Terug naar boven. Rechtsonder, want daar zit de duim -- en boven de tabbalk,
-   die op mobiel 1050 is en anders overheen zou vallen. Onzichtbaar tot je ver
-   genoeg bent, zodat hij niet meteen in de weg staat bij het eerste bericht. */
-.read-top {
-    position: fixed;
-    right: max(1rem, env(safe-area-inset-right, 0));
-    bottom: calc(env(safe-area-inset-bottom, 0) + 4.75rem);
-    z-index: 1040;
-    display: grid;
-    place-items: center;
-    width: 44px;
-    height: 44px;                 /* 44px = de kleinste maat die een duim betrouwbaar raakt */
-    border-radius: 999px;
-    border: 1px solid var(--rule);
-    background: color-mix(in srgb, var(--paper) 88%, transparent);
-    backdrop-filter: blur(14px) saturate(140%);
-    -webkit-backdrop-filter: blur(14px) saturate(140%);
-    color: var(--ink);
-    box-shadow: 0 2px 12px color-mix(in srgb, var(--ink) 12%, transparent);
-    cursor: pointer;
-    opacity: 0;
-    pointer-events: none;
-    transition: opacity .18s ease, transform .18s ease;
-    transform: translateY(6px);
-}
-.read-top.is-zichtbaar { opacity: 1; pointer-events: auto; transform: none; }
-/* Buiten de leesweergave bestaat hij niet -- home.ejs rendert alle drie de
-   secties, dus zonder deze regel zweeft hij ook boven Tijdlijn en Grid. */
-body:not([data-feed-view="reader"]) .read-top,
-body:not(.on-home) .read-top { display: none; }
-/* Op desktop is er geen tabbalk, dus mag hij lager staan. */
-@media (min-width: 768px) {
-    .read-top { bottom: 1.5rem; right: 1.5rem; }
-}
-/* Staat de mini-speler onderin, dan wijkt de knop daarvoor -- anders komt hij er
-   bovenop te liggen (Robins schermafbeelding, 20-8). body.has-audio-player wordt
-   door audio-player.js gezet zodra de speler zichtbaar is, en weer weggehaald
-   als hij verdwijnt, dus dit volgt vanzelf.
-   Op mobiel staat de speler BOVEN de tabbalk gestapeld, dus daar komt zijn
-   hoogte bovenop de ruimte die er al gereserveerd was. */
-body.has-audio-player .read-top { bottom: calc(env(safe-area-inset-bottom, 0) + 4.75rem + 4.25rem); }
-@media (min-width: 768px) {
-    body.has-audio-player .read-top { bottom: calc(1.5rem + 4.25rem); }
-}
-@media (prefers-reduced-motion: reduce) {
-    .read-top { transition: none; transform: none; }
-}
-
-@media (prefers-reduced-motion: reduce) {
-    html:has(body.on-home[data-feed-view="reader"]) {
-        scroll-snap-type: none;
-        scroll-behavior: auto;
-    }
-}
+body.on-archive[data-feed-view="grid"] .feed-grid { display: block; }
 
 /* -------- GRID VIEW TILES (Instagram-stijl) -------- */
@@ -2829,45 +2106,4 @@
     -webkit-tap-highlight-color: rgba(0,0,0,.1);
 }
-
-/* Transparent covers (PNG logos etc.) sit on white so they don't blend into a dark
-   theme. The white is on the IMG, so the tile's accent-gradient placeholder shows
-   while the image is still loading. */
-.post-cover img,
-.post-list-cover img,
-.grid-tile-img { background-color: #fff; }
-/* Accent-gradient placeholder shown while the cover image loads (the image fades in
-   over it), instead of a white flash on cover tiles. */
-.grid-tile:not(.grid-tile-gradient) {
-    background-image: linear-gradient(135deg,
-        color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
-        color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
-}
-/* Cover as a real <img> (not background-image): browsers downsample <img> with the
-   high-quality image pipeline, so high-res line-art covers don't go jagged when shrunk.
-   Fades in on load (.is-loading removed) so the placeholder shows meanwhile. */
-.grid-tile-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; transition: opacity .4s ease; }
-.grid-tile-img.is-loading { opacity: 0; }
-/* Audio tile (Shaer, Robins vraag 30-7): the waveform PNG is white on
-   transparent and floats OVER the tile's own hue gradient, so every audio
-   post keeps its color and gets its shape. Wave and title each get their
-   own band (wave upper, title lower): centering both stacked them right
-   through each other (Robins schermafdruk). */
-.grid-tile-img.grid-tile-wave {
-    background-color: transparent;
-    object-fit: contain;
-    /* explicit box, not auto: an absolutely positioned img falls back to its
-       intrinsic size when width/height are auto, collapsing the band */
-    top: 8%; left: 8%; right: auto; bottom: auto;
-    width: 84%; height: 46%;
-    opacity: .85;
-}
-.grid-tile-audio .grid-tile-title { position: absolute; left: 10%; right: 10%; top: 60%; }
-.grid-tile-audio .grid-tile-gradient-src { position: absolute; left: 10%; right: 10%; top: 76%; }
-/* Cover videos are decorative, not players: let clicks + right-click pass through to the
-   tile link so you get the normal link menu (not the browser's <video> menu/controls).
-   Autoplay is independent of pointer-events, so the video still plays. */
-video.grid-tile-img,
-.post-list-cover video,
-.post-cover video { pointer-events: none; }
 .grid-tile:hover { transform: scale(0.98); }
 .grid-tile-overlay {
@@ -2876,7 +2112,5 @@
     padding: .6rem;
     display: flex;
-    flex-direction: column;
-    justify-content: flex-end;
-    align-items: flex-start;
+    align-items: flex-end;
     background: linear-gradient(to top, rgba(0,0,0,.65) 0%, rgba(0,0,0,0) 50%);
     opacity: 0;
@@ -2884,19 +2118,4 @@
     pointer-events: none; /* klik moet naar de <a> eronder gaan, niet naar de overlay */
 }
-/* Bron-site (cirkel-feed): toont bij hover "van <site>" onder de titel. */
-/* Source label: small text that wraps to 2 lines if needed, with a big chain icon
-   beside it (the text was 1.44rem — bigger than the title — and overflowed on mobile). */
-.grid-tile-overlay-src {
-    color: #fff; opacity: .85;
-    font-size: .72rem; line-height: 1.2; margin-top: .25rem;
-    display: flex; align-items: center; gap: .3rem; width: 100%;
-}
-.grid-tile-overlay-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
-.grid-tile-gradient-src {
-    margin-top: .35rem; font-size: .72rem; line-height: 1.2; opacity: .85;
-    color: var(--ink-soft);
-    display: flex; align-items: center; gap: .3rem; width: 100%;
-}
-.grid-tile-gradient-src::before { content: "⛓"; font-size: 1.3rem; line-height: 1; flex: 0 0 auto; }
 .grid-tile-overlay strong {
     color: #fff;
@@ -2923,5 +2142,4 @@
     background-image: linear-gradient(135deg, hsl(var(--tile-hue, 30), 45%, 88%), hsl(calc(var(--tile-hue, 30) + 30), 35%, 75%));
     display: flex;
-    flex-direction: column;
     align-items: center;
     justify-content: center;
@@ -2944,10 +2162,4 @@
     overflow: hidden;
     z-index: 1;
-    /* Federated link posts can have a long bare URL as their title — break it so it wraps
-       inside the tile and clamps cleanly instead of overflowing past both edges. */
-    max-width: 100%;
-    overflow-wrap: anywhere;
-    word-break: break-word;
-    hyphens: auto;
 }
 
@@ -2972,21 +2184,17 @@
     pointer-events: none;
 }
-.grid-tile-pin svg {
-    width: .95em;
-    height: .95em;
-    margin-top: -1px;
-}
-/* Pinned/boosted tile: accent ring. An outline on the tile is painted UNDER the absolute
-   cover <img>, so draw the ring as a pseudo-element overlay ABOVE the image (z-index above
-   the img, below the corner badges + nsfw veil). */
-.grid-tile.is-pinned { position: relative; z-index: 1; }
-.grid-tile.is-pinned::after {
-    content: '';
-    position: absolute;
-    inset: 0;
-    border: 3px solid var(--accent);
-    border-radius: inherit;
-    pointer-events: none;
+.grid-tile-pin::before {
+    content: "📌";
+    font-size: .9em;
+    line-height: 1;
+}
+/* Pinned-tile overall highlight: accent border + subtle inner glow */
+.grid-tile.is-pinned {
+    outline: 3px solid var(--accent);
+    outline-offset: -3px;
     z-index: 1;
+}
+.grid-tile.is-pinned:hover {
+    outline-offset: -2px;
 }
 .grid-tile-type {
@@ -3156,35 +2364,4 @@
 }
 
-/* Solo / Cirkel scope-switcher (alleen in circle-modus) — segmented toggle, centraal.
-   Hoge specificiteit (+ !important op tekst) zodat 'ie globale link-stijlen wint. */
-.view-switcher-wrap .feed-scope {
-    display: inline-flex;
-    background: var(--paper-2);
-    border: 1px solid var(--rule);
-    border-radius: 999px;
-    padding: 3px;
-}
-.view-switcher-wrap .feed-scope-btn {
-    display: inline-flex;
-    align-items: center;
-    padding: .32rem .95rem;
-    min-height: 30px;
-    border: none !important;
-    border-radius: 999px !important;
-    background: transparent !important;
-    color: var(--ink-muted) !important;
-    font-family: var(--font-ui);
-    font-size: .82rem;
-    font-weight: 500 !important;
-    text-decoration: none !important;
-    cursor: pointer;
-    transition: all .15s;
-}
-.view-switcher-wrap .feed-scope-btn:hover { color: var(--ink) !important; }
-.view-switcher-wrap .feed-scope-btn.is-active {
-    background: var(--ink) !important;
-    color: var(--paper) !important;
-}
-
 .grid-cols-picker {
     display: none; /* default hidden — desktop + grid-active maakt 'm zichtbaar */
@@ -3221,17 +2398,17 @@
 }
 
-/* Desktop + grid-view → toon cols-picker (op de home-feed; niet op archief) */
+/* Desktop + grid-view → toon cols-picker (op home + archive) */
 @media (min-width: 600px) {
-    body.on-home[data-feed-view="grid"] .grid-cols-picker {
+    body.on-home[data-feed-view="grid"] .grid-cols-picker,
+    body.on-archive[data-feed-view="grid"] .grid-cols-picker {
         display: inline-flex;
     }
 }
 
-/* Kolom-overrides op desktop. Mobiel negeert dit (staat vast op 2). Geldt op ELKE
-   feed met grid (home én cirkel/tag/type/user) — scope op .feed-grid .grid-tiles. */
+/* Kolom-overrides op desktop. Mobiel negeert dit (staat vast op 2). */
 @media (min-width: 600px) {
-    body[data-grid-cols="2"] .feed-grid .grid-tiles { grid-template-columns: repeat(2, 1fr); }
-    body[data-grid-cols="3"] .feed-grid .grid-tiles { grid-template-columns: repeat(3, 1fr); }
-    body[data-grid-cols="4"] .feed-grid .grid-tiles { grid-template-columns: repeat(4, 1fr); }
+    body.on-home[data-grid-cols="2"] .grid-tiles { grid-template-columns: repeat(2, 1fr); }
+    body.on-home[data-grid-cols="3"] .grid-tiles { grid-template-columns: repeat(3, 1fr); }
+    body.on-home[data-grid-cols="4"] .grid-tiles { grid-template-columns: repeat(4, 1fr); }
 }
 
@@ -3263,5 +2440,5 @@
 
 /* Masthead: compacter */
-.masthead { padding: calc(.55rem + var(--ios-safe-top, 0px)) 0 .55rem; }
+.masthead { padding: calc(.55rem + var(--safe-top)) 0 .55rem; }
 .masthead-inner { gap: 1rem; }
 .site-title { font-size: 1.25rem; }
@@ -3291,5 +2468,5 @@
 
 /* Site footer compacter */
-.site-footer { padding: 1.25rem 0 calc(1.25rem + env(safe-area-inset-bottom, 0px)); margin-top: 2rem; font-size: .78rem; }
+.site-footer { padding: 1.25rem 0 calc(1.25rem + var(--safe-bot)); margin-top: 2rem; font-size: .78rem; }
 .site-footer-inner { gap: .75rem; }
 
@@ -3301,6 +2478,5 @@
 .profile-bio { font-size: .85rem; margin-top: .15rem; }
 .profile-links { margin-top: .5rem; gap: .4rem; }
-.profile-links a,
-.profile-links .profile-fedi-link { width: 32px; height: 32px; }
+.profile-links a { width: 32px; height: 32px; }
 
 @media (min-width: 768px) {
@@ -3525,21 +2701,4 @@
     border-color: var(--accent, #c2410c);
     background: color-mix(in srgb, var(--accent, #c2410c) 5%, var(--paper-2, transparent));
-}
-/* Korte highlight wanneer je via de mini-speler naar deze track springt. */
-.post-audio-track.pat-flash,
-.post-album-track-compact.pat-flash {
-    animation: patFlash 1.6s ease-out;
-    border-radius: 8px;
-}
-/* Blijvende highlight op de track die NU actief is in de speler. */
-.post-audio-track.pat-playing,
-.post-album-track-compact.pat-playing {
-    background: color-mix(in srgb, var(--accent, #c2410c) 12%, var(--paper-2, transparent));
-    box-shadow: inset 3px 0 0 0 var(--accent, #c2410c);
-    border-radius: 8px;
-}
-@keyframes patFlash {
-    0%, 30% { border-color: var(--accent, #c2410c); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #c2410c) 35%, transparent); }
-    100% { box-shadow: 0 0 0 0 transparent; }
 }
 .post-audio-track .pat-play {
@@ -4983,278 +4142,2 @@
     }
 }
-
-/* === Fediverse interactions — inherits the native .comment styling === */
-.post-fediverse .fedi-stats { display: flex; gap: .45rem; margin: .35rem 0 1.5rem; align-items: center; }
-.post-fediverse .fedi-stat {
-  display: inline-flex; align-items: center; gap: .4rem;
-  padding: .32rem .7rem; border-radius: 999px; font-size: .85rem; line-height: 1;
-  font-variant-numeric: tabular-nums;
-  color: var(--ink-muted); background: transparent;
-  border: 1px solid var(--rule);
-}
-.post-fediverse .fedi-stat svg { width: 15px; height: 15px; }
-.post-fediverse .fedi-stat-btn { cursor: pointer; font: inherit; line-height: 1; transition: color .15s, border-color .15s, background .15s; }
-.post-fediverse .fedi-stat-btn:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--rule)); background: var(--accent-tint); }
-.post-fediverse .fedi-stat-btn:hover svg { fill: color-mix(in srgb, var(--accent) 22%, transparent); }
-.post-fediverse .fedi-handle { color: var(--ink-soft, #888); font-size: .82rem; }
-.post-fediverse .comment-content p { margin: .2rem 0; }
-.post-fediverse .comment-content p:first-child { margin-top: 0; }
-.post-fediverse .comment-content p:last-child { margin-bottom: 0; }
-/* reply toggle: a plain "Reageer" action like the comment buttons (no triangle) */
-.post-fediverse .fedi-reply-toggle { list-style: none; cursor: pointer; display: inline-block; }
-.post-fediverse .fedi-reply-toggle::-webkit-details-marker { display: none; }
-.post-fediverse details[open] .fedi-reply-toggle { margin-bottom: .5rem; }
-
-/* Reply-via-fediverse CTA on post pages */
-.post-fediverse-cta { margin: 1.75rem 0; }
-.fedi-remote-reply-btn { display: inline-flex; align-items: center; gap: .45rem; }
-.post-fediverse-cta .fedi-remote-reply-btn {
-  border: 1px solid color-mix(in srgb, var(--accent, #888) 55%, transparent);
-  background: color-mix(in srgb, var(--accent, #888) 10%, transparent);
-  color: var(--ink, inherit); border-radius: 999px; padding: .5rem 1.05rem;
-  font-weight: 600; cursor: pointer; transition: background .15s ease;
-}
-.post-fediverse-cta .fedi-remote-reply-btn:hover { background: color-mix(in srgb, var(--accent, #888) 22%, transparent); }
-.post-fediverse-cta .fedi-remote-reply-btn svg { color: var(--accent, currentColor); }
-.post-fediverse .comment-actions .fedi-remote-reply-btn { gap: .3rem; }
-
-/* Inline "reply via fediverse" address form (replaces the browser prompt) */
-.fedi-remote-form {
-  position: absolute; z-index: 60; display: inline-flex; align-items: center; gap: .4rem;
-  padding: .4rem; border-radius: 999px;
-  background: var(--paper-2, var(--paper, #fff));
-  border: 1px solid color-mix(in srgb, var(--ink, #000) 12%, transparent);
-  box-shadow: 0 10px 30px rgba(0,0,0,.28);
-}
-.fedi-remote-form input {
-  height: 2.2rem; padding: 0 .9rem; border-radius: 999px; font: inherit; min-width: 230px;
-  border: 1px solid color-mix(in srgb, var(--ink, #000) 18%, transparent);
-  background: color-mix(in srgb, var(--ink, #000) 4%, transparent); color: var(--ink, #000);
-}
-.fedi-remote-form input::placeholder { color: var(--ink-soft, #999); }
-.fedi-remote-form input:focus { outline: none; border-color: color-mix(in srgb, var(--accent, #888) 70%, transparent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #888) 22%, transparent); }
-.fedi-remote-form .fedi-remote-go {
-  height: 2.2rem; min-width: 2.2rem; padding: 0 .85rem; border-radius: 999px;
-  display: inline-flex; align-items: center; justify-content: center; font-size: 1rem;
-}
-.fedi-remote-form .fedi-remote-cancel { background: none; border: none; color: var(--ink-soft, #888); cursor: pointer; font-size: 1.1rem; line-height: 1; padding: .25rem .35rem; }
-.fedi-remote-form .fedi-remote-cancel:hover { color: var(--ink, #000); }
-
-/* ── NSFW / sensitive content — blur + click to reveal ───────────────── */
-.nsfw-media { position: relative; }
-.nsfw-veil {
-  position: absolute; inset: 0; z-index: 4; cursor: pointer; border-radius: inherit;
-  display: flex; flex-direction: column; align-items: center; justify-content: center;
-  gap: .5rem; padding: .75rem; text-align: center;
-  background: color-mix(in srgb, var(--paper, #14141a) 50%, transparent);
-  backdrop-filter: blur(22px) saturate(.6); -webkit-backdrop-filter: blur(22px) saturate(.6);
-}
-.nsfw-media.is-shown > .nsfw-veil { display: none; }
-.nsfw-veil-label { font-weight: 700; font-size: .82rem; color: var(--ink, #f3f1ea); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
-.nsfw-veil-btn {
-  font-size: .72rem; font-weight: 600; padding: .3rem .8rem; border-radius: 999px;
-  border: 1px solid color-mix(in srgb, var(--ink, #fff) 55%, transparent);
-  background: color-mix(in srgb, var(--paper, #000) 35%, transparent); color: var(--ink, #f3f1ea);
-}
-/* Post page: blur cover + body behind a content-warning banner until revealed */
-.nsfw-gate .post-cover,
-.nsfw-gate .post-content { filter: blur(26px); pointer-events: none; user-select: none; transition: filter .2s ease; }
-.nsfw-gate.is-shown .post-cover,
-.nsfw-gate.is-shown .post-content { filter: none; pointer-events: auto; user-select: auto; }
-.nsfw-banner {
-  display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin: 0 0 1.5rem;
-  padding: .8rem 1rem; border-radius: 12px;
-  border: 1px solid color-mix(in srgb, var(--accent, #e8b04b) 45%, transparent);
-  background: color-mix(in srgb, var(--accent, #e8b04b) 9%, transparent);
-}
-.nsfw-gate.is-shown .nsfw-banner { display: none; }
-.nsfw-banner-icon { font-size: 1.2rem; }
-.nsfw-banner-text { font-weight: 600; font-size: .92rem; color: var(--ink); }
-.nsfw-banner-btn {
-  margin-left: auto; cursor: pointer; font: inherit; font-size: .82rem; font-weight: 600;
-  padding: .4rem 1rem; border-radius: 999px; border: 0;
-  background: var(--accent, #e8b04b); color: #1a1205;
-}
-
-/* ── Het bandje (mixtape) ──────────────────────────────────────────────
-   Een cassette, getekend als SVG op de echte maat: 100,4 x 63,8 mm, dus een
-   viewBox van 314x200. De vorige versie tekende twee schijfjes met CSS; dit is
-   een replica -- behuizing, labelvlak, venster, twee spoelen met tandjes, de
-   schroefjes in de hoeken en de openingen voor de kop en de capstans onderin.
-
-   Alle kleuren komen uit de bestaande variabelen, dus licht, donker en het
-   accent van de site volgen vanzelf. */
-.post-tape {
-    position: relative;
-    border: 1px solid var(--rule, rgba(0,0,0,.1));
-    border-radius: 14px;
-    overflow: hidden;
-    margin: 1.25rem 0;
-    background: var(--paper-2, color-mix(in srgb, var(--ink) 3%, transparent));
-}
-
-.tape-shell { position: relative; padding: .8rem .8rem .3rem; }
-.tape-svg { display: block; width: 100%; height: auto; }
-
-/* De behuizing. Twee lagen zodat er een randje omheen zit, zoals bij een echt
-   doosje waar de bovenschaal iets uitsteekt. */
-.tape-body { fill: color-mix(in srgb, var(--ink) 82%, var(--paper, #fff)); }
-.tape-body-inner { fill: color-mix(in srgb, var(--ink) 70%, var(--paper, #fff)); }
-.tape-labelplate { fill: color-mix(in srgb, var(--paper, #fff) 92%, var(--accent)); }
-.tape-glass {
-    fill: color-mix(in srgb, var(--ink) 88%, transparent);
-    stroke: color-mix(in srgb, var(--paper, #fff) 25%, transparent);
-    stroke-width: 1.5;
-}
-.tape-pack { fill: color-mix(in srgb, var(--ink) 55%, var(--paper, #fff)); }
-.tape-ribbon { fill: color-mix(in srgb, var(--ink) 45%, var(--paper, #fff)); }
-.tape-hub { fill: var(--paper, #fff); }
-.tape-tooth { fill: color-mix(in srgb, var(--ink) 60%, var(--paper, #fff)); }
-.tape-screw { fill: color-mix(in srgb, var(--ink) 55%, var(--paper, #fff)); }
-.tape-slot { fill: color-mix(in srgb, var(--ink) 92%, transparent); }
-.tape-slot--capstan { fill: color-mix(in srgb, var(--ink) 96%, transparent); }
-
-/* Draaien. De tandjes zitten in dezelfde groep als de naaf, dus de hele spoel
-   draait als een geheel -- daar gaat het om, want aan die tandjes zie je pas
-   DAT hij draait. Het label blijft stil, anders wordt de titel onleesbaar. */
-.post-tape.is-playing .tape-reel { animation: tape-spin 3s linear infinite; }
-.post-tape.is-playing .tape-reel--right { animation-duration: 2.2s; }
-/* Spoelen: veel sneller, en achteruit ook echt achteruit. */
-.post-tape.is-winding .tape-reel { animation-duration: .45s; }
-.post-tape.is-winding-back .tape-reel { animation-direction: reverse; }
-@keyframes tape-spin { to { transform: rotate(360deg); } }
-@media (prefers-reduced-motion: reduce) {
-    .post-tape.is-playing .tape-reel,
-    .post-tape.is-winding .tape-reel { animation: none; }
-}
-
-/* De tekst staat OP het labelvlak van de cassette. Percentages volgen de
-   viewBox, dus het blijft kloppen op elke breedte. */
-.tape-label {
-    position: absolute;
-    left: 8.4%; right: 8.4%;
-    top: calc(.8rem + 11%);
-    height: 31%;
-    padding: .1rem .4rem;
-    color: color-mix(in srgb, var(--ink) 92%, transparent);
-    overflow: hidden;
-}
-.tape-kind {
-    margin: 0;
-    font-size: clamp(.55rem, 1.6vw, .68rem);
-    letter-spacing: .14em;
-    text-transform: uppercase;
-    opacity: .7;
-}
-.tape-title {
-    margin: 0;
-    font-size: clamp(.85rem, 2.6vw, 1.1rem);
-    line-height: 1.15;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-}
-.tape-artist { margin: 0; font-size: clamp(.65rem, 1.9vw, .8rem); opacity: .8; }
-.tape-meta { margin: 0; font-size: clamp(.6rem, 1.7vw, .72rem); opacity: .6; }
-
-/* De knoppen: terugspoelen, spelen, vooruitspoelen. Meer heeft een cassette
-   niet, en dat is de bedoeling -- er is geen zoekbalk omdat je op een bandje
-   niet kunt zoeken, alleen spoelen. */
-.tape-controls {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: .6rem;
-    padding: .5rem 0 .6rem;
-}
-.tape-btn {
-    display: grid;
-    place-items: center;
-    width: 40px; height: 40px;
-    border-radius: 50%;
-    border: 1px solid var(--rule, rgba(0,0,0,.15));
-    background: var(--paper, #fff);
-    color: var(--ink);
-    cursor: pointer;
-    padding: 0;
-    touch-action: manipulation;   /* vasthouden mag geen zoom of scroll worden */
-    user-select: none;
-}
-.tape-btn svg { width: 18px; height: 18px; }
-.tape-btn:hover { border-color: var(--accent); color: var(--accent); }
-.tape-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
-.tape-btn--play {
-    width: 52px; height: 52px;
-    background: var(--accent);
-    border-color: var(--accent);
-    color: var(--paper, #fff);
-}
-.tape-btn--play svg { width: 22px; height: 22px; }
-.post-tape.is-winding .tape-btn--back,
-.post-tape.is-winding .tape-btn--fwd { border-color: var(--accent); color: var(--accent); }
-
-.tape-now {
-    margin: 0;
-    padding: 0 .8rem .4rem;
-    text-align: center;
-    font-size: .8rem;
-    opacity: .8;
-    min-height: 1.2em;
-}
-
-/* De nummers staan er als INHOUD, niet als knoppen. Geen cursor, geen hover,
-   geen aanwijzing dat je erop kunt drukken: op een cassette kun je dat niet. */
-.tape-tracks {
-    margin: 0;
-    padding: 0 .8rem .8rem;
-    list-style: none;
-    counter-reset: tape;
-    display: grid;
-    gap: .1rem;
-}
-.tape-track {
-    counter-increment: tape;
-    display: flex;
-    gap: .5rem;
-    align-items: baseline;
-    font-size: .85rem;
-    padding: .18rem .3rem;
-    border-radius: 6px;
-    opacity: .75;
-}
-.tape-track::before {
-    content: counter(tape) ".";
-    opacity: .55;
-    min-width: 1.4em;
-    font-variant-numeric: tabular-nums;
-}
-.tape-track-title { flex: 1; }
-.tape-track-dur { opacity: .6; font-variant-numeric: tabular-nums; }
-.tape-track.is-current {
-    opacity: 1;
-    background: color-mix(in srgb, var(--accent) 12%, transparent);
-}
-
-
-/* ── De speler in bandmodus ────────────────────────────────────────────
-   Zelfde speler, ander gedrag: op een cassette kies je geen nummer. De lijst
-   blijft staan zodat je ziet wat erop staat, maar zonder de opmaak die belooft
-   dat je erin kunt prikken. */
-.audio-sheet-queue-list.is-tape .audio-sheet-queue-item {
-    cursor: default;
-    pointer-events: none;
-}
-.audio-sheet-queue-list.is-tape .audio-sheet-queue-item:hover {
-    background: none;
-}
-/* Het lopende nummer blijft wel gemarkeerd -- dat is de enige plek waar je op
-   een bandje leest waar je bent. */
-.audio-sheet-queue-list.is-tape .audio-sheet-queue-item.is-current {
-    opacity: 1;
-}
-/* Spoelknoppen mogen niet als "volgende" voelen: vasthouden hoort geen tekst te
-   selecteren of de pagina te laten zoomen. */
-.audio-btn.is-wind {
-    touch-action: manipulation;
-    user-select: none;
-}
