The set mixed colour emoji with dingbats, and the same glyph read as two things partly BECAUSE emoji render as per-platform artwork. The system chosen: monochrome text-presentation glyphs - the suite is classic-script vanilla HTML with no bundler, so an SVG sprite or icon font is a new asset pipeline, while text glyphs render through the same font stack as the words beside them. The enforceable form of "renders identically on Windows, macOS and a tablet": no emoji-range codepoint and no U+FE0F selector anywhere in UI source, swept by the probe on every run. Converted: green-check/red-cross emoji in the admin and users consoles to checkmark/cross, no-entry to circled-slash (blocked/on hold), the lock to the pencil already meaning "edit with a logged reason" on sign-offs, the star to the diamond, the folder to the reference marker, the side nav's lightning to the gear, and the WATCH glyph (U+231A - emoji-presentation BY DEFAULT per Unicode) to a text-presentation clock face. Dropped where the label already carried the meaning: lightning on Save & view, the camera on Add photo, the page/frame pictograms on file rows (the filename is the label). Stale help copy fixed while its emoji left: it still described the pre-T9.4 "Load sample" and the pre-T7.10 "Usage Logs" locations. The meaning-to-icon mapping is in docs/reference/tokens.md - one meaning per glyph, one glyph per meaning, both directions asserted from the document itself; the probe also sweeps every page for glyphs not in the approved set, so an unmapped icon cannot creep in. Verification (each probe run alone): NEW tests/icon_check.py 5/5. Regressions: frame_check 38/38, files_check 36/36, a11y_check 22/22, cards_check 44/44. Items: S6 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1012 lines
63 KiB
Markdown
1012 lines
63 KiB
Markdown
# Token inventory — every declared and raw value in `html/`
|
||
|
||
**Task:** `T3.1`, updated by `T3.2` · **Items:** `C3`, `S5` · **Produced:** August 15, 2026
|
||
**Branch:** `feat/wp-suite-r2-implementation` · **Read by:** `T3.2`, `T3.5`, `T9.3`
|
||
|
||
`T3.1` produced this as the mapping table `T3.2` builds from; `T3.2` has since been built and
|
||
§2 and §11 record what actually shipped rather than what was proposed. Sections 3 to 10 are
|
||
the **pre-`T3.2` inventory** and are deliberately left as they were — they are the evidence
|
||
for the refactor, and rewriting them into the past tense would destroy the before-picture that
|
||
`T9.3` needs. Everything in them was read from the working tree at `b105135` (end of wave 2).
|
||
|
||
**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>` (17–313) | 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.
|
||
|
||
> **Corrected during `T3.2`:** row 7 is not the only inline `<style>`. `login.html` (3 literals)
|
||
> and `field.html` (26 literals, including the ninth amber at §8-K) carry one too, and
|
||
> `work-package-suite.html:407` has a colour in a `style=` attribute. All four were converted.
|
||
> Counting only the launcher's was an inventory miss, not a scoping decision.
|
||
|
||
### 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 canonical set — as built (`T3.2`)
|
||
|
||
`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` |
|
||
|
||
### 2d. What `T3.2` actually built, where it differs from the above
|
||
|
||
`theme-light.css` now holds **191 declarations**: the 114 Carbon g10 values, `--cds-highlight`,
|
||
the 7 app-shell tokens, and **69 `--wp-*` suite tokens**. It is the only sheet in `html/` that
|
||
contains a colour literal. Two changes from §2a's proposal, both for the same reason — a token
|
||
whose *value* is Carbon but whose *role* Carbon does not define belongs in `--wp-*`, or the
|
||
namespace split stops meaning anything:
|
||
|
||
| Proposed in `T3.1` | Built as | Why |
|
||
|---|---|---|
|
||
| `--cds-hover-support-success` | **`--wp-hover-success`** | `#0e6027` is Carbon green-70, but "hover for a green fill" is not a Carbon role — green is not one of its action colours |
|
||
| `--cds-layer-inverse-01` | **`--wp-appbar-layer`** | `#262626` is Carbon gray-90, but the name was invented; it sits in the app-shell group where both its consumers live |
|
||
|
||
Tokens added beyond §2a/§2b, all of them one-offs that still needed a single home — "one place
|
||
a value is defined" applies to a value used once just as much as to one used forty times:
|
||
|
||
| Group | Tokens |
|
||
|---|---|
|
||
| status borders | `--wp-status-{success,error,warning}-border-{a,b,c}` — 7 |
|
||
| surfaces | `--wp-table-zebra`, `--wp-table-row-hover`, `--wp-nav-bg`, `--wp-nav-hover`, `--wp-nav-active`, `--wp-pop-divider`, `--wp-accent-soft-hover` |
|
||
| elevation | `--wp-shadow-{pop,menu,menu-lg,modal,modal-lg,gate,rail,drawer,sticky,navbar,tooltip,toast}` — 12 |
|
||
| scrims | `--wp-scrim-{drawer,cool,cool-modal,cool-strong,neutral,loading,frosted}`, `--wp-on-accent-divider` |
|
||
| type | `--wp-font-sans`, `--wp-font-sans-2`, `--wp-font-mono`, `--wp-font-mono-2`, `--wp-font-mono-3` |
|
||
| spacing / shape | `--wp-s1`…`--wp-s6`, `--wp-ctl`, `--wp-ctl-sm`, `--wp-radius-0`, `--wp-shadow-none` |
|
||
| one-offs | `--wp-tag-super-{bg,text}`, `--wp-term-{bg,fg,pass,fail}`, `--wp-dev-{bg,fg,rule}`, `--wp-sop-inherited-bg`, `--wp-status-warning-text-alt` |
|
||
|
||
**Twelve distinct shadows** is the number that surprised. They were invisible while spread
|
||
across four sheets as inline `box-shadow` values; collected in one block they are obviously
|
||
eleven more than a flat Carbon UI wants. Collapsing them is a rendered change, so not here —
|
||
but they are now countable, which they were not before.
|
||
|
||
---
|
||
|
||
## 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 2–117** and **169–176**.
|
||
|
||
| Lines | Group | Count | Distinct values | Action in `T3.2` |
|
||
|---|---|---|---|---|
|
||
| 3–6 | `--cds-interactive-01..04` | 4 | `#0f62fe` ×3, `#393939` | keep |
|
||
| 7–12 | `--cds-ui-background`, `--cds-ui-01..05` | 6 | `#f4f4f4` ×2, `#ffffff`, `#e0e0e0`, `#8d8d8d`, `#161616` | keep |
|
||
| 13–18 | `--cds-text-01..05`, `--cds-text-error` | 6 | `#161616 #525252 #a8a8a8 #ffffff #6f6f6f #da1e28` | keep |
|
||
| 19–21 | `--cds-icon-01..03` | 3 | `#161616 #525252 #ffffff` | keep |
|
||
| 22–24 | `--cds-link-01`, `-02`, `--cds-inverse-link` | 3 | `#0f62fe #0043ce #78a9ff` | keep |
|
||
| 25–28 | `--cds-field-01/02`, `--cds-inverse-01/02` | 4 | `#ffffff #f4f4f4 #ffffff #393939` | keep |
|
||
| 29–36 | `--cds-support-01..04` + inverse | 8 | `#da1e28 #198038 #f1c21b #0043ce #fa4d56 #42be65 #f1c21b #4589ff` | keep |
|
||
| 37–46 | overlay, danger, focus, hover/active primary·secondary·tertiary | 10 | incl. `#0353e9` ×2, `#002d9c` ×2 | keep |
|
||
| 47–61 | hover/active/selected UI, disabled | 15 | `#e5e5e5` ×4, `#cacaca` ×2, `#c6c6c6`, `#353535`, `#f4f4f4` ×2, `#bdbdbd`, `#8d8d8d`, `#ba121b`, `#750e13`, `#0043ce` | keep |
|
||
| 62–66 | `--cds-button-*` | 5 | `#0f62fe` ×2, `#393939`, `#da1e28` ×2 | keep |
|
||
| 67–89 | v11 background / layer / field / border set | 23 | mostly aliases of the above literals | keep |
|
||
| 90–115 | 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 |
|
||
| 170–175 | `--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 12–20
|
||
|
||
| 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 |
|
||
| 19–20 | `--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 2–17
|
||
|
||
| 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 10–30, 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 19–25, 29–35)
|
||
|
||
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.
|
||
|
||
### K. A ninth amber, four points from the eighth
|
||
|
||
`field.html:35` fills `.pill.warn` with **`#8a6d00`**, where every other warning text in the
|
||
app is `#8e6a00`. Four points apart, same job, and `field.html`'s inline block was not in the
|
||
`T3.1` inventory — §1 listed only the launcher's, and `login.html` and `field.html` also carry
|
||
one. Almost certainly a typo rather than a decision.
|
||
|
||
`T3.2` named it `--wp-status-warning-text-alt` rather than merging it, on the same rule as
|
||
everything else in §8: merging moves a rendered colour. **BL-009**, resolve at `T3.5`.
|
||
|
||
### 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. `T3.2` — what was done, and how it was proved
|
||
|
||
Done in this order, because the ordering is what kept the diff empty:
|
||
|
||
1. **Deleted the 12 dead `var()` fallbacks** (§7). Provably invisible.
|
||
2. **Added the canonical tokens** to `theme-light.css` (§2a, §2b, §2d) without touching a
|
||
consumer. Additive, zero diff.
|
||
3. **Converted the `:root` blocks** of `console.css`, `work-package-suite-styles.css` and
|
||
`wp-creation-styles.css` to aliases. Names stayed; literals went.
|
||
4. **Converted `wp-chrome.css`'s two `.wp-chrome` blocks**, preserving the light/dark switch.
|
||
5. **Converted `wp-sidenav.css`'s 30 raw literals** to the app-bar tokens, which is the sheet
|
||
whose stated intent ("colours come from the bar") and mechanism (hardcoded hex) disagreed.
|
||
Flipping `--wp-appbar-bg` now takes the drawer with it, which is what the comment claimed.
|
||
6. **Converted the raw literals in rules** across all six sheets and all four inline `<style>`
|
||
blocks, skipping everything §7 lists.
|
||
7. **Left every §8 near-duplicate as its own canonical token.** No winners picked.
|
||
|
||
### Result against the done-when list
|
||
|
||
| Check | Result |
|
||
|---|---|
|
||
| exactly one declaration per canonical value; `#0f62fe` → 1 | **met.** One sheet declares it (`theme-light.css`); the 11 occurrences inside it are Carbon's own v10→v11 alias layer, which §3 records as deliberate and not the `S5` defect |
|
||
| no page stylesheet declares a raw **colour** | **met.** 0 literals across all 5 page sheets and all 4 inline `<style>` blocks; `theme-light.css` is the only file in `html/` holding one |
|
||
| no page stylesheet declares a raw **spacing or type** value | **not met, and not achievable under this task's own "change no rendered value"** — see below |
|
||
| screenshot diff empty on all pages at both widths | **superseded by a stronger check** — see below |
|
||
| `docs/reference/tokens.md` updated to what was built | **met** — §2d |
|
||
|
||
### The spacing and type half of check 2
|
||
|
||
Token *declarations* are aliased: `--s1`…`--s6`, `--ctl`, `--ctl-sm`, `--radius`, `--mono`,
|
||
`--sans` all resolve from `theme-light.css` now. But **483 raw spacing values, 281 raw
|
||
font-sizes and 65 raw radii remain inside rules**, 492 of them in the creator.
|
||
|
||
They cannot be tokenised here, and the reason is not effort. §6b measured that the creator's
|
||
spacing is every integer from 1px to 14px — it is not a scale, it is a histogram, and there is
|
||
no token that `padding: 9px 11px` maps to without changing one of the two numbers. `T3.2`
|
||
forbids changing a rendered value, so tokenising them and honouring that constraint are
|
||
mutually exclusive.
|
||
|
||
Stated plainly rather than quietly skipped: **this check is not met.** The colour half, which
|
||
is what `S5` and `C3` are actually about — four sheets each declaring `#0f62fe` — is met in
|
||
full. The spacing and type half is logged as **BL-010** and belongs with the page rebuilds at
|
||
`T5.x` and `T7.1`, where the values are being chosen again anyway.
|
||
|
||
### Why the screenshot check was replaced
|
||
|
||
The done-when asks for an empty screenshot diff. Captured against the wave 2 build, 11 of 14
|
||
shots were pixel-identical and 3 were not: the creator at 1440px and both admin widths.
|
||
Capturing wave 2 **against itself** produced the same 3 differences, at the same bounding box
|
||
(creator@1440: 344,272px, bbox 288,14→1439,4924). Those shots re-render live content, so a
|
||
pixel diff on them cannot distinguish a regression from the clock.
|
||
|
||
**Trap 2 in the task brief is half right and half wrong.** It names `admin` and `users` as the
|
||
unstable pair. `users` is stable at both widths; the actually-unstable third is the **creator
|
||
at 1440px**, and admin's instability is worse than "live timestamps" implies — its captured
|
||
page *height* varies by ~600px between runs.
|
||
|
||
So `tests/token_check.py` was written, and it checks the thing wave 3 actually claims:
|
||
|
||
- every custom property resolves to the same literal it did before, on every page;
|
||
- every element computes the same `color`, `background-color`, four border colours,
|
||
`outline-color`, `box-shadow`, `text-decoration-color`, `caret-color`, `column-rule-color`,
|
||
`font-family`, `font-size`, `font-weight` and `border-radius`.
|
||
|
||
That is strictly stronger than a screenshot: it covers the hover, focus and disabled rules a
|
||
screenshot never exercises, and it is deterministic.
|
||
|
||
Result, wave 2 versus `T3.2`, all 7 pages: **every one of the 178 wave-2 token names resolves
|
||
identically, and all 3,500 elements compute identically.** 213 tokens are new. 16 tokens
|
||
differ in notation only (`#fff` → `#ffffff`, `rgba(0,0,0,0.16)` → `rgba(0, 0, 0, .16)`), which
|
||
is §8-G — the one class of duplicate this task was supposed to collapse.
|
||
|
||
Two things that cost time and are recorded so they do not cost it again:
|
||
|
||
- The element walk was first keyed by sibling index, which reported 55 phantom differences on
|
||
the SOP page. The cause is three JS-injected overlays — `#wp-sync-badge`, `.wp-navscrim` and
|
||
`#wp-sidenav` — appending in whichever order their async work finishes. All three are
|
||
`position: fixed` with their own `z-index`, so the order changes nothing painted. The probe
|
||
now keys by identity. **BL-011.**
|
||
- The comparator normalises notation before reporting, because otherwise it fails on its own
|
||
success. That is safe only because the element comparison is the real evidence: a
|
||
normalisation that hid a genuine change would show up on every element consuming the token.
|
||
|
||
### Backlog entries this work raised
|
||
|
||
| 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` |
|
||
| BL-009 | `#8a6d00`, a ninth amber four points from the eighth, on the field view | `T3.5` |
|
||
| BL-010 | 483 raw spacing, 281 raw font-size and 65 raw radius values in rules | `T5.x` / `T7.1` |
|
||
| BL-011 | Three JS-injected overlays race to append on the SOP page | wave 9 |
|
||
| BL-012 | `admin` and `creator@1440` are not stable enough to screenshot-diff | wave 9 with `C2` |
|
||
|
||
---
|
||
|
||
## 12. Button roles — `A5`, built at `T3.5`
|
||
|
||
**251 buttons across the 7 pages**, counted in the browser with every wizard step, creator
|
||
section and tool panel forced visible — two thirds of them are `display: none` at load and a
|
||
static grep misses them entirely.
|
||
|
||
### The four roles
|
||
|
||
Defined once, in `theme-light.css`, as `--wp-btn-*`. No fifth role exists.
|
||
|
||
| Role | Looks like | For | Tokens |
|
||
|---|---|---|---|
|
||
| **primary** | filled accent, white text | the one action the screen exists for; at most one per view | `--wp-btn-primary-bg/-fg/-hover/-active` |
|
||
| **secondary** | white fill, `--border-strong` hairline, accent on hover | every other real action — the app's workhorse | `--wp-btn-secondary-bg/-fg/-border/-hover-fg` |
|
||
| **tertiary** | no fill, no border, accent text | navigating or undoing | `--wp-btn-tertiary-fg/-hover-fg` |
|
||
| **danger** | outlined red; filled red only where a control is too small for an outline to read | destructive | `--wp-btn-danger-fg/-border/-soft-bg/-fill-bg/-fill-fg` |
|
||
|
||
### Green is a status colour
|
||
|
||
It says *cleared*, *ready*, *complete* — on a dot, a pill, a banner, a badge — and it never
|
||
fills a button. That was the second button language `A5` recorded: `Save & View` and `SOP
|
||
Complete` shouted louder than every other action in the suite while doing nothing more
|
||
dangerous than saving a form.
|
||
|
||
The green did not go anywhere. `.cstatus button.on-cleared`, `.toggle-btn.enabled`,
|
||
`.wp-nav-dot.ok`, `.rb-ready`, `.badge-R`, `.auto-tag` and the launcher card's left border and
|
||
`.card-status` all still carry it — every one of them a state rather than an action.
|
||
|
||
### Every button class, mapped
|
||
|
||
| Class | Role | Where | Changed at `T3.5`? |
|
||
|---|---|---|---|
|
||
| `button` (bare) | secondary | console | tokens only |
|
||
| `button.primary` | primary | console | tokens only |
|
||
| `button.danger`, `button.mini.danger` | danger, outlined | console | tokens only |
|
||
| `button.mini` | secondary | console | — |
|
||
| `.add-btn` | primary | wizard | tokens only |
|
||
| `.nav-btn` | secondary | wizard | tokens only |
|
||
| `.nav-btn.primary` | **primary** | wizard — `SOP complete` | **was green** |
|
||
| `.seq-del` | danger, filled | wizard — a 28px ✕ | tokens only |
|
||
| `.comments-toggle` | secondary | wizard | — |
|
||
| `.header-button`, `.wp-appbar-btn` | secondary on a dark bar | theme | — |
|
||
| `.btn.btn-primary` | primary | creator | tokens only |
|
||
| `.btn.btn-generate` | **primary** | creator — `Save & view` | **was green** |
|
||
| `.use-btn` | **primary** | creator | **was green** |
|
||
| `.btn.btn-ghost` | secondary | creator | tokens only |
|
||
| `.add-btn` (creator) | secondary, dashed | creator | uppercase removed |
|
||
| `.add-btn-gate` | secondary, amber | creator — adds a QC hold | — |
|
||
| `.row-del` | danger, outlined on hover | creator | tokens only |
|
||
| `.wp-nav-cta`, `.wp-nav-cta-more` | primary | creator navigator | tokens only |
|
||
| `.link-btn`, `.lock-edit`, `.cmt-jump` | tertiary | creator | tokens only |
|
||
| `.mode-btn.active` | primary | creator | — |
|
||
| `.cstatus button.on-*` | **status, not a role** | creator — Open / Cleared / N/A | — |
|
||
| `.card-button` | primary | launcher | — |
|
||
| `.card.complete .card-button` | **primary** | launcher | **was green** |
|
||
| `.submit-btn`, `.comments-toggle` | primary | launcher | — |
|
||
| `.close-btn` | secondary | launcher | — |
|
||
| `.wpc-foot-btn` | secondary | shared chrome | tokens only |
|
||
| `.wpc-clear`, `.comments-dropdown-close`, `.modal-close`, `.cmt-x`, `.wp-sidenav-close` | tertiary | everywhere | — |
|
||
| `.wp-navbtn`, `.wp-nav-toggle`, `.wp-sidenav-link`, `.wp-nav-link`, `.wp-nav-item` | tertiary | drawers and rails | — |
|
||
| `.ui-help-fab` | primary | help centre | out of scope — BL-004 |
|
||
| `.dev-toggle` | deliberately invisible | creator | — |
|
||
|
||
Four green action sites, not the two `A5` names. `.use-btn` and the launcher's completed-SOP
|
||
card button never render green in the default fixture, so the review could not have seen them.
|
||
|
||
### Sentence case
|
||
|
||
Applied to **buttons and field labels only**, which is what `A5` scopes it to.
|
||
|
||
The rule: *first word capitalised, everything after it lowercased, except acronyms* (`SOP`,
|
||
`QC`, `WP`, `UPN`, `PM`, `APM`, `CM`, `QM`, `PDF`, `JSON`, `CSV`, `BIM`, `MIMO`) *and external
|
||
proper nouns* (`Excel`, `Acumatica`). Page names get sentence case too when they appear inside
|
||
a sentence-shaped label — "Open the user directory", not "Open the User Directory" — because
|
||
the label is a description, not a title.
|
||
|
||
- **~30 button labels** rewritten across the launcher, wizard, creator, admin and two scripts.
|
||
- **46 field labels** rewritten. Labels carrying markup — a `.req` asterisk, a `.help-tip`
|
||
chip — had only their text nodes transformed, so the markup survives and "first word" means
|
||
the first word of the label rather than of each fragment.
|
||
- **`text-transform: uppercase` removed from four rules**: `.btn` and `.add-btn` (creator
|
||
buttons) and `label` and `.cmt-namebar label` (creator field labels). The mono face, the
|
||
10px size and the tracking are the creator's idiom and are untouched — only the forced
|
||
uppercase goes.
|
||
- **`help.js` was updated too.** It names `Load Sample` and `SOP Complete` in prose, so
|
||
renaming the buttons without it would have left the help centre describing controls that no
|
||
longer exist.
|
||
|
||
### Not touched, deliberately
|
||
|
||
| What | Why |
|
||
|---|---|
|
||
| `console.css` `.card h2` uppercase | `T3.5` says explicitly not to. Confirmed by diff: the only changes to `console.css` in this task are token substitutions, none of them on `.card h2`. |
|
||
| `table.grid th`, `.wp-types-header`, `.dash-table th` | table headers, not buttons or field labels |
|
||
| `.section-label`, `.sub-heading`, `.wpc-proj-kicker`, `.wpc-pop-head`, `.wp-sidenav-sect` | section eyebrows and headings |
|
||
| `.step-tab` uppercase | a stepper tab is neither a button nor a field label, and the stepper is rebuilt at `T7.x`. Logged as **BL-015**. |
|
||
| `.nav-tab` labels (`SOP Configuration`, `Work Package Creation`) | these name the two tools rather than describing an action; they read as titles and are the same strings the launcher cards use. |
|
||
|
||
---
|
||
|
||
## 13. Wave 3 exit — everything wave 3 changed on screen
|
||
|
||
`wave-3.md` asks for "no unintended visual change on any page versus wave 2". Measured with
|
||
`tests/token_check.py`, wave 2 (`b105135`) against the end of wave 3, all 7 pages:
|
||
|
||
**7 elements changed. All 7 are the fixes the wave was for.**
|
||
|
||
| Page | Element | Change | Task |
|
||
|---|---|---|---|
|
||
| sop | `#role_super_name.user-pick` | `#f4f4f4` → `#ffffff`, border `#e0e0e0` → `#8d8d8d` | `T3.4` (`A3`/`F5`) |
|
||
| sop | `#role_foreman_name.user-pick` | same | `T3.4` |
|
||
| sop | `#sop-complete-btn.nav-btn.primary` | `#198038` → `#0f62fe` | `T3.5` (`A5`) |
|
||
| sop | `#wp-gate button.nav-btn.primary` | `#198038` → `#0f62fe` | `T3.5` |
|
||
| creator | `#sticky-save .btn-generate` | `#198038` → `#0f62fe` | `T3.5` |
|
||
| creator | `.nav-row .btn-generate` | `#198038` → `#0f62fe` | `T3.5` |
|
||
| creator | `#hold-modal .btn-generate` | `#198038` → `#0f62fe` | `T3.5` |
|
||
|
||
Every other element on every page — 3,493 of them — computes exactly what it computed at the
|
||
end of wave 2, and all 178 wave-2 token names resolve to the same literals. `T3.2`'s
|
||
consolidation of five token systems into one changed nothing on screen, which was its whole
|
||
contract.
|
||
|
||
**Three fixes are not visible in that table and are verified another way**, because a computed
|
||
-style diff cannot see them:
|
||
|
||
| Fix | Why it is invisible here | How it was verified |
|
||
|---|---|---|
|
||
| `.card.complete .card-button` green → primary | needs a completed SOP; the fixture has none | source diff |
|
||
| `.use-btn` green → primary | needs a suggested value to be offered | source diff |
|
||
| Sentence case, ~30 buttons + 46 labels | `token_check` fingerprints computed style, not text or `text-transform` | the button inventory: 0 uppercase labels, 251 buttons still present |
|
||
| Focus rings | `:focus` is not in the fingerprint | measured directly with CDP focus emulation — see `T3.4` |
|
||
|
||
### Exit criteria
|
||
|
||
- [x] one token source of truth; page sheets alias only — `theme-light.css` is the only file
|
||
in `html/` containing a colour literal
|
||
- [x] `#0f62fe` declared once — one sheet, down from five
|
||
- [x] no unintended visual change versus wave 2 — 7 changes, 7 intended
|
||
- [x] fields look editable, buttons speak one language
|
||
- [ ] **not met:** `T3.2`'s "no page stylesheet declares a raw spacing or type value" — colour
|
||
is complete, spacing and type are **BL-010**, and §11 explains why the two halves of that
|
||
check cannot both be satisfied in the same task
|
||
|
||
---
|
||
|
||
## 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 3–116 are the Carbon g10 set; lines 170–175 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.
|
||
|
||
## Icons (S6 / T9.3)
|
||
|
||
One system: **monochrome text-presentation glyphs**, chosen because the suite
|
||
is classic-script vanilla HTML with no bundler — an SVG sprite or icon font is
|
||
a new asset pipeline, while text glyphs render through the same font stack as
|
||
the words beside them. The trade accepted: text glyphs vary slightly by font,
|
||
but never flip into per-platform colour artwork the way emoji do, which is the
|
||
failure S6 names. **No emoji anywhere in the UI**; `tests/icon_check.py`
|
||
sweeps every page for emoji-range codepoints and the U+FE0F emoji-presentation
|
||
selector on every run.
|
||
|
||
One meaning per glyph, one glyph per meaning:
|
||
|
||
| Meaning | Glyph | Codepoint | Notes |
|
||
|---|---|---|---|
|
||
| done / ok / success | ✓ | U+2713 | replaced emoji ✅ |
|
||
| close / remove / failure | ✕ | U+2715 | replaced emoji ❌ |
|
||
| needs attention / warning | ⚠ | U+26A0 | text presentation |
|
||
| blocked / on hold | ⊘ | U+2298 | replaced emoji ⛔ |
|
||
| edit with a logged reason | ✎ | U+270E | replaced emoji 🔒; same meaning on sign-off overrides |
|
||
| revert / refresh | ↺ / ↻ | U+21BA / U+21BB | direction distinguishes undo from reload |
|
||
| settings / admin | ⚙ | U+2699 | replaced ⚡ on the side nav |
|
||
| export / download | ⤓ | U+2913 | |
|
||
| import / upload | ⤒ | U+2912 | |
|
||
| key point (help copy) | ◆ | U+25C6 | replaced emoji ⭐ |
|
||
| reference link | ▸ | U+25B8 | replaced emoji 📁 |
|
||
| info tooltip badge | ⓘ | U+24D8 | the `.help-tip` component (S8/T9.5) |
|
||
| back / navigation | ← ‹ › → | U+2190 U+2039 U+203A U+2192 | |
|
||
| views (nav) | ◔ ▤ ▦ ▧ | U+25D4 U+25A4 U+25A6 U+25A7 | one per view, never reused |
|
||
| drag handle | ⣿ | U+283F | sequence reordering |
|
||
| home | ⌂ | U+2302 | side nav |
|
||
| search | ⌕ | U+2315 | app bar |
|
||
| print / save PDF | ⎙ | U+2399 | |
|
||
| power / sign out | ⏻ | U+23FB | side nav |
|
||
| sort direction | ▲ ▼ | U+25B2 U+25BC | column headers, paired |
|
||
| in the QA queue | ◉ | U+25C9 | the CR-014 banner |
|
||
| clock / language & time | ◷ | U+25F7 | replaced ⌚ U+231A, which is emoji-presentation by default |
|
||
| menu (off-canvas) | ☰ | U+2630 | app bar |
|
||
| people / directory | ☺ | U+263A | side nav; text presentation |
|
||
| field view | ⚒ | U+2692 | side nav; text presentation |
|
||
| password / key | ⚿ | U+26BF | side nav |
|
||
|
||
Dropped rather than mapped: ⚡ on action buttons (the label carries the
|
||
action), 📷 on “Add photo” (labelled), 📄/🖼 on file rows (the filename is the
|
||
label; a pictogram repeating “this is a file” said nothing). Every remaining
|
||
glyph sits beside visible text or carries an accessible name — none is the
|
||
only carrier of meaning.
|