/* FocusApp website — Design "Ruhige Ebenen" (Phase 10), Paket 10b:
   Schrift, Tokens, Symbole, Komponenten, Login, Board und Übergänge.
   Paket 10c: Kopfzeile mit Tabs und Segmented Control, Seitenpanel mit
   drei Modi, Formular mit Chips und Sub-ToDo-Editor, zentrierte
   DailyToDo-Ansicht mit Fortschritt.

   Alle Farben, Abstände, Radien, Schatten, Dauern und Kurven stammen aus
   docs/07-design-system.md und stehen genau einmal als CSS-Variable in
   :root (docs/06, "Umsetzungsregeln für das JavaScript und CSS"). In den
   Regeln darunter stehen keine Farb-, px- oder ms-Werte mehr, nur noch
   Variablen, 0, Prozente und einheitenlose Faktoren.

   Nur Dark Mode: prefers-color-scheme wird bewusst nicht ausgewertet
   (docs/07, "Nur Dark Mode").

   Schriftangaben stehen immer als Einzeleigenschaften (font-size,
   line-height, font-weight), nie über die Kurzschreibweise "font" -- die
   Kurzschreibweise kann font-feature-settings zurücksetzen und damit die
   global gesetzten Zeichenvarianten cv05/cv08 verlieren. */

/* Inter 4.1, variabel, SIL Open Font License (Lizenz in fonts/OFL.txt).
   Selbst ausgeliefert, nichts von fremden Servern, nicht verkleinert
   (docs/07, "Auslieferung der Schrift"). */
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url("fonts/InterVariable.woff2") format("woff2");
}

:root {
    color-scheme: dark;

    /* --- Palette (docs/07, "Farbwerte") --------------------------------- */
    --bg: #1F1F1F;
    --surface: #292929;
    --surface-elevated: #333333;
    --stroke: #3D3D3D;
    --text-primary: #FFFFFF;
    --text-secondary: #D6D6D6;
    --text-tertiary: #ADADAD;
    --accent: #54B054;
    --accent-pressed: #479947;
    --danger: #F1707B;
    --overdue: #F1707B;

    /* Prioritätsfarben (docs/07, "Prioritätsfarben") */
    --prio-urgent: #F1707B;
    --prio-major: #EAA300;
    --prio-normal: #479EF5;
    --prio-minor: #ADADAD;

    /* Werte außerhalb der Palette (docs/07, "Zusätzliche Werte außerhalb
       der Palette"): Schwarz mit Deckkraft, keine neuen Farben. */
    --scrim: rgba(0, 0, 0, .5);
    --shadow-1: 0 2px 6px rgba(0, 0, 0, .3), 0 8px 20px rgba(0, 0, 0, .3);
    --shadow-2: 0 4px 12px rgba(0, 0, 0, .35), 0 24px 56px rgba(0, 0, 0, .5);
    --danger-hover-brightness: .92;

    /* --- Ebenen (docs/07, "Ebenen und Schatten") -------------------------
       Ebene 0 Leinwand: bg, keine Trennung. Ebene 1 Inhalt: surface mit
       Rand in stroke, kein Schatten. Ebene 2 schwebend und Ebene 3 modal:
       Schatten plus 1 px Ring in stroke (hier als zweiter box-shadow). */
    --hairline: 1px;
    --elevation-2: var(--shadow-1), 0 0 0 var(--hairline) var(--stroke);
    --elevation-3: var(--shadow-2), 0 0 0 var(--hairline) var(--stroke);

    /* --- Schrift und Typografie-Skala (docs/07, "Typografie-Skala") ------ */
    --font-family: "Inter", "Segoe UI", system-ui, sans-serif;

    --text-display-size: 28px;
    --text-display-line: 34px;
    --text-display-weight: 650;
    --text-display-tracking: -0.02em;

    --text-title-1-size: 20px;
    --text-title-1-line: 28px;
    --text-title-1-weight: 600;
    --text-title-1-tracking: -0.015em;

    --text-title-2-size: 17px;
    --text-title-2-line: 24px;
    --text-title-2-weight: 600;

    --text-title-3-size: 14px;
    --text-title-3-line: 20px;
    --text-title-3-weight: 600;

    --text-body-strong-size: 14px;
    --text-body-strong-line: 20px;
    --text-body-strong-weight: 500;

    --text-body-size: 14px;
    --text-body-line: 22px;
    --text-body-weight: 400;

    --text-meta-size: 12px;
    --text-meta-line: 16px;
    --text-meta-weight: 450;

    --text-label-size: 12px;
    --text-label-line: 16px;
    --text-label-weight: 550;

    /* Abgeleitete Schriftwerte einzelner Komponenten (docs/07,
       "Eingabefeld" und "Wortmarke"). */
    --text-title-field-size: 16px;
    --text-title-field-weight: 550;
    --text-wordmark-weight: 650;
    --text-wordmark-tracking: -0.02em;
    --text-wordmark-header-size: 16px;
    /* Gewicht der Button-Beschriftung: docs/07 legt es nicht fest, Wert aus
       dem freigegebenen Prototyp. */
    --text-button-weight: 550;

    /* --- Abstände: Raster 4, dazu die Feinabstände 6 und 10 -------------
       (docs/07, "Abstände") */
    --space-4: 4px;
    --space-6: 6px;
    --space-8: 8px;
    --space-10: 10px;
    --space-12: 12px;
    --space-16: 16px;
    --space-20: 20px;
    --space-24: 24px;
    --space-32: 32px;
    --space-40: 40px;
    --space-48: 48px;

    --page-margin: var(--space-24);
    --column-gap: var(--space-24);
    --card-gap: var(--space-8);
    --card-padding: var(--space-12);
    --checkbox-title-gap: var(--space-10);
    --title-meta-gap: var(--space-6);
    --label-gap: var(--space-6);
    --field-gap: var(--space-20);
    --dialog-padding: var(--space-24);
    --header-height: 60px;
    --list-end-space: var(--space-24);
    /* Abstand des Boards unter der Kopfzeile: nicht in docs/07, Wert aus dem
       Prototyp. */
    --board-top: var(--space-20);
    --fade-width: var(--space-24);

    /* --- Radien (docs/07, "Radien") ------------------------------------- */
    --r-xs: 4px;
    --r-sm: 8px;
    --r-md: 12px;
    --r-lg: 16px;
    --r-full: 999px;

    /* --- Bauteilmaße (docs/07, "Komponenten") --------------------------- */
    --column-width: 280px;
    --column-header-height: 40px;
    --checkbox-size: 20px;
    --checkbox-size-sm: 18px;
    --checkbox-hit: 32px;
    --checkbox-ring: 1.5px;
    --checkbox-check-size: 14px;
    --checkbox-check-size-sm: 12px;
    --checkbox-check-stroke: 2.5;
    --check-dash: 22;
    --icon-size: 20px;
    --icon-size-sm: 16px;
    --icon-size-xs: 14px;
    --icon-size-empty: 28px;
    --icon-stroke: 1.75;
    --icon-button-size: 32px;
    --button-height: 36px;
    --input-height: 40px;
    --dialog-width: 400px;
    /* Panel (docs/06, "Das Panel und seine drei Modi"): 12 px vom
       Fensterrand, 480 breit, Kopf 56; Eigenschaften-Raster mit einer
       festen Spalte von 112 (docs/06, "ToDo-Detail-Panel"). */
    --panel-width: 480px;
    --panel-inset: var(--space-12);
    --panel-header-height: 56px;
    --property-label-width: 112px;
    --property-row-height: 32px;
    --error-bar-height: 36px;
    --menu-item-height: 36px;
    --menu-min-width: 160px;
    --completed-toggle-height: 32px;
    --login-width: 340px;
    --daily-column-width: 640px;
    --progress-width: 96px;
    --progress-height: 4px;
    --segment-height: 36px;
    --segment-padding: 3px;
    --chip-height: 32px;
    --tab-indicator-height: 2px;
    --header-sep-height: 24px;
    --subtodo-row-height: 36px;
    --subtodo-marker-size: 16px;
    --subtodo-dot-size: 5px;
    --dot-size: 8px;
    --spinner-size: 16px;
    --spinner-stroke: 2px;
    --focus-ring: 2px;
    --focus-offset: 2px;
    --wordmark-glyph-size: 20px;
    --wordmark-glyph-stroke: 4;
    --skeleton-line-width: 96px;
    --skeleton-line-height: 12px;
    --skeleton-card-height: 84px;
    --skeleton-card-height-short: 64px;
    --nav-disabled-opacity: .5;

    /* Stapelreihenfolge */
    --z-menu: 5;
    --z-panel: 10;
    --z-dialog: 30;
    --z-snackbar: 40;

    /* --- Bewegung (docs/07, "Bewegung") --------------------------------- */
    --d1: 100ms;
    --d2: 160ms;
    --d3: 240ms;
    --d4: 320ms;
    --ease-standard: cubic-bezier(.2, 0, 0, 1);
    --ease-in: cubic-bezier(.05, .7, .1, 1);
    --ease-out: cubic-bezier(.3, 0, .8, .15);
    --ease-pop: cubic-bezier(.34, 1.56, .64, 1);

    /* Abhaken: Kreis füllt sich mit Pop in --d3, der Haken zeichnet sich
       gleichzeitig um --check-delay versetzt in --d2. --check-pause ist der
       Abstand zwischen Erfolg und dem nächsten Schritt (docs/06, "Abhaken:
       Wartezustand und Übergang"); app.js liest den Wert von hier. */
    --check-delay: 40ms;
    --check-pause: 360ms;

    /* Abweichende Dauern aus dem Katalog der Übergänge (docs/07): der
       Fade-through beim Wechsel der Ansicht (aus 90, ein 220) und das
       Entfernen einer Sub-ToDo-Zeile (200). */
    --fade-through-out: 90ms;
    --fade-through-in: 220ms;
    --row-out: 200ms;

    /* Skalierungen und Versätze aus dem Katalog der Übergänge */
    --scale-pop-from: .7;
    --scale-dialog-in: .94;
    --scale-dialog-out: .97;
    --scale-menu-in: .92;
    --scale-card-in: .97;
    --snackbar-in-offset: 16px;
    --snackbar-out-offset: 8px;
    --fade-through-rise: 6px;
    --swap-rise: 6px;
    --row-rise: 4px;
    --panel-offset: 40px;

    /* Perioden der Wartespinner und des Skeletons. Bewusst eigene Tokens:
       Sie bleiben bei "Bewegung reduzieren" unverändert, weil die Spinner
       einen Zustand zeigen (docs/07, "Bewegung reduzieren"). */
    --spinner-period: 800ms;
    --button-spinner-period: 700ms;
    --skeleton-period: 1400ms;
    --skeleton-dim: .55;
}

/* Bewegung reduzieren: alle Übergänge laufen mit 1 ms, nur die
   Wartespinner drehen weiter (docs/07, "Bewegung reduzieren"). */
@media (prefers-reduced-motion: reduce) {
    :root {
        --d1: 1ms;
        --d2: 1ms;
        --d3: 1ms;
        --d4: 1ms;
        --check-delay: 1ms;
        --check-pause: 1ms;
        --fade-through-out: 1ms;
        --fade-through-in: 1ms;
        --row-out: 1ms;
    }

    .skeleton {
        animation: none;
    }
}

/* Sichtbarkeit wird über das hidden-Attribut gesteuert. Diese Regel gewinnt
   gegen id-Selektoren, die display: flex setzen. */
[hidden] {
    display: none !important;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--text-primary);
    font-family: var(--font-family);
    font-size: var(--text-body-size);
    line-height: var(--text-body-strong-line);
    font-weight: var(--text-body-weight);
    /* cv05: l mit Haken, cv08: I mit Serifen -- "AI" und "Al" sind
       unterscheidbar (docs/07, "Schrift: Inter"). */
    font-feature-settings: "cv05", "cv08";
    -webkit-font-smoothing: antialiased;
}

button,
input,
select,
textarea {
    font-family: inherit;
    font-size: inherit;
    line-height: inherit;
    font-weight: inherit;
    font-feature-settings: inherit;
    color: inherit;
}

button {
    cursor: pointer;
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

@keyframes fade-in {
    from { opacity: 0; }
}

@keyframes fade-out {
    to { opacity: 0; }
}

/* --- Symbole (docs/07, "Symbole") ------------------------------------- */

.icon-sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

.icon {
    width: var(--icon-size);
    height: var(--icon-size);
    flex: 0 0 auto;
    fill: none;
    stroke: currentColor;
    stroke-width: var(--icon-stroke);
    stroke-linecap: round;
    stroke-linejoin: round;
}

.icon--sm {
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
}

.icon--xs {
    width: var(--icon-size-xs);
    height: var(--icon-size-xs);
}

/* --- Wortmarke (docs/07, "Wortmarke") --------------------------------- */

.wordmark {
    display: inline-flex;
    align-items: center;
    gap: var(--space-10);
    margin: 0;
    color: var(--text-primary);
    font-weight: var(--text-wordmark-weight);
    letter-spacing: var(--text-wordmark-tracking);
}

.wordmark--header {
    font-size: var(--text-wordmark-header-size);
    line-height: var(--text-body-strong-line);
}

.wordmark--login {
    justify-content: center;
    margin-bottom: var(--space-12);
    font-size: var(--text-display-size);
    line-height: var(--text-display-line);
}

/* Das Zeichen von FocusApp (docs/07, "Konstruktion des Zeichens"):
   Zeichenfläche 48, in der Wortmarke mit dem feinen Strich 4 (in Einheiten
   der Zeichenfläche). Gehört nicht zum Symbol-Set, deshalb nicht .icon. */
.wordmark-glyph {
    width: var(--wordmark-glyph-size);
    height: var(--wordmark-glyph-size);
    flex: 0 0 auto;
    fill: none;
    stroke: var(--accent);
    stroke-width: var(--wordmark-glyph-stroke);
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* --- Buttons (docs/07, "Buttons") -------------------------------------
   Alle Buttons sind Pillen. Inhalt auf accent- und danger-Flächen steht in
   bg (docs/07, "Inhalt auf grünen und roten Flächen steht in bg"). */

.btn {
    height: var(--button-height);
    padding: 0 var(--space-16);
    border: var(--hairline) solid transparent;
    border-radius: var(--r-full);
    background: transparent;
    color: var(--text-secondary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-8);
    font-size: var(--text-body-size);
    line-height: var(--text-body-strong-line);
    font-weight: var(--text-button-weight);
    white-space: nowrap;
    transition:
        background-color var(--d1) var(--ease-standard),
        border-color var(--d1) var(--ease-standard),
        color var(--d1) var(--ease-standard),
        filter var(--d1) var(--ease-standard);
}

.btn .icon {
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
}

.btn:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: var(--focus-offset);
}

.btn--block {
    width: 100%;
}

.btn--primary {
    background: var(--accent);
    color: var(--bg);
}

.btn--primary:hover:not(:disabled),
.btn--primary:active:not(:disabled) {
    background: var(--accent-pressed);
}

.btn--secondary {
    border-color: var(--stroke);
    color: var(--text-secondary);
}

/* Der Sekundärbutton steht auf surface-elevated (Dialog, Panel). Für diese
   Fläche nennt docs/07 keinen Hover; verwendet wird stroke wie beim
   Icon-Button. */
.btn--secondary:hover:not(:disabled),
.btn--secondary:active:not(:disabled) {
    background: var(--stroke);
}

.btn--ghost {
    padding: 0 var(--space-12);
    color: var(--text-secondary);
}

/* Ghost liegt auf der Leinwand: Hover in surface (docs/07, "Hover und
   Pressed"). */
.btn--ghost:hover:not(:disabled),
.btn--ghost:active:not(:disabled) {
    background: var(--surface);
}

.btn--danger {
    background: var(--danger);
    color: var(--bg);
}

.btn--danger:hover:not(:disabled),
.btn--danger:active:not(:disabled) {
    filter: brightness(var(--danger-hover-brightness));
}

/* Deaktiviert: Fläche stroke, Text text-tertiary. */
.btn:disabled {
    background: var(--stroke);
    border-color: transparent;
    color: var(--text-tertiary);
    cursor: default;
}

/* Laufend: Spinner im Button, Beschriftung bleibt stehen, keine weitere
   Eingabe (disabled ist gesetzt). Das Aussehen bleibt das des aktiven
   Buttons, damit "läuft" nicht wie "deaktiviert" aussieht. */
.btn.is-running {
    cursor: progress;
}

.btn.is-running::before {
    content: "";
    width: var(--spinner-size);
    height: var(--spinner-size);
    flex: 0 0 auto;
    border: var(--spinner-stroke) solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spin var(--button-spinner-period) linear infinite;
}

.btn--primary.is-running:disabled {
    background: var(--accent);
    color: var(--bg);
}

.btn--secondary.is-running:disabled {
    background: transparent;
    border-color: var(--stroke);
    color: var(--text-secondary);
}

.btn--ghost.is-running:disabled {
    background: transparent;
    color: var(--text-secondary);
}

.btn--danger.is-running:disabled {
    background: var(--danger);
    color: var(--bg);
    filter: none;
}

/* --- Icon-Button (docs/07, "Icon-Button") ----------------------------- */

.icon-btn {
    width: var(--icon-button-size);
    height: var(--icon-button-size);
    flex: 0 0 auto;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-secondary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition:
        background-color var(--d1) var(--ease-standard),
        color var(--d1) var(--ease-standard);
}

/* Hover und Pressed in stroke (docs/07, "Icon-Button" und "Hover und
   Pressed"). */
.icon-btn:hover:not(:disabled),
.icon-btn:active:not(:disabled) {
    background: var(--stroke);
}

.icon-btn:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: var(--focus-offset);
}

/* --- Eingabefelder (docs/07, "Eingabefeld") --------------------------- */

.field {
    display: flex;
    flex-direction: column;
    gap: var(--label-gap);
}

.field-label {
    font-size: var(--text-label-size);
    line-height: var(--text-label-line);
    font-weight: var(--text-label-weight);
    color: var(--text-tertiary);
}

.input {
    width: 100%;
    height: var(--input-height);
    padding: 0 var(--space-12);
    border: var(--hairline) solid var(--stroke);
    border-radius: var(--r-sm);
    background: var(--bg);
    color: var(--text-primary);
    font-size: var(--text-body-size);
    line-height: var(--text-body-line);
    font-weight: var(--text-body-weight);
    outline: none;
    transition:
        border-color var(--d1) var(--ease-standard),
        box-shadow var(--d1) var(--ease-standard);
}

.input::placeholder {
    color: var(--text-tertiary);
    opacity: 1;
}

/* Fokus: Rand und 1 px zusätzlicher Ring in accent. */
.input:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 var(--hairline) var(--accent);
}

.input:disabled {
    color: var(--text-tertiary);
}

/* Titelfeld im Formular: eine Stufe größer. */
.input--title {
    font-size: var(--text-title-field-size);
    font-weight: var(--text-title-field-weight);
}

.input--multiline {
    height: auto;
    padding: var(--space-8) var(--space-12);
    resize: vertical;
}

/* --- Checkbox (docs/07, "Checkbox") -----------------------------------
   Nachgebaut aus einer unsichtbaren input-Checkbox plus eigenem Element:
   label.cb > input.cb-input + span.cb-ring + svg.cb-check. Das Input liegt
   unsichtbar über der Box und bleibt fokussier- und bedienbar; ::before
   vergrößert die Trefferfläche auf 32 px. Server-First: app.js verhindert
   das Umschalten beim Klick und setzt checked erst nach der Antwort. */

.cb {
    --cb-size: var(--checkbox-size);
    position: relative;
    width: var(--cb-size);
    height: var(--cb-size);
    flex: 0 0 auto;
    border-radius: 50%;
    display: inline-grid;
    place-items: center;
    color: var(--bg);
    cursor: pointer;
}

.cb--sm {
    --cb-size: var(--checkbox-size-sm);
}

.cb::before {
    content: "";
    position: absolute;
    inset: calc((var(--cb-size) - var(--checkbox-hit)) / 2);
    border-radius: 50%;
}

.cb-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
    z-index: 1;
}

.cb-input:disabled {
    cursor: default;
}

/* Leer: Ring 1,5 in text-tertiary. */
.cb-ring {
    position: absolute;
    inset: 0;
    border: var(--checkbox-ring) solid var(--text-tertiary);
    border-radius: 50%;
    transition:
        border-color var(--d1) var(--ease-standard),
        background-color var(--d1) var(--ease-standard);
}

.cb .cb-check {
    position: relative;
    width: var(--checkbox-check-size);
    height: var(--checkbox-check-size);
    stroke-width: var(--checkbox-check-stroke);
    stroke-dasharray: var(--check-dash);
    stroke-dashoffset: var(--check-dash);
    pointer-events: none;
}

.cb--sm .cb-check {
    width: var(--checkbox-check-size-sm);
    height: var(--checkbox-check-size-sm);
}

/* Gesetzt: Fläche accent, Haken in bg. */
.cb-input:checked ~ .cb-ring {
    background: var(--accent);
    border-color: var(--accent);
}

.cb-input:checked ~ .cb-check {
    stroke-dashoffset: 0;
    color: var(--bg);
}

/* Hover (nur Website): Ring und Haken-Vorschau in accent. */
.cb:hover .cb-input:enabled:not(:checked) ~ .cb-ring {
    border-color: var(--accent);
}

.cb:hover .cb-input:enabled:not(:checked) ~ .cb-check {
    stroke-dashoffset: 0;
    color: var(--accent);
}

.cb-input:focus-visible ~ .cb-ring {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: var(--focus-offset);
}

/* Wartend: Ring in stroke mit drehendem Viertelbogen in accent, solange
   der Request läuft. */
.cb.is-waiting .cb-ring {
    border-color: var(--stroke);
    border-top-color: var(--accent);
    background: transparent;
    animation: spin var(--spinner-period) linear infinite;
}

.cb.is-waiting .cb-check {
    visibility: hidden;
}

/* Erfolg: Der Kreis füllt sich mit Pop von 0,7 auf 1, gleichzeitig und um
   --check-delay versetzt zeichnet sich der Haken. */
.cb.is-popping .cb-ring {
    animation: cb-pop var(--d3) var(--ease-pop);
}

.cb.is-popping .cb-check {
    animation: cb-draw var(--d2) var(--ease-standard) var(--check-delay) both;
}

@keyframes cb-pop {
    from { transform: scale(var(--scale-pop-from)); }
}

@keyframes cb-draw {
    from { stroke-dashoffset: var(--check-dash); }
    to { stroke-dashoffset: 0; }
}

/* --- Segmented Control (docs/07, "Segmented Control") -----------------
   Für jede Auswahl aus zwei oder drei gleichrangigen Werten: Sortierung,
   Typ und Status im Formular. Die Segmente sind gleich breit, damit der
   Daumen ohne Messen gleiten kann: Er ist genau ein Segment breit und wird
   über --seg-index verschoben, das app.js am Element setzt. Spur in
   surface auf der Leinwand, in bg auf Ebene 3 (seg--elevated). */

.seg {
    --seg-count: 3;
    --seg-index: 0;
    position: relative;
    flex: 0 0 auto;
    height: var(--segment-height);
    padding: var(--segment-padding);
    display: inline-grid;
    grid-template-columns: repeat(var(--seg-count), 1fr);
    border-radius: var(--r-full);
    background: var(--surface);
}

.seg--elevated {
    background: var(--bg);
}

.seg--full {
    display: grid;
    width: 100%;
}

.seg-thumb {
    position: absolute;
    top: var(--segment-padding);
    bottom: var(--segment-padding);
    left: var(--segment-padding);
    width: calc((100% - 2 * var(--segment-padding)) / var(--seg-count));
    border-radius: var(--r-full);
    background: var(--stroke);
    transform: translateX(calc(var(--seg-index) * 100%));
    transition: transform var(--d3) var(--ease-standard);
}

.seg-option {
    position: relative;
    z-index: 1;
    min-width: 0;
    padding: 0 var(--space-12);
    border: 0;
    border-radius: var(--r-full);
    background: none;
    color: var(--text-tertiary);
    font-size: var(--text-body-size);
    font-weight: var(--text-button-weight);
    white-space: nowrap;
    transition: color var(--d2) var(--ease-standard);
}

.seg-option:hover {
    color: var(--text-secondary);
}

.seg-option[aria-pressed="true"] {
    color: var(--text-primary);
}

.seg-option:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: calc(-1 * var(--focus-ring));
}

/* --- Chips (docs/07, "Chips") -----------------------------------------
   Auswahl der Priorität im Formular: Pille mit Farbpunkt und Name. */

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-8);
}

.chip {
    height: var(--chip-height);
    padding: 0 var(--space-12) 0 var(--space-10);
    display: inline-flex;
    align-items: center;
    gap: var(--space-8);
    border: var(--hairline) solid var(--stroke);
    border-radius: var(--r-full);
    background: transparent;
    color: var(--text-secondary);
    font-size: var(--text-body-size);
    font-weight: var(--text-body-strong-weight);
    transition:
        background-color var(--d1) var(--ease-standard),
        border-color var(--d1) var(--ease-standard),
        color var(--d1) var(--ease-standard);
}

.chip[aria-pressed="true"] {
    background: var(--stroke);
    border-color: var(--text-tertiary);
    color: var(--text-primary);
}

.chip:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: var(--focus-offset);
}

/* --- Tabs "ToDos | DailyToDos" (docs/06, "Die Kopfzeile") -------------
   Aktiver Tab in text-primary mit Unterstrich in accent, inaktiver in
   text-tertiary. Der Unterstrich ist ein einziges Element, das beim
   Wechsel gleitet (docs/07, Katalog: "Tab-Unterstrich"); app.js setzt
   Position und Breite nach dem aktiven Tab. */

.tabs {
    position: relative;
    align-self: stretch;
    display: flex;
    align-items: stretch;
    gap: var(--space-4);
}

.tab {
    padding: 0 var(--space-12);
    border: 0;
    background: none;
    color: var(--text-tertiary);
    font-size: var(--text-body-size);
    font-weight: var(--text-button-weight);
    transition: color var(--d2) var(--ease-standard);
}

.tab:hover {
    color: var(--text-secondary);
}

.tab[aria-selected="true"] {
    color: var(--text-primary);
}

.tab:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: calc(-1 * var(--focus-ring));
}

/* Liegt auf der Haarlinie der Kopfzeile auf. */
.tabs-indicator {
    position: absolute;
    left: 0;
    bottom: calc(-1 * var(--hairline));
    width: 0;
    height: var(--tab-indicator-height);
    border-radius: var(--r-xs) var(--r-xs) 0 0;
    background: var(--accent);
    transition:
        transform var(--d3) var(--ease-standard),
        width var(--d3) var(--ease-standard);
}

/* --- Kopfzeile (docs/06, "Die Kopfzeile") ------------------------------
   60 px, auf der Leinwand, Haarlinie unten, scrollt nie mit. Links die
   Wortmarke, rechts rechtsbündig die Bedienelemente. */

.app-header {
    flex: 0 0 auto;
    height: var(--header-height);
    display: flex;
    align-items: center;
    gap: var(--space-24);
    padding: 0 var(--page-margin);
    border-bottom: var(--hairline) solid var(--stroke);
    background: var(--bg);
}

.app-header-left {
    display: flex;
    align-items: center;
    gap: var(--space-24);
}

.app-header-right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-12);
}

/* Senkrechter Trennstrich zwischen Segmented Control und "New ToDo". */
.header-sep {
    flex: 0 0 auto;
    width: var(--hairline);
    height: var(--header-sep-height);
    background: var(--stroke);
}

/* Beide Beschriftungen von "New ToDo" / "New DailyToDo" liegen in
   derselben Raster-Zelle; die unsichtbare hält die Breite. Damit
   verrutscht der Button beim Tabwechsel nicht (docs/06, "Die
   Kopfzeile"). */
.new-label {
    display: grid;
    justify-items: center;
}

.new-label > span {
    grid-area: 1 / 1;
}

.new-label > .is-inactive {
    visibility: hidden;
}

/* Blätter-Pfeile: zwei Icon-Buttons in einer gemeinsamen Pille (docs/07,
   "Die Blätter-Pfeile der Website"). Die Pille bleibt in beiden Zuständen
   stehen, nur das Symbol wird gedämpft. */
.date-nav {
    display: inline-flex;
    border-radius: var(--r-full);
    background: var(--surface);
}

.date-nav .icon-btn {
    color: var(--text-primary);
}

.date-nav .icon-btn:disabled {
    color: var(--text-tertiary);
    opacity: var(--nav-disabled-opacity);
    cursor: default;
}

/* --- Skeleton beim ersten Laden (docs/07, "Skeleton") ------------------ */

#loading {
    height: 100vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.skeleton-board {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    gap: var(--column-gap);
    padding: var(--board-top) var(--page-margin) 0;
    overflow: hidden;
}

.skeleton-cards {
    display: flex;
    flex-direction: column;
    gap: var(--card-gap);
}

.skeleton {
    animation: skeleton-pulse var(--skeleton-period) ease-in-out infinite;
}

.skeleton-line {
    display: block;
    width: var(--skeleton-line-width);
    height: var(--skeleton-line-height);
    border-radius: var(--r-xs);
    background: var(--stroke);
}

.skeleton-card {
    height: var(--skeleton-card-height);
    border-radius: var(--r-md);
    background: var(--surface);
}

.skeleton-card--short {
    height: var(--skeleton-card-height-short);
}

@keyframes skeleton-pulse {
    50% { opacity: var(--skeleton-dim); }
}

/* --- Login (docs/06, "Screen: Login") ---------------------------------
   Ohne Karte, zentriert auf der Leinwand. */

#login {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: var(--page-margin);
}

.login-column {
    width: var(--login-width);
    max-width: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--field-gap);
}

/* Meldung unter den Feldern, immer mit Symbol davor. Fehler in danger,
   "Session expired" bewusst nicht rot, sondern in text-secondary. */
.login-message {
    margin: 0;
    display: flex;
    align-items: center;
    gap: var(--space-8);
    color: var(--danger);
}

.login-message--info {
    color: var(--text-secondary);
}

/* --- Board: Rahmen ------------------------------------------------------
   Die Seite selbst scrollt nicht (docs/06, "Das Fenster-Layout: die Seite
   selbst scrollt nicht"): #board ist genau so hoch wie das Fenster, die
   Kopfzeile und gegebenenfalls der rote Balken sind fix, und #content-area
   darunter füllt die restliche Höhe und scrollt selbst. Nur so liegt die
   waagrechte Scrollleiste der Date-Ansicht am unteren Fensterrand. */

#board {
    height: 100vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Das Skeleton wird beim ersten Laden per Einblenden ersetzt. */
#board.is-entering {
    animation: fade-in var(--d3) var(--ease-in);
}

#content-area {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    position: relative;
}

/* --- Roter Balken (docs/07, "Roter Balken") ---------------------------
   Die Hülle animiert ihre Höhe über grid-template-rows (0fr auf 1fr), der
   Inhaltsbereich darunter gleitet mit, statt zu springen. Er bleibt ein
   Element der Flex-Spalte von #board, #content-area wird um seine Höhe
   kürzer. */

.error-bar {
    flex: 0 0 auto;
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--d3) var(--ease-standard);
}

.error-bar.is-shown {
    grid-template-rows: 1fr;
}

.error-bar-clip {
    min-height: 0;
    overflow: hidden;
}

.error-bar-content {
    height: var(--error-bar-height);
    display: flex;
    align-items: center;
    gap: var(--space-8);
    padding: 0 var(--page-margin);
    background: var(--danger);
    color: var(--bg);
    font-weight: var(--text-label-weight);
}

.error-bar-content .icon {
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
}

/* --- Snackbar "Action failed" (docs/07, "Snackbar") -------------------
   Unten links, 24 px vom Rand, über der waagrechten Scrollleiste. */

.snackbar {
    position: fixed;
    left: var(--page-margin);
    bottom: var(--page-margin);
    z-index: var(--z-snackbar);
    display: flex;
    align-items: center;
    gap: var(--space-8);
    padding: var(--space-12) var(--space-16) var(--space-12) var(--space-12);
    border-radius: var(--r-md);
    background: var(--surface-elevated);
    color: var(--text-primary);
    box-shadow: var(--elevation-2);
    font-weight: var(--text-body-strong-weight);
    animation: snackbar-in var(--d3) var(--ease-in);
}

.snackbar .icon {
    color: var(--danger);
}

.snackbar.is-leaving {
    animation: snackbar-out var(--d2) var(--ease-out) forwards;
}

@keyframes snackbar-in {
    from {
        opacity: 0;
        transform: translateY(var(--snackbar-in-offset));
    }
}

@keyframes snackbar-out {
    to {
        opacity: 0;
        transform: translateY(var(--snackbar-out-offset));
    }
}

/* --- Leerzustand (docs/07, "Leerzustand") -----------------------------
   Zentrierte Überlagerung über dem Inhaltsbereich, kein Element im Fluss,
   nimmt keine Klicks an (docs/06, "Der Leerzustandstext liegt über dem
   Board"). */

.empty-state {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-8);
    color: var(--text-tertiary);
    pointer-events: none;
}

.empty-state .icon--empty {
    width: var(--icon-size-empty);
    height: var(--icon-size-empty);
    color: var(--stroke);
}

/* --- Board-Ansichten (Priority / Status / Date) ------------------------ */

#todos-view {
    height: 100%;
    display: flex;
    flex-direction: column;
    position: relative;
}

#board-columns {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    align-items: stretch;
    gap: var(--column-gap);
    padding: var(--board-top) var(--page-margin) 0;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-color: var(--stroke) transparent;
}

/* Spalten haben keine eigene Fläche und keinen Rand (docs/07, "Board-
   Spalten haben keine eigene Fläche"). Eine Spalte besteht aus zwei
   Bereichen untereinander: dem Kopf mit seiner eigenen Höhe und darunter
   dem senkrecht scrollbaren Bereich mit den Karten. Der Kopf liegt
   bewusst außerhalb dieses Scrollbereichs statt über position: sticky
   darin zu kleben (docs/06, "Der Spaltenkopf liegt außerhalb des
   Scrollbereichs der Karten"): Eine sticky-Variante ergab Karten, die über
   dem Kopf gemalt wurden, und einen Streifen oberhalb des Kopfes, in dem
   der Inhalt durchscrollte. Seit der Kopf keine Fläche mehr hat, ist die
   Trennung erst recht nötig, sonst würden die Karten durch ihn
   hindurchscheinen. */
.column {
    flex: 0 0 var(--column-width);
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.column-header {
    flex: 0 0 auto;
    height: var(--column-header-height);
    display: flex;
    align-items: center;
    gap: var(--space-8);
    padding-bottom: var(--space-8);
    color: var(--text-primary);
    font-size: var(--text-title-3-size);
    line-height: var(--text-title-3-line);
    font-weight: var(--text-title-3-weight);
    font-variant-numeric: tabular-nums;
}

/* Datumsüberschrift der Date-Ansicht: die Farbe zeigt den Bezug zum
   heutigen Tag (docs/07, "Die Datumsüberschrift der Date-Ansicht").
   Künftige Tage bleiben in text-primary. */
.column-header--overdue {
    color: var(--overdue);
}

.column-header--today {
    color: var(--accent);
}

/* Anzahl hinter dem Namen, immer in text-tertiary, auch hinter einem
   farbigen Datum (docs/07, "Gruppen- und Spaltenkopf"). */
.column-count {
    color: var(--text-tertiary);
    font-weight: var(--text-body-strong-weight);
}

/* Kopf der einklappbaren Spalte "Completed" der Status-Ansicht: zugleich
   der Schalter zum Auf- und Zuklappen. */
.column-header-toggle {
    width: 100%;
    margin: 0;
    padding-top: 0;
    padding-left: 0;
    padding-right: 0;
    border: 0;
    background: none;
    text-align: left;
    cursor: pointer;
}

.column-header-toggle .icon {
    color: var(--text-tertiary);
    transition: transform var(--d3) var(--ease-standard);
}

.column-header-toggle[aria-expanded="true"] .icon {
    transform: rotate(90deg);
}

.column-header-toggle:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: var(--focus-offset);
}

/* Der senkrecht scrollbare Bereich. Der seitliche Innenabstand mit
   gleich großem negativem Außenabstand hält Platz für den Fokus-Ring der
   Karten, der sonst am Rand abgeschnitten würde; die Karten bleiben dabei
   genau 280 px breit. */
.column-scroll {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: var(--card-gap);
    margin: 0 calc(-1 * var(--space-4));
    padding: 0 var(--space-4) var(--list-end-space);
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--stroke) transparent;
}

.column-cards {
    display: flex;
    flex-direction: column;
    gap: var(--card-gap);
}

/* Höhenanimation der Spalte "Completed" (Status-Ansicht) über den
   Raster-Trick. Die Hülle .collapse-clip hat selbst keinen Innenabstand,
   damit sie im eingeklappten Zustand wirklich 0 hoch ist. */
.column-collapse {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--d3) var(--ease-standard);
}

.column-collapse.is-open {
    grid-template-rows: 1fr;
}

.column-collapse > .collapse-clip {
    min-height: 0;
    display: flex;
    flex-direction: column;
    margin: 0 calc(-1 * var(--space-4));
    overflow: hidden;
}

.column-collapse .column-scroll {
    margin: 0;
}

/* --- Completed-Umschalter (docs/07, "Completed-Umschalter") -----------
   Leise Textzeile ohne eigene Fläche mit Chevron, "Completed" und Anzahl.
   Höhe und Schriftstufe legt docs/07 für die Website nicht fest (Höhe aus
   dem Prototyp, Stufe "Label"). */

.completed {
    display: flex;
    flex-direction: column;
    margin-top: var(--space-4);
}

.completed-toggle {
    height: var(--completed-toggle-height);
    margin: 0 calc(-1 * var(--space-4));
    padding: 0 var(--space-4);
    display: flex;
    align-items: center;
    gap: var(--space-8);
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--text-tertiary);
    text-align: left;
    font-size: var(--text-label-size);
    line-height: var(--text-label-line);
    font-weight: var(--text-label-weight);
    transition:
        background-color var(--d1) var(--ease-standard),
        color var(--d1) var(--ease-standard);
}

.completed-toggle:hover {
    background: var(--surface);
    color: var(--text-secondary);
}

.completed-toggle:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: var(--focus-offset);
}

.completed-toggle .icon {
    transition: transform var(--d3) var(--ease-standard);
}

.completed-toggle[aria-expanded="true"] .icon {
    transform: rotate(90deg);
}

.completed-count {
    font-variant-numeric: tabular-nums;
}

.completed-collapse {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--d3) var(--ease-standard);
}

.completed-collapse.is-open {
    grid-template-rows: 1fr;
}

.completed-clip {
    min-height: 0;
    margin: 0 calc(-1 * var(--space-4));
    padding: 0 var(--space-4);
    overflow: hidden;
}

.completed-body {
    display: flex;
    flex-direction: column;
    gap: var(--card-gap);
    padding: var(--card-gap) 0 var(--space-4);
}

/* --- Ansicht "Date" -----------------------------------------------------
   Zwei Bereiche nebeneinander statt einer festgeklebten Spalte im
   gemeinsamen Scrollbereich (docs/06, "Der Datumsbereich endet am
   Trenner"): links der waagrecht scrollbare Datumsbereich, rechts davon
   außerhalb die feste Spalte "General ToDos" mit dem Trenner als
   Haarlinie. */

#date-board {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    align-items: stretch;
}

#date-area {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
}

/* min-width: 0 hält den Bereich auf die verfügbare Breite begrenzt, statt
   dass er sich an seinen Spalten aufweitet -- sonst wäre er nie
   scrollbar. */
#date-columns {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: stretch;
    gap: var(--column-gap);
    padding: var(--board-top) var(--page-margin) 0;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-color: var(--stroke) transparent;
}

/* Die letzten 24 px vor dem Trenner laufen weich aus. Bewusst ein Overlay
   statt mask-image auf dem Scroll-Container: eine Maske würde auch die
   waagrechte Scrollleiste ausblenden. Das Overlay liegt außerhalb des
   Scroll-Containers, scrollt also nicht mit, und endet über der
   Scrollleiste; deren Höhe misst app.js und setzt sie als
   --date-scrollbar-height. */
#date-fade {
    position: absolute;
    top: 0;
    right: 0;
    bottom: var(--date-scrollbar-height, 0);
    width: var(--fade-width);
    pointer-events: none;
    background: linear-gradient(to right, transparent, var(--bg));
}

#date-general {
    flex: 0 0 calc(var(--column-width) + 2 * var(--page-margin) + var(--hairline));
    padding: var(--board-top) var(--page-margin) 0;
    border-left: var(--hairline) solid var(--stroke);
}

/* --- ToDo-Karte (docs/07, "ToDo-Karte") ------------------------------- */

.card {
    display: flex;
    align-items: flex-start;
    gap: var(--checkbox-title-gap);
    padding: var(--card-padding);
    border: var(--hairline) solid var(--stroke);
    border-radius: var(--r-md);
    background: var(--surface);
    cursor: pointer;
    transition: background-color var(--d1) var(--ease-standard);
}

.card:hover {
    background: var(--surface-elevated);
}

.card:active {
    background: var(--stroke);
}

.card:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: var(--focus-offset);
}

/* Karte erscheint nach dem Anlegen und Wiedereröffnen: Deckkraft 0 auf 1,
   Skalierung 0,97 auf 1 (docs/07, Katalog: "Karte erscheint"). Das
   Wegklappen nach dem Abhaken läuft über die Web Animations API in
   app.js, weil die Ausgangshöhe der Karte erst dort bekannt ist. */
.card.card--entering {
    animation: card-in var(--d3) var(--ease-in);
}

@keyframes card-in {
    from {
        opacity: 0;
        transform: scale(var(--scale-card-in));
    }
}

.card-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--title-meta-gap);
}

/* Titel in "Body strong", höchstens drei Zeilen, danach Auslassungspunkte. */
.card-title {
    color: var(--text-primary);
    font-size: var(--text-body-strong-size);
    line-height: var(--text-body-strong-line);
    font-weight: var(--text-body-strong-weight);
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
}

.card--done .card-title {
    color: var(--text-tertiary);
    text-decoration: line-through;
}

/* Metazeile: eingerückt auf den Beginn des Titels (sie liegt im selben
   Körper wie der Titel), Stufe "Meta", text-secondary, tabellarische
   Ziffern. Bricht nur um, wenn der Platz nicht reicht. */
.card-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--space-12);
    row-gap: var(--space-4);
    color: var(--text-secondary);
    font-size: var(--text-meta-size);
    line-height: var(--text-meta-line);
    font-weight: var(--text-meta-weight);
    font-variant-numeric: tabular-nums;
}

.meta-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-4);
    white-space: nowrap;
}

.meta-item .icon {
    color: var(--text-tertiary);
}

/* Überfällig: Datum und Kalendersymbol in overdue. */
.meta-item--overdue,
.meta-item--overdue .icon {
    color: var(--overdue);
}

.dot {
    width: var(--dot-size);
    height: var(--dot-size);
    flex: 0 0 auto;
    border-radius: 50%;
}

.dot--urgent { background: var(--prio-urgent); }
.dot--major  { background: var(--prio-major); }
.dot--normal { background: var(--prio-normal); }
.dot--minor  { background: var(--prio-minor); }

/* --- Ansicht "DailyToDos" (docs/06, Ansicht "DailyToDos") -----------
   Eine zentrierte Spalte von 640 px, kein Board. Sie scrollt bei Bedarf
   senkrecht im Inhaltsbereich. Oben ein Kopf mit "DailyToDos" (Title 3),
   Fortschrittsbalken und dem Stand "1/3". */

#daily-view {
    position: relative;
    height: 100%;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--stroke) transparent;
}

.daily-column {
    width: var(--daily-column-width);
    max-width: 100%;
    margin: 0 auto;
    padding: var(--board-top) var(--page-margin) var(--list-end-space);
}

.daily-head {
    height: var(--column-header-height);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-12);
    padding-bottom: var(--space-8);
}

.daily-head-title {
    margin: 0;
    color: var(--text-primary);
    font-size: var(--text-title-3-size);
    line-height: var(--text-title-3-line);
    font-weight: var(--text-title-3-weight);
}

.daily-progress {
    display: flex;
    align-items: center;
    gap: var(--space-10);
    color: var(--text-tertiary);
    font-size: var(--text-label-size);
    line-height: var(--text-label-line);
    font-weight: var(--text-label-weight);
    font-variant-numeric: tabular-nums;
}

/* Fortschrittsbalken (docs/07, "Fortschrittsbalken"): 96 x 4, Radius 4,
   Spur in stroke, Füllung in accent, die Füllung animiert mit 240 ms. */
.progress {
    width: var(--progress-width);
    height: var(--progress-height);
    border-radius: var(--r-xs);
    background: var(--stroke);
    overflow: hidden;
}

.progress-fill {
    display: block;
    width: 0;
    height: 100%;
    border-radius: var(--r-xs);
    background: var(--accent);
    transition: width var(--d3) var(--ease-standard);
}

#daily-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--card-gap);
}

/* Dieselbe Fläche wie die ToDo-Karte, eine Zeile: Checkbox, Titel und am
   rechten Rand das Menü-Symbol. Der kleinere senkrechte Innenabstand
   gleicht den 32-px-Icon-Button aus, die Karte ist damit so hoch wie eine
   einzeilige ToDo-Karte. Kein Hover, ein Klick auf die Karte öffnet
   nichts. */
.daily-card {
    display: flex;
    align-items: center;
    gap: var(--checkbox-title-gap);
    padding: var(--space-6) var(--space-6) var(--space-6) var(--card-padding);
    border: var(--hairline) solid var(--stroke);
    border-radius: var(--r-md);
    background: var(--surface);
}

.daily-card.card--entering {
    animation: card-in var(--d3) var(--ease-in);
}

.daily-title {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--text-primary);
    font-size: var(--text-body-strong-size);
    line-height: var(--text-body-strong-line);
    font-weight: var(--text-body-strong-weight);
    overflow-wrap: anywhere;
}

.daily-card--done .daily-title {
    color: var(--text-tertiary);
    text-decoration: line-through;
}

.daily-menu {
    position: relative;
    flex: 0 0 auto;
}

/* --- Menü (docs/07, "Menü") ------------------------------------------- */

.menu {
    position: absolute;
    top: calc(100% + var(--space-4));
    right: 0;
    z-index: var(--z-menu);
    min-width: var(--menu-min-width);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    border-radius: var(--r-md);
    background: var(--surface-elevated);
    box-shadow: var(--elevation-2);
    transform-origin: top right;
    animation: menu-in var(--d2) var(--ease-in);
}

@keyframes menu-in {
    from {
        opacity: 0;
        transform: scale(var(--scale-menu-in));
    }
}

.menu-item {
    height: var(--menu-item-height);
    padding: 0 var(--space-8);
    display: flex;
    align-items: center;
    gap: var(--space-8);
    border: 0;
    border-radius: var(--r-sm);
    background: none;
    color: var(--text-primary);
    text-align: left;
    white-space: nowrap;
}

.menu-item .icon {
    color: var(--text-tertiary);
}

/* Für Hover auf surface-elevated nennt docs/07 keinen Wert; stroke wie
   beim Icon-Button. */
.menu-item:hover {
    background: var(--stroke);
}

.menu-item:focus-visible {
    outline: var(--focus-ring) solid var(--accent);
    outline-offset: calc(-1 * var(--focus-ring));
}

.menu-item--danger,
.menu-item--danger .icon {
    color: var(--danger);
}

/* --- Panel (docs/06, "Das Panel und seine drei Modi") ----------------
   Schwebt am rechten Rand, 12 px vom Fensterrand, 480 breit, volle Höhe
   abzüglich dieses Abstands, Ebene 3. Die Fläche links davon dunkelt der
   Scrim ab; das Board bleibt dahinter sichtbar. Öffnen: 40 px von rechts
   mit Einblenden (d4, Hinein); Schließen umgekehrt (d3, Hinaus). app.js
   setzt dafür .is-closing und erst nach dem Ende der Animation hidden. */

.panel-layer {
    position: fixed;
    inset: 0;
    z-index: var(--z-panel);
    background: var(--scrim);
    animation: fade-in var(--d4) var(--ease-standard);
}

.panel-layer.is-closing {
    pointer-events: none;
    animation: fade-out var(--d3) var(--ease-out) forwards;
}

.panel {
    position: absolute;
    top: var(--panel-inset);
    right: var(--panel-inset);
    bottom: var(--panel-inset);
    width: var(--panel-width);
    max-width: calc(100% - 2 * var(--panel-inset));
    display: flex;
    flex-direction: column;
    border-radius: var(--r-lg);
    background: var(--surface-elevated);
    box-shadow: var(--elevation-3);
    animation: panel-in var(--d4) var(--ease-in);
}

.panel-layer.is-closing .panel {
    animation: panel-out var(--d3) var(--ease-out) forwards;
}

@keyframes panel-in {
    from {
        opacity: 0;
        transform: translateX(var(--panel-offset));
    }
}

@keyframes panel-out {
    to {
        opacity: 0;
        transform: translateX(var(--panel-offset));
    }
}

/* Kopf: links der Titel des Modus, rechts die Icon-Buttons. */
#panel-header {
    flex: 0 0 auto;
    height: var(--panel-header-height);
    display: flex;
    align-items: center;
    gap: var(--space-8);
    padding: 0 var(--space-12) 0 var(--dialog-padding);
}

/* Titel des Formulars in "Title 2" (docs/07, "Typografie-Skala"). */
#panel-title {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    color: var(--text-primary);
    font-size: var(--text-title-2-size);
    line-height: var(--text-title-2-line);
    font-weight: var(--text-title-2-weight);
}

/* Im Detail-Modus steht im Kopf nur das Wort "ToDo", klein in
   text-tertiary (docs/06, "ToDo-Detail-Panel"). */
.panel[data-mode="detail"] #panel-title {
    color: var(--text-tertiary);
    font-size: var(--text-label-size);
    line-height: var(--text-label-line);
    font-weight: var(--text-label-weight);
}

#panel-header-actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--space-4);
}

/* Körper: scrollt bei Bedarf in sich, nicht mit der Seite. */
#panel-body {
    flex: 1 1 auto;
    min-height: 0;
    padding: var(--space-4) var(--dialog-padding) var(--dialog-padding);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--stroke) transparent;
}

/* Wechsel zwischen Detail und Bearbeiten: der Inhalt blendet mit 6 px
   Anstieg ein (docs/07, Katalog: "Modus des Detail-Panels"). */
#panel-body.is-swapping > :not([hidden]) {
    animation: rise-in var(--d3) var(--ease-in);
}

@keyframes rise-in {
    from {
        opacity: 0;
        transform: translateY(var(--swap-rise));
    }
}

/* Fußleiste, nur im Erstell- und Bearbeiten-Modus: fest am unteren Rand,
   links der Hinweis, rechts "Cancel" und "Save". */
#panel-footer {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--space-8);
    padding: var(--space-12) var(--dialog-padding);
    border-top: var(--hairline) solid var(--stroke);
}

.panel-footer-hint {
    margin-right: auto;
    color: var(--text-tertiary);
    font-size: var(--text-label-size);
    line-height: var(--text-label-line);
}

/* --- ToDo-Detail-Panel (docs/06, "ToDo-Detail-Panel") ----------------- */

#panel-title-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-12);
    margin-bottom: var(--space-20);
}

/* Die Checkbox (20 px) mittig zur ersten Zeile des Titels (28 px). */
.panel-title-checkbox {
    flex: 0 0 auto;
    display: flex;
    padding-top: var(--space-4);
}

#panel-todo-title {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    color: var(--text-primary);
    font-size: var(--text-title-1-size);
    line-height: var(--text-title-1-line);
    font-weight: var(--text-title-1-weight);
    letter-spacing: var(--text-title-1-tracking);
    overflow-wrap: anywhere;
}

#panel-title-row.is-done #panel-todo-title {
    color: var(--text-tertiary);
    text-decoration: line-through;
}

/* Eigenschaften als Raster: links eine feste Spalte von 112 mit Symbol
   und Name in text-tertiary, direkt daneben der Wert in text-primary. */
#panel-properties {
    display: grid;
    grid-template-columns: var(--property-label-width) 1fr;
    column-gap: var(--space-12);
}

.panel-property-label {
    min-height: var(--property-row-height);
    display: flex;
    align-items: center;
    gap: var(--space-8);
    color: var(--text-tertiary);
    font-size: var(--text-label-size);
    line-height: var(--text-label-line);
    font-weight: var(--text-label-weight);
}

.panel-property-value {
    min-height: var(--property-row-height);
    display: flex;
    align-items: center;
    gap: var(--space-8);
    color: var(--text-primary);
    font-size: var(--text-body-strong-size);
    line-height: var(--text-body-strong-line);
    font-weight: var(--text-body-strong-weight);
    font-variant-numeric: tabular-nums;
}

.panel-property-value--overdue {
    color: var(--overdue);
}

/* Sub-ToDos und Details, jeweils eingeleitet durch eine Haarlinie und ein
   Label. */
.panel-section {
    margin-top: var(--space-20);
    padding-top: var(--space-20);
    border-top: var(--hairline) solid var(--stroke);
}

.section-label {
    margin: 0 0 var(--space-8);
    color: var(--text-tertiary);
    font-size: var(--text-label-size);
    line-height: var(--text-label-line);
    font-weight: var(--text-label-weight);
}

#panel-subtodo-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
}

.panel-subtodo-row {
    min-height: var(--subtodo-row-height);
    display: flex;
    align-items: center;
    gap: var(--space-12);
}

.panel-subtodo-content {
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

#panel-detail-text {
    margin: 0;
    color: var(--text-secondary);
    line-height: var(--text-body-line);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* --- Formular (docs/06, "Formular zum Erstellen und Bearbeiten") ------ */

#panel-form {
    display: flex;
    flex-direction: column;
    gap: var(--field-gap);
}

/* Die Felder, die nur ToDos haben, klappen beim Typ "DailyToDo" mit
   Höhe und Deckkraft weg (docs/07, Katalog: "Felder des Formulars").
   Der seitliche Innenabstand hält Platz für Fokus-Ringe, die sonst am
   Rand der Hülle abgeschnitten würden. */
.form-collapse {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    transition:
        grid-template-rows var(--d3) var(--ease-standard),
        opacity var(--d3) var(--ease-standard);
}

.form-collapse.is-open {
    grid-template-rows: 1fr;
    opacity: 1;
}

.form-collapse-clip {
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: var(--field-gap);
    margin: 0 calc(-1 * var(--space-4));
    padding: 0 var(--space-4);
    overflow: hidden;
}

/* Kein Übergang, wenn das Formular frisch geöffnet wird. */
.no-anim,
.no-anim * {
    transition: none !important;
}

/* Datumsfeld mit "×" rechts im Feld, das den Wert leert (docs/06, "Das
   Datumsfeld"). Rechts bleibt Platz für das "×", der Kalender-Knopf des
   Browsers steht links davon. */
.date-wrap {
    position: relative;
    display: flex;
    align-items: center;
}

.input--date {
    padding-right: var(--space-40);
}

.input--date::-webkit-calendar-picker-indicator {
    cursor: pointer;
}

.date-clear {
    position: absolute;
    right: var(--space-4);
    color: var(--text-tertiary);
}

/* Sub-ToDo-Editor (docs/06, "Der Sub-ToDo-Editor"): jede Zeile mit Punkt,
   sichtbarem Eingabefeld und "×"; die letzte Zeile ist das leere Feld
   "Add sub-ToDo" mit Plus-Symbol. Das Feld hat in Ruhe keinen Rand, bei
   Hover einen in stroke, bei Fokus einen in accent. */
.subtodo-editor {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
}

.subtodo-row {
    min-height: var(--subtodo-row-height);
    display: flex;
    align-items: center;
    gap: var(--space-8);
}

.subtodo-row.is-entering {
    animation: row-in var(--d3) var(--ease-in);
}

@keyframes row-in {
    from {
        opacity: 0;
        transform: translateY(calc(-1 * var(--row-rise)));
    }
}

.subtodo-marker {
    flex: 0 0 auto;
    width: var(--subtodo-marker-size);
    height: var(--subtodo-marker-size);
    display: grid;
    place-items: center;
    color: var(--text-tertiary);
}

/* Das Plus vor dem Feld "Add sub-ToDo" ist ein Icon-Button mit voller
   Trefferfläche von 32 px. Der negative Außenabstand hält es in der
   16 px breiten Marker-Spalte, sodass es mittig unter den Punkten der
   Zeilen darüber steht. Inaktiv (leeres Feld) wie ein Blätter-Pfeil am
   Ende: gedämpft, ohne Hover, Klick ohne Wirkung. */
.subtodo-add-button {
    margin: 0 calc((var(--subtodo-marker-size) - var(--icon-button-size)) / 2);
}

.subtodo-add-button:disabled {
    color: var(--text-tertiary);
    opacity: var(--nav-disabled-opacity);
    cursor: default;
}

.subtodo-marker--dot::before {
    content: "";
    width: var(--subtodo-dot-size);
    height: var(--subtodo-dot-size);
    border-radius: 50%;
    background: var(--text-tertiary);
}

.subtodo-input {
    flex: 1 1 auto;
    min-width: 0;
    height: var(--subtodo-row-height);
    padding: 0 var(--space-8);
    border: var(--hairline) solid transparent;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--text-primary);
    outline: none;
    transition:
        border-color var(--d1) var(--ease-standard),
        background-color var(--d1) var(--ease-standard);
}

.subtodo-input::placeholder {
    color: var(--text-tertiary);
    opacity: 1;
}

.subtodo-input:hover {
    border-color: var(--stroke);
}

.subtodo-input:focus {
    border-color: var(--accent);
    background: var(--bg);
}

.subtodo-remove {
    color: var(--text-tertiary);
}

/* --- Dialog (docs/07, "Dialog") ---------------------------------------
   Öffnen: Scrim blendet ein, der Dialog skaliert von 0,94 auf 1 mit
   Einblenden (240 ms, Hinein). Schließen: Skalierung auf 0,97 mit
   Ausblenden (160 ms, Hinaus). app.js setzt dafür .is-closing und erst nach
   dem Ende der Animation hidden. */

.dialog-layer {
    position: fixed;
    inset: 0;
    z-index: var(--z-dialog);
    display: grid;
    place-items: center;
    padding: var(--page-margin);
    background: var(--scrim);
    animation: fade-in var(--d3) var(--ease-standard);
}

.dialog-layer.is-closing {
    pointer-events: none;
    animation: fade-out var(--d2) var(--ease-out) forwards;
}

.dialog {
    width: var(--dialog-width);
    max-width: 100%;
    padding: var(--dialog-padding);
    border-radius: var(--r-lg);
    background: var(--surface-elevated);
    box-shadow: var(--elevation-3);
    animation: dialog-in var(--d3) var(--ease-in);
}

.dialog-layer.is-closing .dialog {
    animation: dialog-out var(--d2) var(--ease-out) forwards;
}

@keyframes dialog-in {
    from {
        opacity: 0;
        transform: scale(var(--scale-dialog-in));
    }
}

@keyframes dialog-out {
    to {
        opacity: 0;
        transform: scale(var(--scale-dialog-out));
    }
}

.dialog-title {
    margin: 0;
    color: var(--text-primary);
    font-size: var(--text-title-2-size);
    line-height: var(--text-title-2-line);
    font-weight: var(--text-title-2-weight);
    overflow-wrap: anywhere;
}

/* Die Zeile unter der Frage: der Titel des Eintrags (docs/06,
   "Löschen-Dialog"). */
.dialog-text {
    margin: var(--space-6) 0 0;
    color: var(--text-secondary);
    overflow-wrap: anywhere;
}

.dialog-actions {
    margin-top: var(--space-24);
    display: flex;
    justify-content: flex-end;
    gap: var(--space-8);
}
