/* Orqenio – gemeinsames Fundament für ALLE Seiten (Chat, Bibliothek, Studio).
 *
 * Warum diese Datei existiert: Bibliothek und Studio brachten jeweils ihre
 * EIGENE Farbpalette mit. Die lief auseinander, sobald sich an der Hauptseite
 * etwas änderte – zuletzt trug die Bibliothek den Akzent #b45f47, während der
 * Chat längst #c87150 führte. Weil die Bibliothek per window.open in einem
 * zweiten Tab NEBEN dem Chat steht, sah man den Unterschied beim Umschalten
 * sofort. Drei Paletten für ein Produkt sind zwei zu viel.
 *
 * Hier steht nur, was für jede Seite gleich gilt: Farben, Abstände,
 * Trefferflächen, Grundschrift und die Basis-Bedienelemente. Alles, was eine
 * Seite eigen macht (Raster, Kopfzeilen, Editor), bleibt in ihrem eigenen
 * Blatt. Insbesondere setzt diese Datei KEINE Höhe auf html/body: der Chat
 * scrollt nicht, Bibliothek und Studio schon.
 *
 * ZWEI SKINS: VORGABE ist das ERPROBTE Design – warmes Beige mit Indigo-Violett
 * (#5b4bc4 hell / #9b8cf0 dunkel). Weitere Farbwelten sind bewusst nur per
 * Umschalter waehlbar (data-skin am <html>; siehe die Skin-Blöcke weiter unten).
 * Klassik bleibt die Vorgabe. Alle Skins folgen für Hell/Dunkel weiter dem
 * Betriebssystem (prefers-color-scheme).
 *
 * FARBROLLEN (in beiden Skins gleich benannt): Der Markenton traegt BEIDE
 * Rollen, die Trennung bleibt aber bestehen:
 *   --accent      Flächen, Marke, Fokusring, Zustandsbalken – NIE Text
 *   --accent-ink  alles, was gelesen wird (deshalb etwas tiefer/heller als --accent)
 * --accent-text bleibt als Vorderfarbe AUF einer Akzentfläche erhalten.
 */

/* Schriften des neuen Designs – LOKAL eingebettet (kein Laufzeit-Aufruf zu
 * Google Fonts, lokal-first). Nur der latin-Subset (deckt Deutsch inkl. ä ö ü ß).
 * Die @font-face-Deklarationen laden erst, wenn sie per font-family referenziert
 * werden – das passiert NUR in den zusätzlichen Skins (siehe --font-sans/--font-mono
 * dort); das erprobte Standard-Design bleibt bei der Systemschrift. Instrument Sans ist
 * eine Variable Font (ein Schnitt fuer 400–700). */
@font-face {
    font-family: "Instrument Sans"; font-style: normal; font-weight: 400 700;
    font-display: swap; src: url("/vendor/fonts/instrument-sans.woff2") format("woff2");
}
@font-face {
    font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400;
    font-display: swap; src: url("/vendor/fonts/ibm-plex-mono-400.woff2") format("woff2");
}
@font-face {
    font-family: "IBM Plex Mono"; font-style: normal; font-weight: 500;
    font-display: swap; src: url("/vendor/fonts/ibm-plex-mono-500.woff2") format("woff2");
}

:root {
    color-scheme: light dark;

    --bg: #f7f7f5; --surface: #ffffff; --surface-2: #f1f0ee; --sidebar: #f0efec;
    --text: #1a1a17; --muted: #5f5f58; --border: #dcdbd5;
    /* Nur dekorative Trenner nutzen --border. Ränder von Bedienelementen
     * brauchen 3:1 – dafür --border-strong. */
    --border-strong: #86857c;
    --accent: #5b4bc4; --accent-ink: #4a3ca8; --accent-text: #ffffff;
    --accent-subtle: rgba(91, 75, 196, 0.10);
    --danger: #b3271b; --success: #317a43; --warning: #7a5c12;
    --accent-dark: #4a3ca8;
    /* Symbolfarben einer Persona. Je Persona INLINE ueberschrieben (app.js);
     * hier stehen die Rueckfallwerte, damit ein Symbol ohne eigene Farbe die
     * Markenfarbe traegt. Zwei Werte, weil die Symbole Duotone sind – mit nur
     * einem faerbt man je nach Symbol mal die vordere, mal die hintere Ebene. */
    --persona-primary: var(--accent);
    --persona-secondary: currentColor;
    --active-persona-color: var(--accent);
    --active-persona-secondary: var(--accent);
    --user-bubble: #eceae6; --radius: 12px;

    /*
     * Radius für BEDIENELEMENTE (Knöpfe, Eingabefelder, Auswahlfelder).
     *
     * Getrennt von --radius: Karten dürfen runder sein als die Dinge, die
     * darin stehen. Knöpfe und Felder teilen sich diesen Wert, weil sie in
     * jeder Leiste nebeneinanderstehen – zwei verschiedene Rundungen in einer
     * Zeile sieht man sofort, ohne sagen zu können, woran es liegt.
     */
    --radius-control: 10px;

    /*
     * DIE RUNDUNGSLEITER – DREI STUFEN, MEHR NICHT.
     *
     * GEMESSEN AM 20.08.2026: 236 border-radius-Angaben in app.css, davon 15
     * über ein Token – und ZWÖLF verschiedene Eckenwerte nebeneinander
     * (6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20). Niemand sieht den
     * Unterschied zwischen 8 und 9 Pixeln. Man sieht aber, dass es nicht aus
     * einem Guss ist – ohne sagen zu können, woran es liegt.
     *
     * NUTZERENTSCHEIDUNG (20.08.2026): „Ich denke so 9-16px sind ausreichend
     * in den allermeisten Fällen." Genau das ist die Leiter:
     *
     *   --radius-control  10px  Bedienelemente, Chips, kleine Karten
     *   --radius          12px  Karten
     *   --radius-lg       16px  grosse Flächen, Modale, Sprechblasen
     *
     * NICHT AUF DER LEITER und bewusst so:
     *  - `--radius-pill` (vollrund) und `50%` sind FORMEN, keine Stufen.
     *  - Werte bis 4px sind Balken, Fortschrittsanzeigen und
     *    Scrollbalken-Griffe. Dort ist der Radius die halbe HÖHE, keine Ecke –
     *    ein 4px-Balken mit 10px Radius wäre eine Wurst.
     *
     * WER HIER DREHT, DREHT AM GANZEN PRODUKT. Das ist der Zweck: Ein
     * Makeover kostet drei Zeilen, keine Suchaktion.
     */
    --radius-lg: 16px;
    /* Vollrund (Pillen, Chips, Fortschrittsbalken). */
    --radius-pill: 999px;

    /* Abstände: 4er-Raster, keine Zwischenwerte. */
    --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
    /*
     * DER SEITENRAND EINER VOLLSEITE.
     *
     * Hier steht nur die VORGABE: ausserhalb einer Seitenkarte gibt es
     * keinen. Den echten Wert setzt die Karte selbst (app.css,
     * .modalOverlay.fullPage .pageCard) – alles darin sitzt buendig darauf,
     * und der Seitenkopf zieht sich mit negativem Rand darueber hinaus.
     *
     * Die Vorgabe steht hier und nicht dort, weil ein Token, das nur in
     * einem Blatt definiert ist, in jedem anderen still ausfaellt: CSS
     * meldet eine fehlende Variable nicht, die Eigenschaft verschwindet
     * einfach. Genau dafuer gibt es Designtokens.test.ts.
     */
    --seiten-rand: 0px;
    --sp-5: 24px; --sp-6: 32px; --sp-7: 48px;

    /* Trefferflächen: 44px ist die Untergrenze, 48px für Hauptaktionen. */
    --tap: 44px;

    /*
     * UMBRUCHBREITEN – die Leiter, an die sich ALLES hält.
     *
     * Sie stehen hier als Kommentar und nicht als Merkmal, weil CSS in
     * `@media` keine Merkmale einsetzen kann. Ein Wächtertest hält die Liste
     * trotzdem geschlossen (`Umbruchbreiten` in Gestaltung.test.ts).
     *
     *   760px  SCHMAL – die eine Umbruchbreite. Alles, was am Telefon
     *          untereinander gehört, bricht HIER um.
     *   560px  KLEIN – zweiter Schritt für Raster, die bei 760 nur einmal
     *          umbrechen und darunter noch einmal.
     *   480 / 460 / 420px  Feinschritte EINZELNER Bauteile (Bildergalerie,
     *          zwölf Wörter, Konnektor-Knöpfe). Sie stehen nie neben etwas,
     *          das gleichzeitig umbrechen müsste.
     *   900px  NUR das Studio – ein Drei-Spalten-Editor wird eher eng als
     *          eine Seite mit einer Spalte.
     *
     * WARUM SO STRENG (05.09.2026): Es waren 620, 640, 700 und 720 zusätzlich
     * im Umlauf – alle mit derselben Absicht („am Handy untereinander"). Im
     * Band zwischen 620 und 760 stand die Seite dadurch halb umgebrochen da:
     * Die Modellzeile lag noch nebeneinander, die Einstellungszeile darunter
     * schon gestapelt. Das sieht man sofort und kann nicht sagen, woran es
     * liegt – der schlechteste Fehler für den ersten Eindruck. Die elf Regeln
     * liegen jetzt auf 760.
     */

    /* Höhe des klebenden Seitenkopfs (Einstellungen/Admin) – wird beim
     * Öffnen GEMESSEN und am Overlay überschrieben (fixiereSeitennavHoehe);
     * die klebende Seiten-Nav setzt darunter an, statt hinter dem Kopf zu
     * verschwinden. 0px = kein klebender Kopf. */
    --seitenkopf-hoehe: 0px;
  /* EIN Monospace-Stack fuer Chat-Codebloecke, Studio-Editor und Diffs -
   * vorher drei Varianten, auf macOS sah Code je Seite anders aus. */
  --font-mono: ui-monospace, "Cascadia Code", Consolas, monospace;
  /* Fliesstext-Schrift. Vorgabe = Systemschrift (lokal-first); der „neu"-Skin
   * setzt hier Instrument Sans davor (siehe :root[data-skin="neu"]). */
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* EINE Inhaltsbreite fuer alle Unterseiten - vorher 1080/1100/1160/1280,
   * die Breite sprang beim Bereichswechsel sichtbar. */
  --seitenbreite: 1100px;
    --rail-w: 60px;
    /* Breite der LISTENSPALTE (ohne Symbolleiste). Das JS ueberschreibt sie
     * beim Ziehen am Rand; der Standard gehoert trotzdem hierher, sonst
     * liefert getPropertyValue("--sidebar-w") beim ersten Lesen einen leeren
     * String und die Rechnung faellt auf ihren Rueckfallwert zurueck. */
    --sidebar-w: 270px;
    /* Gedaempfter Text – schwaecher als --text, aber staerker als --muted. */
    --text-dim: #4a4a44;
    /* Lesespalte: Obergrenze fuer Nachrichten und Eingabe. */
    --lesespalte: 760px;
      --tabbar-h: 56px;

    /* Systemränder einer INSTALLIERTEN App (PWA). Sie liefern überhaupt erst
     * Werte, wenn das Viewport-Tag `viewport-fit=cover` trägt – im normalen
     * Browsertab sind beide 0, dort ändert sich durch sie nichts.
     *
     * Unten GEDECKELT, und zwar aus Erfahrung: Android meldet für die
     * Gestenleiste bis zu 48px, iOS 34px für den Home-Indicator. Ungedeckelt
     * wuchs die untere Bereichsleiste damit von 56px auf über 100px – ein
     * Fünftel des Bildschirms für fünf Knöpfe, und die Knöpfe rutschten so
     * weit nach oben, dass die Leiste nicht mehr sinnvoll bedienbar war.
     * 16px halten die Homebar frei, ohne die Leiste aufzublähen.
     *
     * Oben NICHT gedeckelt: Dort geht es um Statusleiste und Notch, und deren
     * Höhe ist keine Geschmacksfrage – wer sie kürzt, schiebt Bedienelemente
     * unter die Uhr. */
    --safe-bottom: min(env(safe-area-inset-bottom, 0px), 16px);
    --safe-top: env(safe-area-inset-top, 0px);

    --shadow-1: 0 1px 2px rgba(0,0,0,.06), 0 1px 3px rgba(0,0,0,.04);
    --shadow-2: 0 8px 28px rgba(0,0,0,.10);
}
@media (prefers-color-scheme: dark) {
    :root {
        --bg: #1a1915; --surface: #24231e; --surface-2: #2f2e28; --sidebar: #201f1a;
        --text: #eceae4; --muted: #a5a398; --border: #3a382f;
        --border-strong: #7d7c71;
        --accent: #9b8cf0; --accent-ink: #a99bf5; --accent-text: #1a1915;
        --accent-subtle: rgba(155, 140, 240, 0.16);
        --danger: #ff7b6b; --success: #78c98a; --warning: #dfbd63;
        --accent-dark: #a99bf5;
        --user-bubble: #33322b;
        --text-dim: #c4c2b8;
        --shadow-1: 0 1px 2px rgba(0,0,0,.5);
        --shadow-2: 0 8px 28px rgba(0,0,0,.55);
    }
}

/* -------------------------------------------------------------------------
 * ZUSÄTZLICHE SKINS: Alle überschreiben ausschließlich Farbrollen und Schriften.
 * Abstände, Radien und Breiten bleiben gemeinsam, damit ein Theme niemals ein
 * anderes Layout oder eine andere Bedienung erzeugt. Semantik
 * (danger/success/warning) bleibt in jeder Farbwelt gleich.
 * ------------------------------------------------------------------------- */
:root[data-skin="slate"] {
    --bg: #f4f4f8; --surface: #ffffff; --surface-2: #f7f7fb; --sidebar: #ffffff;
    --text: #17171f; --muted: #7a7a8c; --border: #e4e4ee; --border-strong: #bfbfd0;
    --accent: #5b4ce0; --accent-ink: #4a3cc4; --accent-text: #ffffff;
    --accent-subtle: rgba(91, 76, 224, 0.10); --accent-dark: #4a3cc4;
    --user-bubble: #edecfb; --text-dim: #45454f;
    /* Schriften der zusätzlichen Designs (lokal eingebettet, siehe @font-face oben).
     * System-Stack bleibt als Rueckfall, falls eine woff2 fehlt. */
    --font-sans: "Instrument Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-mono: "IBM Plex Mono", ui-monospace, "Cascadia Code", Consolas, monospace;
    --shadow-1: 0 1px 2px rgba(20,20,40,.06);
    --shadow-2: 0 12px 28px rgba(20,20,40,.08);
}
@media (prefers-color-scheme: dark) {
    :root[data-skin="slate"] {
        --bg: #0e0e14; --surface: #15151d; --surface-2: #1b1b25; --sidebar: #15151d;
        --text: #eaeaf2; --muted: #8a8a9c; --border: #282836; --border-strong: #45455a;
        --accent: #7c6cf5; --accent-ink: #9d90f8; --accent-text: #ffffff;
        --accent-subtle: rgba(124, 108, 245, 0.16); --accent-dark: #9d90f8;
        --user-bubble: #211e38; --text-dim: #c8c8d6;
        --shadow-1: 0 1px 2px rgba(0,0,0,.5);
        --shadow-2: 0 12px 28px rgba(0,0,0,.45);
    }
}

/* OZEAN: kühles Blau mit klarer, ruhiger Informationshierarchie. */
:root[data-skin="ocean"] {
    --bg: #f3f8fa; --surface: #ffffff; --surface-2: #edf5f8; --sidebar: #eef6f8;
    --text: #14232a; --muted: #607780; --border: #d6e4e8; --border-strong: #94b3bd;
    --accent: #167da6; --accent-ink: #096486; --accent-text: #ffffff;
    --accent-subtle: rgba(22, 125, 166, .11); --accent-dark: #096486;
    --user-bubble: #e2f1f6; --text-dim: #38535d;
    --font-sans: "Instrument Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-mono: "IBM Plex Mono", ui-monospace, "Cascadia Code", Consolas, monospace;
    --shadow-1: 0 1px 2px rgba(12, 59, 76, .07); --shadow-2: 0 12px 28px rgba(12, 59, 76, .10);
}
@media (prefers-color-scheme: dark) {
    :root[data-skin="ocean"] {
        --bg: #0b1519; --surface: #102126; --surface-2: #162b31; --sidebar: #102126;
        --text: #e2f0f3; --muted: #91aeb6; --border: #29444d; --border-strong: #527783;
        --accent: #43b3db; --accent-ink: #73c9e5; --accent-text: #071114;
        --accent-subtle: rgba(67, 179, 219, .17); --accent-dark: #73c9e5;
        --user-bubble: #15353e; --text-dim: #c3dbe1;
        --shadow-1: 0 1px 2px rgba(0,0,0,.5); --shadow-2: 0 12px 28px rgba(0,0,0,.48);
    }
}

/* WALD: gedecktes Grün für eine wärmere, konzentrierte Arbeitsansicht. */
:root[data-skin="forest"] {
    --bg: #f4f7f2; --surface: #ffffff; --surface-2: #eef3eb; --sidebar: #eff4ed;
    --text: #1a271c; --muted: #657364; --border: #d8e1d5; --border-strong: #9cae9b;
    --accent: #3a7c4b; --accent-ink: #276638; --accent-text: #ffffff;
    --accent-subtle: rgba(58, 124, 75, .11); --accent-dark: #276638;
    --user-bubble: #e5f0e3; --text-dim: #435746;
    --font-sans: "Instrument Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-mono: "IBM Plex Mono", ui-monospace, "Cascadia Code", Consolas, monospace;
    --shadow-1: 0 1px 2px rgba(30, 73, 39, .07); --shadow-2: 0 12px 28px rgba(30, 73, 39, .09);
}
@media (prefers-color-scheme: dark) {
    :root[data-skin="forest"] {
        --bg: #101712; --surface: #172119; --surface-2: #202d22; --sidebar: #172119;
        --text: #e5ede3; --muted: #a0afa0; --border: #344537; --border-strong: #637a67;
        --accent: #70bf7a; --accent-ink: #9bd5a1; --accent-text: #0d150e;
        --accent-subtle: rgba(112, 191, 122, .17); --accent-dark: #9bd5a1;
        --user-bubble: #28412c; --text-dim: #c9d9c8;
        --shadow-1: 0 1px 2px rgba(0,0,0,.5); --shadow-2: 0 12px 28px rgba(0,0,0,.48);
    }
}

* { box-sizing: border-box; }

/* 16px Grundgröße: Alles darunter lässt iOS beim Fokus eines Eingabefeldes
 * automatisch hineinzoomen – danach ist der Viewport skaliert und lässt sich
 * seitlich schieben. Genau das erzeugte die verrutschten Ansichten. */
body { font: 16px/1.55 var(--font-sans);
       background: var(--bg); color: var(--text); -webkit-text-size-adjust: 100%; margin: 0; }

/* Seitlicher Überlauf: an der Wurzel abgeschnitten.
 *
 * Nutzerwunsch (26.07.2026): „sicherstellen, dass es nie einen overflow x
 * gibt bzw. es nicht dazu kommt." Der Fall ist unangenehm, weil er wandert:
 * Eine zu lange Adresse in einer Antwort, eine breite Tabelle, ein Bild mit
 * fester Breite – jedes Mal eine andere Stelle, und sichtbar wird immer
 * dasselbe, nämlich eine Seite, die sich seitlich schieben lässt.
 *
 * `clip` statt `hidden`: `hidden` macht das Element zu einem Scroll-Container
 * und setzt damit `position: sticky` weiter innen ausser Kraft – die
 * Kopfzeile bliebe nicht mehr stehen. `clip` schneidet nur ab.
 *
 * Das ist die letzte Grenze, nicht die Lösung: Breite Inhalte sollen INNEN
 * scrollen (Tabellen, Codeblöcke, die Medienreihe tun das). Wo das jemand
 * vergisst, wird der Inhalt hier abgeschnitten statt die ganze Seite zu
 * verschieben. */
html { overflow-x: clip; }
body { overflow-x: clip; max-width: 100vw; }

/* Zwei Dauerbrenner, die den Überlauf überhaupt erst erzeugen:
 * Ein Bild ohne Breitengrenze und ein Flex-Kind, das per Vorgabe nicht unter
 * seine Inhaltsbreite schrumpfen darf (min-width: auto). */
img, video, canvas, svg, iframe { max-width: 100%; }
pre, table { max-width: 100%; }

.hidden { display: none !important; }
.srOnly { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/*
 * DIE EINE KNOPF-DEFINITION (21.08.2026).
 *
 * BELEGTER BEFUND (Nutzermeldung, Handtest 14.1): „Im Studio sind noch
 * falsche Inputfelder, alles alt.“ Nachgemessen war es umgekehrt - das
 * STUDIO folgte den Projektregeln, die Hauptseite nicht:
 *
 *   Hauptseite: 39 px hoch, 6 px Polster, schwacher Rand (--border)
 *   Studio:     44 px hoch, 8 px Polster, kraeftiger Rand (--border-strong)
 *
 * `studio.css` trug eine ZWEITE, abweichende Fassung derselben Regel. Zwei
 * Definitionen fuer dieselbe Sache laufen immer auseinander - hier taten sie
 * es sichtbar.
 *
 * UEBERNOMMEN WURDEN DIE STUDIO-WERTE, und zwar nicht aus Geschmack: 44 px
 * ist die Untergrenze fuer einen Finger (--tap, per Test bewacht), und ein
 * Bedienelement braucht 3:1 Kontrast am Rand (--border-strong). Die
 * Hauptseite verletzte beides.
 */
button {
    font: inherit; cursor: pointer; border: 1px solid var(--border-strong);
    background: transparent; color: var(--text);
    border-radius: var(--radius-control); padding: var(--sp-2) var(--sp-3);
    min-height: var(--tap);
}
button:hover { background: var(--surface-2); }
button:focus-visible, input:focus-visible, textarea:focus-visible, a:focus-visible,
select:focus-visible, summary:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 1px;
}
button.danger { color: var(--danger); border-color: var(--danger); }

/*
 * DIE ZWEI VARIANTEN, NACH DENEN JEDER GREIFT.
 *
 * GEMESSEN (05.09.2026): Im Skript standen `class="secondary small"` und
 * `class="primary"` an Knöpfen – für keinen dieser drei Namen gab es eine
 * Regel. Die Knöpfe sahen also aus wie jeder andere: Ein „kleiner" Knopf war
 * nicht klein, und die Hauptaktion eines Dialogs („Lernen starten") stand
 * unbetont neben „Schliessen".
 *
 * Solche Namen erfindet niemand böswillig – man greift nach dem, was in jedem
 * anderen Baukasten so heisst. Deshalb gibt es sie jetzt wirklich, statt sie
 * einzeln aus dem Code zu entfernen. `primary` ist bewusst NICHT dabei: Dafür
 * gibt es `.allow` (Dialoge) und `.primaryAction` (Seiten), und ein dritter
 * Name für dieselbe Sache wäre der Anfang derselben Geschichte.
 */
button.secondary { border-color: var(--border); color: var(--muted); }
button.secondary:hover { color: var(--text); }
/* Kleiner heisst SCHMALER, nicht flacher unter das Daumenmaß: Die Höhe bleibt
 * --tap, weil ein Knopf, den man nicht trifft, keine Variante ist. */
button.small { padding: var(--sp-1) var(--sp-2); font-size: 0.86em; }

/* ====================================================================
 * EINGABEFELDER – EINE Gestalt für die ganze Anwendung
 * ====================================================================
 *
 * NUTZERWUNSCH (19.08.2026, wörtlich): „Gerne schaue auch mal alle
 * Input/Selectfelder an die sind überall unterschiedlich und nicht global
 * identisch. Mache eine einheitliche Designstruktur bitte global!"
 *
 * Er hat recht: Vor dieser Regel gab es 44 einzelne Regeln für Felder, jede
 * mit eigenem Innenabstand (8px / 10px / 12px / var(--sp-2)), eigenem Radius
 * (8px / 10px), eigener Randfarbe (--border / --border-strong) und mal mit,
 * mal ohne Mindesthöhe. Nebeneinander sah das aus wie zwei Programme.
 *
 * DIE REGEL AB HIER: Das AUSSEHEN steht hier und nur hier. Örtliche Regeln
 * bestimmen die LAGE (Breite, flex, Abstände nach aussen) – nicht Rand,
 * Radius, Polster oder Hintergrund. Wer das Aussehen örtlich ändert, hat
 * entweder einen sehr guten Grund (dann steht er als Kommentar dabei) oder
 * die nächste Abweichung gebaut.
 *
 * SCHRIFTGRÖSSE, HARTE UNTERGRENZE: Safari zoomt beim Fokus in JEDES Feld
 * hinein, dessen berechnete Grösse unter 16px liegt. Danach ist der
 * Layout-Viewport skaliert und lässt sich seitlich schieben – die Ursache
 * verrutschter Ansichten. Wo etwas kleiner wirken soll, führt der Weg über
 * Innenabstand und Breite, NIE über die Schriftgrösse.
 *
 * MINDESTHÖHE: --tap (44px). Ein Feld, das man am Telefon nicht trifft, ist
 * keine Eingabe.
 *
 * AUSGENOMMEN sind die Felder, die gar keine Textfelder sind: Häkchen,
 * Auswahlpunkte, Schieber, Farbwähler, Dateiauswahl. Für sie wären Polster
 * und Mindesthöhe sinnlos bis schädlich.
 */
/*
 * :where() UM DIE :not()-KETTE - der Grund ist Spezifitaet, nicht Kosmetik.
 *
 * BELEGTER FEHLFALL (Nutzermeldung 21.08.2026, mit Screenshot): Im Suchfeld
 * der Seitenleiste ueberlappte die Lupe den Platzhaltertext.
 *
 * Die Ursache lag hier: Sechs :not([type=...]) zaehlen als sechs
 * Attributselektoren. Diese Regel wog damit (0,6,1) - und schlug JEDE
 * Klassenregel. `.sidebarSearch input { padding-left: 32px }` wiegt (0,1,1)
 * und kam nie an; das Feld behielt die 12px von hier, und die Lupe sass im
 * Text.
 *
 * GEMESSEN: 22 Regeln im Projekt setzten etwas an einem Feld, das nie
 * ankam - Composer, Einkaufsfelder, Studio-Panel, beide Suchfelder.
 *
 * `:where()` steuert NICHTS zur Spezifitaet bei. Die Ausnahmen wirken
 * unveraendert, die Regel wiegt aber nur noch (0,0,1) - so schwer wie ein
 * blosses `input`. Genau so gehoert sich eine BASISregel: Sie gilt, bis
 * jemand ausdruecklich etwas anderes sagt.
 *
 * Das ist dieselbe Lehre wie bei Class first (siehe .ai/css-good-bad.md):
 * Wer Spezifitaet aufbaut, nimmt sich die Moeglichkeit, spaeter etwas zu
 * aendern - und merkt es erst, wenn eine Regel stumm bleibt.
 */
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"])),
textarea,
select {
    font-family: inherit;
    font-size: max(16px, 1rem);
    color: var(--text);
    background: var(--bg);
    /* Kräftigerer Rand als bei Knöpfen: Ein Feld muss aussehen, als könne man
     * hineinschreiben. Ein Knopf trägt seine Bedienbarkeit im Zeigefinger
     * (Hover, Cursor), ein Feld nur im Rand. */
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-control);
    padding: var(--sp-2) var(--sp-3);
    min-height: var(--tap);
    max-width: 100%;
}
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }
textarea {
    /* Ein Textbereich ist mehrzeilig gemeint – eine Zeile Höhe wäre ein
     * Eingabefeld mit Ziehgriff. Waagerecht ziehen bleibt gesperrt: Das
     * sprengt sonst das Raster der Seite. */
    min-height: calc(var(--tap) * 1.6);
    resize: vertical;
    line-height: 1.45;
}
select {
    /* Der Pfeil bleibt der des Systems (kein appearance:none): Eine
     * nachgebaute Liste verhält sich am Telefon anders als die echte, und
     * genau darauf verlassen sich Bedienhilfen. */
    cursor: pointer;
}
input::placeholder, textarea::placeholder { color: var(--muted); opacity: 1; }
input:disabled, textarea:disabled, select:disabled {
    opacity: 0.55; cursor: not-allowed; background: var(--surface-2);
}

/* Die Marke stammt aus Icon-ohne-background.svg und ist als Pfad eingesetzt.
 * Ueber currentColor folgt sie dem Thema – eine Datei statt zweier Fassungen. */
.brandGlyph { width: 1em; height: 1em; display: inline-block; vertical-align: -0.14em; }

/* ------------------------- Symbolleiste (Rail) -------------------------
 * Die schmale Symbolspalte am linken Rand. Sie gilt auf JEDER Seite, die
 * eine Navigation hat – der Nutzer soll beim Wechsel in die Bibliothek
 * nicht das Gefuehl haben, die Anwendung verlassen zu haben.
 *
 * Die Bibliothek hatte hierfuer eine eigene Nachbildung mit 40px statt
 * 44px und der VOLLEN Akzentflaeche unter dem aktiven Eintrag. Genau so
 * entsteht der Eindruck zweier verschiedener Programme. */
.rail {
    background: var(--sidebar);
    border-right: 1px solid var(--border);
    display: flex; flex-direction: column; align-items: center;
    gap: 2px; padding: var(--sp-3) 0 var(--sp-2);
    min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    scrollbar-width: none;
}
.railBrand { color: var(--accent); font-size: 26px; margin-bottom: var(--sp-3); display: block; } /* fill */
.railBtn {
    width: 40px; height: 40px; flex-shrink: 0;
    border: none; background: none; color: var(--muted);
    border-radius: var(--radius); display: grid; place-items: center;
    padding: 0; text-decoration: none; font: inherit; cursor: pointer;
}
.railBtn:hover { background: var(--surface-2); color: var(--text); }
.railBtn.active { background: var(--accent-subtle); color: var(--accent-ink); }
/* Die Symbole der Leiste folgen der TEXTFARBE, nicht dem Akzent.
 *
 * Im Chat setzt app.css fuer Duotone-Symbole `--fa-primary-color: var(--accent)` –
 * dadurch leuchteten dort ALLE Eintraege orange, auch die inaktiven, und man
 * sah der Leiste nicht an, wo man ist. In der Bibliothek fehlte diese Regel,
 * weshalb sie dort von Anfang an richtig aussah: ausgegraut, nur das Aktive
 * hervorgehoben.
 *
 * Hier gilt jetzt ueberall dasselbe – der Zustand ist wichtiger als die Marke. */
.railBtn .ico .fa-duotone,
.railBrand .fa-duotone {
    --fa-primary-color: currentColor;
    --fa-secondary-color: currentColor;
    --fa-secondary-opacity: 0.45;
}
.railSpacer { flex: 1; min-height: var(--sp-4); }
.railGroupGap {
    width: 1px; height: 9px; flex: 0 0 9px;
}
/* Ab Tablet-Breite per Finger bedienbar: 44px ist die eigene Untergrenze. */
@media (min-width: 761px) {
    .railBtn { width: var(--tap); height: var(--tap); }
    .rail { gap: var(--sp-1); }
}

/* ========================= Bereichsleiste unten (mobil) =======================
 * Fünf Ziele in Daumenreichweite, unterhalb von 761px. Auf dem Desktop
 * übernimmt die Symbolleiste diese Aufgabe; dort ist die Leiste aus.
 *
 * Warum sie HIER steht und nicht in app.css: Die Bibliothek hatte mobil eine
 * ganz andere untere Navigation – ihre Symbolleiste wurde zur Fußzeile
 * umgebaut, mit elf Einträgen statt fünf. Wer zwischen Chat und Bibliothek
 * wechselte, bekam zwei verschiedene Navigationen zu sehen (vom Benutzer
 * gemeldet). Eine Leiste für alle Seiten, an EINER Stelle definiert – wie die
 * Symbolleiste darüber auch. */
.tabBar { display: none; }

@media (max-width: 760px) {
    /* FEST am unteren Viewportrand. Vorher war sie eine Rasterzeile – das
     * reichte, solange nichts über ihr lag. Aber jede Vollseiten-Ansicht ist
     * ein fixed-Overlay (z-index 50) und verdeckte sie vollständig: genau auf
     * den Seiten, zwischen denen sie wechseln soll, war sie weg. */
    .tabBar {
        display: flex;
        position: fixed; left: 0; right: 0; bottom: 0; width: 100%;
        /* FESTE Höhe statt „Inhalt plus Polster": Nur so lässt sich der
         * Platzhalter am Seiteninhalt exakt gegenrechnen, und nur so kann die
         * Leiste nicht unbemerkt mitwachsen, wenn ein Gerät großzügige
         * Systemränder meldet. */
        height: calc(var(--tabbar-h) + var(--safe-bottom));
        /* Über Vollseiten-Ansichten (50) und Schublade (40), aber UNTER den
         * echten Fokus-Dialogen (Modal 80, Lightbox 100) – die verlangen
         * bewusst die ganze Aufmerksamkeit. */
        z-index: 55;
        border-top: 1px solid var(--border);
        background: var(--surface);
    }
    /* Bildschirmtastatur offen (app.js setzt die Klasse über visualViewport):
     * Die Leiste weicht, sonst schwebt sie über der Tastatur mitten im Bild
     * und nimmt dem ohnehin kleinen Restviewport weitere 56px weg. */
    body.keyboardOpen .tabBar { display: none; }
    .tabBar .tab {
        flex: 1; min-width: 0;
        /* Der Knopf füllt die Leiste GANZ, und der Systemrand liegt in seinem
         * Innenabstand statt im Polster der Leiste. Andernfalls ist der
         * unterste Streifen sichtbar Leiste, aber kein Knopf – man tippt, und
         * nichts passiert (genau der gemeldete Fehler in der installierten
         * App). So reicht die Trefferfläche bis zur Bildschirmkante, Symbol
         * und Beschriftung bleiben darüber. */
        height: 100%;
        position: relative;
        display: flex; flex-direction: column; align-items: center; justify-content: center;
        gap: 2px; padding: var(--sp-1) 2px calc(var(--sp-1) + var(--safe-bottom));
        border: none; background: none; color: var(--muted);
        border-radius: 0;
        /* In der Bibliothek sind die Ziele Links, im Chat Knöpfe – beide
         * sollen gleich aussehen. */
        text-decoration: none; font: inherit; cursor: pointer;
    }
    .tabBar .tab:hover { background: none; }
    .tabBar .tab .ico { font-size: 17px; line-height: 1; }
    .tabLabel {
        font-size: 11px; line-height: 1.2;
        max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .tabBar .tab.active { color: var(--accent-ink); }
    /* Zustand nicht allein über Farbe anzeigen – der Balken bleibt auch bei
     * Farbfehlsichtigkeit erkennbar. Er hängt an der OBERKANTE des Tabs statt
     * an einem negativen margin-Festwert: Der frühere `margin-top: -46px`
     * wäre bei jeder Änderung von --tabbar-h stumm verrutscht. */
    .tabBar .tab.active::before {
        content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
        width: 26px; height: 3px; border-radius: 0 0 3px 3px; background: var(--accent);
    }
}

/* --------------------------- Symbole (Font Awesome) ---------------------------
 * Diese Grundregeln standen nur in app.css. Medien- und Studioseite laden die
 * nicht, dort fehlten Mindestbreite und Zentrierung. Sie gehoeren in die
 * gemeinsame Grundlage, weil jede Seite dieselbe Symbolkette benutzt. */
.ico { display: inline-block; min-width: 1.15em; text-align: center; }
.ico .fa-duotone {
    --fa-primary-color: var(--accent);
    --fa-secondary-color: currentColor;
    --fa-secondary-opacity: 0.45;
}
/* Auf gefaerbten Flaechen traegt das Symbol die Vordergrundfarbe des Knopfes –
 * mit dem Akzent waere es genauso hell wie sein Untergrund. */
button.allow .ico .fa-duotone { --fa-primary-color: currentColor; --fa-secondary-color: currentColor; --fa-secondary-opacity: 0.6; }
button.danger .ico .fa-duotone { --fa-primary-color: var(--danger); }


.ico .fa-svg-icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    overflow: visible;
    vertical-align: -0.125em;
    fill: currentColor;
}

/* ------------------------ Fenster (Modal) ------------------------
 * Die HUELLE eines Fensters stand bisher nur in app.css. Seit
 * confirm/alert ueberall durch ein eigenes Fenster ersetzt sind, brauchen
 * Bibliothek und Studio dieselbe Huelle – und zwar DIESELBE, nicht eine
 * nachgebaute. Genau daran ist frueher schon die Farbpalette
 * auseinandergelaufen. In app.css bleibt nur, was den Chat eigen macht:
 * Vollseiten-Varianten und die Stapelreihenfolge der einzelnen Overlays. */
.modalOverlay {
    position: fixed; inset: 0; background: rgba(0,0,0,0.45);
    display: flex; align-items: center; justify-content: center; z-index: 50;
}
.modalCard {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
    padding: 22px 24px; width: min(520px, 92vw); max-height: 84dvh; overflow-y: auto;
    box-shadow: 0 18px 60px rgba(0,0,0,0.25);
}
.modalCard h2 { margin: 0 0 8px; font-size: 18px; }
.modalCard .modalReason { color: var(--muted); font-size: 0.9em; margin: 0 0 12px; }
/* --------------------------- Knopfleisten ---------------------------
 * `.modalButtons` ist eine REIHE VON KNOEPFEN, sonst nichts: keine Farbe,
 * keine Klebeposition, keine negativen Aussenmasse.
 *
 * BELEGTER FEHLFALL (Benutzer, 06.09.2026, vier Bildschirmfotos): Bis 3.270.0
 * trug diese Klasse SELBST die Fussleisten-Gestaltung - klebend, mit
 * Hintergrund und mit -24px an beiden Seiten, damit der Hintergrund bis an
 * den Kartenrand reicht. Das war fuer die Leiste am Ende einer Karte gedacht
 * und richtig. Nur: Dieselbe Klasse steht rund dreissig Mal MITTEN im Inhalt
 * (Einstellungskarten, Konnektoren, Freigaben, „Verwaiste Studio-Dateien",
 * „Was Orqenio sich merken darf"). Dort klebte die Reihe beim Rollen fest,
 * legte ihren Hintergrund ueber den Text darunter und ragte links und rechts
 * aus ihrer Karte heraus. Der Benutzer: „die Button backgrounds [sind]
 * ueberlappend zum rest ... Bei ‚Erinnerungen‘ blockiert das sogar Text."
 *
 * Die Lehre ist aelter als der Fall: Eine Klasse, die an dreissig Stellen
 * benutzt wird, darf nur das koennen, was an ALLEN dreissig stimmt. Alles
 * Weitere gehoert an die Stelle, die es braucht - hier an die Leiste, die
 * WIRKLICH am Ende der Karte steht. */
.modalButtons
{
    display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; justify-content: flex-end;
    background: none;
}

/* ------------------- Die Fussleiste bleibt SICHTBAR -------------------
 * BELEGTER FEHLFALL (Benutzer, 02.09.2026, Bildschirmfoto): Im Menue eines
 * Wissensraums lag „Schliessen" unter der Falz - „waere besser wenn man nicht
 * scrollen muesste in der Ansicht (Desktop)".
 *
 * Die Karte rollt als GANZES (max-height + overflow-y oben). Damit wandert
 * die Leiste am Ende mit hinaus, sobald der Inhalt einmal laenger ist als der
 * Bildschirm - und ausgerechnet der Weg HINAUS ist dann der, den man suchen
 * muss.
 *
 * `sticky` statt einer Umbauaktion an jedem Dialog: Die Leiste bleibt am
 * unteren Rand der rollenden Karte stehen. Die negativen Werte heben das
 * Innenmass der Karte (22px 24px) auf, damit der Hintergrund bis an die Kante
 * reicht und der Inhalt nicht darunter durchscheint. Der Hintergrund ist hier
 * kein Schmuck, sondern die Bedingung: Ohne ihn rollt der Text durch die
 * Knoepfe hindurch.
 *
 * NUR DAS DIREKTE LETZTE KIND. Genau das unterscheidet die Fussleiste von den
 * Knopfreihen im Inhalt - die liegen immer in einer Karte, einem Abschnitt
 * oder einer Zeile und sind deshalb nie direktes Kind.
 *
 * Ist der Inhalt kurz, aendert sich nichts: `sticky` wirkt erst, wenn wirklich
 * gerollt wird. */
.modalCard > .modalButtons:last-child
{
    position: sticky;
    bottom: -22px;
    z-index: 1;
    background: var(--surface);
    border-top: 1px solid var(--border);
    padding: 10px 24px 22px;
    margin-left: -24px;
    margin-right: -24px;
    margin-bottom: -22px;
}
.modalButtons .allow { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }

/* ----------------- Rueckfrage / Hinweis (statt confirm/alert) -----------------
 * Eine eigene Ebene UEBER allem anderen. Rueckfragen kommen naemlich oft aus
 * einem schon offenen Fenster heraus („Persona entfernen" im Chatfenster,
 * Sammelaktion in der Chatliste). Wuerde die Frage dessen Karte ersetzen,
 * waere der Dialog darunter nach dem Abbrechen verschwunden – man haette
 * abgebrochen und trotzdem etwas verloren.
 * 120 liegt ueber Modal (80), Persona-Anlegen (85) und Lightbox (100). */
.dialogOverlay { z-index: 120; padding: var(--sp-4); }
.dialogCard { width: min(440px, 92vw); }
/* Umbrueche im Fragetext bleiben stehen: In den alten confirm-Texten trennte
 * eine Leerzeile die Warnung von ihrer Einschraenkung („… bleiben erhalten"). */
.dialogText { margin: 0; color: var(--muted); font-size: 0.9em; white-space: pre-line; }
.dialogText.dialogFehler { color: var(--danger); }

/* ------------------------- „Mehr"-Menue (Bottom Sheet) -------------------------
 * EINE Darstellung fuer Chat und Studio – gebaut von nav.js, gestaltet hier.
 *
 * Vorher: im Chat ein mittiges Modal aus zeigeModal(), im Studio ein
 * zweispaltiges Popover ueber der Leiste. Dieselben Eintraege, zwei Optiken,
 * zwei Verhalten – und beide unvollstaendig (im Chat waren die Zeilen <div>
 * ohne Tastaturzugriff, im Studio versprach role="dialog" eine
 * Fokusbehandlung, die es nicht gab).
 *
 * Als BLATT VON UNTEN und nicht mittig: Der Ausloeser ist der letzte Knopf
 * der unteren Leiste. Ein Menue, das dort aufgeht, wo man getippt hat, ist am
 * Daumen erreichbar; ein mittiges Fenster zwingt die Hand quer ueber den
 * Bildschirm. Am Schreibtisch schadet es nichts – dort ist die Leiste
 * ausgeblendet und das Blatt einfach ein Fenster am unteren Rand.
 *
 * z-index 130: ueber der Tab-Leiste (55), ueber Modal (80) und ueber der
 * Rueckfrage-Ebene (120) – das Menue wird ueber allem geoeffnet, was gerade
 * offen ist, und darf nicht dahinter verschwinden. */
.mehrOverlay {
    position: fixed; inset: 0; z-index: 130;
    display: flex; align-items: flex-end; justify-content: center;
    background: rgba(0, 0, 0, 0.45);
}
.mehrBlatt {
    /*
     * NICHT 100 % – sonst klebt das Blatt an beiden Bildschirmrändern.
     * Nutzerbefund 27.08.2026 mit Bildschirmfoto: „etwas mehr Abstand
     * seitlich". Ein Blatt, das die volle Breite einnimmt, sieht nicht wie
     * ein Fenster über der Seite aus, sondern wie ein abgeschnittener Teil
     * davon.
     */
    width: min(520px, calc(100% - var(--sp-4) * 2));
    /* Ueber der Leiste und ueber dem Systemrand – sonst liegt die letzte
     * Zeile unter der Gestenleiste und ist nicht antippbar. */
    margin-bottom: calc(var(--tabbar-h) + var(--safe-bottom) + var(--sp-2));
    max-height: calc(100dvh - var(--tabbar-h) - var(--safe-bottom) - var(--sp-5));
    overflow-y: auto;
    padding: var(--sp-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-2);
}
/* Am Schreibtisch gibt es die feste Leiste nicht (sie ist erst mobil
 * sichtbar) – dann steht das Blatt mit normalem Abstand am unteren Rand. */
@media (min-width: 761px) {
    .mehrBlatt { margin-bottom: var(--sp-5); max-height: calc(100dvh - var(--sp-7)); }
}
.mehrTitel { margin: 0 0 var(--sp-3); font-size: 18px; }
.mehrListe { display: flex; flex-direction: column; gap: var(--sp-1); }
/* Gruppentitel (Nutzerwunsch 27.08.2026: „die Navi etwas strukturieren").
 * Sie entstehen nur, wenn die Gruppe auch einen sichtbaren Eintrag hat –
 * siehe nav.js. */
.mehrBlatt .mehrGruppe {
    margin: var(--sp-3) 0 var(--sp-1) var(--sp-3);
    color: var(--muted);
    font-size: .72rem; font-weight: 750;
    letter-spacing: .08em; text-transform: uppercase;
}
.mehrBlatt .mehrGruppe:first-child { margin-top: 0; }
/* ALLES unter .mehrBlatt gescoped, und das ist kein Stil-Geschmack: Die Klasse
 * `.mehrZiel` gibt es in app.css bereits fuer andere Menuezeilen (Wissensraum-
 * und Kapitelmenues, gebaut aus personaTextRow). Eine ungescopte Regel hier
 * wuerde denen Innenabstand, Mindesthoehe und Rundung aufdruecken – eine
 * Kaskadenkollision, die man erst am fertigen Bild sieht. */
.mehrBlatt .mehrZiel {
    display: flex; align-items: center; gap: var(--sp-3);
    min-height: var(--tap);
    padding: var(--sp-2) var(--sp-3);
    border-radius: 10px;
    color: var(--text); text-decoration: none;
}
.mehrBlatt .mehrZiel:hover { background: var(--surface-2); }
.mehrBlatt .mehrZiel.active { background: var(--accent-subtle); color: var(--accent-ink); }
.mehrBlatt .mehrZiel > .ico { flex: 0 0 24px; font-size: 18px; }
.mehrBlatt .mehrText { min-width: 0; display: flex; flex-direction: column; }
.mehrBlatt .mehrText strong { font-size: 0.92rem; font-weight: 650; }
.mehrBlatt .mehrText small {
    color: var(--muted); font-size: 0.78rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mehrBlatt .mehrSchliessen { width: 100%; margin-top: var(--sp-3); min-height: var(--tap); }

.redirectView {
    min-height: 100vh;
    display: grid;
    place-content: center;
    justify-items: center;
    gap: var(--sp-3);
    padding: var(--sp-5);
    color: var(--muted);
    text-align: center;
}
.redirectView p { margin: 0; }
.redirectView a { color: var(--accent-ink); }
