/* ============================================
   Design System — Based on shadcn/ui v4 source
   https://github.com/shadcn-ui/ui
   oklch() converted to hex for browser compat
   ============================================ */

/* ---------- Geist Font (self-hosted via npm) ---------- */
@font-face {
    font-family: 'Geist';
    src: url('../node_modules/geist/dist/fonts/geist-sans/Geist-Variable.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Geist';
    src: url('../node_modules/geist/dist/fonts/geist-sans/Geist-Italic[wght].woff2') format('woff2');
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
}

/* ---------- Base page setup (replaces site.css globals) ---------- */
html.ds-page {
    /* 100 % statt fester 16 px: Mit <meta name="text-scale" content="scale"> im Layout folgt die
       Grundschrift so der Android-Schriftgröße (Chrome ignoriert sie sonst). Alles in rem zieht mit. */
    font-size: 100%;
    height: auto;
    overflow: auto;
    /* Solide Themen-Grundfarbe UNTER dem Hintergrundbild: verhindert ein weißes Aufblitzen,
       während das (gecachte) Hintergrund-JPG bei einer Voll-Navigation neu gemalt wird.
       Die richtige Farbe steht dank Pre-Paint-Theme-Klasse schon beim ersten Paint fest. */
    background-color: var(--ds-background);
}

html.ds-page body {
    height: auto;
    overflow: auto;
    margin: 0;
    padding: 0;
}

/* ---------- Alpine x-cloak: Elemente mit x-cloak bleiben unsichtbar, bis Alpine sie
   initialisiert (Alpine entfernt das Attribut bei alpine:init). Verhindert das Aufblitzen
   un-gebundener Templates/Trigger (z.B. ds-select-Doppelzustand, leere ds-calendar-Hülle). ---------- */
[x-cloak] { display: none !important; }

/* ---------- Sanfter Content-Fade-in: nur wenn JS aktiv (html.ds-js, vom Pre-Paint-Script im
   Layout gesetzt). Das Modul (Toolbar + Inhalt) erscheint EINMAL weich, sobald geparst
   (html.ds-loaded), statt in Etappen zu rucken. Der Failsafe-Timeout im Layout setzt ds-loaded
   notfalls auch ohne DOMContentLoaded → Inhalt bleibt NIE unsichtbar hängen. ---------- */
html.ds-js .ds-main #moduleWrapper { opacity: 0; }
html.ds-js.ds-loaded .ds-main #moduleWrapper { opacity: 1; transition: opacity 0.18s ease-out; }

/* ---------- Page-Loader: zentrierter Spinner über dem STATISCHEN Hintergrund, solange das Modul
   im Hintergrund lädt/sich setzt. Sichtbar NUR mit JS (html.ds-js) und nur bis html.ds-loaded
   (Reveal bei window.load + Failsafe, siehe Layout). Der Overlay ist transparent → der statische
   Seiten-Hintergrund bleibt sichtbar; der Inhalt (#moduleWrapper opacity:0) bleibt verborgen, bis
   er fertig gesetzt ist — so ruckelt sich nichts mehr sichtbar zurecht. ---------- */
#dsPageLoader { display: none; }
html.ds-js #dsPageLoader {
    position: fixed;
    inset: 0;
    z-index: 9985;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    opacity: 1;
}
html.ds-js.ds-loaded #dsPageLoader {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease-out, visibility 0s linear 0.25s;
}
/* Page-Loader-Spinner dem TeamHub-Logo nachempfunden: drei rotierende Bögen
   (wie die drei Flügel des Logos), in der Markenfarbe --ds-accent-1.
   Gleiche 3D-Ring-Mechanik wie der MyKI-Loader (custom-spinner.css). */
#dsPageLoader .ds-spinner {
    position: relative;
    width: 4.5rem;
    height: 4.5rem;
    border-radius: 50%;
    perspective: 800px;
}
#dsPageLoader .ds-spinner-ring {
    position: absolute;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    border-radius: 50%;
}
#dsPageLoader .ds-spinner-ring.one {
    left: 0;
    top: 0;
    border-bottom: 6px solid var(--ds-accent-1);
    animation: dsSpinOne 2s linear infinite;
}
#dsPageLoader .ds-spinner-ring.two {
    right: 0;
    top: 0;
    border-right: 6px solid var(--ds-accent-1);
    animation: dsSpinTwo 2s linear infinite;
}
#dsPageLoader .ds-spinner-ring.three {
    right: 0;
    bottom: 0;
    border-top: 6px solid var(--ds-accent-1);
    animation: dsSpinThree 2s linear infinite;
}
@keyframes dsSpinOne {
    0%   { transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg); }
    100% { transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg); }
}
@keyframes dsSpinTwo {
    0%   { transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg); }
    100% { transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg); }
}
@keyframes dsSpinThree {
    0%   { transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg); }
    100% { transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg); }
}

/* Hintergrundbild als FIXE, eigene Compositor-Ebene (::before) — NICHT
   background-attachment:fixed. Letzteres zwingt den Browser, das Bild bei JEDEM
   Scroll-Frame neu zu zeichnen (Flackern/Jank), besonders im Full-Bleed-Feed, wo
   das Bild zwischen den Karten durchscheint und der Scroll-Container <html> ist.
   Ein position:fixed-Layer wird vom Compositor gehalten und nicht neu gemalt.
   (Kein transform/will-change auf dem Scroll-Container — das würde die fixed
   ds-select-Panels + Modals re-trappen.) Light ist Default, Dark via .dark / System. */
/* Body transparent, sonst überdeckt seine eigene (weiße) Hintergrundfarbe den
   fixierten ::before-Layer (Body ist In-Flow-Inhalt von <html> und malt nach den
   negativen z-index-Kindern). html behält seine Farbe als hinterster Fallback. */
html.ds-page body { background-color: transparent; }
html.ds-page body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    /* Eigenes Bild NUR für die Gastseiten: --ds-public-bg-image wird von
       Views/Shared/_PublicAccent.cshtml gesetzt, wenn publicbg.jpg hinterlegt ist.
       Ohne diese Datei bleibt es beim Bild der Installation — die App nutzt dasselbe
       Dateipaar, ein Austausch dort verändert also auch die Arbeitsoberfläche. */
    background-image: var(--ds-public-bg-image, url('/Media/BackgroundImages/lightbg.jpg'));
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center center;
}

html.ds-page.dark body::before {
    background-image: url('/Media/BackgroundImages/darkbg.jpg');
}

@media (prefers-color-scheme: dark) {
    html.ds-page:not(.light) body::before {
        background-image: url('/Media/BackgroundImages/darkbg.jpg');
    }
}

/* Embed-/Fenstermodus (_embed im iframe): Seite muss ECHT transparent sein, damit der
   Glas-Hintergrund des ds-window (halbtransparent + backdrop-blur) durchscheint —
   weder eigene Hintergrundfarbe noch das fixierte Hintergrundbild rendern. */
html.ds-page.ds-embed { background: transparent; }

/* Fenstermodus-iframe: Struktur ist 1:1 das Voll-Layout (inkl. #mainContent.ds-content für
   die Scroll-/Höhen-Parität der Module) — aber OHNE App-Chrome-Reserven: im Fenster gibt es
   weder Dock (90/140px Clearance) noch braucht es die große Kopffreiheit. */
html.ds-page.ds-embed main { padding-bottom: 0; }
html.ds-embed .ds-main .ds-content {
    padding-top: 1rem;
    padding-bottom: 1.5rem;
}
html.ds-page.ds-embed body::before { display: none; }

/* Im Fenster gibt es kein schwebendes Dock → die zentrale Dock-Reserve auf 0. Damit füllen
   alle Module, die ihre Dock-Clearance über `calc(… - var(--app-dock-reserve))` (Höhe ODER
   padding-bottom) beziehen, das Fenster bis zum unteren Rand aus statt einen toten Streifen
   für ein Dock zu lassen, das im iframe nie erscheint. */
html.ds-embed { --app-dock-reserve: 0px; }

/* Gast-Seiten (öffentlicher Kurs-Link, freigegebene Views) tragen dieses Layout ohne App-Shell:
   kein Dock, also auch keine Dock-Reserve — sonst klafft unten ein toter Streifen. */
html.ds-guest { --app-dock-reserve: 0px; }

/* Die Full-Bleed-Module (ToDo/CRM/itops …) tragen im Voll-Layout eine hartcodierte 140px-
   Dock-Clearance als padding-bottom (Regeln oben, mit !important). Im Fenster überflüssig →
   auf normalen Boden-Abstand zurücknehmen. Höhere Spezifität (html.ds-embed) + !important
   schlägt die 140px-!important-Regeln. */
html.ds-embed .ds-main .ds-content:has(.ds-fullbleed),
html.ds-embed .ds-main .ds-content:has(.todo-module),
html.ds-embed .ds-main .ds-content:has(.crm-module),
html.ds-embed .ds-main .ds-content:has(.teamtime-module),
html.ds-embed .ds-main .ds-content:has(.settings-module),
html.ds-embed .ds-main .ds-content:has(.ds-fullbleed-floating) {
    padding-bottom: 1rem !important;
}

/* Fenstermodus-Fill für Shell-Module mit hartcodierter Viewport-Mathe (CRM/itops).
   Diese decken ihre Scroll-Shell im Voll-Layout per `max-height: calc(100vh - Npx)` — N ist
   auf das Voll-Layout-Chrome (Toolbar+Nav+Dock) geeicht und passt im iframe NICHT (anderes
   Chrome, kein Dock) → Streifen ODER Overflow. Im Fenster daher stattdessen die gleiche
   robuste Flex-Fill-Kette wie die tt-/ba-/pass-mv-Module (main=100dvh, moduleWrapper+Content
   +Zwischen-Wrapper flex-column, Shell flex:1) — kein Viewport-Raten mehr. Nur html.ds-embed,
   Voll-Layout bleibt bei seiner max-height-Regel.
   WICHTIG (itops): itops hat ZWEI Views im selben Container — die Systeme-View trägt die
   scrollende .itops-mv-shell (interner Scroller .itops-mv-body), die Dashboard-View ist eine
   lange Widget-Liste OHNE eigenen Scroller. Beide liegen immer im DOM (nur display:none), und
   :has(.itops-mv-shell) matcht auch die versteckte Shell → die Fill-Kette darf NUR greifen,
   wenn die Systeme-View aktiv ist. Sonst bekäme die Dashboard-View overflow:hidden im auf
   100dvh gedeckelten main und ließe sich im Fenster nicht scrollen. Daher body.itops-view-
   systeme voranstellen; in der Dashboard-View fällt main auf normalen (äußeren) Scroll zurück. */
html.ds-embed main.ds-main:has(.ds-shell),
html.ds-embed main.ds-main:has(.crm-shell),
html.ds-embed main.ds-main:has(.myapp-shell),
html.ds-embed body.itops-view-systeme main.ds-main:has(.itops-mv-shell) {
    height: 100dvh; min-height: 0; overflow: hidden !important; padding-bottom: 0 !important;
}
/* moduleWrapper: height:100% (nicht flex:1) — ds-main ist display:block, ein flex-Item-Grow
   würde ohne flex-Parent nicht greifen; height:100% deckelt ihn auf die 100dvh von ds-main. */
html.ds-embed .ds-main:has(.ds-shell) #moduleWrapper,
html.ds-embed .ds-main:has(.crm-shell) #moduleWrapper,
html.ds-embed .ds-main:has(.myapp-shell) #moduleWrapper,
html.ds-embed body.itops-view-systeme .ds-main:has(.itops-mv-shell) #moduleWrapper {
    display: flex; flex-direction: column; height: 100%; min-height: 0; overflow: hidden;
}
/* ab moduleWrapper (flex-column) abwärts: jede Zwischenebene flex-fill bis zur Shell */
html.ds-embed .ds-content:has(.ds-shell),
html.ds-embed .ds-content:has(.ds-shell) > .container-fluid,
html.ds-embed .ds-content:has(.crm-shell),
html.ds-embed .ds-content:has(.crm-shell) .crm-module,
html.ds-embed .ds-content:has(.crm-shell) .crm-module > .container-fluid,
html.ds-embed .ds-content:has(.myapp-shell),
html.ds-embed .ds-content:has(.myapp-shell) > .container-fluid,
html.ds-embed body.itops-view-systeme .ds-content:has(.itops-mv-shell),
html.ds-embed body.itops-view-systeme .ds-content:has(.itops-mv-shell) > .container-fluid,
html.ds-embed body.itops-view-systeme .ds-content:has(.itops-mv-shell) > .container-fluid > div {
    display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow: hidden;
}
html.ds-embed .ds-shell,
html.ds-embed .crm-shell,
html.ds-embed .myapp-shell,
html.ds-embed body.itops-view-systeme .itops-mv-shell {
    max-height: none !important; flex: 1 1 auto; min-height: 0; margin-bottom: .5rem !important;
}

/* Dock-Basis (aus site.css extrahiert) */
html.ds-page .dock-btn {
    border-radius: 10px;
    transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

html.ds-page .dock-btn:hover {
    transform: translateY(-5px) scale(1.1);
}

/* (Abdunkeln der übrigen Dock-Kacheln beim Überfahren entfernt, max 03.11.2026 — siehe DOCK-HOVER.) */

/* ---------- shadcn v4 Tokens (Zinc/Default) ----------
   Original uses oklch(), converted to hex here.
   --radius: 0.625rem (10px) from shadcn source
   ---------------------------------------------------- */
:root {
    --ds-radius: 0.625rem;
    /* ---------- Inhalts-Card-Tokens (EINE Quelle für die content-anzeigenden Item-Karten von
       ToDo/CRM/TeamTime) — vereinheitlicht Eckenradius, Innen-Padding und Schriftgrößen
       modulübergreifend. Die drei Module referenzieren NUR diese Tokens, statt eigene Hausnummern
       zu setzen (.todo-card / .crm-card(-body) / .tt-ticket+.tt-body). --ds-card-pad-compact
       verdichtet sich auf dem Smartphone zentral (siehe @media max-width:575.98px unten), damit
       ALLE drei Module gleich kompakt werden — CRM hatte vorher GAR KEINE Mobile-Verdichtung. */
    --ds-card-radius: calc(var(--ds-radius) * 1.4); /* 14px — = Basis-.ds-card, kanonischer Karten-Radius */
    --ds-card-pad-compact: 0.6rem 0.7rem;           /* Item-Karten-Innenabstand (Desktop) */
    --ds-card-title-compact: 0.8125rem;             /* 13px — Karten-Titel */
    --ds-card-meta: 0.72rem;                        /* Sekundär-/Meta-Text in Karten */
    --ds-card-gap: 0.5rem;                          /* 8px — Abstand ZWISCHEN Karten in Listen/Grids (ToDo/CRM/TeamTime/itops) */
    /* ---------- Kachelhöhen der Modul-Übersichten (ds-card-grid ds-tiles) ----------
       EINE Quelle für „alle Kacheln gleich hoch" über Module hinweg (Max, 18.09.2026:
       „durchgängige Höhe und dass es identisch aussieht"). Zwei Größen, nach Karten-Bauart:
       - standard: Kachel MIT Aktionsleiste (Formulare, Flow, Booking, MyHub, Meet)
       - compact:  nur Kopf — Symbol · Name · eine Meta-Zeile (MyApp-Apps, Kontakt-Dichte)
       - preview:  Kopf + zweizeilige Vorschau (MyApp-Datensatzkarten)
       - bild:     Bild oben + Namensbereich mit doppelter Rundung (Arc-Archive, Stage; = Arc-Dateikarte) */
    --ds-tile-h-standard: 11rem;                    /* 176px */
    --ds-tile-h-compact: 4.75rem;                   /* 76px — wie eine Kontakt-Karte */
    --ds-tile-h-preview: 7.5rem;                    /* 120px */
    --ds-tile-h-bild: 8.6875rem;                    /* 139px — wie die Arc-Dateikarte */
    /* Maximale Inhaltsbreite aller Module (#moduleWrapper). Standard = Tailwind 2xl-Screen.
       Einzige Quelle der Wahrheit — Module ziehen darauf, statt eigene Hausnummern zu setzen. */
    --ds-content-width: 1536px;
    /* Horizontale Innen-Polsterung des Modul-Containers (.ds-content) — EINE globale Stelle.
       Desktop = 2.5rem (Karten-Module). Full-Bleed-Module (ToDo/CRM/TeamTime) setzen den Token
       per :has()-Neutralizer auf 1.25rem um. Auf dem Smartphone wird er global auf 0.25rem
       gezwungen (siehe @media unten). So ist der Seitenrand ÜBERALL gleich — kein Modul braucht
       eine eigene Mobile-Rand-Regel mehr. Module dürfen den Token umsetzen, niemals padding-left/
       -right hartkodieren (sonst entkoppelt sich das Modul wieder vom globalen Standard). */
    --ds-content-pad-x: 2.5rem;
    --ds-background: #ffffff;
    --ds-foreground: #0a0a0a;
    --ds-card: #ffffff;
    /* Schatten der Flächen, die DIREKT auf dem Seitenhintergrund liegen (Panels, Shells, Spalten,
       Dashboard-Karten) — EIN Wert für alle Module (max, 03.11.2026). Zwei Schichten: enger Schatten
       an der Kante + breiter, weicher darunter → die Karte schwebt über dem Hintergrundbild, statt
       aufgeklebt zu wirken. Karten IN Karten bekommen ihn NICHT (sonst unruhig). */
    --ds-surface-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 8px 24px -8px rgba(0, 0, 0, 0.18);
    --ds-card-foreground: #0a0a0a;
    --ds-popover: #ffffff;
    --ds-popover-foreground: #0a0a0a;
    --ds-primary: #2563eb;
    --ds-primary-foreground: #ffffff;
    --ds-secondary: #f4f4f5;
    --ds-secondary-foreground: #18181b;
    --ds-muted: #f5f5f5;
    /* Gedämpfter Text bewusst dunkel (fast schwarz) gehalten — graues #6c757d/0.75-Alpha
       (Bootstrap-Default) war an vielen Stellen zu kontrastarm. */
    --ds-muted-foreground: #2e2e2e;
    --ds-accent: #f5f5f5;
    --ds-accent-foreground: #171717;
    --ds-destructive: #ef4444;
    --ds-destructive-foreground: #ffffff;
    --ds-border: #e5e5e5;
    --ds-input: #e5e5e5;
    --ds-ring: var(--ds-accent-1);
    --ds-success: #16a34a;
    --ds-success-foreground: #ffffff;
    --ds-warning: #f59e0b;
    --ds-warning-foreground: #ffffff;
    --ds-info: #0ea5e9;
    --ds-info-foreground: #ffffff;
    /* Kontakt-Art „Familie" (Plan 07) — dritte Typ-Farbe neben Person (muted) und Firma (info). */
    --ds-family: #9333ea;
    --ds-surface: #fafafa;

    /* Modal-Ebenen: Body dezent gedeckt, Sections heben sich als Cards ab (Inverted Elevation) */
    --ds-modal-surface: #f4f4f5;
    --ds-modal-card: #ffffff;

    /* Kundenfarben (UI-Chrome: Überschriften, Separatoren, Tabs, Links) */
    --ds-accent-1: #3b82f6;
    --ds-accent-2: #6366f1;

    /* Bootstrap-"muted/secondary"-Text an das kontraststärkere Design-Token koppeln.
       Greift nur in ds-/Tailwind-Layouts (design-system.css wird nur dort geladen), damit
       .text-muted / .text-body-secondary in migrierten Modulen genug Kontrast bekommen.
       Die var()-Indirektion löst pro Theme automatisch auf hell/dunkel auf. */
    --bs-secondary-color: var(--ds-muted-foreground);
    --bs-tertiary-color: color-mix(in srgb, var(--ds-muted-foreground) 75%, var(--ds-background));
}

/* Dark Mode — via .dark Klasse

   ELEVATION-SKALA (im Dunkeln gilt: höher gestapelt = heller):
     background #0a0a0a  <  surface #151519  <  card #232328  <  popover #2b2b31
   Die Werte müssen in DIESER Reihenfolge heller werden. Vorher waren surface (#1a1a1a)
   und card (#171717) invertiert — eine Item-Card in einer Surface-Card (ToDo-Übersicht,
   CRM, TeamTime, itops) war DUNKLER als ihr eigener Container, Kontrast 1,02:1, also
   praktisch unsichtbar. Dieselbe Staffelung setzen die Modal-Tokens unten bereits um. */
html.dark {
    --ds-background: #0a0a0a;
    --ds-foreground: #fafafa;
    --ds-card: #232328;
    --ds-card-foreground: #fafafa;
    --ds-popover: #2b2b31;
    --ds-popover-foreground: #fafafa;
    --ds-primary: #3b82f6;
    --ds-primary-foreground: #ffffff;
    --ds-secondary: #2d2d31;
    --ds-secondary-foreground: #e4e4e7;
    --ds-muted: #2c2c30;
    --ds-muted-foreground: #c4c4c4;
    --ds-accent: #404040;
    --ds-accent-foreground: #fafafa;
    --ds-destructive: #dc2626;
    --ds-destructive-foreground: #fafafa;
    --ds-border: rgba(255, 255, 255, 0.14);
    --ds-input: rgba(255, 255, 255, 0.18);
    --ds-ring: var(--ds-accent-1);
    --ds-success: #22c55e;
    --ds-success-foreground: #052e16;
    --ds-warning: #eab308;
    --ds-warning-foreground: #422006;
    --ds-info: #38bdf8;
    --ds-info-foreground: #0c4a6e;
    --ds-family: #c084fc;
    --ds-surface: #151519;
    --ds-modal-surface: #0d0d0e;
    --ds-modal-card: #232328;
    --ds-surface-shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 10px 28px -8px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
}

/* Dark Mode — via System-Preference (wenn kein .light/.dark gesetzt).
   Muss WERTGLEICH zu html.dark oben bleiben. (Vorher drifteten die Blöcke:
   --ds-muted-foreground war hier #a3a3a3 statt #c4c4c4, d.h. wer sein Theme über die
   System-Einstellung bezog, bekam kontrastschwächeren Sekundärtext als wer explizit
   umschaltete.) */
@media (prefers-color-scheme: dark) {
    html:not(.light) {
        --ds-background: #0a0a0a;
        --ds-foreground: #fafafa;
        --ds-card: #232328;
        --ds-card-foreground: #fafafa;
        --ds-popover: #2b2b31;
        --ds-popover-foreground: #fafafa;
        --ds-primary: #3b82f6;
        --ds-primary-foreground: #ffffff;
        --ds-secondary: #2d2d31;
        --ds-secondary-foreground: #e4e4e7;
        --ds-muted: #2c2c30;
        --ds-muted-foreground: #c4c4c4;
        --ds-accent: #404040;
        --ds-accent-foreground: #fafafa;
        --ds-destructive: #dc2626;
        --ds-destructive-foreground: #fafafa;
        --ds-border: rgba(255, 255, 255, 0.14);
        --ds-input: rgba(255, 255, 255, 0.18);
        --ds-ring: var(--ds-accent-1);
        --ds-success: #22c55e;
        --ds-success-foreground: #052e16;
        --ds-warning: #eab308;
        --ds-warning-foreground: #422006;
        --ds-info: #38bdf8;
        --ds-info-foreground: #0c4a6e;
        --ds-family: #c084fc;
        --ds-surface: #151519;
        --ds-modal-surface: #0d0d0e;
        --ds-modal-card: #232328;
        --ds-surface-shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 10px 28px -8px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
    }
}

/* ---------- Base ---------- */
.ds-main,
.ds-sidebar {
    font-family: 'Geist', Helvetica, Arial, sans-serif;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    color: var(--ds-foreground);
}

/* #ChatPanelWrapper trägt .ds-main NUR für den Farb-/Font-Scope des per AJAX
   geladenen Chat-Panels (siehe _Layout_Tailwind.cshtml). Es darf aber NICHT die
   min-height:100vh von .ds-main erben — sonst hängt ein leerer 100vh-Block im
   normalen Fluss unter <main class="ds-main"> und man kann auf JEDER Seite den
   Inhalt komplett "wegscrollen" (doppelte Viewport-Höhe). Alle Panel-Kinder
   (#ucChatPanel, Modals, Overlays) sind position:fixed/absolute und brauchen
   keine Wrapper-Höhe. */
#ChatPanelWrapper {
    min-height: 0;
}

.ds-main *, .ds-sidebar * { border-color: var(--ds-border); }
.ds-main p, .ds-sidebar p { margin: 0 !important; padding: 0 !important; }

/* Globale Textfarbe für alle Elemente im ds-main Scope (nicht für ds-btn/ds-badge).
   ds-badge muss genauso ausgenommen sein wie ds-btn: der Selektor hat Specificity 0-2-1
   und schlug damit die 0-1-0 der .ds-badge-success/-warning/…-Regeln — ein grünes
   "Online"-Badge samt Punkt kam schwarz auf blassgrün heraus. */
.ds-main input, .ds-main select, .ds-main textarea, .ds-main button:not([class*="ds-btn"]),
.ds-main span:not([class*="ds-btn"]):not([class*="ds-badge"]):not([class*="xterm-"]), .ds-main label, .ds-main div {
    color: var(--ds-foreground);
}
/* Dieselbe Token-Farbe für Modal-Inhalte AUSSERHALB von .ds-main: die AJAX-Wrapper
   (#ModalWrapper*, Layout gibt ihnen .ds-modal-scope) und vom Layout an <body>
   reparentierte Modale. Ohne das: schwarzer UA-Button-Text im Dark-Mode — Fingerabdruck:
   ds-select-Trigger unlesbar in DsSubmodal-Partials. Bewusst Klasse statt ID-Selektor,
   damit die Specificity der .ds-main-Regel entspricht und Komponenten-Farben
   (z.B. ds-ws-pal-ic) weiterhin gewinnen.

   ⚠️ `:not([class*="xterm-"])`: Die Terminalausgabe der Konsolen färbt ihre
   Zeichenläufe selbst (`xterm-fg-1` = rot = gelöscht, grün = hinzugefügt). Diese
   Regel ist spezifischer als die von xterm erzeugte und zog sie sonst alle auf
   die Textfarbe — ein einfarbiges `git diff`. Sichtbar wurde es nur ohne WebGL,
   also auf Android ab der zweiten Kachel (gemeldet 04.09.2026).
   Dasselbe für `cm-` (CodeMirror-Syntaxfarben): sonst war jedes Script in einem
   Modal einfarbig (iTOPS-Job-Editor, 21.10.2026). */
.ds-modal-scope input, .ds-modal-scope select, .ds-modal-scope textarea, .ds-modal-scope button:not([class*="ds-btn"]),
.ds-modal-scope span:not([class*="ds-btn"]):not([class*="ds-badge"]):not([class*="xterm-"]):not([class^="cm-"]), .ds-modal-scope label, .ds-modal-scope div,
body > .modal input, body > .modal select, body > .modal textarea, body > .modal button:not([class*="ds-btn"]),
body > .modal span:not([class*="ds-btn"]):not([class*="ds-badge"]):not([class*="xterm-"]):not([class^="cm-"]), body > .modal label, body > .modal div {
    color: var(--ds-foreground);
}
/* Farbklassen die den ds-main Override schlagen */
.ds-main .ds-color-primary, .ds-main .ds-color-primary span { color: var(--ds-primary) !important; }
.ds-main .ds-color-success, .ds-main .ds-color-success span { color: var(--ds-success) !important; }
.ds-main .ds-color-destructive, .ds-main .ds-color-destructive span { color: var(--ds-destructive) !important; }
.ds-main .ds-color-warning, .ds-main .ds-color-warning span { color: var(--ds-warning) !important; }
.ds-main .ds-color-info, .ds-main .ds-color-info span { color: var(--ds-info) !important; }
/* :not(ds-chip) zusätzlich: <a class="ds-chip-btn is-active"> würde sonst accent-auf-accent
   (unsichtbarer Text) bekommen — die Chip-Regeln steuern ihre Farben selbst.
   Menüzeilen (<a class="ds-dropdown-item">) ebenso: sie sind Zeilen in Textfarbe, keine Links
   (MyKI „Dateien" war blau), Notizbuch-Knöpfe als Link (a.ds-kw) auch. Als Liste im selben :not(), damit die Spezifität (0,3,1) bleibt. */
.ds-main a:not([class*="ds-btn"], .ds-dropdown-item, .ds-kw):not([class*="ds-chip"]) { color: var(--ds-accent-1); text-decoration: none; }
.ds-main a:not([class*="ds-btn"], .ds-dropdown-item, .ds-kw):not([class*="ds-chip"]):hover { text-decoration: underline; text-underline-offset: 3px; }

/* Helle (weiße) Formularfelder — bewusst auf weißem Grund, z.B. im Formular-Modal.
   Setzt Hintergrund, Textfarbe und Platzhalter fest, damit es in Light UND Dark
   gut lesbar bleibt (sonst: helle Schrift auf Weiß = unsichtbar im Dark-Theme). */
.ds-field-light {
    background-color: #ffffff !important;
    color: #0a0a0a !important;
    border-color: #d4d4d4 !important;
}
.ds-field-light::placeholder {
    color: #737373 !important;
    opacity: 1;
}

/* Text-Selektion in Accent-Farbe */
html.ds-page ::selection {
    background: var(--ds-accent-1);
    color: #ffffff;
}

/* Scrollbar in Sekundär-Akzentfarbe */
html.ds-page ::-webkit-scrollbar { width: 8px; height: 8px; }
html.ds-page ::-webkit-scrollbar-track { background: transparent; }
html.ds-page ::-webkit-scrollbar-thumb {
    background: var(--ds-accent-2);
    border-radius: 4px;
    opacity: 0.6;
}
html.ds-page ::-webkit-scrollbar-thumb:hover {
    background: var(--ds-accent-2);
    opacity: 1;
}
html.ds-page ::-webkit-scrollbar-corner { background: transparent; }
html.ds-page {
    scrollbar-color: var(--ds-accent-2) transparent;
    scrollbar-width: thin;
}
.ds-main ul, .ds-main ol { margin: 0; }
/* Menüs (<ul class="dropdown-menu">) behalten ihr Innen-Padding — sonst klebte der erste und letzte Eintrag am Rand
   (max, 01.11.2026). :where hält die Spezifität wie vorher, damit sonst nichts kippt. */
.ds-main ul:where(:not(.dropdown-menu)), .ds-main ol { padding: 0; }
/* Ausdrücklicher Einzug schlägt den Reset — sonst ragten die Nummern von Anleitungslisten
   (tw-list-decimal tw-pl-5, z. B. Telefon-Abgleich) links aus dem Text (03.11.2026). */
.ds-main :is(ul, ol).tw-pl-5 { padding-left: 1.25rem; }
.ds-main :is(ul, ol).tw-ps-4 { padding-inline-start: 1rem; }
.ds-main :is(ul, ol).tw-ps-5 { padding-inline-start: 1.25rem; }
.ds-main h1, .ds-main h2, .ds-main h3,
.ds-main h4, .ds-main h5, .ds-main h6 {
    margin: 0; padding: 0; color: var(--ds-foreground);
}

/* ---------- Sidebar ---------- */
.ds-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: 240px;
    height: 100vh;
    z-index: 1000;
    overflow-y: auto;
    padding: 1.5rem 0.75rem;
    background: var(--ds-background);
    border-right: 1px solid var(--ds-border);
}

.ds-sidebar-title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.5rem;
    margin-bottom: 1.5rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--ds-foreground) !important;
    text-decoration: none !important;
    letter-spacing: -0.02em;
}

.ds-sidebar-section {
    padding: 0 0.5rem;
    margin-top: 1.5rem;
    margin-bottom: 0.25rem;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--ds-foreground);
}

.ds-sidebar-link {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.5rem;
    border-radius: calc(var(--ds-radius) * 0.8);
    font-size: 0.875rem;
    color: var(--ds-muted-foreground) !important;
    text-decoration: none !important;
    transition: color 0.1s ease;
}

.ds-sidebar-link:hover { color: var(--ds-foreground) !important; }

.ds-sidebar-link.active {
    color: var(--ds-foreground) !important;
    font-weight: 500;
}

.ds-sidebar-link i {
    font-size: 0.875rem;
    width: 1rem;
    text-align: center;
}

/* ---------- Main ---------- */
.ds-main {
    min-height: 100vh;
    /* dvh = sichtbare Höhe. 100vh ist am Handy die Höhe OHNE Adressleiste → die Seite war immer
       ~100 px zu hoch und scrollte zusätzlich zur Karte (Doppelscroll, Plan 63). */
    min-height: 100dvh;
    overflow: visible !important;
}

/* .ds-content ist die CONTAINER-Ebene (Surface), nicht die Card-Ebene: die <ds-card>-Boxen
   liegen DARIN. Solange beide var(--ds-card) trugen, waren sie flächengleich und die Karten
   existierten nur als Rahmen (dark: #232328 auf #232328, light: #fff auf #fff). Mit
   var(--ds-surface) staffelt es sich in beiden Themes korrekt. Siehe Elevation-Skala oben. */
.ds-main .ds-content {
    padding-top: 2.5rem;
    padding-left: var(--ds-content-pad-x);
    padding-right: var(--ds-content-pad-x);
    padding-bottom: 140px;
    overflow: visible;
    background: var(--ds-surface);
    border-radius: 1rem;
    box-shadow: var(--ds-surface-shadow);
    margin-top: 0;
}

@media (prefers-color-scheme: dark) {
    html:not(.light) .ds-main .ds-content {
        background: var(--ds-surface);
        box-shadow: var(--ds-surface-shadow);
    }
}

html.dark .ds-main .ds-content {
    background: var(--ds-surface);
    box-shadow: var(--ds-surface-shadow);
}

/* ---------- Full-Bleed: die .ds-content-Card AUFLÖSEN für Module, die das Marker-Element tragen
   (.todo-module / .crm-module / .teamtime-module). Diese Regel steht BEWUSST hier im render-
   blockierenden design-system.css (Head), damit der Full-Bleed-Zustand schon beim ERSTEN Paint
   feststeht. Vorher lag sie in der je View NACHgeladenen View-CSS (_ToDoOverview/crm/teamtime)
   → die Card wurde erst als #171717-Kachel gemalt und dann aufgelöst = die "Phantom-Card" +
   ein zweiter Layout/Paint ("lädt nochmal neu"). Die Marker stehen server-seitig im HTML, daher
   greift :has() sofort. (UC_Email nutzt weiterhin seine eigene, media-scoped .email-container-
   Variante mit padding:0 — bewusst nicht hier zusammengefasst.)
   STANDARD ab 2026-06: Neue Module tragen den GENERISCHEN Marker `.ds-fullbleed` am Modul-Wrapper
   (z.B. <div class="ds-module ds-fullbleed"> bzw. den Baukasten-TagHelper <ds-module>) — damit ist
   KEINE design-system.css-Änderung mehr nötig. Die modul-spezifischen Marker
   (.todo-module/.crm-module/.teamtime-module) bleiben als Aliase bestehen. ---------- */
.ds-main .ds-content:has(.ds-fullbleed),
.ds-main .ds-content:has(.todo-module),
.ds-main .ds-content:has(.crm-module),
.ds-main .ds-content:has(.teamtime-module),
.ds-main .ds-content:has(.settings-module) {
    background: transparent !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    --ds-content-pad-x: 1.25rem;
    padding-top: 10px !important;
    padding-bottom: 140px !important;
}

/* ---------- Kein doppelter Seitenrand in Full-Bleed-Modulen ----------
   Diese Module wickeln ihren Inhalt teils noch in ein Bootstrap-.container-fluid, das NOCHMAL
   einen horizontalen Gutter (~24px) draufpackt — der Inhalt säße dann links/rechts weiter
   eingerückt als ToDo (das kein container-fluid hat). Horizontaler Rand kommt AUSSCHLIESSLICH
   aus --ds-content-pad-x (EINE Quelle); den container-fluid-Gutter daher hier neutralisieren,
   damit alle Module am selben Rand starten. (Das Design-System nullt container-Gutter auf
   Mobile ohnehin global; dies deckt zusätzlich den Desktop für die Full-Bleed-Module ab.)
   Generischer Marker `.ds-fullbleed` deckt neue Module automatisch ab. ---------- */
.ds-content:has(.ds-fullbleed) .container-fluid,
.ds-content:has(.todo-module) .container-fluid,
.ds-content:has(.crm-module) .container-fluid,
.ds-content:has(.teamtime-module) .container-fluid {
    padding-left: 0;
    padding-right: 0;
}

/* ---------- Full-Bleed-Variante „schwebende Karten" (Baukasten-Standard ab 2026-06) ----------
   Marker `.ds-fullbleed-floating` (bzw. <ds-module floating="true">). Für Module, deren
   Bereichs-Cards (Toolbar, KPI-Kacheln, Item-/Stat-Cards) DIREKT auf dem Hintergrund schweben —
   OHNE umschließende <ds-surface> (Beispiel: itops, Dashboards). Weil hier keine Surface die
   „Luft" liefert, bekommt das Modul selbst einen etwas größeren, gleichmäßigen Direkt-Rand
   (16px statt der 4px des generischen .ds-fullbleed). Unten 140px fürs schwebende Dock.
   Steht BEWUSST hier im Head-CSS (kein Phantom-Card-Flash, siehe Block oben).
   → Wenn die Cards stattdessen in einer <ds-surface> liegen: den generischen `.ds-fullbleed`
     nehmen (die Surface liefert dann den Innen-Rand). ---------- */
.ds-main .ds-content:has(.ds-fullbleed-floating) {
    background: transparent !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    padding: 1rem 1rem 140px !important;
}
.ds-content:has(.ds-fullbleed-floating) .container-fluid {
    padding-left: 0;
    padding-right: 0;
}

/* ============================================================================
   STANDARD-INHALTS-BAUSTEINE (Baukasten) — ab 2026-06 die EINE Quelle für den Aufbau eines
   Modul-Inhalts. Neue Module setzen sich daraus zusammen, statt Grid/Surface/Gap pro Modul neu
   zu bauen. Alle Werte kommen aus den --ds-card-*-Tokens (siehe :root). Baukasten-TagHelper-
   Entsprechungen: <ds-module>, <ds-surface>, <ds-card-grid>, <ds-card-list>. Demo: /design/Spacing.
   ============================================================================ */

/* Surface = Sektions-/Inhaltskarte, die Item-Karten hält (wie Kontakts content-card). Liegt am
   Modul-Rand (--ds-content-pad-x) und gibt den Karten EIN einheitliches Innen-Polster — auch auf
   dem Smartphone, damit die Karten überall gleich weit vom Rand abrücken (Smartphone-Referenz). */
.ds-surface {
    background: var(--ds-surface, var(--ds-card));
    border: 1px solid var(--ds-border);
    border-radius: 1rem;
    box-shadow: var(--ds-surface-shadow);
    padding: var(--ds-surface-pad, 1.25rem);
}
.ds-surface + .ds-surface { margin-top: var(--ds-card-gap); }
@media (prefers-color-scheme: dark) {
    html:not(.light) .ds-surface { box-shadow: var(--ds-surface-shadow); }
}
html.dark .ds-surface { box-shadow: var(--ds-surface-shadow); }

/* Optionaler Surface-Header (Titel + Aktionen), wie "10 Kontakte". */
.ds-surface-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: var(--ds-card-gap);
}
.ds-surface-title {
    font-size: 1rem;
    font-weight: 600;
    color: var(--ds-foreground);
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

/* Einstellungs-Zeile (<ds-setting>): links Bezeichnung + Hinweis, rechts das Bedienelement in einer
   festen Spalte — so stehen alle Bedienelemente einer Karte auf einer Flucht. Gliederung über
   Abstand, keine Trennlinien. Am Handy stapelt die Zeile; Schalter bleiben rechts. */
.ds-setting {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(14rem, 22rem);
    align-items: center;
    gap: 0.5rem 1.5rem;
}
.ds-setting + .ds-setting { margin-top: 1.25rem; }
.ds-surface-head + .ds-setting,
.ds-card-description + .ds-setting { margin-top: 1rem; }
/* Suchfeld im Kopf einer Surface (<ds-surface search-id>) — rund mit Lupe, Maße wie die Suche in Kontakte. */
.ds-surface-head:has(> .ds-search-field) { flex-wrap: wrap; }
.ds-search-field { position: relative; display: block; flex: 0 1 22rem; min-width: 12rem; margin: 0; }
.ds-search-field > i {
    position: absolute; left: 0.8rem; top: 50%; transform: translateY(-50%);
    color: var(--ds-muted-foreground); font-size: 0.9rem; pointer-events: none;
}
.ds-search-field > input {
    width: 100%; height: 2.25rem; padding: 0 0.9rem 0 2.3rem;
    font-size: 0.875rem; color: var(--ds-foreground);
    background: var(--ds-background);
    border: 1px solid var(--ds-border); border-radius: 0.7rem;
    outline: none; transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.ds-search-field > input::placeholder { color: var(--ds-muted-foreground); }
.ds-search-field > input:focus {
    border-color: var(--ds-ring, var(--ds-primary));
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ds-ring, var(--ds-primary)) 35%, transparent);
}
@media (max-width: 575.98px) { .ds-search-field { flex: 1 1 100%; } }

/* Fußzeile einer Surface (<ds-surface footer>): graue Erklärung unter dem Inhalt. !important, weil
   `.ds-main p { margin: 0 !important }` sonst den Abstand schluckt — zwei Klassen reichten dagegen nicht. */
.ds-surface > .ds-surface-footer,
.ds-shell-body > .ds-surface-footer { margin: 1.5rem 0 0 !important; font-size: 0.8125rem; line-height: 1.45; color: var(--ds-muted-foreground); }
/* Karten-Raster direkt unter der grauen Beschreibung einer Surface: etwas Luft statt Kleben. */
.ds-surface > .ds-card-description + :is(.ds-card-grid, .ds-card-list) { margin-top: 0.75rem; }
.ds-setting-stack { grid-template-columns: minmax(0, 1fr); }
.ds-setting:has(> .ds-setting-control > .ds-switch:only-child) { grid-template-columns: minmax(0, 1fr) auto; }
.ds-setting .ds-setting-label { display: block; margin: 0; font-size: 0.875rem; font-weight: 600; color: var(--ds-foreground); }
.ds-setting .ds-setting-hint { margin: 0.125rem 0 0; font-size: 0.8125rem; color: var(--ds-muted-foreground); }
/* Drei Klassen: `.ds-main button:not([class*="ds-btn"])` (0,2,1) färbte den Link sonst schwarz. */
.ds-main .ds-setting .ds-setting-more {
    background: none; border: 0; padding: 0;
    font: inherit; color: var(--ds-primary); white-space: nowrap; cursor: pointer;
}
.ds-main .ds-setting .ds-setting-more:hover { text-decoration: underline; }
.ds-setting .ds-setting-info {
    margin: 0.5rem 0 0;
    padding: 0.625rem 0.75rem;
    border-radius: 0.5rem;
    font-size: 0.8125rem;
    color: var(--ds-muted-foreground);
    background: color-mix(in srgb, var(--ds-muted) 55%, transparent);
}
.ds-setting-control { display: flex; justify-content: flex-end; align-items: center; min-width: 0; }
.ds-setting-control > * { flex: 1 1 auto; min-width: 0; }
.ds-setting-stack > .ds-setting-control { justify-content: flex-start; }
.ds-setting-control > .ds-switch { flex: 0 0 auto; margin: 0; min-height: 0; }
.ds-setting-control > .ds-chip-group { flex: 0 0 auto; }
@media (max-width: 575.98px) {
    .ds-setting { grid-template-columns: minmax(0, 1fr); }
    .ds-setting > .ds-setting-control { justify-content: flex-start; }
    .ds-setting:has(> .ds-setting-control > .ds-switch:only-child) { grid-template-columns: minmax(0, 1fr) auto; }
}

/* Responsives Karten-Grid mit Standard-Gap. Spaltenbreite über --ds-card-grid-min steuerbar.
   SPALTEN-OBERGRENZE (--ds-card-grid-cols, Standard 4 wie die Kontakt-Übersicht col-xl-3):
   Mit bloßem `minmax(260px, 1fr)` wuchs das Grid auf breiten Bildschirmen auf 5–6 Spalten,
   während Kontakte bei 4 blieb — die Module sahen nebeneinander unterschiedlich aus
   (Max, 18.09.2026: „da sind 5 in einer Reihe, ich möchte es wie in den anderen Modulen auch 4").
   Die Spaltenbreite ist deshalb MINDESTENS ein Viertel der Zeile; nach unten bleibt auto-fill
   responsiv, sobald --ds-card-grid-min nicht mehr passt. */
.ds-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(max(var(--ds-card-grid-min, 260px),
        calc((100% - (var(--ds-card-grid-cols, 4) - 1) * var(--ds-card-gap)) / var(--ds-card-grid-cols, 4))), 1fr));
    gap: var(--ds-card-gap);
    align-items: start;
}

/* Kachel-Grid mit EINHEITLICHER Höhe: `ds-tiles` zusätzlich zu `ds-card-grid`. Alle Karten
   bekommen exakt --ds-tile-h — nicht nur die einer Zeile, sondern jede. Ohne das richtete sich
   jede Zeile nach ihrer höchsten Karte und das Raster franste aus (Kennzahl da/nicht da,
   Beschreibung lang/kurz). Inhalt, der nicht hineinpasst, wird in der Karte geklemmt
   (line-clamp im Modul), nicht ausgeklappt — die Höhe ist das Versprechen. */
.ds-card-grid.ds-tiles {
    align-items: stretch;
    grid-auto-rows: var(--ds-tile-h, 10rem);
}
.ds-card-grid.ds-tiles > * { min-height: 0; }
.ds-card-grid.ds-tiles > .ds-card {
    height: 100%;
    margin-bottom: 0;
    /* Spalte: der Body wächst, die Aktionsleiste sitzt IMMER an der Unterkante. Ohne das stehen
       Body und Leiste oben zusammen und unter der Leiste bleibt die Restfläche leer. */
    display: flex;
    flex-direction: column;
}
.ds-card-grid.ds-tiles > .ds-card > :not(.ds-card-actions):first-child { flex: 1 1 auto; }
/* Geklemmt wird der wachsende Teil der Karte, NICHT die Karte selbst: die Aktionsleiste trägt
   Dropdowns (⋮-Menü, Anrufen/Karte/E-Mail), die aus der Kachel ausbrechen dürfen. */
.ds-card-grid.ds-tiles > .ds-card > :not(.ds-card-actions) {
    min-height: 0;
    overflow: hidden;
}

/* ============================================================================
   MODUL-SHELL (ds-shell) — die Kopfsektion einer Modul-Übersicht, ab 18.09.2026 EINE Quelle.
   Kontakte, Formulare, Flow und Booking hatten dafür je eine eigene, wortgleiche Kopie
   (.crm-shell/.forms-index-shell/.flow-index-shell, Booking bis 06.11.2026); MyHub und Meet hatten
   gar keinen Kopf („in MyHub fehlt die Header-Sektion komplett", Max 18.09.2026). Neue Module
   nehmen diese Klassen, die vier Alt-Kopien bleiben vorerst als sie selbst bestehen.

   Aufbau:
     <section class="ds-shell">
       <header class="ds-shell-head">
         <div class="ds-shell-summary">
           <div class="ds-shell-lead"> Icon + Titel/Untertitel </div>
           <div class="ds-shell-search"> Suche (optional) </div>
           <div class="ds-shell-metrics"> ds-shell-metric* </div>
         </div>
         … optional Filterzeile/Suche …
       </header>
       <div class="ds-shell-body"> Karten-Grid </div>
     </section>
   Der Body ist der EINZIGE Scroller der Ansicht und überlappt den Kopf mit der „doppelten
   Rundung" (siehe crm-overview.css) — daher der größere Bodenabstand im Kopf.

   ZWEI GRÖSSEN, EIN STANDARD (max 07.11.2026: „eine Höhe für volle Breite und eine schmälere, wenn
   mehrere Karten in einer View sind"):
     - VOLL (Standard, ~63 px): eine Karte über die ganze Breite — Arc-Übersicht, Booking, Stage …
     - KOMPAKT (`ds-shell-head ds-shell-kompakt`, ~54 px): mehrere Karten nebeneinander — ToDo-
       Übersicht, E-Mail-Spalten, MyKI (Chats + Chat), Arc-Explorer. Köpfe nebeneinander sind immer
       gleich groß.
   Alle Maße stehen NUR in den --ds-kopf-*-Tokens unten. Module mit eigenem Kopf-Markup
   (.todo-overview-header, .uc-mail-kopf, .crm-head …) lesen dieselben Tokens, statt Zahlen zu kopieren.
   Knöpfe im Kopf: immer `.ds-kw.ds-kw-quer` (randlos, grau), nie umrandete ds-chip-btn/Bootstrap.
   ============================================================================ */
:root {
    --ds-kopf-verlauf: linear-gradient(90deg,
        color-mix(in oklch, var(--ds-accent-1) 12%, var(--ds-card)) 0%,
        var(--ds-card) 50%,
        color-mix(in oklch, var(--ds-accent-1) 12%, var(--ds-card)) 100%);
    /* Symbole/Kacheln in JEDEM Kopf (Modul, Spalte, Karte) in der Leitfarbe des Admins
       (Darstellung → „Primäre Akzentfarbe") — nie --ds-primary (festes Blau), sonst erkennt der
       Kunde seine CI nicht (max 08.11.2026). Dunkel: aufgehellte Leitfarbe (--ds-accent-1-text). */
    --ds-kopf-akzent: var(--ds-accent-1-text, var(--ds-accent-1));
    --ds-kopf-kachel-bg: color-mix(in srgb, var(--ds-accent-1) 12%, var(--ds-background));
    /* VOLL */
    --ds-kopf-pad: .5rem 1.2rem 1.25rem;
    --ds-kopf-kachel: 2.1rem;
    --ds-kopf-kachel-r: .7rem;
    --ds-kopf-kachel-fs: 1.2rem;
    --ds-kopf-titel: 1rem;
    --ds-kopf-titel-fw: 700;
    /* KOMPAKT (mehrere Karten nebeneinander) */
    --ds-kopf-k-pad: .45rem .9rem 1.25rem;
    --ds-kopf-k-minh: 3.4rem;
    --ds-kopf-k-kachel: 1.65rem;
    --ds-kopf-k-kachel-r: .55rem;
    --ds-kopf-k-kachel-fs: .95rem;
    --ds-kopf-k-titel: .95rem;
    --ds-kopf-k-titel-fw: 600;
}
html.ds-page:has(.ds-shell),
html.ds-page:has(.ds-shell) body {
    overflow: hidden;
}
.ds-shell {
    display: flex;
    flex-direction: column;
    /* Bis über das Dock, gescrollt wird innen. Oberer Rand GEMESSEN (ds-geraeteklasse.js → --ds-oben),
       Abstand zum Dock zentral (--ds-dock-luft). Der frühere feste Abzug (138 px) passte nach dem
       schlankeren Dock nicht mehr — Stage/MyHub liefen ins Dock (Max, 07.11.2026). dvh mit vh als Vorzeile. */
    max-height: calc(100vh - var(--ds-oben, 4.5rem) - var(--ds-dock-luft));
    max-height: calc(100dvh - var(--ds-oben, 4.5rem) - var(--ds-dock-luft));
    border-radius: var(--ds-card-radius);
    border: 1px solid var(--ds-border);
    background: var(--ds-card);
    overflow: hidden;                 /* klippt die doppelte Rundung sauber */
    margin-top: .75rem;
    margin-bottom: 1.5rem;
    box-shadow: var(--ds-surface-shadow);
}
@media (prefers-color-scheme: dark) {
    html:not(.light) .ds-shell { box-shadow: var(--ds-surface-shadow); }
}
html.dark .ds-shell { box-shadow: var(--ds-surface-shadow); }

.ds-shell-head {
    flex-shrink: 0;
    background: var(--ds-kopf-verlauf);
    /* unten mehr: der Body legt sich mit der Rundung darüber */
    padding: var(--ds-kopf-pad);
}
.ds-shell-summary { display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap; }
.ds-shell-lead { display: flex; align-items: center; gap: .8rem; min-width: 0; }
/* Symbol-Kachel: ohne eigene Tönung im Markup immer Leitfarbe (ds-tint-… und ds-fg-… dürfen umfärben). */
.ds-shell-icon {
    width: var(--ds-kopf-kachel); height: var(--ds-kopf-kachel); border-radius: var(--ds-kopf-kachel-r); flex-shrink: 0;
    display: grid; place-items: center; font-size: var(--ds-kopf-kachel-fs);
    background: var(--ds-kopf-kachel-bg);
    color: var(--ds-kopf-akzent);
}
/* „Primärton" und „Info" im Markup (ds-tint-primary/-info, ds-fg-primary/-info an Kopf- und Kennzahl-
   Kacheln) heißen in einem Kopf die Leitfarbe des Admins — beide sind dort nur Schmuck, kein Status.
   Status-Töne (success/warning/destr/muted) bleiben. */
:is(.ds-shell-head, .mod-hd, .crm-head, .myapp-hd, .widget-header, .todo-overview-header, .uc-mail-kopf,
    .itops-mv-head, .patch-mv-head, .arc-audit-hd, .perm-editor-head) :is(.ds-tint-primary, .ds-tint-info) { background: var(--ds-kopf-kachel-bg); }
:is(.ds-shell-head, .mod-hd, .crm-head, .myapp-hd, .widget-header, .todo-overview-header, .uc-mail-kopf,
    .itops-mv-head, .patch-mv-head, .arc-audit-hd, .perm-editor-head) :is(.ds-fg-primary, .ds-fg-info) { color: var(--ds-kopf-akzent); }
.ds-shell-lead-text { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.ds-shell-title { font-size: var(--ds-kopf-titel); font-weight: var(--ds-kopf-titel-fw); color: var(--ds-foreground); line-height: 1.2; margin: 0; }
.ds-shell-sub { font-size: .72rem; line-height: 1.2; color: var(--ds-muted-foreground) !important; }
/* Knopfgruppe rechts im Kopf (ds-kw-quer) */
.ds-shell-actions { display: flex; align-items: center; gap: .15rem; flex-shrink: 0; margin-left: auto; }

/* KOMPAKT: mehrere Karten nebeneinander. Gleiche Bauteile, kleinere Tokens. Der Token-Wechsel greift auf
   JEDEM Kopf mit dieser Klasse (auch .mod-hd, .crm-head …), das Layout nur am ds-shell-head. */
.ds-shell-kompakt {
    --ds-kopf-pad: var(--ds-kopf-k-pad);
    --ds-kopf-kachel: var(--ds-kopf-k-kachel);
    --ds-kopf-kachel-r: var(--ds-kopf-k-kachel-r);
    --ds-kopf-kachel-fs: var(--ds-kopf-k-kachel-fs);
    --ds-kopf-titel: var(--ds-kopf-k-titel);
    --ds-kopf-titel-fw: var(--ds-kopf-k-titel-fw);
    min-height: var(--ds-kopf-k-minh);
}
.ds-shell-head.ds-shell-kompakt { display: flex; flex-direction: column; justify-content: center; }
.ds-shell-kompakt .ds-shell-summary { gap: .5rem; flex-wrap: nowrap; }
.ds-shell-kompakt .ds-shell-lead { gap: .5rem; flex: 1 1 auto; }
.ds-shell-kompakt :is(.ds-shell-title, .ds-shell-sub) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Kompakt ist einzeilig: der Untertitel steht grau HINTER dem Titel statt darunter (sonst ~62 px). */
.ds-shell-kompakt .ds-shell-lead-text { flex-direction: row; align-items: baseline; gap: .45rem; }
.ds-shell-kompakt .ds-shell-title { flex: 0 1 auto; }
.ds-shell-kompakt .ds-shell-sub { flex: 0 10 auto; min-width: 0; }
.ds-shell-kompakt .ds-shell-metric-icon { width: var(--ds-kopf-kachel); height: var(--ds-kopf-kachel); border-radius: var(--ds-kopf-kachel-r); }
.ds-shell-kompakt .ds-shell-metric-value { font-size: .95rem; }

.ds-shell-metrics { display: flex; align-items: center; gap: 1.5rem; margin-left: auto; flex-wrap: wrap; }
.ds-shell-metric { display: flex; align-items: center; gap: .55rem; }
.ds-shell-metric-icon {
    width: 2.1rem; height: 2.1rem; border-radius: .65rem; flex-shrink: 0;
    display: grid; place-items: center; font-size: .95rem;
}
.ds-shell-metric-data { display: flex; flex-direction: column; line-height: 1.15; }
/* Wert 1 rem + Label .66 rem passen in die 2,1-rem-Kachel — größer machte jeden Kopf mit Kennzahlen 68 px hoch */
.ds-shell-metric-value { font-size: 1rem; font-weight: 800; color: var(--ds-foreground); font-variant-numeric: tabular-nums; }
.ds-shell-metric-label { font-size: .66rem; color: var(--ds-muted-foreground) !important; }

/* Zweite Kopfzeile (Filter-Chips, Suche) unter der Zusammenfassung. */
.ds-shell-tools {
    display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
    margin-top: .9rem;
}
.ds-shell-tools-spacer { margin-left: auto; }
/* Bedienelemente der zweiten Zeile so hoch wie die Knöpfe (ds-kw-quer, 1,65 rem) — sonst wurde jeder
   zweizeilige Kopf anders hoch (Auswahlfeld 36, Umschalter 40, Suche 34 px; 07.11.2026). */
.ds-shell-tools :is(.form-select, select, .ds-select > button) {
    height: var(--ds-kopf-k-kachel); min-height: 0; padding-top: 0; padding-bottom: 0; font-size: .8rem;
}

/* Chips im Verlaufskopf (<ds-chip-group>: Filter in Kontakte, Feed …) im Notizbuch-Stil wie .ds-kw-quer:
   randlos, grau, gewählt = getönt in der Leitfarbe. Auswahl-Logik und Zähler der Gruppe bleiben. Farben mit
   !important gegen `.ds-main button:not([class*="ds-btn"])` (0,2,1). */
:is(.ds-shell-head, .crm-head) .ds-chip {
    height: var(--ds-kopf-k-kachel); padding: 0 .55rem; gap: .35rem;
    border: 0; border-radius: .6rem; background: transparent; box-shadow: none;
    font-size: .8rem; font-weight: 500; color: var(--ds-foreground) !important;
    transition: background .15s ease, color .15s ease, box-shadow .15s ease, transform .1s ease;
}
:is(.ds-shell-head, .crm-head) .ds-chip > i { font-size: .95rem; }
:is(.ds-shell-head, .crm-head) .ds-chip span:not(.ds-chip-count) { color: inherit !important; }
:is(.ds-shell-head, .crm-head) .ds-chip:hover {
    background: color-mix(in srgb, var(--ds-accent-1) 14%, var(--ds-card));
    color: var(--ds-accent-1-text, var(--ds-accent-1)) !important;
}
:is(.ds-shell-head, .crm-head) .ds-chip:active { transform: scale(.95); }
:is(.ds-shell-head, .crm-head) .ds-chip.ds-chip-selected,
:is(.ds-shell-head, .crm-head) .ds-chip.ds-chip-selected:hover {
    background: color-mix(in srgb, var(--ds-accent-1) var(--ds-menu-active, 22%), transparent);
    color: var(--ds-accent-1-text, var(--ds-accent-1)) !important;
}
:is(.ds-shell-head, .crm-head) .ds-chip.ds-chip-selected .ds-chip-count {
    background: color-mix(in srgb, var(--ds-accent-1) 18%, transparent);
    color: var(--ds-accent-1-text, var(--ds-accent-1)) !important;
}
/* Umschalter (<ds-segmented>, z. B. Kacheln/Liste) in der zweiten Kopfzeile: so hoch wie die Knöpfe. */
.ds-shell-tools .ds-segmented { padding: 2px; }
.ds-shell-tools .ds-segmented-item { height: calc(var(--ds-kopf-k-kachel) - 4px); padding-top: 0; padding-bottom: 0; display: inline-flex; align-items: center; font-size: .8rem; }

/* Kennzahl als Einstieg (Button/Link in die Liste): Fläche erst beim Hover, die negative Margin hält
   den Kopf auf seiner Höhe. EINE Quelle für Booking, iTOPS, Blog, Personalakte … */
.ds-shell-metric.is-clickable {
    border: 0; background: transparent; padding: .15rem .3rem; margin: -.15rem -.3rem;
    border-radius: .6rem; cursor: pointer; text-align: left; font: inherit; color: inherit; text-decoration: none;
}
.ds-main a.ds-shell-metric.is-clickable { color: inherit; text-decoration: none; }
.ds-shell-metric.is-clickable:hover,
.ds-shell-metric.is-clickable:focus-visible { background: color-mix(in srgb, var(--ds-accent-1) 10%, transparent); }

/* SUCHFELD IM KOPF = die Arc-Pille, in JEDEM Modul gleich (max 07.11.2026: „die Suchfiltereingaben sind
   unterschiedlich … einheitlich wie in Arc"). Greift auf jede Bauart „Hülle > Lupe + Eingabe" in einem
   Verlaufskopf (ds-search-field, ds-shell-search, Kontakte, MyApp, Meet, Arc …), ohne Markup-Umbau.
   Höhe 2 rem; in kompakten Köpfen und in der Filterzeile so hoch wie die Knöpfe. Seit 08.11.2026 auch das
   Suchfeld im Menü-Baum (Dropdowns Archive/Ordner/Chats). */
:root { --ds-suche-h: 2rem; --ds-suche-max: 24rem; }   /* 24 rem = Breite der Arc-Suche */
:is(.ds-shell-kompakt, .ds-shell-tools) { --ds-suche-h: var(--ds-kopf-k-kachel); }
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head, .ds-menue-baum) :has(> .bi-search):has(> input) { position: relative; }
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head, .ds-menue-baum) :has(> .bi-search) > input:is([type=text], [type=search], :not([type])) {
    height: var(--ds-suche-h); min-height: 0;
    padding: 0 .75rem 0 1.9rem !important;          /* !important: Arc/Bootstrap setzen das Polster ebenfalls hart */
    font-size: .85rem; line-height: 1.2; color: var(--ds-foreground) !important;
    background: var(--ds-background) !important;   /* !important: ds-field-light setzt Weiß hart (Dunkelmodus) */
    border: 1px solid var(--ds-border) !important; border-radius: 999px;   /* !important: ds-field-light/tw-border-input */
    box-shadow: none; outline: none;
    transition: border-color .15s ease, box-shadow .15s ease;
}
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head, .ds-menue-baum) :has(> .bi-search) > input::placeholder { color: var(--ds-muted-foreground); opacity: 1; }
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head, .ds-menue-baum) :has(> .bi-search) > input:focus {
    border-color: var(--ds-ring, var(--ds-primary)) !important;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ds-ring, var(--ds-primary)) 35%, transparent);
}
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head, .ds-menue-baum) :has(> .bi-search):has(> input) > .bi-search {
    position: absolute; left: .6rem; top: 50%; transform: translateY(-50%); z-index: 1;
    font-size: .8rem; line-height: 1; pointer-events: none;
    color: var(--ds-muted-foreground) !important;
}

/* Trefferzähler + „Zurücksetzen" HINTER dem Feld, wie in Arc — hängt ds-kopf-suche.js an jede Kopf-Suche.
   Die Hülle wird dafür zur Zeile; solange gesucht wird, darf sie über die Feldbreite hinaus wachsen.
   Eigene ×-Knöpfe der Module im Feld entfallen (EIN Zurücksetzen). */
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head) .ds-suche-mit-reset { display: flex; align-items: center; gap: .35rem; }
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head) .ds-suche-mit-reset > input { flex: 1 1 auto; width: auto; min-width: 6rem; }
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head) .ds-suche-mit-reset.ds-suche-aktiv { max-width: none; }
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head) .ds-suche-mit-reset.ds-suche-aktiv > input { flex: 0 1 var(--ds-suche-max); }
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head) .ds-suche-mit-reset > button:not(.ds-suche-reset),
:is(.ds-shell-head, .crm-head, .mod-hd, .myapp-hd, .widget-header, .itops-mv-head, .patch-mv-head) .ds-suche-mit-reset > [hidden] { display: none !important; }
.ds-suche-treffer { flex-shrink: 0; font-size: .75rem; white-space: nowrap; color: var(--ds-muted-foreground) !important; }
.ds-suche-reset { flex-shrink: 0; }
/* Enge Köpfe (kompakt, Widget-Kacheln): Zurücksetzen nur als Symbol, der Text steht im Tooltip */
:is(.ds-shell-kompakt, .widget-header) .ds-suche-reset { width: var(--ds-kopf-k-kachel); padding: 0; justify-content: center; }
:is(.ds-shell-kompakt, .widget-header) .ds-suche-reset > span { display: none; }
/* … und das Feld darf schmaler werden, damit Zähler und × im schmalen Spaltenkopf Platz haben (MyKI-Chatliste) */
:is(.ds-shell-kompakt, .widget-header) .ds-suche-mit-reset { min-width: 0; }
:is(.ds-shell-kompakt, .widget-header) .ds-suche-mit-reset > input { min-width: 3.5rem; }

/* Kopf ohne Body darunter (Seitenkopf über einem Widget-Raster, iTOPS): gleiche Höhe wie ein voller Kopf,
   Polster oben und unten gleich, eigene Rundung statt Überlappung. */
.ds-shell-head.ds-shell-solo { padding-top: .85rem; padding-bottom: .85rem; border-radius: var(--ds-card-radius); }

/* Suche in der Kopfzeile: zwischen Titel und Kennzahlen, mittig im freien Raum (Max, 25.09.2026).
   Reicht die Breite des Kopfes nicht für alles in einer Zeile, rutscht die Suche in eine eigene Zeile
   darunter — gemessen am Kopf selbst (Container-Abfrage), nicht am Fenster: die Seitenleiste nimmt
   unterschiedlich viel Platz. Der Container sitzt nur auf der Zusammenfassung MIT Suche. */
.ds-shell-summary:has(> .ds-shell-search) { container: ds-kopf-suche / inline-size; }
.ds-shell-search { flex: 1 1 16rem; min-width: 12rem; max-width: var(--ds-suche-max); margin-inline: auto; }
@container (max-width: 1100px) { .ds-shell-search { order: 3; flex: 1 1 100%; max-width: none; margin-inline: 0; } }
/* Mit Suche teilen sich NUR ihre beiden Auto-Ränder den freien Raum — sonst nahm der linke Rand der Kennzahlen ein
   Drittel mit und die Suche stand links der Mitte (Booking: 137 px zum Titel, 255 px zu den Kennzahlen). */
.ds-shell-summary:has(> .ds-shell-search) > .ds-shell-metrics { margin-left: 0; }
/* Kopf OHNE Kennzahlen/Knöpfe rechts: Suche in der Kopfmitte. „Mittig im freien Raum" reichte dort bis zum rechten
   Rand — die Suche stand rechts der Mitte (Zeiterfassung, max 07.11.2026). Titel und ein leeres Gegengewicht
   rechts teilen sich den Rest gleich. */
.ds-shell-summary:has(> .ds-shell-search):not(:has(> .ds-shell-metrics, > .ds-shell-actions)) > .ds-shell-lead { flex: 1 1 0; }
.ds-shell-summary:has(> .ds-shell-search):not(:has(> .ds-shell-metrics, > .ds-shell-actions))::after { content: ""; flex: 1 1 0; }
/* Kopf MIT Kennzahlen oder Knöpfen rechts: genauso — Titel und rechte Gruppe teilen sich den Rest gleich, die Suche
   steht in der Kopfmitte. „Mittig im freien Raum" verschob sie um die halbe Breitendifferenz Titel ↔ rechts
   (Booking 209 px, Hilfe 118 px, Unterschriften 185 px; max 09.11.2026). Die rechte Gruppe wird dabei nie schmaler
   als ihr Inhalt (kein Umbruch der Kennzahlen); reicht ihr die Hälfte nicht, weicht die Suche nur so weit wie nötig.
   Nur solange die Suche in der Titelzeile steht — darunter (eigene Zeile) gilt der Umbruch oben. */
@container ds-kopf-suche (width > 1100px) {
    .ds-shell-lead { flex: 1 1 0; }
    .ds-shell-metrics, .ds-shell-actions { flex: 1 1 0; min-width: max-content; justify-content: flex-end; margin-left: 0; }
    .ds-shell-search { margin-inline: 0; }
}
/* Passt die Suche auch schmaler nicht mittig zwischen Titel und rechte Gruppe, setzt ds-kopf-suche.js (mitteHalten)
   diese Klasse: Suche in eigener Zeile darunter, wie unter 1100 px Kopfbreite. */
.ds-shell-summary.ds-suche-eigene-zeile > .ds-shell-search { order: 3; flex: 1 1 100%; max-width: none; margin-inline: 0; }

/* Body: doppelte Rundung nach oben, getönt gegen das Weiß der Karten, EINZIGER Scroller. */
.ds-shell-body {
    position: relative; z-index: 1;
    flex: 1; min-height: 0;
    overflow-y: auto; overflow-x: hidden;
    overscroll-behavior: contain;
    margin-top: calc(-1 * var(--ds-card-radius));
    border-top-left-radius: var(--ds-card-radius);
    border-top-right-radius: var(--ds-card-radius);
    background: var(--ds-surface);
    padding: 1.5rem 1.1rem 1.35rem;
}

/* Schmale Fenster: Kopf bricht um, eine feste Viewport-Rechnung würde das Listenende unter den
   Rand schieben — dort zurück zum gewohnten Seitenscroll (Muster aus myhub-index.css). */
@media (max-width: 767.98px) {
    html.ds-page:has(.ds-shell),
    html.ds-page:has(.ds-shell) body { overflow: auto; }
    .ds-shell { max-height: none; }
    /* BEIDE Achsen visible und Scroll-Weitergabe frei: Mit overflow-x:hidden wird overflow-y:visible zu auto —
       der Body blieb ein (leerer) Scroller, und overscroll-behavior:contain schluckte jedes Wischen auf der
       Liste, die Seite scrollte nur noch über dem Kopf (Fold 8 außen, Benutzer, 31.10.2026). Seitlich
       klippt weiter .ds-shell (overflow:hidden). */
    .ds-shell-body { overflow: visible; overscroll-behavior: auto; }
    .ds-shell-metrics { gap: 1rem; margin-left: 0; }
}

/* Einspaltige Karten-Liste mit Standard-Gap. */
.ds-card-list {
    display: flex;
    flex-direction: column;
    gap: var(--ds-card-gap);
}

/* ---------- Native-Bootstrap-Flächen unter dem Tailwind-Layout dunkelfähig machen ----------
   PROBLEM: Das Tailwind-Layout lädt KEIN site.css (das im Alt-Layout die Bootstrap-Dark-Overrides
   brachte), dafür aber bootstrap-dark-5 (bootstrap-dark.min.css). Dieses pinnt .card/.list-group/
   .table/.dropdown-menu/.nav-tabs HART auf Bootstrap-Hell (z.B. `.card{background:#fff}`) —
   unabhängig von Theme/.dark/[data-bs-theme]. Da das Layout zugleich den HELLEN Token-Text erzwingt,
   wurde heller Text auf weißen BS-Cards UNSICHTBAR (Einstellungen-Sektion = viele Legacy-BS-Views).
   LÖSUNG (wie .form-control/.modal-content bereits weiter unten): auf die Design-Tokens heben — wirkt
   hell UND dunkel automatisch. Scope `html.ds-page` ⇒ (1) höhere Spezifität als bootstrap-darks bare
   `.card`, (2) nur Tailwind-Layout — Alt-Layout-Seiten (site.css) bleiben unberührt. bootstrap-dark-5
   setzt die ECHTEN Properties (nicht --bs-Vars), daher hier ebenfalls direkt überschreiben. ---------- */
html.ds-page .card {
    background-color: var(--ds-card);
    color: var(--ds-card-foreground);
    border-color: var(--ds-border);
}
html.ds-page .card-header,
html.ds-page .card-footer {
    background-color: color-mix(in srgb, var(--ds-card-foreground) 4%, transparent);
    border-color: var(--ds-border);
    color: var(--ds-card-foreground);
}
html.ds-page .list-group-item {
    background-color: transparent;
    color: var(--ds-card-foreground);
    border-color: var(--ds-border);
}
html.ds-page .list-group-item.active {
    background-color: var(--ds-accent-1);
    border-color: var(--ds-accent-1);
    color: #fff;
}
html.ds-page .table {
    color: var(--ds-card-foreground);
    border-color: var(--ds-border);
    --bs-table-bg: transparent;
    --bs-table-color: var(--ds-card-foreground);
    --bs-table-border-color: var(--ds-border);
    --bs-table-striped-bg: color-mix(in srgb, var(--ds-card-foreground) 4%, transparent);
    --bs-table-striped-color: var(--ds-card-foreground);
    --bs-table-hover-bg: color-mix(in srgb, var(--ds-card-foreground) 7%, transparent);
    --bs-table-hover-color: var(--ds-card-foreground);
}
html.ds-page .table > :not(caption) > * > * {
    color: var(--ds-card-foreground);
    border-bottom-color: var(--ds-border);
}
html.ds-page .dropdown-menu {
    background-color: var(--ds-card);
    border-color: var(--ds-border);
    color: var(--ds-card-foreground);
}
html.ds-page .dropdown-item { color: var(--ds-card-foreground); }
html.ds-page .dropdown-divider { border-top-color: var(--ds-border); }
html.ds-page .nav-tabs { border-bottom-color: var(--ds-border); }
html.ds-page .nav-tabs .nav-link { color: var(--ds-muted-foreground); }
html.ds-page .nav-tabs .nav-link:hover { border-color: var(--ds-border); }
html.ds-page .nav-tabs .nav-link.active {
    background-color: var(--ds-card);
    color: var(--ds-card-foreground);
    border-color: var(--ds-border) var(--ds-border) var(--ds-card);
}
html.ds-page .accordion {
    --bs-accordion-bg: transparent;
    --bs-accordion-color: var(--ds-card-foreground);
    --bs-accordion-border-color: var(--ds-border);
    --bs-accordion-btn-bg: transparent;
    --bs-accordion-btn-color: var(--ds-card-foreground);
    --bs-accordion-active-bg: color-mix(in srgb, var(--ds-card-foreground) 6%, transparent);
    --bs-accordion-active-color: var(--ds-card-foreground);
}
html.ds-page .accordion-item {
    background-color: transparent;
    color: var(--ds-card-foreground);
    border-color: var(--ds-border);
}
html.ds-page .accordion-button {
    background-color: transparent;
    color: var(--ds-card-foreground);
}
html.ds-page .accordion-button:not(.collapsed) {
    background-color: color-mix(in srgb, var(--ds-card-foreground) 6%, transparent);
    color: var(--ds-card-foreground);
    box-shadow: none;
}
html.ds-page .accordion-body { color: var(--ds-card-foreground); }
/* Das Bootstrap-Chevron ist ein dunkles SVG (auf Hell sichtbar) — im Dunkelmodus aufhellen,
   sonst verschwindet es auf der dunklen Fläche. */
html.dark .accordion-button::after { filter: invert(1) grayscale(1) brightness(1.8); }

/* Kontext-Alerts (.alert-info/.alert-warning/...) — bootstrap-dark-5 pinnt sie auf HELLE Flächen
   (z.B. #cff4fc), der erzwungene helle Token-Text wurde darauf unleserlich. Auf eine dezente,
   theme-agnostische Tönung der Variantenfarbe über der Card-Fläche heben (color-mix auf --ds-card)
   + Token-Text. Wirkt hell UND dunkel automatisch. (NICHT die Baukasten-ds-alert, die ist eigenständig.) */
html.ds-page .alert-info {
    background-color: color-mix(in srgb, #0dcaf0 15%, var(--ds-card));
    border-color: color-mix(in srgb, #0dcaf0 35%, transparent);
    color: var(--ds-card-foreground);
}
html.ds-page .alert-warning {
    background-color: color-mix(in srgb, #ffc107 15%, var(--ds-card));
    border-color: color-mix(in srgb, #ffc107 35%, transparent);
    color: var(--ds-card-foreground);
}
html.ds-page .alert-success {
    background-color: color-mix(in srgb, #198754 18%, var(--ds-card));
    border-color: color-mix(in srgb, #198754 35%, transparent);
    color: var(--ds-card-foreground);
}
html.ds-page .alert-danger {
    background-color: color-mix(in srgb, #dc3545 15%, var(--ds-card));
    border-color: color-mix(in srgb, #dc3545 35%, transparent);
    color: var(--ds-card-foreground);
}
html.ds-page .alert-primary {
    background-color: color-mix(in srgb, #0d6efd 15%, var(--ds-card));
    border-color: color-mix(in srgb, #0d6efd 35%, transparent);
    color: var(--ds-card-foreground);
}
html.ds-page .alert-secondary {
    background-color: color-mix(in srgb, #6c757d 18%, var(--ds-card));
    border-color: color-mix(in srgb, #6c757d 35%, transparent);
    color: var(--ds-card-foreground);
}
/* Input-Group-Prefix/Suffix (z.B. Icon vor einem Feld) — bootstrap-dark-5 lässt sie hell. */
html.ds-page .input-group-text {
    background-color: color-mix(in srgb, var(--ds-card-foreground) 6%, var(--ds-card));
    border-color: var(--ds-input);
    color: var(--ds-card-foreground);
}
/* Readonly-/„disabled-look"-Felder mit der Bootstrap-Utility .bg-light (trägt !important) — sonst
   weißes Feld + heller Text. Auf eine dezent erhöhte dunkle Fläche heben (nur Formularfelder). */
html.ds-page .form-control.bg-light,
html.ds-page input.bg-light,
html.ds-page textarea.bg-light {
    background-color: color-mix(in srgb, var(--ds-card-foreground) 7%, var(--ds-card)) !important;
    color: var(--ds-card-foreground) !important;
}
/* Checkboxen/Radios (NICHT die .form-switch — die ist Baukasten-eigen und sitzt korrekt). */
html.ds-page .form-check:not(.form-switch) .form-check-input {
    background-color: var(--ds-background);
    border-color: var(--ds-input);
}
html.ds-page .form-check:not(.form-switch) .form-check-input:checked,
html.ds-page .form-check:not(.form-switch) .form-check-input:indeterminate {
    background-color: var(--ds-accent-1);
    border-color: var(--ds-accent-1);
}
/* Viele Modal-Sektionen nutzen Inline-Labels (tw-flex) statt des Bootstrap-.form-check-Wrappers
   → die obige Regel griff dort nie, die Checkbox blieb rohe Bootstrap-Optik ("hässlich",
   im Light-Theme kaum sichtbarer Haken). Hier .form-check-input AUCH ohne .form-check themen.
   Switches (DsSwitch: .ds-switch-input / role=switch) bleiben ausgenommen. */
html.ds-page input.form-check-input:not(.ds-switch-input):not([role=switch]) {
    background-color: var(--ds-background);
    border-color: var(--ds-input);
}
html.ds-page input.form-check-input:not(.ds-switch-input):not([role=switch]):checked,
html.ds-page input.form-check-input:not(.ds-switch-input):not([role=switch]):indeterminate {
    background-color: var(--ds-accent-1);
    border-color: var(--ds-accent-1);
}

/* ---------- Einstellungen-Sektion (RCL Project1.Views.Settings) — Shell + Seitennavigation.
   Bewusst hier im Head-CSS (nicht in nachgeladener View-CSS): Layout-relevant, muss beim
   ERSTEN Paint stehen (sonst Phantom-Card/Sprung). Scoped sticky IN-FLOW Sidebar — NICHT die
   globale .ds-sidebar (die ist position:fixed + zerschiesst Absätze). Mobile = Bootstrap
   responsive Off-Canvas (.offcanvas-lg). ---------- */
.settings-shell {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    /* Settings ist FULL-BLEED (wie ToDo/CRM): .settings-module steht im :has()-Neutralizer, die
       umschließende .ds-content-Card ist aufgelöst. KEIN umschließendes Card-Wrapper — stattdessen
       sitzen die eigenständige Nav-Leiste (solide Fläche) und die Inhalts-Cards direkt auf dem
       Modul-Rand; der Body-Hintergrund scheint NUR in den Zwischenräumen durch (gewollt, wie ToDo).
       Horizontaler Rand kommt aus dem neutralisierten .ds-content (--ds-content-pad-x: 1.25rem),
       daher hier KEIN eigenes Padding. */
    padding: 0;
}
/* max-width:100% ist Pflicht, nicht Deko: min-width:0 allein laesst das Flex-Item trotzdem auf
   seine max-content-Breite wachsen, sobald der Inhalt eine breite Tabelle enthaelt. Die Spalte
   schob sich dann ueber den rechten Bildschirmrand (Aktions-Spalte abgeschnitten), statt den
   Scroll-Container im Inhalt scrollen zu lassen — sichtbar ab mittleren Breiten (~900 px). */
.settings-content { flex: 1 1 auto; min-width: 0; max-width: 100%; }
.settings-nav-toggle { width: 100%; margin-bottom: 0.75rem; }

/* Hilfe-Knopf je Einstellungs-Seite (_Layout_Settings_Tailwind.cshtml).
   Der ds-help-btn-TagHelper rendert NICHTS, wenn es zur Seite kein Erklärvideo gibt — dann darf
   auch der Platzhalter keinen Raum einnehmen. `:empty` allein reicht nicht: Razor lässt Whitespace
   im Container stehen, deshalb zusätzlich `:not(:has(*))`. */
.settings-help-slot { display: flex; justify-content: flex-end; margin-bottom: 0.5rem; }
.settings-help-slot:empty,
.settings-help-slot:not(:has(*)) { display: none; }

@media (min-width: 992px) {
    .settings-nav.offcanvas-lg {
        flex: 0 0 230px;
        width: 230px;
        /* .offcanvas-start traegt translateX(-100%) auch ueber dem Breakpoint -> hier aufheben,
           sonst rutscht die Sidebar um ihre Breite nach links aus dem Viewport. */
        transform: none !important;
        visibility: visible !important;
        position: sticky;
        top: 1rem;
        /* Das schwebende Dock (#MenuWrapper, position:fixed, z-index 1030) liegt am unteren
           Viewport-Rand ÜBER der Nav. Ohne den Abzug endet die Scroll-Liste dahinter: der
           jeweils letzte Eintrag ist zwar sichtbar, aber jeder Klick landet auf dem Dock und
           tut nichts (gemeldet 24.08.2026 für „Version", betraf vorher „Push Benachrichtigungen"). */
        max-height: calc(100vh - 2rem - var(--app-dock-reserve));
        /* dvh: am iPad (Safari) ist vh die Höhe OHNE Browserleisten — die Leiste ragte sonst unter
           die Werkzeugleiste und die letzten Einträge waren erst nach dem Einfahren erreichbar. */
        max-height: calc(100dvh - 2rem - var(--app-dock-reserve));
        overflow-y: auto;
        overscroll-behavior: contain;
        padding: 0.85rem 0.75rem;
        /* SOLIDE Card-Fläche (#171717) — NICHT 3% Weiß: im Full-Bleed sitzt die Nav direkt auf dem
           Body-Hintergrundbild, eine durchsichtige Leiste sah aus wie „kaputt". Jetzt eigenständige
           Karte wie die Inhalts-Cards/ToDo-Spalten. */
        background: var(--ds-card) !important;
        border: 1px solid var(--ds-border, rgba(255,255,255,0.08));
        border-radius: 1rem;
        box-shadow: var(--ds-surface-shadow);
    }
}

/* Scrollbalken der Seitenleiste: dünn und erst beim Darüberfahren sichtbar. scrollbar-width erbt
   NICHT vom html — ohne eigene Angabe malte Chrome hier den breiten Balken mit Pfeilknöpfen in der
   Akzentfarbe. Gilt für die Leiste am Desktop und den Scrollbereich des Flyouts. */
.settings-nav, .settings-nav .settings-nav-body {
    scrollbar-width: thin;
    scrollbar-color: transparent transparent;
}
.settings-nav:hover, .settings-nav .settings-nav-body:hover {
    scrollbar-color: color-mix(in srgb, var(--ds-muted-foreground) 40%, transparent) transparent;
}

/* Mobile: die Nav ist ein Bootstrap-Off-Canvas (Slide-in) — ebenfalls solide #171717-Fläche,
   sonst scheint hinter der Schublade der Body-Hintergrund durch / Bootstrap-Hell. */
html.ds-page .settings-nav.offcanvas-lg {
    background-color: var(--ds-card);
}

/* Dasselbe Dock-Problem wie in der Desktop-Regel oben, nur andersherum gelöst: die Schublade geht
   über die volle Höhe, deshalb bekommt ihr Scroll-Inhalt unten den Dock-Platz als Polster —
   sonst liegt der letzte Eintrag hinter dem Dock und lässt sich nicht anklicken. */
@media (max-width: 991.98px) {
    .settings-nav.offcanvas-lg .settings-nav-body {
        padding-bottom: var(--app-dock-reserve);
    }
    /* Flyout wie „Chats" in MyKI (myki-skin.css .myki-chat-offcanvas): schmaler als der Bildschirm,
       damit sichtbar bleibt, dass dahinter die Seite liegt. */
    .settings-nav.offcanvas-lg {
        width: min(86vw, 360px) !important;
        background: var(--ds-background) !important;
        border-right: 1px solid var(--ds-border);
    }
    .settings-nav.offcanvas-lg .offcanvas-header { padding: 0.85rem 1rem; }
    .settings-nav.offcanvas-lg .offcanvas-title { display: flex; align-items: center; font-size: 1rem; font-weight: 600; }
}
html.dark .settings-nav .btn-close { filter: invert(1) grayscale(100%) brightness(200%); }

.settings-nav-list { width: 100%; }
.settings-nav-cat {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.6;
    padding: 0.25rem 0.5rem;
    margin-top: 0.5rem;
}
.settings-nav-cat:first-child { margin-top: 0; }
.settings-nav-group { list-style: none; margin: 0 0 0.5rem; padding: 0; }
.settings-nav-group li { margin: 0; }
.settings-nav-link {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.6rem;
    border-radius: 0.5rem;
    color: var(--bs-body-color);
    text-decoration: none;
    font-size: 0.875rem;
    line-height: 1.2;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.settings-nav-link .settings-nav-ico { font-size: 1rem; width: 1.15rem; text-align: center; flex: 0 0 auto; }
.settings-nav-link .settings-nav-ico-img { width: 1rem; height: 1rem; flex: 0 0 auto; }
.settings-nav-link .settings-nav-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.settings-nav-link:hover:not(.active) { background: var(--bs-tertiary-bg, rgba(255,255,255,0.06)); color: var(--bs-body-color); }
.settings-nav-link.active {
    background: var(--ds-accent-1, var(--bs-primary));
    color: #fff;
    font-weight: 600;
}
/* Die Resets für `.ds-main a` (Akzentfarbe) und `.ds-main span` (Textfarbe) sind spezifischer und
   färbten den aktiven Punkt Blau bzw. Schwarz auf Blau. */
.settings-nav-link.active,
.settings-nav-link.active .settings-nav-label,
.settings-nav-link.active .settings-nav-ico { color: #fff !important; }

/* Full-Bleed-Folge: Seiten-Titel/-Untertitel, die NICHT in einer Card/Surface/Alert sitzen, stehen
   direkt auf dem Body-Hintergrundbild (wie ToDo/CRM). Auf hellen Bildbereichen wäre heller/grauer Text
   schlecht lesbar → dezenter Schatten + volle Vordergrundfarbe (statt text-muted). Greift NUR auf
   „nackte" Texte außerhalb von Cards (in Cards ist der Schatten dunkel-auf-dunkel = unsichtbar, daher
   ausgeschlossen). Die Nav steht außerhalb von .settings-content und bleibt unberührt. */
html.ds-page .settings-content :is(h1,h2,h3,h4,h5,h6,p,.lead):not(.card *):not(.ds-card *):not(.ds-surface *):not(.ds-shell *):not(.alert *):not(.modal *) {
    text-shadow: 0 1px 4px rgba(0,0,0,0.9), 0 0 3px rgba(0,0,0,0.7);
}
html.ds-page .settings-content :is(p,.lead,.text-muted):not(.card *):not(.ds-card *):not(.ds-surface *):not(.ds-shell *):not(.alert *):not(.modal *) {
    color: var(--ds-foreground);
}

/* ---------- Einstellungen: Kachel-Zeile, Abschnitts-Stapel, Speichern-Leiste (Umbau 10/2026) ----------
   Kachel-Zeile aus _Layout_Settings_Tailwind (erscheint, sobald der SettingsNav-Eintrag eine
   Description hat). Die Kachel „Einstellungen" öffnet die Seitenleiste als Flyout und gibt es nur
   unter 992 px — darüber steht die Leiste ohnehin links. Bleibt am Desktop sonst nichts in der Zeile
   (Seite ohne Aktionen, kein Hilfe-Video), fällt die ganze Zeile weg statt eine Lücke zu lassen. */
/* Suchfeld in der Kachel-Zeile (Benutzer, Gruppen, Rechte …): darf schrumpfen. Das Inline-min-width von
   200 px schob die Zeile am Handy über den Rand und drängte die Kachel „Einstellungen" ins „Mehr"-Menü. */
.settings-toolbar .ds-toolbar-row > div:has(> input[type="search"]) { flex: 1 1 8rem; min-width: 6rem; }
.settings-toolbar .ds-toolbar-row input[type="search"] { min-width: 0 !important; width: 100%; }

/* Schiebt eine Kachel der Seite schon nach rechts (align="right", Suchfeld mit tw-ml-auto), entfällt der
   Trenner vor „Hilfe" — zwei margin-auto/flex-Lücken teilten sich sonst den Platz (Karten in der Mitte). */
.settings-toolbar .ds-toolbar-row > .tw-ml-auto ~ .ds-toolbar-spacer { display: none; }

@media (min-width: 992px) {
    .settings-toolbar #settingsNavKachel { display: none; }
    .settings-toolbar:not(:has(.ds-toolbar-row > :not(#settingsNavKachel):not(.ds-toolbar-spacer))) { display: none; }
}


.settings-stack { display: flex; flex-direction: column; gap: 0.75rem; }
.settings-stack > .ds-surface + .ds-surface { margin-top: 0; }

/* Karten der Übersichtsseiten (EinstellungenController): die ganze Karte ist der Link. Vier Klassen,
   weil `.ds-main a:not([class*="ds-btn"]):not([class*="ds-chip"])` (0,3,1) sie sonst blau färbt. */
.ds-main .settings-content .ds-card-grid > a.settings-link-card { color: var(--ds-foreground); text-decoration: none; }
/* Graue Zeile in Kacheln fester Höhe: höchstens zwei Zeilen, dann „…" — die Höhe ist das Versprechen. */
.settings-content .settings-zeile-2 {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
/* Kopf der Übersichtskarte etwas flacher, damit zwei graue Zeilen sauber in die Kontakt-Kartenhöhe passen. */
.settings-link-card > .ds-entity-head { padding-top: 0.7rem; padding-bottom: 0.6rem; }
.settings-link-card .settings-link-card-pfeil { flex: 0 0 auto; color: var(--ds-muted-foreground); font-size: 0.875rem; }

/* Suche in den Einstellungen (settings-suche.js, plans/79): groß auf der Startseite, klein oben in der Leiste
   (Trefferliste schiebt dort die Bereiche nach unten — schwebend würde die scrollende Leiste sie abschneiden).
   Selektoren mit .ds-main/Attribut, weil `.ds-main div` und `.ds-main a:not(…)` (0,3,1) Farben sonst
   überschreiben; Wege als <small> statt <span> aus demselben Grund. */
.settings-nav-suche { padding: 0 0.25rem 0.75rem; }
.settings-nav-suche .ds-search-field { min-width: 0; }
.settings-nav-suche .settings-suche-treffer {
    margin-top: 0.4rem; padding: 0.3rem;
    background: var(--ds-popover); border: 1px solid var(--ds-border); border-radius: 0.7rem;
}
.settings-start-suche .ds-search-field { flex: none; max-width: 40rem; }
.settings-start-suche .ds-search-field > input { height: 2.75rem; font-size: 1rem; }
.settings-start-suche .settings-suche-treffer { margin-top: 0.75rem; max-width: 40rem; }
.settings-suche-treffer[hidden] { display: none !important; }
.ds-main .settings-suche-gruppe {
    padding: 0.55rem 0.6rem 0.2rem; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em;
    text-transform: uppercase; color: var(--ds-muted-foreground);
}
.settings-treffer {
    display: flex; align-items: flex-start; gap: 0.65rem; width: 100%; padding: 0.45rem 0.6rem;
    border: 0; border-radius: 0.5rem; background: none; text-align: left; cursor: pointer;
}
.ds-main [data-settings-suche-liste] a.settings-treffer,
.ds-main [data-settings-suche-liste] button.settings-treffer { color: var(--ds-foreground); text-decoration: none; }
.settings-treffer:hover, .settings-treffer.is-active { background: var(--ds-accent); }
.settings-treffer > i { margin-top: 0.1rem; color: var(--ds-primary); }
.settings-treffer-text { display: flex; flex-direction: column; min-width: 0; }
.settings-treffer-titel { font-size: 0.875rem; font-weight: 500; }
.settings-treffer-weg { font-size: 0.75rem; line-height: 1.35; color: var(--ds-muted-foreground); }
.ds-main .settings-suche-leer { padding: 0.5rem 0.6rem; font-size: 0.85rem; color: var(--ds-muted-foreground); }
.settings-suche-ki { padding: 0.45rem 0.6rem 0.3rem; }
.settings-ki-antwort p { margin: 0 0 0.6rem !important; font-size: 0.875rem; line-height: 1.5; }
.settings-ki-link { margin: 0.15rem 0.3rem 0.15rem 0; }
.ds-main .settings-ki-laedt, .ds-main .settings-ki-fehler { font-size: 0.85rem; color: var(--ds-muted-foreground); }
/* Sprungziel aus der Suche (#finde=…): kurz einrahmen, dann ausblenden. */
.settings-finde { border-radius: 0.6rem; animation: settings-finde 2.4s ease-out; }
@keyframes settings-finde {
    0%, 45% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-primary) 55%, transparent);
              background-color: color-mix(in srgb, var(--ds-primary) 9%, transparent); }
    100% { box-shadow: 0 0 0 3px transparent; background-color: transparent; }
}
@media (prefers-reduced-motion: reduce) {
    .settings-finde { animation: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-primary) 55%, transparent); }
}

/* Karten auf Einstellungsseiten heben sich ab wie die Kontakt-Karten (crm.css .crm-card): leichter Schatten,
   weicherer Rand — weiß auf #fafafa allein hatte kaum Kontrast (max, 30.10.2026). */
.settings-content .ds-card-grid > .ds-card,
.settings-zeile {
    border-color: color-mix(in srgb, var(--ds-border) 85%, transparent);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 8px -2px rgba(0, 0, 0, 0.06);
}

/* Einstellungs-Liste (Benutzer …): eine Karten-Zeile je Eintrag wie Arc unter Ansicht › Liste. Kopf in EINER
   Zeile mit fester Höhe (Name, Zustand, Kennzahlen, Aktionen), Einzelheiten klappen darunter auf. */
.settings-liste { display: flex; flex-direction: column; gap: var(--ds-card-gap); }
.settings-zeile { background: var(--ds-card); border-width: 1px; border-style: solid; border-radius: var(--ds-card-radius); }
.settings-zeile-kopf {
    display: grid;
    grid-template-columns: auto minmax(11rem, 1.2fr) minmax(0, 1.3fr) minmax(0, 1fr) 6.5rem minmax(0, 1fr) auto;
    align-items: center; gap: 0.75rem;
    min-height: 3.5rem; padding: 0.45rem 0.75rem;
}
.settings-zeile-person { min-width: 0; }
/* Verknüpfter Kontakt unter der E-Mail (Benutzer-Liste). Selektor mit .ds-main, weil
   `.ds-main a:not(...)` (0,3,1) Links sonst umfärbt. */
.ds-main .settings-zeile-person .settings-zeile-kontakt {
    display: flex; align-items: center; gap: 0.3rem; max-width: 100%; margin-top: 0.1rem;
    font-size: 0.75rem; overflow: hidden; white-space: nowrap;
}
.ds-main .settings-zeile-person a.settings-zeile-kontakt { color: var(--ds-primary); text-decoration: none; }
.ds-main .settings-zeile-person .settings-zeile-kontakt > span { overflow: hidden; text-overflow: ellipsis; }
.ds-main .settings-zeile-person a.settings-zeile-kontakt:hover > span { text-decoration: underline; }
.ds-main .settings-zeile-person .settings-zeile-kontakt.is-leer { color: var(--ds-muted-foreground); }
.settings-zeile .settings-zeile-name { font-size: 0.875rem; font-weight: 600; color: var(--ds-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.settings-zeile .settings-zeile-sub { font-size: 0.75rem; color: var(--ds-muted-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.settings-zeile-status { display: flex; gap: 0.3rem; min-width: 0; overflow: hidden; }
.settings-zeile-status > * { flex: 0 0 auto; }
/* Tags der Benutzer-Liste: brechen um statt abgeschnitten zu werden — sie sollen vollständig zu sehen sein. */
.settings-zeile-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; min-width: 0; }
.settings-zeile .settings-zeile-info {
    display: flex; align-items: center; gap: 0.35rem; min-width: 0;
    font-size: 0.8rem; color: var(--ds-muted-foreground);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.settings-zeile-aktionen { display: flex; align-items: center; gap: 0.35rem; }
/* Menüeinträge einzeilig — „Sperren & übergeben" brach sonst um. */
.settings-zeile .dropdown-menu .ds-dropdown-item { white-space: nowrap; }
.settings-zeile-details {
    display: flex; flex-direction: column; gap: 0.75rem;
    padding: 0.25rem 0.75rem 0.85rem calc(0.75rem + 36px + 0.75rem);
}
@media (max-width: 991.98px) {
    /* Schmal: Name + Aktionen oben, Zustand darunter; Kennzahlen stehen in den Details. */
    .settings-zeile-kopf { grid-template-columns: auto minmax(0, 1fr) auto; row-gap: 0.4rem; }
    .settings-zeile-status { grid-column: 2 / -1; grid-row: 2; flex-wrap: wrap; }
    .settings-zeile-tags { grid-column: 2 / -1; grid-row: 3; }
    .settings-zeile-tags.is-leer { display: none; }
    .settings-zeile .settings-zeile-info { display: none; }
    .settings-zeile-details { padding-left: 0.75rem; }
}
@media (max-width: 575.98px) {
    /* Handy: der Name bekommt die ganze erste Zeile, Details/Aktionen rücken neben den Zustand. */
    .settings-zeile-person { grid-column: 2 / -1; grid-row: 1; }
    .settings-zeile-status { grid-column: 2 / -1; grid-row: 2; }
    .settings-zeile-kopf > .settings-zeile-aktionen { grid-column: 2 / -1; grid-row: 4; justify-self: end; }
    .settings-zeile-kopf:has(> .settings-zeile-tags.is-leer) > .settings-zeile-aktionen { grid-row: 3; }
    .settings-zeile-kopf > :first-child { grid-row: 1 / span 4; align-self: start; }
}

/* Kachel „Speichern" (settings-speichern.js), solange Änderungen ungespeichert sind: grün gefüllt mit Ring, pulsiert
   beim Umschalten kurz — und die Kachel-Zeile bleibt beim Scrollen oben stehen. Vorher nur ein kleiner Punkt; max
   01.11.2026: „nicht eindeutig, dass gespeichert werden muss". Padding + negativer Rand gleichen sich aus, damit
   beim Umschalten nichts springt; das Icon trägt seine Farbe inline (TagHelper) → !important. */
.settings-toolbar [data-settings-save] { position: relative; }
/* sticky hängt am nächsten Vorfahren mit overflow ≠ visible: body hat global overflow:auto, scrollt aber nie (das tut
   <html>) — die Zeile stünde damit still. Nur hier freigeben; ds-shell-Seiten (Touch-Scroll-Fix) bleiben unberührt. */
html.ds-page body:has(.settings-toolbar [data-settings-save]):not(:has(.ds-shell)) { overflow: visible; }
.settings-toolbar:has([data-settings-save].settings-ungespeichert) {
    position: sticky; top: 0; z-index: 30;
    padding: 0.5rem; margin: -0.5rem;
    /* Milchglas statt Vollfläche: hinter den Einstellungen liegt meist das Hintergrundbild. */
    background: color-mix(in srgb, var(--ds-background) 72%, transparent);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
    border-radius: 0 0 var(--ds-card-radius, 0.75rem) var(--ds-card-radius, 0.75rem);
}
.ds-main .settings-toolbar [data-settings-save].settings-ungespeichert {
    background: var(--ds-success); border-color: var(--ds-success);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-success) 30%, transparent);
    animation: settings-speichern-puls 1.1s ease-out 2;
}
.ds-main .settings-toolbar [data-settings-save].settings-ungespeichert > i,
.ds-main .settings-toolbar [data-settings-save].settings-ungespeichert > span { color: var(--ds-success-foreground) !important; }
@keyframes settings-speichern-puls {
    0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--ds-success) 60%, transparent); }
    100% { box-shadow: 0 0 0 12px transparent; }
}
@media (prefers-reduced-motion: reduce) {
    .ds-main .settings-toolbar [data-settings-save].settings-ungespeichert { animation: none; }
}

.settings-toolbar [data-settings-save].settings-sendet { opacity: 0.6; pointer-events: none; }

/* Feldbeschriftungen in Einstellungs-Karten wie die Zeilen-Bezeichnung (.ds-setting-label) — sonst
   standen Filter-Felder (ds-form-field) in 16 px neben 14-px-Zeilen. Nur in Surfaces, Modale bleiben. */
.settings-content .ds-surface .form-label { font-size: 0.875rem; font-weight: 600; color: var(--ds-foreground); }
.settings-content .ds-surface .form-check-label { font-size: 0.875rem; }

@media (max-width: 991.98px) {
    /* align-items:stretch: in der Spalte nimmt der Inhalt sonst nur seine Inhaltsbreite (align-items
       flex-start aus der Desktop-Zeile) — zwischen 768 und 991 px stand alles linksbündig mit Lücke rechts. */
    .settings-shell { flex-direction: column; padding: 0; gap: 0; align-items: stretch; }
    .settings-nav-link { min-height: 44px; }
}

/* ---------- Mobile: schmalere Ränder für ALLE Tailwind-Views (GLOBAL & EINHEITLICH) ----------
   Auf ~375px-Handys frisst der Desktop-Rand (2.5rem bzw. 1.25rem) + der Bootstrap-Container-Gutter
   zu viel Breite. Lösung an EINER Stelle:
   (1) Token --ds-content-pad-x global auf 0.25rem zwingen. Das !important auf dem CUSTOM PROPERTY
       schlägt die 1.25rem-Umsetzung der :has()-Neutralizer (ToDo/CRM/TeamTime) — die müssen daher
       KEINE eigene Mobile-Regel mehr haben. (UC_Email/Auth nutzen padding:0 !important direkt und
       bleiben bewusst randlos — der Token greift dort nicht.)
   (2) Redundanten Bootstrap-Container-Gutter modulübergreifend entfernen (sonst doppelter Rand:
       .ds-content + .container/.container-fluid). Element bleibt erhalten (Zentrierung/AJAX intakt).
   WICHTIG: padding-bottom (140px) bleibt UNANGETASTET — load-bearing für scrollIntoView. */
@media (max-width: 575.98px) {
    /* Item-Karten modulübergreifend zentral verdichten: ToDo/CRM/TeamTime ziehen alle auf
       --ds-card-pad-compact, daher reicht EINE Stelle für die Mobile-Dichte aller Inhalts-Karten.
       (Behebt, dass CRM zuvor am Handy auf vollem Desktop-Padding stehen blieb.) */
    :root { --ds-card-pad-compact: 0.5rem 0.55rem; }
    .ds-main .ds-content {
        --ds-content-pad-x: 0.25rem !important;
        padding-top: 1.25rem;
    }
    .ds-main .container,
    .ds-main .container-fluid {
        padding-left: 0 !important;
        padding-right: 0 !important;
    }
}

/* ---------- Header ---------- */
.ds-header { margin-bottom: 1.5rem; }

.ds-title {
    font-size: 2.25rem !important;
    font-weight: 800 !important;
    letter-spacing: -0.04em;
    line-height: 1.1 !important;
    background: linear-gradient(135deg, var(--ds-accent-1) 0%, var(--ds-accent-2) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

html.dark .ds-title,
html:not(.light) .ds-title {
    /* Dark gradient handled via media query below */
}

@media (prefers-color-scheme: dark) {
    html:not(.light) .ds-title {
        background: linear-gradient(135deg, var(--ds-accent-1) 0%, var(--ds-accent-2) 100%);
        -webkit-background-clip: text;
        background-clip: text;
    }
}

html.dark .ds-title {
    background: linear-gradient(135deg, var(--ds-accent-1) 0%, var(--ds-accent-2) 100%);
    -webkit-background-clip: text;
    background-clip: text;
}

.ds-subtitle {
    font-size: 1.0625rem !important;
    color: var(--ds-muted-foreground) !important;
    margin-top: 0.5rem !important;
    line-height: 1.625;
}

.ds-separator {
    display: none;
}

/* ---------- Sections ---------- */
.ds-section {
    margin-bottom: 2rem;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 1.4);
    padding: 1.75rem;
    position: relative;
    /* KEIN overflow:hidden — sonst werden Dropdowns abgeschnitten */
}

/* Kein linker Streifen — clean wie shadcn */

.ds-section-title {
    font-size: 1.25rem !important;
    font-weight: 700 !important;
    letter-spacing: -0.025em;
    margin-bottom: 0.25rem !important;
    color: var(--ds-accent-1) !important;
}

.ds-section-description {
    font-size: 0.9375rem;
    color: var(--ds-muted-foreground);
    margin-bottom: 1.25rem;
}

/* ---------- Cards ---------- */
/* ---------- Cards ---------- */
.ds-card {
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 1.4);
    margin-bottom: 1.5rem;
    padding: 1.5rem;
    overflow: hidden;
}
/* Liegt die Karte DIREKT auf dem Seitenhintergrund (oberste Ebene des Moduls, z. B. Hilfe, Lernen),
   bekommt sie den Flächen-Schatten wie Shells und Panels. Karten in Karten bleiben flach. */
.ds-module > .ds-card { box-shadow: var(--ds-surface-shadow); }
/* Migrationsrest: `<div class="ds-card"><div class="card-body">` — beide bringen Padding mit
   (1.5rem + Bootstraps --bs-card-spacer), die Karte wird dadurch sichtbar zu luftig. Projektweit
   44 Stellen (Stand 25.07.2026). Statt 44× das DOM umzubauen (Risiko unbalancierter divs) nimmt
   diese Regel dem inneren card-body das Padding — ds-card bleibt die alleinige Quelle.
   Kein Bootstrap-Patch: die Regel ist an .ds-card gebunden und greift nur in diesem Kontext. */
.ds-card > .card-body {
    padding: 0;
}
.ds-card-header {
    padding: 1.25rem 1.5rem;
    border-bottom: 1px solid var(--ds-border);
}
.ds-card-title {
    font-size: 1rem !important;
    font-weight: 600 !important;
    color: var(--ds-foreground) !important;
    margin: 0;
}
.ds-card-description {
    font-size: 0.8125rem !important;
    color: var(--ds-muted-foreground) !important;
    margin-top: 0.25rem !important;
}
.ds-card-body { padding: 1.5rem; }
.ds-card-footer {
    padding: 0.75rem 1.5rem;
    border-top: 1px solid var(--ds-border);
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Card ohne Padding (header/body/footer übernehmen) */
.ds-card-structured { padding: 0; }

/* Interaktive Card — hover lift */
.ds-card-interactive {
    cursor: pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.ds-card-interactive:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(0,0,0,.08);
}

/* ============================================================
   AUTH CARD — Login/Unlock/Setup Hero Card
   Verwendet die CI-Farben (--ds-accent-1 / --ds-accent-2).
   Neutralisiert automatisch das umgebende .ds-content wenn ein
   .ds-auth-wrapper darin liegt, so dass die Karte als Hero-Element
   frei auf dem Hintergrund zu schweben scheint.
   ============================================================ */
.ds-main .ds-content:has(.ds-auth-wrapper) {
    background: transparent !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    padding: 0 !important;
}
html.dark .ds-main .ds-content:has(.ds-auth-wrapper),
html:not(.light) .ds-main .ds-content:has(.ds-auth-wrapper) {
    background: transparent !important;
    box-shadow: none !important;
}

.ds-auth-wrapper {
    min-height: calc(100vh - 160px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
    position: relative;
    overflow: hidden;
}

/* Demo-Variante für Baukasten: eigener Hintergrund, keine Content-Neutralisierung */
.ds-auth-demo-wrapper {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3rem 1.5rem;
    min-height: 30rem;
    border-radius: 1rem;
    background: color-mix(in srgb, var(--ds-muted) 35%, var(--ds-background));
    overflow: hidden;
}
.ds-auth-demo-wrapper::before {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse 60% 50% at 50% 0%, color-mix(in srgb, var(--ds-accent-1) 14%, transparent) 0%, transparent 70%),
        radial-gradient(ellipse 50% 40% at 80% 100%, color-mix(in srgb, var(--ds-accent-2, var(--ds-accent-1)) 10%, transparent) 0%, transparent 70%);
    pointer-events: none;
    z-index: 0;
}

/* Softer, nur angedeuteter Farbverlauf hinter der Karte */
.ds-auth-wrapper::before {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse 60% 50% at 50% 0%, color-mix(in srgb, var(--ds-accent-1) 14%, transparent) 0%, transparent 70%),
        radial-gradient(ellipse 50% 40% at 80% 100%, color-mix(in srgb, var(--ds-accent-2, var(--ds-accent-1)) 10%, transparent) 0%, transparent 70%);
    pointer-events: none;
    z-index: 0;
}

.ds-auth-card {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 26rem;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 1.5rem;
    padding: 2.75rem 2.25rem 2.25rem;
    box-shadow:
        0 30px 60px -15px rgba(0, 0, 0, 0.22),
        0 10px 20px -10px rgba(0, 0, 0, 0.12),
        0 0 0 1px rgba(255, 255, 255, 0.04) inset;
    overflow: hidden;
}

/* Dezenter Accent-Streifen oben */
.ds-auth-card::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: linear-gradient(90deg,
        var(--ds-accent-1) 0%,
        var(--ds-accent-2, var(--ds-accent-1)) 100%);
    opacity: 0.9;
}

html.dark .ds-auth-card,
html:not(.light) .ds-auth-card {
    box-shadow:
        0 30px 60px -15px rgba(0, 0, 0, 0.5),
        0 10px 20px -10px rgba(0, 0, 0, 0.35),
        0 0 0 1px rgba(255, 255, 255, 0.05) inset;
}

.ds-auth-hero {
    text-align: center;
    margin-bottom: 1.75rem;
}

.ds-auth-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 4.5rem;
    height: 4.5rem;
    border-radius: 1.25rem;
    background: linear-gradient(135deg,
        var(--ds-accent-1) 0%,
        var(--ds-accent-2, var(--ds-accent-1)) 100%);
    color: #fff;
    font-size: 1.9rem;
    line-height: 1;
    margin-bottom: 1.125rem;
    box-shadow:
        0 12px 28px -8px color-mix(in srgb, var(--ds-accent-1) 55%, transparent),
        0 0 0 1px rgba(255, 255, 255, 0.15) inset,
        0 1px 0 rgba(255, 255, 255, 0.25) inset;
    transform: translateZ(0);
}

.ds-auth-icon i {
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.15));
}

.ds-auth-title {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0 0 0.375rem;
    color: var(--ds-foreground);
    line-height: 1.2;
}

.ds-auth-subtitle {
    font-size: 0.9rem;
    color: var(--ds-muted-foreground);
    margin: 0;
    line-height: 1.55;
}

.ds-auth-body {
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
}

.ds-auth-footer {
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--ds-border);
    text-align: center;
}

/* Mobile */
@media (max-width: 480px) {
    .ds-auth-wrapper { padding: 1rem 0.75rem; min-height: calc(100vh - 140px); }
    .ds-auth-card { padding: 2rem 1.5rem 1.75rem; border-radius: 1.25rem; }
    .ds-auth-icon { width: 4rem; height: 4rem; font-size: 1.75rem; }
    .ds-auth-title { font-size: 1.3rem; }
}

/* Profile Card — farbiger Header */
.ds-card-profile-header {
    padding: 1.25rem;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    position: relative;
}
.ds-card-profile-header.ds-profile-blue { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); color: #fff; }
.ds-card-profile-header.ds-profile-green { background: linear-gradient(135deg, #5a8a7a 0%, #3d6b5e 100%); color: #fff; }
.ds-card-profile-header.ds-profile-slate { background: linear-gradient(135deg, #5a7a8a 0%, #4a6478 100%); color: #fff; }
.ds-card-profile-header.ds-profile-purple { background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%); color: #fff; }
.ds-card-avatar {
    width: 44px; height: 44px; min-width: 44px;
    border-radius: 0.5rem;
    display: flex; align-items: center; justify-content: center;
    font-weight: 600; font-size: 0.875rem;
    background: rgba(255,255,255,0.2);
    border: 2px solid rgba(255,255,255,0.8);
    overflow: hidden;
}
.ds-card-avatar img { width: 100%; height: 100%; object-fit: cover; }
.ds-card-avatar i { font-size: 1.25rem; color: #fff; }
/* Im farbigen Profile-Header IMMER weißer Text/Buttons (hell UND dunkel) — sonst überschreibt
   .ds-card-title{color:foreground} den weißen Header-Text und er wird auf dem Verlauf unleserlich. */
.ds-card-profile-header .ds-card-title { color: #fff !important; }
.ds-card-profile-header .ds-card-description { color: rgba(255,255,255,0.85) !important; }
.ds-card-profile-header .btn {
    color: #fff;
    border: none;
    background: rgba(255,255,255,0.18);
    padding: 0.25rem 0.5rem;
    line-height: 1;
}
.ds-card-profile-header .btn:hover,
.ds-card-profile-header .btn:focus { color: #fff; background: rgba(255,255,255,0.32); }
.ds-card-profile-header .dropdown-menu { color: var(--ds-card-foreground); }
/* Profil-Foto / Platzhalter im farbigen Header (Benutzer-Karten via GetUserImageHtml). */
.ds-card-profile-header img { border: 2px solid rgba(255,255,255,0.85); flex: 0 0 auto; }
.ds-card-profile-header .user-icon-placeholder {
    border-radius: 50%;
    background: rgba(255,255,255,0.2);
    border: 2px solid rgba(255,255,255,0.85);
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.25rem; flex: 0 0 auto;
}
/* In ds-card-grid/-list regelt der Grid-Gap den Abstand → Default-margin der ds-card raus. */
.ds-card-grid > .ds-card,
.ds-card-list > .ds-card { margin-bottom: 0; }

/* Compact Card — für Kanban/Grid */
.ds-card-compact {
    padding: 0.875rem;
    margin-bottom: 0.5rem;
}
.ds-card-compact .ds-card-title { font-size: 0.875rem !important; }

/* Card Badge */
.ds-card-badge {
    display: inline-flex;
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 500;
    line-height: 1.4;
}

/* Card Action Bar — bewusst OHNE Trennlinie darüber (Max, 26.09.2026: „keine Trennlinien mehr"). */
.ds-card-actions {
    display: flex;
    gap: 0.25rem;
    padding: 0.625rem 0.875rem;
}
.ds-card-actions .ds-btn { flex: 1; justify-content: center; font-size: 0.75rem; height: 1.875rem; }

/* ============================================================
   Entity-Card (Benutzer / Rechte / Gruppen u.ä.)
   Item-Karte im Baukasten-Stil wie Kontakte/ToDo: getöntes
   Kreis-Icon im Kopf, Titel/Meta, getönte ds-card-badge-Pills,
   optionale ds-card-actions. KEIN vollflächiger Farbverlauf-Header.
   Tönungen kommen aus den vorhandenen ds-tint- / ds-fg- Utilities.
   ============================================================ */
.ds-card-icon {
    width: 2.5rem; height: 2.5rem; min-width: 2.5rem;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.05rem; overflow: hidden; flex: 0 0 auto;
}
.ds-card-icon img { width: 100%; height: 100%; object-fit: cover; }
.ds-entity-head { display: flex; align-items: center; gap: 0.75rem; padding: 0.875rem 0.875rem 0.625rem; }
.ds-entity-title { font-size: 0.875rem; font-weight: 600; color: var(--ds-foreground); line-height: 1.25; }
.ds-entity-sub { font-size: 0.75rem; color: var(--ds-muted-foreground); }
.ds-entity-body { padding: 0 0.875rem 0.875rem; display: flex; flex-direction: column; gap: 0.75rem; }
.ds-entity-section-label {
    font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em;
    color: var(--ds-muted-foreground); margin-bottom: 0.375rem;
    display: flex; align-items: center; gap: 0.3rem;
}
.ds-entity-badges { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.ds-card-badge i { font-size: 0.75rem; }
/* X-Button in einer entfernbaren Badge (erbt die Badge-Textfarbe) */
.ds-card-badge .ds-badge-x {
    background: none; border: 0; color: inherit; padding: 0; margin-left: 0.125rem;
    line-height: 1; display: inline-flex; align-items: center; opacity: 0.65; cursor: pointer;
}
.ds-card-badge .ds-badge-x:hover { opacity: 1; }
/* Benutzer-Avatar im Karten-Kopf (img ODER Platzhalter-Div aus GetUserImageHtml) */
.settings-user-avatar { border-radius: 50% !important; object-fit: cover; flex: 0 0 auto; }
div.settings-user-avatar {
    background: color-mix(in srgb, var(--ds-primary) 14%, var(--ds-background));
    color: var(--ds-primary);
    display: flex; align-items: center; justify-content: center; font-size: 1.1rem;
}

/* Rechte-Chips: das führende Icon jedes Rechte-Chips in einen getönten Kreis setzen
   (nur im RECHTE-Abschnitt via .ds-entity-badges-roles — nicht Status/Tags/Gruppen).
   Tönung = currentColor des Chips (ds-fg-*); der X-Button steckt in einem <button> und
   ist daher kein direktes > i, bleibt also unberührt. */
.ds-entity-badges-roles .ds-card-badge > i.bi:first-child {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.15rem; height: 1.15rem; min-width: 1.15rem;
    border-radius: 50%;
    background: color-mix(in srgb, currentColor 20%, transparent);
    font-size: 0.625rem;
}

/* Settings-Karten: einheitliche Höhe + Innen-Scroll, damit das Raster ruhig bleibt, obwohl die
   Inhalte stark variieren (eine Rolle kann hunderte Mitglieder haben). Kopf bleibt fix, der Body
   scrollt bei langen Rechte-/Mitglieder-Listen. Nur Item-Cards im Grid — der Leerzustand
   (.ds-empty) steht außerhalb des Grids und bleibt unangetastet. */
.settings-content .ds-card-grid > .ds-card-structured {
    height: 16rem;
    display: flex;
    flex-direction: column;
}
/* Kompakte Item-Karten (Typ-Listen wie Adresstypen): ohne die feste Höhe — dort steht nur Name,
   Abbildung und Aktionen, 16rem wären fast leere Kacheln. Gleich hoch bleiben sie über die Grid-Zeile. */
.settings-content .ds-card-grid.settings-grid-kompakt > .ds-card-structured { height: auto; }
.settings-content .ds-card-grid > .ds-card-structured > .ds-entity-head { flex: 0 0 auto; }
.settings-content .ds-card-grid > .ds-card-structured > .ds-entity-body {
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
    scrollbar-width: thin; scrollbar-color: var(--ds-border) transparent;
}
.settings-content .ds-card-grid > .ds-card-structured > .ds-entity-body::-webkit-scrollbar { width: 6px; }
.settings-content .ds-card-grid > .ds-card-structured > .ds-entity-body::-webkit-scrollbar-thumb {
    background: var(--ds-border); border-radius: 999px;
}

/* Settings-Karten-Aktionsmenü im Baukasten-Dropdown-Look (wie das ds-toolbar-dropdown-Menü):
   opakes Card-Panel + Items als gerundete Pills mit Accent-Hover. Pures Scoped-CSS, damit die
   bestehenden Bootstrap-Dropdowns (data-bs-toggle/dropdown-item + JS-Verdrahtung) unangetastet
   bleiben. `html.ds-page`-Präfix ist nötig, um den generischen grauen `html.ds-page
   .dropdown-item:hover` zu überstimmen. Farben = dieselben Tokens wie das echte .ds-dropdown-item
   (Hover und Active accent-1), Panel = --ds-card (von html.ds-page .dropdown-menu geerbt). */
html.ds-page .settings-content .ds-card .dropdown-menu {
    border-radius: 0.6rem;
    padding: 0.25rem;
    min-width: 12rem;
    margin-top: 0.35rem;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .35), 0 0 0 1px rgba(255, 255, 255, .03);
}
html.ds-page .settings-content .ds-card .dropdown-item {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.4rem 0.6rem;
    margin: 0.05rem 0;
    font-size: 0.8125rem;
    border-radius: 0.4rem;
    transition: background-color .12s, color .12s;
}
html.ds-page .settings-content .ds-card .dropdown-item.text-danger:hover,
html.ds-page .settings-content .ds-card .dropdown-item.text-danger:focus {
    background: color-mix(in srgb, var(--ds-destructive) 15%, transparent);
}
html.ds-page .settings-content .ds-card .dropdown-divider {
    border-color: var(--ds-border); margin: 0.25rem 0;
}

/* ---------- Typography ---------- */
.ds-text {
    font-size: 0.9375rem !important;
    color: var(--ds-muted-foreground) !important;
    line-height: 1.625;
}

.ds-list {
    list-style: none;
    padding: 0 !important;
    margin: 0.5rem 0 0 0 !important;
}

.ds-list li {
    font-size: 0.9375rem;
    color: var(--ds-muted-foreground);
    padding: 0.1875rem 0 0.1875rem 1.25rem;
    position: relative;
}

.ds-list li::before {
    content: "•";
    position: absolute;
    left: 0.25rem;
}

/* ---------- Badges ---------- */
.ds-badge-row { display: flex; flex-wrap: wrap; gap: 0.375rem; }

.ds-badge {
    display: inline-flex;
    align-items: center;
    border-radius: 9999px;
    padding: 0.125rem 0.625rem;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.5;
}

.ds-badge-primary { background: var(--ds-primary); color: var(--ds-primary-foreground); }
.ds-badge-secondary { background: var(--ds-secondary); color: var(--ds-secondary-foreground); border: 1px solid var(--ds-border); }
.ds-badge-success { background: var(--ds-success); color: var(--ds-success-foreground); }
.ds-badge-accent { background: var(--ds-accent); color: var(--ds-accent-foreground); border: 1px solid var(--ds-border); }
/* Fehlerzaehler o.ae. — die Reihe hatte bisher keine Warnfarbe, sodass "3 Fehler"
   optisch genauso ruhig wirkte wie "3 neu". */
.ds-badge-destructive { background: var(--ds-destructive); color: var(--ds-destructive-foreground); }

/* ---------- Code ---------- */
.ds-code {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    background: var(--ds-muted);
    color: var(--ds-foreground);
    padding: 0.2rem 0.4rem;
    border-radius: calc(var(--ds-radius) * 0.6);
}

.ds-code-inline {
    font-size: 0.875rem;
    color: var(--ds-muted-foreground);
    margin-top: 0.5rem;
}

/* ---------- Checklist ---------- */
.ds-checklist {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(175px, 1fr));
    gap: 0.125rem;
}

.ds-check-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: var(--ds-muted-foreground);
    padding: 0.25rem 0;
}

.ds-check-item i { font-size: 0.5rem; opacity: 0.4; }
.ds-check-item.done i { color: var(--ds-success); opacity: 1; }

/* ---------- Example (Preview/Code Tabs) ---------- */
.ds-example {
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius));
    margin-top: 1rem;
    background: var(--ds-background);
}

.ds-example-tabs {
    display: flex;
    border-bottom: 1px solid var(--ds-border);
    background: var(--ds-surface);
}

.ds-example-tab {
    padding: 0.625rem 1rem;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--ds-muted-foreground);
    cursor: pointer;
    border: none;
    background: none;
    font-family: inherit;
    position: relative;
    transition: color 0.1s ease;
}

.ds-example-tab:hover { color: var(--ds-foreground); }

.ds-example-tab.active {
    color: #ffffff;
    background: var(--ds-accent-1);
    border-radius: calc(var(--ds-radius) * 0.6);
    margin: 0.25rem;
}

.ds-example-tab.active::after { display: none; }

.ds-example-preview {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 3rem 2rem;
    min-height: 120px;
    background-color: var(--ds-background);
    background-image: radial-gradient(circle, var(--ds-border) 1px, transparent 1px);
    background-size: 24px 24px;
}

.ds-example-code { display: none; }
.ds-example-code.active { display: block; }

.ds-example-code pre {
    margin: 0 !important;
    padding: 1.25rem 1.5rem !important;
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace !important;
    font-size: 0.8125rem !important;
    line-height: 1.7 !important;
    overflow-x: auto;
    background: var(--ds-surface) !important;
    color: var(--ds-muted-foreground) !important;
    border-radius: 0 !important;
}

/* ═══ MENÜEINTRÄGE: EIN Hover-/Aktiv-Zustand für ALLE Dropdowns (max, 03.11.2026) ═══
   Gilt für Baukasten-Menüs (.ds-dropdown-item: ds-toolbar-dropdown, ds-select, Zeilenmenüs) UND
   Bootstrap-Menüs (.dropdown-item). Vorher gab es fünf Varianten (grau 8 %, Akzent 15 % mit/ohne
   Akzent-Text) — und der Text blieb oft schwarz, weil Einträge ihre Farbe inline mitbringen
   (style="color: var(--ds-foreground)", TagHelper + ToDo „Ansicht"). Daher !important.
   Hover und Tastatur-Markierung (ds-select .is-active) sehen gleich aus; aktiv = kräftiger + halbfett.
   Farbige Einträge (Löschen rot, Leitfarben-Varianten) behalten Farbe und eigenen Hover.

   --ds-accent-1-text: Die Leitfarbe der Konsole kann dunkel sein (z. B. Dunkelblau) — auf dem dunklen
   Menü wäre sie unlesbar und die Tönung unsichtbar. Im Dunkelmodus deshalb zu Weiß hin aufgehellt. */
:root { --ds-accent-1-text: var(--ds-accent-1); --ds-menu-hover: 14%; --ds-menu-active: 22%; }
html.dark { --ds-accent-1-text: color-mix(in srgb, var(--ds-accent-1) 45%, white); --ds-menu-hover: 18%; --ds-menu-active: 26%; }
@media (prefers-color-scheme: dark) {
    html:not(.light) { --ds-accent-1-text: color-mix(in srgb, var(--ds-accent-1) 45%, white); --ds-menu-hover: 18%; --ds-menu-active: 26%; }
}
:is(.ds-dropdown-item:is(:hover, :focus-visible, .is-active), .dropdown-item:is(:hover, :focus)):not(.is-destructive, .text-danger, .text-success, .text-warning, [style*="--ds-destructive"], [style*="--ds-success"], [style*="--ds-warning"]) {
    background: color-mix(in srgb, var(--ds-accent-1-text) var(--ds-menu-hover), transparent) !important;
    color: var(--ds-accent-1-text) !important;
}
:is(.ds-dropdown-item, .dropdown-item):is(.active, :active):not(.is-destructive, .text-danger, .text-success, .text-warning, [style*="--ds-destructive"], [style*="--ds-success"], [style*="--ds-warning"]) {
    background: color-mix(in srgb, var(--ds-accent-1-text) var(--ds-menu-active), transparent) !important;
    color: var(--ds-accent-1-text) !important;
    font-weight: 600;
}
/* Kinder ziehen mit (07.11.2026, max: „sicherstellen, dass der Hover überall funktioniert"): Beschriftungen
   in eigenem <span> (TagHelper `.ds-dropdown-item-label`, ds-select-Optionen, REC-Menüs) und Symbole behielten
   die Farbe des Normalizers `.ds-main span/div` (--ds-foreground) — Fläche getönt, Text blieb schwarz.
   Ausgenommen: Badges, Kennfarben (ds-fg-*, Inline-Farbe) und graue Zweitzeilen. */
:is(.ds-dropdown-item:is(:hover, :focus-visible, .is-active, .active), .dropdown-item:is(:hover, :focus, .active)):not(.is-destructive, .text-danger, .text-success, .text-warning, [style*="--ds-destructive"], [style*="--ds-success"], [style*="--ds-warning"])
    :is(span, div, i, small, strong, b, em, svg):not([class*="badge"], [class*="ds-fg-"], [style*="color"], .tw-text-muted-foreground, .text-muted, .text-body-secondary) {
    color: inherit !important;
}
/* Farbige Einträge ohne eigene Regel: dezente Tönung in ihrer eigenen Farbe. */
.ds-dropdown-item:hover { background: color-mix(in srgb, currentColor 12%, transparent); }

/* Luft im Menü (max, 03.11.2026: „kein Padding, sieht sehr gedrückt aus"): Das Menü bekommt ringsum
   Innenabstand, die Einträge sind 36px hoch und tragen ihre Hover-Fläche als abgerundete Zeile mit
   Abstand zur Kante. Vorher: Menü links/rechts 0, Einträge 32px, in ToDo ohne Seitenabstand (die
   Hover-Fläche stieß an den Rand). Zeilenmenüs (.ds-row-menu-list) tragen seit 07.11.2026 dasselbe Maß selbst (ROW-MENÜ). */
.dropdown-menu:not(.ds-row-menu-list):has(:is(.ds-dropdown-item, .dropdown-item)) { padding: .375rem; }
.dropdown-menu:not(.ds-row-menu-list) :is(.ds-dropdown-item, .dropdown-item) {
    margin: 1px 0;
    padding: .5rem .75rem;
    border-radius: .45rem;
    white-space: nowrap;        /* einzeilig — das Menü wird lieber breiter als zweizeilige Einträge */
}
.dropdown-menu:not(.ds-row-menu-list) :is(.dropdown-divider, .ds-row-menu-divider) { margin: .3rem .25rem; }

/* MENÜ-BAUM (js/shared/ds-menue-baum.js): Baum oder Liste als Werkzeugleisten-Dropdown — Arc „Archive“/„Ordner“,
   E-Mail „Ordner“, MyKI „Chats“ (max 08.11.2026: statt Seitenblatt „wie das Dropdown mit den Archiven“).
   Zeilen = normale Menüeinträge (Maß + Hover aus MENÜEINTRÄGE), nur die Einrückung kommt dazu. */
.dropdown-menu:has(> [data-ds-menue-baum]) { width: 18rem; max-width: calc(100vw - 2rem); }
.ds-menue-baum { list-style: none; }
.ds-mb-suche { padding: .125rem .25rem .375rem; }
.ds-mb-liste { max-height: min(60vh, 26rem); overflow-y: auto; overscroll-behavior: contain; }
.dropdown-menu .ds-menue-baum .ds-mb-zeile {
    display: flex; align-items: center; gap: .5rem; min-width: 0;
    padding-left: calc(.5rem + var(--tiefe, 0) * 1rem);
    font-size: .875rem; line-height: 1.25rem;   /* = Toolbar-Menüeintrag, 36 px */
    text-decoration: none;
    -webkit-touch-callout: none;
}
.ds-mb-pfeil {
    flex: 0 0 1.25rem; height: 1.25rem; margin-right: -.25rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: .3rem; color: var(--ds-muted-foreground); font-size: .7rem;
}
.ds-mb-pfeil[data-auf]:hover { background: color-mix(in srgb, var(--ds-foreground) 10%, transparent); }
.ds-mb-pfeil i { transition: transform .15s ease; }
.ds-mb-pfeil[aria-expanded="true"] i { transform: rotate(90deg); }
.ds-mb-icon { flex: 0 0 auto; display: inline-flex; }
.ds-menue-baum .ds-mb-icon > i { color: var(--ds-primary); }
.ds-mb-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ds-mb-meta { flex: 0 0 auto; font-size: .72rem; }
.ds-mb-zahl, .ds-mb-schloss { flex: 0 0 auto; }
.ds-mb-schloss { font-size: .75rem; color: var(--ds-muted-foreground); }
.ds-menue-baum .ds-mb-gruppe {
    padding: .25rem .75rem .125rem; font-size: .75rem; font-weight: 600; color: var(--ds-muted-foreground);
}
.ds-menue-baum .ds-mb-hinweis { padding: .5rem .75rem; font-size: .8rem; color: var(--ds-muted-foreground); }

/* Dropdown-Gruppe mit vielen Einträgen (z.B. Kontaktlisten): scrollbares
   Spalten-Grid. Die Spaltenzahl bestimmt der Tag-Helper aus der Item-Anzahl
   (data-cols), die Media-Queries fahren sie auf schmalen Displays herunter. */
.ds-dropdown-group {
    display: grid;
    grid-template-columns: 1fr;
    align-content: start;
    gap: 0;
    margin: 0;
    padding: 0;
    list-style: none;
    max-height: var(--ds-dd-max-height, 60vh);
    overflow-y: auto;
    overscroll-behavior: contain;
}

.ds-dropdown-group[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ds-dropdown-group[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ds-dropdown-group[data-cols="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Das Panel darf so breit werden wie das Grid es braucht — aber nie breiter
   als der Viewport. Schrumpft es, fallen unten die Spalten weg. */
.dropdown-menu:has(.ds-dropdown-group) {
    width: max-content;
    max-width: min(92vw, 56rem);
}

@media (max-width: 1200px) {
    .ds-dropdown-group[data-cols="3"],
    .ds-dropdown-group[data-cols="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 768px) {
    .ds-dropdown-group[data-cols] { grid-template-columns: 1fr; }
}

/* Lange Listennamen dürfen die Spalte nicht sprengen. */
.ds-dropdown-group .ds-dropdown-item { min-width: 0; }
.ds-dropdown-group .ds-dropdown-item > i { flex: 0 0 auto; }

.ds-dropdown-group .ds-dropdown-item-label {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* ============================================
   ROW-MENÜ (Kebab „⋮") — Overflow-Aktionsmenü pro Listenzeile
   --------------------------------------------
   Gold-Standard: ToDo-Datei-/Termin-Zeilen. Bisher wurde das Panel an JEDER
   Verwendung mit inline-tw-Klassen + style="background:…" zusammengebaut. Diese
   Regeln machen `<ul class="dropdown-menu ds-row-menu-list">` selbsttragend —
   neue Module brauchen nur noch die zwei Klassen, keine inline-Utilities.
   Markup-Muster:
     <div class="dropdown ds-row-menu">
       <ds-chip-btn data-bs-toggle="dropdown" icon="bi-three-dots-vertical" />
       <ul class="dropdown-menu dropdown-menu-end ds-row-menu-list">
         <li><a class="ds-dropdown-item" href="#" onclick="…;return false;"><i class="bi bi-download"></i>Download</a></li>
         <li><div class="ds-row-menu-divider"></div></li>
         <li><a class="ds-dropdown-item is-destructive" href="#" onclick="…;return false;"><i class="bi bi-trash3"></i>Löschen</a></li>
       </ul>
     </div>
   ============================================ */
.ds-row-menu { position: relative; }            /* = Bootstrap .dropdown; macht die Klasse real */

/* Karten schneiden mit `overflow: hidden` alles ab, was über ihre Kante ragt — auch ein
   aufgeklapptes Zeilenmenü. Das Menü lag dann hinter dem Kartenrand und war unbenutzbar
   (gemeldet 11.09.2026 an den Formular-Karten). `data-bs-boundary="viewport"` hilft dagegen
   nicht: Popper rechnet zwar mit dem Viewport, das Menü bleibt aber im DOM der Karte.
   Deshalb: Karten, die ein Zeilenmenü enthalten, geben den Überhang frei. Browser ohne
   `:has()` ignorieren die Regel und verhalten sich wie bisher. */
.ds-card:has(.ds-row-menu) { overflow: visible; }
.ds-row-menu > .ds-chip-btn { flex-shrink: 0; }

/* Seit 07.11.2026 dasselbe Maß wie alle anderen Menüs (Block „MENÜEINTRÄGE": Luft rundum, Einträge
   36 px, einzeilig) — vorher eigenes, engeres Maß: lange Einträge („Zu Favoriten hinzufügen") brachen
   in zwei Zeilen um, das Menü wirkte gedrückt (max: „entspricht noch nicht unserem Standard"). */
.ds-row-menu-list {
    min-width: 11rem;
    margin-top: 0.35rem;
    padding: 0.375rem;
    border: 1px solid var(--ds-border);
    border-radius: 0.6rem;
    background: var(--ds-card);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .18), 0 2px 10px rgba(0, 0, 0, .1);
}

.ds-row-menu-list .ds-dropdown-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 1px 0;
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    line-height: 1.25rem;
    border-radius: 0.45rem;
    white-space: nowrap;        /* einzeilig — das Menü wird lieber breiter */
    color: var(--ds-foreground);
    text-decoration: none;
    cursor: pointer;
}

/* Destruktive Aktion (Löschen) — rot, bleibt auch im Hover lesbar (überstimmt den
   globalen accent-1-Hover von .ds-dropdown-item). */
.ds-row-menu-list .ds-dropdown-item.is-destructive { color: var(--ds-destructive); }
.ds-row-menu-list .ds-dropdown-item.is-destructive:hover {
    background: color-mix(in srgb, var(--ds-destructive) 14%, transparent);
    color: var(--ds-destructive);
}

/* Themenwechsel in Menüs (z. B. vor „Volle Breite", vor „Löschen") mit feiner Linie — gilt für Zeilenmenüs
   und <ds-toolbar-dropdown-divider>. Am 07.11.2026 kurz nur Abstand, max wollte die Linie zurück. */
.ds-row-menu-divider {
    height: 1px;
    margin: 0.25rem 0.25rem;
    background: var(--ds-border);
}

/* Dropdown-Panels — opak, neutraler Border, kräftiger Schatten */
html.ds-page [x-transition] {
    background: var(--ds-card) !important;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18), 0 2px 10px rgba(0, 0, 0, 0.1) !important;
}

/* ============================================
   WINDOW MODE — Synology-style floating windows
   ============================================ */
.ds-window {
    position: fixed;
    top: 5%;
    left: 10%;
    width: 75%;
    height: 80%;
    /* Fenster-Ebene 500..1000 (Manager nummeriert hoch) — BEWUSST UNTER Bootstrap-Modals
       (Backdrop 1040 / Modal 1055) und Dock (1039): das Menü-Modal aus dem Dock muss
       IMMER über den Fenstern liegen. */
    z-index: 500;
    display: flex;
    flex-direction: column;
    border-radius: calc(var(--ds-radius) * 1.4);
    overflow: hidden;
    box-shadow: 0 25px 60px rgba(0, 0, 0, 0.3), 0 0 0 1px var(--ds-border);
    /* Glas-Look: halbtransparent + Blur über dem Desktop-Hintergrundbild. Die Embed-Seiten
       im iframe rendern mit transparentem body (beide Layouts), damit das Glas durchscheint.
       Light-Theme = RAUCHGLAS (dezent dunkel getönt): weiße Karte (--ds-card) als Glaston war
       Weiß-in-Weiß-Matsche über den Modul-Cards (Max-Feedback) — die dunkle Tönung gibt den
       weißen Inhalts-Cards Kontrast, die Transparenz bleibt erhalten. 40% war Max zu hart,
       28% ist der abgestimmte Kompromiss. Dark-Theme s.u. */
    background: color-mix(in srgb, #313c4e 28%, transparent);
    -webkit-backdrop-filter: blur(24px) saturate(1.4);
    backdrop-filter: blur(24px) saturate(1.4);
    /* KEIN natives resize:both — das bietet nur die Ecke unten rechts; stattdessen
       eigene Griffe an allen Kanten/Ecken (.ds-window-resize-*, vom Manager erzeugt). */
    min-width: 400px;
    min-height: 300px;
}

/* Resize-Griffe: unsichtbare Trefferflächen INNEN am Rand (overflow:hidden clippt außen
   liegende); Ecken größer und über den Kanten. Werte MIN_WIN_W/H klemmt der Manager. */
.ds-window-resize { position: absolute; z-index: 12; background: transparent; touch-action: none; }
.ds-window-resize-n  { top: 0; left: 14px; right: 14px; height: 6px; cursor: ns-resize; }
.ds-window-resize-s  { bottom: 0; left: 14px; right: 14px; height: 6px; cursor: ns-resize; }
.ds-window-resize-e  { right: 0; top: 14px; bottom: 14px; width: 6px; cursor: ew-resize; }
.ds-window-resize-w  { left: 0; top: 14px; bottom: 14px; width: 6px; cursor: ew-resize; }
.ds-window-resize-ne { top: 0; right: 0; width: 14px; height: 14px; cursor: nesw-resize; z-index: 13; }
.ds-window-resize-nw { top: 0; left: 0; width: 14px; height: 14px; cursor: nwse-resize; z-index: 13; }
.ds-window-resize-se { bottom: 0; right: 0; width: 14px; height: 14px; cursor: nwse-resize; z-index: 13; }
.ds-window-resize-sw { bottom: 0; left: 0; width: 14px; height: 14px; cursor: nesw-resize; z-index: 13; }
.ds-window-maximized .ds-window-resize { display: none; }

/* Touchscreens (grober Zeiger): 6px-Kanten sind mit dem Finger nicht treffbar → breitere
   Griffe + größere Ecken. Nur unter (pointer: coarse), Maus-Präzision bleibt unberührt. */
@media (pointer: coarse) {
    .ds-window-resize-n, .ds-window-resize-s { height: 16px; left: 28px; right: 28px; }
    .ds-window-resize-e, .ds-window-resize-w { width: 16px; top: 28px; bottom: 28px; }
    .ds-window-resize-ne, .ds-window-resize-nw,
    .ds-window-resize-se, .ds-window-resize-sw { width: 28px; height: 28px; }
    /* mac-Ampel-Punkte: 12px sind für Finger zu klein */
    .ds-window-btn { width: 1.125rem; height: 1.125rem; }
}

/* Dark-Theme: --ds-card ist dort selbst dunkel — das ursprüngliche 78%-Glas passt. */
html.dark .ds-window {
    background: color-mix(in srgb, var(--ds-card) 78%, transparent);
}

/* Titelleiste hell (Max-Wunsch), aber fast vollfarbig (85% statt 60% — weniger Durchschein-
   Kontrast) — nur die Glasfläche darunter trägt die Rauch-Tönung. */
.ds-window-titlebar {
    display: flex;
    align-items: center;
    height: 2.5rem;
    padding: 0 0.75rem;
    background: color-mix(in srgb, var(--ds-muted) 85%, transparent);
    color: var(--ds-foreground);
    border-bottom: 1px solid var(--ds-border);
    cursor: grab;
    user-select: none;
    flex-shrink: 0;
    /* Touch: Finger-Drag der Titelleiste darf nicht als Seiten-Scroll/Geste interpretiert
       werden — sonst bewegt sich das Fenster auf Touchscreens keinen Millimeter. */
    touch-action: none;
}

.ds-window-titlebar:active {
    cursor: grabbing;
}

.ds-window-title {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ds-foreground);
    flex: 1;
    margin-left: 0.5rem;
}

.ds-window-controls {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    /* MUSS über den Resize-Griffen (.ds-window-resize, z-index 12/13) liegen: die
       n-/ne-/nw-Griffe überlappen sonst den oberen Rand + die obere Ecke der Titelleisten-
       Knöpfe und schlucken deren Klick/Tap (auf Touch mit 16px/28px-Griffen fast die
       ganze Trefferfläche → „Fenster lässt sich nicht schließen"). */
    position: relative;
    z-index: 14;
}

.ds-window-btn {
    width: 0.75rem;
    height: 0.75rem;
    border-radius: 50%;
    border: none;
    cursor: pointer;
    transition: opacity 0.15s;
}

/* macOS Style */
.ds-window-btn:hover { opacity: 0.8; }
.ds-window-btn-close { background: #ef4444; }
.ds-window-btn-minimize { background: #f59e0b; }
.ds-window-btn-maximize { background: #22c55e; }

/* Windows Style */
.ds-window-controls-win {
    gap: 0;
}

.ds-window-btn-win {
    width: 2.75rem;
    height: 2rem;
    border: none;
    background: transparent;
    color: var(--ds-muted-foreground);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8125rem;
    transition: background 0.1s, color 0.1s;
    border-radius: 0;
}

.ds-window-btn-win:hover {
    background: var(--ds-accent);
    color: var(--ds-foreground);
}

.ds-window-btn-win-close:hover {
    background: #ef4444;
    color: #ffffff;
}

/* ============================================
   SNAP ZONES — Windows 11 Style
   ============================================ */
.ds-snap-overlay {
    position: fixed;
    inset: 0;
    z-index: 9998;
    pointer-events: none;
    display: none;
}

.ds-snap-overlay.active {
    display: block;
}

.ds-snap-preview {
    position: fixed;
    background: color-mix(in srgb, var(--ds-accent-1) 15%, transparent);
    border: 2px solid var(--ds-accent-1);
    border-radius: var(--ds-radius);
    transition: all 0.15s ease;
    z-index: 9997;
    display: none;
    pointer-events: none;
}

.ds-snap-preview.active {
    display: block;
}

/* Snap-Menü (Hover über Maximize Button). position:fixed am <body> — im Fenster verankert
   läge es in dessen Stacking-Context und würde von jedem höher gestapelten Nachbarfenster
   überdeckt (iframe schluckt die Klicks). Position setzt der Window-Manager beim Öffnen
   (nach innen ausgerichtet + an den Viewport geklemmt). */
.ds-snap-menu {
    position: fixed;
    z-index: 10000;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius);
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18);
    padding: 0.75rem;
    display: none;
    gap: 0.5rem;
}

.ds-snap-menu.active {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
}

/* Kompat-Schiene für Clients mit noch gecachtem ALTEM ds-window-manager.js (Menü hängt dort
   noch IM Fenster statt am <body> → position:fixed macht es dort wegen backdrop-filter zum
   Gefangenen des Fenster-Stacking-Contexts, "liegt hinter den Fenstern"). Solange das alte JS
   läuft, wieder relativ unterm Button aufklappen; das neue JS hängt das Menü an den <body>,
   dann matcht dieser Selektor nicht mehr. Kann nach ein paar SW-Versionen wieder raus. */
.ds-window-controls .ds-snap-menu {
    position: absolute;
    top: 100%;
    left: 0;
}

.ds-snap-option {
    width: 90px;
    height: 56px;
    border: 1.5px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 0.6);
    cursor: pointer;
    display: flex;
    background: var(--ds-background);
    overflow: hidden;
    transition: border-color 0.1s;
    padding: 3px;
    gap: 2px;
}

.ds-snap-option:hover {
    border-color: var(--ds-accent-1);
}

.ds-snap-option .snap-zone {
    background: var(--ds-muted);
    border-radius: 2px;
    transition: background 0.1s;
}

.ds-snap-option:hover .snap-zone {
    background: color-mix(in srgb, var(--ds-accent-1) 25%, transparent);
}

.ds-snap-option:hover .snap-zone.snap-active {
    background: var(--ds-accent-1);
}

/* „In anderes Browserfenster verschieben" — volle Zeile unter den Layout-Kacheln
   (Menü ist ein 3-Spalten-Grid → über alle Spalten spannen). */
.ds-snap-menu .ds-snap-move {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.25rem;
    padding: 0.45rem 0.6rem;
    border: 1.5px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 0.6);
    background: var(--ds-background);
    color: var(--ds-foreground);
    font-size: 0.75rem;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.1s;
}

.ds-snap-menu .ds-snap-move:hover {
    border-color: var(--ds-accent-1);
}

.ds-snap-menu .ds-snap-move i {
    color: var(--ds-accent-1);
}

/* Snap-Bar oben (erscheint beim Drag nach oben) */
.ds-snap-bar {
    position: fixed;
    top: -80px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 10001;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 1.4);
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18);
    padding: 0.75rem 1rem;
    display: flex;
    gap: 0.625rem;
    transition: top 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}

.ds-snap-bar.active {
    top: 12px;
}

.ds-snap-bar .ds-snap-option {
    width: 100px;
    height: 60px;
}

.ds-snap-bar .ds-snap-option.snap-hover .snap-zone {
    background: color-mix(in srgb, var(--ds-accent-1) 25%, transparent);
}

.ds-snap-bar .ds-snap-option.snap-hover .snap-zone.snap-active {
    background: var(--ds-accent-1);
}

/* Gescrollt wird NUR im iframe (Embed-Seite hat ihren eigenen Scroller) — overflow:hidden
   plus display:block verhindern den Doppel-Scrollbalken durch den Inline-Baseline-Spalt
   des iframes (~4px Überlauf bei height:100%). */
.ds-window-body {
    flex: 1;
    overflow: hidden;
    padding: 0;
}

.ds-window-body iframe {
    display: block;
}

/* moduleWrapper Zentrierung */
#moduleWrapper {
    width: 100%;
    max-width: var(--ds-content-width);
    margin: 0 auto;
}

/* „Volle Breite“ (Ansicht-Menü, js/shared/ds-volle-breite.js; Arc, E-Mail, ToDo): ohne Deckelung, schmaler Rand.
   Der Haken am Menüeintrag erscheint nur, solange die volle Breite an ist.
   Nur in der Geräteklasse „breit“: darunter (Handy, Fold, Tablet hochkant) ist die Seite ohnehin schmaler als
   die Deckelung — dort gibt es weder den Eintrag (samt Trennlinie direkt davor) noch die Wirkung. */
@media (min-width: 992px) {
    html.ds-volle-breite #moduleWrapper { max-width: none !important; }
    html.ds-volle-breite .ds-main .ds-content { --ds-content-pad-x: 0.75rem; }
}
@media (max-width: 991.98px) {
    li[data-ds-volle-breite],
    li:has(> [data-ds-volle-breite]),
    li:has(> .ds-row-menu-divider):has(+ li[data-ds-volle-breite]:last-child) { display: none !important; }
}
.ds-vb-haken { margin-left: auto; padding-left: 0.75rem; visibility: hidden; }
[aria-checked="true"] > .ds-vb-haken { visibility: visible; }

#toolbarContent {
    /* .625rem oben = dieselben 10px wie .ds-content → Kopfleiste überall 12px vom Rand (Regel bei .ds-toolbar.tw-mt-2). */
    padding: 0.625rem 0 0.75rem 0;
}

/* ============================================================================
   TOOLBAR-SLOT BÜNDIG ZUM CONTENT (ToDo-Goldstandard) — EINE zentrale Stelle.
   Module, die ihre Toolbar via `@section Toolbar { <ds-toolbar> … }` liefern,
   landen im #toolbarContent — einem Sibling von .ds-content in #moduleWrapper.
   #toolbarContent hat KEINEN horizontalen Rand (padding: … 0 … 0) und erbt den
   Modul-Rand-Token --ds-content-pad-x NICHT (der wird nur auf .ds-content per
   :has() umgesetzt) → die Header-Buttons kleben bei x=0, während der Content bei
   20px startet (Full-Bleed). Ergebnis: Buttons sitzen weiter links als die Cards.
   Der Goldstandard ToDo hat das Problem nicht, weil es die Toolbar INLINE im
   Content-Wrapper rendert (teilt sich den 20px-Rand).
   Hier ziehen wir die @section-Toolbar-Module zentral auf denselben Rand + Gap:
   - horizontal: 1.25rem (= --ds-content-pad-x der Full-Bleed-Module)
   - oben: 10px (wie die Content-Oberkante bei ToDo, + tw-mt-2 des Wrappers = ~18px)
   - unten: 0 → der Abstand zum Content kommt allein aus dem tw-mb-3 (12px) des
     <ds-toolbar>-Wrappers (= ToDo-Gap); zusätzlich Content-Oberkante auf 0.
   Bewusst auf `.ds-fullbleed` gescoped: Itops nutzt `.ds-fullbleed-floating` +
   eigenes tw-px-4 (bleibt unberührt); Inline-Toolbar-Module (ToDo/CRM/TeamTime …)
   haben gar kein #toolbarContent. ============================================ */
#moduleWrapper:has(.ds-fullbleed) #toolbarContent {
    padding: 0.625rem 1.25rem 0 1.25rem;
}
#moduleWrapper:has(.ds-fullbleed):has(> #toolbarContent) > .ds-content {
    padding-top: 0 !important;
}
/* Schwebende Karten (Compass): 16px-Rand. Eigener Marker `.compass-module`, damit
   Itops (gleiche .ds-fullbleed-floating-Klasse, aber eigenes tw-px-4) NICHT mitgefasst wird. */
#moduleWrapper:has(.compass-module) #toolbarContent {
    padding: 0.625rem 1rem 0 1rem;
}
#moduleWrapper:has(.compass-module):has(> #toolbarContent) > .ds-content {
    padding-top: 0 !important;
}
/* Smartphone: Rand global auf 0.25rem (wie --ds-content-pad-x im Mobile-Block). */
@media (max-width: 575.98px) {
    #moduleWrapper:has(.ds-fullbleed) #toolbarContent,
    #moduleWrapper:has(.compass-module) #toolbarContent {
        padding-left: 0.25rem;
        padding-right: 0.25rem;
    }
}

/* Itops (schwebende @section-Views): der vertikale Abstand nav→Content war zu groß —
   _ItopsNav-Wrapper mb-1 (4px) + #toolbarContent pb (12px) + Content pt (16px, floating) = ~32px.
   Auf den ToDo-Gap (~12px) zusammenziehen: #toolbarContent-pb raus, Content-pt auf 8px →
   zusammen mit dem tw-mb-1 des _ItopsNav ≈ 12px. Horizontal bleibt bei 16px (tw-px-4 im _ItopsNav).
   Bewusst OHNE `.compass-module` (hat mb-3 + eigene 0-Regel) und OHNE die boxed
   `.container-fluid.px-4`-Views (nicht floating → nicht getroffen). */
#moduleWrapper:has(.ds-fullbleed-floating):not(:has(.compass-module)) #toolbarContent {
    padding-bottom: 0;
}
#moduleWrapper:has(.ds-fullbleed-floating):not(:has(.compass-module)):has(> #toolbarContent) > .ds-content {
    padding-top: 0.5rem !important;
}

/* Wenn Window-Mode aktiv: moduleWrapper ausblenden, Hintergrund zeigen */
.ds-main.window-mode > #moduleWrapper {
    display: none;
}

/* Window-Overlay Hintergrund (optional) */
.ds-window-overlay {
    position: fixed;
    inset: 0;
    z-index: 1999;
    background: transparent;
}

/* Maximiert: volle Fläche über dem Dock, KEIN iframe-Neuladen — nur Geometrie per Klasse.
   Vorherige Position/Größe merkt sich ds-window-manager.js in data-premax. */
.ds-window.ds-window-maximized {
    top: 0 !important;
    left: 0 !important;
    width: 100vw !important;
    height: calc(100vh - 88px) !important; /* 80px Dock + 8px Luft */
    border-radius: 0 !important;
    resize: none;
}

/* Minimiert: Fenster lebt weiter (iframe-Zustand bleibt), nur unsichtbar; Wiederherstellen
   über den Chip in der Fensterleiste. */
.ds-window.ds-window-minimized {
    display: none !important;
}

/* Fensterleiste (Fenstermodus): Übersicht aller offenen Fenster + Minimieren-Ziel,
   schwebt mittig über dem Dock. */
.ds-window-taskbar {
    position: fixed;
    bottom: 96px;
    left: 50%;
    transform: translateX(-50%);
    /* über den Fenstern (≤1000), aber unter Dock (1039) und Bootstrap-Modals (1040+) */
    z-index: 1035;
    display: none;
    gap: 0.375rem;
    padding: 0.375rem 0.5rem;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 1.4);
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18);
    max-width: 90vw;
    overflow-x: auto;
}

.ds-window-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    border: 1px solid var(--ds-border);
    background: var(--ds-background);
    color: var(--ds-foreground);
    border-radius: 999px;
    padding: 0.25rem 0.625rem;
    font-size: 0.75rem;
    cursor: pointer;
    white-space: nowrap;
}

.ds-window-chip:hover {
    border-color: var(--ds-accent-1);
}

.ds-window-chip.minimized {
    opacity: 0.55;
}

.ds-window-chip .chip-close {
    opacity: 0.6;
}

.ds-window-chip .chip-close:hover {
    opacity: 1;
    color: var(--ds-destructive);
}

/* Cross-Window-Move: Ablage-Ziel, das in den ANDEREN Teamhub-Browserfenstern erscheint,
   solange dort ein Chip-Drag läuft (BroadcastChannel). Muss ÜBER den iframes liegen —
   die schlucken sonst die dragover/drop-Events der Trägerseite. Kinder + ::before sind
   pointer-events-frei, damit dragleave beim Überfahren des Hinweises nicht flackert. */
.ds-window-drop-overlay {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: none;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--ds-background) 55%, transparent);
    backdrop-filter: blur(2px);
}

.ds-window-drop-overlay.active {
    display: flex;
}

.ds-window-drop-overlay::before {
    content: '';
    position: absolute;
    inset: 12px;
    border: 2px dashed var(--ds-accent-1);
    border-radius: calc(var(--ds-radius) * 1.4);
}

.ds-window-drop-overlay.drop-hover::before {
    border-style: solid;
    background: color-mix(in srgb, var(--ds-accent-1) 10%, transparent);
}

.ds-window-drop-hint {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.75rem 1.25rem;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 999px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18);
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--ds-foreground);
    pointer-events: none;
}

.ds-window-drop-hint i {
    color: var(--ds-accent-1);
    font-size: 1.1rem;
}

/* Combobox Items (offene Liste) */
/* Button-Basis für Previews (spart String-Länge in Views) */
.ds-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    border-radius: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    line-height: 1;
    padding: 0 0.875rem;
    height: 2.125rem;
    border: 1px solid transparent;
    /* Feste Höhe inkl. Rand: <button> rechnet so ohnehin, <a class="ds-btn"> ohne Tailwind-Preflight
       (Gastseiten) sonst 2 px höher — Link- und Knopf-Buttons nebeneinander wären ungleich groß. */
    box-sizing: border-box;
    cursor: pointer;
    transition: all 0.15s cubic-bezier(.4,0,.2,1);
    text-decoration: none;
    font-family: inherit;
    outline: none;
    white-space: nowrap;
    flex-shrink: 0;
    color: var(--ds-foreground);
    position: relative;
    user-select: none;
}
.ds-btn:focus-visible { outline: 2px solid var(--ds-primary); outline-offset: 2px; }
.ds-btn:disabled { opacity: 0.45; pointer-events: none; filter: grayscale(0.3); }
.ds-btn:active:not(:disabled) { transform: scale(0.97); transition-duration: 0.05s; }

/* ── Primary — soft getönt wie die anderen ── */
.ds-btn-primary {
    background: color-mix(in srgb, var(--ds-primary) 10%, var(--ds-background));
    color: var(--ds-primary);
    border-color: color-mix(in srgb, var(--ds-primary) 30%, transparent);
}
.ds-btn-primary:hover {
    background: color-mix(in srgb, var(--ds-primary) 15%, var(--ds-background));
    border-color: var(--ds-primary);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--ds-primary) 20%, transparent);
    transform: translateY(-1px);
}
.ds-btn-primary.ds-btn-solid {
    background: var(--ds-primary);
    color: var(--ds-primary-foreground);
    border-color: transparent;
}
.ds-btn-primary.ds-btn-solid:hover {
    background: color-mix(in srgb, var(--ds-primary) 85%, black);
    box-shadow: 0 3px 10px color-mix(in srgb, var(--ds-primary) 30%, transparent);
}

/* ── Secondary — klar abgegrenzt, subtil ── */
.ds-btn-secondary {
    background: var(--ds-background);
    color: var(--ds-foreground);
    border-color: var(--ds-border);
    box-shadow: 0 1px 2px rgba(0,0,0,.04);
}
.ds-btn-secondary:hover {
    background: var(--ds-muted);
    border-color: color-mix(in srgb, var(--ds-border) 70%, var(--ds-foreground));
    box-shadow: 0 2px 4px rgba(0,0,0,.06);
    transform: translateY(-1px);
}

/* ── Destructive — rot getönt, nicht vollfarbig ── */
.ds-btn-destructive {
    background: color-mix(in srgb, var(--ds-destructive) 10%, var(--ds-background));
    color: var(--ds-destructive);
    border-color: color-mix(in srgb, var(--ds-destructive) 30%, transparent);
}
.ds-btn-destructive:hover {
    background: color-mix(in srgb, var(--ds-destructive) 15%, var(--ds-background));
    border-color: var(--ds-destructive);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--ds-destructive) 20%, transparent);
    transform: translateY(-1px);
}
/* Volle Variante */
.ds-btn-destructive.ds-btn-solid {
    background: var(--ds-destructive);
    color: var(--ds-destructive-foreground);
    border-color: transparent;
}
.ds-btn-destructive.ds-btn-solid:hover {
    background: color-mix(in srgb, var(--ds-destructive) 85%, black);
    box-shadow: 0 3px 10px color-mix(in srgb, var(--ds-destructive) 30%, transparent);
}

/* ── Success — sanft grün getönt ── */
.ds-btn-success {
    background: color-mix(in srgb, var(--ds-success) 10%, var(--ds-background));
    color: var(--ds-success);
    border-color: color-mix(in srgb, var(--ds-success) 30%, transparent);
}
.ds-btn-success:hover {
    background: color-mix(in srgb, var(--ds-success) 15%, var(--ds-background));
    border-color: var(--ds-success);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--ds-success) 20%, transparent);
    transform: translateY(-1px);
}
.ds-btn-success.ds-btn-solid {
    background: var(--ds-success);
    color: var(--ds-success-foreground, #fff);
    border-color: transparent;
}
.ds-btn-success.ds-btn-solid:hover {
    background: color-mix(in srgb, var(--ds-success) 85%, black);
    box-shadow: 0 3px 10px color-mix(in srgb, var(--ds-success) 30%, transparent);
    transform: translateY(-1px);
}

/* ── Warning — sanft amber getönt ── */
.ds-btn-warning {
    background: color-mix(in srgb, var(--ds-warning) 10%, var(--ds-background));
    color: var(--ds-warning);
    border-color: color-mix(in srgb, var(--ds-warning) 30%, transparent);
}
.ds-btn-warning:hover {
    background: color-mix(in srgb, var(--ds-warning) 15%, var(--ds-background));
    border-color: var(--ds-warning);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--ds-warning) 20%, transparent);
    transform: translateY(-1px);
}

/* ── Info — sanft blau getönt ── */
.ds-btn-info {
    background: color-mix(in srgb, var(--ds-info) 10%, var(--ds-background));
    color: var(--ds-info);
    border-color: color-mix(in srgb, var(--ds-info) 30%, transparent);
}
.ds-btn-info:hover {
    background: color-mix(in srgb, var(--ds-info) 15%, var(--ds-background));
    border-color: var(--ds-info);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--ds-info) 20%, transparent);
    transform: translateY(-1px);
}

/* ── Farbige Outline-Varianten ── */
.ds-btn-primary.ds-btn-outline,
.ds-btn-destructive.ds-btn-outline,
.ds-btn-success.ds-btn-outline,
.ds-btn-warning.ds-btn-outline,
.ds-btn-info.ds-btn-outline { background: transparent; box-shadow: none; }

.ds-btn-primary.ds-btn-outline { color: var(--ds-primary); border-color: var(--ds-primary); }
.ds-btn-primary.ds-btn-outline:hover { background: color-mix(in srgb, var(--ds-primary) 8%, var(--ds-background)); }

.ds-btn-destructive.ds-btn-outline { color: var(--ds-destructive); border-color: var(--ds-destructive); }
.ds-btn-destructive.ds-btn-outline:hover { background: color-mix(in srgb, var(--ds-destructive) 8%, var(--ds-background)); }

.ds-btn-success.ds-btn-outline { color: var(--ds-success); border-color: var(--ds-success); }
.ds-btn-success.ds-btn-outline:hover { background: color-mix(in srgb, var(--ds-success) 8%, var(--ds-background)); }

.ds-btn-warning.ds-btn-outline { color: var(--ds-warning); border-color: var(--ds-warning); }
.ds-btn-warning.ds-btn-outline:hover { background: color-mix(in srgb, var(--ds-warning) 8%, var(--ds-background)); }

.ds-btn-info.ds-btn-outline { color: var(--ds-info); border-color: var(--ds-info); }
.ds-btn-info.ds-btn-outline:hover { background: color-mix(in srgb, var(--ds-info) 8%, var(--ds-background)); }

/* ── Outline (neutral) — klarer Rand ── */
.ds-btn-outline {
    background: var(--ds-background);
    border-color: var(--ds-input);
    box-shadow: 0 1px 2px rgba(0,0,0,.04);
}
.ds-btn-outline:hover {
    background: var(--ds-muted);
    border-color: color-mix(in srgb, var(--ds-border) 70%, var(--ds-foreground));
    box-shadow: 0 2px 4px rgba(0,0,0,.06);
    transform: translateY(-1px);
}

/* ── Toggle-Buttons (Bootstrap .btn-check + .ds-btn-Label, z.B. Wochentag-Auswahl im Serientermin) ──
   Ohne diese Regel zeigt ein angehakter Wochentag KEINE optische Markierung (nur Text). Der
   :checked-Zustand des versteckten .btn-check färbt das zugehörige ds-btn-Label im Akzentton ein. */
.btn-check:checked + .ds-btn,
.btn-check:active + .ds-btn,
.btn-check:checked + .ds-btn-outline,
.btn-check:active + .ds-btn-outline {
    background: var(--ds-accent-1);
    border-color: var(--ds-accent-1);
    color: #fff;
    box-shadow: none;
    transform: none;
}
.btn-check:checked + .ds-btn:hover,
.btn-check:checked + .ds-btn-outline:hover {
    background: color-mix(in srgb, var(--ds-accent-1) 88%, #000);
    border-color: color-mix(in srgb, var(--ds-accent-1) 88%, #000);
    color: #fff;
}
.btn-check:focus-visible + .ds-btn { outline: 2px solid var(--ds-ring); outline-offset: 2px; }

/* ── Ghost — unsichtbar bis Hover ── */
.ds-btn-ghost { background: transparent; border-color: transparent; }
.ds-btn-ghost:hover { background: var(--ds-accent); }

/* ── Link — inline Textstil ── */
.ds-btn-link { background: transparent; border-color: transparent; text-underline-offset: 4px; height: auto; padding: 0; color: var(--ds-primary); }
.ds-btn-link:hover { text-decoration: underline; }

/* ── Sizes ── */
.ds-btn-sm { height: 1.75rem; padding: 0 0.625rem; font-size: 0.75rem; border-radius: 0.375rem; }
.ds-btn-lg { height: 2.5rem; padding: 0 1.25rem; font-size: 0.9375rem; }
.ds-btn-icon { height: 2.125rem; width: 2.125rem; padding: 0; }
.ds-btn-icon.ds-btn-sm { height: 1.75rem; width: 1.75rem; }

/* ============================================
   EDITOR — Tiptap Styles
   ============================================ */
.ds-editor-wrap {
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius);
    /* kein overflow:hidden — würde Farb-Dropdowns abschneiden */
    background: var(--ds-background);
    position: relative;
}

.ds-editor-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 0.5rem;
    border-bottom: 1px solid var(--ds-border);
    background: var(--ds-muted);
    border-radius: var(--ds-radius) var(--ds-radius) 0 0;
}

.ds-editor-toolbar .ds-editor-sep {
    width: 1px;
    background: var(--ds-border);
    margin: 0 0.25rem;
    align-self: stretch;
}

.ds-editor-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border: none;
    border-radius: calc(var(--ds-radius) * 0.6);
    background: transparent;
    color: var(--ds-foreground);
    cursor: pointer;
    font-size: 0.875rem;
    transition: background 0.1s;
}

/* Hover/aktiv in der Leitfarbe der Konsole statt Grau (max 05.11.2026, wie die Notizbuch-Knöpfe). :not(:disabled)
   hebt über den Modal-Normalizer (body > .modal button … 0,2,2) — der Editor steckt oft in Modalen. */
.ds-editor-btn:hover:not(:disabled) {
    background: color-mix(in srgb, var(--ds-accent-1) var(--ds-menu-hover, 14%), transparent);
    color: var(--ds-accent-1-text, var(--ds-accent-1));
}
.ds-editor-btn.active:not(:disabled) {
    background: color-mix(in srgb, var(--ds-accent-1) var(--ds-menu-active, 22%), transparent);
    color: var(--ds-accent-1-text, var(--ds-accent-1)); font-weight: 600;
}

.ds-editor-select {
    height: 2rem;
    padding: 0 0.5rem;
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 0.6);
    background: var(--ds-background);
    color: var(--ds-foreground);
    font-size: 0.75rem;
    cursor: pointer;
}
.ds-editor-heading-btn {
    display: flex;
    align-items: center;
    height: 2rem;
    padding: 0 0.6rem;
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 0.6);
    background: var(--ds-background);
    color: var(--ds-foreground);
    font-size: 0.75rem;
    cursor: pointer;
    white-space: nowrap;
    min-width: 7rem;
}
.ds-editor-heading-btn:hover { background: var(--ds-muted); }
.ds-editor-heading-dropdown {
    position: absolute;
    z-index: 50;
    top: 100%;
    left: 0;
    margin-top: 4px;
    min-width: 12rem;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius);
    box-shadow: 0 8px 24px rgba(0,0,0,.15);
    padding: 0.25rem;
    display: flex;
    flex-direction: column;
}
.ds-editor-heading-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.4rem 0.75rem;
    border: none;
    background: none;
    color: var(--ds-foreground);
    border-radius: calc(var(--ds-radius) * 0.5);
    cursor: pointer;
}
.ds-editor-heading-item:hover { background: var(--ds-muted); }
.ds-editor-heading-item.active { background: var(--ds-accent); color: var(--ds-accent-foreground); }

/* Editor Content */
.ds-editor-content {
    color: var(--ds-foreground);
    line-height: 1.625;
    font-size: 0.9375rem;
}

.ds-editor-content:focus { outline: none; }

.ds-editor-content p { margin: 0 0 0.5rem 0 !important; padding: 0 !important; }
.ds-editor-content h1 { font-size: 2rem; font-weight: 700; margin: 1rem 0 0.5rem !important; }
.ds-editor-content h2 { font-size: 1.5rem; font-weight: 700; margin: 0.75rem 0 0.5rem !important; }
.ds-editor-content h3 { font-size: 1.25rem; font-weight: 600; margin: 0.75rem 0 0.375rem !important; }
.ds-editor-content h4 { font-size: 1.0625rem; font-weight: 600; margin: 0.5rem 0 0.25rem !important; }
.ds-editor-content ul, .ds-editor-content ol { padding-left: 1.5rem !important; margin: 0.5rem 0 !important; }
.ds-editor-content li { margin: 0.125rem 0 !important; }
.ds-editor-content li p { margin: 0 !important; }
.ds-editor-content a { color: var(--ds-accent-1); text-decoration: underline; }
/* Bilder nie breiter als der Editor — ein überbreites/zu großes Bild würde sonst den Editor
   aufblähen statt sich einzupassen (Layout-Bruch in Modals mit nachfolgenden Karten). */
.ds-editor-content img { max-width: 100%; height: auto; }
.ds-editor-content hr { border: none; border-top: 1px solid var(--ds-border); margin: 1rem 0; }
.ds-editor-content blockquote { border-left: 6px solid var(--ds-accent-1); padding-left: 1rem; margin: 0.5rem 0 !important; color: var(--ds-muted-foreground); }
.ds-editor-content code { font-family: ui-monospace, monospace; background: var(--ds-muted); padding: 0.125rem 0.375rem; border-radius: 3px; font-size: 0.875rem; }

/* Placeholder */
.ds-editor-content p.is-editor-empty:first-child::before {
    content: attr(data-placeholder);
    float: left;
    color: var(--ds-muted-foreground);
    pointer-events: none;
    height: 0;
}

/* Fullscreen */
/* Fullscreen: Wrap sitzt im #editorFullscreenHost (fixed, inset:0, z:9990) */
.ds-editor-fullscreen {
    width: 100% !important;
    height: 100% !important;
    border-radius: 0 !important;
    border: none !important;
    display: flex !important;
    flex-direction: column !important;
    background: var(--ds-background) !important;
    overflow: visible !important;
}

.ds-editor-fullscreen .ds-editor-toolbar {
    flex-shrink: 0;
}

.ds-editor-fullscreen > div:not(.ds-editor-toolbar):not(.ds-editor-source) {
    flex: 1 !important;
    overflow-y: auto !important;
    min-height: 0 !important;
}

.ds-editor-fullscreen .ProseMirror {
    min-height: 100% !important;
    height: auto !important;
}

.ds-editor-fullscreen .ds-editor-source {
    flex: 1;
    min-height: 0 !important;
}

.ds-editor-source-wrap {
    flex: 1;
    min-height: 300px;
    position: relative;
}

/* Syntax-Highlighted Code Editor */
.ds-source-editor {
    width: 100%;
    min-height: 400px;
    padding: 1rem 1rem 1rem 3.5rem;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    line-height: 1.7;
    background: var(--ds-background);
    color: var(--ds-foreground);
    border: none;
    outline: none;
    overflow: auto;
    white-space: pre;
    word-wrap: normal;
    tab-size: 2;
    counter-reset: line;
}

/* Zeilennummern per CSS Counter */
.ds-source-editor > .line {
    position: relative;
    min-height: 1.7em;
    padding-left: 0;
}

.ds-source-editor .line::before {
    counter-increment: line;
    content: counter(line);
    position: absolute;
    left: -2.75rem;
    width: 2rem;
    text-align: right;
    color: var(--ds-muted-foreground);
    opacity: 0.5;
    font-size: 0.75rem;
    user-select: none;
    pointer-events: none;
}

/* Syntax-Farben */
.ds-source-editor .tag { color: #22863a; }
.ds-source-editor .attr-name { color: #6f42c1; }
.ds-source-editor .attr-value { color: #032f62; }
.ds-source-editor .comment { color: var(--ds-muted-foreground); font-style: italic; }

@media (prefers-color-scheme: dark) {
    .ds-source-editor .tag { color: #7ee787; }
    .ds-source-editor .attr-name { color: #d2a8ff; }
    .ds-source-editor .attr-value { color: #a5d6ff; }
}

html.dark .ds-source-editor .tag { color: #7ee787; }
html.dark .ds-source-editor .attr-name { color: #d2a8ff; }
html.dark .ds-source-editor .attr-value { color: #a5d6ff; }

/* Color Picker Dropdown */
.ds-editor-color-bar {
    display: block;
    width: 14px;
    height: 3px;
    border-radius: 1px;
    margin-top: -2px;
}

.ds-editor-color-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 50;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 0.5rem;
    padding: 0.5rem;
    box-shadow: 0 4px 12px rgba(0,0,0,.15);
    min-width: 160px;
}

.ds-editor-color-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 4px;
}

.ds-editor-color-swatch {
    width: 28px;
    height: 28px;
    border-radius: 4px;
    border: 1px solid var(--ds-border);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.1s, box-shadow 0.1s;
}

.ds-editor-color-swatch:hover {
    transform: scale(1.15);
    box-shadow: 0 0 0 2px var(--ds-accent-1);
}

.ds-editor-color-none {
    background: var(--ds-background);
    color: var(--ds-muted-foreground);
    font-size: 0.75rem;
}

.ds-editor-source {
    width: 100%;
    min-height: 400px;
    padding: 1rem 1rem 1rem 3.5rem;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    line-height: 1.7;
    border: none;
    display: none; /* Hidden, Wert wird per JS gesynct */
    resize: vertical;
    tab-size: 2;
    white-space: pre;
    overflow-x: auto;
    outline: none;
    border-radius: 0;
}

/* === RESIZABLE IMAGE NODEVIEW === */
.ds-img-wrap {
    display: inline-block;
    position: relative;
    cursor: default;
    line-height: 0;
    max-width: 100%;
}
.ds-img-el {
    display: block;
    max-width: 100%;
    border-radius: 4px;
}
.ds-img-toolbar {
    display: none;
    position: absolute;
    /* IM Bild oben schwebend — außerhalb (top:-38px) wurde die Leiste bei einem
       Bild in der ersten Zeile vom Editor-Container abgeschnitten */
    top: 6px;
    left: 50%;
    transform: translateX(-50%);
    max-width: calc(100% - 12px);
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 6px;
    padding: 3px 5px;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 2px;
    z-index: 20;
    box-shadow: 0 2px 8px rgba(0,0,0,.2);
    line-height: normal;
}
.ds-img-selected .ds-img-toolbar { display: flex; }
.ds-img-toolbar-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 26px;
    padding: 0 4px;
    border: none;
    border-radius: 4px;
    background: transparent;
    color: var(--ds-foreground);
    cursor: pointer;
    font-size: 0.8125rem;
    transition: background 0.1s;
}
.ds-img-toolbar-btn:hover { background: var(--ds-accent); }
.ds-img-resize-handle {
    display: none;
    position: absolute;
    bottom: 4px;
    right: 4px;
    width: 12px;
    height: 12px;
    background: var(--ds-accent-1);
    border-radius: 2px;
    cursor: se-resize;
    opacity: 0.8;
}
.ds-img-selected .ds-img-resize-handle { display: block; }
.ds-img-active .ds-img-resize-handle { display: block; }
.ds-img-selected .ds-img-el {
    outline: 2px solid var(--ds-accent-1);
    outline-offset: 2px;
}

/* === GIPHY PICKER === */
.ds-editor-giphy-dropdown {
    position: absolute;
    top: 100%;
    /* Nach unten LINKS aufklappen — sonst läuft das 320px breite Panel
       in schmalen Modalen/Fenstern über den rechten Container-Rand hinaus */
    left: auto;
    right: 0;
    z-index: 50;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 0.5rem;
    padding: 0.5rem;
    box-shadow: 0 4px 12px rgba(0,0,0,.15);
    width: 320px;
}
.ds-editor-giphy-search {
    width: 100%;
    padding: 0.375rem 0.5rem;
    border: 1px solid var(--ds-border);
    border-radius: 0.375rem;
    background: var(--ds-background);
    color: var(--ds-foreground);
    font-size: 0.875rem;
    margin-bottom: 0.5rem;
    outline: none;
}
.ds-editor-giphy-search:focus { border-color: var(--ds-accent-1); }
.ds-editor-giphy-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    max-height: 200px;
    overflow-y: auto;
}
.ds-editor-giphy-grid img {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: 4px;
    cursor: pointer;
    transition: transform 0.1s, box-shadow 0.1s;
}
.ds-editor-giphy-grid img:hover {
    transform: scale(1.05);
    box-shadow: 0 0 0 2px var(--ds-accent-1);
}
.ds-editor-giphy-status {
    text-align: center;
    font-size: 0.75rem;
    color: var(--ds-muted-foreground);
    padding: 0.5rem 0;
}

.ds-combo-item {
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    cursor: pointer;
    transition: background 0.1s;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--ds-border);
    color: var(--ds-foreground);
}

.ds-combo-item i { color: var(--ds-accent-1); }

/* === EMOJI PICKER === */
.ds-editor-emoji-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 100;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 0.5rem;
    padding: 0.5rem;
    box-shadow: 0 4px 12px rgba(0,0,0,.15);
    width: 300px;
}
.ds-editor-emoji-search {
    width: 100%;
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--ds-border);
    border-radius: 0.375rem;
    background: var(--ds-background);
    color: var(--ds-foreground);
    font-size: 0.8rem;
    margin-bottom: 0.4rem;
    outline: none;
}
.ds-editor-emoji-search:focus { border-color: var(--ds-accent-1); }
.ds-editor-emoji-tabs {
    display: flex;
    gap: 2px;
    margin-bottom: 0.4rem;
    flex-wrap: wrap;
}
.ds-editor-emoji-tab {
    padding: 2px 5px;
    border: 1px solid transparent;
    border-radius: 4px;
    background: transparent;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    transition: background 0.1s;
}
.ds-editor-emoji-tab:hover { background: var(--ds-accent); }
.ds-editor-emoji-tab.active { background: var(--ds-accent); border-color: var(--ds-border); }
.ds-editor-emoji-grid {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    gap: 1px;
    max-height: 200px;
    overflow-y: auto;
}
.ds-editor-emoji-btn {
    width: 100%;
    aspect-ratio: 1;
    border: none;
    background: transparent;
    cursor: pointer;
    font-size: 1.2rem;
    line-height: 1;
    border-radius: 4px;
    transition: background 0.1s;
    padding: 2px;
}
.ds-editor-emoji-btn:hover { background: var(--ds-accent); }

/* === FORMULAR-ELEMENTE DROPDOWN === */
.ds-editor-form-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 100;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 0.5rem;
    padding: 0.25rem;
    box-shadow: 0 4px 12px rgba(0,0,0,.15);
    min-width: 200px;
}
.ds-editor-form-item {
    display: flex;
    align-items: center;
    width: 100%;
    border: none;
    background: transparent;
    color: var(--ds-foreground);
    padding: 0.4rem 0.6rem;
    border-radius: 0.375rem;
    font-size: 0.85rem;
    cursor: pointer;
    transition: background 0.1s;
    text-align: left;
}
.ds-editor-form-item:hover { background: var(--ds-accent); }

/* === MAIL-BAUSTEINE DROPDOWN (editorBase._buildBlocksMenu) === */
.ds-editor-blocks-dropdown { min-width: 230px; max-height: 70vh; overflow-y: auto; }
.ds-editor-blocks-head {
    padding: 0.5rem 0.6rem 0.2rem;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ds-muted-foreground);
}
.ds-editor-blocks-ico { width: 1.6rem; margin-right: 0.55rem; text-align: center; }
/* Vorschau-Farben kommen aus den Varianten (Inline), wie später im Mail-HTML */
.ds-editor-blocks-swatch {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.35rem;
    margin-right: 0.55rem;
    border-left: 3px solid;
    border-radius: 3px;
    font-size: 0.75rem;
}
.ds-editor-blocks-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; padding: 0.2rem 0.6rem 0.45rem; }
.ds-editor-blocks-badge {
    border: none;
    border-radius: 10px;
    padding: 1px 8px;
    font-size: 0.75rem;
    line-height: 18px;
    cursor: pointer;
}
.ds-editor-blocks-badge:hover { filter: brightness(0.95); }

/* === DROPDOWN CONFIG MODAL === */
.ds-dd-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: rgba(0,0,0,.4);
    display: flex;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(2px);
}
.ds-dd-modal {
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 0.75rem;
    box-shadow: 0 8px 32px rgba(0,0,0,.25);
    width: 90%;
    max-width: 500px;
    max-height: 80vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.ds-dd-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--ds-border);
}
.ds-dd-modal-header h5 { margin: 0; font-size: 1.1rem; }
.ds-dd-modal-body {
    padding: 1.25rem;
    overflow-y: auto;
    flex: 1;
}
.ds-dd-modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    padding: 0.75rem 1.25rem;
    border-top: 1px solid var(--ds-border);
}
.ds-dd-drag-over {
    border-top: 2px solid var(--ds-accent-1, #3b82f6) !important;
}

/* === CHART CARDS (shadcn style) === */
.ds-chart-card {
    background: var(--ds-card);
    padding: 0;
}

.ds-chart-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    padding: 1.25rem 1.25rem 0;
}

.ds-chart-title {
    font-size: 0.975rem;
    font-weight: 600;
    color: var(--ds-foreground);
    letter-spacing: -0.01em;
}

.ds-chart-subtitle {
    font-size: 0.8rem;
    color: var(--ds-muted-foreground);
    margin-top: 0.125rem;
}

.ds-chart-kpi {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.125rem;
}

.ds-chart-kpi-value {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--ds-success);
    letter-spacing: -0.02em;
}

.ds-chart-kpi-label {
    font-size: 0.7rem;
    color: var(--ds-muted-foreground);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.ds-chart-body {
    padding: 0.75rem 1rem;
    position: relative;
}

.ds-chart-footer {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.75rem 1.25rem;
    border-top: 1px solid var(--ds-border);
    font-size: 0.8rem;
    color: var(--ds-muted-foreground);
}

/* Gauge overlay */
.ds-chart-gauge-wrap {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    max-width: 200px;
    margin: 0 auto;
}

.ds-chart-gauge-center {
    position: absolute;
    bottom: 8%;
    left: 50%;
    transform: translateX(-50%);
    text-align: center;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.ds-chart-gauge-value {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--ds-foreground);
    letter-spacing: -0.03em;
    line-height: 1;
}

.ds-chart-gauge-label {
    font-size: 0.7rem;
    color: var(--ds-muted-foreground);
}

/* Custom legend for donut */
.ds-chart-legend-custom {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    padding: 0.75rem 1.25rem;
}

.ds-chart-legend-item {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.8rem;
}

.ds-chart-legend-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.ds-chart-legend-label {
    color: var(--ds-muted-foreground);
}

.ds-chart-legend-value {
    font-weight: 600;
    color: var(--ds-foreground);
}

/* === SHADCN MODAL OVERRIDES === */
/* Modals werden von Bootstrap an <body> teleportiert, daher kein .ds-main scope */
.modal {
    position: fixed !important;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh !important;   /* Rückfall — siehe dvh-Block direkt darunter */
    overflow-x: hidden;
    overflow-y: auto;
}

/* `100vh` ist auf Mobilgeräten die Höhe OHNE eingeblendete Adressleiste und damit
   GRÖSSER als das, was man sieht. Am Android-Fold gemessen (05.09.2026):
   100vh = 748 px, sichtbar = 692 px. Jedes vollflächige Modal ragte also 56 px
   nach unten aus dem Bild — bei der Konsole genau der Bereich, in dem die Zeile
   steht, in die man gerade tippt.
   `dvh` ist exakt der sichtbare Bereich (gemessen 692 px). Kleiner als `vh` kann
   es nie werden, größer auch nicht: Ein Modal wird dadurch nirgends kleiner als
   nötig, nur passgenau. Am Schreibtisch sind beide Werte gleich.
   Das `!important` muss mitwandern — sonst gewinnt die Regel darüber. */
@supports (height: 100dvh) {
    .modal { height: 100dvh !important; }
}
html.modal-freeze {
    overflow: hidden !important;
    position: fixed !important;
    width: 100%;
    top: var(--modal-scroll-y, 0);
}
.modal-content {
    background: var(--ds-modal-surface);
    color: var(--ds-foreground);
    border: none;
    border-radius: 14px;
    box-shadow:
        0 0 0 1px color-mix(in srgb, var(--ds-border) 70%, transparent),
        0 30px 90px -20px rgba(0,0,0,.45);
    overflow: hidden;
    position: relative;
}
html.dark .modal-content {
    box-shadow:
        0 0 0 1px rgba(255,255,255,.05),
        0 30px 90px -20px rgba(0,0,0,.65);
}
/* Premium entrance animation */
.modal.fade .modal-dialog {
    transform: scale(0.94) translateY(16px);
    opacity: 0;
    filter: blur(4px);
    transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1),
                opacity 200ms ease,
                filter 280ms ease;
}
.modal.show .modal-dialog {
    /* WICHTIG: im show-Zustand transform/filter = 'none' (NICHT scale(1)/blur(0)).
       Ein non-none transform ODER filter macht .modal-dialog zum Containing-Block für
       position:fixed-Nachfahren → ein fixed positioniertes Popover (ds-select-Dropdown) säße
       relativ zum Dialog statt zum Viewport ("hängt in der Luft"). 'none' ist optisch identisch
       und interpoliert die Entrance-Animation gleich (scale(0.94)/blur(4px) → none == → identity). */
    transform: none;
    opacity: 1;
    filter: none;
}
.modal-header {
    padding: 1.1rem 1.25rem 0.9rem;
    border-bottom: none !important;
}
.modal .modal-title {
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: -0.015em;
    color: var(--ds-foreground) !important;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.modal .modal-title i {
    font-size: 1.05rem;
    color: var(--ds-accent-1) !important;
}
.modal-body {
    padding: 0.25rem 1.25rem 0.25rem;
    color: var(--ds-foreground);
}
.modal-body input,
.modal-body textarea,
.modal-body select {
    transition: box-shadow 150ms ease, border-color 150ms ease;
}
.modal-footer {
    padding: 0.5rem 1.25rem 0.875rem;
    border-top: none !important;
    gap: 0.5rem;
    justify-content: flex-end;
    background: transparent;
}
/* Primary-Action im Modal-Footer standardmäßig solid — volle Präsenz als CTA */
.modal-footer .ds-btn-primary:not(.ds-btn-outline):not(.ds-btn-ghost):not(.ds-btn-link) {
    background: var(--ds-primary);
    color: var(--ds-primary-foreground);
    border-color: transparent;
}
.modal-footer .ds-btn-primary:not(.ds-btn-outline):not(.ds-btn-ghost):not(.ds-btn-link):hover {
    background: color-mix(in srgb, var(--ds-primary) 85%, black);
    color: var(--ds-primary-foreground);
    box-shadow: 0 3px 10px color-mix(in srgb, var(--ds-primary) 30%, transparent);
    transform: translateY(-1px);
}

/* Section-Card im Modal — helle Fläche über dem Modal-Body (Inverted Elevation) */
.ds-modal-section {
    background: var(--ds-modal-card);
    border-radius: 10px;
    padding: 0.75rem 1rem;
    box-shadow:
        0 1px 2px rgba(0,0,0,.04),
        0 2px 6px -2px rgba(0,0,0,.06);
}
html.dark .ds-modal-section {
    box-shadow:
        0 0 0 1px rgba(255,255,255,.04),
        0 1px 2px rgba(0,0,0,.3),
        0 3px 8px -2px rgba(0,0,0,.35);
}
.ds-modal-section + .ds-modal-section { margin-top: 0.625rem; }
/* Sections nebeneinander (Grid/Flex): den Abstand macht der gap. Ohne diesen Reset bekäme
   die zweite Section zusätzlich den Geschwister-Margin und stünde versetzt zur ersten. */
.ds-modal-section-grid > .ds-modal-section + .ds-modal-section { margin-top: 0; }
/* Flush-Variante: Section ohne Innen-Padding, für eingebettete Toolbars/Listen die selbst padden */
.ds-modal-section-flush { padding: 0; overflow: hidden; }
.ds-modal-section-toolbar > .ds-modal-toolbar {
    border-bottom: 0;
    background: transparent;
    border-radius: inherit;
}
.ds-modal-section-toolbar .ds-modal-toolbar-search {
    background: var(--ds-modal-surface);
    border-color: color-mix(in srgb, var(--ds-border) 60%, transparent);
}
/* Liste mit separaten Task-Cards auf grauem Modal-Body (nicht in weißer Section) */
.ds-modal-list-cards {
    padding: 0.625rem 0 0;
    gap: 0.625rem;
}
/* ds-card im Modal-Body an Section-Look angleichen (einheitliche Elevation) */
.modal-body .ds-card,
.modal-body-scrollable .ds-card {
    background: var(--ds-modal-card);
    border: none;
    border-radius: 10px;
    margin-bottom: 0;
    box-shadow:
        0 1px 2px rgba(0,0,0,.04),
        0 2px 6px -2px rgba(0,0,0,.06);
}
html.dark .modal-body .ds-card,
html.dark .modal-body-scrollable .ds-card {
    box-shadow:
        0 0 0 1px rgba(255,255,255,.04),
        0 1px 2px rgba(0,0,0,.3),
        0 3px 8px -2px rgba(0,0,0,.35);
}
/* Abstand zwischen benachbarten Cards/Sections im Modal-Body */
.modal-body .ds-card + .ds-card,
.modal-body .ds-card + .ds-modal-section,
.modal-body .ds-modal-section + .ds-card,
.modal-body-scrollable .ds-card + .ds-card,
.modal-body-scrollable .ds-card + .ds-modal-section,
.modal-body-scrollable .ds-modal-section + .ds-card {
    margin-top: 0.625rem;
}
/* Abschnitts-/Feldtitel im Modal (control-label h5, modals.md §6b) wie der Abschnittskopf darunter — der
   ToDo-Gold-Standard app-weit (max 07.11.2026, Arc-Modal-Durchsicht). Vorher galt das nur per ID in ToDo;
   überall sonst griff Bootstraps .h5 (20 px/500) und die Modals wirkten wie „alter Stand“. */
.modal .modal-body .control-label.h5 {
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    color: var(--ds-foreground);
    margin-bottom: 0.5rem;
}
.modal .modal-body .control-label.h5 > i { font-size: 1rem; color: var(--ds-accent-1); }
.modal .modal-body .control-label.h5 > i:not([class*="me-"]) { margin-right: 0.45rem; }

.ds-modal-section-header {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin-bottom: 0.625rem;
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    color: var(--ds-foreground);
}
.ds-modal-section-header i {
    font-size: 1rem;
    color: var(--ds-accent-1);
}
.ds-modal-section-header .ds-sub {
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--ds-muted-foreground);
    margin-left: auto;
}
/* Inputs in Section-Cards auf Modal-Body-Ton zurücksetzen (eingeprägte 3. Ebene) */
.ds-modal-section input:not([type=checkbox]):not([type=radio]),
.ds-modal-section textarea,
.ds-modal-section select {
    background: var(--ds-modal-surface);
    border-color: color-mix(in srgb, var(--ds-border) 60%, transparent);
}
.ds-modal-section input:not([type=checkbox]):not([type=radio]):focus,
.ds-modal-section textarea:focus,
.ds-modal-section select:focus {
    background: var(--ds-modal-card);
    border-color: var(--ds-accent-1);
}
.modal .btn-close {
    width: 2rem;
    height: 2rem;
    border-radius: 0.375rem;
    opacity: 1;
    transition: all 0.15s;
    padding: 0;
    background: transparent;
    background-image: none !important;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}
.modal .btn-close::before {
    content: '\2715';
    font-size: 1.1rem;
    font-weight: 400;
    color: var(--ds-muted-foreground);
    line-height: 1;
}
.modal .btn-close:hover {
    background-color: var(--ds-muted);
}
.modal .btn-close:hover::before {
    color: var(--ds-foreground);
}
/* Modal Backdrop */
.modal-backdrop { background: rgba(0,0,0,.6); backdrop-filter: blur(8px); }
/* Gestapelte Backdrops (Sub-Dialog) — zweiter/dritter Layer nur leicht dämpfen,
   sonst wird's doppelt dunkel. Der darunterliegende Modal wird sanft entfokussiert. */
.modal-backdrop ~ .modal-backdrop {
    background: rgba(0,0,0,.35);
    backdrop-filter: blur(4px);
}
/* Sub-Modal (gestapelt): stärkere Erhebung, damit Unterdialog klar über Parent-Modal schwebt */
.modal.show ~ .modal.show .modal-content {
    box-shadow:
        0 0 0 1px color-mix(in srgb, var(--ds-border) 70%, transparent),
        0 40px 120px -20px rgba(0,0,0,.6);
}
html.dark .modal.show ~ .modal.show .modal-content {
    box-shadow:
        0 0 0 1px rgba(255,255,255,.06),
        0 40px 120px -20px rgba(0,0,0,.8);
}

/* Scrollable Modal helpers — content: flex column with max-height; body: flex-grow + scroll */
.modal-content-scrollable {
    display: flex;
    flex-direction: column;
    /* 3.5rem = Standard-.modal-dialog-Marge (1.75rem oben+unten). Ohne den Abzug ragt
       content(100vh)+Marge über den Viewport -> .modal bekommt einen 2. (Outer-)Scrollbalken
       zusätzlich zum Body-Inner-Scroll = Doppelscroll. */
    max-height: calc(100vh - 3.5rem);
    /* iOS Safari: 100vh zählt den Bereich hinter den Browser-Leisten mit -> Footer wird abgeschnitten.
       dvh = sichtbare (dynamische) Viewport-Höhe; vh bleibt Fallback für alte Browser. */
    max-height: calc(100dvh - 3.5rem);
}
/* Fullscreen-Modi haben KEINE Dialog-Marge -> volle Höhe, sonst Lücke unten. */
.modal-fullscreen .modal-content-scrollable { max-height: 100vh; max-height: 100dvh; }
@media (max-width: 575.98px)  { .modal-fullscreen-sm-down  .modal-content-scrollable { max-height: 100vh; max-height: 100dvh; } }
@media (max-width: 767.98px)  { .modal-fullscreen-md-down  .modal-content-scrollable { max-height: 100vh; max-height: 100dvh; } }
@media (max-width: 991.98px)  { .modal-fullscreen-lg-down  .modal-content-scrollable { max-height: 100vh; max-height: 100dvh; } }
@media (max-width: 1199.98px) { .modal-fullscreen-xl-down  .modal-content-scrollable { max-height: 100vh; max-height: 100dvh; } }
@media (max-width: 1399.98px) { .modal-fullscreen-xxl-down .modal-content-scrollable { max-height: 100vh; max-height: 100dvh; } }
/* Fullscreen durchsetzen: mehrere Module setzen die Dialog-Breite per ID
   (`#XyzModal .modal-dialog { max-width: min(1600px, 96vw) }`). ID-Spezifität (1,0,0) schlägt die
   Bootstrap-Klasse (0,1,0) — der Dialog behielt deshalb UNTER dem Breakpoint seinen Rand, und es
   sah aus, als gäbe es gar keinen Vollbild-Modus. Diese Resets ziehen die Fullscreen-Geometrie
   wieder nach vorn; `!important` ist hier der einzige Weg, der ohne Kenntnis jeder Modul-ID gilt. */
.modal-fullscreen { max-width: none !important; width: 100% !important; margin: 0 !important; }
.modal-fullscreen .modal-content-scrollable { max-height: 100dvh !important; }
@media (max-width: 575.98px)  { .modal-fullscreen-sm-down  { max-width: none !important; width: 100% !important; margin: 0 !important; height: 100%; }
                                .modal-fullscreen-sm-down  .modal-content-scrollable { max-height: 100dvh !important; } }
@media (max-width: 767.98px)  { .modal-fullscreen-md-down  { max-width: none !important; width: 100% !important; margin: 0 !important; height: 100%; }
                                .modal-fullscreen-md-down  .modal-content-scrollable { max-height: 100dvh !important; } }
@media (max-width: 991.98px)  { .modal-fullscreen-lg-down  { max-width: none !important; width: 100% !important; margin: 0 !important; height: 100%; }
                                .modal-fullscreen-lg-down  .modal-content-scrollable { max-height: 100dvh !important; } }
@media (max-width: 1199.98px) { .modal-fullscreen-xl-down  { max-width: none !important; width: 100% !important; margin: 0 !important; height: 100%; }
                                .modal-fullscreen-xl-down  .modal-content-scrollable { max-height: 100dvh !important; } }
@media (max-width: 1399.98px) { .modal-fullscreen-xxl-down { max-width: none !important; width: 100% !important; margin: 0 !important; height: 100%; }
                                .modal-fullscreen-xxl-down .modal-content-scrollable { max-height: 100dvh !important; } }
/* Vollbild-Modale scrollen ausschliesslich INNEN (.modal-body-scrollable). Der aeussere .modal
   (Bootstrap: overflow-y:auto) darf dann gar nicht mitscrollen: auf iOS/WebKit uebernimmt er am
   Ende einer Wischbewegung die Geste und setzt seine Position zurueck — der Inhalt springt
   sichtbar an den Anfang (gemeldet 10.08.2026 aus der iPhone-PWA: Termin im Kalender aufgezogen,
   im Termin-Modal "immer wieder nach oben gesprungen"; Chrome/Android zeigt es nicht). Zweiter
   Effekt derselben Ursache: die Kopfzeile samt Schliessen-X liesse sich wegwischen (siehe
   #LinuxConsoleModal). Ungefaehrlich, weil die Hoehe hier per max-height:100dvh gedeckelt ist —
   es kann nichts ueberlaufen, was `hidden` unerreichbar machen wuerde. */
.modal:has(> .modal-dialog.modal-fullscreen) { overflow: hidden; }
@media (max-width: 575.98px)  { .modal:has(> .modal-dialog.modal-fullscreen-sm-down)  { overflow: hidden; } }
@media (max-width: 767.98px)  { .modal:has(> .modal-dialog.modal-fullscreen-md-down)  { overflow: hidden; } }
@media (max-width: 991.98px)  { .modal:has(> .modal-dialog.modal-fullscreen-lg-down)  { overflow: hidden; } }
@media (max-width: 1199.98px) { .modal:has(> .modal-dialog.modal-fullscreen-xl-down)  { overflow: hidden; } }
@media (max-width: 1399.98px) { .modal:has(> .modal-dialog.modal-fullscreen-xxl-down) { overflow: hidden; } }
.modal-body-scrollable {
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 0;
    /* Overscroll NICHT an den aeusseren .modal/den Body weiterreichen. Ohne das kettet WebKit
       die Wischbewegung am Ende des Inhalts nach aussen — in der iOS-PWA (kein Adressleisten-
       Puffer, viewport-fit=cover) ist das der sichtbare Ruecksprung. Gleiches Mittel wie bei
       ds-calendar, UC-Chat und .ds-dropdown-group. */
    overscroll-behavior: contain;
}
/* Viele Modale rendern Html.BeginForm() als <form> direkt zwischen .modal-content-scrollable und
   .modal-body-scrollable/.modal-footer (Form umschließt Body+Footer). Das <form> ist dabei selbst
   ein Flex-Kind von .modal-content-scrollable, aber ohne eigene Flex-Regeln — es wächst auf seine
   natürliche Inhaltshöhe statt sich der max-height des Contents unterzuordnen, wodurch .modal-body-
   scrollable NIE zum Scrollen kommt und .modal-footer unterhalb des sichtbaren/abgeschnittenen
   Bereichs landet (unerreichbar, "keine Buttons sichtbar"). Das <form> muss dieselbe Flex-Column-
   Kette fortsetzen wie .modal-content-scrollable selbst. */
.modal-content-scrollable > form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* ============================================================
   MENU MODAL (Dock → Menü)
   _MenuModal.cshtml verwendet Legacy-Klassen (card-modal-menu,
   menu-section-badge, btn-close-custom, active-card). Im alten
   Layout kommen die Styles aus site.css/lighttheme/darktheme,
   die das Tailwind-Layout bewusst nicht laedt. Hier portieren
   wir den Look mit DS-Tokens, damit Dark/Light automatisch
   funktionieren.
   ============================================================ */

/* (Legacy-MenuModal-Transparenz entfernt: Das neue iOS-Launcher-Panel
   `.menu-launcher-panel` (menu-launcher.css) bringt seine eigene
   undurchsichtige Fläche mit. Die alte `background:transparent !important`-
   Regel überdeckte sie via ID-Spezifität → Panel unsichtbar/Kontrast kaputt.) */

/* Section-Badge — Pill-Heading je Modulgruppe ("Team", "Kommunikation", ...) */
.menu-section-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    background: color-mix(in srgb, var(--ds-card) 85%, transparent);
    color: var(--ds-foreground);
    border: 1px solid color-mix(in srgb, var(--ds-border) 70%, transparent);
    border-radius: 999px;
    padding: 0.55rem 1.4rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
    transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}
.menu-section-badge i { color: var(--ds-accent-1); }
.menu-section-badge:hover {
    background: color-mix(in srgb, var(--ds-card) 95%, transparent);
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
}

/* Custom Close Button (oben rechts im MenuModal) */
.btn-close-custom {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    background: color-mix(in srgb, var(--ds-card) 85%, transparent);
    color: var(--ds-foreground);
    border: 1px solid color-mix(in srgb, var(--ds-border) 70%, transparent);
    border-radius: 999px;
    padding: 0.5rem 1.1rem;
    font-weight: 500;
    line-height: 1;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
    cursor: pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease, color 0.2s ease;
}
.btn-close-custom:hover {
    background: color-mix(in srgb, var(--ds-card) 95%, transparent);
    color: var(--ds-foreground);
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
}
.btn-close-custom i { color: var(--ds-foreground); }

/* Legacy-Bootstrap-Modal-Karten (.card-modal) im Tailwind-Layout: ohne darktheme.css fielen sie auf
   Bootstrap-Weiß zurück → fast weißer Text (--ds-foreground) auf weißer Karte = unlesbar. Auf die
   Theme-Tokens heben (wirkt Hell + Dunkel). Betrifft u.a. ToDo Termin-/Fällig-/Detail-Modal. */
.card-modal {
    background: var(--ds-card);
    color: var(--ds-foreground);
    border: 1px solid color-mix(in srgb, var(--ds-border) 70%, transparent);
    border-radius: 14px;
}
.card-modal .card-body { color: var(--ds-foreground); }
.card-modal h5,
.card-modal .control-label,
.card-modal label,
.card-modal .form-label { color: var(--ds-foreground); }

/* Native Bootstrap-Formfelder (.form-control/.form-select) im Tailwind-Layout themen — sonst fielen sie
   auf Bootstrap-Weiß zurück (weißes Feld im dunklen Modal, vgl. card-modal). Auf die Design-Tokens heben,
   wirkt Hell + Dunkel automatisch. Der form-select-Pfeil als neutrales Grau (auf hell UND dunkel sichtbar). */
.form-control, .form-select {
    background-color: var(--ds-background);
    color: var(--ds-foreground);
    border-color: var(--ds-input);
}
.form-control:focus, .form-select:focus {
    background-color: var(--ds-background);
    color: var(--ds-foreground);
    border-color: var(--ds-accent-1);
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--ds-accent-1) 25%, transparent);
}
/* Platzhalter bewusst heller als gewöhnlicher Muted-Text — sonst (Light-Theme --ds-muted-foreground #2e2e2e)
   liest sich der Placeholder wie ein bereits ausgefüllter Wert. Mix Richtung Feld-Hintergrund hält es theme-sicher. */
.form-control::placeholder { color: color-mix(in srgb, var(--ds-muted-foreground) 50%, var(--ds-background)); opacity: 1; }
/* Der Pfeil muss OHNE Bootstrap stehen: Gastseiten (öffentliche Formulare, Personalfragebogen, Bewerbung,
   Buchung …) laden kein bootstrap.css — nur das Bild allein kachelte dort quer über das ganze Feld
   („lauter Spitzklammern") und der Browser malte seinen eigenen Pfeil dazu. */
.form-select {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23888888' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right .75rem center;
    background-size: 16px 12px;
    padding-right: 2.25rem;
}
.form-select-sm { background-position: right .5rem center; padding-right: 2rem; }
/* Listenfeld (mehrfach bzw. size > 1): kein Pfeil, wie bei Bootstrap. */
.form-select[multiple], .form-select[size]:not([size="1"]) { background-image: none; padding-right: .75rem; }
.form-select option { background-color: var(--ds-card); color: var(--ds-foreground); }

/* Schnell-Auswahl-Chips unter Datum/Zeit-Feldern (ds-datepicker quick="true") — kompakte Pillen. */
.ds-quick-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.4rem; }
.ds-quick-chip {
    font-size: 0.75rem; line-height: 1; padding: 0.35rem 0.7rem; border-radius: 9999px;
    border: 1px solid var(--ds-input); background: var(--ds-background); color: var(--ds-foreground);
    cursor: pointer; white-space: nowrap;
    transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.ds-quick-chip:hover {
    border-color: var(--ds-accent-1); color: var(--ds-accent-1);
    background: color-mix(in srgb, var(--ds-accent-1) 12%, transparent);
}
/* Wochentag-Chips (Mo–So): schmaler als die Text-Chips, damit alle 7 in eine Zeile passen */
.ds-quick-chip-day { padding: 0.35rem 0.45rem; min-width: 1.9rem; text-align: center; }

/* ============================================================================
   CHIP-BUTTONS — kleine Outline-Chips für Filter / Tags / Schnellaktionen
   INNERHALB der Module (ToDo). Kompakter und eckiger als die runden Pillen
   (.ds-quick-chip / .ds-badge mit border-radius:9999px) — nutzen den moderaten
   ds-btn-Radius, damit sie zum Rest der ToDo passen.
   ============================================================================ */
.ds-chip-row { display: flex; flex-wrap: wrap; gap: 0.375rem; align-items: center; }

.ds-chip-btn {
    display: inline-flex; align-items: center; gap: 0.3rem;
    height: 1.5rem; padding: 0 0.55rem;
    font-size: 0.72rem; font-weight: 500; line-height: 1; white-space: nowrap;
    border-radius: 0.375rem;
    border: 1px solid var(--ds-input);
    background: transparent;
    color: var(--ds-foreground);
    cursor: pointer;
    text-decoration: none;   /* Chips die als <a> gerendert werden (z.B. „Öffnen") nicht unterstreichen */
    transition: background .12s ease, border-color .12s ease, color .12s ease;
    -webkit-user-select: none; user-select: none;
}
.ds-chip-btn:hover { text-decoration: none; }
.ds-chip-btn:hover {
    border-color: var(--ds-accent-1);
    color: var(--ds-accent-1);
    background: color-mix(in srgb, var(--ds-accent-1) 10%, transparent);
}
.ds-chip-btn:focus-visible { outline: 2px solid var(--ds-ring); outline-offset: 1px; }
.ds-chip-btn i { font-size: 0.82em; line-height: 1; }
.ds-chip-btn:disabled, .ds-chip-btn.is-disabled { opacity: .5; cursor: not-allowed; }

/* Aktiv / ausgewählt (Toggle-Zustand) — gefüllt im Akzentton */
.ds-chip-btn.is-active,
.ds-chip-btn[aria-pressed="true"] {
    background: var(--ds-accent-1);
    border-color: var(--ds-accent-1);
    /* !important: Die Textfarben-Resets für .ds-main bzw. `body > .modal` (button/span, Zeile ~452/467)
       sind spezifischer und färbten aktive Chips dunkel — dunkle Schrift auf Akzent-Blau
       (MyHub-Filter „Aktiv", Kontakt-Art „Person", 30.09.2026). */
    color: #fff !important;
}
.ds-chip-btn.is-active span:not([class*="ds-badge"]),
.ds-chip-btn[aria-pressed="true"] span:not([class*="ds-badge"]) { color: inherit !important; }

/* Größe XS — noch kompakter (z.B. für dichte Listen/Karten) */
.ds-chip-btn-xs { height: 1.25rem; padding: 0 0.4rem; font-size: 0.65rem; border-radius: 0.3rem; gap: 0.25rem; }

/* Farbvarianten — getönter Outline; aktiv = volle Farbe.
   Rand leicht eingefärbt (45% der Farbe gemischt mit dem neutralen Input-Rand). */
.ds-chip-btn-primary  { color: var(--ds-primary);     border-color: color-mix(in srgb, var(--ds-primary) 45%, var(--ds-input)); }
.ds-chip-btn-success  { color: var(--ds-success);     border-color: color-mix(in srgb, var(--ds-success) 45%, var(--ds-input)); }
.ds-chip-btn-warning  { color: var(--ds-warning);     border-color: color-mix(in srgb, var(--ds-warning) 45%, var(--ds-input)); }
.ds-chip-btn-danger   { color: var(--ds-destructive); border-color: color-mix(in srgb, var(--ds-destructive) 45%, var(--ds-input)); }
.ds-chip-btn-info     { color: var(--ds-info);        border-color: color-mix(in srgb, var(--ds-info) 45%, var(--ds-input)); }

.ds-chip-btn-primary:hover { color: var(--ds-primary);     border-color: var(--ds-primary);     background: color-mix(in srgb, var(--ds-primary) 10%, transparent); }
.ds-chip-btn-success:hover { color: var(--ds-success);     border-color: var(--ds-success);     background: color-mix(in srgb, var(--ds-success) 10%, transparent); }
.ds-chip-btn-warning:hover { color: var(--ds-warning);     border-color: var(--ds-warning);     background: color-mix(in srgb, var(--ds-warning) 10%, transparent); }
.ds-chip-btn-danger:hover  { color: var(--ds-destructive); border-color: var(--ds-destructive); background: color-mix(in srgb, var(--ds-destructive) 10%, transparent); }
.ds-chip-btn-info:hover    { color: var(--ds-info);        border-color: var(--ds-info);        background: color-mix(in srgb, var(--ds-info) 10%, transparent); }

.ds-chip-btn-primary.is-active { background: var(--ds-primary);     border-color: var(--ds-primary);     color: #fff; }
.ds-chip-btn-success.is-active { background: var(--ds-success);     border-color: var(--ds-success);     color: #fff; }
.ds-chip-btn-warning.is-active { background: var(--ds-warning);     border-color: var(--ds-warning);     color: #fff; }
.ds-chip-btn-danger.is-active  { background: var(--ds-destructive); border-color: var(--ds-destructive); color: #fff; }
.ds-chip-btn-info.is-active    { background: var(--ds-info);        border-color: var(--ds-info);        color: #fff; }

/* Entfernbar — kleines x rechts (Tag-Stil). Klick aufs x kann separat behandelt werden. */
.ds-chip-btn .ds-chip-x {
    display: inline-flex; align-items: center; justify-content: center;
    margin-right: -0.15rem; margin-left: 0.1rem;
    width: 0.9rem; height: 0.9rem; border-radius: 9999px;
    font-size: 0.7em; opacity: .65;
}
.ds-chip-btn .ds-chip-x:hover { opacity: 1; background: color-mix(in srgb, currentColor 18%, transparent); }

/* Farbpunkt-Variante (z.B. Kalenderfarbe/Kategorie als Chip) */
.ds-chip-btn .ds-chip-dot { width: 0.5rem; height: 0.5rem; border-radius: 9999px; flex: 0 0 auto; }

/* ── Chip-Button-Gruppe — verbundene Chips für Aktionen an einem Eintrag
   (z.B. Termin: „Bearbeiten" / „Abhaken"). Gemeinsame Ränder, nur außen abgerundet. ── */
.ds-chip-group { display: inline-flex; }
.ds-chip-group .ds-chip-btn {
    border-radius: 0;
    margin-left: -1px;          /* Ränder überlappen → keine doppelte Linie */
    position: relative;
}
.ds-chip-group .ds-chip-btn:first-child { border-radius: 0.375rem 0 0 0.375rem; margin-left: 0; }
.ds-chip-group .ds-chip-btn:last-child  { border-radius: 0 0.375rem 0.375rem 0; }
.ds-chip-group .ds-chip-btn:only-child  { border-radius: 0.375rem; }
/* Dropdown als letztes Glied einer Knopfgruppe („Details | Bearbeiten | Aktionen ▾"): Bootstrap braucht den
   .dropdown-Wrapper, der Auslöser soll trotzdem nahtlos anschließen und rechts rund sein.
   display:flex am Wrapper: als Block setzte er den inline-flex-Auslöser auf die Textgrundlinie → ~1px tiefer
   als die Nachbarn, die Gruppe hing schief (Benutzer-Liste, 31.10.2026). */
.ds-chip-group > .dropdown { display: flex; }
.ds-chip-group > .dropdown > .ds-chip-btn { margin-left: -1px; border-radius: 0; }
.ds-chip-group > .dropdown:last-child > .ds-chip-btn { border-radius: 0 0.375rem 0.375rem 0; }
/* aktiver/gehoverter Chip hebt seinen (farbigen) Rand über die Nachbarn */
.ds-chip-group .ds-chip-btn:hover,
.ds-chip-group .ds-chip-btn:focus-visible,
.ds-chip-group .ds-chip-btn.is-active { z-index: 1; }
/* XS-Gruppe: außen kleinerer Radius passend zu ds-chip-btn-xs */
.ds-chip-group:has(.ds-chip-btn-xs) .ds-chip-btn:first-child { border-radius: 0.3rem 0 0 0.3rem; }
.ds-chip-group:has(.ds-chip-btn-xs) .ds-chip-btn:last-child  { border-radius: 0 0.3rem 0.3rem 0; }

/* Native Bootstrap-Dropdown-Menüs (z.B. Bucket-/Karten-Aktionen) im Tailwind-Layout themen — sonst
   weißes Menü im dunklen Theme. */
.dropdown-menu {
    background-color: var(--ds-card);
    border-color: color-mix(in srgb, var(--ds-border) 70%, transparent);
    color: var(--ds-foreground);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
}
.dropdown-item { color: var(--ds-foreground); }
.dropdown-divider { border-color: var(--ds-border); }

/* Bootstrap-Tooltips als ds-Oberfläche statt schwarzem Default-Kasten.
   Das Tailwind-Layout lädt KEIN site.css — ohne diese Regeln greift Bootstraps
   --bs-tooltip-bg: var(--bs-emphasis-color) = #000 (pures Schwarz). Die ds-Tokens
   kippen unter html.dark automatisch -> theme-aware ohne prefers-color-scheme/data-bs-theme.
   Init + Orphan-Cleanup: wwwroot/js/tooltip-manager.js */
.tooltip {
    z-index: 1040 !important;
    --bs-tooltip-bg: var(--ds-popover);
    --bs-tooltip-color: var(--ds-popover-foreground);
    --bs-tooltip-opacity: 1;
}
.tooltip .tooltip-inner {
    background-color: var(--ds-popover) !important;
    color: var(--ds-popover-foreground) !important;
    border: 1px solid var(--ds-border) !important;
    border-radius: 8px !important;
    padding: 8px 12px !important;
    font-size: 0.875rem !important;
    font-weight: 400 !important;
    line-height: 1.4 !important;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18) !important;
    max-width: 300px;
}
.tooltip.bs-tooltip-top .tooltip-arrow::before,
.tooltip.bs-tooltip-auto[data-popper-placement^="top"] .tooltip-arrow::before {
    border-top-color: var(--ds-popover) !important;
}
.tooltip.bs-tooltip-bottom .tooltip-arrow::before,
.tooltip.bs-tooltip-auto[data-popper-placement^="bottom"] .tooltip-arrow::before {
    border-bottom-color: var(--ds-popover) !important;
}
.tooltip.bs-tooltip-start .tooltip-arrow::before,
.tooltip.bs-tooltip-auto[data-popper-placement^="left"] .tooltip-arrow::before {
    border-left-color: var(--ds-popover) !important;
}
.tooltip.bs-tooltip-end .tooltip-arrow::before,
.tooltip.bs-tooltip-auto[data-popper-placement^="right"] .tooltip-arrow::before {
    border-right-color: var(--ds-popover) !important;
}

/* Modul-Karten — die einzelnen Klick-Tiles im Menü */
.card-modal-menu {
    background: var(--ds-card);
    color: var(--ds-foreground);
    border: 1px solid color-mix(in srgb, var(--ds-border) 70%, transparent);
    border-radius: 14px;
    box-shadow:
        0 2px 10px rgba(0, 0, 0, 0.08),
        0 1px 3px rgba(0, 0, 0, 0.05);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    overflow: hidden;
}
.card-modal-menu:hover:not(.active-card) {
    transform: translateY(-3px);
    box-shadow:
        0 10px 22px rgba(0, 0, 0, 0.12),
        0 3px 8px rgba(0, 0, 0, 0.08);
}
.card-modal-menu .card-body,
.card-modal-menu .card-body h2,
.card-modal-menu .card-body .fs-5 { color: var(--ds-foreground); }
.card-modal-menu .text-primary { color: var(--ds-accent-1) !important; }

/* Aktive Karte — markiert das aktuell offene Modul */
.card-modal-menu.active-card {
    border: 2px solid var(--ds-accent-1) !important;
    box-shadow:
        0 0 0 4px color-mix(in srgb, var(--ds-accent-1) 18%, transparent),
        0 6px 18px color-mix(in srgb, var(--ds-accent-1) 28%, transparent) !important;
    transform: scale(1.02);
}
.card-modal-menu.active-card .card-body,
.card-modal-menu.active-card .card-body h2,
.card-modal-menu.active-card .card-body .fs-5 {
    color: var(--ds-accent-1) !important;
}

/* Dark Mode — Karten/Badges dezent staerker abheben */
html.dark .menu-section-badge,
html.dark .btn-close-custom {
    background: color-mix(in srgb, var(--ds-card) 65%, transparent);
    border-color: rgba(255, 255, 255, 0.08);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
}
html.dark .menu-section-badge:hover,
html.dark .btn-close-custom:hover {
    background: color-mix(in srgb, var(--ds-card) 85%, transparent);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
}
html.dark .card-modal-menu {
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.04),
        0 4px 12px rgba(0, 0, 0, 0.4);
}
html.dark .card-modal-menu:hover:not(.active-card) {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.07),
        0 10px 26px rgba(0, 0, 0, 0.6);
}

/* ── MenuModal auf Phones: Karten als kompaktes Raster statt 1-pro-Reihe ──
   Die Karten haben inline `width:150px; height:130px` + `m-3`. Im schmalen
   modal-dialog (~334px) passt nur EINE Karte pro Reihe → 20 Module = ~4000px
   Endlos-Scroll. Hier wird jede Modul-Reihe (.d-flex.flex-wrap) zum Grid und
   die Karten füllen die Zelle (inline-Größe per !important überschrieben). */
@media (max-width: 767.98px) {
    #MenuModal .modal-dialog { margin: 0.5rem; }
    #MenuModal .modal-body .d-flex.flex-wrap {
        display: grid !important;
        grid-template-columns: repeat(auto-fill, minmax(4.75rem, 1fr));
        gap: 0.5rem;
        justify-content: stretch !important;
    }
    /* Wrapper-Div um jede Karte füllt die Grid-Zelle */
    #MenuModal .modal-body .d-flex.flex-wrap > div { width: 100%; }
    #MenuModal .card-modal-menu {
        width: 100% !important;
        height: auto !important;
        min-height: 4.75rem;
        margin: 0 !important;
        border-radius: 12px;
    }
    #MenuModal .card-modal-menu .card-body {
        padding: 0.5rem 0.3rem !important;
        display: flex; flex-direction: column;
        align-items: center; justify-content: center; gap: 0.15rem;
        height: 100%;
    }
    #MenuModal .card-modal-menu h2 { font-size: 1.35rem; margin: 0; padding: 0 !important; line-height: 1; }
    #MenuModal .card-modal-menu .pt-2,
    #MenuModal .card-modal-menu .pt-3 { padding-top: 0 !important; }
    #MenuModal .card-modal-menu .fs-5 {
        font-size: 0.72rem !important; line-height: 1.15;
        word-break: break-word; hyphens: auto;
    }
    /* Footer-Buttons (inline width:150px) füllen sauber 2 Spalten */
    #MenuModal .modal-footer .btn,
    #MenuModal .modal-footer form { flex: 1 1 8rem; width: auto !important; min-width: 0; }
    #MenuModal .modal-footer form .btn { width: 100% !important; }
}

/* === TABLE IN EDITOR === */
/* Editor-Tabellen: nur echte Tabellen (data-editor-table) bekommen Rahmen */
.ds-editor-content table[data-editor-table="true"] {
    border-collapse: separate;
    border-spacing: 0;
    width: 100%;
    margin: 0.5rem 0;
    table-layout: auto;
    box-sizing: border-box;
    border: 1px solid var(--tc, var(--ds-border));
    border-radius: 8px;
    overflow: hidden;
}
.ds-editor-content table[data-editor-table="true"] th,
.ds-editor-content table[data-editor-table="true"] td {
    border-right: 1px solid var(--tc, var(--ds-border));
    border-bottom: 1px solid var(--tc, var(--ds-border));
    padding: 0.35rem 0.6rem;
    min-width: 2rem;
    vertical-align: top;
    position: relative;
}
/* Letzte Spalte: kein rechter Rand */
.ds-editor-content table[data-editor-table="true"] th:last-child,
.ds-editor-content table[data-editor-table="true"] td:last-child {
    border-right: none;
}
/* Letzte Zeile: kein unterer Rand */
.ds-editor-content table[data-editor-table="true"] tr:last-child td,
.ds-editor-content table[data-editor-table="true"] tr:last-child th {
    border-bottom: none;
}
.ds-editor-content table[data-editor-table="true"] th {
    background: var(--ds-accent);
    font-weight: 600;
    text-align: left;
}
/* TipTap rendert Tabellen im Editor über eine TableView (Node-View), die das
   data-editor-table-Attribut NICHT auf das <table>-Element überträgt — frisch EINGEFÜGTE
   Tabellen wären beim Schreiben sonst randlos/unsichtbar ("weißer Platzhalter"). Diese
   Fallback-Regeln geben Tabellen OHNE das Attribut in der EDITIERANSICHT dieselbe sichtbare
   Darstellung. Betrifft nur den Editor (.ds-editor-content), nicht den gesendeten/angezeigten
   E-Mail-Output (dessen HTML das Attribut via renderHTML trägt). */
.ds-editor-content table:not([data-editor-table="true"]) {
    border-collapse: separate;
    border-spacing: 0;
    margin: 0.5rem 0;
    table-layout: auto;
    box-sizing: border-box;
    border: 1px solid var(--ds-border);
    border-radius: 8px;
    overflow: hidden;
}
.ds-editor-content table:not([data-editor-table="true"]) th,
.ds-editor-content table:not([data-editor-table="true"]) td {
    border-right: 1px solid var(--ds-border);
    border-bottom: 1px solid var(--ds-border);
    padding: 0.35rem 0.6rem;
    min-width: 2rem;
    vertical-align: top;
    position: relative;
}
.ds-editor-content table:not([data-editor-table="true"]) th:last-child,
.ds-editor-content table:not([data-editor-table="true"]) td:last-child { border-right: none; }
.ds-editor-content table:not([data-editor-table="true"]) tr:last-child td,
.ds-editor-content table:not([data-editor-table="true"]) tr:last-child th { border-bottom: none; }
.ds-editor-content table:not([data-editor-table="true"]) th {
    background: var(--ds-accent);
    font-weight: 600;
    text-align: left;
}
/* Mail-Bausteine (editor.src.js: DsCallout/DsFacts/DsSteps/DsButton) sind Layout-Tabellen — ihr
   Aussehen steckt in den Inline-Styles, die auch beim Empfänger ankommen. Die Rahmen-Fallbacks oben
   dürfen hier nicht greifen; im Editor gilt nur, was hier steht. */
.ds-editor-content table[data-ds-block],
.ds-editor-content table[data-ds-block] table { border: none; border-radius: 0; overflow: visible; }
.ds-editor-content table[data-ds-block] td { border-right: none; border-bottom: none; min-width: 0; padding: 0; position: static; }
.ds-editor-content td[data-ds-part] > :first-child { margin-top: 0 !important; }
.ds-editor-content td[data-ds-part] > :last-child { margin-bottom: 0 !important; }
.ds-editor-content td[data-ds-part="icon"],
.ds-editor-content td[data-ds-part="num"] { user-select: none; }
.ds-editor-content .ds-mail-button { cursor: pointer; }
.ds-editor-content .ds-mail-button.is-selected table,
.ds-editor-content table[data-ds-block].ProseMirror-selectednode { outline: 2px solid var(--ds-ring); outline-offset: 2px; }
/* Gestaltete Signatur (DsSignatur, editor.src.js): fester Block, Inhalt im Shadow-Root */
.ds-editor-content .ds-sig-block { display: block; margin: 0.25rem 0 0.5rem; cursor: default; }
.ds-editor-content .ds-sig-block.ProseMirror-selectednode { outline: 2px solid var(--ds-ring); outline-offset: 2px; border-radius: 6px; }
/* Spalten-Resize-Handle (Tiptap) */
.ds-editor-content .column-resize-handle {
    position: absolute;
    right: -2px;
    top: 0;
    bottom: 0;
    width: 4px;
    cursor: col-resize;
    background: var(--ds-accent-1);
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 1;
}
.ds-editor-content table[data-editor-table="true"] td:hover .column-resize-handle,
.ds-editor-content table[data-editor-table="true"] th:hover .column-resize-handle { opacity: 0.6; }
/* Tiptap: ausgewählte Zelle */
.ds-editor-content .selectedCell {
    outline: 2px solid var(--ds-accent-1);
    outline-offset: -1px;
}
/* Responsive-Badge im Editor */
.ds-editor-content table[data-responsive="true"]::before {
    content: 'responsive';
    display: block;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ds-accent-1);
    margin-bottom: 2px;
    opacity: .7;
}
.ds-editor-content table[data-responsive="true"] {
    display: block;
    overflow-x: auto;
}

/* === TABLE GRID PICKER === */
.ds-editor-table-picker {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 100;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 6px;
    padding: 8px;
    box-shadow: 0 4px 12px rgba(0,0,0,.15);
    min-width: 190px;
}
.ds-table-grid {
    display: grid;
    gap: 2px;
    margin-top: 4px;
    margin-bottom: 0;
}
.ds-table-grid-cell {
    width: 20px;
    height: 20px;
    border: 1px solid var(--ds-border);
    border-radius: 2px;
    background: transparent;
    cursor: pointer;
    transition: background 0.08s, border-color 0.08s;
}
.ds-table-grid-cell.active {
    background: color-mix(in srgb, var(--ds-accent-1) 30%, transparent);
    border-color: var(--ds-accent-1);
}
.ds-table-grid-label {
    font-size: 0.72rem;
    color: var(--ds-muted-foreground);
    text-align: center;
    min-height: 1.1em;
}

/* === TABLE CONTEXT TOOLBAR (body-level, fixed) === */
.ds-table-toolbar {
    position: fixed;
    z-index: 1070;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 6px;
    padding: 3px 5px;
    display: none;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px;
    box-shadow: 0 2px 10px rgba(0,0,0,.2);
    white-space: nowrap;
    max-width: calc(100vw - 16px);
}
.ds-table-toolbar-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    height: 26px;
    min-width: 26px;
    padding: 0 4px;
    border: none;
    border-radius: 4px;
    background: transparent;
    color: var(--ds-foreground);
    cursor: pointer;
    font-size: 0.75rem;
    transition: background 0.1s;
    white-space: nowrap;
}
.ds-table-toolbar-btn:hover { background: var(--ds-accent); }
.ds-table-toolbar-btn.active { color: var(--ds-accent-1); }
.ds-table-toolbar-btn.danger { color: #dc3545; }
.ds-table-toolbar-btn.danger:hover { background: rgba(220,53,69,.1); }
.ds-table-toolbar-sep {
    width: 1px;
    background: var(--ds-border);
    margin: 2px 2px;
    align-self: stretch;
    flex-shrink: 0;
}

/* === LINK PANEL (body-level, fixed) — ersetzt den alten prompt()-Dialog === */
.ds-link-panel {
    position: fixed;
    z-index: 1080;
    display: none;
    width: 320px;
    max-width: calc(100vw - 16px);
    padding: 0.75rem;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 0.5rem;
    box-shadow: 0 8px 24px rgba(0,0,0,.18);
    color: var(--ds-foreground);
}
.ds-link-panel-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8125rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
}
.ds-link-panel-head i { color: var(--ds-primary); font-size: 1rem; }
.ds-link-panel-label {
    display: block;
    font-size: 0.7rem;
    font-weight: 500;
    color: var(--ds-muted-foreground);
    margin-bottom: 0.2rem;
}
.ds-link-panel-input.form-control {
    height: 2rem;
    font-size: 0.8125rem;
    margin-bottom: 0.5rem;
}
.ds-link-panel-check {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.75rem;
    color: var(--ds-muted-foreground);
    cursor: pointer;
    margin-bottom: 0.25rem;
}
.ds-link-panel-check input { accent-color: var(--ds-primary); cursor: pointer; }
.ds-link-panel-error {
    font-size: 0.7rem;
    color: var(--ds-destructive, #dc3545);
    min-height: 0.95rem;
    margin-bottom: 0.25rem;
}
.ds-link-panel-actions { display: flex; align-items: center; gap: 0.375rem; }
.ds-link-panel-spacer { flex: 1 1 auto; }

/* === TABLE SWATCH PANEL === */
.ds-table-swatch-panel {
    position: fixed;
    z-index: 1080;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 6px;
    padding: 6px;
    box-shadow: 0 4px 12px rgba(0,0,0,.2);
    display: none;
}
.ds-table-swatch-grid {
    display: grid;
    grid-template-columns: repeat(9, 20px);
    gap: 3px;
}
.ds-table-swatch-btn {
    width: 20px;
    height: 20px;
    border: 1px solid var(--ds-border);
    border-radius: 3px;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.625rem;
    transition: transform 0.1s, box-shadow 0.1s;
}
.ds-table-swatch-btn:hover {
    transform: scale(1.2);
    box-shadow: 0 0 0 2px var(--ds-accent-1);
    z-index: 1;
    position: relative;
}
.ds-table-swatch-none {
    background: repeating-linear-gradient(
        45deg, transparent, transparent 4px,
        rgba(200,50,50,.4) 4px, rgba(200,50,50,.4) 5px
    ) !important;
}
.ds-table-swatch-custom {
    width: 20px;
    height: 20px;
    border: 1px solid var(--ds-border);
    border-radius: 3px;
    padding: 0;
    cursor: pointer;
    background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red);
}

/* === TABLE BORDER PICKER PANEL === */
.ds-table-border-panel {
    position: fixed;
    z-index: 1080;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: 8px;
    padding: 8px;
    box-shadow: 0 4px 16px rgba(0,0,0,.2);
    display: none;
    min-width: 230px;
}
.ds-tbp-heading {
    font-size: 0.68rem;
    font-weight: 600;
    color: var(--ds-muted-foreground);
    text-transform: uppercase;
    letter-spacing: .04em;
    margin-bottom: 4px;
    margin-top: 8px;
}
.ds-tbp-heading:first-child { margin-top: 0; }
.ds-tbp-presets {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 3px;
    margin-bottom: 8px;
}
.ds-tbp-preset-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 5px 3px;
    border: 1px solid var(--ds-border);
    border-radius: 5px;
    background: transparent;
    color: var(--ds-foreground);
    cursor: pointer;
    font-size: 0.6rem;
    transition: background 0.1s, border-color 0.1s;
}
.ds-tbp-preset-btn i { font-size: 1rem; }
.ds-tbp-preset-btn:hover { background: var(--ds-accent); border-color: var(--ds-accent-1); }
.ds-tbp-row {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;
}
.ds-tbp-label {
    font-size: 0.68rem;
    color: var(--ds-muted-foreground);
    min-width: 36px;
    flex-shrink: 0;
}
.ds-tbp-thick-btn {
    padding: 2px 8px;
    border: 1px solid var(--ds-border);
    border-bottom-style: solid;
    border-bottom-color: currentColor;
    border-radius: 4px;
    background: transparent;
    color: var(--ds-foreground);
    cursor: pointer;
    font-size: 0.68rem;
    transition: background 0.1s;
}
.ds-tbp-thick-btn.active { background: var(--ds-accent); border-color: var(--ds-accent-1); color: var(--ds-accent-1); }
.ds-tbp-colors {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
}
.ds-tbp-color-btn {
    width: 18px;
    height: 18px;
    border: 1px solid var(--ds-border);
    border-radius: 3px;
    cursor: pointer;
    padding: 0;
    transition: transform 0.1s;
    flex-shrink: 0;
}
.ds-tbp-color-btn:hover, .ds-tbp-color-btn.active {
    transform: scale(1.25);
    box-shadow: 0 0 0 2px var(--ds-accent-1);
    position: relative; z-index: 1;
}
.ds-tbp-custom-color {
    background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red) !important;
    width: 18px; height: 18px;
}
.ds-combo-item:hover { background: var(--ds-muted); }
.ds-combo-item:last-child { border-bottom: none; }
.ds-combo-item.ds-combo-active { background: color-mix(in srgb, var(--ds-accent-1) 12%, transparent); }

/* Calendar Grid (8 Spalten: KW + Mo-So) */
.ds-cal-grid { display: grid; grid-template-columns: 1.5rem repeat(7, 1fr); gap: 2px; }
.ds-cal-head { font-size: 0.75rem; font-weight: 500; text-align: center; padding: 0.25rem; color: var(--ds-muted-foreground); }
.ds-cal-kw { font-size: 0.625rem; text-align: center; padding: 0.375rem 0; color: var(--ds-accent-2) !important; opacity: 0.7; display: flex; align-items: center; justify-content: center; font-weight: 600; }
.ds-cal-day {
    font-size: 0.8125rem; text-align: center; padding: 0.375rem;
    border-radius: 9999px; cursor: pointer;
    transition: background 0.15s, color 0.15s; color: var(--ds-foreground);
    aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
}
.ds-cal-day:hover { background: var(--ds-muted); }
/* "Heute" deutlich markieren: Akzent-Ring (Kreis) + fette Akzentschrift, auch ohne Auswahl sichtbar. */
.ds-cal-day.today { font-weight: 700; color: var(--ds-accent-1) !important; box-shadow: inset 0 0 0 1.5px var(--ds-accent-1); }
.ds-cal-day.selected { background: var(--ds-accent-1); color: #fff !important; font-weight: 600; }
/* Heute UND ausgewählt → gefüllter "selected"-Stil gewinnt, Ring entfällt (weißer Text bleibt lesbar). */
.ds-cal-day.today.selected { box-shadow: none; color: #fff !important; }
.ds-cal-empty { padding: 0.375rem; }
/* Tage aus Vor-/Folgemonat: heller, aber auswählbar (gefüllte Reihe wie im Papierkalender).
   today/selected überschreiben die Farbe via !important und bleiben damit klar erkennbar. */
.ds-cal-day.ds-cal-outside { color: var(--ds-muted-foreground); opacity: 0.45; }
.ds-cal-day.ds-cal-outside:hover { opacity: 0.75; }
/* Monats-/Jahres-Raster: display:grid MUSS via Klasse kommen (NICHT inline am x-show-Element) — Alpines
   x-show entfernt beim Anzeigen die inline display-Property (removeProperty('display')), wodurch ein
   inline display:grid verloren ginge und das Element auf display:block zurückfiele (Zellen untereinander).
   Außerdem die quadratische aspect-ratio der Tages-Zellen hier aufheben, sonst werden Monats-/Jahres-Zellen
   in den breiten 3 Spalten riesige Quadrate (nur die erste Reihe sichtbar). */
.ds-cal-mgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.ds-cal-mgrid .ds-cal-day { aspect-ratio: auto; padding: 0.55rem 0.25rem; }

/* Time Picker Grid */
.ds-time-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px; }
/* Stunden-Raster im Zeit-Popover (00–23 in 6 Spalten, kompakter als das 4er-Minuten-Raster) */
.ds-time-grid-hours { grid-template-columns: repeat(6, 1fr); }
.ds-time-grid-hours .ds-time-option { padding: 0.3rem 0.1rem; font-size: 0.78rem; }
.ds-time-option {
    font-size: 0.8125rem; text-align: center; padding: 0.375rem;
    border-radius: calc(var(--ds-radius) * 0.6); cursor: pointer;
    transition: background 0.1s; color: var(--ds-foreground);
}
.ds-time-option:hover { background: var(--ds-muted); }
.ds-time-option.selected { background: var(--ds-accent-1); color: #fff; }

/* ============================================
   BUTTONS — from shadcn/ui button.tsx
   Base: "inline-flex shrink-0 items-center justify-center
          gap-2 rounded-md text-sm font-medium whitespace-nowrap
          transition-all"
   Default size: h-9 px-4 py-2
   ============================================ */
.btn-shadcn {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    white-space: nowrap;
    border-radius: calc(var(--ds-radius) * 0.8); /* rounded-md */
    font-size: 0.875rem; /* text-sm */
    font-weight: 500; /* font-medium */
    line-height: 1.25;
    padding: 0.5rem 1rem; /* py-2 px-4 */
    height: 2.25rem; /* h-9 */
    border: none;
    cursor: pointer;
    transition: all 0.15s;
    text-decoration: none !important;
    font-family: inherit;
    outline: none;
}

.btn-shadcn:disabled { opacity: 0.5; pointer-events: none; }

.btn-shadcn:focus-visible {
    border-color: var(--ds-ring);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-ring) 50%, transparent);
}

/* variant: default — "bg-primary text-primary-foreground hover:bg-primary/90" */
.btn-shadcn-primary {
    background: var(--ds-primary);
    color: var(--ds-primary-foreground);
}
.btn-shadcn-primary:hover { filter: brightness(1.1); opacity: 0.9; }

/* variant: secondary — "bg-secondary text-secondary-foreground hover:bg-secondary/80" */
.btn-shadcn-secondary {
    background: var(--ds-secondary);
    color: var(--ds-secondary-foreground);
}
.btn-shadcn-secondary:hover { filter: brightness(0.95); }

/* variant: destructive — "bg-destructive text-white hover:bg-destructive/90" */
.btn-shadcn-destructive {
    background: var(--ds-destructive);
    color: white;
}
.btn-shadcn-destructive:hover { opacity: 0.9; }

/* variant: outline — "border bg-background shadow-xs hover:bg-accent" */
.btn-shadcn-outline {
    background: var(--ds-background);
    color: var(--ds-foreground);
    border: 1px solid var(--ds-input);
    box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
}
.btn-shadcn-outline:hover {
    background: var(--ds-accent);
    color: var(--ds-accent-foreground);
}

/* variant: ghost — "hover:bg-accent hover:text-accent-foreground" */
.btn-shadcn-ghost {
    background: transparent;
    color: var(--ds-foreground);
}
.btn-shadcn-ghost:hover {
    background: var(--ds-accent);
    color: var(--ds-accent-foreground);
}

/* variant: link — "text-primary underline-offset-4 hover:underline" */
.btn-shadcn-link {
    background: transparent;
    color: var(--ds-primary);
    text-underline-offset: 4px;
    height: auto;
    padding: 0;
}
.btn-shadcn-link:hover { text-decoration: underline !important; }

/* Extra: success */
.btn-shadcn-success {
    background: var(--ds-success);
    color: var(--ds-success-foreground);
}
.btn-shadcn-success:hover { opacity: 0.9; }

/* Extra: warning */
.btn-shadcn-warning {
    background: var(--ds-warning);
    color: var(--ds-warning-foreground);
}
.btn-shadcn-warning:hover { opacity: 0.9; }

/* size: sm — "h-8 gap-1.5 rounded-md px-3" */
.btn-shadcn-sm {
    height: 2rem;
    gap: 0.375rem;
    padding: 0 0.75rem;
    font-size: 0.875rem;
    border-radius: calc(var(--ds-radius) * 0.8);
}

/* size: lg — "h-10 rounded-md px-6" */
.btn-shadcn-lg {
    height: 2.5rem;
    padding: 0 1.5rem;
    border-radius: calc(var(--ds-radius) * 0.8);
}

/* size: xs — "h-6 gap-1 rounded-md px-2 text-xs" */
.btn-shadcn-xs {
    height: 1.5rem;
    gap: 0.25rem;
    padding: 0 0.5rem;
    font-size: 0.75rem;
    border-radius: calc(var(--ds-radius) * 0.8);
}

/* size: icon — "size-9" */
.btn-shadcn-icon { height: 2.25rem; width: 2.25rem; padding: 0; }
.btn-shadcn-icon.btn-shadcn-sm { height: 2rem; width: 2rem; }
.btn-shadcn-icon.btn-shadcn-lg { height: 2.5rem; width: 2.5rem; }
.btn-shadcn-icon.btn-shadcn-xs { height: 1.5rem; width: 1.5rem; }

/* ============================================
   DOCK — Base styles (extracted from site.css)
   Needed for the real _Menu.cshtml to render
   ============================================ */
/* Single Source: vertikaler Platz, den das schwebende Dock (#MenuWrapper) am
   unteren Viewport-Rand belegt = 20px bottom-Offset + ~76px Dock-Höhe.
   Module mit bodenbündigem Inhalt (Chat etc.) rechnen damit:
   height: calc(100vh - var(--app-dock-reserve) - <Kopf/Luft>).
   Wert hier ändern → alle Konsumenten ziehen automatisch nach. */
/* + safe-area: auf iPhones sitzt das Dock sonst auf der Home-Leiste (viewport-fit=cover). */
/* 74 statt 96: Dock seit 03.11.2026 14px schlanker (67 statt 81px) und 12 statt 20px über dem Rand — Abstand Inhalt→Dock bleibt 8px. */
:root { --app-dock-reserve: calc(74px + env(safe-area-inset-bottom, 0px)); }
/* Unterkante JEDER Modul-Karte im Füll-Modell: .5rem über dem Dock — ein Wert für alle Module (Referenz
   Pass/BlogAdmin/TeamTime; Max, 07.11.2026: „einheitlich wie E-Mail und Arc"). Verwendung:
   padding-bottom der .ds-content in der Flex-Kette ODER calc(100dvh - var(--ds-oben) - var(--ds-dock-luft)).
   Fenster/Gast (Reserve 0) → .5rem Rand. */
:root { --ds-dock-luft: calc(var(--app-dock-reserve) + .5rem); }

/* INNEN-SCROLL statt Seiten-Scroll (Max, 07.11.2026: „wie Mail und Arc"). Module ohne eigene Vollhöhen-Karte
   (Dashboards, Listen aus mehreren Bereichs-Karten, Einstellungsseiten) scrollten als ganze Seite — der Inhalt
   lief hinter das Dock. Jetzt steht die Seite, die Werkzeugleiste bleibt, der Inhaltsbereich (#mainContent)
   endet .5rem über dem Dock und scrollt innen (▲/▼ kommen automatisch).
   Neue Module: data-ds-innen-scroll am Modul-Wrapper. Die übrigen Einträge sind die Altmodule: Home und alle
   Dashboards mit schwebenden Karten (.ds-fullbleed-floating, also auch alle iTOPS-Seiten und Arc „Wichtige
   Dokumente“), Feed, Arbeitszeit, ToDo Light, Tags und alle Einstellungsseiten. Handys quer (< 480 hoch) behalten den
   Seiten-Scroll (Regel 3) → die Media Query. Gemessene Karten (.ds-shell, data-ds-bis-dock …) enden darin
   bündig: ohne Außenabstand, sonst scrollte der Bereich um den Rest. */
@media screen and (min-height: 480px), screen and (orientation: portrait) {
    html.ds-page:has(:is([data-ds-innen-scroll], .dashboard-shell, .feed-module, .tl-seite, .az-kennzahlen, #az-monat, [data-tag-edit], .arc-important, .settings-module, .ds-fullbleed-floating)),
    html.ds-page:has(:is([data-ds-innen-scroll], .dashboard-shell, .feed-module, .tl-seite, .az-kennzahlen, #az-monat, [data-tag-edit], .arc-important, .settings-module, .ds-fullbleed-floating)) body {
        overflow: hidden;
    }
    html.ds-page:has(:is([data-ds-innen-scroll], .dashboard-shell, .feed-module, .tl-seite, .az-kennzahlen, #az-monat, [data-tag-edit], .arc-important, .settings-module, .ds-fullbleed-floating)) main.ds-main {
        display: flex; flex-direction: column; box-sizing: border-box;
        height: 100vh; height: 100dvh; min-height: 0;
        padding-bottom: var(--ds-dock-luft);
    }
    html.ds-page:has(:is([data-ds-innen-scroll], .dashboard-shell, .feed-module, .tl-seite, .az-kennzahlen, #az-monat, [data-tag-edit], .arc-important, .settings-module, .ds-fullbleed-floating)) #moduleWrapper {
        display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
    }
    html.ds-page:has(:is([data-ds-innen-scroll], .dashboard-shell, .feed-module, .tl-seite, .az-kennzahlen, #az-monat, [data-tag-edit], .arc-important, .settings-module, .ds-fullbleed-floating)) #toolbarContent {
        flex: 0 0 auto;
    }
    html.ds-page:has(:is([data-ds-innen-scroll], .dashboard-shell, .feed-module, .tl-seite, .az-kennzahlen, #az-monat, [data-tag-edit], .arc-important, .settings-module, .ds-fullbleed-floating)) #mainContent {
        flex: 1 1 auto; min-height: 0;
        overflow-x: hidden; overflow-y: auto;
        padding-bottom: 0 !important;
    }
    html.ds-page:has(:is([data-ds-innen-scroll], .dashboard-shell, .feed-module, .tl-seite, .az-kennzahlen, #az-monat, [data-tag-edit], .arc-important, .settings-module, .ds-fullbleed-floating)) #mainContent :is(.ds-shell, [data-ds-bis-dock], .itops-mv-shell, .itops-dash-band-full) {
        margin-bottom: 0;
    }
    html.ds-page:has(.settings-module) #mainContent .settings-content { padding-bottom: 0; }

    /* Trägt EINE Bereichs-Karte die lange Liste, endet SIE über dem Dock und scrollt innen — ihr Rahmen bleibt
       ganz wie bei Mail/Arc: Arbeitszeit-Monat (Kopf der Karte bleibt stehen), ToDo Light, Arc „Wichtige Dokumente“. */
    html.ds-page:has(:is(#az-monat, .tl-seite, .arc-important)) #mainContent { display: flex; flex-direction: column; overflow: hidden; }
    html.ds-page:has(:is(#az-monat, .tl-seite, .arc-important)) #mainContent > :is(.ds-module, .arc-module),
    html.ds-page:has(.arc-important) .arc-important {
        display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
    }
    html.ds-page:where(:has(#az-monat, .tl-seite)) #mainContent > .ds-module > * { flex: 0 0 auto; }
    html.ds-page:has(.arc-important) .arc-important > .ds-card { flex: 0 1 auto; min-height: 0; overflow-y: auto; margin-bottom: 0; }
    html.ds-page:has(#az-monat) #mainContent > .ds-module > .ds-surface:has(> #az-monat) {
        flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden;
    }
    html.ds-page:has(#az-monat) .ds-surface > .ds-surface-head { flex: 0 0 auto; }
    html.ds-page:has(#az-monat) #az-monat { flex: 0 1 auto; min-height: 0; overflow-y: auto; }
    html.ds-page:has(.tl-seite) #mainContent > .ds-module > .ds-surface:has(.tl-seite) {
        flex: 0 1 auto; min-height: 0; overflow-y: auto;
    }
}
/* ToDo Light liegt seit dem Verlaufskopf (07.11.2026) in einer .ds-shell statt einer .ds-surface. Unter 768 px gibt
   die .ds-shell ihren Innen-Scroll ab (siehe .ds-shell-body), die Regel oben sperrt aber #mainContent — am Handy
   ließ sich „Mein Tag" per Finger gar nicht scrollen (gemessen 12.11.2026, Plan 74 C11). Dort scrollt deshalb
   #mainContent (endet über dem Dock wie alle Innen-Scroller); die Shell klippt seitlich mit `clip` statt `hidden`,
   damit sie kein eigener Scroll-Container ist und haftende Hinweise (Offline) am echten Scroller kleben. */
@media (max-width: 767.98px) and (min-height: 480px), (max-width: 767.98px) and (orientation: portrait) {
    html.ds-page:has(#mainContent .tl-seite) #mainContent { overflow-y: auto; overscroll-behavior: contain; }
    html.ds-page:has(#mainContent .tl-seite) #mainContent .ds-shell { overflow: clip; }
}
/* Handys quer scrollt die Seite (Regel 3). Ist eine .ds-shell nur EIN Abschnitt unter mehreren (Telefon: Leitungen,
   darunter Wartemusik + Journal), darf html:has(.ds-shell) die Seite dort nicht sperren — sonst war alles unter der
   Shell unerreichbar. */
@media (max-height: 479.98px) and (orientation: landscape) {
    html.ds-page:has(.settings-stack > .ds-shell ~ :is(.ds-surface, .ds-shell, .ds-card)),
    html.ds-page:has(.settings-stack > .ds-shell ~ :is(.ds-surface, .ds-shell, .ds-card)) body { overflow: visible auto; }
}

#MenuWrapper {
    position: fixed !important;
    /* 12 statt 20px (max, 03.11.2026): spiegelt die Kopfleiste (12px unter dem oberen Rand). */
    bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important;
    left: 0 !important;
    right: 0 !important;
    z-index: 1030 !important;
    /* Die Hülle ist unsichtbar, aber voll breit (left/right 0) und liegt über den Fenstern
       (500–1000). Ohne das schluckte sie jeden Klick im Dock-Streifen NEBEN dem schmalen Dock —
       z. B. die Fußleisten-Knöpfe eines tief gezogenen Fensters am DeX-Bildschirm (Frank 11/2026). */
    pointer-events: none;
}
/* Bedienbar bleiben die direkten Kinder: #Dock (max-content, schmal) und #linkInfoModal.
   Die Ausblend-Regeln (ds-dock-weg / ds-tastatur) setzen none am Wrapper — dort zusätzlich
   die Kinder abschalten, sonst bliebe das unsichtbare Dock klickbar. */
#MenuWrapper > * { pointer-events: auto; }
html.ds-dock-weg #MenuWrapper > * { pointer-events: none; }

/* Kein Abdunkeln der übrigen Kacheln beim Überfahren mehr (max, 03.11.2026): es nahm auch dem aktiven
   Modul seine Markierung und machte das Dock unruhig. Der Hover der Kachel selbst reicht. */

.dock-btn {
    border-radius: 10px;
    transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.dock-btn:hover {
    transform: scale(1.2);
}

/* ═══ DOCK-HOVER (max, 03.11.2026) ═══
   Vorher hob sich der GANZE Knopf (translateY(-5px) scale(1.1)). Über dem Knopf sind im Dock nur
   4px Luft und #CallMenu clippt (overflow:hidden) → die getönte Fläche des aktiven Moduls wurde oben
   abgeschnitten. Jetzt bleibt die Fläche stehen, nur der Inhalt reagiert: Symbol wächst (vom Fuß aus,
   bleibt in der Fläche), die direkten Nachbarn wachsen ein wenig mit (Dock-Lupe), Symbol + Beschriftung
   färben sich in der Akzentfarbe, beim Klick drückt das Symbol kurz ein.
   Ausgelöst wird an der HÜLLE (.container-buttons > div.p-1 > .dock-btn), nicht am Knopf: Die Hüllen
   liegen lückenlos, zwischen zwei Knöpfen lagen aber 8px ohne Knopf — dort ging der Effekt kurz aus
   und wieder an (Flackern beim Überfahren). */
#MenuWrapper .dock-btn,
#MenuWrapper .dock-btn:hover,
#MenuWrapper .dock-btn:hover ~ .dock-btn,
#MenuWrapper .dock-btn:hover + .dock-btn { transform: none; }
#MenuWrapper .dock-btn { transition: background-color .2s ease; }
#MenuWrapper .dock-btn i {
    display: inline-block;
    margin-bottom: 0;           /* .h4 bringt 0.5rem mit — inline wirkte das nie, inline-block schon */
    transform-origin: 50% 100%;
    transition: transform .3s cubic-bezier(.34, 1.56, .64, 1), color .2s ease;
}
#MenuWrapper .dock-btn span { transition: color .2s ease; }
/* DOCK-MASSE: Kachel so breit wie ihre Beschriftung (voller Name statt „Fahrte…"), Mindestbreite für
   kurze Namen; schlanker durch weniger Polster — Symbol und Schrift bleiben gleich groß. */
#CallMenu > div { width: auto; min-width: 4.25rem; padding: 2px 2px !important; }
/* Chat-Knopf (eigene Spalte rechts): dasselbe senkrechte Maß — mit dem alten p-1 war seine Spalte 4px
   höher, die übrigen Kacheln blieben oben hängen und unter ihnen klaffte ein Streifen (unten 10px Luft,
   oben 6px). */
#Dock > .col-1 .p-1:has(> .dock-btn) { padding-top: 2px !important; padding-bottom: 2px !important; }
/* Unten weniger als oben: Die Zeilenhöhe der Beschriftung lässt unter der Schrift ohnehin Luft — mit
   gleichem Polster wirkte der Raum unter dem Text fast doppelt so groß wie über dem Symbol. */
#MenuWrapper .dock-btn { padding: 5px .6rem 0 !important; }
#MenuWrapper .dock-btn span { line-height: 1.2; }
#MenuWrapper .dock-btn i { line-height: 1.1; }
#MenuWrapper .container-buttons > :hover > .dock-btn:not(.dock-active) {
    background: color-mix(in srgb, var(--ds-accent-1-text) 13%, transparent);
}
#MenuWrapper .container-buttons > :hover > .dock-btn i { transform: scale(1.1); }
#MenuWrapper .container-buttons > :has(+ :hover) > .dock-btn i,
#MenuWrapper .container-buttons > :hover + * > .dock-btn i { transform: scale(1.04); }
#MenuWrapper .container-buttons > :hover > .dock-btn:active i { transform: scale(.9); transition-duration: .08s; }
#MenuWrapper .container-buttons > :hover > .dock-btn a i,
#MenuWrapper .container-buttons > :hover > .dock-btn a span { color: var(--ds-accent-1-text) !important; }
@media (prefers-reduced-motion: reduce) {
    #MenuWrapper .dock-btn i { transition: color .2s ease; }
    #MenuWrapper .container-buttons > * > .dock-btn i { transform: none !important; }
}

@keyframes dockBounceIn {
    0% { transform: translateY(120%) scale(0.3); opacity: 0; }
    35% { transform: translateY(-5%) scale(1.05); opacity: 0.9; }
    55% { transform: translateY(3%) scale(0.98); opacity: 1; }
    100% { transform: translateY(0) scale(1); opacity: 1; }
}

#MenuWrapper.animate-in {
    animation: dockBounceIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards;
}

/* Seitenwechsel (04.11.2026): Das Dock kommt mit der Seite (kein Platzhalter, kein Nachladen mehr).
   Dazu blendet der Browser von Seite zu Seite kurz über, statt hart zu schneiden — das Dock steht in
   beiden Bildern an derselben Stelle und bleibt dadurch ruhig. Bewusst KEIN view-transition-name am
   Dock: der macht es zur Backdrop-Root, der Glas-Blur dahinter fiele weg. Chrome/Android ab 126,
   Safari ab 18.2; ältere Browser wechseln wie bisher. Kurz gehalten, weil Klicks während des
   Überblendens ins Leere gehen. */
@media (prefers-reduced-motion: no-preference) {
    @view-transition { navigation: auto; }
}
::view-transition-old(root),
::view-transition-new(root) { animation-duration: .15s; }

/* padding-bottom für Content damit Dock nichts überdeckt */
html.ds-page main { padding-bottom: 90px; }
/* Ohne Dock (Gast) reicht normaler Boden-Abstand. */
html.ds-page.ds-guest main { padding-bottom: 1.5rem; }

/* ============================================
   Header-Buttons (card-header-button / icon-button)
   Extracted from site.css for compatibility
   ============================================ */
.icon-button {
    display: flex !important;
    flex-direction: column !important;
    align-items: center !important;
    justify-content: center !important;
    text-decoration: none !important;
    gap: 0.15rem;
}

.icon-button:hover {
    text-decoration: none !important;
    transform: translateY(-2px);
}

.icon-button-icon {
    font-size: 1.25rem !important;
    line-height: 1 !important;
    margin-bottom: 0.15rem !important;
}

.icon-button-text {
    font-size: 0.92rem !important;
    line-height: 1.05 !important;
    margin: 0 !important;
}

html.ds-page .card-header-button {
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    height: 54px !important;
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius);
    background: var(--ds-card);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

html.ds-page .card-header-button:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

html.ds-page .card-header-button .card-body {
    padding: 0 0.75rem !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
}

/* ============================================
   DOCK — Modern glass look (ds-page override)
   ============================================ */
html.ds-page #MenuWrapper {
    background: none;
    box-shadow: none;
}

html.ds-page #Dock {
    background: rgba(255, 255, 255, 0.72);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-radius: 1rem;
    border: 1px solid color-mix(in srgb, var(--ds-accent-1) 30%, rgba(255, 255, 255, 0.4));
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1), 0 0 12px color-mix(in srgb, var(--ds-accent-1) 10%, transparent);
    width: max-content;
    max-width: 80vw;
    margin: 0 auto;
    padding: 0.25rem 0.5rem;
    flex-wrap: nowrap;
    overflow: hidden;
}

@media (max-width: 768px) {
    html.ds-page #Dock {
        max-width: calc(100vw - 16px);
    }
}

html.ds-page #Dock #CallMenu {
    /* Nur SEITLICH abschneiden (überzählige Kacheln, fitDockIcons) — nach oben darf das wachsende
       Hover-Symbol überstehen. `clip` statt `hidden`, weil hidden die andere Achse auf auto zwänge. */
    overflow-x: clip;
    overflow-y: visible;
    min-width: 0;
}

/* Die Bootstrap-Spalten des Docks (col-11 Kacheln / col-1 Chat) rechnen in Prozent der
   Dock-Breite — die ist hier aber max-content, also aus genau diesen Spalten errechnet. Die
   Kachel-Spalte bekam so 11/12 ihrer eigenen Breite, und fitDockIcons() schnitt die letzte
   Kachel ab. Ohne Chat-Knopf und ohne Verlauf war das Home (nur „Menü" blieb, jemo 25.09.2026).
   Deshalb Inhaltsbreite statt Prozent; nur die Kachel-Spalte schrumpft, wenn 80vw greift. */
html.ds-page #Dock > .col {
    flex: 0 0 auto;
    width: auto;
}
html.ds-page #Dock > .col-11 {
    flex: 1 1 auto;
    min-width: 0;
}

html.ds-page .dock-btn {
    background: transparent;
    border: none;
    border-radius: 0.625rem;
}

html.ds-page .dock-btn a,
html.ds-page .dock-btn a span,
html.ds-page .dock-btn i {
    color: var(--ds-foreground) !important;
}

html.dark.ds-page .dock-btn a,
html.dark.ds-page .dock-btn a span,
html.dark.ds-page .dock-btn i {
    color: #fafafa !important;
}

@media (prefers-color-scheme: dark) {
    html.ds-page:not(.light) .dock-btn a,
    html.ds-page:not(.light) .dock-btn a span,
    html.ds-page:not(.light) .dock-btn i {
        color: #fafafa !important;
    }
}

html.ds-page .dock-btn.dock-active a,
html.ds-page .dock-btn.dock-active a span,
html.ds-page .dock-btn.dock-active a i,
html.ds-page .dock-btn.dock-active i.h4,
html.ds-page .dock-btn a.text-primary,
html.ds-page .dock-btn a.text-primary span,
html.ds-page .dock-btn a.text-primary i {
    color: var(--ds-accent-1-text) !important;   /* -text: im Dunkelmodus aufgehellt, dunkle Leitfarbe sonst unsichtbar */
}

html.ds-page .dock-btn.dock-active,
html.ds-page .dock-btn:has(a.text-primary) {
    background: color-mix(in srgb, var(--ds-accent-1-text) 16%, transparent);
}

html.ds-page .dock-btn:hover {
    background: color-mix(in srgb, var(--ds-accent-1) 12%, transparent);
}

/* Dunkel: feine helle Haarlinie statt Rahmen in voller Leitfarbe (max, 03.11.2026: „hässlich") —
   wie der Rand der Flächen im Dunkelmodus (--ds-surface-shadow). Ein Hauch Akzent bleibt in der Linie. */
html.dark.ds-page #Dock {
    background: rgba(30, 30, 30, 0.85);
    border: 1px solid color-mix(in srgb, var(--ds-accent-1-text) 15%, rgba(255, 255, 255, 0.1));
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}

html.dark.ds-page .dock-btn:hover {
    background: color-mix(in srgb, var(--ds-accent-1) 15%, transparent);
}

@media (prefers-color-scheme: dark) {
    html.ds-page:not(.light) #Dock {
        background: rgba(30, 30, 30, 0.85);
        border: 1px solid color-mix(in srgb, var(--ds-accent-1-text) 15%, rgba(255, 255, 255, 0.1));
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
    }

    html.ds-page:not(.light) .dock-btn:hover {
        background: color-mix(in srgb, var(--ds-accent-1) 15%, transparent);
    }
}

/* ---------- Stat-Widget / Activity-List / Empty-State (Paket C) ---------- */
.ds-stat { margin-bottom: 0; padding: 1rem; }
.ds-stat-top { display:flex; justify-content:space-between; align-items:start; margin-bottom:.75rem; }
.ds-stat-label { font-size:.75rem; color:var(--ds-muted-foreground); font-weight:500; }
.ds-stat-icon { width:2rem; height:2rem; border-radius:.5rem; display:flex; align-items:center; justify-content:center; }
.ds-stat-icon i { font-size:.95rem; }
.ds-stat-value { font-size:1.875rem; font-weight:700; line-height:1; margin-bottom:.375rem; font-variant-numeric:tabular-nums; }
.ds-stat-value .ds-unit { font-size:1rem; color:var(--ds-muted-foreground); font-weight:500; }
.ds-stat-trend { display:flex; align-items:center; gap:.25rem; font-size:.75rem; }
.ds-stat-trend b { font-weight:600; }
.ds-stat-trend .ds-sub { color:var(--ds-muted-foreground); font-weight:400; }
.ds-stat-spark { height:28px; margin-top:.125rem; }

.ds-tint-success  { background: color-mix(in srgb, var(--ds-success) 12%, var(--ds-background)); }
.ds-tint-info     { background: color-mix(in srgb, var(--ds-info) 12%, var(--ds-background)); }
.ds-tint-warning  { background: color-mix(in srgb, var(--ds-warning) 12%, var(--ds-background)); }
.ds-tint-primary  { background: color-mix(in srgb, var(--ds-primary) 12%, var(--ds-background)); }
.ds-tint-destr    { background: color-mix(in srgb, var(--ds-destructive) 12%, var(--ds-background)); }
.ds-tint-muted    { background: color-mix(in srgb, var(--ds-muted-foreground) 10%, var(--ds-background)); }

.ds-fg-success { color: var(--ds-success); }
.ds-fg-info    { color: var(--ds-info); }
.ds-fg-warning { color: var(--ds-warning); }
.ds-fg-primary { color: var(--ds-primary); }
.ds-fg-destr   { color: var(--ds-destructive); }
.ds-fg-muted   { color: var(--ds-muted-foreground); }

.ds-activity-wrap { margin-bottom:0; padding:0; overflow:hidden; }
.ds-activity-head { padding:.875rem 1rem; border-bottom:1px solid var(--ds-border); display:flex; align-items:center; justify-content:space-between; font-size:.875rem; font-weight:600; }
.ds-activity-body { display:flex; flex-direction:column; }
.ds-activity-row { display:flex; align-items:center; gap:.75rem; padding:.75rem 1rem; border-bottom:1px solid var(--ds-border); }
.ds-activity-row:last-child { border-bottom:0; }
.ds-activity-icon { width:2.25rem; height:2.25rem; border-radius:.5rem; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.ds-activity-main { flex:1; min-width:0; }
.ds-activity-title { font-size:.875rem; font-weight:600; }
.ds-activity-meta { font-size:.75rem; color:var(--ds-muted-foreground); display:flex; gap:.75rem; }
.ds-activity-val { text-align:right; font-size:.75rem; }
.ds-activity-val b { font-weight:600; color:var(--ds-foreground); font-variant-numeric:tabular-nums; }
.ds-activity-val .ds-sub { color:var(--ds-muted-foreground); font-weight:400; }

.ds-empty { margin-bottom:0; padding:2.5rem 1.5rem; text-align:center; }
.ds-empty-icon { width:4rem; height:4rem; margin:0 auto 1rem; border-radius:50%; display:flex; align-items:center; justify-content:center; }
.ds-empty-icon i { font-size:1.75rem; }
.ds-empty-title { font-size:1rem; font-weight:600; margin-bottom:.375rem; overflow-wrap:break-word; hyphens:auto; }
.ds-empty-desc { font-size:.8125rem; color:var(--ds-muted-foreground); margin-bottom:1.25rem; max-width:280px; margin-left:auto; margin-right:auto; line-height:1.5; }

.ds-stat-grid-4 { display:grid; grid-template-columns:repeat(4,1fr); gap:1rem; }
.ds-stat-list-single { max-width:560px; display:flex; flex-direction:column; gap:1rem; }
.ds-empty-grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }

/* Modal Body-Toolbar — sticky row im modal-body mit Suche + Aktionen */
.ds-modal-toolbar { display:flex; align-items:center; gap:.5rem; padding:.625rem 1rem; border-bottom:1px solid var(--ds-border); background:var(--ds-card); position:sticky; top:0; z-index:2; }
.ds-modal-toolbar-spacer { flex:1; }
.ds-modal-toolbar-search { display:flex; align-items:center; gap:.375rem; padding:.375rem .625rem; border:1px solid var(--ds-border); border-radius:.375rem; background:var(--ds-background); min-width:200px; }
.ds-modal-toolbar-search i { color:var(--ds-muted-foreground); font-size:.875rem; }
.ds-modal-toolbar-search input { flex:1; border:0; background:transparent; outline:0; font-size:.8125rem; color:var(--ds-foreground); }

/* Modal Dashboard-Body — Stack aus Stats + Chart + Aktivitaetsliste */
.ds-modal-dash { padding:1rem 1.25rem; display:flex; flex-direction:column; gap:1rem; }
.ds-modal-dash-stats { display:grid; grid-template-columns:repeat(3,1fr); gap:.75rem; }
.ds-modal-chart-wrap { padding:1rem; }
.ds-modal-chart { position:relative; height:240px; }
@media (max-width: 768px) { .ds-modal-dash-stats { grid-template-columns:1fr; } }

/* Task-Card Utilities — wiederverwendbar fuer Listen-Modals, Kanban, etc. */
.ds-modal-list { padding:1rem; display:flex; flex-direction:column; gap:.625rem; }
.ds-task-title { font-size:.8125rem; font-weight:600; margin-bottom:.375rem; }
.ds-task-badges { display:flex; gap:.25rem; margin-bottom:.375rem; flex-wrap:wrap; }
.ds-task-meta { display:flex; justify-content:space-between; align-items:center; font-size:.6875rem; color:var(--ds-muted-foreground); gap:.5rem; }
.ds-task-border-primary { border-left:3px solid var(--ds-primary); }
.ds-task-border-success { border-left:3px solid var(--ds-success); }
.ds-task-border-warning { border-left:3px solid var(--ds-warning); }
.ds-task-border-destr   { border-left:3px solid var(--ds-destructive); }
.ds-task-border-muted   { border-left:3px solid var(--ds-muted-foreground); }

/* Badges mit semantischer Farbe — ergaenzen .ds-card-badge */
.ds-badge-primary { background:color-mix(in srgb, var(--ds-primary) 12%, var(--ds-background)); color:var(--ds-primary); }
.ds-badge-info    { background:color-mix(in srgb, var(--ds-info) 12%, var(--ds-background)); color:var(--ds-info); }
.ds-badge-success { background:color-mix(in srgb, var(--ds-success) 12%, var(--ds-background)); color:var(--ds-success); }
.ds-badge-warning { background:color-mix(in srgb, var(--ds-warning) 12%, var(--ds-background)); color:var(--ds-warning); }
.ds-badge-destr   { background:color-mix(in srgb, var(--ds-destructive) 12%, var(--ds-background)); color:var(--ds-destructive); }
.ds-badge-neutral { background:color-mix(in srgb, var(--ds-muted-foreground) 12%, var(--ds-background)); color:var(--ds-muted-foreground); }

/* ============================================================ */
/* Alerts                                                        */
/* ============================================================ */
.ds-alert { display:flex; gap:.75rem; padding:.875rem 1rem; border-radius:.5rem; border:1px solid var(--ds-border); background:var(--ds-card); align-items:flex-start; }
.ds-alert-icon { flex-shrink:0; font-size:1.125rem; line-height:1; margin-top:.125rem; }
.ds-alert-body { flex:1; min-width:0; }
.ds-alert-title { font-weight:600; font-size:.875rem; margin-bottom:.125rem; color:var(--ds-foreground); }
.ds-alert-text { font-size:.8125rem; color:var(--ds-muted-foreground); line-height:1.4; }
.ds-alert-close { background:transparent; border:0; color:var(--ds-muted-foreground); cursor:pointer; padding:.125rem .375rem; border-radius:.25rem; font-size:1rem; line-height:1; }
.ds-alert-close:hover { background:var(--ds-muted); color:var(--ds-foreground); }
.ds-alert-info     { border-color:color-mix(in srgb, var(--ds-info) 35%, var(--ds-border));        background:color-mix(in srgb, var(--ds-info) 8%, var(--ds-card)); }
.ds-alert-info     .ds-alert-icon { color:var(--ds-info); }
.ds-alert-success  { border-color:color-mix(in srgb, var(--ds-success) 35%, var(--ds-border));     background:color-mix(in srgb, var(--ds-success) 8%, var(--ds-card)); }
.ds-alert-success  .ds-alert-icon { color:var(--ds-success); }
.ds-alert-warning  { border-color:color-mix(in srgb, var(--ds-warning) 35%, var(--ds-border));     background:color-mix(in srgb, var(--ds-warning) 8%, var(--ds-card)); }
.ds-alert-warning  .ds-alert-icon { color:var(--ds-warning); }
.ds-alert-destr    { border-color:color-mix(in srgb, var(--ds-destructive) 35%, var(--ds-border)); background:color-mix(in srgb, var(--ds-destructive) 8%, var(--ds-card)); }
.ds-alert-destr    .ds-alert-icon { color:var(--ds-destructive); }

/* ============================================================ */
/* Chat / Message-List / AI-Streaming                            */
/* ============================================================ */
.ds-chat-wrap { display:flex; flex-direction:column; min-height:0; border:1px solid var(--ds-border); border-radius:.625rem; background:var(--ds-card); overflow:hidden; }
.ds-chat-head { padding:.75rem 1rem; border-bottom:1px solid var(--ds-border); display:flex; align-items:center; gap:.625rem; font-size:.8125rem; font-weight:600; color:var(--ds-foreground); background:var(--ds-card); }
.ds-chat-head .bi { color:var(--ds-primary); font-size:1rem; }
.ds-chat-head-spacer { flex:1; }
.ds-chat-list { flex:1; min-height:0; overflow-y:auto; padding:1rem; display:flex; flex-direction:column; gap:.75rem; background:color-mix(in srgb, var(--ds-muted) 30%, var(--ds-background)); }
.ds-chat-msg { display:flex; max-width:85%; gap:.5rem; }
.ds-chat-msg-user { align-self:flex-end; flex-direction:row-reverse; }
.ds-chat-msg-bot  { align-self:flex-start; }
.ds-chat-avatar { width:1.75rem; height:1.75rem; border-radius:50%; background:var(--ds-muted); display:flex; align-items:center; justify-content:center; color:var(--ds-muted-foreground); flex-shrink:0; font-size:.9rem; }
.ds-chat-msg-user .ds-chat-avatar { background:color-mix(in srgb, var(--ds-primary) 20%, var(--ds-muted)); color:var(--ds-primary); }
.ds-chat-msg-bot  .ds-chat-avatar { background:color-mix(in srgb, var(--ds-info) 20%, var(--ds-muted));    color:var(--ds-info); }
.ds-chat-bubble { padding:.625rem .875rem; border-radius:.75rem; font-size:.8125rem; line-height:1.45; word-wrap:break-word; overflow-wrap:break-word; max-width:100%; }
.ds-chat-bubble-user { background:var(--ds-primary); color:var(--ds-primary-foreground); border-bottom-right-radius:.25rem; }
.ds-chat-bubble-bot  { background:var(--ds-card); color:var(--ds-foreground); border-bottom-left-radius:.25rem; border:1px solid var(--ds-border); }
.ds-chat-bubble-bot :is(p,h1,h2,h3,h4,h5,h6,ul,ol,pre,blockquote):first-child { margin-top:0; }
.ds-chat-bubble-bot :is(p,h1,h2,h3,h4,h5,h6,ul,ol,pre,blockquote):last-child  { margin-bottom:0; }
.ds-chat-bubble-bot p { margin:.4rem 0; }
.ds-chat-bubble-bot ul, .ds-chat-bubble-bot ol { margin:.4rem 0 .4rem 1.1rem; padding:0; }
.ds-chat-bubble-bot code { background:var(--ds-muted); padding:.05rem .35rem; border-radius:.25rem; font-size:.78rem; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.ds-chat-bubble-bot pre { background:var(--ds-muted); padding:.5rem .625rem; border-radius:.375rem; overflow-x:auto; font-size:.76rem; }
.ds-chat-typing { display:inline-flex; gap:.25rem; padding:.125rem 0; align-items:center; }
.ds-chat-typing span { width:.4rem; height:.4rem; border-radius:50%; background:var(--ds-muted-foreground); opacity:.4; animation:ds-chat-bounce 1.2s infinite; }
.ds-chat-typing span:nth-child(2) { animation-delay:.15s; }
.ds-chat-typing span:nth-child(3) { animation-delay:.3s; }
@keyframes ds-chat-bounce { 0%,60%,100% { transform:translateY(0); opacity:.4; } 30% { transform:translateY(-.2rem); opacity:1; } }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.ds-chat-input-row { display:flex; gap:.5rem; padding:.75rem 1rem; border-top:1px solid var(--ds-border); background:var(--ds-card); align-items:flex-end; }
.ds-chat-input { flex:1; border:1px solid var(--ds-border); border-radius:.5rem; padding:.5rem .75rem; background:var(--ds-background); color:var(--ds-foreground); font-size:.8125rem; resize:none; min-height:2.25rem; max-height:8rem; outline:none; font-family:inherit; line-height:1.4; }
.ds-chat-input:focus { border-color:var(--ds-primary); box-shadow:0 0 0 2px color-mix(in srgb, var(--ds-primary) 20%, transparent); }
.ds-chat-input:disabled { opacity:.6; cursor:not-allowed; }
.ds-chat-empty { text-align:center; color:var(--ds-muted-foreground); padding:2rem 1rem; font-size:.8125rem; }
.ds-chat-hint  { font-size:.6875rem; color:var(--ds-muted-foreground); padding:.25rem 1rem .5rem; background:var(--ds-card); }

/* Chat im Modal — füllt modal-body komplett, ohne eigene Border (modal-content liefert sie).
   modal-header ersetzt ds-chat-head, ds-chat-input-row sitzt sticky am unteren Rand. */
.modal-body.ds-modal-chat-body {
    padding: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--ds-modal-surface);
}
.modal-body.ds-modal-chat-body .ds-chat-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    background: transparent;
    padding: 1rem 1.25rem;
}
/* Bot-Bubble auf Modal-Body: hellere Karten-Fläche statt Card-Background — sonst verschwindet sie auf grauem Modal-Surface */
.modal-body.ds-modal-chat-body .ds-chat-bubble-bot {
    background: var(--ds-modal-card);
    border-color: color-mix(in srgb, var(--ds-border) 50%, transparent);
}
/* Floating-Pill-Composer — sitzt auf der Modal-Surface, weicher Schatten nach oben statt harter Border */
.ds-chat-composer {
    flex-shrink: 0;
    padding: .75rem 1rem 1rem;
    background: var(--ds-modal-surface);
    position: relative;
    display: flex;
    flex-direction: column;
    gap: .375rem;
}
.ds-chat-composer::before {
    content: '';
    position: absolute;
    left: 0; right: 0; top: -16px; height: 16px;
    background: linear-gradient(to top, var(--ds-modal-surface), transparent);
    pointer-events: none;
}
.ds-chat-composer-pill {
    display: flex;
    align-items: flex-end;
    gap: .375rem;
    background: var(--ds-modal-card);
    border: 1px solid color-mix(in srgb, var(--ds-border) 55%, transparent);
    border-radius: 1.25rem;
    padding: .375rem .375rem .375rem .625rem;
    box-shadow:
        0 1px 2px rgba(0,0,0,.04),
        0 6px 18px -8px rgba(0,0,0,.12);
    transition: border-color 150ms ease, box-shadow 150ms ease;
}
.ds-chat-composer-pill:focus-within {
    border-color: color-mix(in srgb, var(--ds-primary) 55%, var(--ds-border));
    box-shadow:
        0 1px 2px rgba(0,0,0,.04),
        0 8px 22px -8px color-mix(in srgb, var(--ds-primary) 25%, transparent);
}
html.dark .ds-chat-composer-pill {
    box-shadow:
        0 0 0 1px rgba(255,255,255,.04),
        0 6px 20px -8px rgba(0,0,0,.5);
}
.ds-chat-composer-icon {
    flex-shrink: 0;
    width: 2rem; height: 2rem;
    border-radius: 50%;
    border: none;
    background: transparent;
    color: var(--ds-muted-foreground);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
    align-self: flex-end;
}
.ds-chat-composer-icon:hover { background: color-mix(in srgb, var(--ds-muted) 70%, transparent); color: var(--ds-foreground); }
.ds-chat-composer-icon i { font-size: 1rem; }
.ds-chat-composer-input {
    flex: 1;
    border: none;
    background: transparent;
    outline: none;
    resize: none;
    color: var(--ds-foreground);
    font-size: .875rem;
    line-height: 1.45;
    font-family: inherit;
    min-height: 2rem;
    max-height: 10rem;
    padding: .375rem .25rem;
}
.ds-chat-composer-input::placeholder { color: var(--ds-muted-foreground); }
.ds-chat-composer-input:disabled { opacity: .6; cursor: not-allowed; }
.ds-chat-composer-send {
    flex-shrink: 0;
    width: 2.25rem; height: 2.25rem;
    border-radius: 50%;
    border: none;
    background: var(--ds-primary);
    color: var(--ds-primary-foreground);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: transform 120ms ease, background 120ms ease, opacity 120ms ease;
    align-self: flex-end;
}
.ds-chat-composer-send:hover:not(:disabled) {
    background: color-mix(in srgb, var(--ds-primary) 88%, black);
    transform: translateY(-1px);
}
.ds-chat-composer-send:disabled {
    opacity: .35;
    cursor: not-allowed;
    background: var(--ds-muted-foreground);
}
.ds-chat-composer-send i { font-size: 1.05rem; font-weight: 600; }
.ds-chat-composer-hint {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .5rem;
    padding: 0 .5rem;
    font-size: .6875rem;
    color: var(--ds-muted-foreground);
}
.ds-chat-composer-hint kbd {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .625rem;
    padding: .05rem .3rem;
    border-radius: .25rem;
    background: color-mix(in srgb, var(--ds-muted) 80%, transparent);
    border: 1px solid color-mix(in srgb, var(--ds-border) 70%, transparent);
    color: var(--ds-foreground);
}
/* Wenn der Chat den ganzen Modal-Body einnimmt, ist das Modal vertikal gefüllt — Höhe per modal-dialog steuern */
.modal-dialog.ds-modal-dialog-chat { height: min(80vh, 720px); }
.modal-dialog.ds-modal-dialog-chat .modal-content { height: 100%; }
/* Im Vollbild-Bereich schlägt die feste Chat-Höhe (0,2,0) sonst die Fullscreen-Klasse (0,1,0).
   Jede Variante in IHRER Query — sonst würde ein sm-down-Chat schon bei 900px auf 100% springen,
   wo er gar nicht vollflächig ist. */
@media (max-width: 575.98px) { .modal-fullscreen-sm-down.ds-modal-dialog-chat { height: 100%; } }
@media (max-width: 767.98px) { .modal-fullscreen-md-down.ds-modal-dialog-chat { height: 100%; } }
@media (max-width: 991.98px) { .modal-fullscreen-lg-down.ds-modal-dialog-chat { height: 100%; } }

/* ============================================================ */
/* Timeline / Activity-Verlauf                                    */
/* ============================================================ */
.ds-timeline { position:relative; padding-left:1.5rem; display:flex; flex-direction:column; gap:1rem; }
.ds-timeline::before { content:''; position:absolute; left:.4375rem; top:.25rem; bottom:.25rem; width:2px; background:var(--ds-border); border-radius:1px; }
.ds-timeline-day { position:relative; display:flex; flex-direction:column; gap:.5rem; }
.ds-timeline-day-label { position:relative; font-size:.6875rem; text-transform:uppercase; letter-spacing:.05em; font-weight:600; color:var(--ds-muted-foreground); margin-left:-.125rem; margin-bottom:.125rem; }
.ds-timeline-item { position:relative; padding:.625rem .875rem; border:1px solid var(--ds-border); border-radius:.5rem; background:var(--ds-card); }
.ds-timeline-item::before { content:''; position:absolute; left:-1.3125rem; top:.9375rem; width:.625rem; height:.625rem; border-radius:50%; background:var(--ds-primary); border:2px solid var(--ds-background); box-shadow:0 0 0 2px var(--ds-primary); }
.ds-timeline-item-title { font-size:.8125rem; font-weight:600; margin-bottom:.125rem; color:var(--ds-foreground); }
.ds-timeline-item-meta { font-size:.6875rem; color:var(--ds-muted-foreground); display:flex; gap:.625rem; flex-wrap:wrap; }
.ds-timeline-item-body { font-size:.8125rem; color:var(--ds-foreground); margin-top:.375rem; line-height:1.45; }
.ds-timeline-item-actions { display:flex; gap:.25rem; margin-top:.5rem; justify-content:flex-end; }
.ds-timeline-item-success::before { background:var(--ds-success);          box-shadow:0 0 0 2px var(--ds-success); }
.ds-timeline-item-warning::before { background:var(--ds-warning);          box-shadow:0 0 0 2px var(--ds-warning); }
.ds-timeline-item-destr::before   { background:var(--ds-destructive);      box-shadow:0 0 0 2px var(--ds-destructive); }
.ds-timeline-item-muted::before   { background:var(--ds-muted-foreground); box-shadow:0 0 0 2px var(--ds-muted-foreground); }

/* Änderungsprotokoll — Diff-Segmente in Timeline-Karten (Feld: alt → neu). Nur ds-Tokens. */
.ds-log-seg { display:flex; align-items:center; gap:.4rem; flex-wrap:wrap; }
.ds-log-seg + .ds-log-seg { margin-top:.35rem; }
.ds-log-old { color:var(--ds-muted-foreground); text-decoration:line-through; }
.ds-log-new { color:var(--ds-foreground); font-weight:500; }
.ds-log-arrow { color:var(--ds-muted-foreground); font-size:.7rem; }

/* ============================================================ */
/* Tabs                                                           */
/* ============================================================ */
.ds-tabs-wrap { display:flex; flex-direction:column; gap:1rem; min-width:0; }
.ds-tabs-list { display:flex; gap:.125rem; border-bottom:1px solid var(--ds-border); overflow-x:auto; }
.ds-tabs-list-pill { border:0; background:color-mix(in srgb, var(--ds-muted) 50%, var(--ds-card)); border-radius:.5rem; padding:.25rem; gap:.25rem; width:fit-content; }
.ds-tab { background:transparent; border:0; padding:.5rem .875rem; font-size:.8125rem; font-weight:500; color:var(--ds-muted-foreground); cursor:pointer; border-bottom:2px solid transparent; margin-bottom:-1px; white-space:nowrap; display:inline-flex; align-items:center; gap:.375rem; transition:color .15s, border-color .15s, background .15s; }
.ds-tab:hover { color:var(--ds-foreground); }
.ds-tab-active { color:var(--ds-primary); border-bottom-color:var(--ds-primary); }
.ds-tabs-list-pill .ds-tab { border-bottom:0; border-radius:.375rem; padding:.375rem .75rem; margin-bottom:0; }
.ds-tabs-list-pill .ds-tab-active { background:var(--ds-card); color:var(--ds-foreground); box-shadow:0 1px 2px color-mix(in srgb, black 10%, transparent); }
.ds-tab-panel { display:none; min-width:0; }
.ds-tab-panel-active { display:block; }
.ds-tab-badge { background:color-mix(in srgb, var(--ds-muted) 70%, transparent); color:var(--ds-muted-foreground); font-size:.625rem; padding:.0625rem .375rem; border-radius:1rem; font-weight:600; }
.ds-tab-active .ds-tab-badge { background:color-mix(in srgb, var(--ds-primary) 15%, transparent); color:var(--ds-primary); }

/* Toasts: wwwroot/design/components/ds-toast.css (einzige Stelle, 05.11.2026) */

/* ============================================================
   select2 (Such-Dropdowns) — Baukasten-Theme über ds-Tokens.
   Greift app-weit auf allen _Layout_Tailwind-Seiten (Theme select2-bootstrap-5).
   Light/Dark automatisch über die Tokens. Ergänzt das fehlende Theming, da
   site.css/darktheme.css/lighttheme.css im Tailwind-Layout NICHT geladen werden.
   ============================================================ */
.select2-container--bootstrap-5 .select2-selection {
    background: var(--ds-background);
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius, 0.5rem);
    color: var(--ds-foreground);
    min-height: 2.5rem;
    box-shadow: none;
}
.select2-container--bootstrap-5.select2-container--focus .select2-selection,
.select2-container--bootstrap-5.select2-container--open .select2-selection {
    border-color: var(--ds-ring);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ds-ring) 30%, transparent);
}
.select2-container--bootstrap-5 .select2-selection--single {
    display: flex;
    align-items: center;
}
.select2-container--bootstrap-5 .select2-selection--single .select2-selection__rendered {
    color: var(--ds-foreground);
    padding-left: 0.25rem;
}
.select2-container--bootstrap-5 .select2-selection__placeholder {
    color: var(--ds-muted-foreground);
}
.select2-container--bootstrap-5 .select2-selection--single .select2-selection__arrow b {
    border-color: var(--ds-muted-foreground) transparent transparent transparent;
}
/* Dropdown-Panel */
.select2-container--bootstrap-5 .select2-dropdown {
    background: var(--ds-popover, var(--ds-card));
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius, 0.5rem);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
    color: var(--ds-foreground);
    overflow: hidden;
}
/* Suchfeld im Dropdown */
.select2-container--bootstrap-5 .select2-search--dropdown .select2-search__field {
    background: var(--ds-background);
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius, 0.5rem) - 0.15rem);
    color: var(--ds-foreground);
    padding: 0.4rem 0.6rem;
}
.select2-container--bootstrap-5 .select2-search__field:focus {
    outline: none;
    border-color: var(--ds-ring);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ds-ring) 25%, transparent);
}
/* Ergebnis-Optionen */
.select2-container--bootstrap-5 .select2-results__option {
    color: var(--ds-foreground);
    padding: 0.4rem 0.7rem;
}
.select2-container--bootstrap-5 .select2-results__option--highlighted,
.select2-container--bootstrap-5 .select2-results__option--highlighted[aria-selected] {
    background: var(--ds-accent-1);
    color: #fff;
}
.select2-container--bootstrap-5 .select2-results__option[aria-selected="true"] {
    background: color-mix(in srgb, var(--ds-accent-1) 18%, transparent);
    color: var(--ds-foreground);
}
.select2-container--bootstrap-5 .select2-results__message {
    color: var(--ds-muted-foreground);
}
/* Multiple-Select: Chips */
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
    background: var(--ds-secondary);
    border: 1px solid var(--ds-border);
    border-radius: 0.4rem;
    color: var(--ds-secondary-foreground, var(--ds-foreground));
    padding: 0.1rem 0.4rem;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove {
    color: var(--ds-muted-foreground);
    background: transparent;
    border: 0;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-search__field {
    background: transparent;
    color: var(--ds-foreground);
}

/* Höhere Spezifität (html-Prefix) + !important: das CDN-select2-bootstrap-5-Theme wird in der
   View NACH design-system.css geladen und würde sonst meine Regeln überschreiben (weiße Box). */
html .select2-container--bootstrap-5 .select2-selection {
    background: var(--ds-background) !important;
    border: 1px solid var(--ds-border) !important;
    color: var(--ds-foreground) !important;
    box-shadow: none !important;
}
html .select2-container--bootstrap-5 .select2-selection--single .select2-selection__rendered,
html .select2-container--bootstrap-5 .select2-selection__rendered { color: var(--ds-foreground) !important; }
html .select2-container--bootstrap-5 .select2-selection__placeholder { color: var(--ds-muted-foreground) !important; }
html .select2-container--bootstrap-5 .select2-dropdown {
    background: var(--ds-popover, var(--ds-card)) !important;
    border: 1px solid var(--ds-border) !important;
    color: var(--ds-foreground) !important;
}
/* Suchfeld IM Dropdown-Panel: sichtbarer Rahmen/Hintergrund (Dark-Mode-Lesbarkeit).
   NUR aufs Dropdown-Suchfeld scopen — sonst greift es auch aufs Inline-Suchfeld (siehe unten). */
html .select2-container--bootstrap-5 .select2-search--dropdown .select2-search__field {
    background: var(--ds-background) !important;
    color: var(--ds-foreground) !important;
    border: 1px solid var(--ds-border) !important;
}
/* Inline-Suchfeld im Mehrfach-Select bleibt UNSICHTBAR (nur Placeholder/Chips sichtbar) —
   wie bei allen anderen Dropdowns. Das per Placeholder auf 100% wachsende Feld darf NICHT
   als sichtbare Textbox über die ganze Select-Box erscheinen (kein Rahmen/Hintergrund/Ring). */
html .select2-container--bootstrap-5 .select2-selection--multiple .select2-search__field,
html .select2-container--bootstrap-5 .select2-selection--multiple .select2-search__field:focus {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    color: var(--ds-foreground) !important;
}
html .select2-container--bootstrap-5 .select2-results__option { color: var(--ds-foreground) !important; background: transparent !important; }
html .select2-container--bootstrap-5 .select2-results__option--highlighted,
html .select2-container--bootstrap-5 .select2-results__option--highlighted[aria-selected] { background: var(--ds-accent-1) !important; color: #fff !important; }
html .select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
    background: var(--ds-secondary) !important;
    border: 1px solid var(--ds-border) !important;
    color: var(--ds-secondary-foreground, var(--ds-foreground)) !important;
}
html .select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove { color: var(--ds-muted-foreground) !important; background: transparent !important; border: 0 !important; }

/* ============================================================
   Bootstrap-.btn → Baukasten-ds-btn-Look, GESCOPED auf den ToDo-Kontext
   (.todo-module + die ToDo-Haupt-Modals). Vermeidet 127 Markup-Umbauten und
   bringt die Buttons auf den soft-getönten ds-Look. :is() = Scope einmal,
   ID-Spezifität schlägt Bootstrap. .btn-close/.btn-check/.btn-group bleiben unberührt.
   ============================================================ */
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
    border-radius: 0.5rem; font-size: 0.8125rem; font-weight: 500; line-height: 1;
    padding: 0 0.875rem; min-height: 2.125rem;
    border: 1px solid transparent; transition: all 0.15s cubic-bezier(.4,0,.2,1);
    box-shadow: none; color: var(--ds-foreground);
}
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-sm { min-height: 1.75rem; padding: 0 0.6rem; font-size: 0.75rem; }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-xs { min-height: 1.5rem; padding: 0 0.45rem; font-size: 0.7rem; }
/* Solid-Varianten → ds soft-getönt */
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-primary { background: color-mix(in srgb, var(--ds-primary) 12%, var(--ds-background)); color: var(--ds-primary); border-color: color-mix(in srgb, var(--ds-primary) 30%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-primary:hover { background: color-mix(in srgb, var(--ds-primary) 18%, var(--ds-background)); border-color: var(--ds-primary); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-secondary { background: var(--ds-background); color: var(--ds-foreground); border-color: var(--ds-border); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-secondary:hover { background: var(--ds-muted); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-success { background: color-mix(in srgb, var(--ds-success) 12%, var(--ds-background)); color: var(--ds-success); border-color: color-mix(in srgb, var(--ds-success) 30%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-success:hover { background: color-mix(in srgb, var(--ds-success) 18%, var(--ds-background)); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-danger { background: color-mix(in srgb, var(--ds-destructive) 12%, var(--ds-background)); color: var(--ds-destructive); border-color: color-mix(in srgb, var(--ds-destructive) 30%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-danger:hover { background: color-mix(in srgb, var(--ds-destructive) 18%, var(--ds-background)); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-info { background: color-mix(in srgb, var(--ds-info) 12%, var(--ds-background)); color: var(--ds-info); border-color: color-mix(in srgb, var(--ds-info) 30%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-info:hover { background: color-mix(in srgb, var(--ds-info) 18%, var(--ds-background)); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-warning { background: color-mix(in srgb, var(--ds-warning) 12%, var(--ds-background)); color: var(--ds-warning); border-color: color-mix(in srgb, var(--ds-warning) 30%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-warning:hover { background: color-mix(in srgb, var(--ds-warning) 18%, var(--ds-background)); }
/* Outline-Varianten → ds outline */
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) [class*="btn-outline-"] { background: transparent; }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-primary { color: var(--ds-primary); border-color: color-mix(in srgb, var(--ds-primary) 40%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-primary:hover { background: color-mix(in srgb, var(--ds-primary) 12%, transparent); border-color: var(--ds-primary); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-secondary { color: var(--ds-foreground); border-color: var(--ds-border); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-secondary:hover { background: var(--ds-muted); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-info { color: var(--ds-info); border-color: color-mix(in srgb, var(--ds-info) 40%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-info:hover { background: color-mix(in srgb, var(--ds-info) 12%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-success { color: var(--ds-success); border-color: color-mix(in srgb, var(--ds-success) 40%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-success:hover { background: color-mix(in srgb, var(--ds-success) 12%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-warning { color: var(--ds-warning); border-color: color-mix(in srgb, var(--ds-warning) 40%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-warning:hover { background: color-mix(in srgb, var(--ds-warning) 12%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-danger { color: var(--ds-destructive); border-color: color-mix(in srgb, var(--ds-destructive) 40%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-outline-danger:hover { background: color-mix(in srgb, var(--ds-destructive) 12%, transparent); }
:is(.todo-module,#ModalToDo,#ModalToDetail,#ModalToDoTermin,#ModalToDoFaellig) .btn-link { color: var(--ds-primary); background: transparent; border-color: transparent; }

/* ===== ds-select: robustes Dropdown-Panel =====
   Die Tailwind-Utilities (max-h/overflow/z) stehen nur im C#-TagHelper-String und werden vom
   Tailwind-Content-Scanner nicht erfasst → weggepurged. Daher hier explizit als CSS. */
.ds-select > [x-show="open"] {
    max-height: 18rem;
    overflow-y: auto;
    z-index: 1060;
}

/* =========================================================================
   ds-selbar — Einheitliche Mehrfachauswahl-Leiste (Header-Transform, oben angedockt)
   Modul-unabhängig: window.DsSelectionBar (ds-selection-bar.js) baut/öffnet sie.
   Erscheint als akzentfarbene Leiste am oberen Rand, fährt animiert herein.
   ========================================================================= */
.ds-selbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1200;            /* über Inhalt/Dropdowns (1000–1060), unter Modals (≈2000) */
    transform: translateY(-100%);
    transition: transform .22s cubic-bezier(.2, .7, .3, 1);
    background: var(--ds-card);
    color: var(--ds-foreground);
    border-bottom: 1px solid var(--ds-border);
    box-shadow: 0 4px 16px rgba(0, 0, 0, .10);
    padding-top: env(safe-area-inset-top);
    will-change: transform;
}

.ds-selbar.is-open {
    transform: translateY(0);
}

/* Ein Modal aus der Auswahl heraus (z. B. Arc „Senden …“, Bootstrap-z-index 1055) lag UNTER der
   Leiste — Titel und Schließen-Kreuz waren verdeckt (29.09.2026). Solange ein Modal offen ist,
   liegt die Leiste unter dem Backdrop (1050) und wird mit abgedunkelt. */
body.modal-open .ds-selbar {
    z-index: 1040;
}

.ds-selbar-inner {
    display: flex;
    align-items: center;
    gap: .75rem;
    max-width: 1100px;
    margin: 0 auto;
    padding: .6rem 1rem;
}

.ds-selbar-close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    border: 1px solid var(--ds-border);
    border-radius: 999px;
    background: transparent;
    color: var(--ds-muted-foreground);
    font-size: 1.05rem;
    cursor: pointer;
    transition: background .15s, color .15s;
}
.ds-selbar-close:hover { background: var(--ds-muted); color: var(--ds-foreground); }

.ds-selbar-count {
    flex: 0 0 auto;
    font-size: .95rem;
    white-space: nowrap;
    color: var(--ds-foreground);
}
.ds-selbar-count .ds-selbar-count-num { font-weight: 700; color: var(--ds-primary); }

.ds-selbar-actions {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-left: auto;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.ds-selbar-btn {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .4rem .8rem;
    border: 1px solid var(--ds-border);
    border-radius: .55rem;
    background: transparent;
    color: var(--ds-foreground);
    font-size: .85rem;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
    transition: background .15s, border-color .15s;
}
.ds-selbar-btn:hover { background: var(--ds-muted); }
.ds-selbar-btn i { font-size: 1rem; }

/* Primäre Bulk-Aktion — dezent in der Standard-Primärfarbe */
.ds-selbar-btn-solid {
    background: var(--ds-primary);
    color: var(--ds-primary-foreground, #fff);
    border-color: transparent;
    font-weight: 600;
}
.ds-selbar-btn-solid:hover { filter: brightness(1.06); background: var(--ds-primary); }

/* Destruktive Aktion (Löschen) — neutral, wird erst beim Hover rot */
.ds-selbar-btn-danger { color: var(--ds-destructive, #dc3545); border-color: color-mix(in srgb, var(--ds-destructive) 40%, var(--ds-border)); }
.ds-selbar-btn-danger:hover { background: var(--ds-destructive, #dc3545); border-color: transparent; color: #fff; }

/* Trenner in der Header-Toolbar (<ds-toolbar-spacer />): schluckt den Restplatz, damit alles
   DANACH rechtsbündig sitzt. Ersetzt mehrfaches align="right" — mehrere margin-left:auto in
   einem Flex-Container teilen sich den Restplatz und schieben die Karten in die MITTE. */
.ds-toolbar-spacer {
    flex: 1 1 0;
    min-width: 0;
    align-self: stretch;
}

/* Unter 768px zählt jeder Pixel der (einzeiligen) Toolbar → alle Karten kompakt hintereinander. */
@media (max-width: 767.98px) {
    .ds-toolbar-spacer { display: none; }
}

/* HILFE-KNOPF STEHT IMMER RECHTS AUSSEN — in jeder Header-Toolbar, ob automatisch angehängt
   (<ds-toolbar>) oder von Hand (<ds-help-btn variant="toolbar">). Die Regel lebt bewusst HIER und
   nicht im TagHelper: Der sah nur HTML-Text und hielt jedes „tw-ml-auto" für einen Rechtsschieber —
   auch das eines VERSTECKTEN Elements (UC_Email: Indexierungs-Status) und den Spacer, den es unter
   768px gar nicht gibt. Dann fehlte das Auto-Margin und „Hilfe" klebte links an den Kacheln
   (gemeldet 03.11.2026). CSS wertet dagegen den echten, aktuellen Zustand aus.
   Schiebt davor schon ein SICHTBARES Element nach rechts, entfällt das eigene Auto-Margin —
   zwei teilten sich sonst den Restplatz (Karten in der Mitte). */
.ds-toolbar-row > .ds-toolbar-help { margin-left: auto; }
/* Rechtsschieber = tw-ml-auto (align="right") ODER Bootstraps ms-auto (ToDo #userselection) — fehlte
   ms-auto, stand die rechte Gruppe in der Mitte. Inline-style margin-left:auto erkennt die Regel NICHT. */
.ds-toolbar-row:has(> :is(.tw-ml-auto, .ms-auto):not(.d-none, .tw-hidden, [hidden], .ds-toolbar-overflow) ~ .ds-toolbar-help) > .ds-toolbar-help {
    margin-left: 0;
}
@media (min-width: 768px) {
    .ds-toolbar-row:has(> .ds-toolbar-spacer ~ .ds-toolbar-help) > .ds-toolbar-help { margin-left: 0; }
}

/* ============================================================================
   HEADER-TOOLBAR (<ds-toolbar> → .ds-toolbar-row) — Standard für ALLE Module:
   IMMER einzeilig, alle Kacheln gleich hoch, Beschriftungen bleiben sichtbar.
   Stufen, je enger es wird:
   1. Kacheln behalten ihre natürliche Breite, Beschriftungen brechen nicht um
      (sonst wird eine Kachel höher als die anderen); Auswahlfelder schrumpfen.
   Kacheln sind auf ALLEN Breiten kompakt (Symbol über Text, ~47px hoch; seit 03.11.2026).
   2. < 768px: noch etwas knapper (Innenabstand, Schrift).
   3. < 576px: die Kacheln teilen sich die Zeile, Schrift skaliert mit der Breite;
      mehrteilige Beschriftungen dürfen zweizeilig werden (alle Kacheln wachsen mit).
   4. Passt es immer noch nicht: Kacheln von rechts ins „Mehr"-Menü
      (js/components/base/toolbar-overflow.js).
   Kachel = alles mit tw-min-w-[70px] (ds-toolbar-btn, ds-toolbar-dropdown, Hilfe, Handgebautes).
   ============================================================================ */
.ds-toolbar-row { flex-wrap: nowrap; position: relative; }
.ds-toolbar-row [class*="tw-min-w-[70px]"] { flex-shrink: 0; }
.ds-toolbar-row [class*="tw-min-w-[70px]"] > span { white-space: nowrap; }
/* Kompakte Kacheln auf ALLEN Breiten (max, 03.11.2026: „sehr raum einnehmend") — vorher erst
   unter 768px. Die Tailwind-Werte am Element (px-4 py-2, min-w 70px, Icon text-xl) sind damit
   nur noch Fallback außerhalb einer .ds-toolbar-row. Das Icon bekommt eine knappe Zeilenhöhe:
   mit der geerbten 1.5 belegte es allein ~30px der Kachelhöhe. */
.ds-toolbar-row [class*="tw-min-w-[70px]"] {
    min-width: 3.5rem !important;
    padding: .3rem .6rem !important;
    gap: .15rem !important;
}
.ds-toolbar-row [class*="tw-min-w-[70px]"] > i:not(.tw-absolute) { font-size: 1.05rem; line-height: 1.15; }
.ds-toolbar-row [class*="tw-min-w-[70px]"] > span { line-height: 1.15; }

/* Hover: weicher Schatten UNTER der Kachel in der Akzentfarbe, Hauch Tönung, 1px anheben.
   Die Tailwind-Hover-Klassen am Element wirken zwar, sind aber kaum zu sehen (#f5f5f5 auf #fff,
   grauer Schatten mit 10 % Deckkraft). Deshalb hier zentral, über Tokens → Dark/Light automatisch. */
.ds-toolbar-row [class*="tw-min-w-[70px]"] {
    transition: background-color .15s ease, border-color .15s ease, box-shadow .2s ease, transform .15s ease;
}
.ds-toolbar-row [class*="tw-min-w-[70px]"]:is(:hover, :focus-visible, [aria-expanded="true"]) {
    background: color-mix(in srgb, var(--ds-primary) 5%, var(--ds-card));
    border-color: color-mix(in srgb, var(--ds-primary) 28%, var(--ds-border));
    box-shadow: 0 2px 4px -1px rgba(0,0,0,.08),
                0 10px 20px -8px color-mix(in srgb, var(--ds-primary) 55%, transparent);
    transform: translateY(-1px);
}
.ds-toolbar-row [class*="tw-min-w-[70px]"]:active {
    transform: none;
    box-shadow: 0 2px 6px -3px color-mix(in srgb, var(--ds-primary) 40%, transparent);
}
@media (prefers-reduced-motion: reduce) {
    .ds-toolbar-row [class*="tw-min-w-[70px]"] { transition: none; }
    .ds-toolbar-row [class*="tw-min-w-[70px]"]:is(:hover, :focus-visible, [aria-expanded="true"]) { transform: none; }
}

/* ABSTAND RUND UM DIE KOPFLEISTE — Regel: oben zum Bildschirmrand = unten zum Inhalt (12px).
   Gestaltgesetz der Nähe: Die Leiste gehört zum Inhalt darunter; ihr Abstand dorthin darf nie
   größer sein als nach oben, gleich groß wirkt ruhig. ~10px oben kommen schon aus dem Rahmen
   (.ds-content/Modul), deshalb hier nur der Rest (vorher tw-mt-2 → 18px oben, 12px unten). */
.ds-toolbar.tw-mt-2 { margin-top: .125rem; }
/* Wrapper (Dropdown-Kachel) reichen die Zeilenhöhe an ihre Kachel durch. */
.ds-toolbar-row .dropdown { display: flex; }
.ds-toolbar-row .dropdown > [class*="tw-min-w-[70px]"] { flex: 1 1 auto; }
/* Felder in der Zeile (Suche, Auswahl) geben Platz ab, bevor Kacheln ins „Mehr" wandern —
   bis 6rem, darunter wären sie unbedienbar. Wrapper MIT Kacheln sind davon ausgenommen. */
.ds-toolbar-row > :not([class*="tw-min-w-[70px]"]):not(:has([class*="tw-min-w-[70px]"])):not(.ds-toolbar-spacer) {
    flex-shrink: 1;
    min-width: 6rem;
}
.ds-toolbar-row input { min-width: 0; max-width: 100%; }
@media (max-width: 767.98px) {
    .ds-toolbar-row [class*="tw-min-w-[70px]"] {
        min-width: 0 !important;
        padding: 0.3rem 0.55rem !important;
        gap: 0.1rem !important;
    }
    .ds-toolbar-row [class*="tw-min-w-[70px]"] > span { font-size: 0.72rem; }
    .ds-toolbar-row [class*="tw-min-w-[70px]"] > i { font-size: 1.05rem; }
}
@media (max-width: 575.98px) {
    .ds-toolbar-row { gap: 2px; }
    .ds-toolbar-row > *,
    .ds-toolbar-row [class*="tw-min-w-[70px]"] { flex: 1 1 auto; }
    .ds-toolbar-row [class*="tw-min-w-[70px]"] {
        min-width: min-content !important;
        padding: 0.3rem 0.15rem !important;
        justify-content: center;
    }
    .ds-toolbar-row [class*="tw-min-w-[70px]"] > span {
        font-size: clamp(9px, 2.9vw, 0.72rem);
        line-height: 1.15;
        text-align: center;
        white-space: normal;
    }
}
/* Überlauf-Kacheln: unsichtbar aus dem Fluss (Größe bleibt → kein Resize-Echo), Klick kommt übers Menü. */
.ds-toolbar-row .ds-toolbar-overflow {
    position: absolute !important;
    top: 0;
    left: 0;
    visibility: hidden !important;
    pointer-events: none !important;
}
/* Wrapper, deren einzige Kachel im „Mehr" liegt, dürfen keinen Zeilen-Gap mehr belegen. */
.ds-toolbar-row > :not([class*="tw-min-w-[70px]"]):has(> .ds-toolbar-overflow:only-child) { display: contents; }
.ds-toolbar-more[hidden] { display: none !important; }
.ds-toolbar-more-menu {
    position: fixed;
    z-index: 1090;
    min-width: 12rem;
    max-width: calc(100vw - 1rem);
    padding: 0.25rem;
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: calc(var(--ds-radius) * 0.8);
    box-shadow: 0 10px 28px rgba(0, 0, 0, .18);
}
.ds-toolbar-more-menu[hidden] { display: none; }
.ds-toolbar-more-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.5rem 0.65rem;
    border: 0;
    border-radius: calc(var(--ds-radius) * 0.6);
    background: transparent;
    color: var(--ds-foreground);
    font-size: 0.875rem;
    text-align: left;
    cursor: pointer;
}
/* Hover wie alle Menüeinträge (Block „MENÜEINTRÄGE“: Leitfarben-Tönung + Leitfarben-Text) — vorher grau
   (max 07.11.2026: „Dropdowns ohne Hover“). Gilt für das „Mehr“ der Werkzeugleiste UND das ⋮ von data-ds-overflow. */
.ds-toolbar-more-item:hover,
.ds-toolbar-more-item:focus-visible {
    background: color-mix(in srgb, var(--ds-accent-1-text) var(--ds-menu-hover), transparent);
    color: var(--ds-accent-1-text);
    outline: none;
}
.ds-toolbar-more-item:is(:hover, :focus-visible) > span { color: inherit !important; }
.ds-toolbar-more-item > i { width: 1.1rem; text-align: center; font-size: 1rem; }

/* Aktiv-Zustand einer Baukasten-Toolbar-Karte (z.B. „Auswählen" bei aktivem Auswahl-Modus). */
.ds-toolbar-btn-active {
    border-color: var(--ds-accent-1) !important;
    background: color-mix(in srgb, var(--ds-accent-1) 14%, transparent) !important;
}

/* Dropdown-Aktion in der Auswahl-Leiste (z.B. „Zu Liste"). Das Menü ist ein Popup
   → eigene Karten-/Foreground-Tokens statt der Akzent-/Weiß-Farben der Leiste. */
.ds-selbar-caret { font-size: .7rem; opacity: .85; margin-left: .1rem; }
.ds-selbar-dropdown {
    background: var(--ds-card);
    border: 1px solid var(--ds-border);
    border-radius: .55rem;
    box-shadow: 0 10px 28px rgba(0, 0, 0, .2);
    padding: .3rem;
    min-width: 12rem;
}
.ds-selbar-dropdown .dropdown-item {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .45rem .6rem;
    border-radius: .4rem;
    color: var(--ds-foreground);
}

@media (max-width: 575.98px) {
    .ds-selbar-inner { gap: .5rem; padding: .5rem .6rem; }
    .ds-selbar-count .ds-selbar-count-label { display: none; }   /* nur Zahl auf engen Screens */
    .ds-selbar-btn { padding: .4rem .6rem; }
    .ds-selbar-btn.ds-selbar-btn-iconly .ds-selbar-btn-label { display: none; }  /* opt-in Icon-only */
}

/* ===== Baukasten-Icon-Picker — shared, _DsIconPicker.cshtml + js/shared/ds-icon-picker.js =====
   Kopf: Vorschau des gewählten Symbols + Suchfeld (Baukasten-Input) + Name. Darunter ein ruhiges,
   gruppiertes Raster (Überschriften kleben beim Scrollen oben), Auswahl getönt in der Akzentfarbe statt
   vollflächig. Vorher: ungestaltetes Suchfeld mit überlagerter Lupe, gewähltes Symbol außer Sicht. */
.ds-iconpicker { display: flex; flex-direction: column; gap: 0.5rem; container-type: inline-size; }
/* Schmale Inspektoren (MyApp-/Felder-Designer): Name neben dem Suchfeld weglassen */
@container (max-width: 24rem) { .ds-iconpicker-current-name { display: none; } }
/* Arc (Archiv/Ordner) hat eine eigene Vorschau für Symbol ODER Emoji samt Farbe — die des Pickers wäre doppelt */
.arc-icon-picker .ds-iconpicker-current,
.arc-icon-picker .ds-iconpicker-current-name { display: none; }
.ds-iconpicker-head { display: flex; align-items: center; gap: 0.6rem; }
.ds-iconpicker-current {
    flex: none; width: 2.5rem; height: 2.5rem; border-radius: 0.6rem;
    display: inline-flex; align-items: center; justify-content: center; font-size: 1.25rem;
    background: color-mix(in srgb, var(--ds-accent-1, var(--ds-primary)) 12%, var(--ds-card));
    color: var(--ds-accent-1, var(--ds-primary));
    border: 1px solid color-mix(in srgb, var(--ds-accent-1, var(--ds-primary)) 30%, transparent);
}
.ds-iconpicker-searchwrap { position: relative; flex: 1 1 auto; min-width: 0; }
.ds-iconpicker-searchwrap > i {
    position: absolute; left: 0.7rem; top: 50%; transform: translateY(-50%);
    color: var(--ds-muted-foreground); font-size: 0.85rem; pointer-events: none;
}
.ds-iconpicker .ds-iconpicker-search {
    width: 100%; height: 2.5rem; padding: 0 0.75rem 0 2.1rem;
    border: 1px solid var(--ds-input); border-radius: 0.5rem;
    background: var(--ds-background); color: var(--ds-foreground);
    font-size: 0.875rem; outline: none;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.ds-iconpicker .ds-iconpicker-search::placeholder { color: var(--ds-muted-foreground); }
.ds-iconpicker .ds-iconpicker-search:focus {
    border-color: var(--ds-ring, var(--ds-primary));
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-ring, var(--ds-primary)) 20%, transparent);
}
.ds-iconpicker-current-name {
    flex: none; max-width: 9rem; font-size: 0.8rem; color: var(--ds-muted-foreground);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ds-iconpicker-grid {
    position: relative;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(2.4rem, 1fr));
    gap: 0.2rem;
    max-height: 15rem;
    overflow-y: auto;
    padding: 0 0.4rem 0.4rem;
    border: 1px solid var(--ds-border);
    border-radius: 0.6rem;
    background: var(--ds-card);
    scrollbar-width: thin;
}
.ds-iconpicker-group {
    grid-column: 1 / -1;
    position: sticky; top: 0; z-index: 1;
    padding: 0.5rem 0.2rem 0.25rem;
    background: var(--ds-card);
    font-size: 0.68rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
    color: var(--ds-muted-foreground);
}
.ds-iconpicker-item {
    display: flex; align-items: center; justify-content: center;
    aspect-ratio: 1 / 1; padding: 0;
    font-size: 1.1rem;
    border: 1px solid transparent; border-radius: 0.5rem;
    background: transparent; cursor: pointer;
    color: color-mix(in srgb, var(--ds-foreground) 80%, transparent);
    transition: background 0.12s ease, color 0.12s ease;
}
.ds-iconpicker-item:hover,
.ds-iconpicker-item:focus-visible {
    background: color-mix(in srgb, var(--ds-foreground) 7%, transparent);
    color: var(--ds-foreground);
    outline: none;
}
.ds-iconpicker-item.selected {
    background: color-mix(in srgb, var(--ds-accent-1, var(--ds-primary)) 14%, transparent);
    border-color: color-mix(in srgb, var(--ds-accent-1, var(--ds-primary)) 55%, transparent);
    color: var(--ds-accent-1, var(--ds-primary));
}
.ds-iconpicker-item[hidden], .ds-iconpicker-group[hidden], .ds-iconpicker-empty[hidden] { display: none; }
.ds-iconpicker-empty {
    grid-column: 1 / -1; padding: 1rem 0.5rem; text-align: center;
    font-size: 0.85rem; color: var(--ds-muted-foreground);
}
.ds-input-icon {
    position: relative;
    display: flex;
    align-items: center;
}
.ds-input-icon > i {
    position: absolute;
    left: 0.55rem;
    pointer-events: none;
    color: var(--ds-muted, var(--bs-secondary-color));
}
.ds-input-icon .ds-iconpicker-search {
    padding-left: 2rem;
    width: 100%;
}

/* ============================================================
   Eigene Marken-Icons
   ------------------------------------------------------------
   Verhalten sich exakt wie ein bootstrap-icon (<i class="bi bi-flow">):
   Farbe kommt via currentColor, Größe via font-size. Die Glyphe ist
   eine SVG-Maske — deshalb KEIN ::before-Zeichen wie bei bootstrap-icons.
   Neues Icon: SVG nach wwwroot/design/icons/ und hier eine Zeile ergänzen.
   ============================================================ */
.bi-flow::before {
    content: none;
}

.bi-flow {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    background-color: currentColor;
    -webkit-mask: url("/design/icons/flow.svg") no-repeat center / contain;
    mask: url("/design/icons/flow.svg") no-repeat center / contain;
}

/* ============================================================================
   Terminal-Sitzungsfarben (Linux-Konsole, 12 Stück)
   ----------------------------------------------------------------------------
   Bewusst NUR in :root und ohne Dark-/Light-Zwilling: ein Terminal hat auch im
   hellen Design einen dunklen Hintergrund — das ist die Erwartung an eine
   Konsole und hält die Farben in beiden Themes identisch. Dadurch entfällt die
   Gefahr, dass die drei Token-Blöcke auseinanderlaufen (das ist in diesem
   Stylesheet schon einmal passiert).

   Die Farben sind die EINZIGE Quelle: das Terminal-Thema wird im Browser per
   getComputedStyle von hier abgeleitet. Eine zweite Farbtabelle im JavaScript
   würde nach der ersten Token-Änderung stillschweigend abweichen.

   Die Sitzungsfarbe färbt Text, Cursor, Auswahl und den Rahmen des Fensters.
   Die 16 ANSI-Farben bleiben davon unberührt — sie tragen Bedeutung (rot =
   gelöscht, grün = hinzugefügt), und wer sie umfärbt, macht ein `git diff`
   unlesbar.
   ============================================================================ */
:root {
    --ds-term-bg: #12131a;
    --ds-term-bg-elevated: #191b24;

    /* Bewusst zwei Stufen heller als die übrigen Farben (slate-300 statt -400):
       Slate ist die einzige entsättigte Farbe der Reihe und trägt als
       Fließtext deutlich schlechter. #94a3b8 kam auf 7,2:1, jetzt 12,5:1. */
    --ds-term-slate:  #cbd5e1;
    --ds-term-red:    #f87171;
    --ds-term-orange: #fb923c;
    --ds-term-yellow: #fbbf24;
    --ds-term-lime:   #a3e635;
    --ds-term-green:  #4ade80;
    --ds-term-teal:   #2dd4bf;
    --ds-term-cyan:   #38bdf8;
    --ds-term-blue:   #60a5fa;
    --ds-term-indigo: #818cf8;
    --ds-term-violet: #c084fc;
    --ds-term-pink:   #f472b6;
}

/* ============================================================================
   ds-worktop — Kopfleiste für Arbeits-Modale (Fernwartung, Konsole, RDP, …)
   ============================================================================
   Diese Modale sind vollflächig und tragen im Kopf eine ganze Werkzeugleiste:
   Titel, Verbindungsstatus, fünf bis neun Aktionen und rechts das Schließen-X.
   Mit blossem `d-flex` läuft das auf schmalen Geräten aus dem Bild — und weil das
   X ganz rechts sitzt, verschwindet ausgerechnet der Ausgang als Erstes. Das Modal
   ist dann nur noch über die Zurück-Taste zu verlassen.

   Die Leiste bleibt IMMER einzeilig. Was nicht hineinpasst, wandert in ein
   Überlaufmenü (js/shared/ds-worktop.js) — nicht in eine zweite Zeile (die fraß
   auf dem Handy ein Viertel des Arbeitsbereichs) und nicht in einen waagerecht
   scrollbaren Bereich (den sieht man einer Werkzeugleiste nicht an; auf einem
   aufgeklappten Foldable lagen so drei Schaltflächen unsichtbar rechts daneben).

   Drei Regeln:
     1. Das Schließen-X liegt AUSSERHALB des Aktionsbereichs und schrumpft nie.
     2. Der Titel schrumpft zuerst und schneidet mit Auslassungspunkten ab.
        Reicht das nicht, räumt das Skript von rechts nach links Schaltflächen
        ins Menü — MIT Beschriftung, dort ist Platz dafür. Reine Symbolknöpfe
        sind ausdrücklich nicht erwünscht: Wer die App selten benutzt, kann sie
        nicht entziffern.
     3. `overflow: hidden` ist der Notnagel für den Fall, dass das Skript
        einmal nicht lädt — dann fehlt lieber etwas, als dass die Leiste in den
        Arbeitsbereich hineinwächst.

   Verwendung: `class="modal-header py-2 ds-worktop"`, darin `.ds-worktop-title`,
   optional `.ds-worktop-status`, dann `.ds-worktop-actions` und als letztes
   Geschwisterelement (NICHT darin!) der Schließen-Knopf mit `.ds-worktop-close`.
   Steuerung je Schaltfläche über `data-ds-worktop="keep|menu"`, Einzelheiten im
   Kopf von js/shared/ds-worktop.js.
   ------------------------------------------------------------------------- */
.ds-worktop {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: nowrap;
    min-width: 0;
    overflow: hidden;
}

/* Der Titel gibt als Erster nach und schneidet mit Auslassungspunkten ab.
   KEINE `min-width` als Untergrenze: die wirkt auch nach oben und hielte für
   einen kurzen Rechnernamen („dev") 9rem frei, die dann den Schaltflächen
   fehlen — und weil so nie ein Überlauf entstünde, räumte das Skript nichts
   ins Menü. Die Untergrenze zieht stattdessen ds-worktop.js aus dem Inhalt
   (TITEL_MIN): gequetscht wird der Titel erst, wenn das Menü schon alles
   aufgenommen hat. */
.ds-worktop > .ds-worktop-title {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-bottom: 0;
}

.ds-worktop-status {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .5rem;
}

/* Schrumpft NICHT: was nicht passt, wandert ins Menü statt gequetscht oder
   abgeschnitten zu werden. `margin-left: auto` hält die Aktionen rechts, auch
   wenn es gar keinen Status-Bereich gibt. */
.ds-worktop > .ds-worktop-actions {
    flex: 0 0 auto;
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: .5rem;
    justify-content: flex-end;
}
.ds-worktop-actions > * { flex: 0 0 auto; }

/* Der Ausgang. Steht bewusst neben dem Aktionsbereich und schrumpft nie. */
.ds-worktop-close {
    flex: 0 0 auto !important;
    margin-left: .25rem;
}

/* Der Hilfe-Knopf des <ds-modal>-TagHelpers steht ebenfalls NEBEN dem
   Aktionsbereich, nicht darin: er ist ein reiner Symbolknopf und trüge im
   Überlaufmenü keine Beschriftung — dort ist er nicht zu deuten. */
.ds-worktop > .hp-btn-modal { flex: 0 0 auto; }

/* Eigenes Markup ANSTELLE des Titel-Textes (<ds-modal-title>), in aller Regel ein
   Eingabefeld für den Namen des bearbeiteten Objekts.

   Hier gilt das Gegenteil der Regel oben: Ein <h5> mit Text darf bis auf die
   Auslassungspunkte schrumpfen, ein Eingabefeld nicht — unter ~8rem ist der Name
   weder zu lesen noch zu ändern (auf 390px real auf null gefallen, 17.09.2026).
   Die Mindestbreite ist deshalb erwünscht: Sie erzeugt den Überlauf, der
   ds-worktop.js die Schaltflächen ins Menü räumen lässt, statt den Namen zu fressen. */
.ds-worktop > .ds-worktop-title-custom {
    /* Kein `flex-grow`: Das Feld soll seine Wunschbreite halten, nicht den Rest der
       Zeile an sich ziehen — sonst wandern Schaltflächen ins Menü, obwohl daneben
       Platz wäre. */
    flex: 0 1 18rem;
    min-width: 8rem;
    overflow: visible;          /* sonst schneidet die Ellipsis-Regel den Fokusrahmen ab */
}
.ds-worktop-title-input {
    width: 100%;
    min-width: 0;
    height: 2.25rem;
    font-size: .9375rem;
}

/* Notstufen, die ds-worktop.js setzt, wenn selbst mit leerer Leiste noch der
   Titel gequetscht würde: erst weicht der Verbindungszustand, dann die
   Beschriftung des „Mehr"-Knopfs. Der Rechnername bleibt. */
.ds-worktop .ds-worktop-weg { display: none !important; }
.ds-worktop-more.ds-worktop-more-icon .ds-label { display: none; }

/* --- Überlaufmenü ---------------------------------------------------------
   Hängt an <body> (der Kopf ist `overflow: hidden`, darin wäre es abgeschnitten)
   und liegt über dem Modal. Die Einträge sind dieselben `ds-btn`-Knöpfe wie in
   der Leiste — physisch verschoben, nicht geklont: so bleiben Kennung und
   Ereignisse dieselben, und kein Skript greift versehentlich auf eine Kopie. */
.ds-worktop-menu {
    position: fixed;
    z-index: 1090;                    /* über dem Bootstrap-Modal (1055) */
    min-width: 13rem;
    max-width: min(20rem, calc(100vw - 1rem));
    padding: .3rem;
    background: var(--ds-popover, var(--ds-card));
    color: var(--ds-popover-foreground, var(--ds-card-foreground));
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius, .5rem);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
}
.ds-worktop-menu[hidden] { display: none; }

/* Im Menü sind es Einträge, keine Schaltflächen: volle Breite, linksbündig,
   ohne Rahmen — und die Beschriftung wird auf jeden Fall gezeigt, auch wenn
   sie in der Leiste ausgeblendet gewesen wäre. */
.ds-worktop-menu .ds-btn {
    width: 100%;
    justify-content: flex-start;
    gap: .1rem;
    border-color: transparent !important;
    background: transparent !important;
    color: inherit !important;
    box-shadow: none !important;
    padding: .45rem .6rem;
    font-weight: 500;
}
.ds-worktop-menu .ds-btn:hover,
.ds-worktop-menu .ds-btn:focus-visible {
    background: var(--ds-accent) !important;
    color: var(--ds-accent-foreground) !important;
}
.ds-worktop-menu .ds-btn > i { width: 1.25rem; text-align: center; }
.ds-worktop-menu .ds-btn .ds-label { display: inline !important; }

/* Der primäre Knopf verliert im Menü seine Fläche (alle Einträge sind flach) —
   erkennbar bleibt er an Farbe und Schriftstärke. In Reiterleisten ist das der
   Bereich, in dem man gerade steht. */
.ds-worktop-menu .ds-btn.ds-btn-primary {
    color: var(--ds-primary) !important;
    font-weight: 600;
}

/* Knopfgruppen wandern als Ganzes ins Menü (Bildschirmumschalter der Fernwartung,
   „Benutzer-Bildschirm / Eigene Sitzung" am Mac) — dort stehen sie untereinander.
   Nebeneinander passten zwei beschriftete Knöpfe nicht in die Menübreite. */
.ds-worktop-menu > div {
    display: flex !important;
    flex-direction: column;
    align-items: stretch;
    gap: .1rem;
    width: 100%;
}

@media (max-width: 767.98px) {
    .ds-worktop { gap: .375rem; }
    /* Im Titel darf der erklärende Teil weichen — der Rechnername bleibt. */
    .ds-worktop-title .ds-label { display: none; }
}

@media (max-width: 575.98px) {
    /* Auf dem Telefon weicht auch der Status: Ob die Verbindung steht, sieht man
       am Bild selbst, und der Platz wird für die Bedienung gebraucht. */
    .ds-worktop-status { display: none; }
}

/* ============================================================================
   ds-modal-vollbild — Arbeitsfläche im Vollbild, Kopf im Stil des Notizbuchs
   ============================================================================
   `<ds-modal vollbild="true">` (modals.md §4a). Vorbild ist die Kopfleiste des
   Notizbuchs (js/shared/ds-notizblock.js): eine helle Leiste ohne Schatten (Rahmen-Look
   wie .ds-kw-kopf, max 08.11.2026), randlose Knöpfe mit dem Symbol über der Beschriftung,
   Hover nur als Fläche. Die Views schreiben weiter ganz normale `ds-btn`-Knöpfe
   in <ds-modal-actions> — umgestylt wird ausschließlich hier, im Kopf.
   Schließen-X und Fußleiste (Abbrechen/Speichern) bleiben wie in jedem Modal.
   Wandert ein Knopf ins Überlaufmenü (ds-worktop.js), sieht er dort aus wie
   jeder andere Menüeintrag.
   Abweichung vom Notizbuch: die Beschriftung bleibt auch unter 1400px stehen —
   reine Symbolknöpfe sind im Kopf nicht erlaubt (workbench.md §2).
   ------------------------------------------------------------------------- */
.ds-modal-vollbild {
    --ds-vb-grund: color-mix(in srgb, var(--ds-foreground) 4%, var(--ds-background));
    --ds-vb-kopf-h: 4rem;
}
.ds-modal-vollbild .modal-content {
    border-radius: 0;
    box-shadow: none !important;
    background: var(--ds-card);    /* Rahmen wie bei .ds-kw-kopf: Kopf + Fuß weiß, Inhalt als Fläche darin */
}

.ds-modal-vollbild .modal-header.ds-vb-kopf {
    gap: .35rem;
    min-height: var(--ds-vb-kopf-h);
    padding: .4rem .6rem;
    padding-top: max(.4rem, env(safe-area-inset-top));
    background: var(--ds-card);
    position: relative;
    z-index: 3;
}
.ds-vb-kopf > .ds-worktop-title { font-size: 1rem; padding-left: .15rem; }
.ds-vb-kopf > .ds-worktop-actions { gap: .15rem; }

/* Knöpfe: randlos, Symbol über Beschriftung (Notizbuch ab 1400px). */
.ds-vb-kopf .ds-btn {
    flex-direction: column;
    gap: .2rem;
    height: 3.2rem;
    min-width: 3.9rem;
    padding: 0 .5rem;
    border: 0;
    border-radius: .7rem;
    background: transparent;
    color: var(--ds-foreground);
    box-shadow: none;
    font-size: .7rem;
    font-weight: 500;
    transform: none;
}
.ds-vb-kopf .ds-btn > i {
    font-size: 1.15rem;
    line-height: 1;
    height: 1.15rem;
    margin: 0 !important;
    display: flex;
    align-items: center;
}
/* Gegen die Kontrastregel des Modal-Scopes, die jedes <span> auf die Textfarbe zieht. */
.ds-vb-kopf .ds-btn .ds-label { color: inherit; }
.ds-vb-kopf .ds-btn:hover {
    background: var(--ds-accent);
    color: var(--ds-accent-foreground);
    box-shadow: none;
    transform: none;
}
/* Hauptaktion der Leiste: getönt wie das aktive Werkzeug im Notizbuch. */
.ds-vb-kopf .ds-btn-primary {
    background: color-mix(in srgb, var(--ds-primary) 14%, transparent);
    color: var(--ds-primary);
}
.ds-vb-kopf .ds-btn-primary:hover {
    background: color-mix(in srgb, var(--ds-primary) 22%, transparent);
    color: var(--ds-primary);
}
.ds-vb-kopf .ds-btn-destructive { color: var(--ds-destructive); }
.ds-vb-kopf .ds-btn-destructive:hover {
    background: color-mix(in srgb, var(--ds-destructive) 12%, transparent);
    color: var(--ds-destructive);
}
/* Inhalt: getönter Grund wie im Notizbuch; ein ds-workspace verliert seinen
   eigenen Rahmen (er IST jetzt die Fläche), Palette/Eigenschaften kleben oben. */
.ds-modal-vollbild .modal-body {
    padding: 1rem 1.25rem;
    margin: 0 .75rem;
    border-radius: calc(var(--ds-radius) * 1.6);
    background: var(--ds-vb-grund);
}
.ds-modal-vollbild .modal-content:not(:has(> .modal-footer)) > .modal-body { margin-bottom: .75rem; }
.ds-modal-vollbild .modal-footer {
    padding-bottom: max(.875rem, env(safe-area-inset-bottom));
}
.ds-modal-vollbild .ds-workspace {
    background: transparent;
    border: 0;
    border-radius: 0;
    padding: 0;
}
@media (min-width: 1101px) {
    .ds-modal-vollbild .ds-ws-side {
        top: 0;
        max-height: calc(100vh - var(--ds-vb-kopf-h) - 2rem);
        max-height: calc(100dvh - var(--ds-vb-kopf-h) - 2rem);
    }
}
/* Formulare ohne Arbeitsfläche laufen auf breiten Schirmen nicht über 2.000px
   auseinander — sie stehen mittig in Lesebreite. */
.ds-modal-vollbild .modal-body:not(:has(.ds-workspace)) > * {
    max-width: 72rem;
    margin-inline: auto;
}

@media (max-width: 767.98px) {
    /* Schmal: Symbol über Text bleibt, nur kompakter — das ist schmaler als
       nebeneinander und lässt dem Titel Platz. */
    .ds-modal-vollbild { --ds-vb-kopf-h: 3.5rem; }
    .ds-vb-kopf .ds-btn {
        flex-direction: column;
        gap: .15rem;
        height: 2.85rem;
        min-width: 2.9rem;
        padding: 0 .3rem;
        font-size: .64rem;
        font-weight: 500;
    }
    .ds-vb-kopf .ds-btn > i { font-size: 1.05rem; height: 1.05rem; }
    .ds-modal-vollbild .modal-header.ds-vb-kopf { padding-inline: .35rem; gap: .2rem; }
    .ds-vb-kopf > .ds-worktop-title { font-size: .92rem; }
    .ds-vb-kopf > .ds-worktop-title i { margin-right: .3rem !important; }
    .ds-modal-vollbild .modal-body { padding: .75rem; margin-inline: .5rem; }
}

/* ==========================================================================
   ds-kw — Kopfwerkzeuge im Notizbuch-Stil (Modal-Kopf)
   --------------------------------------------------------------------------
   Dieselben Knöpfe wie im Datei-Betrachter (.fv-kw, file-viewer.css): randlos,
   neutrale Symbole über der Beschriftung (ab 481 px, darunter nur Symbol),
   Hover nur als Fläche, die Leiste genau mittig zwischen Titel und X (ab 641 px),
   Rahmen statt Schatten (s. u.). Standard für Modal-Köpfe (max 05.11.2026,
   modals.md §4b); erster Nutzer: E-Mail verfassen (_ComposeEmail.cshtml).
     <div class="modal-header ds-kw-kopf ds-worktop">
       <h5 class="modal-title ds-worktop-title"><i class="bi bi-…"></i> <span>Titel</span></h5>
       <div class="ds-kw-leiste ds-worktop-actions">
         <button type="button" class="ds-kw"><i class="bi bi-…"></i><span>Text</span></button>
         <div class="dropdown"> ds-kw mit data-bs-toggle + <ul class="dropdown-menu ds-row-menu-list ds-kw-menu"> </div>
       </div>
       <button type="button" class="btn-close ds-worktop-close" data-bs-dismiss="modal"></button>
     </div>
   Jede Funktion hat ihren eigenen Knopf (Einstellungen als Menü-Knopf); was nicht
   in die Zeile passt, räumt ds-worktop.js ins „Mehr“ — der Knopf erscheint nur dann.
   Ein Menü-Knopf steht im „Mehr“ als Abschnitt mit seinen Einträgen darunter.
   is-on = eingeschaltet / vom Standard abweichend (Primärfarbe wie im Betrachter).
   ========================================================================== */
.modal-header.ds-kw-kopf {
    gap: .5rem;
    padding: .4rem .75rem;
    overflow: visible;             /* ds-worktop schneidet sonst die Menüs der Knöpfe ab */
    background: var(--ds-card);    /* helle Leiste wie im Betrachter, nicht die graue Modalfläche */
    position: relative;
    z-index: 2;
}
/* Rahmen (max 08.11.2026, löst den Schatten unter dem Kopf ab — „wirkt altmodisch"): Kopf, Fuß und
   Seitenleisten sind EIN weißer Rahmen, der Inhalt liegt darin als graue, rundum gerundete Fläche,
   auf der weiße Karten stehen (ds-card bzw. ds-modal-section — auch Listen stehen in einer).
   Die Kante zwischen Kopf und Inhalt entsteht nur aus Fläche und Rundung — kein Schatten, keine Linie. */
.modal-content:has(> .modal-header.ds-kw-kopf) {
    --ds-rahmen-luft: .75rem;
    --ds-rahmen-radius: calc(var(--ds-radius) * 1.6);
    background: var(--ds-card);
}
.modal-content:has(> .modal-header.ds-kw-kopf) > .modal-body {
    margin: 0 var(--ds-rahmen-luft);
    border-radius: var(--ds-rahmen-radius);
    background: var(--ds-modal-surface);
}
.modal-content:has(> .modal-header.ds-kw-kopf):not(:has(> .modal-footer)) > .modal-body {
    margin-bottom: var(--ds-rahmen-luft);
}
@media (max-width: 575.98px) {
    .modal-content:has(> .modal-header.ds-kw-kopf) { --ds-rahmen-luft: .5rem; }
}
/* Titel als Block mit „…“: so misst ds-worktop.js an ihm, ob er gequetscht wird (als Flex-Zeile
   schrumpfte nur das innere <span>, der Titel fiel unbemerkt auf „N…“). */
.ds-kw-kopf > .modal-title {
    display: block; flex: 0 1 auto; min-width: 0; margin: 0; font-size: 1rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ds-kw-kopf > .btn-close { flex: none; margin: 0; }
.ds-kw-kopf > .ds-kw-leiste { display: flex; align-items: center; gap: .15rem; margin: 0 auto; flex: none; }
@media (min-width: 641px) {
    .modal-header.ds-kw-kopf { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); column-gap: .75rem; }
    .ds-kw-kopf > .ds-kw-leiste { margin: 0; }
    .ds-kw-kopf > .btn-close { justify-self: end; }
}
/* Knopf — auch der „Mehr“-Knopf, den ds-worktop.js als ds-btn anlegt */
.ds-kw,
.ds-kw-kopf .ds-worktop-more {
    display: inline-flex; align-items: center; justify-content: center;
    height: 2.3rem; min-width: 2.3rem; padding: 0 .4rem; border: 0; border-radius: .7rem;
    background: transparent; color: var(--ds-foreground); box-shadow: none; transform: none;
    font-size: 1.1rem; font-weight: 500; line-height: 1; cursor: pointer;
    text-decoration: none; /* als Link (a.ds-kw) sonst unterstrichen — Bootstrap-Reboot, Home-Kacheln 09.11.2026 */
}
.ds-kw-kopf .ds-worktop-more[hidden] { display: none; }
.ds-kw > i, .ds-kw-kopf .ds-worktop-more > i { line-height: 1; margin: 0 !important; }
.ds-kw > span, .ds-kw-kopf .ds-worktop-more > span { display: none; }
/* Hover/offen in der Leitfarbe der Konsole (--ds-accent-1, vom Admin gesetzt) statt Grau (max 05.11.2026).
   :not(:disabled) hebt die Spezifität über die Modal-Normalizer (body > .modal button … = 0,2,2);
   Symbol und Beschriftung erben die Knopffarbe, sonst färbte der span-Normalizer sie fest. */
:is(.ds-kw, .ds-kw-kopf .ds-worktop-more):is(:hover, .show, [aria-expanded="true"]):not(:disabled) {
    background: color-mix(in srgb, var(--ds-accent-1) var(--ds-menu-hover, 14%), transparent);
    color: var(--ds-accent-1-text, var(--ds-accent-1)); box-shadow: none; transform: none;
}
:is(.ds-kw, .ds-kw-kopf .ds-worktop-more) > :is(i, span) { color: inherit !important; }
.ds-kw:disabled { opacity: .4; cursor: default; background: transparent; }
@media (min-width: 481px) {
    .ds-kw, .ds-kw-kopf .ds-worktop-more { flex-direction: column; gap: .15rem; height: 3.2rem; min-width: 3.4rem; padding: 0 .35rem; }
    .ds-kw > i, .ds-kw-kopf .ds-worktop-more > i { display: flex; align-items: center; height: 1.75rem; font-size: 1.1rem; }
    .ds-kw > span, .ds-kw-kopf .ds-worktop-more > span {
        display: block; font-size: .68rem; font-weight: 500; line-height: 1; white-space: nowrap; opacity: .85;
    }
    .ds-kw-kopf .ds-worktop-more.ds-worktop-more-icon > span { display: none; }
}
/* Eingeschaltet — in der Leitfarbe wie der Hover, nur kräftiger. Über die Leiste, sonst gewinnt die
   Modal-Regel (body > .modal button → Textfarbe); Symbol/Beschriftung erben (siehe oben). */
:is(.ds-kw-leiste, .ds-worktop-menu) .ds-kw.is-on {
    color: var(--ds-accent-1-text, var(--ds-accent-1));
    background: color-mix(in srgb, var(--ds-accent-1) var(--ds-menu-active, 22%), transparent);
}
/* Hauptaktion (höchstens EINE je Kopf, z. B. Senden; max 05.11.2026 „in Primärfarbe“): nur Symbol und
   Beschriftung in der Primärfarbe, keine Fläche — die volle Fläche war „zu deftig“ (max 05.11.2026).
   Steht mit data-ds-worktop="keep" immer in der Leiste, nie im „Mehr“. */
.ds-kw-leiste .ds-kw.ds-kw-primary { color: var(--ds-primary); }
.ds-kw-leiste .ds-kw.ds-kw-primary > span { opacity: 1; }
.ds-kw-leiste .ds-kw.ds-kw-primary:hover:not(:disabled) {
    color: var(--ds-primary); background: color-mix(in srgb, var(--ds-primary) 12%, transparent);
}
/* Menü eines Knopfs: Einträge als <button class="ds-dropdown-item"> (schließen auch das „Mehr“) */
.ds-kw-menu .ds-dropdown-item { width: 100%; border: 0; background: transparent; text-align: left; }
/* Helle Modalfläche ohne ds-kw-kopf (modals.md §4b). Mit ds-kw-kopf regelt der Rahmen oben die
   Flächen; Listen stehen dort in einer ds-modal-section. */
.modal-content.ds-modal-hell { background: var(--ds-card); }

/* Im „Mehr“: Knöpfe als Einträge (Symbol neben Text), Menü-Knöpfe als Abschnitt mit ihren
   Einträgen darunter — ein Untermenü an einem Knopf im geschlossenen „Mehr“ hinge in der Luft. */
.ds-worktop-menu .ds-kw {
    flex-direction: row; justify-content: flex-start; gap: .5rem; width: 100%; height: auto; min-width: 0;
    padding: .45rem .6rem; border-radius: .4rem; font-size: .875rem; color: inherit;
}
.ds-worktop-menu .ds-kw > i { display: inline; width: 1.25rem; height: auto; font-size: 1rem; text-align: center; }
.ds-worktop-menu .ds-kw > span { display: inline; font-size: .875rem; opacity: 1; }
.ds-worktop-menu .dropdown > .ds-kw[data-bs-toggle] {
    pointer-events: none; padding-bottom: .15rem; font-size: .75rem; font-weight: 600;
    color: var(--ds-muted-foreground);
}
.ds-worktop-menu .dropdown > .ds-kw[data-bs-toggle] > span { font-size: .75rem; }
.ds-worktop-menu .ds-kw-menu {
    display: block; position: static !important; inset: auto !important; transform: none !important;
    min-width: 0; margin: 0 0 .25rem; padding: 0 0 0 1.25rem; border: 0; box-shadow: none; background: transparent;
}

/* Querform für Bereichsköpfe mit Verlauf (Spaltenköpfe, z. B. E-Mail): derselbe Notizbuch-Knopf, aber
   Symbol NEBEN der Beschriftung und so flach, dass das Kopfband seine Höhe behält. Hover/offen als
   halbtransparente Fläche — passt sich jedem Ton des Verlaufs an. Ersetzt dort die umrandeten
   ds-chip-btn (max 05.11.2026: „im Farbverlauf irgendwie hässlich“).
     <button type="button" class="ds-kw ds-kw-quer"><i class="bi bi-…"></i><span>Text</span></button> */
.ds-kw.ds-kw-quer {
    flex-direction: row; gap: .35rem; height: 1.65rem; min-width: 1.65rem; padding: 0 .55rem; /* = Titel-Kachel, Kopf bleibt 54 px */
    border-radius: .6rem; font-size: .8rem;
    transition: background .15s ease, color .15s ease, box-shadow .15s ease, transform .1s ease;
}
.ds-kw.ds-kw-quer > i { display: inline; height: auto; font-size: .95rem; transition: transform .15s ease; }
/* Reiner Symbolknopf (keine Beschriftung, z. B. Einklappen, „⋮“): quadratisch */
.ds-kw.ds-kw-quer:not(:has(> span)) { width: 1.65rem; padding: 0; }
/* inherit !important: der Normalizer `.ds-main span:not(…)` (0,4,1) färbte die Beschriftung sonst fest */
.ds-kw.ds-kw-quer > span { display: inline; font-size: .8rem; font-weight: 500; line-height: 1; opacity: 1; color: inherit !important; }
/* Hover deutlich (max 05.11.2026: „dass der Anwender sieht, dass was passiert“): Fläche + Schrift in der
   Leitfarbe, leichter Schatten, Symbol wächst etwas; beim Drücken gibt der Knopf sichtbar nach. */
.ds-kw.ds-kw-quer:hover:not(:disabled), .ds-kw.ds-kw-quer.show {
    background: color-mix(in srgb, var(--ds-accent-1) 14%, var(--ds-card));
    color: var(--ds-accent-1-text, var(--ds-accent-1));
    box-shadow: 0 1px 4px rgba(0, 0, 0, .12);
}
.ds-kw.ds-kw-quer:hover:not(:disabled) > i { transform: scale(1.12); }
.ds-kw.ds-kw-quer:active:not(:disabled) { transform: scale(.95); box-shadow: none; }
.ds-kw.ds-kw-quer:focus-visible { outline: 2px solid var(--ds-ring); outline-offset: 1px; }
.ds-kw.ds-kw-quer.is-on { background: color-mix(in srgb, var(--ds-accent-1) var(--ds-menu-active, 22%), transparent); color: var(--ds-accent-1-text, var(--ds-accent-1)); }
.ds-kw.ds-kw-quer.is-on:hover:not(:disabled) { background: color-mix(in srgb, var(--ds-accent-1) 28%, var(--ds-card)); color: var(--ds-accent-1-text, var(--ds-accent-1)); }

/* ==========================================================================
   Marken-Glyphen
   --------------------------------------------------------------------------
   Zeichen fremder Produkte, die in Listen neben dem Namen stehen (Proxmox VE).
   Bewusst KEIN Bild: eine Bilddatei muss mit ausgeliefert werden, und genau das
   ging schief — /Media/Icons/proxmox.png lag im Entwicklungsstand, aber nicht
   auf den Servern, weshalb das Zeichen dort überall fehlte. Als Maske im
   Stylesheet ist es Teil des Designs und kann nicht verlorengehen.

   Einfarbig statt originalgetreu zweifarbig: die dunkle Hälfte des echten Logos
   wäre im dunklen Erscheinungsbild unsichtbar. Die Form (vier Keile, die auf
   einen Punkt zeigen) trägt den Wiedererkennungswert, die Farbe tut den Rest.
   ========================================================================== */

:root {
    --ds-brand-proxmox: #e57000;
    --ds-glyph-proxmox: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cpath d='M12 4h10l10 13 10-13h10L32 30Z M12 60h10l10-13 10 13h10L32 34Z M4 12v10l13 10-13 10v10L30 32Z M60 12v10L47 32l13 10v10L34 32Z'/%3E%3C/svg%3E");
}

.ds-icon-proxmox {
    display: inline-block;
    width: 1.05em;
    height: 1.05em;
    vertical-align: -0.15em;
    flex: none;
    background-color: var(--ds-brand-proxmox);
    -webkit-mask: var(--ds-glyph-proxmox) center / contain no-repeat;
    mask: var(--ds-glyph-proxmox) center / contain no-repeat;
}

/* ==========================================================================
   VERSTECKEN SCHLÄGT KOMPONENTEN-LAYOUT  (muss am Dateiende stehen)
   --------------------------------------------------------------------------
   tailwind.css wird VOR dieser Datei geladen. Bei gleicher Spezifität gewinnt
   die spätere Regel — also schlug `.ds-alert{display:flex}` das
   `.tw-hidden{display:none}` von Tailwind: ein per tw-hidden versteckter
   ds-Baustein blieb sichtbar und sein Umschalter tat scheinbar nichts
   (Bucket-Info im ToDo-Board, Lösch-Warnung im Seiten-Editor).

   `:not([class*=":tw-"])` nimmt Elemente mit responsiver Display-Variante aus
   (`tw-hidden sm:tw-inline` = auf schmal aus, ab sm sichtbar). Ohne die Ausnahme
   würde diese Regel die sm:/md:-Utilities schlagen und die Beschriftungen auf
   großen Schirmen verschwinden lassen. Aus demselben Grund KEIN !important —
   und damit Inline-Styles (el.style.display = …) weiterhin gewinnen.

   Die höhere Spezifität (0,2,0) schlägt einklassige Komponenten-Regeln auch aus
   später geladenen View-CSS-Dateien. Kontext-Selektoren (`.a .b{display:…}`)
   liegen darüber und brauchen weiterhin ihre eigene Regel.
   ========================================================================== */

.tw-hidden:not([class*=":tw-"]) { display: none; }
[hidden]:not([class*=":tw-"])   { display: none; }

/* ==========================================================================
   Markenhinweis im Fuß öffentlicher Seiten (~/Views/Shared/_PublicBrandFooter.cshtml)
   --------------------------------------------------------------------------
   Bewusst ohne eigene Farbe und Schriftgröße: der Hinweis steht in Fußzeilen mit
   sehr unterschiedlichem Skin (.bk-foot, .myhub-foot, .sg-foot, .arcshare-foot …)
   und soll deren Aussehen erben statt es zu überschreiben.

   .ds-public-foot ist der Ersatz-Fuß für die Layouts, die bisher gar keinen
   hatten (Meet-Gastseite, externer Chat, geteilte Kontaktliste).
   ========================================================================== */

/* Schild vor „Sicher bereitgestellt über" — als Maske statt Icon-Schrift, weil nicht jede
   Gastseite bootstrap-icons lädt. Farbe = Leitfarbe der Installation. */
.ds-brandnote      { display: inline-flex; align-items: center; gap: .4rem; white-space: nowrap; }
.ds-brandnote::before {
    content: '';
    flex: 0 0 auto;
    width: .95rem;
    height: .95rem;
    background: var(--ds-accent-1, var(--ds-primary, #3b82f6));
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 0c-.69 0-1.84.26-2.92.56-1.1.3-2.21.65-2.87.87a1.54 1.54 0 0 0-1.04 1.26c-.6 4.46.78 7.77 2.46 9.97a11.8 11.8 0 0 0 2.52 2.4c.35.25.67.44.94.57.24.12.51.21.77.21s.53-.09.77-.21c.27-.13.6-.32.94-.57a11.8 11.8 0 0 0 2.52-2.4c1.68-2.2 3.06-5.51 2.46-9.97a1.54 1.54 0 0 0-1.04-1.26c-.66-.22-1.77-.57-2.87-.87C9.84.26 8.69 0 8 0m2.85 5.85-3.5 3.5a.5.5 0 0 1-.7 0l-1.5-1.5a.5.5 0 1 1 .7-.7L7 8.29l3.15-3.15a.5.5 0 0 1 .7.7'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 0c-.69 0-1.84.26-2.92.56-1.1.3-2.21.65-2.87.87a1.54 1.54 0 0 0-1.04 1.26c-.6 4.46.78 7.77 2.46 9.97a11.8 11.8 0 0 0 2.52 2.4c.35.25.67.44.94.57.24.12.51.21.77.21s.53-.09.77-.21c.27-.13.6-.32.94-.57a11.8 11.8 0 0 0 2.52-2.4c1.68-2.2 3.06-5.51 2.46-9.97a1.54 1.54 0 0 0-1.04-1.26c-.66-.22-1.77-.57-2.87-.87C9.84.26 8.69 0 8 0m2.85 5.85-3.5 3.5a.5.5 0 0 1-.7 0l-1.5-1.5a.5.5 0 1 1 .7-.7L7 8.29l3.15-3.15a.5.5 0 0 1 .7.7'/%3E%3C/svg%3E") center / contain no-repeat;
}
.ds-brandnote a    { display: inline-flex; color: inherit; text-decoration: none; opacity: .92; transition: opacity .15s ease; }
.ds-brandnote a:hover { opacity: 1; }
/* Trenner hinter der Marke: feine Linie statt „·" (der Punkt bleibt im Markup für Textansichten) */
.ds-brandnote-sep  {
    display: inline-block;
    width: 1px;
    height: 1rem;
    background: currentColor;
    opacity: .28;
    font-size: 0;
    margin: 0 .2rem;
}

/* Hintergrund der öffentlichen Gastseiten — EINE Regel für alle (Portal, Buchung, Formular,
   Signatur, Arc-Freigabe, FAQ, Meet, externer Chat, geteilte Kontaktliste). Vorher trugen drei
   Seiten das Bild der Installation und der Rest stand auf grauer Fläche; für den Empfänger sah
   dasselbe Haus je nach Weg anders aus. Fester Layer statt body-background, damit er beim
   Scrollen steht; hell/dunkel folgt der Theme-Klasse, prefers-color-scheme ist der No-JS-Fall. */
.ds-public-bg::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    /* Eigenes Bild NUR für die Gastseiten: --ds-public-bg-image wird von
       Views/Shared/_PublicAccent.cshtml gesetzt, wenn publicbg.jpg hinterlegt ist.
       Ohne diese Datei bleibt es beim Bild der Installation — die App nutzt dasselbe
       Dateipaar, ein Austausch dort verändert also auch die Arbeitsoberfläche. */
    background-image: var(--ds-public-bg-image, url('/Media/BackgroundImages/lightbg.jpg'));
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center center;
}
html.dark .ds-public-bg::before { background-image: var(--ds-public-bg-image-dark, url('/Media/BackgroundImages/darkbg.jpg')); }
@media (prefers-color-scheme: dark) {
    html:not(.light) .ds-public-bg::before { background-image: var(--ds-public-bg-image-dark, url('/Media/BackgroundImages/darkbg.jpg')); }
}

/* Fuß-Plakette für öffentliche Seiten: Die Layouts stehen auf dem Hintergrundbild der
   Installation — je nach Bild war der Markenhinweis mal auf hellem, mal auf dunklem Grund und
   damit teils unlesbar. Ein eigener, halbtransparenter Grund macht ihn von jedem Bild unabhängig.
   `backdrop-filter` ist Zugabe; ohne Unterstützung trägt die Farbe allein. */
/* Abstand zum Inhalt: niedrige Spezifität — Layouts mit eigenem margin-top behalten ihren Wert. */
.ds-foot-plate { margin-top: 1.25rem; }
/* Aussehen: mit `body` davor, damit die alten Fuß-Klassen der Layouts (padding-top, border-top …)
   die Plakette nicht mehr von innen aufblähen oder zerschneiden. */
body .ds-foot-plate {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: .35rem .7rem;
    width: fit-content;
    max-width: calc(100% - 1.5rem);
    margin-left: auto;
    margin-right: auto;
    padding: .45rem 1.15rem;
    border: 1px solid color-mix(in srgb, #fff 55%, transparent);
    border-radius: 999px;
    background: color-mix(in srgb, var(--ds-card, #fff) 74%, transparent);
    backdrop-filter: blur(14px) saturate(1.4);
    -webkit-backdrop-filter: blur(14px) saturate(1.4);
    box-shadow: 0 8px 24px rgba(15, 23, 42, .08), 0 1px 2px rgba(15, 23, 42, .06);
    color: var(--ds-muted-foreground, #6b7280);
    font-size: .78rem;
    line-height: 1.3;
    text-align: center;
}
html.dark body .ds-foot-plate {
    border-color: rgba(255, 255, 255, .08);
    background: color-mix(in srgb, var(--ds-card, #1c1c21) 70%, transparent);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
}
/* Impressum/Datenschutz: ohne Unterstrich, etwas kräftiger als der Hinweistext */
body .ds-foot-plate > a {
    color: var(--ds-foreground);
    font-weight: 500;
    text-decoration: none;
    opacity: .8;
    transition: opacity .15s ease, color .15s ease;
}
body .ds-foot-plate > a:hover { opacity: 1; color: var(--ds-primary, #3b82f6); }

/* Markenzeichen im Fuß. Das Logo ist ein Wort-Bild-Zeichen MIT Claim — unter etwa 1,4rem wird
   die zweite Zeile unleserlich. Es steht deshalb allein, ohne den Markennamen daneben zu
   wiederholen; der Name bleibt als Alt-Text für den Fall, dass das Bild nicht lädt. */
.ds-brandmark { height: 1.5rem; width: auto; vertical-align: -.45rem; display: block; }
/* Das Logo ist dunkelgrau mit blauem „HUB" — auf dunkler Plakette kaum zu sehen. Umkehren +
   Farbton zurückdrehen macht das Grau hell und lässt das Blau blau. */
html.dark .ds-brandmark { filter: invert(1) hue-rotate(180deg) brightness(1.15); }

.ds-public-foot {
    margin-top: 1.5rem; padding: 0 1rem 1.25rem;
    text-align: center; font-size: .78rem;
    color: var(--ds-muted-foreground, #9ca3af);
    display: flex; align-items: center; justify-content: center;
    gap: .4rem; flex-wrap: wrap;
}
.ds-public-foot a { color: inherit; }

/* ── Abgewählter Bereich der Kontaktakte (12.09.2026) ───────────────────────────────────────────
   Gehört allein der Bereichs-Einstellung (ContactSectionLayout.Cls). BEWUSST nicht Bootstraps
   `d-none`: Mehrere Kacheln schalten sich per classList.remove("d-none") selbst sichtbar, sobald
   ihre Daten ankommen — eine abgewählte Kachel käme damit wieder ins Bild. */
.ds-section-aus {
    display: none !important;
}

/* Autofill-Schutz (js/shared/autofill-schutz.js): Geheimfelder sind type="text" + data-af-geheim, damit
   Chrome/Edge dort nicht ihren Passwortmanager anbieten — maskiert wird hier, auch ohne das Skript. */
input[data-af-geheim]:not(.af-offen) { -webkit-text-security: disc; }
input[data-af-suche]::-webkit-search-cancel-button,
input[data-af-suche]::-webkit-search-decoration { -webkit-appearance: none; display: none; }

/* ============================================================================
   GERÄTEKLASSEN (Plan 63) — EIN Layout für alle Handys, iPhones und Foldables.
   Breite: Kompakt < 576 · Mittel 576–991.98 · Breit ≥ 992 (die vorhandenen Breakpoints).
   Höhe:   Niedrig ≤ 640 px im Querformat — jedes Handy quer, Fold innen quer (Fold 7: 601).
   Im Niedrig-Modus frisst der Rahmen sonst zwei Drittel der Höhe (Toolbar ~60, Dock 96,
   Browserleisten). Darum hier zentral verdichten — Module erben es, ohne etwas zu tun.
   JS-Gegenstück + Dock-Ausblenden beim Scrollen: js/shared/ds-geraeteklasse.js.
   ============================================================================ */
/* Touch-Fläche (Plan 74, C11): Knöpfe im Fuß eines Fensters sind am Handy der Daumen-Weg — Speichern,
   Abbrechen. 34 px (ds-btn) treffen sich schlecht; Ziel ≥ 44 px. Nur Kompakt + grober Zeiger, damit
   Desktop und Maus unverändert bleiben. */
:root { --ds-touch-ziel: 2.75rem; }
@media (max-width: 575.98px) and (pointer: coarse) {
    .modal-footer .ds-btn:not(.ds-btn-sm):not(.ds-btn-link) { height: var(--ds-touch-ziel); min-height: var(--ds-touch-ziel); }
}
#MenuWrapper { transition: transform .25s ease, opacity .25s ease; }
html.ds-dock-weg #MenuWrapper {
    transform: translateY(calc(100% + 24px + env(safe-area-inset-bottom, 0px)));
    opacity: 0;
    pointer-events: none;
}
/* Tastatur offen im Querformat (html.ds-tastatur, ds-geraeteklasse.js): es bleiben ~100–120 px —
   Werkzeugleiste und Dock weg, damit das Eingabefeld sichtbar bleibt. */
@media (max-height: 640px) and (orientation: landscape) {
    html.ds-tastatur .ds-toolbar { display: none !important; }
    html.ds-tastatur #MenuWrapper { opacity: 0; pointer-events: none; }
    html.ds-tastatur #MenuWrapper > * { pointer-events: none; }
}
@media (max-height: 640px) and (orientation: landscape) {
    /* Dock fährt beim Runterscrollen weg (ds-geraeteklasse.js) → kaum Reserve nötig. */
    :root { --app-dock-reserve: calc(8px + env(safe-area-inset-bottom, 0px)); --ds-shell-reserve: 72px; }
    .ds-main .ds-content { padding-top: .5rem; }
    /* Die festen 90 px Dock-Abstand unter main entfallen mit dem ausblendenden Dock — sonst scrollt
       die Seite bei Modulen mit gedeckelter Höhe zusätzlich um genau diese 90 px. */
    html.ds-page main { padding-bottom: var(--app-dock-reserve); }
    /* iPhone quer: Notch/Kamera links oder rechts. */
    .ds-main .ds-content {
        padding-left: max(var(--ds-content-pad-x), env(safe-area-inset-left, 0px));
        padding-right: max(var(--ds-content-pad-x), env(safe-area-inset-right, 0px));
    }
    .ds-toolbar { margin-top: 0 !important; margin-bottom: .35rem !important; }
    /* Kachel: Icon NEBEN statt über dem Label — Label bleibt (Regel „nie nur Icons"). */
    .ds-toolbar-row [class*="tw-min-w-[70px]"] {
        flex-direction: row !important;
        min-width: 0 !important;
        padding: .3rem .6rem !important;
        gap: .35rem !important;
    }
    .ds-toolbar-row [class*="tw-min-w-[70px]"] > span { font-size: .75rem; white-space: nowrap; }
    .ds-toolbar-row [class*="tw-min-w-[70px]"] > i { font-size: 1rem; }
    .ds-shell { margin-top: .25rem; margin-bottom: .5rem; }
}

/* Kopfzeile mit Titel + Knöpfen (Karten, Bereichs-Cards, Spalten) — Baustein für ALLE Module:
   - Titel `.ds-head-title`: bricht notfalls zweizeilig um, wird aber nie schmaler als sein längstes Wort.
   - Knopfzeile `[data-ds-overflow]`: EINE Zeile; was nicht passt, wandert in ein „⋮"-Menü
     (js/components/base/ds-chip-overflow.js). `data-ds-overflow-last` = weicht zuletzt (Einklappen),
     `data-ds-overflow-menu` = steht immer im Menü. */
.ds-head-title { flex: 0 1 auto; min-width: min-content !important; white-space: normal; line-height: 1.2; }
[data-ds-overflow] { display: flex; align-items: center; flex-wrap: nowrap; overflow: hidden; min-width: 0; flex-shrink: 1; max-width: 100%; }
[data-ds-overflow] > * { flex-shrink: 0; }
.ds-overflow-weg { display: none !important; }

/* Scroll-Pfeile (js/components/base/ds-scroll-pfeile.js) — statt Scrollbalken: ▼ unten, solange noch Inhalt
   folgt, ▲ oben nach dem Scrollen. Klein, beim Darüberfahren deutlich (Max, 03.11.2026); Kontrast
   angehoben (Max, 04.11.2026: war zu blass). Seit 07.11.2026 app-weit automatisch — das JS setzt
   data-ds-scroll-pfeile an jeden Scroller, den es übernimmt (auch an <html>, wenn die Seite scrollt).
   Scrollt ein Bereich auch waagrecht (data-ds-scroll-quer), bleibt sein Balken. !important: einzelne
   Module setzen scrollbar-width: thin mit höherer Spezifität. */
[data-ds-scroll-pfeile]:not([data-ds-scroll-quer]) { scrollbar-width: none !important; }
[data-ds-scroll-pfeile]:not([data-ds-scroll-quer])::-webkit-scrollbar { display: none; }
.ds-scroll-pfeil.ds-scroll-pfeil-fest { position: fixed; z-index: 40; }
@media print { .ds-scroll-pfeil { display: none !important; } }
.ds-scroll-pfeil {
    position: absolute; left: 50%; z-index: 3; transform: translateX(-50%);
    width: 1.75rem; height: 1.35rem; padding: 0; border-radius: 999px;
    display: grid; place-items: center;
    border: 1px solid color-mix(in srgb, var(--ds-foreground) 24%, transparent);
    background: color-mix(in srgb, var(--ds-card) 94%, transparent);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    box-shadow: 0 2px 10px rgba(0, 0, 0, .16);
    color: color-mix(in srgb, var(--ds-foreground) 70%, var(--ds-muted-foreground));
    opacity: .95; cursor: pointer;
    transition: opacity .15s ease, color .15s ease, border-color .15s ease;
}
.ds-scroll-pfeil[hidden] { display: none; }
.ds-scroll-pfeil i { font-size: .8rem; line-height: 1; }
.ds-scroll-pfeil:hover { opacity: 1; color: var(--ds-accent-1); border-color: var(--ds-accent-1); }
.ds-scroll-pfeil:focus-visible { opacity: 1; outline: 2px solid var(--ds-ring); outline-offset: 1px; }

/* ---- Pegelanzeige beim Diktat (js/shared/diktat-mikrofon.js) --------------------------------------------
   Roter Aufnahmepunkt + Balken, die live zur Stimme springen (Mitte = tiefe Töne, außen = hohe). Zeigt dem
   Anwender, dass das Mikrofon wirklich Ton liefert — bei Stille bleiben die Balken flach (Max, 28.10.2026). */
.ds-pegel {
    display: inline-flex; align-items: center; gap: .65rem; align-self: flex-start;
    padding: .45rem .9rem; border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--ds-primary) 30%, var(--ds-border));
    background: color-mix(in srgb, var(--ds-primary) 7%, var(--ds-card));
}
.ds-pegel-punkt {
    flex: 0 0 auto; width: .6rem; height: .6rem; border-radius: 50%;
    background: var(--ds-destructive); animation: ds-pegel-puls 1.2s ease-in-out infinite;
}
.ds-pegel-balken { display: flex; align-items: center; gap: 3px; height: 1.75rem; }
.ds-pegel-balken > i {
    display: block; width: 4px; height: 100%; border-radius: 2px;
    background: linear-gradient(180deg, color-mix(in srgb, var(--ds-primary) 55%, var(--ds-card)), var(--ds-primary) 50%,
                color-mix(in srgb, var(--ds-primary) 55%, var(--ds-card)));
    transform: scaleY(.12); transition: transform 70ms linear; will-change: transform;
}
@keyframes ds-pegel-puls { 50% { opacity: .3; } }

/* ==========================================================================
   ds-pdfansicht — schlanker PDF-Betrachter mit einheitlichem Zoom (js/shared/pdf-ansicht.js,
   plans/78 §3): Freigabe-Link, Portal, erzeugte PDFs. Der Host gibt die Höhe vor.
   ========================================================================== */
.ds-pdfansicht { position: relative; overflow: hidden; background: var(--ds-muted, #eef0f3); }
.ds-pdfansicht-scroll { position: absolute; inset: 0; overflow: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
.ds-pdfansicht-pages {
    display: flex; flex-direction: column; align-items: center;
    gap: 12px; padding: 12px; min-width: min-content; transform-origin: 0 0;
}
/* Seiten und Zoom-Leiste wie im Datei-Betrachter (file-viewer.css .fv-pdfdoc-page / .fv-zoom-status):
   Seiten mit Schatten auf grauer Fläche, Leiste „− 100 % +“ unten mittig. */
.ds-pdfansicht-page { flex: 0 0 auto; background: #fff; border-radius: .5rem; overflow: hidden; box-shadow: 0 4px 18px rgba(0, 0, 0, .22); }
.ds-pdfansicht-page canvas { display: block; }
.ds-pdfansicht-ctrls {
    position: absolute; left: 50%; transform: translateX(-50%); bottom: .6rem; z-index: 2;
    display: flex; align-items: center; gap: .15rem; padding: .2rem .35rem;
    background: var(--ds-card, #fff); border-radius: 1rem; box-shadow: 0 2px 10px rgba(0, 0, 0, .12);
}
.ds-pdfansicht-ctrls button {
    height: 1.8rem; min-width: 1.8rem; padding: 0 .35rem; border: 0; border-radius: .7rem;
    background: transparent; color: var(--ds-foreground); cursor: pointer; font-size: .85rem;
}
.ds-pdfansicht-ctrls button:hover,
.ds-pdfansicht-zoom:hover { background: var(--ds-accent, var(--ds-muted, #f1f1f4)); }
.ds-pdfansicht-zoom {
    min-width: 3rem; padding: .3rem .2rem; border-radius: .7rem; cursor: pointer; user-select: none;
    text-align: center; font-size: .8rem; font-variant-numeric: tabular-nums; color: var(--ds-foreground);
}
.ds-pdfansicht-seite {
    position: absolute; left: .75rem; bottom: .75rem; z-index: 2; pointer-events: none;
    padding: .3rem .7rem; border-radius: 999px; font-size: .78rem; font-weight: 600;
    font-variant-numeric: tabular-nums; color: #fff; background: rgba(0, 0, 0, .55);
}
.ds-pdfansicht .ds-pdfansicht-seite { color: #fff; }   /* schlägt .ds-modal-scope div im Modal */
.ds-pdfansicht-fehler {
    height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .5rem; color: var(--ds-muted-foreground); text-align: center; padding: 1rem;
}
.ds-pdfansicht-fehler > i { font-size: 2.5rem; }
.ds-pdfansicht-overlay {
    position: fixed; inset: 0; z-index: 2100; display: flex; flex-direction: column;
    background: var(--ds-background);
}
/* Kopf = Kopf des Datei-Betrachters (file-viewer.css .fv-kopfwz/.fv-kw): Titel | Knöpfe mittig | X */
.ds-pdfansicht-kopf {
    display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; column-gap: .75rem;
    min-height: 3.25rem; padding: .4rem .75rem .4rem 1rem; padding-top: max(.4rem, env(safe-area-inset-top));
    background: var(--ds-card); box-shadow: 0 1px 6px rgba(0, 0, 0, .08); position: relative; z-index: 3;
}
.ds-pdfansicht-titelzeile { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.ds-pdfansicht-titelzeile > i { color: var(--ds-primary); font-size: 1.1rem; }
.ds-pdfansicht-titel { min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-pdfansicht-kw { display: flex; align-items: center; gap: .15rem; }
.ds-pdfansicht-k {
    display: inline-flex; align-items: center; justify-content: center; gap: .15rem;
    height: 2.5rem; min-width: 2.5rem; padding: 0 .55rem; border: 0; border-radius: .7rem;
    background: transparent; color: var(--ds-foreground); font-size: 1.1rem; cursor: pointer; text-decoration: none;
}
.ds-pdfansicht-k:hover { background: var(--ds-accent, var(--ds-muted)); }
.ds-pdfansicht-k:disabled { opacity: .45; cursor: not-allowed; background: transparent; }
.ds-pdfansicht-k > span { display: none; }
/* Zoom im Kopf = Zoom-Pille des Datei-Betrachters (.fv-kw-zpill): ein Element „− 100 % +“ */
.ds-pdfansicht-ctrls.is-kopf {
    position: static; transform: none; box-shadow: none; gap: 0; margin: 0 .15rem;
    height: 2.1rem; padding: 0 .15rem; border-radius: .7rem; background: color-mix(in srgb, var(--ds-foreground) 6%, transparent);
}
.ds-pdfansicht-ctrls.is-kopf button, .ds-pdfansicht-ctrls.is-kopf .ds-pdfansicht-zoom {
    display: inline-flex; align-items: center; justify-content: center; height: 1.8rem; min-width: 1.8rem; padding: 0 .3rem;
    border: 0; border-radius: .55rem; background: transparent; color: var(--ds-foreground); font-size: 1.05rem;
}
.ds-pdfansicht-ctrls.is-kopf .ds-pdfansicht-zoom { min-width: 3.4rem; font-size: .8rem; font-weight: 600; }
.ds-pdfansicht-ctrls.is-kopf button:hover, .ds-pdfansicht-ctrls.is-kopf .ds-pdfansicht-zoom:hover { background: var(--ds-card); box-shadow: 0 1px 3px rgba(0, 0, 0, .12); }
.ds-pdfansicht-x { justify-self: end; }
@media (min-width: 481px) {
    .ds-pdfansicht-k:not(.ds-pdfansicht-x) { flex-direction: column; height: 3.2rem; min-width: 3.4rem; padding: 0 .35rem; }
    .ds-pdfansicht-k:not(.ds-pdfansicht-x) > i { display: flex; align-items: center; height: 1.75rem; }
    .ds-pdfansicht-k:not(.ds-pdfansicht-x) > span { display: block; font-size: .68rem; font-weight: 500; line-height: 1; white-space: nowrap; opacity: .85; }
}
@media (max-width: 640px) { .ds-pdfansicht-ctrls.is-kopf { display: none; } }
.ds-pdfansicht-body { flex: 1; min-height: 0; }
/* Bild in der Überlagerung (DsBildAnsicht) = Bild im Datei-Betrachter (.fv-zoom-board) */
.ds-bild-scroll { display: flex; user-select: none; -webkit-user-select: none; }
.ds-bild-board {
    position: relative; flex: none; margin: auto; overflow: hidden; border-radius: .2rem;
    box-shadow: 0 2px 14px rgba(0, 0, 0, .18);
    background: repeating-conic-gradient(#e7e7ea 0% 25%, #fff 0% 50%) 0 0 / 20px 20px;
}
html.dark .ds-bild-board { background: repeating-conic-gradient(#2a2d33 0% 25%, #1f2227 0% 50%) 0 0 / 20px 20px; }
.ds-bild-img { display: block; width: 100%; height: 100%; -webkit-user-drag: none; }
.ds-pdfansicht.is-gezoomt .ds-bild-scroll { cursor: grab; }

/* ── Gruppentrenner in Listen (ToDo-Spalten, E-Mail, MyKI-Chats) ─────────────────────────────────
   Linie · farbige Beschriftung · Linie, kompakt: 12 px über der Beschriftung, 4 px zur eigenen Gruppe.
   Gemessen für Listen, deren Zeilen keinen eigenen Außenabstand haben — Listen mit Kartenabstand gleichen
   das im Modul-CSS aus (ToDo, MyKI). Farbe inline am <span> (style="color:…"), weil .ds-main span sonst
   --ds-foreground erzwingt. Farben: Neu = success · Fällig = destructive · Heute = warning · sonst info.
   --small/--dotted für die ferneren Zeiträume (Diese Woche … Jahre). */
.ds-group-divider,
.ds-group-subdivider {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .75rem .75rem .25rem;
    line-height: 1rem;
    white-space: nowrap;
}
.ds-group-divider::before, .ds-group-divider::after,
.ds-group-subdivider::before, .ds-group-subdivider::after {
    content: "";
    flex: 1;
    border-top: 1px solid var(--ds-border);
}
.ds-group-divider { font-size: .75rem; font-weight: 700; }
.ds-group-divider i { margin-right: .25rem; }
.ds-group-divider--small { padding-inline: 1.25rem; }
.ds-group-divider--dotted::before, .ds-group-divider--dotted::after { border-top-style: dotted; }
.ds-group-subdivider { padding-inline: 1.25rem; font-size: .72rem; color: var(--ds-muted-foreground); }
.ds-group-subdivider::before, .ds-group-subdivider::after { border-top-style: dashed; }

/* Mail lesen ohne Seitenwechsel (js/shared/mail-lesen.js — Home, ToDo): Leseansicht des Mail-Moduls als
   Vollbild-Ebene über allem, auch über offenen Dialogen (z-index setzt das Skript: über dem obersten). */
.ds-mail-lesen { position: fixed; inset: 0; background: var(--ds-background); }
.ds-mail-lesen iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.ds-mail-lesen-laden { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--ds-muted-foreground); }
html.ds-mail-lesen-offen, html.ds-mail-lesen-offen body { overflow: hidden; }
