/*
 * App-specific Styles
 *
 * Eigene Klassen und seitenspezifische Regeln. Die Grundgestalt (Knoepfe,
 * Felder, Karten, Tabellen, Dialoge, Raster, Hilfsklassen) steht in
 * css/framework.css — dort und nicht hier wird an Groessen und Abstaenden
 * gedreht.
 */

html {
    /* Die Basisschriftgroesse steht in css/framework.css (html { font-size }).
       Hier bewusst NICHT gesetzt: app.css wird nach framework.css geladen und
       wuerde die eine Stellschraube sonst wieder ueberschreiben. */
    /* Reserve the scrollbar gutter so transient height changes (e.g. survey-runner
       flip animations) cannot toggle the scrollbar and shift the layout. */
    scrollbar-gutter: stable;
}

/* While a survey-runner flip plays, paint the scrollbar thumb and track transparent
   without removing the scrollbar from the box model. That keeps the scroll container
   intact, so `scrollbar-gutter: stable` continues to reserve the gutter (no horizontal
   jump), while the user sees no thumb blinking in/out as the wrapper height fluctuates
   mid-rotation. `scrollbar-width: none` and `::-webkit-scrollbar { width: 0 }` would
   shrink the scrollbar away and lose the gutter reservation in most browsers — using
   transparent colors avoids that. */
html.runner-flip-active {
    scrollbar-color: transparent transparent;
}

html.runner-flip-active::-webkit-scrollbar-thumb,
html.runner-flip-active::-webkit-scrollbar-track {
    background-color: transparent;
}

/* Asset-sharing access codes (rendered via RenderTreeBuilder, so styles must be global) */
.access-codes-block {
    background-color: var(--primary-light);
    border-radius: 0.5rem;
    padding: 0.75rem 1rem;
}

.access-codes-block .access-codes-table {
    border-collapse: collapse;
    table-layout: fixed;
    background-color: transparent;
    width: 100%;
}

.access-codes-block .access-codes-cell {
    padding: 0.75rem 0.75rem;
    vertical-align: middle;
    width: 33.3333%;
    background-color: transparent;
}

.access-codes-block .access-codes-cell + .access-codes-cell {
    border-left: 1px solid rgba(0, 0, 0, 0.08);
}

.access-codes-block .access-codes-label {
    font-size: 0.95rem;
    margin-bottom: 0.25rem;
}

.access-codes-block .access-code-value {
    font-size: 1.6rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    line-height: 1.1;
    margin-bottom: 0.5rem;
}

.access-codes-block .access-codes-actions {
    margin-top: 0.25rem;
}


/* Die Hausschrift steht in css/framework.css (--fs-font). */

/* Material Symbols in table cells auto vertical alignment */
td .material-symbols-outlined {
    vertical-align: middle;
}

/* Filled icon class for Material Symbols */
.material-symbols-outlined.filled {
    font-variation-settings: 'FILL' 1;
}

/* Die Marke unseres AIssistant. Als Maske statt als <img>, damit sie die
   Schriftfarbe ihrer Umgebung annimmt: derselbe Knopf traegt sie auf hellem
   wie auf dunklem Grund, ohne zweite Datei. Sie haengt an der Schriftgroesse
   des Elements und laesst sich damit genauso feinstellen wie ein Symbol. */
.ai-mark {
    display: inline-block;
    flex-shrink: 0;
    width: 1em;
    height: 1em;
    font-size: var(--fs-text-lg);
    vertical-align: middle;
    background-color: currentColor;
    -webkit-mask: url('../images/aissistant.svg') no-repeat center / contain;
    mask: url('../images/aissistant.svg') no-repeat center / contain;
}

/* Die gefuellte Schwester der Marke. Dieselbe Zeichnung, nur sind die
   eingeschlossenen Flaechen zu Flaeche geworden und das Visier zur Aussparung.
   Muss nach .ai-mark stehen, damit sie deren Maske ueberschreibt. */
.ai-mark-filled {
    -webkit-mask-image: url('../images/aissistant-filled.svg');
    mask-image: url('../images/aissistant-filled.svg');
}

/* Der Roboter ist hoeher als breit. Wo die Marke neben Text steht, darf sie
   etwas ueber die Zeile hinausragen, sonst wirkt sie geschrumpft. */
.ai-mark-lg {
    font-size: var(--fs-text-xl);
}

.ai-mark-xl {
    font-size: 3rem;
}

/* Der Inhaltsbereich ist selbst das scrollende Element. Ohne Polsterung unten klebt
   die letzte Zeile am Fensterrand, und was dort steht, liegt teilweise unter dem
   Knopf, der nach oben fuehrt. */
.content {
    padding-top: 1rem;
    /* Der schwebende "nach oben"-Knopf sitzt unten rechts ueber dem Inhalt. Ohne
       diesen Platz liegt er auf dem letzten Knopf der Seite. */
    padding-bottom: 6rem;
    flex: 1;
}

@media (max-width: 767.98px) {
    .content {
        padding-top: 0;
        padding-bottom: 7rem;
    }
}

/* Eine Seite, die genau so hoch ist wie der Platz unter der Kopfleiste: Der
   Inhaltsbereich scrollt dann nicht mehr, es gibt also keine Scrollleiste am
   rechten Fensterrand. Was nicht hineinpasst, scrollt innerhalb des Bereichs,
   in den es gehoert. Der Assistent arbeitet so, weil Gespraech und Vorgaben
   nebeneinander stehen und beide unterschiedlich lang werden. */
main > article:has(> .page-fill) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding-bottom: 1rem;
}

.page-fill {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* Der Seitenkopf behaelt seine Hoehe; den Rest bekommt der Bereich darunter. */
.page-fill > .page-header {
    flex: 0 0 auto;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--bs-success);
}

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

/* Inputs with `text-uppercase` should still show their placeholder in normal case —
   uppercasing the hint text makes labels like "TEAM-CODE ..." look shouty and breaks
   readability without adding information. */
input.text-uppercase::placeholder,
textarea.text-uppercase::placeholder {
    text-transform: none;
}

.validation-message {
    color: var(--bs-danger);
}

/* Note: SVG in data-URLs cannot use CSS variables - color #FFE500 for warning icon, #b32121 for background */
.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

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

/* ==========================================================================
   Icon Colors
   ========================================================================== */

.icon-color-primary { color: var(--icon-color-primary); }
.icon-color-primary-light { color: var(--icon-color-primary-light); }
.icon-color-primary-pale { color: var(--icon-color-primary-pale); }
.icon-color-red { color: var(--icon-color-red); }
.icon-color-crimson { color: var(--icon-color-crimson); }
.icon-color-orange { color: var(--icon-color-orange); }
.icon-color-amber { color: var(--icon-color-amber); }
.icon-color-yellow { color: var(--icon-color-yellow); }
.icon-color-lime { color: var(--icon-color-lime); }
.icon-color-green { color: var(--icon-color-green); }
.icon-color-teal { color: var(--icon-color-teal); }
.icon-color-cyan { color: var(--icon-color-cyan); }
.icon-color-blue { color: var(--icon-color-blue); }
.icon-color-indigo { color: var(--icon-color-indigo); }
.icon-color-purple { color: var(--icon-color-purple); }
.icon-color-violet { color: var(--icon-color-violet); }
.icon-color-pink { color: var(--icon-color-pink); }
.icon-color-brown { color: var(--icon-color-brown); }
.icon-color-gold { color: var(--icon-color-gold); }
.icon-color-mint { color: var(--icon-color-mint); }
.icon-color-navy { color: var(--icon-color-navy); }
.icon-color-magenta { color: var(--icon-color-magenta); }
.icon-color-gray { color: var(--icon-color-gray); }
.icon-color-black { color: var(--icon-color-black); }

/* Color swatch — quadratisch für den ColorPickerModal-Grid. Globale Klasse, damit
   sie auch außerhalb scoped CSS (z. B. in den Table-Editoren) greift.
   Größe: 3rem statt 4rem, damit mindestens 6 Swatches pro Reihe Platz haben. */
.icon-color-swatch {
    display: inline-block;
    width: 3rem;
    height: 3rem;
    border: 0.125rem solid var(--bs-border-color);
    border-radius: 0.25rem;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
    padding: 0;
}

.icon-color-swatch:hover {
    transform: scale(1.1);
}

.icon-color-swatch.active {
    border-color: var(--bs-dark);
    border-width: 0.2rem;
    box-shadow: 0 0 0 0.15rem rgba(0, 0, 0, 0.15);
}

/* In-table-Variante: so groß wie ein Material-Symbols-Icon (1.5rem-Default).
   Kein Hover-Effekt, weil der Cursor-Pointer schon vom td gesetzt wird. */
.icon-color-swatch-sm {
    display: inline-block;
    width: 1.5rem;
    height: 1.5rem;
    border: 0.0625rem solid var(--bs-border-color);
    border-radius: 0.2rem;
    padding: 0;
}

/* Color-Family-Vorschau als zusammenhängender Gradient-Balken statt vieler einzelner
   Quadrate. Vorteil: die Preview-Breite bleibt unabhängig von der Skala (3..7) konstant —
   die Spaltenbreite ändert sich nie. Wird in den Vorlagen-Boxen verwendet. */
.color-family-preview {
    display: block;
    width: 100%;
    /* Volle Höhe des umgebenden Buttons (via .family-presets-grid min-height
       gesteuert). align-self: stretch sorgt dafür, dass die Center-Ausrichtung
       des Buttons den Span nicht auf seine Intrinsic-Höhe schrumpft. */
    height: auto;
    align-self: stretch;
    /* Transparente Border statt entfernter Border — der Platz bleibt im Layout
       reserviert, damit Höhe und Breite beim Umschalten "mit/ohne Rahmen" exakt
       gleich bleiben. */
    border: 0.0625rem solid transparent;
    border-radius: 0.2rem;
    padding: 0;
    /* Eigene Mindesthöhe, damit der Balken auch ohne umgebendes
       .family-presets-grid sichtbar ist: in den Choice-Editoren stehen die
       Vorlagen frei und hätten sonst keine Höhe — der Knopf wäre leer. */
    min-height: 1.25rem;
}

/* Color-Family-Button: der Knopf selbst bleibt farblos, sichtbar ist nur die
   Gradient-Leiste darin. Die Regeln stehen direkt hier, weil framework.css keine
   --bs-btn-*-Variablen liest (siehe CLAUDE.md 4.6). */
.color-family-btn,
.color-family-btn.btn-primary,
.color-family-btn.btn-outline-primary {
    padding: 0.25rem;
    background-color: transparent;
}

/* Nebeneinander statt untereinander: in den Choice-Editoren stehen die Vorlagen
   frei über der Tabelle. Volle Breite würde ihnen dort ein Gewicht geben, das sie
   nicht haben — als schmale Leisten passen alle Familien in eine Zeile. */
.color-family-btn-inline {
    flex: 0 0 auto;
    width: 5rem;
}

.color-family-btn:hover:not(:disabled):not(.disabled),
.color-family-btn.btn-primary:hover:not(:disabled):not(.disabled),
.color-family-btn.btn-outline-primary:hover:not(:disabled):not(.disabled) {
    background-color: transparent;
    border-color: var(--primary);
}

.color-family-btn.btn-primary {
    color: var(--primary);
    border-color: var(--primary);
    /* Permanenter Primary-Ring um die selektierte Farbfamilie. Box-Shadow statt
       Border, damit der Ring nicht im Layout zählt (Höhe/Breite bleiben gleich)
       und stabil sichtbar bleibt, auch wenn der Knopf den Fokus verliert. */
    box-shadow: 0 0 0 0.1875rem var(--primary);
}

/* Family-Presets-Grid: gemeinsamer min-height für die drei Spalten Text / Icons /
   Farben — damit die Buttons nicht je nach Inhalt unterschiedlich hoch werden. Der
   Wert orientiert sich an der natürlichen Höhe der Text-Buttons. Mit min-height
   bleiben die Buttons mindestens so hoch, schrumpfen aber nicht, wenn der Inhalt
   (Gradient-Balken oder Icons) kleiner wäre. */
.family-presets-grid .btn-sm {
    min-height: 2.5rem;
}

/* Fortschritts-Checkliste im Qualitätscheck-Wizard: feste, linksbündige Icon-Spalte, damit
   Spinner und Häkchen exakt untereinander am linken Rand ausgerichtet sind und der Text in
   allen Zeilen auf derselben x-Position beginnt. */
.qc-progress-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    flex-shrink: 0;
}

.qc-progress-icon .material-symbols-outlined {
    font-size: 1.25rem;
}

/* Score-Spalte im Item-Editor, die nur für SystemAdministratoren als Debug-Hilfe sichtbar ist.
   Gestrichelter Rahmen signalisiert: wird normalerweise nicht angezeigt. */
.score-debug-cell {
    border: 0.125rem dashed var(--bs-secondary) !important;
}

/* Item-Text im Card-Header der Ergebnis-Karten — feste Höhe von 3 Zeilen, damit alle
   Header gleich hoch sind und die Gauges darunter auf identischer Höhe beginnen. Längerer
   Text wird nach 3 Zeilen mit Ellipsis abgeschnitten (vollständiger Text im title-Tooltip). */
.item-result-header-text {
    margin-bottom: 0;
    font-size: 1rem;
    line-height: 1.5rem;
    height: 4.5rem;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Gauge-Chart-Legende — aufklappbar unter dem segmentierten Balken (default eingeklappt). */
.gauge-legend-details {
    margin-top: 0.75rem;
}

.gauge-legend-summary {
    cursor: pointer;
    text-align: center;
    font-size: 0.875rem;
    color: var(--bs-secondary);
    list-style-position: inside;
}

/* Gauge-Chart-Legende — unter dem SVG-Halbkreis. Wrap-fähig + zentriert,
   damit lange Beschriftungen sauber umbrechen. */
.gauge-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem 1rem;
    margin-top: 0.5rem;
    font-size: 0.875rem;
}

.gauge-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.gauge-legend-swatch {
    display: inline-block;
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 50%;
}

/* Segmentierter Balken direkt unter dem Gauge — ein gleich breites Segment pro
   Antwortoption mit dem prozentualen Anteil. */
.gauge-segments {
    display: flex;
    margin-top: 0.5rem;
    border-radius: 0.5rem;
    overflow: hidden;
}

.gauge-segment {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.35rem 0.25rem;
    font-size: 0.95rem;
    font-weight: 600;
}

/* Klickbare Bootstrap-Karte (z. B. Item-Typ-Präferenzen). Wird mit `card clickable-card`
   kombiniert und reagiert auf Hover mit subtiler Hervorhebung. Interaktive Kind-Elemente
   wie Reset-Buttons müssen @onclick:stopPropagation setzen, damit der Klick nicht zum
   Card-Handler propagiert. */
.clickable-card {
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.clickable-card:hover {
    border-color: var(--bs-primary);
    /* Inset shadow verdickt visuell den Rahmen auf ca. 2px, ohne dass das Layout springt. */
    box-shadow: inset 0 0 0 1px var(--bs-primary);
}

/* Icon picker grid buttons */
.icon-grid-btn {
    width: 3rem;
    height: 3rem;
    padding: 0;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--radius-sm);
    background: var(--bs-white);
    cursor: pointer;
    transition: var(--transition-base);
}

.icon-grid-btn:hover {
    border-color: var(--bs-primary);
    background-color: var(--selected-bg);
}

.icon-grid-btn.active {
    border: 0.25rem solid var(--bs-primary);
    box-shadow: 0 0 0 0.15rem rgba(var(--primary-rgb), 0.3);
    background-color: var(--selected-bg);
}

/* ==========================================================================
   Clickable Elements
   ========================================================================== */

.clickable,
.cursor-pointer {
    cursor: pointer;
}

/* Selectable cards (e.g. mode selection, creation mode) */
.card-selectable {
    display: block;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--radius-md);
    padding: 1.5rem;
    height: 100%;
    cursor: pointer;
    background-color: var(--bs-white);
    transition: var(--transition-colors), box-shadow var(--duration-base) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.card-selectable:hover,
.card-selectable:focus {
    background-color: var(--bs-light);
    border-color: var(--bs-primary);
    box-shadow: var(--shadow-md);
    outline: none;
}

.card-selectable:active {
    transform: scale(0.99);
}

.card-selectable.active {
    border-color: var(--bs-primary);
    background-color: var(--selected-bg);
    box-shadow: var(--shadow-sm);
}

/* ==========================================================================
   Intro Modal
   ========================================================================== */

/* Der Schleier wie bei allen uebrigen Dialogen — hier als Klasse statt als
   style-Attribut, weil das Markup ohnehin neu geschrieben wurde. */
.intro-modal {
    background-color: rgba(0, 0, 0, 0.5);
}

.intro-body {
    max-height: 70vh;
    overflow-y: auto;
}

/* Das Zeichen oben ist Schmuck, nicht Inhalt: gross genug, um den Dialog
   anzukuendigen, aber nicht mehr die halbe Flaeche wie zuvor. Auf der Skala,
   damit es der Basisschriftgroesse folgt. */
.intro-icon {
    font-size: calc(var(--fs-text-3xl) * 1.6);
    line-height: 1;
}

.intro-title-row {
    margin-top: 0.75rem;
    margin-bottom: 1.25rem;
}

.intro-title {
    font-size: var(--fs-text-xl);
    font-weight: 600;
    color: var(--bs-primary);
}

/* Die Zeile mit dem Haken steht zwischen Inhalt und Knopfleiste: die Leiste
   selbst hat keinen Innenabstand mehr, ein Haken darin haette keinen Rand. */
.intro-consent {
    padding: 0.9rem 1.2rem;
    border-top: 1px solid var(--fs-border);
}

.intro-consent .form-check {
    margin-bottom: 0;
}

.intro-page-indicator {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    border: 0.125rem solid var(--bs-border-color);
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.intro-page-indicator.active {
    background-color: var(--bs-primary);
    border-color: var(--bs-primary);
    color: #fff;
}

.intro-close {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    z-index: 10;
    /* .btn-close misst sich in em; ohne eigene Groesse waere das Kreuz so gross
       wie die Schrift des Dialogs und damit zu wuchtig fuer eine Nebenaktion. */
    font-size: var(--fs-text-base);
}

/* ---------------------------------------------------------------------------
   Ersteinrichtung: Willkommensseite und Assistent

   Der Assistent ist ein Ort, an dem man ist, keine Seite, die man durchblaettert.
   Deshalb Vollbild ohne Navigation, links eine stehende Schrittliste, rechts genau
   eine Frage, unten genau eine betonte Aktion.
   --------------------------------------------------------------------------- */

/* --- gemeinsame Bausteine (Felder, Chips, Hinweiskasten) ------------------- */

.setup-field {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.setup-field-label-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
}

.setup-field-label {
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--gray-dark);
}

.setup-field-hint {
    font-size: var(--fs-text-sm);
    line-height: 1.5;
    color: var(--gray-text-secondary);
}

/* Fehler stehen unter dem betroffenen Feld, nicht als Kasten am Seitenende. */
.setup-field-error {
    font-size: var(--fs-text-sm);
    color: var(--danger);
}

.setup-field-row {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
}

.setup-field-row > .setup-field,
.setup-field-row > .form-control,
.setup-field-row > .setup-input {
    flex: 1 1 0;
    min-width: 0;
}

.setup-input {
    min-height: 3rem;
}

.setup-inline-action {
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--primary);
    cursor: pointer;
}

.setup-inline-action:hover {
    color: var(--primary-dark);
}

.setup-loading {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 3rem;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.setup-empty {
    margin: 0;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.setup-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.setup-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-height: 2.5rem;
    padding: 0 1rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--nav-text);
    font-size: var(--fs-text-sm);
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition-colors);
}

.setup-chip:hover {
    border-color: var(--primary);
    color: var(--primary-dark);
}

.setup-chip.selected {
    border-color: transparent;
    background: var(--primary-soft);
    color: var(--primary-dark);
}

.setup-chip .material-symbols-outlined {
    font-size: var(--fs-text-lg);
}

.setup-chip-remove {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    cursor: pointer;
}

.setup-chip-remove .material-symbols-outlined {
    font-size: var(--fs-text-base);
}

/* Hinweiskasten in der Hausfarbe: er ergaenzt, er warnt nicht. */
.setup-note {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    padding: 0.875rem 1rem;
    border: 1px solid var(--info-border);
    border-radius: var(--radius-sm);
    background: var(--primary-tint);
    color: var(--info-text);
    font-size: var(--fs-text-sm);
    line-height: 1.5;
}

.setup-note .material-symbols-outlined {
    flex-shrink: 0;
    font-size: var(--fs-text-lg);
}

.setup-guard {
    max-width: 40rem;
    margin: 3rem auto;
    padding: 0 1.5rem;
}

/* --- Assistent: Rahmen ----------------------------------------------------- */

.wizard-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background: var(--app-bg);
}

.wizard-topbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
    min-height: 3.5rem;
    padding: 0 0.75rem 0 1.25rem;
    background: var(--primary);
    color: var(--white);
}

.wizard-topbar-brand {
    display: flex;
    align-items: center;
    /* Die Marke misst sich in em, sie braucht hier also eine eigene Groesse. */
    font-size: var(--fs-text-md);
    color: var(--white);
}

.wizard-topbar-divider {
    width: 1px;
    height: 1.375rem;
    background: var(--overlay-white-medium);
}

.wizard-topbar-context {
    flex-shrink: 1;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: var(--fs-text-sm);
    font-weight: 500;
    color: var(--white);
}

.wizard-topbar-spacer {
    flex: 1;
}

.wizard-topbar-exit {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.375rem;
    padding: 0 0.875rem;
    border: 0;
    border-radius: var(--radius-md);
    background: none;
    color: var(--white);
    font-size: var(--fs-text-sm);
    font-weight: 500;
    cursor: pointer;
}

.wizard-topbar-exit:hover {
    background: var(--navbar-item-hover);
}

.wizard-topbar-exit .material-symbols-outlined {
    font-size: var(--fs-text-lg);
}

.wizard-body {
    display: flex;
    flex: 1;
    min-height: 0;
}

/* --- Assistent: Schrittliste ---------------------------------------------- */

.wizard-steps {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    flex-shrink: 0;
    width: 21rem;
    padding: 1.75rem 1.25rem;
    background: var(--sidebar-bg);
    border-right: 1px solid var(--sidebar-border);
}

.wizard-steps-progress {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0 0.75rem 0.875rem;
}

.wizard-steps-progress-label {
    font-size: var(--fs-text-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--nav-section-label);
}

.wizard-steps-progress-text {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.wizard-progress-track,
.welcome-progress-track {
    height: 0.375rem;
    border-radius: var(--radius-pill);
    background: var(--row-divider);
    overflow: hidden;
}

.wizard-progress-fill,
.welcome-progress-fill {
    height: 100%;
    background: var(--primary);
    transition: width var(--duration-base) var(--ease-out);
}

.wizard-step {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    width: 100%;
    padding: 0.75rem;
    border: 0;
    border-radius: 0.6875rem;
    background: none;
    text-align: left;
}

.wizard-step.done {
    cursor: pointer;
}

.wizard-step.done:hover {
    background: var(--nav-hover-bg);
}

.wizard-step.current {
    background: var(--primary-soft);
}

.wizard-step-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background: var(--row-divider);
    color: var(--gray-text-secondary);
    font-size: var(--fs-text-sm);
    font-weight: 700;
}

.wizard-step.current .wizard-step-mark {
    background: var(--primary);
    color: var(--primary-ink);
}

.wizard-step-mark.checked {
    background: var(--primary-tint);
    color: var(--success);
}

.wizard-step-mark .material-symbols-outlined {
    font-size: var(--fs-text-md);
}

.wizard-step-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

.wizard-step-title {
    font-size: var(--fs-text-sm);
    font-weight: 500;
    color: var(--nav-text);
}

.wizard-step.current .wizard-step-title {
    font-weight: 600;
    color: var(--primary-dark);
}

.wizard-step-sub {
    font-size: var(--fs-text-xs);
    color: var(--gray-text-secondary);
}

.wizard-steps-footer {
    margin-top: auto;
    padding: 0.75rem;
    font-size: var(--fs-text-xs);
    line-height: 1.5;
    color: var(--gray-text-secondary);
}

/* Auf breiten Geraeten steht die Liste, auf schmalen die Leiste. Nie beides. */
.wizard-steps-bar {
    display: none;
}

/* --- Assistent: Inhaltsspalte --------------------------------------------- */

.wizard-main {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
}

/* Die Spalte steht links an der Schrittliste, nicht in der Mitte des Restplatzes:
   auf einem breiten Bildschirm wandert eine zentrierte Spalte weit vom Menue weg
   und der Blick muss zwischen beiden springen. Die Breite bleibt begrenzt, damit
   die Zeilen lesbar kurz sind. */
.wizard-content {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    flex: 1;
    width: 100%;
    max-width: 42rem;
    padding: 3rem 3.5rem 7rem;
}

.wizard-question {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
}

.wizard-eyebrow {
    font-size: var(--fs-text-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--nav-section-label);
}

.wizard-question-title {
    margin: 0;
    font-size: var(--fs-text-2xl);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--gray-dark);
    text-wrap: pretty;
}

.wizard-question-why {
    margin: 0;
    font-size: var(--fs-text-base);
    line-height: 1.55;
    color: var(--gray-text-secondary);
    text-wrap: pretty;
}

.wizard-fields {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

/* --- Assistent: Aktionsleiste --------------------------------------------- */

/* Der Strich laeuft ueber die volle Breite, die Knoepfe darin nicht: sie folgen
   der Inhaltsspalte. 35rem ist deren Textbreite, also 42rem abzueglich der
   seitlichen 3.5rem. */
.wizard-actions {
    flex-shrink: 0;
    padding: 1rem 3.5rem;
    border-top: 1px solid var(--sidebar-border);
    background: var(--surface);
}

.wizard-actions-inner {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    max-width: 35rem;
}

.wizard-actions-spacer {
    flex: 1;
}

/* Zurueck ist ein stiller Textknopf: er ist da, aber er buhlt nicht. */
.wizard-back {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-height: 3rem;
    padding: 0 1.125rem;
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--nav-text);
    font-size: var(--fs-text-base);
    font-weight: 500;
    cursor: pointer;
}

.wizard-back:hover:not(:disabled) {
    background: var(--surface-sunk);
}

.wizard-back:disabled {
    color: var(--text-subtle);
    cursor: default;
}

.wizard-next {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding: 0 1.75rem;
    border: 0;
    border-radius: var(--radius-sm);
    background: var(--primary);
    color: var(--primary-ink);
    font-size: var(--fs-text-base);
    font-weight: 600;
    cursor: pointer;
    transition: var(--transition-colors);
}

.wizard-next:hover:not(:disabled) {
    background: var(--primary-hover);
}

.wizard-next:disabled {
    background: var(--surface-sunk);
    color: var(--text-subtle);
    cursor: default;
}

.wizard-next-label-short {
    display: none;
}

/* --- Assistent: Abschluss -------------------------------------------------- */

.wizard-done {
    flex: 1;
    padding: 3.5rem 1.5rem;
    overflow-y: auto;
}

.wizard-done-column {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    width: 100%;
    max-width: 52rem;
    margin: 0 auto;
}

.wizard-done-head {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.wizard-done-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 50%;
    background: var(--success-tint);
    color: var(--success);
}

.wizard-done-mark .material-symbols-outlined {
    font-size: 1.875rem;
}

.wizard-done-head-text {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.wizard-done-title {
    margin: 0;
    font-size: var(--fs-text-2xl);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--gray-dark);
}

.wizard-done-intro {
    margin: 0;
    font-size: var(--fs-text-base);
    line-height: 1.55;
    color: var(--gray-text-secondary);
    text-wrap: pretty;
}

.wizard-card {
    flex-shrink: 0;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background: var(--surface);
    overflow: hidden;
}

.wizard-card-head {
    display: flex;
    flex-direction: column;
    gap: 0.1875rem;
    padding: 1.125rem 1.5rem;
    border-bottom: 1px solid var(--gray-border-light);
}

.wizard-card-title {
    font-size: var(--fs-text-md);
    font-weight: 600;
    color: var(--gray-dark);
}

.wizard-card-subtitle {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.wizard-card-body {
    padding: 1.25rem 1.5rem;
}

.wizard-summary-row {
    display: flex;
    align-items: baseline;
    gap: 1.25rem;
    padding: 0.8125rem 1.5rem;
    border-bottom: 1px solid var(--row-divider);
}

.wizard-summary-row:last-child {
    border-bottom: 0;
}

.wizard-summary-label {
    flex-shrink: 0;
    width: 12.5rem;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.wizard-summary-value {
    flex: 1;
    min-width: 0;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--gray-dark);
}

.wizard-done-hint {
    margin: 0;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.wizard-done-switch .form-check-label {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.wizard-done-link {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: var(--fs-text-base);
    font-weight: 600;
}

.wizard-done-link .material-symbols-outlined {
    font-size: var(--fs-text-lg);
}

/* --- Willkommensseite ------------------------------------------------------ */

.welcome-page {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    padding: 0.5rem 0 2rem;
}

.welcome-head {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    max-width: 47.5rem;
}

.welcome-badge {
    align-self: flex-start;
    padding: 0.3125rem 0.75rem;
    border-radius: var(--radius-pill);
    background: var(--primary-tint);
    color: var(--primary-strong);
    font-size: var(--fs-text-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.welcome-title {
    margin: 0;
    font-size: var(--fs-text-3xl);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--gray-dark);
}

.welcome-intro {
    margin: 0;
    font-size: var(--fs-text-md);
    line-height: 1.55;
    color: var(--gray-text-secondary);
    text-wrap: pretty;
}

.welcome-card {
    flex-shrink: 0;
    border: 1px solid var(--info-border);
    border-radius: var(--radius-md);
    background: var(--surface);
    overflow: hidden;
}

.welcome-card-head {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    padding: 1.375rem 1.75rem;
    background: var(--primary-tint);
    border-bottom: 1px solid var(--info-border);
}

.welcome-card-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 50%;
    background: var(--primary);
    color: var(--primary-ink);
}

.welcome-card-mark .material-symbols-outlined {
    font-size: 1.75rem;
}

.welcome-card-head-text {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    flex: 1;
    min-width: 0;
}

.welcome-card-title {
    margin: 0;
    font-size: var(--fs-text-lg);
    font-weight: 600;
    color: var(--primary-strong);
}

.welcome-card-subtitle {
    font-size: var(--fs-text-sm);
    color: var(--nav-text);
}

.welcome-card-progress {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    max-width: 28.75rem;
}

.welcome-card-progress .welcome-progress-track {
    flex: 1;
    background: var(--info-border);
}

.welcome-card-progress-text {
    white-space: nowrap;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--primary-dark);
}

.welcome-card-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    flex-shrink: 0;
    min-height: 3rem;
    padding: 0 1.5rem;
    border-radius: var(--radius-sm);
    background: var(--primary);
    color: var(--primary-ink);
    font-size: var(--fs-text-base);
    font-weight: 600;
    transition: var(--transition-colors);
}

.welcome-card-action:hover {
    background: var(--primary-hover);
    color: var(--primary-ink);
}

.welcome-steps {
    display: flex;
    flex-direction: column;
}

.welcome-step {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.75rem;
    border-bottom: 1px solid var(--row-divider);
    color: var(--nav-text);
}

.welcome-step:last-child {
    border-bottom: 0;
}

a.welcome-step:hover {
    background: var(--surface-subtle);
    color: var(--nav-text);
}

/* Erst der Wiedereinstieg faerbt die Zeile. Beim ersten Aufruf genuegt der
   getoente Nummernkreis: dort ist noch nichts unterbrochen worden. */
.welcome-step.current.resumed {
    background: var(--primary-light);
}

.welcome-step-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: var(--surface-sunk);
    color: var(--gray-text-secondary);
    font-size: var(--fs-text-sm);
    font-weight: 700;
}

.welcome-step-mark.active {
    background: var(--primary);
    color: var(--primary-ink);
}

.welcome-step-mark.tinted {
    background: var(--primary-tint);
    color: var(--primary-strong);
}

.welcome-step-mark.checked {
    background: var(--primary-tint);
    color: var(--success);
}

.welcome-step-mark .material-symbols-outlined {
    font-size: var(--fs-text-lg);
}

.welcome-step-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    flex: 1;
    min-width: 0;
}

.welcome-step-title {
    font-size: var(--fs-text-base);
    font-weight: 600;
    color: var(--gray-dark);
}

.welcome-step-sub {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.welcome-step-link {
    flex-shrink: 0;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--primary);
}

.welcome-footnote {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.welcome-footnote a {
    font-weight: 600;
}

/* --------------------------------------------------------------------------
   Die Startseite eines Privatkontos: vier Schritte nebeneinander.

   Nebeneinander und nicht untereinander, weil der Weg kurz ist und ganz auf einen
   Bildschirm gehoert — wer scrollen muss, um seinen naechsten Schritt zu sehen,
   sieht ihn nicht. Unter 1200px werden zwei Reihen daraus, auf dem Handy eine
   Spalte; die Reihenfolge bleibt in jeder Anordnung dieselbe.
   -------------------------------------------------------------------------- */
.starter {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

.starter-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1rem;
}

.starter-card {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 1.375rem 1.25rem;
    border: 1px solid var(--info-border);
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--nav-text);
    text-decoration: none;
    transition: var(--transition-colors), box-shadow var(--duration-base) var(--ease-out);
}

.starter-card:hover {
    border-color: var(--primary);
    box-shadow: var(--shadow-md);
    color: var(--nav-text);
}

.starter-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    margin-bottom: 0.25rem;
    border-radius: var(--radius-md);
    background: var(--primary-tint);
    color: var(--primary-strong);
}

.starter-mark .material-symbols-outlined {
    font-size: var(--fs-text-xl);
}

.starter-step {
    font-size: var(--fs-text-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--primary-strong);
}

.starter-title {
    font-size: var(--fs-text-md);
    font-weight: 700;
    color: var(--gray-dark);
}

.starter-text {
    flex: 1;
    font-size: var(--fs-text-sm);
    line-height: 1.5;
    color: var(--gray-text-secondary);
    text-wrap: pretty;
}

/* Der Link sitzt unten und wird erst beim Ueberfahren der Karte deutlich: die
   ganze Karte ist der Klick, er ist nur ihre Beschriftung. */
.starter-link {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-top: 0.5rem;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--primary);
}

.starter-link .material-symbols-outlined {
    font-size: var(--fs-text-base);
    transition: transform var(--duration-base) var(--ease-out);
}

.starter-card:hover .starter-link .material-symbols-outlined {
    transform: translateX(0.1875rem);
}

/* Was ausserdem geht, in einer Zeile: kein zweiter Block, der die vier Schritte
   um ihre Ruhe braechte. */
.starter-more {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.starter-more-title {
    font-weight: 700;
    color: var(--gray-dark);
}

.starter-more-item {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

.starter-more-item .material-symbols-outlined {
    font-size: var(--fs-text-base);
    color: var(--primary);
}

@media (max-width: 1199.98px) {
    .starter-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 575.98px) {
    .starter-grid {
        grid-template-columns: 1fr;
    }
}

/* --- schmale Geraete ------------------------------------------------------- */

@media (max-width: 991.98px) {
    .wizard-steps {
        display: none;
    }

    .wizard-body {
        flex-direction: column;
    }

    /* Aus der stehenden Liste wird eine Leiste: Wo bin ich, wie weit noch. */
    .wizard-steps-bar {
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
        flex-shrink: 0;
        padding: 0.875rem 1rem;
        background: var(--surface);
        border-bottom: 1px solid var(--sidebar-border);
    }

    .wizard-steps-bar-line {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 0.75rem;
    }

    .wizard-steps-bar-title {
        font-size: var(--fs-text-sm);
        font-weight: 600;
        color: var(--primary-dark);
    }

    .wizard-steps-bar-time {
        white-space: nowrap;
        font-size: var(--fs-text-xs);
        color: var(--gray-text-secondary);
    }

    /* Auf dem Handy traegt die Leiste nur noch, was sie tragen muss: wo man ist
       und wie man hier wieder herauskommt. */
    .wizard-topbar {
        padding: 0 0.25rem 0 0.875rem;
    }

    .wizard-topbar-brand,
    .wizard-topbar-divider,
    .wizard-topbar-unit,
    .wizard-topbar-exit-label {
        display: none;
    }

    .wizard-topbar-context {
        font-weight: 600;
    }

    .wizard-topbar-exit {
        width: 2.75rem;
        min-height: 2.75rem;
        padding: 0;
        justify-content: center;
    }

    .wizard-content {
        gap: 1.25rem;
        padding: 1.375rem 1rem 7rem;
    }

    .wizard-question-title {
        font-size: var(--fs-text-xl);
    }

    .wizard-actions {
        padding: 0.75rem 1rem 1.125rem;
    }

    .wizard-back-label {
        display: none;
    }

    .wizard-next {
        flex: 1;
        min-height: 3.125rem;
    }

    .wizard-next-label {
        display: none;
    }

    .wizard-next-label-short {
        display: inline;
    }

    .setup-field-row {
        flex-direction: column;
    }

    .setup-field-row > .setup-field,
    .setup-field-row > .form-control,
    .setup-field-row > .setup-input {
        width: 100%;
    }

    .setup-chip {
        min-height: 2.75rem;
    }

    .welcome-title {
        font-size: var(--fs-text-xl);
    }

    .welcome-intro {
        font-size: var(--fs-text-base);
    }

    .welcome-card-head {
        flex-direction: column;
        align-items: stretch;
        gap: 0.625rem;
        padding: 1rem 1.125rem;
    }

    .welcome-card-action {
        width: 100%;
    }

    /* Auf dem Handy traegt die Zeile nur noch ihren Namen. */
    .welcome-step {
        padding: 0.75rem 1rem;
    }

    .welcome-step-mark {
        width: 1.75rem;
        height: 1.75rem;
        font-size: var(--fs-text-xs);
    }

    .welcome-step-sub {
        display: none;
    }
}

/* Survey status alerts — dedicated, do not reuse alert-primary */
.alert-survey-online {
    color: var(--white);
    background-color: var(--bs-success);
    border-color: var(--bs-success);
}

.alert-survey-online .material-symbols-outlined {
    color: var(--white);
}

.alert-survey-offline {
    color: var(--bs-body-color);
    background-color: #e9ecef;
    border-color: #dee2e6;
}

.alert-survey-offline .material-symbols-outlined {
    color: var(--bs-body-color);
}

/* Paper-Backup Intro — page layout helpers */
.intro-step-badge {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    border-radius: 999px;
    background-color: var(--primary-bg-subtle);
    color: var(--primary-dark);
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.02rem;
}

.intro-step-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    background-color: var(--bs-primary);
    color: #fff;
    margin: 0 auto;
}

.intro-step-icon .material-symbols-outlined {
    font-size: 2.25rem;
}

.intro-step-title {
    font-size: 1.35rem;
    font-weight: 600;
    text-align: center;
    margin-bottom: 0.75rem;
}

/* Fliesstext linksbuendig: zentriert ist er auf beiden Seiten ausgefranst und
   wird mit jeder Zeile schwerer zu lesen. Zentriert bleiben Zeichen und Titel. */
.intro-step-body {
    font-size: var(--fs-text-base);
    line-height: 1.55;
    color: var(--bs-body-color);
}

.intro-option-card {
    display: flex;
    align-items: flex-start;
    gap: 0.85rem;
    padding: 0.85rem 1rem;
    border-radius: var(--radius-md);
    background-color: var(--primary-bg-subtle);
    border: 1px solid rgba(var(--primary-rgb), 0.2);
}

.intro-option-card .material-symbols-outlined {
    color: var(--bs-primary);
    flex-shrink: 0;
    margin-top: 0.1rem;
}

.intro-option-card-text {
    text-align: left;
    line-height: 1.45;
}

/* ==========================================================================
   Selected Table Rows
   Same primary background as hover for consistent highlighting.
   ========================================================================== */

.table .selected-row > td {
    background-color: var(--selected-bg);
}

/* Dieselbe Hervorhebung ausserhalb von Tabellen, etwa fuer die Auswahl in einer
   Liste. Die Klasse soll ueberall dasselbe bedeuten, nicht nur in Zeilen. */
.list-group-item.selected-row,
.selected-row:not(tr) {
    background-color: var(--selected-bg);
}

/* Der Port teilt sich die Zeile mit dem Servernamen, braucht aber nur Platz fuer
   vier Ziffern. Ohne feste Breite nimmt er die Haelfte der Gruppe ein. */
.input-group > .port-input {
    flex: 0 0 8rem;
}

/* ==========================================================================
   Active filter/search indicator
   Applied to form-select and form-control elements when a filter is active.
   ========================================================================== */

.filter-active {
    background-color: var(--selected-bg);
}

/* Eine widerrufbare Bestellung im eigenen Konto: links die Nummer und die Frist,
   rechts der Knopf. Auf schmalen Bildschirmen untereinander. */
.withdrawal-entry {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 0;
    border-top: 0.0625rem solid var(--gray-border-light);
}

.withdrawal-entry:first-of-type {
    border-top: 0;
}

/* ==========================================================================
   Beanstandete Felder
   Die Meldung steht am Kopf des Formulars, gearbeitet wird weiter unten. Damit
   niemand suchen muss, was gemeint ist, traegt jedes bemaengelte Feld dieselbe
   Farbe wie die Meldung. Bei einer Auswahl, die aus vielen Knoepfen besteht
   (Tarife) oder aus einem einzelnen Haken (Einwilligung), wird der Bereich
   markiert statt des Bedienelements: ein rotes Kaestchen von 1rem faellt nicht auf.
   ========================================================================== */

.field-invalid,
.field-invalid:focus {
    background-color: var(--danger-tint);
    border-color: var(--danger);
}

.field-invalid-block {
    background-color: var(--danger-tint);
    border: 1px solid var(--danger);
    border-radius: var(--radius-sm);
    padding: 0.75rem;
}

/* Ein Schalter haengt mit negativem Rand nach links aus dem Textfluss heraus; die
   Einrueckung dafuer steht als padding-left an der Zeile selbst. Bekommt dieselbe
   Zeile den Fehlerrahmen, wuerde die Polsterung oben diese Einrueckung ueberschreiben
   und der Schalter stuende links neben dem roten Kasten. Also beides addieren. */
.form-check.field-invalid-block {
    padding-left: calc(1.6em + 0.75rem);
}

.form-switch.field-invalid-block {
    padding-left: calc(2.6em + 0.75rem);
}

/* Zwei Zustaende, die keine Beanstandung sind und deshalb nicht rot werden.
   Die abgelehnte Umsatzsteuer-Identifikationsnummer haelt niemanden auf: sie soll
   auf einen Tippfehler stossen, nicht den Weg versperren. Und eine bestaetigte darf
   man sehen — daran haengt der Betrag darunter. */

.field-warning,
.field-warning:focus {
    background-color: var(--warning-tint);
    border-color: var(--warning);
}

.field-confirmed,
.field-confirmed:focus {
    background-color: var(--success-tint);
    border-color: var(--success);
}

/* Das Nummernfeld traegt waehrend der Abfrage einen Kreisel in seiner rechten
   Innenkante. Er sitzt ueber dem Feld statt daneben, damit die Zeile beim Erscheinen
   nicht umbricht. */
.offer-vatid-field {
    position: relative;
}

.offer-vatid-spinner {
    position: absolute;
    top: 50%;
    inset-inline-end: 0.75rem;
    margin-top: -0.5rem;
    color: var(--primary);
}

/* ==========================================================================
   Search-term highlight inside the item-browser result list
   Bootstrap's default <mark> uses a yellow background; we override here so the
   match stands out in primary green (matches the rest of the app palette).
   No padding so the highlight sits flush against the surrounding text.
   ========================================================================== */

.search-match {
    background-color: var(--bs-primary);
    color: var(--bs-white);
    padding: 0;
}

/* ==========================================================================
   Item-browser modal — collapsible topic drawer
   In topic-search mode the modal body is a flex row: drawer on the left, result
   list on the right. The drawer can be collapsed to a thin strip so the result
   list takes the full modal width when the user wants to focus on browsing hits.
   ========================================================================== */

.item-browser-drawer {
    width: 22rem;
    flex-shrink: 0;
}

.item-browser-drawer-strip {
    width: 2.5rem;
    flex-shrink: 0;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 0.5rem;
    border-right: 1px solid var(--bs-border-color);
    cursor: pointer;
    color: var(--bs-primary);
}

.item-browser-drawer-strip:hover {
    background-color: var(--selected-bg);
}

/* Bootstrap doesn't ship a min-w-0 utility; we need it on flex children that
   should be allowed to shrink narrower than their natural content width — without
   it, the result-list column refuses to give space back when the drawer expands. */
.min-w-0 {
    min-width: 0;
}


/* ==========================================================================
   Secondary perspective marker
   Used in Test contexts to signal that a perspective (parents, teachers,
   self-assessment) is typically less relevant than learner perspectives
   (pupils, students, trainees). The entry stays fully active and selectable;
   it is NOT muted (muted would signal disabled). Italic + a slightly lighter
   weight achieves "less central" without "unavailable".
   ========================================================================== */

.perspective-secondary {
    font-style: italic;
    font-weight: 400;
}

/* ==========================================================================
   Empty State Icons
   ========================================================================== */

.empty-state-icon {
    font-size: 4rem;
}

/* ==========================================================================
   Empty Layout shell (used by /login, /register, /agb, /datenschutz, /impressum, etc.)
   Sticky footer holding the three legal links. The shell is flex-column so the
   footer always sits at the bottom of the viewport even when the page content
   is short.
   ========================================================================== */

.empty-layout-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

/* Full-page screens (login/home) have no survey-runner flip animation, so the
   globally reserved scrollbar gutter (html { scrollbar-gutter: stable }) is not
   needed here. Reserving it would otherwise show as a light strip on the right
   edge against the green gradient — looking like a phantom scrollbar. */
html:has(.empty-layout-shell) {
    scrollbar-gutter: auto;
}

.empty-layout-shell > *:not(.empty-layout-footer) {
    flex: 1 0 auto;
    min-height: 0;
}

/* Sticky rather than merely last in the column: on a long page (imprint, privacy)
   the flex column alone puts the footer below the fold, and the legal links are
   the one thing that has to stay reachable. Sticky and not fixed on purpose —
   fixed would take the footer out of the flow and let content run underneath it,
   and unlike a transform it leaves the language picker's fixed dialog alone. */
.empty-layout-footer {
    position: sticky;
    bottom: 0;
    z-index: 1;
    flex: 0 0 auto;
    padding: 0.375rem 1rem;
    text-align: center;
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
    background: var(--surface);
    border-top: 0.0625rem solid var(--sidebar-border);
}

.empty-layout-footer a {
    color: var(--bs-secondary-color);
    text-decoration: none;
    cursor: pointer;
}

.empty-layout-footer a:hover {
    color: var(--bs-primary);
}

/* Auf schmalen Schirmen sitzt der fixierte Sprachwaehler rechts in der Fusszeile
   und wuerde die zentrierten Rechtslinks ueberdecken. Die Links ruecken deshalb
   nach links, und rechts bleibt die Breite des Sprachwaehlers frei. */
@media (max-width: 48rem) {
    .empty-layout-footer {
        text-align: left;
        padding-right: 7.5rem;
    }
}

/* Wo es das Hamburger-Menue gibt (die generierte Homepage), stehen die
   Rechtslinks auf schmalen Schirmen bereits im aufgeklappten Menue — die
   Fusszeile waere doppelt und faellt dort weg. Auf Seiten ohne Hamburger
   (Anmeldung, AGB, Datenschutz, Impressum) bleibt sie der einzige Weg zu
   Rechtlichem und damit sichtbar. */
@media (max-width: 62rem) {
    .empty-layout-shell:has(.site-nav-burger) .empty-layout-footer {
        display: none;
    }
}

/* ==========================================================================
   Full Page (Home, Login)
   ========================================================================== */

/* The 100vh min-height is now provided by .empty-layout-shell; here we just
   stretch to fill whatever the shell allocates above the footer. */
.fullpage-container {
    flex: 1 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
    padding: 3.125rem 1rem 1rem;
}

.fullpage-body {
    width: 100%;
    max-width: 28rem;
}


.fullpage-body .form-label {
    color: var(--white);
}

.fullpage-body .form-control {
    background-color: rgba(255, 255, 255, 0.15);
    border: none;
    color: var(--white);
}

.fullpage-body .form-control::placeholder {
    color: rgba(255, 255, 255, 0.5);
}

.fullpage-body .form-control:focus {
    background-color: rgba(255, 255, 255, 0.25);
    color: var(--white);
    box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.15);
}

.fullpage-body .input-group .btn-outline-secondary {
    background-color: rgba(255, 255, 255, 0.15);
    border: none;
    color: var(--white);
}

.fullpage-body .input-group .btn-outline-secondary:hover {
    background-color: rgba(255, 255, 255, 0.25);
    color: var(--white);
}

.fullpage-body .form-check-input {
    background-color: rgba(255, 255, 255, 0.15);
    border-color: rgba(255, 255, 255, 0.3);
}

.fullpage-body .form-check-input:checked {
    background-color: var(--white);
    border-color: var(--white);
    /* Bobble in primary color — SVG can't use CSS variables (see CLAUDE.md §4.4) */
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%232a7d4f'/%3e%3c/svg%3e");
}

.fullpage-body .form-check-label {
    color: var(--white);
}

.fullpage-body .form-text {
    color: rgba(255, 255, 255, 0.6);
}

.fullpage-body .btn-primary {
    background-color: var(--white);
    border-color: var(--white);
    color: var(--primary);
    font-weight: 600;
}

.fullpage-body .btn-primary:hover {
    background-color: rgba(255, 255, 255, 0.9);
    border-color: rgba(255, 255, 255, 0.9);
    color: var(--primary);
}

.progress-indicator-preview {
    padding: 0.6rem 0.75rem;
    background: var(--selected-bg);
    border-radius: 0.375rem;
    display: flex;
    align-items: center;
    min-height: 2.4rem;
}

.fullpage-body .progress {
    background-color: rgba(255, 255, 255, 0.2);
}

.fullpage-body .progress-bar {
    background-color: rgba(255, 255, 255, 0.7);
}

.fullpage-hint {
    color: rgba(255, 255, 255, 0.7);
}

.fullpage-icon-unchecked {
    color: rgba(255, 255, 255, 0.15);
}

.fullpage-top-left {
    position: fixed;
    top: 1rem;
    left: 1rem;
    z-index: 1000;
}

.fullpage-top-left a {
    color: var(--white);
    text-decoration: none;
    display: flex;
    align-items: center;
}

.fullpage-top-left a:hover {
    color: rgba(255, 255, 255, 0.8);
}

/* Language picker for full-page screens (login, register, home): pinned to the
   bottom-right corner so it sits in the footer band, mirroring the in-app footer
   layout. The picker's own modal is position:fixed and centered, so the trigger
   position here does not affect it. */
.fullpage-lang {
    position: fixed;
    right: 1rem;
    bottom: 0.4rem;
    z-index: 1000;
}

a.fullpage-link,
a.fullpage-link:visited,
a.fullpage-link:active {
    color: var(--white);
    text-decoration: none;
    opacity: 0.85;
}

a.fullpage-link:hover {
    color: var(--white);
    opacity: 1;
}

a.fullpage-link.fullpage-link-prominent,
a.fullpage-link.fullpage-link-prominent:visited,
a.fullpage-link.fullpage-link-prominent:active {
    color: var(--warning);
    opacity: 1;
}

a.fullpage-link.fullpage-link-prominent:hover {
    color: var(--warning-hover);
}

/* ==========================================================================
   App Brand
   ========================================================================== */

.app-brand {
    display: inline-flex;
    align-items: center;
    line-height: 1;
    color: var(--white);
    text-decoration: none;
}

/* Die Bildmarke liegt als SVG vor und wird als Maske vor die Textfarbe gelegt,
   nicht als <img> eingebunden. Damit folgt sie currentColor (weiss auf dem gruenen
   Balken, beliebig woanders), und die SVG-Datei selbst bleibt farbneutral und
   damit auch fuer Druck brauchbar. */
.app-brand-logo {
    flex-shrink: 0;
    display: block;
    aspect-ratio: 586 / 512;
    background-color: currentColor;
    -webkit-mask: url("../images/logo.svg") no-repeat center / contain;
    mask: url("../images/logo.svg") no-repeat center / contain;
}

.app-brand-title {
    display: inline-flex;
    align-items: center;
    font-family: var(--fs-font);
    font-weight: 600;
    letter-spacing: -0.02em;
    white-space: nowrap;
    line-height: 1;
}

.app-brand-text {
    display: inline-block;
}

.app-brand-ai {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.55em;
    height: 1.55em;
    border-radius: 50%;
    background-color: var(--secondary);
    color: var(--white);
    line-height: 1;
    margin: 0 0 0 3px;
    padding: 0 0 0 0.15em;
    text-align: center;
    box-sizing: border-box;
    letter-spacing: 0;
}

/* Hero variant: logo stacked above title, used on full-page layouts */
.app-brand-hero {
    flex-direction: column;
    gap: 1.25rem;
    margin: 0 0 2rem 0;
}

.app-brand-hero .app-brand-logo {
    height: clamp(3.25rem, 9vw, 5.5rem);
}

.app-brand-hero .app-brand-title {
    font-size: clamp(2rem, 6.5vw, 4.5rem);
}

/* Site variant: used by the logo block of the public website. Every measurement
   comes from the container's font size, which the block sets from the chosen size
   step. One number therefore moves mark and wordmark together, and the proportion
   between them cannot drift. */
.app-brand-site {
    flex-direction: column;
    gap: 0.35em;
}

.app-brand-site .app-brand-logo {
    height: 1.5em;
}

.app-brand-site .app-brand-title {
    font-size: 1em;
}

/* Side by side: the mark carries less ink than the closed letterforms, so at the
   same height it reads as too light. The same 1.2 ratio as in the top bar. */
.site-layout-horizontal .app-brand-site {
    flex-direction: row;
    gap: 0.4em;
}

.site-layout-horizontal .app-brand-site .app-brand-logo {
    height: 1.2em;
}

/* Compact variant: logo left of title, used in the top bar.
   Die Schriftgroesse sitzt am Container, damit Logo und Schriftzug in einem Zug
   skalieren: eine Zahl aendern, das Verhaeltnis bleibt. */
.app-brand-compact {
    flex-direction: row;
    gap: 0.6rem;
    font-size: 1.4rem;
}

/* Dasselbe Verhaeltnis wie im Hero (Bildmarke rund 1.2x der Schriftgroesse).
   Die Strichgrafik ist offen gezeichnet und traegt deshalb weniger Farbe als
   die geschlossenen Buchstaben; auf gleicher Hoehe wirkt sie zu schwach. */
.app-brand-compact .app-brand-logo {
    height: 1.2em;
}

.app-brand-compact .app-brand-title {
    font-size: 1em;
}

@media (max-width: 991.98px) {
    .app-brand-hero {
        gap: 1rem;
        margin-bottom: 1.75rem;
    }

    .app-brand-hero .app-brand-title {
        font-size: clamp(1.85rem, 8vw, 3.25rem);
    }
}

@media (max-width: 575.98px) {
    .app-brand-hero {
        gap: 0.85rem;
        margin-bottom: 1.5rem;
    }

    .app-brand-hero .app-brand-title {
        font-size: clamp(1.6rem, 9vw, 2.5rem);
    }

    .app-brand-compact {
        font-size: 1.1rem;
    }
}

/* ==========================================================================
   Page Title
   ========================================================================== */

.page-title {
    color: var(--bs-primary);
    /* Auf der Typo-Skala aus framework.css statt einer freien 2rem-Angabe. */
    font-size: var(--fs-text-2xl);
    font-weight: 600;
    line-height: 1;
    margin-bottom: 1rem;
}

/* ==========================================================================
   Page header
   The uniform opening block of a page, rendered by the PageHeader component:
   context line, title, description and the page-level actions on the right.
   The header carries the whole gap down to the content, so no page adds a
   margin of its own and every page keeps the same rhythm.
   ========================================================================== */
.page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* Wrap statt quetschen: auf schmalen Schirmen rutschen die Aktionen unter den
       Titel, statt ihn zu ueberlagern oder die Beschreibung auf Spaltenbreite zu
       druecken. Auf breiten Schirmen aendert sich nichts — gewrappt wird erst,
       wenn beides nebeneinander nicht mehr passt. */
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.page-header .page-title {
    margin-bottom: 0;
}

.page-header-text {
    min-width: 0;
}

/* Der Weg zurueck ist immer ein Link, immer ueber dem Titel, immer mit demselben
   Abstand darunter — unabhaengig davon, ob die Seite dafuer eine Adresse oder eine
   Methode hinterlegt. Fruehe Seiten hatten hier mal einen Knopf links neben dem
   Titel, mal einen ueber ihm; beides las sich wie eine andere Anwendung. */
.page-header-back {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    margin-bottom: 0.35rem;
    color: var(--bs-secondary-color);
    text-decoration: none;
    cursor: pointer;
}

.page-header-back:hover {
    color: var(--bs-primary);
}

.page-header-back .material-symbols-outlined {
    font-size: 1.2rem;
}

/* Titel und was direkt daneben gehoert (z.B. das Info-Zeichen, das die Erklaerung
   der Seite oeffnet) — eine Zeile, damit beides auf einer Grundlinie sitzt. */
.page-header-title-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

.page-header-title-row .page-title {
    min-width: 0;
}

/* Im Titel haengt die Marke an der Titelgroesse: ein Symbol daneben, das kleiner
   bleibt als die Schrift, sieht nach Versehen aus. Dasselbe gilt umgekehrt fuer
   kleine Beschriftungen, neben denen die Vorgabegroesse zu wuchtig waere. */
.page-title .ai-mark,
.modal-title .ai-mark,
.card-header h5 .ai-mark,
.card-header h6 .ai-mark,
h6 .ai-mark {
    font-size: 1em;
}

.setup-field-label .ai-mark,
.form-check-label .ai-mark {
    font-size: 1.15em;
}

/* Das Statuszeichen vor dem Namen einer Umfrage — dieselbe Hoehe wie der Titel,
   statt des frueheren style-Attributs im Markup (Regel 4.5). */
.survey-status-icon {
    font-size: 2.4rem;
}

.page-header-eyebrow {
    color: var(--bs-secondary-color);
    margin-bottom: 0.25rem;
}

.page-header-description {
    margin-top: 0.4rem;
    margin-bottom: 0;
}

.page-header-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

/* Info icon button placed next to a .page-title. Sized to visually match
   the 2rem title so flexbox center alignment also reads as centered. */
.page-title-info-btn {
    color: var(--bs-primary);
    line-height: 1;
}

.page-title-info-btn .material-symbols-outlined {
    font-size: var(--fs-text-2xl);
}

.page-subtitle {
    color: var(--bs-secondary);
    font-size: 1.7rem;
    font-weight: 500;
}

/* ==========================================================================
   Customer Type Badges
   All badges derive from the primary color at different lightness levels.
   School = 100% primary (most important customer type).
   ========================================================================== */

.customer-type-badge {
    display: inline-block;
    width: 7rem;
    text-align: left;
}

.customer-type-school,
.customer-type-carrier,
.customer-type-organization,
.customer-type-individual {
    background-color: rgb(var(--bs-primary-rgb)) !important;
    color: white;
}

/* ==========================================================================
   Truncated Table Cells
   Prevents line breaks and clips overflow with ellipsis.
   Requires table-layout: fixed on the table.
   ========================================================================== */

.text-truncate-cell {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 10rem;
}

/* Column hover highlighting for tables with class 'column-hover' */
.column-hover-active {
    background-color: var(--selected-bg) !important;
}

/* Service-period range: two DatePickers in an input-group, minimum width */
.service-period-group {
    width: auto;
}

.service-period-group .form-control {
    width: 7rem;
    flex: 0 0 auto;
}

/* Das sichtbare Feld eines Datumswaehlers ist readonly, weil ausschliesslich der
   Kalender hineinschreiben soll. Grau wie ein gesperrtes Feld darf es deshalb aber
   nicht aussehen: man kann es sehr wohl anklicken, und genau das soll man auch. Also
   heller Grund wie bei jedem anderen Feld, Zeigefinger als Mauszeiger und ein
   Kalenderblatt am rechten Rand, damit man sieht, dass hier etwas aufgeht.
   Die Strichfarbe steht im SVG als fester Wert (#5B6373, dieselbe wie beim Pfeil der
   Auswahlfelder): eine data-URL kann keine CSS-Variable lesen. */
.flatpickr-alt-input[readonly],
.form-control.flatpickr-alt-input[readonly] {
    background-color: var(--fs-surface);
    cursor: pointer;
    padding-right: 2.25em;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235B6373' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cpath d='M16 2v4M8 2v4M3 10h18'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75em center;
    background-size: 1.15em 1.15em;
}

/* Ein wirklich gesperrter Waehler bleibt grau — dort ist die Aussage richtig. */
.flatpickr-alt-input:disabled,
.form-control.flatpickr-alt-input:disabled {
    background-color: var(--fs-surface-sunk);
    cursor: default;
}

/* Flatpickr custom footer with OK/Cancel buttons */
.flatpickr-footer {
    display: flex;
    gap: 0.5rem;
    padding: 0.5rem;
    border-top: 1px solid var(--bs-border-color);
}

.flatpickr-footer-btn {
    flex: 1;
    padding: 0.4rem 0.75rem;
    border: none;
    border-radius: 0.25rem;
    font-size: 0.875rem;
    cursor: pointer;
}

.flatpickr-delete {
    background-color: var(--bs-danger);
    color: var(--bs-white);
}

.flatpickr-delete:hover {
    opacity: 0.85;
}

.flatpickr-cancel {
    background-color: var(--bs-dark);
    color: var(--bs-white);
}

.flatpickr-cancel:hover {
    opacity: 0.85;
}

.flatpickr-ok {
    background-color: var(--bs-primary);
    color: var(--bs-white);
}

.flatpickr-ok:hover {
    opacity: 0.85;
}

/* ============================================================
 * Survey Item Components (si-*)
 * Shared styles for SurveyItemCard and individual item type views.
 * Used in preview, card view, and production surveys.
 * ============================================================ */

/* Likert / Choice options */
.si-likert {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.si-likert.si-likert-tiles {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.5rem;
    align-items: stretch;
}

@media (min-width: 576px) {
    .si-likert.si-likert-tiles {
        grid-template-columns: repeat(auto-fit, minmax(calc(33.3333% - 0.5rem), 1fr));
    }
}

@media (min-width: 992px) {
    .si-likert.si-likert-tiles {
        grid-template-columns: repeat(auto-fit, minmax(calc(20% - 0.5rem), 1fr));
    }
}

.si-likert.si-likert-tiles .si-likert-option {
    flex-direction: column;
    justify-content: flex-start;
    text-align: center;
    padding: 0.75rem 0.5rem;
}

.si-likert.si-likert-tiles .si-likert-icon {
    font-size: 2rem;
    height: 2.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.si-likert.si-likert-tiles .si-likert-text {
    margin-top: 0.125rem;
}

.si-likert-option {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5rem 0.75rem;
    border-radius: 0.5rem;
    cursor: pointer;
    transition: all 0.15s ease;
    border: 1px solid var(--bs-border-color);
    background: var(--bs-white);
}

/* ---- Ranking-Auswertung ----
   Je Option ein Balken, der zeigt, wie sich die Nennungen auf die Plätze verteilen.
   Die Abstufung läuft vom kräftigen ersten Platz zu den blasseren hinteren Plätzen. */

.ranking-result-mean {
    font-weight: 600;
    white-space: nowrap;
}

.ranking-result-bar {
    display: flex;
    min-width: 8rem;
    height: 1.25rem;
    border-radius: 0.25rem;
    overflow: hidden;
    background: var(--bs-light);
}

.ranking-result-segment {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.6875rem;
    color: var(--bs-white);
    overflow: hidden;
}

.ranking-result-place-1 { background: var(--primary); }
.ranking-result-place-2 { background: var(--primary); opacity: 0.82; }
.ranking-result-place-3 { background: var(--primary); opacity: 0.66; }
.ranking-result-place-4 { background: var(--primary); opacity: 0.5; }
.ranking-result-place-5 { background: var(--primary); opacity: 0.36; }
.ranking-result-place-6 { background: var(--primary); opacity: 0.24; }

/* ---- Ranking-Item runner view ----
   Eine Zeile je Option: Platznummer als Auswahlfeld (Tastatur/Touch), Text, Pfeile
   und rechts der Anfasser für Drag & Drop. Alle drei Wege verändern dieselbe
   Reihenfolge, damit Maus, Finger und Tastatur zum gleichen Ergebnis führen. */

.si-ranking {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.si-ranking-row {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.375rem 0.5rem 0.375rem 0.375rem;
    border-radius: 0.5rem;
    border: 1px solid var(--bs-border-color);
    background: var(--bs-white);
    transition: border-color 0.15s ease, opacity 0.15s ease;
}

.si-ranking-row[draggable="true"] {
    cursor: grab;
}

.si-ranking-row.si-ranking-dragging {
    opacity: 0.5;
    border-color: var(--primary);
}

.si-ranking-row.si-ranking-unranked {
    background: var(--bs-light);
    opacity: 0.75;
}

.si-ranking-rank {
    width: 5.5rem;
    flex-shrink: 0;
    text-align: center;
}

.si-ranking-icon {
    font-size: 1.5rem;
    flex-shrink: 0;
}

.si-ranking-text {
    flex: 1 1 auto;
    min-width: 0;
}

.si-ranking-moves {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    flex-shrink: 0;
}

.si-ranking-move {
    border: none;
    background: transparent;
    color: var(--bs-secondary);
    padding: 0;
    width: 1.5rem;
    height: 1.125rem;
    border-radius: 0.25rem;
    cursor: pointer;
}

.si-ranking-move:hover:not(:disabled) {
    background: var(--selected-bg);
    color: var(--primary);
}

.si-ranking-move:disabled {
    opacity: 0.3;
    cursor: default;
}

.si-ranking-move .material-symbols-outlined {
    font-size: 1.125rem;
}

.si-ranking-handle {
    color: var(--bs-secondary);
    flex-shrink: 0;
}

.si-ranking-static .si-ranking-handle,
.si-ranking-static .si-ranking-moves {
    opacity: 0.4;
}

/* Trennlinie zwischen den zählenden Plätzen und dem Rest — nur bei Top-N-Rankings. */
.si-ranking-cutoff {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.25rem 0;
    color: var(--bs-secondary);
    font-size: 0.75rem;
}

.si-ranking-cutoff::before,
.si-ranking-cutoff::after {
    content: "";
    flex: 1 1 auto;
    border-top: 1px dashed var(--bs-border-color);
}

/* ---- Strukturmerkmal-Item runner view ---- */

.si-traits {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.si-trait-option {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5rem 0.75rem;
    border-radius: 0.5rem;
    border: 1px solid var(--bs-border-color);
    background: var(--bs-white);
    cursor: pointer;
    transition: all 0.15s ease;
    margin: 0;
}

.si-trait-option:hover {
    background: var(--bs-light);
    border-color: var(--bs-primary);
}

.si-trait-option.selected {
    background: var(--selected-bg);
    border-color: var(--bs-primary);
}

.si-trait-option.locked {
    cursor: default;
    background: var(--bs-light);
    color: var(--bs-secondary-color);
}

.si-trait-option.locked:hover {
    border-color: var(--bs-border-color);
}

.si-trait-option input[type="checkbox"],
.si-trait-option input[type="radio"] {
    margin: 0;
    flex: 0 0 auto;
}

.si-trait-label {
    flex: 1 1 auto;
}

.si-trait-lock-icon {
    flex: 0 0 auto;
    font-size: 1rem;
    color: var(--bs-secondary-color);
}

.si-likert-option:hover {
    background: var(--bs-light);
    border-color: var(--bs-primary);
}

/* Reflection-locked state: the answer is final and the participant is reading the
   correctness feedback. Suppress hover effects, pointer cursor and click events on
   the answer options so they do not look re-editable. */
.si-locked .si-likert-option,
.si-locked .si-binary-option,
.si-locked .si-rating-icon {
    cursor: default;
    pointer-events: none;
}

.si-locked .si-likert-option:hover,
.si-locked .si-binary-option:hover {
    background: var(--bs-white);
    border-color: var(--bs-border-color);
}

.si-locked .si-likert-option.selected:hover,
.si-locked .si-binary-option.selected:hover {
    background: var(--bs-primary);
    border-color: var(--bs-primary);
}

.si-locked .si-likert-option.si-correct:hover,
.si-locked .si-binary-option.si-correct:hover {
    background: var(--bs-success);
    border-color: var(--bs-success);
}

.si-locked .si-likert-option.si-incorrect:hover,
.si-locked .si-binary-option.si-incorrect:hover {
    background: var(--bs-danger);
    border-color: var(--bs-danger);
}

.si-likert-option.selected {
    background: var(--bs-primary);
    color: var(--bs-white);
    border-color: var(--bs-primary);
}

.si-likert-option.si-correct {
    background: var(--bs-success);
    border-color: var(--bs-success);
}

.si-likert-option.si-incorrect {
    background: var(--bs-danger);
    border-color: var(--bs-danger);
}

/* Reflection box shown after the participant answers (test mode, ShowCorrectAnswerAfterResponse) */
.si-reflection {
    margin-top: 1rem;
    padding: 0.75rem 1rem;
    background: var(--bs-light, #f8f9fa);
    border-left: 3px solid var(--bs-primary);
    border-radius: 0.25rem;
    font-size: 0.95rem;
    line-height: 1.5;
}

.si-reflection-correct {
    border-left-color: var(--bs-success);
    background: rgba(var(--bs-success-rgb), 0.08);
}

.si-reflection-incorrect {
    border-left-color: var(--bs-danger);
    background: rgba(var(--bs-danger-rgb), 0.08);
}

/* Missed-correct: a multiple-choice option that was correct but the participant did
   not pick it. Distinct from "incorrect" (= picked the wrong one) so the learner
   sees at a glance which options they would still have needed for full marks. */
.si-reflection-missed {
    border-left-color: var(--bs-warning);
    background: rgba(var(--bs-warning-rgb), 0.10);
}

.si-reflection + .si-reflection {
    margin-top: 1rem;
}

/* Inside the reflection panel the first reflection block must not have any top
   margin so its top edge aligns with the top of the item card. We can't use
   :first-child because the panel's first child is .si-reflection-panel-handle
   (the mobile drag handle, present on every viewport — display:none on desktop).
   Adjacent-sibling from the handle to the first reflection works at all widths
   and only this pair (subsequent blocks keep the .si-reflection + .si-reflection
   inter-block spacing). */
.si-reflection-panel > .si-reflection-panel-handle + .si-reflection {
    margin-top: 0;
}

.si-reflection-label {
    font-weight: 600;
    margin-right: 0.35rem;
}

.si-reflection-editable {
    cursor: pointer;
    transition: filter 0.15s ease, transform 0.15s ease;
}

.si-reflection-editable:hover {
    filter: brightness(0.97);
}

/* Reflection panel — wraps one or more .si-reflection blocks.
   Layout depends on viewport:
   • Wide desktop (≥1200px): floats to the right of the centered item card.
   • Narrow desktop / tablet (768–1199px): sits inline below the card (default flow).
   • Mobile (<768px): renders as a bottom-sheet with a drag handle, collapsed by
     default — tap the handle to expand. */
.si-reflection-panel {
    margin-top: 1rem;
}

.si-reflection-panel-handle {
    display: none;
}

@media (min-width: 1200px) {
    .si-reflection-panel {
        position: absolute;
        left: calc(100% + 2rem);
        /* The .runner-item-wrapper top sits where the numbered badge floats; the
           actual card top is 1.25rem lower (margin-top of .si-card-numbered).
           Align the panel with the card's visual top edge. */
        top: 1.25rem;
        width: 16rem;
        max-height: calc(100% - 1.25rem);
        overflow-y: auto;
        margin-top: 0;
    }
}

@media (max-width: 767.98px) {
    .si-reflection-panel {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        margin-top: 0;
        max-height: 5.5rem;
        overflow: hidden;
        background: var(--bs-white);
        border-top: 1px solid var(--bs-border-color);
        border-radius: 1rem 1rem 0 0;
        box-shadow: 0 -0.5rem 1rem -0.25rem rgba(0, 0, 0, 0.15);
        padding: 0.25rem 1rem 1rem;
        z-index: 1050;
        transition: max-height 0.3s ease;
    }

    .si-reflection-panel.expanded {
        max-height: 75vh;
        overflow-y: auto;
    }

    .si-reflection-panel-handle {
        display: block;
        width: 3rem;
        height: 0.25rem;
        background: var(--bs-secondary);
        border-radius: 0.125rem;
        margin: 0.25rem auto 0.5rem;
        opacity: 0.4;
        cursor: pointer;
    }

    /* Reserve space at the bottom so the answer card is not hidden behind the
       collapsed bottom-sheet. */
    .runner-card-flip-back .si-card,
    .runner-card-flip-front .si-card {
        margin-bottom: 6rem;
    }
}

.si-likert-option.selected .si-likert-icon,
.si-binary-option.selected .si-binary-icon {
    color: var(--bs-white) !important;
}

.si-likert-icon {
    font-size: 1.5rem;
    flex-shrink: 0;
}

.si-likert-text {
    font-size: 0.875rem;
    line-height: 1.3;
}

/* Single vs. Multiple choice — visual distinction.
   Three layered signals make the mode obvious even to readers who skip the text:
   1. .si-mode-hint (pictogram + label above the options)
   2. .si-choice-indicator (radio circle vs. checkbox inside each option)
   3. The selection behavior itself (single replaces, multi toggles) */
.si-mode-hint {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    color: var(--bs-secondary);
    font-size: 0.875rem;
    margin-bottom: 0.5rem;
}

.si-mode-hint .material-symbols-outlined {
    font-size: 1.125rem;
}

.si-choice-indicator {
    font-size: 1.5rem;
    flex-shrink: 0;
    color: var(--bs-secondary);
    transition: color 0.15s ease;
}

.si-likert-option.selected .si-choice-indicator,
.si-likert-option.si-correct .si-choice-indicator,
.si-likert-option.si-incorrect .si-choice-indicator {
    color: var(--bs-white);
}

/* Flip card — answer phase on the front, reflection phase on the back.
   Used by SurveyRunner to give the participant a clear "commit, then learn"
   moment. Both faces share the same grid cell so the container takes the
   height of whichever face is taller (back tends to be taller because of
   the reflection text). */
.si-flip {
    perspective: 1500px;
}

.si-flip-inner {
    display: grid;
    grid-template-areas: "stack";
    transform-style: preserve-3d;
    transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.si-flip-front,
.si-flip-back {
    grid-area: stack;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

.si-flip-back {
    transform: rotateY(180deg);
}

.si-flip.si-flip-flipped .si-flip-inner {
    transform: rotateY(180deg);
}

@media (prefers-reduced-motion: reduce) {
    .si-flip-inner {
        transition: none;
    }
}

/* Reflection face is read-only — kill hover/cursor on the answer options so the
   participant doesn't get a misleading hint that they can still pick something. */
.si-flip-back .si-likert-option,
.si-flip-back .si-binary-option,
.si-flip-back .si-rating-icon,
.si-flip-back .si-rating-point {
    pointer-events: none;
}

/* Rating */
.si-rating {
    display: flex;
    justify-content: center;
    gap: 0.375rem;
    flex-wrap: wrap;
}

.si-rating-icon {
    cursor: pointer;
}

.si-rating-icon .material-symbols-outlined {
    font-size: 3rem;
}

.si-rating-point {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    border: 0.125rem solid var(--bs-border-color);
    cursor: pointer;
    transition: all 0.15s ease;
    background: var(--bs-white);
}

.si-rating-point:hover {
    border-color: var(--bs-primary);
    transform: scale(1.1);
}

.si-rating-point.selected {
    background: var(--bs-primary);
    border-color: var(--bs-primary);
    color: var(--bs-white);
}

/* Slider */
.si-slider {
    padding: 0.5rem 0;
}

.si-slider-value {
    text-align: center;
    font-size: 2rem;
    font-weight: 700;
    color: var(--bs-primary);
    margin-top: 0.25rem;
}

.si-range-lg::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--bs-primary);
    border: none;
    margin-top: -0.375rem;
    cursor: pointer;
}

.si-range-lg::-moz-range-thumb {
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--bs-primary);
    border: none;
    cursor: pointer;
}

.si-range-lg::-webkit-slider-runnable-track {
    height: 0.75rem;
    border-radius: 0.375rem;
    background: var(--bs-white);
    border: 1px solid var(--bs-border-color);
}

.si-range-lg::-moz-range-track {
    height: 0.75rem;
    border-radius: 0.375rem;
    background: var(--bs-white);
    border: 1px solid var(--bs-border-color);
}

/* Binary choice */
.si-binary {
    display: flex;
    gap: 0.75rem;
}

.si-binary-option {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 1.25rem 0.75rem;
    border: 0.125rem solid var(--bs-border-color);
    border-radius: 0.75rem;
    cursor: pointer;
    transition: all 0.15s ease;
    background: var(--bs-white);
    text-align: center;
    font-weight: 500;
}

.si-binary-option:hover {
    border-color: var(--bs-primary);
    box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.08);
}

.si-binary-option.selected {
    border-color: var(--bs-primary);
    background: var(--bs-primary);
    color: var(--bs-white);
}

.si-binary-option.si-correct {
    border-color: var(--bs-success);
    background: var(--bs-success-bg-subtle);
}

.si-binary-option.si-incorrect {
    border-color: var(--bs-danger);
    background: var(--bs-danger-bg-subtle);
}

.si-binary-icon {
    font-size: 2.5rem;
}

/* Short answer — correctness reflection on the input field */
input.form-control.si-correct {
    border-color: var(--bs-success);
    background-color: var(--bs-success-bg-subtle);
}

input.form-control.si-incorrect {
    border-color: var(--bs-danger);
    background-color: var(--bs-danger-bg-subtle);
}

.si-correct-answer-reveal {
    color: var(--bs-success);
    font-size: 0.95rem;
}

/* Free text */
.si-freetext {
    border: 0.125rem solid var(--bs-border-color);
    border-radius: 0.5rem;
    resize: none;
}

/* Survey Items preview */
.preview-wrapper {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 16rem);
    border: 1px solid var(--bs-border-color);
    border-radius: 0.75rem;
    background: var(--bs-gray-200);
    overflow: hidden;
}

.preview-toolbar {
    display: flex;
    justify-content: center;
    padding: 0.75rem;
    background: var(--bs-gray-200);
    border-bottom: 1px solid var(--bs-border-color);
    flex-shrink: 0;
}

.preview-scroll {
    flex: 1;
    overflow-y: auto;
    padding: 2rem 1rem;
    display: flex;
    justify-content: center;
}

.preview-device {
    background: var(--bs-white);
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
    padding: 2rem;
    width: 100%;
    height: fit-content;
    box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.08);
    transition: max-width 0.3s ease;
}

.preview-desktop {
    max-width: 100%;
}

.preview-tablet {
    max-width: 48rem;
}

.preview-mobile {
    max-width: 24rem;
    padding: 1rem;
}

.preview-section-header {
    font-size: 1.4rem;
    font-weight: 600;
    margin-top: 3rem;
    margin-bottom: 2.5rem;
    padding-bottom: 0.5rem;
    border-bottom: 2px solid var(--bs-primary);
}

.preview-section-header:first-child,
.preview-device > .preview-section-header:first-of-type {
    margin-top: 0;
}

.preview-item {
    margin-bottom: 1.5rem;
}

.preview-item:last-child {
    margin-bottom: 0;
}

/* ---- Matrix questions (si-matrix-*) ----
   Consecutive Likert items with an identical scale rendered as one table:
   rows = statements, columns = scale steps, one shared scale header.
   Below the md breakpoint the table is replaced by stacked single items. */

/* Base card look: SurveyItemCard's .si-card styles are component-scoped and do not
   reach this separate component, so the matrix card carries its own equivalent. */
.si-matrix-card {
    position: relative;
    padding: 1.25rem;
    border: 1px solid var(--gray-border-light);
    border-radius: 0.75rem;
    background: var(--surface);
}

.si-matrix-card.si-card-error {
    border-color: var(--danger);
}

.si-matrix-table-wrap {
    overflow-x: auto;
}

.si-matrix-table {
    width: 100%;
    border-collapse: collapse;
}

.si-matrix-table th,
.si-matrix-table td {
    vertical-align: middle;
    padding: 0.5rem;
    border-bottom: 1px solid var(--gray-border-light);
}

.si-matrix-table thead th {
    border-bottom: 1px solid var(--gray-border-medium);
}

.si-matrix-table tbody tr:last-child th,
.si-matrix-table tbody tr:last-child td {
    border-bottom: none;
}

.si-matrix-question-col {
    width: 40%;
}

.si-matrix-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    gap: 0.125rem;
    text-align: center;
}

.si-matrix-header-icon {
    font-size: 1.5rem;
}

.si-matrix-header-text {
    font-size: var(--fs-text-sm);
    font-weight: 600;
    line-height: 1.25;
}

.si-matrix-question-cell {
    font-weight: 400;
    text-align: start;
}

.si-matrix-question-text {
    line-height: 1.4;
}

.si-inline-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 1.5rem;
    margin-inline-end: 0.5rem;
    padding: 0 0.375rem;
    border-radius: 0.75rem;
    background: var(--primary-tint);
    color: var(--primary-dark);
    font-size: var(--fs-text-xs);
    font-weight: 600;
}

.si-inline-number-required {
    background: var(--primary);
    color: var(--primary-ink);
}

.si-matrix-cell {
    text-align: center;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.si-matrix-cell:hover {
    background: var(--surface-sunk);
}

.si-matrix-dot {
    display: inline-block;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    border: 1px solid var(--gray-border-medium);
    background: var(--surface);
    transition: all 0.15s ease;
}

.si-matrix-cell:hover .si-matrix-dot {
    border-color: var(--primary);
}

.si-matrix-cell.selected .si-matrix-dot {
    border-color: var(--primary);
    background: var(--primary);
    box-shadow: inset 0 0 0 0.1875rem var(--surface);
}

.si-matrix-table.si-locked .si-matrix-cell {
    cursor: default;
    pointer-events: none;
}

.si-matrix-row-error > th,
.si-matrix-row-error > td,
.si-matrix-stack-row.si-matrix-row-error {
    background: var(--danger-tint);
}

.si-matrix-comment-col,
.si-matrix-comment-cell {
    width: 2.5rem;
    text-align: center;
}

.si-matrix-comment-btn {
    border: none;
    background: transparent;
    padding: 0.25rem;
    border-radius: 50%;
    color: var(--gray-text-secondary);
    cursor: pointer;
}

.si-matrix-comment-btn:hover {
    background: var(--surface-sunk);
    color: var(--primary);
}

.si-matrix-comment-btn .material-symbols-outlined {
    font-size: 1.25rem;
}

.si-matrix-comment-row td {
    padding: 0.5rem;
}

.si-matrix-stack {
    display: none;
}

.si-matrix-stack-row {
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--gray-border-light);
}

.si-matrix-stack-row:last-child {
    border-bottom: none;
}

.si-matrix-stack-question {
    display: flex;
    align-items: flex-start;
    gap: 0.25rem;
    margin-bottom: 0.625rem;
}

.si-matrix-stack-question .si-matrix-question-text {
    flex: 1 1 auto;
}

@media (max-width: 767.98px) {
    .si-matrix-table-wrap {
        display: none;
    }

    .si-matrix-stack {
        display: block;
    }
}

/* ---- Generic item group card (si-group-*) ----
   Members of an item group without a special layout share one card: each member
   renders as an embedded item card, separated by hairlines. */

.si-group-row {
    padding: 1rem 0;
    border-bottom: 1px solid var(--gray-border-light);
}

.si-group-row:first-child {
    padding-top: 0;
}

.si-group-row:last-child {
    padding-bottom: 0;
    border-bottom: none;
}

.si-group-member {
    position: relative;
}

.si-group-member.si-card-error {
    background: var(--danger-tint);
    border-radius: 0.5rem;
}

/* Scientific relevance is authored in a plain textarea — keep its line breaks
   when reading it back. */
.relevance-text {
    white-space: pre-wrap;
}

/* The relevance opens as a popover, not a dialog: a glance, then gone again.
   The transparent overlay catches the click beside it and closes it. */
.relevance-anchor {
    position: relative;
    display: inline-flex;
}

.relevance-overlay {
    position: fixed;
    inset: 0;
    z-index: 1040;
}

.relevance-popover {
    position: absolute;
    top: calc(100% + 0.375rem);
    right: 0;
    z-index: 1050;
    width: 24rem;
    max-width: 70vw;
    max-height: 50vh;
    overflow-y: auto;
    padding: 0.75rem 1rem;
    text-align: start;
    font-weight: 400;
    background: var(--surface);
    border: 1px solid var(--gray-border-light);
    border-radius: 0.5rem;
    box-shadow: var(--shadow-lg);
}

.relevance-popover-title {
    margin-bottom: 0.375rem;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--gray-text-secondary);
}

/* ---- Item lists (editor + viewer): bracket along group member rows ----
   Rows that belong to one item group are connected by a vertical primary bar at
   the row start. The run's first and last row add a horizontal arm (⌐ / ∟), so
   the bar reads as a bracket and two adjacent groups are clearly separated. */

.group-member-row > td:first-child {
    position: relative;
}

.group-member-row > td:first-child::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 0.25rem;
    background: var(--primary);
}

.group-member-row-first > td:first-child::before {
    top: 0.375rem;
    border-radius: 0.125rem 0 0 0;
}

.group-member-row-last > td:first-child::before {
    bottom: 0.375rem;
    border-radius: 0 0 0 0.125rem;
}

/* Horizontal bracket arms on the boundary rows. A row that is first AND last
   (stale single-row fragment) only shows the top arm — good enough for a state
   the UI never produces on purpose. */
.group-member-row-first > td:first-child::after,
.group-member-row-last > td:first-child::after {
    content: "";
    position: absolute;
    left: 0.25rem;
    width: 0.75rem;
    height: 0.25rem;
    background: var(--primary);
    border-radius: 0 0.125rem 0.125rem 0;
}

.group-member-row-first > td:first-child::after {
    top: 0.375rem;
}

.group-member-row-last > td:first-child::after {
    bottom: 0.375rem;
}

.group-member-row-first.group-member-row-last > td:first-child::after {
    top: 0.375rem;
    bottom: auto;
}

/* The picker sits among the other global controls on the green bar, and there it
   takes the bar's colours. The white pill it wears on a light ground would sit on
   the bar like a sticker. */
.topbar-lang .lang-pill {
    gap: 0.3rem;
    padding: 0.125rem 0.5rem;
    background-color: transparent;
    border-color: var(--overlay-white-medium);
    color: var(--white);
}

.topbar-lang .lang-pill:hover {
    background-color: var(--navbar-item-hover);
    border-color: var(--white);
}

.topbar-lang .lang-pill .material-symbols-outlined {
    font-size: 1rem;
    color: var(--white);
}

/* Imprint page content */
.imprint-content h4 {
    margin-top: 1.75rem;
    font-size: 1.2rem;
    font-weight: 600;
}

.imprint-content h4:first-child {
    margin-top: 0;
}

.imprint-content p {
    margin-bottom: 0.75rem;
}

/* Add additional app-specific styles below */

/* Inline language flag (size matches surrounding text, circular crop) */
.lang-flag-inline {
    width: 1em;
    height: 1em;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

/* Horizontally scrollable filter grid in the surveys list modal */
.filter-grid {
    gap: 0;
}

.filter-column {
    flex: 0 0 14rem;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--bs-border-color);
    min-height: 0;
}

.filter-column:last-child {
    border-right: 0;
}

.filter-column-header {
    font-weight: 600;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--bs-border-color);
    background-color: var(--bs-light);
    position: sticky;
    top: 0;
    z-index: 1;
}

.filter-column-body {
    overflow-y: auto;
    flex: 1 1 auto;
}

.filter-value {
    padding: 0.5rem 1rem;
    cursor: pointer;
    user-select: none;
    border-bottom: 1px solid var(--bs-border-color);
}

.filter-value:hover {
    background-color: var(--bs-tertiary-bg);
}

.filter-value.selected {
    background-color: var(--bs-primary);
    color: var(--bs-white);
    font-weight: 500;
}

.filter-value.selected:hover {
    background-color: var(--bs-primary);
    color: var(--bs-white);
    opacity: 0.9;
}

/* Authentication method picker cards */
.method-card {
    border: 1px solid var(--bs-border-color);
    border-radius: var(--radius-md);
    padding: 1.5rem;
    cursor: pointer;
    background-color: var(--bs-white);
    transition: var(--transition-colors), box-shadow var(--duration-base) var(--ease-out);
}

.method-card:hover {
    background-color: var(--bs-light);
    border-color: var(--bs-primary);
    box-shadow: var(--shadow-md);
}

.method-card.selected {
    border-color: var(--bs-primary);
    background-color: var(--selected-bg);
    box-shadow: var(--shadow-sm);
}

/* Spinning icon used for in-progress paper import analyses. */
.icon-spin {
    animation: icon-spin-rotation 1.6s linear infinite;
    display: inline-block;
}

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

/* Read-only wrapper used in Surveys/Edit.razor and Surveys/Templates/Edit.razor.
   <fieldset disabled> would otherwise add the browser's default fieldset chrome (border,
   padding, margin) and indent the content — we want it to be transparent layout-wise
   and only contribute the disabled-state semantics to its descendants. */
.ro-fieldset {
    border: 0;
    padding: 0;
    margin: 0;
    min-width: 0;
}

/* Bootstrap defines `fieldset:disabled .btn { pointer-events: none; opacity: ... }`
   which targets the `.btn` CLASS, not the form-listed-element semantics. That kills
   our anchor-based close/cancel buttons (<a class="btn btn-close"> etc.) too — even
   though they are intentionally NOT form-listed-elements so they survive the HTML
   `<fieldset disabled>` cascade. Re-enable interaction for anchor-based buttons inside
   a read-only fieldset; real <button> descendants stay disabled by the HTML cascade. */
.ro-fieldset[disabled] a.btn,
.ro-fieldset[disabled] a.btn-close {
    pointer-events: auto;
    opacity: 1;
}

/* Helper class for non-button list items (<div role="button">) whose mutation handler
   we've gated server-side. Removes the pointer-cursor + Bootstrap hover-highlight so
   the UI doesn't suggest clickability the user no longer has. The Bootstrap
   .list-group-item-action:hover selector is high-specificity and uses CSS variables;
   we mirror those structures here so the override actually wins. */
.ro-list-item {
    cursor: default;
}

.ro-list-item.list-group-item:hover,
.ro-list-item.list-group-item:focus {
    background-color: var(--bs-list-group-bg) !important;
    color: var(--bs-list-group-color) !important;
    z-index: auto !important;
}

/* Active items must keep their active-state colours, even on hover. */
.ro-list-item.list-group-item.active:hover,
.ro-list-item.list-group-item.active:focus {
    background-color: var(--bs-list-group-active-bg) !important;
    color: var(--bs-list-group-active-color) !important;
    border-color: var(--bs-list-group-active-border-color) !important;
}

/* Read-only Quill replacement: identical layout to the active editor, but no toolbar
   and the content is just rendered HTML (not contenteditable). */
.rich-text-editor-readonly {
    border: 1px solid var(--bs-border-color);
    border-radius: 0.375rem;
    background-color: var(--bs-body-bg);
    overflow: auto;
}

/* Editor on the AGB/Datenschutz/Impressum tabs: cap the height so the
   action buttons below and the page footer stay visible without scrolling.
   Budget accounts for: topbar (~3.5rem), article padding, page-title row
   with Versionen button (~4.5rem), info alert (~5rem), Quill toolbar (~2.5rem),
   button row (~3rem) and app-footer (~2rem). */
.terms-editor-viewport .ql-editor {
    max-height: calc(100vh - 28rem);
    min-height: 12rem;
}

/* Inline preview shown next to the editor. Same scroll budget so the two
   columns line up. */
.legal-split .legal-preview {
    border: 1px solid var(--bs-border-color);
    border-radius: 0.375rem;
    padding: 0.75rem 1rem;
    max-height: calc(100vh - 28rem);
    min-height: 12rem;
    overflow-y: auto;
    background-color: var(--bs-body-bg);
}

/* AIssistant path picker: two large clickable cards inside the choice modal. */
.ai-path-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    text-align: center;
    padding: 1.5rem 1rem;
    background-color: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: var(--transition-colors), box-shadow var(--duration-base) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.ai-path-card:hover,
.ai-path-card:focus {
    border-color: var(--bs-primary);
    background-color: var(--selected-bg);
    box-shadow: var(--shadow-md);
    outline: none;
}

.ai-path-card:active {
    transform: scale(0.99);
}

.ai-path-card-icon {
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 50%;
    background-color: var(--bs-primary);
    color: var(--white);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 0.75rem;
}

.ai-path-card-icon .material-symbols-outlined {
    font-size: 2rem;
}

.ai-path-card-title {
    font-weight: 600;
    font-size: 1.1rem;
    margin-bottom: 0.5rem;
}

.ai-path-card-description {
    color: var(--bs-secondary-color);
    font-size: 0.95rem;
    line-height: 1.4;
}

/* Revise-mode item picker: list of existing items with checkboxes. Scrolling is
   handled by the outer right panel — no inner scrollbar. */
.revise-item-list {
    border: 1px solid var(--bs-border-color);
    border-radius: 0.375rem;
    padding: 0.5rem;
    background-color: var(--bs-body-bg);
}

.revise-item-row {
    display: flex;
    align-items: flex-start;
    padding: 0.25rem 0;
    gap: 0.5rem;
    cursor: pointer;
    padding-left: 0;
    margin-bottom: 0;
    min-height: auto;
}

.revise-item-row .form-check-input {
    float: none;
    margin: 0.2rem 0 0 0;
    flex-shrink: 0;
}

.revise-item-row + .revise-item-row {
    border-top: 1px solid var(--bs-border-color);
    margin-top: 0.25rem;
    padding-top: 0.5rem;
}

.revise-item-number {
    font-weight: 600;
    margin-right: 0.25rem;
}

.revise-item-preview {
    color: var(--bs-body-color);
    font-size: 0.9rem;
    line-height: 1.3;
}

/* =================================================================================
   Tree components — shared chrome for TreeEditor (management) and TreePicker (asset
   assignment). Connectors, toggle, indent and node-name layout live here so both
   trees look identical across the app. Component-specific state styles (selected,
   assigned, drag-over, grouping, readonly) stay in the scoped *.razor.css files.
   ================================================================================= */

.tree-node {
    cursor: pointer;
}

.tree-node-header {
    display: flex;
    align-items: center;
    padding: 0.1rem 0;
    gap: 0.1rem;
}

.tree-node-header:hover .tree-node-name {
    background-color: var(--bs-light);
}

.tree-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.4rem;
    height: 1.4rem;
    cursor: pointer;
    flex-shrink: 0;
    /* Mask the spine where it would otherwise cross the visible glyph: the spine line
       runs through the toggle column (Windows-Explorer-style) and the white background
       hides it inside the toggle so only the parts above and below remain visible. */
    background-color: var(--bs-white);
    z-index: 1;
    position: relative;
}

.tree-toggle i {
    font-size: 0.9rem;
}

.tree-toggle-placeholder {
    display: inline-block;
    width: 1.4rem;
    height: 1.4rem;
    flex-shrink: 0;
}

.tree-node-name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 0.225rem 0.4rem;
    border-radius: 0.25rem;
    transition: background-color 0.15s;
}

/* Tree connectors — Windows-Explorer-style. Each child sits inside a `.tree-connector`
   wrapper. The wrapper holds an "indent strip" on its left (`padding-left`) where the
   spine and the horizontal branch are drawn; the node content (toggle + name) flows
   to the right of that strip, so the branch visibly meets the toggle's left edge
   instead of being painted underneath it. */

.tree-children {
    /* Each nesting level adds this padding on top of the parent's content, so every
       deeper child sits one indent step further right without needing per-level
       overrides for spine/toggle/branch positions. */
    padding-left: 1.75rem;
}

.tree-connector {
    position: relative;
}

/* Vertical spine: shared between all siblings, drawn in the connector's indent strip.
   The negative `top` pulls the spine of the first sibling up into the parent's header
   area so it visibly connects to the bottom of the parent's toggle. For non-first
   siblings the same offset just overlaps the previous sibling's spine — both lines
   share the same X column, so the overlap is invisible. */
.tree-connector::after {
    content: '';
    position: absolute;
    /* Centered on the toggle: toggle sits at the connector's left edge (0) and is
       1.4rem wide, so the toggle's horizontal center — and the spine — is at 0.7rem. */
    left: 0.7rem;
    top: -0.4rem;
    bottom: 0;
    border-left: 1px solid var(--bs-secondary);
}


/* Horizontal branch from the spine to where the visible content starts. For a node
   with a toggle, the toggle span is 1.4rem wide but the [+]/[-] glyph itself is only
   ~0.9rem and centered inside that span, so the visible glyph sits ~0.25rem in from
   the span's left edge. The branch extends into the toggle span up to the glyph's
   left edge instead of stopping at the (invisible) span edge — otherwise it looks
   like the line and toggle are floating apart. The toggle has no background, so the
   line shows through the empty padding next to the glyph. */
/* Non-leaf children: the toggle is pulled onto the spine (see the .tree-toggle rule
   further down) so the toggle itself is the visible connection point — no horizontal
   branch needed. */
.tree-connector::before {
    content: none;
}

/* Leaf children have no toggle on the spine, so a horizontal branch still reaches
   from the spine to the icon. The branch sits a touch lower because there's no
   toggle box to anchor against on this row. */
.tree-connector-leaf::before {
    content: '';
    position: absolute;
    /* Starts on the spine line so the L-shape stays clean. */
    left: 0.7rem;
    top: 1.4rem;
    width: 1.2rem;
    border-top: 1px solid var(--bs-secondary);
}

/* TreePicker rows are shorter than TreeEditor rows (smaller font, no permission
   icon in the name), so the leaf branch needs to sit higher and end earlier to
   land at the row's visible content. */
.tree-picker-scroll .tree-connector-leaf::before {
    top: 1rem;
    width: 0.9rem;
}

/* Consumer-side indent: in the Topics/StructuralTraits column layout the badge sits
   directly above the tree. Indenting the tree by ~0.75rem nudges the root spine
   (at 0.7rem inside the tree) to roughly the horizontal centre of the badge above.
   The tree component itself stays at zero outer padding — the indent comes from
   the page's container. */
.topics-overview-col .tree-view,
.trait-picker-col .tree-picker-scroll {
    padding-left: 0.25rem;
}



/* Last sibling: spine stops at the branch level so siblings below don't get a
   stray vertical line. */
.tree-connector-last::after {
    bottom: auto;
    /* Spine starts at top: -0.4rem and must reach the branch at top: 1.25rem, so the
       total height is 1.25rem + 0.4rem. */
    height: 1.65rem;
}

/* Leaf branches sit a touch lower (top: 1.4rem); the last-sibling spine for a leaf
   needs to reach that lower branch level. */
.tree-connector-last.tree-connector-leaf::after {
    height: 1.8rem;
}

/* =================================================================================
   Paper-import review modal — redesigned 2-column layout
   Left column: vertical list of SurveyItemCards (each pre-filled with the recognized
   or teacher-corrected answer; teacher corrections happen directly in the card).
   Right column: parallel list of crops from the stitched sheet image (one per item),
   so the teacher sees the original handwritten/drawn answer next to the rendered card.
   Both columns scroll independently but are kept in sync via initPaperReviewSyncScroll.
   ================================================================================= */

.paper-review-body {
    /* Single scroll container; one block per survey item flows vertically inside.
       Each block has its own coloured header bar above two side-by-side cards
       (rendered item left, original-paper crop right). */
    overflow-y: auto;
    min-height: 0;
}

/* Outer scroll container; one row per survey item flows vertically inside. */
.paper-review-list {
    padding: 0.5rem;
}

/* Per-item row: 2-column grid where the header label ("A1", "A2") and the
   optional uncertainty note span both columns above the cards. The left-side
   SurveyItemCard and the right-side original-paper card sit as siblings in the
   *card row only*, so align-items:stretch makes them exactly the same height
   and they start at the same Y — the label/note above doesn't count toward
   card height. */
.paper-review-item-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 1rem;
    row-gap: 0.5rem;
    align-items: stretch;
    margin-bottom: 1.5rem;
}

/* An answer to an item whose flow does not apply to this sheet: shown, but dimmed,
   because closing the sheet drops it (docs/Flows.md, section 7). */
.paper-review-item-row.paper-review-discarded {
    opacity: 0.55;
}

.paper-review-card-header,
.paper-review-card-note {
    grid-column: 1 / -1;
}

/* Wrapper card on the right column that mirrors the SurveyItemCard look-and-feel
   on the left. The crop image sits inside this card so the original-paper region
   visually reads as the right-column counterpart to the rendered item card. */
.paper-review-original-card {
    background-color: var(--bs-white);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    /* Crop fills the card edge to edge on left/right/bottom; 24px top padding
       gives the original a comfortable breathing space so the printed content
       doesn't kiss the upper card border. */
    padding: 24px 0 0 0;
    overflow: hidden;
    /* Top-aligned so the original-paper region starts at exactly the same Y as
       the rendered question on the left card. If the left card is taller, the
       extra space appears below the crop, not above it. */
    display: flex;
    align-items: flex-start;
    justify-content: center;
}

.paper-review-card-wrap {
    /* Sits in the left column of the per-item grid row; align-items:stretch on
       the row makes this card match the original-paper card's height. */
    display: flex;
    flex-direction: column;
}

.paper-review-card-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    background-color: var(--primary-light);
    border-radius: var(--radius-sm);
    font-weight: 600;
    color: var(--primary-dark);
}

.paper-review-card-header .paper-review-status {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
}

.paper-review-card-header .paper-review-status .material-symbols-outlined {
    font-size: 0.9rem;
}

.paper-review-card-note {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
    margin-bottom: 0.5rem;
}

/* Right column: one tile per item, each showing a Y-window of the stitched sheet PNG.
   Height + image offset are set by initPaperReviewCrops after the image has loaded. */
.paper-review-crop {
    /* Inner crop window — the SVG-like clipping for the stitched-sheet PNG.
       Background and border now live on the wrapper card (.paper-review-original-card),
       so the crop itself is just a transparent positioning context. */
    position: relative;
    width: 100%;
    overflow: hidden;
    scroll-margin-top: 0.5rem;
    /* Default placeholder height while the layout map + image load — gives the
       spinner overlay something to fill. Removed once the crop is .loaded so the
       computed image height takes over (which may be smaller than this). */
    min-height: 6rem;
}

.paper-review-crop.loaded {
    min-height: 0;
}

.paper-review-crop img {
    /* Positioned by JS after load — fall-back values keep the layout stable
       while the image is still being fetched. */
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: auto;
    user-select: none;
    pointer-events: none;
}

/* Loading overlay: full-card white surface with a centered spinner. Visible
   until initPaperReviewCrops has positioned and sized the image, at which
   point it adds .loaded to the crop and the spinner fades out. */
.paper-review-crop-spinner {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--bs-white);
    transition: opacity 0.15s ease-out;
}

.paper-review-crop.loaded .paper-review-crop-spinner {
    opacity: 0;
    pointer-events: none;
}

.paper-review-empty {
    color: var(--bs-secondary-color);
    font-style: italic;
    padding: 1rem;
}

/* Conversation stream — every bubble is left-aligned and (on tablet+) caps at 50%
   of the row. Incoming and outgoing only differ by background colour so the agent
   can still tell direction at a glance. */
.conversation-stream {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 0.5rem 0;
}

.conversation-row {
    display: flex;
    width: 100%;
    justify-content: flex-start;
}

.conversation-bubble {
    width: 100%;
    padding: 0.6rem 0.9rem 0.7rem 0.9rem;
    border-radius: 0.9rem;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
    color: var(--bs-body-color);
}

/* Desktop + Tablet: cap at 50% so long bodies don't span the whole content column.
   On mobile (< 768px) the bubble fills the row. */
@media (min-width: 768px) {
    .conversation-bubble {
        width: 50%;
    }
}

.conversation-row.in .conversation-bubble {
    background-color: #f1f3f5;
}

.conversation-row.out .conversation-bubble {
    background-color: #e6f0ea;
}

.conversation-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    color: var(--bs-secondary-color);
    margin-bottom: 0.35rem;
}

.conversation-from {
    font-weight: 600;
    color: var(--bs-body-color);
}

.conversation-time {
    flex-grow: 1;
}

/* The other language version of a message: the toggle in the bubble's header and the
   block it unfolds. Folded away by default — the team reads its own language. */
.conversation-language-toggle {
    gap: 0.2rem;
    padding: 0;
    font-size: var(--fs-text-xs);
    text-decoration: none;
    color: var(--bs-secondary-color);
}

.conversation-language-toggle:hover {
    color: var(--primary);
}

.conversation-language-toggle .material-symbols-outlined {
    font-size: 1rem;
}

.conversation-language-name {
    white-space: nowrap;
}

.conversation-original {
    margin-top: 0.6rem;
    padding-top: 0.6rem;
    border-top: 1px dashed var(--bs-border-color);
}

.conversation-original .support-message-text {
    white-space: pre-wrap;
    font-family: inherit;
    margin: 0;
}

.conversation-bubble--clickable {
    cursor: pointer;
    transition: box-shadow 0.15s ease, transform 0.05s ease;
}

.conversation-bubble--clickable:hover {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
}

.conversation-bubble--clickable:active {
    transform: translateY(1px);
}

.conversation-editor-original {
    max-height: 30vh;
    overflow-y: auto;
    padding: 0.5rem 0.75rem;
    background-color: #f8f9fa;
    border-radius: 0.5rem;
}

.conversation-body {
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

.conversation-attachments {
    margin-top: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}

/* Modal viewport clamp — keep every modal smaller than the screen so the footer
   (Cancel/Save) is always reachable. Header + footer stay pinned; only the body
   scrolls when content overflows. Per CLAUDE.md §5.6 modals sit at the top, not
   centered, so we anchor the top margin and let the available height drive the
   layout. */
.modal-dialog {
    max-height: calc(100vh - 2rem);
    margin-top: 1rem;
    margin-bottom: 1rem;
    display: flex;
    flex-direction: column;
}

.modal-dialog .modal-content {
    max-height: 100%;
    overflow: hidden;
}

.modal-dialog .modal-body {
    overflow-y: auto;
}

/* ==========================================================================
   Toast
   ========================================================================== */

#app-toast-container {
    position: fixed;
    bottom: 1.5rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 2000;
    display: flex;
    flex-direction: column-reverse;
    align-items: center;
    gap: 0.5rem;
    pointer-events: none;
}

.app-toast {
    background-color: var(--bs-dark);
    color: var(--white);
    padding: 0.5rem 1rem;
    border-radius: 0.375rem;
    font-size: 0.9rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.2);
    opacity: 0;
    transform: translateY(0.5rem);
    transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out;
}

.app-toast-visible {
    opacity: 1;
    transform: translateY(0);
}

/* AI model chat-test result panel (Administration → AI → model edit) */
.ai-test-result {
    margin-top: 0.5rem;
    padding: 0.75rem 1rem;
    border-radius: 0.5rem;
    white-space: pre-wrap;
    word-break: break-word;
}

.ai-test-result--ok {
    background-color: var(--selected-bg);
}

.ai-test-result--fail {
    background-color: var(--bs-danger-bg-subtle);
}

/* ==========================================================================
   Language UI — flag chip, footer pill, picker row-list, admin overview
   (adapted from the SIDAN2 layout, rendered with FeedbackSchool tokens)
   ========================================================================== */

/* Round flag chip (shared Flag component) */
.flag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background-color: var(--surface-subtle);
    box-shadow: inset 0 0 0 1px var(--gray-border-light);
}

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

.flag-lg {
    width: 2rem;
    height: 2rem;
}

.flag-sm {
    width: 1.15rem;
    height: 1.15rem;
}

.flag .flag-globe {
    font-size: 1rem;
    color: var(--nav-icon);
}

.flag-lg .flag-globe {
    font-size: 1.3rem;
}

/* Footer pill trigger */
.lang-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.25rem 0.6rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-pill);
    background-color: var(--surface);
    color: var(--gray-dark);
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lang-pill:hover {
    background-color: var(--surface-subtle);
    border-color: var(--primary);
}

.lang-pill-code {
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.03em;
}

.lang-pill .material-symbols-outlined {
    font-size: 1.2rem;
    color: var(--nav-icon);
}

.lang-pill-spinner {
    width: 1rem;
    height: 1rem;
    border-width: 2px;
    color: var(--primary);
}

/* Der Kreisel im Hinweis: auf der Höhe der ersten Zeile, nicht in ihrer Mitte. */
.lang-notice-spinner {
    flex-shrink: 0;
    margin-top: 0.15rem;
    border-width: 2px;
}

/* Picker modal row-list */
.lang-row {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    padding: 0.6rem 0.4rem;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background-color 0.12s ease;
}

.lang-row:hover {
    background-color: var(--surface-subtle);
}

.lang-row.is-active {
    background-color: var(--selected-bg);
}

.lang-row.is-add {
    margin-top: 0.35rem;
    border-top: 1px solid var(--gray-border-light);
    padding-top: 0.85rem;
    color: var(--primary-dark);
    font-weight: 600;
}

.lang-row-text {
    flex: 1;
    min-width: 0;
}

.lang-row-name {
    font-weight: 600;
    color: var(--gray-dark);
    line-height: 1.2;
}

.lang-row-native {
    font-size: 0.85rem;
    color: var(--gray-text-secondary);
}

.lang-row-spinner,
.lang-row-globe {
    width: 2rem;
    height: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.lang-row-spinner {
    color: var(--primary);
    border-width: 2px;
}

.lang-row-globe {
    color: var(--nav-icon);
}

.lang-row .check {
    color: var(--primary);
}

.lang-row .add-icon {
    color: var(--primary);
}

.lang-search {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding-bottom: 0.75rem;
}

.lang-search .material-symbols-outlined {
    color: var(--nav-icon);
}

.lang-list {
    max-height: 22rem;
    overflow-y: auto;
}

.lang-flash {
    padding: 1rem 0.4rem;
    color: var(--gray-text-secondary);
    font-style: italic;
}

/* Admin languages overview — active list + available grid */
.admin-languages-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1.5rem;
}

.admin-language-row {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    padding: 0.6rem 0.85rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background-color: var(--surface);
}

.admin-language-row-meta {
    flex: 1;
    min-width: 0;
}

.admin-language-row-name {
    font-weight: 600;
    color: var(--gray-dark);
    line-height: 1.2;
}

.admin-language-row-native {
    font-size: 0.85rem;
    color: var(--gray-text-secondary);
}

.admin-language-row-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

.admin-languages-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 0.5rem;
}

.admin-language-pill {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background-color: var(--surface);
    cursor: pointer;
    text-align: left;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}

.admin-language-pill:hover:not(:disabled) {
    background-color: var(--surface-subtle);
    border-color: var(--primary);
}

.admin-language-pill:disabled {
    cursor: default;
    opacity: 0.7;
}

.admin-language-pill-name {
    flex: 1;
    min-width: 0;
    font-weight: 600;
    color: var(--gray-dark);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.admin-language-pill-key {
    font-size: 0.8rem;
    color: var(--gray-text-secondary);
    flex-shrink: 0;
}

.admin-language-spinner {
    width: 2rem;
    height: 2rem;
    color: var(--primary);
    border-width: 2px;
    flex-shrink: 0;
}

.admin-language-pill .admin-language-spinner {
    width: 1.15rem;
    height: 1.15rem;
}

/* ============================================================================
   Public site pages (Homepage editor)

   Styles for the editorially maintained public pages. Prefix "site-".
   Deliberately global rather than scoped: scoped CSS does not reach child
   components, and every block type is its own component — the same reason the
   survey item styles use the "si-" prefix here instead of scoped files.

   Layout comes from named variants only, never from values an editor could
   enter, so a page cannot be made to look broken from the editor.
   ============================================================================ */

/* Der Grund der oeffentlichen Seite ist die Markenfarbe, durchgaengig. Ein Block
   bekommt nur dann eine eigene Flaeche, wenn er sie ausdruecklich verlangt —
   sonst steht der Markengrund einfach stehen, auch unterhalb des letzten Blocks.
   Deshalb faerbt die Seite und nicht der einzelne Block. */
.site-page {
    width: 100%;
    background-color: var(--site-ground);
    color: var(--white);
}

/* ── In-page jump navigation ───────────────────────────────────────────── */

.site-nav {
    position: sticky;
    top: 0;
    z-index: 10;
    background-color: var(--surface);
    border-bottom: 0.0625rem solid var(--gray-border-light);
    backdrop-filter: blur(0.5rem);
}

/* Der Hamburger existiert nur auf schmalen Schirmen; auf breiten stehen die
   Sprunglinks wie gehabt in der Leiste. */
.site-nav-burger {
    display: none;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border: none;
    border-radius: var(--radius-md);
    background: none;
    color: var(--gray-dark);
    cursor: pointer;
}

.site-nav-burger:hover {
    background-color: var(--surface-sunk);
}

@media (max-width: 62rem) {
    .site-nav-burger {
        display: flex;
        align-items: center;
        justify-content: center;
    }

    /* Zusammengeklappt zeigt die Leiste nur Hamburger und Anmelden. Aufgeklappt
       stehen die Sprunglinks als Liste unter der Zeile, jeder Link eine volle,
       gut antippbare Zeile. */
    .site-nav-inner {
        flex-wrap: wrap;
    }

    /* Mit .site-nav davor, damit die Regeln die spaeter definierte Basisregel
       von .site-nav-links unabhaengig von der Reihenfolge ueberstimmen. */
    .site-nav .site-nav-links {
        display: none;
    }

    .site-nav .site-nav-links.site-nav-links-open {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        order: 3;
        width: 100%;
        padding-top: 0.25rem;
    }

    .site-nav .site-nav-links-open .site-nav-link {
        padding: 0.75rem 0.25rem;
        border-top: 0.0625rem solid var(--gray-border-light);
    }

    /* Rechtliches am Ende des aufgeklappten Menues: eine gedaempfte, kleinere
       Zeile, durch die Trennlinie klar von den Sprunglinks abgesetzt. */
    .site-nav .site-nav-links-open .site-nav-legal {
        display: flex;
        align-items: center;
        gap: 1.25rem;
        margin-top: 0.25rem;
        padding: 0.75rem 0.25rem;
        border-top: 0.0625rem solid var(--gray-border-light);
    }
}

/* Auf breiten Schirmen steht Rechtliches in der Fusszeile; im Menue waere es
   doppelt. Sichtbar wird die Zeile nur im aufgeklappten Mobilmenue. */
.site-nav-legal {
    display: none;
}

.site-nav-legal-link {
    color: var(--text-subtle);
    font-size: var(--fs-text-xs);
    opacity: 0.75;
    transition: var(--transition-colors);
}

.site-nav-legal-link:hover,
.site-nav-legal-link:focus {
    color: var(--primary);
    opacity: 1;
}

.site-nav-inner {
    max-width: 75rem;
    margin: 0 auto;
    padding: 0.75rem 1.5rem;
}

.site-nav-link {
    color: var(--text-subtle);
    font-size: var(--font-size-sm);
    font-weight: 500;
    transition: var(--transition-colors);
}

.site-nav-link:hover,
.site-nav-link:focus {
    color: var(--primary);
}

/* ── Header menu across pages ──────────────────────────────────────────── */

.site-main-nav {
    border-bottom: 0.0625rem solid var(--gray-border-light);
    background-color: var(--surface);
}

.site-main-nav-inner {
    max-width: 75rem;
    margin: 0 auto;
    padding: 1rem 1.5rem;
}

.site-main-nav-link {
    color: var(--black);
    font-weight: 600;
    transition: var(--transition-colors);
}

.site-main-nav-link:hover,
.site-main-nav-link:focus,
.site-main-nav-link-current {
    color: var(--primary);
}

/* Submenu opens on hover and on keyboard focus, so it is reachable without a
   pointer. Only one level deep by design. */
.site-nav-group {
    position: relative;
}

.site-nav-chevron {
    font-size: 1.1rem;
}

.site-nav-submenu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 20;
    min-width: 12rem;
    padding: 0.5rem 0;
    border-radius: var(--radius-md);
    border: 0.0625rem solid var(--gray-border-light);
    background-color: var(--surface);
    box-shadow: var(--shadow-md);
    display: none;
}

.site-nav-group:hover .site-nav-submenu,
.site-nav-group:focus-within .site-nav-submenu {
    display: block;
}

/* Angetippt statt ueberfahren: der Chevron-Knopf haelt das Untermenue offen, damit
   es auch ohne Hover (Tablet, Handy) erreichbar ist. */
.site-nav-submenu-open {
    display: block;
}

.site-nav-toggle {
    padding: 0;
    border: none;
    background: none;
    color: inherit;
    cursor: pointer;
}

.site-nav-submenu-link {
    display: block;
    padding: 0.5rem 1rem;
    color: var(--black);
    transition: var(--transition-colors);
}

.site-nav-submenu-link:hover,
.site-nav-submenu-link:focus {
    background-color: var(--selected-bg);
    color: var(--primary-dark);
}

/* ── Breadcrumbs ───────────────────────────────────────────────────────── */

.site-breadcrumbs-inner {
    max-width: 75rem;
    margin: 0 auto;
    padding: 1rem 1.5rem 0;
    font-size: var(--font-size-sm);
}

.site-breadcrumb-link {
    color: var(--text-subtle);
}

.site-breadcrumb-link:hover {
    color: var(--primary);
}

.site-breadcrumb-separator {
    color: var(--gray-medium);
}

.site-breadcrumb-current {
    color: var(--black);
    font-weight: 600;
}

/* ── Block frame ───────────────────────────────────────────────────────── */

/* Die Luft zwischen zwei Bloecken. Sie steht einmal hier und gilt fuer die ganze
   Seite: der Abstand ueber einer Ueberschrift ist immer das Polster des Blocks, in
   dem sie steht, und der des Blocks darueber. */
.site-block {
    padding: 3rem 1.5rem;
}

/* Marke und Spruch am Seitenanfang gehoeren zusammen.

   Als zwei Bloecke stehen zwischen ihnen sonst zweimal 4rem Polster, und der
   Auftakt der Seite zerfaellt in zwei Teile, die nichts miteinander zu tun
   scheinen. Sie werden darum zusammengerueckt, sobald der Kopf genau daraus
   besteht: Logo, direkt gefolgt vom Hero. */
.site-block-logo:first-child {
    padding-bottom: 1rem;
}

.site-block-logo + .site-block-hero {
    padding-top: 0;
}

.site-block-inner,
.site-hero-inner {
    max-width: 75rem;
    margin: 0 auto;
}

/* ── Halbbreite Bloecke ────────────────────────────────────────────────────
   Der Block-Container ist auf breiten Schirmen ein zweispaltiges Raster:
   normale Bloecke belegen beide Spalten, halbbreite eine. Zwei
   aufeinanderfolgende halbbreite Bloecke stehen dadurch nebeneinander,
   ohne dass das Markup sie paaren muss. Unterhalb der Desktop-Breite
   greift das Raster nicht und alles stapelt wie gehabt. */
@media (min-width: 62rem) {
    .site-blocks {
        display: grid;
        grid-template-columns: 1fr 1fr;
    }

    .site-blocks > * {
        grid-column: span 2;
    }

    .site-blocks > .site-block-half {
        grid-column: span 1;
    }

    /* Die Layoutlinien laufen durch: der Inhalt der linken Haelfte beginnt an
       derselben senkrechten Linie wie der Inhalt der vollen Bloecke, der der
       rechten endet an derselben. Rechnung: volle Inhaltsspalte = min(75rem,
       100vw - 3rem), mittig. Halbe Sektion = 50vw mit 1.5rem Polster. Ein
       Inhalt von hoechstens 36rem (37.5rem minus Polster), zur Mitte hin
       buendig gestellt, trifft die Linie bei jeder Breite exakt; zwischen den
       Haelften bleiben 3rem Rinne. margin-inline statt links/rechts, damit
       RTL-Seiten von selbst spiegeln. */
    .site-block-half .site-block-inner,
    .site-block-half .site-hero-inner,
    .site-block-half .site-mediatext-inner {
        max-width: 36rem;
    }

    .site-block-half-start .site-block-inner,
    .site-block-half-start .site-hero-inner,
    .site-block-half-start .site-mediatext-inner {
        margin-inline: auto 0;
    }

    .site-block-half-end .site-block-inner,
    .site-block-half-end .site-hero-inner,
    .site-block-half-end .site-mediatext-inner {
        margin-inline: 0 auto;
    }

    /* Dieselbe Paarung in der Desktop-Vorschau des Editors. In der Tablet- und
       Handy-Vorschau stapeln die Bloecke, wie sie es auf dem Geraet taeten. */
    .homepage-preview:not(.homepage-preview-tablet):not(.homepage-preview-phone) {
        display: grid;
        grid-template-columns: 1fr 1fr;
    }

    .homepage-preview:not(.homepage-preview-tablet):not(.homepage-preview-phone) > .homepage-preview-block {
        grid-column: span 2;
    }

    .homepage-preview:not(.homepage-preview-tablet):not(.homepage-preview-phone) > .homepage-preview-block-half {
        grid-column: span 1;
    }
}

/* In der halben Breite ist neben dem Text kein Platz fuer eine halbe Spalte
   Bild: die Illustration rueckt als kleine Kachel ueber den Titel, dieselbe
   Gestalt wie in den Feature-Karten. */
.site-block-half .site-mediatext-inner {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
}

.site-block-half .site-mediatext-media {
    order: -1;
    flex: 0 0 auto;
}

.site-block-half .site-mediatext-media .site-media-icon {
    /* Ueberschreibt die grosse Glyphen-Kachel weiter unten (width 100%,
       min-height 14rem), die fuer die volle Blockbreite gedacht ist. */
    width: 3.5rem;
    height: 3.5rem;
    min-height: 0;
    margin-bottom: 1rem;
}

.site-block-half .site-mediatext-media .site-media-icon .material-symbols-outlined,
.site-block-half .site-mediatext-media .site-media-icon .ai-mark {
    font-size: 2rem;
}

/* Standard heisst: keine eigene Flaeche. Der Markengrund der Seite bleibt stehen. */
.site-bg-default {
    background-color: transparent;
}

/* Die einzige helle Flaeche. Fuer Abschnitte, die viel Text tragen und dafuer
   ruhigen Grund brauchen. */
.site-bg-muted {
    background-color: var(--surface-subtle);
    color: var(--gray-dark);
}

/* Ausdruecklich die Markenfarbe. Sieht auf Standardgrund gleich aus, macht aber
   einen Unterschied zwischen zwei hellen Abschnitten. */
.site-bg-accent {
    background-color: var(--primary);
    color: var(--white);
}

/* ── Grund und Schrift ─────────────────────────────────────────────────────
   Die Textfarbe kommt ueber Vererbung vom Grund, nicht aus einer Regel je
   Bausteinart. Nur die helle Flaeche muss widersprechen — und weil sie das per
   Klassenspezifitaet nicht kann, steht sie hier jeweils hinter dem Markengrund.
   Reihenfolge ist also Absicht, nicht Zufall. */

.site-headline,
.site-body {
    color: inherit;
}

.site-subline {
    color: inherit;
    /* Deutlich zurueckgenommen: auf dem Markengrund traegt allein die Deckkraft
       den Unterschied zwischen Einleitung und Fliesstext, und bei 0.85 war er
       kaum zu sehen. Auf hellen Flaechen uebernimmt --text-subtle (unten). */
    opacity: 0.72;
}

.site-bg-muted .site-subline {
    color: var(--text-subtle);
    opacity: 1;
}

/* Ein Knopf in der Markenfarbe auf der Markenfarbe waere unsichtbar. Er wird
   umgedreht statt neu eingefaerbt.
   Als richtige Eigenschaften geschrieben, nicht als --bs-*-Variablen: die waren
   Bootstraps und erreichen den Knopf nicht mehr (CLAUDE.md 4.6). */
.site-page .btn-primary {
    color: var(--primary);
    background-color: var(--white);
    border-color: var(--white);
}

/* Beim Ueberfahren ein deckender Weichton. Ein durchscheinender wie
   --primary-bg-subtle laege als 10-Prozent-Gruen auf Gruen und liesse den Knopf
   samt Beschriftung im Grund verschwinden. */
.site-page .btn-primary:hover:not(:disabled):not(.disabled) {
    color: var(--primary-dark);
    background-color: var(--primary-tint);
    border-color: var(--primary-tint);
}

.site-page .btn-secondary {
    color: var(--white);
    background-color: transparent;
    border-color: var(--white);
}

.site-page .btn-secondary:hover:not(:disabled):not(.disabled) {
    color: var(--white);
    background-color: var(--overlay-white-subtle);
    border-color: var(--white);
}

.site-page .site-link-text {
    color: var(--white);
    text-decoration: underline;
}

.site-page .site-placeholder {
    color: var(--overlay-white-half);
}

.site-page .site-divider {
    border-color: var(--overlay-white-subtle);
}

/* Auf der hellen Flaeche gelten wieder die gewohnten Knoepfe und Verweise. */
.site-bg-muted .btn-primary {
    color: var(--primary-ink);
    background-color: var(--primary);
    border-color: var(--primary);
}

.site-bg-muted .btn-primary:hover:not(:disabled):not(.disabled) {
    color: var(--primary-ink);
    background-color: var(--primary-hover);
    border-color: var(--primary-hover);
}

.site-bg-muted .btn-secondary {
    color: var(--white);
    background-color: var(--secondary);
    border-color: var(--secondary);
}

.site-bg-muted .btn-secondary:hover:not(:disabled):not(.disabled) {
    color: var(--white);
    background-color: var(--secondary-hover);
    border-color: var(--secondary-hover);
}

.site-bg-muted .site-link-text {
    color: var(--link-color);
    text-decoration: none;
}

.site-bg-muted .site-placeholder {
    color: var(--gray-medium);
}

.site-bg-muted .site-divider {
    border-color: var(--gray-border-light);
}

/* ── Shared text elements ──────────────────────────────────────────────── */

.site-headline {
    font-size: var(--font-size-xxl);
    font-weight: 700;
    line-height: 1.2;
    margin-bottom: 1rem;
}

.site-block-hero .site-headline {
    font-size: 3rem;
}

.site-subline {
    font-size: var(--font-size-lg);
    line-height: 1.6;
    margin-bottom: 1.5rem;
}

.site-body {
    line-height: 1.7;
}

.site-body > :last-child {
    margin-bottom: 0;
}

.site-body-columns {
    column-count: 2;
    column-gap: 3rem;
}

/* Marks a slot that has no content yet. Only ever rendered inside the editor
   preview, so an empty block stays visible and selectable instead of
   collapsing into something there is no way to click. */
.site-placeholder {
    color: inherit;
    opacity: 0.7;
    font-style: italic;
}

.site-divider {
    max-width: 75rem;
    margin: 0 auto;
    border-color: var(--gray-border-light);
    opacity: 1;
}

/* ── Links and buttons ─────────────────────────────────────────────────── */

.site-links {
    margin-top: 1.5rem;
}

.site-link-text {
    color: var(--link-color);
    font-weight: 500;
    align-self: center;
}

.site-link-text:hover {
    color: var(--link-hover-color);
}

/* ── Media ─────────────────────────────────────────────────────────────── */

.site-media-image {
    margin: 0;
}

.site-media-image img {
    width: 100%;
    height: auto;
    max-width: 100%;
    border-radius: var(--radius-lg);
    display: block;
}

.site-media-image figcaption {
    margin-top: 0.5rem;
    font-size: var(--font-size-sm);
}

.site-media-icon {
    width: 3.5rem;
    height: 3.5rem;
    border-radius: var(--radius-md);
    background-color: var(--overlay-white-subtle);
    border: 0.0625rem solid var(--overlay-white-medium);
    margin-bottom: 1rem;
}

/* On a light ground the tile goes back to the pale green it was designed as.
   Both grounds occur on the same page, so the colour has to follow the ground
   rather than be fixed once. */
.site-bg-muted .site-media-icon,
.site-feature-card .site-media-icon,
.site-linkcard .site-media-icon,
.site-price-card .site-media-icon {
    background-color: var(--primary-bg-subtle);
}

.site-media-icon .material-symbols-outlined,
.site-media-icon .ai-mark {
    font-size: 2rem;
    color: var(--white);
}

.site-bg-muted .site-media-icon .material-symbols-outlined,
.site-feature-card .site-media-icon .material-symbols-outlined,
.site-linkcard .site-media-icon .material-symbols-outlined,
.site-price-card .site-media-icon .material-symbols-outlined,
.site-bg-muted .site-media-icon .ai-mark,
.site-feature-card .site-media-icon .ai-mark,
.site-linkcard .site-media-icon .ai-mark,
.site-price-card .site-media-icon .ai-mark {
    color: var(--primary);
}

.site-media-empty {
    width: 100%;
    min-height: 8rem;
    border: 0.125rem dashed var(--gray-border-medium);
    border-radius: var(--radius-lg);
    background-color: var(--surface-sunk);
}

.site-media-empty .material-symbols-outlined {
    font-size: 2.5rem;
}

/* ── Hero ──────────────────────────────────────────────────────────────── */

.site-hero-inner {
    display: flex;
    align-items: center;
    gap: 3rem;
}

.site-hero-text {
    flex: 1 1 0;
    min-width: 0;
}

.site-hero-media {
    flex: 1 1 0;
    min-width: 0;
}

/* Uses flex order rather than float or explicit left/right positioning, so the
   sides mirror automatically under dir="rtl" without a second rule set. */
.site-block-hero.site-layout-medialeft .site-hero-text {
    order: 2;
}

.site-block-hero.site-layout-mediabelow .site-hero-inner,
.site-block-mediatext.site-layout-mediabelow .site-hero-inner {
    flex-direction: column;
}

.site-block-hero.site-layout-textonly .site-hero-inner {
    justify-content: center;
    text-align: center;
}

/* The buttons sit in their own flex row, so text-align does not reach them —
   without this the headline is centred and the button stays hard left. */
.site-block-hero.site-layout-textonly .site-links,
.site-block-hero.site-layout-mediabelow .site-links,
.site-block-cta .site-links {
    justify-content: center;
}

/* Auf dem Handy stapeln sich die Aktions-Knoepfe der grossen Bloecke in voller
   Breite: gleich breit untereinander statt linksbuendig und unterschiedlich
   lang unter zentriertem Text. Reine Textverweise bleiben davon unberuehrt,
   sie zentrieren sich ueber ihr align-self. */
@media (max-width: 36rem) {
    .site-block-hero .site-links,
    .site-block-cta .site-links,
    .site-logo-inner .site-links {
        flex-direction: column;
        align-items: stretch;
        width: 100%;
    }
}

/* ── Logo block ────────────────────────────────────────────────────────── */

/* The size steps. Each sets only a font size; the brand takes everything else
   from it in em. They are viewport-relative so the largest step still fits on a
   phone without a media query per step. */
.site-logo-small {
    font-size: clamp(1.1rem, 3vw, 1.5rem);
}

.site-logo-medium {
    font-size: clamp(1.5rem, 4.5vw, 2.25rem);
}

.site-logo-large {
    font-size: clamp(1.85rem, 6vw, 3.25rem);
}

.site-logo-extralarge {
    font-size: clamp(2.25rem, 8vw, 4.5rem);
}

/* Die Marke folgt currentColor. Auf dem Markengrund ist das Weiss, auf einer
   hellen Flaeche die Markenfarbe — dasselbe Paar wie bei den Knoepfen oben. */
.site-page .app-brand {
    color: var(--white);
}

.site-bg-muted .app-brand {
    color: var(--primary);
}

/* Subline and buttons sit back at body size — they belong to the page, not to
   the mark, and would otherwise scale up with it. */
.site-logo-subline,
.site-logo-inner .site-links {
    font-size: 1rem;
}

.site-logo-subline {
    margin-top: 1.5rem;
    margin-bottom: 0;
}

.site-logo-inner .site-links {
    justify-content: center;
}

/* ── Feature grid ──────────────────────────────────────────────────────── */

.site-feature-grid {
    margin-top: 2.5rem;
}

.site-feature-card {
    padding: 1.75rem;
    border-radius: var(--radius-lg);
    background-color: var(--surface);
    border: 0.0625rem solid var(--gray-border-light);
    box-shadow: var(--shadow-xs);
    transition: var(--transition-base);
}

.site-feature-card:hover {
    box-shadow: var(--shadow-md);
}

.site-bg-muted .site-feature-card {
    background-color: var(--surface);
}

.site-feature-title {
    font-size: var(--font-size-lg);
    font-weight: 600;
    margin-bottom: 0.5rem;
}

.site-feature-text {
    color: var(--text-subtle);
    line-height: 1.6;
    margin-bottom: 0;
}

/* ── Call to action ────────────────────────────────────────────────────── */

.site-cta-inner {
    max-width: 45rem;
}

/* ── Contact form ──────────────────────────────────────────────────────── */

.site-contact-inner {
    max-width: 45rem;
}

.site-contact-form {
    margin-top: 1.5rem;
}

.site-contact-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 1rem;
}

.site-contact-field {
    margin-bottom: 1rem;
}

/* Removed from view without display:none, so a bot that skips invisible fields
   still sees it while no person ever can. */
.site-contact-trap {
    position: absolute;
    width: 0;
    height: 0;
    opacity: 0;
    border: none;
    padding: 0;
    pointer-events: none;
}

.site-contact-legend {
    font-size: var(--font-size-sm);
    opacity: 0.75;
    margin-bottom: 1rem;
}

/* Die Datenschutz-Bestaetigung steht zwischen Nachricht und Pflichtfeld-Legende.
   Der Link darin muss auf dem Markengrund lesbar bleiben, daher erbt er die
   Textfarbe statt der Linkfarbe der Anwendung. */
.site-contact-consent {
    margin-bottom: 1rem;
}

.site-contact-consent a {
    color: inherit;
    text-decoration: underline;
}

.site-contact-send {
    margin-top: 0.5rem;
}

.site-contact-alert {
    margin-top: 1.5rem;
}

/* ── Narrow screens ────────────────────────────────────────────────────── */

@media (max-width: 62rem) {
    .site-block {
        padding: 3rem 1.25rem;
    }

    .site-hero-inner {
        flex-direction: column;
        gap: 2rem;
    }

    /* The image side no longer means anything once the block is stacked, so the
       order override has to be dropped or the text would sit below the image. */
    .site-block-hero.site-layout-medialeft .site-hero-text {
        order: 0;
    }

    .site-block-hero .site-headline {
        font-size: 2.25rem;
    }

    .site-body-columns {
        column-count: 1;
    }

    /* Name and email side by side need width; stacked they stay comfortable. */
    .site-contact-row {
        grid-template-columns: 1fr;
    }
}

/* ============================================================================
   Homepage editor (administration)

   Chrome around the live preview: the block outline on hover, the toolbar, the
   block type picker. The preview itself is rendered by the same components as
   the public page and is not restyled here — that would defeat the point.
   ============================================================================ */

.homepage-preview {
    max-height: 75vh;
    overflow-y: auto;
}

.homepage-preview-block {
    position: relative;
    cursor: pointer;
    border: 0.125rem solid transparent;
    transition: var(--transition-base);
}

/* Ueber welchem Block die Maus steht, muss auf einen Blick zu sehen sein, und
   zwar auf jedem Grund: die Abschnitte der Seite sind mal weiss, mal gruen, mal
   ein Bild. Ein zarter Rahmen in der Hausfarbe geht darin unter, deshalb der
   Warnton — er kommt sonst nirgends auf der Seite vor und kann daher mit nichts
   verwechselt werden.

   Nur der Rahmen, kein Schleier ueber dem Inhalt: die Vorschau soll die Farben
   zeigen, die der Besucher sieht. Der innere Ring liegt nach innen, weil die
   scrollende Vorschau alles beschneidet, was ueber ihre Kante hinausragt. */
.homepage-preview-block:hover {
    z-index: 1;
    border-color: var(--warning);
    box-shadow: inset 0 0 0 0.1875rem rgba(var(--warning-rgb), 0.25);
}

/* A hidden block stays in the editor so it can be switched back on, but has to
   read as inactive at a glance. */
.homepage-preview-block-hidden {
    opacity: 0.45;
}

/* Editor chrome sitting on top of the page. Opaque on purpose: half-transparent
   over a green section left the buttons floating in the content underneath. */
.homepage-block-toolbar {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    z-index: 5;
    /* Schmaler als der Block und umbruchfaehig: in der Handy-Vorschau sind Badge
       und Knoepfe zusammen breiter als der Block und liefen sonst links hinaus. */
    max-width: calc(100% - 1rem);
    flex-wrap: wrap;
    justify-content: flex-end;
    padding: 0.25rem;
    border-radius: var(--radius-md);
    background-color: var(--surface);
    box-shadow: var(--shadow-sm);
    opacity: 0;
    transition: var(--transition-base);
}

/* The preview carries the class of the public page, which restyles buttons for a
   green ground: a secondary button there is white text on a white outline. On the
   toolbar that ground does not exist, so the ordinary appearance is put back. */
.homepage-block-toolbar .btn-primary {
    color: var(--primary-ink);
    background-color: var(--primary);
    border-color: var(--primary);
}

.homepage-block-toolbar .btn-primary:hover:not(:disabled):not(.disabled) {
    color: var(--primary-ink);
    background-color: var(--primary-hover);
    border-color: var(--primary-hover);
}

.homepage-block-toolbar .btn-secondary {
    color: var(--white);
    background-color: var(--secondary);
    border-color: var(--secondary);
}

.homepage-block-toolbar .btn-secondary:hover:not(:disabled):not(.disabled) {
    color: var(--white);
    background-color: var(--secondary-hover);
    border-color: var(--secondary-hover);
}

.homepage-block-toolbar .badge {
    color: var(--fs-text);
}

.homepage-preview-block:hover .homepage-block-toolbar,
.homepage-preview-block:focus-within .homepage-block-toolbar {
    opacity: 1;
}

/* Ohne Maus gibt es kein Hover: auf Touch-Geraeten bleibt die Toolbar staendig
   sichtbar, sonst waeren Verschieben, Ausblenden und Loeschen unerreichbar. */
@media (hover: none) {
    .homepage-block-toolbar {
        opacity: 1;
    }
}

.homepage-toolbar-icon {
    font-size: 1rem;
}

.homepage-inspector {
    position: sticky;
    top: 1rem;
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
}

.homepage-item-card {
    padding: 0.75rem;
    border-radius: var(--radius-md);
    border: 0.0625rem solid var(--gray-border-light);
    background-color: var(--surface-subtle);
}

.homepage-empty-icon {
    font-size: 3rem;
}

/* ── Block type picker ─────────────────────────────────────────────────── */

.homepage-type-card {
    padding: 1rem;
    border-radius: var(--radius-md);
    border: 0.0625rem solid var(--gray-border-light);
    background-color: var(--surface);
    transition: var(--transition-base);
}

.homepage-type-card:hover {
    border-color: var(--primary);
    background-color: var(--selected-bg);
}

.homepage-type-description {
    font-size: var(--font-size-sm);
}

/* ── Icon picker ───────────────────────────────────────────────────────── */

.homepage-icon-option {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--radius-md);
    border: 0.0625rem solid var(--gray-border-light);
    background-color: var(--surface);
    transition: var(--transition-base);
}

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

.homepage-icon-option-selected {
    border-color: var(--primary);
    background-color: var(--selected-bg);
}

.homepage-icon-option .material-symbols-outlined,
.homepage-icon-option .ai-mark {
    font-size: 1.35rem;
    color: var(--primary);
}

/* Homepage editor: language switcher, translation status, glossary. */

.homepage-language-select {
    width: auto;
    min-width: 10rem;
}

.homepage-progress {
    height: 0.5rem;
    min-width: 6rem;
}

.homepage-progress-label {
    font-size: var(--font-size-sm);
    white-space: nowrap;
}

.homepage-lock-badge {
    padding: 0.1rem 0.35rem;
}

.homepage-term {
    padding: 0.4rem 0.6rem;
}

.homepage-term-remove {
    font-size: 0.5rem;
}

/* ── Public pages: image/text block and downloads ──────────────────────── */

.site-mediatext-inner {
    max-width: 75rem;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 3rem;
}

.site-mediatext-text,
.site-mediatext-media {
    flex: 1 1 0;
    min-width: 0;
}

/* Flex order rather than float, so the sides mirror by themselves under dir="rtl". */
.site-block-mediatext.site-layout-mediaright .site-mediatext-text {
    order: 0;
}

.site-block-mediatext.site-layout-medialeft .site-mediatext-text {
    order: 2;
}

.site-downloads {
    margin: 2rem 0 0;
}

.site-download {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    padding: 1rem 0;
    border-bottom: 0.0625rem solid var(--gray-border-light);
}

.site-download:last-child {
    border-bottom: none;
}

.site-download-icon {
    color: var(--white);
    flex-shrink: 0;
}

.site-bg-muted .site-download-icon {
    color: var(--primary);
}

.site-download-title {
    color: var(--link-color);
    font-weight: 600;
}

.site-download-title:hover {
    color: var(--link-hover-color);
}

.site-download-description {
    font-size: var(--font-size-sm);
    margin-top: 0.25rem;
}

@media (max-width: 62rem) {
    .site-mediatext-inner {
        flex-direction: column;
        gap: 2rem;
    }

    /* Stacked, the image side no longer means anything — without resetting the order
       the text would end up below the picture. */
    .site-block-mediatext.site-layout-medialeft .site-mediatext-text {
        order: 0;
    }
}

/* ── Homepage editor: uploads ──────────────────────────────────────────── */

/* The native file input is unusable as a control, so it is hidden inside a label
   that carries the button styling and triggers it on click. */
.homepage-upload-label {
    position: relative;
    overflow: hidden;
    cursor: pointer;
}

.homepage-upload-input {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
}

.homepage-image-preview img {
    max-width: 100%;
    max-height: 12rem;
    border-radius: var(--radius-md);
    border: 0.0625rem solid var(--gray-border-light);
}

/* Marks a field the pre-publish check will complain about, most notably a picture
   without an alternative text. */
.homepage-field-missing {
    border-color: var(--warning);
}

/* ── Homepage editor: media library ────────────────────────────────────── */

.homepage-media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
    gap: 0.75rem;
}

.homepage-media-tile {
    padding: 0;
    border: 0.125rem solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background-color: var(--surface);
    overflow: hidden;
    text-align: left;
    transition: var(--transition-base);
}

.homepage-media-tile:hover {
    border-color: var(--primary-light);
}

.homepage-media-tile-selected {
    border-color: var(--primary);
}

.homepage-media-tile img {
    width: 100%;
    height: 7rem;
    object-fit: cover;
    display: block;
}

.homepage-media-doc {
    height: 7rem;
    background-color: var(--surface-sunk);
}

.homepage-media-doc .material-symbols-outlined {
    font-size: 2.5rem;
    color: var(--primary);
}

.homepage-media-caption {
    padding: 0.5rem;
    font-size: var(--font-size-sm);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.homepage-media-name {
    font-size: var(--font-size-sm);
}

.homepage-live-hint {
    font-size: var(--font-size-sm);
}

/* Editor preview constrained to a device width. The blocks are unchanged — their own
   media queries do the work, which is the point: what breaks here breaks for real. */
.homepage-preview-tablet {
    max-width: 48rem;
    margin: 0 auto;
    border-left: 0.0625rem solid var(--gray-border-light);
    border-right: 0.0625rem solid var(--gray-border-light);
}

.homepage-preview-phone {
    max-width: 26rem;
    margin: 0 auto;
    border-left: 0.0625rem solid var(--gray-border-light);
    border-right: 0.0625rem solid var(--gray-border-light);
}

/* Die Geraetevorschau ist ein schmaler Kasten in einem breiten Fenster — die
   Breitenklassen der Bloecke haengen aber am Fenster, nicht am Kasten. Ohne die
   folgenden Regeln greift in der Handyvorschau weiter die Desktop-Aufteilung, und
   vier Preiskarten quetschen sich auf 26rem. Die Werte spiegeln, was auf einem
   Geraet dieser Breite tatsaechlich gilt: 26rem liegt unter der ersten Stufe,
   also stapelt alles; 48rem liegt darueber, also zwei nebeneinander. */
.homepage-preview-phone .row > [class*="col-"] {
    width: 100%;
}

.homepage-preview-tablet .row > [class*="col-"] {
    width: 50%;
}

/* Beide Geraetebreiten liegen unter der Desktop-Schwelle, also gilt fuer beide,
   was das Fenster sonst erst unterhalb von 62rem tut. */
.homepage-preview-phone .site-block,
.homepage-preview-tablet .site-block {
    padding: 3rem 1.25rem;
}

.homepage-preview-phone .site-hero-inner,
.homepage-preview-tablet .site-hero-inner,
.homepage-preview-phone .site-mediatext-inner,
.homepage-preview-tablet .site-mediatext-inner {
    flex-direction: column;
    gap: 2rem;
}

.homepage-preview-phone .site-block-hero.site-layout-medialeft .site-hero-text,
.homepage-preview-tablet .site-block-hero.site-layout-medialeft .site-hero-text,
.homepage-preview-phone .site-block-mediatext.site-layout-medialeft .site-mediatext-text,
.homepage-preview-tablet .site-block-mediatext.site-layout-medialeft .site-mediatext-text {
    order: 0;
}

.homepage-preview-phone .site-body-columns,
.homepage-preview-tablet .site-body-columns,
.homepage-preview-phone .site-bullets-columns,
.homepage-preview-tablet .site-bullets-columns {
    column-count: 1;
}

.homepage-preview-phone .site-contact-row,
.homepage-preview-tablet .site-contact-row {
    grid-template-columns: 1fr;
}

.homepage-preview-phone .site-steps-horizontal,
.homepage-preview-tablet .site-steps-horizontal {
    display: block;
}

.homepage-preview-phone .site-steps-horizontal .site-step,
.homepage-preview-tablet .site-steps-horizontal .site-step {
    flex-direction: row;
    padding-bottom: 2rem;
}

.homepage-preview-phone .site-steps-horizontal .site-step:last-child,
.homepage-preview-tablet .site-steps-horizontal .site-step:last-child {
    padding-bottom: 0;
}

.homepage-preview-block-dragover {
    border-color: var(--primary);
    border-style: dashed;
}

/* ── Public pages: the remaining block types ───────────────────────────── */

/* Bullet list */
.site-bullets {
    margin-top: 2rem;
    margin-bottom: 0;
}

.site-bullets-columns {
    column-count: 2;
    column-gap: 3rem;
}

.site-bullet {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.5rem 0;
    /* Keeps an entry from being split across the column break. */
    break-inside: avoid;
}

.site-bullet-icon {
    color: var(--white);
    flex-shrink: 0;
    font-size: 1.35rem;
}

.site-bg-muted .site-bullet-icon {
    color: var(--primary);
}

/* Steps */
.site-steps {
    margin-top: 2.5rem;
    margin-bottom: 0;
}

.site-step {
    display: flex;
    align-items: flex-start;
    gap: 1.25rem;
    padding-bottom: 2rem;
}

.site-steps-horizontal {
    display: flex;
    flex-wrap: wrap;
    gap: 2rem;
}

.site-steps-horizontal .site-step {
    flex: 1 1 14rem;
    flex-direction: column;
    padding-bottom: 0;
}

.site-step-number {
    width: 2.5rem;
    height: 2.5rem;
    flex-shrink: 0;
    border-radius: var(--radius-pill);
    background-color: var(--white);
    color: var(--primary);
    font-weight: 700;
}

.site-bg-muted .site-step-number {
    background-color: var(--primary);
    color: var(--white);
}

.site-step-title {
    font-size: var(--font-size-lg);
    font-weight: 600;
    margin-bottom: 0.25rem;
}

.site-step-text {
    margin-bottom: 0;
    line-height: 1.6;
}

/* Stats */
.site-stats {
    margin-top: 2.5rem;
}

.site-stat-value {
    font-size: 3rem;
    font-weight: 700;
    line-height: 1.1;
    color: inherit;
}

.site-bg-muted .site-stat-value {
    color: var(--primary);
}

.site-stat-label {
    margin-top: 0.25rem;
}

/* Quote */
.site-quote-inner {
    max-width: 48rem;
}

.site-quote {
    margin: 0 0 2.5rem;
}

.site-quote:last-child {
    margin-bottom: 0;
}

.site-quote-mark {
    font-size: 2.5rem;
    color: var(--overlay-white-half);
}

.site-bg-muted .site-quote-mark {
    color: var(--primary-soft);
}

.site-quote-text {
    font-size: var(--font-size-xl);
    line-height: 1.5;
    margin: 0 0 1rem;
}

.site-quote-avatar {
    display: inline-block;
    width: 3rem;
}

.site-quote-avatar .site-media-image img {
    border-radius: var(--radius-pill);
    aspect-ratio: 1;
    object-fit: cover;
}

.site-quote-name {
    font-weight: 600;
}

.site-quote-role {
    font-size: var(--font-size-sm);
}

/* People */
.site-people {
    margin-top: 2.5rem;
}

.site-person-photo {
    max-width: 10rem;
    margin: 0 auto 1rem;
}

.site-person-photo .site-media-image img {
    border-radius: var(--radius-pill);
    aspect-ratio: 1;
    object-fit: cover;
}

.site-person-name {
    font-size: var(--font-size-lg);
    font-weight: 600;
    margin-bottom: 0.25rem;
}

.site-person-role {
    font-size: var(--font-size-sm);
    margin-bottom: 0.5rem;
}

.site-person-text {
    line-height: 1.6;
    margin-bottom: 0;
}

/* FAQ */
/* Versal-Zwischentitel statt einer weiteren fetten Zeile: seit die Fragen die
   Blockfarbe erben, sahen Gruppen und Fragen einander zu aehnlich. */
.site-faq-group {
    font-size: var(--font-size-sm);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin: 2.5rem 0 0.5rem;
    opacity: 0.75;
}

.site-bg-muted .site-faq-group {
    color: var(--text-subtle);
    opacity: 1;
}

.site-faq {
    border-top: 0.0625rem solid var(--gray-border-light);
}

.site-faq-entry {
    border-bottom: 0.0625rem solid var(--gray-border-light);
}

.site-faq-question {
    padding: 1rem 0;
    background: none;
    border: none;
    text-align: start;
    font-weight: 600;
    gap: 1rem;
    /* Buttons erben Farben nicht: ohne diese Zeile gibt der Browser den Fragen
       sein schwarzes Button-Schwarz, auf dem Markengrund und im Dark Mode
       unlesbar. */
    color: inherit;
    font-family: inherit;
    font-size: inherit;
}

/* The question is white on the green ground; a hover that turns it dark green
   would make it harder to read, not easier. Lift it instead. */
.site-faq-question:hover {
    opacity: 0.8;
}

.site-bg-muted .site-faq-question:hover {
    opacity: 1;
    color: var(--primary);
}

.site-faq-chevron {
    flex-shrink: 0;
    transition: var(--transition-base);
}

.site-faq-chevron-open {
    transform: rotate(180deg);
}

.site-faq-answer {
    padding: 0 0 1rem;
    line-height: 1.7;
    color: inherit;
    opacity: 0.85;
}

.site-bg-muted .site-faq-answer {
    opacity: 1;
    color: var(--text-subtle);
}

/* Link list */
.site-linklist {
    margin: 2rem 0 0;
}

.site-linkitem {
    display: flex;
    align-items: flex-start;
    gap: 1.25rem;
    padding: 1.25rem 0;
    border-bottom: 0.0625rem solid var(--gray-border-light);
}

.site-linkitem:last-child {
    border-bottom: none;
}

.site-linkitem-media {
    width: 5rem;
    flex-shrink: 0;
}

.site-linkitem-title {
    font-weight: 600;
}

.site-linkitem-text {
    font-size: var(--font-size-sm);
    margin-top: 0.25rem;
}

.site-linkitem .site-links,
.site-linkcard .site-links {
    margin-top: 0.75rem;
}

.site-linkcard {
    padding: 1.5rem;
    border-radius: var(--radius-lg);
    border: 0.0625rem solid var(--gray-border-light);
    background-color: var(--surface);
}

.site-linkcard-title {
    font-size: var(--font-size-lg);
    font-weight: 600;
    margin: 0.75rem 0 0.5rem;
}

.site-linkcard-text {
    line-height: 1.6;
}

/* Pricing */
.site-pricing {
    margin-top: 0.5rem;
}

/* Die Zeile ueber dem Knopf einer Preiskarte. Klein und ruhig: sie wirbt nicht,
   sie nimmt dem "loslegen" das Risiko und sagt, was dahinter liegt. */
.site-price-note {
    margin: 0 0 0.5rem;
    font-size: var(--fs-text-sm);
    color: var(--fs-text-muted);
    text-align: center;
}

.site-price-card {
    display: flex;
    flex-direction: column;
    padding: 2rem 1.75rem;
    border-radius: var(--radius-lg);
    border: 0.0625rem solid var(--gray-border-light);
    background-color: var(--surface);
    box-shadow: var(--shadow-xs);
}

/* The recommendation is marked by a frame rather than a different colour, so it
   stands out without breaking the row into two visual styles. */
.site-price-card-highlighted {
    border-color: var(--primary);
    border-width: 0.125rem;
    box-shadow: var(--shadow-md);
}

.site-price-name {
    font-size: var(--font-size-lg);
    font-weight: 700;
    margin-bottom: 0.25rem;
}

.site-price-description {
    font-size: var(--font-size-sm);
    margin-bottom: 1rem;
}

.site-price-amount {
    font-size: 2.25rem;
    font-weight: 700;
    color: var(--primary);
    margin-bottom: 1rem;
}

.site-price-features {
    margin-bottom: 1.5rem;
    /* Pushes the button to the bottom so cards of different length still line up. */
    flex-grow: 1;
}

/* Der Redakteur schreibt eine Aufzaehlung, die Karte macht Haken daraus: so sieht
   jede Karte gleich aus, ohne dass irgendwo ein Symbol mitgetippt werden muss. */
.site-price-features ul,
.site-price-features ol {
    margin: 0;
    padding: 0;
    list-style: none;
}

.site-price-features li {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.25rem 0;
}

.site-price-features li::before {
    content: "check";
    flex-shrink: 0;
    font-family: "Material Symbols Outlined";
    font-variation-settings: "FILL" 1;
    font-size: 1.25rem;
    line-height: 1.4;
    color: var(--primary);
}

/* Kaufen und Testen stehen untereinander und ueber die volle Breite der Karte:
   nebeneinander wuerden zwei Knoepfe in einer schmalen Spalte zu zwei Stummeln. */
.site-price-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.site-price-actions .btn {
    width: 100%;
    justify-content: center;
}

/* Ein Absatz ohne Aufzaehlung bleibt ein Absatz — nicht jeder Text auf der Karte
   ist eine Liste. */
.site-price-features p {
    margin: 0 0 0.5rem;
}

.site-price-features p:last-child {
    margin-bottom: 0;
}

@media (max-width: 62rem) {
    .site-bullets-columns {
        column-count: 1;
    }

    /* Gestapelt uebernehmen die horizontalen Schritte die Gestalt der vertikalen:
       Nummer links, Text rechts, mit Abstand nach unten. Nur display:block liess
       die Schritte vorher ohne jeden Zwischenraum aneinanderkleben. */
    .site-steps-horizontal {
        display: block;
    }

    .site-steps-horizontal .site-step {
        flex-direction: row;
        padding-bottom: 2rem;
    }

    .site-steps-horizontal .site-step:last-child {
        padding-bottom: 0;
    }
}

/* Gruppenbalken ausserhalb einer Tabelle
   Wo neben einer Tabelle eine zweite Spalte steht, die keine ist, braucht ihre
   Ueberschrift dieselbe Gestalt wie die Gruppenzeile der Tabelle daneben —
   sonst lesen sich zwei gleichrangige Gruppen wie zwei verschiedene Dinge.
   Werte bewusst aus framework.css abgeschrieben (.table > * > * > * und
   .table-light), damit beide Balken auf derselben Linie liegen. */
.section-bar {
    padding: 0.7rem 0.75rem;
    /* Auch die Schriftgroesse gehoert dazu: .table setzt sie auf --fs-text-sm, und
       der Schalter darin bemisst sich in em. Ohne dieselbe Stufe geraet neben der
       Tabelle beides eine Nummer groesser. */
    font-size: var(--fs-text-sm);
    background-color: var(--surface-sunk);
    border-bottom: 0.0625rem solid var(--gray-border-light);
}

/* Position und Hervorhebung in einer Zeile: die Position ist hoechstens zweistellig,
   also bekommt das Feld genau so viel Platz, wie zwei Ziffern brauchen, und der
   Schalter sitzt als letztes Glied derselben Gruppe daneben. */
.plan-pricingblock .form-control {
    flex: 0 0 auto;
    width: 4.5rem;
}

.plan-pricingblock .form-check-label {
    white-space: nowrap;
}

/* ── Wiki administration ────────────────────────────────────────────────── */

.wiki-category-row {
    transition: var(--transition-colors);
}

.wiki-count {
    font-size: var(--font-size-sm);
}

/* An inactive category or question stays in the list so it can be switched back
   on, but has to read as inactive at a glance. */
.wiki-inactive {
    opacity: 0.55;
}

.wiki-entry {
    padding: 1rem 0;
    border-bottom: 0.0625rem solid var(--gray-border-light);
}

.wiki-entry:first-child {
    padding-top: 0;
}

.wiki-entry:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.wiki-question {
    font-weight: 600;
    margin-bottom: 0.25rem;
}

.wiki-answer {
    font-size: var(--font-size-sm);
    line-height: 1.6;
}

.wiki-answer > :last-child {
    margin-bottom: 0;
}

.wiki-icon {
    font-size: 1rem;
}

.wiki-empty-icon {
    font-size: 2.5rem;
}

/* Public landing page a customer reaches from an automatic support answer. The card
   treatment itself comes from .fullpage-card: on the brand gradient the green title and
   the dark running text were all but invisible. Only the width is wider than the login
   forms, because here it is running text and not a column of fields. */
.site-feedback-card {
    width: 100%;
    max-width: 40rem;
    margin: 0 auto;
}

/* ==========================================================================
   Screen-filling tab (Administration → System → KI)
   ========================================================================== */

/* A tab whose content ends at the lower edge of the window instead of running past it. Its
   height is not set here: what stands above it (a title, an explanation that wraps to one line
   or three) is measured in the browser and written onto the element — see `fitToViewport` in
   utils.js. Every figure subtracted in a calc() would be a guess that is wrong at some width,
   and the page then scrolls by exactly that guess.

   What this rule does say is how the measured height is divided up: the title takes what it
   needs, the columns below get the rest, and `min-height: 0` is what lets them shrink below
   their content — without it they keep their full height and the box grows right back. */
.system-tab-fit {
    display: flex;
    flex-direction: column;
}

.system-tab-fit > .row {
    flex: 1 1 auto;
    min-height: 0;
}
/* ==========================================================================
   The navigator
   --------------------------------------------------------------------------
   One pattern for the whole navigation, from 390px to 1440px and beyond:

     · the bar carries the brand and the way in, nothing else;
     · the path bar under it says where you are, and each of its segments is
       the list of its own siblings;
     · the panel from the right is search first and the tree underneath, as
       many columns as the width carries.

   There is no sidebar any more and no footer anywhere — the legal texts live
   at the lower edge of the panel, one tap from wherever you are.

   Everything here is measured in rem and coloured from the tokens, so the base
   font size in framework.css still scales the whole thing.
   ========================================================================== */

/* One entry, everywhere: in a column of the panel and in a popover of the path
   bar. The two are the same thing at different sizes, so they are the same rule. */
.nav-entry {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    width: 100%;
    min-height: 3rem;
    padding: 0.625rem 0.75rem;
    border: none;
    border-radius: 0.6875rem;
    background: transparent;
    color: var(--nav-text);
    font-family: inherit;
    font-size: var(--fs-text-sm);
    font-weight: 500;
    line-height: 1.4;
    text-align: left;
    cursor: pointer;
    transition: var(--transition-colors);
}

.nav-entry-icon {
    flex-shrink: 0;
    color: var(--nav-icon);
    font-size: var(--fs-text-lg);
    transition: color var(--duration-base) var(--ease-out);
}

.nav-entry-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nav-entry-chevron {
    flex-shrink: 0;
    color: var(--text-subtle);
    font-size: var(--fs-text-lg);
}

.nav-entry-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    min-width: 1.375rem;
    height: 1.375rem;
    padding: 0 0.4375rem;
    border-radius: var(--radius-pill);
    background: var(--primary);
    color: var(--primary-ink);
    font-size: var(--fs-text-xs);
    font-weight: 700;
}

.nav-entry:hover,
.nav-entry.is-focused {
    background: var(--nav-hover-bg);
    color: var(--primary-dark);
}

.nav-entry:hover .nav-entry-icon,
.nav-entry.is-focused .nav-entry-icon {
    color: var(--primary);
}

.nav-entry.active {
    background: var(--primary-soft);
    color: var(--primary-dark);
    font-weight: 600;
}

.nav-entry.active .nav-entry-icon {
    color: var(--primary);
}

/* --------------------------------------------------------------------------
   Module bar
   Sits under the top bar and carries the modules, always the same ones in the
   same order. Each of them opens its own entries underneath. Only where there is
   room for it — below the desktop width the hamburger is the whole way in.
   -------------------------------------------------------------------------- */
.modulebar {
    position: relative;
    z-index: 3;
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 0.125rem;
    height: 3rem;
    flex-shrink: 0;
    padding: 0 1.25rem;
    background: var(--surface);
    border-bottom: 0.0625rem solid var(--sidebar-border);
}

/* Deliberately no overflow on the bar: it would clip the menus, which are the
   whole point of it. Many modules shorten their labels instead. */
.modulebar-item {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-width: 0;
}

.modulebar-button {
    display: inline-flex;
    align-items: center;
    gap: 0.125rem;
    min-height: 2rem;
    padding: 0 0.625rem;
    border: none;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--nav-text);
    font-family: inherit;
    font-size: var(--fs-text-sm);
    font-weight: 500;
    white-space: nowrap;
    min-width: 0;
    cursor: pointer;
    transition: var(--transition-colors);
}

.modulebar-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.modulebar-button:hover {
    background: var(--nav-hover-bg);
}

/* Wo man steht. Es traegt dieselbe Auszeichnung wie ein aktiver Eintrag im
   Navigator — es ist dieselbe Aussage. */
.modulebar-button.is-active {
    background: var(--primary-soft);
    color: var(--primary-dark);
    font-weight: 600;
}

.modulebar-button.is-open {
    background: var(--nav-hover-bg);
    color: var(--primary-dark);
    font-weight: 600;
}

.modulebar-caret {
    flex-shrink: 0;
    font-size: var(--fs-text-base);
    color: var(--text-subtle);
}

.modulebar-popover {
    position: absolute;
    top: 2.5rem;
    left: 0;
    z-index: 4;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 16.25rem;
    max-height: 21.25rem;
    overflow-y: auto;
    padding: 0.5rem;
    background: var(--surface);
    border: 0.0625rem solid var(--gray-border-light);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}

/* --------------------------------------------------------------------------
   Nav rail — eine Ebene, die offen liegt
   Wo man blaettert statt springt, ist ein Menue, das erst geoeffnet werden muss,
   ein Klick zuviel pro Seitenwechsel. Die Reihe zeigt die Nachbarn und braucht
   einen. Verwendet von der Ebenen-Spalte im Layout und von jeder Seite, die ihre
   eigenen Reiter so zeigen will.

   Grundform ist die Reihe, weil sie ueberall hineinpasst; die Spalte ist der
   Zusatz .nav-rail-sidebar und gilt erst ab Desktop-Breite.
   -------------------------------------------------------------------------- */
.nav-rail {
    display: flex;
    align-items: center;
    gap: 0.125rem;
    min-width: 0;
    overflow-x: auto;
    scroll-behavior: smooth;
    scrollbar-width: none;
}

/* Ein Rollbalken in einer 3rem hohen Leiste ist lauter als die Reihe, zu der er
   gehoert. Rad, Trackpad, Finger und die Pfeiltasten bewegen sie trotzdem. */
.nav-rail::-webkit-scrollbar {
    display: none;
}

.nav-rail-item {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    flex-shrink: 0;
    min-height: 2rem;
    padding: 0 0.625rem;
    border: none;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--nav-text);
    font-family: inherit;
    font-size: var(--fs-text-xs);
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: var(--transition-colors);
}

.nav-rail-item:hover {
    background: var(--nav-hover-bg);
    color: var(--nav-text);
}

.nav-rail-item:disabled {
    opacity: 0.5;
    cursor: default;
}

.nav-rail-item.active {
    background: var(--selected-bg);
    color: var(--primary-dark);
    font-weight: 600;
}

.nav-rail-icon {
    flex-shrink: 0;
    font-size: var(--fs-text-base);
    color: var(--text-subtle);
}

.nav-rail-item.active .nav-rail-icon {
    color: var(--primary);
}

/* Der Weg heraus fuehrt woanders hin als die Nachbarn, also steht er abgesetzt:
   in der Reihe durch einen Strich rechts, in der Spalte durch einen darunter. */
.nav-rail-back {
    margin-right: 0.375rem;
    padding-right: 0.75rem;
    border-right: 0.0625rem solid var(--sidebar-border);
    color: var(--text-subtle);
}

.nav-rail-back .nav-rail-icon {
    color: var(--text-subtle);
}

.nav-rail-badge {
    flex-shrink: 0;
    min-width: 1.125rem;
    padding: 0 0.3125rem;
    border-radius: var(--radius-pill);
    background: var(--primary);
    color: var(--white);
    font-size: var(--fs-text-xs);
    font-weight: 600;
    text-align: center;
}

/* --------------------------------------------------------------------------
   Die Reihe als Spalte
   Ab der Desktop-Breite stellt sie sich auf und steht als schmale Spalte neben
   dem Inhalt. Darunter bleibt sie liegen: eine Spalte kostet dort die halbe
   Breite, eine Reihe nur eine Zeile.
   -------------------------------------------------------------------------- */
@media (min-width: 992px) {
    .nav-rail-sidebar {
        flex-direction: column;
        align-items: stretch;
        flex-shrink: 0;
        width: 14rem;
        padding: 0.75rem 0.5rem;
        overflow-x: hidden;
        overflow-y: auto;
        background: var(--surface);
        border-right: 0.0625rem solid var(--sidebar-border);
    }

    .nav-rail-sidebar .nav-rail-item {
        min-height: 2.25rem;
        padding: 0 0.625rem;
        font-size: var(--fs-text-sm);
    }

    .nav-rail-sidebar .nav-rail-icon {
        font-size: var(--fs-text-lg);
    }

    .nav-rail-sidebar .nav-rail-back {
        margin-right: 0;
        margin-bottom: 0.375rem;
        padding-right: 0.625rem;
        padding-bottom: 0.375rem;
        border-right: none;
        border-bottom: 0.0625rem solid var(--sidebar-border);
        border-radius: 0;
    }

    /* In der Spalte gibt es eine Breite, an der ein langer Name enden kann — in
       der Reihe gibt es die nicht, dort laeuft er weiter und wird gewischt. */
    .nav-rail-sidebar .nav-rail-label {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* Ganz rechts wuerde ein Menue aus dem Bild laufen. Die letzten beiden haengen
   sich darum an ihre rechte Kante statt an ihre linke. */
.modulebar-item:nth-last-child(-n+2) .modulebar-popover {
    left: auto;
    right: 0;
}

/* Catches the click that closes an open popover. Transparent and behind it, so
   nothing on the page reacts to that click as well. */
.modulebar-overlay {
    position: fixed;
    inset: 0;
    z-index: 2;
}

/* --------------------------------------------------------------------------
   Panel
   -------------------------------------------------------------------------- */
.navpanel-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1050;
    background: rgba(0, 0, 0, 0.4);
    animation: navpanel-fade var(--duration-base) var(--ease-out);
}

.navpanel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 1051;
    display: flex;
    flex-direction: column;
    /* Der Streifen nimmt, was da ist, bis zu einer Breite, ab der eine vierte
       Spalte fehlt statt Platz. Bewusst in rem und vw statt in Stufen: wer den
       Browser zoomt oder groesser stellt, verschiebt damit beide Groessen
       zugleich, und die Spaltenzahl in NavPanel rechnet mit derselben Formel. */
    width: min(52rem, calc(100vw - 3rem));
    max-width: 100vw;
    background: var(--surface);
    box-shadow: var(--shadow-xl);
    animation: navpanel-in var(--duration-base) var(--ease-out);
}

@keyframes navpanel-in {
    from { transform: translateX(100%); }
    to   { transform: none; }
}

@keyframes navpanel-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Search first: with five levels the name of a page is usually the shortest way
   to it. The focus is in this field the moment the panel opens. */
.navpanel-search {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    flex-shrink: 0;
    padding: 1rem 1.25rem;
    border-bottom: 0.0625rem solid var(--sidebar-border);
}

.navpanel-search-icon {
    color: var(--nav-icon);
    font-size: var(--fs-text-xl);
}

.navpanel-search-input {
    flex: 1;
    min-width: 0;
    border: none;
    outline: none;
    background: none;
    font-family: inherit;
    font-size: var(--fs-text-base);
    color: var(--fs-text);
}

.navpanel-search-input::placeholder {
    color: var(--text-subtle);
}

.navpanel-esc-chip {
    flex-shrink: 0;
    padding: 0.1875rem 0.5rem;
    border: 0.0625rem solid var(--gray-border-light);
    border-radius: var(--radius-sm);
    font-size: var(--fs-text-xs);
    font-weight: 600;
    color: var(--gray-text-secondary);
}

.navpanel-close {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 2.75rem;
    height: 2.75rem;
    border: none;
    border-radius: 0.6875rem;
    background: none;
    color: var(--gray-text-secondary);
    cursor: pointer;
}

.navpanel-close:hover {
    background: var(--nav-hover-bg);
}

/* Die Nadel neben dem Schliessen-Kreuz. Ungesetzt sieht sie aus wie das Kreuz
   daneben, angeheftet traegt sie die Primaerfarbe und eine leichte Flaeche — sie
   ist der einzige Schalter im Streifen, der einen Zustand haelt. */
.navpanel-pin {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 2.75rem;
    height: 2.75rem;
    border: none;
    border-radius: 0.6875rem;
    background: none;
    color: var(--gray-text-secondary);
    cursor: pointer;
    transition: var(--transition-colors);
}

.navpanel-pin:hover {
    background: var(--nav-hover-bg);
}

.navpanel-pin.is-pinned {
    background: var(--selected-bg);
    color: var(--primary);
}

/* Der einmalige Hinweis unter dem Suchfeld. Er kommt erst, nachdem ein Klick den
   Streifen zugemacht hat, und geht fuer immer, sobald der Benutzer die Nadel oder
   den Modifier benutzt hat. */
.navpanel-hint {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    flex-shrink: 0;
    padding: 0.625rem 1.25rem;
    background: var(--selected-bg);
    border-bottom: 0.0625rem solid var(--sidebar-border);
    animation: navpanel-fade var(--duration-base) var(--ease-out);
}

.navpanel-hint-icon {
    flex-shrink: 0;
    color: var(--primary);
    font-size: var(--fs-text-lg);
}

.navpanel-hint-text {
    flex: 1;
    min-width: 0;
    font-size: var(--fs-text-sm);
    color: var(--nav-text);
}

.navpanel-hint-close {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 1.75rem;
    height: 1.75rem;
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--gray-text-secondary);
    cursor: pointer;
}

.navpanel-hint-close:hover {
    background: var(--nav-hover-bg);
}

.navpanel-hint-close .material-symbols-outlined {
    font-size: var(--fs-text-base);
}

/* Only where the panel is too short for a foot — see the height query below. */
.navpanel-search-actions {
    display: none;
    align-items: center;
    gap: 0.25rem;
}

/* --- Results ------------------------------------------------------------- */
.navpanel-results {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0.625rem 0.875rem;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.navpanel-result {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    min-height: 3.375rem;
    padding: 0.5rem 0.75rem;
    border: none;
    border-radius: 0.6875rem;
    background: transparent;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: var(--transition-colors);
}

.navpanel-result:hover,
.navpanel-result.is-focused {
    background: var(--nav-hover-bg);
}

.navpanel-result-icon {
    flex-shrink: 0;
    color: var(--nav-icon);
    font-size: var(--fs-text-lg);
}

.navpanel-result-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

.navpanel-result-label {
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--fs-text);
}

/* The whole way to the entry, not decoration: it is what tells two pages called
   "Einstellungen" five levels apart apart. */
.navpanel-result-path {
    font-size: var(--fs-text-xs);
    color: var(--gray-text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.navpanel-empty {
    padding: 1rem 0.75rem;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

/* --- Columns ------------------------------------------------------------- */
.navpanel-tree {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* The levels that no longer fit on screen. Each crumb is a way back to its
   level, so nothing above the window is out of reach. */
.navpanel-crumbs {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.125rem;
    flex-shrink: 0;
    padding: 0.5rem 1.125rem;
    background: var(--surface-subtle);
    border-bottom: 0.0625rem solid var(--sidebar-border);
    font-size: var(--fs-text-xs);
}

.navpanel-crumbs-icon {
    margin-right: 0.25rem;
    color: var(--text-subtle);
    font-size: var(--fs-text-base);
}

.navpanel-crumb {
    padding: 0.125rem 0.25rem;
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    font-family: inherit;
    font-size: inherit;
    font-weight: 500;
    color: var(--gray-text-secondary);
    cursor: pointer;
}

.navpanel-crumb:hover {
    color: var(--primary-dark);
}

.navpanel-crumb.is-last {
    color: var(--primary-dark);
    font-weight: 600;
}

.navpanel-columns {
    flex: 1;
    min-height: 0;
    display: flex;
}

.navpanel-column {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.navpanel-column + .navpanel-column {
    border-left: 0.0625rem solid var(--sidebar-border);
}

/* Names the level rather than the content, so it reads the same at every depth. */
.navpanel-column-label {
    padding: 0.75rem 1rem 0.375rem;
    font-size: var(--fs-text-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--nav-section-label);
}

/* Die Ueberschrift einer Platzhalterspalte ist leer, muss aber dieselbe Hoehe
   haben — sonst sitzt die Trennlinie daneben zu hoch. */
.navpanel-column-label:empty::before {
    content: "\00a0";
}

.navpanel-column-items {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0 0.625rem 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

/* Keine Zieladresse, sondern eine Aktion — sie legt der Navigation etwas hinzu,
   statt in ihr zu liegen. Genau das sagt die Trennlinie darueber. */
.navpanel-column-action {
    flex-shrink: 0;
    padding: 0.5rem 0.625rem;
    border-top: 0.0625rem solid var(--sidebar-border);
}

/* --- Foot ---------------------------------------------------------------- */
/* Wraps rather than overflows. The narrower the panel, the more likely the four
   entries no longer fit on one line — and an entry half off the edge is worse
   than one on a second line. */
.navpanel-foot {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.25rem 0.5rem;
    flex-shrink: 0;
    padding: 0.75rem 1rem;
    border-top: 0.0625rem solid var(--sidebar-border);
}

.navpanel-foot-item {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.75rem;
    padding: 0 0.75rem;
    border: none;
    border-radius: 0.6875rem;
    background: transparent;
    color: var(--nav-text);
    font-family: inherit;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
}

.navpanel-foot-item:hover {
    background: var(--nav-hover-bg);
    color: var(--primary-dark);
}

.navpanel-foot-item .material-symbols-outlined {
    color: var(--nav-icon);
    font-size: var(--fs-text-lg);
}

/* The language trigger inside the foot is a component of its own; it only has to
   stop looking like a control standing on its own here. */
.navpanel-foot-language .lang-plain-trigger,
.navpanel-inline-language .lang-plain-trigger {
    border: none;
    background: none;
    padding: 0;
    color: var(--primary-dark);
    font-family: inherit;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    cursor: pointer;
}

/* Abmelden braucht ein Formular, weil es eine POST-Anfrage ist. Das Formular soll
   aber kein Kasten in der Reihe sein: display:contents reicht den Knopf an das
   Layout darueber durch, so dass er sich wie jeder andere Eintrag verhaelt — in
   der Reihe wie in der Spalte. */
.navpanel-logout-form {
    display: contents;
}

/* The small print. Deliberately more air below than above, so it reads as the
   foot of the panel and not as an entry that got cut off. */
.navpanel-legal {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    flex-shrink: 0;
    padding: 0.875rem 1.5rem 1.125rem;
    border-top: 0.0625rem solid var(--gray-light);
    font-size: var(--fs-text-xs);
    color: var(--gray-text-secondary);
}

.navpanel-legal a {
    color: var(--gray-text-secondary);
    text-decoration: none;
}

.navpanel-legal a:hover {
    color: var(--primary-dark);
}

.navpanel-inline-action {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-height: 2.5rem;
    padding: 0 0.625rem;
    border: none;
    border-radius: 0.6875rem;
    background: transparent;
    color: var(--nav-text);
    font-family: inherit;
    font-size: var(--fs-text-sm);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.navpanel-inline-action .material-symbols-outlined {
    color: var(--nav-icon);
    font-size: var(--fs-text-base);
}

/* --------------------------------------------------------------------------
   Widths
   Die Breite selbst steht oben an .navpanel als eine Formel. Hier stehen nur noch
   die Feinheiten, die ein schmaler Streifen sonst nicht unterbringt.
   -------------------------------------------------------------------------- */
@media (max-width: 1199.98px) {
    .navpanel-search {
        padding: 0.875rem 1rem;
    }

    .navpanel-esc-chip {
        display: none;
    }

    .navpanel-foot {
        padding: 0.625rem 0.75rem;
    }

    .navpanel-foot-item {
        padding: 0 0.5rem;
    }
}

/* On a phone the panel is the screen. There is nothing beside it to look at, so
   a backdrop would only dim a strip that is not there. */
@media (max-width: 640.98px) {
    .navpanel {
        width: 100%;
    }

    .navpanel-backdrop {
        display: none;
    }

    .navpanel-crumbs {
        background: var(--surface);
    }

    .navpanel-crumbs-icon {
        display: none;
    }

    /* Account, language, theme and help as full rows: one thing per line is
       what a thumb can hit. */
    .navpanel-foot {
        flex-direction: column;
        align-items: stretch;
        gap: 0.125rem;
        padding: 0.5rem 0.625rem;
    }

    .navpanel-foot-item {
        justify-content: flex-start;
        width: 100%;
        min-height: 3rem;
        font-weight: 500;
    }

    .navpanel-foot-language {
        justify-content: flex-start;
    }

    .navpanel-foot-language .navpanel-foot-label {
        flex: 1;
    }

    .navpanel-legal {
        padding: 0.875rem 1.25rem 1.125rem;
    }
}

/* A phone lying on its side: 844 wide and 390 tall. The width is not the problem,
   the height is — a foot and a legal line under three rows of columns leave the
   columns nothing. The three entries of the foot ride in the search row instead. */
@media (max-height: 480px) {
    .navpanel {
        width: 100%;
    }

    .navpanel-backdrop {
        display: none;
    }

    .navpanel-search {
        padding: 0.5rem 0.75rem;
    }

    .navpanel-search-actions {
        display: inline-flex;
    }

    .navpanel-foot {
        display: none;
    }

    .navpanel-esc-chip {
        display: none;
    }

    .navpanel-legal {
        padding: 0.625rem 0.875rem 0.875rem 1.25rem;
    }
}

/* Die Abdunklung hinter einem Dialog. Der Altbestand traegt sie als Inline-Style
   am Dialog; neuer Code nimmt diese Klasse, damit keine Farbe im Markup steht.
   Bewusst nicht global auf .modal, sonst legt sie sich bei den vorhandenen
   Dialogen ein zweites Mal ueber die schon vorhandene. */
.modal-scrim {
    background-color: var(--overlay-dark-heavy);
}

/* ---------------------------------------------------------------------------
   Hilfe: die Anfragen eines Benutzers

   Ein Verlauf, keine Formularmaske. Was der Benutzer schreibt, steht rechts,
   was wir antworten, links. Denselben Datensatz sieht das Support-Team als
   Ticket, nur in seiner eigenen Ansicht.
   --------------------------------------------------------------------------- */

.help-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 3.5rem 1.5rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background: var(--surface);
    text-align: center;
}

.help-empty .material-symbols-outlined {
    font-size: 2.5rem;
    color: var(--text-subtle);
}

.help-empty-title {
    font-size: var(--fs-text-md);
    font-weight: 600;
    color: var(--gray-dark);
}

.help-empty-hint {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

/* --- Uebersicht ------------------------------------------------------------ */

.help-list {
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background: var(--surface);
    overflow: hidden;
}

.help-list-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--row-divider);
    color: var(--nav-text);
}

.help-list-row:last-child {
    border-bottom: 0;
}

.help-list-row:hover {
    background: var(--surface-subtle);
    color: var(--nav-text);
}

.help-list-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background: var(--surface-sunk);
    color: var(--gray-text-secondary);
}

.help-list-mark .material-symbols-outlined {
    font-size: var(--fs-text-lg);
}

.help-list-mark.answered {
    background: var(--primary-tint);
    color: var(--primary-strong);
}

.help-list-mark.closed {
    background: var(--success-tint);
    color: var(--success);
}

.help-list-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    flex: 1;
    min-width: 0;
}

.help-list-subject {
    font-size: var(--fs-text-base);
    font-weight: 600;
    color: var(--gray-dark);
}

.help-list-meta {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.help-list-dot {
    margin: 0 0.375rem;
}

.help-list-id {
    flex-shrink: 0;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.help-list-chevron {
    flex-shrink: 0;
    color: var(--text-subtle);
}

/* --- Verlauf --------------------------------------------------------------- */

.help-chat {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    max-width: 52rem;
}

.help-chat-stream {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.help-bubble-row {
    display: flex;
}

/* Eigene Nachrichten rechts, unsere links: dieselbe Ordnung, die jeder aus
   seinem Telefon kennt. */
.help-bubble-row.mine {
    justify-content: flex-end;
}

.help-bubble {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    max-width: 34rem;
    padding: 0.75rem 1rem;
    border-radius: var(--radius-lg);
    background: var(--surface);
    border: 1px solid var(--gray-border-light);
}

.help-bubble-row.mine .help-bubble {
    background: var(--primary-tint);
    border-color: var(--info-border);
}

.help-bubble-meta {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
}

.help-bubble-from {
    font-size: var(--fs-text-sm);
    font-weight: 600;
    color: var(--gray-dark);
}

.help-bubble-time {
    white-space: nowrap;
    font-size: var(--fs-text-xs);
    color: var(--gray-text-secondary);
}

/* Der Text kommt so an, wie er getippt wurde: Absaetze und Zeilenumbrueche
   sind bei einer Fehlerbeschreibung oft die halbe Information. */
.help-bubble-body {
    white-space: pre-wrap;
    font-size: var(--fs-text-sm);
    line-height: 1.55;
    color: var(--gray-dark);
}

.help-bubble-files {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding-top: 0.25rem;
    border-top: 1px solid var(--row-divider);
}

.help-bubble-file {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: var(--fs-text-sm);
    font-weight: 500;
}

.help-bubble-file.is-plain {
    color: var(--gray-text-secondary);
    font-weight: 400;
}

.help-bubble-file .material-symbols-outlined {
    font-size: var(--fs-text-base);
}

.help-chat-note {
    max-width: 34rem;
}

/* --- Schreiben ------------------------------------------------------------- */

.help-compose {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background: var(--surface);
}

.help-textarea {
    min-height: 5rem;
    resize: vertical;
}

.help-compose-actions {
    display: flex;
    justify-content: flex-end;
}

/* --- Anhaenge -------------------------------------------------------------- */

.help-attach {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.help-attach-trigger {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    align-self: flex-start;
    min-height: 2.25rem;
    padding: 0 0.875rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--nav-text);
    font-size: var(--fs-text-sm);
    font-weight: 500;
    cursor: pointer;
}

.help-attach-trigger:hover {
    border-color: var(--primary);
    color: var(--primary-dark);
}

.help-attach-trigger .material-symbols-outlined {
    font-size: var(--fs-text-base);
}

/* Das native Dateifeld ist unbrauchbar zu gestalten, also traegt das Label die
   Gestalt und das Feld selbst wird unsichtbar darunter gelegt. */
.help-attach-input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.help-attach-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.help-attach-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    max-width: 100%;
    padding: 0.25rem 0.5rem 0.25rem 0.75rem;
    border-radius: var(--radius-pill);
    background: var(--surface-sunk);
    font-size: var(--fs-text-sm);
}

.help-attach-chip .material-symbols-outlined {
    font-size: var(--fs-text-base);
    color: var(--gray-text-secondary);
}

.help-attach-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.help-attach-remove {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: none;
    color: var(--gray-text-secondary);
    cursor: pointer;
}

.help-attach-remove:hover {
    color: var(--danger);
}

.help-attach-hint {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

@media (max-width: 767.98px) {
    .help-bubble {
        max-width: 100%;
    }

    .help-list-id {
        display: none;
    }
}

/* ── Site: readability on the brand ground ────────────────────────────────
   Cards are a light surface on either ground. Their text colour must come from
   the card, not from the section, or a card on the brand ground would render
   white titles on a white card. */
.site-feature-card,
.site-linkcard,
.site-price-card {
    color: var(--gray-dark);
}

/* Links inside a card follow the card, not the brand ground. */
.site-linkcard .site-link-text {
    color: var(--link-color);
    text-decoration: none;
}

/* The utility grey of .text-muted disappears on the brand ground. Secondary
   text outside the light surface and outside cards turns translucent white.
   The !important is needed because the utility itself carries one. */
.site-block:not(.site-bg-muted) .site-step-text.text-muted,
.site-block:not(.site-bg-muted) .site-quote-role.text-muted {
    color: var(--white) !important;
    opacity: 0.85;
}

/* An icon standing in for the picture of a media-text section fills its column
   as a large centred glyph instead of leaving half the block almost empty. */
.site-mediatext-media .site-media-icon {
    width: 100%;
    min-height: 14rem;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 0;
}

.site-mediatext-media .site-media-icon .material-symbols-outlined {
    font-size: 7rem;
}

/* ── Site: carousel ───────────────────────────────────────────────────────
   Native horizontal scrolling with snap points; the arrows only nudge the
   track. The scrollbar is hidden because the arrows and the cut-off card
   already say "there is more". */
.site-carousel {
    display: flex;
    align-items: stretch;
    gap: 0.75rem;
    margin-top: 2.5rem;
}

.site-carousel-track {
    display: flex;
    gap: 1rem;
    flex: 1;
    min-width: 0;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    padding: 0.25rem 0;
}

.site-carousel-track::-webkit-scrollbar {
    display: none;
}

.site-carousel-slide {
    flex: 0 0 18rem;
    scroll-snap-align: start;
}

.site-carousel-card {
    padding: 1.75rem;
    border-radius: var(--radius-lg);
    background-color: var(--surface);
    border: 0.0625rem solid var(--gray-border-light);
    box-shadow: var(--shadow-xs);
    color: var(--gray-dark);
}

.site-carousel-title {
    font-size: var(--font-size-lg);
    font-weight: 600;
    margin-bottom: 0.5rem;
}

.site-carousel-text {
    color: var(--text-subtle);
    line-height: 1.6;
    margin-bottom: 0;
}

/* The carousel card carries the same pale icon tile as the other cards. */
.site-carousel-card .site-media-icon {
    background-color: var(--primary-bg-subtle);
}

.site-carousel-card .site-media-icon .material-symbols-outlined {
    color: var(--primary);
}

/* On the brand ground the arrows are cut from the same cloth as the secondary
   button; on the light surface they become framed white circles. */
.site-carousel-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    align-self: center;
    flex-shrink: 0;
    border-radius: var(--radius-pill);
    border: 0.0625rem solid var(--overlay-white-medium);
    background-color: transparent;
    color: var(--white);
    cursor: pointer;
    transition: var(--transition-base);
}

.site-carousel-arrow:hover {
    background-color: var(--overlay-white-subtle);
}

.site-bg-muted .site-carousel-arrow {
    border-color: var(--gray-border-medium);
    background-color: var(--surface);
    color: var(--primary);
}

.site-bg-muted .site-carousel-arrow:hover {
    background-color: var(--primary-bg-subtle);
}

@media (max-width: 62rem) {
    .site-carousel-slide {
        flex-basis: min(18rem, 70vw);
    }

    .site-carousel-card {
        padding: 1.25rem;
    }

    /* Die Pfeile bleiben sichtbar, nur kleiner: in einem schmalen Desktop-Fenster
       gibt es weder Touch noch einen sichtbaren Scrollbalken — ohne Pfeile waere
       das Karussell dort schlicht nicht bedienbar. Auf dem Handy schadet der
       Pfeil nicht und zeigt zugleich an, dass es weitere Karten gibt. */
    .site-carousel-arrow {
        width: 2.25rem;
        height: 2.25rem;
    }

    .site-carousel {
        gap: 0.375rem;
    }
}

/* ── Theme toggle on the public shell ─────────────────────────────────────
   A small floating button in the corner of the footer band. The icons swap
   with the active theme; the state itself lives on the html element and in
   localStorage (see utils.js). */
.theme-toggle {
    position: fixed;
    right: 1rem;
    bottom: 3.4rem;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: var(--radius-pill);
    border: 0.0625rem solid var(--gray-border-light);
    background-color: var(--surface);
    color: var(--gray-dark);
    cursor: pointer;
    box-shadow: var(--shadow-xs);
    transition: var(--transition-base);
}

.theme-toggle:hover {
    background-color: var(--surface-sunk);
}

/* When the page also carries the language picker, the toggle joins it on one
   line in the footer band: toggle on the left, picker on the right, both
   centered on the same horizontal axis. The right offset clears the picker
   pill (flag + two-letter code + chevron), whose width is practically
   constant across languages. */
.empty-layout-shell:has(.fullpage-lang) .theme-toggle {
    right: 7.5rem;
    bottom: 0.2rem;
}

.theme-toggle .material-symbols-outlined {
    font-size: 1.25rem;
}

/* The swap pair works anywhere, not only on the floating button: the navigator
   foot uses the same classes on its icons and labels. Each span names the theme
   a click switches to, so the -dark pair shows while the light theme is active. */
.theme-toggle-light {
    display: none;
}

html[data-theme="dark"] .theme-toggle-dark {
    display: none;
}

html[data-theme="dark"] .theme-toggle-light {
    display: inline-block;
}

/* The way into the application sits at the far end of the jump bar, away from the
   section links: it leads somewhere else entirely, and a visitor with an account
   looks for it in the corner rather than in a list of sections. */
.site-nav-links {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    min-width: 0;
}

.site-nav-login {
    margin-inline-start: auto;
    flex-shrink: 0;
    white-space: nowrap;
    padding: 0.3rem 0.9rem;
    border-radius: var(--radius-pill);
    border: 0.0625rem solid var(--gray-border-medium);
    color: var(--gray-dark);
}

.site-nav-login:hover {
    background-color: var(--primary-bg-subtle);
    border-color: var(--primary);
    color: var(--primary);
}

/* Auch unterhalb der Desktop-Breite brechen die Sprunglinks um, statt seitwaerts
   zu scrollen: der versteckte Scrollbereich schnitt Links mitten im Wort ab, und
   ohne sichtbaren Scrollbalken war nicht zu erkennen, dass es mehr gibt. Die
   Links selbst brechen nicht mitten im Wort. */
.site-nav-link {
    white-space: nowrap;
}

/* ── Scroll-to-top button ────────────────────────────────────────────────────
   Floating helper rendered by the layouts. Hidden resting state is faded out,
   nudged down and click-through, so it never intercepts pointer events while
   invisible. */
.scroll-top-button {
    position: fixed;
    right: 1.75rem;
    /* Der Abstand nach unten ist eine Stellschraube, weil manche Rahmen unten eine
       eigene Leiste haben (Assistent, Startseite, Rechtstexte). Der Knopf steigt
       dort darueber, statt die Knoepfe dahinter zu verdecken. */
    bottom: calc(var(--scroll-top-offset, 1.75rem) + env(safe-area-inset-bottom, 0px));
    z-index: 1080;
    width: 3rem;
    height: 3rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: var(--primary);
    color: var(--white);
    box-shadow: 0 0.25rem 0.875rem rgba(0, 0, 0, 0.18);
    cursor: pointer;
    opacity: 0;
    transform: translateY(0.5rem);
    pointer-events: none;
    transition: opacity 0.18s ease, transform 0.18s ease;
}

.scroll-top-button.is-visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.scroll-top-button .material-symbols-outlined {
    font-size: var(--fs-text-lg);
}

/* Rahmen mit einer eigenen Leiste am unteren Rand heben den Knopf darueber. */
.wizard-shell {
    --scroll-top-offset: 6rem;
}

.app-shell,
.empty-layout-shell {
    --scroll-top-offset: 5rem;
}

/* Figures on the user-quota card sit at the same weight as the field beside them. */
.quota-figure {
    font-size: var(--fs-text-md);
    font-weight: 600;
}

/* The seat cap is a small number, so the field stays as narrow as the number it holds. */
.unit-quota-max-input {
    max-width: 8rem;
}

/* === Schulkontext ===
   Der Streifen unter der Pfadleiste, solange jemand in einer fremden Schule
   arbeitet. Er traegt die Warnfarbe, weil er nicht uebersehen werden darf, und
   bleibt trotzdem eine Zeile hoch: er begleitet die Arbeit, er unterbricht sie
   nicht. */
.school-context-bar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 1rem;
    background-color: var(--warning-tint);
    border-bottom: 0.0625rem solid var(--warning);
    color: var(--warning-dark);
    font-size: var(--fs-text-sm);
}

.school-context-bar .school-context-text {
    flex: 1 1 auto;
}

/* Derselbe Streifen wie beim Schulkontext, aber in gedaempftem Rot: die Lizenz ist
   abgelaufen. Er nimmt nichts weg, sondern erklaert nur, warum nichts mehr geht. */
.license-bar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 1rem;
    background-color: var(--danger-tint);
    border-bottom: 0.0625rem solid var(--danger);
    color: var(--danger-dark);
    font-size: var(--fs-text-sm);
}

.license-bar-text {
    flex: 1 1 auto;
}

/* Der Weg zur Kasse steht im Streifen selbst. Er traegt dessen Farbe und schreit
   nicht — der Hinweis ist die Nachricht, der Link nur die Tuer daneben. */
.license-bar-link {
    flex: 0 0 auto;
    color: var(--danger-dark);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

.license-bar-link:hover {
    text-decoration: underline;
}

/* Die Auskunft, wenn ein Schreibversuch am fehlenden Vertrag scheitert. Sie tritt an
   die Stelle der Seite, deshalb etwas Luft ringsum. */
.license-block {
    padding: 1.5rem 0;
}

/* ==========================================================================
   Kauf-Strecken: Angebotsgenerator, Kasse, Widerruf.

   Die Regeln standen im Scoped CSS des Angebotsgenerators und galten damit nur
   dort — die Kasse und der Widerruf verwenden dieselben Klassen und bekamen
   nichts davon ab, standen also ohne Abstaende und ohne Form da. Drei Seiten,
   die sich dasselbe Geruest teilen, brauchen ihre Regeln global.
   ========================================================================== */

/* Der Angebotsgenerator.

   Die Seite liegt auf dem hellen Grund (site-bg-muted), nicht auf dem Markengrund
   von .site-page. Alle Farben hier gehen darum von dunkler Schrift auf hellem
   Grund aus: --fs-text fuer Text, --fs-text-muted fuer Hinweise (beide auf Weiss
   geprueft), --primary fuer das Gewaehlte. Kein --overlay-white-*, das gehoert auf
   den dunklen Grund. */

/* Der Grund der ganzen Seite, nicht nur des Abschnitts.

   .site-page traegt sonst den Markengrund, der bei kurzem Inhalt unter dem Block
   als gruene Flaeche stehen bleibt. Auf dieser Seite gibt es nur einen Abschnitt,
   und der ist hell; die Kopfleiste bringt ihren eigenen Grund mit. */
.offer-shell {
    min-height: 100vh;
    background-color: var(--surface-subtle);
    color: var(--fs-text);
}

.offer-page {
    color: var(--fs-text);
    padding-top: 1.5rem;
}

/* Die Einleitung kommt auf hellem Grund sonst in --text-subtle, einem Grauwert,
   der fuer eine kurze Zeile unter einer Ueberschrift gedacht ist. Hier traegt sie
   die Erklaerung der ganzen Seite und bekommt darum den lesbaren Grauwert. */
.offer-page .site-subline {
    color: var(--fs-text-muted);
    opacity: 1;
}

/* Der Weg zurueck steht wie auf der Anmeldeseite oben links. Dort liegt er auf
   dem gruenen Verlauf und ist weiss; hier liegt er auf hellem Grund und muss die
   Markenfarbe tragen, sonst waere er unsichtbar. Platz und Form bleiben gleich. */
.offer-top-left a {
    color: var(--primary);
}

.offer-top-left a:hover {
    color: var(--primary-hover);
}

/* ── Zwei Schritte ──────────────────────────────────────────────────────────
   Erst die Auswahl, dann die Angaben. Die Anzeige darueber sagt, wo der Besucher
   steht und wie viel noch kommt; der erste Schritt ist aus dem zweiten heraus
   anklickbar, weil das Aendern des Tarifs der haeufigste Grund ist zurueckzugehen.

   Vorher standen beide Haelften als zwei Spalten nebeneinander. Das war zu viel
   auf einmal: wer nur wissen wollte, was es kostet, stand schon vor dem ganzen
   Formular. */

.offer-steps {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 2rem 0 1.5rem;
    padding: 0;
    list-style: none;
}

.offer-step {
    display: flex;
    min-width: 0;
}

/* Die Linie zwischen den beiden Schritten. Sie nimmt den uebrigen Platz und macht
   damit aus zwei Marken einen Weg. */
.offer-step-line {
    flex: 1 1 auto;
    height: 0.0625rem;
    background-color: var(--gray-border-medium);
}

.offer-step-button {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--fs-text-sm);
    color: var(--fs-text-muted);
    text-align: left;
}

button.offer-step-button {
    cursor: pointer;
}

button.offer-step-button:hover .offer-step-label {
    color: var(--primary);
}

.offer-step-number {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background-color: var(--gray-border-light);
    color: var(--fs-text-muted);
    font-weight: 600;
}

.offer-step-current .offer-step-button {
    color: var(--fs-text);
    font-weight: 600;
}

.offer-step-current .offer-step-number {
    background-color: var(--primary);
    color: var(--surface);
}

.offer-section-title {
    font-size: var(--fs-text-lg);
    color: var(--fs-text);
    margin: 0 0 0.5rem;
}

.offer-section-title:not(:first-child) {
    margin-top: 2rem;
}

/* Hinweistexte. Bewusst nicht .text-muted: dessen Grauwert ist fuer die
   App-Oberflaeche gedacht und stand hier auf hellem Grund zu blass. */
.offer-hint {
    font-size: var(--fs-text-sm);
    color: var(--fs-text-muted);
    margin: 0 0 1rem;
}

/* Steht der Hinweis direkt unter einem Feld, braucht er Luft nach oben: sonst
   klebt er am Rahmen und liest sich wie ein Teil davon. */
.form-select + .offer-hint,
.form-control + .offer-hint,
.input-group + .offer-hint {
    margin-top: 0.5rem;
}

/* ── Auswahl ───────────────────────────────────────────────────────────────
   Kundentyp und Tarife sehen gleich aus, weil sie dasselbe tun. Der Unterschied
   liegt im Zeichen: Punkt fuer "eines davon", Kaestchen fuer "beliebig viele". */

.offer-choice-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1.5rem;
}

.offer-choice {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    padding: 0.875rem 1rem;
    text-align: left;
    color: var(--fs-text);
    background-color: var(--surface);
    border: 0.0625rem solid var(--gray-border-medium);
    border-radius: var(--radius-md);
    cursor: pointer;
}

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

.offer-choice-selected {
    border-color: var(--primary);
    background-color: var(--selected-bg);
}

.offer-choice-mark {
    color: var(--gray-border-medium);
    flex-shrink: 0;
}

.offer-choice-selected .offer-choice-mark {
    color: var(--primary);
}

.offer-choice-label {
    font-size: var(--fs-text-base);
    font-weight: 600;
}

/* Die erste Frage der Seite traegt unter jeder Antwort einen Satz, der sagt, was
   danach passiert. Ohne ihn stuenden dort drei Woerter, zwischen denen niemand
   entscheiden kann, ohne sie vorher zu kennen. */
.offer-choice-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

.offer-choice-description {
    font-size: var(--fs-text-sm);
    color: var(--fs-text-muted);
}

.offer-choice-icon {
    flex-shrink: 0;
    color: var(--primary);
}

/* ── Tarifzeile ───────────────────────────────────────────────────────────── */

.offer-plan-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
}

.offer-plan-description {
    font-size: var(--fs-text-sm);
    font-weight: 400;
    color: var(--fs-text-muted);
}

.offer-plan-price {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    flex-shrink: 0;
}

.offer-plan-amount {
    font-size: var(--fs-text-md);
    font-weight: 600;
    color: var(--primary-strong);
    white-space: nowrap;
}

.offer-plan-note {
    font-size: var(--fs-text-xs);
    color: var(--fs-text-muted);
}

/* Der Listenpreis bei einer Probelizenz: er bleibt stehen, damit man sieht, was
   man bekommt, gilt aber nicht. Durchgestrichen und gedaempft statt einfach
   weggelassen. */
.offer-plan-amount-void {
    text-decoration: line-through;
    font-weight: 500;
    color: var(--fs-text-muted);
}

.offer-plan-trial {
    font-size: var(--fs-text-xs);
    font-weight: 600;
    color: var(--primary-strong);
    white-space: nowrap;
}

/* ── Felder ────────────────────────────────────────────────────────────────
   Die Felder selbst kommen unveraendert aus framework.css. Hier steht nur ihre
   Anordnung, damit zusammengehoerige Angaben in einer Zeile stehen. */

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

.offer-field .form-label {
    color: var(--fs-text);
}

.offer-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.offer-row .offer-field {
    flex: 1 1 10rem;
}

.offer-grow {
    flex: 2 1 12rem;
}

.offer-field-narrow {
    max-width: 14rem;
}

/* Die erste Frage darf ruhig breit sein: sie ist fuer einen Moment der ganze
   Bildschirminhalt. Breit genug fuer das Land und die Waehrung daneben — steht
   nur eine Waehrung zur Wahl, bleibt das Feld fuer das Land allein und nimmt sich
   die Zeile. */
.offer-country-step {
    max-width: 34rem;
}

.offer-field-wide {
    max-width: 28rem;
}

/* Ein Wert, der feststeht, weil er weiter oben gewaehlt wurde. Kein gesperrtes
   Eingabefeld: das sieht aus, als koennte man es doch noch aendern.

   Das Innenmass ist das des Eingabefeldes, die Rahmenstaerke eingerechnet. Nur so
   steht ein solcher Wert auf derselben Linie wie das Feld daneben, statt einen
   Hauch zu hoch. */
.offer-fixed-value {
    padding: calc(var(--fs-control-padding-y) + 1px) 0;
    font-size: var(--fs-text-base);
    line-height: 1.4;
    color: var(--fs-text);
}

/* Kontingent, Beginn und letzter Tag: kurze Angaben, die nebeneinander gehoeren.
   Untereinander stuenden drei schmale Felder mit viel Weiss daneben.

   Die Grundbreite ist bewusst kleiner als die Hoechstbreite der Felder: sonst
   bricht die Zeile schon um, wenn der Betrachter seine Schrift groesser gestellt
   hat, obwohl die Angaben laengst nebeneinander Platz haetten. Oben buendig,
   damit Feld und Wert auf einer Linie beginnen, auch wenn unter dem einen noch
   ein Hinweis steht. */
.offer-compact-row {
    align-items: flex-start;
}

.offer-row.offer-compact-row > .offer-field {
    flex: 1 1 8rem;
}

.offer-compact-row .offer-hint {
    margin-bottom: 0;
}

/* Die Erfolgsmeldung steht unmittelbar unter der Schaltflaeche, die sie ausgeloest
   hat, und braucht dorthin etwas Luft. */
.offer-result {
    margin-top: 1rem;
    margin-bottom: 0;
}

/* Der Zuschnitt der Probelizenz als Aufzaehlung. Jede Zeile nennt eine Zahl aus dem
   Tarif; gewaehlt wird hier nichts, deshalb steht es als Auskunft und nicht als
   Formularfeld. */
.offer-trial-limits {
    margin: 0.5rem 0;
    padding-left: 1.25rem;
}

.offer-trial-limits li + li {
    margin-top: 0.25rem;
}

/* Der Satz ueber der Schaltflaeche, wie lange das Angebot gilt. Etwas Luft nach
   oben, damit er sich vom Formular darueber loest. */
.offer-validity {
    margin-top: 1.5rem;
}

.offer-consent {
    margin: 1.5rem 0 0;
    color: var(--fs-text);
}

.offer-consent a {
    color: var(--primary);
}

/* Der Hinweis unter einem Schalter braucht Luft nach oben, sonst klebt er daran. */
.offer-consent-hint {
    margin-top: 0.75rem;
}

/* ── Luft ─────────────────────────────────────────────────────────────────────
   Auf den Verkaufsseiten stehen Tarifkarte, Zusammenfassung und Hinweise
   untereinander und werden als dieselbe Art Kasten gelesen. Dann muessen sie auch
   dieselbe Luft haben: eine Meldung mit 0.85rem neben einer Karte mit 2rem sieht
   nicht knapp aus, sondern falsch.
   ────────────────────────────────────────────────────────────────────────────── */

.offer-page .site-price-card,
.offer-page .offer-summary,
.offer-page .alert {
    padding: 1.75rem;
    margin-bottom: 1.25rem;
}

/* Die Beanstandung ueber dem Knopf ist eine Zeile und kein Abschnitt: sie bekommt
   das knappere Innenmass und Luft nach oben, damit sie nicht am Feld klebt, das sie
   beanstandet. */
.alert.form-error {
    padding: 0.875rem 1.125rem;
    margin-top: 1.25rem;
}

.form-error-list {
    margin: 0;
    padding-left: 1.125rem;
}

.form-error-list li + li {
    margin-top: 0.25rem;
}

/* Der Abstand unter der Merkmalsliste haelt auf der Startseite den Knopf am Fuss
   der Karte. Hier gibt es keinen, und dann ist er nur ein leerer Streifen. */
.offer-page .site-price-card .site-price-features {
    margin-bottom: 0;
}

/* ── Zusammenfassung ──────────────────────────────────────────────────────── */

.offer-summary {
    padding: 1.25rem;
    background-color: var(--surface);
    border: 0.0625rem solid var(--gray-border-light);
    border-radius: var(--radius-lg);
}

.offer-summary .offer-section-title {
    margin-top: 0;
}

/* Der Kopf der Aufstellung: der Titel und daneben, worin die Betraege stehen. Auf
   einer Grundlinie, damit das Auswahlfeld nicht hoeher sitzt als die Ueberschrift;
   bei schmalem Schirm bricht es darunter. */
.offer-summary-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.offer-summary-aside {
    margin-bottom: 0.5rem;
}

/* Nur so breit wie ihr Inhalt: "EUR €" braucht keine halbe Zeile. */
.offer-currency-select {
    width: auto;
}

.offer-summary-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.375rem 0;
    color: var(--fs-text-muted);
}

.offer-summary-row:first-of-type {
    color: var(--fs-text);
}

/* Der Platz, an dem sonst ein Betrag steht, wenn es noch keinen gibt. Kursiv, damit
   die Zeile auf den ersten Blick nicht wie eine Zahl aussieht, und ohne eigene
   Farbe: es ist kein Fehler, sondern eine offene Frage. */
.offer-summary-pending {
    font-style: italic;
}

/* Der Nachlass. Er traegt die Zusagefarbe, weil er als Einziges in dieser Aufstellung
   eine gute Nachricht ist — alles andere darin ist eine Forderung. */
.offer-summary-discount {
    color: var(--success);
}

.offer-summary-total {
    margin-top: 0.5rem;
    padding-top: 0.75rem;
    border-top: 0.0625rem solid var(--gray-border-light);
    font-size: var(--fs-text-md);
    font-weight: 600;
    color: var(--primary-strong);
}

/* Die Legende der Pflichtfelder. Sie steht dicht ueber der Schaltflaeche und
   traegt deshalb keinen eigenen Abstand nach unten: der Knopf bringt seinen mit. */
.offer-required-legend {
    font-size: var(--fs-text-sm);
    color: var(--fs-text-muted);
    margin-top: 1.5rem;
}

.offer-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.5rem;
}

/* Der eingeklappte Sonderfall: wer bezahlt, wenn es nicht die Einrichtung selbst
   ist. Der Schalter steht mit etwas Luft nach oben, damit er sich von den
   Pflichtfeldern darueber absetzt und nicht wie eines von ihnen aussieht. */
.offer-billing-toggle {
    margin: 0.5rem 0 1rem;
}

.offer-billing-hint {
    margin-top: -0.5rem;
    margin-bottom: 1rem;
}

/* Eine Seite mit einer einzigen Spalte — der Widerruf fragt zwei Felder ab und
   zeigt eine Bestellung, der Angebotsgenerator einen Schritt nach dem anderen.
   Ueber die volle Breite gezogen liefe der Blick ins Leere. */
.offer-page-narrow {
    max-width: 40rem;
}

/* ──────────────────────────────────────────────────────────────────────────────
   Tarifwahl auf der Bestellseite

   Die Karten sehen aus wie die auf der Startseite, sind hier aber Schaltflaechen:
   der Besucher hat auf einer von ihnen gedrueckt und kann hier noch wechseln. Der
   Ring markiert die Wahl, der Punkt links oben sagt, dass es eine ist — eine Karte
   allein sieht sonst aus wie eine Auskunft und nicht wie ein Angebot zum Anklicken.
   ────────────────────────────────────────────────────────────────────────────── */

.checkout-plans {
    display: grid;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.offer-page .checkout-plans .site-price-card {
    position: relative;
    width: 100%;
    text-align: start;
    cursor: pointer;
    margin-bottom: 0;
    padding-inline-end: 3rem;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.offer-page .checkout-plans .site-price-card:hover {
    border-color: var(--primary);
}

.offer-page .checkout-plans .checkout-plan-selected {
    border-color: var(--primary);
    border-width: 0.125rem;
    background-color: var(--selected-bg);
    box-shadow: var(--shadow-md);
}

.checkout-plan-mark {
    position: absolute;
    top: 1.25rem;
    inset-inline-end: 1.25rem;
    color: var(--fs-text-muted);
}

.checkout-plan-selected .checkout-plan-mark {
    color: var(--primary);
}

/* Die Karte ist eine Schaltflaeche, ihre Teile sind es nicht: Beschreibung, Preis
   und Merkmalsliste stehen darin als span und brauchen deshalb die Blockform, die
   sie auf der Startseite als Absatz und Liste von selbst haetten. */
.checkout-plan .site-price-description,
.checkout-plan .site-price-amount,
.checkout-plan .site-price-features {
    display: block;
}

.checkout-plan .site-price-features {
    margin-top: 0.75rem;
}

/* ── Tarifwahl im Konto ───────────────────────────────────────────────────────
   Die Kasse auf der oeffentlichen Seite hat Platz fuer hohe Karten nebeneinander.
   Im Konto steht dieselbe Wahl in einer halben Spalte, und zwei hohe Karten
   untereinander schieben den Preis des zweiten Tarifs aus dem Bild — verglichen
   wird dann gar nicht mehr.

   Deshalb hier eine Zeile je Tarif: Auswahlpunkt vorn, Name und wofuer er gedacht
   ist in der Mitte, der Preis rechts an der Kante, wo das Auge ihn zwischen den
   Zeilen findet. Was der Tarif kann, klappt unter der gewaehlten Zeile auf.
   ────────────────────────────────────────────────────────────────────────────── */

.plan-choice {
    display: grid;
    gap: 0.75rem;
}

.plan-option {
    border: 0.0625rem solid var(--gray-border-light);
    border-radius: var(--radius-lg);
    background-color: var(--surface);
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}

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

/* Die gewaehlte Zeile traegt dieselbe Markierung wie eine gewaehlte Tabellenzeile:
   wer die eine kennt, erkennt die andere wieder. */
.plan-option-selected {
    border-color: var(--primary);
    background-color: var(--selected-bg);
    box-shadow: var(--shadow-md);
}

/* Die Zeile selbst ist die Schaltflaeche — ganz, nicht nur ihr Punkt. Ein Ziel,
   das eine Fingerbreite misst, trifft niemand gern zweimal. */
.plan-option-head {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 0.875rem;
    width: 100%;
    padding: 1rem 1.125rem;
    border: 0;
    background: none;
    text-align: start;
    cursor: pointer;
    color: inherit;
    font: inherit;
}

.plan-option-mark {
    color: var(--fs-text-muted);
    font-size: var(--fs-text-lg);
}

.plan-option-selected .plan-option-mark {
    color: var(--primary);
}

.plan-option-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

.plan-option-name {
    font-weight: 600;
    font-size: var(--fs-text-md);
}

.plan-option-description {
    color: var(--fs-text-muted);
    font-size: var(--fs-text-sm);
}

/* Der Betrag steht rechts und bricht nicht um: eine umgebrochene Zahl liest sich
   als zwei. */
.plan-option-price {
    font-weight: 700;
    font-size: var(--fs-text-md);
    color: var(--primary);
    white-space: nowrap;
    text-align: end;
}

/* Die Merkmale gehoeren unter die Zeile, eingerueckt auf die Hoehe des Namens —
   sonst haengen sie unter dem Auswahlpunkt und lesen sich wie eine zweite Wahl. */
.plan-option-features {
    padding: 0 1.125rem 1rem 3.5rem;
    font-size: var(--fs-text-sm);
    color: var(--fs-text-muted);
}

.plan-option-features ul,
.plan-option-features ol {
    margin: 0;
    padding-left: 1.125rem;
}

.plan-option-features p:last-child,
.plan-option-features ul:last-child {
    margin-bottom: 0;
}

/* ── Die Angaben darunter ─────────────────────────────────────────────────────
   Beginn und Anschrift werden gelesen und selten geaendert. Als Zeilen mit der
   Bezeichnung links und dem Wert rechts brauchen sie ein Viertel des Platzes, den
   zwei Abschnitte mit eigener Ueberschrift beanspruchten.
   ────────────────────────────────────────────────────────────────────────────── */

.plan-facts {
    margin: 0 0 1.25rem;
    border-top: 0.0625rem solid var(--gray-border-light);
}

.plan-fact {
    display: grid;
    grid-template-columns: 9rem 1fr;
    gap: 0.75rem;
    align-items: baseline;
    padding: 0.75rem 0;
    border-bottom: 0.0625rem solid var(--gray-border-light);
}

.plan-fact dt {
    color: var(--fs-text-muted);
    font-size: var(--fs-text-sm);
    font-weight: 400;
}

.plan-fact dd {
    margin: 0;
    min-width: 0;
}

.plan-fact-missing {
    color: var(--fs-text-muted);
    font-style: italic;
}

.plan-fact-action {
    display: inline-block;
    margin-inline-start: 0.5rem;
    font-size: var(--fs-text-sm);
}

/* Auf schmalen Bildschirmen steht die Bezeichnung ueber dem Wert: 9rem fuer das
   Wort und der Rest fuer eine Anschrift geht sich dort nicht mehr aus. */
@media (max-width: 30rem) {
    .plan-fact {
        grid-template-columns: 1fr;
        gap: 0.25rem;
    }
}

/* Der Grund, warum der Knopf darunter grau ist. Keine Alert-Box: das waere ein
   Abschnitt fuer einen Satz, und der Satz gehoert an den Knopf. */
.plan-blocked {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    color: var(--fs-text-muted);
    font-size: var(--fs-text-sm);
}

.plan-blocked .material-symbols-outlined {
    font-size: var(--fs-text-lg);
    color: var(--warning-text);
}

/* Der Kauf ist das Ziel dieser Karte und bekommt ihre Breite. */
.plan-submit {
    width: 100%;
}

/* Die Karten der Uebungswelt im Hinweis an der Kasse. Die Nummer steht vorn und
   laesst sich in einem Zug markieren, die Erklaerung daneben. */
.test-card-list {
    list-style: none;
    margin: 0.5rem 0 0;
    padding: 0;
}

.test-card-list li {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
}

.test-card-list li + li {
    margin-top: 0.25rem;
}

/* Vorlage tab — delete icon in the audience table */
.reuse-row-icon {
    font-size: 1rem;
}

/* Der Item-Assistent im Dialog: Kopfzeile und Knopfleiste stehen fest, gescrollt
   wird nur der Inhalt des Reiters. Ohne min-height: 0 waechst der Dialogkoerper
   mit seinem Inhalt ueber die Maximalhoehe hinaus, und die Knoepfe unten
   verschwinden aus dem Bild. */
/* Der Dialog nimmt von Anfang an die volle verfuegbare Hoehe ein, statt mit dem
   Inhalt zu wachsen: sonst springt die Knopfleiste beim Reiterwechsel. */
.item-wizard-modal-content {
    height: 100%;
    max-height: 100%;
}

.item-wizard-modal-body {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

/* Die Laenderauswahl im Suchauftrag: 195 Haken passen auf keinen Bildschirm, und
   ein Dialog, der die ganze Seite lang wird, verliert seine Knopfleiste aus dem
   Bild. Deshalb mehrspaltig und mit eigenem Rollbalken. */
.country-picker {
    max-height: 22rem;
    overflow-y: auto;
    columns: 3;
    column-gap: 1rem;
    border: 0.0625rem solid var(--gray-border-light);
    border-radius: 0.5rem;
    padding: 0.75rem;
}

@media (max-width: 768px) {
    .country-picker {
        columns: 1;
    }
}

/* Der Abmeldeweg aus einem Anschreiben. Eine Seite mit drei Saetzen darauf, und
   die stehen nicht am oberen Rand geklebt. */
.unsubscribe-page {
    max-width: 40rem;
    padding: 4rem 1rem;
}

/* Der Kopf eines Abschnitts traegt den Namen und daneben vier Knoepfe. Auf einem
   Telefon passt beides nicht in eine Zeile, und ohne Umbruch schiebt es die Knoepfe
   aus dem Bild. Sie ruecken dann unter den Namen. */
.accordion-button {
    flex-wrap: wrap;
    row-gap: 0.5rem;
}

/* Werkzeugleisten mit zwei Gruppen (Knoepfe links, Filter rechts) brechen um, statt
   die rechte Gruppe aus dem Bild zu schieben. */
.toolbar-wrap {
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* ── Tutorials ──────────────────────────────────────────────────────────────
   Die Bibliothek im Hilfebereich, der Spieler daneben und die drei Spalten der
   Verwaltung. Die Bilder sind das, was hier zaehlt, deshalb bleibt alles andere
   zurueckhaltend. */

.tutorial-video {
    width: 100%;
    max-height: 70vh;
    border-radius: var(--radius-md);
    background: var(--gray-dark);
}

.tutorial-player-description {
    margin: 1rem 0 0;
    color: var(--gray-text-secondary);
}

/* Die Auswahl zwischen mehreren Videos eines Kapitels steht ueber dem Bild und
   wird seitlich gewischt, statt den Spieler nach unten zu druecken. */
.tutorial-picker {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding-bottom: 0.75rem;
}

.tutorial-picker-item {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    flex: 0 0 auto;
    padding: 0.375rem 0.75rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--gray-text-secondary);
    font-size: var(--fs-text-sm);
    cursor: pointer;
}

.tutorial-picker-item .material-symbols-outlined {
    font-size: var(--fs-text-lg);
}

.tutorial-picker-item-active {
    border-color: var(--primary);
    background: var(--selected-bg);
    color: var(--gray-dark);
}

/* --- Bibliothek ------------------------------------------------------------ */

.tutorial-topic {
    margin-bottom: 2.5rem;
}

.tutorial-topic-head {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.tutorial-topic-icon {
    font-size: 2rem;
    color: var(--primary);
}

.tutorial-topic-title {
    margin: 0;
    font-size: var(--fs-text-xl);
}

.tutorial-topic-description {
    margin: 0.25rem 0 0;
    color: var(--gray-text-secondary);
}

.tutorial-chapter {
    margin-bottom: 1.5rem;
}

.tutorial-chapter-title {
    margin: 0;
    font-size: var(--fs-text-md);
}

.tutorial-chapter-description {
    margin: 0.125rem 0 0.75rem;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

.tutorial-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    gap: 0.75rem;
}

.tutorial-card {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.875rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background: var(--surface);
    text-align: left;
    cursor: pointer;
}

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

.tutorial-card-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: var(--radius-pill);
    background: var(--selected-bg);
    color: var(--primary);
}

.tutorial-card-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

.tutorial-card-title {
    font-weight: 600;
    color: var(--gray-dark);
}

.tutorial-card-description {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

/* --- Verwaltung ------------------------------------------------------------ */

.tutorial-empty-icon {
    font-size: 2.5rem;
}

.tutorial-count {
    font-size: var(--fs-text-sm);
}

.tutorial-icon {
    font-size: 1rem;
}

/* Was nicht aktiv ist, bleibt lesbar und tritt zurueck. */
.tutorial-inactive {
    opacity: 0.55;
}

.tutorial-row {
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--gray-border-light);
}

.tutorial-row:last-child {
    border-bottom: none;
}

.tutorial-row-title {
    font-weight: 600;
}

.tutorial-row-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    font-size: var(--fs-text-sm);
}

.tutorial-row-anchor {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

.tutorial-row-anchor .material-symbols-outlined {
    font-size: var(--fs-text-base);
}

.tutorial-video-box {
    padding: 1rem;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background: var(--surface-sunk);
}

/* Das Dateifeld liegt unsichtbar ueber dem Knopf, damit der Knopf aussieht wie
   jeder andere und trotzdem den Dateidialog oeffnet. */
.tutorial-upload-label {
    position: relative;
    overflow: hidden;
    cursor: pointer;
}

.tutorial-upload-input {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
}

/* ── Gespielte Tutorials ────────────────────────────────────────────────────
   Die Buehne baut die Oberflaeche aus unseren eigenen Klassen nach. Hier steht
   nur, was zum Spielen dazukommt: der Zeiger, die Hervorhebung, der Untertitel
   und der Rahmen drumherum. */

.ts-stage {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background: var(--surface-subtle);
    padding: 1.25rem;
    min-height: 22rem;
}

.ts-screen {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* --- Bausteine ------------------------------------------------------------- */

.ts-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--gray-border-light);
}

.ts-header-title {
    font-size: var(--fs-text-2xl);
    font-weight: 600;
}

.ts-text {
    margin: 0;
    color: var(--gray-text-secondary);
}

.ts-field {
    max-width: 26rem;
}

/* Das Eingabefeld ist keins: es zeigt nur, was jemand tippen wuerde. */
.ts-input {
    display: flex;
    align-items: center;
    min-height: 2.5rem;
    background: var(--surface);
}

.ts-caret {
    display: inline-block;
    width: 1px;
    height: 1.1em;
    margin-left: 1px;
    background: transparent;
}

.ts-caret-on {
    background: var(--gray-dark);
    animation: ts-blink 1s steps(1) infinite;
}

@keyframes ts-blink {
    50% { opacity: 0; }
}

.ts-table {
    margin: 0;
    background: var(--surface);
}

.ts-tabs {
    display: flex;
    gap: 0.25rem;
    border-bottom: 1px solid var(--gray-border-light);
}

.ts-tab {
    padding: 0.375rem 0.75rem;
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
    border-bottom: 2px solid transparent;
}

.ts-tab-active {
    color: var(--gray-dark);
    border-bottom-color: var(--primary);
}

/* Ein Dialog liegt auf der Buehne, nicht ueber dem Bildschirm: er gehoert zum
   gezeigten Ausschnitt und nicht zur Anwendung, in der man gerade sitzt. */
.ts-modal {
    align-self: center;
    width: min(30rem, 100%);
    border: 1px solid var(--gray-border-light);
    border-radius: var(--radius-md);
    background: var(--surface);
    box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.18);
    animation: ts-modal-in 0.3s ease-out;
}

@keyframes ts-modal-in {
    from { opacity: 0; transform: translateY(-0.75rem); }
    to   { opacity: 1; transform: none; }
}

.ts-modal-head {
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--gray-border-light);
    font-size: var(--fs-text-md);
    font-weight: 600;
}

.ts-modal-body {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1rem;
}

/* --- Spielen --------------------------------------------------------------- */

/* Was gerade gezeigt wird, tritt hervor, ohne dass sich seine Groesse aendert:
   ein springendes Layout waere schwerer zu verfolgen als der Zeiger. */
.ts-marked {
    outline: 2px solid var(--primary);
    outline-offset: 3px;
    border-radius: var(--radius-sm);
}

.ts-pointer {
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    color: var(--gray-dark);
    transition: transform 0.55s cubic-bezier(0.35, 0.1, 0.25, 1), opacity 0.25s;
}

.ts-pointer-visible {
    opacity: 1;
}

.ts-pointer .material-symbols-outlined {
    font-size: 1.75rem;
    filter: drop-shadow(0 1px 2px rgba(255, 255, 255, 0.9));
}

.ts-pointer-click .material-symbols-outlined {
    animation: ts-click 0.35s ease-out;
}

@keyframes ts-click {
    0%   { transform: scale(1); }
    45%  { transform: scale(0.75); }
    100% { transform: scale(1); }
}

.ts-subtitle {
    position: absolute;
    left: 1.25rem;
    right: 1.25rem;
    bottom: 1rem;
    padding: 0.625rem 0.875rem;
    border-radius: var(--radius-md);
    background: rgba(28, 32, 27, 0.88);
    color: #fff;
    font-size: var(--fs-text-sm);
    line-height: 1.45;
}

/* --- Steuerung ------------------------------------------------------------- */

.ts-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.ts-marks {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    flex: 1 1 auto;
}

.ts-mark {
    flex: 1 1 auto;
    height: 0.375rem;
    max-width: 6rem;
    border: none;
    border-radius: var(--radius-pill);
    background: var(--gray-border-light);
    cursor: pointer;
    transition: background 0.2s;
}

.ts-mark:hover {
    background: var(--text-subtle);
}

.ts-mark-active {
    background: var(--primary);
}

.ts-position {
    font-size: var(--fs-text-sm);
    color: var(--gray-text-secondary);
}

/* Das Skript wird geschrieben wie Code und soll auch so aussehen. */
.ts-editor {
    font-family: var(--font-monospace, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: var(--fs-text-sm);
    line-height: 1.5;
    white-space: pre;
    overflow-x: auto;
}
