/* sAIrmo App-/Admin-Theme — extrahiert aus templates/layout.php (P4.5, 2026-07-08).
   Quelle der Wahrheit fuer produktives CSS ist ab jetzt DIESE Datei.
   Cache-Bruch via ?v=filemtime beim Einbinden in layout.php. */

        /* === Self-hosted Fonts (DSGVO — kein Google-Fonts-Remote-Request mehr;
           LG-München-Risiko). woff2, latin-Subset, aus @fontsource kopiert nach
           public/app-static/fonts/. Pfade relativ zur app.css → /app-static/fonts/.
           ⚠️ Deploy-Bundle MUSS public/app-static/fonts/ enthalten.
           Familien: Fraunces (App-Display), Instrument Serif (App-Accent),
           Inter (Body app+admin). Admin-Display nutzt jetzt ebenfalls Fraunces —
           Spectral liegt nicht in node_modules und ist damit nicht self-hostbar. */
        /* Archivo 900 — ausschliesslich fuer die Wortmarke „sAIrmo.", nirgends sonst.
           Seit dem Markenneustart (20.08.2026) ist sie eine eigene Schrift, weder
           Fraunces noch Inter. Dieselbe Datei liegt in der Homepage; wer sie hier
           entfernt, bekommt die Wortmarke in Fraunces zurueck — also das alte Logo. */
        @font-face {
            font-family: 'Archivo'; font-style: normal; font-display: swap; font-weight: 900;
            src: url(fonts/archivo-latin-900-normal.woff2) format('woff2');
        }
        @font-face {
            font-family: 'Fraunces'; font-style: normal; font-display: swap; font-weight: 400;
            src: url(fonts/fraunces-latin-400-normal.woff2) format('woff2');
        }
        @font-face {
            font-family: 'Fraunces'; font-style: normal; font-display: swap; font-weight: 500;
            src: url(fonts/fraunces-latin-500-normal.woff2) format('woff2');
        }
        @font-face {
            font-family: 'Fraunces'; font-style: normal; font-display: swap; font-weight: 600;
            src: url(fonts/fraunces-latin-600-normal.woff2) format('woff2');
        }
        @font-face {
            font-family: 'Inter'; font-style: normal; font-display: swap; font-weight: 400;
            src: url(fonts/inter-latin-400-normal.woff2) format('woff2');
        }
        @font-face {
            font-family: 'Inter'; font-style: normal; font-display: swap; font-weight: 500;
            src: url(fonts/inter-latin-500-normal.woff2) format('woff2');
        }
        @font-face {
            font-family: 'Inter'; font-style: normal; font-display: swap; font-weight: 600;
            src: url(fonts/inter-latin-600-normal.woff2) format('woff2');
        }
        @font-face {
            font-family: 'Instrument Serif'; font-style: normal; font-display: swap; font-weight: 400;
            src: url(fonts/instrument-serif-latin-400-normal.woff2) format('woff2');
        }
        @font-face {
            font-family: 'Instrument Serif'; font-style: italic; font-display: swap; font-weight: 400;
            src: url(fonts/instrument-serif-latin-400-italic.woff2) format('woff2');
        }

        /* --- Admin-Theme (Operator-Konsole) ---
           Traegt seit 21.08.2026 das sAIrmo-CI. Vorher standen hier bewusst
           mAIandros-Werte (#174557 / #266F87 / #F4F2EF / #E6E2DB), weil die
           Konsole zur Beratungsmarke gehoerte und nicht zum Produkt. Mit dem
           Markenneustart hat Florian das aufgehoben: mAIandros ruht, und zwei
           CI in einer Anwendung kosten mehr, als die Trennung einbrachte.

           Die Farben kommen jetzt wie in der Kunden-App aus brand-tokens.css.
           Dieser Block fuehrt nur noch Schriften und die Uebergangs-Aliase.
           Rueckweg: die vier Werte oben hier wieder setzen — sie ueberschreiben
           dann erneut die Token, und die alten Namen ziehen ueber die Aliase mit. */
        body.theme-admin {
            /* Alt-Namen als Alias — greifen die Token aus brand-tokens.css ab. */
            --tiefenblau: var(--petrol);
            --sandstein:  var(--petrolhell);
            --pergament:  var(--stein);
            --rule:       var(--sand);
            /* War 'Spectral' — jetzt self-hosted 'Fraunces' (Marken-Serif), da
               Spectral nicht in node_modules liegt und nach dem Google-Fonts-Aus
               (DSGVO) sonst auf Georgia zurückfiele. */
            --display-font: 'Fraunces', Georgia, serif;
            --accent-font:  'Instrument Serif', Georgia, serif;
            --header-bg:    var(--petrol);
            --footer-claim: 'sAIrmo';
        }
        /* --- sAIrmo-Theme (Kunden-App) — verwandt, eigener Akzent --- */
        body.theme-app {
            /* Verhindert horizontalen Scrollbalken durch 100vw-Hero (Dashboard).
               100vw inkludiert Scrollbar-Breite — ohne Clip pusht der Hero den Body
               einige Pixel über den Viewport hinaus. */
            overflow-x: clip;
            /* Die Farbwerte stehen NICHT mehr hier, sondern in
               brand-tokens.css (erzeugt aus brand/tokens.json). Dieser Block
               fuehrt nur noch die Uebergangs-Aliase, damit alter Code laeuft —
               neuer Code nutzt --petrol, --petrolhell, --stein, --sand, --apricot. */
            --tiefenblau: var(--petrol);
            --sandstein:  var(--petrolhell);
            --pergament:  var(--stein);
            --rule:       var(--sand);
            --honig:      var(--apricot);
            --display-font: 'Fraunces', Georgia, serif;
            --accent-font:  'Instrument Serif', Georgia, serif;
            --header-bg:    var(--petrol);
            --footer-claim: 'sAIrmo · Du machst, was nur du kannst. sAIrmo macht den Rest.';

            /* === Design-Tokens — neu ab 2026-05-07 ===
               Alte Inline-Werte bleiben kompatibel, neue Komponenten sollen
               diese Vars nutzen statt freier Werte. */
            /* Spacing-Skala (4px-Raster, Faktor 1.5) */
            --space-1: .25rem;   /*  4px */
            --space-2: .5rem;    /*  8px */
            --space-3: .75rem;   /* 12px */
            --space-4: 1rem;     /* 16px */
            --space-5: 1.5rem;   /* 24px */
            --space-6: 2rem;     /* 32px */
            --space-7: 2.5rem;   /* 40px */
            --space-8: 3rem;     /* 48px */

            /* Border-Radien — vier Stufen statt acht */
            --radius-sm: 4px;
            --radius-md: 8px;
            --radius-lg: 16px;
            --radius-pill: 999px;

            /* Schrift-Stufen — wenige, bewusste Sprünge */
            --font-xs:  .8rem;   /* Hinweise, Captions */
            --font-sm:  .9rem;   /* sekundärer Text */
            --font-base: 1rem;   /* Lauftext */
            --font-md:  1.15rem; /* leichte Hervorhebung */
            --font-lg:  1.35rem; /* Card-Headlines */
            --font-xl:  1.75rem; /* Section-Headlines */
            --font-2xl: 2.25rem; /* Page-H1 */

            /* Schatten-Stufen */
            --shadow-1: 0 2px 12px -6px rgba(23, 69, 87, .08);
            --shadow-2: 0 8px 28px -12px rgba(23, 69, 87, .25);
            --shadow-3: 0 18px 40px -16px rgba(23, 69, 87, .35);
        }
        * { box-sizing: border-box; }
        html, body { margin: 0; padding: 0; }
        body {
            font-family: 'Inter', system-ui, sans-serif;
            background: var(--stein);
            color: var(--anthrazit);
            line-height: 1.5;
            /* `100vh` meint auf iOS Safari die Höhe OHNE eingeblendete Adressleiste —
               die Seite ist damit immer ein Stück zu hoch. `dvh` folgt der wirklich
               sichtbaren Höhe; die `vh`-Zeile bleibt als Rückfallebene darüber. */
            min-height: 100vh;
            min-height: 100dvh;
            display: flex;
            flex-direction: column;
            /* Gegenstück zu `viewport-fit=cover` (layout.php): hält den Inhalt im
               Querformat aus den Bildschirmrundungen des iPhones heraus. Im normalen
               Browser sind die Werte 0 — die Zeilen kosten dort nichts. */
            padding-left: env(safe-area-inset-left);
            padding-right: env(safe-area-inset-right);
        }
        h1, h2, h3 { font-family: var(--display-font); color: var(--petrol); font-weight: 600; }
        h1 { font-size: 1.75rem; margin: 0 0 1rem; }
        h2 { font-size: 1.25rem; margin: 1.5rem 0 .75rem; }
        a { color: var(--petrol); }
        a:hover { color: var(--petrolhell); }
        header.app {
            /* Hell seit 21.08.2026, aus demselben Grund wie der Kunden-Header:
               die Wortmarke soll überall in ihrer einzigen Fassung stehen.
               Die Kante unten ist auch hier Pflicht (Stein auf Stein). */
            background: var(--stein);
            color: var(--anthrazit);
            border-bottom: 1px solid var(--grau);
            padding: 1rem 1.5rem;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        header.app .brand {
            font-family: 'Archivo', system-ui, sans-serif;
            font-weight: 900;
            font-size: 1.05rem;
            letter-spacing: -.035em;
        }
        header.app .brand strong { color: var(--apricot); font-weight: inherit; }
        header.app nav a, header.app nav button {
            /* ⚠️ Stand bis 02.09.2026 auf --stein — aus der Zeit, als dieser Balken
               dunkel war. Seit er hell ist (21.08.2026), waere das Stein auf Stein,
               also unsichtbar. Aufgefallen ist es nie, weil JEDES Element im
               Admin-Nav eine eigene Klasse traegt (.nav-link, .nav-dd-item) und die
               spaeter gewinnt: eine tote Regel — aber eine, die dem naechsten
               klassenlosen Link im Nav unsichtbaren Text gegeben haette. */
            color: var(--anthrazit);
            text-decoration: none;
            margin-left: 1rem;
            font-size: .9rem;
            background: none;
            border: none;
            font-family: inherit;
            cursor: pointer;
            padding: 0;
        }
        header.app nav a:hover, header.app nav button:hover { color: var(--petrolhell); }

        /* === Operator-Header-Navigation (Redesign Phase 1) ===
           Spiegelt das Dropdown-Muster des App-Headers (nav-dd). Die Menü-Karte selbst
           bleibt hell.

           ⚠️ **Diese Farben waren für einen dunklen Header gemacht — der Header ist seit
           dem 21.08.2026 hell.** Die Schrift stand auf `--stein`, und `header.app` trägt
           `background: var(--stein)`: dieselbe Farbe, gemessener Kontrast **1:1**. Sichtbar
           blieb nur, was einen eigenen Grund mitbrachte — der aktive Punkt (weiß auf
           petrolhell-28, **1,65:1**, also auch zu blass) und der Superadmin-Punkt. Die
           ganze Systemnavigation war unsichtbar, bis die Maus darüberfuhr. Aufgefallen ist
           es erst am 28.08., als jemand einen frisch eingebauten Menüpunkt suchte und die
           Leiste, in der er steht, gar nicht sehen konnte.

           Die Rollen gelten jetzt gegen hellen Grund: `--schiefer` ist der Sekundärtext auf
           hell (4,99:1), Hover und Aktiv setzen `--anthrazit` auf einen petrolhell-Schleier
           (13,4:1 / 11,6:1). ⚠️ **Nicht `--petrolhell` als Schriftfarbe nehmen** — das
           Token sagt selbst, dass es Zeichenfarbe ist, keine Schrift. */
        header.app nav.admin-nav { display: flex; align-items: center; gap: .15rem; flex-wrap: wrap; }
        header.app nav.admin-nav a.nav-link,
        header.app .nav-dd > summary {
            color: var(--schiefer);
            text-decoration: none;
            font-size: .9rem;
            font-weight: 500;
            margin-left: 0;
            padding: .4rem .6rem;
            border-radius: 6px;
            cursor: pointer;
            list-style: none;
            display: inline-flex;
            align-items: center;
            gap: .3rem;
            transition: color .15s, background .15s;
        }
        header.app nav.admin-nav a.nav-link:hover,
        header.app .nav-dd > summary:hover { color: var(--anthrazit); background: var(--petrolhell-08); }
        header.app nav.admin-nav a.nav-link.active,
        header.app .nav-dd > summary.active { color: var(--anthrazit); background: var(--petrolhell-18); font-weight: 600; }
        header.app .nav-dd { position: relative; }
        header.app .nav-dd > summary::-webkit-details-marker { display: none; }
        header.app .nav-dd .caret { font-size: .62rem; transition: transform .15s; }
        header.app .nav-dd[open] .caret { transform: rotate(180deg); }
        /* Helle Menü-Karte (wie App-Header) */
        header.app .nav-dd .nav-dd-menu {
            position: absolute; top: calc(100% + .4rem); left: 0;
            min-width: 12.5rem; background: #fff; border: 1px solid var(--sand);
            border-radius: 12px; box-shadow: 0 18px 40px -16px rgba(23, 69, 87, .45);
            padding: .4rem; z-index: 60;
        }
        header.app .nav-dd .nav-dd-menu.right { left: auto; right: 0; }
        header.app .nav-dd .nav-dd-head {
            font-family: 'Inter', system-ui, sans-serif;
            font-size: .7rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
            color: var(--text-muted); padding: .5rem .7rem .3rem;
        }
        header.app .nav-dd .nav-dd-item {
            display: block; font-family: 'Inter', system-ui, sans-serif;
            font-size: .9rem; font-weight: 500; color: var(--petrol);
            text-decoration: none; margin-left: 0; padding: .55rem .7rem; border-radius: 8px;
            border-left: 3px solid transparent; transition: background .12s, border-color .12s;
        }
        header.app .nav-dd .nav-dd-item:hover { background: rgba(38, 111, 135, .12); border-left-color: rgba(38, 111, 135, .5); color: var(--petrol); }
        header.app .nav-dd .nav-dd-item.active { background: rgba(38, 111, 135, .18); border-left-color: var(--petrolhell); font-weight: 600; }
        header.app .nav-dd .nav-dd-sep { height: 1px; background: var(--sand); margin: .35rem .3rem; }
        header.app .nav-dd .nav-dd-logout { margin: 0; }
        header.app .nav-dd .nav-dd-logout button {
            display: block; width: 100%; text-align: left; margin-left: 0;
            background: none; border: none; cursor: pointer;
            font-family: 'Inter', system-ui, sans-serif;
            font-size: .9rem; font-weight: 500; color: var(--petrol);
            padding: .55rem .7rem; border-radius: 8px;
            border-left: 3px solid transparent; transition: background .12s, border-color .12s;
        }
        header.app .nav-dd .nav-dd-logout button:hover { background: rgba(38, 111, 135, .12); border-left-color: rgba(38, 111, 135, .5); color: var(--petrol); }
        /* Konto-Pill rechts (Operator-E-Mail) */
        header.app .admin-actions { display: flex; align-items: center; gap: .75rem; }
        /* ⚠️ Rahmen und Grund standen in Stein-Weiß auf steinweißem Header — die Pille war
           unsichtbar, übrig blieb der Superadmin-Punkt allein in der Ecke. `--grau` ist
           laut Token der Rahmen bedienbarer Elemente (3,34:1 auf Stein); `--sand` wäre es
           NICHT, es kommt dort auf 1,16:1 und das Token warnt selbst davor. */
        header.app .nav-dd.konto-dd > summary {
            padding: .4rem .85rem; border-radius: 999px;
            border: 1px solid var(--grau);
            background: transparent;
            max-width: 20rem;
        }
        header.app .nav-dd.konto-dd > summary .pill-label {
            max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
        }
        header.app .nav-dd.konto-dd > summary:hover { background: var(--petrolhell-08); border-color: var(--petrolhell); }
        header.app .nav-dd .super-dot { color: var(--petrolhell); font-size: .6rem; line-height: 1; }
        @media (max-width: 720px) {
            header.app { flex-wrap: wrap; gap: .5rem; }
            header.app nav.admin-nav { order: 3; width: 100%; }
        }

        /* === sAIrmo-Header (Homepage-Look in der App) === */
        header.sairmo-header {
            position: sticky;
            top: 0;
            z-index: 50;
            /* Mit `viewport-fit=cover` (layout.php) klebt der Header beim Scrollen
               sonst UNTER der Dynamic Island / Statusleiste des iPhones. Das Padding
               schafft den Raum; der durchscheinende Blur-Hintergrund laeuft bewusst
               bis an den Displayrand weiter. Im normalen Browser ist env() = 0. */
            padding-top: env(safe-area-inset-top);
            background: rgba(244, 242, 239, 0.85);
            backdrop-filter: blur(8px);
            -webkit-backdrop-filter: blur(8px);
            border-bottom: 1px solid rgba(23, 69, 87, .06);
        }
        header.sairmo-header .inner {
            max-width: 72rem;
            margin: 0 auto;
            padding: 0 1.5rem;
            display: flex;
            align-items: center;
            gap: 1.75rem;
            height: 4rem;
            /* Containing block für das absolut positionierte Burger-Menü,
               sonst rechnet das left/right gegen den 2,4rem schmalen
               Burger-Button und das Panel wird unleserlich schmal. */
            position: relative;
        }
        @media (min-width: 640px) {
            header.sairmo-header .inner { padding: 0 2rem; height: 5rem; }
        }
        header.sairmo-header .brand {
            font-family: 'Archivo', system-ui, sans-serif;
            font-size: 1.4rem;
            font-weight: 900;
            color: var(--petrol);
            letter-spacing: -.035em;
            text-decoration: none;
            line-height: 1;
            white-space: nowrap;
        }
        @media (min-width: 640px) {
            header.sairmo-header .brand { font-size: 1.7rem; }
        }
        /* Logo-System v3 (2026-08-21, Markenneustart): Header rein typografisch —
           Wortmarke „sAIrmo." in ARCHIVO 900, nicht mehr in der Display-Schrift.
           Das „AI" sind VERSALIEN mitten im Wort, auf der Grundlinie, im Akzent.
           Kein Anheben — wer das als „Lift" liest, baut es woanders als
           Hochstellung nach (genau so entstand 2026-07 das hüpfende AI im OG-Bild).

           ⚠️ Die frühere `.82em`-Verkleinerung des AI ist ENTFALLEN: Sie glich die
           hohen Versalien von Fraunces aus. Archivo braucht das nicht — wer sie
           zurückholt, macht das AI ohne Grund kleiner als die Nachbarn.

           Der Schlusspunkt ist QUADRATISCH (siehe `.brand-dot` unten), nicht rund.
           Die Post-Stapel-Bildmarke wird NUR als Favicon/App-Icon genutzt, NICHT
           im Header (Wunsch 2026-06-16). Regeln: Memory `sairmo-wortmarke`. */
        header.sairmo-header .brand strong {
            color: var(--apricot);
            font-weight: inherit;
        }
        /* Der Schlusspunkt ist ein QUADRAT — als Textzeichen laesst er sich nicht
           eckig setzen, deshalb ein leeres Element mit Flaeche. Die Masse sind
           dieselben wie auf der Homepage (.19em Kante, .05em Abstand). */
        .brand-dot,
        .footer-brand .brand-dot {
            display: inline-block;
            width: .19em;
            height: .19em;
            margin-left: .05em;
            background: var(--apricot);
        }
        header.sairmo-header nav.primary {
            display: flex;
            align-items: center;
            gap: 1.75rem;
        }
        header.sairmo-header nav.primary a {
            font-family: 'Inter', system-ui, sans-serif;
            font-size: .9rem;
            font-weight: 500;
            /* --text-muted (Schiefer, 4,87) statt petrol-70: das waren 4,18 und
               damit unter der 4,5 fuer Fliesstext. Der aktive Link unterscheidet
               sich ohnehin nicht nur ueber die Farbe, sondern auch ueber den
               Unterstrich darunter. */
            color: var(--text-muted);
            text-decoration: none;
            padding: .5rem 0;
            position: relative;
            transition: color .15s;
        }
        header.sairmo-header nav.primary a:hover { color: var(--petrol); }
        header.sairmo-header nav.primary a.active {
            color: var(--petrol);
        }
        header.sairmo-header nav.primary a.active::after {
            content: "";
            position: absolute;
            left: 0;
            right: 0;
            bottom: -.45rem;
            height: 2px;
            background: var(--petrolhell);
            border-radius: 2px;
        }
        header.sairmo-header .actions {
            display: flex;
            align-items: center;
            gap: .75rem;
            margin-left: auto;
        }
        /* Pillen im Header dürfen auf schmalen Schirmen nicht unter ihre
           Inhaltsbreite gestaucht werden (sonst verzerrte Ellipsen). */
        header.sairmo-header .brand,
        header.sairmo-header .cta { flex-shrink: 0; }
        header.sairmo-header .logout-link {
            background: none;
            border: none;
            font-family: 'Inter', system-ui, sans-serif;
            font-size: .9rem;
            font-weight: 500;
            color: var(--text-muted);
            cursor: pointer;
            padding: .5rem .25rem;
            transition: color .15s;
        }
        header.sairmo-header .logout-link:hover { color: var(--petrol); }
        @media (max-width: 640px) {
            header.sairmo-header .logout-link { display: none; }
        }
        /* Header-CTA „+ Neuer Post" — die wichtigste Aktion der App, deshalb DER
           Akzent: Apricot mit Night-Schrift. Klar von den Account-Aktionen
           (Greeting, Abmelden) getrennt, die als reiner Text danebenstehen.

           ⚠️ Bis 02.09.2026 stand hier Petrolhell mit Petrol-Schrift — 1,83, die
           Beschriftung war auf der eigenen Flaeche nicht zu lesen. Ursache ist die
           Namens-Nachfolge beim Markenneustart: Dieser Knopf war der AKZENT-Knopf,
           und der hiess damals Koralle/Sandstein. Beim Umbenennen wanderte
           `--koralle` auf `--petrolhell` — fuer die CSS-Variable richtig, fuer die
           ROLLE falsch, denn den Akzent traegt seither Apricot. Der Beleg stand die
           ganze Zeit im Kommentar der Kontur-Regel weiter unten: Sie nennt 1,58, und
           das ist Apricot auf Stein, nicht Petrolhell (5,07). Die Kontur war fuer
           einen Apricot-Knopf gebaut und stand ueber einer Flaeche, die keine
           brauchte. Merksatz: bei jeder Konstante fragen, WELCHE ROLLE sie fuellt,
           nicht wie sie hiess. */
        header.sairmo-header .cta {
            background: var(--apricot);
            color: var(--night);
            text-decoration: none;
            padding: .6rem 1.25rem;
            border-radius: 999px;
            font-size: .9rem;
            font-weight: 600;
            box-shadow: 0 6px 18px -6px var(--petrol-12);
            transition: background .15s, color .15s, transform .1s, box-shadow .15s;
            white-space: nowrap;
            margin-left: .5rem;
            position: relative;
        }
        header.sairmo-header .cta:hover {
            background: var(--apricot-hell);
            color: var(--night);
            box-shadow: 0 8px 22px -6px rgba(23, 69, 87, .35);
        }
        header.sairmo-header .cta:active { transform: translateY(1px); }
        /* Trenner zwischen Account-Block und CTA — dezentes Sandstein-Lineal. */
        header.sairmo-header .actions {
            position: relative;
        }
        /* User-Menu inside the new header */
        header.sairmo-header details.user-menu {
            margin-left: 0;
            position: relative;
        }
        header.sairmo-header details.user-menu summary {
            background: rgba(23, 69, 87, .06);
            color: var(--petrol);
            border: 1px solid rgba(23, 69, 87, .08);
            font-size: .85rem;
            padding: .4rem .85rem;
        }
        header.sairmo-header details.user-menu summary:hover {
            background: rgba(23, 69, 87, .1);
        }
        @media (max-width: 720px) {
            header.sairmo-header .inner { gap: 1rem; }
            header.sairmo-header nav.primary { gap: 1rem; }
            header.sairmo-header nav.primary a { font-size: .85rem; }
            header.sairmo-header .cta { padding: .5rem .8rem; font-size: .85rem; }
        }

        /* === Header-Dropdowns (Marke ▾ / Konto-Pill ▾) — natives <details> ===
           Kein JS zum Öffnen nötig; ein kleiner Outside-Click-Closer im Script-
           Block am Seitenende schließt offene Menüs + verhindert Doppel-Öffnung. */
        header.sairmo-header .nav-dd { position: relative; }
        header.sairmo-header .nav-dd > summary {
            list-style: none;
            cursor: pointer;
            display: inline-flex;
            align-items: center;
            gap: .3rem;
            font-family: 'Inter', system-ui, sans-serif;
            font-size: .9rem;
            font-weight: 500;
            color: var(--text-muted);
            padding: .5rem 0;
            position: relative;
            transition: color .15s;
            -webkit-tap-highlight-color: transparent;
        }
        header.sairmo-header .nav-dd > summary::-webkit-details-marker { display: none; }
        header.sairmo-header .nav-dd > summary:hover { color: var(--petrol); }
        header.sairmo-header .nav-dd > summary.active { color: var(--petrol); }
        header.sairmo-header .nav-dd > summary.active::after {
            content: ""; position: absolute; left: 0; right: 1.1rem; bottom: -.45rem;
            height: 2px; background: var(--petrolhell); border-radius: 2px;
        }
        header.sairmo-header .nav-dd .caret { font-size: .7rem; transition: transform .15s; }
        header.sairmo-header .nav-dd[open] .caret { transform: rotate(180deg); }
        /* Pill-Variante: Tenant-Name / Konto */
        header.sairmo-header .nav-dd.konto-dd > summary {
            padding: .4rem .85rem;
            border-radius: 999px;
            border: 1px solid rgba(23, 69, 87, .15);
            background: rgba(23, 69, 87, .03);
            max-width: 16rem;
        }
        header.sairmo-header .nav-dd.konto-dd > summary .pill-label {
            max-width: 11rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
        }
        header.sairmo-header .nav-dd.konto-dd > summary:hover {
            background: var(--accent-soft);
            border-color: var(--accent-line);
            color: var(--petrol);
        }
        header.sairmo-header .nav-dd.konto-dd > summary.active::after { display: none; }
        /* Menü-Karte */
        header.sairmo-header .nav-dd .nav-dd-menu {
            position: absolute;
            top: calc(100% + .5rem);
            left: 0;
            min-width: 13rem;
            background: #fff;
            border: 1px solid var(--sand);
            border-radius: 12px;
            box-shadow: 0 18px 40px -16px rgba(23, 69, 87, .35);
            padding: .4rem;
            z-index: 60;
        }
        header.sairmo-header .nav-dd .nav-dd-menu.right { left: auto; right: 0; }
        header.sairmo-header .nav-dd .nav-dd-head {
            font-family: 'Inter', system-ui, sans-serif;
            font-size: .72rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
            color: var(--text-muted); padding: .5rem .7rem .35rem;
        }
        header.sairmo-header .nav-dd .nav-dd-item {
            display: block;
            font-family: 'Inter', system-ui, sans-serif;
            font-size: .92rem; font-weight: 500;
            color: var(--petrol);
            text-decoration: none;
            padding: .6rem .7rem;
            border-radius: 8px;
            border-left: 3px solid transparent;
            transition: background .12s, border-color .12s;
        }
        header.sairmo-header .nav-dd .nav-dd-item:hover {
            background: var(--accent-hover);
            border-left-color: var(--accent-line);
        }
        header.sairmo-header .nav-dd .nav-dd-item.active {
            background: var(--accent-soft);
            border-left-color: var(--petrolhell);
            font-weight: 600;
        }
        /* ⚠️ Der Unterstrich der Hauptnavigation gilt hier NICHT.
           `nav.primary a.active::after` (oben) sitzt bewusst tief — er soll bei
           „Übersicht"/„Posts" an der Unterkante der Kopfleiste liegen. Das Dropdown
           steht aber im selben `nav.primary`, und dort landet derselbe Strich
           unterhalb des Eintrags und sieht aus wie ein Trenner zum nächsten.
           Der aktive Eintrag ist ohnehin zweifach markiert: Fläche und Balken links.
           Dasselbe Abschalten steht im Burger-Menü weiter unten — dort war es schon
           aufgefallen, hier nicht. */
        header.sairmo-header .nav-dd .nav-dd-item.active::after { display: none; }
        header.sairmo-header .nav-dd .nav-dd-sep { height: 1px; background: var(--sand); margin: .35rem .3rem; }
        header.sairmo-header .nav-dd .nav-dd-logout { margin: 0; }
        header.sairmo-header .nav-dd .nav-dd-logout button {
            display: block; width: 100%; text-align: left;
            background: none; border: none; cursor: pointer;
            font-family: 'Inter', system-ui, sans-serif;
            font-size: .92rem; font-weight: 500; color: var(--petrol);
            padding: .6rem .7rem; border-radius: 8px;
            border-left: 3px solid transparent;
            transition: background .12s, border-color .12s;
        }
        header.sairmo-header .nav-dd .nav-dd-logout button:hover {
            background: var(--accent-hover);
            border-left-color: var(--accent-line);
        }
        /* Konto-Dropdown wandert auf Mobile ins Burger-Panel (Marke-Dropdown
           steckt in nav.nav-desktop und wird ohnehin ausgeblendet). */
        @media (max-width: 720px) {
            header.sairmo-header .actions .nav-dd.konto-dd { display: none; }
        }

        /* === Mobile-Burger-Menü ===
           Desktop: nav.nav-desktop ist sichtbar, `<details class="burger">` versteckt.
           Mobile (≤ 720 px): nav.nav-desktop versteckt, Burger-Toggle + Mobile-Panel sichtbar.
           Zwei separate Nav-Renderings vermeiden den `<details>`-Hide-Bug auf Desktop. */
        header.sairmo-header details.burger {
            display: none;
            /* KEIN position:relative — sonst wäre dies der Containing-Block
               für nav.nav-mobile und das Panel würde nur 2,4rem breit. */
        }
        header.sairmo-header details.burger > summary.burger-toggle {
            display: inline-flex;
            list-style: none;
            cursor: pointer;
            width: 2.4rem;
            height: 2.4rem;
            border-radius: 8px;
            border: 1px solid rgba(23, 69, 87, .12);
            background: transparent;
            align-items: center;
            justify-content: center;
            transition: background .15s, border-color .15s;
            -webkit-tap-highlight-color: transparent;
        }
        header.sairmo-header details.burger > summary.burger-toggle::-webkit-details-marker { display: none; }
        header.sairmo-header details.burger > summary.burger-toggle:hover {
            background: rgba(23, 69, 87, .04);
            border-color: rgba(23, 69, 87, .25);
        }
        header.sairmo-header details.burger > summary.burger-toggle .bars {
            position: relative;
            width: 1.1rem;
            height: 2px;
            background: var(--petrol);
            border-radius: 2px;
            transition: background .15s;
        }
        header.sairmo-header details.burger > summary.burger-toggle .bars::before,
        header.sairmo-header details.burger > summary.burger-toggle .bars::after {
            content: "";
            position: absolute;
            left: 0; right: 0;
            height: 2px;
            background: var(--petrol);
            border-radius: 2px;
            transition: transform .2s ease, top .2s ease, background .15s;
        }
        header.sairmo-header details.burger > summary.burger-toggle .bars::before { top: -.4rem; }
        header.sairmo-header details.burger > summary.burger-toggle .bars::after  { top:  .4rem; }
        header.sairmo-header details.burger[open] > summary.burger-toggle .bars { background: transparent; }
        header.sairmo-header details.burger[open] > summary.burger-toggle .bars::before { top: 0; transform: rotate(45deg); }
        header.sairmo-header details.burger[open] > summary.burger-toggle .bars::after  { top: 0; transform: rotate(-45deg); }

        @media (max-width: 720px) {
            header.sairmo-header nav.primary.nav-desktop { display: none; }
            header.sairmo-header details.burger { display: block; margin-left: auto; }
            header.sairmo-header details.burger nav.primary.nav-mobile {
                position: absolute;
                top: calc(100% + .35rem);
                right: 1rem;
                left: 1rem;
                background: var(--stein);
                border: 1px solid var(--sand);
                border-radius: 12px;
                box-shadow: 0 18px 40px -16px rgba(23, 69, 87, .35);
                padding: .65rem;
                display: flex;
                flex-direction: column;
                align-items: stretch; /* überschreibt align-items:center aus nav.primary → Items links-bündig + volle Breite */
                gap: 0;
                z-index: 50;
                /* ⚠️ **Das Netz unter den zugeklappten Gruppen.** Die Karte hängt
                   `absolute` an einem `sticky`-Header — was über den Bildschirmrand
                   hinausragt, ist nicht erreichbar, auch nicht durch Scrollen der Seite.
                   Ohne diese Grenze waren Konto, Team und Abmelden am Handy schlicht weg.
                   Die Gruppen halten die Karte normalerweise kurz genug; diese Regel
                   greift, wenn jemand alle aufklappt oder das Menü weiter wächst.
                   `dvh` statt `vh`, weil die Adressleiste mobiler Browser ein- und
                   ausfährt — `vh` rechnet mit der ausgefahrenen und schneidet trotzdem ab. */
                max-height: calc(100dvh - 5.5rem);
                overflow-y: auto;
                overscroll-behavior: contain;
            }
            header.sairmo-header details.burger nav.primary a {
                padding: .85rem 1rem;
                font-size: .98rem;
                color: var(--petrol);
                border-radius: 8px;
                border-left: 3px solid transparent;
                transition: background .12s, border-color .12s, color .12s;
            }
            header.sairmo-header details.burger nav.primary a:hover {
                background: var(--accent-hover);
                border-left-color: var(--accent-line);
            }
            header.sairmo-header details.burger nav.primary a.active {
                background: var(--accent-soft);
                border-left-color: var(--petrolhell);
                font-weight: 600;
            }
            header.sairmo-header details.burger nav.primary a.active::after { display: none; }
            header.sairmo-header details.burger:not([open]) nav.primary.nav-mobile { display: none; }
            header.sairmo-header details.burger .burger-sep {
                display: block; height: 1px; background: var(--sand); margin: .4rem .35rem;
            }
            header.sairmo-header details.burger .burger-section {
                font-size: .72rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
                color: var(--text-muted); padding: .55rem 1rem .3rem;
            }
            /* Aufklappbare Gruppe (Marke / Planung / Konto). Die Überschrift IST der
               Schalter — deshalb hat sie eine eigene Tippfläche und einen Pfeil, der
               zeigt, was passiert. Ohne diesen Hinweis sieht sie aus wie eine Beschriftung
               und wird nicht angetippt. */
            header.sairmo-header details.burger .burger-group > summary.burger-section {
                display: flex;
                align-items: center;
                justify-content: space-between;
                gap: .5rem;
                min-height: 44px; /* Fingerkuppe, nicht Mauszeiger */
                padding: .55rem 1rem;
                border-radius: 8px;
                cursor: pointer;
                list-style: none;
                user-select: none;
            }
            header.sairmo-header details.burger .burger-group > summary::-webkit-details-marker { display: none; }
            header.sairmo-header details.burger .burger-group > summary.burger-section::after {
                content: "▾";
                font-size: .8rem;
                color: var(--text-muted);
                transition: transform .15s;
                transform: rotate(-90deg); /* zu: zeigt nach rechts */
            }
            header.sairmo-header details.burger .burger-group[open] > summary.burger-section::after {
                transform: rotate(0deg);
            }
            header.sairmo-header details.burger .burger-group > summary.burger-section:hover {
                background: var(--accent-hover);
                color: var(--petrol);
            }
            /* Die Einträge einer Gruppe rücken ein — so sieht man, wozu sie gehören,
               auch wenn zwei Gruppen gleichzeitig offen sind. */
            header.sairmo-header details.burger .burger-group > a {
                margin-left: .5rem;
            }
            /* Steht in der Konto-Gruppe und rückt mit ihren Nachbarn ein. */
            header.sairmo-header details.burger .burger-logout { margin: 0 0 0 .5rem; }
            header.sairmo-header details.burger .burger-logout button {
                display: block; width: 100%; text-align: left;
                background: none; border: none; font-family: inherit;
                font-size: .98rem; color: var(--petrol);
                padding: .85rem 1rem; border-radius: 8px; cursor: pointer;
                border-left: 3px solid transparent; transition: background .12s, border-color .12s;
            }
            header.sairmo-header details.burger .burger-logout button:hover {
                background: var(--accent-hover);
                border-left-color: var(--accent-line);
            }
        }


        /* User-Menu (Dropdown via details/summary) */
        details.user-menu {
            position: relative;
            margin-left: 1rem;
        }
        details.user-menu summary {
            list-style: none;
            cursor: pointer;
            display: inline-flex;
            align-items: center;
            gap: .5rem;
            padding: .35rem .75rem;
            border-radius: 999px;
            /* ⚠️ Stand bis 02.09.2026 auf Weiss-8% mit --stein-Schrift — gebaut fuer
               die Zeit, als der Kopfbalken dunkel war. Auf hellem Grund waere das
               Stein auf Weiss, also unsichtbar. Die Klasse kommt heute in keinem
               Template mehr vor (nur die Header-Variante weiter unten ist in
               Gebrauch und war schon korrigiert): eine tote Regel — aber eine, die
               dem naechsten Aufrufer unsichtbaren Text gaebe. */
            background: var(--petrol-08);
            border: 1px solid var(--border-button);
            color: var(--petrol);
            font-size: .85rem;
        }
        details.user-menu summary::-webkit-details-marker { display: none; }
        details.user-menu summary:hover { background: var(--petrol-12); }
        details.user-menu summary .chev { font-size: .7rem; opacity: .7; }
        details.user-menu .panel {
            position: absolute;
            right: 0;
            top: calc(100% + .5rem);
            min-width: 12rem;
            background: #fff;
            color: var(--anthrazit);
            border: 1px solid var(--sand);
            border-radius: 8px;
            box-shadow: 0 12px 32px rgba(0,0,0,.12);
            padding: .35rem;
            z-index: 50;
        }
        details.user-menu .panel a,
        details.user-menu .panel button {
            display: block;
            width: 100%;
            text-align: left;
            padding: .55rem .75rem;
            color: var(--anthrazit);
            text-decoration: none;
            font-size: .9rem;
            border-radius: 4px;
            background: none;
            border: none;
            font-family: inherit;
            cursor: pointer;
        }
        details.user-menu .panel a:hover,
        details.user-menu .panel button:hover { background: var(--sand); color: var(--petrol); }
        details.user-menu .panel .divider {
            height: 1px;
            background: var(--sand);
            margin: .35rem 0;
        }
        details.user-menu .panel .email {
            padding: .5rem .75rem .25rem;
            font-size: .75rem;
            color: var(--text-muted);
            text-transform: uppercase;
            letter-spacing: .04em;
        }
        main {
            flex: 1;
            max-width: 60rem;
            width: 100%;
            margin: 0 auto;
            padding: 2rem 1.5rem;
        }
        /* Operator-Bereich ist Desktop + datendicht (breite Mandanten-Tabellen) —
           mehr Breite als der Lese-optimierte App-/Marketing-Bereich. */
        body.theme-admin main { max-width: 84rem; }
        footer.app {
            text-align: center;
            color: var(--text-muted);
            font-size: .85rem;
            padding: 1.5rem;
            /* Home-Indicator des iPhones: Mit `viewport-fit=cover` reicht die Seite
               bis unter den Balken. `max()` hält den normalen Abstand, wo es keinen
               Indicator gibt. */
            padding-bottom: max(1.5rem, env(safe-area-inset-bottom));
            border-top: 1px solid var(--sand);
        }
        .card {
            background: #fff;
            border: 1px solid var(--sand);
            border-radius: 6px;
            padding: 1.5rem;
            margin-bottom: 1rem;
        }
        .card.narrow { max-width: 28rem; margin-left: auto; margin-right: auto; }
        label { display: block; font-size: .9rem; margin-bottom: .25rem; color: var(--petrol); }
        input[type=email], input[type=text], input[type=url], input[type=tel], input[type=number], input[type=password] {
            width: 100%;
            padding: .6rem .75rem;
            font-family: inherit;
            font-size: 1rem;
            /* Feldkante braucht 3:1 (WCAG 1.4.11) — Sand liegt bei 1,16. */
            border: 1px solid var(--border-field);
            border-radius: 4px;
            background: #fff;
        }
        /* ⚠️ iOS Safari zoomt beim Antippen automatisch in die Seite, sobald ein
           Feld kleiner als 16px ist — und zoomt NICHT von selbst zurueck. Die
           Regel oben steht auf 1rem, aber neun Stellen unterbieten sie (der
           Briefing-Assistent mit `.wiz-free` auf .85rem, die Personas-Auswahl mit
           .72rem …). Im Assistenten mit seinen 23 Feldern hiess das: bei jedem
           Feld hineinzoomen, von Hand wieder herauswischen, weiter.

           Warum hier zentral und mit `!important`: Vier der neun Felder tragen
           ihre Groesse als INLINE-Stil (app_assets, app_personas) und sind anders
           nicht erreichbar. Geprueft: kein einziges Feld im Projekt ist absichtlich
           groesser als 1rem, die Regel kann also nichts verkleinern.
           `pointer: coarse` trifft nur Finger — am Rechner bleibt jede
           Feingestaltung unangetastet. Checkbox/Radio bleiben aussen vor: Sie
           tragen keinen Text und loesen den Zoom nicht aus. */
        @media (pointer: coarse) {
            input:not([type=checkbox]):not([type=radio]),
            select,
            textarea { font-size: 16px !important; }
            /* Ankreuzfelder kommen ab Werk mit rund 13-16px — deutlich unter den
               24px, die WCAG 2.2 (2.5.8) als Untergrenze fuer Zeigerziele nennt.
               Betrifft u. a. die Zustimmung bei der Registrierung: ein Pflichtfeld,
               an dem die Anmeldung sonst scheitert.
               `!important` aus demselben Grund wie bei der Schriftgroesse oben: Drei
               Felder im Generieren-Dialog (Icons, Hashtags, KI-Kennzeichen) tragen
               `width:1.05rem` als INLINE-Stil und waeren sonst nicht erreichbar. */
            input[type=checkbox],
            input[type=radio] { width: 1.5rem !important; height: 1.5rem !important; }
            /* Verhindert, dass ein Doppeltipp auf Bedienelemente als Zoom-Geste
               ausgelegt wird — und nimmt die historische Klickverzoegerung mit. */
            button, .btn, a, label, summary, [role=button] { touch-action: manipulation; }
            /* Nachgemessen am iPhone-Profil (390px, DPR 3): Die Absende-Knoepfe kamen
               auf 42,8px, die Umschalter Passwort/Magic-Link auf 37,6px — beide knapp
               unter der 44px-Untergrenze. Nur eine Mindesthoehe, keine feste: Wer
               laengeren Text traegt, darf weiter wachsen. */
            button, .btn, button.primary, .tab, [role=button], summary { min-height: 44px; }
            .tab { display: inline-flex; align-items: center; justify-content: center; }
            /* Der Burger-Knopf ist auf dem Handy DAS Bedienelement der Navigation —
               gemessen kam er auf 38,4px. `summary` traegt von sich aus keine
               Ausrichtung, deshalb hier mittig setzen statt nur die Hoehe zu heben. */
            summary.burger-toggle { display: flex; align-items: center; justify-content: center; }
        }
        /* === Fokus — EINE Regel fuer alles Bedienbare ===
           Zweischichtig nach dem Vorbild von GOV.UK und dem US Web Design
           System: innen Night, aussen Amber. Grund: Ein einfarbiger Ring
           versagt immer irgendwo. Night traegt auf hellem Grund (15,8 auf
           Stein) und gegen den grauen Feldrahmen (4,7); auf dunklen
           Sektionen verschwindet Night, dort traegt der Amber-Ring (6,9 auf
           Petrol). Beide zusammen funktionieren ueberall.

           :focus-visible statt :focus — der Ring erscheint bei Tastatur-
           bedienung, nicht bei jedem Mausklick.

           ⚠️ NIE durch einen halbtransparenten box-shadow ersetzen. Genau
           das stand hier bis 2026-08-02 (15 % Deckung = Kontrast 1,19 statt
           der geforderten 3,0) und machte den Fokus praktisch unsichtbar.

           ⚠️ Der AEUSSERE Ring liegt auf box-shadow und wird deshalb von
           Elementen mit eigenem Schatten (z. B. .btn im Kunden-Theme)
           ueberschrieben — CSS kennt keine additive box-shadow. Der innere
           Ring ist darum bewusst 3px stark und traegt ALLEIN: Night auf Stein
           ist 15,8, auf Sand 13,7, gegen den grauen Feldrahmen 4,7. Der
           Amber-Ring ist die Zugabe fuer dunkle Flaechen, keine Bedingung. */
        :focus-visible {
            outline: 3px solid var(--focus-ring);
            outline-offset: 2px;
            box-shadow: 0 0 0 5px var(--focus-ring-outer);
        }
        /* Aeltere Engines ohne :focus-visible sollen nicht ganz ohne Ring
           dastehen — dort greift der einfache Fokus. */
        @supports not selector(:focus-visible) {
            :focus { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
        }

        /* === Nur fuer die Vorlesestimme ===
           Text, der gesprochen, aber nicht gezeigt werden soll. `display:none`
           und `visibility:hidden` taugen dafuer NICHT — beide nehmen das Element
           auch aus dem Barrierebaum, es wird dann gar nicht vorgelesen. Deshalb
           der Umweg ueber ein 1px-Feld mit `clip-path`: das Element bleibt im
           Baum, belegt aber keinen Platz. `white-space: nowrap` verhindert, dass
           laengerer Text in der 1px-Zelle umbricht und die Zeilenhoehe der Seite
           verschiebt.

           `.sr-only-focusable` hebt das wieder auf, sobald das Element den Fokus
           bekommt — fuer Bedienbares, das erst beim Hintabben sichtbar werden
           soll. Bisher genau ein Fall: der Sprunglink direkt darunter. */
        .sr-only {
            position: absolute;
            width: 1px;
            height: 1px;
            padding: 0;
            margin: -1px;
            overflow: hidden;
            clip-path: inset(50%);
            white-space: nowrap;
            border: 0;
        }
        .sr-only-focusable:focus {
            position: static;
            width: auto;
            height: auto;
            margin: 0;
            overflow: visible;
            clip-path: none;
            white-space: normal;
        }

        /* === Sprunglink „Zum Inhalt springen" (layout.php, erstes Element im Body) ===
           Eigenen Fokus-Ring bekommt er KEINEN — es gilt die eine `:focus-visible`-
           Regel oben. Hier steht nur, wo er landet und wie er aussieht.

           `position: fixed` schlaegt hier `position: static` aus
           `.sr-only-focusable:focus` (0,3,0 gegen 0,2,0 — deshalb steht der Block
           bewusst DANACH). Statisch waere er zwar auch sichtbar, wuerde aber die
           ganze Seite um seine Hoehe nach unten schieben.

           Abstand zum Rand ist kein Geschmack: Der Fokus-Ring liegt 2px AUSSERHALB
           des Elements und wuerde an Kante 0/0 halb abgeschnitten. `env()` faengt
           zusaetzlich die Statusleiste des iPhones ab (vgl. `viewport-fit=cover`).

           Farben aus der Semantik-Ebene, nicht aus der Palette — der Link liegt in
           beiden Themes ueber demselben hellen Grund und braucht darum keine
           Theme-Weiche. */
        .skip-link {
            background: var(--surface-card);
            color: var(--text-body);
            border-radius: 8px;
            font-weight: 600;
            font-size: .95rem;
            text-decoration: none;
        }
        /* ⚠️ Rahmen und Innenabstand stehen HIER und nicht oben in `.skip-link`.
           Beide Klassen zaehlen (0,1,0); `.skip-link` steht spaeter und wuerde
           damit `padding: 0` / `border: 0` aus `.sr-only` schlagen. Nachgemessen
           am 02.09.2026: Das versteckte Element war dann 39x26px statt 1x1 —
           unsichtbar (clip-path) zwar, aber unnoetig im Weg. */
        .skip-link.sr-only-focusable:focus {
            position: fixed;
            top: calc(env(safe-area-inset-top) + .5rem);
            left: .5rem;
            padding: .75rem 1.15rem;
            border: 1px solid var(--border-strong);
            /* Der klebende Kopf (`header.sairmo-header`) steht auf 50, das
               Entwurfs-Overlay des Briefings auf 50. Darueber, sonst faellt der
               Link genau dort aus, wo man ihn braucht. */
            z-index: 100;
        }

        /* Landeplatz des Sprunglinks. Nachgemessen am 02.09.2026: Nach dem
           Betaetigen sitzt der Fokus auf `<main>` und Chromium wertet ihn als
           sichtbar — der volle Ring legt dann einen 3px-Rahmen samt 5px Amber-Hof
           um den halben Bildschirm. Das ist keine Ruecklaufmeldung mehr, das sieht
           aus wie ein Fehler.

           Ganz loeschen waere trotzdem falsch: Ohne jede Rueckmeldung weiss ein
           sehender Tastaturnutzer nicht, ob der Sprung ueberhaupt etwas getan hat.
           Also bleibt die Linie in der Fokusfarbe, aber INNEN gezogen (kein
           Zuwachs, kein Ueberlauf am Rand) und ohne den Amber-Hof, der sonst nur
           Aufforderungen gehoert. */
        main[tabindex="-1"]:focus-visible {
            outline: 2px solid var(--focus-ring);
            outline-offset: -2px;
            box-shadow: none;
        }

        /* === Fokus auf der Fehlermeldung (app.js setzt ihn nach einem Abschicken) ===
           Nachgemessen am 02.09.2026 mit Chromium: Ein `focus()` aus dem Skript auf
           ein frisch geladenes Dokument zaehlt dort SEHR WOHL als „sichtbarer"
           Fokus — `:focus-visible` trifft zu. Die Annahme, `tabindex="-1"` bleibe
           still, ist falsch.

           Ungebremst legt das den vollen Ring (3px Night plus 5px Amber) um eine
           rote Meldung. Das liest sich wie ein zweiter Defekt, und die Box ist
           nichts Bedienbares — es gibt nichts zu druecken.

           `outline: none` waere die falsche Antwort: Ein sehender Tastaturnutzer
           weiss sonst nicht, wo der Fokus gelandet ist, und stolpert beim naechsten
           Tab ins Nichts. Deshalb bleibt eine Kante — in der Farbe der Meldung
           selbst und INNEN gezogen, damit sie die Box nicht wachsen laesst und
           nicht nach Amber-Aufforderung aussieht. */
        .alert[tabindex="-1"]:focus-visible {
            outline: 2px solid var(--status-error-line);
            outline-offset: -4px;
            box-shadow: none;
        }

        /* === Windows-Kontrastmodus (forced-colors) ===
           Unsere Zielgruppe arbeitet fast ausschliesslich auf Windows. Ist der
           Kontrastmodus aktiv, ersetzt das System alle Farben — eigene Rahmen
           und Schatten verschwinden dann ersatzlos. Deshalb hier die Kanten
           ueber Systemfarben nachziehen, damit Felder, Meldungen und der
           Fokusring erkennbar bleiben. */
        /* === Bewegung reduzieren (WCAG 2.3.3) ===
           Die Website kennt das seit dem Redesign, die App bis 2026-08-04 nicht —
           beim Barrierefreiheits-Durchgang am 02.08. uebersehen. Wer im System
           „Bewegung reduzieren" einschaltet, tut das meist wegen Schwindel oder
           Migraene; auf dem Handy ist die Einstellung besonders verbreitet.

           ⚠️ Bewusst NICHT die uebliche Holzhammer-Regel („alle Animationen auf
           0,01ms"): Die App hat 13 Lade-Ringe, die Zustand kommunizieren. Ein
           stehender Spinner sieht aus wie eine haengende Anwendung — das waere
           schlechter als die Bewegung. Abgeschaltet wird deshalb nur, was rein
           dekorativ ist: die 68 Uebergaenge und die vier Schiebe-Animationen von
           Kalender und Layout-Galerie. */
        @media (prefers-reduced-motion: reduce) {
            *, *::before, *::after {
                transition-duration: .01ms !important;
                scroll-behavior: auto !important;
            }
            .cal-stage .cal-grid,
            .cal-stage .cal-grid[data-slide],
            .layout-galerie[data-slide] {
                animation: none !important;
                transform: none !important;
                opacity: 1 !important;
            }
        }
        @media (forced-colors: active) {
            :focus-visible {
                outline: 3px solid CanvasText;
                outline-offset: 2px;
                box-shadow: none;
            }
            input, textarea, select, button, .card, .alert {
                border: 1px solid CanvasText;
            }
            /* Kein forced-color-adjust: none — der Nutzer hat sich fuer die
               Systemfarben entschieden, die respektieren wir. Die Meldungsart
               traegt ohnehin das Zeichen, nicht die Farbe. */
            .alert::before { color: CanvasText; }
        }
        button.primary, .btn {
            background: var(--petrol);
            color: var(--stein);
            border: none;
            padding: .65rem 1.25rem;
            font-family: inherit;
            font-size: 1rem;
            border-radius: 4px;
            cursor: pointer;
        }
        button.primary:hover, .btn:hover { background: var(--petrol); }
        /* Basis-Sekundaerknopf, themenlos — das Gegenstueck zu `.btn` darueber.
           ⚠️ Warum diese Regel existieren MUSS: Die Sekundaer-Familie war bis
           02.09.2026 ausschliesslich unter `body.theme-app` definiert. In der
           Operator-Konsole (`theme-admin`) griff damit gar nichts — „Verwerfen" in
           der Musterverwaltung stand als nackter Browser-Knopf da und sah aus wie
           die Hauptaktion daneben. Dasselbe Muster wie bei `.btn-sekundaer` am
           31.08.: eine Klasse wird benutzt, aber nie definiert, und es faellt
           niemandem auf, weil ein ungestylter Knopf ja funktioniert.
           Die Pillenform der Kunden-App ueberschreibt das weiter unten. */
        .secondary, .button-secondary, .btn-pill-secondary {
            background: transparent;
            color: var(--petrol);
            border: 1px solid var(--border-button);
            padding: .65rem 1.25rem;
            font-family: inherit;
            font-size: 1rem;
            border-radius: 4px;
            cursor: pointer;
        }
        .secondary:hover, .button-secondary:hover, .btn-pill-secondary:hover {
            background: var(--petrol-08);
            border-color: var(--petrol);
        }
        /* `.btn-sekundaer` ist die KLEINE Sekundaer-Pille — dieselbe Familie wie
           `.secondary` / `.button-secondary` / `.btn-pill-secondary`, nur kompakter.

           Geschichte, damit sie sich nicht wiederholt: Die Klasse stand seit Tagen
           in app_achse.php und spracheingabe.js, ohne dass es je eine CSS-Regel dazu
           gab — die Knoepfe waren nackte Browser-Standardknoepfe (gefunden 31.08.2026).
           Die Nachdefinition machte sie eckig und gross, mit voller Petrol-Kante;
           damit stand die NEBENaktion lauter da als die Pille daneben. Und weil das
           Grundmass nicht passte, verkleinerte sie jeder Aufrufer per Inline-Style —
           alle fuenf, auf zwei verschiedene Masse. Am 02.09.2026 zusammengelegt: eine
           Familie, zwei Groessen, Inline-Overrides raus. Wer hier eine dritte Groesse
           braucht, gibt ihr eine Klasse statt eines style-Attributs. */
        .btn-sekundaer {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: .35rem;
            background: transparent;
            color: var(--petrol);
            border: 1px solid var(--border-button);
            padding: .35rem .85rem;
            font-family: inherit;
            font-size: .82rem;
            font-weight: 500;
            border-radius: 999px;
            text-decoration: none;
            cursor: pointer;
            line-height: 1.3;
            transition: background .15s, border-color .15s;
        }
        .btn-sekundaer:hover { background: var(--petrol-08); border-color: var(--petrol); }
        .muted { color: var(--text-muted); font-size: .9rem; }
        /* Leiser Hinweis, wenn eine Liste leer bleibt (Instagram-Seitenauswahl). Die Klasse
           war benutzt, aber nie definiert — der Absatz stand als ganz normaler Fliesstext da,
           wo eine Nebenbemerkung gemeint war. Gefunden am 31.08.2026. */
        .empty-hint { color: var(--text-muted); font-size: .9rem; line-height: 1.5; }
        /* === Meldungen ===
           Hinweis und Fehler unterscheiden sich NICHT nur durch die Farbe:
           Jede Meldung traegt ein Zeichen. Bis 2026-08-02 war der Unterschied
           rein farblich — fuer die rund 8 % der Maenner mit Rot-Gruen-Schwaeche
           sah eine Fehlermeldung aus wie ein harmloser Hinweis (WCAG 1.4.1). */
        /* ⚠️ **Lasur statt Vollflaeche (24.08.2026).** Bis dahin lag hinter jeder Meldung
           eine deckende Pastellflaeche (`--status-*-bg`) mit einem 3-px-Balken links.
           Auf der Anmeldeseite wirkte ein Tippfehler beim Passwort dadurch wie ein
           Stoerfall — Florian: *„kannst du das auch in diesem dezenten Petrol machen"*.

           Gemeint war nicht die Farbe, sondern die Lautstaerke: Die Meldungen im
           Instagram-Bereich (`.insta-flash`) tragen dieselbe Farbe als 8-%-Lasur mit
           duennem Rand ringsum, und auf dem petrolgetoenten Grund der App liest sich das
           ruhig, fast blaustichig. Genau das ist jetzt der Normalfall.

           **Die Farbe bleibt, was sie war.** Rot ist hier eine getroffene Entscheidung,
           kein Rest: `--fehler` ist laut Token *„bewusst dunkler und blauer als Koralle,
           damit sich Akzent und Stoerung nicht verwechseln"*. Und das Zeichen im
           `::before` traegt die Meldungsart weiterhin ohne Farbe — die Regel darueber
           gilt unveraendert.

           Gemischt wird aus dem Token, nicht aus abgeschriebenen rgba-Werten: Wer den
           Fehlerton aendert, aendert damit auch Flaeche und Rand. */
        .alert {
            background: color-mix(in srgb, var(--status-warning-fg) 8%, transparent);
            border: 1px solid color-mix(in srgb, var(--status-warning-fg) 35%, transparent);
            padding: .75rem 1rem .75rem 2.5rem;
            border-radius: 8px;
            margin-bottom: 1rem;
            position: relative;
            /* ⚠️ **Eine Meldung bringt ihre eigene Flaeche mit — dann muss sie auch ihre
               eigene Tinte mitbringen.** Bis zum 27.08.2026 stand hier keine Farbe; der
               Kasten erbte sie. Das ging gut, solange er auf hellem Grund stand. */
            color: var(--anthrazit);
        }

        /* ⚠️ **Und sie muss sich gegen die invertierte Karte durchsetzen.**
           `body:is(.theme-app, .theme-admin) .card-inverse p` zaehlt (0,2,2) und schlaegt `.alert` (0,1,0).
           Die Galerie-Fehlermeldung wird per JS als `<p class="alert error">` erzeugt und
           stand deshalb in HELLER Tinte auf ihrer eigenen, fast weissen Flaeche:
           gemessener Kontrast **1,10 : 1**, also unlesbar. Vorher trug sie eine
           Inline-Farbe und war wenigstens sichtbar — die Umstellung auf die Klasse hat
           das Problem erst erzeugt.
           Drei Klassen (0,3,1) gewinnen. Dieselbe Lehre wie bei der Galerie daneben:
           Eine helle Insel in einer dunklen Karte stellt ihre Tinte selbst wieder her. */
        body:is(.theme-app, .theme-admin) .card-inverse .alert { color: var(--anthrazit); }
        .alert::before {
            content: "!";
            position: absolute;
            left: .9rem;
            top: .75rem;
            font-weight: 700;
            color: var(--status-warning-fg);
        }
        .alert.error {
            background: color-mix(in srgb, var(--status-error-fg) 8%, transparent);
            border-color: color-mix(in srgb, var(--status-error-fg) 35%, transparent);
        }
        .alert.error::before { content: "\00d7"; color: var(--status-error-fg); font-size: 1.15em; line-height: 1; }
        .alert.success {
            background: color-mix(in srgb, var(--status-success-fg) 8%, transparent);
            border-color: color-mix(in srgb, var(--status-success-fg) 35%, transparent);
        }
        .alert.success::before { content: "\2713"; color: var(--status-success-fg); }
        table.tenants { width: 100%; border-collapse: collapse; font-size: .95rem; }
        table.tenants th, table.tenants td { text-align: left; padding: .5rem .75rem; border-bottom: 1px solid var(--sand); }
        table.tenants th { font-family: var(--display-font); color: var(--petrol); font-weight: 600; }
        .pill { display: inline-block; padding: .1rem .5rem; border-radius: 99px; font-size: .8rem; white-space: nowrap; }
        .pill.active { background: var(--status-success-bg); color: var(--status-success-fg); }
        /* Schrift --text-body, nicht --text-muted: auf der Sand-Flaeche erreicht
           Schiefer nur 4,32. Die Pille bleibt trotzdem leise — das leistet die
           Flaeche, nicht die Schrift. Betrifft zehn Status-Anzeigen der Konsole
           („gesperrt", „nie", „unvollstaendig"), die im Stoerfall gelesen werden. */
        .pill.inactive { background: var(--sand); color: var(--text-body); }

        /* === Mandanten-Liste: Kennzahlen, Toolbar, Filter, Sortierung (Redesign Phase 2) ===
           Nur im Operator-Theme, damit die App-Seite unberührt bleibt. */
        body.theme-admin .tenant-summary { display: flex; flex-wrap: wrap; gap: 1.75rem; margin: .25rem 0 1.1rem; }
        body.theme-admin .tenant-summary .kpi { display: flex; flex-direction: column; gap: .05rem; }
        body.theme-admin .tenant-summary .kpi .num { font-family: var(--display-font); font-size: 1.45rem; font-weight: 600; color: var(--petrol); font-variant-numeric: tabular-nums; line-height: 1.1; }
        body.theme-admin .tenant-summary .kpi .lbl { font-size: .76rem; color: var(--text-muted); letter-spacing: .02em; }
        body.theme-admin .tenant-toolbar { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; justify-content: space-between; margin-bottom: .75rem; }
        body.theme-admin .tenant-search { flex: 1 1 16rem; max-width: 24rem; padding: .5rem .8rem; border: 1px solid var(--border-field); border-radius: 8px; font: inherit; font-size: .9rem; background: #fff; }
        body.theme-admin .tenant-search:focus { border-color: var(--petrol); }
        body.theme-admin .filter-tabs { display: inline-flex; gap: .2rem; background: var(--stein); border: 1px solid var(--sand); border-radius: 999px; padding: .2rem; }
        body.theme-admin .filter-tab { border: none; background: none; cursor: pointer; font: inherit; font-size: .85rem; font-weight: 500; color: var(--text-muted); padding: .35rem .9rem; border-radius: 999px; transition: background .12s, color .12s; }
        body.theme-admin .filter-tab:hover { color: var(--petrol); }
        body.theme-admin .filter-tab.active { background: #fff; color: var(--petrol); box-shadow: 0 1px 3px rgba(23, 69, 87, .12); }
        body.theme-admin table.tenants th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
        body.theme-admin table.tenants th.sortable:hover { color: var(--petrolhell); }
        body.theme-admin table.tenants th .arrow { font-size: .7rem; opacity: .3; margin-left: .2rem; }
        body.theme-admin table.tenants th[aria-sort="ascending"] .arrow,
        body.theme-admin table.tenants th[aria-sort="descending"] .arrow { opacity: 1; color: var(--petrolhell); }
        body.theme-admin table.tenants tr.is-filtered { display: none; }
        body.theme-admin .tenant-noresults { padding: 1.25rem .9rem; color: var(--text-muted); font-size: .9rem; }

        /* === Mandanten-Detail: Kopf + Tab-Leiste (Redesign Phase 3) === */
        body.theme-admin .tenant-head { margin-bottom: 1.5rem; }
        body.theme-admin .tenant-crumbs { font-size: .85rem; margin-bottom: .5rem; }
        body.theme-admin .tenant-crumbs a { color: var(--petrolhell); text-decoration: none; font-weight: 600; }
        body.theme-admin .tenant-crumbs a:hover { text-decoration: underline; }
        body.theme-admin .tenant-crumbs .sep { color: var(--kiesel); margin: 0 .45rem; }
        body.theme-admin .tenant-crumbs .current { color: var(--text-muted); }
        body.theme-admin .tenant-title { margin: .4rem 0 .15rem; display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
        body.theme-admin .tenant-sub { margin: 0 0 .9rem; }
        body.theme-admin .tenant-tabs { display: flex; gap: .1rem; flex-wrap: wrap; border-bottom: 1px solid var(--sand); }
        body.theme-admin .tenant-tabs a {
            font-size: .9rem; font-weight: 500; color: var(--text-muted); text-decoration: none;
            padding: .55rem .9rem; border-bottom: 2px solid transparent; margin-bottom: -1px;
            transition: color .12s, border-color .12s; white-space: nowrap;
        }
        body.theme-admin .tenant-tabs a:hover { color: var(--petrol); }
        body.theme-admin .tenant-tabs a.active { color: var(--petrol); border-bottom-color: var(--petrolhell); font-weight: 600; }
        .help-icon {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 1.1rem;
            height: 1.1rem;
            border-radius: 50%;
            background: var(--sand);
            color: var(--petrol);
            font-size: .75rem;
            font-weight: 600;
            cursor: help;
            margin-left: .25rem;
            vertical-align: middle;
            position: relative;
        }
        .help-icon:hover { background: var(--petrolhell); color: #fff; }

        /* Custom-Tooltip via data-tooltip — ersetzt das langsame, hässliche
           Browser-Native (title=) Tooltip. Erscheint sofort, im sAIrmo-Look. */
        .help-icon[data-tooltip]:hover::before,
        .help-icon[data-tooltip]:focus-visible::before {
            content: attr(data-tooltip);
            position: absolute;
            bottom: calc(100% + 8px);
            left: 50%;
            transform: translateX(-50%);
            background: var(--petrol);
            color: var(--stein);
            padding: .5rem .7rem;
            border-radius: 5px;
            font-size: .78rem;
            font-weight: 400;
            line-height: 1.45;
            white-space: normal;
            width: max-content;
            max-width: 16rem;
            text-align: left;
            box-shadow: 0 6px 18px -4px rgba(23, 69, 87, .35);
            z-index: 100;
            pointer-events: none;
        }
        .help-icon[data-tooltip]:hover::after,
        .help-icon[data-tooltip]:focus-visible::after {
            content: '';
            position: absolute;
            bottom: calc(100% + 3px);
            left: 50%;
            transform: translateX(-50%);
            border: 5px solid transparent;
            border-top-color: var(--petrol);
            z-index: 100;
            pointer-events: none;
        }

        /* === App-Theme-spezifische Politur (sAIrmo-Look) === */
        body.theme-app h1 {
            font-size: 2.25rem;
            font-weight: 500;
            letter-spacing: -.01em;
            line-height: 1.15;
            margin: 0 0 1.25rem;
        }
        body.theme-app h2 {
            font-size: 1.5rem;
            font-weight: 500;
            letter-spacing: -.005em;
            margin: 2rem 0 1rem;
        }
        body.theme-app main {
            padding: 2.5rem 1.5rem 4rem;
            max-width: 72rem; /* matched mit header.sairmo-header .inner und .dash-hero .grid */
        }
        @media (min-width: 640px) {
            body.theme-app main { padding: 2.5rem 2rem 4rem; }
        }
        body.theme-app header.app {
            padding: .9rem 1.5rem;
        }
        body.theme-app header.app .brand {
            font-size: 1.4rem;
            font-weight: 500;
            letter-spacing: -.01em;
        }
        body.theme-app .card {
            background: #fff;
            border: 1px solid var(--sand);
            border-radius: var(--radius-lg);
            padding: 1.75rem;
            box-shadow: var(--shadow-1);
            margin-bottom: 1.25rem;
        }
        /* Empty-State — geteilte Komponente für „noch nichts da"-Flächen.
           Markup:  <div class="empty-state">
                       <h2>Headline</h2>
                       <p>Erklärtext</p>
                       <a href="..." class="primary">CTA</a>
                    </div> */
        body.theme-app .empty-state {
            background: #fff;
            border: 2px dashed var(--petrolhell-35);
            border-radius: var(--radius-lg);
            padding: var(--space-7) var(--space-6);
            text-align: center;
            max-width: 36rem;
            margin: 0 auto;
        }
        body.theme-app .empty-state h2 {
            margin: 0 0 .5rem;
            font-size: 1.2rem;
            font-weight: 500;
        }
        body.theme-app .empty-state p {
            margin: 0 auto 1.25rem;
            max-width: 30rem;
            color: var(--text-muted);
            font-size: .95rem;
            line-height: 1.55;
        }
        body.theme-app .empty-state .meta {
            font-size: .85rem;
            margin-top: 1rem;
            color: var(--text-muted);
        }
        /* Sub-Card — kleinere Card-in-Card-Variante für Helfer-Boxen, z. B.
           „Aus Website entwerfen" / „Aus Beispielbildern entwerfen" auf der
           Briefing-Seite. Sandstein-Outline, Pergament-Bg. */
        body.theme-app .sub-card {
            background: var(--stein);
            border: 1px solid var(--petrolhell-35);
            border-radius: 12px;
            padding: var(--space-4) 1.1rem;
        }
        body.theme-app .sub-card .sub-card-title {
            margin: 0 0 .15rem;
            font-size: .9rem;
            font-weight: 600;
            color: var(--petrol);
            display: flex;
            align-items: center;
            gap: .4rem;
            flex-wrap: wrap;
        }
        body.theme-app .sub-card .sub-card-hint {
            margin: 0 0 .65rem;
            font-size: .75rem;
            color: var(--text-muted);
        }
        body.theme-app .sub-card .sub-card-meta {
            margin: .5rem 0 0;
            font-size: .7rem;
            color: var(--text-muted);
        }
        /* Geteiltes Tile-Grid — verwendet auf Dashboard („Weitere Posts") und
           `/app/posts`. 4:5-Tiles in Auto-Fill-Grid mit Hover-Lift und Lösch-x. */
        body.theme-app .tile-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
            gap: 1.25rem; /* zwischen --space-5 und --space-4, bleibt fix */
        }
        body.theme-app .tile-grid .tile {
            position: relative;
            background: #fff;
            border-radius: 14px;
            overflow: hidden;
            box-shadow: 0 4px 14px -8px rgba(23, 69, 87, .15);
            transition: transform .15s ease, box-shadow .2s ease;
        }
        body.theme-app .tile-grid .tile:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 24px -10px rgba(23, 69, 87, .25);
        }
        body.theme-app .tile-grid .tile a.tile-link {
            display: block;
            text-decoration: none;
            color: inherit;
        }
        body.theme-app .tile-grid .tile .img-wrap {
            aspect-ratio: 4 / 5;
            background: var(--sand);
            position: relative;
            overflow: hidden;
        }
        body.theme-app .tile-grid .tile .img-wrap img {
            width: 100%; height: 100%;
            object-fit: cover;
            display: block;
        }
        /* Karussell-Cover ist 1:1 (Feed) — eigene Box, damit es nicht in 4:5 schief
           beschnitten wird. Plus Badge mit Ebenen-Icon + Slide-Zahl. */
        body.theme-app .tile-grid .tile .img-wrap.is-carousel {
            aspect-ratio: 1 / 1;
        }
        body.theme-app .tile-grid .tile .carousel-badge {
            position: absolute; bottom: .5rem; right: .5rem; z-index: 3;
            display: inline-flex; align-items: center; gap: .35rem;
            padding: .22rem .5rem; border-radius: 999px;
            background: rgba(23, 69, 87, .8); color: #fff;
            font-size: .72rem; font-weight: 600; line-height: 1;
        }
        body.theme-app .tile-grid .tile .carousel-badge .cb-stack {
            position: relative; width: .85rem; height: .85rem; flex: 0 0 auto;
        }
        body.theme-app .tile-grid .tile .carousel-badge .cb-stack::before,
        body.theme-app .tile-grid .tile .carousel-badge .cb-stack::after {
            content: ''; position: absolute; width: .52rem; height: .52rem;
            border: 1.5px solid #fff; border-radius: 2px;
        }
        body.theme-app .tile-grid .tile .carousel-badge .cb-stack::before {
            top: 0; left: 0; background: rgba(255, 255, 255, .22);
        }
        body.theme-app .tile-grid .tile .carousel-badge .cb-stack::after {
            bottom: 0; right: 0; background: var(--petrol);
        }
        body.theme-app .tile-grid .tile .img-wrap.placeholder {
            display: flex; align-items: center; justify-content: center;
            background: var(--stein);
            color: var(--text-muted);
            font-size: .85rem;
            padding: 1rem;
            text-align: center;
        }
        body.theme-app .tile-grid .tile .body {
            padding: .85rem 1rem 1rem;
        }
        body.theme-app .tile-grid .tile .briefing-excerpt {
            font-size: .9rem;
            color: var(--petrol);
            line-height: 1.4;
            margin: 0 0 .35rem;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }
        body.theme-app .tile-grid .tile .meta {
            font-size: .75rem;
            color: var(--text-muted);
            margin: 0;
        }
        /* ⚠️ Archivieren/Löschen liegen ÜBER dem Kachel-Link (`z-index: 2`). Sie waren
           bis 2026-08 nur `opacity: 0` — unsichtbar, aber voll anklickbar. Auf Touch
           gibt es kein Hover, also blieben sie unsichtbar und ein Tipp auf die obere
           rechte Kachelecke archivierte den Post wortlos (Löschen fragt immerhin nach).
           Zwei Regeln, die zusammengehören:
             1. Verstecken NUR dort, wo ein Zeiger schweben kann.
             2. Im versteckten Zustand `pointer-events: none` — ein unsichtbares Ziel
                darf nie treffbar sein, auch nicht am Rechner. */
        body.theme-app .tile-grid .tile .tile-actions {
            position: absolute;
            top: .5rem;
            right: .5rem;
            margin: 0;
            display: flex;
            gap: .5rem;
            z-index: 2;
        }
        @media (hover: hover) and (pointer: fine) {
            body.theme-app .tile-grid .tile .tile-actions {
                gap: .35rem;
                opacity: 0;
                pointer-events: none;
                transform: scale(.85);
                transition: opacity .15s, transform .15s;
            }
            body.theme-app .tile-grid .tile:hover .tile-actions,
            body.theme-app .tile-grid .tile:focus-within .tile-actions {
                opacity: 1;
                pointer-events: auto;
                transform: scale(1);
            }
        }
        body.theme-app .tile-grid .tile .delete-btn,
        body.theme-app .tile-grid .tile .archive-btn {
            background: rgba(23, 69, 87, .85);
            color: var(--stein);
            border: none;
            width: 28px;
            height: 28px;
            border-radius: 50%;
            font-size: 1rem;
            line-height: 1;
            cursor: pointer;
            padding: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 10px -4px rgba(0, 0, 0, .3);
            transition: background .15s, transform .1s;
        }
        /* Archivieren/Zurückholen ist neutral (kein Warn-Rot wie Löschen) —
           Sandstein-Hover signalisiert die reversible Ablage-Aktion. */
        body.theme-app .tile-grid .tile .archive-btn { font-size: .8rem; }
        body.theme-app .tile-grid .tile .archive-btn:hover { background: var(--petrolhell); }
        body.theme-app .tile-grid .tile .delete-btn:hover { background: var(--status-error-fg); }
        body.theme-app .tile-grid .tile .delete-btn:active,
        body.theme-app .tile-grid .tile .archive-btn:active { transform: scale(.92); }
        /* 28px sind mit dem Finger kein Ziel — auf Touch gilt 44px als Untergrenze
           (Apple HIG, Material). Am Rechner bleibt es klein: dort zielt eine Maus. */
        @media (pointer: coarse) {
            body.theme-app .tile-grid .tile .delete-btn,
            body.theme-app .tile-grid .tile .archive-btn {
                width: 44px;
                height: 44px;
                font-size: 1.25rem;
            }
            body.theme-app .tile-grid .tile .archive-btn { font-size: 1.05rem; }
        }
        /* ⚠️ **Beide Themen, und das ist der Fix vom 27.08.2026.**

           `templates/app_layout.php` wird von ZWEI Controllern gerendert: von
           `AppLayoutController` unter `/app/layout` und von `AdminOpsController` unter
           `/admin/tenants/{slug}/layout`. Das Thema haengt aber nicht an der Seite,
           sondern an der URL (`layout.php`: `/app…` → `theme-app`, sonst `theme-admin`).

           Damit galten 47 Regeln nur auf der Kundenseite. Im Admin blieb die Karte
           weiss, waehrend das Markup darin seine helle Tinte behielt — Set-Name,
           Beschreibung, beide Umschalt-Pfeile und der Erklaerabsatz standen weiss auf
           weiss. Es sieht nicht kaputt aus, sondern LEER; der Operator findet die
           Pfeile nicht. Gemessen: 6 von 7 Elementen zwischen 1,07 und 1,12 : 1.

           **`:is()` statt Praefix weglassen.** `body:is(.theme-app, .theme-admin)` zaehlt
           genauso viel wie `body.theme-app` — (0,2,x). Ein blosses `.card-inverse` waere
           eine Klasse weniger, und genau diese Spezifitaet entscheidet zwei bekannte
           Kaempfe: `.card-inverse p` gegen `.alert`, und die Galerie-Erklaertexte (0,3,0)
           gegen `.card-inverse p`. Die Reichweite waechst, die Staerke bleibt.

           Invertierte Card-Variante — Marketing-Homepage-Look („Das Herzstueck"):
           Tiefenblau-Hintergrund mit Pergament-Schrift, Sandstein als Akzent.
           Bewusst dezent: schmaleres Padding, weicher Sandstein-Rand. */
        body:is(.theme-app, .theme-admin) .card-inverse {
            background: var(--petrol);
            color: var(--stein);
            /* Dekorative Kante, kein Bedienelement — deshalb bewusst stein-25 und
               NICHT --border-on-dark: der traegt seit 02.09.2026 die 3:1 fuer
               Knopfrahmen (stein-50) und waere hier ein heller Saum. */
            border: 1px solid var(--stein-25);
            box-shadow: 0 6px 24px -10px rgba(23, 69, 87, .35);
            padding: 1.5rem 1.75rem;
        }
        body:is(.theme-app, .theme-admin) .card-inverse h1,
        body:is(.theme-app, .theme-admin) .card-inverse h2,
        body:is(.theme-app, .theme-admin) .card-inverse h3 {
            color: var(--stein);
            font-family: var(--display-font, Georgia, serif);
            font-weight: 500;
            letter-spacing: -.005em;
            margin-top: 0;
        }
        /* Globaler Sandstein-Akzent — nutzbar in jeder Headline.
           !important, weil `h1, h2, h3 { color: tiefenblau; }` (Zeile ~105) sonst
           in manchen Browsern via `currentColor`-Inheritance gewinnen kann. */
        body.theme-app .accent,
        body.theme-app h1 .accent,
        body.theme-app h2 .accent,
        body.theme-app h3 .accent { color: var(--petrolhell) !important; }
        /* ⚠️ Ausnahme fuer getoente Flaechen. Petrolhell traegt auf dem Seitengrund
           (5,07), aber auf `--accent-soft` — der eigenen Farbe in 18 % — nur 3,98.
           Die Hervorhebung waere dort schlechter lesbar als der Text um sie herum,
           also genau verkehrt herum. Auf Petrol gedreht sind es rund 8.
           Der Attribut-Selektor greift die Hinweiskarten, die ihre Flaeche inline
           mitbringen und keine eigene Klasse haben; `!important` ist Pflicht, weil
           die Regel darueber selbst eines traegt. */
        body.theme-app [style*="accent-soft"] .accent { color: var(--petrol) !important; }
        /* Back-Link in Page-Header — dezenter Sandstein-Hover. */
        body.theme-app a.page-back {
            display: inline-flex;
            align-items: center;
            gap: .25rem;
            color: var(--petrol);
            text-decoration: none;
            font-size: .9rem;
            transition: color .15s, transform .15s;
        }
        body.theme-app a.page-back:hover {
            color: var(--petrolhell);
            transform: translateX(-2px);
        }
        /* Der Akzent in der dunklen Karte ist Apricot, nicht Petrolhell: Petrolhell
           auf Petrol sind 1,83 — die Hervorhebung war dort faktisch unsichtbar.
           `!important` ist hier PFLICHT, nicht Bequemlichkeit: die globale
           `.accent`-Regel oben traegt selbst eines (gegen currentColor-Vererbung
           aus h1/h2/h3) und schluege diese Regel sonst trotz hoeherer Spezifitaet.
           Ohne das kam die Aenderung im Browser nie an. */
        body:is(.theme-app, .theme-admin) .card-inverse h2 .accent,
        body:is(.theme-app, .theme-admin) .card-inverse h3 .accent,
        body:is(.theme-app, .theme-admin) .card-inverse .accent {
            color: var(--apricot) !important;
        }
        body:is(.theme-app, .theme-admin) .card-inverse p { color: rgba(244, 242, 239, .85); }
        body:is(.theme-app, .theme-admin) .card-inverse .muted { color: rgba(244, 242, 239, .7); }
        /* Links tragen in der dunklen Karte Apricot (5,88) — Petrolhell lag bei 1,83
           und war als Link nicht erkennbar. Unterstreichung mitgezogen: die Farbe
           allein transportiert nichts. */
        body:is(.theme-app, .theme-admin) .card-inverse a {
            color: var(--apricot);
            text-decoration-color: var(--apricot);
            text-underline-offset: 3px;
        }
        body:is(.theme-app, .theme-admin) .card-inverse a:hover { color: var(--stein); }
        body:is(.theme-app, .theme-admin) .card-inverse strong { color: var(--stein); font-weight: 600; }
        body:is(.theme-app, .theme-admin) .card-inverse hr {
            border: 0;
            /* dekorativer Trenner — stein-25, siehe Kartenkante oben */
            border-top: 1px solid var(--stein-25);
            margin: 1rem 0;
        }
        /* === Hauptaktion in der dunklen Karte: Apricot ===
           Bis 02.09.2026 stand hier Petrolhell mit Petrol-Schrift. Der Kommentar
           sprach von „auf Sandstein flippen" — das stimmte, solange Sandstein ein
           heller Ton war; seit dem Markenneustart ist `--sandstein` nur noch ein
           Alias auf Petrolhell, und aus dem Kontrast-Flip wurde Petrol auf Petrol:
           1,83 fuer die Flaeche UND 1,83 fuer die Beschriftung.
           Apricot ist DER Akzent der Marke und traegt hier 5,88 gegen die Karte,
           die Night-Schrift 9,00 gegen den Knopf. Auf dunklem Grund braucht Apricot
           keine Kontur — das Verbot dazu gilt gegen den hellen Seitengrund. */
        body:is(.theme-app, .theme-admin) .card-inverse button.primary,
        body:is(.theme-app, .theme-admin) .card-inverse .btn-primary,
        body:is(.theme-app, .theme-admin) .card-inverse .btn,
        body:is(.theme-app, .theme-admin) .card-inverse a.btn,
        body:is(.theme-app, .theme-admin) .card-inverse button.btn,
        body:is(.theme-app, .theme-admin) .card-inverse a.btn-pill-primary,
        body:is(.theme-app, .theme-admin) .card-inverse button.btn-pill-primary {
            background: var(--apricot);
            color: var(--night);
            border-color: var(--apricot);
            font-weight: 600;
        }
        body:is(.theme-app, .theme-admin) .card-inverse button.primary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse .btn-primary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse .btn:hover,
        body:is(.theme-app, .theme-admin) .card-inverse a.btn:hover,
        body:is(.theme-app, .theme-admin) .card-inverse button.btn:hover,
        body:is(.theme-app, .theme-admin) .card-inverse a.btn-pill-primary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse button.btn-pill-primary:hover {
            /* hellt auf statt abzudunkeln — der Knopf steht auf Dunkel */
            background: var(--apricot-hell);
            color: var(--night);
            border-color: var(--apricot-hell);
        }
        /* Secondary in invertierten Cards — Pergament-Outline, transparente Mitte.
           Rahmen ueber --border-on-dark (stein-50, 3,60): die frueheren 35 % lagen
           mit 2,52 unter der 3:1-Schwelle fuer Bedienelemente. */
        body:is(.theme-app, .theme-admin) .card-inverse .secondary,
        body:is(.theme-app, .theme-admin) .card-inverse a.button-secondary,
        body:is(.theme-app, .theme-admin) .card-inverse button.button-secondary,
        body:is(.theme-app, .theme-admin) .card-inverse .btn-pill-secondary,
        body:is(.theme-app, .theme-admin) .card-inverse a.btn-pill-secondary,
        body:is(.theme-app, .theme-admin) .card-inverse button.btn-pill-secondary,
        body:is(.theme-app, .theme-admin) .card-inverse .btn-sekundaer {
            background: transparent;
            color: var(--stein);
            border-color: var(--border-on-dark);
        }
        body:is(.theme-app, .theme-admin) .card-inverse .secondary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse a.button-secondary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse button.button-secondary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse .btn-pill-secondary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse a.btn-pill-secondary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse button.btn-pill-secondary:hover,
        body:is(.theme-app, .theme-admin) .card-inverse .btn-sekundaer:hover {
            background: var(--surface-on-dark);
            border-color: var(--stein);
        }
        /* `.muted`-Labels (z. B. „Erstellt …") in der invertierten Card lesbar halten */
        body:is(.theme-app, .theme-admin) .card-inverse label { color: var(--stein); }
        /* Verschachtelte helle Kacheln (z. B. `.layout-card`) sollen ihre eigenen
           dunklen Texte behalten — sonst werden sie unsichtbar.

           ⚠️ **Die lebende Galerie-Kachel ist davon ausgenommen (27.08.2026).** Das `*`
           reichte bis in das Blatt hinein und faerbte JEDEN Text darin anthrazit — auch
           den, der auf der dunklen Traegerflaeche steht. Ergebnis: dunkle Schrift auf
           dunklem Grund, und zwar NUR auf `/app/layout`, weil die Galerie dort in einer
           invertierten Card sitzt und auf `/app/generate` nicht. Dieselben 23 Layouts
           sahen auf den beiden Seiten verschieden aus; gemessen an der Kopfzeile:
           `rgb(26,31,36)` gegen `rgb(244,242,239)`.

           Die Kachel ist kein Stueck App-Oberflaeche, sondern eine Vorschau des
           fertigen Blattes. Sie fuehrt ihr eigenes Farbsystem (`--traeger`,
           `--auf-traeger`, …), und in das darf die App-Oberflaeche nicht
           hineinregieren — sonst zeigt die Vorschau etwas anderes als der Bake.

           **Ausgenommen ist die ganze Galerie, nicht nur das Blatt.** Der erste Anlauf
           nahm `.kachel` und deren Nachfahren heraus — das reichte nicht: Auch die
           Bildunterschrift und der Bandhinweis stehen in der Karte, und sie bekamen
           weiter das opake Anthrazit statt ihrer eigenen, gedaempften Farbe. Ergebnis
           waere derselbe Fehler in klein gewesen: 16,6 zu 1 Kontrast auf `/app/layout`
           gegen 3,8 zu 1 auf `/app/generate`, also wieder zwei Anblicke derselben Sache.

           `.gal` bringt in `layout-galerie.css` fuer jeden ihrer Texte eine eigene Regel
           mit. Wer dort etwas ergaenzt, faerbt es dort — nicht hier. */
        body:is(.theme-app, .theme-admin) .card-inverse .layout-card:not(.gal *),
        body:is(.theme-app, .theme-admin) .card-inverse .layout-card:not(.gal *) * {
            color: var(--anthrazit);
        }
        body:is(.theme-app, .theme-admin) .card-inverse .layout-card .muted {
            color: var(--text-muted);
        }
        body:is(.theme-app, .theme-admin) .card-inverse .layout-card a,
        body:is(.theme-app, .theme-admin) .card-inverse .layout-card .button-secondary {
            color: var(--petrol);
        }
        /* === Drei Button-Familien ===
           Primary (filled pill, Hauptaktion), Secondary (outline pill, Neben-
           aktion), Subtle (plain link). Alte Klassennamen (`btn`, `primary`,
           `button-secondary`, `btn-pill-primary`, `btn-pill-secondary`) sind
           Aliase auf diese drei — keine Regressionen in bestehendem Markup. */
        body.theme-app button.primary,
        body.theme-app .btn,
        body.theme-app a.btn-pill-primary,
        body.theme-app button.btn-pill-primary {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: .35rem;
            background: var(--petrol);
            color: var(--stein);
            border: 1px solid var(--petrol);
            padding: .65rem 1.4rem;
            border-radius: 999px;
            font-weight: 500;
            font-size: .95rem;
            font-family: inherit;
            text-decoration: none;
            cursor: pointer;
            box-shadow: 0 4px 14px -6px rgba(23, 69, 87, .25);
            transition: background .15s, border-color .15s, color .15s, transform .1s;
        }
        body.theme-app button.primary:hover,
        body.theme-app .btn:hover,
        body.theme-app a.btn-pill-primary:hover,
        body.theme-app button.btn-pill-primary:hover {
            background: var(--anthrazit);
            border-color: var(--anthrazit);
        }
        body.theme-app button.primary:active,
        body.theme-app .btn:active,
        body.theme-app a.btn-pill-primary:active,
        body.theme-app button.btn-pill-primary:active {
            transform: translateY(1px);
        }
        /* Secondary — Outline-Pill, gleiche Form, transparente Mitte. */
        body.theme-app .secondary,
        body.theme-app a.button-secondary,
        body.theme-app button.button-secondary,
        body.theme-app .btn-pill-secondary,
        body.theme-app a.btn-pill-secondary,
        body.theme-app button.btn-pill-secondary,
        body.theme-app .btn-sekundaer {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: .35rem;
            background: transparent;
            color: var(--petrol);
            /* --border-button (petrol-65): der Umriss-Knopf lebt allein von seiner
               Kante. Bis 02.09.2026 stand hier petrol-25 = 1,55 gegen Stein und 1,60
               gegen die weisse Karte — der Knopf hatte faktisch keine Kontur, nur
               Text. Jetzt 3,68 / 3,88, und damit ueber der 3:1 aus WCAG 1.4.11,
               ohne so laut zu werden wie die gefuellte Hauptaktion. */
            border: 1px solid var(--border-button);
            padding: .65rem 1.4rem;
            border-radius: 999px;
            font-weight: 500;
            font-size: .95rem;
            font-family: inherit;
            text-decoration: none;
            cursor: pointer;
            transition: background .15s, border-color .15s;
        }
        body.theme-app .secondary:hover,
        body.theme-app a.button-secondary:hover,
        body.theme-app button.button-secondary:hover,
        body.theme-app .btn-pill-secondary:hover,
        body.theme-app a.btn-pill-secondary:hover,
        body.theme-app button.btn-pill-secondary:hover,
        body.theme-app .btn-sekundaer:hover {
            /* Die Hover-Flaeche lag bei 4 % (1,07) und war praktisch nicht
               wahrnehmbar; der Knopf reagierte sichtbar nur ueber die Kante. */
            background: var(--petrol-08);
            border-color: var(--petrol);
        }
        /* Die kleine Groesse der Familie — der einzige Unterschied zur Pille.
           Muss NACH der Familienregel stehen, die sonst ihr grosses Mass
           durchsetzt (gleiche Spezifitaet, spaeter gewinnt). */
        body.theme-app .btn-sekundaer {
            padding: .35rem .85rem;
            font-size: .82rem;
        }
        /* Akzent-Knopf (Apricot) — auf HELLEM Grund, deshalb mit Kontur in der
           Textfarbe: die helle Apricot-Flaeche grenzt sich vom Seitengrund nicht ab
           (1,62, WCAG 1.4.11), die Kante uebernimmt das. Der Hover ging bis
           02.09.2026 auf --warnung; Amber ist CTA und KEINE Warnfarbe, deshalb
           jetzt die eigene Aufhell-Stufe. */
        body.theme-app .btn-honig,
        body.theme-app button.btn-honig {
            background: var(--apricot);
            color: var(--night);
            border: 1px solid var(--night);
        }
        body.theme-app .btn-honig:hover {
            background: var(--apricot-hell);
            color: var(--night);
        }
        body.theme-app input[type=email],
        body.theme-app input[type=text],
        body.theme-app input[type=url],
        body.theme-app input[type=tel],
        body.theme-app input[type=number],
        body.theme-app input[type=password],
        body.theme-app textarea,
        body.theme-app select {
            /* Rahmen bedienbarer Elemente: --border-field (Grau, 3,34 auf Stein).
               NICHT --rule/Sand — das sind nur 1,16 und damit als Feldkante
               praktisch unsichtbar. WCAG 1.4.11 verlangt hier 3:1. */
            border: 1px solid var(--border-field);
            border-radius: 10px;
            padding: .7rem .9rem;
            background: #fff;
            transition: border-color .15s, box-shadow .15s;
        }
        /* Der Ring kommt aus der globalen :focus-visible-Regel oben.
           Hier nur noch die Kante kraeftiger, damit das aktive Feld auch
           bei Mausbedienung erkennbar bleibt. Kein `outline: none` — das
           war bis 2026-08-02 die Ursache fuer den unsichtbaren Fokus. */
        body.theme-app input:focus,
        body.theme-app textarea:focus,
        body.theme-app select:focus {
            border-color: var(--petrol);
        }
        body.theme-app .pill {
            padding: .2rem .65rem;
            font-weight: 500;
        }
        /* Nur die Form, NICHT die Farbe: Die Meldungsfarben stehen in der
           Basisregel weiter oben. Bis 2026-08-02 setzte dieser Block ein
           pauschales `background: var(--status-warning-bg)` — dadurch trug
           die FEHLERmeldung in der Kunden-App die Warnfarbe, und Erfolg
           bekam eine Koralle-Kante. Beides faellt statisch nicht auf, nur
           im gerenderten Browser. */
        /* ⚠️ `border-left-width: 4px` ist hier weg (24.08.2026). Er stammt aus der Zeit
           des 3-px-Balkens links; seit die Meldung einen duennen Rand ringsum traegt,
           haette er als einzelne dicke Kante ausgesehen. Der Radius bleibt: In der App
           sind die Ecken durchgehend weicher als im Admin-Bereich. */
        body.theme-app .alert {
            border-radius: 10px;
        }
        body.theme-app .muted {
            color: var(--text-muted);
        }
        /* Dezenter Hintergrund-Akzent für /app */
        /* Hintergrund-„Sonnen" wie auf der Marketing-Homepage und im Dashboard-Hero —
           zwei warm getönte, weich verlaufende Blobs oben links/rechts, ein dritter
           sandiger weiter unten. Werte angeglichen an `.dash-hero .hero-blob`. */
        body.theme-app::before {
            content: "";
            position: fixed;
            top: -160px;
            left: -160px;
            width: 480px;
            height: 480px;
            border-radius: 50%;
            background: rgba(255, 178, 122, .30);
            opacity: .5;
            filter: blur(64px);
            pointer-events: none;
            z-index: 0;
        }
        body.theme-app::after {
            content: "";
            position: fixed;
            top: 100px;
            right: -200px;
            width: 560px;
            height: 560px;
            border-radius: 50%;
            background: rgba(38, 111, 135, .25);
            opacity: .5;
            filter: blur(64px);
            pointer-events: none;
            z-index: 0;
        }
        /* Dritter, sandiger Blob unten — wird über ein eigenes festes Element
           gerendert, weil ::before und ::after schon vergeben sind. */
        body.theme-app .app-bg-blob-3 {
            content: "";
            position: fixed;
            bottom: -100px;
            left: 30%;
            width: 400px;
            height: 400px;
            border-radius: 50%;
            background: rgba(230, 226, 219, .60);
            opacity: .5;
            filter: blur(64px);
            pointer-events: none;
            z-index: 0;
        }
        /* Auf dem Dashboard übernimmt `.dash-hero` die Sonnen-Akzente full-bleed —
           dort blenden wir die Body-Blobs aus, damit sie sich nicht doppeln. */
        body.theme-app.has-dash-hero::before,
        body.theme-app.has-dash-hero::after,
        body.theme-app.has-dash-hero .app-bg-blob-3 { display: none; }
        body.theme-app header.app,
        body.theme-app main,
        body.theme-app footer.app {
            position: relative;
            z-index: 1;
        }
        /* Footer im App-Theme — dunkles Band wie Homepage */
        body.theme-app footer.app {
            border-top: none;
            background: var(--petrol);
            color: rgba(244, 242, 239, .7);
            padding: 2.5rem 1.5rem;
            font-size: .9rem;
            margin-top: 4rem;
        }
        body.theme-app footer.app .footer-inner {
            max-width: 64rem;
            margin: 0 auto;
            display: flex;
            justify-content: space-between;
            align-items: center;
            gap: 1.5rem;
            flex-wrap: wrap;
        }
        /* Der Footer bleibt dunkel — dort bringt die Wortmarke ihre SCHUTZFLÄCHE mit,
           statt die Farbe zu wechseln. Genau wie im Footer der Homepage: Die Marke
           selbst ist identisch zum Header, nur der Träger ist ein anderer. Wer die
           Fläche entfernt und stattdessen helle Buchstaben setzt, hat wieder zwei
           Logofassungen. Siehe Memory `sairmo-wortmarke`. */
        body.theme-app footer.app .footer-brand {
            display: inline-flex;
            align-items: baseline;
            background: var(--stein);
            padding: .3rem .6rem;
            font-family: 'Archivo', system-ui, sans-serif;
            font-size: 1.15rem;
            font-weight: 900;
            letter-spacing: -.035em;
            color: var(--petrolhell);
        }
        body.theme-app footer.app .footer-brand strong {
            color: var(--apricot);
            font-weight: inherit;
        }
        body.theme-app footer.app .footer-claim {
            font-family: var(--accent-font);
            font-style: italic;
            color: rgba(244, 242, 239, .65);
        }

        /* Set-Switcher — geteilt zwischen /app/layout und /app/generate.
           Der Hover stand bis 02.09.2026 nur im <style>-Block von app_layout.php;
           auf /app/generate blieben dieselben Knoepfe deshalb stumm. `!important`,
           weil die Knoepfe ihre Flaeche als Inline-`style` mitbringen. */
        .set-switcher button:hover { background: var(--stein-25) !important; }
        /* Layout-Vorlagen-Galerie (geteilt zwischen Layout-Editor und Generate-Form) */
        .layout-galerie {
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            gap: 1rem;
            margin: 1rem 0 1.5rem;
        }
        @media (max-width: 900px) {
            .layout-galerie { grid-template-columns: repeat(3, 1fr); }
        }
        @media (max-width: 560px) {
            .layout-galerie { grid-template-columns: repeat(2, 1fr); }
        }
        .layout-card {
            background: #fff;
            border: 2px solid var(--sand);
            border-radius: 8px;
            padding: .5rem;
            cursor: pointer;
            transition: border-color .15s, transform .15s, box-shadow .15s;
            position: relative;
        }
        .layout-card:hover,
        .layout-card:focus-within { z-index: 200; }
        .layout-card:hover { border-color: var(--petrolhell); }
        .layout-card.active {
            border: 4px solid var(--petrolhell);
            padding: calc(.5rem - 2px); /* gleicht 2px-Border-Sprung aus, damit Tile nicht springt */
            box-shadow: 0 0 0 2px var(--petrolhell-25);
        }
        .layout-card[disabled] { cursor: not-allowed; opacity: .5; }
        .preview {
            position: relative;
            width: 100%;
            aspect-ratio: 1 / 1;
            background: var(--sand);
            border-radius: 4px;
            overflow: hidden;
        }
        .preview.portrait { aspect-ratio: 4 / 5; }
        /* ⚠️ **Der direkte Nachfahre — sonst greift die Bildunterschrift in die Kachel.**

           `.layout-card .name` zaehlt (0,2,0) und trifft JEDES `.name` unter der Karte.
           Seit die Karte eine lebende Kachel enthaelt, ist darunter auch das `.name`,
           das `kante-spalte` INNEN fuer seinen Untertext benutzt. `text-align` wird
           ausserdem VERERBT und erreicht damit jede Zone des Blattes.

           Gemessen am 27.08.2026: In der Kachel stand der Untertext zentriert, im
           gebackenen Post linksbuendig — dort ist diese Datei gar nicht geladen.

           Die Beschriftung ist in allen drei Faellen ein direktes Kind der Karte
           (`<div class="name">` bzw. `<figcaption class="name">`). */
        .layout-card > .name {
            font-size: .85rem;
            text-align: center;
            margin-top: .4rem;
            color: var(--anthrazit);
        }
        .preview .preview-photo { fill: var(--kiesel); }
        .preview .preview-primary { fill: var(--petrol); }
        .preview .preview-primary-fade { fill: var(--petrol); opacity: .55; }
        .preview .preview-accent { fill: var(--petrolhell); }
        .preview .preview-background { fill: var(--stein); }
        .preview .preview-onprimary { fill: var(--stein); }

        /* Logo-Positionen — 3×2-Raster als kompaktes Viereck. Geteilt zwischen
           Layout-Editor und Generate-Form. Drei Zustände:
             - .is-active:   gewählt (Tiefenblau, Pergament-Text)
             - .is-possible: in der Vorlage erlaubt, aber nicht aktiv (Sandstein)
             - .is-disabled: nicht erlaubt (ausgegraut, nicht klickbar) */
        .logo-positions {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            grid-template-rows: repeat(3, 1fr);
            gap: .25rem;
            max-width: 13rem;
        }
        .logo-positions label {
            display: flex; align-items: center; justify-content: center;
            /* Wählbare Kachel, also ein Bedienelement — Sand traegt hier nicht (1,29). */
            background: #fff; border: 1px solid var(--border-button); border-radius: 4px;
            padding: .9rem .4rem; font-size: .8rem; text-align: center;
            line-height: 1.15; white-space: nowrap;
            transition: background .12s, color .12s, border-color .12s, opacity .12s;
        }
        .logo-positions input[type="radio"] { display: none; }
        .logo-positions label.is-possible {
            background: var(--sand); /* dezenter Sandstein-Tint (35% Sandstein auf Pergament) */
            color: var(--petrol);
            border-color: var(--sand);
            cursor: pointer;
        }
        .logo-positions label.is-possible:hover {
            background: var(--kiesel); /* etwas intensiver beim Hover, weiterhin gedeckt */
        }
        .logo-positions label.is-active {
            background: var(--petrol);
            color: var(--stein);
            border: 2px solid var(--petrolhell);
            padding: calc(.9rem - 1px) calc(.4rem - 1px); /* gleicht 2px-Border aus, sonst springt Layout */
            font-weight: 600;
            cursor: pointer;
        }
        .logo-positions label.is-disabled {
            background: var(--stein);
            color: rgba(23, 69, 87, 0.35);
            border-color: var(--sand);
            cursor: not-allowed;
            opacity: .6;
        }
        .logo-positions label[data-pos="top-left"]      { grid-area: 1 / 1; }
        .logo-positions label[data-pos="top-center"]    { grid-area: 1 / 2; }
        .logo-positions label[data-pos="top-right"]     { grid-area: 1 / 3; }
        .logo-positions label[data-pos="middle-left"]   { grid-area: 2 / 1; }
        .logo-positions label[data-pos="middle-center"] { grid-area: 2 / 2; }
        .logo-positions label[data-pos="middle-right"]  { grid-area: 2 / 3; }
        .logo-positions label[data-pos="bottom-left"]   { grid-area: 3 / 1; }
        .logo-positions label[data-pos="bottom-center"] { grid-area: 3 / 2; }
        .logo-positions label[data-pos="bottom-right"]  { grid-area: 3 / 3; }

        /* Confirm-Modal */
        .confirm-backdrop {
            position: fixed; inset: 0;
            background: rgba(23, 69, 87, 0.6);
            display: none;
            align-items: center;
            justify-content: center;
            z-index: 100;
            padding: 1.5rem;
            /* Ohne `contain` reicht eine Wischgeste im Dialog an die Seite dahinter
               durch (Scroll-Chaining) — auf Touch besonders stoerend, weil man beim
               Lesen einer Rueckfrage die Seite darunter verschiebt. Das native
               <dialog> braeuchte das nicht; diese Dialoge sind Eigenbau. */
            overscroll-behavior: contain;
            /* Der Dialog kann laenger sein als ein Handy-Schirm (Upgrade-Hinweis,
               Sitzungsende). Ohne eigenes Scrollen waere er dort abgeschnitten. */
            overflow-y: auto;
            /* `--vv-height` setzt app.js aus `visualViewport` — die Hoehe, die bei
               ausgefahrener Tastatur wirklich sichtbar ist. Ohne die Begrenzung
               reicht das fixierte Overlay unter die Tastatur, und die Felder dort
               sind weder sicht- noch erreichbar. Fallback fuer Browser ohne
               visualViewport: die volle dynamische Hoehe. */
            max-height: var(--vv-height, 100dvh);
        }
        .confirm-backdrop.is-open { display: flex; }
        .confirm-dialog {
            background: var(--stein);
            border: 1px solid var(--sand);
            border-radius: 8px;
            box-shadow: 0 16px 48px rgba(23, 69, 87, 0.25);
            max-width: 26rem;
            width: 100%;
            padding: 1.1rem 1.75rem 1.5rem;
            font-family: inherit;
        }
        .confirm-dialog h2 {
            margin: 0 0 .6rem;
            font-size: 1.15rem;
        }
        .confirm-dialog p {
            margin: 0 0 1.25rem;
            color: var(--anthrazit);
            line-height: 1.45;
        }
        .confirm-dialog .actions {
            display: flex;
            gap: .6rem;
            justify-content: flex-start;
            flex-wrap: wrap;
        }
        .confirm-dialog .actions .btn-cancel {
            background: transparent;
            color: var(--petrol);
            /* Sand traegt hier nicht (1,16 gegen den Stein-Dialog) — und dieser
               Knopf ist der Ausweg aus JEDEM Bestaetigungsdialog der App
               („Abbrechen", „Bleibt erstmal so", „Jetzt ausloggen"). Wer ihn
               nicht findet, klickt im Zweifel die zerstoerende Aktion. */
            border: 1px solid var(--border-button);
        }
        .confirm-dialog .actions .btn-cancel:hover {
            background: #fff;
            border-color: var(--petrol);
        }

        /* === Responsive Post-Seiten ===
           Zweispaltige Grids (Post-Detail: Bild|Aktionen,
           Layout-Varianten-Galerie) brechen auf Mobile auf eine Spalte um,
           statt in winzige Spalten gestaucht zu werden. Spalten-Definition hier
           statt inline, damit die Media-Query überhaupt greifen kann. */
        #post-actions { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
        .variant-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
        @media (max-width: 760px) {
            #post-actions { grid-template-columns: 1fr; }
        }
        @media (max-width: 560px) {
            .variant-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
        }

        /* === Greenfield Mobile-Baseline ===
           Verhindert „rechts abgeschnitten": Grid-/Flex-Kinder haben per Default
           min-width:auto und blähen ihre Spur auf die Inhaltsbreite (z. B. die
           natürliche Bildgröße) auf → horizontaler Überlauf. min-width:0 erlaubt
           Schrumpfen; Medien skalieren mit dem Container. */
        body.theme-app img,
        body.theme-app svg,
        body.theme-app video { max-width: 100%; }
        body.theme-app #post-actions > *,
        body.theme-app .variant-grid > * { min-width: 0; }
        /* Lange Wörter/URLs sprengen den Container nicht mehr. */
        body.theme-app main { overflow-wrap: anywhere; }

/* Button-Lade-Spinner (vormals eigener Inline-Block am Seitenende) */
    button.is-loading { position:relative; }
    button.is-loading::before {
        content:""; display:inline-block; width:.85em; height:.85em;
        margin-right:.5em; vertical-align:-.12em;
        border:2px solid currentColor; border-right-color:transparent;
        border-radius:50%; animation:sairmo-btn-spin .7s linear infinite;
    }
    /* Icon-Knöpfe (Pfeile, Häkchen): zu schmal für „Einen Moment …", deshalb setzt
       app.js dort einen leeren Text und der Spinner steht allein — dann gehört er
       in die Mitte und braucht keinen Abstand nach rechts. */
    button.is-loading-icon::before { margin-right:0; }
    @keyframes sairmo-btn-spin { to { transform:rotate(360deg); } }

/* --- Login-/Signup-Stage (2026-07: aus app_login.php extrahiert, gilt für Login, Signup, Signup-Sent) --- */
    .login-stage {
        position: relative;
        max-width: 28rem;
        margin: 2rem auto 0;
    }
    .login-stage h1 {
        font-size: 2.25rem;
        line-height: 1.1;
        font-weight: 500;
        letter-spacing: -.01em;
        text-align: center;
        margin: 0 0 .5rem;
    }
    .login-stage .lede {
        text-align: center;
        color: var(--text-muted);
        margin: 0 0 2rem;
    }
    .login-stage .login-card {
        background: #fff;
        border-radius: 20px;
        padding: 2rem 2rem 1.75rem;
        box-shadow: 0 24px 48px -20px rgba(23, 69, 87, .2),
                    0 4px 16px -4px rgba(23, 69, 87, .08);
        border: 1px solid var(--sand);
        position: relative;
    }
    .login-stage .tabs {
        display: flex;
        gap: .35rem;
        background: var(--sand);
        padding: .25rem;
        border-radius: 999px;
        margin-bottom: 1.5rem;
    }
    .login-stage .tab {
        flex: 1;
        padding: .5rem .75rem;
        text-align: center;
        font-size: .9rem;
        font-weight: 500;
        text-decoration: none;
        /* --text-body, nicht --text-muted: Der Track ist SAND, und Schiefer
           erreicht darauf nur 4,32. Der Unterschied zwischen aktiv und inaktiv
           traegt hier ohnehin die weisse Flaeche, nicht die Schriftfarbe. */
        color: var(--text-body);
        border-radius: 999px;
        transition: background .15s, color .15s;
    }
    .login-stage .tab:hover { color: var(--petrol); }
    .login-stage .tab.active {
        background: #fff;
        color: var(--petrol);
        box-shadow: 0 2px 6px -2px rgba(23, 69, 87, .15);
    }
    .login-stage form .btn { width: 100%; justify-content: center; }
    .login-stage .below {
        margin-top: 1.5rem;
        text-align: center;
        font-size: .9rem;
        color: var(--text-muted);
    }
    .login-stage .below a { color: rgba(23, 69, 87, .75); text-decoration: underline; text-underline-offset: 3px; }
    .login-stage .below a:hover { color: var(--petrol); }
    .login-stage .signup-hint {
        margin-top: 1.5rem;
        text-align: center;
        font-size: .92rem;
        color: var(--text-muted);
    }
    .login-stage .signup-hint a {
        color: var(--petrol);
        font-weight: 500;
        text-decoration: none;
    }
    .login-stage .signup-hint a:hover { text-decoration: underline; text-underline-offset: 3px; }

        /* ====================================================================
           HELLER Header (21.08.2026 — löst den Dark-Header vom 14.07. ab)
           Florians Entscheid beim Markenneustart: Der Balken wird hell, damit die
           Wortmarke dort in ihrer EINZIGEN Fassung steht — Buchstaben in der
           Zeichenfarbe, AI im Akzent, wie auf der Homepage. Vorher stand sie hier
           hell auf dunkel; das war eine zweite Fassung, und das AI setzte sich von
           den Nachbarbuchstaben nur mit 1,58 ab statt mit 3,21.

           ⚠️ DIE KANTE UNTEN IST PFLICHT, kein Zierrat. Der Balken ist Stein, die
           Seite darunter ist Stein — ohne sichtbare Linie verschwindet der Header
           beim Scrollen. Der Token --grau erreicht dagegen 3,34.

           Wie vorher gilt: Das hier färbt NUR den Balken. Die aufklappenden Karten
           (nav-dd-menu, Burger-Panel) sind eigene helle Flächen und bleiben
           unberührt — deshalb gezielt nav-desktop und Balken-Elemente.
           ==================================================================== */
        header.sairmo-header {
            background: rgba(244, 242, 239, .95);
            border-bottom-color: var(--grau);
        }
        header.sairmo-header .brand { color: var(--petrolhell); }
        header.sairmo-header nav.primary.nav-desktop > a,
        header.sairmo-header .nav-dd > summary,
        header.sairmo-header .logout-link { color: var(--schiefer); }
        header.sairmo-header nav.primary.nav-desktop > a:hover,
        header.sairmo-header nav.primary.nav-desktop > a.active,
        header.sairmo-header .nav-dd > summary:hover,
        header.sairmo-header .nav-dd > summary.active,
        header.sairmo-header .logout-link:hover { color: var(--anthrazit); }
        /* Konto-/User-Pille im hellen Balken */
        header.sairmo-header .nav-dd.konto-dd > summary,
        header.sairmo-header details.user-menu summary {
            color: var(--anthrazit);
            background: transparent;
            border-color: var(--grau);
        }
        header.sairmo-header .nav-dd.konto-dd > summary:hover,
        header.sairmo-header details.user-menu summary:hover {
            color: var(--anthrazit);
            background: var(--sand);
            border-color: var(--schiefer);
        }
        /* Der Akzent-Knopf braucht auf hellem Grund eine Kontur — seine Fläche
           grenzt sich vom Stein nicht ab (1,58). Regel: Memory sairmo-marken-lehren.
           Seit 02.09.2026 traegt die Flaeche wieder Apricot, wozu diese Regel von
           Anfang an gehoerte; die Kontur steht in der Textfarbe, wie beim btn-honig. */
        header.sairmo-header .cta {
            outline: 2px solid var(--night);
            outline-offset: -2px;
        }
        header.sairmo-header .cta:hover {
            background: var(--apricot-hell);
            color: var(--night);
            outline-color: var(--night);
            box-shadow: 0 8px 22px -6px rgba(23, 69, 87, .35);
        }
        /* Hamburger-Button + Striche im hellen Balken */
        header.sairmo-header details.burger > summary.burger-toggle {
            border-color: var(--grau);
        }
        header.sairmo-header details.burger > summary.burger-toggle:hover {
            background: var(--sand);
            border-color: var(--schiefer);
        }
        header.sairmo-header details.burger > summary.burger-toggle .bars,
        header.sairmo-header details.burger > summary.burger-toggle .bars::before,
        header.sairmo-header details.burger > summary.burger-toggle .bars::after {
            background: var(--anthrazit);
        }

/* --- Freigabe-Seite (login-frei, Post-Freigabe-Kanal AP1b) ------------------
   Erbt Bühne und Karte vom Login (.login-stage/.login-card). Zusatz hier: das
   grosse Post-Bild, Caption/Hashtags und der Aktions-Stapel. Bewusst mobil
   zuerst — der Kunde oeffnet diese Seite auf dem Handy, die Hauptaktion liegt
   unten unter dem Daumen. */
    .release-stage .release-image {
        display: block;
        width: 100%;
        height: auto;
        border-radius: 12px;
        border: 1px solid var(--sand);
        background: var(--stein);
    }
    .release-stage .release-caption {
        margin: 1.25rem 0 0;
        line-height: 1.6;
        color: var(--anthrazit);
        overflow-wrap: anywhere;
    }
    .release-stage .release-hashtags {
        margin: .75rem 0 0;
        font-size: .92rem;
        color: var(--text-muted);
        overflow-wrap: anywhere;
    }
    /* KI-Kennzeichnung (Art. 50 EU-KI-Verordnung). Ruhig gesetzt, aber nicht
       versteckt: gleiche Schriftgröße wie die Hashtags, etwas kräftiger, damit
       der Mandant den Hinweis vor dem Freigeben wahrnimmt. */
    .release-stage .release-ai-hinweis {
        margin: .75rem 0 0;
        font-size: .92rem;
        font-weight: 600;
        color: rgba(23, 69, 87, .75);
        /* Wie bei den Hashtags: Der Wortlaut ist frei wählbar, ein sehr langes
           Wort darf die Seite auf dem Handy nicht seitlich aufziehen. */
        overflow-wrap: anywhere;
    }
    .release-stage .release-actions {
        display: flex;
        flex-direction: column;
        gap: .6rem;
        margin-top: 1.75rem;
    }
    .release-stage .release-actions .btn,
    .release-stage .release-actions .btn-pill-secondary {
        width: 100%;
        justify-content: center;
        text-align: center;
    }
    .release-stage .release-edit {
        margin: 1.25rem 0 0;
        text-align: center;
        font-size: .92rem;
    }
    .release-stage .release-edit a {
        color: rgba(23, 69, 87, .75);
        text-decoration: underline;
        text-underline-offset: 3px;
    }
    .release-stage .release-edit a:hover { color: var(--petrol); }
    .release-stage .release-status-text {
        margin: 0;
        line-height: 1.6;
        text-align: center;
        color: rgba(23, 69, 87, .8);
    }

        /* =====================================================================
           Post erstellen: zwei Spalten, Zusaetze in Fenstern (11.09.2026)
           ---------------------------------------------------------------------
           Bis dahin lagen neun Karten untereinander, der Knopf „Generieren" bei
           3359 px; 13 von 17 Kundenseiten brauchten mehr als anderthalb
           Bildschirme. Vorgabe (Florian, 10.09.2026): Arbeitsseiten passen bei
           1440 x 900 ohne Scrollen, Zusaetze gehen in temporaeren Fenstern auf —
           Mitte fuer kurze Entscheidungen, Leiste rechts fuer Auswahl aus Listen.
           Das Fenster selbst kommt aus fenster.css; hier steht nur die Seite.

           Ein Chip nennt seinen ZUSTAND, nicht sich selbst: „Hashtags + KI-Hinweis",
           nicht „Symbole & Hashtags · Hashtags + KI-Hinweis" (Florian: „doppelt
           gemoppelt"). Ein Knopf, der nichts bewirkt, ist gesperrt und sagt warum.
           ===================================================================== */
        .gen-kopf {
            display: grid;
            grid-template-columns: 1fr auto 1fr;
            align-items: center;
            gap: 1rem;
            margin: 0 0 1rem;
        }
        .gen-kopf .page-back { font-size: .9rem; }
        .gen-kopf h1 { font-size: 1.45rem; line-height: 1.1; margin: .15rem 0 0; }
        .gen-kopf .gen-rechts {
            display: flex;
            flex-direction: column;
            align-items: flex-end;
            gap: .3rem;
            text-align: right;
            font-size: .85rem;
            color: var(--text-muted);
        }
        .gen-kopf .gen-rechts strong { color: var(--petrol); }
        /* Der Post-Art-Umschalter bleibt die bestehende Karte mit ihren Inline-
           Farben (activate() setzt sie) — hier nur der Platz in der Mitte. */
        .gen-kopf [role="tablist"] { margin: 0 !important; }

        /* Die Stufe als Pille — dieselbe Auskunft wie „Wie viel wir dir abnehmen"
           auf der Marke-Seite, nur in einer Zeile. Drei Punkte, der erreichte
           in Apricot; Punkte sind hier Weg, keine Liste. */
        .gen-stufe {
            display: inline-flex;
            align-items: center;
            gap: .5rem;
            text-decoration: none;
            color: var(--text-muted);
            font-size: .82rem;
            border: 1px solid var(--sand);
            border-radius: 999px;
            padding: .25rem .75rem .25rem .55rem;
            background: #fff;
        }
        .gen-stufe:hover { border-color: var(--border-button); }
        .gen-stufe strong { color: var(--petrol); font-weight: 600; }
        .gen-stufe .punkte { display: inline-flex; align-items: center; }
        .gen-stufe .punkte i {
            width: .5rem; height: .5rem; border-radius: 50%;
            background: var(--kiesel); display: block; position: relative;
        }
        .gen-stufe .punkte i + i { margin-left: .55rem; }
        .gen-stufe .punkte i + i::before {
            content: ""; position: absolute; right: .5rem; top: 50%;
            width: .55rem; height: 2px; background: var(--kiesel); transform: translateY(-1px);
        }
        .gen-stufe .punkte i.an { background: var(--apricot); outline: 2px solid var(--apricot); outline-offset: 1px; }

        /* Zwei Spalten: links Name, Idee, Prompt — rechts Layout und Zusaetze. */
        .gen-spalten {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 1rem;
            align-items: stretch;
        }
        .gen-spalten > .card { margin-bottom: 0; }
        /* Die dunkle Karte streckt ihr Prompt-Feld auf die Hoehe der rechten Karte —
           sonst bleibt unten dunkler Leerraum, der nach vergessenem Inhalt aussieht. */
        .gen-spalten > .card-inverse { display: flex; flex-direction: column; }
        .gen-spalten > .card-inverse > div:last-child { flex: 1 1 auto; display: flex; flex-direction: column; }
        .gen-spalten > .card-inverse > div:last-child textarea { flex: 1 1 auto; min-height: 7rem; resize: none; }
        .gen-regler { display: flex; align-items: flex-start; gap: 1rem; flex-wrap: wrap; margin-top: .5rem; }
                .gen-ring-block { display: flex; align-items: center; gap: .6rem; }
                .gen-dichte-block { display: flex; flex-direction: column; }
                .gen-dichte-block .gen-zeile { margin-top: 0; }
        .gen-vorschau svg.gen-ring { width: 76px; height: 76px; flex: none; overflow: visible; }
        .gen-ring-name { font-size: .82rem; }

        .gen-layout { display: flex; flex-direction: column; }
        .gen-layout h2 { font-size: 1.3rem; font-weight: 500; margin: 0; }

        /* Vorschau: die lebende Kachel des gewaehlten Layouts, daneben Name, Set und
           der Steuerkopf (Ring, Textmenge). Die Kachel-CSS kommt aus dem Galerie-
           Baustein; der Container hier traegt nur Platz und Rand. */
        .gen-vorschau {
            display: grid;
            grid-template-columns: auto 1fr;
            gap: 1rem;
            align-items: start;
            margin-top: .9rem;
        }
        .gen-vorschau-kachel {
            width: 190px;
            border-radius: 8px;
            border: 1px solid var(--sand);
            overflow: hidden;
            background: var(--stein);
        }
        .gen-vorschau .name { font-weight: 600; font-size: 1rem; }
        .gen-vorschau .name small { display: block; font-weight: 400; color: var(--text-muted); font-size: .8rem; }
        .gen-vorschau .gen-zeile { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; margin-top: .45rem; }
        .gen-vorschau .gen-zeile .muted { font-size: .82rem; }
        .gen-vorschau .gen-hinweis { font-size: .78rem; font-style: italic; color: var(--text-muted); }
        /* Im Karussell steht an der Stelle der Layoutwahl ein Satz: Eine Strecke
           haengt an keinem Blatt, Farbe und Textmenge gelten aber fuer alle Slides. */
        .gen-carousel-hinweis { font-size: .82rem; margin: .45rem 0 0; max-width: 34rem; }
        /* [hidden] allein reicht nicht: .gen-gruppe setzt display:flex und gewinnt. */
        [data-carousel-show][hidden] { display: none !important; }

        /* Die zwei Reiter der Seite. Im Einzelpost steht nur einer, im Karussell
           stehen beide: links das Karussell-Formular, rechts die Layout-Karte aus
           dem Einzelpost-Panel (Ring und Textmenge gelten fuer die ganze Strecke).
           Untereinander war der Karussell-Modus 1363 px hoch und scrollte. */
        [data-gen-panels] { display: flex; flex-direction: column; }
        [data-gen-panels].gen-nebeneinander { flex-direction: row; align-items: flex-start; gap: 1rem; }
        [data-gen-panels].gen-nebeneinander > [data-gen-panel="carousel"] { flex: 1 1 0; min-width: 0; }
        [data-gen-panels].gen-nebeneinander > [data-gen-panel="single"] { flex: 0 0 23rem; }
        [data-gen-panels].gen-nebeneinander .gen-spalten { grid-template-columns: 1fr; }
        @media (max-width: 860px) {
            [data-gen-panels].gen-nebeneinander { flex-direction: column; }
            [data-gen-panels].gen-nebeneinander > [data-gen-panel="single"] { flex: 1 1 auto; }
        }

        /* Hintergrund-Umschalter: KI-Bild oder eigenes Bild (Fenster). */
        .gen-hintergrund {
            display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
            margin-top: .9rem;
        }
        .gen-lbl { font-size: .85rem; color: var(--text-muted); min-width: 5.2rem; }
        .gen-seg {
            display: inline-flex; border: 1px solid var(--border-field);
            border-radius: 8px; overflow: hidden;
        }
        .gen-seg button {
            border: 0; background: #fff; padding: .35rem .75rem;
            font: inherit; font-size: .85rem; color: var(--petrol); cursor: pointer;
        }
        .gen-seg button[aria-pressed="true"] { background: var(--petrol); color: #fff; font-weight: 600; }
        .gen-seg button[disabled] { color: var(--kiesel); background: var(--stein); cursor: not-allowed; }

        /* Die Gruppen der Zusaetze — „Im Bild" (Personas, Produkt) und „Zum Post"
           (Symbole, Hashtags, KI-Hinweis). Unten in der Karte verankert. */
        .gen-gruppen {
            display: flex; flex-direction: column; align-items: flex-start; gap: .55rem;
            margin-top: auto; padding-top: .9rem; border-top: 1px solid var(--sand);
        }
        .gen-gruppe { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
        .gen-chip {
            display: inline-flex; align-items: center; gap: .45rem;
            border: 1px solid var(--border-button); background: #fff; color: var(--petrol);
            border-radius: 999px; padding: .45rem 1rem;
            font: inherit; font-size: .9rem; font-weight: 500; cursor: pointer; white-space: nowrap;
        }
        .gen-chip .dot { width: .55rem; height: .55rem; border-radius: 999px; background: var(--kiesel); flex: 0 0 auto; }
        .gen-chip[data-on="1"] { background: var(--petrol); color: #fff; border-color: var(--petrol); }
        .gen-chip[data-on="1"] .dot { background: var(--apricot); }
        .gen-chip .zahl { font-weight: 400; opacity: .8; }
        .gen-chip[disabled] { opacity: .5; cursor: not-allowed; }


        /* Nur „Post erstellen“: unten kein 4rem-Polster. Die Seite ist darauf ausgelegt,
           bei 1440 x 900 ohne Scrollen zu passen, und der letzte Block ist der Knopf —
           darunter braucht es keinen Raum mehr. `:has()` statt einer Seitenklasse, weil
           layout.php keine fuehrt. */
        /* Nur „Post erstellen": schlankeres Polster oben und unten. Die Seite ist darauf
           ausgelegt, dass die Arbeitsfläche bei 1440 x 900 ohne Scrollen passt; die Fußzeile
           mit den Pflichtangaben liegt bewusst darunter — sie wird gelesen, nicht bedient. */
        body.theme-app main:has([data-gen-seite]) { padding-top: 2rem; padding-bottom: 1.5rem; }
        .gen-aktion { display: flex; align-items: center; gap: 1rem; margin: .6rem 0 0; flex-wrap: wrap; }

        /* Im Fenster: die Galerie-Karte so, wie sie vorher auf der Seite stand —
           nur ohne Karten-Rand, den bringt das Fenster mit. */
        .fenster .gen-fenster-karte { padding: 0; border: 0; box-shadow: none; background: transparent; margin: 0; }

        @media (max-width: 900px) {
            .gen-kopf { grid-template-columns: 1fr; }
            .gen-kopf .gen-rechts { align-items: flex-start; text-align: left; }
            .gen-spalten { grid-template-columns: 1fr; }
            .gen-vorschau { grid-template-columns: 1fr; }
            .gen-vorschau-kachel { width: min(190px, 100%); }
            /* Am Finger: 76 px Ring heisst 26 px je Segment — zu klein zum Treffen.
               132 px bringt jedes Drittel ueber die 44-px-Marke (gemessen mit
               bin/mobil-check.js, 11.09.2026). */
            .gen-vorschau svg.gen-ring { width: 132px; height: 132px; }
        }
