Generate web slides from Comark

fix: defensive recovery for cross-tab edge cases master

Two related bugs from background/focus state during the cross-tab dance: 1. Mermaid renders silently fail in a newly-spawned presenter tab when the tab opens in the background or with reduced rAF priority — SVG never lands in the DOM. Add a visibilitychange + window.focus listener in mermaid.eta that retries any pre.mermaid still missing its <svg> child. 2. Audience scroll-back to slide 1 on presenter close. Root cause: smooth scroll animations in the audience tab fire intersection observer events as slides cross the viewport, and we processed those events even when the audience tab wasn't the user's focus — feeding a stream of navigate.scroll events that marched currentIndex through intermediate values. If the smooth scroll was interrupted at the start (scrollTop never moved), the last IO event reported slide-1, resetting state to the top of the deck. Two-part fix: gate fireUpdates on document.hasFocus() so IO only feeds state when the user is actually scrolling here, and add a visibilitychange/focus handler that resyncs scroll position to match xstate's currentIndex when the audience tab returns to view. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>


+58 -11
2 changed files