Index: src/assets/js/mod/read.js
===================================================================
--- src/assets/js/mod/read.js	(revision 87696ce368ae084de890aa4e682f4294c7825feb)
+++ src/assets/js/mod/read.js	(revision 847775cc74de6b701650a36b640f758fba5f214b)
@@ -166,4 +166,35 @@
 }
 
+/**
+ * Tikken op een bericht opent dat bericht.
+ *
+ * De stroom toont de tekst; het gesprek -- reacties, waarderingen, boosts --
+ * staat op de berichtpagina. De titel en de voetlink zijn echte <a>'s en doen
+ * het werk voor toetsenbord en schermlezer; dit hier is het gemak voor een duim.
+ *
+ * Daarom vier uitzonderingen, want een tik die je niet bedoelde is erger dan
+ * geen tik: iets dat zelf al een doel heeft (link, knop, veld) houdt zijn eigen
+ * werking, een geselecteerde tekst is geen tik, een verschoven vinger is
+ * scrollen, en cmd/ctrl-klik hoort de browser zelf af te handelen.
+ */
+let tapX = 0, tapY = 0;
+function onPointerDown(e) { tapX = e.clientX; tapY = e.clientY; }
+
+function onTap(e) {
+  if (e.defaultPrevented || e.button !== 0) return;
+  if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
+  const t = e.target;
+  if (!t || typeof t.closest !== 'function') return;
+  const art = t.closest('.read-post');
+  if (!art) return;
+  if (t.closest('a, button, input, textarea, select, label, summary, [role="button"]')) return;
+  if (Math.abs(e.clientX - tapX) > 10 || Math.abs(e.clientY - tapY) > 10) return;
+  const sel = window.getSelection && window.getSelection();
+  if (sel && String(sel).trim()) return;
+  const slug = art.dataset.slug;
+  if (!slug) return;
+  location.href = (art.dataset.base || '') + '/' + encodeURIComponent(slug);
+}
+
 function onScroll() {
   const y = window.scrollY || 0;
@@ -183,4 +214,7 @@
   window.addEventListener('scroll', onScroll, { passive: true });
   window.addEventListener('resize', watch, { passive: true });
+  // Op de stroom, niet per artikel: aangevulde berichten doen zo vanzelf mee.
+  s.addEventListener('pointerdown', onPointerDown, { passive: true });
+  s.addEventListener('click', onTap);
   watch();
 }
Index: src/services/i18n.js
===================================================================
--- src/services/i18n.js	(revision 87696ce368ae084de890aa4e682f4294c7825feb)
+++ src/services/i18n.js	(revision 847775cc74de6b701650a36b640f758fba5f214b)
@@ -891,5 +891,5 @@
     'fgate.title': 'Alleen voor vrienden',
     'fgate.sub': 'Dit is exclusief voor ingelogde vrienden. Log in om het te bekijken.',
-    'fgate.login': 'Inloggen / aanmelden', 'read.end': 'Je bent bij het begin van het archief.', 'read.load_error': 'Kon het volgende bericht niet laden.',
+    'fgate.login': 'Inloggen / aanmelden', 'read.open': 'Reacties en waarderingen', 'read.end': 'Je bent bij het begin van het archief.', 'read.load_error': 'Kon het volgende bericht niet laden.',
     'lbio.empty': 'Nog geen links ingesteld.',
     'lbio.back_to_site': 'naar de site',
@@ -1897,5 +1897,5 @@
     'fgate.title': 'Friends only',
     'fgate.sub': 'This is exclusive to logged-in friends. Log in to view it.',
-    'fgate.login': 'Log in / sign up', 'read.end': 'You have reached the beginning of the archive.', 'read.load_error': 'Could not load the next post.',
+    'fgate.login': 'Log in / sign up', 'read.open': 'Replies and reactions', 'read.end': 'You have reached the beginning of the archive.', 'read.load_error': 'Could not load the next post.',
     'lbio.empty': 'No links set up yet.',
     'lbio.back_to_site': 'back to the site',
@@ -2903,5 +2903,5 @@
     'fgate.title': 'Nur für Freunde',
     'fgate.sub': 'Dies ist exklusiv für eingeloggte Freunde. Melde dich an, um es anzusehen.',
-    'fgate.login': 'Anmelden / Registrieren', 'read.end': 'Du bist am Anfang des Archivs angekommen.', 'read.load_error': 'Der nächste Beitrag konnte nicht geladen werden.',
+    'fgate.login': 'Anmelden / Registrieren', 'read.open': 'Antworten und Reaktionen', 'read.end': 'Du bist am Anfang des Archivs angekommen.', 'read.load_error': 'Der nächste Beitrag konnte nicht geladen werden.',
     'lbio.empty': 'Noch keine Links eingerichtet.',
     'lbio.back_to_site': 'zurück zur Seite',
Index: src/views/pages/read.ejs
===================================================================
--- src/views/pages/read.ejs	(revision 87696ce368ae084de890aa4e682f4294c7825feb)
+++ src/views/pages/read.ejs	(revision 847775cc74de6b701650a36b640f758fba5f214b)
@@ -80,4 +80,18 @@
 .on-read .read-post + .read-post { border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent); }
 
+/* De titel is een link, maar mag er niet als een link uitzien: dit is een
+   leesscherm, geen index. Onderstrepen pas als je hem aanwijst. */
+.on-read .read-title a { color: inherit; text-decoration: none; }
+.on-read .read-title a:hover,
+.on-read .read-title a:focus-visible { text-decoration: underline; }
+
+/* De aankondiging onderaan: waar de tik je heen brengt. */
+.on-read .read-foot { margin-top: 2rem; }
+.on-read .read-open {
+  display: inline-block; font-size: .9rem; opacity: .75;
+  text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px;
+}
+.on-read .read-open:hover, .on-read .read-open:focus-visible { opacity: 1; }
+
 .on-read .read-head { padding-bottom: .5rem; }
 .on-read .read-title { font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1.15; margin: 0 0 .3rem; }
Index: src/views/partials/read-article.ejs
===================================================================
--- src/views/partials/read-article.ejs	(revision 87696ce368ae084de890aa4e682f4294c7825feb)
+++ src/views/partials/read-article.ejs	(revision 847775cc74de6b701650a36b640f758fba5f214b)
@@ -20,6 +20,11 @@
          data-title="<%= post.title || '' %>"
          aria-label="<%= post.title || '' %>">
+  <%# De titel is een echte link naar het bericht zelf. De leesstroom toont de
+      TEKST, maar reacties, waarderingen en boosts staan op de berichtpagina --
+      en een stroom waar je niet uit kunt naar het gesprek is een doodlopende weg.
+      Een <a> en niet alleen een tik-afhandelaar: dat werkt ook met een
+      toetsenbord, met een schermlezer, en met cmd-klik. %>
   <header class="read-head">
-    <h1 class="read-title"><%= post.title || '' %></h1>
+    <h1 class="read-title"><a href="<%= _b %>/<%= post.slug %>"><%= post.title || '' %></a></h1>
     <% if (post.published_at) { %><p class="read-when"><%= formatDateTime(post.published_at) %></p><% } %>
   </header>
@@ -29,3 +34,9 @@
         content_html: entry.content_html, _base: _b,
       }) %>
+
+  <%# Zegt waar je heen gaat, in plaats van te vertrouwen op een tik die niemand
+      ziet. De tik-afhandelaar in mod/read.js is het gemak; dit is de aankondiging. %>
+  <footer class="read-foot">
+    <a class="read-open" href="<%= _b %>/<%= post.slug %>"><%= t('read.open') %> &rarr;</a>
+  </footer>
 </article>
Index: src/views/shell.ejs
===================================================================
--- src/views/shell.ejs	(revision 87696ce368ae084de890aa4e682f4294c7825feb)
+++ src/views/shell.ejs	(revision 847775cc74de6b701650a36b640f758fba5f214b)
@@ -503,5 +503,5 @@
   // Eén nummer voor de hele map. Te vaak bumpen kost één download; te weinig
   // bumpen kost een bugfix die nooit aankomt.
-  var MOD_V = 1;
+  var MOD_V = 2;
 
   // name -> 1 (aan het laden) of de module-namespace (geladen). Een module
