9e6756f678
Backfills transcripts that existed only locally in ohm-infra: - 0019.1/.2/.3 - UX-polish wave subagent transcripts (driver 0019.0 never finalized) - 0026.1-.9 - security-audit-0026 subagent transcripts (driver abandoned/closed-out by 0068; audit drove published 0030 remediation) - 0073.0 - PPE/progressive-delivery + engineering-handbook session, originally drafted as a duplicate 0046.0; reassigned next free number (0072 taken by a concurrent session) sessions.json: add 0019/0073 titles, update 0026 title. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
159 lines
7.9 KiB
Markdown
159 lines
7.9 KiB
Markdown
# SESSION-0019.1 — App.css + index.css token sweep
|
||
|
||
Parent: SESSION-0019.0-TRANSCRIPT-… (UX-polish wave, rfc-app v0.21.0, roadmap item #31)
|
||
|
||
## Goal
|
||
|
||
Sweep `frontend/src/App.css` (2434 lines) and `frontend/src/index.css`
|
||
onto the design-token system established in `frontend/src/styles/tokens.css`:
|
||
hardcoded hex → nearest semantic/primitive token, font-size literals →
|
||
`--text-*` scale, border-radius literals → `--radius-*` scale, safe
|
||
spacing where it maps cleanly, a coherent transition vocabulary + a
|
||
consistent `:focus-visible` ring, and base rules pointed at semantic
|
||
tokens. Hard constraint: never rename/remove a selector (parallel
|
||
siblings reference these class names); values + additive rules only.
|
||
|
||
## Pre-state
|
||
|
||
- Worktree: `/Users/benstull/git/rfc-app-v0.21.0-appcss`
|
||
- Branch `feature/v0.21.0-appcss-sweep`, based on `5be2c48` (token-module
|
||
foundation).
|
||
- index.css used literal `#1a1a1a` / `#fafaf8` / inline font stack.
|
||
- App.css had ~98 distinct hex (66× `#fff`, 51× `#1a1a1a`, plus a long
|
||
tail of near-duplicate grays: #888/#999/#777/#666/#555 etc.), 16
|
||
distinct font-size px values, 12 distinct radius px values.
|
||
|
||
## Turn-by-turn arc
|
||
|
||
1. Read tokens.css (the foundation) + both target files in full
|
||
(App.css needed two reads — 2434 lines). Confirmed branch/base.
|
||
2. Extracted the full distinct-hex inventory via grep+uniq across both
|
||
files to build the mapping deterministically rather than guessing.
|
||
3. Round-1 script (`/tmp/sweep.py`): regex word-boundary,
|
||
case-insensitive, longest-key-first replacement of all hex that map
|
||
cleanly to a ramp step or status/accent token. 615 replacements.
|
||
- One dict-key collision worth noting: `#ddd` appears as both a
|
||
gray-300 candidate and an on-dark-muted candidate. Resolved to
|
||
`--c-gray-300` (the consolidation target); the header user-name
|
||
`#ddd`-on-dark shifts imperceptibly to #d1d5db.
|
||
4. Re-grepped remainder; 35 distinct hex left — all genuinely off-token
|
||
(true blues, violet tints/shades, functional state dots, deep
|
||
diff-contrast shades, warm oranges with no token).
|
||
5. Round-2 script (`/tmp/sweep2.py`): conservative — only the 7 hex that
|
||
are unambiguously the same ROLE as an existing token and visually
|
||
near it (light-red error bgs/borders → danger-bg/-border, warm soft
|
||
bgs → warning-bg-soft). 15 replacements. Left everything else.
|
||
6. index.css base `:root` → `var(--font-sans)`, `var(--color-text)`,
|
||
`var(--color-bg)`.
|
||
7. Round-3 script (`/tmp/sweep3.py`): font-size px → `--text-*` (280),
|
||
border-radius px → `--radius-*` (128), `rgba(255,255,255,.15/.25)` →
|
||
`--color-on-dark-soft/-hover` (5), the three 48px header-band values
|
||
→ `--header-height` (3). Note: script rewrite invalidated an Edit I
|
||
had queued for `.app-header`; re-read + re-applied.
|
||
8. Promoted `.app-header` to semantic `--color-header-bg` /
|
||
`--color-text-inverse`.
|
||
9. Appended (not interleaved) the interaction-polish layer: a
|
||
transition vocab on hover-reactive selectors + one `:focus-visible`
|
||
ring using `--color-focus-ring`. Additive only — no resting-state
|
||
change, reduced-motion handled by the token module's media query.
|
||
10. Build: first attempt failed on `VITE_APP_NAME is required` (env
|
||
gate, not CSS). Re-ran with `VITE_APP_NAME=OHM` → built in 249ms,
|
||
only the expected ~500kB chunk-size warning. CSS is sound.
|
||
11. Committed; wrote this transcript.
|
||
|
||
## Hex → token MAPPING TABLE
|
||
|
||
Grays (→ neutral ramp):
|
||
| literal(s) | token | note |
|
||
|---|---|---|
|
||
| #ffffff, #fff | --c-white | |
|
||
| #fafafa, #fafaf8, #fafaf9, #fafbfc, #f9f9f9, #f9fafb | --c-gray-50 | |
|
||
| #f3f4f6, #f5f5f5, #f6f6f4, #f7f7f5, #f7f6f0 | --c-gray-100 | |
|
||
| #f0f0ee, #fcfcfb | --c-gray-150 | warm canvas |
|
||
| #e5e5e5, #e5e7eb, #e5e5e0, #e7e5e4, #eee | --c-gray-200 | |
|
||
| #d1d5db, #d4d4d4, #ddd, #ccc | --c-gray-300 | **#ccc→#d1d5db slightly lighter; #ddd→#d1d5db imperceptible** |
|
||
| #9ca3af, #aaa, #b0b0b0, #94a3b8 | --c-gray-400 | #94a3b8 is slightly cooler→neutral, minor |
|
||
| #6b7280, #888, #999, #777, #666, #555 | --c-gray-500 | **#555→#6b7280 and #999→#6b7280 are the most noticeable gray shifts (the desired consolidation)** |
|
||
| #4b5563, #444, #475569 | --c-gray-600 | **#444→#4b5563 noticeable; #475569→#4b5563 slightly warmer** |
|
||
| #374151, #333 | --c-gray-700 | **#333→#374151 slightly cooler, noticeable** |
|
||
| #1f2937, #222 | --c-gray-800 | **#222→#1f2937 noticeable** |
|
||
| #111 | --c-gray-900 | |
|
||
| #1a1a1a | --c-ink (header→--color-header-bg, base text→--color-text) | |
|
||
|
||
Accent / status (→ family tokens):
|
||
| literal | token |
|
||
|---|---|
|
||
| #5b5bd6 | --c-accent |
|
||
| #4338ca | --c-accent-strong |
|
||
| #7c3aed | --c-violet |
|
||
| #166534 | --c-success-fg |
|
||
| #dcfce7 | --c-success-bg |
|
||
| #991b1b | --c-danger-fg |
|
||
| #b91c1c | --c-danger-fg-strong |
|
||
| #fef2f2, #fff5f5 | --c-danger-bg |
|
||
| #fecaca, #fca5a5, #fcc | --c-danger-border |
|
||
| #fee2e2, #fee | --c-danger-bg (light red error bg; **slightly pinker→#fef2f2**) |
|
||
| #92400e | --c-warning-fg |
|
||
| #b45309 | --c-warning-accent |
|
||
| #fef3c7 | --c-warning-bg |
|
||
| #fffbeb, #fff7ed, #fff8e0 | --c-warning-bg-soft (**#fff7ed warm→#fffbeb, minor**) |
|
||
|
||
Font-size (→ --text-* scale; round-to-nearest flagged):
|
||
10→2xs · 11→xs · 12→sm · 13→base · 14→md · **15→lg(16)** ·
|
||
16→lg · **17→xl(18)** · 18→xl · **19→xl(18)** · 22→2xl ·
|
||
**24→2xl(22)** · **26→3xl(28)** · 28→3xl. 9px left as literal
|
||
(below the 10px scale floor — the .beta-chip micro-tag).
|
||
|
||
Border-radius (→ --radius-* scale):
|
||
2→xs · **3→sm(4)** · 4→sm · **5→md(6)** · 6→md · 8→lg ·
|
||
**10→xl(12)** · 12→xl · **14→xl(12)** · **20→pill** (model-pill,
|
||
already pill-shaped at its height) · 99→pill · 999→pill. `50%`
|
||
(circle dots) left untouched.
|
||
|
||
On-dark + layout:
|
||
rgba(255,255,255,0.15)→--color-on-dark-soft;
|
||
rgba(255,255,255,0.25)→--color-on-dark-hover;
|
||
48px header band (×3)→--header-height.
|
||
rgba(255,255,255,0.08) (header link hover) LEFT — no token.
|
||
|
||
Left as literals (no clean token, intentional): blues #3b82f6 #2563eb
|
||
#1e40af #dbeafe #bfdbfe #eff6ff #eef2ff #c7d2fe; violet tints/shades
|
||
#c4b5fd #ede9fe #ddd6fe #faf5ff #4c1d95 #3737a0 #3730a3; status dots /
|
||
functional #ef4444 #dc2626 #fbbf24 #f59e0b #d97706 #10b981; deep
|
||
diff-contrast #14532d #7f1d1d #78350f #bbf7d0 #f0fdf4; warm/misc
|
||
#9a3412 #c2410c #4a3f00 #cb6a6a #cfc8a8 #e6dca0 #fde68a #fdba74
|
||
#fed7aa #f1f5f9. Spacing (--space-*) left untouched this pass —
|
||
prioritized color/type/radius per the brief; no spacing literal was
|
||
both clearly mappable and zero-layout-risk enough to be worth it.
|
||
|
||
## Cut state
|
||
|
||
- Branch: `feature/v0.21.0-appcss-sweep`
|
||
- Final commit: `cbf02d5507f91cc5bf16a68b3f8a8b6b52990849`
|
||
- Files changed: `frontend/src/App.css`, `frontend/src/index.css` (only).
|
||
- Replacements: ~630 color, 280 font-size, 128 radius, 5 on-dark, 3
|
||
header-height. Build green (`VITE_APP_NAME=OHM npm run build`, 249ms,
|
||
expected chunk-size warning only).
|
||
|
||
## What the driver needs to know
|
||
|
||
- No selector renamed/removed — safe for parallel sibling subagents.
|
||
- Gray consolidation deliberately shifts a handful of mid-grays by a
|
||
visually-noticeable amount (#555/#999→gray-500, #444→gray-600,
|
||
#333→gray-700, #222→gray-800). This IS the intended polish; operator
|
||
should eyeball muted-text and secondary-button text before deploy.
|
||
- 15px reading-body → 16px (lg): markdown/entry/landing body text gets
|
||
1px larger. Intentional rounding; check it reads well.
|
||
- The appended polish layer adds a global `:focus-visible` ring and
|
||
transitions to broad element selectors (button/a/input/…). Low risk
|
||
(focus-visible never fires on pointer), but it is the one place that
|
||
touches elements beyond the named classes.
|
||
|
||
## §19.2 candidates
|
||
|
||
- The on-dark translucent-white pattern (`--color-on-dark-soft/-hover`)
|
||
and the focus-ring/transition vocabulary are deployment-agnostic and
|
||
would belong in a future `flotilla-core`-adjacent shared UI layer if
|
||
rfc-app's frontend ever extracts one — but that's an rfc-app concern,
|
||
not flotilla. No flotilla-side extraction implied by this work.
|