commit 61748ae16daf20881a12374df857d8310ce4b5e6
parent 3ff98a839f999d1fc2fb40c39da02ddb0a9539b3
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Tue, 29 Sep 2026 22:52:37 -0400
common, homepage: Other wears its own token, `--chart-other` (review M1)
tokens.css gains `--chart-other` in both chart blocks: Light #3e545c
(7.36:1 on the ground, 7.99:1 on the chart surface; every CVD pair with a
slot clears 8), Dark #62625c (3.22 / 3.06:1; magenta at CVD 7.3, in the 6–8
floor band), each with its per-slot numbers. OTHER_COLOR points at it, so
Other no longer shares the axis labels' colour and clears the CVD floor
against every slot on both bases (the axis grey was 4.5 / 4.2 against
magenta). The chart's header comment carries the new numbers;
`growth-chart.spec.ts` resolves OTHER_COLOR, pins each base's value and
checks it is not the axis colour.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
5 files changed, 45 insertions(+), 21 deletions(-)
diff --git a/common/styles/tokens.css b/common/styles/tokens.css
@@ -255,6 +255,15 @@ html[data-base="light"] {
--chart-surface: #ffffff;
--chart-grid: rgba(22, 28, 33, 0.09);
--chart-axis: #55646e;
+ /* OTHER: the homepage growth chart's band for the sites it groups
+ (homepage/app/lib/growthGaps.ts), a near-neutral slate at the foot of
+ the palette's lightness band (OKLCH L 0.43, C 0.03). 7.36:1 on the
+ ground, 7.99:1 on the chart surface. Against each slot it can sit on
+ (the dataviz validator, normal / worst CVD): blue 21.9 / 21.4, green
+ 17.4 / 15.2, violet 16.2 / 13.4, amber 22.1 / 18.2, magenta 24.5 /
+ 9.1, rust 14.1 / 10.5 — every CVD pair clears 8; rust is the one
+ normal pair under 15. */
+ --chart-other: #3e545c;
--chart-tooltip-bg: #ffffff;
}
@@ -338,6 +347,14 @@ html[data-base="dark"] {
--chart-surface: #16110a;
--chart-grid: rgba(233, 220, 197, 0.08);
--chart-axis: #8a8170;
+ /* OTHER, on this base: a near-neutral grey (OKLCH L 0.49, C 0.01),
+ the dimmest chart mark. 3.22:1 on the ground, 3.06:1 on the chart
+ surface (the slots: 3.37–6.46:1 on the ground). Against each slot (normal / worst CVD): blue 17.8 / 17.9,
+ green 19.2 / 15.7, violet 23.4 / 21.5, amber 20.3 / 18.1, magenta
+ 19.5 / 7.3, rust 13.5 / 9.3 — magenta in the CVD 6–8 floor band
+ (legal with the legend, the table and Other's place on top), rust the
+ one normal pair under 15. */
+ --chart-other: #62625c;
--chart-tooltip-bg: #1b150d;
}
diff --git a/homepage/app/components/ArchiveGrowthChart.tsx b/homepage/app/components/ArchiveGrowthChart.tsx
@@ -47,21 +47,24 @@ import {
// OTHER (release 14, slice CF; lib/growthGaps.ts). Two or more sites each
// under 5 % of the chart's total fold into ONE band, "Other", on top of the
// stack. The kept sites keep their slots — siteChartColors runs over EVERY
-// site, so a fold never repaints one — and Other wears the chart's neutral
-// grey, `--chart-axis` (Light #55646e, Dark #8a8170; 5.63 / 5.13:1 on the
-// ground, 6.11 / 4.88:1 on the chart surface). The legend shows the kept
-// sites and Other; the hover title and the table name every site, and the
-// image's label and the caption say what Other holds. A grey is below the
-// validator's chroma floor by definition (it is the de-emphasis role, not a
-// categorical slot); against each slot it touches, Other is (normal ΔE /
-// worst of protan and deutan, light · dark):
-// blue 17.6 / 17.6 · 21.3 / 19.8 — the only neighbour in today's data
+// site, so a fold never repaints one — and Other wears its own near-neutral
+// grey, `--chart-other` (tokens.css: Light #3e545c, Dark #62625c; 7.36 /
+// 3.22:1 on the ground, 7.99 / 3.06:1 on the chart surface), not the axis
+// labels' colour. The legend shows the kept sites and Other; the hover title
+// and the table name every site, and the image's label and the caption say
+// what Other holds. A grey is below the validator's chroma floor by
+// definition (it is the de-emphasis role, not a categorical slot); against
+// each slot it can sit on, Other is (normal ΔE / worst of protan and deutan,
+// light · dark):
+// blue 21.9 / 21.4 · 17.8 / 17.9 — the only neighbour in today's data
// (Bonnellyzer, the top kept site in every month Other has data);
-// violet 16.1 / 14.3 · 18.5 / 17.1; amber 17.5 / 14.9 · 11.0 / 10.3;
-// green 13.6 / 9.8 · 12.3 / 4.1; magenta 20.2 / 4.5 · 16.9 / 4.2;
-// rust 14.4 / 11.7 · 14.6 / 11.4.
-// Where a pair is under a floor, the gap between the bands, Other's place on
-// top, the legend and the table carry it.
+// green 17.4 / 15.2 · 19.2 / 15.7; violet 16.2 / 13.4 · 23.4 / 21.5;
+// amber 22.1 / 18.2 · 20.3 / 18.1; magenta 24.5 / 9.1 · 19.5 / 7.3;
+// rust 14.1 / 10.5 · 13.5 / 9.3.
+// Every CVD pair clears the floor (6), and on Light the target (8); Dark's
+// magenta is in the 6–8 band and rust is under the normal-vision 15 on both
+// bases: there the gap between the bands, Other's place on top, the legend
+// and the table carry it.
//
// VALIDATED (the dataviz skill's validator, each base's values on its
// --chart-surface and on the page ground), with the operator's accents
diff --git a/homepage/app/lib/growthGaps.test.ts b/homepage/app/lib/growthGaps.test.ts
@@ -195,7 +195,7 @@ test("the fold with today's proportions: the three largest keep their bands, the
assert.deepEqual(stack[3].hi, totals);
// Colours: the kept sites their families' slots, Other the neutral grey.
assert.deepEqual(layerColors(layers, sites), ["var(--chart-4)", "var(--chart-5)", "var(--chart-1)", OTHER_COLOR]);
- assert.equal(OTHER_COLOR, "var(--chart-axis)");
+ assert.equal(OTHER_COLOR, "var(--chart-other)");
});
test("the threshold's edge: exactly 5 % keeps its band, just under folds", () => {
diff --git a/homepage/app/lib/growthGaps.ts b/homepage/app/lib/growthGaps.ts
@@ -67,10 +67,10 @@ function stackOrder(n: number): number[] {
export const FOLD_PERCENT = 5;
export const OTHER_LABEL = "Other";
-// The chart's neutral grey (tokens.css), on each base: 5.63:1 on the Light
-// ground and 5.13:1 on the Dark one (6.11 / 4.88 on the chart surface).
-// ArchiveGrowthChart.tsx has its separation from each chart slot.
-export const OTHER_COLOR = "var(--chart-axis)";
+// Other's own chart token (tokens.css `--chart-other`), a near-neutral grey:
+// 7.36:1 on the Light ground and 3.22:1 on the Dark one (7.99 / 3.06 on the
+// chart surface). tokens.css has its separation from each chart slot.
+export const OTHER_COLOR = "var(--chart-other)";
// One band of the stack: a site's own (`sites` is its index in the summary's
// list), or Other (the indexes of every folded site, in the list's order).
diff --git a/homepage/e2e/growth-chart.spec.ts b/homepage/e2e/growth-chart.spec.ts
@@ -225,7 +225,7 @@ test("two sites under 5 % are one Other band on top: the legend shows the kept s
await expect(figure.locator("table thead th")).toHaveText(["Year", ...titles, "Total"]);
});
-test("Other is the chart's neutral grey, at least 3:1 on both grounds, and no kept site's colour", async ({
+test("Other is its own grey (--chart-other), at least 3:1 on both grounds, and no kept site's colour", async ({
page,
}) => {
await page.goto("/");
@@ -237,7 +237,11 @@ test("Other is the chart's neutral grey, at least 3:1 on both grounds, and no ke
.locator("figure ul[aria-hidden='true'] li > span")
.evaluateAll((els) => els.map((e) => getComputedStyle(e).backgroundColor));
const other = swatches.at(-1)!;
- expect(other, base).toBe(await resolveFill(page, "var(--chart-axis)"));
+ expect(other, base).toBe(await resolveFill(page, OTHER_COLOR));
+ // Its own token, set on each base (a Dark block without it would fall
+ // back to the Light value from :root).
+ expect(other, base).toBe(base === "light" ? "rgb(62, 84, 92)" : "rgb(98, 98, 92)");
+ expect(other, base).not.toBe(await resolveFill(page, "var(--chart-axis)"));
const ground = await page.evaluate(() => getComputedStyle(document.body).backgroundColor);
expect(contrast(other, ground), `${base}: Other on the ground`).toBeGreaterThanOrEqual(3);
expect(swatches.slice(0, -1), base).not.toContain(other);