/* ==========================================================================
   SUCCUBUS HELL — Design-System
   Sehr dunkles Anthrazit, Türkis als Hauptakzent, Gold für Regel- und
   Ranginformationen, Blau für Systeminfos, Rot ausschließlich für Warnung
   und Löschen. Dezente Rahmen, geringe Rundungen, hohe Informationsdichte.
   ========================================================================== */

:root {
    /* Flächen */
    --sh-bg: #0b0d10;
    --sh-bg-2: #101319;
    --sh-surface: #161a21;
    --sh-surface-2: #1c212a;
    --sh-surface-3: #232935;
    --sh-overlay: rgba(6, 8, 11, .78);

    /* Rahmen */
    --sh-border: #262d38;
    --sh-border-soft: #1e242d;
    --sh-border-strong: #36404f;
    /* Der Rand eines Eingabefelds. Er ist das Einzige, woran man ein leeres Feld
       erkennt, und braucht deshalb 3 : 1 gegen die Fläche, auf der das Feld steht
       (WCAG 1.4.11). --sh-border erreichte 1,26, --sh-border-strong 1,66; das ist
       der kleinste Schritt heller in der Farbe von --sh-border-strong, der auf
       Seite, eingelassener Karte und Karte trägt (UI-009). */
    --sh-border-field: #57677f;

    /* Text */
    --sh-text: #dde3ec;
    --sh-text-dim: #97a1b1;
    /* Die leiseste Textstufe. Bis zum 26.09.2026 #6a7385 — das stand auf keiner
       Fläche bei 4,5 : 1 (3,06 auf --sh-surface-3, 3,66 auf der Karte). #8790a0 ist
       der kleinste Schritt in derselben Farbe, der auf jeder Fläche trägt (UI-009,
       BarrierefreiheitWaechterTests). */
    --sh-text-faint: #8790a0;
    --sh-text-invert: #07090c;

    /* Akzente */
    --sh-accent: #2fd4c4;
    --sh-accent-dim: #1f9c91;
    --sh-accent-soft: rgba(47, 212, 196, .12);
    --sh-accent-line: rgba(47, 212, 196, .35);

    --sh-gold: #d9b45a;
    --sh-gold-dim: #a5863c;
    --sh-gold-soft: rgba(217, 180, 90, .12);

    --sh-blue: #5b9cf0;
    --sh-blue-soft: rgba(91, 156, 240, .12);

    /* #e05561 bis zum 26.09.2026: 3,92 auf --sh-surface-3 und 3,76 auf der eigenen
       Tönung über --sh-surface-2 (Löschknopf im Fensterfuss). Kleinster Schritt
       heller in derselben Farbe (UI-009). */
    --sh-danger: #e46d77;
    --sh-danger-dim: #a63b45;
    --sh-danger-soft: rgba(224, 85, 97, .13);

    --sh-success: #4fbf7b;
    --sh-success-soft: rgba(79, 191, 123, .12);

    --sh-warn: #e0a23c;
    --sh-warn-soft: rgba(224, 162, 60, .12);

    /* #a97bd6 bis zum 26.09.2026: 4,21 auf der eigenen Tönung über --sh-surface-2.
       Kleinster Schritt heller in derselben Farbe (UI-009). */
    --sh-purple: #ad82d8;
    --sh-purple-soft: rgba(169, 123, 214, .12);

    /* Erhöhte Fläche für Karten, die sich abheben sollen. */
    --sh-surface-raised: #1f2530;

    /* Maße */
    --sh-radius: 4px;
    --sh-radius-lg: 6px;
    --sh-radius-xl: 10px;
    /* Die volle Rundung, die aus einem Rechteck eine Pille macht. Als Stufe
       geführt, weil sonst an jeder Fortschrittsleiste und jedem Abzeichen die
       nackte 999 steht und niemand mehr sieht, dass alle dasselbe meinen. */
    --sh-radius-pill: 999px;
    --sh-nav-w: 232px;
    --sh-topbar-h: 52px;
    --sh-gap: 12px;

    /* Abstandsstufen. Zentral, damit nirgends 7px, 13px und 19px nebeneinander
       stehen — verstreute Einzelwerte sind der Grund, warum Oberflächen mit der
       Zeit unruhig werden (REQ-UX-018). Die kleinste Stufe trägt die Fälle, in
       denen zwei Zeilen nur noch getrennt und nicht mehr abgesetzt werden
       sollen — vorher stand dafür überall eine handgeschriebene 2px. */
    --sh-space-2xs: 2px;
    --sh-space-xs: 4px;
    --sh-space-sm: 8px;
    --sh-space-md: 12px;
    --sh-space-lg: 18px;
    --sh-space-xl: 28px;

    /* Übergangsdauer: kurz genug, um nicht zu bremsen (REQ-UX-017). */
    --sh-fast: 120ms;
    --sh-slow: 200ms;

    --sh-shadow: 0 2px 10px rgba(0, 0, 0, .45);
    --sh-shadow-lg: 0 12px 40px rgba(0, 0, 0, .6);
    --sh-shadow-glow: 0 0 0 1px var(--sh-accent-line), 0 4px 18px rgba(47, 212, 196, .12);

    /* Der Fokusring ohne seine Farbe: Versatz und Breite stehen einmal hier,
       die Farbe setzt die Stelle, die ihn benutzt — geschrieben als
       box-shadow: var(--sh-ring) var(--sh-accent-soft). So bleibt der Ring an
       Eingabefeld, Fehlerfeld und Altfeld garantiert gleich breit. */
    --sh-ring: 0 0 0 3px;

    /* Typografie */
    --sh-font: "Segoe UI", "Inter", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --sh-font-mono: "Cascadia Mono", "JetBrains Mono", Consolas, "SF Mono", monospace;
    --sh-fs: 13.5px;
}

/* ------------------------------------------------------------------ Basis */

*, *::before, *::after { box-sizing: border-box; }

html, body {
    height: 100%;
}

body {
    margin: 0;
    background: var(--sh-bg);
    color: var(--sh-text);
    font-family: var(--sh-font);
    font-size: var(--sh-fs);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
    margin: 0 0 .5em;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -.01em;
    color: var(--sh-text);
}

h1 { font-size: 1.5rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1.02rem; }
h4 { font-size: .93rem; }
h5, h6 { font-size: .86rem; }

p { margin: 0 0 .7em; }
p:last-child { margin-bottom: 0; }

a {
    color: var(--sh-accent);
    text-decoration: none;
}
a:hover { color: #57e5d7; text-decoration: underline; }

hr {
    border: 0;
    border-top: 1px solid var(--sh-border);
    margin: 1rem 0;
}

code, kbd, pre, samp { font-family: var(--sh-font-mono); font-size: .92em; }

code {
    background: var(--sh-surface-2);
    border: 1px solid var(--sh-border-soft);
    border-radius: 3px;
    padding: .06em .34em;
    color: var(--sh-accent);
}

pre {
    background: var(--sh-bg-2);
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    padding: .7rem .85rem;
    overflow-x: auto;
}
pre code { background: none; border: 0; padding: 0; color: var(--sh-text); }

blockquote {
    margin: 0 0 .8em;
    padding: .4rem .9rem;
    border-left: 2px solid var(--sh-accent-line);
    background: var(--sh-accent-soft);
    color: var(--sh-text-dim);
}

::selection { background: var(--sh-accent-dim); color: #04120f; }

/* Scrollbars */
* { scrollbar-width: thin; scrollbar-color: var(--sh-border-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: var(--sh-border-strong);
    border-radius: 6px;
    border: 2px solid var(--sh-bg);
}
*::-webkit-scrollbar-thumb:hover { background: #47546a; }

/* --------------------------------------------------------------- Layout */

.sh-app {
    display: grid;
    grid-template-columns: var(--sh-nav-w) 1fr;
    grid-template-rows: var(--sh-topbar-h) 1fr;
    grid-template-areas: "brand top" "nav main";
    height: 100vh;
    overflow: hidden;
}

.sh-brand {
    grid-area: brand;
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: 0 .8rem;
    background: var(--sh-bg-2);
    border-right: 1px solid var(--sh-border);
    border-bottom: 1px solid var(--sh-border);
    min-width: 0;
}

.sh-brand__mark {
    width: 26px;
    height: 26px;
    flex: 0 0 26px;
    display: grid;
    place-items: center;
    border-radius: var(--sh-radius);
    background: linear-gradient(140deg, var(--sh-accent-dim), #124f4a);
    color: #04120f;
    font-weight: 700;
    font-size: .78rem;
    letter-spacing: -.03em;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .09);
}

.sh-brand__text { min-width: 0; }
.sh-brand__title {
    font-size: .87rem;
    font-weight: 700;
    letter-spacing: .01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sh-brand__sub {
    font-size: .66rem;
    color: var(--sh-text-faint);
    text-transform: uppercase;
    letter-spacing: .08em;
    white-space: nowrap;
}

.sh-topbar {
    grid-area: top;
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: 0 .85rem;
    background: var(--sh-bg-2);
    border-bottom: 1px solid var(--sh-border);
    min-width: 0;
}

.sh-nav {
    grid-area: nav;
    background: var(--sh-bg-2);
    border-right: 1px solid var(--sh-border);
    overflow-y: auto;
    overflow-x: hidden;
    padding: .5rem 0 1.5rem;
}

.sh-main {
    grid-area: main;
    overflow-y: auto;
    /* UI-015: Das bleibt hidden und wird nicht auf auto gestellt. Es faengt ab,
       was sonst den ganzen Body waagerecht scrollen liesse — genau das verbietet
       REQ-UX-021. Der Preis war frueher abgeschnittener Inhalt ohne Bildlaufleiste;
       den zahlt jetzt niemand mehr, weil jede Tabelle in .sh-table-wrap sitzt und
       ihren Bildlauf selbst mitbringt. Wer hier auf auto stellt, tauscht einen
       Kasten mit Bildlauf gegen eine wackelnde Seite. */
    overflow-x: hidden;
    background: var(--sh-bg);
    scroll-behavior: smooth;
}

.sh-main__inner {
    padding: 1rem 1.15rem 3rem;
    max-width: 1720px;
    margin: 0 auto;
}

/* Zweispaltige Detailansicht: Inhalt + rechte Kontextspalte.

   Diese Klassen werden seit UI-014 (03.09.2026) ausschliesslich von
   Components/Shared/Kontextspalte.razor gesetzt. Keine Ansicht schreibt sie mehr
   selbst hin. Wer hier etwas aendert, aendert es fuer alle Kontextspalten auf
   einmal — und genau das ist der Zweck.

   Der Umbruch auf schmale Breiten steht an genau einer Stelle: im Regelblock bei
   1200 px weiter unten. Der Druck ebenso, im @media print. */
.sh-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: var(--sh-gap);
    align-items: start;
}
.sh-split--wide { grid-template-columns: minmax(0, 1fr) 380px; }
/* Steht die Seitenspalte im Quelltext VOR dem Inhalt — wie die Schrittliste des
   Wizards —, muss die schmale Spalte die erste sein. Sonst bekommt die
   Navigation den 1fr-Anteil und der eigentliche Inhalt wird zusammengequetscht. */
.sh-split--nav { grid-template-columns: 300px minmax(0, 1fr); }
.sh-split__aside { position: sticky; top: 0; display: grid; gap: var(--sh-gap); }

/* Die Stufenskala 0–5 gehört in eine Zeile. Bricht sie um, wird aus jeder
   Fertigkeit ein sechszeiliger Block und die Tabelle unlesbar. */
.sh-scale { flex-wrap: nowrap; justify-content: flex-end; }
.sh-scale > .sh-chip {
    min-width: 1.75rem;
    justify-content: center;
    cursor: pointer;
    font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------- Navigation */

.sh-nav__group { margin-bottom: .35rem; }

.sh-nav__label {
    padding: .55rem .9rem .3rem;
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--sh-text-faint);
}

.sh-nav__item {
    display: flex;
    align-items: center;
    gap: .55rem;
    width: 100%;
    padding: .36rem .9rem .36rem .8rem;
    border: 0;
    border-left: 2px solid transparent;
    background: none;
    color: var(--sh-text-dim);
    font: inherit;
    font-size: .84rem;
    text-align: left;
    cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
}

.sh-nav__item:hover {
    background: var(--sh-surface);
    color: var(--sh-text);
    text-decoration: none;
}

.sh-nav__item.is-active {
    background: var(--sh-accent-soft);
    border-left-color: var(--sh-accent);
    color: var(--sh-accent);
    font-weight: 600;
}

.sh-nav__icon {
    flex: 0 0 16px;
    width: 16px;
    height: 16px;
    opacity: .85;
}
.sh-nav__item.is-active .sh-nav__icon { opacity: 1; }

.sh-nav__count {
    margin-left: auto;
    font-size: .68rem;
    color: var(--sh-text-faint);
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------ Karten */

.sh-card {
    background: var(--sh-surface);
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    overflow: hidden;
}

.sh-card__head {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--sh-border);
    background: var(--sh-surface-2);
    min-height: 38px;
}

.sh-card__title {
    margin: 0;
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--sh-text-dim);
}

.sh-card__actions { margin-left: auto; display: flex; gap: .35rem; align-items: center; }
.sh-card__body { padding: .75rem; }
.sh-card__body--flush { padding: 0; }
.sh-card__foot {
    padding: .5rem .75rem;
    border-top: 1px solid var(--sh-border);
    background: var(--sh-surface-2);
}

/* Akzentvarianten */
.sh-card--rule { border-color: rgba(217, 180, 90, .3); }
.sh-card--rule .sh-card__head { background: var(--sh-gold-soft); }
.sh-card--rule .sh-card__title { color: var(--sh-gold); }

.sh-card--system { border-color: rgba(91, 156, 240, .3); }
.sh-card--system .sh-card__head { background: var(--sh-blue-soft); }
.sh-card--system .sh-card__title { color: var(--sh-blue); }

.sh-card--danger { border-color: rgba(224, 85, 97, .35); }
.sh-card--danger .sh-card__head { background: var(--sh-danger-soft); }
.sh-card--danger .sh-card__title { color: var(--sh-danger); }

/* ------------------------------------------------------------- Raster */

.sh-grid { display: grid; gap: var(--sh-gap); }
.sh-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.sh-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.sh-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Warum in jeder Rasterspalte ein min(…, 100%) steht (UX-020, REQ-UX-021).

   `minmax(230px, 1fr)` heisst woertlich: Diese Spalte ist NIE schmaler als 230 Pixel.
   Auf einem 360 Pixel breiten Bildschirm mit Polsterung ringsum ist das mehr, als da
   ist — die Spalte laeuft ueber den Rand hinaus, und die ganze Seite bekommt eine
   waagerechte Bildlaufleiste. `auto-fill` hilft dabei nicht: Es entscheidet, WIE VIELE
   Spalten passen, nicht wie schmal eine werden darf.

   `min(230px, 100%)` heisst stattdessen: 230 Pixel, solange 230 Pixel da sind, sonst die
   volle Breite. Oberhalb von 230 Pixeln ist der Wert Zeichen fuer Zeichen derselbe; es
   aendert sich ausschliesslich der Fall, in dem das Raster bisher ueberlief. */
.sh-grid--auto { grid-template-columns: repeat(auto-fill, minmax(min(230px, 100%), 1fr)); }
.sh-grid--cards { grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); }

/* Charakterkacheln sind portraitbetont und brauchen deshalb spuerbar mehr Breite als
   eine gewoehnliche Karte (REQ-UX-032). 320px ergibt um 1366px herum drei Kacheln je
   Reihe, auf dem Tablet zwei bis drei und auf dem Telefon eine; auf sehr breiten
   Bildschirmen werden es fuenf.

   Mit 260px wie bei .sh-grid--cards entstanden sechs schmale Mini-Karten — daher der
   groessere Wert. Auf 360px erhoeht und damit auf vier begrenzt wurde bewusst NICHT:
   Der Nutzer hat die Darstellung mit fuenf Kacheln am 20.08.2026 ausdruecklich als
   passend bestaetigt.

   min() faengt den Fall ab, dass der Bildschirm schmaler ist als die Mindestbreite:
   Ohne das entstuende eine waagerechte Bildlaufleiste (REQ-UX-021). */
.sh-grid--chars { grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); }
.sh-grid--tiles { grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); }
/* Vorschaubilder dürfen großzügig sein — es sind Bilder, keine Symbole. 150px statt
   200px, weil die Galerie in einer Übersichtskarte steht: Bei 200px füllen zwölf
   Bilder die halbe Seite. min() verhindert die waagerechte Bildlaufleiste auf
   schmalen Geräten (REQ-UX-021). */
.sh-grid--gallery { grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); }

.sh-stack { display: grid; gap: var(--sh-gap); }
.sh-stack--tight { gap: .5rem; }

.sh-row {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
}
.sh-row--tight { gap: .3rem; }
.sh-row--between { justify-content: space-between; }
.sh-row--end { justify-content: flex-end; }
.sh-spacer { flex: 1 1 auto; }

/* ------------------------------------------------------- Seitenkopf */

.sh-page-head {
    display: flex;
    align-items: flex-start;
    gap: .8rem;
    margin-bottom: 1rem;
    padding-bottom: .7rem;
    border-bottom: 1px solid var(--sh-border);
    flex-wrap: wrap;
}

.sh-page-head__text { min-width: 0; flex: 1 1 320px; }

.sh-page-head h1 {
    margin: 0;
    font-size: 1.32rem;
    letter-spacing: -.015em;
}

.sh-page-head__sub {
    margin: .18rem 0 0;
    color: var(--sh-text-dim);
    font-size: .84rem;
}

.sh-page-head__actions { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; }

.sh-eyebrow {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--sh-accent);
    margin-bottom: .15rem;
}

/* ------------------------------------------------------------ Buttons */

.sh-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .38rem;
    padding: .34rem .7rem;
    min-height: 30px;
    border: 1px solid var(--sh-border-strong);
    border-radius: var(--sh-radius);
    background: var(--sh-surface-2);
    color: var(--sh-text);
    font: inherit;
    font-size: .82rem;
    font-weight: 500;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    transition: background .12s, border-color .12s, color .12s, opacity .12s;
    text-decoration: none;
}

.sh-btn:hover:not(:disabled) {
    background: var(--sh-surface-3);
    border-color: #465468;
    color: var(--sh-text);
    text-decoration: none;
}

.sh-btn:disabled, .sh-btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

.sh-btn:focus-visible,
.sh-input:focus-visible,
.sh-nav__item:focus-visible,
.sh-tab:focus-visible,
a:focus-visible {
    outline: 2px solid var(--sh-accent);
    outline-offset: 1px;
}

.sh-btn--primary {
    background: var(--sh-accent-dim);
    border-color: var(--sh-accent-dim);
    color: #04120f;
    font-weight: 600;
}
.sh-btn--primary:hover:not(:disabled) { background: var(--sh-accent); border-color: var(--sh-accent); color: #04120f; }

.sh-btn--gold {
    background: transparent;
    border-color: var(--sh-gold-dim);
    color: var(--sh-gold);
}
.sh-btn--gold:hover:not(:disabled) { background: var(--sh-gold-soft); border-color: var(--sh-gold); color: var(--sh-gold); }

.sh-btn--ghost { background: transparent; border-color: transparent; color: var(--sh-text-dim); }
.sh-btn--ghost:hover:not(:disabled) { background: var(--sh-surface-2); color: var(--sh-text); }

.sh-btn--danger { background: transparent; border-color: var(--sh-danger-dim); color: var(--sh-danger); }
.sh-btn--danger:hover:not(:disabled) { background: var(--sh-danger-soft); border-color: var(--sh-danger); }

.sh-btn--sm { min-height: 25px; padding: .17rem .5rem; font-size: .76rem; }
.sh-btn--xs { min-height: 22px; padding: .1rem .42rem; font-size: .72rem; }
.sh-btn--lg { min-height: 38px; padding: .5rem 1.1rem; font-size: .92rem; }
.sh-btn--block { width: 100%; }
.sh-btn--icon { padding: .3rem; min-width: 30px; }
.sh-btn--icon.sh-btn--sm { min-width: 25px; padding: .17rem; }

.sh-btn__icon { width: 15px; height: 15px; flex: 0 0 15px; }

/* Buttongruppe */
.sh-btn-group { display: inline-flex; }
.sh-btn-group .sh-btn { border-radius: 0; margin-left: -1px; }
.sh-btn-group .sh-btn:first-child { border-radius: var(--sh-radius) 0 0 var(--sh-radius); margin-left: 0; }
.sh-btn-group .sh-btn:last-child { border-radius: 0 var(--sh-radius) var(--sh-radius) 0; }
.sh-btn-group .sh-btn.is-active { background: var(--sh-accent-soft); border-color: var(--sh-accent-line); color: var(--sh-accent); z-index: 1; }

/* ----------------------------------------------------------- Formulare */

/* Feld und Beschriftung stehen seit dem 04.09.2026 nur noch HIER (UX-020).

   Beide waren zweimal deklariert - einmal an dieser Stelle, einmal rund 1900 Zeilen
   weiter unten. Die zweite gewann, weil sie spaeter kommt, und nahm dabei die Haelfte
   der ersten mit. Das war nicht bloss unuebersichtlich, es war ein Fehler: Der Modifikator
   `.sh-field--inline` steht ZWISCHEN den beiden. Er setzt `display: flex`, damit
   Beschriftung und Feld nebeneinander stehen - und wurde von der zweiten `.sh-field`
   dahinter wieder auf `display: grid` gezogen. An acht Stellen im Bestand steht
   `class="sh-field sh-field--inline"`, und an keiner davon tat der Modifikator etwas.

   Die Werte hier sind die, die tatsaechlich gewirkt haben: `gap` aus der zweiten,
   `min-width` und die Schriftauszeichnung aus der ersten. Am Aussehen aendert sich damit
   nur das eine, was sich aendern soll. */
.sh-field { display: grid; gap: .2rem; min-width: 0; }

.sh-label {
    display: block;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--sh-text-dim);
    margin-bottom: .2rem;
}

.sh-hint { font-size: .74rem; color: var(--sh-text-faint); }
.sh-error { font-size: .76rem; color: var(--sh-danger); }

.sh-input, .sh-select, .sh-textarea {
    width: 100%;
    padding: .34rem .55rem;
    min-height: 30px;
    background: var(--sh-bg-2);
    border: 1px solid var(--sh-border-field);
    border-radius: var(--sh-radius);
    color: var(--sh-text);
    font: inherit;
    font-size: .84rem;
    transition: border-color .12s, background .12s;
}

/* Hover hebt den Rand an. --sh-border-strong liegt seit UI-009 dunkler als der
   Ruherand und liesse ihn beim Überfahren verschwinden. */
.sh-input:hover, .sh-select:hover, .sh-textarea:hover { border-color: var(--sh-text-faint); }

.sh-input:focus, .sh-select:focus, .sh-textarea:focus {
    outline: none;
    border-color: var(--sh-accent);
    background: var(--sh-bg);
}

.sh-input::placeholder, .sh-textarea::placeholder { color: var(--sh-text-faint); }
.sh-input:disabled, .sh-select:disabled, .sh-textarea:disabled { opacity: .5; cursor: not-allowed; }
.sh-input.is-invalid, .sh-select.is-invalid, .sh-textarea.is-invalid { border-color: var(--sh-danger); }

.sh-textarea { min-height: 90px; resize: vertical; line-height: 1.55; }
.sh-textarea--tall { min-height: 220px; }

.sh-select {
    appearance: none;
    padding-right: 1.6rem;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2397a1b1'%3E%3Cpath d='M4.5 6.5 8 10l3.5-3.5z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right .35rem center;
    background-size: 15px;
}
.sh-select option { background: var(--sh-surface); color: var(--sh-text); }

.sh-check {
    display: inline-flex;
    align-items: center;
    gap: .42rem;
    cursor: pointer;
    font-size: .84rem;
    user-select: none;
}
.sh-check input[type="checkbox"], .sh-check input[type="radio"] {
    width: 15px; height: 15px; margin: 0;
    accent-color: var(--sh-accent);
    cursor: pointer;
    flex: 0 0 15px;
}

/* Ankreuzfeld mit Erklaerung darunter (Belegangaben, REQ-LORE-070).
   Die Grundform zentriert beide Zeilen an der Mitte des Kaestchens; bei zwei
   Zeilen gehoert das Kaestchen an die erste und nicht in die Mitte. */
.sh-check--stapel { display: flex; align-items: flex-start; margin: 0 0 .3rem; }
.sh-check--stapel input[type="checkbox"] { margin-top: .18rem; }
.sh-check--stapel > span { display: flex; flex-direction: column; gap: .1rem; }

.sh-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .65rem; }
.sh-form-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.sh-form-grid__full { grid-column: 1 / -1; }

.sh-search {
    position: relative;
    display: flex;
    align-items: center;
    min-width: 0;
}
.sh-search .sh-input { padding-left: 1.85rem; }
.sh-search__icon {
    position: absolute;
    left: .5rem;
    width: 14px; height: 14px;
    color: var(--sh-text-faint);
    pointer-events: none;
}

/* Nummernfeld für Punktvergabe */
.sh-stepper { display: inline-flex; align-items: center; gap: 0; }
.sh-stepper__btn {
    width: 24px; height: 24px;
    display: grid; place-items: center;
    border: 1px solid var(--sh-border);
    background: var(--sh-surface-2);
    color: var(--sh-text-dim);
    cursor: pointer;
    font-size: .9rem;
    line-height: 1;
    padding: 0;
}
.sh-stepper__btn:hover:not(:disabled) { background: var(--sh-surface-3); color: var(--sh-text); }
.sh-stepper__btn:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-stepper__btn:disabled { opacity: .35; cursor: not-allowed; }
.sh-stepper__btn:first-child { border-radius: var(--sh-radius) 0 0 var(--sh-radius); }
.sh-stepper__btn:last-child { border-radius: 0 var(--sh-radius) var(--sh-radius) 0; }
.sh-stepper__value {
    width: 34px; height: 24px;
    display: grid; place-items: center;
    border: 1px solid var(--sh-border);
    border-left: 0; border-right: 0;
    background: var(--sh-bg-2);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: .85rem;
}

/* --------------------------------------------------------------- Chips */

.sh-chip {
    display: inline-flex;
    align-items: center;
    gap: .28rem;
    padding: .1rem .42rem;
    border: 1px solid var(--sh-border);
    border-radius: 3px;
    background: var(--sh-surface-2);
    color: var(--sh-text-dim);
    font-size: .73rem;
    line-height: 1.5;
    white-space: nowrap;
    max-width: 100%;
    text-decoration: none;
}

a.sh-chip:hover, button.sh-chip:hover {
    border-color: var(--sh-accent-line);
    background: var(--sh-accent-soft);
    color: var(--sh-accent);
    text-decoration: none;
    cursor: pointer;
}
a.sh-chip:focus-visible, button.sh-chip:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 1px; }

button.sh-chip { font-family: inherit; cursor: pointer; }

.sh-chip__text { overflow: hidden; text-overflow: ellipsis; }

.sh-chip--accent { border-color: var(--sh-accent-line); background: var(--sh-accent-soft); color: var(--sh-accent); }
.sh-chip--gold { border-color: rgba(217, 180, 90, .35); background: var(--sh-gold-soft); color: var(--sh-gold); }
.sh-chip--blue { border-color: rgba(91, 156, 240, .35); background: var(--sh-blue-soft); color: var(--sh-blue); }
.sh-chip--danger { border-color: rgba(224, 85, 97, .35); background: var(--sh-danger-soft); color: var(--sh-danger); }
.sh-chip--success { border-color: rgba(79, 191, 123, .35); background: var(--sh-success-soft); color: var(--sh-success); }
.sh-chip--warn { border-color: rgba(224, 162, 60, .35); background: var(--sh-warn-soft); color: var(--sh-warn); }
.sh-chip--purple { border-color: rgba(169, 123, 214, .35); background: var(--sh-purple-soft); color: var(--sh-purple); }
.sh-chip--muted { color: var(--sh-text-faint); }

.sh-chip__x {
    display: grid; place-items: center;
    width: 13px; height: 13px;
    border: 0; padding: 0; margin-left: .1rem;
    background: none; color: inherit;
    opacity: .6; cursor: pointer;
    font-size: .8rem; line-height: 1;
}
.sh-chip__x:hover { opacity: 1; }
.sh-chip__x:focus-visible { opacity: 1; outline: 2px solid var(--sh-accent); outline-offset: 1px; }

/* ------------------------------------------------ Auswahlbausteine (UI-006) */

/* MultiSelect, EntityPicker und TagInput. Die Liste steht im Fluss der Seite und nicht
   als schwebendes Menü: Auf 360 Pixeln ragte ein Menü über den Rand, und es legte sich
   über das, was der Betrachter gerade liest. Treffflächen mindestens 2rem hoch. */
.sh-auswahl { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.sh-auswahl__suche { width: 100%; max-width: 28rem; }
.sh-auswahl__liste {
    display: flex; flex-direction: column;
    max-width: 28rem; max-height: 16rem; overflow-y: auto;
    border: 1px solid var(--sh-border); border-radius: var(--sh-radius);
    background: var(--sh-surface);
}
.sh-auswahl__option {
    display: flex; align-items: center; gap: .4rem;
    min-height: 2rem; padding: .3rem .55rem;
    border: 0; border-bottom: 1px solid var(--sh-border);
    background: none; color: var(--sh-text);
    font: inherit; font-size: .83rem; text-align: left; cursor: pointer;
}
.sh-auswahl__option:hover:not([aria-disabled="true"]), .sh-auswahl__option:focus-visible {
    background: var(--sh-accent-soft); outline: none;
}
.sh-auswahl__option:focus-visible { box-shadow: inset 0 0 0 2px var(--sh-accent-line); }
.sh-auswahl__option[aria-disabled="true"] { cursor: not-allowed; color: var(--sh-text-faint); }
.sh-auswahl__option.is-gewaehlt { font-weight: 600; }
.sh-auswahl__haken { display: inline-grid; place-items: center; width: 14px; flex: 0 0 14px; color: var(--sh-accent); }
.sh-auswahl__text { overflow: hidden; text-overflow: ellipsis; }
.sh-auswahl__leer { padding: .45rem .55rem; }
/* Portrait oder Anfangsbuchstaben vor einer Option (FAM-002). Ein Kreis wie das
   Benutzerbild, etwas grösser, weil hier ein Gesicht erkannt werden soll. */
.sh-auswahl__bild {
    width: 28px; height: 28px; flex: 0 0 28px;
    border-radius: 50%; overflow: hidden;
    display: grid; place-items: center;
    background: var(--sh-surface-2); color: var(--sh-text-dim);
    font-size: .68rem; font-weight: 700;
}
.sh-auswahl__bild img { width: 100%; height: 100%; object-fit: cover; object-position: var(--sh-focus, center); }
.sh-auswahl__gewaehlt { align-items: center; }
.sh-auswahl__fuss {
    display: flex; align-items: center; justify-content: space-between;
    gap: .4rem; padding: .25rem .4rem;
}
.sh-taginput { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.sh-taginput .sh-input { min-width: 0; flex: 1 1 10rem; max-width: 20rem; }
.sh-mb-xs { margin-bottom: var(--sh-space-xs); }

/* Tier-Badge: Gold für Ranginformationen */
.sh-tier {
    display: inline-grid;
    place-items: center;
    min-width: 21px;
    height: 19px;
    padding: 0 .28rem;
    border: 1px solid var(--sh-gold-dim);
    border-radius: 3px;
    background: var(--sh-gold-soft);
    color: var(--sh-gold);
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .02em;
    font-variant-numeric: tabular-nums;
}
.sh-tier--lg { min-width: 27px; height: 24px; font-size: .84rem; }

/* -------------------------------------------------------------- Tabs */

.sh-tabs {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--sh-border);
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
}
.sh-tabs::-webkit-scrollbar { display: none; }

.sh-tab {
    padding: .45rem .75rem;
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--sh-text-dim);
    font: inherit;
    font-size: .83rem;
    white-space: nowrap;
    cursor: pointer;
    transition: color .12s, border-color .12s;
}
.sh-tab:hover { color: var(--sh-text); }
.sh-tab.is-active { color: var(--sh-accent); border-bottom-color: var(--sh-accent); font-weight: 600; }
.sh-tab__count { margin-left: .3rem; font-size: .7rem; color: var(--sh-text-faint); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------ Tabellen */

/* Der scrollbare Kasten um jede Tabelle (UI-015). Er ist die Gegenseite zum
   overflow-x: hidden an .sh-main: dort wird abgeschnitten, was ueberlaeuft, und
   deshalb muss breiter Inhalt seinen eigenen Bildlauf mitbringen. */
.sh-table-wrap { overflow-x: auto; }

.sh-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .82rem;
}

.sh-table th {
    padding: .4rem .6rem;
    text-align: left;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--sh-text-faint);
    background: var(--sh-surface-2);
    border-bottom: 1px solid var(--sh-border);
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 1;
}

.sh-table td {
    padding: .4rem .6rem;
    border-bottom: 1px solid var(--sh-border-soft);
    vertical-align: middle;
}

.sh-table tbody tr:hover td { background: var(--sh-surface-2); }
.sh-table tbody tr:last-child td { border-bottom: 0; }
.sh-table--clickable tbody tr { cursor: pointer; }

/* Die Zeilenschaltfläche einer klickbaren Tabellenzeile (UI-009). Eine Zeile mit
   @onclick ist für die Maus da und für die Tastatur nicht: Ein <tr> nimmt keinen
   Fokus an, und role="button" nähme ihm die Zeilenbedeutung — ein Vorleseprogramm
   hörte keine Tabelle mehr. Deshalb steht der Titel der Zeile in einem echten
   <button>, OHNE eigenes @onclick: Sein Klick — auch der, den Enter und Leertaste
   auslösen — steigt zur Zeile auf und löst dort genau die eine Handlung aus. Ein
   eigenes @onclick daneben liefe doppelt. Aussehen wie der Text, den er umschliesst;
   sichtbar wird er erst mit dem Tastaturfokus. */
.sh-table__open {
    background: none; border: 0; padding: 0; margin: 0;
    font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.sh-table__open:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 2px; border-radius: var(--sh-radius); }
.sh-table__num { text-align: right; font-variant-numeric: tabular-nums; }
.sh-table__actions { text-align: right; white-space: nowrap; width: 1%; }

/* ------------------------------------------------- Definitionslisten */

.sh-dl {
    display: grid;
    grid-template-columns: minmax(90px, auto) minmax(0, 1fr);
    gap: .28rem .7rem;
    margin: 0;
    font-size: .83rem;
}
.sh-dl dt { color: var(--sh-text-faint); font-size: .76rem; }
.sh-dl dd { margin: 0; min-width: 0; word-break: break-word; }
.sh-dl--wide { grid-template-columns: minmax(130px, auto) minmax(0, 1fr); }

/* ---------------------------------------------------------- Statistik */

.sh-stat {
    display: grid;
    gap: .12rem;
    padding: .55rem .7rem;
    background: var(--sh-surface);
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
}
.sh-stat__value {
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
}
.sh-stat__label {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--sh-text-faint);
}
.sh-stat__hint { font-size: .73rem; color: var(--sh-text-dim); }
.sh-stat--accent .sh-stat__value { color: var(--sh-accent); }
.sh-stat--gold .sh-stat__value { color: var(--sh-gold); }
.sh-stat--blue .sh-stat__value { color: var(--sh-blue); }
.sh-stat--danger .sh-stat__value { color: var(--sh-danger); }

/* Dashboard-Kachel */
.sh-tile {
    display: grid;
    grid-template-rows: auto 1fr auto;
    gap: .3rem;
    padding: .7rem .8rem;
    background: var(--sh-surface);
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    color: inherit;
    text-align: left;
    font: inherit;
    cursor: pointer;
    transition: border-color .12s, background .12s, transform .12s;
    min-height: 92px;
}
.sh-tile:hover {
    border-color: var(--sh-accent-line);
    background: var(--sh-surface-2);
    text-decoration: none;
    transform: translateY(-1px);
}
.sh-tile:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 2px; }
.sh-tile__head { display: flex; align-items: center; gap: .4rem; }
.sh-tile__icon { width: 15px; height: 15px; color: var(--sh-accent); flex: 0 0 15px; }
.sh-tile__title {
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--sh-text-dim);
}
.sh-tile__value {
    font-size: 1.55rem;
    font-weight: 700;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
}
.sh-tile__hint { font-size: .72rem; color: var(--sh-text-faint); }
.sh-tile--gold:hover { border-color: rgba(217, 180, 90, .45); }
.sh-tile--gold .sh-tile__icon { color: var(--sh-gold); }
.sh-tile--gold .sh-tile__value { color: var(--sh-gold); }
.sh-tile--blue .sh-tile__icon { color: var(--sh-blue); }

/* -------------------------------------------------------- Attributsbalken */

.sh-attr {
    display: grid;
    grid-template-columns: 40px 1fr 26px;
    align-items: center;
    gap: .45rem;
    font-size: .8rem;
}
.sh-attr__key {
    font-weight: 700;
    font-size: .74rem;
    letter-spacing: .04em;
    color: var(--sh-text-dim);
    cursor: help;
}
.sh-attr__track {
    display: flex;
    gap: 2px;
    height: 8px;
}
.sh-attr__pip {
    flex: 1 1 0;
    background: var(--sh-surface-3);
    border-radius: 1px;
}
.sh-attr__pip.is-on { background: var(--sh-accent); }
.sh-attr__pip.is-core { background: var(--sh-gold); }
.sh-attr__pip.is-bonus { background: var(--sh-purple); }
.sh-attr__value {
    text-align: right;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    font-size: .85rem;
}
.sh-attr--zero .sh-attr__key,
.sh-attr--zero .sh-attr__value { color: var(--sh-text-faint); }

/* Punktebudget-Anzeige */
.sh-budget {
    display: flex;
    align-items: center;
    gap: .45rem;
    padding: .35rem .6rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface-2);
    font-size: .8rem;
}
.sh-budget__value { font-weight: 700; font-variant-numeric: tabular-nums; }
.sh-budget.is-ok { border-color: rgba(79, 191, 123, .4); }
.sh-budget.is-ok .sh-budget__value { color: var(--sh-success); }
.sh-budget.is-over { border-color: rgba(224, 85, 97, .45); background: var(--sh-danger-soft); }
.sh-budget.is-over .sh-budget__value { color: var(--sh-danger); }
.sh-budget.is-left .sh-budget__value { color: var(--sh-warn); }

/* --------------------------------------------------------- Charakterkarte */

.sh-charcard {
    display: grid;
    grid-template-rows: auto 1fr;
    background: var(--sh-surface);
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    overflow: hidden;
    cursor: pointer;
    text-align: left;
    color: inherit;
    font: inherit;
    padding: 0;
    transition: border-color .12s, transform .12s;
}
.sh-charcard:hover { border-color: var(--sh-accent-line); transform: translateY(-1px); text-decoration: none; }
.sh-charcard:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 2px; }

.sh-charcard__portrait {
    position: relative;
    aspect-ratio: 3 / 4;
    background: var(--sh-bg-2);
    overflow: hidden;
}
.sh-charcard__portrait img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}
.sh-charcard__placeholder {
    width: 100%; height: 100%;
    display: grid; place-items: center;
    color: var(--sh-text-faint);
    font-size: 1.7rem;
    font-weight: 700;
    background: linear-gradient(155deg, var(--sh-surface-2), var(--sh-bg-2));
}
.sh-charcard__kind {
    position: absolute;
    top: .35rem; left: .35rem;
    padding: .04rem .3rem;
    border-radius: 2px;
    background: rgba(6, 8, 11, .82);
    border: 1px solid var(--sh-border-strong);
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .06em;
    color: var(--sh-text-dim);
}
.sh-charcard__tier {
    position: absolute;
    top: .35rem; right: .35rem;
    display: flex; gap: .18rem;
}
.sh-charcard__body { padding: .5rem .6rem .6rem; display: grid; gap: .3rem; min-width: 0; }
.sh-charcard__name {
    font-size: .92rem;
    font-weight: 700;
    letter-spacing: -.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sh-charcard__meta {
    font-size: .74rem;
    color: var(--sh-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sh-charcard__tiers {
    display: flex;
    align-items: center;
    gap: .3rem;
    font-size: .7rem;
    color: var(--sh-text-faint);
    font-variant-numeric: tabular-nums;
}
.sh-charcard__chips { display: flex; gap: .22rem; flex-wrap: wrap; }

/* --------------------------------------------------------------- Galerie */

.sh-thumb {
    position: relative;
    display: block;

    /* Entscheidend: ein <button> ist ein Formularelement und schrumpft auf seinen
       Inhalt, statt seine Rasterzelle zu füllen. Ohne diese Zeile blieben die
       Vorschaubilder daumennagelgroß, egal wie breit die Spalte ist. */
    width: 100%;
    aspect-ratio: 1;
    background: var(--sh-bg-2);
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    overflow: hidden;
    cursor: pointer;
    padding: 0;
    transition: border-color .12s;
}
.sh-thumb:hover,
.sh-thumb:focus-visible { border-color: var(--sh-accent-line); }
.sh-thumb:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 2px; }

.sh-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .18s ease;

    /* Der Ausschnitt folgt dem am Bild gesetzten Schwerpunkt (REQ-MEDIA-016,
       REQ-MEDIA-025). Ohne diese Zeile bleibt die Stilangabe an der Kachelhuelle eine
       Kennung, die niemand liest — und zwar lautlos: kein Fehler, keine Meldung, das Bild
       schneidet weiter mittig. Genau das ist der Schritt, den man vergisst.

       Die Kennung --sh-focus setzt die Huelle und vererbt sie hierher. Gebildet wird der
       Zahlwert ausschliesslich im ImageFocusService, und zwar mit InvariantCulture: Unter
       deutscher Kultur entstuende "38,5%", das ist ungueltiges CSS, und der Browser wuerfe
       die ganze Deklaration stillschweigend weg.

       Der Ersatzwert "center" ist zeichengleich mit dem, was object-fit: cover ohne Angabe
       ohnehin tut. Es verschiebt sich damit an keiner Kachel des Bestands ein Pixel; wer
       keinen Schwerpunkt gesetzt hat, sieht genau das Bisherige. */
    object-position: var(--sh-focus, center);
}
.sh-thumb:hover img,
.sh-thumb:focus-visible img { transform: scale(1.04); }

/* Der Dateiname ist selten der Grund, warum jemand hinsieht — meist ist er eine
   Zufallsfolge wie „608a3c…jpg". Dauerhaft eingeblendet verdeckt er ein Sechstel des
   Bildes und wird trotzdem abgeschnitten. Er erscheint deshalb erst beim Zeigen; für
   alles andere trägt die Schaltfläche ein `title`. */
.sh-thumb__cap {
    position: absolute;
    inset: auto 0 0 0;
    padding: 1.1rem .45rem .32rem;
    background: linear-gradient(transparent, rgba(6, 8, 11, .93));
    font-size: .72rem;
    line-height: 1.2;
    color: var(--sh-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: left;
    opacity: 0;
    transition: opacity .14s ease;
}
.sh-thumb:hover .sh-thumb__cap,
.sh-thumb:focus-visible .sh-thumb__cap { opacity: 1; }

/* Zeigegeräteloser Betrieb: Ohne Hover gäbe es den Dateinamen sonst nie zu sehen. */
@media (hover: none) {
    .sh-thumb__cap { opacity: 1; }
    .sh-thumb:hover img { transform: none; }
}

.sh-thumb--wide { aspect-ratio: 4 / 3; }

/* Platzhalter, wenn kein Bild hinterlegt ist — es wird nie ein <img>
   mit ungültiger Adresse gerendert. */
.sh-noimage {
    display: grid;
    place-content: center;
    justify-items: center;
    gap: .3rem;
    width: 100%;
    height: 100%;
    min-height: 64px;
    padding: .6rem;
    text-align: center;
    background: linear-gradient(155deg, var(--sh-surface-2), var(--sh-bg-2));
    color: var(--sh-text-faint);
}

.sh-noimage__icon { opacity: .4; }

/* Kopfbereich der Charakterdetailansicht */
.sh-charhead { display: grid; grid-template-columns: 180px minmax(0, 1fr); gap: var(--sh-gap); }
.sh-charhead__portrait {
    aspect-ratio: 3 / 4;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    overflow: hidden;
    background: var(--sh-bg-2);
}
.sh-charhead__portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sh-charhead__body { min-width: 0; }

@media (max-width: 640px) {
    .sh-charhead { grid-template-columns: minmax(0, 1fr); }
    .sh-charhead__portrait { max-width: 200px; }
}

.sh-noimage__text {
    font-size: .72rem;
    line-height: 1.3;
    max-width: 16ch;
}

/* ---------------------------------------------------------------- Baum */

.sh-tree { font-size: .84rem; }
.sh-tree__node { display: grid; }
.sh-tree__row {
    display: flex;
    align-items: center;
    gap: .35rem;
    padding: .22rem .4rem;
    border-radius: 3px;
    cursor: pointer;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    width: 100%;
}
.sh-tree__row:hover { background: var(--sh-surface-2); }
.sh-tree__row:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-tree__row.is-active { background: var(--sh-accent-soft); color: var(--sh-accent); }
.sh-tree__toggle {
    width: 14px; height: 14px;
    display: grid; place-items: center;
    flex: 0 0 14px;
    color: var(--sh-text-faint);
    font-size: .7rem;
    background: none; border: 0; padding: 0; cursor: pointer;
}
.sh-tree__children {
    margin-left: .55rem;
    padding-left: .55rem;
    border-left: 1px solid var(--sh-border);
}
.sh-tree__meta { margin-left: auto; font-size: .7rem; color: var(--sh-text-faint); }

/* ------------------------------------------------------------ Timeline */

.sh-timeline { position: relative; padding-left: 1.1rem; }
.sh-timeline::before {
    content: "";
    position: absolute;
    left: 4px; top: .4rem; bottom: .4rem;
    width: 1px;
    background: var(--sh-border);
}
.sh-timeline__item { position: relative; padding: 0 0 .9rem; }
.sh-timeline__dot {
    position: absolute;
    left: -1.1rem; top: .32rem;
    width: 9px; height: 9px;
    border-radius: 50%;
    background: var(--sh-accent);
    box-shadow: 0 0 0 3px var(--sh-bg);
}
.sh-timeline__date {
    font-size: .71rem;
    color: var(--sh-text-faint);
    font-variant-numeric: tabular-nums;
}
.sh-timeline__title { font-weight: 600; font-size: .88rem; }

/* --------------------------------------------------------------- Modal */

.sh-modal-backdrop {
    position: fixed;
    inset: 0;
    background: var(--sh-overlay);
    display: grid;
    place-items: center;
    padding: 1rem;
    z-index: 1000;
    animation: sh-fade .12s ease-out;
}

.sh-modal {
    width: 100%;
    max-width: 560px;
    max-height: calc(100vh - 2rem);
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    background: var(--sh-surface);
    border: 1px solid var(--sh-border-strong);
    border-radius: var(--sh-radius-lg);
    box-shadow: var(--sh-shadow-lg);
    animation: sh-pop .14s ease-out;
}
/* UI-009: Beim Öffnen bekommt das Fenster selbst den Fokus (tabindex="-1"), damit das
   Vorleseprogramm seinen Namen ansagt. Das Fenster ist kein Bedienelement — ein Rahmen um
   den ganzen Dialog sähe aus wie ein Fehler. Sichtbar wird der Fokus ab dem ersten
   Tabulator, am Bedienelement selbst. */
.sh-modal:focus { outline: none; }
.sh-modal--wide { max-width: 900px; }
.sh-modal--full { max-width: 1300px; }

.sh-modal__head {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .65rem .85rem;
    border-bottom: 1px solid var(--sh-border);
}
.sh-modal__title { margin: 0; font-size: .95rem; font-weight: 700; }
.sh-modal__body { padding: .85rem; overflow-y: auto; }
.sh-modal__foot {
    display: flex;
    justify-content: flex-end;
    gap: .4rem;
    padding: .65rem .85rem;
    border-top: 1px solid var(--sh-border);
    background: var(--sh-surface-2);
}

@keyframes sh-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sh-pop { from { opacity: 0; transform: translateY(6px) scale(.99); } to { opacity: 1; transform: none; } }

/* Ungeschnittenes Bild im Fließtext — der Kasten legt sich exakt um das Bild.
   Benutzt vom Schwerpunktsetzer (PortraitFokus).

   Hieß bis zum 01.09.2026 ebenfalls .sh-lightbox und teilte den Namen mit der großen
   Bildansicht aus gallery.css. Das ging zweimal schief, weil beide Regeln auf dasselbe
   Element trafen:

     * Die große Ansicht ist eine Vollbildfläche (position: fixed; inset: 0). Von hier
       bekam sie zusätzlich max-width: min(94vw, 1400px) und max-height: 94vh. Ein fest
       positionierter Kasten mit inset: 0 und begrenzter Breite kann nicht alle vier
       Kanten halten und bleibt oben links kleben — auf einem Breitbildschirm sichtbar
       daneben, mit einem breiten leeren Streifen rechts.

     * .sh-lightbox img ist spezifischer als .sh-lightbox__image (Klasse plus Typ gegen
       Klasse allein) und hat dessen max-width/max-height dort still überstimmt. Die
       große Ansicht rechnete also nach 100%/82vh statt nach den vorgesehenen 95vw/80vh.

   Zwei Bereiche, ein Klassenname, und beide Fehler waren im Stilblatt nicht zu sehen,
   sondern nur im Browser. Der Name ist deshalb getrennt. */
.sh-bildfokus img {
    max-width: 100%;
    max-height: 82vh;
    object-fit: contain;
    border-radius: var(--sh-radius);
    background: var(--sh-bg-2);
}

/* Hier standen bis zum 02.09.2026 vierundvierzig Zeilen für ein Toast-System, das
   es nie gab. Der Spielleiter hat entschieden, es nicht zu bauen — und der Code
   hatte längst dasselbe entschieden und es begründet: `Meldungsstreifen.razor`
   schreibt „Bewusst *kein* Toast", weil eine Meldung, die nach drei Sekunden
   verschwindet, für einen Fehler die falsche Bauform ist. Ein Fehler, der von
   selbst verschwindet, ist ein Fehler, den niemand gelesen hat.

   `.sh-toast__icon` war dabei NICHT tot: Drei Meldungskästen — die Fehlerseite,
   die Abweisung und der Baustellenhinweis — benutzten sie wegen der Symbolgröße.
   Ihre Regel war zeichengleich mit `.sh-alert__icon`, und alle drei sind
   Meldungskästen; sie sind dorthin umgezogen. Wer hier blind gelöscht hätte,
   hätte drei Symbole verlieren lassen, ohne dass ein Test angeschlagen wäre. */

/* ------------------------------------------------------------- Zustände */

.sh-empty {
    display: grid;
    place-items: center;
    gap: .4rem;
    padding: 2.2rem 1rem;
    text-align: center;
    color: var(--sh-text-faint);
}
.sh-empty__icon { width: 30px; height: 30px; opacity: .4; }
.sh-empty__title { font-size: .92rem; font-weight: 600; color: var(--sh-text-dim); }
.sh-empty__text { font-size: .82rem; max-width: 420px; }

.sh-loading {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: 1.4rem;
    justify-content: center;
    color: var(--sh-text-faint);
    font-size: .84rem;
}

.sh-spinner {
    width: 15px; height: 15px;
    border: 2px solid var(--sh-border-strong);
    border-top-color: var(--sh-accent);
    border-radius: 50%;
    animation: sh-spin .7s linear infinite;
    flex: 0 0 15px;
}
@keyframes sh-spin { to { transform: rotate(360deg); } }

.sh-skeleton {
    background: linear-gradient(90deg, var(--sh-surface-2) 25%, var(--sh-surface-3) 50%, var(--sh-surface-2) 75%);
    background-size: 200% 100%;
    animation: sh-shimmer 1.3s infinite;
    border-radius: 3px;
}
@keyframes sh-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

.sh-alert {
    display: flex;
    gap: .5rem;
    padding: .55rem .7rem;
    border: 1px solid var(--sh-border);
    border-left-width: 3px;
    border-radius: var(--sh-radius);
    background: var(--sh-surface-2);
    font-size: .83rem;
}
.sh-alert--info { border-left-color: var(--sh-blue); background: var(--sh-blue-soft); }
.sh-alert--success { border-left-color: var(--sh-success); background: var(--sh-success-soft); }
.sh-alert--warn { border-left-color: var(--sh-warn); background: var(--sh-warn-soft); }
.sh-alert--danger { border-left-color: var(--sh-danger); background: var(--sh-danger-soft); }
.sh-alert--rule { border-left-color: var(--sh-gold); background: var(--sh-gold-soft); }
.sh-alert__icon { width: 15px; height: 15px; flex: 0 0 15px; margin-top: .12rem; }

/* ------------------------------------------------------------- Tooltip */

/* Der Erklärungshinweis (UI-017). Bis zum 02.09.2026 lag dieser Block ohne einen
   einzigen Aufrufer hier; der Baustein dazu ist Shared/Erklaerung.razor. */
.sh-tip { position: relative; display: inline-flex; cursor: help; }

/* Der Auslöser ist ein echter Knopf und muss deshalb erst einmal aufhören, wie einer
   auszusehen. Er bleibt fokussierbar — das ist der ganze Punkt. */
.sh-tip__trigger {
    display: inline-grid;
    place-items: center;
    width: 15px;
    height: 15px;
    padding: 0;
    border: 1px solid var(--sh-border-strong);
    border-radius: var(--sh-radius-pill);
    background: transparent;
    color: var(--sh-text-faint);
    font: inherit;
    font-size: .62rem;
    line-height: 1;
    cursor: help;
}
.sh-tip__trigger:hover,
.sh-tip__trigger:focus-visible { border-color: var(--sh-accent); color: var(--sh-accent); }
.sh-tip__bubble {
    position: absolute;
    bottom: calc(100% + 5px);
    left: 50%;
    transform: translateX(-50%);
    min-width: 150px;
    max-width: 290px;
    padding: .4rem .55rem;
    background: #05070a;
    border: 1px solid var(--sh-border-strong);
    border-radius: var(--sh-radius);
    box-shadow: var(--sh-shadow);
    font-size: .76rem;
    font-weight: 400;
    line-height: 1.45;
    color: var(--sh-text);
    text-transform: none;
    letter-spacing: normal;
    white-space: normal;
    text-align: left;
    /* Nur durchsichtig — und ausdrücklich nicht aus dem Barrierefreiheitsbaum
       genommen. Die Blase trägt die Kennung, auf die `aria-describedby` zeigt;
       verschwände sie daraus, ginge der Verweis ins Leere und eine Vorlesehilfe
       läse beim Fokus auf den Auslöser nichts. Für das Auge ist sie so oder so weg. */
    opacity: 0;
    transition: opacity .12s;
    z-index: 900;
    pointer-events: none;
}

/* Maus über dem Hinweis — und der Zustand, den der Baustein setzt.

   `:focus-within` steht hier bewusst NICHT mehr: Stünde die Blase schon offen, sobald
   der Fokus auf dem Auslöser sitzt, könnte Escape sie nicht schliessen — die Regel
   bliebe erfüllt, solange der Fokus dort steht. Die Tastatur öffnet über Enter oder
   Leertaste, also über denselben Klick wie Maus und Fingertipp. */
.sh-tip:hover .sh-tip__bubble,
.sh-tip.is-open .sh-tip__bubble { opacity: 1; }
.sh-tip__title { font-weight: 700; color: var(--sh-accent); display: block; margin-bottom: .1rem; }

/* -------------------------------------------------------- Fortschritt */

.sh-progress {
    height: 4px;
    background: var(--sh-surface-3);
    border-radius: 2px;
    overflow: hidden;
}
.sh-progress__bar { height: 100%; background: var(--sh-accent); transition: width .2s; }
.sh-progress__bar--gold { background: var(--sh-gold); }
.sh-progress__bar--danger { background: var(--sh-danger); }

/* Wizard-Schrittleiste */
.sh-steps {
    display: flex;
    gap: .18rem;
    overflow-x: auto;
    padding-bottom: .28rem;
    scrollbar-width: thin;
}
.sh-step {
    display: flex;
    align-items: center;
    gap: .32rem;
    padding: .28rem .5rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
    color: var(--sh-text-faint);
    font-size: .74rem;
    white-space: nowrap;
    cursor: pointer;
    flex: 0 0 auto;
    font-family: inherit;
}
.sh-step:hover { border-color: var(--sh-border-strong); color: var(--sh-text-dim); }
/* Innen: .sh-steps scrollt waagerecht und schnitte einen äusseren Rahmen ab. */
.sh-step:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-step.is-active {
    border-color: var(--sh-accent);
    background: var(--sh-accent-soft);
    color: var(--sh-accent);
    font-weight: 600;
}
.sh-step.is-done { color: var(--sh-success); border-color: rgba(79, 191, 123, .3); }
.sh-step.is-error { color: var(--sh-danger); border-color: rgba(224, 85, 97, .4); }
.sh-step__num {
    display: grid; place-items: center;
    width: 15px; height: 15px;
    border-radius: 50%;
    background: var(--sh-surface-3);
    font-size: .62rem;
    font-weight: 700;
    flex: 0 0 15px;
}
.sh-step.is-active .sh-step__num { background: var(--sh-accent); color: #04120f; }
.sh-step.is-done .sh-step__num { background: var(--sh-success); color: #04120f; }

/* Autosave-Status */
.sh-autosave {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    font-size: .74rem;
    color: var(--sh-text-faint);
}
.sh-autosave--saving { color: var(--sh-blue); }
.sh-autosave--dirty { color: var(--sh-warn); }
.sh-autosave--saved { color: var(--sh-success); }
.sh-autosave--error { color: var(--sh-danger); }

/* --------------------------------------------------------- Würfeltisch */

.sh-die {
    display: grid;
    place-items: center;
    width: 96px; height: 96px;
    margin: 0 auto;
    border: 2px solid var(--sh-accent-line);
    border-radius: var(--sh-radius-lg);
    background: var(--sh-surface-2);
    font-size: 2.7rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--sh-accent);
    letter-spacing: -.03em;
}
.sh-die--crit-success { border-color: var(--sh-success); color: var(--sh-success); background: var(--sh-success-soft); }
.sh-die--crit-fail { border-color: var(--sh-danger); color: var(--sh-danger); background: var(--sh-danger-soft); }
.sh-die--rolling { animation: sh-shake .28s ease-in-out; }
@keyframes sh-shake {
    0%, 100% { transform: none; }
    25% { transform: translateX(-4px) rotate(-3deg); }
    75% { transform: translateX(4px) rotate(3deg); }
}

.sh-console {
    font-family: var(--sh-font-mono);
    font-size: .77rem;
    background: var(--sh-bg-2);
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    max-height: 320px;
    overflow-y: auto;
}
.sh-console__line {
    display: flex;
    gap: .5rem;
    padding: .22rem .55rem;
    border-bottom: 1px solid var(--sh-border-soft);
    align-items: baseline;
}
.sh-console__line:last-child { border-bottom: 0; }
.sh-console__time { color: var(--sh-text-faint); flex: 0 0 auto; font-size: .72rem; }
.sh-console__text { min-width: 0; flex: 1; word-break: break-word; }
.sh-console__result { font-weight: 700; flex: 0 0 auto; }
.sh-console__result--success { color: var(--sh-success); }
.sh-console__result--fail { color: var(--sh-danger); }

/* -------------------------------------------------- Beziehungsgraph */

.sh-graph { width: 100%; background: var(--sh-bg-2); border-radius: var(--sh-radius); display: block; }
.sh-graph__edge { stroke: var(--sh-border-strong); stroke-width: 1; }
.sh-graph__edge--family { stroke: var(--sh-gold-dim); }
.sh-graph__edge--love { stroke: #c56a8f; }
.sh-graph__edge--friendship { stroke: var(--sh-success); }
.sh-graph__edge--enmity { stroke: var(--sh-danger-dim); }
.sh-graph__edge--master { stroke: var(--sh-purple); }
.sh-graph__edge--politics { stroke: var(--sh-blue); }
.sh-graph__edge--clan { stroke: var(--sh-gold); }
.sh-graph__edge--other { stroke: var(--sh-border-strong); }
.sh-graph__edge--secret { stroke-dasharray: 3 3; }
.sh-graph__pfeil { fill: var(--sh-text-dim); }
.sh-graph__node { fill: var(--sh-surface-3); stroke: var(--sh-border-strong); cursor: pointer; }
/* Hover und Fokus sitzen am Knoten (.sh-graph__knoten, dem Verweis), gezeigt wird
   beides am Kreis. Ein Rahmen um die Gruppe umfasste Kreis und Namen als Rechteck —
   derselbe Kasten, der auf der Weltkarte dreimal gemeldet wurde; der Ring folgt
   statt dessen der Form (UI-009). */
.sh-graph__knoten:hover .sh-graph__node { fill: var(--sh-accent-dim); }
.sh-graph__knoten:focus-visible { outline: none; }
.sh-graph__knoten:focus-visible .sh-graph__node { stroke: var(--sh-accent); stroke-width: 3; }
.sh-graph__node.is-focus { fill: var(--sh-accent); stroke: var(--sh-accent); }
.sh-graph__label { fill: var(--sh-text-dim); font-size: 9px; pointer-events: none; text-anchor: middle; }

/* Beziehung hinzufügen (FAM-002): die Aussage „[Figur] ist [Beziehung] von [Figur]“.
   Breit nebeneinander, schmal untereinander — auf 360 Pixeln läse niemand drei Spalten. */
.sh-aussage {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 12rem) auto minmax(0, 1fr);
    gap: .5rem .65rem;
    align-items: start;
}
.sh-aussage__teil { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.sh-aussage__wort { padding-top: 1.45rem; color: var(--sh-text-dim); font-size: .85rem; }
.sh-aussage__beziehung {
    min-height: 2rem; display: flex; align-items: center; justify-content: center;
    padding: .3rem .6rem; border: 1px solid var(--sh-accent-line); border-radius: var(--sh-radius);
    background: var(--sh-accent-soft); font-weight: 600; text-align: center;
}
@media (max-width: 760px) {
    .sh-aussage { grid-template-columns: minmax(0, 1fr); }
    .sh-aussage__wort { padding-top: 0; }
}
/* Die Knopfgruppen der Beziehungswahl. Der gewählte Knopf trägt Rahmen und Fläche und
   zusätzlich aria-pressed — nicht allein Farbe. */
.sh-wahlgruppen { display: grid; gap: .6rem; }
.sh-wahlgruppe { display: grid; gap: .3rem; }
.sh-wahlgruppe__titel {
    font-size: .66rem; text-transform: uppercase; letter-spacing: .09em; color: var(--sh-text-faint);
}
.sh-wahlgruppe__knoepfe { display: flex; flex-wrap: wrap; gap: .35rem; }
.sh-wahl {
    min-height: 2rem; padding: .25rem .65rem;
    border: 1px solid var(--sh-border); border-radius: var(--sh-radius);
    background: var(--sh-surface); color: var(--sh-text);
    font: inherit; font-size: .82rem; cursor: pointer;
}
.sh-wahl:hover { border-color: var(--sh-border-strong); }
.sh-wahl:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 1px; }
.sh-wahl.is-active { border-color: var(--sh-accent); background: var(--sh-accent-soft); font-weight: 600; }
.sh-wahl.is-active::before { content: "✓ "; }
.sh-wahlgruppe--nachrangig > summary { cursor: pointer; }

/* Stammbaum (FAM-002, REQ-FAM-021).

   Ein Raster mit festen Massen: Randspalte fuer die Generationsueberschriften, danach
   halbe Spalten; eine Karte belegt zwei. Die Masse kommen als CSS-Variablen aus dem
   Dienstteil (Stammbaumlayout) — dieselben Zahlen, mit denen dort die Linienpfade
   gerechnet werden. Deshalb enden die Linien ohne JavaScript auf den Karten.

   Die Linien unterscheiden sich in der Strichart, nicht allein in der Farbe:
   durchgezogen leiblich, gestrichelt Adoption, gepunktet Pflege und Stief, Partner
   waagerecht und kraeftiger, frueher abgeschwaecht und unterbrochen.

   Auf dem Telefon wird dasselbe Markup zur senkrechten Folge der Generationen: Die
   Zeilen stehen untereinander, die Karten volle Breite, die Linienebene tritt zurueck —
   jede Karte sagt in Worten, was sie fuer die Fokusperson ist. */
.sh-stammbaum__werkzeuge {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sh-space-sm) 1rem;
}
.sh-stammbaum__suche { flex: 1 1 14rem; max-width: 22rem; }
.sh-stammbaum__treffer { display: flex; flex-wrap: wrap; gap: .3rem; }

.sh-stammbaum__rahmen {
    overflow: auto;
    max-width: 100%;
    padding: .75rem 0;
    border: 1px solid var(--sh-border-soft);
    border-radius: var(--sh-radius);
    background: var(--sh-surface-2);
}

.sh-stammbaum__flaeche {
    position: relative;
    display: grid;
    grid-template-columns: var(--sb-rand) repeat(var(--sb-spalten), var(--sb-halbspalte));
    grid-template-rows: repeat(var(--sb-zeilen), var(--sb-karte));
    row-gap: var(--sb-abstand);
    width: var(--sb-breite);
    height: var(--sb-hoehe);
    margin: 0 auto;
    zoom: var(--sb-zoom);
}

.sh-stammbaum__linien {
    position: absolute;
    inset: 0 auto auto 0;
    pointer-events: none;
    overflow: visible;
}

/* Auf dem Raster geht jede Zeile in ihren Elternknoten auf. */
.sh-stammbaum__zeile { display: contents; }

.sh-stammbaum__titel {
    grid-row: var(--sb-zeile);
    grid-column: 1;
    align-self: center;
    padding-right: .5rem;
    font-size: .66rem;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--sh-text-faint);
}

/* Die Elternkonstellation („Mit Blue“) steht im Raster nur fuer Vorlesehilfen — die
   Linien zeigen sie; auf dem Telefon wird sie zur Ueberschrift. */
.sh-stammbaum__gruppe {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.sh-stammbaum__platz {
    position: relative;
    z-index: 1;
    grid-row: var(--sb-zeile);
    grid-column: var(--sb-spalte) / span 2;
    display: flex;
    align-items: stretch;
    justify-content: center;
    min-width: 0;
    padding: 0 10px;
}

.sh-stammbaum__platz .sh-char-card--compact {
    width: 100%;
    min-width: 0;
    max-width: none;
    overflow: hidden;
    background: var(--sh-surface);
}

.sh-stammbaum__platz .sh-char-card__meta,
.sh-stammbaum__platz .sh-char-card__facts {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sh-stammbaum__platz--fokus .sh-char-card--compact { box-shadow: 0 0 0 2px var(--sh-accent-line); }
.sh-stammbaum__platz--treffer .sh-char-card--compact { outline: 2px dashed var(--sh-gold); outline-offset: 2px; }
.sh-stammbaum__platz--mehr { align-items: center; }

.sh-stammbaum__linie {
    fill: none;
    stroke: var(--sh-text-dim);
    stroke-width: 1.6;
    vector-effect: non-scaling-stroke;
}
.sh-stammbaum__linie--adoptiv { stroke-dasharray: 7 4; }
.sh-stammbaum__linie--pflege,
.sh-stammbaum__linie--stief { stroke-dasharray: 1.5 4; stroke-linecap: round; stroke-width: 2; }
.sh-stammbaum__linie--partner { stroke: var(--sh-gold); stroke-width: 2.6; }
.sh-stammbaum__linie--geschwister { stroke-width: 1.2; }
.sh-stammbaum__linie--ehemalig { stroke-dasharray: 2 6; opacity: .45; }
.sh-stammbaum__linie--geheim { stroke: var(--sh-warn); }

.sh-stammbaum__legende {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.1rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: .72rem;
    color: var(--sh-text-dim);
}
.sh-stammbaum__legende li { display: inline-flex; align-items: center; gap: .4rem; }

.sh-stammbaum__unterkopf {
    margin: .5rem 0 .25rem;
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--sh-text-dim);
}
.sh-stammbaum__weitere-karten { display: flex; flex-wrap: wrap; gap: .55rem; }

.sh-stammbaum__beziehung {
    display: grid;
    gap: .3rem;
    padding: .5rem .65rem;
    border-left: 3px solid var(--sh-border-strong);
    background: var(--sh-surface);
}
.sh-stammbaum__angaben {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: .1rem .75rem;
    margin: 0;
    font-size: .78rem;
}
.sh-stammbaum__angaben dt { color: var(--sh-text-faint); }
.sh-stammbaum__angaben dd { margin: 0; }
.sh-stammbaum__grundlagen { margin: 0; padding-left: 1.1rem; font-size: .78rem; }
.sh-stammbaum__grundlagen li { margin: .15rem 0; }

/* Telefon: senkrechte Generationenfolge (Abschnitt 28). */
@media (max-width: 760px) {
    .sh-stammbaum__zoom { display: none; }
    .sh-stammbaum__rahmen { padding: .5rem; overflow: visible; }
    .sh-stammbaum__flaeche {
        display: flex;
        flex-direction: column;
        gap: .25rem;
        width: auto;
        height: auto;
        zoom: 1;
    }
    .sh-stammbaum__linien { display: none; }
    .sh-stammbaum__zeile { display: flex; flex-direction: column; gap: .4rem; }
    .sh-stammbaum__zeile + .sh-stammbaum__zeile::before {
        content: "↓";
        align-self: center;
        color: var(--sh-text-faint);
    }
    .sh-stammbaum__titel { padding: 0; }
    .sh-stammbaum__gruppe {
        position: static;
        width: auto; height: auto;
        margin: .25rem 0 0;
        overflow: visible;
        clip: auto;
        clip-path: none;
        white-space: normal;
        font-size: .72rem;
        color: var(--sh-text-dim);
    }
    .sh-stammbaum__platz { padding: 0; }
}
.sh-person {
    display: grid;
    gap: .18rem;
    justify-items: center;
    padding: .4rem .55rem;
    min-width: 118px;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
    cursor: pointer;
    font: inherit;
    color: inherit;
    text-align: center;
}
.sh-person:hover { border-color: var(--sh-accent-line); text-decoration: none; }
.sh-person:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 2px; }
.sh-person.is-focus { border-color: var(--sh-accent); background: var(--sh-accent-soft); }
.sh-person__avatar {
    width: 34px; height: 34px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--sh-surface-3);
    display: grid; place-items: center;
    font-size: .78rem; font-weight: 700;
    color: var(--sh-text-faint);
    overflow: hidden;
}
.sh-person__avatar img { width: 100%; height: 100%; object-fit: cover; }
.sh-person__name { font-size: .78rem; font-weight: 600; }
.sh-person__meta { font-size: .68rem; color: var(--sh-text-faint); }

/* ------------------------------------------------------- Regelwerk */

.sh-prose { font-size: .88rem; line-height: 1.68; max-width: 78ch; }
.sh-prose h2 {
    margin-top: 1.6rem;
    padding-bottom: .3rem;
    border-bottom: 1px solid var(--sh-border);
    color: var(--sh-gold);
    font-size: 1.12rem;
}
.sh-prose h3 { margin-top: 1.2rem; color: var(--sh-text); font-size: .98rem; }
.sh-prose h4 { margin-top: 1rem; color: var(--sh-text-dim); }
.sh-prose ul, .sh-prose ol { margin: 0 0 .8em; padding-left: 1.3rem; }
.sh-prose li { margin-bottom: .22em; }
.sh-prose table { width: 100%; border-collapse: collapse; margin: 0 0 1em; font-size: .84rem; }
.sh-prose th, .sh-prose td { padding: .32rem .55rem; border: 1px solid var(--sh-border); text-align: left; }
.sh-prose th { background: var(--sh-surface-2); color: var(--sh-text-dim); font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; }
.sh-prose img { max-width: 100%; height: auto; border-radius: var(--sh-radius); }
.sh-prose strong { color: var(--sh-text); font-weight: 650; }
.sh-prose > :first-child { margin-top: 0; }

/* BBCode-Ausgabe (REQ-BB-002).
   [center] ist die einzige der vierzehn Auszeichnungen, die kein Element mit eigener
   Standardwirkung erzeugt: BbCode schreibt ein <div class="sh-bb__center">, und ein div
   zentriert von sich aus nichts. Ohne diese Regel blieb zentrierter Text linksbündig —
   die Marke wurde erkannt, umgewandelt und war folgenlos.
   Kein Test konnte es bemerken: Alle drei BbCode-Testklassen prüfen gegen
   HTML-Zeichenketten, nie gegen ein Stylesheet. Gefunden am 02.09.2026 beim Abgleich der
   Anforderungen gegen den Code. */
.sh-bb__center { text-align: center; }

/* [big] — die F-List-Marke, die BbCode seit FLIST-003 kennt.
   Relativ und nicht in Pixeln: Der Kopf des Exports steht in einer Vorschau, die
   selbst schon kleiner gesetzt sein kann. */
.sh-bb__big { font-size: 1.35em; line-height: 1.2; }

/* Markdown in derselben Ausgabe (02.09.2026).

   Die Auszeichnung kam bisher aus vier Ecken des Hauses und wurde vierfach verschieden
   behandelt; Story lief über BbCode und zeigte `###` deshalb wörtlich — in 69 von 94
   Lesetexten. Seit BbCode auch Markdown liest, entstehen hier drei weitere Elemente.

   Der Absatz braucht die Regel am dringendsten: Vorher wurde jeder Zeilenumbruch zu
   einem <br />, und ein langer Text stand als eine einzige Wand da. */
.sh-bb__p { margin: 0 0 .7rem; }
.sh-bb__p:last-child { margin-bottom: 0; }

.sh-bb__h {
    margin: 1.1rem 0 .4rem;
    font-weight: 650;
    line-height: 1.25;
    color: var(--sh-text);
}
.sh-bb__h:first-child { margin-top: 0; }
h3.sh-bb__h { font-size: 1.02rem; }
h4.sh-bb__h { font-size: .94rem; }
h5.sh-bb__h, h6.sh-bb__h { font-size: .88rem; color: var(--sh-text-dim); }

/* Der Wortlaut. Er soll sich abheben, ohne den Zeilenfall zu sprengen —
   deshalb umbruchfähig und nicht in fester Breite. */
.sh-bb__code {
    font-family: var(--sh-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
    font-size: .88em;
    padding: .06rem .28rem;
    border-radius: 3px;
    background: var(--sh-surface-2);
    border: 1px solid var(--sh-border);
    word-break: break-word;
}

.sh-toc { font-size: .82rem; display: grid; gap: .06rem; }
.sh-toc__item {
    display: block;
    padding: .18rem .45rem;
    border-radius: 3px;
    color: var(--sh-text-dim);
    border: 0; background: none; font: inherit;
    text-align: left; width: 100%; cursor: pointer;
}
.sh-toc__item:hover { background: var(--sh-surface-2); color: var(--sh-text); text-decoration: none; }
.sh-toc__item:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-toc__item.is-active { background: var(--sh-gold-soft); color: var(--sh-gold); font-weight: 600; }
.sh-toc__item--l2 { padding-left: 1.1rem; font-size: .79rem; }
.sh-toc__item--l3 { padding-left: 1.8rem; font-size: .76rem; }

/* ----------------------------------------------------------- Dropzone */

.sh-drop {
    display: grid;
    place-items: center;
    gap: .35rem;
    padding: 1.5rem 1rem;
    border: 1px dashed var(--sh-border-strong);
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
    text-align: center;
    color: var(--sh-text-dim);
    transition: border-color .12s, background .12s;
    position: relative;
}
.sh-drop.is-over { border-color: var(--sh-accent); background: var(--sh-accent-soft); }
.sh-drop input[type="file"] {
    position: absolute; inset: 0;
    opacity: 0; cursor: pointer; width: 100%; height: 100%;
}
.sh-drop__icon { width: 26px; height: 26px; opacity: .5; }
.sh-drop__title { font-size: .86rem; font-weight: 600; color: var(--sh-text); }
.sh-drop__hint { font-size: .76rem; color: var(--sh-text-faint); }

/* ---------------------------------------------------------- Gastbanner */

.sh-guest {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .4rem .7rem;
    border: 1px solid rgba(91, 156, 240, .3);
    border-radius: var(--sh-radius);
    background: var(--sh-blue-soft);
    font-size: .82rem;
    flex-wrap: wrap;
    margin-bottom: var(--sh-gap);
}
.sh-guest__text { color: var(--sh-text-dim); }
.sh-guest__text strong { color: var(--sh-blue); }

/* -------------------------------------------------------- Benutzermenü */

.sh-user {
    display: flex;
    align-items: center;
    gap: .42rem;
    padding: .22rem .45rem;
    border: 1px solid transparent;
    border-radius: var(--sh-radius);
    background: none;
    color: var(--sh-text-dim);
    font: inherit;
    font-size: .82rem;
    cursor: pointer;
}
.sh-user:hover { background: var(--sh-surface-2); border-color: var(--sh-border); color: var(--sh-text); }
.sh-user__avatar {
    width: 22px; height: 22px;
    border-radius: 50%;
    background: var(--sh-accent-dim);
    color: #04120f;
    display: grid; place-items: center;
    font-size: .68rem; font-weight: 700;
    flex: 0 0 22px;
    overflow: hidden;
}
/* Das Benutzerbild liest den Bildschwerpunkt wie jede andere Flaeche (MEDIA-014,
   REQ-MEDIA-031). Die Kennung --sh-focus setzt <ProtectedImage> als Stilangabe am Bild
   selbst; ohne gesetzten Schwerpunkt bleibt es bei der Mitte, also beim bisherigen
   Verhalten. In einem Kreis von 22 Pixeln ist das der Unterschied zwischen einem
   Gesicht und einem Bauchnabel. */
.sh-user__avatar img {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: var(--sh-focus, center);
}
.sh-user__role { font-size: .68rem; color: var(--sh-text-faint); }

.sh-menu {
    position: absolute;
    top: calc(100% + 3px);
    right: 0;
    min-width: 205px;
    padding: .22rem;
    background: var(--sh-surface);
    border: 1px solid var(--sh-border-strong);
    border-radius: var(--sh-radius);
    box-shadow: var(--sh-shadow-lg);
    z-index: 800;
    display: grid;
    gap: 1px;
}
.sh-menu__item {
    display: flex;
    align-items: center;
    gap: .45rem;
    width: 100%;
    padding: .35rem .5rem;
    border: 0; border-radius: 3px;
    background: none;
    color: var(--sh-text-dim);
    font: inherit; font-size: .82rem;
    text-align: left; cursor: pointer;
}
.sh-menu__item:hover { background: var(--sh-surface-2); color: var(--sh-text); text-decoration: none; }
.sh-menu__item:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-menu__item--danger { color: var(--sh-danger); }
.sh-menu__item--danger:hover { background: var(--sh-danger-soft); color: var(--sh-danger); }
.sh-menu__sep { height: 1px; background: var(--sh-border); margin: .18rem 0; }
.sh-menu__label {
    padding: .3rem .5rem .15rem;
    font-size: .64rem;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--sh-text-faint);
}
.sh-dropdown { position: relative; }

/* Die Fläche, die einen Klick daneben abfängt. Unter dem Menü (z-index 800) und über
   allem anderen — sonst schlösse ein Klick auf einen Menüpunkt das Menü, bevor er
   ankommt. */
.sh-menu__backdrop {
    position: fixed;
    inset: 0;
    z-index: 799;
    border: 0;
    background: transparent;
    cursor: default;
}

/* Die Benachrichtigungsvorschau ist breiter als ein Aktionsmenü: In ihr stehen Titel und
   Zeitpunkt, nicht ein Verb. */
.sh-menu--wide { min-width: 320px; max-width: min(380px, calc(100vw - 1.5rem)); }
.sh-menu__leer { padding: .4rem .5rem .5rem; }

/* Ungelesenes trägt einen Punkt und nicht nur eine andere Farbe — Farbe allein
   unterscheidet nichts für den, der sie schlecht sieht. */
.sh-menu__item.is-unread { color: var(--sh-text); font-weight: 600; }
.sh-menu__item.is-unread::before {
    content: "";
    flex: 0 0 6px;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--sh-accent);
}

/* ------------------------------------------------------------- Glocke */

.sh-bell { position: relative; overflow: visible; }

/* Die Zahl sitzt am Rand des Knopfes und nicht daneben: In der Kopfzeile ist jeder
   Millimeter vergeben, und die Glocke steht neben dem Benutzernamen. */
.sh-bell__count {
    position: absolute;
    top: -3px;
    right: -4px;
    min-width: 15px;
    padding: 0 3px;
    border-radius: 8px;
    background: var(--sh-accent);
    color: #04120f;
    font-size: .6rem;
    font-weight: 700;
    line-height: 15px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------- Globale Suche */

.sh-omnibox { position: relative; flex: 1 1 260px; max-width: 460px; min-width: 0; }
.sh-omnibox__results {
    position: absolute;
    top: calc(100% + 3px);
    left: 0; right: 0;
    max-height: 65vh;
    overflow-y: auto;
    background: var(--sh-surface);
    border: 1px solid var(--sh-border-strong);
    border-radius: var(--sh-radius);
    box-shadow: var(--sh-shadow-lg);
    z-index: 850;
}
.sh-omnibox__group {
    padding: .3rem .55rem .12rem;
    font-size: .63rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--sh-text-faint);
    background: var(--sh-surface-2);
    border-bottom: 1px solid var(--sh-border-soft);
    position: sticky; top: 0;
}
.sh-omnibox__item {
    display: flex;
    align-items: center;
    gap: .45rem;
    width: 100%;
    padding: .32rem .55rem;
    border: 0; background: none;
    color: var(--sh-text-dim);
    font: inherit; font-size: .82rem;
    text-align: left; cursor: pointer;
}
.sh-omnibox__item:hover, .sh-omnibox__item.is-active { background: var(--sh-accent-soft); color: var(--sh-accent); }
.sh-omnibox__item:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-omnibox__meta { margin-left: auto; font-size: .7rem; color: var(--sh-text-faint); }

/* -------------------------------------------------------- Paginierung */

.sh-pager {
    display: flex;
    align-items: center;
    gap: .35rem;
    justify-content: center;
    padding: .6rem 0 .2rem;
    flex-wrap: wrap;
}
.sh-pager__info { font-size: .78rem; color: var(--sh-text-faint); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------- F-List-Vorschau */

.sh-bbcode {
    font-family: var(--sh-font-mono);
    font-size: .77rem;
    line-height: 1.55;
    white-space: pre-wrap;
    word-break: break-word;
    background: var(--sh-bg-2);
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    padding: .7rem;
    max-height: 620px;
    overflow-y: auto;
    color: var(--sh-text-dim);
}

.sh-flist { font-size: .85rem; line-height: 1.62; }
.sh-flist__center { text-align: center; }
.sh-flist__big { font-size: 1.18em; font-weight: 600; }
.sh-flist__hr { border: 0; border-top: 1px solid var(--sh-border); margin: .6rem 0; }
.sh-flist__collapse {
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    margin: .35rem 0;
    background: var(--sh-surface-2);
}
.sh-flist__collapse > summary {
    padding: .35rem .6rem;
    cursor: pointer;
    font-weight: 600;
    color: var(--sh-gold);
    font-size: .83rem;
    list-style: none;
}
.sh-flist__collapse > summary::-webkit-details-marker { display: none; }
.sh-flist__collapse > summary::before { content: "▸ "; color: var(--sh-text-faint); }
.sh-flist__collapse[open] > summary::before { content: "▾ "; }
.sh-flist__collapse > div { padding: .1rem .6rem .55rem; }

/* ----------------------------------------------------------- Hilfsklassen */

.sh-muted { color: var(--sh-text-dim); }
.sh-faint { color: var(--sh-text-faint); }
.sh-accent { color: var(--sh-accent); }
.sh-gold { color: var(--sh-gold); }
.sh-blue { color: var(--sh-blue); }
.sh-danger { color: var(--sh-danger); }
.sh-success { color: var(--sh-success); }
.sh-warn { color: var(--sh-warn, #d9a441); }

/* Die Möglichkeitenliste im Angriffsdialog (KMU-005).

   Gesperrte Einträge werden ausgegraut und nicht ausgeblendet: Ein fehlender Knopf ist
   von einem Fehler nicht zu unterscheiden (REQ-COMBAT-045, REQ-COMBAT-068). Deshalb
   senkt --gesperrt nur die Deckkraft; der Grund daneben bleibt voll lesbar. */
.sh-moeglichkeiten {
    display: grid;
    gap: .35rem;
    max-height: 22rem;
    overflow-y: auto;
}
.sh-moeglichkeit {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    padding: .4rem .55rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius-sm, 6px);
    cursor: pointer;
}
.sh-moeglichkeit input[type="radio"] {
    width: 15px; height: 15px; margin: .12rem 0 0;
    accent-color: var(--sh-accent);
    flex: 0 0 15px;
}
.sh-moeglichkeit__text { display: grid; gap: .1rem; min-width: 0; }
.sh-moeglichkeit--gesperrt { cursor: not-allowed; opacity: .62; }
.sh-moeglichkeit--gesperrt .sh-warn { opacity: 1; }

/* Die staerkste Moeglichkeit ist vorgewaehlt und traegt deshalb nur eine ruhige
   Kennzeichnung: Sie ist ein Vorschlag und keine Sperre (REQ-COMBAT-049, REQ-COMBAT-051).
   Ein kraeftiger Rahmen laese sie wie die einzig zulaessige Wahl aussehen. */
.sh-moeglichkeit--vorwahl {
    border-color: var(--sh-accent);
    background: color-mix(in srgb, var(--sh-accent) 7%, transparent);
}

/* Die Zahl neben der Zeile: Trefferchance und Wirkungserwartung. Tabellenziffern, damit
   die Werte mehrerer Zeilen untereinander stehen und sich vergleichen lassen. */
.sh-moeglichkeit__wert {
    font-size: .76rem;
    font-variant-numeric: tabular-nums;
    color: var(--sh-text-dim);
}
.sh-moeglichkeit__wert em { font-style: normal; color: var(--sh-accent); font-weight: 650; }

/* Die Handlung ohne Wurf (REQ-COMBAT-064) steht in derselben Auswahlgruppe wie die
   Angriffe, aber erkennbar als etwas anderes: gestrichelter Rand, kein Prozentwert. */
.sh-moeglichkeit--handlung { border-style: dashed; }
.sh-kampf-oeffnungen { color: var(--sh-accent); }

/* Die Aufladung (KMU-009): der Chip an der Karte und die Ansage-Karte im Dialog. */
.kampf-aufladung .sh-chip { font-variant-numeric: tabular-nums; }
.sh-kampf-ansage .sh-card__head { align-items: center; }

/* Der Block ueber dem Ausfuehrenknopf: die getroffene Wahl im Klartext, darunter der
   Grund und die naechstbeste Moeglichkeit (REQ-COMBAT-050). */
.sh-vorwahl {
    display: grid;
    gap: .2rem;
    padding: .5rem .75rem;
    border-top: 1px solid var(--sh-border);
}
.sh-vorwahl__satz { font-weight: 650; font-variant-numeric: tabular-nums; }

/* Der Herkunftssatz unter einem Eintrag der Ergebnisliste — woher die Moeglichkeit stammt,
   woher die Gestalt (KMU-005, REQ-COMBAT-080, REQ-COMBAT-081).

   Eigene Zeile und ausdruecklich kein angehaengter Fliesstext: „Klauen & Zaehne —
   Fertigkeit Feral-Kampf 9 Klauen & Zaehne — natuerliche Waffe der Feralform" waere am
   Tisch nicht mehr zu trennen. min-width: 0, weil das <dd> ein Rasterfeld ist und ein
   langer Satz die Spalte sonst aufzieht. */
.sh-dl dd > .sh-dl__notiz { display: block; min-width: 0; }

.sh-xs { font-size: .73rem; }
.sh-sm { font-size: .8rem; }
.sh-lg { font-size: 1rem; }
.sh-bold { font-weight: 650; }
.sh-mono { font-family: var(--sh-font-mono); font-variant-numeric: tabular-nums; }

/* Nur fuer Vorleseprogramme sichtbar (UI-009, REQ-UI-010).

   Wo ein Pfeil oder ein Symbol die Bedeutung traegt — „Spieler → Spielleiter" —, steht
   der Pfeil auf `aria-hidden` und daneben das Wort in dieser Klasse. Ein Vorleser sagt
   sonst je nach Stimme „Rechtspfeil" oder gar nichts.

   `clip-path` UND `clip`: Das alte `clip` ist abgekuendigt, aber die Vorleser aelterer
   Browser richten sich noch danach. Beides zusammen ist die Fassung, die ueberall
   dasselbe tut. Kein `display: none` und kein `visibility: hidden` — beides nimmt den
   Text auch dem Vorleser weg, und dann steht dort gar nichts mehr. */
.sh-visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}
.sh-nowrap { white-space: nowrap; }
.sh-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.sh-break { word-break: break-word; }
/* Zurückgenommen, nicht gelöscht (ADMIN-018): Die Zeile bleibt lesbar und ist
   als zurückgenommen gezeichnet. */
.sh-strike { text-decoration: line-through; }
.sh-center { text-align: center; }
.sh-right { text-align: right; }

.sh-mt-0 { margin-top: 0; }
.sh-mt { margin-top: var(--sh-gap); }
.sh-mb-0 { margin-bottom: 0; }
.sh-mb { margin-bottom: var(--sh-gap); }
.sh-mt-xs { margin-top: var(--sh-space-xs); }
.sh-p { padding: var(--sh-space-sm); }
.sh-hidden { display: none !important; }

/* Feld und Beschriftung nebeneinander statt untereinander — fuer Kopfzeilen von
   Karten, wo eine zweizeilige Anordnung die Zeile unnoetig hoch machen wuerde. */
.sh-field--inline {
    display: flex;
    align-items: center;
    gap: var(--sh-space-xs);
}

.sh-field--inline > span {
    white-space: nowrap;
    font-size: .74rem;
    color: var(--sh-text-dim);
}

.sh-input--sm {
    padding: .2rem .45rem;
    font-size: .78rem;
}

/* Blazor-Fehleranzeige */
#blazor-error-ui {
    position: fixed;
    bottom: 0; left: 0; right: 0;
    display: none;
    padding: .6rem 1.1rem;
    background: var(--sh-danger-dim);
    color: #fff;
    font-size: .84rem;
    z-index: 1200;
    box-shadow: 0 -2px 12px rgba(0, 0, 0, .5);
}
#blazor-error-ui .dismiss {
    position: absolute;
    top: .4rem; right: .8rem;
    cursor: pointer;
    font-size: 1.1rem;
}

.validation-message { font-size: .76rem; color: var(--sh-danger); }
.invalid { border-color: var(--sh-danger) !important; }

/* ---------------------------------------------------------- Responsive */

.sh-nav-toggle { display: none; }
.sh-nav__backdrop { display: none; }

@media (max-width: 1200px) {
    .sh-split { grid-template-columns: minmax(0, 1fr); }
    .sh-split--wide { grid-template-columns: minmax(0, 1fr); }
    .sh-split--nav { grid-template-columns: minmax(0, 1fr); }
    .sh-split__aside { position: static; }
    .sh-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
    :root { --sh-nav-w: 0px; }

    .sh-app {
        grid-template-columns: 1fr;
        grid-template-areas: "top" "main";
    }

    .sh-brand { display: none; }

    .sh-nav {
        position: fixed;
        top: 0; bottom: 0; left: 0;
        width: 262px;
        z-index: 950;
        transform: translateX(-100%);
        transition: transform .18s ease-out;
        box-shadow: var(--sh-shadow-lg);
        padding-top: .5rem;
    }
    .sh-nav.is-open { transform: none; }

    .sh-nav__backdrop {
        display: block;
        position: fixed;
        inset: 0;
        background: var(--sh-overlay);
        z-index: 940;
        border: 0;
    }

    .sh-nav-toggle { display: inline-flex; }

    .sh-main__inner { padding: .8rem .7rem 3rem; }
    .sh-grid--3, .sh-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .sh-form-grid, .sh-form-grid--3 { grid-template-columns: minmax(0, 1fr); }
    .sh-omnibox { max-width: none; }
    .sh-page-head h1 { font-size: 1.15rem; }
}

@media (max-width: 560px) {
    .sh-grid--2, .sh-grid--3, .sh-grid--4 { grid-template-columns: minmax(0, 1fr); }
    .sh-grid--cards { grid-template-columns: repeat(auto-fill, minmax(min(148px, 100%), 1fr)); }
    .sh-grid--gallery { grid-template-columns: repeat(auto-fill, minmax(min(110px, 100%), 1fr)); }
    .sh-dl { grid-template-columns: minmax(0, 1fr); gap: .1rem .5rem; }
    .sh-dl dt { margin-top: .35rem; }
    .sh-modal { max-height: calc(100vh - 1rem); }
}

/* --------------------------------------------- Fassungsvergleich (RULE-006)

   Der Zeilenvergleich zweier Regelfassungen. Feste Schriftbreite, weil untereinander
   stehende Zeilen nur dann untereinander stehen; umgebrochen wird trotzdem, sonst
   verschoebe eine lange Zeile die ganze Ansicht nach rechts. */

.sh-diff {
    border: 1px solid var(--sh-border-soft);
    border-radius: var(--sh-radius);
    overflow: hidden;
}

.sh-diff__line {
    display: flex;
    gap: .5rem;
    padding: .1rem .5rem;
    font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;
    font-size: .82rem;
    line-height: 1.45;
    border-bottom: 1px solid var(--sh-border-soft);
}

.sh-diff__line:last-child { border-bottom: 0; }

.sh-diff__mark {
    flex: 0 0 1ch;
    color: var(--sh-text-faint);
    user-select: none;
}

.sh-diff__text {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    min-width: 0;
}

.sh-diff__line--weg { background: var(--sh-danger-soft); }
.sh-diff__line--weg .sh-diff__mark { color: var(--sh-danger); }

.sh-diff__line--neu { background: var(--sh-success-soft); }
.sh-diff__line--neu .sh-diff__mark { color: var(--sh-success); }

/* ------------------------------------------------------------- Druck */

@media print {
    :root {
        --sh-bg: #fff; --sh-bg-2: #fff;
        --sh-surface: #fff; --sh-surface-2: #fff; --sh-surface-3: #f2f2f2;
        --sh-text: #000; --sh-text-dim: #333; --sh-text-faint: #666;
        --sh-border: #bbb; --sh-border-soft: #ddd; --sh-border-strong: #999;
        --sh-accent: #0a6f66; --sh-gold: #876b1e; --sh-blue: #1d4f9c;
        /* Auf Papier behielten diese vier bis zum 26.09.2026 ihre Bildschirmwerte und
           standen auf Weiss bei 2,2 bis 3,7 : 1. Je der kleinste Schritt dunkler in
           derselben Farbe, der 4,5 : 1 erreicht (UI-009); Gold ebenso, von #8a6d1f. */
        --sh-danger: #cf2634; --sh-success: #2e7d4d; --sh-warn: #956518; --sh-purple: #8d50c9;
    }

    body { background: #fff; color: #000; font-size: 10.5pt; }

    .sh-app {
        display: block;
        height: auto;
        overflow: visible;
    }
    .sh-nav, .sh-brand, .sh-topbar, .sh-nav__backdrop,
    .sh-page-head__actions, .sh-card__actions, .sh-tabs, .sh-guest,
    .sh-btn, .sh-pager, #blazor-error-ui { display: none !important; }

    .sh-main { overflow: visible; }
    .sh-main__inner { padding: 0; max-width: none; }

    /* Auf Papier gibt es keinen Bildlauf. Ohne diese Gegenregel schnitte ein
       gedrucktes Regelkapitel jede Tabellenspalte ab, die breiter als die Seite
       ist — der Kasten aus UI-015 haette den Druck kaputtgemacht. */
    .sh-table-wrap { overflow: visible; }

    .sh-card { border: 1px solid #bbb; break-inside: avoid; page-break-inside: avoid; }
    .sh-split { display: block; }

    /* UI-018, REQ-UI-011: „ohne Navigation" heisst ohne Seitenspalte.

       Bis zum 03.09.2026 wurde die Spalte nur untereinander gelegt statt weggelassen —
       gedruckt kam sie mit, nur eben unter dem Inhalt. Bei einem Regelkapitel war das
       das komplette Kapitelverzeichnis vor dem Text.

       Die Regel steht hier an einer Stelle und nicht als `sh-no-print` in jeder Ansicht;
       die naechste haette es vergessen. Wo eine Seitenspalte ausnahmsweise Inhalt und
       nicht Navigation traegt, sagt die Ansicht das ausdruecklich ueber
       `sh-split__aside--inhalt` — das ist die benannte Ausnahme, nicht das Aufweichen
       der Regel. */
    .sh-split__aside { display: none; }
    .sh-split__aside--inhalt { display: grid; margin-top: 1rem; }

    .sh-attr__pip { border: 1px solid #999; }
    .sh-attr__pip.is-on { background: #333; }
    .sh-attr__pip.is-core { background: #8a6d1f; }

    /* Die Druckansicht des Regelwerks: jedes Kapitel auf einer eigenen Seite. Ohne das
       liefen achtundzwanzig Kapitel ineinander, und ein Kapitelanfang stuende irgendwo
       auf halber Hoehe (RULE-004). */
    .sh-chapter--druck { break-before: page; page-break-before: always; }
    .sh-chapter--druck:first-of-type { break-before: auto; page-break-before: auto; }

    a { color: #000; text-decoration: none; }
    .sh-print-only { display: block !important; }
    .sh-no-print { display: none !important; }
}

.sh-print-only { display: none; }

/* ------------------------------------------------- Bewegungsreduktion */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}


/* ---------------------------------------------------------- Legacy-Import */

/* Ablagefläche für das Backup-Archiv.

   `position: relative` gehoert hierher und stand bis zum 04.09.2026 dreissig Zeilen
   weiter unten als zweite, einzeilige Deklaration desselben Selektors - hinter der
   Regel, die es braucht. Wer die Flaeche liest, sah nicht, worauf sich das `inset: 0`
   der Dateiauswahl bezieht. */
.sh-dropzone {
    position: relative;
    display: grid;
    justify-items: center;
    gap: .4rem;
    padding: 2.5rem 1.5rem;
    border: 2px dashed var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-bg-2);
    cursor: pointer;
    text-align: center;
    transition: border-color .15s, background .15s;
}

.sh-dropzone:hover,
.sh-dropzone:focus-within { border-color: var(--sh-accent); background: var(--sh-surface-2); }

.sh-dropzone__icon { opacity: .55; }
.sh-dropzone__title { font-weight: 600; }
.sh-dropzone__hint { font-size: .8rem; color: var(--sh-text-dim); }

/* Die Dateiauswahl selbst bleibt bedienbar, ist aber unsichtbar: die
   umgebende Fläche nimmt Klick und Drag-and-drop entgegen. */
.sh-dropzone__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

/* Zahlenspalten in Tabellen. */
.sh-num { text-align: right; font-variant-numeric: tabular-nums; }
.sh-pos { color: var(--sh-success); }
.sh-neg { color: var(--sh-danger); }

/* Berichte im Klartext. */
.sh-pre {
    margin: 0;
    padding: .75rem;
    overflow-x: auto;
    max-height: 28rem;
    border-radius: var(--sh-radius);
    background: var(--sh-bg-2);
    border: 1px solid var(--sh-border-soft);
    font-family: var(--sh-mono, ui-monospace, monospace);
    font-size: .74rem;
    line-height: 1.45;
    white-space: pre;
}

/* `.sh-pre--wrap` stand hier bis zum 02.09.2026.

   Es war die Notloesung fuer genau eine Stelle: den Fraktionsverlauf, der als Wortlaut
   in einem <pre> stand, weil es keine gemeinsame Darstellung fuer Markdown gab. Es gibt
   sie jetzt — BbCode liest beides —, der Verlauf wird gesetzt statt abgeschrieben, und
   die Regel hatte keinen Benutzer mehr. Eine tote Regel mit einer Begruendung, die auf
   eine verschwundene Stelle zeigt, ist schlimmer als keine. */

.sh-card--inset { background: var(--sh-bg-2); box-shadow: none; }

/* Das aufgeschlagene Sprungziel aus der Suche (SYS-012). Der Rahmen ersetzt kein
   Blinken: Die Zeile soll auffindbar sein, nicht aufdringlich. */
.sh-card--gesucht { border-color: rgba(217, 180, 90, .55); background: var(--sh-gold-soft); }

/* Aufklappbarer Bericht: der Kopf bleibt klickbar. */
details.sh-card > summary { cursor: pointer; list-style: none; }
details.sh-card > summary::-webkit-details-marker { display: none; }
details.sh-card > summary::after { content: "▾"; margin-left: auto; opacity: .5; }
details.sh-card[open] > summary::after { content: "▴"; }

/* Vorschaubild in Änderungslisten — 44px, bewusst briefmarkengroß.
   Muss "--mini" heißen: Als zweites `.sh-thumb` stand die Regel weiter unten in der
   Datei und gewann damit die Kaskade gegen die Galerieregel (Zeile 1023). Folge war,
   dass jedes Galeriebild auf 44px zusammenfiel und in einer 200px-Spalte als
   Briefmarke mit riesigen Lücken stand. */
.sh-thumb--mini {
    display: block;
    width: 44px;
    height: 44px;
    aspect-ratio: auto;
    border-radius: calc(var(--sh-radius) / 2);
    overflow: hidden;
    background: var(--sh-bg-2);
    border: 1px solid var(--sh-border-soft);
}

.sh-thumb--mini img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Filterchip als Schaltfläche. */
.sh-chip--button { cursor: pointer; background: none; font: inherit; }
.sh-chip--button.is-active { border-color: var(--sh-accent); color: var(--sh-accent); }

/* Machtskala oberhalb der normalen Skala D–S+. Bewusst deutlich abgesetzt: sie
   beschreibt eine andere Größenordnung, keine weitere Stufe. */
.sh-powerscale {
    padding: .6rem .75rem;
    border-radius: var(--sh-radius);
    border: 1px solid var(--sh-gold);
    background: linear-gradient(135deg, rgba(201, 162, 39, .14), rgba(140, 30, 40, .16));
}

.sh-powerscale__label {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--sh-gold);
}

.sh-powerscale__value {
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--sh-gold);
}

.sh-powerscale__note { font-size: .72rem; color: var(--sh-text-dim); }

/* Hinweis zum Stand eines Bereichs im Charakterbogen. */
.sh-sectionstate {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .6rem .75rem;
    margin-bottom: var(--sh-gap);
    border-radius: var(--sh-radius);
    border: 1px solid var(--sh-border);
    background: var(--sh-bg-2);
}

.sh-sectionstate > div { flex: 1; min-width: 0; }
.sh-sectionstate--open { border-color: var(--sh-accent); }
.sh-sectionstate--review { border-color: var(--sh-gold); }
.sh-sectionstate--muted { opacity: .7; }

/* Entwicklungsstand im Charakterbogen.

   Bis zum 04.09.2026 stand dieser Block ZWEIMAL in dieser Datei, beide Male mit
   derselben Ueberschrift und mit verschiedenen Werten. Gewirkt hat eine Mischung aus
   beiden: die spaeteren Werte, dazu `align-items: center` aus dem `place-items` des
   frueheren, das die spaetere Fassung nicht setzte. Genau diese Mischung steht jetzt
   ausgeschrieben da - das Aussehen aendert sich nicht, aber man kann es lesen. */
.sh-level {
    display: grid;
    justify-items: center;
    align-items: center;
    align-content: center;
    min-width: 4.5rem;
    padding: .4rem .6rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface-2);
}

.sh-level__label {
    font-size: .68rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--sh-text-dim);
}

.sh-level__value {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--sh-gold);
}

.sh-fieldset {
    border: 1px solid var(--sh-border-soft);
    border-radius: var(--sh-radius);
    padding: .75rem;
}

.sh-fieldset legend { padding: 0 .4rem; font-size: .74rem; color: var(--sh-text-dim); }

.sh-field > span { font-size: .74rem; color: var(--sh-text-dim); }
.sh-input--num { max-width: 6rem; }
.sh-input--area { min-height: 4.5rem; resize: vertical; }

/* ---------------------------------------------------------------- Kartengitter
   Für Verzeichnisse, die eher gelesen als überflogen werden: Spezies, später auch
   die Auswahlschritte des Charakter-Wizards. */

.sh-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
    gap: var(--sh-gap);
    align-items: start;
}

.sh-card--tile .sh-card__body { padding: .6rem .75rem; }

/* Ein Merkmal: Wert links, Bedeutung rechts. */
.sh-trait {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: .45rem;
    align-items: start;
}

.sh-note {
    padding: .4rem .55rem;
    border-left: 2px solid var(--sh-border-strong);
    background: var(--sh-surface-2);
    border-radius: 0 var(--sh-radius) var(--sh-radius) 0;
}

.sh-note--sm { font-size: .78rem; }

.sh-chip--xs { padding: 0 .3rem; font-size: .68rem; }

.sh-field--grow { flex: 1 1 16rem; }

/* Nur noch hier (UX-020). Weiter oben stand dasselbe Paar mit `padding-block`; die
   Kurzform `padding` unten hat es vollstaendig ueberschrieben, es war also seit jeher
   wirkungslos. */
.sh-dl--tight dt, .sh-dl--tight dd { padding: .12rem 0; }

.sh-table--tight th, .sh-table--tight td { padding: .28rem .45rem; }
.sh-td--num { width: 3.2rem; text-align: center; white-space: nowrap; }

.sh-row--muted td { color: var(--sh-text-faint); }

/* Eine gewaehlte Tabellenzeile - etwa der Bereich, der im Chatarchiv als Lorequelle
   festgeschrieben werden soll (LORE-015). Flaeche UND Randlinie: Farbe allein traegt
   keine Aussage (REQ-UX-015), und die gedrueckte Zeilennummer sagt es zusaetzlich. */
.sh-row--gewaehlt td { background: var(--sh-accent-soft); }
.sh-row--gewaehlt td:first-child { box-shadow: inset 3px 0 0 var(--sh-accent); }

.sh-cards details > summary { cursor: pointer; color: var(--sh-text-dim); }
.sh-cards details[open] > summary { margin-bottom: .3rem; }

/* ------------------------------------------------------------------ Regelwerk
   Das Regelwerk wird gelesen, nicht überflogen: ruhige Typografie, klare Absätze,
   Kapitelnavigation immer sichtbar. */

.sh-rulebook-nav { display: grid; gap: 1rem; align-content: start; }
.sh-rulebook-nav__group { display: grid; gap: .1rem; }

.sh-rulebook-nav__item {
    display: grid;
    grid-template-columns: 1.6rem 1fr;
    gap: .3rem;
    align-items: baseline;
    width: 100%;
    padding: .22rem .35rem;
    border: 0;
    border-radius: var(--sh-radius);
    background: transparent;
    color: var(--sh-text-dim);
    font: inherit;
    font-size: .82rem;
    text-align: left;
    cursor: pointer;
}

.sh-rulebook-nav__item:hover { background: var(--sh-surface-2); color: var(--sh-text); }
.sh-rulebook-nav__item:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-rulebook-nav__item.is-active {
    background: var(--sh-accent-soft);
    color: var(--sh-accent);
    box-shadow: inset 2px 0 0 var(--sh-accent);
}
.sh-rulebook-nav__no { color: var(--sh-text-faint); font-variant-numeric: tabular-nums; }
.sh-rulebook-nav__item.is-active .sh-rulebook-nav__no { color: inherit; }

.sh-chapter__head { margin-bottom: 1.2rem; }
.sh-chapter__head h2 { margin: .1rem 0 .3rem; }

.sh-chapter__foot {
    display: flex;
    justify-content: space-between;
    gap: var(--sh-gap);
    margin-top: 1.5rem;
    padding-top: .8rem;
    border-top: 1px solid var(--sh-border-soft);
}

.sh-rule { margin-bottom: 1.4rem; }
.sh-rule__title {
    margin: 0 0 .35rem;
    font-size: .95rem;
    color: var(--sh-gold);
}
.sh-rule__body > :first-child { margin-top: 0; }
.sh-rule__body > :last-child { margin-bottom: 0; }
.sh-rule__body p { margin: .35rem 0; max-width: 74ch; line-height: 1.6; }
.sh-rule__body code {
    padding: .05rem .28rem;
    border-radius: 3px;
    background: var(--sh-surface-2);
    font-family: var(--sh-font-mono);
    font-size: .85em;
}

.sh-list { margin: .35rem 0; padding-left: 1.1rem; max-width: 74ch; line-height: 1.6; }
.sh-list li { margin: .18rem 0; }
.sh-list--num { list-style: decimal; }

/* ------------------------------------------------------- Charakter-Wizard
   Die Schrittführung bleibt immer sichtbar: bei 24 Schritten muss jederzeit
   erkennbar sein, wo man steht und was noch fehlt. */

.sh-wizard-nav { display: grid; gap: .9rem; align-content: start; }
.sh-wizard-nav__group { display: grid; gap: .1rem; }

.sh-wizard-nav__item {
    display: grid;
    grid-template-columns: 1.5rem 1fr auto;
    gap: .35rem;
    align-items: center;
    width: 100%;
    padding: .22rem .35rem;
    border: 0;
    border-radius: var(--sh-radius);
    background: transparent;
    color: var(--sh-text-dim);
    font: inherit;
    font-size: .82rem;
    text-align: left;
    cursor: pointer;
}

.sh-wizard-nav__item:hover { background: var(--sh-surface-2); color: var(--sh-text); }
.sh-wizard-nav__item:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-wizard-nav__item.is-active {
    background: var(--sh-accent-soft);
    color: var(--sh-accent);
    box-shadow: inset 2px 0 0 var(--sh-accent);
}
.sh-wizard-nav__no { color: var(--sh-text-faint); font-variant-numeric: tabular-nums; }
.sh-wizard-nav__item.is-active .sh-wizard-nav__no { color: inherit; }
.sh-wizard-nav__mark { font-size: .8rem; }
.sh-wizard-nav__mark.is-done { color: var(--sh-success); }
.sh-wizard-nav__mark.is-open { color: var(--sh-warn); }

/* Eine Auswahl, die ihre Begründung gleich mitbringt. */
.sh-choice {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: .55rem;
    align-items: start;
    padding: .5rem .6rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
    cursor: pointer;
}

.sh-choice:hover { border-color: var(--sh-border-strong); }
/* Den Fokus trägt das Auswahlfeld darin; die Fläche zeigt ihn mit, damit man auf
   der Tastatur sieht, welche Auswahl samt Begründung gemeint ist (UI-009). Nur bei
   :focus-visible — ein Mausklick soll keinen Rahmen hinterlassen. */
.sh-choice:has(:focus-visible) { outline: 2px solid var(--sh-accent); outline-offset: 1px; }
.sh-choice.is-active { border-color: var(--sh-accent-line); background: var(--sh-accent-soft); }
.sh-choice input { margin-top: .25rem; }

.sh-card--tile.is-selected {
    border-color: var(--sh-accent-line);
    box-shadow: 0 0 0 1px var(--sh-accent-line);
}

.sh-row--active td { background: var(--sh-accent-soft); }

/* ------------------------------------------------------------- Bilderliste
   Im Wizard zählt die Zuordnung, nicht die Bildwirkung: kleine Vorschau,
   Dateiname und die Aktionen daneben. */

.sh-imagelist { display: grid; gap: .4rem; }

.sh-imagelist__item {
    display: grid;
    grid-template-columns: 64px 1fr auto;
    gap: .6rem;
    align-items: center;
    padding: .4rem .5rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
}

.sh-imagelist__item.is-portrait { border-color: rgba(217, 180, 90, .35); }

.sh-imagelist__thumb {
    width: 64px;
    height: 64px;
    border-radius: var(--sh-radius);
    overflow: hidden;
    background: var(--sh-surface-2);
}

/* object-position wie an jeder anderen Flaeche: Der Schwerpunkt kommt ueber
   ProtectedImage am <img> an, der Ersatzwert ist das bisherige Verhalten (MEDIA-012). */
.sh-imagelist__thumb img {
    width: 100%; height: 100%; object-fit: cover; display: block;
    object-position: var(--sh-focus, center);
}

.sh-imagelist__missing {
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    color: var(--sh-danger);
}

/* Die Knöpfe bleiben in der ERSTEN Zeile, dritte Spalte — ausdrücklich gesetzt und
   nicht der automatischen Platzierung überlassen. Sobald ein weiteres Kind in die Zeile
   kommt (der Ausschnitt-Editor), schöbe die Automatik sie in eine zweite Zeile, wo sie
   bei Spalte eins beginnen und mit flex-end nach links aus dem Kasten laufen. */
.sh-imagelist__actions {
    grid-column: 3;
    grid-row: 1;
    display: flex;
    gap: .25rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* Der Ausschnitt-Editor ist kein Zeilenteil, sondern eine eigene Zeile über die ganze
   Breite. Er trägt eine Karte mit Vorschau und zwei Reglern; in einer 'auto'-Spalte neben
   einem 64-Pixel-Bild ergibt das kein Bild, sondern einen Unfall. */
.sh-imagelist__ausschnitt {
    grid-column: 1 / -1;
    grid-row: 2;
    min-width: 0;
}

.sh-gallery__item.is-selected { outline: 2px solid var(--sh-accent); outline-offset: 2px; }

/* ------------------------------------------------------------- Medien-Galerie
   Kachel des Medienbestands: oben das Bild, darunter Dateiname und die
   Verknüpfungen. Die Beschriftung steht bewusst neben und nicht in der
   Bildschaltfläche — ein verknüpfter Charaktername ist selbst anklickbar,
   und eine Schaltfläche in einer Schaltfläche gibt es nicht. */

.sh-medialib {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr));
    gap: var(--sh-gap);
}

.sh-medialib__tile {
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow: hidden;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
}

/* Der Rahmen gehört zur Kachel, nicht zusätzlich zur Bildschaltfläche. */
.sh-medialib__tile .sh-gallery__item { border: 0; border-radius: 0; transform: none; }
.sh-medialib__tile:hover { border-color: var(--sh-accent); }

.sh-medialib__body {
    display: grid;
    gap: .28rem;
    min-width: 0;
    padding: .45rem .55rem .5rem;
}

.sh-medialib__name { font-size: .8rem; font-weight: 600; }

.sh-medialib__links { display: flex; flex-wrap: wrap; gap: .25rem; }

.sh-medialib__foot { display: flex; justify-content: flex-end; }

@media (max-width: 560px) {
    .sh-medialib { grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); }
}

/* ------------------------------------------------------------------ Kalender
   Monatsraster mit sieben Spalten, Montag zuerst. Die Tageszelle trägt nur die
   kleine Terminmarke — Zeit, Titel und die Zahl der abwesend gemeldeten
   Teilnehmer. Alles Weitere steht in der Terminliste daneben, weil eine
   Rasterzelle für Teilnehmerlisten zu schmal ist.

   Ein abgesagter Termin verschwindet nicht: er bleibt an seinem Tag stehen und
   wird durchgestrichen. Wer den Termin einmal gesehen hat, soll dort die Absage
   finden und nicht vor einer Lücke stehen. */

.sh-cal { display: grid; gap: .4rem; min-width: 0; }

.sh-cal__bar { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }

.sh-cal__month {
    min-width: 9.5rem;
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: -.01em;
    text-align: center;
}

.sh-cal__grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 1px;
    overflow: hidden;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-border-soft);
}

.sh-cal__weekday {
    padding: .3rem .4rem;
    background: var(--sh-surface-2);
    color: var(--sh-text-dim);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-align: center;
    text-transform: uppercase;
}

.sh-cal__day {
    display: flex;
    flex-direction: column;
    gap: .2rem;
    min-height: 6.4rem;
    min-width: 0;
    padding: .25rem;
    background: var(--sh-surface);
}

/* Tage der Nachbarmonate bleiben sichtbar, treten aber zurück. */
.sh-cal__day--out { background: var(--sh-bg-2); }
.sh-cal__day--out .sh-cal__num { color: var(--sh-text-faint); }

.sh-cal__day--today {
    background: var(--sh-accent-soft);
    box-shadow: inset 0 0 0 1px var(--sh-accent-line);
}

.sh-cal__num {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .25rem;
    color: var(--sh-text-dim);
    font-size: .76rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.sh-cal__badge {
    color: var(--sh-accent);
    font-size: .62rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.sh-cal__events { display: grid; gap: 2px; min-width: 0; }

.sh-cal__event {
    display: flex;
    align-items: baseline;
    gap: .25rem;
    width: 100%;
    min-width: 0;
    padding: .12rem .28rem;
    border: 0;
    border-left: 2px solid var(--sh-border-strong);
    border-radius: 2px;
    background: var(--sh-surface-2);
    color: var(--sh-text);
    font: inherit;
    font-size: .72rem;
    text-align: left;
    cursor: pointer;
}

.sh-cal__event:hover { background: var(--sh-surface-3); }
.sh-cal__event:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }

.sh-cal__event--open {
    background: var(--sh-surface-3);
    box-shadow: inset 0 0 0 1px var(--sh-accent-line);
}

.sh-cal__event--session { border-left-color: var(--sh-accent); }
.sh-cal__event--meeting { border-left-color: var(--sh-blue); }
.sh-cal__event--deadline { border-left-color: var(--sh-gold); }
.sh-cal__event--other { border-left-color: var(--sh-text-faint); }

.sh-cal__event--cancelled { opacity: .62; }
.sh-cal__event--cancelled .sh-cal__time,
.sh-cal__event--cancelled .sh-cal__label { text-decoration: line-through; }

.sh-cal__time { flex: 0 0 auto; color: var(--sh-text-faint); font-variant-numeric: tabular-nums; }

.sh-cal__label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Die Zahl der abwesend gemeldeten Teilnehmer — der eigentliche Hinweis. */
.sh-cal__warn {
    flex: 0 0 auto;
    min-width: 1.05rem;
    padding: 0 .2rem;
    border-radius: 999px;
    background: var(--sh-warn-soft);
    color: var(--sh-warn);
    font-size: .66rem;
    font-weight: 700;
    text-align: center;
}

/* Gemeldete Abwesenheiten des Tages (ABS-003). Sie stehen unter den Terminen
   und erscheinen auch dann, wenn an dem Tag gar kein Termin liegt. */
.sh-cal__absent { display: grid; gap: 1px; min-width: 0; margin-top: auto; }

.sh-cal__absent-item {
    min-width: 0;
    overflow: hidden;
    padding: .05rem .28rem;
    border-left: 2px solid var(--sh-warn);
    border-radius: 2px;
    background: var(--sh-warn-soft);
    color: var(--sh-warn);
    font-size: .66rem;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.sh-cal__legend {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    color: var(--sh-text-faint);
    font-size: .72rem;
}

.sh-cal__legend-item { display: inline-flex; align-items: center; gap: .3rem; }

.sh-cal__dot { width: .5rem; height: .5rem; border-radius: 2px; background: var(--sh-border-strong); }
.sh-cal__dot.sh-cal__event--session { background: var(--sh-accent); }
.sh-cal__dot.sh-cal__event--meeting { background: var(--sh-blue); }
.sh-cal__dot.sh-cal__event--deadline { background: var(--sh-gold); }
.sh-cal__dot.sh-cal__event--other { background: var(--sh-text-faint); }

.sh-cal__struck { text-decoration: line-through; }

.sh-cal__picked { box-shadow: inset 0 0 0 1px var(--sh-accent-line); }

.sh-cal__people { display: grid; gap: .2rem; min-width: 0; }

.sh-cal__person {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .3rem;
    min-width: 0;
    padding: .15rem .3rem;
    border-radius: 2px;
    background: var(--sh-surface-2);
    font-size: .78rem;
}

/* Wer im Zeitraum abwesend gemeldet ist, fällt in der Zeile sofort auf. */
.sh-cal__person--absent { background: var(--sh-warn-soft); }

.sh-cal__person-name { font-weight: 600; }

@media (max-width: 860px) {
    .sh-cal__day { min-height: 4.8rem; padding: .18rem; }
    .sh-cal__event { font-size: .66rem; }
    .sh-cal__time { display: none; }
    .sh-cal__month { min-width: 7rem; font-size: .95rem; }
}

/* ------------------------------------------------------- Katalogauswahl
   Gruppierte Auswahl grosser Kataloge (CatalogPicker, KAT-001).
   Die Gruppenkoepfe sind echte Schaltflaechen: der Aufklappzustand liegt
   in C#, damit die Suche eine Gruppe zuverlaessig oeffnen kann. */

.sh-catpick { display: grid; gap: .4rem; }

.sh-catpick__group {
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
    overflow: hidden;
}

.sh-catpick__head {
    display: flex;
    align-items: center;
    gap: .45rem;
    width: 100%;
    padding: .38rem .55rem;
    border: 0;
    background: var(--sh-surface-2);
    color: var(--sh-text);
    font: inherit;
    font-size: .84rem;
    font-weight: 600;
    line-height: 1.3;
    text-align: left;
    cursor: pointer;
}

.sh-catpick__head:hover { background: var(--sh-surface-3); }
.sh-catpick__head:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }

.sh-catpick__mark { flex: 0 0 auto; color: var(--sh-text-faint); }

.sh-catpick__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sh-catpick__body {
    display: grid;
    gap: .15rem;
    padding: .3rem;
    border-top: 1px solid var(--sh-border);
}

.sh-catpick__item {
    display: grid;
    gap: .08rem;
    width: 100%;
    padding: .3rem .45rem;
    border: 1px solid transparent;
    border-radius: var(--sh-radius);
    background: transparent;
    color: var(--sh-text);
    font: inherit;
    font-size: .83rem;
    line-height: 1.45;
    text-align: left;
    cursor: pointer;
}

.sh-catpick__item:hover:not(:disabled) {
    border-color: var(--sh-accent-line);
    background: var(--sh-accent-soft);
}

.sh-catpick__item:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }

/* Gesperrt (ReadOnly): sichtbar, aber gedaempft und nicht anklickbar.
   Ausdruecklich nicht "bereits gewaehlt" -- eine gewaehlte Zeile bleibt
   anklickbar, sonst liesse sie sich nicht wieder abwaehlen. */
.sh-catpick__item:disabled { opacity: .45; cursor: not-allowed; }

.sh-catpick__title { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; }

.sh-catpick__text { font-size: .74rem; color: var(--sh-text-faint); }

/* ------------------------------------------ Katalogauswahl: Details (REQ-UX-022/023)
   Neben jedem Umschalter steht ein eigener Knopf fuer die Details -- zwei getrennte
   Bedienelemente, damit Nachlesen nie eine Wahl ausloest. Die Details stehen in einer
   seitlichen Flaeche derselben Auswahl, der Wizard wird nicht verlassen.
   Die Breite misst die Auswahl selbst (Containerabfrage) und nicht der Bildschirm:
   Im Schritt Staerken/Schwaechen stehen zwei Auswahlen nebeneinander, und eine
   Bildschirmregel gaebe jeder davon eine Seitenflaeche, fuer die kein Platz ist.
   Schmal steht die Flaeche deshalb ueber der Liste, breit daneben. */
.sh-catpick { container-type: inline-size; }

.sh-catpick__rahmen { display: grid; gap: .6rem; }

.sh-catpick__liste { display: grid; gap: .4rem; min-width: 0; }

.sh-catpick__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: .2rem;
    align-items: start;
}

.sh-catpick__info {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    margin-top: .15rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface-2);
    color: var(--sh-text-faint);
    cursor: pointer;
}

.sh-catpick__info:hover { border-color: var(--sh-accent-line); color: var(--sh-text); }
.sh-catpick__info:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 1px; }
.sh-catpick__info.is-active { border-color: var(--sh-accent); color: var(--sh-accent); background: var(--sh-accent-soft); }

.sh-catpick__rahmen--mit-detail .sh-catpick__detail { order: -1; }

.sh-catpick__detail {
    display: grid;
    gap: .45rem;
    min-width: 0;
    padding: .6rem .7rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface-2);
}

.sh-catpick__detailkopf { display: flex; align-items: center; gap: .4rem; }

.sh-catpick__detailname { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }

.sh-catpick__detailliste { display: grid; gap: .3rem; margin: 0; }
.sh-catpick__detailliste dt { font-size: .72rem; color: var(--sh-text-faint); }
.sh-catpick__detailliste dd { margin: 0; font-size: .82rem; line-height: 1.45; overflow-wrap: anywhere; }

@container (min-width: 40rem) {
    .sh-catpick__rahmen--mit-detail {
        grid-template-columns: minmax(0, 1fr) minmax(0, 18rem);
        align-items: start;
    }

    .sh-catpick__rahmen--mit-detail .sh-catpick__detail {
        order: 0;
        position: sticky;
        top: .75rem;
        max-height: calc(100vh - 1.5rem);
        overflow-y: auto;
    }
}

/* ============ Schritt 15: Staerken und Schwaechen (SW-001) ============ */

/* Zwei Bereiche nebeneinander, auf schmalen Schirmen untereinander.
   Reines CSS Grid mit einer Medienabfrage, kein JavaScript.

   minmax(0, 1fr) statt 1fr ist hier tragend und nicht schmueckend: die
   Vorgabegroesse eines Grid-Bereichs ist "auto", also mindestens so breit
   wie sein laengster unteilbarer Inhalt. Eine lange Katalogzeile wuerde die
   Spalte damit ueber die Seite hinaus aufziehen und genau die waagerechte
   Bildlaufleiste erzeugen, die es nicht geben darf. */
.sh-traits {
    display: grid;
    gap: var(--sh-gap);
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
}

/* Dieselbe Ueberlegung eine Ebene tiefer: ein Flex- oder Grid-Kind darf von
   sich aus nicht unter seine Inhaltsbreite schrumpfen. */
.sh-traits > * { min-width: 0; }

/* Der Bereich fuer einen eigenen Eintrag: eingeklappt und deutlich
   abgesetzt, damit er nicht mehr vor der Katalogauswahl steht.
   Eigene Schaltflaeche statt <details>: der Aufklappzustand gehoert damit
   ausschliesslich nach C# und nicht dem Browser -- genau wie bei
   .sh-catpick, und aus demselben Grund. */
.sh-fold {
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
    overflow: hidden;
}

.sh-fold__head {
    display: flex;
    align-items: center;
    gap: .35rem;
    width: 100%;
    padding: .35rem .5rem;
    border: 0;
    background: var(--sh-surface-2);
    color: var(--sh-text);
    font: inherit;
    font-size: .84rem;
    font-weight: 600;
    line-height: 1.3;
    text-align: left;
    cursor: pointer;
}

.sh-fold__head:hover { background: var(--sh-surface-3); }
.sh-fold__head:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.sh-fold__head:disabled { opacity: .45; cursor: not-allowed; }

.sh-fold__mark { flex: 0 0 auto; color: var(--sh-text-faint); }

.sh-fold__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sh-fold__body {
    padding: .5rem;
    border-top: 1px solid var(--sh-border);
}

@media (max-width: 1100px) {
    .sh-traits { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------ Katalogauswahl: Auswahlzustand
   Die Zeile im CatalogPicker ist ein Umschalter (aria-pressed), kein
   Einmalklick: eine gewaehlte Zeile bleibt anklickbar, damit sie sich auch
   wieder abwaehlen laesst. Gesperrt wird nur noch ueber ReadOnly.
   Deshalb braucht "gewaehlt" einen eigenen, deutlich sichtbaren Zustand —
   Kaestchen mit Haken, das Wort "Gewaehlt", abgesetzter Hintergrund und
   Rahmen. Eine zarte Rahmenfarbe allein reicht nicht.
   Nur angehaengt; oben stehende Regeln bleiben unveraendert. */

/* Kaestchen vor dem Namen. Es steht auch ungewaehlt da, damit die Namen
   nicht springen, sobald eine Zeile ihren Haken bekommt. */
.sh-catpick__box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    border: 1px solid var(--sh-border-strong);
    border-radius: 3px;
    background: var(--sh-surface-2);
    color: var(--sh-gold);
}

/* Anzahl gewaehlter Eintraege am Gruppenkopf: darf nicht schrumpfen. */
.sh-catpick__chosen { flex: 0 0 auto; }

.sh-catpick__item--chosen {
    border-color: var(--sh-gold-dim);
    background: var(--sh-gold-soft);
}

/* Ohne diese Regel uebernaehme der allgemeine Hover-Zustand der Zeile den
   Akzentton und der Unterschied zwischen gewaehlt und ungewaehlt ginge
   ausgerechnet unter dem Zeiger verloren. */
.sh-catpick__item--chosen:hover:not(:disabled) {
    border-color: var(--sh-gold);
    background: var(--sh-gold-soft);
}

.sh-catpick__item--chosen .sh-catpick__box {
    border-color: var(--sh-gold);
    background: var(--sh-gold-soft);
}

/* Gesperrt und gewaehlt: gedaempft, aber die getroffene Wahl bleibt lesbar. */
.sh-catpick__item--chosen:disabled { opacity: .7; }

/* Ein sehr langer eigener Name darf die Spalte nicht aufziehen. Ohne die Null als
   kleinste Breite weigert sich ein Flex-Kind, unter seine Inhaltsbreite zu gehen --
   die Auslassungspunkte an .sh-chip__text kaemen dann nie zum Zug. */
.sh-traits .sh-chip { overflow: hidden; }
.sh-traits .sh-chip__text { min-width: 0; }

/* ==========================================================================
   Geschlechtsakzent an Charakterkacheln (REQ-GEN-030 … REQ-GEN-033)

   Ein dezenter Rahmen, damit Figuren in langen Listen schneller auseinander-
   zuhalten sind. Die Kachel selbst bleibt dunkel — keine eingefaerbten
   Flaechen, kein Neon.

   Die Farbe stammt AUSSCHLIESSLICH aus der Geschlechtsidentitaet. Koerperliche
   Auspraegung und Transidentitaet haben keinerlei Einfluss: Ein Transmann sieht
   aus wie jeder andere maennliche Charakter. Alles andere waere eine sichtbare
   Sonderbehandlung.

   Die Klasse liefert GenderDisplay.Accent(...) — es gibt keine Hexfarbe in
   einer Razor-Datei und keinen Geschlechts-Schalter in einer Ansicht.
   ========================================================================== */

:root {
    --gender-male: #5b9cf0;
    --gender-female: #d96aa8;
    --gender-nonbinary: #a97bd6;
    --gender-agender: #93a0b3;
    --gender-genderfluid-a: #d96aa8;
    --gender-genderfluid-b: #5b9cf0;
    --gender-other: #2fd4c4;
    --gender-unspecified: var(--sh-border-strong);
}

/* Traeger der Akzentfarbe. Jede Kachel setzt nur ihre Klasse; alles Weitere
   richtet sich nach --gender-accent. */
.gender-male         { --gender-accent: var(--gender-male); }
.gender-female       { --gender-accent: var(--gender-female); }
.gender-nonbinary    { --gender-accent: var(--gender-nonbinary); }
.gender-agender      { --gender-accent: var(--gender-agender); }
.gender-other        { --gender-accent: var(--gender-other); }
.gender-unspecified  { --gender-accent: var(--gender-unspecified); }
.gender-genderfluid  { --gender-accent: var(--gender-genderfluid-a); }

/* Der eigentliche Rahmen. Bewusst nur der Rand und ein sehr leiser Schein. */
.sh-person, .sh-card--tile, .sh-char-card {
    transition: border-color var(--sh-fast), box-shadow var(--sh-fast);
}

.gender-male, .gender-female, .gender-nonbinary,
.gender-agender, .gender-other, .gender-unspecified {
    border-color: color-mix(in srgb, var(--gender-accent) 55%, var(--sh-border));
}

/* Der Akzent erscheint auch beim Tastaturfokus — neben dem Fokusrahmen der Kachel
   selbst (UI-009). */
.gender-male:hover, .gender-female:hover, .gender-nonbinary:hover,
.gender-agender:hover, .gender-other:hover, .gender-unspecified:hover,
.gender-male:focus-visible, .gender-female:focus-visible, .gender-nonbinary:focus-visible,
.gender-agender:focus-visible, .gender-other:focus-visible, .gender-unspecified:focus-visible {
    border-color: var(--gender-accent);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--gender-accent) 30%, transparent);
}

/* Genderfluid ist der einzige Fall mit Verlauf — ohne Bewegung, ohne Blinken.
   Der Rahmen entsteht aus zwei uebereinanderliegenden Hintergruenden, damit die
   Flaeche der Kachel dunkel bleibt. */
.gender-genderfluid {
    border-color: transparent;
    background-image:
        linear-gradient(var(--sh-surface), var(--sh-surface)),
        linear-gradient(135deg, var(--gender-genderfluid-a), var(--gender-genderfluid-b));
    background-origin: border-box;
    background-clip: padding-box, border-box;
}

.gender-genderfluid:hover,
.gender-genderfluid:focus-visible {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--gender-genderfluid-a) 30%, transparent);
}

/* Der Auswahlzustand muss trotz Geschlechtsakzent eindeutig bleiben: er sitzt
   INNEN, der Geschlechtsakzent aussen. Eine ausgewaehlte magentafarbene Kachel
   sieht damit weiterhin unverwechselbar ausgewaehlt aus (REQ-GEN-031). */
.gender-male.is-selected, .gender-female.is-selected, .gender-nonbinary.is-selected,
.gender-agender.is-selected, .gender-other.is-selected,
.gender-unspecified.is-selected, .gender-genderfluid.is-selected {
    box-shadow: inset 0 0 0 2px var(--sh-accent), var(--sh-shadow-glow);
}

/* ==========================================================================
   GEMEINSAME CHARAKTERKACHEL — .sh-char-card

   Eine Kachel fuer alle Ansichten: Charakterliste, Auswahlschritte, Beziehungen,
   Stammbaum. Vorher hat jede Ansicht ihre eigene gebaut; dieselbe Figur sah damit
   an drei Stellen unterschiedlich aus, und es gab keinen Ort, an dem sich das
   aendern liess.

   Die Rahmenfarbe steht hier NICHT. Sie stammt aus der Geschlechtsklasse weiter
   oben in dieser Datei und damit ausschliesslich aus der Geschlechtsidentitaet.
   Zustaende — Warnung, Fehler, gesperrt, tot, archiviert — laufen niemals ueber
   denselben Rahmen: sie stehen als Abzeichen im Text. Zwei Bedeutungen an einer
   Stelle waeren nicht auseinanderzuhalten.
   ========================================================================== */

/* Flaeche und Ausweichfarbe des Rahmens stehen bewusst gewichtslos in :where(...).
   Der Geschlechtsakzent steht in dieser Datei weiter oben; ohne diesen Kniff wuerde
   der spaetere Block ihn ueberschreiben. So bleibt jede bestehende Regel unberuehrt
   und der Akzent gewinnt trotzdem. */
:where(.sh-char-card) {
    border-color: var(--sh-border);
    background-color: var(--sh-surface);
}

/* Die Grundform ist portraitbetont: Bild oben ueber die volle Breite, Angaben
   unmittelbar darunter, beides EINE Karte (REQ-UX-027).

   Kein Innenabstand an der Karte selbst — sonst entstuende zwischen Bild und Rahmen
   ein Rand, und das Portrait saehe aus wie ein eingesetztes Bild statt wie ein Teil
   der Kachel. Der Abstand sitzt deshalb ausschliesslich im Koerper.

   overflow: hidden haelt die Bildecken am Radius der Karte. */
.sh-char-card {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-width: 0;
    padding: 0;
    overflow: hidden;
    border-width: 1px;
    border-style: solid;
    border-radius: var(--sh-radius);
    color: inherit;
    font: inherit;
    text-align: left;
}

button.sh-char-card { cursor: pointer; }

.sh-char-card:hover { text-decoration: none; }

.sh-char-card:focus-visible {
    outline: 2px solid var(--sh-accent);
    outline-offset: 1px;
}

/* Portrait und Ersatz. Die Flaeche bleibt dunkel: eingefaerbte Kacheln wuerden mit
   dem Akzent um dieselbe Aussage streiten. */
/* Festes Seitenverhaeltnis statt fester Hoehe: Alle Kacheln bleiben gleich hoch,
   unabhaengig davon, wie das Originalbild geschnitten ist (REQ-UX-030). Fehlt ein
   Portrait, bleibt genau dieselbe Flaeche stehen und traegt den Platzhalter — die
   Karte faellt nicht auf eine Listenzeile zurueck (REQ-UX-031). */
.sh-char-card__portrait {
    position: relative;
    display: grid;
    place-items: center;
    width: 100%;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    background: linear-gradient(155deg, var(--sh-surface-2), var(--sh-bg-2));
    color: var(--sh-text-faint);
}

/* Die beiden Kennzeichen auf dem Bild. Klein gehalten, damit das Portrait sichtbar
   bleibt (REQ-UX-029). Der dunkle Grund sichert die Lesbarkeit auf hellen Bildern. */
.sh-char-card__tag {
    position: absolute;
    top: var(--sh-space-xs);
    z-index: 1;
    display: inline-flex;
    align-items: center;
    max-width: calc(50% - var(--sh-space-sm));
}

.sh-char-card__tag--start { left: var(--sh-space-xs); }
.sh-char-card__tag--end { right: var(--sh-space-xs); }

/* Fehlt die Angabe, verschwindet das Kennzeichen ganz. Ein leeres Abzeichen auf dem
   Portrait sieht aus wie ein Darstellungsfehler und sagt nichts aus. */
.sh-char-card__tag:empty { display: none; }

.sh-char-card__tag > * {
    backdrop-filter: blur(2px);
    background-color: rgb(0 0 0 / .55);
}

/* cover statt contain: Die Flaeche wird vollstaendig gefuellt, das Seitenverhaeltnis
   des Originals bleibt erhalten, nichts wird verzerrt. Der Ausschnitt sitzt leicht
   oberhalb der Mitte — bei Figuren steht dort in aller Regel der Kopf, und ein
   mittiger Ausschnitt schneidet ihn bei hochformatigen Bildern gern ab. */
.sh-char-card__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;

    /* Der Bildausschnitt folgt dem am Bild gesetzten Schwerpunkt (REQ-MEDIA-016).

       Der Ersatzwert ist genau die Zeile, die hier vorher fest stand: Kacheln ohne
       gesetzten Schwerpunkt sehen unveraendert aus, es verschiebt sich nichts im
       Altbestand. „center 35%" statt „center" ist kein Zufall — bei einem Ganzkoerperbild
       trifft die Mitte oft nicht das Gesicht.

       Die Kennung --sh-focus setzt die Kachel als Stilangabe an der Portraitflaeche und
       vererbt sie an das <img>. Der Zahlwert wird ausschliesslich im ImageFocusService
       gebildet, und zwar mit InvariantCulture: unter deutscher Kultur entstuende
       „38,5%", und das ist ungueltiges CSS — der Browser ignorierte die Angabe
       stillschweigend, und die Kachel zeigte weiter die Mitte. */
    object-position: var(--sh-focus, center 35%);
}

/* Ohne Portrait: grosse Anfangsbuchstaben, damit die Flaeche nicht leer wirkt. */
.sh-char-card__initials {
    font-size: 2.4rem;
    font-weight: 700;
    letter-spacing: .02em;
}

/* Der Innenabstand der Karte sitzt hier, nicht an der Karte — siehe .sh-char-card. */
.sh-char-card__body {
    display: grid;
    gap: var(--sh-space-xs);
    min-width: 0;
    padding: var(--sh-space-sm);
}

/* Der Name ist die staerkste Angabe im Koerper und steht allein in seiner Zeile.
   Lange Namen brechen um, statt abgeschnitten zu werden: Ein halber Name ist als
   Kennzeichnung wertlos. Zwei Zeilen sind die Grenze. */
.sh-char-card__name {
    min-width: 0;
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: -.01em;
    line-height: 1.25;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

/* Die Machtzeile: eine Angabe, kein Zustand. Deshalb schlicht und einfarbig statt
   als Abzeichen zwischen den Zustandsabzeichen (REQ-UX-028). */
.sh-char-card__facts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sh-space-xs) var(--sh-space-sm);
    font-size: .72rem;
    color: var(--sh-text-dim);
}

/* Besitzer und Datum ganz unten, zurueckhaltend. */
.sh-char-card__foot {
    margin-top: 2px;
    font-size: .7rem;
    color: var(--sh-text-faint);
    overflow-wrap: anywhere;
}

.sh-char-card__badges {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sh-space-xs);
    min-width: 0;
}

.sh-char-card__meta {
    font-size: .74rem;
    color: var(--sh-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Der Auswahlzustand als Wort. Der Ring innen kommt aus dem Geschlechtsblock; hier
   steht das, was auch ohne Farbunterscheidung lesbar bleibt. */
.sh-char-card__chosen {
    display: inline-flex;
    align-items: center;
    justify-self: start;
    gap: var(--sh-space-xs);
    padding: 0 var(--sh-space-xs);
    border: 1px solid var(--sh-accent-line);
    border-radius: 3px;
    background: var(--sh-accent-soft);
    color: var(--sh-accent);
    font-size: .68rem;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}

/* Die Zelle der Charakterliste (ADMIN-005): Kachel und, fuer Konten mit einer
   Massenaktion, das Auswahlfeld darueber. Das Feld steht ausserhalb der Kachel, weil
   die Kachel selbst eine Schaltflaeche ist — ein Feld darin waere weder gueltig noch
   bedienbar. Die Kachel fuellt den Rest der Zelle, damit eine Rasterzeile weiter gleich
   hohe Kacheln zeigt. */
.sh-massen-zelle {
    display: flex;
    flex-direction: column;
    gap: var(--sh-space-xs);
    min-width: 0;
}

.sh-massen-zelle > .sh-char-card { flex: 1 1 auto; }

/* Kompakte Form fuer Stammbaum und Auswahllisten (REQ-UX-034).

   Sie ist die Sonderform und nicht die Grundform — genau diese Verwechslung war der
   Rueckschritt: Die schmale Zeile war fuer den Stammbaum gebaut und wurde danach auch
   fuer die Charakterliste benutzt, wodurch die portraitbetonte Karte verschwand.

   Hier kehrt der waagerechte Aufbau zurueck: kleines Portrait links, Text rechts.
   Im Stammbaum ist das richtig, weil dort Dutzende Figuren nebeneinander stehen und
   ein grosses Portrait die Verwandtschaftslinien unlesbar machen wuerde. */
.sh-char-card--compact {
    flex-direction: row;
    align-items: center;
    gap: var(--sh-space-sm);
    padding: var(--sh-space-xs) var(--sh-space-sm);
    width: auto;
    min-width: 9rem;
    max-width: 15rem;
}

.sh-char-card--compact .sh-char-card__portrait {
    flex: none;
    width: 28px;
    height: 28px;
    aspect-ratio: auto;
    border-radius: var(--sh-radius);
}

.sh-char-card--compact .sh-char-card__body { padding: 0; }

.sh-char-card--compact .sh-char-card__initials { font-size: .68rem; }

.sh-char-card--compact .sh-char-card__name {
    font-size: .78rem;
    font-weight: 600;
    /* In der Zeile ist Abschneiden richtig: Umbruch wuerde die Reihe im Stammbaum
       verschieben und die Linien verziehen. */
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sh-char-card--compact .sh-char-card__meta { font-size: .68rem; }
.sh-char-card--compact .sh-char-card__chosen { font-size: .64rem; }

/* Auf schmalen Geraeten bleibt das Portrait dominant (REQ-UX-031); enger werden nur
   die Abstaende. Das Bild zu verkleinern wuerde genau den Rueckschritt wiederholen,
   den diese Aenderung behebt. */
@media (max-width: 560px) {
    .sh-char-card__body { padding: var(--sh-space-xs) var(--sh-space-sm); }
    .sh-char-card__name { font-size: .92rem; }
    .sh-char-card--compact { min-width: 0; max-width: none; }
}





/* ============================================================== Weltkarte
   REQ-KARTE-001 bis REQ-KARTE-012.

   Die Karte ist ein Bild aus dem Kartenpaket. Die Anwendung legt formgenaue
   Polygone darueber — keine Rechtecke — und darauf eine leere Ebene, in die
   spaeter die Orte aus der Datenbank kommen. */
.karte {
  display: grid;
  grid-template-columns: minmax(0, 1.9fr) minmax(280px, 1fr);
  gap: var(--sh-space-l, 1.5rem);
  align-items: start;
}
@media (max-width: 1020px) { .karte { grid-template-columns: 1fr; } }

.karte__bild {
  position: relative;
  border-radius: var(--sh-radius, 10px);
  overflow: hidden;
  background: #0b0d13;
  line-height: 0;
}

.karte__grundbild { width: 100%; height: auto; display: block; }

/* Die Overlay-Ebene und der Hover-Zustand sind am 27.08.2026 entfernt (siehe
   WorldMapView.razor). Was bleibt, ist die AUSWAHL -- sie entsteht durch Anklicken und
   nicht durch Darueberfahren. */

/* Die Klickflaechen liegen als Polygone ueber dem Bild. */
.karte__felder { position: absolute; inset: 0; width: 100%; height: 100%; }

.karte__feld {
  fill: #ffffff;
  fill-opacity: 0;
  stroke: none;
  cursor: pointer;
  transition: fill-opacity .12s ease;
}
.karte__feld.is-gewaehlt { fill-opacity: .08; }
/* Ein Riegel und kein Schoenheitsstrich: Das Polygon traegt seit dem 28.08.2026 kein
   tabindex mehr, kann also gar nicht mehr den Fokus bekommen. Faellt es doch einmal
   jemandem ein, eines wieder fokussierbar zu machen, darf der Browser trotzdem KEINEN
   Rahmen um das Umgebungsrechteck zeichnen -- das war dreimal gemeldet und sah aus wie
   ein weisser Kasten quer ueber der Karte. `:focus-visible` allein genuegt dafuer nicht;
   beim Klicken mit der Maus greift es nicht. */
.karte__feld:focus,
.karte__feld:focus-visible { outline: none; }

/* Die Ebene fuer spaeter eingetragene Orte. Sie liegt bereits hier, damit die Orte
   nicht ins Bild gebrannt werden muessen (REQ-KARTE-008). */
.karte__orte { position: absolute; inset: 0; pointer-events: none; }

/* --- Ortshierarchie: Baum, Weg und Unterorte (Schlossreiter) ---

   Die Einrueckung traegt die Bedeutung, nicht die Farbe: Wer Farben schlecht
   unterscheidet, liest die Tiefe trotzdem. Die Linie links ist eine Lesehilfe und keine
   Aussage. */
.ort-baum { display: grid; gap: .15rem; }

.ort-baum__ast { display: grid; gap: .15rem; }

.ort-baum__kinder {
    display: grid;
    gap: .15rem;
    margin-left: .85rem;
    padding-left: .7rem;
    border-left: 1px solid var(--sh-border-soft);
}

.ort-baum__ort {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    width: 100%;
    padding: .3rem .5rem;
    border: 0;
    border-radius: var(--sh-radius);
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.ort-baum__ort:hover { background: var(--sh-bg-2); }
.ort-baum__ort:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.ort-baum__name { font-weight: 600; }

/* --- Der Weg von der Wurzel bis hierher --- */
.ort-weg {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .3rem;
    font-size: .8rem;
}

.ort-weg__teil {
    border: 0;
    background: none;
    padding: 0;
    color: var(--sh-text-dim);
    font: inherit;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: .15em;
}

.ort-weg__teil:hover { color: var(--sh-accent); }
.ort-weg__teil:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 1px; }

/* Der Ort, auf dem man steht, ist kein Verweis — ein Verweis auf sich selbst waere ein
   Knopf, der nichts tut. */
.ort-weg__hier { color: var(--sh-text); font-weight: 600; }
.ort-weg__pfeil { color: var(--sh-text-faint); }

/* --- Die unmittelbaren Unterorte im Ortsdetail --- */
.ort-unterorte {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(13rem, 100%), 1fr));
    gap: .4rem;
}

.ort-unterort {
    display: grid;
    gap: .1rem;
    padding: .5rem .6rem;
    border: 1px solid var(--sh-border-soft);
    border-radius: var(--sh-radius);
    background: var(--sh-bg-2);
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.ort-unterort:hover { border-color: var(--sh-accent-line); }
.ort-unterort:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: -2px; }
.ort-unterort__name { font-weight: 600; }

/* --- Strassen, Bruecken und andere Wege (REQ-KARTE-021 bis REQ-KARTE-028) ---

   Die Wegearten werden ueber die Strichform unterschieden, nicht allein ueber die Farbe:
   Eine Karte, die ihre Bedeutung nur an Farbtoenen traegt, ist fuer Farbfehlsichtige
   unlesbar, und auf einem gemalten Untergrund mit rotem Blutmond gehen ohnehin
   Farbunterschiede unter. Strasse durchgezogen, Pfad fein gestrichelt, Bruecke kurz und
   kraeftig, Faehre und Seeweg gepunktet, Tunnel lang gestrichelt, Grenze Strich-Punkt.

   Alle Farben kommen aus den Tokens des Entwurfssystems — es steht kein Farbwert im
   Markup, wo ihn niemand wiederfindet. */
.karte__wegebene { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.karte__wegebene.is-zeichnend { pointer-events: auto; cursor: crosshair; }

.karte__weg {
  fill: none;
  stroke: var(--sh-text-dim);
  stroke-width: .45;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: stroke;
  cursor: pointer;
  transition: stroke-width var(--sh-fast, .12s) linear;
}

.karte__weg:hover,
.karte__weg:focus-visible { stroke-width: .8; stroke: var(--sh-accent); }

.karte__weg--strasse { stroke: var(--sh-gold-dim); stroke-width: .55; }
.karte__weg--pfad    { stroke: var(--sh-text-faint); stroke-width: .3; stroke-dasharray: .8 .8; }
.karte__weg--bruecke { stroke: var(--sh-gold); stroke-width: .75; stroke-dasharray: .5 .35; }
.karte__weg--faehre  { stroke: var(--sh-blue); stroke-width: .4; stroke-dasharray: .15 .9; }
.karte__weg--seeweg  { stroke: var(--sh-blue-soft); stroke-width: .35; stroke-dasharray: .2 1.2; }
.karte__weg--tunnel  { stroke: var(--sh-text-faint); stroke-width: .45; stroke-dasharray: 1.6 .8; }
.karte__weg--grenze  { stroke: var(--sh-danger-dim); stroke-width: .35; stroke-dasharray: 1.4 .5 .2 .5; }

/* Der Weg, der gerade entsteht. Er hebt sich ab, weil er noch keiner ist. */
.karte__weg--entwurf {
  stroke: var(--sh-accent);
  stroke-width: .6;
  stroke-dasharray: .6 .4;
  pointer-events: none;
}

.karte__wegpunkt {
  fill: var(--sh-accent);
  stroke: var(--sh-bg);
  stroke-width: .15;
  pointer-events: none;
}

/* --- Detailansicht mit Zoom und Verschieben --- */
.karte__bild--detail { cursor: grab; touch-action: none; }
.karte__bild--detail:active { cursor: grabbing; }

/* `transform-origin: 0 0` seit dem 27.08.2026 -- vorher `center center`.
   Uebersicht und Detailansicht rechnen seither MIT DERSELBEN Formel: Aus dem Ursprung
   oben links wird die Umrechnung Bildschirm<->Karte eine schlichte Verschiebung mit
   Faktor, und das Zoomen auf den Mauszeiger ist eine Zeile statt einer
   Fallunterscheidung. Nebenwirkung, ausdruecklich erwuenscht: Die Detailansicht bekommt
   damit die Begrenzung, die ihr fehlte -- man konnte das Bild bisher vollstaendig aus
   dem Rahmen schieben. */
/* `will-change` hier aus demselben Grund entfallen wie an der Buehne: Es liesse den
   Browser das Bild einmal bei Massstab 1 rastern und danach die Bitmap aufblasen -- also
   ausgerechnet in der Ansicht unscharf, die es scharf zeigen soll. */
.karte__detailbild {
  width: 100%; height: auto; display: block;
  transform-origin: 0 0;
  transition: transform .08s linear;
}

/* --- Die zoombare Weltkarte (REQ-KARTE-029 bis 037) --- */

.karte__bild--zoombar { cursor: grab; touch-action: none; overscroll-behavior: contain; }
.karte__bild--zoombar.is-gezoomt:active { cursor: grabbing; }

/* Die Buehne traegt ALLES, was zur Karte gehoert, und wird als Ganzes transformiert.
   Laege die Ortsebene daneben statt darin, wanderten die Marken beim Zoomen weg. */
/* KEIN `will-change: transform` -- und das ist der ganze Punkt.

   Es befoerdert die Buehne zu einer eigenen Verbundebene, und die rastert der Browser
   EINMAL bei Massstab 1 und skaliert danach nur noch die Bitmap. Der Gegenzoom rechnet
   die Ortsbeschriftung vorher auf 11,8 px / Zoom herunter -- bei vierfacher Vergroesserung
   also auf rund 3 px. Genau diese 3 px landen in der Bitmap und werden dann vierfach
   aufgeblasen: winzig UND unscharf zugleich, samt der ganzen Karte darunter.

   Ohne `will-change` rechnet der Browser den angesammelten Massstab in die Rasterung ein.
   Die Beschriftung entsteht dann bei ihren echten 11,8 px, und das Grundbild wird so
   scharf gezeichnet, wie seine 1448 Bildpunkte es hergeben.

   Gemeldet am 27.08.2026: "wenn man ranzoomt werden die beschriftungen unleserlich". */
.karte__buehne {
  position: relative;
  transform-origin: 0 0;
}

/* Die Ebene der hochaufgeloesten Ausschnitte ist am 27.08.2026 zurueckgenommen worden.
   Die Begruendung steht in WorldMapView.razor an der Stelle, an der sie lag. Ihre
   Vermessung (MapPackage.AusschnittProzent) und deren acht Pruefungen bleiben stehen --
   das Kartenpaket ist richtig vermessen, nur die Darstellung trug nicht. */

/* Marken skalieren GEGEN den Zoom und behalten ihre Bildschirmgroesse (REQ-KARTE-034).
   Der Ursprung sitzt auf der Spitze unten mittig -- dem Punkt, der die Lage traegt;
   sonst wanderte die Marke beim Zoomen von ihrem Ort weg. */
.karte__buehne .karte__pin {
  transform-origin: 50% 100%;
  transform: translate(-50%, -100%) scale(var(--karte-gegenzoom, 1));
}

/* --- Legende --- */
.karte__legende { list-style: none; margin: 0; padding: 0; display: grid; gap: .35rem; }
.karte__legendenknopf {
  display: flex; align-items: center; gap: .6rem; width: 100%;
  padding: .5rem .6rem; border-radius: var(--sh-radius-s, 7px);
  background: transparent; border: 1px solid transparent;
  color: inherit; cursor: pointer; text-align: left;
}
.karte__legendenknopf:hover { background: var(--sh-surface-3, #22242c); }
.karte__legendenknopf:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 1px; }
.karte__legendenknopf.is-active {
  border-color: var(--sh-accent, #4bb3a4); background: var(--sh-surface-3, #22242c);
}
.karte__legendenname { flex: 1 1 auto; font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .karte__feld, .karte__detailbild { transition: none; }
}

/* --- Ortsebene auf der Karte (REQ-KARTE-008, REQ-KARTE-014) ---
   Die Marker liegen ueber dem Bild und werden nicht hineingebrannt. Form und
   Beschriftung tragen die Aussage; die Farbe ist Zugabe. */
.karte__orte.is-setzend { pointer-events: auto; cursor: crosshair; }

/* Im Setzmodus reicht die Marke den Klick an die Ortsebene darunter durch. Ohne das
   nimmt sie ihn selbst entgegen und oeffnet den Ort — die Flaeche unter einer bereits
   gesetzten Marke waere dann nicht mehr zu treffen, und dort liegen die Nachbarorte. */
.karte__orte.is-setzend .karte__pin { pointer-events: none; }

.karte__pin {
  position: absolute;
  transform: translate(-50%, -100%);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: none; border: none; padding: 0; cursor: pointer;
  pointer-events: auto;
  line-height: 1.1;
}

.karte__pin-punkt {
  width: 13px; height: 13px;
  background: #e8cf95;
  border: 2px solid #1a1410;
  box-shadow: 0 1px 4px rgba(0,0,0,.75);
}

/* Die Form unterscheidet die Art, nicht nur die Farbe. */
.karte__pin--city    .karte__pin-punkt { border-radius: 2px; width: 15px; height: 15px; }
.karte__pin--village .karte__pin-punkt { border-radius: 50%; width: 11px; height: 11px; }
.karte__pin--castle  .karte__pin-punkt { border-radius: 2px; transform: rotate(45deg); }
.karte__pin--fortress .karte__pin-punkt { border-radius: 0; width: 15px; height: 15px;
  clip-path: polygon(0 100%, 0 30%, 25% 30%, 25% 10%, 50% 30%, 75% 10%, 75% 30%, 100% 30%, 100% 100%); }
.karte__pin--specialplace .karte__pin-punkt { border-radius: 50%; background: #b47ad0; }
.karte__pin--realm   .karte__pin-punkt { border-radius: 0; background: #9fb37a; }

.karte__pin-name {
  font-family: Georgia, "Times New Roman", serif;
  font-size: .74rem; color: #f0e2c0;
  paint-order: stroke fill;
  text-shadow: 0 0 4px #000, 0 1px 2px #000;
  white-space: nowrap;
}

.karte__pin:hover .karte__pin-punkt { background: #fff3d4; transform: scale(1.2); }
.karte__pin--castle:hover .karte__pin-punkt { transform: rotate(45deg) scale(1.2); }
.karte__pin:focus-visible { outline: 2px solid var(--sh-accent, #4bb3a4); outline-offset: 3px; }

.karte__ortzeile { display: flex; align-items: center; gap: .35rem; }
.karte__ortzeile .karte__legendenknopf { flex: 1 1 auto; }

/* --- Zusatzebene „Wer ist gerade wo" (REQ-KARTE-020) ---
   Die Zahl haengt an der Marke, statt sie zu ersetzen: Ohne die Ebene sieht die Karte
   aus wie zuvor. Getragen wird die Aussage von der Ziffer und nicht von der Farbe
   (REQ-UX-015) — wer die Ebene abschaltet, verliert keine Information, die nur hier
   stuende. */
.karte__pin-zahl {
  position: absolute;
  top: -7px; left: 50%;
  transform: translateX(2px);
  min-width: 16px; height: 16px;
  padding: 0 3px;
  border-radius: 8px;
  border: 1px solid #1a1410;
  background: #f0e2c0;
  color: #1a1410;
  font-size: .66rem; font-weight: 700; line-height: 14px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 1px 3px rgba(0,0,0,.7);
  pointer-events: none;
}

/* --- Fraktionsansicht: das Wappen (REQ-WORLD-005) --- */
/* Ein Wappen ist kein Landschaftsbild: Es wird nicht auf die Kartenbreite gezogen,
   sondern gedeckelt und mittig gestellt. Auf die Breite gezogen sähe eine kleine
   Zeichnung ausgefranst aus. */
.fraktion-wappen { display: flex; justify-content: center; padding: .8rem; }
.fraktion-wappen img {
  display: block; max-width: min(100%, 320px); height: auto;
  border-radius: var(--sh-radius);
}

/* --- Ortsansicht (REQ-KARTE-015, REQ-KARTE-018) --- */
/* Das Ortsbild schneidet heute gar nicht: width 100 %, height auto zeigt das ganze
   Bild. object-position bleibt hier deshalb wirkungslos, solange das so ist — die
   Zeile steht trotzdem da, damit die Flaeche dem Schwerpunkt folgt, sobald sie einmal
   auf ein festes Seitenverhaeltnis geht. Ein Seitenverhaeltnis erfindet MEDIA-012
   ausdruecklich nicht. */
.ort-bild img {
    display: block; width: 100%; height: auto; border-radius: var(--sh-radius);
    object-position: var(--sh-focus, center);
}

.ort-karte {
  display: grid; gap: .4rem; text-align: left;
  padding: .8rem .9rem;
  background: var(--sh-surface-2); color: inherit;
  border: 1px solid var(--sh-border); border-radius: var(--sh-radius);
  cursor: pointer;
}
.ort-karte:hover { border-color: var(--sh-accent, #4bb3a4); background: var(--sh-surface-3, #22242c); }
.ort-karte:focus-visible { outline: 2px solid var(--sh-accent, #4bb3a4); outline-offset: 2px; }

.ort-karte__kopf { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.ort-karte__name { flex: 1 1 auto; font-weight: 650; }

/* Zwei Zahlen mit ausgeschriebener Bedeutung. Ein Zahlenpaar allein liesse offen,
   welche Zahl die Herkunft und welche den Aufenthalt meint — und genau diese beiden
   werden nie vermengt (REQ-KARTE-016). */
.ort-karte__zahlen { display: grid; gap: .15rem; }
.ort-zahl { font-size: .76rem; color: var(--sh-text-dim); }
.ort-zahl strong { color: var(--sh-text); font-variant-numeric: tabular-nums; }

.ort-personen { display: flex; flex-wrap: wrap; gap: .35rem; }

.ort-person {
  display: inline-flex; align-items: baseline; gap: .4rem;
  padding: .28rem .55rem;
  background: var(--sh-surface-3, #22242c); color: inherit;
  border: 1px solid var(--sh-border); border-radius: 999px;
  font-size: .8rem; cursor: pointer;
}
.ort-person:hover { border-color: var(--sh-accent, #4bb3a4); }
.ort-person:focus-visible { outline: 2px solid var(--sh-accent, #4bb3a4); outline-offset: 2px; }
.ort-person__name { font-weight: 600; }
.ort-person__zusatz { font-size: .7rem; color: var(--sh-text-faint); }

/* Die Zeile um eine Marke: Marke plus Loeseknopf. Ein eigener Umschlag und NICHT
   .ort-person -- das ist die Marke selbst und braeuchte sonst zwei Rahmen. */
.ort-personzeile { display: inline-flex; align-items: center; gap: .25rem; }

/* ======================================================= Zauber: Schwereleiter
   Die Schwere ist keine freie Zahl, sondern eine Sprosse der Leiter
   5 · 7 · 9 · 11 · 13 · 15 · 17 · 19. Deshalb steht sie als Reihe von Stufen und
   nicht als Zahlenfeld: Ein Eingabefeld lädt dazu ein, eine 12 einzutippen, und eine
   12 ist keine feinere Einstellung, sondern eine Sprosse ohne Gegenstück auf der
   Beherrschungsachse. Was gar nicht erst eingetippt werden kann, muss auch nicht
   abgewiesen werden — abgewiesen wird es serverseitig trotzdem. */

.sh-leiter { display: flex; flex-wrap: wrap; gap: .25rem; }

.sh-leiter__stufe {
    min-width: 2.4rem;
    padding: .28rem .45rem;
    border: 1px solid var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-surface-2);
    color: var(--sh-text-dim);
    font: inherit;
    font-family: var(--sh-font-mono);
    font-variant-numeric: tabular-nums;
    font-size: .82rem;
    line-height: 1.2;
    text-align: center;
    cursor: pointer;
}

.sh-leiter__stufe:hover { border-color: var(--sh-accent-line); color: var(--sh-text); }
.sh-leiter__stufe:focus-visible { outline: 2px solid var(--sh-accent); outline-offset: 1px; }

/* Die neutrale Sprosse — dort ist der Zauber genau so schwer wie ein Schwerthieb.
   Sie ist der Grund, aus dem es diese Leiter überhaupt gibt, und deshalb markiert. */
.sh-leiter__stufe.is-neutral { border-color: var(--sh-gold-dim); color: var(--sh-gold); }

.sh-leiter__stufe.is-aktiv {
    border-color: var(--sh-accent);
    background: var(--sh-accent);
    color: var(--sh-text-invert);
    font-weight: 700;
}

/* Die feste Angabe im Formular (die Magierichtung): sieht aus wie ein Feld, ist aber
   keines. Ein gesperrtes Eingabefeld wäre die schlechtere Auskunft — es sagt „hier
   könnte etwas stehen“, obwohl hier nie etwas anderes stehen wird. */
.sh-zauber-fest {
    padding: .3rem .45rem;
    border: 1px dashed var(--sh-border);
    border-radius: var(--sh-radius);
    background: var(--sh-bg-2);
    color: var(--sh-text-dim);
    font-size: .84rem;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* ====================================================== Zauber: Vorschauzeile
   Am Zauber steht keine feste Prozentzahl. Hier steht die Erfolgsaussicht für EINEN
   eingestellten Wirkenden gegen EIN eingestelltes Ziel — dieselbe Schattenlanze
   trifft je nach Wirkendem zwischen 45 % und 85 %.

   Jede Fläche setzt grid-column UND grid-row ausdrücklich. Das ist keine
   Vorsichtsmaßnahme, sondern die Lehre aus .sh-imagelist__actions weiter oben in
   dieser Datei: Sobald ein weiteres Kind in die Zeile kam, verschob die automatische
   Platzierung alles Folgende. Bei einer Vorschauzeile, die je nach Lage einen
   Kappungs- ODER einen Sperrgrund trägt, kommt genau so ein Kind hinzu. Textspalten
   bekommen zusätzlich min-width: 0, damit ein langer Grund die Spalte aufdehnt statt
   die Karte. */

.sh-zauber-vorschau {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    gap: .15rem .9rem;
    align-items: baseline;
    padding: .7rem .85rem;
    border: 1px solid var(--sh-accent-line);
    border-radius: var(--sh-radius);
    background: var(--sh-accent-soft);
}

.sh-zauber-vorschau__wert {
    grid-column: 1;
    grid-row: 1 / span 2;
    align-self: center;
    color: var(--sh-accent);
    font-family: var(--sh-font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.1;
    white-space: nowrap;
}

.sh-zauber-vorschau__wert span {
    margin-left: .12rem;
    color: var(--sh-text-dim);
    font-size: .85rem;
    font-weight: 400;
}

.sh-zauber-vorschau__zeile {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    color: var(--sh-text);
    font-size: .86rem;
    overflow-wrap: anywhere;
}

.sh-zauber-vorschau__grund {
    grid-column: 2;
    grid-row: 2;
    min-width: 0;
    color: var(--sh-text-dim);
    font-size: .76rem;
    line-height: 1.5;
}

.sh-zauber-vorschau__werte {
    grid-column: 1 / -1;
    grid-row: 3;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .3rem;
    margin-top: .45rem;
}

/* Die Kappung wird gezeigt und nicht weggerechnet: Wer die Schwere von 7 auf 5 dreht
   und nichts geschehen sieht, hält das sonst für einen Fehler der Anwendung. */
.sh-zauber-vorschau.is-gekappt {
    border-color: rgba(224, 162, 60, .45);
    background: var(--sh-warn-soft);
}

.sh-zauber-vorschau.is-gekappt .sh-zauber-vorschau__wert { color: var(--sh-warn); }

.sh-zauber-vorschau.is-gesperrt {
    border-color: rgba(224, 85, 97, .45);
    background: var(--sh-danger-soft);
}

.sh-zauber-vorschau.is-gesperrt .sh-zauber-vorschau__wert { color: var(--sh-danger); }

/* Schmal wird aus zwei Spalten eine — auch hier jede Zeile ausdrücklich, damit die
   Reihenfolge Prozentzahl, Zeile, Grund, Zwischenwerte erhalten bleibt. */
@media (max-width: 640px) {
    .sh-zauber-vorschau { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto auto auto; }
    .sh-zauber-vorschau__wert { grid-column: 1; grid-row: 1; }
    .sh-zauber-vorschau__zeile { grid-column: 1; grid-row: 2; }
    .sh-zauber-vorschau__grund { grid-column: 1; grid-row: 3; }
    .sh-zauber-vorschau__werte { grid-column: 1; grid-row: 4; }
}

/* --------------------------------------------------- Rangliste (REQ-CHAR-108) */
/* Eine breite Tabelle scrollt in ihrem eigenen Kasten und nicht mit der ganzen
   Seite: Waagerecht scrollende Seiten verlieren die Navigation aus dem Blick. */
.sh-table-scroll { overflow-x: auto; }

/* Ein Knopf, der wie ein Verweis aussieht. In dieser Anwendung fuehrt jeder Sprung
   ueber @onclick und die Adresszeile der Huelle, nicht ueber <a href>. */
.sh-linkbtn {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--sh-accent, #7ad1c0); text-align: left;
}
.sh-linkbtn:hover { text-decoration: underline; }

.sh-page-head__lead { margin: .25rem 0 0; color: var(--sh-muted, #9aa4b2); }

/* Ein Text, der seine Zeilenumbrueche behaelt — fuer Belegzitate aus dem
   Verlauf, die ohne sie zu einer Wand zusammenlaufen. */
.sh-pre-wrap { white-space: pre-wrap; }

/* ---------------------------------------------------------- Rechte-Pruefer (REQ-AUTH-074) */

.sh-rechtepruefer-ergebnis {
    padding: .7rem .85rem;
    border: 1px solid var(--sh-border);
    border-left-width: 3px;
    border-radius: var(--sh-radius);
    background: var(--sh-surface);
}
.sh-rechtepruefer-ergebnis--ja { border-left-color: var(--sh-success); }
.sh-rechtepruefer-ergebnis--nein { border-left-color: var(--sh-danger); }
.sh-rechtepruefer-kette { margin: .4rem 0 0 1.1rem; padding: 0; }
.sh-rechtepruefer-kette li { margin: .1rem 0; }
