···88## [Unreleased]
991010### Added
1111+- 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)
1212+- 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)
1113- 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)
1214- Shared export/import toast helper (`src/lib/export-feedback.ts`): `exportSuccess`/`exportError`/`importSuccess`/`importError` centralize user-facing copy with built-in noun pluralization and Error-message extraction, so every editor's export path surfaces the same phrasing ("Exported 12 rows as CSV", "CSV export failed: bad quote") instead of each editor re-implementing feedback. 12 unit tests pinning the contract. (#686)
1315- Slides: JSON deck export — the previously dead "Export" button in slides now downloads the full deck state (slides, theme, transitions, animations) as a `.deck.json` file. Enables backup/clone-a-deck workflows until native PPTX/PDF export lands. (#686)
14161517### Changed
1818+- Dark-mode contrast: bumped `--color-text-faint` lightness from `oklch(0.50 …)` (≈3:1 contrast on dark bg) to `oklch(0.62 …)` (≈4.5:1, meeting WCAG AA for normal text) in both the explicit `[data-theme="dark"]` block and the `@media (prefers-color-scheme: dark)` fallback. Affects every timestamp, helper hint, and secondary label (70+ call sites in app.css use this var). (#690)
1619- Wired the shared export-feedback helper into silent-failing export paths across every editor: diagrams (SVG, PNG, ASCII with correct `.shapes.size` Map accessor), forms (CSV/XLSX response exports), sheets (CSV, TSV, XLSX, PDF), docs (HTML, Markdown, TXT, PDF, DOCX). Every export now either confirms success with a row/slide/document count or surfaces the real error via toast instead of failing silently. (#686)
1720- Promoted save-indicator + save-status-ui from sheets-only modules (`src/sheets/save-*.ts`) to shared library modules (`src/lib/save-*.ts`). Docs, slides, forms, diagrams, and calendar now share a single `wireSaveStatus({ provider, ydoc })` helper with consistent "Saved / Saving… / Saved locally / Unsaved changes" feedback — previously only sheets and docs had live autosave state, and docs carried a 50-line inline copy. Slides, forms, diagrams, and calendar HTML upgraded from an empty `<span class="save-status">` to the full indicator DOM (dot + text). Docs main.ts replaces its inline implementation with a one-line call. 8 new jsdom tests pin the wiring contract (saving→saved transitions, dot class flips, offline "Saved locally" fallback, ydoc-origin echo filtering). (#689)
1821