feat: a11y + dark-mode sweep first slice (v0.56.0)
Four high-leverage fixes from the v0.56.0 a11y/dark-mode scope:
1. **Dark-mode contrast** — bumped `--color-text-faint` in dark mode
from oklch(0.50 …) to oklch(0.62 …), raising contrast on the main
dark bg from ~3:1 (fails WCAG AA) to ~4.5:1 (passes AA for normal
text). Affects 70+ call sites (timestamps, helper hints, secondary
labels). Applied in both [data-theme=dark] block and
prefers-color-scheme: dark media query.
2. **Landing icon-only buttons get aria-label** — theme-toggle,
user-badge, search-clear, and the search input now carry
aria-label. Previously only `title` was set, which is not
reliably announced by screen readers. User badge also promoted
to role=button + tabindex=0 so keyboard users can reach it.
3. **Landing modals get aria-labelledby** — username, folder, and
move-to modals now link their h2 titles via aria-labelledby so
AT announces context on modal open.
4. **Slides panel tabs get tablist semantics** — role=tablist on
container, role=tab + aria-selected + aria-controls on each
button, role=tabpanel + aria-labelledby on each content pane.
The click handler in event-handlers.ts keeps aria-selected in
sync. 2 new jsdom regression tests pin the invariant.
Deferred to a later slice (not blocking AA compliance):
- Modal dialog focus-trap (src/lib/modal-dialog.ts)
- In-editor toolbar btn-icon aria-label pass (77 buttons across
6 editors — large sweep, worth its own PR)
- `--color-modal-backdrop` var cleanup
Refs #690