diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html
index f057f04..7bf089e 100644
--- a/web/zebra-spaces.html
+++ b/web/zebra-spaces.html
@@ -5283,6 +5283,25 @@ $('btn-copy-share').addEventListener('click', async () => {
return;
}
$('rdv-code').value = saved;
+ /* Auto-rejoin without a user gesture works on desktop (browsers
+ * grant audio engagement after first interaction with the origin)
+ * but breaks mobile listener audio: Firefox Android requires the
+ * silent-oscillator wake in primeAudioOnGesture to actually start
+ * the AudioContext render thread, and primeAudioOnGesture only
+ * runs inside the btn-enter click handler. Auto-rejoin that
+ * bypasses the click → audioCtx stays suspended → MediaStream-
+ * Source attaches silently → no audio.
+ *
+ * UA-gated: desktop preserves the zero-click rejoin convenience;
+ * mobile pre-fills the code + asks for one tap on enter so the
+ * gesture window opens and audio actually plays. Fox 2026-06-04
+ * chose this trade after the AudioContext-suspended telemetry. */
+ const isMobile = /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);
+ if (isMobile){
+ logLine('', 'last space: '+saved+' — click enter to resume (mobile needs gesture for audio)');
+ setStatus('click enter to resume — '+saved, 'warn');
+ return;
+ }
logLine('', 'auto-rejoining last space …');
setTimeout(() => { joinSpace().catch(e => logLine('err', 'auto-rejoin failed: ' + e.message)); }, 100);
})();
@@ -5356,8 +5375,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');