refactor: dark-mode token deduplication via private-variable indirection (v0.20.17)

All tokens with dark-mode overrides gain a private --_name counterpart in :root.
Public tokens (--color-*, --module-*, --glass-* etc.) become stable var(--_name)
references. Both dark blocks now only override compact private tokens — no more
manual two-block sync for every future colour change.

Also removes the redundant --color-surface-2 dark override (already auto-derived
via var(--neutral-50)). No visual change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ulas Kalayci
2026-04-20 06:53:08 +02:00
parent 3f989c3bff
commit 18c90653d4
4 changed files with 337 additions and 265 deletions
+5
View File
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.20.17] - 2026-04-20
### Changed
- Design: dark-mode token architecture refactored to private-variable indirection (`--_name`) in `tokens.css` — all tokens with dark-mode overrides now have a private `--_token` variant that holds the actual value, while public tokens (`--color-*`, `--module-*`, `--glass-*` etc.) are stable `var(--_token)` references. Both dark blocks (`@media prefers-color-scheme: dark` and `[data-theme="dark"]`) now only override the compact private tokens; the public API never needs to be touched again for dark-mode changes. The redundant explicit `--color-surface-2` override was removed from both dark blocks (it is already correctly derived via `var(--neutral-50)`). No visual change.
## [0.20.16] - 2026-04-19
### Changed
+3 -1
View File
@@ -452,6 +452,8 @@ Vorteil: Eine Zeile Änderung statt zwei. Nachteil: Zwei CSS-Ebenen (private `--
**Priorität:** Niedrig — wartungstechnisch sinnvoll, kein UX-Impact. Als eigener PR.
**Status:** ✅ Umgesetzt — Private-Token-Indirektion (`--_name`) in `tokens.css`. Beide Dark-Blöcke überschreiben nur noch private Tokens; öffentliche API (`--color-*`, `--module-*` etc.) ist stabil und muss bei zukünftigen Dark-Mode-Änderungen nicht mehr doppelt angepasst werden.
### 8.3 Glass.css Specular-Token-Konsolidierung
`glass.css` wiederholt dieselben `rgba`-Werte für specular highlights (0.18, 0.22, 0.28, 0.32) und inset shadows. **Umgesetzt:** 5 neue Tokens in `tokens.css` (Abschnitt `/* d2) Inset-Specular */`):
@@ -487,7 +489,7 @@ Zeilen 17381745 enthielten `#fff`, `#000`, `#ddd` in einem `@media print`-Blo
| `tasks.css` | `.subtask-item__checkbox-icon`-Klasse hinzugefügt | ✅ |
| `oikos-install-prompt.js` | Fallback `#2554C7``#4338CA`; `#fff``var(--color-text-on-accent, #fff)` | ✅ §8.1 |
| `index.html` | `theme-color="#2563EB"``#4F46E5` | ✅ §8.1 |
| Dark-Mode-Dedup | `@media` + `[data-theme]` kollabieren | 🔲 §8.2 |
| Dark-Mode-Dedup | `@media` + `[data-theme]` kollabieren auf private `--_` Tokens | §8.2 |
| `tokens.css` | 5 neue `--glass-inset-*` Tokens (0.180.32) | ✅ §8.3 |
| `glass.css` | 9 specular rgba-Literale → `var(--glass-inset-*)` | ✅ §8.3 |
| `tasks.css` | 1 specular rgba-Literal → `var(--glass-inset-base)` | ✅ §8.3 |
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "oikos",
"version": "0.20.15",
"version": "0.20.17",
"description": "Self-hosted family planner - calendar, tasks, shopping, meal planning, budget and more. Private, open-source, no subscription.",
"main": "server/index.js",
"type": "module",
+328 -263
View File
@@ -19,73 +19,109 @@
* 13. Übergänge
* 14. Z-Indizes
* 15. Dark Mode
*
* Dark-Mode-Architektur (§8.2):
* Private Tokens (--_name) halten den aktuellen Wert.
* Öffentliche Tokens (--name) zeigen immer auf var(--_name).
* Dark-Mode-Blöcke überschreiben nur die privaten Tokens —
* die öffentliche API bleibt stabil und muss nie doppelt geändert werden.
*/
:root {
/* --------------------------------------------------------
* 1. Farben - Neutral-Skala
* Leicht warmgetönt (kein reines Grau) für einladende Atmosphäre.
* Benannt als --neutral-{stufe} für direkte Nutzung,
* plus semantische Aliase (--color-bg, --color-surface etc.)
* die bestehender Code bereits referenziert.
* Private --_neutral-* für Dark-Mode-Überschreibungen;
* öffentliche --neutral-* sind die stabile API.
* -------------------------------------------------------- */
--neutral-50: #FAFAF8;
--neutral-100: #F5F4F1;
--neutral-150: #EFEEE9;
--neutral-200: #E8E7E2;
--neutral-250: #DDDCD7;
--neutral-300: #D1D0CB;
--neutral-400: #B5B4AF;
--neutral-500: #8E8D89;
--neutral-600: #6C6B67;
--neutral-700: #4A4A46;
--neutral-800: #2E2E2B;
--neutral-900: #1C1C1A;
--neutral-950: #121211;
--_neutral-50: #FAFAF8;
--neutral-50: var(--_neutral-50);
--_neutral-100: #F5F4F1;
--neutral-100: var(--_neutral-100);
--_neutral-150: #EFEEE9;
--neutral-150: var(--_neutral-150);
--_neutral-200: #E8E7E2;
--neutral-200: var(--_neutral-200);
--_neutral-250: #DDDCD7;
--neutral-250: var(--_neutral-250);
--_neutral-300: #D1D0CB;
--neutral-300: var(--_neutral-300);
--_neutral-400: #B5B4AF;
--neutral-400: var(--_neutral-400);
--_neutral-500: #8E8D89;
--neutral-500: var(--_neutral-500);
--_neutral-600: #6C6B67;
--neutral-600: var(--_neutral-600);
--_neutral-700: #4A4A46;
--neutral-700: var(--_neutral-700);
--_neutral-800: #2E2E2B;
--neutral-800: var(--_neutral-800);
--_neutral-900: #1C1C1A;
--neutral-900: var(--_neutral-900);
--_neutral-950: #121211;
--neutral-950: var(--_neutral-950);
/* Semantische Aliase (abwärtskompatibel) */
--color-bg: var(--neutral-100);
--color-surface: #FFFFFF;
--_color-surface: #FFFFFF;
--color-surface: var(--_color-surface);
--color-surface-2: var(--neutral-50);
--color-surface-3: var(--neutral-150);
--_color-surface-3: var(--_neutral-150);
--color-surface-3: var(--_color-surface-3);
--color-border: var(--neutral-200);
--color-border-subtle: var(--neutral-150);
--color-text-primary: var(--neutral-900);
--color-text-secondary: var(--neutral-600); /* WCAG AA: ~5.0:1 auf weiß */
--color-text-tertiary: #6A6964; /* WCAG AA: 4.61:1 auf --color-bg (wärmer, mehr Puffer) */
--_color-text-tertiary: #6A6964;
--color-text-tertiary: var(--_color-text-tertiary); /* WCAG AA: 4.61:1 auf --color-bg */
--color-text-disabled: var(--neutral-300);
--color-text-on-accent: #ffffff; /* Weißer Text auf farbigen Hintergründen (Buttons, Badges, FAB) */
--color-text-on-accent: #ffffff; /* Weißer Text auf farbigen Hintergründen */
/* --------------------------------------------------------
* 2. Farben - Akzent (konfigurierbar)
* Indigo mit leichtem Violett-Drall — charaktervoller als Default-Blau,
* harmoniert mit --color-accent-secondary und --module-calendar.
* -------------------------------------------------------- */
--color-accent: #4F46E5; /* Indigo-600 — 4.93:1 auf weiß */
--color-accent-hover: #4338CA; /* Indigo-700 */
--color-accent-active: #3730A3; /* Indigo-800 */
--color-accent-deep: #2E2D82; /* Tiefer Akzent für Gradienten, Wetter-Widget */
--color-accent-secondary: #7C5CFC; /* Sekundärer Akzent für Logo-Gradient */
--color-accent-light: #EEF2FF; /* Indigo-50 */
--color-accent-subtle: #E0E7FF; /* Indigo-100 */
--color-btn-primary: #4338CA; /* Indigo-700 — WCAG AAA: 7.04:1 auf weiß */
--color-btn-primary-hover: #3730A3; /* Indigo-800 */
--_color-accent: #4F46E5;
--color-accent: var(--_color-accent); /* Indigo-600 — 4.93:1 auf weiß */
--_color-accent-hover: #4338CA;
--color-accent-hover: var(--_color-accent-hover); /* Indigo-700 */
--_color-accent-active: #3730A3;
--color-accent-active: var(--_color-accent-active); /* Indigo-800 */
--color-accent-deep: #2E2D82; /* Tiefer Akzent für Gradienten, Wetter-Widget */
--_color-accent-secondary: #7C5CFC;
--color-accent-secondary: var(--_color-accent-secondary); /* Sekundärer Akzent für Logo-Gradient */
--_color-accent-light: #EEF2FF;
--color-accent-light: var(--_color-accent-light); /* Indigo-50 */
--_color-accent-subtle: #E0E7FF;
--color-accent-subtle: var(--_color-accent-subtle); /* Indigo-100 */
--_color-btn-primary: #4338CA;
--color-btn-primary: var(--_color-btn-primary); /* Indigo-700 — WCAG AAA: 7.04:1 auf weiß */
--_color-btn-primary-hover: #3730A3;
--color-btn-primary-hover: var(--_color-btn-primary-hover); /* Indigo-800 */
/* --------------------------------------------------------
* 3. Farben - Semantisch
* -------------------------------------------------------- */
--color-success: #15803D;
--color-success-hover: #166534;
--color-success-light: #DAFBE1;
--color-warning: #A15C0A; /* Hue-Trennung von --module-meals, 5.23:1 auf weiß */
--color-warning-hover: #824908;
--color-warning-light: #FFF4D4;
--color-danger: #B91C1C; /* Red-700 — 6.90:1 auf weiß (vorher 4.85:1) */
--color-danger-hover: #991B1B; /* Red-800 */
--color-danger-light: #FFE2E0;
--color-info: #0969DA; /* WCAG AA: ~4.6:1 auf weiß */
--color-info-hover: #0550AE;
--color-info-light: #DDF4FF;
--_color-success: #15803D;
--color-success: var(--_color-success);
--color-success-hover: #166534;
--_color-success-light: #DAFBE1;
--color-success-light: var(--_color-success-light);
--_color-warning: #A15C0A;
--color-warning: var(--_color-warning); /* Hue-Trennung von --module-meals, 5.23:1 auf weiß */
--color-warning-hover: #824908;
--_color-warning-light: #FFF4D4;
--color-warning-light: var(--_color-warning-light);
--_color-danger: #B91C1C;
--color-danger: var(--_color-danger); /* Red-700 — 6.90:1 auf weiß */
--color-danger-hover: #991B1B; /* Red-800 */
--_color-danger-light: #FFE2E0;
--color-danger-light: var(--_color-danger-light);
--color-info: #0969DA; /* WCAG AA: ~4.6:1 auf weiß */
--color-info-hover: #0550AE;
--_color-info-light: #DDF4FF;
--color-info-light: var(--_color-info-light);
/* --------------------------------------------------------
* 4. Farben - Modul-Akzente
@@ -93,28 +129,43 @@
* Einsatz in Modul-Headern, Icons, aktiven States.
* Domain-Farben von Severity entkoppelt — siehe §2.5 des Redesign-Vorschlags.
* -------------------------------------------------------- */
--module-dashboard: #4F46E5; /* Indigo - Übersicht, neutral (= --color-accent, bewusster Share) */
--module-tasks: #15803D; /* Grün - Erledigung, Fortschritt (= --color-success, bewusster Share) */
--module-calendar: #8250DF; /* Violett - Termine, Zeit */
--module-meals: #C2410C; /* Orange-700 - Essen, Wärme */
--module-shopping: #DB2777; /* Pink-600 - Einkaufen, Aktion (trennt von Meals) */
--module-notes: #CA8A04; /* Gold - Notizen, Pinnwand (nur Icons/Large-Text: 4.08:1) */
--module-contacts: #0969DA; /* Kräftiges Blau - Kontakte */
--module-budget: #0F766E; /* Teal-700 - Finanzen, Stabilität */
--module-settings: #6E7781; /* Grau - Konfiguration */
--_module-dashboard: #4F46E5;
--module-dashboard: var(--_module-dashboard); /* Indigo - Übersicht (= --color-accent, bewusster Share) */
--_module-tasks: #15803D;
--module-tasks: var(--_module-tasks); /* Grün - Erledigung (= --color-success, bewusster Share) */
--_module-calendar: #8250DF;
--module-calendar: var(--_module-calendar); /* Violett - Termine, Zeit */
--_module-meals: #C2410C;
--module-meals: var(--_module-meals); /* Orange-700 - Essen, Wärme */
--_module-shopping: #DB2777;
--module-shopping: var(--_module-shopping); /* Pink-600 - Einkaufen (trennt von Meals) */
--_module-notes: #CA8A04;
--module-notes: var(--_module-notes); /* Gold - Notizen (nur Icons/Large-Text: 4.08:1) */
--_module-contacts: #0969DA;
--module-contacts: var(--_module-contacts); /* Kräftiges Blau - Kontakte */
--_module-budget: #0F766E;
--module-budget: var(--_module-budget); /* Teal-700 - Finanzen, Stabilität */
--_module-settings: #6E7781;
--module-settings: var(--_module-settings); /* Grau - Konfiguration */
/* --------------------------------------------------------
* 5. Farben - Mahlzeit-Typen
* Zentrale Tokens statt Hardcoding in meals.css
* -------------------------------------------------------- */
--meal-breakfast: #A15C0A; /* Morgensonne-Amber (= --color-warning, bewusster Share) */
--meal-breakfast-light: #FFF4D4;
--meal-lunch: #2DA44E;
--meal-lunch-light: #DAFBE1;
--meal-dinner: #4F46E5; /* Indigo - ruhiger Tag-Ausklang (= --color-accent) */
--meal-dinner-light: #EEF2FF;
--meal-snack: #C2410C; /* = --module-meals — Snack ist Sub-Domain von Meals */
--meal-snack-light: #FFECE3;
--_meal-breakfast: #A15C0A;
--meal-breakfast: var(--_meal-breakfast); /* Morgensonne-Amber (= --color-warning, bewusster Share) */
--_meal-breakfast-light: #FFF4D4;
--meal-breakfast-light: var(--_meal-breakfast-light);
--meal-lunch: #2DA44E;
--_meal-lunch-light: #DAFBE1;
--meal-lunch-light: var(--_meal-lunch-light);
--_meal-dinner: #4F46E5;
--meal-dinner: var(--_meal-dinner); /* Indigo - ruhiger Tag-Ausklang (= --color-accent) */
--_meal-dinner-light: #EEF2FF;
--meal-dinner-light: var(--_meal-dinner-light);
--meal-snack: #C2410C; /* = --module-meals — Snack ist Sub-Domain */
--_meal-snack-light: #FFECE3;
--meal-snack-light: var(--_meal-snack-light);
/* --------------------------------------------------------
* 6. Farben - Prioritäten
@@ -125,18 +176,25 @@
--color-priority-high: #C2410C; /* = --module-meals (bewusster Share: „heiß") */
--color-priority-urgent: #B91C1C; /* = --color-danger (bewusster Share: „gefährlich") */
/* Hintergrundfarben für Priority-Badges — RGB-Tripel folgen den Base-Tokens */
--color-priority-none-bg: rgba(142, 141, 137, 0.08);
--color-priority-low-bg: rgba(142, 141, 137, 0.12);
--color-priority-medium-bg: rgba(161, 98, 7, 0.12);
--color-priority-high-bg: rgba(194, 65, 12, 0.12);
--color-priority-urgent-bg: rgba(185, 28, 28, 0.12);
/* Hintergrundfarben für Priority-Badges */
--_color-priority-none-bg: rgba(142, 141, 137, 0.08);
--color-priority-none-bg: var(--_color-priority-none-bg);
--_color-priority-low-bg: rgba(142, 141, 137, 0.12);
--color-priority-low-bg: var(--_color-priority-low-bg);
--_color-priority-medium-bg: rgba(161, 98, 7, 0.12);
--color-priority-medium-bg: var(--_color-priority-medium-bg);
--_color-priority-high-bg: rgba(194, 65, 12, 0.12);
--color-priority-high-bg: var(--_color-priority-high-bg);
--_color-priority-urgent-bg: rgba(185, 28, 28, 0.12);
--color-priority-urgent-bg: var(--_color-priority-urgent-bg);
/* --------------------------------------------------------
* 7. Overlay / Backdrop
* -------------------------------------------------------- */
--color-overlay: rgba(0, 0, 0, 0.45);
--color-overlay-light: rgba(0, 0, 0, 0.2);
--_color-overlay: rgba(0, 0, 0, 0.45);
--color-overlay: var(--_color-overlay);
--_color-overlay-light: rgba(0, 0, 0, 0.2);
--color-overlay-light: var(--_color-overlay-light);
/* Glass-Overlays (fuer Elemente auf farbigen Hintergruenden) */
--color-glass: rgba(255, 255, 255, 0.18);
@@ -149,9 +207,12 @@
* 3 Stufen: subtle (Karten), medium (Dropdowns, Hover),
* elevated (Modals, FAB).
* -------------------------------------------------------- */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 4px rgba(0, 0, 0, 0.03);
--shadow-md: 0 2px 8px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.04);
--_shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 4px rgba(0, 0, 0, 0.03);
--shadow-sm: var(--_shadow-sm);
--_shadow-md: 0 2px 8px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
--shadow-md: var(--_shadow-md);
--_shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.04);
--shadow-lg: var(--_shadow-lg);
/* --------------------------------------------------------
* 9. Border-Radien
@@ -233,10 +294,13 @@
* 13. Sidebar
* Reduzierter Neumorphismus - subtilere Schatten.
* -------------------------------------------------------- */
--sidebar-bg: var(--neutral-100);
--sidebar-shadow-light: rgba(255, 255, 255, 0.6);
--sidebar-shadow-dark: rgba(0, 0, 0, 0.08);
--safe-area-inset-top: env(safe-area-inset-top, 0px);
--_sidebar-bg: var(--_neutral-100);
--sidebar-bg: var(--_sidebar-bg);
--_sidebar-shadow-light: rgba(255, 255, 255, 0.6);
--sidebar-shadow-light: var(--_sidebar-shadow-light);
--_sidebar-shadow-dark: rgba(0, 0, 0, 0.08);
--sidebar-shadow-dark: var(--_sidebar-shadow-dark);
--safe-area-inset-top: env(safe-area-inset-top, 0px);
--safe-area-inset-bottom: env(safe-area-inset-bottom, 0px);
/* --------------------------------------------------------
@@ -277,20 +341,30 @@
* -------------------------------------------------------- */
/* a) Glass-Hintergründe */
--glass-bg: rgba(255, 255, 255, 0.72);
--glass-bg-hover: rgba(255, 255, 255, 0.82);
--glass-bg-elevated: rgba(255, 255, 255, 0.88);
--glass-border: rgba(255, 255, 255, 0.60);
--glass-border-subtle: rgba(255, 255, 255, 0.35);
--_glass-bg: rgba(255, 255, 255, 0.72);
--glass-bg: var(--_glass-bg);
--_glass-bg-hover: rgba(255, 255, 255, 0.82);
--glass-bg-hover: var(--_glass-bg-hover);
--_glass-bg-elevated: rgba(255, 255, 255, 0.88);
--glass-bg-elevated: var(--_glass-bg-elevated);
--_glass-border: rgba(255, 255, 255, 0.60);
--glass-border: var(--_glass-border);
--_glass-border-subtle: rgba(255, 255, 255, 0.35);
--glass-border-subtle: var(--_glass-border-subtle);
/* a2) Glass-Hintergründe: Vibrancy-Stufe (transparenter, mehr Durchschein) */
--glass-bg-card: rgba(255, 255, 255, 0.52);
--glass-bg-card-hover: rgba(255, 255, 255, 0.65);
--glass-bg-input: rgba(255, 255, 255, 0.48);
--glass-bg-toolbar: rgba(255, 255, 255, 0.58);
--_glass-bg-card: rgba(255, 255, 255, 0.52);
--glass-bg-card: var(--_glass-bg-card);
--_glass-bg-card-hover: rgba(255, 255, 255, 0.65);
--glass-bg-card-hover: var(--_glass-bg-card-hover);
--_glass-bg-input: rgba(255, 255, 255, 0.48);
--glass-bg-input: var(--_glass-bg-input);
--_glass-bg-toolbar: rgba(255, 255, 255, 0.58);
--glass-bg-toolbar: var(--_glass-bg-toolbar);
/* a3) Tint: Modul-Akzentfarbe als subtile Glass-Tonung */
--glass-tint-strength: 6%;
--_glass-tint-strength: 6%;
--glass-tint-strength: var(--_glass-tint-strength);
/* b) Blur-Stufen */
--blur-xs: blur(4px);
@@ -305,8 +379,10 @@
--opacity-glass-elevated: 0.92;
/* d) Highlights / Specular */
--glass-highlight: rgba(255, 255, 255, 0.70);
--glass-highlight-subtle: rgba(255, 255, 255, 0.35);
--_glass-highlight: rgba(255, 255, 255, 0.70);
--glass-highlight: var(--_glass-highlight);
--_glass-highlight-subtle: rgba(255, 255, 255, 0.35);
--glass-highlight-subtle: var(--_glass-highlight-subtle);
/* d2) Inset-Specular: Oberrand-Sheen für Glass-Elemente (volle inset-Kurzform) */
--glass-inset-soft: inset 0 1px 0 rgba(255, 255, 255, 0.18);
@@ -316,9 +392,12 @@
--glass-inset-strong: inset 0 1px 0 rgba(255, 255, 255, 0.32);
/* e) Glass-Schatten */
--glass-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(255, 255, 255, 0.55);
--glass-shadow-md: 0 4px 20px rgba(0, 0, 0, 0.10), 0 0 0 1px rgba(255, 255, 255, 0.50);
--glass-shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.14), 0 0 0 1px rgba(255, 255, 255, 0.45);
--_glass-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(255, 255, 255, 0.55);
--glass-shadow-sm: var(--_glass-shadow-sm);
--_glass-shadow-md: 0 4px 20px rgba(0, 0, 0, 0.10), 0 0 0 1px rgba(255, 255, 255, 0.50);
--glass-shadow-md: var(--_glass-shadow-md);
--_glass-shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.14), 0 0 0 1px rgba(255, 255, 255, 0.45);
--glass-shadow-lg: var(--_glass-shadow-lg);
/* f) Glass-Radien */
--radius-glass-card: 20px;
@@ -332,215 +411,201 @@
}
/* ================================================================
* Dark Mode
* Zwei Selektoren: (1) System-Preference, (2) manueller Override
* via data-theme="dark" auf <html>.
* data-theme="light" erzwingt Light Mode (kein Dark-Override).
* Ohne data-theme folgt die App der System-Einstellung.
* Dark Mode — private Tokens überschreiben, öffentliche API bleibt stabil.
*
* Beide Selektoren überschreiben nur --_private Tokens. Die öffentlichen
* --color-* / --module-* / --glass-* Tokens müssen nie angefasst werden.
*
* (1) System-Preference — greift, wenn kein data-theme gesetzt ist.
* (2) Manueller Override — greift, wenn JS data-theme="dark" setzt
* (auch bei System in Light-Mode).
* ================================================================ */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
/* Neutral-Skala invertiert (warm-dunkel) */
--neutral-50: #1A1A18;
--neutral-100: #222220;
--neutral-150: #2A2A28;
--neutral-200: #333331;
--neutral-250: #3D3D3A;
--neutral-300: #48484A;
--neutral-400: #636360;
--neutral-500: #8E8D89;
--neutral-600: #AEADB0; /* WCAG AA: ~4.8:1 auf #2A2A28 */
--neutral-700: #C8C7C3;
--neutral-800: #E2E1DC;
--neutral-900: #F5F4F1;
--neutral-950: #FAFAF8;
--_neutral-50: #1A1A18;
--_neutral-100: #222220;
--_neutral-150: #2A2A28;
--_neutral-200: #333331;
--_neutral-250: #3D3D3A;
--_neutral-300: #48484A;
--_neutral-400: #636360;
--_neutral-500: #8E8D89;
--_neutral-600: #AEADB0; /* WCAG AA: ~4.8:1 auf #2A2A28 */
--_neutral-700: #C8C7C3;
--_neutral-800: #E2E1DC;
--_neutral-900: #F5F4F1;
--_neutral-950: #FAFAF8;
/* Semantische Aliase folgen automatisch via var(--neutral-*) */
--color-surface: #2A2A28;
--color-surface-2: #1A1A18;
--color-surface-3: #333331;
--_color-surface: #2A2A28;
--_color-surface-3: #333331; /* = neutral-200 dark */
/* Sidebar */
--sidebar-bg: #1A1A18;
--sidebar-shadow-light: rgba(255, 255, 255, 0.04);
--sidebar-shadow-dark: rgba(0, 0, 0, 0.4);
--_sidebar-bg: #1A1A18;
--_sidebar-shadow-light: rgba(255, 255, 255, 0.04);
--_sidebar-shadow-dark: rgba(0, 0, 0, 0.4);
/* Akzent - Dark Mode (Indigo bleibt, nur Lightness/Saturation rücken) */
--color-accent: #818CF8; /* Indigo-400 — 6.8:1 auf #2A2A28 */
--color-accent-hover: #6366F1; /* Indigo-500 */
--color-accent-active: #4F46E5; /* Indigo-600 (= Light-Primary, Mirroring) */
--color-accent-light: #2E2D5B;
--color-accent-subtle: #252255;
--color-btn-primary: #6366F1; /* Indigo-500 — 5.5:1 auf Dark-Surface */
--color-btn-primary-hover: #4F46E5;
--_color-accent: #818CF8; /* Indigo-400 — 6.8:1 auf #2A2A28 */
--_color-accent-hover: #6366F1; /* Indigo-500 */
--_color-accent-active: #4F46E5; /* Indigo-600 (= Light-Primary, Mirroring) */
--_color-accent-light: #2E2D5B;
--_color-accent-subtle: #252255;
--_color-btn-primary: #6366F1; /* Indigo-500 — 5.5:1 auf Dark-Surface */
--_color-btn-primary-hover: #4F46E5;
--_color-accent-secondary: #A78BFA;
--color-accent-secondary: #A78BFA;
/* Semantische Farben */
--_color-success: #4ADE80;
--_color-warning: #F59E0B;
--_color-danger: #FCA5A5;
--_color-text-tertiary: #A3A3A0;
--_color-success-light: #1A3325;
--_color-warning-light: #332400;
--_color-danger-light: #3D1C1A;
--_color-info-light: #1A2D40;
/* Semantische Farben - Dark Mode */
--color-success: #4ADE80;
--color-warning: #F59E0B;
--color-danger: #FCA5A5;
--color-text-tertiary: #A3A3A0;
/* Modul-Akzente (Entflechtung Meals/Shopping spiegelt Light-Mode) */
--_module-dashboard: #818CF8; /* Indigo-400 */
--_module-tasks: #4ADE80;
--_module-calendar: #A78BFA;
--_module-meals: #FB923C; /* Orange-400 */
--_module-shopping: #F472B6; /* Pink-400 */
--_module-notes: #FCD34D;
--_module-contacts: #60A5FA;
--_module-budget: #2DD4BF; /* Teal-400 */
--_module-settings: #94A3B8;
--color-success-light: #1A3325;
--color-warning-light: #332400;
--color-danger-light: #3D1C1A;
--color-info-light: #1A2D40;
/* Modul-Akzente - Dark Mode (Entflechtung Meals/Shopping spiegelt Light-Mode) */
--module-dashboard: #818CF8; /* Indigo-400 - folgt neuem Dark-Accent */
--module-tasks: #4ADE80;
--module-calendar: #A78BFA;
--module-meals: #FB923C; /* Orange-400 */
--module-shopping: #F472B6; /* Pink-400 - trennt wie in Light */
--module-notes: #FCD34D;
--module-contacts: #60A5FA;
--module-budget: #2DD4BF; /* Teal-400 - folgt Light-Mode-Teal */
--module-settings: #94A3B8;
/* Mahlzeit-Typ - Dark Mode */
--meal-breakfast: #F59E0B;
--meal-dinner: #818CF8; /* Indigo-400 - folgt Dark-Accent */
/* Mahlzeit-Typ Light-Varianten */
--meal-breakfast-light: #332400;
--meal-lunch-light: #1A3325;
--meal-dinner-light: #2E2D5B; /* Indigo-Dark-Tint (folgt --meal-dinner) */
--meal-snack-light: #3D2010;
/* Mahlzeit-Typ */
--_meal-breakfast: #F59E0B;
--_meal-breakfast-light: #332400;
--_meal-lunch-light: #1A3325;
--_meal-dinner: #818CF8; /* Indigo-400 */
--_meal-dinner-light: #2E2D5B;
--_meal-snack-light: #3D2010;
/* Priority-Badge Hintergründe */
--color-priority-none-bg: rgba(142, 141, 137, 0.12);
--color-priority-low-bg: rgba(142, 141, 137, 0.18);
--color-priority-medium-bg: rgba(230, 147, 10, 0.18);
--color-priority-high-bg: rgba(212, 81, 30, 0.18);
--color-priority-urgent-bg: rgba(229, 83, 75, 0.18);
--_color-priority-none-bg: rgba(142, 141, 137, 0.12);
--_color-priority-low-bg: rgba(142, 141, 137, 0.18);
--_color-priority-medium-bg: rgba(230, 147, 10, 0.18);
--_color-priority-high-bg: rgba(212, 81, 30, 0.18);
--_color-priority-urgent-bg: rgba(229, 83, 75, 0.18);
/* Overlay */
--color-overlay: rgba(0, 0, 0, 0.6);
--color-overlay-light: rgba(0, 0, 0, 0.35);
--_color-overlay: rgba(0, 0, 0, 0.6);
--_color-overlay-light: rgba(0, 0, 0, 0.35);
/* Schatten stärker im Dark Mode */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.25);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.45);
--_shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.25);
--_shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
--_shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.45);
/* Glass - Dark Mode */
--glass-bg: rgba(40, 40, 38, 0.75);
--glass-bg-hover: rgba(50, 50, 48, 0.82);
--glass-bg-elevated: rgba(58, 58, 55, 0.90);
--glass-border: rgba(255, 255, 255, 0.12);
--glass-border-subtle: rgba(255, 255, 255, 0.07);
--glass-highlight: rgba(255, 255, 255, 0.10);
--glass-highlight-subtle: rgba(255, 255, 255, 0.06);
--glass-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.30), 0 0 0 1px rgba(255, 255, 255, 0.08);
--glass-shadow-md: 0 4px 20px rgba(0, 0, 0, 0.40), 0 0 0 1px rgba(255, 255, 255, 0.07);
--glass-shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.06);
/* Vibrancy - Dark Mode */
--glass-bg-card: rgba(38, 38, 36, 0.50);
--glass-bg-card-hover: rgba(48, 48, 46, 0.62);
--glass-bg-input: rgba(34, 34, 32, 0.45);
--glass-bg-toolbar: rgba(40, 40, 38, 0.55);
--glass-tint-strength: 8%;
/* Glass */
--_glass-bg: rgba(40, 40, 38, 0.75);
--_glass-bg-hover: rgba(50, 50, 48, 0.82);
--_glass-bg-elevated: rgba(58, 58, 55, 0.90);
--_glass-border: rgba(255, 255, 255, 0.12);
--_glass-border-subtle: rgba(255, 255, 255, 0.07);
--_glass-highlight: rgba(255, 255, 255, 0.10);
--_glass-highlight-subtle: rgba(255, 255, 255, 0.06);
--_glass-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.30), 0 0 0 1px rgba(255, 255, 255, 0.08);
--_glass-shadow-md: 0 4px 20px rgba(0, 0, 0, 0.40), 0 0 0 1px rgba(255, 255, 255, 0.07);
--_glass-shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.06);
--_glass-bg-card: rgba(38, 38, 36, 0.50);
--_glass-bg-card-hover: rgba(48, 48, 46, 0.62);
--_glass-bg-input: rgba(34, 34, 32, 0.45);
--_glass-bg-toolbar: rgba(40, 40, 38, 0.55);
--_glass-tint-strength: 8%;
}
}
/* Manueller Dark-Mode-Override: data-theme="dark" auf <html> */
/* Manueller Dark-Mode-Override: data-theme="dark" auf <html> (auch bei System in Light-Mode) */
:root[data-theme="dark"] {
--neutral-50: #1A1A18;
--neutral-100: #222220;
--neutral-150: #2A2A28;
--neutral-200: #333331;
--neutral-250: #3D3D3A;
--neutral-300: #48484A;
--neutral-400: #636360;
--neutral-500: #8E8D89;
--neutral-600: #AEADB0;
--neutral-700: #C8C7C3;
--neutral-800: #E2E1DC;
--neutral-900: #F5F4F1;
--neutral-950: #FAFAF8;
--_neutral-50: #1A1A18;
--_neutral-100: #222220;
--_neutral-150: #2A2A28;
--_neutral-200: #333331;
--_neutral-250: #3D3D3A;
--_neutral-300: #48484A;
--_neutral-400: #636360;
--_neutral-500: #8E8D89;
--_neutral-600: #AEADB0;
--_neutral-700: #C8C7C3;
--_neutral-800: #E2E1DC;
--_neutral-900: #F5F4F1;
--_neutral-950: #FAFAF8;
--color-surface: #2A2A28;
--color-surface-2: #1A1A18;
--color-surface-3: #333331;
--_color-surface: #2A2A28;
--_color-surface-3: #333331;
--sidebar-bg: #1A1A18;
--sidebar-shadow-light: rgba(255, 255, 255, 0.04);
--sidebar-shadow-dark: rgba(0, 0, 0, 0.4);
--_sidebar-bg: #1A1A18;
--_sidebar-shadow-light: rgba(255, 255, 255, 0.04);
--_sidebar-shadow-dark: rgba(0, 0, 0, 0.4);
/* Akzent - Dark Mode (Indigo bleibt, nur Lightness/Saturation rücken) */
--color-accent: #818CF8; /* Indigo-400 — 6.8:1 auf #2A2A28 */
--color-accent-hover: #6366F1; /* Indigo-500 */
--color-accent-active: #4F46E5; /* Indigo-600 (= Light-Primary, Mirroring) */
--color-accent-light: #2E2D5B;
--color-accent-subtle: #252255;
--color-btn-primary: #6366F1; /* Indigo-500 — 5.5:1 auf Dark-Surface */
--color-btn-primary-hover: #4F46E5;
--color-accent-secondary: #A78BFA;
--_color-accent: #818CF8;
--_color-accent-hover: #6366F1;
--_color-accent-active: #4F46E5;
--_color-accent-light: #2E2D5B;
--_color-accent-subtle: #252255;
--_color-btn-primary: #6366F1;
--_color-btn-primary-hover: #4F46E5;
--_color-accent-secondary: #A78BFA;
/* Semantische Farben - Dark Mode */
--color-success: #4ADE80;
--color-warning: #F59E0B;
--color-danger: #FCA5A5;
--color-text-tertiary: #A3A3A0;
--_color-success: #4ADE80;
--_color-warning: #F59E0B;
--_color-danger: #FCA5A5;
--_color-text-tertiary: #A3A3A0;
--_color-success-light: #1A3325;
--_color-warning-light: #332400;
--_color-danger-light: #3D1C1A;
--_color-info-light: #1A2D40;
--color-success-light: #1A3325;
--color-warning-light: #332400;
--color-danger-light: #3D1C1A;
--color-info-light: #1A2D40;
--_module-dashboard: #818CF8;
--_module-tasks: #4ADE80;
--_module-calendar: #A78BFA;
--_module-meals: #FB923C;
--_module-shopping: #F472B6;
--_module-notes: #FCD34D;
--_module-contacts: #60A5FA;
--_module-budget: #2DD4BF;
--_module-settings: #94A3B8;
/* Modul-Akzente - Dark Mode (Entflechtung Meals/Shopping spiegelt Light-Mode) */
--module-dashboard: #818CF8; /* Indigo-400 - folgt neuem Dark-Accent */
--module-tasks: #4ADE80;
--module-calendar: #A78BFA;
--module-meals: #FB923C; /* Orange-400 */
--module-shopping: #F472B6; /* Pink-400 - trennt wie in Light */
--module-notes: #FCD34D;
--module-contacts: #60A5FA;
--module-budget: #2DD4BF; /* Teal-400 - folgt Light-Mode-Teal */
--module-settings: #94A3B8;
--_meal-breakfast: #F59E0B;
--_meal-breakfast-light: #332400;
--_meal-lunch-light: #1A3325;
--_meal-dinner: #818CF8;
--_meal-dinner-light: #2E2D5B;
--_meal-snack-light: #3D2010;
/* Mahlzeit-Typ - Dark Mode */
--meal-breakfast: #F59E0B;
--meal-dinner: #818CF8; /* Indigo-400 - folgt Dark-Accent */
--_color-priority-none-bg: rgba(142, 141, 137, 0.12);
--_color-priority-low-bg: rgba(142, 141, 137, 0.18);
--_color-priority-medium-bg: rgba(230, 147, 10, 0.18);
--_color-priority-high-bg: rgba(212, 81, 30, 0.18);
--_color-priority-urgent-bg: rgba(229, 83, 75, 0.18);
--meal-breakfast-light: #332400;
--meal-lunch-light: #1A3325;
--meal-dinner-light: #2E2D5B; /* Indigo-Dark-Tint (folgt --meal-dinner) */
--meal-snack-light: #3D2010;
--_color-overlay: rgba(0, 0, 0, 0.6);
--_color-overlay-light: rgba(0, 0, 0, 0.35);
--color-priority-none-bg: rgba(142, 141, 137, 0.12);
--color-priority-low-bg: rgba(142, 141, 137, 0.18);
--color-priority-medium-bg: rgba(230, 147, 10, 0.18);
--color-priority-high-bg: rgba(212, 81, 30, 0.18);
--color-priority-urgent-bg: rgba(229, 83, 75, 0.18);
--_shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.25);
--_shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
--_shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.45);
--color-overlay: rgba(0, 0, 0, 0.6);
--color-overlay-light: rgba(0, 0, 0, 0.35);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.25);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.45);
/* Glass - Dark Mode */
--glass-bg: rgba(40, 40, 38, 0.75);
--glass-bg-hover: rgba(50, 50, 48, 0.82);
--glass-bg-elevated: rgba(58, 58, 55, 0.90);
--glass-border: rgba(255, 255, 255, 0.12);
--glass-border-subtle: rgba(255, 255, 255, 0.07);
--glass-highlight: rgba(255, 255, 255, 0.10);
--glass-highlight-subtle: rgba(255, 255, 255, 0.06);
--glass-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.30), 0 0 0 1px rgba(255, 255, 255, 0.08);
--glass-shadow-md: 0 4px 20px rgba(0, 0, 0, 0.40), 0 0 0 1px rgba(255, 255, 255, 0.07);
--glass-shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.06);
/* Vibrancy - Dark Mode */
--glass-bg-card: rgba(38, 38, 36, 0.50);
--glass-bg-card-hover: rgba(48, 48, 46, 0.62);
--glass-bg-input: rgba(34, 34, 32, 0.45);
--glass-bg-toolbar: rgba(40, 40, 38, 0.55);
--glass-tint-strength: 8%;
--_glass-bg: rgba(40, 40, 38, 0.75);
--_glass-bg-hover: rgba(50, 50, 48, 0.82);
--_glass-bg-elevated: rgba(58, 58, 55, 0.90);
--_glass-border: rgba(255, 255, 255, 0.12);
--_glass-border-subtle: rgba(255, 255, 255, 0.07);
--_glass-highlight: rgba(255, 255, 255, 0.10);
--_glass-highlight-subtle: rgba(255, 255, 255, 0.06);
--_glass-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.30), 0 0 0 1px rgba(255, 255, 255, 0.08);
--_glass-shadow-md: 0 4px 20px rgba(0, 0, 0, 0.40), 0 0 0 1px rgba(255, 255, 255, 0.07);
--_glass-shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.06);
--_glass-bg-card: rgba(38, 38, 36, 0.50);
--_glass-bg-card-hover: rgba(48, 48, 46, 0.62);
--_glass-bg-input: rgba(34, 34, 32, 0.45);
--_glass-bg-toolbar: rgba(40, 40, 38, 0.55);
--_glass-tint-strength: 8%;
}
/* ================================================================