Files
Project-SDE-WP-Suite/docs/reference/tokens.md
n.siegfried 0e40e967a0 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>
2026-08-15 18:24:52 -05:00

727 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.