Add design spec for dark cockpit-style visual redesign
Documents the color/type/layout token system and the next-sync countdown evolution agreed on with the user, ahead of implementation planning. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
157
docs/superpowers/specs/2026-08-16-visual-redesign-design.md
Normal file
157
docs/superpowers/specs/2026-08-16-visual-redesign-design.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# Visual Redesign — "Ride Computer" Dark Theme — Design
|
||||
|
||||
Date: 2026-08-16
|
||||
Status: Draft for user review
|
||||
|
||||
## 1. Goal
|
||||
|
||||
Replace the current light, generic admin-template look with a distinctive dark
|
||||
"bike computer cockpit" theme grounded in the app's own subject matter (indoor
|
||||
cycling sync, Garmin telemetry). The redesign is a shared foundation: it must
|
||||
land before the planned dashboard summary tiles and live-update UX polish, so
|
||||
those can be built directly in the new visual language instead of needing a
|
||||
second pass.
|
||||
|
||||
This spec covers only the visual system and the already-shipped next-sync
|
||||
indicator's evolution into a live countdown. It does not add new pages, new
|
||||
data, or new business logic.
|
||||
|
||||
## 2. Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- New CSS design-token system (color, spacing reuse, borders) replacing the
|
||||
current light theme in `app/web/static/style.css`.
|
||||
- Cockpit-style topbar (dark, brand mark, nav, live sync countdown).
|
||||
- Restyled shared components: cards, buttons, badges, tables, forms, empty
|
||||
states — applied globally via shared CSS classes so every existing template
|
||||
(login, account-login, dashboard, account detail/edit, users
|
||||
detail/new/edit, system, sync result fragment) picks it up without
|
||||
structural rewrites.
|
||||
- Typographic treatment: uppercase tracked labels for headings/section labels
|
||||
(extends the existing table-header pattern), tabular monospace numerals for
|
||||
all stats/timestamps/counters.
|
||||
- Evolving the existing static next-sync timestamp (`app/web/static/app.js`,
|
||||
`base.html`) into a live, client-ticking countdown.
|
||||
- Accessible focus states (visible lime outline) and `prefers-reduced-motion`
|
||||
handling for the one animated element (the countdown) and card entrance.
|
||||
|
||||
### Out of scope (separate follow-up specs)
|
||||
|
||||
- Dashboard summary/stat tiles (next phase, builds on this theme).
|
||||
- Live sync results without full page reload (UX-polish phase).
|
||||
- Any light-mode / theme-toggle support (explicitly rejected by user — dark
|
||||
only).
|
||||
- New charts/statistics views.
|
||||
- Any change to routes, models, or sync/business logic.
|
||||
|
||||
## 3. Design tokens
|
||||
|
||||
### Color
|
||||
|
||||
| Token | Hex | Usage |
|
||||
|---|---|---|
|
||||
| `--bg` | `#12151A` | Page background |
|
||||
| `--surface` | `#1A1F27` | Cards, topbar, table zebra-free rows |
|
||||
| `--surface-raised` | `#232935` | Hover states, inputs |
|
||||
| `--border` | `#2A3038` | Hairline dividers/card borders |
|
||||
| `--text` | `#E7EAF0` | Primary text |
|
||||
| `--text-muted` | `#8B93A3` | Secondary text, labels, hints |
|
||||
| `--accent` | `#C8FF4D` | Electric lime — signature countdown, primary buttons, focus rings, "healthy" status |
|
||||
|
||||
Semantic status colors (each with a ~14% opacity tint of the same hue over
|
||||
`--surface` for badge backgrounds, matching the existing `--*-bg` variable
|
||||
pattern already in `style.css`):
|
||||
|
||||
| State | Hex | Meaning |
|
||||
|---|---|---|
|
||||
| Success / healthy | `--accent` `#C8FF4D` | Reuses the signature accent — a healthy sync *is* the good state the accent celebrates |
|
||||
| Warning / degraded | `#FFB454` | Amber |
|
||||
| Danger / action required / failed | `#FF5F6D` | Coral |
|
||||
| Info / syncing / running | `#5FD4FF` | Cyan |
|
||||
| Neutral / disabled | `#5A6472` | Slate |
|
||||
|
||||
These map 1:1 onto the existing `--success`, `--warning`, `--danger`,
|
||||
`--info`, `--neutral` variable names already used by `.badge-*` classes in
|
||||
`style.css` — only their values change, not the class structure, so templates
|
||||
need no edits for badges.
|
||||
|
||||
### Typography
|
||||
|
||||
- Body/UI face: unchanged system stack (`-apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, Helvetica, Arial, sans-serif`) — no new font loads,
|
||||
works offline in a self-hosted container.
|
||||
- Monospace face for all numeric data (stats, timestamps, the countdown,
|
||||
table numeric columns): `ui-monospace, SFMono-Regular, Menlo, Consolas,
|
||||
"Liberation Mono", monospace`, with `font-variant-numeric: tabular-nums`.
|
||||
- Headings and structural labels (`h1`/`h2`, `.badge`, table `th`, the new
|
||||
topbar labels): uppercase, `letter-spacing: 0.06em`, extending the tracked
|
||||
uppercase style `table th` already has today — applied consistently instead
|
||||
of only in tables.
|
||||
|
||||
### Layout
|
||||
|
||||
- Topbar becomes the cockpit header: `--surface` background, hairline bottom
|
||||
border, brand mark left, nav + live countdown grouped right (existing
|
||||
`.topbar-right` wrapper from the next-sync work is reused).
|
||||
- Cards: hairline `--border` outline, `--surface` background, no drop shadow
|
||||
(shadows read poorly on dark; hairlines carry the "device bezel" feel
|
||||
instead). Radius stays at the existing `--radius: 10px`, unchanged.
|
||||
- Buttons: primary uses `--accent` background with dark text (for contrast
|
||||
against the light lime); secondary keeps outline/ghost style against
|
||||
`--surface`.
|
||||
- Focus-visible: 2px `--accent` outline on all interactive elements (links,
|
||||
buttons, inputs) — dark backgrounds need this to stay accessible since the
|
||||
current subtle browser default focus ring is hard to see on `--surface`.
|
||||
|
||||
### Motion
|
||||
|
||||
- The live countdown ticks once per second (text content update only, no
|
||||
layout shift).
|
||||
- Cards fade/slide in ~150ms on initial page load, `translateY(4px) → 0`.
|
||||
- Both respect `prefers-reduced-motion: reduce` (countdown text still updates,
|
||||
since it's informational, not decorative; the card entrance animation is
|
||||
skipped entirely).
|
||||
|
||||
## 4. Signature element: live sync countdown
|
||||
|
||||
`app/web/static/app.js` currently does a one-time UTC→local conversion of the
|
||||
`time[data-utc]` element on `DOMContentLoaded`. It's extended to:
|
||||
|
||||
1. On load, read `data-utc` as the target instant.
|
||||
2. If the target is in the future, start a `setInterval` (1s) that computes
|
||||
the remaining duration and renders it as `HH:MM:SS` (or `MM:SS` under an
|
||||
hour) in monospace, e.g. `NEXT SYNC ▸ 00:12:04`.
|
||||
3. If the target is in the past (page left open past the sync time, or
|
||||
`next_tick` not yet known on first boot), render `due now` instead of a
|
||||
negative countdown.
|
||||
4. The `title` attribute keeps showing the absolute local time (via
|
||||
`toLocaleString()`) and the original UTC instant, so hovering still gives
|
||||
an absolute reference — this preserves today's behavior as a fallback/aid.
|
||||
5. `data-utc` stays the templating contract between server and client (same
|
||||
attribute the current tests assert on), so no server-side route or test
|
||||
changes are needed for this evolution — only `app.js` behavior and the
|
||||
surrounding CSS/markup in `base.html` change.
|
||||
|
||||
No server-side change: `next_sync_tick()` in `app/web/routes.py` and the
|
||||
`base.html` template variable wiring stay as they are; only the visual
|
||||
presentation and `app.js` ticking logic change.
|
||||
|
||||
## 5. Testing
|
||||
|
||||
This is a CSS/JS-presentation change with one markup adjustment (countdown
|
||||
wrapper element/label in `base.html`). Existing server-rendered tests assert
|
||||
on `data-utc="..."` substrings and text content, not on CSS classes or exact
|
||||
visual output, so no test breakage is expected. No new automated test is
|
||||
meaningful for pure CSS token values; the existing
|
||||
`tests/web/test_next_sync_display.py` continues to guard the server-side
|
||||
contract (the attribute and value), and manual verification (screenshot) is
|
||||
used to confirm the visual outcome, consistent with how the next-sync feature
|
||||
was verified.
|
||||
|
||||
## 6. Rollout
|
||||
|
||||
Single pass across `style.css`, `base.html`, `app.js`. No template
|
||||
restructuring needed beyond `base.html`'s topbar, since all other templates
|
||||
already consume the shared `.card`, `.badge`, `button`/`.btn`, `table`, and
|
||||
`form.stacked-form` classes this spec restyles centrally.
|
||||
Reference in New Issue
Block a user