/* ============================================================================
   RAUMIMPERIUM — Stylesheet

   Anspruch: Das Spiel soll auf jedem Schirm gebaut aussehen statt nach nacktem
   HTML — und dabei ohne Abstriche bedienbar bleiben. Es gilt dieselbe Regel wie
   überall im Projekt: Farbe ist IMMER nur Zugabe, nie das einzige Signal
   (WCAG 1.4.1), und jeder Farbwert ist gegen seinen Hintergrund gerechnet —
   `php scratchpad/kontrast.php` prüft alle 45 Paarungen in beiden Modi (90 Prüfungen) und
   bricht ab, wenn eine unter die Schwelle fällt.

   Hell/Dunkel (lichtempfindliche Augen): ALLE Farben leben in :root-Variablen.
   Ohne Cookie folgt die Seite der Systemeinstellung (prefers-color-scheme); der
   Umschalter unter /einstellungen setzt data-theme am <html> (Cookie,
   Core\Darstellung) und übersteuert sie.

   Die Systemeinstellung bleibt bewusst maßgeblich, auch wenn Weltraum nach
   „immer dunkel“ klingt: Wer hell eingestellt hat, hat dafür meistens einen
   Grund. Beide Paletten tragen dieselbe Anmutung — die dunkle als Nachtseite,
   die helle als Tagseite.

   ACHTUNG beim Ändern: Die dunklen Werte stehen ZWEIMAL (Media-Query +
   Attribut), reines CSS kann den Block nicht teilen. Sie MÜSSEN identisch
   bleiben; `php scratchpad/kontrast.php` prüft auch das und nennt jede
   Abweichung beim Namen.
   ============================================================================ */

:root {
    color-scheme: light;
    --text: #111a2e;
    --text-gedimmt: #46536d;       /* Nebentexte: Fußzeile, Meta, Begründungen */
    --text-abgeschaltet: #535f78;  /* inaktive/nicht baubare Zeilen — 5,2:1 auf --bg */
    /* Weltraum-Tag: kühles Blaugrau statt neutralem Weiß. Derselbe Blaustich wie
       im Dunkelmodus, nur von der hellen Seite. */
    --bg: #e4ebf6;
    --bg-karte: #ffffff;              /* Karten/Einschübe: details, Vorschau, Eingaben */
    --bg-einschub: #eff4fb;        /* vorformatierte Berichte */
    --bg-kopf: #f7faff;            /* Kopf/Fuss: abgesetzt vom Seitengrund */
    --bg-tabellenkopf: #d9e3f2;
    --zebra: #f1f5fc;              /* jede zweite Tabellenzeile */
    --rand: #c1cde2;
    --rand-stark: #5d6d8e;         /* Tabellenkopf — 4,3:1 auf --bg */
    --rand-eingabe: #66738f;
    --akzent: #1d4ed8;             /* Aktions-Hintergrund (weiße Schrift) – beide Modi */
    --akzent-text: #fff;
    --aktion-zweit: #3f4a60;       /* Zweit-Knopf-Hintergrund (weiße Schrift) */
    --fokus: #1d4ed8;              /* Tastatur-Fokusring */
    --link: #1747c4;
    --link-besucht: #6d28d9;
    --gefahr: #b00020;             /* Fehler-Text/-Rand */
    --gefahr-aktion: #b00020;      /* Gefahr-Knopf (weiße Schrift) – beide Modi */
    --gefahr-bg: #fde7ea;
    --erfolg-rand: #17733a;
    --erfolg-bg: #e3f4e9;
    --hinweis-bg: #fff6dc;
    --hinweis-rand: #8a6d12;       /* 4,6:1 auf --hinweis-bg */
    --eigen-bg: #d6e6ff;           /* eigene Zeile in der Galaxiekarte */
    --leuchten: rgba(40, 80, 170, .05);     /* Lichtschleier, s. body */
    --schatten: rgba(20, 30, 60, .10);
    /* Optik-Runde „Kommandobrücke“ (2026-10): zweiter Knopf-Ton (Verlauf),
       Leuchtkanten (Zier, nie Textträger) und der Quest-Kasten der Ersten Schritte. */
    --akzent-2: #0e7490;
    --leucht: #0e7490;
    --leucht-2: #b45309;
    --quest-bg: #fff4e0;
    --quest-rand: #b45309;
}

/* Dunkle Werte, Fall 1: Systemeinstellung dunkel + keine (oder dunkle) Wahl. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="hell"]) {
        color-scheme: dark;
        --text: #e8eefb;
        --text-gedimmt: #a7b4cc;
        --text-abgeschaltet: #8e9ab1;  /* 7,0:1 auf --bg */
        /* Weltraum-Nacht: tiefes Blauschwarz statt neutralem Grau. Der Blaustich ist
           der eigentliche Traeger der Anmutung — die Helligkeiten selbst bleiben,
           wo sie waren, damit kein Kontrast kippt. */
        --bg: #050914;
        --bg-karte: #0d1527;
        --bg-einschub: #0a1122;
        --bg-kopf: #040812;            /* Kopf/Fuss: eine Spur tiefer als die Seite */
        --bg-tabellenkopf: #16223b;
        --zebra: #0b1323;              /* jede zweite Tabellenzeile */
        --rand: #22324f;
        --rand-stark: #55709c;
        --rand-eingabe: #7489b0;
        --akzent: #2563eb;
        --akzent-text: #fff;
        --aktion-zweit: #33405c;
        --fokus: #67e8f9;
        --link: #7cc4ff;
        --link-besucht: #c9a7ff;
        --gefahr: #ff8fa3;
        --gefahr-aktion: #b00020;
        --gefahr-bg: #2d0f19;
        --erfolg-rand: #4fc88a;
        --erfolg-bg: #0c271b;
        --hinweis-bg: #2a2210;
        --hinweis-rand: #b8963a;
        --eigen-bg: #173058;
        --leuchten: rgba(120, 165, 255, .07);   /* Sternenschleier, s. body */
        --schatten: rgba(0, 0, 0, .45);
        /* Optik-Runde „Kommandobrücke“ (2026-10): zweiter Knopf-Ton (Verlauf),
           Leuchtkanten (Zier, nie Textträger) und der Quest-Kasten der Ersten Schritte. */
        --akzent-2: #0e7490;
        --leucht: #22d3ee;
        --leucht-2: #f59e0b;
        --quest-bg: #1c1508;
        --quest-rand: #f59e0b;
    }
}

/* Dunkle Werte, Fall 2: explizit gewählt (Cookie) – identisch zu Fall 1. */
:root[data-theme="dunkel"] {
    color-scheme: dark;
    --text: #e8eefb;
    --text-gedimmt: #a7b4cc;
    --text-abgeschaltet: #8e9ab1;  /* 7,0:1 auf --bg */
    /* Weltraum-Nacht: tiefes Blauschwarz statt neutralem Grau. Der Blaustich ist
       der eigentliche Traeger der Anmutung — die Helligkeiten selbst bleiben,
       wo sie waren, damit kein Kontrast kippt. */
    --bg: #050914;
    --bg-karte: #0d1527;
    --bg-einschub: #0a1122;
    --bg-kopf: #040812;            /* Kopf/Fuss: eine Spur tiefer als die Seite */
    --bg-tabellenkopf: #16223b;
    --zebra: #0b1323;              /* jede zweite Tabellenzeile */
    --rand: #22324f;
    --rand-stark: #55709c;
    --rand-eingabe: #7489b0;
    --akzent: #2563eb;
    --akzent-text: #fff;
    --aktion-zweit: #33405c;
    --fokus: #67e8f9;
    --link: #7cc4ff;
    --link-besucht: #c9a7ff;
    --gefahr: #ff8fa3;
    --gefahr-aktion: #b00020;
    --gefahr-bg: #2d0f19;
    --erfolg-rand: #4fc88a;
    --erfolg-bg: #0c271b;
    --hinweis-bg: #2a2210;
    --hinweis-rand: #b8963a;
    --eigen-bg: #173058;
    --leuchten: rgba(120, 165, 255, .07);   /* Sternenschleier, s. body */
    --schatten: rgba(0, 0, 0, .45);
    /* Optik-Runde „Kommandobrücke“ (2026-10): zweiter Knopf-Ton (Verlauf),
       Leuchtkanten (Zier, nie Textträger) und der Quest-Kasten der Ersten Schritte. */
    --akzent-2: #0e7490;
    --leucht: #22d3ee;
    --leucht-2: #f59e0b;
    --quest-bg: #1c1508;
    --quest-rand: #f59e0b;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: system-ui, "Segoe UI", Arial, sans-serif;
    line-height: 1.6;
    color: var(--text);
    background: var(--bg);
    /* Weltraum-Anmutung: zwei sehr weiche Lichtschleier oben links und
       rechts, damit der Grund nicht als tote Flaeche dasteht. Bewusst als
       CSS-Verlauf und nicht als Bild — kein zusaetzlicher Ladevorgang, keine
       Datei im Deploy, und die Farbe folgt automatisch dem gewaehlten Modus.

       Die Deckkraft (--leuchten) liegt bei 5-7 %: Ueber dem Schleier steht nie
       Text direkt auf dem Grund, sondern immer auf einer Karte — und selbst wo
       er es taete, veraendert der Schleier den gemessenen Kontrast erst in der
       dritten Nachkommastelle.

       `fixed`: Der Schleier bleibt beim Scrollen stehen, statt mit der Seite
       nach oben zu wandern. Auf 6 Bildschirmen Hoehe waere er sonst nur ganz
       oben zu sehen. */
    background-image:
        radial-gradient(1200px 700px at 12% -8%, var(--leuchten), transparent 65%),
        radial-gradient(1000px 600px at 92% 4%, var(--leuchten), transparent 60%);
    background-attachment: fixed;
    background-repeat: no-repeat;
}

/* Wer Bewegung/Effekte abbestellt hat, bekommt den flachen Grund. Der Schleier
   bewegt sich zwar nicht, ist aber reine Zier — und `prefers-reduced-*` ist der
   Ort, an dem Nutzer genau das abbestellen. */
@media (prefers-reduced-transparency: reduce) {
    body { background-image: none; }
}

a { color: var(--link); }
a:visited { color: var(--link-besucht); }

/* SPALTENBREITE — auf grossen Bildschirmen soll das Menue so weit auseinander
   gezogen werden, wie es geht.

   Ein festes 70ch fuer alle drei Regionen sind gemessen 604 px Aussenbreite —
   auf einem 2560px-Monitor knapp 24 % der Fensterbreite, der Rest bliebe leer,
   und die 14 Menuepunkte braechen auf JEDER Fensterbreite in drei Zeilen um.
   Nicht die Schrift ist dann zu klein (nirgends steht eine px-Groesse), sondern
   die Spalte zu schmal.

   Drei Stufen ueber data-breite am <html> (Cookie, Core\Darstellung), Standard
   „breit“. Bei „breit“ und „voll“ folgt der Inhalt der FENSTERBREITE statt
   einem festen ch-Wert — ein 90-cm-Schirm (3440 px) wird damit wirklich
   ausgenutzt. Ein fester Wert waere dort wieder eine Spalte in der Mitte
   gewesen: mit 110ch blieben auf 3440 px 72 % der Flaeche leer, und 25 von 27
   Tabellen mussten trotzdem seitwaerts scrollen.

   Warum das gefahrlos ist: Tabellen nehmen sich nur, was sie BRAUCHEN
   (`width: max-content` bzw. `min-width: 100%`), werden also nicht kuenstlich
   auseinandergezogen. Und der 75ch-Deckel fuer Fliesstext weiter unten bleibt in
   allen Stufen — WCAG 2.1 SC 1.4.8 nennt fuer Textbloecke hoechstens 80 Zeichen
   je Zeile, daran aendert ein breiter Monitor nichts. Breiter werden also nur
   die Tabellen, und nur so weit sie es brauchen. */
:root {
    /* Deckel fuer Kopf, Inhalt und Raster. 200rem = 3200 px: das deckt einen
       90-cm-Schirm (3440 px) praktisch voll ab und bremst erst darueber hinaus.
       Gemessen an echten Seiten: die breiteste Tabelle des Spiels ist die
       Imperiums-Matrix mit einer Spalte je Objekt (bei 4 Welten 1366 px, sie
       waechst mit der Weltenzahl weiter). Alles darunter passt lange vorher. */
    --seitenbreite: 200rem;
    /* Kopf und Fuss duerfen nie SCHMALER sein als der Inhalt. */
    --kopfbreite: var(--seitenbreite);
}
:root[data-breite="schmal"] {
    /* Eine einzige Lesespalte. Der Kopf bleibt etwas breiter,
       sonst braucht das Menue wieder drei Zeilen. */
    --seitenbreite: 70ch;
    --kopfbreite: 100ch;
}
:root[data-breite="voll"] { --seitenbreite: 100%; --kopfbreite: 100%; }

main {
    max-width: var(--seitenbreite);
    margin-inline: auto;
    padding: 1rem 1.25rem;
}

/* SEITENTYP-DECKEL. Drei Aufgaben, drei Breiten: Mit einer einzigen Breite fuer
   alles waere das Login-Formular auf einem 3440er-Schirm 3160 px breit fuer ein
   356-px-Eingabefeld.

   `min(...)` statt eines festen Werts: Die Breiten-Einstellung des Spielers
   (--seitenbreite, /einstellungen) bleibt massgeblich, sobald sie KLEINER ist
   als der Deckel. Der Typ macht eine Seite also nie breiter, nur schmaler.

   Kopf und Fuss bleiben absichtlich ueber die volle Fensterbreite: Sie sind
   Rahmen, keine Inhaltsspalte — eine mitschrumpfende Leiste ueber einem
   schmalen Formular saehe aus wie ein Fehler. */
:root[data-seitentyp="kompakt"] main { max-width: min(34rem, var(--seitenbreite)); }
:root[data-seitentyp="lesen"]   main { max-width: min(78rem, var(--seitenbreite)); }

/* Die kompakte Seite ist eine zentrierte KARTE: Bei so wenig Inhalt wirkt der
   Text sonst wie oben links angeheftet. Nur ab Tablet-Breite — auf dem Handy
   waere ein Rahmen um den ganzen Bildschirm nur Rand. */
@media (min-width: 45rem) {
    :root[data-seitentyp="kompakt"] main {
        margin-top: 2.5rem;
        padding: 1.75rem 2rem;
        background: var(--bg-karte);
        border: 1px solid var(--rand);
        border-radius: 10px;
        box-shadow: 0 2px 8px var(--schatten);
    }
}

/* Kopf und Fuss: FLAECHE ueber die ganze Fensterbreite, INHALT auf --kopfbreite
   zentriert.

   Das Element selbst darf NICHT auf --kopfbreite begrenzt werden, weil Kopf und
   Fuss eine eigene Hintergrundfarbe tragen: auf einem Ultrawide schwebte dann
   ein abgesetzter Kasten in der Mitte statt einer durchgehenden Leiste. Die
   Zentrierung uebernimmt hier der Innenabstand — so
   braucht es kein zusaetzliches Huellelement im HTML, und die Landmark-Struktur
   (genau ein header/main/footer) bleibt unangetastet.

   `max()`: Solange das Fenster schmaler ist als --kopfbreite, ist die Rechnung
   negativ und es bleiben die normalen 1,25rem Rand. */
header, footer {
    padding-block: 1rem;
    padding-inline: max(1.25rem, calc((100% - var(--kopfbreite)) / 2));
}

/* Fliesstext behaelt seine Lesebreite, auch wenn die Spalte waechst. Tabellen-
   zellen ausdruecklich ausgenommen — dort ist der Deckel falsch. */
main p, main li, main dd { max-width: 75ch; }
td p, td li, td dd, th p { max-width: none; }

/* RANDSPALTEN — Bauschlange links aussen, Ressourcen-Tafel rechts, darunter
   der Aufgaben-Kasten wie ein Quest-Menue.

   Die DOM-Reihenfolge im Layout ist links → mitte → ereignisse → rechts. Die
   Bereiche werden hier ueber BENANNTE Rasterflaechen platziert: Jeder Kasten
   hat seinen Namen, und welche Spalten es gibt, entscheidet allein, welche
   Kaesten auf der Seite stehen (:has). Fehlt ein Kasten, fehlt seine Spalte —
   und nichts rutscht in eine fremde Spalte, was mit nummerierten Spalten
   passieren konnte (ohne Bau-Kasten, aber mit Ereignissen wanderte der Inhalt
   in die rechte Randspalte).

   Tab- und Sehreihenfolge: Inhalt zuerst, Tafel danach — der Screenreader
   liest die Tafel erst nach dem Inhalt, sehend steht sie rechts daneben. Nur
   die Ereignisse werden nach vorn geholt (Spalte links unter dem Bau-Kasten);
   das ist EIN abgeschlossener Block am Rand, kein Bedienweg, und die
   Alternative — ihn im DOM vor den Inhalt zu ziehen — haette JAWS auf jeder
   Seite 541 px Meldungen VOR das Spiel gestellt.

   ZWEI STUFEN:
   - ab 64rem (1024 px): die RECHTE Spalte mit der Ressourcen-Tafel — so breit
     wie ihre Zahlen (fit-content), bis 80rem mit Name und Bestand (Deckel
     20rem), darueber mit der Rate je Stunde (Deckel 28rem). Bei ueblichen
     Bestaenden bleiben dem Inhalt auf einem 1024er-Tablet rund 700 px, auf dem
     1366er-Laptop rund 1000 px. Tabellen, die breiter sind, scrollen in ihrem
     Container, die Seite nie. Darunter (Handy, kleines Tablet) gibt es die
     Tafel nicht — dort steht die zugeklappte Leiste als Knopf ueber dem Inhalt.
   - ab 110rem (1760 px): zusaetzlich die LINKE Spalte (Bau-Kasten, Ereignisse)
     und der Aufgaben-Kasten unter der Tafel. Beide Randspalten zusammen kosten
     592 px plus Fugen; erst ab 1760 px bleiben dem Inhalt rund 1080 px.

   Die rechte Spalte laeuft beim Scrollen mit — sticky an der SPALTE, nicht am
   Kasten: Das Raster steht auf align-items:start, ein sticky Kasten in einer
   auf Inhaltshoehe geschrumpften Zelle haette keinen Weg zum Kleben. Bei
   Platznot (16 Rohstoffe plus Aufgaben-Kasten auf einem flachen Fenster)
   scrollt die Spalte in sich (max-height), jede Zeile bleibt erreichbar. */
:root[data-rand="an"] .huelle > .rand { display: none; }
:root[data-rand="an"] .rand-rechts > .rand-kasten { display: none; }

@media (min-width: 64rem) {
    :root[data-rand="an"] .huelle {
        display: grid;
        /* Mitte als 1fr: sie bekommt, was die Randspalten uebrig lassen. */
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas: "mitte" "ereignisse";
        max-width: var(--seitenbreite);
        margin-inline: auto;
        align-items: start;
        gap: 0 1.5rem;
    }
    /* Bis 80rem: Name und Bestand. Die Rate je Stunde kommt erst ab 80rem dazu
       — auf einem 1024er-Tablet waere die dritte Spalte nur Umbruch oder
       Querlauf im Kasten, auf dem 1366er-Laptop ist Platz.

       Die Spalte ist SO BREIT WIE IHR INHALT (fit-content), gedeckelt: Feste
       Breiten brachen an echten Spielstaenden — mit 31 Mrd Roheisen und 45 Mio
       je Stunde brauchte die Tabelle 332 px, die Spalte hatte 320, und die
       rechten Ziffern der Raten fehlten. Mit fit-content nimmt sich die Spalte,
       was die Zahlen brauchen (die Zellen brechen nicht um), und nur der
       Deckel begrenzt sie: 20rem im Zwei-Spalten-Modus, 28rem mit Rate. Darueber
       hinaus scrollt der Kasten in sich (overflow-x: auto unten), statt
       Ziffern abzuschneiden. Die Spalte selbst hat als Scroll-Container keine
       automatische Mindestbreite, fit-content wirkt also wirklich als
       min(Inhalt, Deckel). */
    :root[data-rand="an"] .huelle:has(> .rand-rechts) {
        grid-template-columns: minmax(0, 1fr) fit-content(20rem);
        grid-template-areas: "mitte rechts" "ereignisse rechts";
    }
    @media (min-width: 80rem) {
        :root[data-rand="an"] .huelle:has(> .rand-rechts) {
            grid-template-columns: minmax(0, 1fr) fit-content(28rem);
        }
    }
    @media (max-width: 79.99rem) {
        .ressourcen-tafel .rate,
        .ressourcen-tafel thead th:nth-child(3) { display: none; }
    }
    :root[data-rand="an"] .huelle > .mitte       { grid-area: mitte; min-width: 0; }
    :root[data-rand="an"] .huelle > .ereignisse  { grid-area: ereignisse; }
    :root[data-rand="an"] .huelle > .rand-links  { grid-area: links; }
    :root[data-rand="an"] .huelle > .rand-rechts { grid-area: rechts; display: block; }

    /* Im Raster begrenzt das Raster die Breite, nicht mehr main selbst — AUSSER
       bei den schmalen Seitentypen: Deren Deckel muss auch hier gelten, sonst
       waere ein Login-Formular auf einem Ultrawide wieder 3200 px breit. Die
       zwei Regeln stehen bewusst NACH der ersten, weil sie dieselbe
       Spezifitaet haben und sonst ueberschrieben wuerden. */
    :root[data-rand="an"] .huelle > .mitte > main { max-width: 100%; }
    :root[data-rand="an"][data-seitentyp="kompakt"] .huelle > .mitte > main { max-width: min(34rem, var(--seitenbreite)); }
    :root[data-rand="an"][data-seitentyp="lesen"]   .huelle > .mitte > main { max-width: min(78rem, var(--seitenbreite)); }

    :root[data-rand="an"] .rand { padding-top: 1rem; }
    /* --kopf-h: Hoehe der mitlaufenden Menueleiste (0, wenn sie mitscrollt),
       s. „Mitlaufende Menueleiste“ weiter unten. Ohne den Abzug laege der obere
       Teil der Tafel unter der Leiste. */
    :root[data-rand="an"] .huelle > .rand-rechts {
        position: sticky;
        top: var(--kopf-h);
        max-height: calc(100vh - var(--kopf-h));
        overflow-y: auto;
        /* auto statt hidden: Passt eine Zahl trotz fit-content nicht mehr in den
           Deckel, scrollt der Kasten in sich. Abschneiden verlöre Ziffern. */
        overflow-x: auto;
        padding-right: .25rem;
    }

    /* WICHTIG: Die Ausbruchsformel der Text-Tabellen (50vw) setzt eine mittig im
       FENSTER stehende Lesespalte voraus. Neben einer Randspalte stimmt das nicht
       mehr — ohne diese Rueckstellung schoeben sich alle breiten Tabellen unter
       die Tafel. Innerhalb des Rasters bleibt die Tabelle deshalb in ihrer Zelle
       und scrollt dort. */
    :root[data-rand="an"] .huelle .breit-scroll-text {
        max-width: 100%;
        margin-right: 0;
    }
    /* Die zugeklappte Leiste ueber dem Inhalt entfaellt: rechts steht die Tafel,
       und dieselben Zahlen zweimal auf einer Seite waeren fuer JAWS eine
       doppelte Tabelle. */
    :root[data-rand="an"] .werkzeuge > .ressourcen-leiste { display: none; }
}

@media (min-width: 110rem) {
    :root[data-rand="an"] .huelle:has(> .rand-links) {
        grid-template-columns: minmax(0, 17rem) minmax(0, 1fr);
        grid-template-areas: "links mitte" "ereignisse mitte";
    }
    :root[data-rand="an"] .huelle:has(> .rand-links):has(> .rand-rechts) {
        grid-template-columns: minmax(0, 17rem) minmax(0, 1fr) fit-content(28rem);
        grid-template-areas: "links mitte rechts" "ereignisse mitte rechts";
    }
    :root[data-rand="an"] .huelle > .rand-links { display: block; }
    :root[data-rand="an"] .rand-rechts > .rand-kasten { display: block; }

    /* „Neue Ereignisse“ in der LINKEN Spalte, unter dem Bau-Kasten. Mitten im
       Inhalt ist der Block am echten Konto gemessen 541 px hoch — auf jeder
       Seite, auf der Werft 27 % der ganzen Seitenhoehe. Fehlt der Bau-Kasten,
       steht er allein in der Spalte; die Flaeche „links“ bleibt dann leer. */
    :root[data-rand="an"] .huelle > .ereignisse {
        margin-top: 1rem;
        font-size: .95rem;
    }
    :root[data-rand="an"] .huelle > .ereignisse h2 { border-top: 0; padding-top: 0; margin-top: 0; font-size: 1.1rem; }
    :root[data-rand="an"] .huelle > .ereignisse h3 { font-size: .95rem; margin: .75rem 0 .25rem; }
    :root[data-rand="an"] .huelle > .ereignisse ul { padding-left: 1.1rem; }
    :root[data-rand="an"] .huelle > .ereignisse li { margin-bottom: .4rem; }

    /* Jeder Eintrag hoechstens drei Zeilen. Die Meldungstexte sind ganze
       Saetze („Die Flotte ist beim Kometen … angekommen und arbeitet …“); in
       der 272 px schmalen Spalte waechst EIN Eintrag sonst auf 389 px, der
       ganze Block auf 1334 px. Fuer JAWS aendert sich NICHTS: line-clamp ist
       reine Darstellung, der volle Satz steht im DOM und wird vollstaendig
       vorgelesen; sehend zeigt das Auslassungszeichen, dass es weitergeht. */
    :root[data-rand="an"] .huelle > .ereignisse li {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 3;
        line-clamp: 3;
        overflow: hidden;
    }
}

/* Die Randkaesten selbst. Optisch abgesetzt wie der Welt-Wechsler; eingeklappt
   sind sie je genau EIN Tab-Stopp. */
.rand-kasten {
    border: 1px solid var(--rand);
    border-radius: 8px;
    background: var(--bg-karte);
    box-shadow: 0 1px 3px var(--schatten);
    padding: .25rem .85rem;
    margin-bottom: 1rem;
    font-size: .95rem;
}
.rand-kasten > summary { cursor: pointer; font-weight: 600; padding: .35rem 0; }

.rand-kasten ul { margin: .25rem 0 .5rem; padding-left: 1.1rem; }
.rand-kasten li { margin-bottom: .5rem; }
.rand-kasten p { margin: .25rem 0 .5rem; }

/* REGISTERKARTEN (Gebäude- und Werft-Seite, templates/teil/karten.php und
   js/karten.js). Sie ersetzen die früheren Sprunglinks und die Bereichs-
   Leiste (Marc, 2026-09-26: „die fressen unnötig Platz“).

   Zwei Ebenen, sichtbar verschieden:
   - HAUPTKARTEN (.karten) sehen aus wie Registerkarten eines Ordners: eine
     klare Grundlinie über die ganze Breite, die inaktiven Karten stehen als
     getönte Laschen darauf, die AKTIVE Karte trägt die Seitenfarbe, öffnet
     die Grundlinie nach unten — sie geht in das Paneel über — und hat oben
     einen kräftigen Balken. Das Paneel selbst bekommt keinen Kasten: ein
     Rahmen mit Innenabstand kostete den breiten Tabellen darin Platz.
   - UNTERKARTEN (.unterkarten) sind deutlich kleiner und leiser: eine
     Pillenleiste, die umbricht.
   Aktiv ist nie nur eine Farbe (WCAG 1.4.1): Hauptkarte fett, mit Balken und
   offener Grundlinie; Unterkarte fett, mit stärkerem Rand und Unterstrich.
   Beide Zustände gelten für aria-selected (mit Skript) UND aria-current
   (Link-Leiste ohne Skript) — sie sehen gleich aus.

   SCHMALE SCHIRME: Die Hauptkarten bilden NIE eine zweite Reihe — dann
   stünden Laschen ohne Verbindung zum Paneel da, und die Grundlinie, das, was
   die Karten zu Karten macht, läge mitten zwischen den Reihen. Stattdessen
   bricht der NAME innerhalb seiner Karte um (Media-Query weiter unten), alle
   Karten bleiben im Bild. Nur wenn selbst das nicht reicht, scrollt die
   Leiste in sich (die Seite nie); js/karten.js holt die aktive Karte dann
   ins Bild — nur in der Leiste. Die Unterkarten brechen dagegen als Reihe um:
   Es sind bis zu fünf mit langen Namen, eine Wischleiste versteckte gerade
   die hinteren Rubriken. */
.karten {
    list-style: none;
    display: flex;
    align-items: flex-end;
    gap: .3rem;
    margin: 1.5rem 0 .9rem;
    /* Oben Luft für den Fokusring; die Grundlinie ist ein Schatten statt eines
       Rands, damit die aktive Karte sie überdecken kann (ein Rand läge unter
       dem Inhalt, der quer scrollende Kasten schnitte jeden Ueberstand ab). */
    padding: .35rem .5rem 0;
    box-shadow: inset 0 -2px 0 var(--rand-stark);
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: thin;
}
.karten > li { margin: 0; flex: 0 0 auto; }
.karten a {
    display: block;
    margin-bottom: 2px;             /* lässt die Grundlinie unter der Lasche frei */
    padding: .45rem 1.1rem .4rem;
    border: 1px solid var(--rand);
    border-bottom: 0;
    border-radius: 8px 8px 0 0;
    background: var(--bg-tabellenkopf);
    color: var(--text);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}
.karten a:visited { color: var(--text); }
.karten a:hover { background: var(--bg-karte); text-decoration: underline; }
.karten a[aria-selected="true"],
.karten a[aria-current="page"] {
    /* 2 px tiefer: überdeckt die Grundlinie, die Karte geht ins Paneel über. */
    margin-bottom: 0;
    padding-top: calc(.45rem - 2px);
    padding-bottom: calc(.4rem + 2px);
    border-color: var(--rand-stark);
    border-top: 3px solid var(--link);
    background: var(--bg);
    font-weight: 700;
}
.karten a[aria-selected="true"]:hover,
.karten a[aria-current="page"]:hover { background: var(--bg); }
/* Der Fokusring liegt INNEN: Der quer scrollende Kasten schnitte einen Ring
   aussen herum ab. Mit der Maus geklickt kein Ring (nur :focus-visible). */
.karten a:focus-visible { outline-offset: -4px; }
.karten a:focus:not(:focus-visible),
.unterkarten a:focus:not(:focus-visible) { outline: none; }
/* Die Anzahl leiser — derselbe Text für den Screenreader, sehend Beiwerk. */
.karten-zahl { font-weight: 400; color: var(--text-gedimmt); }
/* Schmale Schirme: Die Karten teilen sich die Breite zu gleichen Teilen, und
   ihr Name darf umbrechen („Neue Gebäude / bauen (25)“). Alle Karten bleiben
   so im Bild und die Laschen verbunden mit der Grundlinie — besser als eine
   Leiste, deren hintere Karte man erst wegwischen müsste (gemessen auf 375 px:
   einzeilig passten anderthalb von drei Karten). Ist ein einzelnes Wort
   breiter als sein Anteil („Raumschiffswerft“), bricht es an seiner Wortfuge
   (.fuge, gesetzt von Core\Karten::nameHtml — „Raumschiffs/werft“). Auf die
   Silbentrennung allein ist kein Verlass: Chrome lädt die Trennwörterbücher
   erst nach, in einem frischen Profil trennte er gar nichts, und die Werft-
   Leiste lief auf 375 px über. Querscrollen der Leiste bleibt letzter Ausweg.
   Breiten nach Inhalt statt zu gleichen Teilen sahen schlechter aus: Beim
   Schrumpfen trennte der Browser dann sogar „Gar-nison“.
   Getrennt wird erst ab zehn Buchstaben und mit mindestens vier auf jeder
   Seite (hyphenate-limit-chars): Zusammen mit dem Zeilenausgleich (balance)
   trennte der Browser sonst auch kurze Wörter nur, um zwei gleich lange Zeilen
   zu bekommen — „Bau-/liste (0)“ statt „Bauliste/(0)“. Wo ein Wörterbuch da
   ist, trennt er lange Hälften („Raum-schiffs“) weiter mit Strich. */
@media (max-width: 40rem) {
    .karten { gap: .2rem; padding-inline: .25rem; margin-top: 1.25rem; align-items: stretch; }
    .karten > li { flex: 1 1 0; min-width: min-content; display: flex; }
    .karten a {
        flex: 1 1 auto;
        padding-inline: .35rem;
        font-size: .87rem;
        line-height: 1.3;
        white-space: normal;
        text-align: center;
        hyphens: auto;
        hyphenate-limit-chars: 10 4 4;
        text-wrap: balance;
    }
}
/* Sehr schmal (bis 368 px): Die vier Werft-Karten brauchten auch mit Wortfuge
   noch mehr Platz, als da ist — auf 320 px rund 20 px, englisch auf 360 px
   („Construction queue“) 5 px. Etwas kleinere Schrift und engere Laschen
   statt einer Leiste, die quer scrollt. */
@media (max-width: 23rem) {
    .karten { gap: .15rem; padding-inline: .15rem; }
    .karten a { padding-inline: .2rem; font-size: .8rem; }
}
/* Die Wortfuge langer Kartennamen (Core\Karten::FUGE): ein leerer Inline-Block
   der Breite 0 — davor und danach darf die Zeile brechen, ohne Trennstrich und
   ohne dass sich der zugängliche Name ändert. */
.fuge { display: inline-block; width: 0; }

.unterkarten {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: .3rem .4rem;
    margin: 0 0 .75rem;
    padding: 0;
    font-size: .9rem;
}
.unterkarten > li { margin: 0; }
.unterkarten a {
    display: inline-block;
    padding: .12rem .75rem;
    border: 1px solid var(--rand);
    border-radius: 999px;
    color: var(--text-gedimmt);
    text-decoration: none;
}
.unterkarten a:visited { color: var(--text-gedimmt); }
.unterkarten a:hover { color: var(--text); text-decoration: underline; }
.unterkarten a[aria-selected="true"],
.unterkarten a[aria-current="page"] {
    color: var(--text);
    font-weight: 700;
    background: var(--bg-karte);
    border-color: var(--rand-stark);
    box-shadow: inset 0 -2px 0 var(--link);
}
.unterkarten .karten-zahl { font-weight: inherit; color: inherit; }

/* Ein verstecktes Paneel, eine weggefilterte Zeile oder Gruppe: `hidden`
   gewinnt gegen jede eigene display-Regel (die Gruppen sind flex). */
.karte[hidden], [data-filter][hidden] { display: none !important; }

/* Sprung auf eine Karte (#gebaeude, #neubau …; Rückweg nach einem Bau-Klick,
   Links wie „Zum Neubau“): Ziel ist die sehend versteckte h2 am Anfang des
   Paneels. Mit dem üblichen Abstand der h2-Sprungziele stünde die Kartenleiste
   knapp über dem Fensterrand — mehr Luft, damit sie im Bild bleibt und man
   sieht, auf welcher Karte man gelandet ist. */
.karte > h2.sr-only[id] { scroll-margin-top: calc(var(--kopf-frei) + 4.5rem); }

/* Werft-Karte: Stufe und Bau-Kapazität der Werft über den Unterkarten. */
.werft-angabe { margin: 0 0 .75rem; }
details.werft-angabe > summary { cursor: pointer; }

/* ZWEISPALTIGE GRUPPEN auf breiten Schirmen — damit auf einem 90-cm-Bildschirm
   der ganze Schirm genutzt wird.

   Einspaltig ist er das NICHT: Bei 3440 px ist die Inhaltsspalte 2576 px breit,
   die breiteste Tabelle darin aber nur 1114 px — die Spalte ist zu 43 % gefuellt,
   rechts daneben bleiben 1462 px leer, und die Gebaeude-Seite ist 4,7
   Bildschirmhoehen lang. Tabellen kuenstlich zu strecken waere die falsche
   Antwort (500 px Spaltenbreite fuer eine Zahl); nebeneinander stellen ist die
   richtige: alle 27 Gruppen passen paarweise (2 x 1114 + Fuge < 2576).

   Warum GRID und nicht `columns`: Zugeklappte Gruppen sind alle gleich hoch (nur
   die Titelzeile), es entstehen also keine Loecher — und `grid-column: 1 / -1`
   fuer eine AUFGEKLAPPTE Gruppe ist verlaesslicher als `column-span: all`.

   Fuer den Screenreader aendert sich nichts: Die DOM-Reihenfolge bleibt, das
   Raster ordnet zeilenweise links nach rechts, also genau in Tab-Reihenfolge.
   Erst ab 110rem — derselbe Punkt, ab dem auch die Randspalten erscheinen. */
@media (min-width: 110rem) {
    .gruppen-raster {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0 1.5rem;
        align-items: start;
    }
    /* Ab 150rem (2400 px) drei Spalten. Zugeklappt ist eine Gruppe nur eine
       Titelzeile — auf einem 3440er staenden die 27 Gebaeudegruppen in zwei
       Spalten mit je 1550 px, also fast nur Leerraum neben dem Text. Die
       Aufklapp-Regel darunter (volle Breite) gilt unveraendert weiter. */
    @media (min-width: 150rem) {
        .gruppen-raster { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    }
    /* Aufgeklappt = volle Breite: sonst muesste die Tabelle in die halbe Spalte
       passen und wuerde wieder seitwaerts scrollen. Beim Imperium traegt die
       Umschliessung .gruppe die Ueberschrift mit, dort greift sie am Kind. */
    .gruppen-raster > details[open],
    .gruppen-raster > .gruppe:has(> details[open]) {
        grid-column: 1 / -1;
    }
}

/* GEBAUTE GEBAEUDE (/planet, Karte „Gebaute Gebäude“): die Gruppen je Typ
   ZUGEKLAPPT in einem dichten Raster, das die Breite auf JEDEM Schirm nutzt —
   nicht erst ab 110rem wie das Gruppen-Raster oben (Marc: „optimal
   platzausnutzend zusammengeklappt“). So viele Spalten, wie Gruppen von
   mindestens 28rem nebeneinander passen: auf dem Handy eine, auf 1366 px zwei,
   auf 1920 px drei. 28rem, weil in einer Zelle Titel UND Knopf stehen
   („Deuterium-Raffinerie (12, Ø 7,3)“ neben „Deuterium-Raffinerie: alle +1“).

   Jede Zelle ist Gruppe + Knopf nebeneinander. Der Knopf steht NEBEN dem
   <details>, nicht im <summary> — ein Bedienelement im Schalter liest JAWS
   nicht als eigenen Knopf. Aufgeklappt spannt die Gruppe über die volle
   Breite (ihre Tabelle braucht sie), und der Knopf daneben verschwindet: Das
   Formular in der Gruppe bietet dasselbe +1 (neben +5, +10, Angleichen) —
   stünde er daneben, quetschte er die Tabelle ein und wäre ein doppelter
   Tab-Stopp. Für den Screenreader ändert sich an der Reihenfolge nichts. */
.geb-raster {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 28rem), 1fr));
    gap: .5rem 1rem;
    align-items: start;
    margin: 0 0 1rem;
}
/* Titel und Knopf nebeneinander, solange der Titel dabei mindestens 13rem
   behält; sonst (Handy) rutscht der Knopf rechtsbündig in die Zeile darunter,
   statt den Titel auf drei Zeilen zusammenzuquetschen. 13rem, damit auf
   1366 px auch „Deuterium-Raffinerie (20, Ø 14,2)“ neben seinem Knopf bleibt
   (zweizeilig) — mit 14rem rutschte dort als einzigem der Knopf nach unten.
   Umbrechen darf der Titel nur vor der Klammer (geschützte Leerzeichen,
   templates/planet/uebersicht.php). */
.geb-gruppe {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: .35rem .5rem;
    min-width: 0;
}
.geb-gruppe > details.abschnitt { flex: 1 1 13rem; min-width: 0; margin: 0; }
.geb-gruppe:has(> details[open]) { grid-column: 1 / -1; }
.geb-gruppe:has(> details[open]) > .gruppe-knopf { display: none; }
.gruppe-knopf {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    margin: 0 0 0 auto;
    max-width: 100%;
}
.gruppe-knopf button {
    padding: .4rem .8rem;
    font-size: .92rem;
    text-align: right;
}
/* Ruhiger als der Haupt-Knopf: Zwei Dutzend Gruppen mit je einem kräftig
   blauen Knopf wären eine Wand aus Blau. Gesperrt (zu teuer) greift weiter die
   gedämpfte Optik von button[aria-disabled]. */
.gruppe-knopf button:not([aria-disabled="true"]) { background: var(--aktion-zweit); }
.gruppe-knopf .grund { font-size: .85rem; text-align: right; }
/* ZUGEKLAPPT ist die Zelle EINE Karte: Rahmen und Fläche trägt die Zelle,
   nicht mehr die Titelzeile allein. Vorher endete jede Titelzeile dort, wo der
   Knopf daneben begann — und weil die Knöpfe verschieden lang sind („Stadt:
   alle +1“ gegen „Deuterium-Raffinerie: alle +1“), franste das Raster rechts
   aus. So sind alle Zellen einer Spalte gleich breit, der Knopf sitzt rechts
   in seiner Karte. Aufgeklappt gilt wieder die gewohnte Optik von
   details.abschnitt (Kopf + Kasten). Ohne :has() bleibt die Zeile wie vorher. */
.geb-gruppe:not(:has(> details[open])) {
    align-items: center;
    background: var(--bg-karte);
    border: 1px solid var(--rand);
    border-radius: 6px;
}
.geb-gruppe:not(:has(> details[open])) > details.abschnitt > summary {
    border-color: transparent;
    background: transparent;
}
.geb-gruppe:not(:has(> details[open])) > details.abschnitt > summary:hover { background: var(--bg-tabellenkopf); }
/* Abstand zum Kartenrand — auch wenn der Knopf auf dem Handy in die Zeile
   unter dem Titel rutscht. */
.geb-gruppe:not(:has(> details[open])) > .gruppe-knopf { margin: .3rem .35rem .3rem auto; }

/* MEHRSPALTIGE LISTEN auf breiten Schirmen — die Bildschirmflaeche soll genutzt
   werden, nicht nur ein Viertel links oben.

   Textseiten wie die Hilfe bestehen aus schmalen Absaetzen und langen Listen —
   einspaltig nutzen sie auf 3440 px gemessen 21 % der Flaeche, der Rest bleibt
   leer. Eine Liste ist der eine Inhalt, der sich gefahrlos aufteilen laesst:
   Ihre Eintraege sind unabhaengig voneinander, und `columns` fuellt Spalte fuer
   Spalte von oben nach unten — die Lesereihenfolge bleibt also genau die
   DOM-Reihenfolge.

   Fuer den Screenreader aendert sich nichts: Es ist dieselbe eine <ul> mit
   denselben <li>, JAWS liest sie unveraendert der Reihe nach.

   `break-inside: avoid` haelt jeden Eintrag zusammen — ohne das risse der
   Spaltenumbruch mitten in einen Satz. Gemessen an der Hilfe-Themenliste auf
   3425 px: 819 px hoch einspaltig, 293 px dreispaltig.

   Nur ab 110rem, und nur fuer Listen, die lang genug sind, um etwas zu
   verteilen — bei drei Eintraegen waeren drei Spalten mit je einer Zeile
   schlechter als eine Liste. */
@media (min-width: 110rem) {
    .hilfe-themen:has(> li:nth-child(6)),
    main > ul:has(> li:nth-child(8)) {
        columns: 3 24rem;
        column-gap: 2.5rem;
    }
    .hilfe-themen > li,
    main > ul > li {
        break-inside: avoid;
    }
    /* In der Lesespalte gilt die 75ch-Grenze je SPALTE, nicht fuer die Liste. */
    .hilfe-themen > li, main > ul > li { max-width: none; }
}

/* „Neue Ereignisse“: als Karte abgesetzt — ohne Abgrenzung liefe der Block in
   den Seiteninhalt ueber. */
.ereignisse {
    border: 1px solid var(--rand);
    border-radius: 8px;
    background: var(--bg-karte);
    box-shadow: 0 1px 3px var(--schatten);
    padding: .25rem 1rem 1rem;
    margin: 1.5rem 0 0;
}
.ereignisse .zeit { color: var(--text-gedimmt); font-size: .9rem; }

/* FUSSLEISTE der „Neuen Ereignisse“ (Marc, 2026-09-27): Sammel-Knopf und Weg
   zum Abschalten stehen am Ende der Liste — bei 40 Meldungen Bildschirme tief
   unter der Überschrift, sehend also weg. Die Leiste klebt darum am unteren
   Fensterrand, solange der Kasten im Bild ist.

   `sticky` am KASTEN, nicht `fixed`: Die Leiste verlässt den Kasten nie. Sie
   verdeckt nur seine eigenen Einträge, nie den Seiteninhalt, und ist der
   Kasten zu Ende, steht sie an ihrem Platz darunter. DOM, Lese- und
   Tab-Reihenfolge bleiben — für JAWS ändert sich nichts. Getönter Grund und
   kräftiger Strich wie beim mitlaufenden Tabellenkopf: Was klebt, sieht
   gleich aus. Die negativen Ränder ziehen die Leiste bis an den Kastenrand. */
.ereignisse-fuss {
    position: sticky;
    bottom: 0;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .75rem;
    margin: .75rem -1rem -1rem;
    padding: .6rem 1rem .75rem;
    background: var(--bg-tabellenkopf);
    border-top: 2px solid var(--rand-stark);
    border-radius: 0 0 7px 7px;
    box-shadow: 0 -.5rem .75rem -.5rem var(--schatten);
    container-type: inline-size;
}
.ereignisse-fuss form { margin: 0; }
.ereignisse-fuss button,
.ereignisse-fuss .knopf { line-height: 1.25; text-align: center; }
/* Schmal (linke Randspalte, Handy) stehen Knopf und Link untereinander —
   dann beide so breit wie die Leiste statt verschieden lang. Nebeneinander
   brauchen sie rund 41rem. */
@container (max-width: 42rem) {
    .ereignisse-fuss > form,
    .ereignisse-fuss > .knopf { flex: 1 1 100%; }
    .ereignisse-fuss button { width: 100%; }
}
/* Fokus nicht hinter der Leiste (WCAG 2.4.11): Wer mit Tab durch die Liste
   geht, sieht jeden Eintrag über der Leiste. Nur die Einträge, NICHT die
   Knöpfe der Leiste — die stehen sichtbar unten; mit Abstand hielte der
   Browser sie für verdeckt und rollte bei jedem Tab nach (vgl. „Mitlaufende
   Menüleiste“). */
.ereignisse li a { scroll-margin-bottom: 9rem; }

/* Blaetter-Zeile der Karte: voriges/naechstes System, Rasterzeile,
   Nachbar-Galaxie. Ein <p> mit Fliesstext, KEINE Liste — darum auch kein Flex:
   die Trennzeichen zwischen den Links wuerden sonst zu eigenen Elementen.
   Die Pfeile stehen in aria-hidden-Spans, die Beschriftung traegt Klartext
   („Voriges System: 276“); am Rand steht statt eines toten Links der Grund. */
.blaettern {
    margin: .5rem 0;
    line-height: 2;
}
.blaettern a { white-space: nowrap; }

/* Breite Matrix-Tabellen (Imperiums-Übersicht): Die 70ch-Grenze oben ist
   fürs Lesen von Fließtext richtig, für eine Tabelle mit einer Spalte je Objekt
   aber zu eng. Statt die Grenze global zu lockern, scrollt NUR der Tabellen-
   Container seitwärts — die Seite selbst läuft nie horizontal, und für den
   Screenreader ändert sich nichts (die Tabelle bleibt vollständig im DOM).
   tabindex/role kommen bewusst nicht dazu: ein fokussierbarer Container wäre für
   JAWS ein zusätzlicher Tab-Stopp vor jeder Tabelle.

   position:relative ist KEIN Schmuck: .sr-only ist position:absolute,
   und ohne positionierten Vorfahren verankert sich so ein Span am Seiten-
   Wurzelblock statt am Container — er wird dann NICHT mitgeklippt und schiebt
   die ganze Seite quer auf (in der Sternkarte gemessen: 1366 statt 1265 px).
   Mit dem relativen Container bleibt der Überstand da, wo er hingehört. */
.breit-scroll {
    overflow-x: auto;
    position: relative;
    /* So breit wie die Tabelle BRAUCHT, hoechstens so breit wie der Platz:
       Ohne `fit-content` streckt `min-width: 100%` an der Tabelle sie auf die
       volle Containerbreite — auf einem 3440px-Schirm wuerde die
       Imperiums-Matrix dadurch von 1366 auf 2536 px aufgezogen, also rund
       500 px Spaltenbreite fuer eine Zahl. Das erschwert das Zuordnen von Zeile
       und Spalte, statt es zu erleichtern. Bei schmalem Fenster greift weiter
       `max-width: 100%`, und die Tabelle fuellt den Container wie bisher. */
    width: fit-content;
    max-width: 100%;
}
.breit-scroll > table { min-width: 100%; width: auto; }
.breit-scroll th, .breit-scroll td { white-space: nowrap; }

/* Variante für TEXT-Tabellen: Die Gebäude- und Neubau-Tabelle hat Spalten mit
   ganzen Sätzen darin („Stufe 2 bringt: +3.715/Std Roheisen, −10 Energie,
   −6 Arbeiter, Kosten: …“). In der 70ch-Lesespalte bleiben dafür 106 px übrig,
   jede Zelle wird dadurch sechzehn Zeilen hoch, und die Spalten „Nächster
   Ausbau“ und „Wirkung“ sind kaum noch lesbar. `nowrap` wie oben wäre hier
   falsch (eine Kostenliste in EINER Zeile ist meterlang), darum: Der Container
   darf seitwärts scrollen, die Spalten wachsen nach Inhalt, und der Umbruch
   greift erst am Zellen-Deckel. Für den Screenreader ändert sich nichts – die
   Tabelle bleibt vollständig im DOM, kein zusätzlicher Tab-Stopp.

   Der Container darf dabei aus der Lesespalte AUSBRECHEN, soweit das Fenster es
   zulässt (`margin-inline` mit 50 % − 50vw): auf einem breiten Bildschirm steht
   die Tabelle dann ganz da und muss gar nicht gescrollt werden, auf einem
   schmalen bleibt es beim seitlichen Scrollen im Container. Die SEITE läuft in
   keinem Fall horizontal — die Randreserve (2,5rem) deckt die Scrollleiste. */
.breit-scroll-text {
    overflow-x: auto;
    position: relative;
    /* So breit wie die Tabelle BRAUCHT (nicht mehr): eine schmale Zwei-Spalten-
       Tabelle bleibt dadurch kompakt an der Lesespalte stehen und wird nicht auf
       Fensterbreite gezogen. Nach rechts darf sie bis zum Fensterrand wachsen. */
    width: fit-content;
    /* Platz vom linken Rand der Lesespalte bis zum rechten Fensterrand: die halbe
       Fensterbreite plus die halbe Spaltenbreite, minus Randreserve. (100vw wäre
       falsch — der Container beginnt nicht am Fensterrand, sondern eingerückt.) */
    max-width: calc(50vw + 50% - 1.25rem);
    margin-right: calc(50% - 50vw + 1.25rem);
}
.breit-scroll-text > table { width: max-content; }
/* Zellendeckel: verhindert, dass EIN langer Fliesstext die Tabelle quer zieht.
   Zellen mit Kosten-Posten sind davon ausgenommen — dort ist der Deckel der
   Grund fuer den Umbruch, und die Posten begrenzen sich schon selbst. */
.breit-scroll-text th, .breit-scroll-text td { max-width: 32ch; }
/* 60ch gemessen statt geschaetzt (Bau-Katalog auf 1351 px, 25 Zeilen):
   46ch = 2286 px hoch · 60ch = 2010 px · 72ch = 1954 px · ohne Deckel = 1893 px.
   Ab 90ch faengt die Tabelle an, auf einem 1366er-Laptop seitwaerts zu scrollen —
   die letzten 120 px Hoehengewinn waeren also mit Querscrollen bezahlt. */
.breit-scroll-text td:has(> .kosten) { max-width: 60ch; }
/* Auf breiten Schirmen darf die Spalte mehr nehmen — dort ist der Platz da, und
   jeder Posten, der in dieselbe Zeile passt, spart eine Zeilenhoehe ueber die
   ganze Tabelle. Gemessen auf 3425 px: 60ch = 2075 px hoch, 100ch = 1595 px. */
@media (min-width: 110rem) {
    .breit-scroll-text td:has(> .kosten) { max-width: 100ch; }

    /* Auf breiten Schirmen darf eine KOSTEN-Tabelle die Spalte ausfuellen,
       statt in einem Viertel links oben zu kleben.

       Sonst gilt weiter `width: fit-content` — eine zweispaltige Tabelle mit
       zwei Zahlen auf 3200 px zu ziehen, waere das genaue Gegenteil von
       aufgeraeumt. Genau diese Tabellen aber profitieren: Ihre Kosten-Spalte
       bekommt den Ueberschuss, die Posten passen in eine Zeile, und die Tabelle
       fuellt die Flaeche, statt in einem Viertel links zu kleben.

       Gemessen am Bau-Katalog auf 3425 px: die Tabelle waechst von 1573 auf
       3160 px Breite. Die Hoehe faellt dabei nur um 51 px — der Gewinn dieser
       Regel ist die FLAECHE, nicht die Hoehe. Erst zusammen mit der Regel
       „Knopf neben Grund“ (weiter unten bei den Tabellen) zahlt sie sich auch in
       Hoehe aus: 2269 → 1353 px.

       WARUM ERST AB 110rem, gemessen statt geschaetzt: Darunter ist die volle
       Breite SCHAEDLICH. Mit `fit-content` darf die Tabelle breiter sein als ihr
       Container und dort seitwaerts scrollen; auf 100 % gezwungen bricht sie
       stattdessen um. Auf 1366 px wuerde der Katalog dadurch von 1730 auf
       1993 px wachsen, auf 1024 px sogar von 1745 auf 2786 px. */
    .breit-scroll-text:has(.kostenposten) {
        width: 100%;
        max-width: 100%;
        margin-right: 0;
    }
    .breit-scroll-text:has(.kostenposten) > table { width: 100%; }
}

/* Kopf und Fuss als eigene Flaeche: Sie sind Rahmen, nicht Inhalt, und
   sollen sich sichtbar vom Spielfeld absetzen. Der Streifen laeuft ueber die
   GANZE Fensterbreite (die Regel sitzt auf dem Element, die Breitenbegrenzung
   auf dem Innenabstand weiter unten) — sonst schwebte auf einem Ultrawide ein
   abgesetzter Kasten in der Mitte statt einer Leiste. */
header {
    background: var(--bg-kopf);
    border-bottom: 1px solid var(--rand);
}
footer {
    background: var(--bg-kopf);
    border-top: 1px solid var(--rand);
    color: var(--text-gedimmt);
    font-size: .9rem;
}
/* Ohne engere Abstaende ist die Fusszeile 194 px hoch fuer vier kurze Zeilen —
   mehr als die Haelfte davon nur Absatz-Abstaende (je .9rem oben und unten). Ein
   Absatz mitten im Fliesstext braucht diese Luft, eine Reihe kurzer Fusszeilen
   nicht.
   Struktur und Reihenfolge bleiben, damit JAWS weiter Zeile fuer Zeile springt. */
footer p { margin: .3rem 0; }
footer p:first-child { margin-top: 0; }
footer .sprache-wechsel { margin-top: .5rem; }

/* Der Spielname. Die Sperrung gibt ihm den Titel-Charakter, den eine fette
   Zeile allein nicht hat. */
.marke {
    font-weight: 700;
    /* Groesse und Zeilenhoehe stecken auch in --kopf-weg (unten) — darum als
       Variable am Kopf und die Zeilenhoehe ausdruecklich, nicht geerbt. */
    font-size: var(--marke-gr, 1.3rem);
    line-height: 1.6;
    letter-spacing: .02em;
    margin: 0;
}

/* MITLAUFENDE MENUELEISTE (Wunsch aus dem Test: „Menueleiste fixieren“).

   `position: sticky`, nicht `fixed`: DOM, Landmarks und damit Lese- und
   Tab-Reihenfolge bleiben unveraendert, und die Seite behaelt ihre Hoehe
   (js/scroll-merken.js rechnet weiter richtig). Fuer JAWS aendert sich nichts.

   Nur die MENUEZEILE bleibt stehen: Der Kopf klebt mit negativem `top`, der
   Innenabstand oben und die Markenzeile „Raumimperium“ scrollen weg
   (--kopf-weg). Auf 375 px bleiben so 43 der rund 90 px stehen.

   Nur ab 36rem Fensterhoehe: Im Querformat am Handy und bei starkem Zoom
   (400 % auf 1280 x 1024 lassen rund 256 px Hoehe) scrollt der Kopf mit weg —
   eine stehende Leiste naehme dort einen grossen Teil des Fensters ein
   (WCAG 1.4.10). Abschaltbar unter /einstellungen (data-kopf am <html>).

   --kopf-h ist die Hoehe des STEHENDEN Teils, 0 ausserhalb der Bedingung.
   Alles andere, was mitlaeuft (Tabellenkoepfe, Flash-Meldung, Ressourcen-
   Tafel), klebt darunter, und scroll-margin-top (--kopf-frei) haelt
   Sprungziele und den Tastaturfokus frei (WCAG 2.4.11). js/kopf.js misst die
   Hoehe laufend (Umbruch, aufgeklapptes „Menue“, Sprache) und legt sie als
   --kopf-mess ab; ohne JavaScript gelten die festen Rueckfallwerte.

   Der Abstand gilt fuer alles AUSSER dem Kopf — darum scroll-margin an den
   Elementen, nicht scroll-padding am <html>. Mit scroll-padding lag die
   Leiste selbst im freigehaltenen Streifen: Der Browser hielt jeden
   fokussierten Menuepunkt fuer verdeckt und rueckte ihn zur Mitte, was bei
   einer klebenden Leiste nichts bewirkt und sich bei jedem Tab wiederholte —
   die Seite lief Schritt fuer Schritt nach oben (1920 x 1080: 1500, 953, 406,
   0). Elemente in der Leiste stehen sichtbar oben und brauchen keinen Abstand.

   Der Admin-Balken (Blick in ein fremdes Konto) laeuft NICHT mit: Er traegt
   ein Formular und braucht auf dem Handy mehrere Zeilen. Stattdessen nimmt
   die Leiste seine Farbe als unteren Rand an — der Hinweis bleibt in jeder
   Scrolltiefe sichtbar; der Wortlaut steht oben und im Fenstertitel. */
:root { --kopf-h: 0px; --kopf-frei: 0px; }
/* Sprungziele und Fokus unter der Leiste, nicht dahinter. Bei 0 (Leiste aus,
   flaches Fenster) ist das der Ausgangswert — keine Aenderung. */
body > :not(header),
body > :not(header) * { scroll-margin-top: var(--kopf-frei); }
body > header {
    --marke-gr: 1.3rem;
    /* Innenabstand oben + Markenzeile (Schriftgroesse x Zeilenhoehe 1,6). Stehen
       bleibt nur der Abstand zum Menue (.25rem) — mehr Luft liesse die
       Unterlaenge des Spielnamens („p“) als Krume am oberen Rand stehen. */
    --kopf-weg: calc(1rem + var(--marke-gr) * 1.6);
    /* Wirkt nur, solange der Kopf klebt; js/kopf.js liest den Wert immer. */
    top: calc(-1 * var(--kopf-weg));
}
/* Der Spielname traegt auf dem Handy nicht so gross auf: 1,3rem kosten 33 px
   Kopfhoehe fuer ein Wort, das immer dasselbe sagt. */
@media (max-width: 44.99rem) {
    body > header { --marke-gr: 1.15rem; }
}
@media (min-height: 36rem) {
    :root[data-kopf="an"] {
        --kopf-h: var(--kopf-mess, 3rem);
        --kopf-frei: calc(var(--kopf-h) + .5rem);
    }
    :root[data-kopf="an"] body > header {
        position: sticky;
        /* Ueber Tabellenkoepfen (1), Meldung (3) und Ausklappfeldern (5). */
        z-index: 10;
        /* Unten halber Innenabstand: Mit dem vollen Rem waere die stehende
           Leiste unten viermal so dick wie oben. */
        padding-bottom: .5rem;
    }
}
/* Rueckfall ohne JavaScript ab 64rem: Dort bricht das Menue um, meist in
   zwei Zeilen. */
@media (min-height: 36rem) and (min-width: 64rem) {
    :root[data-kopf="an"] { --kopf-h: var(--kopf-mess, 4.6rem); }
}
body:has(> .admin-balken-zuschauen) > header { border-bottom: 3px solid var(--hinweis-rand); }
body:has(> .admin-balken-handeln) > header { border-bottom: 3px solid var(--gefahr); }

/* Ueberschriften-Hierarchie. Eine klare Staffel der Groessen, und die h2 bekommt
   eine Trennlinie darueber — die billigste Art, Abschnitte sichtbar zu machen,
   ohne jeden Block einzurahmen. Liegen h1 und h2 dicht beieinander (etwa 1,6 und
   1,2rem) und faellt h3 auf die Browser-Vorgabe zurueck, ist auf einer Seite mit
   sechs Abschnitten schwer zu sehen, was zu was gehoert.

   Fuer JAWS aendert das nichts: Die Ebenen stehen richtig im Markup, hier wird
   nur sichtbar, was der Screenreader ohnehin ansagt. */
h1 {
    font-size: 1.75rem;
    line-height: 1.25;
    letter-spacing: -.01em;
    margin: 0 0 .75rem;
}
h2 {
    font-size: 1.3rem;
    line-height: 1.3;
    margin: 2rem 0 .75rem;
    padding-top: .75rem;
    border-top: 1px solid var(--rand);
}
h3 { font-size: 1.08rem; margin: 1.25rem 0 .5rem; }
/* Die erste h2 einer Seite braucht keinen Strich — darueber steht schon der
   Titel, die Linie wuerde ihn nur doppelt abtrennen. */
main > h2:first-of-type { border-top: 0; padding-top: 0; margin-top: 1.25rem; }
/* In Karten und Randkaesten waere der Strich zu viel: die Karte grenzt selbst ab. */
.rand-kasten h2, .vorschau h2, .fehlerbox h2, details h2 { border-top: 0; padding-top: 0; }

/* Sichtbarer Fokus für Tastatur-Navigation. */
a:focus, button:focus, input:focus, [tabindex]:focus {
    outline: 3px solid var(--fokus);
    outline-offset: 2px;
}

/* Sprunglink: nur sichtbar, wenn er den Fokus hat. */
.sprunglink {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--akzent);
    color: var(--akzent-text);
    padding: .5rem 1rem;
    /* Ueber der mitlaufenden Menueleiste (z-index 10) — sonst laege der
       fokussierte Sprunglink unter ihr und waere unsichtbar. */
    z-index: 30;
}
.sprunglink:focus { left: 0; }

/* Navigation im Kopf (gilt auch für die Abschnitt-Sprunglinks der Hilfeseiten,
   nav.abschnitt-nav). */
nav { margin-top: .25rem; display: flex; flex-wrap: wrap; align-items: center; gap: .25rem 1rem; }

/* HAUPTNAVIGATION — eine flache Reihe, ohne Gruppierung und ohne Gruppennamen.

   Gemessen an der Variante mit fuenf beschrifteten Spalten: Auf 375 px war die
   Kopfzeile 435 px hoch — der Inhalt begann erst nach 54 % der Bildschirmhoehe.
   Auf 3440 px zog das Spaltenraster dieselben 16 Woerter ueber 2217 px
   auseinander, mit rund 430 px Luft neben jedem Punkt.

   Stattdessen: flex mit Umbruch, also so viele Punkte je Zeile wie hineinpassen,
   und dieselbe Reihe auf jeder Bildschirmbreite. Die Themen-Bloecke bleiben in
   der REIHENFOLGE erhalten und werden nur durch einen Strich sichtbar
   (.nav-block) — kein Text, kein Tab-Stopp, fuer den Screenreader nicht
   vorhanden. */
header nav { display: block; }
.nav-haupt {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    /* Positionsbezug fuer die visuell versteckten Spans darin (.nur-breit am
       Konto-Eintrag): Sie sind absolut positioniert und ohne positionierten
       Vorfahren am Seitenwurzel-Block verankert — auf dem Handy standen sie
       damit am Ende der WISCHLEISTE, also bei x = 1178 px, und zogen die ganze
       Seite auf 1179 px Breite auf (gemessen bei 375 px). Mit relative bleiben
       sie im Scroller. */
    position: relative;
    flex-wrap: wrap;
    align-items: baseline;
    /* Zeilenabstand knapp, Spaltenabstand so weit wie der Platz erlaubt.

       MOBIL ENGER: Auf 375 px brauchen die 17 Punkte mit dem weiten Abstand
       SECHS Zeilen, der Kopf wird 236 px hoch und die Ueberschrift beginnt erst
       bei 308 px — 38 % des ersten Bildschirms, bevor irgendetwas Inhalt kommt.
       Der weite Abstand ist auf breiten Schirmen richtig
       (er macht aus der Reihe eine Leiste statt eines Woerterblocks), auf dem
       Handy kostet er nur Zeilen. */
    gap: .15rem .7rem;
}
.nav-haupt > li { margin: 0; }

/* Themen-Grenze: senkrechter Strich VOR dem Punkt, der einen neuen Block
   eroeffnet. Rein dekorativ (border, kein Inhalt) — anders als eine Beschriftung
   kostet er weder Hoehe noch Vorlesezeit. Beim Zeilenumbruch faellt er weg (er
   saesse sonst sinnlos am Zeilenanfang).

   ERST AB 45rem: Der Strich bringt sein eigenes `padding-left` mit, das sich zum
   Spalten-`gap` ADDIERT — an jeder Gruppengrenze staenden so 36,8 px Luft. Auf
   einem 375-px-Schirm ist das der teuerste Posten im ganzen Kopf. Die
   Gruppierung steckt ohnehin in der REIHENFOLGE; der Strich macht sie nur
   sichtbar, und Sichtbarkeit ist genau das, was auf dem Handy am wenigsten
   fehlt. Fuer den Screenreader aendert das nichts — er nimmt den Strich gar
   nicht wahr. */
@media (min-width: 45rem) {
    .nav-haupt { gap: .15rem 1.15rem; }

    .nav-haupt > .nav-block {
        border-left: 1px solid var(--rand);
        padding-left: 1.15rem;
        margin-left: -.15rem;
    }
}

/* Eingeklappte Navigation — nur wenn unter /einstellungen ausdruecklich
   gewaehlt, Standard ist die flache Reihe.

   Gemessen auf 375 px: Der Kopf braucht mit der offenen Reihe 205 px, davon
   vier Zeilen Navigation; die Seitenueberschrift beginnt bei 34 % der
   Bildschirmhoehe. Zugeklappt bleibt eine Zeile, der Kopf faellt auf rund 90 px.

   BEWUSST OHNE Media-Query, obwohl der Gewinn nur auf schmalen Schirmen
   anfaellt: Ein <details>, dessen Inhalt ab 45rem per CSS wieder eingeblendet
   wird, meldet dem Screenreader trotzdem „zugeklappt“ — CSS erreicht den
   Barrierefreiheits-Baum nicht, und die Anzeige wuerde luegen. Der Cookie haengt
   ohnehin am Browser: Wer am Handy einklappt, klappt am Rechner nicht mit ein.

   Das <summary> traegt Klartext, keine Ueberschrift (sonst faellt der Punkt aus
   der Ueberschriften-Navigation von JAWS) und kein Symbol statt Text. */
.nav-klapp > summary {
    cursor: pointer;
    font-weight: 600;
    padding: .4rem .6rem;
    margin: 0 -.6rem;
    border-radius: 6px;
}
.nav-klapp[open] > summary { margin-bottom: .35rem; }
/* Eingeklappt stehen „Raumimperium“ und „Menü“ in EINER Zeile (Marc,
   27.09.2026) — auf dem Handy rund 40 px mehr für den Inhalt, auf jeder Seite.
   Der Name steht links (float), der Schalter daneben: `overflow: hidden` macht
   das <summary> zu einem eigenen Block-Kontext, der neben dem Namen Platz
   nimmt, statt darunter; es bleibt ein list-item, sein Dreieck bleibt.
   Aufgeklappt fällt die Liste darunter über die volle Breite. Die ganze Zeile
   bleibt beim Scrollen stehen — weg scrollt nur der Innenabstand darüber
   (--kopf-weg; js/kopf.js misst den stehenden Teil). */
body > header:has(> nav .nav-klapp) { display: flow-root; --kopf-weg: .75rem; }
/* Zeilenhöhe = Höhe des Schalters (2,4rem), damit beide Wörter auf einer
   Mitte stehen; .25rem oben wie der Abstand des Menüs. */
body > header:has(> nav .nav-klapp) > .marke { float: left; margin: .25rem 1rem 0 0; line-height: 2.4rem; }
body > header .nav-klapp > summary { overflow: hidden; width: fit-content; margin-left: 0; }

/* Konto-Block (Name + Abmelden) schliesst direkt an, abgesetzt durch denselben
   Strich wie eine Themen-Grenze.

   BEWUSST NICHT `margin-left: auto` (also nicht an den rechten Rand): gemessen
   auf 3440 px staende der Block dann 1700 px von den Menuepunkten entfernt am
   anderen Ende der Leiste — genau das Auseinanderziehen, das hier stoert. Der
   Kopf bleibt so auf jeder Breite EINE geschlossene Leiste. */
.nav-haupt > .nav-konto {
    display: flex;
    align-items: baseline;
    gap: .6rem;
}
/* Strich wie bei einer Themen-Grenze — aus demselben Grund erst ab 45rem. */
@media (min-width: 45rem) {
    .nav-haupt > .nav-konto {
        border-left: 1px solid var(--rand);
        padding-left: 1.15rem;
    }
}
/* Aktuelle Seite: fett UND unterstrichen UND als Pille hinterlegt.

   Die Pille ist der eigentliche Blickfang — in einer Reihe aus 17 gleich
   aussehenden Woertern findet das Auge eine Flaeche schneller als einen
   Schriftschnitt. Fett und Unterstreichung bleiben trotzdem: Farbe und Flaeche
   duerfen nie das EINZIGE Signal sein (WCAG 1.4.1), und wer mit hohem Kontrast
   oder eigenem Stylesheet liest, verliert den Hintergrund als Erstes.

   Negative Ausgleichs-Margin, damit die Pille die Zeilen nicht auseinander
   drueckt — sonst waere der Kopf durch diese Verbesserung wieder hoeher. */
header nav a[aria-current="page"] {
    font-weight: 700;
    text-decoration: underline;
    background: var(--bg-karte);
    border: 1px solid var(--rand-stark);
    border-radius: 999px;
    padding: .1rem .5rem;
    margin: -.1rem -.15rem;
}
/* Warum --rand-stark und nicht --rand: Der normale Randton kommt gegen den
   Kopfgrund nur auf 1,61:1 — die Pille waere da, ihre Kontur aber praktisch
   unsichtbar, also reines Rauschen. --rand-stark liegt bei 3,47:1 (dunkel) und
   erfuellt damit die 3:1 fuer grafische Objekte. Das Paar steht in
   `scratchpad/kontrast.php`, damit es bei der naechsten Farbrunde nicht
   stillschweigend zurueckfaellt. */
.nav-schlicht { gap: .25rem 1.15rem; }
.nav-status { color: var(--text-gedimmt); font-size: .9rem; }
.nav-logout { margin: 0; }
.nav-logout button { padding: .2rem .7rem; font-size: .85rem; }

/* Formulare & Meldungen. Barrierefrei: der Fehlertext steht immer im Klartext
   dabei – Farbe ist nur ein zusätzliches, nie das einzige Signal. */
form p { margin: 0 0 1rem; }

label { display: block; font-weight: 600; margin-bottom: .25rem; }

/* Auswahlmenüs mit langen Einträgen (Zielwahl im Missions-Schritt: Objektname +
   Koordinate) machen sich sonst so breit wie ihr längster Eintrag und schieben
   auf einem Handy die GANZE Seite quer (gemessen: 642 statt 375 px).
   Die Auswahl-Liste selbst zeigt beim Aufklappen weiterhin den vollen Text, und
   vorgelesen wird ohnehin der ganze Eintrag. */
select { max-width: 100%; }

/* EINSTELLUNGEN: Gruppen als Karten.

   Ohne eigene Regel tragen die fieldsets den Browser-Vorgabe-Rahmen
   (`2px groove`) — ein Kantenstil aus den Neunzigern, der neben den abgerundeten
   Karten des restlichen Spiels wie ein unfertiger Rest wirkt. Dieselbe Optik wie
   `.rand-kasten` macht daraus fertige Bausteine, ohne an der Struktur etwas zu
   aendern: fieldset und legend bleiben, was sie sind, und JAWS gruppiert
   unveraendert.

   Zweispaltig ab 45rem: Die vier Darstellungs-Gruppen sind kurz (drei Knoepfe,
   eine Checkbox) und staenden untereinander als schmale Streifen ueber die halbe
   Seitenhoehe.

   FESTE Spaltenzahl, nicht `auto-fit`: Mit `minmax(18rem, 1fr)` legt der Browser
   auf 1280 px gleich VIER Spalten nebeneinander, jede nur 290 px breit — die
   Beschriftungen der Radio-Knoepfe werden dort zur Schlucht. Auf 3440 px waeren es
   elf gewesen. Drei Spalten erst ab 110rem, wo wirklich Platz ist. */
.einstell-raster {
    display: grid;
    gap: 1rem;
    margin-bottom: 1rem;
}
@media (min-width: 45rem) {
    .einstell-raster { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 110rem) {
    .einstell-raster { grid-template-columns: 1fr 1fr 1fr; }
}
.einstell-raster > fieldset {
    border: 1px solid var(--rand);
    border-radius: 8px;
    background: var(--bg-karte);
    box-shadow: 0 1px 3px var(--schatten);
    padding: .25rem 1rem 1rem;
    margin: 0;
}
.einstell-raster > fieldset > legend {
    font-weight: 600;
    padding: 0 .4rem;
}
/* Der letzte Absatz einer Gruppe braucht keinen Abstand nach unten — sonst
   staffelt sich Karten-Padding auf Absatz-Rand. */
.einstell-raster > fieldset > p:last-child { margin-bottom: 0; }

/* Browser geben jedem <fieldset> ein `min-width: min-content` mit — es schrumpft
   also NIE unter seinen breitesten Inhalt, und ein Auswahlmenü mit langen
   Einträgen zieht damit die ganze Seite quer (Missions-Schritt auf dem Handy:
   642 statt 375 px). Mit min-width:0 gilt wieder die normale Block-Breite. */
fieldset { min-width: 0; }

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"] {
    width: 100%;
    max-width: 40ch;
    padding: .5rem;
    font-size: 1rem;
    border: 1px solid var(--rand-eingabe);
    border-radius: 4px;
    background: var(--bg-karte);
    color: var(--text);
}

input[type="number"] { max-width: 12ch; }

select {
    padding: .5rem;
    font-size: 1rem;
    border: 1px solid var(--rand-eingabe);
    border-radius: 4px;
    background: var(--bg-karte);
    color: var(--text);
}

input[aria-invalid="true"] { border: 2px solid var(--gefahr); }

/* Knoepfe: Praesenz durch Rundung, Schatten und eine Reaktion beim
   Ueberfahren/Druecken. Groesse und Kontrast bleiben davon unberuehrt — die
   Trefferflaeche darf nicht kleiner werden. */
button {
    padding: .5rem 1.25rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--akzent-text);
    background: var(--akzent);
    border: none;
    border-radius: 6px;
    box-shadow: 0 1px 2px var(--schatten);
    cursor: pointer;
}
button:hover { filter: brightness(1.12); }
button:active { transform: translateY(1px); box-shadow: none; }
/* Wer Bewegung abbestellt hat, bekommt kein Verschieben beim Druecken. */
@media (prefers-reduced-motion: reduce) {
    button:active { transform: none; }
}
/* Löschende/abreißende Aktion — als Gefahr markiert (Farbe ist nur Zugabe; der
   Button-Text "Abreißen (50 % zurück)" bleibt das eigentliche Signal für JAWS). */
button.gefahr { background: var(--gefahr-aktion); }

/* Vorgewarnter Knopf: Ohne eigene Regel für button[aria-disabled] sieht ein
   gesperrter Knopf für Sehende exakt aus wie ein aktiver — der Ausbau-Knopf
   steht dann da, obwohl die Ausbauressourcen nicht reichen.

   aria-disabled und NICHT das echte disabled: der Knopf muss klickbar bleiben.
   Die Sperre ist flüchtig („zu teuer“), die Produktion läuft weiter, und ein
   HTML-disabled fiele zusätzlich aus dem virtuellen JAWS-Cursor — mit
   Screenreader wäre dann nicht mehr nachzulesen, was dort stünde. Der Server
   lehnt Ungedecktes ohnehin ab, die Optik ist also Vorwarnung, keine
   Sicherung.

   Der Klartext-Grund daneben (.grund) trägt die Information; die Dämpfung ist
   nur Zugabe (WCAG 1.4.1). Kein cursor:not-allowed — der Klick ist erlaubt. */
button[aria-disabled="true"] {
    color: var(--text-gedimmt);
    background: var(--bg-karte);
    border: 1px solid var(--rand);
}

/* Fehlbetrag in einer Kostenliste (kostenListe() mit Bestand). Wie überall im
   Projekt: die Farbe ist Zugabe, der Klartext „(es fehlen 300)“ trägt die
   Aussage — mit Screenreader ist die Farbe nicht zu sehen, und Farbe allein
   verstößt gegen WCAG 1.4.1. Rot-Ton statt Fettung, damit die Zeile nicht
   schwerer wirkt als der Kostenposten selbst. */
.fehlt { color: var(--gefahr); }

/* Kosten-Posten (Optik). Ein Posten ist „Rohstoff: Menge“ und bleibt in sich
   zusammen (`inline-block` bricht innen nicht um); ob ZWEI Posten neben- oder
   untereinander stehen, entscheidet der Platz in der Spalte.

   Ein hartes <br> je Posten macht auf der Gebäude-Seite (1351 px) aus dem
   Bau-Katalog einen 3579 px hohen Block, obwohl neben der Tabelle 390 px frei
   bleiben.

   Der Abstand nach rechts trennt die Posten sichtbar, ohne ein Trennzeichen
   einzufügen, das der Screenreader mitlesen müsste. */
.kostenposten { display: inline-block; margin-right: .9rem; }
.kostenposten:last-child { margin-right: 0; }
/* Die Posten sind seit 1.86.0 eine echte Liste (ul.kosten > li.kostenposten,
   src/helpers.php kostenListe): Der Screenreader bekommt eine Aufzählung mit
   Einträgen, das Auge weiterhin eine Zeile — die Liste selbst ist inline, ohne
   Punkte, ohne Einzug, ohne Abstand nach oben oder unten. */
ul.kosten { display: inline; list-style: none; margin: 0; padding: 0; }

.feldfehler { display: block; color: var(--gefahr); font-weight: 600; }

/* Meldungen: kraeftige linke Kante statt nur eines duennen Rahmens — auf einer
   vollen Seite geht eine 1px-Umrandung sonst unter. Die Aussage steht wie immer
   im Text, die Farbe ist Zugabe (WCAG 1.4.1). */
.meldung { padding: .75rem 1rem; border-radius: 6px; margin-bottom: 1rem; box-shadow: 0 1px 3px var(--schatten); }
.meldung-fehler { background: var(--gefahr-bg); border: 1px solid var(--gefahr); border-left: 5px solid var(--gefahr); }
.meldung-erfolg { background: var(--erfolg-bg); border: 1px solid var(--erfolg-rand); border-left: 5px solid var(--erfolg-rand); }

/* Fehler-Sammlung im Formular – bewusst statisch (keine Live-Region). */
.fehlerbox { padding: .75rem 1rem; margin-bottom: 1rem; background: var(--gefahr-bg); border: 1px solid var(--gefahr); border-left: 5px solid var(--gefahr); border-radius: 6px; }
.fehlerbox h2 { margin: 0 0 .5rem; font-size: 1.05rem; }
.fehlerbox ul { margin: 0; padding-left: 1.25rem; }

/* Nachrichten-Detailseite. ZWEI Sorten Inhalt teilen sich .nachricht-inhalt, und
   sie brauchen Gegenteiliges:

   - Klartext-Nachrichten stehen in <pre>. Dort MUSS jeder Zeilenumbruch der
     Quelle bleiben — also pre-wrap, und break-word gegen Seitwärts-Scroll.
   - Schlacht- und Spionageberichte sind echtes HTML (<ul>, <table>, <h3>) in
     einem <div>. Dort ist pre-wrap FALSCH: Es hält jedes Leerzeichen der Quelle
     fest, statt es zu kollabieren.

   Sichtbar wurde das an den Ressourcen-Listen von Trümmerfeld und Beute. Bricht
   die Zeile nach „2.764 Stahl,“ um, bleibt das Leerzeichen bei pre-wrap als
   eigenes, 4 px breites Kästchen am Zeilenende hängen, statt zu verschwinden —
   gemessen am 28.08.2026 an einem echten Bericht: drei Zeilen-Rechtecke statt
   zwei, das mittlere 4 px breit. Dazu zerlegte break-word lange Rohstoffnamen
   mitten im Wort. Zusammen las sich die Aufzählung, als fehlten die
   Leerzeichen. */
.nachricht-meta { color: var(--text-gedimmt); font-size: .9rem; margin: 0 0 1rem; }
.nachricht-inhalt { font-family: inherit;
    background: var(--bg-einschub); border: 1px solid var(--rand); border-radius: 8px; padding: 1rem; line-height: 1.5; }
pre.nachricht-inhalt { white-space: pre-wrap; word-break: break-word; }
/* Berichte brechen wie normaler Fliesstext; breite Tabellen scrollen IN der Box,
   statt die Seite seitwärts zu schieben. */
.nachricht-inhalt.kampfbericht { white-space: normal; overflow-x: auto; }

/* Aktions-Schaltflächen: Links in Button-Optik (z. B. Startseite). */
/* Stand je Bereich auf der Startseite. Bewusst eine schlichte Liste
   ohne Aufzählungszeichen und ohne Farbcodierung: Was frei ist, sagt der TEXT
   („Nichts im Bau.“), nicht eine Einfärbung — der leicht gedimmte Ton ist nur
   Zugabe für Sichtnutzer. */
ul.stand { list-style: none; padding: 0; margin: .5rem 0 1.5rem; }
ul.stand li { padding: .3rem 0; border-bottom: 1px solid var(--rand); }
ul.stand li:last-child { border-bottom: 0; }
ul.stand a { margin-left: .5rem; }
ul.stand .stand-frei { color: var(--text-gedimmt); }
ul.stand .stand-frei strong { color: var(--text); }

/* Erste Schritte. Gleiche Haltung wie beim Stand: Der Zustand steht im
   TEXT (in der Überschrift: „– erledigt“ / „– jetzt dran“), die Auszeichnung
   hier ist nur Zugabe für Sichtnutzer. Die Nummer steht in der Überschrift. */
.tutorial-etappe { padding: .2rem 0 .6rem; }
.tutorial-etappe > h2 { font-size: 1.15rem; margin-bottom: .3rem; }
/* Die Etappen-Überschriften stecken in je einem <div>, darum trifft
   „main > h2:first-of-type“ (kein Strich über der ersten h2) auf /tutorial
   erst „Anzeige“ ganz unten. Hier umgekehrt: die erste Etappe ohne Strich,
   „Anzeige“ nach den Etappen wieder mit. */
main > div.tutorial-etappe:first-of-type > h2 { border-top: 0; padding-top: 0; margin-top: 1.25rem; }
main > .tutorial-etappe ~ h2 { border-top: 1px solid var(--rand); padding-top: .75rem; margin-top: 2rem; }
.tutorial-etappe p { margin: .2rem 0; }
/* Erledigte Etappen etwas zurückgenommen — die offenen sind das Ziel. */
.tutorial-erledigt > h2 { color: var(--text-gedimmt); }
/* Teilziele der aktuellen Etappe. Bewusst schlicht: Der Zustand steht
   als Klartext davor („Erledigt:“ / „Offen:“), die Einrückung ist nur Optik. */
.teilziele { margin: .3rem 0 .3rem 1.2rem; padding: 0; }
.teilziele > li { padding: .1rem 0; }
/* Farbe kommt ZUSAETZLICH zum Klartext („Erledigt:“ / „Offen:“), nie statt
   seiner (WCAG 1.4.1) — wer Farben nicht unterscheiden kann oder mit eigenem
   Stylesheet liest, verliert dadurch keine Auskunft. Beide Toene sind als
   TEXTfarbe auf 4,5:1 geprueft (scratchpad/kontrast.php), nicht nur als Rand. */
.teilziel-ok   > strong { color: var(--erfolg-rand); }
.teilziel-offen > strong { color: var(--gefahr); }

/* Ausklappbare Zwischenziele in Ziel-Zeile und Randkasten. Zugeklappt bleibt
   nur die Zahl stehen — das Feld soll schlank bleiben. */
.ziel-zeile > details { margin-top: .35rem; }
.ziel-zeile > details > summary,
.rand-kasten .teilziele-auf > summary { cursor: pointer; font-weight: 600; }
.ziel-zeile .teilziele { font-size: .95rem; }
/* „ausblenden“ sitzt mitten in der Zeile — ein Formular, damit die Aenderung
   ueber POST mit CSRF laeuft, aber es soll wie die Links daneben aussehen. */
.ziel-aus { display: inline; margin: 0; }
.ziel-aus button {
    background: none;
    border: 0;
    padding: 0;
    color: var(--link);
    text-decoration: underline;
    cursor: pointer;
    font: inherit;
}
/* Markierung in --link, NICHT --akzent: --akzent bleibt im Dunkelmodus beim
   dunklen #1d4ed8 und verschwindet dort fast im Hintergrund, --link hellt auf
   (#8ab4f8). Barrierefrei hängt daran nichts — der Zustand steht im Text. */
.tutorial-etappe.tutorial-aktuell { padding-left: .6rem; border-left: 3px solid var(--link); }
/* Die Erklärung einer Etappe in Ziel-Zeile und Randkasten: zugeklappt, Absätze knapp. */
.etappe-erklaerung { margin-top: .35rem; }
.etappe-erklaerung > summary { cursor: pointer; font-weight: 600; }
.etappe-erklaerung p { margin: .2rem 0; }

.aktionen { display: flex; flex-wrap: wrap; gap: .75rem; }
/* Links in Knopf-Optik: exakt dieselbe Form wie ein echter <button>, damit auf
   der Startseite nicht zwei Sorten Knopf nebeneinanderstehen. */
.knopf { display: inline-block; padding: .5rem 1.25rem; background: var(--akzent); color: var(--akzent-text); text-decoration: none; font-weight: 600; border-radius: 6px; box-shadow: 0 1px 2px var(--schatten); }
.knopf:visited { color: var(--akzent-text); }
.knopf:hover { filter: brightness(1.12); }
.knopf-zweit { background: var(--aktion-zweit); }

/* Entwicklungs-Hinweis (z. B. lokaler Reset-Link statt E-Mail-Versand). */
.devhinweis { padding: .75rem 1rem; margin-bottom: 1rem; background: var(--hinweis-bg); border: 1px solid var(--hinweis-rand); border-left: 5px solid var(--hinweis-rand); border-radius: 6px; }

/* Nur für Screenreader: visuell versteckt, aber von JAWS vorgelesen
   (z. B. die ausgeschriebene Koordinate "Galaxie 2, System 14, ..."). */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* AKTUELLES ZIEL als eine Zeile ueber dem Inhalt.

   Sie vertritt den Aufgaben-Kasten aus der rechten Randspalte auf allen Schirmen
   unter 110rem — dort gibt es die Spalte nicht, und die Fuehrung waere sonst
   auf jedem normalen Laptop unsichtbar.

   Ab 110rem verschwindet die Zeile wieder: Dort steht der Kasten, und beides
   zugleich waere fuer eine Sprachausgabe eine doppelte Ansage. */
.ziel-zeile {
    margin: 0 0 1rem;
    padding: .5rem .85rem;
    background: var(--bg-karte);
    border: 1px solid var(--rand);
    border-left: 4px solid var(--link);
    border-radius: 6px;
    font-size: .95rem;
}
@media (min-width: 110rem) {
    :root[data-rand="an"] .ziel-zeile { display: none; }
}

/* Auf schmalen Schirmen nur fuer den Screenreader, ab 45rem sichtbar.
   Fuer Beiwerk, das den Satz vollstaendig macht, aber auf dem Handy eine ganze
   Zeile kostet — heute das „Angemeldet als“ der Kontozeile und das Label
   „Welt“ vor der Auswahlliste im Welt-Wechsler. Unterschied zu
   .sr-only: Das versteckt IMMER, hier geht es um einen Platzkonflikt, den es nur
   auf kleinen Schirmen gibt. */
.nur-breit {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}
@media (min-width: 45rem) {
    .nur-breit {
        position: static;
        width: auto; height: auto;
        margin: 0;
        overflow: visible;
        clip: auto;
    }
}

/* Galaxiekarte: System-Tabelle. */
/* TABELLEN. Tabellen sind in diesem Spiel der Hauptinhalt — Gebaeude, Schiffe,
   Flotten, Rangliste, Imperium. Nackt (duenne graue Trennlinien, sonst nichts)
   verschwimmen sie auf einer Seite mit 27 Tabellen zu einer grauen Wand.

   Drei Mittel, alle rein optisch:
   - Der Kopf bekommt eine FLAECHE und bleibt beim Scrollen oben stehen. Bei
     einer Tabelle mit 25 Zeilen weiss man sonst in der Mitte nicht mehr, welche
     Spalte was ist.
   - Jede zweite Zeile leicht getoent (--zebra), damit das Auge die Zeile haelt.
     Der Ton ist so schwach, dass er den Textkontrast nicht messbar aendert.
   - Die Zeile unter dem Mauszeiger hebt sich ab.

   Fuer JAWS aendert sich nichts: Struktur, Reihenfolge und scope-Angaben bleiben
   unberuehrt, es kommt kein Element und kein Tab-Stopp hinzu. */
table { border-collapse: collapse; width: 100%; margin: 1rem 0; }
caption {
    text-align: left;
    font-weight: 600;
    margin-bottom: .5rem;
    color: var(--text);
}
th, td { text-align: left; padding: .45rem .7rem; border-bottom: 1px solid var(--rand); vertical-align: top; }

thead th {
    background: var(--bg-tabellenkopf);
    border-bottom: 2px solid var(--rand-stark);
    font-size: .9rem;
    letter-spacing: .02em;
    /* Mitlaufender Kopf. Er klebt direkt UNTER der mitlaufenden Menueleiste
       (--kopf-h; 0, wenn die Leiste mitscrollt), sonst laege er darunter.
       Nur dort, wo die Tabelle ueberhaupt hoch genug ist, um das zu merken. */
    position: sticky;
    top: var(--kopf-h);
    z-index: 1;
}
/* In den seitwaerts scrollenden Containern wuerde `sticky` am oberen Rand des
   Containers kleben statt am Fenster — dort bringt es nichts und kann bei
   ueberlappenden Raendern flackern. */
.breit-scroll-text thead th { position: static; }
/* Dasselbe gilt fuer JEDEN Container mit overflow (Imperiums-Matrix,
   Galaxie-Tabelle, Kampfbericht): Dort zaehlt `top` ab der Oberkante des
   Containers, nicht ab dem Fenster. Mit --kopf-h rutschte der Kopf darum um
   die Hoehe der Menueleiste in die erste Zeile (gemessen auf /imperium bei
   1024 px: 25 px Ueberlappung). `top: 0` ist dort, was es vorher war — wirkungslos,
   aber harmlos. Ein NEUER Scroll-Container mit Tabellen gehoert hier dazu. */
.breit-scroll thead th,
.nachricht-inhalt thead th { top: 0; }

tbody tr:nth-child(even) { background: var(--zebra); }
tbody tr:hover { background: var(--eigen-bg); }
/* Tabellen, die Unterkarten filtern (Neubau, Werft): Die weggefilterten Zeilen
   stehen versteckt im Dokument und zählten sonst beim Zebra mit — zwei gleich
   getönte Zeilen übereinander. Gezählt werden nur die sichtbaren. Browser ohne
   `:nth-child(… of …)` behalten das einfache Zebra. Die Hover-Regel steht
   danach mit gleichem Gewicht, damit sie auch auf getönten Zeilen greift. */
@supports selector(:nth-child(2n of p)) {
    tbody > tr[data-filter]:nth-child(even) { background: transparent; }
    tbody > tr[data-filter]:nth-child(even of :not([hidden])) { background: var(--zebra); }
    tbody > tr[data-filter]:hover:not([hidden]) { background: var(--eigen-bg); }
}
tbody th[scope="row"] { font-weight: 600; }

/* Aktions-Zellen: Grund und Knopf nebeneinander.

   Ein <form> ist ein Block und drueckt den Knopf darum IMMER unter den
   Klartext-Grund — auch dann, wenn die Spalte 466 px breit ist und beides
   locker in eine Zeile passt. Gemessen am Bau-Katalog auf 3425 px: Diese eine
   Zeile Umbruch je Gebaeude machte den Block 2269 statt 1353 px hoch, die
   mittlere Zeilenhoehe 73 statt 50 px.

   Die Einschraenkung `:not(:has(...))` haelt das auf Ein-Knopf-Formulare
   begrenzt: Heute sind das alle 509 Formulare in Zellen, aber ein spaeteres
   Formular MIT Eingabefeld (etwa eine Stueckzahl) soll seinen eigenen Block
   behalten. Reicht der Platz nicht, bricht es ohnehin normal um. */
td form:not(:has(input:not([type="hidden"]), select, textarea)),
th form:not(:has(input:not([type="hidden"]), select, textarea)) {
    display: inline-block;
    margin: 0;
    vertical-align: baseline;
}
td .grund { margin-right: .5rem; }
/* Eigene Zeile (Galaxiekarte) sticht ueber Zebra UND Hover hinweg durch. Die
   Information selbst steht wie immer im Text daneben, die Faerbung ist Zugabe. */
tr.eigen, tbody tr.eigen:nth-child(even) { background: var(--eigen-bg); }
tr.eigen td, tr.eigen th { font-weight: 600; }

/* === Galaxie-Übersicht: Sternkarte + Sonnenfarben ===========================
   Die Sternfarben stehen ABSICHTLICH als feste Werte hier und nicht in den
   :root-Blöcken: ein roter Zwerg ist in beiden Modi rot, es gibt also keine
   Hell/Dunkel-Variante zu pflegen (der Kommentar ganz oben gilt nur für
   Variablen, die sich zwischen den Modi unterscheiden). Jeder Punkt trägt
   zusätzlich einen Rand — sonst verschwände die weiße Klasse A im Hellmodus.

   Der Punkt ist reine Optik: leeres <span>, per aria-hidden aus dem
   Screenreader genommen, mit title für den Hover. Die Information selbst
   steht immer als Buchstabe/Wort daneben — Farbe ist nie das einzige Signal. */
.sonnenpunkt {
    display: inline-block;
    width: .7em; height: .7em;
    margin-right: .35em;
    border-radius: 50%;
    border: 1px solid var(--rand-stark);
    vertical-align: middle;
}
.sonne-O { background: #4a7dff; }   /* blau */
.sonne-B { background: #8fbcff; }   /* blauweiß */
.sonne-A { background: #f2f6ff; }   /* weiß */
.sonne-F { background: #ffeeb0; }   /* gelbweiß */
.sonne-G { background: #ffd23f; }   /* gelb */
.sonne-K { background: #ff9f43; }   /* orange */
.sonne-M { background: #e8523f; }   /* rot */

/* Legende = zugleich Klassen-Verteilung. Mehrspaltig, damit sieben Zeilen
   nicht die halbe Seite füllen. */
.sonnen-legende { list-style: none; margin: .5rem 0 1rem; padding: 0;
    display: grid; grid-template-columns: repeat(auto-fit, minmax(16ch, 1fr)); gap: .1rem .75rem; }

/* Das Raster selbst: 20 Spalten passen nicht in die 70ch-Lesespalte, darum
   liegt die Tabelle in .breit-scroll (scrollt seitwärts, Seite bleibt ruhig). */
.sternkarte { font-size: .85rem; width: auto; }
.sternkarte th, .sternkarte td { padding: .1rem .25rem; border: 1px solid var(--rand); text-align: center; white-space: nowrap; }
.sternkarte thead th { font-weight: 400; color: var(--text-gedimmt); }
.sternkarte tbody th[scope="row"] { color: var(--text-gedimmt); font-weight: 400; }
.sternkarte td.rz { min-width: 5.5ch; }
.sternkarte a { text-decoration: none; }
.sternkarte a:hover { text-decoration: underline; }
/* Eigene Systeme: die etablierte tr.eigen-Regel greift hier nicht, im Raster
   ist die eigene Welt eine ZELLE und keine Zeile. */
.sternkarte td.eigen { background: var(--eigen-bg); }
/* Bewohnt (fremder Spieler) = fett statt eigener Farbe — der Klartext steht
   im .sr-only-Zusatz, die Auszeichnung ist nur die schnelle Optik. */
.sternkarte td.bewohnt { font-weight: 700; }
.klassenkuerzel { color: var(--text-gedimmt); font-size: .8em; margin-left: .15em; }
.komet-marke { color: var(--gefahr); font-weight: 700; margin-left: .1em; }

/* Ressourcen-Symbol: ein gezeichnetes Strich-Symbol IM Text (SVG-Sprite in
   templates/teil/ressourcen-symbole.php), in Textfarbe und Schriftgrösse — so
   bleibt jede Kosten- und Beutezeile einzeilig und das Symbol passt zu jedem
   Farbschema. Feste Kastenbreite, damit untereinander stehende Zeilen bündig
   ausrichten; der Kasten ist inline-block ohne Zeilenhöhe, damit er die Zeile
   nicht höher macht als der Text. */
.ress-symbol {
    display: inline-block;
    width: 1.5em;            /* feste Kastenbreite: die Namen darunter fluchten */
    margin-right: .1em;
    line-height: 0;
    vertical-align: -.2em;   /* Symbol sitzt auf der Grundlinie des Namens */
    text-align: left;
}
.ress-symbol svg {
    width: 1.25em;
    height: 1.25em;
}

/* Ressourcen-Leiste (Layout, alle Seiten außer /planet): kompakt & aufklappbar. */
.ressourcen-leiste { max-width: 70ch; margin-inline: auto; padding: 0 1.25rem; }
/* ===== KARTEN ==============================================================
   Alles, was als abgesetzter Kasten auf der Seite steht, teilt sich ab hier EINE
   Form: Kartenfarbe, 8px Radius, feiner Rand, flacher Schatten. Ohne diese
   gemeinsame Form haette jede Stelle ihre eigene Zeile mit 4px und ohne
   Schatten, und das Spiel saehe an jeder Ecke ein bisschen anders aus.

   Der Schatten ist bewusst flach (1px/3px): Er soll die Karte vom Grund heben,
   nicht schweben lassen. */
/* Gleiche Ausrichtung und Breite wie der Welt-Wechsler darüber: Beide sind
   Werkzeuge über dem Inhalt und sollen als EINE Leiste gelesen werden. Stünde
   der Wechsler linksbündig und die Ressourcen-Leiste zentriert, begänne auf
   1440 px die eine bei 0, die andere bei 411 px. */
.ressourcen-leiste { max-width: 70ch; margin: 0; }
.ressourcen-leiste > details { border: 1px solid var(--rand); border-radius: 8px; background: var(--bg-karte); box-shadow: 0 1px 3px var(--schatten); padding: .25rem .85rem; margin: .5rem 0 0; }
.ressourcen-leiste summary { cursor: pointer; font-weight: 600; }
.ressourcen-leiste table { margin: .5rem 0; font-size: .9rem; }
.ressourcen-leiste th, .ressourcen-leiste td { padding: .15rem .5rem; }

/* Bau-/Forschungs-Countdown: wird in-place aktualisiert (kein Cursor-Sprung). */
.countdown-wert { font-variant-numeric: tabular-nums; }

/* Fortschrittsleiste am laufenden Bau-Auftrag (Welt-Seite): reine Optik neben
   der Restzeit, aria-hidden. Schmal und flach, damit sie in der Zeile bleibt;
   countdown.js setzt die Breite des Balkens sekuendlich. */
.bau-fortschritt {
    display: inline-block;
    width: 7rem;
    max-width: 40%;
    height: .55rem;
    vertical-align: middle;
    border: 1px solid var(--rand-stark);
    border-radius: 4px;
    background: var(--bg-einschub);
    overflow: hidden;
}
.bau-fortschritt-balken {
    display: block;
    height: 100%;
    background: var(--akzent);
    transition: width 1s linear;
}
/* Aufleuchten bei Fertigstellung: countdown.js gibt dem Countdown und seiner
   Zeile die Klasse — die Erfolgsfarbe pulst dreimal auf und bleibt dann als
   Fettschrift am Wort „Fertig“ stehen. Wer Bewegung abbestellt hat, bekommt
   die Farbe ohne Pulsen. */
@keyframes aufleuchten {
    0%, 100% { background-color: transparent; }
    35%      { background-color: var(--erfolg-bg); }
}
.ist-fertig { animation: aufleuchten 1.4s ease-in-out 3; }
.laufzeit.ist-fertig .countdown-wert { font-weight: 700; color: var(--erfolg-rand); }
@media (prefers-reduced-motion: reduce) {
    .bau-fortschritt-balken { transition: none; }
    .ist-fertig { animation: none; background-color: var(--erfolg-bg); }
}
/* Abbrechen-Knopf am Eintrag der Bau-Schlange: in derselben Zeile wie Name und
   Zeit, damit die Liste nicht doppelt so hoch wird. Bricht auf schmalen
   Schirmen mit der Zeile um. */
.bau-schlange form.abbruch { display: inline; margin: 0 0 0 .5rem; }

/* Bilder der Himmelskoerper (templates/teil/planetenbild.php). Im KOPF der
   Welt-Seite rechts neben Titel und Kopfdaten wie das Foxy-Bild, unter 40rem weg
   — dort ist jeder Bildschirm-Zentimeter fuer den Text. INLINE (Systemansicht)
   klein vor dem Namen: Sonne neben der Ueberschrift, Planet, Mond, Guertel. Die
   Oberflaeche (.dreht) wandert um genau eine Periode (100 Einheiten) nach links
   und beginnt nahtlos von vorn; Guertel, Kometenkern und Sonnenkorona kreisen
   (.kreist). Beides steht unter prefers-reduced-motion still. */
.planet-bild { overflow: visible; }
.planet-bild-kopf { float: right; width: 120px; height: 120px; margin: 0 0 .5rem 1rem; }
@media (max-width: 40rem) { .planet-bild-kopf { display: none; } }
.planet-bild-inline { vertical-align: middle; margin-right: .35rem; }
@keyframes planet-drehen { to { transform: translateX(-100px); } }
@keyframes planet-kreisen { to { transform: rotate(360deg); } }
.planet-bild .dreht { animation: planet-drehen 80s linear infinite; }
.planet-bild .kreist { transform-box: view-box; transform-origin: 60px 60px; animation: planet-kreisen 240s linear infinite; }
.planet-bild .kreist-komet { transform-origin: 80px 46px; animation-duration: 120s; }
@media (prefers-reduced-motion: reduce) {
    .planet-bild .dreht, .planet-bild .kreist { animation: none; }
}

/* Kopf der Welt-Seite (planet/uebersicht.php) knapp — Codex-Review 27.09.2026:
   Auf dem Handy begannen die Registerkarten erst am unteren Bildschirmrand.
   Reihenfolge, Überschriften und die Beschreibungsliste des Betriebs bleiben,
   nur die Abstände schrumpfen: Bauplätze in einer Zeile; im Betrieb stehen
   Begriff und Wert als EIN fließender Satz („Energie: 70.486 verbraucht /
   192.126 erzeugt“) — in schmalen Spalten brach jeder Wert zweizeilig um, auf
   dem iPhone kostete der Betrieb so 184 px. Auf der Braillezeile steht damit
   je Angabe eine Zeile. Ab 60rem fließen die drei Paare nebeneinander. */
.planet-kopf { margin: 0 0 .25rem; }
h2.knapp { margin-top: 1rem; padding-top: .5rem; margin-bottom: .4rem; }
main > h2.knapp:first-of-type { margin-top: .75rem; }
dl.betrieb { margin: 0; }
dl.betrieb > div { margin: 0 0 .15rem; }
dl.betrieb dt, dl.betrieb dd { display: inline; margin: 0; }
dl.betrieb dt { font-weight: 600; }
dl.betrieb dt::after { content: ":"; }
@media (min-width: 60rem) {
    dl.betrieb { display: flex; flex-wrap: wrap; gap: .25rem 2rem; }
    dl.betrieb > div { margin: 0; }
}
/* Ressourcen und Vorkommen nebeneinander (Marc, 27.09.2026: „auf eine Zeile
   bekommen“): je Überschrift und Klappe ein Paar, ein aufgeklapptes nimmt die
   volle Breite (seine Tabelle braucht sie). Unter 40rem stehen nur die beiden
   Klappen in der Zeile: Die Überschriften bleiben für JAWS (H-Taste), sehend
   sind sie versteckt — die Klappen sagen selbst, was darin ist. Kein Symbol
   statt Text: Auf dem Handy gibt es kein Darüberfahren, das den Namen zeigte. */
.klapp-reihe { display: flex; flex-wrap: wrap; gap: 0 1rem; }
.klapp-paar { flex: 1 1 10rem; min-width: 0; }
.klapp-paar:has(> details[open]) { flex-basis: 100%; }
.klapp-paar > details.abschnitt { margin: .4rem 0 0; }
@media (max-width: 40rem) {
    .klapp-reihe { gap: 0 .5rem; margin-top: .75rem; }
    .klapp-paar > h2 {
        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;
    }
    .klapp-paar > details.abschnitt { margin: 0; }
}

/* Flotten-Mission: Ziel-Vorschau (Distanz/Flugzeit/Treibstoff). */
.vorschau { border: 1px solid var(--rand); border-radius: 8px; background: var(--bg-karte); box-shadow: 0 1px 3px var(--schatten); padding: .5rem .85rem; margin: .75rem 0; }
.vorschau .kennwerte { margin: .35rem 0; }
.vorschau .kennwerte dt { font-weight: 600; }
.vorschau .kennwerte dd { margin: 0 0 .35rem 1.25rem; }

/* Begründungen/abgeschwächte Zeilen (Klartext bleibt das Signal, Farbe nur Zugabe). */
.grund { color: var(--text-gedimmt); font-size: .9rem; }
.nicht-baubar > th, .nicht-baubar > td,
.inaktiv > th, .inaktiv > td { color: var(--text-abgeschaltet); }

/* Ausklappbare Körper (HTML-<details>, ohne JS): Planet je Zeile, Monde je Zelle. */
details.objekt > summary { cursor: pointer; font-weight: 600; }
details.mond { margin-bottom: .25rem; }
details.mond > summary { cursor: pointer; }
details.objekt[open] > summary,
details.mond[open] > summary { margin-bottom: .35rem; }
.objektdetails { margin: 0; font-weight: 400; }
.objektdetails dt { font-weight: 600; }
.objektdetails dd { margin: 0 0 .2rem 1.25rem; }
.aktionen-platzhalter { margin: .25rem 0 0; color: var(--text-gedimmt); }

/* Schiffs-Datenblatt (/schiff) + Klassen-Hinweis hinter Schiffsnamen. */
.schiff-klasse { color: var(--text-gedimmt); font-weight: 400; font-size: .9rem; }
/* minmax(0, …) statt nacktem max-content/1fr: sonst darf keine der beiden Spalten
   unter ihre Wunschbreite schrumpfen, und auf einem Handy schob die Kennwerte-
   Liste der Datenblätter die Seite quer (gemessen: 477 statt 375 px). */
dl.kennwerte { display: grid; grid-template-columns: minmax(0, max-content) minmax(0, 1fr); gap: .15rem 1rem; margin: .25rem 0 1rem; }
dl.kennwerte dt { font-weight: 600; }
/* Umbruch notfalls auch innerhalb eines Wertes: Zusätze wie „420 (Durchschlag –
   tech-fest)“ ragten auf schmalen Fenstern sonst über den Rand hinaus. */
dl.kennwerte dd { margin: 0; overflow-wrap: anywhere; }

/* Forschungs-Voraussetzungen (Schiffs-/Gebäude-Datenblatt):
   grün = erfüllt, rot = fehlt — NUR Zugabe, der Klartext („erfüllt“/„fehlt
   noch“) steht in jeder Zeile und ist das eigentliche Signal (JAWS). */
.voraussetzungen { margin: 0; padding-left: 1.25rem; }
.voraussetzung-erfuellt { color: var(--erfolg-rand); }
.voraussetzung-fehlt { color: var(--gefahr); }

/* Einklappbare Groß-Abschnitte/Gruppen (Planet-Seite): standardmäßig
   ZUGEKLAPPT. Die Überschrift steht IMMER AUSSERHALB des details — eine h2 im
   <summary> liest JAWS nur als Schalter, und sie verschwindet dadurch aus der
   Überschriften-Navigation. */
/* Aufklappbare Abschnitte. Die Zusammenfassungszeile ist der Knopf — sie
   bekommt eine eigene Flaeche, damit sichtbar ist, wo man klickt, und einen
   Zustandswechsel beim Aufklappen. Zugeklappt sieht sie aus wie eine Leiste,
   aufgeklappt wie der Kopf eines Kastens.

   Kein Umbau am Markup: <details>/<summary> bleiben, wie sie sind — bewusst
   KEINE JS-Klappmenues (JAWS). */
details.abschnitt { margin: .6rem 0; }
details.abschnitt > summary,
.rand-kasten > summary,
.ressourcen-leiste > details > summary,
.foxy-kasten > details > summary {
    cursor: pointer;
    font-weight: 600;
    padding: .4rem .6rem;
    margin: 0 -.6rem;
    border-radius: 6px;
}
details.abschnitt > summary { background: var(--bg-karte); border: 1px solid var(--rand); margin: 0; }
details.abschnitt[open] > summary {
    background: var(--bg-tabellenkopf);
    border-radius: 6px 6px 0 0;
    border-bottom-color: var(--rand-stark);
}
details.abschnitt[open] > *:not(summary) {
    border: 1px solid var(--rand);
    border-top: 0;
    border-radius: 0 0 6px 6px;
    padding: .1rem .8rem .5rem;
    background: var(--bg-karte);
}
/* Der Mauszeiger zeigt, dass die Zeile anfassbar ist. */
summary:hover { background: var(--bg-tabellenkopf); }

/* Einstellungen: Radio-/Checkbox-Zeilen stehen nebeneinander, nicht unter dem
   Label — die globale label{display:block}-Regel bricht sie sonst um. */
fieldset p > input[type="radio"] + label,
/* Checkbox/Radio: Beschriftung NEBEN das Kästchen, nicht darunter.
   `label { display: block }` weiter oben ist für Textfelder richtig (Beschriftung
   über dem Feld) — bei einem Kästchen kippt genau diese Regel die Beschriftung
   in die nächste Zeile.
   Die Regel darf NICHT an <fieldset> gebunden sein: Auf der Login-Seite
   („Angemeldet bleiben“) gibt es keins, dort stünde die Beschriftung sonst unter
   dem Kästchen. Darum ohne fieldset-Bindung und mit dem Geschwister-Kombinator
   in beiden Reihenfolgen — manche Formulare setzen die Beschriftung zuerst. */
input[type="checkbox"] + label,
input[type="radio"] + label,
label:has(> input[type="checkbox"]),
label:has(> input[type="radio"]) {
    display: inline;
    font-weight: 400;
}

/* ----------------------------------------------------------------------- Foxy
   Die KI-Spielhilfe. Der Kasten steht unter JEDER Seite, deshalb hält er sich
   optisch zurück: eine dünne Trennlinie, kein Rahmen, keine Farbfläche. */
.foxy-kasten { margin-top: 2rem; border-top: 1px solid var(--rand); padding-top: .75rem; }
.foxy-kasten > details > summary { cursor: pointer; font-weight: 600; }
.foxy-kasten textarea { max-width: 100%; }

/* Antwort im Seitenkasten: Foxys Text bekommt etwas Luft, damit er sich vom
   Formular darunter absetzt — ohne Kasten-im-Kasten. */
.foxy-du { margin: .5rem 0 .25rem; }
.foxy-foxy { margin: 0 0 .75rem; }

/* Gesprächsverlauf auf /foxy. Bewusst eine Liste (JAWS: mit L durchgehen statt
   zwanzig Überschriften) — die Nummern selbst sagen nichts, darum ausgeblendet. */
.foxy-verlauf { list-style: none; margin: 0; padding: 0; }
.foxy-verlauf > li { margin: 0 0 1rem; padding-left: .75rem; border-left: 3px solid var(--rand); }
.foxy-verlauf > li.foxy-foxy { border-left-color: #f4652a; }

/* Der Preis einer Antwort steht klein dahinter — Information, kein Hinweis. */
.foxy-kosten { font-size: .85em; opacity: .75; }

/* „War hilfreich“ / „War nicht hilfreich“: klein unter der Antwort. Die Wahl
   zeigt ein kräftiger Rand — kein Zeichen per CSS-content, das JAWS mitliest. */
.foxy-bewertung { margin: .4rem 0 0; display: flex; flex-wrap: wrap; gap: .5rem; }
.foxy-bewertung button { font-size: .9em; }
.foxy-bewertung button[aria-pressed="true"] { font-weight: 700; border-width: 2px; border-style: solid; }

/* Das Fuchsbild ist Dekoration: schwebt neben dem Einleitungstext und
   verschwindet auf schmalen Bildschirmen, wo der Text den Platz braucht. */
.foxy-bild { float: right; margin: 0 0 .5rem 1rem; }
@media (max-width: 40rem) { .foxy-bild { display: none; } }

/* Foxys Werkzeug-Anlage: die Zahlen im Wortlaut, neben ihrem Text (FoxyAnlage).
   Seit 1.83.4 echtes HTML statt <pre>: Titel, Absätze, Listen und Tabellen mit
   Spaltenköpfen. Die Tabellen scrollen in .breit-scroll-text seitwärts (ohne
   eigenen Tab-Stopp); der Strich links hält den Block zusammen, damit klar
   bleibt, wo Foxys Text endet und die Rechnung des Spielcodes beginnt. */
.foxy-anlage {
    margin: .8em 0;
    padding: .1em 0 .1em .8em;
    font-size: .95em;
    line-height: 1.45;
    border-left: 3px solid currentColor;
}
.foxy-anlage-titel { margin: .2em 0 .4em; font-weight: bold; }
.foxy-anlage p, .foxy-anlage ul { margin: .3em 0; }
.foxy-anlage table { margin: .5em 0; }

/* ABSCHNITTS-SPRUNGMARKEN — die Leiste unter der h1, die zu den h2 der Seite
   fuehrt (HilfeController::mitSprungmarken). Die Gebäude-Seite hatte bis 1.82
   auch eine; dort gliedern jetzt Registerkarten (.karten weiter oben).

   Warum sie Form braucht: Ohne Auszeichnung stehen dort acht bis zwanzig
   nackte Links in einer Zeile, und der Leser haelt sie fuer Fliesstext. Als
   Chip-Reihe ist auf
   einen Blick klar, dass es eine Navigation ist. Auf einem 390er-Handy bricht
   sie um, statt zu scrollen: Eine waagerecht scrollende Leiste versteckt genau
   die hinteren Abschnitte, wegen derer man sie ueberhaupt benutzt. */
/* Der Klappkasten drumherum (Hilfeseiten): zugeklappt eine Zeile, aufgeklappt
   die Chip-Reihe. Bewusst dezent — er ist Werkzeug, nicht Inhalt. */
.abschnitt-sprung { margin: .25rem 0 1.25rem; border-bottom: 1px solid var(--rand); }
.abschnitt-sprung > summary {
    cursor: pointer;
    padding: .25rem 0 .6rem;
    font-size: .95em;
}
.abschnitt-sprung[open] > summary { font-weight: 700; }
.abschnitt-sprung > .abschnitt-nav { border-bottom: 0; margin-top: 0; }

.abschnitt-nav {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .5rem;
    margin: .25rem 0 1.25rem;
    padding-bottom: .9rem;
    border-bottom: 1px solid var(--rand);
}
.abschnitt-nav a {
    display: inline-block;
    padding: .2rem .7rem;
    border: 1px solid var(--rand);
    border-radius: 999px;
    text-decoration: none;
    font-size: .95em;
}
.abschnitt-nav a:hover,
.abschnitt-nav a:focus-visible { text-decoration: underline; }

/* Beim Sprung soll die Ueberschrift nicht am oberen Rand kleben — sonst liest
   man mitten im ersten Satz weiter und weiss nicht, ob man richtig ist.
   --kopf-frei: Platz fuer die mitlaufende Menueleiste (0, wenn sie mitscrollt). */
main h2[id] { scroll-margin-top: calc(var(--kopf-frei) + 1.5rem); }

/* FUSS JEDER HILFE-THEMENSEITE: Uebersicht, ein Thema zurueck, eines weiter.
   Waagerecht, weil es drei kurze Links sind — untereinander saehe es nach
   Inhaltsverzeichnis aus und waere wieder der Block, den es ersetzt. */
.hilfe-weiter {
    list-style: none;
    margin: .5rem 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.4rem;
}
.hilfe-weiter > li { margin: 0; max-width: none; }

/* ===== WISCHLEISTE: Hauptnavigation auf schmalen Schirmen ===================
   Unter 64rem steht die Navigation in EINER Zeile und laesst sich seitwaerts
   wischen, statt in vier Zeilen umzubrechen. Auf 375 px faellt der Kopf damit
   von rund 205 auf rund 95 px; die Seitenueberschrift beginnt im oberen
   Sechstel statt im oberen Drittel des Bildschirms.

   Fuer Tastatur und Screenreader aendert sich nichts: dieselbe <ul>, dieselben
   Links in derselben Reihenfolge; einen fokussierten Link rueckt der Browser
   von selbst ins Bild. Die Blaetter-Pfeile (js/nav-strip.js) sind aria-hidden
   und ohne Tab-Stopp — reine Hilfen fuer Maus und Finger.

   Die Scrollleiste ist ausgeblendet: Der Ueberlauf zeigt sich am angeschnittenen
   letzten Punkt und an den Pfeilen; eine Scrollleiste unter dem Menue saehe
   nach Fehler aus. */
@media (max-width: 63.99rem) {
    .nav-haupt {
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scroll-snap-type: x proximity;
        scrollbar-width: none;
        padding-bottom: .15rem;
        -webkit-overflow-scrolling: touch;
    }
    .nav-haupt::-webkit-scrollbar { display: none; }
    .nav-haupt > li {
        flex: 0 0 auto;
        white-space: nowrap;
        scroll-snap-align: start;
    }
    /* Die Pille der aktuellen Seite ohne Ausgleichs-Margin — in der einen
       Zeile wuerde sie sonst am Rand angeschnitten. */
    header nav a[aria-current="page"] { margin: 0; }
}
.nav-wischbar {
    display: flex;
    align-items: center;
    gap: .35rem;
}
.nav-wischbar > .nav-haupt { flex: 1 1 auto; min-width: 0; }
.nav-pfeil {
    flex: 0 0 auto;
    padding: 0 .55rem;
    line-height: 1.5;
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--text);
    background: var(--bg-karte);
    border: 1px solid var(--rand-stark);
    border-radius: 999px;
    box-shadow: none;
}
.nav-pfeil[hidden] { display: none; }

/* ===== WERKZEUG-ZEILE: Welt-Wechsler und Ressourcen-Leiste nebeneinander ====
   EINE Zeile statt zwei Kästen untereinander — auf dem Handy kostete jeder
   Kasten eine volle Zeile für ein paar Wörter. Die aufgeklappte
   Ressourcen-Leiste legt sich als Feld ÜBER die Seite (absolut zur Zeile),
   statt sie nach unten zu schieben: Nichts springt, und der Inhalt bleibt, wo
   er war. Für JAWS ist das egal — wo das Feld auf dem Bildschirm liegt,
   spielt für den virtuellen Cursor keine Rolle.

   Kein Umbruch (nowrap): Wird es eng, SCHRUMPFT die Auswahlliste des
   Welt-Wechslers (ihr voller Text steht im Klappfeld und wird ohnehin ganz
   vorgelesen); Pfeile und Ressourcen-Knopf behalten ihre Breite. Mit Umbruch
   rutschte der Ressourcen-Knopf bei jedem langen Weltnamen in eine eigene
   Zeile. */
.werkzeuge {
    /* Derselbe Seitenrand wie <main>: Die Zeile stand sonst am Bildschirmrand,
       links vor der Überschrift und rechts ohne Luft. Als Variable, weil das
       aufgeklappte Ressourcen-Feld (unten) denselben Rand einhalten muss. */
    --wz-rand: 1.25rem;
    position: relative;
    display: flex;
    flex-wrap: nowrap;
    gap: .5rem;
    align-items: center;
    margin: .5rem 0 0;
    padding-inline: var(--wz-rand);
}
.werkzeuge:not(:has(details, .welt-wechsler)) { display: none; }
/* OHNE JavaScript steht der Knopf „Wechseln“ (rund 7rem) mit in der Zeile —
   ohne Umbruch blieben der Liste auf dem Handy 18 px, kein Weltname sichtbar.
   Dann darf die Zeile umbrechen: Der Wechsler bekommt die volle Breite, der
   Ressourcen-Knopf rutscht darunter. Nur über (scripting: none), nicht über
   den sichtbaren Knopf: Mit JavaScript ist er bis zum Laden des Skripts
   (defer) ebenfalls da — die Zeile bräche beim ersten Zeichnen um und
   spränge danach zurück. */
@media (scripting: none) {
    .werkzeuge:has(.welt-los:not([hidden])) { flex-wrap: wrap; }
}
.werkzeuge > .ressourcen-leiste {
    flex: 0 0 auto;
    min-width: 0;
    max-width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    box-shadow: none;
    background: none;
}

/* Welt-Wechsler: [◀] Welt [Auswahlliste] [▶] (templates/layout.php). Die
   Pfeile sind Schalter mit sehend verstecktem Namen („Vorheriges Objekt
   anzeigen“) — sichtbar nur der Pfeil als Bild, groß genug als Trefferfläche
   (mind. 2.4rem, WCAG 2.5.8). Liste und Pfeile in derselben Kasten-Optik wie
   der Ressourcen-Knopf daneben, gleich hoch. Jeder Pfeil steckt in einem
   eigenen Formular (layout.php sagt, warum); die Formulare selbst bilden
   keinen Kasten (display: contents), Pfeile und Liste stehen als Flex-Kinder
   direkt im Wechsler. */
.welt-pfeil-form,
.welt-liste-form { display: contents; }
.welt-wechsler {
    position: relative;   /* Bezug für die Ziel-Kästchen der Pfeile (data-tipp) */
    flex: 0 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: .35rem;
    margin: 0;
}
.welt-wechsler label { margin: 0; font-weight: 600; }
.welt-wechsler select {
    flex: 0 1 auto;
    min-width: 0;
    min-height: 2.4rem;
    padding: .35rem .5rem;
    border-radius: 8px;
    box-shadow: 0 1px 3px var(--schatten);
}
/* Die globale Fokus-Regel kennt a/button/input, aber kein select. */
.welt-wechsler select:focus-visible {
    outline: 3px solid var(--fokus);
    outline-offset: 2px;
}
.welt-pfeil {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-width: 2.4rem;
    min-height: 2.4rem;
    padding: 0 .4rem;
    font-size: 1rem;
    line-height: 1;
    color: var(--text);
    background: var(--bg-karte);
    border: 1px solid var(--rand);
    border-radius: 8px;
    box-shadow: 0 1px 3px var(--schatten);
}
.welt-pfeil:hover { background: var(--bg-tabellenkopf); color: var(--link); }
.welt-pfeil-bild { display: block; width: 1rem; height: 1rem; }
/* Das Ziel des Pfeils für Sehende, beim Überfahren und bei Tastaturfokus —
   was sonst ein title wäre. KEIN title: Chrome legt ihn zusätzlich als
   Beschreibung in den Barrierebaum, auch bei gleichem Text wie der Name
   (gemessen), JAWS nennte das Ziel doppelt. Der Text steht in ::after eines
   aria-hidden-Elements und ist damit für den Screenreader nicht da; der
   Name kommt aus dem sehend versteckten Text im Schalter.

   Verankert am WECHSLER, nicht am Pfeil: der vordere links bündig, der
   hintere rechts bündig mit ihm, höchstens so breit wie er (längerer Text
   bricht um).
   Am Pfeil verankert ragte das Kästchen des hinteren auf 320 px links aus dem
   Bild (Liste auf 73 px geschrumpft, Kästchen ab x = -54, Text weg). So
   bleibt es immer zwischen den Seitenrändern der Zeile. */
.welt-pfeil > [data-tipp]::after {
    content: attr(data-tipp);
    display: none;
    position: absolute;
    top: calc(100% + .35rem);
    left: 0;
    z-index: 6;
    box-sizing: border-box;
    width: max-content;
    max-width: min(28rem, 100%);
    padding: .3rem .55rem;
    font-size: .85rem;
    font-weight: 400;
    line-height: 1.35;
    text-align: left;
    color: var(--text);
    background: var(--bg-karte);
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    box-shadow: 0 4px 12px var(--schatten);
    pointer-events: none;
}
.welt-pfeil-nach > [data-tipp]::after { left: auto; right: 0; }
.welt-pfeil:hover > [data-tipp]::after,
.welt-pfeil:focus-visible > [data-tipp]::after { display: block; }
.werkzeuge > .ressourcen-leiste > details { margin: 0; padding: 0; border: 0; box-shadow: none; background: none; }
.werkzeuge details > summary {
    display: block;
    margin: 0;
    padding: .4rem .85rem;
    border: 1px solid var(--rand);
    border-radius: 8px;
    background: var(--bg-karte);
    box-shadow: 0 1px 3px var(--schatten);
    font-weight: 600;
    cursor: pointer;
    overflow-wrap: anywhere;
}
.werkzeuge details[open] > summary {
    border-bottom-left-radius: 0;
    background: var(--bg-tabellenkopf);
}
/* Das Feld hält denselben Seitenrand wie die Zeile (--wz-rand): Mit left: 0
   und max-width: 100% reichte es auf dem Handy bis an beide Bildschirmkanten,
   während die Zeile darüber 1.25rem eingerückt ist. */
.werkzeuge details[open] > :not(summary) {
    position: absolute;
    left: var(--wz-rand);
    top: 100%;
    z-index: 5;
    box-sizing: border-box;
    width: max-content;
    min-width: min(100% - 2 * var(--wz-rand), 22rem);
    max-width: calc(100% - 2 * var(--wz-rand));
    margin: 0;
    padding: .5rem .85rem;
    border: 1px solid var(--rand);
    border-radius: 0 8px 8px 8px;
    background: var(--bg-karte);
    box-shadow: 0 4px 12px var(--schatten);
}
/* Steht der Welt-Wechsler davor, beginnt das Feld links unter IHM, nicht unter
   dem Knopf — die eckige Ecke hinge dann an nichts: rundum rund. */
.werkzeuge:has(> .welt-wechsler) details[open] > summary { border-bottom-left-radius: 8px; }
.werkzeuge:has(> .welt-wechsler) details[open] > :not(summary) { border-radius: 8px; }
.werkzeuge .ressourcen-leiste table { margin: 0; }
/* Die Ausbruchsformel (50vw) gilt im schwebenden Feld nicht: Das Feld ist so
   breit wie sein Inhalt, hoechstens so breit wie die Zeile. */
.werkzeuge .breit-scroll-text { max-width: 100%; margin-right: 0; }

/* ===== RESSOURCEN-TAFEL (rechte Randspalte, ab 64rem) =======================
   Dieselbe Karte wie die Randkaesten. Kompakte Zahlen-Tabelle: Name links,
   Bestand und Rate rechtsbuendig mit Tabellenziffern, damit Groessenordnungen
   untereinander stehen und eine fehlende Stelle sofort auffaellt.

   Das Fuellstands-Band hinter dem Bestand ist reine Zugabe: --f (Prozent des
   Lagers) kommt als Inline-Variable aus dem Layout, der Verlauf faerbt genau
   diesen Anteil der Zelle. Der Ton ist --eigen-bg, der im Spiel schon Text
   traegt (eigene Zeile der Galaxiekarte) — der Kontrast ist damit belegt. Bei
   vollem Lager (Klasse .voll) wird der Name fett: Farbe allein traegt nichts
   (WCAG 1.4.1), und den Deckel als Zahl nennt die Leiste bzw. /planet. */
.ressourcen-tafel {
    border: 1px solid var(--rand);
    border-radius: 8px;
    background: var(--bg-karte);
    box-shadow: 0 1px 3px var(--schatten);
    padding: .5rem .7rem .4rem;
    margin-bottom: 1rem;
    font-size: .88rem;
}
.ressourcen-tafel .tafel-titel { margin: 0 0 .25rem; font-weight: 600; max-width: none; }
.ressourcen-tafel table { margin: 0; width: 100%; }
.ressourcen-tafel th, .ressourcen-tafel td { padding: .12rem .3rem; border-bottom: 1px solid var(--rand); }
.ressourcen-tafel thead th { position: static; font-size: .8rem; }
.ressourcen-tafel thead th:not(:first-child) { text-align: right; }
.ressourcen-tafel th[scope="row"] { font-weight: 400; white-space: nowrap; }
.ressourcen-tafel td { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ressourcen-tafel td.bestand,
.fuellstand {
    background-image: linear-gradient(90deg, var(--eigen-bg) calc(var(--f, 0) * 1%), transparent 0);
}
/* Dasselbe Band in der grossen Bestands-Tabelle auf /planet — dort nur bei den
   fluechtigen Stoffen, deren Tank-Deckel hart ist (Klasse .fuellstand setzt
   das Template). */
.ressourcen-tafel td.rate { color: var(--text-gedimmt); }
.ressourcen-tafel tr.voll th[scope="row"] { font-weight: 700; }
.ressourcen-tafel tbody tr:nth-child(even) { background: var(--zebra); }
/* Die Tafel hat schon einen Rahmen — die Zeile darin braucht keinen Hover. */
.ressourcen-tafel tbody tr:hover { background: transparent; }
.ressourcen-tafel tbody tr:nth-child(even):hover { background: var(--zebra); }

/* ENERGIE-BILANZ, erste Zeile von Leiste und Tafel (energieZelle() in
   helpers.php): grün, solange die Energie reicht, rot bei negativer Bilanz —
   nur Zugabe, das Vorzeichen trägt die Aussage (WCAG 1.4.1). Dieselben Töne wie
   die Forschungs-Voraussetzungen, also in beiden Farbschemata belegt. */
td.energie-plus { color: var(--erfolg-rand); }
td.energie-minus { color: var(--gefahr); font-weight: 600; }

/* „Alle abgeschalteten einschalten“ in der Gebäudegruppe (planet/gruppe.php):
   eigene Zeile unter dem Massen-Ausbau. */
form.aktiv-alle { margin: .4rem 0; }

/* Die Meldung laeuft beim Scrollen mit: Nach einem Bauauftrag stellt
   js/scroll-merken.js die Bildlaufposition wieder her — der Spieler steht dann
   sechs Bildschirme tief, und die Erfolgsmeldung stuende unsichtbar ganz oben.
   Als mitlaufende Zeile bleibt sie im Blick. Fuer JAWS aendert sich nichts,
   die Meldung steht unveraendert am Anfang von <main>. Sie steht unter der
   mitlaufenden Menueleiste (--kopf-h), nicht dahinter. */
main > .meldung { position: sticky; top: calc(var(--kopf-h) + .5rem); z-index: 3; }

/* Seitenwechsel als weicher Uebergang statt weissem Blitz: Der Browser blendet
   die alte Seite in die neue (Cross-Document View Transition; Chrome und Edge
   ab Version 126, andere Browser ignorieren die Regel). Kein JavaScript, keine
   Aenderung am Ablauf — die Seite laedt wie bisher, nur der Wechsel sieht nicht
   mehr nach „ganze Seite neu“ aus. Nur fuer alle, die Bewegung nicht abbestellt
   haben. */
@media (prefers-reduced-motion: no-preference) {
    @view-transition { navigation: auto; }
    ::view-transition-old(root),
    ::view-transition-new(root) { animation-duration: .18s; }
}

/* STARTSEITE FUER GAESTE: Einfuehrung als Liste mit einem fetten Stichwort je
   Punkt und einer Zeile „Mehr dazu“ mit Links ins Handbuch. Schlicht gehalten —
   die Seite soll in einer Minute ueberflogen sein. */
.einfuehrung { font-size: 1.08rem; }
.einfuehrung-liste { list-style: none; padding: 0; margin: .5rem 0 1rem; }
.einfuehrung-liste > li {
    padding: .6rem 0;
    border-bottom: 1px solid var(--rand);
    max-width: 75ch;
}
.einfuehrung-liste > li:last-child { border-bottom: 0; }
.einfuehrung-liste > li > .grund { display: block; margin-top: .2rem; }
/* Auf breiten Schirmen zwei Spalten — sechs Absaetze untereinander sind sonst
   eine schmale Textsaeule in einem leeren Fenster. */
@media (min-width: 64rem) {
    .einfuehrung-liste {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0 2.5rem;
    }
    .einfuehrung-liste > li:nth-last-child(2) { border-bottom: 0; }
}

/* ------------------------------------------------------------ Admin-Bereich */
/* Balken über jeder Seite, solange ein Admin in ein fremdes Konto schaut.
   Zuschauen = Hinweis-Farben, Handeln = Gefahr-Farben: Wer handelt, soll es
   nicht übersehen. */
.admin-balken {
    display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem;
    padding: .5rem 1rem; border-bottom: 3px solid var(--hinweis-rand);
    background: var(--hinweis-bg); color: var(--text);
}
.admin-balken-handeln { border-bottom-color: var(--gefahr); background: var(--gefahr-bg); }
.admin-balken p { margin: 0; flex: 1 1 20rem; }
.admin-balken form { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin: 0; }
.admin-balken input[type="text"] { width: 14rem; max-width: 100%; }

/* Menü des Admin-Bereichs: eine schlichte Zeile von Links. */
.betrieb-navi ul, .betrieb-filter { display: flex; flex-wrap: wrap; gap: .25rem 1rem; list-style: none; padding: 0; margin: 0 0 1rem; }
.betrieb-navi { border-bottom: 1px solid var(--rand); margin-bottom: 1rem; }
.betrieb-navi a[aria-current="page"], .betrieb-filter a[aria-current="page"] { font-weight: bold; text-decoration: none; }
.betrieb-log code { white-space: pre-wrap; word-break: break-word; }
/* Textfelder nie breiter als ihr Platz: cols="60" ist auf dem Handy ~450 px. */
textarea { max-width: 100%; }

/* ============================================================================
   OPTIK-RUNDE „KOMMANDOBRÜCKE“ (2026-10)

   Ziel: Das Spiel soll auch für Sehende nach einem Spiel aussehen, das man
   gern öffnet — Brücken-Optik mit Leuchtkanten, Bildern und einer Titelschrift
   — OHNE dass sich für JAWS/NVDA, die Tastatur oder die Vergrößerung etwas
   ändert. Darum gilt hier eine harte Grenze:

   - NUR Optik. Kein neues Element, kein neuer Tab-Stopp, keine neue
     Live-Region, keine umsortierte Reihenfolge. Alles Neue sind Hintergründe,
     Rahmen, Schatten und INHALTSLOSE Pseudo-Elemente (content: ""), die im
     Barrierebaum nicht vorkommen. Ausnahme ist genau ein nacktes <div> um die
     „Ersten Schritte“ auf der Übersicht (Quest-Kasten, Wunsch Mastermuffin).
   - Text steht NIE auf einem Bild. Bilder sitzen in eigenen Flächen (Band
     neben der Seitenüberschrift, Kopfbild der Startseite) oder als stark
     abgedunkelter Grund (Sternenhimmel: hellster Bildpunkt 18 % — darauf hält
     selbst der gedimmte Text 6:1, gerechnet am Bild, nicht geschätzt).
   - Jede Farbe, die Text trägt oder ein Bedienelement umrandet, steht als
     Variable oben in den :root-Blöcken und läuft durch
     `php scratchpad/kontrast.php` (45 Paare, beide Modi).
   - Leuchtkanten sind Zier: Sie liegen NEBEN den bestehenden Signalen (fett,
     unterstrichen, Klartext), nie an ihrer Stelle (WCAG 1.4.1).
   - Bewegung gibt es nur beim Überfahren/Fokus und nur ohne
     prefers-reduced-motion. Nichts läuft endlos von selbst (WCAG 2.2.2).
   - prefers-contrast: more, prefers-reduced-transparency und forced-colors
     (Windows-Kontrastmodus) bekommen die flache, ruhige Fassung zurück.

   Bilder: img/bereich/*.webp (je Spielbereich ein Band, gewählt über
   data-bereich am <html>, gesetzt im Layout), img/weltraum.webp (Grund im
   Dunkelmodus), img/emblem.svg (Marke). Schrift: Exo 2 (SIL OFL, fonts/OFL.txt)
   nur für Überschriften und Marke — Fließtext, Menü, Knöpfe und Tabellen
   behalten die Systemschrift: Sie ist am besten lesbar, folgt den
   Schrift-Einstellungen des Spielers, und die gemessenen Breiten von Menü,
   Registerkarten und Tabellen bleiben, wie sie sind.
   ============================================================================ */

@font-face {
    font-family: "Exo 2";
    src: url("../fonts/exo2-latin.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
        U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
        U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Exo 2";
    src: url("../fonts/exo2-latin-ext.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
        U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    --schrift-titel: "Exo 2", system-ui, "Segoe UI", Arial, sans-serif;
    /* Halbtransparente Zier-Töne, aus den geprüften Variablen gemischt — sie
       tragen nie Text, darum stehen sie nicht in kontrast.php. */
    --leucht-hauch: color-mix(in srgb, var(--leucht) 7%, transparent);
    --leucht-rand: color-mix(in srgb, var(--leucht) 28%, var(--rand));
    --leucht-schein: color-mix(in srgb, var(--leucht) 45%, transparent);
    --karte-schatten: 0 12px 32px -20px rgba(0, 0, 0, .55);
    /* Die Leuchtecken der Karten: verstärkte Kantenstücke oben links und unten
       rechts — der „HUD“-Rahmen. Als Hintergrund-Verläufe, also ohne Element.
       Sie liegen AUF der Kante (border-box), nicht im Innenraum: So können sie
       nie einen Text, eine Legende oder eine Überschrift berühren — im
       Innenraum stießen sie auf /einstellungen an die Legenden. */
    --ecken:
        linear-gradient(var(--leucht), var(--leucht)) left top / 18px 3px no-repeat border-box,
        linear-gradient(var(--leucht), var(--leucht)) left top / 3px 18px no-repeat border-box,
        linear-gradient(var(--leucht), var(--leucht)) right bottom / 18px 3px no-repeat border-box,
        linear-gradient(var(--leucht), var(--leucht)) right bottom / 3px 18px no-repeat border-box;
    /* Tagseite: ein feines Peilraster statt des Sternenhimmels. 3,5 %
       Deckkraft — unter einer Textzeile verschiebt eine Rasterlinie den
       Kontrast von --text-abgeschaltet (5,2:1) um weniger als 0,1. */
    --grund:
        linear-gradient(rgba(14, 116, 144, .035) 1px, transparent 1px) 0 0 / 56px 56px,
        linear-gradient(90deg, rgba(14, 116, 144, .035) 1px, transparent 1px) 0 0 / 56px 56px;
    --bereich-bild: url("../img/bereich/hero.webp");
}
/* Nachtseite: der echte Sternenhimmel. Wie bei den Farben zweimal (System-
   einstellung + gewählter Modus), reines CSS kann den Block nicht teilen. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="hell"]) {
        --grund: url("../img/weltraum.webp") center / cover no-repeat;
        --karte-schatten: 0 14px 36px -18px rgba(0, 0, 0, .9);
    }
}
:root[data-theme="dunkel"] {
    --grund: url("../img/weltraum.webp") center / cover no-repeat;
    --karte-schatten: 0 14px 36px -18px rgba(0, 0, 0, .9);
}

/* Das Bild je Spielbereich (data-bereich = erster Pfadteil, templates/layout.php). */
:root[data-bereich="start"]          { --bereich-bild: url("../img/bereich/start.webp"); }
:root[data-bereich="imperium"]       { --bereich-bild: url("../img/bereich/imperium.webp"); }
:root[data-bereich="werft"],
:root[data-bereich="gebaeude"],
:root[data-bereich="schiff"],
:root[data-bereich="geschuetz"]      { --bereich-bild: url("../img/bereich/werft.webp"); }
:root[data-bereich="forschung"]      { --bereich-bild: url("../img/bereich/forschung.webp"); }
:root[data-bereich="flotten"]        { --bereich-bild: url("../img/bereich/flotten.webp"); }
:root[data-bereich="kommandanten"]   { --bereich-bild: url("../img/bereich/kommandanten.webp"); }
:root[data-bereich="kampfsimulator"] { --bereich-bild: url("../img/bereich/kampfsimulator.webp"); }
:root[data-bereich="karte"],
:root[data-bereich="galaxie"]        { --bereich-bild: url("../img/bereich/karte.webp"); }
:root[data-bereich="radar"]          { --bereich-bild: url("../img/bereich/radar.webp"); }
:root[data-bereich="spionage"]       { --bereich-bild: url("../img/bereich/spionage.webp"); }
:root[data-bereich="nachrichten"],
:root[data-bereich="nachricht"],
:root[data-bereich="melden"]         { --bereich-bild: url("../img/bereich/nachrichten.webp"); }
:root[data-bereich="highscore"],
:root[data-bereich="spieler"]        { --bereich-bild: url("../img/bereich/highscore.webp"); }
:root[data-bereich="hilfe"],
:root[data-bereich="foxy"]           { --bereich-bild: url("../img/bereich/hilfe.webp"); }
:root[data-bereich="einstellungen"]  { --bereich-bild: url("../img/bereich/einstellungen.webp"); }
:root[data-bereich="tutorial"]       { --bereich-bild: url("../img/bereich/tutorial.webp"); }

/* ---------------------------------------------------------------- Seitengrund
   Ein festes Pseudo-Element hinter allem (z-index -1) statt
   background-attachment: fixed am <body>: scrollt ruhig, kostet beim Scrollen
   kein Neuzeichnen und lässt die beiden Lichtschleier am <body> stehen. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background: var(--grund);
}
@media (prefers-reduced-transparency: reduce) {
    body::before { display: none; }
}

html { scrollbar-color: var(--rand-stark) transparent; }
::selection { background: color-mix(in srgb, var(--leucht) 35%, transparent); }

/* ------------------------------------------------------------ Überschriften
   Titelschrift Exo 2: technisch, breit, aber gut lesbar — sie trägt den
   Spiel-Charakter, ohne dass Fließtext darunter leidet. KEIN text-transform:
   Großbuchstaben per CSS liest mancher Screenreader als Abkürzung vor. */
h1, h2, h3, .marke, .tafel-titel {
    font-family: var(--schrift-titel);
}
h1 { font-size: 2rem; font-weight: 700; letter-spacing: .005em; }
h2 {
    font-weight: 650;
    letter-spacing: .01em;
    /* Statt der grauen Linie ein Leuchtstrich, der nach rechts ausläuft. Die
       Linie bleibt (border-top, nur gefärbt) — wo eine Regel weiter oben
       border-top: 0 setzt, bleibt sie weiterhin weg. */
    border-image: linear-gradient(90deg, var(--leucht), var(--leucht-rand) 30%, transparent 85%) 1;
}
h3 { font-weight: 650; }

/* Unter 45rem: unter der Seitenüberschrift ein kurzer Leuchtstrich. */
main h1::after {
    content: "";
    display: block;
    width: 3.5rem;
    height: 3px;
    margin-top: .45rem;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--leucht), var(--leucht-2));
}

/* BEREICHS-BAND (ab 45rem): Die Seitenüberschrift wird zu einer Titelleiste —
   links der Titel auf voller Kartenfläche, rechts füllt das Bild des Bereichs
   den Rest der Zeile. Das Bild ist ein inhaltsloses ::after und läuft zum
   Titel hin weich aus (mask) — es liegt also NIE unter dem Text: Das Band
   ist ein eigenes Flex-Element und bekommt nur den Platz, den der Titel übrig
   lässt; bei langem Titel schrumpft es bis auf null.

   Nur Überschriften aus reinem Text (:not(:has(> *))): Bei „Eisenmine
   (Rohstoffe)“ mit <span> würden die zwei Teile zu zwei Flex-Elementen, und
   der Wortabstand dazwischen fiele weg.

   Kosten an Höhe: rund 2,5rem mehr als die nackte Überschrift. Auf dem Handy
   gibt es das Band darum nicht — dort zählt jeder Zentimeter für den Inhalt. */
@media (min-width: 45rem) {
    main h1:not(:has(> *)) {
        display: flex;
        align-items: center;
        gap: 1.5rem;
        min-height: 6.25rem;
        padding: .75rem 0 .75rem 1.25rem;
        margin-bottom: 1.1rem;
        background: var(--ecken), linear-gradient(180deg, var(--leucht-hauch), transparent), var(--bg-karte);
        border: 1px solid var(--leucht-rand);
        border-radius: 10px;
        box-shadow: var(--karte-schatten);
        overflow: hidden;
    }
    main h1:not(:has(> *))::after {
        flex: 1 1 0;
        align-self: stretch;
        width: auto;
        min-width: 0;
        height: auto;
        margin: -.75rem 0;
        border-radius: 0;
        background: var(--bereich-bild) center / cover no-repeat;
        -webkit-mask-image: linear-gradient(90deg, transparent, #000 30%);
        mask-image: linear-gradient(90deg, transparent, #000 30%);
    }
    /* SCHLICHTER TITEL ohne Leiste und Band, nur mit dem Leuchtstrich:
       - Welt-Seite: Neben dem Titel dreht schon das Planetenbild, eine leere
         Leiste daneben sähe nach Fehler aus.
       - Anmelden/Registrieren: Der Titel steht in der Karte unter deren
         Bild-Streifen.
       - Startseite für Gäste: Darüber steht das große Kopfbild. */
    :root[data-bereich="planet"] main h1:not(:has(> *)),
    :root[data-seitentyp="kompakt"] main h1:not(:has(> *)),
    :root[data-bereich="start"] main:has(> .einfuehrung) h1:not(:has(> *)) {
        display: block;
        min-height: 0;
        padding: 0;
        background: none;
        border: 0;
        box-shadow: none;
        overflow: visible;
    }
    :root[data-bereich="planet"] main h1:not(:has(> *))::after,
    :root[data-seitentyp="kompakt"] main h1:not(:has(> *))::after,
    :root[data-bereich="start"] main:has(> .einfuehrung) h1:not(:has(> *))::after {
        display: block;
        width: 3.5rem;
        height: 3px;
        margin: .45rem 0 0;
        border-radius: 2px;
        background: linear-gradient(90deg, var(--leucht), var(--leucht-2));
        -webkit-mask-image: none;
        mask-image: none;
    }
}

/* ------------------------------------------------------------------ Kopf
   Die Leiste bekommt Tiefe (feiner Verlauf auf dem deckenden --bg-kopf) und
   unten eine Leuchtlinie von Türkis nach Bernstein. Der Grund bleibt
   deckend — darunter scrollt der Inhalt durch. */
body > header {
    position: relative;
    background: linear-gradient(180deg, var(--leucht-hauch), transparent 70%), var(--bg-kopf);
    box-shadow: 0 10px 28px -22px var(--leucht-schein);
}
body > header::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 2px;
    pointer-events: none;
    background: linear-gradient(90deg, transparent, var(--leucht) 20%, var(--leucht-2) 80%, transparent);
}
/* Im fremden Konto trägt die Kante die Farbe des Admin-Balkens — die Linie
   darf sie nicht überdecken. */
body:has(> .admin-balken) > header::after { display: none; }

/* Die Marke: Emblem (Maske, in Leuchtfarben verlaufend) und der Name mit
   einem Verlauf von Textfarbe nach Türkis. Beide Enden sind als Textfarbe auf
   --bg-kopf geprüft (17:1 bzw. 9:1 dunkel, 16:1 bzw. 5:1 hell). Zeilenhöhe
   und Schriftgröße bleiben — sie stecken in --kopf-weg. */
.marke {
    font-weight: 800;
    letter-spacing: .12em;
}
.marke::before {
    content: "";
    display: inline-block;
    width: 1.2em;
    height: 1.2em;
    margin-right: .5em;
    vertical-align: -.22em;
    background: linear-gradient(135deg, var(--leucht-2), var(--leucht));
    -webkit-mask: url("../img/emblem.svg") center / contain no-repeat;
    mask: url("../img/emblem.svg") center / contain no-repeat;
}
@supports (background-clip: text) {
    .marke {
        background-image: linear-gradient(90deg, var(--text) 35%, var(--leucht));
        background-clip: text;
        -webkit-background-clip: text;
        color: transparent;
    }
    /* Das Emblem darf nicht mit ausgeschnitten werden. */
    .marke::before { -webkit-background-clip: border-box; background-clip: border-box; }
}

/* MENÜ ALS KONSOLEN-TASTEN. Jeder Punkt ist eine flache Taste mit
   abgeschrägten Ecken (corner-shape: bevel; ältere Browser zeigen runde
   Ecken), getönter Kante und einer schwachen Energie-Linie unten. Die
   aktuelle Seite ist eine gefüllte, leuchtende Taste — und behält, was sie
   vorher hatte: fett und unterstrichen (Farbe nie allein, WCAG 1.4.1).

   GEMESSEN, nicht geschätzt (scratchpad, 320–3440 px): Die Tasten kosten
   Innenabstand, dafür schrumpft der Abstand zwischen den Punkten — die
   Menüzeilen bleiben auf jeder Breite gleich viele, die mitlaufende Leiste
   wächst nur um die Kante (Werte in doku/OPTIK.md). Es bleibt dieselbe
   <ul> mit denselben Links: kein neues Element, kein Tab-Stopp. */
.nav-haupt { gap: .3rem .3rem; align-items: center; }
@media (min-width: 45rem) {
    .nav-haupt { gap: .3rem .35rem; }
    .nav-haupt > .nav-block,
    .nav-haupt > .nav-konto {
        border-left-color: var(--leucht-rand);
        padding-left: .7rem;
        margin-left: .35rem;
    }
}
.nav-haupt > li > a,
.nav-schlicht > li > a {
    display: inline-block;
    padding: .1rem .55rem;
    line-height: 1.35;
    color: var(--text);
    text-decoration: none;
    border: 1px solid var(--leucht-rand);
    border-radius: 6px;
    corner-shape: bevel;
    background: linear-gradient(180deg, var(--leucht-hauch), transparent), var(--bg-karte);
    box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--leucht) 30%, transparent);
}
.nav-haupt > li > a:visited { color: var(--text); }
.nav-haupt > li > a:hover {
    border-color: var(--leucht);
    box-shadow: inset 0 -2px 0 var(--leucht), 0 0 12px -3px var(--leucht-schein);
}
/* Aktuelle Seite: gefüllt wie ein Hauptknopf (weiße Schrift auf beiden
   Verlaufsenden geprüft), fett, unterstrichen, Leuchtkante. */
header nav a[aria-current="page"],
header nav a[aria-current="page"]:visited,
header nav a[aria-current="page"]:hover {
    margin: 0;
    padding: .1rem .55rem;
    color: var(--akzent-text);
    font-weight: 700;
    text-decoration: underline;
    text-underline-offset: .2em;
    border: 1px solid var(--leucht);
    border-radius: 6px;
    background: linear-gradient(135deg, var(--akzent), var(--akzent-2));
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), inset 0 -2px 0 var(--leucht),
        0 0 16px -3px var(--leucht-schein);
}
.nav-logout button { padding: .15rem .65rem; line-height: 1.35; }
/* Wischleiste (unter 64rem): schmalere Tasten — mehr Punkte im Bild. */
@media (max-width: 63.99rem) {
    .nav-haupt > li > a,
    header nav .nav-haupt > li > a[aria-current="page"] { padding-inline: .42rem; }
}
@media (prefers-reduced-motion: no-preference) {
    .nav-haupt > li > a { transition: border-color .15s ease, box-shadow .15s ease; }
}

/* ------------------------------------------------------------------ Knöpfe
   HUD-Schaltflächen: abgeschrägte Ecken, Verlauf von --akzent nach
   --akzent-2 (weiße Schrift auf beiden Enden geprüft), Lichtkante oben,
   Energie-Linie unten, beim Überfahren Schein und ein einmaliger
   Lichtstreif. Größe und Trefferfläche bleiben exakt — Kanten und Linien
   sind Schatten, kein Rand. Der Fokusring folgt der Abschrägung. */
button,
.knopf {
    border-radius: 6px;
    corner-shape: bevel;
    background: linear-gradient(135deg, var(--akzent), var(--akzent-2));
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), inset 0 0 0 1px rgba(255, 255, 255, .10),
        inset 0 -2px 0 color-mix(in srgb, var(--leucht) 75%, transparent),
        0 6px 16px -8px color-mix(in srgb, var(--akzent) 80%, transparent);
}
button:hover,
.knopf:hover {
    filter: brightness(1.08);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3), inset 0 0 0 1px rgba(255, 255, 255, .16),
        inset 0 -2px 0 var(--leucht),
        0 0 20px -2px var(--leucht-schein);
}
button:active,
.knopf:active {
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, .35), inset 0 -1px 0 var(--leucht);
}
/* Zweitknopf: dunkle Konsolen-Taste mit Leuchtkante. */
.knopf.knopf-zweit,
.gruppe-knopf button:not([aria-disabled="true"]) {
    background: linear-gradient(180deg, color-mix(in srgb, var(--aktion-zweit) 85%, #fff), var(--aktion-zweit) 55%, color-mix(in srgb, var(--aktion-zweit) 80%, #000));
    box-shadow: inset 0 0 0 1px var(--leucht-rand), inset 0 -2px 0 color-mix(in srgb, var(--leucht) 55%, transparent),
        0 6px 16px -10px rgba(0, 0, 0, .6);
}
.knopf.knopf-zweit:hover,
.gruppe-knopf button:not([aria-disabled="true"]):hover {
    box-shadow: inset 0 0 0 1px var(--leucht), inset 0 -2px 0 var(--leucht), 0 0 16px -4px var(--leucht-schein);
}
/* Gefahr: rot glühend. */
button.gefahr {
    background: linear-gradient(135deg, var(--gefahr-aktion), color-mix(in srgb, var(--gefahr-aktion) 72%, #000));
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), inset 0 -2px 0 color-mix(in srgb, var(--gefahr) 80%, transparent),
        0 6px 16px -8px color-mix(in srgb, var(--gefahr-aktion) 80%, transparent);
}
button.gefahr:hover { box-shadow: inset 0 -2px 0 var(--gefahr), 0 0 20px -2px color-mix(in srgb, var(--gefahr) 60%, transparent); }
/* „ausblenden“ in der Ziel-Zeile sieht aus wie ein Link — ohne Taste. */
.ziel-aus button,
.ziel-aus button:hover,
.ziel-aus button:active { box-shadow: none; background: none; filter: none; corner-shape: round; }
/* Gesperrt (aria-disabled, „zu teuer“): flach, ruhig, mit GESTRICHELTER
   Kante — ein zusätzliches Formsignal neben der gedämpften Schrift und dem
   Klartext-Grund daneben. Gleiche Größe wie vorher (1px Rand). */
button[aria-disabled="true"],
button[aria-disabled="true"]:hover,
button[aria-disabled="true"]:active {
    background: var(--bg-karte);
    border: 1px dashed var(--rand-stark);
    box-shadow: none;
    filter: none;
}
/* Der Lichtstreif: ein inhaltsloses ::after, das beim Überfahren EINMAL
   durch den Knopf zieht. Nur ohne prefers-reduced-motion. Nicht an den
   Pfeil-Schaltern (deren Ziel-Kästchen hängt am Welt-Wechsler, ein
   position: relative am Pfeil verschöbe es) und nicht an Text-Knöpfen. */
@media (prefers-reduced-motion: no-preference) {
    button, .knopf, .nav-haupt > li > a { transition: box-shadow .18s ease, filter .18s ease, border-color .18s ease; }
    :is(button, .knopf):not(.welt-pfeil, .nav-pfeil, .ziel-aus button, [aria-disabled="true"]) {
        position: relative;
        isolation: isolate;
        overflow: hidden;
    }
    :is(button, .knopf):not(.welt-pfeil, .nav-pfeil, .ziel-aus button, [aria-disabled="true"])::after {
        content: "";
        position: absolute;
        inset: 0;
        z-index: -1;
        pointer-events: none;
        background: linear-gradient(110deg, transparent 35%, rgba(255, 255, 255, .16) 50%, transparent 65%);
        transform: translateX(-120%);
    }
    :is(button, .knopf):not(.welt-pfeil, .nav-pfeil, .ziel-aus button, [aria-disabled="true"]):hover::after {
        transform: translateX(120%);
        transition: transform .65s ease;
    }
}

/* Fokus: Der Ring bleibt (3px --fokus), dazu ein weicher Schein. */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, summary:focus-visible {
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--fokus) 22%, transparent);
}
summary:focus-visible { outline: 3px solid var(--fokus); outline-offset: 2px; }

/* --------------------------------------------------------------- Eingaben */
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], select, textarea {
    border-color: var(--rand-eingabe);
    border-radius: 6px;
    background: var(--bg-karte);
    color: var(--text);
}
textarea { border: 1px solid var(--rand-eingabe); padding: .5rem; font: inherit; }
input:hover:not([type="checkbox"], [type="radio"], [type="hidden"]),
select:hover, textarea:hover { border-color: var(--leucht); }
input[type="checkbox"], input[type="radio"] { accent-color: var(--akzent); }

/* ----------------------------------------------------------------- Karten
   EINE Kartenform für alles, was als Kasten auf der Seite steht: Kartengrund
   mit einem Hauch Leuchtfarbe oben, getönter Rand, die Leuchtecken oben links
   und unten rechts, tiefer weicher Schatten. Der Text liegt nie auf den
   Ecken (Innenabstand), der Hauch ändert den Textkontrast um weniger als 1. */
.rand-kasten,
.ereignisse,
.vorschau,
.ressourcen-tafel,
.einstell-raster > fieldset,
.ressourcen-leiste > details,
.nachricht-inhalt {
    background: var(--ecken), linear-gradient(180deg, var(--leucht-hauch), transparent 4rem), var(--bg-karte);
    border-color: var(--leucht-rand);
    border-radius: 10px;
    box-shadow: var(--karte-schatten);
}
/* Alle übrigen Feldgruppen im Inhalt (Kampfsimulator, Flotten-Schritte …)
   tragen statt des Browser-Rillenrahmens dieselbe ruhige Kante. Der
   Innenabstand bleibt der des Browsers — die Formulare sind gemessen. */
main fieldset:not(.einstell-raster > fieldset) {
    border: 1px solid var(--leucht-rand);
    border-radius: 10px;
    background: linear-gradient(180deg, var(--leucht-hauch), transparent 4rem);
}
main fieldset > legend { font-weight: 650; padding: 0 .35rem; }
.einstell-raster > fieldset > legend,
.ressourcen-tafel .tafel-titel { color: var(--text); font-weight: 650; }
.ressourcen-tafel .tafel-titel { letter-spacing: .02em; }

@media (min-width: 45rem) {
    :root[data-seitentyp="kompakt"] main {
        background: var(--ecken), linear-gradient(180deg, var(--leucht-hauch), transparent 6rem), var(--bg-karte);
        border-color: var(--leucht-rand);
        border-radius: 14px;
        box-shadow: var(--karte-schatten), 0 0 40px -24px var(--leucht-schein);
        overflow: hidden;
    }
    /* Anmelden/Registrieren: oben in der Karte ein Bild-Streifen. */
    :root[data-seitentyp="kompakt"] main::before {
        content: "";
        display: block;
        height: 8.5rem;
        margin: -1.75rem -2rem 1.5rem;
        background: url("../img/bereich/hero.webp") center 45% / cover no-repeat;
        border-bottom: 1px solid var(--leucht-rand);
    }
}

/* Aufklappbare Abschnitte: Zeile wie eine Konsole, aufgeklappt mit
   Leuchtkante links — zusätzlich zu Dreieck und Kopf-Fläche, die den Zustand
   schon zeigen. */
details.abschnitt > summary {
    border-color: var(--leucht-rand);
    border-radius: 8px;
    background: linear-gradient(180deg, var(--leucht-hauch), transparent), var(--bg-karte);
}
details.abschnitt[open] > summary {
    border-radius: 8px 8px 0 0;
    border-bottom-color: var(--leucht);
    background: linear-gradient(180deg, var(--leucht-hauch), transparent), var(--bg-tabellenkopf);
    box-shadow: inset 3px 0 0 var(--leucht);
}
details.abschnitt[open] > *:not(summary) {
    border-color: var(--leucht-rand);
    border-radius: 0 0 8px 8px;
}
summary::marker { color: var(--leucht); }
.geb-gruppe:not(:has(> details[open])) {
    border-color: var(--leucht-rand);
    border-radius: 8px;
    background: linear-gradient(180deg, var(--leucht-hauch), transparent), var(--bg-karte);
    box-shadow: var(--karte-schatten);
}
.geb-gruppe:not(:has(> details[open])):hover { border-color: var(--leucht); }

/* --------------------------------------------------------- Quest-Kasten
   Alles, was zu den Ersten Schritten gehört — die Ziel-Zeile über dem
   Inhalt, der Kasten rechts und der Block auf der Übersicht — trägt
   denselben Bernstein-Ton (Wunsch Mastermuffin: „kasten in einer anderen
   farbe, dann merkt man, dass das zusammengehört“). */
.ziel-zeile,
.rand-rechts > .rand-kasten,
.erste-schritte {
    background:
        linear-gradient(var(--quest-rand), var(--quest-rand)) right 4px top 4px / 14px 2px no-repeat,
        linear-gradient(var(--quest-rand), var(--quest-rand)) right 4px top 4px / 2px 14px no-repeat,
        var(--quest-bg);
    border: 1px solid color-mix(in srgb, var(--quest-rand) 45%, var(--rand));
    border-left: 4px solid var(--quest-rand);
    border-radius: 10px;
    box-shadow: var(--karte-schatten), 0 0 26px -18px var(--quest-rand);
}
.erste-schritte { padding: .25rem 1.1rem .5rem; margin: 1.5rem 0; max-width: 80ch; }
.erste-schritte > h2 { border-top: 0; padding-top: .5rem; margin-top: .25rem; }
/* Die h2 „Erste Schritte“ steckt jetzt im Kasten — „main > h2:first-of-type“
   (kein Strich über der ersten h2) träfe sonst „Deine Welten“ darunter. Wie
   bei /tutorial: nach dem Kasten wieder mit Strich. */
main > .erste-schritte ~ h2 { border-top: 1px solid var(--rand); padding-top: .75rem; margin-top: 2rem; }
.tutorial-etappe.tutorial-aktuell { border-left-color: var(--quest-rand); }

/* --------------------------------------------------------------- Tabellen
   Kopf mit Leuchtlinie statt grauem Strich und einem Hauch Leuchtfarbe;
   die Zeile unter dem Zeiger bekommt links eine Leuchtkante. */
thead th {
    background: linear-gradient(180deg, var(--leucht-hauch), transparent), var(--bg-tabellenkopf);
    border-bottom-color: var(--leucht);
}
tbody tr:hover > :first-child { box-shadow: inset 3px 0 0 var(--leucht); }
.ressourcen-tafel tbody tr:hover > :first-child { box-shadow: none; }

/* --------------------------------------------------------- Registerkarten
   Aktive Lasche mit Leuchtbalken und Schein; Zustand weiterhin auch über
   Fettschrift, offene Grundlinie und Balken (nicht nur Farbe). */
.karten { box-shadow: inset 0 -2px 0 var(--leucht-rand); }
.karten a {
    border-color: var(--leucht-rand);
    background: linear-gradient(180deg, var(--leucht-hauch), transparent), var(--bg-tabellenkopf);
}
.karten a[aria-selected="true"],
.karten a[aria-current="page"] {
    border-color: var(--leucht-rand);
    border-top-color: var(--leucht);
    background: var(--bg);
    box-shadow: 0 -8px 18px -10px var(--leucht-schein);
}
.unterkarten a { border-color: var(--leucht-rand); }
.unterkarten a[aria-selected="true"],
.unterkarten a[aria-current="page"] {
    border-color: var(--leucht);
    box-shadow: inset 0 -2px 0 var(--leucht), 0 0 12px -4px var(--leucht-schein);
}
.abschnitt-nav a { border-color: var(--leucht-rand); }
.abschnitt-nav a:hover { border-color: var(--leucht); }

/* ------------------------------------------------- Werkzeug-Zeile & Tafel */
.welt-pfeil,
.welt-wechsler select,
.werkzeuge details > summary {
    border-color: var(--leucht-rand);
    background: linear-gradient(180deg, var(--leucht-hauch), transparent), var(--bg-karte);
}
.welt-pfeil:hover,
.werkzeuge details > summary:hover { border-color: var(--leucht); }
.welt-pfeil-bild { color: var(--leucht); }
.werkzeuge details[open] > :not(summary) {
    border-color: var(--leucht-rand);
    box-shadow: var(--karte-schatten);
}

/* Fortschritt am laufenden Bau: Leuchtbalken. */
.bau-fortschritt { border-color: var(--leucht-rand); border-radius: 999px; }
.bau-fortschritt-balken {
    background: linear-gradient(90deg, var(--akzent), var(--leucht));
    box-shadow: 0 0 8px var(--leucht-schein);
}

/* Bilder der Himmelskörper und Foxy: ein Lichthof. */
.planet-bild-kopf,
.foxy-bild { filter: drop-shadow(0 0 18px var(--leucht-schein)); }

/* -------------------------------------------------------------- Meldungen */
.meldung-erfolg { box-shadow: 0 0 22px -12px var(--erfolg-rand); }
.meldung-fehler,
.fehlerbox { box-shadow: 0 0 22px -12px var(--gefahr); }
.meldung, .fehlerbox, .devhinweis { border-radius: 8px; }

/* -------------------------------------------------------------- Sprunglink */
.sprunglink {
    background: linear-gradient(135deg, var(--akzent), var(--akzent-2));
    border-radius: 0 0 8px 0;
    font-weight: 700;
}

/* ------------------------------------------------------------- Fusszeile */
footer {
    background: linear-gradient(0deg, var(--leucht-hauch), transparent 70%), var(--bg-kopf);
    border-top-color: var(--leucht-rand);
}

/* ------------------------------------------------- Startseite für Gäste
   Ein großes Kopfbild über der Begrüßung — der erste Eindruck. Inhaltslos,
   also für den Screenreader nicht da; die Seite beginnt für JAWS wie bisher
   mit der Überschrift. Die sechs Absätze „So läuft das Spiel“ werden Karten. */
:root[data-bereich="start"] main:has(> .einfuehrung)::before {
    content: "";
    display: block;
    height: clamp(9rem, 26vw, 21rem);
    margin: 0 0 1.5rem;
    border: 1px solid var(--leucht-rand);
    border-radius: 14px;
    background: url("../img/bereich/hero.webp") center 40% / cover no-repeat;
    box-shadow: var(--karte-schatten), 0 0 60px -30px var(--leucht-schein);
}
:root[data-bereich="start"] main:has(> .einfuehrung) h1 { font-size: clamp(1.9rem, 3.2vw, 2.6rem); }
.einfuehrung-liste { gap: 1rem; }
.einfuehrung-liste > li,
.einfuehrung-liste > li:nth-last-child(2) {
    margin: 0 0 1rem;
    padding: .9rem 1.1rem;
    border: 1px solid var(--leucht-rand);
    border-radius: 10px;
    background: var(--ecken), linear-gradient(180deg, var(--leucht-hauch), transparent 4rem), var(--bg-karte);
    box-shadow: var(--karte-schatten);
}
@media (min-width: 64rem) {
    .einfuehrung-liste { gap: 1rem 1.25rem; }
    .einfuehrung-liste > li, .einfuehrung-liste > li:nth-last-child(2) { margin: 0; max-width: none; }
}
.aktionen .knopf { padding: .65rem 1.4rem; }

/* ----------------------------------------------- Ruhige Fassungen
   Mehr Kontrast gewünscht oder Windows-Kontrastmodus: Zier weg, Bilder weg,
   flache Flächen. Was bleibt, sind die Signale, die es vorher schon gab. */
@media (prefers-contrast: more) {
    body::before,
    main h1::after,
    :root[data-seitentyp="kompakt"] main::before,
    :root[data-bereich="start"] main:has(> .einfuehrung)::before { display: none !important; }
    main h1:not(:has(> *)) { min-height: 0; }
    h2 { border-image: none; }
    .marke { color: var(--text); background-image: none; }
}
@media (forced-colors: active) {
    body::before,
    body > header::after,
    .marke::before,
    main h1::after,
    :root[data-seitentyp="kompakt"] main::before,
    :root[data-bereich="start"] main:has(> .einfuehrung)::before { display: none !important; }
    h2 { border-image: none; }
    .marke { color: CanvasText; background-image: none; }
    main h1:not(:has(> *)) { min-height: 0; }
    button, .knopf { border: 1px solid ButtonText; }
    .nav-haupt > li > a { border: 1px solid LinkText; background-image: none; }
    button, .knopf, .sprunglink, thead th, .karten a, details.abschnitt > summary,
    .rand-kasten, .ereignisse, .vorschau, .ressourcen-tafel, .ziel-zeile,
    .erste-schritte, .einfuehrung-liste > li, .geb-gruppe, main h1 { background-image: none; }
}
