From 5d75aa328d265623d4381ffcde575257a6e9aab7 Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Sun, 16 Aug 2026 10:48:43 +0200 Subject: [PATCH] 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 --- .../2026-08-16-visual-redesign-design.md | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-16-visual-redesign-design.md diff --git a/docs/superpowers/specs/2026-08-16-visual-redesign-design.md b/docs/superpowers/specs/2026-08-16-visual-redesign-design.md new file mode 100644 index 0000000..1a3cf7a --- /dev/null +++ b/docs/superpowers/specs/2026-08-16-visual-redesign-design.md @@ -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.