/* ==========================================================================
   S3.DocCenter – Theme & Base Styles
   Based on S3.NorthDataAutoExporter design system
   ========================================================================== */

/* ---------- CSS Custom Properties ---------- */

:root {
    --font-size: 16px;
    --background: #fafafa;
    --foreground: #1f1f1f;
    --card: #ffffff;
    --card-foreground: #1f1f1f;
    --popover: #ffffff;
    --popover-foreground: #1f1f1f;
    --primary: #0C5DA6;
    --primary-foreground: #ffffff;
    --secondary: #f5f5f5;
    --secondary-foreground: #1f1f1f;
    --muted: #f0f0f0;
    --muted-foreground: #6b6b6b;
    --accent: #e6f7ff;
    --accent-foreground: #0C5DA6;
    /* #c62828 statt des früheren #ff4444: Weiß auf #ff4444 ergibt 3,41:1 und
       verfehlt WCAG AA (4,5:1). Das Icon in .action-btn-danger:hover lag mit
       2,79:1 sogar unter der 3:1-Grenze für Bedienelemente. #c62828 erreicht
       5,62:1 bzw. 4,60:1. Siehe STANDARDS.md, Abschnitt Farben. */
    --destructive: #c62828;
    --destructive-foreground: #ffffff;
    --border: #e8e8e8;
    --input: transparent;
    --input-background: #ffffff;
    --font-weight-medium: 500;
    --font-weight-normal: 400;
    --ring: #0C5DA6;
    --radius: 0;
    --sidebar: #333333;
    --sidebar-foreground: #e8e8e8;
    --sidebar-primary: #0C5DA6;
    --sidebar-primary-foreground: #ffffff;
    --sidebar-accent: #3a3a3a;
    --sidebar-accent-foreground: #ffffff;
    --sidebar-border: #444444;
    --sidebar-ring: #0C5DA6;
    --sidebar-submenu: #2b2b2b;
}

/* ---------- Base styles ---------- */

*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html, body {
    height: 100vh;
}

/* PDF.js erstellt versteckte Off-Screen-Canvases als Body-Children.
   Diese Canvases haben height:0 aber position im Dokument, was scrollHeight erhöht. */
body > canvas {
    position: fixed;
    top: 0;
    left: 0;
    pointer-events: none;
}

html {
    font-size: var(--font-size);
}

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: 1rem;
    font-weight: var(--font-weight-normal);
    line-height: 1.5;
    color: var(--foreground);
    background-color: var(--background);
}

h1 {
    font-size: 1.5rem;
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
    border: none;
    outline: none;
}

h2 {
    font-size: 1.25rem;
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
}

h3 {
    font-size: 1.125rem;
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
}

h4 {
    font-size: 1rem;
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
}

label {
    font-size: 1rem;
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
}

button {
    font-size: 1rem;
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
    cursor: pointer;
}

input {
    font-size: 1rem;
    font-weight: var(--font-weight-normal);
    line-height: 1.5;
}

a {
    color: var(--primary);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

/* ---------- Shadow utilities ---------- */

.shadow-header {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.shadow-sidebar {
    box-shadow: 2px 0 8px rgba(0, 0, 0, 0.12);
}

.shadow-actionbar {
    box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.06);
}

.shadow-card {
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.10);
}

.shadow-button {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.shadow-dropdown {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

/* ---------- Layout ---------- */

.layout {
    display: flex;
    flex: 1;
    overflow: hidden;
}

.sidebar {
    background-color: var(--sidebar);
    color: var(--sidebar-foreground);
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
}

.sidebar-animating {
    transition: width 0.2s ease;
}

.sidebar-collapsed {
    width: 64px;
}

.header {
    height: 68px;
    background-color: var(--card);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    padding: 0 1.5rem;
    gap: 1rem;
}

.action-bar {
    background-color: var(--card);
    padding: 0.5rem 2rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    flex-shrink: 0;
    min-height: 48px;
    margin-top: 1rem;
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.10), 0 2px 10px rgba(0, 0, 0, 0.10);
    position: relative;
}

.action-bar-loader {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 3px;
    background-color: color-mix(in srgb, var(--primary) 15%, transparent);
    overflow: hidden;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.action-bar-loader.active {
    opacity: 1;
}

.action-bar-loader::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 40%;
    background-color: var(--primary);
    animation: actionbar-loading 1.2s ease-in-out infinite;
}

@keyframes actionbar-loading {
    0%   { left: -40%; }
    100% { left: 100%; }
}

.content-area {
    flex: 1;
    padding: 2rem;
    overflow-y: auto;
    width: 100%;
}

/* ---------- Content-Container (max-width + zentriert) ---------- */

/* Container-Varianten - die jeweilige Page wraps ihren Top-Level-Inhalt
   mit einer dieser Klassen. Breite steht statisch im Markup, kein
   Runtime-State, kein Page-Wechsel-Flicker. */
.container-narrow,
.container-standard,
.container-wide,
.container-full {
    width: 100%;
    margin: 0 auto;
}

.container-narrow   { max-width: 720px;  }
.container-standard { max-width: 1040px; }
.container-wide     { max-width: 1584px; }
.container-full     { max-width: none;   }

/* ---------- Status badges ---------- */

.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.5rem;
    font-size: 0.75rem;
    font-weight: var(--font-weight-medium);
    border-radius: 9999px;
    white-space: nowrap;
}

.badge-success {
    background-color: #dcfce7;
    color: #166534;
}

.badge-warning {
    background-color: #fef9c3;
    color: #854d0e;
}

.badge-error {
    background-color: #fee2e2;
    color: #991b1b;
}

.badge-primary {
    background-color: color-mix(in srgb, var(--primary) 12%, transparent);
    color: var(--primary);
}

.badge-muted {
    background-color: var(--muted);
    color: var(--muted-foreground);
}

/* Pille, die einem Text in derselben Zelle nachgestellt ist - etwa das
   Gruppenkennzeichen hinter dem Besuchernamen. Ohne eigenen Abstand steht sie
   nur um das Leerzeichen aus dem Markup versetzt und klebt am Namen. */
.badge-nachgestellt {
    margin-left: 0.5rem;
}

/* ---------- Tables ---------- */

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.875rem;
}

.data-table th {
    text-align: left;
    padding: 0.625rem 0.75rem;
    font-weight: var(--font-weight-medium);
    color: var(--muted-foreground);
    border-bottom: 2px solid var(--border);
    white-space: nowrap;
    /* Label oben verankern, damit Spalten ohne Filter dasselbe Label-Y
       haben wie Spalten mit Filter (sonst zentriert die default
       vertical-align: middle das Label in der Zelle). */
    vertical-align: top;
}

.data-table td {
    padding: 0.625rem 0.75rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}

.data-table tbody tr:nth-child(odd) {
    background-color: var(--background);
}

.data-table tbody tr:nth-child(even) {
    background-color: var(--card);
}

.data-table tbody tr:hover {
    background-color: var(--muted);
}

/* Klickbare Zeile - Cursor-Pointer als visuelle Affordance für
   Row-Click-Navigation. Action-Buttons in der Zelle haben
   `@onclick:stopPropagation`, damit sie nicht doppelt navigieren. */
.data-table tbody tr.clickable {
    cursor: pointer;
}

/* Fixed Layout - Spaltenbreiten werden aus <col>-Elementen übernommen,
   erlaubt sticky Header ohne Spalten-Verschiebung, schneidet lange
   Inhalte per `text-overflow: ellipsis` in Zellen mit `overflow: hidden`. */
.data-table.data-table-fixed {
    table-layout: fixed;
}

/* Header-Zelle: 2-zeilig - oben Label+Sort, unten Filter-Input/Select */
.data-table .th-label {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.125rem 0;
    user-select: none;
}

.data-table .th-label.sortable {
    cursor: pointer;
}

.data-table .th-label.sortable:hover {
    color: var(--foreground);
}

.data-table .sort-icon {
    opacity: 0.45;
    flex-shrink: 0;
}

.data-table .sort-icon.sort-active {
    opacity: 1;
    color: var(--primary);
}

/* Robustes Safety-Net: greift auch dann, wenn ein Projekt das Sort-Icon ohne
   `sort-icon`-Klasse rendert (nur `icon-sm`) - passierte unabhängig in VDZ +
   HYTORC. Stylt direkt das svg im sortierbaren Header: inaktiv dezenter Grauton,
   aktiv hervorgehoben (egal ob `sort-active` am DIV oder am Icon hängt). */
.data-table .th-label.sortable svg {
    color: var(--muted-foreground);
    opacity: 0.4;
}

.data-table .th-label.sortable.sort-active svg,
.data-table .th-label.sortable svg.sort-active {
    color: var(--primary);
    opacity: 1;
}

.data-table .th-filter-input,
.data-table .th-filter-select {
    width: 100%;
    margin-top: 0.375rem;
    padding: 0.375rem 0.5rem;
    height: 34px;
    box-sizing: border-box;
    font-size: 0.8125rem;
    /* Formularelemente erben die Schriftart nicht von selbst. Ohne diese Zeile
       lief die ganze Filterzeile in Arial, während die Tabelle darunter im
       Systemstack stand - in sich stimmig und deshalb schwer zu bemerken. */
    font-family: inherit;
    font-weight: var(--font-weight-normal);
    border: 1px solid var(--border);
    background-color: var(--card);
    color: var(--foreground);
    border-radius: var(--radius);
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.data-table .th-filter-input:focus,
.data-table .th-filter-select:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 15%, transparent);
}

.data-table .th-filter-input.is-active,
.data-table .th-filter-select.is-active {
    border-color: var(--primary);
    background-color: color-mix(in srgb, var(--primary) 4%, var(--card));
}

.data-table .th-filter-select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 0.375rem center;
    background-size: 14px;
    padding-right: 1.5rem;
}

/* Select wirkt wie Placeholder solange "Alle" gewählt ist (kein .is-active).
   Optionen im Dropdown bleiben in der normalen Schriftfarbe. */
.data-table .th-filter-select:not(.is-active) {
    color: var(--muted-foreground);
}

.data-table .th-filter-select option {
    color: var(--foreground);
}

/* ----- Filter-Input mit ×-Clear-Button -----
   Wrap übernimmt margin-top vom Input, damit der absolut positionierte
   Clear-Button vertikal mittig im Input sitzt (sonst rutscht er um halben
   Margin nach unten). */
.th-filter-wrap {
    position: relative;
    display: flex;
    align-items: center;
    margin-top: 0.375rem;
}

.th-filter-wrap .th-filter-input {
    flex: 1;
    margin-top: 0;
    padding-right: 1.75rem;
}

.th-filter-clear {
    position: absolute;
    right: 0.375rem;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    background: var(--muted);
    border: none;
    border-radius: 50%;
    color: var(--muted-foreground);
    cursor: pointer;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1;
    padding: 0;
    transition: background-color 0.15s, color 0.15s;
}

.th-filter-clear:hover {
    background: var(--destructive);
    color: #fff;
}

/* ===== Datum-Filter (Popover am Spalten-Header) =====
   Trigger ist ein <div> in der th-Zelle, Popover öffnet via JS-Interop
   (popover-position.js) als position:fixed. Pflicht: font-weight: 400 am
   Trigger, sonst erbt er die 500 von ".data-table th" und der "Zeitraum …"-
   Placeholder wirkt fetter als die Text-Filter-Placeholder daneben. */
.th-date-col {
    position: relative;
    overflow: visible;
}

.th-date-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.25rem;
    width: 100%;
    margin-top: 0.375rem;
    padding: 0.375rem 0.5rem;
    height: 34px;
    box-sizing: border-box;
    font-size: 0.8125rem;
    font-weight: 400;
    border: 1px solid var(--border);
    background-color: var(--card);
    border-radius: var(--radius);
    color: var(--muted-foreground);
    cursor: pointer;
    transition: border-color 0.15s ease;
}

.th-date-trigger:hover {
    border-color: var(--primary);
}

.th-date-trigger.has-value {
    color: var(--foreground);
}

.th-date-trigger.is-active {
    border-color: var(--primary);
    background-color: color-mix(in srgb, var(--primary) 4%, var(--card));
}

.th-date-display {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.date-chevron {
    margin-left: auto;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    color: #999;
}

.date-popover-overlay {
    position: fixed;
    inset: 0;
    z-index: 49;
}

.date-popover-container {
    display: grid;
    grid-template-columns: auto auto;
    background: var(--card);
    border: 1px solid var(--border);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.14);
}

.date-popover-presets {
    padding: 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 170px;
    border-right: 1px solid var(--border);
    flex-shrink: 0;
}

.date-presets-title {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--muted-foreground);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0.25rem 0.5rem 0.375rem;
}

.date-preset-btn {
    font-size: 0.8125rem;
    padding: 0.4rem 0.625rem;
    background: none;
    border: none;
    text-align: left;
    cursor: pointer;
    color: var(--foreground);
    white-space: nowrap;
}

.date-preset-btn:hover {
    background: var(--muted);
}

.date-preset-btn.active {
    background: color-mix(in srgb, var(--primary) 10%, transparent);
    color: var(--primary);
    font-weight: 500;
}

.date-popover {
    padding: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-width: 220px;
}

.date-popover-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.date-popover-row label {
    font-size: 0.75rem;
    color: var(--muted-foreground);
    width: 28px;
    flex-shrink: 0;
}

.date-popover-row .date-input {
    flex: 1;
    min-width: 0;
    margin-top: 0;
}

.date-popover-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.25rem;
    border-top: 1px solid var(--border);
    padding-top: 0.5rem;
}

.date-popover-apply {
    flex: 1;
    font-size: 0.75rem;
    padding: 0.4rem 0.75rem;
    background: var(--primary);
    color: var(--primary-foreground);
    border: 1px solid var(--primary);
    border-radius: var(--radius);
    cursor: pointer;
    text-align: center;
}

.date-popover-apply:hover {
    opacity: 0.9;
}

.date-popover-clear {
    font-size: 0.75rem;
    color: var(--muted-foreground);
    background: none;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    padding: 0.4rem 0.75rem;
}

.date-popover-clear:hover {
    color: var(--foreground);
    border-color: var(--foreground);
}

/* Optionale Selected-Row-Markierung - 3px Primary-Border links + leichter
   Primary-Tint. Wird auf `<tr class="selected">` angewendet. */
.data-table tbody tr.selected {
    background-color: color-mix(in srgb, var(--primary) 8%, var(--card)) !important;
    box-shadow: inset 3px 0 0 var(--primary);
}

/* Empty-State-Zeile innerhalb der Tabelle */
.data-table .empty-state-row td {
    padding: 2.5rem 0.75rem;
}

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    /* STANDARDS 3.10: Innenabstand, sonst kleben Icon und Knopf am Kartenrand. */
    padding: 2.5rem 0.75rem;
    color: var(--muted-foreground);
    text-align: center;
}

/* In Tabellenzeilen gibt die Zelle den Abstand vor (.empty-state-row td). */
.empty-state-row .empty-state {
    padding: 0;
}

/* Zelle mit Ellipsis - funktioniert nur in data-table-fixed (table-layout: fixed). */
.data-table .cell-ellipsis {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Action-Spalte (icon-only Buttons rechts in der Zeile). Header-Label und
   Body-Buttons rechtsbündig. Gap entsteht durch margin-left an Buttons,
   damit der `<td>` als table-cell-Layout intakt bleibt. */
.data-table .cell-actions {
    text-align: right;
    white-space: nowrap;
}

.data-table td.cell-actions .action-btn + .action-btn {
    margin-left: 0.25rem;
}

/* ---------- Cards ---------- */

.card {
    background-color: var(--card);
    color: var(--card-foreground);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.10);
    width: 100%;
}

.card-header {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border);
    font-weight: var(--font-weight-medium);
}

/* ---------- Buttons ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    font-size: 0.875rem;
    font-weight: var(--font-weight-medium);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background-color: var(--card);
    color: var(--foreground);
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease;
    text-decoration: none;
}

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

.btn:disabled,
.btn[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

.btn-primary {
    background-color: var(--primary);
    color: var(--primary-foreground);
    border-color: var(--primary);
}

.btn-primary:hover {
    background-color: color-mix(in srgb, var(--primary) 85%, #000);
    border-color: color-mix(in srgb, var(--primary) 85%, #000);
}

/* Speichern-Rückmeldung am Knopf selbst (STANDARDS 3.19), nicht als Toast.
   Grün aus HYTORC.LizenzService übernommen (5,27:1 auf Weiß), Rot ist der
   Destructive-Wert aus STANDARDS 1 Farben (5,62:1) - beide über 4,5:1. */
.btn--saved,
.btn-primary.btn--saved,
.btn-primary.btn--saved:hover {
    background-color: #0a7d2c;
    border-color: #0a7d2c;
    color: #fff;
}

.btn--saved .icon-sm {
    animation: btn-saved-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes btn-saved-pop {
    0%   { transform: scale(0.4) rotate(-20deg); opacity: 0; }
    60%  { transform: scale(1.2) rotate(5deg); opacity: 1; }
    100% { transform: scale(1) rotate(0); opacity: 1; }
}

.btn--failed,
.btn-primary.btn--failed,
.btn-primary.btn--failed:hover {
    background-color: #c62828;
    border-color: #c62828;
    color: #fff;
}

.btn-secondary {
    background-color: var(--card);
    color: var(--foreground);
    border-color: var(--border);
}

.btn-secondary:hover {
    background-color: var(--muted);
}

.btn-danger {
    background-color: var(--destructive);
    color: var(--destructive-foreground);
    border-color: var(--destructive);
}

.btn-danger:hover {
    background-color: #a52121;
    border-color: #a52121;
}

.btn-sm {
    padding: 0.25rem 0.5rem;
    font-size: 0.8125rem;
}

.action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius);
    background: transparent;
    color: var(--foreground);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.action-btn:hover {
    background-color: var(--muted);
}

.action-btn-danger:hover {
    background-color: #fee2e2;
    color: var(--destructive);
}

.action-bar-title {
    font-size: 1.125rem;
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
    white-space: nowrap;
    border: none;
    outline: none;
    margin: 0;
    padding: 0;
}

.action-bar-title-with-back {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

/* Zusatz hinter dem Titel der Aktionsleiste, z. B. der Bauherr auf der Projektseite. */
.action-bar-untertitel {
    font-size: 0.875rem;
    color: var(--muted-foreground);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    margin-left: 0.25rem;
}

/* ---------- Forms ---------- */

.form-input {
    width: 100%;
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    font-family: inherit;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background-color: var(--input-background);
    color: var(--foreground);
    outline: none;
    transition: border-color 0.15s ease;
}

/* Gleiche Höhe für alles Einzeilige.
   Ohne sie standen drei Höhen nebeneinander: Textfeld 39px, select 36px,
   datetime-local 41px. Padding und Rahmen sind überall gleich - der
   Unterschied kommt aus dem, was der Browser innen selbst beisteuert
   (Zeilenhöhe "normal" beim select, eigene Innenteile beim Datumsfeld).
   Dagegen hilft nur eine gesetzte Höhe.

   Die Rechnung stammt aus den Werten darüber und bleibt richtig, wenn sie
   sich ändern: 1.5em Zeilenhöhe + 2x0.5rem Innenabstand + 2x1px Rahmen.

   Nur input und select, nicht textarea: Die trägt dieselbe Klasse und lebt
   von ihrer Zeilenzahl. */
input.form-input,
.form-select {
    height: calc(1.5em + 1rem + 2px);
    line-height: 1.5;
}

.form-input:focus {
    border-color: var(--ring);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ring) 15%, transparent);
}

.form-input[readonly],
.form-input:read-only {
    background-color: var(--background);
    color: var(--muted-foreground);
    cursor: default;
    border-color: var(--border);
}

.form-input[readonly]:focus,
.form-input:read-only:focus {
    border-color: var(--border);
    box-shadow: none;
}

/* Volle Spaltenbreite wie die Textfelder. Ohne Angabe passt sich ein select an
   seine längste Option an - dann steht in einer zweispaltigen Zeile ein
   169px-Feld neben einem 269px-Feld, und die Zeile sieht aus, als wäre sie
   falsch zusammengesetzt. Der Inhalt ist ausserdem variabel: Gastgeber und
   Besuchsgründe pflegt der Kunde selbst. */
.form-select {
    width: 100%;
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    /* Ein select erbt die Schriftart nicht von selbst - ohne diese Zeile stand
       es in Arial, während daneben der Systemstack lief. Fiel als
       Höhenunterschied auf, bevor es als Schriftunterschied auffiel. */
    font-family: inherit;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background-color: var(--input-background);
    color: var(--foreground);
    outline: none;
    cursor: pointer;
}

/* Ausnahme für feste Aufzählungen aus dem Code - Sprache, Rolle, Status.
   Die wachsen nicht mit den Daten des Kunden, und "Deutsch" in einem Feld über
   die halbe Zeile ist derselbe leere Platz wie bei einem Datum. Gastgeber und
   Besuchsgründe bleiben bei voller Breite: Die pflegt der Kunde, und der
   nächste Eintrag kann länger sein als alle bisherigen. */
.form-select-kurz {
    width: auto;
    min-width: 10rem;
}

.form-select:focus {
    border-color: var(--ring);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ring) 15%, transparent);
}

.form-label {
    display: block;
    margin-bottom: 0.375rem;
    font-size: 0.875rem;
    font-weight: var(--font-weight-medium);
    color: var(--foreground);
}

/* Auswahlkarten: Kästchen bzw. Radio mit Titel und Erklärung, gewählt mit Markenrand (Rollen, Passwortart). */
.optionen {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.option {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
}

.option:hover {
    border-color: var(--primary);
}

.option-an {
    border-color: var(--primary);
    background-color: color-mix(in srgb, var(--primary) 5%, white);
}

.option input {
    margin-top: 0.2rem;
    accent-color: var(--primary);
}

.option-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.option-titel {
    font-size: 0.875rem;
    font-weight: var(--font-weight-medium);
    color: var(--foreground);
}

.option-erklaerung {
    font-size: 0.8125rem;
    color: var(--muted-foreground);
}

.checkbox-label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    cursor: pointer;
    font-size: 0.875rem;
    color: var(--foreground);
}

.form-actions {
    display: flex;
    gap: 0.5rem;
    justify-content: flex-end;
    margin-top: 0.5rem;
}

.form-group {
    margin-bottom: 0.875rem;
}

/* Zwei Felder nebeneinander. Bricht unter 560px um - im Modal ist das die
   Breite, ab der zwei Spalten zu schmal für eine Firmenbezeichnung werden. */
.form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}

@media (max-width: 560px) {
    .form-row {
        grid-template-columns: 1fr;
    }
}

/* Zwischenüberschrift im Formular - gliedert lange Eingabemasken.
   Herkunft: DEVEX.CRM (.detail-abschnitt). */
.form-abschnitt {
    margin: 1.25rem 0 0.75rem;
    padding-top: 0.875rem;
    border-top: 1px solid var(--border);
    font-size: 0.875rem;
    font-weight: var(--font-weight-medium);
    color: var(--muted-foreground);
}

.form-abschnitt:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

/* Erläuterung unter einem Feld - trägt die Begründung, die sonst nur im
   Code steht (z.B. warum die PIN an die hinterlegte Adresse geht). */
/* Abstand nach oben für einen Block, der sonst am vorigen klebt - etwa eine
   Fehlermeldung unter dem letzten Feld. Vier Seiten benutzten dafür
   ".portal-abstand-oben"; die Klasse steht aber nur im Stylesheet des Portals
   und blieb hier wirkungslos. */
.feld-abstand-oben {
    margin-top: 1rem;
}

.form-hinweis {
    margin: 0.375rem 0 0;
    font-size: 0.75rem;
    line-height: 1.4;
    color: var(--muted-foreground);
}

/* Fehlerbanner im Formular. Farblich identisch zu .login-error - der Standard
   sieht dafür den Namen .alert-error vor; .login-error wird beim nächsten
   Touch der Login-Seiten darauf umgestellt. */
.alert-error {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.625rem 1rem;
    background-color: #fee2e2;
    color: #991b1b;
    font-size: 0.875rem;
    border-radius: var(--radius);
}

/* Nebensächliche Aktion im Fliesstext - kein Knopf, damit sie nicht mit den
   beiden Entscheidungen darüber konkurriert. */
.btn-link {
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: var(--primary);
    text-decoration: underline;
    cursor: pointer;
}

/* Aktion in einer Tabellenzeile - steht unter dem Zustand, nicht daneben, damit
   die schmale Spalte nicht bricht. */
.zeile-aktion {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.75rem;
}

.btn-link:hover {
    color: color-mix(in srgb, var(--primary) 85%, #000);
}

/* Zwei Karten untereinander auf derselben Seite. */
.karte-abstand {
    margin-top: 1.25rem;
}

/* ---------- Feldbreite nach Inhalt ---------- */
/* Ein Eingabefeld sagt durch seine Breite, was erwartet wird. Ein Vorname in
   einem Feld über die halbe Zeile behauptet Platz für einen Satz - und wenn
   jedes Feld gleich breit ist, unterscheidet nichts mehr eine Postleitzahl von
   einer Firmenbezeichnung. Deshalb bekommt jedes Feld die Breite seines
   erwarteten Inhalts, nicht die seiner Spalte.

   Umgesetzt als max-width auf der vollen Breite: In einer schmalen Spalte oder
   auf dem Telefon schrumpft das Feld weiter mit, es wächst nur nicht darüber
   hinaus. Ein festes width würde die Umbrüche zerlegen.

   Über den Typ, wo der Typ es hergibt - sonst muss jedes neue Feld daran
   denken, und das erste, das es vergisst, fällt niemandem auf. Die
   Filter-Popover setzen ihre eigene Breite über einen spezifischeren Selektor
   und bleiben davon unberührt. */

/* ~30 Zeichen. */
.form-input[type="email"] {
    max-width: 22rem;
}

/* Passwörter sind länger als sie aussehen, aber keine Sätze. */
.form-input[type="password"] {
    max-width: 20rem;
}

/* Vor- und Nachname, Ort - selten über 20 Zeichen. */
.feld-name {
    max-width: 16rem;
}

/* Firma, Bezeichnung, Titel, Überschrift - kann ein halber Satz werden. */
.feld-lang {
    max-width: 30rem;
}

/* PIN, Kuerzel, Zahl. */
.feld-kurz {
    max-width: 10rem;
}
/* Mehrzeiliger Text - Einleitung, Bestätigungstext, Abschlusstext. Rund 95
   Zeichen je Zeile; darüber wird das Korrekturlesen mühsam, und genau dazu
   sind diese Felder da. */
.feld-flies {
    max-width: 44rem;
}

/* Bewusst über die Inhaltslänge hinaus. Die Klasse steht im Markup, damit die
   Entscheidung sichtbar ist - ein Feld ohne Breitenangabe wäre sonst nicht von
   einem unterscheidbar, bei dem jemand die Frage nur nicht gestellt hat. Wer
   sie setzt, schreibt den Grund daneben. */
.feld-voll {
    max-width: none;
}
.form-input[type="date"] {
    width: auto;
    min-width: 10rem;
}

.form-input[type="datetime-local"] {
    width: auto;
    min-width: 13rem;
}

.form-input[type="time"] {
    width: auto;
    min-width: 7rem;
}

/* Aufzählung ohne Punkte - für kurze Verweislisten in einer Karte. */
/* Filter im Kartenkopf (Journal-Karten, Daniel Simon 2026-11-05): kompakte Auswahl und Umschalter vor dem
   Hauptknopf; .is-active markiert einen gesetzten Filter wie in den Tabellenköpfen. */
.kopf-filter {
    flex: 0 1 auto;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.375rem;
    font-weight: normal;
}

.kopf-filter .form-select {
    width: auto;
    max-width: 11rem;
    padding: 0 1.75rem 0 0.5rem;
    font-size: 0.8125rem;
}

/* Auswahl und Knöpfe im Filterblock gleich hoch. */
.kopf-filter .form-select,
.kopf-filter .btn {
    height: 2rem;
    box-sizing: border-box;
}

.kopf-filter .form-select.is-active,
.kopf-filter .btn.is-active {
    border-color: var(--primary);
    background-color: color-mix(in srgb, var(--primary) 8%, white);
}

.liste-schlicht {
    list-style: none;
    margin: 0;
    padding: 0;
}

.liste-schlicht li {
    padding: 0.25rem 0;
}

/* Kleine Listen in Karten, deren ganze Zeile verlinkt ist (Daniel Simon, 2026-11-05): Der Link mit .zeilen-ziel spannt
   per ::after über die Zeile, andere Links und Knöpfe in der Zeile liegen darüber und bleiben eigenständig. */
.liste-verlinkt > li {
    position: relative;
    isolation: isolate;
    cursor: pointer;
}

/* Hover-Fläche ragt links und rechts etwas über den Text hinaus (Daniel Simon, 2026-11-05); per Pseudo-Element,
   damit die Abstände der einzelnen Listen unverändert bleiben. */
.liste-verlinkt > li:hover::before {
    content: "";
    position: absolute;
    inset: 0 -0.625rem;
    z-index: -1;
    background-color: var(--muted);
}

.liste-verlinkt a.zeilen-ziel::after {
    content: "";
    position: absolute;
    inset: 0;
}

.liste-verlinkt > li :is(a:not(.zeilen-ziel), button) {
    position: relative;
    z-index: 1;
}

/* ---------- Bearbeiten in der Zeile ---------- */
/* Schmaler als ein Formularfeld: Die Zeile soll ihre Höhe behalten, sonst
   springt die ganze Tabelle beim Umschalten in den Änderungsmodus. */
.zeilen-eingabe {
    padding: 0.25rem 0.5rem;
    font-size: 0.875rem;
}

/* In der Tabellenzeile bestimmt die Spalte die Breite: ohne das liefen Datumsfelder (min-width 10rem) über die
   Spalte hinaus in den Zellabstand und stießen an das Nachbarfeld (Daniel Simon, 2026-11-05). */
.data-table .zeilen-eingabe {
    width: 100%;
    min-width: 0;
}

/* Datumsfelder nur so breit wie nötig: Ohne Mindestbreite ist das Feld 134px breit, das reicht für Datum und
   Kalendersymbol. Die Spalte dafür ist 10rem breit (Feld plus Zellabstand), den Rest bekommen die Textspalten. */
.data-table .form-input[type="date"].zeilen-eingabe {
    width: auto;
    max-width: 100%;
    min-width: 0;
}

.cell-actions {
    white-space: nowrap;
}

/* Gedämpft statt in der Markenfarbe: In der Zeile stehen drei Symbole
   nebeneinander, und wenn alle rot sind, hebt sich das Löschen nicht mehr ab -
   die Markenfarbe des Hauses ist selbst ein Rot. */
.cell-actions .btn-link {
    padding: 0.125rem 0.25rem;
    vertical-align: middle;
    color: var(--muted-foreground);
}

.cell-actions .btn-link:hover {
    color: var(--foreground);
}

.cell-actions .btn-link-destructive,
.cell-actions .btn-link-destructive:hover {
    color: var(--destructive);
}

/* ---------- Klickbare Zeile ---------- */
/* Ein echter Link, kein @onclick: Nur so funktionieren Mittelklick, Tastatur,
   "Link in neuem Tab öffnen" und "Adresse kopieren" - alles, was ein Benutzer
   von einem Listeneintrag erwartet. Der <a> bleibt leer und wird über die
   Zeile gestreckt; träge er den Namen, würde dessen overflow:hidden die
   Streckung abschneiden. Die Beschriftung kommt per aria-label.
   Muster aus DEVEX.CRM. */
.data-table tbody tr.clickable {
    cursor: pointer;
    position: relative;
}

.zeilen-link {
    position: absolute;
    inset: 0;
    z-index: 0;
}

/* Bedienelemente in der Zeile müssen über dem gestreckten Link liegen,
   sonst fängt er ihre Klicks ab. */
.data-table tbody tr.clickable .btn,
.data-table tbody tr.clickable .btn-link,
.data-table tbody tr.clickable button,
.data-table tbody tr.clickable input,
.data-table tbody tr.clickable select {
    position: relative;
    z-index: 1;
}

/* ---------- Modals (STANDARDS 3.5) ---------- */
/* Herkunft: DEVEX.CRM/wwwroot/css/app.css, übernommen. */

.modal-backdrop {
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
}

.modal {
    background-color: var(--card);
    width: 600px;
    max-width: calc(100vw - 32px);
    max-height: 85vh;
    overflow-y: auto;
    padding: 1.5rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);
}

.modal-wide {
    width: 1200px;
}

.modal-titel {
    margin: 0 0 1rem;
    font-size: 1.125rem;
    font-weight: var(--font-weight-medium);
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
}

/* Setzt eine Aktion im Modal-Fuss nach links ab - für zerstörende Aktionen,
   die nicht neben Abbrechen/Schliessen stehen sollen, wo man sie versehentlich
   trifft. Herkunft: DEVEX.CRM. */
.modal-actions-links {
    margin-right: auto;
}

.modal-mittig {
    text-align: center;
    padding: 1.5rem 0;
}

.modal-mittig .spinner {
    margin: 0 auto 0.5rem;
    display: block;
}

/* Angezeigter, nicht bearbeitbarer Wert im Formularraster. Bewusst kein
   readonly-Input: Ein Feld, das aussieht wie ein Feld, lädt zum Tippen ein. */
.feld-lesend {
    padding: 0.5rem 0;
    font-size: 0.875rem;
}

/* Zweite Zeile in einer Tabellenzelle - E-Mail unter dem Namen, Herkunft unter
   dem Zustand. */
.zeile-nebentext {
    font-size: 0.75rem;
    color: var(--muted-foreground);
    line-height: 1.4;
}

/* Zerstörende Aktion. Farbwert aus STANDARDS 1 (#c62828, 5,62:1 auf Weiß) -
   der frühere Hauswert #ff4444 unterschritt mit 3,41:1 die AA-Grenze. */
.btn-destructive {
    background-color: #c62828;
    border-color: #c62828;
    color: #fff;
}

.btn-destructive:hover {
    background-color: #a81f1f;
    border-color: #a81f1f;
}

.alert-success {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.625rem 1rem;
    background-color: #dcfce7;
    color: #166534;
    font-size: 0.875rem;
    border-radius: var(--radius);
}

.filter-label {
    font-size: 0.875rem;
    font-weight: var(--font-weight-medium);
    color: var(--muted-foreground);
    white-space: nowrap;
}

/* ---------- Pagination ---------- */

.pagination {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.pagination-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2rem;
    height: 2rem;
    padding: 0 0.5rem;
    font-size: 0.875rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background-color: var(--card);
    color: var(--foreground);
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.pagination-btn:hover {
    background-color: var(--muted);
}

.pagination-btn-active {
    background-color: var(--primary);
    color: var(--primary-foreground);
    border-color: var(--primary);
}

.pagination-btn-active:hover {
    background-color: color-mix(in srgb, var(--primary) 85%, #000);
}

.pagination-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1rem;
    gap: 1rem;
    flex-wrap: wrap;
}

.pagination-info {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 0.875rem;
    color: var(--muted-foreground);
}

.pagination-left,
.pagination-right {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: var(--muted-foreground);
}

.pagination-range {
    font-variant-numeric: tabular-nums;
}

.pagination-ellipsis {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2rem;
    height: 2rem;
    color: var(--muted-foreground);
    user-select: none;
}

/* Page-Size-Select in der Pagination-Card - eigenständig (nicht von
   .th-filter-select abgeleitet, sonst sind Höhe/Padding/Width vermischt). */
.page-size-select {
    height: 34px;
    box-sizing: border-box;
    padding: 0 1.75rem 0 0.625rem;
    font-size: 0.875rem;
    line-height: 1;
    border: 1px solid var(--border);
    background-color: var(--card);
    color: var(--foreground);
    border-radius: var(--radius);
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 0.5rem center;
    background-size: 14px;
    cursor: pointer;
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.page-size-select:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 15%, transparent);
}

/* Vertikaler Abstand zwischen Tabellen-Card und Pagination-Card. */
.list-page {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* ---------- Detail-Page ---------- */

.detail-card {
    padding: 1.5rem 2rem;
}

.detail-grid {
    display: grid;
    grid-template-columns: max-content 1fr;
    column-gap: 2rem;
    row-gap: 0.625rem;
    margin: 0;
    font-size: 0.875rem;
}

.detail-grid dt {
    color: var(--muted-foreground);
    font-weight: var(--font-weight-medium);
    margin: 0;
}

.detail-grid dd {
    margin: 0;
    color: var(--foreground);
}

/* Aktionen unten in einer Karte: Speichern rechts, Löschen links (Aufgaben- und Unteraufgabendetail). */
.karte-aktionen {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 1.25rem;
}

.karte-aktion-links {
    margin-right: auto;
}

/* ---------- Steckbrief (Projektübersicht, Phasenkopf) ---------- */
/* Steckbrief (ks-ci-preview.html Abschnitt 8c, corporate-design.md): Titel rot und fett,
   Labels rechtsbündig fett, Werte links, dazwischen eine DURCHGÄNGIGE rote Linie von 3 px
   (Daniel Simon, 2026-11-05 - bildschirmtauglicher als die 1 pt der Broschüre). Kein
   Zeilenabstand im Grid, damit die Linie nicht unterbrochen wird; der Abstand liegt im Padding. */
.ks-steckbrief-titel {
    color: var(--primary);
    font-size: 1.25rem;
    font-weight: 700;
    margin: 0 0 0.75rem;
}

.ks-steckbrief dl {
    display: grid;
    grid-template-columns: max-content 1fr;
    row-gap: 0;
    margin: 0;
    font-size: 0.875rem;
}

.ks-steckbrief dt {
    font-weight: 700;
    color: var(--ks-ink);
    text-align: right;
    padding: 0.2rem 0.9rem 0.2rem 0;
    border-right: 3px solid var(--primary);
    margin: 0;
}

.ks-steckbrief dt.zeile-mitte {
    justify-content: flex-end;   /* rechtsbündig wie die übrigen Beschriftungen */
}

.ks-steckbrief dd {
    color: var(--ks-ink);
    padding: 0.2rem 0 0.2rem 0.9rem;
    margin: 0;
}

.ks-steckbrief dd {
    min-width: 0;
}

/* Zeilen mit Bedienelementen (Status, Auswahl): Beschriftung und Inhalt vertikal mittig
   (Daniel Simon, 2026-11-05). Gilt für .detail-grid und den Steckbrief. */
dt.zeile-mitte,
dd.zeile-mitte {
    display: flex;
    align-items: center;
}

/* Inhalte dürfen in der Zeile schrumpfen und umbrechen (Flex-Elemente schrumpfen sonst nicht unter ihre Inhaltsbreite). */
dd.zeile-mitte > * {
    min-width: 0;
    max-width: 100%;
}

/* ---------- Navigation ---------- */

.nav-link {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0 1rem;
    height: 40px;
    font-size: 0.875rem;
    color: var(--sidebar-foreground);
    text-decoration: none;
    border-radius: var(--radius);
    transition: background-color 0.15s ease;
}

.nav-link:hover {
    background-color: var(--sidebar-accent);
    color: var(--sidebar-accent-foreground);
    text-decoration: none;
}

.nav-link-active,
.nav-link.active {
    background-color: var(--sidebar-accent);
    color: var(--sidebar-accent-foreground);
    box-shadow: inset 4px 0 0 var(--sidebar-primary);
}

.nav-link-active:hover,
.nav-link.active:hover {
    background-color: var(--sidebar-accent);
    color: var(--sidebar-accent-foreground);
}

/* ---------- Tree / Nav-Row ---------- */
/* Flat + Tree-Items teilen sich die gleiche nav-link-Struktur.
   Active-Indicator (4px box-shadow) sitzt am Sidebar-Rand.
   Folder-Expand-Chevron ist rechts, damit das Icon direkt
   neben dem Indicator steht. */

.tree-link-folder {
    cursor: pointer;
}

.tree-chevron-right {
    margin-left: auto;
    opacity: 0.6;
    transition: transform 0.15s ease;
}

.tree-chevron-open {
    transform: rotate(90deg);
}

.tree-children {
    position: relative;
    margin-left: 16px;
}

.tree-children::before {
    content: '';
    position: absolute;
    left: 8px;
    top: 2px;
    bottom: 2px;
    width: 1px;
    background-color: var(--sidebar-border);
}

/* Collapsed Sidebar: Baumkinder werden komplett ausgeblendet - nur
   Level-0-Folder bleiben als Icons sichtbar. Dadurch fluchtet jedes
   sichtbare Icon mit den flachen NavLinks. */
.tree-children.sidebar-collapsed {
    display: none;
}

/* Collapsed Sidebar: Chevron am Folder-Header raus, sonst würde
   `margin-left: auto` das Folder-Icon aus der zentrierten Spur drücken. */
.nav-collapsed .tree-chevron-right {
    display: none;
}

/* ---------- Icon sizes ---------- */

.icon-sm {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.icon-md {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
}

/* ---------- Blazor ReconnectModal ---------- */

.components-reconnect-first-attempt-visible,
.components-reconnect-repeated-attempt-visible,
.components-reconnect-failed-visible,
.components-pause-visible,
.components-resume-failed-visible,
.components-rejoining-animation {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation,
#components-reconnect-modal.components-reconnect-paused .components-pause-visible,
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible,
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible,
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation,
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible {
    display: block;
}

#components-reconnect-modal:not([open]) {
    display: none;
}

#components-reconnect-modal {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
    color: var(--foreground);
    font-size: 0.875rem;
}

#components-reconnect-modal::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
}

.components-reconnect-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button {
    border: 0;
    background-color: var(--primary);
    color: var(--primary-foreground);
    padding: 0.5rem 1.5rem;
    cursor: pointer;
    font-size: 0.875rem;
    font-weight: var(--font-weight-medium);
}

#components-reconnect-modal button:hover {
    background-color: color-mix(in srgb, var(--primary) 85%, #000);
}

.components-rejoining-animation {
    position: relative;
    width: 60px;
    height: 60px;
}

.components-rejoining-animation div {
    position: absolute;
    border: 3px solid var(--primary);
    opacity: 1;
    border-radius: 50%;
    animation: components-rejoining-animation 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}

.components-rejoining-animation div:nth-child(2) {
    animation-delay: -0.5s;
}

@keyframes components-rejoining-animation {
    0%, 4.9% {
        top: 30px; left: 30px; width: 0; height: 0; opacity: 0;
    }
    5% {
        top: 30px; left: 30px; width: 0; height: 0; opacity: 1;
    }
    100% {
        top: 0; left: 0; width: 60px; height: 60px; opacity: 0;
    }
}

/* ---------- Formular-spezifisch (kompakte Inputs/Labels) ---------- */

.formular .form-input {
    font-size: 0.8125rem;
    padding: 0.25rem 0.5rem;
    height: 1.75rem;
    min-height: 1.75rem;
    max-height: 1.75rem;
    box-sizing: border-box;
    line-height: 1.2;
}

.formular .form-label {
    font-size: 0.6875rem;
    margin-bottom: 0.125rem;
    padding: 0 2px;
    color: var(--muted-foreground);
    font-weight: var(--font-weight-normal);
    display: block;
}

.formular input[type="date"].form-input {
    padding: 0 0.5rem;
    line-height: 1.75rem;
    font-family: inherit;
    -webkit-appearance: none;
    appearance: none;
}

.formular input[type="date"].form-input::-webkit-datetime-edit {
    padding: 0;
    line-height: 1.75rem;
}

.formular input[type="date"].form-input::-webkit-calendar-picker-indicator {
    padding: 0;
    margin: 0;
}

/* ---------- Text Picker (PDF → Input) ---------- */
/* Cursor im PDF bleibt unverändert (Text-Selektion bleibt natürlich) */

/* ---------- Animations ---------- */

/* Lade-Spinner: neutraler rotierender Ring. Ersetzt im Ladezustand ein Icon -
   Icons selbst drehen NIE (STANDARDS.md § Icons). Erbt die Farbe via currentColor. */
.spinner {
    display: inline-block;
    flex: none;
    border-radius: 50%;
    border: 2px solid currentColor;
    border-top-color: transparent;
    animation: spin 0.7s linear infinite;
    vertical-align: middle;
}

.spinner-sm { width: 16px; height: 16px; }
.spinner-md { width: 20px; height: 20px; }

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

/* Rotation des Kreispfeil-Symbols im Ladezustand (STANDARDS.md §1 Icons,
   §3.15). Die Klasse wurde in der Showcase an sechs Stellen verwendet, war
   aber nirgends definiert - es drehte sich also nichts, obwohl der Standard
   es vorschreibt. DEVEX.CRM hatte die Regel deshalb selbst nachgebaut.

   Sie gilt ausschließlich für neutrale Ladesymbole. Ein bedeutungstragendes
   Icon wird im Ladezustand ersetzt, nicht gedreht - dafür gibt es
   Spinner.razor. */
.spin {
    animation: spin 0.8s linear infinite;
}

/* ---------- Login page ---------- */

.login-page {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background-color: var(--sidebar);
    padding: 1.5rem;
}

.login-card {
    width: 100%;
    max-width: 400px;
    padding: 2rem;
}

.login-logo {
    display: flex;
    justify-content: center;
    margin-bottom: 1.5rem;
}

.login-logo-img {
    height: 88px;
    width: auto;
}

/* Wortmarke statt Monogramm: über die Breite gesetzt, nicht über die Höhe.
   Bei 88 px Höhe wäre sie 444 px breit und spränge aus der 400-px-Karte.
   300 px Breite ergeben rund 59 px Höhe - dabei bleibt die Zweitzeile
   "CASING & PACKAGING" lesbar, anders als in der schmalen Kopfleiste. */
.login-logo-wortmarke {
    height: auto;
    width: 100%;
    max-width: 300px;
}

.login-title {
    text-align: center;
    margin-bottom: 1.5rem;
    color: var(--foreground);
}

.login-field {
    margin-bottom: 1rem;
}

.login-btn {
    width: 100%;
    margin-top: 0.5rem;
}

.login-error {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.625rem 1rem;
    margin-bottom: 1rem;
    background-color: #fee2e2;
    color: #991b1b;
    font-size: 0.875rem;
    border-radius: var(--radius);
}

.login-footer {
    margin-top: 1.5rem;
    text-align: center;
    font-size: 0.6875rem;
    color: var(--sidebar-foreground);
    opacity: 0.5;
    line-height: 1.6;
}

.login-version {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
}

.login-fieldset {
    border: 0;
    padding: 0;
    margin: 0;
    min-width: 0;
}

/* ---------- Blazor-specific ---------- */

#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuOTI5IDUxLjMwNCAyNjYuOTQgNTEuOTE0TDI4OS45MDcgNjUuNzA0QzI5MS4xMTkgNjYuMzE0IDI5Mi4xMjkgNjcuMjI4IDI5Mi43MzcgNjguMzY5TDMwNC4yMDIgODcuNjE0QzMwNS4wMzQgODkuNDMxIDMwNS4wMzQgOTEuNTUxIDMwNC4yMDIgOTMuMzY5TDI4OS4yNDYgOTMuMzY5QzI5MC4wNzggOTEuNTUxIDI5MC4wNzggODkuNDMxIDI4OS4yNDYgODcuNjE0TDI3Ny43ODEgNjguMzY5QzI3Ny4xNzMgNjcuMjI4IDI3Ni4xNjMgNjYuMzE0IDI3NC45NTEgNjUuNzA0TDI1MS45ODQgNTEuOTE0QzI1Mi45OTUgNTEuMzA0IDI1NC4yMDYgNTEgMjU1LjQxOCA1MUwyNjMuNTA2IDUxWiIgZmlsbD0iI0ZGNDQzMyIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9nPjwvc3ZnPg==) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

.blazor-error-boundary::after {
    content: "An error has occurred."
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid var(--destructive);
}

/* ==========================================================================
   Ergänzungen aus NCP.BesucherCenter (generisch, keine NCP-Fachlichkeit)
   ========================================================================== */

/* --- Ladezustand des Anmeldeknopfs ---------------------------------------
   Die Anmeldeseite ist statisch gerendert (das Auth-Cookie kann nur im
   HttpContext ausgestellt werden), ein Blazor-Ladezustand ist dort nicht
   möglich. Stattdessen schaltet form-submit-spinner.js den Knopf beim
   Absenden auf .is-loading. Übernommen aus DEVEX.CRM. */
.login-btn-spinner {
    display: none;
}

.login-btn.is-loading {
    pointer-events: none;
    opacity: 0.85;
}

.login-btn.is-loading .login-btn-spinner {
    display: inline-block;
}

/* Abmelden liegt in einem Formular (POST mit Antiforgery-Token). Das Formular
   darf im Dropdown keinen eigenen Kasten aufmachen. */
.header-dropdown-form {
    margin: 0;
    display: block;
}

.header-dropdown-form button {
    width: 100%;
    background: none;
    border: none;
    font: inherit;
    text-align: left;
}

/* Login: vollständiges Kaiser-Logo (Wortmarke + Slogan, Seitenverhältnis 2,25 : 1),
   über die Breite gesetzt wie bei NCP - 260px ergeben rund 116px Höhe. */
.login-logo-kaiser {
    height: auto;
    width: 100%;
    max-width: 260px;
}

/* Firmierung unter dem Anwendungsnamen auf der Anmeldeseite. */
.login-title {
    margin-bottom: 0.25rem;
}

.login-firma {
    text-align: center;
    font-size: 0.875rem;
    color: var(--muted-foreground);
    margin-bottom: 1.5rem;
}

/* Hinweisbanner in Gelb (Farbwerte der .badge-warning) - etwa für das Standardpasswort. */
.alert-warning {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.625rem 1rem;
    background-color: #fef9c3;
    color: #854d0e;
    font-size: 0.875rem;
    border-radius: var(--radius);
}

.alert-warning a {
    color: inherit;
    text-decoration: underline;
}

/* Empty-State einer Seite, deren Inhalt in einem späteren Paket entsteht (LeererBereich). */
.leerer-bereich {
    padding: 3rem 1.5rem;
}

.leerer-bereich-titel {
    font-size: 1rem;
    font-weight: var(--font-weight-medium);
    color: var(--foreground);
}

/* ---------- Status mit Übersteuerung (OP-7, Shared/StatusSteuerung.razor) ---------- */
/* Muster HG.HGVerwaltung (StatusBadge mit Pin-Symbol, Hinweis „manuell gepinnt · Automatik“). */
.status-steuerung {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.status-schloss {
    width: 0.75rem;
    height: 0.75rem;
    margin-right: 0.25rem;
}

.status-hinweis {
    font-size: 0.75rem;
    color: var(--muted-foreground);
}

.status-trenner {
    margin: 0 0.25rem;
}

/* „manuell setzen“: Link-Optik, öffnet die Auswahl (StatusSteuerung). */
.status-link {
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: var(--primary);
    cursor: pointer;
}

.status-link:hover {
    text-decoration: underline;
}

.status-auswahl {
    width: auto;
    max-width: min(12rem, 100%);   /* in schmalen Spalten nicht über den Rand */
    padding-top: 0.25rem;
    padding-bottom: 0.25rem;
    font-size: 0.8125rem;
}

/* ---------- Fristfarben (Grobkonzept PC.04, OP-9/OP-12, Core/Statuslogik/Fristen) ---------- */
/* Diese Kalenderwoche orange, heute oder überfällig rot - als Pille, damit die Farbe nicht allein am
   Text hängt. Rot in den Werten der .badge-error, Orange mit 6,4 : 1 auf dem Hintergrund. */
.frist {
    white-space: nowrap;
}

.frist-woche,
.frist-faellig {
    padding: 0.0625rem 0.375rem;
    border-radius: 9999px;
    font-weight: var(--font-weight-medium);
}

.frist-woche {
    background-color: #ffedd5;
    color: #9a3412;
}

.frist-faellig {
    background-color: #fee2e2;
    color: #991b1b;
}

.frist-leer {
    color: var(--muted-foreground);
}

/* Fehlermeldung direkt am Feld (STANDARDS 3.4) - zusätzlich zur Sammelmeldung über dem Speichern. */
.feld-fehler {
    margin: 0.375rem 0 0;
    font-size: 0.75rem;
    color: #991b1b;
}

/* ==========================================================================
   Kaiser Ingenieurbau - Kundenakzent (ADR-002), als letzter Block (Muster NCP).
   Übernommen aus docs/00-kundenartefakte/branding/ks-theme.css; SSOT der Werte ist
   corporate-design.md. Werte dort ändern und hier nachziehen, nicht umgekehrt.
   ========================================================================== */

:root {
    /* EIN Markenrot für die ganze Anwendung: #E2001A (Rot des Kaiser-Website-Logos,
       Pixel-Histogramm). Festgelegt Daniel Simon, 2026-11-05 (ADR-002).
       Weiß darauf 4,94 : 1 - erfüllt WCAG AA für Buttons und roten Text auf Weiß. */
    --primary: #E2001A;
    --primary-foreground: #ffffff;
    --ring: #E2001A;

    /* Kein Rot-Tint: ein heller Rot-Hintergrund läse sich wie die Fehlerpille (#fee2e2)
       und bräuchte für lesbaren Text ein zweites, dunkleres Rot. Neutral wie --muted. */
    --accent: #f0f0f0;
    --accent-foreground: #1f1f1f;

    /* Active-Indicator/Focus in der (weiterhin dunklen) Sidebar */
    --sidebar-primary: #E2001A;
    --sidebar-ring: #E2001A;

    /* Kaiser-Neutrale (gemessen, Broschüre) – Logo-Band und Ink.
       Gelb #FFCB04 am 2026-11-05 gestrichen - keine Kaiser-Farbe, s. corporate-design.md. */
    --ks-red: #E2001A;
    --ks-grey: #D1D3D4;
    --ks-ink: #231F20;
}

/* Laufende Status in S3-Blau - Projekt „Aktiv", Phase/Aufgabe „In Bearbeitung" (Daniel Simon, 2026-11-05, ADR-002): neutrale Pillen sind bei warmer Markenfarbe
   grau (.badge-muted); „Aktiv" soll sich davon abheben, ohne rot zu wirken. Seit Paket 3/4: Abgeschlossen .badge-success,
   Wartend .badge-warning, Storniert .badge-error (Core/Enums Anzeige.Badge). Werte = .badge-primary des
   S3-Standards mit S3-Primary #0C5DA6 (Kontrast 5,60 : 1, STANDARDS 1). */
.badge-info {
    background-color: #e2ecf4;
    color: #0C5DA6;
}

/* Warme Markenfarbe - Regeln aus STANDARDS (ADR-002):
   - Löschen-Button als Kontur statt Fläche (STANDARDS 3.3), sonst zwei gleich helle rote Flächen.
   - Neutrale Kennzeichen mit .badge-muted, .badge-primary wird nicht verwendet (STANDARDS 1). */
.btn-danger {
    background-color: var(--card);
    color: #991b1b;
    border-color: var(--destructive);
}
.btn-danger:hover {
    background-color: #fee2e2;
    border-color: var(--destructive);
    color: #991b1b;
}

/* ---------- Kennzahlen oben auf einer Seite (StatCard, Paket 5/6) ----------
   Übernommen aus DS.Steuerverwaltung (app.css .kpi-grid); Kachel aus S3.FinCenter.vNext (StatCard). */
.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 0.75rem;
}

.kpi-grid > * {
    min-width: 0;
}

/* Beträge rechtsbündig mit gleich breiten Ziffern (Kosten, OP-10). */
.betrag {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Kopf über Beträgen ebenso rechtsbündig - sonst gewinnt ".data-table th" (Daniel Simon, 2026-11-05). */
.data-table th.betrag {
    text-align: right;
}

.data-table tfoot td {
    font-weight: 600;
    border-top: 2px solid var(--border);
    background: var(--background);
}

/* Papierkorb-Seite */
.pk-icon {
    color: var(--muted-foreground);
    vertical-align: -2px;
}

/* ---------- Dokumentliste mit Vorschau (Modul Dokumente OP-17, Dokumente-Tab OP-48) ----------
   Aus Pages/Dokumente.razor.css hierher verschoben, weil beide Seiten dasselbe Layout nutzen. */
/* Liste links, Vorschau rechts (OP-17). Ohne Auswahl nimmt die Liste die volle Breite. */
.dok-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
}

.dok-layout.mit-vorschau {
    grid-template-columns: minmax(0, 1fr) minmax(440px, 46%);
}

.dok-liste {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
}

/* Die Vorschau bleibt beim Scrollen der Liste stehen und füllt die sichtbare Höhe
   (Header 68px, Action-Bar, Innenabstand der Inhaltsfläche). */
.dok-vorschau {
    position: sticky;
    top: 0;
    height: calc(100vh - 68px - 4rem - 64px);
    min-height: 420px;
}

/* ---------- Schmale Bildschirme (Daniel Simon, 2026-11-05) ----------
   Unter 1100px steht die Dokumentvorschau unter der Liste; unter 700px dürfen breite Tabellen in ihrer Karte seitlich
   scrollen statt die Seite zu sprengen, Actionbar und Kopf brechen um bzw. werden knapper. Die Sidebar startet unter
   900px eingeklappt (MainLayout). */
@media (max-width: 1100px) {
    .dok-layout.mit-vorschau {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 700px) {
    .card:has(table.data-table) {
        overflow-x: auto;
    }

    .card table.data-table {
        min-width: 36rem;
    }

    .action-bar,
    .action-bar-actions,
    .action-bar-title-with-back {
        flex-wrap: wrap;
        row-gap: 0.5rem;
    }

    .header-user-name,
    .header-title {
        display: none;
    }

    .kpi-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .ks-steckbrief dt {
        padding-right: 0.6rem;
    }

    .ks-steckbrief dd {
        padding-left: 0.6rem;
        overflow-wrap: anywhere;
    }
}
