Index: src/views/pages/admin-site-edit.ejs
===================================================================
--- src/views/pages/admin-site-edit.ejs	(revision 24cdcc61abea38cc9e4d1996d3736d1c14c5d142)
+++ src/views/pages/admin-site-edit.ejs	(revision 8f2f97ce2ca4540506ee22910e99a093826a9555)
@@ -163,11 +163,4 @@
         <span><%= t('asite.enable_audio') %></span>
       </label>
-      <%# Prutter is een Hub-only premium-functie — toggle alleen tonen in Hub-modus. %>
-      <% if (typeof tenancy !== 'undefined' && tenancy === 'hub') { %>
-      <label class="cb">
-        <input type="checkbox" name="enable_prutter" value="1" <%= site.enable_prutter ? 'checked' : '' %>>
-        <span><%= t('asite.enable_prutter') %> <small class="form-hint-inline"><%= t('asite.enable_prutter_hint') %></small></span>
-      </label>
-      <% } %>
     </fieldset>
 
Index: src/views/pages/prutter-conversation.ejs
===================================================================
--- src/views/pages/prutter-conversation.ejs	(revision 24cdcc61abea38cc9e4d1996d3736d1c14c5d142)
+++ 	(revision )
@@ -1,257 +1,0 @@
-<div class="prutter-conv-page" data-conversation-id="<%= conversation.id %>" data-me="<%= user.id %>">
-  <header class="prutter-conv-header">
-    <a class="prutter-back" href="<%= siteUrlBase %>/prutter" aria-label="<%= t('prcv.back_aria') %>" title="<%= t('prcv.inbox') %>">
-      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
-    </a>
-    <div class="prutter-conv-avatar">
-      <% if (other && other.avatar_url) { %>
-        <img src="<%= other.avatar_url %>" alt="">
-      <% } else { %>
-        <span><%= (other && other.username || '?').charAt(0).toUpperCase() %></span>
-      <% } %>
-    </div>
-    <div class="prutter-conv-id">
-      <span class="prutter-conv-name"><%= other ? other.username : t('prcv.unknown') %></span>
-      <% if (other) { %>
-        <a class="prutter-conv-sub" href="/users/<%= encodeURIComponent(other.username) %>"><%= t('prcv.view_profile') %></a>
-      <% } %>
-    </div>
-  </header>
-
-  <ol class="prutter-thread" id="prutter-thread">
-    <% messages.forEach(function(m) { %>
-      <li class="prutter-msg <%= m.author_id === user.id ? 'prutter-msg--mine' : 'prutter-msg--theirs' %>" data-msg-id="<%= m.id %>">
-        <div class="prutter-msg-bubble"><%= m.content %></div>
-        <div class="prutter-msg-time" title="<%= m.created_at %>"><%= formatDateTime(m.created_at) %></div>
-      </li>
-    <% }); %>
-  </ol>
-
-  <form class="prutter-composer" id="prutter-composer"
-        method="post"
-        action="<%= siteUrlBase %>/prutter/<%= conversation.id %>/send"
-        hx-post="<%= siteUrlBase %>/prutter/<%= conversation.id %>/send"
-        hx-target="#prutter-thread"
-        hx-swap="beforeend">
-    <textarea name="content" rows="1" maxlength="2000" placeholder="<%= t('prcv.placeholder') %>" required></textarea>
-    <button type="submit" class="btn btn-primary"><%= t('prcv.send') %></button>
-  </form>
-</div>
-
-<script>
-(function() {
-  // Auto-scroll to bottom on load and after appends.
-  var thread = document.getElementById('prutter-thread');
-  function scrollToBottom() { thread.scrollTop = thread.scrollHeight; }
-  scrollToBottom();
-  window.__prutterScroll = scrollToBottom;
-
-  // Live updates via WebSocket.
-  // Browser auto-resolves protocol/host; same origin as the page.
-  try {
-    var page = document.querySelector('.prutter-conv-page');
-    var convId = page.dataset.conversationId;
-    var me = page.dataset.me;
-    var proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
-    var ws = new WebSocket(proto + '//' + location.host + '/ws/prutter');
-
-    ws.addEventListener('message', function(ev) {
-      try {
-        var data = JSON.parse(ev.data);
-        if (data.type !== 'new_message' || data.conversationId !== convId) return;
-        var m = data.message;
-        // Don't double-render our own messages (already added via HTMX response)
-        if (m.author_id === me) return;
-
-        var li = document.createElement('li');
-        li.className = 'prutter-msg prutter-msg--theirs';
-        li.dataset.msgId = m.id;
-        var bubble = document.createElement('div');
-        bubble.className = 'prutter-msg-bubble';
-        bubble.textContent = m.content;  // text content = automatic escaping
-        var time = document.createElement('div');
-        time.className = 'prutter-msg-time';
-        time.textContent = new Date(m.created_at).toLocaleString();
-        li.appendChild(bubble);
-        li.appendChild(time);
-        thread.appendChild(li);
-        scrollToBottom();
-      } catch (e) { /* ignore malformed */ }
-    });
-  } catch (e) {
-    console.warn('Prutter WS unavailable:', e);
-  }
-
-  // ── Composer: invoer-gedrag + auto-groei + wissen na versturen ──────────
-  var form = document.getElementById('prutter-composer');
-  var ta = form ? form.querySelector('textarea') : null;
-  if (form && ta) {
-    var MAXH = function () { return Math.round(window.innerHeight * 0.4); };
-    function autoGrow() {
-      ta.style.height = 'auto';
-      ta.style.height = Math.min(ta.scrollHeight, MAXH()) + 'px';
-    }
-    function isTouch() {
-      return window.matchMedia && window.matchMedia('(pointer: coarse)').matches;
-    }
-    function submit() {
-      if (!ta.value.trim()) return;
-      if (form.requestSubmit) form.requestSubmit();
-      else form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
-    }
-
-    ta.addEventListener('input', autoGrow);
-    ta.addEventListener('keydown', function (e) {
-      if (e.key !== 'Enter' || e.isComposing) return;   // IME-invoer met rust laten
-      // Touch (mobiel/tablet): Enter = nieuwe regel, versturen via de Stuur-knop.
-      if (isTouch()) return;
-      // Desktop: Shift+Enter = nieuwe regel, gewone Enter = versturen.
-      if (e.shiftKey) return;
-      e.preventDefault();
-      submit();
-    });
-
-    // Wissen + terug naar één regel ná een geslaagde verzending.
-    form.addEventListener('htmx:afterRequest', function (e) {
-      if (e.detail && e.detail.successful) {
-        ta.value = '';
-        autoGrow();
-        scrollToBottom();
-        ta.focus();
-      }
-    });
-
-    autoGrow();
-  }
-})();
-</script>
-
-<style>
-/* De chat is position:fixed (los uit de flow) → de site-footer (met copyright,
-   versie én de "Installeer app"-knop) schemerde erdoorheen in het lege
-   berichtgebied. In de chat hoort die footer niet thuis: verbergen. */
-body:has(.prutter-conv-page) .site-footer { display: none; }
-
-/* ── Full-height chat-layout (mobile-first) ──────────────────────────────
-   De pagina is FIXED gepind tussen de topnav (desktop) en de onderste balken
-   (bottom-tab + audiospeler), zodat ALLEEN de thread scrollt — niet de hele
-   pagina. De offsets volgen de body-classes has-bottom-tab/has-audio-player,
-   dus de composer valt nooit achter een balk. */
-.prutter-conv-page {
-  position: fixed;
-  left: 0; right: 0;
-  top: 0;                 /* mobiel: masthead is verborgen → vanaf de top */
-  bottom: 0;
-  max-width: 760px; margin: 0 auto;
-  display: flex; flex-direction: column;
-  padding: 0.5rem 0.75rem;
-  z-index: 1;
-}
-/* Desktop: de sticky masthead staat erboven → begin eronder. */
-@media (min-width: 768px) {
-  .prutter-conv-page { top: 64px; padding: 0.75rem 1rem; }
-}
-/* Onderste vrije ruimte = de balken die de viewport-bodem overlappen. */
-@media (max-width: 767px) {
-  body.has-bottom-tab .prutter-conv-page { bottom: calc(56px + env(safe-area-inset-bottom, 0)); }
-}
-body.has-audio-player .prutter-conv-page { bottom: calc(76px + env(safe-area-inset-bottom, 0)); }
-@media (max-width: 767px) {
-  body.has-bottom-tab.has-audio-player .prutter-conv-page { bottom: calc(56px + 76px + env(safe-area-inset-bottom, 0)); }
-}
-
-/* Compacte chat-kop: terug-pijl + avatar + naam op één regel. */
-.prutter-conv-header {
-  flex: 0 0 auto;
-  display: flex; align-items: center; gap: 0.65rem;
-  padding-bottom: 0.6rem; margin-bottom: 0.5rem;
-  border-bottom: 1px solid var(--rule);
-}
-.prutter-back {
-  flex: 0 0 auto;
-  display: inline-flex; align-items: center; justify-content: center;
-  width: 40px; height: 40px; border-radius: 8px;
-  color: var(--ink); text-decoration: none;
-}
-.prutter-back:hover { color: var(--accent); background: var(--paper-2); }
-.prutter-back svg { width: 20px; height: 20px; }
-.prutter-conv-avatar {
-  flex: 0 0 auto;
-  width: 40px; height: 40px; border-radius: 50%;
-  overflow: hidden; background: var(--paper-2);
-  display: inline-flex; align-items: center; justify-content: center;
-  color: var(--accent); font-weight: 700;
-}
-.prutter-conv-avatar img { width: 100%; height: 100%; object-fit: cover; }
-.prutter-conv-id { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
-.prutter-conv-name {
-  font-family: var(--font-display, serif); font-size: 1.15rem; color: var(--ink);
-  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
-}
-.prutter-conv-sub { font-size: 0.78rem; color: var(--ink-muted, var(--ink-soft)); text-decoration: none; }
-.prutter-conv-sub:hover { color: var(--accent); }
-
-/* De ENIGE scroller. min-height:0 is cruciaal in een flex-kolom, anders
-   groeit de lijst i.p.v. te scrollen. */
-.prutter-thread {
-  flex: 1 1 auto; min-height: 0;
-  list-style: none; margin: 0;
-  display: flex; flex-direction: column; gap: 0.4rem;
-  padding: 0.25rem 0.1rem 0.5rem;
-  overflow-y: auto; overscroll-behavior: contain;
-  -webkit-overflow-scrolling: touch;
-}
-
-.prutter-msg { display: flex; flex-direction: column; max-width: 82%; }
-.prutter-msg-bubble {
-  padding: 0.55rem 0.85rem;
-  border-radius: 14px;
-  white-space: pre-wrap;
-  word-wrap: break-word;
-  line-height: 1.4;
-  font-size: 0.95rem;
-}
-.prutter-msg-time {
-  font-size: 0.7rem;
-  color: var(--ink-muted, var(--ink-soft));
-  margin-top: 0.15rem;
-}
-
-.prutter-msg--theirs { align-self: flex-start; }
-.prutter-msg--theirs .prutter-msg-bubble {
-  background: var(--paper);
-  border: 1px solid var(--rule);
-  border-bottom-left-radius: 4px;
-}
-.prutter-msg--theirs .prutter-msg-time { padding-left: 0.5rem; }
-
-.prutter-msg--mine { align-self: flex-end; align-items: flex-end; }
-.prutter-msg--mine .prutter-msg-bubble {
-  background: var(--accent);
-  color: white;
-  border-bottom-right-radius: 4px;
-}
-.prutter-msg--mine .prutter-msg-time { padding-right: 0.5rem; }
-
-.prutter-composer {
-  flex: 0 0 auto;
-  display: flex; gap: 0.5rem; align-items: flex-end;
-  padding-top: 0.6rem; margin-top: 0.25rem;
-  border-top: 1px solid var(--rule);
-}
-.prutter-composer textarea {
-  flex: 1;
-  padding: 0.65rem 0.85rem;
-  border: 1px solid var(--rule);
-  border-radius: 12px;
-  background: var(--paper);
-  color: var(--ink);
-  font-family: inherit;
-  font-size: 1rem;            /* ≥16px → iOS zoomt niet in bij focus */
-  line-height: 1.35;
-  resize: none;
-  min-height: 44px; max-height: 40vh;
-  overflow-y: auto;   /* scrollt intern zodra de auto-groei de max raakt */
-}
-.prutter-composer .btn { flex: 0 0 auto; min-height: 44px; }
-</style>
Index: src/views/pages/prutter-inbox.ejs
===================================================================
--- src/views/pages/prutter-inbox.ejs	(revision 24cdcc61abea38cc9e4d1996d3736d1c14c5d142)
+++ 	(revision )
@@ -1,111 +1,0 @@
-<div class="container prutter-inbox-page">
-  <header class="prutter-header">
-    <h1>Prutter</h1>
-    <p class="prutter-tagline"><%= t('prin.tagline') %></p>
-  </header>
-
-  <% if (!conversations.length) { %>
-    <p class="prutter-empty">
-      <%= t('prin.empty') %>
-    </p>
-  <% } else { %>
-    <ol class="prutter-conv-list">
-      <% conversations.forEach(function(c) { %>
-        <li class="prutter-conv-row">
-          <a class="prutter-conv-link" href="<%= siteUrlBase %>/prutter/<%= c.id %>">
-            <div class="prutter-conv-avatar">
-              <% if (c.other_avatar) { %>
-                <img src="<%= c.other_avatar %>" alt="">
-              <% } else { %>
-                <span><%= (c.other_username || '?').charAt(0).toUpperCase() %></span>
-              <% } %>
-            </div>
-            <div class="prutter-conv-body">
-              <div class="prutter-conv-meta">
-                <strong class="prutter-conv-name"><%= c.other_username %></strong>
-                <% if (c.last_message_at) { %>
-                  <span class="prutter-conv-time"><%= formatDateTime(c.last_message_at) %></span>
-                <% } %>
-              </div>
-              <% if (c.last_message_preview) { %>
-                <div class="prutter-conv-preview"><%= c.last_message_preview %></div>
-              <% } else { %>
-                <div class="prutter-conv-preview muted"><%= t('prin.empty_conv') %></div>
-              <% } %>
-            </div>
-            <% if (c.unread_count > 0) { %>
-              <span class="prutter-unread-badge"><%= c.unread_count %></span>
-            <% } %>
-          </a>
-        </li>
-      <% }); %>
-    </ol>
-  <% } %>
-</div>
-
-<style>
-/* Geen site-footer in Prutter (ook niet op de inbox) — net als de chat. */
-body:has(.prutter-inbox-page) .site-footer { display: none; }
-
-.prutter-inbox-page { max-width: 720px; margin: 3rem auto; padding: 0 1rem; }
-.prutter-header h1 {
-  font-family: var(--font-display, serif);
-  font-size: 2rem; margin: 0 0 0.25rem;
-}
-.prutter-tagline { color: var(--ink-muted, var(--ink-soft)); margin: 0 0 1.5rem; }
-.prutter-empty {
-  text-align: center; padding: 2rem; color: var(--ink-muted, var(--ink-soft));
-  background: var(--paper-2); border: 1px dashed var(--rule); border-radius: 8px;
-}
-
-.prutter-conv-list { list-style: none; padding: 0; margin: 0; }
-.prutter-conv-row { border-bottom: 1px solid var(--rule); }
-.prutter-conv-row:last-child { border-bottom: 0; }
-.prutter-conv-link {
-  display: flex; gap: 0.85rem; align-items: center;
-  padding: 0.85rem 0;
-  text-decoration: none; color: var(--ink);
-  transition: background 100ms;
-}
-.prutter-conv-link:hover { background: var(--paper-2); }
-
-.prutter-conv-avatar {
-  flex-shrink: 0;
-  width: 44px; height: 44px;
-  border-radius: 50%;
-  overflow: hidden;
-  background: var(--paper-2);
-  border: 1px solid var(--rule);
-  display: inline-flex; align-items: center; justify-content: center;
-}
-.prutter-conv-avatar img { width: 100%; height: 100%; object-fit: cover; }
-.prutter-conv-avatar span {
-  font-family: var(--font-display, serif);
-  font-weight: 700; color: var(--accent);
-}
-
-.prutter-conv-body { flex: 1; min-width: 0; }
-.prutter-conv-meta {
-  display: flex; justify-content: space-between; gap: 0.5rem;
-  margin-bottom: 0.15rem;
-}
-.prutter-conv-name { font-weight: 600; }
-.prutter-conv-time {
-  color: var(--ink-muted, var(--ink-soft));
-  font-size: 0.8rem; flex-shrink: 0;
-}
-.prutter-conv-preview {
-  color: var(--ink-soft);
-  font-size: 0.9rem;
-  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
-}
-.prutter-conv-preview.muted { font-style: italic; color: var(--ink-muted, var(--ink-soft)); }
-
-.prutter-unread-badge {
-  background: var(--accent); color: white;
-  border-radius: 10px;
-  padding: 0.1rem 0.5rem;
-  font-size: 0.75rem;
-  font-weight: 600;
-}
-</style>
Index: src/views/pages/user.ejs
===================================================================
--- src/views/pages/user.ejs	(revision 24cdcc61abea38cc9e4d1996d3736d1c14c5d142)
+++ src/views/pages/user.ejs	(revision 8f2f97ce2ca4540506ee22910e99a093826a9555)
@@ -27,9 +27,4 @@
         <% } %>
       </p>
-      <% if (user && user.id !== author.id && site && site.enable_prutter && (typeof tenancy !== 'undefined' && tenancy === 'hub') && (typeof premiumUnlocked === 'undefined' || premiumUnlocked)) { %>
-        <p class="user-actions">
-          <a href="<%= siteUrlBase %>/prutter/new?to=<%= encodeURIComponent(author.username) %>" class="btn btn-primary">💬 <%= t('pusr.send_dm') %></a>
-        </p>
-      <% } %>
     </div>
   </header>
Index: src/views/partials/bottom-tab.ejs
===================================================================
--- src/views/partials/bottom-tab.ejs	(revision 24cdcc61abea38cc9e4d1996d3736d1c14c5d142)
+++ src/views/partials/bottom-tab.ejs	(revision 8f2f97ce2ca4540506ee22910e99a093826a9555)
@@ -13,5 +13,4 @@
 const _canPost     = !!(user && (typeof canMutate === 'undefined' || canMutate)
                         && permissions && permissions.canCreatePost && permissions.canCreatePost(user, site));
-const _hasPrutter  = !!(user && site && site.enable_prutter && (typeof tenancy !== 'undefined' && tenancy === 'hub') && (typeof premiumUnlocked === 'undefined' || premiumUnlocked));
 const _ownProfile  = user ? ('/users/' + user.username) : null;
 const _isHub       = (typeof tenancy !== 'undefined' && tenancy === 'hub');
@@ -32,5 +31,4 @@
 else if (_p.indexOf('/search') === 0 || _p.indexOf('/tag/') === 0 || _p.indexOf('/type/') === 0) _active = 'search';
 else if (_p === '/posts/new' || /^\/posts\/[^/]+\/edit$/.test(_p)) _active = 'create';
-else if (_p.indexOf('/prutter') === 0) _active = 'prutter';
 else if (_p.indexOf('/account') === 0 || (_ownProfile && _p.indexOf(_ownProfile) === 0)) _active = 'profile';
 else if (_p.indexOf('/auth/login') === 0) _active = 'login';
@@ -80,18 +78,4 @@
   <% } %>
 
-  <!-- Prutter (DMs) -->
-  <% if (_hasPrutter) { %>
-    <a class="bottom-tab-item<%= _active === 'prutter' ? ' is-active' : '' %>"
-       href="<%= _siteUrlBase %>/prutter"
-       aria-label="Prutter berichten" <%= _active === 'prutter' ? 'aria-current="page"' : '' %>>
-      <svg class="bottom-tab-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-        <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
-      </svg>
-      <span class="bottom-tab-label">Prutter</span>
-      <% if (typeof unreadDmCount !== 'undefined' && unreadDmCount > 0) { %>
-        <span class="bottom-tab-badge" aria-label="<%= unreadDmCount %> ongelezen"><%= unreadDmCount > 99 ? '99+' : unreadDmCount %></span>
-      <% } %>
-    </a>
-  <% } %>
 
   <!-- Profiel / Inloggen -->
Index: src/views/partials/topnav.ejs
===================================================================
--- src/views/partials/topnav.ejs	(revision 24cdcc61abea38cc9e4d1996d3736d1c14c5d142)
+++ src/views/partials/topnav.ejs	(revision 8f2f97ce2ca4540506ee22910e99a093826a9555)
@@ -15,5 +15,4 @@
 const _isAdmin     = typeof bodyClass !== 'undefined' && bodyClass.indexOf('on-admin') >= 0;
 const _hasSearch   = !site || site.show_search === undefined || site.show_search;
-const _hasPrutter  = user && site && site.enable_prutter && (typeof tenancy !== 'undefined' && tenancy === 'hub') && (typeof premiumUnlocked === 'undefined' || premiumUnlocked);
 const _canPost     = user && (typeof canMutate === 'undefined' || canMutate)
                      && permissions && permissions.canCreatePost && permissions.canCreatePost(user, site);
@@ -98,10 +97,4 @@
           </div>
         </details>
-      <% } %>
-
-      <% if (_hasPrutter) { %>
-        <a class="nav-btn" href="<%= _siteUrlBase %>/prutter" aria-label="Prutter (DMs)" title="Prutter">
-          <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
-        </a>
       <% } %>
 
Index: src/views/shell.ejs
===================================================================
--- src/views/shell.ejs	(revision 24cdcc61abea38cc9e4d1996d3736d1c14c5d142)
+++ src/views/shell.ejs	(revision 8f2f97ce2ca4540506ee22910e99a093826a9555)
@@ -33,5 +33,5 @@
 // Listing pages (search/tag/type/archive) shouldn't be indexed (dupe content)
 if (currentPath) {
-  if (/^\/(?:search|tag|type|archive|users|prutter|account|admin)(?:$|\/)/.test(currentPath)) {
+  if (/^\/(?:search|tag|type|archive|users|account|admin)(?:$|\/)/.test(currentPath)) {
     _shouldIndex = false;
   }
