Root cause: onStreamProgress callback fires 20-50x/sec during LLM streaming,
each calling setLastExtractionStatus with syncRuntime=true (default), which
triggers setRuntimeStatus -> refreshPanelLiveState() -> _refreshDashboard().
_refreshDashboard iterates all graph nodes (.filter x2) and performs heavy
DOM updates each time. When the panel is open, this blocks the main thread.
Fixes:
1. panel.js: Add requestAnimationFrame throttle to refreshLiveState() with
minimum 80ms gap between actual DOM refreshes. Rapid calls are collapsed
into a single animation frame, preventing main thread saturation.
2. extraction-controller.js: Change onStreamProgress to use syncRuntime=false
so streaming updates no longer trigger setRuntimeStatus (which would also
update the floating ball on each chunk).
3. recall-controller.js: Same fix for recall onStreamProgress which had
the identical syncRuntime=true issue.