/* HansePolle Verwaltung — Umsetzung des Designsystems (docs/design.md).
   Fonts werden selbst gehostet (DSGVO), Variable Fonts: eine Datei je Familie. */

@font-face {
    font-family: 'Cormorant Garamond';
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url('fonts/cormorant-garamond-latin.woff2') format('woff2');
}
@font-face {
    font-family: 'Mulish';
    font-style: normal;
    font-weight: 300 800;
    font-display: swap;
    src: url('fonts/mulish-latin.woff2') format('woff2');
}

:root {
    /* Marken-Salbei */
    --sage-100: #eef2e2;
    --sage-300: #d3ddb8;
    --sage-500: #b4c484;
    --sage-600: #a1b46f;
    /* Dunkler als das Website-Salbei (#6f8244): trägt hier 11-px-Labels,
       Tabellenköpfe und Textlinks und braucht dafür WCAG AA auch auf
       Tint-Flächen (sage-100/mist), nicht nur auf Weiß. */
    --sage-700: #5d6d39;

    /* Warme Neutrale */
    --white: #ffffff;
    --mist: #f4f4f2;
    --border: #e3e3df;
    --ink: #23261d;
    --body: #2b2e26;
    /* Dunkler als der Marken-Grauton der Website (#8a8d80): Meta-Texte sind hier
       echte Inhalte (Mitgliedsnummern, Hinweise) und brauchen WCAG AA (≥4.5:1). */
    --muted: #6a6d62;

    /* Akzente — sparsam */
    --hanse-blue: #2f4858;
    --kiez-rose: #d9738f;
    --rose-tint: #f6e3e9;
    --rose-ink: #a94e69;

    --ring: 0 0 0 3px rgba(180, 196, 132, 0.28);
}

* { box-sizing: border-box; }

/* Versteckte <symbol>-Bibliothek fürs Link-Icon-Set (ADR-0024) — kein Inline-`style`,
   die CSP dieses Projekts erlaubt `style-src 'self'` ohne `unsafe-inline`. */
.icon-defs { position: absolute; }

::selection { background: var(--sage-500); color: var(--ink); }

body {
    margin: 0;
    font-family: 'Mulish', system-ui, sans-serif;
    font-size: 15px;
    background: var(--mist);
    color: var(--body);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* ===== Kopfzeile ===== */
.topbar {
    background: var(--white);
    border-bottom: 1px solid var(--border);
    padding: 14px 20px;
    display: flex;
    align-items: center;
    gap: 20px;
}
.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    text-decoration: none;
    color: var(--ink);
    border-bottom: none;
    padding-bottom: 0;
}
/* Bildmarke des Vereinslogos (Anker + Blatt) statt der früheren Anker-SVG.
   Bleibt im Original-Schwarz der Marke — sie ist ein Bild, keine per
   `currentColor` einfärbbare Ikone. Feste Breite/Höhe im Markup verhindert
   Layout-Sprünge beim Laden. */
.brand-mark { width: 30px; height: 30px; flex: none; object-fit: contain; }
.brand strong {
    font-family: 'Cormorant Garamond', serif;
    font-size: 22px;
    font-weight: 600;
    letter-spacing: 0.02em;
}
.brand span {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: var(--muted);
    margin-left: 2px;
}

/* ===== Konto-Menü (ADR-0024) =====
   Kreisförmiges Kürzel oben rechts, CSS-only Dropdown (<details>/<summary>, kein JS) —
   bekanntes, gelebtes Muster (Gmail, GitHub, claude.ai). Ersetzt den vorherigen
   "Mein Konto"-Block am Sidebar-Fuß; erscheint unabhängig vom Anheft-/Aufklapp-Zustand
   der Sidebar, weil es im Header lebt, nicht in ihr. */
.account-menu { position: relative; margin-left: auto; }
.account-menu summary {
    list-style: none;
    cursor: pointer;
    width: 36px;
    height: 36px;
    border-radius: 999px;
    background: var(--sage-500);
    color: var(--ink);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
    border: 1px solid var(--sage-600);
}
.account-menu summary::-webkit-details-marker { display: none; }
.account-menu summary::marker { content: ''; }
.account-menu summary:focus-visible { outline: 2px solid var(--sage-500); outline-offset: 2px; }
.account-menu[open] summary { outline: 2px solid var(--sage-500); outline-offset: 2px; }
.account-dropdown {
    position: absolute;
    right: 0;
    top: 44px;
    z-index: 20;
    min-width: 208px;
    background: var(--white);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 8px;
    box-shadow: 0 10px 28px rgba(35, 38, 29, 0.16);
}
.account-dropdown-name {
    margin: 0 0 4px;
    padding: 8px 10px 10px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    font-weight: 700;
    color: var(--ink);
}
.account-dropdown ul { display: flex; flex-direction: column; gap: 2px; list-style: none; margin: 0; padding: 0; }
.account-dropdown a, .account-dropdown .linklike {
    display: flex;
    align-items: center;
    min-height: 40px;
    padding: 9px 10px;
    width: 100%;
    text-align: left;
    border-radius: 12px;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: normal;
    text-transform: none;
    color: var(--body);
    text-decoration: none;
    border-bottom: none;
}
.account-dropdown a:hover, .account-dropdown .linklike:hover { background: var(--mist); color: var(--body); }

/* ===== Navigation (ADR-0024, löst ADR-0020s "immer sichtbar ab 1024px" ab) =====
   Ein Baum für alle Berechtigungen, kein Mitglieder-/Verwaltungs-Split. Grundzustand ist
   ein Aufklapp-Overlay (CSS-only Checkbox-Hack, kein JS im Projekt) — auf JEDEM
   Breakpoint, auch am Schreibtisch: die Sidebar ist nicht mehr dauerhaft sichtbar,
   sondern nur auf Wunsch. Die Stecknadel oben in der Sidebar heftet sie an (dockt sie
   ab 1024px als feste Spalte an, siehe Media Query unten) — bekanntes Muster
   (VS Code/Notion: Auto-Hide-Sidebar mit Pin). */
.nav-toggle-input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    overflow: hidden;
}
.nav-toggle-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 0 6px;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--sage-700);
    cursor: pointer;
    user-select: none;
}
.nav-toggle-icon {
    position: relative;
    display: block;
    width: 20px;
    height: 2px;
    background: currentColor;
    flex: none;
}
.nav-toggle-icon::before,
.nav-toggle-icon::after {
    content: '';
    position: absolute;
    left: 0;
    width: 20px;
    height: 2px;
    background: currentColor;
}
.nav-toggle-icon::before { top: -6px; }
.nav-toggle-icon::after { top: 6px; }
.nav-toggle-input:focus-visible ~ .topbar .nav-toggle-btn {
    outline: 2px solid var(--sage-500);
    outline-offset: 2px;
}

.nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(35, 38, 29, 0.35);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
    z-index: 25;
}
.nav-toggle-input:checked ~ .nav-scrim { opacity: 1; pointer-events: auto; }

.sidenav {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(300px, 86vw);
    background: var(--white);
    border-right: 1px solid var(--border);
    box-shadow: 0 8px 24px rgba(35, 38, 29, 0.14);
    padding: 18px 12px 24px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    z-index: 30;
}
.nav-toggle-input:checked ~ .sidenav { transform: translateX(0); }
/* Gruppen sind benannt (Aufhebung von ADR-0021s "vorerst flach", 2026-07-22
   Überarbeitung). Trennung zwischen den Gruppen bleibt bewusst reiner Weißraum,
   keine Linien — Christians ursprüngliche Vorgabe aus ADR-0021 gilt für die Optik
   weiter. Die einzige echte Trennlinie im Baum ist die vor "Mein Konto" unten. */
.sidenav-group + .sidenav-group { margin-top: 20px; }
.sidenav-group ul { display: flex; flex-direction: column; gap: 4px; list-style: none; margin: 0; padding: 0; }
.sidenav-group-title {
    margin: 0 0 4px;
    padding: 0 12px;
    font-family: 'Mulish', system-ui, sans-serif;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--muted);
}
.sidenav a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    border-radius: 12px;
    font-size: 14px;
    font-weight: 600;
    color: var(--body);
    text-decoration: none;
    border-bottom: none;
    min-height: 44px;
}
.sidenav a:hover { background: var(--mist); }
.sidenav a.active { background: var(--sage-100); color: var(--sage-700); }
.nav-icon { width: 17px; height: 17px; flex: none; color: var(--sage-700); }
/* Zahlicon ungelesener Neuigkeiten (BL-0053) — rechtsbündig im Flex-Link, kompakter als der Standard-Badge. */
.nav-badge { margin-left: auto; font-size: 11px; padding: 2px 9px; }

/* Anheften (ADR-0024): dockt die Sidebar ab 1024px an (Media Query unten), sonst
   bleibt sie auf jeder Breite ein Aufklapp-Overlay. Anker-Icon statt 📌-Emoji —
   passt zum maritimen Vokabular und ist über alle Systeme/Browser gleich gerendert.
   Zustand kommt direkt vom Server als body.sidenav-pinned (kein Checkbox-Hack mehr,
   Nachbesserung 2026-07-23) — die vorherige :has()-Ableitung aus einer Checkbox
   rendere nach dem POST/Redirect-Roundtrip beim Klick zeitweise falsch (Sidebar volle
   Breite statt angedockt), erst ein manueller Reload zeigte den korrekten Zustand. */
.sidenav-pin-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 40px;
    padding: 8px 12px;
    margin: 0 0 16px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: none;
    appearance: none;
    cursor: pointer;
    user-select: none;
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--muted);
}
.sidenav-pin-btn:hover { background: var(--mist); }
.sidenav-pin-btn svg { width: 15px; height: 15px; flex: none; }
.sidenav-pin-label-on { display: none; }
.sidenav-pin-btn:focus-visible {
    outline: 2px solid var(--sage-500);
    outline-offset: 2px;
}
body.sidenav-pinned .sidenav-pin-btn {
    background: var(--sage-100);
    border-color: var(--sage-300);
    color: var(--sage-700);
}
body.sidenav-pinned .sidenav-pin-label-off { display: none; }
body.sidenav-pinned .sidenav-pin-label-on { display: inline; }
/* Anheften wirkt erst ab 1024px (Media Query oben drüber wird unten ergänzt) — unter
   1024px ist die Sidebar immer ein Overlay, kein Platz für eine dauerhaft angedockte
   Spalte. Der Button bliebe sonst sichtbar, aber wirkungslos. */
@media (max-width: 1023.98px) {
    .sidenav-pin-btn { display: none; }
}

@media (min-width: 1024px) {
    .topbar { padding: 18px 32px; }
    /* Grid nur bei angehefteter Sidebar — sonst bliebe die 248px-Nav-Spalte als
       leere Lücke stehen und würde Hauptinhalt/Footer aus der Bildschirmmitte
       schieben (Bug 2026-07-22, Christian). Ohne Anheften bleibt die Sidebar auch
       ab 1024px ein Aufklapp-Overlay wie mobil — Grundzustand ist eingeklappt. */
    body.sidenav-pinned {
        display: grid;
        grid-template-columns: 248px 1fr;
        grid-template-rows: auto 1fr auto;
        grid-template-areas: "header header" "nav main" "nav footer";
    }
    body.sidenav-pinned .topbar { grid-area: header; }
    body.sidenav-pinned .container { grid-area: main; }
    body.sidenav-pinned .footer { grid-area: footer; }
    body.sidenav-pinned .nav-toggle-btn,
    body.sidenav-pinned .nav-scrim { display: none; }
    body.sidenav-pinned .sidenav {
        grid-area: nav;
        position: static;
        top: auto; bottom: auto; left: auto;
        width: auto;
        transform: none;
        box-shadow: none;
        padding: 24px 12px;
    }
}
@media (prefers-reduced-motion: reduce) {
    .sidenav, .nav-scrim { transition: none; }
}

form.filter-form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
    margin: 0;
}

.filter-actions button {
    margin: 0;
    white-space: nowrap;
}

.inline { display: inline; margin: 0; }
/* Datum-/Monats-Auswahl + Vor/Zurück (Termin-/Kalenderseiten): eigene Klasse
   statt .toolbar, weil `form .toolbar` bewusst margin-bottom:0 setzt (für
   abschließende Formular-Aktionen gedacht) — hier folgt aber meist eine
   Tabelle/Kartenliste, die echten Abstand braucht (Christian-Feedback
   2026-07-27: Abstand zu gering, Vor/Zurück-Links "nicht optimal"). Label +
   Datums-/Monatsfeld bleiben normale Blockelemente (unverändert), nur die
   Aktionszeile (Anzeigen + Vor/Zurück) wird zur umbrechenden Flex-Reihe;
   Vor/Zurück selbst sind `.btn-secondary` statt `.linklike` (gleiches Muster
   wie die Paginierung in templates/audit/log.php) — echte Tap-Targets statt
   schmaler Text-Links. */
.picker-nav { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 0 0 24px; }
/* Vor/Zurück sollen sich von "Anzeigen" abheben, aber ruhiger wirken als ein
   Submit-Button — Farbfläche statt Kontur (Christian-Feedback 2026-07-29:
   "kein Border"), gleiche sage-100/700-Kombination wie Badges/Chips. */
.picker-nav a.btn-secondary {
    background: var(--sage-100);
    border: none;
    color: var(--sage-700);
    padding: 13px 22px;
}
.picker-nav a.btn-secondary:hover { background: var(--sage-300); }
.linklike {
    background: none;
    border: 0;
    padding: 6px 0;
    margin: 0;
    cursor: pointer;
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--muted);
}
.linklike:hover { color: var(--sage-700); background: none; }
/* Tag-/Monats-Navigation: zwei linklike-Anker direkt nebeneinander brauchen Luft. */
a.linklike { border-bottom: none; }
a.linklike + a.linklike { margin-left: 18px; }
/* Abstand zwischen zwei Zeilen-Aktionen unterschiedlicher Tragweite (z. B.
   "Ausgabe erfassen" neben "Stornieren…"), damit .tap-targets negativer
   Rand keine Nachbar-Aktion überlappt. */
.row-actions { display: inline-flex; align-items: center; gap: 10px; }

/* ===== Inhalt ===== */
.container {
    width: 100%;
    max-width: 1120px;
    margin: 0 auto;
    padding: 40px 32px 64px;
    flex: 1;
}

h1 {
    font-family: 'Cormorant Garamond', serif;
    font-weight: 500;
    font-size: 38px;
    line-height: 1.1;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 0 0 28px;
}
h1::after {
    content: '';
    display: block;
    width: 44px;
    height: 2px;
    background: var(--sage-500);
    margin-top: 14px;
}
h2 {
    font-family: 'Cormorant Garamond', serif;
    font-weight: 600;
    font-size: 25px;
    color: var(--sage-700);
    margin: 40px 0 12px;
}
h3 {
    font-family: 'Cormorant Garamond', serif;
    font-weight: 600;
    font-size: 19px;
    color: var(--ink);
    margin: 28px 0 8px;
}
p { margin: 16px 0; }
hr { border: none; border-top: 1px solid var(--border); margin: 32px 0; }

.public-body ul,
.public-body ol {
    margin: 16px 0;
    padding-left: 24px;
}
.public-body li { margin: 4px 0; }
.public-body li > ul,
.public-body li > ol { margin: 4px 0; }

/* Textlinks laut Designsystem: sage-700 mit 2px-sage-300-Unterstrich.
   Komponenten-Links (Nav, Buttons, Karten, Kalenderzellen) opten unten aus. */
a { color: var(--sage-700); text-decoration: none; border-bottom: 2px solid var(--sage-300); padding-bottom: 1px; }
a:hover { border-bottom-color: var(--sage-600); }

/* Aktionsleiste unter der Überschrift */
.toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin: 0 0 28px;
    max-width: none;
}
.toolbar button { margin-top: 0; }
.toolbar label { margin: 0; }
.toolbar h1 { margin-bottom: 0; }
/* Ein <form> als Toolbar-Flex-Item ist selbst kein Flex-Container: ein block-
   Label darin bricht sonst auf eine eigene Zeile und macht das Formular höher
   als benachbarte Buttons/Links, wodurch align-items:center diese verschiebt. */
.toolbar form.inline { display: inline-flex; align-items: center; gap: 12px; }
/* Divider-Höhenbeitrag aus der Flex-Zentrierung nehmen, ohne ihn zu verschieben:
   H1 wird sonst durch margin-top+height des ::after ~16px höher als die Buttons. */
.toolbar h1::after { margin-bottom: -16px; }

/* ===== Buttons ===== */
button,
.btn,
.btn-secondary,
.btn-dark {
    display: inline-block;
    font-family: 'Mulish', system-ui, sans-serif;
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink);
    background: var(--sage-500);
    border: none;
    border-radius: 999px;
    padding: 13px 30px;
    cursor: pointer;
    text-decoration: none;
    line-height: 1.35;
}
button:hover, .btn:hover { background: var(--sage-600); }
button:focus-visible, .btn:focus-visible, a:focus-visible { outline: none; box-shadow: var(--ring); }
form > button { display: block; margin-top: 20px; }
form .toolbar { margin: 20px 0 0; }

button.btn-secondary,
.btn-secondary {
    background: transparent;
    border: 1.5px solid var(--sage-500);
    color: var(--sage-700);
    padding: 11.5px 28px;
}
button.btn-secondary:hover, .btn-secondary:hover { background: var(--sage-100); border-color: var(--sage-500); }

button.btn-dark, .btn-dark { background: var(--hanse-blue); color: var(--sage-100); }
button.btn-dark:hover, .btn-dark:hover { background: #24384a; }

/* ===== Badges ===== */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--sage-100);
    border: 1px solid var(--sage-300);
    color: #4a5238;
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 0.05em;
    padding: 4px 12px;
    border-radius: 999px;
    white-space: nowrap;
}
.badge-solid { background: var(--sage-500); border-color: var(--sage-500); color: var(--ink); }
.badge-dark { background: var(--hanse-blue); border-color: var(--hanse-blue); color: #dbe6ec; }
.badge-muted { background: var(--white); border-color: var(--border); color: var(--muted); }
.badge-rose { background: var(--rose-tint); border-color: var(--rose-tint); color: var(--rose-ink); }
.badge-icon { flex-shrink: 0; }

/* ===== Tabellen ===== */
table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: var(--white);
    border: 1px solid var(--border);
    border-radius: 16px;
    overflow: hidden;
    margin: 0 0 24px;
}
th, td {
    text-align: left;
    padding: 12px 12px;
    border-bottom: 1px solid var(--border);
    vertical-align: center;
}
th {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--sage-700);
    background: #f8f9f4;
    border-bottom-color: var(--sage-300);
}
tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: #fbfcf8; }
.muted { color: var(--muted); }

.help-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin-left: 10px;
    border: 1px solid var(--border);
    border-radius: 50%;
    font-family: 'Mulish', sans-serif;
    font-size: 13px;
    font-weight: 700;
    color: var(--sage-700);
    vertical-align: middle;
    text-decoration: none;
}
.help-link:hover { background: var(--sage-500); border-color: var(--sage-500); color: #fff; }

.help-content h1:first-child { margin-top: 0; }
.help-content table { margin: 16px 0 24px; }
.help-content pre {
    background: #f8f9f4;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 14px 16px;
    overflow-x: auto;
}
.help-content code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
}
.help-content pre code { font-size: inherit; }

/* ===== Formulare ===== */
label {
    display: block;
    margin: 0;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--sage-700);
}
input, select, textarea {
    width: 100%;
    max-width: 26rem;
    font-family: inherit;
    font-size: 15px;
    color: var(--body);
    background: var(--white);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 16px;
    outline: none;
}
/* Höhe an Buttons (≈43,55px) angleichen; textarea bleibt bei 12px, da mehrzeilig. */
input:not([type="checkbox"]):not([type="radio"]), select {
    padding: 11px 16px;
    line-height: 1.35;
}
/* Feste statt prozentualer Breite: verhindert zirkuläre Größenberechnung, wenn das
   umschließende <form> selbst shrink-to-fit sized ist (z. B. in .toolbar/.inline). */
input[type="month"] { width: auto; max-width: none; }
input:focus, select:focus, textarea:focus {
    border-color: var(--sage-500);
    box-shadow: var(--ring);
}
.input-error {
    border-color: var(--rose-ink);
    background: var(--rose-tint);
}
input[type="checkbox"],
input[type="radio"] {
    width: 18px;
    height: 18px;
    accent-color: var(--sage-600);
    vertical-align: -4px;
    margin-right: 6px;
    padding: 0;
    box-shadow: none;
}
::placeholder { color: var(--muted); opacity: 1; }
/* Größere Tap-Fläche für Checkbox/Radio im Tresen-/Termin-Kontext (S18) —
   Padding + negativer Margin vergrößert nur die Klickfläche, nicht die
   sichtbare Box; bewusst als eigene Klasse statt globaler Regel, um das
   restliche, dichtere Formular-Layout (Desktop-Verwaltung) nicht zu ändern. */
.tap-target { display: inline-flex; align-items: center; gap: 6px; padding: 13px; margin: -13px; cursor: pointer; }
/* Slot-Auswahl (.table-cards.slot-picker, Termin buchen/umbuchen): eine
   Radio-Auswahl aus vielen kurzen Zeitfenstern braucht eine Zeile pro Slot
   mit Radio + Uhrzeit + Frei-Angabe nebeneinander — bei jeder Bildschirm-
   breite, nicht nur mobil. `display: contents` auf den `<td>`s lässt die
   `<tr>` selbst zur Flex-Reihe werden (semantisches Tabellen-Markup bleibt
   für Screenreader erhalten); jede Zelle bekommt einen <label for="…">-
   Wrapper auf dieselbe Radio-`id`, damit ein Klick überall in der Zeile
   den Slot auswählt, nicht nur auf Text oder Options-Box.

   Erst-Fassung nutzte `height: 100%` auf dem Label, um die ganze `<td>`
   auszufüllen — das ist bei echten `<table>`-Zellen aber unzuverlässig:
   Prozent-Höhen in einer Table-Cell lösen browserabhängig gegen die
   Zellhöhe *vor* dem zeilenweiten Höhenausgleich auf, nicht gegen die
   tatsächliche, final gleich hohe Zeile — Messung per Headless-Chrome ergab
   dadurch einen ca. 6–9px hohen toten Rand oben/unten in jeder Zeile, nicht
   klickbar. `display: contents` + Flexbox mit `align-items: stretch`
   umgeht das vollständig: Flex-Items ohne eigene Höhe füllen per Spezifikation
   exakt die Kreuzachse des Containers, keine Prozent-Auflösung nötig.
   Dieselbe Mechanik gilt deshalb jetzt einheitlich für Desktop und Mobile
   (statt zwei verschiedener, getrennt gepflegter Lösungen).

   Nachbesserung (Christian-Feedback: zu eng, letzte Zeile wirkt unten
   abgeschnitten): die generische mobile Karten-Regel `.table-cards tr`
   (eigener Regelblock unten im 720px-Media-Query, `border`/`border-radius:
   16px`/`background:white`/`margin:0 0 10px`, gedacht für gestapelte Werte-
   Karten wie „Deine Termine") wurde von dieser dichteren Zeile nie explizit
   abgekoppelt — nur die hier gesetzten Properties (`display`, `padding`,
   `margin`) gewannen per Spezifität, Border/Radius/Background der
   Kartenregel blieben unbemerkt aktiv. Mit `margin: 0` lagen die Zeilen so
   flächenbündig aneinander, dass sich ihre eigenen abgerundeten Ecken an
   jeder Nahtstelle gegenseitig einkerbten (kleine, unregelmäßige Lücken
   statt einer sauberen Trennlinie) und die letzte Zeile ohne eigenen
   Bottom-Border wirkte, als würde ihre Rundung ins Leere laufen — genau der
   gemeldete „abgeschnitten"-Eindruck. Fix: Border/Radius/Background hier
   explizit neutralisiert, echte Abstände (`margin-bottom`) statt einer
   Trennlinie zwischen den Optionen (dichtes Muster bleibt „eigene Zeile pro
   Slot", bekommt aber sichtbaren Raum dazwischen statt kollidierender
   Rundungen), `border-radius: 10px` neu gesetzt, damit der Ausgebucht-
   Hintergrund (`--mist`, s. u.) als klar abgegrenzte, abgerundete Fläche
   erscheint statt als hartkantiges Rechteck. */
/* `tr` als Flex-Reihe traf (unbeabsichtigt) auch die `<thead>`-Zeile — deren
   `<th>`s bekommen (anders als die `<td>`s) kein `display: contents`, blieben
   also eigene Flex-Items ohne die `flex: 1`/`flex: none`-Regeln der Body-
   Spalten. Ergebnis auf Desktop (`<thead>` ist erst ab 720px per Media-Query
   ausgeblendet): die Kopfzeile hing links zusammengedrängt, "Uhrzeit" stand
   nicht über den Uhrzeiten, rechts blieb toter Raum — die gemeldete falsche
   Darstellung. Fix: `grid` statt `flex`, mit fest benannten Spaltenbreiten
   (`grid-template-columns`), dieselbe Regel gilt für Kopf- und Body-Zeilen,
   dadurch liegen `<th>` und die Body-Spalten zwangsläufig auf denselben
   Spalten — kein `flex: 1`/`flex: none` mehr pro Zelle nötig, das übernimmt
   jetzt die Spaltendefinition. 48px für Spalte 1 = exakt die Breite der
   Radio-Spalte (16px padding-left + 18px Radio + 6px margin-right + 8px
   padding-right, s. u.). */
.table-cards.slot-picker tr {
    display: grid;
    grid-template-columns: 48px 1fr auto;
    align-items: stretch;
    padding: 0;
    margin: 0 0 6px;
    border: none;
    /* 12px = die Radius-Stufe für Bedienelemente (`docs/design.md` §Formulare);
       vormals 10px, eine Stufe außerhalb der dokumentierten Skala
       (22/20/16/12). Sichtbar wird der Radius nur an der Mist-Tönung
       ausgebuchter Slots, s. `:has(input:disabled)` unten. */
    border-radius: 12px;
    background: none;
}
.table-cards.slot-picker tr:last-child { margin-bottom: 0; }
.table-cards.slot-picker tr:has(input:disabled) { background: var(--mist); }
.table-cards.slot-picker td { display: contents; }
.table-cards.slot-picker label.tap-target {
    text-transform: none;
    letter-spacing: normal;
    font: inherit;
    color: inherit;
    display: flex;
    align-items: center;
    margin: 0;
    padding: 14px 8px;
}
.table-cards.slot-picker td:first-child label.tap-target { padding-left: 16px; }
.table-cards.slot-picker td:last-child label.tap-target { padding-right: 16px; }
.table-cards.slot-picker td[data-th="Uhrzeit"] label.tap-target {
    font-size: 15px;
    font-weight: 700;
    color: var(--ink);
}
.table-cards.slot-picker td[data-th="Frei"] label.tap-target { font-size: 12px; color: var(--muted); }
.table-cards.slot-picker td[data-th="Frei"] .badge { font-size: 11px; padding: 3px 10px; }
/* Kopfzeile optisch an die Slot-Zeilen angeglichen (kein wuchtiger, groß
   gepolsterter Tabellenkopf wie bei den übrigen Tabellen) — die generische
   `th`-Regel (Großbuchstaben, `#f8f9f4`-Hintergrund, 12px Padding) bleibt
   dafür bewusst ungenutzt. */
.table-cards.slot-picker thead th {
    background: none;
    padding: 8px;
    border-bottom-color: var(--border);
}
.table-cards.slot-picker thead th:first-child { padding-left: 16px; }
.table-cards.slot-picker thead th:last-child { padding-right: 16px; }
/* Auswahl-Labels (Checkbox UND Radio) tragen eine Option, keine Feld-
   beschriftung — sie sollen lesbar bleiben statt in der 11px-Versal-Optik
   der generischen `label`-Regel zu stehen. Radios waren bis 2026-08-08 nicht
   erfasst: im Sortenformular standen die Darreichungsform-Radios in
   GROSSBUCHSTABEN direkt über den Wirkungs-Checkboxen in Fließtext
   (Christian-Feedback). Der Slot-Picker setzt seine Labels weiter selbst
   (`.table-cards.slot-picker label.tap-target`, höhere Spezifität). */
label:has(input[type="checkbox"]),
label:has(input[type="radio"]) {
    text-transform: none;
    letter-spacing: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--body);
}
fieldset {
    border: 1px solid var(--border);
    border-radius: 16px;
    background: var(--white);
    margin: 24px 0 0;
    padding: 18px 22px 22px;
    /* max-width: 26rem; */
}
legend {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--sage-700);
    padding: 0 8px;
}
fieldset label { margin: 8px 0; }
/* Berechtigungs-Checklisten (Rolle bearbeiten): lange, satzartige Labels
   ("Eigene Termine buchen und verwalten") wirken in der generischen
   26rem-Fieldset-Breite abgeschnitten/eng, während das Namensfeld darüber
   (`.panel input{max-width:100%}`) die volle Panel-Breite nutzt — Christian-
   Feedback 2026-07-27. Eigene Klasse statt der generischen Regel, da die
   26rem-Breite für kurze Listen (Rollen-/Geschmacksprofil-Checkboxen)
   bewusst bleibt. */
.fieldset-wide { max-width: 100%; }
/* Auswahlgruppe innerhalb eines Formularabschnitts (Radio-/Checkbox-Gruppe in
   einem `.form-sections`-Fieldset): behält `fieldset`/`legend`, damit
   Screenreader die Gruppe samt Beschriftung ankündigen, verliert aber Rahmen,
   Hintergrund und Polsterung — sonst entstünde ein Kasten im Kasten. Die
   Legende bleibt in der Versal-Optik der übrigen Legenden, ohne den seitlichen
   Einzug, der nur zum Unterbrechen einer Rahmenlinie da ist. */
.fieldset-plain {
    border: none;
    background: none;
    padding: 0;
    margin: 18px 0 0;
    max-width: none;
}
.fieldset-plain > legend { padding: 0; }
/* Formularabschnitte (Sorten-, Mitgliederformular): untereinander über die
   volle Panelbreite, eine Spalte. Grid statt der früheren `flex-wrap`-Variante
   (Christian 2026-08-08, zuerst fürs Sortenformular, dann fürs Mitglieder-
   formular) — nebeneinander gestellt wurden die Abschnitte auf gleiche Höhe
   gestreckt, auf die generischen 26rem gedeckelt, und Erklärungstexte liefen in
   einer schmalen Spalte um. Es gibt bewusst nur noch diese eine Variante: eine
   ungenutzte mehrspaltige Klasse danebenstehen zu lassen wäre tote Regel. */
.form-sections { display: grid; grid-template-columns: 1fr; gap: 20px; }
/* Direkte Kinder: die Abschnitts-Fieldsets sind die Rasterzellen, eine darin
   verschachtelte `.fieldset-plain`-Gruppe behält ihre eigenen Abstände. */
.form-sections > fieldset { max-width: none; margin-top: 0; }
/* Die volle Breite gilt den Abschnitten, den Erklärungstexten und den
   Auswahlreihen — nicht den Eingabefeldern: ein 800 px breites Namensfeld
   sähe aus, als erwarte es einen Absatz. Sie behalten deshalb das generische
   26rem-Maß, das `.panel input{max-width:100%}` sonst aufhebt. `textarea`
   bleibt bewusst voll breit (mehrzeilige Freitexte). */
.form-sections fieldset input:not([type="checkbox"]):not([type="radio"]),
.form-sections fieldset select { max-width: 26rem; }
/* Einzelne Häkchen direkt im Abschnitt bekommen eine eigene Zeile. `.tap-target`
   ist `inline-flex`; solange die Abschnitte 26rem schmal waren, brach das von
   selbst um — über die volle Panelbreite rutschten sie neben das Feld darüber
   ("SEPA-Mandat liegt vor" neben der Mandatsreferenz) und lasen sich, als
   gehörten sie dazu. Nur direkte Kinder: die Optionsreihen in einer
   `.fieldset-plain`-Gruppe (Wirkung, Geschmacksprofil) sollen weiter
   nebeneinander fließen, dort ist das Nebeneinander die Aussage. */
.form-sections > fieldset > label.tap-target { display: flex; }
table input, table select { max-width: 100%; }
table input[type="text"], .input-short { max-width: 9rem; }

/* Schmale, zentrierte Formularkarte (Anmeldung) */
.panel {
    background: var(--white);
    border: 1px solid var(--border);
    border-radius: 22px;
    padding: 40px 44px 44px;
    max-width: 720px;
    margin-bottom: 16px;
}
.panel-wide { max-width: none; }
.panel-center { margin: 48px auto 0; }
.panel-center h1 { text-align: center; color: var(--sage-700); }
.panel-center h1::after { margin-left: auto; margin-right: auto; background: var(--sage-300); }
.panel input, .panel select, .panel textarea { max-width: 100%; margin: 6px 0 12px 0;}
.panel button { width: 100%; padding: 15px 30px; }
/* .panel-wide (Zeilen-Formulare, z. B. Termin-Verfügbarkeit/Abrechnungslauf):
   volle Breite passt für Tabellen, aber ein "SPEICHERN"-Button oder ein
   Kurzfeld (Uhrzeit/Zahl) sollen dabei nicht auf Zeilenbreite mitwachsen. */
.panel-wide input.input-short { max-width: 9rem; }
.panel-wide button { width: auto; }

/* Verwaltungs-Dashboard: aktionsorientierte Zeilen statt Stat-Kacheln
   (`PRODUCT.md` Anti-Referenz "generisches SaaS-Dashboard") — flache Zeilen
   auf --mist mit Haarlinien-Trennung, Zahl im Linktext. */
.dashboard-admin-list { list-style: none; margin: 0; padding: 0; }
.dashboard-admin-list li { border-top: 1px solid var(--border); }
.dashboard-admin-list li:first-child { border-top: none; }
.dashboard-admin-list a {
    display: block;
    padding: 14px 4px;
    background: var(--mist);
    color: var(--body);
    border-bottom: none;
}
.dashboard-admin-list a:hover { color: var(--sage-700); }

/* ===== Hinweise ===== */
.flash {
    border-radius: 12px;
    padding: 13px 18px;
    margin-bottom: 20px;
    font-weight: 600;
    max-width: none;
}
.flash-success { background: var(--sage-100); border: 1px solid var(--sage-300); color: #4a5238; }
.flash-error { background: var(--rose-tint); border: 1px solid #eccdd7; color: var(--rose-ink); }
/* Neutraler Hinweis (z. B. protokollierte Grenz-Hinweise nach bestätigter
   Ausgabe): informiert, ohne wie ein Fehler auszusehen — maritimer Ton. */
.flash-info { background: #e7edf1; border: 1px solid #cfdae2; color: var(--hanse-blue); }
.flash p { margin: 8px 0; }
.flash p:first-child { margin-top: 0; }
.flash p:last-child { margin-bottom: 0; }

/* ===== JS-Bestätigungsdialog (ADR-0029, BL-0046) — progressive Enhancement
   für destruktive Aktionen; No-JS-Fallback ist das bestehende serverseitige
   Zwei-Schritt-Muster (Flash-Banner + zweiter Klick), unverändert. */
dialog#js-confirm-dialog {
    border: none;
    border-radius: 12px;
    padding: 24px;
    max-width: 420px;
    width: calc(100% - 48px);
    box-shadow: 0 10px 28px rgba(35, 38, 29, 0.16);
}
dialog#js-confirm-dialog::backdrop { background: rgba(35, 38, 29, 0.45); }
dialog#js-confirm-dialog:focus { outline: none; }
dialog#js-confirm-dialog:focus-visible { outline: none; box-shadow: var(--ring), 0 10px 28px rgba(35, 38, 29, 0.16); }
dialog#js-confirm-dialog .flash { margin: 0 0 20px; }
.js-confirm-dialog-actions { display: flex; gap: 12px; justify-content: flex-end; }
.js-confirm-dialog-actions button { display: inline-block; margin-top: 0; }
.flash ul { margin: 8px 0; padding-left: 22px; }

/* ===== Age-Verification & Cookie-Einwilligung (öffentliche Website, D9/K4) ===== */
.age-gate {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(35, 38, 29, 0.72);
}
.age-gate-box {
    background: var(--white);
    border-radius: 22px;
    padding: 36px 32px;
    max-width: 26rem;
    text-align: center;
    box-shadow: 0 10px 28px rgba(35, 38, 29, 0.16);
}
.age-gate-box h2 { margin: 0 0 12px; color: var(--sage-700); }
.age-gate-box p { margin: 0 0 22px; }
.age-gate-box form { margin: 0; }
.age-gate-box .btn { width: 100%; }
.age-gate-leave { display: inline-block; margin-top: 14px; color: var(--muted); font-size: 13px; }

.cookie-consent {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 100;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 18px 32px;
    background: var(--white);
    border-top: 1px solid var(--border);
    box-shadow: 0 -8px 24px rgba(35, 38, 29, 0.14);
}
.cookie-consent p { margin: 0; max-width: 42rem; }
.cookie-consent-actions { display: flex; gap: 12px; margin: 0; flex-wrap: wrap; }
.cookie-consent-actions button { display: inline-block; margin-top: 0; }

@media (max-width: 720px) {
    .cookie-consent { padding: 16px 20px; }
    .cookie-consent-actions { width: 100%; }
    .cookie-consent-actions button { flex: 1 1 auto; }
}

/* ===== Fußzeile ===== */
.footer {
    background: var(--white);
    border-top: 1px solid var(--border);
    text-align: center;
    padding: 28px 32px;
}
.footer p {
    font-family: 'Cormorant Garamond', serif;
    font-size: 18px;
    font-weight: 600;
    color: var(--ink);
    margin: 0 auto;
}
.footer span { display: block; font-family: 'Mulish', sans-serif; font-size: 12px; font-weight: 400; color: var(--muted); }

/* ===== Kleine Bildschirme ===== */
@media (max-width: 720px) {
    .topbar { padding: 14px 20px; gap: 16px; }
    .container { padding: 28px 20px 48px; }
    h1 { font-size: 31px; }
    table { display: block; overflow-x: auto; border-radius: 12px; }
    .panel { padding: 28px 24px 32px; }
    .month-grid-day-inner { min-height: 60px; padding: 4px; }
    /* Bei 7 fixen Spalten bleibt auf schmalen Screens kaum Platz — Label
       UND die freie Ausnahmetag-Begründung werden wie .visually-hidden
       entfernt (Screenreader lesen beides weiterhin), nur Icon + Zahl
       bleiben sichtbar. Zusätzlich schrumpft das Badge selbst (Chrome/
       Icon/Abstand), sonst reicht bei zweistelligen Zahlen ("12 frei")
       selbst ohne Label die Zellbreite (~46px bei 375px Viewport) nicht.*/
    .month-grid .badge-label,
    .month-grid .month-grid-reason {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }
    .month-grid-day .badge { padding: 2px 4px; gap: 2px; }
    .month-grid-day .badge-icon { width: 10px; height: 10px; }
    /* Native Date-Picker (iOS/Android) unterschreiten die 9rem-Deckelung von
       .input-short/table input — min-width erzwingt genug Raum, ohne die
       9rem-Grenze für andere Inputtypen (z. B. table input[type="text"]) zu
       ändern. */
    input[type="date"] { min-width: 10rem; }
}

/* ===== Terminübersicht (Monatsgrid, Scheduling) ===== */
.month-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 1px;
    background: var(--border);
    border: 1px solid var(--border);
    border-radius: 16px;
    overflow: hidden;
    margin: 0 0 24px;
}
.month-grid-head {
    background: #f8f9f4;
    padding: 10px 8px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--sage-700);
    text-align: center;
}
.month-grid-day {
    background: var(--white);
}
.month-grid-day.is-empty { background: #fbfcf8; }
.month-grid-day.is-today { background: var(--sage-100); }
/* Die ganze Zelle ist klickbar: .month-grid-day-inner trägt Layout/Padding und
   ist je nach Buchbarkeit ein <a> (Ui-seitig verlinkt) oder ein <div> (nicht
   anklickbar, z. B. außerhalb des Buchungsfensters im Portal). */
.month-grid-day-inner {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    min-height: 92px;
    padding: 8px 10px;
    height: 100%;
    box-sizing: border-box;
}
a.month-grid-day-inner { text-decoration: none; border-bottom: none; color: inherit; cursor: pointer; }
a.month-grid-day-inner:hover { background: var(--sage-100); }
.month-grid-day .day-number { font-weight: 700; color: var(--hanse-blue); }
.month-grid-day .day-number.muted { color: var(--muted); font-weight: 400; }
.month-grid-day .badge { font-size: 11px; padding: 3px 10px; }
.month-grid-day .today-marker { display: inline-block; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--sage-600); }
.month-grid-day .month-grid-reason { display: block; font-size: 11px; line-height: 1.3; }
.month-grid-head abbr { text-decoration: none; }

/* ===== Strain Guide (Mitglieder-Portal) ===== */
.strain-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 24px;
    margin-top: 28px;
}
.strain-card {
    background: var(--white);
    border: 1px solid var(--border);
    border-radius: 20px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: border-color 0.15s ease;
}
.strain-card:hover { border-color: var(--sage-500); }
/* Live-Suche (ADR-0029, BL-0047) blendet nicht treffende Karten per
   [hidden] aus — die eigene `display: flex` oben hat sonst als Autoren-CSS
   Vorrang vor dem User-Agent-Stylesheet-`[hidden] { display: none }`. */
.strain-card[hidden] { display: none; }
.strain-card-link {
    display: flex;
    flex-direction: column;
    flex: 1;
    text-decoration: none;
    border-bottom: none;
    color: var(--body);
}
.strain-card-footer { padding: 0 18px 18px; }
.strain-card-footer .btn-secondary { display: block; text-align: center; }
.strain-card .strain-photo {
    position: relative;
    aspect-ratio: 4 / 3;
    background: var(--sage-100);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 42px;
    overflow: hidden;
}
.strain-card .strain-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.strain-photo-badge { position: absolute; top: -12px; right: 16px; }
.strain-photo-badge .badge { box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25); }
.strain-card .strain-body { padding: 16px 18px 18px; }
.strain-card .strain-title {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
}
.strain-card .strain-title h3 {
    font-family: 'Cormorant Garamond', serif;
    font-size: 22px;
    font-weight: 600;
    color: var(--ink);
    margin: 0;
}
.strain-card .strain-thc { font-weight: 800; color: var(--sage-700); white-space: nowrap; }
.strain-card .strain-meta { color: var(--muted); font-size: 13px; margin: 4px 0 10px; }
.chip {
    display: inline-block;
    background: var(--sage-100);
    border-radius: 999px;
    padding: 3px 12px;
    font-size: 12px;
    font-weight: 600;
    color: var(--sage-700);
    margin: 0 6px 6px 0;
}
/* Sativa/Indica-Anteil (AP-SG.1, ADR-0031 Punkt 4) — vormals .effect-*,
   gleiche Farbwerte, aber Bedeutung entkoppelt von der Wirkung: eine Sorte
   kann mehrere Wirkungen tragen, aber nur einen Sativa/Indica-Anteil. */
.si-sativa { background: var(--sage-100); }
.si-balanced { background: #f7ecd9; }
.si-indica { background: #e7edf1; }
.guide-legend { color: var(--muted); font-size: 13px; margin-top: 10px; width: 100%;}
.guide-legend .chip { margin-right: 10px; }
.strain-detail { display: grid; grid-template-columns: minmax(260px, 420px) 1fr; gap: 36px; align-items: start; }
.strain-detail .strain-photo { border-radius: 20px; overflow: hidden; background: var(--sage-100); }
.strain-detail .strain-photo img { width: 100%; display: block; }
@media (max-width: 720px) { .strain-detail { grid-template-columns: 1fr; } }

/* ===== Portal-Dashboard: Navigations-Kacheln (kein Sorten-Bezug, bewusst
   eigene Klassen statt .strain-card/.strain-grid — siehe DESIGN.md §6). ===== */
.nav-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 20px;
    margin-top: 20px;
}
.nav-tile {
    display: block;
    background: var(--white);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 18px 20px;
    text-decoration: none;
    color: var(--body);
    transition: border-color 0.15s ease;
}
.nav-tile:hover { border-color: var(--sage-500); }
.nav-tile h2 { margin: 0 0 4px; }
.nav-tile p { color: var(--muted); font-size: 13px; margin: 0; }
.nav-tile p + p { margin-top: 4px; }

/* ===== Live-Suchfeld (ADR-0029) — wird nur bei aktivem JS von app.js in den
   DOM eingefügt; ohne JS existiert kein Suchfeld, dafür bleibt die jeweilige
   Liste wie gewohnt vollständig sicht-/durchsuchbar. Genutzt vom Sortenguide
   (BL-0047) und von der Packungs-Auswahl am Tresen (BL-0062). ===== */
.live-search { margin: 0 0 20px; }

/* ===== Guide-Filter (dezente Leiste statt großer Formularkarte) ===== */
.guide-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 20px;
    margin: 20px 0 28px;
    padding: 14px 20px;
    background: var(--sage-100);
    border-radius: 16px;
    border: 1px solid var(--border);
}
.filter-group { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.filter-group-label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--sage-700);
    margin-right: 2px;
}
.filter-chip-input {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    opacity: 0;
}
.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 6px 14px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--white);
    color: var(--sage-700);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.filter-chip:hover { border-color: var(--sage-500); }
.filter-chip-input:checked + .filter-chip { background: var(--sage-500); border-color: var(--sage-500); color: var(--ink); }
.filter-chip-input:focus-visible + .filter-chip { box-shadow: var(--ring); }
.filter-actions { display: flex; align-items: center; gap: 12px; margin-left: auto; }

/* ===== Aufklappbare Zeilen (<details>): Monatslauf-Prüfphase, Termin-Verfügbarkeit ===== */
.statement-row, .collapsible-row {
    border: 1px solid var(--border);
    border-radius: 16px;
    margin: 0 0 12px;
    background: var(--white);
}
.statement-row summary, .collapsible-row summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 20px;
    cursor: pointer;
    list-style: none;
    font-weight: 600;
    color: var(--sage-700);
    border-radius: 16px;
}
.statement-row summary::-webkit-details-marker, .collapsible-row summary::-webkit-details-marker { display: none; }
.statement-row summary::before, .collapsible-row summary::before {
    content: '▸';
    color: var(--sage-500);
    margin-right: 8px;
    transition: transform 0.15s ease;
}
.statement-row[open] summary::before, .collapsible-row[open] summary::before { transform: rotate(90deg); }
.statement-row summary:hover, .collapsible-row summary:hover { background: var(--sage-100); }
.statement-row summary:focus-visible, .collapsible-row summary:focus-visible { outline: none; box-shadow: var(--ring); }
.statement-row[open] summary, .collapsible-row[open] summary { border-radius: 16px 16px 0 0; }
.statement-row .panel, .collapsible-row .panel { border-top: 1px solid var(--border); border-radius: 0 0 16px 16px; margin: 0; }
.collapsible-row summary .muted { font-weight: 400; }

/* Packungs-Auswahl am Tresen (BL-0062): je Sorte eine aufklappbare Zeile,
   darin die verfügbaren Packungen als Kästchen. Bewusst ein Raster statt
   einer Liste — Etikett-Codes sind kurz und gleich lang, nebeneinander
   passen auf einen Blick deutlich mehr aufs Bild. */
.package-picker { margin-bottom: 20px; }
.package-picker-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 4px 16px;
    padding: 20px;
}
.package-picker-list .tap-target { margin: 0; padding: 10px 13px; }
.json-inline {
    display: block;
    max-width: 400px;
    white-space: break-spaces;
    overflow-wrap: anywhere;
    word-break: break-word;
}
/* System-Log (ADR-0057): Kontextfelder als kompakte Schlüssel/Wert-Liste;
   lange Werte (Pfade, Fehlermeldungen) brechen um statt die Tabelle zu sprengen. */
.log-context { display: grid; grid-template-columns: max-content 1fr; gap: 2px 10px; margin: 0; font-size: 13px; }
.log-context dt { color: var(--muted); }
.log-context dd { margin: 0; overflow-wrap: anywhere; }
.system-log code { overflow-wrap: anywhere; }

/* ===== Sortenfotos ===== */
.photo-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    aspect-ratio: 4 / 3;
    padding: 48px;
    font-size: 42px;
    text-align: center;
}
.photo-preview { max-width: 240px; border-radius: 12px; display: block; }
/* Sortenbilder (ADR-0053): Verwaltungsraster und Galerie auf der Detailseite. */
.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; margin-bottom: 16px; }
.photo-tile { margin: 0; }
.photo-tile .photo-preview { width: 100%; max-width: 100%; aspect-ratio: 3 / 4; object-fit: cover; }
.photo-tile figcaption { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 6px; }
/* Galerie: Scroll-Snap-Spur mit einer Slide je Bild (Wischen ohne JS), die
   Miniaturen sind Anker auf die Slides. Einheitliches 3:4-Feld, `contain`
   statt `cover`, damit kein Bild beschnitten wird. Vor/Zurück-Buttons
   erzeugt app.js (initStrainGallery). */
.strain-gallery-wrap { position: relative; }
.strain-gallery-track { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth; scrollbar-width: none; }
.strain-gallery-track::-webkit-scrollbar { display: none; }
.strain-gallery-track:focus-visible { outline: 2px solid var(--sage-500); outline-offset: -2px; }
.strain-gallery-slide { flex: 0 0 100%; scroll-snap-align: center; aspect-ratio: 3 / 4; }
.strain-detail .strain-photo .strain-gallery-slide img { width: 100%; height: 100%; object-fit: contain; }
.strain-gallery-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: rgba(255, 255, 255, 0.88);
    color: var(--ink);
    font-size: 22px;
    line-height: 1;
    padding: 0;
    cursor: pointer;
}
.strain-gallery-nav:hover { background: var(--white); }
.strain-gallery-nav:focus-visible { outline: 2px solid var(--sage-500); outline-offset: 2px; }
.strain-gallery-nav[aria-disabled="true"] { opacity: 0.35; cursor: default; }
.strain-gallery-prev { left: 10px; }
.strain-gallery-next { right: 10px; }
.strain-gallery { display: flex; gap: 8px; overflow-x: auto; padding: 8px; background: var(--sage-100); }
.strain-gallery a { flex: none; border-radius: 10px; border: 2px solid transparent; }
.strain-gallery a[aria-current="true"] { border-color: var(--sage-700); }
.strain-gallery a:focus-visible { outline: 2px solid var(--sage-500); outline-offset: 2px; }
.strain-detail .strain-photo .strain-gallery img { width: 96px; height: 128px; object-fit: cover; border-radius: 8px; display: block; }
@media (prefers-reduced-motion: reduce) {
    .strain-gallery-track { scroll-behavior: auto; }
}

/* Tresen-Mitgliedskarte: Foto prominent, Bearbeitung zurückhaltend
   (`<details>`, wie `.collapsible-row`) — der Tresen-Moment ist Anzeige,
   nicht Pflege. */
.photo-preview-lg { max-width: 100%; width: 100%; }
@media (min-width: 480px) { .photo-preview-lg { width: 320px; } }

/* Kleines Vorschaubild in der Mitgliederliste — nur ein Anhaltspunkt, keine
   Identifikationsgrundlage aus der Distanz. */
.photo-icon { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; display: block; }

/* ===== Tresen ===== */
/* Die Entscheidungszahl des Tresen-Moments („wie viel darf das Mitglied
   noch?") — bewusst prominent, keine Stat-Kachel: eine Textzeile. */
.allowance-highlight { font-size: 15px; margin: 0 0 8px; }
.allowance-highlight strong { font-size: 48px; font-weight: 800; color: var(--sage-700); }

/* Fällig-Zahl, Pendant zu .allowance-highlight: eine Textzeile, keine
   Stat-Kachel — hanse-blue statt sage-700 bindet sie an die Geld-Zone. */
.due-highlight { font-size: 15px; margin: 0 0 8px; }
.due-highlight strong { font-size: 25px; font-weight: 800; color: var(--hanse-blue); }

/* Kassenblock zweispaltig ab Tablet-Querformat/Desktop: Herleitung links,
   Formular rechts. Bewusst eigener Breakpoint (nicht 720px, das ist die
   .table-cards-Kartenumbruch-Schwelle; nicht 1024px, das ist das
   Sidenav-Anheften) — darunter strukturell identisch zur einspaltigen
   Ausgangslage. */
.cash-block-grid { display: grid; grid-template-columns: 1fr; gap: 24px; }
@media (min-width: 960px) {
    .cash-block-grid { grid-template-columns: 1.2fr 1fr; gap: 40px; align-items: start; }
}

/* Foto + Rest-Kontingent auf der Tresen-Mitgliedskarte: mobil Foto zuerst
   (per grid-template-areas, nicht Quellreihenfolge — das Kontingent bleibt
   danach für Screenreader/No-JS an derselben logischen Stelle), ab Tablet
   nebeneinander mit dem Foto rechts. Gleicher Breakpoint wie
   .cash-block-grid. */
.photo-allowance-grid {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-areas: "photo" "allowance";
    gap: 16px;
}
@media (min-width: 960px) {
    .photo-allowance-grid { grid-template-columns: 1fr 1fr; grid-template-areas: "allowance photo"; gap: 40px; align-items: start; }
}
.photo-allowance-grid > .photo-panel { 
    grid-area: photo; 
    display: flex;
    flex-direction: column;
    align-items: center; /* Zentriert Inhalte horizontal */
    text-align: center;
}
.photo-allowance-grid > .allowance-panel { grid-area: allowance; }

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* Tabellen, die am Tresen auch auf Tablet/Telefon funktionieren müssen:
   unter 720 px werden Zeilen zu Karten mit Label je Wert (data-th) statt
   horizontal zu scrollen — die Kernspalte („Rest") und die Aktions-Buttons
   bleiben dadurch immer sichtbar. */
@media (max-width: 720px) {
    .table-cards { display: block; background: none; border: none; overflow: visible; }
    .table-cards thead { display: none; }
    .table-cards tbody { display: block; }
    /* Karten-Neugestaltung (Christian-Feedback 2026-07-29: die vorherige
       Kachel-Version war "eine Katastrophe" — jede Zeile bekam dieselbe
       Text-Wucht, keine Kern-Aussage stach heraus). Die Zeile wird zur
       vertikalen Flex-Karte: die erste Spalte (immer die inhaltliche
       Kernaussage — Termin/Zeitpunkt/Monat/Mitglied, siehe die Templates,
       die .table-cards nutzen) wird als Karten-Überschrift hervorgehoben,
       alles Weitere bleibt Metadatenzeile in gewohnter Label:Wert-Optik.
       Eine echt leere Zelle (z. B. eine leere "Anmerkung") verschwindet
       ganz, statt als nackte Beschriftung ohne Wert stehen zu bleiben. */
    .table-cards tr {
        display: flex;
        flex-direction: column;
        gap: 6px;
        background: var(--white);
        border: 1px solid var(--border);
        border-radius: 16px;
        margin: 0 0 10px;
        padding: 14px 16px;
    }
    .table-cards td {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
        align-items: baseline;
        gap: 4px 12px;
        border-bottom: none;
        padding: 0;
        min-width: 0;
    }
    .table-cards td:empty { display: none; }
    .table-cards tr td:first-child {
        font-size: 15px;
        font-weight: 700;
        color: var(--ink);
    }
    .table-cards tr td:first-child[data-th]::before { color: var(--muted); font-weight: 700; }
    .table-cards td[data-th]::before {
        content: attr(data-th);
        font-size: 11px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.14em;
        color: var(--sage-700);
        flex: none;
    }
    /* Aktionszelle ohne data-th (Buttons/Links am Kartenende): sichtbar von
       den Daten darüber abgesetzt statt nahtlos in der Flex-Spalte zu hängen. */
    .table-cards td:not([data-th]):not(:empty) {
        margin-top: 4px;
        padding-top: 10px;
        border-top: 1px solid var(--mist);
    }
    .table-cards tbody tr:hover td { background: none; }
    /* Sortenguide: die Übersichtstabelle ist auf Mobile redundant zum
       darunterliegenden Foto-Grid (.strain-grid) — dort reicht das Grid
       allein, die Tabelle bleibt Desktop-only. */
    .guide-table { display: none; }

    /* Slot-Auswahl (.table-cards.slot-picker): Layout/Flex-Mechanik ist seit
       der Headless-Chrome-Messung (s. Kommentar oben bei der Basis-Regel)
       breakpoint-unabhängig — hier bleibt nur noch die mobile Unterdrückung
       der generischen Karten-Beschriftung übrig, die die `.table-cards`-
       Regel oben sonst per `content: attr(data-th)` vor jede Zelle setzen
       würde (bei einer Zeile pro Slot störend, nicht wie bei den
       gestapelten Karten gewünscht). */
    .table-cards.slot-picker td[data-th]::before { content: none; }
}

/* ===== Kopfzeile (öffentlich, `ADR-0027`) =====
   Mobile-first: Grundzustand ist ein CSS-only Off-Canvas-Drawer (Checkbox-
   Hack `#public-nav-toggle`, gleicher Mechanismus wie die interne Sidenav,
   ADR-0020, aber eigener Klassensatz — keine Gruppen, kein Anheften). Anders
   als die interne Sidenav (seit ADR-0024 auf jedem Breakpoint eingeklappt)
   wird die Public-Nav ab 640px wieder eine dauerhaft sichtbare horizontale
   Leiste (Marketing-Nav-Muster, öffentliche Seite soll nicht wie eine App
   wirken). Der CTA-Button ("Mitglied werden") lebt bewusst außerhalb des
   Drawers und bleibt auf jeder Breite sichtbar (Konversionsziel). */
body.public .topbar { padding: 12px 16px; row-gap: 10px; flex-wrap: wrap; }
body.public .brand { order: 1; }
body.public .brand strong { font-size: 18px; }
/* CTA erzwingt einen eigenen zweiten Zeilenumbruch (flex-basis 100%) statt mit
   Marke/Toggle um die erste Zeile zu konkurrieren. Kein weißerne Textumbruch-
   Verbot: bei sehr schmalen Displays darf der Text auf zwei Zeilen umbrechen
   (übliches Muster für volle-Breite-CTAs), statt horizontal zu überlaufen. */
.public-cta {
    order: 3;
    flex: 1 0 100%;
    margin-left: 0;
    padding: 10px 16px;
    text-align: center;
}

.public-nav-toggle-input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    overflow: hidden;
}
.public-nav-toggle-btn {
    order: 2;
    margin-left: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    flex-shrink: 0;
    color: var(--sage-700);
    cursor: pointer;
    user-select: none;
}
.public-nav-toggle-icon { position: relative; display: block; width: 20px; height: 2px; background: currentColor; flex: none; }
.public-nav-toggle-icon::before,
.public-nav-toggle-icon::after {
    content: '';
    position: absolute;
    left: 0;
    width: 20px;
    height: 2px;
    background: currentColor;
}
.public-nav-toggle-icon::before { top: -6px; }
.public-nav-toggle-icon::after { top: 6px; }
.public-nav-toggle-input:focus-visible ~ .public-nav-toggle-btn {
    outline: 2px solid var(--sage-500);
    outline-offset: 2px;
}

.public-nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(35, 38, 29, 0.35);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
    z-index: 25;
}
/* `:has()` statt Geschwister-Selektor (`~`): Checkbox liegt im `<header>`,
   `.public-nav`/`.public-nav-scrim` müssen aber strukturell an ihrem Platz
   bleiben (Drawer fest positioniert bzw. ab 640px echter Flex-Item der
   Topbar) — ein reiner Geschwister-Selektor könnte diese Struktur nicht
   erreichen. Anders als beim verworfenen `:has()`-Versuch der internen
   Sidenav (ADR-0024) hier kein Server-Roundtrip/Session-Zustand beteiligt,
   rein clientseitiges Umschalten innerhalb desselben Seitenaufrufs. */
body:has(.public-nav-toggle-input:checked) .public-nav-scrim { opacity: 1; pointer-events: auto; }

.public-nav {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(280px, 86vw);
    background: var(--white);
    border-left: 1px solid var(--border);
    box-shadow: -8px 0 24px rgba(35, 38, 29, 0.14);
    padding: 72px 12px 24px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
    transform: translateX(100%);
    transition: transform 0.2s ease;
    z-index: 30;
}
body:has(.public-nav-toggle-input:checked) .public-nav { transform: translateX(0); }
.public-nav a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 9px 14px;
    border-radius: 12px;
    font-family: 'Mulish', system-ui, sans-serif;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--body);
    border-bottom: none;
}
.public-nav a:hover { background: var(--mist); color: var(--sage-700); }
.public-nav a[aria-current="page"] { background: var(--sage-100); color: var(--sage-700); }

@media (min-width: 640px) {
    body.public .topbar { padding: 20px 32px; flex-wrap: nowrap; }
    .public-nav-toggle-btn, .public-nav-scrim { display: none; }
    .public-nav {
        order: 2;
        position: static;
        top: auto; right: auto; bottom: auto;
        width: auto;
        background: none;
        border-left: none;
        box-shadow: none;
        padding: 0;
        overflow: visible;
        flex-direction: row;
        align-items: center;
        gap: 28px;
        transform: none;
        transition: none;
        z-index: auto;
        margin-left: auto;
    }
    .public-cta { order: 3; flex: 0 0 auto; margin-left: 0; padding: 13px 30px; text-align: left; }
    .public-nav a {
        min-height: auto;
        padding: 0;
        border-radius: 0;
        font-size: 13px;
        letter-spacing: 0.14em;
        color: var(--muted);
    }
    .public-nav a:hover { background: none; color: var(--sage-700); }
    .public-nav a[aria-current="page"] { background: none; color: var(--sage-700); }
}
@media (prefers-reduced-motion: reduce) {
    .public-nav, .public-nav-scrim { transition: none; }
}

/* `.public-shell` bündelt Header/Nav/Main/Footer als eigenen Flex-Container
   (übernimmt die Rolle, die zuvor `body` direkt für diese Elemente spielte),
   damit er bei aktivem Age-Gate/Cookie-Banner komplett per `inert` vom
   Tastatur-/Screenreader-Zugriff ausgeschlossen werden kann, ohne die
   Sticky-Footer-Flex-Kette (`body` → … → `.public-main { flex: 1 }`) zu
   brechen. */
.public-shell { display: flex; flex-direction: column; flex: 1; min-width: 0; }

/* ===== Hauptbereich: kein Container-Zwang auf <main>, jede Seite
   entscheidet selbst, wo sie volle Breite (Hero) oder die 760px-Lesebreite
   (.public-container) braucht. ===== */
.public-main { width: 100%; flex: 1; }
.public-container { width: 100%; max-width: 760px; margin: 0 auto; padding: 40px 32px 64px; }
.public-page h1 { margin-top: 0; }
.public-hero { width: 100%; max-height: 360px; object-fit: cover; border-radius: 16px; margin-bottom: 24px; }
.public-body :first-child { margin-top: 0; }
.public-body { max-width: 72ch; }

/* Vollflächiger Startseiten-Hero (ADR-0023-Folgearbeit): Foto mit dunklem
   Verlauf, Titel als heller Cormorant-Schriftzug darüber. Nur für die
   Startseite (page.php prüft $page->slug), weil das feste Templates ohne
   freien Seitenbau bleiben — keine neuen CMS-Felder, nur ein zweiter,
   slug-gebundener Darstellungspfad für dieselben zwei Felder (Titel, Hero). */
.hero-masthead { position: relative; width: 100%; }
.hero-masthead-img { width: 100%; height: 460px; object-fit: cover; display: block; }
.hero-masthead-copy {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px;
    text-align: center;
    /* color-mix statt fixer rgba-Werte: Verlauf bleibt an --ink gekoppelt und
       garantiert AA-Kontrast für den weißen Titel unabhängig vom Redaktionsfoto. */
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--ink) 40%, transparent) 0%,
        color-mix(in srgb, var(--ink) 72%, transparent) 100%);
}
.hero-masthead-copy h1 {
    color: var(--white);
    font-size: clamp(34px, 5vw, 64px);
    max-width: 18ch;
    margin: 0;
    text-wrap: balance;
    text-shadow: 0 2px 20px color-mix(in srgb, var(--ink) 55%, transparent);
    animation: hero-rise 700ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.hero-masthead-copy h1::after { margin-left: auto; margin-right: auto; background: var(--sage-500); }
@keyframes hero-rise {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
    .hero-masthead-copy h1 { animation: none; }
}
@media (max-width: 720px) {
    .hero-masthead-img { height: 320px; }
    .hero-masthead-copy h1::after { display: none; }
}

/* Zentrierter Formular-Lead (Mitgliedsantrag): eigene Klasse statt
   .panel-center-weiter Vereinnahmung, damit die linksbündigen Hinweistexte
   in Passwort-/Einladungs-Panels (Portal) unverändert bleiben. */
.panel-center .lead { text-align: center; color: var(--muted); max-width: 48ch; margin: 0 auto 24px; }

/* Öffentliche Fußzeile: Marken-Moment statt schmaler Verwaltungsleiste. */
.public .footer { background: var(--mist); padding: 56px 32px 48px; }
.public .footer .footer-links {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 22px;
    margin: 14px auto 0;
    font-family: 'Mulish', system-ui, sans-serif;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--sage-700);
}
.footer-links a { color: inherit; border-bottom: none; }
.footer-links a:hover { color: var(--sage-600); }

/* Hero-Vorschau im CMS-Editor (Verwaltung): ersetzt eine Inline-Style-
   Ausnahme, damit auch Editor-Templates ohne style="" auskommen. */
.hero-thumb { max-width: 240px; border-radius: 12px; margin: 8px 0 0; display: block; }

/* Honeypot: für Menschen unsichtbar, aber im DOM/Accessibility-Tree
   normal vorhanden (kein aria-hidden auf dem Feld selbst, um Screenreader
   nicht durch widersprüchliche required+hidden-Zustände zu verwirren) —
   nur visuell aus dem Viewport geschoben. */
.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }