/* ============================================
   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 {
    font-size: 16px;
    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);
}

html.ds-page .container-buttons:hover > :not(:hover) {
    opacity: 0.5;
}

/* ---------- 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) */
    --ds-tile-h-standard: 11rem;                    /* 176px */
    --ds-tile-h-compact: 4.75rem;                   /* 76px — wie eine Kontakt-Karte */
    --ds-tile-h-preview: 7.5rem;                    /* 120px */
    /* 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;
    --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;
}

/* 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;
    }
}

/* ---------- 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). */
.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-"]), .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-"]), 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. */
.ds-main a:not([class*="ds-btn"]):not([class*="ds-chip"]) { color: var(--ds-accent-1); text-decoration: none; }
.ds-main a:not([class*="ds-btn"]):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; padding: 0; }
.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: 0 2px 8px rgba(0, 0, 0, 0.04);
    margin-top: 0;
}

@media (prefers-color-scheme: dark) {
    html:not(.light) .ds-main .ds-content {
        background: var(--ds-surface);
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.04);
    }
}

html.dark .ds-main .ds-content {
    background: var(--ds-surface);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.04);
}

/* ---------- 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: 0 2px 8px rgba(0, 0, 0, 0.04);
    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: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.04); }
}
html.dark .ds-surface { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.04); }

/* 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;
}

/* 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-index-shell); 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.
   ============================================================================ */
html.ds-page:has(.ds-shell),
html.ds-page:has(.ds-shell) body {
    overflow: hidden;
}
.ds-shell {
    display: flex;
    flex-direction: column;
    /* Toolbar + Nav abziehen → gescrollt wird innen. dvh mit vh als Vorzeile (Android/DeX). */
    max-height: calc(100vh - var(--ds-shell-reserve, 185px));
    max-height: calc(100dvh - var(--ds-shell-reserve, 185px));
    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: 0 2px 8px rgba(0, 0, 0, 0.04);
}
@media (prefers-color-scheme: dark) {
    html:not(.light) .ds-shell { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.04); }
}
html.dark .ds-shell { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.04); }

.ds-shell-head {
    flex-shrink: 0;
    background: 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%);
    /* Maße wie das Vorbild Formulare/Flow/Booking (Max 25.09.2026: Kopf war höher als dort);
       unten mehr: der Body legt sich mit der Rundung darüber */
    padding: .5rem 1.2rem 1.25rem;
}
.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; }
.ds-shell-icon {
    width: 2.1rem; height: 2.1rem; border-radius: .7rem; flex-shrink: 0;
    display: grid; place-items: center; font-size: 1.2rem;
}
.ds-shell-lead-text { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.ds-shell-title { font-size: 1rem; font-weight: 700; 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; }

.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; }
.ds-shell-metric-value { font-size: 1.18rem; font-weight: 800; color: var(--ds-foreground); font-variant-numeric: tabular-nums; }
.ds-shell-metric-label { font-size: .72rem; 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; }

/* 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-type: inline-size; }
.ds-shell-search { flex: 1 1 16rem; min-width: 12rem; max-width: 26rem; margin-inline: auto; }
/* Suchfeld so hoch wie die Symbole der Kennzahlen — sonst macht es die Kopfzeile höher */
.ds-shell-search .form-control { height: 2.1rem; min-height: 0; padding-top: .2rem; padding-bottom: .2rem; font-size: .85rem; }
@container (max-width: 1100px) { .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; }
    .ds-shell-body { overflow-y: visible; }
    .ds-shell-metrics { gap: 1rem; margin-left: 0; }
    .ds-shell-metric-value { font-size: 1.05rem; }
}

/* 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-item:hover,
html.ds-page .dropdown-item:focus {
    background-color: color-mix(in srgb, var(--ds-card-foreground) 8%, transparent);
    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 {
    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 {
    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));
        overflow-y: auto;
        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: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.04);
    }
}

/* 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);
    }
}

.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(.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(.alert *):not(.modal *) {
    color: var(--ds-foreground);
}

@media (max-width: 991.98px) {
    .settings-shell { flex-direction: column; padding: 0; gap: 0; }
    .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;
}
/* 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;
}
.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 accent-1, Active accent-2), 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:hover,
html.ds-page .settings-content .ds-card .dropdown-item:focus {
    background: color-mix(in srgb, var(--ds-accent-1) 15%, transparent);
    color: var(--ds-accent-1);
}
html.ds-page .settings-content .ds-card .dropdown-item.active,
html.ds-page .settings-content .ds-card .dropdown-item:active {
    background: color-mix(in srgb, var(--ds-accent-2) 18%, transparent);
    color: var(--ds-accent-2);
}
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;
}

/* Dropdown Items — Hover = Accent-1, Active = Accent-2 */
.ds-dropdown-item:hover {
    background: color-mix(in srgb, var(--ds-accent-1) 15%, transparent);
    color: var(--ds-accent-1);
}

/* Tastatur-Markierung (ds-select): optisch identisch zum Hover, damit
   Pfeiltasten-Navigation und Maus-Hover denselben Zustand zeigen. */
.ds-dropdown-item.is-active {
    background: color-mix(in srgb, var(--ds-accent-1) 15%, transparent);
    color: var(--ds-accent-1);
}

.ds-dropdown-item:active,
.ds-dropdown-item.active {
    background: color-mix(in srgb, var(--ds-accent-2) 18%, transparent);
    color: var(--ds-accent-2);
    font-weight: 500;
}

/* 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; }

.ds-row-menu-list {
    min-width: 11rem;
    margin-top: 0.35rem;
    padding: 0.25rem;
    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: 0 1px;
    padding: 0.375rem 0.6rem;
    font-size: 0.875rem;
    line-height: 1.2;
    border-radius: 0.4rem;
    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);
}

.ds-row-menu-divider {
    height: 1px;
    margin: 0.25rem 0;
    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;
}

#toolbarContent {
    padding: 0.5rem 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;
}

.ds-editor-btn:hover { background: var(--ds-accent); }
.ds-editor-btn.active { background: var(--ds-accent); color: 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: 12px;
    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;
}
.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; }
/* 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-item:hover, .dropdown-item:focus {
    background-color: color-mix(in srgb, var(--ds-accent-1) 15%, transparent);
    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; }
/* 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: 10px;
    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; }

.ds-copy-btn {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    background: var(--ds-accent);
    border: 1px solid var(--ds-border);
    color: var(--ds-muted-foreground);
    padding: 0.25rem 0.625rem;
    border-radius: calc(var(--ds-radius) * 0.8);
    font-size: 0.6875rem;
    font-family: inherit;
    cursor: pointer;
}

.ds-copy-btn:hover {
    background: var(--ds-muted);
    color: var(--ds-foreground);
}

/* ============================================
   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). */
:root { --app-dock-reserve: calc(96px + env(safe-area-inset-bottom, 0px)); }

#MenuWrapper {
    position: fixed !important;
    bottom: calc(20px + env(safe-area-inset-bottom, 0px)) !important;
    left: 0 !important;
    right: 0 !important;
    z-index: 1030 !important;
}

#Dock:hover > :not(:hover) { opacity: 0.5; }
.container-buttons:hover > :not(:hover) { opacity: 0.5; }

.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);
}

#MenuWrapper .dock-btn {
    transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

#MenuWrapper .dock-btn:hover {
    transform: translateY(-5px) scale(1.1);
}

#MenuWrapper .dock-btn:hover ~ .dock-btn { transform: scale(1.05); }
#MenuWrapper .dock-btn:hover + .dock-btn { transform: scale(1.08); }

@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;
}

/* Dock-Skeleton: reserviert die Dock-Fläche unten-mittig, bis das echte Dock (AJAX) da ist.
   Wird im Load-Callback per #dockSkeleton.remove() entfernt. Reiner Platzhalter mit Glimmen,
   damit unten kein leeres Loch klafft und das Dock nicht aus dem Nichts "reinspringt". */
#dockSkeleton {
    position: fixed;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1029;
    pointer-events: none;
}
#dockSkeleton .ds-dock-skeleton-bar {
    width: min(420px, 80vw);
    height: 64px;
    border-radius: 1rem;
    background: linear-gradient(100deg, rgba(255,255,255,0.08) 30%, rgba(255,255,255,0.18) 50%, rgba(255,255,255,0.08) 70%);
    background-size: 200% 100%;
    animation: dsDockSkeleton 1.2s ease-in-out infinite;
    -webkit-backdrop-filter: blur(20px);
    backdrop-filter: blur(20px);
    border: 1px solid rgba(255, 255, 255, 0.12);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.10);
}
@keyframes dsDockSkeleton {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* 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 {
    overflow: hidden;
    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) !important;
}

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) 14%, transparent);
}

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

html.dark.ds-page #Dock {
    background: rgba(30, 30, 30, 0.85);
    border: 1px solid var(--ds-accent-1);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 12px color-mix(in srgb, var(--ds-accent-1) 20%, transparent);
}

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 var(--ds-accent-1);
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 12px color-mix(in srgb, var(--ds-accent-1) 20%, transparent);
    }

    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                                                         */
/* ============================================================ */
/* z-index über den gesamten Modal-Stack: CRM-Modals liegen bei 2000 (crm-modals.css),
   gestapelte Sub-Modals bei 2020+ (modal-stack.js), der Arc-Picker bei 20000. Toasts
   sind die oberste Ebene und müssen darüber liegen — sonst verschwindet z.B. der
   Bild-Upload-Fehler im Kontakt-Modal hinter dem Modal. */
.ds-toast-container { position:fixed; top:1rem; right:1rem; z-index:20050; display:flex; flex-direction:column; gap:.5rem; pointer-events:none; max-width:calc(100vw - 2rem); }
.ds-toast { pointer-events:auto; display:flex; gap:.625rem; padding:.75rem .875rem; border:1px solid var(--ds-border); border-radius:.5rem; background:var(--ds-card); box-shadow:0 4px 12px color-mix(in srgb, black 15%, transparent), 0 1px 3px color-mix(in srgb, black 10%, transparent); min-width:260px; max-width:380px; align-items:flex-start; animation:ds-toast-in .25s ease-out; }
.ds-toast-icon { flex-shrink:0; font-size:1.125rem; line-height:1; margin-top:.125rem; }
.ds-toast-body { flex:1; min-width:0; }
.ds-toast-title { font-weight:600; font-size:.8125rem; margin-bottom:.125rem; color:var(--ds-foreground); }
.ds-toast-text { font-size:.75rem; color:var(--ds-muted-foreground); line-height:1.4; word-wrap:break-word; }
.ds-toast-close { background:transparent; border:0; color:var(--ds-muted-foreground); cursor:pointer; padding:.125rem .375rem; border-radius:.25rem; margin:-.125rem -.25rem -.125rem 0; font-size:.95rem; line-height:1; }
.ds-toast-close:hover { background:var(--ds-muted); color:var(--ds-foreground); }
.ds-toast-info    { border-left:3px solid var(--ds-info); }
.ds-toast-info    .ds-toast-icon { color:var(--ds-info); }
.ds-toast-success { border-left:3px solid var(--ds-success); }
.ds-toast-success .ds-toast-icon { color:var(--ds-success); }
.ds-toast-warning { border-left:3px solid var(--ds-warning); }
.ds-toast-warning .ds-toast-icon { color:var(--ds-warning); }
.ds-toast-destr   { border-left:3px solid var(--ds-destructive); }
.ds-toast-destr   .ds-toast-icon { color:var(--ds-destructive); }
.ds-toast-leave { animation:ds-toast-out .2s ease-in forwards; }
@keyframes ds-toast-in  { from { opacity:0; transform:translateX(16px); } to { opacity:1; transform:translateX(0); } }
@keyframes ds-toast-out { from { opacity:1; transform:translateX(0); } to   { opacity:0; transform:translateX(16px); } }

/* ============================================================
   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; }
}

/* ============================================================================
   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.
   2. < 768px: kompakte Kacheln (weniger Innenabstand).
   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; }
/* 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;
}
.ds-toolbar-more-item:hover,
.ds-toolbar-more-item:focus-visible { background: var(--ds-accent); outline: none; }
.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);
}
.ds-selbar-dropdown .dropdown-item:hover,
.ds-selbar-dropdown .dropdown-item:focus {
    background: color-mix(in srgb, var(--ds-foreground) 8%, transparent);
    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 (Bootstrap-Icons mit Suche) — shared, _DsIconPicker.cshtml ===== */
.ds-iconpicker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(2.75rem, 1fr));
    gap: 0.35rem;
    max-height: 220px;
    overflow-y: auto;
    padding: 0.5rem;
    border: 1px solid var(--ds-border, var(--bs-border-color));
    border-radius: 0.5rem;
}
.ds-iconpicker-item {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1 / 1;
    font-size: 1.2rem;
    border-radius: 0.5rem;
    cursor: pointer;
    color: var(--ds-body, var(--bs-body-color));
    transition: background 0.15s ease, transform 0.15s ease;
}
.ds-iconpicker-item:hover {
    background: var(--ds-surface-hover, var(--bs-tertiary-bg));
    transform: scale(1.08);
}
.ds-iconpicker-item.selected {
    background: var(--ds-primary, var(--bs-primary));
    color: #fff;
}
.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; }
}

/* ==========================================================================
   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.
   ============================================================================ */
#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; }
}
@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). */
.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; }
