Index: src/assets/css/audio.css
===================================================================
--- src/assets/css/audio.css	(revision cf968904813964dcf21535fb8ca69f33e5e31f57)
+++ src/assets/css/audio.css	(revision 76e9cfd1b3959f1e140695d2cc641616781861c4)
@@ -111,4 +111,18 @@
   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 {
Index: src/assets/js/audio-player.js
===================================================================
--- src/assets/js/audio-player.js	(revision cf968904813964dcf21535fb8ca69f33e5e31f57)
+++ src/assets/js/audio-player.js	(revision 76e9cfd1b3959f1e140695d2cc641616781861c4)
@@ -189,5 +189,10 @@
     }
     console.log('[pcms-audio] loading', t.title, t.url);
+    // Schone overgang: pause + reset voorkomt state-corruption van het
+    // audio-element na meerdere src-changes (bug die continuous playback
+    // brak na 3-4 tracks). audio.load() forceert reset van internal state.
+    try { audio.pause(); } catch (e) {}
     audio.src = t.url;
+    try { audio.load(); } catch (e) {}
     titleEl.textContent  = t.title  || 'Untitled';
     artistEl.textContent = t.artist || '';
@@ -214,5 +219,15 @@
     const p = audio.play();
     if (p && typeof p.catch === 'function') {
-      p.catch((err) => console.warn('[pcms-audio] play() rejected', err));
+      p.catch((err) => {
+        console.warn('[pcms-audio] play() rejected:', err.name, err.message);
+        // Browser-autoplay-policy heeft 't gestopt (typisch na 3-4
+        // automatische plays op iOS Safari, of als tab tijdelijk inactive
+        // was). Visuele hint dat user op play moet tappen.
+        if (err && err.name === 'NotAllowedError') {
+          root.classList.add('audio-needs-tap');
+          isPlaying = false;
+          root.classList.remove('is-playing');
+        }
+      });
     }
   }
@@ -268,5 +283,13 @@
   // 5. Audio element events → UI sync
   // ============================================================
-  audio.addEventListener('play',  () => { isPlaying = true;  root.classList.add('is-playing'); });
+  // Error-counter voorkomt infinite-loop als ALLE tracks broken zijn.
+  let consecutiveErrors = 0;
+
+  audio.addEventListener('play',  () => {
+    isPlaying = true;
+    consecutiveErrors = 0;  // reset bij succesvolle play
+    root.classList.add('is-playing');
+    root.classList.remove('audio-needs-tap');  // verstop tap-hint
+  });
   audio.addEventListener('pause', () => { isPlaying = false; root.classList.remove('is-playing'); });
   audio.addEventListener('ended', next);
@@ -274,6 +297,13 @@
     const code = audio.error ? audio.error.code : '?';
     console.error('[pcms-audio] playback error', code, audio.src, e);
+    consecutiveErrors++;
+    // Bij netwerk/decode-fout: skip naar volgende track ipv stilstaan.
+    // Max 3 fouten op rij voordat we opgeven (anders infinite loop).
+    if (consecutiveErrors < 3 && queue.length > 1) {
+      console.warn('[pcms-audio] auto-skip naar volgende na error', consecutiveErrors);
+      setTimeout(next, 400);
+    }
   });
-  audio.addEventListener('stalled', () => console.warn('[pcms-audio] stalled'));
+  audio.addEventListener('stalled', () => console.warn('[pcms-audio] stalled at', audio.currentTime));
   audio.addEventListener('volumechange', () => { root.classList.toggle('is-muted', audio.muted || audio.volume === 0); });
   audio.addEventListener('timeupdate', () => {
Index: src/views/shell.ejs
===================================================================
--- src/views/shell.ejs	(revision cf968904813964dcf21535fb8ca69f33e5e31f57)
+++ src/views/shell.ejs	(revision 76e9cfd1b3959f1e140695d2cc641616781861c4)
@@ -277,5 +277,5 @@
      ?v=N — cache-buster: bump bij elke audio-player.js wijziging zodat
      Cloudflare (max-age=1y) niet de oude versie blijft serveren. -->
-<script src="/assets/js/audio-player.js?v=2"></script>
+<script src="/assets/js/audio-player.js?v=3"></script>
 <% if (site && site.enable_audio_player && audioTracks && audioTracks.length > 0) { %>
   <script>window.PCMS_SITE_TRACKS = <%- JSON.stringify(audioTracks) %>;</script>
