/* Ergänzungen der Hub-Oberfläche zum gemeinsamen Designsystem (app.css der Komponenten-
   Bibliothek). Nur, was es dort nicht gibt: die Anmeldeseite. */
.hub-login {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}

.hub-login-card {
    width: 100%;
    max-width: 380px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 28px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.hub-login-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--text);
}

.hub-login-title {
    margin: 0;
    font-size: 20px;
    font-weight: 500;
}

.hub-login-sub {
    margin: 0;
    font-size: 12.5px;
    opacity: 0.7;
}

.hub-login-actions {
    display: flex;
    gap: 8px;
    margin-top: 4px;
}

.hub-login-actions .btn {
    flex: 1;
}

.hub-login-hint {
    margin: 4px 0 0;
    font-size: 11.5px;
    line-height: 1.5;
    opacity: 0.65;
}

/* ---- Verwaltungsseiten des Hubs (PKI, Benutzer, Mein Konto) ---------------------------------
   Die Seiten tragen das view-Gerüst der Komponenten-Bibliothek; hier steht nur, was app.css
   nicht mitbringt. */

/* Die Bibliothek setzt ihre Seitentitel als <div class="view-title">; die Hub-Seiten brauchen
   ein echtes <h1> (FocusOnNavigate springt nach Navigation dorthin) — ohne Browser-Margin. */
h1.view-title { margin: 0; }

/* Echte <table>-Zeilen im Look der table-card (.t-head/.t-row der Bibliothek sind CSS-Grids).
   Die Verwaltung bleibt bewusst bei <table>: Kopf und Zellen gehören semantisch zusammen, und
   die E2E-Prüfungen greifen spaltenweise zu (td:nth-child). */
.target-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.target-table thead th {
    padding: 8px 14px;
    text-align: left;
    background: var(--panel2);
    border-bottom: 1px solid var(--border-soft);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text5);
    white-space: nowrap;
}
.target-table tbody td { padding: 10px 14px; border-bottom: 1px solid var(--border-soft); vertical-align: middle; }
.target-table tbody tr:last-child td { border-bottom: none; }
.target-table tbody tr:hover { background: var(--hover); }
/* Die ganze Zeile führt in den Detail-Dialog (Benutzer, Gruppen) — dasselbe Verhalten wie in der
   Asset-Liste, deren .t-row.clickable das Vorbild ist. */
.target-table tbody tr.clickable { cursor: pointer; }
.target-table td .cell-primary { font-size: 12.5px; }
.target-table td .cell-sub { font-family: var(--font-mono); font-size: 10.5px; color: var(--text4); margin-top: 2px; }
/* .cell-check der Bibliothek ist ein Flex-Container für Grid-Zeilen; in einer Tabellenzelle
   würde display:flex die Zelle stauchen — hier zählt nur die Ausrichtung des Kästchens. */
.target-table td.cell-check { display: table-cell; text-align: center; }
/* Wer wirklich Mitglied ist, ist die eigentliche Auskunft der Mitgliederliste — die Kante links
   trennt sie von den bloß wählbaren Konten, ohne dass man Häkchen zählen muss (Muster
   .t-row.checked der Asset-Liste). */
.target-table tbody tr.member-on { box-shadow: inset 2px 0 0 var(--accent, #4CC2A9); }

/* Eine Liste INNERHALB einer Dialog-Rubrik: ohne eigenen Außenabstand, damit sie unter ihrem
   Etikett sitzt und nicht daneben. */
.detail-section > .table-card { margin: 2px 0 0; }
.target-table td.mono { font-family: var(--font-mono); font-size: 11.5px; color: var(--text2); }
.target-table td.strong { font-weight: 500; }
.target-table td.dim { font-family: var(--font-mono); font-size: 11px; color: var(--text3); white-space: nowrap; }
/* Auswahlfelder in Tabellenzeilen kompakter als im Formular. */
.target-table .select-input { padding: 5px 9px; font-size: 12px; }

/* Kompakte Fassung der Eingabefelder — für Zeilen, in denen ein Feld neben Knöpfen der Größe
   .btn.sm steht (Sichtungsliste). Ohne sie überragte das Feld die Knöpfe um vier Pixel. */
.text-input.sm, .select-input.sm { padding: 4px 9px; font-size: 11.5px; }

/* In einer panel-card steht dieselbe Tabelle ohne eigenen Kasten: nur Kopf- und Trennlinien. */
.panel-card .target-table thead th { background: transparent; padding: 0 14px 6px 0; }
.panel-card .target-table tbody td { padding: 8px 14px 8px 0; }
.panel-card .target-table tbody tr:hover { background: transparent; }

/* Rechtsbündige Aktionsgruppe einer Tabellenzeile (Muster .cell-actions, nur umbruchfähig). */
.row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 6px; flex-wrap: wrap; }

/* Freigabe-Chips (Kunden je Benutzer, „darf provisionieren"): eine Checkbox in Pillenform.
   Die Checkbox bleibt sichtbar — sie IST das Bedienelement, und die E2E-Prüfungen klicken sie. */
.chip-row { display: flex; flex-wrap: wrap; gap: 5px; }
.chip-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px 3px 7px;
    border-radius: 99px;
    border: 1px solid var(--border-strong);
    background: transparent;
    font-family: var(--font-mono);
    font-size: 10.5px;
    color: var(--text3);
    cursor: pointer;
    white-space: nowrap;
    user-select: none;
}
.chip-toggle:hover { border-color: var(--text4); color: var(--text2); }
.chip-toggle input { width: 12px; height: 12px; margin: 0; accent-color: var(--accent, #4CC2A9); }
.chip-toggle.on {
    background: color-mix(in srgb, var(--accent, #4CC2A9) 13%, transparent);
    border-color: color-mix(in srgb, var(--accent, #4CC2A9) 40%, transparent);
    color: var(--text);
}
.chip-toggle:has(input:disabled) { opacity: .55; cursor: default; }

/* Der Kunden-Stand kennt DREI Werte (Asset-Umbau): freigegeben, nichts, entzogen. „Nichts" ist
   nicht dasselbe wie „entzogen" — wer seine Freigabe über eine Gruppe erbt, dem nimmt nur ein
   ausdrücklicher Entzug etwas weg. Deshalb drei Knöpfe statt eines Hakens; sie sitzen seit
   2026-09-07 als Schalter am rechten Rand einer Tabellenzeile. */
.grant-switch {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px;
    border-radius: 99px;
    border: 1px solid var(--border-strong);
}
.grant-state {
    border: 1px solid transparent;
    border-radius: 99px;
    background: transparent;
    font-family: var(--font-mono);
    font-size: 10px;
    padding: 1px 7px;
    color: var(--text4);
    cursor: pointer;
}
.grant-state:hover { color: var(--text2); border-color: var(--border-strong); }
.grant-state.frei.on {
    background: color-mix(in srgb, var(--accent, #4CC2A9) 18%, transparent);
    border-color: color-mix(in srgb, var(--accent, #4CC2A9) 45%, transparent);
    color: var(--text);
}
.grant-state.entzug.on {
    background: color-mix(in srgb, var(--danger, #E24B4A) 18%, transparent);
    border-color: color-mix(in srgb, var(--danger, #E24B4A) 45%, transparent);
    color: var(--text);
}
.grant-state.on:not(.frei):not(.entzug) { color: var(--text2); border-color: var(--border-strong); }

/* Der Freigabe-Editor selbst: Kundenebene oben, Asset-Ausnahmen darunter, durch eine Linie
   getrennt. Bis 2026-09 standen beide Hälften ohne Abstand und ohne Trennung übereinander —
   im Dialog fiel sofort auf, dass sie zwei verschiedene Dinge sind. */
.grant-editor { display: flex; flex-direction: column; gap: 12px; }
.grant-exceptions {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 12px;
    border-top: 1px solid var(--border-soft);
}
/* Die Kante links sagt die Richtung, ohne dass man die Stand-Spalte lesen muss: grün steht für
   freigegeben, rot für ausdrücklich entzogen. Ohne Kante heißt „keine eigene Freigabe" — und das
   ist etwas anderes als ein Entzug. */
.target-table tbody tr.member-off { box-shadow: inset 2px 0 0 var(--danger, #E24B4A); }

/* Mitglied aus dem Identitätsanbieter (Hub §5.1): der kleine Zusatz am Chip sagt, woher die
   Mitgliedschaft kommt und wann der Anbieter sie zuletzt bestätigt hat. */
.chip-tag {
    font-size: 9.5px;
    color: var(--text4);
    border-left: 1px solid var(--border-strong);
    padding-left: 6px;
    margin-left: 2px;
    white-space: nowrap;
}
.chip-toggle.on .chip-tag { color: var(--text3); }

/* Eine gesichtete Anbietergruppe: Kennung, Zahlen, Entscheidungsknöpfe. */
.sighting {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--panel2);
}
.sighting-head { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; }
.sighting-head .mono { font-weight: 600; }
.sighting-head .dim { font-size: 11px; }

/* Abschnittskopf über einer Tabelle: Titel + erklärender Untertitel (view-title/-sub im Kleinen). */
.section-head { margin-top: 8px; }
.section-head .t { font-size: 13px; font-weight: 600; }
.section-head .s { font-size: 11.5px; color: var(--text3); margin-top: 2px; max-width: 760px; line-height: 1.5; }

/* Titelzeile einer panel-card (Muster der Zertifikatsverwaltung) und der erklärende Satz
   darunter. Beide Klassen benutzen Zertifikatsseite und „Mein Konto" seit je — gestaltet war
   nur die erste, weshalb der Hinweis unter der Überschrift in voller Textgröße stand. */
.panel-card .pc-title { font-weight: 600; font-size: 13px; }
.panel-card .pc-hint { font-size: 12px; line-height: 1.55; color: var(--text3); max-width: 760px; }

/* Die Bildfläche ist eine eigene Insel (Hub-Konzept §6.3): DOM-technisch ein Geschwister der
   Verwaltung, sichtbar gehört sie mitten in den Arbeitsbereich. hub.js hängt sie dafür in den
   Schlitz des sichtbaren Sitzungsreiters.

   ENTSCHEIDEND ist, was passiert, wenn sie gerade in KEINEM Schlitz hängt — weil ein Reiter neu
   rendert, der Draht abriss, die Laufzeit später kommt oder der Benutzer weggeblättert hat:
   Dann ist sie unsichtbar. Punkt. Früher war sie in diesem Fall ein festes Overlay über der
   ganzen Oberfläche und verdeckte Navigation, Reiterleiste und Bedienleiste — derselbe
   Fehlerbericht kam dreimal. Ein verlorener Platz darf höchstens „kein Bild" bedeuten,
   niemals „Oberfläche zu". */
.vnc-island {
    display: none;
    background: #000;
}

.vnc-insel-halter {
    position: relative;
}

/* Der Schlitz gehört dem Skript, nicht Blazor: Blazor rendert ihn genau einmal leer und fasst ihn
   nie wieder an. Damit kann kein Abgleich des Renderers die eingehängte Insel verschieben oder
   mitentfernen — sie liegt außerhalb dessen, was Blazor als seine Kinder führt. */
.vnc-insel-halter > .vnc-insel-schlitz {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.vnc-insel-schlitz > .vnc-island.an {
    display: flex;
    position: absolute;
    inset: 0;
    pointer-events: auto;
}

/* Die Bühne der Sitzung darf nicht durch den leeren Halter zusammenfallen. */
.vnc-insel-schlitz > .vnc-island > .vnc-stage {
    flex: 1;
    min-height: 0;
}

/* ---- Ladeanzeige der WebAssembly-Laufzeit (Hub-Konzept §6.3) --------------------------------
   Der Bildteil bringt beim ersten Aufruf rund 24 MB mit. Ohne Anzeige sieht das aus wie eine
   schwarze Fläche, die nichts tut — mit Anzeige ist es ein Ladevorgang mit Ende. */

/* Steht die Laufzeit, verschwinden beide Ladeanzeigen über eine Klasse an der Wurzel — nicht
   dadurch, dass das Skript ihre Knoten aus dem DOM nimmt. Die Knoten gehören Blazor; wer sie
   hinter dessen Rücken entfernt, lässt den nächsten Abgleich auf einen Knoten ohne Elternteil
   laufen und reißt damit den ganzen Renderdurchgang mit. */
.wasm-bereit .insel-laden,
.wasm-bereit .hub-ladeschild,
.wasm-bereit .hub-ladeleiste {
    display: none;
}

/* Lesbare Fassung der Ladeleiste: nennt beim Namen, worauf gewartet wird, samt Prozent und
   Megabyte. Oben rechts, klein, ohne Klickfang — sie erklärt eine Wartezeit, sie fordert nichts. */
.hub-ladeschild {
    position: fixed;
    top: 10px;
    right: 12px;
    z-index: 60;
    padding: 5px 10px;
    border-radius: 999px;
    background: var(--panel, #16181d);
    border: 1px solid var(--line, #2a2e37);
    color: var(--text2, #b6bcc8);
    font-size: 11.5px;
    font-family: var(--font-mono);
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity .2s ease-out;
}

.hub-ladeschild.sichtbar { opacity: 1; }

.insel-laden {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    background: #000;
    color: var(--text2);
}

.insel-laden-titel { font-size: 13px; }

.insel-laden-bar {
    width: min(340px, 60%);
    height: 4px;
    border-radius: 2px;
    background: rgba(255, 255, 255, .14);
    overflow: hidden;
}

.insel-laden-bar > span {
    display: block;
    height: 100%;
    width: 0;
    background: var(--accent, #4CC2A9);
    transition: width .25s ease-out;
}

/* Unbestimmter Balken: Es gibt keine Gesamtgröße, gegen die sich ein Fortschritt rechnen ließe
   (die Boot-Konfiguration steckt seit .NET 10 in dotnet.js). Ein wandernder Block sagt „es geht
   voran", ohne eine Genauigkeit zu behaupten, die wir nicht haben. Die echten Zahlen stehen
   darunter. */
.insel-laden-bar.unbestimmt > span,
.hub-ladeleiste.unbestimmt {
    width: 35%;
    animation: hub-unbestimmt 1.4s ease-in-out infinite;
    transition: none;
}

@keyframes hub-unbestimmt {
    0%   { margin-left: -35%; }
    100% { margin-left: 100%; }
}

/* Wer Bewegung im Bild nicht verträgt, bekommt einen ruhenden, halb gefüllten Balken. */
@media (prefers-reduced-motion: reduce) {
    .insel-laden-bar.unbestimmt > span,
    .hub-ladeleiste.unbestimmt {
        animation: none;
        width: 50%;
        margin-left: 0;
    }
}

.insel-laden-sub {
    font-size: 11.5px;
    color: var(--text3);
    font-family: var(--font-mono);
}

/* Dünne Leiste ganz oben, solange die Laufzeit lädt: Sie erklärt, warum ein früher Klick noch
   nicht ankommt. */
.hub-ladeleiste {
    position: fixed;
    top: 0;
    left: 0;
    height: 2px;
    width: 0;
    background: var(--accent, #4CC2A9);
    z-index: 2000;
    transition: width .25s ease-out;
    pointer-events: none;
}

/* Zustimmungskarten des MCP-Endpunkts (Hub-Konzept §13.3): Verbindungsanfragen eines KI-Clients
   warten hier auf den Benutzer — auf jeder Seite sichtbar, über der Oberfläche, unter Dialogen. */
.mcp-zustimmung {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 1500;
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: min(360px, calc(100vw - 32px));
}

.mcp-zustimmung .karte {
    background: var(--panel);
    border: 1px solid var(--accent, #4CC2A9);
    border-radius: 10px;
    padding: 12px 14px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, .45);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.mcp-zustimmung .titel {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text3);
}

.mcp-zustimmung .ziel { font-weight: 600; font-size: 14px; }

.mcp-zustimmung .grund { font-size: 12.5px; color: var(--text2); }

.mcp-zustimmung .zeile {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
}

.mcp-zustimmung .zeit {
    font-size: 11px;
    color: var(--text3);
    font-family: var(--font-mono);
}

/* --- Benutzerchat: Postkorb und Gesprächsansicht (Benutzerchat-Konzept §10.2) -------------- */

.chat-inbox-row {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px 14px;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.chat-inbox-row:hover { background: var(--hover, rgba(127, 127, 127, 0.08)); }

.chat-inbox-row.selected { background: var(--hover, rgba(127, 127, 127, 0.14)); }

.chat-line {
  max-width: 78%;
  margin-bottom: 10px;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--panel, rgba(127, 127, 127, 0.1));
}

/* Der Benutzer steht links, der Support rechts — dieselbe Leserichtung wie im Fenster des
   Benutzers, nur spiegelbildlich: Wer hier sitzt, ist die andere Seite. */
.chat-line.operator { margin-left: auto; background: var(--accent-soft, rgba(11, 107, 203, 0.18)); }

/* Die künstliche Intelligenz ist IMMER als solche gekennzeichnet (Entscheidung 10, §11.7) —
   auch hier, damit ein übernehmender Mitarbeiter auf einen Blick sieht, was von einem Modell
   stammt und was der Benutzer selbst geschrieben hat. */
.chat-line.ki { border: 1px solid var(--accent, #7c5cd6); }

.chat-line.system {
  max-width: 100%;
  text-align: center;
  background: transparent;
  font-size: 0.85em;
  opacity: 0.75;
}

.chat-sender { font-size: 0.78em; font-weight: 600; opacity: 0.85; margin-bottom: 2px; }

.chat-text { white-space: pre-wrap; overflow-wrap: anywhere; }

.chat-time { font-size: 0.7em; opacity: 0.6; margin-top: 3px; }

.chat-attachment {
  margin-top: 6px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
}

/* Ausführbare Dateien und Archive sichtbar markiert, damit ein Mitarbeiter weiß, was er
   anklickt (Benutzerchat §11.8). */
.chat-attachment.danger { border-color: var(--danger, #a3341f); }
