1Design tokens

The "Violet & Steel" palette, dark-first. Token names and structure are inherited from TDL; only the values change. Accent is indigo-violet; the reserved semantic colors (warn / danger / PR) are held distinct from it.

--bgsteel page
--surfacecard
--surface-alttint
--accent#6d5ef0 violet
--warnamber
--dangerred
--prgreen · PR only
--borderhairline

2Typography

System sans for body, a strong display family for titles and the big numerals, mono for IDs/weights/code. Weights are the hero — rendered in display weight with tabular figures.

Push Day A — page title
Section header
Body text. The default size for content, 13px / 1.5.
Muted descriptions and hints, color not opacity.
102.5 kg × 8
mono · tk_01K8 · /sessions/2026-05-28

3Buttons

The elevation invariant: 1px border, drop shadow, contrasting fill. One .btn-primary per context. Danger carries an automatic ⚠ glyph; destructive (filled red) is confirmation-only.

Every link is underlined by default — the universal text affordance. Accent for primary, muted for secondary. Never blue.

5Status & chips

Status is flat, glyph-prefixed, non-interactive — the glyph carries meaning so it survives colorblindness. Chips are flat metadata pills with no border. PR uses the reserved green.

Synced In progress Sync failed Offline · 3 queued
Chest Barbell Slow negatives ✓ PR

6Form inputs

1px border, subtle fill, accent focus ring. Labels above the control.

kg · planned for the top set

7Cards

Primary content container. Cards never nest. .card-danger for irreversible-action zones.

Push A v4

6 exercises · last run 24 May

Delete routine

Past sessions are kept; only the template is removed.

8Modals

Themed dialogs only — never alert()/confirm(). Two buttons: Cancel left, commit right.

9Tables

Uppercase-muted headers, muted separators. Numeric columns use mono.

DateAvg weightVolumeMax est. 1RM
28 May91.7 kg25122
24 May90.0 kg24119
21 May90.0 kg22117

10Tabs

Active tab gets the accent bottom border. Tabs navigate; toolbars act.

Tab content area.

Selectable rows; active item carries a 3px accent left border (never a full background).

12Topbar

App chrome. Brand link top-left (the one un-underlined link), mode bar centered, chrome buttons right. .chrome-btn and .brand-link appear only here.

planning.fit

13Feedback

Toasts carry a glyph prefix. Empty states say what is missing and what to do next.

Synced 3 sets Offline — queued locally Sync failed — will retry
No sessions yet. Plan your first workout from a routine.

14Progress & code

# Brzycki estimate, technique-relative
1RM = weight * 36 / (37 - reps)

Short choice lists. Danger item last, separated.

16Gym primitives PFDL

Domain primitives that do not exist in TDL/ADL. A descending-weight sequence of .set-rows is a drop set (no special type). The .rep-stepper is the hero control — reps are an output, recorded to failure. .deviation marks plan-vs-actual (weight/technique/order) with a glyph + the struck-through original. PR uses the reserved green.

122 kg est. 1RM · rough guide, technique-relative
Drop set · 3 sets to failure
102.5kg
planned weight
reps
PR
90kg
planned weight
reps
82.5kg
80 kg changed
"felt strong, bumped it"

17Invariant rules

Inherited from TDL, plus the PFDL-specific reserved-semantics rule. Violations are bugs, not style preferences.

  1. Category separation. Every interactive/state element is exactly one of .btn, .status, .chrome-btn, .brand-link; categories never share a location.
  2. Color plus glyph. Any state that matters is carried by both color and shape. ⚠ destructive, ✓ PR/current, ↻ deviation, colored dot for status.
  3. No false affordances. Non-clickable things must not look clickable. No outlined static labels, no cursor: pointer on non-buttons.
  4. One primary per context. Exactly one .btn-primary per view/form/modal.
  5. Every link underlined. The brand link is the one exception.
  6. Reserved semantics. Accent is never success. amber = warn, red = danger, green = PR / positive only. The accent (violet) carries interactivity, not state.
  7. Numerals are display-weight, tabular. Weights and reps render in the display family with tabular-nums so columns of numbers align and read at a glance.
  8. The gym surface is mobile-first and offline-first. It is the one phone-width, service-worker-backed route; everything else is desktop server-rendered (DESIGN §9.1).
  9. ISO UTC everywhere in data, logs, configs. Local time is a display conversion only.
  10. No browser dialogs. alert()/confirm()/prompt() are banned; every dialog is a themed modal.