feat(design): the scheme set, the colour contract and the token utilities (E28 S3a)

Four schemes (Midnight; Forest cyan, Slate fuchsia, Matrix lime), YouTube
and Starship retired with no data migration: normalizeTheme maps a stored
retired scheme to Midnight. A vitest contract measures every scheme x mode
(text 4.5:1, control edge 3:1, status text, the accent's 30-degree hue gap);
it caught light-mode danger at 4.43:1, now red-700. The state layers, the
strong edge, the touch target and the fades are index.css tokens and
utilities the lab now reads. Backdrops recoloured to the new accents, with
a grey overlay grain that actually breaks the banding (longest flat run
15-26px -> 4-8px). The glass tuner is retired.
This commit is contained in:
2026-09-24 04:33:13 +02:00
parent 9c4a999e54
commit ad136c3fe8
26 changed files with 326 additions and 851 deletions
+6 -16
View File
@@ -21,17 +21,9 @@ import {
Youtube,
} from "lucide-react";
import { Btn } from "./batchA";
import { hexContrast, hueGap } from "./labColor";
import { hexContrast, hueGap } from "../lib/colorMath";
import { Reference, Sample } from "./labKit";
import {
FADE_ABOVE_PANEL,
FADE_BELOW,
FADE_BELOW_PANEL,
FADE_EDGES_X,
FILLED,
H,
LAYER,
} from "./labTokens";
import { FADE_ABOVE_PANEL, FADE_BELOW, FADE_BELOW_PANEL, FILLED, H, LAYER } from "./labTokens";
// E28 S2 · Batch B — surfaces, chrome and colour, DECIDED (owner, 2026-09-24): every recommendation,
// except B7, where the owner combined the soft tint + edge bar with optional labels. B1 (density) and
@@ -57,7 +49,7 @@ type SchemeDef = { name: string; dark: Pal; light: Pal };
const STATUS: Record<Mode, Record<"danger" | "dangerFg" | "warn" | "success", string>> = {
dark: { danger: "#f87171", dangerFg: "#2a0a0a", warn: "#fbbf24", success: "#34d399" },
light: { danger: "#dc2626", dangerFg: "#ffffff", warn: "#b45309", success: "#047857" },
light: { danger: "#b91c1c", dangerFg: "#ffffff", warn: "#b45309", success: "#047857" },
};
const pal = (
@@ -70,7 +62,8 @@ const pal = (
accentFg: string,
): Pal => ({ bg, surface, border, fg, muted, accent, accentFg });
// Backgrounds and text are today's (index.css); only the accents are new.
// A literal copy of index.css's scheme tokens, so the four tiles render side by side (the live CSS
// switches only one scheme at a time). index.css is the source; theme.contract.test.ts holds it.
const SCHEMES: SchemeDef[] = [
{
name: "Midnight · blue",
@@ -458,10 +451,7 @@ function Fades() {
</div>
</Sample>
<Sample label="4 · An overflowing chip row">
<div
className="overflow-x-auto no-scrollbar"
style={{ maskImage: FADE_EDGES_X, WebkitMaskImage: FADE_EDGES_X }}
>
<div className="overflow-x-auto no-scrollbar fade-edges-x">
<div className="flex w-max gap-1.5 px-6">
{CHIPS.map((c) => (
<span key={c} className="chip px-2.5 py-1 text-xs">