feat(t5): Farb-Token additiv, Sonnen-Farbsätze und Kontrast-Wächter (T5a A1)

Neue Token neben den bestehenden (Schrift auf Hauptfarbe und Warnung,
Zustands-, Bereichs- und Königinnen-Töne, Fokus- und Rahmenmaße,
Wabenstriche), zwei vollständige Sonnen-Sätze (hell/dunkel) mit
größerer Schrift, 3-px-Fokus und ohne Schatten, Holo-Sonne für die
Beute-Bühne und .holo-stage-Fokusring, Druck immer im hellen Satz,
forced-colors. Wächter misst alle 21 Paare der Spec-Tabelle 4.4 in
vier Sätzen (OKLCH → sRGB → WCAG, Tönungen alpha-gemischt), prüft den
sRGB-Farbraum und erzwingt das Umschalten in A4. Sichtbar ändert sich
nur ein minimal entsättigter Holo-Kantenton (vorher außerhalb sRGB).

Refs #26

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick.RosenloecherandClaude Opus 5.5 committed 2026-10-16 16:23:33 +02:00
1 parent a7a7599304
commit 6b1b3cfa90
6 files changed
+846 -4

No files matched your search

+259 -3
View File
@@ -2,7 +2,10 @@
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@custom-variant dark (&:is(.dark *));
@custom-variant dark (&:where(.dark, .dark *));
@custom-variant sun (&:where([data-contrast="sun"] *));
@custom-variant pointer-fine (@media (pointer: fine));
@custom-variant pointer-coarse (@media (pointer: coarse));
@theme inline {
--color-background: var(--background);
@@ -47,6 +50,24 @@
--color-holo-fill: var(--holo-fill);
--color-holo-label-bg: var(--holo-label-bg);
--color-holo-label-fg: var(--holo-label-fg);
--color-primary-ink: var(--primary-ink);
--color-warning-ink: var(--warning-ink);
--color-destructive-foreground: var(--destructive-foreground);
--color-condition-excellent-ink: var(--condition-excellent-ink);
--color-condition-good-ink: var(--condition-good-ink);
--color-condition-average-ink: var(--condition-average-ink);
--color-condition-weak-ink: var(--condition-weak-ink);
--color-condition-critical-ink: var(--condition-critical-ink);
--color-area-betrieb: var(--area-betrieb);
--color-area-erfassung: var(--area-erfassung);
--color-area-arbeit: var(--area-arbeit);
--color-area-ernte: var(--area-ernte);
--color-area-neutral: var(--area-neutral);
--color-queen-white: var(--queen-white);
--color-queen-yellow: var(--queen-yellow);
--color-queen-red: var(--queen-red);
--color-queen-green: var(--queen-green);
--color-queen-blue: var(--queen-blue);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
@@ -135,10 +156,35 @@
/* Hive "screen": always dark, in light and dark mode (spec 9.3). */
--holo-bg: oklch(0.18 0.03 250);
--holo-edge: oklch(0.72 0.15 243);
--holo-edge-strong: oklch(0.87 0.1 238);
--holo-edge-strong: oklch(0.87 0.07 238);
--holo-fill: oklch(0.78 0.14 220 / 10%);
--holo-label-bg: oklch(0.26 0.04 250);
--holo-label-fg: oklch(0.95 0.02 230);
/* T5 tokens, end values (spec 4.2); the old values above switch in task A4. */
--primary-ink: oklch(0.47 0.115 55);
--warning-ink: oklch(0.5 0.11 65);
--destructive-foreground: oklch(0.985 0.005 30);
--condition-excellent-ink: oklch(0.4 0.09 150);
--condition-good-ink: oklch(0.41 0.09 125);
--condition-average-ink: oklch(0.44 0.09 85);
--condition-weak-ink: oklch(0.46 0.12 52);
--condition-critical-ink: oklch(0.47 0.16 28);
--area-betrieb: oklch(0.46 0.08 150);
--area-erfassung: oklch(0.5 0.12 60);
--area-arbeit: oklch(0.48 0.08 250);
--area-ernte: oklch(0.52 0.11 75);
--area-neutral: oklch(0.45 0.02 60);
--queen-white: oklch(0.97 0.005 90);
--queen-yellow: oklch(0.86 0.17 95);
--queen-red: oklch(0.58 0.2 27);
--queen-green: oklch(0.58 0.15 145);
--queen-blue: oklch(0.52 0.15 255);
--focus-width: 2px;
--focus-offset: 2px;
--control-border-width: 1px;
--comb-stroke-1: 2px;
--comb-stroke-2: 4px;
--comb-stroke-3: 6px;
}
.dark {
@@ -195,10 +241,220 @@
/* Hive "screen": always dark, in light and dark mode (spec 9.3). */
--holo-bg: oklch(0.18 0.03 250);
--holo-edge: oklch(0.72 0.15 243);
--holo-edge-strong: oklch(0.87 0.1 238);
--holo-edge-strong: oklch(0.87 0.07 238);
--holo-fill: oklch(0.78 0.14 220 / 10%);
--holo-label-bg: oklch(0.26 0.04 250);
--holo-label-fg: oklch(0.95 0.02 230);
/* T5 tokens, end values (spec 4.2); the old values above switch in task A4. */
--primary-ink: oklch(0.82 0.13 80);
--warning-ink: oklch(0.82 0.13 82);
--destructive-foreground: oklch(0.17 0.03 30);
--condition-excellent-ink: oklch(0.8 0.11 150);
--condition-good-ink: oklch(0.83 0.11 125);
--condition-average-ink: oklch(0.86 0.11 90);
--condition-weak-ink: oklch(0.82 0.11 60);
--condition-critical-ink: oklch(0.78 0.11 28);
--area-betrieb: oklch(0.74 0.09 150);
--area-erfassung: oklch(0.8 0.12 70);
--area-arbeit: oklch(0.76 0.07 250);
--area-ernte: oklch(0.8 0.1 80);
--area-neutral: oklch(0.76 0.02 70);
--queen-white: oklch(0.97 0.005 90);
--queen-yellow: oklch(0.86 0.17 95);
--queen-red: oklch(0.62 0.2 27);
--queen-green: oklch(0.66 0.15 145);
--queen-blue: oklch(0.62 0.15 255);
}
/* Sun ("Sonne"): maximum luminance difference outdoors (spec 4.3). The two sets follow the
order light, dark, sun-light, sun-dark; sun-dark restates everything sun-light sets. */
:root[data-contrast="sun"] {
--background: oklch(1 0 0);
--card: oklch(1 0 0);
--popover: oklch(1 0 0);
--sidebar: oklch(1 0 0);
--foreground: oklch(0.13 0.02 55);
--card-foreground: oklch(0.13 0.02 55);
--popover-foreground: oklch(0.13 0.02 55);
--sidebar-foreground: oklch(0.13 0.02 55);
--primary-foreground: oklch(0.13 0.02 55);
--ring: oklch(0.13 0.02 55);
--muted: oklch(0.95 0.01 80);
--muted-foreground: oklch(0.32 0.03 60);
--border: oklch(0.4 0.03 60);
--input: oklch(0.2 0.03 55);
--primary-ink: oklch(0.38 0.1 52);
--text-sm: 1rem;
--text-xs: 0.875rem;
--focus-width: 3px;
--control-border-width: 2px;
--comb-stroke-1: 3px;
--comb-stroke-2: 5px;
--comb-stroke-3: 7px;
--shadow-soft: none;
--shadow-elevated: none;
/* Hive stage: black screen, pure white edges and label text. */
--holo-bg: oklch(0 0 0);
--holo-edge: oklch(1 0 0);
--holo-edge-strong: oklch(1 0 0);
--holo-label-fg: oklch(1 0 0);
--holo-label-bg: oklch(0.12 0 0);
}
.dark[data-contrast="sun"] {
--background: oklch(0.1 0.005 55);
--card: oklch(0.1 0.005 55);
--popover: oklch(0.1 0.005 55);
--sidebar: oklch(0.1 0.005 55);
--foreground: oklch(0.99 0.005 85);
--card-foreground: oklch(0.99 0.005 85);
--popover-foreground: oklch(0.99 0.005 85);
--sidebar-foreground: oklch(0.99 0.005 85);
--primary-foreground: oklch(0.19 0.03 55);
--ring: oklch(0.99 0.005 85);
--muted: oklch(0.2 0.01 55);
--muted-foreground: oklch(0.88 0.02 80);
--border: oklch(0.7 0.02 70);
--input: oklch(0.92 0.01 80);
--primary-ink: oklch(0.82 0.13 80);
--text-sm: 1rem;
--text-xs: 0.875rem;
--focus-width: 3px;
--control-border-width: 2px;
--comb-stroke-1: 3px;
--comb-stroke-2: 5px;
--comb-stroke-3: 7px;
--shadow-soft: none;
--shadow-elevated: none;
--holo-bg: oklch(0 0 0);
--holo-edge: oklch(1 0 0);
--holo-edge-strong: oklch(1 0 0);
--holo-label-fg: oklch(1 0 0);
--holo-label-bg: oklch(0.12 0 0);
}
/* The hive stage is its own always-dark surface; the page focus ring (--primary-ink) has less
than 3:1 on it (spec 17.8), so the stage draws the ring in its strong edge colour. */
.holo-stage {
--ring: var(--holo-edge-strong);
}
/* Tinted surfaces: set --tint (and --tint-ink) on the element. In sun the tint becomes the
plain card with a 2 px border in the ink instead of a 15 % wash (spec 4.3). */
@layer components {
.tint {
--tint: var(--primary);
--tint-ink: var(--primary-ink);
background-color: color-mix(in oklch, var(--tint) 15%, transparent);
}
}
:root[data-contrast="sun"] .tint {
background-color: var(--card);
border: var(--control-border-width) solid var(--tint-ink);
}
:root[data-contrast="sun"] body header.sticky {
background-color: var(--card);
backdrop-filter: none;
}
/* Print and PDF preview always use the light set (spec 4.1). Kept in step with :root by
contrast.spec.ts. */
@media print {
:root,
.dark,
:root[data-contrast="sun"],
.dark[data-contrast="sun"] {
--background: oklch(0.955 0.017 80);
--foreground: oklch(0.22 0.028 55);
--card: oklch(0.995 0.004 90);
--card-foreground: oklch(0.22 0.028 55);
--popover: oklch(0.995 0.004 90);
--popover-foreground: oklch(0.22 0.028 55);
--primary: oklch(0.6 0.15 48);
--primary-foreground: oklch(0.99 0.02 85);
--secondary: oklch(0.44 0.07 145);
--secondary-foreground: oklch(0.98 0.015 100);
--muted: oklch(0.9 0.02 82);
--muted-foreground: oklch(0.48 0.032 65);
--accent: oklch(0.93 0.032 74);
--accent-foreground: oklch(0.26 0.045 50);
--destructive: oklch(0.5 0.16 30);
--border: oklch(0.85 0.024 78);
--input: oklch(0.85 0.024 78);
--ring: oklch(0.6 0.15 48);
--warning: oklch(0.68 0.14 75);
--warning-foreground: oklch(0.24 0.04 60);
--success: oklch(0.46 0.06 145);
--success-foreground: oklch(0.98 0.015 100);
--condition-excellent: oklch(0.58 0.13 145);
--condition-excellent-foreground: oklch(0.16 0.04 145);
--condition-good: oklch(0.64 0.13 118);
--condition-good-foreground: oklch(0.26 0.05 118);
--condition-average: oklch(0.7 0.14 90);
--condition-average-foreground: oklch(0.28 0.05 90);
--condition-weak: oklch(0.68 0.15 55);
--condition-weak-foreground: oklch(0.26 0.05 55);
--condition-critical: oklch(0.64 0.16 30);
--condition-critical-foreground: oklch(0.15 0.04 30);
--chart-1: oklch(0.6 0.135 50);
--chart-2: oklch(0.46 0.06 145);
--chart-3: oklch(0.68 0.14 75);
--chart-4: oklch(0.5 0.16 30);
--chart-5: oklch(0.55 0.05 250);
--sidebar: oklch(0.995 0.004 90);
--sidebar-foreground: oklch(0.22 0.028 55);
--sidebar-primary: oklch(0.6 0.15 48);
--sidebar-primary-foreground: oklch(0.99 0.02 85);
--sidebar-accent: oklch(0.93 0.032 74);
--sidebar-accent-foreground: oklch(0.26 0.045 50);
--sidebar-border: oklch(0.85 0.024 78);
--sidebar-ring: oklch(0.6 0.15 48);
--shadow-elevated: 0 1px 2px -1px oklch(0.3 0.05 50 / 8%), 0 8px 24px -8px oklch(0.3 0.05 50 / 16%);
--shadow-soft: 0 1px 2px -1px oklch(0.3 0.05 50 / 6%), 0 4px 12px -4px oklch(0.3 0.05 50 / 10%);
--holo-bg: oklch(0.18 0.03 250);
--holo-edge: oklch(0.72 0.15 243);
--holo-edge-strong: oklch(0.87 0.07 238);
--holo-fill: oklch(0.78 0.14 220 / 10%);
--holo-label-bg: oklch(0.26 0.04 250);
--holo-label-fg: oklch(0.95 0.02 230);
--primary-ink: oklch(0.47 0.115 55);
--warning-ink: oklch(0.5 0.11 65);
--destructive-foreground: oklch(0.985 0.005 30);
--condition-excellent-ink: oklch(0.4 0.09 150);
--condition-good-ink: oklch(0.41 0.09 125);
--condition-average-ink: oklch(0.44 0.09 85);
--condition-weak-ink: oklch(0.46 0.12 52);
--condition-critical-ink: oklch(0.47 0.16 28);
--area-betrieb: oklch(0.46 0.08 150);
--area-erfassung: oklch(0.5 0.12 60);
--area-arbeit: oklch(0.48 0.08 250);
--area-ernte: oklch(0.52 0.11 75);
--area-neutral: oklch(0.45 0.02 60);
--queen-white: oklch(0.97 0.005 90);
--queen-yellow: oklch(0.86 0.17 95);
--queen-red: oklch(0.58 0.2 27);
--queen-green: oklch(0.58 0.15 145);
--queen-blue: oklch(0.52 0.15 255);
--text-sm: 0.875rem;
--text-xs: 0.75rem;
--focus-width: 2px;
--control-border-width: 1px;
--comb-stroke-1: 2px;
--comb-stroke-2: 4px;
--comb-stroke-3: 6px;
}
}
/* Forced colours: the system palette wins; strokes use CanvasText so shapes stay visible. */
@media (forced-colors: active) {
:root,
.dark,
:root[data-contrast="sun"],
.dark[data-contrast="sun"] {
--ring: CanvasText;
--border: CanvasText;
--input: CanvasText;
}
}
/* ---------------------------------------------------------------------------