T3.1 - C3/S5: inventory the token systems, and correct the accent baseline

Produces docs/reference/tokens.md. No stylesheet is touched; T3.1 is inventory.

What the inventory found that the plan did not say:

- It is six stylesheets plus the launcher's inline <style>, not four (D1 again).
  202 custom-property declarations, all listed with file and line.
- The wave 0 accent baseline is wrong: 15 declarations across 5 sheets, not 14
  across 4. console.css:13 packs five declarations onto one line and the
  baseline's `^\s*--` regex only ever matches the first, so console's own
  --accent was never counted. Corrected command is in tokens.md section 10.
  The wave 9 target of one sheet is unchanged; there is one more to remove.
- Three mono stacks, not two. The file map recorded console.css dropping
  ui-monospace and Segoe UI Mono; wp-chrome.css:159,221 is a third stack that
  drops Cascadia Mono and Segoe UI Mono.
- --shadow-lg does not differ by blur, as the file map says. Both are
  0 4px 16px. The difference is the colour: rgba(0,0,0,.16) against
  rgba(20,30,50,.12). That means they can be unified later with no layout
  consequence at all.
- Twelve var() fallbacks can never fire, because the token they fall back from
  is declared at :root on a sheet the page loads. Free deletions for T3.2.
- --shadow: none is a no-op token with 8 consumers. Left for T3.3, which is
  hunting exactly this class of silent nothing.
- 111 var() references live in .js files across 23 token names. A rename there
  fails silently - no build error, no console warning, just an unstyled
  element. Section 9 is the list to grep before deleting any alias.
- There is a second brand blue: #2563d6, filling .sop-inherited at 7% alpha on
  every field a work package inherited from its SOP. Logged as BL-008.

The document states one rule up front, because it is the difference between a
clean wave 3 and a broken one: consolidation is not unification. Where two
sheets declare the same value, T3.2 collapses them. Where they declare
different values for the same role - the two banner greens, the three error
borders, the two shadows - each value gets its own canonical name and the pair
is recorded. Picking a winner between two near-identical greys is a visual
change, which T3.2 forbids.

Section 8 computes the near-duplicates rather than eyeballing them. The one to
watch is the zebra stripe: console's #fafafa sits six points from #f4f4f4, and
collapsing them erases the striping on the nine-column user table.

New backlog entries: BL-004 (help.js ships 52 colours in a different design
language), BL-005 (two modals styled entirely by inline style= attributes),
BL-006 (17 half-pixel font sizes), BL-007 (--radius: 0 contradicted 45 times in
the sheet that declares it), BL-008 (the second blue).

One decision T3.2 needs and this task cannot make: adopting the superset mono
stack changes the rendered face on machines that have Segoe UI Mono or
ui-monospace but not IBM Plex Mono, which is most of the target environment.
That is a real change on admin and users. Either accept it and re-shoot those
two baselines - capturing twice, since they are not byte-stable - or keep
console.css's narrower stack as a second token until T3.5. Written up in
tokens.md section 6d and 8-H; built to neither until it is answered.

Verification: f_items 5 FIXED / F6 REPRODUCES as expected, browser_check
71/71. Screenshots not applicable - this task changes no rendered surface.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-15 18:24:52 -05:00
parent b105135a98
commit 0e40e967a0
2 changed files with 790 additions and 0 deletions

726
docs/reference/tokens.md Normal file
View File

@@ -0,0 +1,726 @@
# Token inventory — every declared and raw value in `html/`
**Task:** `T3.1` · **Items:** `C3` part 1, `S5` part 1 · **Produced:** August 15, 2026
**Branch:** `feat/wp-suite-r2-implementation` · **Read by:** `T3.2`, `T3.5`, `T9.3`
This is the mapping table `T3.2` builds from. Nothing here changes a stylesheet — `T3.1` is
inventory only. Everything below was read from the working tree at `b105135` (end of wave 2),
not quoted from the review.
**Read [§8 Near-duplicates](#8-near-duplicates--where-unintended-visual-change-will-come-from)
before writing a single line of `T3.2`.** That section is the whole risk in this wave.
---
## 0. The rule this wave is enforcing
From `CLAUDE.md`:
> After wave 3 there is exactly one place a color, spacing or type value is defined. Page
> stylesheets alias that source and declare nothing new.
And the constraint `T3.2` adds on top:
> **Do not** change any rendered value in this task.
Those two together mean one thing that has to be said out loud, because it is the difference
between a clean wave 3 and a broken one:
> ### Consolidation is not unification.
>
> Where two sheets declare the **same** value under different names, `T3.2` collapses them to
> one declaration and aliases the names. That is free — nothing renders differently.
>
> Where two sheets declare **different** values for the same role — `--shadow-lg`, the two
> banner-border greens, the three mono stacks — `T3.2` gives **each value its own canonical
> name** and records the pair in §8. Collapsing those is a *visual change*, which `T3.2`
> forbids. It belongs to `T3.3`/`T3.4`/`T3.5` or to `backlog.md`.
>
> A "consolidation" that quietly picks a winner between two near-identical greys is exactly
> the failure this wave exists to prevent.
---
## 1. Scope: what "four token systems" actually means
`wave-3.md:22` and `IMPLEMENTATION.md` both say "the four stylesheets". Per **D1** in
`docs/reference/file-map.md` there are **six**, and after `T2.2` a seventh surface matters:
the launcher's inline `<style>`.
| # | Surface | Lines | Custom props declared | In `T3.2` scope? |
|---|---|---|---|---|
| 1 | `theme-light.css` | 250 | **120** (114 `--cds-*`, 6 `--wp-appbar-*`) | yes — becomes the source |
| 2 | `console.css` | 192 | **28** unprefixed at `:root` | yes — aliases |
| 3 | `work-package-suite-styles.css` | 663 | **16** unprefixed at `:root` | yes — aliases |
| 4 | `wp-creation-styles.css` | 897 | **24** (21 at `:root`, 3 `--nav-w` on `body`) | yes — aliases |
| 5 | `wp-chrome.css` | 249 | **14** `--wpc-*`, scoped to `.wp-chrome`, none at `:root` | yes — aliases |
| 6 | `wp-sidenav.css` | 109 | **0** — every colour is a hardcoded hex | yes — 31 raw values |
| 7 | `index.html` inline `<style>` (17313) | 296 | 0 — already consumes `--cds-*` | yes — 12 raw values, 7 of them dead |
**202 custom-property declarations in total.** Plus the raw literals in §5.
### Out of `T3.2` scope, stated so nobody goes looking
| Surface | Why it is out | Where it goes |
|---|---|---|
| `help.js:79` injected sheet — **52 colour literals, zero `var()`** | It is a whole parallel palette in a different design language (slate `#27313f`/`#334155`, violet `#7c3aed`/`#f3e8ff`, its own blue `rgba(37,99,214,.15)`). Converting it is a *restyle*, not a consolidation, and it would break `T3.2`'s empty-diff done-when. | **BL-004** |
| `wp-creation-app.js:1257` print window | `w.document.write()` builds a **separate document** that loads none of the suite's stylesheets. `var()` cannot resolve there. Genuine one-off. | stays raw, documented in §7 |
| `wp-creation-app.js:1389` `body{--nav-w:288px}` | Root cause of **BL-001**; `T7.1` owns it. Touching it here changes the creator's layout at 390px, which is a visual change. | `T7.1` |
| `auth-guard.js:67-92` password modal + `wp-format.js:120-150` prefs modal, inline styles | **35 raw literals** (16 + 19) in `style=` attributes, not a stylesheet. `T2.2` already replaced the nav half of this markup; both modals are rebuilt under `C1` at `T9.5`. | **BL-005** |
| `work-package-suite-app.js`, `admin.js`, `users.js` inline `style.*` | They **consume** page tokens (`var(--muted)`, `var(--red)`, `var(--s2)` …) rather than declaring them. See §9 — this is why names must survive as aliases. | no change needed |
---
## 2. The proposed canonical set
`theme-light.css` is already the source of truth in everything but name: it is **linked first
on all 7 pages**, it holds 114 of the 202 declarations, and its values are real Carbon g10.
`T3.2` should make that official rather than invent a new file.
Two namespaces, and the split is not cosmetic — it records provenance:
- **`--cds-*`** — values that are genuine IBM Carbon g10. Unchanged, plus the two additions
below which are also real Carbon token names that this sheet simply never declared.
- **`--wp-*`** — roles Carbon does not define, which the suite invented. Naming these
separately is what stops the next person "correcting" `#8e6a00` to a Carbon yellow.
### 2a. Additions to `--cds-*` (Carbon values, currently redeclared per sheet)
| New canonical token | Value | Carbon name | Replaces |
|---|---|---|---|
| `--cds-highlight` | `#edf5ff` | `$highlight` / blue-10 | `--accent-soft`, `--primary-light`, `--accent-dim` (3 sheets) |
| `--cds-hover-support-success` | `#0e6027` | green-70 | 5 raw literals, declared nowhere today |
### 2b. Additions under `--wp-*` (suite inventions, no Carbon equivalent)
| New canonical token | Value | Why it is not Carbon | Replaces |
|---|---|---|---|
| `--wp-status-success-bg` | `#defbe6` | green-10 *is* Carbon; the **role** is not (`$notification-background-success` is a different construct) | `--green-bg`, `--accent-green-dim` |
| `--wp-status-error-bg` | `#fff1f1` | as above (red-10) | `--red-bg`, `--red-dim` |
| `--wp-status-warning-bg` | `#fdf6dd` | Carbon yellow-10 is `#fcf4d6`**this is not it** | `--amber-bg`, `--warning-bg`, `wp-chrome.css:50`, `index.html:298` |
| `--wp-status-warning-text` | `#8e6a00` | no Carbon amber text token exists; this is the suite's accessible-on-`#fdf6dd` amber | `--amber`, `--warning`, `--accent-amber` |
| `--wp-font-sans` | see §6 | — | 6 sites, 2 variants |
| `--wp-font-mono` | see §6 | — | 4 sites, 3 variants |
| `--wp-s1``--wp-s6` | `4 8 12 16 20 28` px | — | `console.css` `--s1..--s6`; the only real spacing scale in the repo |
| `--wp-ctl`, `--wp-ctl-sm` | `32px`, `26px` | — | `console.css:19-20` |
| `--wp-radius-0` | `0` | — | `--radius`, and 34 literal `border-radius: 0` |
### 2c. Kept, and kept **separate**, because their values differ
These are not duplicates. Each gets a canonical name; nobody collapses them in `T3.2`.
See §8 for the decision each one is waiting on.
| Canonical token | Value | Used by | Paired with |
|---|---|---|---|
| `--wp-shadow-lg-neutral` | `0 4px 16px rgba(0,0,0,.16)` | wizard `--shadow-lg` | `--wp-shadow-lg-cool` |
| `--wp-shadow-lg-cool` | `0 4px 16px rgba(20,30,50,.12)` | creator `--shadow-lg` | `--wp-shadow-lg-neutral` |
| `--wp-status-success-border-a` | `#a7f0ba` (green-20, Carbon) | `console.css:82` | `-b` |
| `--wp-status-success-border-b` | `#b6e3c6` (not Carbon) | `wp-creation-styles.css:494,532` | `-a` |
---
## 3. Declaration inventory — `theme-light.css` (the source)
All 120 stay exactly as they are. Grouped by role here so the *shape* is readable; every one
of the 120 is listed individually with its line number in **[Appendix A](#appendix-a--every-theme-lightcss-declaration-line-by-line)**.
The file is a flat `:root` block at **lines 2117** and **169176**.
| Lines | Group | Count | Distinct values | Action in `T3.2` |
|---|---|---|---|---|
| 36 | `--cds-interactive-01..04` | 4 | `#0f62fe` ×3, `#393939` | keep |
| 712 | `--cds-ui-background`, `--cds-ui-01..05` | 6 | `#f4f4f4` ×2, `#ffffff`, `#e0e0e0`, `#8d8d8d`, `#161616` | keep |
| 1318 | `--cds-text-01..05`, `--cds-text-error` | 6 | `#161616 #525252 #a8a8a8 #ffffff #6f6f6f #da1e28` | keep |
| 1921 | `--cds-icon-01..03` | 3 | `#161616 #525252 #ffffff` | keep |
| 2224 | `--cds-link-01`, `-02`, `--cds-inverse-link` | 3 | `#0f62fe #0043ce #78a9ff` | keep |
| 2528 | `--cds-field-01/02`, `--cds-inverse-01/02` | 4 | `#ffffff #f4f4f4 #ffffff #393939` | keep |
| 2936 | `--cds-support-01..04` + inverse | 8 | `#da1e28 #198038 #f1c21b #0043ce #fa4d56 #42be65 #f1c21b #4589ff` | keep |
| 3746 | overlay, danger, focus, hover/active primary·secondary·tertiary | 10 | incl. `#0353e9` ×2, `#002d9c` ×2 | keep |
| 4761 | hover/active/selected UI, disabled | 15 | `#e5e5e5` ×4, `#cacaca` ×2, `#c6c6c6`, `#353535`, `#f4f4f4` ×2, `#bdbdbd`, `#8d8d8d`, `#ba121b`, `#750e13`, `#0043ce` | keep |
| 6266 | `--cds-button-*` | 5 | `#0f62fe` ×2, `#393939`, `#da1e28` ×2 | keep |
| 6789 | v11 background / layer / field / border set | 23 | mostly aliases of the above literals | keep |
| 90115 | v11 text / link / icon / support / interactive set | 26 | mostly aliases of the above literals | keep |
| 116 | `--cds-shadow` | 1 | `rgba(0,0,0,.16)` | keep — see §8-F |
| 170175 | `--wp-appbar-bg/fg/fg-dim/border/hover/height` | 6 | `#161616 #ffffff #c6c6c6 #6f6f6f #353535 48px` | keep |
**Note for `T9.3`:** `theme-light.css` re-declares the *same literal* under many names by
design — that is Carbon's v10→v11 alias layer (`--cds-ui-01` and `--cds-layer` are both
`#ffffff`, deliberately). Those are **not** the `S5` defect and must not be "deduplicated". The
`S5` defect is the same literal declared in *different sheets*, which is §4.
One raw literal in this file: **`theme-light.css:203`** `background: #fff` on `.wp-logo-chip`.
`--cds-ui-01`. (The chip is a deliberate white plate under a white-background wordmark; the
value is white for a reason, but it should still read from the token.)
---
## 4. Declaration inventory — the five page sheets
Every one of these is a duplicate declaration of a value `theme-light.css` already holds,
unless flagged. **Action** is what `T3.2` writes.
### 4a. `console.css` — 28 declarations, lines 1220
| Line | Token | Value | Canonical | Action |
|---|---|---|---|---|
| 12 | `--bg` | `#f4f4f4` | `--cds-background` | alias |
| 12 | `--surface` | `#fff` | `--cds-layer` | alias — **notation-only dupe**, see §8-G |
| 12 | `--border` | `#e0e0e0` | `--cds-border-subtle` | alias |
| 12 | `--border-strong` | `#8d8d8d` | `--cds-border-strong` | alias |
| 12 | `--text` | `#161616` | `--cds-text-primary` | alias |
| 13 | `--muted` | `#525252` | `--cds-text-secondary` | alias |
| 13 | `--dim` | `#8d8d8d` | `--cds-ui-04` | alias — contrast issue is `T4.6`, not here |
| 13 | `--accent` | `#0f62fe` | `--cds-interactive-01` | alias — **missed by the wave-0 count, see §10** |
| 13 | `--accent-hover` | `#0353e9` | `--cds-hover-primary` | alias |
| 13 | `--accent-soft` | `#edf5ff` | `--cds-highlight` (new) | alias |
| 14 | `--green` | `#198038` | `--cds-support-success` | alias |
| 14 | `--green-bg` | `#defbe6` | `--wp-status-success-bg` (new) | alias |
| 15 | `--red` | `#da1e28` | `--cds-support-error` | alias |
| 15 | `--red-bg` | `#fff1f1` | `--wp-status-error-bg` (new) | alias |
| 15 | `--amber` | `#8e6a00` | `--wp-status-warning-text` (new) | alias |
| 15 | `--amber-bg` | `#fdf6dd` | `--wp-status-warning-bg` (new) | alias |
| 16 | `--head-bg` | `#f4f4f4` | `--cds-layer-accent` | alias |
| 16 | `--zebra` | `#fafafa` | — | **one-off**, §8-A. Not a Carbon grey; a 4-step-lighter zebra stripe |
| 16 | `--row-hover` | `#eef0f2` | — | **one-off**, §8-B. Deliberately not `--accent-soft`; see the comment at `:115-116` |
| 17 | `--mono` | `'IBM Plex Mono','Cascadia Mono',Consolas,monospace` | `--wp-font-mono` | **value differs**, §8-H |
| 18 | `--s1``--s6` | `4 8 12 16 20 28`px | `--wp-s1..6` (new) | **promote** — this is the canonical spacing scale |
| 1920 | `--ctl`, `--ctl-sm` | `32px`, `26px` | `--wp-ctl`, `--wp-ctl-sm` (new) | promote |
Lines 85 and 115 contain `--dim` / `--accent-soft` inside **comments** — a naïve
`grep '--x:'` counts them. They are prose, not declarations.
### 4b. `work-package-suite-styles.css` — 16 declarations, lines 217
| Line | Token | Value | Canonical | Action |
|---|---|---|---|---|
| 2 | `--primary` | `#0f62fe` | `--cds-interactive-01` | alias |
| 3 | `--primary-light` | `#edf5ff` | `--cds-highlight` (new) | alias |
| 4 | `--success` | `#198038` | `--cds-support-success` | alias |
| 5 | `--warning` | `#8e6a00` | `--wp-status-warning-text` (new) | alias |
| 6 | `--warning-bg` | `#fdf6dd` | `--wp-status-warning-bg` (new) | alias |
| 7 | `--danger` | `#da1e28` | `--cds-support-error` | alias |
| 8 | `--text` | `#161616` | `--cds-text-primary` | alias |
| 9 | `--text-light` | `#525252` | `--cds-text-secondary` | alias |
| 10 | `--text-dim` | `#8d8d8d` | `--cds-ui-04` | alias — **`T4.6` re-measures this**, do not change the value in wave 3 |
| 11 | `--border` | `#e0e0e0` | `--cds-border-subtle` | alias |
| 12 | `--border-strong` | `#8d8d8d` | `--cds-border-strong` | alias |
| 13 | `--bg` | `#f4f4f4` | `--cds-background` | alias |
| 14 | `--bg-card` | `#ffffff` | `--cds-layer` | alias |
| 15 | `--appbar` | `#161616` | `--wp-appbar-bg` | alias — file-map called this out; it is the same value under a second name |
| 16 | `--shadow` | `none` | `--wp-shadow-none` | alias — **and it is a no-op, see §7** |
| 17 | `--shadow-lg` | `0 4px 16px rgba(0,0,0,0.16)` | `--wp-shadow-lg-neutral` | **value differs from the creator's**, §8-F |
Line 340 mentions `--cds-field: #ffffff` inside the `T1.5` comment. Prose, not a declaration.
### 4c. `wp-creation-styles.css` — 24 declarations (21 at `:root` lines 1030, 3 on `body`)
| Line | Token | Value | Canonical | Action |
|---|---|---|---|---|
| 10 | `--bg` | `#f4f4f4` | `--cds-background` | alias |
| 11 | `--surface` | `#ffffff` | `--cds-layer` | alias |
| 12 | `--surface2` | `#f4f4f4` | `--cds-layer-accent` | alias |
| 13 | `--border` | `#e0e0e0` | `--cds-border-subtle` | alias |
| 14 | `--border-strong` | `#8d8d8d` | `--cds-border-strong` | alias |
| 15 | `--text` | `#161616` | `--cds-text-primary` | alias |
| 16 | `--text-muted` | `#525252` | `--cds-text-secondary` | alias |
| 17 | `--text-dim` | `#8d8d8d` | `--cds-ui-04` | alias — applied at **10px** on `:374`; `T4.6` owns the contrast |
| 18 | `--accent` | `#0f62fe` | `--cds-interactive-01` | alias |
| 19 | `--accent-dim` | `#edf5ff` | `--cds-highlight` (new) | alias |
| 20 | `--accent-green` | `#198038` | `--cds-support-success` | alias |
| 21 | `--accent-green-dim` | `#defbe6` | `--wp-status-success-bg` (new) | alias |
| 22 | `--accent-amber` | `#8e6a00` | `--wp-status-warning-text` (new) | alias |
| 23 | `--accent-amber-dim` | `#fdf6dd` | `--wp-status-warning-bg` (new) | alias |
| 24 | `--red` | `#da1e28` | `--cds-support-error` | alias |
| 25 | `--red-dim` | `#fff1f1` | `--wp-status-error-bg` (new) | alias |
| 26 | `--radius` | `0` | `--wp-radius-0` (new) | alias — **and contradicted 45×, see §7** |
| 27 | `--shadow` | `none` | `--wp-shadow-none` | alias — no-op, §7 |
| 28 | `--shadow-lg` | `0 4px 16px rgba(20,30,50,.12)` | `--wp-shadow-lg-cool` | **value differs**, §8-F |
| 29 | `--mono` | `'IBM Plex Mono', ui-monospace, 'Cascadia Mono', 'Segoe UI Mono', Consolas, monospace` | `--wp-font-mono` | **the fullest stack — adopt this one**, §8-H |
| 30 | `--sans` | `'IBM Plex Sans', …, 'Helvetica Neue', sans-serif` | `--wp-font-sans` | alias, §8-H |
| 685 | `--nav-w` (on `body`) | `288px` | — | **leave alone — `T7.1`/BL-001** |
| 686 | `--nav-w` (`body.wp-nav-collapsed`) | `56px` | — | leave alone |
| 817 | `--nav-w` (`@media ≤860px`) | `56px` | — | leave alone |
### 4d. `wp-chrome.css` — 14 declarations, scoped to `.wp-chrome` (lines 1925, 2935)
These are **not** `:root` declarations. They are a two-value theme switch: the same seven
role names resolve light or dark depending on `[data-bar="dark"]`. That pattern is correct and
should survive; only the literals move behind tokens.
| Line | Token | Light value → canonical | Line | Dark value → canonical |
|---|---|---|---|---|
| 19 | `--wpc-fg` `#161616``--cds-text-primary` | 29 | `#ffffff``--wp-appbar-fg` |
| 20 | `--wpc-fg-dim` `#525252``--cds-text-secondary` | 30 | `#c6c6c6``--wp-appbar-fg-dim` |
| 21 | `--wpc-bg` `#ffffff``--cds-layer` | 31 | `#262626`**one-off**, §8-J |
| 22 | `--wpc-bg-soft` `#f4f4f4``--cds-layer-accent` | 32 | `#393939``--cds-interactive-02` |
| 23 | `--wpc-border` `#c6c6c6``--cds-border-subtle-selected` | 33 | `#6f6f6f``--wp-appbar-border` |
| 24 | `--wpc-hover` `#e8e8e8``--cds-layer-hover` | 34 | `#353535``--wp-appbar-hover` |
| 25 | `--wpc-accent` `#0f62fe``--cds-interactive-01` | 35 | `#78a9ff``--cds-link-inverse` |
### 4e. `wp-sidenav.css` — 0 declarations, 31 raw literals
Every colour is hardcoded. The header comment says why — "Colours come from the dark app bar
it hangs off … not from `theme-light.css`" — but the *values* are all Carbon greys that
`theme-light.css` already holds, so the reasoning ("match the bar") and the mechanism
("hardcode it") disagree. Aliasing them to the appbar tokens makes the stated intent true.
| Value | Sites | Canonical |
|---|---|---|
| `#161616` | `:35` and the `:8` comment | `--wp-appbar-bg` |
| `#f4f4f4` | `:15`, `:35`, `:68`, `:89`, `:108` | `--cds-text-inverse` |
| `#353535` | `:17`, `:77`, `:92` | `--wp-appbar-hover` |
| `#ffffff` | `:18`, `:93` (focus rings), `:77` | `--wp-appbar-fg` |
| `#e8e8e8` | `:21` (light-bar hover) | `--cds-layer-hover` |
| `rgba(22,22,22,.55)` | `:25` scrim | **near-dupe of `--cds-overlay`** `rgba(22,22,22,.5)` — §8-F |
| `rgba(0,0,0,.4)` | `:38` drawer shadow | one-off, §7 |
| `#393939` | `:49`, `:59`, `:103` (rules) | `--cds-inverse-02` |
| `#a8a8a8` | `:53`, `:65`, `:100`, `:106` | `--cds-text-placeholder` |
| `#c6c6c6` | `:71`, `:74`, `:96` | `--wp-appbar-fg-dim` |
| `#8d8d8d` | `:82` | `--cds-ui-04` |
| `#262626` | `:94` current-row fill | one-off, §8-J |
| `#0f62fe` | `:94` current-row rule | `--cds-interactive-01` |
| `#78a9ff` | `:98` current-row icon | `--cds-link-inverse` |
### 4f. `index.html` inline `<style>` — 0 declarations, 6 raw literals
The block already consumes `--cds-*` throughout; these six are the stragglers.
12 literals: **5 live, 7 dead**.
| Line | Literal | Context | Canonical |
|---|---|---|---|
| 126 | `#0e6027` | `.card.complete .card-button:hover` | `--cds-hover-support-success` (new) |
| 291 | `#fff` | `.proj-row select` background | `--cds-field` |
| 298 | `#fdf6dd` / `#f1c21b` / `#8e6a00` | `.proj-archived-note` — the amber triple | `--wp-status-warning-bg` / `--cds-support-warning` / `--wp-status-warning-text` |
| 291, 292 ×2, 300 ×2, 303, 305 | `#8d8d8d` ×3, `#fff` ×2, `#e0e0e0`, `#0f62fe` | **`var()` fallbacks only — 7 of them** | delete the fallbacks — see §7 |
`index.html:13` `<meta name="theme-color" content="#161616">` is markup, not CSS. It cannot
take a `var()`. Leave it; note it in §7.
---
## 5. Raw literals used in rules, by sheet
Counts exclude declarations and comments — measured by stripping `/* … */` first, then
subtracting literals that sit inside a `--x:` declaration. Full site lists are in §4e/§4f for
the two sheets that are all-raw; the rest are itemised here.
| Sheet | Raw literals in rules | The ones that are not already a token |
|---|---|---|
| `theme-light.css` | **1** | `:203` `#fff` |
| `console.css` | **19** | `#a7f0ba` `:82` · `#ffd7d9` `:83` · `#fddc69` `:84` · `#0f1525` `#d7e0f5` `:90` · `#56d364` `#ff7b72` `:92` · `#e8daff` `#6929c4` `:145` · `#e8e8e8` `:146` · `rgba(20,30,50,.5)` `:158` · `rgba(20,30,50,.3)` `:161` · `rgba(20,30,50,.12)` `:174` · `#fff` ×6 (`:49 :52 :53 :54 :67 :138`) |
| `work-package-suite-styles.css` | **15** | `#fff` `:43 :78 :105 :133 :562` · `#c6c6c6` `:111 :150` · `#6f6f6f` `:134 :144 :149` · `#353535` `:143` · `#0353e9` `:476` (a dead `var()` fallback) · `#0e6027` ×2 `:498` · `rgba(0,0,0,0.5)` `:606` |
| `wp-chrome.css` | **22** | the whole `.wpc-pop` block `:125-180` is raw (`#fff #161616 #e0e0e0 #6f6f6f #f0f0f0 #f4f4f4 #edf5ff #0f62fe #c6c6c6`) plus the archived banner `:50-52` |
| `wp-creation-styles.css` | **68** | see below |
| `wp-sidenav.css` | **30** (a 31st is in the header comment) | §4e |
| `index.html` inline | **12** (5 live, 7 dead) | §4f |
### The creator's raw literals — the largest group
Grouped by what they are, because they need different treatment:
**Already-tokenised values written raw** — straight substitution, zero risk:
`#fff` ×19 (`:248 :262 :264 :372 :385 :389 :446 :471 :498 :504 :505 :506 :517 :536 :618 :706 :715 :784 :823`) → `--cds-text-on-color` / `--cds-layer`;
`#0353e9` ×3 (`:263 :711 :718`) → `--cds-hover-primary`;
`#0e6027` ×2 (`:265 :447`) → `--cds-hover-support-success`;
`#161616` ×2 (`:618 :623`, the `.sop-chip` tooltip) → `--cds-ui-05`;
`#0043ce` (`:231`) → `--cds-link-secondary`.
**Accent tints with no token** — §8-C, do not merge:
`#b9d2fb` ×4 (`:230 :449 :614 :636`) · `#cdd9f2` ×2 (`:515 :581`) · `#e2ecfc` (`:582`).
**`var()` fallbacks that can never fire** — the token is declared at `:root` in the same
sheet, so the fallback is dead code. §7.
`var(--accent-dim,#eef3fd)` `:581 :839` · `var(--accent-dim,#eaf0fd)` `:515` ·
`var(--accent,#0f62fe)` `:854`.
**Planner-style neutral greys, no token** — §8-B, do not merge:
`#fbfbfc` (`:680`) · `#eef0f3` ×3 (`:696 :740 :773`) · `#e8eaed` ×2 (`:741 :774`).
**Status borders, no token** — §8-D:
`#b6e3c6` ×2 (`:494 :532`) · `#f0d9ad` ×3 (`:451 :461 :495`) · `#f3c4c4` (`:496`) ·
`#ffc4c4` (`:663`).
**Deliberate one-offs** — §7:
dev-mode banner `#3a2a00` `#ffd479` (`:573`), `#ffb000` (`:574`) ·
`rgba(37,99,214,0.07)` (`:565`) — §8-E ·
`rgba(255,255,255,.94)` (`:598`), `rgba(255,255,255,.28)` (`:715`) ·
`rgba(244,245,247,.82)` (`:302`) — §8-A.
**Cool-tinted shadows and scrims** — one family, seven alphas: `rgba(20,30,50, .06 .08 .16
.18 ×2 .22 .28)` (`:599 :824 :818 :647 :722 :621 :391`) plus `rgba(20,28,40,.55)` (`:521`)
and `rgba(0,0,0,.25)` (`:518`), `rgba(0,0,0,.3)` (`:523`). §8-F.
---
## 6. Type, spacing, radius and font scales
### 6a. Type — 27 distinct font-size values, three notations
`rem` on the two Carbon-native surfaces, `px` everywhere else, **and half-pixels in the
creator**. There is no scale; there is a histogram.
| Value | Total | Where |
|---|---|---|
| `9px` `9.5px` `10px` `10.5px` | 34 | creator 28, chrome 4, wizard 1, sidenav 1 |
| `11px` `11.5px` | 46 | creator 34, console 3, sidenav 4, wizard 2, index 2, chrome 1 |
| `12px` `12.5px` | 53 | creator 32, console 7, index 6, wizard 5, chrome 2, sidenav 1 |
| `13px` `13.5px` | 66 | creator 31, console 10, index 9, chrome 7, wizard 4, sidenav 3, theme 2 |
| `14px` | 21 | wizard 7, creator 7, theme 2, chrome 2, index 2, sidenav 1 |
| `15px` `16px` `17px` `18px` `20px` `22px` `26px` | 27 | creator 13, wizard 9, console 2, theme 1, sidenav 1 |
| `.75rem``2.25rem` (10 values) | 16 | theme 8, index 8 |
| `8px`, `.92em`, `inherit` | 3 | creator 2, console 1 |
**Recommendation for `T3.2`:** publish `--wp-type-*` as a **documented ladder that page
sheets may adopt**, and convert only the values that already sit on it. Rewriting 27 sizes
onto 8 steps changes rendering on every page and is forbidden here. The half-pixel sizes
(`9.5 10.5 11.5 12.5 13.5`, 17 sites, creator + chrome) are the ones to retire — log as
**BL-006**, do it during the `T7.1` rebuild where the creator is being re-laid-out anyway.
### 6b. Spacing — three systems
| System | Where | Values |
|---|---|---|
| **Token scale** | `console.css` `--s1..--s6` | `4 8 12 16 20 28` px — 62 `var()` consumers, 2 of them in `users.js` |
| **`rem` ladder** | wizard + `index.html` inline | `0.25 0.3 0.5 0.55 0.6 0.65 0.7 0.75 0.85 0.9 1 1.25 1.4 1.5 1.75 2 2.5 3` rem — 18 steps, 8 of them used once |
| **Raw px, no scale** | creator, chrome, sidenav | every integer `1``14`, then `16 18 20 22 24 28 32 36 52 56 72` — 289 sites in the creator alone |
`--s1..--s6` is the only one of the three that is a scale. `T3.2` promotes it to `--wp-s*` and
aliases `console.css`. The other two get converted as their pages are rebuilt (`T5.x`, `T7.x`),
not now.
### 6c. Radius — the token says square, the sheet says otherwise
`--radius: 0` is declared once and honoured **23 times** in `wp-creation-styles.css` — and
contradicted by raw values **45 times** in the same file: `2px 3px 4px 5px 6px 8px 9px 10px
12px 14px 20px 50%`, plus the two asymmetric CTA radii at `:707` and `:716`.
Across all sheets: `0` ×34, `3px` ×13, `4px` ×10, `6px` ×9, `50%` ×7, `9px` ×6, `20px` ×5.
The square-corner idiom is Carbon and it is the intent everywhere except the creator, which
drifted. **Do not fix in `T3.2`** — changing 45 radii is the most visible possible diff.
Log as **BL-007** against `T7.1`.
### 6d. Font stacks — 2 sans variants, 3 mono variants
| Stack | Sites | Difference |
|---|---|---|
| Sans **with** `'Helvetica Neue'` | `theme-light:121`, `wizard:22`, creator `--sans:30` | — |
| Sans **without** `'Helvetica Neue'` | `console:22`, `wp-chrome:54`, `wp-sidenav:36` | drops one fallback |
| Mono A | creator `--mono:29` | `'IBM Plex Mono', ui-monospace, 'Cascadia Mono', 'Segoe UI Mono', Consolas, monospace` |
| Mono B | `console:17` | drops `ui-monospace` **and** `'Segoe UI Mono'` |
| Mono C | `wp-chrome:159, :221` | drops `'Cascadia Mono'` **and** `'Segoe UI Mono'` |
The file map recorded two mono stacks; there are **three**. Adopt Mono A (the superset) as
`--wp-font-mono` and the Helvetica-Neue sans as `--wp-font-sans`.
**This is a rendering change on machines that have `'Segoe UI Mono'` or `ui-monospace` but not
`'IBM Plex Mono'`** — i.e. most Windows machines without Plex installed, which is the target
environment. Adopting the superset stack in `T3.2` would change the admin console's monospace
face. → **Alias to the superset but keep `console.css`'s narrower stack as
`--wp-font-mono-console` until `T3.5`**, or accept the change and re-shoot `admin`/`users`.
Flagged, not decided — see §8-H.
---
## 7. One-offs, kept raw, with reasons
Values that should **not** become tokens, and why. `T3.2` leaves each of these alone.
| Value(s) | Where | Reason |
|---|---|---|
| `#1a2230` `#2563d6` `#cdd9f2` `#f0f2f5` `#ccc` | `wp-creation-app.js:1257` | The print window is a **separate document** written with `document.write()`. It loads no stylesheet, so `var()` cannot resolve. Hardcoding is the only correct option here. |
| `#0f1525` `#d7e0f5` `#56d364` `#ff7b72` | `console.css:90-92` | `pre.out` is a **terminal emulator**. Green-on-dark pass / red-on-dark fail is the convention being quoted; it is not the product palette and should not track it. |
| `#3a2a00` `#ffd479` `#ffb000` | `wp-creation-styles.css:573-574` | The dev-mode banner is **meant** to look wrong. Making it consume the product's amber would make it look intentional, which defeats it. |
| `#e8daff` `#6929c4` | `console.css:145` | Carbon purple-10/purple-60, used once, for the Project Super User tag. Real Carbon values with no `--cds-*` slot in this sheet's subset. Promote only if a second consumer appears. |
| `#161616` | `index.html:13` `<meta name="theme-color">` | Markup attribute. Cannot take a `var()`. |
| `rgba(0,0,0,.4)` | `wp-sidenav.css:38` | Drawer drop-shadow. Neutral by intent — it falls on both light and dark hosts. §8-F |
| `--shadow: none` | wizard `:16`, creator `:27` | **A no-op token with 8 consumers.** `box-shadow: var(--shadow)` renders nothing on `.step-navigation`, `.seq-step`, `.card`, `.stepper`, `.btn-primary`, `.btn-generate`. It is not broken — flat is the Carbon idiom — but it is 8 dead declarations. Keep the alias; note for `T3.3`, which is hunting exactly this class of silent no-op. |
| `var(--accent-dim,#eef3fd)` ×2, `var(--accent-dim,#eaf0fd)`, `var(--accent,#0f62fe)`, `var(--cds-hover-primary,#0353e9)`, `var(--cds-border-strong,#8d8d8d)` ×3, `var(--cds-ui-01,#fff)` ×2, `var(--cds-ui-03,#e0e0e0)`, `var(--cds-link-01,#0f62fe)` | **12 sites:** creator `:515 :581 :839 :854`, wizard `:476`, `index.html:291 :292`(×2) `:300`(×2) `:303 :305` | **Dead fallbacks.** Every one of these tokens is declared at `:root` on a sheet the page loads, so the fallback can never render. They are a meaningful share of the raw-hex count and cost nothing to delete. Deleting them is `T3.2` work and is provably invisible. |
---
## 8. Near-duplicates — where unintended visual change will come from
Computed, not eyeballed: every pair of distinct colours in the six sheets plus the launcher's
inline block, ranked by summed channel distance. Anything a careless refactor would collapse.
### A. Off-whites around `#f4f4f4` — 5 values
| Value | Site | Role |
|---|---|---|
| `#f4f4f4` | canonical, 22 sites | page background / layer-accent |
| `#fafafa` | `console.css:16` `--zebra` | table zebra stripe |
| `#fbfbfc` | `wp-creation-styles.css:680` | `.wp-nav` panel background |
| `rgba(244,245,247,.82)` | `wp-creation-styles.css:302` | loading overlay |
| `#f0f0f0` | `wp-chrome.css:139,163` | popover divider hairlines |
The zebra is the trap. `#fafafa` sits **6 points lighter** than `#f4f4f4`; collapsing them
erases the striping on the user table entirely, on the one page where nine columns make
striping load-bearing. `T3.2` keeps all five.
### B. Hover greys — 5 values, max spread 26
`#e8e8e8` (canonical `--cds-layer-hover`, 7 sites) · `#e5e5e5` (`--cds-selected-ui`, 8) ·
`#eef0f2` (`console --row-hover`) · `#eef0f3` (creator `.wp-nav-*:hover`, 3) ·
`#e8eaed` (creator `.wp-nav-item.active`, 2).
`#eef0f2` and `#eef0f3` are **one point apart** and in different sheets — almost certainly the
same colour typed twice from memory. They are still not interchangeable in `T3.2`: `console`
has a comment at `:115-116` explaining that its row hover is deliberately *not* the accent
tint. Two canonical tokens, one decision logged.
### C. Accent tints — 4 values, and 2 of them are dead
| Value | Site | Live? |
|---|---|---|
| `#edf5ff` | canonical (blue-10), 4 sheets | live |
| `#eef3fd` | `wp-creation-styles.css:581,839` | **dead**`var()` fallback, token declared |
| `#eaf0fd` | `wp-creation-styles.css:515` | **dead** — same |
| `#e2ecfc` | `wp-creation-styles.css:582` `.ref-link:hover` | live, one-off |
Deleting the two dead fallbacks removes two near-duplicates at zero rendering risk. That is
the cheapest win in this wave.
### D. Status borders — the pairs that must not merge
| Role | Value A | Value B | Note |
|---|---|---|---|
| success border | `#a7f0ba` `console:82` | `#b6e3c6` `creator:494,532` | A is Carbon green-20; B is not Carbon at all |
| error border | `#ffd7d9` `console:83` | `#f3c4c4` `creator:496`, `#ffc4c4` `creator:663` | **three** values for one role; `#f3c4c4`/`#ffc4c4` differ by 12 |
| warning border | `#fddc69` `console:84` | `#f0d9ad` `creator:451,461,495` | A is Carbon yellow-30; B is not |
| accent border | `#b9d2fb` ×4 | `#cdd9f2` ×2 | neither is Carbon blue-20 (`#d0e2ff`) |
Eight values doing four jobs. Every one renders somewhere today. `T3.2` names all eight;
picking four winners is a `T3.5` conversation.
### E. There is a second blue in the app
`rgba(37,99,214,0.07)` at `wp-creation-styles.css:565` — that is **`#2563d6`**, not
`#0f62fe`. It fills `.sop-inherited`, the highlight on every field a work package inherited
from its SOP. At 7% alpha nobody has noticed, but it is a second brand blue, and `help.js`
carries the same one at `rgba(37,99,214,.15)` and `wp-creation-app.js:1257` uses it solid.
Not a `T3.2` fix — swapping it to `#0f62fe` shifts a real fill. Log as **BL-008**, resolve at
`T3.5` alongside the button roles, since "one accent" is the same conversation.
### F. Shadows and scrims — one blur, four tints
| Family | Values | Sites |
|---|---|---|
| neutral | `rgba(0,0,0, .16 .25 .3 .4 .5)` | theme `--cds-shadow`, wizard `--shadow-lg` + `.modal`, creator `#toast` + `.modal`, sidenav |
| cool | `rgba(20,30,50, .06 .08 .12 .16 .18 .22 .28 .3 .5)` | creator ×10, console ×3, chrome ×1 |
| cool-darker | `rgba(20,28,40,.55)` | creator `.modal-overlay:521` |
| near-black | `rgba(22,22,22, .5 .55)` | `--cds-overlay`, sidenav scrim `:25` |
**Correcting the file map:** it records `--shadow-lg` as differing by "a different blur". The
blur is identical — `0 4px 16px` in both. The difference is the **colour**:
`rgba(0,0,0,0.16)` (wizard) vs `rgba(20,30,50,.12)` (creator). Same geometry, warmer/cooler
and 4% apart in alpha. That matters because it means the two can be unified later by choosing
a tint, with no layout consequence at all.
`rgba(22,22,22,.5)` vs `rgba(22,22,22,.55)` is the same colour at two alphas — the sidenav
scrim is 5% darker than `--cds-overlay` for no recorded reason. Cheapest merge in the set, but
still a rendered change: not in `T3.2`.
### G. Notation-only duplicates — safe to collapse
`#fff` vs `#ffffff`: 69 sites between them, identical rendering. Same for the whitespace
variants `rgba(0, 0, 0, .16)` / `rgba(0,0,0,.16)` and `rgba(22, 22, 22, .5)`.
`--surface: #fff` (console) and `--surface: #ffffff` (creator) are the same token name, the
same colour, two notations, two sheets. This is the one class of duplicate `T3.2` can collapse
with no thought required.
### H. Font stacks — see §6d
Three mono stacks, two sans stacks. Adopting the superset is a **real rendering change** on
machines missing IBM Plex Mono. Decide in `T3.2`; if adopted, `admin` and `users` need
re-shot baselines — and remember **trap 2**: those two pages are not byte-stable (live
timestamps), so capture twice before believing any diff.
### J. `#262626` — Carbon gray-90, used twice, no token
`wp-chrome.css:31` (dark search field) and `wp-sidenav.css:94` (current row). It is a real
Carbon value that `theme-light.css` simply never declared. Add `--cds-layer-01-inverse:
#262626`? No — cleanest is `--wp-appbar-layer: #262626`, in the appbar group where its two
consumers live.
---
## 9. Tokens read from JavaScript — names that cannot be deleted
`T3.2` says to keep existing names as aliases "where deleting them would touch large amounts
of markup". This is the concrete list. These `var()` references live in **`.js` files**, so a
rename fails silently — no build error, no console warning, just an unstyled element.
| Consumer | Tokens it reads | Count |
|---|---|---|
| `work-package-suite-app.js` | `--border` 15, `--bg` 7, `--danger` 6, `--text-dim` 5, `--primary` 2, `--primary-light` 1, `--text-light` 2, `--text` 1, `--warning` 1, `--mono` 1 | 41 |
| `wp-creation-app.js` | `--text-dim` 8, `--accent` 5, `--accent-amber` 4, `--accent-green` 3, `--red` 3, `--nav-w` 2, `--surface2` 1, `--rail-top` 1 | 27 |
| `admin.js` | `--muted` 14, `--green` 8, `--red` 5, `--amber` 2 | 29 |
| `users.js` | `--muted` 4, `--red` 4, `--s2` 2, `--green` 1 | 11 |
| `field.js` | `--cds-text-helper` 2, `--cds-text-secondary` 1 | 3 |
**111 JS-side references across 23 distinct token names** (21 once the two runtime-set
properties below are set aside). Every one of those names must still resolve after `T3.2`.
Grep before deleting any alias:
```bash
grep -n 'var(--NAME' *.js
```
Two runtime-set properties are declared in no stylesheet and must not be shadowed:
`--wp-chrome-h` (`work-package-suite-app.js:528`) and `--rail-top`
(`wp-creation-app.js:1328`).
---
## 10. The `#0f62fe` count — correcting the wave 0 baseline
`file-map.md` §4 metric 5 records **14 declarations in 4 sheets** and defines the metric as
"the number of stylesheets that declare their own accent token", with a wave 9 target of 1.
**The count is 15, in 5 sheets.** The baseline command misses one:
```bash
grep -nE '^\s*--[a-zA-Z0-9-]+\s*:\s*#0f62fe' *.css # 14 — anchored to ^
```
`console.css:13` packs five declarations onto one line, and `--accent:#0f62fe` is the third of
them. `^\s*--` only ever matches the **first** declaration on a line, so console's accent was
never counted. Corrected command and result:
```bash
grep -ohE '\-\-[a-zA-Z0-9-]+\s*:\s*#0f62fe' *.css | wc -l # 15 declarations
grep -lE '\-\-[a-zA-Z0-9-]+\s*:\s*#0f62fe' *.css | wc -l # 5 sheets
```
| Sheet | Token | Line |
|---|---|---|
| `theme-light.css` | `--cds-interactive-01` + 10 Carbon aliases | 3, 5, 6, 22, 39, 62, 64, 69, 88, 97, 115 |
| `console.css` | `--accent` | **13 — missed by the baseline** |
| `work-package-suite-styles.css` | `--primary` | 2 |
| `wp-chrome.css` | `--wpc-accent` | 25 |
| `wp-creation-styles.css` | `--accent` | 18 |
**The wave 9 target is unchanged: 1 sheet.** The extra sheet does not change the goal, it
changes the count of what has to be removed — 4 page-sheet declarations, not 3.
Two secondary corrections while this is open:
- **Raw occurrences: 30, not 31.** `file-map.md` recorded 31 at wave 0. `T2.2` deleted the
flat strip and took one with it. This is the metric the file map explicitly says *not* to
track ("track the sheet count, not the raw occurrence count") — recorded here only so the
discrepancy is not rediscovered as a defect.
- Current spread of the 30: `theme-light` 11, `wp-chrome` 4, `help.js` 4, `wp-creation-styles`
2, and one each in `console.css`, `work-package-suite-styles`, `wp-sidenav`, `index.html`,
`auth-guard.js`, `work-package-suite-app.js`, `wp-creation-app.js`, `wp-format.js`.
---
## 11. What `T3.2` should actually do, in order
Written as a sequence because the ordering is what keeps the screenshot diff empty.
1. **Delete the dead `var()` fallbacks** (§7, 12 sites). Provably invisible; shrinks the raw
count before anything risky starts.
2. **Add the new canonical tokens** to `theme-light.css` — §2a and §2b — without touching any
consumer. Additive, zero diff.
3. **Convert `console.css`, `work-package-suite-styles.css`, `wp-creation-styles.css` `:root`
blocks to aliases**, one sheet per commit-sized step. Names stay, literals go. Verify §9's
20 JS-read names still resolve.
4. **Convert `wp-chrome.css`'s two `.wp-chrome` blocks** to aliases, preserving the
light/dark switch mechanism exactly.
5. **Convert `wp-sidenav.css`'s 31 raw literals** to the appbar tokens. This is the sheet with
the largest gap between stated intent and mechanism, so it is also the most satisfying.
6. **Convert the raw literals in rules**, sheet by sheet, using §5. Skip everything §7 lists.
7. **Leave every §8 near-duplicate as its own canonical token.** Do not pick winners.
8. Re-run `tests/baseline_shots.py` at both widths on all 7 pages and diff against wave 2.
Capture `admin` and `users` **twice** — trap 2.
9. Update this document's §2 to what was actually built, per `T3.2`'s fourth done-when.
### Backlog entries this task raises
| ID | What | Suggested |
|---|---|---|
| BL-004 | `help.js`'s 52-colour parallel palette in a different design language | wave 9 (`C4`) |
| BL-005 | `auth-guard.js` + `wp-format.js` modal inline styles, 35 raw literals | `T9.5` with `C1` |
| BL-006 | 17 half-pixel font sizes in the creator and chrome | `T7.1` |
| BL-007 | `--radius: 0` contradicted by 45 raw radii in the creator | `T7.1` |
| BL-008 | `#2563d6`, a second brand blue, in `.sop-inherited` and `help.js` | `T3.5` |
---
## 12. Button roles — `T3.5`
Reserved. `T3.5`'s fifth done-when is "button roles are documented in
`docs/reference/tokens.md`"; it fills this section in with the four roles (primary, secondary,
tertiary, destructive) and the mapping of every existing button class to one of them.
Inventory for it to start from — the button classes that exist today, and the two green
action buttons `A5` names:
| Sheet | Classes | Green action? |
|---|---|---|
| `console.css` | `button`, `button.primary`, `button.danger`, `button.mini` | no |
| `work-package-suite-styles.css` | `.add-btn`, `.nav-btn`, `.nav-btn.primary`, `.comments-toggle`, `.header-button` | **yes — `.nav-btn.primary` is `--success` `#198038`** (`:492-498`) |
| `wp-creation-styles.css` | `.btn`, `.btn-ghost`, `.btn-primary`, `.btn-generate`, `.use-btn`, `.add-btn`, `.add-btn-gate`, `.row-del`, `.mode-btn`, `.link-btn`, `.wp-nav-cta` | **yes — `.btn-generate` and `.use-btn` are `--accent-green`** (`:264 :445`) |
| `theme-light.css` | `.wp-appbar-btn`, `.wp-appbar-btn.primary` | no |
| `index.html` inline | `.card-button`, `.comments-toggle`, `.submit-btn`, `.close-btn` | **yes — `.card.complete .card-button`** (`:125-126`) |
Three green-action sites, not two. `Save & View` and `SOP Complete` are the two the review
named; the launcher's completed-SOP card button is the third and is the same defect.
---
## Appendix A — every `theme-light.css` declaration, line by line
`T3.1`'s first done-when is "lists every declaration with file and line". §4 itemises the 82
page-sheet declarations; this is the other 120, so the list is complete rather than grouped.
Column `#` is the line number in `html/theme-light.css`. Read down each column pair in turn.
| # | Token | Value | # | Token | Value | # | Token | Value |
|--:|---|---|--:|---|---|--:|---|---|
| 3 | `--cds-interactive-01` | `#0f62fe` | 43 | `--cds-hover-secondary` | `#4c4c4c` | 83 | `--cds-field` | `#ffffff` |
| 4 | `--cds-interactive-02` | `#393939` | 44 | `--cds-active-secondary` | `#6f6f6f` | 84 | `--cds-field-hover` | `#e8e8e8` |
| 5 | `--cds-interactive-03` | `#0f62fe` | 45 | `--cds-hover-tertiary` | `#0353e9` | 85 | `--cds-border-subtle` | `#e0e0e0` |
| 6 | `--cds-interactive-04` | `#0f62fe` | 46 | `--cds-active-tertiary` | `#002d9c` | 86 | `--cds-border-strong` | `#8d8d8d` |
| 7 | `--cds-ui-background` | `#f4f4f4` | 47 | `--cds-hover-ui` | `#e5e5e5` | 87 | `--cds-border-inverse` | `#393939` |
| 8 | `--cds-ui-01` | `#ffffff` | 48 | `--cds-hover-light-ui` | `#e5e5e5` | 88 | `--cds-border-interactive` | `#0f62fe` |
| 9 | `--cds-ui-02` | `#f4f4f4` | 49 | `--cds-hover-selected-ui` | `#cacaca` | 89 | `--cds-border-subtle-selected` | `#c6c6c6` |
| 10 | `--cds-ui-03` | `#e0e0e0` | 50 | `--cds-active-ui` | `#c6c6c6` | 90 | `--cds-text-primary` | `#161616` |
| 11 | `--cds-ui-04` | `#8d8d8d` | 51 | `--cds-active-light-ui` | `#cacaca` | 91 | `--cds-text-secondary` | `#525252` |
| 12 | `--cds-ui-05` | `#161616` | 52 | `--cds-selected-ui` | `#e5e5e5` | 92 | `--cds-text-placeholder` | `#a8a8a8` |
| 13 | `--cds-text-01` | `#161616` | 53 | `--cds-selected-light-ui` | `#e5e5e5` | 93 | `--cds-text-helper` | `#6f6f6f` |
| 14 | `--cds-text-02` | `#525252` | 54 | `--cds-inverse-hover-ui` | `#353535` | 94 | `--cds-text-on-color` | `#ffffff` |
| 15 | `--cds-text-03` | `#a8a8a8` | 55 | `--cds-hover-danger` | `#ba121b` | 95 | `--cds-text-inverse` | `#f4f4f4` |
| 16 | `--cds-text-04` | `#ffffff` | 56 | `--cds-active-danger` | `#750e13` | 96 | `--cds-text-disabled` | `#bdbdbd` |
| 17 | `--cds-text-05` | `#6f6f6f` | 57 | `--cds-hover-row` | `#f4f4f4` | 97 | `--cds-link-primary` | `#0f62fe` |
| 18 | `--cds-text-error` | `#da1e28` | 58 | `--cds-visited-link` | `#0043ce` | 98 | `--cds-link-secondary` | `#0043ce` |
| 19 | `--cds-icon-01` | `#161616` | 59 | `--cds-disabled-01` | `#f4f4f4` | 99 | `--cds-link-visited` | `#0043ce` |
| 20 | `--cds-icon-02` | `#525252` | 60 | `--cds-disabled-02` | `#bdbdbd` | 100 | `--cds-link-inverse` | `#78a9ff` |
| 21 | `--cds-icon-03` | `#ffffff` | 61 | `--cds-disabled-03` | `#8d8d8d` | 101 | `--cds-link-primary-hover` | `#0353e9` |
| 22 | `--cds-link-01` | `#0f62fe` | 62 | `--cds-button-primary` | `#0f62fe` | 102 | `--cds-icon-primary` | `#161616` |
| 23 | `--cds-link-02` | `#0043ce` | 63 | `--cds-button-secondary` | `#393939` | 103 | `--cds-icon-secondary` | `#525252` |
| 24 | `--cds-inverse-link` | `#78a9ff` | 64 | `--cds-button-tertiary` | `#0f62fe` | 104 | `--cds-icon-on-color` | `#ffffff` |
| 25 | `--cds-field-01` | `#ffffff` | 65 | `--cds-button-danger-primary` | `#da1e28` | 105 | `--cds-icon-inverse` | `#f4f4f4` |
| 26 | `--cds-field-02` | `#f4f4f4` | 66 | `--cds-button-danger-secondary` | `#da1e28` | 106 | `--cds-icon-disabled` | `#bdbdbd` |
| 27 | `--cds-inverse-01` | `#ffffff` | 67 | `--cds-background` | `#f4f4f4` | 107 | `--cds-support-error` | `#da1e28` |
| 28 | `--cds-inverse-02` | `#393939` | 68 | `--cds-background-inverse` | `#161616` | 108 | `--cds-support-success` | `#198038` |
| 29 | `--cds-support-01` | `#da1e28` | 69 | `--cds-background-brand` | `#0f62fe` | 109 | `--cds-support-warning` | `#f1c21b` |
| 30 | `--cds-support-02` | `#198038` | 70 | `--cds-background-active` | `#e5e5e5` | 110 | `--cds-support-info` | `#0043ce` |
| 31 | `--cds-support-03` | `#f1c21b` | 71 | `--cds-background-hover` | `#e8e8e8` | 111 | `--cds-support-error-inverse` | `#fa4d56` |
| 32 | `--cds-support-04` | `#0043ce` | 72 | `--cds-background-selected` | `#e5e5e5` | 112 | `--cds-support-success-inverse` | `#42be65` |
| 33 | `--cds-inverse-support-01` | `#fa4d56` | 73 | `--cds-background-selected-hover` | `#cacaca` | 113 | `--cds-support-warning-inverse` | `#f1c21b` |
| 34 | `--cds-inverse-support-02` | `#42be65` | 74 | `--cds-layer` | `#ffffff` | 114 | `--cds-support-info-inverse` | `#4589ff` |
| 35 | `--cds-inverse-support-03` | `#f1c21b` | 75 | `--cds-layer-accent` | `#f4f4f4` | 115 | `--cds-interactive` | `#0f62fe` |
| 36 | `--cds-inverse-support-04` | `#4589ff` | 76 | `--cds-layer-accent-hover` | `#e8e8e8` | 116 | `--cds-shadow` | `rgba(0, 0, 0, .16)` |
| 37 | `--cds-overlay` | `rgba(22, 22, 22, .5)` | 77 | `--cds-layer-accent-active` | `#e0e0e0` | 170 | `--wp-appbar-bg` | `#161616` |
| 38 | `--cds-danger` | `#da1e28` | 78 | `--cds-layer-hover` | `#e8e8e8` | 171 | `--wp-appbar-fg` | `#ffffff` |
| 39 | `--cds-focus` | `#0f62fe` | 79 | `--cds-layer-active` | `#e5e5e5` | 172 | `--wp-appbar-fg-dim` | `#c6c6c6` |
| 40 | `--cds-hover-primary` | `#0353e9` | 80 | `--cds-layer-selected` | `#e5e5e5` | 173 | `--wp-appbar-border` | `#6f6f6f` |
| 41 | `--cds-active-primary` | `#002d9c` | 81 | `--cds-layer-selected-hover` | `#cacaca` | 174 | `--wp-appbar-hover` | `#353535` |
| 42 | `--cds-hover-primary-text` | `#0043ce` | 82 | `--cds-layer-selected-inverse` | `#393939` | 175 | `--wp-appbar-height` | `48px` |
**120 declarations.** Lines 3116 are the Carbon g10 set; lines 170175 are the app-shell
group added by the suite. Many share a literal by design — that is Carbon's v10→v11 alias
layer, not the `S5` defect. See the note at the end of §3.

View File

@@ -116,3 +116,67 @@ deliberately deferred.
the task must leave byte-identical, and would be thrown away in wave 2.
- **Suggested wave or follow-up:** `T2.2` should ship the drawer with adequate targets;
`C1`'s audit at `T9.5` confirms it app-wide.
### BL-004 — `help.js` ships a 52-colour palette in a different design language
- **Found during:** T3.1
- **Where:** `html/help.js:79` (the injected `<style>`)
- **What:** the help centre injects its own stylesheet with **52 colour literals and zero
`var()`**. It is not a fourth copy of the suite palette — it is a different one: slate
(`#27313f`, `#334155`, `#e2e8f0`), violet (`#7c3aed`, `#f3e8ff`), its own blue
(`rgba(37,99,214,.15)`, see BL-008) and its own greys (`#fafbfc`, `#eef1f6`, `#f4f6f9`,
`#f7f8fa`). It loads on the launcher, SOP wizard, creator and field view.
- **Why not now:** `T3.2`'s contract is "no rendered change", and converting this palette is a
restyle, not a consolidation — it would change the help centre on four pages and break the
empty-screenshot-diff done-when. The token rule in `CLAUDE.md` does reach it, so it is real
work, not a non-issue.
- **Suggested wave or follow-up:** wave 9, alongside `C4`. Documented in
`docs/reference/tokens.md` §1.
### BL-005 — Two modals are styled entirely by inline `style=` attributes
- **Found during:** T3.1
- **Where:** `html/auth-guard.js:67-92` (change-password) and `html/wp-format.js:120-150`
(preferences)
- **What:** 35 raw colour literals between them — `#0f62fe`, `#8d8d8d`, `#e0e0e0`, `#defbe6`,
`#fff1f1`, `#0e6027`, `rgba(20,30,50,.5)` and so on — written into `style=` strings, so no
stylesheet can reach them and no token can either.
- **Why not now:** they are markup built by JS, not a stylesheet, so they are outside `T3.2`'s
four-sheet surface. Both dialogs are rebuilt as accessible components under `C1`.
- **Suggested wave or follow-up:** `T9.5`, with the `C1` audit.
### BL-006 — Seventeen half-pixel font sizes
- **Found during:** T3.1
- **Where:** `html/wp-creation-styles.css` (14) and `html/wp-chrome.css` (3)
- **What:** `9.5px`, `10.5px`, `11.5px`, `12.5px`, `13.5px` sit inside an otherwise integer
type scale of 27 distinct sizes. They round inconsistently between engines and there is no
reason for any of them.
- **Why not now:** retiring them moves text on every creator screen; `T3.2` forbids rendered
change and `T7.1` re-lays-out this page anyway.
- **Suggested wave or follow-up:** `T7.1`. See `docs/reference/tokens.md` §6a.
### BL-007 — `--radius: 0` is contradicted 45 times in the sheet that declares it
- **Found during:** T3.1
- **Where:** `html/wp-creation-styles.css:26` and 45 raw `border-radius` values in the same file
- **What:** the creator declares `--radius: 0` and honours it 23 times, then writes `2px 3px
4px 5px 6px 8px 9px 10px 12px 14px 20px 50%` directly in 45 other places, plus two
asymmetric CTA radii at `:707` and `:716`. Square corners are the Carbon idiom and the
intent everywhere else in the suite; this one sheet drifted.
- **Why not now:** changing 45 radii is the most visible diff available, and `T3.2` must
produce none.
- **Suggested wave or follow-up:** `T7.1`. See `docs/reference/tokens.md` §6c.
### BL-008 — There is a second brand blue: `#2563d6`
- **Found during:** T3.1
- **Where:** `html/wp-creation-styles.css:565`, `html/help.js`, `html/wp-creation-app.js:1257`
- **What:** `.sop-inherited` — the highlight on every field a work package inherited from its
SOP — fills with `rgba(37,99,214,0.07)`, which is **`#2563d6`**, not the suite's `#0f62fe`.
`help.js` carries the same blue at `.15` alpha and the print window uses it solid for
headings. At 7% nobody has noticed, but "one accent colour" is not currently true even after
the four token systems collapse to one.
- **Why not now:** swapping it changes a rendered fill, which `T3.2` forbids. It is the same
conversation as the green action buttons.
- **Suggested wave or follow-up:** `T3.5`, with `A5`. See `docs/reference/tokens.md` §8-E.