/* Lernplaner – Oberfläche.

   Umsetzung des vom Kunden am 10.09.2026 gewählten Entwurfs C „Fokus":
   dunkel als Grundzustand, dicht, kontraststark, Uhrzeiten in Monospace.
   Das helle Thema ist vollständig ausgeführt, nicht bloss eine Umkehrung:
   Auf hellem Grund tragen Rahmen die Struktur, im Dunkeln die Flächen.

   ZWEI REGELN, die diese Datei durchziehen:

   1. JEDER FARBWERT STEHT GENAU EINMAL, in der Farbtafel unten. Alles andere
      arbeitet nur mit Namen. Der Kunde hat sich ausbedungen, die Farbe am
      Ende noch einmal wechseln zu können, ohne dass das Aufwand auslöst.

   2. KEIN EINZIGER STIL AUS DEM PROGRAMM. Die Sicherheitsrichtlinie erlaubt
      weder ein <style>-Element noch ein style-Attribut. Was anderswo eine
      berechnete Höhe oder Farbe wäre, ist hier eine Klasse aus dieser Datei
      – siehe die Rasterklassen beim Stundenraster. Das ist kein Umweg,
      sondern die Bedingung dafür, dass 'unsafe-inline' aus der Richtlinie
      draussen bleiben kann. */

:root {
  color-scheme: dark light;

  --grund: #0a0e15;
  --flaeche: #121823;
  --flaeche-hoch: #1a2231;
  --text: #f2f6fb;
  --text-leise: #93a1b5;
  --linie: #243044;
  --linie-stark: #35455f;

  /* === FARBTAFEL ========================================================
     Jede Akzentfarbe steht hier GENAU EINMAL, mit drei Werten:
       -ton    die Farbe selbst (Knöpfe, Uhrzeiten, aktiver Bereich)
       -grund  die gedeckte Fläche dahinter (laufender Termin, Kachel)
       -auf    die Schrift, die AUF der Farbe liegt (Knopfbeschriftung)
     Wer eine Farbe ändern will, ändert sie hier – und nirgends sonst.
     Die helle Fassung derselben Tafel steht weiter unten; alles andere in
     dieser Datei arbeitet nur noch mit Namen, nie mit Farbwerten. */
  --petrol-ton:  #5ccfc4;  --petrol-grund:  #0d2a2b;  --petrol-auf:  #04201f;
  --kupfer-ton:  #e9a06a;  --kupfer-grund:  #2b1d12;  --kupfer-auf:  #1b0f05;
  --violett-ton: #bda4f5;  --violett-grund: #221a35;  --violett-auf: #140b26;
  --stahl-ton:   #8ab4ff;  --stahl-grund:   #17233d;  --stahl-auf:   #0b1120;
  --graphit-ton: #cbd5e1;  --graphit-grund: #1e2836;  --graphit-auf: #0a0e15;
  --salbei-ton:  #a8cf8f;  --salbei-grund:  #1b2416;  --salbei-auf:  #101a08;

  /* === VORGABE ==========================================================
     DIE EINE STELLE, an der die voreingestellte Akzentfarbe steht. Wechseln
     heißt: in diesen drei Zeilen „petrol" durch einen anderen Namen aus der
     Tafel ersetzen. Sonst ändert sich nichts – weder im HTML noch im PHP.
     In der fertigen App ist selbst das nicht nötig: Dort schreibt der
     Front-Controller `data-akzent` aus den Einstellungen, und diese Vorgabe
     greift nur, wenn nichts eingestellt ist.
     Weil hier Namen statt Werte stehen, gilt sie für hell und dunkel
     zugleich – die Tafel unten wird ausgetauscht, die Vorgabe bleibt. */
  --signal:       var(--petrol-ton);
  --signal-grund: var(--petrol-grund);
  --auf-signal:   var(--petrol-auf);

  /* === KATEGORIE-FARBTAFEL ==============================================
     Acht Farben für die Kategorien des Kunden (Kundenwunsch 11.09.2026:
     verschiedene Ereignisse, verschiedene Farben). EIGENE Tafel, nicht die
     Akzenttafel darüber: Die Akzentfarbe ist eine Einstellung des
     Erscheinungsbilds und wechselt; eine Kategoriefarbe bedeutet ein Fach und
     darf sich nicht mitverändern.

     Alle acht sind in hell UND dunkel nachgemessen (Ton auf Fläche, Text auf
     Kachelgrund, leiser Text auf Kachelgrund): überall über 4,5:1, der
     niedrigste Wert ist 4,71:1 (Orange hell). Die Farbwinkel liegen weit
     auseinander (12°, 35°, 52°, 158°, 174°, 218°, 259° plus ein entsättigtes
     Grau), damit acht Kategorien im Kachelraster auch nebeneinander
     unterscheidbar sind.

     Zusätzlich gegen die ZUSTANDSFARBEN gemessen (UI-Experte, Durchlauf 2:
     das alte Salbei lag mit ΔE 3,9 praktisch auf dem Grün für "fällig"):
     Jeder Ton hält zu Gut, Warn und Fehler ΔE ≥ 20 – mit einer Ausnahme, die
     sich nicht wegmessen lässt: Orange im hellen Thema liegt bei ΔE 16 zum
     Warn-Braun, weil "Warn" dort selbst ein dunkles Orange ist. Deshalb trägt
     "geändert" in jeder Kachel zusätzlich das WORT, nicht nur den gelben
     Balken – Farbe ist nie der einzige Träger. */
  --kat-stahl-ton:   #8ab4ff;  --kat-stahl-grund:   #17233d;
  --kat-petrol-ton:  #5ccfc4;  --kat-petrol-grund:  #0d2a2b;
  --kat-smaragd-ton: #34d399;  --kat-smaragd-grund: #12291f;
  --kat-safran-ton:  #dfd06a;  --kat-safran-grund:  #292611;
  --kat-kupfer-ton:  #e8a54a;  --kat-kupfer-grund:  #2b1d12;
  --kat-koralle-ton: #f5967f;  --kat-koralle-grund: #2e1817;
  --kat-violett-ton: #bda4f5;  --kat-violett-grund: #221a35;
  --kat-graphit-ton: #cfd4da;  --kat-graphit-grund: #1e2836;
  /* Die Schrift AUF der Farbe (Knopfbeschriftung) braucht nur eine Fassung
     je Thema: Im Dunkeln sind alle acht Töne hell, im Hellen alle dunkel. */
  --kat-auf: #0a0e15;

  /* Zustandsfarben. Sie gehören NICHT zum Akzent und wechseln nie mit:
     „erledigt", „achtung" und „fehler" müssen unabhängig von einer
     Einstellung dasselbe bedeuten. */
  --gut: #9ccc8f;
  --gut-grund: #1a2416;
  --auf-gut: #0f1a08;
  --warn: #fbbf24;
  --warn-grund: #2a2110;
  --fehler: #fb7185;

  --schrift: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --zahlen: ui-monospace, "SF Mono", "Roboto Mono", "DejaVu Sans Mono", monospace;

  /* Höhe einer Stunde im Stundenraster. Gerastert wird in Viertelstunden:
     feiner als jede Vorlesungszeit im Stundenplan des Kunden (09:15, 14:15)
     und grob genug, dass die Rasterklassen weiter unten eine überschaubare
     Liste bleiben. */
  --stunde: 3.25rem;
  --viertel: calc(var(--stunde) / 4);
}

@media (prefers-color-scheme: light) {
  :root {
    --grund: #eef1f6;
    --flaeche: #ffffff;
    --flaeche-hoch: #ffffff;
    --text: #0a0e15;
    --text-leise: #4a5568;
    --linie: #cdd5e0;
    --linie-stark: #0a0e15;

    /* Dieselbe Tafel in der hellen Fassung. Die Vorgabe oben zeigt auf die
       Namen, nicht auf die Werte – sie muss hier nicht wiederholt werden. */
    --petrol-ton:  #0f766e;  --petrol-grund:  #d7f2ee;  --petrol-auf:  #ffffff;
    --kupfer-ton:  #9a4d16;  --kupfer-grund:  #f7e7d8;  --kupfer-auf:  #ffffff;
    --violett-ton: #6d28d9;  --violett-grund: #ede9fe;  --violett-auf: #ffffff;
    --stahl-ton:   #1d4ed8;  --stahl-grund:   #e8effd;  --stahl-auf:   #ffffff;
    --graphit-ton: #334155;  --graphit-grund: #e6eaf0;  --graphit-auf: #ffffff;
    --salbei-ton:  #45691a;  --salbei-grund:  #e8f2d8;  --salbei-auf:  #ffffff;

    /* Dieselbe Kategorie-Tafel in der hellen Fassung. */
    --kat-stahl-ton:   #1d4ed8;  --kat-stahl-grund:   #e8effd;
    --kat-petrol-ton:  #0f766e;  --kat-petrol-grund:  #d7f2ee;
    --kat-smaragd-ton: #127a4b;  --kat-smaragd-grund: #dcf5e8;
    --kat-safran-ton:  #6f6100;  --kat-safran-grund:  #f7edcd;
    --kat-kupfer-ton:  #b65a0a;  --kat-kupfer-grund:  #f7e7d8;
    --kat-koralle-ton: #c81e1e;  --kat-koralle-grund: #fbe3e0;
    --kat-violett-ton: #6d28d9;  --kat-violett-grund: #ede9fe;
    --kat-graphit-ton: #3f4650;  --kat-graphit-grund: #e6eaf0;
    --kat-auf: #ffffff;

    --gut: #3f6212;
    --gut-grund: #ecfccb;
    --auf-gut: #ffffff;
    --warn: #92400e;
    --warn-grund: #fef3c7;
    --fehler: #be123c;
  }
}

/* === UMSCHALTEN =========================================================
   Ein Attribut am <html>-Element wählt eine Zeile der Tafel aus. Sechs
   Zeilen für sechs Farben, gültig für hell und dunkel – ein Attribut ist
   kein Stil und verletzt die Sicherheitsrichtlinie nicht.
   Eine siebte Farbe wäre: ein Eintrag in beiden Tafeln, eine Zeile hier,
   eine Zeile bei den Tupfern unten. Mehr nicht. */
[data-akzent="petrol"]  { --signal: var(--petrol-ton);  --signal-grund: var(--petrol-grund);  --auf-signal: var(--petrol-auf); }
[data-akzent="kupfer"]  { --signal: var(--kupfer-ton);  --signal-grund: var(--kupfer-grund);  --auf-signal: var(--kupfer-auf); }
[data-akzent="violett"] { --signal: var(--violett-ton); --signal-grund: var(--violett-grund); --auf-signal: var(--violett-auf); }
[data-akzent="stahl"]   { --signal: var(--stahl-ton);   --signal-grund: var(--stahl-grund);   --auf-signal: var(--stahl-auf); }
[data-akzent="graphit"] { --signal: var(--graphit-ton); --signal-grund: var(--graphit-grund); --auf-signal: var(--graphit-auf); }
[data-akzent="salbei"]  { --signal: var(--salbei-ton);  --signal-grund: var(--salbei-grund);  --auf-signal: var(--salbei-auf); }

/* === KATEGORIEFARBE AN EINEM EINZELNEN ELEMENT ==========================
   Derselbe Kniff wie beim Akzent, nur lokal: Das Attribut definiert --signal
   für DIESES Element und seine Kinder neu. Damit übernehmen alle vorhandenen
   Regeln – Kachelgrund, linker Balken, Uhrzeit, Monatspunkt – die Farbe der
   Kategorie, ohne dass eine einzige von ihnen geändert werden müsste.

   ACHTUNG: `data-farbe` gehört ausschliesslich an einen einzelnen Termin.
   An einem Container gesetzt, färbte es alles darin um. */
[data-farbe="stahl"]   { --signal: var(--kat-stahl-ton);   --signal-grund: var(--kat-stahl-grund);   --auf-signal: var(--kat-auf); }
[data-farbe="petrol"]  { --signal: var(--kat-petrol-ton);  --signal-grund: var(--kat-petrol-grund);  --auf-signal: var(--kat-auf); }
[data-farbe="smaragd"] { --signal: var(--kat-smaragd-ton); --signal-grund: var(--kat-smaragd-grund); --auf-signal: var(--kat-auf); }
[data-farbe="safran"]  { --signal: var(--kat-safran-ton);  --signal-grund: var(--kat-safran-grund);  --auf-signal: var(--kat-auf); }
[data-farbe="kupfer"]  { --signal: var(--kat-kupfer-ton);  --signal-grund: var(--kat-kupfer-grund);  --auf-signal: var(--kat-auf); }
[data-farbe="koralle"] { --signal: var(--kat-koralle-ton); --signal-grund: var(--kat-koralle-grund); --auf-signal: var(--kat-auf); }
[data-farbe="violett"] { --signal: var(--kat-violett-ton); --signal-grund: var(--kat-violett-grund); --auf-signal: var(--kat-auf); }
[data-farbe="graphit"] { --signal: var(--kat-graphit-ton); --signal-grund: var(--kat-graphit-grund); --auf-signal: var(--kat-auf); }

* { box-sizing: border-box; }

/* Jedes Zeichen in dieser App ist ein SVG im 24er-Raster OHNE eigene
   Grössenangabe. Ohne diese Grundregel wäre es 300x150 Bildpunkte gross –
   einmal passiert, sah das Warndreieck aus wie ein Verkehrsschild. Die
   Regeln weiter unten setzen je Ort ihre eigene Grösse. */
svg { flex: none; width: 20px; height: 20px; }

/* Das Programm blendet Felder mit dem hidden-Attribut aus (Uhrzeiten bei
   einem ganztägigen Termin, das Ende der Reihe bei "einmalig"). Ohne diese
   Zeile bliebe genau das wirkungslos: Die display-Regeln weiter unten sind
   spezifischer als das hidden aus dem Standard-Stylesheet des Browsers. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--grund);
  color: var(--text);
  font: 16px/1.45 var(--schrift);
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 { margin: 0; font-weight: 700; letter-spacing: -0.015em; }
p { margin: 0; }
a { color: inherit; }

:focus-visible { outline: 3px solid var(--signal); outline-offset: 2px; }
/* Die Überschrift bekommt nach jedem Seitenwechsel den Fokus, damit ein
   Bildschirmleser die neue Seite vorliest. Der Ring gehört aber zu einem
   Bedienelement – hier hat ihn niemand mit der Tastatur angesteuert, und er
   legte sich über die Zeile darunter. */
.kopf h1:focus { outline: none; }

.sprung { position: absolute; left: -9999px; }
.sprung:focus { left: 0.5rem; top: 0.5rem; z-index: 10; background: var(--flaeche); padding: 0.75rem 1rem; }

.marke, .kennzeichen {
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* --- Gerüst -------------------------------------------------------------- */
.rahmen {
  display: grid;
  grid-template-areas: "kopf" "inhalt" "nav";
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr auto;
  min-height: 100dvh;
}

/* Am Handy ein Raster: Titel links, Werkzeuge rechts in EINER Zeile, die
   Chips darunter über die ganze Breite. Als Flex-Zeile brach der Kopf auf
   drei Zeilen (121 px) um, und das Zahnrad stand allein in der dritten. */
.kopf {
  grid-area: kopf;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.875rem;
  background: var(--flaeche);
  border-bottom: 1px solid var(--linie);
}
.kopf h1 { font-size: 1.25rem; overflow-wrap: anywhere; hyphens: auto; }
.kopf > div:first-child { min-width: 0; }
.kopf .statuszeile { grid-column: 1 / -1; grid-row: 2; justify-content: flex-start; }
.kopf .statuszeile:empty { display: none; }
.kopf .werkzeuge { grid-column: 2; grid-row: 1; }
.kopf .statuszeile { display: flex; gap: 0.375rem; flex-wrap: wrap; justify-content: flex-end; }
.chip {
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--linie-stark);
  border-radius: 3px;
  color: var(--text-leise);
  white-space: nowrap;
}
.chip.stark { color: var(--gut); border-color: var(--gut); background: var(--gut-grund); }
.chip.warn { color: var(--warn); border-color: var(--warn); background: var(--warn-grund); }

.inhalt {
  grid-area: inhalt;
  width: 100%;
  padding: 0.75rem 0.875rem calc(5.5rem + env(safe-area-inset-bottom));
  display: grid;
  gap: 0.75rem;
  align-content: start;
}

/* --- Navigation ---------------------------------------------------------- */
.nav {
  grid-area: nav;
  position: fixed;
  inset: auto 0 0 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--flaeche);
  border-top: 1px solid var(--linie-stark);
  padding-bottom: env(safe-area-inset-bottom);
}
.nav a {
  display: grid;
  justify-items: center;
  gap: 0.25rem;
  min-height: 56px;
  padding: 0.5rem 0.25rem;
  text-decoration: none;
  color: var(--text-leise);
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-top: 2px solid transparent;
}
.nav a svg { width: 22px; height: 22px; }
.nav a[aria-current="page"] { color: var(--signal); border-top-color: var(--signal); background: var(--signal-grund); }

@media (min-width: 768px) {
  .rahmen {
    grid-template-columns: 13rem 1fr;
    grid-template-rows: auto 1fr;
    grid-template-areas: "nav kopf" "nav inhalt";
  }
  .nav {
    position: sticky;
    /* Erst das inset der Handy-Regel löschen, DANN top setzen. Andersherum
       setzte `inset: auto` das top wieder zurück, die Leiste klebte nicht
       und endete auf langen Seiten (Einstellungen) mitten im Bild. */
    inset: auto;
    top: 0;
    height: 100dvh;
    align-self: start;
    align-content: start;
    grid-template-columns: 1fr;
    border-top: 0;
    border-right: 1px solid var(--linie-stark);
    padding: 0.75rem 0.5rem;
    gap: 0.25rem;
  }
  .nav a {
    grid-template-columns: 22px 1fr;
    justify-items: start;
    align-items: center;
    gap: 0.625rem;
    min-height: 44px;
    border-top: 0;
    border-left: 2px solid transparent;
    padding: 0.5rem 0.75rem;
    font-size: 0.75rem;
  }
  .nav a[aria-current="page"] { border-left-color: var(--signal); }
  .kopf { padding: 1rem 1.5rem; grid-template-columns: minmax(0, 1fr) auto auto; }
}

/* Tablet-Breite (768–1023 px): Seitenleiste nur mit Zeichen. Die 13 rem der
   vollen Leiste liessen den sieben Tagesspalten des Stundenrasters je 64 px –
   bei drei gleichzeitigen Terminen 19 px je Kachel (UI-Experte, Durchlauf 2).
   Die Beschriftung bleibt als title und für Bildschirmleser erhalten. */
@media (min-width: 768px) and (max-width: 1023px) {
  .rahmen { grid-template-columns: 4rem 1fr; }
  .nav { padding: 0.75rem 0.375rem; }
  .nav a { grid-template-columns: 22px; justify-items: center; padding: 0.625rem 0; }
  .nav a .nav-text { position: absolute; left: -9999px; }
}

@media (min-width: 768px) {
  .kopf .statuszeile { grid-column: 2; grid-row: 1; justify-content: flex-end; }
  .kopf .werkzeuge { grid-column: 3; }
  .inhalt { padding: 1rem 1.5rem 2rem; }
  .zweispaltig { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; align-items: start; }
}

/* --- Blöcke -------------------------------------------------------------- */
.block {
  background: var(--flaeche);
  border: 1px solid var(--linie);
  border-radius: 4px;
}
.block > h2 {
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-leise);
  padding: 0.625rem 0.75rem;
  border-bottom: 1px solid var(--linie);
}
.block > * + * { border-top: 1px solid var(--linie); }
.block .feld { padding: 0.75rem; }

.termin {
  display: grid;
  grid-template-columns: 4.25rem 1fr;
  gap: 0.125rem 0.75rem;
  padding: 0.75rem;
  text-decoration: none;
}
.termin .uhr {
  grid-row: span 2;
  font: 700 0.9375rem/1.35 var(--zahlen);
  color: var(--signal);
}
.termin .uhr span { display: block; color: var(--text-leise); font-weight: 400; }
.termin .was { font-weight: 700; overflow-wrap: anywhere; hyphens: auto; }
.termin .wo { font-size: 0.8125rem; color: var(--text-leise); }
.termin.laeuft { background: var(--signal-grund); border-left: 3px solid var(--signal); }
.termin.abgesagt .was { text-decoration: line-through; color: var(--text-leise); }

.aus {
  display: inline-block;
  margin-left: 0.375rem;
  padding: 0.15rem 0.35rem;
  border: 1px solid var(--warn);
  border-radius: 3px;
  color: var(--warn);
  font: 700 0.625rem/1 var(--schrift);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  vertical-align: 0.1em;
}

.zahlfeld { display: flex; align-items: baseline; gap: 0.75rem; padding: 0.75rem; }
.zahlfeld .wert { font: 700 3rem/0.9 var(--zahlen); color: var(--gut); }
.zahlfeld p { font-size: 0.875rem; color: var(--text-leise); }

.aufgabe { display: grid; gap: 0.375rem; padding: 0.75rem; }
/* Der ganze Titel ist die Trefferfläche, nicht nur der 20px-Kasten (Punkt 8,
   Phase 4) – ein <label> um Kasten und Text herum macht das ohne eigenes
   Skript, dieselbe Technik wie .maske .schalter. */
.aufgabe-zeile { display: flex; align-items: flex-start; gap: 0.75rem; min-height: 44px; cursor: pointer; }
.aufgabe-zeile .kasten { width: 1.25rem; height: 1.25rem; margin-top: 0.15rem; accent-color: var(--gut); flex: none; }
/* min-width:0 erlaubt dem Flex-Kind, unter seine Inhaltsbreite zu schrumpfen –
   ohne das sprengt ein einzelnes langes Wort (Jura-Komposita!) die ganze
   Zeile samt der festen unteren Navigation (UI-Experte, Durchlauf 4). */
.aufgabe-text { min-width: 0; }
.aufgabe-text p { overflow-wrap: anywhere; hyphens: auto; }
.aufgabe .quelle { display: block; font-size: 0.75rem; color: var(--text-leise); }
.aufgabe.erledigt .aufgabe-zeile p { text-decoration: line-through; color: var(--text-leise); }
.aufgabe .stapelzeile { padding-left: 2rem; }
.spaet { color: var(--warn); font-weight: 700; }
/* Höhere Spezifität als .aufgabe .quelle nötig, sonst gewinnt dessen
   --text-leise die Kaskade (zwei Klassen gegen eine), und "überfällig"
   bliebe unauffällig grau statt in der Warnfarbe. */
.aufgabe .quelle.spaet { color: var(--warn); }

.leiste { height: 6px; background: var(--linie); border-radius: 2px; overflow: hidden; }
.leiste i { display: block; height: 100%; background: var(--gut); }
.leiste.warn i { background: var(--warn); }
/* Fünferstufen für dynamisch berechnete Fortschritte (tasks.js:
   balkenKlasse) – eine feste Klassenliste statt eines Inline-Stils, den die
   Sicherheitsrichtlinie (style-src ohne 'unsafe-inline') verbietet. */
.balken-0 { width: 0%; }
.balken-5 { width: 5%; }
.balken-10 { width: 10%; }
.balken-15 { width: 15%; }
.balken-20 { width: 20%; }
.balken-25 { width: 25%; }
.balken-30 { width: 30%; }
.balken-35 { width: 35%; }
.balken-40 { width: 40%; }
.balken-45 { width: 45%; }
.balken-50 { width: 50%; }
.balken-55 { width: 55%; }
.balken-60 { width: 60%; }
.balken-65 { width: 65%; }
.balken-70 { width: 70%; }
.balken-75 { width: 75%; }
.balken-80 { width: 80%; }
.balken-85 { width: 85%; }
.balken-90 { width: 90%; }
.balken-95 { width: 95%; }
.balken-100 { width: 100%; }

.ziel-zeile {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.35rem 0.75rem;
  align-items: center;
  padding: 0.75rem;
}
.ziel-zeile .name { font-weight: 700; grid-column: 1; overflow-wrap: anywhere; hyphens: auto; }
.ziel-zeile .wo { grid-column: 1 / -1; }
.ziel-zeile .leiste { grid-column: 1 / -1; }
.ziel-zeile .knopf { min-height: 44px; padding: 0 0.875rem; font-size: 0.8125rem; }

.knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 1.25rem;
  border: 1px solid var(--signal);
  border-radius: 4px;
  background: var(--signal);
  color: var(--auf-signal);
  font: 700 0.9375rem/1 var(--schrift);
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
  transition: opacity 150ms linear;
}
.knopf:hover { opacity: 0.85; }
/* Ohne das war ein per disabled=true gesperrter Knopf während einer Anfrage
   nicht von einem bedienbaren zu unterscheiden – Doppel-Submits wurden zwar
   serverseitig verhindert, aber niemand sah, dass ein Klick schon lief
   (UI-Experte, Durchlauf 4). */
.knopf:disabled { opacity: 0.6; cursor: not-allowed; }
.knopf svg { width: 18px; height: 18px; margin-right: 0.4rem; }
.knopf.gut { background: var(--gut); border-color: var(--gut); color: var(--auf-gut); }
.knopf.nein { background: transparent; border-color: var(--fehler); color: var(--fehler); }
/* Zurückhaltender Knopf: tut etwas, ist aber nicht das, wonach die Seite
   ruft. Ohne ihn stünde „Reihe ab hier beenden" so auffällig da wie
   „Nur diesen Tag ändern" – und die beiden meinen sehr Verschiedenes. */
.knopf.still { background: transparent; border-color: var(--linie-stark); color: var(--text); }
.knopf.breit { width: 100%; }

.warnfeld {
  display: flex;
  gap: 0.625rem;
  align-items: flex-start;
  padding: 0.75rem;
  border: 1px solid var(--warn);
  border-left-width: 4px;
  border-radius: 4px;
  background: var(--warn-grund);
  color: var(--warn);
  font-size: 0.875rem;
}
.warnfeld svg { flex: none; width: 20px; height: 20px; }

/* --- Wochenraster: am Handy sechs schmale Spalten ------------------------ */
.wochenleiste {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.625rem 0.75rem;
}
.wochenleiste b { font: 700 0.9375rem/1.2 var(--schrift); }
.wochenleiste span { display: block; font: 400 0.75rem/1.3 var(--zahlen); color: var(--text-leise); }
.pfeil {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid var(--linie-stark);
  border-radius: 4px;
  color: var(--text);
  cursor: pointer;
}
.pfeil svg { width: 18px; height: 18px; }

.wochenraster {
  display: grid;
  gap: 1px;
  background: var(--linie);
  border-top: 1px solid var(--linie);
}
/* Mo–Fr stehen immer, Samstag/Sonntag nur bei Bedarf (Rückstand Punkt 7) –
   die Spaltenzahl kommt deshalb als Klasse, nicht als fester Wert oben.
   sp-von-N zählt dieselbe Weise: als Position in der sichtbaren Woche. */
.wochenraster.spalten-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.wochenraster.spalten-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.wochenraster.spalten-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); }
.wochenraster .spalte { background: var(--flaeche); padding: 0.375rem 0.25rem; min-height: 8rem; }
.wochenraster .spalte.heute { background: var(--flaeche-hoch); }
/* Die Tagesköpfe sind eigene Rasterzellen, nicht Teil der Spalte: Zwischen
   ihnen und den Spalten liegt der Streifen für ganztägige und mehrtägige
   Termine, der über alle Spalten reicht. */
.wochenraster .tagkopf {
  background: var(--flaeche);
  text-align: center;
  font: 700 0.6875rem/1.3 var(--schrift);
  letter-spacing: 0.04em;
  color: var(--text-leise);
  padding: 0.375rem 0.25rem;
}
.wochenraster .tagkopf.heute { background: var(--flaeche-hoch); color: var(--signal); }
.wochenraster .tagkopf span { display: block; font: 400 0.6875rem/1.3 var(--zahlen); }
.kachel {
  display: block;
  text-decoration: none;
  background: var(--signal-grund);
  border-left: 2px solid var(--signal);
  border-radius: 2px;
  padding: 0.3rem 0.25rem;
  margin-bottom: 0.25rem;
  font-size: 0.75rem;
  line-height: 1.25;
  min-height: 44px;
}
/* Höchstens drei Zeilen: Bei 36 px Textbreite (sechs Spalten auf 360 px)
   wird "Aktuelle Rechtsprechung Zivilrecht" sonst zu acht Zeilen Silben.
   Der volle Titel steht in der Tagesliste darunter und im title-Attribut.
   Dauerhaft besser wäre ein Kurzname am Termin – Frage an den Auftraggeber. */
.kachel b {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  font-weight: 700;
  hyphens: auto;
  overflow-wrap: anywhere;
}
.kachel time {
  display: block;
  font: 400 0.625rem/1.3 var(--zahlen);
  color: var(--text-leise);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kachel.aus-kachel { background: transparent; border-left-color: var(--warn); }
.kachel.aus-kachel b { text-decoration: line-through; color: var(--text-leise); }

/* --- Wochenansicht am Rechner: Stundenraster mit Zeitachse ---------------
   Vom Kunden so gewünscht (10.09.2026): am Handy die sechs Spalten aus C, weil
   dort die ganze Woche auf einen Blick zählt; am Rechner die Zeitachse aus
   Entwurf A, weil sich nur daran ablesen lässt, WANN er frei hat. Eine Lücke
   ist im Kachelraster nicht sichtbar, im Stundenraster schon.
   Beides steht im selben HTML und wird allein über die Breite umgeschaltet. */
.stundenraster { display: none; }

@media (min-width: 768px) {
  .wochenraster { display: none; }

  .stundenraster {
    display: grid;
    gap: 1px;
    background: var(--linie);
    border-top: 1px solid var(--linie);
  }
  .stundenraster.spalten-5 { grid-template-columns: 3.25rem repeat(5, minmax(0, 1fr)); }
  .stundenraster.spalten-6 { grid-template-columns: 3.25rem repeat(6, minmax(0, 1fr)); }
  .stundenraster.spalten-7 { grid-template-columns: 3.25rem repeat(7, minmax(0, 1fr)); }
  .stundenraster > * { background: var(--flaeche); }
  .stundenraster .kopfzelle {
    padding: 0.5rem 0.25rem;
    text-align: center;
    font: 700 0.75rem/1.3 var(--schrift);
    letter-spacing: 0.04em;
    color: var(--text-leise);
  }
  .stundenraster .kopfzelle span { display: block; font: 400 0.6875rem/1.3 var(--zahlen); }
  .stundenraster .kopfzelle.heute { background: var(--signal-grund); color: var(--signal); }

  /* Die Zeitachse gibt die Höhe vor: Ihre Stundenzellen sind die einzigen
     Zellen mit fester Höhe, alle Tagesspalten werden vom Raster auf dieselbe
     Höhe gezogen. Wieviele Stunden gezeigt werden, entscheidet das Programm
     aus den Terminen der Woche – deshalb steht hier keine feste Anzahl. */
  .stundenraster .stunden { display: grid; grid-auto-rows: var(--stunde); }
  .stundenraster .stunden b {
    font: 400 0.6875rem/1 var(--zahlen);
    color: var(--text-leise);
    text-align: right;
    padding: 0.25rem 0.5rem 0 0;
    border-top: 1px solid var(--linie);
  }

  .stundenraster .spalte {
    display: grid;
    grid-auto-rows: var(--viertel);
    /* Zwölf Spalten, damit sich gleichzeitige Termine ohne krumme Werte auf
       2, 3, 4 oder 6 Bahnen aufteilen lassen (siehe .bahn-*). */
    grid-template-columns: repeat(12, minmax(0, 1fr));
  }
  .stundenraster .spalte.heute { background-color: var(--flaeche-hoch); }
  /* Die Stundenlinien als Hintergrundbild statt als leere Zellen: So bleibt
     jede Spalte EIN Rasterbereich, in den die Termine gesetzt werden – und
     die Anzahl der Stunden muss im Stylesheet nirgends stehen. */
  .stundenraster .spalte {
    background-image: repeating-linear-gradient(
      to bottom,
      transparent 0 calc(var(--stunde) - 1px),
      var(--linie) calc(var(--stunde) - 1px) var(--stunde)
    );
  }
  .stundenraster .veranstaltung {
    margin: 2px;
    padding: 0.375rem 0.5rem;
    border-radius: 3px;
    border-left: 3px solid var(--signal);
    background: var(--signal-grund);
    font-size: 0.8125rem;
    line-height: 1.3;
    text-decoration: none;
    overflow: hidden;
  }
  .stundenraster .veranstaltung b {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
    font-weight: 700;
    overflow-wrap: anywhere;
    hyphens: auto;
  }
  .stundenraster .veranstaltung time { display: block; font: 400 0.6875rem/1.4 var(--zahlen); color: var(--text-leise); }
  .stundenraster .veranstaltung.aus-kachel { background: transparent; border-left-color: var(--warn); }
  .stundenraster .veranstaltung.aus-kachel b { text-decoration: line-through; color: var(--text-leise); }
}

/* --- Karteikarten -------------------------------------------------------- */
.abfragezeile { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.75rem; font: 700 0.875rem/1 var(--zahlen); }
.abfragezeile .rest { color: var(--text-leise); font-weight: 400; }

.kartenbild { margin: 0; padding: 0.75rem; display: grid; gap: 0.5rem; justify-items: center; }
.kartenbild svg, .kartenbild img { width: 100%; max-width: 32rem; height: auto; border: 1px solid var(--linie-stark); border-radius: 3px; }
/* Echte Fotos sind nie so gleichmässig hell wie die Entwurfs-Illustration –
   ein dunkler Hintergrund verhindert, dass ein noch ladendes oder schmaleres
   Bild wie ein Loch in der Seite wirkt. */
.kartenbild img { background: var(--flaeche-hoch); object-fit: contain; aspect-ratio: 4 / 3; }
.kartenbild figcaption { font-size: 0.75rem; color: var(--text-leise); }
.kartenpapier { fill: #f7f4ec; stroke: none; }
.kartenlinie { stroke: #d9d2c2; stroke-width: 1; }
.kartenschrift { fill: none; stroke: #16202e; stroke-width: 2.6; stroke-linecap: round; }

.antwortleiste { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
.antwortleiste .knopf { min-height: 60px; }

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

/* --- Einstellungen: Unterpunkte --------------------------------------------
   Eine Zeile je Unterseite, rechts der aktuelle Stand und ein Pfeil – wie
   in den Einstellungen des Handys. Die Akzentfarbe steht seit 11.09.2026
   nicht mehr selbst auf der Einstellungsseite, sondern dahinter. */
.unterpunkt {
  display: grid;
  grid-template-columns: 1fr auto 20px;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem;
  min-height: 56px;
  text-decoration: none;
}
.unterpunkt .name { display: block; font-weight: 700; }
.unterpunkt .quelle { display: block; font-size: 0.8125rem; color: var(--text-leise); }
.unterpunkt .stand { font: 700 0.8125rem/1 var(--schrift); color: var(--signal); white-space: nowrap; }
.unterpunkt svg { color: var(--text-leise); }

/* --- Einstellungsseite „Akzentfarbe" ------------------------------------- */
.wahl {
  display: grid;
  grid-template-columns: 1.5rem 1fr;
  gap: 0.75rem 0.875rem;
  align-items: center;
  padding: 0.875rem;
  min-height: 56px;
  cursor: pointer;
}
.wahl input {
  width: 1.5rem;
  height: 1.5rem;
  margin: 0;
  accent-color: var(--signal);
}
.wahl .name { display: block; font-weight: 700; }
.wahl .quelle { display: block; font-size: 0.8125rem; color: var(--text-leise); }
.wahl .probe {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}
.tupfer {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 4px;
  background: var(--signal);
  border: 1px solid var(--linie-stark);
  flex: none;
}
.probe .knopf { min-height: 40px; padding: 0 0.875rem; font-size: 0.8125rem; }
.probe .zeitprobe {
  font: 700 0.875rem/1 var(--zahlen);
  color: var(--signal);
  background: var(--signal-grund);
  border-left: 3px solid var(--signal);
  padding: 0.5rem 0.625rem;
  border-radius: 0 3px 3px 0;
}


/* === Rasterklassen für das Stundenraster ================================
   Ein Termin von 09:15 bis 11:45 braucht eine berechnete Position. Genau
   das darf hier nicht als Stil ins Markup geschrieben werden (siehe Regel 2
   im Kopf dieser Datei), also steht jede mögliche Position als Klasse hier:
   .z<n> ist die Anfangszeile, .d<n> die Anzahl Viertelstunden.
   Gezählt wird ab der ERSTEN gezeigten Stunde der Woche, nicht ab
   Mitternacht – das Programm rechnet den Versatz aus. 96 Zeilen decken
   auch den unwahrscheinlichen Fall ab, dass eine Woche von 0 bis 24 Uhr
   gezeigt wird.
   Termine werden auf die umschliessende Viertelstunde gerundet; die
   genaue Uhrzeit steht als Text in der Kachel. */
.z1{grid-row-start:1}.z2{grid-row-start:2}.z3{grid-row-start:3}.z4{grid-row-start:4}.z5{grid-row-start:5}.z6{grid-row-start:6}.z7{grid-row-start:7}.z8{grid-row-start:8}
.z9{grid-row-start:9}.z10{grid-row-start:10}.z11{grid-row-start:11}.z12{grid-row-start:12}.z13{grid-row-start:13}.z14{grid-row-start:14}.z15{grid-row-start:15}.z16{grid-row-start:16}
.z17{grid-row-start:17}.z18{grid-row-start:18}.z19{grid-row-start:19}.z20{grid-row-start:20}.z21{grid-row-start:21}.z22{grid-row-start:22}.z23{grid-row-start:23}.z24{grid-row-start:24}
.z25{grid-row-start:25}.z26{grid-row-start:26}.z27{grid-row-start:27}.z28{grid-row-start:28}.z29{grid-row-start:29}.z30{grid-row-start:30}.z31{grid-row-start:31}.z32{grid-row-start:32}
.z33{grid-row-start:33}.z34{grid-row-start:34}.z35{grid-row-start:35}.z36{grid-row-start:36}.z37{grid-row-start:37}.z38{grid-row-start:38}.z39{grid-row-start:39}.z40{grid-row-start:40}
.z41{grid-row-start:41}.z42{grid-row-start:42}.z43{grid-row-start:43}.z44{grid-row-start:44}.z45{grid-row-start:45}.z46{grid-row-start:46}.z47{grid-row-start:47}.z48{grid-row-start:48}
.z49{grid-row-start:49}.z50{grid-row-start:50}.z51{grid-row-start:51}.z52{grid-row-start:52}.z53{grid-row-start:53}.z54{grid-row-start:54}.z55{grid-row-start:55}.z56{grid-row-start:56}
.z57{grid-row-start:57}.z58{grid-row-start:58}.z59{grid-row-start:59}.z60{grid-row-start:60}.z61{grid-row-start:61}.z62{grid-row-start:62}.z63{grid-row-start:63}.z64{grid-row-start:64}
.z65{grid-row-start:65}.z66{grid-row-start:66}.z67{grid-row-start:67}.z68{grid-row-start:68}.z69{grid-row-start:69}.z70{grid-row-start:70}.z71{grid-row-start:71}.z72{grid-row-start:72}
.z73{grid-row-start:73}.z74{grid-row-start:74}.z75{grid-row-start:75}.z76{grid-row-start:76}.z77{grid-row-start:77}.z78{grid-row-start:78}.z79{grid-row-start:79}.z80{grid-row-start:80}
.z81{grid-row-start:81}.z82{grid-row-start:82}.z83{grid-row-start:83}.z84{grid-row-start:84}.z85{grid-row-start:85}.z86{grid-row-start:86}.z87{grid-row-start:87}.z88{grid-row-start:88}
.z89{grid-row-start:89}.z90{grid-row-start:90}.z91{grid-row-start:91}.z92{grid-row-start:92}.z93{grid-row-start:93}.z94{grid-row-start:94}.z95{grid-row-start:95}.z96{grid-row-start:96}

.d1{grid-row-end:span 1}.d2{grid-row-end:span 2}.d3{grid-row-end:span 3}.d4{grid-row-end:span 4}.d5{grid-row-end:span 5}.d6{grid-row-end:span 6}.d7{grid-row-end:span 7}.d8{grid-row-end:span 8}
.d9{grid-row-end:span 9}.d10{grid-row-end:span 10}.d11{grid-row-end:span 11}.d12{grid-row-end:span 12}.d13{grid-row-end:span 13}.d14{grid-row-end:span 14}.d15{grid-row-end:span 15}.d16{grid-row-end:span 16}
.d17{grid-row-end:span 17}.d18{grid-row-end:span 18}.d19{grid-row-end:span 19}.d20{grid-row-end:span 20}.d21{grid-row-end:span 21}.d22{grid-row-end:span 22}.d23{grid-row-end:span 23}.d24{grid-row-end:span 24}
.d25{grid-row-end:span 25}.d26{grid-row-end:span 26}.d27{grid-row-end:span 27}.d28{grid-row-end:span 28}.d29{grid-row-end:span 29}.d30{grid-row-end:span 30}.d31{grid-row-end:span 31}.d32{grid-row-end:span 32}
.d33{grid-row-end:span 33}.d34{grid-row-end:span 34}.d35{grid-row-end:span 35}.d36{grid-row-end:span 36}.d37{grid-row-end:span 37}.d38{grid-row-end:span 38}.d39{grid-row-end:span 39}.d40{grid-row-end:span 40}
.d41{grid-row-end:span 41}.d42{grid-row-end:span 42}.d43{grid-row-end:span 43}.d44{grid-row-end:span 44}.d45{grid-row-end:span 45}.d46{grid-row-end:span 46}.d47{grid-row-end:span 47}.d48{grid-row-end:span 48}
.d49{grid-row-end:span 49}.d50{grid-row-end:span 50}.d51{grid-row-end:span 51}.d52{grid-row-end:span 52}.d53{grid-row-end:span 53}.d54{grid-row-end:span 54}.d55{grid-row-end:span 55}.d56{grid-row-end:span 56}
.d57{grid-row-end:span 57}.d58{grid-row-end:span 58}.d59{grid-row-end:span 59}.d60{grid-row-end:span 60}.d61{grid-row-end:span 61}.d62{grid-row-end:span 62}.d63{grid-row-end:span 63}.d64{grid-row-end:span 64}
.d65{grid-row-end:span 65}.d66{grid-row-end:span 66}.d67{grid-row-end:span 67}.d68{grid-row-end:span 68}.d69{grid-row-end:span 69}.d70{grid-row-end:span 70}.d71{grid-row-end:span 71}.d72{grid-row-end:span 72}
.d73{grid-row-end:span 73}.d74{grid-row-end:span 74}.d75{grid-row-end:span 75}.d76{grid-row-end:span 76}.d77{grid-row-end:span 77}.d78{grid-row-end:span 78}.d79{grid-row-end:span 79}.d80{grid-row-end:span 80}
.d81{grid-row-end:span 81}.d82{grid-row-end:span 82}.d83{grid-row-end:span 83}.d84{grid-row-end:span 84}.d85{grid-row-end:span 85}.d86{grid-row-end:span 86}.d87{grid-row-end:span 87}.d88{grid-row-end:span 88}
.d89{grid-row-end:span 89}.d90{grid-row-end:span 90}.d91{grid-row-end:span 91}.d92{grid-row-end:span 92}.d93{grid-row-end:span 93}.d94{grid-row-end:span 94}.d95{grid-row-end:span 95}.d96{grid-row-end:span 96}

/* Die Linie „jetzt" im Stundenraster. Sie sitzt auf derselben Zeilenleiste
   wie die Termine, liegt aber über ihnen. */
.stundenraster .jetzt {
  grid-column: 1 / -1;
  align-self: start;
  height: 2px;
  margin-top: -1px;
  background: var(--fehler);
  z-index: 1;
  pointer-events: none;
}

/* === Bahnen für gleichzeitige Termine ===================================
   Zwei Vorlesungen zur selben Zeit stünden sonst übereinander und die
   hintere wäre unsichtbar. Die Tagesspalte hat zwölf Rasterspalten.

   ÜBERLAPPEND statt gleich geteilt: Bei 64 px Spaltenbreite (768 px mit
   Seitenleiste) blieben von drei gleich geteilten Bahnen je 19 px – lesbar
   war "Ö R I". Jetzt behält jede Kachel rund zwei Drittel der Breite, die
   nächste liegt versetzt darüber; die linke obere Ecke mit Titelanfang und
   Uhrzeit bleibt bei jeder frei. Der z-index steigt mit der Bahn, damit die
   spätere über der früheren liegt. Sechs Bahnen sind die Obergrenze
   (nochmals zwölf Spalten geteilt); fünf benutzen die Sechserteilung. */
.bahn-1-1 { grid-column: 1 / 13; }
.bahn-2-1 { grid-column: 1 / 9; }   .bahn-2-2 { grid-column: 5 / 13; z-index: 1; }
.bahn-3-1 { grid-column: 1 / 8; }   .bahn-3-2 { grid-column: 4 / 11; z-index: 1; }
.bahn-3-3 { grid-column: 6 / 13; z-index: 2; }
.bahn-4-1 { grid-column: 1 / 7; }   .bahn-4-2 { grid-column: 3 / 9; z-index: 1; }
.bahn-4-3 { grid-column: 5 / 11; z-index: 2; }  .bahn-4-4 { grid-column: 7 / 13; z-index: 3; }
.bahn-6-1 { grid-column: 1 / 5; }   .bahn-6-2 { grid-column: 3 / 7; z-index: 1; }
.bahn-6-3 { grid-column: 5 / 9; z-index: 2; }   .bahn-6-4 { grid-column: 7 / 11; z-index: 3; }
.bahn-6-5 { grid-column: 8 / 12; z-index: 4; }  .bahn-6-6 { grid-column: 9 / 13; z-index: 5; }

/* === Anmeldung ==========================================================
   Eigener Bildschirm ohne Navigation: Vor der Anmeldung gibt es nichts zu
   navigieren. */
.anmeldung {
  min-height: 100dvh;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 1rem;
  padding: 1.5rem;
}
.anmeldung .block { width: 100%; max-width: 22rem; }
.anmeldung h1 { font-size: 1.5rem; }
.anmeldung .marke { color: var(--text-leise); }

/* === Kopfzeile: Werkzeuge rechts ======================================== */
.kopf .werkzeuge { display: flex; gap: 0.375rem; align-items: center; }
.kopf .werkzeuge a, .kopf .werkzeuge button {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--linie-stark);
  border-radius: 4px;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  text-decoration: none;
}
.kopf .werkzeuge svg { width: 20px; height: 20px; }
.kopf .werkzeuge a[aria-current="page"] { color: var(--signal); border-color: var(--signal); }

/* === Reiter Tag · Woche · Monat ========================================= */
.reiter { display: flex; flex-wrap: wrap; gap: 0.375rem; padding: 0.625rem 0.75rem; }
/* Ausdrücklich nur die Reiter, nicht jeder Verweis in der Leiste: Ein
   .reiter a würde auch den Knopf „Termin" treffen und ihm seine
   Knopffarbe nehmen – heller Text auf hellem Grund. */
.reiter .reiter-eintrag {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 0.875rem;
  border: 1px solid var(--linie-stark);
  border-radius: 4px;
  text-decoration: none;
  font: 700 0.8125rem/1 var(--schrift);
  color: var(--text-leise);
}
.reiter .reiter-eintrag[aria-current="page"] {
  color: var(--signal);
  border-color: var(--signal);
  background: var(--signal-grund);
}
.reiter .luecke { flex: 1 1 auto; }
/* Steht NACH .reiter-eintrag, sonst gewinnt dessen Polsterung.
   Bei 360 px passen drei Reiter und der Knopf nur in eine Zeile, wenn die
   Reiter enger sind; die Trefferfläche bleibt 44 px hoch. */
@media (max-width: 400px) {
  .reiter { padding: 0.5rem; gap: 0.25rem; }
  .reiter .reiter-eintrag { padding: 0 0.6rem; }
  .reiter .knopf { padding: 0 0.75rem; }
}

/* === Monatsraster =======================================================
   Am Handy sind sieben Spalten rund 50 px breit – dort steht die Zahl und
   je ein Punkt pro Termin. Ab 768 px ist Platz für Uhrzeit und Titel.
   Dieselbe Entscheidung wie bei der Woche, aus demselben Grund. */
.monatskopf {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--linie);
  border-top: 1px solid var(--linie);
}
.monatskopf span {
  background: var(--flaeche);
  padding: 0.375rem 0.25rem;
  text-align: center;
  font: 700 0.6875rem/1.3 var(--schrift);
  letter-spacing: 0.04em;
  color: var(--text-leise);
}
.monatsraster {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--linie);
}
.monatsraster .tag {
  background: var(--flaeche);
  min-height: 4.5rem;
  padding: 0.25rem;
  display: grid;
  align-content: start;
  gap: 2px;
  text-decoration: none;
}
.monatsraster .tag.fremd { background: var(--grund); }
.monatsraster .tag.fremd .monatszahl { color: var(--text-leise); }
.monatsraster .tag.heute { background: var(--flaeche-hoch); }
.monatszahl { font: 700 0.8125rem/1.2 var(--zahlen); text-align: right; padding: 0 0.125rem; }
.monatsraster .tag.heute .monatszahl { color: var(--signal); }
.punkte { display: flex; flex-wrap: wrap; gap: 3px; padding: 0.125rem; }
.punkte i { width: 6px; height: 6px; border-radius: 50%; background: var(--signal); }
.punkte i.aus { background: transparent; border: 1px solid var(--warn); }
.minikachel { display: none; }
@media (min-width: 768px) {
  .monatsraster .tag { min-height: 6.5rem; }
  .punkte { display: none; }
  .minikachel {
    display: block;
    background: var(--signal-grund);
    border-left: 2px solid var(--signal);
    border-radius: 2px;
    padding: 0.125rem 0.25rem;
    font-size: 0.75rem;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .minikachel time { font: 400 0.6875rem/1.25 var(--zahlen); color: var(--text-leise); margin-right: 0.25rem; }
  .minikachel.aus-kachel { background: transparent; border-left-color: var(--warn); color: var(--text-leise); text-decoration: line-through; }
  .mehr { font-size: 0.6875rem; color: var(--text-leise); padding-left: 0.25rem; }
  /* Ab hier zählen die Minikacheln (drei), nicht die Punkte (vier). */
  .mehr-punkte { display: none; }
  .mehr-kacheln { display: block; }
}
.mehr { font-size: 0.6875rem; color: var(--text-leise); }
.mehr-kacheln { display: none; }

/* === Eingabemaske ======================================================= */
.maske { display: grid; gap: 0.875rem; padding: 0.875rem; }
.maske label { display: grid; gap: 0.3rem; }
.maske .feldname {
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-leise);
}
.maske input[type="text"], .maske input[type="date"], .maske input[type="time"],
.maske input[type="number"], .maske input[type="password"], .maske select, .maske textarea {
  font: inherit;
  width: 100%;
  min-height: 48px;
  padding: 0.6rem 0.7rem;
  background: var(--grund);
  color: var(--text);
  border: 1px solid var(--linie-stark);
  border-radius: 4px;
}
.maske textarea { min-height: 5rem; resize: vertical; }
.maske .reihe { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
/* Zwei Felder je Zeile ab 768 px; am Handy untereinander. Und die Maske
   endet bei 52 rem: Ein Titelfeld über 1 100 px Breite hilft niemandem. */
.maske .zeile { display: grid; gap: 0.875rem; align-items: start; }
.masken-block { width: 100%; max-width: 52rem; }
@media (min-width: 768px) {
  .maske .zeile { grid-template-columns: 1fr 1fr; }
  /* Die bestätigende Tat steht rechts, Abbrechen links davon – und die
     Knöpfe wachsen nicht mehr über die halbe Maske. */
  .knopfreihe.aktionen { justify-content: flex-end; }
  .knopfreihe.aktionen .knopf { flex: 0 1 auto; min-width: 10rem; }
}
.maske .schalter {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 48px;
  cursor: pointer;
}
.maske .schalter input { width: 1.5rem; height: 1.5rem; margin: 0; accent-color: var(--signal); }
.maske .schalter .feldname { letter-spacing: 0.06em; color: var(--text); }
.maske .hinweis { font-size: 0.8125rem; color: var(--text-leise); }
.knopfreihe { display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0.875rem; }
.knopfreihe .knopf { flex: 1 1 10rem; }

/* === Terminkarte und Popover ============================================
   Ein Termin öffnet sich als Karte ÜBER der Ansicht, nicht als eigene Seite
   (Kunde, 11.09.2026). Ein echtes <dialog>: Abdunkeln, Escape, Fokusfalle
   und Rückkehr des Fokus kommen vom Browser. Am Rechner mittig, am Handy
   als Blatt von unten – dort ist der Daumen. */
.popover {
  padding: 0;
  border: 1px solid var(--linie-stark);
  border-radius: 6px;
  background: var(--flaeche-hoch);
  color: var(--text);
  width: min(100% - 2rem, 30rem);
  max-height: calc(100dvh - 2rem);
  box-shadow: 0 12px 40px rgb(0 0 0 / 0.45);
}
.popover::backdrop { background: rgb(0 0 0 / 0.55); }
.popover-inhalt { position: relative; display: grid; }
.popover-inhalt > * + * { border-top: 1px solid var(--linie); }
.popover .schliessen {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid transparent;
  border-radius: 4px;
  background: transparent;
  color: var(--text-leise);
  cursor: pointer;
}
.popover .schliessen:hover { color: var(--text); border-color: var(--linie-stark); }
.popover .schliessen + * { border-top: 0; }
@media (max-width: 767px) {
  .popover {
    margin: auto 0 0 0;
    width: 100%;
    max-width: none;
    max-height: 88dvh;
    border-radius: 10px 10px 0 0;
    border-bottom: 0;
    padding-bottom: env(safe-area-inset-bottom);
  }
}

/* Der Kopf der Karte: Kategorie, Titel, Wann, Wo, Notiz. Die Kategorie
   färbt wie überall nur --signal; der Balken links ist derselbe wie in der
   Terminliste. */
.termin-kopf { display: grid; gap: 0.25rem; padding: 0.875rem 3.25rem 0.875rem 0.875rem; }
.termin-kopf[data-farbe] { border-left: 3px solid var(--signal); }
.termin-kopf .kategorie { font-size: 0.8125rem; color: var(--text-leise); }
.termin-kopf .was { font-size: 1.125rem; overflow-wrap: anywhere; hyphens: auto; }
.termin-kopf .was:focus { outline: none; }
.termin-kopf .wann { font: 700 0.9375rem/1.35 var(--zahlen); color: var(--signal); }
.termin-kopf .wo { font-size: 0.8125rem; color: var(--text-leise); }
.termin-kopf .notiz { margin-top: 0.5rem; font-size: 0.875rem; white-space: pre-wrap; }
.termin-karte .termin-kopf { padding-right: 0.875rem; }
/* Taten nach Reichweite: kleine Überschrift, darunter die Knöpfe. */
.gruppe > h3 {
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-leise);
  padding: 0.75rem 0.875rem 0;
}
.popover .knopfreihe { padding: 0.75rem 0.875rem; }
.popover .knopf { min-height: 44px; font-size: 0.875rem; padding: 0 1rem; }

/* === Zustände: leer, lädt, Fehler ======================================= */
.leer { padding: 1.25rem 0.875rem; color: var(--text-leise); font-size: 0.875rem; text-align: center; }
.fehlerfeld {
  display: flex;
  gap: 0.625rem;
  align-items: flex-start;
  padding: 0.75rem;
  border: 1px solid var(--fehler);
  border-left-width: 4px;
  border-radius: 4px;
  background: var(--flaeche);
  color: var(--fehler);
  font-size: 0.875rem;
}

/* Kurzmeldung nach dem Speichern. Über der Navigationsleiste, damit sie am
   Handy nicht unter dem Daumen verschwindet. */
.meldung {
  position: fixed;
  left: 0.75rem;
  right: 0.75rem;
  bottom: calc(5rem + env(safe-area-inset-bottom));
  z-index: 5;
  padding: 0.75rem 0.875rem;
  border: 1px solid var(--linie-stark);
  border-left: 4px solid var(--gut);
  border-radius: 4px;
  background: var(--flaeche-hoch);
  color: var(--text);
  font-size: 0.875rem;
  box-shadow: 0 6px 20px rgb(0 0 0 / 0.35);
}
.meldung.schlecht { border-left-color: var(--fehler); color: var(--fehler); }
@media (min-width: 768px) {
  .meldung { left: auto; right: 1.5rem; bottom: 1.5rem; max-width: 24rem; }
}

/* Kein Netz (Phase 6, Punkt 11): anders als .meldung nicht von selbst
   verschwindend – der Zustand hält an, bis wieder Netz da ist. Bewusst im
   normalen Fluss (nicht fixiert): .kopf ist selbst nicht fixiert, ein
   fixiertes Band läge sonst über der Überschrift statt sie zu verdrängen. */
.offline-band {
  padding: calc(0.375rem + env(safe-area-inset-top, 0px)) 0.75rem 0.375rem;
  text-align: center;
  font-size: 0.8125rem;
  font-weight: 700;
  background: var(--warn-grund);
  color: var(--warn);
  border-bottom: 1px solid var(--warn);
}

/* Lädt: alten Inhalt abblenden und sperren, bis die neue Seite da ist.
   Der Übergang fällt unter prefers-reduced-motion weg (Regel weiter unten). */
.inhalt[aria-busy="true"] { opacity: 0.55; pointer-events: none; transition: opacity 150ms linear; }

/* Dasselbe für einen einzelnen ladenden Block innerhalb einer Seite (z. B.
   ics.js beim Einlesen) – die Seite drumherum bleibt bedienbar, der
   Ladeblock selbst zeigt denselben Zustand wie oben. */
.block[aria-busy="true"] { opacity: 0.55; transition: opacity 150ms linear; }

/* === Kleinigkeiten ====================================================== */
.stapelzeile { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.termin .uhr .dauer { font-size: 0.6875rem; }
.kachel.geaendert-kachel { border-left-color: var(--warn); }
.stundenraster .veranstaltung.geaendert-kachel { border-left-color: var(--warn); }
.marke-unbekannt {
  display: inline-block;
  margin-left: 0.375rem;
  padding: 0.15rem 0.35rem;
  border: 1px solid var(--fehler);
  border-radius: 3px;
  color: var(--fehler);
  font: 700 0.625rem/1 var(--schrift);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  vertical-align: 0.1em;
}
.nurlesen { position: absolute; left: -9999px; }

/* --- Nachträge zum Entwurf ------------------------------------------------
   Alles hier folgt aus Fällen, die die vier Entwurfsseiten nicht zeigen
   konnten – nicht aus einer Meinungsänderung zur Gestaltung. */

/* Tagesköpfe sind Verweise auf den einzelnen Tag. Am Handy gilt für sie
   dieselbe Mindesthöhe wie für alles Antippbare: 44 px. */
.wochenraster .tagkopf, .stundenraster .kopfzelle { text-decoration: none; }
a.tagkopf { display: grid; align-content: center; min-height: 44px; }
a.kopfzelle { display: block; }

/* === Streifen für ganztägige und mehrtägige Termine =====================
   Ein Termin über mehrere Tage ist EIN Balken über alle berührten Tage –
   nicht je Tag eine Kachel „ab 09:00" / „bis 17:00" (Kunde, 11.09.2026:
   der Klausurenkurs). Der Streifen liegt über den Tagesspalten und reicht
   über die ganze Breite; innen wiederholt er die Spaltenvorlage des Rasters
   mit demselben Abstand, deshalb liegen seine Spalten genau über denen des
   Rasters. Die Lage eines Balkens ist eine Klasse (.sp-von-N, .sp-tage-N),
   kein Stil – Regel 2 im Kopf dieser Datei. `dense`: Zwei Balken, die sich
   nicht überschneiden, teilen sich eine Zeile. */
.streifen {
  grid-column: 1 / -1;
  display: grid;
  grid-auto-flow: row dense;
  gap: 2px 1px;
  padding: 0.25rem 0;
  background: var(--flaeche);
  border-bottom: 1px solid var(--linie);
}
.wochenraster.spalten-5 .streifen { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.wochenraster.spalten-6 .streifen { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.wochenraster.spalten-7 .streifen { grid-template-columns: repeat(7, minmax(0, 1fr)); }
.streifen .achse {
  grid-column: 1;
  grid-row: 1;
  font: 400 0.625rem/1.2 var(--zahlen);
  color: var(--text-leise);
  text-align: right;
  padding: 0.35rem 0.5rem 0 0;
  /* "ganztägig" passt bei 0,625rem nicht in die 3,25rem breite Zeitachsen-
     spalte – mit white-space:nowrap + overflow:hidden (Fundstand, Rückstand
     Punkt 8) stand dort sichtbar "ganztägi" statt des ganzen Worts. Zwei
     Zeilen sind hier unproblematisch: Die Zeile wächst mit dem Inhalt
     (kein festes grid-auto-rows), es gibt also nichts, worüber der Text
     hinausragen könnte. */
  overflow-wrap: break-word;
}
.streifen .kachel { margin: 0 2px; min-height: 0; }
.streifen .kachel time { white-space: normal; }
/* Ohne Zeitachse (Handy) beginnt Montag in Spalte 1, mit Zeitachse in 2. */
.wochenraster .sp-von-1 { grid-column-start: 1; }
.wochenraster .sp-von-2 { grid-column-start: 2; }
.wochenraster .sp-von-3 { grid-column-start: 3; }
.wochenraster .sp-von-4 { grid-column-start: 4; }
.wochenraster .sp-von-5 { grid-column-start: 5; }
.wochenraster .sp-von-6 { grid-column-start: 6; }
.wochenraster .sp-von-7 { grid-column-start: 7; }
.stundenraster .sp-von-1 { grid-column-start: 2; }
.stundenraster .sp-von-2 { grid-column-start: 3; }
.stundenraster .sp-von-3 { grid-column-start: 4; }
.stundenraster .sp-von-4 { grid-column-start: 5; }
.stundenraster .sp-von-5 { grid-column-start: 6; }
.stundenraster .sp-von-6 { grid-column-start: 7; }
.stundenraster .sp-von-7 { grid-column-start: 8; }
.sp-tage-1 { grid-column-end: span 1; }
.sp-tage-2 { grid-column-end: span 2; }
.sp-tage-3 { grid-column-end: span 3; }
.sp-tage-4 { grid-column-end: span 4; }
.sp-tage-5 { grid-column-end: span 5; }
.sp-tage-6 { grid-column-end: span 6; }
.sp-tage-7 { grid-column-end: span 7; }
@media (min-width: 768px) {
  .stundenraster.spalten-5 .streifen { grid-template-columns: 3.25rem repeat(5, minmax(0, 1fr)); }
  .stundenraster.spalten-6 .streifen { grid-template-columns: 3.25rem repeat(6, minmax(0, 1fr)); }
  .stundenraster.spalten-7 .streifen { grid-template-columns: 3.25rem repeat(7, minmax(0, 1fr)); }
  .streifen .kachel { font-size: 0.8125rem; padding: 0.3rem 0.5rem; }
  .streifen .kachel b { -webkit-line-clamp: 2; }
  .streifen .kachel time { font-size: 0.6875rem; white-space: nowrap; }
}

/* "ganztägig" passt nicht in die Monospace-Uhrzeitspalte einer Terminzeile. */
.termin .uhr.ganztags { font: 700 0.75rem/1.35 var(--schrift); letter-spacing: -0.01em; }

/* Ein Seitenteil, der sich selbst neu zeichnet (die Kategorienseite), ist EIN
   Rasterfeld im Inhalt – ohne diese Zeile fehlte zwischen seinen Blöcken der
   Abstand, den .inhalt sonst setzt. */
.seitenteil { display: grid; gap: 0.75rem; align-content: start; }

/* --- Kategorien -----------------------------------------------------------
   DER ZUSTAND SCHLÄGT DIE KATEGORIE. Ein abgesagter Termin bleibt gelb
   umrandet, ohne Füllung und durchgestrichen, auch wenn seine Kategorie rot
   ist. Dafür ist keine neue Regel nötig: `.kachel.aus-kachel` und
   `.veranstaltung.aus-kachel` setzen Hintergrund und Rahmenfarbe schon und
   sind spezifischer als `.kachel`. Die Kategorie ändert nur --signal, nicht
   diese Regeln. Wer hier etwas umbaut, muss diese Reihenfolge erhalten –
   sonst hinge „fällt aus" an einer Farbe, die der Kunde frei vergibt.

   In der Terminliste trägt die Kategorie einen Balken links, wie ein
   laufender Termin. Die 3 px Versatz sind dieselben wie dort – der Entwurf
   gleicht sie bewusst nicht aus. */
.termin[data-farbe] { border-left: 3px solid var(--signal); }
/* NACH der Kategorieregel, gleich spezifisch – die spätere gewinnt. Vorher
   trug ein geänderter Zivilrecht-Termin in der Liste einen blauen Balken,
   in der Wochenkachel einen gelben (UI-Experte, Durchlauf 2). */
.termin.geaendert { border-left: 3px solid var(--warn); }

/* Farbtupfer vor dem Kategorienamen – Farbe ist nie der einzige Träger einer
   Information, der Name steht immer daneben. */
.kat-tupfer {
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 2px;
  background: var(--signal);
  border: 1px solid var(--linie-stark);
  vertical-align: -0.05em;
  margin-right: 0.35rem;
  flex: none;
}
.kat-zeile {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.5rem 0.75rem;
  align-items: center;
  padding: 0.75rem;
}
.kat-zeile .name { font-weight: 700; overflow-wrap: anywhere; hyphens: auto; }
.kat-zeile .wo { grid-column: 1; }
.kat-zeile .knopf { min-height: 44px; padding: 0 0.875rem; font-size: 0.8125rem; }

/* Farbwahl in der Kategorie-Maske: acht Tupfer statt eines Auswahlfelds –
   eine Farbe wählt man nach dem Aussehen, nicht nach dem Namen. */
.farbwahl { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.farbwahl label {
  position: relative;
  display: grid;
  grid-template-rows: 48px auto;
  justify-items: center;
  gap: 0.25rem;
  width: 4.5rem;
  cursor: pointer;
}
.farbwahl .farbname { font-size: 0.6875rem; color: var(--text-leise); text-align: center; line-height: 1.2; }
/* Der Auswahlknopf liegt unsichtbar über dem Tupfer: Er bleibt ein echtes
   <input type="radio"> – mit Tastatur bedienbar, für Bildschirmleser eine
   Auswahl, mit dem Namen der Farbe als Beschriftung daneben (.nurlesen).
   Sichtbar ist der Tupfer, ausgewählt wird er über den Geschwisterwähler und
   nicht über :has() – der Ring muss auch dort erscheinen, wo :has() fehlt,
   sonst wäre gar nicht zu sehen, welche Farbe gewählt ist. */
.farbwahl input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.farbwahl i {
  display: block;
  width: 48px;
  height: 48px;
  border-radius: 4px;
  border: 1px solid var(--linie-stark);
  background: var(--signal-grund);
  box-shadow: inset 0 0 0 6px var(--signal);
}
.farbwahl input:checked + i { border-color: var(--signal); box-shadow: inset 0 0 0 12px var(--signal); }
.farbwahl input:focus-visible + i { outline: 3px solid var(--text); outline-offset: 2px; }

/* === Kalenderdatei: Einlesen, Bilanz, Abonnement (Phase 3) ============= */

/* Der Datei-Knopf ist ein <label> um ein echtes <input type="file">: Der
   Browser öffnet die Dateiwahl selbst, das Feld bleibt mit Tastatur
   erreichbar. Sichtbar ist nur der Knopf; das Feld liegt unsichtbar darüber
   (wie der Auswahlknopf in .farbwahl, aus demselben Grund). */
.datei-knopf { position: relative; cursor: pointer; }
.datei-knopf input { position: absolute; inset: 0; width: 100%; opacity: 0; cursor: pointer; }
.datei-knopf:has(input:focus-visible) { outline: 3px solid var(--text); outline-offset: 2px; }

/* Die Bilanz-Überschrift bekommt nach dem Lesen den Fokus (Bildschirmleser
   sollen dort weiterlesen) – ohne Ring, wie die Seitenüberschrift. */
.block > h2:focus { outline: none; }
.bilanz-summe { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; }
.bilanz-summe .zahl { font: 700 1.125rem/1.2 var(--zahlen); }
.bilanz-summe .statuszeile { display: flex; flex-wrap: wrap; gap: 0.375rem; }

/* Eine Zeile der Bilanz: Zeitspalte in Monospace wie in der Terminliste,
   Titel daneben. Kein Verweis – die Termine sind noch nicht im Kalender. */
.bilanz-zeile {
  display: grid;
  /* „Do 15.10. 09:15" in Monospace braucht 7 rem; darunter bräche die Zeit
     in den Titel hinein. */
  grid-template-columns: 7.5rem 1fr;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  min-height: 44px;
  align-items: start;
}
.bilanz-zeile .uhr { font: 700 0.8125rem/1.4 var(--zahlen); color: var(--signal); }
@media (max-width: 400px) {
  /* Bei 360 px bleiben dem Titel sonst 8 rem: Zeit und Titel untereinander. */
  .bilanz-zeile { grid-template-columns: 1fr; gap: 0.125rem; }
}
.bilanz-zeile .was { display: block; font-weight: 700; overflow-wrap: anywhere; hyphens: auto; }
.bilanz-zeile .wo { display: block; font-size: 0.8125rem; color: var(--text-leise); }
.bilanz-zeile.entfaellt .was { text-decoration: line-through; color: var(--text-leise); }
.bilanz-zeile.entfaellt .uhr { color: var(--warn); }

/* Zugeklappte Liste der unveränderten Termine. Die Zusammenfassung ist
   Trefferfläche wie eine Überschrift. */
.bilanz-mehr summary {
  padding: 0.625rem 0.75rem;
  min-height: 44px;
  display: flex;
  align-items: center;
  cursor: pointer;
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-leise);
}
.bilanz-mehr summary:focus-visible { outline: 3px solid var(--text); outline-offset: -3px; }

/* Adresse ausgeschrieben und umbrechend – das Eingabefeld darunter scrollt
   nur einzeilig und zeigt sie am Handy nie ganz auf einen Blick. */
.adresstext { font: 0.8125rem/1.4 var(--zahlen); overflow-wrap: anywhere; }

/* Adresse zum Kopieren: das Feld darf schrumpfen, der Knopf nicht. */
.kopierfeld { display: flex; gap: 0.5rem; align-items: stretch; }
.kopierfeld input {
  flex: 1 1 auto;
  min-width: 0;
  font: 0.8125rem/1.4 var(--zahlen);
  padding: 0.6rem 0.7rem;
  background: var(--grund);
  color: var(--text);
  border: 1px solid var(--linie-stark);
  border-radius: 4px;
}
.kopierfeld .knopf { flex: 0 0 auto; }

/* ============================================================================
   Aufgaben („Lernzielkarten") und Lernen („Lernkasten")
   Übernommen aus den Struktur-Entwürfen entwuerfe/aufgaben und
   entwuerfe/lernen (entwuerfe/gemeinsam/bausteine.css + der für Entwurf 2
   nötige Teil aus entwuerfe/lernen/zusatz.css). Nichts hier ändert eine
   Regel weiter oben – reine Ergänzung um Klassen, die die App bis jetzt
   nicht brauchte. Farben ausschliesslich als vorhandene Namen von oben.
   Trefferflächen: nie unter 44 px, nebeneinander mindestens 0.5rem Luft. */

/* --- Gemeinsame Kleinigkeiten ------------------------------------------- */

/* Metazeile („12.02.2027 · noch 150 Tage", „18 Karten · 5 heute fällig").
   .wo ist oben nur innerhalb von .termin und .ziel-zeile gestylt – in den
   neuen Bausteinen wäre sie sonst so gross wie der Titel. */
.eintrag-karte .wo, .detail-kopf .wo, .dialog-kopf .wo, .kachel-liste .wo {
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--text-leise);
}

/* .aufgabe-text ist oben nur ein <div> gestylt (min-width:0) – auf
   /aufgaben öffnet ein Tipp auf den Text jetzt den Ändern-Dialog, dafür
   ist er ein <button>. Reset auf denselben Stand wie ein reines <div>. */
button.aufgabe-text {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* Block-Beschriftung mit einem Knopf rechts daneben. Die h2 sieht genauso
   aus wie .block > h2 (dort greift die Regel nicht, weil die h2 hier in
   einem Wrapper steckt). Der Knopf ist leichter als ein Aktionsknopf: eine
   Nebenhandlung, kein Aufruf. */
.block-kopfzeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.375rem 0.375rem 0.375rem 0.75rem;
  min-height: 44px;
  border-bottom: 1px solid var(--linie);
}
.block-kopfzeile h2 {
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-leise);
  padding: 0;
  border: 0;
}
.block-kopfzeile .knopf { flex: none; min-height: 40px; padding: 0 0.75rem; font-size: 0.8125rem; }
/* .block > * + * setzt bereits einen Strich oberhalb – nicht doppelt. */
.block > .block-kopfzeile + * { border-top: 0; }

/* Knöpfe mit Symbol davor (knopf() in kern.js). */
.knopf svg + span { margin-left: 0; }
.knopf.still svg { color: var(--text-leise); }

/* Zurückhaltende Zeile „+ Neues Lernziel" / „+ Aufgabe hinzufügen" am Ende
   einer Liste: volle Breite, Signalfarbe, ohne Rahmen – sichtbar, aber
   leiser als der eigentliche Aktionsknopf. */
.hinzu-zeile {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  min-height: 48px;
  padding: 0 0.75rem;
  border: 0;
  background: transparent;
  color: var(--signal);
  font: 700 0.875rem/1.3 var(--schrift);
  text-align: left;
  cursor: pointer;
  transition: background 150ms linear;
}
.hinzu-zeile:hover { background: var(--signal-grund); }
.hinzu-zeile svg { width: 18px; height: 18px; flex: none; }

/* Zurück-Verweis im Drill-down. Ein Pfeil-Symbol statt eines Textzeichens,
   damit es überall gleich aussieht. */
.zurueck-schmal {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-height: 44px;
  padding: 0 0.75rem 0 0.5rem;
  color: var(--text-leise);
  text-decoration: none;
  font: 700 0.8125rem/1 var(--schrift);
}
.zurueck-schmal:hover { color: var(--text); }
.zurueck-schmal svg { width: 18px; height: 18px; }
/* Der Strich zwischen Zurück-Verweis und Kopf darunter wäre einer zu viel. */
.block > .zurueck-schmal + * { border-top: 0; }

/* Kopf einer Detailansicht: echte Überschrift (nicht die winzige
   Block-Beschriftung – der Titel ist hier das Thema der Seite), rechts
   Knöpfe, darunter Metazeilen, Balken, Stand. */
.detail-kopf { display: grid; gap: 0.25rem; padding: 0.75rem; }
.detail-kopf-zeile { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; }
.detail-kopf h2 { font-size: 1.125rem; line-height: 1.3; overflow-wrap: anywhere; hyphens: auto; min-width: 0; padding-top: 0.35rem; }
.detail-kopf h2:focus { outline: none; }
.detail-kopf-knoepfe { display: flex; gap: 0.5rem; flex: none; }
.detail-kopf .knopf { flex: none; min-height: 40px; padding: 0 0.75rem; font-size: 0.8125rem; }
.detail-kopf .leiste { margin-top: 0.25rem; }
/* Knopf nur mit Symbol (Stift): quadratisch, aber beschriftet (aria-label). */
.detail-kopf .knopf.nur-symbol { width: 40px; padding: 0; }
.detail-kopf .knopf.nur-symbol svg { margin: 0; }

/* Leerzustand mit Handlung: Text plus der eine nächste Schritt. */
.leer-mit-tat {
  display: grid;
  justify-items: center;
  gap: 0.75rem;
  padding: 1.5rem 0.875rem;
  color: var(--text-leise);
  font-size: 0.875rem;
  text-align: center;
}
.leer-mit-tat .knopf { min-height: 44px; font-size: 0.875rem; padding: 0 1rem; }

/* --- Schwebender Knopf: immer erreichbar, verdeckt aber nie die untere
   Navigation (deren Höhe hier fest nachgebildet ist) – und dank des
   Zusatz-Abstands am Inhaltsende auch nicht die letzte Zeile. --- */
.schwebeknopf {
  position: fixed;
  right: 1rem;
  bottom: calc(5rem + env(safe-area-inset-bottom));
  z-index: 4;
  gap: 0.375rem;
  padding: 0 1.125rem 0 0.875rem;
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.4);
}
.schwebeknopf svg { width: 20px; height: 20px; margin: 0; }
.mit-schwebeknopf .inhalt { padding-bottom: calc(9.5rem + env(safe-area-inset-bottom)); }
/* Die Kurzmeldung sitzt oben genau dort, wo hier der Knopf schwebt – also
   eine Etage höher. */
.mit-schwebeknopf .meldung { bottom: calc(8.75rem + env(safe-area-inset-bottom)); }
@media (min-width: 768px) {
  .schwebeknopf { bottom: 1.5rem; right: 1.5rem; }
  .mit-schwebeknopf .inhalt { padding-bottom: 6rem; }
  .mit-schwebeknopf .meldung { bottom: 5.5rem; }
}

/* --- Eingabedialoge (eingabeDialog() in kern.js) ------------------------- */
.dialog-kopf { display: grid; gap: 0.25rem; padding: 0.875rem 3.25rem 0 0.875rem; }
.dialog-kopf h2 { font-size: 1.125rem; line-height: 1.3; }
/* Der Kopf ist kein eigenes „Feld" – kein Strich zwischen ihm und der Maske. */
.popover-inhalt > .dialog-kopf + .dialog-maske { border-top: 0; }
/* Die Knopfreihe steckt IN der Maske: ihre eigene Polsterung käme zur
   Maskenpolsterung dazu (doppelter Rand unten). */
.dialog-maske .knopfreihe { padding: 0.125rem 0 0; }
.dialog-maske textarea { min-height: 4.5rem; }
.dialog-maske input::placeholder, .dialog-maske textarea::placeholder { color: var(--text-leise); opacity: 0.7; }
/* Fehler direkt am Feld, nicht irgendwo oben. */
.feldfehler { font-size: 0.8125rem; color: var(--fehler); font-weight: 700; }
.feldfehler[hidden] { display: none; }
.dialog-maske [aria-invalid="true"] { border-color: var(--fehler); }
/* Nebenknöpfe (z. B. „Löschen") links, Abbrechen/Speichern rechts. */
.knopfreihe-links { display: flex; gap: 0.5rem; flex: 1 1 100%; }
@media (min-width: 768px) {
  .knopfreihe-links { flex: 1 1 auto; margin-right: auto; }
  .knopfreihe.aktionen .knopfreihe-links .knopf { min-width: 0; }
}

/* --- Eintragskarte: ganze Zeile anklickbar, Pfeil rechts als Hinweis, dass
   es weitergeht (ein Lernziel auf /aufgaben). Raster: Name / Meta / Balken /
   Stand, Pfeil daneben. --- */
.eintrag-karte {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "name pfeil" "wo pfeil" "leiste pfeil" "stand pfeil";
  align-items: center;
  gap: 0.25rem 0.75rem;
  width: 100%;
  padding: 0.75rem;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background 150ms linear;
}
.eintrag-karte:hover { background: var(--flaeche-hoch); }
.eintrag-karte .name { grid-area: name; font-weight: 700; overflow-wrap: anywhere; hyphens: auto; }
.eintrag-karte .wo { grid-area: wo; }
.eintrag-karte .leiste { grid-area: leiste; margin-top: 0.125rem; }
.eintrag-karte .stand { grid-area: stand; }
.eintrag-karte .weiter { grid-area: pfeil; color: var(--text-leise); width: 20px; height: 20px; }

/* --- Fächer-Balken: fünf Leitner-Fächer als ein Balken, Breite = Karten im
   Fach. Je weiter rechts, desto sicherer gewusst – die Deckkraft der
   Erfolgsfarbe steigt mit dem Fach; es gibt keine zweite Farbe. --- */
.faecher { display: flex; gap: 2px; height: 6px; border-radius: 2px; overflow: hidden; background: var(--linie); }
.faecher i { display: block; flex: 0 0 auto; min-width: 4px; background: var(--gut); }
.faecher .fach-1 { opacity: 0.25; }
.faecher .fach-2 { opacity: 0.4; }
.faecher .fach-3 { opacity: 0.55; }
.faecher .fach-4 { opacity: 0.75; }
.faecher .fach-5 { opacity: 1; }

/* --- Kartenliste: Kacheln mit dem Bild der Vorderseite. Zwei Spalten am
   Handy, so viele wie Platz ist am Rechner (mindestens 8.5 rem breit). --- */
.kachel-liste {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: 0.75rem;
  padding: 0.75rem;
}
.kachel-liste.leer-liste { display: block; padding: 0; }
.kachel-karte {
  display: grid;
  gap: 0.375rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: 4px;
}
.kachel-karte .kachel-bild {
  display: block;
  aspect-ratio: 8 / 5;
  border: 1px solid var(--linie-stark);
  border-radius: 3px;
  overflow: hidden;
  transition: border-color 150ms linear, transform 150ms ease-out;
}
.kachel-karte .kachel-bild img { display: block; width: 100%; height: 100%; object-fit: cover; }
.kachel-karte:hover .kachel-bild { border-color: var(--signal); transform: translateY(-2px); }
.kachel-karte.faellig .kachel-bild { border-color: var(--gut); box-shadow: inset 0 0 0 1px var(--gut); }
.kachel-karte .kachel-text { display: grid; gap: 0.125rem; min-width: 0; }
.kachel-karte .name { font-weight: 700; font-size: 0.875rem; overflow-wrap: anywhere; hyphens: auto; }
.kachel-karte .wo { font-size: 0.75rem; color: var(--text-leise); }
.kachel-karte.faellig .wo { color: var(--gut); font-weight: 700; }

/* Suchfeld mit Lupe – ein Feld wie in .maske, aber ohne Beschriftung
   darüber (die Lupe sagt schon alles; aria-label für Bildschirmleser). */
.suchfeld { position: relative; padding: 0.75rem; }
.suchfeld svg { position: absolute; left: 1.5rem; top: 50%; width: 18px; height: 18px; transform: translateY(-50%); color: var(--text-leise); pointer-events: none; }
.suchfeld input {
  font: inherit;
  width: 100%;
  min-height: 44px;
  padding: 0.5rem 0.7rem 0.5rem 2.5rem;
  background: var(--grund);
  color: var(--text);
  border: 1px solid var(--linie-stark);
  border-radius: 4px;
}

/* --- Die Karte zum Umdrehen ------------------------------------------------
   Vorder- und Rückseite liegen im 3-D-Raum übereinander; die Hülle dreht
   sich um die senkrechte Achse (preserve-3d), die abgewandte Seite ist
   unsichtbar (backface-visibility). Die Kurve bremst am Ende – wie ein
   Blatt, das man umlegt. --- */
.kartenbuehne { display: grid; justify-items: center; padding: 0.75rem; }
.flipkarte { width: 100%; max-width: 32rem; perspective: 1400px; position: relative; }
.flipkarte-knopf {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: 6px;
}
.flipkarte-innen {
  position: relative;
  aspect-ratio: 8 / 5;
  transform-style: preserve-3d;
  transition: transform 550ms cubic-bezier(0.2, 0.75, 0.25, 1);
}
.flipkarte[data-seite="hinten"] .flipkarte-innen { transform: rotateY(180deg); }
.flipkarte .seite {
  position: absolute;
  inset: 0;
  display: grid;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border: 1px solid var(--linie-stark);
  border-radius: 6px;
  overflow: hidden;
  background: #f7f4ec;
}
.flipkarte .seite img { display: block; width: 100%; height: 100%; object-fit: contain; background: #f7f4ec; }
.flipkarte .seite .leer { align-self: center; padding: 0 1rem; text-align: center; color: #6b6255; }
.flipkarte .hinten { transform: rotateY(180deg); }
/* Seitenmarke in der Ecke der Karte – auf dem hellen Papier dunkel. */
.flipkarte .seiten-marke {
  position: absolute;
  right: 0.5rem;
  bottom: 0.5rem;
  padding: 0.2rem 0.45rem;
  border-radius: 3px;
  background: rgb(22 32 46 / 0.75);
  color: #f2f6fb;
  font: 700 0.625rem/1 var(--schrift);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Hereinkommen und Rausfliegen der Karte in der Abfrage: rechts raus bei
   „Gewusst", links bei „Nicht gewusst" – die Richtung trägt die Bedeutung
   mit. Unter prefers-reduced-motion nimmt die App weiter oben alle
   Animationen weg; der Code wartet dann nicht auf animationend, sondern auf
   einen kurzen Timeout. */
.flipkarte.rein { animation: karte-rein 260ms ease-out both; }
.flipkarte.raus-gut { animation: karte-raus-gut 380ms cubic-bezier(0.4, 0, 1, 1) both; }
.flipkarte.raus-nein { animation: karte-raus-nein 380ms cubic-bezier(0.4, 0, 1, 1) both; }
@keyframes karte-rein {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
  to { opacity: 1; transform: none; }
}
@keyframes karte-raus-gut {
  to { opacity: 0; transform: translateX(70%) rotate(8deg); }
}
@keyframes karte-raus-nein {
  to { opacity: 0; transform: translateX(-70%) rotate(-8deg); }
}

/* Stapel-Effekt: bis zu zwei Kanten „darunter" deuten den Rest des Stapels
   an. Eigene Elemente hinter der Karte (nicht Pseudo-Elemente der Karte),
   damit sie liegen bleiben, wenn die oberste rausfliegt. */
.buehne-innen { position: relative; width: 100%; max-width: 32rem; }
.buehne-innen .flipkarte { position: relative; z-index: 1; }
.kartenbuehne.mit-stapel { padding-bottom: 1.5rem; }
.stapel-hinter {
  position: absolute;
  inset: 0;
  display: block;
  border-radius: 6px;
  border: 1px solid var(--linie-stark);
  background: #e9e4d8;
}
.stapel-hinter.hinter-1 { transform: translateY(7px) scale(0.97); }
.stapel-hinter.hinter-2 { transform: translateY(14px) scale(0.94); background: #dcd6c8; }

/* --- Abfrage: Umdrehen-Knopf, danach die Bewertung an derselben Stelle. --- */
/* „8 übrig" bleibt auf einer Zeile; das Stichwort darf umbrechen. */
.abfrage .abfragezeile > span:first-child { white-space: nowrap; }
.abfrage .abfragezeile .rest { font-family: var(--schrift); text-align: right; line-height: 1.3; }
.abfrage .hinweis-mitte { text-align: center; margin-top: 0.5rem; font-size: 0.75rem; color: var(--text-leise); }
.abfrage .bewertung { display: grid; gap: 0.5rem; padding: 0.75rem; }
.abfrage .bewertung h3 {
  font: 700 0.6875rem/1 var(--schrift);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-leise);
}
.abfrage .bewertung .wo { font-size: 0.75rem; color: var(--text-leise); }
.abfrage .bewertung .folge-gut { color: var(--gut); }
.abfrage .bewertung .folge-nein { color: var(--fehler); }
/* Die Bewertung erscheint, wenn die Karte umgedreht ist – leicht von unten. */
.abfrage .bewertung:not([hidden]) { animation: karte-rein 200ms ease-out both; }

/* Abfrage als Dialog: breiter als die Eingabedialoge, damit die Karte Platz
   hat; die Blöcke darin ohne eigenen Rahmen. */
.popover.abfrage-dialog { width: min(100% - 2rem, 38rem); }
.popover.abfrage-dialog .abfrage .block { border: 0; border-radius: 0; }
.popover.abfrage-dialog .dialog-kopf { padding-bottom: 0.5rem; border-bottom: 1px solid var(--linie); }

/* Ein Dialog, der aus seiner Kachel „wächst" (Karte ansehen). */
.popover.wachsend[open] { animation: dialog-wachsen 200ms ease-out both; }
@keyframes dialog-wachsen {
  from { opacity: 0; transform: scale(0.94); }
  to { opacity: 1; transform: none; }
}
@media (max-width: 767px) {
  /* Am Handy kommt das Blatt von unten; „wachsen" wäre dort falsch. */
  .popover.wachsend[open] { animation: blatt-hoch 220ms ease-out both; }
  @keyframes blatt-hoch { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
}

/* --- Aufnehmen im Dialog --- */
/* .feld ist oben nur innerhalb von .block gepolstert – im Dialog fehlte das. */
.popover .feld { padding: 0.75rem; }
.aufnahme { display: grid; }
.aufnahme > * + * { border-top: 1px solid var(--linie); }
.aufnahme .kartenbild img { display: block; max-width: 22rem; width: 100%; border-radius: 4px; }
.aufnahme .aufnahme-knoepfe { display: grid; gap: 0.5rem; }
.popover .dialog-kopf .chip { vertical-align: middle; }

/* --- Zuschnitt vor der Kompression (zuschnitt.js) ---
   Die Bühne bekommt ihr Seitenverhältnis und die Breitengrenze per CSSOM
   aus dem Foto; Foto, SVG-Griffe und Lupe liegen deckungsgleich darin.
   touch-action: none, sonst scrollt das Blatt statt die Ecke zu ziehen. */
.popover.zuschnitt { width: min(100% - 2rem, 40rem); }
.zuschnitt-schritt { padding: 0.75rem; display: grid; }
.zuschnitt-buehne {
  position: relative;
  width: 100%;
  margin: 0 auto;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  border-radius: 4px;
  overflow: visible;
}
.zuschnitt-buehne > canvas:first-child { display: block; width: 100%; height: 100%; border-radius: 4px; }
.zuschnitt-buehne > svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.zuschnitt-flaeche { fill: color-mix(in srgb, var(--signal) 18%, transparent); stroke: var(--signal); stroke-width: 2; vector-effect: non-scaling-stroke; }
.zuschnitt-griff { fill: var(--flaeche-hoch); stroke: var(--signal); stroke-width: 3; vector-effect: non-scaling-stroke; }
.zuschnitt-griff.aktiv { fill: var(--signal); }
.zuschnitt-fang { fill: transparent; cursor: grab; }
.zuschnitt-lupe {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  width: 120px;
  height: 120px;
  display: none;
  border: 2px solid var(--flaeche-hoch);
  border-radius: 50%;
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.5);
  color: var(--signal); /* Fadenkreuz – zuschnitt.js liest die Farbe aus */
  pointer-events: none;
  z-index: 2;
}
.zuschnitt-lupe.rechts { left: auto; right: 0.5rem; }
.zuschnitt-lupe.sichtbar { display: block; }
.zuschnitt-vorschau { padding: 0; }
.zuschnitt-vorschau canvas { display: block; width: 100%; max-width: 32rem; height: auto; border: 1px solid var(--linie-stark); border-radius: 3px; }

/* --- Stapelzeile mit den Taten direkt daneben, ohne Bildschirmwechsel; und
   der Leitner-Kasten als fünf Fächer, die als Filter der Kartenliste
   dienen. --- */
.stapel-zeile { display: grid; gap: 0.5rem; padding: 0.75rem; }
.stapel-zeile .stapel-name {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.stapel-zeile .stapel-name .name { font-weight: 700; overflow-wrap: anywhere; hyphens: auto; }
.stapel-zeile .stapel-name .wo { display: block; font-size: 0.8125rem; color: var(--text-leise); }
.stapel-zeile .stapel-name svg { flex: none; width: 20px; height: 20px; color: var(--text-leise); }
.stapel-zeile .taten { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.stapel-zeile .taten .knopf { min-height: 40px; padding: 0 0.75rem; font-size: 0.8125rem; }
.stapel-zeile .taten .knopf.nur-symbol { width: 40px; padding: 0; }
.stapel-zeile .taten .knopf.nur-symbol svg { margin: 0; }
.stapel-zeile .taten .chip { margin-left: auto; }

.leitner-kasten { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0.375rem; padding: 0.75rem; }
.leitner-kasten button {
  display: grid;
  gap: 0.125rem;
  justify-items: center;
  min-height: 56px;
  padding: 0.5rem 0.25rem;
  border: 1px solid var(--linie-stark);
  border-radius: 4px;
  background: transparent;
  color: var(--text);
  font: inherit;
  cursor: pointer;
  transition: background 150ms linear, border-color 150ms linear;
}
.leitner-kasten button:hover { background: var(--flaeche-hoch); }
.leitner-kasten button[aria-pressed="true"] { border-color: var(--signal); background: var(--signal-grund); }
.leitner-kasten .zahl { font: 700 1.25rem/1 var(--zahlen); }
.leitner-kasten .fachname { font: 700 0.625rem/1.2 var(--schrift); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-leise); }
.leitner-kasten .wann { font-size: 0.6875rem; color: var(--text-leise); }
.leitner-kasten button[aria-pressed="true"] .fachname { color: var(--signal); }

/* Startseiten-artiger Block „Heute" auf /lernen: die Zahl gross, wie .zahlfeld. */
.heute-zahl .zahlfeld { padding-bottom: 0.25rem; }
