/*
 * Design-System der Richtsoft Platform — Basisschicht (M21.1).
 *
 * Aufbau: (1) Token als CSS Custom Properties, (2) Dark-Palette, (3) sanfter Reset, (4) Element-Basis,
 * (5) Blazor-Framework-Hooks. Komponenten- und Layoutklassen folgen in M21.2/M21.3 — hier steht bewusst
 * nur, was jede Seite ohne eigene Klasse erbt.
 *
 * Zwei Randbedingungen bestimmen die Bauform (siehe docs/milestones/M21.md):
 * - Die CSP aus M04.7 ist scharf: auf /docs/* gilt style-src 'self' ohne 'unsafe-inline'. Deshalb keine
 *   Inline-Styles, keine style="…"-Attribute und keine externen Ressourcen (Fonts/CDN) — Farben, Fonts und
 *   Icons müssen aus dieser Datei bzw. scoped .razor.css kommen.
 * - Die Oberfläche ist static SSR ohne JavaScript. Alles Interaktive (Fokus, Hover, Aufklappen) muss mit
 *   CSS allein funktionieren.
 *
 * Farbwelt: neutrale Graustufen mit genau einem Akzentton (Default laut M21.md, solange die Markenfrage
 * offen ist). Dark Mode folgt allein prefers-color-scheme — ein Umschalter bräuchte Persistenz und damit
 * JS oder ein Cookie.
 */

:root {
    /* Lässt Browser-Defaults (Formularelemente, Scrollbars) der aktiven Palette folgen. */
    color-scheme: light dark;

    /* ---- Farbe: Flächen ---- */
    --color-surface: #ffffff;
    --color-surface-sunken: #f4f5f7;
    --color-surface-raised: #ffffff;
    --color-surface-hover: #eceef1;
    --color-surface-accent-soft: #e8f1fb;

    /* ---- Farbe: Text ---- */
    --color-text: #14171a;
    --color-text-muted: #575f68;
    --color-text-on-accent: #ffffff;

    /* ---- Farbe: Rahmen ---- */
    --color-border: #d3d8de;
    /* -strong trägt Ränder, die etwas abgrenzen müssen (Eingabefelder, Badges, Leerzustand) → ≥ 3:1 (WCAG 1.4.11),
       und zwar auch auf der abgesenkten Fläche, nicht nur auf Weiß. */
    --color-border-strong: #838991;

    /* ---- Farbe: Akzent ---- */
    --color-accent: #0f5696;
    --color-accent-hover: #0b4076;
    --color-accent-muted: #4a8ac9;

    /*
     * ---- Farbe: Status (semantisch) ----
     * Je Status ein Textton (auf -surface UND auf der Grundfläche lesbar) und eine getönte Fläche. Die
     * Paare sind auf WCAG-AA (≥ 4,5:1) geprüft; die Prüfung wiederholt sich in M21.3 für die Badges.
     */
    --color-success: #14663a;
    --color-success-surface: #e4f3ea;
    --color-warning: #74500a;
    --color-warning-surface: #fbf0d9;
    --color-danger: #a3161c;
    --color-danger-surface: #fbeaea;
    --color-info: #0d556f;
    --color-info-surface: #e3f1f7;

    /*
     * ---- Farbe: paletten-fest ----
     * Das Fehlerbanner des Frameworks (#blazor-error-ui) bleibt in BEIDEN Paletten hell, damit es bei
     * Verbindungsverlust nicht mit dem Seiteninhalt verschwimmt (es trägt dafür color-scheme: light only,
     * siehe MainLayout.razor.css). Die Werte standen bis M21.7 als rohe Hex-Zahlen in jener Datei — zwei davon
     * Kopien der Light-Token oben, die beim nächsten Palettenwechsel still auseinandergelaufen wären, und alle
     * drei außer Reichweite von DesignTokenContrastTests, der nur app.css liest. Sie stehen deshalb hier und
     * werden im Dark-Block ausdrücklich mit demselben Wert wiederholt: „fest" ist eine Entscheidung, die man
     * sehen können muss, und der Dauertest verlangt für jedes --color-Token eine Dark-Definition.
     */
    --color-warning-fixed: #74500a;
    --color-warning-surface-fixed: #fbf0d9;
    --color-warning-text-fixed: #3d2b06;

    /* ---- Fokus ---- */
    --color-focus-ring: #0f5696;
    --focus-ring-width: 2px;
    --focus-ring-offset: 2px;

    /* ---- Typografie ---- */
    /* System-Font-Stack: kein Webfont, weil jede externe Schriftquelle die CSP aufweichen würde. */
    --font-family-base: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-family-mono: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Consolas, "Liberation Mono", monospace;

    --font-size-xs: 0.75rem;
    --font-size-sm: 0.875rem;
    --font-size-md: 1rem;
    --font-size-lg: 1.125rem;
    --font-size-xl: 1.375rem;
    --font-size-2xl: 1.75rem;
    --font-size-3xl: 2.25rem;

    --font-weight-normal: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;

    --line-height-tight: 1.25;
    --line-height-normal: 1.6;

    /* ---- Abstände (4-px-Raster) ---- */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4rem;

    /* ---- Radien ---- */
    --radius-sm: 3px;
    --radius-md: 6px;
    --radius-lg: 10px;
    --radius-pill: 999px;

    /* ---- Schatten ---- */
    --shadow-sm: 0 1px 2px rgba(15, 23, 32, 0.08);
    --shadow-md: 0 2px 6px rgba(15, 23, 32, 0.10), 0 1px 2px rgba(15, 23, 32, 0.06);
    --shadow-lg: 0 8px 24px rgba(15, 23, 32, 0.14), 0 2px 6px rgba(15, 23, 32, 0.08);
}

/*
 * Dark-Palette. Überschrieben werden ausschließlich Farb-Token — Typo-, Abstands-, Radien- und
 * Fokus-Maße bleiben identisch, damit beide Paletten dasselbe Layout ergeben.
 */
@media (prefers-color-scheme: dark) {
    :root {
        --color-surface: #16191e;
        --color-surface-sunken: #101317;
        --color-surface-raised: #1d2128;
        --color-surface-hover: #262b33;
        --color-surface-accent-soft: #16293d;

        --color-text: #e7eaee;
        --color-text-muted: #9ba3ae;
        --color-text-on-accent: #0a1017;

        --color-border: #2f353e;
        --color-border-strong: #6d757f;

        --color-accent: #74b2f0;
        --color-accent-hover: #9bc9f6;
        --color-accent-muted: #4a7fb4;

        --color-success: #62cb92;
        --color-success-surface: #13301f;
        --color-warning: #e3b45f;
        --color-warning-surface: #33270e;
        --color-danger: #f28f8a;
        --color-danger-surface: #3a1b1a;
        --color-info: #6ec6e9;
        --color-info-surface: #0f2c39;

        /* Bewusst IDENTISCH zur Light-Palette — siehe die Begründung an der Definition oben. */
        --color-warning-fixed: #74500a;
        --color-warning-surface-fixed: #fbf0d9;
        --color-warning-text-fixed: #3d2b06;

        --color-focus-ring: #74b2f0;

        /* Auf dunklem Grund trägt nicht der Schatten die Tiefe, sondern der Kontrast der Fläche. */
        --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.40);
        --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.30);
        --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.55), 0 2px 6px rgba(0, 0, 0, 0.35);
    }
}

/* ------------------------------------------------------------------ */
/* Reset — sanft: räumt Browser-Inkonsistenzen ab, ohne Semantik zu    */
/* entfernen (Listen und Überschriften behalten ihre Bedeutung).       */
/* ------------------------------------------------------------------ */

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

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd {
    margin: 0;
}

/* Bilder/Medien brechen das Layout auf schmalen Viewports sonst auf. */
img,
picture,
svg,
video {
    display: block;
    max-width: 100%;
}

/* Formularelemente erben Schrift nicht von selbst. */
input,
button,
textarea,
select {
    font: inherit;
    color: inherit;
}

/* Nutzer mit reduzierter Bewegungsvorliebe bekommen keine Animation aufgezwungen. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ------------------------------------------------------------------ */
/* Element-Basis                                                       */
/* ------------------------------------------------------------------ */

html {
    /* Respektiert die Browser-Schriftgröße des Nutzers (keine px-Festlegung). */
    -webkit-text-size-adjust: 100%;
}

body {
    background-color: var(--color-surface-sunken);
    color: var(--color-text);
    font-family: var(--font-family-base);
    font-size: var(--font-size-md);
    line-height: var(--line-height-normal);
    min-height: 100vh;
}

/* Der margin-block stiftet den vertikalen Rhythmus, solange eine Seite keine eigenen Klassen trägt. */
h1, h2, h3, h4, h5, h6 {
    line-height: var(--line-height-tight);
    font-weight: var(--font-weight-semibold);
    text-wrap: balance;
    margin-block: var(--space-5) var(--space-3);
}

h1 { font-size: var(--font-size-3xl); }
h2 { font-size: var(--font-size-2xl); }
h3 { font-size: var(--font-size-xl); }
h4 { font-size: var(--font-size-lg); }
h5, h6 { font-size: var(--font-size-md); }

p, ul, ol, dl, table, pre, blockquote, form {
    margin-block: 0 var(--space-4);
}

a {
    color: var(--color-accent);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
}

a:hover {
    color: var(--color-accent-hover);
}

/*
 * Sichtbarer Fokus für Tastaturnutzer. :focus-visible statt :focus, damit Mausklicks keinen Ring
 * hinterlassen — der Ring ist eine Orientierungshilfe, keine Zustandsanzeige.
 */
:focus-visible {
    outline: var(--focus-ring-width) solid var(--color-focus-ring);
    outline-offset: var(--focus-ring-offset);
}

/* Blazor setzt den Fokus nach Navigation auf h1 — dort ist der Ring Rauschen, nicht Orientierung. */
h1:focus,
h1:focus-visible {
    outline: none;
}

hr {
    border: 0;
    border-top: 1px solid var(--color-border);
    margin-block: var(--space-5);
}

small {
    font-size: var(--font-size-sm);
}

code, kbd, samp, pre {
    font-family: var(--font-family-mono);
    font-size: var(--font-size-sm);
}

code {
    background-color: var(--color-surface-sunken);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0.1em 0.35em;
}

pre {
    background-color: var(--color-surface-sunken);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow-x: auto;
    padding: var(--space-4);
}

pre code {
    background: none;
    border: 0;
    padding: 0;
}

blockquote {
    border-left: 3px solid var(--color-border-strong);
    color: var(--color-text-muted);
    padding-left: var(--space-4);
}

table {
    border-collapse: collapse;
}

th {
    text-align: left;
    font-weight: var(--font-weight-semibold);
}

th, td {
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

fieldset {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
}

legend {
    font-weight: var(--font-weight-semibold);
    padding-inline: var(--space-2);
}

label {
    font-weight: var(--font-weight-medium);
}

/* ------------------------------------------------------------------ */
/* Blazor-Framework-Hooks                                              */
/* Diese Klassen vergibt das Framework selbst — sie müssen zur         */
/* Token-Welt passen, auch wenn keine Komponente sie explizit setzt.   */
/* ------------------------------------------------------------------ */

/* Validierungszustände aus EditForm/DataAnnotations. Fachlich maßgeblich bleibt die FluentValidation
   am Command; diese Marker sind reine UI-Rückmeldung. */
.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--color-success);
}

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

.validation-message {
    color: var(--color-danger);
    font-size: var(--font-size-sm);
}

/* Fallback-Fläche der ErrorBoundary-Komponente (derzeit ungenutzt, aber vom Framework jederzeit
   aktivierbar) — deutschsprachig und ohne das eingebettete Base64-SVG des Scaffold-Templates. */
.blazor-error-boundary {
    background-color: var(--color-danger-surface);
    border: 1px solid var(--color-danger);
    border-radius: var(--radius-md);
    color: var(--color-danger);
    padding: var(--space-4);
}

.blazor-error-boundary::after {
    content: "Ein unerwarteter Fehler ist aufgetreten.";
}

/* ================================================================== */
/* Komponenten-Grundstock (M21.3)                                      */
/*                                                                     */
/* Die Klassennamen sind NICHT neu erfunden: sie bedienen genau die    */
/* Klassen, die der Bestand schon vergibt (.form-row 135×, .user-table */
/* 22×, .auth-error 24×, .pager, .detail-grid, .hint, .license-key …), */
/* für die es bis M21.3 keine einzige Regel gab. Was hier steht, wirkt */
/* deshalb sofort auf allen Seiten — Ausnahme sind die Badge-Varianten */
/* unten, die den Grundstock für M21.5/M21.6 bilden.                   */
/* ================================================================== */

/* ---------------- Meldungen ---------------- */

/*
 * Vier Sorten Rückmeldung mit einer gemeinsamen Form: fachlicher Fehler (.error/.auth-error), Erfolg
 * (.success/.auth-success), die formularweite Sammelmeldung von <ValidationSummary> (.validation-errors)
 * und der Hinweis (.hint). Farbe trägt die Bedeutung nie allein — jede Meldung steht als eigener Block
 * mit Rahmen, und die Fehlerfälle sind im Markup zusätzlich mit role="alert" ausgezeichnet.
 */
.auth-error,
.auth-success,
.error,
.success,
.license-issued,
.license-resent,
.validation-errors {
    border: 1px solid;
    border-radius: var(--radius-md);
    margin-block: 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
}

.auth-error,
.error,
.validation-errors {
    background-color: var(--color-danger-surface);
    border-color: var(--color-danger);
    color: var(--color-danger);
}

.auth-success,
.success,
.license-issued,
.license-resent {
    background-color: var(--color-success-surface);
    border-color: var(--color-success);
    color: var(--color-success);
}

/* ValidationSummary rendert eine <ul> — die Aufzählungspunkte sind hier Rauschen. */
.validation-errors {
    list-style: none;
    padding-left: var(--space-4);
}

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

.hint {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* ---------------- Formulare ---------------- */

/* Eine Beschriftung über ihrem Feld, darunter Platz für die Validierungsmeldung. */
.form-row {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-block-end: var(--space-4);
    /* Ein Eingabefeld wird ab einer gewissen Breite nicht lesbarer, nur schwerer zu überblicken. */
    max-width: 32rem;
}

input:not([type="checkbox"]):not([type="radio"]),
select,
textarea {
    background-color: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    color: var(--color-text);
    padding: var(--space-2) var(--space-3);
    width: 100%;
}

input:not([type="checkbox"]):not([type="radio"]):disabled,
select:disabled,
textarea:disabled {
    background-color: var(--color-surface-sunken);
    color: var(--color-text-muted);
    cursor: not-allowed;
}

textarea {
    min-height: 8rem;
    resize: vertical;
}

/* Bei Ankreuzfeldern gehört die Beschriftung neben das Feld, nicht darüber. */
.checkbox-option,
.scope-option {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-weight: var(--font-weight-normal);
}

/* ---------------- Schaltflächen ---------------- */

/*
 * Der Bestand vergibt an Schaltflächen fast nie eine Klasse — deshalb ist das <button>-Element selbst die
 * primäre Variante. Sekundär und gefährlich kommen als Modifier dazu (M21.5/M21.6 setzen sie).
 */
button,
.button {
    background-color: var(--color-accent);
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-md);
    color: var(--color-text-on-accent);
    cursor: pointer;
    display: inline-block;
    font-weight: var(--font-weight-medium);
    padding: var(--space-2) var(--space-4);
    text-decoration: none;
}

button:hover,
.button:hover {
    background-color: var(--color-accent-hover);
    border-color: var(--color-accent-hover);
    color: var(--color-text-on-accent);
}

button:disabled,
.button:disabled {
    background-color: var(--color-surface-sunken);
    border-color: var(--color-border);
    color: var(--color-text-muted);
    cursor: not-allowed;
}

.button-secondary {
    background-color: var(--color-surface);
    border-color: var(--color-border-strong);
    color: var(--color-text);
}

.button-secondary:hover {
    background-color: var(--color-surface-hover);
    border-color: var(--color-border-strong);
    color: var(--color-text);
}

/*
 * Zerstörerische Aktionen (Widerrufen, Deaktivieren) bewusst getönt statt vollflächig rot: die Fläche wäre
 * der auffälligste Knopf der Seite und lockt damit genau zu dem Klick, der schwer rückgängig zu machen ist.
 */
.button-danger {
    background-color: var(--color-danger-surface);
    border-color: var(--color-danger);
    color: var(--color-danger);
}

.button-danger:hover {
    background-color: var(--color-danger);
    border-color: var(--color-danger);
    color: var(--color-surface);
}

/* ---------------- Tabellen und Datenlisten ---------------- */

.user-table {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    /* separate statt collapse, sonst schneidet der Radius die Rahmen der Randzellen ab. */
    border-collapse: separate;
    border-spacing: 0;
    width: 100%;
}

.user-table th {
    background-color: var(--color-surface-sunken);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    letter-spacing: 0.03em;
    text-transform: uppercase;
    white-space: nowrap;
}

.user-table td {
    border-bottom: 1px solid var(--color-border);
}

.user-table tbody tr:last-child td {
    border-bottom: 0;
}

/* Zebrastreifen: hilft beim Verfolgen einer Zeile über breite Tabellen. */
.user-table tbody tr:nth-child(even) {
    background-color: var(--color-surface-sunken);
}

.user-table tbody tr:hover {
    background-color: var(--color-surface-hover);
}

/* Stammdaten als Definitionsliste: Bezeichnung und Wert nebeneinander. */
.detail-grid,
.customer-datasheet {
    display: grid;
    grid-template-columns: minmax(8rem, max-content) 1fr;
    gap: var(--space-2) var(--space-4);
}

.detail-grid dt,
.customer-datasheet dt {
    color: var(--color-text-muted);
    font-weight: var(--font-weight-medium);
}

.detail-grid dd,
.customer-datasheet dd {
    margin: 0;
}

/* ---------------- Karten ---------------- */

/*
 * Abgesetzter Inhaltsblock. .card ist die allgemeine Form; die übrigen Selektoren sind die kartenartigen
 * Blöcke, die der Bestand bereits auszeichnet (Katalogeintrag, Wissensartikel, Support-Nachricht,
 * Vorlagen-Vorschau) — sie bekommen dieselbe Form, statt eine zweite daneben zu erfinden.
 */
.card,
.catalog-product,
.docs-article,
.support-message,
.notification-preview {
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    margin-block-end: var(--space-4);
    padding: var(--space-5);
}

/* Auf der abgesetzten Inhaltsfläche würde eine gleichfarbige Karte verschwinden — sie hebt sich über den
   Rahmen ab, nicht über die Fläche. */
.support-message {
    background-color: var(--color-surface-sunken);
}

.support-message-meta {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    margin-block-end: var(--space-2);
}

.support-message-body {
    white-space: pre-wrap;
}

/*
 * Wer hat geschrieben (M21.5)? Im Verlauf ist genau das die Frage, die man beim Überfliegen stellt. Die Antwort
 * steht als Text in .support-message-meta — die Tönung ist die zweite, schnellere Spur, nie die einzige.
 * Antworten des Supports heben sich über die Akzentfläche ab, eigene Nachrichten bleiben auf der Grundfläche.
 */
.support-message-agent {
    background-color: var(--color-surface-accent-soft);
    border-color: var(--color-accent-muted);
}

/* Lizenz- und API-Schlüssel: umbruchfähig, damit sie den Container nicht sprengen. */
.license-key,
.api-key {
    background-color: var(--color-surface-sunken);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow-wrap: anywhere;
    padding: var(--space-3);
    white-space: pre-wrap;
}

/* ---------------- Status-Badges ---------------- */

/*
 * Grundstock für die Statusanzeigen der Fachmodule (Kunde, Produkt, Lizenz, Ticket, Transaktion). Die
 * Zuordnung Status → Variante ist Sache der jeweiligen Seite und folgt in M21.5/M21.6; hier stehen die
 * Varianten. Jede Kombination aus Textton und Fläche ist in BEIDEN Paletten auf ≥ 4,5:1 geprüft
 * (DesignTokenContrastTests) — Badges tragen kleine Schrift, deshalb die strengere Textschwelle.
 */
.badge,
.support-badge,
.docs-visibility {
    background-color: var(--color-surface-hover);
    border: 1px solid var(--color-text-muted);
    border-radius: var(--radius-pill);
    color: var(--color-text-muted);
    display: inline-block;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.02em;
    padding: var(--space-1) var(--space-3);
    white-space: nowrap;
}

.badge-success {
    background-color: var(--color-success-surface);
    border-color: var(--color-success);
    color: var(--color-success);
}

.badge-warning {
    background-color: var(--color-warning-surface);
    border-color: var(--color-warning);
    color: var(--color-warning);
}

.badge-danger {
    background-color: var(--color-danger-surface);
    border-color: var(--color-danger);
    color: var(--color-danger);
}

.badge-info {
    background-color: var(--color-info-surface);
    border-color: var(--color-info);
    color: var(--color-info);
}

/*
 * Die beiden Support-Marker aus M12 tragen bereits eigene Klassen. „Interne Notiz"/„Nur intern" bekommt die
 * Warnfarbe, weil die Verwechslung teuer ist: dieser Text ist nicht für den Kunden bestimmt. Der
 * Antwortvorschlag ist dagegen bloß ein Zustand und bekommt die neutrale Hinweisfarbe.
 */
.support-badge-internal {
    background-color: var(--color-warning-surface);
    border-color: var(--color-warning);
    color: var(--color-warning);
}

.support-badge-proposed {
    background-color: var(--color-info-surface);
    border-color: var(--color-info);
    color: var(--color-info);
}

/*
 * Ein Kartenblock beginnt und endet mit seinem Rand, nicht mit dem Außenabstand seiner Kinder: die erste
 * Überschrift bzw. der letzte Absatz erbt sonst den globalen margin-block und reißt die Karte auf.
 */
:is(.card, .catalog-product, .docs-article, .support-message, .notification-preview) > :first-child {
    margin-block-start: 0;
}

:is(.card, .catalog-product, .docs-article, .support-message, .notification-preview) > :last-child {
    margin-block-end: 0;
}

/* Gleichrangige Karten nebeneinander, ab ~360 px einspaltig — ohne Media Query, auto-fit erledigt das. */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: var(--space-4);
    margin-block-end: var(--space-5);
}

/* In einem Raster tragen die Karten den Abstand gemeinsam (gap), nicht jede für sich. */
.card-grid > .card {
    margin-block-end: 0;
}

/* ---------------- Seitentext ---------------- */

/* Einordnender Satz unter der Überschrift: sagt, wozu die Seite da ist. */
.page-lead {
    color: var(--color-text-muted);
    font-size: var(--font-size-lg);
    max-width: 60ch;
}

/* ---------------- Aktionen ---------------- */

/*
 * Eine Zeile mit Handlungsangeboten (primär + Abbruch/Zurück). Umbruchfähig, damit zwei Schaltflächen auf
 * schmalem Viewport untereinander landen statt aus der Fläche zu laufen.
 */
.actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-block: var(--space-4) 0;
}

/* ---------------- Breite Tabellen ---------------- */

/*
 * Datenlisten mit vielen Spalten passen unter ~600 px nicht mehr in die Fläche. Statt Spalten zu verstecken
 * (der Nutzer sieht dann nicht, dass etwas fehlt) scrollt die Tabelle in ihrem eigenen Kasten — die Seite
 * selbst scrollt nie waagerecht. Bewusst ohne tabindex: die Zeilen tragen ihre Verweise, der Tastaturfokus
 * scrollt den Kasten dadurch von selbst mit.
 */
.table-scroll {
    overflow-x: auto;
    margin-block-end: var(--space-4);
}

/*
 * Ohne Mindestbreite quetscht eine vielspaltige Tabelle ihre Spalten zusammen, statt den Kasten scrollen zu
 * lassen — der Kasten wäre dann wirkungslos. Die Mindestbreite gehört deshalb hierher, an den Kasten, und nicht
 * an den Dichte-Modifier (M21.7): auch der öffentliche Katalog (Editionsmatrix, wächst mit jeder Edition um eine
 * Spalte) und der Free-Antrag im Portal (sieben Spalten) liegen in einem Kasten und müssen scrollen statt
 * schrumpfen. Die dichten Verwaltungstabellen tragen mehr Spalten und überschreiben das Maß weiter unten.
 */
.table-scroll > table {
    margin-block-end: 0;
    min-width: 36rem;
}

/* ---------------- Dateilisten ---------------- */

/* Anhänge und Pakete: Aufzählungspunkte tragen hier keine Bedeutung, die Dateinamen tun es. */
.file-list {
    list-style: none;
    padding-left: 0;
}

.file-list li + li {
    margin-block-start: var(--space-2);
}

/* ---------------- Blättern ---------------- */

/* .support-queue-paging ist der Blätterer der Support-Queue aus M12 — dieselbe Sache unter einem eigenen Namen.
   Er wird hier mitbedient, statt das Markup umzubenennen und die gewachsene Klasse zu verlieren. */
.pager,
.support-queue-paging,
.docs-search-paging {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-block-start: var(--space-4);
}

.pager span,
.support-queue-paging span {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* ---------------- Leerzustand ---------------- */

/*
 * Der Bestand meldet leere Listen durchgängig als <p role="status">. Das ist der Anker: ein abgesetzter
 * Kasten statt eines verlorenen Satzes.
 *
 * :not([class]) ist hier tragend, nicht kosmetisch — dieselbe Auszeichnung trägt auch Erfolgsmeldungen
 * (<p role="status" class="success">, .license-issued, .license-resent). Ein Selektor ohne die Einschränkung
 * hätte höhere Spezifität (0-1-1) als deren Klassen (0-1-0) und würde eine Erfolgsmeldung in den grauen
 * Leerzustandskasten verwandeln.
 *
 * .empty-state (M21.5) ist die zweite Form desselben Gedankens, für den Fall MIT Handlungsangebot: ein frisch
 * angelegtes Konto sieht im Portal fast nur leere Listen, und dort genügt „nichts vorhanden" nicht — der nächste
 * Schritt muss dabeistehen. Das braucht einen Container statt eines Absatzes (Text UND Verweis). Beide Formen
 * teilen deshalb eine Regel, damit sie nicht auseinanderlaufen. Wer einen weiteren Leerzustand auszeichnet,
 * nimmt .empty-state — oder setzt die Form dort selbst.
 */
p[role="status"]:not([class]),
.empty-state {
    background-color: var(--color-surface-sunken);
    border: 1px dashed var(--color-border-strong);
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    margin-block-end: var(--space-4);
    padding: var(--space-5);
    text-align: center;
}

.empty-state > :first-child {
    margin-block-start: 0;
}

.empty-state > :last-child {
    margin-block-end: 0;
}

/* Im zentrierten Kasten steht die Aktion in der Mitte, nicht links außen. */
.empty-state .actions {
    justify-content: center;
}

/* ================================================================== */
/* Adminbereich (M21.6)                                                */
/*                                                                     */
/* Die Verwaltung wird täglich gelesen, das Portal zweimal im Jahr.    */
/* Deshalb dichter und mit mehr Spalten — aber auf denselben Token und */
/* denselben Bausteinen, nicht als zweites Design daneben. Auch hier   */
/* gilt: bedient werden die Klassen, die der Bestand bereits vergibt.  */
/* ================================================================== */

/* ---------------- Filterleisten ---------------- */

/*
 * Jede Verwaltungsliste trägt ein GET-Filterformular mit eigener Klasse — und bis M21.6 ohne eine einzige Regel.
 * Gestapelte .form-row ergeben dann eine Leiste, die auf einem Notebook den halben Schirm füllt, bevor die erste
 * Datenzeile kommt. Als Zeile mit Umbruch bleibt der Filter da, wo er hingehört: über den Daten, nicht vor ihnen.
 * align-items: flex-end setzt die Schaltfläche auf die Grundlinie der Felder, deren Beschriftung darüber steht.
 */
.customer-filter,
.docs-admin-filter,
.license-filter,
.notification-filter,
.price-mapping-filter,
.product-filter,
.support-queue-filter,
.transaction-filter,
.webhook-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3) var(--space-4);
    background-color: var(--color-surface-sunken);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    /* Auch oben ein Abstand: auf den Listenseiten steht über der Leiste eine Schaltfläche („Neu anlegen"),
       deren .actions-Regel bewusst ohne Außenabstand nach unten auskommt. */
    margin-block: var(--space-4);
    padding: var(--space-3) var(--space-4);
}

/* In der Zeile trägt der Abstand der gap, nicht jedes Feld für sich; die Breite bleibt begrenzt, damit ein
   einzelnes Suchfeld die Leiste nicht allein ausfüllt. */
:is(.customer-filter, .docs-admin-filter, .license-filter, .notification-filter, .price-mapping-filter,
    .product-filter, .support-queue-filter, .transaction-filter, .webhook-filter) > .form-row {
    flex: 1 1 10rem;
    margin-block-end: 0;
    max-width: 18rem;
}

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

/*
 * Die Querverweise innerhalb eines Bereichs (Vorlagen ↔ Vorschau ↔ Protokoll, Redaktionsliste ↔ Taxonomie).
 * Ohne Regel kleben sie als nackte Verweise aneinander und sind von Fließtext nicht zu unterscheiden.
 */
.docs-admin-nav,
.notification-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin-block-end: var(--space-5);
}

/* Kopfzeile eines Redaktions-Artikels: Slug und Zustände nebeneinander statt als Absatzfolge. */
.docs-admin-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* ---------------- Aktionsleisten aus mehreren Formularen ---------------- */

/*
 * Die Lizenzverwaltung setzt jede Aktion als eigenes <EditForm> ab (eigenes Antiforgery-Token je Aktion) — als
 * Blockelemente stünden die Schaltflächen sonst untereinander, obwohl sie eine Entscheidung sind.
 */
.license-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-block: var(--space-5) var(--space-4);
}

.license-actions > form {
    margin-block-end: 0;
}

/* ---------------- Dichte Datenlisten ---------------- */

/*
 * Der Dichte-Modifier der Verwaltungstabellen. Bewusst als eigene Klasse und nicht als Regel auf .user-table:
 * dieselbe Tabellenform trägt auch das Kundenportal, und dort ist die luftigere Zeile richtig.
 */
.table-dense {
    font-size: var(--font-size-sm);
}

.table-dense th,
.table-dense td {
    padding: var(--space-1) var(--space-2);
}

/*
 * Beim Blättern durch eine lange Liste geht sonst nach zwei Bildschirmhöhen verloren, welche Spalte welche ist.
 * Die Kopfzeile trägt eine deckende Fläche (--color-surface-sunken) — durchscheinende Zeilen wären schlimmer als
 * gar keine Haftung.
 *
 * Der Selektor ist bewusst NICHT auf .table-dense verengt, obwohl die Regel im Adminabschnitt steht: in einem
 * waagerecht scrollenden Kasten (.table-scroll) ist der Kasten der Scrollport, und `top: 0` findet dort keine
 * senkrechte Scrollachse — die Haftung ist also genau in den langen Verwaltungslisten wirkungslos (notiert als
 * M21.6-Befund (d) in docs/BACKLOG.md). Wirksam ist sie in den kastenlosen Tabellen, und das sind vor allem die
 * des Kundenportals. Eine Verengung auf .table-dense würde die Regel deshalb überall abschalten statt sie zu
 * schärfen; die Reichweite bleibt, die Beschreibung ist hiermit richtiggestellt (M21.7).
 */
.user-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
}

/* Mehr Spalten als eine Portaltabelle — deshalb das größere Maß (Grundregel am Kasten, siehe .table-scroll). */
.table-scroll > .table-dense {
    min-width: 48rem;
}

/* ================================================================== */
/* Öffentliche Fläche (M21.4)                                          */
/*                                                                     */
/* Katalog, Kauf, Wissensbasis und Anmeldung — die Seiten, die ein     */
/* Fremder zuerst sieht. Auch hier: bedient werden die Klassen, die    */
/* der Bestand seit M07/M10/M15 vergibt, ergänzt um .form-panel.       */
/* ================================================================== */

/* ---------------- Formular-Panel ---------------- */

/*
 * Einzelformulare mit genau einer Aufgabe (Anmelden, Passwort vergessen, Kaufen, Kein Zugriff): eine schmale,
 * abgesetzte Fläche statt eines Formulars, das links oben in einer 72rem breiten Inhaltsfläche klebt. Die
 * Seitenüberschrift steht bewusst außerhalb, damit sie wie auf allen anderen Seiten links beginnt.
 */
.form-panel {
    background-color: var(--color-surface-sunken);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    margin-block-end: var(--space-5);
    max-width: 32rem;
    padding: var(--space-5);
}

.form-panel > :first-child {
    margin-block-start: 0;
}

.form-panel > :last-child {
    margin-block-end: 0;
}

/* Im Panel begrenzt das Panel die Breite, nicht die einzelne Zeile. */
.form-panel .form-row {
    max-width: none;
}

/* ---------------- Katalog ---------------- */

/* Häkchen der Funktionsübersicht: mittig unter der Editionsspalte, sonst verliert das Auge die Zuordnung. */
.catalog-feature-mark {
    text-align: center;
}

/* ---------------- Wissensbasis ---------------- */

/* Suchfeld, Beschriftung und Schaltfläche in einer Zeile; auf schmalem Viewport bricht die Schaltfläche um. */
.docs-search-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin-block-end: var(--space-5);
    max-width: 40rem;
}

.docs-search-form label {
    flex-basis: 100%;
}

.docs-search-form input {
    flex: 1 1 14rem;
    width: auto;
}

.docs-category {
    margin-block-end: var(--space-5);
}

.docs-article-list,
.docs-search-results {
    list-style: none;
    padding-left: 0;
}

.docs-article-list li,
.docs-search-results li {
    border-bottom: 1px solid var(--color-border);
    padding-block: var(--space-2);
}

.docs-article-list li:last-child,
.docs-search-results li:last-child {
    border-bottom: 0;
}

.docs-search-snippet {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    margin-block: var(--space-1) 0;
}

/*
 * Sichtbarkeitshinweis („Nur für Kunden", „Intern") als Badge in Hinweisfarbe — Zustand, keine Warnung.
 * Die Form kommt aus der Badge-Sammelregel oben (M21.7: sie stand hier vorher vollständig nachgebaut und wäre
 * beim nächsten Formwechsel auseinandergelaufen); hier bleiben nur Farbe und die abweichenden Abstände — der
 * Hinweis sitzt hinter einer Überschrift und trägt deshalb weniger Innen- und etwas Außenabstand.
 */
.docs-visibility {
    background-color: var(--color-info-surface);
    border-color: var(--color-info);
    color: var(--color-info);
    margin-inline-start: var(--space-2);
    padding: 0 var(--space-2);
}

.docs-article-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-4);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/*
 * Artikeltext aus dem Markdown-Renderer: die Elemente tragen keine Klassen (der Sanitizer entfernt sie ohnehin),
 * deshalb wird über den Container gestylt. Die Zeilenlänge ist auf Lesbarkeit begrenzt; Tabellen und Codeblöcke
 * scrollen in sich, statt die Karte zu sprengen.
 */
.docs-article-body {
    max-width: 72ch;
}

.docs-article-body table {
    display: block;
    overflow-x: auto;
}

.docs-article-body li + li {
    margin-block-start: var(--space-1);
}
