Index: src/views/partials/bottom-tab.ejs
===================================================================
--- src/views/partials/bottom-tab.ejs	(revision 2165b6d3d57ceaa8b5d1f70491868482149470cf)
+++ src/views/partials/bottom-tab.ejs	(revision 7bc636b391c66ac399c33e54f7173a022c6a3cbd)
@@ -4,14 +4,14 @@
 // Tabs:
 //   logged-out:  Home · Zoek · Inloggen        (3 tabs)
-//   logged-in:   Home · Zoek · [Plus] · Profiel
+//   logged-in:   Home · Zoek · [Plus] · [Prutter] · Profiel
 //   The Plus tab is a FAB-style center action (accent bg, slightly raised).
 //   It only appears for users with create-post permission.
+//   Prutter only appears when the site has DMs enabled.
 
 const _siteUrlBase = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '';
 const _path        = (typeof currentPath !== 'undefined' && currentPath) ? currentPath : '/';
-const _canPost     = !!(user && (typeof canMutate === 'undefined' || canMutate)
-                        && permissions && permissions.canCreatePost && permissions.canCreatePost(user, site));
+const _canPost     = !!(user && permissions && permissions.canCreatePost && permissions.canCreatePost(user, site));
+const _hasPrutter  = !!(user && site && site.enable_prutter);
 const _ownProfile  = user ? ('/users/' + user.username) : null;
-const _homeHref    = _siteUrlBase + '/';
 
 // Strip site prefix for cleaner matching
@@ -26,4 +26,5 @@
 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';
@@ -33,11 +34,8 @@
 
   <!-- Home -->
-  <%# htmx navigation (no full reload): the persistent audio player in document.body
-      survives, so music does not skip when navigating. On mobile the top bar is hidden
-      anyway, so a context reset via full-load is not needed here. %>
   <a class="bottom-tab-item<%= _active === 'home' ? ' is-active' : '' %>"
-     href="<%= _homeHref %>"
-     hx-get="<%= _homeHref %>?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
-     hx-push-url="<%= _homeHref %>" hx-indicator="#pcms-loading"
+     href="<%= _siteUrlBase %>/"
+     hx-get="<%= _siteUrlBase %>/?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
+     hx-push-url="<%= _siteUrlBase %>/" hx-indicator="#pcms-loading"
      aria-label="Home" <%= _active === 'home' ? '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">
@@ -45,15 +43,15 @@
       <polyline points="9 22 9 12 15 12 15 22"/>
     </svg>
-    <span class="bottom-tab-label"><%= t('tab.home') %></span>
+    <span class="bottom-tab-label">Home</span>
   </a>
 
   <!-- Zoek -->
   <button type="button" class="bottom-tab-item<%= _active === 'search' ? ' is-active' : '' %>"
-          id="bottom-tab-search-toggle" aria-label="<%= t('nav.search') %>">
+          id="bottom-tab-search-toggle" aria-label="Zoeken">
     <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">
       <circle cx="11" cy="11" r="7"/>
       <line x1="21" y1="21" x2="16.65" y2="16.65"/>
     </svg>
-    <span class="bottom-tab-label"><%= t('tab.search') %></span>
+    <span class="bottom-tab-label">Zoek</span>
   </button>
 
@@ -61,7 +59,7 @@
   <% if (_canPost) { %>
     <a class="bottom-tab-item bottom-tab-fab<%= _active === 'create' ? ' is-active' : '' %>"
-       href="<%= _siteUrlBase %>/posts/new"
-       hx-get="<%= _siteUrlBase %>/posts/new?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
-       hx-push-url="<%= _siteUrlBase %>/posts/new" hx-indicator="#pcms-loading"
+       href="/posts/new"
+       hx-get="/posts/new?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
+       hx-push-url="/posts/new" hx-indicator="#pcms-loading"
        aria-label="Nieuwe post">
       <svg class="bottom-tab-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
@@ -69,8 +67,22 @@
         <line x1="5" y1="12" x2="19" y2="12"/>
       </svg>
-      <span class="bottom-tab-label"><%= t('tab.write') %></span>
+      <span class="bottom-tab-label">Schrijven</span>
     </a>
   <% } %>
 
+  <!-- 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 -->
@@ -81,18 +93,13 @@
             aria-label="Profiel menu" aria-haspopup="dialog">
       <% if (user.avatar_url) { %>
-        <img class="bottom-tab-avatar bottom-tab-avatar-img" src="<%= avatar(user.avatar_url, 128) %>" alt="">
+        <img class="bottom-tab-avatar bottom-tab-avatar-img" src="<%= user.avatar_url %>" alt="">
       <% } else { %>
         <span class="bottom-tab-avatar"><%= user.username.charAt(0).toUpperCase() %></span>
       <% } %>
-      <span class="bottom-tab-label"><%= t('tab.profile') %></span>
-      <% if (typeof notifUnread !== 'undefined' && notifUnread > 0) { %>
-        <span class="bottom-tab-badge" aria-label="<%= notifUnread %> ongelezen meldingen"><%= notifUnread > 99 ? '99+' : notifUnread %></span>
-      <% } %>
+      <span class="bottom-tab-label">Profiel</span>
     </button>
   <% } else { %>
     <a class="bottom-tab-item<%= _active === 'login' ? ' is-active' : '' %>"
        href="/auth/login"
-       hx-get="/auth/login?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
-       hx-push-url="/auth/login" hx-indicator="#pcms-loading"
        aria-label="Inloggen">
       <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">
@@ -101,5 +108,5 @@
         <line x1="15" y1="12" x2="3" y2="12"/>
       </svg>
-      <span class="bottom-tab-label"><%= t('nav.login') %></span>
+      <span class="bottom-tab-label">Inloggen</span>
     </a>
   <% } %>
@@ -302,5 +309,16 @@
 </style>
 
-<%# De zoekknop zit nu in de chrome-module (assets/js/mod/chrome.js).
-    Inline script hier wordt door de CSP geweigerd zodra deze partial via htmx
-    binnenkomt, en dat is bij elke navigatie -- zie shaer-0i6. %>
+<script>
+// Wire the bottom-tab search button into the existing #search-overlay
+(function() {
+  const btn = document.getElementById('bottom-tab-search-toggle');
+  const overlay = document.getElementById('search-overlay');
+  if (btn && overlay) {
+    btn.addEventListener('click', function() {
+      overlay.hidden = false;
+      const inp = overlay.querySelector('input');
+      if (inp) inp.focus();
+    });
+  }
+})();
+</script>
