/* chat-o Räume – Stylesheet. Bis v1.9.2 stand das im <style> der worker.js. */

/* ============================================================
   v2.9.2: DESIGN-SYSTEM
   Alle Farben kommen aus diesen Variablen. Vorher standen ~60 verschiedene
   Hex-Werte verstreut im Stylesheet; jetzt gibt es eine Palette, die in
   Hell und Dunkel (Systemeinstellung) gleich lesbar ist. Kontraste sind
   auf WCAG AA ausgelegt (Text >= 4.5:1, gedaempfter Text >= 4.5:1 auf
   Flaechen).
   ============================================================ */
:root {
  color-scheme: light;
  /* v3.98.0 (Sören: „Können wir aus dem weiß noch etwas dunkleres
     gemütlicheres grau machen?"): Die Seite war reines Weiß. Jetzt ein
     warmes Hellgrau – 2 Punkte mehr Rot als Blau, das ist der Unterschied
     zwischen „Büro" und „Wohnzimmer".
     Die ABSTUFUNG bleibt, wie sie war: Seite heller als Fläche, Fläche
     heller als Feld. Dreht man das um, sieht eine Karte aus wie ein Loch. */
  --bg: #f4f3f1;              /* Seite */
  --surface: #ecebe8;         /* Karten, Zeilen, Eingabefelder */
  --surface-2: #e4e2dd;       /* gedrueckt, Chips */
  --border: #d8d6d1;          /* Haarlinien */
  --border-2: #737b89;        /* Rahmen von Feldern und Knoepfen */
  --text: #12131a;
  --text-2: #3d4250;
  --text-3: #5c6373;
  --muted: #585f6d;           /* Nebentext */
  --muted-2: #575e6c;         /* Platzhalter, Zeitstempel, ✕ */
  /* v2.10.6: --muted-2 hatte auf --bg/--surface nur ~2,8:1 - zu wenig fuer
     Symbole wie das Loeschkreuz; dafuer gibt es seither --icon-muted.
     v3.32.0: Beide Werte tragen die Schwelle jetzt selbst, --muted-2 kam von
     #9a9aa3 auf #5f6674. proben/probe-kontrast.mjs rechnet das bei jedem
     Deploy nach - wer hier etwas aendert, sieht dort sofort, ob es haelt. */
  --icon-muted: #5c6373;
  --primary: #12131a;         /* Hauptknoepfe, aktiver Reiter */
  --on-primary: #ffffff;
  --accent: #0a53c4;          /* Links, KI, Hervorhebung */
  --accent-strong: #0847ab;
  --accent-bg: #e8f0fe;
  --accent-border: #b9d2fb;
  --success: #0f7a3d;         /* Abhaken, Ungelesen */
  --success-text: #0d6633;
  --success-bg: #e3f5e9;
  --success-border: #a9dcbd;
  --danger: #b71f1f;
  --danger-bg: #fdeaea;
  --danger-border: #f0b9b9;
  --warn: #e8a317;
  --warn-text: #7a4d06;
  --warn-bg: #fdf3dd;
  --warn-border: #eccf8e;
  --purple: #6431bd;
  --purple-bg: #f1ebfd;
  --bubble-own: #d9f4c7;
  --bubble-other: #eff0f3;
  --bubble-ai: #0a52c9;
  --shadow-1: 0 1px 2px rgba(0,0,0,.06), 0 1px 1px rgba(0,0,0,.03);
  --shadow-2: 0 8px 24px rgba(0,0,0,.14);
  --shadow-sheet: 0 -8px 30px rgba(0,0,0,.18);
  --overlay: rgba(0,0,0,.45);
  /* v3.33.0: Ein Blatt hat eine Breite und eine Höhe. Vorher waren es acht
     Breiten (320 bis 560) und fünf Höhen - zwei nebeneinander geöffnete
     Blätter waren unterschiedlich groß. */
  --blatt-breit: 520px;
  --blatt-schmal: 340px;
  --blatt-hoch: min(88vh, calc(100% - 32px));
  /* ============================================================
     DIE ECKENLEITER (--r-xs … --r-kreis) steht seit v3.129.1 in
     public/leiter.css, nicht mehr hier. v3.85.0 (Sören: "Alles soll die
     gleiche Designsprache haben") hatte sie hier und in start.css
     abgeschrieben - die fünf eigenständigen Seiten luden keins von beiden
     und waren eine Woche lang eckig (Sören, 23.09.2026: "Du hast die
     designregeln ignoriert das anmeldefenster ist jetzt eckig").
     index.html lädt leiter.css VOR dieser Datei. LEITFADEN.md Teil 5.
     ============================================================ */
  /* Die alten Namen bleiben als ZEIGER - sonst müssten 28 Stellen mit,
     die heute schon ein Token benutzen. */
  --radius: var(--r-m);
  --radius-s: var(--r-s);
  --radius-l: var(--r-l);
  /* Schatten und Schrift gehören zur selben Sprache und werden von
     derselben Probe geprüft. */
  --shadow-keiner: 0 0 0 0 transparent;
  --shadow-ring-innen: inset 0 0 0 2px rgba(255,255,255,.35);
  --shadow-leiste: 0 -6px 24px rgba(0,0,0,0.22);
  --font-fest: ui-monospace, monospace;
  /* v3.95.0 (Sören: „Die reiter viel zu klein beschriftet" / „Reiter immer
     noch zu Klein"): Die Reiterschrift stand an DREI Stellen - in der
     Grundregel, in einer zweiten Regel weiter unten und in einer
     @media-Regel für Handys. Die dritte gewann und machte 0,78 rem daraus;
     meine ersten beiden Änderungen liefen deshalb ins Leere. Jetzt EIN
     Wert, drei Verweise (LEITFADEN.md Teil 1). */
  --reiter-schrift: 0.95rem;
  /* Ringe sind keine Schatten: Die DICKE kommt aus der Leiter, die FARBE
     von der Stelle. Benutzt wird das als `box-shadow: var(--ring-2)
     var(--accent)` - CSS setzt beides einfach hintereinander. So ist auch
     die Ringdicke Teil der Designsprache und nicht zwölfmal frei getippt. */
  --ring-0: 0 0 0 0;
  --ring-1: 0 0 0 1px;
  --ring-2: 0 0 0 2px;
  --ring-3: 0 0 0 3px;
  --ring-innen-1: inset 0 0 0 1px;
  --ring-innen-2: inset 0 0 0 2px;
  --ring: var(--ring-3) var(--accent);
  /* v2.9.3: Die Sicherheitsabstaende des Geraets als Variable - so kann auch
     ein Blatt sie beruecksichtigen (vorher lag der Titel eines Blatts auf
     dem iPhone hinter der Statusleiste). */
  --sat: env(safe-area-inset-top, 0px);
  /* v3.129.1 (Sören auf dem Samsung: „passt aber schau mal die untere
     kante wie doof das aussieht“): --sab ist jetzt die EINZIGE Stelle, die
     den unteren Rand liest. Der Browser meldete dort 48 px für seine
     Tastenleiste, obwohl die Seite über der Leiste endet - unter der
     Eingabezeile stand ein leeres Band. public/unterkante.js misst, wie
     weit die Seite wirklich in den unsicheren Streifen reicht, und setzt
     --sab an <html> kleiner, wenn sie es nicht tut. Jede Unten-Stelle
     benutzt var(--sab), nie env() selbst - sonst macht eine Stelle das
     Band allein wieder auf (proben/oberflaeche/unterkante-dom.mjs 1). */
  --sab: env(safe-area-inset-bottom, 0px);
  /* v3.32.0: Diese vier wurden im Stylesheet benutzt, aber nie definiert -
     `background: var(--card)` blieb dadurch durchsichtig (app.css 3688, 3699,
     3720, 3734, 3876), `--ok` fiel auf ein Gruen mit 1,98:1 zurueck. */
  /* v3.32.0: Sonderrollen, die vorher als harte Farbwerte mitten im
     Stylesheet standen. Jede ist in beiden Themen geprueft. */
  --auf-farbe: #ffffff;       /* Schrift auf Akzent/Grün/Rot */
  --stets-weiss: #ffffff;     /* v3.51.0: bleibt in beiden Themen weiss - Schalterknauf, PDF-Grund, Schrift auf der blauen KI-Blase */
  --band: #0e5741;            /* Band im Einkaufsmodus */
  --band-text: #eafff4;
  --band-punkt: #7ff0b4;
  --meldung: #1f2430;         /* Rueckgaengig-Leiste */
  --meldung-text: #ffffff;
  --meldung-aktion: #7fe3ff;
  --warn-auf: #3a2b06;        /* Schrift AUF einer Warnflaeche */
  --kal-aufgabe: #4f46c9;
  --auf-kal-aufgabe: #ffffff;
  --bild-grund: #15151a;      /* Vollbild fuer Anhaenge, bewusst dunkel */
  --card: #ffffff;
  --card-2: #f5f6f8;
  --ok: #0f7a3d;
  --leise: #616875;
  /* v3.142.1 (Sören: „Und den hinweis kleiner gestalten“): noch eine Stufe
     leiser als --muted der grauen Zeilen - NUR für den kleinen KI-Hinweis
     (.systemNote.leise). Prüfung: --leise war dunkel gleich --muted
     (#959cab), der Hinweis also im dunklen Thema nicht leiser. 4,91:1 auf
     --bg, 4,57:1 auf --surface (probe-kontrast). */
  --leise-2: #636a77;
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", Inter, sans-serif;
  /* v3.92.0 (Sören: „Alles soll modern klar organisch sein." – gewählt hat
     er nach der Schriftprobe „Charakter"). Die Charakterschrift steht NUR in
     den großen Zeilen: Datum, Kachelzahlen. Text, Reiter und Uhrzeiten
     bleiben --font. Grund: Eine Schrift mit Charakter ermüdet, wenn sie
     überall steht - und die Reiterleiste der Feier hat keine Reserve
     (gemessen: 350 von 360 px). Ein Token, damit ein Wechsel eine Zeile ist. */
  --font-gross: "Bricolage Grotesque", var(--font);
}
/* v3.92.0: SELBST GEHOSTET, nicht von Google. Ein <link> auf
   fonts.googleapis.com schickt die IP jedes Familienmitglieds bei jedem Start
   an Google; das LG München hat dafür 2022 Schadenersatz zugesprochen, und
   für einen kostenpflichtigen Dienst wäre das kein Restrisiko
   (DESIGN-VORSCHLAG.md). Die Datei liegt in public/ und in der Hülle
   (sw.js), damit sie auch im Funkloch da ist. 41 KB, lateinischer Schnitt. */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/BricolageGrotesque.woff2") format("woff2");
}
/* v3.47.0 (Paket 6, Befund D66): Alle Blaetter rechneten mit `vh`. Auf
   Mobil-Safari meint `vh` die Hoehe OHNE eingefahrene Leisten - bei
   ausgefahrener Adressleiste ragte ein 88-vh-Blatt unten aus dem Bild.
   `dvh` meint die Hoehe, die gerade wirklich da ist. Die alte Zeile bleibt
   oben stehen: Wer `dvh` nicht kennt, bekommt weiter `vh` statt gar nichts. */
@supports (height: 1dvh) {
  :root { --blatt-hoch: min(88dvh, calc(100% - 32px)); }
}
/* v2.9.3: Hell oder Dunkel entscheidet data-thema am <html>. Ein kurzes
   Skript im Kopf der Seite setzt es, noch bevor etwas gezeichnet wird:
   "auto" fragt das Geraet, sonst gilt die Wahl aus den Einstellungen.
   Deshalb steht hier keine Media Query mehr - sonst waere die Wahl
   nicht uebersteuerbar. */
/* 25.10.2026 (Beta kopf-einfarbig, Sören: „Der header ist immer noch 2 farbig“):
   Der Kopf ist dort schwarz wie die Systemleiste (--kopf-system, app-bausteine.css).
   Im HELLEN Thema trägt er darum die Tokens des DUNKLEN - dieselbe Liste, keine
   kopierten Farben. html.kopf-schmal setzt kopf-system.js nur unter 900 px. */
html.kopf-schmal.beta-kopf-einfarbig:not([data-thema="dunkel"]) #raumKopf,
html.kopf-schmal.beta-kopf-einfarbig:not([data-thema="dunkel"]) .raumKopfzeile,
:root[data-thema="dunkel"] {
    color-scheme: dark;
    --bg: #101116;
    --surface: #1a1c22;
    --surface-2: #24272f;
    --border: #2c2f38;
    --border-2: #79808f;
    --text: #eceef3;
    --text-2: #c2c7d2;
    --text-3: #a0a7b5;
    --muted: #959cab;
    --muted-2: #8e95a3;
    --icon-muted: #a0a7b5;   /* siehe :root; 7,8:1 auf --bg */
    --primary: #eceef3;
    --on-primary: #101116;
    --accent: #7fb0ff;
    --accent-strong: #a6c8ff;
    --accent-bg: #16233a;
    --accent-border: #2f4a7d;
    --success: #5ed48d;
    --success-text: #7fe0a6;
    --success-bg: #122a1c;
    --success-border: #2a5c3c;
    --danger: #ff8a80;
    --danger-bg: #33191a;
    --danger-border: #6d3230;
    --warn: #e8b451;
    --warn-text: #f2cf87;
    --warn-bg: #2e2410;
    --warn-border: #5f4c1f;
    --purple: #c3a4ff;
    --purple-bg: #26183d;
    --bubble-own: #1a3d24;
    --bubble-other: #26262d;
    --bubble-ai: #1f4fbb;
    --shadow-1: 0 1px 2px rgba(0,0,0,.4);
    --shadow-2: 0 8px 24px rgba(0,0,0,.6);
    --shadow-sheet: 0 -8px 30px rgba(0,0,0,.7);
    --overlay: rgba(0,0,0,.6);
    --auf-farbe: #101116;
    --band: #0e5741;
    --band-text: #eafff4;
    --band-punkt: #7ff0b4;
    --meldung: #e8eaf0;
    --meldung-text: #12131a;
    --meldung-aktion: #0a3f66;
    --warn-auf: #2a2205;
    --kal-aufgabe: #9b95f0;
    --auf-kal-aufgabe: #101116;
    --bild-grund: #15151a;
    --card: #1a1c22;
    --card-2: #24272f;
    --ok: #5ed48d;
    --leise: #959cab;
    --leise-2: #868d9b;   /* v3.142.1: 5,65:1 auf --bg, 5,11:1 auf --surface - leiser als --muted (6,84:1) */
    --ring: 0 0 0 3px #7fb0ff;
}

  * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
  html { -webkit-text-size-adjust: 100%; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
  body { color: var(--text); line-height: 1.4; }
  input, select, textarea, button { font-family: inherit; color: inherit; }
  input, select, textarea { background: var(--bg); }
  /* Grundform aller Textfelder - Felder ohne eigene Regel (z.B. im Reiter
     Essen) sahen vorher nach Browser-Standard aus. */
  :where(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]), select, textarea) {
    min-height: 44px; padding: 10px 12px; border: 1px solid var(--border-2); border-radius: var(--r-s);
    font-size: 16px; max-width: 100%;
  }
  :where(#essenView) .gerichteKopfLeiste input { width: 100%; }
  ::placeholder { color: var(--muted-2); opacity: 1; }
  /* Tastatur-Bedienung: jedes Element bekommt einen sichtbaren Fokusring,
     Maus und Finger nicht (focus-visible). */
  /* v3.37.0 (Paket 5, Befund D60): "outline: none" loescht die Anzeige des
     Browsers; der Ersatz haengt allein an :focus-visible. Kennt eine
     Umgebung das nicht (aeltere WebViews), gaebe es GAR KEINE Fokusanzeige
     mehr. Deshalb wird der Umriss nur dort entfernt, wo es einen Ersatz
     gibt. */
  @supports selector(:focus-visible) { :focus { outline: none; } }
  :focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-s); }
  button:focus-visible, a:focus-visible, [tabindex]:focus-visible { box-shadow: var(--ring); }
  input:focus-visible, select:focus-visible, textarea:focus-visible { box-shadow: var(--ring); border-color: var(--accent) !important; }
  ::selection { background: var(--accent-bg); }
  /* v23.34: Jeder Knopf gibt beim Antippen eine kurze Rueckmeldung. Vorher
     reagierte ausser "Erledigte weg" nichts - man wusste nie, ob der Tipp
     angekommen ist. Reines CSS, ohne JavaScript, ohne Verzoegerung. */
  button { cursor: pointer; font-family: inherit; touch-action: manipulation; }
  button:active, .item .check:active, .item .del:active, .item .calBtn:active,
  .lernZeile .weg:active, .kalTag:active, .systemNote:active, .lernStats:active {
    transform: scale(0.96); filter: brightness(0.9);
  }
  @media (prefers-reduced-motion: reduce) {
    button:active, .item .check:active, .item .del:active, .item .calBtn:active,
    .lernZeile .weg:active, .kalTag:active, .systemNote:active, .lernStats:active {
      transform: none;
    }
  }
  /* v23.31: Auf dem Handy hat sich beim Tippen die ganze SEITE verschoben -
     das Schreibfeld wanderte mit, der Chat war daneben nicht mehr lesbar.
     Die Seite selbst darf sich jetzt gar nicht mehr bewegen; gescrollt wird
     nur noch INNERHALB der Bereiche. */
  /* v23.33: Das Zittern beim Scrollen kommt daher, dass Safari beim
     Scrollen seine Leisten ein- und ausfaehrt. Dabei aendert sich die
     Fensterhoehe, damit 100dvh, damit die Hoehe der App - bei jedem
     Wisch. Und weil die Leiste manchmal schon weg ist, waehrend dvh noch
     den alten Wert meldet, blieb unten ein heller Streifen stehen.
     Beide Ursachen verschwinden, wenn die SEITE gar nicht mehr scrollt:
     dann faehrt auch keine Leiste. Gescrollt wird nur noch innerhalb der
     Bereiche. Wichtig: das gilt fuer body - NIEMALS fuer html. Genau
     dieser Fehler in v23.31 hat das Bild verrutschen lassen. */
  /* v23.36: Weiss statt Beige. iOS nimmt die Seitenfarbe fuer die Zonen
     um die Seite herum (Statusleiste, unterer Rand) - beige sah dort aus
     wie ein Fehler. */
  html {
    height: 100%;
    margin: 0;
    background: var(--bg);
  }
  body {
    position: fixed;
    inset: 0;
    overflow: hidden;
    overscroll-behavior: none;
    margin: 0;
    font-family: var(--font);
    background: var(--bg);
  }
  #app {
    display: flex;
    flex-direction: column;
    /* v23.37: Die App fuellt den fixierten body von Rand zu Rand. Die
       gemessene Hoehe (visualViewport) gilt NUR bei offener Tastatur -
       immer gesetzt liess sie unten einen Streifen frei, weil iOS dort
       weniger meldete, als die Seite hoch ist. */
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    /* v23.35: 14 px Luft ueber der Tableiste - sonst klebt sie an der
       Statusleiste und liegt halb in deren Unschaerfe. Der untere Rand
       gehoert jetzt der Eingabezeile bzw. den Listen selbst. */
    /* v3.33.0: Das Demo-Band liegt fest oben. #app ist absolut positioniert
       und ignoriert das Polster am body, also kommt der Platz hier dazu -
       sonst deckt das Band den Raumkopf zu. Ohne Band ist die Variable
       nicht gesetzt und es bleibt bei den 24 px. */
    padding-top: calc(env(safe-area-inset-top, 0px) + 24px + var(--demoband-versatz, 0px));
    padding-bottom: 0;
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    box-sizing: border-box;
    max-width: 480px;
    margin: 0 auto;
    background: var(--bg);
  }
  /* Bei offener Tastatur: so hoch wie wirklich sichtbar, und um den
     Betrag nach unten geschoben, um den Safari die Seite hochzieht. */
  body.tastatur #app {
    bottom: auto;
    height: var(--app-hoehe, 100%);
    transform: translateY(var(--app-versatz, 0px));
  }

  /* --- Setup-Overlay --- */
  /* v3.47.0 (Paket 6, Befund D64): Die Maske war `inset: 0` mit
     `justify-content: center` und OHNE overflow. Im Querformat (390 px Hoehe)
     passten Logo, Claim, zwei grosse Knoepfe, Trenner und die zwei
     Familien-Knoepfe nicht hinein - der Ueberschuss wurde oben UND unten
     abgeschnitten und war nicht erreichbar, weil zentrierter Inhalt in einer
     Flex-Spalte ueber den Anfang hinauswaechst.
     `safe center` zentriert nur, solange der Platz reicht, und rueckt sonst
     an den Anfang; zusammen mit overflow-y wird alles erreichbar. Die Zeile
     davor bleibt als Rueckfall fuer Browser ohne `safe` stehen - dort ist
     wenigstens der untere Teil scrollbar. */
  #setup {
    position: fixed; inset: 0; background: var(--bg);
    display: flex; flex-direction: column; align-items: center;
    justify-content: center;
    justify-content: safe center;
    overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    gap: 14px;
    padding: max(24px, var(--sat)) 24px max(24px, var(--sab)); z-index: 20;
  }
  /* Ohne das schrumpfen die Bloecke in der scrollbaren Spalte, statt zu
     scrollen - dann waere der Text im Querformat gestaucht statt erreichbar. */
  #setup > * { flex: none; }
  #setup h2 { margin: 0 0 4px; }
  #setupName, #setupRole, #setupGuestKey {
    display: flex; flex-direction: column; align-items: center; gap: 14px;
  }
  /* v3.87.0 – WARUM HIER :where() STEHT (gemessen, nicht geraten)
     „Behälter + Element" wie `#setup button` wiegt (1,0,1) und schlägt
     damit JEDE einfache Bauteil-Klasse (0,1,0) im selben Behälter – auch
     jedes Bauteil, das erst später hineingelegt wird. So gefunden wurden
     sieben Stellen, u. a. `.keyZeigen` (der Knopf wurde 220 px breit, die
     Zeile lief bei 390 px auf 448 px hinaus und war abgeschnitten) sowie
     `.teilWahlChip` und `.mengeKnopf` (grün wie ein Hauptknopf statt
     graue Pille – die angetippten Chips sahen richtig aus, die NICHT
     angetippten grün).
     Bisher wurden die Ausnahmen einzeln nachgetragen
     (`#setup button.zurueckLink`, `:not(.woandersBtn)` in v3.86.0) –
     wieder eine zweite Liste, die zur ersten passen muss
     (LEITFADEN.md Teil 1). Mit :where() zählt nur noch das Element:
     (0,0,1). Die Regel bleibt eine Vorgabe, jedes Bauteil darf sie
     überschreiben, und die Ausnahmen mit Attribut-Wähler
     ([type="checkbox"] …) gewinnen weiterhin. */
  :where(#setup) button {
    width: 220px; padding: 14px; border: none; border-radius: var(--r-s);
    background: var(--primary); color: var(--on-primary); font-size: 1rem; font-weight: 600;
  }
  #setup input {
    width: 220px; padding: 12px; border: 1px solid var(--border-2); border-radius: var(--r-s); font-size: 16px;
    text-align: center; letter-spacing: 0.06em;
  }
  /* v1.3.0 */
  #setupLogo { font-size: 1.7rem; font-weight: 800; letter-spacing: -0.02em; margin: 0 0 6px; }
  #setup .hint { margin: 0; color: var(--text-3); font-size: 0.92rem; }
  #setup button.zweit { background: var(--bg); color: var(--text); border: 1px solid var(--border-2); }
  #setup button.zurueckLink {
    background: none; color: var(--accent); font-weight: 600; padding: 8px; width: auto; min-height: 44px;
  }
  #setupFehler {
    max-width: 260px; text-align: center; font-size: 0.92rem; line-height: 1.35;
    color: var(--danger); background: var(--danger-bg); border: 1px solid var(--danger-border);
    border-radius: var(--r-s); padding: 10px 12px;
  }

  /* --- Tabs --- */
  /* v3.33.0: eine Stufe über der Trefferfläche der Datumszeile - sonst fängt
     diese die obersten 8 px jedes Reiters ab. */
  /* v3.91.0: :where() um den Behälter - siehe app-bausteine.css.
     Diese Regeln wogen „Behälter + Element/Klasse" und schlugen damit jede
     Baustein-Klasse. In :where() zählt der Behälter nicht mehr mit; die
     Regel gilt unverändert, verliert aber gegen eine Klasse. Kein
     !important nötig. */
  :where(#tabs) { display: flex; border-bottom: 1px solid var(--border); background: var(--bg); position: relative; z-index: 2; }
  /* Raeume-Fassung */
  /* v1.8.0: Links der Zurueck-Knopf, rechts das Zahnrad - beide Seiten
     gleich breit, damit der Raumname wirklich in der Mitte steht. Vorher
     hing das Zahnrad in der KI-Leiste darunter, die im Projekt-Raum sonst
     leer war und nur Platz gefressen hat. */
  :where(#raumKopf) { align-items: center; gap: 4px; padding: 0 6px 4px; background: var(--bg); }
  :where(#raumKopf) .raumZurueck { border: none; background: none; color: var(--accent); font-size: 1rem; font-weight: 600;
    padding: 8px 6px; min-height: 44px; flex: 0 0 88px; text-align: left; white-space: nowrap; }
  :where(#raumKopf) .raumTitel { font-weight: 700; font-size: 1.05rem; flex: 1; min-width: 0; text-align: center;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  :where(#raumKopf) .raumKopfRechts { flex: 0 0 88px; display: flex; justify-content: flex-end; }
  :where(#raumKopf) .keyBtn { border: none; background: none; font-size: 1.15rem; width: 44px; height: 44px; padding: 0; }
  #raumView { flex: 1; overflow-y: auto; padding: 4px 12px calc(12px + var(--sab)); }
  .raumKopfzeile { display: flex; align-items: center; justify-content: space-between; padding: 6px 2px 10px; }
  .raumKopfzeile h2 { margin: 0; font-size: 1.5rem; }
  .raumKopfKnoepfe { display: flex; gap: 6px; }
  .raumKopfKnoepfe .keyBtn { border: none; background: none; font-size: 1.15rem; width: 44px; height: 44px; }
  .raumEintrag { display: flex; align-items: center; gap: 12px; padding: 12px 6px; border-bottom: 1px solid var(--border);
    cursor: pointer; min-height: 64px; }
  .raumEintrag:active { background: var(--surface-2); }
  .raumSymbol { width: 48px; height: 48px; border-radius: var(--r-l); background: var(--surface); display: flex; align-items: center;
    justify-content: center; font-size: 1.5rem; flex: none; }
  .raumText { flex: 1; min-width: 0; }
  .raumName { font-weight: 700; font-size: 1rem; display: flex; justify-content: space-between; gap: 8px; }
  .raumName .zeit { font-weight: 400; font-size: 0.78rem; color: var(--muted); flex: none; }
  .raumVorschau { color: var(--muted); font-size: 0.86rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
  .raumUngelesen { background: var(--success); color: var(--auf-farbe); border-radius: var(--r-m); min-width: 22px; height: 22px; padding: 0 7px;
    font-size: 0.78rem; font-weight: 700; display: flex; align-items: center; justify-content: center; flex: none; }
  /* v3.32.0: .55 drueckte den Text auf 2,18:1. Der Block bleibt gedimmt,
     aber lesbar; die Kennzeichnung traegt ohnehin das Wort „Archiviert“. */
  .raumEintrag.archiviert { opacity: .78; }
  /* v2.40.0: Kleine Darstellung - eine Zeile, halbes Symbol, keine
     Vorschau. Für Räume, die man selten braucht, aber nicht archivieren
     will. Die Tipphöhe bleibt über 44px, sonst trifft man daneben. */
  /* min-height muss mit: Die normale Zeile hält 64px, sonst spart "klein"
     nur die Vorschauzeile und sieht fast gleich aus (gemessen: 72 -> 64px,
     also 8px - das ist kein Unterschied, den jemand bemerkt). 46px ist
     die kleinste Höhe, die man auf dem Handy noch sicher trifft. */
  .raumEintrag.klein { padding: 5px 6px; gap: 10px; min-height: 46px; }
  .raumEintrag.klein .raumSymbol { width: 30px; height: 30px; border-radius: var(--r-m); font-size: 1rem; }
  .raumEintrag.klein .raumName { font-size: 0.92rem; }
  /* Ordnen-Modus: die Knopfreihe rechts, der Eintrag selbst ist kein Knopf mehr. */
  .raumEintrag.ordnen { cursor: default; }
  /* v3.20.0: fünf Knöpfe (▲▼ ⤡ 📦 🗑) passen auf einem schmalen Handy nicht
     in eine Reihe - sie brechen um, statt den Raumnamen zu quetschen. */
  .raumOrdnenKnoepfe { display: flex; gap: 4px; flex: none; flex-wrap: wrap; justify-content: flex-end; max-width: 126px; }
  .ordnenBtn {
    width: 44px; min-height: 44px; border-radius: var(--r-s);
    border: 1px solid var(--border-2); background: var(--bg);
    color: var(--text-2); font: inherit; font-size: 0.92rem; cursor: pointer;
  }
  .ordnenBtn:disabled { opacity: 0.3; cursor: default; }
  .ordnenBtn[aria-pressed="true"] { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
  .ordnenBtn.gefahr { border-color: var(--danger-border); color: var(--danger); background: var(--danger-bg); }
  .raumOrdnenFuss { display: flex; gap: 8px; align-items: center; justify-content: space-between; margin-top: 14px; flex-wrap: wrap; }
  .raumOrdnenFertig {
    flex: 1; min-height: 46px; border: 0; border-radius: var(--r-m);
    background: var(--primary); color: var(--on-primary); font: inherit; font-weight: 700; cursor: pointer;
  }
  /* v3.132.0: kein eigener Balken mehr (die Gruppe ist ein Abschnitt) - die
     fremde Gruppe erkennt man am Raum-Kärtchen und an der Akzentschrift. */
  .fremdGruppe .groupHeader { color: var(--accent-strong); }
  .andereGast { display: flex; align-items: center; gap: 8px; padding: 8px 0; border-top: 1px solid var(--border); }
  .andereGast button { min-height: 40px; border: 1px solid var(--accent); color: var(--accent); background: var(--bg); border-radius: var(--r-s); padding: 6px 12px; font-weight: 600; }
  /* v1.3.1: endgueltig loeschen */
  .andereGast .wer { flex: 1; min-width: 0; }
  .andereGast .wer .nam { font-size: 0.92rem; }
  .andereGast .wer .wo { font-size: 0.78rem; color: var(--muted); }
  .loeschBtn {
    min-height: 40px; border: 1px solid var(--danger) !important; color: var(--danger) !important;
    background: var(--bg); border-radius: var(--r-s); padding: 6px 11px; font-weight: 600;
  }
  #raumAndere .gruppe { margin-top: 14px; }
  /* v23.10: fuenf Tabs muessen auf ein schmales Handy passen, ohne
     umzubrechen - deshalb kleinere Schrift und Zeilenumbruch aus. */
  /* v1.8.0: Reicht der Platz nicht (fuenf Reiter auf 320 px, sechs im
     Projekt-Raum), wurde "Gäste" rechts einfach abgeschnitten. Jetzt
     schrumpft kein Wort mehr - die Leiste laesst sich stattdessen seitlich
     wischen, und der aktive Reiter wird beim Wechsel ins Bild geholt. */
  #tabs { overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain; }
  #tabs::-webkit-scrollbar { display: none; }
  /* Weicher Verlauf am rechten Rand, solange rechts noch Reiter liegen -
     sonst weiss niemand, dass man wischen kann. Klebt per sticky am Rand
     und faehrt mit; die Klasse setzt das Skript beim Scrollen. */
  /* Breite, Rand, Reihenfolge und Zeichen der beiden Verläufe: gleich
     darunter (v3.146.0) - je eine Zahl, nicht hier ein zweites Mal. */
  #tabs::after { position: sticky; right: 0; flex: none;
    align-self: stretch; pointer-events: none; opacity: 0; transition: opacity .15s;
    background: linear-gradient(90deg, transparent, var(--reiter-grund, var(--bg)) 70%); }
  #tabs.wischbar::after { opacity: 1; }
  #tabs::before { position: sticky; left: 0; flex: none; z-index: 1;
    align-self: stretch; pointer-events: none; opacity: 0; transition: opacity .15s;
    background: linear-gradient(270deg, transparent, var(--reiter-grund, var(--bg)) 70%); }
  #tabs.wischbarLinks::before { opacity: 1; }
  /* ============================================================
     v3.146.0 – DIE LEISTE ZUM WISCHEN (bis v3.148.0 hinter Beta
     „reiter-scrollen“; seit v3.149.0 für alle – Sören hat sie am
     06.10.2026 in der Prüfliste freigegeben)
     Sören (05.10.2026): „Reiterleise scrollbar machen“

     GEMESSEN an v3.145.0 (Chromium, echte Berührung über CDP, 390 und
     320 px, alle drei Raumtypen): Die Leiste rollt schon quer, und ein
     Wisch auf ihr wechselt keinen Reiter. Was fehlte, war zu SEHEN:
     1. Im Haushalt gab es den Verlauf am rechten Rand gar nicht. Die eigene
        Reihenfolge (v3.81.0) gibt jedem Haushalts-Reiter order 1–9, auch
        in der Standard-Folge. ::after hat order 0 und stand damit VOR dem
        ersten Reiter – mit seinem negativen Rand links außerhalb des
        Bildes. Die Feier hatte dafür eine eigene Regel (order: 10, weiter
        unten), der Haushalt nie. reiterband-dom 2 prüfte nur die Klasse
        „wischbar“, nicht, wo der Verlauf steht – darum blieb es grün.
     2. Ein weicher Rand allein zeigt nicht verlässlich, dass es weitergeht.
        Was unter seinem deckenden Teil liegt, ist unsichtbar: Auf 320 px
        verschwand „Au(fgaben)“ ganz, und die Leiste sah aus, als ende sie
        bei „Termine“; in der Feier auf 390 px blendete nur „Einkauf“ aus.
        Nachgerechnet für jeden Verlauf (28–64 px, 70 oder 100 % deckend,
        85 % Endwert) über alle Breiten von 320 bis 480 px: Bei rund einem
        Drittel der Randlagen fällt die Lücke zwischen zwei Wörtern genau
        unter den Rand, und KEIN angeschnittenes Wort ist zu sehen. Das
        hängt an der Schrift – auf dem iPhone fallen die Wörter anders.
     3. Beim Wechsel holte reiterInsBild den Reiter nur bis 12 px an den
        Rand – unter den Verlauf, und vom nächsten Reiter war nichts zu
        sehen (app.js reiterInsBild).

     Die Antworten:
     - order -999/999: die Verläufe vor bzw. hinter JEDEM Reiter, egal
       welche Reihenfolge jemand eingestellt hat (eigene Folge 1–9, Feier
       1–10). Eine Zahl „hinter allem“ statt einer Liste der Reiter – die
       eigene Regel der Feier (#tabs.eventReiter::after, order 10) ist
       darum seit v3.149.0 weg.
     - 44 px statt 28 – breit genug, dass der Nachbar beim Wechsel
       angeschnitten hervorschauen kann (reiterInsBild liest die Breite
       hier ab, keine zweite Zahl im Skript).
     - Ein Weiter-Zeichen (‹ ›) im deckenden Ende des Verlaufs: Es steht
       da, wo es weitergeht, egal wo die Wörter fallen, und verschwindet
       mit dem Verlauf. Farbe wie ein Reiter, der nicht offen ist (--muted,
       4,5:1 hell und dunkel). Es fängt keinen Tipp ab (pointer-events:
       none): Ein Tipp dort öffnet den Reiter darunter – den nächsten.
       Für Vorleser ist es leer („/ ""“; ältere Browser nehmen die Zeile
       davor). reiter-scrollen-dom.mjs S2 misst es an den Bildpunkten.

     NICHT touch-action: pan-x. Der erste Bau gab der Leiste pan-x, damit
     „ein schräger Daumen nicht als senkrechter Versuch gelesen wird“. Mit
     echter Berührung gemessen war es umgekehrt: Ab 45° und bei einem Bogen,
     der erst ein paar Pixel hoch und dann quer geht, verwirft der Browser
     die Geste – 0 px statt 110–160 px. Ohne pan-x rollt die Leiste wie in
     v3.145.0 (GESTEN.md Teil 4; S4 der Probe zieht jeden dieser Wege mit
     echter Berührung). Soll pan-x für das iPhone wiederkommen, dann nur
     nach einer Messung auf dem Gerät.
     ============================================================ */
  #tabs::before,
  #tabs::after { width: 44px; box-sizing: border-box; display: flex; align-items: center;
    padding: 4px 3px 0; color: var(--muted); font-size: var(--reiter-schrift); font-weight: 700; line-height: 1; }
  #tabs::before { order: -999; margin-right: -44px; justify-content: flex-start;
    content: "‹"; content: "‹" / ""; }
  #tabs::after { order: 999; margin-left: -44px; justify-content: flex-end;
    content: "›"; content: "›" / ""; }
  :where(#tabs) button {
    position: relative;
    /* Bei genug Platz teilen sich alle Reiter die Breite; ist es eng,
       behaelt jeder seine Wortbreite und die Leiste wird wischbar. */
    flex: 1 0 auto; padding: 16px 10px 12px; min-height: 50px;
    border: none; background: none;
    /* v3.95.0 (Sören: „Die reiter viel zu klein beschriftet", „Reiter immer
       noch zu Klein"): 0,82 rem waren 13 px. Jetzt 0,95 rem. Die Leiste
       wischt seitlich, wenn es eng wird - das tut sie im Haushalt seit
       v1.8.0, und Sören hat sich in v3.81.0 ausdrücklich dafür entschieden
       („Lieber wieder auf das alte Scrollen zurück"). */
    font-size: var(--reiter-schrift); font-weight: 600; color: var(--muted);
    border-bottom: 2px solid transparent;
    white-space: nowrap;
  }
  /* Der aktive Tab wird nicht fetter, sonst springt die Leiste. */
  :where(#tabs) button.active { font-weight: 700; }
  /* v3.44.0: Der Strich ist kein border-bottom mehr, sondern ein eigener
     Balken (#reiterStrich) - nur der kann beim Wischen mitwandern. Die
     Farbe bleibt am aktiven Knopf, der Strich kommt von unten. */
  :where(#tabs) button.active { color: var(--text); }
  #reiterStrich { position: absolute; left: 0; bottom: 0; height: 2.5px;
    background: var(--text); border-radius: var(--r-xs) var(--r-xs) 0 0; opacity: 0;
    pointer-events: none; z-index: 3;
    transition: transform .2s cubic-bezier(.25,.6,.25,1), width .2s cubic-bezier(.25,.6,.25,1), opacity .15s; }
  @media (prefers-reduced-motion: reduce) { #reiterStrich { transition: none; } }
  /* Das Abzeichen sitzt UEBER dem Wort statt dahinter - sonst bleibt fuer
     "Besorgungen" auf einem 390px-Bildschirm kein Platz. */
  :where(#tabs) .badge {
    position: absolute; top: 2px; left: 50%; transform: translateX(-50%);
    background: var(--success); color: var(--auf-farbe);
    font-size: 0.7rem; line-height: 1.4; border-radius: var(--r-s); padding: 0 5px;
    font-variant-numeric: tabular-nums;
  }

  /* --- Chat --- */
  #chatView { flex: 1; display: flex; flex-direction: column; min-height: 0; position: relative; }
  /* v23.34: Wer hochgescrollt hat, sieht neue Nachrichten als Zaehler auf
     einem Pfeil, statt sie zu verpassen. Sitzt ueber der Eingabezeile. */
  #nachUnten { display: none; position: absolute; right: 14px; bottom: calc(76px + var(--sab)); z-index: 5;
    min-width: 44px; height: 44px; border-radius: var(--r-l); border: none; padding: 0 12px;
    background: var(--primary); color: var(--on-primary); font-size: 1.05rem; font-weight: 700;
    box-shadow: var(--shadow-2); align-items: center; justify-content: center; gap: 5px; }
  #nachUnten.sichtbar { display: flex; }
  #nachUnten .zahl { display: none; background: var(--success); color: var(--auf-farbe); border-radius: var(--r-s);
    font-size: 0.78rem; padding: 1px 7px; font-variant-numeric: tabular-nums; }
  #nachUnten .zahl.hat { display: inline-block; }
  /* v23.33: Die Leiste ist am Handy auf ZWEI Zeilen umgebrochen und hat
     damit ein Sechstel des Bildes gefressen. Jetzt bleibt sie einzeilig:
     die Statistik kuerzt bei Bedarf, die Knoepfe stehen fest rechts. */
  #aiSettings {
    display: flex; align-items: center; gap: 6px; padding: 6px 10px; flex-wrap: nowrap;
    border-bottom: 1px solid var(--border); background: var(--surface); font-size: 0.78rem; color: var(--text-3);
  }
  #aiSettings label.confirmToggle {
    display: flex; align-items: center; gap: 5px; white-space: nowrap;
    flex: 0 0 auto; min-width: 0;
  }
  #aiSettings label.confirmToggle input { width: 20px; height: 20px; flex: none; margin: 0; }
  /* v1.8.0: Ohne das Zahnrad ist in der Leiste wieder Platz. Auf ganz
     schmalen Geraeten faellt nur noch das "immer" weg - ein nacktes
     Kaestchen ohne Wort (so war es bis 345 px) versteht niemand. */
  /* v3.47.0 (Paket 6, Befund D67): Die Grenze lag bei 340 px - eine Breite,
     die kaum ein Geraet mehr hat. Das Gedraenge in der Leiste beginnt aber
     schon bei 360 px, also genau auf den meistverkauften Handys. */
  @media (max-width: 380px) {
    #aiSettings .wegAufSchmal { display: none; }
  }
  /* Im Projekt-Raum ist die Leiste leer (kein Lexikon, kein Nachfragen) -
     dann verschwindet sie ganz statt einen leeren Streifen zu lassen. */
  #aiSettings.leer { display: none !important; }
  /* Die Kurzform ist so schmal, dass sie nie schrumpfen muss - sonst
     bleibt vom "48" nur das Gehirn-Zeichen uebrig. */
  #aiSettings .lernStats { white-space: nowrap; flex: none; }
  #aiSettings button.keyBtn {
    flex: none; border: none; background: none; font-size: 1rem;
    width: 32px; height: 32px; padding: 0; opacity: 0.65; position: relative;
  }
  /* v23.34: Die Symbole bleiben 32 px gross, die TREFFFLAECHE ist 44 px. */
  #aiSettings button.keyBtn::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 44px; height: 44px; transform: translate(-50%, -50%);
  }
  #aiSettings .lernStats { padding: 8px 0; }
  .promptRow { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
  /* v23.34: 44 px Mindesthoehe - die Knoepfe in den KI-Karten waren mit
     28 px die kleinsten der ganzen App, ausgerechnet dort, wo man
     entscheidet. */
  .promptRow button {
    background: rgba(255,255,255,0.2); border: 1px solid rgba(255,255,255,0.4); color: white;
    border-radius: var(--r-s); padding: 10px 14px; min-height: 44px; font-size: 0.86rem; font-weight: 600;
  }
  #messages { flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 6px;
    /* Der Chat scrollt fuer sich - ohne die Seite darunter mitzuziehen. */
    overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    /* v3.129.0 (GESTEN.md Regel 10): Dieser Scroller traegt pan-y SELBST -
       Chromium gibt an jedem Scroll-Container das Schwenken neu frei, das
       pan-y von #chatView kam hier nie an. Ohne diese Zeile blaettert der
       Chat auf Android nicht (siehe app-bausteine.css bei .bsWischt). */
    touch-action: pan-y; }
  /* Bei offener Tastatur gibt es unten keinen Rand zu umgehen - der wuerde
     nur Platz kosten, den man zum Lesen braucht. */
  body.tastatur #inputRow { padding-bottom: 10px; }
  body.tastatur #nachUnten { bottom: 76px; }
  .bubble {
    max-width: 75%; padding: 8px 12px; border-radius: var(--r-m); font-size: 0.92rem;
    line-height: 1.3; word-wrap: break-word; position: relative;
  }
  .bubble.own { align-self: flex-end; background: var(--bubble-own); border-bottom-right-radius: var(--r-xs); }
  .bubble.other { align-self: flex-start; background: var(--bubble-other); border-bottom-left-radius: var(--r-xs); }
  .bubble.ai {
    align-self: center; max-width: 88%; background: var(--bubble-ai); color: white;
    border-radius: var(--r-m); text-align: left;
  }
  .bubble.ai .meta { color: rgba(255,255,255,0.75); }
  /* v2.24.0: Der Sprungknopf ("Ausgaben ansehen ->") in der blauen KI-Blase
     war hellgrau mit weisser Schrift - kaum zu lesen. Weiss auf Blau, wie
     die Rueckgaengig-Knoepfe in der Karte. */
  /* v3.139.0 (Sören: „Oder rückgängig machen button in ki blase“): Neben dem
     Sprungknopf steht jetzt das Rückgängig der ✨-Blase. Beide Knöpfe der
     Reihe sehen gleich aus - Weiss auf Blau; Ecke und Schrift teilen sie mit
     dem Rückgängig der grauen Zeile (EINE Regel, bei .systemNote
     button.undoBtn unten; die Ecke fehlte dem Sprungknopf bis hierher ganz,
     er war eckig). Die Reihe bricht um, wenn beide nicht nebeneinander
     passen (390 px). Der Zustand danach („rückgängig gemacht“ und was nicht
     zurückging) steht in der Schrift der Blase: das Grau der Systemzeile
     (--text-3) wäre auf Blau nicht zu lesen. */
  .bubble.ai .sysDetail { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 6px; }
  .bubble.ai .sysDetail .undoBtn { border: 1px solid rgba(255,255,255,0.55); background: rgba(255,255,255,0.15); color: var(--stets-weiss); min-height: 44px; }
  /* Nachbesserung v3.139.0 (Gegenprüfung): Der Fokusring (--ring, in der
     Farbe --accent) lag im hellen Thema mit 1,01:1 auf dem Blau der Blase -
     per Tastatur sah man nicht, welcher Knopf dran ist. Das galt schon für
     alle Knöpfe der ✨-Blase; auf Blau ist der Ring weiss. */
  .bubble.ai button:focus-visible { box-shadow: var(--ring-3) var(--stets-weiss); }
  .bubble.ai .sysDetail .systemZeit { color: inherit; font-size: 0.78rem; }
  .bubble.ai .sysDetail .undoRest { flex: 1 1 100%; }
  .bubble.ai .label {
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase;
    opacity: 0.85; margin-bottom: 3px;
  }
  .erkennungZeile { font-size: 0.92rem; margin: 2px 0; }
  .erkennungHinweis { font-size: 0.82rem; opacity: 0.85; margin: 6px 0 2px; line-height: 1.35; }
  .erkennungZusatz { opacity: 0.8; font-size: 0.86rem; }
  .erkennungDone { font-size: 0.82rem; opacity: 0.9; margin-top: 8px; font-weight: 600; }
  .feedbackRow { display: flex; gap: 8px; margin-top: 6px; }
  .feedbackRow button {
    background: rgba(255,255,255,0.15); border: none; border-radius: var(--r-s);
    padding: 6px 14px; min-height: 40px; min-width: 48px; font-size: 1rem;
  }
  .feedbackDone { font-size: 0.7rem; opacity: 0.8; margin-top: 6px; }
  /* v23.8: schlanke Zeile statt grauer Blase. Rueckgaengig und Zeit
     erscheinen erst beim Antippen - im Ruhezustand nur eine Zeile. */
  .systemNote {
    align-self: stretch; max-width: 100%; text-align: left;
    background: none; color: var(--muted); border-radius: 0;
    padding: 4px 4px 4px 4px; font-size: 0.82rem; margin: 1px 0;
    /* v3.99.0: min-height 44 (einheitlich-dom 3). Die Zeile ist role=button
       mit tabindex - dahinter steckt "↩︎ Rückgängig", laut dem Kommentar von
       v3.37.0 die wichtigste Korrektur der App. Bei 26 px war sie kaum zu
       treffen. align-items von baseline auf center, sonst klebte der Text
       bei mehr Höhe oben. */
    min-height: 44px;
    display: flex; align-items: center; gap: 6px; cursor: pointer;
    border-left: 2px solid var(--border);
    /* v3.135.0 (Sörens Bild vom iPhone, 25.09.2026: „Ansicht komplett
       verbuggt“): Aufgeklappt lag .sysDetail in DERSELBEN Flex-Zeile wie der
       Text. Bei 390 px nahmen „↩︎ Rückgängig“, „Im Kalender ansehen →“ und
       die Uhrzeit die Breite, der Text wurde zu einer Spalte von 13 px -
       jedes Wort eine Zeile, 354 px hoch (gemessen). Und weil min-height
       (v3.99.0) das automatische Mindestmaß eines Flex-Kindes ersetzt,
       durfte #messages (flex column) die Zeile auf 152 px zusammendrücken:
       Der Text lief 94 px über die nächsten Zeilen. Jetzt bricht die Zeile
       um (der Detail-Teil steht darunter, siehe .sysDetail), und sie wird
       nie kleiner als ihr Inhalt. */
    flex-wrap: wrap; flex-shrink: 0;
  }
  .systemNote .sysText { flex: 1; min-width: 0; line-height: 1.35; }
  .systemNote .sysDetail { display: none; margin-top: 4px; flex: 1 0 100%; }
  .systemNote.offen { color: var(--text-3); border-left-color: var(--muted-2); }
  .systemNote.offen .sysDetail { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  .systemNote .sysSpring { color: var(--accent); font-weight: 600; }
  /* v3.139.0: Form des Rückgängig - für die graue Zeile UND die ✨-Blase
     (abgeleitet, nicht abgeschrieben; LEITFADEN Teil 1). Farbe, Rand und
     Höhe setzt jede Umgebung selbst. */
  .systemNote button.undoBtn, .bubble.ai .sysDetail .undoBtn {
    border-radius: var(--r-s); padding: 8px 13px; font-size: 0.78rem; font-weight: 600;
  }
  .systemNote button.undoBtn {
    border: 1px solid var(--muted-2); background: none; color: var(--text-3); min-height: 40px;
  }
  .systemZeit { color: var(--text-3); font-size: 0.7rem; }
  /* v23.38: Tages-Trennzeile im Chat. */
  /* v2.15.0: Die Trennzeile klebt jetzt oben am Rand, solange man in ihrem
     Tag scrollt. Vorher stand das Datum nur EINMAL zwischen den Blasen -
     wer weiter oben las, sah nur noch Uhrzeiten und wusste nicht mehr, von
     welchem Tag sie stammen. Der Kniff ist derselbe wie in jedem Messenger.
     z-index 2, damit sie ueber den Blasen liegt, aber unter dem Blatt. */
  /* v3.4.0 (Sören: "das Feld Heute oben im Chat ist komisch"): nicht mehr
     klebend - das Schild lag beim Rollen mitten auf einer Blase. */
  #messages .tagTrenner { position: static; pointer-events: none; }
  .tagTrenner { display: flex; justify-content: center; margin: 10px 0 6px; }
  /* Auf dem klebenden Streifen muss die Schrift auch dann lesbar sein, wenn
     eine Blase darunter durchlaeuft - deshalb ein voller Hintergrund. */
  #messages .tagTrenner span { box-shadow: none; }
  .tagTrenner span { background: var(--surface-2); color: var(--text-3); font-size: 0.7rem; font-weight: 600;
    padding: 4px 11px; border-radius: var(--r-m); letter-spacing: .01em; }
  .bubble .meta { font-size: 0.7rem; color: var(--text-3); margin-top: 3px; } /* v3.142.0: Rolle siehe unten (.bubble .meta, D11) */
  /* v23.35: Die Zeile reicht bis an die Unterkante; der Safe-Area-Rand
     liegt IN ihr, nicht mehr als leerer Streifen darunter.
     v3.129.1: ...und zwar nur so viel davon, wie die Seite wirklich
     verdeckt (--sab, siehe :root und public/unterkante.js). */
  #inputRow { display: flex; gap: 8px; padding: 10px 10px calc(10px + var(--sab));
    border-top: 1px solid var(--border); background: var(--bg); flex: none; align-items: center; }
  /* 16 px sind Pflicht: bei kleinerer Schrift zoomt iOS beim Antippen in
     das Feld hinein und die ganze Ansicht verrutscht. */
  #inputRow input, #inputRow textarea { flex: 1; min-width: 0; padding: 13px 16px; border: none; background: var(--surface);
    border-radius: var(--r-l); font-size: 16px; outline: none; }
  #inputRow input:focus, #inputRow textarea:focus { background: var(--surface-2); }
  /* v3.36.0: Das Chatfeld waechst mit - eine Zeile bis fuenf, dann rollt es. */
  #inputRow textarea { resize: none; font-family: inherit; line-height: 1.35;
    max-height: 118px; overflow-y: auto; }
  #inputRow button {
    flex: none; width: 46px; height: 46px; border-radius: var(--r-kreis); border: none;
    background: var(--primary); color: var(--on-primary); font-size: 1.15rem;
  }
  #inputRow button.ideaBtn { background: var(--accent); }
  #inputRow button.ideaBtn[disabled] { opacity: 0.5; }

  /* ---- v2.30.0: Sprachnachrichten -----------------------------------
     Der Mikrofon-Knopf sieht aus wie das ✨ daneben (heller Knopf, kein
     Hauptknopf) - gesendet wird weiter nur mit ➤. Waehrend der Aufnahme
     wird derselbe Knopf zum Stopp und ist rot: dass gerade aufgenommen
     wird, muss man aus zwei Metern Abstand sehen. */
  #inputRow button[hidden] { display: none; }
  #inputRow button#mikroBtn { background: var(--surface-2); color: var(--text); }
  #inputRow button#mikroBtn.laeuft { background: var(--danger); color: var(--auf-farbe); }
  #inputRow button#mikroBtn[disabled] { opacity: 0.55; }
  /* Der Aufnahme-Streifen nimmt den Platz des Eingabefeldes ein. */
  #aufnahmeLeiste { display: none; flex: 1; min-width: 0; align-items: center; gap: 8px;
    padding: 5px 12px 5px 5px; border-radius: var(--r-l); background: var(--danger-bg);
    border: 1px solid var(--danger-border); }
  #inputRow.aufnahme #aufnahmeLeiste, #inputRow.wandelt #aufnahmeLeiste { display: flex; }
  #inputRow.aufnahme > input, #inputRow.wandelt > input,
  #inputRow.aufnahme > #sendBtn, #inputRow.wandelt > #sendBtn,
  #inputRow.aufnahme > .ideaBtn, #inputRow.wandelt > .ideaBtn { display: none; }
  /* Beim Umwandeln laeuft schon der Server - abbrechen kann man da nichts
     mehr, also steht das ✕ auch nicht mehr da. */
  #inputRow.wandelt #aufnahmeWeg, #inputRow.wandelt .aufPunkt { display: none; }
  #inputRow.wandelt #aufnahmeLeiste { background: var(--surface); border-color: var(--border); }
  #inputRow #aufnahmeWeg { flex: none; width: 44px; height: 44px; border-radius: var(--r-kreis);
    background: var(--bg); color: var(--text); font-size: 1rem; border: 1px solid var(--border-2); }
  #aufnahmeLeiste .aufPunkt { flex: none; width: 10px; height: 10px; border-radius: var(--r-kreis);
    background: var(--danger); animation: aufnahmePuls 1.4s infinite ease-in-out; }
  @keyframes aufnahmePuls { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
  @media (prefers-reduced-motion: reduce) { #aufnahmeLeiste .aufPunkt { animation: none; opacity: .95; } }
  #aufnahmeLeiste .aufText { display: flex; flex-direction: column; min-width: 0; }
  #aufnahmeLeiste .aufZeit { font-size: 0.92rem; font-weight: 700; color: var(--text);
    font-variant-numeric: tabular-nums; }
  #aufnahmeLeiste .aufUnter { font-size: 0.7rem; color: var(--text-3); line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .guestTag {
    font-size: 0.7rem; background: var(--warn); color: var(--text); border-radius: var(--r-xs);
    padding: 0 4px; margin-left: 4px; font-weight: 700;
  }
  #gaesteView { flex: 1; overflow-y: auto; padding: 12px 12px calc(12px + var(--sab)); display: none; }
  #updateBanner { display: none; align-items: center; gap: 10px; background: var(--warn-bg);
    border-bottom: 1px solid var(--warn-border); padding: 9px 12px; font-size: 0.82rem; color: var(--warn-text); }
  #updateBanner span { flex: 1; }
  #updateBanner button { border: 1px solid var(--warn-border); background: var(--bg); color: var(--warn-text);
    border-radius: var(--r-s); padding: 8px 13px; min-height: 40px; font-size: 0.82rem; font-weight: 700; }
  /* v23.21: Der Sammel-Hinweis stand nur im Besorgungen-Tab - waehrend
     man im Chat tippt, sah man ihn also nie. Jetzt ganz oben, in jedem Tab. */
  #ladenBanner { display: none; align-items: center; gap: 9px; background: var(--band);
    padding: 9px 12px; font-size: 0.82rem; color: var(--band-text); }
  /* Der Ladenname darf kuerzen, der Rest bleibt einzeilig - sonst rutscht
     das Banner bei langen Namen auf zwei Zeilen. */
  #ladenBanner .txt { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 4px;
    white-space: nowrap; }
  #ladenBanner .txt > .wort { flex: none; }
  #ladenBanner b { font-weight: 700; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
  #ladenBanner #ladenBannerZahl { opacity: .82; font-weight: 400; flex: none; }
  #ladenBanner .punkt { width: 8px; height: 8px; border-radius: var(--r-kreis); background: var(--band-punkt);
    flex: none; animation: sammelPuls 1.6s infinite ease-in-out; }
  @keyframes sammelPuls { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
  @media (prefers-reduced-motion: reduce) { #ladenBanner .punkt { animation: none; opacity: .9; } }
  #ladenBanner button { border: 1px solid var(--band-punkt); background: transparent; color: var(--band-text);
    border-radius: var(--r-s); padding: 8px 14px; min-height: 40px; font-size: 0.82rem; font-weight: 700; }

  #gaesteView label.aiToggle { display: flex; align-items: center; gap: 8px; margin: 18px 0; font-size: 0.92rem; }
  #gaesteView h4 { margin: 4px 0 10px; font-size: 0.82rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; }
  /* v1.8.0: "Aus Raum entfernen" und "Archivieren" sind umkehrbar - sie
     tragen jetzt Grau. Rot bleibt dem endgueltigen Loeschen vorbehalten,
     sonst sehen zwei rote Knoepfe nebeneinander gleich gefaehrlich aus. */
  .kickBtn {
    color: var(--text-2); font-size: 0.82rem; font-weight: 600; background: var(--bg); border: 1px solid var(--border-2);
    border-radius: var(--r-s); padding: 8px 12px; min-height: 40px; white-space: nowrap;
  }
  .gastZeile .von { margin-top: 2px; }
  .gastZeile .gastKnoepfe { display: flex; gap: 6px; flex: none; align-items: center; }
  .gastZeile .loeschBtn { width: 40px; padding: 6px 0; text-align: center; }
  #guestList code {
    background: var(--border); border-radius: var(--r-xs); padding: 1px 5px; font-size: 0.7rem; color: var(--text-2);
  }
  /* v2.10.6 (Review-Fix): Passwort maskiert per Default - Auge deckt auf, das zweite Icon kopiert. */
  .pwAugeBtn, .pwKopierBtn {
    border: none; background: none; color: var(--muted); font-size: 0.86rem; padding: 4px; margin-left: 2px;
    min-width: 28px; min-height: 28px; cursor: pointer; vertical-align: middle;
  }
  .pwAugeBtn:active, .pwKopierBtn:active { color: var(--text); }

  /* --- Liste / Termine --- */
  /* v2.9.1: essenView fehlte hier - der Reiter Essen liess dadurch die
     ganze Seite mitscrollen (Reiterleiste verschwand) und innen liess sich
     nichts rollen. */
  /* v2.12.0: Die drei neuen Reiter rollen genauso wie die alten. Ohne
     diese Zeile scrollt die ganze Seite statt des Inhalts und die
     Reiterleiste verschwindet nach oben weg. */
  /* v3.21.1 (Sören: "Die Punkte-Übersicht ist schön, aber das gleiche
     Problem wie beim Reiter Feier: Die anderen Reiter werden ausgeblendet
     und man kann auch nicht mehr scrollen"): "#punkteView" fehlte hier -
     derselbe Fehler wie bei #eventPlanView in v3.16.0 und bei #essenView in
     v2.9.1. Wer eine neue Ansicht anlegt und diese Zeile vergisst, bekommt
     IMMER dieses Bild: body hat overflow:hidden, gerollt wird in der
     Ansicht - fehlt sie hier, rollt stattdessen die ganze Seite, und die
     Reiterleiste wandert nach oben aus dem Bild.
     DESHALB: Jede neue Reiter-Ansicht gehört in diese Aufzählung. Eine
     Probe prüft das ab jetzt für jedes Element, das switchTab() umschaltet. */
  #listView, #termineView, #todosView, #essenView,
  #heuteView, #kontakteView, #ausgabenView, #punkteView { flex: 1; overflow-y: auto;
    padding: 12px 12px calc(12px + var(--sab)); display: none; }
  /* v2.12.0: Bausteine, die sich Heute-Ueberblick, Kontakte, Ausgaben
     und Belohnungen teilen. Bewusst wenige, allgemeine Klassen -
     jeder Bereich soll sich aus demselben Baukasten bedienen. */
  .blockKarte { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-m);
    padding: 12px; margin: 0 0 10px; }
  .blockKopf { display: flex; align-items: center; justify-content: space-between; gap: 8px;
    font-size: 0.7rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em;
    margin: 16px 2px 6px; }
  .blockKopf .zahl { font-weight: 700; color: var(--text); text-transform: none; letter-spacing: 0; }
  .blockLeer { color: var(--muted); font-size: 0.86rem; padding: 10px 2px; }
  /* Ein Betrag steht nie im Fliesstext - er wird gelesen wie eine Zahl in
     einer Tabelle, deshalb Tabellenziffern und feste Ausrichtung. */
  .betrag { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
  .betrag.minus { color: var(--danger); }
  .betrag.plus { color: var(--ok); }
  /* v2.12.0: Fahrdienst-Zeile am Termin. Der eigene Name steht fett und
     als "du" da - wer die Liste ueberfliegt, soll sehen, was an IHM haengt,
     ohne jeden Namen zu lesen. Fett und Wort statt nur Farbe. */
  .fahrZeile { font-size: 0.78rem; color: var(--muted); margin-top: 2px; }
  .fahrZeile .fahrTeil.ich { color: var(--text); font-weight: 700; }
  /* v2.12.1: Im Einkaufsmodus Dazugekommenes. Wer mit dem Wagen im Laden
     steht, guckt nicht auf den Chat - der Nachtrag muss ins Auge springen.
     Das Aufblinken laeuft EINMAL (kein Dauerpuls, der beim Einkaufen nervt);
     die Marke bleibt, damit auch nach dem Blinken noch klar ist, was neu ist.
     Wer Bewegung reduziert haben will, bekommt nur die Marke. */
  .item.shoppingMode.frischDazu { border-left: 3px solid var(--primary); animation: frischRein .5s ease-out 2; }
  .neuMarke { display: inline-block; margin-left: 8px; font-size: 0.7rem; font-weight: 700;
    padding: 1px 7px; border-radius: var(--r-voll); background: var(--primary); color: var(--on-primary); vertical-align: middle; }
  /* v3.142.0, Nachbesserung (Gegenprüfung vom 29.09.2026): In der Terminzeile
     trennt ein Leerzeichen die Marke vom Titel (app-termine.js terminZeile).
     Mit margin-left stand sie bei 320 px nach dem Umbruch 8 px eingerückt
     unter dem Titel; ein Leerzeichen fällt am Zeilenanfang weg. */
  .terminZeile .neuMarke { margin-left: 0; }
  @keyframes frischRein {
    0% { background: var(--primary); }
    100% { background: transparent; }
  }
  @media (prefers-reduced-motion: reduce) {
    .item.shoppingMode.frischDazu { animation: none; }
  }
  /* v3.100.1 - Sören: „Die striche links zur Kennzeichnung sind einfach
     abgeschnitten und passen nicht zu rundung."
     Hier stand ein border-left: bündig an der Kante, über die volle Höhe,
     eckig - und damit von der 26-px-Rundung der Karte abgeschnitten.
     Er sagte ausserdem dasselbe wie der Quadranten-Streifen daneben, in
     derselben Farbe: ZWEI Elemente für eine Aussage. Gemessen war beides
     rgb(255,138,128).
     Er faellt ersatzlos weg. Ueberfaellig heisst dringendVon() >= 1, also
     Quadrant „sofort" oder „abgeben" - nie „rest". Jede ueberfaellige
     Aufgabe traegt den Streifen also ohnehin; es geht keine Markierung
     verloren. Die getoente Flaeche bleibt. */
  .item.overdue { background: var(--danger-bg); }
  .item .frist { font-size: 0.78rem; color: var(--muted); margin-top: 2px; }
  .item .frist.rot { color: var(--danger); font-weight: 600; }
  .todoSection { font-size: 0.7rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; margin: 16px 2px 6px; }
  .todoSection:first-child { margin-top: 2px; }
  .item {
    display: flex; align-items: center; gap: 10px; padding: 12px;
    background: var(--surface); border-radius: var(--r-s); margin-bottom: 8px;
  }
  /* v23.31: Die Symbole waren mit 22 px zu klein zum sicheren Treffen.
     Sichtbar bleiben sie zurueckhaltend, die TREFFFLAECHE ist jetzt 44 px -
     das Mass, ab dem ein Fingertipp verlaesslich sitzt. */
  .item .check {
    width: 26px; height: 26px; border-radius: var(--r-kreis); border: 2px solid var(--muted);
    flex-shrink: 0; display: flex; align-items: center; justify-content: center;
    position: relative; font-size: 0.92rem;
  }
  .item .check::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 44px; height: 44px; transform: translate(-50%, -50%);
  }
  .item.done .check { background: var(--success); border-color: var(--success); color: var(--auf-farbe); }
  .item.done .name { text-decoration: line-through; color: var(--muted); }
  .item .name { flex: 1; font-size: 0.92rem; overflow-wrap: anywhere; }
  /* v3.25.0: Der Textblock einer Listenzeile (Name, Menge, Wer) war
     schrumpfend - bei kurzen Namen klebten ✕ und 🏬 direkt am Wort, bei
     langen standen sie am Rand. Mit zwei Knöpfen fiel das auf. Jetzt füllt
     der Block die Zeile, und die Knöpfe stehen immer rechts. */
  /* v3.86.0 (Sören: „Design ist an manchen stellen nicht konsequent
     durchgesetzt"): :not(.woandersBtn) ist neu. Der 🏬-Knopf trägt selbst
     role="button" und fiel damit unter DIESE Regel (0,5,1) statt unter
     seine eigene `.woandersBtn { flex: none; width: 38px }` (0,1,0).
     GEMESSEN bei 390 px: Der Knopf war 117,5 px breit statt 38 und nahm
     dem Namen die halbe Zeile - "Batterien AA (4 Stück)" brach um, die
     Laden-Chips stapelten sich dreireihig. */
  .item > div[role="button"]:not(.check):not(.del):not(.calBtn):not(.woandersBtn) { flex: 1; min-width: 0; }
  .item .von { font-size: 0.78rem; color: var(--muted); }
  /* v1.8.0: Termin-Zeile: Uhrzeit und Ort stehen unter dem Titel statt
     in Klammern dahinter - das Datum steht ohnehin im Tagestrenner. */
  .item .wann { font-size: 0.82rem; color: var(--text-3); margin-top: 2px; font-variant-numeric: tabular-nums; }
  .item .wann b { font-weight: 700; color: var(--text); }
  .item .del, .item .calBtn {
    position: relative; flex: none; width: 44px; height: 44px; display: flex;
    align-items: center; justify-content: center;
  }
  .item .del { color: var(--icon-muted); font-size: 1.15rem; }
  .item .calBtn { font-size: 1.15rem; opacity: 0.75; }
  .kochBtn { display: flex; align-items: center; justify-content: center; width: 34px; min-height: 34px;
    font-size: 1.05rem; cursor: pointer; border-radius: var(--r-s); flex: 0 0 auto; }
  .kochBtn:active { background: var(--border); }
  /* v3.83.0: Die Huelle einer Listenzeile. Der Zeilen-Wisch ist weg - was
     bleibt, ist der Rahmen, an dem Ziehen (Reihenfolge), langes Druecken
     und eintragHervorheben haengen. Kein touch-action und kein
     user-select mehr: Die Seite darf hier wieder quer gewischt werden
     (Reiterwechsel), und der Name einer Zeile laesst sich markieren. */
  .swipeReihe { position: relative; margin-bottom: 8px; border-radius: var(--r-s); overflow: hidden; }
  /* v3.151.2 (Sören, 07.10.2026, mit einem Bild einer Aufgabe: „bei langem
     klick auf aufgabe wird text markiert“): Langes Drücken auf einer Zeile
     öffnet das Menü zur Zeile (app-gesten.js haltenBinden) - und iOS
     markierte GLEICHZEITIG das Wort darunter, mit „Kopieren/Nachschlagen“
     darüber. Schlimmer: Mit dem Markieren übernimmt iOS den Finger, und das
     Ende der Berührung kam bei der Seite nicht mehr an - das Ziehen, das
     nach 350 ms beginnt, lief weiter und sperrte jedes Scrollen
     (projekt.js, beiPause). Darum markiert ein langer Druck auf einer Zeile
     nichts mehr, und iOS legt kein eigenes Menü darüber - wie seit v3.146.0
     schon bei den Vorschlägen (.vsZeile). v3.83.0 hatte das Markieren der
     Zeilen ausdrücklich erlaubt; seit es das Menü gibt, nimmt es ihm den
     Finger. Felder in einer Zeile bleiben markierbar. */
  .swipeReihe { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
  .swipeReihe :is(input, textarea, [contenteditable="true"]) { -webkit-user-select: text; user-select: text; }
  .swipeReihe .item { margin-bottom: 0; position: relative; z-index: 1;
    background: var(--surface); }
  /* Kurze Meldung mit Rückgängig - jedes Löschen und Abhaken ist damit
     für ein paar Sekunden umkehrbar. */
  #wischMeldung { position: fixed; left: 50%; transform: translateX(-50%);
    bottom: calc(78px + var(--sab)); z-index: 40; display: none;
    align-items: center; gap: 12px; padding: 11px 14px;
    /* v3.176.1 (Sören, 24.10.2026, aus dem Familien-Durchgang vom 23.10.):
       Bei 320 px stand die Leiste mit 340 px 10 px über beiden Rändern, und
       der Name wurde mit „…“ abgeschnitten - bei „Elternsprechtag in der
       Grundschule …“ sah man nicht, WAS entfernt wurde. Jetzt so breit wie
       der Inhalt, höchstens 340 px und nie breiter als der Bildschirm; der
       Name bricht um, die Knöpfe rutschen bei Bedarf in eine zweite Zeile. */
    width: max-content; max-width: min(340px, calc(100vw - 24px)); flex-wrap: wrap;
    /* v3.34.0: Die Leiste hat seit v3.32.0 eigene Rollen (--meldung*), nutzte
       aber weiter --primary/--on-primary. Beides sah gleich aus, aber die
       Kontrastprobe rechnete an der Wirklichkeit vorbei. */
    border-radius: var(--r-m); background: var(--meldung); color: var(--meldung-text); font-size: 0.82rem;
    box-shadow: var(--shadow-2); }
  #wischMeldung button { border: none; background: none; color: var(--meldung-aktion);
    font-size: 0.86rem; font-weight: 700; padding: 8px 4px; min-height: 40px; flex: none; }
  /* v3.34.0: „War kein Eintrag“ ist der leisere der beiden Knöpfe -
     „Rückgängig“ bleibt der, den man im Zweifel sucht. */
  #wischMeldung #wischFalschBtn { color: var(--meldung-text); font-weight: 500; }
  #wischMeldung .was { flex: 1 1 9em; min-width: 0; line-height: 1.35;
    overflow-wrap: anywhere; }
  #emptyList { text-align: center; color: var(--muted); margin-top: 40px; font-size: 0.92rem; }
  /* v23.23: Abgehakte Punkte blieben ewig stehen - hier fliegen sie raus. */
  #speicherWarnung { display: none; margin: 14px 0 0; padding: 11px 12px; border-radius: var(--r-s);
    background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn-text); font-size: 0.82rem; line-height: 1.45; }
  #erledigteWeg { display: none; width: 100%; margin: 14px 0 4px; padding: 13px; min-height: 44px;
    border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--surface);
    color: var(--text-3); font-size: 0.86rem; font-weight: 600; }
  #erledigteWeg:active { background: var(--border); }
  /* v23.7: zeigt an, dass die Erkennung im Hintergrund noch laeuft */
  #kiStatus { display: none; align-items: center; gap: 7px; padding: 5px 14px 7px;
    font-size: 0.78rem; color: var(--muted); background: var(--bg); }
  #kiStatus .punkte { display: inline-flex; gap: 3px; }
  #kiStatus .punkte i { width: 4px; height: 4px; border-radius: var(--r-kreis); background: var(--muted-2);
    animation: kiPuls 1.1s infinite ease-in-out; }
  #kiStatus .punkte i:nth-child(2) { animation-delay: .16s; }
  #kiStatus .punkte i:nth-child(3) { animation-delay: .32s; }
  @keyframes kiPuls { 0%, 70%, 100% { opacity: .25; } 35% { opacity: 1; } }
  @media (prefers-reduced-motion: reduce) { #kiStatus .punkte i { animation: none; opacity: .55; } }
  .bubble.fehlgeschlagen { border: 1px solid var(--danger); cursor: pointer; }
  /* v2.10.6 (Review-Fix): title allein war auf Touch nie sichtbar - sichtbarer Hinweis in der Bubble. */
  .sendeFehlerHinweis { margin-top: 4px; font-size: 0.78rem; color: var(--danger); }
  /* 25.10.2026: zu lange Nachricht - Kürzen oder Teilen statt nur Wiederholen. */
  .sendeFehlerKnoepfe { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
  .sendeFehlerKnoepfe button { min-height: 44px; padding: 0 12px; font: inherit; font-size: 0.82rem; color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-s); cursor: pointer; }

  /* --- Manuelles Hinzufuegen --- */
  .addForm {
    padding: 12px; background: var(--surface); border-radius: var(--r-s); margin-bottom: 14px;
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  }
  /* v23.31: Ohne min-width schrumpfen Rasterfelder nicht unter ihre
     Wunschbreite - "Menge" und "Einkaufsort" ragten am Handy 58 px ueber
     den Rand hinaus. Und 16 px Schrift, damit iOS beim Antippen nicht
     hineinzoomt. */
  /* v3.99.0: in :where() - sonst schluege die Regel das Titelfeld .bsBlattTitel. */
  :where(.addForm input) { min-width: 0; min-height: 44px; padding: 11px 10px; border: 1px solid var(--border-2);
    border-radius: var(--r-s); font-size: 16px; }
  .addForm input[type="checkbox"], .addForm input[type="radio"] { min-height: 0; padding: 0; border: none; border-radius: 0; }
  /* v3.99.0: war var(--success) - gruen. Die Haupt-Handlung sieht ueberall
   gleich aus: im Blatt heisst sie "Speichern", im Formular "+ Hinzufuegen",
   beide sind dieselbe Zusage. Zwei Farben dafuer heisst: zweimal lernen. */
:where(.addForm) button {
    grid-column: 1 / -1; padding: 12px; min-height: 44px; border: none; border-radius: var(--r-s);
    background: var(--primary); color: var(--auf-farbe); font-weight: 700; font-size: 0.92rem;
  }
  /* v1.8.0: Beschriftete Felder (Datum, Von, Bis, Frist) und eine
     Aufteilung, bei der kein Feld allein in einer halben Zeile haengt. */
  .addForm .voll { grid-column: 1 / -1; }
  /* v3.99.0: in :where() - zum elften Mal dieselbe Bauart. Seit die Notiz
     auch im Anlege-Formular steht, schlug „.addForm textarea" (0,1,1) den
     Baustein .bsFeld (0,1,0) bei padding und border-radius: das Feld hatte
     als einziges im Formular einen Rahmen und eine andere Rundung. Gefunden
     hat es einheitlich-dom 5, bevor ich es gesehen habe. Die Regel behält
     ihre Wirkung auf jedes Textfeld ohne Baustein und verliert nur ihr
     Gewicht. */
  :where(.addForm textarea) { min-width: 0; padding: 11px 10px; border: 1px solid var(--border-2); border-radius: var(--r-s);
    font-size: 16px; font-family: inherit; line-height: 1.4; resize: vertical; background: var(--bg); }
  .addForm label.feld { display: flex; flex-direction: column; gap: 3px; min-width: 0;
    font-size: 0.7rem; font-weight: 600; color: var(--muted); letter-spacing: .02em; }
  /* v3.99.0: Das <select> steht hier in :where(). Seit die Auswahl-Zeile
     auch im Anlege-Formular sitzt, ist das select ein .bsWahlFeld - es liegt
     unsichtbar ÜBER seiner Zeile und holt sich seine Maße von dort. Die
     alte Regel (0,2,1) schlug den Baustein (0,1,0) und zwang ihm wieder
     width:100% auf. Gefunden hat das einheitlich-dom 5, keine Minute nachdem
     ich es gebaut hatte. */
  .addForm label.feld input { width: 100%; min-width: 0; }
  :where(.addForm label.feld select) { width: 100%; min-width: 0; }
  .addForm .dreier { grid-column: 1 / -1; display: grid; grid-template-columns: 1.25fr 1fr 1fr; gap: 8px; }
  /* iOS zeichnet Datums- und Zeitfelder sonst schmaler als ihre Nachbarn. */
  /* v3.98.0: Der Teil fuers Blatt steht in :where() - damit wiegt er (0,0,0)
     und der Baustein .bsFeld (0,1,0) gewinnt, ohne dass irgendwo
     !important steht (app-bausteine.css, Regel 2). appearance:none und die
     44 px gelten weiter fuer Datumsfelder, die kein Baustein sind. */
  /* v3.99.0: in :where() - seit das Datumsfeld im Anlege-Formular den
     Baustein .bsFeld traegt, schlug diese aeltere Regel ihn (mehr
     Schritte). Zehnter Fund derselben Bauart in dieser Sitzung;
     einheitlich-dom 5 hat ihn gefangen, bevor er sichtbar wurde. */
  :where(.addForm input[type="date"], .addForm input[type="time"]),
  :where(#editModalFields input[type="date"], #editModalFields input[type="time"]) {
    -webkit-appearance: none; appearance: none; min-height: 44px; background: var(--bg); color: var(--text); }
  .addForm input[type="date"]::-webkit-date-and-time-value, .addForm input[type="time"]::-webkit-date-and-time-value {
    text-align: left; }
  .addForm input[type="time"] { padding-left: 8px; padding-right: 6px; }
  /* v1.3.0: Auf-/Zuklappen der Anlege-Formulare */
  /* v3.97.0 (Sören: „Rhythmus mit haken erst wenn abgehakt kommt
     auswahlfeld"): Die ganze Zeile ist das Label - also 44 px hoch und
     überall antippbar, nicht nur das kleine Kästchen. */
  /* v3.97.0: Die gezeichneten Zeichen (zeichen.js). Sie stehen IM
     Textfluss und sollen auf der Zeile sitzen wie ein Buchstabe, nicht auf
     der Grundlinie hängen. flex: none, damit sie in engen Zeilen nicht
     zusammengedrückt werden. */
  .zeichen { vertical-align: -0.16em; flex: none; }
  .halteKnopf .zeichen { vertical-align: -0.22em; margin-right: 2px; }
  .hakenZeile { display: flex; align-items: center; gap: 10px; min-height: 44px; cursor: pointer; }
  .hakenZeile input { width: 22px; height: 22px; flex: none; accent-color: var(--accent); }
  .hakenZeile span { font-size: 0.92rem; }
  /* v3.100.0 - Sören: „Passe die Kastenformen an die neuen formen aus dem
     aufgabenblatt an." Im Blatt gibt es NICHTS Gestricheltes - ein
     gestrichelter Rahmen war die einzige Stelle dieser Art in der App.
     Jetzt dieselbe gefuellte Flaeche mit --r-m wie ein Feld im Blatt.
     Gilt fuer ALLE Reiter, die den Knopf tragen (Besorgungen, Termine,
     Aufgaben, Ideen): Ein Bedienelement, eine Bauart - es nur im
     Aufgaben-Reiter zu aendern haette zwei Sprachen gemacht. */
  .anlegenToggle {
    width: 100%; padding: 11px 14px; min-height: 48px; margin-bottom: 12px;
    border: 0; border-radius: var(--r-m); background: var(--surface);
    color: var(--text); font-weight: 700; font-size: 0.95rem; text-align: center;
  }
  .anlegenToggle.offen { background: var(--surface-2); margin-bottom: 8px; }
  /* v3.100.0 - Sören: „Knopf +aufgabe wird kleiner ca. 2/3 des platzes von
     links aus und rechts daneben kommt ein feld mit +checkliste."
     2 zu 1 ist genau zwei Drittel; die Knoepfe tragen ihren eigenen
     Abstand nicht mehr, den setzt das Paar. */
  /* v3.100.0 - Sören: „Größenaufteilung groß aufgabe etwas kleiner liste
     und klein filter." 3 zu 2, der Filter nimmt nur sich selbst. Die
     eigene Zeile fuer den Filter faellt damit weg - gemessen 56 px, die
     der Reiter jetzt mehr fuer Aufgaben hat. */
  .anlegenPaar { display: flex; gap: 8px; margin-bottom: 12px; align-items: stretch; }
  .anlegenPaar .anlegenToggle { margin-bottom: 0; flex: 3 1 0; min-width: 0; }
  .anlegenPaar .anlegenZweit { flex: 2 1 0; }
  .anlegenPaar #ansichtAufgabenWahl { flex: none; display: flex; margin: 0; }

  /* --- Einkaufsmodus ---
     v2.10.4: Kein schwarzer Block mehr, sondern die rechte Haelfte des
     Segments "Liste | Einkaufen" - das Aussehen kommt aus .ansichtWahl. */
  /* v1.8.0: Der Umschalter "Räume getrennt · auf zusammen umschalten"
     brach in zwei Zeilen um und las sich wie ein Raetsel. Jetzt ein
     Schalter mit klarer Aussage und Zustand. */
  .schalterZeile { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 48px;
    padding: 8px 12px; margin: -4px 0 12px; border: 1px solid var(--border); border-radius: var(--r-s); background: var(--bg);
    font: inherit; text-align: left; color: var(--text); }
  .schalterZeile .txt { flex: 1; min-width: 0; font-size: 0.86rem; font-weight: 600; }
  .schalterZeile .ut { display: block; font-size: 0.7rem; color: var(--muted); font-weight: 400; margin-top: 1px; }
  .schalter { width: 42px; height: 26px; border-radius: var(--r-m); background: var(--border-2); position: relative; flex: none;
    transition: background .15s; }
  .schalter::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: var(--r-kreis);
    background: var(--stets-weiss); box-shadow: var(--shadow-1); transition: left .15s; }
  .schalterZeile.an .schalter { background: var(--success); }
  .schalterZeile.an .schalter::after { left: 19px; }
  .item.shoppingMode { padding: 18px 14px; font-size: 1.15rem; }
  .item.shoppingMode .check { width: 30px; height: 30px; font-size: 1.15rem; }
  .item.shoppingMode .name { font-size: 1.15rem; }

  /* --- Laden-Auswahl (Einkaufsmodus) --- */
  /* v3.132.0: wie die Zeile „Diese Woche“ der Aufgaben (.punkteZeileKopf) -
     Pokal, Personen mit Farbpunkt, die Führung grün. */
  .wochenBattle { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; padding: 8px 14px;
    border: 1px solid var(--border); border-radius: var(--r-m); background: var(--surface); color: var(--text); }
  .wochenBattle .pzTitel { font-size: 0.82rem; font-weight: 700; flex: none; display: inline-flex; align-items: center; gap: 4px; }
  .wochenBattle .pzWerte { flex: 1; min-width: 0; display: flex; gap: 6px; overflow: hidden; }
  .wochenBattle .pzPerson { font-size: 0.78rem; color: var(--text-2); background: var(--surface-2); border-radius: var(--r-voll);
    padding: 2px 8px; white-space: nowrap; }
  .wochenBattle .pzPerson.erster { background: var(--success-bg); color: var(--success-text); font-weight: 700; }
  /* minmax(0,1fr): sonst schiebt ein langes Raum-Kaertchen die Spalte
     breit und der Nachbar bricht mitten im Wort ("Alnatu ra"). */
  .ladenGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  /* v3.132.0 (Sören: „die anzeige der läden selbst optisch anpassen auf den
     rest der app"): helle Karten statt schwarzer Kacheln - schwarz heißt
     in der App „gewählt“ (.kopfKnopf.an). Und wie die Laden-Karten der
     Liste und die Checkliste (.checklisteKarte): links bündig, Name fett,
     die Zahl als Pille, darunter leise, was drinsteht. */
  .ladenCard {
    display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; min-height: 88px;
    padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-m); background: var(--surface); color: var(--text);
    font: inherit; text-align: left; cursor: pointer;
  }
  .ladenCard:active { background: var(--surface-2); }
  .ladenCard.ohneOrt { background: var(--warn-bg); border-color: var(--warn-border); }
  .ladenCard.ohneOrt .ladenName { color: var(--warn-text); }
  .ladenCard.ohneOrt .ladenCount { background: var(--warn); color: var(--warn-auf); }
  .ladenName { font-size: 0.92rem; font-weight: 700; overflow-wrap: anywhere; }
  .ladenVorschau { width: 100%; font-size: 0.78rem; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ladenRaum { font-size: 0.7rem; font-weight: 600; background: var(--surface-2); color: var(--text-3);
    border-radius: var(--r-s); padding: 1px 8px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ladenCount { font-size: 0.78rem; font-weight: 700; background: var(--surface-2); color: var(--text-2); border-radius: var(--r-voll); padding: 2px 8px; }

  /* --- Einzel-Laden-Ansicht (Einkaufsmodus) --- */
  .ladenHeader { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
  .ladenZurueck { border: none; background: var(--border); border-radius: var(--r-s); padding: 8px 14px; min-height: 44px; font-size: 0.86rem; font-weight: 600; }
  .ladenTitel { font-size: 1.15rem; font-weight: 700; flex: 1; min-width: 0; text-align: center; margin-right: 60px;
    overflow-wrap: anywhere; }
  .progressBarAussen { height: 14px; background: var(--border); border-radius: var(--r-s); overflow: hidden; margin-bottom: 4px; }
  .progressBarInnen { height: 100%; background: var(--success); transition: width 0.4s ease; }
  .progressText { text-align: center; font-size: 0.82rem; color: var(--text-3); font-weight: 600; margin-bottom: 14px; }
  .fertigBanner {
    text-align: center; background: var(--success); color: var(--auf-farbe); font-weight: 700;
    border-radius: var(--r-s); padding: 12px; margin-bottom: 12px; font-size: 0.92rem;
  }
  /* v2.25.0: "Ohne Laden - auch hier?" unter der Ladenliste. Sichtbar
     abgesetzt (gestrichelte Linie, gedaempfter Kopf), damit niemand die
     Punkte fuer Rewe-Punkte haelt - der Balken oben zaehlt sie nicht. */
  /* v3.132.0: Im Laden ist die Liste EIN Zettel wie die Laden-Karte der
     Liste - Zeilen mit Haarlinie statt einzelner Karten. „Ohne Laden –
     auch hier?“ ist ein zweiter Zettel, gestrichelt: Er gehört nicht zu
     diesem Laden, bis man etwas davon hier kauft. Der Kopf in normaler
     Schreibung wie ein Laden-Titel (vorher Versalien). */
  .ladenZettel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-m); overflow: hidden; }
  .ladenZettel:empty { display: none; }
  .ladenZettel .item.shoppingMode, .auchHierBlock .item.shoppingMode { margin: 0; border: 0; border-radius: 0; }
  .ladenZettel .item + .item, .auchHierBlock .item + .item { border-top: 1px solid var(--border); }
  .auchHierBlock { margin-top: 14px; border: 1px dashed var(--border-2); border-radius: var(--r-m); background: var(--bg); overflow: hidden; }
  .auchHierKopf { padding: 10px 12px 0; font-size: 0.92rem; font-weight: 700; color: var(--text); }
  .auchHierText { padding: 0 12px; font-size: 0.78rem; color: var(--muted); margin: 2px 0 8px; line-height: 1.4; }
  .auchHierBlock .item.shoppingMode.auchHier { background: var(--bg); border-top: 1px dashed var(--border-2); }
  .item.shoppingMode.auchHier .check { border-style: dashed; }
  .nichtHierBtn { flex: none; min-height: 44px; min-width: 44px; padding: 0 12px; border: 1px solid var(--border-2); border-radius: var(--r-voll);
    background: var(--surface); color: var(--text-2); font-size: 0.78rem; font-weight: 600; white-space: nowrap; cursor: pointer; }
  .nichtHierBtn:active { background: var(--surface-2); }
  /* v3.143.0 (Sören: „Sprudelwasser kauft man nicjt im baumarkt.“): Was
     es hier eher nicht gibt, steht hinter diesem Knopf - eine ganze Zeile
     wie die Punkte darüber, 44 px, Farbe des Hinweistexts. */
  .auchHierMehr { display: block; width: 100%; min-height: 44px; padding: 0 12px; border: 0; border-top: 1px dashed var(--border-2);
    background: var(--bg); color: var(--accent-strong); font-size: 0.78rem; font-weight: 600; text-align: left; cursor: pointer; }
  .auchHierMehr:active { background: var(--surface-2); }
  .auchHierMehrListe .item.shoppingMode.auchHier:first-child { border-top: 1px dashed var(--border-2); }
  /* v3.24.0: "Gab es hier nicht" - ein 🏬 je offener Zeile im
     Einkaufsmodus. Die Zeile selbst hakt weiter ab; der Knopf hat seine
     eigenen 44 px und liegt am rechten Rand, weit weg vom Namen. */
  /* v3.24.0/v3.25.0: 🏬 "Gab es hier nicht". Im Einkaufsmodus ein <button>
     am rechten Rand, in der normalen Liste ein <div> neben ✕ - beide mit
     44 px Trefffläche, damit man sie mit dem Wagen in der Hand trifft. */
  .woandersBtn { flex: none; width: 44px; min-height: 44px; display: flex;
    align-items: center; justify-content: center;
    border: 0; background: none; color: var(--icon-muted); font-size: 1.15rem; line-height: 1;
    border-radius: var(--r-s); cursor: pointer; }
  .woandersBtn:active { background: var(--surface-2); }
  .item.shoppingMode .woandersBtn { margin: -8px -4px -8px 4px; font-size: 1.15rem; }
  /* In der Liste ist die Zeile enger - der Knopf war hier 38 px schmal.
     v3.132.0 (Läden in der Sprache der App): 44 px wie jeder Knopf, das
     Zeichen ist schmaler als das Emoji davor; der Name behält mehr als die
     Hälfte der Zeile (zeilenknoepfe-dom 16, laeden-optik-dom L6). */
  .woandersChips { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 4px; }
  .woandersChip { min-height: 44px; padding: 8px 14px; border: 1px solid var(--border-2);
    border-radius: var(--r-voll); background: var(--bg); color: var(--text); font: inherit;
    font-size: 0.92rem; font-weight: 600; cursor: pointer; }
  .woandersChip:active { background: var(--surface-2); }
  /* v3.26.0: Das Blatt hat jetzt vier Abschnitte (steht bei · stattdessen ·
     zusätzlich · anderer Laden). Ohne Zwischenüberschriften wäre es eine
     Wand aus gleich aussehenden Knöpfen. */
  .woKopf { font-size: 1rem; font-weight: 700; margin-bottom: 10px; }
  .woAbschnitt { margin: 0 0 14px; }
  .woLabel { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em;
    text-transform: uppercase; color: var(--muted); margin-bottom: 4px; }
  .woAbschnitt .blattKnoepfe { margin-top: 8px; }
  .woandersChip.an { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); }
  /* v3.96.0 (Sören: „An dieser Stelle fehlt die Auswahlmöglichkeit ‚weiß
     nicht' bzw. Ohne Laden"): Steht in DERSELBEN Reihe wie die Läden - es
     ist dieselbe Frage. Gestrichelt und ruhig, damit man sieht: das ist
     kein Laden, sondern die Antwort „keiner davon". */
  .woandersChip.weissNicht { border-style: dashed; color: var(--muted); }
  .woandersChip.an[disabled] { opacity: .75; cursor: default; }
  .woandersChip.zusatz { border-style: dashed; }
  /* v3.132.0: der gelernte Laden oder der Vorschlag der KI - vorn und in
     der Akzentfarbe (wie früher .ortChip.gelernt unter der Zeile). */
  .woandersChip.tipp { border-color: var(--accent); color: var(--accent); }
  /* Der Vermerk an der Zeile: "auch bei Edeka". Klein und ruhig - er sagt
     etwas ueber den Punkt, er ist kein Knopf. */
  .auchBeiVermerk { display: inline-block; margin-left: 6px; font-size: 0.7rem;
    color: var(--accent-strong); background: var(--accent-bg); border: 1px solid var(--accent-border);
    border-radius: var(--r-voll); padding: 0 7px; white-space: nowrap; vertical-align: middle; }
  .item.shoppingMode .auchBeiVermerk { font-size: 0.7rem; margin-left: 8px; }
  /* v3.143.0: „passt eher nicht hierher“ - leiser als „auch bei“: kein
     Knopf, keine Warnfläche, nur ein gestrichelter Rahmen in Nebentext-
     Farbe. Das 🏬 der Zeile verschiebt. */
  .passtNichtVermerk { display: inline-block; margin-left: 6px; font-size: 0.7rem; color: var(--muted);
    border: 1px dashed var(--border-2); border-radius: var(--r-voll); padding: 0 7px; white-space: nowrap; vertical-align: middle; }
  .item.shoppingMode .passtNichtVermerk { margin-left: 8px; }
  /* „erscheint auch bei jedem Laden“ - darf zwei Zeilen nehmen, es ist ein Satz. */
  .ladenVorschau.ladenHinweis { white-space: normal; }
  /* Bearbeiten-Blatt: "Nicht bei: Dm ✕  Aldi ✕" - das ✕ hat die volle
     Trefflaeche von 44 px, der Chip bleibt optisch schlank. */
  .nichtBeiZeile { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 8px 0 4px; }
  .nichtBeiLabel { font-size: 0.82rem; font-weight: 600; color: var(--text-3); margin-right: 2px; }
  .nichtBeiChip { display: inline-flex; align-items: center; gap: 2px; padding-left: 10px; border: 1px solid var(--border-2); border-radius: var(--r-voll);
    background: var(--surface); font-size: 0.82rem; color: var(--text-2); min-height: 44px; }
  .nichtBeiWeg { width: 44px; height: 44px; border: none; background: none; color: var(--icon-muted); font-size: 1rem; cursor: pointer; border-radius: var(--r-kreis); }
  .nichtBeiWeg:disabled { opacity: 0.4; }

  /* --- Konfetti --- */
  .konfettiStueck {
    position: fixed; top: -10px; width: 8px; height: 14px; z-index: 50;
    animation: konfettiFall 1.6s ease-in forwards; pointer-events: none; border-radius: var(--r-xs);
  }
  @keyframes konfettiFall {
    to { transform: translateY(105vh) rotate(360deg); opacity: 0.3; }
  }

  /* --- Gruppierung nach Einkaufsort --- */
  /* v3.132.0 (Sören: „jetzt noch die anzeige der läden selbst optisch
     anpassen auf den rest der app" - und zur ersten Fassung: „Übersicht in
     besorgungen gefällt noch nicht"): EIN LADEN IST EIN ZETTEL. Jeder Laden
     ist eine Karte wie die Checkliste im Reiter Aufgaben (.checklisteKarte:
     Fläche, Rahmen, --r-m, fetter Titel 0.92rem, die Zahl als Pille wie
     .ckStand, zugeklappt die Vorschau darunter wie .ckVorschau). Die
     Besorgungen stehen darin als Zeilen mit Haarlinie.
     Die erste Fassung machte den Laden zur leisen Versal-Überschrift über
     losen Karten: zwölf Besorgungen waren zwölf Karten, und der Laden - das,
     wonach man einkauft - war das Kleinste auf der Seite. Der Kopf bleibt
     der Knopf zum Auf- und Zuklappen, 44 px hoch. */
  .listGroup { margin-bottom: 8px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-m); overflow: hidden; }
  .groupHeader {
    display: flex; flex-wrap: wrap; align-items: center; gap: 2px 8px;
    padding: 8px 6px 8px 12px; min-height: 44px; font-size: 0.92rem; font-weight: 700; color: var(--text); cursor: pointer;
  }
  .groupCount { flex: none; font-size: 0.78rem; font-weight: 700; color: var(--text-2); background: var(--surface-2);
    border-radius: var(--r-voll); padding: 2px 8px; }
  .groupRight { display: flex; align-items: center; gap: 6px; flex: none; margin-left: auto; }
  /* v1.8.0: Bei Laeden aus anderen Raeumen stand "🎉 GEBURTSTAGSPARTY OMA
     HILDEGARD · ACTION" in Grossbuchstaben ueber zwei Zeilen. Jetzt traegt
     der Laden den Namen, der Raum steht als Kaertchen daneben. */
  .groupHeader .gruppenName { min-width: 0; overflow-wrap: anywhere; line-height: 1.5; }
  .groupHeader .gruppenName .raumChip { margin-left: 8px; font-size: 0.7rem; font-weight: 600; }
  .ladenTitel .raumChip { display: block; margin: 4px auto 0; width: fit-content; max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.7rem; }
  .groupTerminInfo { font-size: 0.7rem; background: var(--accent); color: var(--auf-farbe); border-radius: var(--r-s); padding: 2px 6px; white-space: nowrap;
    display: inline-flex; align-items: center; gap: 4px; font-weight: 600; }
  /* Ortssuche-Karten (fehlte seit v23.10 - Patch-Lauf war abgebrochen) */
  /* Die Karte sitzt in der blauen KI-Blase - Textfarben deshalb
     ausdruecklich setzen, sonst erbt sie Weiss auf Hellgrau. */
  .ortKarte { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-s);
    padding: 9px 11px; margin-top: 7px; color: var(--text); }
  .ortKarte .ortName { font-weight: 600; font-size: 0.86rem; color: var(--text); }
  .ortKarte .ortZeile { font-size: 0.82rem; color: var(--text-3); margin-top: 2px; }
  .ortKarte .ortZeile a { color: var(--accent); }
  .ortKarte .ortHinweis { font-size: 0.7rem; color: var(--warn-text); margin-top: 3px; }
  .ortKarte .ortNote { color: var(--warn-text); font-weight: 600; letter-spacing: -0.5px; }
  .ortKarte .ortWahl { margin-top: 7px; }
  .ortKarte .ortWahl button { border: 1px solid var(--muted-2); background: var(--bg); border-radius: var(--r-s);
    padding: 9px 14px; min-height: 44px; font-size: 0.82rem; font-weight: 600; color: var(--text-2); }
  .ortKarte.gewaehlt { border-color: var(--success); background: var(--success-bg); }
  /* Weiss auf dem Blau der KI-Blase erreicht nur 3,8:1 - fuer diesen
     kleinen Hinweis deshalb ein dunklerer Streifen darunter. */
  .ortQuelle { font-size: 0.7rem; color: var(--auf-farbe); margin-top: 9px; line-height: 1.4;
    background: var(--accent-strong); padding: 6px 9px; border-radius: var(--r-s); }
  /* v23.15: Umschalter Liste/Kalender + Monatsraster */
  #addTerminFormBox { grid-template-columns: 1fr 1fr; margin-bottom: 14px; }
  /* v1.1.0: Ideen-Raum */
  #ideenView { flex: 1; overflow-y: auto; padding: 12px 12px calc(12px + var(--sab)); display: none; }
  /* v1.4.0: Phasen, Leitsatz, Mehr */
  #phasenView, #mehrView { flex: 1; overflow-y: auto; padding: 12px 12px calc(12px + var(--sab)); display: none; }
  .leitsatzFeld { background: var(--bg); border-radius: var(--r-m); padding: 12px 14px; margin-bottom: 10px; }
  .leitsatzFeld label { display: block; font-weight: 700; font-size: 0.86rem; margin-bottom: 6px; }
  .leitsatzFeld textarea, #raumRegeln { width: 100%; box-sizing: border-box; min-height: 70px; padding: 10px 12px; border: 1px solid var(--border);
    border-radius: var(--r-s); font-size: 16px; font-family: inherit; line-height: 1.4; resize: vertical; background: var(--surface); }
  .lernZeile { display: flex; align-items: center; gap: 8px; padding: 7px 0; border-top: 1px solid var(--border); font-size: 0.86rem; color: var(--text-2); }
  .lernZeile:first-child { border-top: none; }
  .lernZeile span { flex: 1; }
  .lernZeile button { border: none; background: none; color: var(--danger); font-size: 0.92rem; padding: 2px 6px; }
  .tabWrap { overflow-x: auto; background: var(--bg); border-radius: var(--r-m); -webkit-overflow-scrolling: touch; }
  .datenTabelle { border-collapse: collapse; width: 100%; font-size: 0.86rem; }
  .datenTabelle th, .datenTabelle td { padding: 10px 12px; text-align: left; white-space: nowrap; border-bottom: 1px solid var(--border); }
  .datenTabelle th { color: var(--text-3); font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: .02em; }
  .datenTabelle tr:last-child td { border-bottom: none; }
  .datenTabelle .tabZeilenLoesch { color: var(--danger); text-align: center; cursor: pointer; }
  .raumTypWahl { display: flex; gap: 6px; }
  .raumTypWahl button { flex: 1; min-height: 44px; border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-s); font-size: 0.86rem; font-weight: 600; color: var(--text-2); }
  .raumTypWahl button.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
  .haushaltWahl { border: 1px solid var(--border); border-radius: var(--r-s); padding: 10px 12px; margin-top: 2px; background: var(--surface); }
  .haushaltWahl .hwTitel { font-size: 0.7rem; letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--muted); font-weight: 600; margin-bottom: 7px; }
  .haushaltWahl label { display: flex; align-items: center; gap: 9px; font-size: 0.86rem;
    color: var(--text-2); min-height: 30px; cursor: pointer; }
  .haushaltWahl input { width: 18px; height: 18px; flex: 0 0 auto; }
  /* v3.171.1: „Raumart“ (Beta raum-orga, app-orga-raum.js) - jede Wahl 44 px hoch. */
  #orgaArtBlock label { min-height: 44px; }
  .haushaltWahl .hwHinweis { font-size: 0.78rem; color: var(--muted); margin-top: 6px; line-height: 1.35; }
  .raumTypHinweis { font-size: 0.82rem; color: var(--muted); margin: -2px 0 4px; line-height: 1.35; }
  /* --- v1.9.0: Projekt-Raum - Ideen · Plan · Notizen --- */
  .ideenSuchZeile { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
  .ideenSuchZeile input { flex: 1; min-width: 0; min-height: 44px; padding: 10px 14px; border: 1px solid var(--border); border-radius: var(--r-m);
    font-size: 16px; background: var(--surface); -webkit-appearance: none; appearance: none; }
  .ideenSuchZeile input:focus { outline: none; background: var(--bg); border-color: var(--muted-2); }
  .ideenSuchZeile input::-webkit-search-cancel-button { -webkit-appearance: none; }
  .ideenNeuBtn { flex: none; width: 44px; height: 44px; border-radius: var(--r-l); border: none; background: var(--primary); color: var(--on-primary); font-size: 1.5rem; line-height: 1; padding: 0; }
  .ideenTabs button.eingang { border-style: dashed; color: var(--warn-text); border-color: var(--warn-border); }
  .ideenTabs button .pn { display: block; max-width: 46vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .phaseWahl .pwZiel { font-size: 0.78rem; font-weight: 400; color: var(--muted); white-space: normal; }
  .faelligBox { background: var(--warn-bg); border: 1px solid var(--warn-border); border-radius: var(--r-m); padding: 10px 12px 6px; margin-bottom: 12px; }
  .faelligTitel { font-size: 0.7rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--warn-text); margin-bottom: 4px; }
  .faelligBox .faelligZeile { border-top-color: var(--warn-border); min-height: 40px; }
  /* Baustein = Abschnitt mit Ueberschrift, Zeilen darunter */
  .bst { background: var(--bg); border-radius: var(--r-m); margin-bottom: 10px; overflow: hidden; border: 1px solid var(--border); }
  .bstKopf { display: flex; align-items: center; gap: 8px; padding: 6px 6px 6px 14px; min-height: 52px; }
  .bstFarbe { width: 10px; height: 10px; border-radius: var(--r-xs); flex: none; }
  .bstKopf { cursor: pointer; }
  .bstName { flex: 1; min-width: 0; font-weight: 700; font-size: 1rem; padding: 8px 0; overflow-wrap: anywhere; }
  .bstWer { display: block; font-weight: 400; font-size: 0.78rem; color: var(--muted); margin-top: 1px; }
  .bstZahl { flex: none; background: var(--surface); color: var(--text-3); border-radius: var(--r-s); padding: 2px 9px; font-size: 0.78rem; font-weight: 700; font-variant-numeric: tabular-nums; }
  .bstMenu { flex: none; width: 40px; height: 40px; border: none; background: none; color: var(--muted); font-size: 1.15rem; padding: 0; border-radius: var(--r-l); }
  .bstMenu:active { background: var(--border); }
  .bstFertig { flex: none; min-height: 36px; border: none; background: var(--primary); color: var(--on-primary); border-radius: var(--r-s); padding: 0 12px; font-weight: 700; font-size: 0.82rem; }
  .bstPfeil { flex: none; width: 34px; text-align: center; color: var(--muted-2); font-size: 0.92rem; cursor: pointer; padding: 10px 0; }
  .bst.zu .bstBody { display: none; }
  .bstNotiz { margin: 0 14px 6px; padding: 8px 10px; background: var(--warn-bg); border-left: 3px solid var(--warn-border); border-radius: var(--r-xs); font-size: 0.82rem; color: var(--text-3); line-height: 1.4; white-space: pre-wrap; }
  /* Eine Zeile = ein Gedanke */
  .gedanke { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px 10px 14px; border-top: 1px solid var(--surface-2); cursor: pointer; min-height: 48px; }
  .gedanke:active { background: var(--surface); }
  .gedanke.frisch { background: var(--warn-bg); transition: background 1.2s ease 1.5s; }
  /* v1.9.1: Griff zum Ziehen; kein Abhak-Kreis mehr (Status steht als Marke) */
  .gGriff { flex: none; width: 34px; align-self: stretch; display: flex; align-items: center; justify-content: center; margin: -10px -6px -10px 0;
    color: var(--border-2); font-size: 1.15rem; touch-action: none; cursor: grab; user-select: none; -webkit-user-select: none; }
  /* v2.10.6 (Review-Fix): Tastaturalternative zum Ziehen - dezent sichtbar, bei Fokus/Hover deutlicher. */
  .reihenKnoepfe { flex: none; display: flex; flex-direction: column; gap: 2px; align-self: center; }
  .reihenBtn { width: 26px; min-height: 22px; border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-xs);
    color: var(--muted); font-size: 0.7rem; line-height: 1; padding: 0; }
  .reihenBtn:hover, .reihenBtn:focus-visible { color: var(--text); border-color: var(--accent); }
  .reihenBtn:disabled { opacity: .2; cursor: default; }
  .gedanke { user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
  .gedanke.dndWarte { background: var(--surface); }
  .gedanke.dndAktiv { position: relative; z-index: 5; background: var(--bg); box-shadow: var(--shadow-2); border-radius: var(--r-s); transition: none; cursor: grabbing; }
  .gListe.dndLaeuft .gedanke:not(.dndAktiv) { transition: transform .12s; }
  .marke.status { font-weight: 700; border-radius: var(--r-xs); padding: 0 6px; background: var(--surface); color: var(--text-3); }
  .marke.status.bearbeitung { background: var(--accent-bg); color: var(--accent-strong); }
  .marke.status.umgesetzt { background: var(--success-bg); color: var(--success-text); }
  .marke.status.verworfen { background: var(--surface); color: var(--muted); text-decoration: line-through; }
  .marke.notiz { color: var(--purple); }
  .bstVorschau { display: block; font-weight: 400; font-size: 0.78rem; color: var(--muted); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .bst:not(.zu) .bstVorschau { display: none; }
  .ideenTabs button.aufzu { color: var(--text-3); }
  .gText { flex: 1; min-width: 0; }
  .gTitel { font-size: 0.92rem; line-height: 1.35; overflow-wrap: anywhere; }
  .gedanke.umgesetzt .gTitel, .gedanke.verworfen .gTitel { color: var(--muted); }
  .gedanke.bearbeitung { border-left: 3px solid var(--accent-strong); padding-left: 11px; }
  .gedanke.verworfen .gTitel { text-decoration: line-through; }
  .gBeschr { font-size: 0.82rem; color: var(--text-3); margin-top: 2px; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .gMarken { display: flex; flex-wrap: wrap; gap: 4px 8px; margin-top: 4px; }
  /* v3.97.0 (Sören: „Schrift ragt über"): nowrap bleibt - eine Marke, die
     mitten im Datum umbricht, ist schlechter als eine kurze. Aber sie darf
     jetzt SCHRUMPFEN und notfalls mit … enden, statt über den Rand zu
     laufen. Vorher war beides nicht möglich: kein Umbruch, kein Schrumpfen,
     also Überlauf. */
  .marke { display: inline-flex; align-items: center; gap: 4px; font-size: 0.7rem; color: var(--muted);
    white-space: nowrap; min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
  .marke i { width: 7px; height: 7px; border-radius: var(--r-xs); display: inline-block; }
  .marke.phase { color: var(--text-3); background: var(--surface); border-radius: var(--r-xs); padding: 0 6px; }
  .marke.person { color: var(--accent); }
  .marke.frist { color: var(--warn-text); }
  .marke.frist.ueber, .marke.frist.heute { color: var(--danger); font-weight: 700; }
  .marke.ki { color: var(--purple); }
  .gSort { flex: none; display: flex; gap: 4px; margin: -4px -4px 0 0; }
  .gSort button { width: 40px; height: 40px; border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-s); font-size: 1rem; color: var(--text-2); padding: 0; }
  .gLeer { padding: 10px 14px 12px; font-size: 0.82rem; color: var(--muted); border-top: 1px solid var(--surface-2); }
  .gNeu { display: block; width: 100%; text-align: left; padding: 11px 14px; min-height: 44px; border: none; border-top: 1px solid var(--surface-2);
    background: none; color: var(--accent); font-size: 0.86rem; font-weight: 600; }
  .logbuch { border-top: 1px solid var(--surface-2); }
  .logbuch summary { list-style: none; padding: 10px 14px; min-height: 44px; display: flex; align-items: center; font-size: 0.82rem; color: var(--muted); cursor: pointer; }
  .logbuch summary::-webkit-details-marker { display: none; }
  .logbuch summary::before { content: "▸"; margin-right: 8px; font-size: 0.82rem; }
  .logbuch[open] summary::before { content: "▾"; }
  .logbuch .gedanke { background: var(--surface); }
  .mindmapBox { background: var(--bg); border-radius: var(--r-m); border: 1px solid var(--border); margin-top: 4px; }
  .mindmapBox summary { list-style: none; padding: 12px 14px; min-height: 48px; display: flex; align-items: center; font-weight: 700; font-size: 0.92rem; color: var(--text-3); cursor: pointer; }
  .mindmapBox summary::-webkit-details-marker { display: none; }
  .mindmapBox summary::after { content: "▾"; margin-left: auto; color: var(--muted-2); }
  .mindmapBox:not([open]) summary::after { content: "▸"; }
  .mindmapBox #ideenMindmap { padding: 0 6px 6px; margin: 0; }
  /* Plan: Phasen */
  .phase { background: var(--bg); border-radius: var(--r-m); margin-bottom: 10px; overflow: hidden; border: 1px solid var(--border); }
  .phase.eingang { border-style: dashed; border-color: var(--warn-border); background: var(--warn-bg); }
  .phKopf { display: flex; align-items: flex-start; gap: 10px; padding: 12px 6px 10px 14px; border-left: 4px solid var(--text); }
  .phase.eingang .phKopf { border-left-color: var(--warn-border); }
  .phNr { flex: none; width: 26px; height: 26px; border-radius: var(--r-m); background: var(--primary); color: var(--on-primary); font-size: 0.82rem; font-weight: 700;
    display: flex; align-items: center; justify-content: center; margin-top: 1px; }
  .phase.eingang .phNr { background: var(--warn-border); }
  .phText { flex: 1; min-width: 0; }
  .phName { font-weight: 700; font-size: 1rem; line-height: 1.3; overflow-wrap: anywhere; }
  .phZiel { font-size: 0.82rem; color: var(--text-3); margin-top: 2px; line-height: 1.4; }
  .phZiel.leer { color: var(--muted-2); font-style: italic; cursor: pointer; }
  .phKopf .bstZahl { margin-top: 3px; }
  .phKopf .bstMenu, .phKopf .bstFertig { margin-top: -6px; }
  .phaseWahl { display: flex; flex-direction: column; gap: 8px; }
  .phaseWahl button { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-height: 48px; border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-s);
    padding: 10px 12px; font-size: 0.92rem; font-weight: 600; text-align: left; color: var(--text); }
  .blattFrage { font-size: 0.92rem; font-weight: 600; margin-bottom: 12px; line-height: 1.35; }
  /* Notizen: Seitenliste */
  .seiteZeile { display: flex; align-items: center; gap: 12px; padding: 12px 10px 12px 14px; min-height: 60px; background: var(--bg); border: 1px solid var(--border);
    border-radius: var(--r-m); margin-bottom: 8px; cursor: pointer; }
  .seiteZeile:active { background: var(--surface); }
  .seiteZeile.leitsatz { background: var(--accent-bg); border-color: var(--accent-bg); }
  .seiteSym { flex: none; font-size: 1.3rem; width: 30px; text-align: center; }
  .seiteText { flex: 1; min-width: 0; }
  .seiteName { font-weight: 700; font-size: 1rem; }
  .seiteVorschau { font-size: 0.82rem; color: var(--muted); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .seitePfeil { flex: none; color: var(--muted-2); font-size: 1.3rem; padding-right: 4px; }
  .seiteKopf { display: flex; align-items: center; gap: 6px; margin: -4px 0 10px; }
  .seiteZurueck { flex: none; border: none; background: none; color: var(--accent); font-weight: 600; font-size: 0.92rem; min-height: 44px; padding: 0 6px; white-space: nowrap; }
  .seiteTitel { flex: 1; min-width: 0; text-align: center; font-weight: 700; font-size: 1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Blaetter */
  .blattSelect { width: 100%; min-height: 44px; padding: 10px 12px; border: 1px solid var(--border-2); border-radius: var(--r-s); font-size: 16px; background: var(--bg); margin-top: 3px; font-family: inherit; }
  .blattZweier { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .blattZweier > div { min-width: 0; }
  .blattZweier input, .blattZweier select { width: 100%; min-width: 0; }
  /* v3.47.0 (Paket 6, Befund A38): Vier gleich breite Segmente
     ("Offen / In Arbeit / ✓ Umgesetzt / Verworfen") lassen bei 320-360 px
     nur 65-75 px je Knopf. Mit `white-space: nowrap` (Voreinstellung im
     Knopf) wurde der Text abgeschnitten. Jetzt darf er umbrechen, die
     Zeile darf notfalls umbrechen, und auf schmalen Geraeten wird die
     Schrift eine Stufe kleiner. */
  /* v3.99.0: darf umbrechen - „Kategorie“ mit fünf Knöpfen lief neben dem Wort über. */
  .segment { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
  /* 0 1 auto: Beim Umbruch dehnte sich der letzte Knopf allein ueber die
     ganze Reihe und sah aus wie die Haupt-Handlung. */
  /* Die Form kommt aus dem Innenabstand (14 px wie beim Chip), nicht aus
     min-width: Eine min-width hier verliert gegen ".addForm .segment button"
     (mehr Schritte, mehr Gewicht) - gemessen, der Knopf blieb 52 px breit und
     las sich bei vollem Radius als Kreis. */
  .segment button { flex: 0 1 auto; min-width: 0; min-height: 42px; border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-s); font-size: 0.86rem; font-weight: 600; color: var(--text-2); padding: 0 14px;
    white-space: normal; line-height: 1.2; }
  @media (max-width: 400px) {
    /* v3.99.0: Der Innenabstand war 3 px. Die Regel stammt aus der Zeit, als
       die Segmente die Zeile FUELLTEN (flex: 1 1 0) und fuenf Knoepfe
       nebeneinander passen mussten - eng war da richtig. Seit sie umbrechen
       duerfen, macht 3 px aus "normal" einen 52 px breiten Knopf, der mit
       voller Rundung wie ein Radioknopf aussieht. Auf JEDEM Handy, denn die
       Bedingung trifft bei 390 px zu. Gemessen, nachdem zwei Versuche ueber
       min-width an staerkeren Regeln gescheitert waren. */
    .segment button { font-size: 0.78rem; padding: 0 12px; }
  }
  .segment button.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
  .blattMeta { font-size: 0.78rem; color: var(--muted); margin-top: 2px; }
  .blattZeile { display: flex; gap: 8px; margin-top: 4px; flex-wrap: wrap; }
  .blattZeile > button { flex: 1 1 45%; min-height: 44px; white-space: normal; }
  .blattZeile > button:disabled { opacity: .4; }
  .blattLoeschen { min-height: 44px; border: 1px solid var(--danger-border); background: var(--danger-bg); color: var(--danger); border-radius: var(--r-s); padding: 8px 12px; font-weight: 600; font-size: 0.86rem; }
  .blattLoeschen.bereit { background: var(--danger); color: var(--auf-farbe); border-color: var(--danger); }
  :where(#editModalFields) label { display: block; }
  #editModalFields .lernZeile button { border: none; background: none; color: var(--danger); font-size: 0.92rem; padding: 2px 6px; min-width: 40px; min-height: 40px; }
  #ideenMindmap { background: var(--bg); border-radius: var(--r-m); padding: 6px; margin-bottom: 14px; }
  #ideenMindmap svg { width: 100%; height: auto; display: block; }
  #ideenMindmap .mmKat { cursor: pointer; }
  .ideenTabs { display: flex; gap: 6px; overflow-x: auto; padding: 2px 0 10px; margin: -2px 0 6px; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .ideenTabs::-webkit-scrollbar { display: none; }
  .ideenTabs button { flex: none; min-height: 40px; border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-l); padding: 0 14px;
    font-size: 0.82rem; font-weight: 600; color: var(--text-2); white-space: nowrap; display: flex; align-items: center; gap: 6px; }
  .ideenTabs button.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
  .ideenTabs button .punkt { width: 8px; height: 8px; border-radius: var(--r-xs); display: inline-block; }
  .ideenTabs button .z { background: rgba(0,0,0,.08); border-radius: var(--r-s); padding: 0 6px; font-size: 0.7rem; }
  .ideenTabs button.aktiv .z { background: rgba(255,255,255,.22); }
  .ideenTabs button.plus { border-style: dashed; color: var(--accent); border-color: var(--accent-border); }
  .bausteinKopf { background: var(--bg); border-radius: var(--r-m); padding: 12px 14px; margin-bottom: 10px; }
  .bausteinKopf .bkTitel { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 1.05rem; }
  .bausteinKopf .bkTitel button { margin-left: auto; border: none; background: none; color: var(--muted); font-size: 1.15rem; padding: 4px 6px; min-height: 36px; }
  .bausteinKopf .bkMeta { font-size: 0.82rem; color: var(--text-3); margin-top: 4px; }
  .bausteinKopf textarea { width: 100%; box-sizing: border-box; margin-top: 10px; min-height: 84px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-s);
    font-size: 16px; font-family: inherit; line-height: 1.4; resize: vertical; background: var(--surface); }
  .bausteinKopf .notizHinweis { font-size: 0.7rem; color: var(--muted-2); margin-top: 4px; text-align: right; min-height: 1em; }
  .faelligZeile { display: flex; align-items: center; gap: 8px; padding: 8px 0; border-top: 1px solid var(--border); cursor: pointer; }
  .faelligZeile:first-of-type { border-top: none; }
  .faelligZeile .fzDatum { flex: none; width: 58px; font-weight: 700; font-size: 0.82rem; color: var(--warn-text); }
  .faelligZeile.ueber .fzDatum { color: var(--danger); }
  .faelligZeile .fzText { flex: 1; min-width: 0; font-size: 0.92rem; }
  .faelligZeile .fzWer { font-size: 0.78rem; color: var(--accent); }
  /* v3.122.0 (Sören: "Aber die felder sind sonst runder oder?"): Ja - hier
     stand "#editModalFields textarea" mit Spezifitaet (1,0,1), und eine ID
     schlaegt jeden Baustein. Das Notizfeld bekam damit --r-s (12 px),
     waehrend die zwoelf anderen Felder desselben Blatts den Baustein
     .bsFeld mit --r-m (18 px) tragen. In :where() wiegt die Regel (0,0,1)
     und verliert gegen .bsFeld (0,1,0) - dieselbe Loesung wie schon
     dreimal in v3.98.0/v3.99.0, ohne ein einziges !important. */
  :where(.editModalFields, #editModalFields) textarea { width: 100%; box-sizing: border-box; min-height: 80px; padding: 10px 12px; border: 1px solid var(--border-2); border-radius: var(--r-s); font-size: 16px; font-family: inherit; }
  #addTerminFormBox input[type="date"], #addTerminFormBox input[type="time"] { color: var(--text-2); }
  .raumChip { display: inline-block; font-size: 0.7rem; font-weight: 600; color: var(--accent); background: var(--accent-bg);
    border-radius: var(--r-s); padding: 1px 6px; margin-left: 6px; vertical-align: middle; }
  /* v3.100.0: Dieselben Pillen wie die Frist-Schnellwahl im Blatt
     (.bsWahlChip) - eine Auswahl aus wenigen, also Chips. Kein Rahmen um
     jede Haelfte mehr. */
  .ansichtWahl { display: flex; gap: 6px; margin-bottom: 12px; }
  .ansichtWahl button { flex: 0 1 auto; padding: 8px 18px; min-height: 44px; border: 0; background: var(--surface);
    border-radius: var(--r-voll); font-size: 0.92rem; font-weight: 600; color: var(--text); }
  .ansichtWahl button.aktiv { background: var(--primary); color: var(--on-primary); }
  .kalKopf { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
  .kalKopf div { font-weight: 700; font-size: 0.92rem; }
  .kalKopf button { border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-s);
    width: 44px; height: 44px; font-size: 1.15rem; color: var(--text-2); }
  .kalWochentage { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 3px; }
  .kalWochentage span { text-align: center; font-size: 0.7rem; color: var(--muted); font-weight: 600;
    text-transform: uppercase; letter-spacing: .03em; }
  .kalGitter { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
  .kalTag { aspect-ratio: 1; border-radius: var(--r-s); display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 3px; font-size: 0.82rem;
    background: var(--surface); border: 1px solid transparent; font-variant-numeric: tabular-nums; }
  .kalTag.fremd { color: var(--border-2); background: transparent; }
  .kalTag.heute { border-color: var(--text); font-weight: 700; }
  .kalTag.gewaehlt { background: var(--primary); color: var(--on-primary); }
  .kalTag.gewaehlt .kalPunkte i { outline: 1px solid rgba(255,255,255,.7); }
  .kalPunkte { display: flex; gap: 2px; height: 5px; }
  .kalPunkte i { width: 5px; height: 5px; border-radius: var(--r-kreis); display: block; }
  .kalTagTitel { margin: 16px 0 6px; font-size: 0.86rem; font-weight: 700; }
  .kalLeer { font-size: 0.82rem; color: var(--muted-2); padding: 4px 2px; }
  .teilChips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
  .teilChip { font-size: 0.7rem; font-weight: 600; padding: 1px 7px; border-radius: var(--r-s); }
  .crossBadge { font-size: 0.7rem; background: var(--success); color: var(--auf-farbe); border-radius: var(--r-xs); padding: 1px 6px; margin-left: 6px; white-space: nowrap; }
  /* v3.132.0: In der Karte des Ladens ist jede Besorgung eine Zeile - kein
     eigener Rahmen, keine eigene Rundung, getrennt durch eine Haarlinie.
     Die Fläche bleibt DECKEND (v23.24, siehe unten): beim Wischen darf
     nichts durchscheinen. Drei Klassen tief, damit die allgemeine
     .item-Regel weiter unten (Rahmen, --radius) hier nicht greift. */
  .groupBody { border-top: 1px solid var(--border); }
  .groupBody .swipeReihe { margin: 0; border-radius: 0; }
  .groupBody .swipeReihe + .swipeReihe { border-top: 1px solid var(--border); }
  .groupBody .swipeReihe .item { margin: 0; border: 0; border-radius: 0; padding: 4px 6px 4px 12px; min-height: 52px; }
  .groupBody .item .von:empty { display: none; }
  /* v3.132.0, gefunden von einheitlich-dom (3): Ohne Namen darunter ist der
     Textblock nur eine Zeile hoch (38 px) - ein Tipp knapp über oder unter
     dem Wort traf die Zeile statt „Bearbeiten“. Der Block füllt deshalb die
     Höhe der Zeile, mindestens 44 px, und hält den Text in der Mitte.
     Grid statt Flex: .name trägt aus der Zeile flex: 1 - in einer
     Flex-Spalte wüchse es auf die ganze Höhe, und der Name stünde oben
     (gesehen im Bild). Im Grid gilt flex nicht. */
  .groupBody .item > div[role="button"]:not(.check):not(.del):not(.calBtn):not(.woandersBtn) {
    align-self: stretch; min-height: 44px; display: grid; align-content: center;
  }
  /* v23.24: In der Gruppe sitzen die Zeilen buendig - die Wisch-Huelle
     darf keinen eigenen Rand aufmachen. Und die Zeile braucht hier eine
     DECKENDE Farbe, sonst scheint beim Wischen der Hintergrund durch. */
  /* In Termin- und To-Do-Liste stehen die Zeilen einzeln - dort behaelt
     die Huelle Abstand und Rundung und braucht eine deckende Farbe. */
  #terminListe .swipeReihe .item, #todoGroups .swipeReihe .item,
  #kalTagListe .swipeReihe .item { background: var(--surface); }
  #terminListe .swipeReihe .item.overdue, #todoGroups .swipeReihe .item.overdue { background: var(--danger-bg); }
  .groupBody .swipeReihe .item { background: var(--surface); }

  /* --- Bearbeiten-Modal --- */
  /* v23.39: Mitteilungen */
  #pushModal {
    position: fixed; inset: 0; background: var(--overlay);
    display: none; align-items: center; justify-content: center; z-index: 30; padding: 20px;
  }
  /* v1.7.1: wie bei Lexikon und Archiv - fester Kopf, fester Fuss,
     scrollbarer Inhalt dazwischen. */
  #pushModal .modalBox { max-width: var(--blatt-breit); display: flex; flex-direction: column; max-height: var(--blatt-hoch); }
  #pushBody { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch; margin: -4px -4px 12px; padding: 4px; }
  .modalKopf { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex: none; }
  /* Lange Raumnamen kuerzen im Kopf - der volle Name steht im Feld darunter. */
  .modalKopf > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* v3.51.0 (Befund D43): Die Schliessen-Taste war dreimal hintereinander
     neu definiert (34, 40, 44 px). Jetzt steht sie EINMAL hier - mit den
     Werten, die zuletzt galten. */
  .modalX { border: none; background: var(--surface-2); color: var(--text-2); width: 44px; height: 44px; min-width: 44px;
    border-radius: var(--r-l); font-size: 0.92rem; line-height: 1; cursor: pointer; padding: 0; }
  .modalX:active { background: var(--border-2); }
  .pushStatus { font-size: 0.92rem; color: var(--text-2); line-height: 1.45; margin-bottom: 14px; }
  /* v1.8.0: Nur die Ueberschrift ist ein Block - fette Woerter INNERHALB
     der Anleitung ("Teilen", "Zum Home-Bildschirm") standen sonst jeweils
     allein in einer Zeile. */
  .pushStatus > b { display: block; margin-bottom: 4px; }
  .pushStatus ol { margin: 6px 0 0 18px; padding: 0; }
  .pushStatus li { margin: 3px 0; }
  #pushAuchOffen { margin: 0 0 12px; }
  #pushAuchOffen label { display: flex; align-items: flex-start; gap: 8px; font-size: 0.86rem;
    color: var(--text-2); line-height: 1.35; cursor: pointer; }
  #pushAuchOffen input { margin-top: 2px; flex: 0 0 auto; width: 18px; height: 18px; }
  #pushAuchOffen .unter { font-size: 0.78rem; color: var(--muted); margin: 4px 0 0 26px; line-height: 1.35; }
  .pushZeile { display: flex; gap: 8px; }
  .pushZeile button { flex: 1; min-height: 44px; border-radius: var(--r-s); border: none; font-size: 0.92rem; font-weight: 600; }
  .pushZeile .an { background: var(--success); color: var(--auf-farbe); }
  .pushZeile .test { background: var(--border); color: var(--text-2); }
  .pushZeile .aus { background: var(--danger-bg); color: var(--danger); }
  .pushMeldung { font-size: 0.82rem; color: var(--text-3); margin-top: 10px; min-height: 1.2em; }
  /* v2.32.0: Die eine Seite hat Abschnitte - "nur dieses Gerät", "für alle
     im Haushalt", "prüfen". Die Ueberschrift traegt den Unterschied, der
     Satz darunter erklaert ihn. Farben nur ueber die Variablen, damit hell
     und dunkel gleich gut lesbar bleiben. */
  .pushAbschnitt { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }
  .pushAbschnitt h4 { margin: 0 0 4px; font-size: 0.78rem; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--muted); font-weight: 600; }
  .pushAbschnitt .pushUnterKopf { margin: 16px 0 4px; font-size: 0.78rem; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--muted); font-weight: 600; }
  .pushErklaerung { margin: 0 0 10px; font-size: 0.82rem; color: var(--text-3); line-height: 1.45; }
  /* v2.90.0: "Aus fremden Haushalten abmelden". Kein Warnrot - es ist keine
     gefaehrliche Handlung, sondern ein Aufraeumen. */
  .pushFremdKnopf { width: 100%; min-height: 44px; border-radius: var(--r-m); border: 1px solid var(--border);
    background: var(--card-2, var(--card)); color: var(--text); font-size: 0.92rem; font-weight: 600; cursor: pointer; }
  .pushFremdKnopf:active { transform: scale(0.99); }
  #pushFremdMeldung { margin-top: 8px; font-size: 0.82rem; color: var(--text-3); line-height: 1.45; }
  #pushFremdMeldung:empty { display: none; }
  .pushAnlaesse { margin-bottom: 12px; }
  /* Die Anlass-Schalter sind .setZeile - dort steht schon alles (48 px hoch,
     Rand, Knauf). Hier nur, was in diesem Fenster anders ist: der Erklaersatz
     darf umbrechen, sonst stuenden drei Woerter je Zeile. */
  #pushBody .setZeile .ut { white-space: normal; }
  /* v2.32.0 (Pruef-Befund): OHNE "height: auto" blieb jede Zeile bei ihren
     48 px stehen, sobald der Erklaersatz auf zwei oder drei Zeilen umbrach -
     der Text lief unten aus dem Kasten heraus und ueber die naechste Zeile.
     Ein <button> waechst in Chromium nicht von selbst mit seinem Inhalt; in
     den Einstellungen fiel das nie auf, weil die Untertitel dort einzeilig
     sind. Hier sind sie es nicht. */
  #pushBody .setZeile { height: auto; align-items: flex-start; }
  #pushBody .setZeile .sym, #pushBody .setZeile .schalterKnauf { margin-top: 2px; }
  #pushUebersicht { font-size: 0.86rem; color: var(--text-3); margin-top: 14px; line-height: 1.5; }
  #pushProtokoll { margin-top: 12px; font-size: 0.78rem; color: var(--text-3); max-height: 200px; overflow-y: auto; }
  #pushProtokoll h4 { margin: 0 0 6px; font-size: 0.82rem; color: var(--text-2); }
  #pushProtokoll .pz { padding: 5px 0; border-top: 1px solid var(--border); line-height: 1.35; }
  #pushProtokoll .pz b { color: var(--text-2); }
  #pushProtokoll .ok { color: var(--success-text); font-weight: 600; }
  #pushProtokoll .nok { color: var(--danger); font-weight: 600; }
  #pushProtokoll .skip { color: var(--muted); font-weight: 600; }
  /* v2.74.1 (Sörens Befund vom 08.09.): #rueckModal fehlte hier. Es bekam
     nur ".modalBox"-Regeln, war selbst aber ein ganz gewöhnliches div im
     Textfluss - beim Öffnen stand sein Inhalt mitten in der Raumliste,
     ohne Hintergrund. Aufgefallen ist es erst, als nach dem Löschen der
     letzten Rückmeldung die Karten fehlten, die es vorher verdeckt hatten. */
  #setModal, #neuModal, #raumModal, #rueckModal, #tourModal {
    display: none; position: fixed; inset: 0; background: var(--overlay);
    z-index: 1200; align-items: center; justify-content: center; padding: 16px;
  }
  #raumModal .modalBox { max-width: var(--blatt-breit); display: flex; flex-direction: column; max-height: var(--blatt-hoch); }
  #raumModalBody { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch; margin: -4px -4px 12px; padding: 4px; }
  /* v1.8.0: Wie bei allen anderen Fenstern: Kopf und Knopfleiste stehen
     fest, nur der Inhalt scrollt. Vorher scrollte das ganze Fenster, und
     der Schliessen-Knopf lag beim Changelog unter dem Bildschirmrand. */
  #setModal .modalBox { max-width: var(--blatt-breit); display: flex; flex-direction: column; max-height: var(--blatt-hoch); }
  #setBody { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch; margin: -4px -4px 12px; padding: 4px; }
  .setGruppe { margin-bottom: 18px; }
  /* v3.22.0: Kapitel-Überschrift INNERHALB einer Einstellungsseite - die
     Seite "Punkte" führt drei Themen (Einkaufen, wer sammelt, wofür). */
  .setKapitel { margin: 16px 2px 6px; font-size: 0.78rem; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--muted); font-weight: 600; }
  #setBody > .setKapitel:first-child { margin-top: 2px; }
  .setAuswahlBlock { margin: 2px 0 6px; padding: 10px 12px; border: 1px solid var(--border);
    border-radius: var(--radius); background: var(--surface); }
  .setAuswahlBlock .blattKnoepfe { margin-top: 8px; }

/* v3.23.0: Der Editor für die Stufenleiter - eine Zeile je Stufe:
   Nummer, Symbol, Name, "ab X P", Entfernen. Auf 320 px muss alles in
   EINE Zeile passen, deshalb schmale Felder und ein kurzes Zahlenfeld. */
.pkEditListe { display: flex; flex-direction: column; gap: 6px; margin: 8px 0; }
.pkEditZeile { display: flex; align-items: center; gap: 6px; }
.pkEditNr { flex: none; width: 16px; text-align: right; font-size: 0.7rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* Die Kennung mitschreiben: "#editModalFields input" setzt width:100%
   (0,1,1) - eine Klasse allein käme dagegen nicht an, und alle drei Felder
   stünden brettbreit untereinander. */
#editModalFields .pkEditZeile input { margin-top: 0; }
#editModalFields .pkEditSymbol { flex: none; width: 46px; min-height: 44px; text-align: center; font-size: 1.05rem; padding: 4px 2px; }
#editModalFields .pkEditName { flex: 1; min-width: 0; min-height: 44px; padding: 8px 10px; font-size: 16px; }
.pkEditAb { flex: none; display: inline-flex; align-items: center; gap: 2px; }
#editModalFields .pkEditAbFeld { width: 68px; min-height: 44px; text-align: right; padding: 8px 6px; font-size: 16px; }
#editModalFields .pkEditAbFeld:disabled { opacity: .55; }
.pkEditAb span { font-size: 0.7rem; color: var(--muted); }
.pkEditWeg { flex: none; width: 32px; min-height: 44px; border: 0; background: none; color: var(--muted-2); font-size: 1rem; cursor: pointer; }
.pkEditWeg.leer { cursor: default; }
.pkEditWeg:active { color: var(--danger); }
@media (max-width: 340px) {
  /* Auf einem schmalen Handy muss die vierstellige Punktzahl ganz
     hineinpassen - lieber das kleine "P" weg (die Vorlese-Beschriftung
     sagt es weiter) als eine abgeschnittene Zahl. */
  #editModalFields .pkEditSymbol { width: 38px; }
  #editModalFields .pkEditAbFeld { width: 62px; }
  #editModalFields .pkEditName { padding: 8px 6px; }
  .pkEditAb span { display: none; }
  .pkEditZeile { gap: 4px; }
  .pkEditWeg { width: 26px; }
}
  .setGruppe h4 { margin: 0 0 8px; font-size: 0.78rem; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--muted); font-weight: 600; }
  /* v2.41.0: Kopfzeile der Einstellungen mit Zurück-Weg. */
  .setKopf { display: flex; align-items: center; gap: 6px; }
  .setZurueck {
    flex: none; width: 44px; min-height: 44px; margin-left: -10px;
    border: 0; border-radius: var(--r-s); background: none;
    color: var(--text-2); font: inherit; font-size: 1.4rem; line-height: 1; cursor: pointer;
  }
  .setZurueck:active { background: var(--surface-2); }
  /* Ein Menüpunkt, der auf eine Unterseite führt: wie eine setZeile, aber
     mit Pfeil rechts - so sieht man vorher, dass es weitergeht. */
  .setZeile .pfeil { flex: none; color: var(--muted-2); font-size: 1.05rem; }
  .setSeitenFuss { margin-top: 4px; font-size: 0.82rem; color: var(--muted); }
  /* Trennt das Gefährliche (Chat leeren, Abmelden) vom Rest - man soll es
     nicht auf dem Weg nach unten treffen. */
  .setTrenner { height: 1px; background: var(--border); margin: 14px 2px 10px; }

  .setZeile { display: flex; align-items: center; gap: 12px; width: 100%;
    min-height: 48px; padding: 9px 12px; margin-bottom: 6px; border: 1px solid var(--border);
    border-radius: var(--r-s); background: var(--bg); cursor: pointer; text-align: left; font: inherit; }
  .setZeile:active { background: var(--surface-2); }
  .setZeile .sym { font-size: 1.15rem; flex: 0 0 auto; width: 24px; text-align: center; }
  .setZeile .txt { flex: 1; min-width: 0; }
  /* v1.8.0: Titel und Untertitel sind span-Elemente - ohne display:block
     standen sie in EINER Zeile ("MitteilungenVom Gerät blockiert …"). */
  .setZeile .tt { display: block; font-size: 0.92rem; color: var(--text); font-weight: 500; }
  .setZeile .ut { display: block; font-size: 0.78rem; color: var(--muted); margin-top: 1px; line-height: 1.3; }
  .setZeile.warn .tt { color: var(--danger); }
  .setFuss { font-size: 0.78rem; color: var(--muted-2); text-align: center; margin-top: 4px; line-height: 1.5; }
  #neuModal .modalBox { max-width: var(--blatt-breit); display: flex; flex-direction: column; max-height: var(--blatt-hoch); }
  #neuBody { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch; margin: -4px -4px 12px; padding: 4px; }
  #neuBody .neuVersion { margin-bottom: 14px; }
  #neuBody .neuVersion.offen { border-left: 3px solid var(--success); padding-left: 12px; }
  #neuBody .neuVersion.alt { border-left: 3px solid var(--border); padding-left: 12px; }
  /* v1.8.0: Der Aufklapp-Pfeil sitzt oben rechts neben der Versionsnummer
     statt irgendwo unter der Schlagzeile zu schweben. */
  #neuBody .neuVersion.alt > summary { cursor: pointer; list-style: none; position: relative; padding-right: 26px; min-height: 44px; }
  #neuBody .neuVersion.alt > summary::-webkit-details-marker { display: none; }
  #neuBody .neuVersion.alt > summary::after { content: "▸"; color: var(--muted-2); position: absolute; right: 4px; top: -2px; font-size: 1.15rem; }
  #neuBody .neuVersion.alt[open] > summary::after { content: "▾"; }
  #neuBody .neuVersion.alt > summary .neuSchlag { font-weight: 500; color: var(--text-3); }
  #neuBody .neuKopf { font-size: 0.78rem; color: var(--muted); margin-bottom: 4px;
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  #neuBody .neuNr { font-weight: 600; color: var(--text-3); }
  #neuBody .neuDatum { color: var(--muted-2); }
  #neuBody .neuChip { background: var(--success); color: var(--auf-farbe); font-size: 0.7rem; font-weight: 700;
    letter-spacing: 0.05em; padding: 1px 6px; border-radius: var(--r-l); }
  #neuBody .neuSchlag { font-size: 0.92rem; font-weight: 600; color: var(--text); margin-bottom: 8px; line-height: 1.35; }
  #neuBody ul { margin: 0 0 4px 18px; padding: 0; }
  #neuBody li { margin: 5px 0; font-size: 0.92rem; color: var(--text-2); line-height: 1.45; }
  #neuBody .neuTrenner { display: flex; align-items: center; gap: 10px; margin: 18px 0 14px; }
  #neuBody .neuTrenner::before, #neuBody .neuTrenner::after {
    content: ""; flex: 1; height: 1px; background: var(--border); }
  #neuBody .neuTrenner span { font-size: 0.7rem; color: var(--muted-2); letter-spacing: 0.04em; }
  #neuBody .neuTechnik { margin-top: 10px; border-top: 1px solid var(--border); padding-top: 8px; }
  #neuBody .neuTechnik summary { font-size: 0.82rem; color: var(--text-3); cursor: pointer; }
  #neuBody .neuTechnik li { font-size: 0.82rem; color: var(--text-3); }
  /* v2.84.0: Umschalter und die Ansicht "Neu für dich". */
  #neuBody .neuWahl { display: flex; gap: 6px; margin: 0 0 14px; }
  #neuBody .neuWahl button { flex: 1; min-height: 44px; border: 1px solid var(--border-2); background: var(--bg);
    color: var(--text-2); border-radius: var(--r-s); font-size: 0.82rem; font-weight: 600; padding: 8px 6px; }
  #neuBody .neuWahl button.aktiv { background: var(--surface); color: var(--text); border-color: var(--accent); }
  #neuBody .neuVorspann { font-size: 0.82rem; color: var(--text-3); margin: 0 0 14px; line-height: 1.45; }
  #neuBody .neuFunktion { margin-bottom: 16px; padding-left: 12px; border-left: 3px solid var(--border); }
  #neuBody .neuFunktion.frisch { border-left-color: var(--success); }
  #neuBody .neuFunktion .neuSchlag { margin-bottom: 6px; }
  #neuBody .neuFunktion .neuDatum { font-size: 0.7rem; color: var(--muted-2); margin-top: 4px; }
  #neuBody .neuArt { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.05em; padding: 1px 6px;
    border-radius: var(--r-l); background: var(--surface); color: var(--muted); }

  /* v2.84.0: Der Rundgang für Neue (tutorial.js). */
  #tourBody .tourPunkte { display: flex; gap: 6px; justify-content: center; margin: 0 0 16px; }
  #tourBody .tourPunkte span { width: 7px; height: 7px; border-radius: var(--r-kreis); background: var(--border-2); }
  #tourBody .tourPunkte span.aktiv { background: var(--accent); }
  #tourBody .tourText { font-size: 0.92rem; color: var(--text-2); line-height: 1.5; margin: 0 0 14px; }
  #tourBody .tourFuss { font-size: 0.82rem; color: var(--text-3); line-height: 1.45; margin: 14px 0 0;
    border-top: 1px solid var(--border); padding-top: 10px; }
  #tourBody .tourListe { margin: 0 0 0 18px; padding: 0; }
  #tourBody .tourListe li { margin: 7px 0; font-size: 0.92rem; color: var(--text-2); line-height: 1.45; }
  #tourBody .tourChat { background: var(--surface); border-radius: var(--r-m); padding: 12px; }
  #tourBody .tourBlase { background: var(--accent); color: var(--auf-farbe); border-radius: var(--r-m) var(--r-m) var(--r-m) var(--r-xs);
    padding: 9px 12px; font-size: 0.92rem; display: inline-block; max-width: 100%; }
  #tourBody .tourFolge { font-size: 0.86rem; color: var(--text-3); margin-top: 8px; line-height: 1.4; }

  /* v2.86.0: Zugang je Person - eine Zeile unter dem Namen. */
  .leuteZugang { margin-right: 6px; }
  .leuteZugangZeile { display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    margin: 0 0 10px 34px; font-size: 0.82rem; color: var(--text-3); }
  .leuteZugangZeile .blattAktion { min-height: 40px; padding: 6px 12px; font-size: 0.82rem; }
  .leuteZugangWeg { min-height: 40px; border: 1px solid var(--border-2); border-radius: var(--r-s);
    background: var(--bg); color: var(--danger); font-size: 0.82rem; padding: 6px 10px; }
  .leuteZugangWeg:active { background: var(--danger-bg); }

  /* v2.87.0: Das Band über allem, wenn man in einer Demo steckt. */
  #demoBand { position: fixed; top: 0; left: 0; right: 0; z-index: 1600;
    display: flex; align-items: center; gap: 10px; padding: 8px 12px;
    background: var(--warn-bg); color: var(--warn-text); border-bottom: 1px solid var(--warn-border);
    font-size: 0.82rem; line-height: 1.35; padding-top: calc(8px + env(safe-area-inset-top)); }
  #demoBand button { flex: 0 0 auto; min-height: 44px; border: 1px solid var(--warn-border);
    border-radius: var(--r-s); background: var(--bg); color: var(--text-2); font-size: 0.82rem;
    font-weight: 600; padding: 6px 10px; }
  /* v3.33.0: Hier stand fest 44 px, das Band ist auf einem schmalen Gerät
     aber 70 px hoch (der Satz bricht um) - es lag also über dem Raumkopf,
     genau bei den Leuten, die einen Demo-Link bekommen. Die Höhe kommt
     jetzt gemessen aus demoBandPruefen(). */
  body.mitDemoBand { padding-top: var(--demoband-hoehe, 44px); }

  /* v3.69.0: Probemonat - Band kurz vor dem Ende, Wand danach. */
  #tarifBand { position: fixed; top: 0; left: 0; right: 0; z-index: 1600;
    display: flex; align-items: center; gap: 10px; padding: 8px 12px;
    background: var(--warn-bg); color: var(--warn-text); border-bottom: 1px solid var(--warn-border);
    font-size: 0.82rem; line-height: 1.35; padding-top: calc(8px + env(safe-area-inset-top)); }
  #tarifBand span { flex: 1 1 auto; }
  #tarifBand a { flex: 0 0 auto; min-height: 44px; display: inline-flex; align-items: center; border: 1px solid var(--warn-border);
    border-radius: var(--r-s); background: var(--bg); color: var(--text-2); font-size: 0.82rem; font-weight: 600; padding: 6px 10px; text-decoration: none; }
  body.mitTarifBand { padding-top: 60px; }
  /* :not([hidden]) - sonst überstimmt das display:flex das hidden-Attribut, und die
     unsichtbare Wand fängt alle Klicks der App ab (der Sweep fand es). */
  #tarifWand:not([hidden]) { position: fixed; inset: 0; z-index: 1700; display: flex; align-items: center; justify-content: center;
    padding: 16px; background: rgba(10, 12, 20, 0.55); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); }
  .tarifWandKarte { max-width: 420px; width: 100%; background: var(--bg); color: var(--text); border-radius: var(--radius-l); padding: 22px 20px;
    box-shadow: var(--shadow-2); text-align: center; }
  .tarifWandSymbol { font-size: 44px; line-height: 1; margin-bottom: 8px; }
  .tarifWandKarte h3 { margin: 0 0 8px; font-size: 1.15rem; }
  :where(.tarifWandKarte) p { margin: 0 0 10px; font-size: 0.92rem; line-height: 1.45; }
  .tarifWandKnoepfe { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin: 14px 0 8px; }
  .tarifWandKnopf { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; padding: 8px 16px;
    border-radius: var(--radius-s); border: 1px solid var(--border); background: var(--surface, var(--bg)); color: var(--text); font: inherit; font-weight: 600; text-decoration: none; cursor: pointer; }
  .tarifWandKnopf.haupt { background: var(--accent); color: var(--auf-farbe); border-color: var(--accent); }
  .tarifWandKlein { font-size: 0.82rem; color: var(--text-2); }

  /* v2.89.0: Die Abschnitte im Blatt "Personen & Zugänge". */
  .zugAbschnitt { margin-bottom: 22px; }
  .zugAbschnitt + .zugAbschnitt { border-top: 1px solid var(--border); padding-top: 16px; }
  .zugAbschnitt > h4 { margin: 0 0 10px; font-size: 0.92rem; color: var(--text-2); }
  .zugAbschnitt .aiToggle { display: flex; align-items: center; gap: 10px; min-height: 44px; font-size: 0.92rem; color: var(--text-2); }
  /* v3.142.0 (Befund D9): Der Satz links, der Schalter (.bsSchalter) rechts - wie jede Schalter-Zeile. */
  .zugAbschnitt .aiToggle .aiToggleText { flex: 1 1 auto; min-width: 0; }
  #pushSelbsttest { margin-top: 12px; font-size: 0.78rem; color: var(--text-3); line-height: 1.35; }
  #pushSelbsttest h4 { margin: 12px 0 6px; font-size: 0.82rem; color: var(--text-2); }
  #pushSelbsttest .pz { padding: 4px 0; border-top: 1px solid var(--border); word-break: break-word; }
  #pushSelbsttest .ok { color: var(--success-text); font-weight: 700; }
  #pushSelbsttest .nok { color: var(--danger); font-weight: 700; }
  #pushDiagnose { margin-top: 12px; font-size: 0.78rem; color: var(--text-3); line-height: 1.35; }
  #pushDiagnose h4 { margin: 0 0 6px; font-size: 0.82rem; color: var(--text-2); }
  #pushDiagnose .pz { padding: 4px 0; border-top: 1px solid var(--border); word-break: break-word; }
  #editModal {
    position: fixed; inset: 0; background: var(--overlay);
    display: none; align-items: center; justify-content: center; z-index: 30; padding: 20px;
  }
  /* v23.34: Am Handy liegen die Modale als Bottom-Sheet am unteren Rand.
     Vorher standen sie mittig und scrollten nicht - mit offener Tastatur
     waren Datum und Uhrzeit beim Termin-Bearbeiten unerreichbar. Hoehe und
     Versatz kommen aus denselben Variablen wie bei #app, damit das Fenster
     immer im SICHTBAREN Bereich liegt. */
  /* v1.8.0: Der Handy-Block (Bottom-Sheets) steht jetzt am ENDE der
     Stilangaben - siehe dort. Hier stand er vorher VOR den Regeln fuer
     #lernModal und #archivModal, die ihn mit gleicher Gewichtung wieder
     ueberschrieben haben: diese Fenster schwebten deshalb als Karte mit
     Rand ueber dem unteren Bildschirmdrittel statt sauber unten anzuliegen. */
  .modalBox { background: var(--bg); border-radius: var(--r-m); padding: 20px; width: 100%; max-width: var(--blatt-schmal); }
  .modalBox h3 { margin: 0 0 14px; }
  #editModalFields { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
  :where(#editModalFields) label { font-size: 0.78rem; color: var(--text-3); font-weight: 700; }
  :where(#editModalFields) input {
    width: 100%; padding: 11px 12px; border: 1px solid var(--border-2); border-radius: var(--r-s);
    font-size: 16px; margin-top: 3px;
  }
  /* v3.37.0 (Paket 5, Befund S44): 0.7 rem sind 11,2 px - fuer ein Wort in
     einem Chip in Ordnung, fuer ganze Erklaerabsaetze nicht. Und genau die
     stehen hier: die Personen-Einleitung, die Punkte-Regeln, die
     Import-Hinweise, die Farb- und Genehmigen-Erklaerung (rund 330
     Zeichen). Eine Stufe hoeher auf der vorhandenen Skala. */
  .feldHinweis { font-size: 0.78rem; color: var(--muted); margin-top: 2px; line-height: 1.45; }
  .modalActions { display: flex; gap: 10px; justify-content: flex-end; }
  .modalActions button { padding: 11px 18px; min-height: 44px; border-radius: var(--r-s); border: none; font-size: 0.92rem; font-weight: 600; }
  .modalActions button.cancelBtn { background: var(--border); color: var(--text-2); }
  .modalActions button.saveBtn { background: var(--primary); color: var(--on-primary); }

  #versionTag {
    position: absolute; bottom: 2px; left: 12px; font-size: 0.7rem; color: var(--muted-2); pointer-events: none;
  }
  /* Bei offener Tastatur lag die Versionsnummer mitten auf dem Schreibfeld. */
  body.tastatur #versionTag { display: none; }

  /* --- Archiv-Modal (v23.1) --- */
  #lernModal {
    display: none; position: fixed; inset: 0; background: var(--overlay);
    align-items: center; justify-content: center; z-index: 60; padding: 16px;
  }
  #lernModal .modalBox { max-width: var(--blatt-breit); display: flex; flex-direction: column; max-height: var(--blatt-hoch); }
  #lernBody { overflow-y: auto; flex: 1; margin: -4px -4px 10px; padding: 4px; }
  .lernErklaerung { font-size: 0.78rem; color: var(--text-3); background: var(--accent-bg); border: 1px solid var(--border);
    border-radius: var(--r-s); padding: 9px 11px; line-height: 1.45; }
  .lernErklaerung b { color: var(--text); }
  .lernZahlen { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 12px 0 4px; }
  .lernZahl { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-s); padding: 9px 10px; }
  .lernZahl .wert { font-size: 1.3rem; font-weight: 700; }
  .lernZahl .was { font-size: 0.7rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
  .lernGruppe { margin-top: 16px; }
  .lernGruppe h4 { margin: 0 0 3px; font-size: 0.82rem; }
  .lernGruppe .wirkung { font-size: 0.7rem; color: var(--muted); margin: 0 0 7px; line-height: 1.4; }
  .lernZeile { display: flex; align-items: center; gap: 8px; padding: 6px 2px; border-top: 1px solid var(--border); font-size: 0.86rem; }
  .lernZeile .wort { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .lernZeile .mal { font-size: 0.78rem; color: var(--muted); font-variant-numeric: tabular-nums; }
  /* 44 px Trefflaeche fuer das ✕, ohne die Zeile hoeher zu machen. */
  .lernZeile .weg { color: var(--icon-muted); cursor: pointer; width: 44px; height: 44px; flex: none;
    display: flex; align-items: center; justify-content: center; margin: -8px -10px -8px 0; font-size: 1.05rem; }
  .lernZeile.istGesperrt .wort { text-decoration: line-through; color: var(--muted); }
  .lernLeer { font-size: 0.78rem; color: var(--muted-2); padding: 6px 2px; }
  .lernKorrektur { font-size: 0.78rem; color: var(--text-3); padding: 5px 2px; border-top: 1px solid var(--border); }
  .kiLogZeile { padding: 7px 2px; border-top: 1px solid var(--border); }
  .kiLogText { font-size: 0.82rem; color: var(--text); }
  .kiLogErkannt { font-size: 0.7rem; color: var(--success-text); margin-top: 2px; }
  .kiLogErkannt.leer { color: var(--danger); }
  .kiLogZeit { font-size: 0.7rem; color: var(--muted-2); margin-top: 1px; }
  .lernStats { font-size: 0.7rem; color: var(--muted); margin-top: 4px; line-height: 1.45; }

  #archivModal {
    position: fixed; inset: 0; background: var(--overlay);
    display: none; align-items: center; justify-content: center; z-index: 30; padding: 20px;
  }
  #archivModal .modalBox { max-width: var(--blatt-breit); display: flex; flex-direction: column; max-height: var(--blatt-hoch); }
  #archivBody { overflow-y: auto; margin-bottom: 14px; min-height: 60px; }
  .archivEintrag {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    padding: 10px 4px; border-bottom: 1px solid var(--border);
  }
  .archivEintrag .archivInfo { flex: 1; cursor: pointer; }
  .archivEintrag .archivZeitraum { font-weight: 600; font-size: 0.92rem; }
  .archivEintrag .archivAnzahl { font-size: 0.82rem; color: var(--muted); }
  .archivEintrag .archivDelBtn {
    border: none; background: var(--danger-bg); color: var(--danger); border-radius: var(--r-s);
    padding: 8px 14px; min-height: 40px; font-size: 0.82rem;
  }
  .archivMsg { padding: 5px 2px; border-bottom: 1px solid var(--surface-2); font-size: 0.86rem; }
  .archivMsg .archivMeta { font-size: 0.7rem; color: var(--muted); }
  .archivLeerHinweis { color: var(--muted); font-size: 0.86rem; padding: 10px 2px; }

  /* v1.8.0: Die Versionsnummer lag unten links UEBER dem ✨-Knopf und im
     Startbild ueber den Ankreuzfeldern. Sie steht ohnehin in den
     Einstellungen ("Oberfläche v…") - hier ist sie weg. Das Element bleibt,
     das Skript schreibt weiter hinein. */
  #versionTag { display: none; }

  /* --- Handy: alle Fenster als Bottom-Sheet (v23.34, v1.8.0) ---
     Steht bewusst als LETZTER Block, damit keine spaetere Regel mit
     gleicher Gewichtung (#lernModal .modalBox usw.) ihn aushebelt.
     Hoehe und Versatz bei offener Tastatur kommen aus denselben Variablen
     wie bei #app, damit das Fenster immer im SICHTBAREN Bereich liegt. */
  @media (max-width: 480px) {
    #editModal, #lernModal, #archivModal, #pushModal, #setModal, #neuModal, #raumModal, #tourModal, #rueckModal {
      top: 0; left: 0; right: 0; bottom: 0;
      align-items: flex-end; padding: 0;
    }
    body.tastatur #editModal, body.tastatur #lernModal, body.tastatur #archivModal, body.tastatur #pushModal,
    body.tastatur #setModal, body.tastatur #neuModal, body.tastatur #raumModal, body.tastatur #rueckModal {
      bottom: auto;
      height: var(--app-hoehe, 100%);
      transform: translateY(var(--app-versatz, 0px));
    }
    #editModal .modalBox, #lernModal .modalBox, #archivModal .modalBox, #pushModal .modalBox,
    #setModal .modalBox, #neuModal .modalBox, #raumModal .modalBox, #tourModal .modalBox, #rueckModal .modalBox {
      max-width: none; width: 100%; border-radius: var(--r-l) var(--r-l) 0 0;
      /* v2.9.3: Auf einem iPhone ist oben die Statusleiste - ohne diesen
         Abstand lag der Titel des Blatts dahinter und war abgeschnitten. */
      max-height: calc(100% - var(--sat, 0px) - 24px);
      display: flex; flex-direction: column;
      padding: 10px 18px calc(16px + var(--sab));
    }
    /* Griff oben - Zeichen dafuer, dass es ein Sheet ist. */
    .modalBox::before {
      content: ""; display: block; width: 38px; height: 4px; border-radius: var(--r-xs);
      background: var(--border-2); margin: 0 auto 12px; flex: none;
    }
    .modalBox h3 { flex: none; }
    #editModalFields, #pushBody, #lernBody, #archivBody, #setBody, #neuBody, #raumModalBody {
      flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
      -webkit-overflow-scrolling: touch; padding: 2px 2px 6px; margin: -2px -2px 12px; }
    .modalActions { flex: none; }
    .modalActions button { flex: 1; }
  }

/* --- v2.1.0: Aufgaben (Reiter), Punkte, Archiv --- */
.todoSection { display: flex; align-items: center; gap: 8px; }
.todoSection.rot { color: var(--danger); }
.todoSectionZahl { background: var(--surface); color: var(--text-3); border-radius: var(--r-s); padding: 0 7px; font-size: 0.7rem; font-weight: 700; letter-spacing: 0; text-transform: none; }
.item.aufgabe { align-items: flex-start; }
.item.aufgabe .check { margin-top: 1px; }
.item.aufgabe .gText { flex: 1; min-width: 0; cursor: pointer; }
.item.aufgabe .name { font-size: 0.92rem; line-height: 1.35; }
.item.aufgabe .gMarken { margin-top: 3px; }
.marke.rhythmus { color: var(--accent-strong); }
.marke.punkte { color: var(--warn-text); letter-spacing: 1px; }
.marke.frist.ueber { color: var(--danger); font-weight: 700; }
.dndListe { margin-bottom: 4px; }
.dndListe .swipeReihe.dndAktiv { box-shadow: var(--shadow-2); z-index: 5; position: relative; }
.dndListe .swipeReihe.dndWarte .item { background: var(--surface); }
.todoLogbuch { margin-top: 10px; border: 1px solid var(--border); border-radius: var(--r-s); }
.todoLogbuch summary { padding: 12px 14px; }
.todoLogbuch .swipeReihe { border-radius: 0; margin-bottom: 0; }
.todoLogbuch .item { border-radius: 0; margin-bottom: 0; border-top: 1px solid var(--border); background: var(--surface); }
.erledigtHeute { background: var(--success-bg); border: 1px solid var(--success-border); border-radius: var(--r-s); padding: 4px 12px; margin-bottom: 8px; }
.erledigtZeile { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-top: 1px solid var(--success-bg); min-height: 44px; }
.erledigtZeile:first-child { border-top: none; }
.erledigtZeile .ok { flex: none; width: 22px; height: 22px; border-radius: var(--r-kreis); background: var(--success); color: var(--auf-farbe); font-size: 0.82rem; font-weight: 700; display: flex; align-items: center; justify-content: center; }
.erledigtZeile .txt { flex: 1; min-width: 0; font-size: 0.92rem; }
.erledigtZeile .wer { display: block; font-size: 0.7rem; color: var(--muted); }
.erledigtZeile button { flex: none; border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-s); width: 40px; height: 40px; font-size: 1rem; color: var(--text-2); }

/* --- v2.27.0: "Wer hat das gemacht?" ---
   Eine Erledigung ohne Person ist KEIN Fehler - sie wartet nur auf eine
   Antwort. Deshalb ruhig (Grauton, kein Rot): der Hinweis oben im
   Punkte-Blatt, die offene Zeile im Verlauf und die Knopf-Blätter.
   .erledigtWahl macht die ganze Verlaufszeile antippbar und muss die
   40x40-Regel für Knöpfe in .erledigtZeile ausdrücklich aushebeln. */
.erledigtZeile .erledigtWahl {
  flex: 1; min-width: 0; width: auto; height: auto; min-height: 44px;
  display: flex; align-items: center; text-align: left;
  background: none; border: none; border-radius: var(--r-s);
  padding: 2px 4px; margin: 0 -4px; color: inherit; font: inherit; }
.erledigtZeile .erledigtWahl:active { background: var(--surface-2); }
.erledigtZeile .werFrage { color: var(--text-2); font-weight: 700; }
.erledigtZeile.hervor { background: var(--surface-2); border-radius: var(--r-s); }
.pkFrageHinweis {
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px;
  text-align: left; border: 1px solid var(--border-2); background: var(--surface);
  color: var(--text-2); border-radius: var(--r-s); padding: 8px 12px;
  font-size: 0.86rem; font-weight: 600; }
.pkFrageHinweis:active { background: var(--surface-2); }
.pkFrageHinweis .pkFragePfeil { margin-left: auto; color: var(--text-3); font-size: 1.15rem; }
/* Die Knöpfe im Blatt: Farbpunkt + Name, mittig, mindestens 44 px hoch
   (das bringt .blattAktion mit; hier kommt nur die Ausrichtung dazu). */
.blattKnoepfe .werKnopf { display: flex; align-items: center; justify-content: center; gap: 8px; }
.blattKnoepfe .werKnopf.keiner { color: var(--text-3); }
.punkteKarte { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-m); padding: 12px 14px 8px; margin-bottom: 12px; cursor: pointer; }
.punkteKarte:active { background: var(--surface); }
.pkKopf { display: flex; justify-content: space-between; align-items: center; font-weight: 700; font-size: 0.92rem; margin-bottom: 6px; }
.pkMehr { color: var(--accent); font-weight: 600; font-size: 0.82rem; }
.pkUnter { font-weight: 400; color: var(--muted); font-size: 0.78rem; margin-left: 6px; }
.pkBlock { margin-bottom: 14px; }
/* v3.20.0: Offene Wünsche stehen als eigener Kasten über den Belohnungen -
   sie sind eine Frage an die Eltern, keine Liste zum Durchblättern. */
.wunschBlock { border: 1px solid var(--warn-border); background: var(--warn-bg); border-radius: var(--r-s); padding: 6px 10px; margin: 4px 0 10px; }
.wunschKopf { font-size: 0.78rem; font-weight: 700; color: var(--warn-text); margin-bottom: 2px; }
.wunschZeile { border-bottom: 0; padding: 4px 0; }
.wunschKnoepfe { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
.wunschKnoepfe .blattAktion { flex: 0 0 auto; min-height: 40px; padding: 6px 12px; font-size: 0.82rem; white-space: nowrap; }
/* v3.20.0 (Befund beim Bilddurchlauf): In .erledigtZeile ist jeder Knopf
   40x40 breit - gedacht für Zeichen wie ↩︎ und ✎. Der Knopf „Einlösen“
   stand deshalb seit v2.12.0 als „Ein…“ da. Knöpfe mit einem WORT darauf
   bekommen ihre Breite vom Text. */
.erledigtZeile button.wortKnopf, .wunschKnoepfe .blattAktion { width: auto; min-width: 44px; padding-inline: 14px; white-space: nowrap; }
.wunschKnoepfe .blattAktion.leise { background: var(--surface); border-color: var(--border-2); color: var(--text-2); }
.pkBlock > label { display: block; font-size: 0.78rem; color: var(--text-3); font-weight: 700; margin-bottom: 4px; }
.punkteZeile { display: flex; align-items: center; gap: 10px; padding: 5px 0; }
.punkteZeile .pName { flex: 0 0 76px; font-size: 0.86rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.punkteZeile .pBalken { flex: 1; height: 10px; background: var(--surface); border-radius: var(--r-xs); overflow: hidden; }
.punkteZeile .pBalken i { display: block; height: 100%; background: var(--success); border-radius: var(--r-xs); min-width: 2px; }
.punkteZeile .pWert { flex: 0 0 auto; font-size: 0.86rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.punkteZeile .pAnzahl { font-weight: 400; color: var(--muted); font-size: 0.7rem; margin-left: 4px; }
#addTodoFormBox label.feld select { min-height: 44px; }

/* v2.1.1: Gelernte Aufgaben – Titel darf umbrechen, Sterne/Rhythmus rechts bleiben lesbar */
.lernGruppe.aufgaben .lernZeile .wort { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.25; }
.lernGruppe.aufgaben .lernZeile .mal { flex: 0 0 auto; max-width: 46%; text-align: right; }

/* ============================================================
   v2.2.0: Essensplan im Reiter Termine
   ============================================================ */
/* v3.47.0 (Paket 6, Befund F54): "📅 Woche planen · + Essen einplanen ·
   ✨ Vorschlag" teilen sich 320-390 px. Der mittlere Knopf brach in zwei
   Zeilen, die Nachbarn nicht - drei ungleich hohe Knoepfe. Jetzt sind
   alle drei gleich hoch (stretch, nicht mittig), und unterhalb von
   400 px faellt das Wort "einplanen" weg; die Vorlese-Beschriftung am
   Knopf nennt es weiter vollstaendig. */
.essenLeiste { display: flex; align-items: stretch; gap: 6px; margin: -4px 0 12px; }
@media (max-width: 400px) {
  .essenLeiste .essenWort { display: none; }
  /* Damit alle drei einzeilig bleiben, faellt unter 400 px zusaetzlich das
     Zeichen am Anfang weg. Ein Wort sagt mehr als ein Bildchen; die
     Vorlese-Beschriftung am Knopf nennt ohnehin die ganze Sache. */
  .essenLeiste .essenZeichen { display: none; }
  .essenLeiste button { padding: 6px 4px; }
}
.essenLeiste button { flex: 1; min-height: 40px; border: 1px dashed var(--warn-border); background: var(--warn-bg); color: var(--warn-text); border-radius: var(--r-s); font-size: 0.82rem; font-weight: 600; padding: 6px 8px; }
.kalPunkte i.essen { background: var(--warn); border-radius: var(--r-xs); }
.item.essen { background: var(--warn-bg); border-left: 3px solid var(--warn); border-radius: var(--r-s); padding-left: 9px; }
/* v2.9.3: EINE Zeile - Gericht, dahinter die Mahlzeit als Kuerzel. */
.item.essen.einzeilig { padding-top: 7px; padding-bottom: 7px; gap: 8px; }
.item.essen .essenText { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 7px; overflow: hidden; }
.item.essen .essenText .name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.92rem; }
.item.essen .essenMahl { flex: none; font-size: 0.78rem; color: var(--warn-text); }
.item.essen .essenNotiz { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.item.essen .name { color: var(--warn-text); }
.item.essen .essenSymbol { width: 26px; height: 26px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 1rem; }
.item.essen .essenNotiz { font-weight: 400; color: var(--warn-text); font-size: 0.82rem; }
.essenTagKnopf { width: 100%; min-height: 42px; margin-top: 6px; border: 1px dashed var(--warn-border); background: transparent; color: var(--warn-text); border-radius: var(--r-s); font-size: 0.82rem; font-weight: 600; }
/* Blätter */
.mitKnopf { display: flex; gap: 6px; align-items: stretch; }
.mitKnopf input { flex: 1; min-width: 0; }
.vorschlagKnopf { flex: none; width: 46px; min-height: 44px; margin-top: 3px; border: 1px solid var(--warn-border); background: var(--warn-bg); border-radius: var(--r-s); font-size: 1rem; }
.vorschlagKnopf:disabled { opacity: 0.5; }
.gerichtChips, .essenChips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.gerichtChip, .essenChip { border: 1px solid var(--border); background: var(--surface-2); color: var(--text-2); border-radius: var(--r-voll); padding: 6px 10px; font-size: 0.78rem; font-weight: 600; min-height: 32px; }
.essenChip { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn-text); }
.essenChip.eingekauft { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); }
.essenChip small { font-weight: 400; opacity: 0.75; }
.zweier { display: grid; grid-template-columns: 1.4fr 1fr; gap: 8px; }
.blattKnoepfe { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.blattAktion { min-height: 44px; border: 1px solid var(--warn-border); background: var(--warn-bg); color: var(--warn-text); border-radius: var(--r-s); font-weight: 600; font-size: 0.86rem; padding: 8px 12px; }
.blattAktion:disabled { opacity: 0.45; }
.wocheKopf { display: flex; align-items: center; justify-content: space-between; font-weight: 700; font-size: 0.92rem; }
.wocheKopf button { width: 44px; height: 44px; border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--bg); font-size: 1.15rem; }
.wocheTag { display: flex; gap: 10px; padding: 8px 0; border-top: 1px solid var(--border); }
.wocheTag.heute .wocheTagName { color: var(--warn); }
.wocheTagName { flex: 0 0 44px; font-weight: 800; font-size: 0.92rem; padding-top: 12px; line-height: 1.1; }
.wocheTagName small { display: block; font-weight: 500; color: var(--muted); font-size: 0.7rem; }
.wocheTagInhalt { flex: 1; min-width: 0; }
.wocheTagInhalt .essenChips { margin: 0 0 6px; }
.zutatenGericht { font-size: 0.86rem; color: var(--text-2); padding: 2px 0; }
.zutatenGericht .mal { font-size: 0.7rem; color: var(--muted); }
.zutatenListe { border-top: 1px solid var(--border); }
.zutatZeile { display: flex; gap: 12px; align-items: flex-start; padding: 9px 0; border-bottom: 1px solid var(--border); font-size: 0.92rem; min-height: 44px; }
#editModalFields .zutatZeile input[type="checkbox"] { width: 22px; height: 22px; margin: 2px 0 0; accent-color: var(--warn); flex: none; }
.zutatZeile .zutatName { flex: 1; min-width: 0; }
.zutatZeile .zutatName .mal { color: var(--muted); font-size: 0.82rem; }
.zutatZeile.schonDa .zutatName { color: var(--muted); }
/* Zutaten-Zeilen: die allgemeinen Blatt-Regeln (label als Block, Eingaben in voller Breite) hier zuruecknehmen */
#editModalFields .zutatZeile { display: flex; font-size: 0.92rem; color: var(--text); font-weight: 400; }
#editModalFields .zutatZeile input[type="checkbox"] { padding: 0; border: none; margin-top: 3px; }

/* v2.2.1: Ort/Adresse/Link am Termin */
.item .wann a.ortLink { color: var(--accent); text-decoration: none; border-bottom: 1px dotted rgba(26,115,232,.5); }
.feldHinweis a.ortLink { color: var(--accent); text-decoration: none; }

/* v2.2.6: Ort, Anschrift und Link am Termin – eine ruhige kleine Zeile */
.item .ortZeile { margin-top: 3px; font-size: 0.78rem; line-height: 1.45; color: var(--muted); }
.item .ortLink { color: var(--accent-strong); text-decoration: none; font-weight: 600; padding: 1px 0;
  display: inline-block; max-width: 100%; vertical-align: bottom;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.item .ortLink:active { opacity: 0.6; }
.item .ortAdresse { color: var(--muted); }
.item .ortTeil { white-space: nowrap; max-width: 100%; }
.item .ortTrenner { color: var(--border-2); margin: 0 5px; }
.item.done .ortLink { color: var(--muted-2); }

/* v2.17.0: Der verknuepfte Kontakt am Termin - eine weitere Angabe zum Ort.
   Eigen ist nur die Farbe des Oeffnungsstatus, und die steht nie allein:
   Symbol und Wort sagen dasselbe (wie in der Kontaktliste).
   v3.160.8: Die Kontaktzeile von v2.17.0 (.kontaktZeile mit dem Namen als
   Link .kontaktLink, terminKontaktZeileHtml) gibt es nicht mehr - seit das
   Termin-Blatt aus Beta freigegeben ist, steht der Kontakt als Text in der
   Zeile darüber und als Feld darunter (terminKontaktChipsHtml, Regeln unten
   bei .tbChip). Ihre Regeln sind weg; der Status bleibt. */
.item .terminStatus { font-weight: 700; color: var(--muted); }
.item .terminStatus.offen { color: var(--success-text); }
.item .terminStatus.gleich { color: var(--warn-text); }
.item .terminStatus.zu { color: var(--muted); }
.item.done .terminStatus { color: var(--muted-2); }

/* ---- v2.4.0: Unsere Gerichte ------------------------------------- */
.gerichteKopf { margin-bottom: 10px; }
.vegSchalter { display: flex; align-items: center; gap: 8px; font-size: 0.92rem; padding: 8px 0; cursor: pointer; }
.vegSchalter input { width: 20px; height: 20px; accent-color: var(--success-text); flex: none; }
.gerichteFehler { color: var(--danger); }
.gerichteNeu { margin-bottom: 8px; }
.gerichteSuche { width: 100%; margin-bottom: 8px; }
.gerichteListe { max-height: 46vh; max-height: 46dvh; overflow-y: auto; -webkit-overflow-scrolling: touch; margin: 0 -4px; padding: 0 4px;
  touch-action: pan-y; /* v3.129.0: Scroller in der Essen-Fläche - GESTEN.md Regel 10 */ }
.gerichtZeile { display: flex; align-items: center; gap: 6px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.gerichtZeile:last-child { border-bottom: 0; }
.gerichtAus .gerichtName { color: var(--muted); text-decoration: line-through; }
.gerichtName { flex: 1 1 auto; min-width: 0; text-align: left; background: none; border: 0; padding: 8px 2px; font: inherit; color: inherit; cursor: pointer; display: flex; flex-direction: column; gap: 1px; }
.gerichtZusatz { font-size: 0.7rem; color: var(--muted); }
.gerichtKnoepfe { display: flex; gap: 2px; flex: none; }
.gMarke { position: relative; width: 34px; height: 34px; border: 0; background: none; border-radius: var(--r-s); font-size: 1rem; line-height: 1; padding: 0; cursor: pointer; opacity: 0.35; filter: grayscale(1); }
.gMarke.an { opacity: 1; filter: none; background: var(--surface-2); }
.gMarke.gWeg { opacity: 0.3; filter: none; font-size: 0.92rem; color: var(--muted); }
.gerichteHilfe { margin-top: 10px; line-height: 1.5; }

/* ---- v2.4.0: Aufgaben im Kalender und Tagesansicht --------------- */
.kalPunkte i.aufgabe { background: var(--kal-aufgabe); }
.kalPunkte i.aufgabe.spaet { background: var(--danger); }
.kalAufgabe { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); }
.kalAufgabe.ueberfaellig .kalAufgabeText > span:first-child { color: var(--danger); }
/* v3.99.0: 44 statt 30 - einheitlich-dom 3. Das Abhaken in der Terminliste
   war mit dem Finger kaum zu treffen. */
.kalHaken { position: relative; flex: none; width: 44px; height: 44px; border: 0; background: none; font-size: 1.15rem; line-height: 1; color: var(--muted); cursor: pointer; padding: 0; }
/* v3.99.0: min-height 44 - die Aufgabenzeile in der Terminliste war 18 px
   hoch. Eine Zeile Text ist hier ein Knopf, kein Text. */
.kalAufgabeText { flex: 1 1 auto; min-width: 0; min-height: 44px; display: flex; flex-direction: column; justify-content: center; gap: 1px; text-align: left; background: none; border: 0; padding: 2px 0; font: inherit; color: inherit; cursor: pointer; }
.kalAufgabeZusatz { font-size: 0.7rem; color: var(--muted); }
.tagAbschnitt { font-size: 0.78rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; margin: 14px 0 4px; }
.tagAbschnitt:first-child { margin-top: 4px; }
.tagKnoepfe { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.tagKnoepfe button, .tagKnoepfe .essenTagKnopf { flex: 1 1 auto; }
.tagHeuteZeile { display: flex; justify-content: center; margin: -4px 0 8px; }
.tagHeuteZeile button { border: 1px solid var(--border); background: var(--bg); border-radius: var(--r-voll); padding: 4px 14px; font-size: 0.82rem; color: var(--text-2); cursor: pointer; }
#tagTitel { font-weight: 600; }

/* v2.4.0 / v3.13.0: Die Ansichtsleiste traegt nur noch vier Ansichten -
   die zwei Einblend-Schalter stehen in ihrer eigenen Zeile (.einblendZeile).
   Vier Knoepfe passen bei 390 px nebeneinander; bei 320 px bricht
   "Geburtstage" um, und das ist richtig so. */
.ansichtWahl { flex-wrap: wrap; }
.ansichtWahl #ansichtListe, .ansichtWahl #ansichtKalender, .ansichtWahl #ansichtTag { flex: 1 1 22%; }
/* Geburtstage ist die vierte Ansicht, aber ihr Wort ist doppelt so lang wie
   die anderen drei. Statt es zu verstuemmeln, darf sie in die zweite Zeile -
   dort aber nur so breit sein, wie ihr Text braucht. */
.ansichtWahl #ansichtGeburtstage { flex: 0 1 auto; white-space: nowrap; }
/* Bei 320 px wird aus "🎂 Geburtstage" ein "🎂" - dann passen die vier
   Ansichten immer noch in eine Zeile. */
@media (max-width: 359px) { .ansichtWahl #ansichtGeburtstage .gebWort { display: none; } }

/* Der Haken im Gerichte-Blatt gegen die Breitenregel der Blatt-Felder. */
#editModalFields .vegSchalter { display: flex; align-items: center; gap: 10px; }
#editModalFields .vegSchalter input[type="checkbox"] { width: 22px; height: 22px; min-height: 0; margin: 0; flex: 0 0 auto; }
/* Fleischlos/mit-Fleisch ist eine Anzeige, kein An-Aus - darum ohne Graufilter. */
.gerichtZeile .gMarke[data-ga="veg"] { filter: none; opacity: 1; background: none; }
.gerichtZeile .gMarke[data-ga="veg"].an { background: var(--success-bg); }
.gMarke.gWeg { opacity: 0.45; color: var(--muted); }

/* ---- v2.4.1: Antwort-Knoepfe in der KI-Sprechblase ---------------- */
.antwortKnoepfe { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 2px; }
.antwortKnopf { flex: 0 1 auto; border: 1px solid var(--success-border); background: var(--bg); color: var(--success-text);
  border-radius: var(--r-voll); padding: 8px 14px; font-size: 0.86rem; font-weight: 600; min-height: 44px; cursor: pointer; /* v2.24.0: 44 px wie jeder Tipp-Knopf */
  /* v2.26.0: Die Aenderungs-Karte hat DREI Knoepfe, einer davon lang ("Ja,
     kuenftig ohne Nachfrage"). Die Reihe bricht um (flex-wrap oben), und
     ein einzelner Knopf darf nie breiter als die Blase werden - sonst
     liefe er auf 390 px rechts hinaus. Der Text bricht dann im Knopf. */
  max-width: 100%; white-space: normal; text-align: center; line-height: 1.3; }
.antwortKnopf:active { background: var(--success-bg); }
.antwortKnopf.anderer { color: var(--text-3); border-color: var(--border); font-weight: 500; }
.antwortKnopf:disabled { opacity: 0.5; }
.antwortKnopf.laeuft { background: var(--success); border-color: var(--success); color: var(--auf-farbe); opacity: 1; }
/* v2.17.0: Vorher --success-text (dunkelgruen) auf der blauen KI-Blase -
   rund 1,6:1, also praktisch nicht zu lesen. Aufgefallen ist es an der
   Ort-Karte: ausgerechnet die Bestaetigung der folgenreichsten Antwort
   ("Nie fragen") stand unlesbar da. Die Zeile steht ausschliesslich in
   der KI-Blase (antwortHtml wird nur dort gerufen), erbt also deren
   Weiss; das Haekchen bleibt die Aussage, die Farbe war nie eine. */
.antwortFertig { margin-top: 8px; font-size: 0.82rem; font-weight: 600; color: inherit; opacity: 0.9; }
/* v2.10.6 (Review-Fix): Inline-Feld statt prompt() fuer "anderer Laden ..." - selber Chip-Stil. */
.andererLadenZeile { display: flex; gap: 6px; width: 100%; margin-top: 2px; }
.andererLadenFeld { flex: 1; min-width: 0; min-height: 38px; border: 1px solid var(--border-2); background: var(--bg);
  border-radius: var(--r-voll); padding: 0 14px; font-size: 16px; color: var(--text); }
.antwortKnopf.andererOk { flex: none; }
/* v3.143.0: Antworten hinter „Andere Art …“ (antwort.mehrAb) - erst nach
   dem Tipp da. Ausdrücklich, weil .antwortKnopf in einer Flex-Reihe steht. */
.antwortKnopf[hidden] { display: none; }

/* v2.17.0: "Nie fragen" ist die einzige Antwort mit Gedaechtnis - sie sieht
   deshalb anders aus als "Nein" und fragt vor dem Senden nach (inline, im
   selben Chip-Stil wie das Laden-Feld; Browser-Dialoge gibt es hier seit
   v2.10.6 nicht mehr). */
.antwortKnopf.gefahr { border-color: var(--danger-border); color: var(--danger); }
.antwortKnopf.gefahr:active { background: var(--danger-bg); }
.nieSicherZeile { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; width: 100%; margin-top: 4px; }
/* Diese beiden stehen IMMER in der blauen KI-Blase - deshalb die Farbe der
   Blase erben statt einer eigenen. --text-3 war dort fast unlesbar. */
.nieSicherText { flex: 1 0 100%; font-size: 0.82rem; line-height: 1.4; color: inherit; opacity: 0.9; }
/* Was die Sammelfrage schon angelegt hat, und der Hinweis nach dem
   Zuruecknehmen - beides nur Bericht, kein Knopf. */
.antwortFortschritt { margin-top: 8px; font-size: 0.82rem; font-weight: 600; color: inherit; opacity: 0.9; }
/* Der Weg zurueck aus "Nie fragen". Wie die Daumen-Knoepfe in derselben
   Blase: durchscheinendes Weiss, damit er auf Blau ueberhaupt zu sehen ist. */
.antwortZurueck { margin-top: 8px; }
.antwortZurueck .undoBtn { border: 1px solid rgba(255,255,255,0.45); background: rgba(255,255,255,0.15);
  color: inherit; border-radius: var(--r-voll); padding: 8px 14px; font-size: 0.82rem; font-weight: 600; min-height: 38px; }
.antwortZurueck .undoBtn:disabled { opacity: 0.5; }

/* v2.4.1: kurze Rueckmeldung ohne Dialog */
/* v3.47.0 (Paket 6, Befund D65): Hier stand `bottom: 84px` ohne die
   sichere Zone. Auf einem iPhone mit Home-Anzeige rutschte die Meldung
   samt "Erneut senden" auf die Eingabezeile. #wischMeldung (822) rechnet
   die Zone laengst heraus - jetzt beide gleich. */
.kurzMeldung { position: fixed; left: 50%; bottom: calc(84px + var(--sab));
  transform: translateX(-50%) translateY(10px);
  background: var(--primary); color: var(--on-primary); padding: 10px 16px; border-radius: var(--r-voll); font-size: 0.86rem;
  /* v2.11.2: ueber allem (Blaetter liegen auf 1200) - sonst ist die Meldung
     samt "Rueckgaengig" nach einer Aktion aus einem Blatt heraus nicht zu
     sehen, und der Weg zurueck damit verbaut. */
  z-index: 1500; opacity: 0; pointer-events: none; transition: opacity .18s, transform .18s; max-width: 88vw; text-align: center; }
.kurzMeldung.an { opacity: 1; transform: translateX(-50%) translateY(0); }
/* v2.49.0: Meldung mit Knopf ("Erneut senden") - die muss antippbar sein. */
.kurzMeldung.mitKnopf { pointer-events: auto; border-radius: var(--r-l); padding: 10px 14px; }
.kurzMeldungKnopf { margin-left: 8px; border: 1px solid var(--on-primary); background: transparent; color: var(--on-primary);
  border-radius: var(--r-voll); padding: 6px 12px; font-size: 0.86rem; font-weight: 600; min-height: 32px; cursor: pointer; }
.bubble.audio .audioErneut { margin-top: 6px; }
/* v2.52.0: Umfrage am Programmpunkt (Feier-Blatt) und Auswertung (Orga) */
.evProgZeile { flex-wrap: wrap; }
.evProgUmfrage { flex: 1 0 100%; margin: 2px 0 8px; font-size: 0.86rem; }
.evProgUmfrage summary { cursor: pointer; color: var(--muted); list-style: none; }
.evProgUmfrage summary::before { content: "▸ "; }
.evProgUmfrage[open] summary::before { content: "▾ "; }
/* v3.142.0 (Befund D9): „Was die Gäste gefragt werden“ war 19 px hoch -
   ein Tipp 12 px daneben ging ins Leere. Jetzt eine 44-px-Zeile. Als
   Flex-Zeile verliert „▸ “ sein Leerzeichen (das Ende eines Flex-Kindes
   wird beschnitten) - der Abstand kommt darum aus gap. */
.evProgUmfrage summary { min-height: 44px; display: flex; align-items: center; gap: 5px; }
.evProgUmfrage summary::-webkit-details-marker { display: none; }
.evProgMitLabel { display: flex; gap: 8px; align-items: center; margin: 6px 0; }
.evProgFolge input { width: 100%; margin-top: 6px; }
.evProgFolge .evProgMax { width: 64px; margin: 0 4px; }
.evProgMaxLabel { display: flex; align-items: center; margin-top: 6px; }
.evUmfrage { border: 1px solid var(--border); border-radius: var(--r-m); padding: 10px 12px; margin: 8px 0; }
.evUmfrageTitel { font-weight: 600; margin-bottom: 4px; }
.evUmfrageZeile { font-size: 0.92rem; margin: 2px 0; }
.evUmfrageZeile.leise, .evUmfrage .leise { color: var(--muted); }
.evUmfrageZahl { display: inline-block; min-width: 1.6em; font-weight: 700; font-variant-numeric: tabular-nums; }
.evUmfrageFrage { margin-top: 8px; font-weight: 600; font-size: 0.92rem; }
.evUmfrageOption { font-size: 0.92rem; margin: 2px 0 2px 6px; }
/* v3.103.0 (Sören: "am ende kommt aber eine unübersichtliche angabe der
   ausgewählten Gegenstände raus"): Die Stückliste eines Programmpunkts -
   das, was man mit zum Laden nimmt. Eine Zeile je Stück, die Zahlen
   untereinander (tabular-nums, rechtsbündig), die Namen dahinter
   aufklappbar statt dauerhaft. Die Summe steht im Kopf, nicht noch einmal
   am Ende - vorher stand dieselbe Auswahl zweimal da. */
.evStueckListe { margin: 6px 0 2px; border: 1px solid var(--border); border-radius: var(--r-m); overflow: hidden; }
.evStueckKopf { padding: 8px 12px; background: var(--surface-2); font-size: 0.86rem; font-weight: 700; }
.evStueck { display: flex; align-items: baseline; gap: 10px; padding: 7px 12px; border-top: 1px solid var(--border); }
.evStueckZahl { flex: none; min-width: 2.2em; text-align: right; font-size: 1.05rem; font-weight: 800;
  font-variant-numeric: tabular-nums; }
.evStueckName { flex: 1; min-width: 0; font-size: 0.95rem; }
/* 0,78 statt 0,8: vorhandene Stufe. probe-kontrast erlaubt hoechstens 14. */
.evStueckWer { padding: 0 12px 7px calc(2.2em + 22px); font-size: 0.78rem; color: var(--muted); }
/* Ein Schalter je Programmpunkt - er zeigt die Namen an den Zeilen UND an
   den Stuecken. Zwei waeren zwei Bedienungen fuer dieselbe Frage. */
.evNamenKnopf { display: block; width: 100%; min-height: 44px; padding: 0; border: 0;
  background: none; color: var(--accent-strong); font: inherit; font-size: 0.86rem;
  text-align: left; cursor: pointer; }
/* Die Namen stehen unter ihrer Zeile, eingerueckt unter der Zahl - nicht
   dahinter, wo sie die Zahl der naechsten Zeile wegschieben. */
.evUmfrageNamen { margin: 2px 0 4px 1.6em; font-size: 0.82rem; color: var(--muted); line-height: 1.45; }
/* v2.51.0: Wochentage einer Wochen-Serie zum Antippen */
.wochentagWahl { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.wochentagWahl .wochentagChip { min-width: 42px; text-align: center; padding: 6px 8px; }
.wochentagWahl .wochentagChip.an { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

/* ---- v2.5.0: bekannte Laeden zum Antippen ------------------------ */
.ladenChips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 2px; }
.ladenChip { border: 1px solid var(--border); background: var(--bg); color: var(--text-2); border-radius: var(--r-voll);
  padding: 6px 12px; font-size: 0.82rem; min-height: 32px; cursor: pointer; }
.ladenChip.an { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
#editModalFields .ladenChips { margin-top: 8px; }

/* v2.5.0: Im Einkaufsmodus hakt die ganze Zeile ab. */
.item.shoppingMode { cursor: pointer; -webkit-tap-highlight-color: rgba(37,211,102,.18); }
.item.shoppingMode:active { background: var(--success-bg); }

/* ---- v2.5.0: Reiter Essen ---------------------------------------- */
.gerichteKopfLeiste { margin-bottom: 10px; }
.gerichteFilter { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.gFilter { border: 1px solid var(--border); background: var(--bg); color: var(--text-3); border-radius: var(--r-voll);
  padding: 6px 12px; font-size: 0.78rem; min-height: 32px; cursor: pointer; }
.gFilter.an { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.gerichteZeileKopf { padding: 4px 0 10px; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.reglerZeile { display: flex; align-items: center; gap: 10px; font-size: 0.78rem; color: var(--muted); margin: 4px 0; }
.reglerZeile input[type="range"] { flex: 1; accent-color: var(--success); }
.gerichteListe.schmal { max-height: none; }
.gZeile { display: flex; align-items: center; gap: 8px; padding: 9px 2px; border-bottom: 1px solid var(--border); cursor: pointer; }
.gZeile:active { background: var(--surface); }
.gName { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gWerte { flex: none; display: flex; align-items: center; gap: 6px; font-size: 0.78rem; color: var(--muted); }
.gWert { white-space: nowrap; }
.gAufwand { color: var(--warn-text); }
.gZeichen { font-size: 0.86rem; letter-spacing: -1px; }
.gDetailMarken { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.gDetailMarken .gMarke { width: auto; padding: 0 12px; height: 36px; font-size: 0.82rem; border: 1px solid var(--border); }
.bewerterZeile { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 4px 0; }
.sterne { display: flex; align-items: center; gap: 2px; }
.stern { border: 0; background: none; font-size: 1.3rem; line-height: 1; padding: 2px 1px; cursor: pointer; color: var(--border-2); }
.stern.an { color: var(--warn); }
.sternWeg { border: 0; background: none; color: var(--muted); font-size: 0.92rem; padding: 0 6px; cursor: pointer; }
.gZutaten { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.zZeile { display: flex; gap: 6px; align-items: center; }
.zZeile .zArtikel { flex: 2 1 0; min-width: 0; }
.zZeile .zMenge { flex: 1 1 0; min-width: 0; }
.zZeile .zWeg { flex: none; width: 34px; height: 34px; border: 0; background: none; color: var(--muted); font-size: 0.92rem; cursor: pointer; }
.kiLogDauer { color: var(--muted); }
.kiLogDauer.lang { color: var(--warn-text); font-weight: 600; }

/* v2.5.0: Der Essen-Reiter braucht denselben Rand wie die anderen Ansichten. */
#essenView .gerichteListe { margin: 0; padding: 0; }
#gDetail > div + div > label { display: block; margin-top: 16px; }

/* ---- v2.6.0: Planung am Termin ----------------------------------- */
.planKopf { font-size: 0.86rem; color: var(--muted); margin-bottom: 10px; }
.planAbschnitt { font-size: 0.78rem; font-weight: 600; color: var(--muted); text-transform: uppercase;
  letter-spacing: 0.03em; margin: 16px 0 4px; }
.planListe { display: flex; flex-direction: column; }
.planZeile { display: flex; align-items: center; gap: 6px; padding: 6px 0; border-bottom: 1px solid var(--border); }
.planZeile:last-child { border-bottom: 0; }
.planZeile.fertig .planText { opacity: 0.5; text-decoration: line-through; }
.planHaken { flex: none; width: 32px; height: 32px; border: 0; background: none; font-size: 1.15rem;
  color: var(--muted); cursor: pointer; padding: 0; }
.planZeile.fertig .planHaken { color: var(--success-text); }
.planText { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.planZusatz { font-size: 0.7rem; color: var(--muted); }
.planWeg { flex: none; width: 30px; height: 30px; border: 0; background: none; color: var(--icon-muted); font-size: 0.92rem; cursor: pointer; }
.planNeu { margin-top: 8px; }
.planLaden { width: 100%; margin-top: 6px; }
.planSchalter { margin-top: 16px; }
.planMarke { font-size: 0.7rem; color: var(--purple); white-space: nowrap; }
/* v2.10.6 (Review-Fix): planBadge ist jetzt ein <button> (Tastaturzugang) - border:none/font:inherit
   heben die Browser-Standardoptik des <button> auf, damit die Badge-Optik gleich bleibt. */
.planBadge { display: inline-block; margin-left: 6px; font: inherit; font-size: 0.7rem; background: var(--purple-bg); color: var(--purple);
  border: none; border-radius: var(--r-voll); padding: 2px 8px; white-space: nowrap; cursor: pointer; vertical-align: middle; }
.planBadge.fertig { background: var(--success-bg); color: var(--success-text); }
.marke.planMarke { background: var(--purple-bg); color: var(--purple); }

/* ---- v2.8.0: Vorschlagskarte, Vorrat, Dubletten ------------------ */
.vorschlagKarte { border: 1px solid var(--success-border); background: var(--success-bg); border-radius: var(--r-m); padding: 14px; margin-bottom: 12px; }
.vkKopf { font-size: 0.7rem; font-weight: 700; color: var(--success-text); text-transform: uppercase; letter-spacing: 0.05em; }
.vkName { font-size: 1.15rem; font-weight: 700; margin: 4px 0 2px; line-height: 1.3; overflow-wrap: anywhere; }
.vkGrund { font-size: 0.86rem; color: var(--text-3); line-height: 1.4; overflow-wrap: anywhere; }
.vkMarken { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.vkMarke { font-size: 0.7rem; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-voll); padding: 3px 9px; color: var(--text-3); white-space: nowrap; }
.vkMarke.veg { color: var(--success-text); border-color: var(--success-border); }
.vkKnoepfe { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.vkKnoepfe button { flex: 1 1 30%; min-height: 42px; border: 1px solid var(--border); background: var(--bg); border-radius: var(--r-s);
  font-size: 0.86rem; font-weight: 600; color: var(--text-2); cursor: pointer; padding: 8px 6px; }
.vkKnoepfe .vkJa { background: var(--success); border-color: var(--success); color: var(--auf-farbe); flex-basis: 100%; }
.vkLeer { font-size: 0.86rem; color: var(--muted); line-height: 1.4; }

.dublettenKasten { border: 1px solid var(--warn-border); background: var(--warn-bg); border-radius: var(--r-m); padding: 12px; margin-bottom: 12px; }
.dubKopf { font-size: 0.7rem; font-weight: 700; color: var(--warn-text); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 6px; }
.dubZeile { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 5px 0; }
.dubText { flex: 1 1 60%; font-size: 0.86rem; color: var(--text-3); overflow-wrap: anywhere; }
.dubKnopf { flex: 0 0 auto; border: 1px solid var(--warn-border); background: var(--bg); color: var(--warn-text); border-radius: var(--r-voll);
  padding: 6px 12px; font-size: 0.78rem; font-weight: 600; min-height: 34px; cursor: pointer; }

.vorratBox { margin-top: 18px; }
.vorratAuf { width: 100%; text-align: left; border: 1px solid var(--border); background: var(--bg); border-radius: var(--r-s);
  padding: 12px 14px; font-size: 0.92rem; font-weight: 600; color: var(--text-2); cursor: pointer; min-height: 46px; }
.vorratGitter { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; }
.vorratChip { border: 1px solid var(--border); background: var(--bg); color: var(--text-2); border-radius: var(--r-voll);
  padding: 7px 12px; font-size: 0.82rem; min-height: 34px; cursor: pointer; }
.vorratChip.an { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); font-weight: 600; }
.vorratMal { color: var(--muted); font-size: 0.7rem; }
.vorratLeeren { border: 0; background: none; color: var(--muted); font-size: 0.82rem; padding: 8px 0; cursor: pointer; }

/* ---- v2.9.0: Wochenstreifen im Essen-Reiter ---------------------- */
.wochenStreifen { margin-bottom: 12px; }
.wsKopf { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.wsKopf button { width: 38px; height: 34px; border: 1px solid var(--border); background: var(--bg); border-radius: var(--r-s); font-size: 1rem; cursor: pointer; }
.wsTitel { font-size: 0.82rem; font-weight: 600; color: var(--muted); }
.wsTage { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.wsTag { display: flex; flex-direction: column; align-items: stretch; gap: 2px; min-height: 64px;
  border: 1px solid var(--border); background: var(--bg); border-radius: var(--r-s); padding: 5px 3px; cursor: pointer; overflow: hidden; }
.wsTag.heute { border-color: var(--success); box-shadow: var(--ring-innen-1) var(--success); }
.wsTagName { font-size: 0.7rem; font-weight: 700; color: var(--muted); text-align: center; }
.wsTag.heute .wsTagName { color: var(--success-text); }
.wsGericht { font-size: 0.7rem; line-height: 1.25; color: var(--warn-text); background: var(--warn-bg); border-radius: var(--r-xs); padding: 1px 3px;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; word-break: break-word; }
/* v3.142.0 (Befund D16 der Prüfung zu Sörens „Suche weiter nach fehlern,
   sicherheitslücken und Design Optimierungen“): In den Tageszellen (rund
   41 px) brach ein Gericht mitten im Wort und ohne Strich - „Frikad|ellen…“,
   „Gemü|secu…“, „Pfannk|uchen“; word-break: break-word bricht, wo der Platz
   endet, auch auf dem iPhone. Jetzt trennt der Browser nach deutschen
   Silben mit Strich (lang="de" steht am Dokument; start.css macht es auf
   der Startseite seit Langem so). Nur was auch getrennt nicht passt, bricht
   noch hart. */
.wsGericht { word-break: normal; overflow-wrap: anywhere; -webkit-hyphens: auto; hyphens: auto; }
/* v3.47.0 (Paket 6, Befund D69): Sieben Spalten sind bei 320 px Fenster
   38,9 px je Tag - darin stand der Gerichtname zweizeilig in unter
   10 px Schrift. Unter 360 px steht die Woche deshalb in zwei Reihen zu
   vier Tagen; jeder Tag hat dann rund 74 px und lesbare Schrift. Die
   Reihenfolge der Tage bleibt gleich.
   v3.142.0: Dieser Block stand VOR der Grundregel von .wsGericht - gleich
   stark, also gewann die spätere (LEITFADEN Teil 5): Die vier Spalten kamen
   an, die größere Schrift und die dritte Zeile nie. Jetzt steht die
   Ausnahme unter der Regel, die sie überschreibt. */
@media (max-width: 359px) {
  .wsTage { grid-template-columns: repeat(4, 1fr); }
  .wsGericht { font-size: 0.78rem; -webkit-line-clamp: 3; }
}
.wsMehr { font-size: 0.7rem; color: var(--muted); text-align: center; }
.wsPlus { flex: 1; display: flex; align-items: center; justify-content: center; color: var(--muted-2); font-size: 1.15rem; }
.zutatZeile.imVorrat .zutatName { opacity: 0.75; }

/* v2.9.1: Menge per Pfeiltasten */
.mengeZeile { display: flex; gap: 6px; align-items: stretch; }
.mengeZeile input { flex: 1 1 auto; min-width: 0; }
.mengeKnopf { flex: none; width: 44px; border: 1px solid var(--border-2); background: var(--bg); border-radius: var(--r-s);
  font-size: 1.15rem; color: var(--text-2); cursor: pointer; min-height: 44px; }
.mengeKnopf:active { background: var(--surface-2); }
#editModalFields .mengeZeile input { margin-top: 0; }

/* ============================================================
   v2.9.2: FEINSCHLIFF (steht bewusst am Ende und ueberschreibt)
   Einheitliche Rundungen, ruhigere Karten, groessere Trefflaechen,
   klarere Hauptaktionen. Orientiert an iOS-Listen (Karten auf Haarlinie),
   iMessage (Blasen) und Things (Aufgaben).
   ============================================================ */

/* Typografie: ein Grundmass fuer alle Bereiche */
#app { font-size: 16px; }
h2, h3 { letter-spacing: -0.01em; }
.raumKopfzeile h2 { font-size: 1.7rem; font-weight: 800; letter-spacing: -0.02em; }
#raumKopf .raumTitel { font-size: 1.05rem; }

/* Reiter: kraeftiger Balken, kein Springen */
/* ============================================================
   v3.126.0 (Sören: "Geburtstagsanimation für geburtstagskinder … fallen
   ballons und Herzchen runter und die reiterleiste ist für den heutigen
   Tag geschmückt")

   Die Bahn steht HIER, nicht im Skript. GESTEN.md: Das Skript entscheidet
   nur, OB etwas fällt - wie es fällt, ist Sache des Browsers. Aus dem
   Skript kommen nur Startpunkt, Verzögerung, Größe und die Drift.
   position: fixed + pointer-events: none: Die Stücke liegen über der
   Seite, verschieben nichts und fangen keinen Tipp ab.
   ============================================================ */
.gebStueck {
  position: fixed; top: -8vh; left: 0; z-index: 50;
  pointer-events: none; user-select: none; line-height: 1;
  animation: gebFall 5.2s cubic-bezier(.35, .1, .6, 1) forwards;
}
@keyframes gebFall {
  0%   { transform: translate3d(0, 0, 0) rotate(-8deg); opacity: 0; }
  8%   { opacity: 1; }
  85%  { opacity: 1; }
  100% { transform: translate3d(var(--geb-drift, 0px), 118vh, 0) rotate(12deg); opacity: 0; }
}

/* Der Schmuck an der Reiterleiste (Sören: "Die girlande ist noch nicht
   schön. Kannst du die aus abwechselnden emojis machen?"): eine Kette aus
   Ballon, Herz und Tröte im oberen Innenabstand, den .bsReiter ohnehin hat.
   Deshalb kein neues Element und keine verschobene Zeile - gemessen ändert
   sich an der Höhe der Leiste nichts (Probe 8).

   WARUM ALS HINTERGRUND-BILD: An #tabs hängen beide Pseudo-Elemente schon
   (die Wisch-Ränder, app.css oben), und ein echtes Element in der Leiste
   würde mitscrollen und Platz nehmen. Emoji kann eine Farbe nicht - ein
   SVG mit <text> schon. GEMESSEN: Chromium zeichnet die Emoji darin in
   Farbe, genau wie im Fließtext.

   ZWEI ANLÄUFE DAVOR, beide verworfen, beide nach einem Bild: erst ein
   durchgehender Streifen in UI-Statusfarben (las sich wie ein Ladebalken),
   dann farbige Punkte (hübscher, aber immer noch kein Geburtstag). */
#tabs.gebSchmuck {
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='17'%3E%3Ctext x='4' y='14' font-size='12'%3E🎈%3C/text%3E%3Ctext x='36' y='14' font-size='12'%3E💗%3C/text%3E%3Ctext x='68' y='14' font-size='12'%3E🎉%3C/text%3E%3C/svg%3E");
  background-size: 96px 17px;
  background-repeat: repeat-x;
  /* 2 px Luft nach oben: An der Kante geklebt sahen die Ballons
     abgeschnitten aus, obwohl sie es nicht waren. */
  background-position: left 2px;
}

#tabs { border-bottom: 1px solid var(--border); }
:where(#tabs) button { color: var(--muted); font-size: var(--reiter-schrift); padding: 15px 10px 11px; }
:where(#tabs) button.active { color: var(--text); }
/* v3.44.0: In der Raeume-Fassung traegt der Balken die Akzentfarbe. */
#reiterStrich { background: var(--primary); }
:where(#tabs) .badge { background: var(--success); }

/* Karten und Zeilen */
.item { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
/* v3.100.0 - Sören: „Die Aufgabenfelder müssen noch runder." 18 -> 26 px
   (--r-l), dieselbe Rundung wie das Blatt selbst und die Knoepfe darin. */
.swipeReihe { border-radius: var(--r-l); }
.item .check { border-color: var(--muted-2); }
.item.done .check { background: var(--success); border-color: var(--success); }
.item .del { color: var(--icon-muted); }
.groupHeader { border-radius: var(--radius); }
.raumEintrag { padding: 12px 8px; border-radius: var(--radius); border-bottom: 0; }
.raumEintrag + .raumEintrag { margin-top: 2px; }
.raumEintrag:active { background: var(--surface); }
.raumSymbol { background: var(--surface); border: 1px solid var(--border); }
.raumVorschau { color: var(--muted); }
.raumName .zeit { color: var(--muted); }

/* Chat */
#messages { padding: 12px 12px 8px; gap: 5px; }
.bubble { border-radius: var(--r-l); padding: 9px 13px; font-size: 1rem; line-height: 1.35; box-shadow: var(--shadow-1); }
.bubble.own { border-bottom-right-radius: var(--r-xs); }
.bubble.other { border-bottom-left-radius: var(--r-xs); }
.bubble.ai { border-radius: var(--r-l); box-shadow: none; }
/* v3.142.0 (Befund D11 der Prüfung zu Sörens „Suche weiter nach fehlern,
   sicherheitslücken und Design Optimierungen“): Name und Uhrzeit unter der
   EIGENEN Nachricht standen im dunklen Thema mit 4,39:1 auf dem Grün
   (--muted auf --bubble-own). probe-kontrast.mjs rechnete dafür --text-3 -
   eine Rolle, die hier gar nicht stand -, und dunkel-kontrast-dom.mjs maß den
   Demo-Chat, in dem der Besucher nie selbst geschrieben hatte. Jetzt trägt
   die Metazeile die Rolle, die gerechnet wird: --text-3 (dunkel 5,00:1,
   hell 5,08:1 auf der eigenen, 5,28:1 auf der fremden Blase). Die Probe
   liest die Rolle aus dieser Regel, statt sie anzunehmen. */
.bubble .meta { color: var(--text-3); }
.systemNote { border-left-color: var(--border-2); }
#inputRow { border-top: 1px solid var(--border); background: var(--bg); }
#inputRow input, #inputRow textarea { background: var(--surface); border: 1px solid transparent; }
/* v3.32.0 (Prüfung D58): Hier stand `box-shadow: none` - die ID-Spezifität
   schlug die Fokusregel aus Zeile 140, und ausgerechnet das Chat-Schreibfeld
   hatte keinen sichtbaren Fokus. Ohne die Zeile greift wieder --ring. */
#inputRow input:focus, #inputRow textarea:focus { background: var(--bg); border-color: var(--accent); }
#inputRow button { width: 44px; height: 44px; }
#inputRow #sendBtn { background: var(--accent); color: var(--auf-farbe); }
#inputRow button.ideaBtn { background: var(--surface-2); color: var(--text); }
#aiSettings { background: var(--bg); border-bottom: 1px solid var(--border); color: var(--muted); }
#nachUnten { box-shadow: var(--shadow-2); }

/* Knoepfe: eine Rundung, klare Hauptaktion */
/* v3.100.0: .anlegenToggle steht hier nicht mehr - er traegt seit dieser
   Version die Form aus dem Blatt (--r-m, gefuellt, kein Rahmen). Diese
   Liste ist die eine Stelle, an der Eckenrundungen vergeben werden; wer
   eine Form aendert, aendert sie HIER und nicht per hoeherer Spezifitaet
   weiter oben. */
.modalActions button, .pushZeile button,
.blattAktion, .kickBtn, .loeschBtn, .andereGast button,
.vkKnoepfe button, .vorratAuf, .mengeKnopf, .wsKopf button { border-radius: var(--r-s); }
/* v3.99.0: „.addForm button" in :where() gelegt. Die Regel meint die Knöpfe
   des Formulars, traf aber JEDEN Knopf darin - auch einen Baustein. Als
   Regel mit Element-Schritt (0,1,1) schlug sie .bsWahlChip (0,1,0): Die
   Personen-Chips im Anlege-Formular bekamen 12 px statt der vollen Rundung,
   während dieselben Chips im Blatt rund waren. Vierte Fundstelle desselben
   Musters in drei Versionen (#bPunkte button, #editModalFields
   input[type=checkbox], jetzt diese) - deshalb prüft einheitlich-dom das
   jetzt für ALLE Bausteine auf einmal. */
:where(.addForm) button { border-radius: var(--r-s); }
.modalActions button.cancelBtn { background: var(--surface-2); color: var(--text); }
.modalActions button.saveBtn { background: var(--primary); color: var(--on-primary); }
#setup button { border-radius: var(--radius); box-shadow: var(--shadow-1); }
#setup input { border-color: var(--border-2); border-radius: var(--radius); }
.segment button, .ideenTabs button, .ansichtWahl button, .raumTypWahl button { border-radius: var(--r-voll); }
.gerichtChip, .essenChip, .vorratChip, .ladenChip, .gFilter { min-height: 38px; }

/* Fenster und Blaetter */
.modalBox { border-radius: var(--r-l); box-shadow: var(--shadow-2); background: var(--bg); }
.modalBox h3 { font-size: 1.15rem; }
@media (max-width: 480px) {
  .modalBox { box-shadow: var(--shadow-sheet); }
  .modalBox::before { background: var(--border-2); }
}
:where(#editModalFields) input, :where(#editModalFields) select, .blattSelect { border-radius: var(--r-s); border-color: var(--border-2); min-height: 44px; }
/* v3.83.0: Die zweite Erinnerung („und zusätzlich …“) hängt unter der
   ersten und ist als Fortsetzung zu lesen, nicht als eigenes Feld. */
.erinnerungZweite { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.erinnerungZweite[hidden] { display: none; }
.erinnerungZweiteWort { flex: none; font-size: 0.82rem; color: var(--muted); }
.erinnerungZweite .blattSelect { margin-top: 0; }
/* v3.13.3 (Prüfdurchgang): "#editModalFields input { width:100% }" traf auch
   Kästchen zum Ankreuzen - das Häkchen wurde brettbreit und sprang in eine
   eigene Zeile, der Text stand darunter. Es sah aus wie ein Fehler und war
   einer. Ein Kästchen ist so groß wie ein Kästchen. */
/* v3.99.0: in :where() gelegt. Der Grund von v3.13.3 gilt unveraendert - ein
   Kaestchen ist so gross wie ein Kaestchen -, aber als ID-Regel (1,1,1) schlug
   sie jeden Baustein. Der Geburtstags-Schalter (.bsSchalter, 51x31) wurde
   damit auf 22x22 gequetscht und sah aus wie eine Sichel. Dieselbe Bauart hat
   mich in v3.98.0 schon einmal erwischt (#bPunkte button). :where() nimmt der
   Regel das Gewicht, ohne ihre Wirkung zu nehmen. */
:where(#editModalFields input[type="checkbox"], #editModalFields input[type="radio"]) {
  width: 22px; height: 22px; min-height: 0; flex: none; margin-top: 0;
}
:where(#editModalFields) label { color: var(--text-3); }
.setZeile { border-radius: var(--r-s); border-color: var(--border); background: var(--surface); }
.setZeile:active { background: var(--surface-2); }

/* Trefflaechen: nichts unter 40 px, wichtige Ziele 44 px */
.kochBtn { width: 44px; min-height: 44px; }
.zZeile .zWeg { width: 44px; height: 44px; }
.planWeg { width: 40px; height: 40px; }
.planHaken { width: 44px; height: 44px; }
/* v3.51.0 (Befund D57): 32 px breit war zu schmal fuer fuenf Sterne mit 2 px Abstand. */
.stern { padding: 8px 3px; min-width: 44px; min-height: 44px; }
.sternWeg { min-width: 44px; min-height: 44px; }
.sternWeg { min-width: 40px; min-height: 44px; }
.wsKopf button { width: 44px; height: 40px; }
.dubKnopf { min-height: 40px; }

/* Banner: Rueckmeldungen ruhig, aber sichtbar */
#updateBanner { background: var(--warn-bg); border-bottom-color: var(--warn-border); color: var(--warn-text); }
#updateBanner button { border-color: var(--warn-border); background: var(--bg); color: var(--warn-text); }
#setupFehler { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger); border-radius: var(--r-s); }
#emptyList { color: var(--muted); line-height: 1.5; padding: 0 24px; }
#versionTag { color: var(--muted-2); }
/* v3.54.0 (Marktreife 2): Staging-Band - unuebersehbar, aber nicht im Weg.
   Warnfarbe aus der Palette; sitzt oben ueber allem, rollt nicht mit. */
/* v3.59.0: Umzugsband auf der alten Adresse - dieselbe Machart wie das
   Staging-Band, mit Link und Schliessen-Knopf (44 px). */
#umzugBand { position: sticky; top: 0; z-index: 60; display: flex; align-items: center; gap: 10px;
  padding: 6px 12px; font-size: 0.82rem; line-height: 1.35;
  background: var(--accent-bg); color: var(--text); border-bottom: 1px solid var(--accent-border); }
#umzugBand[hidden] { display: none; } /* display:flex oben schlaegt sonst das hidden-Attribut */
#umzugBand a { color: var(--accent-strong); font-weight: 700; }
#umzugBand button { flex: 0 0 auto; min-width: 44px; min-height: 44px; border: 1px solid var(--accent-border);
  border-radius: var(--r-s); background: var(--bg); color: var(--text-2); font-size: 1rem; }
#umgebungBand { position: sticky; top: 0; z-index: 60; padding: 6px 12px; text-align: center;
  font-size: 0.82rem; line-height: 1.35; background: var(--warn-bg); color: var(--warn-text);
  border-bottom: 1px solid var(--warn-border); }

/* Schaltflaechen reagieren auch auf dem Desktop */
@media (hover: hover) {
  button:not(:disabled):hover { filter: brightness(0.96); }
  .raumEintrag:hover, .setZeile:hover { background: var(--surface); }
}
/* Weniger Bewegung, wenn gewuenscht */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}
.modalBox:focus, .modalBox:focus-visible { outline: none; box-shadow: var(--shadow-2); }

/* v2.9.3: Personen im Haushalt (Blatt unter ⚙️) */
.leuteListe { display: flex; flex-direction: column; }
.leuteZeile { display: flex; align-items: center; gap: 8px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.leuteZeile:last-child { border-bottom: 0; }
/* v3.51.0 (Befund S50): Bei 320 px blieben dem Namen rund 80 px - "Désirée
   🔑 das bist du" wurde abgeschnitten. Zwei Zeilen statt Auslassungspunkte. */
.leuteName { flex: 1; min-width: 0; font-size: 0.92rem; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.25; overflow-wrap: anywhere; }
.leuteWeg { flex: none; width: 44px; height: 44px; border: 0; background: none; color: var(--icon-muted); font-size: 1.05rem; cursor: pointer; }

/* v2.9.3: Hell / Dunkel / Automatisch */
.themaWahl { display: flex; gap: 8px; }
.themaWahl button { flex: 1; min-height: 44px; border: 1px solid var(--border-2); background: var(--bg);
  border-radius: var(--r-s); font-size: 0.82rem; font-weight: 600; color: var(--text-2); white-space: nowrap; }
.themaWahl button.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

/* v2.9.4: Essen – Schnellfilter, Begründung, Zutaten-Listen, Bündelung */
.vorschlagFilter { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.vfChip { border: 1px solid var(--border-2); background: var(--bg); color: var(--text-2);
  border-radius: var(--r-voll); padding: 8px 13px; min-height: 40px; font-size: 0.82rem; font-weight: 600; cursor: pointer; }
.vfChip.an { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); }
.vkGruende { margin: 6px 0 0; padding: 0 0 0 2px; list-style: none; }
.vkGruende li { font-size: 0.86rem; color: var(--text-3); line-height: 1.45; padding-left: 15px; position: relative; }
.vkGruende li::before { content: "·"; position: absolute; left: 4px; color: var(--success-text); font-weight: 700; }
.zlGruppe { margin-top: 10px; }
.zlGruppe .vorratAuf.offen { border-color: var(--border-2); font-weight: 700; }
.zlVorschlaege { margin-top: 10px; border-top: 1px solid var(--border); padding-top: 8px; }
.zutatBuendel { font-size: 0.82rem; color: var(--success-text); background: var(--success-bg);
  border: 1px solid var(--success-border); border-radius: var(--r-s); padding: 8px 11px; margin-bottom: 10px; line-height: 1.4; }
.zutatZeile.geteilt .zutatName { font-weight: 600; }
.zutatGeteilt { font-size: 0.7rem; font-weight: 700; color: var(--success-text);
  background: var(--success-bg); border-radius: var(--r-voll); padding: 2px 7px; white-space: nowrap; }
.vfZeile { display: flex; flex-wrap: wrap; gap: 6px; }
.vorschlagFilter .reglerZeile { margin-top: 8px; }

/* v2.9.5: Terminzeile kompakt - Titel plus EINE Meta-Zeile (Zeit · Ort · wer) */
.item.terminZeile { padding-top: 9px; padding-bottom: 9px; }
.item.terminZeile .name { font-size: 0.92rem; line-height: 1.3; }
.item.terminZeile .meta { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 10px; margin-top: 3px;
  font-size: 0.78rem; color: var(--muted); line-height: 1.4; }
.item.terminZeile .meta .wann, .item.terminZeile .meta .ortZeile { margin-top: 0; font-size: 0.78rem; }
.item.terminZeile .meta .wann b { font-weight: 700; color: var(--text-2); }
.teilChips.inline { display: inline-flex; gap: 4px; margin: 0; }
.teilChips.inline .teilChip { font-size: 0.7rem; padding: 1px 7px; line-height: 1.5; }
.item.terminZeile .calBtn, .item.terminZeile .del { width: 40px; height: 40px; }

/* v2.9.5: Blaetter auch auf dem Desktop scrollbar - vorher wuchs ein hohes
   Blatt (Gericht mit 9 Zutaten, Woche planen) ueber den Bildschirm hinaus,
   ohne dass man scrollen konnte. Auf dem Handy gab es das schon. */
#editModal .modalBox, #lernModal .modalBox, #archivModal .modalBox, #raumModal .modalBox,
#setModal .modalBox, #neuModal .modalBox, #pushModal .modalBox { display: flex; flex-direction: column;
  max-height: min(88vh, calc(100% - 32px)); max-height: min(88dvh, calc(100% - 32px)); }
#editModalFields, #lernBody, #archivBody, #raumModalBody, #setBody, #neuBody, #pushBody {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.modalBox h3, .modalActions { flex: none; }
#editModalFields { margin-bottom: 14px; padding: 2px; }

/* v2.9.5: Die Ein-/Ausblend-Schalter im Termine-Reiter waren als volle
   Amber-Flaechen die lautesten Elemente der Seite - dabei sind sie nur
   Filter. Jetzt ruhige Chips: an = zarte Tönung, aus = Umriss. */

/* v2.9.6: Terminliste - drei Sorten, drei Gewichte.
   Tagesband breit und dunkel, Termine gross, Essen klein und amber,
   Aufgaben klein und blau. Der Unterschied soll auf einen Blick da sein. */
#terminListe .tagTrenner.banner { display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  margin: 16px 0 8px; padding: 7px 12px; border-radius: var(--r-s); background: var(--primary); color: var(--on-primary); }
#terminListe .tagTrenner.banner:first-child { margin-top: 4px; }
#terminListe .tagTrenner.banner span { background: none; color: inherit; padding: 0; font-size: 0.86rem; font-weight: 800; letter-spacing: .02em; text-transform: uppercase; }
#terminListe .tagTrenner.banner .bannerDatum { font-weight: 500; text-transform: none; opacity: .75; font-size: 0.82rem; }
#terminListe .tagTrenner.banner.heute { background: var(--accent); color: var(--auf-farbe); }
/* v3.100.1: Derselbe eingerueckte Streifen wie bei den Aufgaben - ein
   border-left ist buendig und eckig und wird von der 26-px-Rundung der
   Karte abgeschnitten. Die Farbe kommt aus --strich (app-termine.js setzt
   sie je nach erstem Teilnehmer). */
/* v3.100.3 (Sören: "S1 überschreibt den erledigt kreis von terminen"): Der
   Strich liegt seit v3.100.1 absolut, nicht mehr als border-left. Ein
   border-left gehoert zur Box - die Polsterung beginnt danach, der Kreis
   konnte nie darunter geraten. Ein absoluter Strich weiss davon nichts:
   im Stil "spalte" (Standard!) stand padding-left auf 6 px, der Strich auf
   8-11 - also quer ueber dem Erledigt-Kreis.
   Darum ist die Bahn jetzt ein Token, und die LINKE POLSTERUNG WIRD DARAUS
   ABGELEITET (LEITFADEN Teil 1). Wer die Bahn verschiebt, verschiebt die
   Polsterung mit; zwei Zahlen, die zueinander passen muessen, gibt es
   nicht mehr. Wer enger will, setzt --strichBahn - nicht padding-left. */
/* v3.102.0 (Variante B): Der farbige Strich links faellt an der TERMINZEILE
   weg - die Personenspur sagt dasselbe, deutlicher und mit Namen. Beides
   nebeneinander waere wieder die Doppelpflege, die B beseitigen soll
   (LEITFADEN Teil 1). Bei den Aufgaben bleibt der Strich: dort gibt es
   keine Spur, und er trägt dort die Einstufung, nicht die Person.
   Die Regel haengt jetzt an der ZEILE statt an #terminListe - damit traegt
   die Tagesansicht die Polsterung genauso, ohne Nachpflege. */
.item.terminZeile {
  position: relative; --strichBahn: 0px;
  padding: 14px 12px 14px 12px; border-left: 0; }
.item.terminZeile::after { content: none; }
#terminListe .item.terminZeile .name { font-size: 1.05rem; font-weight: 700; }
#terminListe .item.terminZeile .meta { font-size: 0.82rem; margin-top: 4px; }
/* v3.102.0 (Variante B): DIE PERSONENSPUR. Eine Scheibe statt dreier
   Fundstellen derselben Person (Strich, Punktreihe, Namens-Chip).
   34 px: gross genug fuer eine Initiale, klein genug, dass die Zeile
   einzeilig bleibt. Farbe und Schriftfarbe setzt terminSpurHtml() -
   personSchriftAuf() entscheidet, weil Weiss auf Gelb nur 1,95:1 traegt. */
.terminSpur { flex: none; position: relative; width: 34px; height: 34px; margin-top: 1px;
  border-radius: var(--r-kreis); display: grid; place-items: center;
  font-size: 0.86rem; font-weight: 800; line-height: 1; }
/* Ohne Zuordnung: die Haus-Marke. Ein Termin ohne Person gilt fuer den
   ganzen Haushalt - das ist eine Aussage, kein fehlender Eintrag. */
.terminSpur.ohne { background: var(--surface-2); color: var(--muted-2); }
/* v3.102.0: Die Marke "+1" stand zuerst auf 0,6 rem - probe-kontrast hat
   das zu Recht rot gemeldet (unter 11 px, und eine 15. Schriftstufe). Jetzt
   0,7 rem, die kleinste vorhandene Stufe. */
.terminSpur i { position: absolute; right: -4px; bottom: -4px; font-style: normal;
  font-size: 0.7rem; font-weight: 700; line-height: 1; padding: 1px 4px;
  border-radius: var(--r-voll); background: var(--surface); color: var(--text-2);
  border: 1px solid var(--bg); }
/* Kreis und ✕ stehen rechts nebeneinander - sie gehoeren zusammen
   (abhaken und loeschen), und links ist jetzt die Spur. */
.zeilenKnoepfe { flex: none; display: flex; align-items: flex-start; gap: 2px; }
/* Gezeichnete Zeichen in der Zeile tragen die Farbe der Zeile, nicht ihre
   eigene - das war der Unterschied zum Emoji im dunklen Thema. */
.zIco { display: inline-flex; vertical-align: -2px; color: var(--muted-2); }
#terminListe .item.terminZeile .check { width: 28px; height: 28px; }
#terminListe .item.essen.einzeilig { padding: 4px 8px 4px 9px; margin-bottom: 6px; min-height: 36px; border-left-width: 3px; }
#terminListe .item.essen .essenText .name { font-size: 0.86rem; font-weight: 500; }
#terminListe .item.essen .essenSymbol { width: 20px; height: 20px; font-size: 0.86rem; }
#terminListe .item.essen .essenMahl { font-size: 0.7rem; }
#terminListe .item.essen .calBtn, #terminListe .item.essen .del { width: 34px; height: 34px; font-size: 0.92rem; }
#terminListe .kalAufgabe { background: var(--accent-bg); border: 1px solid var(--accent-border); border-left: 3px solid var(--accent);
  border-radius: var(--r-s); padding: 5px 8px 5px 9px; margin-bottom: 6px; min-height: 36px; font-size: 0.86rem; }
#terminListe .kalAufgabe .kalAufgabeText > span:first-child { color: var(--accent-strong); font-weight: 500; }
#terminListe .kalAufgabe .kalAufgabeZusatz { color: var(--muted); }

/* v2.9.6: Laden-Wahl im Anlegen-Formular und im Bearbeiten-Blatt.
   v3.99.0 (Sören: „Lass uns schritt für schritt die menüs anpassen"): Der
   blau abgesetzte Kasten mit Überschrift in Großbuchstaben und eigenen
   Chips ist weg. Er war eine eigene Sprache mitten in einem Blatt, das
   sonst mit einer auskommt - und genau das, was „oll und veraltet"
   aussah. Der Behälter bleibt nur als Anker: zeichneLadenVorschlaege
   findet ihn über data-fuerfeld und tauscht ihn aus.
   Die Chips tragen jetzt .bsWahlChip; .ladenChip ist nur noch der Haken
   für den Klick-Zuhörer. Die drei Regeln darunter mussten weg, weil sie
   mit zwei Schritten (0,2,0) den Baustein (0,1,0) geschlagen hätten -
   dieselbe Bauart, die einheitlich-dom 5 schon elfmal gefunden hat. */
.ladenWahl { background: none; border: 0; padding: 0; }
.ladenWahl .bsWahlReihe { margin: 0; }
.ladenWahl .ladenChip.neu { border-style: dashed; }
.ladenNeuZeile { display: flex; gap: 6px; margin-top: 8px; }
.ladenNeuZeile .ladenNeuFeld { flex: 1; min-width: 0; }
.ladenNeuZeile .ladenNeuOk { flex: none; min-width: 56px; border-radius: var(--r-s); border: 0; background: var(--accent); color: var(--auf-farbe); font-weight: 700; }
.addForm label.feld { display: flex; flex-direction: column; gap: 4px; font-size: 0.78rem; font-weight: 700; color: var(--text-3); }
.addForm label.feld input, .addForm label.feld .mengeZeile { font-weight: 400; color: var(--text); }
.addForm label.feld.voll { grid-column: 1 / -1; }
.ladenNeuZeile[hidden] { display: none; }

/* v2.9.7: Tagesband, Essen und Aufgaben noch schmaler - Termine bleiben. */
#terminListe .tagTrenner.banner { margin: 12px 0 6px; padding: 3px 10px; border-radius: var(--r-s); }
#terminListe .tagTrenner.banner span { font-size: 0.7rem; }
#terminListe .tagTrenner.banner .bannerDatum { font-size: 0.7rem; }
#terminListe .item.essen.einzeilig { padding: 1px 6px 1px 8px; min-height: 28px; margin-bottom: 4px; gap: 6px; border-radius: var(--r-s); }
#terminListe .item.essen .essenText .name { font-size: 0.82rem; }
#terminListe .item.essen .essenSymbol { width: 16px; height: 16px; font-size: 0.78rem; }
#terminListe .item.essen .essenMahl { font-size: 0.7rem; }
#terminListe .item.essen .calBtn, #terminListe .item.essen .del { width: 28px; height: 28px; font-size: 0.86rem; }
#terminListe .kalAufgabe { padding: 1px 6px 1px 8px; min-height: 28px; margin-bottom: 4px; gap: 6px; font-size: 0.82rem; border-radius: var(--r-s); }
/* v3.99.0: Der Haken war hier 26 px - die Aufgaben IN der Terminliste sind
   absichtlich verdichtet, damit sie die Termine nicht erschlagen.
   ZUERST habe ich versucht, nur die TREFFERFLÄCHE mit einem ::after auf 44 px
   zu erweitern und das Zeichen klein zu lassen. Die Probe hat das widerlegt,
   und zwar richtig: 21 px rechts der Mitte liegt der Aufgabentext, nicht mehr
   der Haken. Seitwärts ist kein Platz - das lässt sich nicht tricksen.
   Die Zeile ist ohnehin 48 px hoch, seit der Aufgabentext 44 px misst. Also
   bekommt der Haken die 44 px auch. Das Zeichen bleibt bei 1 rem.
   SICHTBARE FOLGE, und sie war nicht bestellt: Diese Zeilen sind jetzt 48
   statt 28 px hoch. Die Verdichtung war Absicht; die Mindestgröße steht aber
   ohne Ausnahme in CLAUDE.md, und eine 28-px-Zeile mit zwei Knöpfen darin
   trifft man auf dem Handy nicht. */
#terminListe .kalAufgabe .kalHaken { width: 44px; height: 44px; font-size: 1rem; }
/* v3.138.0 (Sören, 26.09.2026: „Demo app Chat funktioniert nicht gut. Packe
   alles gelernte aus allen apps in die demo und prüfe ob die demo mit den
   gleichen Funktionen läuft.“): Dieselbe Regel für das ESSEN in der
   Terminliste. Gefunden, weil der Demo-Haushalt jetzt einen Essensplan hat:
   einheitlich-dom 3 maß die Essenszeilen hier zum ersten Mal - Text 18 px,
   🛒 und ✕ je 28 px (Trefferfläche 40 px). So war es seit v2.9.7; keine
   Probe sah es, weil der Demo-Haushalt nie ein Essen hatte. Wie bei den
   Aufgaben oben: Die beiden Knöpfe bekommen 44 px (seitwärts ist zwischen
   ihnen kein Platz für eine unsichtbare Fläche), der Text eine Trefferfläche
   von 44 px Höhe, ohne die Zeile zu verschieben - mit demselben Mittel wie
   die Links in Textzeilen weiter unten (Innenabstand oben und unten, gleich
   viel negativer Außenabstand). Ein ::after wie bei .kalAufgabeText ginge
   hier nicht: .essenText schneidet mit overflow: hidden ab (Auslassungs-
   punkte), auch die eigene unsichtbare Fläche. Die Zeichen bleiben so groß,
   wie sie waren.
   SICHTBARE FOLGE: Essenszeilen in der Terminliste sind 46 statt 28 px hoch. */
#terminListe .item.essen .calBtn, #terminListe .item.essen .del { width: 44px; height: 44px; }
#terminListe .item.essen .essenText { padding-block: 13px; margin-block: -13px; }
#terminListe .kalAufgabe .kalAufgabeText { padding: 0; gap: 0; flex-direction: row; align-items: baseline; flex-wrap: wrap; column-gap: 6px; }
#terminListe .kalAufgabe .kalAufgabeZusatz { font-size: 0.7rem; }
#terminListe .kalAufgabe .teilChip { font-size: 0.7rem; padding: 0 6px; }

/* v2.9.8: Wischen legt den Knopf nur frei - der Tipp darauf loescht. */
/* v3.39.0: Der Knopf ist jetzt genau 96 px breit und die Schrift steht
   mittig darin - ein zusaetzlicher Rand nach aussen wuerde sie aus der
   Mitte schieben. Die beiden alten padding-Zeilen stammen aus der Zeit,
   als der Grund ueber die ganze Zeile lief. */
/* v3.38.0: Beide Knöpfe sind gleich groß und gleich zu treffen - der grüne
   rechts genauso wie der rote links. */

/* v2.9.8: Rueckfrage-Fenster */
/* v2.11.2: Die Rueckfrage muss ueber JEDEM Blatt liegen. Sie lag auf 60,
   waehrend #raumModal/#setModal/#neuModal auf 1200 liegen - eine Rueckfrage
   aus einem dieser Blaetter heraus oeffnete sich also DAHINTER: unsichtbar
   und nicht anklickbar. In der Praxis: "Raum endgueltig loeschen" tat
   nichts, "Chat leeren" tat nichts, "Gast loeschen" tat nichts. Der Fehler
   kam mit v2.10.6 herein, als confirm() durch dieses Blatt ersetzt wurde -
   der Browser-Dialog lag immer oben, das eigene Blatt nicht.
   Ebenen ab hier: Blaetter 1200, Rueckfrage 1400, Meldung 1500. */
#frageModal { position: fixed; inset: 0; background: var(--overlay); display: none;
  align-items: center; justify-content: center; z-index: 1400; padding: 20px; }
#frageModal .frageBox { max-width: var(--blatt-schmal); border-radius: var(--r-l); }
#frageModal .frageBox::before { display: none; }
#frageModal h3 { font-size: 1.05rem; margin-bottom: 6px; }
#frageModal p { margin: 0 0 18px; font-size: 0.92rem; color: var(--text-2); line-height: 1.4; }
#frageModal .modalActions button { flex: 1; }
#frageModal .modalActions button.gefaehrlich { background: var(--danger); color: var(--auf-farbe); }

/* v2.9.8: Einkaufsgruppen standardmaessig zu; Vorschau und Schalter.
   v3.131.0: Der Schalter „Alle zuklappen“ ist ein Symbol im Kopf
   (.listenKopf .kopfKnopf) - seine eigene Pille ist weg. */
/* v3.132.0: ein gezeichneter Winkel statt ▸/▾ - zugeklappt zeigt er nach
   rechts. */
.gruppenPfeil { color: var(--text-3); display: inline-flex; align-items: center; justify-content: center; width: 24px; }
.gruppenPfeil .zeichen { transition: transform 0.15s ease; }
.listGroup.zu .gruppenPfeil .zeichen { transform: rotate(-90deg); }
@media (prefers-reduced-motion: reduce) { .gruppenPfeil .zeichen { transition: none; } }
/* Die Vorschau eines zugeklappten Ladens steht wie bei der Checkliste
   (.ckVorschau) als eigene leise Zeile unter Name und Zahl - sie steht im
   Kopf (ein Tipp klappt auf) und bricht per order/flex-basis um. */
.groupHeader .gruppenName { flex: 0 1 auto; min-width: 0; }
.gruppenVorschau { order: 9; flex: 1 0 100%; min-width: 0; font-size: 0.78rem; font-weight: 400; color: var(--text-3); line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 6px; }
.groupHeader:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* v2.9.8: Zutaten unter dem Gerichtnamen in der Liste. */
.gZeile .gText { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.gZeile .gText .gName { flex: none; }
.gZeile .gZutatenKurz { display: block; font-size: 0.7rem; color: var(--text-3); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* v2.9.8: Antworten auf Nachrichten */
#antwortLeiste { display: flex; align-items: center; gap: 8px; padding: 8px 12px 0; background: var(--bg); flex: none; }
#antwortLeiste[hidden] { display: none; }
.antwortZitat, .zitat { display: flex; flex-direction: column; min-width: 0; border-left: 3px solid var(--accent);
  background: var(--accent-bg); border-radius: var(--r-s); padding: 5px 9px; cursor: pointer; }
.antwortZitat { flex: 1; }
.antwortZitat b, .zitat b { font-size: 0.7rem; color: var(--accent-strong); font-weight: 700; }
.antwortZitat span, .zitat span { font-size: 0.82rem; color: var(--text-2); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
#antwortLeiste .antwortWeg { flex: none; width: 36px; height: 36px; border-radius: var(--r-kreis); border: none;
  background: var(--surface-2); color: var(--text-2); font-size: 0.92rem; }
/* v2.33.0: Dieses Geraet - Hilfe-Blatt */
.geraetHilfe h4 { margin: 14px 0 6px; font-size: 0.92rem; }
.geraetHilfe ol { padding-left: 20px; margin: 4px 0; }
.geraetHilfe li { margin: 3px 0; }
.geraetHilfe p { margin: 4px 0; }
.geraetHilfe .geraetKurz, .geraetHilfe .geraetWarum { color: var(--muted); font-size: 0.86rem; }
.geraetHilfe .knopfKlein { border: 1px solid var(--border-2); background: var(--surface); border-radius: var(--r-s); padding: 6px 12px; font-size: 0.92rem; cursor: pointer; }
.pushGeraetTipp { margin-top: 8px; font-size: 0.86rem; }
.pushGeraetTipp ol { padding-left: 20px; margin: 4px 0; }

/* v2.33.0: Besorgungen ohne Laden - oben, rot, mit Vorschlags-Chips */
/* v3.13.0: Die Gruppe ohne Laden war komplett rot - Rahmen, Name, Zähler,
   jeder Eintrag, dazu ⚠️. Rot heißt "da ist etwas kaputt"; hier ist nur
   noch kein Laden gewählt. Sie bleibt sichtbar (sie erscheint bei jedem
   Laden mit), aber in der ruhigen Hinweisfarbe. */
/* v3.132.0: wie eine überfällige Aufgabe (.item.overdue: getönte Fläche)
   - die ganze Karte in der ruhigen Hinweisfarbe, der Titel und das
   Laden-Zeichen jeder Zeile ebenso: Hier fehlt eine Entscheidung. (Die
   erste Fassung trug an jeder Zeile einen Streifen - ein Zeichen je Zeile
   für eine Aussage über die ganze Gruppe.) */
.listGroup.ohneOrt { background: var(--warn-bg); border-color: var(--warn-border); }
.listGroup.ohneOrt .groupHeader { color: var(--warn-text); }
.listGroup.ohneOrt .groupCount { background: var(--warn); color: var(--warn-auf); }
.listGroup.ohneOrt .groupBody, .listGroup.ohneOrt .groupBody .swipeReihe + .swipeReihe { border-top-color: var(--warn-border); }
.listGroup.ohneOrt .groupBody .swipeReihe .item { background: var(--warn-bg); }
.listGroup.ohneOrt .woandersBtn { color: var(--warn-text); }
/* v3.132.0: Die Vorschlags-Chips unter jeder Zeile (.ortChips, .ortChip,
   „Wo kaufst du das?“) sind weg - die Vorschläge stehen vorn in der
   Laden-Auswahl (.woandersChip.tipp, woandersBlatt). */
/* v3.32.0: Die eigene Media Query hier widersprach der Themenwahl über data-thema
     (Gerät hell + Thema dunkel ergab 2,72:1). Jetzt trägt --purple beide Fälle. */

/* v2.33.0: Sprachnachrichten */
.bubble.audio { min-width: min(78vw, 300px); }
.bubble.audio .audioZeile { display: flex; align-items: center; gap: 6px; }
.bubble.audio .audioZeile audio { flex: 1; min-width: 0; height: 36px; max-width: 260px; }
.bubble.audio .audioSymbol { font-size: 1.15rem; }
.bubble.audio .audioDauer { font-size: 0.82rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.bubble.audio .audioStand { font-size: 0.82rem; color: var(--muted); margin-top: 4px; display: flex; align-items: center; gap: 6px; }
.bubble.audio .audioStand .audioPuls { animation: kiPuls 1.4s infinite; font-size: 0.7rem; }
@media (prefers-reduced-motion: reduce) { .bubble.audio .audioStand .audioPuls { animation: none; } }
.bubble.audio .audioFehler { color: var(--warn-text); }
.bubble.audio .audioWeg { font-size: 0.92rem; color: var(--muted); }
.bubble.audio details.audioText { margin-top: 4px; }
.bubble.audio details.audioText summary { cursor: pointer; font-size: 0.82rem; color: var(--muted); list-style: none; }
.bubble.audio details.audioText summary::before { content: "▸ "; }
.bubble.audio details.audioText[open] summary::before { content: "▾ "; }
.bubble.audio .audioTextInhalt { margin-top: 4px; white-space: pre-wrap; }
.bubble.own.audio audio { filter: none; }
.bubble .zitat { margin: -2px 0 6px; }
.bubble.own .zitat { background: rgba(255,255,255,.35); }
:root[data-thema="dunkel"] .bubble.own .zitat { background: rgba(0,0,0,.18); }
.bubble .antwortenBtn { border: none; background: none; color: var(--muted); font-size: 0.86rem; padding: 0 4px;
  min-height: 0; cursor: pointer; vertical-align: baseline; }
.bubble .antwortenBtn:active, .bubble .antwortenBtn:hover { color: var(--text-2); }
/* v3.83.0: Die Sprechblase hatte bis v3.82.0 eine eigene Wischgeste
   ("nach rechts = antworten") und dafuer touch-action: pan-y - das hat
   dem Seitenwechsel im Chat den Weg nach links abgeschnitten. Beides ist
   weg; geantwortet wird ueber den ↩-Knopf in der Blase. */
.bubble.hervor { animation: blaseHervor 1.6s ease-out; }
@keyframes blaseHervor { 0%, 40% { box-shadow: var(--ring-3) var(--accent); } 100% { box-shadow: var(--shadow-keiner); } }
/* Antwortleiste offen: der ↓-Knopf rueckt darueber. */
#chatView:has(#antwortLeiste:not([hidden])) #nachUnten { bottom: calc(128px + var(--sab)); }
body.tastatur #chatView:has(#antwortLeiste:not([hidden])) #nachUnten { bottom: 128px; }

/* v2.21.0: Erstbesuch-Streifen "Neu hier? Was kann ich sagen?" ueber dem
   Eingabefeld (public/sagen.js). Dieselbe Stelle wie die Antwortleiste, aber
   in der Hinweisfarbe - er soll auffallen, ohne den Chat zu verdecken. Alle
   Farben aus den Variablen, damit Hell und Dunkel von selbst stimmen. */
#sagenHinweis { display: flex; align-items: center; gap: 8px; padding: 6px 10px 6px 14px; flex: none;
  background: var(--accent-bg); border-top: 1px solid var(--accent-border); font-size: 0.82rem; color: var(--text-2); }
#sagenHinweis[hidden] { display: none; }
#sagenHinweis .sagenHinweisText { flex: none; }
#sagenHinweis .sagenHinweisKnopf { flex: 1; min-width: 0; min-height: 40px; text-align: left; padding: 6px 8px;
  border: none; background: none; color: var(--accent-strong); font-weight: 700; font-size: 0.86rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#sagenHinweis .sagenHinweisWeg { flex: none; width: 40px; height: 40px; border-radius: var(--r-kreis); border: none;
  background: var(--surface-2); color: var(--text-2); font-size: 0.92rem; }
#chatView:has(#sagenHinweis:not([hidden])) #nachUnten { bottom: calc(128px + var(--sab)); }
body.tastatur #chatView:has(#sagenHinweis:not([hidden])) #nachUnten { bottom: 128px; }

/* v2.10.0: Checklisten im Reiter Aufgaben */
.checklistenBlock { margin-bottom: 14px; }
.checklistenKopf { display: flex; align-items: center; gap: 8px; }
.checklisteNeuBtn { margin-left: auto; border: 1px solid var(--border-2); background: var(--surface); color: var(--text-2);
  border-radius: var(--r-voll); padding: 4px 12px; min-height: 30px; font-size: 0.78rem; font-weight: 600; }
.checklisteLeer { font-size: 0.82rem; color: var(--text-3); padding: 4px 2px 6px; line-height: 1.4; }
.checklisteKarte { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-m); padding: 10px 12px;
  margin-bottom: 8px; cursor: pointer; }
.checklisteKarte:active { background: var(--surface-2); }
.checklisteKarte.komplett { border-color: var(--success-border, var(--success)); }
.ckKopf { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.ckTitel { font-weight: 700; font-size: 0.92rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ckStand { flex: none; font-size: 0.78rem; font-weight: 700; color: var(--text-2); background: var(--surface-2); border-radius: var(--r-voll); padding: 2px 8px; }
.checklisteKarte.komplett .ckStand { background: var(--success); color: var(--auf-farbe); }
.ckBalken { height: 5px; border-radius: var(--r-xs); background: var(--border); margin: 8px 0 6px; overflow: hidden; }
.ckBalken i { display: block; height: 100%; background: var(--success); border-radius: var(--r-xs); transition: width .2s ease-out; }
.ckBalken.gross { height: 8px; margin: 0 0 6px; }
.ckVorschau { font-size: 0.78rem; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ckVorschau.fertig { color: var(--success-text, var(--success)); font-weight: 600; }
.ckMarken { font-size: 0.7rem; color: var(--muted); margin-top: 4px; }
/* v3.142.1 (Sören, 29.09.2026: „… Notizen?“): DIE NOTIZ IN DER LISTE - am
   Termin seit v2.19.0 (bis hierher stand ihr Aussehen in einladung.js, weil
   sie mit dem Einlesen von Einladungen kam), jetzt auch an Aufgabe und
   Checkliste. EINE Regel für alle: eine Zeile mit Ellipse, leise Farbe; der
   ganze Text steht im Blatt. Nur Größe und Abstand richten sich nach der
   Zeile, in der sie steht (die Terminzeile ist ein umbrechendes flex, dort
   nimmt sie die volle Breite). */
.notizZeile { min-width: 0; margin-top: 2px; color: var(--text-3); line-height: 1.45;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.item.terminZeile .meta .notizZeile { flex: 1 1 100%; }
.item.aufgabe .notizZeile, .checklisteKarte .notizZeile { font-size: 0.78rem; margin-top: 3px; }
/* Im Blatt der Checkliste steht die Notiz ganz - Zeilenumbrüche bleiben. */
.ckNotiz { font-size: 0.82rem; color: var(--text-2); line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere;
  margin: 2px 0 8px; }
.ckNotizWort { font-weight: 700; color: var(--text-2); }
/* Blatt */
.ckFortschritt { margin-bottom: 8px; }
.ckFortschritt span { font-size: 0.82rem; color: var(--text-2); font-weight: 600; }
.ckListe { display: flex; flex-direction: column; border-top: 1px solid var(--border); }
.ckZeile { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.ckHaken { flex: none; width: 30px; height: 30px; border-radius: var(--r-kreis); border: 2px solid var(--border-2); background: var(--bg);
  color: var(--auf-farbe); font-size: 0.92rem; font-weight: 700; display: flex; align-items: center; justify-content: center; }
.ckZeile.done .ckHaken { background: var(--success); border-color: var(--success); }
.ckText { flex: 1 1 auto; min-width: 0; font-size: 0.92rem; line-height: 1.3; cursor: pointer; display: flex; flex-direction: column; gap: 1px; }
.ckZeile.done .ckText { color: var(--text-3); text-decoration: line-through; }
.ckKauf { font-size: 0.7rem; color: var(--accent-strong); text-decoration: none; }
.ckKnopf { position: relative; flex: none; width: 34px; height: 34px; border: none; background: none; border-radius: var(--r-s); font-size: 1rem; color: var(--text-3); }
.ckKnopf:active { background: var(--surface-2); }
/* v2.10.5: Das ✕ rueckt vom Kaufen-Knopf ab und wird leiser - die beiden
   lagen direkt nebeneinander, und ein Fehltipp traf schnell den falschen. */
.ckKnopf.weg { font-size: 0.86rem; color: var(--muted); margin-left: 6px; }
.ckKnopf.weg:active { color: var(--text); }
/* v3.83.0: Der Stift macht die Zeile an Ort und Stelle zum Eingabefeld.
   Es sitzt genau dort, wo eben noch der Text stand - gleiche Schriftgroesse,
   gleiche Zeile, nur mit Rahmen. Deshalb faellt nichts um, wenn es aufgeht. */
.ckKnopf.stift { font-size: 0.86rem; }
.ckAendern { flex: 1 1 auto; min-width: 0; font-size: 0.92rem; line-height: 1.3;
  min-height: 44px; padding: 6px 10px; border: 1px solid var(--accent);
  border-radius: var(--radius-s); background: var(--bg); color: var(--text); }
.ckLadenWahl { flex-basis: 100%; padding: 6px 0 4px 38px; }
.ckLadenKnoepfe { display: flex; gap: 8px; margin-top: 6px; }
.ckLadenKnoepfe .blattAktion { flex: 1; }
.ckNeuZeile { display: flex; gap: 8px; margin: 10px 0 4px; }
.ckNeuZeile input { flex: 1; min-width: 0; }
.ckNeuZeile button { flex: none; width: 44px; height: 44px; border-radius: var(--r-s); border: none; background: var(--primary); color: var(--on-primary); font-size: 1.15rem; }
/* v3.99.0: in :where() - als ID-Regel (1,0,1) schlüge sie den Baustein
   .bsBlattBlock textarea (0,1,1). Dieselbe Bauart wie fünfmal zuvor. */
:where(#editModalFields) textarea { width: 100%; box-sizing: border-box; padding: 10px 12px; border-radius: var(--r-s); border: 1px solid var(--border-2);
  background: var(--surface); color: var(--text); font: inherit; font-size: 16px; resize: vertical; }
/* Gruppen-Kopf: als Checkliste */
/* v3.132.0: gezeichnet statt ☑️, und mit voller Trefferfläche - der
   Abstand nach oben und unten gibt die 44 px dem Kopf zurück. */
.gruppeZuCk { border: none; background: none; padding: 0; min-width: 44px; min-height: 44px; margin: -6px 0;
  display: inline-flex; align-items: center; justify-content: center; color: var(--muted); cursor: pointer; }
.gruppeZuCk:active, .gruppeZuCk:hover { color: var(--text); }
/* v2.10.1: Zwei Sorten Punkte - packen und kaufen */
.ckBlockKopf { display: flex; justify-content: space-between; align-items: center; font-size: 0.7rem; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase; color: var(--text-3); padding: 10px 0 4px; }
.ckBlockKopf span { text-transform: none; letter-spacing: 0; font-weight: 600; background: var(--surface-2); border-radius: var(--r-voll); padding: 1px 8px; }
.ckZeile.kaufen .ckHaken { border-style: dashed; }
.ckKauf.gekauft { color: var(--success-text); }
.ckKauf.offen { color: var(--warn-text, var(--accent-strong)); cursor: pointer; text-decoration: underline dotted; }

/* v2.10.2: Besorgung gehoert zu einer Checkliste */
.ckMarke { cursor: pointer; }
.ckMarke.klein { display: inline-block; margin-left: 8px; font-size: 0.7rem; font-weight: 600; color: var(--accent-strong);
  background: var(--accent-bg); border-radius: var(--r-s); padding: 1px 7px; vertical-align: middle; }
.ckVorschau.leer { color: var(--muted-2); font-style: italic; }

/* v2.10.4: Datumszeile im Kopf */
:where(#raumKopf) .raumTitelBlock { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 0; }
:where(#raumKopf .raumTitelBlock) .raumTitel { flex: none; max-width: 100%; }
#raumKopf .raumDatum { border: none; background: none; padding: 0 4px; min-height: 0; margin-top: -1px;
  font-size: 0.7rem; font-weight: 600; letter-spacing: .01em; color: var(--muted); white-space: nowrap; cursor: pointer; }
#raumKopf .raumDatum:active { color: var(--accent); }
.raumeDatum { margin-left: auto; margin-right: 8px; font-size: 0.78rem; font-weight: 600; color: var(--muted); white-space: nowrap; }
/* 26.10.2026 (Fehler: Deploy 3.183.0 hielt an Probe N7 an, 1000 px ohne Beta):
   In der 295 px breiten Zeile am Rechner (Spalte 320 px) rutschte der letzte
   Knopf 4 px aus der Zeile - nur an Tagen, deren Datum breiter ist: „So,
   25.10. · KW 43“ misst 57,9 px, „Mo, 26.10. · KW 44“ 61,3 px, und bei
   „Mi“/„Do“ oder zweistelligem Monat sind es noch mehr. Wort + Datum + Knöpfe
   hatten nur 1,6 px Luft; kein Teil durfte schrumpfen außer den Knöpfen
   selbst (flex-shrink 1 -> schmaler als 44 px). Regel: Knöpfe und Wort
   behalten ihre Größe, das Datum bekommt nur, was übrig bleibt - und zwar
   ganz oder gar nicht (kein halbes Datum): Es ist selbst eine umbrechende
   Zeile von einer Zeile Höhe; passt ein Teil nicht mehr, rutscht er in die
   zweite, abgeschnittene Zeile (erst die Kalenderwoche, dann das Datum).
   Das leere ::before davor (so hoch wie die Zeile, sonst hätte die erste
   Zeile Höhe 0 und die zweite rückte ins Bild) sorgt dafür, dass auch das
   erste Stück umbrechen darf. Gilt für jede Zahl Knöpfe (auch vier, mit dem Helfer-Knopf).
   Probe: raumtyp-namen-dom.mjs N7 (Datum jeder Länge, bis vier Knöpfe). */
.raumKopfzeile > h2 { flex: none; margin-right: 8px; }
.raumKopfzeile > .raumKopfKnoepfe { flex: none; }
.raumKopfKnoepfe > * { flex: none; }
.raumKopfzeile > .raumeDatum { display: flex; flex-wrap: wrap; justify-content: flex-end; align-content: flex-start; min-width: 0; height: 1.3em; line-height: 1.3; overflow: hidden; }
.raumKopfzeile > .raumeDatum::before { content: ""; width: 0; height: 1.3em; flex: none; }
.raumKopfzeile > .raumeDatum .rdKw { padding-left: 0.3em; }
/* v3.47.0 (Paket 6, Befund S16): "Räume" + Datum + drei Knoepfe zu 44 px
   ergeben rund 362 px. Bei 320 px Fensterbreite sind aber nur 292 px da,
   und kein Teil konnte schrumpfen - die Knoepfe rutschten hinaus.
   Zuerst faellt die Kalenderwoche weg, danach wird die Ueberschrift
   kleiner. Beides nur unterhalb der Breiten, bei denen es klemmt. */
@media (max-width: 380px) {
  .raumeDatum .rdKw { display: none; }
}
@media (max-width: 340px) {
  .raumKopfzeile h2 { font-size: 1.4rem; }
  .raumeDatum { margin-right: 4px; }
}
/* v3.169.0 (UX-Befund): Mit dem Beta-Schriftzug (html.mitBeta, 44 px mehr)
   klebten bei 320 px „Räume“ und Datum aneinander („RäumeDi, 13.10.“) und
   die Knöpfe ragten 30 px aus dem Bild. Nur dann tritt es auf - darum gilt
   alles hier NUR mit Beta-Schriftzug; ohne ist der Kopf wie vorher
   (Leitfaden-Befund: Optik für alle wäre Staging). Mit Schriftzug hat das
   Wort 8 px Luft, Wort und Knöpfe schrumpfen nicht, und wird es zu eng,
   weicht das Datum: bis 470 px ohne Kalenderwoche, bis 410 px und in der
   320 px schmalen Spalte am Rechner ganz (gemessen: dort blieben ihm 0 bis
   48 px für 52 px Text). Es steht im Raum ohnehin im Kopf.
   Probe: proben/oberflaeche/raumtyp-namen-dom.mjs N7, N8. */
/* (h2, Knöpfe und Datum: seit 26.10.2026 für alle, siehe .raumeDatum oben.) */
@media (max-width: 470px) {
  html.mitBeta .raumeDatum .rdKw { display: none; }
}
@media (max-width: 410px), (min-width: 900px) {
  html.mitBeta .raumeDatum { display: none; }
}
/* Am Rechner ist die Raumliste eine 320 px schmale Spalte: Dort passen
   „Räume“, Abstand, Beta-Schriftzug mit Wort und drei Knöpfe nicht (7 px zu
   viel, gemessen) - der Schriftzug zeigt dort nur sein Zeichen, wie am
   schmalen Handy. */
@media (min-width: 900px) {
  html.mitBeta .raumKopfzeile .betaMarkeWort { display: none; }
  html.mitBeta .raumKopfzeile .betaMarkePille { padding: 0 6px; }
}

/* v2.10.4: Aufgeraeumte Kopfzeilen der Reiter
   - Besorgungen: "+ Besorgung" und "Alle auf/zu" in EINER Zeile,
     Einkaufsmodus als Segment.
   - Termine: Ansicht und Filter in einer schmalen Zeile. */
/* v3.102.0 (Sören: "Weiter mit dem design", Variante B): DER KOPF-RIEGEL
   des Termine-Reiters. Eine Zeile statt dreier. Gemessen: vorher 226 px
   zwischen Reiterleiste und erstem Termin, mit sichtbarem Personen-Filter
   282 px - ein Drittel des Bildschirms. "+ Termin" nimmt den Platz, die
   drei Symbolknoepfe sind 48 px breit wie .filterKnopf bei den Aufgaben
   (v3.100.0) - dieselbe Sprache, kein zweites Mass. */
/* v3.131.0 (Sören: „Links besorgung bleibt. Daneben dann ein symbol fürs
   auf ein einklappen und ein symbol für Einkaufsmodus und ein symbol für
   teilen. Also dass nur noch eine Zeile benötigt wird"): Der Kopf der
   Besorgungen ist gebaut wie dieser - dieselben Regeln, kein zweites Maß. */
.terminKopf, .listenKopf { display: flex; align-items: stretch; gap: 8px; margin-bottom: 12px; }
.terminKopf .anlegenToggle, .listenKopf .anlegenToggle { flex: 1 1 auto; min-width: 0; margin: 0; }
.kopfKnopf { flex: none; width: 48px; min-height: 48px; padding: 0; border: 0;
  border-radius: var(--r-m); background: var(--surface); color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.kopfKnopf.an { background: var(--primary); color: var(--on-primary); }
/* v3.102.0: Der Listenfuss traegt, was man NACHSCHLAEGT - ein Tag am Stueck
   und die Geburtstage im Jahr. Ruhig, aber 44 px hoch und voll bedienbar:
   sie sind umgezogen, nicht abgeschafft. */
.terminFuss { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0 8px; }
.terminFuss button { flex: 1 1 auto; min-height: 44px; padding: 0 14px; border: 1px solid var(--border);
  border-radius: var(--r-m); background: none; color: var(--text-2); font: inherit; font-size: 0.86rem; cursor: pointer; }
.terminFuss button.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
/* v3.102.0: Eine Aufgabe mit Frist steht in der Terminliste mit - sie sah
   dort aus wie aus einer anderen App: duenner blauer Kasten, winziger Ring,
   eigene Ecken. Jetzt dieselbe Karte wie ein Termin, nur ohne Personenspur
   (die Zustaendigkeit steht als Chip) - der Unterschied bleibt die getoente
   Flaeche, nicht die Form. */
/* v3.102.0: Eine Aufgabe mit Frist steht in der Terminliste absichtlich
   VERDICHTET - "damit sie die Termine nicht erschlagen" (v3.99.0). Das
   bleibt so; sie ist dort der Nebensatz, nicht der Hauptsatz. Angeglichen
   wird nur die FORM: dieselbe Rundung wie die neuen Karten und kein eckiger
   Rand links mehr - die Farbfläche sagt schon, dass es eine Aufgabe ist. */
#terminListe .kalAufgabe { border-radius: var(--r-m); border-left-width: 1px; }

/* v3.131.0: Bis zu vier Symbole neben „+ Besorgung“. Unter 360 px werden sie
   44 statt 48 px breit (die Mindestgröße bleibt), rücken enger, und
   „+ Besorgung“ nimmt die nächstkleinere Schriftstufe - gemessen bei 320 px
   war es sonst abgeschnitten (96 px Platz). Geprüft in besorgungen-kopf-dom. */
.listenKopf .anlegenToggle { white-space: nowrap; }
/* Im Einkaufsmodus gibt es kein „+ Besorgung“ (zeichneAnlegenBereich) - dann
   stehen die Zeichen rechts, wo sie sonst auch stehen, statt nach links zu
   rutschen. */
.listenKopf { justify-content: flex-end; }
@media (max-width: 359px) {
  .listenKopf { gap: 4px; }
  .listenKopf .kopfKnopf { width: 44px; min-height: 44px; }
  .listenKopf .anlegenToggle { padding-left: 6px; padding-right: 6px; font-size: 0.86rem; }
}
/* v3.132.0 (Sören: „Die ganze funktion vorrat soll raus!"): Hier stand die
   Zahl am Vorrat-Zeichen (.kopfZahl) - mit dem Vorrat entfernt. */
.ansichtWahl.schmal { gap: 6px; margin-bottom: 10px; }
/* v3.100.0: Die Pille statt der Ecke - dieselbe Form wie bei allen anderen
   Ansichtswahlen (die --r-voll-Zeile weiter oben, die hier ueberstimmt
   wurde) und wie die Frist-Schnellwahl im Blatt.
   Die min-height steht jetzt bei 44 statt 38. Das ist KEINE Reparatur: Die
   Knoepfe waren gemessen schon vorher 44 px hoch - eine andere Regel
   ueberstimmte die 38. Die Zahl hier sagt jetzt dasselbe wie das Ergebnis,
   damit der naechste, der sie liest, nicht auf 38 vertraut. */
.ansichtWahl.schmal button { padding: 8px 14px; min-height: 44px; font-size: 0.86rem; border-radius: var(--r-voll); }
/* ============================================================
   v3.131.0 – EINKAUFSLISTE TEILEN (public/einkauf-teilen.js)
   Sören (23.09.2026): „Ich gehe auf das teilen symbol bei besorgungen und
   kann die Listen auswählen … Ich sehe jederzeit welche listen und
   positionen geteilt werden und kann das Teilen jederzeit beenden."
   Nur Tokens, vorhandene Schriftstufen, Ecken aus der Leiter, keine
   eigenen Schatten; alles, was man antippt, mindestens 44 px.
   ============================================================ */
/* Das Teilen-Zeichen steht im Kopf (.listenKopf) - seit dem einzeiligen
   Kopf gibt es die eigene Zeile neben „Liste · Einkaufen · Vorrat“ nicht mehr. */

/* Das Band: solange geteilt wird, in Liste und Einkaufen. Kein eigener
   Scroller (GESTEN Regel 10) - die Knöpfe brechen um. */
/* v3.132.0 (Sören: „Banner für geteilte liste kleiner und einklappbar"):
   zu eine Zeile - der Kopf ist der Knopf (44 px), wie der Kopf eines
   Ladens; auf darunter Läden, Ablauf und die Knöpfe. */
#teilenBand { margin: 0 0 8px; padding: 0 6px 0 12px; border: 1px solid var(--accent-border); border-radius: var(--r-m);
  background: var(--accent-bg); color: var(--text); font-size: 0.86rem; line-height: 1.4; }
.teilenBandKopf { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px; padding: 0; border: 0; background: none;
  color: var(--accent-strong); font: inherit; text-align: left; cursor: pointer; }
.teilenBandKopf:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-s); }
.teilenBandTitel { font-weight: 700; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.teilenBandZahl { flex: none; font-size: 0.78rem; font-weight: 700; color: var(--text-2); background: var(--bg); border-radius: var(--r-voll); padding: 2px 8px; }
.teilenBandPfeil { margin-left: auto; flex: none; display: inline-flex; width: 32px; justify-content: center; color: var(--text-3); }
.teilenBandPfeil .zeichen { transition: transform 0.15s ease; }
.teilenBandKopf[aria-expanded="false"] .teilenBandPfeil .zeichen { transform: rotate(-90deg); }
@media (prefers-reduced-motion: reduce) { .teilenBandPfeil .zeichen { transition: none; } }
.teilenBandMehr { padding: 0 6px 10px 0; }
.teilenBandMehr[hidden] { display: none; }
.teilenBandZeile { overflow-wrap: anywhere; }
.teilenBandKlein { margin-top: 2px; font-size: 0.78rem; color: var(--text-2); }
.teilenBandNeue { display: flex; flex-wrap: wrap; align-items: center; gap: 0 8px; margin-top: 4px; font-size: 0.82rem; color: var(--text-2); }
.teilenBandKnoepfe { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.teilenBandKnoepfe button { flex: 1 1 auto; min-height: 44px; padding: 0 16px; border: 1px solid var(--accent-border); border-radius: var(--r-s);
  background: var(--bg); color: var(--text); font-size: 0.86rem; font-weight: 600; }
.teilenBandKnoepfe button:active { background: var(--surface-2); }
.teilenBandLeise, .tfLeise { min-height: 44px; padding: 0 2px; border: 0; background: none; color: var(--accent);
  font-size: 0.82rem; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }

/* Die Frage nach neuen Punkten (R8) - in allen drei Ansichten, bis jemand
   antwortet. Eine Frage ist eine Zeile. */
#teilenFragen { margin: 0 0 12px; padding: 8px 12px 10px; border: 2px dashed var(--border-2); border-radius: var(--r-m); background: var(--bg); }
.tfKopf { font-size: 0.82rem; font-weight: 700; color: var(--text-3); margin: 2px 0 4px; }
.tfZeile { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; padding: 4px 0; }
.tfText { flex: 1 1 140px; min-width: 0; font-size: 0.92rem; color: var(--text); overflow-wrap: anywhere; }
.tfKnoepfe, .tfAlle { display: flex; flex-wrap: wrap; gap: 8px; }
.tfAlle { margin-top: 6px; }
.tfKnoepfe button, .tfAlle button, .sysTeilenZeile button { min-height: 44px; padding: 0 14px; border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: var(--surface); color: var(--text); font-size: 0.86rem; font-weight: 600; }
.tfKnoepfe button.ja, .tfAlle button.ja, .sysTeilenZeile button.ja { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.tfMehr { font-size: 0.82rem; color: var(--text-3); padding: 2px 0; }

/* Dieselbe Frage an der Chat-Systemzeile „… zur Liste hinzugefügt." -
   AUSSERHALB des zugeklappten .sysDetail, also immer sichtbar, unter dem
   Text (order) und über die volle Breite. Leer nimmt sie keinen Platz. */
.systemNote[data-teilen-ids] { flex-wrap: wrap; }
.systemNote .sysTeilen { order: 3; flex: 1 0 100%; }
.systemNote .sysTeilen:empty { display: none; }
.sysTeilenZeile { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 4px 0 2px; cursor: default; }
.sysTeilenFrage { color: var(--text-2); font-weight: 600; }
.sysTeilenKnoepfe { display: flex; gap: 8px; flex: none; }

/* 31.10.2026 (Beta „laden-auswahl“, app-liste.js ladenKastenAnhaengen; Sören: „… immer auswahlkasten: ort nicht
   erkannt und dann die häufigsten oder text.“): Der Auswahlkasten an der grauen Zeile - außerhalb des zugeklappten
   .sysDetail, also immer sichtbar, über die volle Breite unter dem Text. Chips und Feld mindestens 44 px; das Feld
   hat 1rem, damit iOS nicht hineinzoomt. Schmal (320 px): die Chips brechen um, das Feld füllt die Zeile. */
html.beta-laden-auswahl .systemNote.hatLadenKasten { flex-wrap: wrap; }
html.beta-laden-auswahl .ladenKasten { order: 3; flex: 1 0 100%; min-width: 0; margin: 6px 0 2px; padding: 10px 12px 12px; border: 1px solid var(--border-2);
  border-radius: var(--r-s); background: var(--surface); cursor: default; }
html.beta-laden-auswahl .ladenKastenTitel { font-size: 0.86rem; font-weight: 700; color: var(--text); margin: 0 0 8px; }
html.beta-laden-auswahl .ladenKastenChips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 8px; }
html.beta-laden-auswahl .ladenChip { min-height: 44px; padding: 0 14px; border: 1px solid var(--accent-border); border-radius: var(--r-s);
  background: var(--bg); color: var(--text); font-size: 0.86rem; font-weight: 600; max-width: 100%; overflow-wrap: anywhere; }
html.beta-laden-auswahl .ladenChip:active { background: var(--surface-2); }
html.beta-laden-auswahl .ladenKastenFeld { display: flex; gap: 8px; align-items: stretch; }
html.beta-laden-auswahl .ladenKastenFeld input { flex: 1 1 0; min-width: 0; min-height: 44px; padding: 0 12px; border: 1px solid var(--border-2);
  border-radius: var(--r-s); background: var(--bg); color: var(--text); font-size: 1rem; }
html.beta-laden-auswahl .ladenSenden { flex: none; min-height: 44px; padding: 0 16px; border: 1px solid var(--primary); border-radius: var(--r-s);
  background: var(--primary); color: var(--on-primary); font-size: 0.86rem; font-weight: 600; }
html.beta-laden-auswahl .ladenKasten button:disabled, html.beta-laden-auswahl .ladenKasten input:disabled { opacity: .6; }

/* Marken: an der Zeile, am Gruppenkopf. Klein, im Textblock, kein Knopf. */
.geteiltMarke { display: inline-flex; align-items: center; gap: 3px; margin-left: 6px; padding: 0 7px; font-size: 0.7rem; font-weight: 600;
  color: var(--accent-strong); background: var(--accent-bg); border: 1px solid var(--accent-border); border-radius: var(--r-voll);
  white-space: nowrap; vertical-align: middle; }
.geteiltMarke.fehlt { color: var(--warn-text); background: var(--warn-bg); border-color: var(--warn-border); }
.geteiltMarke.gekauft { color: var(--success-text); background: var(--success-bg); border-color: var(--success-border); }
.geteiltZahl { display: inline-flex; align-items: center; gap: 2px; padding: 1px 6px; font-size: 0.7rem; font-weight: 700;
  color: var(--accent-strong); background: var(--accent-bg); border: 1px solid var(--accent-border); border-radius: var(--r-s); }

/* Das Blatt. Häkchen sind Knöpfe (role=checkbox) - kein rohes <input>,
   und nicht der runde .check, der in der App „gekauft" heißt. */
.tbEinleitung { margin: 0; font-size: 0.86rem; color: var(--text-2); line-height: 1.45; }
.tbLeiste { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.tbKnopf { min-height: 44px; padding: 0 16px; border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: var(--surface); color: var(--text); font-size: 0.86rem; font-weight: 600; }
.tbZaehler { margin-left: auto; font-size: 0.86rem; font-weight: 600; color: var(--text-2); }
.tbGruppen { display: flex; flex-direction: column; gap: 8px; }
.tbGruppe { border-radius: var(--r-m); background: var(--surface); overflow: hidden; }
.tbGruppenKopf { display: flex; align-items: stretch; }
.tbHaken { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; padding: 6px 10px; border: 0;
  background: none; color: var(--text); font-size: 0.92rem; text-align: left; }
.tbGruppenKopf .tbHaken { flex: 1 1 auto; min-width: 0; font-weight: 700; }
.tbPunkt { padding-left: 22px; border-top: 1px solid var(--border); }
.tbName { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.tbZahl { flex: none; font-size: 0.82rem; font-weight: 600; color: var(--text-3); }
.tbPfeil { flex: none; width: 48px; min-height: 48px; border: 0; background: none; color: var(--text-3); font-size: 0.92rem; }
.tbZusatz { display: block; font-size: 0.78rem; font-weight: 400; color: var(--text-3); }
.tbKasten { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px;
  border: 2px solid var(--border-2); border-radius: var(--r-xs); background: var(--bg); color: var(--on-primary); }
.tbKasten .zeichen, .tbKasten .tbStrich { display: none; }
.tbStrich { width: 12px; height: 2px; border-radius: var(--r-xs); background: currentColor; }
.tbHaken[aria-checked="true"] .tbKasten, .tbHaken[aria-checked="mixed"] .tbKasten { background: var(--primary); border-color: var(--primary); }
.tbHaken[aria-checked="true"] .tbKasten .zeichen { display: block; }
.tbHaken[aria-checked="mixed"] .tbKasten .tbStrich { display: block; }
/* Der Hauptknopf bleibt beim Rollen unten im Blatt sichtbar. bottom und
   padding-bottom decken den Innenabstand des Rollbereichs (#editModalFields,
   bis 6 px) ab - gemessen: sonst schauen darunter 2–6 px der Liste hervor. */
.tbFuss { position: sticky; bottom: -6px; z-index: 1; display: flex; flex-direction: column; gap: 6px;
  padding: 10px 0 6px; border-top: 1px solid var(--border); background: var(--bg); }
.tbFuss .feldHinweis[hidden], .tbMeldung:empty { display: none; }
.tbMeldung { color: var(--text-2); font-weight: 600; }
/* v3.100.0: Der Filterknopf im Reiter Aufgaben. Ein Zeichen und das Wort,
   wonach gerade sortiert ist - antippen wechselt. Das Wort bleibt: ein
   Zeichen allein sagt „hier kann man sortieren", nicht WONACH. */
/* v3.100.0: Klein und quadratisch, nur das Zeichen. Der Zustand steckt in
   der Fuellung: ruhig = Voreinstellung (nach Frist), gefuellt = umgestellt.
   Ein Knopf ohne Wort MUSS seinen Zustand zeigen, sonst tippt man blind. */
.filterKnopf { display: inline-flex; align-items: center; justify-content: center;
  width: 48px; min-height: 48px; padding: 0; border: 0; border-radius: var(--r-m);
  background: var(--surface); color: var(--muted); font: inherit; }
.filterKnopf.an { background: var(--primary); color: var(--on-primary); }
.filterKnopf:active { background: var(--surface-2); }
.filterKnopf.an:active { background: var(--text-2); }
/* v3.13.0: Die Ansichtsleiste enthält nur noch Ansichten. Die zwei
   Einblend-Schalter stehen in einer eigenen Zeile darunter - siehe
   .einblendZeile. Die alten .mitFiltern-Regeln sind damit hinfällig. */
.einblendZeile { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin: -6px 0 12px; }
/* v3.102.0: display:flex einer Klasse schlaegt das display:none von
   [hidden] - die Zeile stand deshalb offen da, obwohl sie verborgen
   sein sollte (gemessen: 126 px Kopf statt 60). */
.einblendZeile[hidden] { display: none; }
.einblendWort { font-size: 0.78rem; color: var(--text-3); margin-right: 2px; }
.einblendZeile .essenSchalter {
  flex: 0 1 auto; min-height: 36px; padding: 6px 12px;
  border: 1px solid var(--border); border-radius: var(--r-voll); background: var(--bg);
  font-size: 0.82rem; font-weight: 600; color: var(--text-3); cursor: pointer;
}
.einblendZeile .essenSchalter.aktiv { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn-text); }
.einblendZeile .essenSchalter:not(.aktiv) { opacity: 0.75; text-decoration: line-through; }
#ansichtGeburtstage .gebWort { display: inline; }
/* v3.2.1: 🎂 ist eine ANSICHT wie Liste/Kalender/Tag, kein Filter - deshalb
   dieselbe Form wie die drei, das Wort dazu, sobald Platz ist, und ein
   sichtbarer Abstand vor den beiden Ein/Aus-Schaltern 🍽️ 📋. */
/* Schalterzeile in den Einstellungen (aus den Reitern hierher gewandert) */
/* v3.22.0 (Befund beim Bilddurchlauf): Die Regel ".schalter" von v1.8.0
   (der kleine Kippschalter, 42x26 px) greift auch auf ".setZeile schalter" -
   ihre height:26px wird durch min-height:48px auf genau 48 px angehoben und
   bleibt dort. Eine Schalterzeile wuchs deshalb NICHT mit ihrem Text: Wer
   einen längeren Untertitel schrieb, bekam ihn über den Rahmen hinaus
   gemalt. Bisher fiel es nicht auf, weil alle Untertitel kurz waren.
   height:auto stellt das ab - für jede Schalterzeile in der ganzen App. */
.setZeile.schalter { position: relative; height: auto; }
/* v3.51.0 (Befund D41): Drei Kippschalter in drei Massen (42x26, 40x24,
   34x20) im selben Produkt. Jetzt ueberall 42 x 26 mit 20er-Knauf, wie
   .schalter in der Personen-Palette. */
.setZeile.schalter .schalterKnauf { flex: none; width: 42px; height: 26px; border-radius: var(--r-voll); background: var(--border-2);
  position: relative; transition: background .15s; }
.setZeile.schalter .schalterKnauf::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
  border-radius: var(--r-s); background: var(--stets-weiss); box-shadow: var(--shadow-1); transition: transform .15s; }
.setZeile.schalter.an .schalterKnauf { background: var(--success); }
.setZeile.schalter.an .schalterKnauf::after { transform: translateX(16px); }
/* v3.148.0: Die Schritte der Prüfliste (beta-pruefung.js) sind eine
   Reihenfolge zum Abhaken - die Nummer im Kreis, abgehakt der Haken auf
   Grün wie bei .ckHaken (Checklisten). Kein Kippschalter: Ein Schalter
   stellt etwas ein, ein Haken sagt „erledigt“. */
.setZeile .pruefHaken { width: 30px; height: 30px; border-radius: var(--r-kreis); border: 2px solid var(--border-2);
  background: var(--bg); color: var(--text-2); font-size: 0.82rem; font-weight: 700;
  display: flex; align-items: center; justify-content: center; }
.setZeile[aria-checked="true"] .pruefHaken { background: var(--success); border-color: var(--success); color: var(--auf-farbe); }
/* v3.149.0 (Sören: „Wenn ich in den test abhaken bin und dinge in den Chat
   schreiben soll kopiert man den text indem man das feld antippt."): Die
   Sätze für den Chat stehen unter ihrem Schritt als eigene Felder - bündig
   mit dessen Text (12 Polster + 30 Kreis + 12 Abstand), damit man sieht,
   wozu sie gehören. Ein Feld, kein Link: Es tut etwas (kopieren), es führt
   nirgendwohin. Kopiert trägt es den Haken auf Grün wie der Schritt selbst. */
.pruefSaetze { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin: -2px 0 10px 54px; min-width: 0; }
.pruefSatz { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; max-width: 100%; padding: 8px 12px;
  border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--surface-2); color: var(--text);
  font: inherit; font-size: 0.86rem; line-height: 1.35; text-align: left; cursor: pointer; }
.pruefSatz:active { background: var(--surface); }
.pruefSatzText { min-width: 0; overflow-wrap: anywhere; }
.pruefSatzZeichen { flex: none; display: inline-flex; color: var(--text-2); }
.pruefSatz.kopiert { border-color: var(--success-border); background: var(--success-bg); }
.pruefSatz.kopiert .pruefSatzZeichen { color: var(--success-text); }
@media (max-width: 374px) { .pruefSaetze { margin-left: 12px; } }
/* v3.153.2 (Sören: „In prüfliste unter dem prüfpunkt feld einrichten wenn
   dieser fehlerhaft ist und textfeld was genau jicht funktioniert.“):
   „Klappt nicht“ steht unter jedem Schritt, bündig mit dessen Text wie die
   Sätze darüber - leise (ein Umriss), denn meistens klappt es. Geöffnet:
   das Feld für das, was nicht klappt, und „Senden“. Ein vermerkter Schritt
   trägt den Vermerk in den Farben der Warnung (gelb, nicht rot: Es ist ein
   offener Punkt, kein Absturz). */
.pruefFehlerZeile, .pruefFehlerFeld, .pruefFehlerVermerk { margin: -2px 0 10px 54px; min-width: 0; }
/* v3.153.3: zwei Knöpfe nebeneinander - „Klappt nicht“, „Klappt, aber …“;
   wird es eng, rutscht der zweite darunter. */
.pruefFehlerZeile { display: flex; flex-wrap: wrap; gap: 8px; }
.pruefFehlerKnopf { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 8px 12px;
  border: 1px solid var(--border-2); border-radius: var(--r-s); background: none; color: var(--text-2);
  font: inherit; font-size: 0.86rem; cursor: pointer; }
.pruefFehlerKnopf:active { background: var(--surface); }
.pruefFehlerVermerk { display: flex; gap: 8px; align-items: flex-start; padding: 8px 12px; border-radius: var(--r-s);
  border: 1px solid var(--warn-border); background: var(--warn-bg); color: var(--warn-text); font-size: 0.86rem; line-height: 1.4; }
.pruefFehlerVermerk .sym { flex: none; display: inline-flex; margin-top: 1px; }
.pruefFehlerVermerk .txt { min-width: 0; overflow-wrap: anywhere; }
.pruefFehlerNachsatz { display: block; margin-top: 2px; color: var(--text-2); }
/* v3.153.3: „Klappt, aber“ - der Schritt klappt; grün wie der Haken, nicht
   gelb wie eine offene Warnung. */
.pruefFehlerVermerk.aber { border-color: var(--success-border); background: var(--success-bg); color: var(--success-text); }
.pruefFehlerFeld { display: flex; flex-direction: column; gap: 8px; }
.pruefFehlerLabel { font-size: 0.86rem; font-weight: 600; color: var(--text); }
/* 16 px: kleiner zoomt das iPhone beim Antippen hinein (wie #meldenBeschreibung). */
.pruefFehlerText { width: 100%; box-sizing: border-box; min-height: 88px; padding: 10px 12px; border: 1px solid var(--border-2);
  border-radius: var(--r-s); background: var(--bg); color: var(--text); font: inherit; font-size: 16px; resize: vertical; }
.pruefFehlerText[aria-invalid="true"] { border-color: var(--warn-border); }
.pruefFehlerKnoepfe { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }
.pruefFehlerKnoepfe button { min-height: 44px; padding: 10px 18px; border-radius: var(--r-s); border: none; font: inherit; font-size: 0.92rem; font-weight: 600; cursor: pointer; }
.pruefFehlerAbbruch { background: var(--surface-2); color: var(--text); }
.pruefFehlerSenden { background: var(--primary); color: var(--on-primary); }
.pruefFehlerSenden[disabled] { opacity: .6; cursor: default; }
.pruefFehlerHinweis { font-size: 0.78rem; color: var(--muted); line-height: 1.4; }
/* Vorführung (08.10.2026, Sören: „Kann man die prüfungen automatisieren? …
   ich schaue zu?“): Unter jedem Schritt, was die Vorführung dabei sah -
   grün wie ein Haken, gelb wie eine Warnung (nicht rot: es ist ein offener
   Punkt), „nur auf dem Gerät“ leise. Der Knopf „Video ansehen“ öffnet die
   Aufnahme im Blatt. */
.pruefAuto { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: -2px 0 10px 54px; min-width: 0; padding: 8px 12px;
  border-radius: var(--r-s); border: 1px solid var(--success-border); background: var(--success-bg); color: var(--success-text); font-size: 0.86rem; line-height: 1.4; }
.pruefAuto.rot { border-color: var(--warn-border); background: var(--warn-bg); color: var(--warn-text); }
.pruefAuto[data-pruef-auto="geraet"] { border-color: var(--border-2); background: none; color: var(--text-2); }
.pruefAuto .sym { flex: none; display: inline-flex; }
.pruefAuto .txt { flex: 1 1 160px; min-width: 0; overflow-wrap: anywhere; }
.pruefAutoGrund { display: block; margin-top: 2px; color: var(--text-2); }
/* Prüfliste offen (24.10.2026, Sören: „… mir nur die offenen punkte in der
   App anzeigen“): Ein Lauf auf einer anderen Version zählt nicht - leise wie
   „nur auf dem Gerät“. Die automatisch geprüften Schritte stehen zugeklappt
   unter einer Zeile wie Freigegebenes (Winkel zeigt auf/zu). */
.pruefAuto.alt { border-color: var(--border-2); background: none; color: var(--text-2); }
.pruefAutoGruppe { margin: 4px 0 8px; }
.pruefAutoKopf .sym { color: var(--success-text); }
.pruefAutoKopf .pfeil { display: inline-flex; transition: transform .2s; }
.pruefAutoKopf .pfeil.auf { transform: rotate(180deg); }
.pruefAutoVideo { flex: none; min-height: 44px; padding: 8px 12px; border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: var(--bg); color: var(--text); font: inherit; font-size: 0.86rem; font-weight: 600; cursor: pointer; }
.pruefAutoVideo:active { background: var(--surface); }
.pruefVideoBlatt { display: flex; flex-direction: column; gap: 10px; }
.pruefVideo { display: block; width: 100%; max-height: 55vh; border-radius: var(--r-s); background: var(--surface-2); object-fit: contain; }
.pruefVideoStand { margin: 0; font-size: 0.86rem; color: var(--text-2); }
@media (max-width: 374px) { .pruefFehlerZeile, .pruefFehlerFeld, .pruefFehlerVermerk, .pruefAuto { margin-left: 12px; } }
/* v3.153.2 (Sören: „Nach für alle freigeben wird der prüfabschnitt
   eingeklappt“): Freigegebenes steht zugeklappt unten - eine Zeile mit
   Titel und „für alle seit …“, der Winkel zeigt, dass sie aufgeht. */
.pruefFreiKopf .pfeil { display: inline-flex; transition: transform .2s; }
.pruefFreiKopf .pfeil.auf { transform: rotate(180deg); }
/* v3.168.0 (Sören: „Achso in der Beta Prüfliste ist viel zu viel“): Die
   Prüfliste zeigt EINE Neuerung. Oben „1 von N im Test“ (leise, wie ein
   Seitenzähler); unter „Für alle freigeben“ ein kleiner Zweitknopf
   „Später“ - ein Umriss wie „Klappt nicht“, denn er schiebt nur auf. */
.pruefZaehler { margin: 0 2px 8px; font-size: 0.86rem; font-weight: 600; color: var(--text-2); }
.pruefSpaeterZeile { display: flex; justify-content: flex-start; margin: 4px 0 8px; }
.pruefSpaeter { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 8px 14px;
  border: 1px solid var(--border-2); border-radius: var(--r-s); background: none; color: var(--text-2);
  font: inherit; font-size: 0.86rem; cursor: pointer; }
.pruefSpaeter:active { background: var(--surface); }
@media (prefers-reduced-motion: reduce) { .pruefFreiKopf .pfeil { transition: none; } }
/* v3.149.0 (Sören: „… Cool wäre vielleicht ein beta schriftzug oben der
   dauerhaft angezeigt wird und ich direkt zu den aufgaben springe."): DER
   BETA-SCHRIFTZUG im Raumkopf und über der Raumliste (index.html,
   beta-schalter.js betaMarkeTipp). Nur mit eingeschalteter Beta zu sehen
   (html.mitBeta) - ohne Beta ist der Kopf, wie er war. Der Knopf ist 44 px
   hoch und breit (treffbar), die Pille darin klein: Sie sagt, dass Beta an
   ist, und nimmt dem Raumnamen so wenig Platz wie möglich. Lila wie die
   Planung - in der App die Farbe für „noch in Arbeit“. Unter 360 px bleibt
   nur das Zeichen (das Wort steht im aria-label). */
.betaMarke { display: none; flex: none; align-items: center; justify-content: center; min-width: 44px; min-height: 44px;
  margin: 0; padding: 0 2px; border: none; background: none; color: inherit; font: inherit; cursor: pointer; }
html.mitBeta .betaMarke { display: inline-flex; }
.betaMarkePille { display: inline-flex; align-items: center; gap: 4px; height: 26px; padding: 0 9px;
  border-radius: var(--r-voll); background: var(--purple-bg); color: var(--purple);
  font-size: 0.78rem; font-weight: 700; white-space: nowrap; }
.betaMarkeZeichen { display: inline-flex; }
.betaMarke:active .betaMarkePille { background: var(--surface-2); }
@media (max-width: 359px) { .betaMarkeWort { display: none; } .betaMarkePille { padding: 0 6px; } }
/* 26.10.2026 (Beta „helfer“, Sören: „Helfer muss nach oben neben das beta
   symbol. In form von ? Oder roboter süß und klein gezeichnet grau“): DER
   HELFER-KNOPF neben dem Beta-Schriftzug, im Raumkopf (#helferKnopf) und über
   der Raumliste (#helferKnopfRaeume). Nur mit Beta UND Beta „helfer“
   (html.mitBeta.beta-helfer) - sonst display:none, der Kopf ist wie vorher.
   Grau (--muted), currentColor: im schwarzen Kopf (kopf-einfarbig) hebt sich
   die Farbe über die dortigen Token ab. Tippfläche 44 x 44, aber nur 32 px
   Platz im Kopf (der Raumname hat Vorrang, wetter-kopf-dom K2): je 6 px Außenabstand negativ, die Fläche liegt über dem
   leeren Rand der Nachbarn (der Beta-Schriftzug und die Suche sind selbst
   44 px breit, ihr Zeichen sitzt mittig). Weder Zuhörer noch touch-action. */
.helferKnopf { display: none; flex: none; align-items: center; justify-content: center; width: 44px; min-width: 44px; height: 44px; min-height: 44px;
  margin: 0 -6px; padding: 0; border: none; background: none; color: var(--muted); font: inherit; cursor: pointer; position: relative; z-index: 1; }
html.mitBeta.beta-helfer .helferKnopf { display: inline-flex; }
.helferKnopfZeichen { display: inline-flex; }
/* Über der Raumliste sitzen fünf Knöpfe nebeneinander (Beta, Helfer, Ordnen,
   Einstellungen, Konto): auf schmalen Telefonen ragte die Reihe gemessen
   um 8 px über den Rand (320 px). Die Zeichen sind 44-px-Flächen mit rund
   11 px Luft um sich - ohne den Abstand dazwischen bleibt jede Fläche 44 px
   und die Zeichen stehen nicht enger als im Raumkopf. */
@media (max-width: 379px) { html.mitBeta.beta-helfer .raumKopfKnoepfe { gap: 0; } }
.helferKnopf:active { color: var(--text); }
.helferKnopf:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; border-radius: var(--r-s); }

/* v2.10.4: Essen – eingeklappte Vorschlags-Einstellungen und Zutaten-Listen */
.vfAuf, .zlAuf { display: flex; align-items: center; gap: 8px; width: 100%; margin: 0 0 10px; padding: 9px 12px; min-height: 42px;
  border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--surface); color: var(--text); text-align: left; }
.vfAuf:active, .zlAuf:active { background: var(--surface-2); }
.vfAufTitel, .zlAufTitel { font-size: 0.86rem; font-weight: 700; flex: none; }
.vfAufStand, .zlAufStand { flex: 1; min-width: 0; font-size: 0.78rem; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vfAufPfeil, .zlAufPfeil { flex: none; color: var(--muted); }
#vorschlagFilter[hidden], #zutatenListenBox[hidden] { display: none; }

/* v2.10.4: Punktestand als eine Zeile */
/* v3.100.0 - Sören: „Nur die Umrandung etwas runder im wie bei apple."
   Die Form kommt aus dem Blatt: gefuellte Flaeche, --r-m, kein Rahmen.
   Gemessen war der Reiter bei 12 px MIT Rahmen, das Blatt bei 18 px OHNE -
   der Reiter war also eckiger und umrandet, das Blatt runder und gefuellt.
   42 -> 44 px, weil die Zeile antippbar ist. */
.punkteZeileKopf { display: flex; align-items: center; gap: 8px; width: 100%; margin-bottom: 10px; padding: 8px 14px;
  min-height: 44px; border: 0; border-radius: var(--r-m); background: var(--surface); cursor: pointer; }
.punkteZeileKopf:active { background: var(--surface-2); }
.punkteZeileKopf .pzTitel { font-size: 0.82rem; font-weight: 700; flex: none; }
.punkteZeileKopf .pzWerte { flex: 1; min-width: 0; display: flex; gap: 6px; overflow: hidden; }
.punkteZeileKopf .pzPerson { font-size: 0.78rem; color: var(--text-2); background: var(--surface-2); border-radius: var(--r-voll);
  padding: 1px 8px; white-space: nowrap; }
.punkteZeileKopf .pzPerson.erster { background: var(--success-bg); color: var(--success-text); font-weight: 700; }
.punkteZeileKopf .pzLeer { font-size: 0.78rem; color: var(--muted); }
.punkteZeileKopf .pzMehr { flex: none; color: var(--muted); }

/* v2.10.4: Blaetter - eine klare Hauptaktion, der Rest leiser */
.blattKnoepfe .blattAktion { background: var(--surface); border: 1px solid var(--border-2); color: var(--text-2); font-weight: 600; }
.blattKnoepfe .blattAktion.haupt { background: var(--accent-bg); border-color: var(--accent-border); color: var(--accent-strong); font-weight: 700; }
.blattKnoepfe .blattAktion:active { background: var(--surface-2); }
/* v3.153.4 (Sören, 07.10.2026: „Termin löschen unter mehr rot einfärben“):
   Löschen im Termin-Blatt rot - Text, Zeichen und Rand, wie .warnAktion.
   v3.102.0 wollte die rote Schrift schon („.blattAktion.blattWeg“, die
   Fläche erst beim Drücken), aber die Regel stand weiter oben und wog
   gleich viel wie die zwei Zeilen hier darüber - die spätere gewann, der
   Knopf war grau. Darum jetzt mit drei Klassen und HINTER ihnen. */
.blattKnoepfe .blattAktion.blattWeg { color: var(--danger); border-color: var(--danger-border); }
.blattKnoepfe .blattAktion.blattWeg:active { background: var(--danger-bg); }

/* v2.10.6 (Review-Fix): Trefflaechen unter 40x40px (.ckKnopf, .gMarke, .kalHaken, die kompakten
   .calBtn/.del in #terminListe) bekommen ein unsichtbares, zentriertes ::before als groesseren
   Klick-/Tastatur-Hit-Bereich, ohne die sichtbare Icon-Groesse zu aendern. 40px minus die jeweilige
   Icon-Breite verteilt sich exakt auf den Abstand zum Nachbar-Icon (z.B. .ckKnopf + .ckKnopf.weg:
   6px Abstand, je 3px pro Seite) - die Hit-Bereiche stossen an, ohne sich zu ueberlappen, damit
   zwei benachbarte Icons nicht denselben erweiterten Bereich teilen (siehe v2.10.5 weiter oben:
   genau das sollte vermieden werden). Die Basis-Selektoren brauchen dafuer position:relative
   (dort ergaenzt); hier nur noch das ::before selbst. */
.ckKnopf::before, .gMarke::before, .kalHaken::before, .item .del::before, .item .calBtn::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 40px;
  height: 40px;
}

/* v2.10.6 (Review-Fix): Passwort-Sheet beim Gast-Anlegen (ersetzt alert()) - Passwort gut lesbar,
   mit eigenem Kopieren-Knopf darunter. */
.gastPwGross {
  display: block; margin: 10px 0; padding: 10px 12px; background: var(--surface); border: 1px solid var(--border-2);
  border-radius: var(--r-s); font-size: 1.05rem; font-weight: 700; letter-spacing: 0.03em; text-align: center; color: var(--text);
}
#frageText .pwKopierBtn {
  display: block; margin: 0 auto; width: auto; min-height: 40px; padding: 0 14px; border: 1px solid var(--border-2);
  border-radius: var(--r-s); color: var(--text-2); font-weight: 600; font-size: 0.86rem;
}
/* v2.10.4: Die Filter der Gerichteliste in EINER wischbaren Zeile statt
   zwei umbrechenden. */
.gerichteFilter { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  padding-bottom: 2px; }
.gerichteFilter::-webkit-scrollbar { display: none; }
.gerichteFilter > * { flex: 0 0 auto; }

/* v2.10.5: Rueckfrage mit drei Antworten - bei dreien untereinander. */
#frageModal .modalActions { flex-wrap: wrap; }
#frageModal .modalActions button.zweit { flex: 1 1 100%; order: -1; background: var(--surface); border: 1px solid var(--border-2); color: var(--text); }
#frageModal .modalActions button[hidden] { display: none; }

/* v2.10.7: Volltextsuche (🔍 im Raumkopf) - Blatt mit Suchfeld, Treffer
   nach Art gruppiert, Begriff mit <mark> hervorgehoben. */
.sucheZeile { margin-bottom: 2px; }
.sucheZeile input[type="search"] { -webkit-appearance: none; appearance: none; }
.sucheZeile .vorschlagKnopf { margin-top: 0; }
.sucheStand { min-height: 1.2em; margin: 4px 2px 6px; font-size: 0.78rem; }
.sucheErgebnis { display: flex; flex-direction: column; gap: 12px; }
.sucheGruppe { display: flex; flex-direction: column; gap: 4px; }
.sucheGruppeKopf { display: flex; align-items: center; gap: 6px; padding: 4px 2px 2px; font-size: 0.7rem; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); }
.sucheGruppeKopf .stZahl { text-transform: none; letter-spacing: 0; font-weight: 600; background: var(--surface-2);
  border-radius: var(--r-voll); padding: 0 8px; line-height: 1.5; }
.sucheTreffer { display: flex; align-items: flex-start; gap: 10px; width: 100%; padding: 9px 10px; min-height: 44px;
  border: 1px solid var(--border); border-radius: var(--r-s); background: var(--surface); color: var(--text); text-align: left;
  font: inherit; cursor: pointer; }
.sucheTreffer:active { background: var(--surface-2); }
.sucheTreffer .stSym { flex: none; width: 22px; text-align: center; font-size: 1rem; line-height: 1.4; }
.sucheTreffer .stText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.sucheTreffer .stZeile { font-size: 0.92rem; line-height: 1.35; overflow-wrap: anywhere; }
.sucheTreffer .stMeta { font-size: 0.7rem; color: var(--muted); }
.sucheTreffer.erledigt .stZeile { color: var(--muted); text-decoration: line-through; }
.sucheTreffer mark { background: var(--warn-bg); color: var(--warn-text); border-radius: var(--r-xs); padding: 0 1px; font-weight: 700; }
.sucheLeer { padding: 18px 6px; text-align: center; font-size: 0.92rem; color: var(--muted); }
/* Treffer im Reiter kurz hervorheben (wie eine Chat-Blase) */
.swipeReihe.hervor, .checklisteKarte.hervor, .archivMsg.hervor { animation: blaseHervor 1.6s ease-out; }

/* v2.10.7: Termine - Vergangenes eingeklappt am Ende der Liste */
.vergangeneKopf { display: flex; align-items: center; gap: 8px; width: 100%; margin: 18px 0 8px; padding: 9px 12px; min-height: 42px;
  border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--surface); color: var(--text-2); text-align: left;
  font: inherit; font-size: 0.86rem; font-weight: 700; cursor: pointer; }
.vergangeneKopf:active { background: var(--surface-2); }
.vergangeneKopf .vkTitel { flex: 1; }
.vergangeneKopf .vkZahl { font-weight: 600; background: var(--surface-2); color: var(--text-3); border-radius: var(--r-voll); padding: 1px 9px; }
.vergangeneKopf .gruppenPfeil { width: 16px; }
.vergangeneListe { opacity: .85; }
.vergangeneListe[hidden] { display: none; }
#terminListe .vergangeneListe .tagTrenner.banner { background: var(--surface-2); color: var(--text-2); }

/* v2.10.7: Speicher-Diagnose in den Einstellungen - eine Info-Zeile, kein Knopf */
.setZeile.setInfo { cursor: default; }
.setZeile.setInfo:active { background: var(--surface); }
.setZeile.setInfo .tt { font-weight: 500; font-size: 0.82rem; line-height: 1.35; }
.setZeile.setInfo.warn .tt { color: var(--danger); }
.setZeile.setInfo.warn .ut { color: var(--danger); font-weight: 700; }
.setZeile.setInfo.warn { border-color: var(--danger-border); background: var(--danger-bg); }

/* v2.10.7: Die alte Regel ".schalter::after" (Umschalter aus v1.8.0) griff auch auf
   ".setZeile.schalter" und malte einen weissen Kreis oben links in jede Schalterzeile
   der Einstellungen - der Knauf hat sein eigenes ::after. */
.setZeile.schalter::after { content: none; }

/* v2.10.7: Hinweis des Servers im Zutaten-Blatt (gekuerzte Verarbeitung) */
.zutatBuendel.zutatHinweis { color: var(--warn-text); background: var(--warn-bg); border-color: var(--warn-border); }

/* ============================================================
   v2.11.0: Wichtigkeit/Dringlichkeit, Reisen, Phasen, Erinnerungen
   Farben ausschliesslich aus den vorhandenen Variablen - eine eigene
   Palette fuer vier Quadranten waere eine zweite Farbsprache in einer
   App, die schon eine hat.
   ============================================================ */

/* Quadranten-Überschriften im Stil der bestehenden Abschnitte
   ("☑️ CHECKLISTEN"): dieselbe Typografie, nur ein farbiger Strich links,
   damit man die vier Bloecke beim Scrollen auseinanderhaelt. */
.todoSection.quadrantKopf { border-left: 3px solid var(--border-2); padding-left: 8px; margin-left: -2px; }
.todoSection.quadrantKopf.sofort { color: var(--danger); border-left-color: var(--danger); }
.todoSection.quadrantKopf.einplanen { color: var(--accent-strong); border-left-color: var(--accent); }
.todoSection.quadrantKopf.abgeben { color: var(--warn-text); border-left-color: var(--warn); }
.todoSection.quadrantKopf.rest { color: var(--muted); border-left-color: var(--border-2); }
.quadrantListe { margin-bottom: 4px; }

/* v2.11.0: .addForm label.feld ist display:flex - das schlaegt das
   eingebaute [hidden]{display:none} des Browsers. Ohne diese Zeile bliebe
   das Unterkunfts-Feld nach dem Eintragen sichtbar. */
.addForm label.feld[hidden] { display: none; }

/* Die beiden Segmente im Anlege-Formular tragen dieselbe kleine
   Beschriftung wie "Rhythmus"/"Aufwand" daneben (label.feld). */
.addForm #addTodoWichtigLabel, .addForm #addTodoDringendLabel {
  display: block; font-size: 0.78rem; font-weight: 700; color: var(--text-3); margin-bottom: 4px; }
.addForm .segment button { min-height: 40px; font-size: 0.82rem; }

/* v2.11.2: Einstufung als schmaler Streifen am linken Rand statt als
   Text-Marke in der Zeile - siehe todoZeile() in aufgaben.js. Ruhiger,
   kostet keinen Platz in der ohnehin engen Markenzeile, und "🔥 Sofort"
   steht nicht mehr im Widerspruch zur Ueberschrift "IRGENDWANN". */
.item.aufgabe[data-quadrant] { position: relative; padding-left: 16px; }
/* v3.100.1: Der Abstand oben und unten muss die RUNDUNG der Karte frei
   lassen. Bei 18 px Radius reichten 10 px; seit die Karten 26 px rund sind
   (Sören: „Die Aufgabenfelder müssen noch runder"), liegt 10 px mitten in
   der Kurve - das Strichende wurde angeschnitten.
   Gerechnet: Die Kante der Karte liegt an der Stelle x der Senkrechten bei
   y = R - sqrt(R² - (R-x)²). Bei R=26 und x=8 sind das 7,2 px; 15 px lassen
   also Luft. eintragen-dom 43 rechnet das nach, statt die 15 abzuschreiben -
   wird die Rundung wieder groesser, faellt es dort auf. */
.item.aufgabe[data-quadrant]::after {
  content: ""; position: absolute; left: 8px; top: 15px; bottom: 15px; width: 3px;
  border-radius: var(--r-voll); background: var(--border-2);
}
.item.aufgabe[data-quadrant="sofort"]::after { background: var(--danger); }
.item.aufgabe[data-quadrant="einplanen"]::after { background: var(--accent); }
.item.aufgabe[data-quadrant="abgeben"]::after { background: var(--warn); }
/* In der Quadranten-Ansicht sagt es schon die Ueberschrift. */
.quadrantListe .item.aufgabe[data-quadrant] { padding-left: 10px; }
.quadrantListe .item.aufgabe[data-quadrant]::after { display: none; }
/* Nur fuer Vorlesehilfen - optisch nicht vorhanden, aber im Textfluss. */
.nurVorlesen {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.marke.ortMarke { color: var(--text-3); }
.marke.erinnerungMarke { color: var(--accent-strong); }

/* v2.11.0: Reise = mehrtaegiger Termin. In der Liste eine ruhige Karte mit
   Zeitraum und Unterkunft, im Kalender ein dezent hinterlegter Tag statt
   eines Punktes - ein Punkt an acht Tagen sagt nicht, dass es EINE Reise ist. */
.item.terminZeile.reise, #terminListe .item.terminZeile.reise, #kalTagListe .item.terminZeile.reise {
  background: var(--accent-bg); border-color: var(--accent-border); border-left: 4px solid var(--accent); }
.reiseSpanne { font-weight: 700; color: var(--accent-strong); }
.item .unterkunftZeile { margin-top: 3px; font-size: 0.78rem; color: var(--muted); line-height: 1.45; }
/* (v3.160.8: „.item .unterkunftZeile .ortLink“ ist weg - die Unterkunft
   steht seit dem Termin-Blatt (aus Beta freigegeben) als Text da, ohne Link.) */
/* v3.102.0: Das Reiseband war eine gefuellte Flaeche und damit lauter als
   HEUTE. Jetzt ein 3-px-Balken an der Unterkante: immer noch ein
   durchgehendes Band ueber die Reisetage, aber es tritt hinter den Tag
   zurueck, auf den es ankommt. */
.kalTag.reiseTag { position: relative; background: none; }
.kalTag.reiseTag::before { content: ""; position: absolute; left: 0; right: 0; bottom: 2px;
  height: 3px; background: var(--accent); opacity: .55; }
.kalTag.reiseStart::before { left: 3px; border-top-left-radius: var(--r-voll); border-bottom-left-radius: var(--r-voll); }
.kalTag.reiseEnde::before { right: 3px; border-top-right-radius: var(--r-voll); border-bottom-right-radius: var(--r-voll); }
.kalTag.reiseTag.fremd { background: transparent; }
/* v3.149.3 (gefunden mit oberflaeche/schulferien-dom.mjs S2b): „background:
   none“ oben nahm dem GEWÄHLTEN Reisetag seine Füllung - in den Kästen (und
   im aufgeklappten Gitter der Woche) stand die Zahl dann weiß auf Hellgrau,
   unsichtbar. „Ruhig“ und „Balken“ setzen ihren gewählten Tag selbst
   (#kalenderBox[data-stil=…], stärker als diese Zeile). */
.kalTag.reiseTag.gewaehlt { background: var(--primary); }
/* v3.129.1: 8 px waren eine Größe außerhalb der Leiter, die probe-stil nie
   sah (sie las nur „border-radius“, nicht die einzelnen Ecken). Nach oben
   gerundet wie in v3.85.0: --r-s, dieselbe Ecke wie jeder andere Tag. */
.kalTag.reiseStart { border-top-left-radius: var(--r-s); border-bottom-left-radius: var(--r-s); }
.kalTag.reiseEnde { border-top-right-radius: var(--r-s); border-bottom-right-radius: var(--r-s); }
/* v3.149.3 (Sören: „Ferientage fehlen noch im Kalender“; bis v3.150.1
   hinter Beta „schulferien“, seit v3.151.0 für alle): Schulferien - ein
   3-px-Band an der OBERKANTE in Grün, das Reiseband liegt an der Unterkante
   in Blau; Urlaub in den Ferien zeigt beide. Gilt in allen Stilen; die
   Klasse setzt app-termine.js (ferienAm). Bis v3.150.1 stand hier „keine
   Fläche: Wochen voller Farbe wären lauter als HEUTE (v3.102.0)“ - das
   galt einer VOLLEN Farbe; die leise Fläche von v3.151.0 (darunter) steht
   hinter HEUTE zurück (in „Ruhig“ seine gefüllte Scheibe, in den Kästen
   sein Rahmen - gemessen in oberflaeche/schulferien-dom.mjs). */
.kalTag.ferienTag { position: relative; }
/* v3.151.0 (Sören, mit einem Bild des Monats im Stil „Ruhig“: „Kalender
   zeigt nur eine farbe an also denkt man ferien sind schon am 24.
   zuende“): Das Band allein stand direkt unter der Linie zur Zeile darüber
   und las sich als Strich unter DEREN Zahlen - die Herbstferien bis Sa
   31.10. endeten scheinbar unter der 24, und in der Zeile 26.–31. war nur
   das Blau der Reise zu sehen. Jetzt trägt jeder Ferientag dazu eine leise
   grüne Fläche: Man sieht, welche Zeile das Band oben begrenzt, und an
   jedem Tag beide Farben. Ein Platz unter der Zahl kam nicht in Frage -
   dort liegen die Punkte (in „Ruhig“ und den Kästen) und die Balken der
   Termine, gemessen mit oberflaeche/schulferien-dom.mjs. Wo ein Tag schon
   eine eigene Fläche hat - der gewählte Tag in den Kästen (gefüllt), ein
   Feiertag (Kästen, Balken) -, behält er sie; die Tage außerhalb des
   Monats bleiben blass. Die Zahl hat auf der Fläche 4,5:1 (S2c). */
#kalenderBox .kalTag.ferienTag:not(.fremd):not(.gewaehlt):not(.feiertag),
#kalenderBox[data-stil="ruhig"] .kalTag.ferienTag:not(.fremd),
#kalenderBox[data-stil="balken"] .kalTag.ferienTag:not(.fremd):not(.feiertag) { background: var(--success-bg); }
/* Volle Farbe, keine Deckkraft: mit .7 waren es auf --surface 2,8:1 -
   unter den 3:1, die ein Zeichen mit Bedeutung braucht (WCAG 1.4.11,
   oberflaeche/schulferien-dom.mjs S3). */
.kalTag.ferienTag::after { content: ""; position: absolute; left: 0; right: 0; top: 2px;
  height: 3px; background: var(--success); }
.kalTag.ferienStart::after { left: 3px; border-top-left-radius: var(--r-voll); border-bottom-left-radius: var(--r-voll); }
.kalTag.ferienEnde::after { right: 3px; border-top-right-radius: var(--r-voll); border-bottom-right-radius: var(--r-voll); }
.kalTag.ferienTag.fremd::after { opacity: .3; }
#kalenderBox[data-stil="balken"] .kalTag.ferienTag::after { top: 0; }
/* Der gewählte Tag ist in den Kästen gefüllt (--primary): Grün darauf hat
   im dunklen Thema 1,6:1 - dort trägt das Band die Schriftfarbe des Tags.
   „Ruhig“ und „Balken“ füllen den gewählten Tag nicht. */
#kalenderBox:not([data-stil="ruhig"]):not([data-stil="balken"]) .kalTag.gewaehlt.ferienTag::after { background: var(--on-primary); }
.wChip.ferien { position: relative; }
.wChip.ferien::after { content: ""; position: absolute; left: 8px; right: 8px; top: 2px; height: 3px;
  border-radius: var(--r-voll); background: var(--success); }
.wChip.gewaehlt.ferien::after { background: var(--auf-farbe); }
/* Die Zeile am Tag, in der Liste und im Heute-Blatt: wie die des
   Feiertags, aber im Grün des Bands - man soll sie dem Band zuordnen. */
.feiertagZeile.ferienZeile { border-style: solid; border-color: var(--success-border); background: var(--success-bg); color: var(--success-text); }

/* Aufklappbarer Unterkunfts-Block im Termin-Blatt */
.blattKlapp { border: 1px solid var(--border); border-radius: var(--r-s); padding: 0 10px; margin-top: 8px; }
.blattKlapp > summary { list-style: none; cursor: pointer; padding: 11px 2px; font-size: 0.86rem; font-weight: 700; color: var(--text-2); min-height: 44px; display: flex; align-items: center; }
.blattKlapp > summary::-webkit-details-marker { display: none; }
.blattKlapp[open] > summary { border-bottom: 1px solid var(--border); margin-bottom: 6px; }
.blattKlapp > div:last-child { padding-bottom: 8px; }

/* v2.11.0: Planung in zwei Phasen - VORHER erledigen / DABEI dran denken */
.planPhase { display: flex; align-items: center; gap: 8px; font-size: 0.7rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--text-3); margin: 14px 0 6px; }
.planPhase.dabei { color: var(--accent-strong); }
.planPhase .planPhaseZahl { background: var(--surface); color: var(--text-3); border-radius: var(--r-s); padding: 0 7px; font-size: 0.7rem; letter-spacing: 0; text-transform: none; }
.planZeile .planSchieben { flex: none; border: 0; background: var(--surface-2); color: var(--text-3); border-radius: var(--r-s); width: 40px; height: 40px; min-height: 40px; padding: 0; font-size: 0.92rem; }
.planZeile .planSchieben:active { background: var(--surface-2); }

/* Zutaten-Blatt: der Hinweis „steht schon offen (1 Bund) → wird 2 Bund“ */
.zutatZeile .feldHinweis.zutatOffen { color: var(--accent-strong); }
.zutatZeile.schonDa .zutatName { color: var(--text); }
.name .erinnerungMarke { font-size: 0.82rem; margin-left: 2px; }

/* ============================================================
   v2.22.0: Serien (wiederkehrende Termine) und Feiertage
   ============================================================ */
/* 🔁 vor dem Titel eines Vorkommens - nicht fett, damit der Titel vorn bleibt. */
.name .serieMarke { font-weight: 400; font-size: 0.82em; color: var(--muted); white-space: nowrap; } /* v2.52.1: "🔁 Mi+Fr" */
/* Die Zeile im Blatt: "🔁 jeden Dienstag · seit 08.09. · bis 15.12." plus
   der Hinweis auf das 6-Monats-Fenster. Ruhig hinterlegt wie eine Reise. */
.serieZeile { background: var(--accent-bg); border: 1px solid var(--accent-border); border-radius: var(--r-s);
  padding: 9px 12px; margin-bottom: 10px; font-size: 0.86rem; font-weight: 600; color: var(--accent-strong); line-height: 1.4; }
.serieZeile .feldHinweis { font-weight: 400; color: var(--text-3); margin-top: 3px; }
.serieFelder { margin-top: 8px; }
/* "Serie beenden" ist umkehrbar (Rueckgaengig im Chat) - deshalb Grau wie
   die anderen Blatt-Aktionen, kein Rot. */
.blattKnoepfe .blattAktion.serieEnde { color: var(--text-3); }
/* Drei Antworten ("Abbrechen / Ganze Serie / Nur dieses Mal") passen nicht
   nebeneinander in 320 px - dann umbrechen, der Hauptknopf zuletzt. */
#frageModal .modalActions { flex-wrap: wrap; }
#frageModal .modalActions button { min-width: 40%; }
/* Feiertag: graue Zeile ohne Knoepfe - in Liste, Tag und Kalender-Blatt. */
.feiertagZeile { display: flex; align-items: center; gap: 8px; min-height: 40px; padding: 8px 12px; margin: 4px 0;
  border-radius: var(--r-s); background: var(--surface); color: var(--text-3); font-size: 0.86rem; font-weight: 600;
  border: 1px dashed var(--border-2); }
.feiertagZeile.heuteFeiertag { margin: 0 2px 12px; }
/* Im Monatsraster: die Tageszahl in der Akzentfarbe und ein duenner Ring -
   die Punkte darunter bleiben den Terminen. */
.kalTag.feiertag { color: var(--accent-strong); font-weight: 700; border-color: var(--accent-border); background: var(--accent-bg); }
.kalTag.feiertag.fremd { color: var(--border-2); background: transparent; border-color: transparent; }
.kalTag.feiertag.gewaehlt { color: var(--on-primary); background: var(--primary); }
/* Einstellungen: Zeile mit Auswahlfeld (Bundesland). */
.setZeile.setAuswahl { cursor: default; }
.setZeile.setAuswahl:active { background: var(--surface); }
/* Das Auswahlfeld in einer eigenen Zeile unter dem Text - "Nordrhein-
   Westfalen" und "Mecklenburg-Vorpommern" passen neben den Text nicht. */
.setZeile.setAuswahl { flex-wrap: wrap; row-gap: 8px; }
.setZeile.setAuswahl .setSelect { flex: 1 1 100%; margin-left: 36px; min-width: 0; min-height: 44px; padding: 8px 10px; border-radius: var(--r-s);
  border: 1px solid var(--border-2); background: var(--bg); color: var(--text); font-size: 16px; font-family: inherit; }
/* v3.142.0 (Befund D9): Das Bundesland stand als rohes Auswahlfeld des
   Browsers in den Einstellungen (Haushalt und Dieser Raum) - die einzigen
   beiden, die einheitlich-dom 2 fand, als sie endlich IM Einstellungsfenster
   maß. Umgestaltet wie jedes Feld: eigene Fläche, eigener Rahmen, der Pfeil
   aus zwei Strichen in --muted (hell wie dunkel). Stärker als die Regeln
   darüber, deren `background` das Bild sonst zurücksetzte. */
select.blattSelect, .setZeile.setAuswahl select.setSelect, select.setSelect {
  -webkit-appearance: none; appearance: none; padding-right: 34px;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: right 19px center, right 14px center; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }

/* ============================================================
   v2.23.0: PERSONEN - Farbe je Person, Filter je Person, Punkte-Schalter
   Die Farbe ist immer ein PUNKT, nie Textfarbe: die Palette (personen.js)
   ist frei waehlbar, und Gelb als Schrift waere auf Weiss unlesbar. Der
   feine Rand (--punkt-rand) gibt hellen Farben auf hellem und dunklen auf
   dunklem Grund eine Kante.
   ============================================================ */
:root { --punkt-rand: rgba(0,0,0,.18); }
:root[data-thema="dunkel"] { --punkt-rand: rgba(255,255,255,.28); }
.pPunkt { display: inline-block; width: 10px; height: 10px; border-radius: var(--r-kreis); flex: none; vertical-align: middle;
  box-shadow: var(--ring-innen-1) var(--punkt-rand); margin-right: 5px; }
.pPunkt.gross { width: 18px; height: 18px; margin-right: 0; }
/* Die Punktreihe hinter dem Titel eines Termins */
.pPunkte { display: inline-flex; gap: 3px; margin-left: 7px; vertical-align: middle; }
.pPunkte .pPunkt { width: 9px; height: 9px; margin-right: 0; }
/* Chips: neutraler Grund, Punkt vor dem Namen (vorher: Farbe als Grund, weisse Schrift) */
.teilChip { display: inline-flex; align-items: center; background: var(--surface-2); color: var(--text-2); }
.teilChip .pPunkt { width: 8px; height: 8px; margin-right: 4px; }
.marke.person .pPunkt { width: 9px; height: 9px; margin-right: 4px; }
.fahrZeile .pPunkt { width: 8px; height: 8px; margin-right: 3px; }
.punkteZeile .pName .pPunkt, .pzPerson .pPunkt { width: 9px; height: 9px; margin-right: 4px; }
.pzPerson { display: inline-flex; align-items: center; }
/* v2.34.0: Marke der Raumvariante - klein in der Raumliste und im Kopf,
   gross im Blatt "Raum bearbeiten". Bewusst zurueckhaltend: ein Hinweis,
   kein Etikett, das den Raumnamen ueberstrahlt. */
.raumVariante {
  display: inline-flex; align-items: center; gap: 3px;
  margin-left: 7px; padding: 1px 7px;
  font-size: 0.7rem; font-weight: 600; line-height: 1.6;
  border-radius: var(--r-s); white-space: nowrap;
  background: var(--surface-2); color: var(--muted);
}
.raumVariante.gross { margin-left: 0; font-size: 0.78rem; padding: 3px 10px; }
#raumKopf .raumVarianteKopf { line-height: 1; }
#raumKopf .raumVariante { margin-left: 0; font-size: 0.7rem; padding: 0 6px; }
.raumVarianteZeile { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.raumVarianteSatz { font-size: 0.82rem; color: var(--text-3); flex: 1; min-width: 180px; }

/* v2.33.2: Teilnehmer antippen statt tippen. Die Knoepfe stehen unter dem
   Feld; "an" heisst eingetragen. Deutlich unterscheidbar auch fuer Augen,
   die Farbe schlecht trennen: der eingetragene Knopf hat Rahmen UND
   kraeftigen Grund, nicht nur eine andere Toenung. 34px hoch, damit man
   auf dem Handy nicht danebentippt. */
.teilWahl { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.teilWahl:empty { display: none; }
.teilWahlChip {
  display: inline-flex; align-items: center; gap: 4px;
  min-height: 34px; padding: 4px 11px;
  font-size: 0.82rem; font-weight: 600; line-height: 1.2;
  border: 1.5px solid var(--border-2); border-radius: var(--r-l);
  background: var(--surface-2); color: var(--text-2);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.teilWahlChip .pPunkt { width: 9px; height: 9px; margin-right: 2px; }
.teilWahlChip.an { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.teilWahlChip.an::after { content: "✓"; font-size: 0.82rem; margin-left: 2px; }
.teilWahlChip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Gedimmt: gilt fuer alle, aber nicht "ihr" Eintrag (Termin ohne Teilnehmer,
   Aufgabe ohne Zustaendigkeit) waehrend ein Personen-Filter aktiv ist. */
.item.gedimmt, .kalAufgabe.gedimmt { opacity: .78; }

/* Die Filter-Chips: eine Zeile UEBER den Ansicht-Knoepfen, rollt waagerecht -
   bei zehn Personen passen nicht alle nebeneinander. */
.personenFilter { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; margin: 0 -2px 8px; padding: 2px 2px; }
.personenFilter::-webkit-scrollbar { display: none; }
.personenFilter[hidden] { display: none; }
.pfChips { display: flex; gap: 6px; width: max-content; }
/* v2.97.0 (Sörens Weitergabe von Sarah: "oder kleiner damit alle sofort
   sichtbar sind"): schmaler und etwas kleiner geschrieben - vier statt drei
   Chips passen damit auf ein 390er Display. Die Hoehe bleibt bei 44 px:
   darunter wird die Flaeche zum Antippen unzuverlaessig. */
.pfChip { flex: none; display: inline-flex; align-items: center; gap: 2px; min-height: 44px; padding: 7px 11px; border-radius: var(--r-voll);
  border: 1px solid var(--border-2); background: var(--bg); color: var(--text-2); font: inherit; font-size: 0.82rem; font-weight: 600;
  white-space: nowrap; cursor: pointer; }
.pfChip:active { background: var(--surface-2); }
.pfChip.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.pfChip .pPunkt { width: 10px; height: 10px; margin-right: 5px; }
.pfChip.aktiv .pPunkt { box-shadow: var(--ring-2) var(--on-primary); }

/* Personen-Blatt: Farbpunkt (Knopf), Name, Schalter "Punkte", Entfernen */
.leuteZeile { gap: 6px; }
.pFarbeKnopf { flex: none; width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: none; cursor: pointer; border-radius: var(--r-s); }
.pFarbeKnopf:active { background: var(--surface-2); }
.pFarbeKnopf[aria-expanded="true"] { background: var(--surface-2); }
.pFarbeKnopf.leer { cursor: default; opacity: .5; }
.leuteNeuHinweis { font-size: 0.7rem; color: var(--muted); font-weight: 400; }
.pPunkteSchalter { flex: none; display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 4px 6px 4px 10px;
  border: 1px solid var(--border-2); border-radius: var(--r-voll); background: var(--bg); color: var(--muted); font: inherit; font-size: 0.7rem;
  font-weight: 600; cursor: pointer; }
.pPunkteSchalter.an { color: var(--success-text); border-color: var(--success-border); background: var(--success-bg); }
.pPunkteSchalter .schalterKnauf { flex: none; width: 42px; height: 26px; border-radius: var(--r-voll); background: var(--border-2); position: relative; transition: background .15s; }
.pPunkteSchalter .schalterKnauf::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: var(--r-kreis);
  background: var(--stets-weiss); box-shadow: var(--shadow-1); transition: transform .15s; }
.pPunkteSchalter.an .schalterKnauf { background: var(--success); }
.pPunkteSchalter.an .schalterKnauf::after { transform: translateX(16px); }
/* v3.20.0: zweiter Schalter je Person - "darf Belohnungen genehmigen".
   Er steht in einer eigenen Zeile unter dem Namen, damit die Zeile auf
   dem Handy nicht umbricht. */
.leuteRechtZeile { display: flex; align-items: center; margin: 2px 0 0 34px; }
.pGenehmigtSchalter[disabled] { opacity: .7; cursor: default; }
/* Die Palette unter der Zeile: zehn Farben plus "Standard" */
.pPalette { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 4px 12px 48px; border-bottom: 1px solid var(--border); }
.pPalette[hidden] { display: none; }
.pPalette .pFarbe { width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center; border: 2px solid transparent;
  border-radius: var(--r-m); background: var(--surface); cursor: pointer; }
.pPalette .pFarbe.gewaehlt { border-color: var(--text); }
.pPalette .pFarbe.standard { width: auto; padding: 0 12px; font: inherit; font-size: 0.82rem; font-weight: 600; color: var(--text-2); }
/* v2.97.0: Dieselbe Palette unter "Ansicht" - dort gibt es keinen Farbknopf
   davor, unter dem sie eingerueckt stehen muesste, und keine Zeile darunter,
   von der sie sich abgrenzen muesste. */
#meineFarbePalette { padding: 2px 0 4px; border-bottom: 0; }

/* ============================================================
   v2.26.0: TREFFFLAECHEN >= 44 px (Testerin auf 390x844)
   Eine Playwright-Messung (/tmp/review/harness/knopfgroessen-check.mjs) hat
   auf der Hauptseite, in den Reitern und in den Blaettern unter ⚙️ rund 90
   sichtbare Bedienelemente gefunden, die in einer Richtung unter 44 px lagen
   - meist 38 oder 40 px, das alte Mass. Hier nur Padding/min-height/Breite,
   kein Umbau; die Optik bleibt, die Zeilen werden 4-6 px hoeher.
   Reine Icon-Knoepfe ohne Rahmen (Passwort-Auge, ↩ Antworten, Gruppenkopf-
   Symbol, Datumszeile im Kopf) bekommen den 44er-Kasten mit negativem
   Aussenrand: die Zeile bleibt so hoch wie vorher, nur die Trefffaeche waechst.
   ============================================================ */
/* Ansichts-Umschalter "Liste / Einkaufen / Vorrat", "Liste / Kalender / Tag",
   "Nach Frist / Wichtigkeit", "Dieser Monat / Alle", Heute-Blatt */
.ansichtWahl.schmal button { min-height: 44px; }
.einblendZeile .essenSchalter { min-height: 44px; }

/* v3.13.0 (Sörens Prüfauftrag, "lege doppelte Dinge zusammen"): Jede
   Aufgabe trug ZWEI Wege zum Umsortieren nebeneinander - den Ziehgriff ⠿
   und die Pfeile ▲▼. Auf dem Handy zieht man; die Pfeile sind der Weg für
   Tastatur und Screenreader. Sie bleiben da, wo sie gebraucht werden:
   am Rechner immer, auf einem Touchgerät, sobald die Zeile den Fokus hat.
   Weggenommen wird nichts. */
/* v3.13.0 (Fortsetzung): Weggenommen wird nichts. Wer mit Screenreader
   arbeitet, kann eine Zeile NICHT ziehen - fuer ihn sind die Pfeile der
   einzige Weg. Sie werden auf dem Handy deshalb nur schmaler und ruhiger,
   nicht unsichtbar: der Griff bleibt der Hauptweg, die Pfeile der zweite.
   (Ein display:none haette sie ausserdem unfokussierbar gemacht.) */
@media (hover: none) and (pointer: coarse) {
  /* v3.32.0: .38 machte die Pfeile fast unsichtbar, und die Regel verkleinerte
     sie ausgerechnet auf dem Handy unter 44 px. Sichtbar und treffbar. */
  .dndZeile .reihenBtn { width: 44px; min-height: 44px; color: var(--muted); }
  .dndZeile:focus-within .reihenBtn { color: var(--text); }
}

/* v3.13.0: Notruf als eine Zeile - die Nummern bleiben mit einem Tipp
   erreichbar, nehmen aber nicht mehr den halben Reiter ein. */
.notrufZeile {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin-bottom: 6px; padding: 6px 8px;
  border: 1px solid var(--danger-border); border-radius: var(--r-m); background: var(--danger-bg);
}
.notrufWort { font-size: 0.82rem; font-weight: 700; color: var(--danger); margin-right: 2px; }
.notrufKnopf {
  display: inline-flex; align-items: center; gap: 5px;
  min-height: 44px; padding: 6px 12px;
  border: 1px solid var(--danger-border); border-radius: var(--r-voll); background: var(--bg);
  text-decoration: none; color: var(--danger); font-weight: 800; font-size: 0.92rem;
}
.notrufKnopf:active { background: var(--danger-border); }
.notrufDetails { margin: 0 0 14px; }
.notrufDetails summary { min-height: 36px; display: flex; align-items: center; font-size: 0.82rem; color: var(--text-3); cursor: pointer; }
/* v3.142.0 (Befund D9): 36 px hoch und - weil display:flex den Marker des
   Browsers unterdrückt - ohne Pfeil; niemand sah, dass sich hier etwas
   aufklappen lässt. Jetzt 44 px und derselbe Pfeil wie im Programm der
   Feier und im Logbuch (▸ zu, ▾ auf). */
.notrufDetails summary { min-height: 44px; list-style: none; }
.notrufDetails summary::-webkit-details-marker { display: none; }
.notrufDetails summary::before { content: "▸"; margin-right: 8px; }
.notrufDetails[open] summary::before { content: "▾"; }
.notrufErklaerZeile { font-size: 0.82rem; margin: 3px 0; color: var(--text-2); }
.notrufErklaerZeile .leise { color: var(--muted); }

/* v3.157.0 (Beta „notdienst“, Sören: „Apotheken Notdienst immer die nächste
   Notdienst apotheke in den kontakten ganz oben. Genaus die nächste notdienst
   praxis. …“): die Notdienste unter der Notruf-Zeile (public/kontakte.js
   ktNotdienstHtml). Eine Karte mit zwei Zeilen wie zwei Kontakte - die
   Zeile öffnet die Karte, 📞 daneben ruft an, jede Fläche mindestens 44 px.
   Ruhig gehalten: Rot gehört dem Notruf darüber, Grün nur dem „jetzt“. */
.ndKarte { margin: 0 0 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); overflow: hidden; }
/* v3.165.0 (Sören: „Bessere ersichtlichkeit welcher ort gerade genutzt
   wird? Die hässlichen emojis weg?“): Der Kopf nennt den Ort groß als Wort,
   davor das Linien-Zeichen der Art (Haus, Koffer, Nadel); darunter die
   Reise oder „und Umgebung“, ohne Netz der Stand. */
.ndKopf { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px 6px; }
.ndKopfZeichen { flex: none; width: 24px; display: flex; justify-content: center; padding-top: 2px; color: var(--accent-strong); }
.ndKopfText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ndKopfWas { font-size: 0.78rem; font-weight: 700; color: var(--muted); }
.ndKopfOrt { font-size: 1.05rem; font-weight: 800; line-height: 1.3; color: var(--text); overflow-wrap: anywhere; }
.ndStand { font-size: 0.78rem; font-weight: 700; color: var(--warn-text); }
/* v3.158.0 (Sören: „Die notdienst suche muss auch im Urlaub funktionieren?“):
   unter der Überschrift die anderen Orte zum Umschalten (Zuhause, Reise,
   Hier) - je Knopf eine Zeile, ein langer Reisetitel endet mit „…“. */
/* v3.165.0: ein Umschalter aus Wörtern („Zuhause | Reise | Hier“), alle
   Orte, der geltende gefüllt (aria-pressed) - statt nur der anderen Orte
   als Emoji-Knöpfe. Wird es eng (320 px, lange Reisetitel), brechen die
   Teile um; ein langer Titel endet mit „…“. */
.ndOrte { display: flex; flex-wrap: wrap; gap: 2px; margin: 2px 12px 10px; padding: 2px; border: 1px solid var(--border-2); border-radius: var(--r-voll); background: var(--bg); }
.ndOrt {
  flex: 1 1 0; min-width: 0; max-width: 100%; min-height: 44px; padding: 0 12px; border: 0; border-radius: var(--r-voll);
  background: transparent; color: var(--accent-strong); font-size: 0.82rem; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ndOrt:active { background: var(--surface-2); }
.ndOrt[aria-pressed="true"] { background: var(--primary); color: var(--on-primary); cursor: default; }
.ndUnter { font-size: 0.78rem; color: var(--muted); }
.ndHinweis { padding: 0 12px 6px; font-size: 0.82rem; color: var(--warn-text); }
/* v3.160.0 (Beta „gruppe-auf-zeit“, werbung/PLAN-JGA-RAUM.md): der Block
   „Gruppe auf Zeit“ in „Raum bearbeiten“ (gruppe.js) - Restzeit, Link,
   wer dabei ist. Gebaut aus .haushaltWahl, damit er aussieht wie die Blöcke
   daneben. */
.grSatz { font-size: 0.86rem; line-height: 1.45; color: var(--text-2); margin-bottom: 4px; }
.grBlock .grUnter { margin-top: 12px; }
.grKnoepfe { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 6px; }
.grKnoepfe .grKnopf { flex: 1 1 auto; min-height: 44px; }
.grLink { font-size: 0.82rem; color: var(--text-2); overflow-wrap: anywhere; background: var(--bg);
  border: 1px solid var(--border); border-radius: var(--r-s); padding: 8px 10px; user-select: all; -webkit-user-select: all; }
.grLeute { list-style: none; margin: 4px 0 6px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.grPerson { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.grName { min-width: 0; font-size: 0.92rem; font-weight: 600; overflow-wrap: anywhere; }
.grPerson .grKnopf { flex: none; min-height: 44px; }
.grBlock .grKi { margin-top: 10px; }
.ndReihe { display: flex; align-items: stretch; }
.ndReihe + .ndReihe { border-top: 1px solid var(--border); }
.ndZeile {
  flex: 1; min-width: 0; min-height: 44px; display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 12px; color: var(--text); text-decoration: none;
}
.ndZeile:active, .ndTel:active { background: var(--surface-2); }
.ndSymbol { flex: none; width: 24px; display: flex; justify-content: center; padding-top: 1px; color: var(--accent-strong); }
/* v3.165.0: der Punkt vor „Notdienst bis …“ und dem Öffnungsstatus der
   Praxis - gezeichnet statt 🟢/🟡/🔴, in der Farbe des Worts daneben. */
.ndPunkt { display: inline-block; width: 8px; height: 8px; margin-right: 6px; border-radius: var(--r-voll); background: currentColor; vertical-align: 1px; }
.ndStatus { font-size: 0.82rem; font-weight: 700; color: var(--muted); }
.ndStatus[data-art="offen"] { color: var(--ok); }
.ndStatus[data-art="gleich"] { color: var(--warn-text); }
.ndFinderZeichen { display: inline-flex; }
.ndInline { display: inline-flex; vertical-align: -2px; }
.ndText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ndArt { font-size: 0.78rem; color: var(--muted); }
.ndName { font-size: 0.92rem; font-weight: 700; line-height: 1.35; overflow-wrap: anywhere; }
.ndJetzt { font-size: 0.82rem; font-weight: 700; color: var(--ok); }
.ndInfo { font-size: 0.82rem; color: var(--muted); line-height: 1.4; overflow-wrap: anywhere; }
.ndWeiter { font-size: 0.82rem; font-weight: 700; color: var(--accent-strong); }
.ndTel {
  flex: none; width: 52px; min-height: 44px; display: flex; align-items: center; justify-content: center;
  border-left: 1px solid var(--border); color: var(--accent-strong); text-decoration: none;
}
.ndFuss { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 12px; border-top: 1px solid var(--border); }
.ndFinder {
  flex: 1 1 auto; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 44px; padding: 0 14px;
  border: 1px solid var(--border-2); border-radius: var(--r-voll); background: var(--bg);
  color: var(--accent-strong); font-size: 0.82rem; font-weight: 700; text-decoration: none;
}
.ndQuelle { padding: 0 12px 10px; font-size: 0.78rem; color: var(--muted); }
.ndLaden { padding: 10px 12px; font-size: 0.82rem; color: var(--muted); }
/* v3.165.0 (Sören im Flugmodus: „Nichts funktioniert in Kontakte“): über
   der Liste, wenn sie aus dem Gerät kommt - von wann, und dass Ändern Netz
   braucht. */
.ktOffline { margin: 0 0 12px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); font-size: 0.82rem; line-height: 1.45; color: var(--text-2); }

/* v3.13.1: Der leere Chat sagt jetzt, was man hier tun kann. */
#chatLeer { margin: 24px auto; padding: 0 6px; max-width: 340px; text-align: center; }
.chatLeerTitel { font-size: 1.05rem; font-weight: 700; color: var(--text); margin-bottom: 6px; }
.chatLeerText { font-size: 0.86rem; line-height: 1.5; color: var(--text-2); }
.chatLeerBeispiele { display: flex; flex-direction: column; gap: 8px; margin: 14px 0 8px; }
.chatLeerBeispiel {
  min-height: 44px; padding: 10px 14px;
  border: 1px solid var(--border); border-radius: var(--r-voll); background: var(--surface);
  font: inherit; font-size: 0.86rem; color: var(--text); cursor: pointer;
}
.chatLeerBeispiel:active { background: var(--border); }
.chatLeerFuss { font-size: 0.78rem; color: var(--text-3); }

/* v3.13.3 (Prüfdurchgang): Fünf Aufwand-Stufen (★ bis ★★★★★) passen bei
   390 px nicht nebeneinander - die letzte lief aus dem Blatt hinaus. Das
   Segment darf jetzt schmaler werden und, wenn es eng wird, seitlich
   rollen; die Treffergröße von 44 px bleibt. */
/* v3.98.0: Die drei Regeln fuer #bPunkte sind WEG. Sie stammen aus der
   Zeit, als der Aufwand ein Segment aus fuenf Sternknoepfen war, das
   waagerecht scrollen musste. Seit dem Umbau ist #bPunkte eine Leiter -
   und "#bPunkte button { flex: 1 1 auto }" hat als ID-Regel (1,0,1) den
   Baustein .bsStufe (0,1,0) geschlagen: Die Sternstufen wuchsen auf 39 px
   und fuellten die Huelle, waehrend die Balkenstufen bei 28 px blieben.
   Der erste Stern begann dadurch 7 px weiter rechts als der erste Strich -
   Soeren: "die leiter und die sterne sollen ab der gleichen höhe
   anfangen". Genau die Bauart, gegen die app-bausteine.css steht. */
/* Segmente in den Formularen und Bearbeiten-Blaettern (Wichtigkeit, Aufwand, Zustaendig) */
.segment button, .addForm .segment button { min-height: 44px; min-width: 44px; }
/* Laden-Chips im Anlege-Formular und die uebrigen Chip-Knoepfe.
   v3.99.0: „.ladenWahl .ladenChip" ist raus - der Laden-Chip IST jetzt ein
   .bsWahlChip und bringt seine 44 px selbst mit. Mit zwei Schritten (0,2,0)
   hätte die Regel den Baustein (0,1,0) geschlagen; einheitlich-dom 5 hat
   genau das gemeldet. Die übrigen Chips ohne Baustein behalten sie. */
.gerichtChip, .essenChip, .vorratChip, .ladenChip, .gFilter, .vfChip, .ideenTabs button,
.antwortZurueck .undoBtn, .andererLadenFeld { min-height: 44px; }
/* Chat: 👍/👎, Rueckgaengig in der Systemzeile, ✕ der Antwortleiste */
.feedbackRow button { min-height: 44px; }
.systemNote button.undoBtn { min-height: 44px; }
#antwortLeiste .antwortWeg { width: 44px; height: 44px; }
/* Erstbesuch-Streifen ueber dem Eingabefeld */
#sagenHinweis .sagenHinweisKnopf { min-height: 44px; }
#sagenHinweis .sagenHinweisWeg { width: 44px; height: 44px; }
/* ↩ Antworten an jeder Nachricht: 44er-Kasten, aber die Meta-Zeile bleibt
   so hoch wie vorher (negativer Rand oben/unten). Kein Rahmen, kein
   Hintergrund - sichtbar aendert sich nichts. */
.bubble .antwortenBtn { display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0; margin: -14px -8px -14px 0; vertical-align: middle; }
/* Familie & Zugaenge: Auge/Kopieren am Passwort, Entfernen/Sperren/Loeschen, Kaestchen */
.pwAugeBtn, .pwKopierBtn { display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0; margin: -10px -6px; }
#frageText .pwKopierBtn { display: block; margin: 0 auto; min-height: 44px; }
/* v3.131.0: „↗ Teilen“ und „⧉ Text kopieren“ untereinander, nicht aneinander */
#frageText .pwKopierBtn + .pwKopierBtn { margin-top: 8px; }
.kickBtn, .loeschBtn, .andereGast button { min-height: 44px; }
.gastZeile .loeschBtn { width: 44px; min-width: 44px; flex: none; }
#gaesteView label.aiToggle { min-height: 44px; }
#gaesteView label.aiToggle input, .haushaltWahl input, #pushAuchOffen input { width: 22px; height: 22px; }
.haushaltWahl label { min-height: 44px; }
/* Blaetter: ✕ oben rechts, Loeschen im Archiv, Selbsttest im Mitteilungs-Blatt */
.archivEintrag .archivDelBtn { min-height: 44px; }
#pushSelbsttest button, #wischMeldung button, #updateBanner button, #ladenBanner button, .dubKnopf { min-height: 44px; }
#editModalFields .lernZeile button { min-width: 44px; min-height: 44px; }
/* Aufgaben: Zeilentext, Sortier- und Reihen-Knoepfe, "+ Neue" Checkliste */
.item.aufgabe .gText { min-height: 44px; }
.gSort button, .erledigtZeile button, .planWeg, .planZeile .planSchieben, .bstMenu { width: 44px; height: 44px; min-height: 44px; }
.reihenBtn { width: 44px; }
.checklisteNeuBtn { min-height: 44px; padding: 4px 14px; }
/* Besorgungen: Gruppenkopf-Symbol "Als Checkliste" - 44er-Kasten im 48er Kopf */
.gruppeZuCk { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; margin: -12px -8px -12px 0; }
/* Termine: Zeile, Kalender-/Loeschknopf, Vergangene, Tag-Knoepfe */
.item.terminZeile .calBtn, .item.terminZeile .del { width: 44px; height: 44px; }
/* v3.142.0, Nachbesserung: an der Klasse, nicht am vorgelesenen Namen - der
   heißt jetzt wie die Zeile („Zahnarzt, Di 06.10., 10:00 – Termin
   bearbeiten“, app-termine.js terminZeileName). Am Wortlaut hing sonst die
   44-px-Fläche (gemessen: 42 px, einheitlich-dom 3). */
.item.terminZeile .terminKnopf { min-height: 44px; display: flex; flex-direction: column; justify-content: center; }
.vergangeneKopf, .vfAuf, .zlAuf, .punkteZeileKopf, .vkKnoepfe button, .essenTagKnopf, .essenLeiste button { min-height: 44px; }
.tagKnoepfe button:not(.essenTagKnopf) { min-height: 44px; border: 1px dashed var(--border-2); border-radius: var(--r-s); background: transparent; color: var(--text-2); font-size: 0.82rem; font-weight: 600; }
.wsKopf button { height: 44px; }
/* Kopfzeile: die Datumszeile ("Sa, 05.09. · KW 36") ist ein Knopf zu heute -
   12 px hoch. 44er-Kasten, die Kopfzeile bleibt gleich hoch. */
/* v3.33.0 (Prüfung C37 und eine Messung im Browser): Die 44-px-Trefferfläche
   der 12-px-Datumszeile ragt über negative Ränder aus ihrer Zeile heraus.
   Nach oben ist das harmlos - dort steht nur der Raumname, kein Knopf. Nach
   unten lag sie über der Reiterleiste, und die Reiter waren dort nur 42 statt
   50 px treffbar. Die Fläche darf bleiben, aber die Reiter gehören darüber,
   deshalb liegt #tabs jetzt eine Stufe höher im Stapel (Zeile 279).
   Die Zeile selbst bleibt kompakt, sonst wächst der ganze Kopf um 27 px. */
#raumKopf .raumDatum { min-height: 44px; padding: 0 8px; margin: -16px 0 -14px; display: inline-flex; align-items: center; position: relative; z-index: 1; }
/* Die unsichtbaren Hit-Bereiche aus v2.10.6 (40 px) ziehen mit auf 44 px. */
.ckKnopf::before, .gMarke::before, .kalHaken::before, .item .del::before, .item .calBtn::before { width: 44px; height: 44px; }

/* v2.28.0: Adressen im Fließtext (Chat, Gedanken, Notizen). Unterstrichen
   statt nur farbig - Farbe allein ist für Farbenblinde kein Hinweis. Lange
   Adressen dürfen umbrechen, sonst schiebt eine URL die ganze Zeile auf. */
.textLink {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  word-break: break-word;
  overflow-wrap: anywhere;
}
/* v3.32.0: stand weiß auf der hellgrünen eigenen Blase, 1,19:1. */
.bubble.own .textLink { color: var(--text); text-decoration-color: var(--text-3); }

/* ============================================================
   v2.28.0: Der Ideen-Raum hat EINEN Reiter "Gedanken" mit drei
   Stellungen (Liste · Bausteine · Phasen), Filter-Chips im Stil der
   Personen-Chips und ruhige Zeilen ohne Bedienelemente.
   ============================================================ */

/* Der Umschalter: ein Segment ueber die volle Breite, damit die drei
   Stellungen gleich gewichtet sind - keine davon ist ein Sonderfall. */
.ideenAnsicht { display: flex; gap: 6px; margin: 0 0 6px; }
.ideenAnsicht button {
  flex: 1 1 0; min-width: 0; min-height: 44px; padding: 0 8px;
  border: 1px solid var(--border-2); background: var(--bg); color: var(--text-2);
  border-radius: var(--r-voll); font: inherit; font-size: 0.92rem; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer;
}
.ideenAnsicht button:active { background: var(--surface-2); }
.ideenAnsicht button.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

/* Die zweite Reihe (Offen/Alle · Sortieren · Alle auf) erbt die Pillen-Optik
   von .ideenTabs. 40 px waren zu klein fuer einen Daumen - jetzt 44. */
.ideenTabs button { min-height: 44px; }
.ideenTabs.ideenZweite { padding-bottom: 6px; margin-bottom: 0; }
.ideenTabs .sortierBtn { margin-left: auto; border-style: dashed; color: var(--text-3); }
.ideenTabs .sortierBtn.aktiv { background: var(--accent); border-color: var(--accent); border-style: solid; color: var(--auf-farbe); }
.ideenTabs .aufzu { color: var(--text-3); }

/* Filter-Chips: eine Reihe je Merkmal, waagerecht rollend - genau wie die
   Personen-Chips (.pfChip, .pfChips, .pPunkt aus dem Personen-Block). */
.ideenFilterReihe { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; margin: 0 -2px 6px; padding: 2px; }
.ideenFilterReihe::-webkit-scrollbar { display: none; }
.ideenFilterReihe .pfChip { font-size: 0.82rem; }
.ideenFilterReihe .pfChip .pPunkt { width: 10px; height: 10px; border-radius: var(--r-xs); display: inline-block; margin-right: 6px; box-shadow: var(--ring-1) var(--border-2); }
.ideenFilterReihe .pfChip.aktiv .pPunkt { box-shadow: var(--ring-2) var(--on-primary); }

/* Die flache Liste: EINE Karte statt sechs Gruppenkarten. */
.gListe.flach { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-m); overflow: hidden; margin-bottom: 10px; }
.gListe.flach > .gedanke:first-child { border-top: none; }

/* Leere Gruppen: eine schmale Sammelzeile am Ende statt fuenf leerer Karten. */
.leerSammel {
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px;
  padding: 8px 14px; margin: 0 0 10px; text-align: left;
  border: 1px dashed var(--border-2); border-radius: var(--r-m); background: transparent;
  color: var(--muted); font: inherit; font-size: 0.82rem; cursor: pointer;
}
.leerSammel:active { background: var(--surface); }
.leerSammel .lsPfeil { flex: none; color: var(--muted-2); }
.leerSammel .lsLabel { flex: none; font-weight: 700; color: var(--text-3); }
.leerSammel .lsNamen { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Phasen lassen sich jetzt genauso zuklappen wie Bausteine. */
.phase.zu .bstBody { display: none; }
.phase .bstPfeil { align-self: flex-start; }

/* Ruhige Zeile: Griff und Pfeile gibt es nur im Sortier-Modus. Dort hebt
   sich die Liste ab, damit klar ist, dass gerade sortiert wird. */
.gListe.dndLaeuft, .gedanke.sortierbar { touch-action: pan-y; }
.gListe > .gedanke.sortierbar { background: var(--surface); }

/* Notiz-Seite: erst lesen (Adressen anklickbar), dann bearbeiten. */
.notizLese {
  min-height: 40vh; min-height: 40dvh; padding: 12px 14px; margin-top: 0;
  border: 1px solid var(--border); border-radius: var(--r-s); background: var(--surface);
  font-size: 1rem; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere;
}
.notizEditBtn { width: 100%; min-height: 44px; margin-top: 10px; }

/* Trefferflächen im Ideen-Raum auf 44 px. Das ⋯ am Baustein/an der Phase
   war 40×40, die Sortier-Pfeile 26×22 - beides zu klein für einen Daumen.
   Die Pfeile stehen nur im Sortier-Modus, deshalb darf die Zeile dort
   höher werden; die ruhige Zeile bleibt schmal. */
.bstMenu { width: 44px; height: 44px; }
.gedanke .reihenKnoepfe { gap: 4px; }
.gedanke .reihenBtn { width: 44px; min-height: 44px; font-size: 0.82rem; }

/* ============================================================
   v2.29.0: TEILEN, RAUMNAME IM ZUGANGS-PANEL, MITTEILUNGEN JE RAUM
   ============================================================ */

/* Vier Knöpfe passen auf 390 px nicht mehr neben den Namen. Name und
   Passwort stehen deshalb über der Knopfreihe, die Reihe darf umbrechen.
   „Teilen“ ist die einzige nicht-graue Aktion - sie ist die, die man sucht. */
.gastZeile { flex-wrap: wrap; align-items: flex-start; }
.gastZeile .gastWer { flex: 1 1 100%; min-width: 0; }
.gastZeile .gastKnoepfe { flex: 1 1 100%; flex-wrap: wrap; justify-content: flex-end; }
.teilenBtn {
  min-height: 44px; border: 1px solid var(--accent); color: var(--accent); background: var(--bg);
  border-radius: var(--r-s); padding: 8px 14px; font-weight: 700; font-size: 0.82rem; white-space: nowrap;
}
.teilenBtn:active { background: var(--accent-bg); }

/* Der ruhige Satz unter dem Namensfeld - er beantwortet die Frage, die beim
   Tippen aufkommt, ohne zu warnen. */
.zugangHinweis { font-size: 0.78rem; color: var(--muted); line-height: 1.4; margin: -2px 2px 0; }
.gruppeHinweis { font-size: 0.78rem; color: var(--muted); line-height: 1.4; margin: 0 0 6px; }

/* Teilen-Blatt (kein Teilen-Menü vorhanden): der fertige Text zum Nachlesen
   und ein zweiter Anlauf für die Zwischenablage. overflow-wrap, weil in dem
   Text lange Adressen stehen. */
.teilenHinweis { display: block; font-size: 0.82rem; color: var(--text-2); line-height: 1.4; margin-bottom: 8px; }
.teilenText {
  display: block; max-height: 42vh; max-height: 42dvh; overflow: auto; margin: 0 0 10px;
  padding: 10px 12px; background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--r-s);
  font-size: 0.82rem; line-height: 1.45; color: var(--text); text-align: left;
  white-space: pre-wrap; overflow-wrap: anywhere; user-select: text; -webkit-user-select: text;
}
.teilenBtnBlatt { display: block; width: 100%; margin: 10px 0 4px; }
.teilenUnter { display: block; font-size: 0.78rem; color: var(--muted); line-height: 1.35; }

/* Mitteilungen je Raum: eine Zeile je Raum, Kästchen rechts. Die ganze
   Zeile ist die Trefffläche (das <label> schaltet mit), deshalb 52 px. */
/* Alles unter #editModalFields, weil dort jedes <label> auf Block und jedes
   <input> auf 44 px Hoehe gesetzt ist - ohne diese Genauigkeit bricht die
   Zeile um und das Kaestchen wird zum Kachelknopf.
   v2.32.0: #pushBody kommt dazu - die Liste steht jetzt als Abschnitt in der
   Mitteilungs-Seite, das Blatt daneben gibt es nicht mehr. */
#editModalFields .rmKopf, #pushBody .rmKopf { font-size: 0.82rem; color: var(--text-2); line-height: 1.45; margin: 0 0 2px; }
#editModalFields .rmListe, #pushBody .rmListe { display: flex; flex-direction: column; gap: 8px; }
#editModalFields .rmZeile, #pushBody .rmZeile {
  display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 8px 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-s); cursor: pointer;
  font-size: 0.92rem; font-weight: 400; color: var(--text);
}
#editModalFields .rmZeile:active, #pushBody .rmZeile:active { background: var(--surface-2); }
#editModalFields .rmZeile .rmSym, #pushBody .rmZeile .rmSym { flex: 0 0 auto; width: 24px; text-align: center; font-size: 1.15rem; }
#editModalFields .rmZeile .rmTxt, #pushBody .rmZeile .rmTxt { flex: 1; min-width: 0; }
#editModalFields .rmZeile .rmName, #pushBody .rmZeile .rmName { display: block; font-size: 0.92rem; font-weight: 600; color: var(--text); }
#editModalFields .rmZeile .rmUnter, #pushBody .rmZeile .rmUnter { display: block; font-size: 0.78rem; font-weight: 400; color: var(--muted); margin-top: 1px; }
#editModalFields .rmZeile .rmBox, #pushBody .rmZeile .rmBox {
  flex: 0 0 auto; width: 26px; height: 26px; min-height: 26px; margin: 0; padding: 0;
  border-radius: var(--r-xs); accent-color: var(--success);
}
#editModalFields .rmMeldung, #pushBody .rmMeldung { min-height: 18px; font-size: 0.82rem; color: var(--text-3); line-height: 1.4; }
#editModalFields .rmMeldung.nok, #pushBody .rmMeldung.nok { color: var(--danger); font-weight: 600; }

/* Ohne Abo kein leeres Blatt, sondern der Grund und der Weg dorthin. */
#editModalFields .rmAus, #pushBody .rmAus {
  padding: 12px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-s);
  font-size: 0.86rem; color: var(--text-2); line-height: 1.45;
}
#editModalFields .rmAus b, #pushBody .rmAus b { display: block; color: var(--text); margin-bottom: 4px; }
#editModalFields .rmWeg, #pushBody .rmWeg { font-size: 0.78rem; color: var(--muted); line-height: 1.4; }

/* ============================================================
   v2.31.0: EVENT-RAUM – Kopf · Gäste · Mitbringen · Kosten · Mengen
   Baut auf den vorhandenen Bausteinen auf (.blockKarte, .blockKopf,
   .blockLeer, .betrag) und ergänzt nur, was eine Feier eigen hat: die
   Kopfzeile mit der Kopfzahl, Status-Chips zum Durchtippen, den
   Vergleich mehrerer Angebote nebeneinander und den Mengenrechner.
   Alles auf 390 px gerechnet; nichts unter 44 px.
   ============================================================ */

/* ============================================================
   Die Ansichten des Event-Raums rollen wie die vorhandenen Reiter.

   v3.16.0 (Sören: "Der Reiter Feier im Partyraum öffnet sich immer noch im
   Fenster"): "#eventPlanView" FEHLTE in dieser Regel - als einzige der
   vier. Der Reiter "Feier" konnte deshalb nicht rollen: Was nicht auf den
   Bildschirm passte, war schlicht nicht erreichbar (body hat
   overflow:hidden, gerollt wird in der jeweiligen Ansicht). Das ist der
   eigentliche Grund, warum dieser Reiter nur aus kurzen Zeilen bestand,
   die ein FENSTER öffneten - das Fenster war die einzige Fläche, die
   rollen konnte. Jetzt rollt der Reiter selbst, und der Inhalt steht da,
   wo er hingehört: auf der Seite.
   ============================================================ */
#eventPlanView, #eventGaesteView, #mitbringenView, #kostenView {
  flex: 1; overflow-y: auto; display: none;
  padding: 12px 12px calc(12px + var(--sab));
}

/* --- Reiterreihenfolge im Event-Raum ---
   Die Leiste steht im DOM in Haushalts-Reihenfolge. Hier bekommt sie die
   Reihenfolge, in der man eine Feier plant: erst wer kommt, dann was
   fehlt, dann was es kostet. */
#tabs.eventReiter #tabEventPlan { order: 1; }
#tabs.eventReiter #tabChat { order: 2; }
#tabs.eventReiter #tabEventGaeste { order: 3; }
#tabs.eventReiter #tabMitbringen { order: 4; }
#tabs.eventReiter #tabTodos { order: 5; }
#tabs.eventReiter #tabListe { order: 6; }
#tabs.eventReiter #tabKosten { order: 7; }
#tabs.eventReiter #tabKontakte { order: 8; }
#tabs.eventReiter #tabGaeste { order: 9; }
/* Die beiden Wisch-Verläufe am Rand der Leiste stehen seit v3.149.0 für
   jeden Raumtyp vor bzw. hinter allen Reitern (#tabs::before/::after,
   order -999/999, oben bei „DIE LEISTE ZUM WISCHEN“) - die eigene Zeile
   der Feier (order 10) war eine zweite Liste und ist weg. */

/* --- Der Kopf: steht über allen Reiter-Inhalten --- */
#eventKopf {
  flex: none; display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 60px; padding: 10px 12px; border: 0; border-bottom: 1px solid var(--border);
  background: var(--surface); text-align: left; font-family: inherit; color: var(--text);
}
#eventKopf:active { background: var(--surface-2); }
#eventKopf .evKopfSymbol { flex: none; font-size: 1.5rem; line-height: 1; }
/* v3.105.0: derselbe Pfeil wie in den Zeilen darunter - nach rechts
   gedreht, weil das Band weiterfuehrt. */
#eventKopf .evKopfPfeil { display: inline-flex; color: var(--muted-2); transform: rotate(90deg); }
#eventKopf .evKopfText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
#eventKopf .evKopfZeile1 { font-size: 0.92rem; font-weight: 700; letter-spacing: -0.01em; }
#eventKopf .evKopfZeile2 { font-size: 0.82rem; color: var(--text-3); }
#eventKopf .evKopfZahl { font-size: 0.78rem; color: var(--muted); font-variant-numeric: tabular-nums; }
#eventKopf .evKopfPfeil { flex: none; color: var(--muted-2); font-size: 1.15rem; }

/* --- Knopfreihen, Hinweise --- */
.evKnopfReihe { display: flex; gap: 8px; margin: 10px 0; }
.evHauptKnopf, .evZweitKnopf {
  flex: 1; min-height: 44px; padding: 10px 12px; border-radius: var(--r-s);
  font-size: 0.86rem; font-weight: 600; border: 1px solid transparent;
}
.evHauptKnopf { background: var(--primary); color: var(--on-primary); }
.evZweitKnopf { background: var(--bg); color: var(--text); border-color: var(--border-2); }
.evZweitKnopf:active { background: var(--surface-2); }
.evHauptKnopf.breit, .evZweitKnopf.breit { flex: 1 0 100%; }
.evHauptKnopf.schmal, .evZweitKnopf.schmal { flex: none; align-self: flex-start; margin-top: 8px; }
.evHinweis { font-size: 0.78rem; color: var(--muted); line-height: 1.45; margin: 2px 2px 10px; }
.evHinweis.leise { margin-top: 12px; color: var(--muted-2); }

/* --- Gäste: Zahlen, Status-Chips, Zähler --- */
.evZahlen { display: flex; gap: 6px; }
.evZahl {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 8px 4px; border-radius: var(--r-s); background: var(--surface);
  border: 1px solid var(--border); font-size: 0.7rem; color: var(--muted);
}
.evZahl b { font-size: 1.15rem; color: var(--text); font-variant-numeric: tabular-nums; }
.evZahl.st-zu { background: var(--success-bg); border-color: var(--success-border); }
.evZahl.st-zu b { color: var(--success-text); }
.evZahl.st-ab { color: var(--muted-2); }
.evZahlenSumme { margin: 6px 2px 0; font-size: 0.78rem; color: var(--text-3); }

.evGastListe { margin-top: 4px; }

/* v2.35.0: Was die Gäste geantwortet haben - unter der Gästeliste, weil es
   dieselbe Frage beantwortet: womit muss ich rechnen. */
.evWuensche { margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--border); }
.evWunschKopf { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-weight: 700; margin-bottom: 4px; }
.evWunschOffen { font-size: 0.7rem; font-weight: 600; color: var(--muted); background: var(--surface-2); border-radius: var(--r-s); padding: 1px 8px; }
.evWunschTitel { margin-top: 14px; font-size: 0.82rem; font-weight: 700; color: var(--text-3); }
.evWunschReihe { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.evWunschChip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: var(--r-m);
  font-size: 0.82rem; font-weight: 600;
  background: var(--surface-2); color: var(--text-2);
}
/* v3.15.0: Die Zahl trägt jetzt ihr Wort ("5 Personen") - eine nackte Zahl
   neben "≈ 11 l" ließ offen, was sie zählt. */
.evWunschZahl {
  min-width: 17px; height: 17px; padding: 0 7px; border-radius: var(--r-s);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.7rem; white-space: nowrap; background: var(--primary); color: var(--on-primary);
}
.evWunschAntworten { font-size: 0.7rem; font-weight: 600; color: var(--muted); white-space: nowrap; }
.evWunschLeer { font-size: 0.82rem; color: var(--muted); }
/* Allergien mit Namen: Der Gastgeber muss wissen, für wen er kocht. Warnfarbe,
   weil hier ein Fehler weh tut - nicht als Schmuck. */
.evAllergieListe { margin-top: 6px; border-radius: var(--r-s); background: var(--warn-bg); border: 1px solid var(--warn-border); padding: 8px 11px; }
.evAllergieZeile { font-size: 0.86rem; color: var(--warn-text); padding: 2px 0; }
.evMusikListe { margin-top: 6px; border-radius: var(--r-s); background: var(--surface); padding: 8px 11px; }
.evMusikZeile { font-size: 0.86rem; padding: 2px 0; border-top: 1px solid var(--border); }
.evMusikZeile:first-child { border-top: 0; }
/* v2.39.0: Der Knopf, hinter dem das Anlege-Formular steckt. Über die
   volle Breite und ruhig - er ist kein Hauptweg, sondern der seltene Fall. */
.raumNeuKnopf {
  display: block; width: 100%; margin-top: 14px; min-height: 46px;
  border: 1px dashed var(--border-2); border-radius: var(--r-m);
  background: none; color: var(--text-3); font: inherit; font-weight: 600; cursor: pointer;
}
.raumNeuKnopf:hover { border-color: var(--muted); color: var(--text); }
/* 23.10.2026 (INFO.md: „Mehr einstellen im Anlege-Formular nur 35 px hoch
   (Regel 44 px)“): 44 px wie jeder Knopf; der Text bleibt mittig in der
   Zeile (kleinkram-dom.mjs R). */
.raumNeuMehr summary { cursor: pointer; font-size: 0.86rem; font-weight: 600; color: var(--text-3); padding: 12px 0; min-height: 44px; box-sizing: border-box; }
.raumNeuMehr[open] summary { margin-bottom: 4px; }
.raumNeuKnoepfe { display: flex; gap: 8px; }
.raumNeuKnoepfe button { flex: 1; }
.raumNeuKnoepfe .raumNeuAb { background: var(--surface-2); color: var(--text-2); }

/* v2.38.0: Der Einladungs-Vermerk je Gast. Drei Zustände, drei Farben -
   "noch nicht eingeladen" ist der einzige, der etwas VON MIR verlangt und
   trägt deshalb die Warnfarbe. */
.evEinladung {
  display: inline-flex; align-items: center; gap: 4px;
  min-height: 30px; padding: 2px 9px; margin-left: auto;
  border-radius: var(--r-m); border: 1px solid transparent;
  font: inherit; font-size: 0.7rem; font-weight: 600;
  cursor: pointer; white-space: nowrap;
}
.evEinladung.offen { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn-text); }
.evEinladung.wartet { background: var(--surface-2); color: var(--text-3); }
.evEinladung.fertig { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); }

/* v2.37.0: Der Reiter "Feier" - die Einrichtung auf einer Seite, in der
   Reihenfolge, in der ein Gast die Einladung liest. */
/* v3.105.0 (Sören: "Feier design passt überhaupt nicht zur neuen
   designsprache"): Die neun Punkte lagen in EINEM grauen Kasten, durch
   Haarlinien geteilt - die Form, die der Rest der App seit v3.100.0
   hinter sich hat. Jetzt traegt jeder Punkt seine eigene Karte, in
   derselben Rundung wie eine Aufgabe oder ein Termin (--r-l = 26 px). */
.evPlanKopf { margin: 4px 0 12px; }
.evPlanKopf h2 { margin: 0 0 3px; font-size: 1.15rem; }
.evPlanStand { font-size: 0.92rem; color: var(--text-2); font-weight: 600; }
.evPlanListe { display: flex; flex-direction: column; gap: 8px; background: none; border-radius: 0; overflow: visible; }
.evPlanZeile {
  display: flex; width: 100%; gap: 12px; align-items: center; box-sizing: border-box;
  padding: 13px 14px; min-height: 64px; border: 0;
  background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
/* NACH der Grundregel oben, nicht davor: Sonst haengt die Flaeche der
   Sprungzeilen an der Spezifitaet statt an der Reihenfolge - genau die
   Falle, die in v3.104.0 einen gewaehlten Tag weiss auf weiss gemalt hat
   (LEITFADEN.md, "Zwei Regeln gleicher Staerke"). */
.evPlanListe > .evPlanZeile, .evPlanBlock {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-l); overflow: hidden;
}
/* Die Marke des Abschnitts - und sie traegt den Zustand. Vorher stand der
   rechts, in derselben Spalte wie der Weiter-Pfeil; man musste raten, was
   das Zeichen gerade meint.
   MARKIERT wird das OFFENE, nicht das Erledigte: Die Kopfzeile sagt "2
   Punkte sind noch offen" - finden muss man also die zwei. Andersherum
   (gefuellt = erledigt) standen bei einer fast fertigen Feier sieben
   laute Kreise auf der Seite und zeigten das, was keine Arbeit mehr
   macht. Gemessen am Bild, nicht geschaetzt.
   34 px ist dieselbe Groesse wie die Personenspur an einem Termin
   (v3.102.0) - eine Sprache ueber beide Reiter. */
.evPlanSymbol { flex: none; width: 34px; height: 34px; border-radius: var(--r-kreis);
  box-sizing: border-box; background: var(--surface-2); color: var(--icon-muted);
  display: grid; place-items: center; }
.evPlanZeile:not(.fertig) .evPlanSymbol { border: 2px solid var(--accent); color: var(--accent); }
.evPlanText { flex: 1; min-width: 0; }
.evPlanName { display: block; font-weight: 600; font-size: 0.95rem; }
/* Der Wert bleibt einzeilig: Sonst wird aus der Übersicht eine zweite
   Liste, und die Übersicht war der Sinn der Seite. */
.evPlanWert { display: block; font-size: 0.82rem; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.evPlanWert i { color: var(--muted); }
/* Rechts steht nur noch die Handlung, nie der Zustand. */
.evPlanHaken { flex: none; display: inline-flex; color: var(--muted-2); }
.evPlanHaken.weiter { transform: rotate(90deg); }
/* ============================================================
   v3.16.0 (Sören: "Der Reiter Feier öffnet sich immer noch im Fenster"):
   Die Felder eines Abschnitts stehen jetzt AUF DER SEITE, direkt unter
   seiner Zeile. Die Feldstile lagen bisher alle unter "#editModalFields" -
   also im Blatt. Hier stehen dieselben Regeln für ".evPlanFelder", damit
   ein Feld auf der Seite genauso aussieht wie im Blatt und nicht wie ein
   nacktes Formular aus dem Netz von 1998.
   ============================================================ */
.evPlanBlock.offen { background: var(--surface-2); border-color: var(--border-2); }
.evPlanBlock.offen > .evPlanZeile .evPlanName { color: var(--accent); }
/* Der Wert darf offen mehrzeilig sein - zugeklappt bleibt er einzeilig. */
.evPlanBlock.offen > .evPlanZeile .evPlanWert { white-space: normal; }
.evPlanFelder { display: flex; flex-direction: column; gap: 10px; padding: 2px 13px 14px; }
.evPlanFelder label { display: block; font-size: 0.78rem; color: var(--text-3); font-weight: 700; }
.evPlanFelder input, .evPlanFelder select {
  width: 100%; box-sizing: border-box; padding: 11px 12px; margin-top: 3px;
  border: 1px solid var(--border-2); border-radius: var(--r-s); min-height: 44px;
  background: var(--bg); color: var(--text); font: inherit; font-size: 16px;
}
.evPlanFelder input[type="checkbox"], .evPlanFelder input[type="radio"] {
  width: 22px; height: 22px; min-height: 0; flex: none; margin-top: 0;
}
/* iOS zeichnet Datums- und Zeitfelder sonst schmaler als ihre Nachbarn. */
.evPlanFelder input[type="date"], .evPlanFelder input[type="time"] { -webkit-appearance: none; appearance: none; }
.evPlanFelder textarea {
  width: 100%; box-sizing: border-box; min-height: 80px; padding: 10px 12px;
  border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: var(--surface); color: var(--text); font: inherit; font-size: 16px; resize: vertical;
}
.evPlanFelder .haushaltWahl label { display: flex; align-items: center; gap: 8px; font-size: 0.92rem; font-weight: 400; color: var(--text); }
.evPlanFelder .evProgMitLabel, .evPlanFelder .evProgMaxLabel { font-weight: 400; font-size: 0.86rem; color: var(--text); }
.evPlanFelder .evKnopfReihe { margin-top: 4px; }

.blockKopf.gross { font-size: 1rem; margin-top: 18px; }
/* v3.111.0: Zeichen und Wort eines Kopfes gehoeren zusammen - .blockKopf
   ist ein Flex mit space-between und wuerde zwei Kinder auseinanderziehen. */
.plKopfWort { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }

/* v2.43.0: Geschenke im Netz suchen - Suchzeile und Trefferliste im Blatt. */
/* v3.10.0 (Sören: "bei Wunsch im Netz suchen, oben hinpacken - sonst muss
   man den Wunsch ja 2 mal tippen"): Die Suche hat kein eigenes Feld mehr,
   sie nimmt den Wunsch von oben. Deshalb steht hier nur noch der Knopf mit
   seinem Hinweis. */
.gsSuchZeile { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.gsSuchZeile .knopfKlein { flex: none; min-height: 44px; padding: 0 14px; }
.gsSuchHinweis { flex: 1; min-width: 120px; margin: 0; }
#gsTreffer { margin-top: 8px; }
.gsTreffer {
  display: block; width: 100%; text-align: left; margin-bottom: 6px;
  padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--r-s);
  background: var(--bg); font: inherit; color: var(--text); cursor: pointer;
}
.gsTreffer:active { background: var(--surface-2); }
.gsTitel { display: block; font-weight: 600; font-size: 0.92rem; }
.gsQuelle { display: block; font-size: 0.7rem; color: var(--accent-strong); margin-top: 1px; }
.gsText { display: block; font-size: 0.82rem; color: var(--text-3); margin-top: 3px; }

/* v2.36.0: Geschenkliste beim Mitbringen. */
.evGeschenke { margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--border); }
.evGeschenkZeile { padding: 10px 0; border-top: 1px solid var(--border); }
.evGeschenkZeile:first-of-type { border-top: 0; }
.evGeschenkZeile.vergeben { opacity: 0.7; }
.evGeschenkName {
  display: flex; width: 100%; gap: 10px; align-items: baseline; justify-content: space-between;
  background: none; border: 0; padding: 0; text-align: left;
  font: inherit; font-weight: 600; color: var(--text); cursor: pointer;
}
.evGeschenkPreis { flex: none; font-weight: 400; font-size: 0.82rem; color: var(--muted); }
.evGeschenkNotiz { font-size: 0.82rem; color: var(--text-3); margin-top: 2px; }
.evGeschenkLink { font-size: 0.82rem; margin-top: 3px; }
.evGeschenkStand {
  margin-top: 6px; font-size: 0.82rem; color: var(--success-text);
  background: var(--success-bg); border: 1px solid var(--success-border);
  border-radius: var(--r-s); padding: 5px 9px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}

/* v2.45.0: Klassiker zum Antippen und die Erinnerungs-Kennzeichnung.
   v3.114.0 (Sören: "Klassiker zu sehr versteckt. Bessere darstellung
   bitte"): Das eingeklappte <details> ist weg - mit ihm der 40-px-Griff,
   der die 44-px-Regel verletzte, und die Prüfung einheitlich-dom 3 konnte
   ihn baubedingt nicht sehen (ein <summary> ist kein <button>). An seiner
   Stelle steht eine offene Reihe aus .evChips; die volle Auswahl liegt in
   einem Blatt und verändert die Höhe des Blocks nicht mehr. */
.evVorschlag { margin-top: 10px; }
.evKlassikerZahl { padding: 1px 7px; border-radius: var(--r-voll); background: var(--surface-2); color: var(--text-3); font-weight: 700; }

/* v3.14.0: Rezept und Zutaten am Gericht der Feier. */
.evPortionKasten {
  margin: 6px 0 2px; padding: 8px 10px;
  border: 1px solid var(--success-border); border-radius: var(--r-s); background: var(--success-bg);
  font-size: 0.86rem; color: var(--success-text);
}
.stZutatZeile { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
#editModalFields .stZutatZeile .stZutatArtikel { flex: 1 1 60%; min-width: 0; margin-top: 0; }
#editModalFields .stZutatZeile .stZutatMenge { flex: 1 1 40%; min-width: 0; margin-top: 0; }
.stZutatWeg {
  flex: none; width: 36px; min-height: 44px; border: 1px solid var(--border); border-radius: var(--r-s);
  background: var(--bg); color: var(--text-3); font-size: 0.92rem; cursor: pointer;
}
.stZutatWeg:active { background: var(--border); }
/* v3.114.0: Nur noch das, was diesen Chip wirklich von der Grundform
   (app.css "EINE CHIP-FORM") unterscheidet - Höhe, Rundung und
   Innenabstand kommen von dort. Vorher war er der einzige Auswahl-Chip der
   App mit 26-px-Ecke und gestricheltem Rand: die elfte Klasse, die aus der
   von Hand gepflegten Aufzählung gefallen war. */
.evKlassikerChip {
  /* Höhe, Rundung, Innenabstand und Schriftgröße kommen aus der Grundform
     weiter unten (eine Wahrheit, nicht zwei) - hier steht nur die Farbe. */
  border: 1px solid var(--border-2); background: var(--bg);
  font-family: inherit; color: var(--text-2);
}
.evKlassikerChip:active { background: var(--surface-2); }
/* Die Tür zur vollen Auswahl - derselbe Chip, nur zurückgenommen. */
.evKlassikerChip.mehr { color: var(--text-3); }
/* v3.115.0: Die selbst gemerkten Getränke - eine Zeile je Getränk, mit
   einem eigenen Weg-Knopf. Nicht als Kreuz im Chip: der hat schon eine
   Aufgabe, und zwei 44-px-Flächen passen nicht in eine Pille. */
.evEigenZeile { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 0; border-top: 1px solid var(--border); }
.evEigenZeile:first-of-type { border-top: 0; }
.evEigenName { font-size: 0.86rem; color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.evEigenWeg {
  flex: none; min-height: 44px; padding: 8px 14px;
  border: 1px solid var(--border-2); border-radius: var(--r-voll); background: var(--bg);
  font-family: inherit; font-size: 0.82rem; color: var(--text-3); cursor: pointer;
}
.evEigenWeg:active { background: var(--surface-2); }
/* Der scharfe Zustand sieht aus wie überall sonst im Haus (blattLoeschen.bereit). */
.evEigenWeg.bereit { background: var(--danger); border-color: var(--danger); color: var(--auf-farbe); }
/* Im Blatt: angetippt heißt ausgewählt, nicht angelegt. */
.evKlassikerChip.gewaehlt { background: var(--primary); border-color: var(--primary); color: var(--on-primary); font-weight: 700; }
.evErinnernMarke { flex: none; font-size: 0.92rem; }
.evGastZeile.erinnern { border-color: var(--warn-border); background: var(--warn-bg); }
.evHinweis.warn { color: var(--warn-text); background: var(--warn-bg); border: 1px solid var(--warn-border); border-radius: var(--r-s); padding: 7px 10px; }

/* v2.42.0: Wer sorgt für Getränke und Essen - die Wahl ganz oben im
   Orga-Reiter, weil sie bestimmt, was die Gäste gefragt werden. */
.evSorge { margin-bottom: 24px; }
.evModusReihe { display: flex; gap: 6px; margin: 8px 0 10px; }
.evModus {
  /* v3.99.0: 44 statt 42 - einheitlich-dom 3. */
  flex: 1; min-height: 44px; padding: 4px 8px;
  border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--bg);
  font: inherit; font-size: 0.82rem; font-weight: 600; color: var(--text-2); cursor: pointer;
}
.evModus.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.evUnterKopf { margin-top: 16px; font-size: 0.82rem; font-weight: 700; color: var(--text-3); }
.evGebrachtListe { margin-top: 6px; border-radius: var(--r-s); background: var(--surface); padding: 8px 11px; }
.evGebrachtZeile { font-size: 0.86rem; padding: 3px 0; border-top: 1px solid var(--border); }
.evGebrachtZeile:first-child { border-top: 0; }
.evGebrachtMenge { color: var(--muted); font-size: 0.82rem; }

/* v3.82.0: Planung der Feier - Tabellen je Gang, Einkaufs-Blatt, Mails. */
.plBlock { margin-bottom: 24px; }
/* v3.121.0 (Sören: "Zu viele Erklärungen auf der ganzen Seite"): Statt
   eines 208 Zeichen langen Satzes die ZAHL selbst - und daneben der Weg zu
   ihrer Herkunft. 1.5rem ist eine bestehende Stufe (die Skala steht bei
   genau 14). Umbruchfähig, damit auf schmalen Geräten nichts drängelt. */
.plGrund { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px; padding: 2px 0 6px; }
.plGrundZahl { font-size: 1.5rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.1; }
.plGrundWort { font-size: 0.86rem; color: var(--text-2); }
.plGrundWarum {
  min-height: 44px; padding: 0; border: 0; background: none; font: inherit; font-size: 0.78rem;
  color: var(--accent); cursor: pointer; text-align: left;
}
.plGrundText { flex: 1 0 100%; font-size: 0.78rem; color: var(--text-3); line-height: 1.45; }
.plTabelle { margin-top: 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); padding: 6px 12px 4px; }
.plTabelleKopf { font-size: 0.82rem; font-weight: 700; color: var(--text-3); padding: 4px 0 2px; }
/* v3.111.0 (Sören, mit einem Bild seiner Feier: "Die Darstellung ist
   nicht besonders schön"): Name, Personenzahl und Menge standen in EINER
   Zeile - Menge als "auto"-Spalte mit nowrap, Name als schrumpfende
   1fr-Spalte mit ellipsis. Bei "94 Flaschen à 0,75 l (7 Kästen + 10)"
   gewann die Menge, und der NAME verschwand ganz: aus "Wasser" wurde ein
   leeres Feld, aus "Alkoholfreies Bier" ein "Alkoholfrei…". Das Einzige,
   was die Zeile identifiziert, war das Erste, was wegfiel.
   Jetzt zwei Zeilen: oben Name und Personen, darunter die Menge ueber die
   ganze Breite. Nichts drueckt mehr etwas anderes weg. */
.plZeile {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 8px; row-gap: 1px; align-items: center;
  padding: 10px 0; border-top: 1px solid var(--border);
}
.plZeile.leer { opacity: 0.7; }
.plZeile.geschaetzt .plMenge { color: var(--muted); font-style: italic; }
.plName {
  min-width: 0; min-height: 44px; padding: 0; border: 0; background: none; text-align: left;
  font: inherit; font-weight: 600; font-size: 0.95rem; color: var(--text); cursor: pointer;
  /* Ein langer Name bricht um, statt abgeschnitten zu werden. */
  white-space: normal; overflow-wrap: anywhere; line-height: 1.25;
}
.plZeile.klein .plName { min-height: 32px; font-weight: 500; font-size: 0.86rem; white-space: normal; }
.plName.still { cursor: default; }
.plPersonen {
  flex: none; min-height: 44px; padding: 0 10px; border: 1px solid var(--border-2); border-radius: var(--radius-s);
  background: var(--bg); font: inherit; font-size: 0.78rem; font-weight: 700; color: var(--text-2); cursor: pointer; white-space: nowrap;
}
/* v3.121.0: Seit der Rechenweg hinter dem Aufklappen liegt, muss die Zeile
   ZEIGEN, dass da etwas ist. Ein Pfeil, der sich dreht - dieselbe Geste
   wie überall sonst in der App. */
/* Als Pseudoelement, nicht als Zeichen im Knopf: So steht der Pfeil nicht
   im Text - weder fuer Vorleser noch beim Kopieren noch in einer Probe,
   die "12 Pers." erwartet. */
button.plPersonen::after {
  content: "⌄"; display: inline-block; margin-left: 5px; color: var(--text-3);
  transition: transform 0.15s ease;
}
button.plPersonen[aria-expanded="true"]::after { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { button.plPersonen::after { transition: none; } }
.plPersonen[aria-expanded="true"] { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.plPersonen.still { border: 0; background: none; min-height: 32px; padding: 0; font-weight: 500; color: var(--text-3); cursor: default; }
/* Die Menge steht unter dem Namen, ueber die ganze Breite - sie ist die
   Auskunft, fuer die man herkommt, und darf umbrechen. */
/* v3.121.0 (Sören: "Können wir die ansicht orga etwas verschlanken? Zu
   viele Erklärungen auf der ganzen Seite"): Die Menge ist das, wofür man
   die Seite aufmacht - sie stand in derselben Größe da wie der Rechenweg
   darunter. Jetzt ist sie das eine Laute der Zeile; alles andere wird
   leiser. 1.3rem ist eine BESTEHENDE Stufe - die Skala steht bei genau 14,
   eine fünfzehnte wäre rot (probe-kontrast).
   Auf eigener Zeile, nicht neben dem Namen: Genau daran ist v3.111.0
   gescheitert, als "94 Flaschen à 0,75 l (7 Kästen + 10)" den Namen
   verdrängte. Die Zeile darf breit sein, nur nicht drängeln. */
.plMenge { grid-column: 1 / -1; font-weight: 700; font-size: 0.95rem; text-align: left; line-height: 1.3; }
.plZeile:not(.klein) .plMenge {
  font-size: 1.3rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.2; padding: 1px 0 2px;
}
/* Aber eine Null ist nichts, worauf man stolz ist: Wo niemand dabei ist,
   bleibt die Zahl leise. Sonst schriee die Leere am lautesten. */
.plZeile:not(.klein).leer .plMenge { font-size: 0.95rem; font-weight: 700; color: var(--text-3); }
.plZeile.klein .plMenge { font-size: 0.86rem; font-weight: 600; }
/* v3.106.0 (Sören: "die menge der essen ist nicht gut gestaltet"): Die
   Rechnung lief als eine Kette durch die Zeile. Jetzt steht jeder Schritt
   auf einer eigenen Zeile - so liest man sie wie eine Rechnung und nicht
   wie einen Absatz. Der Status ("kaufen", "Rezept fuer 4") bleibt in der
   Reihe, er gehoert nicht zum Rechenweg. */
/* v3.121.0: Der Rechenweg steht nicht mehr dauernd da - er beantwortet
   eine Frage, die man selten stellt, und nahm an zehn Zeilen 940 Zeichen
   und 499 px ein (gemessen). Er kommt jetzt mit dem Aufklappen, an dem
   auch schon steht, WER angekreuzt hat: eine Geste, eine Erklärung. */
.plRechnung { grid-column: 1 / -1; font-size: 0.78rem; color: var(--text-3); display: flex; flex-wrap: wrap; gap: 3px 12px; }
.plZeile:not(.klein) .plRechnung { margin-top: 4px; }
.plSchritt { flex: 1 0 100%; }
/* Ab dem zweiten Schritt ein ruhiger Einzug: die Folgeschritte haengen am
   ersten, statt wie gleichrangige Saetze zu wirken. */
.plSchritt + .plSchritt { padding-left: 10px; border-left: 2px solid var(--border); }
.plRechnung.leise { color: var(--muted); font-style: italic; }
.plStatus { color: var(--accent-strong); white-space: nowrap; }
/* v3.112.0 (Sören: "Der kaufen Knopf ist auch versteckt und nicht schön
   beim essen"): Die Kaufzeile steht direkt an der Planungszeile - links
   der Mengensteller aus den Besorgungen (.mengeZeile), rechts der Weg in
   den Warenkorb. Beide mindestens 44 px, beide umbruchfaehig: Auf einem
   schmalen Gerät rutscht der Knopf unter den Steller, statt ihn zu
   quetschen. */
.plKauf { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 6px; }
/* Der Steller traegt nur die ZAHL - die Einheit steht darueber und
   wandert beim Tippen mit. So passt beides in EINE Reihe. */
/* v3.121.0 (gemessen, nicht gesucht): Das Feld war 52 px breit, "25,5"
   braucht 59 - JEDE Kommazahl wurde abgeschnitten und stand als "25,!" da.
   Der Fehler ist aelter als dieser Umbau; aufgefallen ist er erst, als die
   Menge darueber gross wurde und man beide Zahlen nebeneinander sah. */
.plKauf .mengeZeile { flex: 0 0 auto; width: 11rem; min-width: 0; margin: 0; }
.plKauf .mengeZeile .bsFeld { text-align: center; min-width: 0; }
.plKorb {
  flex: 1 1 auto; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 0 14px; border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: var(--surface); color: var(--text); font: inherit; font-size: 0.86rem; font-weight: 600; cursor: pointer;
}
/* v3.119.0 (Sören: "erscheint ein haken in dem Feld auf die liste und wird
   grün … wird das feld orange und es steht aktualisieren drin"): Die drei
   Zustände des Knopfes. Farbe UND Wort ändern sich - wer die Farben nicht
   unterscheidet, liest "Auf der Liste" bzw. "Aktualisieren". */
.plKorb.drauf { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); }
.plKorb.anders { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn-text); }
.plKorb:active { background: var(--surface-2); }
.plWer { grid-column: 1 / -1; font-size: 0.82rem; color: var(--text-2); background: var(--bg); border-radius: var(--radius-s); padding: 6px 9px; }
.plLeer { font-size: 0.86rem; color: var(--muted); font-style: italic; padding: 8px 0; }
.plZeile.offenPos .plMenge { color: var(--warn-text); }
/* Blatt "Einkaufsliste zusammenstellen" */
.ekGruppe { margin-top: 12px; border-top: 1px solid var(--border); padding-top: 8px; }
.ekGruppeKopf { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 0.95rem; }
.ekGruppeMenge { font-size: 0.82rem; color: var(--text-3); }
.ekGruppeWeg { margin-left: auto; min-height: 36px; padding: 0 10px; border: 1px solid var(--border-2); border-radius: var(--radius-s); background: var(--bg); font: inherit; font-size: 0.78rem; color: var(--text-2); cursor: pointer; }
.ekGruppeRechnung { font-size: 0.78rem; color: var(--text-3); margin: 2px 0 4px; }
.ekZeile { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 0; }
.ekZeile.schonDrauf { opacity: 0.75; }
/* v3.110.0: Eine Zeile ohne errechnete Menge ist da, aber nicht
   angehakt - sie tritt zurueck, ohne zu verschwinden. */
.ekZeile.ohneMenge { opacity: 0.85; }
#editModalFields .ekZeile .ekAn { width: 22px; height: 22px; margin: 0 4px 0 0; flex: none; }
#editModalFields .ekZeile .ekArtikel { flex: 1 1 55%; min-width: 0; margin-top: 0; }
#editModalFields .ekZeile .ekMenge { flex: 1 1 30%; min-width: 90px; margin-top: 0; }
.ekLaden { flex: 1 0 100%; font-size: 0.7rem; color: var(--text-3); padding-left: 32px; }
.ekEigene { margin-top: 10px; }
.mailProtokoll { border-radius: var(--radius-s); background: var(--surface); padding: 6px 11px; }
.mailProtokollZeile { font-size: 0.82rem; padding: 3px 0; border-top: 1px solid var(--border); }
.mailProtokollZeile:first-child { border-top: 0; }

/* Programmzeilen im Blatt: Uhrzeit schmal, Text breit. */
.evProgZeile { display: flex; gap: 8px; margin-bottom: 7px; }
.evProgZeile .evProgZeit { flex: 0 0 108px; }
.evProgZeile .evProgText { flex: 1; min-width: 0; }
.evGast {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-m);
  padding: 8px 10px 10px; margin-bottom: 8px;
}
/* v2.42.0: Eine Zeile je Gast, aufklappbar. Zugeklappt: Name, Kopfzahl,
   Antwort. Der Rest kommt beim Aufklappen. */
.evGastZeile {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-m);
  margin-bottom: 6px; overflow: hidden;
}
.evGastZeile > summary {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 10px; min-height: 52px; cursor: pointer; list-style: none;
}
.evGastZeile > summary::-webkit-details-marker { display: none; }
.evGastZeile > summary::after { content: "›"; flex: none; color: var(--muted-2); transition: transform 0.15s; }
.evGastZeile[open] > summary::after { transform: rotate(90deg); }
.evGastKoepfe { flex: none; font-size: 0.82rem; color: var(--muted); white-space: nowrap; }
.evGastInhalt { padding: 0 10px 10px; border-top: 1px solid var(--border); padding-top: 8px; }
.evGastWuensche { margin-top: 8px; font-size: 0.82rem; color: var(--text-3); }
/* v2.46.0: Streichen steht unten und mit Abstand - man soll es nicht auf
   dem Weg zum Notizfeld treffen. */
.evGastStreichen { margin-top: 10px; }
.evGastStreichen .blattLoeschen { width: 100%; }
.evGastWuensche div { padding: 1px 0; }
.evGast.st-ab { opacity: .8; }
.evGast.st-zu { border-color: var(--success-border); }
.evGastKopf { display: flex; align-items: center; gap: 8px; }
.evGastName {
  flex: 1; min-width: 0; min-height: 44px; text-align: left; border: 0; background: none;
  font-size: 1rem; font-weight: 600; color: var(--text); padding: 0; overflow-wrap: anywhere;
}
.evLinkMarke {
  display: block; font-size: 0.7rem; font-weight: 600; color: var(--accent-strong);
}
.evStatusChip {
  flex: none; min-height: 44px; padding: 0 12px; border-radius: var(--r-voll);
  border: 1px solid var(--border-2); background: var(--bg);
  font-size: 0.78rem; font-weight: 700; color: var(--text-2); white-space: nowrap;
}
.evStatusChip.st-zu { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); }
.evStatusChip.st-ab { background: var(--surface-2); color: var(--muted); }
.evStatusChip.st-vielleicht { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn-text); }
/* v3.142.0 (Befund D7 der Prüfung zu Sörens „Suche weiter nach fehlern,
   sicherheitslücken und Design Optimierungen“): Name und Antwort-Pille sind
   Kinder der Flex-Zeile und damit Blöcke mit 44 px Mindesthöhe - ohne
   eigenes Zentrieren klebte der Text 2 px unter der Oberkante, darunter
   25–28 px Luft; „✓ zugesagt“ sah verrutscht aus, der Name stand höher als
   „2 Personen“ daneben. Die Pille zentriert ihren Text, der Name steht mit
   seiner Link-Marke (darunter, display:block) als Gruppe in der Mitte. */
.evStatusChip { display: inline-flex; align-items: center; justify-content: center; }
.evGastName { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; }

/* v2.38.0: flex-wrap + align-items, damit der Einladungs-Vermerk rechts
   sitzt und auf schmalen Geräten umbricht statt die Zähler zu quetschen. */
.evGastZahlen { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 4px; }
.evZaehler {
  flex: 1; display: flex; align-items: center; justify-content: space-between; gap: 2px;
  border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--bg); overflow: hidden;
}
.evZaehlBtn {
  flex: none; width: 44px; min-height: 44px; border: 0; background: none;
  font-size: 1.15rem; color: var(--text-2);
}
.evZaehlBtn:active { background: var(--surface-2); }
.evZaehlWert {
  flex: 1; text-align: center; font-size: 1rem; font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1.05;
}
.evZaehlWert i { display: block; font-size: 0.7rem; font-weight: 600; font-style: normal; color: var(--muted); }
/* v3.12.1: Die Notiz eines Gastes - vollständig lesbar und als seine
   Nachricht erkennbar. Vorher eine einzeilige Zeile, in der ein Satz nach
   60 Zeichen aufhörte. */
.evNotizKasten {
  margin-top: 8px; padding: 8px 10px 6px;
  border: 1px solid var(--border); border-radius: var(--r-s); background: var(--surface);
}
.evNotizKasten.vomGast { border-color: var(--warn-border); background: var(--warn-bg); }
.evNotizKopf { font-size: 0.78rem; font-weight: 700; color: var(--text-2); margin-bottom: 4px; }
.evNotizKasten.vomGast .evNotizKopf { color: var(--warn-text); }
.evNotizKasten.vomGast .evNotizFeld { color: var(--warn-text); }
.evNotizFeld {
  width: 100%; margin: 0; font-size: 16px; line-height: 1.4;
  border: 0; background: none; padding: 0; resize: vertical; min-height: 2.8em;
  color: var(--text); font-family: inherit;
}
.evNotizKasten.leer .evNotizFeld { color: var(--text-2); }
.evNotizMarke { flex: none; margin-left: 4px; font-size: 0.92rem; }

/* --- Auswahl-Blätter (Kontakte, Link verwalten) --- */
.evWahlListe { display: flex; flex-direction: column; gap: 6px; }
.evWahlListe button {
  width: 100%; min-height: 52px; text-align: left; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--r-s); background: var(--surface);
  font-size: 0.92rem; font-weight: 600; color: var(--text);
}
.evWahlListe button:active { background: var(--surface-2); }
.evWahlNeben { display: block; font-size: 0.78rem; font-weight: 400; color: var(--muted); margin-top: 2px; line-height: 1.4; }

/* --- Mitbringen --- */
.evPosStandGesamt { margin: 2px 2px 4px; font-size: 0.78rem; color: var(--muted); }
.evPos {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-m);
  padding: 8px 10px 10px; margin-bottom: 8px;
  display: flex; flex-direction: column; align-items: flex-start;
}
/* Frei und vergeben sollen sich auf einen Blick unterscheiden - nicht nur
   durch Farbe, sondern durch den Balken links und den Satz in der Zeile. */
.evPos.mbFrei { border-left: 3px solid var(--warn); }
.evPos.mbVoll { border-left: 3px solid var(--success); background: var(--bg); }
.evPosKopf { width: 100%; text-align: left; border: 0; background: none; padding: 4px 0; min-height: 44px; }
.evPosTitel { display: block; font-size: 1rem; font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.evPosStand { display: block; font-size: 0.78rem; color: var(--muted); margin-top: 1px; font-variant-numeric: tabular-nums; }
.evPos.mbVoll .evPosStand { color: var(--success-text); }
.evPosNamen { display: block; font-size: 0.82rem; color: var(--text-3); margin-top: 3px; }
.evPosNamen i { font-style: normal; color: var(--muted); }
.evPosNotiz { display: block; font-size: 0.78rem; color: var(--muted); margin-top: 3px; line-height: 1.4; }
.evPosVoll { font-size: 0.78rem; font-weight: 700; color: var(--success-text); margin-top: 8px; }

/* --- Kosten: Budget --- */
.evGeldZeile {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 5px 0; font-size: 0.92rem; color: var(--text-2);
}
.evGeldZeile + .evGeldZeile { border-top: 1px solid var(--border); }
.evGeldZeile > span:last-child { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--text); white-space: nowrap; }
.evGeldZeile.plus > span:last-child { color: var(--success-text); }
.evGeldZeile.minus > span:last-child { color: var(--danger); }
.evGeldGross { font-size: 1.15rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.evGeldNeben { font-size: 0.78rem; color: var(--muted); margin-top: 4px; }
/* Deutlich, aber ruhig: ein Satz auf warmem Grund, kein rotes Ausrufezeichen. */
.evWarnung {
  margin-top: 10px; padding: 9px 11px; border-radius: var(--r-s);
  background: var(--warn-bg); border: 1px solid var(--warn-border);
  color: var(--warn-text); font-size: 0.82rem; line-height: 1.45;
}
.blockKarte.evUeberzogen { border-color: var(--warn-border); }

/* --- Kosten: Angebote nebeneinander ---
   Auf 390 px passt keine Tabelle. Deshalb Spalten, die man seitwärts
   wischt: die nächste Karte schaut ein Stück heraus, damit man sieht,
   dass da noch etwas ist. */
.angVergleich { display: flex; gap: 10px; }
.angVergleich.mehrere {
  overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
  scrollbar-width: none; padding-bottom: 4px;
}
.angVergleich.mehrere::-webkit-scrollbar { display: none; }
.angKarte {
  flex: 1 0 100%; min-width: 0; scroll-snap-align: start;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-m); padding: 10px 12px 12px;
}
.angVergleich.mehrere .angKarte { flex: 0 0 84%; }
.angKarte.st-gebucht { border-color: var(--success-border); }
.angKarte.st-abgelehnt { opacity: .8; }
.angKopf { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  min-height: 44px; border: 0; background: none; padding: 0; text-align: left; }
.angName { font-size: 1rem; font-weight: 700; color: var(--text); overflow-wrap: anywhere; }
.angStatus { flex: none; font-size: 0.7rem; font-weight: 700; padding: 3px 8px; border-radius: var(--r-voll);
  background: var(--surface-2); color: var(--muted); white-space: nowrap; }
.angStatus.st-gebucht { background: var(--success-bg); color: var(--success-text); }
.angStatus.st-angebot { background: var(--accent-bg); color: var(--accent-strong); }
.angPreis { font-size: 1.3rem; font-weight: 800; font-variant-numeric: tabular-nums; margin: 2px 0 8px; letter-spacing: -0.02em; }
.angPreis i { display: block; font-size: 0.7rem; font-weight: 500; font-style: normal; color: var(--muted); letter-spacing: 0; }
.angHinweise { margin: 8px 0 0; padding: 8px 10px 8px 26px; border-radius: var(--r-s);
  background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn-text);
  font-size: 0.78rem; line-height: 1.45; }
.angHinweise li + li { margin-top: 4px; }

/* --- Chips (Inklusive-Wahl im Angebots-Blatt) --- */
.evChips { display: flex; flex-wrap: wrap; gap: 6px; }
.evChip { min-height: 44px; padding: 0 12px; border-radius: var(--r-voll);
  border: 1px solid var(--border-2); background: var(--bg); font-size: 0.82rem; font-weight: 600; color: var(--text-2); }
.evChip.an { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

/* --- Mengenrechner --- */
.mengenKnopf {
  width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  min-height: 52px; padding: 9px 12px; margin-bottom: 10px; text-align: left;
  border: 1px solid var(--border-2); border-radius: var(--r-m); background: var(--surface);
}
.mengenKnopf:active { background: var(--surface-2); }
.mengenKnopfTitel { font-size: 0.92rem; font-weight: 700; color: var(--text); }
.mengenKnopfNeben { font-size: 0.78rem; color: var(--muted); }
.mengenListe { display: flex; flex-direction: column; gap: 6px; }
.mengenZeile {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 48px; padding: 8px 12px; text-align: left;
  border: 1px solid var(--border); border-radius: var(--r-s); background: var(--bg);
}
.mengenZeile.an { background: var(--surface); border-color: var(--border-2); }
.mengenHaken {
  flex: none; width: 26px; height: 26px; border-radius: var(--r-xs); border: 2px solid var(--muted-2);
  display: flex; align-items: center; justify-content: center; font-size: 0.92rem; color: transparent;
}
.mengenZeile.an .mengenHaken { background: var(--success); border-color: var(--success); color: var(--auf-farbe); }
.mengenName { flex: 1; min-width: 0; font-size: 0.92rem; font-weight: 600; color: var(--text); }
.mengenZeile:not(.an) .mengenName { color: var(--muted); font-weight: 400; }
.mengenAlk { font-style: normal; font-size: 0.7rem; font-weight: 600; color: var(--muted);
  border: 1px solid var(--border-2); border-radius: var(--r-voll); padding: 1px 6px; margin-left: 6px; }
.mengenMenge { flex: none; font-size: 0.92rem; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); }
.mengenZeile:not(.an) .mengenMenge { color: var(--muted-2); }
.mengenMerker { margin: 4px 0 0; padding-left: 20px; font-size: 0.86rem; color: var(--text-3); line-height: 1.55; }

/* Drei Raumtypen passen nicht mehr in eine Zeile von 390 px. */
.raumTypWahl { flex-wrap: wrap; }
.raumTypWahl button { flex: 1 1 30%; min-width: 104px; }

/* Eine lange Aufzählung ("Nicht inklusive: Besteck, Gläser, …") passt nicht
   neben ihr Etikett - sie steht darunter und darf umbrechen. */
.evGeldZeile.lang { flex-direction: column; align-items: flex-start; gap: 1px; }
.evGeldZeile.lang > span:last-child { white-space: normal; overflow-wrap: anywhere; font-weight: 600; }

/* v2.59.0: EINHEITLICHE FENSTER (Soerens Wunsch). Jedes Fenster hat oben
   rechts ein X und unten einen grossen "Zurück"-Knopf; Tippen neben das
   Fenster schliesst NICHT mehr (zu oft versehentlich passiert). */
/* ============================================================
   v3.85.0 (Sören: "weiter und zurück buttons ändern ihre position beim
   tippen. Sehr schlechte eigenschaft alles sollte immer auf gleicher höhe
   bleiben"): DIE FUSSZEILE STEHT STILL.

   Die vier Vorschaukarten sind verschieden hoch (das Wochen-Band bringt
   eine Tagesliste mit, das Monatsgitter zwei Zeilen). Dadurch wanderte die
   Fusszeile bei jedem Tipp nach oben oder unten - und weil "Weiter" auf
   der letzten Karte wegfiel, sprang "Zurück" zusätzlich in der Breite.

   Jetzt: Der Rumpf hat eine Mindesthöhe, die die höchste Karte trägt, und
   beide Knöpfe teilen sich die Zeile zu gleichen Teilen - auch der, der
   gerade unsichtbar ist (visibility: hidden hält seinen Platz).
   ============================================================ */
#ansichtBody { min-height: 340px; }
.ansichtFenster .modalActions, #ansichtModal .modalActions { min-height: 56px; align-items: stretch; }
#ansichtModal .modalActions button { flex: 1 1 0; min-height: 48px; font-size: 1rem; }
.modalActions .zurueckBtn { flex: 1 1 0; min-height: 48px; font-size: 1rem; }
.modalActions { justify-content: stretch; }
.modalActions button { flex: 1 1 auto; }
.setKopf .modalX { margin-left: auto; }

/* v2.60.0: Rueckmeldungen */
#rueckModal .modalBox { display: flex; flex-direction: column;
  max-height: min(88vh, calc(100% - 32px)); max-height: min(88dvh, calc(100% - 32px)); }
#rueckBody { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; margin-bottom: 12px; }
.rmKopf { margin-bottom: 10px; }
.rmKnopf { width: 100%; min-height: 44px; border-radius: var(--r-s); border: 1px solid var(--border-2); background: var(--surface-2); color: var(--text); font-weight: 600; margin-bottom: 6px; }
.rmLeise { color: var(--muted); font-size: 0.86rem; line-height: 1.4; margin: 4px 0 8px; }
.rmKarte { border: 1px solid var(--border-2); border-radius: var(--r-m); padding: 10px 12px; margin-bottom: 10px; background: var(--surface); }
.rmKarte.erledigt { opacity: .8; }
.rmKarte.wartet { opacity: .75; pointer-events: none; }
.rmZeile1 { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; font-size: 0.86rem; margin-bottom: 6px; }
.rmArt { font-weight: 700; } .rmVon { color: var(--text-2); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; } .rmZeit { color: var(--muted); }
.rmText { white-space: pre-wrap; overflow-wrap: anywhere; font: inherit; font-size: 0.86rem; line-height: 1.4; margin: 0; max-height: 240px; overflow-y: auto; }
.rmKontext { margin-top: 6px; font-size: 0.86rem; } .rmKontext summary { cursor: pointer; color: var(--accent); font-weight: 600; }
.rmKi { margin-top: 8px; padding: 8px 10px; border-radius: var(--r-s); background: var(--warn-bg); border: 1px solid var(--warn-border); }
.rmKiTitel { font-weight: 700; font-size: 0.86rem; margin-bottom: 4px; }
.rmKnoepfe { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
/* v3.149.0: 44 statt 40 px - der neue Knopf „🖼 Bilder“ steht in dieser Reihe,
   und CLAUDE.md verlangt 44 px für jedes Bedienelement; die Reihe bleibt gleich hoch. */
.rmKnoepfe button { min-height: 44px; padding: 6px 10px; border-radius: var(--r-s); border: 1px solid var(--border-2); background: var(--bg); color: var(--text); font-size: 0.86rem; font-weight: 600; }
.rmKnoepfe button.rmWeg { color: var(--danger); }
/* v3.149.0 (Sören, 06.10.2026: „Bei fehler melden sollte man Screenshots
   anhängen können.“): Bildschirmfotos an einer Rückmeldung (public/rueckmeldung.js).
   Erst auf Tipp geladen, klein in einer Reihe; jedes ist ein Knopf (76 px,
   also über 44 px), der es im Anhang-Betrachter groß zeigt. Dessen Knöpfe
   Herunterladen, Teilen und Entfernen gehören zu Termin-Anhängen - solange
   er ein Bildschirmfoto zeigt (.rmBildGross), blendet die letzte Regel sie
   aus. Leert ihn „Zurück“ (anhangBetrachterZu) oder öffnet er einen
   Termin-Anhang, gilt sie nicht mehr - ohne dass app-termine.js davon weiß.
   Das Fehler-melden-Fenster selbst bringt sein Aussehen in public/melden.js mit. */
.rmBilder { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.rmBild { width: 76px; height: 76px; padding: 0; border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--bild-grund); overflow: hidden; cursor: zoom-in; }
.rmBild img { display: block; width: 100%; height: 100%; object-fit: cover; }
.rmBildLeer { flex: 1 1 100%; font-size: 0.82rem; color: var(--muted); line-height: 1.4; }
#anhangBetrachter:has(.rmBildGross) .abKnoepfe, #anhangBetrachter:has(.rmBildGross) #abNeuerTab { display: none; }

/* v2.64.0: Haushalt einrichten - drei Abschnitte in einem Blatt. */
.einrAbschnitt { border: 1px solid var(--border); border-radius: var(--r-m); padding: 10px 12px 12px; margin-bottom: 12px; background: var(--surface); }
.einrAbschnitt h4 { margin: 0 0 8px; font-size: 0.92rem; }
.einrAbschnitt .blattSelect { width: 100%; }
.einrChip { display: inline-flex; align-items: center; gap: 4px; padding-right: 4px; }
.einrChipWeg { border: none; background: none; color: inherit; opacity: .8; font-size: 0.92rem; min-width: 28px; min-height: 28px; cursor: pointer; padding: 0; border-radius: var(--r-voll); }
/* v3.142.0 (Befund D9): Das ✕ war 28×28 px - ein Finger daneben traf den
   Chip, der nichts tut. Jetzt 44×44 px Trefferfläche; der negative Rand
   nimmt dem Chip genau das wieder weg, was der Knopf größer wurde (der
   Chip ist 44 px hoch, 8 px Polster oben und unten, 4 px rechts). */
.einrChip .einrChipWeg { min-width: 44px; min-height: 44px; margin: -8px -4px -8px -10px; }
.einrChipWeg:active { opacity: 1; }
/* v3.143.0: Der Name im Chip öffnet das Blatt „🏬 Laden“ (Art, Webseite).
   Er nimmt das linke Polster des Chips mit in seine Trefferfläche (44 px
   hoch, wie das ✕ rechts); die Art dahinter steht in normaler Stärke. */
.einrChip .einrChipName { border: 0; background: none; color: inherit; font: inherit; min-height: 44px; margin: -8px 0 -8px -14px;
  padding: 0 0 0 14px; cursor: pointer; text-align: left; border-radius: var(--r-voll); }
.einrChipArt { font-weight: 400; }

/* 23.10.2026 (Sören: „ja essensplan erstmal raus“ – „Reiter ganz
   ausblenden“): Ohne Beta „essensplan“ gibt es den Reiter Essen nicht, und
   der Schalter „Essen“ im Kalender hätte nichts zu schalten. Als CSS, damit
   es beim Umlegen sofort gilt; die Wischfolge liest die Leiste selbst
   (app-gesten.js reiterFolge) und kennt den Reiter dann nicht. Weiche und
   Stellen: public/app-essensplan.js. */
html:not(.beta-essensplan) #tabEssen,
html:not(.beta-essensplan) #ansichtEssen { display: none; }

/* 26.10.2026 (Beta „mealprep-baukasten“, Sören: „… wählt man die
   grundzutaten aus und er baut daraus mindestens 7 gerichte …“): der Knopf
   im Reiter Essen und das Blatt (public/baukasten.js). Ohne die Beta ist
   die Zeile weg; den Reiter selbst gibt es nur mit „essensplan“ (oben). */
html:not(.beta-mealprep-baukasten) #baukastenLeiste { display: none; }
.baukastenGruppe { margin-top: 8px; }
.baukastenGruppe .gerichtChip { min-height: 44px; }
.gerichtChip.aktiv { background: var(--accent-bg); border-color: var(--accent-border); color: var(--accent); }
.essenChips .essenChip[data-bk-plus], .essenChips .essenChip[data-bk-mehr] { min-height: 44px; }
.baukastenGericht { display: block; padding: 8px 0; min-height: 44px; border-bottom: 1px solid var(--border); }
.baukastenGericht input { width: 20px; height: 20px; vertical-align: middle; margin-right: 6px; }

/* v2.65.0: Beta-Kennzeichnung (bis 23.10.2026 am Reiter Essen; seither
   trägt ihn nur noch Beta selbst – das Schild bleibt für das Mehr-Menü). */
.betaTag { display: inline-block; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--warn-text); background: var(--warn-bg); border: 1px solid var(--warn-border); border-radius: var(--r-xs); padding: 1px 5px; margin-left: 2px; vertical-align: 1px; }
.betaHinweis { margin: 8px 12px 4px; padding: 8px 12px; border: 1px solid var(--warn-border); background: var(--warn-bg); color: var(--warn-text); border-radius: var(--r-s); font-size: 0.82rem; line-height: 1.4; }

/* v2.70.0: Roter Punkt am Zahnrad, solange eine Rückmeldung offen ist.
   Nicht nur Farbe: der Knopf trägt zusätzlich ein aria-label mit der Zahl. */
.keyBtn.hatMarke { position: relative; }
.keyBtn.hatMarke::after { content: ""; position: absolute; top: 4px; right: 4px; width: 9px; height: 9px;
  border-radius: var(--r-kreis); background: var(--danger); border: 2px solid var(--bg); box-sizing: content-box; }

/* v2.72.0: Die Marke an einer Einstellungs-Zeile - derselbe rote Punkt wie
   am Zahnrad, nur mit der Zahl darin, damit man dem Punkt folgen kann. */
.setMarke { flex: none; min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--r-voll);
  background: var(--danger); color: var(--auf-farbe); font-size: 0.7rem; font-weight: 700; line-height: 20px;
  text-align: center; margin-left: 6px; }

/* v2.73.0: Zugriffe verwalten - die Zahlenblöcke je Konto. */
.zugriffZahlen { margin-top: 8px; border-top: 1px solid var(--border); }
.zugriffZeile { display: flex; justify-content: space-between; gap: 10px; padding: 5px 0; font-size: 0.82rem;
  border-bottom: 1px solid var(--border); color: var(--text-2); }
.zugriffZeile:last-child { border-bottom: none; }
.zugriffZeile b { color: var(--text); white-space: nowrap; }
/* v2.77.0: Ein gesperrter Haushalt sieht auch aus wie einer, und der
   Löschen-Knopf sieht nicht aus wie der daneben. */
.blockKarte.gesperrt { border-color: var(--danger-border); background: var(--danger-bg); }
.blattAktion.warnAktion { border-color: var(--danger-border); color: var(--danger); background: var(--bg); }
.blattAktion.warnAktion:active { background: var(--danger-bg); }
/* v2.78.0: Die Geräte, die Mitteilungen aus einem Haushalt bekommen. */
.zugriffGeraet { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 0.82rem; color: var(--text-2); }
.zugriffGeraet:last-child { border-bottom: none; }
.zugriffGeraetZeit { color: var(--muted); font-size: 0.78rem; }
.zugriffGeraetWeg { flex: 0 0 auto; min-width: 44px; min-height: 44px; border: 1px solid var(--border-2);
  border-radius: var(--r-s); background: var(--bg); color: var(--danger); font-size: 1rem; }
.zugriffGeraetWeg:active { background: var(--danger-bg); }

/* v3.0.0: Geburtstage - Ansicht unter Termine und Feld bei den Personen. */
.gebZeile { cursor: pointer; }
.gebZeile.heute { border-color: var(--accent-strong); }
.gebKopf { display: flex; align-items: center; gap: 10px; }
.gebSymbol { font-size: 1.3rem; line-height: 1; }
.gebText { min-width: 0; }
.gebAlter { font-weight: 400; color: var(--muted); font-size: 0.9em; }
.gebMarke { white-space: nowrap; }
.gebHinweis { margin: 4px 0 10px; }
.leuteGebZeile { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 2px 0 6px 34px; font-size: 0.86rem; }
.leuteGebLabel { display: flex; align-items: center; gap: 6px; }
/* v3.136.0: 150 px statt 130. Gemessen bei 390 px: Der Griff im Feld
   (padding-right 46 px) ließ bei 130 px nur 74 px für den Text, „24.12.1980“
   braucht 80 - die letzten Ziffern waren abgeschnitten (scrollWidth 134 >
   clientWidth 128). 142 wären knapp: SF Pro auf dem iPhone setzt Ziffern
   breiter als die Linux-Schrift der Probe. Die Warnung vor 150 px (v3.83.0:
   Infozeile rutscht unter das Feld) galt der Zeile mit 34 px Einzug; seit
   v3.78.0 steht die Zeile in den aufgeklappten Details (320 px breit), und
   dort steht die Infozeile („24.12. · wird 46“) bei 390 px ohnehin unter
   dem Feld - bei 130 wie bei 150 px, die Zeile bleibt 80 px hoch.
   Probe: geburtstag-dom (kein Überlauf).
   Die rote Marke eines unlesbaren Feldes ist input.mangel (unten, aus
   feldMarkeSetzen in app-gesten.js) - keine eigene Regel hier: eine über
   aria-invalid allein verlor gegen input:focus-visible (!important, oben)
   und war mit Fokus unsichtbar. */
.leuteGeb { width: 150px; min-height: 44px; padding: 6px 8px; font-size: 16px; border: 1px solid var(--border); border-radius: var(--r-s); background: var(--card); color: inherit; }

/* ============================================================
   v3.83.0: DER KALENDER-GRIFF IM DATUMS-TEXTFELD.
   Sichtbar ist das 📅 am rechten Rand des Feldes; darüber liegt ein
   durchsichtiges <input type="date"> über die volle Fläche - ein Tipp
   darauf öffnet den Kalender des Geräts. 44 px, wie jedes andere
   Bedienelement, und ohne dass die Zeile dafür höher wird.
   ============================================================ */
.datumFeld { position: relative; display: inline-flex; align-items: center; }
.datumFeld > input { padding-right: 46px; }
.datumGriff { position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: var(--radius-s); }
.datumGriff:active { background: var(--surface-2); }
.datumGriffZeichen { font-size: 1.05rem; pointer-events: none; }
/* Das Feld deckt den Griff ganz ab - es ist die Trefffläche, nicht nur
   das kleine Kalendersymbol am Rand, das der Browser selbst zeichnet.
   max-width: none, weil die allgemeine Feldregel jedes Eingabefeld auf
   100 % deckelt und die Fläche sonst wieder schrumpfte. */
.datumGriffFeld { position: absolute; inset: 0; width: 100%; height: 100%;
  max-width: none; opacity: 0; border: none; padding: 0; margin: 0; background: none; cursor: pointer; }
/* Der Fokus gehört dem unsichtbaren Feld - zu sehen ist er am Griff. */
.datumGriff:focus-within { box-shadow: var(--ring); }
.leuteGebInfo { color: var(--muted); }

/* v3.0.0: Anhaenge am Termin. */
.anhangZeile { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 3px; font-size: 0.86rem; }
.anhangLink { color: var(--accent-strong); text-decoration: none; word-break: break-word; }
.anhangListe { display: flex; flex-direction: column; gap: 4px; margin: 4px 0 8px; }
.anhangEintrag { display: flex; align-items: center; gap: 8px; min-height: 40px; }
.anhangEintrag .anhangLink { flex: 1; min-width: 0; }
.anhangMeta { color: var(--muted); font-size: 0.82rem; white-space: nowrap; }
.anhangWeg { flex: none; min-width: 40px; min-height: 40px; border: 1px solid var(--border); border-radius: var(--r-s); background: var(--card); color: inherit; font-size: 1rem; }
.anhangKnopf { display: block; text-align: center; cursor: pointer; }
/* v3.18.1: Zwei Wege nebeneinander - Album und Kamera. Unter 300 px
   Blattbreite bricht die Zeile um, statt die Wörter zu quetschen. */
.anhangKnoepfe { display: flex; gap: 8px; flex-wrap: wrap; }
.anhangKnoepfe .anhangKnopf { flex: 1 1 46%; min-width: 130px; }
.einBehalten { display: flex; gap: 10px; align-items: flex-start; margin: 10px 0; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-s); }
.einBehalten input { width: 22px; height: 22px; margin-top: 2px; flex: none; }
.einBehalten small { display: block; color: var(--muted); margin-top: 2px; }
/* v3.1.0: Geburtstagsliste - Eingabe, Foto, Text, Vorschau; 🎂 im Blatt. */
.gebWerkzeuge { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 10px; position: relative; }
.gebWerkzeuge .blattAktion { flex: 1 1 30%; text-align: center; min-height: 44px; cursor: pointer; }
.gebFormular { border: 1px solid var(--border); border-radius: var(--r-s); padding: 10px 12px; margin-bottom: 10px; }
/* v3.136.0: Die Meldungszeile der Geburtstagsliste steht immer im Markup
   (zeichneGeburtstage, app-termine.js) - leer nimmt sie keinen Platz. */
.gebMeldung:empty { display: none; }
.gebFormular textarea { width: 100%; box-sizing: border-box; min-height: 90px; }
.gebFormKnoepfe { display: flex; gap: 8px; margin-top: 8px; }
.gebFormKnoepfe button { flex: 1; min-height: 44px; }
.gebVorschau { border: 1px solid var(--border); border-radius: var(--r-s); padding: 10px 12px; margin-bottom: 10px; }
.gebVorKopf { font-weight: 700; margin-bottom: 6px; }
.gebVorZeile { display: flex; align-items: center; gap: 10px; min-height: 40px; }
.gebVorZeile input { width: 22px; height: 22px; flex: none; }
.gebUnsicher { color: var(--warn-text); font-size: 0.85em; }
.gebWeg { flex: none; min-width: 40px; min-height: 40px; border: 1px solid var(--border); border-radius: var(--r-s); background: var(--card); color: inherit; font-size: 1rem; }
.gebKopf { position: relative; }
.gebKopf .gebText { flex: 1; min-width: 0; }
.gebHaken { display: flex; align-items: center; gap: 8px; min-height: 40px; font-weight: 600; }
.gebHaken input { width: 22px; height: 22px; }
/* v3.1.1: Anhaenge sichtbar - eigene Zeile und Marke am Titel. */
.item .anhangZeile { margin-top: 5px; padding-top: 5px; border-top: 1px dashed var(--border); font-size: 0.86rem; }
.anhangWort { color: var(--muted); margin-right: 2px; }
.anhangBadge { display: inline-block; margin-left: 6px; font-size: 0.7rem; padding: 1px 6px; border-radius: var(--r-s); background: var(--purple-bg); color: var(--purple); vertical-align: middle; white-space: nowrap; }

/* v3.2.0: Anhang-Betrachter. Ebene 1300 - ueber den Blaettern (1200), unter
   der Rueckfrage (1400), damit "Entfernen?" darueber liegt. */
#anhangBetrachter { position: fixed; inset: 0; z-index: 1300; display: none; flex-direction: column; background: var(--bg); color: var(--text); }
.abKopf { display: flex; align-items: center; gap: 10px; padding: 10px 12px; padding-top: max(10px, env(safe-area-inset-top)); border-bottom: 1px solid var(--border); }
.abZurueck { flex: none; min-height: 44px; border: 1px solid var(--border); background: var(--card); color: inherit; border-radius: var(--r-s); padding: 6px 12px; font-weight: 600; font-size: 0.92rem; }
.abTitel { flex: 1; min-width: 0; }
#abName { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#abUnter { display: block; font-size: 0.78rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.abInhalt { flex: 1; min-height: 0; overflow: auto; display: flex; align-items: center; justify-content: center; background: var(--bild-grund); }
.abBild { max-width: 100%; max-height: 100%; object-fit: contain; }
.abPdf { width: 100%; height: 100%; border: 0; background: var(--stets-weiss); }
.abKnoepfe { display: flex; gap: 8px; padding: 10px 12px 6px; border-top: 1px solid var(--border); }
.abKnoepfe .blattAktion { flex: 1; min-width: 0; padding: 8px 6px; font-size: 0.82rem; background: var(--surface); border-color: var(--border-2); color: var(--text-2); }
.abKnoepfe .abWeg { color: var(--danger); }
.abMeldung { padding: 0 12px; padding-bottom: max(10px, var(--sab)); font-size: 0.82rem; color: var(--muted); min-height: 1.4em; }
.abMeldung a { color: var(--accent-strong); text-decoration: none; }

/* v3.3.0: Kalender - der Tag unter dem Gitter. */
.kalMonatSumme { font-size: 0.78rem; color: var(--muted-2); text-align: center; margin-top: 6px; }
.kalTagBereich { margin-top: 10px; border-top: 1px solid var(--border); padding-top: 10px; }
.kalKopf.klein { margin-bottom: 4px; }
:where(.kalKopf.klein) div { font-size: 0.92rem; }
.kalKopf.klein button { width: 40px; height: 40px; font-size: 1.15rem; }
.kalTagBereich .kalTagTitel { margin: 0; text-align: center; flex: 1; }
.kalTagBereich .tagHeuteZeile { margin: 0 0 6px; }

/* v3.3.0: Tagesgruppen in der Terminliste - vier Stile, siehe listenStil().
   Alle Bausteine stehen im Kopf; jeder Stil blendet ein, was er braucht.
   Die Kopf-Regeln tragen ".tagGruppe .tagKopf.banner", damit sie das
   dunkle Band (#terminListe .tagTrenner.banner.heute) sicher ueberstimmen. */
#terminListe .tagGruppe { margin: 0; }
#terminListe .tagKopf .tWt, #terminListe .tagKopf .tNr, #terminListe .tagKopf .tMon, #terminListe .tagKopf .tName, #terminListe .tagKopf .tLinie { display: none; }
#terminListe:not([data-stil="banner"]) .tagGruppe .tagKopf.banner, #terminListe:not([data-stil="banner"]) .tagGruppe .tagKopf.banner.heute {
  background: none; color: var(--text-2); padding: 0; margin: 0; border-radius: 0; text-transform: none; }
#terminListe:not([data-stil="banner"]) .tagGruppe .tagKopf.banner .bannerText, #terminListe:not([data-stil="banner"]) .tagGruppe .tagKopf.banner .bannerDatum { display: none; }
#terminListe:not([data-stil="banner"]) .tagGruppe .tagKopf.banner span { text-transform: none; letter-spacing: 0; font-weight: 600; color: inherit; }

/* Stil "spalte": Datumsspalte links (Wochentag + grosse Zahl), Eintraege rechts. */
#terminListe[data-stil="spalte"] .tagGruppe { display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 0 8px; padding: 10px 0 4px; border-top: 1px solid var(--border); }
#terminListe[data-stil="spalte"] .tagGruppe:first-child { border-top: none; padding-top: 4px; }
#terminListe[data-stil="spalte"] .tagGruppe .tagKopf.banner { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 0; padding-top: 6px; }
#terminListe[data-stil="spalte"] .tagGruppe .tagKopf.banner .tWt { display: block; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
#terminListe[data-stil="spalte"] .tagGruppe .tagKopf.banner .tNr { display: flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: var(--r-kreis); font-size: 1.15rem; font-weight: 700; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
#terminListe[data-stil="spalte"] .tagGruppe .tagKopf.banner .tMon { display: block; font-size: 0.7rem; color: var(--muted-2); }
#terminListe[data-stil="spalte"] .tagGruppe.heute .tagKopf.banner .tNr { background: var(--accent); color: var(--auf-farbe); }
#terminListe[data-stil="spalte"] .tagGruppe.heute .tagKopf.banner .tWt { color: var(--accent); }
#terminListe[data-stil="spalte"] .tagEintraege { min-width: 0; }
/* v3.100.3: enger als die anderen Stile - aber ueber --strichBahn, damit die
   linke Polsterung mitwandert (14 px statt 18) und der Kreis frei bleibt. */
#terminListe[data-stil="spalte"] .tagEintraege .item.terminZeile {
  --strichBahn: 4px; padding-top: 10px; padding-bottom: 10px; padding-right: 8px; }
#terminListe[data-stil="spalte"] .tagEintraege .item.terminZeile .name { font-size: 1rem; }

/* Stil "linie": Tageszeile mit Linie, Heute in Akzentfarbe, bleibt beim Rollen oben. */
#terminListe[data-stil="linie"] .tagGruppe .tagKopf.banner { display: flex; align-items: center; gap: 10px; margin: 14px 0 6px; padding: 6px 0; background: var(--bg); position: sticky; top: 0; z-index: 2; }
#terminListe[data-stil="linie"] .tagGruppe:first-child .tagKopf.banner { margin-top: 2px; }
#terminListe[data-stil="linie"] .tagGruppe .tagKopf.banner .tName { display: inline; font-size: 0.82rem; font-weight: 600; letter-spacing: 0; white-space: nowrap; }
#terminListe[data-stil="linie"] .tagGruppe .tagKopf.banner .tName b { font-weight: 800; }
#terminListe[data-stil="linie"] .tagGruppe .tagKopf.banner .tLinie { display: block; flex: 1; height: 1px; background: var(--border-2); }
#terminListe[data-stil="linie"] .tagGruppe.heute .tagKopf.banner { color: var(--accent); }
#terminListe[data-stil="linie"] .tagGruppe.heute .tagKopf.banner .tLinie { background: var(--accent); opacity: .5; }

/* Stil "strahl": Zeitstrahl links mit Punkt je Tag. */
#terminListe[data-stil="strahl"] .tagGruppe { position: relative; margin-left: 9px; padding: 0 0 10px 16px; border-left: 2px solid var(--border-2); }
#terminListe[data-stil="strahl"] .tagGruppe:last-child { border-left-color: transparent; }
#terminListe[data-stil="strahl"] .tagGruppe .tagKopf.banner { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; padding: 4px 0; }
#terminListe[data-stil="strahl"] .tagGruppe .tagKopf.banner::before { content: ""; position: absolute; left: -7px; top: 9px; width: 12px; height: 12px; border-radius: var(--r-kreis); background: var(--bg); border: 2px solid var(--border-2); box-sizing: border-box; }
#terminListe[data-stil="strahl"] .tagGruppe .tagKopf.banner .tName { display: inline; font-size: 0.82rem; font-weight: 600; letter-spacing: 0; }
#terminListe[data-stil="strahl"] .tagGruppe.heute .tagKopf.banner .tName { display: inline-block; background: var(--accent); color: var(--auf-farbe); padding: 2px 10px; border-radius: var(--r-voll); }
#terminListe[data-stil="strahl"] .tagGruppe.heute .tagKopf.banner::before { background: var(--accent); border-color: var(--accent); }
#terminListe[data-stil="strahl"] .tagGruppe.heute { border-left-color: var(--accent); }
.listenStilWahl button { font-variant-numeric: tabular-nums; }

/* v3.4.0: Terminzeile ohne Kreis - Erledigt per Wischen nach rechts (gruen),
   Loeschen nach links (rot). Der Haken steht dann als ✓ vor dem Titel.
   v3.37.0 (Paket 5, Befund B2): Der Kreis ist wieder da. "display: none"
   nimmt ein Element auch aus der Tab-Reihenfolge - damit gab es fuer einen
   Termin GAR KEINEN Weg zum Abhaken ausser dem Wisch: kein Knopf in der
   Zeile, kein Schalter im Blatt. Wer die Geste nicht kennt oder eine
   Tastatur, eine Vorlesehilfe oder eine Schaltersteuerung benutzt, konnte
   einen Termin nicht erledigen. Der Kreis bleibt leiser als in den anderen
   Listen (duennerer Rand), aber er ist da und anzuspringen. */
.item.terminZeile .check { border-color: var(--border); }
/* v3.34.0: Rechts heisst in jeder Liste erledigen, also ist die Flaeche
   ueberall gruen. Der gelbbraune Ton stand frueher fuer "Kein Artikel". */
/* v3.4.0: KI-Blase kompakter - Daumen in der Zeit-Zeile. */
.bubble.ai .meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; }
.bubble.ai .meta .feedbackRow { margin: 0 0 0 auto; gap: 4px; }
.bubble.ai .meta .feedbackRow button { min-height: 30px; min-width: 38px; padding: 2px 8px; font-size: 0.92rem; border-radius: var(--r-s); }
.bubble.ai .meta .feedbackDone { margin: 0 0 0 auto; }

/* v3.4.1: Wischen - "durchgezogen" (ab 140 px) fuehrt beim Loslassen sofort
   aus; der Grund wird dann kraeftiger. Tag/Monat-Wischen: der neue Inhalt
   kommt von der Seite herein. */
/* v3.34.0: Die Klasse "voll" gehoerte zum Durchziehen, das sofort geloescht
   hat. Das gibt es nicht mehr - Loeschen braucht immer den zweiten Tipp. */
@keyframes kalVonRechts { from { transform: translateX(40px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes kalVonLinks { from { transform: translateX(-40px); opacity: 0; } to { transform: none; opacity: 1; } }
.vonRechts { animation: kalVonRechts .22s ease-out; }
.vonLinks { animation: kalVonLinks .22s ease-out; }
@media (prefers-reduced-motion: reduce) { .vonRechts, .vonLinks { animation: none; } }

/* v3.5.0: Kalender-Stile (kalenderStil()). Balken und Wochenstreifen sind
   immer im DOM und werden je Stil ein-/ausgeblendet. */
.kalBalkenBox, .kalWoche { display: none; }
/* v3.104.0 (Sören: "Oben über den terminen hätte ich gern einen streifen
   mit der aktuellen Woche ähnlich wie es vorher war"): Derselbe Streifen
   wie im Kalender, nur ueber der Terminliste - und flacher, weil er dort
   neben der Liste steht und nicht statt ihrer. [hidden] gewinnt hier
   ausdruecklich gegen das display:grid (in v3.102.0 hatte genau das die
   Einblend-Zeile offen stehen lassen). */
.listenWoche { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin: 0 0 14px; }
.listenWoche[hidden] { display: none; }
/* v3.104.0 (Sören, mit einem Vorbild: "Die obere leiste sieht nicht gut aus.
   Es soll optisch in diese Richtung."): Kein Kasten um jeden Tag - sieben
   Rahmen nebeneinander sind sieben Rahmen fuer eine Information. Nur der
   gewaehlte Tag bekommt eine gefuellte Pille, HEUTE einen Punkt darunter.
   Zahl gross oben, Wochentag klein darunter. */
.listenWoche .wChip { min-height: 56px; padding: 7px 0 6px; background: none;
  border: 0; border-radius: var(--r-l); gap: 1px; }
.listenWoche .wChip .nr { font-size: 1.15rem; font-weight: 700; order: 0; }
.listenWoche .wChip .wt { font-size: 0.7rem; font-weight: 500; letter-spacing: 0; order: 1; }
.listenWoche .wChip .kalPunkte { order: 2; margin-top: 2px; }
/* HEUTE ist die staerkste Marke, solange nichts gewaehlt ist - wie im
   Monatsgitter seit v3.102.0 (eine Form, keine Deckkraft). */
.listenWoche .wChip.heute .nr { color: var(--accent); }
.listenWoche .wChip.heute .wt { color: var(--accent); }
/* Vergangene Tage ZUERST, die Auswahl DANACH: beide haben dieselbe
   Spezifitaet, und die spaetere Regel gewinnt. Andersherum bekam ein
   gewaehlter Tag in der Vergangenheit von .vorbei sein background: none
   zurueck - weisse Schrift auf hellem Grund, unsichtbar. Gemessen. */
.listenWoche .wChip.vorbei { background: none; }
.listenWoche .wChip.gewaehlt { background: var(--primary); }
.listenWoche .wChip.gewaehlt .nr, .listenWoche .wChip.gewaehlt .wt { color: var(--on-primary); }
/* Vergangene Tage treten zurueck - sie sind Auskunft, keine Auswahl.
   Nicht ausgegraut bis zur Unlesbarkeit: der Kontrast bleibt ueber 3:1,
   damit man noch sieht, ob dort etwas war. */
.wChip.vorbei { background: none; }
.wChip.vorbei .nr, .wChip.vorbei .wt { color: var(--muted-2); }
.wChip.vorbei .kalPunkte i { opacity: .45; }
#kalTitel .kalKw { color: var(--muted); font-weight: 600; font-size: 0.82rem; margin-left: 4px; }
#kalenderBox[data-stil="woche"] #kalTitel { cursor: pointer; }

/* ruhig: nur Zahlen, duenne Wochenlinien, heute als Kreis */
#kalenderBox[data-stil="ruhig"] .kalTag { background: none; border: none; border-radius: 0; border-top: 1px solid var(--border); gap: 2px; font-size: 0.92rem; }
#kalenderBox[data-stil="ruhig"] .kalTag:nth-child(-n+7) { border-top: none; }
#kalenderBox[data-stil="ruhig"] .kalTag > span:first-child { width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; border-radius: var(--r-kreis); }
#kalenderBox[data-stil="ruhig"] .kalTag:nth-child(7n+6), #kalenderBox[data-stil="ruhig"] .kalTag:nth-child(7n) { color: var(--muted); }
#kalenderBox[data-stil="ruhig"] .kalTag.fremd { color: var(--border-2); background: transparent; }
#kalenderBox[data-stil="ruhig"] .kalTag.heute { border-color: var(--border); }
/* v3.102.0 (gemessen): HEUTE trug nur eine farbige Ziffer, das Reiseband
   dagegen eine gefuellte Flaeche ueber sieben Tage - die Reise rief, heute
   fluesterte. Eine Flaeche kann gegen eine Ziffer nicht verlieren. Heute
   bekommt die gefuellte Scheibe deshalb IMMER, nicht nur wenn der Tag
   zusaetzlich gewaehlt ist; der Vorrang ist damit eine Formfrage und keine
   Frage der Deckkraft, die beim naechsten Farbwechsel wieder kippt. */
#kalenderBox[data-stil="ruhig"] .kalTag.heute > span:first-child {
  background: var(--accent); color: var(--auf-farbe); font-weight: 800;
  min-width: 26px; height: 26px; border-radius: var(--r-kreis);
  display: inline-grid; place-items: center; }
#kalenderBox[data-stil="ruhig"] .kalTag.feiertag { background: none; border-color: var(--border); }
/* v3.102.0: siehe .kalTag.reiseTag - der Balken gilt in allen Stilen. */
#kalenderBox[data-stil="ruhig"] .kalTag.gewaehlt { background: none; color: var(--text); }
#kalenderBox[data-stil="ruhig"] .kalTag.gewaehlt > span:first-child { background: var(--text); color: var(--bg); font-weight: 700; }
#kalenderBox[data-stil="ruhig"] .kalTag.heute.gewaehlt > span:first-child { background: var(--accent); color: var(--auf-farbe); }
#kalenderBox[data-stil="ruhig"] .kalTag.gewaehlt .kalPunkte i { outline: none; }

/* balken: hoehere Zellen mit Balken statt Punkten */
#kalenderBox[data-stil="balken"] .kalTag { aspect-ratio: auto; min-height: 62px; align-items: stretch; justify-content: flex-start; padding: 3px 2px 2px; gap: 2px; min-width: 0; overflow: hidden; border-radius: var(--r-xs); font-size: 0.78rem; }
#kalenderBox[data-stil="balken"] .kalTag > span:first-child { text-align: left; padding-left: 3px; font-weight: 600; }
#kalenderBox[data-stil="balken"] .kalTag.heute > span:first-child { color: var(--accent); font-weight: 800; }
#kalenderBox[data-stil="balken"] .kalTag.gewaehlt { background: var(--surface); color: var(--text); outline: 2px solid var(--text); outline-offset: -2px; }
#kalenderBox[data-stil="balken"] .kalTag.feiertag.gewaehlt { color: var(--accent-strong); background: var(--accent-bg); }
#kalenderBox[data-stil="balken"] .kalTag .kalPunkte { display: none; }
#kalenderBox[data-stil="balken"] .kalBalkenBox { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.kalBalken { display: block; font-style: normal; font-size: 0.7rem; line-height: 1.25; padding: 1px 3px; border-radius: var(--r-xs); color: var(--auf-farbe); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-align: left; font-weight: 600; background: var(--accent); }
.kalBalken.essen { background: var(--warn); color: var(--warn-auf); }
.kalBalken.aufgabe { background: var(--kal-aufgabe); color: var(--auf-kal-aufgabe); }
.kalBalken.aufgabe.spaet { background: var(--danger); }
.kalMehr { display: block; font-style: normal; font-size: 0.7rem; color: var(--muted); padding-left: 3px; text-align: left; }

/* woche: Streifen statt Gitter; Gitter nur aufgeklappt */
#kalenderBox[data-stil="woche"] .kalWoche { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; margin-bottom: 4px; }
#kalenderBox[data-stil="woche"]:not(.gitterAuf) .kalWochentage, #kalenderBox[data-stil="woche"]:not(.gitterAuf) #kalGitter { display: none; }
#kalenderBox[data-stil="woche"].gitterAuf .kalWochentage { margin-top: 10px; }
.wChip { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 8px 0 6px; border-radius: var(--r-m); background: var(--surface); border: 1px solid transparent; color: var(--text); font: inherit; min-height: 60px; }
.wChip .wt { font-size: 0.7rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 700; }
.wChip .nr { font-size: 1.15rem; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.wChip.heute .nr { color: var(--accent); }
.wChip.heute { border-color: var(--border-2); }
.wChip.feiertag .nr { color: var(--accent-strong); }
.wChip.we .wt { color: var(--muted-2); }
.wChip.gewaehlt { background: var(--accent); color: var(--auf-farbe); border-color: var(--accent); }
.wChip.gewaehlt .wt, .wChip.gewaehlt .nr { color: var(--auf-farbe); }
.wChip .kalPunkte { height: 5px; }
.wChip.gewaehlt .kalPunkte i { outline: 1px solid rgba(255,255,255,.7); }

/* v3.9.0: Wünsche eines Gastes - je Zeile ein ✕ zum Herausnehmen. */
.evWunschZeile { display: flex; align-items: center; gap: 8px; min-height: 34px; }
.evWunschText { flex: 1; min-width: 0; word-break: break-word; }
.evWunschWeg { flex: none; width: 32px; min-height: 32px; border: 1px solid var(--border); border-radius: var(--r-s); background: var(--card); color: var(--muted); font-size: 0.92rem; }
.evWunschWeg.bestaetigen { border-color: var(--danger); color: var(--danger); }

/* v3.9.0: Programm-Umfrage im Blatt - beschriftete Felder, Antworten einzeln. */
.evProgLabel { display: block; margin: 10px 0 2px; font-size: 0.78rem; font-weight: 700; color: var(--text-2); }
.evProgOptListe { display: flex; flex-direction: column; gap: 6px; }
.evProgOptZeile { display: flex; align-items: center; gap: 6px; }
.evProgFolge .evProgOptZeile input { margin-top: 0; }
.evProgOptWeg { flex: none; width: 36px; min-height: 36px; border: 1px solid var(--border-2); border-radius: var(--r-s); background: var(--bg); color: var(--muted); font-size: 0.92rem; }
/* v3.142.0 (Befund D9, gefunden mit der erweiterten einheitlich-dom 3b):
   36×36 px - das ✕ neben jeder Antwort einer Programm-Frage. */
.evProgOptWeg { width: 44px; min-height: 44px; }
.evProgOptDazu { margin-top: 6px; }
.evProgMaxLabel { display: block; margin-top: 10px; }
.evUmfrageSumme { margin-top: 6px; padding-top: 6px; border-top: 1px dashed var(--border); font-size: 0.86rem; font-weight: 600; }
/* v3.10.0: Die Merkmale eines Programmpunktes stehen unter seinem Namen -
   ohne Aufklappen sieht man, was die Gäste dort gefragt werden. */
/* v3.104.0: Die Zeile ist flex-wrap. Ist die Info kurz (ein Punkt ohne
   Folgefrage hat nur noch EINE Marke, seit die Abwesenheiten weg sind),
   passte sie neben das Textfeld - und das schrumpfte auf die Breite
   eines Buchstabens. Info und Aufklapper nehmen jetzt immer eine eigene
   Zeile, und das Textfeld behaelt eine Mindestbreite. */
.evProgInfo { display: flex; flex-wrap: wrap; gap: 4px 6px; margin: 4px 0 2px; flex: 1 0 100%; }
.evProgZeile > .evProgUmfrage { flex: 1 0 100%; }
.evProgZeile .evProgText { min-width: 9rem; }
/* v3.104.0: "ohne Folgefrage" ist eine Auskunft, keine Einstellung -
   also kein Rahmen wie bei .evProgMerkmal, nur ein leiser Nachsatz. */
.evProgOhne { align-self: center; font-size: 0.78rem; color: var(--muted-2); font-style: italic; }
.evProgMerkmal { padding: 2px 7px; border: 1px solid var(--border); border-radius: var(--r-voll); background: var(--surface); font-size: 0.7rem; color: var(--text-2); }
.evProgMerkmal.aus { opacity: 0.6; }
/* v3.10.0: Aus den gezählten Antworten eine Liste machen. */
.evUmfrageUebernehmen { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--border); }
.evUmfrageUebernehmen .feldHinweis { margin: 0; }
.evUmfrageUebernehmen .knopfKlein { min-height: 36px; padding: 0 10px; font-size: 0.82rem; }
/* v3.11.0: Unter der Literzahl im Mengenrechner das Gebinde ("5 Flaschen à
   1 l") - Liter kauft niemand. */
.mengenGebinde { display: block; font-style: normal; font-size: 0.7rem; font-weight: 400; color: var(--text-3); }

/* ============================================================
   v3.12.0 - Sörens Rückmeldung vom 09.09.2026:
   "Ich finde nicht, wo ich die Listen aus den Antworten erstellen kann.
    Zudem ist die Erstellerseite sehr unübersichtlich. Die einzelnen Punkte
    lassen sich schwer voneinander unterscheiden. Zurück-Knöpfe fehlen und
    es ist nicht überall einheitlich."
   ============================================================ */

/* Zurück zur Feier-Übersicht: die Zeile unter dem Band, immer an derselben
   Stelle und in derselben Form wie das "‹" in den Einstellungen. */
#evRuecksprung {
  display: block; width: 100%; text-align: left;
  padding: 11px 14px; min-height: 44px;
  border: 0; border-bottom: 1px solid var(--border);
  background: var(--surface); color: var(--text-2);
  font-size: 0.86rem; font-weight: 600; cursor: pointer;
}
#evRuecksprung:active { background: var(--border); }

/* Die Sprungleiste im Orga-Reiter: was es hier gibt - und ein Tipp bringt
   einen hin. Sie rollt seitlich, statt zu stapeln. */
/* v3.128.0 (Sören: "Die Filterfunktion anzeigen ist nicht so schön wie in
   den anderen räumen"): Die Reihe rollt jetzt waagerecht, statt auf einem
   schmalen Gerät in zwei Zeilen umzubrechen – dieselbe Bauart wie der
   Ideen-Filter im Projekt-Raum. Form, Höhe und Farbe der Chips kommen aus
   .pfChip (Personen-Block weiter oben); hier steht nichts davon noch einmal.
   Das Wort "Anzeigen" davor ist weg: Seit die Sprungleiste entfallen ist,
   gibt es keine zweite Chipreihe, mit der man sie verwechseln könnte. */
.orgaFilterReihe { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; margin: 4px -2px 10px; padding: 2px; }
.orgaFilterReihe::-webkit-scrollbar { display: none; }

/* "Daraus eine Liste machen" ist kein Kleingedrucktes - es ist der Zweck
   der ganzen Zählung. Deshalb ein eigener Kopf und ganze Knöpfe. */
.evUmfrageUebernehmenKopf {
  width: 100%; margin-bottom: 2px;
  font-size: 0.82rem; font-weight: 700; color: var(--text-2);
}
#mitbringenView .evUmfrageUebernehmen .knopfKlein {
  flex: 1 1 auto; min-height: 40px; justify-content: center;
  /* Ohne nowrap bricht der Text IM Knopf um (Symbol über Wort) statt die
     Reihe umzubrechen - das sah aus wie zwei halbe Knöpfe. */
  white-space: nowrap;
}

/* "Die einzelnen Punkte lassen sich schwer voneinander unterscheiden":
   Getränke, Gerichte und Wünsche standen als flache Zeilen untereinander,
   nur von einer Haarlinie getrennt. Im Orga-Reiter wird jede zu einer
   eigenen Karte - dasselbe Muster wie die Mitbring-Positionen darunter. */
/* v3.124.0: Die Getränke- und Gericht-Zeilen standen hier auch - sie sind
   weggefallen (sie zeigten alles ein zweites Mal, siehe event.js). Die
   Karte bleibt für die Wünsche. */
#mitbringenView .evGeschenkZeile {
  border: 1px solid var(--border); border-radius: var(--r-m);
  background: var(--surface);
  margin: 8px 0; padding: 10px 12px;
}
#mitbringenView .evGeschenkZeile:first-of-type { border-top: 1px solid var(--border); }

/* v3.12.1: Das ganze Programm auf einmal - eine Zeile unter den Umfragen. */
.evUmfrageAlle {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin: 10px 0 4px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--r-m); background: var(--surface);
}
.evUmfrageAlle .knopfKlein { flex: 1 1 auto; min-height: 40px; justify-content: center; white-space: nowrap; }
.evUmfrageUebernehmen.leise { border-top-style: dotted; }
.evUmfrageUebernehmen.leise .feldHinweis { margin: 0; }

/* ============================================================
   v3.10.0: EVENT-RAUM – Reiterleiste und Abschnitte
   (Sören: „Der Reiter Feier schwimmt nach rechts und links.“ und
    „Dann die einzelnen Abschnitte klarer trennen, ähnlich wie
     Kalenderlisten-Ansicht.“)
   ============================================================ */

/* --- A) Die acht Event-Reiter passen nebeneinander ---
   Bisher war die Leiste im Event-Raum breiter als der Schirm (gemessen:
   420 px auf 390 px). Sie wurde deshalb bei JEDEM Reiterwechsel ein
   Stück gescrollt (reiterInsBild) - "Feier" stand mal links, mal rechts.
   Die Leiste als Ganzes wird nicht schmaler gemacht, nur die Reiter im
   Event-Raum: kleinere Schrift und weniger Innenabstand links/rechts.
   Dazu heisst "Besorgungen" im Event-Raum "Einkauf" (raumTypAnwenden in
   app.js) - das eine Wort war so breit wie zwei andere zusammen.
   Der Haushalts-Raum hat laengere Woerter und bleibt wischbar.
   Die Hoehe bleibt bei 50 px (min-height aus #tabs button) - unter 44 px
   trifft man auf dem Handy daneben, deshalb wird nur seitlich gespart. */
/* v3.95.0: HIER STAND DER SONDERWEG DES FEIER-RAUMS - 0,7 rem (11 px) und
   4 px Polster, damit acht Reiter ohne Wischen in 360 px passen.
   Sören, mit einem Bild aus genau diesem Raum: „Die reiter viel zu klein
   beschriftet." Und danach nochmal: „Reiter immer noch zu Klein."
   Acht lesbare Wörter passen nicht in 360 px - das ist keine Frage der
   Umsetzung, sondern Arithmetik. Von den beiden möglichen Antworten
   (kleiner schreiben oder wischen lassen) hat Sören die zweite schon in
   v3.81.0 gewählt. Also gilt im Feier-Raum dieselbe Schrift wie überall,
   und die Leiste wischt seitlich - wie im Haushalt seit v1.8.0.
   Die Reihenfolge der Reiter (order, weiter oben) bleibt unberührt. */
#tabs.eventReiter #tabMehrMenue { order: 10; }
/* --- B) Abschnitte in den Event-Ansichten klar trennen ---
   Vorbild ist die Terminliste im Stil "spalte"/"linie": ruhige Gruppen,
   die eine feine Linie voneinander abstellt, statt einer durchlaufenden
   Wand. Keine neuen Farben - nur var(--border), var(--surface),
   var(--text-2)/(--text-3), damit hell und dunkel gleich sitzen. */

/* Der grosse Abschnittskopf ("Wer sorgt für Getränke", "Programm-Umfragen",
   "Wer bringt was mit") traegt die Trennlinie selbst: Linie + Luft darueber,
   Kopf darunter. Nicht mehr in Versalien - eine Ueberschrift, kein Etikett. */
#eventPlanView .blockKopf.gross,
#eventGaesteView .blockKopf.gross,
#mitbringenView .blockKopf.gross,
#kostenView .blockKopf.gross {
  margin: 26px 2px 8px; padding-top: 18px;
  border-top: 1px solid var(--border);
  font-size: 1rem; font-weight: 700; color: var(--text);
  text-transform: none; letter-spacing: -0.01em;
}
/* Der Hinweis unter einem Abschnittskopf gehoert zum Kopf, nicht zum
   naechsten Block - deshalb dichter dran. */
#eventPlanView .blockKopf.gross + .evHinweis,
#eventGaesteView .blockKopf.gross + .evHinweis,
#mitbringenView .blockKopf.gross + .evHinweis,
#kostenView .blockKopf.gross + .evHinweis { margin-top: -2px; margin-bottom: 12px; }

/* Der kleine Kopf innerhalb eines Abschnitts (Kategorien beim Mitbringen,
   "Budget", "Angebote") bekommt den Stil "linie" aus der Terminliste: Wort,
   dann eine feine Linie bis zum Rand, die Zahl ganz rechts. */
#eventPlanView .blockKopf:not(.gross),
#eventGaesteView .blockKopf:not(.gross),
#mitbringenView .blockKopf:not(.gross),
#kostenView .blockKopf:not(.gross) {
  justify-content: flex-start; gap: 10px;
  margin: 20px 2px 8px;
  font-size: 0.78rem; text-transform: none; letter-spacing: 0;
  font-weight: 700; color: var(--text-2);
}
#eventPlanView .blockKopf:not(.gross)::after,
#eventGaesteView .blockKopf:not(.gross)::after,
#mitbringenView .blockKopf:not(.gross)::after,
#kostenView .blockKopf:not(.gross)::after {
  content: ""; order: 1; flex: 1; height: 1px; background: var(--border);
}
/* Die Zahl hinter der Linie, damit die Linie den Zwischenraum fuellt. */
#eventPlanView .blockKopf:not(.gross) .zahl,
#eventGaesteView .blockKopf:not(.gross) .zahl,
#mitbringenView .blockKopf:not(.gross) .zahl,
#kostenView .blockKopf:not(.gross) .zahl {
  order: 2; flex: none; font-size: 0.78rem; color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* "Was die Gäste geantwortet haben" und "Geschenkliste" waren schon so
   gebaut (Linie + Abstand) - hier nur auf dasselbe Mass gebracht. */
#eventGaesteView .evWuensche, #mitbringenView .evGeschenke {
  margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--border);
}
#eventGaesteView .evWunschKopf { font-size: 1rem; letter-spacing: -0.01em; margin-bottom: 8px; }

/* Die Umfragekarten stehen weiter auseinander und ruhen auf der Flaeche
   der App - dieselbe Karte wie .evPos, damit im Reiter nur ein Kartentyp
   vorkommt. */
#mitbringenView .evUmfrage { background: var(--surface); margin: 0 0 8px; padding: 10px 12px 11px; }
#mitbringenView .evUmfrage:last-of-type { margin-bottom: 2px; }
#mitbringenView .evUmfrageTitel { font-size: 0.92rem; }

/* Die Getränke-/Essen-Wahl und die Mitbring-Liste bekommen unten Luft,
   damit der naechste Abschnitt nicht direkt anschliesst. */
#mitbringenView .evSorge { margin-bottom: 4px; }
#mitbringenView .evPosStandGesamt { margin: 10px 2px 8px; }

/* Die kleinen Ueberschriften in den Antwort-Blöcken ("🥤 Getränke",
   "⚠️ Allergien …") und im Orga-Reiter bekommen dieselbe feine Linie wie
   die Kategorie-Köpfe - damit auch innerhalb eines Abschnitts sichtbar
   ist, wo eine Gruppe anfaengt. */
#eventGaesteView .evWunschTitel, #mitbringenView .evWunschTitel,
#eventGaesteView .evUnterKopf, #mitbringenView .evUnterKopf {
  display: flex; align-items: center; gap: 10px; margin-top: 18px;
}
#eventGaesteView .evWunschTitel::after, #mitbringenView .evWunschTitel::after,
#eventGaesteView .evUnterKopf::after, #mitbringenView .evUnterKopf::after {
  content: ""; flex: 1; height: 1px; background: var(--border);
}

/* ============================================================
   v3.21.0: DER REITER "PUNKTE" (public/punkte.js)

   Die Seite soll Spass machen, ohne aus der App ein Spielzeug zu machen.
   Deshalb: EINE farbige Karte (die eigene, in der Farbe der Person), alles
   Weitere in der ruhigen Sprache des Rests. Keine Verlaufsfarben quer ueber
   die Seite, keine Schatten-Orgie - der Blick soll oben haengenbleiben.
   Alle Farben kommen aus den Variablen, damit Hell und Dunkel stimmen.
   ============================================================ */
.pkSeite { padding: 0 0 12px; display: flex; flex-direction: column; gap: 14px; }
.pkKopf { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.pkKopf h2 { margin: 0; font-size: 1.15rem; letter-spacing: -0.01em; }
.pkKopfWoche { font-size: 0.78rem; color: var(--muted); }

/* --- Die eigene Karte --- */
.pkIch {
  border-radius: var(--radius-l); padding: 14px;
  /* Die Farbe der Person, mit dem Untergrund gemischt: kraeftig genug, um
     "das bist du" zu sagen, ruhig genug zum Lesen. */
  /* Zuerst die schlichte Fassung - ein Browser ohne color-mix (aeltere
     Android-Geraete) behaelt sie und bekommt eine ruhige graue Karte statt
     gar keinem Hintergrund. */
  background: var(--surface);
  background: linear-gradient(160deg, color-mix(in srgb, var(--pkFarbe, var(--accent)) 26%, var(--bg)), var(--surface));
  border: 1px solid var(--border);
  border-color: color-mix(in srgb, var(--pkFarbe, var(--accent)) 34%, var(--border));
  display: flex; flex-direction: column; gap: 10px;
}
.pkIchKopf { display: flex; align-items: center; gap: 10px; }
.pkAvatar {
  flex: none; width: 34px; height: 34px; border-radius: var(--r-kreis); color: var(--person-schrift, var(--stets-weiss));
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 0.92rem; box-shadow: var(--shadow-ring-innen);
}
.pkAvatar.gross { width: 46px; height: 46px; font-size: 1.3rem; }
.pkIchText { flex: 1; min-width: 0; }
.pkIchName { font-size: 1rem; font-weight: 700; letter-spacing: -0.01em; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pkIchStufe { font-size: 0.82rem; color: var(--text-3); margin-top: 1px; }
.pkHeute {
  flex: none; text-align: center; font-size: 1.15rem; font-weight: 800; color: var(--success-text);
  background: var(--success-bg); border: 1px solid var(--success-border); border-radius: var(--r-m); padding: 4px 10px;
}
.pkHeute span { display: block; font-size: 0.7rem; font-weight: 600; color: var(--success-text); letter-spacing: .02em; }

/* Der Stufenbalken - dieselbe Form wie der Belohnungsbalken (.ckBalken),
   damit "Fortschritt" in der ganzen App gleich aussieht. */
.pkStufenBalken { height: 10px; border-radius: var(--r-xs); background: var(--surface-2); background: color-mix(in srgb, var(--text) 12%, transparent); overflow: hidden; }
.pkStufenBalken i { display: block; height: 100%; border-radius: var(--r-xs); background: var(--success); transition: width .45s ease; }
.pkStufenBalken.dunkel { background: var(--surface-2); }
.pkStufenText { font-size: 0.78rem; color: var(--text-3); }
.pkStufenText.dunkel { margin: 6px 0 10px; }

.pkKacheln { display: flex; gap: 8px; }
.pkKachel {
  flex: 1; min-width: 0; text-align: center; padding: 8px 4px; border-radius: var(--r-m);
  background: var(--bg); background: color-mix(in srgb, var(--bg) 72%, transparent); border: 1px solid var(--border);
}
.pkKacheln.dunkel .pkKachel { background: var(--surface); }
.pkKachel b { display: block; font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.pkKachel span { display: block; font-size: 0.7rem; color: var(--muted); margin-top: 1px; }

/* Die sieben Tage. Balken von unten, heute mit Ring - eine Woche auf einen
   Blick, ohne Achsen und Zahlenkolonnen. */
.pkTage { display: flex; gap: 4px; align-items: flex-end; }
.pkTag { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 2px; }
.pkTagBalken { width: 100%; height: 40px; border-radius: var(--r-xs); background: var(--surface-2); background: color-mix(in srgb, var(--text) 8%, transparent); display: flex; align-items: flex-end; overflow: hidden; }
.pkTagBalken i { display: block; width: 100%; background: var(--success); background: color-mix(in srgb, var(--success) 55%, var(--bg)); border-radius: var(--r-xs); transition: height .45s ease; }
.pkTag.voll .pkTagBalken i { background: var(--success); }
.pkTag.heute .pkTagBalken { box-shadow: var(--ring-2) var(--accent); }
.pkTagWert { font-size: 0.7rem; font-weight: 700; color: var(--text-3); min-height: 0.9em; font-variant-numeric: tabular-nums; }
.pkTagName { font-size: 0.7rem; color: var(--muted); }
.pkTag.heute .pkTagName { color: var(--accent); font-weight: 700; }

.pkVergleich { font-size: 0.82rem; color: var(--text-2); }
.pkVergleich.gut { color: var(--success-text); font-weight: 600; }

.pkTunKnopf {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; min-height: 46px; padding: 8px 12px; border-radius: var(--r-m);
  border: 0; background: var(--primary); color: var(--on-primary);
  font: inherit; font-size: 0.86rem; font-weight: 700; cursor: pointer; text-align: left;
}
.pkTunKnopf:active { opacity: .85; }
.pkTunPunkte { flex: none; font-size: 0.78rem; font-weight: 600; background: rgba(255,255,255,.2); border-radius: var(--r-voll); padding: 3px 9px; }
.pkAlles { font-size: 0.82rem; color: var(--success-text); font-weight: 600; }

/* Die Serie. Klein, warm, nie als Vorwurf - sie steht nur da, wenn sie
   laeuft (ab zwei Tagen). */
.pkSerie { flex: none; font-size: 0.7rem; font-weight: 700; color: var(--warn-text); background: var(--warn-bg); border: 1px solid var(--warn-border); border-radius: var(--r-voll); padding: 1px 7px; }
.pkSerie.hell { background: rgba(255,255,255,.55); border-color: transparent; }
#tabs .pkBadge { font-size: 0.7rem; font-weight: 700; margin-left: 2px; }

/* --- Das gemeinsame Ziel --- */
.pkTeam { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; background: var(--surface); }
.pkTeam.geschafft { border-color: var(--success-border); background: var(--success-bg); }
.pkTeamKopf { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: 0.86rem; font-weight: 600; }
.pkTeamKopf b { font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.pkTeamBalken { height: 8px; border-radius: var(--r-xs); background: var(--surface-2); overflow: hidden; margin: 8px 0 6px; }
.pkTeamBalken i { display: block; height: 100%; border-radius: var(--r-xs); background: var(--accent); transition: width .45s ease; }
.pkTeam.geschafft .pkTeamBalken i { background: var(--success); }
.pkTeamText { font-size: 0.78rem; color: var(--text-3); }

/* --- Podium und Rangliste --- */
.pkBlockKopf { display: flex; align-items: baseline; gap: 8px; font-size: 0.78rem; font-weight: 700; color: var(--text-3); margin-top: 2px; }
.pkBlockKopf span { font-weight: 400; color: var(--muted); }
.pkPodium { display: flex; align-items: flex-end; justify-content: center; gap: 8px; padding: 4px 0 0; }
.pkPlatz { flex: 1; max-width: 112px; display: flex; flex-direction: column; align-items: center; gap: 3px; text-align: center; }
.pkMedaille { font-size: 1.15rem; line-height: 1; }
.pkPlatzName { font-size: 0.78rem; font-weight: 600; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pkPlatzWert { font-size: 0.7rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.pkSockel {
  width: 100%; border-radius: var(--r-s) var(--r-s) 0 0; background: var(--surface-2); color: var(--muted);
  display: flex; align-items: flex-start; justify-content: center; font-size: 0.7rem; font-weight: 700; padding-top: 3px;
}
.pkPlatz.p1 .pkSockel { height: 38px; background: var(--warn-bg); background: color-mix(in srgb, var(--warn) 42%, var(--surface)); color: var(--warn-text); }
.pkPlatz.p2 .pkSockel { height: 26px; }
.pkPlatz.p3 .pkSockel { height: 18px; }

.pkRang { display: flex; flex-direction: column; gap: 6px; }
.pkZeile {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  min-height: 58px; padding: 8px 10px; border-radius: var(--r-m);
  border: 1px solid var(--border); background: var(--bg); color: var(--text); font: inherit; cursor: pointer;
}
.pkZeile:active { background: var(--surface); }
.pkZeile.selbst { border-color: var(--accent-border); background: var(--accent-bg); }
.pkZeileText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pkZeileName { font-size: 0.92rem; font-weight: 600; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pkDu { font-size: 0.7rem; font-weight: 700; color: var(--accent-strong); background: var(--bg); border: 1px solid var(--accent-border); border-radius: var(--r-voll); padding: 0 6px; }
.pkZeileStufe { font-size: 0.7rem; color: var(--muted); }
.pkZeileBalken { display: block; height: 6px; border-radius: var(--r-xs); background: var(--surface-2); overflow: hidden; margin-top: 2px; }
.pkZeileBalken i { display: block; height: 100%; border-radius: var(--r-xs); background: var(--success); transition: width .45s ease; }
.pkZeileWert { flex: none; font-size: 1.15rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.pkZeileWert span { font-size: 0.7rem; font-weight: 600; color: var(--muted); margin-left: 2px; }

/* --- Das Ziel (Belohnung) --- */
.pkZiel { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; background: var(--surface); }
.pkZiel.erreicht { border-color: var(--success-border); background: var(--success-bg); }
.pkZielKopf { font-size: 0.78rem; font-weight: 700; color: var(--text-3); margin-bottom: 6px; }
.pkZielZeile { display: flex; align-items: center; gap: 8px; }
.pkZielSymbol { flex: none; font-size: 1.15rem; line-height: 1.2; }
.pkZielName { flex: 1; min-width: 0; font-size: 0.92rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pkZielWert { flex: none; font-size: 0.78rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.pkZielBalken { height: 8px; border-radius: var(--r-xs); background: var(--surface-2); overflow: hidden; margin: 8px 0 6px; }
.pkZielBalken i { display: block; height: 100%; border-radius: var(--r-xs); background: var(--warn); transition: width .45s ease; }
.pkZiel.erreicht .pkZielBalken i { background: var(--success); }
.pkZielText { font-size: 0.78rem; color: var(--text-3); }
/* v3.99.0: 44 statt 40 - einheitlich-dom 3. */
.pkZielKnopf { margin-top: 8px; min-height: 44px; padding: 6px 12px; border-radius: var(--r-s); border: 1px solid var(--border-2); background: var(--bg); color: var(--text-2); font: inherit; font-size: 0.82rem; font-weight: 600; cursor: pointer; }

.pkFuss { display: flex; gap: 8px; flex-wrap: wrap; }
.pkFussKnopf { flex: 1 1 140px; min-height: 46px; border-radius: var(--r-m); border: 1px solid var(--border-2); background: var(--bg); color: var(--text-2); font: inherit; font-size: 0.86rem; font-weight: 600; cursor: pointer; }
.pkFussKnopf:active { background: var(--surface); }
.pkHinweisKasten { font-size: 0.82rem; color: var(--text-3); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; }
.pkPersonKopf { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }

/* v3.21.1: Die Stufenleiter im Blatt "Alle Stufen". Erreichte Stufen
   bleiben stehen (mit Haken) - der Weg dahinter ist die halbe Motivation. */
.pkStufenText.knopf {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  font: inherit; font-size: 0.78rem; color: var(--text-3); padding: 10px 0; min-height: 44px; cursor: pointer;
}
.pkStufenText.knopf:active { opacity: .7; }
.pkStufenPfeil { color: var(--muted-2); }
.pkLeiterKopf { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.pkLeiter { display: flex; flex-direction: column; gap: 2px; }
.pkLeiterZeile { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--r-s); border: 1px solid transparent; }
.pkLeiterZeile.erreicht { background: var(--surface); }
.pkLeiterZeile.hier { background: var(--accent-bg); border-color: var(--accent-border); }
.pkLeiterSymbol { flex: none; font-size: 1.3rem; line-height: 1.2; width: 28px; text-align: center; }
.pkLeiterZeile:not(.erreicht) .pkLeiterSymbol { filter: grayscale(1); opacity: .45; }
.pkLeiterText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.pkLeiterName { font-size: 0.92rem; font-weight: 600; }
.pkLeiterZeile:not(.erreicht) .pkLeiterName { color: var(--text-3); font-weight: 500; }
.pkLeiterHier { font-size: 0.7rem; font-weight: 700; color: var(--accent-strong); background: var(--bg); border: 1px solid var(--accent-border); border-radius: var(--r-voll); padding: 0 6px; margin-left: 4px; }
.pkLeiterAb { font-size: 0.7rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.pkLeiterBalken { display: block; height: 5px; border-radius: var(--r-xs); background: var(--surface-2); overflow: hidden; margin-top: 4px; }
.pkLeiterBalken i { display: block; height: 100%; border-radius: var(--r-xs); background: var(--success); }
.pkLeiterHaken { flex: none; width: 18px; text-align: center; color: var(--success); font-weight: 700; }

/* Ganz schmale Geraete: die drei Kacheln und das Podium duerfen enger. */
@media (max-width: 340px) {
  .pkKachel b { font-size: 0.92rem; }
  .pkKachel span { font-size: 0.7rem; }
  .pkZeileWert { font-size: 1rem; }
  .pkTagBalken { height: 32px; }
}
/* Wer Bewegung nicht mag, bekommt keine: die Balken springen dann sofort
   auf ihren Wert. */
@media (prefers-reduced-motion: reduce) {
  .pkStufenBalken i, .pkTagBalken i, .pkTeamBalken i, .pkZeileBalken i, .pkZielBalken i { transition: none; }
}

/* v3.28.0: Der Faustwert je Person steht mit seiner Einheit daneben –
   "2 Stück", "300 ml". Das Wort ist Beschriftung, kein Feld: Es darf
   nicht mitschrumpfen, wenn die Zahl breiter wird. */
#editModalFields .stJeKopfZeile { display: flex; align-items: center; gap: 8px; }
#editModalFields .stJeKopfZeile input { flex: 1 1 auto; min-width: 0; }
.stEinheitWort { flex: none; font-size: 15px; color: var(--leise); font-weight: 600; }

/* v3.29.0: Anmeldemaske - der Weg fuer Neue zuerst (wenn Konten offen),
   darunter, durch eine leise Zeile getrennt, die Familie. */
#setup button.kontoWeg { margin-bottom: 0; }

/* ============================================================
   v3.30.0: DER RUNDGANG BEWEGT SICH (Sören: "Könnte man es animieren?")
   Drei kleine Bewegungen, jede mit einem Grund:
     - die Karte faehrt herein (man merkt, dass etwas Neues dasteht)
     - die Chat-Blase kommt wie eine Nachricht, die Antwort der App einen
       Moment spaeter (die Reihenfolge IST die Botschaft: erst du, dann sie)
     - der aktive Punkt waechst (wo bin ich)
   Wer Bewegung abgeschaltet hat (prefers-reduced-motion), sieht alles
   sofort - nichts blinkt, nichts wartet.
   ============================================================ */
@keyframes tourEin { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes tourBlaseEin { from { opacity: 0; transform: translateX(-14px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes tourFolgeEin { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
#tourBody.tourNeu { animation: tourEin .28s ease-out; }
#tourBody.tourNeu .tourBlase { animation: tourBlaseEin .32s cubic-bezier(.2,.8,.3,1.2) both; animation-delay: .18s; }
#tourBody.tourNeu .tourFolge { animation: tourFolgeEin .3s ease-out both; animation-delay: .75s; }
#tourBody.tourNeu .tourListe li { animation: tourFolgeEin .28s ease-out both; }
#tourBody.tourNeu .tourListe li:nth-child(2) { animation-delay: .1s; }
#tourBody.tourNeu .tourListe li:nth-child(3) { animation-delay: .2s; }
#tourBody.tourNeu .tourListe li:nth-child(4) { animation-delay: .3s; }
#tourBody .tourPunkte span { transition: transform .25s ease, background-color .25s ease; }
#tourBody .tourPunkte span.aktiv { transform: scale(1.45); }
#tourBody .tourChat { position: relative; }
#tourBody .tourChat::after { content: "…"; position: absolute; right: 14px; top: 10px; font-size: 1rem; color: var(--text-3); opacity: 0; }
/* Die drei Punkte "tippt gerade": kurz da, weg, bevor die Antwort kommt. */
@keyframes tourTippen { 0%, 100% { opacity: 0; } 25%, 65% { opacity: 1; } }
#tourBody.tourNeu .tourChat::after { animation: tourTippen .8s ease-out both; }
/* v3.31.0: WISCHEN (Sören: "Natürlicher wäre, wenn man wischen kann").
   Der Browser darf im Rundgang nur senkrecht selbst scrollen; quer gehoert
   der Finger uns (pan-y), sonst kaemen die pointermove-Ereignisse nicht an.
   Waehrend des Wischens folgt die Karte dem Finger ohne Uebergang, beim
   Loslassen federt sie zurueck; die naechste Karte kommt aus der Richtung,
   in die man gewischt hat. */
#tourModal .modalBox { touch-action: pan-y; }
#tourBody { transition: transform .22s ease-out; }
#tourBody.wischt { transition: none; }
@keyframes tourEinVor { from { opacity: 0; transform: translateX(32px); } to { opacity: 1; transform: none; } }
@keyframes tourEinZurueck { from { opacity: 0; transform: translateX(-32px); } to { opacity: 1; transform: none; } }
#tourBody.tourNeu[data-richtung="vor"] { animation-name: tourEinVor; }
#tourBody.tourNeu[data-richtung="zurueck"] { animation-name: tourEinZurueck; }
#tourBody .tourWischHinweis { margin: -8px 0 12px; text-align: center; font-size: 0.78rem; letter-spacing: .04em; color: var(--text-3); }
@media (prefers-reduced-motion: reduce) {
  #tourBody.tourNeu, #tourBody.tourNeu .tourBlase, #tourBody.tourNeu .tourFolge, #tourBody.tourNeu .tourListe li { animation: none; opacity: 1; transform: none; }
  #tourBody .tourChat::after { display: none; }
  #tourBody .tourPunkte span { transition: none; }
  #tourBody { transition: none; }
}

/* v3.30.0: ANMELDEMASKE (Sören: "Kann die Anmeldemaske vereinfacht und
   verschönert werden?"). Ein Satz, der sagt, was chat-o ist; dann fuer
   Neue genau zwei Wege (anlegen / anmelden); die Familie darunter, kleiner
   und ruhig. Gilt nur, wenn Konten offen sind - sonst bleibt die Maske,
   wie die Familie sie kennt. */
/* v3.64.0: Die Startseiten-Regeln (v3.62.0) sind nach public/start.css gezogen -
   die Website hat ihr eigenes Stylesheet. Hier stand ein Rest, der die
   Kachel-Szenen mit 1,4 rem grossen Spans stoerte. */
/* v3.30.0: Rundgang-Titel dürfen umbrechen (kein „…“ auf schmalen Geräten),
   die zwei Hauptwege der Anmeldemaske sind breiter als die Familien-Knöpfe. */
#tourModal .modalKopf > span { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.25; }
#setup #setupKontoBtn, #setup #setupKontoAnmelden { width: 264px; max-width: 100%; }

/* ============================================================
   v3.33.0: TREFFBAR, OHNE GROESSER ZU WIRKEN (Paket 2)
   Eine Zeile Text als Knopf ist oft nur 18 bis 22 px hoch. Groesser
   setzen wuerde das Layout auseinanderziehen, deshalb dasselbe Mittel,
   das der Abhak-Kreis seit jeher nutzt: ein unsichtbares ::after, das
   die Trefferflaeche auf 44 px bringt. Sichtbar aendert sich nichts.
   ============================================================ */
.kalAufgabeText { position: relative; }
.kalAufgabeText::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  transform: translateY(-50%); height: 44px; min-height: 100%;
}
/* Links in einer Textzeile: die Box selbst wachsen lassen, aber den Zeilenfluss
   nicht verschieben.
   v3.160.8: nicht „Anrufen“ unter der Terminkarte (.tbChip) - das ist ein
   Feld mit eigenen 44 px in eigener Reihe, keine Textzeile (app.css
   .terminZeile .tbChip, seit v3.146.0). Bis v3.160.7 schlug die Feld-Regel
   diese mit dem Beta-Vorsatz (html.beta-…); ohne ihn wöge sie weniger
   (0,2,0 gegen 0,2,1). :where hält die Stärke dieser Regel, wie sie war. */
.item .ortLink, .feldHinweis .ortLink, .item .telLink, .item a[href^="tel:"]:where(:not(.tbChip)) {
  display: inline-block; padding-block: 13px; margin-block: -13px;
}
/* v3.142.0 (Befund D1 der Prüfung zu Sörens „Suche weiter nach fehlern,
   sicherheitslücken und Design Optimierungen“): Die Regel darüber gilt für
   Links IN einer Textzeile. In der Kontaktkarte stehen Nummer, Mail,
   Adresse und Webseite als BLÖCKE untereinander - dort zog der negative
   Rand jede Zeile 13 px in die vorige, und ein Tipp mittig auf die Nummer
   öffnete Google Maps. Eine Zeile der Karte ist ihre eigene 44-px-Fläche;
   gleich stark wie die Regel darüber und deshalb direkt darunter
   (LEITFADEN Teil 5: erst die Grundregel, dann die Ausnahme). */
.item a.ktZeile { display: flex; align-items: center; min-height: 44px; padding-block: 0; margin-block: 0; }
/* v3.142.0, Nachbesserung (Gegenprüfung vom 29.09.2026): .ortLink schneidet
   mit nowrap und Ellipse ab - in einem Flex-Kasten greift die Ellipse aber
   nicht (der Text ist ein anonymes Flex-Kind), bei 320 px stand „📍
   Hauptstraße 5, 12345 Muster“ hart abgeschnitten da. Eine Zeile der
   Kontaktkarte darf umbrechen; Platz hat die Karte dafür. */
.item a.ktZeile { white-space: normal; overflow-wrap: anywhere; text-overflow: clip; }

/* ============================================================
   v3.33.0: EINE CHIP-FORM (Paket 2)
   Fuer "Chip" gab es elf eigene Klassen mit sechs verschiedenen Hoehen
   (32, 34, 36, 40, 44) und fuenf Innenabstaenden. Nebeneinander sah das
   aus wie aus zwei Apps. Die Klassen bleiben - sie tragen Farbe und
   Zustand -, aber Hoehe, Rundung und Innenabstand kommen jetzt von hier.
   Damit ist jeder Chip auch treffbar, was fuenf von ihnen nicht waren.
   ============================================================ */
.ladenChip, .gFilter, .vorratChip, .vfChip, .pfChip, .evChip, .woandersChip,
.teilWahlChip, .evKlassikerChip {
  /* .wahlChip fehlt hier bewusst: den gibt es nur auf der Gäste-Seite, und
     die bringt ihr eigenes Stylesheet mit (gast.html). Dort sind die Chips
     laut Messung bereits 44 bis 48 px hoch. */
  min-height: 44px;
  padding: 8px 14px;
  border-radius: var(--r-voll);
  font-size: 0.82rem;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}

/* ============================================================
   v3.35.0: DER KRINGEL BEIM ZIEHEN (Paket 3b)
   Er schwebt über der Liste und verschiebt nichts - die Liste selbst
   bleibt, wo sie ist, damit beim Loslassen nichts springt.
   ============================================================ */
/* v3.81.0 (Sören: "wird teilweise gar nicht oder nicht korrekt angezeigt.
   Schönere moderne Animation"): Eine Scheibe mit Schatten, die beim Ziehen
   wächst und deutlicher wird (--anteil 0…1 aus app-gesten.js); darin ein
   Pfeil, der sich mit dem Weg umdreht und ab der Schwelle blau wird. Beim
   Laden weicht der Pfeil einem drehenden Ring. Gleich auf jeder Seite. */
.ziehKringel {
  position: absolute; left: 0; right: 0; top: 0; height: 0;
  display: flex; align-items: flex-end; justify-content: center;
  pointer-events: none; z-index: 3;
  transform: translateY(var(--zieh, 0px));
  transition: transform .18s ease-out;
}
.ziehKringel.laeuft { transition: transform .22s ease-out; }
.ziehRing {
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; margin-bottom: 8px; border-radius: var(--r-kreis);
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-2);
  transform: scale(calc(0.55 + 0.45 * var(--anteil, 0)));
  opacity: calc(0.3 + 0.7 * var(--anteil, 0));
  transition: transform .12s ease-out, opacity .12s ease-out, border-color .15s;
}
.ziehPfeil { width: 18px; height: 18px; color: var(--muted); transform: rotate(calc(180deg * var(--anteil, 0))); transition: transform .12s ease-out, color .15s; }
.ziehKringel.bereit .ziehRing { border-color: var(--accent); }
.ziehKringel.bereit .ziehPfeil { color: var(--accent); }
.ziehRad { display: none; width: 18px; height: 18px; border-radius: var(--r-kreis); border: 2.5px solid var(--border-2); border-top-color: var(--accent); }
.ziehKringel.laeuft .ziehPfeil { display: none; }
.ziehKringel.laeuft .ziehRad { display: block; animation: ziehDreht .7s linear infinite; }
@keyframes ziehDreht { to { transform: rotate(360deg); } }
/* Jeder Bereich braucht einen Bezugspunkt, sonst sitzt die Scheibe am
   Fenster statt oben in der Liste - so war es bis v3.80 in der Raumliste
   und im Chat ("wird gar nicht angezeigt"). */
#listView, #termineView, #todosView, #essenView,
#heuteView, #kontakteView, #ausgabenView, #punkteView,
#raumView, #messages, #ideenView, #mehrView, #phasenView,
#eventPlanView, #eventGaesteView, #mitbringenView, #kostenView { position: relative; }
/* v3.52.0: Ohne diese Regel deutet ein Chromium-Browser (Android) die
   Querbewegung als Scrollversuch und bricht die Zeigerfolge mit
   pointercancel ab - der Reiter-Wisch kam dort nie ueber die ersten
   Pixel hinaus (die Probe mit echten Touch-Ereignissen zeigte es).
   Erlaubt bleiben senkrechtes Rollen und das Zoomen mit zwei Fingern;
   quer scrollbare Kinder und die Zeilen-Wische regeln sich selbst. */
/* ============================================================
   v3.85.0 (Sören: "Scrollen wirkt immer noch sehr unschön"): DIE DRITTE
   ABGESCHRIEBENE LISTE.

   Hier standen elf Flächen mit Namen - und es fehlten dieselben vier wie
   in REITER_FLAECHEN: die der Feier. Ohne `touch-action: pan-y` darf der
   Browser senkrechtes Scrollen nicht selbst übernehmen; er muss bei JEDER
   Fingerbewegung auf JavaScript warten (der Wisch-Zuhörer läuft mit
   { passive: false }). Genau das fühlt sich zäh an - und in der Feier
   fühlte es sich anders an als im Haushalt.

   Jetzt aus der ROLLE abgeleitet: Jede Reiterfläche trägt
   role="tabpanel" (index.html), also greift die Regel auf jeder - auch
   auf jeder künftigen. LEITFADEN.md Teil 1.
   ============================================================ */
[role="tabpanel"] { touch-action: pan-y pinch-zoom; }

/* Die Nachbarseite, die beim Wischen als Vorschau danebenliegt. Ihr
   display stand bisher als "block" im JS - #chatView braucht aber flex
   (app.js switchTab setzt es selbst so), sonst verliert die
   Nachrichtenliste ihr flex:1 und das Textfeld rutscht unter die letzte
   Nachricht statt an den Rand. Beim Abräumen sprang es dann an seinen
   Platz: Sörens "das Textfeld springt bei Chat rein beim wischen".
   Zwei Wahrheiten über dieselbe Sache - jetzt eine, und zwar hier. */
/* !important, weil switchTab das display INLINE setzt (style.display =
   "none") - eine Klassenregel kaeme dagegen nicht an. Genau deshalb stand
   der Wert frueher im JS; jetzt steht er hier, aber stark genug. */
.reiterNachbar { display: block !important; }
#chatView.reiterNachbar { display: flex !important; }
@media (prefers-reduced-motion: reduce) {
  .ziehKringel { transition: none; }
  .ziehKringel.laeuft .ziehRad { animation: none; }
  .ziehRing, .ziehPfeil { transition: none; }
}

/* v3.35.0 (Paket 3b): Das Menue zum langen Druecken. Es sitzt unten wie
   ein Blatt, hat 44 px hohe Zeilen und nennt genau die Wege, die die
   Zeile ohnehin kennt. */
#halteMenue { position: fixed; inset: 0; z-index: 260; background: rgba(0,0,0,0.38);
  display: flex; align-items: flex-end; justify-content: center;
  padding: 0 8px calc(8px + var(--sab)); }
#halteMenue .halteBlatt { width: 100%; max-width: var(--blatt-breit);
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  border-radius: var(--r-l); padding: 6px; box-shadow: var(--shadow-leiste);
  animation: halteAuf .16s ease-out; }
#halteMenue .halteTitel { font-size: 0.82rem; color: var(--text-3); font-weight: 600;
  padding: 10px 12px 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#halteMenue .halteKnopf { display: block; width: 100%; min-height: 44px; text-align: left;
  background: transparent; color: var(--text); border: 0; border-radius: var(--r-m);
  padding: 10px 12px; font-size: 0.95rem; cursor: pointer; }
#halteMenue .halteKnopf:hover, #halteMenue .halteKnopf:focus-visible { background: var(--surface); }
#halteMenue .halteKnopf:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
#halteMenue .halteKnopf.gefahr { color: var(--danger); font-weight: 600; }
#halteMenue .halteKnopf.abbrechen { margin-top: 4px; border-top: 1px solid var(--border);
  border-radius: 0 0 var(--r-m) var(--r-m); color: var(--text-2); text-align: center; }
@keyframes halteAuf { from { transform: translateY(14px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { #halteMenue .halteBlatt { animation: none; } }
#halteMenue .halteBlatt:focus { outline: none; }

/* ============================================================
   v3.36.0 (Paket 4): LADEZUSTAND
   Bisher zeigte jede Liste vor der ersten Antwort ihren LEERTEXT
   ("Noch nichts auf der Liste"). Das ist eine Aussage über die Daten,
   die zu dem Zeitpunkt niemand treffen kann - und sie ist meistens
   falsch. Das Gerippe sagt stattdessen: "gleich".
   ============================================================ */
.ladeGerippe { padding: 4px 0; }
.ladeGerippe .gz { height: 52px; border-radius: var(--r-m); margin-bottom: 8px;
  background: var(--surface); position: relative; overflow: hidden; }
.ladeGerippe .gz::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--surface-2), transparent);
  transform: translateX(-100%); animation: gerippeWandert 1.3s ease-in-out infinite; }
.ladeGerippe .gz:nth-child(2)::after { animation-delay: .12s; }
.ladeGerippe .gz:nth-child(3)::after { animation-delay: .24s; }
.ladeGerippe .gz:nth-child(4)::after { animation-delay: .36s; }
@keyframes gerippeWandert { to { transform: translateX(100%); } }
.ladeSatz { color: var(--text-3); font-size: 0.86rem; padding: 10px 2px;
  display: flex; align-items: center; gap: 8px; }
.ladeSatz::before { content: ""; width: 14px; height: 14px; flex: none;
  border-radius: var(--r-kreis); border: 2px solid var(--border-2); border-top-color: var(--accent);
  animation: ziehDreht .8s linear infinite; }
@media (prefers-reduced-motion: reduce) {
  .ladeGerippe .gz::after { animation: none; }
  .ladeSatz::before { animation: none; }
}
/* v3.36.0 (Paket 4): Leer- und Fehlerzustand von Listen - beide mit Weg. */
.listeFehler, .listeLeer { color: var(--text-3); padding: 20px 12px; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 10px; }
.listeLeerHinweis { font-size: 0.86rem; color: var(--muted); }
/* v3.36.0 (Paket 4): Die Anmeldemaske stellt sich nach dem Netzabruf um.
   Bis dahin bleibt sie verdeckt - sonst springen die Knöpfe. */
#setupRole.wartet { position: relative; min-height: 220px; }
#setupRole.wartet > * { visibility: hidden; }
#setupRole.wartet::after { content: "Einen Moment …"; visibility: visible;
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--text-3); font-size: 0.92rem; }
/* v3.36.0 (Paket 4): Ein Feld, dem etwas fehlt. */
input.mangel, textarea.mangel, select.mangel { border-color: var(--danger) !important; }
.mangelSatz { color: var(--danger); font-size: 0.78rem; margin: 4px 0 0; }
/* v3.36.0 (Paket 4, Befund A16): Namen zum Antippen unter „Nur für“. */
.blFuerChips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
/* v3.36.0 (Paket 4, Befund S4): „Zeigen“ am Tool-Key-Feld. */
.keyZeile { display: flex; gap: 8px; align-items: center; justify-content: center; }
.keyZeile input { flex: none; }
.keyZeigen { min-height: 44px; padding: 8px 12px; border-radius: var(--r-m);
  border: 1px solid var(--border); background: var(--surface); color: var(--text-2);
  font-size: 0.86rem; cursor: pointer; }
/* v3.36.0 (Paket 4, Befund A31): Schnellwahl für die Frist. */
.fristSchnell { display: flex; flex-wrap: wrap; gap: 6px; }
.fristSchnell button { min-height: 44px; padding: 8px 12px; border-radius: var(--r-voll);
  border: 1px solid var(--border); background: var(--surface); color: var(--text-2);
  font-size: 0.82rem; cursor: pointer; }
.fristSchnell button:hover { background: var(--surface-2); }
/* v3.36.0 (Paket 4): Das Eingabefeld im Frage-Fenster. */
#frageFeldBox { margin: 4px 0 12px; }
#frageFeldBox input { width: 100%; }

/* ============================================================
   v3.37.0 (Paket 5): NUR FÜR VORLESEHILFEN
   Sichtbar für Vorlesehilfen, unsichtbar auf dem Bildschirm - und ohne
   die Seite zu verschieben. Bewusst nicht display:none: das nähme das
   Element auch aus dem Vorlesebaum.
   ============================================================ */
.nurVorleser {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* v3.37.0 (Paket 5, Befund C2): Die Systemzeile ist ein Bedienelement -
   dahinter steckt „↩︎ Rückgängig“. Der Pfeil sagt das, ohne Platz zu
   kosten; er dreht sich, wenn die Zeile offen ist. */
.systemNote .sysPfeil { flex: none; margin-left: auto; color: var(--muted-2);
  transition: transform .15s ease-out; }
.systemNote.offen .sysPfeil { transform: rotate(90deg); }
.systemNote:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-s); }
@media (prefers-reduced-motion: reduce) { .systemNote .sysPfeil { transition: none; } }

/* v3.142.1 (Sören, 29.09.2026, mit Bild der Staging-Demo: „In dem zuge
   bitte mehrere ki Nachrichten zusammenfassen damit der chat wieder ruhiger
   wird.“): Graue Zeilen, die zusammen entstanden sind, stehen als EINE
   (app-chat.js sysGruppeFolge). Der Kopf IST eine graue Zeile (.systemNote:
   derselbe Rand, dieselben 44 px, derselbe Pfeil, der sich beim Öffnen
   dreht); darunter, eingerückt, die Zeilen der Gruppe - jede wie immer.
   Zugeklappt sind sie weg, AUSSER eine fragt gerade etwas („Auch in die
   geteilte Liste?“, .sysTeilen): Eine offene Frage verschwindet nie in einer
   Gruppe. Grundregel zuerst, die Ausnahme danach (LEITFADEN Teil 5). */
.sysGruppe { align-self: stretch; max-width: 100%; display: flex; flex-direction: column; gap: 5px; flex-shrink: 0; }
.sysGruppe > .sysGlieder { display: flex; flex-direction: column; gap: 5px; margin-left: 12px; }
.sysGruppeKopf:not(.offen) + .sysGlieder { display: none; }
.sysGruppeKopf:not(.offen) + .sysGlieder:has(> .systemNote > .sysTeilen:not(:empty)) { display: flex; }
.sysGruppeKopf:not(.offen) + .sysGlieder > .systemNote:not(:has(> .sysTeilen:not(:empty))) { display: none; }
.sysGruppeKopf .sysMehr { flex: none; font-weight: 600; color: var(--text-3); white-space: nowrap; }
/* Steht im Kopf die erste Zeile („… und 2 weitere“), höchstens zwei Zeilen
   hoch - sonst wäre die EINE Zeile so lang wie vorher. Ganz lesen lässt sie
   sich aufgeklappt; die Vorlesehilfe liest sie ohnehin ganz. */
.sysGruppeKopf .sysText { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }

/* v3.142.1 (Sören: „Und den hinweis kleiner gestalten, und ohne emoji.“):
   Der Hinweis „Nicht erkannt – …“ (kiHinweis, raum-ki.js
   meldeKlassifikationsFehler) ist leiser als eine graue Zeile, die etwas
   eingetragen hat: eine Stufe kleiner (0.78rem statt 0.82rem, beide aus der
   Schriftleiter), eine leisere Schrift (--leise-2: hell 4,9:1, dunkel
   5,7:1 auf dem Grund des Chats statt 5,8:1 und 6,8:1 einer grauen Zeile -
   gemessen in chat-ruhig-dom.mjs H1d) und nur die Haarlinie als Rand.
   Bedienbar bleibt sie wie jede graue Zeile (44 px).
   Prüfung v3.142.1: Bis dahin stand hier --leise - im dunklen Thema derselbe
   Wert wie --muted, der Hinweis war dort nur 0,64 px kleiner, nicht leiser.
   Aufgeklappt steht der ganze Satz des Servers beim Deckel
   (.sysErklaerung) auf voller Breite. */
.systemNote.leise { font-size: 0.78rem; color: var(--leise-2); border-left-color: var(--border); }
.systemNote .sysErklaerung { flex: 1 0 100%; line-height: 1.35; }

/* v3.38.0 (Sörens Befund „man muss diese wieder suchen“): Der eben
   bearbeitete oder angelegte Eintrag leuchtet kurz auf. Kein Blinken -
   ein weicher Ring, der wieder verschwindet. */
.frischHervor { animation: frischHervorAn 2.2s ease-out; border-radius: var(--r-m); }
@keyframes frischHervorAn {
  0%   { box-shadow: var(--ring-0) var(--accent-bg); background: var(--accent-bg); }
  15%  { box-shadow: var(--ring-3) var(--accent); background: var(--accent-bg); }
  100% { box-shadow: var(--shadow-keiner); background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .frischHervor { animation: none; outline: 2px solid var(--accent); outline-offset: 2px; }
}

/* v3.39.0: Der Streifen "neue Fassung ist da". Er sitzt ueber der
   Reiterleiste, damit er nichts verdeckt, was man gerade liest, und
   verschwindet erst, wenn man ihn wegtippt oder neu laedt. Vorher stand
   dort eine Kurzmeldung, die nach zwei Sekunden weg war - deshalb lief
   Sörens Handy tagelang auf einer alten Fassung weiter. */
#fassungStreifen { position: fixed; left: 12px; right: 12px; z-index: 300;
  bottom: calc(var(--sab) + 68px);
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-radius: var(--r-m);
  background: var(--accent-bg); color: var(--accent-strong);
  border: 1px solid var(--accent); box-shadow: var(--shadow-2);
  font-size: 0.86rem; }
#fassungStreifen .fassungText { flex: 1 1 auto; min-width: 0; }
#fassungStreifen .fassungJetzt { flex: 0 0 auto; min-height: 36px; padding: 6px 12px; font-size: 0.86rem; }
#fassungStreifen .fassungSpaeter { flex: 0 0 auto; min-width: 36px; min-height: 36px;
  background: none; border: none; color: inherit; font-size: 0.92rem; cursor: pointer; border-radius: var(--r-s); }
#fassungStreifen .fassungSpaeter:active { background: rgba(0,0,0,.08); }

/* v3.39.0: Das Einladungs-Schreibfeld ist von vornherein gross - eine
   Einladung ist kein Einzeiler. */
.evTextGross { min-height: 180px; line-height: 1.45; }

/* ============================================================
   v3.40.0 (Sören: "Wischgesten zwischen den Reitern immer noch nicht
   schön"): Die neue Seite gleitet herein, statt einfach da zu sein.
   Zusammen mit dem Hinausgleiten der alten (in reiterWischBinden) wird
   aus zwei Sprüngen eine Bewegung. Wer weniger Bewegung eingestellt hat,
   bekommt weiter den direkten Wechsel.
   ============================================================ */
/* v3.41.0 (Sören: "sehr langsam und träge. Wirkt billig"): Die neue Seite
   kommt weiter aussen her und schneller an - 140 ms statt 200, und ohne
   Einblenden. Sie faehrt herein, sie erscheint nicht. */
@keyframes reiterHereinRechts {
  from { transform: translateX(60%); }
  to   { transform: translateX(0); }
}
@keyframes reiterHereinLinks {
  from { transform: translateX(-60%); }
  to   { transform: translateX(0); }
}
/* Waehrend die Seite mitgeht, ist sie eine Karte: gerundet, mit Schatten
   und ein Stueck zurueckgetreten. Ohne das sieht der freigelegte Grund
   daneben nach Loch aus statt nach Absicht. */
/* v3.41.0: Kein Schatten mehr - der liess die Seite wie einen Aufkleber
   wirken. Nur die Rundung bleibt, damit die Kante nicht hart an den
   freigelegten Grund stoesst. */
/* v3.151.2: Die Rundung schneidet clip-path ab, nicht overflow: hidden.
   overflow: hidden machte die Fläche für die Dauer des Wischs unrollbar -
   und blieb ein Wisch hängen, weil sein Ende nie ankam (App gewechselt),
   rollte sie gar nicht mehr (Sören: „kann ich in chato nicht mehr
   scrollen“; gesten-pause-dom P4). clip-path zeichnet dieselbe Ecke und
   lässt das Rollen, wie es ist. */
.reiterZieht { border-radius: var(--r-m); will-change: transform; clip-path: inset(0 round var(--r-m)); }
/* v3.42.0: Die Nachbarseite waehrend der Geste. Sie ist aus dem Fluss
   genommen (fest an die Stelle der aktuellen gesetzt) und braucht deshalb
   ihren eigenen Grund - sonst schiene die alte Seite durch sie hindurch. */
.reiterNachbar { z-index: 3; background: var(--bg); border-radius: var(--r-m);
  overflow: hidden; will-change: transform; }
/* v3.43.0: 200 ms und die ruhigere Kurve - 140 ms mit der scharfen Kurve
   war ein Schnalzer. Dieser Weg wird nur noch beschritten, wenn es keine
   Nachbarseite gibt (Reiter noch nie geoeffnet). */
.reiterVonRechts { animation: reiterHereinRechts .2s cubic-bezier(.25,.6,.25,1); }
.reiterVonLinks  { animation: reiterHereinLinks  .2s cubic-bezier(.25,.6,.25,1); }
@media (prefers-reduced-motion: reduce) {
  .reiterVonRechts, .reiterVonLinks { animation: none; }
}


/* ============================================================
   v3.49.0 (Paket 6b): RECHNER UND TABLET
   Bis hierher hatte das Stylesheet keine einzige min-width-Regel: Bei
   1280 Pixeln nutzte die App 480, der Rest blieb leer (Befunde S72, C17,
   A22, D68). Drei Stufen:
     ab 600 px: die Saeule bekommt Rand und Schatten, damit sie nicht
                kantenlos im Weiss steht, und wird 600 breit - so passt
                jedes Blatt (--blatt-breit 520) HINEIN statt darueber
                hinaus (Befund D39).
     ab 900 px: zwei Spalten - links die Raumliste, rechts der Raum.
     Modale bleiben, wie sie sind: sie sind fixiert und mittig.
   ============================================================ */
#breitLeer { display: none; }

@media (min-width: 600px) {
  #app {
    max-width: 600px;
    border-left: 1px solid var(--border);
    border-right: 1px solid var(--border);
    box-shadow: var(--shadow-1);
  }
  /* Mit 600 px Breite brauchen die Saeule und ihre Zeilen etwas mehr Luft. */
  #raumView { padding-left: 16px; padding-right: 16px; }
}

@media (min-width: 900px) {
  #app {
    max-width: 1180px;
    display: grid;
    /* Linke Spalte fest, rechte nimmt den Rest - minmax(0, …), damit ein
       breiter Inhalt (Chat, Tabelle) die Spalte nicht sprengt. */
    grid-template-columns: 320px minmax(0, 1fr);
    /* Reihen: Update-Band, Laden-Band, Raumkopf, Reiter, Flaeche, Version.
       Leere Reihen (versteckte Baender) fallen auf 0 zusammen; die Flaeche
       nimmt den Rest. */
    grid-template-rows: auto auto auto auto minmax(0, 1fr) auto;
    column-gap: 0;
  }
  /* Jedes Kind landet ausdruecklich in seiner Reihe - sonst rutschen die
     Reihen, sobald ein Band erscheint. */
  #app > * { grid-column: 2; }
  #updateBanner { grid-row: 1; }
  #ladenBanner { grid-row: 2; }
  #raumKopf { grid-row: 3; }
  #tabs { grid-row: 4; }
  #app > [role="tabpanel"], #chatView, #phasenView, #breitLeer { grid-row: 5; min-height: 0; }
  #versionTag { grid-row: 6; }
  /* Die Raumliste: linke Spalte, ueber alle Reihen, IMMER sichtbar - auch
     wenn app.js sie beim Betreten eines Raums ausblendet (inline-Stil). */
  #raumView {
    grid-column: 1; grid-row: 1 / 7;
    display: block !important;
    border-right: 1px solid var(--border);
    padding-left: 12px; padding-right: 12px;
  }
  /* Die linke Spalte ist 320 px breit - so schmal wie ein kleines Handy.
     Deshalb gelten hier dieselben Kuerzungen wie dort: Kalenderwoche weg,
     Ueberschrift eine Stufe kleiner, Luft zwischen Wort und Datum (seit
     26.10.2026 vom Wort selbst, margin-right 8 px; hier 10 px Rand am
     Datum, 4 px zu den Knoepfen: jeder Pixel zaehlt bei vier Knoepfen). */
  .raumeDatum .rdKw { display: none; }
  .raumKopfzeile h2 { font-size: 1.4rem; }
  .raumeDatum { margin-right: 4px; }
  /* Die Knöpfe sind 44-px-Flächen mit rund 11 px Luft um das Zeichen: in der
     295 px breiten Zeile (Wort 82 px) bleiben ohne den 6-px-Abstand dazwischen
     Platz für fünf (Beta-Schriftzug, Helfer, Ordnen, Einstellungen, Konto). */
  .raumKopfKnoepfe { gap: 0; }
  /* Der Raum steht daneben - ein "‹ Räume" fuehrt nirgendwohin. */
  #raumZurueck { display: none; }
  /* Welcher Raum ist offen? */
  .raumEintrag.aktiv { background: var(--accent-bg); }
  .raumEintrag.aktiv .raumName > span:first-child { color: var(--text); }
  /* Platzhalter, solange rechts nichts offen ist. */
  #breitLeer { align-items: center; justify-content: center; color: var(--muted); text-align: center; font-size: 1.05rem; line-height: 1.6; }
  #breitLeer .breitLeerText { font-size: 1.05rem; }
  #breitLeer .breitLeerText::first-line { font-size: 2.4rem; }
  body:not(.inRaum) #breitLeer { display: flex; }
  /* Chat: 75 % von 850 px waeren Zeilen mit 120 Zeichen - schwer zu lesen. */
  .bubble { max-width: min(75%, 560px); }
  /* Termine (Befund B42): Monatsgitter links, der gewaehlte Tag rechts
     daneben statt darunter. Die Reihenfolge im HTML bleibt unveraendert. */
  #kalenderBox { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 20px; align-items: start; }
  #kalenderBox > * { grid-column: 1; }
  #kalenderBox > #kalTagBereich { grid-column: 2; grid-row: 1 / span 6; }
}

/* v3.49.0 (Paket 6b, Befund C21): Bei offener Tastatur blieben Raumkopf und
   Reiterleiste stehen. Auf einem 320 x 568-Geraet blieben dem Verlauf rund
   150 px - zwei Blasen. Messenger blenden die Kopfzeile beim Tippen aus.
   Nur auf dem Handy; die Reiter bleiben, damit der Balken nicht springt. */
@media (max-width: 480px) {
  body.tastatur #raumKopf { display: none !important; }
}

/* v3.50.0: Ort-Vorschlaege waehrend des Tippens (app.js orteAnbinden).
   Die Liste steht im Textfluss direkt unter dem Feld - kein schwebendes
   Element, das auf dem Handy unter der Tastatur verschwinden koennte.
   In einer Flex-Zeile mit Umbruch oder einem Raster (Termin-Formular)
   nimmt sie eine ganze Reihe. Kind-Selektoren mit zwei Klassen, damit
   die Regeln der Formulare (.addForm button, #editModalFields ...) nichts
   davon uebersteuern. */
.ortVorschlaege { width: 100%; flex: 1 1 100%; grid-column: 1 / -1; box-sizing: border-box; margin: 4px 0 0; padding: 0;
  border: 1px solid var(--border-2); border-radius: var(--radius); background: var(--bg); box-shadow: var(--shadow-2); overflow: hidden; }
.ortVorschlaege > .ortVorschlag { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: auto; margin: 0;
  border: 0; border-bottom: 1px solid var(--border); border-radius: 0; background: var(--bg); padding: 8px 12px; min-height: 44px;
  box-sizing: border-box; font: inherit; font-size: 1rem; color: var(--text); cursor: pointer; text-align: left; -webkit-tap-highlight-color: transparent; }
.ortVorschlaege > .ortVorschlag:last-of-type { border-bottom: 0; }
.ortVorschlaege > .ortVorschlag[aria-selected="true"], .ortVorschlaege > .ortVorschlag:hover { background: var(--surface); }
.ortVorschlaege > .ortVorschlag b { font-weight: 600; font-size: 0.92rem; color: var(--text); }
.ortVorschlaege > .ortVorschlag span { font-size: 0.78rem; color: var(--muted); }
.ortVorschlaege > .ortQuelle { font-size: 0.7rem; color: var(--muted-2); background: var(--bg); padding: 4px 12px 6px; margin: 0; text-align: right; border-top: 1px solid var(--border); }
/* v3.164.0 (Beta „adress-vorschlag“): Statt einer Liste ein Satz - etwa,
   dass die Ortsvorschläge für heute aufgebraucht sind. Kein Schatten, kein
   Rahmen einer Liste: Es gibt nichts zu wählen. Das Element entsteht nur
   mit Beta (app-gesten.js orteHinweis) - ohne Beta greift die Regel nie. */
.ortVorschlaege.ortNurHinweis { border: 0; box-shadow: none; background: transparent; }
.ortVorschlaege > .ortHinweis { font-size: 0.78rem; color: var(--muted); padding: 2px 2px 4px; margin: 0; line-height: 1.4; }

/* v3.146.0 (Sören: „Einkaufsliste vorschlagen (bei neuem artikel
   hinzugefügt nach 2oder 3 Buchstaben vorschläge anzeigen mit den meist
   gekauften dingen zuerst …)“; seit v3.160.9 für alle, aus Beta
   „einkauf-vorschlaege“ freigegeben): die Liste unter dem Feld einer
   neuen Besorgung (app-liste.js artikelVorschlagZeichnen). Dieselbe Bauart
   wie die Ort-Vorschläge darüber - im Textfluss, nicht schwebend, damit sie
   auf dem Handy nicht unter der Tastatur verschwindet. Jede Zeile 44 px,
   der Name links (was getippt ist, fett), rechts leise der übliche Laden
   oder „steht schon drauf“. Die mit Pfeiltasten gewählte Zeile trägt einen
   Rahmen in der Akzentfarbe - der Ton allein (--surface auf --bg) ist zu
   schwach, um ihn ohne Maus zu finden. */
.artikelVorschlaege { display: block; width: 100%; grid-column: 1 / -1; box-sizing: border-box; margin: 4px 0 12px; padding: 0;
  border: 1px solid var(--border-2); border-radius: var(--radius); background: var(--bg); box-shadow: var(--shadow-2); overflow: hidden; }
.bsBlattTitelHuelle + .artikelVorschlaege { margin-top: -6px; }
.artikelVorschlaege > .artikelVorschlag { display: flex; align-items: center; gap: 10px; min-height: 44px; margin: 0; padding: 8px 12px;
  box-sizing: border-box; border-bottom: 1px solid var(--border); background: var(--bg); color: var(--text); font-size: 1rem; line-height: 1.3;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  /* Nachbesserung (Prüfung vom 05.10.2026): Ruht der Finger länger auf
     einer Zeile, soll das iPhone weder das Wort markieren noch ein Menü
     zeigen - der Tipp übernimmt den Vorschlag (auf dem Gerät ungeprüft). */
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.artikelVorschlaege > .artikelVorschlag:last-child { border-bottom: 0; }
.artikelVorschlaege > .artikelVorschlag[aria-selected="true"] { background: var(--surface); outline: 2px solid var(--accent); outline-offset: -2px; }
@media (hover: hover) {
  .artikelVorschlaege > .artikelVorschlag:hover { background: var(--surface); }
}
/* Nachbesserung: In der eigenen Zeile der Feier-Einkaufsliste steht die
   Liste IN der Zeile (event-planung.js einkaufZeileDazu). Eine Zeile ohne
   Menge ist auf 85 % gedimmt (.ekZeile.ohneMenge) - das dimmte die Liste
   mit. Die eigene Zeile, in der man gerade tippt, steht voll da (nur die
   eigenen Zeilen haben Vorschläge). */
.ekGruppe.eigene .ekZeile:focus-within { opacity: 1; }
.ekZeile > .artikelVorschlaege { margin: 2px 0 6px; }
.artikelVorschlag .avName { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.artikelVorschlag .avName b { font-weight: 700; }
.artikelVorschlag .avNeben { flex: 0 1 auto; min-width: 0; max-width: 55%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 0.78rem; color: var(--muted); }

/* ============================================================
   v3.51.0: AUFRAEUM-DURCHGANG - Kleinigkeiten aus der Abschlussliste
   ============================================================ */
/* S5: Rechtliches auf der Anmeldemaske - klein, aber 44 px hoch treffbar. */
#setup .setupRecht { margin: 4px 0 0; display: flex; gap: 4px; font-size: 0.78rem; }
#setup .setupRecht a { color: var(--text-3); display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px; text-decoration: underline; text-underline-offset: 3px; }
/* F8: .knopfKlein hatte keine Grundregel - "+ Punkt", "+ Antwort", "Als Liste
   kopieren" fielen auf das Browser-Aussehen zurueck. Eine Form, 44 px. Die
   Kontextregeln (.geraetHilfe, .gsSuchZeile) gelten weiter. */
.knopfKlein { min-height: 44px; padding: 0 12px; border: 1px solid var(--border-2); background: var(--surface); border-radius: var(--r-s);
  font: inherit; font-size: 0.86rem; font-weight: 600; color: var(--text-2); cursor: pointer; }
.knopfKlein:active { background: var(--surface-2); }
/* C19: Beim Wisch nach rechts an einer Blase sah man nur den ↩-Kreis. Ab der
   Schwelle bekommt die Blase einen Rand in Akzentfarbe (und einen Stups). */
/* C30: Rueckgaengig-Leiste und Kurzmeldung lagen uebereinander, wenn beide
   kamen ("Abgehakt." + "… entfernt · Rueckgaengig"). Ist die Leiste offen,
   rueckt die Kurzmeldung darueber. */
.kurzMeldung.hoeher { bottom: calc(160px + var(--sab)); }
/* D53: Bei 320 px sind sieben Kalendertage je 38,9 px breit; das Quadrat
   machte sie auch so hoch. Unter 360 px zaehlt die Hoehe, nicht das Quadrat. */
@media (max-width: 359px) {
  .kalTag { aspect-ratio: auto; min-height: 44px; }
}

/* ============================================================
   v3.52.0: FUENF REITER PLUS "MEHR"
   Unter 900 px verschwinden die Reiter mit .imMehr aus der Leiste (der
   Raumtyp setzt die Klasse in raumTypAnwenden) und der Mehr-Knopf zeigt
   sie in einem Blatt. Ab 900 px ist Platz fuer alle - dann ist der
   Mehr-Knopf weg und nichts liegt hinter einer zweiten Ebene.
   ============================================================ */
/* v3.81.0: Die Regel "unter 899 px .imMehr ausblenden" ist weg - kein
   Reiter liegt mehr hinter "Mehr" (app.js raumTypAnwenden setzt die Klasse
   nicht mehr); die Leiste wischt seitlich wie vor v3.52.0. */
@media (min-width: 900px) {
  #tabMehrMenue { display: none !important; }
}
/* v3.95.0: HIER stand die Regel, die alles kleiner machte - 0,78 rem auf
   jedem Handy, mit der Begründung "dann passen sie in 390 px". Genau das
   war Sörens Befund: „Die reiter viel zu klein beschriftet." Die Leiste
   wischt seitlich, wenn es eng wird; das ist die Antwort auf zu wenig
   Platz, nicht unlesbare Schrift. Das Polster bleibt enger als am großen
   Bildschirm - Platz sparen an der Luft ist in Ordnung, an der Schrift
   nicht. */
@media (max-width: 480px) {
  :where(#tabs) button { padding: 15px 8px 11px; }
}
#tabMehrMenue .mehrWort::after { content: " ▾"; font-size: 0.7em; opacity: .7; }
#tabMehrMenue .mehrPunkt { display: inline-block; width: 7px; height: 7px; border-radius: var(--r-kreis); background: var(--success); margin-left: 4px; vertical-align: middle; }
#halteMenue .halteKnopf.aktiv { font-weight: 700; color: var(--text); }
#halteMenue .halteKnopf.aktiv::after { content: " ✓"; color: var(--success-text); }

/* ============================================================
   v3.77.0: EINSTELLUNGEN - Zurueck-Wisch wie auf dem iPhone und ein leiser
   Uebergang je Seite. touch-action wie bei den Reitern (v3.52.0): sonst
   deutet Chromium die Querbewegung als Scrollversuch und bricht ab.
   ============================================================ */
#setBody { touch-action: pan-y pinch-zoom; transition: transform .22s ease-out, opacity .22s ease-out; }
#setBody.wischt { transition: none; }
@keyframes setSeiteVor { from { opacity: 0; transform: translateX(28px); } to { opacity: 1; transform: none; } }
@keyframes setSeiteZurueck { from { opacity: 0; transform: translateX(-28px); } to { opacity: 1; transform: none; } }
#setBody.seiteVor { animation: setSeiteVor .24s cubic-bezier(.25,.6,.25,1); }
#setBody.seiteZurueck { animation: setSeiteZurueck .24s cubic-bezier(.25,.6,.25,1); }
@media (prefers-reduced-motion: reduce) {
  #setBody { transition: none; }
  #setBody.seiteVor, #setBody.seiteZurueck { animation: none; }
}

/* ============================================================
   v3.78.0: PERSONEN IM HAUSHALT - ein Name je Zeile, aufklappbar.
   Zugeklappt: Farbpunkt, Name, Kurzfassung, Pfeil. Aufgeklappt: eine
   Liste, eine Einstellung je Zeile, immer in derselben Reihenfolge.
   ============================================================ */
.leuteZeile { display: block; padding: 0; gap: 0; }
.leuteKopf { display: flex; align-items: center; gap: 2px; }
.leuteAuf { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 4px 4px;
  border: 0; background: none; font: inherit; color: var(--text); text-align: left; cursor: pointer; border-radius: var(--r-s); }
.leuteAuf:active { background: var(--surface-2); }
.leuteAuf .pPunkt { flex: none; }
.leuteText { flex: 1; min-width: 0; }
.leuteKurz { display: block; font-size: 0.78rem; color: var(--muted); margin-top: 1px; line-height: 1.3; }
.leutePfeil { flex: none; color: var(--muted-2); font-size: 1.05rem; transition: transform .18s ease-out; }
.leuteZeile.offen .leutePfeil { transform: rotate(90deg); }
.leuteDetails { padding: 0 0 8px 34px; }
.leuteDetails[hidden] { display: none; }
.leuteReihe { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap;
  min-height: 44px; padding: 4px 0; margin: 0; border-top: 1px dashed var(--border); }
.leuteReiheText { font-size: 0.86rem; color: var(--text-2); flex: none; }
.pPunkteSchalter.leuteReihe { width: 100%; border-radius: 0; border: 0; border-top: 1px dashed var(--border); background: none;
  padding: 4px 0; font-size: 0.86rem; color: var(--text-2); font-weight: 500; flex-wrap: nowrap; }
.pPunkteSchalter.leuteReihe.an { color: var(--text); background: none; }
.pPunkteSchalter.leuteReihe .pSchalterText { flex: 1; text-align: left; }
.leuteDetails .pPalette { padding: 0; border: 0; justify-content: flex-end; flex: 1; }
.leuteDetails .leuteGebZeile { margin: 0; justify-content: flex-start; }
.leuteZeile.neu .leuteName { color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .leutePfeil { transition: none; } }

/* v3.79.0: Gastgeber-Sicht - Mitkommende und E-Mail eines Gastes. */
.evMailMarke { flex: none; margin-left: 4px; font-size: 0.92rem; }
.evGastMit { font-size: 0.82rem; color: var(--muted); margin: 2px 0 6px; overflow-wrap: anywhere; }

/* ============================================================
   v3.80.0: DARSTELLUNG ALS VORSCHAUFENSTER (ansicht.js). Das Fenster ist
   wie der Rundgang gebaut (#tourModal) und teilt dessen Punkte, Text und
   Herein-Animationen. Die Vorschau (.ansichtVorschau) baut die Stile mit
   denselben Farben und Formen nach - Schriftgroessen nur aus der Skala.
   ============================================================ */
#ansichtModal { display: none; position: fixed; inset: 0; background: var(--overlay); z-index: 1200; align-items: center; justify-content: center; padding: 16px; }
#ansichtModal .modalBox { max-width: var(--blatt-breit); display: flex; flex-direction: column; max-height: var(--blatt-hoch); }
#ansichtBody { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; touch-action: pan-y pinch-zoom; transition: transform .22s ease-out; }
#ansichtBody.wischt { transition: none; }
#ansichtBody.tourNeu { animation: tourEin .28s ease-out; }
#ansichtBody.tourNeu[data-richtung="vor"] { animation-name: tourEinVor; }
#ansichtBody.tourNeu[data-richtung="zurueck"] { animation-name: tourEinZurueck; }
#ansichtBody .tourPunkte { display: flex; gap: 6px; justify-content: center; margin: 0 0 12px; }
#ansichtBody .tourPunkte span { width: 7px; height: 7px; border-radius: var(--r-kreis); background: var(--border-2); }
#ansichtBody .tourPunkte span.aktiv { background: var(--accent); }
#ansichtBody .tourWischHinweis { text-align: center; font-size: 0.78rem; color: var(--muted); margin: -6px 0 8px; }
#ansichtBody .tourText { font-size: 0.92rem; color: var(--text-2); line-height: 1.5; margin: 0 0 12px; }
#ansichtBody .tourFuss { font-size: 0.82rem; color: var(--text-3); line-height: 1.45; margin: 10px 0 0; }
.ansichtName { margin: 10px 0 4px; font-size: 1.05rem; font-weight: 700; }
.ansichtGewaehlt { font-size: 0.78rem; font-weight: 600; color: var(--success-text); background: var(--success-bg); border: 1px solid var(--success-border); border-radius: var(--r-voll); padding: 2px 8px; margin-left: 6px; vertical-align: middle; }
.ansichtWaehlen { width: 100%; }
.ansichtWaehlen[disabled] { opacity: .75; }
.ansichtVorschau { border: 1px solid var(--border); border-radius: var(--radius-l); background: var(--bg); padding: 12px; font-size: 0.78rem; line-height: 1.3; color: var(--text); pointer-events: none; }
.avTag { margin-bottom: 8px; }
.avTag:last-child { margin-bottom: 0; }
.avEintrag { display: flex; gap: 8px; align-items: center; padding: 6px 8px; margin-top: 4px; border: 1px solid var(--border); border-radius: var(--radius-s); background: var(--surface); }
.avZeit { flex: none; min-width: 46px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--text-2); font-size: 0.7rem; }
.avTitel { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.avBand { display: flex; justify-content: space-between; align-items: center; background: var(--text); color: var(--bg); border-radius: var(--radius-s); padding: 6px 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; font-size: 0.7rem; }
.avBand .avBandDatum { font-weight: 400; text-transform: none; letter-spacing: 0; opacity: .85; }
.avTag.heute .avBand { background: var(--accent); color: var(--auf-farbe); }
.ansichtVorschau[data-stil="spalte"] .avTag { display: grid; grid-template-columns: 38px minmax(0, 1fr); gap: 0 8px; padding: 6px 0; border-top: 1px solid var(--border); }
.ansichtVorschau[data-stil="spalte"] .avTag:first-child { border-top: 0; padding-top: 0; }
.avDatum { display: flex; flex-direction: column; align-items: center; }
.avWt { font-size: 0.7rem; font-weight: 700; color: var(--muted); }
.avNr { display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: var(--r-kreis); font-size: 1.05rem; font-weight: 700; }
.avMon { font-size: 0.7rem; color: var(--muted-2); }
.avTag.heute .avNr { background: var(--accent); color: var(--auf-farbe); }
.avTag.heute .avWt { color: var(--accent); }
.avLinieKopf { display: flex; align-items: center; gap: 8px; margin: 6px 0 2px; font-size: 0.78rem; color: var(--text-2); }
.avLinieKopf b { font-weight: 800; }
.avLinieKopf i { flex: 1; height: 1px; background: var(--border-2); }
.avTag.heute .avLinieKopf { color: var(--accent); }
.avTag.heute .avLinieKopf i { background: var(--accent); opacity: .5; }
.ansichtVorschau[data-stil="strahl"] .avTag { position: relative; margin-left: 7px; padding: 0 0 8px 14px; border-left: 2px solid var(--border-2); }
.ansichtVorschau[data-stil="strahl"] .avTag:last-child { border-left-color: transparent; }
.avStrahlKopf { position: relative; display: flex; align-items: center; gap: 6px; margin: 0 0 2px; font-size: 0.78rem; color: var(--text-2); }
.avStrahlKopf::before { content: ""; position: absolute; left: -21px; top: 4px; width: 10px; height: 10px; border-radius: var(--r-kreis); background: var(--bg); border: 2px solid var(--border-2); }
.avTag.heute .avStrahlKopf::before { background: var(--accent); border-color: var(--accent); }
.avTag.heute .avStrahlName { background: var(--accent); color: var(--auf-farbe); border-radius: var(--r-voll); padding: 1px 8px; font-weight: 700; }
.ansichtVorschau[data-stil="strahl"] .avTag.heute { border-left-color: var(--accent); }
.avKalKopf { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; font-size: 0.7rem; font-weight: 700; color: var(--muted); margin-bottom: 4px; }
.avKalGitter { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.avZelle { min-height: 34px; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 3px 2px; border-radius: var(--r-xs); font-size: 0.78rem; }
.avZelle b { font-weight: 600; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; border-radius: var(--r-kreis); }
.avPunkte { display: flex; gap: 2px; }
.avPunkte i { width: 4px; height: 4px; border-radius: var(--r-kreis); background: var(--accent); }
.ansichtVorschau[data-stil="ruhig"] .avZelle { border-top: 1px solid var(--border); border-radius: 0; }
.ansichtVorschau[data-stil="ruhig"] .avZelle:nth-child(-n+7) { border-top: 0; }
.ansichtVorschau[data-stil="ruhig"] .avZelle.heute b { color: var(--accent); font-weight: 800; box-shadow: var(--ring-innen-2) var(--accent); }
.ansichtVorschau[data-stil="ruhig"] .avZelle.gewaehlt b { background: var(--text); color: var(--bg); }
.ansichtVorschau[data-stil="kaesten"] .avZelle, .ansichtVorschau[data-stil="balken"] .avZelle, .ansichtVorschau[data-stil="woche"] .avZelle { background: var(--surface-2); border: 1px solid var(--border); }
.ansichtVorschau[data-stil="kaesten"] .avZelle.heute, .ansichtVorschau[data-stil="woche"] .avZelle.heute, .ansichtVorschau[data-stil="balken"] .avZelle.heute { border-color: var(--accent); }
.ansichtVorschau[data-stil="kaesten"] .avZelle.heute b, .ansichtVorschau[data-stil="woche"] .avZelle.heute b, .ansichtVorschau[data-stil="balken"] .avZelle.heute b { background: var(--accent); color: var(--auf-farbe); }
.ansichtVorschau[data-stil="balken"] .avZelle { min-height: 52px; align-items: stretch; }
.ansichtVorschau[data-stil="balken"] .avZelle b { align-self: center; }
.avBalken { display: block; font-size: 0.7rem; line-height: 1.3; padding: 0 3px; border-radius: var(--r-xs); color: var(--auf-farbe); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.avBalken.a { background: var(--accent); }
.avBalken.b { background: var(--success); }
.avMehr { font-size: 0.7rem; color: var(--muted); text-align: center; }
.avTagesliste { margin-top: 8px; border-top: 1px solid var(--border); padding-top: 6px; }
.avTagesTitel { font-size: 0.78rem; font-weight: 700; margin-bottom: 2px; }
@media (max-width: 480px) {
  #ansichtModal { top: 0; left: 0; right: 0; bottom: 0; align-items: flex-end; padding: 0; }
  #ansichtModal .modalBox { max-width: none; width: 100%; border-radius: var(--r-l) var(--r-l) 0 0; max-height: calc(100% - var(--sat, 0px) - 24px); padding: 10px 18px calc(16px + var(--sab)); }
}
@media (prefers-reduced-motion: reduce) { #ansichtBody { transition: none; } #ansichtBody.tourNeu { animation: none; } }

/* v3.80.0: VERARBEITETE DATEN (transparenz.js) - Zeilen mit Wert rechts. */
.datenTitel { margin: 16px 2px 6px; font-size: 0.78rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.datenListe { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); padding: 0 12px; margin-top: 6px; }
.datenZeile { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 8px 0; border-top: 1px solid var(--border); font-size: 0.86rem; }
.datenZeile:first-child { border-top: 0; }
.datenWas { flex: 1; min-width: 0; }
.datenHinweis { display: block; font-size: 0.78rem; color: var(--muted); line-height: 1.35; margin-top: 1px; }
.datenHinweis code { font-family: var(--font-fest); font-size: 0.7rem; }
.datenWert { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; max-width: 55%; }
.datenFehler { color: var(--danger); }

/* v3.81.0: REITER ANORDNEN (ansicht.js reiterOrdnenOeffnen) */
.reiterOrdnen { display: flex; flex-direction: column; margin-top: 8px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); padding: 0 8px 0 12px; }
.reiterOrdnenZeile { display: flex; align-items: center; gap: 8px; min-height: 48px; border-top: 1px solid var(--border); }
.reiterOrdnenZeile:first-child { border-top: 0; }
.reiterOrdnenNr { flex: none; width: 20px; font-size: 0.78rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.reiterOrdnenName { flex: 1; min-width: 0; font-size: 0.92rem; font-weight: 500; }
.reiterOrdnenKnopf { flex: none; width: 44px; height: 44px; border: 1px solid var(--border-2); border-radius: var(--radius-s); background: var(--bg); color: var(--text-2); font: inherit; font-size: 0.82rem; cursor: pointer; }
.reiterOrdnenKnopf:active { background: var(--surface-2); }
.reiterOrdnenKnopf[disabled] { opacity: .35; cursor: default; }

/* ============================================================
   v3.146.0: DAS AUFGERÄUMTE TERMIN-BLATT (seit v3.160.8 für alle - aus
   Beta „termin-blatt“ freigegeben, Prüfliste am 07.10.2026)

   Sören, 05.10.2026: „Termin ändern ist unübersichtlich und voll (das
   wichtigste ist drin und selten genutzte dinge einklappen) ausserdem ist
   die Darstellung im dunkelmodus unübersichtlich. Scrollen funktioniert
   teilweise nicht. Anklicken eines vollen termins ist schwierig da er
   teilweise auf kontakte springt.“

   Bis v3.160.7 galt alles hier nur mit Beta (html.beta-…); seit v3.160.8
   ohne den Vorsatz. Wo eine ältere Regel dieselben Elemente traf und nur
   gegen den Vorsatz verlor, ist ihr Wert dort entfernt oder die Regel hier
   trägt, was sie dafür braucht (jeweils daneben vermerkt) - die Stile sind
   dieselben wie mit Beta. Die Anordnung baut terminBlattHtml
   (app-termine.js); hier steht, wie sie aussieht.

   GRUPPEN STATT EINER LANGEN SPALTE. Gemessen (v3.145.0, dunkel): Jedes
   Feld stand mit 1,26:1 auf dem Blatt, Gruppen gab es keine - „Wann“,
   „Wiederholt“, „Ort“ und „Erinnerung“ liefen ohne Absatz ineinander.
   Jetzt ist jede Gruppe eine Karte (--card mit Haarlinie --border auf
   --bg): hell eine helle Karte auf dem warmen Grau, dunkel eine Stufe
   heller als das Blatt. Die Felder darin bleiben --surface-2.
   ============================================================ */
.tbBlatt { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.tbBlatt .bsBlattTitelHuelle { margin: 0; }
.tbGruppe { display: flex; flex-direction: column; gap: 6px; min-width: 0;
  padding: 4px 12px; background: var(--card); border: 1px solid var(--border); border-radius: var(--r-l); }
/* Eine Karte, deren Zeilen alle ausgeblendet sind (die 2. Erinnerung, solange
   die erste „keine“ ist), steht nicht als leerer Rahmen da. */
.tbGruppe:not(:has(> :not([hidden]))) { display: none; }
/* „von – bis“ in einer Zeile: zwei gleich breite Uhrzeitfelder. Weniger
   Innenabstand als sonst - bei 320 px bleiben dem Paar 184 px.
   v3.160.8: Das Feld steht mit seiner Hülle im Selektor (.tbFeld >), so wie
   es im Blatt steht - damit wiegt die Regel (0,3,0) und schlägt im
   Anlege-Formular „.addForm input[type=time]“ (0,2,1, 8/6 px Innenabstand
   für die übrigen Zeitfelder dort) und den Baustein „.bsFeldPaar .bsFeld“
   (0,2,0, flex 2 - lädt später). Bis v3.160.7 tat das der Beta-Vorsatz
   (html.beta-…). */
.tbZeitPaar { align-items: center; gap: 6px; }
.tbZeitPaar .tbFeld > .bsFeld { flex: 1 1 0; min-width: 0; padding-inline: 10px; }
.tbBis { flex: none; color: var(--text-3); }
/* Hier stand bis v3.151.0 eine Regel für schmale Bildschirme: Neben dem
   Wort „Uhrzeit“ blieben dem Paar bei 320 px 182 px, dort rückte das Wort
   über das Paar. Seit v3.151.1 steht kein Wort mehr daneben (unten) - das
   Paar hat überall die ganze Breite der Karte. */

/* v3.151.1 (Sören, 07.10.2026: „… Generell kann die Beschreibung raus. Es
   reicht wenn sie in dem ausgegrauten feld steht. Dafür generieren wir mehr
   platz“): DIE FELDER OHNE WORT DANEBEN. Jedes Feld nimmt die ganze Breite
   seiner Karte, sein Name steht im Feld (terminBlattHtml, tbFeldHtml).
   Datum und Uhrzeit kennen keinen Platzhalter - für sie zeichnet die Hülle
   den Namen, solange terminFeldNamen sie als leer markiert (data-leer): in
   Farbe, Größe und Einzug eines Platzhalters. So lange ist, was der Browser
   im Feld zeigt (Chromium „tt.mm.jjjj“, ein „bis“ gleich dem Tag),
   unsichtbar; fasst man das Feld an, ist es wieder ganz das Feld des
   Browsers - niemand tippt blind. Jede Regel einzeln: Ein Pseudo-Element,
   das ein Browser nicht kennt, verwirft sonst die ganze Liste. */
.tbFeld { position: relative; min-width: 0; }
/* Hier stand bis v3.160.7 „.tbFeld > .bsFeld { width: 100% }“ - gegen das
   width: auto, das .bsFeldPaar .bsFeld (app-bausteine.css) den Feldern im
   Paar „von – bis“ gab. Seit v3.160.8 trägt der Baustein es nicht mehr; die
   ganze Breite gibt .bsFeld selbst. */
/* Safari auf dem iPhone setzt Datum und Uhrzeit in die Mitte des Felds - der
   Name im leeren Feld steht links, der Text in jedem anderen Feld auch. Im
   Anlege-Formular stand das schon so (.addForm, v3.98.0), im Blatt nicht. */
.tbFeld > .bsFeld::-webkit-date-and-time-value { text-align: left; }
.tbZeitPaar .tbFeld { flex: 1 1 0; }
/* Mit der Kennung davor: Im Anlege-Formular färbt „#addTerminFormBox
   input[type=date]“ (eine Kennung, 1,1,1) Datum und Uhrzeit - ohne sie
   blieb dort die Schrift des Browsers unter dem Namen stehen (gemessen,
   termin-blatt-dom A10). */
:is(#editModalFields, #addTerminFormBox) .tbFeld[data-leer]:not(:focus-within) > .bsFeld { color: transparent; -webkit-text-fill-color: transparent; }
.tbFeld[data-leer]:not(:focus-within) > .bsFeld::-webkit-datetime-edit { opacity: 0; }
.tbFeld[data-leer]:not(:focus-within) > .bsFeld::-webkit-date-and-time-value { opacity: 0; }
.tbFeld[data-leer]:not(:focus-within)::after { content: attr(data-name); position: absolute;
  inset-inline-start: 14px; top: 50%; transform: translateY(-50%); max-width: calc(100% - 28px);
  color: var(--muted-2); font-size: 16px; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
.tbZeitPaar .tbFeld[data-leer]:not(:focus-within)::after { inset-inline-start: 10px; max-width: calc(100% - 20px); }
/* Die Unterkunft (zwei Felder) steht mit demselben Abstand wie jedes Feld
   der Karte - ihre Hülle ist kein Glied der Karte, die Felder darin stießen
   sonst aneinander (gemessen: 0 px). Nur, solange sie zu sehen ist. */
.tbBlatt .tbUnterkunft:not([hidden]) { display: flex; flex-direction: column; gap: 6px; }
/* Der Satz zum Ende des Termins spricht nur, wenn er etwas zu sagen hat
   (Reise, Ende vor Beginn, über Mitternacht, Beginn = Ende) - „Leer lassen
   für einen normalen Termin“ und „Endet am selben Tag um …“ sagen neben
   „von – bis“ nichts Neues. Den Stand setzt terminReiseUmschalten. */
/* v3.151.1: … und auch die Reise sagt er nicht mehr („Reise über 5 Tage –
   steht an jedem Tag im Kalender.“). Sören: „Generell kann die Beschreibung
   raus.“ Dass es eine Reise ist, zeigt das zweite Datum direkt unter dem
   ersten. Es bleiben die Sätze, ohne die man etwas falsch verstünde oder
   nicht speichern könnte: Ende vor Beginn, Beginn gleich Ende, über
   Mitternacht. */
.tbEndeHinweis:not([data-stand]),
.tbEndeHinweis[data-stand="leer"],
.tbEndeHinweis[data-stand="ok"],
.tbEndeHinweis[data-stand="reise"] { display: none; }
/* v3.146.0, Nachbesserung: Hier stand die Regel, die den Erklärsatz beim
   letzten Tag („Für Reisen und Termine über mehrere Tage …“) schweigen
   ließ, solange der Satz zum Ende sprach. Seit v3.150.1 steht der letzte
   Tag immer oben, und den Erklärsatz gibt es nicht mehr (app-termine.js
   terminBlattHtml) - zum Ende spricht nur noch der eine Satz darüber. */
/* Eine Gruppe, die in einer anderen Karte steht (Adresse, Link,
   2. Erinnerung, ein eingetragener letzter Tag), behält ihre Hülle - die
   Zeilen stehen aber in der Karte, als wären es ihre eigenen. */
.tbTeil { display: contents; }
/* Route und Link öffnen: eine eigene Fläche von 44 px, die weder in das Feld
   darüber noch in die Zeile darunter ragt (anders als .feldHinweis .ortLink
   mit seinem unsichtbaren Rand, v3.33.0). */
/* Das ✕ eines Anhangs im Blatt war 40 px (gemessen) - seit v3.146.0 44. */
.tbBlatt .anhangWeg { min-width: 44px; min-height: 44px; }
.tbWeg { display: flex; align-items: center; gap: 6px; min-height: 44px; margin: 0; padding: 0 2px;
  color: var(--accent-strong); font-size: 0.82rem; font-weight: 600; text-decoration: none; }

/* „Mehr“: dieselbe Karte, als Schalter. Darunter stehen in kleiner Schrift
   die Namen dessen, was eingeklappt ist (terminBlattHtml liest sie aus der
   Liste der Gruppen und aus den Knöpfen). */
.tbMehr { display: block; min-width: 0; }
.tbMehrZeile { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 6px 12px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--r-l); cursor: pointer; list-style: none; }
.tbMehrZeile::-webkit-details-marker { display: none; }
.tbMehrText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tbMehrWort { font-size: 0.95rem; font-weight: 600; color: var(--text); }
.tbMehrWas { font-size: 0.78rem; color: var(--muted); line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tbMehrWinkel { flex: none; color: var(--text-3); font-size: 1.15rem; transition: transform .18s ease; }
.tbMehr[open] .tbMehrWinkel { transform: rotate(90deg); }
.tbMehrInnen { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
/* Die Knöpfe (Planung, Erledigt, In den Kalender, …, Löschen) nebeneinander,
   so viele die Breite trägt - untereinander waren es bis zu sieben volle
   Zeilen. */
.tbMehrInnen > .blattKnoepfe { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 8px; margin-top: 0; }
@media (prefers-reduced-motion: reduce) { .tbMehrWinkel { transition: none; } }

/* DUNKEL: Felder als Felder erkennbar. --surface-2 auf der Karte sind dort
   1,14:1 - ein Feld war vom Grund kaum zu unterscheiden. Ein Ring in
   --border-2 trägt 3,77:1 (WCAG 1.4.11 verlangt 3:1 für die Grenze eines
   Bedienelements). Nur dunkel: Hell trägt die Fläche (1,27:1 auf der hellen
   Karte), und Sören wollte dort keine Linien (v3.98.0: „das erste was
   auffällt sind die trennbalken“). Beim Tippen wird der Ring zum
   Akzent-Ring - dieselbe Aussage wie hell der Tonwechsel. */
html[data-thema="dunkel"] .tbBlatt .bsFeld,
html[data-thema="dunkel"] .tbBlatt .bsBlattTitelHuelle { box-shadow: var(--ring-innen-1) var(--border-2); }
html[data-thema="dunkel"] .tbBlatt .bsFeld:focus-visible,
html[data-thema="dunkel"] .tbBlatt .bsBlattTitelHuelle:focus-within { box-shadow: var(--ring-innen-2) var(--accent); }

/* SCROLLEN. Gemessen mit echter Berührung (CDP, wie wisch-beruehrung-dom):
   Der Inhalt rollt von jeder Stelle aus - von Feldern, Auswahlen, Chips,
   Wörtern, Knöpfen, auch schräg angesetzt. Nicht rollen der Kopf und die
   Leiste mit „Speichern“: Sie liegen außerhalb des rollenden Bereichs, und
   ein Zug dort ging an die Seite dahinter. Auf dem iPhone verschiebt das bei
   offener Tastatur das ganze Bild statt des Blatts (Annahme, auf dem Gerät
   ungeprüft). touch-action: none sagt dem Browser: Hier gibt es nichts zu
   schieben - am Kopf gehört der Zug dem Wegwischen des Blatts
   (blattWischBinden), an der Leiste niemandem. Bewusst NICHT an .modalBox
   oder #editModal: Beide umschließen den rollenden Bereich, und ob WebKit
   touch-action an einem Scroller neu beginnt wie Chromium (GESTEN.md Regel
   10), ist nicht gemessen - dort könnte none das Rollen selbst sperren.
   Gilt nur, solange das Termin-Blatt offen ist (:has(.tbBlatt)). */
#editModal:has(.tbBlatt) .modalKopf,
#editModal:has(.tbBlatt) .modalActions { touch-action: none; }
/* v3.146.0, Nachbesserung (Gegenprüfung): DER GRIFF GEHÖRT ZUM KOPF.
   Gemessen mit echter Berührung (CDP, 390 px, 180 px nach unten): Am Kopf
   schloss das Blatt, am GRIFF darüber nicht - pointerdown, pointercancel,
   das Blatt blieb stehen. Der Griff war .modalBox::before; das Ziel einer
   Berührung dort (wie am Rand links und rechts neben dem Kopf und im
   Abstand darunter) ist .modalBox mit touch-action auto. blattWischBinden
   nimmt die obersten 76 px des Blatts an - davon gehörten nur 44 px dem Kopf.
   Jetzt IST der ganze Streifen der Kopf: über die volle Breite (der
   Seitenrand des Blatts als Innenabstand), oben mit dem Abstand, in dem der
   Griff liegt, unten mit dem Abstand zum Inhalt. Der Griff ist sein
   ::before. Gezeichnet wie bisher (38 × 4 px, --border-2, 10 px unter der
   Kante); der Inhalt beginnt an derselben Stelle wie vorher (82 px). Nur
   auf dem Handy - darüber steht das Blatt mittig und hat sein ✕. */
@media (max-width: 480px) {
  #editModal:has(.tbBlatt) .modalBox { padding-top: 0; }
  #editModal:has(.tbBlatt) .modalBox::before { display: none; }
  #editModal:has(.tbBlatt) .modalBox .modalKopf { position: relative; margin: 0 -18px; padding: 26px 18px 14px; }
  #editModal:has(.tbBlatt) .modalBox .modalKopf::before { content: ""; position: absolute; top: 10px; left: 50%; width: 38px; height: 4px;
    margin-left: -19px; border-radius: var(--r-xs); background: var(--border-2); }
}
/* Tastatur offen: Der Platz gehört dem Inhalt. Gemessen bei 450 px
   sichtbarer Höhe: 258 von 418 px rollten - Griff, Kopf und Leiste nahmen
   38 %. Griff weg (ziehen geht weiter am Kopf), Abstände knapper - die
   Abstände über und unter dem Kopf sind seit der Nachbesserung sein
   eigener Innenabstand, also auch bei offener Tastatur Kopf. */
@media (max-width: 480px) {
  body.tastatur #editModal:has(.tbBlatt) .modalBox { padding-top: 0; padding-bottom: 8px; }
  body.tastatur #editModal:has(.tbBlatt) .modalBox .modalKopf { padding-top: 8px; padding-bottom: 6px; }
  body.tastatur #editModal:has(.tbBlatt) .modalBox .modalKopf::before { display: none; }
  body.tastatur #editModal:has(.tbBlatt) #editModalFields { margin-bottom: 8px; }
}

/* ============================================================
   v3.149.0: DAS BLATT „NEUER TERMIN“ WIE BEIM IPHONE (seit v3.160.8 für
   alle - aus Beta „termin-blatt“ freigegeben)
   v3.149.2: nur noch bei der Datumsauswahl im Kalender (app-termine.js
   terminNeuBlattHtml) - „Termin ändern“ und „+ Termin“ oben sind wieder
   die Fassung von v3.146.0 (Block davor). Eigene Klassen (.ti…), damit
   keine Regel der einen Fassung in die andere greift.

   Sören, 06.10.2026, mit einem Bild aus dem iPhone-Kalender („Neues
   Ereignis“): „Termin anlegen wenn auf datum klickt öffnet sich diese
   anzeige wie beim iPhone.“ Vorher (v3.146.0) stand hier das Blatt mit
   „Mehr“; die Anordnung baut terminBlattHtml (app-termine.js), hier steht,
   wie sie aussieht. Bis v3.160.7 galt alles nur mit Beta (html.beta-…),
   seit v3.160.8 für alle (siehe den Block davor).

   WIE DAS IPHONE: oben ✕ und ✓ statt einer Leiste unten; der Titel als
   großes Feld; die Zeit in der ersten Karte (Beginn und Ende je mit Tag und
   Uhrzeit nebeneinander, darunter „Ganztägig“ als Schalter und die
   Wiederholung); dann Karten mit kleinem Titel darüber (Wo, Wer, Optionen,
   Details). Jede Karte --card mit Haarlinie --border, wie v3.146.0 - hell
   eine helle Karte auf dem warmen Grau, dunkel eine Stufe heller als das
   Blatt. Keine Linien zwischen den Zeilen: Sören wollte keine Trennbalken
   (v3.98.0: „das erste was auffällt sind die trennbalken“).
   ============================================================ */
/* Das ✓ im Kopf gibt es nur im Blatt „Neuer Termin“ (Regeln unten). */
.modalOk { display: none; }
.tiBlatt { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.tiBlatt .bsBlattTitelHuelle { margin: 0 0 2px; }
.tiGruppe { display: flex; flex-direction: column; gap: 2px; min-width: 0;
  padding: 4px 14px; background: var(--card); border: 1px solid var(--border); border-radius: var(--r-l); }
/* Eine Karte, deren Zeilen alle ausgeblendet sind, steht nicht als leerer
   Rahmen da. */
.tiGruppe:not(:has(> :not([hidden]))) { display: none; }
/* Der kleine Titel über einer Karte (Wo, Wer, Optionen, Details) - wie die
   grauen Überschriften im iPhone-Blatt, in normaler Schreibung. */
.tiAbschnitt { margin: 6px 6px -2px; font-size: 0.82rem; font-weight: 600; color: var(--text-2); }
/* Beginn und Ende: Tag und Uhrzeit als zwei Felder nebeneinander, das Datum
   breiter (zehn Zeichen gegen fünf). Ganztägig fallen die Uhrzeiten weg -
   der Tag nimmt die ganze Breite. */
.tiPaar { gap: 6px; }
.tiPaar .bsFeld { padding-inline: 10px; }
.tiGanz .tiPaar .bsFeld[type="time"] { display: none; }
/* Schmal (320 px): Neben dem Wort blieben dem Paar 182 px - dort steht das
   Wort über dem Paar, und jedes Feld bekommt seine Hälfte der Karte. */
@media (max-width: 360px) {
  .tiGruppe .bsBlattZeile:has(.tiPaar) { grid-template-columns: minmax(0, 1fr); gap: 4px; padding-top: 4px; }
}
/* „Ganztägig“: ein Kippschalter in den Maßen aller Schalter der App
   (42 × 26, Knauf 20 - v3.51.0, .setZeile.schalter), rechts in der Zeile.
   Die Fläche zum Tippen ist 44 × 44. */
.tiSchalter { justify-self: end; display: inline-flex; align-items: center; justify-content: flex-end;
  min-width: 44px; min-height: 44px; margin-left: auto; padding: 0; border: none; background: none; cursor: pointer; }
.tiKnauf { position: relative; flex: none; width: 42px; height: 26px; border-radius: var(--r-voll);
  background: var(--border-2); transition: background .15s; }
.tiKnauf::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
  border-radius: var(--r-voll); background: var(--stets-weiss); box-shadow: var(--shadow-1); transition: transform .15s; }
.tiSchalter[aria-checked="true"] .tiKnauf { background: var(--success); }
.tiSchalter[aria-checked="true"] .tiKnauf::after { transform: translateX(16px); }
.tiSchalter:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-xs); }
@media (prefers-reduced-motion: reduce) { .tiKnauf, .tiKnauf::after { transition: none; } }
/* Der Satz zum Ende des Termins spricht nur, wenn er etwas zu sagen hat
   (Reise, Ende vor Beginn, über Mitternacht, Beginn = Ende) - „Leer lassen
   für einen normalen Termin“ und „Endet am selben Tag um …“ sagen neben
   Beginn und Ende nichts Neues. Den Stand setzt terminReiseUmschalten. */
/* Ein Hinweis ohne Text (der Satz zur Serie, solange sie „nie“ ist) nimmt
   keinen Platz in der Karte. */
.tiGruppe .feldHinweis:empty { display: none; }
.tiEndeHinweis:not([data-stand]),
.tiEndeHinweis[data-stand="leer"],
.tiEndeHinweis[data-stand="ok"] { display: none; }
/* Der Fahrdienst klappt in seiner Karte auf (wie im Formular bis v3.160.7) - ohne eigenen
   Rahmen in der Karte, sonst stünde ein Kasten im Kasten. */
.tiGruppe > .blattKlapp { margin: 0; padding: 0; border: none; }
/* Die Handlungen beim Ändern (Planung, Erledigt, In den Kalender, …,
   Löschen) nebeneinander, so viele die Breite trägt - untereinander waren
   es bis zu sieben volle Zeilen. */
.tiAktionen > .blattKnoepfe { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 8px; margin: 10px 0; }
/* Die Handlungen stehen ohne Titel darüber - abgesetzt wie jede Karte
   (mindestens 8 px, termin-blatt-dom B1). */
.tiAktionen { margin-top: 6px; }
/* Route und Link öffnen: eine eigene Fläche von 44 px, die weder in das Feld
   darüber noch in die Zeile darunter ragt (anders als .feldHinweis .ortLink
   mit seinem unsichtbaren Rand, v3.33.0). */
/* Das ✕ eines Anhangs im Blatt war 40 px (gemessen) - seit v3.149.0 44. */
.tiBlatt .anhangWeg { min-width: 44px; min-height: 44px; }
.tiWeg { display: flex; align-items: center; gap: 6px; min-height: 44px; margin: 0; padding: 0 2px;
  color: var(--accent-strong); font-size: 0.82rem; font-weight: 600; text-decoration: none; }
/* Die Route als Kartenknopf neben dem Ort - getönt wie alles, was
   woandershin führt (--accent-bg, wie die Felder unter der Terminkarte). */
.tiRoute { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px;
  border-radius: var(--r-m); background: var(--accent-bg); color: var(--accent-strong); text-decoration: none; }
.tiRoute:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* DER KOPF WIE BEIM IPHONE: ✕ links (zurück - fragt, wenn etwas geändert
   ist), der Titel in der Mitte, ✓ rechts (eintragen bzw. speichern). Die
   Leiste mit „Zurück“ und „Speichern“ unten entfällt - zwei Knöpfe für
   dasselbe wären einer zu viel, und oben stehen sie auch bei offener
   Tastatur im Bild. */
#editModal:has(.tiBlatt) .modalKopf > span { flex: 1; min-width: 0; text-align: center; }
#editModal:has(.tiBlatt) .modalX { order: -1; border-radius: var(--r-voll); }
#editModal:has(.tiBlatt) .modalOk { order: 1; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; min-width: 44px; padding: 0; border: none; border-radius: var(--r-voll);
  background: var(--accent); color: var(--auf-farbe); font: inherit; font-size: 1.05rem; font-weight: 700; line-height: 1; cursor: pointer; }
#editModal:has(.tiBlatt) .modalOk:active { background: var(--accent-strong); }
#editModal:has(.tiBlatt) .modalActions { display: none; }

/* DUNKEL: Felder als Felder erkennbar. --surface-2 auf der Karte sind dort
   1,14:1 - ein Feld war vom Grund kaum zu unterscheiden. Ein Ring in
   --border-2 trägt 3,77:1 (WCAG 1.4.11 verlangt 3:1 für die Grenze eines
   Bedienelements). Nur dunkel: Hell trägt die Fläche (1,27:1 auf der hellen
   Karte), und Sören wollte dort keine Linien (v3.98.0: „das erste was
   auffällt sind die trennbalken“). Beim Tippen wird der Ring zum
   Akzent-Ring - dieselbe Aussage wie hell der Tonwechsel. */
html[data-thema="dunkel"] .tiBlatt .bsFeld,
html[data-thema="dunkel"] .tiBlatt .bsBlattTitelHuelle { box-shadow: var(--ring-innen-1) var(--border-2); }
html[data-thema="dunkel"] .tiBlatt .bsFeld:focus-visible,
html[data-thema="dunkel"] .tiBlatt .bsBlattTitelHuelle:focus-within { box-shadow: var(--ring-innen-2) var(--accent); }

/* SCROLLEN. Gemessen mit echter Berührung (CDP, wie wisch-beruehrung-dom):
   Der Inhalt rollt von jeder Stelle aus - von Feldern, Auswahlen, Chips,
   Wörtern, Knöpfen, auch schräg angesetzt. Nicht rollen der Kopf und die
   Leiste mit „Speichern“: Sie liegen außerhalb des rollenden Bereichs, und
   ein Zug dort ging an die Seite dahinter. Auf dem iPhone verschiebt das bei
   offener Tastatur das ganze Bild statt des Blatts (Annahme, auf dem Gerät
   ungeprüft). touch-action: none sagt dem Browser: Hier gibt es nichts zu
   schieben - am Kopf gehört der Zug dem Wegwischen des Blatts
   (blattWischBinden), an der Leiste niemandem. Bewusst NICHT an .modalBox
   oder #editModal: Beide umschließen den rollenden Bereich, und ob WebKit
   touch-action an einem Scroller neu beginnt wie Chromium (GESTEN.md Regel
   10), ist nicht gemessen - dort könnte none das Rollen selbst sperren.
   Gilt nur, solange das Termin-Blatt offen ist (:has(.tiBlatt)). */
#editModal:has(.tiBlatt) .modalKopf,
#editModal:has(.tiBlatt) .modalActions { touch-action: none; }
/* v3.146.0, Nachbesserung (Gegenprüfung): DER GRIFF GEHÖRT ZUM KOPF.
   Gemessen mit echter Berührung (CDP, 390 px, 180 px nach unten): Am Kopf
   schloss das Blatt, am GRIFF darüber nicht - pointerdown, pointercancel,
   das Blatt blieb stehen. Der Griff war .modalBox::before; das Ziel einer
   Berührung dort (wie am Rand links und rechts neben dem Kopf und im
   Abstand darunter) ist .modalBox mit touch-action auto. blattWischBinden
   nimmt die obersten 76 px des Blatts an - davon gehörten nur 44 px dem Kopf.
   Jetzt IST der ganze Streifen der Kopf: über die volle Breite (der
   Seitenrand des Blatts als Innenabstand), oben mit dem Abstand, in dem der
   Griff liegt, unten mit dem Abstand zum Inhalt. Der Griff ist sein
   ::before. Gezeichnet wie bisher (38 × 4 px, --border-2, 10 px unter der
   Kante); der Inhalt beginnt an derselben Stelle wie vorher (82 px). Nur
   auf dem Handy - darüber steht das Blatt mittig und hat sein ✕. */
@media (max-width: 480px) {
  /* v3.149.0: Wie das iPhone fast bildschirmhoch - bis knapp unter die
     Statusleiste statt 88 % (#editModal .modalBox): So stehen Zeit, Ort,
     wer dabei ist und die Erinnerung ohne Rollen da. */
  #editModal:has(.tiBlatt) .modalBox { padding-top: 0; max-height: calc(100% - var(--sat, 0px) - 12px); }
  #editModal:has(.tiBlatt) .modalBox::before { display: none; }
  #editModal:has(.tiBlatt) .modalBox .modalKopf { position: relative; margin: 0 -18px; padding: 26px 18px 14px; }
  #editModal:has(.tiBlatt) .modalBox .modalKopf::before { content: ""; position: absolute; top: 10px; left: 50%; width: 38px; height: 4px;
    margin-left: -19px; border-radius: var(--r-xs); background: var(--border-2); }
}
/* Tastatur offen: Der Platz gehört dem Inhalt. Gemessen bei 450 px
   sichtbarer Höhe: 258 von 418 px rollten - Griff, Kopf und Leiste nahmen
   38 %. Griff weg (ziehen geht weiter am Kopf), Abstände knapper - die
   Abstände über und unter dem Kopf sind seit der Nachbesserung sein
   eigener Innenabstand, also auch bei offener Tastatur Kopf. */
@media (max-width: 480px) {
  body.tastatur #editModal:has(.tiBlatt) .modalBox { padding-top: 0; padding-bottom: 8px; }
  body.tastatur #editModal:has(.tiBlatt) .modalBox .modalKopf { padding-top: 8px; padding-bottom: 6px; }
  body.tastatur #editModal:has(.tiBlatt) .modalBox .modalKopf::before { display: none; }
  body.tastatur #editModal:has(.tiBlatt) #editModalFields { margin-bottom: 8px; }
}

/* DIE TERMINZEILE (terminZeile, terminKontaktChipsHtml): Ort, Straße und
   Link sind Text - ein Tipp darauf öffnet den Termin. Kontakt, Anruf und
   Planung sind Felder mit eigenen 44 px in einer eigenen Reihe; nichts
   davon ragt in eine Textzeile. Die Tönung (--accent-bg mit --accent-border)
   sagt „führt woandershin“, ohne dass ein Strich die Karte zerschneidet. */
.terminZeile .ortName { color: var(--text-2); font-weight: 600; }
/* Jedes Stück der Orts- und Kontaktzeile ist ein Kasten (wie .ortLink bis
   v3.160.7 ohne Beta): Zwischen den Stücken darf die Zeile umbrechen. Als reiner Text
   liefen sie bei 320 px über den Rand.
   v3.146.0, Nachbesserung (Gegenprüfung): Im Stück wurde mit „…“ gekürzt -
   bei 320 px stand „🔴 zu, öffnet morg…“ und „Kinderarztpraxi…“. Das ist
   genau die Angabe, für die man auf die Karte schaut. Jetzt bricht ein
   Stück, das allein breiter ist als die Spalte, in sich um (überall, wo es
   muss); kürzer wird nichts. Kostet bei 320 px eine Zeile, sonst nichts. */
.terminZeile .ortTeil { display: inline-block; max-width: 100%; vertical-align: bottom; white-space: normal; overflow-wrap: anywhere; }
/* … und die Zeile selbst ist nie breiter als die Textspalte (ohne das lief
   „Kinderarztpraxis Dr. Meyer“ bei 320 px unter das ✕ - gemessen). */
.terminZeile .meta > .ortZeile { flex: 1 1 100%; min-width: 0; max-width: 100%; }
/* Die Reihe der Felder steht unter der ganzen Karte, eingerückt bis zur
   Textspalte (Scheibe 34 px + Abstand 10 px). */
.item.terminZeile { flex-wrap: wrap; }
.terminZeile .tbKontaktInfo { flex: 1 1 100%; min-width: 0; }
/* Sichtbar 34 px, getroffen 46 px: Der unsichtbare Rand (::after, 7 px ab
   der Innenkante, also 6 px über den Rahmen hinaus - gemessen: bei 5 px
   waren es nur 42 px, weil ::after an der Innenkante des Rahmens ansetzt)
   bleibt im Abstand der eigenen Reihe (11 px bis zur Textzeile darüber, der
   Rand der Karte darunter) - er reicht in keine Textzeile, anders als der 13-px-Rand
   von .item .ortLink. „Anrufen“ ist ein rundes Feld mit dem Zeichen.
   v3.146.0, Nachbesserung (Gegenprüfung, gemessen): Die Reihe brach nie um,
   und das Kontaktfeld nahm, was übrig blieb - bei 320 px in der Liste 77 px
   („📇 Ki…“), und das Planungsfeld schrumpfte unter seinen Inhalt („📋 1/3“
   ragte 8 px aus der Pille, bis an den Kartenrand). Jetzt behält jedes Feld
   seine Breite (flex: none; der Name des Kontakts steht als Text in der
   Zeile darüber, das Feld sagt „Kontakt“). Reicht die Breite nicht, bricht
   die REIHE um, nie ein Feld: zwischen zwei Reihen 14 px, genau die zweimal
   7 px unsichtbarer Rand - die Trefferflächen stoßen aneinander, keine liegt
   über der anderen. Unter 375 px Breite steht die Reihe ohne Einzug unter
   der ganzen Karte: Dort fehlen sonst die 44 px, damit Kontakt, Anruf und
   Planung nebeneinander passen. */
.terminZeile .tbChipReihe { flex: 1 1 100%; display: flex; flex-wrap: wrap; gap: 14px 8px; margin: -4px 0 0 44px; padding-block: 5px 0; min-width: 0; }
@media (max-width: 374px) { .terminZeile .tbChipReihe { margin-left: 0; } }
.terminZeile .tbChip { position: relative; display: inline-flex; align-items: center; gap: 6px; min-height: 34px; min-width: 44px; max-width: 100%;
  margin: 0; padding: 0 12px; box-sizing: border-box; border: 1px solid var(--accent-border); border-radius: var(--r-voll);
  background: var(--accent-bg); color: var(--accent-strong); font: inherit; font-size: 0.82rem; font-weight: 600; line-height: 1.2;
  text-decoration: none; cursor: pointer; }
.terminZeile .tbChip::after { content: ""; position: absolute; left: 0; right: 0; top: -7px; bottom: -7px; }
.terminZeile .tbKontaktChip { flex: none; }
.terminZeile .tbTelChip { flex: none; justify-content: center; padding: 0; width: 44px; }
.terminZeile .tbChipText { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.terminZeile .tbNummer { color: var(--text-2); font-variant-numeric: tabular-nums; }
.terminZeile .planBadge.tbChip { flex: none; background: var(--purple-bg); color: var(--purple); border-color: var(--border); }
.terminZeile .planBadge.tbChip.fertig { background: var(--success-bg); color: var(--success-text); border-color: var(--success-border); }
.terminZeile.done .tbChip { color: var(--muted-2); }
/* Anhänge in der Zeile: dieselbe Form - vorher Text von 20 px Höhe. */
.terminZeile .anhangZeile { gap: 10px 8px; padding-block: 10px 5px; }
.terminZeile .anhangLink { position: relative; display: inline-flex; align-items: center; min-height: 34px; max-width: 100%;
  padding: 0 12px; box-sizing: border-box; border: 1px solid var(--accent-border); border-radius: var(--r-voll); background: var(--accent-bg); }
.terminZeile .anhangLink::after { content: ""; position: absolute; left: 0; right: 0; top: -7px; bottom: -7px; }
/* v3.146.0, Nachbesserung (Gegenprüfung): „Überweisung.pdf“ brach bei
   320 px in drei Zeilen um („📄 / Überweisung.pd / f“ - word-break von
   .anhangLink) und das Feld wurde 60 px hoch. Das Feld bleibt einzeilig,
   der Name (eigener Kasten, anhangZeileHtml) kürzt mit „…“ - der ganze
   Name steht im title und im Blatt. Der Kasten, nicht das Feld, schneidet
   ab: Am Feld hängt der unsichtbare Rand (::after), den overflow: hidden
   mit abschneiden würde. */
.terminZeile .anhangLink { gap: 6px; white-space: nowrap; word-break: normal; }
.terminZeile .tbAnhangName { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ============================================================
   v3.150.0 (Sören: „Wenn man scrollt könnte man doch eigentlich überall
   die reiterleiste ausblenden.“) - KOPF UND LEISTE GEHEN BEIM SCROLLEN,
   wie bei YouTube (app-gesten.js leistenGescrollt). Seit v3.160.10 für
   alle (aus Beta „leisten-weg“ freigegeben).

   Damit dabei NICHTS springt, liegen die Leisten (.leistenTeil: der
   Raumkopf und alles bis zur ersten Fläche, abgeleitet in leistenTeile)
   ÜBER der Fläche: Die Fläche beginnt oben am Kopf (margin-top: -H) und
   trägt vor ihrem Inhalt H Platz (::before) - in Ruhe sieht alles aus wie
   vorher, beim Rollen läuft der Inhalt unter den Leisten durch. Gehen ist
   dann nur Schieben (transform; seit v3.150.1 dem Finger nach und unter den
   Rand oben, bis dahin mit Ausblenden): keine neue Anordnung, kein
   scrollTop von Hand, der Finger behält den Schwung.
   H = --leisten-hoehe (leistenMessen). z-index 4: über der Nachbarseite
   beim Wischen (.reiterNachbar, 3) und dem Kringel (.ziehKringel, 3).
   Am Rechner (ab 900 px) stehen Kopf und Leiste in eigener Rasterzeile -
   dort bleibt alles, wie es ist.
   ============================================================ */
@media (max-width: 899px) {
  /* v3.150.1 (Sören: „Reiterleiste ist gut nur die Animation könnte
     smoother sein.“): Die Leisten folgen dem Finger - das transform setzt
     app-gesten.js (leistenSetzen) in jedem Bild an den Leisten selbst. Der
     Übergang hier gilt nur fürs Einrasten nach dem Loslassen; beim Folgen
     schaltet leistenSetzen ihn ab. */
  .leistenTeil { position: relative; z-index: 4;
    transition: transform .26s cubic-bezier(.2,.8,.2,1); }
  /* Der Rand über dem Kopf (das Polster oben an #app: Statusleiste, 24 px,
     das Demo-Band) deckt zu, was von den Leisten nach oben hinausgleitet -
     sie verschwinden dort wie unter einer Kante, statt halb in der
     Statusleiste zu stehen. Er ist genau so hoch, wie der Kopf von oben weg
     ist (--leisten-oben, leistenMessen, aus offsetTop - keine zweite Rechnung
     für das Polster), und hat die Farbe der Seite, die dort ohnehin zu
     sehen ist: In Ruhe ändert er kein Pixel. */
  #app::before { content: ""; position: absolute; top: 0; left: 0; right: 0;
    height: var(--leisten-oben, 0px); z-index: 5; background: var(--bg); }
  /* Was die Leisten oben verdecken, sagt scroll-padding-top (scrollIntoView,
     die Vorschläge in app-liste.js vorschlagSichtbereich) - sind sie ganz
     weg, setzt leistenSetzen es an der Fläche, die rollt, auf 0. */
  #app > [role="tabpanel"] { margin-top: calc(-1 * var(--leisten-hoehe, 0px)); scroll-padding-top: var(--leisten-hoehe, 0px); }
  /* Im Chat rollt nicht die Fläche, sondern der Verlauf darin. */
  #app > [role="tabpanel"]:not(#chatView)::before,
  #messages::before { content: ""; display: block; flex: none; height: var(--leisten-hoehe, 0px); }
  #messages { scroll-padding-top: var(--leisten-hoehe, 0px); }
  /* Der Verlauf setzt seine Abstände mit gap - der Platz davor bekäme
     sonst einen eigenen dazu, und der Chat stünde in Ruhe tiefer als ohne
     die Leisten darüber. Den Wert liest leistenMessen aus dem Verlauf selbst
     (--leisten-luecke) - keine zweite Zahl, die zur ersten passen muss. */
  #messages::before { margin-bottom: calc(-1 * var(--leisten-luecke, 0px)); }
  /* Was oben an der Fläche hängt, hängt jetzt unter den Leisten. Die
     klebenden Tagesköpfe gehen den Weg der Leisten mit (leistenKoepfeSetzen
     setzt top in jedem Bild); der Übergang gilt fürs Einrasten. */
  .ziehKringel { top: var(--leisten-hoehe, 0px); }
  #terminListe[data-stil="linie"] .tagGruppe .tagKopf.banner { top: var(--leisten-hoehe, 0px); transition: top .26s cubic-bezier(.2,.8,.2,1); }
}
@media (max-width: 899px) and (prefers-reduced-motion: reduce) {
  .leistenTeil,
  #terminListe[data-stil="linie"] .tagGruppe .tagKopf.banner { transition: none; }
}

/* ============================================================
   v3.152.0: „ANORDNUNG ÄNDERN“ WIE AUF DEM HOME-BILDSCHIRM
   (seit v3.160.11 für alle, aus Beta „aufgaben-anordnen“ freigegeben)

   Sören, 07.10.2026: „… wenn man lange drückt und im Menü Anordnung
   ändern auswählt kann man alle aufgaben hin und her schieben und oben
   dann auf Fertig klicken. Wie zb bei iphone wenn man icons auf
   Bildschirm verschiebt.“

   Den Zustand hält aufgaben.js (aufgabenAnordnen, #todosView.anordnen);
   hier steht, wie er aussieht:
   - oben eine Leiste mit „Fertig“ - sie klebt am oberen Rand der Fläche,
     damit „Fertig“ auch in einer langen Liste da ist (unter dem Kopf und
     der Reiterleiste, z-index 3; die Leisten liegen bei 4);
   - die Aufgaben wackeln, jede in ihrem Takt, damit es nicht wie ein Block
     zittert (seit v3.152.1, unten). Die gehaltene steht still - wie ein
     Symbol auf dem iPhone, das man angehoben hat;
   - Abhaken und Löschen ruhen; was sich nicht ordnen lässt (Checklisten,
     Heute erledigt, das Logbuch), tritt zurück.
   Weniger Bewegung: kein Wackeln, stattdessen ein Ring um jede Aufgabe,
   die sich schieben lässt.
   ============================================================ */
/* top: Die Fläche beginnt oben am Kopf (die Leisten liegen darüber,
   „leisten-weg“) - die Leiste klebt darunter; gehen die Leisten, schiebt
   leistenKoepfeSetzen sie mit (inline top). Bis v3.160.10 stand dieser Wert
   in einer eigenen Regel für beide Beta-Klassen, sonst galt top: 0. */
.anordnenLeiste { position: sticky; top: 0; z-index: 3; display: flex; align-items: center; gap: 12px;
  margin: 0 0 12px; padding: 8px 4px 10px; background: var(--bg); border-bottom: 1px solid var(--border); }
/* 23.10.2026 (INFO.md: „Anordnen am Rechner (≥ 900 px): Leiste „Fertig“
   verdeckt „Heute““): Über der Fläche liegen die Leisten nur unter 900 px
   (oben, „leisten-weg“) - am Rechner stehen Kopf und Reiterleiste in eigener
   Rasterzeile. Dort klebte die Leiste trotzdem um deren Höhe tiefer
   (gemessen 1200 px: 125 px) und deckte mit ihrer Decke die Gruppe „Heute“
   samt erster Aufgabe zu. Wie beim Kopf des Kalenders (.kdKopf, unten): top
   = Höhe der Leisten nur dort, wo sie über der Fläche liegen
   (kleinkram-dom.mjs A). */
@media (max-width: 899px) {
  .anordnenLeiste { top: var(--leisten-hoehe, 0px); }
}
/* Klebend steht die Leiste am Rand des INHALTS der Fläche - unter deren
   Polster oben. Durch diesen Streifen lief die Liste über „Fertig“ hinweg
   sichtbar weiter (gemessen: 12 px). Die Decke reicht von der Leiste nach
   oben bis an den Rand der Fläche - dort schneidet die Fläche sie ab
   (overflow), also ohne das Polster abzuschreiben. Sie fängt auch die
   Tipps ab: Was man nicht sieht, soll man nicht treffen. */
.anordnenLeiste::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%;
  height: 100vh; background: var(--bg); }
.anordnenText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.anordnenTitel { font-size: 0.95rem; font-weight: 600; color: var(--text); }
.anordnenHinweis { font-size: 0.78rem; color: var(--muted); }
.anordnenFertig { flex: none; min-height: 44px; min-width: 88px; padding: 0 20px; border: none;
  border-radius: var(--r-voll); background: var(--primary); color: var(--on-primary); font-size: 0.95rem; font-weight: 600; cursor: pointer; }
.anordnenFertig:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#todosView.anordnen :is(.anlegenPaar, #personenFilterAufgaben) { display: none; }
#todosView.anordnen :is(.checklistenBlock, .erledigtHeute, .todoLogbuch) { opacity: .45; pointer-events: none; }
#todosView.anordnen .dndZeile :is(.check, .del) { opacity: .3; pointer-events: none; }
/* v3.152.1 (Sören: „Die Animation wirkt noch etwas steif. Bzw fehlt“):
   Bis hierher drehte jede Aufgabe gleich weit (0,45 Grad - an einer Zeile
   von 366 px heben sich die Enden um 1,4 px) im selben Takt hin und her, in
   drei Gruppen: ein Pendel. Jetzt zwei Bewegungen in verschiedenem Takt -
   Drehen und ein leises Wippen -, je Aufgabe eigener Takt und eigene Weite
   (0,55 bis 0,75 Grad; aufgaben.js aufgabenWackelnAusrichten). Sie liegen
   auf `rotate` und `translate`: `transform` gehört dem Finger und dem
   Gleiten (projekt.js dndAnordnenSanft), die drei setzen sich zusammen. */
@keyframes aufgabeDreht { from { rotate: calc(-1 * var(--wackelWeite, .6deg)); } to { rotate: var(--wackelWeite, .6deg); } }
@keyframes aufgabeWippt { from { translate: -0.3px 0.5px; } to { translate: 0.3px -0.5px; } }
#todosView.anordnen .dndListe > .dndZeile {
  animation: aufgabeDreht var(--wackelDreh, .26s) ease-in-out infinite alternate, aufgabeWippt var(--wackelWipp, .34s) ease-in-out infinite alternate;
  transition: box-shadow .16s ease-out; }
#todosView.anordnen .dndListe > .dndZeile.dndAktiv { animation: none; }
/* Anheben, Platz machen, Ablegen (projekt.js, v3.152.1): */
#todosView.anordnen .dndListe > .dndZeile.dndHebt { transition: transform .16s ease-out, box-shadow .16s ease-out; }
#todosView.anordnen .dndListe > .dndZeile.dndGleitet { transition: transform .22s cubic-bezier(.2,.8,.2,1), box-shadow .16s ease-out; }
#todosView.anordnen .dndListe > .dndZeile.dndLandet { position: relative; z-index: 5;
  transition: transform .22s cubic-bezier(.2,.8,.2,1), box-shadow .22s ease-out; }
/* Die Pfeile für alle, die nicht ziehen (WCAG 2.5.7): unsichtbar, bis einer
   den Fokus hat - wer mit dem Finger ordnet, sieht nur das Wackeln. */
.anordnenPfeile { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.anordnenPfeile:focus-within { position: static; width: auto; height: auto; overflow: visible; clip-path: none; flex: none; align-self: center; }
.anordnenPfeile .reihenKnoepfe { flex-direction: row; gap: 4px; }
@media (prefers-reduced-motion: reduce) {
  #todosView.anordnen .dndListe > .dndZeile:not(.dndAktiv) { animation: none; box-shadow: var(--ring-innen-1) var(--accent-border); }
  /* v3.152.1: und nichts gleitet - Anheben, Platz machen und Ablegen stehen
     sofort. */
  #todosView.anordnen .dndListe > .dndZeile,
  #todosView.anordnen .dndListe > .dndZeile:is(.dndHebt, .dndGleitet, .dndLandet) { transition: none; }
}

/* ============================================================
   v3.161.0 (Beta „kalender-details“) – KALENDER WIE BEIM IPHONE:
   „Details“ und „Gestapelt“ (public/kalender-details.js).
   Sören (07.10.2026, mit einem Bild der Monatsansicht seines iPhones):
   „Neue Darstellungen Kalender wie bei apple detailansicht hinzufügen“.
   Die Monate stehen untereinander; oben bleiben Monatsname, ‹ › „Heute“
   und die Wochentage stehen (sticky im Reiter, der rollt - #termineView).
   Etiketten in der Farbe der Person: der Grund ist die Farbe leicht auf
   dem Seitengrund (20 %), die Schrift die Farbe in der Schrift (45 %) -
   beides aus Tokens gemischt, so trägt es hell UND dunkel. Gemessen vor dem
   Bau: mit 24 %/55 % kamen das Gelb der Personen hell auf 4,0:1 und Orange
   (--warn) auf 4,2:1; jetzt jede Personenfarbe und jeder Token hell
   ≥ 5,2:1, dunkel ≥ 7,4:1 (kalender-details-dom.mjs misst es im Browser).
   Die Striche von „Gestapelt“ tragen die Farbe unverändert - wie die
   Punkte im Gitter (personen.js v3.32.0: als Punkt gedacht); was ein Tag
   enthält, sagen die Vorlesehilfe und das Blatt nach dem Tipp.
   Ohne Beta greift keine Regel.
   ============================================================ */
.kalDetails { display: none; }
html.beta-kalender-details #kalenderBox[data-stil="details"] > .kalDetails,
html.beta-kalender-details #kalenderBox[data-stil="gestapelt"] > .kalDetails { display: block; }
/* Ein Etikett, das breiter ist als sein Tag, wird abgeschnitten - nie die
   Seite breiter. clip statt hidden: kein eigener Rollbereich, der Kopf
   klebt weiter am Reiter. */
html.beta-kalender-details .kdMonate { overflow-x: clip; }
html.beta-kalender-details #kalenderBox[data-stil="details"] > :not(.kalDetails),
html.beta-kalender-details #kalenderBox[data-stil="gestapelt"] > :not(.kalDetails) { display: none; }
/* Der Kopf klebt oben am Reiter, der rollt (#termineView), und reicht über
   dessen Polster bis an die Ränder. Klebend stünde er unter dem oberen
   Polster - durch diesen Streifen liefen die Tage sichtbar weiter
   (gemessen: 12 px). Darum hängt er um das Polster höher, als er steht
   (transform), und gibt den Platz unten zurück (margin) - die Maße kommen
   aus dem Reiter selbst (kdZeichnen: --kd-polster-oben/-seite), keine
   Abschrift. Unter Kopf und Reiterleiste (sie liegen über der Fläche,
   „leisten-weg“) klebt er wie die Tagesköpfe: top = ihre Höhe, und gehen
   sie, schiebt leistenKoepfeSetzen ihn mit (.leistenKlebt, inline top). */
html.beta-kalender-details .kdKopf { position: sticky; top: 0; z-index: 3; background: var(--bg);
  margin: var(--kd-polster-oben, 0px) calc(-1 * var(--kd-polster-seite, 0px)) calc(-1 * var(--kd-polster-oben, 0px));
  padding: 2px var(--kd-polster-seite, 0px) 6px; transform: translateY(calc(-1 * var(--kd-polster-oben, 0px)));
  border-bottom: 1px solid var(--border); }
@media (max-width: 899px) {
  html.beta-kalender-details .kdKopf { top: var(--leisten-hoehe, 0px); transition: top .26s cubic-bezier(.2,.8,.2,1); }
}
@media (max-width: 899px) and (prefers-reduced-motion: reduce) {
  html.beta-kalender-details .kdKopf { transition: none; }
}
html.beta-kalender-details .kdKopfZeile { display: flex; align-items: center; gap: 6px; }
html.beta-kalender-details .kdTitel { order: 0; flex: 1; min-width: 0; font-size: 1.3rem; font-weight: 800;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html.beta-kalender-details .kdPfeil { order: 1; flex: none; width: 44px; height: 44px; border: 1px solid var(--border-2);
  background: var(--bg); border-radius: var(--r-s); font-size: 1.15rem; color: var(--text-2); }
html.beta-kalender-details .kdPfeil + .kdTitel + .kdPfeil { order: 2; }
html.beta-kalender-details .kdHeute { order: 3; flex: none; min-height: 44px; padding: 0 14px; border: 0;
  border-radius: var(--r-voll); background: var(--surface); color: var(--accent); font-size: 0.86rem; font-weight: 700; }
html.beta-kalender-details .kdHeute.still { color: var(--muted); }
html.beta-kalender-details .kdJahr { font-size: 0.86rem; font-weight: 700; color: var(--muted); }
@media (max-width: 359px) { html.beta-kalender-details .kdTitel { font-size: 1.05rem; } }
html.beta-kalender-details .kdWochentage { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); margin-top: 6px; }
html.beta-kalender-details .kdWochentage span { text-align: center; font-size: 0.7rem; font-weight: 700; color: var(--text-2); }
html.beta-kalender-details .kdWochentage span.we { color: var(--muted); }
html.beta-kalender-details .kdFrueher { display: block; width: 100%; min-height: 44px; margin: 2px 0 0; border: 0;
  background: none; color: var(--accent); font-size: 0.86rem; font-weight: 700; }
html.beta-kalender-details .kdMonat { scroll-margin-top: var(--kd-kopf, 84px); }
html.beta-kalender-details .kdMonatKopf { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); margin: 12px 0 2px; }
html.beta-kalender-details .kdMonatName { margin: 0; padding-left: 4px; font-size: 1.3rem; font-weight: 800; white-space: nowrap; color: var(--text); }
html.beta-kalender-details .kdMonatName.rechts { text-align: right; padding: 0 4px 0 0; }
html.beta-kalender-details .kdMonatName.jetzt { color: var(--accent); }
html.beta-kalender-details .kdWoche { position: relative; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  border-top: 1px solid var(--border); }
/* Die Kalenderwoche sitzt auf der Linie über ihrer Zeile, wie beim iPhone -
   nicht neben der Zahl des Montags. Etwas über der Mitte der Linie: Bei
   -0,5em reichte ihr Kasten 1,6 px in den der Zahl darunter
   (kalender-details-dom.mjs K7). */
html.beta-kalender-details .kdKw { position: absolute; left: 0; top: -0.75em; padding-right: 4px; font-size: 0.7rem; font-weight: 600;
  line-height: 1; color: var(--muted); background: var(--bg); pointer-events: none; }
html.beta-kalender-details .kdTag, html.beta-kalender-details .kdLeer { min-width: 0; min-height: 92px; }
html.beta-kalender-details .kalDetails[data-stil="gestapelt"] .kdTag,
html.beta-kalender-details .kalDetails[data-stil="gestapelt"] .kdLeer { min-height: 66px; }
html.beta-kalender-details .kdTag { display: flex; flex-direction: column; align-items: stretch; gap: 2px;
  padding: 4px 1px 3px; cursor: pointer; color: var(--text); }
html.beta-kalender-details .kdTag.ferien { background: var(--success-bg); }
html.beta-kalender-details .kdNr { align-self: center; min-width: 28px; height: 28px; display: grid; place-items: center;
  font-size: 1.05rem; font-weight: 500; font-variant-numeric: tabular-nums; border-radius: var(--r-kreis); }
html.beta-kalender-details .kdTag.we .kdNr { color: var(--muted); }
html.beta-kalender-details .kdTag.feiertag .kdNr { color: var(--accent-strong); font-weight: 700; }
html.beta-kalender-details .kdTag.heute .kdNr { background: var(--accent); color: var(--auf-farbe); font-weight: 800; }
html.beta-kalender-details .kdEintraege { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
html.beta-kalender-details .kdE { display: block; font-style: normal; font-size: 0.7rem; font-weight: 600; line-height: 1.35;
  min-height: calc(0.7rem * 1.35); padding: 0 3px; margin: 0 1px; border-radius: var(--r-xs);
  white-space: nowrap; overflow: hidden; text-overflow: clip;
  background: color-mix(in srgb, var(--kd-f, var(--accent)) 20%, var(--bg));
  color: color-mix(in srgb, var(--kd-f, var(--accent)) 45%, var(--text)); }
/* Eine Reise über mehrere Tage: ein Band über die Zellen, rund nur an
   Anfang und Ende. */
html.beta-kalender-details .kdE.kdBand { margin: 0 -1px; border-radius: 0; }
html.beta-kalender-details .kdE.kdBand.kdStart { margin-left: 1px; border-top-left-radius: var(--r-xs); border-bottom-left-radius: var(--r-xs); }
html.beta-kalender-details .kdE.kdBand.kdEnde { margin-right: 1px; border-top-right-radius: var(--r-xs); border-bottom-right-radius: var(--r-xs); }
html.beta-kalender-details .kdMehr { display: block; font-style: normal; font-size: 0.7rem; font-weight: 600; line-height: 1.35;
  text-align: center; color: var(--muted); }
/* Gestapelt: dieselben Einträge als Striche, ohne Text. */
html.beta-kalender-details .kalDetails[data-stil="gestapelt"] .kdE { min-height: 0; height: 5px; padding: 0; margin: 1px 4px;
  border-radius: var(--r-voll); background: var(--kd-f, var(--accent)); }
html.beta-kalender-details .kalDetails[data-stil="gestapelt"] .kdE.kdBand { margin: 1px -1px; border-radius: 0; }
/* Die Vorschau in ⚙️ → Darstellung & Gerät → Kalender (ansicht.js). */
html.beta-kalender-details .avKdMonat { font-size: 0.86rem; font-weight: 800; color: var(--accent); margin: 0 0 4px 3px; }
html.beta-kalender-details .avKdWoche { position: relative; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  border-top: 1px solid var(--border); }
html.beta-kalender-details .avKdKw { position: absolute; left: 0; top: 2px; font-size: 0.7rem; line-height: 1; color: var(--muted); }
html.beta-kalender-details .avKdTag { display: flex; flex-direction: column; gap: 2px; min-width: 0; min-height: 70px; padding: 3px 1px; }
html.beta-kalender-details .avKdTag b { align-self: center; min-width: 20px; height: 20px; display: grid; place-items: center;
  font-weight: 500; border-radius: var(--r-kreis); }
html.beta-kalender-details .avKdTag.we b { color: var(--muted); }
html.beta-kalender-details .avKdTag.heute b { background: var(--accent); color: var(--auf-farbe); font-weight: 800; }
html.beta-kalender-details .avKdTag i { display: block; font-style: normal; font-size: 0.7rem; font-weight: 600; line-height: 1.35;
  padding: 0 2px; border-radius: var(--r-xs); white-space: nowrap; overflow: hidden;
  background: color-mix(in srgb, var(--kd-f, var(--accent)) 20%, var(--bg)); color: color-mix(in srgb, var(--kd-f, var(--accent)) 45%, var(--text)); }
html.beta-kalender-details .ansichtVorschau[data-stil="gestapelt"] .avKdTag i { height: 5px; padding: 0; margin: 0 3px;
  border-radius: var(--r-voll); background: var(--kd-f, var(--accent)); }

/* ============================================================
   v3.162.0 - DAS WETTER IN HEUTE UND IN DER FEIER (seit v3.168.0 für alle)
   Sören (07.10.2026): „Wetter funktion bitte umsetzen“ - früher, zu den
   Entwürfen der Richtung C: „Bei Heute noch ein Wetter widget einbauen.“
   Bis v3.168.0 galt alles hier nur unter (LEITFADEN
   Teil 6); seit der Freigabe ist die Weiche aufgelöst. Farben, Ecken und Schriftstufen aus den Tokens,
   keine Schatten; jede Fläche zum Tippen mindestens 44 px, Text 4,5:1 hell
   und dunkel (oberflaeche/wetter-dom.mjs misst es).
   ============================================================ */
/* Der Tageskopf: links Gruß und Datum, rechts der Blick. Passen beide nicht
   nebeneinander (320 px und ein langer Monat), rutscht der Blick in die
   nächste Zeile - nichts ragt heraus, nichts wird abgeschnitten. */
.wtKopf { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  column-gap: 12px; row-gap: 2px; }
.wtKopfText { flex: 1 1 auto; min-width: 0; }
.wtBlick { flex: none; display: inline-flex; flex-direction: column; align-items: flex-end; justify-content: center;
  min-height: 52px; max-width: 100%; padding: 4px 8px; margin: 0 -8px 0 auto; border: 0; border-radius: var(--r-m);
  background: none; color: var(--text); font: inherit; text-align: right; cursor: pointer; }
.wtBlick:active { background: var(--surface-2); }
.wtBlickOben { display: inline-flex; align-items: center; gap: 6px; }
.wtBlickOben .zeichen { flex: none; color: var(--text-2); }
.wtBlickGrad { font-family: var(--font-gross); font-size: 1.7rem; font-weight: 700; letter-spacing: -0.03em;
  line-height: 1.1; font-variant-numeric: tabular-nums; }
.wtBlickOrt { max-width: 11em; font-size: 0.78rem; color: var(--muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
/* Die Schiene: vier Tage als EINE Karte - ein Tipp öffnet das Blatt. */
.wtSchieneBox { margin: 0 0 12px; }
.wtSchiene { display: flex; flex-direction: column; gap: 8px; width: 100%; min-height: 44px; padding: 12px 8px 10px;
  border: 0; border-radius: var(--r-l); background: var(--surface); color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.wtSchiene:active { background: var(--surface-2); }
.wtTage { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px; }
.wtTag { display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; }
.wtTagName { font-size: 0.78rem; font-weight: 600; color: var(--text-3); }
.wtTag .zeichen { flex: none; color: var(--text-2); }
.wtTagGrad { font-size: 0.92rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.wtMax { font-weight: 700; color: var(--text); }
.wtMin { color: var(--muted); }
.wtSatz { display: block; margin: 0 6px; font-size: 0.86rem; font-weight: 600; color: var(--accent-strong); }
.wtQuelle { margin: 4px 8px 0; font-size: 0.7rem; color: var(--muted); }
.wtOhneOrt { display: block; width: 100%; min-height: 44px; margin: 0; padding: 10px 12px; border: 0;
  border-radius: var(--r-m); background: var(--surface); color: var(--text-2); font: inherit; font-size: 0.86rem;
  line-height: 1.4; text-align: left; }
.wtOhneOrt.wtWeg { cursor: pointer; }
.wtOhneOrt.wtWeg:active { background: var(--surface-2); }
/* Der Weg bricht nicht in der Mitte um („⚙️“ allein am Zeilenende). */
.wtPfad { white-space: nowrap; font-weight: 600; color: var(--text); }
/* Das Gerippe, solange das erste Wetter kommt (LEITFADEN Teil 2 D:
   vor der ersten Antwort ein Gerippe, nicht „nichts da“). */
.wtGerippe { cursor: default; }
.wtSchiene.wtGerippe { flex-direction: row; gap: 8px; }
.wtGz { position: relative; overflow: hidden; display: block; flex: 1; height: 64px;
  border-radius: var(--r-m); background: var(--surface-2); }
.wtBlick .wtGz { flex: none; width: 72px; height: 40px; }
.wtGz::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--surface), transparent);
  transform: translateX(-100%); animation: gerippeWandert 1.3s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .wtGz::after { animation: none; }
}
/* Die Übersicht der Feier: eine Karte über den Punkten der Planung. */
.wtFeierBox { margin: 0 0 12px; }
.wtFeierBox:empty { display: none; }
.wtFeier { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 64px; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: var(--r-l); background: var(--surface); color: var(--text);
  font: inherit; text-align: left; cursor: pointer; }
.wtFeier:active { background: var(--surface-2); }
.wtFeierZeichen { flex: none; display: grid; place-items: center; color: var(--text-2); }
.wtFeierText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.wtFeierWas { font-size: 0.95rem; font-weight: 600; overflow-wrap: anywhere; }
.wtFeierWert { font-size: 0.86rem; color: var(--text-2); }
.wtFeierBeginn { font-size: 0.82rem; color: var(--text-3); }
.wtFeierHinweis { margin: 0; padding: 4px 4px 0; font-size: 0.86rem; line-height: 1.4; color: var(--text-3); }
/* Das Blatt: jetzt, die nächsten Stunden, die Tage, die anderen Orte. */
.wtBlatt { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.wtJetzt { display: flex; align-items: center; gap: 12px; min-width: 0; }
.wtJetzt .zeichen { flex: none; color: var(--text-2); }
.wtJetztGrad { flex: none; font-family: var(--font-gross); font-size: 2.4rem; font-weight: 700;
  letter-spacing: -0.03em; line-height: 1; font-variant-numeric: tabular-nums; }
.wtJetztText { display: flex; flex-direction: column; min-width: 0; }
.wtJetztWas { font-size: 1rem; font-weight: 600; }
.wtJetztOrt { font-size: 0.82rem; color: var(--muted); overflow-wrap: anywhere; }
.wtBlatt .wtSatz { margin: 0; }
.wtTitel { margin: 6px 0 0; font-size: 0.86rem; font-weight: 700; color: var(--text-2); }
/* Zwölf Stunden in zwei Reihen zu sechs - auch bei 320 px (je 46 px). */
.wtStunden { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 6px 4px; }
.wtStunde { display: flex; flex-direction: column; align-items: center; gap: 2px; min-width: 0; padding: 6px 0 4px;
  border-radius: var(--r-s); background: var(--surface); }
.wtStundeZeit { font-size: 0.78rem; color: var(--text-3); font-variant-numeric: tabular-nums; }
.wtStunde .zeichen { flex: none; color: var(--text-2); }
.wtStundeGrad { font-size: 0.92rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.wtStundeRegen { min-height: 1.1em; font-size: 0.7rem; color: var(--accent-strong); font-variant-numeric: tabular-nums; }
.wtTageListe { display: flex; flex-direction: column; }
.wtTagZeile { display: grid; grid-template-columns: 4.9em 24px minmax(0, 1fr) auto; align-items: center;
  column-gap: 10px; min-height: 44px; padding: 4px 2px; border-bottom: 1px solid var(--border); }
.wtTagZeile:last-child { border-bottom: 0; }
.wtTagZeileName { font-size: 0.86rem; font-weight: 600; white-space: nowrap; }
.wtTagZeile .zeichen { color: var(--text-2); }
.wtTagZeileText { display: flex; flex-direction: column; min-width: 0; font-size: 0.86rem; color: var(--text-2); }
.wtTagZeileRegen { font-size: 0.78rem; color: var(--accent-strong); }
.wtTagZeileGrad { font-size: 0.92rem; white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; }
.wtOrte { display: flex; flex-direction: column; gap: 6px; }
.wtOrt { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; min-height: 44px;
  padding: 8px 12px; border: 0; border-radius: var(--r-m); background: var(--surface); color: var(--text);
  font: inherit; text-align: left; cursor: pointer; }
.wtOrt:active { background: var(--surface-2); }
.wtOrtName { min-width: 0; font-size: 0.92rem; font-weight: 600; overflow-wrap: anywhere; }
.wtOrtWert { flex: none; display: inline-flex; align-items: center; gap: 6px; font-size: 0.86rem; color: var(--text-2); }
.wtOrtGrad { font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
/* Ein Ort ohne Wetter ist keine Fläche zum Tippen - nur sein Satz. */
.wtOrt.wtOrtLeer { flex-direction: column; align-items: flex-start; gap: 2px; cursor: default; }
.wtOrtLeer .wtOrtWert { flex: 1 1 auto; display: block; }
.wtFuss { display: flex; flex-wrap: wrap; align-items: center; column-gap: 4px; margin: 4px 0 0;
  font-size: 0.78rem; color: var(--muted); }
.wtFussLink { display: inline-flex; align-items: center; min-height: 44px; font-weight: 600; color: var(--accent-strong); }
/* v3.165.0 - DAS WETTER IM RAUMKOPF. Sören (08.10.2026): „Wettersymbol in
   den header neben haushalt … und daneben die gradzahl. Immer angezeigt
   ganz clean“. Kein Rahmen, keine Fläche: Zeichen und Zahl in der Farbe
   des Nebentexts, die Zahl in der Größe des Raumnamens, nur leichter. Der
   Knopf ist 44 px hoch (wie Suche und Einstellungen) - der Kopf bleibt
   52 px. Er schrumpft nie; neben ihm kürzt der Raumname mit „…“
   (.bsKopfWort). Dazu darf der Titel nicht mehr den ganzen Rest der Zeile
   nehmen (app.css: .raumTitel flex: 1) - sonst stünde das Wetter rechts
   außen statt neben dem Namen. Der Fokusring liegt innen: .bsKopfName
   schneidet ab, was über den Rand ragt.
   Gemessen bei 390 px mit Beta: Neben Zurück, Beta-Pille, Suche und
   Einstellungen blieben für Zeichen, „Haushalt“ und Wetter 169 px - 9 zu
   wenig, „Haushalt“ wurde zu „Hau…“. Darum steht auf dem Telefon neben dem
   Wetter nur das Zeichen der Beta-Pille (wie schon unter 360 px; das Wort
   steht im aria-label) - der Raumname hat Vorrang vor dem Wort „Beta“. */
.bsKopfEins.wtMitKopf .raumTitel { flex: 0 1 auto; }
@media (max-width: 479px) {
  .bsKopfEins.wtMitKopf .betaMarkeWort { display: none; }
  .bsKopfEins.wtMitKopf .betaMarkePille { padding: 0 6px; }
}
.wtRaumWetter { flex: none; display: inline-flex; align-items: center; gap: 4px; min-width: 44px; height: 44px;
  margin: 0 0 0 -4px; padding: 0 4px; border: 0; border-radius: var(--r-s); background: none; color: var(--text-2);
  font: inherit; font-size: 1.05rem; font-weight: 500; line-height: 1; white-space: nowrap; cursor: pointer; }
.wtRaumWetter .zeichen { flex: none; }
.wtRaumWetterGrad { font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
.wtRaumWetter:active { background: var(--surface-2); }
.wtRaumWetter:focus-visible { box-shadow: var(--ring-innen-2) var(--accent); }

/* ============================================================
   v3.163.0 (Beta „einstellungen-suche“, Sören: „Gibt es eine Anleitung in
   chato in der man zb per volltext sucht was man machen möchte …“ – „1. gut“):
   das Suchfeld über der Übersicht der Einstellungen und seine Treffer
   (public/einstellungen-suche.js). Treffer sind .setZeile wie jede andere
   Zeile - nur Tokens, 44 px.
   ============================================================ */
html.beta-einstellungen-suche .suKopf { margin: 0 0 8px; }
html.beta-einstellungen-suche .suFeld { width: 100%; min-height: 44px; padding: 10px 12px; border: 1px solid var(--border-2);
  border-radius: var(--r-s); background: var(--bg); color: var(--text); font: inherit; font-size: 16px;
  -webkit-appearance: none; appearance: none; }
html.beta-einstellungen-suche .suStand { margin: 0 2px 6px; font-size: 0.78rem; color: var(--muted); }
html.beta-einstellungen-suche .suStand:empty { display: none; }
html.beta-einstellungen-suche .suTrefferZeile .ut { overflow-wrap: anywhere; }
html.beta-einstellungen-suche .suLeer { padding: 6px 2px 10px; }
html.beta-einstellungen-suche .suLeerSatz { margin: 0 0 6px; font-size: 0.92rem; color: var(--text); overflow-wrap: anywhere; }
/* Die Zeile, zu der ein Treffer (oder „Dorthin“ im Helfer) springt - ohne
   Klasse davor: Der Helfer springt auch, wenn nur seine Beta an ist. Bei
   „Bewegung reduzieren“ steht die Hervorhebung still da (JS nimmt sie nach
   1,8 s wieder weg). */
.suHell { background: var(--accent-bg); }
@media (prefers-reduced-motion: no-preference) {
  .suHell { animation: blaseHervor 1.8s ease-out; }
}
/* v3.165.1 (Rückmeldung aus der Prüfliste: „Mach den reiter eure läden
   einklAppbar“): „Eure Läden“ unter ⚙️ → Haushalt - der Kopf ist der Knopf
   (44 px), wie beim geteilten Einkauf (.teilenBandKopf). Die Überschrift
   bleibt eine h4, damit die Suche sie weiter findet. */
.zugAbschnitt > h4.suKlappH { margin: 0 0 4px; }
.suKlappKopf { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px; padding: 0; border: 0; background: none;
  color: inherit; font: inherit; font-weight: inherit; text-align: left; cursor: pointer; }
.suKlappKopf:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-s); }
.suKlappTitel { min-width: 0; overflow-wrap: anywhere; }
.suKlappZahl { flex: none; font-size: 0.78rem; font-weight: 700; color: var(--text-2); background: var(--surface-2); border-radius: var(--r-voll); padding: 2px 8px; }
.suKlappPfeil { margin-left: auto; flex: none; display: inline-flex; width: 32px; justify-content: center; color: var(--text-3); }
.suKlappPfeil .zeichen { transition: transform 0.15s ease; }
.suKlappKopf[aria-expanded="false"] .suKlappPfeil .zeichen { transform: rotate(-90deg); }
@media (prefers-reduced-motion: reduce) { .suKlappPfeil .zeichen { transition: none; } }
.suKlapp > [hidden] { display: none; }

/* ============================================================
   v3.163.0 (Beta „helfer“, Sören: „… mach dafür einen extra helfer sonst ist
   der Chat nur noch chaotischer …“): das Blatt des Helfers (public/helfer.js)
   - ein eigenes kleines Gespräch, bewusst nicht wie der Familien-Chat.
   ============================================================ */
html.beta-helfer .hfErklaerung { margin: 0 0 10px; }
html.beta-helfer .hfVerlauf { display: flex; flex-direction: column; gap: 10px; margin: 0 0 10px; }
html.beta-helfer .hfPaar { display: flex; flex-direction: column; gap: 6px; }
html.beta-helfer .hfFrage { align-self: flex-end; max-width: 85%; margin: 0; padding: 8px 12px; border-radius: var(--r-m);
  background: var(--accent-bg); color: var(--text); font-size: 0.92rem; overflow-wrap: anywhere; }
html.beta-helfer .hfAntwort { align-self: flex-start; max-width: 92%; padding: 8px 12px; border-radius: var(--r-m);
  background: var(--surface); color: var(--text); }
html.beta-helfer .hfAntwortText { margin: 0; font-size: 0.92rem; line-height: 1.4; overflow-wrap: anywhere; }
html.beta-helfer .hfFehler { background: var(--warn-bg); }
html.beta-helfer .hfFehler .hfAntwortText { color: var(--warn-text); }
html.beta-helfer .hfDenkt .hfAntwortText { color: var(--muted); }
html.beta-helfer .hfZiele { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
html.beta-helfer .hfDorthin { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: 100%;
  text-align: left; border-color: var(--accent-border); background: var(--bg); color: var(--accent-strong); }
html.beta-helfer .hfDorthinWeg { font-weight: 500; font-size: 0.78rem; color: var(--text-2); overflow-wrap: anywhere; }
html.beta-helfer .hfLeer { margin: 0; font-size: 0.86rem; color: var(--muted); }
html.beta-helfer .hfEingabe { margin: 0 0 8px; }
html.beta-helfer .hfEingabe input { min-height: 44px; font-size: 16px; }
html.beta-helfer .hfSenden { min-width: 44px; min-height: 44px; }

/* ============================================================
   v3.172.0 (Beta „einstellungen-ordnung“, Sören: „Einstellungen auch noch
   nicht behoben.“ – „das symbol für löschen und verschieben in der
   übersicht ist irreführend“): Übersicht in Gruppen, „Raum einstellen“,
   Raumliste beim Ordnen (public/app-einstellungen-ordnung.js). Ohne Beta
   gilt keine dieser Regeln.
   ============================================================ */
/* Die Unterzeile der Übersicht bleibt EINE Zeile – die Texte sind dafür
   kurz gehalten (ORDNUNG_UNTER_MAX); wird es doch eng (320 px, großer
   Text), kürzt sie mit „…“, statt die Zeile wachsen zu lassen. */
html.beta-einstellungen-ordnung .ordnungGruppe .setZeile .ut { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html.beta-einstellungen-ordnung .ordnungGruppe .setZeile.setInfo .ut { white-space: normal; }
html.beta-einstellungen-ordnung .ordnungGruppe h4 { overflow-wrap: anywhere; }
html.beta-einstellungen-ordnung .ordnungGruppe.klein { margin-top: 26px; }
/* Endgültig löschen und verlassen: Zeichen und Wort rot. Chat leeren legt
   nur weg – das Zeichen in der Warnfarbe, das Wort normal. */
html.beta-einstellungen-ordnung .setZeile.loeschen .tt,
html.beta-einstellungen-ordnung .setZeile.loeschen .sym { color: var(--danger); }
html.beta-einstellungen-ordnung .setZeile.mahnung .sym { color: var(--warn-text); }
html.beta-einstellungen-ordnung .setZeile .sym .zeichen { display: block; margin: 0 auto; }
/* Raumliste beim Ordnen: drei Knöpfe in einer Reihe, die Zeile höchstens
   64 px – ohne Vorschau und Uhrzeit, das Symbol etwas kleiner. */
html.beta-einstellungen-ordnung .raumEintrag.ordnen { padding-top: 8px; padding-bottom: 8px; min-height: 0; gap: 10px; }
html.beta-einstellungen-ordnung .raumEintrag.ordnen:not(.klein) .raumSymbol { width: 36px; height: 36px; border-radius: var(--r-m); font-size: 1.15rem; }
/* Beim Ordnen zählt der Name: Vorschau, Uhrzeit und die Marke der
   Raumart weichen (die Marke steht wieder da, sobald „Fertig“ getippt ist). */
html.beta-einstellungen-ordnung .raumEintrag.ordnen .raumVorschau,
html.beta-einstellungen-ordnung .raumEintrag.ordnen .raumName .zeit,
html.beta-einstellungen-ordnung .raumEintrag.ordnen .raumVariante { display: none; }
html.beta-einstellungen-ordnung .raumEintrag.ordnen .raumName > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
html.beta-einstellungen-ordnung .ordnungKnoepfe { flex-wrap: nowrap; max-width: none; }
html.beta-einstellungen-ordnung .ordnungKnoepfe .ordnenBtn { display: inline-flex; align-items: center; justify-content: center; padding: 0; }
html.beta-einstellungen-ordnung .ordnungMehr { font-size: 1.15rem; font-weight: 700; line-height: 1; }
html.beta-einstellungen-ordnung #raumOrdnenKnopf .zeichen { display: block; margin: 0 auto; }

/* ============================================================
   24.10.2026 – DIE LADESEITE (Beta „start-ladeseite“)
   Sören: „Immer wenn man chato startet kommt die website. Bitte erstelle
   eine schöne animierte ladeseite.“
   Das Kopf-Skript in index.html setzt html.startLaedt, wenn das Gerät
   angemeldet ist (chato_role) und die Beta beim letzten Kontakt an war.
   Dann steht statt der Website (#setup) die Ladeseite da, bis der Raum
   darunter gezeichnet ist (app-gesten.js ladeSchirmFertig): Fläche --bg,
   das Zeichen mittig, der Ring des „o“ schließt sich einmal, die Wortmarke
   darunter – zusammen knapp 2 s (Sog, s. u.), danach Stillstand (kein Pulsieren, nichts
   läuft weiter). Der Abgang: 180 ms Deckkraft auf 0 und eine Spur größer;
   der Raum steht darunter schon, nichts verschiebt sich. Ohne Beta oder
   ohne Anmeldung gilt keine dieser Regeln außer der ersten.
   ============================================================ */
#ladeSchirm { display: none; }
html.startLaedt #ladeSchirm {
  display: flex; position: fixed; inset: 0; z-index: 9998;
  flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: 16px; background: var(--bg); color: var(--text);
  transition: opacity 180ms ease-out, transform 180ms ease-out;
}
/* Die Website bleibt verborgen, solange geladen wird - auch gegen den
   Inline-Stil, den die Anmeldung setzt. Zeigt die App die Website doch
   (nicht mehr angemeldet), räumt ladeSchirmFertig die Ladeseite weg, und
   die Website erscheint beim Abgang darunter. */
html.startLaedt:not(.startGeht) #setup { display: none !important; }
html.startLaedt.startGeht #ladeSchirm { opacity: 0; transform: scale(1.04); pointer-events: none; }
#ladeSchirm .ladeZeichen { display: block; position: relative; z-index: 1; width: 76px; height: 76px;
  animation: ladeZeichenAuf 240ms cubic-bezier(.2, .8, .2, 1) both, ladePuls 900ms cubic-bezier(.3, .7, .3, 1) 880ms; }
#ladeSchirm .ladeStopA { stop-color: var(--marke-a); }
#ladeSchirm .ladeStopB { stop-color: var(--marke-b); }
#ladeSchirm .ladeBlase { fill: var(--stets-weiss); }
/* Der Masken-Wisch: Der Ring wird von 9 Uhr im Uhrzeigersinn bis 6 Uhr
   freigelegt (75 von 100); das letzte Viertel trägt die Ecke der Blase
   schon von Anfang an. Er schließt sich ZULETZT, wenn die Chips aufgenommen
   sind. */
#ladeSchirm .ladeRingWisch { stroke-dasharray: 100; stroke-dashoffset: 25; animation: ladeRing 1440ms linear 540ms both; }
#ladeSchirm .ladeWort { position: relative; z-index: 1; font-size: 1.5rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1; animation: ladeWortAuf 320ms cubic-bezier(.2, .8, .2, 1) 300ms both; }
#ladeSchirm .ladeWortO { background: linear-gradient(100deg, var(--marke-a), var(--marke-b)); -webkit-background-clip: text; background-clip: text; color: transparent; }
#ladeSchirm .ladeSchirmSatz { position: relative; z-index: 1; margin: 0; min-height: 1.4em; max-width: 280px; text-align: center; font-size: 0.92rem; color: var(--muted); opacity: 0; transition: opacity 300ms ease-out; }
html.startWartet #ladeSchirm .ladeSchirmSatz { opacity: 1; }
/* 24.10.2026 – DER SOG (Sören: „Cool wär doch wenn texte und aufgaben in das
   logo in der mitte gezogen werden und das logo die sozusagen aufsaugt. …
   hackelt auch.“) – und danach, iPhone: „Und kann man das etwas besser
   erkennbar machen was da reinfliegt? Das geht so schnell.“ GEMESSEN: Vorher
   flogen sechs Chips 50 ms versetzt in 460 ms - keiner stand länger als ein
   Wimpernschlag still. Jetzt zeigt sich jeder Chip einzeln: vier Chips, je
   240 ms versetzt, jeder 900 ms lang - 280 ms von außen heranschweben und
   einblenden, dann ruhig stehen (über 0,9 Deckkraft rund 500 ms: lesbar),
   dann 360 ms beschleunigend in die Mitte gesaugt (schrumpfend); das Zeichen
   pulsiert bei jeder Aufnahme, zuletzt schließt sich der Ring. Gesamt 1,98 s,
   danach Stillstand. Die Länge steht NUR hier (Verzögerung + Dauer des Rings);
   app-gesten.js liest sie als Mindestanzeige. NUR transform und opacity: läuft
   auf dem Grafikprozessor weiter, auch wenn die Seite Skripte lädt - der Ring
   (Maske) ist das Einzige, was die Seite selbst zeichnet, darum kommt er
   zuletzt. Kein will-change, kein Filter, kein Schatten. */
#ladeSchirm .ladeSog { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
#ladeSchirm .ladeChip {
  --hx: 0px; --hy: -120px; --ex: 0px; --ey: -30px; --v: 0ms; /* je Chip inline in index.html: Halteplatz, Anflug, Beginn */
  position: absolute; left: 50%; top: 50%; white-space: nowrap; max-width: calc(100vw - 32px);
  padding: 10px 16px; border: 1px solid var(--border); border-radius: var(--r-m);
  background: var(--surface); color: var(--text); font-size: 1rem; font-weight: 600; line-height: 1.2;
  opacity: 0; transform: translate(-50%, -50%) translate(0, 0) scale(.12);
  animation: ladeChipFlug 900ms linear var(--v) both, ladeChipSicht 900ms linear var(--v) both;
}
/* 0-280 ms heranschweben (bremst ab), bis 540 ms stehen, dann 360 ms in die Mitte (beschleunigt). */
@keyframes ladeChipFlug {
  0% { transform: translate(-50%, -50%) translate(calc(var(--hx) + var(--ex)), calc(var(--hy) + var(--ey))) scale(.92); animation-timing-function: cubic-bezier(.2, .8, .2, 1); }
  31% { transform: translate(-50%, -50%) translate(var(--hx), var(--hy)) scale(1); }
  60% { transform: translate(-50%, -50%) translate(var(--hx), var(--hy)) scale(1); animation-timing-function: cubic-bezier(.55, .05, .9, .45); }
  100% { transform: translate(-50%, -50%) translate(0, 0) scale(.12); }
}
@keyframes ladeChipSicht { 0% { opacity: 0; } 22% { opacity: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }
/* Vier Aufnahmen bei 900, 1140, 1380 und 1620 ms (Chip-Beginn + 900): je ein kleiner Puls, der letzte der größte. */
@keyframes ladePuls {
  0% { transform: none; } 9% { transform: scale(1.05); } 24% { transform: none; }
  26.7% { transform: none; } 35.7% { transform: scale(1.06); } 50% { transform: none; }
  53.3% { transform: none; } 62.3% { transform: scale(1.07); } 77% { transform: none; }
  80% { transform: none; } 89% { transform: scale(1.09); } 100% { transform: none; }
}
@keyframes ladeZeichenAuf { from { opacity: 0; transform: scale(.92); } to { opacity: 1; transform: none; } }
/* 25.10.2026 (Sören: „Bei der startanimation füllt sich das chato logo nicht mit jeder task sondern am ende erst. Mach das bitte wie einen fortschrittsbalken“):
   Der Ring füllt sich in vier Vierteln, jedes endet genau, wenn der zugehörige Chip aufgenommen ist (900, 1140, 1380, 1620 ms; Beginn 540 ms =
   Abflug des ersten Chips). Dauer 1440 ms ab 540 ms = 1980 ms wie bisher, die Mindestanzeige bleibt gleich. Prozent = (Aufnahme - 540) / 1440. */
@keyframes ladeRing {
  0% { stroke-dashoffset: 100; animation-timing-function: cubic-bezier(.3, .7, .3, 1); }
  25% { stroke-dashoffset: 81.25; animation-timing-function: cubic-bezier(.3, .7, .3, 1); }
  41.667% { stroke-dashoffset: 62.5; animation-timing-function: cubic-bezier(.3, .7, .3, 1); }
  58.333% { stroke-dashoffset: 43.75; animation-timing-function: cubic-bezier(.3, .7, .3, 1); }
  75%, 100% { stroke-dashoffset: 25; }
}
@keyframes ladeWortAuf { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
/* Reduzierte Bewegung: keine Chips, alles steht von Anfang an, der Abgang ist
   eine reine Überblendung von 150 ms. */
@media (prefers-reduced-motion: reduce) {
  #ladeSchirm .ladeZeichen, #ladeSchirm .ladeRingWisch, #ladeSchirm .ladeWort { animation: none; }
  #ladeSchirm .ladeSog { display: none; }
  #ladeSchirm .ladeSchirmSatz { transition: none; }
  html.startLaedt #ladeSchirm { transition: opacity 150ms linear; }
  html.startLaedt.startGeht #ladeSchirm { transform: none; }
}

/* ============================================================
   24.10.2026 – DER KNOPF OBEN LINKS (Beta „knopf-oben-links“)
   Sören: „Wenn man oben im reiter auf das haus klickt springt man aktuell
   in den chat. Das sollte einstellbar sein.“ – GEMESSEN: Nur „‹“ reagierte;
   das Raumzeichen daneben war eine tote Stelle. Mit Beta stehen beide in
   EINEM Knopf (app-menue.js knopfObenZeichnen), 44 px hoch; das Zeichen im
   Namen fällt weg. Ohne Beta bleibt der Knopf „‹“ allein.
   ============================================================ */
#raumZurueck .knopfObenZeichen { display: none; }
html.beta-knopf-oben-links .bsKopfName .bsKopfZeichen { display: none; }
html.beta-knopf-oben-links #raumZurueck { width: auto; min-width: 44px; display: inline-flex; align-items: center; gap: 2px; padding: 0 6px 0 2px; }
html.beta-knopf-oben-links #raumZurueck .knopfObenZeichen { display: grid; }
html.beta-knopf-oben-links #raumZurueck:active .knopfObenZeichen { background: var(--border); }
/* Am Rechner steht die Raumliste daneben - dort bleibt es wie bisher: kein
   Knopf, das Zeichen im Namen. */
@media (min-width: 900px) {
  html.beta-knopf-oben-links #raumZurueck { display: none; }
  html.beta-knopf-oben-links .bsKopfName .bsKopfZeichen { display: grid; }
}

/* 24.10.2026 (Sören: Beim Absenden der Fehlermeldung passiert nach „Senden“ erst
   nichts, „Danke“ erscheint erst nach einer Weile – unklar, ob abgesendet wurde;
   Beta „senden-zustand“, melden.js meldenSendeZustand): Der Knopf zeigt SOFORT
   „Wird gesendet …“ mit kleinem Kreisel; danach blendet das Danke-Feld sanft ein.
   Nur Opacity/Transform – kein Zuhörer am Dokument, kein touch-action. */
html.beta-senden-zustand #meldenModal .modalActions button.meldenSendet { opacity: .85; cursor: progress; }
html.beta-senden-zustand .meldenKreisel { display: inline-block; width: 1em; height: 1em; margin-right: 8px; vertical-align: -0.15em;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: var(--r-voll); animation: meldenDreh .8s linear infinite; }
html.beta-senden-zustand #meldenSendeStatus { margin: 0 0 8px; font-size: 0.86rem; color: var(--muted); animation: meldenEin .2s ease both; }
html.beta-senden-zustand #meldenSendeStatus:empty { display: none; }
html.beta-senden-zustand #meldenSendeStatus.fehler { color: var(--danger); font-weight: 600; }
html.beta-senden-zustand #meldenModal.meldenFertig .modalActions button:not(.zurueckBtn) { display: none; }
html.beta-senden-zustand .meldenDanke { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 28px 12px; text-align: center;
  background: var(--success-bg); color: var(--success-text); border: 1px solid var(--success-border); border-radius: var(--radius); animation: meldenEin .32s ease both; }
html.beta-senden-zustand .meldenDankeHaken { font-size: 1.5rem; line-height: 1; font-weight: 700; }
html.beta-senden-zustand .meldenDankeText { font-weight: 600; }
html.beta-senden-zustand .meldenDankeSub { font-size: 0.86rem; margin: 0; }
@keyframes meldenDreh { to { transform: rotate(360deg); } }
@keyframes meldenEin { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  html.beta-senden-zustand .meldenKreisel { animation: none; border-right-color: currentColor; opacity: .6; }
  html.beta-senden-zustand .meldenDanke, html.beta-senden-zustand #meldenSendeStatus { animation: none; }
}

/* v3.179.0: leerer Absatz ohne Beta nimmt keinen Raum (Leitfaden-Fund) */
#meldenSendeStatus:empty { display: none; }

/* 26.10.2026 (Sören: „Bitte Funktion bild in Chat hinzufügen.“ und „Das bild soll doch die
   Erkennung aktivieren“; Beta „bild-im-chat“, public/app-bild.js, Server src/raum-bild.js).
   Zwei Teile: (1) KNOPF und VORSCHAU-STREIFEN nur mit Beta - ohne sie bleibt die Eingabezeile
   wie gehabt; (2) die BLASE einer Bild-Nachricht gilt für alle, denn der Server liefert Bilder
   immer aus. Tokens aus :root, keine freien Farben und Schatten; Bewegung nur der kleine Ring,
   mit reduzierter Bewegung steht er still. Kein Zuhörer am Dokument, kein touch-action. */
html:not(.beta-bild-im-chat) #bildBtn, html:not(.beta-bild-im-chat) #bildStreifen { display: none; }
#inputRow button#bildBtn { background: var(--surface-2); color: var(--text); }
#inputRow.aufnahme > #bildBtn, #inputRow.wandelt > #bildBtn { display: none; }
/* Unter 360 px passen 📷, Feld und zwei weitere Knöpfe nicht nebeneinander (320 px: das Feld
   bliebe bei rund 138 px). Dort steht neben 📷 nur 🎙️ - oder ➤, sobald Text oder ein Bild da ist. */
@media (max-width: 359.98px) {
  #inputRow.mitBild:not(.hatInhalt) #sendBtn { display: none; }
  #inputRow.mitBild.hatInhalt #mikroBtn { display: none; }
}
/* Der Streifen über der Eingabezeile: Miniatur, Größe, ✕ (44 px). */
#bildStreifen { display: flex; align-items: center; gap: 10px; padding: 8px 12px 0; background: var(--bg); flex: none; }
#bildStreifen[hidden] { display: none; }
#bildStreifen img { flex: none; width: 64px; height: 64px; object-fit: cover; border-radius: var(--r-s); background: var(--surface-2); }
#bildStreifen.bereitet img { visibility: hidden; }
#bildStreifen .bildStreifenText { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; font-size: 0.82rem; color: var(--text-2); }
#bildStreifen #bildStreifenMeldung { font-size: 0.78rem; color: var(--text-3); line-height: 1.3; }
#bildStreifen #bildStreifenMeldung.fehler { color: var(--danger); font-weight: 600; }
#bildStreifen #bildStreifenMeldung:empty { display: none; }
#bildStreifen #bildStreifenWeg { flex: none; width: 44px; height: 44px; border-radius: var(--r-kreis); border: none;
  background: var(--surface-2); color: var(--text-2); font-size: 0.92rem; }
#chatView:has(#bildStreifen:not([hidden])) #nachUnten { bottom: calc(156px + var(--sab)); }
body.tastatur #chatView:has(#bildStreifen:not([hidden])) #nachUnten { bottom: 156px; }

/* Die Blase: Breite aus dem Seitenverhältnis (--verh, gesetzt von app-bild.js), Höhe 120 bis 320 px,
   Platzhalter in --surface-2 - so springt der Verlauf nicht, wenn das Bild nachlädt. */
.bubble.bild { width: max(200px, min(75%, calc(320px * var(--verh, 1.3333) + 12px))); padding: 6px; }
.bubble.bild .meta, .bubble.bild .bildUnterschrift, .bubble.bild .bildLesen, .bubble.bild .bildLaedt { padding: 0 6px; }
.bubble.bild .zitat { margin: 0 0 6px; }
.bildFlaeche { position: relative; display: block; width: 100%; aspect-ratio: var(--verh, 1.3333); min-height: 120px; max-height: 320px;
  padding: 0; border: none; overflow: hidden; border-radius: var(--r-s); background: var(--surface-2); color: var(--text-2); cursor: pointer; }
div.bildFlaeche { cursor: default; }
.bildFlaeche .bildBild { display: block; width: 100%; height: 100%; object-fit: cover; }
.bildFlaeche .bildFehlt { display: none; position: absolute; inset: 0; align-items: center; justify-content: center; padding: 12px;
  text-align: center; font-size: 0.82rem; }
.bildFlaeche.fehlt .bildBild { visibility: hidden; }
.bildFlaeche.fehlt .bildFehlt { display: flex; }
.bubble.bild.wartet .bildBild { opacity: .6; }
.bildUnterschrift { margin-top: 6px; line-height: 1.3; }
.bildLesen { margin-top: 4px; font-size: 0.7rem; color: var(--text-3); }
.bildLaedt { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 4px; font-size: 0.78rem; color: var(--text-2); }
.bildLaedt .bildLaedtText { flex: 1 0 auto; white-space: nowrap; }
.bildLaedt .bildAbbrechen { flex: 1 1 auto; }
.bildRing { flex: none; width: 18px; height: 18px; border-radius: var(--r-kreis); border: 3px solid var(--border-2); border-top-color: var(--accent); animation: bildDreht .9s linear infinite; }
@keyframes bildDreht { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .bildRing { animation: none; } }
.bildAbbrechen, .bildNochmal { min-height: 44px; padding: 0 12px; font: inherit; font-size: 0.82rem; color: var(--text); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-s); cursor: pointer; }
.bildNochmal { display: block; width: 100%; margin-top: 6px; color: var(--danger); text-align: left; }
.bubble.bild.fehlgeschlagen .sendeFehlerKnoepfe { padding: 0 6px; }
.bubble.bild.fehlgeschlagen .sendeFehlerHinweis { padding: 0 6px; }
/* Entfernt: eine graue Blase mit Rückgängig (nur für den Absender). */
.bubble.bildWeg { background: var(--surface-2); color: var(--text-2); }
.bubble.bildWeg .bildWegText { font-style: italic; }
.bubble.bildWeg .bildRueckgaengig { min-height: 44px; margin-top: 4px; padding: 0 12px; font: inherit; font-size: 0.82rem; color: var(--text);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-s); cursor: pointer; }

/* 28.10.2026 (Beta „umfrage-im-chat“, app-umfrage-chat.js): die Zeile „Aus der Umfrage …“ über einer
   Nachricht aus dem Umfrage-Chat. Eine fremde Blase (links), der Vermerk klein und ruhig darüber;
   angetippt (ein Knopf) öffnet er die Umfrage. Nur Tokens der App, der Knopf ist mindestens 44 px hoch. */
.bubble.umfrageChat { max-width: min(85%, 28rem); }
.bubble.umfrageChat .umfrageChatVermerk { display: flex; align-items: flex-start; gap: 6px; width: 100%; margin: 0 0 4px; padding: 0; border: 0; background: none; font: inherit; font-size: 0.82rem; line-height: 1.3; color: var(--text-2); text-align: left; }
.bubble.umfrageChat button.umfrageChatVermerk { min-height: 44px; margin: -8px 0 -4px; padding: 8px 0; cursor: pointer; text-decoration: underline; text-decoration-color: var(--text-3); text-underline-offset: 3px; align-items: center; }
.bubble.umfrageChat .umfrageChatWort { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; font-weight: 600; }
.bubble.umfrageChat .umfrageChatText { white-space: pre-wrap; overflow-wrap: anywhere; }
