Files
mywhoosh2garmin/docs/superpowers/specs/2026-08-16-visual-redesign-design.md
Bastian Wagner 5d75aa328d 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>
2026-08-16 10:48:43 +02:00

7.3 KiB

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.