/* ═══════════════════════════════════════════════════════════════
   Toloro Desktop — Seiten-Spezifisches: Login, QA, Fotos, ETL, …
   ═══════════════════════════════════════════════════════════════ */

/* ── Login / Auth-Seiten ─────────────────────────────────────── */
.login-page {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100dvh;
    padding: 24px;
    background:
        radial-gradient(1200px 600px at 80% -10%, rgba(232, 122, 42, 0.16), transparent 60%),
        linear-gradient(160deg, var(--primary) 0%, var(--primary-hover) 100%);
}

.login-card {
    width: 100%;
    max-width: 400px;
    background: var(--bg);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: 40px 32px;
}

.login-logo {
    text-align: center;
    margin-bottom: 32px;
}

.login-logo-text {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--primary);
}

.login-logo-text .brand-accent {
    color: var(--accent);
    font-style: normal;
}

.login-logo-sub {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin-top: 4px;
}

/* ── Photo Grid ───────────────────────────────────────────── */
/* auto-FILL, nicht auto-fit (#500): auto-fit klappt leere Spuren zusammen,
   dadurch wurde ein einzelnes Foto über die volle Breite gezogen und zwei
   Fotos je über die halbe. Mit auto-fill bleiben die leeren Spuren stehen,
   die Kacheln behalten ihre Thumbnail-Größe (~220 px) — egal ob 1, 2 oder
   50 Fotos im Reiter liegen. Gilt für beide Foto-Reiter (Altsystem + Toloro),
   die sich das Fragment app2/fragments/project-photos teilen. */
.photo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 10px;
}
.photo-card {
    position: relative;
    overflow: hidden;
    cursor: pointer;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 6px;
    background: var(--bg);
}
.photo-frame {
    position: relative;
    width: 100%;
    height: 160px;
    border-radius: calc(var(--radius) - 2px);
    background: var(--bg-muted);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.photo-thumb {
    width: 100%;
    height: 160px;
    object-fit: cover;
    display: block;
    opacity: 0;
    transition: opacity 0.2s ease;
}
.photo-frame.loaded .photo-thumb {
    opacity: 1;
}
.photo-frame .photo-spinner {
    position: absolute;
    width: 22px;
    height: 22px;
    border: 3px solid var(--border);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin 0.9s linear infinite;
}
.photo-frame.loaded .photo-spinner {
    display: none;
}
.photo-name {
    margin-top: 6px;
    font-weight: 600;
    font-size: var(--text-sm);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.photo-folder {
    color: var(--text-secondary);
    font-size: 0.78rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.photo-star-btn {
    position: absolute;
    top: 10px;
    right: 10px;
    background: rgba(0,0,0,0.5);
    border: none;
    color: #FCD34D;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.15s;
}
.photo-card:hover .photo-star-btn,
.photo-card:active .photo-star-btn {
    opacity: 1;
}

/* ── Fotos anhaken und per Mail schicken (toloro#4356) ────────
   Die Kachel trägt Bildfläche (der Knopf, der die Großansicht öffnet) und
   Häkchen NEBENEINANDER: Ein Bedienelement im `role="button"` wäre
   ungültig, und sein Klick wanderte zur Kachel (UX-Leitplanke S1). Das
   Häkchen liegt in der Ecke über dem Bild, ist immer sichtbar (nicht erst
   beim Überfahren) und hat 32 px Trefferfläche. */
.photo-kachel {
    position: relative;
}
.photo-kachel--gewaehlt .photo-card {
    border-color: var(--primary);
    box-shadow: 0 0 0 1px var(--primary);
}
.photo-haken {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 1;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.92);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.3);
    cursor: pointer;
}
.photo-haken input {
    width: 18px;
    height: 18px;
    margin: 0;
    cursor: pointer;
    accent-color: var(--primary);
}

/* Die Leiste über dem Raster steht IMMER da, sobald es Mailrecht und Fotos
   gibt, und behält ihre Höhe: Erschiene sie erst mit dem ersten Häkchen,
   rutschte das Raster um ihre Höhe nach unten, und der zweite Klick träfe
   das Bild statt des Häkchens (S3). Sie klebt unter der Kopfzeile, deren
   wirkliche Höhe desktop.js misst (toloro#3463). */
.foto-leiste {
    position: sticky;
    top: var(--kopfzeile-hoehe, var(--header-height));
    z-index: 5;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 14px;
    min-height: 56px;
    margin-bottom: 12px;
    padding: 8px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}
.foto-leiste-satz {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--text-sm);
    color: var(--text-secondary);
}
.foto-leiste-summe {
    color: var(--text);
    font-weight: 600;
}
/* Über dem Deckel: Summe und Satz im Fehler-Textton `--danger-text` —
   `--danger` selbst hielte auf Weiß keine 4,5:1. Der Satz steht in DERSELBEN
   Zeile wie die Summe: eine zweite Zeile machte die Leiste höher und
   schöbe das Raster unter der Hand nach unten (S3). */
.foto-leiste--voll .foto-leiste-summe,
.foto-leiste-deckel {
    color: var(--danger-text);
}
/* Die Kachel, die den Fokus bekommt (Schließen der Großansicht, Umschalt+Tab
   nach oben), landet UNTER der klebenden Leiste und nicht hinter ihr: Die
   Kopfzeile rechnet schon scroll-padding-top im html heraus (layout.css),
   hier kommt die Leiste dazu — ihre Mindesthöhe 56 px und 12 px Luft. Nur
   unter einer Leiste; ohne Mailrecht gibt es keine. */
.foto-leiste ~ .photo-grid .photo-card {
    scroll-margin-top: 68px;
}

/* ── Desktop Grids ──────────────────────────────────────────── */
@media (min-width: 1024px) {
    /* Dashboard: Termine + Handlungsbedarf nebeneinander */
    .dashboard-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 24px;
        align-items: start;
    }

    .dashboard-grid .section {
        margin-bottom: 0;
    }

    /* Settings: Sektionen in Spalten */
    .settings-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 24px;
        align-items: start;
    }

    .settings-grid .section {
        margin-bottom: 0;
    }

    .settings-grid-full {
        grid-column: 1 / -1;
    }

    /* Due: Aktiv + Verschoben nebeneinander */
    .due-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 24px;
        align-items: start;
    }

    .due-grid .section {
        margin-bottom: 0;
    }

    /* Offers: Überfällig + Anstehend nebeneinander */
    .offers-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 24px;
        align-items: start;
    }

    .offers-grid .section {
        margin-bottom: 0;
    }
}

/* ── Planning Table ─────────────────────────────────────────── */
.planning-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}

@media (min-width: 1024px) {
    .planning-scroll {
        overflow-x: visible;
    }

    .planning-table {
        min-width: 100%;
    }
}

/* ── Floating Action Button (Camera) ────────────────────────── */
.fab-camera {
    position: fixed;
    bottom: calc(24px + var(--safe-bottom));
    right: 24px;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: var(--primary);
    color: #fff;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(21, 41, 63, 0.4);
    z-index: 90;
    transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;
    -webkit-tap-highlight-color: transparent;
}

.fab-camera:active {
    transform: scale(0.92);
}

.fab-camera:hover {
    box-shadow: 0 6px 24px rgba(21, 41, 63, 0.5);
}

.fab-camera svg {
    width: 28px;
    height: 28px;
    fill: currentColor;
}

.fab-camera.uploading {
    opacity: 0.7;
    pointer-events: none;
}

/* Spinner im FAB */
.fab-camera .fab-spinner {
    width: 28px;
    height: 28px;
    border: 3px solid rgba(255,255,255,0.3);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

/* ── Pending Uploads Section ────────────────────────────────── */
.pending-uploads {
    margin-bottom: 16px;
}

.pending-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(100px, 140px));
    gap: 8px;
    padding: 12px;
}

.pending-item {
    position: relative;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--bg-muted);
}

.pending-thumb {
    width: 100%;
    height: 90px;
    object-fit: cover;
    display: block;
}

.pending-status {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 4px 6px;
    font-size: 0.7rem;
    font-weight: 600;
    text-align: center;
}

.pending-status.status-pending {
    background: var(--warning-soft);
    color: #92400E;
}

.pending-status.status-uploading {
    background: var(--info-soft);
    color: #3730A3;
}

.pending-status.status-uploaded {
    background: var(--success-soft);
    color: #065F46;
}

.pending-status.status-failed {
    background: var(--danger-soft);
    color: #991B1B;
}

/* Endzustand „abgelehnt" (toloro#1317): kräftiger als „fehlgeschlagen",
   weil hier nichts mehr von selbst passiert — der Eintrag wartet auf
   eine Entscheidung des Bedieners, nicht auf den nächsten Versuch. */
.pending-status.status-rejected {
    background: var(--danger);
    color: #FFF;
    flex-direction: column;
    gap: 2px;
    line-height: 1.25;
}

.pending-status.status-rejected .pending-rejected-grund {
    font-weight: 500;
    word-break: break-word;
}

.pending-rejected-aktionen {
    display: flex;
    gap: 4px;
    padding: 4px 6px;
    justify-content: center;
}

.pending-rejected-aktionen button {
    font-size: 0.68rem;
    padding: 2px 6px;
}

.pending-status svg {
    width: 12px;
    height: 12px;
    fill: currentColor;
    flex-shrink: 0;
}

/* Sekundäre Zeile unter „Hochgeladen": Restdauer der lokalen
   24h-Sichtbarkeit — bewusst kleiner/leiser als das Status-Badge,
   damit sie nicht als Upload-Restzeit gelesen wird. */
.pending-uploaded-hint {
    padding: 0 6px 4px;
    font-size: 0.6rem;
    font-weight: 400;
    text-align: center;
    background: var(--success-soft);
    color: #065F46;
    opacity: 0.75;
}

/* ── QR-Scan-Button + Modal ──────────────────────────────────── */
/* Wiederverwendbares Pattern: Input + Scan-Button nebeneinander.
   Eingesetzt in Equipment-Anlegen/Bearbeiten neben Geräte-Nummer/QR. */
.qr-input-row {
    display: flex;
    align-items: stretch;
    gap: 8px;
}

.qr-input-row .qr-input-field {
    flex: 1 1 auto;
    min-width: 0; /* erlaubt flex-shrink unter intrinsische Breite */
}

.qr-input-row .qr-scan-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.qr-scanner-modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.72);
    z-index: 400;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    padding-top: calc(16px + var(--safe-top, 0px));
    padding-bottom: calc(16px + var(--safe-bottom, 0px));
}

.qr-scanner-card {
    background: var(--bg, #fff);
    color: var(--text, #111);
    border-radius: 12px;
    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.4);
    padding: 20px;
    max-width: 520px;
    width: 100%;
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    position: relative;
}

.qr-scanner-close {
    position: absolute;
    top: 8px;
    right: 12px;
    background: transparent;
    border: none;
    font-size: 28px;
    line-height: 1;
    cursor: pointer;
    color: var(--text-secondary, #666);
    padding: 4px 10px;
    min-height: 44px;
    min-width: 44px;
}

.qr-scanner-close:hover {
    color: var(--text, #111);
}

.qr-scanner-title {
    margin: 0 0 6px 0;
    font-size: 1.125rem;
    font-weight: 700;
}

.qr-scanner-hint {
    margin: 0 0 12px 0;
    font-size: 0.875rem;
    color: var(--text-secondary, #666);
}

.qr-scanner-video-wrap {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: #000;
    border-radius: 8px;
    overflow: hidden;
}

.qr-scanner-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.qr-scanner-frame {
    position: absolute;
    inset: 12% 12% 12% 12%;
    border: 3px solid rgba(34, 197, 94, 0.8);
    border-radius: 8px;
    pointer-events: none;
}

.qr-scanner-success {
    position: absolute;
    inset: 0;
    background: rgba(34, 197, 94, 0.35);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 6rem;
    font-weight: 700;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
    animation: qr-scan-flash 0.3s ease-out;
}

@keyframes qr-scan-flash {
    from { opacity: 0; transform: scale(0.6); }
    to   { opacity: 1; transform: scale(1); }
}

.qr-scanner-error {
    margin: 12px 0 0 0;
    padding: 8px 12px;
    background: rgba(220, 38, 38, 0.1);
    border-left: 3px solid #dc2626;
    color: #991b1b;
    font-size: 0.875rem;
    border-radius: 4px;
}


/* ═══════════════════════════════════════════════════════════════
   Rollen & Rechte (/desktop/admin/roles)

   Drei Ansichten in einer Seite: Rollen-Liste, Rollen-Detail (der
   einzige Ort, an dem Rechte gesetzt werden) und eine transponierte,
   nur lesende Matrix. Aufbau und Verhalten folgen dem von Christian
   abgenommenen Klickdummy „Rollen & Rechte".

   Warum eigene Bausteine: die alte Matrix (Rollen als Zeilen, Rechte
   als Spalten) scrollt schon bei zwölf Rechten nach rechts und wird
   mit jedem weiteren Recht unbedienbarer. Der Katalog wächst — nach
   unten zu wachsen kann der Browser gratis, nach rechts nicht.
   ═══════════════════════════════════════════════════════════════ */

/* ── Knopf-Varianten stehen nicht mehr hier ────────────────────
   `.btn-xs` stand hier bis 14.08.2026 ein zweites Mal (28px) und
   überschrieb wegen der späteren Ladereihenfolge die Definition in
   components.css. Die Größe gibt es jetzt nur noch dort (26px).
   `.btn-danger-ghost` ging denselben Weg (#585, 21.08.2026): eine
   global gültige Knopf-Variante gehört zu den Bausteinen, auch wenn
   sie heute nur eine Seite benutzt. */

/* ── Reiter zwischen den Ansichten ───────────────────────────── */
.view-tabs { display: flex; gap: 4px; margin-bottom: 20px; flex-wrap: wrap; }
.view-tab {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 9px 16px; border-radius: var(--radius-full);
    border: 1px solid var(--border); background: var(--bg);
    color: var(--text-secondary); font-size: var(--text-sm); font-weight: 600;
    cursor: pointer; transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.view-tab:hover { border-color: var(--border-active); color: var(--text); }
.view-tab.active { background: var(--primary); border-color: var(--primary); color: #fff; }
.view-tab svg { width: 16px; height: 16px; fill: currentColor; }

/* ── Werkzeugleiste (Suche, Filter, Sortierung) ──────────────── */
.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 16px; }
.toolbar .search { position: relative; flex: 1; min-width: 220px; }
.toolbar .search svg {
    position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
    width: 17px; height: 17px; fill: var(--text-muted); pointer-events: none;
}
.toolbar .search input { padding-left: 37px; min-height: 38px; width: 100%; }
.toolbar .search .clear {
    position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
    border: none; background: none; cursor: pointer; color: var(--text-muted);
    padding: 4px; line-height: 0; border-radius: var(--radius-full);
}
.toolbar .search .clear:hover { background: var(--bg-muted); color: var(--text); }
.toolbar .search .clear svg { position: static; transform: none; width: 15px; height: 15px; fill: currentColor; }
.toolbar .form-input.compact { min-height: 34px; padding: 4px 8px; width: auto; }

.switch {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: var(--text-sm); color: var(--text-secondary);
    cursor: pointer; user-select: none; white-space: nowrap;
}
.switch input { width: 16px; height: 16px; accent-color: var(--primary); }

/* ── Kennzahlen über der Liste ───────────────────────────────── */
.stat-row { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 18px; }
.stat-box {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius-md); padding: 12px 16px; min-width: 130px;
}
.stat-num { font-size: var(--text-xl); font-weight: 700; line-height: 1.15; }
.stat-lbl { font-size: var(--text-xs); color: var(--text-secondary); margin-top: 1px; }

/* ── Rollen-Liste ────────────────────────────────────────────── */
/* Eine Zeile je Rolle. Die Zeilenhöhe ist unabhängig von der Größe des
   Rechte-Katalogs — nur so bleibt die Liste auch bei vielen Rollen
   und Modulen überfliegbar. */
.role-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.role-table thead th {
    text-align: left; padding: 10px 14px;
    background: var(--bg-muted);
    font-size: var(--text-xs); font-weight: 700;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.role-table thead th .th-hint { display: block; font-weight: 500; font-size: 0.66rem; }
.role-table tbody td { padding: 11px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.role-table tbody tr:last-child td { border-bottom: none; }
.role-table tbody tr:hover td { background: var(--bg-subtle); }
.role-table tbody tr.is-system td:first-child { box-shadow: inset 3px 0 0 var(--primary); }

.rt-name { min-width: 220px; }
.rt-titel { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rt-label { font-weight: 700; font-size: var(--text-sm); }
.rt-titel code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.68rem; color: var(--text-muted);
    background: var(--bg-muted); padding: 1px 6px; border-radius: var(--radius-sm);
}
.rt-desc {
    font-size: var(--text-xs); color: var(--text-secondary); margin-top: 3px;
    max-width: 340px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rt-zahl { font-variant-numeric: tabular-nums; color: var(--text-secondary); width: 70px; }
.rt-umfang { width: 120px; white-space: nowrap; }
.rt-quote { font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--text-sm); }
.rt-quote-max { font-weight: 500; color: var(--text-muted); }
.rt-bar {
    display: block; height: 5px; margin-top: 4px; border-radius: 3px;
    background: var(--bg-muted); overflow: hidden;
}
.rt-bar span { display: block; height: 100%; background: var(--primary); }

/* Modul-Verteilung als Dichte-Balken statt Chip-Wolke: ein Segment je
   Modul, Farbintensität = Füllgrad. Bleibt gleich hoch, egal wie viele
   Module der Katalog hat — Segmente werden schmaler, die Zeile nicht
   höher. Text-Chips würden dagegen in beide Richtungen wachsen. */
.dens { display: flex; gap: 2px; align-items: stretch; min-width: 120px; max-width: 180px; }
.dens-seg {
    flex: 1 1 0; min-width: 3px; height: 20px; border-radius: 2px;
    background: var(--bg-muted);
    box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.04);
}
.dens-seg.teil { background: rgba(21, 41, 63, calc(0.12 + 0.62 * var(--f))); }
.dens-seg.voll { background: var(--success); }
.dens-seg.leer {
    background: repeating-linear-gradient(45deg, var(--bg-muted), var(--bg-muted) 3px, #fff 3px, #fff 6px);
}

/* Die Aktionen bleiben am rechten Rand kleben: die Zeile wird mit jeder
   weiteren Modul-Spalte breiter, und ein Löschen-Knopf, den man erst
   herscrollen muss, ist keiner. */
.rt-aktionen { text-align: right; white-space: nowrap; width: 1%; min-width: 190px; }
.role-table thead th:last-child,
.role-table tbody td.rt-aktionen {
    position: sticky; right: 0; z-index: 1;
    box-shadow: -8px 0 8px -8px rgba(15, 23, 42, 0.28);
}
.role-table thead th:last-child { background: var(--bg-muted); }
.role-table tbody td.rt-aktionen { background: var(--bg); }
.role-table tbody tr:hover td.rt-aktionen { background: var(--bg-subtle); }
.rt-aktionen .btn { margin-left: 4px; vertical-align: middle; }
.rt-aktionen .btn-icon { padding: 5px; min-height: 26px; }
.rt-aktionen .btn-icon svg { width: 15px; height: 15px; fill: currentColor; }

@media (max-width: 1250px) {
    .rt-desc { max-width: 220px; }
    .dens { min-width: 90px; }
}

/* ── Rollen-Detail: Rechte-Gruppen je Modul ──────────────────── */
.perm-group {
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--surface); margin-bottom: 10px; overflow: hidden;
}
.perm-group-head {
    display: flex; align-items: center; gap: 12px; padding: 12px 14px;
    background: var(--bg-muted); border-bottom: 1px solid transparent;
    cursor: pointer; user-select: none;
}
.perm-group.open .perm-group-head { border-bottom-color: var(--border); }
.perm-group-head:hover { background: var(--bg-subtle); }
.perm-group-caret {
    width: 16px; height: 16px; fill: var(--text-muted);
    flex-shrink: 0; transition: transform 0.15s;
}
.perm-group.open .perm-group-caret { transform: rotate(90deg); }
.perm-group-title { font-weight: 700; font-size: var(--text-sm); flex: 1; min-width: 0; }
.perm-group-count {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--text-xs); color: var(--text-secondary);
    background: var(--bg); border: 1px solid var(--border);
    padding: 2px 8px; border-radius: var(--radius-full); white-space: nowrap;
}
/* Die Gruppen-Checkbox schaltet das ganze Modul — „indeterminate" zeigt
   „teilweise gesetzt", ohne einen dritten Klick-Zustand zu erfinden. */
.perm-group-check { width: 17px; height: 17px; accent-color: var(--primary); cursor: pointer; flex-shrink: 0; }

.perm-group-body { padding: 4px 0; }
.perm-group:not(.open) .perm-group-body { display: none; }

.perm-row {
    display: flex; align-items: flex-start; gap: 11px;
    padding: 9px 14px 9px 42px; border-bottom: 1px solid var(--bg-muted);
}
.perm-row:last-child { border-bottom: none; }
.perm-row:hover { background: var(--bg-subtle); }
.perm-row input[type="checkbox"] {
    width: 17px; height: 17px; margin-top: 2px;
    accent-color: var(--primary); flex-shrink: 0; cursor: pointer;
}
.perm-row input[type="checkbox"]:disabled { cursor: not-allowed; }
.perm-row-main { display: block; flex: 1; min-width: 0; }
.perm-row-label { display: block; font-weight: 600; font-size: var(--text-sm); }
/* Die Beschreibung steht unter dem Label, nicht im Tooltip: bei feinem
   Katalog rät sonst niemand mehr, was ein Recht bewirkt. */
.perm-row-desc {
    display: block; font-size: var(--text-xs); color: var(--text-secondary);
    margin-top: 2px; line-height: 1.45;
}
/* Der Satz über einer Gruppe, deren Rechte an einem Modul hängen (toloro#3442):
   eingerückt wie die Beschriftungen der Rechte darunter, ohne Abstand nach oben. */
.perm-group-modulhinweis { margin-top: 0; padding: 6px 14px 6px 42px; }
.perm-row-key {
    display: block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.68rem; color: var(--text-muted); margin-top: 3px;
}
.perm-row.derived {
    background: repeating-linear-gradient(45deg, transparent, transparent 6px,
        rgba(148, 163, 184, 0.05) 6px, rgba(148, 163, 184, 0.05) 12px);
}
.perm-row.changed { box-shadow: inset 3px 0 0 var(--accent); }

.tag-derived {
    display: inline-block; font-size: 0.68rem; font-weight: 700;
    background: var(--bg-muted); color: var(--text-secondary);
    padding: 1px 7px; border-radius: var(--radius-full); margin-left: 6px;
    vertical-align: 1px;
}

/* Firmen-Kennzeichen an Rechten, die nur bei einer der beiden Firmen
   wirken (#611). Der Umriss unterscheidet es vom grauen tag-derived,
   die AUSSAGE steht aber im Text („nur PKS") — ein Kennzeichen, das
   sich allein über Farbe erklärt, erklärt sich für Farbfehlsichtige
   gar nicht. */
.tag-firma {
    display: inline-block; font-size: 0.68rem; font-weight: 700;
    background: transparent; color: var(--text-secondary);
    border: 1px dashed var(--border-strong, var(--border));
    padding: 0 6px; border-radius: var(--radius-full); margin-left: 6px;
    vertical-align: 1px; cursor: help;
}

/* Vorlagen je Modul — drei Klicks statt zwölf */
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.seg button {
    border: none; background: var(--bg); cursor: pointer;
    padding: 4px 11px; font-size: var(--text-xs); font-weight: 600;
    color: var(--text-secondary); border-right: 1px solid var(--border);
}
.seg button:last-child { border-right: none; }
.seg button:hover { background: var(--primary-soft); color: var(--primary); }

/* ── Mitlaufende Speicherleiste ──────────────────────────────── */
.savebar {
    position: sticky; bottom: 0; z-index: 60;
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
    border: 1px solid var(--border); border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg); padding: 12px 16px; margin-top: 16px;
}
.savebar .spacer { flex: 1; }
.diff-add { color: #065F46; font-weight: 700; font-size: var(--text-sm); }
.diff-del { color: #991B1B; font-weight: 700; font-size: var(--text-sm); }

/* ── Matrix (nur lesend, transponiert) ───────────────────────── */
.matrix-wrap {
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--surface); overflow: auto; max-height: calc(100dvh - 300px);
}
.matrix { border-collapse: separate; border-spacing: 0; width: 100%; font-size: var(--text-sm); }
.matrix th, .matrix td { border-bottom: 1px solid var(--border); }
.matrix thead th {
    position: sticky; top: 0; z-index: 3; background: var(--bg-muted);
    padding: 10px 8px; font-size: var(--text-xs); font-weight: 700;
    text-align: center; vertical-align: bottom;
    border-bottom: 2px solid var(--border-active); min-width: 92px;
}
.matrix thead th.mx-corner {
    left: 0; z-index: 4; text-align: left; min-width: 300px; width: 300px;
    border-right: 2px solid var(--border-active);
}
.matrix th.mx-role-sys { color: var(--primary); }
.matrix th .mx-role-sub {
    display: block; font-weight: 500; color: var(--text-muted);
    font-size: 0.68rem; margin-top: 2px;
}
.matrix td.mx-name {
    position: sticky; left: 0; z-index: 2; background: var(--surface);
    padding: 7px 12px 7px 26px; border-right: 2px solid var(--border-active);
    min-width: 300px; width: 300px;
}
.matrix tr:hover td { background: var(--bg-subtle); }
.mx-name-label { font-weight: 600; }
.mx-name-key {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.66rem; color: var(--text-muted); display: block; margin-top: 1px;
}
.matrix tr.mx-group td {
    position: sticky; left: 0; z-index: 2; background: var(--primary-soft);
    font-weight: 700; font-size: var(--text-xs);
    text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--primary); padding: 7px 12px;
}
.matrix tr.mx-group td.mx-group-fill { position: static; background: var(--primary-soft); }
.matrix td.mx-cell { text-align: center; padding: 7px 8px; }
.mx-yes { color: var(--success-text); font-weight: 700; }
.mx-no { color: var(--border-active); }
.mx-derived { color: var(--text-muted); font-weight: 700; }
.matrix td.mx-cell svg { width: 15px; height: 15px; display: inline-block; fill: currentColor; }
.matrix td.mx-cell.diff-a { background: var(--info-soft); }
.matrix td.mx-cell.diff-b { background: var(--accent-soft); }

.legend {
    display: flex; gap: 16px; flex-wrap: wrap; margin-top: 12px;
    font-size: var(--text-xs); color: var(--text-secondary);
}
.legend span { display: inline-flex; align-items: center; gap: 5px; }
.legend svg { width: 13px; height: 13px; fill: currentColor; }

/* ── Modal (Rolle anlegen / duplizieren / Rechte übernehmen) ─── */
.modal-backdrop {
    position: fixed; inset: 0; z-index: 500;
    background: rgba(13, 29, 47, 0.45);
    display: flex; align-items: flex-start; justify-content: center;
    padding: 24px 16px; overflow-y: auto;
    /* Der Dialog erbt NICHTS von seiner Zeile (toloro#1115). Er liegt im
       Markup in der Zelle, aus der er aufgerufen wird — und eine
       Aktionsspalte trägt üblicherweise white-space:nowrap und
       text-align:right. Beides wird vererbt: Ohne diese zwei Zeilen läuft
       ein Erklärabsatz im Dialog einzeilig aus dem Kasten heraus und die
       Beschriftungen kleben rechts. Der Fehler ist tückisch, weil die
       Felder selbst richtig aussehen. */
    white-space: normal; text-align: left;
}
.modal {
    background: var(--bg); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg); width: 100%; max-width: 680px; margin: auto 0;
    display: flex; flex-direction: column;
}
.modal-head {
    padding: 16px 20px; border-bottom: 1px solid var(--border);
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.modal-title { font-weight: 700; font-size: var(--text-lg); }
.modal-body { padding: 20px; }
.modal-foot {
    padding: 14px 20px; border-top: 1px solid var(--border);
    display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap;
    background: var(--bg-subtle); border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.modal-close {
    background: none; border: none; cursor: pointer; color: var(--text-muted);
    padding: 6px; line-height: 0; border-radius: var(--radius-sm);
}
.modal-close:hover { background: var(--bg-muted); color: var(--text); }
.modal-close svg { width: 20px; height: 20px; fill: currentColor; }

.role-pick { display: flex; flex-direction: column; gap: 6px; max-height: 44vh; overflow-y: auto; }
.role-pick label {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 9px 12px; border: 1px solid var(--border);
    border-radius: var(--radius-sm); cursor: pointer; font-size: var(--text-sm);
}
.role-pick label:hover { border-color: var(--border-active); background: var(--bg-subtle); }
.role-pick input { margin-top: 3px; accent-color: var(--primary); }
.role-pick .rp-sub { display: block; font-size: var(--text-xs); color: var(--text-secondary); margin-top: 2px; }

.note-box {
    background: var(--bg-subtle); border: 1px solid var(--border);
    border-left: 3px solid var(--info); border-radius: var(--radius-sm);
    padding: 10px 13px; font-size: var(--text-sm); color: var(--text-secondary);
}
.note-box strong { color: var(--text); }

/* ── Das Briefsymbol hinter einer Mailadresse (toloro#3923) ───────────
   Der Partner des Hörers in der Beteiligten-Liste (`fragments/beteiligte
   .html`, toloro#2152) und in der Empfänger-Matrix darunter
   (`fragments/empfaenger.html`, #2202): dieselbe Größe und dieselbe
   Hausfarbe, damit beide als ein Paar gelesen werden und auf der Zeile
   nur EIN Orange steht. Bis #3923 trug das Symbol ein fest notiertes
   Orange im Markup — die zweite Stufe, die #3500 am Hörer abgebaut hatte.

   Die Klasse sitzt am <svg>, nicht am Verweis: Der Verweis behält seine
   Seitenklasse (`bet-brief`/`emp-brief`) für das, was nur seine Zeile
   braucht — `display` fürs `x-show` (Alpine, #948), Polster und
   Hover-Fläche der Matrix. Farbe in `color` und das Symbol in
   `currentColor`, genau wie `.hoerer svg` (components.css). */
.briefsymbol {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    vertical-align: middle;
    color: var(--accent-text);
    fill: currentColor;
}

/* ── Anrufliste als Tabelle (toloro#3499, eine Zeile je Anruf seit #4507) ─
   Muster der Lead-Tabelle (#3420/#3496): `table-layout: fixed`, die
   Breiten stehen an den Köpfen, Datenzellen brechen nicht um, sondern
   kürzen mit Auslassungspunkten — der volle Text steht im `title`. Fest
   sind Zeit, Richtung, Wer, Leitung und „Bei uns"; „Projekt" nimmt den
   Rest. Drei Stufen: unter 1440 px werden „Wer", „Leitung" und „Bei uns"
   schmaler, damit die Karte bei 1280 px mit klassischer Bildlaufleiste
   nicht schiebt; ab 1700 px bekommt „Wer" mehr, damit lange Namen neben
   der Nummer ganz stehen (Probe anruftabelle-breiten.test.js). Schmaler
   als die Mindestbreite schiebt die Karte waagerecht, statt die Spalten
   zu zerquetschen.

   EINE ZEILE JE ANRUF (toloro#4507): Bis dahin hing unter jedem Anruf mit
   Bezug eine Projektzeile mit bis zu fünf Chips; im Schnitt brauchte ein
   Anruf 68 px, zwölf standen auf einem Bildschirm. Jetzt steht genau ein
   Projekt in der Spalte „Projekt", die übrigen im Menü „+n". */
.app2-content:has(.anruftabelle) {
    max-width: none;
}

.anrufliste-kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.anrufliste-kopf h1 {
    margin: 0;
}

/* Die Leiste: Reiter, Suche, Leitung in einer Zeile (FI03). */
.anrufliste-leiste {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.anrufliste-leiste .pill-tabs {
    margin: 0;
}

.anrufliste-suche {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 1;
    min-width: 280px;
}

.anrufliste-suchfeld {
    position: relative;
    flex: 1;
}

.anrufliste-suchfeld svg {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    fill: var(--text-muted);
    pointer-events: none;
}

.anrufliste-suchfeld .form-input {
    padding-left: 40px;
}

.anrufliste-leitung {
    width: auto;
    flex: none;
}

/* Waagerecht schieben, wo die Tabelle nicht ins Fenster passt (1024 bis
   1279 px: die Seitenleiste steht, das Fenster ist schmal). */
.anruftabelle-karte {
    overflow-x: auto;
}

.anruftabelle {
    table-layout: fixed;
    /* Feste Spalten (873 px) plus „Projekt" ≥ 220 px — so breit, wie bei
       1440 px mit klassischer Bildlaufleiste Platz ist (1093 px, dieselbe
       Grenze wie Mandanten-, Benutzer- und Lead-Tabelle). */
    min-width: 1093px;
    /* Die Vorlesetexte (`.sr-only`, absolut gesetzt) beziehen sich auf die
       Tabelle und damit auf die schiebende Karte — sonst auf die Seite, die
       sie unsichtbar verbreitern könnten (QA zu toloro#3496). */
    position: relative;
}

.anruftabelle th,
.anruftabelle td {
    padding: 8px;
}

.anruftabelle .anruf-daten td {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Nach „Zuordnen" führt der Rückweg auf die Zeile (`#zeile-<n>`, K6) —
   sie landet unter Kopfzeile und klebendem Spaltenkopf, nicht dahinter. */
.anruftabelle .anruf-daten {
    scroll-margin-top: calc(var(--kopfzeile-hoehe, var(--header-height)) + 48px);
}

/* Die Spalte „Dauer" (toloro#3693) gibt es nur, wenn ein Anruf der Seite
   eine Dauer trägt; ihre 68 px kommen aus Zeit, Richtung, Leitung und
   „Bei uns", die dafür auf ihren breitesten Inhalt gehen — ohne Dauer
   bekommt „Projekt" den Platz. Rechtsbündig, Ziffern fluchtend, grau wie die
   Zeit: Die Dauer ist ein Nachweis je Anruf, keine Kennzahl. */
.anruftabelle .at-zeit     { width: 122px; font-variant-numeric: tabular-nums; }
.anruftabelle .at-richtung { width: 116px; }
.anruftabelle .at-wer      { width: 280px; }
.anruftabelle .at-projekt  { width: auto; }
.anruftabelle .at-leitung  { width: 126px; }
.anruftabelle .at-annahme  { width: 161px; }
.anruftabelle .at-dauer    { width: 68px; }

.anruftabelle td.at-dauer,
.anruftabelle th.at-dauer {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.anruftabelle td.at-dauer {
    color: var(--text-secondary);
}

.anruftabelle .at-wartezeit {
    margin-left: 4px;
    font-variant-numeric: tabular-nums;
}

/* Schmale Stufe unter 1440 px: Feste Spalten 792 px + „Projekt" 132 =
   924 px, nutzbar bei 1280 px mit klassischer Bildlaufleiste: 933 px.
   „Zeit" und „Bei uns" sind so schmal wie ihr breitester Inhalt
   („15.12.25 09:10", „Alexa Admin (NST 21)") — was sie hergeben, bekommt
   der Projekt-Chip (QA zu toloro#4507, U1).
   „Wer" fasst die längste unbekannte Nummer samt Hörer und „Zuordnen"
   (142 + 6 + 19 + 6 + 75 px plus Innenabstand).
   Die Zeichengrenzen der Tabulator-Stopps (Anruflistenansicht) richten
   sich nach dieser Stufe. */
@media (max-width: 1439px) {
    .anruftabelle {
        min-width: 924px;
    }

    .anruftabelle .at-zeit {
        width: 122px;
    }

    .anruftabelle .at-wer {
        width: 264px;
    }

    .anruftabelle .at-leitung {
        width: 130px;
    }

    .anruftabelle .at-annahme {
        width: 156px;
    }

    /* Unter 1440 px ist für „Dauer" kein Platz, ohne dass die Karte schiebt
       oder ein fester Wert abschneidet: Jede Spalte steht dort schon auf
       ihrem breitesten Inhalt. Die Dauer steht dann im Hinweis der Zeit. */
    .anruftabelle .at-dauer {
        display: none;
    }
}

/* Unter 1700 px fällt neben einem bekannten Namen die Nummer weg — sonst
   blieben dem Namen bei 1280 px fünf Zeichen, bei 1440 px dreizehn. Sie
   steht im Hinweis am Namen und am Hörer; Kontaktdaten gehören ohnehin in
   die Akte, nicht in die Zeile (Hausregel Listen). Ohne Namen bleibt die
   Nummer stehen, sie ist dann das „Wer". */
@media (max-width: 1699px) {
    .anruftabelle .at-nummer--neben {
        display: none;
    }
}

/* Breite Stufe ab 1700 px: Platz ist da, „Wer" nimmt ihn — der Name soll
   neben der Nummer ganz stehen. Die Mindestbreite wächst mit (feste
   Spalten 993 px + „Projekt" 220). */
@media (min-width: 1700px) {
    .anruftabelle {
        min-width: 1213px;
    }

    .anruftabelle .at-wer {
        width: 400px;
    }
}

/* DER SPALTENKOPF KLEBT (toloro#4507): 50 Anrufe sind mehrere
   Bildschirmhöhen. Er klebt am Seitenbildlauf unter der Kopfzeile — das
   geht nur, wenn die Karte selbst kein Bildlauf-Kasten ist. Deshalb erst
   ab 1280 px, wo die Tabelle neben der Seitenleiste ganz ins Fenster
   passt, `overflow: clip` statt `auto`: schneidet die runden Ecken weiter,
   macht aber keinen Kasten auf, an dem `sticky` hinge. Schmaler (auch ein
   halbes 1920er-Fenster) schiebt die Karte und der Kopf steht oben in ihr. */
@media (min-width: 1280px) {
    .anruftabelle-karte {
        overflow-x: clip;
        overflow-y: visible;
    }

    .anruftabelle thead th {
        position: sticky;
        top: var(--kopfzeile-hoehe, var(--header-height));
        z-index: 3;
        background: var(--bg);
        box-shadow: inset 0 -1px 0 var(--border);
    }

    /* Das offene Agenten-Panel nimmt rechts 420 px (agent-chat.css) — dann
       passt die Tabelle nicht mehr, und die Karte schiebt wieder, statt
       „Bei uns" abzuschneiden. */
    body.agent-panel-offen .anruftabelle-karte {
        overflow-x: auto;
    }
}

/* Richtung: Symbol UND Wort (V325/#457) — nie über die Farbe allein. Das
   Rot sagt „verpasst" nur zusätzlich; als Wort steht es in „Bei uns". */
.anruftabelle .at-symbol {
    display: inline-flex;
    vertical-align: middle;
    margin-right: 6px;
    color: var(--primary);
}

.anruftabelle .at-symbol svg {
    width: 16px;
    height: 16px;
    fill: currentColor;
}

.anruftabelle .at-symbol--ausgehend { color: var(--text-secondary); }
.anruftabelle .at-symbol--verpasst  { color: var(--danger-text); }

.anruftabelle .at-richtung-wort {
    font-weight: 600;
}

/* Wer: der Name kürzt, Nummer, Hörer und „Zuordnen" nie. */
.anruftabelle .at-wer-zeile {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.anruftabelle .at-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text);
    font-weight: 600;
    text-decoration: none;
}

.anruftabelle a.at-name:hover {
    color: var(--primary);
    text-decoration: underline;
}

.anruftabelle .at-nummer {
    flex: none;
    white-space: nowrap;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Neben einem Namen ist die Nummer Beiwerk: gedämpft und nicht fett. */
.anruftabelle .at-nummer--neben {
    font-weight: 400;
    color: var(--text-secondary);
}

.anruftabelle .at-wer-zeile .hoerer,
.anruftabelle .at-zuordnen {
    flex: none;
}

/* Projekt: ein Chip, der kürzt, und „+n" daneben, das nie kürzt. */
.anruftabelle .at-projekt-zeile {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.anruftabelle .at-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    max-width: 100%;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    background: var(--bg-muted);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 2px 10px;
    text-decoration: none;
    transition: background .12s ease, border-color .12s ease, color .12s ease;
}

.anruftabelle .at-chip:hover {
    background: var(--primary-soft);
    border-color: var(--primary);
    color: var(--primary);
}

.anruftabelle .at-chip svg {
    width: 13px;
    height: 13px;
    fill: currentColor;
    flex-shrink: 0;
    opacity: .65;
}

.anruftabelle .at-chip span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Die Projektnummer ist das Aktenzeichen — sie kürzt nie, nur der Name
   dahinter (QA zu toloro#4507, U1: von 1000 bis 1439 px stand sonst nur
   „S2…" da). */
.anruftabelle .at-chip .at-chip-nr {
    flex: none;
    overflow: visible;
}

.anruftabelle .at-chip .at-chip-name {
    min-width: 0;
}

/* Der bezeugte Vorgang ist eine Feststellung, keine Vermutung (#457
   Stufe 2) — er hebt sich von einem abgeleiteten Projekt ab, am Rand und
   am Wort „Aus:", nicht nur an der Farbe. */
.anruftabelle .at-chip--vorgang {
    background: var(--primary-soft);
    border-color: var(--primary);
    color: var(--primary);
    font-weight: 600;
}

.anruftabelle .at-chip--vorgang svg {
    opacity: 1;
}

.anruftabelle .at-mehr,
.anruftabelle .at-mehr-knopf {
    flex: none;
}

/* Die Einträge sind Projektnamen und brechen nicht um; die Breite kommt
   aus dem längsten, die Höhe ist gedeckelt. */
.at-mehr-liste {
    min-width: 260px;
    max-width: 480px;
    max-height: 340px;
    overflow-y: auto;
    white-space: nowrap;
    text-align: left;
}

.at-mehr-liste a {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Per Tastatur (QA-Lehre aus toloro#3496): Ein `title` erscheint nur unter
   der Maus. Was in einer Zelle gekürzt stehen KANN (`.at-voll` — Name,
   Leitung, Bei uns), ist ein Tabulator-Stopp (ein Link von selbst, sonst
   `tabindex="0"`, das der View-Helfer nur bei langem Text setzt) und zeigt
   im Fokus den vollen Text: Die Zelle lässt ihn heraus, das Element liegt
   über den Nachbarzellen. Nur bei `:focus-visible` (Tastatur) —
   `:focus-within` griffe auch beim Mausklick. Den Fokusring bringt die
   zentrale Regel in components.css. */
.anruftabelle .anruf-daten td:has(.at-voll:focus-visible) {
    overflow: visible;
}

.anruftabelle .at-voll:focus-visible {
    position: relative;
    z-index: 2;
    overflow: visible;
    max-width: none;
    flex-shrink: 0;
    box-shadow: var(--shadow-md);
}

.anruftabelle .at-voll:not(.badge):focus-visible {
    padding-right: 6px;
    background: var(--bg);
}

/* Ein Chip kürzt — im Fokus steht er ganz. */
.anruftabelle .at-chip:focus-visible {
    max-width: none;
}

/* Leitung: Das Abzeichen kürzt wie eine Zelle — `.badge` ist sonst ein
   Flex-Kasten, und der kennt keine Auslassungspunkte. */
.anruftabelle .at-leitung .badge {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

/* Der Dialog „Nummer zuordnen" (toloro#4507). */
.anrufliste-zuordnen {
    max-width: 560px;
}

.anrufliste-zuordnen-treffer {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 12px;
    max-height: 44vh;
    overflow-y: auto;
}

.anrufliste-zuordnen-zeile {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 9px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: var(--text-sm);
}

.anrufliste-zuordnen-zeile:hover,
.anrufliste-zuordnen-zeile:has(input:checked) {
    border-color: var(--border-active);
    background: var(--bg-subtle);
}

.anrufliste-zuordnen-zeile input {
    accent-color: var(--primary);
}

/* ── Aktivitäten-Zeitleiste (#432) ────────────────────────────────────
   Dichte Zeilen statt großzügiger Karten: eine Zeile je Eintrag,
   Zeitpunkt · Art · Vorgang · Wer in festen Spalten. Der Text läuft
   einzeilig mit Ellipsis und klappt auf Klick vollständig auf — lange
   Audit-Texte (Feld alt→neu, #354) bleiben so erreichbar, ohne die
   Fläche zu beherrschen. PC-first, ausgelegt auf 1000 px Inhaltsbreite.
   Geteilt von app2/fragments/project-activities.html. */
/* Die Art-Spalte war 150 px breit und schnitt damit fast jede längere
   Aufschrift ab — „Aufgabe a…", „Sachstands-N…", „Empfängerregel geänd…"
   (Befund toloro#2802).

   212 px statt der im Entwurf gezeichneten 204: Nachgemessen im Browser
   gegen diese Blätter braucht ausgerechnet der Beispieltext des Befunds,
   „Sachstands-Nachfassung gestartet", 209 px — bei 204 hätte die Spalte
   ihn um fünf Pixel verfehlt, und die Änderung hätte genau das nicht
   geheilt, wofür sie da ist. Gemessen bei 1440 px Fensterbreite, also
   1072 px Inhalt (1440 − 264 Seitenleiste − 2×32 Rand − 2×20 Karte); die
   Zeile steht dann auf 118/212/528/132/18 px und läuft nicht über.

   Die längsten Aufschriften des Katalogs (bis „Aufgabe aus einem anderen
   Projekt übernommen", 283 px) tragen weiter drei Punkte — sie ganz
   unterzubringen kostete die Vorgangs-Spalte mehr, als es der Randfall
   wert ist, und der volle Text steht im title.

   Die Altsystem-Akte trägt in derselben Spalte ein Abzeichen mehr (die
   Herkunft) und wächst um denselben Betrag mit. */
/* Die Zeitspalte trägt seit toloro#2802 zwei Formen: „17.09.2026, 10:12"
   in einer gewöhnlichen Zeile und „17.09.2026, 09:32–11:02" in der grauen
   Sammelzeile darüber. Die zweite braucht gemessen 149 px (headless
   Chromium, 1440 px, Inter 12 px, tabular-nums) — bei den früheren 118 px
   riss sie ab. Die Spalte gilt für BEIDE Zeilenarten gleich; alles andere
   nähme der Liste ihre Flucht. */
.activity-list {
    --activity-zeit: 152px; --activity-art: 212px;
    display: flex; flex-direction: column;
}
.activity-list-herkunft { --activity-art: 280px; }

.activity-head,
.activity-row {
    display: grid;
    grid-template-columns: var(--activity-zeit, 152px) var(--activity-art, 150px) minmax(0, 1fr) 132px 18px;
    gap: 10px;
    align-items: baseline;
    padding: 5px 12px;
}
.activity-head {
    padding-top: 8px; padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
    font-size: var(--text-xs); font-weight: 600;
    letter-spacing: 0.04em; text-transform: uppercase;
    color: var(--text-muted);
}
.activity-row { font-size: var(--text-sm); }
.activity-row + .activity-row { border-top: 1px solid var(--border); }
.activity-row:hover { background: var(--bg-subtle); }
/* Die gedämpfte Protokoll-Zeile (toloro#2802, Politur-Runde 18.09.2026).
   Ein EINZELNER Protokoll-Eintrag bekommt keine graue Sammelzeile — die
   kostete denselben Platz und sagte weniger, weil sein Text durch den
   Namen der Ereignisart ersetzt würde. Er steht deshalb in seinem eigenen
   Wortlaut da, nur leiser: derselbe Grauton wie die Sammelzeile, knapper
   gepolstert. Dieselbe Marke tragen in der Ansicht „Alles" auch die
   Zeilen aus einem Lauf — dort ist „das ist Protokoll" dieselbe Aussage. */
.activity-row.activity-row--protokoll {
    background: var(--bg-subtle); color: var(--text-secondary);
    padding-top: 4px; padding-bottom: 4px;
}
.activity-row--protokoll:hover { background: var(--bg-muted); color: var(--text); }
/* Eine Zeile AUS einem Lauf rückt ein — aber nur in „Wichtiges": Dort
   steht die graue Zeile darüber, und der Einzug sagt, wozu die Zeile
   gehört. In „Alles" gibt es keine graue Zeile, und ein Einzug ohne
   sichtbaren Bezug behauptete eine Zugehörigkeit, die man nicht sieht
   (gemessen in der Sichtprobe zur Politur-Runde). Welche Ansicht gilt,
   hängt der Baustein als Klasse an die Liste. */
.activity-list:not(.is-alles) .activity-row.activity-row--imlauf {
    padding-left: 26px;
}

/* ── Die Leiste über der Liste (toloro#2802) ───────────────────────
   Links der Umschalter „Wichtiges | Alles", rechts die Suche. Sie
   sitzt IN der Liste und nicht im Kartenkopf: Sie gehört zu dieser
   Liste, und im Kopf stünde sie neben Knöpfen, die etwas anlegen. */
.aktivitaeten-leiste {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    padding: 8px 12px; border-bottom: 1px solid var(--border);
}
/* Zwei Knöpfe als ein Segment — die Wahl zwischen zwei Zuschnitten
   derselben Liste, nicht zwei Ziele. */
.aktivitaeten-umschalter {
    display: inline-flex; border: 1px solid var(--border);
    border-radius: 6px; overflow: hidden;
}
.aktivitaeten-schalter {
    display: inline-flex; align-items: center; gap: 6px;
    background: var(--bg); border: none; cursor: pointer;
    padding: 5px 12px; font-size: var(--text-sm); color: var(--text-secondary);
}
.aktivitaeten-schalter + .aktivitaeten-schalter { border-left: 1px solid var(--border); }
.aktivitaeten-schalter:hover { background: var(--bg-subtle); }
.aktivitaeten-schalter.is-aktiv {
    background: var(--primary-soft); color: var(--primary); font-weight: 600;
}
/* Die Zahl am Schalter zählt EINTRÄGE, nicht Zeilen — sie steht
   deshalb ruhig daneben und nicht als farbiges Abzeichen. */
.aktivitaeten-zahl { font-variant-numeric: tabular-nums; opacity: .8; }
.aktivitaeten-suche { margin-left: auto; max-width: 320px; flex: 1 1 200px; }
/* Der Satz, was eingeklappt ist. Er ist kein Warnhinweis — er erklärt
   eine Anzeige-Entscheidung, also die ruhige Fläche der Liste. */
.aktivitaeten-hinweis {
    padding: 6px 12px; border-bottom: 1px solid var(--border);
    font-size: var(--text-xs); color: var(--text-secondary);
}

/* ── Die Kurzlage über der Zeitleiste (toloro#2940) ────────────────
   Vier Fragen links, die Antworten rechts nebeneinander — der Kasten
   muss beim Kundenanruf ohne Scrollen dastehen. Jede Antwort ist ein
   eigener kleiner Baustein (Etikett · Text · Zusatz), damit der Blick
   an der Angabe hängen bleibt und nicht an einem Fließtext. Was hakt,
   steht rot — nur das, sonst wäre Rot keine Aussage mehr. */
.kurzlage {
    padding: 10px 12px; border-bottom: 1px solid var(--border);
    background: var(--bg-subtle);
}
.kurzlage-titel {
    margin: 0 0 6px; font-size: var(--text-xs); font-weight: 600;
    text-transform: uppercase; letter-spacing: .04em; color: var(--text-secondary);
}
.kurzlage-fragen {
    display: grid; grid-template-columns: minmax(150px, 210px) minmax(0, 1fr);
    gap: 6px 12px; margin: 0; align-items: baseline;
}
.kurzlage-frage {
    font-size: var(--text-sm); font-weight: 600; color: var(--text);
}
.kurzlage-antworten {
    display: flex; flex-wrap: wrap; gap: 4px 8px; margin: 0; min-width: 0;
}
.kurzlage-leer { font-size: var(--text-sm); color: var(--text-secondary); }
.kurzlage-zeile {
    display: inline-flex; align-items: baseline; gap: 6px; max-width: 100%;
    padding: 2px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--bg); font-size: var(--text-sm); color: var(--text);
    text-decoration: none;
}
.kurzlage-zeile--link:hover { border-color: var(--primary); background: var(--primary-soft); }
.kurzlage-zeile--link .kurzlage-text { color: var(--primary); }
.kurzlage-zeile--warnung { border-color: var(--danger); background: var(--danger-soft); }
.kurzlage-zeile--warnung .kurzlage-etikett,
.kurzlage-zeile--link.kurzlage-zeile--warnung .kurzlage-text { color: var(--danger-text); }
.kurzlage-etikett {
    font-size: var(--text-xs); color: var(--text-secondary); white-space: nowrap;
}
.kurzlage-text {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kurzlage-zusatz {
    font-size: var(--text-xs); color: var(--text-secondary); white-space: nowrap;
}
@media (max-width: 720px) {
    .kurzlage-fragen { grid-template-columns: minmax(0, 1fr); }
}

/* ── Die schmale graue Zeile über einem Protokoll-Lauf ─────────────
   Dieselben fünf Spalten wie eine gewöhnliche Zeile, damit Zeitpunkt,
   Art, Vorgang und Wer untereinander stehen bleiben — eine eigene
   Aufteilung machte aus der Liste zwei Listen. Grau und ohne
   Abzeichen: Sie ist die leise Fassung, nicht eine weitere Sorte
   Ereignis. */
.activity-protokollzeile {
    display: grid;
    grid-template-columns: var(--activity-zeit, 152px) var(--activity-art, 150px) minmax(0, 1fr) 132px 18px;
    gap: 10px; align-items: baseline;
    padding: 4px 12px; cursor: pointer;
    background: var(--bg-subtle);
    font-size: var(--text-xs); color: var(--text-secondary);
}
.activity-protokollzeile:hover { background: var(--bg-muted); color: var(--text); }
.activity-row + .activity-protokollzeile,
.activity-protokollzeile + .activity-row,
.activity-protokollzeile + .activity-protokollzeile { border-top: 1px solid var(--border); }
/* Den Tagestrennstrich trägt sie ebenfalls, wenn die erste Zeile ihres
   Laufs ihn hat: In „Wichtiges" ist die ausgeblendet, und der Strich
   stünde sonst im Unsichtbaren. Die Regel dazu steht am Ende dieses
   Blocks — sie braucht mehr Gewicht als die Nachbar-Regeln darüber. */
.activity-protokoll-zeit { white-space: nowrap; font-variant-numeric: tabular-nums; }
.activity-protokoll-zahl { font-weight: 600; white-space: nowrap; }
.activity-protokoll-arten,
.activity-protokoll-akteur {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.activity-protokoll-pfeil { line-height: 0; align-self: center; }
.activity-protokoll-pfeil svg {
    width: 16px; height: 16px; fill: currentColor; transition: transform 0.15s;
}
.activity-protokollzeile.is-auf { background: var(--bg-muted); color: var(--text); }
.activity-protokollzeile.is-auf .activity-protokoll-pfeil svg { transform: rotate(180deg); }

/* ── Der Tagestrennstrich, ganz zuletzt und mit drei Klassen Gewicht ──
   (toloro#2802, Vorgabe Matthias 18.09.2026: KEINE Tagesüberschrift —
   Datum und Uhrzeit bleiben in jeder Zeile, der Wechsel ist ein dicker
   Strich. Welche Zeile ihn trägt, entscheidet der Server, nicht dieses
   Blatt und nicht die Vorlage.)

   Er muss JEDE Zeilentrennung darüber stechen, und davon gibt es
   inzwischen vier — `.activity-row + .activity-row` und die drei
   Nachbar-Regeln der grauen Zeile, alle mit zwei Klassen Gewicht. Eine
   Fassung mit ebenfalls zwei Klassen hing damit an der Reihenfolge im
   Blatt, und genau so ist der Strich in der Politur-Runde still
   verschwunden: In „Alles" trägt die unsichtbare graue Zeile davor die
   Kante an ihren Nachbarn weiter, und `.activity-protokollzeile +
   .activity-row` stand später. Drei Klassen entscheiden das unabhängig
   von der Zeile, in der sie stehen. */
.activity-list .activity-row.activity-row--tageswechsel,
.activity-list .activity-protokollzeile.activity-protokollzeile--tageswechsel {
    border-top: 3px solid var(--text-secondary);
}

/* ── Termine an ihrem Tag (toloro#4535) ─────────────────────────────
   Ein Termin aus der Einsatzplanung ist eine Zeile wie jede andere, nur
   in einer Farbe abgesetzt — EINE Farbe für alle Termine, kein Status
   (Matthias, 20.10.2026: ob ein Termin stattgefunden hat, pflegt niemand).
   Zwei Klassen Gewicht, damit `.activity-row:hover` die Fläche nicht
   überschreibt. Die Schrift nimmt das -text-Token (Kontrast 7,9:1). */
.activity-row.activity-row--termin { background: var(--info-soft); }
.activity-row.activity-row--termin:hover { background: var(--info-soft); filter: brightness(.97); }
.activity-row--termin .activity-text { color: var(--info-text); }
.activity-row--termin .activity-actor-name { font-style: italic; }
/* Das Terminart-Abzeichen in der Art-Spalte: `.activity-kind .badge`
   stellt Abzeichen dort auf inline-block (Ellipsis) — der Farbpunkt
   braucht aber die Flex-Zeile seines Abzeichens. Drei Klassen Gewicht:
   Mit zwei stünde die Regel gleichauf mit `.activity-kind .badge`, die
   weiter unten im Blatt steht und damit gewänne — der leere Punkt wäre
   ein Inline-Element ohne Breite, also unsichtbar (Gegenprüfung #4535). */
.activity-kind .badge.activity-terminart { display: inline-flex; }
/* Der „heute"-Strich unter dem letzten künftigen Termin: gestrichelt und
   leise. Unter ihm steht meist der dicke Tagesstrich der ersten
   vergangenen Zeile — gewollt: Der Tag wechselt dort ja. */
.activity-heute {
    display: flex; align-items: center; gap: 10px;
    padding: 2px 12px;
    font-size: var(--text-xs); color: var(--text-muted);
    border-top: 1px solid var(--border);
}
.activity-heute::before { content: ""; flex: 0 0 140px; border-top: 2px dashed var(--border); }
.activity-heute::after  { content: ""; flex: 1; border-top: 2px dashed var(--border); }
.activity-heute span { white-space: nowrap; }

.activity-time {
    font-size: var(--text-xs); color: var(--text-secondary);
    white-space: nowrap; font-variant-numeric: tabular-nums;
}
.activity-kind { display: flex; gap: 4px; min-width: 0; }
.activity-kind .badge {
    display: inline-block; max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Das Zeichen vor dem Typnamen (#498). Eigener Abstand statt des
   Badge-`gap`, weil die Abzeichen hier auf inline-block umgestellt sind
   (Ellipsis) und `gap` dort nicht greift. */
.activity-typ-zeichen { margin-right: 4px; }
.activity-main { display: flex; gap: 6px; min-width: 0; align-items: baseline; }
/* Die Abzeichen schrumpfen mit (toloro#2802, zweite Gegenprüfung). Sie
   standen auf `flex-shrink: 0`, und bei 1280 px Fensterbreite ging deshalb
   der Vorgangstext auf 0 px, während der Stift über die Spalte „Wer"
   rutschte. Jetzt teilen sich Abzeichen und Text den Engpass; die Ellipsis
   am Bezug (unten) fängt den Rest ab. */
.activity-flags { display: flex; gap: 4px; min-width: 0; overflow: hidden; }
/* Fällt jedes Abzeichen weg, lässt Thymeleaf den Leerraum zwischen den
   Tags stehen — der Kasten ist dann leer, aber nicht :empty. Gefragt ist
   also nach echten Kindern, sonst bliebe vor jedem Text ohne Abzeichen
   eine Lücke. */
.activity-flags:not(:has(*)) { display: none; }
/* Die Abzeichen mit eigener Aussage — Dringlichkeit, Kundensichtbar,
   bearbeitet, Frist — am Ende der Vorgangsspalte, vor dem Stift (QA zu
   toloro#4490): So beginnt jeder Satz an derselben Kante. Sie teilen sich
   den Engpass wie die Abzeichen vor dem Satz (gleiche Regel oben); der
   linke Rand `auto` hält sie rechts, auch wenn ein kurzer Satz die Zeile
   nicht füllt (`.activity-text` wächst nur, wo er Platz bekommt). */
.activity-flags--ende { margin-left: auto; }
/* Der Gegenstand der Zeile als Sprung-Link (#1308) — „Angebot A-26-1",
   „Rechnung stellen". Er sieht aus wie ein Abzeichen und verhält sich wie
   ein Link: die Farbe der Anwendung, damit man ihn zwischen den stummen
   Abzeichen als anklickbar erkennt, ohne dass die Zeile bunt wird. */
/* `min-width: 0` ausgeschrieben (toloro#2879). Wirksam ist hier schon das
   `overflow: hidden` in derselben Regel — ein Flex-Kind mit eigenem
   Überlauf hat bereits die selbsttätige Mindestbreite 0 (CSS Flexbox
   §4.5), dieses Abzeichen kürzte also immer schon. Die Null steht
   trotzdem da, weil das Blatt sie an jeder kürzenden Zelle ausschreibt
   (`.activity-kind`, `.activity-actor`, `.activity-protokoll-arten`) und
   weil sie gebraucht wird, sobald jemand den Überlauf hier wegnimmt.
   Warum es bei der Terminart darunter NICHT reichte, steht dort. */
.activity-bezug {
    background: var(--primary-soft); color: var(--primary);
    text-decoration: none; max-width: 260px; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.activity-bezug:hover { text-decoration: underline; }
/* Die Terminart am Termin-Eintrag (#1357). Sie ist ein stummes Abzeichen
   neben dem Sprung-Link — die Farbe steckt im Punkt, nicht im Kasten:
   Ein flächig eingefärbtes Etikett je Terminart machte die Zeitleiste
   bunt und stritte mit dem Sprung-Link um die Aufmerksamkeit. Der Punkt
   trägt dieselbe Farbe wie die Kachel im Einsatzplan und ist genau so
   groß, dass man ihn beim Überfliegen wiedererkennt. */
/* `min-width: 0` (toloro#2879): Die selbsttätige Mindestbreite eines
   Flex-Kindes ist seine min-content-Breite — bei `white-space: nowrap`
   also der VOLLE Wortlaut. Das gilt aber nur, solange das Kind SELBST
   `overflow: visible` hat; mit eigenem Überlauf ist die Mindestbreite
   schon 0 (CSS Flexbox §4.5). Genau daran hing der Unterschied: Dieses
   Abzeichen trägt selbst kein `overflow` — nur der Name darin tut das.
   Es konnte deshalb nicht schrumpfen, ragte aus `.activity-flags` heraus
   und wurde von dessen `overflow: hidden` glatt abgeschnitten, statt mit
   „…" zu enden. HIER ist die Null also die einzige Tür; am Namen
   darunter und am Bezug darüber steht sie nur ausgeschrieben. */
.activity-terminart {
    display: inline-flex; align-items: center; gap: 5px;
    background: var(--bg-muted); color: var(--text-secondary);
    max-width: 200px; min-width: 0; white-space: nowrap;
}
.activity-terminart-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Der Innenschatten hält auch eine sehr helle Terminart-Farbe sichtbar —
   ohne ihn verschwände ein fast weißer Punkt auf hellem Grund. */
.activity-terminart-punkt {
    width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
}
/* Der Satz behält einen Mindestanteil (toloro#2879). Er war der einzige
   Posten des Vorgangs-Feldes, der wirklich schrumpfte — und er schrumpfte
   als erster auf null: `flex: 1` heißt Grundmaß 0, und beim Verteilen
   eines Fehlbetrags wiegt ein Posten mit Grundmaß 0 nichts. Der ganze
   Fehlbetrag fiel auf die Abzeichen, die ihn nicht hergaben (siehe oben),
   also blieb er am Satz hängen. Gemessen in der Browser-Gegenprüfung zu
   #2858 (cm, 20.09.2026): Bei 1100 px Fensterbreite bekam eine
   Termin-Zeile mit Terminart und Termin-Abzeichen 0 px Satz — ausgerechnet
   die Zeile, deren Abzeichen #2858 bewusst stehen lässt, weil der Satz die
   Terminart nicht nennt.

   Eine Untergrenze und nicht nur ein Grundmaß `flex: 1 1 8ch`: Ein
   Grundmaß schrumpft mit, denn es behält den Schrumpffaktor 1.
   Nachgerechnet mit den gemessenen Breiten bleiben davon 20 bis 26 px
   stehen — gut drei Zeichen statt acht (Gegenprobe im Prüfstand). `min-width` friert den Satz bei acht
   Zeichen ein und schiebt den ganzen Fehlbetrag auf die Abzeichen, wo er
   hingehört: Die kürzen mit Ellipsis und tragen ihren vollen Wortlaut im
   `title`. */
.activity-text {
    flex: 1; min-width: 8ch; cursor: pointer;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.activity-text.is-auf { white-space: pre-wrap; overflow: visible; word-break: break-word; }
.activity-text.is-leer { color: var(--text-muted); }
/* Angabe und Satz (toloro#4574): zugeklappt die Angabe — sie kürzt am Ende
   mit der Ellipse der Zeile, die Kennung vorn bleibt stehen —, aufgeklappt
   der volle Satz, der wie jeder aufgeklappte Text umbricht. Beide erben
   Umbruch und Kürzung von `.activity-text`; Alpine schaltet nur um. */
.activity-angabe, .activity-satz { white-space: inherit; }
/* Der Urheber — seit toloro#2802 mit dem Abzeichen „automatisch" darin
   (vorher stand es in der Art-Spalte und schrumpfte dort jede Aufschrift
   mit). Der NAME kürzt, das Abzeichen nicht: Dass kein Mensch gehandelt
   hat, ist die Aussage; der volle Name steht im title der Zelle. */
.activity-actor {
    display: flex; align-items: baseline; gap: 4px; min-width: 0;
    font-size: var(--text-xs); color: var(--text-secondary);
}
.activity-actor-name {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    /* Der Name schrumpft nicht neben dem Abzeichen (toloro#4573) — schon ein
       Bruchteil eines Pixels ließe die Ellipse „Bru…" stehen. Nur ein Name,
       der allein breiter ist als die Zelle, kürzt noch. */
    flex-shrink: 0; max-width: 100%;
}
/* Die Wer-Spalte ab 1300 px Fensterbreite 200 statt 132 px (toloro#3744):
   Mit dem Abzeichen „keine Bearbeitung" (≈95 px) blieb vom Namen sonst
   „N..". Die Breite geht vom Vorgang ab, der als einzige Spalte flexibel
   ist — ab 1300 px bleiben ihm mindestens rund 330 px. Darunter bleibt es
   bei 132 px, damit der Vorgang bei 1100 px nicht auf 0 fällt (Akzeptanz 1
   in aktivitaeten-zeitleiste-blatt.test.js, toloro#2879). Dort kürzt seit
   toloro#4573 das Abzeichen statt des Namens: „Wer" ist ein Wort
   („Nicole", „Alexander S."), und es ist das, was am Telefon zählt; das
   Abzeichen erklärt sich weiter beim Drüberfahren. */
@media (min-width: 1300px) {
    .activity-head,
    .activity-row,
    .activity-protokollzeile {
        grid-template-columns: var(--activity-zeit, 152px) var(--activity-art, 150px) minmax(0, 1fr) 200px 18px;
    }
}
/* Systemspuren (toloro#2377, am Urheber seit #3717): Das hat kein Mensch
   getan, und die Zeile zählt nicht als Bearbeitung. Das Abzeichen sagt es in
   Worten, der gedimmte Akteur beim Überfliegen — ohne die Zeile zu
   verstecken, denn sie gehört in die Akte.
   Seit toloro#3744 gibt es ein zweites Abzeichen in derselben Zelle,
   „keine Bearbeitung" (Mensch, zählt nicht) — gleiche Form, gleiche Farbe:
   .activity-marke ist die eine Regel für beide, die Klassen
   .activity-automatisch / .activity-keine-bearbeitung sind nur Griffe für
   Proben. Die Zelle kommt aus fragments/aktivitaet-wer.html und sieht in
   der Zeitleiste und in der Karte „Zuletzt passiert" gleich aus. */
.activity-actor.is-automatisch { color: var(--text-muted); font-style: italic; }
.activity-marke {
    opacity: .75; white-space: nowrap;
    /* Fehlt Platz, gibt das Abzeichen nach (toloro#4573) und endet mit
       „…" — dafür braucht es inline-block statt der Flex-Zeile von .badge. */
    min-width: 0; display: inline-block;
    overflow: hidden; text-overflow: ellipsis;
}
/* Karte „Zuletzt passiert": Wer-Zelle plus Uhrzeit rechts in der Kopfzeile. */
.activity-wer-zeit { margin-left: auto; display: flex; align-items: baseline; gap: 4px; min-width: 0; }
/* Der Zähler einer Sammelzeile (toloro#2802) — „3×" rechts im
   Vorgangs-Feld, links vom Stift. Klein und stumm wie ein Abzeichen,
   aber anklickbar: Er klappt dieselben Einzelheiten auf wie der Pfeil am
   Zeilenende. Er schrumpft nicht mit — die Ellipsis trägt der Text
   daneben, wie beim Stift.

   Er hängt an der GRUNDLINIE der ersten Textzeile (toloro#2880) und
   trägt dafür kein eigenes `align-self`: `.activity-main` steht auf
   `align-items: baseline`, das genügt. Er stand auf `align-self: center`
   und rutschte damit in einer aufgeklappten Sammelzeile
   (`.activity-text.is-auf`, mehrere Textzeilen) in die senkrechte Mitte
   des Blocks — seit !3361 sichtbar schief, weil der Stift dort oben
   hängt. Kein eigener Versatz wie beim Symbol: Der Zähler ist Text, und
   Text gehört auf die Grundlinie, nicht an die Oberkante. */
.activity-zaehler {
    background: none; border: none; padding: 0; line-height: 1;
    cursor: pointer; color: var(--text-secondary); flex-shrink: 0;
    font-size: var(--text-xs); font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.activity-zaehler:hover,
.activity-zaehler.is-auf { color: var(--primary); }
/* Der Sprung zum Gegenstand steht seit toloro#2938 IM SATZ: Nennt der
   Satz den Gegenstand, ist genau dieses Wortstück der Link. Vorher stand
   hier `.activity-sprung`, ein 14-px-Pfeil in `--text-muted` am
   Zeilenende, neben dem gleich aussehenden Stift — Christians Befund vom
   21.09.2026 auf Prod: „Man kann nicht mehr klicken."

   Er sieht aus wie ein Link und nicht wie ein Abzeichen: Hausfarbe, und
   der Unterstrich kommt erst beim Überfahren. Ein dauernder Unterstrich
   zöge in einer Liste aus 60 Sätzen eine zweite Kante durch jede Zeile;
   die Farbe allein reicht hier nicht als einziges Unterscheidungsmerkmal,
   deshalb steht der Name zusätzlich im `title` („Zur Aufgabe …") und der
   Link ist ein echtes `a href` — mit der Tastatur erreichbar, den
   Fokusring zeichnet components.css. */
.activity-satzlink { color: var(--primary); text-decoration: none; }
.activity-satzlink:hover, .activity-satzlink:focus-visible { text-decoration: underline; }
/* Trefferfläche für den Stift (Gegenprüfung 20.09.2026, !3355): Ein
   14-px-Ziel, das ein Formular öffnet. Innenabstand hebt es auf
   24 × 24 px; der negative Außenabstand hält die Zeile senkrecht, wo sie
   ist (Zeilenhöhe und Grundlinie unverändert). Waagerecht sind es −2 px
   statt −5 px — die Fläche stieß damals an die des Pfeils daneben, der
   mit toloro#2938 weggefallen ist; der Wert bleibt, weil er die Zeile
   nicht verschiebt. NUR in der Hauptzeile: Die aufgeklappten
   Einzelheiten einer Sammelzeile stehen 17 px hoch mit 2 px Abstand —
   dort überdeckten sich die 24-px-Flächen zweier Stifte senkrecht, und
   der untere gewänne den Klick auf den Rand des oberen. */
/* Und er hängt an der ERSTEN Textzeile (toloro#2879). Er stand auf
   `align-self: center`; klappt man einen langen Satz auf
   (`.activity-text.is-auf`, `pre-wrap`), wächst die Zeile auf mehrere
   Textzeilen, und die Mitte des Blocks ist dann nicht mehr die Mitte des
   Satzanfangs — gemessen bei 300 Zeichen: Zeilenhöhe 95 px, Text ab
   y 143,5, Symbol bei y 178,5, optisch auf Höhe der dritten Zeile. Das
   Symbol gehört aber zur Zeile, nicht zum Absatz.

   `flex-start` allein setzte es an die Oberkante der Flex-Zeile: Der
   negative Außenabstand von -5 px hebt den 24-px-Kasten so an, dass das
   14-px-Symbol genau dort beginnt. In der zugeklappten Zeile stand es
   bisher 3,5 px tiefer (Flex-Zeile 21 px, Symbolkasten 14 px, mittig).
   Ein oberer Abstand von -2 px statt -5 px schiebt es diese 3 px zurück,
   und die Zeile bleibt senkrecht, wo sie war: Der Außenkasten misst damit
   17 px und damit immer noch weniger als die 21 px der Zeile. */
.activity-main > .activity-bearbeiten {
    padding: 5px; margin: -2px -2px -5px; align-self: flex-start;
}

/* Der Stift am rechten Rand der Vorgangs-Spalte (toloro#1906). Er sitzt
   IN .activity-main und nicht in einer sechsten Rasterspalte: Die kostete
   jede Zeile Breite, auch die, an der niemand etwas ändern darf. Er
   schrumpft nicht mit — der Text daneben trägt die Ellipsis. */
.activity-bearbeiten {
    background: none; border: none; padding: 0; line-height: 0;
    cursor: pointer; color: var(--text-muted); flex-shrink: 0;
    align-self: center;
}
.activity-bearbeiten:hover,
.activity-bearbeiten.is-auf { color: var(--primary); }
.activity-bearbeiten svg { width: 14px; height: 14px; fill: currentColor; }

/* Das aufgeklappte Formular als eigene Rasterzeile unter der Zeile —
   Zeile 3, damit es sich mit den Einzelheiten einer Sammelzeile (Zeile 2)
   nicht in dieselbe Zelle setzt. Kein `display` im style-Attribut: x-show
   räumt es beim Einblenden weg (#948), die Fläche kommt von hier. */
.aktivitaet-bearbeiten {
    grid-column: 3 / -1; grid-row: 3;
    display: flex; flex-direction: column; gap: 8px;
    margin: 4px 0 8px; padding-left: 10px;
    border-left: 2px solid var(--primary-soft);
}
.aktivitaet-bearbeiten textarea { width: 100%; }
.aktivitaet-bearbeiten-haken {
    display: flex; align-items: flex-start; gap: 8px;
    font-size: var(--text-sm); cursor: pointer;
}
.aktivitaet-bearbeiten-hinweis { display: block; color: var(--text-secondary); }
.aktivitaet-bearbeiten-knoepfe { display: flex; gap: 8px; justify-content: flex-end; }

.activity-toggle {
    background: none; border: none; padding: 0; line-height: 0;
    cursor: pointer; color: var(--text-muted); align-self: center;
}
.activity-toggle:hover { color: var(--text); }
.activity-toggle svg { width: 16px; height: 16px; fill: currentColor; transition: transform 0.15s; }
.activity-toggle.is-auf svg { transform: rotate(180deg); }

/* Die Einzelheiten einer Sammelzeile (#1500): „24 Bilder eingestellt"
   klappt auf die 24 Rohzeilen auf. Sie stehen als eigene Rasterzeile
   unter der Zeile, eingerückt bis zur Vorgangs-Spalte — so liest man
   auf einen Blick, dass sie zur Zeile darüber gehören und nicht
   selbst Zeitleiste sind. */
.activity-einzelheiten {
    grid-column: 3 / 5; grid-row: 2;
    display: flex; flex-direction: column; gap: 10px;
    margin: 2px 0 4px; padding-left: 10px;
    border-left: 2px solid var(--border);
    font-size: var(--text-xs); color: var(--text-secondary);
}
/* Eine aufgeklappte Rohzeile trägt seit toloro#2802 ihren eigenen Stift und
   ihr eigenes Formular. Das Formular ist ein Kind dieser Flex-Zeile und
   bricht deshalb auf eine volle Breite um, statt sich neben den Text zu
   quetschen. */
.activity-einzelheit {
    display: flex; gap: 8px; min-width: 0; flex-wrap: wrap;
    align-items: baseline;
}
/* Der Stift einer aufgeklappten Rohzeile bekommt dieselbe Trefferfläche
   wie der in der Hauptzeile — jetzt, wo Platz dafür ist (toloro#2879,
   Befund cm vom 20.09.2026). In !3355 blieb er bei 14 × 14 px, weil die
   Zeilen 17 px hoch mit 2 px Abstand standen: Zwei 24-px-Flächen
   überdeckten sich dort senkrecht um 5 px, und der untere Stift gewann
   den Klick auf den Rand des oberen. Das war die richtige Entscheidung
   für den falschen Zustand — WCAG 2.5.8 war damit weder über die Größe
   (14 px) noch über den Abstand erfüllt: Der Abstandsweg verlangt 24 px
   zwischen den Mittelpunkten, und 17 + 2 sind 19.

   Geheilt wird deshalb der Abstand und nicht die Fläche: 10 px statt
   2 px Zeilenabstand oben ergeben 27 px Rasterabstand. Damit ist die
   Ausnahmeregel schon erfüllt, und die 24-px-Fläche passt obendrein ohne
   Überdeckung hinein (27 − 24 = 3 px Luft) — also die stärkere Hälfte
   von 2.5.8, die Größe selbst. Waagerecht steht in diesen Zeilen kein
   zweites Ziel; die -2 px halten den Zeilenumbruch, wo er war. Die
   Zeilen der Hauptleiste rührt das nicht an. */
.activity-einzelheit > .activity-bearbeiten { padding: 5px; margin: -5px -2px; }
.activity-einzelheit .aktivitaet-bearbeiten {
    /* Die Rasterplatzierung der Zeilen-Fassung gilt hier nicht — dort ist
       das Formular eine eigene Rasterzeile, hier ein Flex-Kind. */
    grid-column: auto; grid-row: auto;
    flex-basis: 100%; margin: 4px 0 6px;
}
.activity-einzelheit-zeit {
    white-space: nowrap; font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}
/* Die Art je aufgeklappter Zeile (toloro#2802). Sie steht zwischen
   Uhrzeit und Text und schrumpft nicht: Bei einem Bündel aus gemischten
   Texten ist sie die Auskunft, WAS da dreimal passiert ist. */
.activity-einzelheit-art {
    white-space: nowrap; flex-shrink: 0;
    color: var(--text-muted); font-weight: 600;
}
.activity-einzelheit-text {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.activity-foot {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 10px 12px; border-top: 1px solid var(--border);
    font-size: var(--text-xs); color: var(--text-secondary);
}

/* Tablet-Rückfallebene: die Spalten passen nicht mehr nebeneinander,
   die Zeile bricht auf zwei Zeilen um — Handy ist kein Ziel (#432). */
@media (max-width: 900px) {
    .activity-head { display: none; }
    .activity-row {
        grid-template-columns: auto minmax(0, 1fr) 18px;
        row-gap: 3px;
    }
    /* Die graue Zeile bricht mit: Spanne und Anzahl oben, Arten und
       Urheber darunter. Sie folgt dem Raster der Zeile daneben, damit
       die Liste auch auf dem Tablet EINE Liste bleibt. */
    .activity-protokollzeile {
        grid-template-columns: auto minmax(0, 1fr) 18px;
        row-gap: 2px;
    }
    /* Dieselbe Aufteilung wie bei der gewöhnlichen Zeile darüber:
       Zeitpunkt | Wer | Pfeil, darunter Art | Vorgang. Der Urheber stand
       hier bis zur Politur-Runde in Spalte 3 — das ist die 18 px breite
       Pfeilspalte, und ein Name, der 110 px braucht, stand dort als „S…". */
    .activity-protokoll-zeit   { grid-column: 1; grid-row: 1; }
    .activity-protokoll-akteur { grid-column: 2; grid-row: 1; }
    .activity-protokoll-pfeil  { grid-column: 3; grid-row: 1; }
    .activity-protokoll-zahl   { grid-column: 1; grid-row: 2; }
    .activity-protokoll-arten  { grid-column: 2 / span 2; grid-row: 2; }
    .aktivitaeten-suche { margin-left: 0; }
    .activity-time  { grid-column: 1; grid-row: 1; }
    .activity-actor { grid-column: 2; grid-row: 1; }
    .activity-toggle { grid-column: 3; grid-row: 1; }
    .activity-kind  { grid-column: 1; grid-row: 2; }
    .activity-main  { grid-column: 2 / span 2; grid-row: 2; }
    .activity-einzelheiten { grid-column: 1 / -1; grid-row: 3; }
    .aktivitaet-bearbeiten { grid-column: 1 / -1; grid-row: 4; padding-left: 0; }
}

/* ══════════════════════════════════════════════════════════════════
   Aufgaben-Detailseite: Verlauf und Kommentare (toloro#1262)
   ══════════════════════════════════════════════════════════════════
   Bewusst KEINE Spaltentabelle wie `.activity-list`: Dort sucht man
   eine Zeile in einer langen Akte, hier liest man die Geschichte EINER
   Aufgabe — chronologisch aufsteigend, mit dem Antwortfeld darunter.
   Das ist ein kleiner Chatverlauf, kein Register.

   Der Unterschied Kommentar ↔ Systemereignis steckt in Form UND Wort
   (kräftigere Kante, eigene Fläche, Abzeichen „Kommentar"); Farbe
   allein wäre für Farbfehlsichtige keine Information. */
.tsk-verlauf {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-direction: column; gap: 8px;
}
.tsk-verlauf-zeile {
    display: flex; flex-direction: column; gap: 3px;
    padding: 7px 10px;
    border-left: 3px solid var(--border);
    background: var(--bg-subtle);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.tsk-verlauf-kopf {
    display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap;
}
/* Der Stand im Kopf der Aufgabenseite (toloro#3715): was zuletzt
   eingetragen wurde, unter der Metazeile. Leise wie die Metazeile — außer
   an einer überfälligen Aufgabe ohne Eintrag: dann rot UND fett, und das
   erste Wort („Kein Eintrag") sagt es auch ohne Farbe. */
.tsk-stand {
    margin-top: 6px;
    font-size: var(--text-sm);
    color: var(--text-secondary);
    overflow-wrap: anywhere;
}
.tsk-stand-rot { color: var(--danger-text); font-weight: 700; }
/* Das Warten im Kopf der Aufgabenseite (toloro#3719, Variante A): „⌛ Wartet
   seit 29.09. auf … (Nicole Musterau): „…“". Grau wie die Metazeile; nach dem
   Ablauf rot UND fett — das Abzeichen darüber sagt „wartete bis". */
.tsk-warten {
    margin-top: 6px;
    font-size: var(--text-sm);
    color: var(--text-secondary);
    overflow-wrap: anywhere;
}
.tsk-warten-nach { color: var(--danger-text); font-weight: 700; }
.tsk-warten-zaehler { font-weight: 600; }
.tsk-sanduhr {
    width: 12px; height: 12px; margin-right: 4px; vertical-align: -1px;
    fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round;
}
/* Der graue Vermerk neben den Abzeichen: „wartete bis 08.10." (toloro#3719). */
.tsk-meta-vermerk { font-size: var(--text-xs); color: var(--text-muted); }
/* Der Satz an einer Aufgabe, die nicht warten kann (St 20), und der Satz
   im Weiterleiten-Dialog einer wartenden Aufgabe — leise, eine Zeile. */
.tsk-hinweis-zeile {
    margin-top: 6px;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}
/* Die Antwort kam außerhalb des Fadens (toloro#3723): an der neuen
   Mail-Aufgabe der Hinweis „Im Projekt wartet … — hierzu zuordnen?" mit dem
   Knopf daneben. Lauter als die leise Hinweiszeile — er will einen Klick. */
.tsk-zuordnen {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    margin-top: 8px; padding: 8px 10px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    font-size: var(--text-sm); color: var(--text);
}
.tsk-zuordnen-form { margin: 0; }
/* Der Satz unter dem Kommentarfeld einer überfälligen Aufgabe (toloro#3715). */
.tsk-kommentar-hinweis { color: var(--text-secondary); }
.tsk-verlauf-wer { font-size: var(--text-xs); font-weight: 600; }
.tsk-verlauf-zeit {
    font-size: var(--text-xs); color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.tsk-verlauf-text {
    font-size: var(--text-sm); white-space: pre-wrap; word-break: break-word;
}
.tsk-verlauf-kommentar {
    border-left-width: 4px;
    border-left-color: var(--primary);
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--border);
}

/* ══════════════════════════════════════════════════════════════════
   Schreibtisch-Übersicht /desktop/schreibtische (#969, E1c)
   ══════════════════════════════════════════════════════════════════
   Nur vier Regeln: die Tabelle selbst ist die bestehende `.table`, die
   Kopfzahlen sind `.stat`, die Nachweiszeile ist ein `.list-item`. Was
   hier steht, ist genau das, was es dort nicht gibt — der klickbare
   Zeilenname, die Markierung des aufgerissenen Tisches und die rote
   Uhr. Alles andere wäre eine zweite Tabellensprache. */
.tisch-tabelle .tisch-name {
    font-weight: 600;
    color: var(--text);
    text-decoration: none;
}

.tisch-tabelle .tisch-name:hover {
    text-decoration: underline;
}

/* Der gerade aufgerissene Tisch bleibt in der Tabelle sichtbar — sonst
   verliert man beim Scrollen, wessen Aufgaben unten stehen. */
.tisch-tabelle tr.tisch-aktiv {
    background: var(--primary-soft);
}

/* Die zu spät gewordene Fälligkeit. Rot UND fett: Farbe allein ist für
   rotgrün-blinde Augen keine Auskunft. */
.tisch-spaet {
    color: var(--danger-text);
    font-weight: 700;
}

/* Der Erklärsatz auf „Mein Schreibtisch" (#969): WARUM diese Zeile bei
   mir liegt. Leiser als der Projektbezug daneben — er beantwortet eine
   Frage, die man nur einmal stellt, und darf die Zeile nicht dominieren. */
.tisch-warum {
    color: var(--text-muted);
}

/* Die Mail-Vorschau in einer Listenzeile (toloro#1539): Absender und
   Textanfang der E-Mail, aus der die Aufgabe entstanden ist. Sie steht in
   derselben Unterzeile wie Projekt und Erklärsatz — die kürzt bereits mit
   Auslassung, also wächst die Zeile nicht. Etwas kräftiger als der
   Erklärsatz daneben: „von wem" ist die Frage, für die diese Zeile gebaut
   ist. */
.tisch-mail {
    color: var(--text-secondary);
}

/* Dieselbe Vorschau im Aufgabenspiegel. Dort steht sie in einer
   Tabellenzelle, und die bricht von sich aus um — deshalb hier die
   Kürzung, die die Schreibtisch-Unterzeile schon mitbringt. Der Deckel ist
   derselbe wie bei `.tisch-fehler` darunter: Ein langer Vorspann darf die
   Spalten daneben nicht aus dem Bild schieben. */
.tisch-mailzeile {
    max-width: 420px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

/* Der Stand einer offenen Aufgabe (toloro#3715): was zuletzt eingetragen
   wurde — „zuletzt 25.09. · N. Musterau: HUK niemand erreicht" — bzw. an
   einer überfälligen ohne Eintrag „kein Eintrag seit der Frist". Er steht in
   der Unterzeile hinter dem Projekt, kräftiger als der Erklärsatz, dessen
   Platz er einnimmt: „was ist passiert?" ist die Frage, mit der der
   Vorgesetzte die Liste liest. Die rote Lage ist rot UND fett, und ihr
   erstes Wort ist ein anderes als „zuletzt" — Form und Wort, nie nur
   Farbe (UX-Leitplanken an #3714). */
.tisch-stand {
    color: var(--text-secondary);
}

.tisch-kein-eintrag {
    color: var(--danger-text);
    font-weight: 700;
}

/* Das Warten in der Unterzeile (toloro#3719): „⌛ auf Unterlagen von Fa.
   Müller" — die Sanduhr ist dasselbe Bild wie „warten auf" am Projekt, in
   der Höhe der Schrift. */
.tisch-sanduhr {
    width: 10px;
    height: 10px;
    margin-right: 3px;
    vertical-align: -1px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.2;
    stroke-linecap: round;
}

/* Die Fälligkeitsspalte einer Aufgabe mit Warten (toloro#3720): Die Hülle
   verschwindet aus dem Layout, ihre zwei Zeilen stehen in der senkrechten
   Spalte wie die gewohnten. Die zweite Zeile („Frist war 07.09.",
   „wartete bis 08.10.") ist klein und grau. */
.tisch-fristzelle {
    display: contents;
}

.tisch-frist-zweite {
    font-size: 11px;
    color: var(--text-muted);
    line-height: 1.3;
    text-align: right;
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Derselbe Stand in einer Tabellenzelle (Aufgabenspiegel) und in der
   einzeiligen Aufgabenliste der Projektakte: einzeilig, gekürzt mit
   Auslassung, der ganze Satz im Hinweis — dieselbe Bauart wie die
   Mail-Vorschau darüber. */
.tisch-standzeile {
    max-width: 420px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

/* Der letzte Fehlertext einer hängenden Systemaufgabe (#973, I8). Er ist
   der Grund, warum jemand diese Seite überhaupt öffnet — deshalb darf er
   umbrechen statt abzuschneiden. Gedeckelt, damit ein langer Satz die
   übrigen Spalten nicht aus dem Bild schiebt. */
.tisch-fehler {
    max-width: 420px;
    white-space: normal;
    color: var(--text-muted);
    font-size: 0.85rem;
    line-height: 1.35;
}

/* ══════════════════════════════════════════════════════════════════
   Aufgabenspiegel /desktop/aufgabenspiegel (#976, E4b)
   ══════════════════════════════════════════════════════════════════
   Dieselbe Sparsamkeit wie bei der Schreibtisch-Übersicht darüber: die
   Tabelle ist die bestehende `.table`, die Kopfzahlen sind `.stat`, die
   rote Uhr ist `.tisch-spaet` — geteilt und nicht abgeschrieben, damit
   „zu spät" auf beiden Controlling-Sichten gleich aussieht. Was hier
   steht, ist genau das, was es dort nicht gibt: die klickbare Zahl in
   der Matrix, die Zwischen- und Gesamtsummenzeile und die Leiste der
   gespeicherten Ansichten. */

/* Die Zahl in der Zelle IST der Weg in die Liste darunter. Sie sieht
   deshalb wie eine Zahl aus und nicht wie ein Link — unterstrichen wäre
   eine Matrix aus 30 Zellen unlesbar; der Hinweis kommt beim Überfahren. */
.spiegel-tabelle td.num a {
    color: var(--text);
    text-decoration: none;
    font-variant-numeric: tabular-nums;
}

.spiegel-tabelle td.num a:hover {
    text-decoration: underline;
}

.spiegel-tabelle .spiegel-art {
    font-weight: 600;
}

/* Die Zwischenüberschrift je Gruppe. Sie trägt eine Zwischensumme und
   keine Links: geklickt wird die Art, nicht die Schublade. */
.spiegel-tabelle tr.spiegel-gruppe td {
    background: var(--bg-muted);
    font-weight: 600;
    color: var(--text-secondary);
}

/* Die Summenzeile — abgesetzt, damit sie beim Überfliegen nicht als
   weitere Aufgabenart gelesen wird. */
.spiegel-tabelle tfoot tr.spiegel-summe td {
    border-top: 2px solid var(--border);
    font-weight: 700;
}

/* Die Leiste der gespeicherten Ansichten: benannte Filter, kein
   Datenbestand. Jede trägt ihr Löschkreuz gleich mit — eine Ansicht, die
   man nur über eine Verwaltungsseite loswird, sammelt sich an. */
.spiegel-ansichten {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.spiegel-ansicht {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 8px;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: var(--text-sm);
}

.spiegel-ansicht a {
    color: var(--text);
    text-decoration: none;
}

.spiegel-ansicht a:hover {
    text-decoration: underline;
}

.spiegel-ansicht-aktiv {
    background: var(--primary-soft);
    border-color: var(--primary);
}

.spiegel-ansicht-weg {
    border: 0;
    background: none;
    cursor: pointer;
    padding: 0 2px;
    line-height: 1;
    color: var(--text-muted);
}

.spiegel-ansicht-weg:hover {
    color: var(--danger-text);
}

/* ── Lead-Inbox: Sichten und Zeilen (toloro#2063) ─────────────────
   Christian, 08.09.2026: „Das ist echt nicht wirklich übersichtlich
   diese Seite. Insbesondere die Buttons rechts… noch schlimmer sind die
   Filter oben." Die Lead-Inbox bedienen Leute, die keine PC-Profis sind;
   bis hierher standen acht Knopfreihen über der Liste, bevor der erste
   Lead sichtbar wurde.

   An ihrer Stelle steht eine Reihe fertiger SICHTEN mit Trefferzahl.
   Als Kacheln und nicht als `.tabs`: Die Zahl ist der eigentliche
   Inhalt („was fasse ich als nächstes an"), und sie soll groß dastehen
   statt als Abzeichen hinter einem Wort. Der zweite Grund ist eine
   Lehre aus toloro#1509 — `.tabs` schaltet bei Überbreite auf Querlauf
   und schneidet den letzten Reiter unsichtbar ab. Hier umbricht die
   Reihe stattdessen, und „Rückgabe endet" (der Reiter, hinter dem Geld
   steht) bleibt auch bei 1000 px sichtbar. */
.lead-sichten {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 12px;
}

.lead-sicht {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 132px;
    padding: 8px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
    color: var(--text);
    text-decoration: none;
    transition: border-color 0.15s, background 0.15s;
}

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

/* Die aktive Sicht ist die Antwort auf „wo bin ich gerade" und muss sich
   auf einen Blick abheben — nicht nur durch eine Randfarbe, die neben
   dem Mauszeiger-Zustand nicht mehr zu unterscheiden wäre. */
.lead-sicht-aktiv,
.lead-sicht-aktiv:hover {
    background: var(--primary-soft);
    border-color: var(--primary);
    box-shadow: inset 0 -3px 0 var(--primary);
}

.lead-sicht-zahl {
    font-size: var(--text-lg);
    font-weight: 700;
    line-height: 1.1;
}

.lead-sicht-text {
    font-size: var(--text-xs);
    color: var(--text-secondary);
    white-space: nowrap;
}

/* Dringlichkeit wie am Briefsymbol der Zeile: gelb läuft heute ab, rot
   ist verstrichen. Sie färbt NUR die Zahl und nur, solange die Zahl
   nicht null ist (Bedingung in der Vorlage) — eine rote Null wäre ein
   Alarm ohne Anlass, und nach drei Tagen sieht niemand mehr hin.

   Den Ton nennt das Modell (`LeadInboxService.Sicht#ton()`), die Farbe
   steht hier. `lead-sicht-neutral` bekommt deshalb bewusst KEINE Regel:
   Die Vorlage hängt den Ton ohne Fallunterscheidung an, und eine leere
   Regel wäre eine Zeile, die nur so tut, als täte sie etwas. */
.lead-sicht-warnung .lead-sicht-zahl { color: var(--warning-text); }
.lead-sicht-gefahr  .lead-sicht-zahl { color: var(--danger-text); }

/* ── Kontaktstufe (toloro#4632) ──────────────────────────────────
   Vier Stufen, unterschieden durch FORM und HELLIGKEIT, nicht durch die
   Farbe allein (Rot-Grün-Schwäche im Haus; Orange gegen Blau gegen Grau):
     nicht kontaktiert  voller Punkt, orange
     nachfassen fällig  Ring, orange
     versuch läuft      halb gefüllter Kreis, blau
     unerreichbar       durchgestrichener Kreis, grau
   Das Zeichen steht im Abzeichen der Zeile und in den Zählern darüber. */
.lk-zeichen {
    display: inline-block;
    flex: none;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    box-sizing: border-box;
    position: relative;
}
.lk-nicht_kontaktiert  .lk-zeichen { background: var(--warning-text); }
.lk-nachfassen_faellig .lk-zeichen { border: 2px solid var(--warning-text); }
.lk-versuch_laeuft     .lk-zeichen {
    border: 1.5px solid var(--info-text);
    background: linear-gradient(90deg, transparent 50%, var(--info-text) 50%);
}
.lk-unerreichbar       .lk-zeichen { border: 1.5px solid var(--neutral); }
.lk-unerreichbar       .lk-zeichen::after {
    content: "";
    position: absolute;
    left: 50%;
    top: -1px;
    bottom: -1px;
    width: 1.5px;
    margin-left: -0.75px;
    background: var(--neutral);
    transform: rotate(45deg);
}

.lead-kontakt-leiste {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    margin-bottom: 12px;
}

.lead-kontakt-kacheln {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.lead-kontakt-kachel {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 40px;
    padding: 6px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
    color: var(--text);
    font-size: var(--text-sm);
    text-decoration: none;
}
.lead-kontakt-kachel:hover { border-color: var(--primary); }
/* „Jetzt handeln" sticht hervor: kräftiger Rand in Orange. */
.lead-kontakt-kachel.lk-nicht_kontaktiert,
.lead-kontakt-kachel.lk-nachfassen_faellig {
    border: 2px solid var(--warning-text);
    padding: 5px 13px;
}
.lead-kontakt-kachel-aktiv,
.lead-kontakt-kachel-aktiv:hover {
    background: var(--primary-soft);
    box-shadow: inset 0 -3px 0 var(--primary);
}
.lead-kontakt-kachel-zahl {
    font-size: var(--text-lg);
    font-weight: 700;
    line-height: 1;
}

.lead-gruppen-schalter {
    text-decoration: none;
}

/* ── Die Zeile öffnet die Akte ────────────────────────────────────
   Bis toloro#2063 war nur der kleine Link „Akte öffnen" unten rechts
   klickbar; auf „Meine Projekte" ist die ganze Zeile ein Link. Hier
   geht das NICHT über ein <a> um den Zeileninhalt: In der Zeile stehen
   Formulare („Übernehmen") und Knöpfe, und ein <form> in einem <a> ist
   ungültiges HTML — der Browser zieht das Formular aus dem Link heraus,
   und der Knopf verliert seine Wirkung.

   Stattdessen deckt das ::after des Titel-Links die ganze Zeile ab. Was
   darüber bedienbar bleiben muss, hebt sich heraus: die Aktionsspalte,
   der orange Hörer samt Rufnummer — und alles mit einem `title`, denn
   ein Tooltip erscheint nur, wenn der Mauszeiger das Element selbst
   trifft (Fristherkunft, „Unvollständig", die Rückgabefrist).

   DAFÜR REICHT `position: relative` — und ein `z-index` wäre hier sogar
   schädlich (gemessen an der gerenderten Seite): Er machte aus der
   Aktionsspalte einen eigenen Stapelkontext, und das ⋯-Menü darin
   (`.dropdown-menu`, z-index 50) käme aus diesem Kontext nicht mehr
   heraus — aufgeklappt verschwand es hinter dem „Übernehmen"-Knopf der
   nächsten Zeile. Ohne z-index liegen Overlay und Spalte im selben
   Kontext, und dort gewinnt, was später im Baum steht: die
   Aktionsspalte steht hinter dem Titel, das Menü über allem. */
.lead-zeile {
    position: relative;
}

.lead-zeile:hover {
    background: var(--bg-muted);
}

.lead-zeile-link {
    text-decoration: none;
    color: inherit;
}

.lead-zeile-link::after {
    content: "";
    position: absolute;
    inset: 0;
}

.lead-zeile-aktionen,
.lead-zeile [title] {
    position: relative;
}

/* Die Aktionsspalte: oben EIN Knopf und daneben das ⋯-Menü, darunter
   „Wer kümmert sich" — und das nur, wenn sich wirklich jemand kümmert.
   Die Mindestbreite von früher (170 px für vier Bedienelemente) ist
   entfallen; sie hielt die Spalte auch dann breit, wenn nichts darin
   stand, und bei 1000 px Fensterbreite drückte sie den Titel um. */
.lead-zeile-aktionen {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    flex: none;
}

.lead-zeile-knoepfe {
    display: flex;
    align-items: flex-start;
    gap: 6px;
}

/* Das ⋯-Menü hängt als `position:absolute` an diesem Halter — ohne die
   eigene Lage klebte es am nächsten positionierten Vorfahren, und das
   ist hier die ganze Zeile (`.lead-zeile`). */
.lead-zeile-menue {
    position: relative;
    flex: none;
}

/* ── Die Leitfrist in der Zeile ───────────────────────────────────
   toloro#2066: Die Rückgabefrist steht direkt unter dem Titel, weil
   der Betreuer seinen Tag an ihr ausrichtet — wer sie verpasst,
   bezahlt den Lead. Sie ist deshalb bewusst KEINE `.list-item-subtitle`:
   Die Zeile darunter (Ort, Quelle, Eingang) ist Beschreibung, diese
   hier ist eine Frist mit Ampel und trägt eine Stufe mehr Gewicht.

   `flex-wrap` statt fester Breiten: Bei 1000 px Fensterbreite bricht
   der Countdown unter den Zeitpunkt, statt die Zeile zu sprengen —
   dieselbe Überlegung, mit der die Sichten-Reihe umbricht statt zu
   scrollen. `position: relative` kommt aus `.lead-zeile [title]` (der
   Tooltip mit der Fristherkunft muss über der Zeilen-Überdeckung
   liegen); hier steht es nicht noch einmal. */
.lead-zeile-frist {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 2px;
    font-size: var(--text-sm);
    font-weight: 600;
    width: fit-content;
}

.lead-zeile-frist svg {
    width: 14px;
    height: 14px;
    flex: none;
    fill: currentColor;
}

/* Der Countdown ist die zweite Hälfte derselben Aussage und deshalb
   nicht `text-muted`: Er trägt die Farbe der Ampel mit, nur ohne die
   Strichstärke — grau gesetzt läse er sich als Fußnote, und genau er
   ist die Zahl, auf die es in den letzten Stunden ankommt. */
.lead-zeile-frist-rest {
    font-weight: 400;
}

/* Rot heißt „abgelaufen oder im Warnfenster — jetzt entscheiden", gelb
   „es läuft eine Uhr". Den Ton nennt das Modell (`Rueckgabe#ampel()`),
   die Farbe steht hier.

   Genommen werden die DUNKLEN Töne von `.badge-danger`/`.badge-warning`
   und nicht `--danger`/`--warning` selbst: Als Flächenfarben sind die
   beiden richtig, als Textfarbe auf Weiß aber zu blass (#EF4444 = 3,8:1,
   #F59E0B = 2,2:1 — unter den 4,5:1 aus #1805). Hier steht Text, den
   jemand wirklich lesen muss; er trägt die Uhrzeit, an der Geld hängt.
   Und die Farbe ist nie das einzige Merkmal: Die Dringlichkeit steht
   ausgeschrieben daneben („noch 5 Std.", „seit 3 Std. vorbei"). */
.lead-zeile-frist-gefahr  { color: #991B1B; }
.lead-zeile-frist-warnung { color: #92400E; }

/* ── Meine Leads als Tabelle (toloro#3420, nachgezogen toloro#3496) ───
   Muster Projekttabelle (#2909): `table-layout: fixed`, die Breiten stehen
   an den Köpfen, Zellen brechen nicht um, sondern kürzen mit
   Auslassungspunkten — der volle Text steht im `title`. Eine feste Breite
   hat jede Spalte außer „Lead"; „Lead" bekommt den Rest.

   WIE die Projekttabelle schiebt die Karte waagerecht, sobald das Fenster
   schmaler ist als die Mindestbreite der Tabelle. Ohne sie bekäme „Lead"
   bei festen Nachbarn auf schmalem Fenster nur noch ein paar Pixel, und die
   Aktionsspalte ragte über den Fensterrand (`body { overflow-x: hidden }` —
   dort nicht erreichbar; gemessen in der QA zu !3955). Das ⋯-Menü der Zeile
   schwebt deshalb am Fenster (`.dropdown-menu--schwebend`), sonst schnitte
   das `overflow` es ab.

   NACHGEZOGEN (toloro#3496, Entscheidung F9). Christian, 28.09.2026:
   „wichtige Dinge sind abgeschnitten". Die Breiten sind GEMESSEN
   (Headless-Chromium mit Inter aus css/tokens.css, Zahlen im MR !4112), nicht
   geschätzt; je Spalte steht der Maßstab daneben. Drei Stufen, weil die
   Seitenleiste bei 1536 px von 264 auf 280 px springt (css/layout.css):

     ab 1800 px   Büroschirm      voller Knopftext, Kopf „Vollständig" als Wort
     1536–1799    Büro/Laptop     „Annehmen", ✓ als Kopf, Anliegen 108 px
     unter 1536   Laptop um 1440  wie darüber, Anliegen gibt den Rest ab

   Fehlende Pixel kommen aus „Anliegen" — nie aus Ort, Von oder Eingang
   (Auflage F9); der volle Text des Anliegens steht im Hinweis. Die
   Mindestbreite je Stufe = feste Spalten + 150 px für „Lead"
   („L26-123 · Nachname" misst 139,4 px) und passt je Stufe in die nutzbare
   Breite ihres schmalsten Fensters — MIT klassischer Bildlaufleiste
   (17 px). Das rechnet `src/test/js/desktop/lead-tabelle-breiten.test.js`
   aus genau diesen Zahlen nach: Wer eine Breite ändert, sieht dort, ob sie
   noch passt. */
.app2-content:has(.leadtabelle) {
    max-width: none;
}

.leadtabelle-karte {
    overflow-x: auto;
}

.leadtabelle {
    table-layout: fixed;
    /* 1286 px feste Spalten + 150 px für „Lead". */
    min-width: 1436px;
    /* Hält die `sr-only`-Texte des Kopfs („Aktion", „Vollständig") in der
       schiebenden Karte (QA zu toloro#3496). Ohne Bezugsrahmen hing ihre
       Lage an einem Vorfahren AUSSERHALB der Karte: ganz rechts stehend
       (Aktionsspalte ohne Knopf) machten sie die Seite unsichtbar breiter —
       gemessen 80 px bei 1280 px Fensterbreite. Die Zeilen tragen ihren
       Bezugsrahmen schon selbst (`.lead-zeile`). */
    position: relative;
}

.leadtabelle th,
.leadtabelle td {
    padding: 6px 8px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Maßstab je Spalte (Text + 2 × Innenabstand, gemessen):
   Rückgabe  Kopf „RÜCKGABE ↑" 84,5 · „noch 40 Std." 84,7
   Ort       „67125 Dannstadt-Schauernheim" 212,4 (Issue: passt ohne Ellipse)
   Vollst.   Kopf „VOLLSTÄNDIG" 89,8
   Von       Issue: ≥ 170 / ≥ 140 px
   Eingang   „22.09. 08:15" 81,4 (Issue: ≥ 112 / ≥ 100 px)
   Rückm.    Kopf „RÜCKMELDUNG ↑" 114,5 (mit Sortierpfeil)
   Aktion    „Annehmen → Projekt" 173,2 + 6 + ⋯ 26 */
.leadtabelle .lt-rueckgabe    { width: 104px; }
.leadtabelle .lt-lead         { width: auto; }
.leadtabelle .lt-ort          { width: 230px; }
.leadtabelle .lt-anliegen     { width: 160px; }
.leadtabelle .lt-vollstaendig { width: 108px; }
.leadtabelle .lt-von          { width: 170px; }
.leadtabelle .lt-eingang      { width: 112px; font-variant-numeric: tabular-nums; }
.leadtabelle .lt-faellig      { width: 132px; font-variant-numeric: tabular-nums; }
.leadtabelle .lt-wer          { width: 48px; }
.leadtabelle .lt-aktion       { width: 222px; overflow: visible; }

/* Keine Zeile trägt einen Knopf (Klasse aus `th:with` in app2/leads.html):
   Die Spalte ist genau so breit wie der ⋯-Knopf (26 px + Innenabstand), und
   „Wer" steht rechtsbündig davor — zwischen Kürzel und ⋯ liegen nur die
   beiden Innenabstände (gemessen 16 / 10 / 8 px je Stufe). Der Selektor ist mit Absicht
   spezifischer als die Stufen unten — sonst überschriebe jede Stufe die
   schmale Breite wieder mit der Knopfbreite. */
.leadtabelle.leadtabelle--ohne-knopf .lt-aktion { width: 42px; }

/* Kurz- und Langform (toloro#3496): Was ab 1800 px als Wort steht, steht
   darunter kürzer — der Kopf „Vollständig" als ✓, der Knopf „Annehmen →
   Projekt" als „Annehmen". Vorlesehilfen hören immer die Langform (`sr-only`
   daneben, beide sichtbaren Formen sind `aria-hidden`). */
.leadtabelle .lt-schmal { display: none; }

/* 1536–1799 px: Innenabstand 5 px, die Knöpfe der Zeile schmaler gepolstert
   (Reserve aus F9) — „Übernehmen" ist dann der breiteste Knopf:
   107,9 + 6 + ⋯ 26 + 10 = 149,9 px. */
@media (max-width: 1799px) {
    .leadtabelle { min-width: 1172px; }
    .leadtabelle th,
    .leadtabelle td { padding: 6px 5px; }
    .leadtabelle .lt-rueckgabe    { width: 96px; }
    .leadtabelle .lt-ort          { width: 224px; }
    .leadtabelle .lt-anliegen     { width: 108px; }
    .leadtabelle .lt-vollstaendig { width: 36px; }
    .leadtabelle .lt-von          { width: 140px; }
    .leadtabelle .lt-eingang      { width: 100px; }
    .leadtabelle .lt-faellig      { width: 126px; }
    .leadtabelle .lt-wer          { width: 40px; }
    .leadtabelle .lt-aktion       { width: 152px; }
    .leadtabelle.leadtabelle--ohne-knopf .lt-aktion { width: 36px; }
    .leadtabelle .lt-primaer { padding-left: 10px; padding-right: 10px; }
    .leadtabelle .lt-breit  { display: none; }
    .leadtabelle .lt-schmal { display: inline; }
}

/* Unter 1536 px (Laptop um 1440): Innenabstand 4 px, und „Anliegen" gibt
   her, was die übrigen Spalten brauchen. Bei 1440 px mit klassischer
   Bildlaufleiste bleiben der Tabelle 1093 px — genau die Mindestbreite. */
@media (max-width: 1535px) {
    .leadtabelle { min-width: 1093px; }
    .leadtabelle th,
    .leadtabelle td { padding: 6px 4px; }
    .leadtabelle .lt-rueckgabe    { width: 94px; }
    .leadtabelle .lt-ort          { width: 222px; }
    .leadtabelle .lt-anliegen     { width: 47px; }
    .leadtabelle .lt-vollstaendig { width: 26px; }
    .leadtabelle .lt-faellig      { width: 124px; }
    .leadtabelle .lt-aktion       { width: 150px; }
    .leadtabelle.leadtabelle--ohne-knopf .lt-aktion { width: 34px; }
}

/* Was einen `title` trägt, hebt sich über die Zeilen-Überdeckung
   (`.lead-zeile-link::after`). `position: relative` allein reicht nur für
   Zellen HINTER der Spalte „Lead" — die Rückgabe steht davor und läge in
   der Malreihenfolge unter der Überdeckung: Ihr Titel (der Zeitpunkt der
   Frist) wäre mit der Maus nie zu sehen. Kein z-index an
   `.lead-zeile-aktionen`: Das schwebende Menü darin muss über den Zeilen
   darunter liegen, ein Stapelkontext dort sperrte es ein. */
.leadtabelle .lead-zeile [title] {
    z-index: 1;
}

/* Der Countdown in der Zelle: dieselbe Ampel wie bisher
   (`.lead-zeile-frist-gefahr/-warnung` oben), ohne die Abstände der
   Kartenzeile — in der Zelle ist er die ganze Angabe. */
.leadtabelle .lead-zeile-frist {
    display: inline;
    margin-top: 0;
}

/* Marker neben dem Namen, mit kleinem Abstand. */
.leadtabelle .lt-lead .badge {
    margin-left: 4px;
}

/* Kontakt unter dem Namen (toloro#4632): Abzeichen, daneben die Zählung,
   die notfalls mit Auslassungspunkten endet — der ganze Satz steht im
   `title`. */
.leadtabelle .lt-kontakt {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 3px;
    overflow: hidden;
}
.lk-abzeichen {
    display: inline-flex;
    align-items: center;
    flex: none;
    gap: 5px;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: var(--text-xs);
    font-weight: 600;
    line-height: 1.5;
}
.lk-abzeichen.lk-nicht_kontaktiert  { background: var(--warning-soft); color: #92400E; }
.lk-abzeichen.lk-nachfassen_faellig { background: var(--bg); color: #92400E;
                                      box-shadow: inset 0 0 0 1.5px var(--warning-text); }
.lk-abzeichen.lk-versuch_laeuft     { background: var(--info-soft); color: #3730A3; }
.lk-abzeichen.lk-unerreichbar       { background: var(--neutral-soft); color: #334155; }
.leadtabelle .lt-kontakt-satz {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

/* Gruppen nach Kontaktstufe: eine Kopfzeile je <tbody>, ohne den
   Großbuchstaben-Stil der Spaltenköpfe. Die ruhigen Gruppen („Versuch
   läuft", „Unerreichbar") liegen auf grauem Grund — dort ist gerade nichts
   zu tun; der Text bleibt voll lesbar. */
.leadtabelle .lt-gruppe-kopf th {
    padding-top: 10px;
    padding-bottom: 8px;
    text-transform: none;
    letter-spacing: 0;
    font-size: var(--text-sm);
    color: var(--text);
    background: var(--warning-soft);
    border-top: 3px solid var(--warning-text);
    border-bottom: 1px solid var(--border);
}
.leadtabelle .lt-gruppe-ruhig .lt-gruppe-kopf th {
    background: var(--bg-muted);
    border-top: 1px solid var(--border-active);
}
.lt-gruppe-titel {
    font-weight: 700;
    margin-right: 8px;
}
.lt-gruppe-hinweis {
    font-weight: 400;
    color: var(--text-secondary);
}
.leadtabelle .lt-gruppe-ruhig .lead-zeile {
    background: var(--bg-subtle);
}

/* „Vollständig" (toloro#3496): ✓ im dunklen Grün von `.badge-success`
   (Symbol, 3:1 genügt; der Ton hält auch 4,5:1), der Strich grau. Der Strich
   füllt die Zelle, damit sein Hinweis („was fehlt") nicht an 7 px hängt. */
.leadtabelle .lt-vollstaendig {
    text-align: center;
}

.lt-haken {
    color: #065F46;
    font-weight: 700;
}

.lt-luecke {
    display: block;
    position: relative;
    color: var(--text-secondary);
}

.lt-luecke-strich {
    display: block;
}

/* Per Tastatur (QA zu toloro#3496): Ein `title` erscheint nur unter der
   Maus. Anliegen (am Laptop „Wa…") und die Lücke in „Vollständig" sind
   deshalb Tabulator-Stopps und zeigen im Fokus, was die Maus im Hinweis
   sieht — das Anliegen ganz, die Lücke den Satz der Vorlesehilfe. Nur bei
   `:focus-visible` (Tastatur), der Mausklick bleibt ruhig. Die Zelle lässt
   dafür ihren Inhalt heraus; z-index 2 liegt über den Hinweisen der
   Nachbarzellen (z-index 1, oben). Den Fokusring bringt die zentrale Regel
   in css/components.css (`[tabindex]:focus-visible`).
   `:has(:focus-visible)` und NICHT `:focus-within`: Ein Mausklick auf den
   Text gibt ihm ebenfalls den Fokus — mit `:focus-within` lief der volle
   Text dann ohne Grund über die Nachbarzellen (gemessen in der QA). */
.leadtabelle td.lt-anliegen:has(.lt-anliegen-text:focus-visible),
.leadtabelle td.lt-vollstaendig:has(.lt-luecke:focus-visible) {
    overflow: visible;
}

.leadtabelle .lt-anliegen-text:focus-visible {
    z-index: 2;
    padding-right: 6px;
    background: var(--bg);
    box-shadow: var(--shadow-md);
}

/* Der Satz bricht um, statt über den Kartenrand zu laufen (gemessen: 571 px
   in einer Zeile, bei 1440 px 20 px hinter dem Rand abgeschnitten) — zwei
   Zeilen passen in die Zeilenhöhe. */
.leadtabelle .lt-luecke:focus-visible .lt-luecke-text {
    left: calc(100% + 6px);
    top: 50%;
    z-index: 2;
    width: max-content;
    max-width: 26rem;
    height: auto;
    white-space: normal;
    text-align: left;
    line-height: 1.35;
    margin: 0;
    padding: 2px 8px;
    overflow: visible;
    clip: auto;
    transform: translateY(-50%);
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
}

/* „Wer" rechtsbündig: Ohne Knopfzeile steht das Kürzel so dicht vor dem
   ⋯-Knopf (zwei Innenabstände), statt eine breite Lücke aufzumachen. */
.leadtabelle .lt-wer {
    text-align: right;
}

/* Rückmeldung überfällig: rot und kräftig — „seit" davor sagt es auch ohne
   Farbe. Der dunkle Ton wie bei der Ampel oben (4,5:1 auf Weiß, #1805). */
.lt-ueberfaellig {
    color: #991B1B;
    font-weight: 600;
}

/* Aktion: EIN Knopf und das ⋯-Menü nebeneinander, rechtsbündig. */
.leadtabelle .lead-zeile-aktionen {
    flex-direction: row;
    justify-content: flex-end;
}

.lt-formular {
    margin: 0;
}

.lt-knopf-link {
    text-decoration: none;
}

/* Schmal gepolstert: Knopf und ⋯-Knopf müssen nebeneinander in die
   Aktionsspalte passen. */
.lt-menue-knopf {
    padding: 4px;
}

/* ── Die Lead-Akte: eine Seite, Kopf mit Primärknopf (toloro#3421) ────
   Bis toloro#3421 trugen Kopf, Karten und Listenzeilen der Akte ihr
   Gerüst im style-Attribut (über fünfzig Stellen). Die Regeln stehen jetzt
   hier, nach den Tokens aus css/tokens.css; die Frist-Farben sind die der
   Liste darüber (`.lead-zeile-frist-*`) — eine Ampel für beide Seiten.

   Aufbau: `.lead-akte-kopf` (links die Sache, rechts Primärknopf + ⋯),
   `.lead-akte-karten` (Kontakt · Anfrage, dasselbe Raster in „Weitere
   Angaben"), `.lead-akte-weitere` (der Aufklapper), die Listenzeilen der
   Versuche und Ereignisse. */
.lead-akte-kopf {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

/* 360 px Grundbreite: Bei 1100 px Fensterbreite passen Sache und
   Primärknopf so noch nebeneinander (QA toloro#3421, gemessen im
   Headless-Chromium; mit 420 px rutschte der Knopf unter die Sache). */
.lead-akte-kopf-sache {
    min-width: 0;
    flex: 1 1 360px;
}

.lead-akte-titel {
    margin: 0;
}

.lead-akte-abzeichen {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    align-items: center;
    margin-top: 6px;
}

.lead-akte-sachzeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    margin-top: 8px;
}

/* Der Countdown in der Sachzeile ist `.lead-zeile-frist` der Liste; dort
   steht er unter der Zeile (margin-top), hier in ihr. */
.lead-akte-sachzeile .lead-zeile-frist {
    margin-top: 0;
}

.lead-akte-sachzeile-wort {
    font-weight: 400;
}

.lead-akte-kopf-zeile {
    margin-top: 6px;
}

/* Rechts: Primärknopf, der Satz darunter, daneben das ⋯. */
/* `margin-left: auto`: Bricht der Kopf doch um (schmaler als ~1050 px),
   bleibt der Primärknopf rechts — „rechts im Kopf" ist die Zusage. */
.lead-akte-kopf-handlung {
    display: flex;
    gap: 6px;
    align-items: flex-start;
    flex: none;
    max-width: 100%;
    margin-left: auto;
}

.lead-akte-primaer {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
    /* 340 px, wie vor !4205 (toloro#3718): Hier steht höchstens EIN Knopf
       („Übernehmen" oder „Bereit zum Auftrag …") und sein Satz. Die 560 px
       aus QA !4205 (U2) trugen drei Entscheidungsknöpfe in einer Zeile —
       die stehen seit toloro#3718 im ⋯-Menü. Nur die Lead-Akte, der
       Projektkopf hat seine eigene Regel. */
    max-width: 340px;
}

.lead-akte-primaer-knoepfe {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.lead-akte-wasjetzt {
    text-align: right;
}

.lead-akte-inline-form {
    display: inline;
    margin: 0;
}

.lead-akte-menue-anker {
    position: relative;
    flex: none;
}

.dropdown-menu.lead-akte-menue {
    min-width: 250px;
}

/* Die Formulare im Klappmenü tragen keinen eigenen Kasten: Ihr Knopf ist
   ein Menüeintrag wie die Nachbarn. */
.lead-akte-menue-form {
    display: contents;
}

.lead-akte-menue-symbol {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

.lt-menue-knopf svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

/* Aufklapper im Kopf („Herkunft und Fristen") und an „Andere Aufgabe
   verknüpfen". */
.lead-akte-aufklapp {
    cursor: pointer;
    width: fit-content;
}

.lead-akte-herkunft {
    margin-top: 8px;
}

.lead-akte-herkunft-raster {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    margin-top: 8px;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-subtle);
}

/* Lead-Akte: der fehlende Storno-Link bei Kanal „Link je Lead" (#3081).
   Er belegt die ganze Rasterzeile — ein Warnkasten in einer 200-px-Spalte
   bräche nach jedem zweiten Wort um. */
.lead-akte-storno-luecke { grid-column: 1 / -1; }

.lead-akte-storno-luecke-satz { margin-bottom: 8px; }

.lead-akte-storno-luecke-wege {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

/* Ablehnen-Dialog: Storno von Hand bei Link und Formular (#3080). */
.lead-ablehnen-storno-satz { margin-bottom: 8px; }

.lead-ablehnen-storno-knoepfe {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: center;
}

/* Ablehnen-Dialog: „Ja, ich habe bereits storniert" (#3528). */
.lead-ablehnen-storniert {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    cursor: pointer;
}

.lead-ablehnen-storniert input { margin-top: 3px; }

.lead-ablehnen-baustein {
    margin-top: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

.lead-ablehnen-baustein-text {
    white-space: pre-wrap;
    margin-top: 8px;
    max-height: 220px;
    overflow-y: auto;
    color: var(--text-secondary);
}

/* Weiterleiten-Dialog (toloro#3680): schmaler als der Ablehnen-Dialog —
   zwei Felder und ein Satz. „Steckbrief ansehen" steht links im Fuß, weg
   von den beiden Knöpfen, die den Dialog beenden. */
.lead-weiterleiten-dialog { max-width: 560px; }

.lead-weiterleiten-steckbrief { margin-right: auto; }

/* Das Banner nach dem Weiterleiten (toloro#3680): „Weitergeleitet an …
   — Übergabepaket herunterladen", der Link darin ist die Handlung. */
.lead-weitergeleitet-banner a { font-weight: 700; }

/* Die Knöpfe der Karte „Dateien" (QA !4205, U13): Übergabepaket und
   Steckbrief als eine Gruppe rechts, der Ordnerpfad bleibt links. */
.lead-akte-dateien-knoepfe {
    display: flex;
    gap: 6px;
    align-items: baseline;
}

.lead-akte-ursprung-form {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-wrap: wrap;
}

.lead-akte-ursprung-feld {
    width: 120px;
}

/* Kontakt · Anfrage, und dasselbe Raster unter „Weitere Angaben". */
.lead-akte-karten {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    gap: 16px;
    margin-bottom: 16px;
}

.lead-akte-karte-kopf {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    flex-wrap: wrap;
}

.lead-akte-knopfreihe {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    align-items: center;
}

.lead-akte-kontaktdaten {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

.lead-akte-rufnummer {
    display: flex;
    gap: 6px;
    align-items: center;
}

/* Die Karte „Anfrage" hat zwei Teile — wo, und was. */
.lead-akte-anfrage-teil + .lead-akte-anfrage-teil {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}

.lead-akte-freitext {
    white-space: pre-wrap;
}

.lead-akte-umbruch {
    word-break: break-all;
}

.lead-akte-roh {
    white-space: pre-wrap;
    word-break: break-word;
    margin: 0;
}

/* „Weitere Angaben" — eingeklappt, mit einer Zusammenfassung, die sagt,
   was drin ist. */
.lead-akte-weitere {
    margin-top: 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
}

.lead-akte-weitere-kopf {
    display: flex;
    gap: 12px;
    align-items: baseline;
    flex-wrap: wrap;
    padding: 12px 16px;
    cursor: pointer;
}

.lead-akte-karten--weitere {
    padding: 0 16px 16px;
    margin-bottom: 0;
}

/* ── Das Lead-Fenster (toloro#3621) ─────────────────────────────────
   Seit dem Lead-Fenster steht der Kopf der Akte in der Mappenkopf-Karte des
   Projektfenster-Layouts; deren Innenabstand ersetzt den Abstand nach unten,
   den der Kopf auf der Einseiten-Akte brauchte. */
.pf-mappenkopf > .lead-akte-kopf {
    margin-bottom: 0;
}

/* Die drei Kennzahlen der Übersicht: Rückmeldung fällig, Rückgabe, nächste
   Aufgabe — nebeneinander, solange Platz ist. */
.lead-kennzahlen {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 16px;
}

/* Termine am Lead — dieselbe Zeile wie im Termine-Reiter der Projektakte,
   rechts die eine Handlung. */
.lead-termin {
    align-items: flex-start;
}

.lead-termin--vergangen {
    opacity: .6;
}

.lead-termin-niemand {
    color: var(--warning-text);
}

/* Listenzeilen der Kontaktversuche und der Ereignisse. */
.lead-akte-listenzeile {
    display: flex;
    gap: 12px;
    padding: 4px 0;
    border-bottom: 1px solid var(--border);
}

.lead-akte-listenzeile--weit {
    padding: 8px 0;
}

.lead-akte-zeitspalte {
    width: 130px;
    flex-shrink: 0;
}

.lead-akte-textspalte {
    flex: 1;
    min-width: 0;
    word-break: break-word;
}

.lead-akte-rechts {
    text-align: right;
}

.lt-menue {
    min-width: 200px;
}

/* ── Projektliste als Tabelle (toloro#2909, Leit #2907 D8) ────────────
   Eine Zeile je Projekt, flach und klein (Listen-Maßstab 11.08.). PC-first:
   1920 px ist der Normalfall, bei ~1000 px darf nichts zerfallen. Deshalb
   `table-layout: fixed` — die Breiten stehen an den Köpfen, und die Zellen
   brechen nicht um, sondern kürzen mit Auslassungspunkten (den vollen Text
   trägt das `title` der Zelle).

   Feste Breiten haben Wappen, Nummer, PLZ Ort, Status und „angelegt" —
   Spalten, deren Inhalt eine bekannte Länge hat. Projekt, Straße,
   Auftraggeber, Bauleiter, Projekttyp und Firma teilen sich den Rest zu
   gleichen Teilen: Eine Prozentbreite je Spalte summierte sich bei 1000 px
   mit den festen Breiten über 100 % und schöbe die Tabelle aus der Karte.

   Ob eine Spalte steht, entscheidet die Vorlage (Monteur/Extern: ohne
   Auftraggeber, Projekttyp, Firma, angelegt — D11). Hier steht nichts, was
   davon abhängt. */
.projekttabelle-karte {
    overflow-x: auto;
}

/* Unter 1024 px deckelt das Layout den Inhalt auf die Tablet-Breite
   (`--content-max`, layout.css) — für Formulare gedacht. Eine Tabelle mit
   elf Spalten zerfiele darin zu Ein-Buchstaben-Zellen; diese Seite nimmt
   deshalb die volle Fensterbreite. Bleibt es dann immer noch zu eng
   (Fenster unter ~950 px), schiebt die Karte waagerecht, statt die Spalten
   weiter zu quetschen (`min-width`). */
.app2-content:has(.projekttabelle) {
    max-width: none;
}

.projekttabelle {
    table-layout: fixed;
    /* Jede Metafeld-Spalte (toloro#2911) hebt die Mindestbreite um ihre
       eigene Breite: Mit allen festen und drei Metafeld-Spalten schiebt die
       Karte bei ~1000 px waagerecht, statt Projekt und Straße auf ein Wort
       zu kürzen. Wer feste Spalten abwählt, gibt deren Platz frei — je feste
       Spalte 100 px, höchstens die 900 px, die Bau 2 für alle festen
       Spalten vorsah. So passen Nummer, Projekt, Ort, Bauleiter, Status und
       drei Metafelder bei 1000 px ohne Schieben. --pt-meta und --pt-fest
       setzt die Vorlage. */
    min-width: calc(min(900px, var(--pt-fest, 9) * 100px) + var(--pt-meta, 0) * 130px);
}

.projekttabelle th,
.projekttabelle td {
    padding: 6px 8px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.projekttabelle .pt-wappen { width: 34px; padding-right: 0; }
.projekttabelle .pt-nummer { width: 98px; font-variant-numeric: tabular-nums; }
.projekttabelle .pt-ort { width: 150px; }
.projekttabelle .pt-status { width: 140px; }
.projekttabelle .pt-angelegt { width: 104px; font-variant-numeric: tabular-nums; }
/* Metafeld-Spalten (toloro#2911): feste Breite — Schadennummer und
   Versicherungsschein-Nr. sind kurz, ein längerer Wert endet in
   Auslassungspunkten und steht voll im `title` der Zelle. */
.projekttabelle .pt-meta { width: 130px; }

/* Die übrigen Spalten teilen sich den Rest zu gleichen Teilen — ausdrücklich
   ohne Breite, damit bei 1000 px nichts über den Kartenrand schiebt. */
.projekttabelle .pt-projekt,
.projekttabelle .pt-strasse,
.projekttabelle .pt-auftraggeber,
.projekttabelle .pt-bauleiter,
.projekttabelle .pt-typ,
.projekttabelle .pt-firma {
    width: auto;
}

/* Auf breiten Schirmen bekommen die kurzen Wörter (Bauleiter, Projekttyp,
   Firma) einen festen Anteil; der Rest geht an Projekt, Straße und
   Auftraggeber, deren Inhalte lang sind. Erst ab 1400 px: Darunter reichte
   die Summe aus Anteilen und festen Breiten über 100 %. */
@media (min-width: 1400px) {
    .projekttabelle .pt-bauleiter { width: 10%; }
    .projekttabelle .pt-typ { width: 9%; }
    .projekttabelle .pt-firma { width: 8%; }
}

/* Um 1000 px herum rücken die festen Spalten zusammen, damit für die
   geteilten mehr bleibt: „geschlossen" passt in 100 px, das Kennzeichen
   „archivierbar" daneben wird dann gekürzt und trägt seinen Satz im
   `title`. */
@media (max-width: 1199px) {
    .projekttabelle th,
    .projekttabelle td { padding: 6px 6px; }
    .projekttabelle .pt-wappen { width: 30px; }
    .projekttabelle .pt-nummer { width: 88px; }
    .projekttabelle .pt-ort { width: 128px; }
    .projekttabelle .pt-status { width: 100px; }
    .projekttabelle .pt-angelegt { width: 96px; }
}

/* Wappen bzw. Mappen-Symbol in Zeilenhöhe — dieselbe Marke wie früher in
   der Kartenliste (#1700), nur kleiner, damit die Zeile flach bleibt. */
.projekttabelle .list-item-icon {
    width: 24px;
    height: 24px;
}

.projekttabelle .list-item-icon svg {
    width: 14px;
    height: 14px;
}

.projekttabelle .list-item-icon--logo {
    padding: 1px;
}

/* Am geschlossenen Projekt wird das Mappen-Symbol gedämpft — das Wappen
   nicht: Ein blass gerechnetes fremdes Logo sähe aus wie ein schlecht
   gedrucktes (#1700). */
.pt-geschlossen .list-item-icon:not(.list-item-icon--logo) {
    background: var(--bg-muted);
    color: var(--text-muted);
}

/* Der Kopf ist ein Link auf dieselbe Liste in anderer Ordnung (D9). */
.pt-kopf {
    color: inherit;
    text-decoration: none;
}

.pt-kopf:hover {
    color: var(--primary);
}

.pt-kopf.ist-aktiv {
    color: var(--text);
}

/* Die ganze Zeile öffnet das Projektfenster (projekt-fenster.js,
   `data-zeilen-link`) — der Zeiger sagt es. */
.pt-zeile {
    cursor: pointer;
}

.pt-projekt-link {
    color: inherit;
    font-weight: 600;
    text-decoration: none;
}

.pt-projekt-link:hover {
    text-decoration: underline;
}

/* Geschlossene Projekte gedämpft wie in der Kartenliste vorher — über die
   Textfarbe, nicht über `opacity`: Ein blass gerechnetes Wappen sähe aus
   wie ein schlecht gedrucktes (#1700). */
.pt-geschlossen td,
.pt-geschlossen .pt-projekt-link {
    color: var(--text-muted);
}

.pt-status .badge {
    margin-left: 4px;
}

/* ── Filterleiste über der Projekttabelle (toloro#2910, Leit #2907 D1/D7) ──
   Eine Zeile aus kompakten Feldern (`form-input--kompakt`), die bei
   schmalem Fenster UMBRICHT — sie klappt nichts auf und schiebt die
   Tabelle nicht aus dem Bild. Jedes Feld trägt seine Beschriftung klein
   darüber; die Breiten sind so gewählt, dass bei 1920 px alles in einer
   Zeile steht und bei ~1000 px zwei Zeilen daraus werden. */
.plf-leiste {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 8px 12px;
}

.plf-feld {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.plf-feld .form-input {
    width: auto;
    max-width: 220px;
}

.plf-name {
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

/* Drei feste Breiten statt „so breit wie der längste Eintrag": Ein
   Bauleiter mit langem Namen soll die Leiste nicht in eine zweite Zeile
   schieben. Summe bei allen Feldern ~1.500 px — passt bei 1920 px in eine
   Zeile, bei ~1000 px werden zwei daraus. */
.plf-feld .plf-schmal {
    width: 132px;
}

.plf-feld .plf-mittel {
    width: 140px;
}

.plf-feld .plf-breit {
    width: 170px;
}

.plf-feld .plf-plz {
    width: 72px;
}

.plf-zeitraum {
    display: flex;
    gap: 4px;
}

.plf-zeitraum .form-input {
    width: 130px;
}

/* Das Häkchen sitzt auf der Linie der Felder, nicht auf ihrer Beschriftung. */
.plf-haken {
    flex-direction: row;
    align-items: center;
    gap: 6px;
    min-height: 32px;
    font-size: var(--text-sm);
}

.plf-knopf {
    min-height: 32px;
}

/* Die Treffer der Parteisuche liegen ÜBER der Tabelle, nicht dazwischen —
   eine Tipphilfe, die die Liste nach unten schiebt, verdrängt genau das,
   was man sehen will. */
.plf-beteiligter {
    position: relative;
}

.plf-treffer {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 30;
    width: 320px;
    max-height: 320px;
    overflow-y: auto;
    margin-top: 2px;
    padding: 4px 0;
    list-style: none;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
}

.plf-treffer-knopf {
    display: block;
    width: 100%;
    padding: 6px 10px;
    border: 0;
    background: none;
    text-align: left;
    font-size: var(--text-sm);
    color: var(--text);
    cursor: pointer;
}

.plf-treffer-knopf:hover,
.plf-treffer-knopf:focus-visible {
    background: var(--bg-subtle);
}

.plf-leer {
    padding: 6px 10px;
}

/* Chips: jeder gesetzte Filter mit ✕, daneben „alle zurücksetzen". */
.plf-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.plf-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 4px 2px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    background: var(--bg-subtle);
    font-size: var(--text-sm);
    color: var(--text);
}

.plf-chip-weg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: var(--radius-full);
    color: var(--text-secondary);
    text-decoration: none;
}

.plf-chip-weg:hover {
    background: var(--bg-muted);
    color: var(--text);
}

.plf-zuruecksetzen {
    margin-left: 4px;
}

/* ── Metafeld-Filter in der Leiste (toloro#2911, D10) ──
   Feld, Bedingung, Wert und „+" in einer Zeile. Welche Eingabe zur Art
   passt, schaltet projektliste-filter.js; ohne Skript stehen alle da. */
.plf-metafeld-zeile {
    display: flex;
    gap: 4px;
    align-items: center;
}

.plf-feld .plf-mf-wert {
    width: 110px;
}

.plf-metafeld-zeile input[type="date"] {
    width: 130px;
}

.plf-metafeld-zeile [hidden] {
    display: none;
}

/* ── Zählzeile mit „Spalten"-Knopf (toloro#2911 Punkt 1) ── */
.pt-zaehlzeile {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

/* Die Trefferzahl darf umbrechen, der Knopf daneben nicht. */
.pt-trefferzahl {
    min-width: 0;
}

.pt-spalten {
    position: relative;
    flex-shrink: 0;
}

/* Die Häkchenliste liegt ÜBER der Tabelle, rechtsbündig am Knopf — wie
   die Tipphilfe des Beteiligten: Sie verdrängt nichts. */
.pt-spaltenwahl {
    position: absolute;
    right: 0;
    top: 100%;
    z-index: 30;
    width: 260px;
    max-height: 70vh;
    overflow-y: auto;
    margin-top: 4px;
    padding: 10px 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
}

.pt-spaltenwahl-titel {
    margin-top: 6px;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
}

.pt-spaltenwahl-zeile {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 0;
    font-size: var(--text-sm);
}

.pt-spaltenwahl-fuss {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 10px;
}

/* ── Mandanten als Tabelle (toloro#3493, Muster Projekt- und Lead-Tabelle) ──
   Eine Zeile je Mandant, einzeilige Zellen, jede Angabe genau einmal
   (app2/admin/mandanten.html). `table-layout: fixed`: Jede Spalte außer
   „Firma" hat eine feste Breite, „Firma" bekommt den Rest; die Karte
   schiebt waagerecht, sobald das Fenster schmaler ist als die Mindestbreite
   der Tabelle (`.card` schnitte sonst ab, Befund 00e0963828).

   ZWEI STUFEN (Entscheidung F4):
     ab 1800 px   alle Spalten wie im Issue — Code und E-Mail eigen
     darunter     Telefon + E-Mail teilen sich „Erreichbarkeit", der Code
                  steht im Kürzel-Abzeichen, die gelben Abzeichen tragen ihre
                  Kurzform
   Was fehlen darf (schwache Hinweise), steht in beiden Stufen nur als „i" —
   mit Wort kostete es in der vollen Zeile die ganze Hauptnummer.

   DIE BREITEN SIND GEMESSEN (Headless-Chromium mit Inter, Zahlen im MR zu
   toloro#3493), nicht geschätzt: Jede feste Spalte trägt die Zeile, in der
   ALLE ihre Abzeichen stehen — ein Abzeichen fällt nie der Auslassung zum
   Opfer; gekürzt wird der Wert daneben (`.mnt-wert`), das Abzeichen
   schrumpft nicht. Die Mindestbreite je Stufe = feste Spalten + „Firma"
   mit allen ihren Abzeichen (mindestens 150 px) und passt in die nutzbare
   Breite des schmalsten Fensters der Stufe MIT klassischer Bildlaufleiste
   (17 px): 1800 px → 1437 px, 1440 px → 1093 px. Das rechnet
   src/test/js/desktop/mandanten-tabelle-breiten.test.js aus genau diesen
   Regeln nach — wer eine Breite ändert, sieht dort, ob sie noch passt. */
.app2-content:has(.mandantentabelle) {
    max-width: none;
}

.mandantentabelle-karte {
    overflow-x: auto;
}

/* Ab 1440 px passt die Tabelle in die Karte (Mindestbreite ≤ nutzbare
   Breite, die Breiten-Probe rechnet es nach) — dort ist die Karte KEIN
   Rollbereich, sondern ragt heraus lassend wie `.card-has-menu` (QA zu
   toloro#3493). Ein waagerechter Rollbereich schneidet auch senkrecht ab
   (`overflow-x: auto` macht `overflow-y` zu `auto`), und die Tabelle hat
   nur eine Handvoll Zeilen: Gemessen reichte der Fokus-Kasten eines langen
   Hinweises (Verwechslung, Lücken der Mail-Marke, ≈ 7 Zeilen) bei zwei
   oder drei Zeilen weder nach unten noch nach oben in die Karte — die
   Tastatur las nur die ersten drei Zeilen des Satzes. Darunter schiebt die
   Karte wie gehabt. */
@media (min-width: 1440px) {
    .mandantentabelle-karte {
        overflow: visible;
    }
}

/* Ohne Beschnitt ragten die Ecken des Kopfes über die Rundung der Karte. */
.mandantentabelle thead th:first-child {
    border-top-left-radius: calc(var(--radius-md) - 1px);
}

.mandantentabelle thead th:last-child {
    border-top-right-radius: calc(var(--radius-md) - 1px);
}

.mandantentabelle {
    table-layout: fixed;
    /* 1203 px feste Spalten + 218 px „Firma" mit allen drei Abzeichen
       (ausgemustert 87,9 + Verwechslung 90,3 + „i" 16,9, drei Lücken à 4 px
       zwischen Wert und Abzeichen, Innenabstand 10). */
    min-width: 1421px;
    /* Bezugsrahmen der `sr-only`-Texte (Kopf „Aktion", Vorlesetexte der
       Abzeichen): Ohne ihn hinge ihre Lage an einem Vorfahren AUSSERHALB
       der schiebenden Karte und machte die Seite unsichtbar breiter
       (gemessen an der Lead-Tabelle, QA zu toloro#3496). */
    position: relative;
}

.mandantentabelle th,
.mandantentabelle td {
    padding: 6px 5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Maßstab je Spalte (gemessen, Inhalt + 2 × Innenabstand) — was nie gekürzt
   wird: Kopf „KÜRZEL" 50 · „CODE" 36 · „GEÄNDERT" 70 · Sitz: Wert +
   „keine Betriebsstätte" 120,2 · Telefon: Hauptnummer „+49 681 410 99 466"
   ≈ 133 + Hörer 19 (15 px Symbol + 4 px Rand, `.hoerer`) + „+2" 14,9 · Register: Wert + „USt-Id fehlt" 74,9 +
   „Gericht fehlt" 80 · Mail-Marke: Wert + „unvollständig" 85,7 + „i" 16,9 ·
   Aktion: „Stammdaten" 121,8 + ⋯ 26. */
.mandantentabelle .mnt-kuerzel     { width: 60px; }
.mandantentabelle .mnt-firma       { width: auto; }
.mandantentabelle .mnt-code        { width: 46px; }
.mandantentabelle .mnt-sitz        { width: 135px; }
.mandantentabelle .mnt-erreichbarkeit { width: 185px; }
.mandantentabelle .mnt-email       { width: 144px; }
.mandantentabelle .mnt-register    { width: 173px; }
.mandantentabelle .mnt-bank        { width: 90px; }
.mandantentabelle .mnt-marke       { width: 128px; }
.mandantentabelle .mnt-geaendert   { width: 80px; font-variant-numeric: tabular-nums; }
.mandantentabelle .mnt-aktion      { width: 162px; overflow: visible; }

/* Lang- und Kurzform: `mnt-breit` steht nur ab 1800 px, `mnt-schmal` nur
   darunter — Kopf „Telefon"/„Erreichbarkeit", Code im Kürzel, Wörter in den
   Abzeichen. Vorlesehilfen hören den vollen Satz (`sr-only` daneben). */
.mandantentabelle .mnt-schmal { display: none; }

@media (max-width: 1799px) {
    /* 874 px feste Spalten + 219 px „Firma" = 1093 px: genau die nutzbare
       Breite bei 1440 px mit Bildlaufleiste. „Firma" braucht mit allen
       drei Abzeichen 216 px. */
    .mandantentabelle { min-width: 1093px; }
    .mandantentabelle th,
    .mandantentabelle td { padding: 6px 4px; }
    .mandantentabelle .mnt-kuerzel     { width: 64px; }
    .mandantentabelle .mnt-sitz        { width: 100px; }
    .mandantentabelle .mnt-erreichbarkeit { width: 164px; }
    .mandantentabelle .mnt-register    { width: 118px; }
    .mandantentabelle .mnt-bank        { width: 80px; }
    .mandantentabelle .mnt-marke       { width: 120px; }
    .mandantentabelle .mnt-geaendert   { width: 78px; }
    .mandantentabelle .mnt-aktion      { width: 150px; }
    .mandantentabelle .mnt-code,
    .mandantentabelle .mnt-email       { display: none; }
    .mandantentabelle .mnt-breit       { display: none; }
    .mandantentabelle .mnt-schmal      { display: inline; }
    .mandantentabelle .mnt-abz.mnt-schmal { display: inline-flex; }
    .mandantentabelle .mnt-stammdaten  { padding-left: 10px; padding-right: 10px; }
}

/* Die Zelle: Wert, Abzeichen und Hörer nebeneinander. Nur der Wert
   schrumpft (mit Auslassungspunkten); Abzeichen, „+n" und Hörer nie. */
.mnt-zelle {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    /* Bezugsrahmen des Fokus-Kastens eines Werts (unten): Der Wert selbst
       kürzt mit `overflow: hidden` und schnitte den Kasten sonst ab. */
    position: relative;
}

.mnt-zelle > * {
    flex: none;
}

.mnt-zelle > .mnt-wert {
    flex: 0 1 auto;
    min-width: 0;
}

/* Die Firma ist der Name der Zeile — er darf nicht hinter seinen
   Abzeichen verschwinden (QA zu toloro#3493). Gemessen mit der schlimmsten
   Zeile (ausgemustert + Verwechslung + „i"): Die Abzeichen brauchen 207 px,
   „Firma" hat bei 1440 px 211 px und bei 1800 px 225 px Innenraum — für den
   Namen blieben 4 bzw. 18 px, also nur die Auslassungspunkte. Deshalb, NUR
   hier: Reicht der Platz nicht für den Namen mit 5,5 rem (88 px) und alle
   Abzeichen, brechen die Abzeichen in eine zweite Zeile um. Die Grundbreite
   entscheidet den Umbruch; danach wächst der Name bis zu seiner vollen
   Breite (`max-width: max-content` — die Abzeichen bleiben dicht am Namen).
   Kein Abzeichen wird gekürzt (F5), die Zeile wird 6 px höher, und das nur
   dort, wo es sonst keinen Namen gäbe. Andere Zellen tauschen weiter den
   Wert gegen das Abzeichen (F5: der Wert steht dann im Hinweis). */
.mandantentabelle .mnt-firma .mnt-zelle {
    flex-wrap: wrap;
    row-gap: 2px;
}

.mandantentabelle .mnt-firma .mnt-zelle > .mnt-wert {
    flex: 1 1 5.5rem;
    max-width: max-content;
}

.mnt-wert {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

/* „+2" hinter Sitz und Hauptnummer: weitere Betriebsstätten bzw. Nummern,
   die Liste im Hinweis. */
.mnt-mehr {
    color: var(--text-secondary);
    font-size: var(--text-xs);
}

/* Das Kürzel-Abzeichen kürzt selbst, falls statt der Abkürzung der Name
   einspringt (`abkuerzungOderErsatz`). */
.mandantentabelle .mnt-kuerzel-abz {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
}

/* Die drei Gewichte (Entscheidung F5): rot = `badge-danger`, gelb =
   `badge-warning`, schwach = dieses hier — ohne Fläche, nur ein feiner
   Rand, damit dauerhaft offene „darf fehlen"-Angaben nicht zum Wegsehen
   erziehen. Der Rand ist ein Schatten nach innen und zählt nicht zur
   Breite (die Messung gilt für alle drei gleich). */
.mnt-schwach {
    background: var(--bg);
    color: var(--text-secondary);
    box-shadow: inset 0 0 0 1px var(--border);
}

.mnt-abz {
    position: relative;
    cursor: help;
}

/* Mail-Marke: die zwei Hausfarben als Felder, die Farbe steht als
   Variable am Feld (`--farbe`), die Regel hier (kein Stil im Markup). */
.mnt-farbe {
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-right: 3px;
    border-radius: 3px;
    border: 1px solid var(--border);
    background: var(--farbe, transparent);
    vertical-align: -1px;
}

.mnt-ausgemustert td:not(.mnt-aktion) {
    color: var(--text-muted);
}

.mnt-ausgemustert .mnt-farbe {
    opacity: .5;
}

/* Per Tastatur (Lehre aus der QA zu toloro#3496): Ein `title` erscheint
   nur unter der Maus. Wert und Abzeichen sind deshalb Tabulator-Stopps und
   klappen im Fokus den Kasten auf, der den Hinweis ausschreibt — den vollen
   Wert samt Nebenwerten bzw. den ganzen Satz des Dienstes. Nur bei
   `:focus-visible` (Tastatur): Ein Mausklick fokussiert ebenfalls, und der
   Kasten liefe dann ohne Grund über die Nachbarn. `:has(:focus-visible)`
   und NICHT `:focus-within` — aus demselben Grund. Aufgeklappt wird unter
   dem Wert, in der rechten Tabellenhälfte nach links, in der letzten Zeile
   nach oben: Die Karte schiebt waagerecht und schnitte ihn sonst ab. Den
   Fokusring bringt die zentrale Regel in css/components.css. */
.mandantentabelle td:has(:focus-visible) {
    overflow: visible;
}

.mandantentabelle :focus-visible > .mnt-tipp {
    left: 0;
    top: calc(100% + 4px);
    z-index: 2;
    width: max-content;
    max-width: 26rem;
    height: auto;
    margin: 0;
    padding: 4px 8px;
    overflow: visible;
    clip: auto;
    white-space: normal;
    text-align: left;
    line-height: 1.35;
    font-size: var(--text-xs);
    font-weight: 400;
    text-transform: none;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
}

.mandantentabelle .mnt-register :focus-visible > .mnt-tipp,
.mandantentabelle .mnt-bank :focus-visible > .mnt-tipp,
.mandantentabelle .mnt-marke :focus-visible > .mnt-tipp,
.mandantentabelle .mnt-geaendert :focus-visible > .mnt-tipp {
    left: auto;
    right: 0;
}

.mandantentabelle tbody tr:last-child :focus-visible > .mnt-tipp {
    top: auto;
    bottom: calc(100% + 4px);
}

/* Aktion: „Stammdaten" und das ⋯-Menü nebeneinander, rechtsbündig. */
.mnt-aktionen {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
}

.mnt-menue {
    display: inline-flex;
    flex: none;
}

.mnt-menue-knopf {
    padding: 4px;
}

.mnt-menue-knopf svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

.mnt-menue-liste {
    min-width: 180px;
    white-space: nowrap;
    text-align: left;
}

/* „Entfernen" rot — derselbe dunkle Ton wie `.badge-danger` (4,5:1). */
.mandantentabelle .mnt-entfernen {
    color: #991B1B;
}

/* Nur unter 1800 px enger gepolstert (Medienblock oben); die Klasse
   steht, damit der Knopf dort gemeint werden kann. */
.mnt-stammdaten {
    white-space: nowrap;
}

.mandantentabelle .mnt-leer {
    padding: 12px 6px;
    white-space: normal;
    color: var(--text-muted);
}

/* ── Benutzerverwaltung als Tabelle (toloro#3492, Muster Lead- und
   Mandantentabelle) ──────────────────────────────────────────────────
   Eine Zeile je Benutzer, einzeilige Zellen, jede Angabe genau einmal
   (app2/access.html). `table-layout: fixed`: Jede Spalte außer „Name" hat
   eine feste Breite, „Name" bekommt den Rest; die Karte schiebt waagerecht,
   sobald das Fenster schmaler ist als die Mindestbreite.

   DREI STUFEN (Entscheidung F6, wie die Leads):
     ab 1800 px   alle Spalten — Funktion, Nebenstelle und Diensthandy eigen
     1536–1799    Funktion in den Hinweis der Rolle; Nebenstelle und
                  Diensthandy teilen sich „Telefon"
     darunter     dazu der letzte Login in den Hinweis der Zugang-Zelle
   Zugang, Aktion und die Spaltenköpfe werden nie gekürzt; Werte (Name,
   Anmeldename, Funktion, Rufnummer) kürzen mit Auslassung, voll im Hinweis.

   DIE BREITEN SIND GEMESSEN (Headless-Chromium mit Inter, Zahlen im MR zu
   toloro#3492 und in src/test/js/desktop/benutzer-tabelle-breiten.test.js):
   Zugang — der längste Zustand „✉ Passwort-Link offen · noch 48 Std."
   246 px (der Link nimmt Passkeys und API-Zugänge mit, daneben steht also
   kein Schlüssel); „⏸ Deaktiviert 12.09.25 (ABC)" + API 1 236 px.
   „Eingeladen" heißt nie angemeldet — ohne Anmeldung gibt es weder Passkey
   noch API-Zugang; stünde doch einer da, bricht er um (unten). Aktion
   „Desktop-Link kopieren" (btn-xs) 152 px bzw. „Wieder aktivieren" 123 px
   + ⋯ 26 px. Die Rechnung hält benutzer-tabelle-breiten.test.js fest. */
.app2-content:has(.benutzertabelle) {
    max-width: none;
}

.benutzertabelle-karte {
    overflow-x: auto;
}

.benutzertabelle {
    table-layout: fixed;
    /* 1288 px feste Spalten + 149 px „Name" = 1437 px: die nutzbare Breite
       bei 1800 px mit Bildlaufleiste. */
    min-width: 1437px;
    /* Bezugsrahmen der `sr-only`-Texte (QA zu toloro#3496): ohne ihn
       hinge ihre Lage außerhalb der schiebenden Karte. */
    position: relative;
}

.benutzertabelle th,
.benutzertabelle td {
    padding: 6px 5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Maßstab je Spalte (gemessen, Inhalt + 2 × Innenabstand):
   Anmeldename  Kopf „ANMELDENAME ↓" 115 · Rolle „Administration" 95
   Nebenst.     Kopf „NEBENST. ↓" 78 · Diensthandy „+49 176 12345678" 122 + Hörer
   Zugang       246 (siehe oben) · Login „28.08.25 08:08" 102
   Merkmale     Kopf „MERKMALE" 72, Kurzwort-Abzeichen, umbrechend
   Aktion       „Desktop-Link kopieren" 152 + ⋯ 26 */
.benutzertabelle .bt-name        { width: auto; }
.benutzertabelle .bt-anmeldename { width: 126px; }
.benutzertabelle .bt-rolle       { width: 106px; }
.benutzertabelle .bt-funktion    { width: 90px; }
.benutzertabelle .bt-firmen      { width: 76px; }
.benutzertabelle .bt-nebenstelle { width: 88px; font-variant-numeric: tabular-nums; }
.benutzertabelle .bt-diensthandy { width: 156px; }
.benutzertabelle .bt-telefon     { width: 154px; display: none; }
.benutzertabelle .bt-zugang      { width: 258px; }
.benutzertabelle .bt-login       { width: 112px; }
.benutzertabelle .bt-merkmale    { width: 84px; }
.benutzertabelle .bt-aktion      { width: 192px; overflow: visible; }

/* Lang- und Kurzform des Kopierknopfs: „App-Link kopieren" ab 1800 px,
   darunter „Link kopieren" (Leitplanken b5); der Hinweis nennt immer die
   Fassung samt Adresse. „↓ Login" am Kopf „Zugang" nur unter 1536 px. */
.benutzertabelle .bt-schmal { display: none; }
.benutzertabelle .bt-nur-eng { display: none; }

@media (max-width: 1799px) {
    /* 1062 px feste Spalten + 111 px „Name" = 1173 px: die nutzbare
       Breite bei 1536 px mit Bildlaufleiste. Der Name hat hier am
       wenigsten Platz — bei 1680 px sind es schon 255 px. „Telefon"
       trägt „— · kein Diensthandy" (144 px) ganz. */
    .benutzertabelle { min-width: 1173px; }
    .benutzertabelle th,
    .benutzertabelle td { padding: 6px 4px; }
    .benutzertabelle .bt-anmeldename { width: 123px; }
    .benutzertabelle .bt-rolle       { width: 104px; }
    .benutzertabelle .bt-firmen      { width: 72px; }
    .benutzertabelle .bt-telefon     { width: 154px; display: table-cell; }
    .benutzertabelle .bt-zugang      { width: 256px; }
    .benutzertabelle .bt-login       { width: 110px; }
    .benutzertabelle .bt-merkmale    { width: 81px; }
    .benutzertabelle .bt-aktion      { width: 162px; }
    .benutzertabelle .bt-funktion,
    .benutzertabelle .bt-nebenstelle,
    .benutzertabelle .bt-diensthandy { display: none; }
    .benutzertabelle .bt-breit       { display: none; }
    .benutzertabelle .bt-schmal      { display: inline; }
}

@media (max-width: 1535px) {
    /* 952 px feste Spalten + 141 px „Name" = 1093 px: genau die nutzbare
       Breite bei 1440 px mit Bildlaufleiste. Der letzte Login steht hier
       im Hinweis der Zugang-Zelle (F6) — so kürzt der Name zuletzt. */
    .benutzertabelle { min-width: 1093px; }
    .benutzertabelle .bt-login       { display: none; }
    .benutzertabelle .bt-nur-eng     { display: inline; }
}

/* Die Zelle: Teile nebeneinander, nur der Wert schrumpft (mit
   Auslassungspunkten) — Abzeichen, Hörer und Zeichen nie. */
.bt-zelle {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
}

.bt-zelle > * {
    flex: none;
}

.bt-zelle > .bt-wert {
    flex: 0 1 auto;
    min-width: 0;
}

.bt-wert {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

/* Der Name ist der Name der Zeile — er verschwindet nicht hinter seinen
   Abzeichen („✓ gerade gespeichert", „🔒 Toloro GmbH", „passt nicht zur
   Suche"): Reicht der Platz nicht für 5,5 rem Name und alle Abzeichen,
   brechen die Abzeichen in eine zweite Zeile um (Muster Mandantentabelle,
   QA zu toloro#3493). */
.benutzertabelle .bt-name .bt-zelle {
    flex-wrap: wrap;
    row-gap: 2px;
}

.benutzertabelle .bt-name .bt-zelle > .bt-wert {
    flex: 1 1 5.5rem;
    max-width: max-content;
}

/* Kürzel-Abzeichen der Firmen und Merkmale: umbrechen statt kürzen —
   ein Abzeichen fällt nie der Auslassung zum Opfer; die Zeile wird nur
   dort höher, wo es sonst nicht passte. */
.benutzertabelle .bt-abzeichenreihe {
    flex-wrap: wrap;
    row-gap: 2px;
}

/* Zugang: Jeder Zustand mit den Schlüsseln, die er haben kann, passt in
   eine Zeile. Stünde doch einmal mehr da (die Zeile der Leitplanken,
   „Eingeladen · noch 6 Tage" mit 🔐 2 und API 1, 266 px — ein nie
   angemeldetes Konto hat beides nicht), rutscht ein Schlüssel in die
   zweite Zeile — gekürzt wird nichts. */
.benutzertabelle .bt-zugang .bt-zelle {
    flex-wrap: wrap;
    row-gap: 2px;
}

/* Der Tastatur-Fokus an Wert und Abzeichen wird nicht von der Zelle
   abgeschnitten (Muster Mandantentabelle). */
.benutzertabelle td:has(:focus-visible) {
    overflow: visible;
}

.bt-bild {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: var(--radius-full);
    overflow: hidden;
    background: var(--bg-muted);
    color: var(--text-secondary);
    font-size: var(--text-xs);
    font-weight: 700;
}

.bt-bild img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.bt-bild--gross {
    width: 56px;
    height: 56px;
    font-size: var(--text-lg);
}

.bt-kuerzel,
.bt-du,
.bt-blass {
    color: var(--text-secondary);
}

.bt-kuerzel {
    font-size: var(--text-xs);
}

.bt-mailzeichen {
    color: var(--text-secondary);
    cursor: help;
}

/* Die schwache Lücke („keine E-Mail") — Sprache der Mandantentabelle. */
.bt-schwach {
    background: var(--bg);
    color: var(--text-secondary);
    box-shadow: inset 0 0 0 1px var(--border);
}

/* Zugang: Zeichen und Wort, die Farbe nur dazu (Kontrast ≥ 4,5:1 auf Weiß). */
.bt-stand {
    font-weight: 600;
    white-space: nowrap;
}

.bt-stand--aktiv { color: #166534; }
.bt-stand--offen { color: #1E40AF; }
.bt-stand--abgelaufen { color: #92400E; }
.bt-stand--ohne { color: var(--text-secondary); font-weight: 500; }
.bt-stand--deaktiviert { color: #991B1B; }
.bt-stand--support { color: var(--text-secondary); }

.bt-schluessel {
    background: var(--bg-muted);
    color: var(--text);
}

/* Die deaktivierte Zeile: gedimmt werden die Datenzellen, nicht die
   Aktionszelle — das schwebende Menü erbte sonst die Blässe (Stolperstein
   6 der Mandantentabelle). */
.bt-zeile--deaktiviert td:not(.bt-aktion):not(.bt-zugang) {
    color: var(--text-muted);
}

/* Gerade gespeichert und Ausnahmezeile: Rand UND Wort, nie Farbe allein
   (#724). Die Ausnahme passt nicht (mehr) zum Filter — beim nächsten Laden
   ist sie weg. */
.bt-zeile--gespeichert td:first-child,
.bt-zeile--ziel td:first-child {
    box-shadow: inset 3px 0 0 var(--success);
}

.bt-zeile--ausnahme td {
    background: var(--warning-soft);
}

.bt-zeile--ausnahme td:first-child {
    box-shadow: inset 3px 0 0 var(--warning);
}

/* Die Meldungszeile unter einer Zeile: Rückmeldung nach der Handlung bzw.
   der Satz der Ausnahmezeile (Stolperstein 14). */
.bt-meldungszeile td {
    white-space: normal;
    padding-top: 4px;
    padding-bottom: 8px;
}

.bt-meldungszeile--ausnahme td {
    background: var(--warning-soft);
}

.bt-meldung {
    font-size: var(--text-sm);
    white-space: pre-line;
}

.bt-meldung + .bt-meldung {
    margin-top: 4px;
}

.bt-meldung--fehler { color: #991B1B; }
.bt-meldung--erfolg { color: #166534; }
.bt-meldung--warnung { color: #92400E; }
.bt-meldung--ausnahme { color: #92400E; }

.bt-suchhinweis {
    font-size: var(--text-xs);
    color: #92400E;
    /* Steht im Namen und darf dort umbrechen — die Zelle ist schmal. */
    white-space: normal;
}

.bt-link {
    background: none;
    border: none;
    padding: 0;
    color: var(--primary);
    text-decoration: underline;
    cursor: pointer;
    font: inherit;
}

/* Aktion: EIN Knopf und das ⋯-Menü nebeneinander, rechtsbündig. */
.bt-aktionen {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
}

.bt-formular {
    margin: 0;
}

/* Die Haupthandlung schrumpft nicht unter ihre Beschriftung — die Spalte
   ist für sie gemessen. */
.bt-primaer,
.bt-formular {
    flex: none;
}

/* Ziffern, die man untereinander vergleicht: Nebenstelle im „Telefon"
   und die Zahl im Seitenkopf. */
.bt-nst,
.bt-zahl {
    font-variant-numeric: tabular-nums;
}

/* Das Feld, an dem die Ablehnung hängt (Bruch 4): Rand UND der Satz
   darüber, nie Farbe allein. */
.bt-feld-fehler {
    border-color: var(--danger);
    box-shadow: 0 0 0 1px var(--danger);
}

.bt-menue {
    display: inline-flex;
    flex: none;
}

.bt-menue-knopf {
    padding: 4px;
}

.bt-menue-knopf svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

.bt-menue-liste {
    min-width: 210px;
    white-space: nowrap;
    text-align: left;
}

.benutzertabelle .bt-gefahr {
    color: #991B1B;
}

/* „Kopiert ✓" ersetzt den Knopftext zwei Sekunden lang (benutzer-tabelle.js). */
.bt-kopiert {
    display: none;
}

.bt-kopieren.ist-kopiert .bt-kopieren-text {
    display: none;
}

.bt-kopieren.ist-kopiert .bt-kopiert {
    display: inline;
}

/* Kopf der Seite, Filterleiste, Klappbereich „Externen anlegen". */
.bt-seitenkopf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}

.bt-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 8px 12px;
    margin-bottom: 12px;
}

.bt-suche {
    flex: 1 1 280px;
    max-width: 420px;
}

.bt-filter-feld {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.bt-dienstadressen {
    margin-left: auto;
}

.bt-anlegen-kopf {
    padding: 12px 16px;
    cursor: pointer;
    font-weight: 600;
}

.bt-anlegen-rumpf {
    padding: 0 16px 16px;
}

.bt-feld-180 {
    width: 180px;
}

.bt-haken {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    font-size: var(--text-sm);
}

.bt-haken input {
    width: 16px;
    height: 16px;
    accent-color: var(--primary);
}

/* Die Dialoge: Bearbeiten breit (Raster), die übrigen schmal. */
.modal.bt-dialog {
    max-width: 860px;
}

.modal.bt-dialog--schmal {
    max-width: 520px;
}

.bt-raster {
    display: grid;
    grid-template-columns: repeat(2, minmax(220px, 1fr));
    gap: 12px 16px;
}

.bt-haken-spalte {
    display: flex;
    flex-direction: column;
    gap: 6px;
    justify-content: flex-end;
}

.bt-pillen {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 6px;
}

.bt-pille {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    background: var(--bg);
    font-size: var(--text-sm);
    cursor: pointer;
}

.bt-pille input {
    width: 14px;
    height: 14px;
    accent-color: var(--primary);
}

.bt-bildflaeche {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

.bt-bildtext {
    flex: 1;
    min-width: 0;
}

.bt-unsichtbar {
    display: none;
}

.bt-folgen {
    margin: 0;
    padding-left: 18px;
}

.bt-text-fehler { color: #991B1B; }
.bt-text-gut { color: #166534; }
.bt-text-warnung { color: #92400E; }
.bt-text-hinweis { color: var(--text-secondary); }

.bt-knopf-gefahr {
    color: #991B1B;
    border-color: #991B1B;
}

/* ── Projektakte · Termine-Reiter: Ereigniszeilen (toloro#3320) ────────
   Zwischen den Terminzeilen (.list-item) stehen Freigaben und Versände
   als farbig hinterlegtes Band — Matthias' „andersfarbig hinterlegte
   Zeile" (25.09.2026, Variante A). Symbolspalte und Datumsspalte fluchten
   mit den Terminzeilen (40 px Symbol + 12 px Abstand), damit das Auge
   beim Scrollen eine Datumsspalte hat. Textfarben mit Kontrast ≥ 4,5:1
   auf ihrem Band (#065F46 auf --success-soft 6,8:1; #9A4A12 auf
   --accent-soft 5,4:1) — .badge-accent wäre mit 3,5:1 zu blass für
   Fließtext. */
.termin-ereignis {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 16px;
    border-bottom: 1px solid var(--border);
    font-size: var(--text-sm);
    line-height: 1.4;
}
.termin-ereignis:last-child { border-bottom: none; }
.termin-ereignis-icon {
    width: 40px;
    flex-shrink: 0;
    display: flex;
    justify-content: center;
}
.termin-ereignis-icon svg { width: 20px; height: 20px; fill: currentColor; }
.termin-ereignis-datum {
    flex-shrink: 0;
    width: 150px;
    font-variant-numeric: tabular-nums;
    font-size: var(--text-xs);
    font-weight: 600;
}
.termin-ereignis-text {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
}
.termin-ereignis-titel { font-weight: 600; }
/* Der Nebensatz ist nur kleiner, nicht blasser: eine Abblendung fiele
   auf dem orangen Band unter 4,5:1 (0,8 → 3,7:1). */
.termin-ereignis-neben { font-size: var(--text-xs); }
.termin-ereignis--freigabe { background: var(--success-soft); color: #065F46; }
.termin-ereignis--versand  { background: var(--accent-soft);  color: #9A4A12; }

/* ═══════════════════════════════════════════════════════════════
   Mitteilungen (/desktop/admin/mitteilungen) — Empfänger (toloro#3325)
   ═══════════════════════════════════════════════════════════════ */

/* Die Rollen zur Wahl: ein Raster, das mit der Breite wächst — acht
   Rollen untereinander wären eine Liste, die keiner überblickt. */
.mitteilung-rollen {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 8px 24px;
  padding-left: 24px;
}

/* Bei „Alle Rollen“ sind die Haken gesperrt und treten zurück —
   gedimmt über eine Klasse, nicht über :style (#2764). */
.mitteilung-rollen--gedimmt {
  opacity: 0.5;
}


/* ═══ Versanddialog: „Was Frau Degen bekommt" (toloro#3244) ═══════════
   Links Anschrift, Weg und Beilagen, rechts die Kundensicht. Flex statt
   Raster: Bleibt die rechte Spalte leer (kein Toloro-Angebot, oder das
   Fragment kam leer zurück), nimmt die linke die ganze Breite — ein
   Raster hielte ihr die halbe Seite frei. Unter 900 px stehen beide
   untereinander (flex-wrap über die Grundbreiten). */
.versand-kundensicht--zweispaltig {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: flex-start;
}

.versand-kundensicht--zweispaltig > .versand-kundensicht__links {
    flex: 1 1 380px;
    min-width: 0;
}

.versand-kundensicht__rechts {
    flex: 1 1 340px;
    min-width: 0;
    margin-top: 12px;
}

/* Nicht :empty — das leere Fragment (KEINE, Fehler beim Aufbau) kommt als
   Zeilenumbruch zurück, und ein Textknoten aus Leerraum hebt :empty auf.
   Dann stünde rechts eine leere halbe Seite (QA toloro#3244). Gezählt
   werden deshalb Elemente: ohne Element kein Platz. */
.versand-kundensicht__rechts:not(:has(*)) {
    display: none;
}

.kundensicht {
    padding: 12px 14px;
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

.kundensicht__kopf {
    font-weight: 600;
    font-size: var(--text-sm);
    margin-bottom: 8px;
}

.kundensicht__block + .kundensicht__block {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
}

.kundensicht__titel {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: 6px;
}

.kundensicht__kopfzeilen {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 2px 10px;
    overflow-wrap: anywhere;
}

/* Feste Höhe: An den Inhalt eines rechtlosen Rahmens kommt die Seite nicht
   heran (wie in „Mail ansehen"). Weiß, weil die Mail beim Kunden weiß ist. */
.kundensicht__rahmen {
    display: block;
    width: 100%;
    height: 340px;
    margin-top: 6px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.kundensicht__blatt {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: var(--text-sm);
    cursor: pointer;
}

.kundensicht__blatt input {
    margin-top: 3px;
}

.kundensicht__zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    margin-top: 4px;
}

.kundensicht__umschalter {
    display: inline-flex;
    gap: 14px;
    font-size: var(--text-sm);
}

.kundensicht__umschalter label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    cursor: pointer;
}

.kundensicht__zahl {
    width: 72px;
    margin-left: 4px;
}

.kundensicht-leiste {
    list-style: none;
    margin: 0;
    padding: 0 0 0 12px;
    border-left: 2px solid var(--border);
    font-size: var(--text-sm);
}

.kundensicht-leiste__punkt {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 8px;
    padding: 2px 0;
}

.kundensicht-leiste__tag {
    min-width: 72px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

/* Eine Aufgabe beim Büro ist kein Kontakt zum Kunden — leiser gesetzt. */
.kundensicht-leiste__punkt--aufgabe {
    color: var(--text-secondary);
}

/* ══════════════════════════════════════════════════════════════
   Lead-Geber: Tabelle und Detailseite mit Reitern (#3422)
   templates/app2/verwaltung/lead-geber.html und lead-geber-detail.html
   ══════════════════════════════════════════════════════════ */

.lg-kopf {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    flex-wrap: wrap;
}

.lg-zurueck {
    display: inline-block;
    margin-bottom: 8px;
    color: var(--text-secondary);
    text-decoration: none;
}

.lg-zurueck:hover { color: var(--primary); }

.lg-abzeichen {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 6px;
}

.lg-kennzahlen { padding-top: 6px; }

.lg-leer { padding: 32px 24px; }

/* Eine Karte ohne Kopf: .card-body polstert oben mit 0 (es erwartet einen
   .card-header darüber) — hier sitzt der Text sonst an der Oberkante. */
.lg-ohne-kopf { padding-top: 16px; }

/* ── Tabelle ─────────────────────────────────────────────────── */
/* Muster Lead-Tabelle (!3955, #3472): feste Breiten für die Spalten mit
   bekannter Länge, der Name bekommt den Rest (`auto`). Die Mindestbreite
   ist die Summe der festen Spalten plus ein lesbarer Name (~220 px) —
   darunter schiebt die Karte waagerecht, statt den Namen auf „U…" zu
   quetschen und „Letzter Eingang" über den Rand zu schieben (bis #3472:
   842 px fest bei 880 px Mindestbreite, gemessen bei 1100 px). */
.lg-tabelle-karte { overflow-x: auto; }

.lg-tabelle {
    width: 100%;
    /* 922 px fest + 220 px Name; unter 1800 px: 834 + 200. */
    min-width: 1142px;
    table-layout: fixed;
}

.lg-tabelle th,
.lg-tabelle td {
    padding: 8px 10px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: left;
}

/* Die Köpfe dürfen umbrechen: „Leads diesen Monat / offen" und
   „Rückgabefrist" in Versalien passen nicht in die Spaltenbreite der
   Werte, und abgeschnitten („RÜCKGABE…") sagt der Kopf nicht mehr, was
   darunter steht (QA #3422, 1440 px). */
.lg-tabelle th {
    white-space: normal;
    overflow: visible;
    vertical-align: bottom;
}

.lg-tabelle .lg-name { width: auto; }
.lg-tabelle .lg-aktiv { width: 96px; }
.lg-tabelle .lg-eingang { width: 160px; }
/* „Storno-Adresse, eigene Vorlage" ist der längste Kurztext des
   Absage-Wegs (LeadGeberAnzeige.absageKurz) — die Spalte trägt ihn ganz. */
.lg-tabelle .lg-absage { width: 260px; }
.lg-tabelle .lg-frist { width: 136px; }
.lg-tabelle .lg-zahl { width: 150px; font-variant-numeric: tabular-nums; }
.lg-tabelle .lg-letzter { width: 120px; font-variant-numeric: tabular-nums; }

/* Unter 1800 px (Laptops um 1440/1366, Büroschirme um 1600) rücken die
   festen Spalten zusammen, damit der Name lesbar bleibt — dieselbe Stufe
   wie bei der Lead-Tabelle. */
@media (max-width: 1799px) {
    .lg-tabelle { min-width: 1034px; }
    .lg-tabelle th,
    .lg-tabelle td { padding: 8px 6px; }
    .lg-tabelle .lg-aktiv { width: 84px; }
    .lg-tabelle .lg-eingang { width: 150px; }
    .lg-tabelle .lg-absage { width: 250px; }
    .lg-tabelle .lg-frist { width: 116px; }
    .lg-tabelle .lg-zahl { width: 130px; }
    .lg-tabelle .lg-letzter { width: 104px; }
}

/* Die ganze Zeile öffnet die Detailseite (projekt-fenster.js,
   `data-zeilen-link`) — der Zeiger sagt es. */
.lg-zeile { cursor: pointer; }
.lg-zeile:hover { background: var(--bg-subtle); }
.lg-inaktiv td { color: var(--text-muted); }

.lg-name-link {
    color: inherit;
    font-weight: 600;
    text-decoration: none;
}

.lg-name-link:hover { color: var(--primary); }

/* ── Dialog „Neuer Lead-Geber" ───────────────────────────────── */
.lg-dialog {
    width: 480px;
    max-width: 100%;
    margin: 0;
}

.lg-dialog-fuss {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    border-top: 1px solid var(--border);
    padding-top: 16px;
}

/* ── Detailseite ─────────────────────────────────────────────── */
.lg-reiter { margin-bottom: 16px; }

.lg-zahlfeld { max-width: 140px; }

.lg-knopfzeile {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.lg-speichern {
    display: flex;
    justify-content: flex-end;
    border-top: 1px solid var(--border);
    padding-top: 12px;
    margin-top: 16px;
}

.lg-loeschen { color: var(--danger-text); }

.lg-platzhalter {
    margin: 6px 0 0;
    padding-left: 18px;
}

.lg-vorschau {
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-muted);
}

.lg-vorschau-text {
    white-space: pre-wrap;
    margin-top: 8px;
    color: var(--text-secondary);
}

/* Reiter „Ablehnungsgründe" (#3527): der Listeneditor. Je Zeile Name,
   Schalter, Zahl und Knöpfe in einer Reihe; Hinweise und Fehler darunter.
   Die Liste trägt ihre Nummerierung nicht sichtbar — die Reihenfolge ist
   die Zeilenfolge, ↑/↓ verschieben. */
.lg-gruende-liste {
    list-style: none;
    margin: 0;
    padding: 0;
}

.lg-grund-zeile {
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}

.lg-grund-zeile--inaktiv { color: var(--text-muted); }

.lg-grund-kopf {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}

.lg-grund-name { flex: 1 1 280px; min-width: 200px; }

.lg-grund-schalter {
    display: flex;
    gap: 6px;
    align-items: center;
    font-size: var(--text-sm);
    white-space: nowrap;
}

.lg-grund-zahl { min-width: 90px; white-space: nowrap; }

/* #3529: Code für die Schnittstelle — nur bei verknüpftem Zugang. Die
   Auswahl nennt Code und Katalogwort; sie darf schmaler werden als die
   Bezeichnung, aber nicht so schmal, dass der Code abgeschnitten wird. */
.lg-grund-code { flex: 0 1 280px; min-width: 200px; }
.lg-code-kopf { margin-bottom: 8px; }

.lg-grund-hinweis {
    margin-top: 4px;
    color: var(--text-secondary);
}

.lg-gruende-leer { padding: 8px 0 16px; }

.lg-gruende-inaktiv { margin-top: 16px; }

/* Kanal „Kein Storno" (Stolperstein 14): Die Vorlage ruht — ausgegraut,
   aber lesbar; der Satz darüber sagt warum. */
.lg-ruht .card-body > .form-group,
.lg-ruht .lg-vorschau { opacity: .6; }

.lg-felder {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: 8px 16px;
    margin: 0;
    font-size: var(--text-sm);
}

.lg-felder dt { font-weight: 600; }
.lg-felder dd { margin: 0; }

.lg-auswertung {
    width: 100%;
    font-size: var(--text-sm);
}

.lg-auswertung th,
.lg-auswertung td { padding: 8px 12px; }

.lg-rechts { text-align: right; white-space: nowrap; }

/* `.table th` setzt text-align:left mit höherer Spezifität — ohne diese
   Zeile stünden die Zahlenköpfe links über rechtsbündigen Zahlen. */
.lg-auswertung th.lg-rechts { text-align: right; }

.lg-summe td {
    border-top: 2px solid var(--border);
    font-weight: 700;
}

/* Die Sätze unter „Ablehnungen nach Grund" (#3529), die „nicht vermerkt",
   einen Grund in mehreren Zeilen und „ohne Storno-Spur" erklären —
   eingerückt wie die Zellen darüber, damit sie zur Tabelle gehören und
   nicht zur nächsten Karte. */
.lg-tabelle-fuss { margin: 0; padding: 8px 12px 12px; }

/* ── Mahnwesen · „Entwürfe warten auf Versand" bei 1100 px (QA zu toloro#3494) ──
   Acht Spalten — Haken, Rechnung, Projekt, Kunde, Stufe, Weg, Angelegt am,
   „Prüfen und versenden" — in einer Karte, die bei 1100 px Fensterbreite
   rund 770 px misst. Mit der Vorgabe-Polsterung der `.table` (12 px je
   Seite) und nicht umbrechenden Zellen war die Tabelle gut 900 px breit,
   und weil `.card` `overflow: hidden` trägt, schnitt die Karte die letzte
   Spalte ab: keine Bildlaufleiste, aber auch kein „Prüfen und versenden"
   (Render-Probe im Browser, 28.09.2026). Deshalb: schmalere Polsterung, der
   Kunde bekommt eine Mindestbreite und bricht notfalls im Wort um (der
   volle Name steht im Titel), Link und Kopf „Angelegt am" dürfen umbrechen
   — gemessen 750 px Mindestbreite. Wird es enger (schmales Fenster,
   überlanges Wort), schiebt die Hülle waagerecht, statt abzuschneiden. */
.mahn-entwuerfe-huelle {
    overflow-x: auto;
}

.mahn-entwuerfe th,
.mahn-entwuerfe td {
    padding-left: 8px;
    padding-right: 8px;
}

.mahn-entwuerfe .mahn-kunde {
    min-width: 7.5rem;
    overflow-wrap: anywhere;
}

/* ── Mahnwesen · Spalte „Offen" (toloro#3592) ──
   Rechtsbündig, ohne Umbruch und mit gleich breiten Ziffern, damit die Beträge
   untereinander stehen — wie „Offen" in den Forderungen; der Kopf und die
   Summenzeile darunter richten sich mit derselben Klasse aus. Weicht der Rest
   von heute vom Entwurf ab, steht der eingefrorene Betrag als zweite Zeile im
   Warnton darunter (Leitplanken Nr. 3: sichtbar, nicht im Tooltip). Auch in
   der Liste „Entscheidung nötig". */
.mahn-offen {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.mahn-offen-entwurf {
    font-size: var(--text-xs);
    color: var(--warning-text);
}

/* ── Mahnwesen · „Löschen" in der Zeile der Entwürfe (toloro#3612) ──
   Ein Wort wie der Link „Prüfen und versenden" darüber, kein Symbol —
   technisch ein Knopf (POST über das Formular #mahn-entwurf-loeschen),
   deshalb die Knopf-Vorgaben zurückgesetzt. Eine eigene Zeile unter dem
   Link: Die Tabelle wird dadurch nicht breiter (1100 px, QA zu #3494).
   Rot im Hover-Ton von `.btn-danger`, damit das Wort auf Weiß lesbar
   bleibt; gefragt wird vorher im Browser. */
.mahn-entwuerfe .mahn-loeschen {
    display: block;
    margin-top: 2px;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: var(--danger-text);
    cursor: pointer;
    text-align: left;
}

.mahn-entwuerfe .mahn-loeschen:hover {
    text-decoration: underline;
}

/* ── Telefonie · Häkchen-Raster der Rufgruppe (toloro#2835) ──
   Die Mitglieder einer Rufgruppe (Türklingel) sind Häkchen über ALLE
   Nebenstellen des Hauses, nach Nummer, mehrspaltig — kein
   `<select multiple>`, bei dem ein Fehlklick die ganze Auswahl löscht,
   und keine Zahlenfelder, die eine Reihenfolge behaupten, die es nicht
   gibt (UX-Leitplanken #2835, Stolperstein 3). `auto-fill` legt so
   viele Spalten nebeneinander, wie hineinpassen; bei 30 Nebenstellen
   sind es auf dem Büro-Bildschirm drei oder mehr. Das Fieldset trägt
   keinen eigenen Rahmen: Es gruppiert nur (für den Zähler und die
   Legende), die Karte ist der Rahmen. */
.telefon-mitglieder {
    border: 0;
    padding: 0;
    margin: 0 0 12px;
}

.telefon-raster {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 4px 16px;
    margin-top: 8px;
}

/* ── Startseite · „Meine Angebote & Rechnungen“ (toloro#4220) ──
   Die Karte zählt, was jemand selbst an Angeboten und Rechnungen
   geschrieben hat: links die letzten drei Monate als Tabelle, rechts
   sechs Monate als Säulen. Die zwei Farben sind geprüft (Abstand auch
   bei Rot-Grün-Schwäche, Kontrast ≥ 3:1 zum Kartengrund); die Sorte
   steht zusätzlich immer als Wort daneben, nie nur als Farbe. Der
   laufende Monat ist schraffiert — er ist noch nicht fertig. Jeder
   Betrag ist ein Knopf, der darunter die Belege des Monats je Projekt
   aufklappt (`.bz-belege`). */
.bz {
    --bz-angebote: #2E6BB0;
    --bz-rechnungen: #D9661A;
    margin-bottom: 24px;
    /* „show:top“ beim Wechsel der Karte (#4234): die Kopfzeile rechnet schon
       scroll-padding-top im html heraus (layout.css), hier nur etwas Luft. */
    scroll-margin-top: 12px;
}

.bz-karte {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 16px 18px 12px;
}

.bz-kopf {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}

.bz-kopf-wahl {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.bz-titel {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--text);
    margin: 0;
}

.bz-unter {
    font-size: var(--text-xs);
    color: var(--text-muted);
    margin-top: 2px;
}

.bz-leer {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin: 4px 0 8px;
}

.bz-leise {
    color: var(--text-muted);
}

.bz-wahl {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: var(--text-sm);
}

.bz-wahl-text {
    color: var(--text-secondary);
    white-space: nowrap;
}

.bz-wahl-feld {
    width: auto;
    min-width: 180px;
}

.bz-rumpf {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    gap: 24px;
    align-items: center;
}

@media (max-width: 1100px) {
    .bz-rumpf {
        grid-template-columns: minmax(0, 1fr);
    }
}

.bz-tabelle {
    width: 100%;
    border-collapse: collapse;
}

.bz-tabelle th,
.bz-tabelle td {
    text-align: left;
    padding: 6px 8px;
    vertical-align: top;
}

.bz-tabelle thead th {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 1px solid var(--border);
}

.bz-tabelle thead th.bz-jetzt {
    color: var(--text);
}

.bz-spalte-unter {
    display: block;
    text-transform: none;
    letter-spacing: 0;
    font-weight: 400;
    color: var(--text-muted);
}

.bz-tabelle tbody th {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    width: 1%;
    padding-top: 12px;
    padding-right: 16px;
}

.bz-tabelle tbody tr + tr th,
.bz-tabelle tbody tr + tr td {
    border-top: 1px solid var(--border);
}

.bz-tabelle td.bz-jetzt {
    background: var(--bg-subtle);
}

.bz-zahl {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 4px 6px;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.bz-zahl:hover,
.bz-zahl:focus-visible {
    border-color: var(--border-active);
    background: var(--surface);
}

.bz-zahl-leer {
    cursor: default;
}

.bz-klein.bz-abzug {
    color: var(--danger-text);
    /* Die längste Zeile der Tabelle („darin … Storno/Kundengutschrift“) darf
       umbrechen — sonst wird die Tabelle breiter als ihre Spalte und die
       rechte Monatsspalte läuft unter die Achsentexte des Diagramms. */
    white-space: normal;
}

.bz-betrag {
    display: block;
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.bz-klein {
    display: block;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    white-space: nowrap;
}

.bz-punkt {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 3px;
    margin-right: 7px;
}

.bz-punkt-angebote {
    background: var(--bz-angebote);
}

.bz-punkt-rechnungen {
    background: var(--bz-rechnungen);
}

/* Diagramm: Teilstriche absolut in der Fläche, Säulen als Flex-Reihe
   darüber; die Monatsnamen in einer eigenen Reihe darunter, gleich
   breit verteilt. Die linke Spalte (34px) trägt die Achsentexte. */
.bz-diagramm {
    margin: 0;
}

.bz-legende {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    margin: 0 0 6px 34px;
}

.bz-flaeche {
    position: relative;
    height: 160px;
    margin: 8px 0 0 34px;
}

.bz-strich {
    position: absolute;
    left: 0;
    right: 0;
    border-top: 1px solid var(--border);
}

.bz-strich-text {
    position: absolute;
    left: -34px;
    top: -7px;
    width: 28px;
    text-align: right;
    font-size: 10px;
    color: var(--text-muted);
}

.bz-gruppen {
    position: absolute;
    inset: 0;
    display: flex;
}

.bz-gruppe {
    flex: 1 1 0;
    display: flex;
    justify-content: center;
    align-items: flex-end;
    gap: 2px;
}

.bz-saeule {
    display: block;
    width: 14px;
    border-radius: 4px 4px 0 0;
}

.bz-saeule-angebote {
    background: var(--bz-angebote);
}

.bz-saeule-rechnungen {
    background: var(--bz-rechnungen);
}

.bz-laufend .bz-saeule-angebote {
    background: repeating-linear-gradient(45deg, var(--bz-angebote) 0 2px, rgba(46, 107, 176, 0.35) 2px 5px);
}

.bz-laufend .bz-saeule-rechnungen {
    background: repeating-linear-gradient(45deg, var(--bz-rechnungen) 0 2px, rgba(217, 102, 26, 0.35) 2px 5px);
}

.bz-monate {
    display: flex;
    margin-left: 34px;
    border-top: 1px solid var(--text-muted);
}

.bz-monat {
    flex: 1 1 0;
    text-align: center;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    padding-top: 4px;
}

.bz-fuss {
    font-size: var(--text-xs);
    color: var(--text-muted);
    margin: 10px 0 0;
}

/* Vergleich für Vorgesetzte */
.bz-monatswahl {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.bz-monatsknopf {
    background: none;
    border: 0;
    border-left: 1px solid var(--border);
    padding: 6px 12px;
    font: inherit;
    font-size: var(--text-sm);
    color: var(--text-secondary);
    cursor: pointer;
}

.bz-monatsknopf:first-child {
    border-left: 0;
}

.bz-monatsknopf-an {
    background: var(--primary);
    color: #fff;
    font-weight: 600;
}

.bz-vergleich-rahmen {
    overflow-x: auto;
}

.bz-vergleich {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.bz-vergleich th,
.bz-vergleich td {
    padding: 8px 10px;
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.bz-vergleich th:first-child,
.bz-vergleich td:first-child {
    text-align: left;
}

.bz-vergleich thead th {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 1px solid var(--border);
}

.bz-vergleich .bz-gruppenkopf th {
    border-bottom: 0;
    padding-bottom: 0;
    text-align: left;
}

.bz-vergleich tbody td {
    border-bottom: 1px solid var(--border);
    color: var(--text);
}

.bz-vergleich tfoot td {
    font-weight: 700;
    border-top: 2px solid var(--border);
}

.bz-vergleich .bz-trenner {
    border-left: 1px solid var(--border);
}

.bz-name {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--primary);
    cursor: pointer;
    text-align: left;
}

.bz-name,
.bz-auf-tabelle a {
    color: var(--primary);
    text-decoration: underline;
    text-decoration-color: var(--border-active);
    text-underline-offset: 3px;
}

.bz-name:hover,
.bz-auf-tabelle a:hover {
    text-decoration-color: currentColor;
}

/* „Ohne Projektleiter“ (#4234): anklickbar, aber leiser als die Namen. */
.bz-name.bz-leise {
    color: var(--text-secondary);
}

.bz-balkenzelle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    justify-content: flex-end;
}

.bz-spur {
    display: inline-flex;
    width: 110px;
}

.bz-balken {
    display: block;
    height: 10px;
    border-radius: 0 4px 4px 0;
}

.bz-balken-angebote {
    background: var(--bz-angebote);
}

.bz-balken-rechnungen {
    background: var(--bz-rechnungen);
}

/* Aufschlüsselung einer Monatssumme, je Projekt */
.bz-belege:empty {
    display: none;
}

.bz-belege {
    margin-top: 12px;
    border-top: 1px solid var(--border);
    padding-top: 12px;
}

.bz-auf-kopf {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
    margin-bottom: 8px;
}

.bz-auf-titel {
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--text);
    margin: 0;
}

.bz-auf-zu {
    flex-shrink: 0;
}

.bz-auf-tabelle {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.bz-auf-tabelle th,
.bz-auf-tabelle td {
    padding: 6px 10px;
    text-align: left;
    font-variant-numeric: tabular-nums;
}

.bz-auf-tabelle thead th {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 1px solid var(--border);
}

.bz-auf-tabelle tbody td {
    border-bottom: 1px solid var(--border);
}

.bz-auf-tabelle .bz-projekt th,
.bz-auf-tabelle .bz-projekt td {
    background: var(--bg-subtle);
    font-weight: 600;
    border-bottom: 1px solid var(--border);
}

.bz-auf-tabelle tfoot td {
    font-weight: 700;
    border-top: 2px solid var(--border);
}

.bz-auf-tabelle .bz-rechts {
    text-align: right;
    white-space: nowrap;
}

.bz-projektsumme {
    color: var(--text);
}

/* Titel-Vorgabe und Zusatz (#4234): darf umbrechen, damit die Tabelle
   bei langen Titeln nicht in die Breite geht. */
.bz-titelzelle {
    color: var(--text-secondary);
    max-width: 32ch;
}

.bz-auf {
    display: block;
}

/* ── Startseite · Kachel-Raster und „Startseite anpassen“ (toloro#4392) ──
   Die Startseite ist ein Raster mit zwölf Spalten; wie viele davon eine
   Kachel belegt und wie hoch sie ist, steht im Block „Kacheln im festen
   Raster“ (toloro#4416) am Ende des Blatts. Unter 1024 px steht alles untereinander,
   wie vorher die beiden Spalten von .dashboard-grid. Die Blöcke in den
   Kacheln (.section, .bz) tragen eigene Abstände nach unten; im Raster
   setzt der Rasterabstand sie, nicht die Kachel. */
.sk-gruss {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    flex-wrap: wrap;
}

.sk-raster {
    display: grid;
    grid-template-columns: 1fr;
}

.sk-kachel {
    min-width: 0;
    margin-bottom: 16px;
}

/* Nur der letzte Block einer Kachel verliert seinen Abstand nach unten —
   mehrere Blöcke in einer Kachel (Notdienst: Dienst + Anrufe;
   Handlungsbedarf + Kundenzufriedenheit) behalten ihre Luft dazwischen. */
.sk-kachel > :last-child {
    margin-bottom: 0;
}

.sk-leer {
    margin-bottom: 16px;
}

.sk-leer-wege {
    display: flex;
    gap: 8px;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 12px;
}

@media (min-width: 1024px) {
    .sk-raster {
        grid-template-columns: repeat(12, 1fr);
        gap: 24px;
        align-items: start;
    }

    .sk-kachel {
        margin-bottom: 0;
        grid-column: span 12;
    }
}

/* „Startseite anpassen“: das Brett mit den liegenden Kacheln als kompakte
   Karten (Titel, Erklärung, Größenwahl — kein Inhalt, UX-Leitplanke) in voller
   Breite; der Katalog ist eine Schublade von rechts, die erst „+ Kachel
   hinzufügen“ öffnet (Matthias, 17.10.2026). Gezogen wird nur am Griff
   (Vorbild positionen-drag-griff.js, #2039); ▲▼ sind sichtbare Knöpfe, damit
   es auch ohne Maus und am Handy geht. */

.sk-leiste {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 12px 16px;
    margin-bottom: 16px;
    background: var(--primary-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

.sk-leiste-text {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--primary);
}

.sk-leiste-sub {
    font-size: var(--text-xs);
    color: var(--text-secondary);
    margin-top: 2px;
}

.sk-leiste-knoepfe {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.sk-brett {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
    align-content: start;
}

.sk-karte {
    position: relative;
    padding: 12px 14px;
    outline: 2px dashed var(--border-active);
    outline-offset: 3px;
    min-width: 0;
}

.sk-karte.sk-zieht {
    opacity: 0.5;
}

.sk-karte.sk-ziel {
    outline-color: var(--primary);
}

.sk-karte-kopf {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.sk-karte-text-block {
    min-width: 0;
    flex: 1;
}

.sk-griff {
    flex: none;
    cursor: grab;
    color: var(--text-muted);
    font-weight: 700;
    letter-spacing: -2px;
    padding: 2px 6px 2px 4px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg);
    user-select: none;
    touch-action: none;
}

.sk-karte-titel {
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--text);
}

.sk-karte-text {
    font-size: var(--text-sm);
    color: var(--text-secondary);
}

.sk-knoepfe {
    display: flex;
    gap: 6px;
    flex: none;
    margin-left: auto;
}

.sk-knopf {
    width: 28px;
    height: 28px;
    border-radius: 7px;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text-secondary);
    display: grid;
    place-items: center;
    font-weight: 700;
    cursor: pointer;
}

.sk-knopf:disabled {
    opacity: 0.35;
    cursor: default;
}

.sk-knopf-weg {
    color: #991B1B;
}

.sk-karte-fuss {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 10px;
    font-size: var(--text-xs);
    color: var(--text-muted);
}

.sk-brett-leer {
    grid-column: 1 / -1;
    display: grid;
    place-items: center;
    min-height: 120px;
    padding: 16px;
    border: 2px dashed var(--border-active);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    font-size: var(--text-sm);
    text-align: center;
}

.sk-zurueck {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: -4px 0 12px;
    font-size: var(--text-sm);
    color: var(--text-secondary);
}

.sk-schleier {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.35);
    z-index: 900;
}

.sk-schublade {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(380px, 100vw);
    z-index: 901;
    display: flex;
    flex-direction: column;
    border-radius: 0;
    box-shadow: var(--shadow-lg);
}

.sk-schublade .card-header {
    padding: 16px 16px 8px;
    align-items: flex-start;
}

.sk-schublade-liste {
    flex: 1;
    overflow-y: auto;
    padding-bottom: 16px;
}

/* Ist der Assistent angedockt (agent-chat.css, fest rechts, Ebene 1090), rückt
   die Schublade neben ihn — sonst läge sie unsichtbar unter dem Chat. Ab 900 px,
   darunter füllt der Chat ohnehin die ganze Breite. */
@media (min-width: 900px) {
    body.agent-panel-offen .sk-schublade {
        right: var(--agent-panel-breite);
    }
}

.sk-panel-hinweis {
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sk-suche {
    margin: 0 16px 10px;
}

.sk-gruppe {
    padding: 8px 16px 2px;
    font-size: var(--text-2xs);
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.sk-eintrag {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    border-top: 1px solid var(--border);
}

.sk-eintrag-text {
    flex: 1;
    min-width: 0;
}

.sk-eintrag-titel {
    display: block;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
}

.sk-eintrag.sk-liegt .sk-eintrag-titel {
    color: var(--text-secondary);
}

.sk-eintrag-sub {
    display: block;
    font-size: var(--text-2xs);
    color: var(--text-muted);
    line-height: 1.3;
}

.sk-plus {
    flex: none;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 1px solid var(--primary);
    background: var(--bg);
    color: var(--primary);
    display: grid;
    place-items: center;
    font-size: 16px;
    font-weight: 700;
    cursor: pointer;
}

.sk-plus:disabled {
    background: var(--success-soft);
    border-color: #6EE7B7;
    color: #065F46;
    font-size: 12px;
    cursor: default;
}

.sk-katalog-leer {
    padding: 12px 16px 16px;
    font-size: var(--text-sm);
    color: var(--text-muted);
}

@media (min-width: 1024px) {
    .sk-brett {
        grid-template-columns: repeat(12, 1fr);
    }
}

/* ── Belegseite · Reiter, ⋯-Menü, Ablage-Zeile, „nächster Schritt" (toloro#4418/#4419) ──
   Die Belegseite (app2/billing-detail.html) zeigt unter Kopf und Feld
   „nächster Schritt" Reiter in fester Reihenfolge (beleg-reiter.js). Die
   Reiterleiste ist die Hausform (.tabs/.tab); hier steht nur, was sie und
   der Kopf zusätzlich brauchen. */

/* Die Reiterleiste der Belegseite: alle Reiter samt Zähler sichtbar, auch
   bei 1280 px — sie bricht um, statt waagerecht zu scrollen (`.tabs` trägt
   overflow-x:auto: Bei 1280 px stand „Zahlungen & Mahnunge" abgeschnitten
   da, das Abzeichen „offen" fehlte). Ohne overflow ist auch der Strich des
   offenen Reiters wieder zu sehen: `.tab` rückt ihn mit margin-bottom:-2px
   auf die Linie der Leiste, und der Bildlaufkasten schnitt ihn ab. */
.tabs.beleg-reiter {
    flex-wrap: wrap;
    overflow: visible;
}

.beleg-reiter .tab {
    padding: 10px 12px;
}

/* Der Strich des offenen Reiters sitzt am Reiter selbst (inset), nicht auf
   der Linie der Leiste: Bricht die Leiste um, stünde ein Strich aus der
   ersten Zeile sonst auf der zweiten (margin-bottom:-2px von `.tab`). */
.tabs.beleg-reiter button.tab {
    margin-bottom: 0;
}

.tabs.beleg-reiter button.tab.active {
    border-bottom-color: transparent;
    box-shadow: inset 0 -2px 0 var(--accent);
}

/* Der Zähler am Reiter („Verlauf 7", „offen"): klein und grau, damit er
   den Namen nicht übertönt; „offen" in der Farbe der offenen Forderung. */
.beleg-reiter-zahl {
    display: inline-block;
    margin-left: 6px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--bg-muted);
    color: var(--text-secondary);
    font-size: var(--text-2xs);
    font-weight: 600;
    line-height: 1.6;
    vertical-align: 1px;
}

.beleg-reiter-zahl--offen {
    background: var(--warning-soft);
    color: var(--warning-text);
}

/* Der ⋯-Knopf im Kopf sieht aus wie seine Nachbarn (btn btn-outline
   btn-sm); `fp-menue-knopf` ist hier nur der Anker, an dem
   forderungen-menue.js den eigenen Knopf beim Klick daneben erkennt. */
.beleg-kopf-menue {
    display: inline-flex;
    flex: none;
}

.beleg-kopf-menue .fp-menue-knopf {
    min-width: 34px;
    justify-content: center;
    letter-spacing: 0.08em;
}

/* Das ⋯-Menü: breiter als ein Zeilenmenü, weil Formulare darin stehen
   (Druckbündel mit „Exemplare je Anlage", der Ablage-Kasten); bei
   kleinem Fenster scrollt es in sich, statt unter den Rand zu laufen. */
.beleg-menue {
    min-width: 300px;
    max-width: 460px;
    max-height: 75vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 4px 0;
    text-align: left;
    white-space: normal;
}

.beleg-menue-kopf {
    padding: 4px 12px 6px;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border);
    margin-bottom: 4px;
}

/* Die Laufanzeige im Menü „+ Angebot erstellen ▾" (toloro#4435, UX-Blick
   B7): Nach dem Klick sind alle Einträge gesperrt, der gewählte trägt
   aria-busy (angebot-anlegen.js) — sichtbar wird es erst mit dem Satz
   dahinter. Eigene Klasse, weil .beleg-menue auch das ⋯-Menü der
   Belegseite trägt, wo anderes läuft als eine Anlage. */
.angebot-menue button[aria-busy="true"]::after {
    content: " – wird angelegt …";
    color: var(--text-secondary);
}

/* „Exemplare je Anlage" unter den Druckbündel-Einträgen. */
.beleg-menue-feld {
    padding: 0 12px 6px;
}

/* „→ Versenden" aus der Zeile der Reiter Angebote/Rechnungen (toloro#4434):
   die Bestätigung klappt unter der Zeile auf — eingerückt, mit Strich wie
   die Folgebelege der Vorgangskette, damit sie zur Zeile gehört und die
   Liste nicht sprengt. */
.zeilenversand {
    margin: 8px 0 0 20px;
    padding: 8px 12px;
    border-left: 2px solid var(--border);
    background: var(--bg-subtle);
    text-align: left;
}

.zeilenversand__formular {
    margin: 8px 0 0;
}

.zeilenversand__knoepfe {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    margin-top: 8px;
}

/* Der Rückweg in den Reiter springt die Zeile an (`#angebot-<id>`,
   `#vorgang-<id>`, toloro#4584). Die Kopfzeile des Fensters rechnet
   `scroll-padding-top` an der Wurzel schon heraus (layout.css); der Rand hier
   lässt die Zeile mit Luft darunter stehen statt bündig an der Kante. Die
   angesprungene Zeile ist dezent markiert — sie ist die, um die es ging. */
[data-zeilenversand-zeile] {
    scroll-margin-top: 16px;
}

[data-zeilenversand-zeile]:target {
    background: var(--bg-subtle);
    box-shadow: inset 3px 0 0 var(--success);
}

/* Erklärende Sätze im Menü (Storno, Subunternehmeraufträge, Folge des
   Löschens) — und ihre Links als Links, nicht als Menüzeilen. */
.beleg-menue-hinweis {
    padding: 4px 12px 6px;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    line-height: 1.4;
}

.beleg-menue-hinweis a {
    display: inline;
    padding: 0;
    color: var(--primary);
    text-decoration: underline;
    font-size: inherit;
}

/* Der Ablage-Kasten als Ganzes unten im Menü — grau, wie Matthias'
   Zielbild es zeigt. Sein Fragment bringt die eigene Trennlinie mit. Die
   Zeilen des Kastens rücken ein wie die Menüeinträge; „GAEB-Datei ablegen"
   sieht aus wie jeder andere Eintrag (Fragment unverändert, nur hier im
   Menü angeglichen), das ⓘ bleibt daneben. */
.beleg-menue-ablage {
    padding: 0 0 4px;
    color: var(--text-secondary);
}

.beleg-menue-ablage #beleg-ablage > div {
    padding-left: 12px;
    padding-right: 12px;
}

.beleg-menue-ablage #beleg-ablage > div[x-data] {
    padding-left: 0;
}

.beleg-menue-ablage #beleg-ablage > div[x-data] form {
    flex: 1 1 auto;
}

.beleg-menue-ablage a {
    display: inline;
    padding: 0;
}

.dropdown-menu.beleg-menue .beleg-menue-ablage #beleg-ablage > div[x-data] form button.btn {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 12px;
    border: none;
    border-radius: 0;
    background: none;
    color: var(--text);
    font-size: var(--text-sm);
    font-weight: 400;
    height: auto;
}

.dropdown-menu.beleg-menue .beleg-menue-ablage #beleg-ablage > div[x-data] form button.btn:hover {
    background: var(--bg-muted);
}

.beleg-menue-ablage .info-karte {
    margin-left: 12px;
}

/* Das ⓘ der GAEB-Datei im Ablage-Kasten ist ein <button> ohne .btn — die
   Regel für Menüeinträge (`.dropdown-menu button:not(.btn)`) machte es zur
   ganzen Menüzeile. Hier bekommt es seine Gestalt (.info-knopf) zurück. */
.beleg-menue button.info-knopf {
    display: inline-flex;
    width: 20px;
    padding: 0;
    font-size: 12px;
    text-align: center;
    border: 1px solid var(--border);
    border-radius: 50%;
}

.beleg-menue button.info-knopf:hover {
    background: none;
}

/* Die rote Ablage-Zeile im Kopf — nur, wenn es etwas zu tun gibt. */
.beleg-ablage-fehler {
    margin-top: 12px;
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    background: var(--danger-soft);
    color: var(--danger-text);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: var(--text-sm);
}

/* Feld „nächster Schritt" an der Rechnung mit offener Forderung: gelb wie
   das Banner der Teilannahme, überfällig mit rotem Rand. */
.beleg-naechster-schritt {
    padding: 16px 20px;
    background: var(--warning-soft);
    border-color: var(--warning);
    color: var(--warning-text);
}

.beleg-naechster-schritt--ueberfaellig {
    border-color: var(--danger);
}

.beleg-naechster-schritt-verzug {
    color: var(--danger-text);
}
/* ── Startseite · Zahlen-Kacheln: Rahmen, Menü, Zahlen, Balken (toloro#4393) ──
   Jede Zahlen-Kachel kommt im selben Rahmen (app2/fragments/startkachel):
   Kopf mit Titel und Menü ⋯, darunter der Inhalt der Kachel, unten „Mehr ›“.
   Das Menü ist ein <details> — kein Skript, schließt beim Austausch von selbst.
   Zahlen sind Links auf die Seite, aus der sie kommen (Dashboard-Muster #393). */
.sk-rahmen {
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: visible;
}

/* Der Platzhalter füllt die Kachel, bis der Rahmen kommt; ein Hinweis-Rahmen
   (ohne Recht, unbekannt) ist leiser als eine Zahl. */
.sk-platzhalter {
    height: 100%;
}

.sk-rahmen-hinweis {
    background: var(--bg-subtle);
}

.sk-rahmen-kopf {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
    padding: 14px 16px 6px;
}

.sk-rahmen-titel {
    font-weight: 600;
    font-size: var(--text-base);
    color: var(--text);
}

/* „Was zählt hier?“ unter dem Kopf, eingerückt wie der Titel (toloro#4393). */
.sk-rahmen-info {
    margin: 0 16px 8px;
}

.sk-rahmen-schnitt {
    font-weight: 500;
    color: var(--text-secondary);
    font-size: var(--text-sm);
}

.sk-rahmen-inhalt {
    padding: 4px 16px 14px;
    flex: 1;
}

.sk-rahmen-fuss {
    display: flex;
    justify-content: flex-end;
    padding: 0 8px 8px;
}

/* Flacher Rahmen (toloro#4723, Systemcheck in Groß): Titel, Inhalt und Menü in
   EINER Reihe, das ⓘ darunter über die volle Breite. Die Alpine-Hülle und
   der Kopf lösen sich als Kästen auf (display: contents), damit ihre Kinder
   im Raster des Rahmens liegen — click.outside und Fokus arbeiten am DOM,
   nicht am Kasten, das bleibt heil. */
.sk-rahmen-flach {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 14px;
}

.sk-rahmen-flach > [x-data],
.sk-rahmen-flach .sk-rahmen-kopf {
    display: contents;
}

.sk-rahmen-flach .sk-rahmen-titel {
    grid-area: 1 / 1;
    padding: 10px 0 10px 16px;
    white-space: nowrap;
}

.sk-rahmen-flach .sk-menue {
    grid-area: 1 / 3;
    margin-right: 12px;
}

.sk-rahmen-flach .sk-rahmen-inhalt {
    grid-area: 1 / 2;
    padding: 8px 0;
}

.sk-rahmen-flach .sk-rahmen-info {
    grid-area: 2 / 1 / 3 / 4;
    margin: 0 16px 10px;
}

.sk-rahmen-flach .sk-rahmen-fuss {
    grid-area: 3 / 1 / 4 / 4;
}

.sk-menue {
    position: relative;
    flex: none;
}

.sk-menue-knopf {
    list-style: none;
    cursor: pointer;
    width: 30px;
    height: 26px;
    border: 1px solid var(--border);
    border-radius: 7px;
    display: grid;
    place-items: center;
    color: var(--text-secondary);
    font-weight: 700;
    background: var(--bg);
}

.sk-menue-knopf::-webkit-details-marker {
    display: none;
}

.sk-menue-liste {
    position: absolute;
    right: 0;
    top: 32px;
    z-index: 50;
    min-width: 220px;
    padding: 4px 0;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg);
}

.sk-menue-titel {
    padding: 8px 12px 4px;
    font-size: var(--text-2xs);
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.sk-menue-eintrag {
    display: block;
    width: 100%;
    text-align: left;
    padding: 7px 12px;
    border: 0;
    background: transparent;
    font-size: var(--text-sm);
    color: var(--text);
    cursor: pointer;
}

.sk-menue-eintrag:hover {
    background: var(--bg-muted);
}

.sk-menue-eintrag.aktiv {
    background: var(--primary-soft);
    color: var(--primary);
    font-weight: 600;
}

.sk-menue-form {
    margin: 4px 0 0;
    border-top: 1px solid var(--border);
}

.sk-menue-anheften {
    color: var(--primary);
    font-weight: 600;
}

.sk-zahlen {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
}

.sk-zahl {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    min-width: 0;
}

.sk-zahl:hover .sk-zahl-wert {
    color: var(--primary);
}

.sk-zahl-wert {
    font-size: 1.625rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--text);
}

.sk-zahl-text {
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sk-unterzeile {
    margin-top: 12px;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
}

.sk-balkenliste {
    display: grid;
    gap: 6px;
    margin-top: 6px;
}

.sk-balkenzeile {
    display: grid;
    grid-template-columns: minmax(80px, 34%) 1fr 40px;
    gap: 8px;
    align-items: center;
    font-size: var(--text-sm);
}

.sk-balken-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sk-balken-spur {
    height: 8px;
    border-radius: 4px;
    background: var(--bg-muted);
    overflow: hidden;
}

.sk-balken {
    display: block;
    height: 8px;
    border-radius: 4px;
    background: var(--primary);
}

.sk-balken-wert,
.sk-rechts {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.sk-tabelle {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.sk-tabelle th {
    text-align: left;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
    padding: 6px 8px;
    border-bottom: 1px solid var(--border);
}

.sk-tabelle td {
    padding: 6px 8px;
    border-bottom: 1px solid var(--bg-muted);
}

.sk-tabelle-balken {
    width: 30%;
}

/* ── Startseite · Unternehmen, Betrieb, Technik (toloro#4398) ──
   Die Kacheln „Wo klemmt es heute?“, die vier Fragen (Fluss, Geld, Kunden,
   Laden), „Heute im Haus“, „Wo hängt es bei wem“, Technik-Ampel und
   Statistiken. Ampel nur als Punkt oder schmale Leiste links, nie als
   Fläche (Konzept §5); die Zellen der Bauleiter-Tabelle sind die eine
   Ausnahme, dort ist die Farbe die Auskunft. */
.sk-punkt {
    display: inline-block;
    flex: none;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--neutral);
}

.sk-punkt-rot {
    background: var(--danger);
}

.sk-punkt-gelb {
    background: var(--warning);
}

.sk-punkt-gruen {
    background: var(--success);
}

/* Offen: seit dem Start noch keine Probe — grau, kein Befund (toloro#4724). */
.sk-punkt-offen {
    background: var(--neutral);
}

.sk-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.sk-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    padding: 5px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    background: var(--bg-subtle);
    font-size: var(--text-sm);
    color: var(--text);
    text-decoration: none;
}

a.sk-chip:hover {
    border-color: var(--border-active);
}

.sk-chip-rot {
    background: var(--danger-soft);
    border-color: var(--danger-soft);
}

.sk-chip-gelb {
    background: var(--warning-soft);
    border-color: var(--warning-soft);
}

.sk-chip-gruen {
    background: var(--success-soft);
    border-color: var(--success-soft);
}

/* Schwelle aus: das Schild ohne Farbe, wie die Karte daneben (toloro#4428). */
.sk-chip-neutral {
    background: var(--bg-subtle);
    border-color: var(--border);
}

.sk-stand {
    margin: 10px 0 0;
    font-size: var(--text-xs);
    color: var(--text-muted);
    text-align: right;
    cursor: help;
}

.sk-satz {
    margin: 6px 0 0;
    font-size: var(--text-sm);
    color: var(--text-secondary);
}

.sk-leersatz {
    margin: 6px 0;
    font-size: var(--text-sm);
    color: var(--text-secondary);
}

/* „Wo klemmt es heute?“ nach Bereichen (toloro#4530): je Bereich ein Kasten,
   die Stufe als Form — Achteck klemmt, Dreieck auffällig, Haken in Ordnung,
   X gestört —, die Farbe nur zusätzlich (Rot-Grün-Schwäche). Die Kästen
   fließen ins Raster, so passt die Kachel in jede Breite. */
.sk-bereiche {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
    gap: 12px;
    align-items: start;
}

/* Mittel ist halb so breit: schmalere Kästen, damit zwei nebeneinander passen. */
.sk-bereiche-dicht {
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}

.sk-bereich {
    min-width: 0;
    padding: 10px 12px 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

.sk-bereich-kopf {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 4px 8px;
    border-bottom: 1px solid var(--border);
}

.sk-bereich-titel {
    flex: 1 1 auto;
    margin: 0;
    font-size: var(--text-base);
    font-weight: 600;
}

.sk-bereich-zahl {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
}

.sk-bereich-zahl-ok {
    color: var(--success-text);
}

.sk-zeilen {
    margin: 0;
    padding: 0;
    list-style: none;
}

.sk-zeilen li + li {
    border-top: 1px solid var(--bg-muted);
}

.sk-zeile {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 4px;
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    color: var(--text);
    text-decoration: none;
}

a.sk-zeile:hover {
    background: var(--bg-subtle);
}

.sk-zeile-text {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.sk-zeile-rot strong {
    font-weight: 700;
}

.sk-zeile-gelb strong {
    font-weight: 600;
}

.sk-zeile-satz {
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sk-zeile-pfeil {
    color: var(--text-muted);
}

.sk-bereich-ruhig {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 8px 4px 2px;
    font-size: var(--text-sm);
    color: var(--text-secondary);
}

.sk-bereich-mehr {
    margin: 4px 4px 0;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sk-pruefung-wort {
    font-weight: 600;
    color: var(--text);
}

.sk-pruefung-wie {
    color: var(--text-muted);
}

.sk-zeichen {
    flex: none;
    width: 18px;
    height: 18px;
}

.sk-zeile .sk-zeichen {
    margin-top: 1px;
}

.sk-zeichen-klemmt path {
    fill: var(--danger-text);
}

.sk-zeichen-klemmt rect,
.sk-zeichen-klemmt circle {
    fill: var(--surface);
}

.sk-zeichen-auffaellig path {
    fill: var(--warning-soft);
    stroke: var(--warning-text);
    stroke-width: 1.6;
    stroke-linejoin: round;
}

.sk-zeichen-auffaellig rect,
.sk-zeichen-auffaellig circle {
    fill: var(--warning-text);
}

.sk-zeichen-ok circle {
    fill: none;
    stroke: var(--success-text);
    stroke-width: 1.6;
}

.sk-zeichen-ok path {
    fill: none;
    stroke: var(--success-text);
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.sk-zeichen-gestoert circle {
    fill: var(--danger-text);
}

.sk-zeichen-gestoert path {
    fill: none;
    stroke: var(--surface);
    stroke-width: 2;
    stroke-linecap: round;
}

/* Offen: grauer Ring mit drei Punkten — „wird geprüft“ (toloro#4724). */
.sk-zeichen-offen circle:first-child {
    fill: none;
    stroke: var(--text-muted);
    stroke-width: 1.6;
}

.sk-zeichen-offen circle + circle {
    fill: var(--text-muted);
}

.sk-wert-rot {
    color: var(--danger-text);
}

.sk-kennzahlen {
    display: grid;
    /* In einer Viertel-Kachel ist keine Spalte 190 px breit — dann eine Karte je Zeile statt Überlauf. */
    grid-template-columns: repeat(auto-fill, minmax(min(190px, 100%), 1fr));
    gap: 10px;
    margin-top: 10px;
}

.sk-kennzahl {
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
}

.sk-kennzahl-rot {
    border-left-color: var(--danger);
}

.sk-kennzahl-gelb {
    border-left-color: var(--warning);
}

.sk-kennzahl-gruen {
    border-left-color: var(--success);
}

/* Schwelle aus (oder ohne Stufe): neutral wie die Karte ohne Ampel — grün
   hieße „im Rahmen“, das sagt eine ausgeschaltete Schwelle nicht (toloro#4428). */
.sk-kennzahl-neutral {
    border-left-color: var(--border);
}

.sk-kennzahl-titel {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
}

.sk-kennzahl-wert {
    display: inline-block;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--text);
    text-decoration: none;
}

a.sk-kennzahl-wert:hover {
    color: var(--primary);
}

.sk-kennzahl-einheit {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-secondary);
}

.sk-kennzahl-satz {
    margin: 4px 0 0;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sk-alter {
    display: flex;
    height: 8px;
    margin-top: 6px;
    border-radius: 4px;
    overflow: hidden;
    background: var(--bg-muted);
}

.sk-alter-teil {
    display: block;
    height: 8px;
}

.sk-alter-0 {
    background: var(--neutral);
}

.sk-alter-1 {
    background: var(--primary);
}

.sk-alter-2 {
    background: var(--warning);
}

.sk-alter-3 {
    background: var(--danger);
}

.sk-alter-legende {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 10px;
    margin-top: 4px;
    font-size: var(--text-2xs);
    color: var(--text-muted);
}

.sk-spalten {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 16px;
}

.sk-balken-rot {
    background: var(--danger);
}

.sk-balken-primaer {
    background: var(--primary);
}

.sk-balken-akzent {
    background: var(--accent);
}

.sk-balken-ruhig {
    background: var(--neutral);
}

.sk-legende {
    display: flex;
    gap: 12px;
    margin-bottom: 6px;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sk-legende-feld {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 4px;
    border-radius: 2px;
    vertical-align: -1px;
}

.sk-heat td {
    border-bottom: 2px solid var(--bg);
    font-variant-numeric: tabular-nums;
}

.sk-heat td a {
    color: inherit;
    text-decoration: none;
}

.sk-heat td a:hover {
    text-decoration: underline;
}

.sk-heat th[scope="row"] {
    white-space: nowrap;
}

.sk-heat-buero th {
    color: var(--text-secondary);
}

.sk-zelle-neutral {
    background: var(--bg-subtle);
}

.sk-zelle-gruen {
    background: var(--success-soft);
}

.sk-zelle-gelb {
    background: var(--warning-soft);
}

.sk-zelle-rot {
    background: var(--danger-soft);
}

.sk-ampel {
    display: grid;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Systemcheck als Streifen (toloro#4723): die grünen Namen hintereinander mit
   einem Haken, Abweichungen als Schilder daneben, der Stand rechts. Jedes
   Stück ist ein <details>; das Prüfblatt klappt als Karte UNTER dem Schild
   auf (absolut, über dem Nachbarn), damit der Streifen flach bleibt. */
.sk-check {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    font-size: var(--text-sm);
}

.sk-check-kopf {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    list-style: none;
    cursor: pointer;
    border-radius: 999px;
}

.sk-check-kopf::-webkit-details-marker {
    display: none;
}

.sk-check-gut-kopf {
    padding: 3px 6px;
    color: var(--text-secondary);
}

.sk-check-gut-kopf:hover,
.sk-check-gut[open] > .sk-check-gut-kopf {
    background: var(--bg-subtle);
}

.sk-check-abweichung-kopf {
    padding: 3px 12px 3px 8px;
    border: 1px solid var(--border);
    background: var(--bg-subtle);
}

.sk-check-gestoert .sk-check-abweichung-kopf {
    border-color: var(--danger-soft);
    background: var(--danger-soft);
}

.sk-check-gestoert strong {
    color: var(--danger-text);
}

.sk-check-auffaellig .sk-check-abweichung-kopf {
    border-color: var(--warning-soft);
    background: var(--warning-soft);
}

.sk-check-auffaellig strong {
    color: var(--warning-text);
}

.sk-check-offen strong {
    color: var(--text-secondary);
}

.sk-check-satz {
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

/* Die Karte hängt am Streifen (position: relative an .sk-check), nicht am
   Schild: links bündig unter der Zeile, so wird sie am rechten Rand nie
   abgeschnitten — auch nicht beim letzten Schild. */
.sk-check-blatt {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 30;
    width: min(36rem, 100%);
    margin: 0;
    padding: 10px 12px;
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sk-check-blatt p {
    margin: 0 0 4px;
}

.sk-check-blatt-liste li + li {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid var(--bg-muted);
}

.sk-check-stand {
    margin-left: auto;
    font-size: var(--text-xs);
    color: var(--text-muted);
    white-space: nowrap;
}

/* Schmal (Handy, Tablet hochkant): kein Raster, kein Schweben — Titel über
   dem Streifen, die Karte klappt im Fluss darunter auf. */
@media (max-width: 1023px) {
    .sk-rahmen-flach {
        display: flex;
        flex-direction: column;
        align-items: stretch;
    }

    .sk-rahmen-flach > [x-data],
    .sk-rahmen-flach .sk-rahmen-kopf {
        display: flex;
    }

    .sk-rahmen-flach .sk-rahmen-titel {
        padding: 0;
        white-space: normal;
    }

    .sk-rahmen-flach .sk-menue {
        margin-right: 0;
    }

    .sk-rahmen-flach .sk-rahmen-inhalt {
        padding: 4px 16px 14px;
    }

    .sk-check-blatt {
        position: static;
        width: auto;
        margin-top: 6px;
        box-shadow: none;
    }
}

.sk-lampe {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    font-size: var(--text-sm);
    color: var(--text);
    text-decoration: none;
}

.sk-lampe .sk-punkt {
    align-self: center;
}

a.sk-lampe:hover strong {
    color: var(--primary);
}

.sk-lampe-gross {
    font-size: var(--text-base);
}

.sk-lampe-satz {
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sk-liste {
    margin: 8px 0 0;
    padding: 0;
    list-style: none;
    font-size: var(--text-sm);
}

.sk-liste li {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    padding: 3px 0;
    border-bottom: 1px solid var(--bg-muted);
}

.sk-liste-rechts {
    color: var(--text-secondary);
    text-align: right;
}

.sk-liste-mehr {
    justify-content: flex-end;
}

.sk-teile {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
}

.sk-teil {
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
}

.sk-teil-titel {
    margin-bottom: 6px;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
}

.sk-diagramme {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
    margin-top: 8px;
}

.sk-diagramm {
    min-width: 0;
    margin: 0;
}

.sk-diagramm-feld {
    position: relative;
    height: 220px;
}

/* ── Startseite · Vertrieb (toloro#4397) ──
   Die fünf Vertriebs-Kacheln nehmen die Zahlen-, Balken- und Tabellenklassen
   der Zahlen-Kacheln; dazu kommen hier nur die Monatssäulen (zwölf Monate,
   gestapelt für neu/Bestand), eine Liste für „Länger nicht beauftragt“ und die
   enge Monatstabelle. Ohne Skript: Höhen kommen als style aus dem Modell. */
.skv-saeulen {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 4px;
    align-items: end;
    margin-top: 12px;
}

.skv-saeule {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    min-width: 0;
    text-decoration: none;
    color: inherit;
}

.skv-saeule-wert {
    font-size: var(--text-2xs);
    color: var(--text-secondary);
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.skv-saeule-spur {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    height: 96px;
}

.skv-saeule-balken {
    display: flex;
    flex-direction: column;
    min-height: 1px;
    border-radius: 3px 3px 0 0;
    background: var(--primary);
    overflow: hidden;
}

.skv-saeule-oben {
    display: block;
    background: var(--accent);
}

.skv-saeule-monat {
    font-size: var(--text-2xs);
    color: var(--text-muted);
    text-align: center;
}

.skv-saeule:hover .skv-saeule-balken {
    opacity: 0.85;
}

/* Der laufende Monat ist noch nicht zu Ende — heller, damit niemand ihn mit
   den vollen Monaten daneben vergleicht. */
.skv-saeule-laufend .skv-saeule-balken {
    opacity: 0.55;
}

.skv-saeule-laufend .skv-saeule-monat {
    font-weight: 700;
    color: var(--text);
}

.skv-legende {
    display: flex;
    gap: 14px;
    margin-top: 6px;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.skv-legende-eintrag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.skv-legende-punkt {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 2px;
    background: var(--primary);
}

.skv-legende-neu {
    background: var(--accent);
}

.skv-zeilenlink {
    text-decoration: none;
    color: inherit;
}

.skv-zeilenlink:hover .sk-balken-name {
    color: var(--primary);
    text-decoration: underline;
}

.skv-tabellenrahmen {
    overflow-x: auto;
}

.skv-matrix th,
.skv-matrix td {
    padding: 5px 6px;
}

.skv-summenzeile th,
.skv-summenzeile td {
    font-weight: 700;
    border-top: 1px solid var(--border);
}

.skv-liste {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
    display: grid;
    gap: 6px;
    font-size: var(--text-sm);
}

.skv-listenzeile {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
}

.skv-listenzusatz {
    flex: none;
    color: var(--text-secondary);
    font-size: var(--text-xs);
}

.skv-fussnote {
    margin-top: 8px;
}

/* ── Startseite · Geld und Kunden: Umsatz, Angebote, Forderungen, Bewertungen (toloro#4396) ──
   Eine Vorlage für vier Kacheln (app2/fragments/kacheln/kennblick): Trend an der
   Kopfzahl (Pfeil und Wort, nie die Farbe allein), ein Satz, Säulen je Monat aus
   CSS (Teile von unten nach oben, Farbe und Höhe kommen fertig aus der Kachel),
   breitere Balkenwerte für Beträge, Kundenwort in der Tabelle, „Was zählt hier?“. */
/* Darf die Rolle die Zielseite nicht öffnen, steht die Zahl ohne href da —
   dann auch ohne Hover-Farbe und Zeiger, sonst sähe sie wie ein Link aus. */
.sk-zahl:not([href]):hover .sk-zahl-wert {
    color: var(--text);
}

.skg-saeule:not([href]):hover .skg-saeule-wert {
    color: var(--text-secondary);
    font-weight: 400;
}

.skg-balkenzeile:not([href]):hover .sk-balken-name {
    color: inherit;
}

.skg-einheit {
    margin-left: 3px;
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--text-secondary);
}

.skg-trend {
    align-self: flex-start;
    margin-top: 4px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: var(--text-2xs);
    font-weight: 600;
    white-space: nowrap;
}

.skg-trend-hoch {
    background: var(--success-soft);
    color: var(--success-text);
}

.skg-trend-runter {
    background: var(--danger-soft);
    color: var(--danger-text);
}

.skg-trend-gleich {
    background: var(--bg-muted);
    color: var(--text-secondary);
}

.skg-satz {
    margin: 8px 0 0;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

/* Ein Satz, der nach der Schwelle gefärbt ist (Versandfertig: „12 Belege warten
   länger als 1 Werktag“) — .skg-satz steht nach den Wertfarben und würde sie
   sonst grau überschreiben. */
.skg-satz.sk-wert-rot {
    color: var(--danger-text);
}

.skg-satz.sk-wert-gelb {
    color: var(--warning-text);
}

.skg-saeulen {
    display: flex;
    align-items: stretch;
    gap: 10px;
    height: 150px;
    margin-top: 8px;
}

.skg-saeule {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    text-decoration: none;
    color: inherit;
}

.skg-saeule-wert,
.skg-saeule-monat {
    text-align: center;
    font-size: var(--text-2xs);
    color: var(--text-secondary);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.skg-saeule-stapel {
    flex: 1;
    display: flex;
    flex-direction: column-reverse;
    border-bottom: 1px solid var(--border);
}

.skg-saeule-teil {
    display: block;
    width: 100%;
    flex: none;
}

.skg-saeule-teil:last-child {
    border-radius: 3px 3px 0 0;
}

.skg-saeule:hover .skg-saeule-wert {
    color: var(--primary);
    font-weight: 600;
}

/* Der laufende Monat ist noch nicht fertig: blasser, das Sternchen am Monat sagt es. */
.skg-laufend .skg-saeule-stapel {
    opacity: 0.6;
}

.skg-legende {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    margin-top: 8px;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.skg-punkt {
    display: inline-block;
    width: 9px;
    height: 9px;
    margin-right: 5px;
    border-radius: 2px;
}

.skg-balkenzeile {
    grid-template-columns: minmax(80px, 30%) 1fr minmax(64px, auto);
    text-decoration: none;
    color: inherit;
}

.skg-balkenzeile:hover .sk-balken-name {
    color: var(--primary);
}

.skg-leise {
    color: var(--text-muted);
}

/* Zahlenspalten stehen auch im Kopf rechtsbündig — „.sk-tabelle th“ setzt
   sonst links, und Kopf und Zahl stünden versetzt. */
.sk-tabelle th.sk-rechts {
    text-align: right;
}

.skg-zitat {
    font-style: italic;
    color: var(--text-secondary);
    white-space: normal;
}

.skg-zellenlink {
    color: inherit;
    text-decoration: none;
}

.skg-zellenlink:hover {
    color: var(--primary);
    text-decoration: underline;
}

.skg-summe td {
    font-weight: 700;
    border-top: 1px solid var(--border);
}

.skg-fuss {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: flex-end;
    gap: 6px 12px;
    margin-top: 12px;
    font-size: var(--text-xs);
}

.skg-ziel {
    font-weight: 600;
    color: var(--primary);
    text-decoration: none;
    white-space: nowrap;
}

.skg-ziel:hover {
    text-decoration: underline;
}

/* ── Startseite · Kacheln im festen Raster: Breite, Höhe, Ziehen (toloro#4416) ──
   Breite in sechs Stufen des Zwölferrasters (sk-breite-3 … -12, Kachelbreite),
   Höhe nach Inhalt oder 1 bis 6 Reihen à 120 px inklusive 24 px Abstand
   (sk-hoehe-n: n · 120 − 24 px). startseite.js legt das Raster in Zeilen von
   8 px (sk-raster-fein) und setzt je Kachel --sk-reihen = gemessene Höhe plus
   Abstand: So rückt eine Kachel unter eine kürzere Nachbarin, die Reihenfolge
   bleibt (kein dense). Ohne Skript bleibt das Raster mit Reihen nach Inhalt.
   Alles erst ab 1024 px — schmal steht alles untereinander, Höhe nach Inhalt,
   kein Griff. */
@media (min-width: 1024px) {
    .sk-breite-3 { grid-column: span 3; }
    .sk-breite-4 { grid-column: span 4; }
    .sk-breite-6 { grid-column: span 6; }
    .sk-breite-8 { grid-column: span 8; }
    .sk-breite-9 { grid-column: span 9; }
    .sk-breite-12 { grid-column: span 12; }

    .sk-raster-fein {
        grid-auto-rows: 8px;
        row-gap: 0;
        align-items: start;
    }

    .sk-raster-fein > .sk-kachel,
    .sk-raster-fein > .sk-karte,
    .sk-raster-fein > .sk-brett-leer {
        grid-row-end: span var(--sk-reihen, 1);
    }

    /* Feste Höhe auf der Startseite: genau n Reihen. */
    .sk-raster > .sk-hoehe-1 { height: 96px; }
    .sk-raster > .sk-hoehe-2 { height: 216px; }
    .sk-raster > .sk-hoehe-3 { height: 336px; }
    .sk-raster > .sk-hoehe-4 { height: 456px; }
    .sk-raster > .sk-hoehe-5 { height: 576px; }
    .sk-raster > .sk-hoehe-6 { height: 696px; }

    /* Eine Zahlen-Kachel mit fester Höhe rollt innen: Kopf (Titel, ⓘ, ⋯) und
       Fuß („Mehr ›“) bleiben stehen, nur der Inhalt dazwischen rollt — nie
       abgeschnitten. Die Kachel selbst rollt nicht, sonst schnitte sie das
       Menü ⋯ ab, das über sie hinausragen darf. */
    .sk-rollt-innen > .sk-rahmen,
    .sk-rollt-innen > .sk-platzhalter {
        height: 100%;
    }

    .sk-rollt-innen .sk-rahmen-inhalt {
        min-height: 0;
        overflow-y: auto;
    }

    /* Das ⓘ bleibt in der Kachel: Die Hülle aus Kopf und Karte „Was zählt
       hier?“ darf schrumpfen, die Karte rollt innen. Offen nimmt sie den
       Platz des Inhalts (der ihn zurückbekommt, wenn sie zugeht) und ist in
       jeder Höhe ganz lesbar — sie läuft nie unter die Nachbarkachel. */
    .sk-rollt-innen .sk-rahmen > [x-data] {
        display: flex;
        flex-direction: column;
        min-height: 0;
    }

    .sk-rollt-innen .sk-rahmen-info {
        min-height: 0;
        overflow-y: auto;
    }

    /* Der flache Streifen (Systemcheck in Groß, toloro#4723) bleibt auch in
       fester Höhe ein Raster; seine Prüfblätter schweben über die Kachel
       hinaus und werden nicht innen abgeschnitten. */
    .sk-rollt-innen .sk-rahmen-flach > [x-data] {
        display: contents;
    }

    .sk-rollt-innen .sk-rahmen-flach .sk-rahmen-inhalt {
        overflow: visible;
    }

    /* Solange das ⓘ im Kopf offen ist, macht der Inhalt ganz Platz — sonst
       schaute ein abgeschnittener Streifen der Zahlen unter der Karte hervor.
       Nur das ⓘ im Kopf: die Teile von „Kommt das Geld?“ & Co. tragen ihr
       eigenes ⓘ im Inhalt, das den Inhalt nicht ausblenden darf. */
    .sk-rollt-innen .sk-rahmen:has(> [x-data] > .sk-rahmen-kopf .info-knopf[aria-expanded="true"]) > .sk-rahmen-inhalt {
        display: none;
    }

    /* Ein fester Block (Schnellzugriff, Termine, Handlungsbedarf …) hat kein
       Menü im Kopf: Er rollt als Ganzes. */
    .sk-rollt-ganz {
        overflow-y: auto;
    }

    /* Solange unten noch etwas kommt, blendet der Rand weich aus
       (startseite.js); ganz unten steht alles klar da. Der Rand ist höchstens
       ein Drittel des Fensters hoch — in einem flachen Fenster bliebe sonst
       nichts klar stehen. */
    .sk-hat-mehr {
        -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - min(28px, 33%)), transparent);
        mask-image: linear-gradient(to bottom, #000 calc(100% - min(28px, 33%)), transparent);
    }

    /* Das Brett von „Startseite anpassen“ steht im selben Raster wie die
       Startseite; eine Karte mit fester Höhe ist mindestens so hoch wie ihre
       Reihen (die kompakte Karte selbst braucht fast eine). */
    .sk-brett {
        position: relative;
        column-gap: 24px;
    }

    .sk-brett > .sk-hoehe-1 { min-height: 96px; }
    .sk-brett > .sk-hoehe-2 { min-height: 216px; }
    .sk-brett > .sk-hoehe-3 { min-height: 336px; }
    .sk-brett > .sk-hoehe-4 { min-height: 456px; }
    .sk-brett > .sk-hoehe-5 { min-height: 576px; }
    .sk-brett > .sk-hoehe-6 { min-height: 696px; }

    /* Schmale Karten (Viertel, Drittel): Griff und Knöpfe in die erste Zeile,
       Titel und Erklärung darunter in voller Breite — neben drei Knöpfen
       bliebe für den Titel kaum ein Wort Platz. */
    .sk-brett > .sk-breite-3 .sk-karte-kopf,
    .sk-brett > .sk-breite-4 .sk-karte-kopf {
        flex-wrap: wrap;
    }

    .sk-brett > .sk-breite-3 .sk-karte-text-block,
    .sk-brett > .sk-breite-4 .sk-karte-text-block {
        order: 3;
        flex-basis: 100%;
    }
}

/* Die Karte auf dem Brett: Kopf oben, Breite und Höhe unten — bei fester Höhe
   bleibt der Fuß am unteren Rand, wo auch der Griff ◢ sitzt. */
.sk-brett > .sk-karte {
    z-index: 1;
    display: flex;
    flex-direction: column;
}

.sk-karte .sk-karte-fuss {
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 6px 14px;
    margin-top: auto;
    padding-top: 10px;
    padding-right: 26px;
}

/* Ein langes Wort im Titel („Kundenbewertungen“) bricht um, statt unter die
   Knöpfe zu laufen. */
.sk-brett .sk-karte-titel {
    overflow-wrap: anywhere;
    hyphens: auto;
}

.sk-karte.sk-masst {
    outline-style: solid;
    outline-color: var(--primary);
}

.sk-mass {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.sk-mass-wahl {
    width: auto;
    min-height: 28px;
    padding: 2px 6px;
    font-size: var(--text-xs);
    border-width: 1px;
}

/* Der Griff unten rechts: ziehen rastet auf das Raster ein, Pfeiltasten gehen
   auch. Schmal (unter 1024 px) gibt es kein Raster und darum keinen Griff. */
.sk-ziehgriff {
    display: none;
    position: absolute;
    right: 4px;
    bottom: 4px;
    width: 22px;
    height: 22px;
    place-items: center;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg);
    color: var(--text-muted);
    cursor: nwse-resize;
    touch-action: none;
    user-select: none;
}

@media (min-width: 1024px) {
    .sk-ziehgriff {
        display: grid;
    }
}

.sk-ziehgriff:hover,
.sk-ziehgriff:focus-visible {
    color: var(--primary);
    border-color: var(--primary);
}

.sk-ziehgriff svg {
    width: 12px;
    height: 12px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
}

/* Die Größe als Schild an der Karte, solange man zieht oder der Griff den
   Fokus hat: „Hälfte · 3 Reihen“. Auf schmalen Karten (Viertel, Drittel)
   stünde es auf der Auswahl „Höhe“ — dort hängt es unter der Karte im
   Abstand zur nächsten (24 px). */
.sk-mass-schild {
    position: absolute;
    right: 32px;
    bottom: 5px;
    z-index: 2;
    padding: 2px 10px;
    border-radius: var(--radius-full);
    background: var(--primary);
    color: #FFFFFF;
    font-size: var(--text-xs);
    font-weight: 600;
    white-space: nowrap;
    box-shadow: var(--shadow-sm);
    pointer-events: none;
}

.sk-brett > .sk-breite-3 .sk-mass-schild,
.sk-brett > .sk-breite-4 .sk-mass-schild {
    top: calc(100% + 1px);
    right: 0;
    bottom: auto;
}

/* Das Schild steht unter schmalen Karten — dafür darf die Karte (.card
   schneidet sonst ab) über ihren Rand hinaus zeichnen. */
.sk-brett > .sk-breite-3.sk-karte,
.sk-brett > .sk-breite-4.sk-karte {
    overflow: visible;
}

/* Die Rasterlinien, solange gezogen wird: die zwölf Spalten als leichte
   Bänder, die Reihen als Linien dort, wo die Unterkante der gezogenen Karte
   einrastet (ab ihrer Oberkante alle 120 px, je 24 px vor dem Abstand). */
.sk-rasterlinien {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image:
        repeating-linear-gradient(to right,
            rgba(21, 41, 63, 0.05) 0, rgba(21, 41, 63, 0.05) var(--sk-spalte, 64px),
            transparent var(--sk-spalte, 64px), transparent calc(var(--sk-spalte, 64px) + 24px)),
        repeating-linear-gradient(to bottom,
            transparent 0, transparent 95px,
            rgba(21, 41, 63, 0.28) 95px, rgba(21, 41, 63, 0.28) 97px,
            transparent 97px, transparent 120px);
    background-position: 0 0, 0 var(--sk-oben, 0px);
}

/* ── Startseite · Telefonate (toloro#4420) ──
   Die Kachel „Telefonate“ (app2/fragments/kacheln/telefonate): Säulen je Stunde
   und je Arbeitstag aus den Säulen der Geld-Kacheln (skg-saeule), angenommen
   unten, ohne Meldung darüber, verpasst rot oben; in Groß daneben das
   Auslastungsbild Wochentag × Stunde. Jede Zelle trägt ihre Zahl als Text —
   die Farbstufe kommt nur dazu, nie allein. */
.skt-zahl-rot {
    color: var(--danger-text);
}

.skt-rueckruf {
    margin-top: 8px;
}

.skt-teil-angenommen {
    background: var(--primary);
}

.skt-teil-ohne {
    background: var(--neutral);
}

.skt-teil-verpasst {
    background: var(--danger);
}

/* Die Spitzenstunde: Zahl und Stunde fett, damit sie ohne Farbe auffällt. */
.skt-spitze .skg-saeule-wert,
.skt-spitze .skg-saeule-monat {
    font-weight: 700;
    color: var(--text);
}

.skg-saeulen.skt-saeulen-klein {
    height: 90px;
    gap: 6px;
}

.skt-stand {
    margin-right: auto;
    color: var(--text-muted);
}

/* Groß: links heute und die Arbeitstage, rechts das Auslastungsbild — am
   Rahmen abgelesen, denn „Mehr ›“ tauscht nur ihn aus. Wird es doch zu
   schmal (kleines Fenster), rollt nur das Bild waagerecht, der Wochentag
   bleibt dabei links stehen. */
.skt-heute,
.skt-woche {
    min-width: 0;
}

/* Nebeneinander nur, wenn die Kachel innen breit genug ist: Das
   Auslastungsbild braucht gut 600 px, also drei Fünftel von gut 1000 px.
   Gemessen wird die Breite des Inhalts (Container), nicht das Fenster — in
   „Drei Viertel“ und in einem schmaleren Fenster steht das Bild darum unter
   den Säulen. */
.sk-rahmen-inhalt:has(> .skt-mitte) {
    container-type: inline-size;
}

@container (min-width: 1050px) {
    .sk-rahmen[data-groesse="g"] .skt-mitte {
        display: grid;
        grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
        gap: 28px;
        align-items: start;
    }
}

.skt-bild-rahmen {
    overflow-x: auto;
    margin-top: 6px;
}

.skt-bild {
    font-variant-numeric: tabular-nums;
}

.skt-bild th.skt-bild-kopf {
    text-align: center;
    padding: 4px 2px;
    white-space: nowrap;
}

.skt-bild .skt-bild-quote {
    white-space: nowrap;
}

.skt-bild th.skt-bild-tag {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--bg);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--bg-muted);
    white-space: nowrap;
}

.skt-bild td.skt-zelle {
    text-align: center;
    padding: 5px 1px;
    min-width: 26px;
    border: 2px solid var(--bg);
    border-radius: 4px;
    font-size: var(--text-xs);
}

.skt-bild-summe {
    font-weight: 600;
}

/* Vier Stufen nach dem Anteil an der vollsten Zelle; ohne color-mix die
   weiche Primärfarbe bzw. die volle. */
.skt-stufe-0 {
    color: var(--text-muted);
}

.skt-stufe-1 {
    background: var(--primary-soft);
    color: var(--text);
}

.skt-stufe-2 {
    background: var(--primary-soft);
    background: color-mix(in srgb, var(--primary) 30%, var(--bg));
    color: var(--text);
}

.skt-stufe-3 {
    background: var(--primary);
    background: color-mix(in srgb, var(--primary) 72%, var(--bg));
    color: var(--bg);
}

.skt-stufe-4 {
    background: var(--primary);
    color: var(--bg);
}


/* ── Startseite · Schwellen für „Wo klemmt es heute?“ (toloro#4417) ──
   Die Maske /desktop/admin/startseite-schwellen (sks-*) und der Zusatz im ⓘ
   der Zahlen-Kacheln (sk-info-*): die gültigen Schwellen als Liste und der
   Verweis „Schwellen einstellen ›“. */

.sk-info-zeilen {
    margin: 6px 0 0;
    padding-left: 16px;
}

.sk-info-zeilen li + li {
    margin-top: 2px;
}

.sk-info-verweis {
    display: inline-block;
    margin-top: 6px;
    font-weight: 600;
    color: var(--primary);
    text-decoration: none;
}

.sk-info-verweis:hover {
    text-decoration: underline;
}

.sks-einleitung {
    max-width: 920px;
    margin-bottom: 16px;
    line-height: 1.5;
}

.sks-formular {
    max-width: 1280px;
}

.sks-leiste {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin: 0 0 16px;
}

.sks-gruppe {
    margin-bottom: 20px;
}

.sks-gruppe-titel {
    margin: 0 0 8px;
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--text);
}

.sks-kachel {
    margin-bottom: 12px;
    padding: 12px 16px;
}

.sks-kachel-titel {
    margin: 0 0 8px;
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--text);
}

.sks-kachel-hinweis {
    margin: 0;
}

.sks-tabelle-huelle {
    overflow-x: auto;
}

.sks-tabelle {
    width: 100%;
    min-width: 760px;
    table-layout: fixed;
}

/* Gleiche Spalten in allen Tabellen der Maske: Kennzahl, Gelb, Rot, An, Vorgabe, Zurück. */
.sks-tabelle th:nth-child(1) { width: 31%; }
.sks-tabelle th:nth-child(2),
.sks-tabelle th:nth-child(3) { width: 16%; }
.sks-tabelle th:nth-child(4) { width: 5%; }
.sks-tabelle th:nth-child(5) { width: 15%; }
.sks-tabelle th:nth-child(6) { width: 17%; }

.sks-tabelle td {
    vertical-align: middle;
}

.sks-name {
    overflow-wrap: anywhere;
}

.sks-marke {
    margin-left: 6px;
}

.sks-klein {
    display: block;
    margin-top: 2px;
    font-size: var(--text-xs);
}

.sks-fehler {
    display: block;
    margin-top: 4px;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--danger-text);
}

.sks-zeile-eingestellt td:first-child {
    box-shadow: inset 3px 0 0 var(--info);
}

.sks-zeile-fehler td:first-child {
    box-shadow: inset 3px 0 0 var(--danger);
}

.sks-feld {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.sks-wort {
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sks-zahl {
    width: 76px;
    text-align: right;
}

.sks-zahl-fehler {
    border-color: var(--danger);
}

/* Ein Wort wie „Werktage“ passt nicht neben jedes Feld — es rückt dann unter die Zahl, statt in die Nachbarspalte zu laufen. */
.sks-zeichen {
    min-width: 12px;
    white-space: nowrap;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.sks-schalter {
    width: 18px;
    height: 18px;
}

.sks-vorgabe {
    overflow-wrap: anywhere;
}

.sks-aktion {
    text-align: right;
}

/* Eine Zahl, die ihre Kachel nach der Schwelle färbt (Leads überfällig in
   „Sind die Kunden zufrieden?“): gelb wie das Schild in „Wo klemmt es
   heute?“ — rot ist .sk-wert-rot. */
.sk-wert-gelb {
    color: var(--warning-text);
}

/* Startseite Stufe 3a — schritte-dauer, von-hand (#4460)
   „Schritte: Soll gegen Ist“: je Punkt ein Balkenpaar — oben das Soll (grau),
   darunter das Ist (rot über Soll); in der Firmen-Tabelle der Anteil pünktlich
   als Balken mit Zahl daneben. „Von Hand statt automatisch“: Säulen mit
   Handarbeit (gelb) über dem Rest (ruhig). Stand bzw. Fenster links im Fuß. */
.sksd-paar {
    display: grid;
    gap: 3px;
}

.sksd-paar .sk-balken-spur,
.sksd-paar .sk-balken {
    height: 6px;
}

.sksd-anteil {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 6px;
    align-items: center;
    font-variant-numeric: tabular-nums;
}

.sksd-fenster,
.skvh-stand {
    margin-right: auto;
    color: var(--text-muted);
}

.skg-saeulen.skvh-saeulen {
    height: 110px;
    gap: 6px;
}

/* „Mo 13.“ und „KW 42“ unter zehn bzw. acht Säulen: In halber Breite ist eine Säule
   schmaler als die Beschriftung — sie bricht dann am Leerzeichen um statt in die Nachbarin zu laufen. */
.skvh-saeulen .skg-saeule-monat {
    white-space: normal;
    line-height: 1.15;
}

.skvh-teil-hand {
    background: var(--warning);
}

.skvh-teil-rest {
    background: var(--neutral);
}

/* Startseite Stufe 3a — geraete-einsatz (#4463)
   Je Kategorie ein gestapelter Balken in der Spur der Balkenliste: auf
   Baustellen, bei Mitarbeitern, frei im Lager nebeneinander. Die Teile sind
   .sk-alter-teil (8 px hoch), die Farben .sk-balken-primaer/-akzent/-ruhig;
   die Spur legt sie nur in eine Reihe. */
.skge-stapel {
    display: flex;
}

.skge-stapel > .sk-alter-teil {
    flex: none;
}

/* Reiter „Schriftverkehr": die Post einer Maschine (toloro#4607)
   Grau wie auf der Partei-Karte — der Titel trägt das Wort der Art, das
   Abzeichen „automatisch" steht daneben (nie Grau allein). Bleibt der Titel
   ein Link auf die Aufgabe, zeigt ihn die Unterstreichung bei Zeiger und
   Tastatur; den Fokusring legt die zentrale Regel (components.css). Kontrast
   --text-secondary auf Weiß 5,05:1. */
.sv-zeile--automatisch .sv-zeile-titel {
    color: var(--text-secondary);
}

.sv-zeile--automatisch a.sv-zeile-titel:focus-visible {
    text-decoration: underline;
}

/* Ein Titel ohne Link (eingegangene Mail ohne Aufgabe, auch die graue Post
   einer Maschine) täuscht beim Darüberfahren keinen Link vor (UX-Blick zu
   !5158): Die Unterstreichung aus `.sv-zeile-titel:hover` (components.css)
   gehört nur dem `<a>`. Steht hier statt dort, weil components.css in einem
   fremden offenen MR liegt — beim nächsten Griff dort zusammenführen
   (Selektor auf `a.sv-zeile-titel:hover` einengen, diese Regel weg). */
span.sv-zeile-titel:hover {
    text-decoration: none;
}

/* ── „Was der Kunde bekommt": die Kacheln der Mahnung (toloro#4616) ──────
   Rechts neben „Anhänge der Mail" je Datei eine Kachel mit dem Bild ihrer
   ersten Seite (Fragment app2/fragments/mahn-kachel, Reihe aus
   freigabe-beilage.js). Das Blatt hat A4-Maß (150 × 212), das Bild liegt
   oben an und wird skaliert, nie beschnitten; lädt es nicht, blendet
   freigabe-beilage.js das graue Blatt mit dem Satz ein (mk-kachel--fehlt
   plus hidden=false am Satz). Die Kachel ist ein Mausziel ohne Tab-Stopp;
   beim Darüberfahren dunkelt nur der Rand nach — ein Ring sähe aus wie
   der Fokus. */
.mk-reihe {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
}

.mk-kachel {
    width: 150px;
}

.mk-seite {
    display: block;
    position: relative;
    width: 150px;
    height: 212px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 3px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.14);
    overflow: hidden;
    box-sizing: border-box;
    cursor: zoom-in;
}

.mk-seite:hover {
    border-color: var(--primary);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}

.mk-bild {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: top;
}

.mk-fehlt {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 12px;
    text-align: center;
    font-size: var(--text-xs);
    color: var(--text-secondary);
    background: var(--bg-subtle);
}

.mk-kachel--fehlt .mk-bild {
    display: none;
}

.mk-name {
    margin-top: 6px;
    font-size: var(--text-xs);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mk-meta {
    font-size: var(--text-2xs);
    color: var(--text-secondary);
}

.mk-abzeichen {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-subtle);
    font-size: var(--text-2xs);
    vertical-align: 1px;
}

.mk-abzeichen--fest {
    color: var(--info-text);
}

/* ── Duplikatsverdacht über der Mail (toloro#4648) ─────────────────────
   Matthias, 22.10.2026: „Das muss groß erkenntlich sein, warum diese
   Aufgabe entstanden ist.“ Groß nur ⚠ und „Duplikatsverdacht“, darunter
   klein der vorhandene Lead. Farben aus den Warn-Tokens wie .alert-warning. */
.duplikat-kasten {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    padding: 18px 22px;
    border: 2px solid var(--warning);
    background: var(--warning-soft);
    color: var(--warning-text);
}

.duplikat-kasten-zeichen {
    font-size: 32px;
    line-height: 1;
    flex-shrink: 0;
}

.duplikat-kasten-inhalt {
    flex: 1;
    min-width: 0;
}

.duplikat-kasten-titel {
    margin: 0;
    font-size: 24px;
    font-weight: 800;
    line-height: 1.2;
}

.duplikat-kasten-text {
    margin: 6px 0 0;
    font-size: var(--text-sm);
}

.duplikat-kasten-liste {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.duplikat-kasten-lead {
    padding: 8px 12px;
    border: 1px solid var(--warning);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--text-sm);
}

.duplikat-kasten-lead a {
    color: var(--text);
}

.duplikat-kasten-grund {
    margin-top: 2px;
    font-size: var(--text-xs);
    color: var(--text-secondary);
}

.duplikat-kasten-knoepfe {
    margin-top: 12px;
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.duplikat-kasten-knoepfe:empty {
    display: none;
}
