diff --git a/zebra-report/zebra-spaces.html b/zebra-report/zebra-spaces.html
index 1c0e4af..6739acb 100644
--- a/zebra-report/zebra-spaces.html
+++ b/zebra-report/zebra-spaces.html
@@ -1625,6 +1625,16 @@ function renderIdentity(){
if (el) el.textContent = myKeys ? myKeys.pubHex : '';
}
+/* Transcribe-state declarations live up here (not next to the Whisper
+ * code further down) so the click-handler binding + restore block
+ * just below CAN read transcribeEnabled without tripping a TDZ
+ * error. Model is cached after first download so subsequent loads
+ * spin the worker up fast. Fox 2026-06-05: "transcribe states
+ * should be saved in localstorage to survive on refresh." */
+const TRANSCRIBE_KEY = 'zspc:transcribe-on';
+let transcribeEnabled = false;
+try { if (localStorage.getItem(TRANSCRIBE_KEY) === '1') transcribeEnabled = true; } catch(_){}
+
$('btn-vault').addEventListener('click', () => $('vault-panel').classList.toggle('hidden'));
$('btn-transcribe').addEventListener('click', () => toggleTranscribe().catch(e => logLine('err','transcribe toggle: '+e.message)));
/* If transcribe was on at the previous session, restore the state
@@ -2217,13 +2227,9 @@ function transcribeViaWorker(chunk){
});
}
-/* Transcribe state persists in localStorage so refresh restores the
- * user's preference. Model is cached after first download so subsequent
- * loads spin the worker up fast. Fox 2026-06-05: "transcribe states
- * should be saved in localstorage to survive on refresh." */
-const TRANSCRIBE_KEY = 'zspc:transcribe-on';
-let transcribeEnabled = false;
-try { if (localStorage.getItem(TRANSCRIBE_KEY) === '1') transcribeEnabled = true; } catch(_){}
+/* (transcribeEnabled + TRANSCRIBE_KEY are declared earlier near the
+ * top of the script so the restore-from-localStorage block at the
+ * button-binding site doesn't trip a TDZ error.) */
/* whisper-tiny.en hallucinations on silence / low-energy chunks. The
* RMS gate in the capture worklet catches dead silence; this set
* catches what gets past it — quiet-room ambient with the same
@@ -2336,7 +2342,8 @@ async function handleWhisperChunk(uuid, chunk){
* the user's handle. */
let _selfCapture = null;
async function startSelfCapture(){
- if (_selfCapture || !micStream) return;
+ if (_selfCapture){ logLine('', 'whisper: self capture already running'); return; }
+ if (!micStream){ logLine('', 'whisper: self capture skip (no micStream yet)'); return; }
/* audioCtx may not exist yet for a host alone in the room (no
* remote speakers have triggered attachAudioStreamViaWorklet). Make
* sure it's up before we try to attach a worklet to it. Resume it
@@ -2350,7 +2357,7 @@ async function startSelfCapture(){
try { audioCtx.resume(); } catch(_){}
}
const ok = await loadWhisperCaptureWorklet(audioCtx);
- if (!ok) return;
+ if (!ok){ logLine('err','self capture: worklet module load failed'); return; }
try {
const src = audioCtx.createMediaStreamSource(micStream);
const cap = new AudioWorkletNode(audioCtx, 'whisper-capture');
@@ -7413,8 +7420,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');