diff --git a/public/css/styles.css b/public/css/styles.css index 543e95c..8074e4a 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -21,8 +21,8 @@ widgets (date picker, scrollbars, selects). ------------------------------------------------------------- */ :root { - /* Hex, not oklch: an engine below Chromium 111 drops an oklch token and the primary button - loses its background. */ + /* Hex, never oklch: below Chromium 111 `var(--accent)` is invalid at computed-value time and the + primary button loses its background. A fallback declaration cannot catch that. */ /* ---- raw LIGHT palette ---- */ --l-bg:#f3f3f4; --l-surface:#ffffff; --l-surface-2:#f6f6f7; --l-surface-3:#fbfbfc; --l-border:#e5e5e8; --l-border-2:#d6d6da; diff --git a/src/ui/stylesheet-floor.test.ts b/src/ui/stylesheet-floor.test.ts index 4027031..b4d919a 100644 --- a/src/ui/stylesheet-floor.test.ts +++ b/src/ui/stylesheet-floor.test.ts @@ -6,9 +6,10 @@ import { fileURLToPath } from "node:url"; const cssDir = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "public", "css"); -test("no stylesheet declares an oklch() colour, which an engine below Chromium 111 drops", () => { - // A dropped custom property leaves var(--accent) invalid: white text on no background. - for (const file of readdirSync(cssDir).filter((f) => f.endsWith(".css"))) { - assert.ok(!/oklch\(/.test(readFileSync(join(cssDir, file), "utf8")), `${file} declares oklch()`); - } -}); +// A custom property holding oklch() passes unchecked on an engine below Chromium 111, so the +// var() that reads it is invalid at computed-value time: white text on no background. +for (const file of readdirSync(cssDir).filter((f) => f.endsWith(".css"))) { + test(`${file} declares no oklch() colour`, () => { + assert.ok(!/oklch\(/i.test(readFileSync(join(cssDir, file), "utf8"))); + }); +} diff --git a/todo.md b/todo.md index e0d8c9e..294247d 100644 --- a/todo.md +++ b/todo.md @@ -6,13 +6,14 @@ `Bar = 1` -`Next ID = 35` +`Next ID = 36` ## Items | ID | Release | Blocked by | Exempt | Item | L | E | I | R | S | Moves | Score | |---|---|---|---|---|---|---|---|---|---|---|---| | 29 | 0.4.21 | | defect | **Show the whole nav tree on an engine without `:has()`, and fold it only where `:has()` works.** | 2 | 2 | 2 | 4 | 3 | 4 by 6 | 26.9 | +| 35 | 0.4.21 | | defect | **Raise the contrast of the dark-mode primary button's white text and of the light-mode status badges' text to 4.5:1.** | 1 | 2 | 1 | 2 | 2 | 6 by 3 | 18.0 | | 31 | 0.4.21 | | | **Delete the design-preview rules in `public/css/auth.css` that no view uses.** | 1 | 1 | 1 | 1 | 2 | code health by 2, 8 by 1 | 13.3 | | 26 | 0.4.21 | | | **Add a domain glossary and the project's intended horizon to the README.** | 1 | 2 | 1 | 2 | 3 | 9 by 3, code health by 2 | 11.9 | | 8 | 0.4.21 | | | **Run the visual E2E specs at viewports from a large desktop down to a small phone.** | 2 | 1 | 1 | 2 | 4 | code health by 3 | 9.0 | @@ -48,6 +49,12 @@ README → "Two browser floors": Chromium 87 must reach every page. `public/css/ no nested entry can be reached. Hide the children only inside `@supports selector(:has(a))`. The theme switch is inert there too, since every theme rule is a `:has()`: hide it under the same guard. +### 35. Raise the contrast of the dark-mode primary button's white text and of the light-mode status badges' text to 4.5:1. + +Measured in `public/css/styles.css`: white text on the dark-mode primary button (`--d-accent` +`#6ba0e8`) is 2.69:1, and the text of the light-mode pos, warn and info badges on their backgrounds 4.17, 4.40 and 4.48:1. WCAG AA +needs 4.5:1 for normal text. + ### 31. Delete the design-preview rules in `public/css/auth.css` that no view uses. `.auth-view`, the `:target` screen switch, `.tpl-*`, the `fstate`/`rstate` radios and the