Co-Authored-By: Claude Opus 5.5 <[email protected]> # Conflicts: # docs/Architecture.md # docs/Decisions.md # docs/WorkBreakdown.md # server-py/sidecar.py # src/App.tsx # src/server/live.ts # src/server/transcribe.ts # tests/fixtures/fake_sidecar.py # tests/transcribe.test.ts
2.7 KiB
Design
Derived from the shipped src/index.css (single stylesheet, plain CSS, no framework). Describes what
exists, not an aspiration. Update in the same commit as visual changes.
Foundations
- Theme: dark by default, light when the OS prefers it (
@media (prefers-color-scheme: light)overrides the tokens; no in-app toggle).<meta name="theme-color">has a variant per scheme. The PWA manifest and icons stay dark (#16181d). - Tokens (
:root, dark → light):--bg #16181d → #f5f6f8·--fg #e8e8e8 → #1a1d23·--muted #9aa3b2 → #5b6372·--panel #1f232b → #ffffff·--border #343a46 → #d3d8e0·--surface-raised(inputs, code) ·--surface-selected(selected/drag-active) ·--accent #7aa2f7 → #2f5bd3+--on-accent·--success/-bg/-border·--danger/-muted/-bg/-border+--on-danger·--live(recording) ·--shadow. No raw colours outside the token block — add a token (with both values) instead. - Contrast: every text/background token pair is ≥ 4.5:1 in both themes (checked when the light theme landed, D-037). Re-check any new pair.
- Type: Inter Variable, self-hosted (
@fontsource-variable/inter, 7 unicode-range subsets served from/fonts/, precached; seescripts/fonts.ts, D-037). Body line-height 1.5;h12.2rem / 1.15. - Layout: single centred column,
.app { max-width: 720px; padding: 2.5rem 1.25rem 3rem; gap: 1.5rem },body { min-width: 320px }. - Radius: 8px for controls (most common); 10–14px for panels/cards; 999px for pills/badges.
- Motion:
0.15scolour/border transitions;pulse(live dot) andblink(cursor) animations, disabled underprefers-reduced-motion. - Browser surfaces:
accent-colorand::selectioncome from--accent.
Components
One BEM-ish class block per React component in src/components/ (.model-picker, .dropzone,
.live-controls, .engine-toggle, .auth-panel, .update-toast, .vocabulary-hint, …), with modifier classes like
-selected, -active, -disabled. Interactive states use :hover:enabled and :focus-visible.
.visually-hidden exists for screen-reader-only text.
Card headers (.transcript-header: title + export/Copy buttons) wrap, so on a phone the buttons
move under the title instead of overflowing the card.
Secondary disclosures (.storage-manager, .translate-panel) share one look: a 12px-radius
--panel card with a semibold <summary>, muted 0.85rem hints, outlined 8px buttons. Inside the
translate panel the one action (.translate-button) is the only accent-outlined button and fills
with --accent / --on-accent on hover; a translation renders as a second .transcript card below
it rather than a card nested inside the panel.