:root {
  --bg: #0b0d10;
  --fg: #f2f4f7;
  --muted: #9aa4b2;
  --ok: #35d07f;
  --warn: #ffb020;
  --bad: #ff5c5c;
  /* Eigene Farbe fürs Sprechen. Rot ist vergeben (privat, gesperrt), Grün
     heißt „jetzt auslösen" — eine dritte Bedeutung braucht eine dritte Farbe,
     sonst liest sich die laufende Sprachaufnahme wie eine Warnung. */
  --talk: #4aa8ff;
  /* Und eine vierte fürs Antworten auf eine Frage. Blau ist „ich spreche",
     dieses Lila ist „ich spreche **zu dem, der gefragt hat**". Zwei
     Sprechtasten in derselben Farbe wären zwei Wege, von denen einer die
     Antwort an den Falschen schickt. */
  --stern: #c99bff;
  --pad: max(14px, env(safe-area-inset-bottom));

  /* Kopfzeile und Symbolleiste rahmen jeden Bereich ein. Als Variablen, weil
     ein halbes Dutzend Elemente sich daran ausrichtet — die Sprechtaste, der
     Auslöser, die Auftragskarte, die Meldungen. Ein Zahlenwert, an sechs
     Stellen abgeschrieben, hält keinen Umbau aus. */
  /* Schätzwerte. Gemessen wird trotzdem — siehe messeRahmen() in app.js. */
  --kopf-h: calc(34px + env(safe-area-inset-top));
  --leiste-h: calc(58px + env(safe-area-inset-bottom));
  --tonzeile-h: 34px;
  /* Höhe der unteren Ecke insgesamt. Gemessen, siehe messeRahmen(). */
  --eckzeile-h: 92px;

  /* Farben der Coaches, gleich wie im Dashboard (dashboard/static/styles.css).
     Derselbe Coach muss auf beiden Bildschirmen dieselbe Farbe haben, sonst
     ist die Farbe keine Auskunft mehr, sondern Dekoration. */
  --coach-health: #199e70;
  --coach-personal: #d55181;
  --coach-work: #3987e5;
  --coach-business-marketing: #d95926;
  --coach-private: #9085e9;
  --coach-scrum: #6b7684;
  --coach-unbekannt: #8b93a0;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0; height: 100%; overflow: hidden;
  background: var(--bg); color: var(--fg);
  font: 15px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  overscroll-behavior: none;
}

#view {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  background: #000;
}
/* Gespiegelt wird, was `spiegeltJetzt()` sagt — Vorschau und gespeichertes
   Bild folgen derselben Entscheidung. Vorher hing die Vorschau starr an der
   Frontkamera, während die Datei nie gespiegelt wurde; wer ein Selfie machte,
   bekam etwas anderes, als er beim Ausrichten gesehen hatte. */
body.spiegel #view { transform: scaleX(-1); }

#flash {
  position: fixed; inset: 0; background: #fff; opacity: 0;
  pointer-events: none; transition: opacity .12s ease-out;
}
#flash.on { opacity: .85; transition: none; }

/* Aufhellen ohne LED: weiße Fläche über allem, die das Motiv auf Armlänge
   beleuchtet. Die Bildschirmhelligkeit selbst kann eine Webseite nicht
   stellen — Weiß auf voller Fläche ist das, was geht. Für die Frontkamera
   der einzige Weg, weil dort keine LED sitzt. */
body.aufhellen::before {
  content: ''; position: fixed; inset: 0; z-index: 20;
  background: #fff; pointer-events: none;
}
/* Der Sucher schrumpft in die Ecke, statt fast den ganzen Bildschirm zu
   belegen. Vorher blieb vom Weiß nur ein Rand — das beleuchtet nichts.
   Ausgerichtet ist zu diesem Zeitpunkt ohnehin schon; die Ecke reicht, um zu
   sehen, dass das Motiv noch im Bild ist. Jedes Stück Fläche, das der Sucher
   nimmt, fehlt als Licht. */
body.aufhellen #view {
  z-index: 21; position: fixed;
  inset: auto 12px 12px auto; width: 30%; height: 22%;
  border-radius: 10px; box-shadow: 0 2px 10px #0004;
}
/* Auch die Bedienung tritt zurück: dunkle Knöpfe auf weißem Grund fressen
   Licht und sind in dem Moment sowieso nicht in Gebrauch. */
body.aufhellen .kopf,
body.aufhellen .leiste,
body.aufhellen .kamerazeile,
body.aufhellen .shutter,
body.aufhellen .sprechen,
body.aufhellen .sprecher,
body.aufhellen .tonzeile,
body.aufhellen .dreh-schicht { opacity: 0; transition: opacity .12s ease; }

/* Unscharf: rotes Aufblitzen am Bildrand. Anders als der weiße Auslöseblitz,
   damit die beiden nicht verwechselt werden. */
body.unscharf #view {
  outline: 6px solid var(--bad); outline-offset: -6px;
  animation: ruettel .45s ease-in-out 2;
}
@keyframes ruettel {
  0%, 100% { transform: none; }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}

body.privat #view { outline: 4px solid var(--bad); outline-offset: -4px; }

/* Ein Agent hat diese eine Aufnahme als privat angefordert. Dieselbe rote
   Sprache wie beim eigenen Schalter — Stefan soll nicht zweierlei lernen
   müssen. Der Schalter selbst wird nur umrandet, nicht gefüllt: er ist
   nicht gedrückt und bleibt bedienbar. */
body.agent-privat #view { outline: 4px solid var(--bad); outline-offset: -4px; }
/* Ring um das Schloss, nicht auf ihm: eine Animation auf dem Symbol selbst
   blendet es mit aus, und dann fehlt genau das Zeichen, um das es geht. */
body.agent-privat #privateBtn .ico { box-shadow: 0 0 0 2px var(--bad); }
body.agent-privat #privateBtn .ico::after {
  content: ''; position: absolute; width: 50px; height: 50px; border-radius: 50%;
  border: 2px solid var(--bad); animation: puls 1.6s ease-out infinite;
}
body.agent-privat #privateBtn .lbl { color: var(--bad); }
body.gesperrt #view { outline: 4px solid var(--warn); outline-offset: -4px; }
body.privat.gesperrt #view {
  outline-color: var(--bad);
  box-shadow: inset 0 0 0 8px var(--warn);
}

/* ── Kopfzeile ────────────────────────────────────────────────────────────
   Wer gerade spricht, darunter der Zustand. Sie steht in jedem Bereich, weil
   die Frage „wer redet da gerade" nicht davon abhängt, welchen Reiter Stefan
   offen hat — und weil eine Stimme aus der Hosentasche bei sieben Coaches
   ohne Absender nicht zuzuordnen ist.

   Undurchsichtig, nicht nur abgedunkelt: Im Kamerabereich liegt der Sucher
   darunter, und eine halbtransparente Kopfzeile über einem bewegten Bild ist
   nicht mehr zu lesen. */
/* Eine Zeile, so hoch wie früher die untere Hälfte. Der große Sprecherblock
   mit Bild und „verbunden und hörbereit" stand bis zum 2026-08-08 hier oben
   und sagte den ganzen Tag dasselbe; wer spricht, steht jetzt unten links,
   wo der Daumen liegt und wo es sich wirklich ändert. */
.kopf {
  position: fixed; top: 0; left: 0; right: 0; z-index: 8;
  padding: max(5px, env(safe-area-inset-top)) 10px 5px;
  background: linear-gradient(#0b0d10f2 60%, #0b0d10cc);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid #ffffff14;
}

/* Zustand und Griffe: Verbindungspunkt, die runden Knöpfe, Uhr rechts. */
.kopfZustand {
  display: flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--muted);
}
/* Die Uhr steht **neben dem Verbindungspunkt**, nicht vor den beiden Knöpfen.
   Mit `margin-left: auto` wurde sie ans andere Ende geschoben und schwebte
   dort zwischen der freien Mitte und den Knöpfen. Stefan am 2026-08-09: „Die
   könnte ich jetzt zum Beispiel direkt neben den grünen Button, dann wäre das
   sauberer." Die Lücke in der Mitte bleibt damit frei — sie war Absicht. */
.kopfZustand .uhr { font-variant-numeric: tabular-nums; }
/* Der Schub ans rechte Ende wandert an den ersten der beiden Knöpfe. */
.kopfZustand #vollBtn { margin-left: auto; }

.chip.rund {
  padding: 4px 8px; font-size: 15px; line-height: 1;
  display: inline-flex; align-items: center; gap: 4px;
}

/* ── Bereiche ─────────────────────────────────────────────────────────────
   Vier Flächen zwischen Kopfzeile und Symbolleiste, von denen immer genau
   eine sichtbar ist. Der Wechsel läuft über `body[data-bereich]`, nicht über
   `hidden` an jedem Abschnitt: So kann eine Regel auch andere Teile der Seite
   mitschalten — den Sucher, die Sprechtaste, die Auftragskarte. */
.bereich {
  position: fixed; z-index: 2;
  top: var(--kopf-h); left: 0; right: 0; bottom: var(--leiste-h);
  display: none; flex-direction: column;
  overflow: hidden;
}
/* Der Inhalt endet über der unteren Ecke, statt dahinter zu verschwinden.
   Nicht im Kamerabereich: Dort liegt unten das Sucherbild, und das soll die
   ganze Fläche füllen — die Knöpfe schweben bewusst darüber. */
body:not([data-bereich="kamera"]) .bereich {
  bottom: calc(var(--leiste-h) + var(--eckzeile-h));
}
/* Läuft ein Gespräch, rückt die Sprecherblase eine Zeile höher — beide
   nebeneinander wäre in einem Viertel nicht zu lesen. */
/* Läuft ein Gespräch, rückt die Sprecherblase eine Zeile höher — sie und die
   Ecke nebeneinander wären in einem Viertel nicht zu lesen. Seit das Band weg
   ist, reicht der Abstand der Ecke selbst. */
body.imGespraech .sprecher {
  bottom: calc(var(--leiste-h) + var(--tonzeile-h) + 24px);
}
body[data-bereich="aufgaben"] #b-aufgaben,
body[data-bereich="fragen"]   #b-fragen,
body[data-bereich="chat"]     #b-chat,
body[data-bereich="kamera"]   #b-kamera,
body[data-bereich="status"]   #b-status { display: flex; }

/* Der Sucher liegt hinter allem und wird nur im Kamerabereich gezeigt.
   `visibility` statt `display`: Ein ausgeblendetes Video verliert in manchen
   Browsern seinen Stream, und der wäre beim Zurückwechseln neu zu starten. */
body:not([data-bereich="kamera"]) #view { visibility: hidden; }
body:not([data-bereich="kamera"]) .last { display: none; }

/* Listenbereiche scrollen, der Kamerabereich nie. */
#b-aufgaben, #b-fragen, #b-chat, #b-status { background: var(--bg); }
.bereichKopf {
  display: flex; align-items: baseline; gap: 10px;
  padding: 12px 14px 6px; flex: none;
}
.bereichKopf h2 {
  margin: 0; font-size: 13px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--muted);
}
.bereichKopf .text { width: auto; margin-left: auto; font-size: 12px; padding: 0; }

.leerlauf {
  margin: 0; padding: 22px 20px; color: var(--muted);
  font-size: 13.5px; text-align: center; line-height: 1.5;
}
.leerlauf[hidden] { display: none; }

/* ── Symbolleiste ─────────────────────────────────────────────────────────
   Vier Zeichen, keine Wörter — wie bei jeder App, in der die Bereiche wenige
   und immer dieselben sind. Ein Wort darunter kostet genau den Platz, den die
   Trefferfläche braucht. */
.leiste {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 8;
  height: var(--leiste-h);
  padding-bottom: env(safe-area-inset-bottom);
  display: flex; align-items: stretch;
  background: #0b0d10f2; backdrop-filter: blur(10px);
  border-top: 1px solid #ffffff14;
}
.reiter {
  appearance: none; border: 0; background: transparent; color: #6d7684;
  flex: 1; display: grid; place-items: center; padding: 0; position: relative;
  transition: color .15s ease;
}
.reiter svg {
  width: 25px; height: 25px; fill: none; stroke: currentColor;
  stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
.reiter[aria-selected="true"] { color: var(--fg); }
/* Der aktive Reiter bekommt zusätzlich einen Strich. Farbe allein trägt
   nicht: Auf dem Handy in der Sonne ist der Unterschied zwischen Grau und
   Weiß genau der, den man nicht sieht. */
.reiter[aria-selected="true"]::before {
  content: ''; position: absolute; top: 0; left: 26%; right: 26%; height: 2px;
  background: var(--fg); border-radius: 0 0 2px 2px;
}
.reiter:active { color: var(--fg); }
/* Ungelesenes im Chat. Nur ein Punkt, keine Zahl: Wie viele Sätze aufgelaufen
   sind, ändert nichts daran, dass man hineinsehen muss. */
.reiter .punkt {
  position: absolute; top: 11px; right: calc(50% - 17px);
  width: 8px; height: 8px; border-radius: 50%; background: var(--talk);
  border: 2px solid #0b0d10;
}
.reiter .punkt[hidden] { display: none; }

/* Offene Fragen als **Zahl**, nicht als Punkt — anders als beim Chat. Beim
   Chat ändert die Anzahl nichts daran, dass man hineinsehen muss. Hier schon:
   Ob eine Frage wartet oder sieben, entscheidet, ob er es zwischendurch macht
   oder sich hinsetzt. */
.reiter .zahl {
  position: absolute; top: 8px; right: calc(50% - 21px);
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  background: var(--warn); color: #000; border: 2px solid #0b0d10;
  font-size: 10px; font-weight: 700; line-height: 12px; text-align: center;
}
.reiter .zahl[hidden] { display: none; }

/* Bedienung mitdrehen, wenn Android die Bildschirmdrehung sperrt. Die
   Elemente bleiben, wo sie sind — nur ihr Inhalt kippt mit, damit er beim
   quer gehaltenen Gerät lesbar bleibt. Derselbe Winkel dreht auch das
   gespeicherte Bild, sonst lägen die Aufnahmen falsch herum. */
/* Eine Schicht, die als Ganzes mit der Gerätelage kippt. Der Inhalt wird
   darin normal positioniert — Auftrag oben, letzte Aufnahme unten links —
   und landet dadurch bei jeder Haltung dort, wo Stefan ihn erwartet. Jedes
   Element einzeln zu drehen und zu verschieben führt dagegen dazu, dass
   Karten über dem Auslöser landen oder in der Mitte hängen. */
.dreh-schicht {
  position: fixed; inset: 0; z-index: 4;
  pointer-events: none;
  transition: transform .25s ease, width .25s ease, height .25s ease;
}
.dreh-schicht > * { pointer-events: auto; }

/* Bei Querlage tauschen Breite und Höhe die Rollen; die Schicht wird um den
   Mittelpunkt gedreht. */
body[data-dreh="90"] .dreh-schicht,
body[data-dreh="270"] .dreh-schicht {
  width: 100vh; height: 100vw;
  top: 50%; left: 50%; right: auto; bottom: auto;
  margin: 0;
}
body[data-dreh="90"]  .dreh-schicht { transform: translate(-50%, -50%) rotate(90deg); }
body[data-dreh="270"] .dreh-schicht { transform: translate(-50%, -50%) rotate(270deg); }
body[data-dreh="180"] .dreh-schicht { transform: rotate(180deg); }

/* Die Schalter unten drehen sich einzeln, sie bleiben in der Leiste. Die
   Chips oben stehen fest: der Ordnername ist breit und liefe gedreht aus
   dem Bild. */
body[data-dreh="90"]  .side { transform: rotate(90deg); }
body[data-dreh="180"] .side { transform: rotate(180deg); }
body[data-dreh="270"] .side { transform: rotate(270deg); }
/* Das Mikrofonzeichen der Sprechtaste blieb bisher stehen, während sich alles
   andere mitdrehte — ein Detail, das aber sofort auffällt, weil die Taste die
   größte Fläche unten rechts ist. Der Knopf selbst bleibt rund und an seinem
   Platz; nur sein Zeichen kippt mit. */
body[data-dreh="90"]  .sprechen .ico, body[data-dreh="90"]  .senden { transform: rotate(90deg); }
body[data-dreh="180"] .sprechen .ico, body[data-dreh="180"] .senden { transform: rotate(180deg); }
body[data-dreh="270"] .sprechen .ico, body[data-dreh="270"] .senden { transform: rotate(270deg); }
.sprechen .ico { transition: transform .25s ease; }
.side { transition: transform .25s ease; }
/* Der Knopf für die Automatik dreht sich nicht mit — sonst wüsste man beim
   Umschalten nicht mehr, welcher er ist. */
#drehBtn { transform: none !important; }
/* Gelb wie die anderen Zustandsanzeigen. Grün ist für "jetzt drücken"
   reserviert — die Lageautomatik verlangt nichts, sie läuft nur mit. */
#drehBtn[aria-pressed="true"] { border-color: var(--warn); color: var(--warn); }

/* Sprachausgabe pausiert. Gelb wie alles, was etwas anhält, ohne es
   unkenntlich zu machen — und deutlich genug, dass die Stille einen
   sichtbaren Grund hat. */
#tonBtn[aria-pressed="true"] { border-color: var(--warn); color: var(--warn); }

/* Das mitlaufende Mikrofon. Es ist das einzige Element dieser Oberfläche, das
   dauerhaft etwas tut, ohne dass jemand es angestoßen hat — also zeigt es das
   auch dauerhaft an: blau wie alles Sprachliche, mit einem langsam atmenden
   Ring. Langsam, weil es den ganzen Tag im Blick ist; ein schnelles Blinken
   würde man nach einer Stunde abkleben wollen.

   Aus ist es unauffällig grau. Das ist Absicht: Der Ruhezustand eines
   Mikrofons braucht keine Aufmerksamkeit, der offene schon. */
/* Baustelle. Oben unter der Leiste, gelb wie alles, was etwas anhält, ohne es
   unkenntlich zu machen. Sie steht durchgehend, solange sie läuft — eine
   Meldung, die nach drei Sekunden verschwindet, wäre genau die, die man
   verpasst, wenn man das Handy gerade weglegt. */
/* **Ganz unten am Bildschirmrand, wie ein Aufkleber.** Oben hat es am
   2026-08-08 genau die Stelle verdeckt, die Stefan beurteilen wollte — ein
   Hinweis über der Arbeit ist kein Hinweis mehr, sondern ein Vorhang. Auch
   eine eigene Zeile über der Symbolleiste war falsch: Sie schob wieder etwas
   weg. Es liegt jetzt **über** der Leiste und verdeckt deren Zeichen zum Teil.
   Das ist gewollt — es ist ein Hinweis für uns, kein Bedienelement für ihn. */
.baustelle {
  position: fixed; bottom: 0; left: 0; right: 0;
  margin: 0 auto; width: fit-content; max-width: 92vw;
  /* Über der Symbolleiste (z-index 8), nicht darunter: Es soll deren Zeichen
     teilweise verdecken. Meldungen liegen mit 12 weiterhin darüber — eine
     Absage, die hinter dem Baustellenhinweis verschwindet, ist der Fehler, den
     wir am 2026-08-08 schon einmal repariert haben. */
  z-index: 9; display: flex; align-items: center; gap: 6px;
  background: #000c; border: 1px solid #ffb02066; backdrop-filter: blur(8px);
  /* **So flach wie der Text.** Es liegt über der Symbolleiste, und jede Zeile
     Polsterung verdeckt eine Zeile Bedienung — Stefan am 2026-08-08: „Das darf
     auf gar keinen Fall ein White Space haben, sonst überdeckt es mein
     komplettes Menü." Ein Hinweis für uns darf im Weg sein, aber nicht so
     sehr, dass er die App unbenutzbar macht. */
  border-radius: 999px 999px 0 0; padding: 2px 12px 3px;
  font-size: 11px; line-height: 1.25; color: var(--warn);
  animation: auftauchen .2s ease;
}
.baustelle[hidden] { display: none; }
.baustelle b { font-weight: 700; }
.baustelle .wozu { color: var(--muted); font-variant-numeric: tabular-nums; }

/* Pause. Anders als die Baustelle über die volle Breite und mit ruhigem
   Atem: Sie gilt bis zum Widerruf, ohne Zeitverfall, und der Preis dafür ist
   Sichtbarkeit. Eine vergessene Pause schaltet still die Gefahrenwarnungen
   ab — deshalb ein Band, das man nicht übersieht, und keine Ecke.
   Das Pulsen ist langsam: Es soll erinnern, nicht drängen. */
/* Dieselbe Sorte Auskunft wie die Pause, deshalb dieselbe Stelle und
   dieselbe Form — nur rot, weil hier etwas fehlt statt bewusst gesetzt zu
   sein. */
.wachHinweis {
  position: fixed; top: calc(var(--kopf-h) + 6px); left: 10px; right: 10px;
  z-index: 7; text-align: center;
  background: #2a0b0be6; border: 1px solid var(--bad); backdrop-filter: blur(8px);
  border-radius: 12px; padding: 9px 14px;
  font: 600 12px/1.3 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: #ffbdbd;
}
.wachHinweis[hidden] { display: none; }

.pauseBand {
  position: fixed; top: calc(var(--kopf-h) + 6px); left: 10px; right: 10px;
  z-index: 7; display: flex; align-items: center; justify-content: center; gap: 8px;
  appearance: none; text-align: left;
  background: #2a1a00e6; border: 1px solid var(--warn); backdrop-filter: blur(8px);
  border-radius: 12px; padding: 9px 14px;
  font: 600 12px/1.3 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--warn);
  animation: auftauchen .2s ease, pausenAtem 3.2s ease-in-out .2s infinite;
}
.pauseBand[hidden] { display: none; }
.pauseBand b { font-weight: 800; letter-spacing: .02em; }
.pauseBand .wozu { color: #ffd9a0; font-weight: 500; }
.pauseBand:active { transform: scale(.985); }
@keyframes pausenAtem {
  0%, 100% { box-shadow: 0 0 0 0 #ffb02000; }
  50%      { box-shadow: 0 0 0 4px #ffb02026; }
}
/* Solange pausiert ist, tritt der Rest der Seite zurück. Der Zustand ist die
   Nachricht, nicht der Inhalt darunter. */
body.ton-pause .bereich { opacity: .72; }
@media (prefers-reduced-motion: reduce) {
  /* Dieselbe Sorte Auskunft wie die Pause, deshalb dieselbe Stelle und
   dieselbe Form — nur rot, weil hier etwas fehlt statt bewusst gesetzt zu
   sein. */
.wachHinweis {
  position: fixed; top: calc(var(--kopf-h) + 6px); left: 10px; right: 10px;
  z-index: 7; text-align: center;
  background: #2a0b0be6; border: 1px solid var(--bad); backdrop-filter: blur(8px);
  border-radius: 12px; padding: 9px 14px;
  font: 600 12px/1.3 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: #ffbdbd;
}
.wachHinweis[hidden] { display: none; }

.pauseBand { animation: auftauchen .2s ease; }
}

#mikBtn { position: relative; color: var(--muted); }
#mikBtn[aria-pressed="true"] { border-color: #4aa8ff7a; color: var(--talk); }
#mikBtn[aria-pressed="true"]::after {
  content: ''; position: absolute; inset: -3px; border-radius: 999px;
  border: 1px solid var(--talk); animation: atmen 2.8s ease-in-out infinite;
  pointer-events: none;
}
@keyframes atmen {
  0%, 100% { opacity: .15; transform: scale(1); }
  50%      { opacity: .7;  transform: scale(1.08); }
}

/* Ohne den Verlauf hinter der Leiste stehen Schrift und Symbole direkt auf
   dem Kamerabild — ein Schatten hält sie auch vor hellen Motiven lesbar. */
.conn, .side .lbl, .side .ico { text-shadow: 0 1px 4px #000c, 0 0 12px #0009; }

/* Nur der Punkt: Der Verbindungszustand hat drei Farben und braucht keine
   Worte. Oben wird Platz für die Sprachbedienung gebraucht. */
.conn { display: flex; align-items: center; padding: 6px; }
.conn .dot { width: 11px; height: 11px; border-radius: 50%; background: var(--warn); box-shadow: 0 0 8px currentColor; }
.conn.on .dot { background: var(--ok); }
.conn.off .dot { background: var(--bad); }

.chip {
  appearance: none; border: 1px solid #ffffff2e; background: #0009; color: var(--fg);
  border-radius: 999px; padding: 7px 13px; font-size: 13px; backdrop-filter: blur(6px);
}
.chip b { font-weight: 600; }

.ausloeser { display: grid; justify-items: center; gap: 10px; }

/* Auftrag über dem Auslöser: was fotografiert werden soll und von wem die
   Bitte kommt. Steht über dem Daumen, nicht darunter — dort verdeckt die
   Hand beim Auslösen nichts. */
/* Oben mittig in der Dreh-Schicht — dort, wo der Blick beim Ausrichten
   ohnehin hingeht, und nie über dem Auslöser. */
.auftrag {
  position: absolute; top: calc(var(--kopf-h) + 8px); left: 50%; transform: translateX(-50%);
  display: grid; justify-items: center; gap: 3px; text-align: center;
  max-width: min(320px, 84%); width: max-content;
  background: #0007; border: 1px solid var(--ok); backdrop-filter: blur(6px);
  border-radius: 12px; padding: 8px 15px;
  animation: auftauchen .25s ease;
}
.auftrag b { font-size: 15px; font-weight: 600; line-height: 1.3; }
.auftrag span { font-size: 11px; color: var(--ok); font-weight: 600; }

/* Warten mehrere, zeigt ein Kreis in der Ecke deren Zahl. Die Karte selbst
   bleibt einem Auftrag vorbehalten — Überschrift und Absender müssen
   zusammengehören, sonst liest es sich, als warteten zwei auf dasselbe. */
.mehr-badge {
  position: absolute; top: -9px; right: -9px;
  width: 26px; height: 26px; border-radius: 50%;
  appearance: none; border: 1px solid var(--ok);
  background: #0b0d10; color: var(--ok);
  font-size: 11px; font-weight: 700; line-height: 1;
  display: grid; place-items: center; padding: 0;
}
.mehr-badge[hidden] { display: none; }
.mehr-badge:active { background: var(--ok); color: #06301c; }

/* Beendet einen Auftrag, bei dem die Anzahl offen gelassen wurde. */
.fertig {
  appearance: none; margin-top: 6px;
  border: 1px solid var(--ok); background: var(--ok); color: #06301c;
  border-radius: 999px; padding: 6px 18px;
  font-size: 13px; font-weight: 700;
}
.fertig[hidden] { display: none; }
.fertig:active { opacity: .7; }
@keyframes auftauchen {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
body.privat .auftrag { border-color: var(--bad); }
body.privat .auftrag span { color: var(--bad); }
/* Muss nach .auftrag stehen: sonst gewinnt display:grid gegen [hidden] und
   die Karte bleibt stehen, obwohl niemand mehr wartet. */
.auftrag[hidden] { display: none; }

/* Auslöser: mittig, unmittelbar über der Symbolleiste — dieselbe Höhe wie die
   Sprechtaste rechts daneben. Die vier Schalter (Nur ich, Ordner, Kamera,
   Privat) sind dafür eine Reihe nach oben gerückt: Nebeneinander in einer
   Zeile hätten Auslöser, vier Schalter und Sprechtaste auf 375 px keinen
   Platz, und die Sprechtaste muss in allen vier Bereichen an derselben Stelle
   liegen. Alles andere am Kamerabereich bleibt, wie es war. */
.shutter {
  position: fixed; z-index: 6;
  left: 50%; transform: translateX(-50%);
  bottom: calc(var(--leiste-h) + 10px);
  appearance: none; border: 4px solid #fff; background: #fff3;
  width: 78px; height: 78px; border-radius: 50%;
  display: grid; place-items: center; padding: 0;
  transition: transform .08s ease, border-color .2s ease;
}
.shutter:active { transform: translateX(-50%) scale(.92); }
body:not([data-bereich="kamera"]) .shutter,
body:not([data-bereich="kamera"]) .kamerazeile { display: none; }

/* Die vier Schalter, unverändert in Aussehen und Reihenfolge — jetzt oben im
   Bereich, unter der Kopfzeile. Über dem Sucher schwebend, weil der Sucher die
   ganze Fläche füllt. */
.kamerazeile {
  position: fixed; z-index: 6;
  left: 0; right: 0; top: calc(var(--kopf-h) + 8px);
  display: flex; align-items: flex-start; justify-content: space-evenly;
  padding: 0 8px;
}
/* Ein Agent wartet auf eine Aufnahme — dann ist klar, dass das Drücken
   gerade erwartet wird und nicht ins Leere läuft. */
body.erwartet .shutter {
  border-color: var(--ok);
  animation: warten 1.5s ease-in-out infinite;
}
body.erwartet .shutter span { background: var(--ok); }

/* Aufnahme läuft: gelb statt grün, und ohne Puls. Grün heißt "drück jetzt" —
   solange verarbeitet wird, wäre das eine falsche Aufforderung. */
body.aufnahme .shutter {
  border-color: var(--warn);
  animation: none;
}
body.aufnahme .shutter span { background: var(--warn); }

/* Reihenaufnahme: Der Auslöser ist jetzt der Stoppknopf. Rotes Quadrat statt
   Kreis — dieselbe Form, die überall "Aufnahme beenden" bedeutet. */
body.intervall-laeuft .shutter {
  border-color: var(--bad);
  animation: warten 1.5s ease-in-out infinite;
}
body.intervall-laeuft .shutter span {
  background: var(--bad);
  width: 30px; height: 30px; border-radius: 6px;
  transition: all .2s ease;
}
body.intervall-laeuft.aufnahme .shutter { animation: none; }
@keyframes warten {
  0%, 100% { box-shadow: 0 0 0 0 rgba(53, 208, 127, .55); }
  50%      { box-shadow: 0 0 0 12px rgba(53, 208, 127, 0); }
}
/* Privat schlägt Warten: die Warnung darf nie von einem Hinweis
   überdeckt werden. */
body.privat.erwartet .shutter { border-color: var(--bad); }
body.privat.erwartet .shutter span { background: var(--bad); }
body.privat .warte-label { color: var(--bad); }
.shutter span { width: 60px; height: 60px; border-radius: 50%; background: #fff; display: block; }
.shutter[disabled] { opacity: .45; }
body.privat .shutter { border-color: var(--bad); }
body.privat .shutter span { background: var(--bad); }

.side {
  appearance: none; border: 0; background: transparent; color: var(--fg);
  display: grid; justify-items: center; gap: 4px; width: 64px; padding: 6px 0;
  font-size: 10px; letter-spacing: .02em;
}
.side .ico {
  font-size: 19px; width: 46px; height: 46px; border-radius: 50%;
  background: #ffffff1f; display: grid; place-items: center;
}
/* Ordnernamen können lang werden — abschneiden statt die Leiste sprengen. */
.side .lbl {
  max-width: 62px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Fernauslösung gesperrt: gelb, weil es nichts unkenntlich macht,
   sondern nur mich aussperrt. */
#lockBtn[aria-pressed="true"] .ico { background: var(--warn); }
#lockBtn[aria-pressed="true"] .ico::after { border-color: var(--warn); }
#lockBtn[aria-pressed="true"] .lbl { color: var(--warn); }
.side[aria-pressed="true"] .ico { background: var(--bad); }
.side[aria-pressed="true"] .ico::after {
  content: ''; position: absolute; width:  46px; height: 46px; border-radius: 50%;
  border: 2px solid var(--bad); animation: puls 1.6s ease-out infinite;
}
@keyframes puls { to { transform: scale(1.35); opacity: 0; } }
.side .ico { position: relative; }
.side .lbl { color: var(--muted); }
.side[aria-pressed="true"] .lbl { color: var(--bad); font-weight: 600; }

/* Countdown vor einer Fernauslösung mit Vorlauf. Bewusst groß und mittig:
   Stefan richtet in der Zeit das Handy aus und schaut nicht auf Details. */
.countdown {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
  z-index: 7; display: grid; place-items: center;
  width: 180px; height: 180px; pointer-events: none;
}
.countdown[hidden] { display: none; }
/* Läuft ein Countdown, tritt die Auftragskarte zurück: Beides gleichzeitig
   konkurriert um denselben Blick, und in der Sekunde zählt nur die Zahl. */
body.countdown-laeuft .auftrag { opacity: 0; transition: opacity .2s; }
.countdown svg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  transform: rotate(-90deg);          /* Start oben, im Uhrzeigersinn */
}
.countdown circle { fill: none; stroke-width: 5; }
.countdown .spur { stroke: #ffffff26; }
.countdown .lauf {
  stroke: var(--ok); stroke-linecap: round;
  transition: stroke-dashoffset 1s linear, stroke .3s;
}
.countdown .zahl {
  font-size: 66px; font-weight: 200; line-height: 1;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 2px 18px #000c;
}
.countdown .was {
  position: absolute; bottom: -6px;
  font-size: 12px; color: var(--muted); white-space: nowrap;
  text-shadow: 0 1px 8px #000;
}

/* Bei einer Serie: welcher Schritt gerade läuft, als Kreis am Ring — dieselbe
   Sprache wie das "+N" an der Auftragskarte. */
.countdown .schritt {
  position: absolute; top: 4px; right: 4px;
  width: 30px; height: 30px; border-radius: 50%;
  background: #0b0d10; border: 1px solid var(--ok); color: var(--ok);
  font-size: 12px; font-weight: 700;
  display: grid; place-items: center;
}
.countdown .schritt[hidden] { display: none; }
.countdown.privat .schritt { border-color: var(--bad); color: var(--bad); }

/* Restdauer der ganzen Serie, damit klar ist, worauf man sich einlässt. */
.countdown .gesamt {
  position: absolute; bottom: -26px;
  font-size: 11px; color: var(--muted); white-space: nowrap;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 8px #000;
}
.countdown .gesamt[hidden] { display: none; }
/* Letzte drei Sekunden: Farbe wechselt und die Zahl pulst je Schritt. */
.countdown.gleich .lauf { stroke: var(--warn); }
.countdown.gleich .zahl { color: var(--warn); animation: tick .9s ease-out; }
/* Vom Agenten als privat angefordert: durchgehend rot, damit vor dem
   Auslösen klar ist, dass dieses Bild niemand außer Stefan sieht. */
.countdown.privat .lauf,
.countdown.privat.gleich .lauf { stroke: var(--bad); }
.countdown.privat .zahl,
.countdown.privat.gleich .zahl { color: var(--bad); }
.countdown.privat .was { color: var(--bad); font-weight: 600; }
@keyframes tick {
  0%   { transform: scale(1.35); opacity: .5; }
  100% { transform: scale(1); opacity: 1; }
}

/* Wer gerade spricht. Eine Stimme aus der Hosentasche ist ohne Absender
   nicht zuzuordnen — bei mehreren Coaches ist das die eigentliche Frage.
   Deshalb steht der Name oben und nicht am Rand: Er ist die Auskunft, der
   Satz darunter nur die Beigabe.

   Blau statt Grün: Grün heißt in dieser Oberfläche „jetzt auslösen", und
   eine sprechende Stimme ist keine Aufforderung zu fotografieren. Blau ist
   die Farbe der Sprache — dieselbe wie bei der Sprechtaste unten, nur die
   andere Richtung. */
/* Mittig gesetzt über `margin: auto`, nicht über `translateX(-50%)`: Die
   Einblendung animiert `transform` und würde die Zentrierung für ihre 0,2 s
   überschreiben — die Leiste käme sichtbar aus der falschen Ecke und
   spränge dann an ihren Platz. */
/* Unten links, gegenüber der Sprechtaste: rechts redet Stefan, links reden
   sie. Die Breite ist gedeckelt, damit ein langer Satz nicht bis unter die
   Taste läuft — er wird abgeschnitten, nicht umgebrochen, sonst wüchse die
   Blase in die Fläche hinein, die gerade gelesen wird. */
.sprecher {
  position: fixed; z-index: 6;
  left: 6px; bottom: calc(var(--leiste-h) + var(--tonzeile-h) + 18px);
  display: flex; align-items: center; gap: 10px;
  /* Über der Reihe, nicht in ihr: Hier darf die Blase breiter werden als ein
     Viertel, weil auf dieser Höhe weder Auslöser noch Sprechtaste liegen. */
  max-width: min(calc(100vw - 92px), 400px);
  background: #000c; border: 1px solid #4aa8ff4d; backdrop-filter: blur(10px);
  border-radius: 999px; padding: 7px 15px;
  box-shadow: 0 8px 28px #0008;
  animation: auftauchen .2s ease;
}
.sprecher[hidden] { display: none; }
/* Zwei Zeilen in einer Spalte, damit der lange Satz den Namen nicht
   wegdrückt. `min-width: 0` ist die Bedingung dafür, dass die Ellipse
   überhaupt greift — ohne sie wächst die Zeile aus der Leiste heraus. */

/* Der Satz wird **ganz** gezeigt. Bis zum 2026-08-08 stand er einzeilig und
   abgeschnitten; den Platz dafür liefert der weggefallene Name. Drei Zeilen
   sind die Grenze — darüber deckte die Blase den Inhalt zu, den sie erklärt. */
.sprecher .satz {
  font-size: 12px; color: var(--fg); line-height: 1.35;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
}

/* Das Band „Gespräch mit …" ist am 2026-08-09 entfallen. Stefan: „Aktives
   Gespräch ist angezeigt durch diesen fucking Button. Wir müssen nicht nochmal
   was drüberschreiben." Die Gesichter stehen groß in der Tonecke — ein Band
   darüber war eine zweite Anzeige derselben Sache.

/* Ein Eintrag mit Bild in einem Blatt — für die Coach-Auswahl. */
.wahl.mitBild { display: flex; align-items: center; gap: 10px; }
.wahl.mitBild .avatar { width: 30px; height: 30px; font-size: 12px; flex: none; }
.wahl.mitBild[aria-pressed="true"] { border-color: var(--ok); }

/* Lautstärke, Ruhe, Pause. Unten links unter dem Sprecher, in Daumenreichweite
   — sie standen bis zum 2026-08-08 oben in der Kopfzeile, wo „Ruhe aus" wie
   ein Schalter aussah und das Einstellungsblatt öffnete.
   Sie stehen immer da, auch wenn niemand spricht: Ihre Stelle soll gelernt
   werden, und ein Knopf, der wandert, wird nie gefunden. */
.tonzeile {
  position: fixed; z-index: 6;
  left: 6px; bottom: calc(var(--leiste-h) + 12px);
  /* **Ein Viertel, nicht mehr.** Die untere Reihe ist in vier Teile geteilt:
     links die Tongriffe, rechts die Sprechtaste, die Hälfte dazwischen gehört
     dem Bereich — im Kamerabereich dem Auslöser. Bis zum 2026-08-08 nahm der
     Block „100 %, Ruhe, Pause" über die halbe Breite und ragte in die
     Kamera-Knöpfe. Die Aufteilung hält nur, wenn die Ecken sich an ihr
     Viertel halten, deshalb steht die Grenze hier und nicht im Inhalt. */
  /* Drei gleich große Kreise, die zusammen ins Viertel passen — auf einem
     375er 27 px, auf einem 360er 26. Berechnet statt geraten, sonst bricht
     die Reihe auf schmalen Geräten um und die Ecke wird doppelt so hoch. */
  --eckKnopf: min(30px, calc((25vw - 14px) / 2));
  --eckGesicht: min(46px, calc(25vw - 14px));
  width: calc(25vw - 8px);
  display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
}
/* **Das Gesicht mittig über die zwei Knöpfe.** Gemessen am 2026-08-09: Das
   Gesicht saß bei Mitte 29, die beiden Knöpfe darunter bei Mitte 38 — neun
   Pixel Versatz, genug, dass es schief aussieht, zu wenig, um es zu benennen.
   Stefan hat es benannt.

   Gerechnet statt eingetragen: Beide Maße hängen an der Bildschirmbreite, ein
   fester Wert stimmte nur auf einem Gerät. Die Knopfreihe ist zwei Knöpfe plus
   4 px Abstand breit; die halbe Differenz ist der Versatz. `max(0px, …)` für
   den Fall, dass das Gesicht auf einem schmalen Gerät breiter wäre als die
   Reihe — dann bleibt es links stehen statt nach außen zu rutschen. */
.tonzeile .zieleKnopf {
  margin-left: max(0px, calc((2 * var(--eckKnopf) + 4px - var(--eckGesicht)) / 2));
}
/* Gesicht groß oben, die beiden Knöpfe darunter — dieselbe Fläche wie die
   Sprechtaste gegenüber, nur besser genutzt. Bis zum 2026-08-08 stand das
   Gesicht klein neben den Knöpfen und war kaum zu erkennen.

   **Die Knöpfe tragen einen kräftigen Rand.** Über dem Sucherbild sind sie
   sonst nicht zu sehen — Stefan: „Wenn zum Beispiel Kamera da ist, habe ich
   die Buttons gar nicht gesehen." Ein Knopf, den man nur auf dunklem Grund
   findet, ist auf hellem keiner. */
/* Doppelt qualifiziert: `.avatar` bringt eigene Maße mit und steht später im
   Stylesheet — eine einklassige Regel verlöre gegen sie, und das Bild wäre
   größer als die Knöpfe daneben. */
.tonKnoepfe { display: flex; gap: 4px; }
.tonzeile .tonBtn.rund {
  width: var(--eckKnopf); height: var(--eckKnopf);
  padding: 0; border-radius: 50%;
  border: 2px solid #ffffff5c; background: #000c; backdrop-filter: blur(8px);
  box-shadow: 0 2px 10px #000a;
  display: grid; place-items: center; font-size: 14px;
}
.tonzeile .tonBtn.an { border-color: var(--warn); color: var(--warn); }

/* Das große Gesicht. Mehrere Ziele liegen gestapelt übereinander — die Breite
   bleibt gleich, egal wie viele es sind, und nur so hält das Viertel. */
.zieleKnopf {
  appearance: none; border: 0; background: transparent; padding: 0;
  position: relative; display: block;
  width: var(--eckGesicht); height: var(--eckGesicht);
}
.zieleKnopf .av {
  position: absolute; inset: 0;
  border-radius: 50%; overflow: hidden;
  border: 2px solid #ffffff5c; box-shadow: 0 2px 10px #000a;
  display: grid; place-items: center;
  background: var(--farbe, var(--coach-unbekannt));
  font: 700 15px/1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: #fff;
}
.zieleKnopf .av img { width: 100%; height: 100%; object-fit: cover; display: block; }
.zieleKnopf .av i { font-style: normal; }
/* Der Stapel: jedes weitere Gesicht ein Stück versetzt, damit man sieht, dass
   es mehrere sind, ohne dass die Ecke breiter wird. */
.zieleKnopf .av:nth-child(2) { transform: translate(5px, 5px) scale(.72); }
.zieleKnopf .av:nth-child(3) { transform: translate(10px, 10px) scale(.56); }
.zieleKnopf .av:nth-child(4) { transform: translate(14px, 14px) scale(.44); }
.zieleKnopf.imGespraech .av:first-child { border-color: var(--ok); }
/* Ohne Gespräch und ohne Sprecher tritt es zurück, verschwindet aber nicht —
   ein Loch ließe die Knöpfe darunter bei jedem Satz springen. */
.zieleKnopf.still { opacity: .45; }
.tonBtn {
  appearance: none; border: 1px solid #ffffff2e; background: #ffffff14;
  color: var(--fg); border-radius: 999px;
  padding: 7px 13px; font-size: 12px; font-weight: 600; white-space: nowrap;
  transition: transform .1s ease, background .15s ease;
}
.tonBtn:active { transform: scale(.93); }
/* "Ruhe" ohne Ton wäre ein Knopf, der nichts tut. Er bleibt sichtbar, damit
   seine Stelle gelernt wird — blass genug, um nicht danach zu greifen. */
.tonBtn:disabled { opacity: .3; }
/* Ruhe ist der Abbruch — dieselbe Sprache wie überall in dieser Oberfläche,
   aber nur als Kontur: Es ist kein gefährlicher Knopf, nur ein endgültiger. */
.tonBtn.ruhe { border-color: #ff5c5c66; color: #ffbdbd; }
.tonBtn.laut { background: #0009; backdrop-filter: blur(8px); }
.tonBtn.laut b { color: var(--fg); font-variant-numeric: tabular-nums; }
/* Pausiert ist ein Zustand, kein Vorgang — er trägt Farbe, solange er gilt. */
.tonBtn.pause.an { background: var(--warn); color: #2a1a00; border-color: transparent; }

/* Pausiert: die Blase bleibt stehen, auch wenn niemand spricht — sonst wäre
   der einzige Hinweis auf die Stille die Stille selbst. */
.sprecher.pausiert { border-color: #ffb02059; }
.sprecher.pausiert .satz { color: var(--warn); }
.sprecher.pausiert .welle i { background: var(--warn); }
/* Rederecht: Er ist dran, sagt aber noch nichts. Gedämpft, weil es eine
   Ankündigung ist und keine Stimme — eine Welle darüber wäre eine Lüge. */
.sprecher.rederecht { border-color: #ffffff2e; }
.sprecher.rederecht .satz { color: var(--muted); }

/* Der Ton ist noch nicht freigegeben. Dann ist die ganze Leiste der Knopf:
   Ein Browser spielt ohne Fingergeste nichts ab, und was fehlt, ist genau
   eine Berührung — die soll man nicht suchen müssen. */
.sprecher.antippen { border-color: #ffb020a6; cursor: pointer; }
.sprecher.antippen .satz { color: var(--warn); }

/* Vier Balken, die im Takt springen — zeigt, dass gerade Ton läuft, auch
   wenn Stefan das Handy nicht am Ohr hat. Sie stehen still, solange nichts
   gespielt wird: eine Welle über der Stille wäre eine Lüge. */
.welle { display: flex; align-items: center; gap: 2px; height: 16px; flex: 0 0 auto; }
.welle i {
  display: block; width: 3px; height: 100%; border-radius: 2px;
  background: var(--talk);
  animation: welle .9s ease-in-out infinite;
  animation-play-state: paused; opacity: .3; transform: scaleY(.28);
}
.sprecher.spricht .welle i { animation-play-state: running; opacity: 1; }
.welle i:nth-child(2) { animation-delay: .15s; }
.welle i:nth-child(3) { animation-delay: .3s; }
.welle i:nth-child(4) { animation-delay: .45s; }
@keyframes welle {
  0%, 100% { transform: scaleY(.3); }
  50%      { transform: scaleY(1); }
}

/* Kein Kamerabild — dann ist die leere Fläche die Auskunft. Ein Fehlerdialog
   über allem hätte hier nichts zu suchen: Die Seite arbeitet weiter, nur eben
   als Lautsprecher. Was fehlt, steht ruhig in der Mitte, statt sich als
   Störung aufzuführen.

   Der Grund ist absichtlich klein und der ausführliche Text hinter „Warum?"
   versteckt. Wer die Seite als Kopfhörer benutzt, will nicht jedes Mal lesen,
   welchen Chrome-Dialog er vor zwei Wochen weggewischt hat. */
/* Liegt im Kamerabereich, nicht über der ganzen Seite: Kopfzeile und
   Symbolleiste bleiben bedienbar, während die Kamera klemmt. */
.ohneKamera {
  position: absolute; inset: 0; z-index: 1;
  display: grid; place-content: center; justify-items: center; gap: 7px;
  padding: 24px; text-align: center; pointer-events: none;
  background: radial-gradient(120% 80% at 50% 42%, #141b25 0%, #0b0d10 72%);
}
.ohneKamera[hidden] { display: none; }
.ohneKamera .zeichen {
  font-size: 42px; opacity: .9; filter: drop-shadow(0 6px 18px #000a);
  margin-bottom: 2px;
}
.ohneKamera b { font-size: 16px; font-weight: 600; }
.ohneKamera .warum { font-size: 13px; color: var(--muted); max-width: 32ch; }
.ohneKamera .knoepfe { display: flex; gap: 18px; pointer-events: auto; margin-top: 4px; }
/* .text ist sonst eine Zeile über die ganze Breite — hier stehen zwei
   nebeneinander. */
.ohneKamera .knoepfe .text { width: auto; }
.ohneKamera .knoepfe .leise { color: #6c7683; }

/* Blass wird der Auslöser nur im **Fehlerfall**. Im Ruhezustand ist er der
   normale Weg zum Bild — er startet die Kamera und löst aus. Ihn dort
   auszugrauen hieße zu behaupten, es ginge nichts, obwohl alles geht. */
body.kamera-fehler .shutter,
body.kamera-fehler #flipBtn { opacity: .3; }


/* Sprechtaste: die Gegenrichtung zur Sprachausgabe. Rund, unten rechts, in
   **jedem** Bereich an derselben Stelle — dort, wo der Daumen beim Halten des
   Geräts ohnehin liegt. Sie muss blind zu treffen sein: Das Handy ist dabei in
   der Hand oder in der Tasche, nicht vor dem Gesicht.

   Im Kamerabereich sitzt sie rechts neben dem Auslöser, auf gleicher Höhe.
   Damit behält die Kamera ihren gewohnten Aufbau, und die Sprechtaste bleibt
   trotzdem dort, wo sie in den anderen drei Bereichen steht.

   Die frühere Fassung lief über die volle Breite. Das war richtig, solange die
   Seite nur Kamera war und die Taste ein Anbau; mit vier Bereichen wäre ein
   Balken über der Symbolleiste in jedem von ihnen im Weg. */
.sprechen {
  position: fixed; z-index: 7;
  right: 16px; bottom: calc(var(--leiste-h) + 14px);
  width: 66px; height: 66px; padding: 0;
  appearance: none; border: 1px solid #ffffff33; background: #000a;
  backdrop-filter: blur(8px); color: var(--fg);
  border-radius: 50%;
  display: grid; place-items: center;
  box-shadow: 0 6px 20px #0007;
  /* Ohne das macht Android aus dem langen Druck eine Textauswahl oder ein
     Kontextmenü — und lässt dabei die Aufnahme fallen. */
  touch-action: none; user-select: none; -webkit-user-select: none;
  transition: background .15s ease, border-color .15s ease, transform .08s ease;
}
.sprechen .ico { font-size: 26px; line-height: 1; }
.sprechen:active { transform: scale(.94); }

/* Was die Taste früher als Beschriftung trug, steht jetzt daneben — und nur,
   solange es etwas zu sagen gibt. Ein runder Knopf mit Mikrofonzeichen
   erklärt sich; „Halten und sprechen" muss nicht den ganzen Tag dastehen. */
/* Der Ring trägt den Zustand. Er liegt als eigene Fläche über der Taste,
   damit der Pegel ihn aufblähen kann, ohne die Trefferfläche zu bewegen —
   ein Knopf, der unter dem Finger wandert, wird beim Halten losgelassen. */
.sprechen .ring {
  position: absolute; inset: -3px; border-radius: 50%;
  border: 2px solid transparent;
  transition: border-color .15s ease, box-shadow .07s linear;
  pointer-events: none;
}
.sprechen .dauer {
  position: absolute; bottom: 9px; left: 0; right: 0;
  font: 700 10px/1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-variant-numeric: tabular-nums; color: var(--talk);
}
.sprechen .dauer[hidden] { display: none; }
/* Die Zeit rückt das Zeichen ein Stück hoch, statt es zu überschreiben. */
.sprechen.an .ico { transform: translateY(-6px); }

/* Hört zu. Der Ring pulst mit dem Pegel: `--pegel` läuft von 0 bis 1 und
   kommt aus der Messung des Mikrofons. Ein stiller Ring bei laufender
   Aufnahme ist die einzige Anzeige, an der „das Handy hört dich nicht"
   überhaupt auffällt — deshalb ist er an den Ton gekoppelt und nicht an
   einen Zeittakt, der auch bei totem Mikrofon weiterliefe. */
body.spricht .sprechen {
  border-color: var(--talk); background: #06263fdd; color: #fff;
}
body.spricht .sprechen .ring {
  border-color: var(--talk);
  box-shadow: 0 0 0 calc(var(--pegel, 0) * 10px) rgba(74, 168, 255, .18);
}

/* Die drei Ausgänge. Sendet gelb, angekommen grün, abgewiesen rot — dieselbe
   Sprache wie überall in dieser Oberfläche. Vibration und Ton sagen dasselbe;
   Farbe allein wäre die halbe Antwort, wenn er nicht hinsieht. */
.sprechen.sendet .ring { border-color: var(--warn); }
.sprechen.fertig .ring { border-color: var(--ok); }
.sprechen.fehler .ring { border-color: var(--bad); }
.sprechen.sendet { border-color: var(--warn); }
.sprechen.fertig { border-color: var(--ok); }
.sprechen.fehler { border-color: var(--bad); background: #1a0b0be6; }

/* Meldungen liegen über allen Hinweisbändern. Am 2026-08-08 lag das
   Baustellen-Band (z-index 6) über der Absage einer Sprachaufnahme (damals 5):
   Die Seite hatte den Grund gesagt, und er war nicht zu lesen. Eine Meldung,
   die etwas erklärt, ist wertlos, wenn ein Dauerhinweis sie zudeckt — also
   steht sie auch über den Blättern (z-index 9). Nur die Aufhellung (20) bleibt
   darüber; die ist Licht, keine Anzeige. Das `top` setzt `toast()` selbst,
   gemessen an den Bändern, die gerade stehen. */
/* Mittig über `margin: auto`, nicht über `translateX(-50%)`: Mit `left: 50%`
   steht dem Kasten nur die halbe Bildschirmbreite zur Verfügung, und ein
   mehrzeiliger Text bricht dann mitten im Wort um, obwohl daneben Platz ist.
   Bei der einzeiligen Pille fiel das nie auf. */
.toast {
  position: fixed; top: calc(var(--kopf-h) + 6px); left: 0; right: 0;
  margin: 0 auto; width: fit-content;
  z-index: 12; max-width: 88vw;
  background: #000c; border: 1px solid #ffffff2e; backdrop-filter: blur(8px);
  padding: 9px 15px; border-radius: 999px; font-size: 13px;
}

/* Eine Absage sagt, was zu tun ist — das sind zwei, drei Zeilen, und die
   passen in keine Pille. Rot wie alles Abweisende in dieser Oberfläche, mit
   ruhigem Rand statt Füllung: Es ist eine Auskunft, kein Alarm. */
.toast.fehler {
  max-width: min(92vw, 420px);
  border-radius: 14px; border-color: #ff5c5c8c;
  background: #1a0b0be6; box-shadow: 0 8px 28px #0009;
  padding: 12px 16px; line-height: 1.45; text-align: left;
}

/* Letzte Aufnahme samt Bewertung — bleibt stehen, bis die nächste kommt.
   Die Stufe steckt im Rahmen des Vorschaubilds, der Ablageort liegt darauf. */
/* Unten links in der Dreh-Schicht. Der Abstand hält sie von der
   Bedienleiste frei, ohne dass sie beim Warten verschoben werden müsste —
   die Auftragskarte sitzt jetzt oben und kommt ihr nicht mehr ins Gehege. */
/* Der Abstand nach unten deckt Bedienleiste *und* Sprechtaste ab. Er wuchs
   mit der Taste mit — sonst läge die Vorschau darauf, und ein blind
   gesuchter Knopf, der halb unter einer Karte liegt, ist keiner mehr. */
.last {
  /* Über der linken Ecke, gemessen statt geraten. Die 174 px stammten aus der
     Zeit, als die Kamera-Schalter unten standen; seit sie oben sitzen, hing
     die Vorschau in der Luft. `--eckzeile-h` misst, wie hoch die Ecke gerade
     wirklich baut — mit Sprecherblase mehr als ohne. */
  position: absolute; left: 12px; bottom: calc(var(--leiste-h) + var(--eckzeile-h) + 14px);
  display: flex; align-items: center; gap: 7px;
  background: #000a; border: 1px solid #ffffff1f; backdrop-filter: blur(8px);
  border-radius: 12px; padding: 6px; width: fit-content;
  transition: left .25s ease, right .25s ease, bottom .25s ease;
}
/* Quer gehalten liegt die Bedienleiste an der Seite statt unten — der große
   Abstand nach unten wird dann nicht mehr gebraucht. Die Ecke bleibt links
   unten, damit die Vorschau immer an derselben Stelle steht. */
/* Quer liegt die Bedienleiste an der Seite, die in der gedrehten Schicht
   "unten links" ist. Der Abstand entspricht ihrer Höhe, sonst überlappt die
   Vorschau die Schalter. */
/* Die beiden Querlagen sind nicht spiegelgleich, und genau daran ist die
   Vorschau zweimal gescheitert. Bei gesperrter Bildschirmdrehung bleibt die
   Bedienung physisch, wo sie ist; die gedrehte Schicht schiebt ihre eigene
   linke Kante aber je nach Winkel woandershin:

     90°  — „links" liegt physisch **oben**: dort stehen seit dem Umbau die
            Kamera-Schalter, nicht mehr nur die schmale Kopfzeile. Der alte
            Wert von 62 px stammt aus der Zeit davor und schob die Vorschau
            zu weit nach rechts.
     270° — „links" liegt physisch **unten**: dort stehen die Ecke und der
            Auslöser. Derselbe Abstand wie im Hochformat.

   Beide Werte sind jetzt gerechnet statt geraten — feste Zahlen haben den
   nächsten Umbau noch nie überlebt. */
body[data-dreh="90"]  .last { left: calc(var(--kopf-h) + 88px); bottom: 24px; }
body[data-dreh="270"] .last { left: calc(var(--leiste-h) + var(--eckzeile-h) + 16px); bottom: 24px; }
.last img {
  width: 58px; height: 58px; object-fit: cover; display: block; flex: none;
  border-radius: 8px; background: #222; border: 2px solid var(--muted);
}
.last.normal img   { border-color: var(--ok); }
.last.sexy img     { border-color: var(--warn); }
.last.explizit img { border-color: var(--bad); }

/* Während Aufbereitung, Übertragung und Prüfung: pulsierender Rahmen, damit
   erkennbar ist, dass noch gearbeitet wird. Bei voller Auflösung vergehen
   zwischen Auslösen und Ergebnis mehrere Sekunden. */
.last.laeuft img { border-color: var(--muted); animation: arbeitet 1.1s ease-in-out infinite; }
.last.laeuft .zahl { color: var(--fg); font-weight: 500; }
@keyframes arbeitet {
  0%, 100% { opacity: 1; }
  50%      { opacity: .45; }
}
/* Wer das Bild veranlasst hat, steht oben — bei einer Aufnahme von vor neun
   Minuten ist das die eigentliche Frage. Darunter die Messwerte in einer
   Zeile, darunter der Ablageort. */
.last .urheber {
  font-size: 12px; font-weight: 600; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.last .ort {
  font-size: 10px; color: var(--ok);
  font-family: ui-monospace, Menlo, monospace;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.last.explizit .ort { color: var(--bad); }
.last.sexy .ort { color: var(--warn); }

/* Stufen-Anzeige in der Vorschau. Bewusst ohne Rahmen und Pillenform —
   die sah aus wie ein Schalter und lud zum Drücken ein. */
.badge {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 12px; font-weight: 600; letter-spacing: .01em;
}
.badge .sym { width: 14px; height: 14px; display: grid; place-items: center; flex: none; }
.badge .sym svg { width: 14px; height: 14px; display: block; fill: currentColor; }
.badge b { font-weight: 600; }

.badge.normal   { color: var(--ok); }
.badge.sexy     { color: var(--warn); }
.badge.explizit { color: var(--bad); }

/* Drei Messwerte: Symbol, Name, Prozent. Über der Schwelle wird die Zeile
   farbig und fett — darunter bleibt sie gedämpft. */
.last .rechts { display: grid; gap: 1px; padding-right: 2px; }
/* Messwerte und Alter teilen sich eine Zeile. Das Alter steht hinter den
   Symbolen, wo Platz frei ist, statt eine eigene Zeile zu belegen.
   Alle drei Angaben sind gleich groß und stehen auf einer Linie: vorher
   hatten sie verschiedene Schriftgrößen und wurden an der Grundlinie
   ausgerichtet — mit Symbolen dazwischen wird daraus ein Auf und Ab. */
.last .zeile { display: flex; align-items: center; gap: 8px; line-height: 1; }
.last .alter {
  font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums;
  white-space: nowrap; margin-left: auto; line-height: 1;
}

/* Messwerte nebeneinander statt untereinander: Sie sind gleichrangig, und
   die Zeile darüber und darunter — wer und wohin — braucht den Platz. */
.werte { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; line-height: 1; }
.wert {
  display: flex; align-items: center; gap: 3px;
  font-size: 11px; line-height: 1; color: var(--muted);
}
.wert svg { width: 12px; height: 12px; display: block; fill: currentColor; opacity: .8; flex: none; }
.wert .zahl { font-variant-numeric: tabular-nums; font-weight: 600; line-height: 1; }

.wert.aktiv { color: currentColor; font-weight: 600; }
.wert.aktiv svg { opacity: 1; }
.wert.aktiv.sexy { color: var(--warn); }
.wert.aktiv.porn, .wert.aktiv.hentai { color: var(--bad); }

.overlay {
  position: fixed; inset: 0; z-index: 9; display: grid; place-items: center;
  background: #0b0d10ee; padding: 24px;
}
/* Muss nach .overlay stehen: sonst gewinnt display:grid gegen das
   [hidden]-Attribut und beide Overlays liegen sichtbar übereinander. */
.overlay[hidden] { display: none; }
/* Querformat auf einem flachen Bildschirm. Kopfzeile und Symbolleiste bleiben,
   wo sie sind — der Wechsel zwischen den Bereichen darf nicht davon abhängen,
   wie das Gerät gehalten wird —, aber beide werden flacher, und die
   Zustandszeile entfällt: Bei 400 px Höhe ist jede Zeile, die nichts tut, eine
   zu viel. Die Auftragskarte wandert in die Mitte, weil oben kein Platz mehr
   für sie ist. */
@media (orientation: landscape) and (max-height: 500px) {
  :root {
    --kopf-h: calc(30px + env(safe-area-inset-top));
    --leiste-h: calc(46px + env(safe-area-inset-bottom));
  }
  /* Die Kopfzeile bleibt stehen — sie ist jetzt eine Zeile, und mit ihr
     verschwänden Uhr, Vollbild und Zahnrad. Weg fällt nur der Sprecher, denn
     quer ist unten links kein Platz neben Tongriffen und Bildvorschau. */
  .sprecher { display: none; }
  .kamerazeile { bottom: calc(var(--leiste-h) + 78px); }
  .auftrag {
    position: fixed; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    max-width: min(340px, 58vw);
  }
  .last {
    left: 12px; bottom: calc(var(--leiste-h) + 8px);
    max-width: calc(100vw - 200px);
  }
  body.erwartet .last { bottom: calc(var(--leiste-h) + 8px); }
}

/* Beurteilung eines automatisch gesperrten Bildes. Es wird groß gezeigt —
   die Frage lässt sich nur am Bild beantworten, nicht an Messwerten. */
.pruefbild {
  display: block; width: 100%; max-height: 46vh; object-fit: contain;
  border-radius: 10px; background: #000; margin-bottom: 12px;
  border: 2px solid var(--bad);
}
.pruef-knoepfe { display: grid; gap: 4px; }
.pruef-knoepfe .primary { background: var(--ok); color: #06301c; }

.overlay .card { max-width: 420px; }

/* Auswahlblätter drehen mit. Quer wird die Bildschirmhöhe zur Breite —
   deshalb dort in vh statt vw messen, sonst wird die Karte zu schmal. */
.overlay .card { transition: transform .25s ease; }
body[data-dreh="90"]  .overlay .card { transform: rotate(90deg); }
body[data-dreh="180"] .overlay .card { transform: rotate(180deg); }
body[data-dreh="270"] .overlay .card { transform: rotate(270deg); }

body[data-dreh="90"]  .card.blatt,
body[data-dreh="270"] .card.blatt { width: min(400px, 88vh); }
body[data-dreh="90"]  .liste,
body[data-dreh="270"] .liste { max-height: 44vw; }
.overlay h1 { font-size: 19px; margin: 0 0 8px; }
.overlay p { color: var(--muted); margin: 0 0 18px; }
.overlay .hint {
  border-left: 3px solid var(--warn); padding-left: 12px;
  color: var(--fg); font-size: 14px;
}
.primary {
  appearance: none; border: 0; border-radius: 10px; padding: 12px 18px;
  background: var(--fg); color: #0b0d10; font-weight: 600; font-size: 15px;
}

/* Ordnerauswahl: bereits benutzte Themen antippen statt abtippen. */
.card.blatt { width: min(400px, 88vw); }
.card.blatt h1 { margin-bottom: 14px; }
.card.blatt h2 {
  font-size: 12px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); margin: 0 0 8px;
}

.liste { display: grid; gap: 6px; max-height: 46vh; overflow-y: auto; margin-bottom: 14px; }
.liste .eintrag {
  appearance: none; width: 100%; text-align: left;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  border: 1px solid #ffffff24; background: #ffffff0f; color: var(--fg);
  border-radius: 10px; padding: 12px 14px; font-size: 15px;
}
.liste .eintrag:active { background: #ffffff24; }
.liste .eintrag.aktiv { border-color: var(--ok); color: var(--ok); font-weight: 600; }
.liste .eintrag .zahl { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.liste .eintrag.aktiv .zahl { color: var(--ok); }
.liste .leer { color: var(--muted); font-size: 13px; padding: 4px 2px; }

.neu { display: flex; gap: 8px; margin-bottom: 6px; }
.neu input {
  flex: 1; min-width: 0; appearance: none;
  border: 1px solid #ffffff2e; background: #0006; color: var(--fg);
  border-radius: 10px; padding: 12px 14px; font-size: 15px;
}
.neu input:focus { outline: none; border-color: var(--fg); }

.text {
  appearance: none; border: 0; background: transparent; color: var(--muted);
  font-size: 14px; padding: 10px 0; width: 100%;
}

/* ── Absender: Bild oder Initiale, in der Farbe des Coaches ─────────────────
   Bei sieben Coaches ist der Name allein zu langsam zu lesen. Farbe und
   Gesicht erkennt man beim Hinsehen, den Namen erst beim Lesen — und auf ein
   Handy in der Hand sieht man kurz, nicht lange.

   Die Farbe ist dieselbe wie im Dashboard. Wer beide Bildschirme benutzt,
   soll nicht zweierlei lernen. Fehlt ein Portrait, steht die Initiale da:
   ein leerer Kreis wäre die schlechtere Auskunft als ein Buchstabe. */
.avatar {
  position: relative; flex: none;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; overflow: hidden;
  background: color-mix(in srgb, var(--farbe, var(--coach-unbekannt)) 20%, transparent);
  border: 1px solid color-mix(in srgb, var(--farbe, var(--coach-unbekannt)) 60%, transparent);
  color: var(--farbe, var(--coach-unbekannt));
  font-size: 13px; font-weight: 700; font-style: normal;
}
.avatar.gross { width: 38px; height: 38px; font-size: 15px; }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar i { font-style: normal; }

/* ── Aufgaben ─────────────────────────────────────────────────────────────
   Was ansteht, gelesen vom Board des Dashboards. Nur lesend: Gestartet wird
   eine Aufgabe von Stefan, und wo er das tut, entscheidet nicht diese Seite. */
/* `minmax(0, 1fr)` statt der Vorgabe: Ohne das bemisst sich die Spalte am
   breitesten Inhalt, und eine Zeile mit langem Titel schiebt alle anderen aus
   dem Bild. Die Null ist der Punkt — sie erlaubt dem Inhalt zu schrumpfen. */
.karten {
  flex: 1; overflow-y: auto; padding: 0 12px 14px;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 0;
  align-content: start;
}
/* ── Kurze Fragen ────────────────────────────────────────────────────────
   Hier sind es Karten und keine Zeilen, anders als bei den Aufgaben: Eine
   Aufgabe wird überflogen, eine Frage wird beantwortet. Sie braucht Platz für
   das Artefakt und für Knöpfe, die man im Gehen trifft. */
/* Zeichen in der Aufgabenzeile, dass ein Dokument daranhängt. Nur das
   Zeichen — der Inhalt kommt beim Aufklappen. */
.aufgabenZeile .hatDoku { color: var(--talk); font-size: 12px; flex: none; }
/* Das zweite Gesicht: der Ansprechpartner, wenn er nicht der Besitzer ist.
   Kleiner als der Farbbalken links — es ist die Ausnahme, nicht die Hauptsache. */
.aufgabenZeile .avatar.ansprech {
  width: 18px; height: 18px; border-radius: 50%; flex: none; font-size: 9px;
  display: inline-flex; align-items: center; justify-content: center;
  overflow: hidden; border: 1px solid #ffffff2e;
}
.aufgabenZeile .ansprechZeile,
.aufgabenZeile .coachZeile { display: none; }
.aufgabenZeile.offen .ansprechZeile,
.aufgabenZeile.offen .coachZeile {
  display: block; flex-basis: 100%; margin-top: 4px;
  font-size: 11.5px; color: var(--muted);
}
.aufgabenZeile .dokument { display: none; }
.aufgabenZeile.offen .dokument { display: block; flex-basis: 100%; margin-top: 6px; }
.aufgabenZeile .dokuTitel { display: block; font-size: 12px; margin-bottom: 4px; }
.aufgabenZeile .dokuStern { display: flex; justify-content: center; margin-top: 10px; }

.fragenKopf {
  margin: 6px 2px 2px; font-size: 12px; color: var(--muted);
}
.frageKarte {
  border-left: 3px solid var(--farbe, var(--talk));
  background: #ffffff08; border-radius: 10px;
  margin: 8px 0; padding: 10px 11px;
}
.frageKarte .kopf {
  display: flex; align-items: center; gap: 7px; font-size: 12px;
}
.frageKarte .kopf .avatar {
  width: 21px; height: 21px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; overflow: hidden;
}
.frageKarte .kopf .alter { margin-left: auto; color: var(--muted); font-size: 11px; }
/* „kommt nicht weiter" steht neben dem Namen, nicht als Farbe der ganzen
   Karte: Es erklärt die Reihenfolge, es soll nicht drängen. */
.frageKarte .kopf .haelt {
  font-size: 10px; color: var(--warn); border: 1px solid #ffb02055;
  border-radius: 999px; padding: 1px 7px; white-space: nowrap;
}
.frageKarte .frageTitel { margin-top: 6px; font-size: 13.5px; line-height: 1.35; }
.frageKarte.zu { padding-bottom: 8px; opacity: .72; }

/* **Die ganze Höhe, nicht die halbe.** Stefan am 2026-08-09: „Zudem in diesem
   Fragezeichen-Ding, das ist nur halb gefüllt. Wir können die volle Höhe hier
   nutzen. Bis unter den Mikrofon-Button."

   Vorher `46vh` — gedacht, damit eine Karte nicht die ganze Liste verdrängt.
   Bei zwei Zeilen Text ist das egal, bei einem Artefakt von zweitausend
   Zeichen ist es die Hälfte des Bildschirms zu wenig. Der Rest der Karte
   (Kopf, Titel, Knöpfe) braucht rund 150 px; alles darüber gehört dem Inhalt,
   und die Fläche endet ohnehin über der Tonecke. */
.artefakt {
  margin-top: 9px; padding: 9px 10px; border-radius: 9px;
  border: 1px solid #ffffff1f; background: #ffffff08;
  font-size: 12.5px; line-height: 1.5;
  max-height: calc(100vh - var(--kopf-h) - var(--leiste-h) - var(--eckzeile-h) - 150px);
  overflow-y: auto;
}
.artefakt b { display: block; margin: 4px 0 2px; }
.artefakt .zeile { display: block; color: #cdd4de; }
.artefakt ul { margin: 4px 0; padding-left: 18px; color: #cdd4de; }
.artefakt code { background: #ffffff14; padding: 1px 4px; border-radius: 4px; font-size: .92em; }
.artefakt img { display: block; max-width: 100%; height: auto; border-radius: 6px; }
/* Fremdes HTML läuft abgeriegelt: kein Skript, kein Zugriff auf diese Seite,
   und damit kein Weg an den Zugangstoken in der Adresszeile. */
.artefakt iframe.fremd {
  width: 100%; min-height: 140px; border: 0; background: #fff; border-radius: 6px;
}

/* **Der Fußbereich, von unten gelesen.** Die unterste Zeile gehört dem Stern
   allein; Knöpfe wachsen nach oben. So sitzt er in jeder Fragenart an
   derselben Stelle — beim Sprechen sucht man nicht, man tippt hin, wo es
   letztes Mal war. */
.frageFuss { margin-top: 11px; }
.frageZeile { display: flex; gap: 9px; margin-bottom: 8px; }
.frageSternZeile { display: flex; justify-content: center; }
.frageKn {
  appearance: none; flex: 1; padding: 11px 0; border-radius: 10px;
  border: 1px solid #ffffff2e; background: transparent; color: var(--muted);
  font: inherit; font-size: 13px;
}
.frageKn.ja { border-color: var(--ok); color: var(--ok); }
.frageKn.nein { border-color: var(--bad); color: var(--bad); }
.frageKn.weiter { font-size: 12.5px; padding: 9px 0; }
.frageKn:active { background: #ffffff14; }

/* **Der Stern muss anders aussehen als die Sprechtaste unten rechts.** Die
   redet mit dem Gesprächspartner; dieser hier redet mit dem, der gefragt hat.
   Wer den falschen greift, schickt seine Antwort an jemanden, der die Frage
   nie gestellt hat — deshalb runde Form, eigene Farbe und der Empfänger als
   Beschriftung darunter. */
.frageStern {
  appearance: none; flex: none; width: 62px; height: 62px; border-radius: 50%;
  border: 2px solid var(--stern); background: #c99bff14; color: var(--stern);
  display: grid; place-items: center; gap: 0; padding: 0; font: inherit;
  touch-action: none;
}
.frageStern .ico { font-size: 20px; line-height: 1; }
.frageStern .wem { font-size: 8.5px; line-height: 1.1; max-width: 56px; overflow: hidden; }
.frageStern:active { background: #c99bff33; transform: scale(.96); }
body.spricht .frageStern { border-color: var(--bad); color: var(--bad); background: #ff5c5c22; }

/* Gewischt wird nur im Artefakt — waagerecht, ohne dass der Browser daraus
   ein Scrollen macht. */
.frageKarte .artefakt { touch-action: pan-y; }

.frageKlein { display: flex; gap: 16px; margin-top: 9px; }
.frageKleinKn {
  appearance: none; border: 0; background: transparent; padding: 4px 0;
  color: var(--muted); font: inherit; font-size: 11.5px;
  border-bottom: 1px dotted #ffffff33;
}
.frageKarte .unterwegs { margin: 10px 0 2px; font-size: 12px; color: var(--talk); }

/* Zeilen statt Karten — dieselbe Form wie im Brett, nur schmaler. Eine Karte
   je Aufgabe zeigte vier auf einem Bildschirm; eine Zeile zeigt zehn, und die
   Frage „was steht an" beantwortet sich beim Hinsehen statt beim Scrollen. */
/* Bewusst flex und nicht grid: Mit Raster musste jede Spalte vorher benannt
   sein, und ein Element mehr — das „läuft" — schob die Zeile in drei Reihen.
   Eine Zeile, die je nach Inhalt ihre Form ändert, ist keine Zeile. */
.aufgabenZeile {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 4px; border-bottom: 1px solid #ffffff10;
  font-size: 13px;
}
.aufgabenZeile .w, .aufgabenZeile .u {
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: 11px;
  text-align: center; border-radius: 5px; padding: 2px 0;
}
.aufgabenZeile .w { background: #ffffff14; color: var(--muted); min-width: 18px; flex: none; }
.aufgabenZeile .u { min-width: 14px; flex: none; }
.aufgabenZeile .w4, .aufgabenZeile .w5 { background: #4aa8ff2e; color: #b9dcff; }
/* Dringlichkeit trägt Farbe erst, wenn sie etwas bedeutet. Überfällig ist
   eine eigene Klasse, kein weiterer Schritt — dieselbe Entscheidung wie im
   Rangmodell des Bretts. */
.aufgabenZeile .u { color: var(--warn); background: #ffb0201f; }
.aufgabenZeile .u9 { color: var(--bad); background: #ff5c5c26; }
.aufgabenZeile .u.leer { background: none; }
.aufgabenZeile .coachbar { width: 4px; height: 22px; border-radius: 2px; flex: none; }
/* Der Titel nimmt, was übrig ist, und wird abgeschnitten statt umzubrechen —
   sonst wächst die Zeile, und die Spalten daneben wandern. */
.aufgabenZeile .tt {
  flex: 1 1 0; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Aufgeklappt darf der Titel umbrechen: Dann ist Platz, und der Rest des
   Satzes ist auf einem Gerät ohne Mauszeiger sonst nirgends zu lesen. */
.aufgabenZeile.langerTitel.offen .tt { white-space: normal; overflow: visible; }
.aufgabenZeile .frist { font-size: 11px; color: var(--muted); white-space: nowrap; flex: none; }
.aufgabenZeile .frist.faellig { color: var(--warn); }
.aufgabenZeile .frist.ueberfaellig { color: var(--bad); font-weight: 700; }
.aufgabenZeile .dauer {
  font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums;
  flex: none; min-width: 42px; text-align: right;
}
.aufgabenZeile .laeuftZeichen {
  flex: none; font-size: 10px; font-weight: 700;
  color: var(--ok); text-transform: uppercase; letter-spacing: .05em;
  appearance: none; font: inherit; cursor: pointer;
}
/* Es ist ein Knopf, kein Etikett — wo etwas laeuft, hoert es auch auf. */
.laeuftZeichen:active { opacity: .6; }
.laeuftZeichen:disabled { opacity: .5; }
.aufgabenZeile.laeuft { background: #35d07f0f; }
/* Der nächste Schritt klappt unter der Zeile auf, statt sie zu verbreitern. */
.aufgabenZeile .schritt {
  flex: 1 0 100%; display: none;
  font-size: 12px; color: var(--muted); line-height: 1.35; padding: 2px 0 2px 26px;
}
.aufgabenZeile.offen .schritt { display: block; }
.aufgabenZeile.mitSchritt { cursor: pointer; }

.karte {
  display: flex; gap: 10px; align-items: flex-start;
  border: 1px solid #ffffff1c; border-left: 3px solid var(--farbe, var(--coach-unbekannt));
  background: #ffffff0a; border-radius: 12px; padding: 11px 13px;
}
/* Die laufende Aufgabe hebt sich ab. Sie ist die einzige Zeile, bei der die
   Frage „und woran arbeite ich gerade" schon beantwortet ist. */
.karte.laeuft { background: #ffffff14; border-color: color-mix(in srgb, var(--farbe) 70%, transparent); }
.karte .inhalt { display: grid; gap: 4px; min-width: 0; flex: 1; }
.karte b { font-size: 14.5px; font-weight: 600; line-height: 1.3; }
.karte .meta {
  display: flex; flex-wrap: wrap; gap: 8px;
  font-size: 11.5px; color: var(--muted);
}
.karte .meta .frist.faellig { color: var(--warn); font-weight: 600; }
.karte .meta .frist.ueberfaellig { color: var(--bad); font-weight: 700; }
.karte .meta .laeuft { color: var(--ok); font-weight: 600; }
.karte .schritt { font-size: 12px; color: var(--muted); line-height: 1.35; }

/* ── Chat ─────────────────────────────────────────────────────────────────
   Beide Richtungen mit Absender. Was ein Agent gesprochen hat, steht hier zum
   Nachlesen — eine Stimme in der Hosentasche ist weg, sobald sie zu Ende
   gesprochen hat, und genau dann fragt man sich, was sie gesagt hat. */
.chat {
  flex: 1; overflow-y: auto;
  padding: 12px 12px 14px; display: grid; gap: 12px; align-content: start;
}
.zeile-chat { display: flex; gap: 9px; align-items: flex-start; }
.zeile-chat.selbst { flex-direction: row-reverse; }
.blase { max-width: 76%; display: grid; gap: 3px; min-width: 0; }
.blase .absender {
  font-size: 11px; font-weight: 700; color: var(--farbe, var(--muted));
  display: flex; gap: 7px; align-items: baseline;
}
.blase .zeit { font-weight: 400; color: var(--muted); font-variant-numeric: tabular-nums; }
.blase .satz {
  background: #ffffff12; border: 1px solid #ffffff1a;
  border-radius: 13px; padding: 9px 12px;
  font-size: 14px; line-height: 1.4; overflow-wrap: anywhere;
}
.zeile-chat.selbst .absender { flex-direction: row-reverse; }
.zeile-chat.selbst .satz { background: #0d2c47; border-color: #4aa8ff40; }
/* Eine Sprachaufnahme, deren Text noch nicht vorliegt. Nicht als leerer Satz
   und nicht als Fehler: Sie ist angekommen, nur noch nicht verschriftet. */
.blase .satz.offen { color: var(--muted); font-style: italic; }
.blase .satz.misslungen { border-color: #ff5c5c66; color: #ffbdbd; }

/* ── Die unterste Zeile sind drei Zonen ───────────────────────────────────
   Stefan am 2026-08-09: „Es gibt das linke Viertel, die mittlere Hälfte und
   das rechte Viertel. Die mittlere Hälfte gehört dem Bereich innen. Da soll
   sie hin, ganz unten, wo ein Chat halt hingehört. Da wo bei der Kamera zum
   Beispiel der Kamera-Button ist."

   **Links und rechts gehören der Seite**, in jeder Ansicht an derselben
   Stelle: Tongriffe und Sprechtaste. Ein Knopf, der wandert, wird nie
   gefunden. **Die Mitte gehört dem Bereich** — in der Kamera der Auslöser, im
   Chat die Schreibzeile.

   Die Aufteilung stand bis heute nur als Kommentar an der Tonecke und wurde
   für die Kamera von Hand nachgebaut; der Chat hat sie nie bekommen. Deshalb
   steht sie jetzt als eine Regel da: **Wer einen neuen Bereich baut, setzt
   seinen Griff in `.mitteUnten` und muss über links und rechts nichts
   wissen.** */
.mitteUnten {
  position: fixed; z-index: 6;
  left: 25vw; width: 50vw;
  bottom: calc(var(--leiste-h) + 12px);
  display: flex; align-items: center; justify-content: center;
}

.chatEingabe {
  /* Erbt Lage und Breite von der Zone. Vorher lief die Zeile über die volle
     Breite und lag 138 px über dem Rand — über allem statt in der Mitte.
     Das Feld darin war schon 180 px breit, also fast genau die halbe Breite;
     **es ändert sich die Höhe, nicht die Breite.** */
  gap: 8px;
  padding: 0 0 env(safe-area-inset-bottom);
  background: transparent;
}
.chatEingabe input {
  flex: 1; min-width: 0; appearance: none;
  border: 1px solid #ffffff2e; background: #ffffff0f; color: var(--fg);
  border-radius: 999px; padding: 11px 15px; font-size: 15px;
}
.chatEingabe input:focus { outline: none; border-color: var(--talk); }

/* Der Senden-Knopf legt sich über die Sprechtaste, sobald Text im Feld steht.
   Der Platz ist ohnehin belegt, und mit Text ist Senden das Naheliegende —
   Stefans Vorschlag am 2026-08-08. Ohne Text bleibt die Sprechtaste. */
.senden {
  position: fixed; z-index: 8;
  right: 16px; bottom: calc(var(--leiste-h) + 14px);
  width: 66px; height: 66px; padding: 0; border-radius: 50%;
  appearance: none; border: 2px solid var(--talk); background: #06263fee;
  backdrop-filter: blur(8px); color: #fff;
  display: grid; place-items: center; font-size: 24px;
  box-shadow: 0 6px 20px #0007;
  animation: auftauchen .12s ease;
}
.senden[hidden] { display: none; }
.senden:active { transform: scale(.94); }
/* Solange gesendet werden kann, tritt die Sprechtaste zurück — zwei runde
   Knöpfe übereinander wären ein Knopf zu viel an derselben Stelle. */
body.tippt .sprechen { display: none; }
.senden:disabled { opacity: .35; }

/* ── Status ───────────────────────────────────────────────────────────────
   Absichtlich schlicht: was läuft, was zuletzt ankam, ob die Verbindung
   steht. Geschärft wird er, wenn er benutzt wird — ein Statusbild, das
   niemand angesehen hat, ist noch nicht zu Ende gedacht. */
.zeilen { flex: 1; overflow-y: auto; padding: 0 14px 14px; display: grid; gap: 0; align-content: start; }

/* Die Agenten mit ihren Werten — dasselbe, was im Dashboard auf den
   Coach-Karten steht. Sie stehen oben, die Technik darunter: „Wie steht es"
   wird öfter gefragt als „warum geht etwas nicht". */
.coachKarte {
  border: 1px solid #ffffff14; border-left: 3px solid var(--farbe, var(--muted));
  border-radius: 12px; background: #ffffff08;
  padding: 10px 12px; margin: 8px 0;
  display: grid; gap: 8px;
}
.coachKarte .kopf { display: flex; align-items: center; gap: 9px; }
.coachKarte .kopf b { font-size: 13.5px; font-weight: 700; }
/* „arbeitet" sagt: läuft. Nicht: stimmt etwas nicht. Deshalb dieselbe ruhige
   Farbe wie das Sprechen und keine Warnfarbe. */
.coachKarte .kopf .arbeitet {
  font-size: 10px; color: var(--talk); border: 1px solid #4aa8ff44;
  border-radius: 999px; padding: 1px 7px; white-space: nowrap; margin-left: 6px;
}
/* Hier **mit** Warnfarbe: Das ist keine Verlaufsmeldung, sondern etwas, das
   nicht passiert ist. */
.coachKarte .kopf .abgebrochen {
  font-size: 10px; color: var(--warn); border: 1px solid #ffb02055;
  border-radius: 999px; padding: 1px 7px; white-space: nowrap; margin-left: 6px;
}
/* Ganze Zeile statt `title`: Auf dem Handy gibt es kein Hover. */
.coachKarte .abbruchGrund {
  font-size: 11px; color: var(--warn); opacity: .85; margin: 3px 0 0;
  line-height: 1.35; overflow-wrap: anywhere;
}
.coachKarte .kopf .offen {
  margin-left: auto; font-size: 11px; color: var(--muted); flex: none;
}
.coachKarte .ohneWerte { font-size: 12px; color: var(--muted); }
.coachKarte .werte { display: flex; flex-wrap: wrap; gap: 6px; }
/* Ein Wert je Pille: Name klein darüber, Zahl groß. Nebeneinander statt
   untereinander, weil sechs Zeilen je Coach die Seite zur Tabelle machen. */
.coachKarte .wert {
  display: grid; gap: 1px; justify-items: center;
  border: 1px solid #ffffff1f; border-radius: 9px;
  padding: 5px 9px; min-width: 52px;
  background: #0006;
}
.coachKarte .wert i { font-style: normal; font-size: 10px; color: var(--muted); }
.coachKarte .wert b { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.coachKarte .wert.gut b { color: var(--ok); }
.coachKarte .wert.warn b { color: var(--warn); }
.coachKarte .wert.schlecht b { color: var(--bad); }
/* Technik zum Aufklappen. Zugeklappt ist sie eine Zeile, aufgeklappt alles,
   was vorher dauernd dastand. */
.mehrZustand { margin-top: 10px; }
.mehrZustand > summary {
  cursor: pointer; list-style: none;
  padding: 10px 0; border-top: 1px solid #ffffff14;
  font-size: 12px; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .06em;
}
.mehrZustand > summary::-webkit-details-marker { display: none; }
.mehrZustand > summary::after { content: ' ▾'; }
.mehrZustand[open] > summary::after { content: ' ▴'; }
.mehrZustand h3 { margin: 14px 0 2px; }

.zeilen > .ohneWerte { color: var(--muted); font-size: 13px; padding: 18px 0; text-align: center; }
.zeilen .z {
  display: flex; align-items: baseline; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid #ffffff10;
  font-size: 13.5px;
}
.zeilen .z .was { color: var(--muted); flex: none; width: 40%; }
.zeilen .z .wert { flex: 1; text-align: right; overflow-wrap: anywhere; }
.zeilen .z.gut .wert { color: var(--ok); }
.zeilen .z.warn .wert { color: var(--warn); }
.zeilen .z.schlecht .wert { color: var(--bad); }
.zeilen h3 {
  margin: 16px 0 2px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--muted);
}

/* ── Einstellungsblatt ────────────────────────────────────────────────────
   Alles, was den Ton betrifft, plus die zwei Schalter für die Ansicht. Die
   Kamera bleibt in ihrem eigenen Blatt: eine Linse an zwei Orten zu suchen
   ist teurer als ein Blatt mehr. */
.regler { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.regler input[type="range"] { flex: 1; accent-color: var(--talk); }
.regler output {
  font-variant-numeric: tabular-nums; font-size: 13px; color: var(--muted);
  min-width: 4.5ch; text-align: right;
}
.wahl {
  appearance: none; width: 100%; text-align: left;
  display: grid; gap: 3px;
  border: 1px solid #ffffff24; background: #ffffff0f; color: var(--fg);
  border-radius: 10px; padding: 11px 14px;
}
.wahl b { font-size: 14.5px; font-weight: 600; }
.wahl span { font-size: 11.5px; color: var(--muted); line-height: 1.35; }
.wahl:active { background: #ffffff24; }
.wahl[aria-pressed="true"] { border-color: var(--warn); }
.wahl[aria-pressed="true"] b { color: var(--warn); }
#ruheBtn2 { border-color: #ff5c5c40; }
#ruheBtn2 b { color: #ffbdbd; }
