fix(design): meet AA on tinted surfaces, and stop the footer inverting in dark
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m11s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 12s
PR Checks / Build Frontend (no push) (pull_request) Successful in 52s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 3m6s
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m11s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 12s
PR Checks / Build Frontend (no push) (pull_request) Successful in 52s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 3m6s
Full audit across home, search, rankings, admissions, compare, and primary / secondary / special / no-data school pages, in both themes, measuring computed styles rather than reading CSS. Contrast: the status hues were specced against --bg-primary, but they are used as chip text on their own tint, which sits on cards and secondary surfaces rather than the page ground. Measured in the wild they were 3.85–4.44:1 — under AA — on Ofsted badges, delta chips, report-card chips and metric values, i.e. most of the product's actual signal. Darkened the light hues (#0e6e66 → #0b625a, #9a5b00 → #7f4a00) and lifted the dark teal (#3fb3a4 → #4fc0b0) so each clears AA on its own tint, which is the worst case rather than the easy one. Chart and series ramps follow. The footer was painting itself with a text token and lettering itself with a background token: `background: var(--text-primary); color: var(--bg-secondary)`. That reads correctly in one theme and inverts in the other — in dark mode it became a light slab at the bottom of a dark page, with amber section headings at 1.98:1. Added --surface-sunken and its on-* companions, which stay dark in BOTH themes (deliberately not --surface-inverse, whose whole job is to flip), and moved the footer onto them. Section headings were also using a status hue purely as decoration; they are now a muted on-surface token. The "Open full map" pill was a fixed white background with a themed text colour, so in dark mode it rendered light violet on white at 1.84:1. Both sides are token-driven now. Tabular numerals are now the default for .main rather than per-component opt-in, with prose opting back out — a handful of figures (miniNatPill, compareRowVal, factVal) had been missed by the class-name-based pass. Added a two-theme AA gate over home, rankings and admissions. It waits for `transition: color` to settle first: an earlier measurement pass read mid-transition values and reported seven failures that did not exist at rest. Worth stating plainly — most of what a naive audit flags here is its own artifact, and the check has to account for that to be worth having. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+36
-15
@@ -45,17 +45,17 @@
|
||||
--brand-on: #fcfcfa; /* text/icon sitting on a brand fill */
|
||||
|
||||
/* ── Status: above / at / below the comparison point ────────────── */
|
||||
--status-above: #0e6e66; /* 5.2:1 on --bg-primary */
|
||||
--status-above-bg: rgba(14, 110, 102, 0.10);
|
||||
--status-below: #9a5b00; /* 4.8:1 on --bg-primary */
|
||||
--status-below-bg: rgba(154, 91, 0, 0.11);
|
||||
--status-above: #0b625a; /* 6.6:1 on --bg-primary, 5.1:1 on its own tint */
|
||||
--status-above-bg: rgba(11, 98, 90, 0.10);
|
||||
--status-below: #7f4a00; /* 6.3:1 on --bg-primary, 5.1:1 on its own tint */
|
||||
--status-below-bg: rgba(127, 74, 0, 0.11);
|
||||
--status-at: var(--text-muted);
|
||||
--status-at-bg: rgba(92, 101, 112, 0.10);
|
||||
|
||||
/* ── Charts: the same three hues, extended by lightness only ────── */
|
||||
--chart-1: #584a9b;
|
||||
--chart-2: #0e6e66;
|
||||
--chart-3: #9a5b00;
|
||||
--chart-2: #0b625a;
|
||||
--chart-3: #7f4a00;
|
||||
--chart-4: #8a7cc9;
|
||||
--chart-5: #3e9c92;
|
||||
--chart-6: #c9903d;
|
||||
@@ -68,8 +68,8 @@
|
||||
moderate saturation, and every one clears AA on --bg-primary, so they
|
||||
read as one family and work as legend text as well as chart lines. */
|
||||
--series-1: #584a9b;
|
||||
--series-2: #0e6e66;
|
||||
--series-3: #9a5b00;
|
||||
--series-2: #0b625a;
|
||||
--series-3: #7f4a00;
|
||||
--series-4: #a03a5e;
|
||||
--series-5: #2f5f8f;
|
||||
--series-6: #4a6b2f;
|
||||
@@ -93,6 +93,16 @@
|
||||
--phase-nursery-bg: rgba(122, 85, 96, 0.10);
|
||||
--phase-nursery-text: #64454f;
|
||||
|
||||
/* ── Sunken surface: the footer, and anything meant to read as a dark
|
||||
anchor band. Deliberately NOT --surface-inverse: "inverse" flips
|
||||
with the theme, which turned the footer into a light slab at the
|
||||
bottom of a dark page. This stays dark in both. ──────────────── */
|
||||
--surface-sunken: #16202a;
|
||||
--on-sunken: #e4e2dc;
|
||||
--on-sunken-muted: #b3b8bd;
|
||||
--on-sunken-faint: #7f878f;
|
||||
--on-sunken-link: #b9aeef;
|
||||
|
||||
/* ── Medals: rankings podium. Metal, not palette — kept legible on
|
||||
both grounds rather than literally gold/silver/bronze. ───────── */
|
||||
--medal-gold: #a67c00;
|
||||
@@ -104,8 +114,8 @@
|
||||
an arbitrary alpha reads the raw channels from here. Keep these in
|
||||
sync with the hex tokens above — they are the same colours. */
|
||||
--brand-rgb: 88, 74, 155;
|
||||
--status-above-rgb: 14, 110, 102;
|
||||
--status-below-rgb: 154, 91, 0;
|
||||
--status-above-rgb: 11, 98, 90;
|
||||
--status-below-rgb: 127, 74, 0;
|
||||
--ink-rgb: 22, 32, 42;
|
||||
--text-inverse-rgb: 247, 247, 244;
|
||||
--shadow-rgb: 22, 32, 42;
|
||||
@@ -185,14 +195,14 @@
|
||||
--brand-bg: rgba(156, 140, 232, 0.14);
|
||||
--brand-on: #10151b;
|
||||
|
||||
--status-above: #3fb3a4; /* 7.2:1 */
|
||||
--status-above-bg: rgba(63, 179, 164, 0.14);
|
||||
--status-above: #4fc0b0; /* 8.4:1 on --bg-primary, 4.8:1 on its own tint */
|
||||
--status-above-bg: rgba(79, 192, 176, 0.14);
|
||||
--status-below: #d99b2e; /* 7.7:1 */
|
||||
--status-below-bg: rgba(217, 155, 46, 0.14);
|
||||
--status-at-bg: rgba(141, 153, 166, 0.14);
|
||||
|
||||
--chart-1: #9c8ce8;
|
||||
--chart-2: #3fb3a4;
|
||||
--chart-2: #4fc0b0;
|
||||
--chart-3: #d99b2e;
|
||||
--chart-4: #6f5fc4;
|
||||
--chart-5: #2b8a7e;
|
||||
@@ -201,7 +211,7 @@
|
||||
--chart-reference: #8d99a6;
|
||||
|
||||
--series-1: #9c8ce8;
|
||||
--series-2: #3fb3a4;
|
||||
--series-2: #4fc0b0;
|
||||
--series-3: #d99b2e;
|
||||
--series-4: #e07a9d;
|
||||
--series-5: #6fa8dc;
|
||||
@@ -225,12 +235,18 @@
|
||||
--phase-nursery-bg: rgba(191, 152, 163, 0.14);
|
||||
--phase-nursery-text: #d1aeb8;
|
||||
|
||||
--surface-sunken: #0a0e13;
|
||||
--on-sunken: #d8dde2;
|
||||
--on-sunken-muted: #9aa4ae;
|
||||
--on-sunken-faint: #6d777f;
|
||||
--on-sunken-link: #b0a3ee;
|
||||
|
||||
--medal-gold: #d4a72c;
|
||||
--medal-silver: #a8b0bb;
|
||||
--medal-bronze: #c08552;
|
||||
|
||||
--brand-rgb: 156, 140, 232;
|
||||
--status-above-rgb: 63, 179, 164;
|
||||
--status-above-rgb: 79, 192, 176;
|
||||
--status-below-rgb: 217, 155, 46;
|
||||
--ink-rgb: 228, 233, 238;
|
||||
--text-inverse-rgb: 16, 21, 27;
|
||||
@@ -285,6 +301,10 @@ button {
|
||||
|
||||
/* Every digit that could line up in a column does. This is a data product;
|
||||
proportional numerals in a results table read as amateur. */
|
||||
/* The interface is mostly figures, so tabular is the default here rather
|
||||
than something each component has to remember. Running prose opts back out
|
||||
below — proportional figures read better in a sentence. */
|
||||
.main,
|
||||
table,
|
||||
[data-numeric] {
|
||||
font-variant-numeric: tabular-nums;
|
||||
@@ -293,6 +313,7 @@ table,
|
||||
/* Prose gets the serif; the interface never does. */
|
||||
.prose {
|
||||
font-family: var(--font-prose);
|
||||
font-variant-numeric: normal;
|
||||
font-size: var(--step-0);
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user