/*
  Handy zuerst. Systemschriften, keine Webschriften: nichts wird nachgeladen,
  nichts springt beim Laden. Nur die dunkle Fassung: reines Schwarz, Flächen
  nur über Tonwerte, keine Akzentfarbe (die Hauptaktion ist die helle Pille),
  Farbe kommt allein aus Bildern und Videos. Tippziele mindestens 44 mal 44
  Pixel, ohne Ausnahme.

  Aufbau dieser Datei: Tokens, Grund, Grundbausteine (Kopf, Leiste, Segment,
  Pille, Block, Liste, Blatt, Cover, Skelett), Anmeldung, danach die
  Bausteine der Ansichten aus der Zeit vor dem Umbau, die ihre Farben und
  Formen ausschließlich über die Tokens beziehen. Die Ansichten selbst
  liegen in sicht-*.css und workspace.css.
*/

:root {
  /* Flächen */
  --grund: #000000;
  --flaeche: #1c1c1e;
  --flaeche-2: #2c2c2e;
  --linie: rgba(255, 255, 255, 0.12);
  --hell: #f5f5f7;

  /* Schrift */
  --schrift: #ffffff;
  --grau: #8e8e93;
  --schrift-leise: #98989d;

  /* Auf hellen Blöcken */
  --tinte: #000000;
  --tinte-grau: #6e6e73;
  --tinte-linie: rgba(0, 0, 0, 0.1);

  /* Ecken: groß für Karten und Blätter, mittel für einzelne Kacheln, klein
     für Raster und Bilder. Knöpfe und Segmente sind Pillen. */
  --r-gross: 20px;
  --r-mittel: 12px;
  --r-klein: 8px;

  /* Namen aus der Zeit vor dem Umbau. Alle bestehenden Regeln beziehen
     Farben und Formen über sie und laufen damit ohne Änderung weiter; nur
     die Werte sind neu. Zustände (gut, Warnung, schlecht) haben keine Farbe:
     sie stehen über Wort, Symbol und hellen Block. */
  --grund-karte: var(--flaeche);
  --grund-tief: var(--flaeche-2);
  --betont: #f5f5f7;
  --betont-schrift: #000000;
  --betont-verlauf: #f5f5f7;
  --betont-schein: transparent;
  --gut: #ffffff;
  --warnung: #ffffff;
  --schlecht: #ffffff;
  --duo-blau: var(--flaeche);
  --duo-gruen: var(--flaeche);
  --duo-rosa: var(--flaeche-2);
  --duo-orange: var(--flaeche-2);
  --duo-schrift: #ffffff;
  --duo-schrift-leise: #98989d;
  --duo-flaeche: rgba(255, 255, 255, 0.12);
  --radius-karte: var(--r-gross);
  --radius-klein: var(--r-mittel);
  --radius-leiste: 999px;
  --radius-blatt: var(--r-gross);
  --radius-pille: 999px;
  --schatten-karte: none;
  --schatten-segment: none;
  --schatten-leiste: none;
  --karten-kante: 1px solid var(--linie);

  /* Segment: Spur und aktive Pille. Im hellen Blatt umgedreht. */
  --seg-spur: var(--flaeche);
  --seg-an: var(--hell);
  --seg-an-schrift: #000000;
  --segment-aktiv: var(--hell);

  /* Rhythmus, alles im 4-Pixel-Raster */
  --tippziel: 44px;
  --rand: 16px;
  --kartenabstand: 12px;
  --leiste-hoehe: 60px;
  --fab-groesse: 56px;
  --sicher-unten: env(safe-area-inset-bottom, 0px);
  --sicher-oben: env(safe-area-inset-top, 0px);
  /* Der Streifen am unteren Rand, den die schwebende Leiste einnimmt: Abstand
     zur Unterkante, die Leiste selbst und 16 Pixel Luft darüber. #haupt
     rechnet damit sein Polster aus. */
  --leiste-raum: calc(var(--sicher-unten) + 12px + var(--leiste-hoehe) + 16px);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  /* Das Dokument selbst scrollt nie, siehe die Begruendung an .rahmen weiter
     unten: nur so hat Safaris eigene Werkzeugleiste nichts, woran sie sich
     beim Ein- und Ausblenden festmachen koennte. */
  height: 100%;
  /* Absicherung fuer den Standalone-Modus (Stufe 7, Task 1): die dynamische
     Einheit haelt das Dokument auf der tatsaechlich sichtbaren Bildschirm-
     hoehe, falls height: 100% allein im installierten PWA-Modus nicht die
     volle Hoehe trifft. Ein Browser ohne dvh ueberspringt die Zeile
     einfach und bleibt beim Fallback darueber (height: 100%). */
  min-height: 100dvh;
  overflow: hidden;
  background: var(--grund);
  color: var(--schrift);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.45;
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 { margin: 0; font-weight: 700; }

/* Das Symbolblatt in index.html nimmt keinen Platz ein. */
.symbolblatt { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Anmeldung, Einrichtung, Sitzungsende (siehe anmeldung.js).
   Schwarz mit heller Pille, kein Akzent. Der Bildschirm setzt die Tokens
   lokal, damit alles darin (Felder, Codeliste, Meldungen) ohne eigene Farben
   mitzieht. Er liegt über den Blättern (z-index 100), damit ein Sitzungsende
   auch dann sichtbar wird, wenn gerade ein Blatt offen ist. */

.tor {
  --grund: #000000;
  --grund-karte: #000000;
  --grund-tief: #1c1c1e;
  --linie: #38383a;
  --schrift: #ffffff;
  --schrift-leise: #98989d;
  --schlecht: #ffffff;
  --gut: #ffffff;
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--grund);
  color: var(--schrift);
  display: flex;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: max(var(--rand), env(safe-area-inset-top, 0px)) var(--rand) max(var(--rand), var(--sicher-unten));
}

.tor[hidden] { display: none; }

/* Auto-Raender zentrieren den Inhalt, solange er kurz ist, und lassen ihn
   bei langem Inhalt (QR-Code, Codeliste) sauber nach oben anschlagen. */
.tor-inhalt { width: 100%; max-width: 400px; margin: auto; padding: 24px 0; }
.tor :focus-visible { outline-color: var(--schrift); }

.tor-kopf { margin-bottom: 28px; }
.tor-kopf h1 { font-size: 32px; line-height: 1.15; letter-spacing: -0.02em; margin: 0 0 8px; }
.tor-unter { color: var(--schrift-leise); margin: 0 0 12px; font-size: 17px; }
.tor-kopf .tor-unter { margin: 0; }
.tor-klein { color: var(--schrift-leise); margin: 8px 4px 0; font-size: 14px; }

.tor-formular { display: flex; flex-direction: column; gap: 14px; }

/* Felder als eine Gruppe mit feiner Linie dazwischen, ohne eigene Kaesten. */
.tor-gruppe {
  border: 1px solid var(--linie);
  border-radius: var(--radius-klein);
  overflow: hidden;
  background: var(--grund);
}
.tor-gruppe > * + * { border-top: 1px solid var(--linie); }
.tor-gruppe input {
  display: block;
  width: 100%;
  min-height: 54px;
  padding: 0 16px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--schrift);
  font-size: 17px;
}
.tor-gruppe input::placeholder { color: var(--schrift-leise); }
/* Der Fokus zeigt sich am runden Rand der Gruppe, ein Rahmen am Feld wuerde eckig ueber die Rundung ragen. */
.tor-gruppe input:focus-visible { outline: none; }
.tor-gruppe:focus-within { border-color: var(--schrift); }

.tor-zeile { position: relative; display: flex; align-items: center; }
.tor-zeile input { padding-right: 104px; }
.tor-zeigen {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  min-height: var(--tippziel);
  min-width: var(--tippziel);
  padding: 0 12px;
  border: 0;
  background: transparent;
  color: var(--schrift-leise);
  font: inherit;
  font-size: 15px;
  cursor: pointer;
}

.tor-hinweis { margin: 0; font-size: 15px; color: var(--schrift-leise); }
.tor-hinweis.fehler, .tor-hinweis:not([hidden]) { color: var(--schlecht); }

.tor-knopf {
  width: 100%;
  min-height: 52px;
  border: 0;
  border-radius: var(--radius-pille);
  background: var(--schrift);
  color: var(--grund);
  font: inherit;
  font-size: 17px;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
}
.tor-knopf:disabled { opacity: 0.4; cursor: default; }
.tor-knopf:active:not(:disabled) { opacity: 0.8; }

.tor-link {
  display: inline-block;
  min-height: var(--tippziel);
  padding: 0 8px;
  border: 0;
  background: transparent;
  color: var(--schrift-leise);
  font: inherit;
  font-size: 15px;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  align-self: center;
  line-height: var(--tippziel);
}
.tor-link-gross { font-size: 17px; color: var(--schrift); }

/* QR-Code und Schluessel (auch in den Konto-Einstellungen benutzt). Das Bild
   bleibt immer auf weissem Grund, sonst liest keine Kamera es im Dunkelmodus. */
.konto-qr-block { display: flex; flex-direction: column; align-items: center; margin: 0 0 20px; text-align: center; }
.konto-qr { display: block; width: 220px; max-width: 70vw; height: auto; border-radius: 8px; background: #ffffff; margin: 0 0 4px; }
.konto-schluessel {
  margin: 0;
  font: 600 16px ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.06em;
  word-break: break-all;
  user-select: all;
}

.konto-codes-block { display: flex; flex-direction: column; margin: 0 0 20px; }
.konto-codes {
  list-style: none;
  margin: 0 0 8px;
  padding: 0;
  border: 1px solid var(--linie);
  border-radius: var(--radius-klein);
  overflow: hidden;
}
.konto-codes li {
  padding: 13px 16px;
  font: 600 18px ui-monospace, SFMono-Regular, Menlo, monospace;
  user-select: all;
}
.konto-codes li + li { border-top: 1px solid var(--linie); }

/* Konto-Einstellungen (Unterseite von Heute) */
.konto-formular { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }
.konto-feld { display: flex; flex-direction: column; gap: 6px; }

input, textarea {
  font: inherit;
  color: var(--schrift);
  background: var(--grund-karte);
  border: 1px solid var(--linie);
  border-radius: var(--radius-klein);
  padding: 12px 14px;
  min-height: var(--tippziel);
  width: 100%;
}

/* Sichtbarer Fokus ueberall, mit Abstand zum Element, damit der Ring auch
   auf einer randlosen Kapsel oder einem farbigen Grund erkennbar bleibt. */
:focus-visible {
  outline: 2px solid var(--betont);
  outline-offset: 2px;
}

textarea { min-height: 160px; resize: vertical; }

/* Die beiden Knoepfe am Ende des Blatts stehen untereinander und ueber die
   volle Breite: ein button ist von Haus aus inline-block und stuende sonst
   nebeneinander, was den Abbrechen-Knopf so gross wie den Hochladen-Knopf
   erscheinen liesse. */
/* #notiz-blatt-inhalt steht mit in der Liste, weil app.js den Inhalt des
   Notiz-Blatts (Ziel "Eigene Idee" im Halbkreis) in diesen Behaelter baut
   und die Knoepfe darin genauso ueber die volle Breite gehoeren. */
.blatt-inhalt > .knopf,
#notiz-blatt-inhalt > .knopf { display: block; width: 100%; margin-top: 10px; }

/* ... und verschwinden wieder, wenn das Blatt sie versteckt. Ohne diese eine
   Zeile bleiben sie sichtbar: das display: block darueber ist eine
   Autorenregel und schlaegt das display: none, das der Browser dem
   hidden-Merkmal von Haus aus gibt. Gefunden im Pruefstand von Stufe 6, Task
   9: nach einem fertigen Upload standen "Hochladen" und "Abbrechen" weiter
   unter dem Ergebnis, obwohl app.js sie laengst auf hidden gesetzt hatte
   (ein Altbefund aus Task 4, dieselbe Falle wie bei .marke und
   .konzept-kachel-koerper an anderer Stelle in dieser Datei). */
.blatt-inhalt > .knopf[hidden],
#notiz-blatt-inhalt > .knopf[hidden] { display: none; }

/* Die Liste der gewaehlten Dateien im Upload-Blatt (Stufe 6, Task 9,
   Mehrfachauswahl): eine Zeile je Datei, getrennt durch dieselbe feine Linie
   wie sonst in der App, ohne eigene Karte darum. Eine Karte je Datei waere
   bei sechs Dateien ein Stapel aus sechs Karten in einem Blatt, das selbst
   schon eine Karte ist. */
.upload-liste { margin: 0 0 4px; }

.upload-zeile { padding: 12px 0; border-top: 1px solid var(--linie); }
.upload-zeile:first-child { border-top: 0; padding-top: 0; }

/* Dateiname links, Groesse rechts. Der Name darf kuerzen, die Groesse nie:
   sie ist kurz und traegt die Entscheidung mit, was hier gerade hochgeht. */
.upload-kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.upload-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.upload-groesse {
  flex: 0 0 auto;
  color: var(--schrift-leise);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

/* Der Stand einer Zeile: wartet, Balken, Platzhalter, Ergebnis oder Fehler.
   Der erste Absatz darin steht dicht unter dem Namen, damit Name und Stand
   als eine Einheit lesbar bleiben. */
.upload-stand { margin-top: 6px; }
.upload-stand > p:last-child { margin-bottom: 0; }
.upload-stand .fortschritt { margin-top: 6px; }
.upload-stand .meldung { margin-top: 0; }

/* Der Entwurf/Direkt-einplanen-Schalter im Upload-Blatt (Punkt 4 des
   Auftrags): zwei benannte, gleichrangige Optionen, keine An/Aus-Frage,
   deshalb zwei Knoepfe mit aria-pressed statt eines Kippschalters wie beim
   KI-Flag (siehe hochladenModusSetzen in app.js). */
/* Dieselbe segmentierte Pille wie die Reiter im Bereich Skripte (Auftrag
   Punkt 8): eine Kapsel als Spur, die gewaehlte Seite als hellere Kapsel
   darin. .knopfreihe-eng traegt dafuer die Spur, siehe dort. */
.segment-knopf {
  background: transparent;
  border-color: transparent;
  color: var(--schrift-leise);
  min-height: 40px;
  padding: 9px 12px;
}

.segment-knopf[aria-pressed="true"] {
  background: var(--segment-aktiv);
  color: var(--seg-an-schrift);
  border-color: transparent;
  font-weight: 700;
  box-shadow: var(--schatten-segment);
}

/* Die Spur um die beiden Segment-Knoepfe. Eigene Klasse im Markup statt
   einer :has()-Regel: die App soll auch auf einem aelteren Safari richtig
   aussehen, und eine Klasse sagt ausserdem an der Stelle, an der sie steht,
   was gemeint ist. */
.segment-spur {
  gap: 4px;
  padding: 4px;
  background: var(--grund-tief);
  border-radius: var(--radius-pille);
  margin-top: 12px;
}

.segment-spur .knopf { flex: 1 1 0; }

/* Knoepfe */

/* Alle Knoepfe sind Kapseln (Auftrag Punkt 7): sekundaer neutral auf der
   erhoehten Flaeche, primaer im Akzentverlauf. 44 Pixel Mindesthoehe
   ausnahmslos. */
.knopf {
  font: inherit;
  font-weight: 600;
  color: var(--schrift);
  background: var(--grund-tief);
  border: 1px solid transparent;
  border-radius: var(--radius-pille);
  min-height: var(--tippziel);
  min-width: var(--tippziel);
  padding: 11px 18px;
  cursor: pointer;
  touch-action: manipulation;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.knopf:active { transform: scale(0.98); }
.knopf:disabled { opacity: 0.5; cursor: default; transform: none; }
.knopf-klein { padding: 8px 14px; font-size: 15px; }

.knopf-gross {
  background: var(--betont-verlauf);
  color: var(--betont-schrift);
  border-color: transparent;
  font-size: 17px;
  min-height: 52px;
}

/* Der entscheidende Knopf: sichtbar das Groesste auf seiner Karte. */
.knopf-freigeben {
  background: var(--betont-verlauf);
  color: var(--betont-schrift);
  border-color: transparent;
  font-size: 19px;
  font-weight: 700;
  min-height: 56px;
  width: 100%;
}

.knopf-abbrechen { background: transparent; color: var(--schrift-leise); }

/* Gerüst */

/* #rahmen deckt genau den sichtbaren Bereich ab (position: fixed, inset: 0).
   Kopf und Unterkopf sind darin normale Flex-Kinder, nur #haupt dazwischen
   scrollt für sich, und die Leiste schwebt darüber. Das Dokument selbst
   scrollt nie (html, body: overflow hidden), damit Safaris Werkzeugleiste
   nichts hat, woran sie sich beim Ein- und Ausblenden festmachen könnte. */
.rahmen[hidden] { display: none; }

.rahmen {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
}

/* Kopf auf jedem Reiter: Workspace links, Glocke rechts. */
.kopf {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: max(6px, var(--sicher-oben)) var(--rand) 8px;
  background: var(--grund);
}

.ws {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  min-height: var(--tippziel);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--schrift);
  font: inherit;
  font-size: 17px;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
}

.ws-buchstabe {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--hell);
  color: #000000;
  display: grid;
  place-items: center;
  font-size: 14px;
  font-weight: 700;
}

.ws-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-pfeil { flex: 0 0 auto; color: var(--schrift-leise); }

/* Runder Knopf auf dunkler Fläche (Glocke, Zurück). */
.rund {
  position: relative;
  flex: 0 0 auto;
  width: var(--tippziel);
  height: var(--tippziel);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--flaeche);
  color: var(--schrift);
  display: grid;
  place-items: center;
  cursor: pointer;
  touch-action: manipulation;
}

.rund svg { display: block; }

/* Zählstand an der Glocke: eine Zahl, kein Punkt. */
.glocke-zahl {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--hell);
  color: #000000;
  font-size: 12px;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.glocke-zahl[hidden] { display: none; }

/* Kopf einer Unterseite: runder Zurück-Knopf und Titel. */
.unterkopf {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 2px var(--rand) 8px;
  background: var(--grund);
}

.unterkopf[hidden] { display: none; }

.unterkopf-titel {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: 1.1;
}

/* Der einzige Bereich, der scrollt. Die Leiste liegt über ihm, der Inhalt
   scrollt darunter durch; das Polster unten hält jedes letzte Element
   erreichbar. */
#haupt {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  padding: var(--rand) var(--rand) calc(var(--leiste-raum) + var(--rand));
}

.bereich[hidden] { display: none; }

/* Die schwebende Leiste: fünf Reiter in einer Pille und der runde Plus-Knopf.
   position: absolute im Rahmen, nicht fixed zum Bildschirm, aus demselben
   Grund wie oben (Safaris Layout-Viewport ändert sich beim Scrollen). */
.leiste {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: calc(var(--sicher-unten) + 12px);
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 8px;
}

.leiste-tabs {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--leiste-hoehe);
  display: flex;
  align-items: stretch;
  padding: 4px 2px;
  border-radius: 999px;
  background: rgba(44, 44, 46, 0.82);
  -webkit-backdrop-filter: blur(24px);
  backdrop-filter: blur(24px);
  border: 0.5px solid rgba(255, 255, 255, 0.14);
}

.leiste-knopf {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--grau);
  font: inherit;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  touch-action: manipulation;
  transition: background 0.15s ease, color 0.15s ease;
}

.leiste-knopf[aria-current="true"] {
  color: #ffffff;
  background: rgba(255, 255, 255, 0.12);
}

.leiste-symbol { display: block; flex: 0 0 auto; }
.leiste-wort { white-space: nowrap; }

.leiste-plus {
  flex: 0 0 auto;
  width: var(--fab-groesse);
  height: var(--fab-groesse);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--hell);
  color: #000000;
  display: grid;
  place-items: center;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  transition: transform 0.15s ease;
}

.leiste-plus:active { transform: scale(0.94); }
.leiste-plus svg { display: block; }

/* --- Grundbausteine ----------------------------------------------------- */

/* Segment: zwei bis drei Wahlen in einer Pille. Aktiv ist die helle Pille. */
.seg {
  display: flex;
  gap: 0;
  padding: 3px;
  border-radius: 999px;
  background: var(--seg-spur);
  margin: 0 0 var(--kartenabstand);
}

.seg[hidden] { display: none; }

.seg-knopf {
  flex: 1 1 0;
  min-width: 0;
  min-height: 40px;
  padding: 8px 6px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--grau);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  touch-action: manipulation;
}

.seg-knopf[aria-pressed="true"],
.seg-knopf[aria-current="true"] {
  background: var(--seg-an);
  color: var(--seg-an-schrift);
}

/* Pille: große Aktion, 52 Pixel hoch. */
.pille {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font: inherit;
  font-size: 17px;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
}

.pille:disabled { opacity: 0.4; cursor: default; }
.pille-hell { background: var(--hell); color: #000000; }
.pille-dunkel { background: var(--flaeche-2); color: #ffffff; }
.pille-schwarz { background: #000000; color: #ffffff; }
.pille-reihe { display: flex; gap: 10px; }
.pille-reihe > * { flex: 1 1 0; min-width: 0; }

/* Block: heller, voller Block auf dunklem Grund für das Aktive. */
.block {
  background: var(--hell);
  color: #000000;
  border-radius: var(--r-gross);
  padding: 16px;
}

.block-dunkel {
  background: var(--flaeche);
  color: var(--schrift);
  border-radius: var(--r-gross);
}

/* Liste: Zeilen mit feiner Trennlinie, im hellen Block, im dunklen Block
   oder im Blatt. Die Farben kommen aus den Tokens des Umfelds. */
.liste {
  background: var(--grund-karte);
  border-radius: var(--r-gross);
  overflow: hidden;
}

.liste-zeile {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  padding: 10px 16px;
  border: 0;
  border-top: 0.5px solid var(--linie);
  background: transparent;
  color: var(--schrift);
  font: inherit;
  font-size: 17px;
  text-align: left;
  cursor: pointer;
  touch-action: manipulation;
}

.liste-zeile:first-child { border-top: 0; }
.liste-zeile > svg { flex: 0 0 auto; }
.liste-zeile-text { flex: 1 1 auto; min-width: 0; }
.liste-zeile-text strong { display: block; font-weight: 600; }
.liste-zeile-text span { display: block; font-size: 14px; color: var(--schrift-leise); }
.liste-zeile em { font-style: normal; margin-left: auto; color: var(--schrift-leise); font-size: 15px; }

/* Cover: Titelbild als Fläche. Fehlt das Bild, steht der Hook groß als Text
   auf --flaeche (siehe coverBauen in app.js). Der Verlauf liegt nur über dem
   Bild, damit Schrift darauf lesbar bleibt. */
.cover {
  position: relative;
  overflow: hidden;
  background: var(--flaeche) center 20% / cover no-repeat;
  border-radius: var(--r-klein);
}

.cover-schrift {
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 12px;
  z-index: 1;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.02em;
}

.cover-hook {
  display: flex;
  align-items: flex-end;
  padding: 14px;
  background: var(--flaeche);
  font-size: 22px;
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.02em;
}

.cover-bild::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(transparent 52%, rgba(0, 0, 0, 0.9) 90%);
}

/* Blatt (Wunsch aus der Karte): Schleier, helles Blatt von unten, Griff. */
.blatt {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.blatt[hidden] { display: none; }

.blatt-hintergrund {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
}

.blatt-inhalt {
  /* Das Blatt ist hell: seine Tokens drehen sich um, damit jeder Baustein
     darin ohne eigene Farben mitzieht. */
  --grund: #f5f5f7;
  --grund-karte: #ffffff;
  --grund-tief: #e5e5ea;
  --flaeche: #ffffff;
  --flaeche-2: #e5e5ea;
  --linie: rgba(0, 0, 0, 0.1);
  --schrift: #000000;
  --schrift-leise: #6e6e73;
  --grau: #6e6e73;
  --betont: #000000;
  --betont-schrift: #ffffff;
  --betont-verlauf: #000000;
  --gut: #000000;
  --warnung: #000000;
  --schlecht: #000000;
  --duo-schrift: #000000;
  --duo-schrift-leise: #6e6e73;
  --seg-spur: #e5e5ea;
  --seg-an: #000000;
  --seg-an-schrift: #ffffff;
  --segment-aktiv: #000000;
  position: relative;
  width: 100%;
  max-width: 480px;
  max-height: 85dvh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--grund);
  color: var(--schrift);
  border-radius: var(--r-gross) var(--r-gross) 0 0;
  padding: 10px var(--rand) max(var(--rand), var(--sicher-unten));
  animation: blatt-herein 0.18s ease-out;
}

@keyframes blatt-herein {
  from { transform: translateY(12%); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

.blatt-griff {
  width: 38px;
  height: 5px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.18);
  margin: 0 auto 14px;
}

.blatt-inhalt h2 { font-size: 22px; letter-spacing: -0.015em; margin: 0 0 12px; }

/* Workspace-Blatt: unscharfer Grund, Zeilen als Blöcke (schirm-7). */
.blatt-ws { align-items: center; }

.blatt-ws .blatt-hintergrund {
  background: rgba(0, 0, 0, 0.5);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
}

.blatt-ws .blatt-inhalt {
  --grund: transparent;
  --grund-karte: #1c1c1e;
  --grund-tief: #2c2c2e;
  --flaeche: #1c1c1e;
  --flaeche-2: #2c2c2e;
  --linie: rgba(255, 255, 255, 0.12);
  --schrift: #ffffff;
  --schrift-leise: #98989d;
  --grau: #8e8e93;
  --betont: #f5f5f7;
  --betont-schrift: #000000;
  --betont-verlauf: #f5f5f7;
  --gut: #ffffff;
  --warnung: #ffffff;
  --schlecht: #ffffff;
  background: transparent;
  border-radius: 0;
  max-height: 100dvh;
  padding: max(var(--rand), var(--sicher-oben)) var(--rand) max(var(--rand), var(--sicher-unten));
  animation: none;
}

/* Der Weg zu einem neuen Karussell (siehe karussellZeileBauen in app.js).
   Bis zur Nachbesserung eine eigene Karte mit sechs Zeilen Erklaertext ueber
   dem Knopf; jetzt eine Zeile: der Knopf links, der Preis leise daneben.
   Umbruch erlaubt, damit der Preis auf sehr schmalen Geraeten unter den
   Knopf rutscht statt ihn zu quetschen. */
.karussell-zeile {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: var(--kartenabstand);
}

.karussell-preis { color: var(--schrift-leise); font-size: 13px; }

/* Die Reiterleiste im Bereich Skripte (Stufe 6, Task 3, Auftrag Punkt 1):
   "als schmale Leiste unter der Ueberschrift", also im scrollenden Inhalt
   von #haupt, nicht wie .leiste oben fest am unteren Bildschirmrand (Jans
   Befund 1 aus Task 1 gilt hier genauso: eine zweite fest positionierte
   Leiste haette dasselbe Springen wieder eingefuehrt). Dasselbe Bedienmuster
   wie .leiste-knopf (aria-current fuer den aktiven Reiter), aber flacher und
   mit einer Unterstreichung statt einem Schatten oben, damit sie sich von
   der unteren Navigation unterscheidet. */
/* Segmentierte Pille (Auftrag Punkt 7): EIN Kapselhintergrund, in dem der
   aktive Reiter als eigene, hellere Kapsel liegt. Ersetzt die frueheren
   Unterstreichungen: dieselbe Formensprache wie die untere Leiste, die
   ebenfalls ohne Striche auskommt.

   Weiterhin im scrollenden Inhalt von #haupt, nicht fest am Bildschirm
   (Jans Befund 1 aus Task 1 gilt unveraendert, siehe .rahmen oben). */
.reiterleiste {
  display: flex;
  gap: 3px;
  margin-bottom: 16px;
  padding: 4px;
  background: var(--grund-tief);
  border-radius: var(--radius-pille);
}

.reiter-knopf {
  flex: 1 1 0;
  min-width: 0;
  /* Volle 44 Pixel, nicht 36: gemessen wurde vorher der KNOPF, und die vier
     Pixel Polster der Spur liegen ausserhalb von ihm, zaehlen also nicht zur
     Tippflaeche. Die Spur ist damit 52 Pixel hoch. */
  min-height: var(--tippziel);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border: 0;
  border-radius: var(--radius-pille);
  background: transparent;
  color: var(--schrift-leise);
  font: inherit;
  /* Stufe 7, Task 3: 13px statt 14px, Innenpolster 3px statt 6px seitlich
     (siehe padding unten): vier Reiter statt drei brauchen bei 375 Pixeln
     Breite jeden freien Pixel, sonst frisst die Ellipse aus .reiter-wort
     laengere Woerter wie "Eingeplant" bis zur Unlesbarkeit ("Einge...", im
     Pruefstand-Screenshot 120-freigabe-dark-375.png vor dieser Aenderung
     gesehen). */
  font-size: 12px;
  font-weight: 600;
  padding: 8px 2px;
  cursor: pointer;
  touch-action: manipulation;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.reiter-knopf[aria-current="true"] {
  background: var(--segment-aktiv);
  color: var(--seg-an-schrift);
  font-weight: 700;
  box-shadow: var(--schatten-segment);
}

.reiter-wort {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Der Zaehler klein rechts vom Wort (Auftrag Punkt 7), immer leise: er
   ordnet ein, er ist nicht die Auskunft. */
.reiter-zahl {
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--schrift-leise);
  flex: 0 0 auto;
}

/* Karten und Listen */

.karte {
  background: var(--grund-karte);
  border: var(--karten-kante);
  border-radius: var(--radius-karte);
  padding: 18px;
  margin-bottom: var(--kartenabstand);
  box-shadow: var(--schatten-karte);
}

.karte-kopf {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

/* Das Formatwort als schlichte graue Textzeile, ohne Kapsel und ohne Versalien
   (Regel Jan: keine Etiketten-Kapseln). */
.marke {
  display: inline-block;
  color: var(--schrift-leise);
  font-size: 13px;
  font-weight: 600;
}

/* Ohne diese Zeile bliebe die KI-Marke sichtbar: das display der Klasse
   schlaegt das display: none, das der Browser einem hidden-Element gibt.
   Dieselbe Zeile gibt es aus demselben Grund fuer .tor, .rahmen, .bereich
   und .sprechtext. */
.marke[hidden] { display: none; }

.leise { color: var(--schrift-leise); font-size: 14px; }

/* Beschriftung ueber einem bearbeitbaren Feld (etwa "Text im Video"), damit
   klar ist, was dort steht, ohne dass jemand "Hook" oder "Caption" lesen
   muss. Klein und leise wie .fussnote, aber davor statt danach. */
.feld-label { color: var(--schrift-leise); font-size: 13px; font-weight: 700; margin: 0 0 4px; }

/* Ein antippbares Anzeigefeld, das sich beim Tipp in ein Eingabefeld
   verwandelt (Hook, Caption, Sprechtext). Bis zur Nachbesserung stand unter
   jedem der drei die graue Zeile "Zum Bearbeiten antippen." - dreimal
   derselbe Satz in einer einzigen aufgeklappten Kachel. Jetzt sagt es ein
   kleines Stift-Icon in der oberen rechten Ecke, leise und ohne Worte; die
   Vorlesefunktion hoert den Hinweis weiterhin ueber das aria-label des
   Feldes selbst (siehe hookTeil in app.js). */
.bearbeitbar { position: relative; }

.bearbeitbar-stift {
  position: absolute;
  width: 16px;
  height: 16px;
  color: var(--schrift-leise);
  opacity: 0.75;
  /* Der Tipp gilt dem Feld darunter, nicht dem Icon. */
  pointer-events: none;
}

/* Der Hook ist jetzt antippbar, siehe hookTeil in app.js. */
.hook { font-size: 19px; font-weight: 700; margin: 0 0 8px; cursor: pointer; }

/* Der Hook hat kein eigenes Polster: das Icon steht am rechten Rand auf
   Hoehe der ersten Zeile, der Text weicht ihm ueber padding-right aus. */
.hook.bearbeitbar { padding-right: 26px; }
.hook .bearbeitbar-stift { top: 5px; right: 0; }

/* Caption und Sprechtext sind gepolsterte Kaesten: das Icon sitzt innen in
   der Ecke, mit demselben Abstand zum Rand wie der Text. */
.caption .bearbeitbar-stift,
.sprechtext .bearbeitbar-stift { top: 13px; right: 13px; }
.caption.bearbeitbar,
.sprechtext.bearbeitbar { padding-right: 40px; }

/* Das Eingabefeld, das an die Stelle von .hook tritt, sobald sie angetippt
   wird: gleiche Schriftgroesse und gleiches Gewicht, damit der Wechsel nicht
   wie ein Sprung wirkt (siehe .sprechtext-feld weiter unten fuer denselben
   Gedanken beim Sprechtext). */
.hook-feld { font-size: 19px; font-weight: 700; margin: 0 0 8px; }

/* Die Caption: derselbe Kasten wie .sprechtext (Rahmen, Hintergrund,
   Innenabstand), aber in normaler Schriftgroesse statt der auf Armlaenge
   vergroesserten Sprechtext-Schrift: sie wird beim Pruefen vor der Freigabe
   gelesen, nicht beim Filmen aus der Distanz. */
.caption {
  margin-top: 6px;
  padding: 14px;
  background: var(--grund);
  border: 1px solid var(--linie);
  border-radius: var(--radius-klein);
  white-space: pre-wrap;
  overflow-wrap: break-word;
  cursor: pointer;
}

.caption-feld { margin-top: 6px; min-height: 140px; }

/* Das Kommentar-Keyword: bewusst auffaelliger als Hook und Caption (breiterer
   Rahmen in der Akzentfarbe, groessere, weit gesetzte Schrift), damit Jan es
   vor dem Filmen auf einen Blick findet und laut vorlesen kann, statt es im
   Fliesstext der Caption zu suchen. Nicht antippbar zum Bearbeiten wie .hook
   und .caption, sondern zum Kopieren, siehe keywordTeil in app.js. */
.keyword {
  margin-top: 6px;
  padding: 14px;
  background: var(--grund);
  border: 2px solid var(--betont);
  border-radius: var(--radius-klein);
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.04em;
  cursor: pointer;
  min-height: var(--tippziel);
  display: flex;
  align-items: center;
  /* Wort links, Kopieren-Icon rechts (Befund K8 der Pruefung zu Stufe 7,
     Task 2): das Icon ersetzt den Satz, der vorher darueber erklaerte, dass
     Antippen kopiert. */
  justify-content: space-between;
  gap: 12px;
}
/* Ein Keyword ist ein Wort ohne Leerzeichen: ohne diese Zeile schiebt ein
   langes Keyword das Icon bei 375 Pixeln aus der Kachel heraus. */
.keyword-wort { overflow-wrap: anywhere; }
.keyword-icon { flex: 0 0 auto; color: var(--schrift-leise); }

/* Das Feld "Antwort per DM" (Migration 25, Stufe 7, Task 5, antwortArt
   'text'): etwas kompakter als .caption-feld (140px), ein DM-Text braucht
   selten die volle Hoehe einer Caption. Sonst dieselbe Basis wie jedes
   textarea (Rahmen, Innenabstand, Breite), siehe die Regel ganz oben. */
.antwort-feld { margin-top: 6px; min-height: 110px; }

.zeile { margin: 0 0 6px; }
.abstand { margin-top: 12px; }

.knopfreihe {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
}

.knopfreihe .knopf { flex: 1 1 140px; }

/* Zwei Knoepfe nebeneinander mit laengerer Beschriftung ("Roh hochladen" und
   "Fertig hochladen", "Ja, anschalten" und "Abbrechen"): bei schmalen Handys
   (390px) reicht die Breite sonst nur fuer den kuerzeren Text auf einer Zeile,
   der laengere bricht um, und das Paar wirkt schief. Etwas weniger
   Innenabstand statt kuerzerer Beschriftung. Hiess bis Stufe 3
   .knopfreihe-video, weil es zuerst nur das Upload-Paar betraf. */
/* Dieselbe Falle wie bei .blatt-inhalt > .knopf oben: display: flex ist eine
   Autorenregel und schlaegt das hidden-Merkmal. Betrifft den
   Entwurf/Einplanen-Schalter im Upload-Blatt, den die Bibliothek gar nicht
   kennt und den das fertige Ergebnis ausblendet. */
.knopfreihe[hidden] { display: none; }

.knopfreihe-eng { gap: 8px; }
.knopfreihe-eng .knopf { padding-left: 10px; padding-right: 10px; }

/* Der Sprechtext: gross genug, um ihn beim Aufnehmen aus Armlaenge zu lesen,
   und antippbar, siehe sprechtextTeil in app.js: ein Tipp verwandelt genau
   diesen Kasten in ein Textfeld, an derselben Stelle. */
.sprechtext {
  margin-top: 12px;
  padding: 14px;
  background: var(--grund);
  border: 1px solid var(--linie);
  border-radius: var(--radius-klein);
  font-size: 25px;
  line-height: 1.65;
  letter-spacing: 0.01em;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  hyphens: none;
  cursor: pointer;
}

.sprechtext[hidden] { display: none; }

/* Der Text einer gespeicherten Notiz: Jans eigene Worte, so wie er sie
   getippt oder diktiert hat, mit seinen Zeilenumbruechen. Nicht so gross wie
   .sprechtext, den er beim Filmen ablesen muss, sondern normale Lesegroesse:
   eine Notiz wird gelesen, nicht vorgelesen. */
.notiz-text {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}

/* Die Herkunftszeile einer Notiz aus dem Themen-Radar oder einer Claude-Sitzung
   (herkunft ungleich 'jan', siehe notizHerkunftZeileBauen in app.js). Der Link
   zur Quelle hebt sich farblich ab, sonst sieht er wie normaler leiser Text aus
   und niemand tippt ihn an. */
.notiz-herkunft { margin-top: 6px; }

/* Senkrechtes Polster an einem Link MITTEN in einer Zeile vergroessert seine
   Tippflaeche (von 17 auf 33 Pixel Hoehe), ohne die Zeile hoeher zu machen:
   bei display: inline waechst der Trefferbereich, der Zeilenumbruch nicht.
   Die vollen 44 Pixel sind hier nicht erreichbar, ohne die Notiz-Karte
   auseinanderzuziehen; ein Link im Fliesstext ist von der Regel zur
   Mindestgroesse ausdruecklich ausgenommen (WCAG 2.5.8, "inline"). */
/* white-space: nowrap, damit der Link am Zeilenende nicht in zwei Stuecke
   zerfaellt ("Quelle" hier, "ansehen" dort): zwei getrennte blaue Fetzen
   sehen aus wie zwei Links, und keiner von beiden ist gut zu treffen. */
.notiz-herkunft a { color: var(--betont); padding: 8px 0; white-space: nowrap; }

/* Notiz-Eingabe (Stufe 6, Task 6): das Textfeld und der Mikrofon-Knopf
   nebeneinander, der Knopf quadratisch neben dem hohen textarea, oben
   ausgerichtet statt mittig, damit er nicht optisch "schwebt". */
.notiz-feld-reihe {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.notiz-feld-reihe textarea { flex: 1 1 auto; }

/* Traegt seit der Nachbesserung ein Linien-Icon statt des Farb-Emojis
   (siehe SYMBOLE in app.js): ein buntes Mikrofon war das einzige Farbbild in
   einer Oberflaeche aus Linien-Icons. */
.knopf-mikro {
  position: relative;
  flex: 0 0 auto;
  width: var(--tippziel);
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.knopf-mikro svg { display: block; }

/* Waehrend die Spracherkennung laeuft (aria-pressed="true"), dieselbe
   Betont-Faerbung wie ein gedrueckter Segment-Knopf. */
.knopf-mikro[aria-pressed="true"] {
  background: var(--betont);
  color: var(--betont-schrift);
  border-color: transparent;
}

/* Dazu ein Ring, der langsam nach aussen laeuft: "es hoert gerade zu" ist
   ein Zustand, der weitergeht, ohne dass jemand etwas tut, und den zeigt
   Bewegung ehrlicher als eine Farbe allein. Die Farbe bleibt trotzdem die
   eigentliche Auskunft, der Ring ist Zugabe: bei prefers-reduced-motion
   steht er still (siehe ganz unten). */
.knopf-mikro[aria-pressed="true"]::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid var(--betont);
  animation: mikro-ring 1.6s ease-out infinite;
  pointer-events: none;
}

@keyframes mikro-ring {
  from { transform: scale(1); opacity: 0.6; }
  to { transform: scale(1.35); opacity: 0; }
}

/* Anhang-Kacheln (Stufe 6, Task 6): sowohl die lokale Auswahl vor dem
   Speichern (mit Entfernen-Kreuz, siehe notizAnhangAuswahlBauen in app.js)
   als auch die Vorschau auf einer bereits gespeicherten Notiz-Karte (ohne
   Kreuz, siehe notizAnhangVorschauBauen) benutzen dieselbe Kachelgroesse,
   damit beide Ansichten gleich aussehen. */
.notiz-anhang-vorschau {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

.notiz-anhang-kachel {
  position: relative;
  width: 76px;
  height: 76px;
  border-radius: var(--radius-klein);
  overflow: hidden;
  background: var(--grund-tief);
  border: 1px solid var(--linie);
}

.notiz-anhang-kachel img,
.notiz-anhang-kachel video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Das Entfernen-Kreuz oben rechts auf einer Auswahl-Kachel, vor dem
   Hochladen. Eigene, kleinere Tippziel-Ausnahme (24px statt --tippziel):
   die Kachel selbst ist mit 76px schon klein, ein 44px-Kreuz wuerde sie
   fast vollstaendig verdecken. */
.notiz-anhang-entfernen {
  position: absolute;
  top: 3px;
  right: 3px;
  width: 24px;
  height: 24px;
  min-width: 0;
  min-height: 0;
  line-height: 22px;
  padding: 0;
  border-radius: 999px;
  border: none;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 16px;
  cursor: pointer;
  touch-action: manipulation;
}

/* Die Vorschau auf einer bereits gespeicherten Notiz-Karte, ohne Kreuz:
   ein img direkt, keine .notiz-anhang-kachel-Huelle noetig. */
.notiz-anhang-bild {
  display: block;
  width: 76px;
  height: 76px;
  border-radius: var(--radius-klein);
  object-fit: cover;
  background: var(--grund-tief);
  border: 1px solid var(--linie);
}

/* Das Textfeld, das an die Stelle von .sprechtext tritt, sobald sie
   angetippt wird: gleiche Schriftgroesse und gleicher Zeilenabstand, damit
   der Wechsel nicht wie ein Sprung wirkt. */
.sprechtext-feld {
  margin-top: 12px;
  font-size: 25px;
  line-height: 1.65;
  letter-spacing: 0.01em;
  min-height: 220px;
}

/* Alle Seiten eines Karussells/Bildpostes auf der Skriptseite (Stufe 7, Task
   4, siehe karussellSeitenReiheBauen in app.js), waagerecht zum Wischen:
   mehrere kleine Karten nebeneinander, damit ein Blick auf den ganzen Aufbau
   des Karussells geht, ohne durchwischen zu muessen. Kein scroll-snap: bei
   vielen kleinen Karten waere ein Einrasten eher hinderlich als hilfreich. */
.karussell-seiten-reihe {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

/* 22 px Eckrundung (var(--radius-karte), Auftrag woertlich) und 3:4 statt des
   echten Renderformats 4:5 (BREITE/HOEHE in src/karussell/rendern.ts):
   etwas schmaler, damit auf 375 Pixel Breite mehr als zwei Karten
   gleichzeitig sichtbar sind. */
.karussell-seiten-karte {
  flex: 0 0 auto;
  width: 132px;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-karte);
  border: 1px solid var(--linie);
  background: var(--grund-tief);
  object-fit: cover;
}

/* Befund 1 der Endpruefung Stufe 5: die eingebettete Videovorschau auf der
   Konzept-Karte (siehe videoVorschau in web/app.js). Breite 100 Prozent und
   das Hochformat der Reels (1080 zu 1920, siehe BREITE/HOEHE in
   src/reel/textebene.ts) als aspect-ratio, damit die Karte auf dem Handy
   nicht gesprengt wird und schon vor dem Laden Platz freihaelt. */
.karte-video {
  display: block;
  width: 100%;
  aspect-ratio: 1080 / 1920;
  margin-top: 10px;
  border-radius: var(--radius-klein);
  border: 1px solid var(--linie);
  background: var(--grund);
  object-fit: contain;
}

/* Zustaende */

.hinweis {
  padding: 16px 18px;
  border-radius: var(--radius-karte);
  background: var(--grund-karte);
  border: var(--karten-kante);
  box-shadow: var(--schatten-karte);
  color: var(--schrift-leise);
}

.hinweis-fehler { color: var(--schlecht); }
.hinweis-gut { color: var(--gut); }

/* Kleiner Umschalter (Stufe 6, Task 10): "PDF nur gegen E-Mail" auf der
   aufgeklappten Skript-Kachel, siehe schalterBauen/keywordTeil in
   web/app.js. Erster echter Schalter dieser Oberflaeche (bisher gab es nur
   Knoepfe, die ihre eigene Beschriftung wechseln, etwa der KI-Knopf): ein
   role="switch"-Button statt einer Checkbox, damit Aussehen und
   Vorlesefunktion unabhaengig von einem systemeigenen Checkbox-Stil bleiben.
   Nur bestehende Tokens (--betont, --grund-tief, --grund-karte,
   --radius-pille), keine neue Farbe oder Rundung. */
.schalter-zeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: var(--tippziel);
  padding: 4px 0;
}

.schalter {
  flex: 0 0 auto;
  position: relative;
  width: 56px;
  height: var(--tippziel);
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  touch-action: manipulation;
}

/* Die Spur des Schalters: 28 Pixel hoch in der 44 Pixel hohen Tippfläche. */
.schalter::before {
  content: "";
  position: absolute;
  left: 4px;
  right: 4px;
  top: 8px;
  height: 28px;
  border-radius: var(--radius-pille);
  background: var(--grund-tief);
  transition: background-color 150ms ease;
}

/* Der Knopf des Schalters: ein eigenes Element, weil ::before schon die Spur
   trägt und ::after für den Fokusring in Frage käme. */
.schalter-knopf {
  position: absolute;
  top: 11px;
  left: 7px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--grau);
  transition: transform 150ms ease, background-color 150ms ease;
}

.schalter[aria-checked="true"]::before { background: var(--betont); }
.schalter[aria-checked="true"] .schalter-knopf { transform: translateX(20px); background: #000000; }
.schalter:disabled { opacity: 0.6; }

/* Die drei Posten-Kaestchen auf der Skriptseite (Stufe 7, Task 2: "KI-
   Kennzeichnung", "Heute posten", "An einem Tag posten"), 44px Zeilen mit
   Haekchen-Icon statt eines Schalters: anders als .schalter (ein Zustand,
   sofort umgekehrt) ist hier oft eine Begruendung noetig (ausgegraut, mit
   dem Grund), und "An einem Tag posten" traegt zusaetzlich Datum und
   Uhrzeit. Eine ganze Zeile ist deshalb der Knopf, nicht nur ein kleiner
   Schalter am Rand. Dieselbe Zeilenhoehe und denselben Aufbau (Text links,
   Zustand rechts) wie .schalter-zeile, nur mit einem Kaestchen statt eines
   Schiebers. */
.kaestchen-zeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: var(--tippziel);
  padding: 4px 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--linie);
  font: inherit;
  color: inherit;
  text-align: left;
}
.kaestchen-zeile:last-child { border-bottom: 0; }
/* [disabled] als Attributselektor, nicht :disabled: eine gesperrte Zeile
   ohne Handlung (siehe kaestchenZeileBauen in app.js) ist ein <div>, kein
   <button>, und :disabled kennt nur echte Formularelemente. Das Attribut
   greift an beiden Elementarten gleich.

   Nur die NICHT angekreuzten Zeilen werden blass (Befund B2 der Pruefung):
   eine angekreuzte Zeile ohne Handlung ist nichts Gesperrtes, sondern ein
   erledigter Zustand ("Heute posten" steht an), und der soll voll deckend
   dastehen, mit dem Haken in der Akzentfarbe. Blass bleibt damit genau das,
   was Jan gerade wirklich nicht tun kann, samt Grund daneben (etwa "Video
   fehlt"). */
.kaestchen-zeile[disabled][aria-checked="false"] { opacity: 0.55; }

.kaestchen-text { display: flex; flex-direction: column; gap: 2px; }
.kaestchen-beschriftung { font-weight: 600; }
.kaestchen-grund { font-size: 13px; color: var(--schrift-leise); }

/* Das Kaestchen selbst: ein Kreis (--radius-pille passt auf jede
   Kantenlaenge), leer bei "nicht angekreuzt", gefuellt mit dem Haken bei
   "angekreuzt". Farbe statt eines zweiten Icons fuer den leeren Zustand:
   der Haken bleibt im DOM, nur unsichtbar (color: transparent), sodass sich
   an der Groesse des Kaestchens nichts verschiebt. */
.kaestchen {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-pille);
  border: 1px solid var(--linie);
  display: flex;
  align-items: center;
  justify-content: center;
  color: transparent;
}
.kaestchen-zeile[aria-checked="true"] .kaestchen {
  background: var(--betont);
  border-color: var(--betont);
  color: var(--betont-schrift);
}
/* overflow-wrap, weil in einer Fehlermeldung die Antwort des Servers steckt
   und darin ein Stueck ohne Leerzeichen stehen kann (eine Anfrage-Kennung,
   eine Adresse). Ohne diese Zeile laeuft so ein Stueck bei 375 Pixeln aus der
   Karte heraus, und der Rest des Satzes ist nicht mehr zu lesen. */
.meldung { margin: 10px 0 0; font-weight: 600; overflow-wrap: anywhere; }
.meldung-fehler { color: var(--schlecht); }
.meldung-gut { color: var(--gut); }

/* Derselbe Abstand wie zwischen zwei Karten, oben UND unten: eine Reihe
   Kacheln ist im Fluss nichts anderes als eine Karte. Bis zur Nachbesserung
   stand hier nur ein margin-top von 8 Pixeln, und die Reihe "Ausgaben"
   beruehrte die Karte "Bibliothek" darunter ohne jeden Abstand. */
.kacheln { display: flex; gap: var(--kartenabstand); margin: var(--kartenabstand) 0; }

/* Eine Zaehlerkachel ist kompakter als eine gewoehnliche Karte (Auftrag
   Punkt 6): weniger Polster, damit vier davon in zwei Reihen nicht den
   halben Bildschirm einnehmen. */
.kachel { flex: 1 1 0; padding: 14px; margin-bottom: 0; }

.kachel-zahl {
  font-size: 32px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin: 2px 0;
}

/* Die oberste Reihe auf Heute: vier Kacheln, zwei mal zwei. Nebeneinander
   waeren sie bei 375px keine 80 Pixel breit, und eine zweistellige Zahl mit
   Beschriftung passt dort nicht hinein. Grid statt flex-wrap, damit beide
   Zeilen gleich hoch sind, auch wenn eine Unterzeile umbricht. */
.kacheln-vier {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* Ohne diese Zeile ist jede Zeile so hoch wie ihre eigene hoechste Kachel:
     gemessen 110 und 130 Pixel, weil die Unterzeilen der unteren beiden
     Kacheln umbrechen. Zwei verschieden hohe Zeilen in einem 2x2 sehen aus
     wie ein Fehler. 1fr gibt beiden Zeilen denselben Anteil, also dieselbe
     Hoehe; die Unterzeilen sind zusaetzlich gekuerzt, damit diese gemeinsame
     Hoehe nicht unnoetig waechst (siehe standKachelnBauen in app.js). */
  grid-auto-rows: 1fr;
  gap: var(--kartenabstand);
}

/* Neuer Befund 5 der Nachpruefung (Fixwelle 2): die Kachel "Eingeplant"
   bekommt seit Befund K10 eine zweite Unterzeile ("auf N Kanaelen", siehe
   standKachelnBauen in app.js), aber nur, wenn eingeplantKanaele von
   eingeplant abweicht. grid-auto-rows: 1fr gleicht zwar beide Zeilen
   aneinander an, nicht aber denselben Zustand VOR und NACH dem Laden: beim
   ersten Aufruf zeigt der Platzhalter (.skelett-kachel) die alte, kuerzere
   Hoehe, dann kommen die echten Zahlen und die zweite Unterzeile laesst
   alle vier Kacheln nachtraeglich wachsen, das Raster springt. Eine feste
   Mindesthoehe, die den Fall MIT zweiter Unterzeile schon aufnimmt, haelt
   beide Zustaende gleich hoch. Im Pruefstand gemessen (Playwright, 375 mal
   812, dark, GET /api/uebersicht mit einem Konzept auf zwei Kanaelen
   gegen dasselbe Konzept auf einem Kanal): 150,4 Pixel mit der zweiten
   Unterzeile, 130,1 Pixel ohne (dieselbe Zahl wie die alte
   .skelett-kachel-Messung unten). 151 Pixel aufgerundet, ein ganzer Pixel
   Sicherheit gegen Rundungsabweichungen der Schriftdarstellung. */
.kacheln-vier .kachel {
  min-height: 151px;
}

/* Eine antippbare Kachel. Ein button bringt eigene Voreinstellungen mit
   (mittige Schrift, Systemschriftart, eigener Rahmen), die hier alle
   zurueckgesetzt werden: sichtbar soll sie genau wie eine .karte aussehen,
   sich aber wie ein Knopf verhalten. */
.kachel-knopf {
  font: inherit;
  color: inherit;
  text-align: left;
  width: 100%;
  cursor: pointer;
  touch-action: manipulation;
  /* Kein margin-bottom: 0 mehr (Stufe 6, Task 6b): das brauchen nur die
     Kacheln IM Raster, wo der Abstand vom gap kommt, und das setzt jetzt
     .kachel selbst. Eine allein stehende Karte mit dieser Klasse (Freigabe,
     Bibliothek) behaelt dadurch den normalen Kartenabstand nach unten und
     klebt nicht mehr an der naechsten Karte. */
  /* Ein button zentriert seinen Inhalt senkrecht. In einer Reihe aus zwei
     Kacheln, von denen eine eine umgebrochene Unterzeile hat, stuenden die
     beiden Beschriftungen dann auf verschiedenen Hoehen: die Reihe saehe
     schief aus. Diese drei Zeilen setzen den Inhalt nach oben. */
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
}

/* Eine Kachel mit dem Wert 0 wird gezeigt, aber gedaempft: eine leere
   Uebersicht ist auch eine Auskunft, sie soll den Blick nur nicht auf sich
   ziehen.

   Gedaempft ueber die Farbe der Zahl, nicht mehr ueber opacity: 0.55 auf der
   ganzen Kachel (Stufe 6, Task 6b, Auftrag Punkt 12). Eine halbdurchsichtige
   Schrift mischt sich mit dem Kartengrund, und gerechnet blieb davon im
   Hellmodus nur noch 4.1:1 bei der Zahl und 2.5:1 bei den beiden
   Beschriftungen uebrig, beides unter den geforderten 4.5:1. Die leise
   Schriftfarbe haelt 6.0:1 und daempft trotzdem sichtbar. */
.kachel-null .kachel-zahl { color: var(--schrift-leise); font-weight: 600; }

/* Ueberschrift eines ganzen Abschnitts ("Als Naechstes", "Schon
   rausgegangen"), deutlich groesser als die Tagesueberschriften darunter
   (.tag-kopf): stuenden beide gleich da, waere nicht zu erkennen, wo ein
   Abschnitt aufhoert und der naechste anfaengt. */
/* Beschriftung eines Abschnitts ("Heute noch", "Als Naechstes", "Fotos"):
   klein, Versalien, weit gesetzt (Auftrag Punkt 5). Ein solches Label ordnet,
   ohne selbst laut zu sein; die Karten darunter tragen den Inhalt.

   .abschnitt-kopf und .tag-kopf sind dieselbe Form und unterscheiden sich
   nur in der Farbe: der Abschnitt steht in der vollen Schriftfarbe, die
   Tages- beziehungsweise Kartenbeschriftung darin eine Stufe leiser. Damit
   bleibt im Bereich Plan sichtbar, wo ein Abschnitt ("Als Naechstes")
   aufhoert und ein Tag darin ("Montag, 07.09.") anfaengt, ohne dass zwei
   verschiedene Schriftgroessen noetig waeren. */
.abschnitt-kopf {
  margin: 28px 0 10px;
  font-size: 12px;
  font-weight: 700;
  color: var(--schrift);
}

/* Nur die allererste Beschriftung eines Bereichs steht ohne Abstand nach
   oben. Vorher galt das fuer jede, die als erstes Kind IRGENDEINES
   Behaelters stand: auf der Bibliotheksseite klebte "Rohvideos" deshalb
   direkt unter dem Fotoraster darueber, weil beide Abschnitte je einen
   eigenen Behaelter haben (siehe bibliothekAbschnittBauen in app.js). */
.bereich > .abschnitt-kopf:first-child,
.bereich > *:first-child > .abschnitt-kopf:first-child { margin-top: 0; }

/* Duenn (Auftrag Punkt 6): ein Balken ist hier eine Randnotiz zur Zahl
   darueber, nicht selbst die Auskunft. */
.balken {
  height: 6px;
  border-radius: var(--radius-pille);
  background: var(--grund-tief);
  overflow: hidden;
  margin-top: 12px;
}

.balken-fuell { height: 100%; background: var(--gut); border-radius: var(--radius-pille); }
.balken-fuell.warnung { background: var(--warnung); }
.balken-fuell.schlecht { background: var(--schlecht); }

.fortschritt {
  height: 8px;
  border-radius: var(--radius-pille);
  background: var(--grund-tief);
  overflow: hidden;
  margin-top: 12px;
}

.fortschritt-fuell {
  height: 100%;
  width: 0%;
  background: var(--betont);
  transition: width 0.2s linear;
}

.tag-kopf {
  margin: 20px 0 8px;
  font-size: 12px;
  font-weight: 700;
  color: var(--schrift-leise);
}

.tag-kopf:first-child { margin-top: 0; }

/* Chevron rechts im Kopf der Strategie-Karte auf Heute (Stufe 7, Task 7):
   zeigt an, dass die ganze Karte ein Knopf ist und eine Unterseite oeffnet
   (saeulenBerichtKarteBauen in web/app.js). Dieselbe Pfeilform wie das Symbol
   "weiter" (Kalender-Navigation, SYMBOLE in app.js): ein Chevron nach rechts
   sieht in beiden Faellen gleich aus, eine zweite, identische Pfaddefinition
   nur fuer einen zweiten Namen waere kein Gewinn. margin-left auto schiebt
   es im .karte-kopf ganz nach rechts, ohne dass .karte-kopf selbst (von
   mehreren Karten geteilt) eine eigene justify-content-Regel braucht. */
.strategie-karte-chevron { margin-left: auto; flex: 0 0 auto; color: var(--schrift-leise); }

.eintrag {
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 12px 0;
  border-bottom: 1px solid var(--linie);
}

.eintrag:last-child { border-bottom: 0; }
.eintrag-zeit { font-variant-numeric: tabular-nums; font-weight: 700; min-width: 58px; }
.eintrag-text { flex: 1 1 auto; }

.fussnote { color: var(--schrift-leise); font-size: 14px; margin-top: 8px; }

/* Die Preisliste in der Karte "Taeglich neue Skripte" (siehe
   preisTabelleBauen in app.js): links das Wort, rechts der Betrag, dahinter
   das Kuerzel der Herkunft. Kompakt gesetzt, weil acht Zeilen untereinander
   stehen; die Karte soll auf einem Handy nicht laenger sein als das, was sie
   sagt. */
/* Das Pensum links, die typischen Monatskosten rechts, auf einer Zeile
   (siehe taeglichKarteBauen in app.js). */
.pensum-zeile {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  /* 15 statt der geerbten 17 Pixel: bei 375 Pixeln Breite passen die beiden
     Angaben sonst nicht nebeneinander, und die Zeile bricht in zwei um. */
  font-size: 15px;
}

/* 12 Pixel und kurz gehalten: die Karte ist bei 375 Pixeln Breite innen nur
   307 Pixel breit, und das Pensum links braucht davon 178. Groesser gesetzt
   bricht die Zeile um. */
.pensum-kosten {
  color: var(--schrift-leise);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.preis-tabelle { margin-top: 8px; }

/* Der schlechteste Monat, unter der Preisliste, leiser als sie. */
.preis-hoechstens {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--schrift-leise);
  font-variant-numeric: tabular-nums;
}

/* Eng gesetzt (13 Pixel, Zeilenhoehe 1.35, 2 Pixel Polster): acht Zeilen bei
   der gewoehnlichen Zeilenhoehe von 1.45 machten die Karte 500 Pixel hoch,
   so sind es 415. Eine Preisliste wird ueberflogen, nicht gelesen. */
.preis-zeile {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 1px 0;
  font-size: 13px;
  line-height: 1.35;
}

.preis-was {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Feste Mindestbreite und Tabellenziffern: nur so stehen die Betraege
   untereinander auf einer Kante, und nur dann laesst sich eine Preisliste
   ueberhaupt mit einem Blick vergleichen. */
.preis-wert {
  flex: 0 0 auto;
  min-width: 58px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

/* Leise und in fester Breite, damit die Betraege davor ihre Kante behalten.
   Steht nur da, wenn nicht alle acht Preise aus derselben Art Quelle kommen
   (siehe preisTabelleBauen). */
.preis-quelle {
  flex: 0 0 auto;
  min-width: 62px;
  font-size: 12px;
  color: var(--schrift-leise);
}

/* Der Zeichenzaehler beim Hook, sobald die Grenze ueberschritten ist
   (HOOK_MAX_ZEICHEN in app.js). Ersetzt nur die Farbe von .fussnote. */
.fussnote-fehler { color: var(--schlecht); }

/* Der Kopf von Heute: der Hero-Block "Naechster Post" (Nachtrag des
   Koordinators zu Stufe 7, Task 3, siehe naechsterPostBauen in app.js), der
   die fruehere grosse Uhr samt Datumszeile ersetzt. Die Uhrzeit des
   naechsten Posts als grosse Zahl (tabular-nums, unveraendert aus Stufe 6,
   Task 1: eine feste, vom Server gelieferte Zeit zuckt zwar nicht mehr beim
   Minutenwechsel wie die frueher mitlaufende Handy-Uhr, tabular-nums bleibt
   trotzdem richtig, sobald Jan zu einem anderen Post blaettert), Tag und
   Plattform-Chip leise darunter. */
.heute-kopf { margin-bottom: 20px; }

/* Der ganze Hero-Block ist ein Knopf (Tippen oeffnet die Skriptseite des
   naechsten Posts), soll aber wie reiner, unbetonter Text aussehen: eigene
   Zuruecksetzung, weil .kachel-knopf auf einer Kartenflaeche (.karte) beruht,
   die es hier ausdruecklich nicht gibt (derselbe blosse Kopf wie vorher die
   Uhr, keine Kartenbox). */
.heute-naechster-post {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  padding: 0;
  margin: 0 0 20px;
  font: inherit;
  color: inherit;
  cursor: pointer;
  touch-action: manipulation;
}

.heute-uhrzeit {
  margin: 0;
  font-size: 56px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.035em;
  line-height: 1.02;
}

.heute-datum {
  margin: 6px 0 0;
  font-size: 15px;
  color: var(--schrift-leise);
  line-height: 1.3;
}

/* Der leise Titel unter der Tageszeile: derselbe .leise-Text, nur mit etwas
   Abstand nach oben, damit er nicht an der Marke klebt. */
.heute-naechster-post > .leise { margin: 6px 0 0; }

/* Die Karte auf Heute, direkt unter dem Hero-Block "Naechster Post", die
   den Bereich Skripte mit dem Reiter Freigabe oeffnet (Stufe 7, Task 3;
   urspruenglich Auftrag Punkt 1 aus Stufe 6, Task 6b, damals noch zu einer
   eigenen Freigaben-Unterseite). Wartet etwas, traegt sie den Akzentverlauf
   und ist das Lauteste auf dem Bildschirm; wartet nichts, bleibt sie eine
   gewoehnliche, leise Karte. */
.freigabe-karte { padding: 16px 18px; }

.freigabe-karte-offen {
  background: var(--betont-verlauf);
  border-color: transparent;
  color: var(--betont-schrift);
}

.freigabe-zeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.freigabe-text { min-width: 0; }

.freigabe-zahl {
  font-size: 40px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

/* Volles Weiss, keine Deckung: auf dem Akzentverlauf kam die Zeile mit 85
   Prozent nur auf 3.8:1 (gemessen), und der Verlauf ist so hell, dass jede
   sichtbare Daempfung unter 4.5:1 faellt. Leiser wirkt die Zeile ohnehin
   schon durch Groesse und Gewicht: 15 Pixel normal gegen 40 Pixel fett
   darueber. */
.freigabe-wort { font-size: 15px; font-weight: 400; margin-top: 2px; }

.freigabe-wort-gross { font-size: 17px; font-weight: 600; }

.freigabe-symbol { flex: 0 0 auto; }
.freigabe-karte:not(.freigabe-karte-offen) .freigabe-symbol { color: var(--schrift-leise); }

/* Die beiden Hero-Kacheln "Heute noch" und "Heute schon raus" (Auftrag
   Punkt 6): gedaempfte Duotone-Verlaeufe, weisse Schrift. Die Verlaeufe
   selbst stehen als Tokens ganz oben, ihr hellstes Ende ist so dunkel
   gewaehlt, dass Weiss darauf 4.5:1 haelt. */
.duo-karte {
  border-color: transparent;
  color: var(--duo-schrift);
  box-shadow: none;
}

.duo-blau { background: var(--duo-blau); }
.duo-gruen { background: var(--duo-gruen); }
.duo-rosa { background: var(--duo-rosa); }
.duo-orange { background: var(--duo-orange); }

/* Alles, was auf einer Duotone-Kachel leise sein soll, wird ueber die
   Deckung leise, nicht ueber eine eigene Graustufe: eine graue Schrift
   verliert auf einem farbigen Grund sofort ihren Kontrast. */
.duo-karte .leise,
.duo-karte .fussnote,
.duo-karte .hinweis { color: var(--duo-schrift-leise); }

.duo-karte .abschnitt-kopf,
.duo-karte .tag-kopf { color: var(--duo-schrift-leise); }

.duo-karte .hinweis {
  background: var(--duo-flaeche);
  border-color: transparent;
  padding: 12px 14px;
}

.duo-karte .eintrag { border-bottom-color: rgba(255, 255, 255, 0.18); }

/* Kopf einer Duotone-Kachel: Beschriftung links, die Zahl gross rechts. */
.duo-kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.duo-kopf-wort { margin: 0; }

.duo-zahl {
  font-size: 34px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  line-height: 1;
}

/* Der runde Zurueck-Knopf einer Unterseite (Bibliothek, Leads, Strategie,
   die Skriptseite), dasselbe Muster wie der kleine runde Zurueck-Pfeil in Jans
   Zielbild zwei. Er steht seit der Nachbesserung IM Kopf der App, links vom
   Titel (siehe unterseiteKopfSetzen in app.js), nicht mehr als eigene Zeile
   im Inhalt: dort standen "Heute" (28 Pixel) und darunter "Freigaben"
   (22 Pixel) als zwei Ueberschriften uebereinander. Jetzt traegt der eine
   Kopf den Titel der Unterseite, und der Zurueck-Knopf daneben sagt, dass
   es einen Weg heraus gibt.

   Ein button bringt eigene Voreinstellungen mit (Rahmen, Hintergrund,
   Systemschriftart), die hier zurueckgesetzt werden, dieselbe Ueberlegung
   wie bei .kachel-knopf weiter unten. 40 mal 40 sichtbar, aber ueber das
   ::after bleibt die Tippflaeche bei den geforderten 44 Pixeln, und ueber
   das negative Polster steht der Kreis trotzdem buendig am linken
   Seitenrand. */
.unterseite-zurueck {
  position: relative;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--grund-karte);
  border: var(--karten-kante);
  border-radius: 50%;
  color: var(--schrift);
  padding: 0;
  margin: 0 0 0 -2px;
  box-shadow: var(--schatten-karte);
  cursor: pointer;
  touch-action: manipulation;
}

.unterseite-zurueck::after {
  /* Unsichtbare Vergroesserung der Tippflaeche auf 44 mal 44, ohne den
     sichtbaren Kreis zu vergroessern. */
  content: '';
  position: absolute;
  width: 44px;
  height: 44px;
}

/* Zwei Spalten passen bei 375px Breite bequem, mit genug Platz fuer eine
   erkennbare Vorschau; drei waeren auf einem schmalen Handy zu klein, um die
   Beschreibung beim Antippen sinnvoll darunter zu lesen. */
.bib-raster {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  /* Derselbe Abstand wie zwischen zwei Karten: 10 Pixel fielen aus dem
     Raster, das sonst ueberall 12 betraegt. */
  gap: var(--kartenabstand);
  margin-top: var(--kartenabstand);
}

.bib-kachel {
  background: var(--grund-karte);
  border: var(--karten-kante);
  border-radius: var(--radius-klein);
  overflow: hidden;
  box-shadow: var(--schatten-karte);
}

/* Wie .bib-zurueck oben: ein button zurueckgesetzt, damit nur das Bild
   selbst sichtbar bleibt. */
.bib-kachel-bild-knopf {
  display: block;
  width: 100%;
  padding: 0;
  margin: 0;
  border: none;
  background: none;
  cursor: pointer;
  touch-action: manipulation;
}

/* Quadratisch (1:1), damit ein Hochformat-Foto und ein Breitbild-Standbild
   im selben Raster gleich gross wirken; object-fit: cover schneidet den
   Rest ab, statt das Bild zu verzerren. */
.bib-bild {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--grund);
}

.bib-details { padding: 10px; }
.bib-details[hidden] { display: none; }

/* Derselbe Platzhalter wie .skelett, aber quadratisch statt eines schmalen
   Balkens (siehe skelettBibliothekRaster in app.js). */
.skelett-bib-kachel { height: auto; aspect-ratio: 1 / 1; border-radius: var(--radius-klein); margin: 0; }

/* Der Anzeigetitel einer Konzept-Karte (Stufe 6, Task 1, Punkt 5; siehe
   anzeigeTitel in src/server/app.ts und titelKopfBauen in app.js): fett wie
   .hook, aber nicht antippbar, hier gibt es nichts zu bearbeiten. Vorher
   stand hier gar kein eigener Titel, nur die Saeule oben in der Marke, und
   ein Saeulenname wie "Der Denkfehler" sah dadurch wie der Konzeptname aus. */
.karte-titel { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 3px; line-height: 1.3; }

/* Die beiden Zeilen unter dem Titel einer Skript-Kachel. Bis zur
   Nachbesserung trugen Saeule und Zustandshinweis dieselbe Klasse (.leise,
   14 Pixel, dieselbe Farbe) und standen damit gleichrangig untereinander:
   drei Zeilen ohne erkennbare Ordnung. Jetzt drei Stufen: der Titel gross
   und in voller Schriftfarbe, die Saeule als kleines Chip (voll lesbar, aber
   erkennbar eine Einordnung, kein Satz), der Zustand darunter klein und
   leise. */
.kachel-saeule {
  display: inline-block;
  margin: 0 0 6px;
  padding: 2px 10px;
  border-radius: var(--radius-pille);
  background: var(--grund-tief);
  color: var(--schrift);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.4;
}

/* text-wrap: pretty (ein Zusatz, ohne ihn bleibt alles beim Alten): verhindert,
   dass das letzte Wort allein in einer Zeile steht. Auf der Freigabe-Kachel
   mit Grund ("Vorschau fehlt noch. Baut das System, Keyword nein") stand
   sonst "nein" allein unter "Keyword"; jetzt rutscht "Keyword" mit. Ein
   Browser, der die Eigenschaft nicht kennt, ignoriert sie. */
.kachel-zustand { margin: 0; font-size: 13px; color: var(--schrift-leise); text-wrap: pretty; }

/* Die Terminzeile ("Termin Sa., 17. Okt., 18:20", "Rausgegangen ...",
   "Voraussichtlich ...", siehe kachelTerminText in app.js): ein eigener
   Absatz im selben leisen Stil, direkt unter dem Zustand. Sie steht allein
   in ihrer Zeile und bricht nie mitten im Datum um: bei 375 Pixel passt auch
   die laengste Form ("Voraussichtlich Mi., 30. Sept., 16:00") in eine Zeile,
   und auf einem noch schmaleren Geraet ragt sie hoechstens ins Polster der
   Kachel, statt dass "18:20" allein in der naechsten Zeile steht. */
.kachel-termin { white-space: nowrap; }

/* Stufe 7, Task 2: die Skriptnummer, in der zusammengeklappten Kachel und im
   Kopf der Skriptseite ("Skript 54"), im selben Versalien-Stil wie ein Chip
   (.marke: Versalien, weiter Buchstabenabstand), aber ohne eigene Flaeche,
   denn sie steht direkt neben dem Formatchip, nicht in einem zweiten. */
.kachel-nummer {
  font-size: 13px;
  font-weight: 700;
  color: var(--schrift-leise);
}

/* Zeile 1 einer Skript-Kachel (Nummer, Formatchip) und Zeile 3 (Saeulen-Chip,
   Dauer): dieselbe einfache Reihe zweimal, siehe skriptKachelBauen. */
.kachel-kopfzeile,
.kachel-saeule-zeile { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; }
.kachel-saeule-zeile .kachel-saeule { margin: 0; }

/* Der Kopfblock der Skriptseite (Stufe 7, Task 2): der Anzeigetitel gross
   (22/700, ein eigenes h2, nicht zu verwechseln mit dem Unterseiten-Kopf der
   App, der "Skript 54" traegt, siehe unterseiteKopfSetzen), darunter die
   Chip-Reihe (Format, Saeule, Dauer, dazu Termin oder Zustand): mehrere
   .marke-Chips nebeneinander, umbrechend bei wenig Platz statt abgeschnitten
   zu werden. */
.skriptseite-titel { font-size: 22px; letter-spacing: -0.01em; line-height: 1.3; margin: 0; }

/* .chip-reihe (bis Stufe 7, Task 7 ".skriptseite-chips" geheissen, hier auf
   den allgemeinen Namen umbenannt, weil die Strategie-Karte auf Heute
   (saeulenBerichtKarteBauen in web/app.js) dieselbe Zeile jetzt ebenfalls
   braucht): eine Reihe .marke-Chips, umbrechend bei wenig Platz statt
   abgeschnitten zu werden. Eigener Name (nicht ".kopf-...") um Verwechslung
   mit .kopf, der festen App-Kopfzeile, auszuschliessen. */
.chip-reihe { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 0; }

/* Ein Textblock mit echten Zeilenumbruechen (Stufe 7, Task 2, Abschnitt
   "Worum es geht": die Seitenfolge eines Karussells steht als EIN Absatz mit
   "\n" zwischen den Seiten, siehe worumEsGeht in src/server/app.ts). Ohne
   diese Regel wuerden Zeilenumbrueche im Text ignoriert und alles liefe in
   einer Zeile zusammen. */
.mehrzeilig { white-space: pre-line; overflow-wrap: anywhere; }

/* Die aufklappbare Kachel im Bereich Skripte (Stufe 6, Task 3, Auftrag Punkt
   2): .karte traegt weiterhin Rahmen, Hintergrund und Ecken, aber kein
   eigenes Polster mehr (padding: 0), weil .konzept-kachel-kopf, der Knopf
   darin, dieses Polster selbst mitbringt: sichtbar bleibt EINE Karte, ob
   zusammengeklappt (nur der Kopf) oder aufgeklappt (Kopf plus der volle,
   unveraendert aus karteBauen(k, true) uebernommene Kartenkoerper darunter,
   der sein eigenes Polster ueber .konzept-kachel-koerper traegt, siehe unten). */
.konzept-kachel { padding: 0; }

/* Ein button bringt eigene Voreinstellungen mit (mittige Schrift, eigener
   Rahmen), die hier zurueckgesetzt werden: sichtbar soll er aussehen wie der
   Kopf einer gewoehnlichen Karte, sich aber wie ein Knopf verhalten. Dasselbe
   Muster wie .kachel-knopf oben, hier fuer eine einzelne Konzept-Kachel statt
   einer Uebersichtskachel. */
.konzept-kachel-kopf {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  border-radius: var(--radius-karte);
  padding: 16px 18px;
  cursor: pointer;
  touch-action: manipulation;
}

/* Der letzte Textblock im Kopf (Saeule, oder der Zustandshinweis, wenn er
   da ist) braucht keinen eigenen Abstand nach unten: den setzt schon das
   Polster des Knopfs selbst. Ohne diese Zeile stuenden der Abstand der
   Zeile UND 16px Knopf-Polster untereinander. Auf das letzte Kind gemuenzt
   statt auf .zeile: die beiden Zeilen im Kopf tragen seit der Nachbesserung
   eigene Klassen (.kachel-saeule, .kachel-zustand). */
.konzept-kachel-kopf > :last-child { margin-bottom: 0; }

/* Die Freigabe-Kachel, kompaktes Layout (Befund W1 der Pruefung zu Stufe 7,
   Task 4, siehe freigabeKachelBauen in app.js): Miniatur und Kopfinhalt
   nebeneinander in EINEM Kopf-Knopf (.freigabe-kachel-kopf), darunter ueber
   die volle Breite die Zustandszeile und die Knopfreihe. Ziel laut Auftrag:
   hoechstens 360px Kachelhoehe bei 375px Breite (im Pruefstand gemessen).
   Ersetzt das fruehere Layout mit einem 4:5-Bild ueber die volle Breite, bei
   dem die Knoepfe auf einem iPhone SE erst nach Scrollen sichtbar waren. */
.freigabe-kachel-kopf {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.freigabe-kachel-inhalt {
  flex: 1 1 auto;
  min-width: 0;
}

/* Nachbesserung (Pruefung vor Stufe 7, Task 5): .konzept-kachel-kopf >
   :last-child oben trifft in der Freigabe-Kachel nur noch die Huelle
   .freigabe-kachel-inhalt selbst (das letzte Kind von .freigabe-kachel-kopf
   ist seit W1 die Huelle, nicht mehr die Saeule-Zeile direkt, siehe
   freigabeKachelBauen in app.js: Miniatur und Huelle liegen nebeneinander).
   Das Nullen der Huelle aendert aber nichts an DEREN eigenem letzten Kind
   (.kachel-saeule-zeile, margin-bottom 6px ohne Zustandssatz): genau dieser
   Rest-Abstand blieb sichtbar. Dieselbe Regel jetzt eine Ebene tiefer. */
.freigabe-kachel-inhalt > :last-child { margin-bottom: 0; }

/* Hoechstens drei Zeilen (Befund W1 woertlich), danach Auslassungspunkte:
   die uebliche Technik fuer mehrzeiliges Abschneiden, von jedem Zielbrowser
   dieser App unterstuetzt (Safari/iOS, Chrome/Android). */
.freigabe-kachel-titel {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

/* Miniatur links im Kopf-Knopf: 140px hoch, Breite ueber aspect-ratio
   (Befund W1 woertlich). 4:5 ist die Vorgabe (Karussell/Bildpost, macht bei
   140px Hoehe genau die geforderten 112px Breite, dasselbe Seitenverhaeltnis
   wie eine Karussell-Seite, siehe BREITE/HOEHE in src/karussell/
   rendern.ts); .freigabe-vorschau-hoch dreht das fuer jedes Video (A, B, D)
   auf 9:16, naeher am echten Reel-Format. Gilt fuer ein echtes Bild UND den
   Platzhalter gleichermassen ("dieselbe Miniaturflaeche", Auftrag
   woertlich). Radius 14px (Befund woertlich, var(--radius-klein)). */
.freigabe-vorschau {
  display: block;
  flex: 0 0 auto;
  height: 140px;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-klein);
  object-fit: cover;
  background: var(--grund-tief);
}

.freigabe-vorschau-hoch { aspect-ratio: 9 / 16; }

/* Der einheitliche Platzhalter (freigabePlatzhalterBauen in app.js): seit
   Befund W1 nur noch das Format-Icon, mittig in derselben Miniaturflaeche
   wie ein echtes Bild (Auftrag woertlich); der bisherige Zustandssatz
   ("Vorschau fehlt: ...", "Wartet auf ein Rohvideo ...") steht seither in
   .freigabe-kachel-zustand unter dem ganzen Kopf-Knopf, wo die volle
   Kachelbreite fuer ihn da ist statt der schmalen Miniatur (siehe
   freigabeZustandText in app.js). */
.freigabe-vorschau-platzhalter {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--schrift-leise);
}

/* Das Play-Dreieck ueber einem echten Videostandbild (Befund W1 woertlich:
   "Play-Icon-Overlay"), damit die 9:16-Miniatur eines Videos auf den ersten
   Blick als Video zu erkennen ist, nicht als Foto. Dunkle, halbdurchsichtige
   Kapsel hinter dem Icon, dasselbe Verdunkeln wie beim Entfernen-Kreuz einer
   Notiz-Anhangskachel (.notiz-anhang-entfernen), hier rund statt eckig. */
.freigabe-vorschau-video { position: relative; overflow: hidden; }
.freigabe-vorschau-video .freigabe-vorschau-bild {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.freigabe-vorschau-spielen {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 8px;
  border-radius: var(--radius-pille);
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
}

/* Die Zustandszeile ueber die volle Kachelbreite, unter dem Kopf-Knopf
   (Befund W1 woertlich: "die Zustandszeile mit 'Voraussichtlich ...'"):
   derselbe Text wie zuvor im Kopf-Knopf (kachelZustandssatz), jetzt mit dem
   Grund fuer einen gesperrten Freigeben-Knopf vorangestellt (siehe
   freigabeZustandText in app.js), an einer Stelle mit mehr Platz als die
   schmale Miniatur. Seit der Nachbesserung zum Reiter-Fix eine Huelle um zwei
   Absaetze: den Zustand und darunter die Terminzeile ("Voraussichtlich ...",
   .kachel-termin). Die Huelle traegt Polster und Abstand, die Absaetze
   (.kachel-zustand) liegen ohne Abstand untereinander. */
.freigabe-kachel-zustand { padding: 0 18px; margin: 0 0 12px; }

/* Freigeben/Ablehnen unter dem Kopf-Knopf (freigabeKnopfeBauen in app.js):
   .konzept-kachel hat kein eigenes Polster, dieser Behaelter bringt sein
   eigenes mit, seitlich wie der Kopf-Knopf (18px), unten etwas weniger
   (16px, der Kopf-Knopf traegt oben schon 16px). Bleibt eine feste Klasse,
   waehrend der Inhalt zwischen der Zwei-Knopf-Reihe und einer Rueckfrage
   wechselt. */
.freigabe-aktionen { padding: 0 18px 16px; }

/* Befund W1 woertlich: 44px statt der sonst 56px hohen Haupt-Handlung, damit
   die ganze Kachel bei 375px Breite unter 360px Hoehe bleibt; width: auto
   statt 100%, weil der Knopf sich die Zeile jetzt mit Ablehnen teilt
   (.knopfreihe .knopf traegt schon flex: 1 1 140px). Die grosse,
   freistehende Fassung auf der Skriptseite (freigebenBauen) bleibt
   unberuehrt: sie traegt keine .freigabe-aktionen-Klasse. */
.freigabe-aktionen .knopf-freigeben { min-height: var(--tippziel); width: auto; }

/* Der aufgeklappte Kartenkoerper (karteBauen(k, true), siehe skriptKachelBauen
   in app.js): eigenes Polster, damit Hook/Skript/Caption/Knoepfe nicht bis an
   den Rand der Kachel reichen, aber ohne den oberen Rand des Kopf-Knopfs zu
   wiederholen (border-top statt eines zweiten Kartenrahmens). Kein eigenes
   display hier (anders als .marke oben): ohne eine solche Regel gewinnt das
   display: none des hidden-Attributs unangefochten, ein eigenes [hidden]
   waere in diesem Fall ueberfluessig. */
.konzept-kachel-koerper {
  padding: 16px 18px 18px;
  border-top: 1px solid var(--linie);
}

/* Platzhalter im Zustand "laedt" (Stufe 6, Task 1, Punkt 2; siehe zeigeLaedt
   in app.js): graue Balken in der Form der kommenden Inhalte, keine
   Drehscheibe. Dieselben Klassen wie die echten Kacheln/Karten/Zeilen
   (.karte, .kacheln-vier, .eintrag) tragen Polster und Abstaende schon, ein
   Balken ersetzt hier nur die einzelne Textzeile, daher dieselbe Hoehe wie
   der Inhalt, den er ankuendigt: nichts springt, wenn der Inhalt da ist.

   Balkenhoehe folgt dabei der Schriftgroesse des Inhalts, den ein Balken
   ankuendigt (14px hier fuer gewoehnlichen Fliesstext), nicht der vollen
   Zeilenhoehe (line-height 1.45): die etwas grosszuegigen Aussenabstaende
   gleichen das aus. Bei deutlich groesserer Schrift (Uhrzeit, Kartentitel)
   reicht dieser Ausgleich allein nicht mehr, siehe .skelett-uhrzeit und
   .skelett-titel unten, dort steht die gemessene Hoehe direkt. */
.skelett {
  height: 14px;
  border-radius: 6px;
  background: var(--grund-tief);
  margin: 8px 0;
  animation: skelett-puls 1.2s ease-in-out infinite;
}

.skelett-marke { width: 88px; height: 22px; border-radius: var(--radius-pille); margin: 0; }
/* .kachel-zahl, 32px/700 mit Zeilenhoehe 1.1: im Pruefstand 35 Pixel. */
.skelett-zahl { height: 35px; }
/* .kalender-kopf-label, 17px/700: im Pruefstand rund 22 Pixel, dieselbe
   Schaetzung wie .skelett-titel unten (gleiche Groesse und Gewicht). Nur im
   allerersten Skeleton des Bereichs verwendet, siehe zeigeLaedt. */
.skelett-kalender-kopf { height: 22px; margin: 0 0 var(--kartenabstand); }
/* Neu gemessen nach dem Umbau der Typografie (Stufe 6, Task 6b, Auftrag
   Punkt 9): .heute-uhrzeit ist jetzt 56px/700 mit Zeilenhoehe 1.02, also 57
   Pixel hoch, .heute-datum 15px mit Zeilenhoehe 1.3, also 20 Pixel. Der
   ganze Kopf (Uhr plus Datum plus Abstand) misst im Pruefstand 83 Pixel
   (vorher 87). */
.skelett-uhrzeit { height: 57px; width: 150px; margin: 0; }
.skelett-datum { height: 20px; width: 65%; margin: 6px 0 0; }
/* Die beiden zusaetzlichen Zeilen des Hero-Blocks "Naechster Post"
   (Nachtrag des Koordinators zu Stufe 7, Task 3): die Abschnittsbeschriftung
   ueber der Uhrzeit (.abschnitt-kopf, 12px) und der leise Titel darunter
   (.leise, 14px). */
.skelett-abschnitt-kopf { height: 16px; width: 45%; margin: 0 0 10px; }
.skelett-naechster-post-titel { height: 20px; width: 80%; margin: 8px 0 0; }
/* .karte-titel, jetzt 17px/600 mit Zeilenhoehe 1.3, im Pruefstand 22px. */
.skelett-titel { height: 22px; }

/* Stufe 6, Task 6b: der Bereich Notiz. Im Pruefstand gemessen (375 mal 812):
   das Eingabefeld oben 328 Pixel, eine Notiz-Karte 249 bis 335 Pixel je nach
   Textlaenge und Anhang, Median 281 (Nachbesserung: die erste Messung nahm
   das Eingabefeld als vierte Karte mit und kam deshalb auf 300). */
.skelett-notiz-feld { min-height: 328px; }
.skelett-notiz-karte { min-height: 280px; }

/* Stufe 6, Task 10: der Bereich Leads. Der Knopf "CSV herunterladen" in der
   Hoehe von .knopf-gross (52 Pixel), eine Lead-Zeile als flache Karte mit
   zwei Textzeilen (E-Mail, dann Vorname/Lead-Magnet/Datum). */
.skelett-lead-knopf { height: 52px; border-radius: var(--radius-pille); margin: 12px 0; }
.skelett-lead-zeile { min-height: 64px; }

/* Stufe 6, Task 3: die Skeleton-Form fuer den Bereich Skripte, dessen
   Kacheln jetzt zusammengeklappt starten (siehe skriptKachelBauen in
   app.js). 175 Pixel, der Median aus
   sieben zusammengeklappten Kacheln unterschiedlichen Formats und Zustands
   im Pruefstand (Stufe-6-Task-3-Pruefstand, 375 mal 812, gemessen mit
   getBoundingClientRect): 147 Pixel bei einem einzeiligen Titel ohne
   Zustandshinweis-Zeile, bis 188 Pixel beim laengstmoeglichen Titel
   (ANZEIGE_TITEL_MAX_ZEICHEN) mit allen drei Zustandshinweis-Teilen
   (Video, Keyword, Termin).
   Stufe 6, Task 6b, nach der Nachbesserung erneut gemessen: 142 Pixel, der
   Median aus acht Kacheln ueber alle drei Reiter im Pruefstand (142 bis 164
   Pixel). Der Platzhalter selbst ist mit seinen vier Balken 144 Pixel hoch,
   die Mindesthoehe greift also gar nicht mehr; sie bleibt als Untergrenze
   stehen, falls ein Balken einmal wegfaellt. */
.skelett-skript-kachel { min-height: 142px; }

/* Stufe 6, Task 3: die Reiterleiste als Platzhalter, im Pruefstand
   gemessen (dieselbe Quelle wie .skelett-skript-kachel oben). Stufe 6, Task
   6b: jetzt 52 Pixel, weil die segmentierte Pille ihre 44 Pixel hohen
   Knoepfe in 4 Pixel Polster fasst. */
.skelett-reiterleiste { min-height: 52px; }

/* Befund 1b der Pruefung Stufe 6 Task 1: 134 Pixel, im Pruefstand gemessen
   und fuer alle vier Kacheln der Reihe gleich (das Grid gleicht ohnehin auf
   die hoechste Kachel der Zeile aus, siehe .kacheln-vier oben). */
/* Neu gemessen nach dem Umbau (Stufe 6, Task 6b): die vier Zaehlerkacheln
   sind mit dem kompakteren Polster (14 statt 16 Pixel) und der groesseren
   Zahl (32 statt 27) 110 Pixel (obere Reihe) bis 130 Pixel (untere Reihe,
   laengere Unterzeile) hoch gewesen. Seit der Nachbesserung sind beide
   Reihen gleich hoch (grid-auto-rows an .kacheln-vier oben), im Pruefstand
   alle vier Kacheln 130.1 Pixel: der Platzhalter nennt jetzt diese eine
   gemessene Zahl statt eines Mittelwerts aus zwei verschiedenen. */
/* Neuer Befund 5 der Nachpruefung (Fixwelle 2): derselbe Wert wie die neue
   Mindesthoehe an .kacheln-vier .kachel oben (151 Pixel, aufgerundet von
   150,4 Pixel mit zweiter Unterzeile), nicht mehr die alte, kuerzere
   130-Pixel-Messung ohne sie. Der Platzhalter ist sonst niedriger als der
   Zustand, den er ankuendigt, und das Raster waechst beim Eintreffen der
   echten Zahlen nach. */
.skelett-kachel { min-height: 151px; }

/* Stufe 6, Task 6b: die beiden neuen Flaechen ganz oben auf Heute. Die
   Freigabe-Karte misst im Pruefstand 100 Pixel (grosse Zahl plus eine Zeile
   darunter, 16 Pixel Polster). Die beiden Duotone-Kacheln haengen an der
   Zahl ihrer Zeilen: 170 Pixel bei einer, 215 bei zweien, gemessen im
   Pruefstand bei 375 mal 812; 190 Pixel ist der Mittelwert. */
.skelett-freigabe-karte { min-height: 100px; }
.skelett-duo-karte { min-height: 190px; }

/* Der Kopf einer Duotone-Kachel als Platzhalter (Stufe 6, Task 6b,
   Nachbesserung): Beschriftung links, die grosse Zahl rechts, genau wie in
   der echten Kachel (.duo-kopf). Vorher standen in der 190 Pixel hohen
   Flaeche nur zwei linksbuendige Balken und darunter viel Leere, was wie
   eine kaputte Kachel aussah statt wie eine, die gleich Inhalt bekommt. */
.skelett-duo-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.skelett-duo-kopf .skelett { margin: 0; }
/* .duo-zahl, 34px/700 mit Zeilenhoehe 1: im Pruefstand 34 Pixel. */
.skelett-duo-zahl { height: 34px; }

/* Eine Zeilengruppe im Duotone-Platzhalter, gebaut wie eine echte Zeile
   (.eintrag): ein kurzer Balken fuer die Uhrzeit links, daneben Titel und
   leise Unterzeile. Vorher standen unter dem Kopf nur zwei nackte Balken,
   und die untere Haelfte der 190 Pixel hohen Kachel blieb leer. */
.skelett-duo-zeile {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 8px 0;
}

.skelett-duo-zeile .skelett { margin: 0; }
.skelett-duo-zeit { height: 17px; flex: 0 0 auto; }
.skelett-duo-text { flex: 1 1 auto; min-width: 0; }
.skelett-duo-text .skelett { height: 17px; }
.skelett-duo-text .skelett + .skelett { height: 14px; margin-top: 4px; }

/* Die drei Balken der Freigabe-Karte in ihren echten Hoehen: .freigabe-zahl
   ist 40px/700 mit Zeilenhoehe 1.05 (42 Pixel), .freigabe-wort 15px (20),
   das Symbol daneben 26 mal 26. */
.skelett-freigabe-zahl { height: 42px; margin: 0; }
.skelett-freigabe-wort { height: 20px; margin: 2px 0 0; }
.skelett-freigabe-symbol { height: 26px; width: 26px; margin: 0; flex: 0 0 auto; }

/* Stufe 6, Task 8: der Strategie-Bereich, im Pruefstand gemessen (375 mal
   812, getBoundingClientRect): eine Saeulen-Karte 179 Pixel (alle vier
   gleich hoch), eine Beitraege-Karte mit drei Zeilen 441 bis 466 Pixel je
   nach Zeilenumbruch im Titel, die Vorschlag-Karte 293 Pixel, eine
   Erkenntnis-Zitat-Karte 118 Pixel. Die Eingabekarte am Ende teilt sich
   .skelett-notiz-feld mit dem Notiz-Bereich (siehe unten): beide sind
   derselbe Baustein (notizFeldBauen), 328 Pixel hoch in beiden Bereichen. */
.skelett-saeule-karte { min-height: 179px; }
.skelett-beitraege-karte { min-height: 450px; }
.skelett-vorschlag-karte { min-height: 293px; }
.skelett-erkenntnis-karte { min-height: 118px; }

@keyframes skelett-puls {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

/* Der aufgeklappte Kartenkoerper faehrt kurz herein (Auftrag Punkt 10).
   Eine Animation statt eines Uebergangs, weil der Koerper ueber das
   hidden-Attribut auf- und zugeht: von display: none aus gibt es nichts,
   wovon ein transition ausgehen koennte. */
.konzept-kachel-koerper:not([hidden]) { animation: koerper-herein 0.16s ease-out; }

@keyframes koerper-herein {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  /* Das Halbkreis-Menue erscheint dann ohne Auf- und Einblenden, aber es
     erscheint: die Geste selbst bleibt, nur die Bewegung faellt weg. */
  .halbkreis-schleier,
  .halbkreis-ziel { animation: none !important; }

  * { transition: none !important; }
  .skelett { animation: none !important; opacity: 0.75; }
  /* Auch die beiden Einblendungen (Blatt von unten, Kartenkoerper): sie
     sind Beiwerk, die Bedienung braucht sie nicht. */
  .blatt-inhalt,
  .konzept-kachel-koerper:not([hidden]) { animation: none !important; }
  .leiste-fab:active { transform: translateX(-50%) !important; }
  /* Der Ring am laufenden Mikrofon steht still, bleibt aber sichtbar: er ist
     hier der zweite Traeger derselben Auskunft neben der Farbe, kein
     blosser Schmuck. */
  .knopf-mikro[aria-pressed="true"]::after {
    animation: none !important;
    opacity: 0.6;
  }
}

/* Bibliothek der Schnittarten. Karten einspaltig am Handy, ab breiteren
   Fenstern ein Raster mit auto-fill; Karten einer Reihe sind gleich hoch
   (Grid streckt), der Fuss mit dem Knopf schiebt sich nach unten. Orange nur
   als harter Akzent in Status und Knopf, Ecken 12 px, Schrift hoechstens 700. */
.sa-seite {
  --sa-orange: #ffffff;
  --sa-orange-knopf: #f5f5f7;
  --sa-orange-knopf-schrift: #000000;
}
.sa-regel { color: var(--schrift-leise); margin: 0 0 6px; }
.sa-unterzeile { margin: -4px 0 10px; }
.sa-raster {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--kartenabstand);
  margin-top: var(--kartenabstand);
}
@media (min-width: 640px) {
  .sa-raster { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
}
.sa-karte {
  display: flex;
  flex-direction: column;
  border-radius: 12px;
  margin-bottom: 0;
  min-width: 0;
}
.sa-buehne {
  position: relative;
  aspect-ratio: 9 / 16;
  width: 100%;
  border-radius: 8px;
  overflow: hidden;
  background: var(--grund-tief);
}
.sa-video { display: block; width: 100%; height: 100%; object-fit: cover; background: #000; }
.sa-buehne-leer {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 18px;
  text-align: center;
}
.sa-leer-text { margin: 0; font-weight: 700; color: var(--schrift-leise); }
.sa-leer-hinweis { margin: 0; font-size: 14px; color: var(--schrift-leise); }
.sa-beispielzeile { margin: 8px 0 6px; min-height: 1.4em; }
.sa-vorschauen { display: flex; gap: 8px; margin-bottom: 4px; }
.sa-vorschau {
  flex: 1 1 0;
  min-width: 0;
  max-width: 96px;
  padding: 0;
  font: inherit;
  text-align: left;
  color: var(--schrift-leise);
  background: transparent;
  border: 1px solid var(--linie);
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
}
.sa-vorschau[aria-pressed="true"] { border-color: var(--sa-orange); color: var(--schrift); }
.sa-vorschau img { display: block; width: 100%; aspect-ratio: 9 / 16; object-fit: cover; }
.sa-vorschau-titel {
  display: block;
  padding: 4px 6px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sa-status { margin: 10px 0 2px; font-size: 14px; font-weight: 700; color: var(--sa-orange); }
.sa-name { margin: 0 0 8px; font-size: 20px; font-weight: 700; letter-spacing: -0.01em; line-height: 1.25; }
.sa-zwischen { margin: 12px 0 4px; font-size: 14px; font-weight: 700; }
.sa-liste { list-style: none; margin: 0 0 10px; padding: 0; }
.sa-liste li {
  position: relative;
  padding: 7px 0 7px 24px;
  border-top: 1px solid var(--linie);
  font-size: 15px;
}
.sa-liste li:last-child { border-bottom: 1px solid var(--linie); }
.sa-liste li::before {
  content: "\2713";
  position: absolute;
  left: 2px;
  top: 7px;
  color: var(--schrift-leise);
  font-size: 14px;
}
.sa-fuss { margin-top: auto; padding-top: 12px; }
.sa-meldung { margin: 0 0 8px; min-height: 1.4em; font-size: 14px; }
.sa-meldung[hidden] { display: block; visibility: hidden; }
.sa-ersatzfeld {
  display: block;
  width: 100%;
  margin: 0 0 8px;
  font: inherit;
  font-size: 14px;
  color: var(--schrift);
  background: var(--grund-tief);
  border: 1px solid var(--linie);
  border-radius: 8px;
  padding: 8px;
  resize: none;
}
.sa-ersatzfeld[hidden] { display: none; }
.sa-knopf {
  width: 100%;
  background: var(--sa-orange-knopf);
  color: var(--sa-orange-knopf-schrift);
  font-weight: 700;
}
.skelett-schnittarten-regel { height: 16px; margin-bottom: 8px; }
.sa-skelett-karte { height: 420px; border-radius: 12px; margin: 0; }
