···88## [Unreleased]
991010### Added
1111+- A11y: modal focus trap — `modalPrompt`/`modalConfirm` now wrap Tab/Shift+Tab within the dialog so keyboard users cannot tab out to background elements while a modal is open. A new exported `handleFocusTrap(event, dialog)` helper wraps focus between first/last focusable children and pulls focus back into the dialog if it escapes (e.g. user tabs to a background link). 8 new jsdom tests pin the contract (Tab wrap, Shift+Tab wrap, escape recovery, mid-tab no-op, non-Tab no-op, integration with modalPrompt + modalConfirm). Closes the last major keyboard-accessibility gap in the shared modal helper. (#690)
1112- A11y: landing-page icon-only buttons (theme toggle, user badge, search clear) now carry `aria-label` so screen readers can announce them — previously only `title` was set, which is unreliable for AT. The user badge also gets `role="button"` + `tabindex="0"` so keyboard users can reach it. Landing modals (username, folder, move) now declare `aria-labelledby` pointing at their title heading so modal opens announce context. (#690)
1213- A11y: slides Notes/Animations panel tabs now carry the full tablist semantics — `role="tablist"` on the container, `role="tab"` + `aria-selected` + `aria-controls` on each button, and `role="tabpanel"` + `aria-labelledby` on each content pane. The click handler keeps `aria-selected` in sync when tabs switch. 2 new jsdom regression tests pin the invariant. (#690)
1314- Slides mobile panel toggle: on phones (<=480px) the slides thumbnail panel was previously hidden with `display:none` and no way to bring it back, making slide navigation impossible. A new `btn-toggle-slide-panel` in the slides topbar now flips a `.slides-panel--mobile-open` class that renders the panel as a full-height overlay so users can jump to any slide. Tapping a thumbnail or hitting Escape closes the overlay. (#688)