/* ================================
   TVZA — kit.css
   Tokens, shell, nav, row/tile/panel, buttons, icons, hint card.
   Split out of style.css (Phase A). See legacy.css for old class
   names and assets/css/feature/*.css for page-specific rules.
   ================================ */

:root {
  /* ── Firn — Kernpalette ──────────────────────────────────────
     Blau auf Weiss, hell. Der Grund ist bewusst nicht reinweiss:
     Schnee im Schatten ist blau, und ein neutrales Weiss wirkt
     daneben tot. Die Schrift ist kein Schwarz, sondern ein sehr
     dunkles Blau, damit im Bild nichts fremd sitzt. */
  --bg:        #EFF4FA;
  --surface:   #FFFFFF;
  --surface-2: #F6F9FD;
  --ink:       #12293F;
  --ink-soft:  #546C86;   /* AA gegen --bg: 4.91 — #5A748F lag mit 4.39 knapp darunter */

  /* Das Markenblau gehoert ALLEIN dem App-Symbol und den Plaettchen
     (seit v.35.30.0 nicht mehr dem n im Wortzeichen, siehe --firn-n).
     Es ist kraeftiger als
     der Bedienakzent, weil es einmal und klein erscheint — waehrend
     der Akzent ueberall ist und darum leise bleiben muss. Nie fuer
     Knoepfe oder Zustaende verwenden. */
  --brand: #1256B0;

  /* Der Blau-Ramp, auf dem die Huelle sitzt — dunkel nach hell. Die
     drei --brand-navy-* Namen bleiben, weil legacy.css und zwei Regeln
     in dieser Datei sie lesen und dev/navigation.test.mjs auf der
     Indirektion besteht; ihre Werte sind jetzt Firn. Der Name wird in
     Phase 8 mit allem anderen umbenannt, nicht vorher. */
  --brand-navy: #0B1B2A;
  --brand-navy-mid: #24548E;
  --brand-navy-deep: #2C63A4;
  /* Das Alpengluehen aus dem Zeichen: der einzige warme Ton der Marke. */
  --alpenglut: #F6A183;
  /* Das n im Wortzeichen: ein tieferes Alpengluehen, das auf JEDEM Grund
     traegt — hell, Navy, Dunkelmodus. Darum ohne Dunkel-Fassung. */
  --firn-n: #DC6538;
  --brand-gradient: linear-gradient(135deg, var(--brand-navy), var(--brand-navy-mid), var(--brand-navy-deep));

  /* Der Akzent markiert, er fuellt nicht: eine Kante, ein Plaettchen,
     ein Zustand. Ganze Flaechen im Akzent sind in einer App, die man
     taeglich oeffnet, immer zu laut. */
  --accent:    var(--brand-navy-deep);
  --accent-hover: var(--brand-navy-mid);
  --accent-bg: #E4EDF7;
  /* The app shell always uses Firn blue. Individual areas may override
     --accent inside their content, but never the selected navigation. */
  --nav-active: var(--brand-navy-deep);
  --nav-active-bg: #E4EDF7;
  /* Danger / Löschen — eigenes Rot, passt sich pro Modus an */
  --danger:    oklch(0.52 0.19 25);
  --danger-bg: oklch(0.95 0.03 25);
  --border:    #D8E4F1;

  /* Tracker tints — muted, same lightness/chroma, differ only in hue */
  --tint-ski:    oklch(0.945 0.035 265);
  --tint-food:   oklch(0.945 0.035 145);
  --tint-trip:   oklch(0.945 0.040 60);
  --tint-matura: oklch(0.945 0.035 330);
  --tint-lernkarten: oklch(0.945 0.035 195);
  --tint-watch:  oklch(0.945 0.035 165);
  --tint-weather: oklch(0.945 0.035 230);
  --tint-msg:     oklch(0.945 0.035 292);
  --tint-training: oklch(0.945 0.035 20);

  /* Stronger tracker hues (text, borders, fills) */
  --ski:    oklch(0.48 0.11 265);
  --food:   oklch(0.48 0.11 145);
  --trip:   oklch(0.50 0.11 60);
  --matura: oklch(0.48 0.11 330);
  --watch:  oklch(0.46 0.10 165);
  --weather: oklch(0.48 0.11 230);
  --msg:     oklch(0.48 0.11 292);
  --training: oklch(0.48 0.11 20);
  --ski-deep:  oklch(0.38 0.10 265);
  --food-deep: oklch(0.38 0.10 145);
  --trip-deep: oklch(0.40 0.10 60);
  --matura-deep: oklch(0.38 0.10 330);
  --lernkarten-deep: oklch(0.38 0.10 195);
  --watch-deep: oklch(0.36 0.09 165);
  --weather-deep: oklch(0.38 0.10 230);
  --msg-deep:     oklch(0.38 0.10 292);
  --training-deep: oklch(0.38 0.10 20);

  /* Kurs colours — Watchlist only */
  --kurs-up:   oklch(0.58 0.13 150);
  --kurs-down: oklch(0.58 0.17 25);

  /* Wax colours — these name a physical thing, so they stay hex.
     Declared here instead of inline in skitracker.html. */
  --wax-blue:   #2563EB;
  --wax-red:    #DC2626;
  --wax-violet: #7C3AED;
  --wax-yellow: #CA8A04;
  --wax-green:  #16A34A;


  /* Status ist keine Modulfarbe (§3). Ein Haken bleibt gruen, auch im
     roten Trainingsbereich — sonst liest sich "erledigt" wie "Fehler". */
  --ok:      oklch(0.48 0.11 145);
  --ok-bg:   oklch(0.945 0.035 145);
  --warn:    oklch(0.50 0.11 60);
  --warn-bg: oklch(0.945 0.040 60);

  /* Zwei Tiefenstufen statt keiner: eine fuer Karten, eine fuer alles,
     was ueber der Seite liegt. Im Dunkelmodus uebernimmt der Rahmen. */
  --sh-card: 0 1px 2px oklch(0.22 0.01 250 / .05), 0 8px 24px -12px oklch(0.22 0.01 250 / .16);
  --sh-lift: 0 2px 4px oklch(0.22 0.01 250 / .07), 0 26px 60px -22px oklch(0.22 0.01 250 / .38);
  --rule-soft: #E4EBF3;

  /* ── Abstands-Skala ─────────────────────────────────────────────
     Sieben Stufen aus EINEM Grundwert. Wer den Rhythmus der ganzen
     App enger oder weiter haben will, aendert eine Zeile.

     Der Grundwert ist fluid: auf einem schmalen Handy ruecken die
     Dinge zusammen, ab Tablettbreite stehen sie am bequemen Maximum
     und wachsen nicht weiter. Ohne die obere Grenze wuerden Abstaende
     auf einem grossen Bildschirm ins Alberne laufen.

     Die Stufen sind Vielfache (1, 2, 3, 4, 6, 8, 12) und keine freien
     Zahlen — dadurch passen zwei Abstaende, die nebeneinander stehen,
     immer zueinander. Genau das fehlte: 143 harte px-Werte standen
     gegen 35 Token-Verwendungen, also hatte jede Stelle ihre eigene
     Zahl, und Knoepfe klebten mal aneinander und hatten mal Luft.

     Der Hoechstwert ist 4px und nicht mehr: bei 4.4px wurde die App
     spuerbar luftig, weil jede Stufe mitwaechst und ein Fehler von
     10 % sich bei --s5 zu drei Pixeln summiert. Am oberen Ende trifft
     die Skala jetzt genau die alten Werte (4/8/12/16/24/32/48), am
     unteren rueckt sie zusammen. */
  /* Hoehe der unteren Leiste am Handy. Stand als 64px an neun Stellen —
     Inhalt, Erinnerungen und Blaetter rechnen damit, wie weit sie ueber
     der Leiste bleiben muessen. */
  --nav-hoehe: 64px;
  --space: clamp(3.4px, 0.25vw + 2.5px, 4px);
  --s1: calc(var(--space) * 1);
  --s2: calc(var(--space) * 2);
  --s3: calc(var(--space) * 3);
  --s4: calc(var(--space) * 4);
  --s5: calc(var(--space) * 6);
  --s6: calc(var(--space) * 8);
  --s7: calc(var(--space) * 12);

  /* Radius scale (§3) — exactly four steps, nothing in between.
     --r1/--r2/--r3 stay as aliases so untouched pages keep rendering;
     the aliases themselves live in legacy.css. */
  --r-icon:  11px;   /* icon plate, nav entry, chart column */
  --r-row:   14px;   /* row, tile, button */
  --r-panel: 16px;   /* panel holding several blocks */
  --r-pill:  999px;  /* pill, badge, avatar */

  /* No shadows (§3). Depth comes from --border alone. The three
     --shadow-* variables were already transparent, so every rule that
     pointed at them animated to nothing; both are gone now. The only
     real shadow left is the drag clone in reorder mode. */
  --ring: 0 0 0 3px color-mix(in oklab, var(--accent) 22%, transparent);

  /* Typography */
  --font-ui: 'Hanken Grotesk', system-ui, sans-serif;
  --text-xs: 12px; --text-sm: 13px; --text-base: 15px;
  --text-lg: 18px; --text-xl: 22px; --text-2xl: 28px;

  /* Still read by several kit rules (.main, .offline-banner,
     .tvz-footer-panel) even though it was grouped with the legacy
     aliases in the original file — kept here so those rules don't
     depend on legacy.css being present. */
  --max-width:    680px;
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --ok:      oklch(0.78 0.11 145);
  --ok-bg:   oklch(0.30 0.045 145);
  --warn:    oklch(0.80 0.11 60);
  --warn-bg: oklch(0.31 0.050 60);
  --sh-card: 0 1px 0 oklch(1 0 0 / .04), 0 10px 30px -18px oklch(0 0 0 / .9);
  --sh-lift: 0 1px 0 oklch(1 0 0 / .05), 0 30px 70px -26px oklch(0 0 0 / 1);
  --rule-soft: #1B2C38;

  /* Firn im Dunkeln: derselbe Bau, gedrehte Rollen. Der Grund behaelt
     den Blaustich, damit es nicht in ein neutrales Grau kippt. */
  --bg:        #0E1A26;
  --surface:   #15242F;
  --surface-2: #1C2F3D;
  --ink:       #E6EFF7;
  --ink-soft:  #8AA4BC;
  --brand:     #8DBBE8;
  --accent:    #7FADDC;
  --accent-hover: #9AC1E8;
  --accent-bg: #182C3C;
  --nav-active: #7FADDC;
  --nav-active-bg: #182C3C;
  --danger:    oklch(0.64 0.15 25);
  --danger-bg: oklch(0.28 0.06 25);
  --border:    #21353F;

  /* Tracker-Tints im Dark Mode abdunkeln, damit sie nicht "poppen" (gleiche Hues) */
  --tint-ski:    oklch(0.30 0.045 265);
  --tint-food:   oklch(0.30 0.045 145);
  --tint-trip:   oklch(0.31 0.050 60);
  --tint-matura: oklch(0.30 0.045 330);
  --tint-lernkarten: oklch(0.30 0.045 195);
  --tint-watch:  oklch(0.30 0.045 165);
  --tint-weather: oklch(0.30 0.045 230);
  --tint-msg:     oklch(0.30 0.045 292);
  --ski-deep:  oklch(0.78 0.11 265);
  --food-deep: oklch(0.78 0.11 145);
  --trip-deep: oklch(0.80 0.11 60);
  --matura-deep: oklch(0.78 0.11 330);
  --lernkarten-deep: oklch(0.78 0.11 195);
  --watch-deep: oklch(0.78 0.10 165);
  --weather-deep: oklch(0.78 0.11 230);
  --msg-deep:     oklch(0.78 0.11 292);
  --tint-training: oklch(0.30 0.045 20);
  --training-deep: oklch(0.78 0.11 20);
  --kurs-up:   oklch(0.72 0.13 150);
  --kurs-down: oklch(0.70 0.15 25);
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Das hidden-Attribut sagt etwas über den Inhalt aus, nicht über die
   Darstellung — es darf nicht davon abhängen, ob zufällig eine Klasse
   display setzt. Genau das passierte an drei Stellen: .nav__count
   zeigte eine leere rote Pille unter Nachrichten, obwohl nichts
   ungelesen war, und die leeren Fortschrittsblöcke der Kacheln
   (.tile-prog, .tile-live) nahmen Platz ein, bevor Daten da waren.
   Der eine Ausrufer hier erspart denselben Fehler an jeder künftigen
   Stelle. */
[hidden] { display: none !important; }
html { font-size: 16px; -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-ui);
  font-size: var(--text-base);
  background: var(--bg);
  color: var(--ink);
  min-height: 100vh;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { text-wrap: balance; line-height: 1.3; }
h1, h2 { letter-spacing: -0.015em; }

/* Premium detail: themed text selection + visible keyboard focus */
::selection { background: color-mix(in oklab, var(--accent) 24%, transparent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.form-input:focus-visible, .form-select:focus-visible, .form-textarea:focus-visible { outline: none; }

/* Slim themed scrollbars (desktop) */
@media (pointer: fine) {
  * { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
  *::-webkit-scrollbar { width: 8px; height: 8px; }
  *::-webkit-scrollbar-thumb { background: var(--border); border-radius: var(--r-pill); }
  *::-webkit-scrollbar-track { background: transparent; }
}

a { text-decoration: none; color: inherit; }
button, input, select, textarea { font-family: inherit; }

/* ─── App shell ─── */
.app { min-height: 100vh; display: flex; flex-direction: column; }
/* dvh statt vh: auf dem Handy zieht sich die Browserleiste beim Scrollen
   ein, 100vh rechnet aber mit der ausgefahrenen Leiste und schiebt
   dadurch alles, was am unteren Rand sitzen soll, aus dem Bild. */
@supports (min-height: 100dvh) { .app { min-height: 100dvh; } }
/* Der Rumpf reserviert unten bereits Platz für die Navileiste. Ohne
   diesen Abzug verlangt .app zusätzlich die volle Viewporthöhe, die
   Seite wird um die Leistenhöhe zu lang, und was unten sitzen soll
   verschwindet hinter der Leiste. */
body.has-nav .app { min-height: calc(100vh - var(--nav-hoehe) - env(safe-area-inset-bottom, 0px)); }
@supports (min-height: 100dvh) {
  body.has-nav .app { min-height: calc(100dvh - var(--nav-hoehe) - env(safe-area-inset-bottom, 0px)); }
}

/* Ein offener Nachrichten-Thread ist eine feste Fläche statt einer
   scrollenden Seite: nur der Verlauf scrollt, das Eingabefeld steht
   fest darunter. Dafür braucht die Kette eine ECHTE Höhe — mit
   min-height wächst der Verlauf mit dem Inhalt weiter, das Feld
   wandert nach unten aus dem Bild und die Leiste deckt es zu. */
/* Am Handy verschwindet die Tab-Leiste in zwei Fällen: in einer offenen
   Unterhaltung — dort führt der Zurück-Pfeil heraus, die Tabs sind
   überflüssig und stehen nur zwischen Eingabefeld und Tastatur — und
   überall dort, wo gerade in ein Feld geschrieben wird. Am Laptop liegt
   die Leiste links und stört nie, darum nur unterhalb von 900px. */
@media (max-width: 899px) {
  body.dm-thread .nav,
  body.kb-open .nav { display: none; }
  body.dm-thread.has-nav,
  body.kb-open.has-nav { padding-bottom: 0; }
  body.dm-thread.has-nav .app { height: 100vh; }
  body.kb-open.has-nav .app { min-height: 100vh; }
  @supports (height: 100dvh) {
    body.dm-thread.has-nav .app { height: 100dvh; }
    body.kb-open.has-nav .app { min-height: 100dvh; }
  }
}

body.dm-thread { overflow: hidden; }
/* Die Versionszeile haengt an .app und wuerde dem Eingabefeld im Thread
   Hoehe wegnehmen. Sie gehoert ans Ende einer scrollenden Seite. */
body.dm-thread .fx-version { display: none; }
body.dm-thread .app {
  height: calc(100vh - var(--nav-hoehe) - env(safe-area-inset-bottom, 0px));
  min-height: 0;
}
@supports (height: 100dvh) {
  body.dm-thread .app { height: calc(100dvh - var(--nav-hoehe) - env(safe-area-inset-bottom, 0px)); }
}
/* Mit offener Tastatur ist der sichtbare Ausschnitt die ganze Seite: die
   Leiste ist weg, und das Eingabefeld steht über der Tastatur
   (v.35.69.0). Ohne das endete der Thread darunter. */
body.dm-thread.kb-open .app {
  height: calc(var(--vv-hoehe, 100dvh) - var(--tastatur, 0px));
  min-height: 0;
}

/* Page entry animation */
.main, .login-card {
  animation: fadeIn 0.2s ease both;
}
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* ─── Wordmark ─── (used by the old .header AND the still-active
   .tvz-footer-panel — shared, not legacy-only) */
.tvz-wordmark {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 26px;
  font-weight: 700;
  line-height: 1;
  color: var(--accent);
  text-shadow: none;
}
/* Small TvZ mark for page headers (Timo-exclusive pages) */
.tvz-mark {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink-soft);
}
.logo { color: var(--ink); }

/* ─── Back button ─── (shared by the old .header and the current .appbar) */
.back-btn {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: 44px;
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: 500;
  transition: color 150ms ease;
}
.back-btn:hover { color: var(--ink); }
.back-btn svg { width: 18px; height: 18px; }

/* ─── Offline banner ───
   Er liegt ÜBER der Seite, nicht in ihr (v.35.70.8). Bis dahin stand er
   sticky im Fluss, vor der Kopfleiste: sobald er sichtbar wurde, schob er
   die Leiste nach unten, und die Seite wurde höher als der Bildschirm —
   Michel am Handy: "der obere Bar ist verschwunden oder plötzlich
   scrollable geworden". Ein Hinweis darf nichts verschieben, und er darf
   keinen Tipp abfangen. */
.offline-banner {
  position: fixed;
  top: calc(60px + env(safe-area-inset-top, 0px) + var(--s2));
  left: 50%;
  translate: -50% 0;
  z-index: 90;
  margin: 0;
  width: max-content;
  max-width: calc(100vw - 2 * var(--s4));
  pointer-events: none;
  background: var(--tint-trip);
  color: var(--trip-deep);
  border: 1px solid color-mix(in oklab, var(--trip) 30%, var(--border));
  border-radius: var(--r-pill);
  text-align: center;
  padding: var(--s2) var(--s4);
  font-size: var(--text-xs);
  font-weight: 600;
  display: none;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 150ms ease, transform 150ms ease;
}
.offline-banner.visible {
  display: block;
  opacity: 1;
  transform: translateY(0);
}

/* ─── Main ─── */
.main {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--s5) var(--s4) var(--s7);
  width: 100%;
  flex: 1;
}

/* ─── Section ─── */
.section { margin-bottom: var(--s5); }

.section-head {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-bottom: var(--s3);
}

.section-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 0;
  flex: 1;
}

.overview-toggle,
.overview-drag {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--r1);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  line-height: 1;
  opacity: 0.62;
  transition: transform 150ms ease, background 150ms ease, color 150ms ease, opacity 150ms ease;
  -webkit-appearance: none;
  appearance: none;
}
.overview-toggle:hover,
.overview-drag:hover {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--ink);
  opacity: 1;
}
.overview-toggle::before {
  content: "";
  width: 7px;
  height: 7px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}
.section--collapsed .overview-toggle::before { transform: translateX(-2px) rotate(-45deg); }
.overview-drag {
  cursor: grab;
  touch-action: none;
}
.overview-drag:active { cursor: grabbing; }
.overview-drag::before {
  content: "";
  width: 3px;
  height: 3px;
  border-radius: var(--r-pill);
  background: currentColor;
  box-shadow:
    0 -6px 0 currentColor,
    0 6px 0 currentColor,
    6px -6px 0 currentColor,
    6px 0 0 currentColor,
    6px 6px 0 currentColor;
  transform: translateX(-3px);
}
.section--collapsed > :not(.section-head) { display: none !important; }

/* ─── Card grid ─── */
.card-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s4);
}

.module-tile {
  min-width: 0;
  position: relative;
}
.module-tile .card {
  height: 100%;
  cursor: pointer;
}
.module-tile--dragging,
.module-tile--dragging .card { cursor: grabbing; }
.module-tile:hover .card { border-color: var(--ink-soft); }

.card {
  background: var(--surface);
  border-radius: var(--r3);
  padding: var(--s4) var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  border: 1px solid var(--border);
  transition: border-color 180ms ease;
  cursor: pointer;
}
.card:hover  { border-color: var(--ink-soft); }
.card:active { transform: scale(0.98); }

.card-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--r-pill);
  display: grid;
  place-items: center;
  font-size: 20px;
  line-height: 1;
  background: var(--surface-2);
  color: var(--ink-soft);
}
.card-icon svg { display: block; }
.card--ski    .card-icon { background: var(--tint-ski);  color: var(--ski-deep); }
.card--food   .card-icon { background: var(--tint-food); color: var(--food-deep); }
.card--trip   .card-icon { background: var(--tint-trip); color: var(--trip-deep); }
.card--matura .card-icon { background: var(--tint-matura); color: var(--matura-deep); }
.card--training .card-icon { background: var(--tint-training); color: var(--training-deep); }
.card--watch  .card-icon { background: var(--tint-watch); color: var(--watch-deep); }
.card--weather .card-icon { background: oklch(0.93 0.04 230); color: oklch(0.45 0.11 235); }
:root[data-theme="dark"] .card--weather .card-icon { background: oklch(0.30 0.05 235); color: oklch(0.82 0.09 230); }
.card--dm .card-icon { background: oklch(0.93 0.04 300); color: oklch(0.45 0.13 300); }
:root[data-theme="dark"] .card--dm .card-icon { background: oklch(0.30 0.05 300); color: oklch(0.82 0.10 300); }

.card-content h3 { font-size: var(--text-base); font-weight: 700; }
.card-content p  { font-size: var(--text-sm); color: var(--ink-soft); margin-top: 2px; }

/* ─── Live tile content (compact footer, sized to fit narrow tiles) ─── */
.tile-live { margin-top: auto; padding-top: var(--s2); font-size: var(--text-xs); line-height: 1.3;  min-width: 0; }
.tile-live[hidden] { display: none; }
/* Only the first appearance animates — a ticking price must not flicker. */
.tile-live--first { animation: tileLiveIn .35s ease; }
@keyframes tileLiveIn { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }

/* progress-bar tiles (Maturaarbeit, Maturaarbeit-Tracker, Food) */
.tile-prog { display: flex; flex-direction: column; gap: var(--s1); }
.tile-prog .tl-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s2); }
.tile-prog .tl-pct { font-weight: 800; font-size: var(--text-sm); color: var(--ink); line-height: 1; }
.tile-prog .tl-meta { color: var(--ink-soft); font-size: var(--text-xs); font-weight: 600; white-space: nowrap; }
.tile-prog .tl-bar { height: 5px; border-radius: var(--r-pill); background: var(--surface-2); overflow: hidden; border: 1px solid var(--border); }
.tile-prog .tl-fill { height: 100%; border-radius: var(--r-pill); width: 0; transition: width .65s cubic-bezier(.4,0,.2,1); }
.card--matura .tl-fill { background: linear-gradient(90deg, var(--matura), var(--matura-deep)); }
.card--food   .tl-fill { background: linear-gradient(90deg, var(--food), var(--food-deep)); }

/* rotating Watchlist ticker on the Start-page tile — two compact lines
   so it never overflows. Only rendered on index.html (#tileWatch), not
   on watchlist.html itself, so it stays in kit.css rather than a
   feature file. */
.tile-ticker { min-height: 30px; }
.tile-ticker .tk-quote { display: flex; flex-direction: column; gap: 1px; transition: opacity .35s ease; min-width: 0; }
.tile-ticker.swap .tk-quote { opacity: 0; }
.tile-ticker .tk-top { display: flex; align-items: baseline; gap: var(--s2); min-width: 0; }
.tile-ticker .tk-sym { font-weight: 800; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile-ticker .tk-dp { font-weight: 700; font-variant-numeric: tabular-nums; margin-left: auto; white-space: nowrap; }
.tile-ticker .tk-dp.up   { color: oklch(0.58 0.13 150); }
.tile-ticker .tk-dp.down { color: oklch(0.58 0.17 25); }
.tile-ticker .tk-px { font-variant-numeric: tabular-nums; color: var(--ink-soft); font-weight: 700; white-space: nowrap; }

/* weather live row on the Start-page tile (condition + chance of
   precipitation — no temperature). Only rendered on index.html
   (#tileWeather), not on weather.html itself. */
#tileWeather { display: flex; align-items: center; gap: var(--s1); min-width: 0; }
#tileWeather .wxl-ic  { font-size: 15px; line-height: 1; flex: none; }
#tileWeather .wxl-lab { font-weight: 700; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#tileWeather .wxl-pop { color: var(--ink-soft); font-weight: 600; white-space: nowrap; flex: none; }

/* DM tile — last conversation preview, only on index.html (#tileDm). */
.dm-tile-badge { position: absolute; top: 10px; right: 10px; z-index: 2; min-width: 22px; height: 22px;
  padding: 0 var(--s2); border-radius: var(--r-pill); background: oklch(0.55 0.20 25); color: #fff; font-size: 12px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; }
#tileDm { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
#tileDm .dm-name { font-weight: 800; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#tileDm .dm-prev { color: var(--ink-soft); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Ski + generic one-line status footer. #tileSki only renders on
   index.html's dashboard, not on skitracker.html, so it stays here
   rather than in feature/ski.css alongside skitracker.html's own
   content (wax colours, stars, badge). */
#tileSki, .tile-status { display: flex; align-items: baseline; gap: var(--s2); min-width: 0; }
#tileSki .st-main, .tile-status .st-main { font-weight: 800; color: var(--ink); white-space: nowrap; }
#tileSki .st-sub, .tile-status .st-sub { color: var(--ink-soft); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* next-event row (Kalender) on the Start-page tile, only on index.html
   (#tileTrip), not on planner.html itself. */
#tileTrip { display: flex; align-items: baseline; gap: var(--s2); min-width: 0; }
#tileTrip .tp-when { font-weight: 800; color: var(--trip-deep); white-space: nowrap; }
#tileTrip .tp-what { color: var(--ink-soft); font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ─── Link rows (external projects) ─── */
.link-list { display: flex; flex-direction: column; gap: var(--s2); }

.project-row {
  align-items: center;
  cursor: default;
}
.project-row:hover { border-color: var(--ink-soft); }
.project-actions {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  justify-content: flex-end;
}
.action-btn {
  min-width: 94px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  border: 1px solid var(--border);
  border-radius: var(--r1);
  background: transparent;
  color: var(--ink);
  font-size: var(--text-xs);
  font-weight: 700;
  cursor: pointer;
  transition: transform 150ms ease, background 150ms ease, border-color 150ms ease;
}
.action-btn:hover { background: var(--surface-2); }
.action-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.action-btn:disabled:hover {
  transform: none;
  background: transparent;
}
.action-btn span { font-size: 15px; display: inline-flex; align-items: center; }
.action-btn svg { display: block; }
.action-btn--public { background: var(--tint-food); border-color: var(--border); color: var(--food-deep); }
.action-btn--public:hover { background: var(--tint-food); }
.action-btn--danger { background: var(--danger-bg); border-color: var(--border); color: var(--danger); }
.action-btn--danger:hover { background: var(--danger-bg); }

/* ─── Form card ─── */
/* ── Stapel ────────────────────────────────────────────────────────
   Der eine Weg, Dinge untereinander zu setzen: ein Behaelter mit gap,
   nicht margin an jedem Kind.

   Der Unterschied ist nicht Geschmack. Mit margin traegt jedes Kind
   seinen eigenen Abstand, und wer eines vergisst — etwa einen Knopf,
   der direkt in einer Karte liegt — bekommt zwei Elemente, die
   aneinanderkleben, waehrend das naechste Paar Luft hat. Genau das war
   in der Kaderverwaltung zu sehen. Mit gap ist der Abstand eine
   Eigenschaft des Stapels: er gilt zwischen ALLEN Kindern, und man
   kann ihn nicht an einer Stelle vergessen. */
.stack { display: flex; flex-direction: column; gap: var(--s3); }
.stack--eng  { gap: var(--s2); }
.stack--weit { gap: var(--s5); }

.form-card {
  background: var(--surface);
  border-radius: var(--r-panel);
  border: 1px solid var(--border);
  padding: var(--s4);
  margin-bottom: var(--s4);

  /* Die Karte IST ein Stapel. Dadurch bekommen Formularfelder,
     Hinweise und Knoepfe darin denselben Abstand, ohne dass jeder
     Bautyp dafuer seine eigene Regel braucht. */
  display: flex; flex-direction: column; gap: var(--s3);
}

/* Innerhalb eines Stapels kommt der Abstand vom gap. Die alten
   margin-bottom der Kinder wuerden ihn verdoppeln — sichtbar als
   Formular, dessen Felder doppelt so weit auseinanderstehen wie seine
   Knoepfe. */
.form-card > .form-group,
.form-card > .form-group:last-of-type,
.form-card > .form-row,
.form-card > .form-title,
.stack > .form-group,
.stack > .form-group:last-of-type,
.stack > .form-row { margin-bottom: 0; }

.form-title {
  font-size: 14px;
  font-weight: 700;
  margin-bottom: var(--s3);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s3);
}

.form-group { margin-bottom: var(--s3); }

/* Ein Hinweis unter einem Feld ist leiser als das Feld. Bis v.35.58.0
   hatte .form-hint keine Regel und stand in voller Textgrösse — in den
   Einstellungen und beim Registrieren. */
.form-hint {
  margin: var(--s1) 0 0;
  color: var(--ink-soft);
  font-size: 12.5px;
  line-height: 1.45;
}
.form-hint:empty { display: none; }
.form-group:last-of-type { margin-bottom: var(--s4); }

.form-label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  margin-bottom: var(--s1);
}

.form-input,
.form-select,
.form-textarea {
  width: 100%;
  min-height: 44px;
  padding: var(--s3) var(--s3);
  border: 1px solid var(--border);
  border-radius: var(--r1);
  font-size: 14px;
  color: var(--ink);
  background: var(--surface);
  transition: border-color 150ms ease;
  outline: none;
  -webkit-appearance: none;
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
  border-color: var(--accent);
  box-shadow: var(--ring);
}

.form-textarea { resize: vertical; min-height: 72px; }

/* ─── Buttons ─── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: 44px;
  padding: var(--s3) var(--s5);
  border-radius: var(--r1);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  border: none;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.btn:active { transform: scale(0.97); }
.btn-primary  { background: var(--accent); color: white; }
.btn-primary:hover { background: var(--accent-hover); }
:root[data-theme="dark"] .btn-primary { color: var(--brand-navy); }
.btn-danger   { background: transparent; color: var(--danger); padding: var(--s1) var(--s2); font-size: var(--text-xs); min-height: 44px; }
.btn-danger:hover { background: var(--danger-bg); }
.btn-block    { width: 100%; }

/* ─── Tabs ─── */
.tabs {
  display: flex;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r1);
  padding: 3px;
  margin-bottom: var(--s4);
  gap: 2px;
}

.tab {
  flex: 1;
  min-height: 38px;
  padding: var(--s2) var(--s3);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  text-align: center;
  font-size: var(--text-sm);
  font-weight: 500;
  border-radius: var(--r-icon);
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
  color: var(--ink-soft);
  user-select: none;
}
.tab svg { display: block; }

.tab.active {
  background: var(--surface);
  color: var(--ink);
  font-weight: 700;
  box-shadow: inset 0 0 0 1px var(--border);
}

/* ─── Progress ─── */
/* ─── Empty state ─── */
.empty-state { text-align: center; padding: var(--s6) var(--s4); color: var(--ink-soft); }
.empty-icon {
  font-size: 26px; margin: 0 auto var(--s3);
  width: 56px; height: 56px; border-radius: var(--r-pill);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); border: 1px solid var(--border);
}
.empty-icon svg { width: 26px; height: 26px; }
.empty-text  { font-size: 14px; max-width: 320px; margin: 0 auto; line-height: 1.5; }

/* ─── Section divider ─── */
.divider { height: 1px; background: var(--border); margin: var(--s4) 0; }

/* ─── Detail/list toggle (currently unused by any page's markup — kept
   as found, per "cut and paste only, don't delete a rule you think is
   dead") ─── */
.detail-view.visible { display: block; }
.list-view.hidden { display: none; }

/* ─── Desktop ─── */
@media (min-width: 900px) {
  .main { padding: var(--s6) var(--s5) calc(var(--s7) + var(--s3)); }
  .card-grid { grid-template-columns: repeat(4, 1fr); }
  .form-row { grid-template-columns: 1fr 1fr; }
}

/* ════ v2 additions ════════════════════════════ */

/* Modal */
.modal-backdrop {
  position: fixed; inset: 0;
  background: oklch(0.15 0.01 250 / 0.45);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  display: none;
  align-items: center; justify-content: center;
  z-index: 500; padding: var(--s5);
}
.modal-backdrop.visible { display: flex; animation: backdropIn 0.18s ease both; }
@keyframes backdropIn { from { opacity: 0; } to { opacity: 1; } }
.modal {
  background: var(--surface);
  border-radius: var(--r3);
  border: 1px solid var(--border);
  padding: var(--s5);
  width: 100%; max-width: 420px;
  max-height: 90vh; overflow-y: auto;
  animation: modalIn 0.22s cubic-bezier(.2,.9,.3,1.05) both;
}
@keyframes modalIn {
  from { opacity: 0; transform: scale(0.95) translateY(8px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

/* Global settings layer. Area pages keep their exact position and state;
   the one complete settings dialog from index.html appears above them. */
.global-settings-layer {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: grid;
  place-items: center;
  padding: var(--s4);
  background: oklch(0.15 0.01 250 / 0.48);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  animation: backdropIn 0.18s ease both;
}
.global-settings-layer[hidden] { display: none !important; }
.global-settings-shell {
  position: relative;
  width: min(720px, 100%);
  height: min(900px, calc(100dvh - 32px));
  overflow: hidden;
  border-radius: var(--r3);
}
.global-settings-frame {
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
  background: transparent;
  opacity: 0;
  transition: opacity 160ms ease;
}
.global-settings-layer.is-loaded .global-settings-frame { opacity: 1; }
.global-settings-loading {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--s3);
  border: 1px solid var(--border);
  border-radius: var(--r3);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 13px;
  font-weight: 700;
}
.global-settings-layer.is-loaded .global-settings-loading { display: none; }
.global-settings-loading .spinner {
  width: 24px;
  height: 24px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: globalSettingsSpin 700ms linear infinite;
}
@keyframes globalSettingsSpin { to { transform: rotate(360deg); } }
.global-settings-close {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--ink);
  font: 22px/1 inherit;
  cursor: pointer;
}
.global-settings-layer.is-loaded .global-settings-close {
  opacity: 0;
  pointer-events: none;
}
body.settings-layer-open { overflow: hidden; }

/* Embedded settings are still the real dashboard dialog, only without a
   second dashboard and navigation behind it. The admin-only half of this
   mechanism (html.admin-embed) lives in feature/access.css — several of
   these rules originally shared one comma-selector with it; declarations
   below are duplicated verbatim under the settings-embed-only selector,
   noted here so the split is traceable. */
html.settings-embed,
html.settings-embed body {
  min-height: 100%;
  background: transparent !important;
}
html.settings-embed body {
  padding: 0 !important;
  overflow: hidden;
}
html.settings-embed body > :not(#settingsModal):not(script) { display: none !important; }
html.settings-embed #settingsModal {
  display: flex !important;
  position: fixed;
  inset: 0;
  padding: 0;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
html.settings-embed #settingsModal .modal { max-height: 100dvh; }

.modal-title { font-size: var(--text-base); font-weight: 700; margin-bottom: var(--s4); }
.modal-actions { display: flex; gap: var(--s2); margin-top: var(--s4); }
.modal-actions .btn { flex: 1; }
.btn-secondary { background: transparent; color: var(--ink); border: 1px solid var(--border); }
.btn-secondary:hover { background: var(--surface-2); }

/* Segmented options — reused by ski/food/planner pages alike, so the
   mechanism (and the page--ski/food/trip tint hooks) stays here. */
.seg {
  display: flex; gap: var(--s2); flex-wrap: wrap;
}
.seg-opt {
  min-height: 38px;
  display: inline-flex; align-items: center;
  padding: var(--s2) var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  font-size: var(--text-sm); font-weight: 500;
  cursor: pointer; user-select: none;
  background: var(--surface);
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.seg-opt:hover { background: var(--surface-2); }
.seg-opt.on { background: var(--accent); color: white; border-color: var(--accent); }
/* Page-specific active seg tint */
.page--ski    .seg-opt.on { background: var(--ski); border-color: var(--ski); }
.page--food   .seg-opt.on { background: var(--food); border-color: var(--food); }
.page--trip   .seg-opt.on { background: var(--trip); border-color: var(--trip); }

/* Autocomplete — reused by food (ingredients), watchlist and weather
   (location search), so it stays a shared kit component. */
.ac-wrap { position: relative; }
.ac-list {
  position: absolute; top: 100%; left: 0; right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r1);
  z-index: 50; max-height: 200px; overflow-y: auto;
  display: none;
}
.ac-list.visible { display: block; }
.ac-item { padding: var(--s2) var(--s3); font-size: 14px; cursor: pointer; transition: background 150ms ease; }
.ac-item:hover, .ac-item.sel { background: var(--surface-2); }
.ac-item small { color: var(--ink-soft); }

/* ════ v3: TvZ footer ══════════════════════════ */
/* Das grosse Wortzeichen am Seitenende gehört auf die Startseite, wo es
   im Marken-Panel steht. Auf einer Unterseite steht es allein in einer
   leeren Fläche und wirkt verloren — dort markiert die Versionszeile
   das Ende der Seite. */
.tvz-footer { display: none; }
.tvz-footer-panel {
  width: 100%;
  max-width: var(--max-width);
  display: grid;
  grid-template-columns: 130px 1fr;
  align-items: center;
  gap: var(--s5);
  text-align: left;
  background: var(--brand-gradient);
  color: white;
  border: 0;
  border-radius: var(--r3);
  padding: var(--s5) var(--s5);
}
.tvz-footer-logo {
  border-right: 1px solid rgba(255,255,255,0.24);
  padding-right: var(--s5);
}
.tvz-footer-logo span:last-child {
  display: block;
  margin-top: var(--s2);
  font-size: 11px;
  color: rgba(255,255,255,0.72);
}
.tvz-footer-copy strong {
  display: block;
  font-size: var(--text-base);
  margin-bottom: var(--s1);
}
.tvz-footer-copy span {
  display: block;
  color: rgba(255,255,255,0.78);
  font-size: var(--text-sm);
}
/* Bedingungen, Datenschutz, Betreiber (v.35.70.0): drei Wege in einer
   Zeile, nicht drei Bloecke untereinander. */
.tvz-footer-copy .tvz-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s4);
  margin-top: var(--s2);
}
.tvz-footer-copy .tvz-footer-links a {
  color: rgba(255,255,255,0.84);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-size: var(--text-sm);
}
.tvz-footer-copy p {
  margin-top: var(--s3);
  padding: var(--s3) var(--s3);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--r1);
  color: rgba(255,255,255,0.84);
  font-size: var(--text-xs);
  line-height: 1.5;
}
.tvz-footer-box {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r2);
  padding: var(--s3) var(--s4);
}
.tvz-footer img { height: 30px; opacity: 0.72; }
.tvz-footer span { font-size: 11px; color: var(--ink-soft); }
.tvz-footer-panel .tvz-wordmark { color: white; font-size: 32px; }
.tvz-footer-panel .tvz-footer-logo span:last-child { color: rgba(255,255,255,0.72); }
.tvz-footer-panel .tvz-footer-copy span { color: rgba(255,255,255,0.78); }

@media (max-width: 899px) {
  /* Dashboard bar (Marke + Benutzer-Chip) keeps its stacked layout. */
  .project-row { align-items: flex-start; flex-direction: column; }
  .project-actions { width: 100%; justify-content: stretch; }
  .action-btn { flex: 1; min-width: 0; }
  .tvz-footer-panel { display: flex; flex-direction: column; align-items: flex-start; }
  .tvz-footer-logo { border-right: 0; padding-right: 0; }
}

/* ════════════════════════════════════════════════
   Reorder / Edit mode ("Anordnen")
   ════════════════════════════════════════════════ */

/* Floating "Anordnen" button (bottom-right). Hidden while already editing. */
.reorder-fab {
  position: static;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: 0 var(--s3);
  min-height: 36px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--accent);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: background 150ms ease, opacity 150ms ease;
}
.reorder-fab svg { display: block; }
/* Solange ein Dialog offen ist, gehört der Vordergrund dem Dialog. Der
   Knopf schwebte sonst über den Einstellungen und liess sich dort
   anklicken, obwohl er nichts mit ihnen zu tun hat. */
body:has(.modal-backdrop.visible) .reorder-fab,
body:has(.modal-backdrop.show) .reorder-fab { display: none; }
/* Anordnen gehört ausschliesslich zur Startseite. Bei der dauerhaften
   App-Hülle bleibt deren DOM im Hintergrund bestehen; ohne diese Regel
   würde der Knopf über jedem geladenen Bereich schweben. */
body:has(.tvza-route-frame) .reorder-fab,
body:has(.tvza-route-frame) .reorder-hint { display: none; }
.reorder-fab:hover { background: var(--surface-2); }
.reorder-fab:active { transform: scale(0.97); }
body.reorder-editing .reorder-fab {
  opacity: 0;
  pointer-events: none;
  transform: scale(.96);
}
@media (max-width: 899px) {
  .reorder-fab {
    padding: 0 var(--s3);
    min-height: 34px;
  }
  .reorder-fab svg { width:16px; height:16px; }
}

/* ── Settings menu layout — even vertical rhythm ── */
#settingsModal .modal {
  max-width: 600px;
  padding: var(--s5);
  background: var(--surface-2);
}
/* Header with title + X close */
.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s4);
  padding: var(--s1) 2px var(--s3);
}
.modal-head .modal-title { margin-bottom: 0; }
.modal-kicker {
  margin-bottom: 3px;
  color: var(--accent);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.modal-subtitle {
  margin: var(--s1) 0 0;
  color: var(--ink-soft);
  font-size: 13px;
  line-height: 1.4;
}
.modal-close {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--ink-soft);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: background 150ms ease, color 150ms ease;
}
.modal-close:hover { background: var(--border); color: var(--ink); }
#settingsModal .modal-title {
  margin-bottom: 0;
  font-size: 22px;
  line-height: 1.15;
}
.settings-section {
  min-width: 0;
  margin: 0;
  padding: var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  background: var(--surface);
  transition: background-color 180ms ease;
}
.settings-section--focused {
  background: color-mix(in srgb, var(--accent) 9%, transparent);
}
.settings-section-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 var(--s3);
}
.settings-layout {
  min-width: 0;
  display: grid;
  gap: var(--s3);
}
.settings-section-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s4);
  margin-bottom: var(--s4);
}
.settings-section-head .settings-section-title { margin-bottom: var(--s1); }
.settings-section-copy {
  max-width: 520px;
  margin: 0 0 var(--s4);
  color: var(--ink-soft);
  font-size: 13px;
  line-height: 1.5;
}
.settings-section-head .settings-section-copy { margin-bottom: 0; }
.settings-save-state {
  flex: none;
  min-height: 26px;
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  margin: 0;
  padding: var(--s1) var(--s2);
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--kurs-up) 10%, var(--surface));
  color: var(--kurs-up);
  font-size: 11px;
  font-weight: 750;
  white-space: nowrap;
}
.settings-save-state::before {
  content: "✓";
  width: 14px;
  height: 14px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--kurs-up);
  color: white;
  font-size: 9px;
  line-height: 1;
}
.settings-save-state[data-state="saving"] {
  background: var(--accent-bg);
  color: var(--accent);
}
.settings-save-state[data-state="saving"]::before {
  content: "";
  box-sizing: border-box;
  border: 2px solid color-mix(in srgb, var(--accent) 28%, transparent);
  border-top-color: var(--accent);
  background: transparent;
  animation: globalSettingsSpin 650ms linear infinite;
}
.settings-save-state[data-state="error"] {
  background: color-mix(in srgb, var(--danger) 10%, var(--surface));
  color: var(--danger);
}
.settings-save-state[data-state="error"]::before {
  content: "!";
  background: var(--danger);
}
#settingsModal .settings-divider { display: none; }
#settingsModal #moduleToggles {
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
}
/* Die Gruppenköpfe (Firn, TVZA) gehen über die ganze Breite — sonst
   belegt jeder eine Zelle des Rasters und steht neben einem Schalter. */
#settingsModal #moduleToggles > .marke { grid-column: 1 / -1; margin-bottom: 0; }
#settingsModal .modal-actions { margin-top: var(--s4); }
#settingsModal .form-group { margin-bottom: var(--s4); }
#settingsModal #myShares:not(:empty) { margin-top: var(--s4); }

/* Theme toggle row inside the Settings menu */
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  background: color-mix(in srgb, var(--surface-2) 68%, var(--surface));
  border: 1px solid var(--border);
  border-radius: var(--r2);
  padding: var(--s3) var(--s4);
}
.settings-row-label { font-size: 14px; font-weight: 600; color: var(--ink); display: flex; flex-direction: column; gap: 2px; }
.settings-row-label small { font-size: 12px; font-weight: 500; color: var(--ink-soft); }
.theme-toggle-btn {
  width: 44px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--ink);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  flex-shrink: 0;
}
.theme-toggle-btn:hover { border-color: var(--ink-soft); }

/* Drag handles for sections: hidden until edit mode */
.overview-drag { display: none; }
body.reorder-editing .overview-drag { display: inline-flex; }

/* Slim status bar pinned to the very bottom while arranging */
.reorder-hint {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: var(--s3);
  background: var(--ink);
  color: var(--surface);
  font-size: 13px;
  font-weight: 600;
  padding: var(--s2) var(--s4);
  padding-bottom: calc(var(--s2) + env(safe-area-inset-bottom, 0px));
  opacity: 0;
  pointer-events: none;
  z-index: 1200;
  transform: translateY(100%);
  transition: opacity 200ms ease, transform 200ms ease;
}
body.reorder-editing .reorder-hint {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.reorder-hint-text {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.reorder-hint button {
  border: 0;
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  padding: var(--s2) var(--s4);
  border-radius: var(--r-pill);
  cursor: pointer;
  flex-shrink: 0;
}

/* Wobble keyframe (iOS-style) */
@keyframes tvzaWobble {
  0%   { transform: rotate(-0.55deg); }
  50%  { transform: rotate(0.55deg); }
  100% { transform: rotate(-0.55deg); }
}

/* While editing: items wobble, show they are grabbable, links are inert */
body.reorder-editing .module-tile,
body.reorder-editing .project-row,
body.reorder-editing [data-overview-section] {
  touch-action: none;          /* drag instead of scroll only while editing */
}
body.reorder-editing .module-tile .card,
body.reorder-editing .project-row a,
body.reorder-editing .project-row .project-actions {
  pointer-events: none;        /* taps don't open / trigger while sorting */
}
body.reorder-editing .module-tile,
body.reorder-editing .project-row {
  cursor: grab;
}

/* Wobble only the smaller items (tiles + project rows) */
body.reorder-editing .module-tile .card,
body.reorder-editing .project-row {
  animation: tvzaWobble 0.34s ease-in-out infinite;
  will-change: transform;
}
body.reorder-editing .card-grid .module-tile:nth-child(2n) .card { animation-delay: 0.06s; }
body.reorder-editing .card-grid .module-tile:nth-child(3n) .card { animation-delay: 0.12s; }
body.reorder-editing .project-row:nth-child(2n) { animation-delay: 0.05s; }
body.reorder-editing .project-row:nth-child(3n) { animation-delay: 0.11s; }

/* Sections get a clear grabbable affordance (no wobble — too large) */
body.reorder-editing [data-overview-section] > .section-head {
  cursor: grab;
}
body.reorder-editing .overview-drag {
  opacity: 1;
  color: var(--accent);
  background: var(--surface-2);
  border-color: var(--border);
}

/* Grip dots on tiles while editing */
body.reorder-editing .module-tile::after {
  content: "";
  position: absolute;
  top: 12px;
  right: 12px;
  width: 3px;
  height: 3px;
  border-radius: var(--r-pill);
  background: var(--ink-soft);
  box-shadow:
    0 5px 0 var(--ink-soft), 0 10px 0 var(--ink-soft),
    5px 0 0 var(--ink-soft), 5px 5px 0 var(--ink-soft), 5px 10px 0 var(--ink-soft);
  opacity: 0.5;
  pointer-events: none;
  z-index: 2;
}

/* Lifted clone that follows the finger/cursor */
.reorder-clone {
  filter: drop-shadow(0 16px 36px rgba(0,0,0,0.24));
}
.reorder-clone .card,
.reorder-clone.link-row,
.reorder-clone .section-head {
  animation: none !important;
}
.reorder-clone:not(.reorder-clone--landing) {
  transform: scale(1.05) rotate(1.4deg);
  transition: transform 0.14s ease;
}
.reorder-clone .card {
  box-shadow: 0 16px 36px rgba(0,0,0,0.24);
  border-color: rgba(15,52,96,0.4);
}

/* The gap left behind by the lifted item */
.reorder-placeholder {
  animation: none !important;
}
.reorder-placeholder .card,
.reorder-placeholder.link-row,
.reorder-placeholder[data-overview-section] > * {
  visibility: hidden;
}
.reorder-placeholder {
  outline: 2px dashed var(--accent);
  outline-offset: -2px;
  border-radius: var(--r2);
  background: color-mix(in oklab, var(--accent) 10%, transparent);
}

/* ─── Reduced motion ─── */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ══════════════════════════════════════════════════════════════════
   BAUSATZ — the shared kit (§4) and the shell (§5)

   Everything below is the redesign. Pages are migrated onto it one at
   a time; until a page is migrated its old classes still work, because
   the legacy aliases at the bottom of this file point the old names at
   these same rules.

   One breakpoint only: 900px. Below it the phone layout, above it the
   laptop layout. No other breakpoints.
   ══════════════════════════════════════════════════════════════════ */

/* ── Bereich colour carrier ────────────────────────────────────────
   A Bereich sets two locals; every component reads --tint for the
   plate and --deep for the glyph. That is the whole colour contract:
   never a surface, never text, never a border. */
[data-bereich]            { --tint: var(--surface-2); --deep: var(--ink-soft); }
[data-bereich="ski"]      { --tint: var(--tint-ski);     --deep: var(--ski-deep); }
[data-bereich="food"]     { --tint: var(--tint-food);    --deep: var(--food-deep); }
[data-bereich="trip"],
[data-bereich="kalender"] { --tint: var(--tint-trip);    --deep: var(--trip-deep); }
[data-bereich="matura"]   { --tint: var(--tint-matura);  --deep: var(--matura-deep); }
[data-bereich="watch"]    { --tint: var(--tint-watch);   --deep: var(--watch-deep); }
[data-bereich="lernkarten"] { --tint: var(--tint-lernkarten); --deep: var(--lernkarten-deep); }
[data-bereich="weather"]  { --tint: var(--tint-weather); --deep: var(--weather-deep); }
[data-bereich="msg"]      { --tint: var(--tint-msg);     --deep: var(--msg-deep); }
[data-bereich="training"] { --tint: var(--tint-training); --deep: var(--training-deep); }
[data-bereich="admin"]    { --tint: var(--accent-bg);     --deep: var(--accent); }

/* Terminarten einer Gruppe. Die Farbe ist hier keine Dekoration,
   sondern die Information: blau heisst Training, gruen Lager, rot
   Rennen — im Kalender, in der Liste und in der Vorschau immer
   dieselbe Zuordnung.

   Eigene Namen statt geliehener: die vorhandenen Bereichsfarben haben
   zwar passende Farbtoene, aber data-bereich="weather" an einem
   Krafttraining waere beim naechsten Lesen ein Raetsel. */
[data-bereich="t-training"] { --tint: var(--tint-weather); --deep: var(--weather-deep); }
[data-bereich="t-lager"]    { --tint: var(--tint-food);    --deep: var(--food-deep); }
[data-bereich="t-rennen"]   { --tint: var(--tint-training); --deep: var(--training-deep); }
/* Eine Feier (v.35.75.0) gibt es nur bei Familie und Freunden. Sie
   bekommt einen eigenen Ton, weil man sie im Kalender suchen wird —
   und nicht den der drei Sportarten, die etwas anderes bedeuten. */
[data-bereich="t-feier"]    { --tint: var(--tint-matura);  --deep: var(--matura-deep); }

/* ── 4.1 Zeile — the one row component ─────────────────────────────
   Replaces .link-row, .item-card, .file-row, .grp-card, .pending-card. */
.row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-row);
  transition: border-color 150ms ease;
  cursor: pointer;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
}
.row:hover      { border-color: var(--ink-soft); }   /* colour only, never movement */
.row:active     { transform: scale(0.97); }
.row--static    { cursor: default; }
.row--static:hover { border-color: var(--border); }

.row__icon {
  flex: none;
  width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-icon);
  background: var(--tint, var(--surface-2));
  color: var(--deep, var(--ink-soft));
  font-size: 13px; font-weight: 800;      /* for the letter variant */
}
.row__icon svg { width: 18px; height: 18px; stroke-width: 1.8; }

/* Diese drei sind <span>, also von Haus aus inline. Ohne display:block
   verwirft der Browser Höhe und margin am Balken und ignoriert
   overflow/text-overflow am Untertitel — der Balken blieb dadurch eine
   haarfeine Linie ohne Füllung. */
.row__body  { flex: 1; min-width: 0; }
.row__title { display: block; font-size: 14px; font-weight: 700; line-height: 1.35; }
.row__sub   {
  display: block;
  font-size: 12px; font-weight: 400; color: var(--ink-soft); line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Right column — exactly one of these per row. */
.row__end   { flex: none; display: flex; align-items: center; gap: var(--s2); }

/* Ein Plaettchen, das ein Emoji traegt statt eines Strichsymbols.
   Das Emoji ist Inhalt — der Nutzer hat es selbst gewaehlt —, also
   bekommt es keine Strichfarbe aufgezwungen. */
.row__icon--emoji { font-size: 17px; line-height: 1; }

/* Kleine Aktionen am rechten Rand einer Zeile: veroeffentlichen,
   bearbeiten, loeschen. Nur Symbol; was sie tun, sagen title und
   aria-label. Drei beschriftete Knoepfe je Zeile waren der Grund,
   warum die Projektliste unruhig wirkte. */
.row__aktion {
  flex: none;
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 1px solid transparent;
  border-radius: var(--r-icon);
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background-color 150ms ease, color 150ms ease, border-color 150ms ease;
}
.row__aktion svg { width: 16px; height: 16px; }
.row__aktion:hover { background: var(--surface-2); color: var(--ink); border-color: var(--border); }
.row__aktion--an { color: var(--accent); }
.row__aktion--gefahr:hover { color: var(--danger, #B4453C); }

/* ── Eingabe in einer Zeile ────────────────────────────────────────
   Der Einheiten-Player traegt Wert und Wiederholungen rechts in der
   Satzzeile ein. Ein .form-input ist dort zu breit — er ist auf
   width:100% gebaut, weil er sonst in einem Formular steht.

   64px reichen fuer "12.5" und drei Ziffern Gewicht, und die Hoehe
   bleibt bei 44px: das ist die Flaeche, die man mit einer Hantel in
   der anderen Hand noch trifft. */
.row__end .form-input {
  width: 64px; min-width: 0;
  padding: var(--s1) var(--s2);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Zeile als Schalter (Modul-Liste in den Einstellungen). Gleiche Zeile
   wie überall, rechts ein Kästchen statt Chevron — statt eigener
   Klassen mit Emoji und System-Checkbox. */
.avatar.avatar--ink {
  background: var(--tint, var(--surface-2));
  color: var(--deep, var(--ink-soft));
  width: 36px; height: 36px; font-size: 13px;
  cursor: default;
}

.row--check {
  width: 100%;
  min-width: 0;
  min-height: 70px;
  cursor: pointer;
  user-select: none;
}
.row--check.is-checked {
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
}
.module-toggle-state {
  min-width: 64px;
  color: var(--ink-soft);
  font-size: 11px;
  font-weight: 700;
  text-align: right;
}
.row--check.is-checked .module-toggle-state { color: var(--accent); }
/* The base checkbox look is shared with .admin-mod's checkbox in
   feature/access.css (same declarations, duplicated there) — the two
   were fused in one comma-selector in the original file. */
.row--check input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 22px; height: 22px; flex: none; margin: 0;
  border: 1.5px solid var(--border);
  border-radius: var(--r-icon);
  background: var(--surface);
  cursor: pointer;
  display: inline-grid; place-content: center;
  transition: background 140ms ease, border-color 140ms ease;
}
.row--check input[type="checkbox"] {
  width: 42px;
  height: 24px;
  padding: 2px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  border-radius: var(--r-pill);
  background: var(--surface-2);
}
.row--check input[type="checkbox"]::after {
  content: ""; width: 11px; height: 11px;
  clip-path: polygon(14% 45%, 0 60%, 40% 100%, 100% 22%, 85% 8%, 38% 71%);
  background: #fff; transform: scale(0);
  transition: transform 140ms cubic-bezier(0.2, 0.85, 0.25, 1);
}
.row--check input[type="checkbox"]::after {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  clip-path: none;
  background: white;
  box-shadow: 0 1px 4px rgba(15, 23, 42, .2);
  transform: translateX(0);
}
.row--check input[type="checkbox"]:checked {
  background: var(--accent); border-color: var(--accent);
}
.row--check input[type="checkbox"]:checked::after { transform: scale(1); }
.row--check input[type="checkbox"]:checked::after {
  transform: translateX(18px);
}
.row--check input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
@media (max-width: 700px) {
  #settingsModal .modal {
    max-width: none;
    max-height: 100dvh;
    min-height: 100dvh;
    border: 0;
    border-radius: 0;
    padding: var(--s4);
  }
  #settingsModal #moduleToggles { grid-template-columns: 1fr; }
  .settings-section-head { display: block; }
  .settings-save-state { margin-top: var(--s3); }
}
@media (max-width: 480px) {
  .module-toggle-state { display: none; }
}
.row__chev  { width: 16px; height: 16px; color: var(--ink-soft); stroke-width: 1.8; }
.row__num   { font-size: 14px; font-weight: 800; font-variant-numeric: tabular-nums; }
.row__time  { font-size: 11px; font-weight: 700; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.row__badge {
  min-width: 20px; height: 20px; padding: 0 var(--s2);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--danger); color: #fff;
  font-size: 11px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.row__add {
  width: 30px; height: 30px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--accent); color: #fff; border: none; cursor: pointer;
}
.row__status {
  padding: 0 var(--s3); height: 24px;
  display: inline-flex; align-items: center;
  border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border);
  font-size: 11px; font-weight: 800; color: var(--ink-soft);
}

/* Progress instead of a subtitle. */
.row__bar {
  display: block;
  margin-top: var(--s2); height: 5px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  overflow: hidden;
}
.row__bar > i {
  display: block; height: 100%;
  background: var(--deep, var(--accent));
  border-radius: var(--r-pill);
  transition: width 300ms cubic-bezier(0.2, 0.85, 0.25, 1);
}

/* A list of rows. */
.rows { display: flex; flex-direction: column; gap: var(--s2); }

/* Text-only placeholder inside an empty .rows section.
   Nur oben und unten Luft, nicht seitlich: der Satz steht an derselben
   Kante wie die Ueberschrift darueber und die Zeilen, die spaeter an
   seiner Stelle stehen. Mit Innenabstand rundum begann er 12 Pixel
   weiter drin — eine dritte Kante in einem Abschnitt, der zwei hat. */
.empty-hint { padding: var(--s3) 0; }

/* ── 4.2 Kachel — quick access ─────────────────────────────────────*/
.tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s2); }
.tile {
  display: flex; flex-direction: column; align-items: center; gap: var(--s2);
  padding: var(--s3) var(--s2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-row);
  transition: border-color 150ms ease;
  cursor: pointer;
  min-width: 0;
}
.tile:hover  { border-color: var(--ink-soft); }
.tile:active { transform: scale(0.97); }
.tile__icon {
  width: 34px; height: 34px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-icon);
  background: var(--tint, var(--surface-2));
  color: var(--deep, var(--ink-soft));
}
.tile__icon svg { width: 18px; height: 18px; stroke-width: 1.8; }
.tile__name {
  font-size: 11px; font-weight: 700; text-align: center; line-height: 1.25;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tile__meta { display: none; }
/* Die Metazeile lief über die Kachel hinaus, sobald der Text länger war
   als die Spalte breit ist — sie kürzt jetzt, statt zu überlaufen. */
.tile__meta, .tile-live {
  min-width: 0; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tile-prog { white-space: normal; }

/* ── 4.3 Panel ─────────────────────────────────────────────────────*/
.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  padding: var(--s4) var(--s4);
}
.panel__big {
  font-size: 30px; font-weight: 800; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.panel__grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s3);
  margin-top: var(--s4);
}
.panel__grid dt { font-size: 12px; color: var(--ink-soft); font-weight: 600; }
.panel__grid dd { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; }

/* ── Bereichsmarke — the small uppercase section label ─────────────*/
/* ── Das Wortzeichen ───────────────────────────────────────────────
   Fir + n. Das "n" ist das Erkennungszeichen — es muss auch dann noch
   als eigenes Zeichen lesbar sein, wenn vom Rest nichts mehr da ist.
   Darum traegt es nicht nur die Farbe, sondern auch das Gewicht.

   EINE Farbe, auf jedem Grund. Bis v.35.29.0 waren es zwei: Marken-Blau
   auf hellem Grund, Alpengluehen auf Navy — weil das Blau gegen Navy
   zusammenfaellt (2,5 : 1) und das helle Gluehen auf Weiss (2,0 : 1).
   Das sah aus wie zwei Marken. --firn-n ist ein tieferes Alpengluehen,
   derselbe warme Ton wie der Gipfel im App-Symbol, und traegt auf allen
   Gruenden: mind. 3,3 : 1 auf Hell, 4,7 : 1 auf Navy und im Dunkelmodus.
   Darum hat es keine Dunkel-Fassung. dev/marke.test.mjs rechnet nach. */
.firn {
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--ink);
  white-space: nowrap;
}
.firn--hell { color: #FFFFFF; }

.firn > b {
  font-weight: 900;
  color: var(--firn-n);
  /* Optisch traegt das n sonst zu wenig: es ist der kuerzeste
     Buchstabe im Wort und verliert gegen das grosse F. */
  letter-spacing: 0;
}

.marke {
  font-size: 11.5px; font-weight: 800; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-faint, var(--ink-soft));
  margin-bottom: var(--s2);
}

/* Marke mit einer Zahl am rechten Rand — "MITGLIEDER … 4 Personen".
   Die Zahl gehoert zur Ueberschrift und nicht in die Kopfleiste: dort
   loescht mountShell sie beim Mounten wieder weg. */
.marke--reihe {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s3);
}
.marke--reihe > span:last-child { font-weight: 700; letter-spacing: 0.06em; }

/* Die Beschriftung nimmt den Platz, alles Weitere sammelt sich rechts.
   Ohne das verteilt space-between drei Kinder gleichmaessig, und der
   Titel steht dann irgendwo in der Mitte. */
.marke--reihe > :first-child { flex: 1; }
.marke--reihe button { flex: none; }

/* ── TVZA — das Zeichen des persönlichen Teils (v.35.35.0) ─────────
   Firn ist der Ort für Gruppen; was Timo für sich und seine Freunde
   gebaut hat, trägt dieses Zeichen: auf Start über dem eigenen Teil, in
   den Einstellungen, im Admin-Bereich und im Kopf der Seiten selbst.
   Leise mit Absicht — es sagt, wem etwas gehört, es wirbt nicht. Die
   Farbe ist die der Umgebung (currentColor), darum trägt es auf hellem
   Grund wie im dunklen Kopf.

   Für den TVZA-Kreis ist Start TVZA; über den Firn-Bereichen steht dort
   dasselbe Zeichen mit "Firn" (v.35.48.0) — die Tür in die andere
   Software, in derselben Stimme. */
.tvza-marke,
.firn-marke {
  display: inline-flex; align-items: center; flex: none;
  padding: 1px var(--s1);
  border: 1px solid currentColor;
  border-radius: var(--r-pill);
  font-size: 10px; font-weight: 800; line-height: 1.3;
  letter-spacing: 0.08em; text-transform: uppercase;
  opacity: 0.72;
  vertical-align: middle;
}
.marke--tvza:not(:first-child) { margin-top: var(--s4); }

/* Das Wortzeichen TVZA: dieselben Buchstaben, dasselbe Gewicht und
   derselbe Abstand wie .tvza-marke, nur gross und ohne Rahmen — auf der
   Projektseite und in der Leiste, wenn man in TVZA ist. Die Farbe kommt
   aus der Umgebung. */
.tvza { font-weight: 800; letter-spacing: 0.08em; white-space: nowrap; }

/* ── Firn oder TVZA (wechsel.js, v.35.40.0) ────────────────────────
   Beide Wortzeichen liegen übereinander; sichtbar ist das, was
   data-software am nächsten Vorfahren sagt — ohne Angabe Firn. So
   blenden sie ineinander, während sich das Zeichen daneben vom Berg
   zum T verwandelt. */
.software-wort { display: inline-grid; align-items: center; }
.software-wort > * { grid-area: 1 / 1; transition: opacity 240ms ease; }
.software-wort > .tvza { opacity: 0; }
[data-software="tvza"] .software-wort > .tvza { opacity: 1; }
[data-software="tvza"] .software-wort > .firn { opacity: 0; }

/* Beim Wechsel gleitet oben in der Mitte eine Karte herein und das
   Zeichen verwandelt sich darin — am Handy und am Laptop. v.35.51.0
   stand sie gross in der Bildmitte über abgedunkelter Seite; Michel:
   "less intrusive". Jetzt ohne Abdunkeln, oben, kompakt — aber gross
   genug, dass man die Verwandlung sieht. Die Karte trägt die Farbe der
   Software und wechselt sie mit. Durchklickbar; wechsel.js baut sie und
   nimmt sie wieder weg. */
.wechsel-hinweis {
  position: fixed; z-index: 400; left: 50%;
  top: calc(env(safe-area-inset-top, 0px) + var(--s3));
  opacity: 0;
  transform: translate(-50%, -12px);
  transition: opacity 220ms ease, transform 260ms cubic-bezier(0.2, 0.9, 0.3, 1.15);
  pointer-events: none;
}
.wechsel-hinweis.is-da { opacity: 1; transform: translate(-50%, 0); }
.wechsel-hinweis__karte {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2) var(--s5) var(--s2) var(--s2);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--r-pill);
  background-color: #1256B0;
  color: #FFFFFF;
  font-size: 22px; line-height: 1;
  transition: background-color 600ms ease;
}
.wechsel-hinweis[data-software="tvza"] .wechsel-hinweis__karte { background-color: #1A1A2E; }
.wechsel-hinweis svg { display: block; width: 44px; height: 44px; flex: none; border-radius: 22%; }
@media (prefers-reduced-motion: reduce) {
  .wechsel-hinweis, .wechsel-hinweis.is-da { transform: translate(-50%, 0); }
  .wechsel-hinweis__karte { transition: none; }
}

/* Das Zeichen der Leiste pulsiert, während es sich verwandelt. */
@keyframes zeichen-puls {
  0% { transform: scale(1); }
  40% { transform: scale(1.35); }
  100% { transform: scale(1); }
}
.nav.is-wechsel .nav__zeichen { animation: zeichen-puls 900ms cubic-bezier(0.3, 0.8, 0.3, 1); }
@media (prefers-reduced-motion: reduce) {
  .nav.is-wechsel .nav__zeichen { animation: none; }
}

/* Knoepfe unter einem Abschnitt. Nebeneinander, solange sie passen. */
/* ── Die Vorschau in der Tageskarte ────────────────────────────────
   Aufbau wie in der Schul-Mail, an der sich die Karte orientiert:
   Datum links, Sache in der Mitte, Uhrzeit rechts. Tabellarische
   Ziffern, damit die Spalten stehen und nicht tanzen. */
.brief__marke {
  margin-top: var(--s5);
  margin-bottom: var(--s2);
  padding-top: var(--s3);
  border-top: 1px solid color-mix(in oklab, var(--accent) 18%, var(--border));
}
.brief__liste { display: grid; gap: var(--s2); }
.brief__zeile {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  font-size: 13.5px;
  line-height: 1.4;
}
.brief__wann {
  flex: none;
  min-width: 5.5em;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.brief__was  { flex: 1; min-width: 0; color: var(--ink-soft); }
.brief__zeit {
  flex: none;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}

.knopfreihe {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  margin-top: var(--s4);
}

/* ── 4.4 Knöpfe — three, final ─────────────────────────────────────*/
.b {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: 46px; padding: 0 var(--s5);
  border: 1px solid transparent;
  border-radius: var(--r-row);
  font-size: 14px; font-weight: 700; font-family: inherit;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.b:active           { transform: scale(0.97); }
.b--primary         { background: var(--accent); color: #fff; }
.b--primary:hover   { background: var(--accent-hover); }
.b--secondary       { background: var(--surface); border-color: var(--border); color: var(--ink); }
.b--secondary:hover { border-color: var(--ink-soft); }
.b--danger          { background: transparent; color: var(--danger); }
.b--danger:hover    { background: var(--danger-bg); }
.b--block           { width: 100%; }
:root[data-theme="dark"] .b--primary { color: var(--brand-navy); }

/* ── 4.5 Icons ─────────────────────────────────────────────────────
   One set: viewBox 0 0 24 24, fill none, stroke currentColor. Emoji
   used as a *function* symbol are replaced; emoji the user typed in
   themselves stay, because there they are content. */
.ic { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* Ein einziges Plus für alle Aktionen. Die Balken werden als Prozent
   der festen 16-px-Fläche gezeichnet; 12.5 % sind exakt 2 px und
   vermeiden die weicheren 1.8-px-Halbpixel mancher früherer Varianten.
   .calendar-action-icon shared this rule with .ui-plus in the original
   file — its declarations are duplicated in feature/calendar.css. */
.ui-plus {
  position: relative;
  display: block;
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  margin: 0;
}
.ui-plus::before,
.ui-plus::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 75%;
  height: 12.5%;
  border-radius: var(--r-pill);
  background: currentColor;
  transform: translate(-50%, -50%);
}
.ui-plus::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

/* ── 5.1 Kopf — same on every page ─────────────────────────────────*/
.appbar {
  position: sticky; top: 0; z-index: 40;
  background: var(--brand-gradient);
  color: #fff;
  padding-top: env(safe-area-inset-top);
}
.appbar .back-btn, .appbar__btn, .appbar .avatar { color: #fff; }
.appbar__inner {
  /* Eine Grösse steuert die Bedienelemente rechts, und die Abstände
     leiten sich daraus ab statt aus der Viewportbreite. Dadurch bleibt
     das Verhältnis von Kringel zu Lücke auf jedem Bildschirm gleich —
     vorher wuchsen die Abstände mit vw, während die Kringel schon am
     Anschlag waren, und wirkten deshalb zu gross. */
  --ctl: clamp(30px, 7.6vw, 34px);
  display: flex; align-items: center;
  gap: calc(var(--ctl) * 0.25);
  padding: clamp(10px, 3vw, 14px) calc(var(--ctl) * 0.44) clamp(12px, 3.5vw, 16px);
  max-width: 1160px; margin: 0 auto;
}
/* Die Begrüssung bleibt auf einer Zeile: sie skaliert mit der
   Viewportbreite statt auf einer festen Grösse zu bestehen und
   umzubrechen, und kürzt im Notfall mit Auslassungspunkten. So kostet
   der Kopf auf einem schmalen Gerät nicht zwei Zeilen Höhe. */
.appbar__greet {
  font-size: clamp(17px, 5.2vw, 26px);
  font-weight: 800; letter-spacing: -0.02em; line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.appbar__date {
  font-size: clamp(11px, 3.2vw, 13px);
  color: rgba(255,255,255,0.7); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.appbar__title   { text-align: left; font-size: clamp(14px, 4vw, 15px); font-weight: 700;
                   overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Ein Titel, der eine Wahl öffnet (setShellTitleWahl): der Name der
   Gruppe mit einem Winkel — tippen heisst wechseln (v.35.49.0). */
.appbar__title--wahl {
  position: relative;
  max-width: 100%;
  padding-right: var(--s4);
  border-radius: var(--r-icon);
  cursor: pointer;
}
.appbar__title--wahl::after {
  content: "";
  position: absolute;
  right: 3px;
  top: 50%;
  width: 7px;
  height: 7px;
  border: solid currentColor;
  border-width: 0 2px 2px 0;
  opacity: 0.75;
  transform: translateY(-70%) rotate(45deg);
}
.appbar__title--wahl:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
/* Am Handy bleibt der Gruppenname der Wechselweg, aber als schlichter
   Textknopf statt als gerundete iPhone-artige Flaeche. */
@media (max-width: 899px) {
  .appbar__title--wahl { border-radius: 0; background: transparent; }
}
/* Der Farbpunkt der Gruppe vor dem Namen (v.35.68.0, titelFarbeSetzen). */
.appbar__title--punkt::before {
  content: "";
  display: inline-block;
  width: 10px; height: 10px;
  margin-right: var(--s2);
  border-radius: var(--r-pill);
  background: var(--titel-punkt);
  box-shadow: 0 0 0 2px rgba(255,255,255,0.85);
  vertical-align: 0.05em;
}
.appbar--bereich .appbar__title {
  display: block;
  margin-right: auto;
  line-height: 1.2;
}
/* Bereichsseiten verwenden dieselbe Kopfzeile wie Start. Die dauerhaft
   sichtbare Navigation ersetzt den alten Zurück-Pfeil. */
.appbar--bereich .appbar__inner { display: flex; }
.appbar--bereich .back-btn,
.appbar--bereich #shellBack { display: none; }
.appbar__end { display: flex; align-items: center; gap: var(--s2); justify-self: end; }
.appbar__spacer  { flex: 1; min-width: 0; }
.appbar__btn {
  width: 36px; height: 36px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: var(--r-icon);
  background: rgba(255,255,255,0.12); color: #fff; cursor: pointer;
}
.appbar__btn:active { transform: scale(0.97); }
/* 3px Bereich stripe under the header of a Bereich page. */
.appbar__accent { height: 3px; background: var(--tint, transparent); }

/* Weather pill in the header — injected on every page via shell.js, not
   specific to weather.html, so it stays in kit.css. */
.wx-pill {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2); flex: none;
  height: var(--ctl, 32px); padding: 0 calc(var(--ctl, 32px) * 0.34);
  border-radius: var(--r-pill);
  background: rgba(255,255,255,0.12); color: #fff;
  font-size: clamp(12px, 3.4vw, 13px); font-weight: 700; font-variant-numeric: tabular-nums;
}
.wx-pill svg { width: 16px; height: 16px; flex: none; stroke-width: 1.7; }

.appbar .tvzn-bell {
  width: var(--ctl, 32px);
  height: var(--ctl, 32px);
  flex: none;
  color: #fff;
}
/* Header controls have one stable order on direct and client-routed pages. */
.appbar__inner > .wx-pill { order: 10; }
.appbar__inner > .tvzn-bell,
.appbar__end > .tvzn-bell { order: 20; }
.appbar__inner > .tvza-route-page-action,
.appbar__end > #profileBtn,
.appbar__end > #settingsBtn { order: 30; }
.appbar__inner > .acct,
.appbar__end > .acct { order: 40; }
.avatar {
  width: var(--ctl, 32px); height: var(--ctl, 32px); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: rgba(255,255,255,0.12); color: #fff;
  font-size: 12px; font-weight: 800; border: none; cursor: pointer;
}

/* ─── Konto-Menü ───
   Einstellungen und Abmelden hängen am Avatar statt als eigene Knöpfe
   in der Kopfzeile zu stehen. Das Menü selbst gehört zur Fläche, nicht
   zum Farbverlauf — also Flächenfarbe und Rahmen, kein Schatten. */
.acct { position: relative; flex: none; }
.acct__menu {
  position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 208px; max-width: min(78vw, 280px);
  padding: var(--s2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  color: var(--ink);
  z-index: 120;
}
.acct__menu[hidden] { display: none; }
.acct__head {
  display: flex; flex-direction: column; gap: 1px;
  padding: var(--s2) var(--s3) var(--s3);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--s1);
}
.acct__who  { font-size: 14px; font-weight: 700; }
.acct__mail {
  font-size: 12px; color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct__item {
  display: flex; align-items: center; gap: var(--s3); width: 100%;
  padding: var(--s3); min-height: 44px;
  border: none; background: none; cursor: pointer;
  border-radius: var(--r-icon);
  font: 700 14px/1 inherit; color: var(--ink); text-align: left;
}
.acct__item svg { flex: none; fill: none; stroke: currentColor; stroke-width: 1.8;
                  stroke-linecap: round; stroke-linejoin: round; }
.acct__item:hover { background: var(--surface-2); }
.acct__item:active { transform: scale(0.97); }
.acct__item--danger { color: var(--danger); }
.acct__item--danger:hover { background: var(--danger-bg); }

/* ── 5.2 Navigation — four destinations ────────────────────────────*/
.nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  display: grid; grid-template-columns: repeat(4, 1fr);
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding: var(--s2) var(--s2) calc(var(--s2) + env(safe-area-inset-bottom));
}
.nav__item {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  color: var(--ink-soft); font-size: 10px; font-weight: 700;
  background: none; border: none; cursor: pointer; position: relative;
}
.nav__item svg { width: 21px; height: 21px; stroke-width: 1.9; }
.nav__item.is-active { color: var(--nav-active); font-weight: 700; }
/* Eine Zeile, auch wenn die Gruppe "BSV Perspektivkader" heisst: am Handy
   brach der Tab sonst auf zwei Zeilen um und stand höher als die anderen
   (Rundgang v.35.46.0). Der ganze Name steht oben auf der Gruppenseite. */
.nav__item { min-width: 0; }
.nav__wort { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav__dot {
  position: absolute; top: -2px; right: 50%; margin-right: -14px;
  width: 8px; height: 8px; border-radius: var(--r-pill); background: var(--danger);
}
.nav__count { display: none; }
/* "Gruppe wechseln" unter dem Gruppe-Tab gibt es nur am Laptop. Am Handy
   ist die Leiste ein Raster aus vier Spalten, ein fuenftes Element risse
   es auf — dort wechselt man ueber die Karte oben auf der Gruppenseite. */
.nav__wechsel { display: none; }
/* Die Liste der Gruppen und das Wort "Gruppen" gibt es nur am Laptop. */
.nav__gruppen, .nav__wort--mehrere { display: none; }
/* Kopf und Fuss der Leiste gibt es nur am Laptop. Am Handy liegt die
   Leiste unten und traegt die vier Tabs; das Konto steht dort im Kopf
   der Seite. */
.appbar__marke, .nav__kopf, .nav__fuss { display: none; }
.nav a[aria-current="page"] { cursor: default; }
/* Keep the bottom bar from covering the last row of content. */
.has-nav { padding-bottom: calc(var(--nav-hoehe) + env(safe-area-inset-bottom)); }

.global-reminder-fab,
.global-reminder-backdrop,
.global-reminder-sheet { display:none; }
@media (max-width:899px) {
  .global-reminder-fab:not([hidden]) {
    position:fixed;
    z-index:44;
    right:3%;
    bottom:calc(var(--tvza-shell-bottom, var(--nav-hoehe)) + clamp(10px, 2.5vw, 16px));
    width:clamp(48px, 14vw, 58px);
    aspect-ratio:1;
    display:grid;
    place-items:center;
    border:1px solid var(--accent);
    border-radius:50%;
    background:var(--accent);
    color:#fff;
    padding:0;
    font:inherit;
    cursor:pointer;
    box-shadow:0 8px 22px rgba(15,52,96,.24);
  }
  .global-reminder-fab svg { width:42%; height:42%; }
  .global-reminder-fab__count {
    position:absolute;
    top:-5px;
    right:-4px;
    min-width:20px;
    height:20px;
    padding:0 var(--s1);
    display:grid;
    place-items:center;
    border:2px solid var(--surface);
    border-radius:var(--r-pill);
    background:#2f7d5a;
    color:#fff;
    font-size:10px;
    font-weight:900;
    line-height:1;
  }
  .global-reminder-fab__count.has-open { background:#cf2f3b; }
  body:has(.modal-backdrop.visible) .global-reminder-fab,
  body:has(.modal-backdrop.show) .global-reminder-fab,
  /* Nur, solange die Einstellungen OFFEN sind. Bis v.35.54.0 hing das
     am blossen Vorhandensein der Einstellungs-Ebene — die steht aber immer
     (versteckt) im Dokument, und der Knopf war darum nie zu sehen. */
  body.settings-layer-open .global-reminder-fab,
  body.global-reminders-open .global-reminder-fab {
    display:none;
  }

  .global-reminder-backdrop {
    position:fixed;
    z-index:60;
    top:0;
    right:0;
    bottom:var(--tvza-shell-bottom, calc(var(--nav-hoehe) + env(safe-area-inset-bottom)));
    left:0;
    display:none;
    background:rgba(15,23,42,.52);
  }
  .global-reminder-backdrop.visible { display:block; }
  .global-reminder-sheet {
    display:block;
    position:fixed;
    z-index:61;
    right:0;
    bottom:var(--tvza-shell-bottom, calc(var(--nav-hoehe) + env(safe-area-inset-bottom)));
    left:0;
    width:min(680px,100%);
    max-height:min(76dvh,680px);
    margin:0 auto;
    overflow:hidden;
    border:1px solid color-mix(in srgb,var(--accent) 16%,var(--border));
    border-bottom:0;
    border-radius:var(--r-panel) var(--r-panel) 0 0;
    background:var(--surface);
    color:var(--ink);
    box-shadow:0 -18px 50px rgba(15,23,42,.18);
    opacity:0;
    pointer-events:none;
    transform:translateY(104%);
    transition:transform 260ms cubic-bezier(.22,.61,.36,1),opacity 160ms ease;
  }
  .global-reminder-sheet.visible {
    opacity:1;
    pointer-events:auto;
    transform:translateY(0);
  }
  .global-reminder-list-view,
  .global-reminder-form-view {
    max-height:min(76dvh,680px);
    padding:clamp(15px,4vw,20px) 5% clamp(14px,4vw,20px);
  }
  .global-reminder-list-view {
    display:flex;
    flex-direction:column;
  }
  .global-reminder-form-view {
    overflow-y:auto;
    overscroll-behavior:contain;
  }
  .global-reminder-form-view[hidden],
  .global-reminder-list-view[hidden] { display:none; }
  .global-reminder-sheet__head {
    display:flex;
    align-items:center;
    gap:var(--s3);
    margin-bottom:var(--s3);
  }
  .global-reminder-sheet__head > div { flex:1; min-width:0; }
  .global-reminder-sheet__head h2 {
    flex:1;
    margin:0;
    color:var(--ink);
    font-size:clamp(19px,5.5vw,24px);
    line-height:1.15;
  }
  .global-reminder-sheet__eyebrow {
    display:block;
    margin-bottom:3px;
    color:var(--accent);
    font-size:10px;
    font-weight:900;
    letter-spacing:.08em;
    text-transform:uppercase;
  }
  .global-reminder-icon-button {
    width:42px;
    height:42px;
    flex:0 0 auto;
    display:grid;
    place-items:center;
    padding:0;
    border:1px solid var(--border);
    border-radius:50%;
    background:var(--surface);
    color:var(--ink);
    cursor:pointer;
  }
  .global-reminder-list {
    flex:1;
    min-height:0;
    overflow-y:auto;
    overscroll-behavior:contain;
    border-top:1px solid var(--border);
    scrollbar-width:none;
  }
  .global-reminder-list::-webkit-scrollbar { display:none; }
  .global-reminder-row {
    display:flex;
    align-items:center;
    gap:var(--s3);
    min-height:64px;
    padding:var(--s3) 1px;
    border-bottom:1px solid var(--border);
  }
  .global-reminder-check {
    width:27px;
    height:27px;
    flex:0 0 auto;
    display:grid;
    place-items:center;
    padding:0;
    border:2px solid color-mix(in srgb,var(--ink) 34%,var(--border));
    border-radius:50%;
    background:var(--surface);
    color:#fff;
    font-weight:900;
    cursor:pointer;
  }
  .global-reminder-check.is-done {
    border-color:var(--accent);
    background:var(--accent);
  }
  .global-reminder-row__body {
    flex:1;
    min-width:0;
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    padding:var(--s1) 0;
    border:0;
    background:transparent;
    color:var(--ink);
    text-align:left;
    cursor:pointer;
  }
  .global-reminder-row__title {
    max-width:100%;
    overflow:hidden;
    font-size:15px;
    font-weight:800;
    text-overflow:ellipsis;
    white-space:nowrap;
  }
  .global-reminder-row__meta {
    margin-top:3px;
    color:color-mix(in srgb,var(--ink) 68%,transparent);
    font-size:12px;
    font-weight:600;
  }
  .global-reminder-row.is-done .global-reminder-row__title {
    color:color-mix(in srgb,var(--ink) 62%,transparent);
    text-decoration:line-through;
  }
  .global-reminder-row.is-overdue .global-reminder-row__meta {
    color:var(--danger);
    font-weight:800;
  }
  .global-reminder-edit {
    min-width:38px;
    min-height:38px;
    padding:0;
    border:0;
    background:transparent;
    color:var(--ink);
    font-size:18px;
    cursor:pointer;
  }
  .global-reminder-add,
  .global-reminder-save {
    width:100%;
    min-height:50px;
    flex:0 0 auto;
    display:flex;
    align-items:center;
    justify-content:center;
    gap:var(--s2);
    margin-top:var(--s3);
    border:1px solid var(--accent);
    border-radius:var(--r-pill);
    background:var(--accent);
    color:#fff;
    font:inherit;
    font-size:14px;
    font-weight:800;
    line-height:1;
    cursor:pointer;
  }
  .global-reminder-add > span:first-child { font-size:22px; line-height:1; }
  .global-reminder-empty {
    flex:1;
    min-height:180px;
    display:flex;
    flex-direction:column;
    align-items:center;
    justify-content:center;
    gap:var(--s1);
    color:var(--ink);
    text-align:center;
  }
  .global-reminder-empty svg {
    width:30px;
    height:30px;
    margin-bottom:var(--s1);
    color:var(--accent);
  }
  .global-reminder-empty span,
  .global-reminder-error {
    color:color-mix(in srgb,var(--ink) 66%,transparent);
    font-size:13px;
  }
  .global-reminder-field {
    display:block;
    margin-bottom:var(--s3);
  }
  .global-reminder-field > span {
    display:block;
    margin-bottom:var(--s1);
    color:color-mix(in srgb,var(--ink) 70%,transparent);
    font-size:12px;
    font-weight:800;
  }
  .global-reminder-field input,
  .global-reminder-field textarea {
    width:100%;
    min-height:46px;
    padding:var(--s3) var(--s3);
    border:1px solid var(--border);
    border-radius:var(--r1);
    background:var(--surface);
    color:var(--ink);
    font:inherit;
  }
  .global-reminder-field textarea { min-height:86px; resize:vertical; }
  .global-reminder-fields {
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:var(--s3);
  }
  .global-reminder-complete,
  .global-reminder-delete {
    width:100%;
    min-height:46px;
    margin-top:var(--s2);
    border-radius:var(--r-pill);
    background:transparent;
    font:inherit;
    font-size:13px;
    font-weight:800;
    line-height:1;
    cursor:pointer;
  }
  .global-reminder-complete {
    border:1px solid var(--accent);
    color:var(--accent);
  }
  .global-reminder-complete.is-completed {
    border-color:var(--border);
    color:var(--ink);
  }
  .global-reminder-delete {
    border:0;
    color:var(--danger);
  }
  .global-reminder-complete[hidden],
  .global-reminder-delete[hidden] { display:none; }
}

/* ── Persistent app shell ───────────────────────────────────────────
   Header and navigation stay untouched; only this content surface is
   exchanged after the destination is fully ready. */
.tvza-route-frame {
  position: fixed;
  z-index: 35;
  top: var(--tvza-shell-top, 62px);
  right: 0;
  bottom: var(--tvza-shell-bottom, calc(var(--nav-hoehe) + env(safe-area-inset-bottom)));
  left: 0;
  width: auto;
  height: auto;
  background: var(--bg);
  overflow: hidden;
  opacity: 1;
  transform: translateX(0);
  transition: opacity 180ms ease, transform 210ms cubic-bezier(.2,.8,.2,1);
}
.tvza-route-frame > iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  background: var(--bg);
}
.tvza-route-frame.is-entering {
  opacity: 0;
  transform: translateX(14px);
  pointer-events: none;
}
.tvza-route-frame.is-leaving {
  z-index: 34;
  opacity: 0;
  transform: translateX(-8px);
  pointer-events: none;
}
/* Geparkt (v.35.53.0): die Seite steht und lebt weiter, nur unsichtbar
   — mit ihrer vollen Grösse, damit sie darin richtig misst (display:none
   gäbe ihr null Pixel, und der Kalender stellte die Liste falsch). */
.tvza-route-frame.is-parked {
  z-index: 33;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition: none;
}
@media (max-width:899px) {
  .tvza-route-frame.is-entering.from-right { transform:translateX(10%); }
  .tvza-route-frame.is-entering.from-left { transform:translateX(-10%); }
  .tvza-route-frame.is-leaving.to-left { transform:translateX(-8%); }
  .tvza-route-frame.is-leaving.to-right { transform:translateX(8%); }
}
.tvza-route-progress {
  display: none;
}
@media (min-width: 900px) {
  .tvza-route-frame.is-entering {
    transform: translateY(8px) scale(.996);
  }
  .tvza-route-frame.is-leaving {
    transform: translateY(-4px) scale(.998);
  }
}
.appbar--route-view .appbar__greet {
  font-size: clamp(14px, 4vw, 15px);
  font-weight: 700;
  letter-spacing: 0;
}
/* Weather is Start-page information, not a different Bereich shell action. */
.appbar--route-view .wx-pill {
  display: none !important;
}

/* A content frame runs the real page code, but its duplicate shell is
   hidden before first paint by theme.js. */
html.tvza-content-frame .appbar,
html.tvza-content-frame .nav,
html.tvza-content-frame .fx-version,
html.tvza-content-frame .global-reminder-fab {
  display: none !important;
}
html.tvza-content-frame body,
html.tvza-content-frame body.has-nav {
  min-height: 100dvh;
  padding: 0 !important;
}
html.tvza-content-frame body > .app,
html.tvza-content-frame body > main {
  min-height: 100dvh;
}

/* ── The one breakpoint: 900px ─────────────────────────────────────*/
@media (min-width: 900px) {
  .row      { padding: var(--s4) var(--s4); gap: var(--s4); }
  .row__bar { height: 6px; }
  .panel    { padding: var(--s5) var(--s5); }
  .b        { min-height: 42px; }

  /* Tiles go 2 × 2 and left-aligned, with room for a meta line. */
  .tiles { grid-template-columns: repeat(2, 1fr); gap: var(--s3); }
  .tile  {
    flex-direction: row; align-items: flex-start; justify-content: flex-start;
    flex-wrap: wrap; gap: var(--s3); padding: var(--s4) var(--s4); min-height: 104px;
  }
  .tile__icon { width: 36px; height: 36px; }
  .tile__name { font-size: 14px; text-align: left; width: calc(100% - 48px); }
  .tile__meta {
    display: block; width: 100%; min-width: 0;
    font-size: 12px; color: var(--ink-soft);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* ══ Die Huelle am Laptop ════════════════════════════════════════
     Zwei Spalten: links die Leiste im Navy, rechts der Inhalt mit
     einem hellen Kopf darueber.

     Eine Zahl bestimmt die Breite der Leiste: --leiste. Sie stand
     vorher als 216px an fuenf Stellen (Leiste, Rumpf, Router-Rahmen,
     Fortschrittsbalken, und zugeklappt noch einmal als 64px an drei) —
     genau die Sorte Zahl, die beim naechsten Umbau an einer Stelle
     vergessen wird. */
  body { --leiste: 232px; }
  body.nav-schmal { --leiste: 72px; }

  /* ── Der Kopf ───────────────────────────────────────────────────
     Er gehoert zum INHALT: seine Kante ist die Kante der Spalte
     darunter. Vorher begann der Titel am linken Rand des Kopfs und der
     Inhalt 100 Pixel weiter rechts — zwei Linien, wo eine sein soll.
     Seiten mit breiterem Inhalt (Kalender, Matura) setzen
     --kopf-breite und --kopf-rand selbst. */
  /* Navy wie am Handy und wie die Leiste daneben (v.35.51.0). Bis dahin
     war der Kopf am Laptop weiss — Michel: "oben, wieso ist sie weiss?";
     neben der dunklen Leiste las er sich wie ein Fehler. */
  .appbar {
    margin-left: 0;
    width: 100%;
    z-index: 50;
    background: var(--brand-gradient);
    color: #fff;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  }
  .appbar__accent { display: none; }
  .appbar__inner {
    --ctl: 34px;
    max-width: var(--kopf-breite, var(--max-width));
    margin: 0 auto;
    height: 60px;
    padding: 0 var(--kopf-rand, var(--s5));
    display: flex; align-items: center; gap: var(--s2);
  }
  /* Auf der Gruppenseite nennt und wechselt die linke Leiste die Gruppe
     bereits. Punkt, Name und Winkel im Kopf waeren dort derselbe Weg ein
     zweites Mal; am Handy (ohne Seitenleiste) bleiben sie sichtbar. */
  .appbar[data-route="gruppe"] .appbar__spacer {
    visibility: hidden;
    pointer-events: none;
  }
  .appbar__btn {
    background: transparent;
    color: rgba(255, 255, 255, 0.82);
    transition: background-color 150ms ease, color 150ms ease;
  }
  .appbar__btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
  /* Das Konto steht am Laptop in der Leiste. Zwei Wege zu den
     Einstellungen auf einem Bildschirm waren einer zu viel. */
  .appbar .acct { display: none; }
  .appbar__marke { display: none; }
  .appbar--bereich .appbar__title { margin-left: 0; }
  /* Begrüssung und Datum stehen nebeneinander, nicht gestapelt. */
  .appbar__spacer { display: flex; align-items: baseline; gap: var(--s3); margin-left: 0; }
  .appbar__greet  { font-size: 16px; font-weight: 700; color: #fff; }
  .appbar__title  { font-size: 16px; font-weight: 700; color: #fff; }
  .appbar__date   { font-size: 13px; margin-top: 0; color: rgba(255, 255, 255, 0.7); flex: none; }

  /* ── Die Leiste ─────────────────────────────────────────────────*/
  .nav {
    position: fixed; top: 0; bottom: 0; left: 0; right: auto;
    width: var(--leiste);
    display: flex; flex-direction: column; gap: var(--s1);
    padding: 0 var(--s3) var(--s3);
    border-top: none; border-right: none;
    background: linear-gradient(170deg, var(--brand-navy) 0%, #0F2745 55%, var(--brand-navy-mid) 100%);
    overflow-y: auto;
    overflow-x: hidden;
    --nav-active-bg: rgba(255, 255, 255, 0.12);
    --nav-active: #FFFFFF;
  }

  /* Kopf: Zeichen und Wort, gleich hoch wie der Kopf der Seite, damit
     die Haarlinie darunter in einer Flucht ueber beide Spalten laeuft. */
  .nav__kopf {
    display: flex; align-items: center; gap: var(--s3);
    /* 61 = 60 Kopf + 1 Haarlinie: so liegen die Linien unter beiden
       Koepfen auf derselben Hoehe. */
    height: 61px; flex: none;
    margin: 0 calc(-1 * var(--s3)) var(--s3);
    padding: 0 var(--s5);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    color: #fff; text-decoration: none;
  }
  .nav__zeichen { display: block; width: 28px; height: 28px; flex: none; border-radius: 7px; }
  .nav__marke   { font-size: 21px; line-height: 1; }

  .nav__item {
    flex-direction: row; justify-content: flex-start; align-items: center;
    gap: var(--s3);
    min-height: 40px; padding: 0 var(--s3);
    border-radius: var(--r-icon);
    font-size: 14px; font-weight: 600;
    color: rgba(255, 255, 255, 0.7);
    transition: background-color 150ms ease, color 150ms ease;
  }
  .nav__item svg { width: 20px; height: 20px; flex: none; }
  .nav__item:hover { background: rgba(255, 255, 255, 0.06); color: #fff; }
  .nav__item.is-active { background: var(--nav-active-bg); color: var(--nav-active); font-weight: 700; }
  /* Der aktive Ort traegt einen Strich im Alpengluehen am Rand. Eine
     hellere Flaeche allein ist auf dem Verlauf unten schwaecher als
     oben — der Strich ist ueberall gleich deutlich. */
  .nav__item.is-active::before {
    content: '';
    position: absolute; left: calc(-1 * var(--s3)); top: var(--s2); bottom: var(--s2);
    width: 3px; border-radius: 0 3px 3px 0;
    background: var(--alpenglut);
  }
  .nav__dot   { display: none; }
  .nav__count {
    display: inline-flex; align-items: center; justify-content: center;
    margin-left: auto; min-width: 20px; height: 20px; padding: 0 var(--s1);
    border-radius: var(--r-pill); background: var(--danger); color: #fff;
    font-size: 11px; font-weight: 800;
  }

  /* Fuss: das Konto und der Klappknopf. Das Konto ist der EINE Weg zu
     den Einstellungen am Laptop — derselbe Baustein wie der Kreis im
     Kopf am Handy. */
  .nav__fuss {
    display: flex; flex-direction: column; gap: var(--s1);
    margin-top: auto;
    padding-top: var(--s3);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
  }
  .acct--leiste { position: relative; }
  .nav__konto {
    display: flex; align-items: center; gap: var(--s3);
    width: 100%; padding: var(--s2);
    border: 0; border-radius: var(--r-row);
    background: transparent; color: #fff;
    font: inherit; text-align: left; cursor: pointer;
    transition: background-color 150ms ease;
  }
  .nav__konto:hover,
  .nav__konto[aria-expanded="true"] { background: rgba(255, 255, 255, 0.08); }
  .avatar.avatar--leiste {
    width: 32px; height: 32px;
    background: rgba(255, 255, 255, 0.14); color: #fff;
    font-size: 12px;
  }
  .nav__kontoText { display: flex; flex-direction: column; min-width: 0; }
  .nav__kontoName {
    font-size: 13px; font-weight: 700; line-height: 1.3;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .nav__kontoSub { font-size: 12px; line-height: 1.3; color: rgba(255, 255, 255, 0.6); }
  /* Das Menue geht nach OBEN auf — unten ist der Bildschirm zu Ende. */
  .acct--leiste .acct__menu {
    top: auto; bottom: calc(100% + var(--s2));
    left: 0; right: auto; min-width: 100%;
  }

  /* Der Klappknopf ist ein Rechteck mit Trennstrich, kein Pfeil: der
     Zurueck-Pfeil einer Unterseite steht gleich daneben im Kopf, und
     zwei gleiche Winkel nebeneinander taten zwei verschiedene Dinge. */
  .nav__klapp {
    display: flex; align-items: center; gap: var(--s3);
    min-height: 36px; padding: 0 var(--s3);
    border: 0; border-radius: var(--r-icon);
    background: transparent; color: rgba(255, 255, 255, 0.55);
    font: inherit; font-size: 13px; font-weight: 600; text-align: left;
    cursor: pointer;
    transition: background-color 150ms ease, color 150ms ease;
  }
  .nav__klapp:hover { background: rgba(255, 255, 255, 0.06); color: #fff; }
  .nav__klapp svg { width: 18px; height: 18px; flex: none; stroke: currentColor; fill: none;
                    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

  /* Die Wechselzeile haengt sichtbar am Gruppe-Tab: eingerueckt auf die
     Hoehe seines Worts, kleiner und leiser — sie gehoert zu ihm, sie ist
     kein fuenftes Ziel. */
  .nav__wechsel:not([hidden]) {
    display: flex; align-items: center; gap: var(--s2);
    min-height: 32px; margin-top: calc(-1 * var(--s1));
    /* Einzug = Rand + Symbolbreite + Luecke des Tabs darueber. Die 20px
       sind die Breite des Tab-Symbols (Geometrie, kein Abstand). */
    padding: 0 var(--s3) 0 calc(var(--s3) * 2 + var(--nav-symbol, 20px));
    border: 0; border-radius: var(--r-icon);
    background: transparent; color: rgba(255, 255, 255, 0.55);
    font: inherit; font-size: 12.5px; font-weight: 600; text-align: left;
    cursor: pointer;
    transition: background-color 150ms ease, color 150ms ease;
  }
  .nav__wechsel:hover { background: rgba(255, 255, 255, 0.06); color: #fff; }
  .nav__wechsel svg { width: 14px; height: 14px; flex: none; stroke: currentColor; fill: none;
                      stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
  body.nav-schmal .nav__wechsel:not([hidden]) { justify-content: center; padding: 0; margin-top: 0; }

  /* Die Gruppen als Liste unter dem Tab (v.35.49.0). Aufgeklappt ersetzt
     sie den Wechselknopf; zugeklappt bleibt der Knopf, denn für Namen
     ist dort kein Platz. */
  body:not(.nav-schmal) .nav__wechsel:not([hidden]) { display: none; }
  body:not(.nav-schmal) .nav__gruppen:not([hidden]) {
    display: flex; flex-direction: column; gap: 2px;
    margin: 0 0 var(--s1);
  }
  body:not(.nav-schmal) .nav__item.hat-gruppenliste .nav__wort:not(.nav__wort--mehrere) { display: none; }
  body:not(.nav-schmal) .nav__item.hat-gruppenliste .nav__wort--mehrere { display: inline; }
  .nav__gruppe {
    display: flex; align-items: center; gap: var(--s2);
    min-height: 32px;
    padding: 0 var(--s3) 0 calc(var(--s3) + var(--s1));
    border-radius: var(--r-icon);
    color: rgba(255, 255, 255, 0.7);
    font-size: 13px; font-weight: 600; text-decoration: none;
    transition: background-color 150ms ease, color 150ms ease;
  }
  .nav__gruppe:hover { background: rgba(255, 255, 255, 0.06); color: #fff; }
  .nav__gruppe.is-aktiv { color: #fff; font-weight: 700; }
  .nav__gruppe.is-aktiv[aria-current] { background: rgba(255, 255, 255, 0.08); }
  .nav__gruppe-zeichen {
    width: 22px; height: 22px; flex: none;
    display: grid; place-items: center;
    border-radius: 6px;
    background: var(--tint, rgba(255, 255, 255, 0.12));
    color: var(--deep, #fff);
    font-size: 9px; font-weight: 800; letter-spacing: 0.02em;
  }
  .nav__gruppe-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* "+ Neue Gruppe": leise — da, wenn man es sucht, aber kein Knopf. */
  .nav__gruppe--neu { color: rgba(255, 255, 255, 0.45); font-size: 12.5px; font-weight: 600; }
  .nav__gruppe--neu .nav__gruppe-zeichen {
    background: transparent;
    border: 1px dashed rgba(255, 255, 255, 0.3);
    color: rgba(255, 255, 255, 0.6);
    font-size: 13px;
  }
  body.nav-schmal .nav__gruppen { display: none; }

  /* ── Zugeklappt ─────────────────────────────────────────────────
     Symbolspalte statt Verschwinden: der Weg zurueck bleibt sichtbar.
     Die Woerter gehen, die Ziele bleiben — und das Konto auch. */
  body.nav-schmal .nav { padding: 0 var(--s2) var(--s3); }
  body.nav-schmal .nav__kopf {
    justify-content: center; padding: 0;
    margin: 0 calc(-1 * var(--s2)) var(--s3);
  }
  body.nav-schmal .nav__marke,
  body.nav-schmal .nav__wort,
  body.nav-schmal .nav__kontoText { display: none; }
  body.nav-schmal .nav__item,
  body.nav-schmal .nav__klapp { justify-content: center; padding: 0; }
  body.nav-schmal .nav__item.is-active::before { left: calc(-1 * var(--s2)); }
  body.nav-schmal .nav__konto { justify-content: center; padding: var(--s2) 0; }
  body.nav-schmal .nav__klapp svg { transform: scaleX(-1); }
  body.nav-schmal .nav__count {
    position: absolute; top: var(--s1); right: var(--s1); margin: 0;
    min-width: 16px; height: 16px; font-size: 10px;
  }
  body.nav-schmal .acct--leiste .acct__menu { left: 0; min-width: 220px; }

  .tvza-route-frame {
    left: var(--leiste);
    bottom: 0;
  }
  .tvza-route-progress { left: var(--leiste); }

  /* Content sits beside the rail; the header pulls itself back out over
     the full width (siehe oben). */
  /* Am Laptop ist die Leiste links, der untere Rand also wieder frei. */
  .has-nav      { padding-bottom: 0; padding-left: var(--leiste); }
  body.has-nav .app  { min-height: 100vh; }
  body.dm-thread .app { height: 100vh; }
  @supports (height: 100dvh) {
    body.has-nav .app  { min-height: 100dvh; }
    body.dm-thread .app { height: 100dvh; }
  }
  .shell__cols  {
    display: grid; grid-template-columns: 1.35fr 1fr; gap: var(--s5);
    max-width: 1160px; margin: 0 auto; padding: 0 var(--s6) var(--s6);
  }
}

/* ── 8. Der Hinweis — the one proactive card ───────────────────────*/
.hint {
  display: flex; align-items: flex-start; gap: var(--s3);
  background: var(--accent-bg);
  border: 1px solid color-mix(in oklab, var(--accent) 18%, var(--border));
  border-radius: var(--r-panel);
  padding: var(--s4) var(--s4);
  animation: hintIn 200ms cubic-bezier(0.2, 0.85, 0.25, 1);
}
.hint__from {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 15px; font-weight: 700; color: var(--accent); flex: none;
}
.hint__text { flex: 1; font-size: 15px; font-weight: 600; line-height: 1.5; }
.hint__x {
  width: 26px; height: 26px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: var(--r-pill);
  background: transparent; color: var(--ink-soft); cursor: pointer;
}
.hint__x:hover { background: var(--surface-2); }

/* ── Versteckter Dateiwaehler ──────────────────────────────────────
   Ein <input type="file"> laesst sich nicht gestalten; bedient wird es
   von einem <label>, das wie ein Knopf aussieht. Das Feld selbst
   bleibt unsichtbar — aber NICHT display:none, sonst ist es fuer
   Tastatur und Screenreader verschwunden. */
.datei-feld {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Ein Knopf, der wie ein Link aussieht (v.35.64.0): "Erneut versuchen",
   "Rückgängig", "Alle auswählen" — neben einem Satz, nicht als Balken. */
.linkknopf {
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit; font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}

/* Nur für Screenreader. */
.nur-vorlesen {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Ein Häkchen mit Satz daneben, gross genug für einen Daumen. */
.check-zeile {
  display: flex; align-items: center; gap: var(--s3);
  min-height: 44px;
  cursor: pointer;
}
.check-zeile input { width: 20px; height: 20px; flex: none; accent-color: var(--accent); }

/* ── Segmentwahl ───────────────────────────────────────────────────
   Fuer eine Frage mit wenigen, sich ausschliessenden Antworten: die
   Zusage zu einem Training, einem Lager oder einer Reise.

   Vorher standen dort drei Knoepfe in voller Breite untereinander. Das
   las sich wie drei Angebote statt wie eine Frage, und es kostete auf
   dem Handy die halbe Bildschirmhoehe fuer eine Entscheidung, die aus
   einem Tippen besteht. Nebeneinander ist ausserdem sichtbar, dass die
   drei zusammengehoeren und sich gegenseitig ausschliessen.

   44px Mindesthoehe: darunter wird ein Segment auf einem Handy zum
   Zielproblem. */
/* Eine Schiene, in der die gewaehlte Antwort liegt — keine Reihe von
   Knoepfen mit Trennstrichen dazwischen. Die Striche waren der Fehler:
   neben einer gefuellten Flaeche trennen sie nichts mehr und sahen aus
   wie ein Balken, der dort verloren steht. Was die Segmente trennt,
   ist die Fuellung selbst. */
.seg {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: var(--r-row);
  background: var(--surface-2);
}
.seg__item {
  flex: 1 1 0; min-width: 0; min-height: 40px;
  padding: 0 var(--s2);
  border: 0;
  border-radius: calc(var(--r-row) - 3px);
  background: transparent; color: var(--ink-soft);
  font: inherit; font-size: var(--text-sm); font-weight: 600;
  cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.seg__item:hover { color: var(--ink); }
.seg__item[aria-pressed="true"] { background: var(--accent); color: #fff; }
.seg__item[aria-pressed="true"]:hover { background: var(--accent-hover); color: #fff; }
.seg__item:disabled { opacity: .5; cursor: default; }
/* Im Dunkeln ist das Akzentblau hell — Weiss darauf war kaum lesbar.
   Dieselbe Schrift wie der Hauptknopf (.btn-primary, .b--primary). */
:root[data-theme="dark"] .seg__item[aria-pressed="true"],
:root[data-theme="dark"] .radio-row label:has(input:checked) { color: var(--brand-navy); }

/* ── Zurück ────────────────────────────────────────────────────────
   Eine Ansicht zu verlassen ist Navigation, keine Handlung. Als
   Knopf ueber die volle Breite sah es aus wie etwas, das man TUT —
   und stand gleichberechtigt neben "Leitung uebergeben", was es
   ganz sicher nicht ist. Oben links, klein, wie ueberall sonst. */
.backlink {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: var(--s1);
  min-height: 32px; padding: 0;
  border: 0; background: none;
  font: inherit; font-size: var(--text-sm); font-weight: 600;
  color: var(--ink-soft); cursor: pointer;
}
.backlink:hover { color: var(--ink); }
.backlink .ic { flex: none; }

/* ── Die Tageszusammenfassung ──────────────────────────────────────
   Dieselbe Karte, aber gestapelt statt nebeneinander: sie traegt
   mehrere Saetze, waehrend der Hinweis immer genau einer ist.

   Das Plaettchen trug bis v.35.65.0 das orange "n" (--brand); seither
   ein leises Info-Zeichen im --accent der Bedienung (Michel: "dezent,
   passend zum blauen Design"). */
.hint--tag { flex-direction: column; align-items: stretch; gap: var(--s3); }
.hint__kopf { display: flex; align-items: center; gap: var(--s2); }
.hint__marke {
  width: 22px; height: 22px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  background: color-mix(in oklab, var(--accent) 14%, var(--surface));
  color: var(--accent);
}
.hint__tag {
  font-size: 11px; font-weight: 700; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-soft);
}
/* Der Schliessknopf sitzt rechts aussen, ohne dafuer eine eigene
   Positionierung zu brauchen. */
.hint--tag .hint__x { margin-left: auto; }
.hint__satz { font-size: 15px; line-height: 1.55; font-weight: 500; }
@keyframes hintIn {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .hint { animation: none; } }

/* ── Schnellzugriff (§4.2 / §6.1) ──────────────────────────────────
   The Start page's four tiles. They keep the .module-tile / .card markup
   the reorder code and the live-tile scripts both bind to, and take the
   kit's tile shape through CSS instead — four across on a phone, 2 x 2
   and left-aligned on a laptop. */
.card-grid--quick { grid-template-columns: repeat(4, 1fr); gap: var(--s2); }
.card-grid--quick .card {
  flex-direction: column; align-items: center; justify-content: flex-start;
  gap: var(--s2); padding: var(--s3) var(--s2); min-height: 0; text-align: center;
  border-radius: var(--r-row);
}
.card-grid--quick .card-icon {
  width: 34px; height: 34px; border-radius: var(--r-icon); margin: 0;
}
.card-grid--quick .card-icon svg { width: 18px; height: 18px; }
.card-grid--quick .card-content h3 {
  font-size: 11px; font-weight: 700; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The subtitle and the live footer do not fit a 4-up phone tile; the
   same numbers are one tap away and most of them are in Heute already. */
.card-grid--quick .card-content p,
.card-grid--quick .tile-live { display: none; }

@media (min-width: 900px) {
  .card-grid--quick { grid-template-columns: repeat(2, 1fr); gap: var(--s3); }
  .card-grid--quick .card {
    flex-direction: row; align-items: flex-start; flex-wrap: wrap;
    gap: var(--s3); padding: var(--s4) var(--s4); min-height: 104px; text-align: left;
  }
  .card-grid--quick .card-icon { width: 36px; height: 36px; }
  .card-grid--quick .card-content { width: calc(100% - 48px); }
  .card-grid--quick .card-content h3 { font-size: 14px; }
  .card-grid--quick .card-content p { display: block; font-size: 12px; color: var(--ink-soft); }
  .card-grid--quick .tile-live { display: block; width: 100%; }
}

/* Section changes retain the shell visually and fade only the page
   content. Browsers without cross-document transitions ignore this. */
@view-transition { navigation: auto; }
.appbar { view-transition-name: tvza-appbar; }
.nav { view-transition-name: tvza-navigation; }
::view-transition-old(root) {
  animation: 90ms ease both tvzaPageOut;
}
::view-transition-new(root) {
  animation: 150ms ease both tvzaPageIn;
}
::view-transition-old(tvza-appbar),
::view-transition-new(tvza-appbar),
::view-transition-old(tvza-navigation),
::view-transition-new(tvza-navigation) {
  animation-duration: 130ms;
}
@keyframes tvzaPageOut {
  to { opacity: 0.82; transform: translateY(-2px); }
}
@keyframes tvzaPageIn {
  from { opacity: 0.82; transform: translateY(3px); }
}
@media (prefers-reduced-motion: reduce) {
  .tvza-route-frame { transition: none; }
  ::view-transition-old(root),
  ::view-transition-new(root),
  ::view-transition-old(tvza-appbar),
  ::view-transition-new(tvza-appbar),
  ::view-transition-old(tvza-navigation),
  ::view-transition-new(tvza-navigation) { animation: none; }
}

/* ══ v.32 Oberflaeche — Anfang ══════════════════════════════════════ */

/* Tiefe kehrt zurueck (§3 neu gefasst). Die alte Regel "keine Schatten, nur
   Rahmen" machte alle Ebenen gleich laut: eine Kachel, ein Dialog und die
   Seite selbst lagen optisch nebeneinander. Jetzt zwei Stufen — eine fuer
   Karten, eine fuer alles, was ueber der Seite liegt. Im Dunkelmodus tragen
   --sh-* nur noch eine Lichtkante, dort macht der Rahmen die Arbeit. */

/* .link-list > .link-row shared this rule with .card/.tile/.link-list > a
   in the original file (legacy class fused with kit classes in one
   comma-selector) — its declarations are duplicated in legacy.css. */
.card,
.tile,
.link-list > a {
  border-radius: 20px;
  border-color: var(--rule-soft, var(--border));
  box-shadow: var(--sh-card);
  transition: transform 180ms cubic-bezier(.22,.61,.36,1),
              border-color 180ms cubic-bezier(.22,.61,.36,1),
              box-shadow 180ms cubic-bezier(.22,.61,.36,1);
}
.card:hover,
.tile:hover,
.link-list > a:hover {
  transform: translateY(-2px);
  border-color: var(--border);
  box-shadow: var(--sh-lift);
}
.card:active, .tile:active { transform: translateY(0) scale(.985); }

.card { padding: var(--s4); gap: var(--s3); }

/* Modulfarbe wird Plaettchen, nicht Kreis. Ein abgerundetes Quadrat liest
   sich als Kategorie, ein Kreis als Person — und die Bereiche sind
   Kategorien. */
.card-icon,
.tile__icon {
  border-radius: 12px;
}
.card-icon { width: 38px; height: 38px; }

/* Abschnittsmarken: klein, gesperrt, ruhig. Sie sollen die Karte darunter
   ankuendigen, nicht mit ihr konkurrieren. */
.section-title,
/* .marke steht weiter oben — die Dublette hier ist entfallen. */

/* Der aktive Tab bekommt eine Flaeche statt nur Farbe — am Handy ist das
   der einzige Ort, an dem man sieht, wo man ist. */
.nav__item {
  border-radius: 12px;
  padding: var(--s2) 2px var(--s1);
  transition: background 180ms cubic-bezier(.22,.61,.36,1),
              color 180ms cubic-bezier(.22,.61,.36,1);
}
.nav__item.is-active,
.nav a[aria-current="page"].nav__item {
  background: var(--nav-active-bg);
}

/* Dialoge liegen ueber der Seite und duerfen das auch zeigen. */
.modal {
  border-radius: 24px;
  box-shadow: var(--sh-lift);
}
.modal-backdrop { backdrop-filter: blur(2px); }

/* Kopfzeile: eine Trennlinie statt einer Kante, damit sie mitschwimmt. */
.appbar {
  border-bottom: 1px solid var(--rule-soft, var(--border));
}

/* Fortschrittsbalken bekommen die gleiche Rundung wie alles andere.
   .kcal-fill (food) shared this rule with .tl-fill (generic tile-prog
   fill) in the original file — its declaration is duplicated in
   feature/food.css. */
.tl-fill { border-radius: var(--r-pill); }


/* ── Einstellungen als gruppierte Liste ──────────────────────────────
   Vorher: ein Dialog, dessen Abschnitte nur durch <hr> getrennt waren —
   alles lag auf einer Flaeche und man musste die Linien lesen, um die
   Gruppen zu finden. Jetzt traegt jede Gruppe ihre eigene Karte; die
   Trenner werden dadurch ueberfluessig. */

#settingsModal .settings-section {
  background: var(--surface);
  border: 1px solid var(--rule-soft, var(--border));
  border-radius: 16px;
  padding: var(--s4) var(--s4);
}
#settingsModal .settings-divider { display: none; }
#settingsModal .settings-layout { display: flex; flex-direction: column; gap: var(--s4); }
#settingsModal .settings-section-title {
  font-size: 11.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-faint, var(--ink-soft));
  margin-bottom: var(--s1);
}

/* ── In der Karte liegt keine zweite Karte (v.35.58.0) ───────────────
   Michel: "Einstellungen können noch überarbeitet werden — das ist ja
   wohl nicht dein Bestes". Jede Zeile trug noch einmal Rahmen und
   Fläche (Erscheinungsbild, Sprache, jeder Bereich), der Hinweis stand
   in Textgrösse (.form-hint hatte gar keine Regel), die Sprachwahl ragte
   am Handy aus der Zeile, und die Bereiche standen am Laptop zu zweit
   nebeneinander, bis "Schliff & Wachs" abgeschnitten war. Jetzt: die
   Karte ist die Gruppe, die Zeilen sind flach und durch Haarlinien
   getrennt, rechts steht, was man bedient. */
#settingsModal .settings-row {
  min-height: 52px;
  padding: var(--s3) 0;
  background: none;
  border: 0;
  border-radius: 0;
}
#settingsModal .settings-row + .settings-row {
  border-top: 1px solid var(--rule-soft, var(--border));
}
#settingsModal .settings-row-label { min-width: 0; font-size: 15px; }
#settingsModal .settings-row .seg { flex: 0 1 320px; }
#settingsModal .settings-select { flex: 0 1 200px; width: auto; min-width: 0; }
#settingsModal .settings-section > .form-hint { margin-top: var(--s1); }
/* Deine Gruppen ordnen (v.35.68.0): Griff zum Ziehen, Pfeile, dazu bei
   der Leitung der Weg in die Einstellungen der Gruppe. */
.gruppen-folge { justify-content: flex-start; }
.gruppen-folge .settings-row-label { flex: 1; }
.gruppen-folge__griff {
  width: 36px; height: 44px; flex: none;
  display: grid; place-items: center;
  border: 0; border-radius: var(--r-icon);
  background: transparent; color: var(--ink-soft);
  cursor: grab; touch-action: none;
}
.gruppen-folge__griff:active { cursor: grabbing; }
.gruppen-folge__griff:focus-visible, .gruppen-folge__pfeil:focus-visible, .gruppen-folge__einst:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.gruppen-folge.is-zieht { background: var(--accent-bg); }
.gruppen-folge__pfeile { display: inline-flex; gap: var(--s1); flex: none; }
.gruppen-folge__pfeil {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink); cursor: pointer;
}
.gruppen-folge__pfeil:disabled { opacity: .35; cursor: default; }
.gruppen-folge__einst {
  flex: none; padding: 0 var(--s2); min-height: 40px;
  border: 0; background: none; color: var(--accent);
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
@media (max-width: 480px) { .gruppen-folge { flex-wrap: wrap; } .gruppen-folge__einst { order: 5; margin-left: calc(var(--s7) + var(--s1)); } }


/* Am Handy steht das Erscheinungsbild über seinen drei Knöpfen — neben
   dem Wort hätten "Automatisch", "Hell" und "Dunkel" keinen Platz. */
@media (max-width: 520px) {
  #settingsModal .settings-row--stapel { flex-direction: column; align-items: stretch; gap: var(--s2); }
  #settingsModal .settings-row--stapel .seg { flex: none; }
}

/* Die Bereiche: dieselben flachen Zeilen, eine Spalte. */
#settingsModal #moduleToggles { display: flex; flex-direction: column; gap: 0; }
#settingsModal #moduleToggles .row--check {
  min-height: 60px;
  padding: var(--s3) 0;
  background: none;
  border: 0;
  border-radius: 0;
}
#settingsModal #moduleToggles .row--check + .row--check {
  border-top: 1px solid var(--rule-soft, var(--border));
}
#settingsModal #moduleToggles .row--check:active { transform: none; }
#settingsModal #moduleToggles > .marke { margin: var(--s4) 0 var(--s1); }
#settingsModal #moduleToggles > .marke:first-child { margin-top: var(--s2); }
#settingsModal .module-toggle-state { display: none; }
#settingsModal .settings-section-head { margin-bottom: 0; }

/* Rechte beim Teilen: zwei Knöpfe in einer Schiene wie .seg statt
   nackter Radioknöpfe. Das Radio bleibt das Bedienelement (Tastatur,
   Vorlesen) und liegt unsichtbar über seinem Knopf. */
.radio-row {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: var(--r-row);
  background: var(--surface-2);
}
.radio-row label {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  min-height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: calc(var(--r-row) - 3px);
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
}
.radio-row input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.radio-row label:has(input:checked) { background: var(--accent); color: #fff; }
.radio-row label:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Am Handy ist ein zentrierter Dialog der falsche Ort: er laesst rundherum
   Rand stehen, den niemand braucht, und der Daumen kommt schlecht an den
   oberen Rand. Ab hier faehrt er als Blatt von unten herein. */
@media (max-width: 599px) {
  #settingsModal.modal-backdrop { align-items: flex-end; padding: 0; }
  #settingsModal .modal {
    max-width: none;
    max-height: 92vh;
    border-radius: 24px 24px 0 0;
    border-bottom: 0;
    padding: var(--s5) var(--s4) calc(var(--s5) + env(safe-area-inset-bottom));
    animation: sheetIn .26s cubic-bezier(.22,.61,.36,1) both;
  }
}
@keyframes sheetIn {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  #settingsModal .modal { animation: none; }
}

/* ══ v.32 Oberflaeche — Ende ════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════
   Der Einheiten-Player.

   Gebaut fuer den Kraftraum: eine Hand am Handy, die andere an der
   Hantel, Finger feucht. Darum ist der Normalfall EIN TIPP auf die
   Zeile — die Vorgabe stimmt ja fast immer. Die Eingabefelder
   erscheinen erst, wenn es anders lief.
   ══════════════════════════════════════════════════════════════════ */

/* ── Fortschritt ───────────────────────────────────────────────────
   Als Leiste, nicht als graue Zeile. Sie ist das, was einen bei der
   Stange haelt, und "2 von 6" in 12 Pixeln grau ist das nicht. */
.fortschritt {
  height: var(--s2);
  background: var(--surface-2);
  border-radius: var(--r-pill);
  overflow: hidden;
  margin-bottom: var(--s4);
}
.fortschritt__fuellung {
  display: block;
  height: 100%;
  width: 0;
  border-radius: var(--r-pill);
  background: var(--accent);
  transition: width 260ms cubic-bezier(.22,.61,.36,1);
}

/* ── Name und Video ────────────────────────────────────────────────
   Das Video gehoert an den Namen. In der Vorlage steht es eine Zeile
   darunter; hier waere das eine Zeile, die man ueberliest. */
.ueb-kopf { display: flex; align-items: center; gap: var(--s3); }
.ueb-kopf .form-title { flex: 1; min-width: 0; margin: 0; }

/* Mit Wort, nicht nur als Dreieck: ein Play-Zeichen allein las Michel
   nicht als "Video dieser Übung" (v.35.50.0). */
.ueb-video {
  flex: none;
  min-height: 36px;
  display: inline-flex; align-items: center; gap: var(--s1);
  padding: 0 var(--s3) 0 var(--s2);
  border-radius: var(--r-pill);
  background: var(--accent-bg);
  color: var(--accent);
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
  transition: background-color 150ms ease;
}
.ueb-video:hover { background: color-mix(in oklab, var(--accent) 18%, var(--surface)); }
.ueb-video svg { fill: currentColor; stroke: none; }

/* ── Der Timer ─────────────────────────────────────────────────────
   Pause nach einem Satz und Übungen auf Zeit (v.35.50.0). Gross genug,
   um ihn aus zwei Metern zu lesen, wenn das Telefon auf der Bank liegt. */
.uhr {
  margin: var(--s3) 0;
  padding: var(--s4);
  border: 1px solid color-mix(in oklab, var(--accent) 35%, var(--border));
  border-radius: var(--r-row);
  background: var(--accent-bg);
}
.uhr__kopf { display: flex; justify-content: space-between; gap: var(--s2); color: var(--accent); font-size: 13px; font-weight: 700; }
.uhr__zeit {
  margin: var(--s2) 0;
  color: var(--ink);
  font-size: clamp(44px, 16vw, 64px);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-align: center;
}
.uhr__leiste { height: 6px; overflow: hidden; border-radius: var(--r-pill); background: color-mix(in oklab, var(--accent) 15%, var(--surface)); }
.uhr__fuellung { display: block; width: 0; height: 100%; background: var(--accent); transition: width 250ms linear; }
.uhr__knoepfe { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s3); }
.uhr__knoepfe .b { flex: 1 1 auto; }
.uhr.is-fertig { border-color: var(--success, var(--accent)); }
.uhr.is-fertig .uhr__zeit { color: var(--success, var(--accent)); }

/* ── Ein Satz ──────────────────────────────────────────────────────*/

.satz--gemacht { border-color: color-mix(in oklab, var(--accent) 32%, var(--border)); }

/* Der Haken ist die ganze Bedienung: gross genug fuer einen Daumen,
   und er sagt durch seine Form, ob der Satz steht. */
.satz__haken {
  flex: none;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border: 1.5px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 14px; font-weight: 800;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;
}
.satz__haken:hover { border-color: var(--ink-soft); }
.satz__haken[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--surface);
}
.satz__haken svg { stroke: currentColor; stroke-width: 2.6; fill: none;
                   stroke-linecap: round; stroke-linejoin: round; }

.satz__wert {
  font-size: 14px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  min-width: 4.5em; text-align: right;
}

/* ── Die andere Trainingswoche ─────────────────────────────────────
   Ein Plan laeuft zwei Wochen, und genau aus dem Nebeneinander liest
   man ab, ob es besser geworden ist. */
.vorwoche {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  padding: var(--s2) 0;
  font-size: 13px;
  border-top: 1px solid var(--rule-soft, var(--border));
}
.vorwoche__tag {
  flex: none; min-width: 4em;
  font-weight: 800; letter-spacing: 0.04em;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.vorwoche__werte { flex: 1; min-width: 0; color: var(--ink); font-variant-numeric: tabular-nums; }
.vorwoche__notiz { flex: none; color: var(--ink-soft); font-style: italic; }

/* ══ Frage, Eingabe, Meldung ═══════════════════════════════════════
   Der gestaltete Ersatz fuer prompt(), confirm() und alert() —
   assets/js/dialog.js. Am Handy ein Blatt von unten, wo der Daumen
   ist; am Laptop eine Karte in der Mitte. */
.frage {
  border: 0; padding: 0; margin: 0;
  max-width: none; max-height: none;
  width: 100%; height: 100%;
  background: transparent;
  display: flex; align-items: flex-end; justify-content: center;
}
.frage:not([open]) { display: none; }
.frage::backdrop { background: oklch(0.2 0.03 250 / 0.45); }
.frage__karte {
  width: 100%; max-width: 440px;
  display: flex; flex-direction: column; gap: var(--s3);
  margin: 0;
  padding: var(--s5) var(--s5) calc(var(--s5) + env(safe-area-inset-bottom));
  background: var(--surface); color: var(--ink);
  border-radius: var(--r-panel) var(--r-panel) 0 0;
  box-shadow: var(--sh-lift);
  /* Ein Dialog mit Eingabefeld (Code eintippen, Gruppe benennen) darf
     nicht hinter der Tastatur enden (v.35.69.0). */
  margin-bottom: var(--tastatur, 0px);
  animation: frageAuf 180ms cubic-bezier(0.2, 0.85, 0.25, 1);
}
.frage__titel { margin: 0; font-size: 17px; font-weight: 800; line-height: 1.3; }
/* pre-line: ein Text mit Absaetzen (Terminkarte: Zeile, Absage, Notiz)
   bleibt in Absaetzen, statt zu einem Block zusammenzulaufen. */
.frage__text  { margin: 0; font-size: 14px; line-height: 1.5; color: var(--ink-soft); white-space: pre-line; }
.frage__feld  { width: 100%; }
/* Ein Einladungscode wird abgelesen und abgetippt — gross und gesperrt,
   damit man ihn Zeichen fuer Zeichen vergleichen kann. */
.frage__feld--gross {
  font-size: 22px; font-weight: 800; letter-spacing: 0.18em;
  text-transform: uppercase; text-align: center;
}
.frage__knoepfe { display: flex; gap: var(--s2); margin-top: var(--s2); }
.frage__knoepfe .b { flex: 1; }
/* Im Dialog ist "Loeschen" die Antwort, nicht ein Nebenknopf: gefuellt. */
.frage .b--danger { background: var(--danger); color: #fff; }
.frage .b--danger:hover { background: color-mix(in oklab, var(--danger) 88%, black); }
@keyframes frageAuf { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (min-width: 900px) {
  .frage { align-items: center; }
  .frage__karte { border-radius: var(--r-panel); padding: var(--s5); }
}
@media (prefers-reduced-motion: reduce) { .frage__karte { animation: none; } }

/* ══ Wahlkarten ════════════════════════════════════════════════════
   Eine Frage mit wenigen Antworten, die man SEHEN soll, bevor man
   waehlt: was fuer eine Gruppe, welche Art von Termin. Vorher war das
   ein Auswahlfeld oder — beim Anlegen einer Gruppe — eine Ziffer, die
   man in ein Browserfenster tippte. */
/* mehrere() in dialog.js: an wen im Chat (v.35.53.0). */
.mehrere {
  display: grid; gap: var(--s2);
  max-height: 50vh; overflow-y: auto;
  margin-block: var(--s3);
}
.mehrere__zeile {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2) var(--s3);
  border: 1.5px solid var(--border); border-radius: var(--r-row);
  background: var(--surface); cursor: pointer;
}
.mehrere__zeile:has(input:checked) { border-color: var(--accent); background: var(--accent-bg); }
.mehrere__zeile input { flex: none; width: 18px; height: 18px; accent-color: var(--accent); }
.mehrere__name { font-weight: 600; }
.mehrere__text { display: block; font-size: 12px; color: var(--ink-soft); }

.wahlkarten { display: grid; gap: var(--s2); }
.wahlkarte {
  display: grid; grid-template-columns: auto 1fr; align-items: center;
  column-gap: var(--s3); row-gap: var(--s1);
  padding: var(--s3) var(--s4);
  border: 1.5px solid var(--border); border-radius: var(--r-row);
  background: var(--surface); color: var(--ink);
  font: inherit; text-align: left; cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.wahlkarte:hover { border-color: var(--ink-soft); }
.wahlkarte[aria-checked="true"] {
  border-color: var(--accent);
  background: color-mix(in oklab, var(--accent-bg) 60%, var(--surface));
}
.wahlkarte__bild {
  grid-row: span 2;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-icon);
  background: var(--tint, var(--surface-2)); color: var(--deep, var(--ink));
}
.wahlkarte__bild svg { width: 24px; height: 24px; fill: none; stroke: currentColor;
                       stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* Das Bild als Plaettchen mit zwei Buchstaben — fuer Gruppen, deren
   Farbe ueber --tint/--deep hereinkommt (dieselbe wie im Kalender). */
.wahlkarte__bild--kuerzel { font-size: 15px; font-weight: 800; letter-spacing: 0.02em; }
.wahlkarte__titel { font-size: 15px; font-weight: 800; }
.wahlkarte__text  { font-size: 13px; line-height: 1.4; color: var(--ink-soft); }
@media (min-width: 900px) {
  .wahlkarten--drei { grid-template-columns: repeat(3, 1fr); }
  .wahlkarten--drei .wahlkarte {
    grid-template-columns: 1fr; align-content: start; row-gap: var(--s2);
    padding: var(--s4);
  }
  .wahlkarten--drei .wahlkarte__bild { grid-row: auto; }
}

/* ══ Wahlknoepfe ═══════════════════════════════════════════════════
   Die kleine Form derselben Idee: eine Reihe Pillen, eine davon
   gewaehlt. Fuer die Art eines Termins — Training, Lager, Rennen, und
   "Eigene", wenn es nichts davon ist. Die Farbe ist die der Art, damit
   man in der Liste spaeter wiedererkennt, was man hier gewaehlt hat. */
.wahl { display: flex; flex-wrap: wrap; gap: var(--s2); }
.wahl__knopf {
  display: inline-flex; align-items: center; gap: var(--s2);
  min-height: 40px; padding: 0 var(--s4);
  border: 1.5px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 14px; font-weight: 700; cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.wahl__knopf::before {
  content: ''; width: 8px; height: 8px; border-radius: var(--r-pill);
  background: var(--deep, var(--ink-soft));
}
.wahl__knopf:hover { border-color: var(--ink-soft); }
.wahl__knopf[aria-checked="true"] {
  border-color: var(--deep, var(--accent));
  background: var(--tint, var(--accent-bg));
}

/* ── Bilder zur Uebung ─────────────────────────────────────────────
   Unter der Kurzinfo, so breit wie die Karte. Zwei nebeneinander, wenn
   Platz ist: bei vier Schritten einer Bewegung liest man sie als Folge. */
.ueb-bilder {
  display: grid; gap: var(--s2);
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}
.ueb-bilder img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--border); border-radius: var(--r-row);
  background: var(--surface-2);
}

/* ── Der Assistent (v.35.53.0) ──────────────────────────────────────
   Eine Pille, die über jeder Seite schwebt (ki-pille.js) — am Handy
   links über der Leiste (rechts sitzen die Erinnerungen), am Laptop
   unten rechts. Ein Tipp öffnet das Gespräch: am Handy ein Blatt über
   der Leiste, am Laptop eine Spalte. Nur im obersten Dokument. */
.ki-pille {
  position: fixed;
  z-index: 45;
  left: 3%;
  bottom: calc(var(--tvza-shell-bottom, calc(var(--nav-hoehe) + env(safe-area-inset-bottom))) + clamp(10px, 2.5vw, 16px));
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  max-width: 60vw;
  min-height: 44px;
  padding: 0 var(--s4) 0 var(--s3);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--r-pill);
  background: var(--brand-gradient);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 8px 22px rgba(15,52,96,.28);
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.ki-pille:hover { transform: translateY(-1px); box-shadow: 0 10px 26px rgba(15,52,96,.34); }
.ki-pille:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.ki-pille .ic { flex: none; color: #ffd27a; }
.ki-pille__name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
body.ki-offen .ki-pille,
body:has(dialog[open]) .ki-pille,
body.global-reminders-open .ki-pille,
/* In einer offenen Unterhaltung liegt unten das Eingabefeld (v.35.61.0). */
body.chat-offen .ki-pille,
body.settings-layer-open .ki-pille { display: none; }
@media (min-width: 900px) {
  .ki-pille { left: auto; right: var(--s5); bottom: var(--s5); max-width: 280px; }
  body.ki-offen .ki-pille { display: none; }
}

.ki-blatt {
  position: fixed;
  z-index: 58;
  left: 0;
  right: 0;
  /* Über der Tastatur (v.35.69.0): --tastatur misst jede Seite selbst
     (tastatur.js), --tvza-shell-bottom setzt der Router, wo er läuft. */
  bottom: max(var(--tvza-shell-bottom, calc(var(--nav-hoehe) + env(safe-area-inset-bottom))), var(--tastatur, 0px));
  display: flex;
  flex-direction: column;
  /* Mit offener Tastatur ist nur der sichtbare Ausschnitt da (--vv-hoehe,
     router.js) — das Blatt passt sich an, statt oben hinauszuragen. */
  max-height: min(78dvh, 640px, calc(var(--vv-hoehe, 100dvh) - var(--s3)));
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: var(--r-panel) var(--r-panel) 0 0;
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 -12px 40px rgba(15,23,42,.22);
}
@media (min-width: 900px) {
  .ki-blatt {
    left: auto;
    right: var(--s5);
    bottom: var(--s5);
    width: min(400px, calc(100vw - 2 * var(--s5)));
    height: min(640px, calc(100dvh - 2 * var(--s6)));
    max-height: none;
    border-bottom: 1px solid var(--border);
    border-radius: var(--r-panel);
  }
}
.ki-blatt__kopf {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s3) var(--s3) var(--s4);
  border-bottom: 1px solid var(--border);
}
.ki-blatt__zeichen {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--brand-gradient);
  color: #ffd27a;
}
.ki-blatt__wer { flex: 1; min-width: 0; }
.ki-blatt__name { font-weight: 800; font-size: 15px; }
.ki-blatt__unter { color: var(--ink-soft); font-size: 12px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ki-blatt__unter:empty { display: none; }
.ki-blatt__zu {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
}
.ki-blatt__zu:hover { background: var(--accent-bg); color: var(--ink); }

.ki-verlauf {
  overscroll-behavior: contain;
  flex: 1;
  min-height: 120px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  padding: var(--s3) var(--s4);
}
.ki-hinweis {
  margin: 0;
  padding: var(--s2) var(--s3);
  border-radius: var(--r-row);
  background: var(--accent-bg);
  color: var(--ink-soft);
  font-size: 12px;
  line-height: 1.45;
}
.ki-nachricht {
  max-width: 88%;
  padding: var(--s2) var(--s3);
  border-radius: var(--r-panel);
  font-size: 14px;
  line-height: 1.45;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.ki-nachricht--ki { align-self: flex-start; background: var(--accent-bg); border-bottom-left-radius: 5px; }
.ki-nachricht--ich { align-self: flex-end; background: var(--accent); color: #fff; border-bottom-right-radius: 5px; }
.ki-nachricht--info { align-self: center; max-width: 100%; color: var(--ink-soft); font-size: 12px; text-align: center; }
.ki-nachricht--warten { color: var(--ink-soft); animation: ki-atmen 1.2s ease-in-out infinite; }
@keyframes ki-atmen { 50% { opacity: .45; } }

.ki-karte {
  display: grid;
  gap: var(--s1);
  padding: var(--s3);
  border: 1.5px solid var(--border);
  border-radius: var(--r-row);
  background: var(--surface);
}
.ki-karte__was { color: var(--ink-soft); font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; }
.ki-karte__titel { font-weight: 700; }
.ki-karte__wann { color: var(--ink-soft); font-size: 13px; }
/* Die vorgeschlagenen Lernkarten (v.35.77.0): jede einzeln zu sehen,
   bevor sie eingetragen werden. Eigenes Scrollen, damit dreissig
   Vokabeln das Gespraech nicht wegschieben. */
.ki-voci {
  list-style: none; margin: var(--s2) 0 0; padding: 0;
  max-height: 14rem; overflow-y: auto; overscroll-behavior: contain;
  border: 1px solid var(--border); border-radius: var(--r-icon);
}
.ki-voci li {
  display: flex; gap: var(--s3); justify-content: space-between;
  padding: var(--s1) var(--s2); font-size: 13px;
}
.ki-voci li + li { border-top: 1px solid var(--border); }
.ki-voci__vorn { font-weight: 600; overflow-wrap: anywhere; }
.ki-voci__hinten { color: var(--ink-soft); text-align: end; overflow-wrap: anywhere; }
.ki-karte__knoepfe { display: flex; gap: var(--s2); margin-top: var(--s2); }
.ki-karte__knoepfe .b { flex: 1; }
.ki-karte__stand { margin-top: var(--s1); color: var(--ink-soft); font-size: 13px; font-weight: 700; }
.ki-karte--erledigt { border-color: var(--accent); }
.ki-karte--erledigt .ki-karte__stand { color: var(--accent); }
.ki-karte--nein { color: var(--ink-soft); font-size: 13px; border-style: dashed; }
/* Eine Nachricht über den Assistenten (v.35.67.0): An, Von, Text — und
   erst "Senden" schickt genau diesen Text. */
.ki-karte__feld { display: grid; grid-template-columns: 3.2em minmax(0, 1fr); gap: var(--s2); align-items: baseline; font-size: 14px; }
.ki-karte__label { color: var(--ink-soft); font-size: 12px; font-weight: 700; }
.ki-empf-liste { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--s1); }
.ki-empf--fehlt { color: var(--danger); }
.ki-empf--ok::after { content: " ✓"; color: var(--success, var(--accent)); }
.ki-empf--nein { color: var(--danger); }
.ki-empf__wahl { display: grid; gap: var(--s1); font-size: 13px; }
.ki-karte__nachricht { white-space: pre-wrap; overflow-wrap: anywhere; padding: var(--s2) var(--s3); border-radius: var(--r-row); background: var(--surface-2); }
.ki-karte__eingabe { min-height: 96px; resize: vertical; font-size: 16px; }
.ki-karte__hinweis { color: var(--ink-soft); font-size: 12.5px; }
.ki-karte__link { color: var(--accent); font-size: 13px; font-weight: 700; text-decoration: none; }
.ki-karte--nachricht .ki-karte__knoepfe { flex-wrap: wrap; }


.ki-vorschlaege {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  padding: 0 var(--s4) var(--s2);
}
.ki-vorschlaege:empty { display: none; }
.ki-vorschlag {
  padding: var(--s1) var(--s3);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.ki-vorschlag:hover { border-color: var(--accent); background: var(--accent-bg); }

.ki-eingabe {
  flex: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-auto-flow: column;
  gap: var(--s2);
  align-items: end;
  padding: var(--s2) var(--s3) var(--s1) var(--s4);
  border-top: 1px solid var(--border);
}
.ki-feld {
  width: 100%;
  min-height: 44px;
  max-height: 120px;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--border);
  border-radius: var(--r-row);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  line-height: 1.35;
  resize: none;
}
.ki-feld:focus { outline: none; border-color: var(--accent); }
.ki-senden {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}
.ki-blatt.is-arbeitet .ki-senden { opacity: .5; cursor: progress; }
/* Diktieren (v.35.59.0): neben dem Senden, pulsiert, solange es zuhört. */
.ki-eingabe:has(.ki-mikro) { grid-template-columns: minmax(0, 1fr) auto auto; }
.ki-mikro {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-soft);
  cursor: pointer;
}
.ki-mikro:hover { color: var(--ink); border-color: var(--ink-soft); }
.ki-mikro.is-hoert {
  border-color: var(--danger);
  background: var(--danger);
  color: #fff;
  animation: kiHoert 1.2s ease-in-out infinite;
}
@keyframes kiHoert {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--danger) 45%, transparent); }
  50% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--danger) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .ki-mikro.is-hoert { animation: none; } }
.ki-stufe {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s1) var(--s4) var(--s3);
  color: var(--ink-soft);
  font-size: 12px;
  cursor: pointer;
}
.ki-stufe input { accent-color: var(--accent); }
.ki-stufe__rest:empty { display: none; }
@media (prefers-reduced-motion: reduce) {
  .ki-pille { transition: none; }
  .ki-nachricht--warten { animation: none; }
}

/* Der Assistent einer Gruppe trägt ihre Farbe (v.35.55.0) — der
   persönliche bleibt navy. --tint und --deep kommen aus gruppenStil()
   (gruppenwahl.js), dieselben wie im Kalender und im Gruppenwechsel. */
.ki-pille.is-gruppe,
.ki-blatt__zeichen.is-gruppe {
  background: var(--tint);
  color: var(--deep);
  border-color: transparent;
}
.ki-pille.is-gruppe .ic,
.ki-blatt__zeichen.is-gruppe { color: var(--deep); }

/* Die Reihe schrumpft nicht (v.35.60.0): im senkrechten Blatt drückte ein
   langes Gespräch sie zusammen, die Knöpfe waren halb abgeschnitten und
   die Reihe bekam einen eigenen Scrollbalken (Michels Bildschirm).
   Seitlich wischen bleibt, ohne sichtbaren Balken. */
.ki-wahlrahmen {
  --ki-wahl-pfeil: 28px;
  position: relative;
  flex: none;
  border-bottom: 1px solid var(--border);
}
.ki-wahl {
  flex: none;
  display: flex;
  gap: var(--s2);
  padding: var(--s2) var(--s4);
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  scroll-behavior: smooth;
}
.ki-wahl::-webkit-scrollbar { display: none; }
.ki-wahl__pfeil { display: none; }
.ki-wahl__knopf {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  flex: none;
  min-height: 34px;
  max-width: 200px;
  white-space: nowrap;
  padding: var(--s1) var(--s3) var(--s1) var(--s1);
  border: 1.5px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.ki-wahl__knopf[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-bg); }
.ki-wahl__zeichen {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: var(--r-pill);
  background: var(--brand-gradient);
  color: #ffd27a;
  font-size: 10px;
  font-weight: 800;
}
.ki-wahl__zeichen .ic { width: 14px; height: 14px; }
.ki-wahl__zeichen { flex: none; }
.ki-wahl__knopf > span:last-child { overflow: hidden; text-overflow: ellipsis; }
.ki-wahl__knopf.is-gruppe .ki-wahl__zeichen { background: var(--tint); color: var(--deep); }

/* Am Laptop war nicht erkennbar, dass rechts weitere Assistenten liegen.
   Pfeile und Verlauf erscheinen nur bei echtem Ueberlauf; am Handy bleibt
   die Reihe eine ungestoerte Wischflaeche. */
@media (min-width: 900px) {
  .ki-wahlrahmen.hat-ueberlauf .ki-wahl {
    padding-inline: calc(var(--s4) + var(--ki-wahl-pfeil));
  }
  .ki-wahlrahmen.hat-ueberlauf::before,
  .ki-wahlrahmen.hat-ueberlauf::after {
    content: '';
    position: absolute;
    z-index: 1;
    top: 0;
    bottom: 0;
    width: calc(var(--ki-wahl-pfeil) + var(--s3));
    pointer-events: none;
  }
  .ki-wahlrahmen.hat-links::before {
    left: 0;
    background: linear-gradient(90deg, var(--surface) 58%, transparent);
  }
  .ki-wahlrahmen.hat-rechts::after {
    right: 0;
    background: linear-gradient(270deg, var(--surface) 58%, transparent);
  }
  .ki-wahlrahmen.hat-ueberlauf .ki-wahl__pfeil {
    position: absolute;
    z-index: 2;
    top: 50%;
    display: grid;
    place-items: center;
    width: var(--ki-wahl-pfeil);
    height: var(--ki-wahl-pfeil);
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-icon);
    background: var(--surface);
    color: var(--ink);
    cursor: pointer;
    transform: translateY(-50%);
  }
  .ki-wahl__pfeil--links { left: var(--s2); }
  .ki-wahl__pfeil--rechts { right: var(--s2); }
  .ki-wahl__pfeil:disabled { opacity: .38; cursor: default; }
}

/* ── Formatierter Text (v.35.60.0, formatierung.js) ─────────────────
   Antworten des Assistenten und Nachrichten im Chat: Absätze, Listen,
   fett, kursiv, Code. Die Blasen stehen auf pre-wrap — der Inhalt hier
   bringt seine Umbrüche als <br> und <p> mit. */
.fmt { white-space: normal; overflow-wrap: anywhere; }
.fmt p { margin: 0; }
.fmt > * + * { margin-top: var(--s2); }
.fmt ul, .fmt ol { margin-block: 0; padding-left: var(--s5); }
.fmt li + li { margin-top: 2px; }
.fmt li.fmt-tief { margin-left: var(--s4); list-style-type: circle; }
.fmt strong { font-weight: 750; }
.fmt code {
  padding: 0 3px;
  border-radius: 4px;
  background: color-mix(in srgb, currentColor 10%, transparent);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92em;
}

/* Die Auskunft "Warum fehlt eine Gruppe?" (v.35.70.6): Text zum Lesen und
   Verschicken, auch auf einem Handy ohne Konsole. */
.gruppen-diagnose {
  margin: var(--s2) 0 0;
  padding: var(--s3);
  border: 1px solid var(--border);
  border-radius: var(--r-row);
  background: var(--surface-2);
  color: var(--ink);
  font-size: var(--text-xs);
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  user-select: text;
}
