/* ============================================================
   Caltrix App CSS — Design-Tokens + Komponenten
   Quelle der Tokens: mockup/styles/tokens.css
   Quelle der Komponenten: mockup/styles/shared.css
   ============================================================ */

/* ── Design Tokens ── */
:root {
  --primary:      #1f628e;
  --primary-mid:  #2a7aad;
  --primary-dark: #195170;
  --accent:       #e09d71;
  --accent-dark:  #c07a45;
  --green:        #7ad180;
  --cream:        #ecdcc8;
  --danger:       #e05353;
  --warning:      #f59e0b;

  --bg:      #fdfcfb;
  --surface: #f8f4ef;
  --white:   #ffffff;

  --text:    #1a2e3b;
  --muted:   #6c869e;
  --border:  #e4d9ce;

  --fh: 'DM Sans', system-ui, sans-serif;
  --fb: 'Lora', Georgia, serif;

  --r-xs:   4px;
  --header-h: 56px;
  --r-sm:   8px;
  --r-md:   12px;
  --r-lg:   16px;
  --r-full: 9999px;

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.05), 0 1px 2px rgba(0,0,0,0.04);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.09), 0 1px 4px rgba(0,0,0,0.05);

  /* Semantische Tokens (zuvor verstreut hartkodiert — Werte unverändert).
     Quelle gespiegelt in mockup/styles/tokens.css. */
  --primary-light:  #e6f0f8;   /* aktive Nav, Primary-Pills, Hover-Flächen */
  --primary-border: #c3ddf0;   /* Rahmen auf Primary-Tints (z. B. Admin-Tag) */
  --ring:           rgba(31,98,142,0.10); /* Fokus-/Aktiv-Ring */

  --success:        #2d8a37;
  --success-bg:     #f0faf0;
  --success-border: #b4e6b8;
  --danger-bg:      #fdf2f2;
  --danger-border:  #f8c5c5;
  --warning-text:   #9a4a0f;
  --warning-bg:     #fffbeb;
  --warning-border: #fcd34d;
  --expert:         #6d28d9;
  --expert-bg:      #f5f0ff;
  --accent-bg:      #fef3e8;   /* Advanced-Level-Fläche */
  --accent-border:  #f8d8b8;   /* Rand auf --accent-bg */

  /* Hinweis-Meldung. Stand bis zur Token-Runde hartkodiert in `.alert-info` und
     leuchtete darum im Dunkelmodus weiter hellblau. */
  --info:           #1e40af;
  --info-bg:        #eff6ff;
  --info-border:    #bfdbfe;
  /* Text der Basic-Stufe auf `--primary-light`. Ebenfalls hartkodiert gewesen:
     ein dunkles Blau, das im Dunkelmodus auf dunklem Grund verschwand. */
  --level-basic:    #1a5a8a;

  /* ── Markenzeichen (2×2-Raster) ──
     Eigene Tokens und BEWUSST nicht `--primary`/`--accent`: Das Zeichen muss in
     App und auf caltrix.de identisch aussehen, `--primary` dagegen überschreibt
     jeder White-Label-Mandant per Inline-Style auf <body>. Hingen die Felder an
     `--primary`, trüge ein Mandant mit eigener Farbe ein umgefärbtes Caltrix-
     Zeichen — genau der Bruch, den das Logo-Dokument ausschließt. */
  --brand-mark:        #163A5F;   /* drei Felder, Tiefblau */
  --brand-mark-accent: #E8A33D;   /* viertes Feld, Amber */

  color-scheme: light;
}

/* Tenant-Branding überschreibt --primary */
/* (wird per Inline-Style auf <body> gesetzt) */

/* ── Dark Mode ──
   Phase 1: vollständiges Variablen-Set, app-weit lesbar. Visuelles Feintuning
   (z. B. Akzent-Pastelltöne) darf in einer späteren Iteration folgen. Aktiviert
   über .dark auf <html> (Anti-Flicker-Inline-Script im Layout-<head>). */
html.dark {
  --bg:      #14181c;
  --surface: #1b2127;
  --white:   #232b32;   /* „erhabene" Fläche: Karten, Inputs, Header */

  --text:    #e7eef4;
  --muted:   #93a6b8;
  --border:  #313b44;

  --primary-light:  rgba(84,145,184,0.18);
  --primary-border: rgba(84,145,184,0.38);
  --ring:           rgba(132,179,207,0.30);

  --success:        #5fbf6a;
  --success-bg:     rgba(95,191,106,0.13);
  --success-border: rgba(95,191,106,0.32);
  --danger-bg:      rgba(224,83,83,0.15);
  --danger-border:  rgba(224,83,83,0.36);
  --warning-text:   #e0a44a;
  --warning-bg:     rgba(245,158,11,0.13);
  --warning-border: rgba(245,158,11,0.32);
  --expert:         #b794f6;
  --expert-bg:      rgba(124,58,237,0.18);
  --accent-bg:      rgba(224,157,113,0.15);
  --accent-border:  rgba(224,157,113,0.34);

  --info:           #93c5fd;
  --info-bg:        rgba(59,130,246,0.14);
  --info-border:    rgba(59,130,246,0.34);
  /* Aufgehellt: der Grund ist hier `--primary-light` über `--white`, also dunkel. */
  --level-basic:    #9ecbea;

  /* Die inverse Fassung des Zeichens (Logo-Dokument: „dunkle App-Leiste →
     invers"): die drei Felder werden weiß, das vierte bleibt Amber. Damit trägt
     der Dunkelmodus dieselbe Geometrie und dasselbe Farbpaar. */
  --brand-mark: #ffffff;

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.40), 0 1px 2px rgba(0,0,0,0.30);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.50), 0 1px 4px rgba(0,0,0,0.35);

  color-scheme: dark;
}

/* ── Base ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 16px; }
body {
  font-family: var(--fh);
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
a { color: inherit; }
img, svg { display: block; }
/* Ein Bild darf seinen Kasten nie sprengen. Betrifft vor allem das, was nicht
   aus dem Layout kommt: Modul-Logos aus fremden Quellen und der Fließtext eines
   Medien-Bausteins, den die Redaktion pflegt. Ohne die Regel schiebt ein
   einziges 1200-px-Bild die ganze Seite zur Seite. `height: auto` hält dabei das
   Seitenverhältnis, wenn nur die Breite begrenzt wird. */
img { max-width: 100%; height: auto; }

/* ── Tastaturfokus ──
   Eine Regel für alles, was von sich aus fokussierbar ist. Vorher hing der
   Fokus an zehn Einzelregeln, und die trafen ausschließlich Eingabefelder:
   Knöpfe, Nav-Links, Reiter, Menüeinträge und die Bottom-Navigation hatten
   gar keinen. Dort blieb der Ring des Browsers stehen, der auf einer
   `--primary`-gefüllten Fläche kaum zu sehen ist.

   `:focus-visible` und nicht `:focus`: der Ring gehört der Tastatur. Nach
   einem Mausklick auf einen Knopf will ihn niemand sehen, und genau deshalb
   wurde er früher pauschal abgeschaltet.

   Eingabefelder überschreiben das weiter unten mit ihrer eigenen Variante
   (Rahmenfarbe plus `--ring`-Schatten); deren Selektoren sind spezifischer und
   gewinnen. */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
/* Auf gefüllten Flächen liegt der Ring sonst Kante an Kante auf der Füllung. */
.btn-primary:focus-visible,
.user-avatar-btn:focus-visible { outline-offset: 3px; }

/* ── Sprungmarke ──
   Erster fokussierbare Punkt jeder Seite. Unsichtbar, bis die Tastatur ihn
   erreicht — dann springt sie über Kopfzeile, Navigation und Aktionen hinweg
   direkt in den Inhalt. */
.skip-link {
  position: absolute;
  left: 8px;
  top: -100px;
  z-index: 300;
  padding: 10px 16px;
  background: var(--white);
  color: var(--primary);
  border: 1px solid var(--primary);
  border-radius: var(--r-sm);
  font-size: 0.875rem;
  font-weight: 700;
  text-decoration: none;
  box-shadow: var(--shadow-md);
  transition: top 0.15s;
}
.skip-link:focus { top: 8px; }

/* Das Sprungziel selbst bekommt keinen Ring: es ist ein Bereich, kein
   Bedienelement, und der Ring um den halben Bildschirm verwirrt mehr als er
   hilft. Fokussierbar bleibt es, damit die Tastatur wirklich dort weitermacht. */
.main-content:focus { outline: none; }

/* Nur für Screenreader. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── Site Header ── */
.site-header {
  position: sticky; top: 0; z-index: 100;
  /* Die Seitenleiste hängt darunter und braucht die Höhe. Eine Zahl an zwei
     Stellen wäre eine Zahl, die auseinanderläuft. */
  --header-h: 56px;
  background: var(--white);
  border-bottom: 1px solid var(--border);
  height: 56px;
  flex-shrink: 0;
}
.site-header__inner {
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 32px;
  height: 100%;
  display: flex;
  align-items: center;
  gap: 32px;
  /* Bezugsrahmen für das „Mehr"-Menü der Top-Nav, das außerhalb der beschnittenen
     Leiste hängen muss. */
  position: relative;
}

/* Mandanten-Logo neben der Wortmarke. Es kommt aus dem Upload des Kunden, ist
   also beliebig breit — auf dem Telefon schöbe ein Querformat sonst Glocke,
   Hilfe und Profil aus der Kopfzeile. Höhe führt, die Breite ist gedeckelt. */
.tenant-logo { height: 28px; width: auto; max-width: 128px; object-fit: contain; margin-left: -16px; flex-shrink: 0; }

/* ── Logo ── */
/* Die Wortmarke, seit dem 2026-09-04 in der eingetragenen Fassung.
   „Caltrix" ist als kombinierte Wort-/Bildmarke in Farbe eingetragen (DPMA
   30 2026 245 801), und damit ist der Satz der Wortmarke keine Geschmacksfrage
   mehr: Versalien, DM Sans 600, Laufweite +0,055 em, Markenblau. Vorher stand
   sie in DM Sans 800 mit negativer Laufweite und in `--primary`, also im
   Oberflächenblau, das jeder White-Label-Mandant überschreibt. Genau das war
   der Fehler: Der Schriftzug wäre bei einem Mandanten mit eigener Primärfarbe
   in dessen Farbe erschienen.

   Die Farbe kommt deshalb aus `--brand-mark`, derselben Quelle wie das Zeichen
   daneben, und kippt im Dunkelmodus mit ihm auf Weiß. Versalien über
   `text-transform` und nicht im Text: Im DOM steht weiter „Caltrix", und die
   Vorlesehilfe liest einen Namen und keine Buchstabenfolge. Vorgaben in
   `docs/logos/LIESMICH.md`. */
.site-logo {
  display: flex; align-items: center; gap: 9px;
  color: var(--brand-mark);
  font-weight: 600;
  font-size: 1.0625rem;
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: 0.055em;
  flex-shrink: 0;
  white-space: nowrap;
}

/* ── Top Navigation ── */
.topnav {
  display: flex; align-items: center; gap: 2px;
  flex: 1;
  /* `min-width: 0` hebt das Flex-Minimum auf, sonst wächst die Leiste über die
     Kopfzeile hinaus und schiebt die Aktionen rechts hinaus. Ein Auffangmenü
     braucht sie nicht mehr: Die erste Zeile trägt höchstens fünf Einträge, und
     die hängen an Rollen statt an gebuchten Produkten. */
  min-width: 0;
}
.topnav__link {
  font-size: 0.875rem; font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  padding: 7px 14px;
  border-radius: var(--r-sm);
  transition: color 0.15s, background 0.15s;
  white-space: nowrap;
  flex-shrink: 0;
}
.topnav__link:hover { color: var(--text); background: var(--surface); }
.topnav__link.active { color: var(--primary); font-weight: 600; background: var(--primary-light); }

/* ── Header Actions ── */
.header-actions {
  display: flex; align-items: center; gap: 6px;
  margin-left: auto;
}
.icon-btn {
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px;
  border: none; background: none;
  color: var(--muted);
  border-radius: var(--r-sm);
  cursor: pointer;
  position: relative;
  transition: background 0.15s, color 0.15s;
}
.icon-btn:hover { background: var(--surface); color: var(--text); }
/* Ungelesen-Abzeichen an der Glocke. Stand doppelt: einmal hier und einmal als
   Inline-`<style>` im Lerner-Layout, das diese Regel überschrieb. Die
   ausgelieferte Fassung war also die dortige, und die steht jetzt hier.

   `min-width` plus Polsterung statt fester Breite, denn der Inhalt ist mal „3"
   und mal „9+". Der Ring liegt als `box-shadow` an, nicht als `border`: ein
   Rahmen zählt zur Kastengröße und drückte das Abzeichen aus der Rundung. */
.notif-badge {
  position: absolute; top: -3px; right: -3px;
  min-width: 16px; height: 16px; padding: 0 4px;
  background: var(--danger); color: #fff;
  font-family: var(--fh);
  font-size: 0.625rem; font-weight: 700; line-height: 16px;
  text-align: center;
  border-radius: var(--r-full);
  box-shadow: 0 0 0 2px var(--white);
}
.user-avatar-btn {
  display: flex; align-items: center; gap: 6px;
  background: none; border: none; cursor: pointer;
  padding: 4px 8px 4px 4px;
  border-radius: var(--r-sm);
  transition: background 0.15s;
}
.user-avatar-btn:hover { background: var(--surface); }
.user-avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--primary);
  color: white;
  font-size: 0.6875rem; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  letter-spacing: 0.03em;
}
/* Dieselbe Rundung für das Foto. `object-fit: cover` ist hier nur der Gürtel:
   Zugeschnitten wird beim Ablegen (`App\Support\Avatar`), das Bild ist also
   bereits quadratisch. Ein schmaler Rand hebt ein helles Foto vom hellen Grund
   ab, ohne dass es wie ein Rahmen aussieht. */
.user-avatar--photo,
.comm-avatar--photo {
  /* `display:block` überschreibt das `flex` der Grundregel: Das gilt dem
     Kürzel, das darin zentriert steht, und ein Bild braucht es nicht. */
  display: block;
  object-fit: cover;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
}

/* Profilfoto ändern (nur auf der eigenen Profilseite). */
.avatar-edit { display: flex; flex-direction: column; align-items: center; gap: 8px; margin-bottom: 16px; }
.avatar-edit__form { margin: 0; }
/* Der Knopf IST das Label: Ein `input[type=file]` sieht in jedem Browser anders
   aus und in keinem gut. Das Feld liegt darin und ist mit `.sr-only` verborgen,
   nicht mit `display:none`, denn sonst wäre es auch für die Tastatur weg. */
.avatar-edit__pick { cursor: pointer; }
.avatar-edit__remove { font-size: 0.75rem; color: var(--muted); }
.avatar-edit__remove:hover { color: var(--danger); }
.avatar-edit__hint { font-size: 0.6875rem; color: var(--muted); margin: 0; text-align: center; }
.admin-tag {
  font-size: 0.6875rem; font-weight: 700;
  background: var(--primary-light); color: var(--primary);
  padding: 2px 8px; border-radius: var(--r-full);
  letter-spacing: 0.025em;
  border: 1px solid var(--primary-border);
}

/* ── Sub Navigation (zweite Zeile) ── */
.sub-nav {
  background: var(--white);
  border-bottom: 1px solid var(--border);
  padding: 0 32px;
  /* Bezugsrahmen für die Verlaufskante rechts. */
  position: relative;
}
/* Die Kante sagt, dass die Zeile weitergeht. Auf dem Telefon ist sie der
   einzige Hinweis darauf, denn die Bildlaufleiste ist verborgen und das System
   zeichnet dort keine. `pointer-events: none`, sonst schluckte sie den Griff
   auf den letzten Eintrag. */
.sub-nav::after {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 1px;
  width: 28px;
  background: linear-gradient(to right, transparent, var(--white));
  pointer-events: none;
}
.sub-nav__inner {
  max-width: 1440px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 0;
  /* EINE Zeile, immer. Sie trägt höchstens sieben Einträge und passt damit auf
     dem Schreibtisch von selbst; auf dem Telefon wird gewischt (siehe unten).
     Umbrechen darf sie nicht: Eine Zeile, die je nach Seite ein- oder zweizeilig
     ist, verschiebt den Inhalt bei jedem Seitenwechsel senkrecht.

     Trennstriche zwischen Sinngruppen gibt es nicht mehr. Sie waren eine
     unbenannte dritte Ebene: Sie ordneten etwas, das sie nicht benannten. */
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
}
.sub-nav__inner::-webkit-scrollbar { display: none; }
.sub-nav__link { scroll-snap-align: start; }
.sub-nav__badge {
  display: inline-block;
  min-width: 16px;
  margin-left: 5px; padding: 1px 5px;
  border-radius: 999px;
  background: var(--primary); color: #fff;
  font-size: 0.625rem; font-weight: 700; line-height: 1.4;
  text-align: center;
}
/* Dritte Ebene: die Unter-Navigation innerhalb eines Produkts. Sie sitzt
   optisch tiefer als die zweite Zeile, damit man ihr ansieht, dass sie zu der
   Seite darunter gehört und nicht zur Zeile darüber. */
.sub-nav--nested { background: var(--surface); }
.sub-nav--nested .sub-nav__link { padding-top: 9px; padding-bottom: 9px; }
.sub-nav__link {
  font-size: 0.875rem; font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  padding: 12px 16px;
  border-bottom: 2px solid transparent;
  transition: color 0.15s, border-color 0.15s;
  white-space: nowrap;
}
.sub-nav__link:hover { color: var(--text); }
.sub-nav__link.active { color: var(--primary); border-bottom-color: var(--primary); font-weight: 600; }

/* ── Segmented Control: die dritte Ebene, auf der Seite ──
   Zwei bis vier Optionen über der Überschrift. Bewusst keine vierte Leiste
   unter der Kopfzeile: Die gehörte optisch zur Navigation über alles, obwohl
   sie nur zu dieser einen Seite gehört, und sie schöbe den Inhalt bei jedem
   Seitenwechsel um ihre Höhe nach unten.

   Nur vorhandene Tokens, keine neuen Farben: die Fläche ist `--surface`, die
   gewählte Option `--white` mit der kleinen Schatten-Stufe, damit sie wie ein
   angehobenes Blatt liegt statt wie ein eingefärbter Knopf. */
.segmented {
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 0 0 24px;
  padding: 3px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  /* Die Reihe ist so breit wie ihre Optionen und nicht so breit wie die Seite:
     Ein Segmented Control über 1280 px läse sich als Werkzeugleiste. */
  width: fit-content;
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
}
.segmented::-webkit-scrollbar { display: none; }
.segmented__item {
  flex-shrink: 0;
  scroll-snap-align: start;
  padding: 7px 16px;
  /* Bezugsrahmen für den Schatten der Beschriftung, siehe unten. */
  position: relative;
  font-size: 0.875rem; font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  background: none;
  border: none;
  border-radius: var(--r-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}
/* Die gewählte Option ist fett, und fett ist breiter. Ohne Gegenmaßnahme wächst
   sie beim Anklicken um ein paar Pixel und schiebt ihre Nachbarn zur Seite: Die
   Reihe zappelt bei jedem Wechsel, und eine Option, die eben noch unter dem
   Zeiger lag, liegt es nicht mehr.

   Deshalb steht die Beschriftung ein zweites Mal in der Option, fett, unsichtbar
   und ohne Höhe. Sie zählt zur Mindestbreite und sonst zu nichts, also ist der
   Kasten immer so breit wie sein fetter Zustand. `attr()` liest den Text aus dem
   Markup — die Blade-Vorlagen schreiben ihn als `data-label` mit. */
.segmented__item::after {
  content: attr(data-label);
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: 600;
  pointer-events: none;
}
.segmented__item:hover { color: var(--text); }
.segmented__item.is-active,
.segmented__item.active {
  background: var(--white);
  color: var(--primary);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}
/* Die zweite Reihe: was ein Produkt an eigenen Masken mitbringt.
   Sie ist eine Ebene tiefer und sieht seither auch danach aus. Als zweite Reihe
   Pillen war sie so laut wie die Reihe darüber, und zwei gleich laute Reihen
   übereinander lesen sich als eine zerrissene: Man sah nicht, welche zum Menü
   gehört und welche zur Seite.

   Deshalb hier nichts Gefülltes: kleinere Schrift, kein Grund, und das Aktive
   trägt einen Unterstrich in Textfarbe statt einer blauen Pille. Der Strich
   sitzt auf der Trennlinie der Reihe und schneidet sie an genau der Stelle
   durch, an der man steht. */
.segmented--sub {
  background: none;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  padding: 0;
  gap: 2px;
  margin-bottom: 24px;
}
/* Sechzehn Pixel unter das Segmented Control: nah genug, dass die beiden Reihen
   zusammengehören, weit genug, dass sie nicht eine sind. (Die Reihe darüber
   trägt 24 px Abstand nach unten.) Steht die zweite allein — Brotkrumen im
   Pfad-Editor, im Verlauf —, behält sie den normalen Abstand zum Inhalt. */
.segmented + .segmented--sub { margin-top: -8px; }
.segmented--sub .segmented__item,
.segmented--sub .sub-nav__link {
  padding: 7px 10px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--muted);
  background: none;
  border: none;
  border-radius: 0;
  /* Der Unterstrich liegt AUF der Trennlinie der Reihe und nicht darüber:
     `-1px` schiebt ihn über die eine Linie des Elternteils. */
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  flex-shrink: 0;
  white-space: nowrap;
}
.segmented--sub .segmented__item:hover,
.segmented--sub .sub-nav__link:hover { color: var(--text); }
.segmented--sub .segmented__item.is-active,
.segmented--sub .segmented__item.active,
.segmented--sub .sub-nav__link.active {
  background: none;
  box-shadow: none;
  color: var(--text);
  font-weight: 600;
  /* Textfarbe und nicht `--primary`: Die Reihe darüber trägt das Blau, und zwei
     blaue Stellen übereinander streiten darum, welche gerade gilt. */
  border-bottom-color: var(--text);
}

/* Die Spalte, in der eine Seite steht. Sie umfasst die Reiter der dritten Ebene
   UND den Inhalt, damit beide dieselbe linke Kante haben; eine Seite mit eigener
   schmaler Spalte um nur den Inhalt herum ließ die Reiter 168 px daneben stehen.
   Ohne Angabe ist sie so breit wie der Inhaltsbereich und kostet nichts. */
.page-column { width: 100%; margin: 0 auto; }
.page-column--narrow  { max-width: 880px; }
.page-column--reading { max-width: 720px; }

/* ── Main Content ── */
/* Die Spalte neben der Seitenleiste: Inhalt und Fußleiste übereinander
   (2026-09-02). Sie trägt die Breite, die der Fuß braucht — von der rechten Kante
   der Leiste bis an den Bildschirmrand — während die Inhaltsspalte darin bei ihren
   1280 px bleibt und mittig steht.

   `min-width: 0` ist tragend: Ein Flex-Element misst von sich aus mindestens so
   viel wie sein Inhalt, und eine breite Tabelle schöbe sonst die Seitenleiste aus
   dem Bild. */
.app-main {
  flex: 1;
  min-width: 0;
  align-self: stretch;
  display: flex;
  flex-direction: column;
}

.main-content {
  /* Das Innenmaß steht als Variable, weil das untere Polster zugleich der Abstand
     zur Fußleiste ist: Die hält von sich aus keinen. Dieselbe Zahl an zwei Stellen
     liefe auseinander, sobald eine Bruchstelle das Maß ändert. */
  --content-pad: 32px;
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--content-pad);
  /* Wächst in der Spalte, damit die Fußleiste auch unter einer Seite mit drei
     Zeilen unten sitzt und nicht in der Bildmitte hängt. */
  flex: 1;
  width: 100%;
}

/* Die zentrierte Hülle der Seiten OHNE Anmeldung (`layouts.guest`,
   `layouts.public`). Die Breite je Seite kommt über `--shell-width`, das
   Innenmaß bleibt am Layout, denn Gast-Hülle und Anmelde-Karte polstern
   verschieden.

   `width: 100%` ist hier tragend und kein Beiwerk. `body` ist ein
   Spalten-Flex-Container (siehe Base), und ein Flex-Element mit einem
   `auto`-Rand quer zur Achse wird nicht gedehnt: Es fällt auf seine
   Inhaltsbreite zurück, und `max-width` deckelt dann nur noch etwas, das
   ohnehin schmaler ist. Genau daran nahm die Gast-Hülle die angehobene Breite
   von 1180 px nie an, sondern maß 991 px, also die Breite ihres Inhalts.
   `.main-content` trägt dieselbe Zeile aus demselben Grund. */
.page-shell {
  width: 100%;
  max-width: var(--shell-width, 960px);
  margin: 0 auto;
}

/* ── Breadcrumb ── */
.breadcrumb {
  /* Umbrechend: der letzte Krümel ist ein Modultitel und damit beliebig lang.
     Auf einem schmalen Telefon stand er sonst neben der Seite. */
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  font-size: 0.8125rem; color: var(--muted);
  margin-bottom: 24px;
}
.breadcrumb a { color: var(--muted); text-decoration: none; transition: color 0.15s; }
.breadcrumb a:hover { color: var(--primary); }
.breadcrumb__sep { color: var(--border); font-size: 0.75rem; }
.breadcrumb__current { color: var(--text); font-weight: 500; }

/* ── Rumpf: Seitenleiste und Inhalt ──
   Die Seitenleiste ersetzt seit 2026-09-01 die waagerechte zweite Menüzeile
   (Zielbild §4). Der Gewinn ist nicht die Richtung, sondern die Sichtbarkeit:
   Alle Ziele eines Arbeitskontexts stehen ohne Aufklappen da, und die
   Überschriften ordnen sie, ohne selbst ein Ort zu sein.

   Zwei Zustände. Breit trägt sie Beschriftungen, kompakt nur die Anfangsbuchstaben
   samt Tooltip; kompakt ist die Voreinstellung auf Seiten mit eigener
   Arbeitsfläche (Regel 13), denn der Pfad-Editor führt links und rechts schon
   eigene Spalten. */
.app-shell {
  display: flex;
  align-items: flex-start;
  /* Die Leiste steht, der Inhalt scrollt. Sie braucht dafür eine Hülle, die bis
     ans Seitenende reicht, sonst hinge sie beim Scrollen einer langen Tabelle
     in der Luft.

     `flex: 1` und keine feste Mindesthöhe: `body` ist ein Spalten-Flex-Container
     aus Kopfzeile, Hülle und Fußleiste, und die Hülle nimmt darin, was die
     beiden anderen übrig lassen. Mit `100vh - Kopfzeile` käme die Höhe der
     Fußleiste obendrauf, und eine Seite mit drei Zeilen scrollte um genau
     diesen Streifen. */
  flex: 1;
}
.sidebar {
  flex: 0 0 var(--sidebar-w, 232px);
  width: var(--sidebar-w, 232px);
  align-self: stretch;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border-right: 1px solid var(--border);
  position: sticky;
  top: var(--header-h, 56px);
  max-height: calc(100vh - var(--header-h, 56px));
  transition: flex-basis 0.15s, width 0.15s;
}
.sidebar__scroll { flex: 1; overflow-y: auto; padding: 12px 10px 8px; }
.sidebar__group { margin-bottom: 10px; }
.sidebar__group:last-child { margin-bottom: 0; }
/* Nicht anklickbar, kein Hover, kein Fokus, kein Aktivzustand (Regeln 2 und 3).
   Sie ordnet, sie führt nicht. */
.sidebar__heading {
  /* Klebt beim Scrollen oben: Eine lange Leiste laesst sonst vergessen, unter
     welcher Ueberschrift man gerade liest, und genau das ist die Aufgabe der
     Ueberschrift. */
  position: sticky; top: 0; z-index: 1;
  background: var(--white);
  padding: 6px 10px 4px;
  font-size: 0.6875rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--muted);
  user-select: none;
}
.sidebar__link {
  display: flex; align-items: center; gap: 8px;
  /* Dicht, aber nicht gedrängt. Die Verwaltung trägt gut zwanzig Ziele, und
     bei 48 px je Zeile passt die Hälfte davon nicht auf ein Notebook. Die
     Zeilenhöhe steht deshalb ausdrücklich hier und kommt nicht aus dem
     Fließtext des Körpers, wo sie fürs Lesen gemacht ist und nicht fürs
     Überfliegen. */
  padding: 6px 10px; line-height: 1.35;
  border-radius: var(--r-sm, 6px);
  font-size: 0.875rem; font-weight: 500;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap; overflow: hidden;
  transition: background 0.12s, color 0.12s;
}
/* Das Sinnbild behaelt seine Groesse, auch wenn die Beschriftung lang ist. */
.sidebar__link svg { flex: 0 0 auto; opacity: 0.75; }
.sidebar__link.active svg { opacity: 1; }
.sidebar__link:hover { background: var(--surface); }
.sidebar__link.active { background: var(--primary-light); color: var(--primary); font-weight: 600; }
.sidebar__badge {
  margin-left: auto;
  font-size: 0.6875rem; font-weight: 700;
  background: var(--primary); color: var(--white);
  border-radius: 999px; padding: 1px 7px;
}
.sidebar__toggle {
  display: flex; align-items: center; gap: 8px;
  margin: 0; padding: 12px 16px;
  border: none; border-top: 1px solid var(--border);
  background: none; cursor: pointer;
  font: inherit; font-size: 0.8125rem; color: var(--muted);
}
.sidebar__toggle:hover { color: var(--text); }

/* Kompakt: die Leiste behält ihre Ordnung, verliert aber die Wörter. Die
   Überschriften werden zu einem Strich, denn ein abgeschnittenes Wort ordnet
   nichts. */
/* Kompakt: nur die Sinnbilder.

   Bis 2026-09-01 stand hier der Anfangsbuchstabe jedes Ziels
   (`content: attr(title)`). Gedacht war er als Symbol-Ersatz, herausgekommen
   sind unter „Mein Bereich" fuenf „M" untereinander: Meine Termine, Meine
   Antraege, Meine Zeiten, Mein Entgelt, Meine Akte. Seit die Ziele echte
   Sinnbilder tragen (`NavIcons`), traegt der kompakte Zustand sie, und die
   Leiste bleibt bedienbar statt nur schmal. Der volle Name kommt als Tooltip
   aus `title`.

   Der Unterschied zum Fokusmodus bleibt: Dort ist die Leiste ganz weg und der
   Rueckweg steht in der Werkzeugleiste der Seite. */
.app-shell--compact .sidebar { flex-basis: 52px; width: 52px; }
/* Die Beschriftung wird UNSICHTBAR, nicht entfernt.

   `display: none` nimmt den Text auch aus dem Accessibility-Tree, und dann hat
   der Link keinen zugaenglichen Namen mehr: Das Sinnbild daneben ist
   `aria-hidden`, weil es sonst zweimal vorgelesen wuerde, und uebrig bliebe nur
   das `title`-Attribut. Auf das ist kein Verlass, denn ob ein Screenreader es
   als Namen nimmt, haengt an Programm und Einstellung.

   Geclippt statt entfernt bleibt der Name im Baum. Wer sieht, sieht das Symbol;
   wer hoert, hoert das Wort. */
.app-shell--compact .sidebar__label {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}
.app-shell--compact .sidebar__scroll { padding: 12px 8px 8px; }
.app-shell--compact .sidebar__link { justify-content: center; padding: 9px 0; }
/* Die Plakette wandert an die Ecke des Symbols: Neben ihm bliebe kein Platz,
   und weglassen darf man sie nicht, denn sie ist der Grund hinzusehen. */
.app-shell--compact .sidebar__link { position: relative; }
.app-shell--compact .sidebar__badge {
  position: absolute; top: 3px; right: 6px;
  min-width: 15px; height: 15px; padding: 0 3px;
  font-size: 0.625rem; line-height: 15px;
}
/* Die Ueberschrift wird zum Strich: Ihr Wort passt nicht, ihre Ordnung schon. */
.app-shell--compact .sidebar__heading {
  height: 1px; padding: 0; margin: 10px 6px;
  overflow: hidden; text-indent: -999em;
  background: var(--border);
}
.app-shell--compact .sidebar__toggle { justify-content: center; padding: 12px 0; }
.app-shell--compact .sidebar__toggle svg { transform: rotate(180deg); }

/* Fokusmodus (Regel 12): die Leiste ganz weg, und nur hier. Eine Seitenleiste,
   die sich jederzeit ausblenden laesst, ist keine Navigation mehr, sondern eine
   Einstellung; eine, die es fuer lange Bearbeitungen tut, ist ein Werkzeug. Der
   Weg zurueck steht in derselben Werkzeugleiste, die hineingefuehrt hat. */
.app-shell--focus .sidebar { display: none; }

.drawer-trigger { display: none; }
.drawer-scrim { display: none; }

@media (max-width: 900px) {
  /* Auf dem Telefon wird die Leiste zur Schublade: Sie liegt über dem Inhalt
     statt neben ihm, und ohne Schublade bliebe die Verwaltung dort ganz ohne
     Navigation — die zweite Zeile, die das bisher trug, gibt es nicht mehr. */
  /* Spalten-Fluss und nicht `block`: Die Inhaltsspalte muss auch hier die volle
     Höhe annehmen, sonst stünde der Fuß einer kurzen Seite mitten im Bild. Die
     Schublade selbst ist fixiert und damit außer Fluss, sie wird kein
     Flex-Element. */
  .app-shell { display: flex; flex-direction: column; align-items: stretch; }
  .sidebar {
    position: fixed; top: var(--header-h, 56px); bottom: 0; left: 0; z-index: 95;
    max-height: none;
    transform: translateX(-100%);
    transition: transform 0.18s ease;
    box-shadow: var(--shadow-md, 0 4px 16px rgba(0,0,0,0.12));
  }
  body.drawer-open .sidebar { transform: translateX(0); }
  body.drawer-open .drawer-scrim {
    display: block;
    position: fixed; inset: var(--header-h, 56px) 0 0 0; z-index: 94;
    background: rgba(0,0,0,0.35);
  }
  .sidebar__toggle { display: none; }
  .drawer-trigger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px;
    border: 1px solid var(--border); border-radius: var(--r-sm, 6px);
    background: none; color: var(--muted); cursor: pointer;
  }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar { transition: none; }
}

/* ── „Wartet auf dich" ──
   Der erste Block der Startseite (Zielbild §6.1). Er zeigt eine Bringschuld und
   sieht deshalb anders aus als die Kacheln darunter: keine Kachelreihe, sondern
   eine Liste, denn eine Bringschuld liest man von oben nach unten ab. Die Zahl
   steht vorn, weil sie die Dringlichkeit trägt, und die Handlung rechts, weil
   dort die Hand ohnehin hinwill. */
.waiting {
  background: var(--white);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  padding: 16px 20px;
  margin-bottom: 24px;
}
.waiting__title {
  margin: 0 0 10px;
  font-size: 0.75rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--muted);
}
.waiting__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.waiting__row {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.waiting__row:last-child { border-bottom: none; }
.waiting__count {
  flex: 0 0 auto;
  min-width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: var(--primary-light); color: var(--primary);
  font-size: 0.8125rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.waiting__reason { flex: 1; min-width: 0; font-size: 0.9375rem; color: var(--text); }
@media (max-width: 640px) {
  .waiting__row { flex-wrap: wrap; }
  .waiting__reason { flex-basis: calc(100% - 38px); }
}

/* ── Die Kacheln von „Heute“ ──
   Zielbild §6.1. Jede Kachel sagt dasselbe in derselben Reihenfolge: Grund,
   Stand, Handlung. Sie sitzen unter „Wartet auf dich“ und sind eine Stufe
   leiser als der Block darüber, denn der zeigt eine Bringschuld und diese
   zeigen einen Hinweis.

   Das Gitter füllt sich selbst: Bei einer Kachel steht eine, bei dreien stehen
   drei. Eine feste Spaltenzahl hätte Lücken erzeugt, wo nichts anliegt, und
   eine leere Kachel ist eine Meldung ohne Anlass. */
.today {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}
.today__tile {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 4px;
}
.today__label {
  font-size: 0.6875rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--muted);
}
.today__reason {
  font-size: 1rem; font-weight: 650; color: var(--text);
  overflow-wrap: anywhere;
}
.today__status { font-size: 0.8125rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* Der Knopf sitzt unten, auch wenn die Nachbarkachel mehr Zeilen trägt: Drei
   Knöpfe auf drei Höhen lesen sich als drei verschiedene Dinge. */
.today__action { margin-top: auto; align-self: flex-start; }

/* ── Objektheader ──
   Der Kopf jeder Seite, die ein konkretes Objekt zeigt (Zielbild §7.2). Er
   beantwortet „wo bin ich" von oben nach unten: Pfad, Name, Status, Handlungen,
   und darunter die Ansichten dieses einen Objekts.

   Die Objektreiter sind bewusst die dritte Lautstärke. Über der Überschrift
   sitzt das Segmented Control und wechselt zwischen Beständen; ganz unten sitzt
   die 12-px-Reihe des Fachmoduls. Die Objektreiter liegen dazwischen: derselbe
   Unterstrich, aber in Inhaltsgröße, denn sie gehören zum Objekt und nicht zum
   Menü. Wer die drei Reihen übereinander sieht, soll ohne Erklärung wissen,
   welche wohin führt. */
.object-header { margin-bottom: 24px; }
.object-header .breadcrumb { margin-bottom: 10px; }
.object-header__row {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.object-header__ident { min-width: 0; }
.object-header__title {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  margin: 0;
  font-size: 1.625rem; font-weight: 800; letter-spacing: -0.02em;
  /* Ein Objektname ist beliebig lang und darf nicht aus der Seite laufen. */
  overflow-wrap: anywhere;
}
.object-header__status { font-size: 0.75rem; font-weight: 600; }
.object-header__meta { margin: 6px 0 0; font-size: 0.9375rem; color: var(--muted); }
/* Handlungen sind keine Navigation (§9): rechts, als Knöpfe, ohne Umbruch. */
.object-header__actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.object-tabs {
  display: flex; gap: 4px;
  margin-top: 18px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
}
.object-tabs::-webkit-scrollbar { display: none; }
.object-tabs__item {
  flex-shrink: 0;
  padding: 8px 12px;
  font-size: 0.875rem; font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  /* Der Strich liegt AUF der Trennlinie und nicht darüber. */
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 0.15s;
}
.object-tabs__item:hover { color: var(--text); }
.object-tabs__item.active {
  color: var(--text); font-weight: 600;
  border-bottom-color: var(--text);
}
@media (max-width: 640px) {
  .object-header__row { flex-direction: column; }
  .object-header__actions { width: 100%; }
}

/* ── Cards ── */
.card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
}
.card-title {
  font-size: 0.75rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--muted);
  margin-bottom: 14px;
}
/* `.card` bringt bewusst keine Polsterung mit, denn manche Karte trägt eine
   randlose Tabelle. Der Regelfall ist aber gepolstert, und weil es die Klasse
   dafür nicht gab, stand in den Views hundertfach `style="padding:24px"`. */
.card--pad    { padding: 24px; }
.card--pad-lg { padding: 32px; }

/* ── Wiederkehrende Textbausteine ──
   Diese fünf Muster standen zusammen über tausendmal als Inline-Style in den
   Views. Das ist nicht nur Schreibarbeit: ein Inline-Style schlägt jede
   Media-Query, weshalb die Telefon-Anpassungen am Dateiende teils mit
   `!important` dagegenhalten mussten. Als Klasse ist beides erledigt. */

/* Die kleine Überschrift über einem Wert („Aktiver Pfad", „Noch offen"). */
.eyebrow {
  font-size: 0.6875rem; font-weight: 700;
  color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.text-muted-sm { font-size: 0.875rem;  color: var(--muted); }
.text-muted-xs { font-size: 0.8125rem; color: var(--muted); }

/* Zeile mit Beschriftung links und Wert rechts. Anders als `.detail-row` ohne
   Trennlinie und ohne Polsterung, denn dieses Muster steht auch frei. */
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

/* Senkrechter Stapel mit gleichem Abstand. */
.stack    { display: flex; flex-direction: column; gap: 8px; }
.stack-sm { display: flex; flex-direction: column; gap: 4px; }

/* Seitenkopf: H1 plus einleitender Satz. Lora trägt die H1 (Design-Brief §2.3). */
.page-head  { margin-bottom: 28px; }
.page-title {
  font-size: 1.875rem; font-weight: 800;
  color: var(--text);
  letter-spacing: -0.025em;
  margin-bottom: 6px;
}
.page-intro { font-size: 1rem; color: var(--muted); }

/* ── Pills / Tags ── */
.pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px;
  border-radius: var(--r-full);
  font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.pill-primary { background: var(--primary-light); color: var(--primary); }
.pill-accent  { background: var(--accent-bg); color: var(--accent-dark); border: 1px solid var(--accent-border); }
.pill-danger  { background: var(--danger-bg); color: var(--danger); border: 1px solid var(--danger-border); }
.pill-success { background: var(--success-bg); color: var(--success); }
.pill-muted   { background: var(--surface); color: var(--muted); border: 1px solid var(--border); }
.pill-expert  { background: var(--expert-bg); color: var(--expert); }

/* ── Level Tags ── */
.level {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--r-full);
  font-size: 0.6875rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.level-basic    { background: var(--primary-light); color: var(--level-basic); }
.level-advanced { background: var(--accent-bg); color: var(--warning-text); }
.level-expert   { background: var(--expert-bg); color: var(--expert); }

/* ── Progress Bar ── */
.progress-bar {
  height: 8px;
  background: var(--border);
  border-radius: var(--r-full);
  overflow: hidden;
}
.progress-bar__fill {
  height: 100%;
  background: var(--primary);
  border-radius: var(--r-full);
}

/* ── Buttons ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px 16px;
  border-radius: var(--r-sm);
  font-family: var(--fh);
  font-size: 0.875rem; font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.15s;
  border: 1px solid transparent;
  white-space: nowrap;
  line-height: 1.4;
}
/* `display: inline-flex` schlägt sonst das `hidden`-Attribut: ein per Skript
   ausgeblendeter Knopf bliebe stehen (Quiz-Durchlauf, Weiter/Abgeben). */
.btn[hidden] { display: none; }
.btn-primary { background: var(--primary); color: white; border-color: var(--primary); }
.btn-primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
.btn-outline { background: transparent; color: var(--primary); border-color: var(--primary); }
.btn-outline:hover { background: var(--primary-light); }
.btn-ghost { background: transparent; color: var(--muted); border-color: var(--border); }
.btn-ghost:hover { background: var(--surface); color: var(--text); }
.btn-danger-ghost { background: transparent; color: var(--danger); border-color: var(--danger-border); }
.btn-disabled { background: var(--surface) !important; color: var(--muted) !important; border-color: var(--border) !important; cursor: not-allowed !important; }
.btn-sm { padding: 5px 12px; font-size: 0.8125rem; }
.btn-xs { padding: 3px 10px; font-size: 0.75rem; }

/* ── Status Dots ── */
.status-dot {
  width: 32px; height: 32px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; font-size: 14px;
}
.status-done    { background: var(--primary); color: white; }
.status-active  { background: var(--primary-light); color: var(--primary); border: 2.5px solid var(--primary); }
.status-pending { background: var(--surface); color: var(--muted); border: 2px solid var(--border); }

/* ── Module Cards ── */
.module-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 16px 20px;
  display: flex; align-items: center; gap: 16px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.15s;
}
.module-card:hover { box-shadow: var(--shadow-md); }
.module-card.is-active { border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring), var(--shadow-sm); }
.module-card__body { flex: 1; min-width: 0; }
.module-card__num { font-size: 0.6875rem; font-weight: 700; color: var(--muted); letter-spacing: 0.05em; margin-bottom: 2px; }
.module-card__title { font-size: 0.9375rem; font-weight: 600; color: var(--text); margin-bottom: 5px; line-height: 1.3; }
.module-card__meta { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: 0.8125rem; color: var(--muted); }
/* Die Aktionen stehen untereinander und rechtsbündig. Das stand bis zum
   Mobil-Durchgang als Inline-Style in `_module-card.blade.php` und war damit von
   keiner Media-Query erreichbar — auf dem Telefon blieb die Spalte stehen und
   drückte den Titel auf 141 px zusammen. */
.module-card__actions { flex-shrink: 0; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.module-card__prereq { display: flex; align-items: center; gap: 5px; font-size: 0.75rem; color: var(--muted); background: var(--surface); border: 1px solid var(--border); padding: 2px 9px; border-radius: var(--r-full); margin-top: 6px; width: fit-content; }

/* ── Module Tiles ──
   Die Kachel-Darstellung eines Moduls. Steht hier und nicht mehr in der
   Modul-Übersicht, seit die Pfad-Ansicht „Übersicht" dieselbe Kachel zeigt —
   zwei Seiten, ein Aussehen. Markup: partials via learner/modules/_tile. */
.module-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; }
@media (max-width: 900px) { .module-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .module-grid { grid-template-columns: minmax(0, 1fr); } }

.module-tile {
  display: flex; flex-direction: column;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.module-tile:hover { transform: translateY(-3px); box-shadow: var(--shadow-md, 0 8px 24px rgba(0,0,0,.10)); border-color: var(--primary); }
/* Gesperrt: sichtbar, aber nicht anklickbar — sonst führt die Kachel ins Leere. */
.module-tile.is-locked { opacity: 0.7; pointer-events: none; }

.module-tile__media {
  position: relative; height: 132px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2, var(--bg, #f3f4f6));
  border-bottom: 1px solid var(--border);
}
.module-tile__media img { max-width: 78%; max-height: 78%; object-fit: contain; }
.module-tile__initial { font-size: 2.5rem; font-weight: 800; color: var(--primary); opacity: .55; }
.module-tile__source-badge {
  position: absolute; top: 8px; right: 8px;
  font-size: 0.6875rem; font-weight: 600; padding: 2px 8px;
  border-radius: 999px; background: var(--white); border: 1px solid var(--border); color: var(--muted);
}

.module-tile__body { display: flex; flex-direction: column; gap: 8px; padding: 16px; flex: 1; }
.module-tile__pills { display: flex; flex-wrap: wrap; gap: 6px; }
.module-tile__title { font-size: 1rem; font-weight: 700; line-height: 1.3; margin: 0; color: var(--text); }
.module-tile__desc { font-size: 0.8125rem; color: var(--muted); margin: 0; line-height: 1.45; }
.module-tile__meta { display: flex; flex-wrap: wrap; gap: 14px; margin-top: auto; padding-top: 8px; font-size: 0.75rem; color: var(--muted); }
.module-tile__meta span { display: inline-flex; align-items: center; gap: 5px; }
/* Aus wie vielen Medien ein Modul besteht, ist die Frage vor dem Klick —
   deshalb trägt diese eine Angabe die Akzentfarbe statt des Grau der Zeile. */
.module-tile__media-count { color: var(--primary); font-weight: 700; }

/* ── Abhängigkeits-Graph ──
   Hervorheben blendet alles ab, was nicht am betrachteten Modul hängt. Der
   Übergang gehört hierher und nicht ins JavaScript, denn nur hier lässt er
   sich an die Systemeinstellung binden. */
@media (prefers-reduced-motion: no-preference) {
  .graph-node, .graph-viewport path { transition: opacity 0.15s; }
}

/* ── Source Icons ── */
.src-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%; flex-shrink: 0;
  font-size: 9px; font-weight: 800; font-family: var(--fh);
}
.src-yt   { background: #ff0000; }
.src-gh   { background: #24292e; }
.src-cf   { background: #0052cc; border-radius: 4px; }
.src-sp   { background: #038387; border-radius: 4px; }
.src-ps   { background: #f15b2a; border-radius: 4px; }
.src-pdf  { background: var(--surface); border: 1px solid var(--border); color: var(--muted); border-radius: 4px; }
.src-wiki { background: #e8e8e8; color: #555; border-radius: 4px; }

/* ── Avatar ── */
.avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--primary);
  color: white;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.75rem; font-weight: 700; flex-shrink: 0;
}

/* ── Stat Tiles ── */
.stat-tile {
  background: var(--surface);
  border-radius: var(--r-sm);
  padding: 14px 16px;
  text-align: center;
}
.stat-tile__value { font-size: 1.625rem; font-weight: 800; color: var(--primary); line-height: 1; margin-bottom: 4px; }
.stat-tile__label { font-size: 0.75rem; color: var(--muted); }

/* ── Site Footer ── */
.site-footer {
  /* Seit dem 2026-09-02 in `.app-main` und damit über die volle Breite NEBEN der
     Seitenleiste: Der Streifen beginnt an deren rechter Kante und läuft bis an den
     rechten Rand.

     Beide Nachbarschaften waren einmal da und beide waren falsch. In der
     Inhaltsspalte endete er mit deren 1280 px und stand auf einem breiten
     Bildschirm eingerückt und mittig da. Unter der ganzen Hülle lief er unter die
     Seitenleiste durch, und die verlor damit ihren Boden und sprang.

     Er scrollt mit wie jeder andere Inhalt und sitzt trotzdem immer unten: Die
     Inhaltsspalte darüber nimmt sich als Flex-Element den ganzen übrigen Platz.
     Nach oben hält deren unteres Polster den Abstand, damit der Streifen nie am
     letzten Kasten klebt. */
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding: 18px 32px;
  text-align: center;
  font-size: 0.8125rem;
  color: var(--muted);
}
.site-footer a { color: var(--muted); text-decoration: none; transition: color 0.15s; }
.site-footer a:hover { color: var(--primary); }
.site-footer .link-button { color: var(--muted); }
.site-footer .link-button:hover { color: var(--primary); }

/* Ein Knopf, der wie ein Link aussieht. Für Auslöser, deren Ziel ein Dialog auf
   derselben Seite ist: Als `<a href="#">` wäre es ein Sprung ins Nichts, den
   die Tastatur trotzdem als Adresse ankündigt. */
.link-button {
  background: none; border: 0; padding: 0;
  font: inherit; color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: color 0.15s;
}

/* ── Divider ── */
.divider { border: none; border-top: 1px solid var(--border); }

/* ── Toggle Button Group ── */
.view-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.view-toggle__btn {
  padding: 6px 14px;
  background: none; border: none;
  font-family: var(--fh); font-size: 0.8125rem; font-weight: 500;
  color: var(--muted); cursor: pointer;
  transition: background 0.15s, color 0.15s;
  display: flex; align-items: center; gap: 5px;
}
.view-toggle__btn.active { background: var(--primary); color: white; }
.view-toggle__btn:not(.active):hover { background: var(--surface); }
.view-toggle__btn:not(:last-child) { border-right: 1px solid var(--border); }

/* ── Drag Handle ── */
.drag-handle { color: var(--border); cursor: grab; flex-shrink: 0; }
.drag-handle:hover { color: var(--muted); }

/* ── Three-dot Menu ── */
.menu-btn {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  border: none; background: none;
  border-radius: var(--r-sm); color: var(--muted); cursor: pointer;
  transition: background 0.15s, color 0.15s;
  flex-shrink: 0;
}
.menu-btn:hover { background: var(--surface); color: var(--text); }

/* ── Insert Zone (Editor) ── */
.insert-zone {
  height: 8px;
  display: flex; align-items: center;
  position: relative;
  margin: 2px 0;
}
.insert-zone__line {
  width: 100%; height: 2px;
  border-radius: 1px;
  background: transparent;
  border: 1px dashed transparent;
  transition: all 0.15s;
}
.insert-zone:hover .insert-zone__line,
.insert-zone.hovered .insert-zone__line {
  border-color: var(--primary);
  background: rgba(31,98,142,0.06);
  height: 28px;
}
.insert-zone__label {
  position: absolute; left: 50%; transform: translateX(-50%);
  font-size: 0.75rem; font-weight: 600; color: var(--primary);
  opacity: 0; white-space: nowrap;
  transition: opacity 0.15s;
  pointer-events: none;
}
.insert-zone.hovered .insert-zone__label { opacity: 1; }

/* ── Validation Items ── */
.valid-item { display: flex; align-items: flex-start; gap: 10px; font-size: 0.875rem; padding: 6px 0; }
.valid-item__icon { flex-shrink: 0; margin-top: 1px; }
.valid-ok   { color: var(--success); }
.valid-warn { color: var(--warning-text); }

/* ── Data Table ── */
.data-table { width: 100%; border-collapse: collapse; }
.data-table th {
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--muted); padding: 10px 14px;
  text-align: left; border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.data-table td {
  padding: 12px 14px; font-size: 0.875rem; color: var(--text);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.data-table tr:last-child td { border-bottom: none; }
.data-table tr:hover td { background: var(--surface); }
.data-table td.link { color: var(--primary); font-weight: 600; cursor: pointer; }
.data-table td.link:hover { text-decoration: underline; }

/* ── KPI Cards (Admin Sprint 6) ── */
/* `auto-fit` statt vier fester Spuren: Vier Kacheln stehen weiter nebeneinander,
   fünf brechen nicht in eine Restzeile mit einem Waisenkind, und auf einem
   schmalen Fenster ergibt sich 2×2 von selbst, statt vier Spalten auf je 80 px
   zu quetschen (`minmax(0, 1fr)` erlaubte das Schrumpfen bis zur Unlesbarkeit). */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 20px; margin-bottom: 28px; }
.kpi-card { background: var(--white); border: 1px solid var(--border); border-radius: var(--r-md); padding: 22px 24px; box-shadow: var(--shadow-sm); }
.kpi-card__label { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: var(--muted); margin-bottom: 8px; }
.kpi-card__value { font-size: 2rem; font-weight: 800; color: var(--text); line-height: 1; margin-bottom: 4px; }
.kpi-card__sub { font-size: 0.8125rem; }
.kpi-card__sub.good   { color: var(--success); }
.kpi-card__sub.warn   { color: var(--warning-text); }
.kpi-card__sub.danger { color: var(--danger); font-weight: 600; }
.kpi-card__sub.muted  { color: var(--muted); }

/* Kachel mit Ziel (CALTRIX-174). Sie erbt Farbe und Schrift der stillen Kachel,
   denn eine blau eingefärbte Kennzahl wäre schlechter zu lesen als die Zahl,
   um die es geht; klickbar wirkt sie über Rahmen, Schatten und den Anstieg
   beim Überfahren. */
.kpi-card--link { display: block; color: inherit; text-decoration: none; transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s; }
.kpi-card--link:hover { border-color: var(--primary-border); box-shadow: var(--shadow-md); transform: translateY(-1px); }

/* Zahl im Fließtext, die weiterführt: gepunktet unterstrichen, damit sie sich
   vom Satz abhebt, ohne wie ein Menüpunkt auszusehen. */
.stat-link { color: inherit; text-decoration: none; border-bottom: 1px dotted currentColor; }
.stat-link:hover { color: var(--primary); border-bottom-style: solid; }

/* ── Two-column layout (Admin Sprint 6) ── */
.two-col-area { display: grid; grid-template-columns: minmax(0, 60fr) minmax(0, 40fr); gap: 20px; margin-bottom: 28px; }

/* ── Org Tree (Admin Sprint 6) ── */
.tree-item { display: flex; align-items: center; gap: 10px; padding: 10px 0; cursor: pointer; border-bottom: 1px solid var(--border); }
.tree-item:last-child { border-bottom: none; }
.tree-item__icon { color: var(--muted); transition: transform 0.2s; flex-shrink: 0; }
.tree-item.open .tree-item__icon { transform: rotate(90deg); }
.tree-item__name { font-size: 0.9375rem; font-weight: 600; color: var(--text); }
.tree-item__meta { font-size: 0.8125rem; color: var(--muted); margin-left: auto; }
.team-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; padding: 12px 0 4px 28px; }
.team-card { background: var(--white); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 14px 16px; box-shadow: var(--shadow-sm); position: relative; }
/* Die Team-Karte führt ins Team (CALTRIX-174), wie die Kennzahl-Kachel ohne
   Link-Farbe, sonst leuchtete die halbe Organisationsstruktur blau. */
.team-card--link { display: block; color: inherit; text-decoration: none; transition: border-color 0.15s, box-shadow 0.15s; }
.team-card--link:hover { border-color: var(--primary-border); box-shadow: var(--shadow-md); }
.team-card__name { font-size: 0.9375rem; font-weight: 700; color: var(--text); margin-bottom: 4px; }
.team-card__meta { font-size: 0.8125rem; color: var(--muted); margin-bottom: 10px; }
.team-card__stats { display: flex; gap: 14px; }
.team-card__stat { font-size: 0.8125rem; }
.team-card__stat strong { display: block; font-size: 1.125rem; font-weight: 800; color: var(--primary); }

/* ── Top Module List (Admin Sprint 6) ── */
.top-module-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; }
.top-module-row:not(:last-child) { border-bottom: 1px solid var(--border); }
/* Die ganze Zeile führt in die Bibliothek (CALTRIX-174); der Titel darin bleibt
   Textfarbe, die Zeile hebt sich beim Überfahren ab. */
.top-module-row--link { color: inherit; text-decoration: none; }
.top-module-row--link:hover { background: var(--surface); }
.rank-badge { width: 24px; height: 24px; border-radius: 50%; background: var(--surface); color: var(--muted); font-size: 0.75rem; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }

/* ── Activity Feed ── */
.activity-item { display: flex; align-items: flex-start; gap: 12px; padding: 10px 0; }
.activity-item:not(:last-child) { border-bottom: 1px solid var(--border); }
.activity-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--primary); flex-shrink: 0; margin-top: 6px; }
.activity-dot-green  { background: var(--success); }
.activity-dot-orange { background: var(--accent-dark); }
.activity-text { font-size: 0.875rem; color: var(--text); line-height: 1.4; }
.activity-time { font-size: 0.75rem; color: var(--muted); margin-top: 2px; }

/* ── Search Input ── */
.search-input {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 6px 12px;
  font-family: var(--fh); font-size: 0.875rem; color: var(--muted);
  width: 220px;
}
.search-input svg { flex-shrink: 0; }

/* ── Mini Progress Bar ── */
.mini-bar { height: 5px; background: var(--border); border-radius: 3px; overflow: hidden; min-width: 60px; }
.mini-bar__fill { height: 100%; background: var(--primary); border-radius: 3px; }

/* ── Auth Layout ── */
.auth-wrap {
  min-height: 100vh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: var(--bg);
  padding: 32px 16px;
}
/* Pflichtangaben unter der Anmeldekarte (G3) — ohne Login erreichbar, also Pflicht. */
.auth-legal {
  margin: 18px 0 0;
  font-size: 0.75rem;
  color: var(--muted);
  text-align: center;
}
.auth-legal a { color: var(--muted); text-decoration: underline; }
.auth-legal a:hover { color: var(--text); }
.auth-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  padding: 40px;
  width: 100%;
  max-width: 420px;
}
/* Dieselbe Wortmarke auf der Anmeldeseite: Sie darf nicht anders aussehen als
   die im Kopf, sonst trägt die erste Seite, die jemand sieht, eine zweite
   Fassung der Marke. */
.auth-logo {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  color: var(--brand-mark);
  font-weight: 600; font-size: 1.125rem;
  text-transform: uppercase;
  letter-spacing: 0.055em;
  margin-bottom: 28px;
  text-decoration: none;
}
.auth-title {
  font-size: 1.25rem; font-weight: 700;
  color: var(--text);
  margin-bottom: 4px;
  text-align: center;
}
.auth-sub {
  font-size: 0.875rem; color: var(--muted);
  text-align: center;
  margin-bottom: 28px;
}

/* ── Form Elements ── */
.form-group { margin-bottom: 18px; }
.form-label {
  display: block;
  font-size: 0.875rem; font-weight: 600;
  color: var(--text);
  margin-bottom: 6px;
}
/* Steht das Feld im Vordergrund und nicht seine Beschriftung — etwa in einer
   Bearbeiten-Zeile, die ihre Spalten schon durch die Anordnung erklärt —, tritt
   das Label zurück. */
.form-label--compact { font-size: 0.75rem; color: var(--muted); margin-bottom: 4px; }
.form-input {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: var(--fh); font-size: 0.9375rem;
  color: var(--text);
  background: var(--white);
  transition: border-color 0.15s, box-shadow 0.15s;
  outline: none;
}
.form-input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--ring);
}
.form-input.has-error { border-color: var(--danger); }
.form-error {
  font-size: 0.8125rem; color: var(--danger);
  margin-top: 5px;
}
.form-divider {
  display: flex; align-items: center; gap: 12px;
  margin: 20px 0;
  color: var(--muted); font-size: 0.8125rem;
}
.form-divider::before, .form-divider::after {
  content: '';
  flex: 1;
  border-top: 1px solid var(--border);
}
.btn-block { width: 100%; }

/* ── Alert / Flash Messages ── */
.alert {
  padding: 12px 16px;
  border-radius: var(--r-sm);
  font-size: 0.875rem;
  margin-bottom: 16px;
}
.alert-danger  { background: var(--danger-bg); color: var(--danger); border: 1px solid var(--danger-border); }
.alert-success { background: var(--success-bg); color: var(--success); border: 1px solid var(--success-border); }
.alert-warning { background: var(--warning-bg); color: var(--warning-text); border: 1px solid var(--warning-border); }
.alert-info    { background: var(--info-bg); color: var(--info); border: 1px solid var(--info-border); }

/* ── Responsive Layout-Helfer (Lerner-Ansicht mobilfreundlich) ──
   Eigene Klassen statt Inline-grid, damit die Media-Query sie überschreiben kann
   (Inline-Styles hätten höhere Spezifität).

   Jede Spur ist `minmax(0, …)` und nicht `1fr`. Der Unterschied zählt erst auf
   dem Telefon, dort aber hart: `1fr` heißt `minmax(auto, 1fr)`, und `auto` ist
   nach unten die Mindestbreite des Inhalts. Ein einziger nicht umbrechender
   Titel in einer Karte zieht die Spur damit auf seine volle Textlänge auf — die
   Karte wächst über den Bildschirm hinaus, obwohl die Media-Query längst auf
   eine Spalte gefaltet hat. Genau so stand das Dashboard bei 390 px 218 px
   neben der Seite. Mit `minmax(0, …)` darf die Spur schrumpfen, und der Titel
   kürzt sich wie vorgesehen mit Auslassungspunkten. */
.dash-grid        { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; }
.dash-grid__wide  { grid-column: 1 / -1; }
.dash-active-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; }
.profile-split    { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 28px; align-items: flex-start; }
.profile-stats    { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin-bottom: 24px; }
/* Expertensuche (`CALTRIX-26`): Treffer links, die eigene Sichtbarkeit rechts.
   Die Hauptspalte darf auf 0 schrumpfen (`minmax(0, …)`), sonst sprengen lange
   Kompetenz-Pillen das Raster statt umzubrechen. */
.experts-split    { display: grid; grid-template-columns: minmax(0, 1fr) 260px; gap: 20px; align-items: flex-start; }
.path-layout      { display: flex; gap: 32px; align-items: flex-start; }
.path-aside       { width: 280px; flex-shrink: 0; position: sticky; top: 80px; display: flex; flex-direction: column; gap: 16px; }

/* ── Lerner-Dashboard ──
   Die Seite stand vollständig in Inline-Styles (41 Stück auf einer Datei) und
   damit außerhalb jeder Media-Query. Die Klassen hier sind eins zu eins das,
   was vorher am Element klebte. */
.dash-grid        { margin-top: 0; }
.dash-grid--top   { margin-top: 28px; }

.dash-hero               { margin-bottom: 28px; }
.dash-hero__label        { display: inline-flex; align-items: center; gap: 6px; margin-bottom: 12px; }
.dash-hero__dot          { width: 8px; height: 8px; border-radius: 50%; background: var(--primary); display: inline-block; }
.dash-hero__title        { font-size: 1.5rem; font-weight: 800; color: var(--text); line-height: 1.2; margin-bottom: 4px; }
.dash-hero__desc         { margin-bottom: 20px; }
.dash-hero__progress-row { margin-bottom: 8px; }
.dash-hero__percent      { font-size: 0.875rem; font-weight: 700; color: var(--primary); }
.dash-hero__bar          { margin-bottom: 24px; }

.dash-next {
  background: var(--primary-light);
  border: 1px solid var(--primary-border);
  border-radius: var(--r-sm);
  padding: 18px 20px;
  display: flex; align-items: center; gap: 14px;
}
.dash-next__body    { flex: 1; min-width: 0; }
.dash-next__eyebrow { margin-bottom: 4px; }
.dash-next__title   { font-size: 0.9375rem; font-weight: 700; color: var(--text); margin-bottom: 4px; }

.dash-remaining        { justify-content: center; align-items: flex-start; }
.dash-remaining__value { font-size: 2rem; font-weight: 800; color: var(--text); line-height: 1; }

.path-tile            { padding: 14px 0; }
.path-tile--divided   { border-bottom: 1px solid var(--border); padding-bottom: 16px; margin-bottom: 4px; }
.path-tile__head      { font-size: 0.9375rem; font-weight: 600; color: var(--text); margin-bottom: 6px; }
.path-tile__link      { text-decoration: none; color: inherit; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.path-tile__meta      { margin-bottom: 8px; }

.recent-item          { display: flex; align-items: center; gap: 12px; padding: 10px 0; }
.recent-item--divided { border-bottom: 1px solid var(--border); }
.recent-item__mark {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--primary); color: #fff;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.recent-item__title   { font-size: 0.875rem; font-weight: 600; color: var(--text); margin-bottom: 2px; }

/* ── Betreuungsliste der Personalabteilung (2026-08-30) ──
   Karten statt Tabelle für die, bei denen etwas zusammenkommt: Eine Zeile
   zwingt jede Person in dieselbe Zahl Spalten, und genau das soll hier nicht
   sein. Wer planmäßig läuft, steht danach als Tabelle. */
.arr-heading { margin: 22px 2px 10px; }
.arr-card { margin-bottom: 12px; border-left: 3px solid var(--accent, #d97706); }
.arr-card--severe { border-left-color: var(--danger, #dc2626); }
.arr-card__head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.arr-card__name { font-size: 1.0625rem; font-weight: 700; color: var(--text); }
.arr-card__warn { color: var(--danger, #dc2626); font-weight: 600; }
.arr-card__lead { font-size: 0.875rem; font-weight: 600; color: var(--danger, #dc2626); margin: 0 0 6px; }
.arr-signals { margin: 0 0 12px; padding-left: 18px; font-size: 0.875rem; color: var(--text); }
.arr-signals li { padding: 2px 0; }
.arr-card__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.arr-form { margin: 0; }

/* ── Sicht des Paten (2026-08-30) ──
   Eine Karte je begleitetem Menschen, bewusst ohne Prozentzahl: Eine Quote lädt
   zum Vergleichen ein, und verglichen wird hier nichts. */
.buddy-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; }
.buddy-card__head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.buddy-card__name { font-size: 1.0625rem; font-weight: 700; color: var(--text); }
.buddy-block { padding-top: 12px; border-top: 1px solid var(--border); margin-top: 12px; }
.buddy-block__title { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
.buddy-task { display: flex; justify-content: space-between; gap: 10px; padding: 5px 0; font-size: 0.875rem; flex-wrap: wrap; }
.buddy-task.is-overdue { color: var(--danger, #dc2626); font-weight: 600; }
.buddy-line { display: flex; align-items: flex-start; gap: 9px; padding: 5px 0; font-size: 0.875rem; color: var(--text); }
.buddy-line__mark { flex-shrink: 0; margin-top: 2px; color: var(--muted); }
.buddy-line.is-done .buddy-line__mark { color: var(--success, #16a34a); }
.buddy-line.is-late .buddy-line__mark { color: var(--accent, #d97706); }
.buddy-prompt__text { font-size: 0.9375rem; color: var(--text); line-height: 1.55; margin: 0; }
.buddy-limit { display: flex; align-items: center; gap: 7px; margin: 18px 2px 0; max-width: 80ch; }

/* ── Personenseite der Führungskraft (2026-08-30) ──
   Was bei ihr liegt, steht oben und in Rot; der Fortschritt des Mitglieds kommt
   danach. Die Reihenfolge ist die Aussage der Seite und deshalb auch die des
   Stylesheets. */
.tm-crumb { margin-bottom: 14px; }
.tm-head { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; flex-wrap: wrap; }
.tm-head__avatar { width: 48px; height: 48px; font-size: 1.125rem; }
.tm-head__actions { margin-left: auto; }

.tm-open { border-left: 3px solid var(--danger, #dc2626); margin-bottom: 16px; }
.tm-open__title { font-size: 0.875rem; font-weight: 700; color: var(--danger, #dc2626); margin-bottom: 8px; }
.tm-open__row { display: flex; gap: 10px; justify-content: space-between; padding: 5px 0; flex-wrap: wrap; }
.tm-open__label { font-size: 0.9375rem; color: var(--text); }
.tm-open__meta  { font-size: 0.8125rem; color: var(--danger, #dc2626); font-weight: 600; }

.tm-grid { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: 18px; align-items: flex-start; }
.tm-main, .tm-side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

.tm-step { padding: 9px 0 9px 12px; border-left: 2px solid var(--border); margin-bottom: 4px; }
.tm-step--waiting { border-left-color: var(--accent, #d97706); }
.tm-step__title { font-size: 0.9375rem; font-weight: 600; color: var(--text); margin-bottom: 2px; }

.tm-numbers { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.tm-number { flex: 1 1 120px; padding: 12px 14px; background: var(--surface); border-radius: var(--r-sm); }
.tm-number__label { font-size: 0.75rem; color: var(--muted); margin-bottom: 2px; }
.tm-number__value { font-size: 1.375rem; font-weight: 800; color: var(--text); line-height: 1; }
.tm-number--warn .tm-number__value { color: var(--danger, #dc2626); }
.tm-bar { margin-bottom: 8px; }
.tm-signals__hint { margin: 8px 0 0; }
.tm-mood__state { margin: 8px 0 4px; font-weight: 600; }

/* Der Stimmungsverlauf: gleich breite Felder, eine Woche je Feld, keine Achse
   und keine Zahl. Eine Kurve daraus wäre eine Bewertung. */
.mood-strip { display: flex; gap: 6px; }
.mood-week {
  flex: 1; height: 26px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--border);
}
.mood-week--good { background: #d9f0dd; border-color: #b6e0bf; }
.mood-week--ok   { background: #fbe6c4; border-color: #f2d199; }
.mood-week--bad  { background: #f7d4d4; border-color: #efb4b4; }
.mood-week.is-current { box-shadow: inset 0 0 0 1px var(--primary); }

/* ── Meilenstein-Leiste (2026-08-30) ──
   Gleich breite Kacheln nebeneinander, die bei Platzmangel umbrechen. Kein
   Zeitstrahl mit Linie: Die Abstände wären dann eine Aussage über die Dauer,
   und die stimmt bei „Tag 30 / Tag 90" nie. */
.milestone-bar__row { display: flex; gap: 12px; flex-wrap: wrap; }
.milestone {
  flex: 1 1 180px; min-width: 0;
  padding: 12px 14px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface);
}
.milestone__when  { font-size: 0.75rem; color: var(--muted); margin-bottom: 3px; }
.milestone__date  { color: var(--muted); }
.milestone__title { font-size: 0.9375rem; font-weight: 600; color: var(--text); line-height: 1.35; }
.milestone__state { font-size: 0.75rem; margin-top: 4px; }
.milestone.is-done { border-color: var(--success, #16a34a); }
.milestone.is-done .milestone__state { color: var(--success, #16a34a); font-weight: 600; }
.milestone.is-waiting { border-color: var(--accent, #d97706); }
.milestone.is-waiting .milestone__state { color: var(--accent, #d97706); font-weight: 600; }

/* ── Ankommen: Checkliste und Wochenstimmung (2026-08-30) ──
   Beides sieht die Person auf zwei Seiten (Preboarding-Maske und Dashboard) und
   soll dort gleich aussehen. Der Haken ist ein Formular-Knopf und kein
   Kästchen: Die strikte CSP lässt keinen Inline-Handler zu, und ein Haken, der
   ohne Skript nicht funktioniert, wäre auf einem privaten Telefon vor dem
   ersten Arbeitstag der schlechteste Ort zum Ausprobieren. */
.arrival-list__intro { margin: -2px 0 10px; }
.arrival-list__count { margin: 0 0 8px; font-weight: 600; }
.arrival-items { list-style: none; margin: 0; padding: 0; }
.arrival-item { display: flex; align-items: flex-start; gap: 10px; padding: 7px 0; }
.arrival-item__form { margin: 0; flex-shrink: 0; }
.arrival-item__box {
  width: 22px; height: 22px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--white); color: #fff;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.arrival-item__box:hover { border-color: var(--primary); }
.arrival-item.is-done .arrival-item__box { background: var(--success, #16a34a); border-color: var(--success, #16a34a); }
.arrival-item__label { font-size: 0.9375rem; color: var(--text); line-height: 1.45; padding-top: 1px; }
.arrival-item.is-done .arrival-item__label { color: var(--muted); text-decoration: line-through; }

/* Die Verwaltungsseite: erst der Stand, dann das Feld, mit dem er gesetzt wird. */
.arrival-admin__state { margin-bottom: 6px; }
.arrival-admin__list { margin: 0 0 12px; padding-left: 18px; font-size: 0.875rem; color: var(--text); }
.arrival-admin__list li.is-done { color: var(--muted); text-decoration: line-through; }
.arrival-admin__form { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.arrival-admin__form textarea { width: 100%; }

/* Drei Gesichter nebeneinander, gleich groß und gleich gewichtet: Keines soll
   die naheliegende Antwort sein. */
.mood-row { display: flex; gap: 8px; margin: 0 0 10px; }
.mood-btn {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 6px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--white);
  cursor: pointer;
  font-family: inherit;
  transition: border-color 0.15s, background 0.15s;
}
.mood-btn:hover { border-color: var(--primary); }
.mood-btn.is-chosen { border-color: var(--primary); background: var(--primary-light); }
.mood-btn__face { font-size: 1.5rem; line-height: 1; }
.mood-btn__label { font-size: 0.6875rem; color: var(--muted); text-align: center; line-height: 1.3; }
.mood-btn.is-chosen .mood-btn__label { color: var(--primary); font-weight: 600; }
.mood-state { margin: 0 0 6px; font-weight: 600; }

/* ── Preboarding-Maske (2026-08-30) ──
   Die Seite zwischen Zusage und erstem Arbeitstag. Ruhig gehalten: großer
   Zähler, ein persönlicher Satz, die Inhalte darunter — und am Ende der
   Freiwilligkeits-Kasten, der fest verdrahtet ist. */
.pre-head { margin-bottom: 18px; }
.pre-badge { margin-bottom: 10px; display: inline-block; }
.pre-title { font-size: 1.75rem; font-weight: 800; letter-spacing: -0.02em; color: var(--text); margin: 0 0 8px; }
.pre-note { font-size: 1rem; color: var(--muted); line-height: 1.7; margin: 0; }

.pre-countdown { display: flex; align-items: center; gap: 22px; margin-bottom: 16px; }
.pre-countdown__days {
  display: flex; align-items: baseline; gap: 6px;
  padding-right: 22px; border-right: 1px solid var(--border);
}
.pre-countdown__number { font-size: 2.5rem; font-weight: 800; color: var(--primary); line-height: 1; }
.pre-countdown__unit   { font-size: 0.875rem; font-weight: 600; color: var(--muted); }
.pre-countdown__date   { font-size: 1.0625rem; font-weight: 700; color: var(--text); margin-top: 2px; }

.pre-paths { margin-bottom: 16px; }
.pre-path { padding: 14px 0; border-bottom: 1px solid var(--border); }
.pre-path:last-child { border-bottom: none; padding-bottom: 0; }
.pre-path__head  { gap: 12px; margin-bottom: 8px; }
.pre-path__title { font-size: 1.0625rem; font-weight: 700; color: var(--text); text-decoration: none; }
.pre-path__bar   { margin-bottom: 6px; }
.pre-path__meta  { margin: 0 0 10px; }

.pre-modules { list-style: none; margin: 0; padding: 0; }
.pre-module { display: flex; align-items: center; gap: 10px; padding: 7px 0; font-size: 0.875rem; color: var(--text); }
.pre-module__mark {
  width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: 0.6875rem; font-weight: 700; color: var(--muted);
  flex-shrink: 0;
}
.pre-module.is-done .pre-module__mark { background: var(--success, #16a34a); border-color: var(--success, #16a34a); color: #fff; }
.pre-module.is-done .pre-module__title { color: var(--muted); }

.pre-voluntary { background: var(--surface); border-left: 3px solid var(--accent, #d97706); }
.pre-voluntary__title { font-size: 0.9375rem; font-weight: 700; color: var(--text); margin-bottom: 6px; }
.pre-voluntary__body  { font-size: 0.875rem; color: var(--muted); line-height: 1.7; margin: 0; }

.pre-outro { margin: 16px 2px 0; }

/* Der Willkommenstext in der Verwaltungsliste: Textfeld und Knopf untereinander,
   damit die Spalte in einer Tabelle mit sechs Spalten nicht ausufert. */
.pre-note-form { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; min-width: 220px; margin: 0; }
.pre-note-form textarea { width: 100%; }

/* Erklärzeile unter einem Eingabefeld. Die Klasse war an mehreren Masken schon
   im Einsatz und hatte keine Regel — sie sah aus wie gewöhnlicher Text. */
.form-hint { display: block; font-size: 0.75rem; color: var(--muted); line-height: 1.5; margin-top: 4px; }

/* ── Onboarding-Analytik (2026-08-30) ──
   Das Säulenbild ist der Kern der Seite: Ein Einbruch an Position vier sieht
   man, man liest ihn nicht. Reines CSS, keine Bibliothek — die Werte stehen als
   Prozenthöhe am Element, und die Tabelle darunter trägt dieselben Zahlen für
   alle, die keine Bilder lesen. */
.kpi-card--warn { border-color: var(--accent, #d97706); }

.chip-row { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  display: inline-block;
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.8125rem; font-weight: 500;
  color: var(--muted); text-decoration: none;
  background: var(--white);
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.chip:hover { color: var(--text); }
.chip.is-active { color: var(--primary); border-color: var(--primary); background: var(--primary-light); font-weight: 600; }

.drop-chart-card { margin-bottom: 16px; }
.drop-chart__hint { margin: -2px 0 14px; }
.drop-chart {
  display: flex; align-items: flex-end; gap: 6px;
  height: 190px;
  padding: 0 2px;
  border-bottom: 1px solid var(--border);
}
.drop-chart__col { flex: 1; min-width: 18px; display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }
.drop-chart__bar {
  background: var(--primary);
  border-radius: 3px 3px 0 0;
  min-height: 3px;
}
.drop-chart__bar.is-worst { background: var(--danger, #dc2626); }
.drop-chart__x { text-align: center; font-size: 0.75rem; color: var(--muted); padding-top: 6px; }
.drop-chart__x.is-worst { color: var(--danger, #dc2626); font-weight: 700; }
.drop-chart__note {
  margin-top: 16px; padding: 12px 14px;
  border-left: 3px solid var(--accent, #d97706);
  background: var(--surface);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.drop-chart__note-title { font-size: 0.875rem; font-weight: 600; color: var(--text); margin: 0 0 4px; }
.drop-chart__note-flat { margin: 14px 0 0; }
.drop-chart__table { margin-top: 18px; }
.drop-chart__table tr.is-worst { background: var(--surface); }
.drop-chart__loss { color: var(--danger, #dc2626); font-weight: 600; }

.analytics-block { margin-bottom: 16px; }
.analytics-meter { display: flex; align-items: center; gap: 8px; }
.analytics-meter__bar { flex: 1; min-width: 60px; }
.analytics-weak { color: var(--accent, #d97706); font-weight: 600; }
.analytics-footnote { margin: 16px 2px 0; max-width: 90ch; }

/* ── Team-Cockpit (2026-08-30) ──
   Die Ampel sagt, was zu spät ist; die Warnzeichen daneben sagen, was gerade
   dabei ist, zu spät zu werden. Beides steht in derselben Zeile, aber optisch
   getrennt: Der Punkt links ist der Zustand, die Pillen darunter sind die
   Vorboten. */
.cockpit-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
.cockpit-tile { padding: 15px 18px; }
.cockpit-tile--danger  { border-left: 3px solid var(--danger, #dc2626); }
.cockpit-tile--accent  { border-left: 3px solid var(--accent, #d97706); }
.cockpit-tile--primary { border-left: 3px solid var(--primary); }
.cockpit-tile__value { font-size: 1.625rem; font-weight: 800; color: var(--text); line-height: 1; }
.cockpit-tile__label { font-size: 0.8125rem; color: var(--muted); margin-top: 4px; }

/* Die Kachel als Filter (2026-09-04). Sie bleibt eine Kachel und wird kein
   Knopf: gleiche Höhe, gleicher Text, keine Linkfarbe. Was sich ändert, ist der
   Zeiger und der Ring der gerade schneidenden Kachel, denn die Tabelle
   darunter sagt den Rest. */
.cockpit-tile--link { display: block; text-decoration: none; color: inherit; transition: box-shadow 0.12s ease, border-color 0.12s ease; }
.cockpit-tile--link:hover { box-shadow: var(--shadow-md); }
.cockpit-tile--link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Der Ring liegt außen und nicht auf dem Rahmen: Die farbige Kante links sagt,
   worum es geht, und die dürfte ein `border-color` überschreiben. */
.cockpit-tile.is-active { box-shadow: 0 0 0 2px var(--primary), 0 0 0 5px var(--ring); }
.cockpit-tile.is-active .cockpit-tile__label { color: var(--text); font-weight: 600; }

.cockpit-table-card { padding: 0; overflow-x: auto; }
.cockpit-table { min-width: 1040px; }
.cockpit-member { display: flex; align-items: flex-start; gap: 9px; }
.cockpit-member__name { font-weight: 600; color: var(--text); }
.cockpit-dot { width: 9px; height: 9px; border-radius: 50%; margin-top: 5px; flex-shrink: 0; }
.cockpit-dot--overdue  { background: var(--danger, #dc2626); }
.cockpit-dot--due_soon { background: var(--accent, #d97706); }
.cockpit-dot--ok       { background: var(--success, #16a34a); }
.cockpit-risks { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.cockpit-risk { font-size: 0.6875rem; }
.cockpit-day  { font-variant-numeric: tabular-nums; font-weight: 600; }
.cockpit-mood { white-space: nowrap; }
.cockpit-mood__face { font-size: 1.25rem; line-height: 1; }
.cockpit-path { min-width: 180px; }
.cockpit-path__bar  { margin-bottom: 5px; }
.cockpit-path__meta { font-size: 0.75rem; }
.cockpit-path__warn { color: var(--danger, #dc2626); font-weight: 600; font-size: 0.75rem; }
.cockpit-waiting    { font-weight: 600; }
.cockpit-actions    { justify-content: flex-end; gap: 6px; }
.cockpit-remind     { margin: 0; }
.cockpit-footnote   { margin: 12px 2px 0; max-width: 90ch; }

.cockpit-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; margin-top: 20px; }
.cockpit-group { padding: 10px 0; border-bottom: 1px solid var(--border); }
.cockpit-group:last-child { border-bottom: none; }
.cockpit-group__head { display: flex; align-items: center; gap: 8px; font-size: 0.875rem; font-weight: 700; color: var(--text); margin-bottom: 6px; }
.cockpit-task { padding: 5px 0 5px 10px; border-left: 2px solid var(--border); margin-bottom: 4px; }
.cockpit-task.is-overdue { border-left-color: var(--danger, #dc2626); }
.cockpit-task__title { font-size: 0.875rem; color: var(--text); }

/* Ein überfälliger Balken wird rot: Der Fortschritt ist derselbe, die Aussage
   eine andere. */
.progress-bar__fill--danger { background: var(--danger, #dc2626); }

/* ── Dashboard der ersten Wochen (Onboarding-Modus, 2026-08-30) ──
   Links der Weg, rechts die Menschen und die Termine. Die Aufteilung ist
   Absicht: Was links steht, liegt beim Ankommenden selbst; was rechts steht,
   liegt bei jemand anderem. */
.onb-grid { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: 22px; align-items: flex-start; }
.onb-main, .onb-side { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.onb-note { margin: 18px 0 0; }

.onb-next {
  border-left: 3px solid var(--primary);
}
.onb-next__eyebrow { margin-bottom: 8px; }
.onb-next__title   { font-size: 1.25rem; font-weight: 700; color: var(--text); line-height: 1.3; margin: 0 0 6px; }
.onb-next__meta    { margin: 0 0 18px; }
.onb-next__actions { display: flex; gap: 10px; flex-wrap: wrap; }

.onb-path__head { margin-bottom: 6px; font-size: 1rem; font-weight: 700; }
.onb-path__meta { margin-bottom: 8px; }
.onb-other__hint { margin: -4px 0 4px; }

.onb-person { display: flex; align-items: center; gap: 12px; padding: 9px 0; }
.onb-person__name { font-size: 0.875rem; font-weight: 600; color: var(--text); margin-bottom: 1px; }

.onb-event { display: flex; align-items: center; gap: 12px; padding: 10px 0; }
.onb-event--divided { border-bottom: 1px solid var(--border); }
.onb-event__date {
  width: 40px; flex-shrink: 0;
  display: flex; flex-direction: column; align-items: center;
  line-height: 1.1;
}
.onb-event__day   { font-size: 1.0625rem; font-weight: 800; color: var(--text); }
.onb-event__month { font-size: 0.625rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.onb-event__title { font-size: 0.875rem; font-weight: 600; color: var(--text); margin-bottom: 1px; }

.onb-checkin { display: flex; align-items: flex-start; gap: 10px; padding: 8px 0; }
.onb-checkin__dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; }
.onb-checkin__dot.is-waiting { background: var(--accent, #d97706); }
.onb-checkin__dot.is-back    { background: var(--danger, #dc2626); }
.onb-checkin__title { font-size: 0.875rem; font-weight: 600; color: var(--text); margin-bottom: 1px; }

.dash-empty            { padding: 12px 0; }
.dash-all-paths        { margin-top: 16px; }
.profile-stats--flush  { margin-bottom: 0; }

@media (max-width: 900px) {
  .onb-grid { grid-template-columns: minmax(0, 1fr); }
  .cockpit-split { grid-template-columns: minmax(0, 1fr); }
  .tm-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ── Responsive ── */
@media (max-width: 640px) {
  .site-header__inner { padding: 0 16px; gap: 16px; }
  .topnav { display: none; }
  .main-content { --content-pad: 20px; padding: 20px 16px; }
  /* Der Platz für die fixierte Bottom-Navigation (inkl. iOS-Safe-Area) hängt
     seit dem 2026-09-02 am Fuß und nicht mehr an der Inhaltsspalte: Er ist das
     Letzte auf der Seite und säße sonst hinter der Leiste. */
  .site-footer { padding: 18px 16px calc(18px + 76px + env(safe-area-inset-bottom, 0px)); }
  .auth-card { padding: 28px 20px; }

  /* Mehrspaltige Lerner-Layouts auf eine Spalte zusammenfalten. */
  .dash-grid, .dash-active-grid, .profile-split, .experts-split { grid-template-columns: minmax(0, 1fr); }
  .profile-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Pfad-Detail: Sidebar unter die Modulliste, volle Breite, nicht mehr sticky. */
  .path-layout { flex-direction: column; }
  .path-aside  { width: 100%; position: static; top: auto; }

  /* Höhere Spezifität als die spätere Basisregel `.bottom-nav { display:none }`,
     damit die Quell-Reihenfolge die Einblendung nicht aushebelt. */
  nav.bottom-nav { display: flex; }

  /* Der Rest der Telefon-Anpassungen steht am Dateiende („Telefon-Feinschliff"):
     er überschreibt Regeln, die erst weiter unten definiert werden, und käme von
     hier aus bei gleicher Spezifität nicht dagegen an. */
}

@media (min-width: 641px) and (max-width: 1024px) {
  .site-header__inner { padding: 0 24px; }
  .main-content { --content-pad: 24px; }
}

/* ── Bottom-Navigation (Mobile) ──
   Erscheint nur < 640px (dort wird die Top-Nav ausgeblendet). Fünf Slots:
   Lernen · Entdecken · Suche · Community · Mehr (Sheet). */
.bottom-nav {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  background: var(--white); border-top: 1px solid var(--border);
  padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -2px 12px rgba(0,0,0,0.05);
}
.bottom-nav__item {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 4px 2px; background: none; border: none; cursor: pointer;
  font-family: var(--fh); font-size: 0.625rem; font-weight: 600;
  color: var(--muted); text-decoration: none; position: relative; min-width: 0;
}
.bottom-nav__item svg { width: 22px; height: 22px; }
.bottom-nav__item.active { color: var(--primary); }
.bottom-nav__item span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bottom-nav__dot {
  position: absolute; top: 2px; right: calc(50% - 16px);
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--danger, #dc2626); box-shadow: 0 0 0 2px var(--white);
}

/* ── „Mehr“-Bottom-Sheet ── */
.bottom-sheet { position: fixed; inset: 0; z-index: 200; display: none; }
.bottom-sheet.open { display: block; }
.bottom-sheet__bd { position: absolute; inset: 0; background: rgba(0,0,0,0.4); }
.bottom-sheet__panel {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: var(--white); border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding: 8px 8px calc(12px + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -4px 24px rgba(0,0,0,0.18); max-height: 80vh; overflow-y: auto;
}
.bottom-sheet__grip { width: 36px; height: 4px; border-radius: 2px; background: var(--border); margin: 8px auto 10px; }
.bottom-sheet__item {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 13px 14px; border: none; background: none; cursor: pointer;
  font-family: var(--fh); font-size: 0.9375rem; color: var(--text);
  text-decoration: none; text-align: left; border-radius: var(--r-sm);
}
.bottom-sheet__item:hover, .bottom-sheet__item:active { background: var(--surface); }
.bottom-sheet__item svg { flex-shrink: 0; }
.bottom-sheet__item--danger { color: var(--danger); }
.bottom-sheet__sep { height: 1px; background: var(--border); margin: 6px 8px; }
/* Abschnitts-Überschrift im Sheet. Auf dem Telefon steht die ganze Navigation
   untereinander, und ohne diese Zwischenzeilen wäre nicht zu sehen, wo „Lernen"
   aufhört und „Personal" anfängt. */
.bottom-sheet__label {
  padding: 10px 14px 4px;
  font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
}
/* Ein zusammengefasster Eintrag steht im Sheet mit seinen Reitern: Auf dem
   Telefon gibt es keine Zeile darunter, auf der sie sonst erschienen. Die
   Zwischenzeile ist deshalb leiser als die des Abschnitts über ihr. */
.bottom-sheet__label--sub {
  padding-top: 6px;
  text-transform: none;
  letter-spacing: 0;
  font-size: 0.75rem;
}
.bottom-sheet__item--sub { padding-left: 28px; color: var(--muted); }

/* ── User Dropdown ── */
.user-dropdown { position: relative; }

.user-dropdown__menu {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 220px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
  z-index: 100;
  overflow: hidden;
}
.user-dropdown.open .user-dropdown__menu { display: block; }

.user-dropdown__header {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 16px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 0.875rem;
}

.user-dropdown__item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 16px;
  font-size: 0.875rem;
  color: var(--text);
  text-decoration: none;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  transition: background 0.12s;
}
.user-dropdown__item:hover { background: var(--surface); }
.user-dropdown__item--danger { color: var(--danger); }
.user-dropdown__item--danger:hover { background: var(--danger-bg); }
/* Haarlinie zwischen den drei Gruppen des Menüs: eigene Flächen, Schalter,
   Abmelden. Sie trennt und benennt nicht, und anders als in der zweiten
   Navigationszeile ist das hier richtig, denn drei Gruppen mit Überschriften
   wären in einem Aufklappmenü mit acht Zeilen mehr Apparat als Inhalt. */
.user-dropdown__sep { height: 1px; background: var(--border); margin: 4px 0; }
.user-dropdown__name { font-weight: 700; color: var(--text); }
.user-dropdown__mail { font-size: 0.75rem; color: var(--muted); }
/* Das Abmelden-Formular ist nur Hülle für seinen Knopf und darf keine eigene
   Höhe in die Menüliste bringen. */
.user-dropdown__form { margin: 0; }

/* Das Abzeichen im „Mehr"-Sheet steht in der Zeile statt an der Glocke: dort
   trägt es kein Symbol, an dem es hängen könnte, sondern schließt die Zeile ab. */
.notif-badge--inline { position: static; margin-left: auto; box-shadow: none; }

/* Theme-Toggle: zeigt die jeweils umschaltbare Option (Light-/Dark-Segment).
   Rein CSS-gesteuert über html.dark — kein JS-Text-Handling nötig. */
.theme-seg { display: flex; align-items: center; gap: inherit; }
.theme-seg--dark { display: none; }
html.dark .theme-seg--light { display: none; }
html.dark .theme-seg--dark { display: flex; }

/* ── Admin CRUD (Sprint 8) ── */
.admin-table { width:100%; border-collapse:collapse; background:var(--white); border:1px solid var(--border); border-radius:var(--r-md); overflow:hidden; }
.admin-table th { text-align:left; font-size:0.75rem; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:0.04em; padding:12px 16px; border-bottom:1px solid var(--border); }
.admin-table td { padding:13px 16px; border-bottom:1px solid var(--border); font-size:0.9375rem; }
.admin-table tr:last-child td { border-bottom:none; }
.admin-table tbody tr:hover td { background:var(--surface); }
.admin-link { font-weight:600; color:var(--text); text-decoration:none; }
.admin-link:hover { color:var(--primary); }
/* Öffnet der Klick ein Modal statt einer Seite, ist das Element ein Button und
   muss trotzdem wie ein Link aussehen — sonst steht mitten in der Tabellenzeile
   ein grauer Kasten. */
button.admin-link { background:none; border:0; padding:0; font:inherit; font-weight:600; text-align:left; cursor:pointer; }
/* CALTRIX-89: `wrap`, seit die Medien-Registry drei Aktionen je Zeile trägt.
   Acht Spalten und ein Titel über die volle Länge lassen der letzten Spalte
   keine drei Knöpfe nebeneinander; ohne Umbruch schiebt sie die Tabelle über den
   Bildschirmrand, und ausgerechnet „Löschen" landet draußen. Rechtsbündig
   bleibt es dabei, der zweite Knopf rutscht also unter den ersten. */
.row-actions { display:flex; flex-wrap:wrap; gap:8px; justify-content:flex-end; align-items:center; }
.admin-toolbar { display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin:16px 0 22px; }
.admin-input { padding:8px 12px; border:1px solid var(--border); border-radius:var(--r-sm); font-family:var(--fh); font-size:0.9375rem; background:var(--white); }
.admin-input:focus { outline:none; border-color:var(--primary); box-shadow:0 0 0 3px var(--ring); }
/* Der Hintergrund scrollt selbst, damit ein Dialog, der höher ist als der
   Bildschirm, erreichbar bleibt statt oben und unten hinauszuragen. Auf dem
   Telefon ist das der Regelfall: Support-Anfrage und Melde-Dialog tragen beide
   ein mehrzeiliges Textfeld. `padding` hält ihn von den Rändern frei. */
.admin-modal-bd { position:fixed; inset:0; background:rgba(0,0,0,0.4); display:none; align-items:center; justify-content:center; z-index:200; overflow-y:auto; padding:16px; }
.admin-modal-bd.open { display:flex; }
.admin-modal { background:var(--white); border-radius:var(--r-lg); padding:24px; width:460px; max-width:100%; max-height:calc(100vh - 32px); overflow-y:auto; box-shadow:var(--shadow-md); }
/* Breite Modal-Variante (z. B. Modul-Komposition mit eingebetteter Medien-Tabelle). */
.admin-modal--lg { width:920px; max-height:90vh; overflow-y:auto; }
/* Sehr breite Variante für mehrspaltige Formulare (Medien-Registry): zwanzig
   Felder untereinander liefen unten aus dem Bildschirm heraus.

   Gescrollt wird NUR der Feldbereich, nicht das ganze Modal: Überschrift und
   Aktionsleiste bleiben stehen. Auf einem flachen Bildschirm reicht die Höhe
   für zwanzig Felder auch dreispaltig nicht immer — der Speichern-Knopf muss
   trotzdem ohne Scrollen erreichbar sein. */
.admin-modal--xl { width:1180px; max-height:90vh; display:flex; flex-direction:column; overflow:hidden; }
.admin-modal--xl > form { display:flex; flex-direction:column; flex:1; min-height:0; }
.admin-modal--xl .form-cols { flex:1; min-height:0; overflow-y:auto; padding-right:6px; }
.admin-modal--xl .admin-modal-actions { flex-shrink:0; padding-top:14px; border-top:1px solid var(--border); }

/* Mehrspaltiges Formular. `auto-fit` faltet die Spalten bei schmalem Fenster von
   selbst untereinander, ohne eigene Media-Query. */
.form-cols { display:grid; grid-template-columns:repeat(auto-fit, minmax(270px, 1fr)); gap:0 28px; align-items:start; }
.form-cols .admin-form-field { margin-bottom:11px; }
.form-col { min-width:0; }
.form-col__title {
  font-size:0.75rem; font-weight:700; color:var(--muted);
  text-transform:uppercase; letter-spacing:0.04em;
  margin:0 0 12px; padding-bottom:7px; border-bottom:1px solid var(--border);
}
.field-hint { margin-top:4px; font-size:0.75rem; line-height:1.45; color:var(--muted); }

/* Ein `fieldset`, das nur da ist, um seinen Inhalt stillzulegen: Der Browser reicht
   `disabled` an alles darin weiter, und damit kann keine Zeile vergessen werden.
   Sichtbar sein soll er nicht, deshalb fällt sein eigener Rahmen weg. `min-width:0`
   ist dabei nicht Kosmetik: Ein `fieldset` trägt von sich aus eine Mindestbreite nach
   seinem Inhalt, und ein Raster darin (`.form-cols`) käme sonst nicht unter die
   Fensterbreite zurück. */
.form-lock { border:0; padding:0; margin:0; min-width:0; }
/* Ein deaktiviertes Feld ist blass genug; der ganze Block soll nicht auch noch
   verschwinden, denn nachlesen ist ausdrücklich erlaubt. */
.form-lock:disabled { opacity:0.85; }

/* Der Titel einer Zeile, der irgendwohin führt. Er sieht aus wie Text und verrät
   sich beim Zeigen, denn eine Tabelle voller unterstrichener Titel liest sich als
   Linkliste und nicht als Bestand. */
.row-title { color:inherit; text-decoration:none; }
.row-title:hover { color:var(--primary); text-decoration:underline; }
.admin-modal h3 { font-size:1.125rem; font-weight:800; margin-bottom:16px; }
/* Kompakte Tabelle innerhalb eines Modals (Medien-Auswahl). */
.modal-table { width:100%; border-collapse:collapse; font-size:0.8125rem; }
.modal-table th { text-align:left; padding:6px 8px; color:var(--muted); font-weight:600; border-bottom:1px solid var(--border); position:sticky; top:0; background:var(--white); }
.modal-table td { padding:6px 8px; border-bottom:1px solid var(--border); vertical-align:middle; }
.modal-table tr:hover td { background:var(--surface,#f6f7f9); }
.modal-table-wrap { max-height:38vh; overflow-y:auto; border:1px solid var(--border); border-radius:var(--r-sm); }
.compose-toolbar { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-bottom:10px; }
.compose-toolbar input, .compose-toolbar select { padding:7px 10px; border:1px solid var(--border); border-radius:var(--r-sm); font-family:var(--fh); font-size:0.875rem; }
/* Aktuelle Modul-Komposition: kontrastreiche Karten, damit klar erkennbar ist, was enthalten ist. */
.compose-attached { display:flex; flex-direction:column; gap:6px; margin-bottom:18px; }
.compose-row { display:flex; align-items:center; gap:8px; padding:8px 12px; border:1px solid var(--border); border-left:3px solid var(--primary); border-radius:var(--r-sm); background:var(--surface,#f6f7f9); }
.compose-row .compose-row-title { flex:1; font-weight:600; color:var(--text); }
.compose-row .compose-row-meta { font-weight:400; color:var(--muted); font-size:0.75rem; }
/* Toggle „Inhalte hinzufügen“: Bibliotheks-Bereich erst auf Klick. */
.compose-library[hidden] { display:none; }
.admin-form-field { margin-bottom:14px; }
.admin-form-field label { display:block; font-size:0.8125rem; font-weight:600; color:var(--text); margin-bottom:5px; }
.admin-form-field input, .admin-form-field select, .admin-form-field textarea { width:100%; padding:8px 12px; border:1px solid var(--border); border-radius:var(--r-sm); font-family:var(--fh); font-size:0.9375rem; }
.admin-form-field input:focus, .admin-form-field select:focus, .admin-form-field textarea:focus { outline:none; border-color:var(--primary); box-shadow:0 0 0 3px var(--ring); }
.admin-modal-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:18px; }

/* Suchfeld über einer langen Auswahlliste (partials/option-filter). Steht dicht
   über seinem Select und tritt kleiner auf als das Feld, das es filtert — es ist
   ein Werkzeug an der Eingabe und nicht selbst eine. */
.option-filter { margin-bottom:5px; font-size:0.8125rem !important; padding:6px 10px !important; }

/* ── Formularfelder (.form-control) ──
   Die Klasse stand im Markup, hatte aber nirgends eine Regel: die Felder in
   „Mein Vorwissen", „Meine Entwicklung", im Profil und im Pfad-Editor kamen
   als nackte Browser-Standards heraus, mitten in einer sonst gestalteten
   Oberfläche. Die Werte entsprechen `.admin-form-field`, damit ein Feld überall
   gleich aussieht. */
.form-control {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--white);
  color: var(--text);
  font-family: var(--fh);
  font-size: 0.9375rem;
  line-height: 1.4;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.form-control:hover:not(:disabled) { border-color: var(--primary-border); }
.form-control:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.form-control:disabled { background: var(--surface); color: var(--muted); cursor: not-allowed; }
/* Ungültige Eingabe erst melden, wenn wirklich etwas dasteht — ein leeres
   Pflichtfeld beim Betreten der Seite rot zu färben, hilft niemandem. */
.form-control:not(:placeholder-shown):invalid { border-color: var(--danger); }

/* Auswahlfelder tragen einen eigenen Pfeil: der native ist je nach Browser und
   Betriebssystem ein anderer und passt in keinem davon zur Umgebung. Die Farbe
   steckt in der Grafik, deshalb je Thema eine eigene. */
:root    { --select-arrow: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236c869e' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); }
html.dark { --select-arrow: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2393a6b8' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); }

select.form-control {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 34px;
  background-image: var(--select-arrow);
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 16px 16px;
  cursor: pointer;
}
select.form-control:focus { background-image: var(--select-arrow); }
/* Mehrzeilige Auswahl klappt nicht auf und braucht deshalb keinen Pfeil. */
select.form-control[multiple], select.form-control[size]:not([size="1"]) {
  appearance: auto; -webkit-appearance: auto; padding-right: 12px; background-image: none;
}
textarea.form-control { resize: vertical; min-height: 76px; }
/* Ein Feld für eine Zahl braucht nicht die Breite eines Satzes. */
input[type="number"].form-control { max-width: 220px; }
/* Der Hinweis unter einem Feld ist `.field-hint` (siehe oben); über dem Feld
   braucht er den Abstand nach unten statt nach oben. */
.field-hint--above { margin-top: 0; margin-bottom: 6px; }

/* Ein Knopf, der wie Text aussieht. Für Stellen, an denen etwas anklickbar
   ist, ohne dass daraus eine Schaltfläche werden soll — die Tageszeile der
   Zeiterfassung etwa, die das Formular darüber füllt. Ein <button> und kein
   <a> oder <span>: Tastatur und Screenreader sollen ihn finden. */
.btn-plain {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  border-bottom: 1px dashed var(--border);
}
.btn-plain:hover { color: var(--primary); border-bottom-color: var(--primary); }
.btn-plain:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 2px; }

/* ── Eine Reihe gleichrangiger Felder (.field-row) ──
   Für Einstellungsmasken, in denen mehrere Felder nebeneinander stehen und
   nicht jedes gleich viel Erklärung braucht.

   `align-items: start` ist der Kern und war der Fehler: Mit `end` richtet sich
   jedes Feld am FUSS der Reihe aus, und weil die Hinweise unterschiedlich lang
   sind, rutscht ein Feld ohne Hinweis nach unten. Beschriftung und Eingabe
   stehen dann auf drei verschiedenen Höhen, obwohl sie eine Reihe sein sollen.
   Oben ausgerichtet liegen Label und Eingabefeld auf einer Linie, und die
   Hinweise dürfen darunter unterschiedlich weit hängen. */
.field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px 18px;
  align-items: start;
}
.field-row > .form-field { display: flex; flex-direction: column; min-width: 0; }
/* Zahlen dürfen schmal bleiben, ohne dass ihre Spalte einläuft. */
.field-row input[type="number"], .field-row input[type="time"] { max-width: 100%; }

/* Was die Reihe abschließt und keine eigene Spalte ist: ein Schalter, ein
   Hinweis, die Schaltfläche. In der Reihe stünde die Schaltfläche als
   vierte oder fünfte Spalte und sähe aus wie ein weiteres Feld. */
.field-row__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border);
}
.field-row__foot .field-hint { margin-top: 0; flex: 1 1 320px; }
.field-row__check { display: flex; align-items: center; gap: 8px; }
.field-row__check .form-label { margin: 0; }
/* Pflichtfeld-Kennzeichnung. Ein Stern am Label, dazu einmal pro Formular die
   Legende — ohne sie ist ein Stern nur ein Zeichen. `aria-hidden` wäre falsch:
   Screenreader lesen ihn vor, und das ist genau die Information. */
.req { color: var(--danger); font-weight: 700; margin-left: 2px; }

/* Mehrspaltiges Formular mit den regulären `.form-group`-Feldern (Veranstaltungs-
   Maske): 18 px Abstand je Feld sind in drei Spalten zu viel Luft. */
.form-cols .form-group { margin-bottom: 14px; }
.form-cols .form-group:last-child { margin-bottom: 0; }

/* ── Filterbare Mehrfachauswahl (`.picker`) ──
   Für Auswahllisten, die zu lang für ein <select multiple> sind: Suchfeld,
   scrollende Liste mit Ankreuzfeldern, Zähler. Gefiltert wird durch Verstecken
   (public/js/event-form.js), damit eine ausgeblendete Zeile angehakt bleibt. */
.picker { border:1px solid var(--border); border-radius:var(--r-sm); background:var(--white); overflow:hidden; }
.picker__head { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:8px 10px; border-bottom:1px solid var(--border); background:var(--surface,#f6f7f9); }
.picker__filter { flex:1; min-width:160px; padding:6px 10px; border:1px solid var(--border); border-radius:var(--r-sm); font-family:var(--fh); font-size:0.875rem; background:var(--white); color:var(--text); }
.picker__filter:focus { outline:none; border-color:var(--primary); box-shadow:0 0 0 3px var(--ring); }
.picker__only { display:flex; align-items:center; gap:6px; font-size:0.8125rem; color:var(--muted); cursor:pointer; white-space:nowrap; }
.picker__only input { width:auto; }
.picker__list { max-height:240px; overflow-y:auto; }
.picker__row { display:flex; align-items:center; gap:9px; padding:6px 12px; font-size:0.875rem; color:var(--text); cursor:pointer; }
.picker__row:hover { background:var(--surface,#f6f7f9); }
.picker__row input { width:auto; flex-shrink:0; }
.picker__row[hidden] { display:none; }
.picker__empty { padding:12px; margin:0; font-size:0.8125rem; color:var(--muted); }
.picker__empty[hidden] { display:none; }
.picker__count { padding:7px 12px; margin:0; border-top:1px solid var(--border); font-size:0.75rem; color:var(--muted); }

/* Klickbare Sortier-Header (Tabellen-Übersichten) */
.sort-link { color:inherit; text-decoration:none; display:inline-flex; align-items:center; gap:4px; }
.sort-link:hover { color:var(--primary); }
.sort-link .sort-arrow { font-size:0.625rem; color:var(--primary); }
/* Produkt-Kacheln auf dem Dashboard („Deine Produkte", partials/product-tiles).
   Sie hatten nie eine Regel und standen deshalb untereinander — ein `div` ohne
   Layout ist eine Spalte, und die Kacheln sahen aus wie eine Liste. */
.product-tiles { display:grid; grid-template-columns:repeat(auto-fit, minmax(230px, 1fr)); gap:16px; }
.product-tile { display:block; padding:18px 20px; text-decoration:none; color:inherit; transition:border-color 0.15s, box-shadow 0.15s; }
.product-tile:hover { border-color:var(--primary); box-shadow:var(--shadow-sm); }
.product-tile__icon { display:flex; align-items:center; justify-content:center; width:38px; height:38px; border-radius:var(--r-sm); background:var(--surface); color:var(--primary); margin-bottom:12px; }
.product-tile__title { font-size:1rem; font-weight:700; color:var(--text); }
.product-tile__desc { font-size:0.875rem; line-height:1.5; color:var(--muted); margin:4px 0 0; }

/* Kopfzahlen der Lernakte (gesamt / läuft ab / abgelaufen). */
.record-kpis { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:14px; margin-bottom:22px; }
.record-kpis .detail-card { margin-bottom:0; text-align:center; }
.detail-card { background:var(--white); border:1px solid var(--border); border-radius:var(--r-md); padding:20px; margin-bottom:18px; }
.detail-card__title { font-size:0.875rem; font-weight:700; color:var(--text); margin-bottom:14px; }
.detail-row { display:flex; align-items:center; justify-content:space-between; padding:9px 0; border-bottom:1px solid var(--border); gap:10px; }
.detail-row:last-child { border-bottom:none; }
.detail-label { font-size:0.875rem; color:var(--muted); }

/* ── Modul-Interaktionen (Lerner) ── */
.mod-int-btn { background:var(--white); border:1px solid var(--border); border-radius:var(--r-full); padding:3px 10px; font-size:0.75rem; font-weight:600; color:var(--muted); cursor:pointer; font-family:var(--fh); transition:all 0.12s; }
.mod-int-btn:hover { border-color:var(--primary); color:var(--primary); }
.mod-int-btn.is-on { background:var(--primary); color:#fff; border-color:var(--primary); }

/* ── In-App-Hilfe ── */
.help-card { display:flex; gap:14px; align-items:flex-start; background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg); padding:18px; text-decoration:none; color:var(--text); transition:border-color 0.12s, box-shadow 0.12s, transform 0.12s; }
.help-card:hover { border-color:var(--primary); box-shadow:0 4px 16px rgba(0,0,0,0.05); transform:translateY(-1px); }
.help-card__icon { flex-shrink:0; width:42px; height:42px; border-radius:var(--r-md); background:var(--surface); color:var(--primary); display:flex; align-items:center; justify-content:center; }
.help-row { display:flex; align-items:center; justify-content:space-between; gap:14px; background:var(--white); border:1px solid var(--border); border-radius:var(--r-md); padding:14px 16px; text-decoration:none; color:var(--text); transition:border-color 0.12s, background 0.12s; }
.help-row:hover { border-color:var(--primary); background:var(--surface); }
.help-article { color:var(--text); line-height:1.65; }
.help-article h2 { font-size:1.15rem; font-weight:700; margin:26px 0 8px; }
.help-article h3 { font-size:1rem; font-weight:700; margin:18px 0 6px; }
.help-article p { margin:10px 0; }
.help-article ul { margin:10px 0; padding-left:22px; }
.help-article li { margin:5px 0; }
.help-article a { color:var(--primary); font-weight:600; }
.help-article code { background:var(--surface); border:1px solid var(--border); border-radius:6px; padding:1px 5px; font-size:0.85em; }
.help-article pre { background:#1e293b; color:#e2e8f0; border-radius:var(--r-md); padding:14px 16px; overflow-x:auto; margin:12px 0; }
.help-article pre code { background:none; border:none; padding:0; color:inherit; font-size:0.82rem; }

/* ── Pagination (kompakt, FS-3) ── */
.pagination { display:flex; align-items:center; gap:8px; }
.pagination__link { display:inline-flex; align-items:center; justify-content:center; min-width:32px; height:32px; padding:0 8px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--white); color:var(--text); text-decoration:none; font-size:1rem; line-height:1; transition:border-color 0.12s, color 0.12s; }
.pagination__link:hover { border-color:var(--primary); color:var(--primary); }
.pagination__link--disabled { color:var(--muted); opacity:0.5; pointer-events:none; }
.pagination__info { font-size:0.8125rem; color:var(--muted); }

/* ── Personen-Live-Suche (FS-3) ── */
.person-search__results { position:absolute; top:calc(100% + 4px); left:0; right:0; background:var(--white); border:1px solid var(--border); border-radius:var(--r-md); box-shadow:var(--shadow-md); z-index:50; max-height:360px; overflow-y:auto; }
.person-search__row { display:block; padding:10px 14px; text-decoration:none; color:var(--text); border-bottom:1px solid var(--border); }
.person-search__row:last-child { border-bottom:none; }
.person-search__row:hover { background:var(--surface); }
.person-search__empty { padding:12px 14px; color:var(--muted); font-size:0.875rem; }

/* ── Kalender: Listenansicht (Core-Komponente <x-calendar.list>) ── */
.cal-list { display:flex; flex-direction:column; }
.cal-list__item { display:flex; align-items:center; gap:16px; padding:14px 16px; border-radius:var(--r-md); text-decoration:none; color:inherit; transition:background 0.12s; }
.cal-list__item + .cal-list__item { border-top:1px solid var(--border); }
a.cal-list__item:hover { background:var(--surface); }
.cal-list__date { flex-shrink:0; width:54px; text-align:center; display:flex; flex-direction:column; line-height:1.05; }
.cal-list__day { font-size:1.5rem; font-weight:800; color:var(--text); }
.cal-list__month { font-size:0.6875rem; font-weight:700; text-transform:uppercase; letter-spacing:0.05em; color:var(--primary); }
.cal-list__body { min-width:0; }
.cal-list__title { font-weight:700; color:var(--text); margin-bottom:2px; }
.cal-list__time { font-size:0.8125rem; color:var(--muted); }
.cal-list__empty { padding:28px 16px; text-align:center; color:var(--muted); font-size:0.9375rem; }

/* ── Kalender: Monatsansicht (Core-Komponente <x-calendar.month>) ── */
.cal-month__head { margin-bottom:10px; }
.cal-month__title { font-size:1.0625rem; font-weight:700; color:var(--text); }
.cal-month__weekdays { display:grid; grid-template-columns:repeat(7,1fr); gap:1px; margin-bottom:6px; }
.cal-month__weekday { text-align:center; font-size:0.75rem; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:0.04em; padding:4px 0; }
.cal-month__grid { display:grid; grid-template-columns:repeat(7,1fr); gap:1px; background:var(--border); border:1px solid var(--border); border-radius:var(--r-md); overflow:hidden; }
.cal-month__cell { background:var(--white); min-height:104px; padding:6px 7px; display:flex; flex-direction:column; gap:4px; }
.cal-month__cell--muted { background:var(--surface); }
.cal-month__cell--muted .cal-month__daynum { color:var(--muted); opacity:0.55; }
.cal-month__daynum { align-self:flex-start; font-size:0.8125rem; font-weight:600; color:var(--text); }
.cal-month__cell--today .cal-month__daynum { display:inline-flex; align-items:center; justify-content:center; min-width:22px; height:22px; padding:0 6px; border-radius:var(--r-full); background:var(--primary); color:#fff; }
.cal-month__event { display:block; font-size:0.6875rem; font-weight:600; line-height:1.3; padding:2px 6px; border-radius:6px; background:var(--primary-light); color:var(--primary); text-decoration:none; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
a.cal-month__event:hover { background:var(--primary); color:#fff; }

@media (max-width:640px) {
  .cal-month__cell { min-height:64px; padding:4px; }
  .cal-month__weekday { font-size:0.625rem; }
  .cal-month__event { font-size:0.625rem; padding:1px 4px; }
}

/* ============================================================
   Onboarding-Journey (T20 S15) — Lerner-Zeitachse
   Phasen-Stepper, „Dein nächster Schritt", Fälligkeits-Chips,
   Pre-Boarding-Willkommen und die neuen Bausteine (Checkliste,
   Reflexion, Meilenstein). Rein semantische Klassen auf den
   bestehenden Tokens, damit Light/Dark ohne Sonderfall tragen.
   ============================================================ */

/* --- Nächster Schritt: die eine Karte, die den Blick fängt --- */
.next-step {
  display:flex; align-items:center; gap:18px; flex-wrap:wrap;
  background:var(--white); border:1px solid var(--primary-border);
  border-left:4px solid var(--primary);
  border-radius:var(--r-lg); padding:20px 22px; margin-bottom:24px;
  box-shadow:var(--shadow-sm);
}
.next-step--overdue { border-color:var(--danger-border); border-left-color:var(--danger); }
.next-step--done { border-color:var(--success-border); border-left-color:var(--success); }
.next-step__body { flex:1; min-width:220px; }
.next-step__eyebrow {
  display:flex; align-items:center; gap:7px; font-size:0.6875rem; font-weight:700;
  text-transform:uppercase; letter-spacing:0.07em; color:var(--primary); margin-bottom:6px;
}
.next-step--overdue .next-step__eyebrow { color:var(--danger); }
.next-step--done .next-step__eyebrow { color:var(--success); }
.next-step__title { font-size:1.125rem; font-weight:800; color:var(--text); line-height:1.25; margin:0 0 6px; }
.next-step__meta { display:flex; align-items:center; flex-wrap:wrap; gap:6px 14px; font-size:0.8125rem; color:var(--muted); }
/* Umbrechend, weil beide Beschriftungen aus der Übersetzung kommen und keine
   feste Länge haben — auf 320 px passen „Jetzt starten" und „In der Liste
   zeigen" nicht nebeneinander. */
.next-step__actions { display:flex; gap:8px; align-items:center; flex-wrap:wrap; flex-shrink:0; }

/* --- Pfad-Details auf-/zuklappen: alles unter dem nächsten Schritt ---
   Bewusst ein unauffälliger Textknopf und keine Karte: er trennt zwei
   Bereiche und soll nicht mit dem nächsten Schritt um Aufmerksamkeit
   ringen. Die beiden Labels stehen beide im HTML; welches gilt,
   entscheidet aria-expanded — so bleibt der Zustand für Screenreader
   und CSS dieselbe Quelle. */
.details-toggle {
  display:flex; align-items:center; gap:9px; flex-wrap:wrap;
  width:100%; margin:-8px 0 22px; padding:9px 12px;
  background:transparent; border:1px solid transparent; border-radius:var(--r-md);
  font-family:inherit; font-size:0.8125rem; font-weight:700; color:var(--muted);
  text-align:left; cursor:pointer; transition:background 0.15s, color 0.15s, border-color 0.15s;
}
.details-toggle:hover { background:var(--surface); border-color:var(--border); color:var(--primary); }
.details-toggle:focus-visible { outline:2px solid var(--primary); outline-offset:2px; }
.details-toggle__chevron { flex-shrink:0; transition:transform 0.18s ease; }
.details-toggle[aria-expanded="false"] .details-toggle__chevron { transform:rotate(-90deg); }
.details-toggle[aria-expanded="true"]  .details-toggle__label--collapsed { display:none; }
.details-toggle[aria-expanded="false"] .details-toggle__label--expanded  { display:none; }
.details-toggle__hint { font-weight:400; font-size:0.75rem; color:var(--muted); }

/* --- Phasen-Stepper: die Zeitachse als Ganzes --- */
.journey-steps {
  display:flex; gap:10px; margin-bottom:26px; overflow-x:auto; padding-bottom:4px;
  scrollbar-width:thin;
}
.journey-step {
  flex:1 1 0; min-width:132px; text-decoration:none; color:inherit;
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-md);
  padding:12px 14px; display:flex; flex-direction:column; gap:8px;
  transition:border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.journey-step:hover { border-color:var(--primary); transform:translateY(-1px); box-shadow:var(--shadow-sm); }
.journey-step.is-current { border-color:var(--primary); box-shadow:0 0 0 3px var(--ring); }
.journey-step.is-complete { background:var(--success-bg); border-color:var(--success-border); }
.journey-step.is-overdue { border-color:var(--danger-border); }
.journey-step__head { display:flex; align-items:center; justify-content:space-between; gap:8px; }
.journey-step__label { font-size:0.8125rem; font-weight:700; color:var(--text); }
.journey-step.is-complete .journey-step__label { color:var(--success); }
.journey-step__badge {
  flex-shrink:0; width:18px; height:18px; border-radius:50%; display:inline-flex;
  align-items:center; justify-content:center; background:var(--surface); color:var(--muted);
  border:1.5px solid var(--border);
}
.journey-step.is-complete .journey-step__badge { background:var(--success); border-color:var(--success); color:#fff; }
.journey-step.is-current .journey-step__badge { border-color:var(--primary); background:var(--primary-light); color:var(--primary); }
.journey-step__count { font-size:0.75rem; color:var(--muted); }
.journey-step__bar { height:4px; border-radius:2px; background:var(--border); overflow:hidden; }
.journey-step__fill { height:100%; border-radius:2px; background:var(--primary); transition:width 0.3s; }
.journey-step.is-complete .journey-step__fill { background:var(--success); }

/* --- Phasen-Abschnitt in der Modulliste --- */
.journey-phase { margin-bottom:6px; }
.journey-phase__head {
  display:flex; align-items:baseline; justify-content:space-between; gap:12px; flex-wrap:wrap;
  padding:18px 0 10px;
}
.journey-phase:not(:first-child) .journey-phase__head { border-top:1px solid var(--border); margin-top:10px; }
.journey-phase__title { display:flex; align-items:center; gap:9px; font-size:0.9375rem; font-weight:800; color:var(--text); margin:0; }
.journey-phase__dot {
  width:9px; height:9px; border-radius:50%; background:var(--border); flex-shrink:0;
}
.journey-phase.is-current .journey-phase__dot { background:var(--primary); box-shadow:0 0 0 4px var(--ring); }
.journey-phase.is-complete .journey-phase__dot { background:var(--success); }
.journey-phase__meta { font-size:0.75rem; color:var(--muted); display:flex; align-items:center; gap:10px; flex-wrap:wrap; }

/* --- Fälligkeits-Chip am Baustein --- */
.due-chip {
  display:inline-flex; align-items:center; gap:4px; font-size:0.6875rem; font-weight:700;
  padding:2px 9px; border-radius:var(--r-full);
  background:var(--surface); color:var(--muted); border:1px solid var(--border);
}
.due-chip--soon { background:var(--warning-bg); color:var(--warning-text); border-color:var(--warning-border); }
.due-chip--overdue { background:var(--danger-bg); color:var(--danger); border-color:var(--danger-border); }
.due-chip--done { background:var(--success-bg); color:var(--success); border-color:var(--success-border); }

/* --- Pre-Boarding: Willkommen vor dem ersten Tag --- */
.preboarding {
  border-radius:var(--r-lg); padding:26px 28px; margin-bottom:24px; color:#fff;
  background:var(--primary-dark);
  background-image:linear-gradient(135deg, rgba(255,255,255,0.16), rgba(0,0,0,0.28));
}
.preboarding__eyebrow { font-size:0.6875rem; font-weight:700; text-transform:uppercase; letter-spacing:0.08em; opacity:0.85; margin-bottom:8px; }
.preboarding__title { font-size:1.375rem; font-weight:800; letter-spacing:-0.02em; margin:0 0 8px; line-height:1.2; }
.preboarding__text { font-size:0.9375rem; opacity:0.92; line-height:1.6; margin:0 0 16px; max-width:62ch; }
.preboarding__countdown { display:flex; align-items:baseline; gap:10px; }
.preboarding__days { font-size:2.5rem; font-weight:800; line-height:1; }
.preboarding__unit { font-size:0.875rem; opacity:0.9; }

/* --- Abschluss-Feier + Folgepfad --- */
.journey-finish {
  background:var(--success-bg); border:1px solid var(--success-border);
  border-radius:var(--r-lg); padding:24px 26px; margin-bottom:24px;
}
.journey-finish__title { display:flex; align-items:center; gap:9px; font-size:1.125rem; font-weight:800; color:var(--success); margin:0 0 6px; }
.journey-finish__text { font-size:0.9375rem; color:var(--text); margin:0 0 16px; max-width:62ch; }
.journey-finish__next {
  display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap;
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-md); padding:16px 18px;
}
.journey-finish__label { font-size:0.6875rem; font-weight:700; text-transform:uppercase; letter-spacing:0.07em; color:var(--muted); margin-bottom:3px; }
.journey-finish__path { font-size:1rem; font-weight:700; color:var(--text); }

/* --- Zeitachsen-Karte in der Seitenleiste --- */
.timeline-card__day { display:flex; align-items:baseline; gap:8px; margin-bottom:12px; }
.timeline-card__num { font-size:2rem; font-weight:800; color:var(--primary); line-height:1; }
.timeline-card__unit { font-size:0.8125rem; color:var(--muted); }

/* --- Checkliste als Baustein --- */
.checklist { display:flex; flex-direction:column; gap:2px; }
.checklist__row {
  display:flex; align-items:flex-start; gap:11px; padding:9px 11px; border-radius:var(--r-sm);
  cursor:pointer; transition:background 0.12s;
}
.checklist__row:hover { background:var(--surface); }
.checklist__row input { margin-top:2px; width:17px; height:17px; accent-color:var(--primary); flex-shrink:0; cursor:pointer; }
.checklist__row input:disabled { cursor:default; }
.checklist__text { font-size:0.9375rem; color:var(--text); line-height:1.45; }
.checklist__row.is-checked .checklist__text { color:var(--muted); text-decoration:line-through; }
.checklist__foot { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-top:12px; }
.checklist__progress { font-size:0.8125rem; color:var(--muted); }

/* --- Reflexionsfeld --- */
.reflection__prompt { font-size:0.9375rem; color:var(--text); line-height:1.6; margin:0 0 12px; }
.reflection__input {
  width:100%; min-height:120px; resize:vertical; padding:12px 14px; font-family:var(--fh);
  font-size:0.9375rem; line-height:1.55; color:var(--text);
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-sm);
}
.reflection__input:focus { outline:none; border-color:var(--primary); box-shadow:0 0 0 3px var(--ring); }
.reflection__foot { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-top:10px; }
.reflection__hint { font-size:0.75rem; color:var(--muted); }

/* --- Meilenstein / Check-in --- */
.milestone {
  border:1px dashed var(--primary-border); border-radius:var(--r-md);
  background:var(--primary-light); padding:18px 20px;
}
.milestone.is-confirmed { border-style:solid; border-color:var(--success-border); background:var(--success-bg); }
.milestone__prompt { font-size:0.9375rem; color:var(--text); line-height:1.6; margin:0 0 14px; }
.milestone__state { display:flex; align-items:center; gap:8px; font-size:0.875rem; font-weight:600; color:var(--primary); margin-bottom:10px; }
.milestone.is-confirmed .milestone__state { color:var(--success); }
.milestone__note { font-size:0.875rem; color:var(--text); background:var(--white); border:1px solid var(--border); border-radius:var(--r-sm); padding:10px 12px; margin-bottom:12px; }
.milestone__form { display:flex; flex-direction:column; gap:10px; }
.milestone__form textarea {
  width:100%; min-height:70px; resize:vertical; padding:10px 12px; font-family:var(--fh);
  font-size:0.875rem; color:var(--text); background:var(--white);
  border:1px solid var(--border); border-radius:var(--r-sm);
}
.milestone__form textarea:focus { outline:none; border-color:var(--primary); box-shadow:0 0 0 3px var(--ring); }
.milestone__actions { display:flex; gap:8px; flex-wrap:wrap; }

/* --- Check-in-Postfach (Führungskraft/Buddy) --- */
.checkin-card {
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-md);
  padding:18px 20px; margin-bottom:14px; box-shadow:var(--shadow-sm);
}
.checkin-card__head { display:flex; align-items:center; gap:12px; margin-bottom:12px; }
.checkin-card__who { font-size:0.9375rem; font-weight:700; color:var(--text); }
.checkin-card__where { font-size:0.75rem; color:var(--muted); }
.checkin-card__title { font-size:0.9375rem; color:var(--text); margin:0 0 10px; }

/* --- Praxisaufgabe (T20 S16) --- */
.task {
  border:1px dashed var(--border); border-radius:var(--r-md);
  background:var(--surface, #f6f7f9); padding:18px 20px;
}
.task.is-waiting { border-style:solid; border-color:var(--primary-border); background:var(--primary-light); }
.task.is-approved { border-style:solid; border-color:var(--success-border); background:var(--success-bg); }
.task.is-returned { border-style:solid; border-color:var(--accent-border, var(--border)); background:var(--accent-bg, var(--surface)); }
.task__brief { font-size:0.9375rem; color:var(--text); line-height:1.6; margin:0 0 14px; }
.task__state { display:flex; align-items:center; gap:8px; font-size:0.875rem; font-weight:600; color:var(--muted); margin-bottom:10px; }
.task.is-waiting .task__state { color:var(--primary); }
.task.is-approved .task__state { color:var(--success); }
.task.is-returned .task__state { color:var(--accent-text, var(--text)); }
.task__note {
  font-size:0.875rem; color:var(--text); background:var(--white); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:10px 12px; margin-bottom:12px;
}
.task__form { display:flex; flex-direction:column; gap:12px; margin-top:12px; }
.task__row { display:flex; gap:12px; flex-wrap:wrap; }
.task__row .task__field { flex:1; min-width:220px; }
.task__field { display:flex; flex-direction:column; gap:5px; }
.task__label { font-size:0.75rem; font-weight:600; color:var(--muted); }
.task__field textarea, .task__field input[type="url"] {
  width:100%; resize:vertical; padding:10px 12px; font-family:var(--fh);
  font-size:0.9375rem; line-height:1.55; color:var(--text); background:var(--white);
  border:1px solid var(--border); border-radius:var(--r-sm);
}
.task__field textarea:focus, .task__field input[type="url"]:focus { outline:none; border-color:var(--primary); box-shadow:0 0 0 3px var(--ring); }
.task__field input[type="file"] { font-size:0.8125rem; color:var(--muted); }
.task__actions { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.task__hint { font-size:0.75rem; color:var(--muted); }
.task__error { font-size:0.8125rem; color:var(--danger); margin:0; }

/* --- Abgabe, wie eingereicht (Baustein, Postfach, Journal) --- */
.submission {
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-sm);
  padding:12px 14px; margin-bottom:12px;
}
.submission__meta { font-size:0.75rem; color:var(--muted); margin:0 0 6px; }
.submission__text { font-size:0.875rem; color:var(--text); line-height:1.6; margin:0; white-space:pre-wrap; }
.submission__attachments { display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }
.submission__chip {
  display:inline-flex; align-items:center; gap:6px; font-size:0.75rem; font-weight:600;
  padding:5px 10px; border-radius:999px; text-decoration:none;
  color:var(--primary); background:var(--primary-light); border:1px solid var(--primary-border);
}
.submission__chip:hover { text-decoration:underline; }

/* --- Lernjournal (T20 S16) --- */
.journal-entry {
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-md);
  padding:16px 18px; margin-bottom:12px;
}
.journal-entry__head { display:flex; align-items:flex-start; justify-content:space-between; gap:14px; flex-wrap:wrap; margin-bottom:8px; }
.journal-entry__title { font-size:0.9375rem; font-weight:700; color:var(--text); margin:0; }
.journal-entry__where { font-size:0.75rem; color:var(--muted); margin:0; }
.journal-entry__side { display:flex; align-items:center; gap:8px; flex-shrink:0; }
.journal-entry__text { font-size:0.875rem; color:var(--text); line-height:1.6; margin:0; }
.journal-entry__review {
  font-size:0.8125rem; color:var(--text); background:var(--surface, #f6f7f9);
  border-radius:var(--r-sm); padding:9px 11px; margin:10px 0 0;
}

/* --- Gesprächsleitfaden (T20 S17) --- */
.guide {
  border:1px solid var(--border); border-radius:var(--r-sm);
  background:var(--white); margin:0 0 14px;
}
.guide__summary {
  display:flex; align-items:center; gap:8px; cursor:pointer; list-style:none;
  padding:10px 12px; font-size:0.8125rem; font-weight:600; color:var(--text);
}
.guide__summary::-webkit-details-marker { display:none; }
.guide__summary:hover { color:var(--primary); }
.guide__badge {
  margin-left:auto; font-size:0.625rem; font-weight:600; text-transform:uppercase;
  letter-spacing:0.04em; color:var(--muted);
}
.guide__body { padding:0 12px 12px; border-top:1px solid var(--border); }
.guide__intro { font-size:0.75rem; color:var(--muted); margin:10px 0 8px; }
.guide__text { font-size:0.875rem; color:var(--text); line-height:1.65; margin-bottom:10px; }

/* --- Begleit-Aufgaben im Postfach (T20 S17) --- */
.companion-card {
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-md);
  padding:18px 20px; margin-bottom:14px; box-shadow:var(--shadow-sm);
}
.companion-task {
  display:flex; align-items:flex-start; justify-content:space-between; gap:14px; flex-wrap:wrap;
  border:1px solid var(--border); border-radius:var(--r-sm);
  background:var(--surface, #f6f7f9); padding:12px 14px; margin-bottom:8px;
}
.companion-task.is-overdue { border-color:var(--danger-border, var(--border)); background:var(--danger-bg, var(--surface)); }
.companion-task__main { min-width:0; flex:1; }
.companion-task__title { font-size:0.9375rem; font-weight:600; color:var(--text); margin:0; }
.companion-task__desc { font-size:0.8125rem; color:var(--muted); line-height:1.55; margin:4px 0 0; }
.companion-task__meta { display:flex; align-items:center; gap:6px; flex-wrap:wrap; font-size:0.75rem; color:var(--muted); margin:6px 0 0; }
.companion-done { border-top:1px solid var(--border); margin-top:10px; padding-top:10px; }
.companion-done__row { display:flex; align-items:center; gap:10px; flex-wrap:wrap; font-size:0.8125rem; margin-bottom:4px; }
.companion-done__title { color:var(--success); font-weight:600; }
.companion-done__meta { color:var(--muted); }

@media (max-width:640px) {
  .companion-task { flex-direction:column; align-items:stretch; }
  .journey-steps { gap:8px; }
  .journey-step { min-width:118px; padding:10px 12px; }
  .next-step { padding:16px 18px; gap:14px; }
  .next-step__actions { width:100%; }
  .next-step__actions .btn { flex:1; justify-content:center; }
  .preboarding { padding:20px; }
  .task__row { flex-direction:column; }
}

/* ── Quiz: Durchlauf und Abschluss (T2 Assessments) ──
   Ein laufender Versuch zeigt eine Frage nach der anderen. Die Schritte stehen
   alle im HTML; app.js blendet aus, was gerade nicht dran ist. Ohne JavaScript
   bleibt es die lange Liste von früher — richtig, nur unbequemer. */
.quiz-progress { margin-bottom:18px; }
.quiz-progress__track {
  height:6px; border-radius:var(--r-full); background:var(--surface);
  border:1px solid var(--border); overflow:hidden;
}
.quiz-progress__bar {
  height:100%; width:0; border-radius:var(--r-full);
  background:var(--primary); transition:width 0.25s ease;
}
.quiz-progress__label { font-size:0.8125rem; font-weight:600; color:var(--muted); margin:7px 0 0; }
.quiz-deadline {
  font-size:0.8125rem; color:var(--warning-text, var(--text));
  background:var(--warning-bg, var(--surface)); border:1px solid var(--warning-border, var(--border));
  border-radius:var(--r-sm); padding:8px 12px; margin:0 0 14px;
}
.quiz-step { padding:20px; margin-bottom:14px; }
.quiz-step__question { font-size:1.0625rem; font-weight:700; color:var(--text); line-height:1.5; margin:0 0 12px; }
.quiz-step__meta { font-weight:400; color:var(--muted); font-size:0.8125rem; }
/* Die ganze Zeile ist das Ziel, nicht nur der kleine Kreis daneben. */
.quiz-option {
  display:flex; align-items:center; gap:12px; cursor:pointer;
  padding:11px 14px; margin-bottom:8px; font-size:0.9375rem; color:var(--text);
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-sm);
  transition:border-color 0.12s, background 0.12s;
}
.quiz-option:hover { border-color:var(--primary-border); background:var(--primary-light); }
.quiz-option input { flex-shrink:0; accent-color:var(--primary); width:17px; height:17px; }
.quiz-option:has(input:checked) { border-color:var(--primary); background:var(--primary-light); }
.quiz-nav { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:6px; }
/* „Zurück" links, alles Vorwärtige rechts — der Daumen sucht das Weiter dort. */
.quiz-nav [data-action="quiz-next"], .quiz-nav [data-quiz-submit] { margin-left:auto; }

/* --- Abschluss eines Versuchs --- */
.quiz-result {
  position:relative; background:var(--white); border:1px solid var(--border);
  border-left:4px solid var(--muted); border-radius:var(--r-md);
  padding:22px 24px; margin-bottom:20px; box-shadow:var(--shadow-sm);
}
.quiz-result.is-passed { border-left-color:var(--success); background:var(--success-bg); }
.quiz-result.is-failed { border-left-color:var(--border); }
.quiz-result__title { font-size:1.375rem; font-weight:800; color:var(--text); margin:0 0 4px; }
.quiz-result.is-passed .quiz-result__title { color:var(--success); }
.quiz-result__score { font-size:1rem; font-weight:600; color:var(--text); margin:0 0 14px; }
.quiz-result__pass { font-size:0.8125rem; font-weight:400; color:var(--muted); margin-left:8px; }
.quiz-result__answers { list-style:none; margin:0 0 16px; padding:0; }
.quiz-result__answers li {
  display:flex; align-items:baseline; gap:8px; font-size:0.875rem; color:var(--text);
  padding:6px 0; border-bottom:1px solid var(--border);
}
.quiz-result__answers li:last-child { border-bottom:none; }
.quiz-result__mark { font-weight:700; }
.quiz-result__answers li.is-correct .quiz-result__mark { color:var(--success); }
.quiz-result__answers li.is-incorrect .quiz-result__mark { color:var(--danger); }
.quiz-result__question { flex:1; min-width:0; }
.quiz-result__verdict { font-size:0.75rem; color:var(--muted); white-space:nowrap; }
.quiz-result__actions { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.quiz-result__hint { font-size:0.8125rem; color:var(--muted); margin:12px 0 0; }

/* --- Konfetti (nur beim Bestehen) ---
   Reine CSS-Animation auf ein paar Dutzend Schnipseln, die app.js einhängt und
   nach dem Fall wieder wegräumt. Kein Fremdpaket, keine Zeichenfläche: die
   strikte CSP lässt ohnehin nur eigene Skripte zu. */
.confetti { position:fixed; inset:0; pointer-events:none; overflow:hidden; z-index:60; }
.confetti__piece {
  position:absolute; top:-12px; width:9px; height:14px; opacity:0;
  animation:confetti-fall linear forwards;
}
@keyframes confetti-fall {
  0%   { opacity:1; transform:translate3d(0,0,0) rotate(0deg); }
  100% { opacity:0.9; transform:translate3d(var(--drift,0px),102vh,0) rotate(var(--spin,540deg)); }
}
/* Wer Bewegung abbestellt hat, bekommt keine — die Karte sagt es auch so. */
@media (prefers-reduced-motion:reduce) {
  .confetti { display:none; }
  .quiz-progress__bar { transition:none; }
}

/* ============================================================
   Live-Übertragung im Vollbild

   Vollbild gilt für genau ein Element samt allem darin. Solange der native Knopf
   des Videos es anforderte, war das das `<video>` selbst, und die Abstimmung als
   Geschwister der Bühne damit weg. Seit 2026-09-01 geht die Bühne
   (`[data-live-player]`) hinein, und `live-player.js` verschiebt Bedienstreifen
   und Abstimmungskarte für die Dauer dort hinein.

   Gehakt wird an der Klasse und nicht an `:fullscreen`: Die Pseudoklasse trägt in
   älteren Browsern ein Präfix, und ein einziger unbekannter Selektor macht die
   ganze Regelgruppe ungültig. Das Skript setzt die Klasse ohnehin im selben
   Moment.
   ============================================================ */

[data-live-player].is-fullscreen {
  width: 100vw;
  height: 100vh;
  /* Bühne, Streifen und Karte tragen ihre Maße als Inline-Style, und dagegen kommt
     eine Stylesheet-Regel nur mit `!important` an. Ohne `aspect-ratio: auto` rechnet
     die Bühne ihr 16:9 gegen die Bildschirmhöhe, und der Bedienstreifen säße dann am
     unteren Rand eines Kastens statt am unteren Rand des Bildschirms. */
  aspect-ratio: auto !important;
  background: #000 !important;
}

[data-live-player].is-fullscreen [data-live-video] { object-fit: contain; }

/* Der Bedienstreifen legt sich über den unteren Rand des Bildes. Ohne ihn käme der
   Zuschauer im Vollbild an nichts mehr heran, denn die Standardbedienung gibt es
   hier bewusst nicht. */
[data-live-player].is-fullscreen [data-live-controls] {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  padding: 18px 22px;
  border-top: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.78), rgba(0, 0, 0, 0));
}

[data-live-player].is-fullscreen [data-live-controls] .btn {
  color: #fff;
  background: rgba(0, 0, 0, 0.4);
  border-color: rgba(255, 255, 255, 0.35);
}

[data-live-player].is-fullscreen [data-live-controls] span { color: rgba(255, 255, 255, 0.75) !important; }

/* Die Abstimmung liegt über dem Bild, unten und in Lesebreite. Dunkler Grund statt
   der hellen Karte, denn dahinter läuft ein Video. */
[data-live-player].is-fullscreen [data-live-poll] {
  position: absolute;
  left: 50%;
  bottom: 76px;
  transform: translateX(-50%);
  width: min(560px, calc(100% - 48px));
  margin: 0 !important;
  z-index: 2;
  background: rgba(16, 20, 26, 0.94);
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}

[data-live-player].is-fullscreen [data-live-poll] p { color: #fff !important; }
[data-live-player].is-fullscreen [data-live-poll] [data-live-poll-hint] { color: rgba(255, 255, 255, 0.72) !important; }
[data-live-player].is-fullscreen [data-live-poll] [data-live-poll-result] span { color: rgba(255, 255, 255, 0.9); }

/* ============================================================
   Telefon-Feinschliff (Lerner-Sicht bedienbar unter 640 px)

   Bewusst ganz am Dateiende und nicht oben beim „Responsive"-Block: was hier
   steht, überschreibt Komponenten, die weiter oben definiert sind. Bei gleicher
   Spezifität entscheidet die Reihenfolge, und von oben käme etwa
   `.mod-int-btn` nicht gegen seine eigene Basisregel an — dieselbe Falle, für
   die `nav.bottom-nav` sich oben eine höhere Spezifität nehmen musste.

   Was das Layout auf eine Spalte faltet, bleibt oben stehen: dort greift es
   gegen Regeln, die früher definiert sind, und gehört sachlich zum Layout.
   ============================================================ */
@media (max-width: 640px) {

  /* --- Produkt-Sub-Nav: waagerecht wischbar statt abgeschnitten ---
     Die zweite Navigationsebene trägt bis zu sechs Einträge, alle mit
     `white-space: nowrap`. Ohne eigene Regel lief sie schlicht aus dem Bild:
     bei 390 px standen „Module" und „Lesezeichen" bis zu 193 px neben der
     Seite und waren mit keiner Geste erreichbar — stattdessen scrollte das
     ganze Dokument waagerecht. Jetzt scrollt nur die Leiste, und sie reicht
     dafür bis an beide Ränder, damit ein angeschnittener Eintrag zeigt, dass
     es weitergeht. Die Bildlaufleiste bleibt verborgen; auf einem Telefon
     zeichnet das System ohnehin keine. */
  .sub-nav { padding: 0; }
  .sub-nav__inner {
    /* Gescrollt wird seit der Umstellung auf jeder Breite (siehe die
       Basisregel); hier kommt nur dazu, was das Telefon braucht: der Schwung
       beim Wischen und ein Innenmaß bis an die Ränder, damit ein
       angeschnittener Eintrag zeigt, dass es weitergeht. */
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    padding: 0 16px;
  }
  .sub-nav__link { padding: 13px 14px; }

  /* --- Baustein-Karte der Pfadansicht ---
     Statuspunkt, Quell-Symbol, Titel und Aktionen nebeneinander ergaben auf dem
     Telefon 422 px in einem 343-px-Kasten: die Karte ragte 48 px heraus, und für
     den Titel blieben 141 px. Die Aktionen bekommen deshalb eine eigene Zeile
     über die volle Breite — sie sind der Grund, warum es eng wurde, und
     nebeneinander sind sie unten leichter zu treffen als rechts gestapelt. */
  .module-card { flex-wrap: wrap; padding: 14px 16px; gap: 12px; }
  .module-card__body { flex: 1 1 140px; }
  .module-card__actions {
    /* `flex: 1 1 100%` und nicht nur `flex-basis`: die Basisregel setzt
       `flex-shrink: 0`, und dann kann die Zeile die zwei Pixel des
       Kartenrahmens nicht mehr abgeben — die Karte ragt genau so weit heraus. */
    flex: 1 1 100%;
    min-width: 0;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 8px;
  }
  /* `flex: 1 1 140px` und nicht `flex: 1`: Knöpfe tragen `white-space: nowrap`,
     und ein Flex-Element schrumpft nicht unter seinen Mindest-Inhalt. Zwei lange
     Beschriftungen („Inhalte öffnen →" neben „Als erledigt markieren →") hätten
     die Zeile deshalb gesprengt statt sich zu teilen. Mit einer Wunschbreite von
     140 px passen zwei kurze Knöpfe nebeneinander, während ein langes Paar
     umbricht — und `min-width: 0` erlaubt dabei das Schrumpfen. */
  .module-card__actions > form { flex: 1 1 140px; min-width: 0; display: flex; }
  .module-card__actions > .btn { flex: 1 1 140px; min-width: 0; }
  .module-card__actions > .btn,
  .module-card__actions > form > .btn { justify-content: center; white-space: normal; }
  .module-card__actions > form > .btn { flex: 1; }

  /* --- Zeilen mit Wert rechts (Lernakte, Agenda, „Über diesen Pfad") ---
     Die rechte Spalte bricht nicht um (Uhrzeit, Ort, Status-Pille) und drückte
     den Titel links zusammen. Umbrechen statt quetschen. */
  .detail-row { flex-wrap: wrap; }
  .detail-row > :first-child { min-width: 0; }

}

/* ── Sprungmarke über alles (Strg+K) ──
   Auslöser in der Kopfzeile, Palette als natives <dialog>. Die Trefferzeilen
   baut public/js/search-palette.js — deshalb Klassen und kein Inline-Style.
   Farben ausschließlich über Tokens, damit der Dunkelmodus ohne zweite Regel
   mitkommt. */
.search-trigger {
  display: inline-flex; align-items: center; gap: 8px;
  height: 36px; padding: 0 10px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg); color: var(--muted);
  font-family: var(--fh); font-size: 0.8125rem;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}
.search-trigger:hover { border-color: var(--primary); color: var(--text); }
.search-trigger:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
/* Unter 640 px bleibt nur das Symbol: In der mobilen Kopfzeile stehen daneben
   schon Glocke, Hilfe und Profilmenü. */
.search-trigger__label, .search-trigger__kbd { display: none; }
.search-trigger__kbd {
  padding: 1px 5px;
  border: 1px solid var(--border); border-radius: var(--r-xs);
  background: var(--surface);
  font-family: var(--fh); font-size: 0.6875rem; line-height: 1.5; color: var(--muted);
}
@media (min-width: 640px) {
  .search-trigger { width: 13rem; }
  .search-trigger__label { display: block; }
  .search-trigger__kbd { display: block; margin-left: auto; }
}

/* Oben statt mittig: Die Liste wächst nach unten, ein senkrecht zentrierter
   Dialog schöbe das Eingabefeld bei jedem Tastendruck an eine andere Stelle. */
.search-palette {
  width: min(40rem, calc(100vw - 2rem));
  max-height: min(32rem, 80vh);
  margin: max(8vh, 3rem) auto auto;
  padding: 0;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--white); color: var(--text);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
/* `display` erst im geöffneten Zustand — ein <dialog> ist sonst sichtbar,
   obwohl es zu ist. */
.search-palette[open] { display: flex; flex-direction: column; }
.search-palette::backdrop { background: rgba(0,0,0,0.4); }

.search-palette__head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
}
.search-palette__input {
  flex: 1; min-width: 0;
  border: none; background: transparent;
  font-family: var(--fh); font-size: 0.9375rem; color: var(--text);
  outline: none;
}
.search-palette__input::placeholder { color: var(--muted); }
.search-palette__esc {
  flex-shrink: 0;
  padding: 2px 7px;
  border: 1px solid var(--border); border-radius: var(--r-xs);
  background: var(--surface);
  font-family: var(--fh); font-size: 0.6875rem; color: var(--muted);
  cursor: pointer;
}
.search-palette__results { flex: 1; min-height: 0; overflow-y: auto; padding: 6px; }
.search-palette__note { padding: 24px 10px; text-align: center; font-size: 0.875rem; color: var(--muted); }
.search-palette__foot {
  display: flex; flex-wrap: wrap; gap: 6px 14px;
  padding: 8px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface);
  font-size: 0.6875rem; color: var(--muted);
}
.search-palette__foot kbd {
  padding: 0 4px; border-radius: var(--r-xs);
  background: var(--white); font-family: var(--fh); font-size: 0.6875rem;
}
.search-palette__foot kbd + kbd { margin-left: 2px; }

.search-group + .search-group { margin-top: 4px; }
.search-group__label {
  padding: 8px 10px 4px;
  font-size: 0.625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted);
}
.search-hit {
  display: flex; align-items: baseline; gap: 8px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  font-size: 0.875rem; color: var(--text); text-decoration: none;
}
/* Der Hervorhebung folgt Enter — sie kommt deshalb von der Auswahl (Tastatur
   wie Maus, siehe search-palette.js) und nicht von :hover. */
.search-hit.is-active { background: var(--primary-light); }
.search-hit__ref { flex-shrink: 0; font-size: 0.75rem; color: var(--primary); }
.search-hit__title { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.search-hit__meta { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.75rem; color: var(--muted); }
.search-hit__badge {
  flex-shrink: 0; margin-left: auto;
  padding: 1px 7px; border-radius: var(--r-full);
  background: var(--surface); font-size: 0.6875rem; color: var(--muted);
}

/* ── Bedienung mit dem Finger ──
   Zwei Bedingungen, weil zwei verschiedene Fragen dahinterstehen. Das Layout
   oben hängt an der Breite: ob zwei Spalten nebeneinander passen, entscheidet
   der Platz. Wie groß ein Knopf sein muss und wie groß Schrift in einem
   Eingabefeld, entscheidet dagegen das Eingabegerät — ein iPad im Querformat
   ist 1024 px breit und wird trotzdem mit dem Daumen bedient.

   `pointer: coarse` beschreibt das primäre Eingabegerät. Ein Notebook mit
   Touchscreen meldet weiter `fine`, denn dort führen Maus und Trackpad; es
   behält also die kompakten Größen. */
@media (max-width: 640px), (pointer: coarse) {

  /* --- Tippziele ---
     Die kompakten Größen sind für den Mauszeiger gebaut: `.btn-sm` misst 30 px
     hoch, `.btn-xs` 24 px, die Ansichts-Umschalter 29 px. Für den Daumen sind
     das keine Ziele. Am Finger wachsen sie auf 44 px — die Größe, unter der
     iOS und Android beide vor Fehlgriffen warnen.

     `min-height` führt, die Polsterung regelt nur die Breite: so misst jede
     Größe verlässlich 44 px, statt sich aus Schriftgröße, Zeilenhöhe und
     Polsterung zufällig knapp darunter zu ergeben. */
  .btn      { min-height: 44px; padding: 10px 18px; }
  .btn-sm   { padding: 10px 14px; font-size: 0.875rem; }
  .btn-xs   { padding: 8px 12px; font-size: 0.8125rem; }
  .icon-btn { width: 44px; height: 44px; }
  .menu-btn { width: 44px; height: 44px; }
  /* Am Finger ist der Auslöser der Sprungmarke ein Symbol-Knopf wie die
     Nachbarn und misst deshalb dasselbe. */
  .search-trigger { min-height: 44px; min-width: 44px; justify-content: center; }
  .search-hit { padding: 11px 10px; }
  .view-toggle__btn { min-height: 44px; padding: 10px 16px; }
  /* Lesezeichen, Daumen und die Zeit-Chips im Vorwissen: `min-height` statt
     mehr Polsterung, sonst wird aus der Pille ein Klotz. Der Knopf zentriert
     seinen Inhalt von sich aus senkrecht. */
  .mod-int-btn { padding: 9px 14px; font-size: 0.8125rem; min-height: 44px; }
  .user-dropdown__item { padding: 13px 16px; }
  .quiz-option { padding: 14px; }
  .checklist__row { padding: 12px 11px; }

  /* --- Eingabefelder: 16 px, sonst zoomt iOS beim Antippen hinein ---
     Safari auf iPhone und iPad vergrößert die Seite, sobald ein fokussiertes
     Feld kleiner als 16 px gesetzt ist, und zoomt danach nicht von selbst
     zurück — ab da sitzt die Seite verschoben und ist nur noch mit zwei
     Fingern zu bedienen. Die Felder der Anwendung liegen zwischen 13 px und
     15 px, einige davon als Inline-Style (Lernzeit-Blöcke, Sichtbarkeit im
     Vorwissen). Nur deshalb steht hier `!important`: gegen ein
     Inline-`font-size` kommt eine Stylesheet-Regel sonst nicht an. Kästchen,
     Schalter und Schieberegler tragen keinen Text und bleiben ausgenommen. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="hidden"]),
  select,
  textarea { font-size: 16px !important; }
}

/* ── Mail-Vorschau (2026-09-02) ──
   Der Brief steht in einem Rahmen und nicht in der Seite: Er bringt seinen eigenen
   Body samt Hintergrund und Schrift mit, und hineingerendert sähe er anders aus als
   beim Empfänger. Feste Höhe mit eigenem Scrollen, denn eine Mail ist beliebig lang
   und soll die Maske darüber nicht wegschieben; wer sie ganz sehen will, öffnet den
   Link daneben. */
.mail-preview__frame {
  display: block;
  width: 100%;
  height: 620px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--white);
}
@media (max-width: 640px) {
  .mail-preview__frame { height: 460px; }
}
