Foundations

Colour

Twenty two raw values and twenty one roles. A component never reads a value from the top half of this page: colour is the one thing a theme and a rebrand override, so it is read through a role or not at all. Geometry goes the other way and is read straight from the primitive, because it has nothing to override.

Primitive, the raw values

Fourteen of these are the product. Nine came off brand-plate-j.png, eight as pixels and one measured, and five are derived. The eight below the rule are the light end of the same ramp, added at step 3 of this stage, and they are the only values this stage introduced. Every one carries where it came from.

The warm neutral ramp, and it carries the whole console

--warm-950#11110f · pixel of plate J, GROUND
--warm-900#171714 · pixel of plate J, detail pane
--warm-850#232219 · derived from the ground
--warm-800#2a2418 · pixel of plate J, active row
--warm-500#675f50 · pixel of plate J, RULE
--warm-400#7b7260 · derived, the rule hue raised to clear 3:1
--warm-300#9d9182 · derived, severity medium
--warm-200#aaa397 · pixel of plate J, SECONDARY
--warm-50#e9e4da · pixel of plate J, TEXT

Amber, the one saturated hue the console spends

--amber-500#d29c3f · pixel of plate J, ACCENT
--amber-950#18140e · measured on plate J, text on Accept

Attribute A2 says saturation is scarce, and on this product that is a number rather than a stance: the accent does four jobs and no fifth, counted in the DOM on the finished screen rather than asserted. Latitude, the live state, where you are, and the row being decided with its primary action.

The failure hue and the severity ramp

--clay-500#b25d44 · pixel of plate J, FAILURE. No role: one use in the product and it is this swatch
--clay-400#d9704f · derived, severity high
--warm-300#9d9182 · severity medium
--slate-300#828e96 · severity low, the only cool value anywhere

The ramp descends in chroma and not in loudness. On a dark ground every value has to clear 4.5:1, which compresses the whole ramp into 4.6 to 6.5, so brightness cannot carry it. Warm to cool, and it never reaches green: a low severity case is not a resolved one, and green would say it was. Nothing in this product is green anywhere, including the six state chips, because they are positions and not outcomes.

The light end of the same ramp, and it is all this stage added

A role without a pair is not allowed and the ramp above has no light end, so eight values were derived by the method the product already used for --warm-850 and --warm-400: hold the plate's hue and saturation, move lightness until the threshold is met. Nothing here is sampled from anywhere new and nothing here is a second palette.

--warm-0#f8f7f4 · TEXT hue at lightness 96.5. The light page
--warm-25#f1ede7 · the same at 92.5. 1.09 off the page, against the dark pair's 1.05
--warm-100#e5e3de · RULE hue, lightened to 1.20. Mirrors --warm-850 at 1.18
--amber-100#f2e1c6 · ACCENT hue, lightened to 1.20. Mirrors --warm-800 at 1.23
--amber-700#835e1f · ACCENT hue, darkened until it clears 4.5 on the worst light ground
--clay-600#aa4525 · the same method, severity high
--warm-600#6e6356 · severity medium
--slate-500#5c666d · severity low

Semantic, the roles

Every role names the surface it paints, because the surface decides the threshold. One role may not paint two surfaces even when the purpose is one and the value is identical: a fill role dropped onto a small bold label passes as a surface and fails as text, and a table of text and background pairs cannot see it, because nobody declared it as text.

Both themes are shown at once, on purpose. Each card is split: the left half is the theme the product ships and the right half is its pair. Neither half follows the switcher in the panel, because the pairs were written as material at step 3 and a page that showed only the current one would hide half of what it documents.

Contrast, computed in this page

Not transcribed. Every figure below is measured when the page renders, by painting each role onto each ground and reading the result back, so a token that changes changes this table with it. Every role is tabulated, not only the ones somebody called textual, because that is exactly where a fill role painting a label would hide.

Thresholds: 4.5:1 for ink, dropping to 3:1 at 24px or at 19px bold. 3:1 for fill and line, WCAG 1.4.11, non-text contrast. Eight rows are exempt and each carries its reason in the verdict: a ground is not a boundary, a divider is not a control, and a decorative glyph is not text. The exemption is written rather than assumed, which is the only way the next reader can tell a decision from an oversight.

RolePaintsMeasured against DarkLightFloorVerdict

The two lines that are below a floor on purpose

--line-separator separates and never carries meaning, so it sits below every floor deliberately. It is the line between rows, and it lived in four files and in no variable at all until the stage 06 audit found it.

--line-edge draws panel edges at 2.997 in dark and 2.88 in light, and that is allowed for exactly what it does. WCAG 1.4.11 covers what identifies a control, not a divider. Anything that is the boundary of a control takes --line-control, which clears 3:1 from both directions. This was recorded at stage 06 as sitting at "exactly 3.00", which was a rounded number reported as a threshold met, and the recomputation corrected it.