/* Grundstile, Teil 1 von 8: Schriften, Farb-Token (hell/dunkel), Grundlayout, Topbar, Leisten, Fenster.
   Die acht Dateien unter css/base/ werden in dieser Reihenfolge
   eingebunden; bei gleicher Spezifitaet gewinnt die spaetere Regel.
   Neue Regeln an die Datei anhaengen, zu der sie fachlich gehoeren,
   und dabei pruefen, ob eine spaetere Datei sie ueberschreibt. */

/* =====================================================================
 Geolyser-MapApp - Geolyser Brand Base
 + linke Sidebar (OneNote-Style)
 ===================================================================== */

/* ---- Web-Fonts (self-hosted) ---- */
@font-face { font-family: "IBM Plex Sans"; font-weight: 300; font-style: normal; font-display: swap;
    src: url("/fonts/IBMPlexSans-Light.ttf") format("truetype"); }
@font-face { font-family: "IBM Plex Sans"; font-weight: 400; font-style: normal; font-display: swap;
    src: url("/fonts/IBMPlexSans-Regular.ttf") format("truetype"); }
@font-face { font-family: "IBM Plex Sans"; font-weight: 500; font-style: normal; font-display: swap;
    src: url("/fonts/IBMPlexSans-Medium.ttf") format("truetype"); }
@font-face { font-family: "IBM Plex Sans"; font-weight: 600; font-style: normal; font-display: swap;
    src: url("/fonts/IBMPlexSans-SemiBold.ttf") format("truetype"); }
@font-face { font-family: "Space Grotesk"; font-weight: 300 700; font-style: normal; font-display: swap;
    src: url("/fonts/SpaceGrotesk-VariableFont_wght.ttf") format("truetype-variations"); }

/* ---- Brand-Tokens ---- */
:root {
    --c-dark:        #181B1D;
    --c-dark-soft:   #1f2426;
    --c-graphite:    #394043;
    --c-light:       #FFFFFF;

    --c-primary:     #007FB4;
    --c-primary-hi:  #00A0D2;
    --c-cyan:        #3BBDE8;
    --c-cyan-soft:   #9BD9F5;
    --c-primary-dk:  #00608D;
    --c-primary-xdk: #004161;

    --c-signal:      #02FE89;
    --c-signal-dim:  rgba(2, 254, 137, 0.18);
    --c-signal-dk:   #00c76a;

    --c-error:       #ff5c65;
    --c-error-bg:    rgba(255, 92, 101, 0.08);
    --c-warn:        #ffc04a;

    --bg:            var(--c-dark);
    --bg-elevated:   #20262a;
    --bg-panel:      #1c2126;       /* Sidebars / Topbar-Body */
    --bg-card:       rgba(255, 255, 255, 0.03);
    --border:        rgba(155, 217, 245, 0.10);
    --border-hi:     rgba(59, 189, 232, 0.35);
    --fg:            #eef3f6;
    --muted:         #8a979e;
    --muted-hi:      #b8c3c9;
    --input-bg:      #0d1214;
    --input-bg-ro:   #0a0d0f;
    --map-info-bg:   rgba(24, 27, 29, 0.82);

    --radius-sm:     6px;
    --radius:        10px;
    --radius-lg:     16px;

    /* Seitenabstand IN den beiden Panels. Kopfreihe, Modus-Kasten,
       Suchfeld, Filterzeile, Fussleiste und die Koerper der Modi
       halten alle diesen einen Wert, damit nichts gegeneinander
       versetzt steht. Vorher standen dort 8, 10 und 12 Pixel
       nebeneinander, und der Versatz war an den Raendern der
       modus-kopf-Kaesten deutlich zu sehen.

       Das Mass richtet sich nach den LISTEN, die es im Panel schon
       gibt: .features-panel-list und .sidebar-list laufen ohne
       Seitenabstand durch, .golf-panel-body haelt zwei Pixel. Die
       Kaesten und Reihen sollen genauso breit sein wie sie, nicht
       schmaler. Zwei Pixel bleiben, damit ein Rahmen nicht auf der
       Panelkante klebt. */
    --panel-rand:    2px;

    --shadow-card:   0 10px 40px rgba(0,0,0,0.45), 0 1px 0 rgba(255,255,255,0.02) inset;
    --shadow-lift:   0 14px 50px rgba(0, 127, 180, 0.18);

    --map-surface:       #0a0d0f;
    --map-control-bg:    rgba(24, 27, 29, 0.85);
    --map-control-bg-lo: rgba(24, 27, 29, 0.82);
    --topbar-bg:         rgba(24, 27, 29, 0.7);

    --sidebar-rail-w:    52px;
    --sidebar-w:         300px;
    --topbar-h:          56px;

    --body-gradient:
        radial-gradient(1200px 600px at 80% -10%, rgba(0, 127, 180, 0.14), transparent 60%),
        radial-gradient(900px 500px at -10% 110%, rgba(2, 254, 137, 0.06), transparent 60%),
        var(--bg);

    --font-ui:       "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --font-display:  "Space Grotesk", "IBM Plex Sans", sans-serif;

    color-scheme: dark;
}

:root[data-theme="light"] {
    /* Skala (von dunkel nach hell): --bg : Body-Hintergrund
     * (blau-grau) --bg-card : Sidebar-Innenhuelle (etwas
     * heller als --bg) --bg-elevated : Modal-Card / Topbar
     * (weiss + leichte Tönung) --input-bg : Inputs / Selects
     * (rein weiss) */
    --bg:            #e3ecf4;
    --bg-elevated:   #ffffff;
    --bg-panel:      #eaf1f8;       /* Sidebars: leicht bluer als Modal-Card */
    --bg-card:       #eaf1f8;
    --border:        #c1ced9;       /* solider blau-grau-Rand */
    --border-hi:     #8fa6b8;
    --fg:            #161b1e;
    --muted:         #566168;
    --muted-hi:      #2a3438;
    --input-bg:      #ffffff;
    --input-bg-ro:   #e8eef4;
    --map-info-bg:   rgba(255, 255, 255, 0.88);
    --c-signal:      #00b368;
    --c-signal-dim:  rgba(0, 179, 104, 0.14);
    --c-signal-dk:   #009458;
    --shadow-card:   0 10px 30px rgba(0, 40, 60, 0.08), 0 1px 0 rgba(255, 255, 255, 0.6) inset;
    --shadow-lift:   0 14px 50px rgba(0, 127, 180, 0.15);
    --map-surface:       #e4ecf0;
    --map-control-bg:    rgba(255, 255, 255, 0.92);
    --map-control-bg-lo: rgba(255, 255, 255, 0.88);
    --topbar-bg:         rgba(255, 255, 255, 0.85);
    --body-gradient:
        radial-gradient(1200px 600px at 80% -10%, rgba(0, 127, 180, 0.08), transparent 60%),
        radial-gradient(900px 500px at -10% 110%, rgba(0, 179, 104, 0.05), transparent 60%),
        var(--bg);
    color-scheme: light;
}

/* ---- Alias-Tokens ----
 * Diese Namen kursierten historisch im Code (css/base/, JS, HTML),
 * waren aber NIE definiert. Ohne Fallback fiel die Deklaration komplett
 * weg (transparente Hintergruende), mit Fallback galt immer der
 * theme-blinde Festwert (z.B. dunkelgruene Haken auf Dark).
 * Details + Findings: docs/DESIGN.md §11.
 * Fuer NEUEN Code weiterhin die Original-Tokens verwenden —
 * diese Aliase sind Kompatibilitaets-Schicht, kein Freibrief. */
:root {
    --text:            var(--fg);
    --text-muted:      var(--muted);
    --c-fg:            var(--fg);
    --c-fg-muted:      var(--muted);
    --c-border:        var(--border);
    --bg-page:         var(--bg);
    --bg-input:        var(--input-bg);
    --c-bg-input:      var(--input-bg);
    --c-bg-elev:       var(--bg-elevated);
    --surface:         var(--bg-elevated);
    --surface-2:       var(--bg-card);
    --surface-elevated: var(--bg-elevated);
    --panel-bg:        var(--bg-panel);
    --bg-surface:      var(--bg-panel);
    --card-bg:         var(--bg-card);
    --bg-deep:         var(--map-surface);
    --bg-hover:        rgba(255, 255, 255, 0.08);
    --hover-bg:        var(--bg-hover);
    --bg-elevated-hover: rgba(255, 255, 255, 0.06);
    --c-danger:        var(--c-error);
    --danger:          var(--c-error);
    --err:             var(--c-error);
    --c-success:       var(--c-signal-dk);
    --c-green:         var(--c-signal-dk);
    --c-success-fg:    var(--c-signal-dk);
    --c-success-bg:    var(--c-signal-dim);
    --c-amber:         var(--c-warn);
    --accent:          var(--c-primary-hi);
    --c-accent:        var(--c-primary-hi);
    --c-accent-soft:   var(--c-cyan-soft);
    --accent-hover:    var(--c-primary);
    --radius-md:       8px;
    --font-body:       var(--font-ui);
    --font-mono:       ui-monospace, "Cascadia Mono", Consolas, monospace;
}
:root[data-theme="light"] {
    --bg-hover:        rgba(0, 0, 0, 0.06);
    --bg-elevated-hover: rgba(0, 0, 0, 0.05);
    --c-amber:         #c98a00;   /* --c-warn (#ffc04a) ist auf Weiss zu hell */
}

/* ---- Reset / Base ---- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }

/* REGEL Icons im Dunkelmodus . Alle Dateien unter /img/icons/ sind
   einfarbig dunkel gezeichnet. Als <img> in einem Knopf werden sie im
   Dunkelmodus hier GRUNDSAETZLICH hell, ohne eigene Regel je Knopf. Wer
   eine andere Faerbung braucht (Hover-Tuerkis, aktiv), schreibt sie wie
   bisher spezifischer; diese Regel steht absichtlich frueh in der Datei
   und verliert gegen jede spaetere gleich starke Regel. Ausnahme
   ausdruecklich mit .icon-farbig. Neue Zeichen weiterhin bevorzugt als
   Inline-SVG mit currentColor (DESIGN.md par. 8). */
/* :where() haelt die Staerke bei (0,1,1), damit jede Knopf-Regel mit
   Klasse (Hover, aktiv) weiter gewinnt. */
:where([data-theme="dark"]) :where(button, a, [role="button"]) img:where([src*="/img/icons/"]):not(.icon-farbig) {
    filter: brightness(0) invert(1);
}

body {
    font-family: var(--font-ui);
    color: var(--fg);
    background: var(--body-gradient);
    -webkit-font-smoothing: antialiased;
    line-height: 1.4;
}
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 600; margin: 0 0 .4em 0; }
a { color: var(--c-primary-hi); text-decoration: none; }
a:hover { text-decoration: underline; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
button:disabled { cursor: not-allowed; opacity: .55; }

/* ---- Topbar ---- */
.topbar {
    height: var(--topbar-h);
    display: flex; align-items: center; justify-content: space-between;
    padding: 0 16px;
    background: var(--topbar-bg);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--border);
    position: sticky; top: 0; z-index: 50;
}
.brand { display: flex; align-items: center; gap: 10px; color: var(--fg); }
.brand:hover { text-decoration: none; }
.customer-logo { height: 28px; width: auto; display: block; }
.wordmark { font-family: var(--font-display); font-weight: 600; letter-spacing: .01em; }
.topbar-right { display: flex; align-items: center; gap: 10px; flex: 1 1 auto; justify-content: flex-end; }
#user-pill {
    color: var(--muted-hi);
    font-size: .85em;
    /* gleiche Hoehe wie die Icon-Buttons in der
 Topbar (36px), damit der Pill optisch in einer Linie sitzt. */
    height: 36px;
    padding: 0 14px;
    border-radius: 999px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    /* b: jetzt klickbarer Button (Profil-Modal). */
    cursor: pointer;
    font-family: inherit;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    transition: border-color .12s, background .12s, color .12s;
}
#user-pill:hover {
    border-color: var(--c-primary-hi);
    color: var(--c-primary-hi);
}
#user-pill:focus-visible {
    outline: 2px solid var(--c-primary-hi);
    outline-offset: 2px;
}
#user-pill.role-admin       { color: var(--c-signal); border-color: var(--c-signal-dim); }
#user-pill.role-editor      { color: var(--c-primary-hi); border-color: var(--border-hi); }
#user-pill.role-contributor { color: var(--c-cyan); }
#user-pill.role-viewer      { color: var(--muted); }

/* User-Pill auf map.html ist jetzt ein
 quadratischer Avatar-Icon-Btn statt einer Username-Text-Pille. Damit
 hat der Button immer die gleiche Groesse wie die anderen Topbar-Icon-
 Btns (36x36), unabhaengig von Username-Laenge. Dashboard/Trash haben
 weiterhin die Text-Pille (kein .icon-btn), also bleiben deren Styles
 in der Regel oben unangetastet — die folgenden Overrides greifen nur
 auf #user-pill.icon-btn. */
#user-pill.icon-btn {
    /* Explizit 36x36 + padding:0 (Specificity-Override gegen den
 Default-`#user-pill { height:36px; padding:0 14px }`- Block
 oben). Mobile- Override (44x44) folgt im
 @media-(max-width:600px)-Block. */
    width: 36px;
    height: 36px;
    padding: 0;
    /* Ghost-Tint analog zu `.ghost` (Specificity-Hack: #user-pill ueber-
       schreibt sonst den Ghost-Background). Dark-Mode override unten. */
    background: rgba(0, 0, 0, 0.04);
    border-radius: var(--radius);
    overflow: hidden;
    line-height: 0;
    justify-content: center;
}
#user-pill.icon-btn:hover {
    background: rgba(0, 0, 0, 0.10);
}
[data-theme="dark"] #user-pill.icon-btn {
    background: rgba(255, 255, 255, 0.06);
}
[data-theme="dark"] #user-pill.icon-btn:hover {
    background: rgba(255, 255, 255, 0.12);
}
#user-pill.icon-btn .user-pill-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--bg-card);
    flex: 0 0 auto;
}
#user-pill.icon-btn .user-pill-avatar > svg,
#user-pill.icon-btn .user-pill-avatar > img {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
}

/* ---- Buttons ---- */
.primary, .ghost {
    border-radius: var(--radius);
    padding: 8px 14px;
    font-weight: 500;
    border: 1px solid transparent;
    transition: background .12s ease, border-color .12s ease, color .12s ease;
    text-align: center;
    text-decoration: none;
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
}
.primary {
    background: var(--c-primary);
    color: var(--c-light);
    border-color: var(--c-primary-dk);
}
.primary:hover { background: var(--c-primary-hi); }
.primary:disabled { background: var(--c-primary-dk); }
.ghost {
    /* "transparent" laesst .ghost-Buttons in
 vielen Modals identisch zur Karten-Card aussehen (--bg-card ist im
 Dark-Mode quasi transparent). Wir setzen einen dezenten Tint, der
 die Buttons gegen den Modal-Bg abhebt aber kein Brand-Akzent ist. */
    background: rgba(0, 0, 0, 0.04);
    color: var(--fg);
    border-color: var(--border);
}
.ghost:hover {
    background: rgba(0, 0, 0, 0.10);
    border-color: var(--border-hi);
}
[data-theme="dark"] .ghost {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.14);
}
[data-theme="dark"] .ghost:hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.24);
}
.icon-btn { padding: 6px; line-height: 0; }
.icon-btn .icon { display: block; }
/* Footer-Icon-Btns einheitlich 48x34 — gilt fuer alle
 modal-footer--compact (Layers-Modal + DB-Modal) damit Import, Bulk-
 Load, Bulk-Delete (und im DB-Modal auch Edit, Add, Export) optisch
 identisch ausgerichtet sind. Image- und SVG-Inhalte werden zentriert. */
.modal-footer--compact .icon-btn {
    width: 48px;
    height: 34px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.modal-footer--compact .icon-btn img,
.modal-footer--compact .icon-btn svg {
    display: block;
}
/* Bulk-"Aus Projekt entfernen" wird dynamisch injiziert und per
 hidden-Attribut (JS: btn.hidden = !inProject()) nur in Nicht-Default-
 Projekten gezeigt. Das display:inline-flex oben ueberstimmt sonst den
 UA-Default [hidden]{display:none}, sodass der Button auch im Default-
 Projekt sichtbar bliebe. Hidden hart durchsetzen. */
.modal-footer--compact .icon-btn[data-action="bulk-unlink-project"][hidden] {
    display: none !important;
}

/* Theme toggle - Fix: beide Modi explizit, damit nicht im Dark-Mode
 * beide Icons sichtbar sind, wenn data-theme noch nicht gesetzt ist. */
.theme-toggle .icon-sun  { display: block; }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun  { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"]  .theme-toggle .icon-sun  { display: block; }
:root[data-theme="dark"]  .theme-toggle .icon-moon { display: none; }

/* ---- Map shell layout ---- */
.page--map { overflow: hidden; }
.map-shell {
    position: relative;
    display: flex;
    height: calc(100vh - var(--topbar-h));
    min-height: 0;
}
.map-canvas {
    flex: 1 1 auto;
    min-width: 0;
    background: var(--map-surface);
}

/* ---- Sidebar (OneNote-Style) -------------------------------------- */
.sidebar {
    position: relative;
    flex: 0 0 var(--sidebar-w);
    width: var(--sidebar-w);
    display: flex;
    flex-direction: row;
    background: var(--bg-panel);
    border-right: 1px solid var(--border);
    /* laengere + weichere Transition (cubic-
 * bezier ease-out) damit das Expand/Collapse fluessig wirkt. JS
 * defert den schweren renderList-Call passend zur Animations-
 * dauer (siehe sidebar.js + features-panel.js). */
    transition: width .26s cubic-bezier(0.22, 0.61, 0.36, 1),
                flex-basis .26s cubic-bezier(0.22, 0.61, 0.36, 1);
    will-change: width, flex-basis;
    overflow: hidden;
    /* ueber Leaflet-Controls (z 1000), damit der Mobile-Overlay-Modus
       (siehe @media unten) die Karten-Controls korrekt verdeckt. */
    z-index: 1100;
}
.sidebar--collapsed {
    flex-basis: var(--sidebar-rail-w);
    width: var(--sidebar-rail-w);
}
.sidebar-rail {
    flex: 0 0 var(--sidebar-rail-w);
    width: var(--sidebar-rail-w);
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 8px 0;
    gap: 4px;
    border-right: 1px solid var(--border);
}
.sidebar:not(.sidebar--collapsed) .sidebar-rail { display: none; }
.sidebar-rail-toggle, .sidebar-rail-add {
    width: 36px; height: 36px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm);
    background: transparent; border: 1px solid transparent;
    color: var(--fg);
}
.sidebar-rail-toggle:hover, .sidebar-rail-add:hover {
    background: var(--bg-card); border-color: var(--border-hi);
}
.sidebar-rail-count {
    margin-top: auto;
    font-size: .75em;
    color: var(--muted);
    padding: 4px 0;
}
.sidebar-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.sidebar--collapsed .sidebar-body { display: none; }

/* Kopfreihe der Layer-Leiste: nur noch die Knopfreihe. Die
 Ueberschrift ist weggefallen, der Kasten darunter
 (.sidebar-banner.modus-kopf) sagt dasselbe. Die Trennlinie ist mit ihr
 gegangen: der Rahmen des Kastens trennt schon.
 flex-wrap bleibt, damit die Knoepfe bei schmaler Leiste weiter in eine
 zweite Zeile rutschen statt sich zusammenzuquetschen. */
.sidebar-head {
    display: flex; align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
    padding: 10px var(--panel-rand) 8px;
}
.sidebar-head-actions {
    display: flex; gap: 4px;
    /* stand hier auf `0 0 auto`, durfte
     * also nicht schmaler werden als seine Wunschbreite. Die sieben
     * Knoepfe brauchen zusammen 244 px; sobald die Leiste schmaler ist
     * (auf einem Tablet mit 541 px sind es 40 % = 216 px, davon 203 px
     * fuer den Kopf), lief die Reihe ueber den Rand hinaus statt
     * umzubrechen, und `overflow-x: hidden` schnitt sie ab. Abgeschnitten
     * war ausgerechnet der letzte Knopf: "Einklappen". Er lag ausserhalb
     * der Leiste und war nicht anklickbar, die Leiste liess sich also
     * nur noch ueber den Umweg des Schienen-Umschalters schliessen.
     * Mit `0 1 auto` + `min-width: 0` schrumpft der Block und das
     * `flex-wrap` darin greift endlich: die Knoepfe stapeln sich in
     * eine zweite Zeile, so wie der Kommentar oben es immer gemeint
     * hat. Ab etwa 660 px aendert sich nichts, dort passt die Reihe
     * ohnehin in eine Zeile. */
    flex: 0 1 auto;
    min-width: 0;
    margin-left: auto;   /* Actions rechtsbuendig, auch in der 2. Zeile */
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* Der Einklapp-Knopf gehoert nicht zu den Layer-Werkzeugen daneben,
   er schliesst die ganze Leiste. Ein zusaetzlicher Abstand von 10 px
   (zum 4-px-Abstand der Reihe) setzt ihn sichtbar ab, ohne ihn
   herauszureissen. Bricht die Reihe um, faellt der Abstand weg: am
   Zeilenanfang wuerde er nur schief aussehen. */
.sidebar-head-actions .sidebar-einklappen { margin-left: 10px; }

.sidebar-list {
    list-style: none;
    margin: 0; padding: 4px 0;
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
}
.sidebar-empty {
    margin: 16px 12px;
    color: var(--muted);
    font-size: .9rem;
    text-align: center;
    line-height: 1.5;
}
.sidebar-empty-plus {
    display: inline-flex;
    width: 22px; height: 22px;
    align-items: center; justify-content: center;
    border-radius: 6px;
    background: var(--bg-card);
    color: var(--c-primary-hi);
    vertical-align: -5px;
}

/* Layer-Row */
.layer-row {
    position: relative;
    display: grid;
    grid-template-columns: 14px 1fr auto auto;
    gap: 6px;
    align-items: center;
    /* Das Innenmass der Zeile, unabhaengig vom Seitenabstand des
       Panels: die Zeile laeuft ueber die volle Breite, ihr Text steht
       eingerueckt. */
    padding: 6px 10px 6px 8px;
    border-left: 3px solid transparent;
    cursor: default;
}
.layer-row + .layer-row { border-top: 1px solid var(--border); }
.layer-row:hover { background: var(--bg-card); }
.layer-row--draw { border-left-color: var(--c-signal); background: var(--c-signal-dim); }
.layer-row--draft .layer-name-text { font-style: italic; }
.layer-row.is-flash { animation: flash-row .8s ease; }
@keyframes flash-row {
    0%   { background: var(--c-signal-dim); }
    100% { background: transparent; }
}

.layer-swatch {
    width: 12px; height: 12px;
    border-radius: 3px;
    background: var(--swatch, var(--c-primary));
    box-shadow: 0 0 0 1px rgba(0,0,0,0.25) inset;
}
.layer-name {
    text-align: left;
    background: transparent; border: 0; padding: 2px 0;
    color: var(--fg);
    font-size: .92rem;
    overflow: hidden;
    display: flex; align-items: center; gap: 6px;
    min-width: 0;
}
.layer-name-text {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    flex: 1 1 auto;
}
.layer-name-edit {
    /* Inline-Rename-Input war im Dark-Mode
 weiß-auf-weiß. Ursache: das outerHTML-replace ersetzt den
 .layer-name-Button durch ein .layer-name-edit-Input, das aber
 (a) nicht im grid-area 'name' landete und (b) durch Browser-
 Default-Style ein weißes Hintergrund-Rendering bekam, das die
 var(--input-bg)-Regel nicht zuverlässig überschrieb. Fix:
 explizit grid-area + !important auf bg/color, damit der Dark-
 Theme-Wert sicher gewinnt. */
    grid-area: name;
    width: 100%;
    background: var(--input-bg) !important;
    color: var(--fg) !important;
    border: 1px solid var(--border-hi);
    border-radius: var(--radius-sm);
    padding: 2px 6px;
    font-size: .9rem;
}
.layer-badge {
    font-size: .7em;
    background: var(--c-warn);
    color: #1f1500;
    padding: 1px 6px;
    border-radius: 999px;
    font-weight: 600;
}
/* geaenderte Layer bekommen einen "Editiert"-
 Badge in amber statt einem alleinstehenden "*"-Marker. Selber Pill-
 Stil wie der Draft-Badge (var(--c-warn)), aber andere Hintergrund-
 Farbe damit Draft und Editiert visuell unterscheidbar bleiben. */
.layer-badge--dirty {
    background: var(--c-amber, #c98a00);
    color: #1f1500;
}
[data-theme="dark"] .layer-badge--dirty {
    background: #f0c270;
    color: #2a1f00;
}
/* Stats-Farbsystem app-weit.
 Jede Stat-Klasse hat einen leichten Pastell-Hintergrund + Border in der
 Farb-Familie. Der TEXT bleibt in der jeweiligen Mode-Schriftfarbe
 (var(--fg)) — keine farbigen Texte. Dark-Mode bekommt etwas mehr
 Background-Alpha damit der Effekt sichtbar bleibt.
 Gilt fuer popup-stat egal wo: Map-Popup, Feature-Modal, DB-Sidepanel,
 Layer-Aggregat. */
.popup-stat--vol {
    background: rgba(139, 92, 246, 0.14);
    border: 1px solid rgba(139, 92, 246, 0.45);
    color: var(--fg);
    font-weight: 600;
}
.popup-stat--cut {
    background: rgba(220, 80, 80, 0.14);
    border: 1px solid rgba(220, 80, 80, 0.45);
    color: var(--fg);
}
.popup-stat--fill {
    background: rgba(70, 170, 90, 0.14);
    border: 1px solid rgba(70, 170, 90, 0.45);
    color: var(--fg);
}
.popup-stat--net {
    background: rgba(70, 130, 200, 0.12);
    border: 1px solid rgba(70, 130, 200, 0.45);
    color: var(--fg);
    font-weight: 600;
}
.popup-stat--length {
    background: rgba(244, 114, 182, 0.14);
    border: 1px solid rgba(244, 114, 182, 0.45);
    color: var(--fg);
}
.popup-stat--area {
    background: rgba(16, 185, 129, 0.14);
    border: 1px solid rgba(16, 185, 129, 0.45);
    color: var(--fg);
}
.popup-stat--perim {
    background: rgba(255, 127, 80, 0.16);
    border: 1px solid rgba(255, 127, 80, 0.50);
    color: var(--fg);
}
.popup-stat--elev {
    background: rgba(245, 158, 11, 0.16);
    border: 1px solid rgba(245, 158, 11, 0.50);
    color: var(--fg);
}
/* GPS-Z-Chips (GPS-Z-Trennung): direkt gemessene Hoehen
 leicht tuerkis abgesetzt, damit sie nicht mit der DSM-Hoehe (--elev)
 verwechselt werden. */
.popup-stat--gpsz {
    border-color: rgba(6, 130, 156, 0.55);
    color: var(--c-primary-hi, #06829c);
}
/* SuperAdmin: GPS-Hoehe im Popup klickbar (Edit). Button sieht aus wie
 * der Pill-Stat, mit dezentem Stift-Hinweis. */
.popup-stat--editable {
    cursor: pointer;
    font: inherit;
    line-height: inherit;
}
.popup-stat--editable::after { content: " \270E"; opacity: 0.7; }
.popup-stat--editable:hover {
    border-color: var(--c-primary, #007FB4);
    filter: brightness(1.06);
}

/* --- Fuelleffekte --------------------------- */
/* Breite Kachel im Feature-Farb-Picker: volle Zeile unter den
 Reinfarben, damit der Unterschied zu den Farb-Tiles sichtbar ist. */
.feature-fill-effect-btn {
    flex-basis: 100%;
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    margin-top: 6px;
    padding: 8px 10px;
    /* in beiden Designs deutlich vom Farb-Raster
     abgehoben — tuerkiser Verlauf + kraeftige Border + Hover-Lift. */
    border: 1.5px solid rgba(0, 127, 180, 0.55);
    border-radius: var(--radius-sm, 6px);
    background: linear-gradient(135deg,
        rgba(0, 127, 180, 0.16), rgba(0, 179, 104, 0.12));
    color: var(--c-primary-hi, #06829c);
    font-weight: 600;
    cursor: pointer;
    font-size: 0.88em;
    transition: border-color .15s, background .15s,
                box-shadow .15s, transform .12s;
}
.feature-fill-effect-btn:hover {
    border-color: var(--c-primary, #007FB4);
    background: linear-gradient(135deg,
        rgba(0, 127, 180, 0.28), rgba(0, 179, 104, 0.20));
    box-shadow: 0 2px 10px rgba(0, 127, 180, 0.30);
    transform: translateY(-1px);
}
.feature-fill-effect-btn:active { transform: translateY(0); }
[data-theme="light"] .feature-fill-effect-btn {
    background: linear-gradient(135deg,
        rgba(0, 127, 180, 0.10), rgba(0, 179, 104, 0.08));
    color: var(--c-primary, #007FB4);
}
[data-theme="light"] .feature-fill-effect-btn:hover {
    background: linear-gradient(135deg,
        rgba(0, 127, 180, 0.18), rgba(0, 179, 104, 0.14));
    box-shadow: 0 2px 10px rgba(0, 127, 180, 0.22);
}
.feature-fill-effect-btn.is-active {
    border-color: var(--c-primary);
    box-shadow: inset 0 0 0 1px rgba(0, 127, 180, 0.45);
}

/* Fuelleffekt-Button halbiert, rechts daneben
 der Muster-Button. Beide teilen sich die Zeile mit Abstand dazwischen. */
.feature-fill-row {
    flex-basis: 100%;
    width: 100%;
    display: flex;
    gap: 8px;
    margin-top: 6px;
}
.feature-fill-effect-btn--half {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    margin-top: 0;        /* Abstand kommt jetzt vom .feature-fill-row */
}
/* Muster-Button: gleiche Form wie der Fuelleffekt-Button, eigener
 violett-getoenter Akzent zur optischen Trennung. */
.feature-pattern-btn {
    flex: 1 1 0;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 8px 10px;
    border: 1.5px solid rgba(124, 92, 255, 0.55);
    border-radius: var(--radius-sm, 6px);
    background: linear-gradient(135deg,
        rgba(124, 92, 255, 0.16), rgba(0, 127, 180, 0.10));
    color: var(--c-primary-hi, #6f5cff);
    font-weight: 600;
    cursor: pointer;
    font-size: 0.88em;
    transition: border-color .15s, background .15s, box-shadow .15s, transform .12s;
}
.feature-pattern-btn:hover {
    border-color: #7c5cff;
    background: linear-gradient(135deg,
        rgba(124, 92, 255, 0.28), rgba(0, 127, 180, 0.16));
    box-shadow: 0 2px 10px rgba(124, 92, 255, 0.30);
    transform: translateY(-1px);
}
.feature-pattern-btn:active { transform: translateY(0); }
.feature-pattern-btn.is-active {
    border-color: #7c5cff;
    box-shadow: inset 0 0 0 1px rgba(124, 92, 255, 0.45);
}
[data-theme="light"] .feature-pattern-btn {
    background: linear-gradient(135deg,
        rgba(124, 92, 255, 0.10), rgba(0, 127, 180, 0.06));
    color: #5a45d8;
}

/* --- Audioaufnahmen pro Feature (Slot-Rework) */
.feature-audio-status {
    display: block;
    margin-top: 4px;
    font-size: 0.82em;
    color: var(--muted-hi);
}
/* 5 flache Slots in einer Reihe — wie die Bilder-Reihe, aber niedriger
 (40px hoch statt quadratisch). */
.audio-slots {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 6px;
    margin-top: 4px;
}
.audio-slot {
    position: relative;
    /* etwas hoeher als 40px, damit unter dem Avatar das Aufnahme-Datum
     Platz hat. Leere/Record-Slots zentrieren das Mic. */
    height: 54px;
    border: 1px dashed var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--input-bg);
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
}
.audio-slot.is-filled { border-style: solid; }
.audio-slot--recording {
    border-color: var(--c-error, #d7301f);
    border-style: solid;
}
.audio-slot--disabled { opacity: 0.45; }
.audio-slot--loading {
    grid-column: 1 / -1;
    height: auto;
    border: 0;
    background: transparent;
    color: var(--muted-hi);
}
/* Klick-Button fuellt den ganzen Slot. */
.audio-slot-btn {
    width: 100%; height: 100%;
    border: 0; background: transparent;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    color: var(--c-primary, #007FB4);
    padding: 0;
}
.audio-slot-btn:disabled { cursor: not-allowed; }
.audio-slot-btn:hover:not(:disabled) { background: var(--bg-card); }
.audio-slot-btn .audio-ico { fill: currentColor; }
/* Gefuellter Slot: Avatar oben, Datum darunter. */
.audio-slot-play {
    flex-direction: column;
    gap: 3px;
}
.audio-avatar {
    position: relative;
    width: 26px; height: 26px;
    flex: 0 0 auto;
}
.audio-avatar svg {
    width: 100%; height: 100%;
    display: block;
    border-radius: 50%;
}
/* Das Bild liegt jetzt UEBER dem Initialen-SVG; laedt es nicht (kein
   Avatar gesetzt, 404), entfernt `wireAudioAvatars` es wieder und das
   SVG darunter bleibt stehen. */
.audio-avatar-img {
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}
.audio-play-badge {
    position: absolute;
    bottom: -3px; right: -3px;
    width: 14px; height: 14px;
    border-radius: 50%;
    background: var(--c-primary, #007FB4);
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 0 0 1.5px var(--input-bg);
}
.audio-play-badge svg { width: 9px; height: 9px; }
.audio-slot-play.is-playing .audio-play-badge {
    background: var(--c-error, #d7301f);
}
.audio-date {
    font-size: 0.6em;
    line-height: 1.1;
    color: var(--muted-hi);
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.audio-slot-btn.is-recording {
    color: var(--c-error, #d7301f);
    animation: geolyser-audio-pulse 1s ease-in-out infinite;
}
@keyframes geolyser-audio-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}
/* Mikrofon-Icon (schwarzes SVG via <img>) — im Dark Mode hell faerben. */
.audio-ico-mic { display: block; opacity: 0.85; }
[data-theme="dark"] .audio-ico-mic { filter: invert(1); }
/* Kleines rotes Loesch-X oben rechts (wie bei den Bildern). */
.audio-slot-remove {
    position: absolute;
    top: 2px; right: 2px;
    width: 18px; height: 18px;
    border-radius: 999px;
    border: 0;
    background: var(--c-error, #d7301f);
    color: #fff;
    cursor: pointer;
    line-height: 1;
    font-size: 0.8em;
    padding: 0;
    display: flex; align-items: center; justify-content: center;
}
.audio-slot-remove:hover { filter: brightness(1.12); }

/* --- Muster-Generator-Modal --------------- */
.pattern-body { display: flex; flex-direction: column; gap: 12px; }
.pattern-preview-wrap {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    overflow: hidden;
    line-height: 0;
}
.pattern-preview-canvas {
    width: 100%;
    height: 120px;
    display: block;
}
.pattern-field { display: flex; flex-direction: column; gap: 6px; }
.pattern-field .field-label { font-weight: 600; font-size: 0.86em; }
.pattern-bg-row { display: flex; align-items: center; gap: 12px; }
.pattern-check { display: inline-flex; align-items: center; gap: 6px; }
.pattern-bg-row input[type="color"],
.pattern-line-row input[type="color"] {
    width: 38px; height: 30px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 4px);
    background: transparent;
    cursor: pointer;
    padding: 0;
}
.pattern-lines { display: flex; flex-direction: column; gap: 6px; }
.pattern-line-row {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    flex-wrap: wrap;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    /* Hellblauer Zeilen-Hintergrund; im Dark Mode dunkel. */
    background: #E3ECF4;
}
[data-theme="dark"] .pattern-line-row {
    background: #272D31;
}
/* Eingabefelder im Muster-Modal: die Mini-Zahlenfelder bekommen den
 * App-Input-Farbton (hell #F0F3F6 / dunkel #0D1214) sowie denselben
 * Rahmen + die gleiche Abrundung + den gleichen Focus-Ring wie die
 * uebrigen App-Inputs (.field input). Das Namensfeld fuer eigene Muster
 * steht In der Stil-Bibliothek (.stil-bib-speichern). */
.pattern-mini input {
    background: #F0F3F6;
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-sizing: border-box;
}
.pattern-mini input:focus {
    outline: none;
    border-color: var(--border-hi);
    box-shadow: 0 0 0 3px rgba(0, 127, 180, 0.18);
}
[data-theme="dark"] .pattern-mini input {
    background: #0D1214;
}
.pattern-mini {
    display: flex;
    flex-direction: column;
    font-size: 0.72em;
    color: var(--muted-hi);
    gap: 2px;
}
.pattern-mini input {
    width: 58px;
    padding: 4px 6px;
}
.pattern-line-del {
    margin-left: auto;
    width: 26px; height: 26px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--bg-card);
    color: var(--c-error, #d7301f);
    cursor: pointer;
    font-size: 16px; line-height: 1;
}
.pattern-line-del:hover {
    background: var(--c-error, #d7301f);
    color: #fff; border-color: var(--c-error, #d7301f);
}
.pattern-add-line {
    align-self: flex-start;
    font-size: 0.82em;
    padding: 4px 10px;
}
.pattern-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.pattern-swatch {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 4px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--bg-card);
    cursor: pointer;
    font-size: 0.72em;
    color: var(--muted-hi);
    width: 78px;
}
.pattern-swatch:hover { border-color: var(--c-primary, #007FB4); }
.pattern-swatch img {
    width: 100%;
    height: 38px;
    object-fit: cover;
    border-radius: 3px;
    background:
        repeating-conic-gradient(#e9edf1 0% 25%, #cdd5dd 0% 50%) 0 / 12px 12px;
}
.pattern-footer { display: flex; justify-content: space-between; gap: 8px; }
/* Quadratische 40x40-Icon-Buttons im Muster-Modal-Footer
 * (Uebernehmen-Haken + Kein-Muster-clear). */
.pattern-icon-btn {
    width: 40px;
    height: 40px;
    min-width: 40px;
    min-height: 40px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
}
.pattern-icon-btn img,
.pattern-icon-btn svg { display: block; }
/* Fuelleffekt-Modal: Apply-Button (Checkmark) ebenfalls quadratisch 40x40.
 * Hoehere Spezifitaet (.filleffect-save-btn.filleffect-apply-btn) als die
 * Basis-Regel .filleffect-save-btn { padding:8px 20px }, damit die 40x40
 * tatsaechlich greifen. */
.filleffect-save-btn.filleffect-apply-btn {
    width: 40px;
    height: 40px;
    min-width: 40px;
    padding: 0;
}
/* Fuelleffekt-Footer: Clear-Button links, Apply (Checkmark) rechts —
 * gleiche Anordnung wie der Muster-Modal-Footer. */
.filleffect-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
}
/* clear-Icon (schwarze Linien) auf dem amber Button in beiden Themes
 * sichtbar halten. */
.pattern-clear-icon { width: 18px; height: 18px; }
[data-theme="dark"] .pattern-clear-icon { filter: invert(1); }

/* --- Stil-Bibliothek (js/stil-bibliothek.js) ----------------------
 Eigene und freigeschaltete fremde Linienstile bzw. Muster im Linienstil-
 und im Muster-Fenster: Liste mit Vorschau, Name, "von <Name>" bei
 fremden. Verwaltet wird im Einstellfenster (Zahnrad im Abschnittskopf,
 js/modus-setup.js). Eigene, nicht geteilte Eintraege tragen wie die
 Vorlagen einen gestrichelten Rand. */
.stil-bib-kopf { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.stil-bib-kopf > .field-label { font-weight: 600; font-size: 0.86em; }
.stil-zahnrad { width: 30px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center; }
.stil-bib { display: flex; flex-direction: column; gap: 8px; }
.stil-bib-liste {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 228px;
    overflow-y: auto;
}
.stil-zeile {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 3px 4px 3px 3px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-card);
}
.stil-zeile.ist-privat { border-style: dashed; }
.stil-zeile.ist-aktiv { border-color: var(--c-primary); box-shadow: 0 0 0 1px var(--c-primary) inset; }
.stil-wahl {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 2px 4px;
    border: 0;
    background: transparent;
    color: var(--fg);
    text-align: left;
    cursor: pointer;
}
.stil-wahl:hover .stil-name { color: var(--c-primary); }
.stil-vorschau {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 68px;
    height: 26px;
    border-radius: 4px;
    overflow: hidden;
    color: var(--fg);
    /* Schachbrett wie die Muster-Kacheln: auch weisse Linien bleiben sichtbar */
    background: repeating-conic-gradient(#e9edf1 0% 25%, #cdd5dd 0% 50%) 0 / 10px 10px;
}
.stil-vorschau img { width: 100%; height: 100%; object-fit: cover; display: block; }
.stil-text { display: flex; flex-direction: column; min-width: 0; }
.stil-name { font-size: .9em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stil-herkunft { font-size: .76em; color: var(--muted-hi); }
/* kleine Vorschau in der Zeile des Einstellfensters (.ms-zeile-bild) */
.stil-vorschau.stil-vorschau--klein { width: 44px; height: 22px; }
/* .ms-zeile-bild ist in js/modus-setup.js fuer Symbole auf 26 px gebaut;
   eine Linien- oder Mustervorschau braucht die Breite. */
.ms-zeile-bild:has(> .stil-vorschau--klein) { width: 46px; }
.ms-zeile-bild .stil-vorschau--klein svg { max-width: none; width: 44px; height: 18px; }
.stil-leer, .stil-hinweis { padding: 4px 2px; }
.stil-bib-speichern { display: flex; gap: 8px; }
.stil-bib-speichern input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 8px 10px;
    color: var(--fg);
    background: var(--input-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}
.stil-bib-speichern input:focus { outline: none; border-color: var(--border-hi); box-shadow: 0 0 0 3px rgba(0, 127, 180, 0.18); }
.stil-bib-speichern .icon-btn { width: 40px; height: 40px; padding: 0; display: inline-flex; align-items: center; justify-content: center; }

/* --- Linienstil-Fenster (js/line-style-modal.js) ------------------- */
.ls-modal { max-width: 480px; }
.ls-body { display: flex; flex-direction: column; gap: 12px; }
.ls-abschnitt { display: flex; flex-direction: column; gap: 6px; }
.ls-abschnitt > .field-label { font-weight: 600; font-size: 0.86em; }
.ls-vorschau {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    line-height: 0;
    padding: 4px 0;
    background: repeating-conic-gradient(#e9edf1 0% 25%, #cdd5dd 0% 50%) 0 / 12px 12px;
}
.ls-arten { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.ls-art {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 6px 4px 5px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-card);
    color: var(--fg);
    font-size: .76em;
    cursor: pointer;
}
.ls-art:hover { border-color: var(--border-hi); }
.ls-art.is-active { border-color: var(--c-primary); box-shadow: 0 0 0 1px var(--c-primary) inset; color: var(--c-primary); }
.ls-art span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.ls-zahlen .ls-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ls-zahlen .wand-field[hidden] { display: none; }
.ls-farbe-zeile { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ls-farbe-knopf {
    width: 36px;
    height: 36px;
    padding: 3px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-card);
    cursor: pointer;
}
.ls-farbe-feld { display: block; width: 100%; height: 100%; border-radius: 3px; }
.ls-farbe-feld.ist-leer { border: 1px dashed var(--muted); }
.ls-farbe-weg { padding: 6px 10px; font-size: .82em; }
.ls-farbe-weg[hidden] { display: none; }
/* .modal-footer setzt weiter unten justify-content:flex-end; Nebenwege
   (Kein Muster) stehen links, der Haken rechts. */
.modal-footer.ls-fuss,
.modal-footer.pattern-footer { justify-content: space-between; }
.ls-fuss-links { display: inline-flex; align-items: center; gap: 6px; }
.pattern-fuss-links { display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 480px) {
    .ls-arten { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ls-zahlen .ls-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Speichern-Icon-Button (Fuelleffekt-Dialog + Setup-Fenster). */
.filleffect-save-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 8px 20px;
}
/* Setup-Fenster: ruhiges, einheitliches Spacing. */
.filleffect-setup .filleffect-field { margin: 0 0 14px; display: block; }
.filleffect-setup .filleffect-field .field-label {
    display: block;
    margin-bottom: 6px;
    white-space: nowrap;
}
.filleffect-row {
    display: flex;
    align-items: flex-start;
    gap: 18px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
.filleffect-row .filleffect-field { margin: 0; }
/* alle Eingabefelder im Setup einheitlich gross + gleiche
 Hintergrundfarbe wie der Rest der App (hell #F0F3F6 / dunkel #0D1214). */
.filleffect-setup input[type="number"],
.filleffect-setup select {
    width: 150px;
    height: 36px;
    box-sizing: border-box;
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--input-bg, #0d1214);
    color: var(--fg);
    font-size: 0.92em;
}
[data-theme="light"] .filleffect-setup input[type="number"],
[data-theme="light"] .filleffect-setup select {
    background: #f0f3f6;
}
.filleffect-setup input[type="number"]:focus,
.filleffect-setup select:focus {
    outline: none;
    border-color: var(--c-primary, #007FB4);
}
/* Feld nur fuer eine Checkbox (Fett / Schattierung) — Label-Hoehe
 gleich wie die Eingabefelder daneben, damit die Reihe sauber sitzt. */
.filleffect-field--check .filleffect-checkline {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 36px;
    cursor: pointer;
    user-select: none;
}
.filleffect-field--check input[type="checkbox"] { margin: 0; }
.filleffect-check {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    padding-bottom: 6px;
    user-select: none;
}
.filleffect-setup > .filleffect-check { margin: 0 0 14px; padding-bottom: 0; }
/* Farb-Swatches: abgerundete Quadrate wie die uebrigen Farb-Picker
 der App (vorher Kreise). */
.filleffect-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.filleffect-swatch {
    width: 26px; height: 26px;
    border-radius: 6px;
    border: 2px solid var(--border);
    background: var(--sw);
    cursor: pointer;
    transition: transform .1s, box-shadow .15s, border-color .15s;
}
.filleffect-swatch:hover { transform: scale(1.1); }
.filleffect-swatch.is-active {
    border-color: var(--c-primary, #007FB4);
    box-shadow: 0 0 0 2px rgba(0, 127, 180, 0.35);
}
/* Verlauf-Swatch: Terrain-Farbskala als Mini-Gradient. */
.filleffect-swatch--gradient {
    background: linear-gradient(135deg,
        rgb(44,127,184) 0%, rgb(127,205,187) 33%,
        rgb(237,248,177) 66%, rgb(215,48,31) 100%);
}
/* Vorschau-Bereiche der Setup-Fenster. */
.filleffect-preview {
    margin-top: 2px;
    min-height: 110px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: rgba(127, 127, 127, 0.06);
    overflow: hidden;
}
.filleffect-preview-img,
.filleffect-preview-svg {
    display: block;
    max-width: 100%;
    max-height: 280px;
    width: auto;
}
/* Gelaende-Vorschau bewusst flacher, damit das Fenster ohne
 Scrollbalken auskommt. */
.filleffect-preview--terrain .filleffect-preview-img { max-height: 200px; }
/* Dual-Slider im Setup: Platz fuer die Wert-Labels unter den Handles
 und den Reset-Knopf rechts — sonst erzeugt der absolute Overflow eine
 dauerhafte Scrollbar im Modal-Body. */
.filleffect-setup .dsm-legend-slider {
    margin: 10px 34px 34px 8px;
}
.filleffect-setup { overflow-x: hidden; }
/* Gefaelle-Skalen-Auswahl. */
.filleffect-slope-choices {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.filleffect-slope-choice {
    padding: 6px 14px;
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--bg-page);
    color: var(--fg);
    cursor: pointer;
    font-size: 0.9em;
    transition: border-color .15s, background .15s;
}
.filleffect-slope-choice:hover { border-color: var(--c-primary-hi); }
.filleffect-slope-choice.is-active {
    border-color: var(--c-primary, #007FB4);
    background: rgba(0, 127, 180, 0.14);
    font-weight: 600;
}
.filleffect-preview-svg { width: 100%; height: auto; }
.filleffect-info { margin: 8px 0 0; }
.filleffect-source { width: 100%; }
/* Zusammenfassung im Haupt-Dialog: Farb-Chip + Mini-Vorschau. */
.filleffect-summary {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    min-height: 28px;
}
.filleffect-chip {
    display: inline-block;
    width: 18px; height: 18px;
    border-radius: 5px;
    border: 1.5px solid var(--border);
    background: var(--sw);
    vertical-align: middle;
}
.filleffect-mini {
    display: inline-block;
    border: 1px solid var(--border);
    border-radius: 5px;
    background: rgba(127, 127, 127, 0.10);
    vertical-align: middle;
}
/* Hoehenlinien-Label: dunkler Halo fuer helle Linienfarben. */
.geolyser-contour-label--dark-halo {
    text-shadow:
        -1px -1px 0 #333, 1px -1px 0 #333,
        -1px 1px 0 #333, 1px 1px 0 #333;
}
/* Typ-Kacheln im Fuelleffekt-Dialog. */
.filleffect-types {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    margin: 10px 0 14px;
}
.filleffect-type {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 10px;
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--bg-page);
    color: var(--fg);
    cursor: pointer;
    font-size: 0.9em;
}
.filleffect-type:hover { border-color: var(--c-primary-hi); }
.filleffect-type.is-active {
    border-color: var(--c-primary);
    background: rgba(0, 127, 180, 0.10);
}
/* Hoehenlinien-Beschriftung auf der Karte: kleiner Text mit
 weissem Halo, nicht klickbar. */
.geolyser-contour-label {
    font-size: 10px;
    font-weight: 700;
    color: #5d3a10;
    text-shadow:
        -1px -1px 0 #fff, 1px -1px 0 #fff,
        -1px 1px 0 #fff, 1px 1px 0 #fff;
    white-space: nowrap;
    pointer-events: none;
    transform: translate(-50%, -50%);
    /* Labels lagen je nach DOM-Reihenfolge HINTER dem
     SVG-Vektor-Container des Panes — explizit drueber heben. */
    z-index: 600 !important;
}
.geolyser-fill-overlay { pointer-events: none; }
/* Farbverlauf-Picker: Fuelleffekt-Setups + DSM-Modal-Legenden. */
/* Verlaufsfelder 44 x 28: so hoch wie das Zahnrad (.farbverlauf-einst,
   28 px), das in derselben Reihe steht. Gilt gleich fuer die DSM-
   Legenden (.dsm-ramp-swatch) und die Feuchtigkeitskarte
   (.fk-skala-feld), damit die Reihen ueberall gleich aussehen
   . */
.filleffect-swatch--wide { width: 44px; height: 28px; }
.filleffect-row--shade { align-items: flex-start; }
/* Schriftgroesse+Fett-Gruppe flowt in der Beschriftungs-
 Zeile (kein eigener Block). */
.filleffect-optgroup {
    display: contents;
}
/* Author-Regel display:contents wuerde sonst das UA [hidden]{display:none}
 ueberstimmen — Optgroup liesse sich nicht ausblenden. */
.filleffect-optgroup[hidden] {
    display: none;
}
/* Schatten-Eingaben etwas kuerzer, damit Staerke + Laenge sauber
 neben die Schattierungs-Checkbox passen. */
.filleffect-row--shade select,
.filleffect-row--shade input[type="number"] { width: 118px; }
.dsm-ramp-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    /* mehr Luft zwischen Picker, Slider + Hint im DSM-
     Modal — war zu gequetscht. */
    margin: 14px 0 12px;
}
.dsm-ramp-swatch {
    width: 44px; height: 28px;
    border-radius: 6px;
    border: 2px solid var(--border);
    cursor: pointer;
    transition: transform .1s, box-shadow .15s, border-color .15s;
}
.dsm-ramp-swatch:hover { transform: scale(1.08); }
.dsm-ramp-swatch.is-active {
    border-color: var(--c-primary, #007FB4);
    box-shadow: 0 0 0 2px rgba(0, 127, 180, 0.35);
}
.dsm-slope-ramp-bar {
    height: 12px;
    border-radius: 3px;
    border: 1px solid var(--border);
    margin: 4px 24px 2px;
}
.dsm-slope-ramp-labels {
    display: flex;
    justify-content: space-between;
    margin: 0 24px;
    font-size: 0.78em;
    opacity: 0.75;
}

/* Kreis-Radius-Chip — gleicher Stil
 wie Area (gruen), leicht blaustichig um ihn visuell zu unterscheiden. */
.popup-stat--radius {
    background: rgba(14, 165, 233, 0.14);
    border: 1px solid rgba(14, 165, 233, 0.45);
    color: var(--fg);
}
[data-theme="dark"] .popup-stat--vol    { background: rgba(139, 92, 246, 0.22); }
[data-theme="dark"] .popup-stat--cut    { background: rgba(220, 80, 80, 0.22); }
[data-theme="dark"] .popup-stat--fill   { background: rgba(70, 170, 90, 0.22); }
[data-theme="dark"] .popup-stat--net    { background: rgba(70, 130, 200, 0.22); }
[data-theme="dark"] .popup-stat--length { background: rgba(244, 114, 182, 0.22); }
[data-theme="dark"] .popup-stat--area   { background: rgba(16, 185, 129, 0.22); }
[data-theme="dark"] .popup-stat--perim  { background: rgba(255, 127, 80, 0.24); }
[data-theme="dark"] .popup-stat--elev   { background: rgba(245, 158, 11, 0.24); }
[data-theme="dark"] .popup-stat--radius { background: rgba(14, 165, 233, 0.22); }
/* Auch im Layer-Aggregat (Sidepanel-Expand) die farbigen Backgrounds
   verwenden — overrided das neutrale bg-card-Default. */
.layer-features-aggregate--rich .popup-stat--vol    { background: rgba(139, 92, 246, 0.14); border-color: rgba(139, 92, 246, 0.45); color: var(--fg); font-weight: 600; }
.layer-features-aggregate--rich .popup-stat--cut    { background: rgba(220, 80, 80, 0.14); border-color: rgba(220, 80, 80, 0.45); color: var(--fg); }
.layer-features-aggregate--rich .popup-stat--fill   { background: rgba(70, 170, 90, 0.14); border-color: rgba(70, 170, 90, 0.45); color: var(--fg); }
.layer-features-aggregate--rich .popup-stat--net    { background: rgba(70, 130, 200, 0.12); border-color: rgba(70, 130, 200, 0.45); color: var(--fg); font-weight: 600; }
.layer-features-aggregate--rich .popup-stat--length { background: rgba(244, 114, 182, 0.14); border-color: rgba(244, 114, 182, 0.45); color: var(--fg); }
.layer-features-aggregate--rich .popup-stat--area   { background: rgba(16, 185, 129, 0.14); border-color: rgba(16, 185, 129, 0.45); color: var(--fg); }
.layer-features-aggregate--rich .popup-stat--perim  { background: rgba(255, 127, 80, 0.16); border-color: rgba(255, 127, 80, 0.50); color: var(--fg); }
.layer-features-aggregate--rich .popup-stat--elev   { background: rgba(245, 158, 11, 0.16); border-color: rgba(245, 158, 11, 0.50); color: var(--fg); }
[data-theme="dark"] .layer-features-aggregate--rich .popup-stat--vol    { background: rgba(139, 92, 246, 0.22); }
[data-theme="dark"] .layer-features-aggregate--rich .popup-stat--cut    { background: rgba(220, 80, 80, 0.22); }
[data-theme="dark"] .layer-features-aggregate--rich .popup-stat--fill   { background: rgba(70, 170, 90, 0.22); }
[data-theme="dark"] .layer-features-aggregate--rich .popup-stat--net    { background: rgba(70, 130, 200, 0.22); }
[data-theme="dark"] .layer-features-aggregate--rich .popup-stat--length { background: rgba(244, 114, 182, 0.22); }
[data-theme="dark"] .layer-features-aggregate--rich .popup-stat--area   { background: rgba(16, 185, 129, 0.22); }
[data-theme="dark"] .layer-features-aggregate--rich .popup-stat--perim  { background: rgba(255, 127, 80, 0.24); }
[data-theme="dark"] .layer-features-aggregate--rich .popup-stat--elev   { background: rgba(245, 158, 11, 0.24); }
.popup-stat.has-vol-tooltip {
    position: relative;
    cursor: help;
}
.popup-stat.has-vol-tooltip > .vol-chip-tooltip {
    display: none;
    position: absolute;
    bottom: calc(100% + 6px);
    left: 0;
    z-index: 1300;
    background: var(--bg-card, #fff);
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 8px 10px;
    box-shadow: 0 6px 18px rgba(0,0,0,0.20);
    width: 240px;
    font-size: 0.82em;
    line-height: 1.45;
    white-space: normal;
}
.popup-stat.has-vol-tooltip:hover > .vol-chip-tooltip,
.popup-stat.has-vol-tooltip:focus > .vol-chip-tooltip,
.popup-stat.has-vol-tooltip:focus-within > .vol-chip-tooltip {
    display: block;
}
.popup-stat.has-vol-tooltip .vol-tooltip-svg {
    display: block;
    margin-top: 6px;
    width: 220px;
    height: auto;
    border-radius: 4px;
}
[data-theme="dark"] .popup-stat.has-vol-tooltip > .vol-chip-tooltip {
    background: #1f2024;
    color: #eee;
    border-color: rgba(255,255,255,0.18);
}

/* Sidebar-Footer. Reine Presence-Zeile, KEIN Undo mehr.
 Hintergrund + Borders transparent, soll sich nicht von der Sidebar
 abheben. Label "Online:" links, dann Avatare. Empty-Hint zeigt ein
 Incognito-Icon in coral. */
.sidebar-foot {
    margin-top: auto;
    padding: 8px var(--panel-rand);
    border-top: 0;
    background: transparent;
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 0 0 auto;
}
.sidebar-foot-row {
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: 30px;
}
.sidebar-foot-row--presence {
    flex-wrap: wrap;
    align-items: center;
}

/* Sammel-Hinweis auf ungespeicherte Layer, ueber der Praesenz-Zeile.
   Amber, weil es eine Warnung ist und keine Fehlermeldung: verloren ist
   noch nichts, es muss nur gespeichert werden. */
.sidebar-entwuerfe {
    justify-content: space-between;
    gap: 8px;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    /* Dieselben Amber-Werte wie .btn-amber weiter unten. NICHT als
       neue Token erfunden: --c-amber-bg und --c-amber-bd gibt es
       nicht, und genau solche Phantom-Namen haben schon einmal
       fehlende Dark-Mode-Hintergruende verursacht (DESIGN.md 11). */
    border: 1px solid rgba(201, 138, 0, 0.45);
    background: rgba(201, 138, 0, 0.12);
}
.sidebar-entwuerfe[hidden] { display: none; }
.sidebar-entwuerfe-zahl {
    font-size: 0.78em;
    color: var(--fg);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* "Alle speichern": nur die Diskette, und die Akzentfarbe nur in Rand
   und Symbol. Ein ganz ausgefuellter blauer Knopf zog im Fuss der
   Leiste mehr Aufmerksamkeit auf sich als die Sache wert ist: die
   Zeile daneben ist ein Hinweis, kein Auftrag, und der Knopf ist ein
   Angebot. Das Wort steht als title und aria-label daran. */
.sidebar-entwuerfe-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border-radius: var(--radius-sm);
    border: 1px solid var(--c-primary);
    background: transparent;
    color: var(--c-primary);
    cursor: pointer;
}
.sidebar-entwuerfe-btn:hover {
    border-color: var(--c-primary-hi);
    color: var(--c-primary-hi);
    background: var(--bg-card);
}
.sidebar-entwuerfe-btn:focus-visible {
    outline: 2px solid var(--c-primary-hi);
    outline-offset: 2px;
}
.sidebar-entwuerfe-btn svg {
    flex: 0 0 auto;
    width: 15px;
    height: 15px;
    display: block;
}
.sidebar-presence-label {
    font-size: 0.78em;
    color: var(--muted-hi);
    margin-right: 4px;
    flex: 0 0 auto;
}

/* Rueckgaengig im Fuss der Layer-Leiste, links neben "Online:".
   Gesperrt wird ueber aria-disabled statt ueber das disabled-Attribut:
   der Knopf soll auch im gesperrten Zustand anklickbar bleiben und den
   Grund als Kurzmeldung zeigen (auf Touch gibt es keinen Tooltip). */
.sidebar-undo-btn {
    width: 30px;
    height: 30px;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: transparent;
    border: 1px solid transparent;
    color: var(--fg);
    cursor: pointer;
    padding: 0;
}
/* Sobald etwas rueckgaengig zu machen ist, faerbt sich der Knopf
   dezent rose ein. Dieselbe Farbfamilie wie die Biotop-Kennung
   (rgba(236,72,153,...)), damit die Oberflaeche nicht noch einen
   weiteren Akzent bekommt. Kein Rot: hier geht nichts kaputt. */
.sidebar-undo-btn:not(.is-off) {
    color: #be185d;
    background: rgba(236, 72, 153, 0.10);
    border-color: rgba(236, 72, 153, 0.35);
}
[data-theme="dark"] .sidebar-undo-btn:not(.is-off) {
    color: #f9a8d4;
}
.sidebar-undo-btn:not(.is-off):hover {
    background: rgba(236, 72, 153, 0.20);
    border-color: rgba(236, 72, 153, 0.60);
}
.sidebar-undo-btn:hover {
    background: var(--bg-card);
    border-color: var(--border-hi);
}
.sidebar-undo-btn.is-off {
    color: var(--muted);
    opacity: 0.55;
}
.sidebar-undo-btn.is-off:hover {
    background: transparent;
    border-color: transparent;
}
/* Auf Touch-Geraeten die uebliche Mindestgroesse. */
@media (pointer: coarse) {
    .sidebar-undo-btn { width: 36px; height: 36px; }
}
.sidebar-presence-list {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: center;
    flex: 1 1 auto;
    min-width: 0;
}
.presence-empty-hint--incognito {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 999px;
    color: #ff7f7f;            /* coral */
    background: rgba(255, 127, 80, 0.12);
    border: 1px solid rgba(255, 127, 80, 0.45);
    box-shadow: 0 0 0 0 rgba(255, 127, 80, 0.4);
    animation: presence-empty-pulse 2.4s ease-in-out infinite;
}
@keyframes presence-empty-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255, 127, 80, 0.35); }
    50%      { box-shadow: 0 0 0 5px rgba(255, 127, 80, 0); }
}
[data-role="sidebar-presence-host"]:empty::before {
    content: "-";
    color: var(--muted);
    font-size: 0.78em;
    opacity: 0.5;
}

/* Layer-Aggregat-Anzeige unter der ausgeklappten
 Features-Liste. Zeigt Σ Flaeche / Σ Laenge / Σ Umfang. */
.layer-features-aggregate {
    padding: 4px 12px 6px;
    margin: -2px 0 6px;
    color: var(--muted-hi);
    font-size: 0.78em;
    font-style: italic;
    border-bottom: 1px dotted var(--border);
}
/* Rich-Aggregate als Chip-Reihe statt Plain-String. */
.layer-features-aggregate--rich {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    font-style: normal;
}
.layer-features-aggregate--rich .popup-stat {
    background: var(--bg-card);
    color: var(--muted-hi);
    border: 1px solid var(--border);
    padding: 2px 6px;
    border-radius: 999px;
    font-size: 1em;
}

/* Feature-Checkbox in der Layer-Liste + ausgegraute
 Items wenn Feature unchecked. */
.layer-feature-checkbox {
    margin: 0 4px 0 0;
    cursor: pointer;
    flex-shrink: 0;
}
.layer-feature.is-off .layer-feature-name {
    text-decoration: line-through;
    opacity: 0.5;
}

/* Geteilt-Badge (Layer von anderem User per Invitation). */
.layer-badge--shared {
    background: #6c8cff;
    color: #fff;
}
[data-theme="dark"] .layer-badge--shared {
    background: #8da5ff;
    color: #1a1f3a;
}
.layer-meta {
    color: var(--muted);
    font-size: .75em;
    min-width: 1.5em;
    text-align: right;
}
.layer-toggles {
    display: flex; gap: 2px;
    align-items: center;
}
.layer-toggle {
    width: 26px; height: 26px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--muted);
}
/* der "Alle Layer ein-/ausblenden"-Button in den
   Kopf-Kasten (.sidebar-kopf-layer) ist zwar ein .layer-toggle (gleiche Farb-/
   is-on-Logik wie die Layer-Augen), soll aber so gross sein wie die
   uebrigen Head-Buttons dort (32x32 + 18px-Icon), nicht 26x26/16px
   wie die kompakten Augen in den Layer-Zeilen. */
.sidebar-kopf-layer .layer-toggle[data-action="toggle-all-visible"] {
    width: 32px; height: 32px;
    /* gleiche Eckenrundung wie die .ghost-Nachbarn
       (--radius 10px) statt --radius-sm (6px). */
    border-radius: var(--radius);
}
.sidebar-kopf-layer .layer-toggle[data-action="toggle-all-visible"] svg {
    width: 18px; height: 18px;
}
/* Er ist ein .layer-toggle und hat dessen Hover geerbt - der ist
   aber fuer die kleinen Augen in den Layer-Zeilen gedacht
   (transparenter Ruhezustand). Zwischen den .ghost-Nachbarn im Kopf,
   die auf --bg-elevated sitzen, war davon nichts zu sehen. Er
   bekommt hier denselben Ruhe- UND Hover-Zustand wie sie; die
   is-on-Faerbung des Knopfes bleibt unangetastet, weil sie spaeter
   in der Datei steht. */
.sidebar-kopf-layer .layer-toggle[data-action="toggle-all-visible"] {
    background: var(--bg-elevated);
    border-color: var(--border);
}
.sidebar-kopf-layer .layer-toggle[data-action="toggle-all-visible"]:hover {
    background: var(--bg-card);
    border-color: var(--border-hi);
    color: var(--fg);
}
[data-theme="light"] .sidebar-kopf-layer
    .layer-toggle[data-action="toggle-all-visible"] {
    background: var(--bg);
    border-color: var(--border);
}
[data-theme="light"] .sidebar-kopf-layer
    .layer-toggle[data-action="toggle-all-visible"]:hover {
    background: var(--bg-card);
    border-color: var(--c-primary-hi);
}
.layer-toggle:hover { color: var(--fg); background: var(--bg-card); border-color: var(--border); }
.layer-toggle.is-on { color: var(--c-primary-hi); background: rgba(0, 160, 210, 0.10); border-color: var(--border-hi); }

/* Kurzer Puls auf dem Auge. Die Platzvermessung blendet
   beim Start ihren eigenen Layer aus, damit die Messpunkte nicht doppelt
   auf der Karte liegen; ohne Signal sieht das aus, als waere der Layer
   verschwunden. Drei Pulse, danach nimmt sidebar.js die Klasse wieder
   weg (PULSE_MS). Ring statt Farbwechsel, damit die is-on-Logik des
   Knopfes unangetastet bleibt. */
@keyframes geolyser-toggle-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(0, 160, 210, 0.55); }
    50%      { box-shadow: 0 0 0 6px rgba(0, 160, 210, 0); }
}
.layer-toggle.is-pulsing {
    animation: geolyser-toggle-pulse 0.8s ease-out 3;
    color: var(--c-primary-hi);
}
/* Wer Bewegung abbestellt hat, bekommt denselben Hinweis statisch. */
@media (prefers-reduced-motion: reduce) {
    .layer-toggle.is-pulsing {
        animation: none;
        box-shadow: 0 0 0 3px rgba(0, 160, 210, 0.45);
    }
}
.layer-row--draw .layer-toggle[data-action="toggle-draw"].is-on {
    color: var(--c-signal); background: var(--c-signal-dim); border-color: var(--c-signal-dim);
}

/* Layer-Menu (dropdown) */
.layer-menu {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    margin: 4px 0 6px 0;
    box-shadow: var(--shadow-card);
}
.layer-menu hr {
    border: 0; border-top: 1px solid var(--border);
    margin: 4px 0;
}
.layer-menu button[role="menuitem"] {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 8px;
    background: transparent; border: 0; color: var(--fg);
    border-radius: var(--radius-sm);
    text-align: left;
    font-size: .9rem;
}
.layer-menu button[role="menuitem"]:hover { background: var(--bg-card); }
.layer-menu button[role="menuitem"].is-destructive { color: var(--c-error); }
.layer-menu button[role="menuitem"].is-destructive:hover { background: var(--c-error-bg); }
/* Gesperrter Menue-Eintrag: sichtbar, grau, und NICHT
   pointer-events:none. Der Klick wird gebraucht: er zeigt den Grund als
   Kurzmeldung (sidebar.js, onClick). Auf Touch ist das der einzige Weg
   dorthin, dort gibt es kein Hover und damit keinen Tooltip. */
.layer-menu button[role="menuitem"]:disabled {
    opacity: 0.42;
    cursor: not-allowed;
    pointer-events: none;
}
.layer-menu button[role="menuitem"].is-disabled {
    opacity: 0.42;
    cursor: help;
}
.layer-menu button[role="menuitem"].is-disabled:hover {
    background: transparent;
}
.layer-menu-colors {
    display: flex; flex-wrap: wrap; gap: 4px;
    padding: 4px 6px 6px 6px;
}
.layer-color-pick {
    width: 18px; height: 18px;
    border-radius: 4px;
    background: var(--swatch, var(--c-primary));
    border: 2px solid transparent;
    box-shadow: 0 0 0 1px rgba(0,0,0,0.20) inset;
}
.layer-color-pick.is-on { border-color: var(--fg); }
.layer-color-pick:hover { transform: scale(1.06); }

/* ---- Features-Panel (rechte Sidebar) -------------------------------- */
/* Spiegelbild zur linken Sidebar - dieselben Tokens (--sidebar-w,
   --sidebar-rail-w), Border auf der LINKEN statt rechten Kante. */
.features-panel {
    position: relative;
    flex: 0 0 var(--sidebar-w);
    width: var(--sidebar-w);
    display: flex;
    flex-direction: row-reverse;
    background: var(--bg-panel);
    border-left: 1px solid var(--border);
    /* smoothere Expand/Collapse-Transition,
 * gleiche Werte wie .sidebar. JS-Seite (features-panel.js expand)
 * defert den teuren renderList nach Transition-Ende. */
    transition: width .26s cubic-bezier(0.22, 0.61, 0.36, 1),
                flex-basis .26s cubic-bezier(0.22, 0.61, 0.36, 1);
    will-change: width, flex-basis;
    overflow: hidden;
    z-index: 1100;
}
.features-panel--collapsed {
    flex-basis: var(--sidebar-rail-w);
    width: var(--sidebar-rail-w);
}
.features-panel-rail {
    flex: 0 0 var(--sidebar-rail-w);
    width: var(--sidebar-rail-w);
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 8px 0;
    gap: 4px;
    border-left: 1px solid var(--border);
}
.features-panel:not(.features-panel--collapsed) .features-panel-rail { display: none; }
.features-panel-rail-toggle, .features-panel-rail-db {
    width: 36px; height: 36px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm);
    background: transparent; border: 1px solid transparent;
    color: var(--fg);
}
.features-panel-rail-toggle:hover, .features-panel-rail-db:hover {
    background: var(--bg-card); border-color: var(--border-hi);
}
/* Modus-Knoepfe der Schiene (js/panel-modi.js railSpiegeln, dazu
   "Punkt aufnehmen" der Schnellaufnahme). Form wie der Vollansicht-
   Knopf, Farbe aus der Akzent-Klasse der linken Leiste. */
.features-panel-rail-modi {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
}
.features-panel-rail-btn {
    /* 32 wie Aufklapp-Pfeil und Vollansicht darueber (Regel weiter
       unten bei .features-panel-rail-db). */
    width: 32px; height: 32px;
    padding: 0;
    flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--muted-hi);
    cursor: pointer;
}
.features-panel-rail-btn:hover {
    background: var(--bg-card);
    border-color: var(--border-hi);
    color: var(--fg);
}
.features-panel-rail-btn svg { display: block; width: 18px; height: 18px; }
[data-theme="light"] .features-panel-rail-btn { background: var(--bg); }
.features-panel--collapsed .features-panel-rail {
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none;
}
.features-panel-rail > * { flex-shrink: 0; }
.features-panel-rail-count {
    margin-top: auto;
    font-size: .75em;
    color: var(--muted);
    padding: 4px 0;
}
.features-panel-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.features-panel--collapsed .features-panel-body { display: none; }

/* Der Kopf steht in ZWEI Reihen: oben die Knoepfe (Einklappen links,
   Vollansicht und Projektumschalter rechts), darunter ueber die volle
   Breite die Reiterzeile der Panel-Modi (js/panel-modi.js). Die
   Reiterzeile liegt weiter IM Kopf: ein eigenes Element daneben waere
   von den Modus-Ansichten ausgeblendet worden, die alle Geschwister
   des Kopfes verstecken. */
.features-panel-head {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    row-gap: 8px;
    /* Keine Trennlinie mehr: der Rahmen des Kastens darunter
       (.features-panel-banner.modus-kopf) trennt schon, zwei Linien
       direkt uebereinander sahen nach Fehler aus. */
    padding: 10px var(--panel-rand) 8px;
}
.features-panel-head-row {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
/* Rechte Knopfgruppe. `margin-left:auto` haelt sie auch dann rechts,
   wenn der Titel wegfaellt (das tut er, sobald Reiter dastehen). */
.features-panel-head-tools {
    flex: 0 0 auto;
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 6px;
}
/* Fragezeichen im Fenster-Kopf (js/modal-hilfe.js), links vom
   Schliessen-Kreuz. Zurueckhaltend: es soll gefunden werden, wenn man
   es sucht, und sonst nicht stoeren. */
.modal-header .modal-hilfe-btn {
    margin-left: auto;
    color: var(--muted-hi);
    flex: 0 0 auto;
    /* Derselbe Kantenradius wie das Schliessen-Kreuz daneben. Ohne das
       erbt das Fragezeichen den groesseren Knopf-Radius (--radius,
       10 px) und sitzt sichtbar runder neben einem 6-px-Kreuz. */
    border-radius: var(--radius-sm);
}
.modal-header .modal-hilfe-btn:hover {
    color: var(--fg);
}
/* Steht ein Fragezeichen da, braucht das Kreuz den Automatik-Abstand
   nicht mehr, sonst schoebe er die beiden auseinander. */
.modal-header .modal-hilfe-btn + .modal-close-btn {
    margin-left: 4px;
}

/* Vollbild-Knopf im Fenster-Kopf (js/modal-vollbild.js), zwischen
   Fragezeichen und Schliessen-Kreuz. Gleiche Zurueckhaltung wie das
   Fragezeichen. Er schiebt sich selbst an den rechten Rand; steht ein
   Fragezeichen oder Minimieren-Knopf davor, rueckt er nur 4 px ab. */
.modal-header .modal-vollbild-btn {
    margin-left: auto;
    color: var(--muted-hi);
    flex: 0 0 auto;
    border-radius: var(--radius-sm);
}
.modal-header .modal-vollbild-btn:hover {
    color: var(--fg);
}
.modal-header .modal-hilfe-btn + .modal-vollbild-btn,
.modal-header .modal-minimize-btn + .modal-vollbild-btn,
.modal-header .modal-vollbild-btn + .modal-close-btn,
.modal-header .modal-vollbild-btn + [data-action="close-modal"] {
    margin-left: 4px;
}
/* Vollbild: das Fenster fuellt den ganzen Bildschirm ohne Rand. Nur ab
   1025 px; bis 1024 px sind alle Fenster ohnehin bildschirmfuellend
   (Tablet-Regel "Modals im Mobile auf echtem Vollbild"), dort ist der
   Knopf ausgeblendet. !important, weil viele Fenster ihre Breite als
   Inline-Stil tragen (style="max-width: 620px"). */
@media (min-width: 1025px) {
    .modal.is-vollbild {
        padding: 0;
        align-items: stretch;
        justify-content: stretch;
    }
    .modal.is-vollbild > .modal-card {
        width: 100% !important;
        max-width: none !important;
        height: 100dvh !important;
        max-height: none !important;
        margin: 0 !important;
        border: 0 !important;
        border-radius: 0 !important;
        /* Sicherheitsnetz: waechst ein Inhalt mit der Breite (Bilder,
           Raster), scrollt das Fenster, statt den Fuss unter den
           Bildschirmrand zu schieben. */
        overflow-y: auto;
    }
    /* Der Mittelteil nimmt die gewonnene Hoehe, der Fuss sitzt unten.
       Gleiche Bereiche wie beim Vollbild auf dem Smartphone (siehe
       "Universelles Fullscreen-Modal-Pattern"), dazu die Listen, die im
       Fenster auf 60vh begrenzt sind. */
    .modal.is-vollbild > .modal-card > .modal-footer,
    .modal.is-vollbild > .modal-card > .modal-actions {
        margin-top: auto !important;
        flex-shrink: 0;
    }
    .modal.is-vollbild > .modal-card > .modal-header {
        flex-shrink: 0;
    }
    .modal.is-vollbild > .modal-card > .modal-body,
    .modal.is-vollbild > .modal-card > .modal-form,
    .modal.is-vollbild > .modal-card > [data-role="body"],
    .modal.is-vollbild .load-modal-list,
    .modal.is-vollbild .bulk-edit-list,
    .modal.is-vollbild > .modal-card > .project-list,
    .modal.is-vollbild > .modal-card > .gcp-capture-body {
        flex: 1 1 auto !important;
        min-height: 0 !important;
        max-height: none !important;
        overflow-y: auto;
    }
    /* ArUco: die sechs Marker in einer Reihe statt 3 x 2, sonst werden
       sie in voller Breite so hoch, dass die Punktliste verschwindet. */
    .modal.is-vollbild .aruco-slots {
        grid-template-columns: repeat(6, minmax(0, 1fr));
    }
    /* Schaubilder duerfen mitwachsen: im Fenster sind sie auf eine feste
       Hoehe begrenzt, im Vollbild auf den Bildschirm abzueglich Kopf,
       Fuss und Kennzahlen. */
    .modal.is-vollbild .geolyser-profile-chart svg,
    .modal.is-vollbild .dsm-surface-svg {
        max-height: calc(100dvh - 220px);
    }
    .modal.is-vollbild .dsm-surface-view--mesh {
        height: calc(100dvh - 260px);
        max-height: none;
    }
}
@media (max-width: 1024px) {
    /* !important und .modal davor: die allgemeine Knopfregel
       ".modal .modal-header .icon-btn { display: inline-flex }" weiter
       unten ist spezifischer und blendet den Knopf sonst auf
       Smartphone und Tablet wieder ein. */
    .modal .modal-header .modal-vollbild-btn {
        display: none !important;
    }
    /* Ohne sichtbaren Vollbild-Knopf braucht das Kreuz wieder den
       Automatik-Abstand, ausser ein Fragezeichen oder Minimieren-Knopf
       steht davor. */
    .modal-header .modal-vollbild-btn + .modal-close-btn,
    .modal-header .modal-vollbild-btn + [data-action="close-modal"] {
        margin-left: auto;
    }
    .modal-header .modal-hilfe-btn + .modal-vollbild-btn + .modal-close-btn,
    .modal-header .modal-hilfe-btn + .modal-vollbild-btn + [data-action="close-modal"],
    .modal-header .modal-minimize-btn + .modal-vollbild-btn + .modal-close-btn {
        margin-left: 4px;
    }
}

.panel-modi-reiter {
    /* Eigene Reihe, volle Breite des Kopfes. */
    flex: 0 0 auto;
    width: 100%;
    display: flex;
    /* Kein Umbruch: erst wird gemessen, dann fallen die Woerter weg
       (js/panel-modi.js, passeBreiteAn). Eine umbrechende Zeile kann
       man nicht messen, sie passt per Definition immer. */
    flex-wrap: nowrap;
    gap: 4px;
    min-width: 0;
}
.panel-modi-reiter-btn {
    flex: 0 1 auto;
    max-width: 100%;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    /* Feste Hoehe 30 px, mit und ohne Wort. Mit Wort ergaben Innenabstand
       und Zeilenhoehe 31,6 px, im schmalen Zustand 30 px: der Kasten des
       Modus darunter sprang je nach Zahl der offenen Modi um 1,6 px
       . */
    height: 30px;
    box-sizing: border-box;
    padding: 0 10px;
    border-radius: var(--radius-sm);
    border: 2px solid var(--border);
    background: var(--bg-card);
    color: var(--muted-hi);
    font-size: 0.88rem;
    line-height: 1.25;
    cursor: pointer;
    overflow: hidden;
    white-space: nowrap;
}
/* Das Wechsel-Symbol steht an JEDEM Reiter. Es sagt nicht "hier bist
   du", sondern "hier wird umgeschaltet". */
.panel-modi-reiter-symbol {
    flex: 0 0 auto;
    display: inline-flex;
    line-height: 0;
    opacity: 0.75;
}
.panel-modi-reiter-symbol svg {
    width: 15px;
    height: 15px;
}
.panel-modi-reiter-wort {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Das eigene Symbol des Reiters (Datenbank, Blatt, Fahne, Stempel,
   Blitz). Es liegt still daneben und tritt erst an die Stelle des
   Wechsel-Pfeils, wenn die Woerter wegfallen - ein Kasten mit Pfeil
   sieht aus wie der naechste, ein Kasten mit dem Zeichen des Modus
   sagt, wohin er fuehrt. */
.panel-modi-reiter-eigen {
    display: none;
    flex: 0 0 auto;
    line-height: 0;
}
.panel-modi-reiter-eigen svg,
.panel-modi-reiter-eigen .vl-stamp-icon,
.panel-modi-reiter-eigen .bt-eco-icon {
    width: 16px;
    height: 16px;
}
.panel-modi-reiter-btn:hover {
    border-color: var(--border-hi);
    color: var(--fg);
}
.panel-modi-reiter-btn:hover .panel-modi-reiter-symbol {
    opacity: 1;
}
/* Nur waehrend der Messung (js/panel-modi.js, passeBreiteAn): die
   Reiter stehen kurz auf ihrer NATUERLICHEN Breite, damit ein
   Ueberlauf ueberhaupt entstehen kann. Ohne das schrumpfen sie
   stattdessen, und die Zeile laeuft nie ueber - dann kaeme der schmale
   Zustand nie zustande. */
.panel-modi-reiter.ist-messung .panel-modi-reiter-btn {
    flex: 0 0 auto;
    max-width: none;
}
.panel-modi-reiter.ist-messung .panel-modi-reiter-wort {
    overflow: visible;
    text-overflow: clip;
}

/* Zu wenig Platz: die Woerter fallen weg, es bleiben quadratische
   Symbol-Knoepfe - das Format, das der Kopf vor der Reiterzeile hatte,
   nur mit dem Zeichen des Modus statt des Pfeils. Den Namen traegt
   jeder Knopf weiter als `title` und `aria-label`. */
.panel-modi-reiter.is-schmal .panel-modi-reiter-wort,
.panel-modi-reiter.is-schmal .panel-modi-reiter-symbol {
    display: none;
}
.panel-modi-reiter.is-schmal .panel-modi-reiter-eigen {
    display: inline-flex;
}
.panel-modi-reiter.is-schmal .panel-modi-reiter-btn {
    width: 30px;
    height: 30px;
    flex: 0 0 auto;
    padding: 0;
    gap: 0;
    justify-content: center;
}
/* Wenn selbst die Symbole nicht mehr nebeneinander passen, darf die
   Zeile umbrechen: abgeschnittene Knoepfe waeren schlimmer. */
.panel-modi-reiter.is-schmal {
    flex-wrap: wrap;
    row-gap: 4px;
}
/* Die Datenbank ist der Grundzustand: aktiv, solange KEINE der drei
   Modus-Ansichten vorne liegt. Rein deklarativ, damit die Markierung
   auch dann stimmt, wenn ein Modus seine Ansicht selbst umschaltet. */
body:not([data-bt-view="bt"]):not([data-golf-view="golf"]):not([data-vorlagen-view="vorlagen"]):not([data-schnell-view="schnell"])
    .panel-modi-db {
    background: var(--bg-elevated);
    color: var(--fg);
    border-color: var(--c-primary);
}
.features-panel-collapse {
    width: 28px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--fg);
}
.features-panel-collapse:hover {
    background: var(--bg-card); border-color: var(--border-hi);
}

.features-panel-search {
    position: relative;
    margin: 8px var(--panel-rand);
}
.features-panel-search-icon {
    position: absolute; top: 50%; left: 8px;
    transform: translateY(-50%);
    color: var(--muted);
    pointer-events: none;
    line-height: 0;
}
.features-panel-search-input {
    width: 100%;
    background: var(--input-bg);
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 6px 28px 6px 30px;
    font-size: .9rem;
}
.features-panel-search-input:focus {
    border-color: var(--border-hi); outline: none;
}
.features-panel-search-clear {
    position: absolute; top: 50%; right: 4px;
    transform: translateY(-50%);
    width: 22px; height: 22px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; border: 0;
    color: var(--muted);
    border-radius: 999px;
}
.features-panel-search-clear:hover { color: var(--fg); background: var(--bg-card); }

.features-panel-filterbar {
    position: relative;
    display: flex; flex-wrap: wrap; gap: 4px;
    padding: 0 10px 8px 10px;
    border-bottom: 1px solid var(--border);
}
.features-panel-chip {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 3px 8px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--muted-hi);
    font-size: .8rem;
}
.features-panel-chip:hover { color: var(--fg); border-color: var(--border-hi); }
.features-panel-chip.is-active {
    color: var(--c-primary-hi);
    border-color: var(--border-hi);
    background: rgba(0, 160, 210, 0.10);
}
/* Filter-Zeile als Flex-Row, damit der neue
   "Zurücksetzen"-Button (setzt Layer + Tags + Sucheingabe zurueck)
   rechtsbuendig neben den beiden Chips sitzt. Der Popover ist absolut
   positioniert und bleibt vom Flex-Layout unberuehrt. */
.features-panel-filters {
    display: flex;
    align-items: center;
    gap: 6px;
}
.features-panel-filter-reset {
    margin-left: auto;
    width: 30px;
    height: 26px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
}
.features-panel-popover {
    position: absolute;
    top: calc(100% - 4px);
    left: 10px; right: 10px;
    z-index: 5;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-card);
    max-height: 280px;
    display: flex; flex-direction: column;
    overflow: hidden;
}
/* Autocomplete-Search-Box ueber der Tristate-Liste. */
.features-panel-popover-search {
    flex: 0 0 auto;
    padding: 6px 8px;
    border-bottom: 1px solid var(--border);
    background: var(--bg-card);
}
.features-panel-popover-search input {
    width: 100%;
    padding: 5px 8px;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--bg, #fff);
    color: var(--text);
    font-size: .85rem;
    box-sizing: border-box;
}
.features-panel-popover-search input:focus {
    outline: none;
    border-color: var(--c-primary);
}
.features-panel-popover-list {
    list-style: none; margin: 0; padding: 4px 0;
    overflow-y: auto;
    flex: 1 1 auto;
}
.features-panel-popover-row {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 10px;
    cursor: pointer;
    font-size: .85rem;
}
.features-panel-popover-row:hover { background: var(--bg-card); }
.features-panel-popover-row.is-highlight {
    background: rgba(0, 160, 210, 0.10);
    box-shadow: inset 3px 0 0 var(--c-primary, #007FB4);
}
.features-panel-popover-row input { accent-color: var(--c-primary); }
.features-panel-popover-empty {
    padding: 10px; color: var(--muted); font-size: .85rem; text-align: center;
}
.features-panel-popover-foot {
    border-top: 1px solid var(--border);
    padding: 4px;
    display: flex; justify-content: flex-end;
}
/* fruehere .ghost-btn-Definition entfernt — sie
 * wurde von der kanonischen Definition im Button-Differenzierungs-
 * Block (weiter unten, "Catchall fuer alle .ghost / .ghost-btn")
 * vollstaendig ueberschattet (gleiche Spezifitaet, spaeter in der
 * Kaskade, inkl. font: inherit). Kein visueller Unterschied. */

.features-panel-status {
    padding: 6px 12px;
    font-size: .75em;
    color: var(--muted);
    border-bottom: 1px solid var(--border);
}
.features-panel-list {
    list-style: none;
    margin: 0; padding: 0;
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
}
/* Lazy-Hint-Variante — gleiche Optik, leicht
 * italic + etwas mehr padding damit es als bewusster Hinweis lesbar
 * ist und nicht als "leeres Filter-Ergebnis" verwechselt wird. */
.features-panel-empty--lazy {
    font-style: italic;
    line-height: 1.5;
    padding: 24px 16px !important;
}
.features-panel-empty {
    padding: 16px 12px;
    color: var(--muted);
    font-size: .85rem;
    text-align: center;
}
.features-panel-item {
    display: grid;
    grid-template-columns: 10px 1fr;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    align-items: start;
}
.features-panel-item:hover { background: var(--bg-card); }
.features-panel-item.is-active {
    background: rgba(0, 160, 210, 0.10);
    border-left: 3px solid var(--c-primary-hi);
    padding-left: 9px;
}
.features-panel-dot {
    width: 10px; height: 10px;
    border-radius: 50%;
    margin-top: 5px;
    box-shadow: 0 0 0 1px rgba(0,0,0,0.30) inset;
}
.features-panel-item-body { min-width: 0; }
.features-panel-name {
    font-size: .92rem; color: var(--fg);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.features-panel-meta {
    margin-top: 2px;
    display: flex; flex-wrap: wrap; gap: 6px;
    font-size: .72em; color: var(--muted);
}
.features-panel-cat { color: var(--muted-hi); }
.features-panel-layer::before { content: "@ "; opacity: .6; }
.features-panel-tags {
    margin-top: 4px;
    display: flex; flex-wrap: wrap; gap: 3px;
}
.features-panel-tag, .features-panel-tag-more {
    font-size: .7em;
    background: var(--bg-card);
    border: 1px solid var(--border);
    color: var(--muted-hi);
    padding: 1px 5px;
    border-radius: 999px;
}
.features-panel-tag-more { color: var(--muted); font-style: italic; }

/* Teilezahl einer gesetzten Vorlage.
 *
 * Eine Vorlage aus Flaeche, Linie und Punkt steht in der Feature-Liste
 * und in der Datenbank-Vollansicht als EINE Zeile. Diese kleine Zahl
 * neben dem Namen sagt, dass mehr als eine Geometrie dahintersteckt -
 * ohne sie wundert sich jemand, warum ein Loeschen drei Formen von der
 * Karte nimmt.
 *
 * Bewusst dezent und in denselben Tokens wie die Tag-Chips daneben:
 * die Zahl ist ein Hinweis, keine Aktion. */
.features-panel-gruppe,
.db-gruppe {
    display: inline-block;
    margin-left: 4px;
    font-size: .7em;
    line-height: 1.4;
    min-width: 1.5em;
    text-align: center;
    background: var(--bg-card);
    border: 1px solid var(--border);
    color: var(--muted-hi);
    padding: 0 5px;
    border-radius: 999px;
    vertical-align: middle;
}

/* Mobile-Overlay-Modus.
 *
 * die Grenze lag hier bei 700 px und war
 * damit zu hoch. Zwei Regelbloecke widersprachen sich: dieser wollte
 * eine 340 px breite Leiste, die sich UEBER die Karte legt, der Block
 * `@media (max-width: 1024px)` weiter unten erzwingt aber mit
 * `!important` 40 % Breite. Ergebnis zwischen 541 und 700 px: eine
 * schmale Leiste im Overlay-Modus, obwohl daneben Platz gewesen waere.
 *
 * Das kostete nicht nur Flaeche. Die Leaflet-Steuerung klebt links
 * oben in der Karte, lag also komplett unter der Leiste: mit
 * aufgeklappter Layer-Liste waren auf einem 541-px-Geraet ALLE zwoelf
 * Werkzeugknoepfe verdeckt. Wer beim Zeichnen die Liste aufklappte,
 * kam an "Beenden", "Letzten Vertex loeschen" und "Abbrechen" nicht
 * mehr heran und sass fest (nachgemessen, alle drei nicht anklickbar).
 *
 * Ab 541 px laeuft die Leiste deshalb im QUERFORMAT im normalen Fluss
 * und schiebt die Karte zur Seite.
 *
 * Im Hochformat bis 1024 px und unter 541 px gilt: ein aufgeklapptes Panel legt sich bis an die Schiene
 * gegenueber ueber die Karte, und es ist immer nur eines offen (Block
 * "Hochformat bis 1024 px" weiter unten, js/leisten-lage.js). Daneben
 * waere ohnehin keine brauchbare Karte geblieben. Die Bedienung des
 * Zeichnens haengt dort nicht an der Werkzeugleiste: das Zeichen-Fenster
 * steht in der Leiste unter der Karte (js/zeichen-dock.js) mit eigenem
 * Abbrechen und Speichern. */
@media (max-width: 540px) {
    /* Lage und Breite: Block "Hochformat bis 1024 px" (dort bis an die
     * Schiene gegenueber). Hier bleibt nur der Schatten. */
    .sidebar:not(.sidebar--collapsed) {
        box-shadow: 8px 0 32px rgba(0,0,0,0.35);
    }

    .features-panel:not(.features-panel--collapsed) {
        box-shadow: -8px 0 32px rgba(0,0,0,0.35);
    }
}
/* Der Schienen-Hintergrund gilt weiter bis 700 px, er haengt nicht am
 * Overlay-Modus. */
@media (max-width: 700px) {
    .sidebar--collapsed .sidebar-rail { background: var(--bg-elevated); }
    .features-panel--collapsed .features-panel-rail { background: var(--bg-elevated); }
}

/* Zeichenziel-Streifen unten mittig auf der Karte (js/zeichenziel.js).
   Liegt IM Kartencontainer, deshalb ueber den Leaflet-Controls (z 1000)
   aber unter den Seitenleisten (z 1100), damit eine aufgeklappte Leiste
   ihn im Smartphone-Overlay verdeckt statt umgekehrt.

   UNTEN, nicht oben: oben mittig sass damals die Koordinatenanzeige
   (.map-status), die beiden lagen uebereinander. Steht
   auch sie unten; sie weicht dem Streifen aus (js/leisten-lage.js
   rechnet ihn als Hindernis und setzt sie darueber). Unten mittig steht
   allerdings die Attribution (.attribution-bottom-center, 11 px plus
   2 px Polster, also rund 17 px hoch). Der Streifen sitzt deshalb EINE
   ZEILE darueber und bleibt dabei mittig; er ist absolut positioniert
   und verschiebt nichts, was neben oder unter ihm liegt.

   Und NUR waehrend gezeichnet wird UND nur mit gesetztem Ziel. Die
   Frage "wo landet das?" stellt sich in dem Moment, in dem ein Werkzeug
   laeuft; die uebrige Zeit waere der Streifen nur ein Schild, das immer
   da haengt. `body.geolyser-pm-drawing` setzt map.js in
   `zeichnenSperre()` an genau den drei Ausstiegen, an denen ein
   Zeichenmodus beginnt und endet, `hat-ziel` setzt js/zeichenziel.js.
   Ohne Ziel bleibt er aus: "Kein Zeichenziel" waere keine Auskunft. */
.geolyser-zeichenziel {
    /* NUR dieses eine `display` in dieser Regel. Hier standen zwei -
       `none` oben, `inline-flex` weiter unten -, und die zweite Angabe
       gewinnt: der Streifen war IMMER sichtbar, sobald ein Ziel
       gesetzt war, ganz gleich ob gezeichnet wurde. Genau das war der
       Fehler, den die Regel eigentlich verhindern sollte. */
    display: none;
    position: absolute;
    /* Eine Zeile ueber der Attribution, nicht auf ihr. Mittig ueber der
       SICHTBAREN Karte und ueber jedem Knopf, der darunter laege
       (Zoom im Hochformat): js/leisten-lage.js setzt --zz-x, --zz-unten
       und die Hoechstbreite --unten-max-b. */
    bottom: var(--zz-unten, 22px);
    left: var(--zz-x, 50%);
    transform: translateX(-50%);
    z-index: 1050;
    align-items: center;
    gap: 6px;
    max-width: min(60vw, 420px, var(--unten-max-b, 420px));
    padding: 4px 10px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--map-info-bg, var(--bg-panel));
    color: var(--fg);
    font-size: 0.78rem;
    line-height: 1.3;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.25);
    cursor: pointer;
    white-space: nowrap;
}
body.geolyser-pm-drawing .geolyser-zeichenziel.hat-ziel {
    display: inline-flex;
}
.geolyser-zeichenziel:hover {
    border-color: var(--border-hi);
}
.geolyser-zeichenziel-punkt {
    width: 9px;
    height: 9px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--swatch, var(--c-primary));
}
.geolyser-zeichenziel-wort {
    color: var(--muted-hi);
}
.geolyser-zeichenziel-name {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
/* Er nimmt keine Klicks an: ein Aufklappen der Leiste mitten im
   Zeichnen wuerde die Karte verschieben. Er ist Anzeige, kein
   Bedienelement - und weil er ueber der Attribution liegt, darf er
   deren Links nicht abfangen. */
.geolyser-zeichenziel {
    pointer-events: none;
    cursor: default;
}
@media (max-width: 540px) {
    .geolyser-zeichenziel {
        max-width: min(calc(100vw - 24px), var(--unten-max-b, 100vw));
        font-size: 0.74rem;
    }
}

/* ---- Loading-Overlay ---- */
.map-loading {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    background: rgba(0,0,0,0.25);
    backdrop-filter: blur(2px);
    /* ueber Leaflet-Controls (z 1000), aber unter dem Modal (z 2000). */
    z-index: 1200;
    pointer-events: none;
}
.map-loading[hidden] { display: none; }
.map-loading-card {
    pointer-events: auto;
    background: var(--map-info-bg);
    border: 1px solid var(--border);
    color: var(--fg);
    padding: 14px 22px;
    border-radius: var(--radius);
    display: flex; gap: 12px; align-items: center;
    box-shadow: var(--shadow-card);
}
.spinner {
    width: 18px; height: 18px;
    border: 2px solid var(--border-hi);
    border-top-color: var(--c-primary-hi);
    border-radius: 50%;
    animation: spin .9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Error-Banner / Toast ---- */
/*
 * Wichtig zur z-index-Ordnung: Leaflet setzt .leaflet-top und .leaflet-bottom
 * (Container fuer Zoom, Layer-Control, Geoman-Toolbar etc.) auf z-index 1000.
 * Damit unsere Overlays nicht von der Geoman-Toolbar oder dem Layer-Control
 * verdeckt werden, liegen sie hoeher.
 */
.map-error {
    position: absolute; top: 52px; left: 50%; transform: translateX(-50%);
    background: var(--c-error-bg);
    color: var(--c-error);
    border: 1px solid var(--c-error);
    padding: 8px 14px;
    border-radius: var(--radius-sm);
    z-index: 1500;
    font-size: .9rem;
    max-width: 80%;
}
.map-toast {
    /* 40px nach unten (war bottom:80px). */
    position: absolute; bottom: 40px; left: 50%; transform: translateX(-50%);
    background: var(--map-info-bg);
    color: var(--fg);
    border: 1px solid var(--border-hi);
    padding: 8px 14px;
    border-radius: var(--radius);
    z-index: 1500;
    font-size: .9rem;
    box-shadow: var(--shadow-card);
}
.map-toast[hidden] { display: none; }

/* ---- Modal (generisch) ---- */
/* z-index 2000: ueber Leaflet-Controls (z 1000) und ueber unseren toasts.
 * backdrop-filter blur, damit Karte/UI hinter dem Modal weich
 * unscharf wird ("aus, aber sichtbar"). */
.modal {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.45);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    /* safe center statt center, damit ein Modal
 das groesser als der Viewport ist nicht oben aus dem sichtbaren
 Bereich heraus zentriert wird. Wenn der Inhalt zu hoch ist, faellt
 es auf flex-start zurueck und kann von oben nach unten gescrollt
 werden. Greift insbesondere im Tablet-Bereich (769-1024 px), wo
 die Mobile-Fullscreen-Regel (siehe @media (max-width:768px)) noch
 nicht greift. */
    display: flex; align-items: safe center; justify-content: center;
    z-index: 2000;
    padding: 24px;
}
.modal[hidden] { display: none; }
.modal-card {
    background: var(--bg-elevated);
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    max-width: 460px; width: 100%;
    padding: 22px 24px;
    position: relative;
    /* 100dvh statt 100vh. Auf Tablets/Mobile
 mit dynamischer Browser-URL-Leiste ist 100vh groesser als der
 tatsaechlich sichtbare Bereich, dann steht der obere Modal-Rand
 hinter der URL-Leiste. dvh trackt den realen Viewport. */
    max-height: calc(100dvh - 48px);
    display: flex;
    flex-direction: column;
}
.modal-card--wide  { max-width: 760px; }
.modal-card--wider { max-width: 980px; }
/* Vermessungs-Uebersicht: die Tabelle traegt je benutzter Abschlagfarbe
 * eine eigene Spalte, dazu Bahn, zwei Par-Felder, Gruenlaenge, Bemerkung
 * und Status. Bei den 980px von .modal-card--wider fehlten dafuer rund
 * 100px, und die Tabelle musste auch auf einem grossen Schirm waagerecht
 * gescrollt werden. Eigene Breite statt .modal-card--wider anzufassen -
 * das Mass haengt an DIESER Tabelle, nicht an allen breiten Fenstern.
 * Der min()-Deckel haelt das Fenster auf kleineren Schirmen im Bild; die
 * Mobile-Regel (Vollbild, !important) gewinnt weiterhin. */
#golf-survey-table-modal .modal-card {
    max-width: min(1120px, calc(100vw - 32px));
}

/* scrollbares Inneres fuer das External-Tileset-Form,
 * damit der Speichern-Button auch im WMS-Modus mit allen Feldern
 * (inkl. Spring-Punkt + Auth-Akkordeon) immer sichtbar bleibt. */
.xt-create-form {
    flex: 1 1 auto;
    overflow-y: auto;
    min-height: 0;
    /* Etwas Innenabstand damit Form nicht direkt an der Scroll-Edge klebt. */
    padding-right: 4px;
}

/* Fly-to-Pfeil-Knopf im Layer-Control (.geolyser-fly-to). */
/* Layer-Control-Labels als flex-Container,
 damit der Fly-to-Button per margin-left:auto an den rechten Rand der
 Layer-Box rutscht statt direkt am Layer-Namen zu kleben. Leaflet rendert
 ein <div> (Input + Span) als ersten Child und unser Button (via
 label.appendChild) als zweiten - die werden damit links/rechts
 verteilt. Das innere <div> behaelt sein eigenes Layout. */
.leaflet-control-layers-base label {
    display: flex;
    align-items: center;
    gap: 4px;
}
/* Overlay-Labels als 3-Spalten-Grid:
 ┌─────────┬───────────────────────┬──────────┐
 │ pan-to │ checkbox + name (Z1) │ sort │
 │ (2 row) │ opacity-slider (Z2) │ (2 row) │
 └─────────┴───────────────────────┴──────────┘
 Pan-to + Sort-Arrows ueberspannen beide Zeilen ueber grid-row.
 Der innere Leaflet-Container <div> (Checkbox + Name) ist Z1,
 die Opacity-Slider-Row ist Z2. */
/* vereinfachtes Layout - Label als position:relative,
 Sort-Arrows absolut am rechten Rand ueber beide Zeilen. Innerhalb
 des Labels normaler Flow (input + flyTo + span im inneren div, dann
 opacity-slider-row darunter), mit padding-right damit nichts unter
 die Sort-Arrows rutscht. */
.leaflet-control-layers-overlays label {
    display: block;
    position: relative;
    padding: 2px 36px 2px 4px;  /* rechts Platz fuer Sort-Arrows */
}
.leaflet-control-layers-overlays label > div {
    /* Leaflets eingefuegtes div mit input+span (+ flyTo via insertBefore). */
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
}
.leaflet-control-layers-overlays label > .geolyser-opacity-slider-row {
    margin-top: 2px;
    padding-left: 24px;
}
.leaflet-control-layers-overlays label > .geolyser-layer-sort-arrows {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    margin: 0;
}
/* Kunden-Gruppierung der Tilesets (nur Geolyser-Super-Container, per
 decorateLayerControlWithCustomerGroups injiziert). Kopfzeile = klickbarer
 Aufklapp-Header, Member-Labels bleiben direkte Kinder der Overlay-Liste. */
.geolyser-tileset-group-head {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px;
    margin-top: 4px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 600;
    color: var(--fg);
    border-top: 1px solid var(--border);
    user-select: none;
}
.geolyser-tileset-group-head:first-child {
    margin-top: 0;
    border-top: 0;
}
.geolyser-tileset-group-head:hover { color: var(--accent, #3BBDE8); }
.geolyser-tileset-group-caret {
    flex: 0 0 auto;
    font-size: 10px;
    line-height: 1;
    transition: transform 0.15s ease;
}
.geolyser-tileset-group-head.is-collapsed .geolyser-tileset-group-caret {
    transform: rotate(-90deg);
}
.geolyser-tileset-group-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.geolyser-tileset-group-count {
    flex: 0 0 auto;
    min-width: 18px;
    text-align: center;
    background: var(--border);
    color: var(--fg);
    border-radius: 8px;
    padding: 0 6px;
    font-size: 11px;
    font-weight: 600;
}
/* Eingeklappte Member-Labels ausblenden. Die Overlay-Label-Regel oben
 setzt display:block, was den UA-Default [hidden]{display:none}
 ueberstimmt — daher explizit erzwingen. */
.leaflet-control-layers-overlays label[hidden] { display: none !important; }
.geolyser-fly-to {
    border: none;
    background: transparent;
    cursor: pointer;
    /* Button sitzt zwischen Checkbox und Text -
 margin-left:auto braucht's nicht mehr, weil insertBefore den Btn
 direkt nach dem input-Element einfuegt. */
    margin-left: 4px;
    margin-right: 4px;
    padding: 2px 4px;
    color: var(--accent, #3BBDE8);
    vertical-align: middle;
    line-height: 1;
    border-radius: 4px;
    transition: background 0.12s ease, transform 0.12s ease;
}
.geolyser-fly-to:hover {
    background: rgba(59, 189, 232, 0.12);
    transform: translateY(-1px);
}
.geolyser-fly-to img,
.geolyser-fly-to svg {
    display: block;
    width: 18px;
    height: 18px;
}
/* Disabled-State fuer Tilesets ohne Spring-
 Punkt. Btn bleibt sichtbar (gleicher Slot wie aktive Btns), aber
 ausgegraut und ohne Hover-Lift. cursor:help signalisiert dass der
 Tooltip Information liefert (statt der "verboten"-Zeiger). */
.geolyser-fly-to.is-disabled,
.geolyser-fly-to:disabled {
    color: var(--muted, #8a979e);
    opacity: 0.45;
    cursor: help;
}
.geolyser-fly-to.is-disabled:hover,
.geolyser-fly-to:disabled:hover {
    background: transparent;
    transform: none;
}
.modal-header {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    margin: -22px -24px 12px -24px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border);
}
.modal-header .modal-title { margin: 0; }
.modal-header-tabs {
    display: flex; gap: 4px;
}
/* Waehrend die Reiterzeile mit der Maus gezogen wird (js/reiter-ziehen.js). */
.modal-header-tabs.ist-gezogen {
    cursor: grabbing;
    user-select: none;
}
.modal-header-tabs.ist-gezogen .modal-header-tab { cursor: grabbing; }
.modal-header-tab {
    border: 1px solid transparent;
    background: transparent;
    color: var(--muted-hi);
    padding: 6px 14px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font: inherit;
    transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.modal-header-tab:hover {
    background: var(--bg-card);
    color: var(--fg);
}
/* aktiver Tab klar erkennbar im Light- UND Dark-Mode. */
.modal-header-tab.is-active {
    background: var(--c-primary);
    color: var(--c-light);
    border-color: var(--c-primary-dk);
    font-weight: 500;
}
.modal-close-btn {
    border: 0;
    background: transparent;
    color: var(--muted-hi);
    cursor: pointer;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    line-height: 0;
}
.modal-close-btn:hover { background: var(--input-bg); color: var(--fg); }
/* Action-Button mit fuehrendem Icon (z.B. "Speichern", "Verwerfen",
   "Widerrufen" in den Confirm-Dialogs). SVG links, Label rechts. */
.btn-with-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
.btn-with-icon svg {
    flex-shrink: 0;
}
.btn-with-icon > span {
    line-height: 1;
}
.modal-body {
    overflow-y: auto;
    margin: 0 -8px;
    padding: 0 8px;
}
.modal-footer {
    display: flex; gap: 8px; justify-content: flex-end;
    border-top: 1px solid var(--border);
    margin: 16px -24px -22px -24px;
    padding: 12px 18px;
}
.modal-title { margin: 0 0 12px 0; }
.modal-text { margin: 0 0 16px 0; color: var(--muted-hi); }
.modal-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
/* Nur die TOP-LEVEL-Form (direktes Kind von .modal-card) bekommt
 flex:1 + overflow:auto. Geschachtelte Forms (Profil-Modal hat 2-3 Forms
 nebeneinander im Body) wuerden sich sonst gegenseitig auf height:0
 druecken (timezone-form, password-form Bug). */
.modal-card > .modal-form {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}
.field { display: flex; flex-direction: column; gap: 4px; }
/* .field hat display:flex — das
 ueberschreibt den UA-Default display:none fuer [hidden]. Explizit
 erzwingen damit der Avatar-Picker im Bug-Modal korrekt
 aus-/eingeblendet werden kann. */
.field[hidden] { display: none !important; }
.field-label { font-size: .8em; color: var(--muted); }
/* Gleiche Optik wie alle anderen Dropdowns im Modal, DESIGN.md 5.5.
   Die Felder im i2i-Export tragen .i2i-in und haengen hier mit dran. */
.field input, .field select, .field textarea, .i2i-in, .clsp-src {
    background: var(--input-bg);
    color: var(--fg);
    border: 1px solid var(--border);
    padding: 8px 10px;
    border-radius: var(--radius-sm);
}
.field input:focus, .field select:focus, .field textarea:focus,
.i2i-in:focus, .clsp-src:focus {
    outline: none; border-color: var(--border-hi);
    box-shadow: 0 0 0 3px rgba(0, 127, 180, 0.18);
}
.form-error { color: var(--c-error); margin: 0; font-size: .85em; }

/* Status-Linie im Bug-Report- und aehnlichen Modals.
 * data-kind = info | ok | error setzt die Farbe. */
.modal-status {
    margin: 6px 0 0;
    font-size: .88em;
    padding: 6px 10px;
    border-radius: var(--radius-sm, 6px);
    background: var(--bg-card);
    color: var(--fg);
}
.modal-status[data-kind="info"]  { color: var(--muted-hi); }
.modal-status[data-kind="ok"]    { color: var(--c-signal-dk, #00a04f); }
.modal-status[data-kind="error"] { color: var(--c-error); background: var(--c-error-bg); }
.modal-actions {
    display: flex; gap: 8px; justify-content: flex-end;
    margin-top: 8px;
}
.modal-actions--stack { flex-direction: column; }
.modal-actions--stack .primary, .modal-actions--stack .ghost {
    width: 100%; padding: 12px 14px;
    flex-direction: column; align-items: flex-start;
}
.modal-action-hint {
    font-size: .8em;
    color: var(--muted-hi);
    font-weight: 400;
    margin-top: 2px;
}

/* ---- Login / Dashboard / Trash / Index (gemeinsame Hilfsklassen) ---- */
.page--center {
    min-height: 100%;
    display: flex; align-items: center; justify-content: center;
    padding: 32px 16px;
}
.card {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    padding: 24px;
    max-width: 460px;
    width: 100%;
}
.dashboard, .trash {
    max-width: 1100px;
    margin: 24px auto;
    padding: 0 16px;
}
table.simple {
    width: 100%; border-collapse: collapse;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}
table.simple th, table.simple td {
    padding: 8px 10px; text-align: left;
    border-bottom: 1px solid var(--border);
}
table.simple tr:last-child td { border-bottom: 0; }
table.simple th { color: var(--muted); font-weight: 500; font-size: .85em; }

/* ---- Leaflet-Anpassungen ---- */
.leaflet-container { background: var(--map-surface); font-family: var(--font-ui); }
.leaflet-control-attribution {
    background: var(--map-info-bg) !important;
    color: var(--muted-hi) !important;
    border-radius: 6px 6px 0 0;
    font-size: 11px;
}
.leaflet-control-attribution a { color: var(--c-primary-hi) !important; }
/* Attribution wird per JS aus dem leaflet-bottom-right
 * Container raus geloest und direkt in #map gehaengt - dann positioniert
 * sie sich relativ zur ganzen Karte und kann unten mittig stehen. */
.leaflet-control-attribution.attribution-bottom-center {
    position: absolute;
    left: 50%;
    bottom: 0;
    transform: translateX(-50%);
    margin: 0 !important;
    z-index: 600;
    pointer-events: auto;
    padding: 2px 8px;
    border-radius: 6px 6px 0 0;
    max-width: calc(100% - 40px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Leaflet-Bar-Buttons (Zoom +/-, Locate) analog zu GPS-Tools:
 * solider dunkler Hintergrund, weisses Icon im Dark-Mode, beim Hover
 * Icon + Border in Tuerkis (c-primary-hi). Default (Light) bleibt ein
 * heller Card-Hintergrund. */
/* e: Buttons in Zoom-Control + Geoman-Toolbar 4px auseinander
 * ziehen, damit die Border (besonders der tuerkise Hover/Aktiv-Border)
 * sauber rund um jeden einzelnen Button sichtbar ist. Default-Leaflet
 * stackt sie sonst direkt aneinander mit Shared-Border. */
.leaflet-bar {
    background: transparent !important;
    box-shadow: none !important;
    border: 0 !important;
}
.leaflet-bar a {
    background: var(--bg-elevated);
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px) !important;
    margin-bottom: 4px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}
.leaflet-bar a:last-child {
    margin-bottom: 0;
}
.leaflet-bar a:hover {
    background: var(--bg-elevated);
    color: var(--c-primary-hi);
    border-bottom-color: var(--c-primary-hi);
    border-color: var(--c-primary-hi);
}
.leaflet-bar a.leaflet-disabled {
    background: var(--bg-elevated);
    color: var(--muted);
    opacity: 0.55;
}
[data-theme="dark"] .leaflet-bar a {
    background: #20262a;
    color: #ffffff;
    border-color: var(--border);
}
[data-theme="dark"] .leaflet-bar a:hover {
    background: #2b3338;
    color: var(--c-primary-hi);
    border-color: var(--c-primary-hi);
    border-bottom-color: var(--c-primary-hi);
}
.leaflet-control-scale-line {
    background: var(--map-control-bg-lo) !important;
    color: var(--fg) !important;
    border-color: var(--border) !important;
    /* Leaflet-Default packt einen weissen Text-Shadow drum,
 * der im Dark-Mode wie ein Glow wirkt. Plain Text ohne Schatten. */
    text-shadow: none !important;
}
[data-theme="dark"] .leaflet-control-scale-line {
    color: #ffffff !important;
}
/* i: Scale-Line muss ueber den Legal-Links (.map-legal-links)
 * sitzen, sonst ueberdeckt sie unten rechts den Datenschutz/Impressum-
 * Hinweis. Etwa 26px Reserve = Hoehe der Legal-Pill + 4px Luft. */
.leaflet-control-scale {
    margin-bottom: 28px !important;
}
