/* Alpinity Agents-Portal — die Seitenmodule beider Produkte.
 *
 * HERKUNFT: Diese Datei ist die Zusammenführung von `voice.css` und `chat.css`
 * (beide entfallen am 2026-08-20). Vorher lud der Telefonteil app.css + voice.css,
 * der Chatteil app.css + chat.css — und chat.css überschrieb die gemeinsame
 * Kopfzeile so weit, dass dasselbe Portal zwei Gestaltungen hatte und eine
 * Änderung an app.css nur eine Hälfte erreichte.
 *
 * ARBEITSTEILUNG mit app.css:
 *   app.css   = Tokens, Typografie, Hülle (Leiste, Schubfach, Unternavigation),
 *               Bausteine, die überall gleich sind (Karte, Kachel, Knopf, Feld,
 *               Tabelle, Meldung, Marke, Balkenreihe, Diagramm, Abspieler).
 *   portal.css= Seitenmodule: Startseite, Assistentenliste, Steckbrief, Editor,
 *               Wissensabschnitte, Verlauf, Transkript, Konnektoren.
 *
 * Zwei Regeln, die man beim Erweitern nicht brechen darf (sie stehen auch in
 * app.css, weil sie für beide Dateien gelten):
 *
 *   1. DIE LICHTKANTE. Karten, Knöpfe und Felder haben ausschliesslich einen
 *      `border-top` in einem helleren Ton. Ein gleichmässiger vierseitiger
 *      Rahmen sieht sofort falsch aus.
 *   2. KEIN GRÜN. Die grünen Werte im Framer-Markup sind wirkungslose Fallbacks
 *      aus altem Branding. Für „erfolgreich/erledigt" gibt es Petrol oder
 *      zurückhaltendes Weiss.
 *
 * In dieser Datei steht bewusst KEIN Hex-Wert — alle Farben kommen als Token aus
 * app.css. Wer hier eine neue Farbe braucht, braucht in Wahrheit ein neues Token.
 *
 * Aufbau:
 *   1  Sektionsrhythmus
 *   2  Startseite
 *   3  Upsell
 *   4  Assistentenliste, Steckbrief, Aktionskarten
 *   5  Editor (Anweisungen, Onboarding)
 *   6  Wissensabschnitte und Markdown-Typografie
 *   7  Gespräche, Transkript, Klienten, Änderungen
 *   8  Konnektoren und interne Befunde
 *   9  Rechtsseiten
 *  10  Stimmprobe
 *  11  Schmale Fenster
 */

/* ========================================================================== */
/* 1  Sektionsrhythmus                                                        */
/* ========================================================================== */

/* Zwei Kartenblöcke ohne Abstand lesen sich als ein einziger, verunglückter
   Raster. Jeder Block bekommt Abstand und einen eigenen Titel; DESIGN.md Punkt 2:
   keine Sektion ohne gesperrtes Versal-Label. */
.section { margin-top: var(--s-7); }
.section:first-of-type { margin-top: 0; }
.section > .section-head {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin-bottom: var(--s-4); flex-wrap: wrap;
}
.section > .section-head .eyebrow { margin: 0; }
.section > .section-head .section-note { font-size: 13.5px; color: var(--text-2); margin: 0; }

/* Der Seitenkopf: Luft nach unten, aber nicht mehr als die Sektionen untereinander. */
.page-head { margin-bottom: var(--s-7); }
.page-head .lead { margin-bottom: 0; }

/* Fokus überall gleich, auch auf Zeilen und Karten. */
a.card:focus-visible,
a.tile:focus-visible,
.bot-row:focus-visible,
.action-card:focus-visible,
.home-karte:focus-visible,
.choice:focus-within {
  outline: 2px solid var(--accent-light);
  outline-offset: 2px;
}

/* ========================================================================== */
/* 2  Startseite                                                              */
/* ========================================================================== */

/* Die Startseite war bis 2026-08-20 komplett ungestaltet: sie gab `.karte`,
   `.karten`, `.produkt-karte` und `.seitenkopf` aus — Klassen, für die es in
   keiner Datei einen Selektor gab. Ein Layout aus nicht existierenden Klassen
   sieht genau so aus, und es war ausgerechnet die erste Seite nach der Anmeldung. */

.home-karten {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--s-5);
}

.home-karte {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-6);
  background: var(--surface);
  border: 0;
  border-top: 2px solid var(--border);
  border-radius: var(--r-card);
  color: inherit;
  text-decoration: none;
  transition: border-top-color .15s ease, background-color .15s ease;
}
a.home-karte:hover { text-decoration: none; border-top-color: var(--accent-mid); background: var(--surface-2); }
.home-karte .eyebrow { margin: 0; }
.home-karte h2 { font-size: 26px; letter-spacing: -0.04em; }
.home-karte p { margin: 0; color: var(--text-2); max-width: 46ch; }
.home-karte .home-foot {
  display: flex; align-items: center; gap: var(--s-3);
  margin-top: auto; padding-top: var(--s-4); flex-wrap: wrap;
}

/* Ein nicht gebuchtes Produkt wird ZURÜCKGENOMMEN, nicht eingefärbt — die Marke
   trägt einen Akzent, ein Zustand wird über Form unterschieden. Die Deckkraft
   bleibt bei 0.72 und nicht darunter: sonst fällt der Fliesstext unter die
   Lesbarkeitsschwelle, und eine Kachel, die man nicht lesen kann, verkauft nichts. */
.home-karte.ist-gesperrt { opacity: 0.72; }
.home-karte.ist-gesperrt:hover,
.home-karte.ist-gesperrt:focus-within { opacity: 1; }

/* ========================================================================== */
/* 3  Upsell                                                                  */
/* ========================================================================== */

/* Eine Seite, kein Shop: am Ende steht ein Gespräch. Deshalb eine ruhige Liste
   und EINE hervorgehobene Karte, kein Preisraster. */
.liste-kann { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--s-3); }
.liste-kann li {
  position: relative;
  padding-left: var(--s-6);
  color: var(--text-2);
  font-size: 16px;
  line-height: 1.55;
}
/* Der Haken ist ein CSS-Zeichen, kein Emoji: er soll auf jedem Gerät gleich
   aussehen und nicht farbig werden. */
.liste-kann li::before {
  content: '';
  position: absolute;
  left: 0; top: 0.55em;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.aktionen { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: center; margin: var(--s-5) 0 0; }
.aktionen form { display: contents; }

/* ========================================================================== */
/* 4  Assistentenliste, Steckbrief, Aktionskarten                             */
/* ========================================================================== */

/* Ein Assistent ist ein Objekt, keine Kachel: volle Breite, aber auch voll belegt.
   Eine einzelne Kachel in einem Zweispalter wird auf 1136px gestreckt und enthält
   vier Zeilen Text am linken Rand — die hohlste Fläche im ganzen Portal. */
.bot-list { display: flex; flex-direction: column; gap: var(--s-3); }

.bot-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 176px 208px 20px;
  align-items: center;
  gap: var(--s-5);
  padding: var(--s-5);
  background: var(--surface);
  border: 0;
  border-top: 2px solid var(--border);
  border-radius: var(--r-card);
  color: inherit;
  text-decoration: none;
  transition: border-top-color .15s ease, background-color .15s ease;
}
.bot-row:hover { text-decoration: none; border-top-color: var(--accent-mid); background: var(--surface-2); }
.bot-row:hover .bot-row-go { color: var(--accent-light); transform: translateX(3px); }

.bot-row-name {
  font-family: var(--font);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.25;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-width: 0;
  overflow-wrap: anywhere;
}
.bot-row-sub { font-size: 13.5px; color: var(--text-2); margin-top: 3px; overflow-wrap: anywhere; }

/* Zwei Fakten rechts, in Spalten ausgerichtet — Label klein und leise, Wert darunter. */
.fact { min-width: 0; margin: 0; }
.fact dt {
  font-family: var(--font-label);
  font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-2); margin: 0 0 5px;
}
.fact dd { margin: 0; font-size: 14.5px; line-height: 21px; color: var(--text); letter-spacing: -0.01em; overflow-wrap: anywhere; }
.fact dd.mono { font-size: 13px; line-height: 21px; }

.bot-row-go {
  justify-self: end;
  color: var(--text-2);
  transition: transform .15s ease, color .15s ease;
  line-height: 0;
}

/* Der Puls sagt „antwortet gerade" und gehört zum Live-Zustand eines Assistenten.
   Der Punkt selbst kommt aus app.css (.dot-on mit Hof, semantische Tokens).
   app.css schaltet unter prefers-reduced-motion alle Animationen global ab. */
.bot-row .dot-on,
.status-line .dot-on { animation: dot-pulse 2.4s ease-out infinite; }
@keyframes dot-pulse {
  0%   { box-shadow: 0 0 0 3px color-mix(in srgb, var(--state-on) 22%, transparent); }
  70%  { box-shadow: 0 0 0 7px color-mix(in srgb, var(--state-on) 0%, transparent); }
  100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--state-on) 22%, transparent); }
}

/* Statuszeile direkt unter dem Namen — ohne Karte. Der Zustand des Assistenten
   ist keine Kennzahl, er ist eine Eigenschaft der Überschrift. */
.status-line {
  display: flex; align-items: center; gap: var(--s-3);
  margin-top: var(--s-3);
  font-size: 15px; color: var(--text-2);
  flex-wrap: wrap;
}
.status-line b { font-weight: 500; color: var(--text); }
.status-line .sep { color: var(--border-2); }

/* Steckbrief: vier Fakten, EIN Objekt, Haarlinien dazwischen. Vier einzelne
   Karten mit je zwölf Zeichen Inhalt sind vier hohle Flächen; dieselben Angaben
   in einem Objekt lesen sich als Datenblatt. */
.spec {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  background: var(--surface);
  border: 0;
  border-top: 2px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
  margin: 0;
}
.spec > div {
  display: grid; grid-template-rows: auto minmax(38px, auto) auto; align-content: start;
  padding: var(--s-5); border-left: 1px solid var(--border-2); min-width: 0;
}
.spec > div:first-child { border-left: none; }
.spec dt {
  font-family: var(--font-label);
  font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-2); margin: 0 0 var(--s-3);
}
.spec dd {
  margin: 0; align-self: start;
  font-size: 17px; font-weight: 500; letter-spacing: -0.02em; color: var(--text);
  overflow-wrap: anywhere;
}
.spec dd.mono { font-size: 14px; font-weight: 400; letter-spacing: 0; }
.spec .u { font-size: 13px; font-weight: 400; color: var(--text-2); letter-spacing: 0; line-height: 1.45; }

/* Eine Zahl ist eine Zahl und darf so aussehen. */
.spec dd.num {
  font-family: var(--font);
  font-size: 34px; font-weight: 500; line-height: 1; letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
}
.spec dd.num .unit { font-size: 17px; font-weight: 400; letter-spacing: -0.02em; }

/* Aktionskarten: die zwei Dinge, die man hier wirklich tut — also die grössten
   Flächen der Seite, mit einer Zahl darin statt nur einem Satz. */
.action-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--s-4); }
.action-card {
  display: flex; flex-direction: column;
  min-height: 188px;
  padding: var(--s-5);
  background: var(--surface);
  border: 0;
  border-top: 2px solid var(--border);
  border-radius: var(--r-card);
  color: inherit; text-decoration: none;
  transition: border-top-color .15s ease, background-color .15s ease;
}
.action-card:hover { text-decoration: none; border-top-color: var(--accent-mid); background: var(--surface-2); }
.action-card:hover .action-go { color: var(--accent-light); transform: translateX(3px); }
.action-card h3 { font-size: 20px; font-weight: 500; letter-spacing: -0.03em; margin: 0 0 var(--s-2); }
.action-card p { color: var(--text-2); font-size: 14.5px; margin: 0; max-width: 42ch; }
.action-foot {
  display: flex; align-items: center; gap: var(--s-3);
  margin-top: auto; padding-top: var(--s-4);
}
.action-metric {
  font-family: var(--font);
  font-size: 15px; color: var(--text); letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.action-metric span { color: var(--text-2); }
.action-go { margin-left: auto; color: var(--text-2); line-height: 0; transition: transform .15s ease, color .15s ease; }

/* ========================================================================== */
/* 5  Editor                                                                  */
/* ========================================================================== */

/* Zweispalter: links die Arbeit, rechts die Einstellungen. Modell und Sprache
   sind keine Arbeitsschritte, sie sind Schalter — untereinander in der Mitte der
   Seite lesen sie sich wie ein Formular, das man von oben nach unten abarbeitet. */
.editor-layout { display: grid; grid-template-columns: minmax(0, 1fr) 296px; gap: var(--s-5); align-items: start; }
.editor-main { min-width: 0; }
.editor-side { display: flex; flex-direction: column; gap: var(--s-4); min-width: 0; }
.editor-side .card { padding: var(--s-4) var(--s-5) var(--s-5); }
.editor-side h3 { font-size: 15px; font-weight: 500; letter-spacing: -0.02em; margin-bottom: var(--s-4); }

.editor-head {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin-bottom: var(--s-3); flex-wrap: wrap;
}
.editor-head h2 { font-size: 20px; font-weight: 500; letter-spacing: -0.03em; }
.editor-head .counter { margin-left: auto; font-size: 12.5px; font-variant-numeric: tabular-nums; }

/* Das Schreibfeld. Kein Kasten im Kasten: der Text IST die Fläche. 13px
   Monospace über 60vh ist eine graue Wand; 14px auf 1.75 Zeilenhöhe mit 24px
   Rand liest sich wie ein Dokument. */
.prompt-editor {
  width: 100%;
  min-height: 64vh;
  resize: vertical;
  padding: var(--s-5);
  font-family: var(--font-mono);
  font-size: 14px;
  line-height: 1.75;
  tab-size: 2;
  background: var(--surface);
  border: 0;
  border-top: 2px solid var(--border);
  border-radius: var(--r-btn);
}
.prompt-editor:focus { border: 1px solid var(--accent-light); border-top: 1px solid var(--accent-light); }
/* Huelle um die Bearbeiten-Tipps: im Lese-Modus versteckt, beim Sofort-Wechsel
   per Skript eingeblendet — der Abstand gehoert zur Huelle, nicht zum ersten Tipp. */
.editor-tips { margin-top: var(--s-3); }
.editor-tips[hidden] { display: none; }
.editor-tip { font-size: 13.5px; color: var(--text-2); margin: var(--s-3) 0 0; }

/* Hülle um Lese-Ansicht und Schreibfeld. Sie hält beide an derselben Stelle im
   Fluss, damit der Wechsel zwischen den Ansichten die Seite nicht springen lässt. */
.anweisungen { min-width: 0; }

/* Die Lese-Ansicht der Anweisungen.
   Derselbe Rahmen wie das Schreibfeld, damit der Wechsel die Seite nicht springen
   lässt — aber Fliesstext statt Monospace: das hier liest ein Mensch, um zu
   verstehen, was sein Assistent tut, nicht um Zeichen zu zählen.
   Die Rauten sind weg; die Gliederung, die sie beschreiben, ist zu sehen. */
.prompt-lesen {
  padding: var(--s-5);
  background: var(--surface);
  border: 0;
  border-top: 2px solid var(--border);
  border-radius: var(--r-btn);
  max-height: 64vh;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.prompt-lesen > :first-child { margin-top: 0; }
.prompt-lesen > :last-child { margin-bottom: 0; }
.prompt-lesen p {
  color: var(--text-2); font-size: 15px; line-height: 1.65;
  margin: 0 0 var(--s-3); max-width: 78ch; overflow-wrap: anywhere;
}
/* markdown.js beginnt bei h3 — die h1 der Seite gehört der Seite. */
.prompt-lesen h3 {
  font-size: 19px; font-weight: 500; letter-spacing: -0.03em; color: var(--text);
  margin: var(--s-6) 0 var(--s-3);
}
.prompt-lesen h4 {
  font-size: 16px; font-weight: 500; letter-spacing: -0.02em; color: var(--text);
  margin: var(--s-5) 0 var(--s-2);
}
.prompt-lesen h5, .prompt-lesen h6 {
  font-family: var(--font-label);
  font-size: 12px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent-pale); margin: var(--s-5) 0 var(--s-2);
}
.prompt-lesen ul, .prompt-lesen ol {
  color: var(--text-2); font-size: 15px; line-height: 1.65;
  margin: 0 0 var(--s-3); padding-left: 1.3em; max-width: 78ch;
}
.prompt-lesen li { margin-bottom: var(--s-2); }
.prompt-lesen li::marker { color: var(--text-3); }
.prompt-lesen hr { border: 0; border-top: 1px solid var(--border-2); margin: var(--s-5) 0; }
.prompt-lesen strong { color: var(--text); font-weight: 500; }
.prompt-lesen code {
  font-family: var(--font-mono); font-size: 13px; color: var(--accent-pale);
  overflow-wrap: anywhere;
}
.prompt-lesen .empty { padding: var(--s-6) 0; }

/* Im aufgeklappten Transparenzblock ist weniger Platz: dort steht derselbe
   gerenderte Text, aber ohne eigenen Rahmen und eine Stufe kleiner. */
.prompt-lesen-eng {
  padding: 0;
  background: transparent;
  border-top: 0;
  border-radius: 0;
  max-height: none;
  overflow: visible;
}
.prompt-lesen-eng p, .prompt-lesen-eng ul, .prompt-lesen-eng ol { font-size: 14px; line-height: 1.6; }
.prompt-lesen-eng h3 { font-size: 15px; margin: 0 0 var(--s-3); }

/* Der Umschalter sitzt in der Kopfzeile des Editors, rechts neben dem Zähler. */
.editor-head .btn { margin-left: var(--s-3); }
.editor-head .counter { margin-left: auto; }

/* Auswahlzeilen für Modell und Sprache.
   app.css formatiert jedes `label` als gesperrtes Versal-Label; text-transform
   vererbt sich, also erschienen Modellname und Erklärung sonst in Grossbuchstaben
   mit weiter Sperrung — „CLAUDE-SONNET-5 / SCHNELL UND GÜNSTIG". */
.choice {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  gap: var(--s-3);
  align-items: start;
  padding: var(--s-3);
  margin: 0 calc(var(--s-3) * -1) 2px;
  border-radius: var(--r-badge);
  cursor: pointer;
  text-transform: none;
  letter-spacing: normal;
  font-family: var(--font);
  font-size: 14px;
  font-weight: 400;
  color: var(--text);
  transition: background-color .15s ease;
}
.choice:hover { background: var(--surface-2); }
.choice input[type='radio'] { width: 18px; height: 18px; margin: 1px 0 0; accent-color: var(--accent-light); cursor: pointer; }
.choice b { display: block; font-weight: 500; letter-spacing: -0.01em; }
.choice .hint { display: block; font-size: 13px; color: var(--text-2); margin-top: 2px; line-height: 1.45; }
/* :has fehlt nur in sehr alten Browsern; dort bleibt die Markierung am nativen
   Optionsfeld sichtbar, die Zeile ist dann nur nicht hinterlegt. */
.choice:has(input:checked) { background: var(--accent-soft); }
.choice.ist-gesperrt { opacity: 0.6; cursor: default; }

/* Kleines Textfeld für die Standardsprache — ohne Versallabel darüber. */
.mini-field {
  display: flex; align-items: center; gap: var(--s-3);
  margin-top: var(--s-4); padding-top: var(--s-4);
  border-top: 1px solid var(--border-2);
}
.mini-field span { font-size: 13.5px; color: var(--text-2); }
.mini-field input { width: 5rem; padding: 9px 12px; text-align: center; }

/* Aktionsleiste. Bei 23 000 Zeichen im Feld liegt „Speichern" zwei Bildschirme
   unter dem Text, den man gerade geändert hat. Sie bleibt am unteren Rand stehen
   und nennt den Zustand: ungespeicherte Änderungen ja oder nein. */
.actionbar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin: var(--s-5) 0 0;
  padding: var(--s-4) var(--s-5);
  background: var(--nav-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 0;
  border-top: 2px solid var(--border);
  border-radius: var(--r-card);
  flex-wrap: wrap;
}
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .actionbar { background: var(--surface); }
}
.actionbar .state { display: flex; align-items: center; gap: var(--s-3); font-size: 13.5px; color: var(--text-2); min-width: 0; }
.actionbar.dirty .state { color: var(--text); }
.actionbar input[type='text'] { flex: 1 1 260px; min-width: 0; padding: 10px 12px; font-size: 14px; }
.actionbar .btn { padding: 12px 18px; font-size: 15px; }

/* Meldungen: Ursache, Fundstelle, Vorschlag — getrennt, nicht als Fliesstext. */
.finding { margin-top: var(--s-3); }
.finding + .finding { padding-top: var(--s-3); border-top: 1px solid var(--border-2); }
.finding p { margin: 0 0 var(--s-2); font-size: 14px; line-height: 1.55; max-width: 76ch; }
.finding p:last-child { margin-bottom: 0; }
.finding .found,
.finding .fix {
  display: block;
  font-family: var(--font-mono);
  font-size: 12.5px; line-height: 1.6;
  padding: var(--s-3);
  border-radius: var(--r-badge);
  background: var(--surface);
  border-left: 2px solid var(--border);
  overflow-wrap: anywhere;
}
.finding .fix { border-left-color: var(--accent-light); }
.finding .apply { display: block; margin-top: var(--s-3); }
.finding .k {
  font-family: var(--font-label);
  font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-2); display: block; margin: var(--s-3) 0 5px;
}

/* Der gesperrte Transparenzblock — sichtbar, aber zusammengeklappt.
   Er darf nicht verschwinden (das ist die Zusage an den Kunden), aber er darf
   auch nicht den Seitenanfang besetzen: er ändert sich nie. */
details.locked-block { padding: 0; }
details.locked-block > summary {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  cursor: pointer;
  font-size: 14px; color: var(--text);
  list-style: none;
}
details.locked-block > summary::-webkit-details-marker { display: none; }
details.locked-block > summary::marker { content: ''; }
details.locked-block > summary .lock { color: var(--accent-light); line-height: 0; flex-shrink: 0; }
details.locked-block > summary .hint { color: var(--text-2); font-size: 13px; margin-left: auto; }
details.locked-block > summary:hover .hint { color: var(--text); }
details.locked-block > summary:focus-visible { outline: 2px solid var(--accent-light); outline-offset: -2px; border-radius: var(--r-card); }
.locked-body {
  padding: var(--s-4);
  border-top: 1px solid var(--border-2);
}
.locked-body p { font-size: 14px; line-height: 1.6; color: var(--text-2); margin: 0 0 var(--s-3); }
.locked-body p:last-child { margin-bottom: 0; }
.locked-body .quote { color: var(--text); }

/* ========================================================================== */
/* 6  Wissensabschnitte und Markdown-Typografie                               */
/* ========================================================================== */

/* Das Suchfeld klebt unter der Navigation. Bei 200 Abschnitten scrollt es sonst
   weg, sobald man den zweiten aufklappt — und die Suche ist genau dann nützlich,
   wenn man schon mitten in der Liste steht.

   `top` ist GENAU `--nav-space`, ohne Abzug. `--nav-space` ist der Platz, den
   `main` oben freihält, und liegt damit immer unterhalb der schwebenden Leiste
   (auf dem Telefon 13px darunter, am Rechner 26px) — safe-area eingerechnet, weil
   die Variable sie enthält. Mit einem Abzug von 32px, wie er hier zuerst stand,
   schob sich das klebende Feld beim Rollen 19 Pixel UNTER die Leiste; auf dem
   Bildschirmfoto war das nicht zu sehen, weil ein Ganzseitenfoto klebende
   Elemente an ihrer Ruheposition zeichnet. Gemessen wurde es im gerollten
   Zustand. Wer hier wieder etwas abzieht, baut denselben Fehler ein. */
.abschnitt-suche {
  position: sticky;
  top: var(--nav-space);
  z-index: 4;
  display: flex;
  gap: var(--s-3);
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: var(--s-3);
  padding: var(--s-3);
  background: var(--nav-bg);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 0;
  border-top: 1px solid var(--border-2);
  border-radius: var(--r-card);
}
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .abschnitt-suche { background: var(--surface); }
}
.abschnitt-suche input[type='search'] {
  flex: 1 1 220px;
  min-width: 0;
  padding: 10px 14px;
  font-size: 15px;
}
.abschnitt-zahl {
  font-family: var(--font-label);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-2);
  margin: 0 0 var(--s-3);
}

/* Der Inhalt IST Markdown: roh angezeigt steht dort „# GET-FIT" und „---" im
   Klartext. Das sieht nach Rohdaten aus, nicht nach einem Produkt. Gerendert
   wird über lib/chat/markdown.js. */
.chunk-list { display: flex; flex-direction: column; gap: var(--s-3); }

.chunk {
  padding: 0;
  overflow: hidden;
  background: var(--surface);
  border: 0;
  border-top: 2px solid var(--border);
  border-radius: var(--r-card);
}
.chunk > summary {
  display: flex; align-items: baseline; gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  cursor: pointer; list-style: none;
  transition: background-color .15s ease;
}
.chunk > summary::-webkit-details-marker { display: none; }
.chunk > summary::marker { content: ''; }
.chunk > summary:hover { background: var(--surface-2); }
.chunk > summary:focus-visible { outline: 2px solid var(--accent-light); outline-offset: -2px; }
.chunk[open] > summary { border-bottom: 1px solid var(--border-2); }

.chunk-title {
  font-family: var(--font); font-size: 15px; color: var(--text);
  letter-spacing: -0.01em; flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chunk-meta {
  font-family: var(--font-mono); font-size: 12px; color: var(--text-2);
  flex-shrink: 0; white-space: nowrap;
}
.chunk-warn { color: var(--state-alert); }

/* Der gerenderte Inhalt. Grosszügige Zeilenhöhe — das liest ein Mensch. */
.chunk-body { padding: var(--s-4) var(--s-5) var(--s-5); }
.chunk-body > :first-child { margin-top: 0; }
.chunk-body > :last-child { margin-bottom: 0; }
.chunk-body p { color: var(--text-2); font-size: 14.5px; line-height: 1.6; margin: 0 0 var(--s-3); overflow-wrap: anywhere; }
.chunk-body h3 { font-size: 16px; font-weight: 500; letter-spacing: -0.02em; margin: var(--s-4) 0 var(--s-2); }
.chunk-body h4, .chunk-body h5, .chunk-body h6 {
  font-size: 14.5px; font-weight: 500; color: var(--text); margin: var(--s-4) 0 var(--s-2);
}
.chunk-body ul, .chunk-body ol {
  color: var(--text-2); font-size: 14.5px; line-height: 1.6;
  margin: 0 0 var(--s-3); padding-left: 1.4em;
}
.chunk-body li { margin-bottom: 4px; }
.chunk-body hr { border: 0; border-top: 1px solid var(--border-2); margin: var(--s-4) 0; }
.chunk-body code { font-family: var(--font-mono); font-size: 13px; color: var(--accent-pale); overflow-wrap: anywhere; }
.chunk-body strong { color: var(--text); font-weight: 500; }

/* Tabellen im Wissen rollen seitwärts, statt die Seite zu sprengen. */
.md-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 0 var(--s-3); }
.md-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.md-table th, .md-table td {
  text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border-2);
  white-space: nowrap;
}
.md-table th {
  color: var(--text); font-family: var(--font-label); font-size: 11.5px;
  text-transform: uppercase; letter-spacing: .1em; font-weight: 500;
}
.md-table td { color: var(--text-2); }

/* ========================================================================== */
/* 7  Gespräche, Transkript, Klienten, Änderungen                             */
/* ========================================================================== */

/* Änderungsvergleich zweier Fassungen. Hier bleibt der Rohtext stehen — ein
   Vergleich, der die Auszeichnung wegrendert, vergliche nicht mehr, was
   gespeichert wird. */
.diff { font-family: var(--font-mono); font-size: 13px; line-height: 1.55; margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.diff ins { background: var(--accent-soft); color: var(--text); text-decoration: none; display: block; }
.diff del { background: var(--danger-soft); color: var(--text-2); text-decoration: none; display: block; }
.diff .ctx { color: var(--text-2); display: block; }

/* Gesprächsverlauf: Sprechblasen, eingehend links, ausgehend rechts.
   Der Verlauf ist ein EIGENES Rollfeld mit fester Höhe, kein Seiteninhalt: bei 189
   Nachrichten schob er sonst Pauseschalter und Antwortfeld hunderte Bildpunkte nach
   unten, und wer antworten wollte, musste erst am ganzen Gespräch vorbeirollen
   (Julians Befund 21.08.). app.js rollt das Feld beim Laden ans Ende — die neueste
   Nachricht ist der Grund, warum man die Seite öffnet. Ohne Skript steht das Feld am
   Anfang; rollen im Feld geht auch dann. */
.msg-verlauf {
  display: flex; flex-direction: column;
  max-height: 480px;
  max-height: min(58dvh, 620px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--s-4);
  margin-bottom: var(--s-5);
  background: rgba(20, 20, 20, 0.45);
  border: 1px solid var(--border);
  border-top-color: var(--border-2);
  border-radius: var(--r-card);
}
.msg {
  max-width: min(62ch, 100%);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-btn);
  margin-bottom: var(--s-3);
  overflow-wrap: anywhere;
  flex-shrink: 0;
}
.msg-in  { background: var(--surface);     border-top: 1px solid var(--border); }
.msg-out { background: var(--accent-deep); border-top: 1px solid var(--accent-mid); margin-left: auto; }
.msg .small { color: var(--text-2); }

.verlauf-row { grid-template-columns: minmax(0, 1fr) 120px 20px; }

/* Anruftranskript. Rolle und Text nebeneinander, damit man den Wechsel sieht,
   ohne jede Zeile zu lesen. */
.transkript { list-style: none; margin: var(--s-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-3); }
.transkript li {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: var(--s-4);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--border);
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--text-2);
  overflow-wrap: anywhere;
}
.transkript li:last-child { border-bottom: 0; }
.rolle {
  font-family: var(--font-label);
  font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-2);
}
.rolle-agent .rolle { color: var(--accent-pale); }
.rolle-agent { color: var(--text); }

/* Die Zusammenfassung ist der einzige lange Text in einer Tabellenzeile — sie
   darf umbrechen, während die Spalten daneben schmal bleiben. */
.zusammenfassung { min-width: 220px; overflow-wrap: anywhere; }

/* Klienten: Suchzeile und Anlegen-Formular als waagerechte Reihen. */
.suchzeile { display: flex; gap: var(--s-3); align-items: center; margin-bottom: var(--s-5); flex-wrap: wrap; }
.suchzeile input { flex: 1 1 240px; min-width: 0; }
.formular-zeile { display: flex; gap: var(--s-3); align-items: flex-end; flex-wrap: wrap; }
.formular-zeile .field { flex: 1 1 200px; margin-bottom: 0; min-width: 0; }

.zeilen-aktionen { white-space: nowrap; }

/* ========================================================================== */
/* 8  Konnektoren und interne Befunde                                         */
/* ========================================================================== */

.con-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--s-4); }

/* Interner Abgleich Portal ↔ Live-Workflow (nur Alpinity-Konten). */
.befund-zeile td { padding-top: 0; }
.befund {
  padding: var(--s-3);
  margin-bottom: var(--s-2);
  border-radius: var(--r-badge);
  background: var(--surface);
  border-left: 2px solid var(--border-2);
  font-size: 13.5px;
  line-height: 1.55;
  overflow-wrap: anywhere;
}
.befund:last-child { margin-bottom: 0; }
.befund strong { color: var(--text); font-weight: 500; }
.befund-ok { border-left-color: var(--accent-light); }
.befund-warn { border-left-color: var(--danger); }

/* ========================================================================== */
/* 9  Rechtsseiten                                                            */
/* ========================================================================== */

/* Impressum, Datenschutz, Nutzungsbedingungen. Öffentlich, ohne Anmeldung, ohne
   Navigation — eine einzelne Textspalte auf demselben Schwarz. Bewusst schmaler
   als der Rest des Portals: das hier wird gelesen, nicht bedient, und ab etwa
   75 Zeichen je Zeile verliert das Auge beim Rücksprung die Zeile.

   Die Seiten tragen dieselbe schwarz-durchscheinende Statusleiste wie das Portal,
   haben aber KEINE schwebende Kopfzeile, die den Abstand nach oben halten würde —
   deshalb steht die safe-area hier direkt am Inhalt. Ohne sie stünde die
   Überschrift auf dem iPhone unter der Uhr. */
.recht-seite { background: var(--bg); }

.recht {
  max-width: 760px;
  margin: 0 auto;
  padding:
    calc(var(--s-8) + env(safe-area-inset-top))
    max(var(--s-5), env(safe-area-inset-right))
    calc(var(--s-8) + env(safe-area-inset-bottom))
    max(var(--s-5), env(safe-area-inset-left));
}
.recht h1 { margin-bottom: var(--s-5); }
.recht h2 {
  font-size: 22px;
  letter-spacing: -0.03em;
  margin: var(--s-7) 0 var(--s-3);
}
.recht p, .recht li { color: var(--text-2); line-height: 1.65; overflow-wrap: break-word; }
.recht p { margin: 0 0 var(--s-4); }
.recht ul { margin: 0 0 var(--s-4); padding-left: 1.3em; }
.recht li { margin-bottom: var(--s-2); }
.recht strong { color: var(--text); font-weight: 500; }
/* Der Entwurfshinweis steht auf jeder Rechtsseite ganz oben und braucht Luft. */
.recht .notice { margin: var(--s-4) 0 var(--s-6); }
.recht .eyebrow a { color: var(--accent-pale); }
/* Die Fusszeile der Rechtsseiten steht im Textfluss, nicht am Seitenende. */
.recht .foot {
  margin-top: var(--s-8);
  padding: var(--s-5) 0 0;
  gap: var(--s-4);
}

/* Dieselben drei Links in der Fusszeile des angemeldeten Portals. Sie rutschen
   ans Ende der Zeile, damit sie die Betriebsangaben davor nicht auseinanderziehen. */
.foot-recht { margin-left: auto; }
.foot-recht a { color: var(--text-2); }
.foot-recht a:hover { color: var(--text); }

@media (max-width: 720px) {
  .recht h2 { font-size: 19px; }
  /* Nach links, sobald die Fusszeile ohnehin umbricht — rechtsbündig sähe dort
     wie ein Versehen aus. */
  .foot-recht { margin-left: 0; }
}

/* ========================================================================== */
/* 10  Stimmprobe                                                             */
/* ========================================================================== */

/* Der eigene Abspieler kommt aus app.css (.player). Hier steht nur, was den
   NATIVEN Abspieler betrifft — er bleibt als Rückfall im Markup stehen und ist
   ohne JavaScript das Einzige, was da ist.
   `preload="none"` im Markup: ohne Antippen verlässt keine Anfrage den Browser. */
.voice-preview { margin-top: var(--s-3); }
.voice-preview audio {
  width: 100%;
  height: 36px;
  margin-top: var(--s-2);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color-scheme: dark;
}

/* ========================================================================== */
/* 11  Schmale Fenster                                                        */
/* ========================================================================== */

@media (max-width: 1080px) {
  .editor-layout { grid-template-columns: minmax(0, 1fr); }
  .editor-side { flex-direction: row; flex-wrap: wrap; }
  .editor-side > * { flex: 1 1 300px; }
}

@media (max-width: 860px) {
  .bot-row { grid-template-columns: minmax(0, 1fr) 20px; gap: var(--s-4); }
  .bot-row .fact { grid-column: 1 / -1; display: flex; align-items: baseline; gap: var(--s-3); }
  .bot-row .fact dt { margin: 0; min-width: 88px; flex: none; }
  .bot-row-go { grid-row: 1; grid-column: 2; }
  .verlauf-row { grid-template-columns: minmax(0, 1fr) 20px; }
  .spec { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .spec > div { border-top: 1px solid var(--border-2); }
  .spec > div:nth-child(odd) { border-left: none; }
  .spec > div:nth-child(-n+2) { border-top: none; }
  /* Die Aktionsleiste klebt unten — auf einem Telefon war sie damit 239px hoch
     (Zustand, Notizfeld und zwei Knöpfe je auf eigener Zeile) und verdeckte ein
     Drittel des Bildschirms, gemessen am 20.08.2026 auf 390×844. Eine Leiste, die
     mehr verdeckt als sie erreichbar macht, ist keine Hilfe mehr.
     Also: der Zustandstext entfällt (er ist Beiwerk, den Zustand sagt auch der
     Knopf), die Knöpfe teilen sich eine Zeile. */
  /* Die Aktionsleiste KLEBT AUF DEM TELEFON NICHT.
     Sie war dort 239px hoch (Zustand, Notizfeld und zwei Knöpfe je auf eigener
     Zeile) und verdeckte ein Drittel des Bildschirms. Kompakter ist sie jetzt
     ohnehin — aber entscheidend ist: eine klebende Leiste über einem Bereich mit
     eigener Rollfläche sperrt dessen unteres Ende weg, und genau diese Kombination
     hat hier schon zweimal Ärger gemacht. Am Boden der Seite steht sie ohnehin
     dort, wo man sie sucht, und der Lesebereich darüber ist kurz. */
  .actionbar {
    position: static;
    gap: var(--s-3);
    padding: var(--s-3) var(--s-4);
  }
  .actionbar .state { display: none; }
  .actionbar input[type='text'] { flex: 1 1 100%; }
  .actionbar .btn { flex: 1 1 auto; padding: 10px 14px; }

  /* Der Lesebereich bleibt begrenzt und rollt in sich — auch auf dem Telefon.
     Ohne Begrenzung wuchs die Agent-Seite mit einem 23 000 Zeichen langen Prompt
     auf 79 836 Pixel: rund 95 Bildschirme, die man erst durchwischen muss, um an
     Stimme und Sprachmodell darunter zu kommen (gemessen 21.08.2026 auf 390×844).
     Das ging vorher nicht, weil die klebende Leiste das untere Ende des Kastens
     verdeckte — sie klebt jetzt nicht mehr, damit ist der Weg frei. */
  .prompt-editor { min-height: 48vh; font-size: 13.5px; padding: var(--s-4); }
  .prompt-lesen { max-height: 60vh; overflow-y: auto; padding: var(--s-4); }
  .home-karte { padding: var(--s-5); }
}

@media (max-width: 560px) {
  .spec { grid-template-columns: minmax(0, 1fr); }
  .spec > div { border-left: none; border-top: 1px solid var(--border-2); }
  .spec > div:first-child { border-top: none; }
  .bot-row-name { font-size: 19px; }
  .home-karte h2 { font-size: 22px; }
  /* Rolle über den Text statt daneben: 88px Spalte plus Text ergeben auf einem
     Telefon zwei Zeichen je Zeile. */
  .transkript li { grid-template-columns: minmax(0, 1fr); gap: var(--s-1); }
  .aktionen .btn { width: 100%; }
}

