/* ===========================================================================
   styles.css – Gestaltung der interaktiven DBA-Weltkarte
   ---------------------------------------------------------------------------
   Ausgelagert aus index.html (vormals Inline-<style>). Reines Verschieben –
   inhaltlich unverändert. Dadurch kann die CSP ohne 'unsafe-inline' auskommen
   (siehe deploy/htaccess.live, security/SICHERHEIT.md).
   Reihenfolge: Layout · Karten-Label · Reset-Button · InfoBox · Länder-Label ·
   Popup (Statistiken) · DBA-Popup · Mobile-Anpassungen.
   =========================================================================== */

/* --- Schriftart „Geist" (self-hosted, SIL Open Font License 1.1) ------------
   Geist (Vercel) ist die durchgehende Hausschrift der Karte – sie löst die vormals
   verwendete, KOSTENPFLICHTIGE Helvetica Neue ab (Lizenzthema damit erledigt, s. doku/22).
   Vier Schnitte, bewusst NUR aufrecht (kein Kursiv), Zeichensatz Latin:

     200  ExtraLight  Ländername beim Hover · Sticker-Name (Fokus-Ansicht) · Kartenname
     300  Light       Absatztext der Land-Detail-Ansicht
     400  Regular     alles Übrige (Suche, Menüs, Buttons, Popups)
     500  Medium      Info-Zeilen der Fokus-Ansicht · Kennzahlen der Detail-Ansicht · Legende

   Kein local() in src: Geist ist auf keinem System vorinstalliert, ein local()-Treffer
   wäre nur eine fremde Schrift gleichen Namens. Immer die mitgelieferte Datei.
   Dateien und Bezugsweg: app/fonts/README.md. */
@font-face {
    font-family: "Geist";
    font-style: normal;
    font-weight: 200;                                  /* ExtraLight (bei Vercel „UltraLight") */
    font-display: swap;
    src: url("fonts/Geist-ExtraLight.woff2") format("woff2");
}

@font-face {
    font-family: "Geist";
    font-style: normal;
    font-weight: 300;                                  /* Light */
    font-display: swap;
    src: url("fonts/Geist-Light.woff2") format("woff2");
}

@font-face {
    font-family: "Geist";
    font-style: normal;
    font-weight: 400;                                  /* Regular */
    font-display: swap;
    src: url("fonts/Geist-Regular.woff2") format("woff2");
}

@font-face {
    font-family: "Geist";
    font-style: normal;
    font-weight: 500;                                  /* Medium */
    font-display: swap;
    src: url("fonts/Geist-Medium.woff2") format("woff2");
}

/* EINE Quelle für die Schriftkette – überall im Stylesheet nur noch var(--font).
   Die Fallbacks greifen nur, falls eine woff2-Datei fehlt oder noch lädt. */
:root {
    --font: "Geist", "Helvetica Neue", Helvetica, Arial, sans-serif;
    /* Linke Kante von Kartenname, senkrechter Linie, Legende UND dem Suchknopf: 7,5 % der
       Fensterbreite. Steht bewusst hier auf :root (nicht mehr nur an #mapChrome), weil die
       Suche ein eigenes Element außerhalb von #mapChrome ist und exakt dieselbe Kante
       braucht. Mobiler Wert im @media-Block unten. */
    --map-chrome-left: clamp(24px, 7.5vw, 150px);

    /* --- Größen-Regler im T-Testbereich (Wunsch 13.08.2026) --------------------
       Zwei waagerechte Regler stellen die Größe von Legende und Namensschild in vier
       Stufen: Stufe 0 = die früheren Maße, 1…3 jeweils kleiner. Gesetzt wird allein
       dieser Faktor (script.js: SIZE_STEPS), alle Maße hängen daran – Kreise UND Schrift
       der Legende bzw. Kasten UND Schrift des Kartennamens.
       Standard ist bei der Legende seit 04.09.2026 Stufe 2, beim Namensschild seit
       09.09.2026 ebenfalls Stufe 2 (Desktop-Standard); Stufe 0 bleibt als Vergleich
       erreichbar. Fallback-Werte hier, falls JS ausfällt (script.js: SIZE_STEPS
       überschreibt sie beim Laden).
       Doku: doku/27_KARTENNAME_LEGENDE.md */
    --legend-scale: 0.7;
    --title-scale: 0.7;
    /* Sticker-Schrift (FA/LDA/Länder ohne Karte), Fallback falls JS ausfällt – script.js
       überschreibt ihn beim Laden über den Regler „Sticker-Schrift". */
    --sticker-scale: 0.85;

    /* --- Kartenmenü: Band + vier große Kreise (Entwürfe uploads/main-menu) ---------
       Alle Maße im Entwurf (2116 x 1482 px) ausgemessen und in Fensteranteile umgerechnet,
       damit die Anordnung auf jeder Fenstergröße die der Vorlage bleibt:
         Kreis-Ø        76 px  = 3,6 vw = 5,13 vh
         Kreis-Abstand  5,7 px = 7,5 % des Durchmessers
         Bandhöhe      373 px  = 25,2 % der Fensterhöhe
       Der Entwurf hat das Format 1,43:1 – dort sind 3,6 vw und 5,13 vh dasselbe. Das min()
       nimmt auf FLACHEN Fenstern (16:9 und breiter) den vh-Wert: sonst wüchse die
       Kreisspalte über die 25,2 % Bandhöhe hinaus und das Band müsste unschön mitwachsen.
       Doku: doku/24_KARTENANSICHTEN.md */
    --menu-dot: clamp(22px, min(3.6vw, 5.13vh), 76px);
    --menu-gap: calc(var(--menu-dot) * 0.075);
    /* Rasterhöhe einer Menüzeile = Kreis + Abstand. Auf ihr sitzt sowohl der Kreis im
       Umschalter als auch die zugehörige Gruppe in #mapMenu – deshalb liegen beide immer
       aufeinander, ohne dass irgendwo Geometrie ausgerechnet werden muss. */
    --menu-row: calc(var(--menu-dot) + var(--menu-gap));
    /* Aufklapp-Bewegung: Kreise (Größe + Abstand) und Verschiebung der Spalte nach rechts
       laufen mit EINER Dauer und EINER Kurve, damit die Kreismitte während der ganzen
       Bewegung auf derselben Bahn bleibt (vorher wirkte das Aufziehen wackelig). Die Dauer
       kennt auch script.js (MENU_SETTLE_MS) – dort werden Hover-Wechsel so lange stumm
       gehalten, weil die wachsenden Kreise sonst unter dem ruhenden Zeiger hindurchwandern
       und laufend Zeilen auf- und zuklappen. */
    --menu-anim: 260ms;
    --menu-ease: cubic-bezier(0.22, 0.61, 0.36, 1);    /* weich auslaufend */
    --menu-count: 4;                                   /* Anzahl Kreise; script.js (pruneMapMenu) setzt den echten Wert */
    --menu-top: 12px;                                  /* Oberkante des Umschalters */
    --menu-pad-y: 8px;                                 /* dessen senkrechte Polsterung */
    /* Bandhöhe: oben und unten GLEICHER Abstand zwischen Bandrand und Kreisen (Wunsch
       14.10.2026, Desktop/Tablet/Handy). Abstand oben = --menu-top + --menu-pad-y (Seitenrand
       bis Oberkante des ersten Kreises); derselbe Wert gilt von der Unterkante des letzten
       Kreises bis zur Bandunterkante. 4 Kreise, aber nur 3 Abstände dazwischen. */
    --menu-edge-y: calc(var(--menu-top) + var(--menu-pad-y));
    --menu-band-h: calc(var(--menu-edge-y) * 2
                        + var(--menu-count) * var(--menu-dot)
                        + (var(--menu-count) - 1) * var(--menu-gap));
}

/* --- Layout / Grundgerüst -------------------------------------------------- */
html, body {
    height: 100%;
    /* Ozean-Blau als Seiten-Hintergrund: falls das SVG (z. B. ganz früh
       im Load) doch mal einen Rand lässt, ist dieser blaues Wasser statt
       eines weißen Rechtecks. Gleiche Farbe wie das #background-Rect.
       Das über die viewBox hinaus gezogene #background-Rect (s. index.html) deckt die
       Ränder ab – auch in der Fokus-Ansicht (weißes Wasser) und auf den Themenkarten
       mit eigener Wasserfarbe. Dieser Wert greift daher nur noch ganz früh im Load. */
    background: #d8f3ff;
}

body {
    margin: 0;
    font-family: var(--font);
    overflow: hidden; /* kein Rubber-Band-Scroll auf Mobilgeräten */
}
/* Auch html selbst beschneiden: sonst reicht der Kreis-Umschalter im geöffneten Menü (per
   translateX über den Bildrand geschoben) als Überstand ins Dokument, und iOS-Safari
   weitet daraufhin die Layout-Breite auf – die Halbkreise standen mobil dann nicht mehr
   auf dem Bildrand (Meldung 29.09.2026, seit die Kreise 44 px groß sind). */
html { overflow: hidden; }

/* ---------------------------------------------------------------------------
   Ladeschirm (doku/28)
   Beim ersten Besuch gehen rund 1,1 MB über die Leitung – ohne diesen Schirm
   sähe man in dieser Zeit einen leeren bzw. halb aufgebauten Bildschirm. Er
   liegt über allem und verschwindet erst, wenn die Karte fertig gezeichnet UND
   vorgewärmt ist (Schriften geladen, Geometrie im Startmaßstab): body.app-ready.

   Farbe = Wasser der Startkarte (DBA), damit der Übergang in die fertige Karte
   nicht als Farbsprung auffällt. Bewusst fest verdrahtet: maps.json ist in dem
   Moment noch gar nicht geladen.

   Den Füllstand trägt --loader-p (0…100), gesetzt von script.js über das CSSOM
   (element.style.setProperty) – das ist von der CSP `style-src 'self'` NICHT
   betroffen, anders als ein <style>-Block im HTML.
--------------------------------------------------------------------------- */
:root {
    --loader-bg: #004775;
    --loader-ring: 104px;
    --loader-p: 0;
}

#loader {
    position: fixed;
    inset: 0;
    z-index: 200;                    /* über Menüs (42), Messhilfe (60), allem */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    background: var(--loader-bg);
    color: #fff;
    /* Sichtbar, bis die Karte steht. Das Ausblenden läuft weich; visibility zieht
       verzögert nach, damit der Schirm während der Blende nichts abfängt. */
    opacity: 1;
    visibility: visible;
    transition: opacity 420ms ease, visibility 0s linear 0s;
}
body.app-ready #loader {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 420ms ease, visibility 0s linear 420ms;
}

/* Der Ring: ein Kreis mit conic-gradient, dem ein zweiter Kreis in Hintergrundfarbe
   die Mitte ausstanzt. Bewusst KEINE mask (in Safari nur mit -webkit-Präfix und
   teurer) und kein SVG – so bleibt der Schirm billig, während im Hintergrund
   geladen und gezeichnet wird. */
#loaderRing {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--loader-ring);
    height: var(--loader-ring);
    border-radius: 50%;
    background: conic-gradient(#fff calc(var(--loader-p) * 1%),
                               rgba(255, 255, 255, 0.22) 0);
    /* Der Füllstand springt nicht, sondern läuft weich nach – sonst wirkt die
       Anzeige hektisch, weil die Dateien in Schüben ankommen. */
    transition: background 220ms linear;
}
#loaderRing::after {
    content: "";
    position: absolute;
    inset: 9px;
    border-radius: 50%;
    background: var(--loader-bg);
}

#loaderPct {
    position: relative;              /* über der ausgestanzten Mitte */
    z-index: 1;
    font-size: calc(var(--loader-ring) * 0.27);
    font-weight: 300;
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;   /* die Zahl zappelt nicht beim Zählen */
}
#loaderPct .loader-pct-sign {
    font-size: 0.62em;
    opacity: 0.75;
    margin-left: 0.08em;
}

#loaderText {
    margin: 0;
    font-size: 15px;
    font-weight: 300;
    letter-spacing: 0.01em;
    opacity: 0.85;
}

@media (max-width: 768px) {
    :root { --loader-ring: 84px; }
    #loaderText { font-size: 14px; }
}

/* Wer Animationen abbestellt hat, bekommt den Schirm ohne Blende. */
@media (prefers-reduced-motion: reduce) {
    #loader, #loaderRing { transition: none; }
}

/* Vollbild-SVG: füllt den Viewport in beiden Orientierungen. Das
   viewBox-Seitenverhältnis wird per JS an den Bildschirm angepasst
   (computeSize), daher entsteht mit preserveAspectRatio kein Letterbox.
   touch-action:none ist Pflicht, sonst schluckt iOS die Pinch-Geste.
   Gezielt #map (nicht bare 'svg'), sonst würde auch das Lupen-Inline-SVG
   im #searchToggle auf Vollbild gezogen. */
#map {
    display: block;
    /* fixed + 100 % statt 100dvh: iOS-Chrome rechnet dvh kleiner als den sichtbaren Bereich,
       unten blieb ein blauer Streifen (Meldung 14.10.2026). fixed bezieht sich wie
       #legalLinks, Suchkreis und #mapChrome auf den sichtbaren Rand. */
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    touch-action: none;
}

/* --- Karten-Label (SVG-Text auf der Karte) --------------------------------- */
.law-text {
    fill: black;
    font-size: 16px;
    text-anchor: middle;
    pointer-events: none;
    background: white;
    paint-order: stroke;
    stroke: white;
    stroke-width: 4px;
}

/* --- Kartenname & Legende --------------------------------------------------- */
/* Nachbau der Designer-Entwürfe (uploads/kartennameUndLegende), Maße dort ausgemessen
   und in Fensteranteile umgerechnet – die Anordnung bleibt dadurch auf jeder Fenster-
   größe die der Vorlage:
     Kartenname → farbiger Kasten oben links, oben aus dem Bild ragend, Text
                  linksbündig an der Unterkante, Geist ExtraLight (wie der Ländername)
     Linie      → 2px, senkrecht vom Kasten bis zum unteren Bildrand
     Legende    → unten links an dieser Linie, Kreis + Text in Geist Medium
                  (wie die Info-Zeilen); die SCHRIFTFARBE ist die Farbe des Kreises
   Farben, Texte und Kategorien kommen aus app/maps.json (renderMapChrome in script.js).
   Doku: doku/27_KARTENNAME_LEGENDE.md */
#mapChrome {
    /* fixed (wie #legalLinks, die in Safari am Bildschirmrand sitzt): absolute rechnete
       gegen die Seite, die in iOS-Safari kürzer als der sichtbare Bildschirm ist, und die
       Linie der Legende endete vor dem unteren Rand (Meldung 14.10.2026, Tablet quer). */
    position: fixed;
    inset: 0;
    /* Unter allen Bedienelementen und unter den Landes-Stickern (z-index 50):
       Name und Legende sind reine Beschriftung und dürfen nie etwas verdecken. */
    z-index: 5;
    pointer-events: none;             /* geklickt wird durch sie hindurch auf die Karte */
    /* Weiches Aus-/Einblenden in der Fokus- und der Detail-Ansicht (s. body-Klassen
       unten). Dauer = FOCUS_DURATION in script.js. */
    opacity: 1;
    transition: opacity 400ms ease;

    /* --- gemeinsame Maße (aus den Entwürfen gemessen) --- */
    /* linke Kante von Kasten, Linie und Legende steht auf :root (--map-chrome-left),
       weil der Suchknopf unten links dieselbe Kante braucht. */
    --map-title-fill: #88a564;        /* Startwerte; überschrieben von renderMapChrome */
    --map-title-line: #88a564;
    --map-water: #004775;
}

/* In der Fokus-Ansicht (Wasser wird weiß, Flächen hellgrau) und in der Land-Detail-
   Ansicht gelten die Kartenfarben nicht mehr – Name und Legende blenden weich aus und
   beim Verlassen genauso weich wieder ein. */
body.world-focus #mapChrome,
body.detail-open #mapChrome {
    opacity: 0;
}

/* Kartenwechsel: kurze Kreuzblende, während der Name und die Legendenzeilen getauscht
   werden (swapMapChrome in script.js) – halbe Dauer, damit Aus- und Einblenden zusammen
   der Dauer des Umfärbens entsprechen. */
#mapChrome.swapping {
    opacity: 0;
    transition-duration: 200ms;
}

#mapTitle {
    position: absolute;
    left: var(--map-chrome-left);
    /* Der Kasten ragt oben aus dem Bild: der negative Versatz ist größer als der
       Abstand der Rahmen-outline, damit oben KEIN Rahmen sichtbar wird (wie in der
       Vorlage, wo der Kasten oben angeschnitten ist). */
    top: -14px;
    box-sizing: border-box;
    /* sichtbare Höhe ≈ 15 % der Fensterhöhe (zzgl. des herausragenden Teils), verkleinert
       um die Stufe des Reglers „Kartenname" im Testbereich (--title-scale). */
    height: calc(clamp(84px, 15vh, 170px) * var(--title-scale, 1) + 14px);
    max-width: calc(100vw - var(--map-chrome-left) - 20px);
    display: flex;
    align-items: flex-end;            /* Name steht an der Unterkante des Kastens */
    background: var(--map-title-fill);
    /* Der feine weiße Rahmen ist bewusst KEIN border: die outline liegt mit Abstand
       außerhalb, dadurch bleibt zwischen Kasten und Rahmen eine Lücke, in der das
       Wasser durchscheint – genau wie in den Entwürfen. */
    outline: 1px solid #fff;
    outline-offset: 3px;
    font-family: var(--font);
    font-weight: 200;                 /* Geist ExtraLight */
    font-size: calc(clamp(17px, 1.45vw, 30px) * var(--title-scale, 1));
    line-height: 1.15;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
}

#mapTitleText {
    padding: 0 0.5em 0.5em 0.75em;    /* Einzug links / Abstand zur Unterkante */
}

/* Die senkrechte Linie ist die linke Kante dieser Hülle. Sie beginnt dadurch genau an der
   OBERKANTE DES OBERSTEN LEGENDENKREISES (nicht schon am Kartennamen) und läuft bis zum
   unteren Bildrand – ohne dass die Höhe der Legende irgendwo ausgerechnet werden muss.
   Ihre Farbe ist immer die Farbe des Namensschildes (--map-title-line = title.fill). */
#mapLegendWrap {
    position: absolute;
    left: var(--map-chrome-left);
    bottom: 0;
    /* Abstand der untersten Legendenzeile zum unteren Bildrand ≈ 12 % der Fensterhöhe;
       als padding, damit die Linie darunter weiterläuft. */
    padding-bottom: clamp(40px, 12vh, 130px);
    /* Feine Linie (Wunsch 13.08.2026: dünner als die früheren 2px). */
    border-left: 1px solid var(--map-title-line);
    /* Schriftgröße steht hier (nicht an der Liste), weil der Schein unten in em rechnet
       und die Linie mit einschließt. Der Faktor ist die Stufe des Reglers
       „Legendensymbole" im Testbereich (--legend-scale). */
    font-size: calc(clamp(12px, 1.18vw, 24px) * var(--legend-scale, 1));
    /* OHNE Schein (Wunsch 13.08.2026). Bis dahin lag hinter Schrift und Kreisen ein
       weicher Schein in der Wasserfarbe der Karte, damit ein gleichfarbiger Eintrag auch
       auf Landfläche lesbar bleibt. Zum Anschauen und Vergleichen gibt es ihn weiter:
       Häkchen „Legende-shadow" im T-Testbereich setzt body.legend-shadow (s. unten). */
}

/* PROBEWEISE (Häkchen „Legende-shadow" im T-Testbereich, doku/27): leichter Schatten wie
   bei den vier Kreisen der Menüleiste (box-shadow 0 2px 5px rgba(0,0,0,.2)) – hier als
   drop-shadow, damit ihn auch die Schrift und die senkrechte Linie bekommen. Damit ist zu
   sehen, ob z. B. weiße Schrift auf weißer Landfläche so noch erkennbar bleibt. */
body.legend-shadow #mapLegendWrap {
    filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.2));
}

.map-legend {
    margin: 0;
    padding: 0;
    list-style: none;
    font-family: var(--font);
    font-weight: 500;                 /* Geist Medium */
    /* Durchmesser der Kreise, verkleinert um die Stufe des Reglers „Legendensymbole"
       im Testbereich (--legend-scale, s. :root). Alle Abstände der Legende hängen an
       diesem Wert – die Zeilen rücken damit automatisch mit zusammen. */
    --legend-dot: calc(clamp(14px, 1.95vw, 42px) * var(--legend-scale, 1));
}

.map-legend-item {
    display: flex;
    align-items: center;
    /* Abstand der Kreise untereinander seit 09.09.2026 um die Hälfte kleiner (Wunsch:
       Kreise näher zusammen, auf allen 5 Themenkarten – hängt schon an --legend-dot). */
    margin-top: calc(var(--legend-dot) * 0.125);
    /* Abstand zur senkrechten Linie seit 09.09.2026 ebenfalls um die Hälfte kleiner
       (Wunsch: alle Legendenkreise auf dem Desktop näher an die Linie, weiter nach
       links). */
    padding-left: calc(var(--legend-dot) * 0.075);
    font-family: var(--font);
    font-weight: 500;
    white-space: nowrap;
}

.map-legend-item:first-child { margin-top: 0; }

.map-legend-swatch {
    flex: none;
    width: var(--legend-dot);
    height: var(--legend-dot);
    margin-right: calc(var(--legend-dot) * 0.4);
    border-radius: 50%;
    background: var(--swatch);
}

/* Kategorie mit Schraffur (Brasilien auf Karte 1): der Kreis baut die Schraffur der
   Landfläche nach – weißer Grund, Diagonalen in der Kartenfarbe.

   RICHTUNG: von links unten nach rechts oben („/“) wie auf dem Land (SVG-Pattern hatchK2,
   patternTransform rotate(-45)). Dafür ist 135deg richtig und NICHT 45deg: In CSS gibt der
   Winkel die Richtung der Verlaufs-LINIE an, die Streifen stehen quer dazu. 45deg (Linie
   nach rechts oben) ergibt also „\“-Streifen – so lag es bis 04.08.2026 falsch herum.

   SYMMETRISCH: Ein grüner Streifen soll genau durch die Kreismitte laufen, damit das
   Muster oben/unten gleich aussieht. Die Verlaufslinie ist über dem Quadrat (Seite
   --legend-dot = D) D·√2 lang, die Mitte liegt bei 0.7071·D.

   FEINER SEIT 13.08.2026: dünnere Striche, dafür öfter – dieselbe Änderung wie auf der
   Landfläche (script.js: HATCH_TILE/HATCH_WIDTH, dort 0.6 zu 3 = Verhältnis 0.2). Mit
   Strichbreite 0.028·D und Abstand 0.14·D beginnt der erste Streifen bei
   0.7071 − 0.028/2 − 4·0.14 = 0.1331·D; seine Mitte liegt dann bei 0.1471·D + k·0.14·D und
   trifft bei k = 4 die Kreismitte.
   (Der angegebene Bereich ist die Kachel – sie wiederholt sich in BEIDE Richtungen.) */
.map-legend-swatch.hatched {
    background:
        repeating-linear-gradient(135deg,
            var(--swatch-hatch) calc(var(--legend-dot) * 0.1331) calc(var(--legend-dot) * 0.1611),
            var(--swatch) calc(var(--legend-dot) * 0.1611) calc(var(--legend-dot) * 0.2731));
}

/* --- Reset-Button ---------------------------------------------------------- */
/* DESKTOP: sitzt im Testbereich (#testMenu) unter dem Zoom-Panel und klappt mit ihm
   hinter dem „T" auf – daher keine eigene Positionierung, sondern normales Flex-Kind
   in voller Panelbreite. MOBIL steht er unverändert dauerhaft oben rechts
   (s. @media-Block unten). */
#resetBtn {
    z-index: 10;
    display: flex;
    align-items: center;   /* „Zurücksetzen" + Esc-Kästchen vertikal mittig */
    justify-content: center;
    width: 100%;
    box-sizing: border-box;
    padding: 8px 14px;
    font-size: 14px;
    background: white;
    border: 1px solid #aaa;
    border-radius: 4px;
    cursor: pointer;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

/* Tasten-Kästchen „Esc" im Reset-Button: zeigt den Desktop-Shortcut (Esc setzt
   die Karte zurück, s. script.js). Am Handy gibt es keine Esc-Taste → wird in der
   Mobile-Media-Query unten ausgeblendet. */
#resetBtn .kbd-hint {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 6px;
    font-size: 11px;
    line-height: 1.4;
    font-family: inherit;
    color: #555;
    background: #f2f2f2;
    border: 1px solid #bbb;
    border-radius: 3px;
    box-shadow: inset 0 -1px 0 #ccc;
    vertical-align: middle;
}

/* === Länder-Suche =========================================================== */
/* Es gibt ZWEI Erscheinungsformen mit derselben Logik und demselben DOM:
     • NEUES DESIGN (Standard, kein body-Klassenname): runder weißer Knopf unten links
       an der Legendenlinie, der beim Anklicken nach rechts zu einer Pille aufzieht.
       Regeln weiter unten im Block „Länder-Suche – neues Design".
     • PROTOTYP (body.search-classic, Häkchen „Search-prototype" im Testbereich):
       die frühere Leiste unten mittig, mobil hinter der Lupe oben rechts. Das sind die
       Regeln direkt hier – sie bleiben unverändert die Basis und werden vom neuen
       Design überschrieben.
   Doku: doku/15_LAENDER_SUCHE.md */

/* --- Länder-Suche, PROTOTYP (Eingabefeld + Trefferliste, unten mittig) ------ */
/* DESKTOP: am unteren Bildschirmrand horizontal zentriert; die Trefferliste klappt
   nach OBEN auf (s. #countrySearchList) und zeigt weiter genau 4 Zeilen
   (max-height = --row-h * 4), der Rest wird gescrollt. z-index über InfoBox (20)
   und den Popups (30–35), damit die Trefferliste immer bedienbar bleibt.
   Hinweis: Die InfoBox säße an derselben Stelle – sie ist derzeit abgeschaltet
   (INFOBOX_ENABLED = false, doku/25). Wird sie reaktiviert, muss eine der beiden
   Leisten ausweichen. */
#countrySearch {
    position: absolute;
    bottom: 24px;
    left: 50%;
    /* --search-dodge-x: waagerechtes AUSWEICHEN vor einem eingeblendeten Namens-Label
       (Hover-Name/Auswahl-Label). 0px = Ruhelage mittig; den Wert setzt script.js in
       dodgeSearchForLabel und nimmt ihn nach dem Ausblenden wieder zurück. Die
       Transition (= SELECTION_LABEL_FADE_MS) macht Hin- und Rückweg weich. */
    transform: translateX(calc(-50% + var(--search-dodge-x, 0px)));
    transition: transform 350ms ease;
    z-index: 40;
    width: 200px;
    max-width: calc(100vw - 20px);
    font-family: var(--font);
}

/* LAND-DETAIL-ANSICHT (nur Desktop/Querformat – exakte Umkehrung des isPhone-Querys):
   Das Land zoomt nach links in DETAIL_BOX, die Suchleiste bleibt auf DERSELBEN Höhe
   (bottom: 24px) und fährt waagerecht von der Bildmitte unter das Land. Die Ziel-Mitte
   liefert JS als --detail-search-x aus DETAIL_BOX (script.js), damit beides zusammenbleibt.
   Dauer = ZOOM_ANIMATION_DURATION (750 ms), die Leiste wandert also mit dem Zoom.
   `:not(.open)` schützt nur den Grenzfall exakt quadratischer Displays, wo beide
   Media-Querys greifen – dort gilt weiter das mobile Aufklapp-Layout.
   NUR PROTOTYP: im neuen Design sitzt die Suche ohnehin links unten und wandert nicht
   mit – darum hängt der ganze Block an body.search-classic. */
@media (min-aspect-ratio: 1/1) and (min-width: 501px) {
    /* transform muss mitgenannt werden, sonst überschriebe diese Regel das Ausweichen
       vor dem Namens-Label (--search-dodge-x) und es spränge hart. */
    body.search-classic #countrySearch:not(.open) { transition: left 750ms ease, transform 350ms ease; }
    body.search-classic.detail-open #countrySearch:not(.open) { left: var(--detail-search-x, 18%); }
}

/* Nur mobil relevant (Aufklapp-Leiste mit Lupen-Icon): auf dem Desktop komplett
   ausgeblendet, damit dort Layout/Verhalten der Suche 1:1 bleiben. Sichtbar erst
   im Mobile-@media-Block (Lupe) bzw. wenn #countrySearch.open gesetzt ist (✕). */
#searchToggle, #searchClose { display: none; }

/* Der Knopf trägt zwei Symbole (s. index.html). Grundzustand = Prototyp: Lupe sichtbar,
   Stern aus. Das neue Design dreht das im Abschnitt am Dateiende um. */
#searchToggle .icon-star { display: none; }

/* --- Rechte Bedienspalte (#sideMenu) --------------------------------------- */
/* Auf dem DESKTOP ist der Wrapper layout-neutral: `display: contents` nimmt ihn aus
   dem Kasten-Baum, seine Kinder (#mapMenu, #testMenu) behalten also ihre eigenen
   absoluten Positionen und klappen getrennt auf (Kreise bzw. „T"). Mobil wird er im
   @media-Block zum Flex-Container und trägt das gemeinsame Auf-/Zuklappen. */
#sideMenu {
    display: contents;
}

/* --- Vier-Kreise-Umschalter (Kartenansichten) ------------------------------ */
/* Vier weiße Kreise. Anklicken schaltet body.mapmenu-open: die Kreise fahren so weit
   nach rechts, dass ihre MITTE genau auf dem Bildschirmrand liegt – stehen bleiben
   vier Halbkreise. Rein weiß OHNE Kontur; sichtbar auf dem weißen Wasser der
   Fokus-Ansicht bleiben sie über den Schatten. DESKTOP: oben rechts. MOBIL: unter der
   Lupe (nur das top wird im @media-Block überschrieben). */
#mapMenuToggle {
    --dot: 12px;
    --gap: 1.5px;
    --pad-x: 10px;
    --edge: 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* fixed statt absolute: ein fixiertes Element zählt nicht zum scrollbaren Überstand des
       Dokuments. Der offen per translateX über den Rand geschobene Umschalter weitete sonst
       auf iOS die Layout-Breite auf (29.09.2026). Sichtbar ändert sich nichts, die Seite
       scrollt nicht. */
    position: fixed;
    top: var(--menu-top);
    right: var(--edge);
    z-index: 41;
    padding: var(--menu-pad-y) var(--pad-x);
    border: none;
    background: transparent;
    cursor: pointer;
    /* BEWUSST OHNE Übergang: die Spalte springt sofort an ihren Platz. Sichtbar ist sie
       nicht (transparent, ohne Rahmen) – zu sehen sind allein die Kreise darin, und die
       tragen seit dem Umbau die GANZE Bewegung in einem einzigen transform (s. .menu-dot
       und flipMenuDots() in script.js). Vorher lief hier eine zweite, eigene Animation
       neben dem Wachsen der Kreise – beim Zuklappen liefen die beiden sichtbar
       auseinander (erst nach links, dann nach oben statt auf gerader schräger Bahn). */
}
#mapMenuToggle .menu-dot {
    width: var(--dot);
    height: var(--dot);
    /* Abstand der vier Kreise untereinander. Bewusst als margin und NICHT als `gap` am
       Flex-Container: die Kreise wachsen beim Öffnen des Menüs von 12 px auf --menu-dot,
       und margin-top lässt sich in jedem Browser zuverlässig mit-animieren. Genau dadurch
       rücken die unteren drei Kreise beim Aufziehen weiter nach unten (Entwurf). */
    margin-top: var(--gap);
    /* border-box, damit der Probe-Rand unten (body.dots-outlined) die Kreise NICHT
       vergrößert und der Abstand in beiden Varianten gleich bleibt. */
    box-sizing: border-box;
    border-radius: 50%;
    background: #fff;
    /* keine graue Kontur (bewusst) – der Schatten allein hebt die Kreise ab */
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
    /* Größe und Abstand springen (kein Übergang auf width/height/margin-top): das LAYOUT
       steht damit sofort im Zielzustand, und die sichtbare Bewegung macht allein das
       transform hier – gesetzt von flipMenuDots() in script.js (messen → invers setzen →
       auf `none` animieren). So stecken Verschiebung, Wachsen und Auseinanderrücken in
       EINER Eigenschaft und laufen zwangsläufig gemeinsam: jeder Kreis fährt auf gerader
       schräger Bahn. Vorher waren es zwei Animationen (transform am Umschalter auf der
       Grafikkarte, width/height/margin-top hier im Layout) – die liefen beim Zuklappen
       sichtbar auseinander. */
    transition: transform var(--menu-anim) var(--menu-ease),
                opacity 130ms ease;
    will-change: transform;
}
#mapMenuToggle .menu-dot:first-child { margin-top: 0; }
/* Probeweise wieder mit grauer Kontur – geschaltet über die Taste „Grey border f. menu
   circles" im Testbereich („T"). Nur zum Vergleichen, damit die Entscheidung offen bleibt. */
body.dots-outlined #mapMenuToggle .menu-dot {
    border: 1px solid #aaa;
}
/* Offen: die Kreise wachsen auf Menügröße und fahren so weit nach rechts, dass ihre MITTE
   auf dem Bildschirmrand liegt. Beides zusammen ergibt die vier Halbkreise des Entwurfs. */
body.mapmenu-open:not(.mapmenu-classic) #mapMenuToggle {
    --dot: var(--menu-dot);
    --gap: var(--menu-gap);
}
body.mapmenu-open #mapMenuToggle {
    transform: translateX(calc(var(--edge) + var(--pad-x) + var(--dot) / 2));
}
/* Der Kreis der gerade aufgeklappten Gruppe wird unsichtbar – an seiner Stelle steht die
   Beschriftung (Entwürfe menu-point*-hovered.jpg). Bewusst NUR opacity: der Kreis behält
   damit seine Trefferfläche. Mit display/visibility würde der Zeiger im selben Moment aus
   dem Element fallen, die Gruppe klappte wieder zu und das Menü flackerte. */
body.mapmenu-open #mapMenuToggle .menu-dot.is-hidden {
    opacity: 0;
}

/* --- „T"-Umschalter (Testbereich) ------------------------------------------ */
/* NUR DESKTOP. Großer weißer Buchstabe am rechten Rand, vertikal mittig; öffnet
   #testMenu und fährt dabei nach rechts, bis seine Mitte auf dem Bildschirmrand
   liegt (gleiche 280-ms-Bewegung wie die Kreise). Weiß mit dünner grauer Kontur +
   Schatten – sonst verschwindet er im weißen Wasser der Fokus-Ansicht. */
#testMenuToggle {
    --edge: 8px;
    position: absolute;
    top: 50%;
    right: var(--edge);
    z-index: 41;
    transform: translateY(-50%);
    padding: 0 4px;
    border: none;
    background: transparent;
    cursor: pointer;
    font-family: var(--font);
    font-size: 64px;
    font-weight: 300;
    line-height: 1;
    color: #fff;
    -webkit-text-stroke: 1px #aaa;
    text-shadow: 0 2px 5px rgba(0, 0, 0, 0.25);
}
body.testmenu-open #testMenuToggle {
    transform: translateY(-50%) translateX(calc(50% + var(--edge)));
}
/* transform trägt hier die Zentrierung UND die Fahrt – die Transition darf deshalb
   nur den transform betreffen (kein `all`, sonst springt die Schrift). */
#testMenuToggle { transition: transform 280ms ease; }

/* Testbereich abgeschaltet (14.10.2026): body.testmenu-off blendet das „T" und das Test-Panel
   aus (display:none, die Eingabefelder bleiben im DOM und behalten ihre Grundwerte). Der
   Zurücksetzen-Knopf bleibt unberührt. Wieder einschalten: Klasse im <body> von index.html
   entfernen. Doku: doku/28_LADEANZEIGE_UND_TEMPO.md. */
body.testmenu-off #testMenuToggle,
body.testmenu-off #zoomTestPanel { display: none !important; }

/* --- Testbereich (#testMenu) ----------------------------------------------- */
/* DESKTOP: senkrechter Block rechts neben dem „T", vertikal mittig – Zoom-Panel und
   Zurücksetzen-Knopf untereinander. Blendet weich ein/aus (Muster wie das mobile
   Kreis-Menü: visibility verzögert, damit das Ausblenden zu Ende läuft).
   MOBIL ist der Wrapper per `display: contents` layout-neutral (s. @media-Block). */
#testMenu {
    position: absolute;
    top: 50%;
    /* Abstand zum Rand so groß, dass das nach rechts gefahrene „T" NEBEN dem Panel
       stehen bleibt – auf dem weißen Panel wäre der weiße Buchstabe unsichtbar. */
    right: 44px;
    z-index: 9;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    width: 200px;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 250ms ease, visibility 0s linear 250ms;
}
body.testmenu-open #testMenu {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 250ms ease, visibility 0s linear 0s;
}

/* EXPERIMENT: Test-Panel für die Startperspektive. Steht im Testbereich (Desktop) bzw.
   im aufklappbaren Kreis-Menü (mobil) – in beiden Fällen ohne eigene Positionierung. */
#zoomTestPanel {
    width: 100%;
    box-sizing: border-box;
    padding: 10px 12px;
    background: white;
    border: 1px solid #aaa;
    border-radius: 4px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
    font-family: var(--font);
}
#zoomTestPanel h2 {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 500;   /* Geist Medium – kräftigster mitgelieferter Schnitt */
    color: #333;
}
#zoomTestPanel button {
    display: block;
    width: 100%;
    margin-top: 6px;
    padding: 8px 10px;
    font-size: 13px;
    background: #f7f7f7;
    border: 1px solid #aaa;
    border-radius: 4px;
    cursor: pointer;
}
#zoomTestPanel button:hover { background: #eee; }
/* Prototyp-Karte (maps.json-ID k1) – gehört zur Radiogruppe der Kartenansichten, steht
   aber hier im Testbereich. Optik wie eine Zeile im Kartenmenü, mit Trennlinie über
   den Zoomout-Tasten. */
#protoMapOption {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid #ddd;
    font-size: 13px;
    cursor: pointer;
}
#protoMapOption input[type="radio"] {
    width: 15px;
    height: 15px;
    margin: 0;
    accent-color: #d97b0f;
    cursor: pointer;
}
#protoMapOption input[type="radio"]:checked + span { font-weight: 500; color: #000; }
#protoMapOption:focus-within { outline: 2px solid #d97b0f; outline-offset: 1px; }
/* Probeschalter „Grey border f. menu circles" – gibt den vier Menü-Kreisen wieder eine
   graue Kontur (s. #mapMenuToggle .menu-dot). Reine Entscheidungshilfe im Testbereich,
   Optik wie die Prototyp-Karten-Zeile darüber. */
/* Gleiche Optik für die Häkchen darunter: „Search-prototype" (alte Suche, doku/15),
   „Menu-prototype" (altes Kartenmenü-Panel, doku/24) und „Tempo messen" (Messhilfe,
   doku/28). */
#dotBorderOption,
#searchProtoOption,
#menuProtoOption,
#perfOption,
#legendShadowOption {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    font-size: 13px;
    cursor: pointer;
}
#dotBorderOption input[type="checkbox"],
#searchProtoOption input[type="checkbox"],
#menuProtoOption input[type="checkbox"],
#perfOption input[type="checkbox"],
#legendShadowOption input[type="checkbox"] {
    width: 15px;
    height: 15px;
    margin: 0;
    accent-color: #d97b0f;
    cursor: pointer;
}
#dotBorderOption input[type="checkbox"]:checked + span,
#searchProtoOption input[type="checkbox"]:checked + span,
#menuProtoOption input[type="checkbox"]:checked + span,
#perfOption input[type="checkbox"]:checked + span,
#legendShadowOption input[type="checkbox"]:checked + span { font-weight: 500; color: #000; }
#dotBorderOption:focus-within,
#searchProtoOption:focus-within,
#menuProtoOption:focus-within,
#perfOption:focus-within,
#legendShadowOption:focus-within { outline: 2px solid #d97b0f; outline-offset: 1px; }

/* --- Größen-Regler „Legendesymbole" und „Kartenname" (Wunsch 13.08.2026) -----
   Je eine Zeile mit Beschriftung, waagerechtem Regler (vier Stufen) und der aktuellen
   Stufe rechts. Optik wie die Häkchen darüber, damit der Testbereich als ein Block
   gelesen wird. Doku: doku/27_KARTENNAME_LEGENDE.md */
#zoomTestPanel .size-option {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    font-size: 13px;
    cursor: pointer;
}
#zoomTestPanel .size-option > span {
    flex: none;
    /* Beide Beschriftungen gleich breit → die Regler stehen untereinander. */
    width: 82px;
}
#zoomTestPanel .size-option input[type="range"] {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    accent-color: #d97b0f;
    cursor: pointer;
}
#zoomTestPanel .size-option output {
    flex: none;
    width: 12px;
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: #555;
}
#zoomTestPanel .size-option:focus-within { outline: 2px solid #d97b0f; outline-offset: 1px; }

/* Das Zurücksetzen-Symbol gehört dem Handy (s. Mobile-Block): auf dem Desktop steht im
   Testbereich weiter der Knopf mit Text und Esc-Hinweis. */
#resetBtn .icon-undo { display: none; }
/* Stufe 4 ist eine reine Handy-Stufe (die Desktop-Startansicht ist schon die ganze
   Welt – dort wäre sie nur eine sehr kleine Weltkarte). Auf dem Desktop deshalb aus;
   der Mobile-@media-Block unten blendet sie wieder ein. Selektor mit `button`, damit
   er dieselbe Spezifität wie `#zoomTestPanel button { display: block }` überbietet. */
#zoomTestPanel button#zoomOut4Btn { display: none; }
/* Stufe 5 ist eine reine TABLET-HOCHFORMAT-Stufe: Hochformat (max-aspect-ratio 1/1,
   also dieselbe Hälfte der mobilen Query wie oben) UND Breite ab 501 px – unter
   501 px liegt laut Projekt-Konvention das Handy. Grundzustand daher aus. */
#zoomTestPanel button#zoomOut5Btn { display: none; }
@media (max-aspect-ratio: 1/1) and (min-width: 501px) {
    #zoomTestPanel button#zoomOut5Btn { display: block; }
}

/* --- Menüleiste der Kartenansichten ---------------------------------------- */
/* Gemeinsames Ein-/Ausblenden für beide Fassungen (neues Band-Menü und Prototyp-Panel):
   erscheint nur bei body.mapmenu-open. z-index 9 (< Such-Trefferliste 40), damit die
   Trefferliste frei darüber aufklappen kann. visibility verzögert, damit das Ausblenden
   weich zu Ende läuft. */
#mapMenu {
    position: absolute;
    z-index: 9;
    margin: 0;
    font-family: var(--font);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--menu-anim) var(--menu-ease),
                visibility 0s linear var(--menu-anim);
}
/* Zweiter Zurücksetzen-Knopf unten rechts im Band: NUR MOBIL sichtbar (dort per
   Media Query auf display:flex zurückgeholt, s. u.). */
#resetBtnMenu { display: none; }
body.mapmenu-open #mapMenu {
    opacity: 1;
    visibility: visible;
    transition: opacity var(--menu-anim) var(--menu-ease), visibility 0s linear 0s;
}

/* --- Neues Band-Menü (Standard) ------------------------------------------- */
/* Das breite Band am oberen Bildrand: es zeichnet die Karte darunter unscharf und legt
   ein dunkles Grün darüber. Liegt über #mapChrome (z-index 5) – der Kartenname oben links
   scheint dadurch verschwommen durch, genau wie im Entwurf – und unter #mapMenu (9) und
   dem Umschalter (41).
   Solange das Menü ZU ist, nimmt das Band keine Zeiger-Ereignisse an – es darf das obere
   Viertel der Karte nicht blockieren. OFFEN ist es dagegen die Hover-Fläche des Menüs:
   Solange der Zeiger irgendwo im Band steht, bleibt das Menü offen; verlässt er es, fährt
   es wieder zu. Ein Klick ins Band schließt es sofort (der pointerdown-Handler am SVG
   greift dort nicht mehr, weil das Band die Karte überdeckt). */
#mapMenuBand {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: var(--menu-band-h);
    z-index: 8;
    pointer-events: none;
    background: rgba(64, 84, 62, 0.66);
    backdrop-filter: blur(30px);
    -webkit-backdrop-filter: blur(30px);
    opacity: 0;
    transition: opacity var(--menu-anim) var(--menu-ease);
    /* eigene Ebene: die Weichzeichnung soll nicht in jedem Bild der Kreis-Bewegung neu
       gerechnet werden */
    will-change: opacity;
}
body.mapmenu-open:not(.mapmenu-classic) #mapMenuBand {
    opacity: 1;
    pointer-events: auto;
}
body.mapmenu-classic #mapMenuBand { display: none; }

/* Die Beschriftungsspalte. Sie beginnt an derselben Oberkante wie die Kreise (Umschalter-
   `top` + dessen Polsterung) und besteht aus vier Zeilen im Kreisraster – Gruppe n liegt
   damit automatisch auf Kreis n.
   Rechte Kante: der Text endet 0,72 Kreisdurchmesser links neben der Kreiskante; da die
   Kreismitte auf dem Bildschirmrand liegt, sind das --menu-dot * (0,5 + 0,72). */
body:not(.mapmenu-classic) #mapMenu {
    position: fixed;                 /* frei über der Karte, nicht in der Bedienspalte */
    top: calc(var(--menu-top) + var(--menu-pad-y));
    /* Die ZEILEN reichen bis an den rechten Bildrand, der TEXT hört vorher auf
       (s. .map-menu-labels). Vorher endete die Zeile schon am Text – der Streifen
       zwischen Beschriftung und Kreisen gehörte damit niemandem: dort stehen zu bleiben
       zeigte nichts an. Jetzt zählt auch dort allein die Höhe. */
    right: 0;
    left: 0;
    display: flex;
    flex-direction: column;
    padding: 0;
    border: none;
    background: none;
}
/* „Kartenansicht" bleibt für Screenreader erhalten, ist aber nicht mehr zu sehen. */
body:not(.mapmenu-classic) #mapMenu legend {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
/* Eine Zeile des Kreisrasters. Sie ist NUR so hoch wie ihr Kreis – der Beschriftungsblock
   darin liegt absolut und darf nach unten herausragen (Kreis 2 mit zwei Einträgen), ohne
   die folgenden Zeilen zu verschieben. Genau das zeigen die Entwürfe: beim Aufklappen
   bleiben alle übrigen Kreise stehen. */
/* Eine Zeile ist die volle Breite des Bandes hoch einer Rasterhöhe. Genau das ist ihre
   Trefferfläche: es zählt allein, auf welcher HÖHE der Zeiger steht – auch ganz links im
   Bild klappt damit die Beschriftung des Kreises auf, der auf derselben Höhe sitzt.
   Solange das Menü ZU ist, bleibt sie aus: sonst fingen die vier unsichtbaren Streifen
   Klicks auf die Karte ab. */
.map-menu-group {
    position: relative;
    height: var(--menu-row);
    pointer-events: none;
}
body.mapmenu-open:not(.mapmenu-classic) .map-menu-group {
    pointer-events: auto;
}
/* Die AUFGEKLAPPTE Gruppe liegt über den folgenden Zeilen. Ohne das war der zweite
   Eintrag von Kreis 2 („Steuerbefreiungen …") nicht zu treffen: er ragt in die Zeile von
   Kreis 3 hinein, und die steht im DOM später – sie lag also darüber, fing den Zeiger ab
   und klappte statt dessen Art. 17 auf. */
.map-menu-group.is-active {
    z-index: 2;
}
/* Rechtsbündiger Block: `max-content` macht ihn so breit wie seinen längsten Eintrag –
   dadurch ist die feine Linie darunter genau so breit wie der längste Eintrag der Gruppe
   (Entwurf menu-point2And3-hovered.jpg). */
.map-menu-labels {
    position: absolute;
    top: 0;
    /* Rechte Textkante: 0,72 Kreisdurchmesser links neben der Kreiskante; da die Kreismitte
       auf dem Bildschirmrand liegt, sind das --menu-dot * (0,5 + 0,72). Der Wert saß früher
       an #mapMenu – der trägt jetzt die Zeilen bis zum Bildrand. */
    /* Desktop, Wunsch 14.10.2026: Abstand Textende -> Halbkreis halbiert (0,72 -> 0,36 Ø). */
    --label-inset: calc(var(--menu-dot) * 0.86);
    right: var(--label-inset);
    width: max-content;
    max-width: 100%;
    opacity: 0;
    pointer-events: none;
    /* Kurz und weich: der Wechsel von Zeile zu Zeile soll dem Zeiger unmittelbar folgen
       (der frühere 200-ms-Wert wirkte träge). */
    transition: opacity 130ms ease;
}
.map-menu-group.is-active .map-menu-labels {
    opacity: 1;
    pointer-events: auto;
}
/* ZWEIZEILIGE Gruppe (Kreis 2): Der Block rückt so weit nach oben, dass die weiße
   Trennlinie zwischen den beiden Einträgen auf der MITTE des Halbkreises liegt – die
   beiden Einträge stehen dann symmetrisch darüber und darunter. Rechnung: die Linie ist
   die Unterkante der ersten Zeile, sitzt also eine Rasterhöhe unter der Blockoberkante;
   die Kreismitte liegt einen halben Durchmesser unter der Zeilenoberkante. Verschiebung
   = Rasterhöhe − Ø/2 = Ø/2 + Abstand. Die Klasse setzt script.js an jeder Gruppe mit mehr
   als einem Eintrag (einzeilige bekommen ihren eigenen Ausgleich unten an der Zeile
   selbst, s. .map-menu-group:not(.is-double) .map-menu-labels label).
   Gilt unverändert für den DESKTOP-Hover (hier zeigt immer nur eine Gruppe gleichzeitig,
   die volle Rasterzeile pro Eintrag passt zur großen Bildschirmschrift). Für das Handy
   (alle Gruppen gleichzeitig offen) gibt es unten im @media(hover:none) eine eigene,
   kompaktere Fassung – s. dortiger Kommentar. */
.map-menu-group.is-double .map-menu-labels {
    top: calc(-0.5 * var(--menu-dot) - var(--menu-gap));
}
/* Trefferfläche des aufgeklappten Blocks bis zum linken Bildrand – auch für die zweite
   Zeile von Kreis 2, die aus ihrer Zeile herausragt. Sonst gälte dort links neben dem Text
   wieder die darunterliegende Zeile von Kreis 3. Unsichtbar, reine Fläche. */
.map-menu-group.is-active .map-menu-labels::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    /* bis an den rechten Bildrand, also auch über den Streifen zwischen Text und Kreisen */
    right: calc(var(--label-inset) * -1);
    left: -100vw;
}
.map-menu-labels label {
    /* positioniert, damit die Beschriftung über der Trefferfläche oben liegt */
    position: relative;
    display: flex;
    align-items: center;
    justify-content: flex-end;   /* Text rechtsbündig */
    box-sizing: border-box;
    height: var(--menu-row);     /* erste Zeile sitzt damit auf der Kreismitte */
    font-weight: 200;            /* Geist ExtraLight – wie der Kartenname (doku/27) */
    /* Schriftgröße an den KREIS gekoppelt, nicht an die Fensterbreite: im Entwurf ist die
       Zeile knapp drei Viertel so hoch wie ein Kreis, und dieses Verhältnis soll auch dann
       stimmen, wenn die Kreise auf flachen Fenstern über den vh-Wert kleiner werden. */
    font-size: calc(var(--menu-dot) * 0.72);
    line-height: 1.1;
    color: #fff;
    text-align: right;
    white-space: nowrap;
    cursor: pointer;
}
/* EINZEILIGE Gruppen (Kreis 1/3/4): der Text sitzt bei voller Zeilenhöhe zu tief – mittig
   über der (weiter unten verschobenen) Linie statt klar darüber (Meldung 09.09.2026). Ein
   `padding-bottom` zieht NUR den Text nach oben: bei box-sizing:border-box bleibt die
   Zeilenhöhe (= Trefferfläche) unverändert, aber `align-items: center` zentriert ihn jetzt
   in der kleineren (hier: auf 0 geschrumpften) Fläche darüber – der Text landet damit auf
   Höhe der ZEILENOBERKANTE = Kreisoberkante, also spürbar über der auf die Kreismitte
   gerückten Linie, statt nur knapp. Die Linie selbst hängt an ::after weiter unten
   (bottom:0 zielt auf die BORDER-Kante, nicht die Polsterkante – Polster verschiebt daher
   nur den Text, nie die Linie). Bei der ZWEIZEILIGEN Gruppe (Kreis 2) übernimmt der eigene
   Versatz an .map-menu-group.is-double .map-menu-labels bereits die richtige Höhe für
   beide Einträge – dort NICHT zusätzlich polstern. */
body:not(.mapmenu-classic) .map-menu-group:not(.is-double) .map-menu-labels label {
    /* DESKTOP, Wunsch 14.10.2026: Abstand Menüname -> untere Linie = Radius eines Kreises
       (Ø/2, Kreisunterkante bis Kreismitte). Die Linie liegt --menu-gap über dem Zeilenende
       (::after unten), der Text sitzt darüber am Boden der Zeile. Touch überschreibt das
       im @media(hover:none)-Block. */
    align-items: flex-end;
    padding-bottom: calc(var(--menu-gap) + var(--menu-dot) / 2 - 0.2em);   /* 0,2em = Unterlänge: gemessen wird ab Grundlinie */
}
/* Kreis 2 (zwei Einträge): erster Eintrag ebenso Ø/2 über der Trennlinie (bottom:0). */
body:not(.mapmenu-classic) .map-menu-group.is-double .map-menu-labels label:first-child {
    align-items: flex-end;
    padding-bottom: calc(var(--menu-dot) / 2 - 0.2em);
}
/* Die feine Linie steht unter dem ERSTEN Eintrag der Gruppe: bei einzeiligen Gruppen als
   Unterstreichung, bei Kreis 2 als Trenner zwischen den beiden Einträgen.
   SEIT 13.08.2026 läuft sie DURCH BIS AN DEN RECHTEN BILDRAND: als border-bottom endete
   sie an der rechten Textkante (0,72 Kreisdurchmesser vor dem Rand) – der Streifen bis zum
   Rand, auf dem die Halbkreise sitzen, blieb ohne Linie. Deshalb ein eigenes Element
   (::after), das über die Blockkante hinausreicht; `right` ist derselbe Wert, um den der
   Beschriftungsblock vom Rand eingerückt ist, mit umgekehrtem Vorzeichen. */
.map-menu-labels label:first-child {
    border-bottom: 1px solid rgba(255, 255, 255, 0.85);
}
/* Im neuen Band-Menü übernimmt das ::after unten die Linie (bis zum Bildrand). */
body:not(.mapmenu-classic) .map-menu-labels label:first-child {
    border-bottom: none;
}
body:not(.mapmenu-classic) .map-menu-labels label:first-child::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    right: calc(var(--label-inset) * -1);
    height: 1px;
    background: rgba(255, 255, 255, 0.85);
    pointer-events: none;
}
/* Die Linie lag bei EINZEILIGEN Gruppen (Kreis 1/3/4) am unteren Zeilenrand – deutlich
   TIEFER als die Kreismitte, weil die Zeile genauso hoch ist wie ein Kreis PLUS Abstand.
   Bei der ZWEIZEILIGEN Gruppe (Kreis 2) übernimmt der eigene Versatz an
   .map-menu-group.is-double .map-menu-labels bereits die richtige Höhe – hier NICHT noch
   einmal verschieben. Soll (Kundenvorlage „distances on smartphone.pdf", 28.09.2026,
   nachgemessen gegen die Original-Entwürfe uploads/main-menu/menu-point1/4/5-hovered.jpg):
   die Linie sitzt am UNTEREN Rand des dabei ausgeblendeten Halbkreises, NICHT in dessen
   Mitte – die Meldung vom 09.09.2026 hatte das falsch nachgebaut (Kreismitte statt
   Kreisunterkante). Rechnung: Kreisunterkante liegt „gap" oberhalb des Zeilenendes
   (Zeile = Kreis + Abstand hoch, Kreismitte sitzt Ø/2 unter der Zeilenoberkante, also
   Ø/2 + Abstand unter der Zeilenoberkante = Zeilenhöhe − Abstand vom Zeilenende). */
body:not(.mapmenu-classic) .map-menu-group:not(.is-double) .map-menu-labels label:first-child::after {
    bottom: var(--menu-gap);
}
/* Die Radiobuttons tragen weiterhin die Auswahl (name="mapView" → selectMap), sind aber
   unsichtbar; sichtbar ist nur der Kartenname. Nicht display:none – sonst wären sie nicht
   mehr mit der Tastatur erreichbar. */
body:not(.mapmenu-classic) .map-menu-labels input[type="radio"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}
body:not(.mapmenu-classic) .map-menu-labels label:focus-within span {
    outline: 2px solid #fff;
    outline-offset: 4px;
}
/* Die aktive Kartenansicht ist etwas kräftiger gesetzt. */
body:not(.mapmenu-classic) .map-menu-labels input[type="radio"]:checked + span {
    font-weight: 300;
}

/* --- TOUCH-GERÄTE (Handy + Tablet): ALLE Menüpunkte auf einmal ---------------
   Wunsch 13.08.2026. Mit Maus folgt die Beschriftung dem Zeiger – es ist immer genau eine
   Zeile aufgeklappt. Auf einem Touchscreen gibt es keinen Zeiger: dort brauchte es bisher
   zwei Tipper (erst die Zeile aufklappen, dann wählen) und man sah nicht, welche Karten es
   überhaupt gibt. Sobald das Menü offen ist, stehen deshalb ALLE fünf Kartennamen
   untereinander und jeder ist mit einem Tipp zu wählen.

   Bedingung ist `(hover: none)` – ein Gerät ohne Zeiger – und NICHT die Fensterbreite,
   damit auch Tablets im Querformat dazugehören. Bewusst als Media-Query statt als
   JS-gesetzte Klasse: dieselbe Bedingung fragt script.js über menuAllRows() ab, beide
   können dadurch nicht auseinanderlaufen.

   Layout SEIT 28.09.2026 (Kundenvorlage „distances on smartphone.pdf"): Die vier Kreise
   bleiben ein gleichmäßiges Raster (--menu-row je Kreis, unverändert). Die frühere Fassung
   holte die Beschriftungsblöcke dafür aus ihrer absoluten Lage in den normalen Fluss – jede
   Gruppe wurde dadurch so hoch wie ihre Einträge, und die ZWEIZEILIGE Gruppe (Kreis 2)
   beanspruchte dadurch ZWEI volle Rasterzeilen statt einer. Weil die Kreise selbst
   gleichmäßig geblieben sind, rutschten dadurch Kreis 3 und Kreis 4 gegenüber ihren
   Beschriftungen um eine ganze Zeile auseinander (Meldung 28.09.2026: Linien landeten am
   falschen Kreis, Kreis 1/3/4 ohne Abstand aneinandergeklebt).
   Der Fix: mobil bleibt JEDE Gruppe exakt eine Rasterzeile hoch UND absolut positioniert,
   genau wie im Desktop-Hover-Zustand einer einzelnen aufgeklappten Gruppe (s. oben) – nur
   dass hier ALLE Gruppen dauerhaft „aktiv" sind statt nur eine per Hover. */
@media (hover: none) {
    :root { --menu-gap: calc(var(--menu-dot) * 0.17); }
    /* Alle Beschriftungsblöcke dauerhaft sichtbar/klickbar statt nur die per Hover
       „aktive" Gruppe – Hover gibt es auf einem Touchscreen nicht (s. o.). position/top
       bleiben die Desktop-Werte (absolut, Doppel-Gruppe nach oben versetzt). */
    body:not(.mapmenu-classic) .map-menu-labels {
        opacity: 1;
        pointer-events: auto;
        /* Wunsch 28.09.2026: Abstand zwischen Text und den Halbkreisen = Abstand der
           Halbkreise untereinander (--menu-gap). Die Kreismitte liegt auf dem Bildrand,
           sichtbar ist also ein Radius (Ø/2); die rechte Textkante sitzt Radius + Abstand
           vom Rand. Linie (::after) und Trefferfläche (::before) folgen über die Variable. */
        --label-inset: calc(var(--menu-dot) * 0.5 + var(--menu-gap));
    }
    /* Die Doppel-Gruppe (Kreis 2) bekommt hier eine EIGENE, kompaktere Fassung statt der
       Desktop-Rasterzeile pro Eintrag: Am Desktop zeigt Hover immer nur EINE Gruppe
       gleichzeitig – ragt deren zweiter Eintrag dabei optisch in die (unsichtbare) Zeile
       von Kreis 3 hinein, fällt das nie auf. Mobil stehen dagegen ALLE Gruppen gleichzeitig
       offen: mit der vollen Rasterzeile pro Eintrag überlappte der zweite Eintrag
       („Steuerbefreiungen…") dabei sichtbar den Text von Kreis 3 („Art. 17 DBA…").
       Mit Ø/2 Zeilenhöhe pro Eintrag (statt Ø + Abstand) und ohne den Verschiebe-Versatz
       (die Basisregel oben setzt bereits top:0) berührt der erste Eintrag oben genau die
       Oberkante seiner eigenen Zeile, und der zweite Eintrag endet einen Abstand VOR der
       Oberkante von Kreis 3 – exakt so viel Luft wie zwischen den Kreisen selbst. Die
       Trennlinie bleibt exakt auf der Kreismitte (Rechnung: erster Eintrag endet bei
       Zeilenoberkante + Ø/2 = Kreismitte). */
    body:not(.mapmenu-classic) .map-menu-group.is-double .map-menu-labels {
        top: 0;
    }
    body:not(.mapmenu-classic) .map-menu-group.is-double .map-menu-labels label {
        height: calc(var(--menu-dot) * 0.5);
    }
    /* EINZEILIGE Gruppen (Kreis 1/3/4 = Menüpunkte 1, 4, 5): Wunsch 28.09.2026, Abstand
       Text -> untere Linie auf ein Viertel verkleinern. Der Desktop-Trick (padding-bottom
       = volle Zeilenhöhe + align-items:center, s. oben) zentriert den Text auf der
       Zeilenoberkante und lässt ihn dadurch bewusst nach oben überstehen – das ergibt den
       (für die Linien-Ausrichtung an der Kreisunterkante gedachten) großen Leerraum
       zwischen Text und Linie. Mobil bleibt die Linie an derselben Stelle (Kreisunterkante,
       s. .map-menu-group:not(.is-double) .map-menu-labels label:first-child::after weiter
       oben, hier NICHT verändert), nur der Text rückt näher heran: align-items:flex-start
       schiebt die Textzeile mit padding-top so weit herunter, dass ihr Grundlinienabstand
       zur Linie nur noch ein Viertel des ursprünglichen Werts ist (am echten Kartenbild
       nachgemessen, s. tools/verify_map_menu.py --touch). */
    body:not(.mapmenu-classic) .map-menu-group:not(.is-double) .map-menu-labels label {
        /* Text sitzt über der Linie: Abstand Textunterkante -> Linie = 0,4 Schriftgrößen
           (em), Linie liegt --menu-gap über dem Zeilenende. Bezogen auf die Schrift statt
           auf feste Pixel, damit es auf dem Tablet (größere Kreise/Schrift) genauso
           aussieht wie auf dem Handy (44 px / 17 px ergeben dieselben Werte wie vorher). */
        align-items: flex-end;
        padding-top: 0;
        /* Wunsch 14.10.2026 (Handy + Tablet): Grundlinie -> Linie = doppelter Abstand
           Textende -> Halbkreis (2 × --menu-gap, s. --label-inset oben; Wunsch 14.10.2026 nachträglich verdoppelt). Linie liegt --menu-gap über dem
           Zeilenende, 0,2em = Unterlänge. */
        padding-bottom: calc(var(--menu-gap) * 3 - 0.2em);
    }
    /* Wunsch 29.09.2026: Punkt 1/2/4/5 alle um den vorherigen Sichtabstand (5 px, Grundlinie -> Linie) nach oben. Kreis 2: erster Eintrag hat denselben Abstand zur Linie darunter
       wie Punkt 1/4/5 (gemessen: 0,6 px Textunterkante -> Linie; 0,6 px Polster gleicht das
       aus), zweiter Eintrag ~4 px nach unten (weg von der Linie darüber). Bei
       align-items:center verschiebt Polster den Text um sein halbes Maß. */
    body:not(.mapmenu-classic) .map-menu-group.is-double .map-menu-labels label:first-child {
        align-items: flex-end;
        /* wie Punkt 1/4/5: Grundlinie -> Linie = 2 × --menu-gap (Linie bei bottom:0) */
        padding-bottom: calc(var(--menu-gap) * 2 - 0.2em);
    }
    body:not(.mapmenu-classic) .map-menu-group.is-double .map-menu-labels label:last-child {
        align-items: flex-start;
        padding-top: 0.33em;
    }
    /* Schrift der Menüzeilen an die Kreisgröße gekoppelt (Handy: 44 px Kreis = 17 px
       Schrift), Abstand der Kreise wie auf dem Handy. Gilt für alle Touch-Geräte, also auch
       das Tablet im Querformat, wo die Desktop-Schrift (0,72 × Ø) die Zeilen sprengte und
       die Linien durch den Text liefen (Meldung 14.10.2026). */
    body:not(.mapmenu-classic) .map-menu-labels label {
        font-size: calc(var(--menu-dot) * 0.386);
    }
    /* Tablet (breiter Bildschirm): Schrift darf größer sein als auf dem Handy (Wunsch
       14.10.2026); 0,44 × Ø ist das Maximum, bei dem die zweizeilige Gruppe noch in ihre
       Rasterzeile passt. */
    @media (min-width: 700px) {
        body:not(.mapmenu-classic) .map-menu-labels label {
            font-size: calc(var(--menu-dot) * 0.44);
        }
    }
    /* Die Kreise tragen hier keine Zuordnung zu genau einer aufgeklappten Zeile mehr (alle
       stehen gleichzeitig offen). Sie bleiben als Umschalter stehen, aber keiner wird mehr
       ausgeblendet – das „is-hidden" gehört zum Zeiger-Betrieb. */
    body.mapmenu-open #mapMenuToggle .menu-dot.is-hidden {
        opacity: 1;
    }
}

/* --- TABLET IM QUERFORMAT: Zurücksetzen-Symbol wie auf dem Handy (Wunsch 14.10.2026) ---
   Das Symbol (oben links neben den drei Punkten, im offenen Menü unten links im Band) steht
   bisher nur im Handy-Block (Hoch-/Schmalformat). Ein Tablet im Querformat fällt durch
   diese Bedingung und bekam den Desktop-Aufbau, in dem der Knopf im Testbereich hinter dem
   „T" steckt. Hier dieselben Regeln für Touch-Geräte ohne Handy-Bedingung. Der Wrapper
   #testMenu darf dabei weder transformiert noch ausgeblendet sein (ein transform macht ihn
   zum Bezugsrahmen für `fixed`, opacity wirkt auf den Knopf): das Zoom-Panel darin blendet
   stattdessen selbst ein und aus. */
@media (hover: none) and (min-width: 501px) and (min-aspect-ratio: 1/1) {
    body:not(.mapmenu-classic) #testMenu {
        /* `fixed` statt `absolute`: ohne das transform (s. o.) ragte der Wrapper unten über
           das Fenster hinaus, die Seite wurde scrollbar und Safari schob die ganze Karte
           nach oben (Meldung 14.10.2026). Mittig per top/bottom + margin: auto. */
        position: fixed;
        top: 0;
        bottom: 0;
        height: max-content;
        margin: auto 0;
        max-height: calc(100vh - 24px);
        transform: none;
        opacity: 1;
        visibility: visible;
        pointer-events: none;
        transition: none;
    }
    body:not(.mapmenu-classic) #zoomTestPanel {
        opacity: 0;
        visibility: hidden;
        transition: opacity 250ms ease, visibility 0s linear 250ms;
    }
    body.testmenu-open:not(.mapmenu-classic) #zoomTestPanel {
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
        transition: opacity 250ms ease, visibility 0s linear 0s;
    }
    body:not(.mapmenu-classic) #testMenu > #resetBtn {
        position: fixed;
        top: 8px;
        right: 52px;
        left: auto;
        z-index: 41;
        width: 44px;
        height: 44px;
        padding: 0;
        background: none;
        border: none;
        border-radius: 50%;
        box-shadow: none;
        pointer-events: auto;
        transition: opacity var(--menu-anim) var(--menu-ease);
    }
    body.mapmenu-open:not(.mapmenu-classic) #testMenu > #resetBtn {
        opacity: 0;
        pointer-events: none;
    }
    body:not(.mapmenu-classic) #resetBtn .reset-text {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    body:not(.mapmenu-classic) #resetBtn .kbd-hint { display: none; }
    body:not(.mapmenu-classic) #resetBtn .icon-undo,
    body:not(.mapmenu-classic) #resetBtnMenu .icon-undo {
        display: block;
        width: 30px;
        height: 30px;
        filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.35));
    }
    /* im offenen Band: links auf Höhe der letzten Menüzeile */
    body:not(.mapmenu-classic) #resetBtnMenu {
        position: absolute;
        top: calc(var(--menu-row) * (var(--menu-count) - 1));
        left: 6px;
        height: var(--menu-row);
        z-index: 3;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 40px;
        padding: 0;
        background: none;
        border: none;
        border-radius: 50%;
        pointer-events: auto;
    }
    #resetBtn .icon-undo.spin,
    #resetBtnMenu .icon-undo.spin {
        animation: reset-spin-tablet 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
    }
    @keyframes reset-spin-tablet {
        from { transform: rotate(0deg); }
        to   { transform: rotate(360deg); }
    }
}

/* --- Prototyp-Panel (Rückweg, Häkchen „Menu-prototype" im Testbereich) ------ */
/* Schwebendes weißes Panel rechts unter dem Vier-Kreise-Umschalter (top:120 = dessen
   Unterkante ~100px + Abstand). Optik bewusst identisch zu #zoomTestPanel/#resetBtn,
   damit alles als ein Bedienbereich gelesen wird. Die Gruppen-Hüllen des neuen Designs
   werden dafür per `display: contents` aus dem Kasten-Baum genommen – die fünf Zeilen
   stehen dann wieder als flache Liste untereinander. */
body.mapmenu-classic #mapMenu {
    top: 120px;
    right: 10px;
    width: 230px;
    max-width: calc(100vw - 20px);
    box-sizing: border-box;
    padding: 4px 12px 10px;
    background: white;
    border: 1px solid #aaa;
    border-radius: 4px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
body.mapmenu-classic.mapmenu-open #mapMenu { pointer-events: auto; }
body.mapmenu-classic .map-menu-group,
body.mapmenu-classic .map-menu-labels { display: contents; }
body.mapmenu-classic #mapMenu legend {
    padding: 0 4px;
    font-size: 13px;
    font-weight: 500;   /* Geist Medium – kräftigster mitgelieferter Schnitt */
    color: #333;
}
body.mapmenu-classic #mapMenu label {
    display: flex;
    align-items: flex-start;   /* mehrzeilige Titel bleiben am Radiobutton ausgerichtet */
    justify-content: flex-start;
    gap: 8px;
    height: auto;
    padding: 5px 2px;
    font-size: 13px;
    font-weight: 400;
    line-height: 1.3;
    color: #333;
    text-align: left;
    white-space: normal;
    border: none;
    cursor: pointer;
    border-radius: 3px;
}
body.mapmenu-classic #mapMenu label:hover { background: #f2f2f2; }
body.mapmenu-classic #mapMenu input[type="radio"] {
    flex: none;
    margin: 1px 0 0;
    accent-color: #d97b0f;    /* Auswahl-Orange der Karte (COLORS.SELECTED) */
    cursor: pointer;
}
/* Die aktive Kartenansicht hervorheben – der Radiobutton allein ist bei fünf
   ähnlich langen Zeilen schnell übersehen. */
body.mapmenu-classic #mapMenu input[type="radio"]:checked + span { font-weight: 500; color: #000; }
body.mapmenu-classic #mapMenu label:focus-within { outline: 2px solid #d97b0f; outline-offset: 1px; }

#countrySearchInput {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 10px;
    font-size: 14px;
    border: 1px solid #aaa;
    border-radius: 4px;
    background: white;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

/* Kurz eingeblendete Trefferzahl („n Treffer"), rechtsbündig über dem Eingabefeld.
   top/right:0 + gleiches padding/font wie #countrySearchInput → Text sitzt auf der
   Feldzeile. pointer-events:none → Klicks gehen weiter ins Feld. Ein-/Ausblenden per
   opacity via JS (display:none Grundzustand, wie #countryLabel). */
#searchCount {
    position: absolute;
    top: 0;
    right: 0;
    padding: 8px 10px;
    font-size: 14px;
    color: #757575;
    pointer-events: none;
    white-space: nowrap;
    display: none;
}

/* DESKTOP: Liste klappt NACH OBEN auf (die Suchleiste steht unten am Bildschirmrand).
   Absolut über dem Eingabefeld statt im Fluss – dadurch bleibt #searchCount (top:0)
   weiterhin auf der Feldzeile. Mobil steht die Leiste oben und die Liste wieder im
   normalen Fluss darunter (s. @media-Block). */
#countrySearchList {
    position: absolute;
    bottom: 100%;
    left: 0;
    right: 0;
    list-style: none;
    margin: 0 0 4px;
    padding: 0;
    background: white;
    border: 1px solid #aaa;
    border-radius: 4px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25);
    --row-h: 34px;                         /* Zeilenhöhe = .country-search-item height */
    max-height: calc(var(--row-h) * 4);    /* genau 4 sichtbare Zeilen, dann scrollen */
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;                   /* vertikales Scrollen (SVG hat touch-action:none) */
    overscroll-behavior: contain;
}

#countrySearchList[hidden] { display: none; }

.country-search-item {
    box-sizing: border-box;
    height: 34px;                          /* == --row-h → exakt 4 Zeilen sichtbar */
    padding: 7px 10px;
    font-size: 14px;
    line-height: 20px;
    color: #1a1a1a;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.country-search-item:hover,
.country-search-item.active {
    background: #eef3fb;
}

/* --- InfoBox (unten, kurzer Text pro Land) --------------------------------- */
#infoBox {
    position: absolute;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    width: 33%;
    /* 1/3 der Bildschirmbreite */
    max-width: 400px;
    background: rgba(255, 255, 255, 0.9);
    padding: 12px 18px;
    border-radius: 8px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
    font-size: 14px;
    color: #333;
    text-align: center;
    z-index: 20;
    pointer-events: none;
    /* Klicks gehen durch zur Karte */
}

#infoText {
    word-wrap: break-word;
}

/* Die Leiste ist derzeit abgeschaltet (script.js: INFOBOX_ENABLED = false), das JS setzt
   dafür das hidden-Attribut. Eigene Regel nötig, weil #infoBox oben display-wirksame
   Eigenschaften trägt und das Browser-Default für [hidden] sonst überstimmt würde. */
#infoBox[hidden] {
    display: none;
}

/* --- Landes-Sticker (Beschriftung, folgt dem Land) -------------------------- */
/* Design: senkrechte Linie links (#6d6e71), rechts daneben der Ländername in
   Geist ExtraLight (#6d6e71), darunter zwei Info-Zeilen in Geist Medium
   (#939598). #germanyLabel ist der Sticker Deutschlands in der Fokus-Ansicht – gleiches
   Design, aber ohne Info-Zeilen.
   Die FRÜHERE Beschriftung (fettes schwarzes Label auf weißem Kissen) ist vollständig
   gesichert und wieder aktivierbar: doku/22_BESCHRIFTUNG_BACKUP.md. */
.country-sticker {
    position: absolute;
    pointer-events: none;
    /* Die senkrechte Linie – seit 13.08.2026 deutlich dünner (vorher 2px). */
    border-left: 1px solid #6d6e71;
    padding-left: 12px;
    /* Standard: linksbündig am Anker (rechts neben dem Land), vertikal mittig */
    transform: translate(0, -50%);
    white-space: nowrap;
    /* über dem Popup (30) und allen übrigen Overlays, damit das nach Auswahl kurz
       mittig eingeblendete Ländernamen-Label nicht vom Popup verdeckt wird */
    z-index: 50;
    display: none;
}

/* Auswahl-Label (kurz mittig auf der Landfläche) – dort mittig statt linksbündig.
   Dieses Label liegt AUF der Landfläche und erscheint auch beim Hover über Länder ohne
   eigene Karte. Auf dunkleren Kartenfarben (Grün, Blau) war das helle Grau #6d6e71 schlecht
   lesbar. Es bekommt deshalb einen weichen weißen Schein als Untergrund – gestaffelte
   drop-shadows statt eines Kissens: kein sichtbarer Kasten, keine Kante, das schlanke
   Sticker-Design (senkrechte Linie + Thin-Schrift) bleibt unverändert. drop-shadow (nicht
   text-shadow), damit auch die senkrechte Linie den Schein bekommt.
   Rückweg: diesen filter entfernen.

   Lange Ländernamen dürfen hier UMBRECHEN: Der Name muss immer VOLLSTÄNDIG lesbar sein –
   auch wenn man tief in ein Land gezoomt hat und nur noch ein Stück davon sieht. Einzeilig
   („Vereinigte Arabische Emirate", „Zentralafrikanische Republik") lief er sonst über den
   Bildrand hinaus und wurde rechts abgeschnitten. Deshalb `white-space: normal` plus eine
   Höchstbreite: Der Umbruch greift NUR, wenn es einzeilig nicht ins Fenster passt – dann
   steht jedes Wort in einer eigenen Zeile, nichts wird beschnitten. Dass das Label danach
   auch komplett im Bild LIEGT, besorgt flashCountryLabel (script.js). */
.country-sticker.centered {
    transform: translate(-50%, -50%);
    /* OHNE senkrechte Linie (Wunsch 13.08.2026): Dieser Sticker steht MITTIG auf der
       Landfläche – bei den weißen Ländern ist er nur der Ländername. Eine Linie links
       (oder bei .flip rechts) davon hing dort ohne Bezug in der Fläche. Der Einzug fällt
       damit ebenfalls weg, sonst stünde der Name nicht mehr mittig. */
    border-left: none;
    border-right: none;
    padding-left: 0;
    padding-right: 0;
    white-space: normal;
    /* `width: max-content` ist hier PFLICHT und kein Beiwerk: Ein absolut positioniertes
       Element mit `left` bekommt sonst nur die Restbreite bis zum rechten Rand als
       Platzangebot – ein Label kurz vor der rechten Kante bräche dann in lauter
       Einbuchstaben-Zeilen um, obwohl `transform: translate(-50%,-50%)` es danach wieder
       nach links zieht. Mit max-content zählt allein die Höchstbreite unten. */
    width: max-content;
    /* border-box, damit Linie (2px) und Einzug (12px) in der Höchstbreite STECKEN – sonst
       ist der Kasten am Ende genau um diese 14px breiter als gedacht. */
    box-sizing: border-box;
    max-width: var(--sticker-max-w, calc(100vw - 24px));
    overflow-wrap: break-word;   /* Notbremse für ein einzelnes überlanges Wort */
    filter: drop-shadow(0 0 2px rgba(255, 255, 255, 0.95))
            drop-shadow(0 0 5px rgba(255, 255, 255, 0.9))
            drop-shadow(0 0 12px rgba(255, 255, 255, 0.75));
}

/* Die frühere Beschriftung (LABEL_CLASSIC) bringt ihr eigenes weißes Kissen mit – dort
   wäre der Schein doppelt gemoppelt; sie bleibt auch einzeilig wie früher. */
.country-sticker.centered.classic {
    filter: none;
    white-space: nowrap;
    width: auto;
    max-width: none;
}

/* Umgeklappt: Ist rechts neben dem sichtbaren Landesteil kein Platz, sitzt der Sticker
   LINKS vom Land. Dann gehört die senkrechte Linie nach rechts – also wieder zum Land hin –
   und der Text wird rechtsbündig. `left` ist in diesem Fall die RECHTE Kante des Stickers. */
.country-sticker.flip {
    border-left: none;
    border-right: 1px solid #6d6e71;   /* dünner seit 13.08.2026, s. .country-sticker */
    padding-left: 0;
    padding-right: 12px;
    text-align: right;
    transform: translate(-100%, -50%);
}

/* Mittiger Namens-Sticker OHNE Linie – auch wenn er (aus einer vorherigen Platzierung)
   noch die Klasse .flip trägt: die Regel oben würde sonst die rechte Linie zurückbringen,
   weil sie später im Stylesheet steht. Reihenfolge-Absicherung, kein zweiter Zustand. */
.country-sticker.centered.flip {
    border-right: none;
    padding-right: 0;
}

.sticker-name {
    display: block;
    font-family: var(--font);
    font-weight: 200;                 /* Geist ExtraLight */
    /* seit 04.09.2026 kleiner (Grundstellung) + Regler „Sticker-Schrift" im T-Testbereich,
       s. script.js --sticker-scale. Gilt für FA, LDA-Titel-Sticker und den mittigen
       Ländernamen bei Ländern ohne eigene Karte (dieselbe Klasse). */
    font-size: calc(26px * var(--sticker-scale, 1));
    line-height: 1.15;
    letter-spacing: 0.2px;
    color: #6d6e71;
}

/* Info-Zeilen nur, wenn es welche gibt (Deutschland bekommt keine) – gesteuert über
   die Klasse .with-info am Sticker, damit auch der Abstand darüber wegfällt. */
.sticker-info {
    display: none;
    margin-top: 6px;
}

.country-sticker.with-info .sticker-info {
    display: block;
}

.sticker-info-line {
    display: block;
    font-family: var(--font);
    font-weight: 500;                 /* Geist Medium */
    font-size: calc(14px * var(--sticker-scale, 1));  /* s. .sticker-name */
    line-height: 1.45;
    color: #939598;
}

/* Karten-Hinweis-Link im Klick-Label (laws.json -> mapHint; z. B. VAE: „Art.-17-DBA …"
   führt zur Art.-17-Karte). Blau + unterstrichen wie ein klassischer Link und wieder
   klickbar – der Sticker selbst steht auf pointer-events: none. Sichtbar nur mit
   .with-maplink, gesetzt in flashCountryLabel (script.js). */
.sticker-maplink {
    display: none;
    font-family: var(--font);
    font-weight: 500;                 /* Geist Medium */
    font-size: 14px;
    line-height: 1.45;
    margin-top: 6px;
    color: #0b62c4;
    text-decoration: underline;
    cursor: pointer;
    pointer-events: auto;
}

.country-sticker.with-maplink .sticker-maplink {
    display: block;
}

/* FRÜHERE Beschriftung – 1:1 erhalten und über LABEL_CLASSIC = true (script.js) wieder
   aktivierbar: fetter schwarzer Name auf weißem Kissen, mittig auf der Landfläche, keine
   Info-Zeilen, kein Deutschland-Sticker. Doku: doku/22_BESCHRIFTUNG_BACKUP.md */
.country-sticker.classic {
    border-left: none;
    padding: 2px 6px;
    background: rgba(255, 255, 255, 0.7);
    border-radius: 4px;
    transform: translate(-50%, -50%);
}

.country-sticker.classic .sticker-name {
    font-family: inherit;
    font-size: 16px;
    font-weight: bold;
    letter-spacing: normal;
    line-height: normal;
    color: #101010;
}

.country-sticker.classic .sticker-info {
    display: none;
}

/* --- Detail-Ansicht (Textspalte rechts neben dem geklickten Land) ----------- */
/* Erscheint beim Klick auf ein Land mit eigener Karte: das Land zoomt in die linke
   Spalte, hier stehen rechts daneben Name, sechs Kennzahlen-Zeilen und der Absatztext.
   Schrift-/Farbwelt wie die Landes-Sticker: Name in Geist ExtraLight (#6d6e71), die
   Kennzahlen in Geist Medium (#939598), der Absatztext in Geist Light (#58595b).
   Gleiche Ein-/Ausblendzeit wie die Fokus-Ansicht (400 ms).
   Doku: doku/23_LAND_DETAIL_ANSICHT.md */
#countryDetail {
    /* Schriftgrößen skalieren mit der Fensterbreite, damit das Verhältnis zum
       daneben liegenden Land auf jedem Schirm gleich wirkt. */
    --detail-name: clamp(20px, 3.1vw, 46px);
    --detail-fact: clamp(11px, 1.55vw, 23px);
    --detail-body: clamp(9px, 1.02vw, 15px);
    --detail-line: calc(var(--detail-body) * 1.8);
    /* fixed statt absolute (Meldung 14.10.2026, Moldau in iOS-Chrome): Die Karte ist seit dem
       Fix vom selben Tag fixed und füllt den sichtbaren Bereich. Prozentwerte einer absolut
       platzierten Spalte beziehen sich dagegen auf body (height:100%), und der ist in iOS-Chrome
       kürzer als der sichtbare Bereich: top:35 % lag dadurch im Land statt darunter. */
    position: fixed;
    left: 36%;
    top: 8%;
    /* Rechts bleibt der Streifen der Bedienelemente frei (Panel 230px + 2×10px Abstand):
       sonst liefen Kennzahlen und Absatztext unter die Menüleiste der Kartenansichten
       (und unter das Zoom-Test-Panel). Breite ergibt sich aus left/right → passt sich
       der Fensterbreite an. */
    /* Der volle Streifen von 250px gilt nur, wenn ein Panel wirklich offen ist (s. u.) und auf
       breiten Fenstern. Im Normalzustand stehen rechts nur Vier-Kreise-Umschalter und „T"
       (je ~50px): auf einem schmalen Desktop-Fenster blieb sonst fast ein Drittel der Breite
       leer (Meldung 12.10.2026, Safari-Fenster ~790px). Stufenlos von 80px (bis 900px
       Fensterbreite) auf 250px (ab 1400px). */
    right: clamp(80px, calc(80px + (100vw - 900px) * 0.34), 250px);
    /* Sicherung gegen sehr niedrige Fenster: der Block endet immer im Bild. Bis 10.09.2026
       lief das über block-Layout + festes 16-Zeilen max-height auf .detail-text – dabei
       konnte .detail-text unten aus DIESEM overflow:hidden herausragen (Name+Kennzahlen+
       16 Zeilen zusammen höher als 86%), und genau der herausragende Rest war dann per
       Scrollen NIE erreichbar (er lag ja außerhalb des sichtbaren Bereichs). Jetzt Flex-
       Spalte: Name/Kennzahlen behalten ihre natürliche Höhe (flex-shrink:0 unten), .detail-
       text bekommt IMMER genau den Rest (flex:1 1 auto; min-height:0) und schneidet sich
       dadurch nie selbst ab – bei wenig Platz wird die Box kleiner, es bleibt aber alles
       über ihren eigenen Scrollbalken erreichbar. */
    display: none;             /* JS schaltet auf "flex" um (showDetailPanel) */
    flex-direction: column;
    /* Unten Abstand zur Fußzeile (Copyright | Datenschutz | Impressum): in Chrome (Tablet quer,
       niedrigere Bühne durch die große Tab-/Adressleiste) lief die letzte Textzeile bis an die
       Fußzeile (Meldung 14.10.2026). Der Block endet jetzt mindestens 70px über dem Rand. */
    max-height: min(86%, calc(92% - 70px));
    overflow: hidden;
    opacity: 0;
    pointer-events: none;
    z-index: 40;
}

/* Offenes Kartenmenü liegt VOR dem LDA-Text: sonst stand der Ländername scharf über dem Band
   (Meldung 14.10.2026). Mit z-index unter dem Band (8) scheint der Text nur noch weich
   gezeichnet durch, genau wie der Kartenname (#mapChrome). */
body.mapmenu-open:not(.mapmenu-classic) #countryDetail {
    z-index: 7;
}

/* Ist ein Panel rechts offen (Testbereich oder Prototyp-Menü, je 230px breit), bleibt der
   volle Streifen frei, sonst läge der Text darunter. */
@media (min-width: 701px) {
    body.testmenu-open #countryDetail,
    body.mapmenu-classic #countryDetail { right: 250px; }
}

/* Trägt die senkrechte Linie für Name + DBA-Info GEMEINSAM (s. Kommentar in index.html) –
   dieselbe Linie wie am Sticker, jetzt aber auf den Wrapper verschoben statt auf den Namen
   allein, damit sie mit der (mobil eingeblendeten) .detail-info mitwächst. */
.detail-heading {
    border-left: 2px solid #6d6e71;
    padding-left: 0.35em;
    flex: none;                 /* Flex-Item in #countryDetail: eigene Höhe, nicht schrumpfen */
}

/* pointer-events:auto seit 18.09.2026 wie .detail-text weiter unten: Ländername soll sich
   markieren/kopieren lassen (Kundenwunsch), sonst gilt dieselbe Regel (s. dortiger
   Kommentar) – ein Klick ohne Auswahl beendet die LDA trotzdem, s. script.js. */
.detail-name {
    display: block;
    font-family: var(--font);
    font-weight: 200;                  /* Geist ExtraLight */
    font-size: var(--detail-name);
    line-height: 1.1;
    letter-spacing: 0.2px;
    color: #6d6e71;
    pointer-events: auto;
}

/* DBA-Info-Zeilen unter dem Namen – dieselben Zeilen/Farben wie am FA-Sticker
   (.sticker-info-line), hier aber NUR mobil sichtbar (s. u.): auf dem Desktop zeigt sie
   schon die Fokus-Ansicht vor dem Klick, auf dem Handy gibt es keine Fokus-Ansicht (kein
   Hover), darum stehen sie hier unter dem Namen in der Detail-Ansicht selbst. */
.detail-info {
    display: none;
    margin-top: 0.3em;
}

.detail-info-line {
    display: block;
    font-family: var(--font);
    font-weight: 500;                  /* Geist Medium, wie .sticker-info-line */
    font-size: calc(var(--detail-fact) * 0.82);
    line-height: 1.4;
    color: #939598;
    pointer-events: auto;              /* markierbar wie .detail-name/.detail-facts */
}

/* Die sechs Kennzahlen-Zeilen: Hauptstadt, Sprache, Fläche, Bevölkerung, BIP, GNI.
   Beginnen bündig unter der senkrechten Linie (kein Einzug wie beim Namen).
   pointer-events:auto (seit 18.09.2026, s. Kommentar bei .detail-name) vererbt sich auf
   die <li>-Zeilen darunter. */
.detail-facts {
    list-style: none;
    margin: 0.55em 0 0 0;
    padding: 0;
    flex: none;                 /* Flex-Item in #countryDetail: eigene Höhe, nicht schrumpfen */
    pointer-events: auto;
}

.detail-facts li {
    font-family: var(--font);
    font-weight: 500;                  /* Geist Medium */
    font-size: var(--detail-fact);
    line-height: 1.5;
    color: #939598;
}

/* Absatztext: bis zu 16 Zeilen hoch (max-height = 16 × Zeilenhöhe), längerer Text wird
   ab 10.09.2026 gescrollt statt abgeschnitten (Kundenvorgabe, da die Künstler/Sportler-
   Texte bis ~2000 Zeichen lang sind). `flex: 1 1 auto; min-height: 0` (statt block/feste
   Höhe): #countryDetail ist eine Flex-Spalte mit eigenem max-height:86%+overflow:hidden –
   bei fixer 16-Zeilen-Höhe ragte dieses Feld auf niedrigen Fenstern UNTEN aus genau diesem
   Rahmen heraus, und der herausragende Rest war dann selbst mit Scrollen nie erreichbar
   (er lag außerhalb des sichtbaren Bereichs). Mit flex-shrink bekommt es nie mehr Höhe, als
   in #countryDetail noch frei ist – der komplette Text bleibt dadurch über den eigenen
   Scrollbalken erreichbar, auch wenn die Box dafür kleiner als 16 Zeilen wird.
   `pointer-events: auto` (seit 18.09.2026, Kundenwunsch: Absatztext markieren/kopieren
   können, s. Git-Historie). Vorher erbte das Feld bewusst `pointer-events: none` von
   #countryDetail, damit ein Klick auf die Textspalte zur Karte durchgereicht wird – ohne
   das blieb ein Klick auf dieser Fläche wirkungslos hängen, statt die LDA zu beenden.
   Das Durchreichen übernimmt jetzt script.js: der `pointerup`-Handler der LDA behandelt
   einen Klick auf `.detail-text` OHNE Textauswahl genauso wie einen Klick daneben (LDA
   schließt); nur wenn `window.getSelection()` nach dem Loslassen Text enthält, bleibt die
   Ansicht offen, damit der markierte Text erhalten bleibt (s. dortiger Kommentar). Das
   Scrollen läuft weiterhin über den `wheel`-Handler in script.js (window, prüft
   detailCountry + Zeigerposition über dieser Box) – mit `pointer-events: auto` reicht zwar
   auch natives Scrollen, der Handler bleibt aber unverändert stehen (`preventDefault`
   verhindert doppeltes Scrollen). */
.detail-text {
    margin: 1.7em 0 0 0;
    font-family: var(--font);
    font-weight: 400;                  /* Geist Regular */
    font-size: var(--detail-body);
    line-height: var(--detail-line);
    color: #58595b;
    flex: 1 1 auto;
    min-height: 0;
    max-height: calc(16 * var(--detail-line));
    overflow-y: auto;
    overflow-x: hidden;
    pointer-events: auto;
    white-space: pre-wrap;             /* seit 16.09.2026: Absätze aus laws.json[].text
       (\n / \n\n) sollen als Zeilen-/Leerzeilenumbruch erscheinen wie in der Kundenquelle
       (vorher bewusst OHNE pre-wrap, s. Git-Historie – das ist damit aufgehoben). Bleibt
       XSS-sicher: script.js setzt den Text weiter per textContent, nicht innerHTML. */
}

/* Desktop (seit 10.10.2026): keine feste 16-Zeilen-Obergrenze mehr. Auf einem 27-Zoll-Monitor
   mit 1920x1080 zeigte Argentinien (K1) den Scrollbalken, obwohl unter dem Text noch viel
   Platz frei war. Die Höhe ergibt sich jetzt allein aus dem freien Platz in #countryDetail
   (Flex-Spalte, max-height 86 %): passt der Text, gibt es keinen Balken, sonst scrollt er.
   Mobil bleibt die Basisregel (dort begrenzt ohnehin `bottom` die Box). */
@media (min-width: 701px) {
    .detail-text { max-height: none; }
}

/* Scrollbalken des LDA-Absatztextes DAUERHAFT sichtbar (Kundenwunsch 24.09.2026): Der
   Betrachter soll schon beim Öffnen sehen, dass unten weiterer Text folgt. Systeme mit
   Overlay-Scrollbalken (macOS, iOS, Android) blenden den Balken sonst erst beim Scrollen
   ein. Ein eigenes ::-webkit-scrollbar-Design erzwingt dort einen klassischen, immer
   sichtbaren Balken (Chrome/Safari/Edge). Der Balken erscheint nur, wenn der Text wirklich
   länger als das Feld ist (overflow-y:auto). Firefox: scrollbar-color/-width, nur per
   @supports, weil Chrome ab 121 sonst ::-webkit-scrollbar ignoriert. Firefox unter macOS
   hält seine Overlay-Balken trotzdem versteckt (Systemeinstellung, per CSS nicht änderbar). */
.detail-text {
    padding-right: 0.6em;              /* Text klebt nicht am Balken */
}
.detail-text::-webkit-scrollbar {
    width: 8px;
}
.detail-text::-webkit-scrollbar-track {
    background: rgba(0, 0, 0, 0.08);
    border-radius: 4px;
}
.detail-text::-webkit-scrollbar-thumb {
    background: #8a8b8e;
    border-radius: 4px;
}
.detail-text::-webkit-scrollbar-thumb:hover {
    background: #6d6e71;
}
@supports not selector(::-webkit-scrollbar) {
    .detail-text {
        scrollbar-width: thin;
        scrollbar-color: #8a8b8e rgba(0, 0, 0, 0.08);
    }
}

/* --- Aktiver Scroll-Balken links (nur Handy, s. Kommentar in index.html) ----
   #detailScrollbar wird von updateDetailScrollbar() (script.js) per position:fixed über
   top/height/left an das aktuelle .detail-text-Rechteck gelegt und nur eingeblendet,
   solange dort tatsächlich mehr Text steht als sichtbar ist – deckt sich also mit exakt
   der Bedingung, unter der auch der (unsichtbare) native Balken rechts erscheinen würde. */
#detailScrollbar {
    display: none;
    position: fixed;
    width: 4px;
    border-radius: 2px;
    background: rgba(0, 0, 0, 0.12);
    pointer-events: none;
    z-index: 41;
}
#detailScrollbarThumb {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    border-radius: 2px;
    background: #6d6e71;
}
@media (min-width: 701px) {
    /* Am Desktop übernimmt der ::-webkit-scrollbar oben (funktioniert dort zuverlässig,
       Maus-Browser respektieren ihn) – der zusätzliche Balken bleibt hier ungenutzt. */
    #detailScrollbar { display: none !important; }
}

/* Hochformat/Handy: das Land sitzt oben (DETAIL_BOX_PHONE), die Textspalte darunter.
   Layout nach Vorlage `buggs/smartphonedisign-LDA.jpg` (Wunsch 04.09.2026): DBA-Info direkt
   unter dem Namen (s. .detail-info oben – auf dem Handy gibt es keine Fokus-Ansicht, die
   sie vorher zeigen könnte), Kennzahlen fett, Spalte schmaler als vorher (war randvoll auf
   88 % Breite). */
/* Seit 14.10.2026 auch für Tablets im Hochformat (iPad 11": 820 px breit): script.js stuft sie
   über isPhone() (max-aspect-ratio 1/1) als Handy ein und legt das Land nach oben; die
   Textspalte schaltete aber erst unter 700 px um und lag deshalb über dem Land. Query
   jetzt deckungsgleich zu isPhone() + bisheriger Handybreite. */
@media (max-width: 700px), (max-aspect-ratio: 1/1) {
    #countryDetail {
        /* Seitenränder SEIT 28.09.2026 symmetrisch und breiter (Kundenvorlage „distances on
           smartphone.pdf": Rand C ≈ 11,4 % der Bildschirmbreite auf jeder Seite, nachgemessen
           an der Vorlage – vorher 6 % links/14 % rechts, spürbar schmaler und schief). */
        left: 11%;
        /* Abstand zum Land darüber (DETAIL_BOX_PHONE endet bei y1=0.33, s. script.js)
           verkleinert (Wunsch 28.09.2026, vorher 40 % = 7 % Bildhöhe Luft). */
        top: 35%;
        right: auto;    /* Hochformat: kein reservierter Streifen rechts wie am Desktop */
        width: 78%;
        /* Unten bleibt Platz für die grüne Fußzeile „Datenschutz | Impressum" frei (s.
           #legalLinks weiter unten) – ohne das lief der LDA-Text bis unter die Fußzeile und
           war dort verdeckt (Meldung 28.09.2026). max-height (Basisregel: 86 % der ganzen
           Karte) ersetzt durch ein festes bottom, das die Fußzeilenhöhe kennt. */
        max-height: none;
        bottom: calc(52px + env(safe-area-inset-bottom, 0px));
    }
    .detail-info.with-info { display: block; }   /* leer (kein Eintrag) bleibt ohne Lücke aus */
    .detail-facts li { font-weight: 700; }
    /* Scrollen per Finger: `pointer-events: auto` steht seit 18.09.2026 schon in der
       Basisregel oben (Textmarkierung). touch-action:pan-y + overscroll-behavior bleiben
       hier zusätzlich nötig, wie bei #countrySearchList (dort dieselbe Notwendigkeit, weil
       das SVG global touch-action:none trägt, s. dort). */
    .detail-text {
        -webkit-overflow-scrolling: touch;
        touch-action: pan-y;
        overscroll-behavior: contain;
    }
}

/* Tablet-Hochformat: vw-Schriften wären hier winzig (820 px × 1,02 % ≈ 8 px). */
@media (min-width: 701px) and (max-aspect-ratio: 1/1) {
    #countryDetail {
        --detail-name: clamp(28px, 4.2vw, 46px);
        --detail-fact: clamp(15px, 2.1vw, 23px);
        --detail-body: clamp(14px, 1.7vw, 18px);
    }
}

/* In der Detail-Ansicht tritt die alte InfoBox weich zurück (DETAIL_HIDE_INFOBOX). */
#infoBox {
    transition: opacity 400ms ease;
}

#infoBox.detail-hidden {
    opacity: 0;
    pointer-events: none;
}

/* --- Popup (Länder-Statistiken) -------------------------------------------- */
/* Popup-Fenster mit Länder-Statistiken.
   Kein blockierender Hintergrund: die Karte bleibt klickbar, damit ein
   Klick auf ein anderes Land dessen Popup öffnet bzw. Wegklicken schließt. */
#popup {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.96);
    width: 360px;
    max-width: 90vw;
    max-height: 85vh;
    overflow-y: auto;
    background: rgba(255, 255, 255, 0.82);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    border-radius: 12px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
    padding: 22px 24px 18px;
    z-index: 30;
    /* Kein display/visibility-Umschalten: das Popup bleibt immer gerendert
       und wird NUR ueber opacity (+ pointer-events) ein-/ausgeblendet. So
       gibt es keinen diskreten visibility-Sprung, der die Opacity-Transition
       beim Einblenden verschlucken wuerde – das Fade laeuft in BEIDE
       Richtungen weich. pointer-events:none laesst Klicks im unsichtbaren
       Zustand zur Karte durch. */
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.18s ease, transform 0.18s ease;
    font-size: 14px;
    color: #2b2b2b;
}

#popup.show {
    pointer-events: auto;
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}

#popupClose {
    position: absolute;
    top: 10px;
    right: 12px;
    width: 30px;
    height: 30px;
    border: none;
    background: transparent;
    font-size: 24px;
    line-height: 1;
    color: #888;
    cursor: pointer;
    border-radius: 6px;
}

#popupClose:hover {
    background: #f0f0f0;
    color: #222;
}

#popupTitle {
    margin: 0 30px 2px 0;
    font-size: 22px;
    color: #1a1a1a;
}

#popupSubtitle {
    margin: 0 0 4px;
    color: #777;
    font-size: 13px;
}

#popupStand {
    margin: 0 0 14px;
    color: #999;
    font-size: 12px;
    font-style: italic;
}

#popupStats {
    width: 100%;
    border-collapse: collapse;
}

#popupStats th,
#popupStats td {
    text-align: left;
    padding: 7px 4px;
    border-bottom: 1px solid #eee;
    vertical-align: top;
}

#popupStats th {
    font-weight: 500;   /* Geist Medium – kräftigster mitgelieferter Schnitt */
    color: #555;
    width: 45%;
}

#popupStats td {
    color: #1a1a1a;
    font-weight: 500;   /* Geist Medium – kräftigster mitgelieferter Schnitt */
}

/* --- Klickbarer DBA-Link im infoBox ---------------------------------------- */
.dba-link {
    pointer-events: auto;
    background: none;
    border: none;
    color: #1a5eb5;
    cursor: pointer;
    font-size: 14px;
    font-family: var(--font);
    padding: 0;
    text-decoration: underline;
}

.dba-link:hover {
    color: #0d3d8a;
}

/* --- DBA-Popup (Deutschland-Detailtext) ------------------------------------ */
/* DBA-Popup: gleitet von unten in die Bildschirmmitte */
#dbaPopup {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 520px;
    max-width: 92vw;
    max-height: 82vh;
    overflow-y: auto;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
    padding: 24px 26px 22px;
    z-index: 35;
    pointer-events: none;
    opacity: 0;
    transform: translate(-50%, calc(-50% + 48px));
    transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1),
                opacity 0.22s ease;
}

#dbaPopup.show {
    transform: translate(-50%, -50%);
    opacity: 1;
    pointer-events: auto;
}

#dbaPopupClose {
    position: absolute;
    top: 10px;
    right: 12px;
    width: 30px;
    height: 30px;
    border: none;
    background: transparent;
    font-size: 24px;
    line-height: 1;
    color: #888;
    cursor: pointer;
    border-radius: 6px;
}

#dbaPopupClose:hover {
    background: #f0f0f0;
    color: #222;
}

#dbaPopup h2 {
    margin: 0 36px 10px 0;
    font-size: 20px;
    color: #1a1a1a;
}

#dbaPopup .dba-meta {
    font-size: 12px;
    color: #999;
    font-style: italic;
    margin-bottom: 14px;
}

#dbaPopup p {
    margin: 0 0 10px;
    font-size: 14px;
    line-height: 1.6;
    color: #2b2b2b;
}

#dbaPopup ul {
    margin: 0 0 12px 0;
    padding-left: 20px;
    font-size: 14px;
    color: #2b2b2b;
    line-height: 1.6;
}

#dbaPopup table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    margin-top: 10px;
}

#dbaPopup table th,
#dbaPopup table td {
    text-align: left;
    padding: 6px 4px;
    border-bottom: 1px solid #eee;
}

#dbaPopup table th {
    color: #555;
    font-weight: 500;   /* Geist Medium – kräftigster mitgelieferter Schnitt */
    width: 50%;
}

/* --- Mobile / schmaler Bildschirm ------------------------------------------ */
/* Smartphone (Hochformat bzw. schmaler Bildschirm): InfoBox als vollbreites
   Bottom-Sheet statt 33%-Pille (auf 428px sonst unlesbar), Reset-Button
   kompakter, Popups viewport-relativ. #infoBox bleibt pointer-events:none
   (außer .dba-link) → das Sheet blockiert keine Karten-Taps. */
@media (max-aspect-ratio: 1/1), (max-width: 500px) {
    /* Kartenname + Legende bleiben in derselben Anordnung wie auf dem Desktop (Kasten
       oben links, Legende unten links an der Linie), nur kleiner: die Desktop-Maße sind
       Anteile der FENSTERBREITE und fielen im Hochformat sonst auf ihre Mindestwerte
       zurück – der Kasten wirkte dann viel zu wuchtig. Der Kartenname darf hier
       umbrechen (bis zu zwei Zeilen), damit lange Namen nicht abgeschnitten werden. */
    :root {
        --map-chrome-left: 16px;
        /* Mobil sind 3,6 vw nur ~14 px – zu klein zum Antippen. Feste 34 px (plus die
           Polsterung des Umschalters) ergeben weiter ein sicheres Tippziel, aber etwas
           kleiner als vorher (Wunsch 04.09.2026, s. Menüzeilen-Ausrichtung). */
        --menu-dot: 44px;
        /* Abstand der vier Kreise untereinander: auf dem Handy deutlich großzügiger als am
           Desktop (0,075 × Ø dort) – die Kundenvorlage „distances on smartphone.pdf"
           (28.09.2026) zeigt zwischen den Halbkreisen sichtbaren Luftraum statt der bisher
           fast aneinanderklebenden Kreise (Meldung: „Abstände zu schmal"). Etwa 0,17 × Ø,
           nachgemessen an der Vorlage. */
        --menu-gap: calc(var(--menu-dot) * 0.17);
        /* Die vier Kreise beginnen seit 13.08.2026 GANZ OBEN – auf derselben Höhe, auf der
           auch das Zurücksetzen-Symbol anfängt (top: 8px). Vorher standen sie unter der
           Lupe (48px); die Lupe sitzt im neuen Suchdesign aber unten links, oben rechts
           war der Platz also frei. */
        --menu-top: 8px;
    }

    /* Der Kartenname (Namenssticker) ist auf Handy und Tablet wieder sichtbar (Wunsch
       14.10.2026; vom 04.09.2026 bis dahin per display:none ausgeblendet). Er darf
       umbrechen und lässt rechts Platz für den Kreis-Umschalter. */
    #mapTitle {
        white-space: normal;
        max-width: calc(100vw - var(--map-chrome-left) - var(--menu-dot) - 40px);
    }

    #mapLegendWrap {
        /* Unterste Legendenzeile muss ÜBER dem Suchkreis (unten links, Mitte bei
           --search-center-y) enden; die früheren 24px ließen die oberen Kreise auf ihm
           sitzen (Meldung 14.10.2026, Chrome Smartphone). */
        padding-bottom: calc(var(--search-center-y) + var(--search-dot) * 1.1);
        /* seit 04.09.2026 größer (Wunsch: Legendenkreise mit Schrift auf dem Handy größer) */
        font-size: calc(15px * var(--legend-scale, 1));
    }

    .map-legend { --legend-dot: calc(21px * var(--legend-scale, 1)); }

    #infoBox {
        width: 100%;
        max-width: none;
        left: 0;
        bottom: 0;
        transform: none;
        border-radius: 12px 12px 0 0;
        padding: 14px 18px calc(14px + env(safe-area-inset-bottom));
    }

    /* MOBIL steht der Zurücksetzen-Knopf oben rechts – er rückt um die feste
       Lupen-Breite nach links (8 + 36 + 8 = 52), damit das Lupen-Icon rechts daneben
       Platz hat. Im DOM hängt er seit dem Desktop-Umbau im Testbereich (#testMenu);
       der ist mobil `display: contents` und erzeugt damit KEINEN Bezugsrahmen –
       deshalb `fixed` (Bezug = Viewport) statt `absolute`, sonst säße der Knopf im
       aufklappbaren #sideMenu. visibility explizit zurücksetzen: sie wird von
       #sideMenu vererbt (opacity dagegen liegt bewusst nur auf den Panels).

       SEIT 13.08.2026 ist er dort kein Kästchen mit Text mehr, sondern das runde
       Zurücksetzen-SYMBOL (weißer, nicht ganz geschlossener dünner Ring mit Pfeil, s.
       index.html): kein Rahmen, kein Hintergrund, keine Schrift – nur das Symbol, das
       sich beim Antippen einmal dreht (.spin, s. unten).

       SEIT 28.09.2026 blendet er weich aus, solange das Kartenmenü offen ist (Wunsch:
       er überlagerte dort die erste Menüzeile) – dafür übernimmt #resetBtnMenu unten
       rechts im aufgeklappten Band dieselbe Funktion, s. u. */
    #testMenu > #resetBtn {
        position: fixed;
        top: 8px;
        right: 52px;
        left: auto;
        z-index: 41;
        width: 44px;
        height: 44px;
        padding: 0;
        background: none;
        border: none;
        border-radius: 50%;
        box-shadow: none;
        visibility: visible;
        opacity: 1;
        pointer-events: auto;
        transition: opacity var(--menu-anim) var(--menu-ease);
    }
    body.mapmenu-open:not(.mapmenu-classic) #testMenu > #resetBtn {
        opacity: 0;
        pointer-events: none;
    }
    /* Zweiter Knopf, links auf Höhe der letzten (fünften) Menüzeile im aufgeklappten
       Kartenmenü-Band (#mapMenu): gleiches Symbol, gleicher Handler (script.js:
       bindResetButton). Er ist ein normales Kind von #mapMenu und blendet darum
       automatisch MIT dem Band ein/aus (dessen opacity/visibility, s. o.) – ohne eigene
       Übergangsregel. #mapMenu selbst ist `position: fixed`, das reicht als
       Bezugsrahmen für die absolute Positionierung hier.
       top/height decken GENAU die Box der letzten .map-menu-group ab (vier Zeilen, s.
       index.html – die Reihenfolge ist fest, darum hier bewusst `3 *` statt einer
       Variablen): dadurch liegt die Mitte des Knopfs exakt auf der Mitte dieser Zeile,
       auf gleicher Höhe wie „FKAustG-Staaten" und ihr Kreis (Wunsch 28.09.2026, vorher
       stand er darunter). pointer-events explizit auto: #mapMenu setzt für sich selbst
       none (nur einzelne .map-menu-group-Zeilen holen es sich zurück), dieser Knopf ist
       aber kein Kind einer solchen Zeile. Nur mobil sichtbar (Desktop: s. u.,
       display:none). */
    #resetBtnMenu {
        position: absolute;
        top: calc(var(--menu-row) * (var(--menu-count) - 1));
        left: 6px;
        height: var(--menu-row);
        z-index: 3;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 40px;
        padding: 0;
        background: none;
        border: none;
        border-radius: 50%;
        pointer-events: auto;
    }
    #resetBtnMenu .icon-undo {
        display: block;
        width: 30px;
        height: 30px;
        filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.35));
    }
    /* Die Beschriftung „Zurücksetzen" entfällt mobil – das Symbol trägt die Bedeutung
       (der Text bleibt im HTML für Screenreader erhalten, s. .reset-text). */
    #resetBtn .reset-text {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    #resetBtn .icon-undo {
        display: block;
        width: 30px;
        height: 30px;
        /* Weiß wie die Menü-Kreise, mit demselben leichten Schatten – sonst verschwände
           der dünne Ring auf hellem Wasser und auf dem weißen Wasser der Fokus-Ansicht. */
        filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.35));
    }
    /* Eine Umdrehung beim Antippen: die Klasse setzt script.js und nimmt sie am Ende der
       Animation wieder ab. Endet exakt bei 360° (≡ 0°), ohne Rückschwung. Gilt für BEIDE
       Knöpfe (#resetBtn oben, #resetBtnMenu im Band) – bisher nur an #resetBtn gebunden,
       darum blieb die Drehung am zweiten Knopf aus (Wunsch 28.09.2026). */
    #resetBtn .icon-undo.spin,
    #resetBtnMenu .icon-undo.spin {
        animation: reset-spin 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
    }
    @keyframes reset-spin {
        from { transform: rotate(0deg); }
        to   { transform: rotate(360deg); }
    }

    /* Kein Esc auf Touch-Geräten → Tasten-Kästchen ausblenden, Button zeigt
       nur „Zurücksetzen". */
    #resetBtn .kbd-hint {
        display: none;
    }

    /* --- Aufklappbare Bedienspalte (Kartenansichten + Zoom-Test) --------------
       Auf dem kleinen Schirm würden die Panels dauerhaft die halbe Karte verdecken.
       Sie stecken deshalb hinter dem Vier-Kreise-Umschalter (#mapMenuToggle) und
       erscheinen nur, solange body.mapmenu-open gesetzt ist. Der Wrapper wird hier
       vom `display: contents` des Desktops auf einen Flex-Container umgestellt: die
       Panels stehen untereinander, ohne dass ihre Höhen von Hand verrechnet werden
       müssen (der Desktop-Stapel arbeitet dagegen mit festen top-Werten). */
    #sideMenu {
        position: absolute;
        top: 112px;               /* unter dem Umschalter (top:48 + ~56 Kreishöhe) */
        right: 8px;
        z-index: 9;
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        gap: 8px;
        max-width: calc(100vw - 16px);
        /* Geschlossen: unsichtbar UND nicht antippbar. visibility verzögert schalten,
           damit das Ausblenden noch weich läuft (Muster wie #popup). Das weiche
           Überblenden (opacity) liegt bewusst auf den PANELS, nicht hier: der
           Zurücksetzen-Knopf hängt seit dem Desktop-Umbau ebenfalls in diesem Teilbaum
           und muss mobil dauerhaft sichtbar bleiben – eine opacity auf dem Vorfahren
           ließe sich vom Kind nicht mehr aufheben, visibility dagegen schon. */
        visibility: hidden;
        pointer-events: none;
        transition: visibility 0s linear 250ms;
    }
    body.mapmenu-open #sideMenu {
        visibility: visible;
        pointer-events: auto;
        transition: visibility 0s linear 0s;
    }
    /* Der Testbereich steckt seit 04.08.2026 AUCH MOBIL hinter dem „T" – wie auf dem
       Desktop. Vorher hing er als zweites Panel unter der Kartenmenü-Leiste im
       Kreis-Menü: dort klappte beim Antippen eines Schalters gleichzeitig das
       Kreis-Menü zu, das Panel verschwand unter der Hand und es sah aus, als reagiere
       nichts. Jetzt ist er ein eigener Bereich mit eigenem Umschalter, unabhängig vom
       Kartenmenü (openTestMenu schließt das Kartenmenü, s. script.js).

       Er hängt im DOM weiter in #sideMenu, wird aber per `fixed` aus dessen Fluss
       genommen. Wichtig dabei:
         - `visibility`/`pointer-events` werden von #sideMenu VERERBT und hier deshalb
           ausdrücklich neu gesetzt (sonst bliebe der Bereich unsichtbar, solange das
           Kreis-Menü zu ist),
         - das weiche Ein-/Ausblenden liegt bewusst NICHT als `opacity` auf #testMenu,
           sondern auf dem Panel darin: der Zurücksetzen-Knopf ist ebenfalls ein Kind und
           muss mobil dauerhaft oben rechts stehen bleiben – eine opacity am Vorfahren
           ließe sich von ihm nicht mehr aufheben.
       Doku: doku/24 (Testbereich) / doku/28. */
    #testMenu {
        display: flex;
        position: fixed;
        /* Senkrecht mittig OHNE transform: ein transform am Vorfahren macht diesen zum
           Bezugsrahmen für `position: fixed`-Kinder – der Zurücksetzen-Knopf hängt hier
           drin und säße dann im Panel statt oben rechts am Bildschirm. Deshalb über
           top/bottom + `margin: auto` zentriert. */
        top: 0;
        bottom: 0;
        height: max-content;
        margin: auto 0;
        right: 44px;              /* neben dem nach rechts gefahrenen „T" */
        left: auto;
        z-index: 42;              /* über Band-Menü und Kreisspalte */
        transform: none;
        width: 210px;
        max-width: calc(100vw - 60px);
        max-height: calc(100vh - 24px);
        overflow-y: auto;         /* kleine Geräte: der Inhalt bleibt erreichbar */
        /* Die Desktop-Regel blendet #testMenu per opacity aus. Mobil MUSS sie hier
           zurückgenommen werden: der Zurücksetzen-Knopf hängt als Kind darin und steht
           dauerhaft oben rechts – eine opacity am Vorfahren könnte er nicht aufheben,
           er verschwände also mitsamt dem zugeklappten Testbereich. Gesteuert wird
           mobil allein über visibility/pointer-events, das Weiche macht das Panel. */
        opacity: 1;
        visibility: hidden;
        pointer-events: none;
        transition: visibility 0s linear 250ms;
    }
    body.testmenu-open #testMenu {
        visibility: visible;
        pointer-events: auto;
        transition: visibility 0s linear 0s;
    }
    /* Das Panel darin blendet weich ein – und nur es (s. o.). */
    #mapMenu,
    #zoomTestPanel {
        opacity: 0;
        visibility: hidden;
        transition: opacity 250ms ease, visibility 0s linear 250ms;
    }
    body.mapmenu-open #mapMenu,
    body.testmenu-open #zoomTestPanel {
        opacity: 1;
        visibility: visible;
        transition: opacity 250ms ease, visibility 0s linear 0s;
    }
    /* Die Panels der Kreis-Spalte geben ihre Positionierung an den Flex-Container ab –
       der Testbereich nicht mehr, der steht jetzt frei hinter dem „T". */
    #sideMenu > *:not(#testMenu) {
        position: static;
        top: auto;
        right: auto;
        transform: none;
        margin: 0;
        width: 210px;
        max-width: calc(100vw - 16px);
    }
    /* Im Testbereich füllt das Panel den Kasten. */
    #testMenu > #zoomTestPanel {
        position: static;
        width: 100%;
        margin: 0;
    }
    /* Der „T"-Umschalter ist mobil derselbe wie auf dem Desktop, nur kleiner und mit
       fingergerechter Trefferfläche. */
    #testMenuToggle {
        font-size: 44px;
        padding: 8px 14px;
    }
    /* Nur hier sichtbar: die vierte Zoomout-Stufe ist eine Handy-Stufe (s. o.).
       Dieselbe Query steuert isPhone() in script.js → Sichtbarkeit und
       Deutschland-Startansicht schalten immer gemeinsam. */
    #zoomTestPanel button#zoomOut4Btn { display: block; }
    /* Umgekehrt: die Prototyp-View ist eine reine DESKTOP-Taste. Nur dort ist die
       Startansicht 2 x herausgezoomt; mobil wäre die Taste identisch mit der dortigen
       Startansicht (= Zurücksetzen) und damit funktionslos. */
    #zoomTestPanel button#protoViewBtn { display: none; }

    body.mapmenu-classic #mapMenu { padding: 2px 10px 6px; }
    body.mapmenu-classic #mapMenu legend { font-size: 12px; }
    body.mapmenu-classic #mapMenu label { padding: 4px 2px; font-size: 12px; }
    /* Rückweg-Panel: flache Liste ohne Band, der zweite Reset-Knopf gehört nur zum
       neuen Band-Design und bleibt hier aus – oben rechts steht weiter #resetBtn. */
    body.mapmenu-classic #resetBtnMenu { display: none; }

    /* Das neue Band-Menü ist mobil KEIN Panel in der Bedienspalte, sondern liegt wie auf
       dem Desktop frei über der Karte. `position: fixed` nimmt es aus dem Flex-Fluss von
       #sideMenu und bezieht es auf den Viewport (nicht auf den mobil positionierten
       #sideMenu). Übrig bleibt in der Spalte nur das Zoom-Test-Panel – das rückt unter
       das Band, damit es nicht darin verschwindet. */
    /* Selektor mit BEIDEN IDs (#sideMenu > #mapMenu): Die Regel
       `#sideMenu > *:not(#testMenu) { position: static }` weiter unten zählt zwei IDs und
       hätte diese hier sonst überstimmt – die Menüzeilen rutschten dann in den Flex-Fluss
       der Bedienspalte UNTER das Band und standen mitten auf der Karte (weiße Schrift auf
       heller Landfläche). Aufgefallen am 13.08.2026, als auf Touch-Geräten alle fünf
       Kartennamen gleichzeitig erscheinen. */
    body:not(.mapmenu-classic) #sideMenu > #mapMenu {
        position: fixed;
        top: calc(var(--menu-top) + var(--menu-pad-y));
        right: 0;
        left: 0;
        margin: 0;
        width: auto;
        max-width: none;
    }
    body:not(.mapmenu-classic) #sideMenu {
        top: calc(var(--menu-band-h) + 8px);
    }
    /* Mobil ist die Schrift der Menüzeilen an die Kreisgröße gekoppelt (feste 40 px),
       nicht an die Fensterbreite – sonst stünde neben 40-px-Kreisen 14-px-Text. */
    body:not(.mapmenu-classic) .map-menu-labels label { font-size: 17px; }
    /* Aufgeklappte Suche belegt denselben Bereich → Umschalter aus (wie die Lupe). */
    body.search-open #mapMenuToggle { display: none; }

    /* Länder-Suche als Aufklapp-Leiste: eingeklappt zeigt sich nur das Lupen-Icon
       (rechts neben dem Reset-Knopf). Tipp öffnet die volle Suchleiste am oberen
       Rand (#countrySearch.open) mit großer, gut tippbarer Trefferliste. Funktionen
       identisch zum Desktop – nur die Darstellung ist mobil optimiert. */
    #searchToggle {
        display: flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 8px;
        right: 8px;
        z-index: 41;
        width: 36px;
        height: 32px;
        padding: 0;
        background: white;
        border: 1px solid #aaa;
        border-radius: 4px;
        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
        color: #333;
        cursor: pointer;
    }

    /* Aufgeklappt (body.search-open): die Lupe blendet aus – an ihrer Stelle
       übernimmt das ✕ in der Suchleiste das Schließen. Beim Schließen kehrt die
       Lupe zurück. Klasse wird von openSearch/closeSearch gesetzt. */
    body.search-open #searchToggle { display: none; }

    /* Eingeklappt: Suchfeld/Liste versteckt (überschreibt das Desktop-top:52-Layout). */
    #countrySearch { display: none; }

    /* Aufgeklappt: volle Leiste am oberen Rand (Safe-Area beachtet). z-index über
       dem Auswahl-Namenslabel (#countryLabel = 50), damit ein evtl. noch sichtbares
       Landes-Label nach einer Auswahl NICHT über den Trefferzeilen erscheint. */
    #countrySearch.open {
        display: block;
        z-index: 60;
        top: calc(env(safe-area-inset-top) + 8px);
        bottom: auto;              /* Desktop-Verankerung unten aufheben */
        left: 8px;
        right: 8px;
        transform: none;           /* Desktop-Zentrierung aufheben */
        width: auto;
        max-width: none;
    }

    /* Die Leiste steht mobil OBEN – die Trefferliste klappt also wieder nach unten
       auf und läuft dafür im normalen Fluss (Desktop: absolut nach oben). */
    #countrySearch.open #countrySearchList {
        position: static;
        margin: 4px 0 0;
    }

    /* ✕ ganz rechts in der Leiste, vertikal mittig auf der EINGABEZEILE. Höhe an
       die Feldhöhe (44 px) gekoppelt, NICHT height:100% – sonst zentriert es über
       die ganze offene Leiste (inkl. Trefferliste) und rutscht aus dem Sichtfeld. */
    #countrySearch.open #searchClose {
        display: flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        width: 40px;
        height: 44px;
        padding: 0;
        border: none;
        background: transparent;
        font-size: 26px;
        line-height: 1;
        color: #888;
        cursor: pointer;
    }

    /* Großes, touch-freundliches Feld + hohe Liste (nur im offenen Zustand).
       16 px Schrift = angenehmes Tap-Ziel; feste 44 px Höhe = gemeinsame
       Bezugszeile für das ✕; rechts 44 px Platz für das ✕. */
    #countrySearch.open #countrySearchInput { height: 44px; padding: 10px 44px 10px 12px; font-size: 16px; }
    /* line-height 24 + padding 10 = 44 px Zeilenhöhe → „n Treffer" vertikal mittig
       auf der Eingabezeile (JS setzt display:block, daher kein Flex hier). */
    #countrySearch.open #searchCount {
        right: 44px;
        padding: 10px 12px;
        font-size: 14px;
        line-height: 24px;
        box-sizing: border-box;
    }
    #countrySearch.open #countrySearchList {
        --row-h: 44px;
        max-height: calc(var(--row-h) * 6);   /* ~6 Zeilen sichtbar, Rest scrollt */
    }
    #countrySearch.open .country-search-item {
        height: 44px;
        padding: 12px;
        font-size: 16px;
        line-height: 20px;
    }

    /* Popups auf dem Handy kompakter: nie breiter als der Screen (mit Rand),
       kleinere Schrift/Innenabstände, damit sie nicht den halben Bildschirm
       sprengen. Zentriert (kein Desktop-Links-Versatz, s. openPopup). */
    #popup,
    #dbaPopup {
        width: 86vw;
        max-width: 86vw;
        max-height: 78vh;
        padding: 16px 16px 14px;
        font-size: 12.5px;
    }

    #popupTitle { font-size: 18px; }
    #popupSubtitle { font-size: 12px; }
    #popupStand { font-size: 11px; }
    #popupStats th,
    #popupStats td { padding: 5px 3px; font-size: 12.5px; }

    #dbaPopup h2 { font-size: 17px; }
    #dbaPopup p,
    #dbaPopup ul { font-size: 12.5px; line-height: 1.5; }
    #dbaPopup table { font-size: 11.5px; }
    #dbaPopup table th,
    #dbaPopup table td { padding: 5px 3px; }
}

/* ===========================================================================
   Länder-Suche – NEUES DESIGN (runder Knopf unten links an der Legende)
   ---------------------------------------------------------------------------
   Nachbau des Designer-Entwurfs uploads/search_button (Maße dort im Fenster
   1844 x 1310 ausgemessen und in Fensteranteile umgerechnet):

     geschlossen  weißer Kreis, Durchmesser 37 px = Größe der Legendenkreise,
                  linke Kante 145 px = linke Kante der Legendenkreise,
                  Mitte 100 px über dem unteren Bildrand (unter dem letzten
                  Legendeneintrag, an derselben senkrechten Linie)
     offen        dieselbe Höhe, 168 px breit – die LINKE Kante bleibt stehen,
                  die Pille wächst nach rechts; das Stern-Symbol dreht sich
                  dabei um 180°

   Dieser Abschnitt steht bewusst GANZ AM ENDE der Datei: er überschreibt die
   Prototyp-Regeln (Leiste unten mittig / mobile Lupe) inklusive der mobilen
   @media-Regeln, ohne dass dort etwas umgebaut werden müsste. Häkchen
   „Search-prototype" im Testbereich setzt body.search-classic – dann greift
   dieser ganze Abschnitt nicht mehr und die alte Suche ist zurück.
   Doku: doku/15_LAENDER_SUCHE.md
   =========================================================================== */
:root {
    /* seit 04.09.2026 an --legend-scale gekoppelt (Wunsch: Suchkreis IMMER so groß wie
       die Legendenkreise) – vorher blieb er beim Verstellen des Legende-Reglers fix. */
    --search-dot: calc(clamp(26px, 1.95vw, 42px) * var(--legend-scale, 1));
    /* Breite der offenen Pille. Der Entwurf zeigt 168 px (9,2vw); das ist zu schmal:
       rechts steht die Trefferzahl („240 Treffer", sobald mehr Treffer als Zeilen da
       sind) und lief in den Platzhalter „Land suchen" hinein. Darum so breit, dass
       beides nebeneinander Platz hat. */
    --search-open-w: clamp(200px, 12vw, 300px);
    --search-center-y: clamp(52px, 7.6vh, 120px);   /* Mitte über dem unteren Rand */
    /* linke Kante der Legendenkreise: Linie (--map-chrome-left) + 2 px Linienbreite
       + padding-left der Legendenzeilen (seit 09.09.2026 0,075 x Kreis, s.
       .map-legend-item – Abstand zur grünen Linie auf dem Desktop halbiert). */
    --search-left: calc(var(--map-chrome-left) + 2px + var(--search-dot) * 0.075);
    --search-bottom: calc(var(--search-center-y) - var(--search-dot) / 2);
    /* Höhe der Bildschirmtastatur; setzt script.js (visualViewport), solange das Feld
       mobil offen ist – sonst läge die Pille hinter der Tastatur. */
    --kb-inset: 0px;
}

/* Der Knopf ist ein eigenes Element NEBEN #mapChrome (nicht darin): #mapChrome ist
   pointer-events:none und aria-hidden – ein bedienbarer Knopf gehört dort nicht hinein.
   Das gemeinsame Ein-/Ausblenden mit der Legende macht die opacity-Regel weiter unten. */
body:not(.search-classic) #searchToggle {
    display: flex;
    align-items: center;
    justify-content: center;
    /* fixed wie #mapChrome und #legalLinks: absolute rechnete in Chrome/Safari (iPhone)
       gegen die Seite statt gegen den sichtbaren Rand, der Kreis stand höher als die
       Legendenrechnung annahm und die Legende saß auf ihm (Meldung 14.10.2026). */
    position: fixed;
    left: var(--search-left);
    right: auto;
    top: auto;
    bottom: calc(var(--search-bottom) + var(--kb-inset, 0px));
    width: var(--search-dot);
    height: var(--search-dot);
    padding: 0;
    border: none;
    border-radius: 50%;
    background: #fff;
    color: gray;                       /* Ring + Stern wie im Entwurfs-SVG */
    cursor: pointer;
    z-index: 41;                       /* über der Pille (40) */
    opacity: 1;
    transition: opacity 400ms ease, bottom 250ms ease;
}

body:not(.search-classic) #searchToggle .icon-lens { display: none; }

body:not(.search-classic) #searchToggle .icon-star {
    display: block;
    width: 100%;
    height: 100%;
    transition: transform 400ms ease;
}

/* Aufziehen = 180° im Uhrzeigersinn, Zufahren = zurück gegen den Uhrzeigersinn.
   Bezug ist body.search-open (openSearch/closeSearch), NICHT #countrySearch.open:
   der Knopf steht im DOM VOR der Suchhülle, ein Geschwister-Selektor griffe nicht.
   Der Stern ist vierfach symmetrisch – sichtbar ist also die Drehbewegung selbst. */
body:not(.search-classic).search-open #searchToggle .icon-star {
    transform: rotate(180deg);
}

/* Mobil blendet der Prototyp beim Öffnen Lupe und Kreis-Menü aus (beide teilen sich
   dort die Ecke oben rechts). Hier steht die Suche unten links – beides bleibt. */
body:not(.search-classic).search-open #searchToggle { display: flex; }
body:not(.search-classic).search-open #mapMenuToggle { display: flex; }

/* Die Hülle ist die weiße Pille: geschlossen genau so breit wie der Kreis (und damit
   unsichtbar unter ihm), offen --search-open-w. Nur die Breite wird animiert, die
   linke Kante steht fest. */
body:not(.search-classic) #countrySearch {
    display: block;
    position: fixed;
    left: var(--search-left);
    right: auto;
    top: auto;
    bottom: calc(var(--search-bottom) + var(--kb-inset, 0px));
    transform: none;
    width: var(--search-dot);
    height: var(--search-dot);
    max-width: calc(100vw - var(--search-left) - 12px);
    z-index: 40;
    opacity: 1;
    transition: width 400ms ease, opacity 400ms ease, bottom 250ms ease;
}

body:not(.search-classic) #countrySearch.open { width: var(--search-open-w); }

/* Trefferliste im neuen Design: eckige weiße Fläche OHNE Rahmenlinie (Wunsch
   04.08.2026). Die Grundregel #countrySearchList bringt 4px Radius und eine dünne
   graue Linie mit – die bleibt dort stehen, damit der Prototyp (body.search-classic)
   sein altes Aussehen behält, und wird hier für das neue Design zurückgenommen. */
body:not(.search-classic) #countrySearchList {
    border: none;
    border-radius: 0;
}

/* Das Eingabefeld füllt die Pille. Links bleibt der Kreis frei (padding), rund und
   ohne Rahmen wie im Entwurf. Geschlossen ist es unsichtbar und nicht anklickbar –
   sichtbar ist dann nur der Kreis. */
body:not(.search-classic) #countrySearchInput {
    height: 100%;
    padding: 0 calc(var(--search-dot) * 0.45) 0 calc(var(--search-dot) * 1.1);
    border: none;
    border-radius: 999px;
    font-size: clamp(12px, 0.85vw, 18px);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
    opacity: 0;
    pointer-events: none;
    transition: opacity 250ms ease;
}

body:not(.search-classic) #countrySearch.open #countrySearchInput {
    opacity: 1;
    pointer-events: auto;
}

/* Der Standard-Fokusrahmen des Browsers legte einen harten schwarzen Ring um die Pille
   (im Entwurf ist sie rein weiß). Die aufgezogene Pille IST hier die Fokus-Anzeige –
   sie erscheint ausschließlich, wenn das Feld den Fokus hat. */
body:not(.search-classic) #countrySearchInput:focus { outline: none; }

/* Tastaturbedienung: der Kreis-Knopf bekommt einen sichtbaren Fokusring (nur bei
   Tastatur-Fokus, nicht beim Klicken) – sonst wäre er beim Durchtabben unsichtbar. */
body:not(.search-classic) #searchToggle:focus-visible {
    outline: 2px solid #d97b0f;
    outline-offset: 2px;
}

/* „n Treffer" rechts in der Pille, auf der Zeilenmitte (JS setzt display:block,
   deshalb line-height statt Flex). */
body:not(.search-classic) #searchCount {
    right: calc(var(--search-dot) * 0.35);
    padding: 0;
    line-height: var(--search-dot);
    font-size: clamp(11px, 0.72vw, 15px);
}

/* Das ✕ des Prototyps entfällt – geschlossen wird über den Stern-Knopf, Esc,
   die Landauswahl oder einen Klick daneben. */
body:not(.search-classic) #searchClose,
body:not(.search-classic) #countrySearch.open #searchClose { display: none; }

/* Ausblenden GEMEINSAM MIT DER LEGENDE (Fokus- und Detail-Ansicht, gleiche 400 ms
   wie #mapChrome). Ausnahme: ist das Feld gerade OFFEN (body.search-open), bleibt es
   stehen – sonst verschwände es mitten im Tippen, sobald die Maus über ein Land
   wandert. Beim Schließen fällt die Ausnahme weg und es blendet sofort mit aus. */
body:not(.search-classic):not(.search-open).world-focus #countrySearch,
body:not(.search-classic):not(.search-open).world-focus #searchToggle,
body:not(.search-classic):not(.search-open).detail-open #countrySearch,
body:not(.search-classic):not(.search-open).detail-open #searchToggle {
    opacity: 0;
    pointer-events: none;
}

/* --- neues Design, mobil ---------------------------------------------------- */
@media (max-aspect-ratio: 1/1), (max-width: 500px) {
    :root {
        --search-dot: calc(44px * var(--legend-scale, 1));     /* gut tippbar, folgt Legende */
        --search-open-w: min(calc(100vw - 32px), 260px);
        --search-center-y: calc(34px + env(safe-area-inset-bottom));
        /* Seit 09.09.2026: derselbe Abstand zur grünen Linie wie bei den Legendenpunkten
           darüber (Wunsch), NICHT proportional zum (viel größeren) --search-dot – sonst
           rückt der Kreis weiter nach rechts als die Legende. Basis ist darum wie bei
           .map-legend das mobile --legend-dot (21px * --legend-scale, s. o.), mit demselben
           Faktor 0,15 wie .map-legend-item padding-left. */
        --search-left: calc(var(--map-chrome-left) + 2px + calc(21px * var(--legend-scale, 1)) * 0.15);
    }

    /* Die Legende rückt so weit nach oben, dass der Knopf darunter Platz hat
       (Kreismitte 34 + halber Kreis 22 + Luft ≈ 76). Nur im neuen Design – im
       Prototyp steht unten links nichts, dort bleibt der alte Abstand. */
    body:not(.search-classic) #mapLegendWrap { padding-bottom: calc(76px + env(safe-area-inset-bottom)); }

    /* Der Prototyp legt die Leiste mobil an den OBEREN Rand und die Liste in den
       normalen Fluss. Hier bleibt alles wie auf dem Desktop: Pille unten links,
       Trefferliste klappt nach oben auf. */
    body:not(.search-classic) #countrySearch.open #countrySearchList {
        position: absolute;
        bottom: 100%;
        margin: 0 0 6px;
    }

    body:not(.search-classic) #countrySearch.open #countrySearchInput {
        height: 100%;
        padding: 0 14px 0 calc(var(--search-dot) * 1.05);
        font-size: 16px;                                      /* kein iOS-Zoom */
    }

    body:not(.search-classic) #countrySearch.open #searchCount {
        right: 12px;
        padding: 0;
        line-height: var(--search-dot);
        font-size: 13px;
    }
}

/* ---------------------------------------------------------------------------
   Messhilfe „Tempo messen" (T-Testbereich, doku/28)
   Kleine Anzeige unten rechts mit Bildrate, längstem Frame und den Dauern der
   teuren Render-Schritte. Gedacht für die Prüfung auf iPhone/iPad.
   Bewusst schlicht und billig: fester Platz, keine Filter, keine Schatten – die
   Anzeige darf das, was sie misst, nicht selbst ausbremsen. Sie liegt über allem
   und ist trotzdem durchklickbar (pointer-events: none).
--------------------------------------------------------------------------- */
#perfHud {
    position: fixed;
    right: 8px;
    /* Nicht ganz unten: dort steht seit doku/36 die Zeile „Datenschutz | Impressum".
       Der Aufschlag ist deren Höhe samt Abstand – die Messhilfe legt sich sonst
       genau darüber. */
    bottom: 44px;
    z-index: 60;
    max-width: 62vw;
    padding: 8px 10px;
    border-radius: 8px;
    background: rgba(0, 0, 0, 0.72);
    color: #fff;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.45;
    white-space: pre;
    pointer-events: none;
}
#perfHud[hidden] { display: none; }

/* Auffällig, sobald ein Bild länger als zwei Sechzigstelsekunden gebraucht hat: der Wert
   „längste Pause" ist das eigentliche Ruckelmaß und soll auf dem Handy ins Auge fallen.
   Die Klasse sitzt am Kasten (nicht an einzelnen Zeilen), damit der Text per textContent
   geschrieben werden kann – Projektkonvention, kein innerHTML. */
#perfHud.perf-bad {
    color: #ffd7d1;
    box-shadow: inset 0 0 0 2px #ff7b6b;
}

@media (max-width: 768px) {
    #perfHud {
        font-size: 11px;
        right: 6px;
        bottom: calc(42px + var(--kb-inset, 0px));
    }
}

/* ---------------------------------------------------------------------------
   Rechtliche Verweise unten rechts (doku/36)
   „Datenschutz  |  Impressum" – zwei Verweise auf die statischen Seiten
   datenschutz.html und impressum.html im selben Ordner.

   Sie sind DAUERHAFT sichtbar: anders als Kartenname und Legende (#mapChrome)
   blenden sie in der Fokus- und der Detail-Ansicht NICHT aus, damit sie in jeder
   Ansicht mit einem Klick erreichbar bleiben.

   Lesbarkeit: das Grau #6d6e71 bekommt denselben weichen weißen Schein wie der
   eingeblendete Ländername (.country-sticker.centered) – gestaffelte drop-shadows
   statt eines Kissens. Dadurch steht die Zeile auf dem dunkelblauen Wasser der
   Karte 1, auf dem hellen Wasser der Karte 4 und auf dem weißen Wasser der
   Fokus-Ansicht gleichermaßen lesbar, ohne einen sichtbaren Kasten mitzubringen.

   Der Ladeschirm liegt darüber (z-index 200); die Zeile erscheint trotzdem erst
   MIT der Karte (body.app-ready), damit sie nicht während des Ladens unter dem
   Schirm hervorschimmert.
--------------------------------------------------------------------------- */
#legalLinks {
    position: fixed;
    /* env(...) für iPhone-Sicherheitsränder (das Layout ist viewport-fit=cover),
       Bewusst OHNE --kb-inset: die Fußzeile wandert nicht mit der Tastatur nach oben
       (Meldung 14.10.2026, iPhone Chrome/Safari); bei offener Suche blendet sie aus. */
    right: calc(clamp(14px, 2vw, 28px) + env(safe-area-inset-right, 0px));
    bottom: calc(clamp(12px, 1.6vh, 20px) + env(safe-area-inset-bottom, 0px));
    /* Über der Karte und den Landes-Stickern (50), unter der Messhilfe (60) und
       dem Ladeschirm (200). */
    z-index: 55;
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: var(--font);
    font-weight: 500;
    font-size: 13px;
    line-height: 1;
    /* Farbe = Leitfarbe der laufenden Karte, gesetzt von renderMapChrome() auf :root; der
       Grundwert hier greift auf der Prototyp-Karte, die keinen Namen hat.
       Seit 09.09.2026 OHNE Schein/Schatten (Wunsch: absolut kein Schatten unter den beiden
       Verweisen) – zum Anschauen, wie ein Schatten wie bei den vier Menü-Kreisen wirkt, gibt
       es das Häkchen „submenu-shadow" im T-Testbereich (s. u.). */
    color: var(--map-title-fill, #4a4b4d);
    opacity: 0;
    transition: opacity 420ms ease;
}

body.app-ready #legalLinks {
    opacity: 1;
}

/* Suche offen (Tastatur oben): Fußzeile ausblenden, damit sie nicht auf der Suchzeile liegt. */
body.search-open #legalLinks {
    opacity: 0;
    pointer-events: none;
}

/* PROBEWEISE (Häkchen „submenu-shadow" im T-Testbereich): derselbe Schatten wie bei
   „Legende-shadow" (drop-shadow 0 2px 5px rgba(0,0,0,.2)), damit er der Schrift folgt und
   keinen Kasten um die Verweise legt. Beim Neuladen ist das Häkchen AUS. */
body.submenu-shadow #legalLinks {
    filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.2));
}

#legalLinks a {
    color: inherit;
    text-decoration: none;
    /* Etwas Fläche um die kleine Schrift, damit der Verweis auch mit dem Finger
       sicher zu treffen ist – ohne dass die Zeile optisch größer wirkt. */
    padding: 6px 2px;
    margin: -6px 0;
}

/* Beim Überfahren nur unterstreichen: die Schriftfarbe ist die Leitfarbe der Karte, ein
   Farbwechsel müsste für jede der fünf Karten eigens gewählt werden. */
#legalLinks a:hover,
#legalLinks a:focus-visible {
    text-decoration: underline;
    text-underline-offset: 3px;
}

#legalLinks a:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 2px;
    border-radius: 3px;
}

/* Feiner senkrechter Trennstrich zwischen den beiden Verweisen. */
#legalLinks .legal-sep {
    width: 1px;
    height: 11px;
    background: currentColor;
    opacity: 0.55;
}

@media (max-aspect-ratio: 1/1), (max-width: 500px) {
    #legalLinks {
        font-size: 12px;
        gap: 8px;
    }
    /* Copyright-Zeile nur am PC (Wunsch 13.10.2026): mobil entfällt sie. */
    #legalLinks .legal-copy,
    #legalLinks .legal-copy-sep {
        display: none;
    }
}

/* --- Fußzeilen-Band in der mobilen LDA (Kundenvorlage 28.09.2026) ----------
   Auf dem Handy zeigt die Länder-Detailansicht (body.detail-open) die beiden Verweise NICHT
   mehr als schwebende Zeile wie sonst auf der Karte, sondern als durchgehendes grünes Band
   über die volle Breite unten – genau wie in „distances on smartphone.pdf". Grünton dort
   nachgemessen: #3e794a. Nur in der LDA (nicht auf der Karten-/Fokus-Ansicht): dort bleibt
   die schlichte schwebende Zeile ohne Kasten (Wunsch 09.09.2026, s. Kommentar oben)
   unverändert. #countryDetail lässt dafür unten Platz (s. dortiger Kommentar). */
@media (max-width: 700px) {
    body.detail-open #legalLinks {
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        /* OHNE das hier: width:100% gilt am content-box (Standard), das Padding kommt on
           top dazu, der Kasten wird 32px breiter als der Bildschirm und „Impressum" ragt
           rechts raus (Meldung 28.09.2026, iPhone 13 Pro). */
        box-sizing: border-box;
        justify-content: flex-end;
        gap: 10px;
        padding: 10px 16px;
        padding-right: calc(16px + env(safe-area-inset-right, 0px));
        padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
        background: #3e794a;
        color: #fff;
    }
}

/* Umrahmung der Fokus-Ansicht als EIGENE EBENE (18.10.2026, doku/29 Abschn. 10).
   Sie ist mit einer SVG-Maske ausgeschnitten (#focus-halo-mask, bei Kanada tausende
   Stützpunkte). Ohne eigene Ebene wird diese Maske bei JEDEM Bild der Blende neu gerastert
   (Bildpausen 120 bis 150 ms beim Hovern von Kanada/USA). Als Ebene bleibt sie stehen und nur
   ihre Deckkraft ändert sich. Reine Tempo-Maßnahme, Aussehen unverändert.
   Rückweg: diese Regel entfernen. */
.focus-halo,
.focus-halo-group {
    will-change: opacity;
    transform: translateZ(0);
}

/* Umrahmung als Canvas (script.js, HALO_MODE): zwei Ebenen direkt über dem Karten-SVG, unter
   Kartenname, Stickern und allen Bedienelementen (wie vorher die Ringe im SVG). Nur die
   Deckkraft ändert sich beim Ein-/Ausblenden, gezeichnet wird bei Änderungen. */
.halo-canvas {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
    pointer-events: none;
    opacity: 0;
}

