/*
 * VespaScope – Messgeräte-Oberfläche auf dem 3dtools-Design-System.
 *
 * Alle Farben, Schriftgrössen, Abstände, Radien, Schatten und Dauern kommen
 * aus assets/ds/. Die Brücke – Dunkelsatz und die Umbiegung der alten
 * Variablen – steht in theme.css. In dieser Datei darf kein Hex-Wert und
 * keine freie Länge mehr stehen; Ausnahmen sind einzeln begründet.
 */

@import url("theme.css");

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-app);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

body { display: flex; flex-direction: column; }

a { color: var(--accent); }
code, kbd { font-family: var(--font-app-mono); font-size: var(--fs-body-sm); }

h1, h2, h3 {
  font-family: var(--font-app-display);
  line-height: 1.25;
  margin: 0 0 var(--space-2);
  font-weight: 700;
  letter-spacing: -0.012em;
}
h1 { font-size: var(--fs-h3); letter-spacing: -0.022em; }
h2 { font-size: var(--fs-body-lg); }
h3 { font-size: var(--fs-body); }
p { margin: 0 0 var(--space-4); }

/* ------------------------------------------------------------ Grundgerüst */

.topbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  padding-top: max(var(--space-2), env(safe-area-inset-top));
  background: var(--s-shell);
  border-bottom: 1px solid var(--s-shell-line);
  position: sticky;
  top: 0;
  z-index: 40;
}

/*
 * Hülle Punkt 1: oben links das Adlerzeichen, daneben der Firmenname in
 * Archivo 800 / 19px / −0.025em, "GmbH" mit Schnitt 500 und 55 % Deckkraft.
 */
.brand {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  white-space: nowrap;
}
.brand-mark {
  width: 38px;
  height: 38px;
  flex: none;
  object-fit: contain;
}
.brand-name {
  font-family: var(--font-app-display);
  font-weight: 800;
  font-size: 19px;                 /* Hülle, Punkt 1 – feste Vorgabe */
  letter-spacing: -0.025em;
  color: var(--s-shell-fg);
}
.brand-name .gmbh { font-weight: 500; opacity: .55; }
.brand-app {
  font-size: var(--fs-caption);
  color: var(--s-shell-dim);
  border-left: 1px solid var(--s-shell-line);
  padding-left: var(--space-3);
  margin-left: var(--space-1);
}

.tabs {
  display: flex;
  gap: var(--space-1);
  margin-left: auto;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs a {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  color: var(--s-shell-dim);
  text-decoration: none;
  white-space: nowrap;
  font-size: var(--fs-body-sm);
  transition: var(--transition-control);
}
.tabs a:hover { background: var(--s-shell-tool); color: var(--s-shell-fg); }
.tabs a.active {
  background: var(--s-shell-tool);
  color: var(--s-shell-fg);
  box-shadow: inset 0 -2px 0 var(--accent);   /* 2px für aktive Tab-Unterstriche */
}
.tabs a .pill { margin-left: var(--space-2); }

main { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.wrap { padding: var(--space-4); max-width: var(--container-wide); width: 100%; margin: 0 auto; }
.wrap.tight { max-width: var(--container-default); }

/* ------------------------------------------------------------- Bausteine */

/*
 * Button nach dem Vertrag aus components/core/Button.d.ts:
 * variant primary | accent | signal | secondary | ghost, size sm | md | lg.
 * Ohne Klasse gilt "secondary". Die frühere Klasse .primary hiess blau —
 * im System ist Primär das Navy und Blau der Akzent; sie heisst deshalb
 * jetzt .accent.
 */
/*
 * `hidden` muss `display` schlagen – sonst versteckt es nichts.
 *
 * Die Browser-Grundregel `[hidden] { display: none }` hat dieselbe
 * Spezifität wie eine Klasse, und Autorenregeln kommen danach. Jedes
 * `.btn { display: inline-flex }` hat sie damit ausgehebelt: **alle**
 * versteckten Knöpfe der Anwendung waren sichtbar.
 *
 * Im Feld hiess das: „Wächter beenden" stand da, obwohl der Wächter aus war,
 * und „Vorschlag übernehmen" liess sich drücken, obwohl es keinen Vorschlag
 * gab – das schrieb dann `Number(undefined)`, also NaN, in die Schwelle. Ab
 * da galt jedes Feld als verdeckt, dauerhaft und über Neustarts hinweg.
 * Eine Zeile CSS, drei Fehlerbilder.
 */
[hidden] { display: none !important; }

.btn {
  appearance: none;
  border: 1px solid var(--s-tool-line);
  background: var(--s-tool);
  color: var(--fg);
  min-height: var(--control-h-md);
  padding: 0 var(--space-4);
  border-radius: var(--radius-md);
  font: inherit;
  font-size: var(--fs-body-sm);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  transition: var(--transition-control), transform var(--dur-instant) var(--ease-standard);
  white-space: nowrap;
}
.btn:hover:not(:disabled) {
  background: color-mix(in srgb, var(--s-tool-fg) 16%, transparent);
  border-color: var(--s-tool-fg);
}
.btn:active:not(:disabled) { transform: scale(var(--press-scale)); }
.btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-color: var(--border-focus); }
.btn:disabled { opacity: .45; cursor: not-allowed; }

.btn.primary { background: var(--navy-700); border-color: var(--navy-600); color: var(--white); font-weight: 600; }
.btn.primary:hover:not(:disabled) { background: var(--navy-600); border-color: var(--navy-500); }

.btn.accent { background: var(--accent-strong); border-color: var(--accent-strong); color: var(--white); font-weight: 600; }
.btn.accent:hover:not(:disabled) { background: var(--blue-600); border-color: var(--blue-600); }

/*
 * Scharf gestellt, aber nicht am Auslösen: der Wachmodus wartet.
 *
 * Bewusst ruhiger als der Aufnahmeknopf und ohne Pulsieren – dieser Zustand
 * hält stundenlang an, und etwas, das stundenlang blinkt, sieht man nach
 * fünf Minuten nicht mehr. Der Umriss bleibt kräftig, damit auf einen Blick
 * erkennbar ist, dass der Wächter läuft.
 */
.btn.accent.active {
  background: var(--s-tool);
  border-color: var(--accent-strong);
  color: var(--accent-strong);
}

/*
 * Erledigter Einmessschritt.
 *
 * Fundgrün, weil das Designsystem dafür genau diese Rolle vorsieht:
 * „Blau führt, Fundgrün bestätigt, Navy arbeitet, Rot warnt." Der Knopf sagt
 * damit nicht „drück mich", sondern „das hier steht" – und er bleibt
 * anklickbar, weil sich jede Messung wiederholen lässt.
 */
.btn.fertig {
  border-color: color-mix(in srgb, var(--fund) 60%, transparent);
  background: color-mix(in srgb, var(--fund) 14%, transparent);
  color: var(--lime-400);
}
.btn.fertig:hover:not(:disabled) {
  background: color-mix(in srgb, var(--fund) 24%, transparent);
  border-color: var(--fund);
}

.btn.signal { border-color: color-mix(in srgb, var(--signal) 55%, transparent); color: var(--danger); }
.btn.signal:hover:not(:disabled) { background: color-mix(in srgb, var(--signal) 22%, transparent); border-color: var(--signal); }

.btn.ghost { background: transparent; border-color: transparent; }
.btn.ghost:hover:not(:disabled) { background: var(--s-shell-tool); border-color: var(--s-tool-line); }

/*
 * Stiller Löschknopf (ghost + signal). Beide Regeln sind gleich spezifisch,
 * ohne diese Zeile gewänne allein die Reihenfolge und die Signalfarbe fiele
 * je nach Sortierung weg. Rahmenlos ist hier gewollt: das ✕ in einer Zeile
 * soll zurückhaltend bleiben, aber rot lesbar.
 */
.btn.ghost.signal { color: var(--danger); border-color: transparent; }
.btn.ghost.signal:hover:not(:disabled) {
  background: color-mix(in srgb, var(--signal) 22%, transparent);
  border-color: color-mix(in srgb, var(--signal) 55%, transparent);
}

.btn.small { min-height: var(--control-h-sm); padding: 0 var(--space-3); font-size: var(--fs-caption); }

/*
 * Ein Knopf, der wie Text aussieht. Für Angaben in der Statuszeile, hinter
 * denen etwas zu tun ist: der Gerätename ist die Stelle, an der man beim
 * Nachsehen landet („welches Mikrofon läuft hier eigentlich?"), und ein
 * zweiter Knopf daneben wäre nur Lärm.
 */
.linkknopf {
  appearance: none; border: 0; background: none; padding: 0;
  font: inherit; color: inherit; cursor: pointer;
  text-decoration: underline; text-decoration-style: dotted;
  text-underline-offset: 3px;
}
.linkknopf:hover { color: var(--accent-strong); }

/*
 * Aufnahmeknopf. Rot ist im System Signal und keine Handlungsfarbe — genau
 * das ist hier gemeint: "Aufnahme läuft". Das langsame Pulsieren ist kein
 * Übergang, sondern eine Zustandsanzeige; ohne sie ist eine laufende
 * Aufnahme aus zwei Metern Abstand nicht zu erkennen.
 */
.btn.rec { background: var(--signal); border-color: var(--signal); color: var(--white); font-weight: 600; }
.btn.rec:hover:not(:disabled) { background: var(--red-700); border-color: var(--red-700); }
.btn.rec.active {
  background: var(--s-tool);
  border-color: var(--signal);
  color: var(--danger);
  animation: rec-puls 1.4s var(--ease-standard) infinite;
}
@keyframes rec-puls { 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--signal) 22%, transparent); } }

/*
 * Die Hauptknöpfe der Aufnahmeansicht: alle gleich breit.
 *
 * `auto-fit` mit einer Mindestbreite heisst: nebeneinander, solange Platz ist,
 * sonst zwei Reihen – und in jedem Fall gleich gross. Ein ausgeblendeter Knopf
 * ("Wächter beenden", solange nichts läuft) belegt keine Spalte, die
 * übrigen verteilen sich neu.
 *
 * `min-width: 0` ist nötig, weil .btn nicht umbricht: ohne das würde ein
 * langer Text die Spalte auseinanderschieben und die Gleichheit zerstören.
 */
.knopfreihe {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-3);
}
.knopfreihe > .btn { min-width: 0; overflow: hidden; }

/*
 * Fokusfenster: alles Wichtige auf dem Bild.
 *
 * Am Mast steht man gebückt über dem Telefon und dreht am Regler – wer dabei
 * scrollen muss, verliert entweder das Bild oder den Knopf aus den Augen.
 * Schärfewert und Handlungen liegen deshalb als Leiste **auf** dem Bild, die
 * Entfernung direkt darunter. Damit passt der ganze Vorgang auf einen
 * Bildschirm.
 */
.kamera-buehne { position: relative; }
.kamera-buehne video {
  display: block; width: 100%;
  border-radius: var(--radius-lg);
  background: #000;
}
/* Das Raster beim Einlesen der Platte liegt deckungsgleich über dem Bild. */
.platte-netz {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
}

.kamera-overlay {
  position: absolute; left: var(--space-3); right: var(--space-3); bottom: var(--space-3);
  display: grid; gap: var(--space-2);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  /* Dunkel und leicht verwischt, damit die Schrift über jedem Bildinhalt
     lesbar bleibt – gegen Gras genauso wie gegen eine helle Platte. */
  background: rgba(9, 15, 30, .72);
  backdrop-filter: blur(6px);
  color: var(--white);
}
.kamera-overlay .schaerfe {
  display: flex; align-items: center; gap: var(--space-3);
  font-family: var(--font-mono); font-size: var(--fs-body-sm);
}
.kamera-overlay .schaerfe .meter { flex: 1; }
/*
 * Immer drei Spalten, auch auf dem Telefon – und klein.
 *
 * Mit der üblichen Mindestbreite brachen die Knöpfe bei 400 px auf zwei
 * Reihen um, und die Leiste verdeckte die halbe Köderplatte. Genau die will
 * man beim Scharfstellen aber sehen.
 */
.kamera-overlay .knopfreihe {
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
}
.kamera-overlay .btn {
  min-height: var(--control-h-sm);
  padding: 0 var(--space-2);
  font-size: var(--fs-caption);
  text-overflow: ellipsis;
}
/* Auf dem Bild sitzende Knöpfe bleiben hell, egal welches Thema. */
.kamera-overlay .btn:not(.primary) {
  background: rgba(255, 255, 255, .14);
  border-color: rgba(255, 255, 255, .28);
  color: var(--white);
}
.kamera-overlay .btn:not(.primary):hover:not(:disabled) { background: rgba(255, 255, 255, .24); }

/* Zwei Knöpfe nebeneinander, gleich breit – für Schritte, die zusammengehören. */
.knopfpaar {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}
.knopfpaar > .btn { min-width: 0; }

.row { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
.row.tight { gap: var(--space-2); }
.spacer { flex: 1; }

/* ------------------------------------------------------------- Formulare */

label { display: block; font-size: var(--fs-caption); color: var(--fg-dim); margin-bottom: var(--space-3); }

input, select, textarea {
  width: 100%;
  margin-top: var(--space-1);
  min-height: var(--control-h-md);
  padding: var(--space-2) var(--space-3);
  background: var(--s-page);
  border: 1px solid var(--s-tool-line);
  border-radius: var(--radius-md);
  color: var(--fg);
  font: inherit;
  font-size: var(--fs-body-sm);
  transition: var(--transition-control);
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--border-focus);
  box-shadow: var(--shadow-focus);
}
input[type=range] {
  padding: 0; background: transparent; border: 0; min-height: 0;
  accent-color: var(--accent);
}
input[type=checkbox] {
  width: auto; min-height: 0; margin: 0 var(--space-2) 0 0;
  vertical-align: -2px; accent-color: var(--accent);
}
textarea { resize: vertical; min-height: 60px; }
select {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--fg-dim) 50%),
    linear-gradient(135deg, var(--fg-dim) 50%, transparent 50%);
  background-position: right var(--space-4) center, right var(--space-2) center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: var(--space-7);
}

/* ----------------------------------------------------------------- Karten */

.card {
  background: var(--s-card);
  border: 1px solid var(--s-line);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}
.card + .card { margin-top: var(--space-5); }
.card h2:first-child, .card h3:first-child { margin-top: 0; }

/* ------------------------------------------------------- Badge und Tag */

/* Badge, tone neutral | info | success | warning | danger | brand | fund */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--fs-micro);
  background: var(--s-tool);
  color: var(--fg-dim);
  white-space: nowrap;
}
.pill.dot::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.pill.ok   { background: color-mix(in srgb, var(--ok) 18%, transparent);     color: var(--ok); }
.pill.warn { background: color-mix(in srgb, var(--warn) 18%, transparent);   color: var(--warn); }
.pill.bad  { background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger); }
.pill.fund { background: color-mix(in srgb, var(--fund) 18%, transparent);   color: var(--lime-400); }

/*
 * Hinweisfeld. Im System nicht vorgesehen — bewusste Ergänzung: nach jeder
 * Aufnahme muss eine Warnung ("übersteuert", "kaum lauter als der
 * Hintergrund") stehen bleiben, bis sie gelesen ist. Ein Toast verschwindet
 * dafür zu schnell, ein Badge fasst den Satz nicht.
 */
.msg { padding: var(--space-3); border-radius: var(--radius-md); font-size: var(--fs-body-sm); }
.msg.ok   { background: color-mix(in srgb, var(--ok) 14%, transparent);     color: var(--ok); }
.msg.warn { background: color-mix(in srgb, var(--warn) 14%, transparent);   color: var(--warn); }
.msg.bad  { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }

.mono { font-family: var(--font-app-mono); }
.dim { color: var(--fg-dim); }
.faint { color: var(--fg-faint); }
.small { font-size: var(--fs-caption); }
.nowrap { white-space: nowrap; }

/* ---------------------------------------------------------- Spektrogramm */

/*
 * Messfläche. Der Grund ist dunkler als jede Systemfläche, damit die
 * Farbskala ihren vollen Umfang zeigt; die Falschfarbendarstellung folgt
 * physikalischen, nicht gestalterischen Regeln (siehe DESIGN-MIGRATION.md,
 * Abschnitt "Was ausserhalb bleibt").
 */
.spec-host {
  position: relative; width: 100%;
  background: var(--navy-950);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.spec-image, .spec-overlay { position: absolute; inset: 0; display: block; }
.spec-overlay { touch-action: none; cursor: crosshair; }

.spec-panel { display: flex; flex-direction: column; gap: var(--space-3); }
.spec-frame { height: min(62vh, 620px); min-height: 280px; }
.spec-frame.short { height: min(42vh, 380px); }

/* --------------------------------------------------------------- Anzeigen */

/* Kennzahlkachel – readme.md nennt sie im Portal, als Komponente gibt es sie nicht. */
.gauges { display: grid; grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); gap: var(--space-2); }
.gauge {
  background: var(--s-card);
  border: 1px solid var(--s-line);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
}
.gauge .k {
  font-size: var(--fs-micro);
  color: var(--fg-faint);
  text-transform: uppercase;
  letter-spacing: .14em;              /* Dachzeile, feste Vorgabe */
}
.gauge .v { font-size: var(--fs-body-lg); font-weight: 600; font-family: var(--font-app-mono); }
.gauge .v small { font-size: var(--fs-caption); color: var(--fg-dim); font-weight: 400; margin-left: 2px; }
.gauge.hi .v { color: var(--fund); }   /* Fundgrün bestätigt: hier ist etwas erkannt */

/*
 * Pegelanzeige. Der Verlauf ist keine Zierde: blau heisst brauchbar,
 * bernstein laut, rot übersteuert. Fundgrün bleibt aussen vor, es ist für
 * Treffer reserviert und keine Skalenfarbe.
 */
.meter {
  height: 7px; border-radius: var(--radius-sm);
  background: var(--s-tool); overflow: hidden; margin-top: var(--space-1);
  box-shadow: var(--shadow-inner-sunken);
}
.meter > i {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--blue-400), var(--warn) 70%, var(--signal) 92%);
  transition: width var(--dur-instant) linear;
}

/* --------------------------------------------------------------- Archiv */

.grid-recs { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--space-3); }
.rec-card {
  background: var(--s-card);
  border: 1px solid var(--s-line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  cursor: pointer;
  transition: transform var(--dur-base) var(--ease-standard), box-shadow var(--dur-base) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard);
  position: relative;
}
/* Interaktive Karten heben sich um 2px, shadow-1 -> shadow-3 in 200 ms. */
.rec-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); border-color: var(--s-tool-line); }
.rec-card.sel { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.rec-card .thumb { display: block; width: 100%; aspect-ratio: 16/7; object-fit: cover; background: var(--navy-950); }
.rec-card .thumb.empty { display: grid; place-items: center; color: var(--fg-faint); font-size: var(--fs-caption); }
.rec-card .body { padding: var(--space-2) var(--space-3) var(--space-3); }
.rec-card .title { font-size: var(--fs-body-sm); font-weight: 600; display: flex; align-items: center; gap: var(--space-2); }
.rec-card .meta { font-size: var(--fs-micro); color: var(--fg-dim); margin-top: var(--space-1); display: flex; gap: var(--space-2); flex-wrap: wrap; }
.rec-card .tick {
  position: absolute; top: var(--space-2); left: var(--space-2);
  width: 22px; height: 22px; border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--navy-950) 80%, transparent);
  border: 1px solid var(--s-tool-line);
  display: grid; place-items: center; font-size: var(--fs-caption);
}
.rec-card.sel .tick { background: var(--accent-strong); color: var(--white); border-color: var(--accent); }

/*
 * Tag nach components/core/Tag.d.ts. Die Farbe kommt aus den Daten: jede
 * Kategorie trägt ihre eigene, vom Nutzer vergeben und in der Datenbank
 * gespeichert. Das System hat dafür keine Palette – siehe DESIGN-MIGRATION.md.
 */
.cat-chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 2px var(--space-2); border-radius: var(--radius-pill);
  font-size: var(--fs-micro);
  background: var(--s-tool); border: 1px solid transparent;
}
.cat-chip i { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }
button.cat-chip {
  cursor: pointer; color: var(--fg-dim); font: inherit;
  font-size: var(--fs-caption); padding: var(--space-1) var(--space-3);
  min-height: var(--control-h-sm);
  transition: var(--transition-control);
}
button.cat-chip.on { background: color-mix(in srgb, var(--s-tool-fg) 18%, transparent); border-color: currentColor; color: var(--fg); }

.filters { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: flex-end; margin-bottom: var(--space-3); }
.filters label { margin: 0; min-width: 120px; }
.filters label.grow { flex: 1; min-width: 180px; }

/* Tabellen: Versalien-Mikroköpfe, Trenner in --border-subtle-Stärke. */
table { width: 100%; border-collapse: collapse; font-size: var(--fs-body-sm); }
th, td { text-align: left; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--s-line); vertical-align: middle; }
th {
  font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .14em;
  color: var(--fg-faint); font-weight: 600;
}
tr:last-child td { border-bottom: 0; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------- Dialog */

.sheet-bg {
  position: fixed; inset: 0;
  background: var(--overlay-scrim);
  z-index: 90;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
  backdrop-filter: blur(2px);
}
.sheet {
  background: var(--s-card);
  border: 1px solid var(--s-line);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow);
  width: min(1100px, 100%); max-height: 92vh;
  padding: var(--space-5);
  /*
   * Nur senkrecht scrollen. Waagrecht liess sich das Fenster beim Wischen
   * ein Stück verschieben – das sieht nach einem Fehler aus und ist keiner:
   * es genügt ein einziges Kind, das ein paar Pixel breiter ist als der
   * Inhalt (ein Raster, ein langes Wort), und schon erlaubt der Browser das
   * Verschieben. `overscroll-behavior` hält zusätzlich das Gummiband an, das
   * auf dem Telefon dasselbe Bild erzeugt, ganz ohne Überbreite.
   */
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
}
.sheet.narrow { width: min(520px, 100%); }
.sheet-head { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.sheet-head h2 { margin: 0; flex: 1; }

.toasts {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: max(var(--space-5), env(safe-area-inset-bottom));
  z-index: 120; display: flex; flex-direction: column; gap: var(--space-2);
  align-items: center; pointer-events: none;
}
.toast {
  background: var(--s-card); border: 1px solid var(--s-line); color: var(--fg);
  padding: var(--space-3) var(--space-4); border-radius: var(--radius-lg);
  box-shadow: var(--shadow); font-size: var(--fs-body-sm);
  animation: rise var(--dur-base) var(--ease-standard); max-width: 90vw;
}
.toast.bad { border-color: color-mix(in srgb, var(--danger) 55%, transparent); color: var(--danger); }
.toast.ok { border-color: color-mix(in srgb, var(--ok) 55%, transparent); color: var(--ok); }
/* Ein- und Ausblenden mit kleiner Verschiebung, nie mit Skalierung. */
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }

/* -------------------------------------------------------- Einfache Seiten */

.page-plain { align-items: center; justify-content: center; padding: var(--space-5); }
.page-plain .card { width: min(var(--container-narrow), 100%); margin: auto; }
.page-plain .card.narrow { width: min(400px, 100%); }
.lead { color: var(--fg-dim); }

.checks { list-style: none; padding: 0; margin: 0 0 var(--space-5); }
.checks li { display: flex; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--s-line); align-items: flex-start; }
.checks li:last-child { border: 0; }
.checks .mark { width: 20px; text-align: center; font-weight: 700; flex: none; }
.checks .ok .mark { color: var(--ok); }
.checks .bad .mark { color: var(--danger); }
.checks .warn .mark { color: var(--warn); }
.checks small { color: var(--fg-dim); }

/* ------------------------------------------------------------ Zifferblock */

/*
 * Die Tasten sind bewusst gross: das Gerät wird draussen bedient, oft mit
 * kalten Fingern. 64px Höhe liegt über der Bedienelementhöhe des Systems,
 * was hier gewollt ist — eine Taste, die man dreimal treffen muss, kostet
 * mehr als eine, die etwas Platz braucht.
 */
.pin-punkte {
  display: flex; justify-content: center; gap: var(--space-3);
  margin: var(--space-5) 0;
  min-height: 14px;
}
.pin-punkte i {
  width: 12px; height: 12px; border-radius: 50%;
  border: 1px solid var(--s-tool-line);
  transition: background-color var(--dur-fast) var(--ease-standard);
}
.pin-punkte i.voll { background: var(--accent); border-color: var(--accent); }

.pin-pad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
}
.pin-taste {
  min-height: 64px;
  font-size: var(--fs-body-lg);
  font-family: var(--font-app-mono);
  font-weight: 600;
  justify-content: center;
}
.pin-taste:disabled { opacity: .3; }

/* ------------------------------------------------------------ Belegbilder */

/*
 * Die Bilder stehen quer unter dem Spektrogramm, damit man beim Beschriften
 * Ton und Bild zusammen im Blick hat. Drei Abzüge einer Auslösung passen
 * nebeneinander; mehr wird geschoben statt umgebrochen, sonst wandert das
 * Spektrogramm bei jeder Aufnahme woanders hin.
 */
.belege {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.belege::-webkit-scrollbar { display: none; }
.belege:empty { display: none; }

.beleg-feld { margin: 0; flex: 0 0 auto; text-align: center; }
.beleg {
  display: block;
  height: 96px;
  width: auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--s-line);
  background: var(--navy-950);
  cursor: zoom-in;
  transition: transform var(--dur-base) var(--ease-standard), box-shadow var(--dur-base) var(--ease-standard);
}
.beleg:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); }
.beleg-feld figcaption { margin-top: 2px; font-family: var(--font-app-mono); }

/*
 * Das Kurzvideo als Daumennagel, in derselben Reihe wie die Belegbilder.
 *
 * In voller Breite schob es Kategorien und Messwerte aus dem Bild – beim
 * Beschriften braucht man aber Spektrogramm, Ton, Belege und Zahlen
 * gleichzeitig. Angeklickt wird es gross.
 */
.beleg-feld.ist-video { position: relative; }
.beleg-feld.ist-video video {
  display: block;
  height: 96px; width: auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--s-line);
  background: var(--navy-950);
  cursor: zoom-in;
  transition: transform var(--dur-base) var(--ease-standard), box-shadow var(--dur-base) var(--ease-standard);
}
.beleg-feld.ist-video video:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); }
.beleg-feld.ist-video .spielzeichen {
  position: absolute; top: 48px; left: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  color: var(--white);
  font-size: 22px;
  text-shadow: 0 1px 6px rgb(0 0 0 / .8);
}

/* --------------------------------------------------------------- Diagramme */

.bars { display: flex; flex-direction: column; gap: var(--space-2); }
.bar-row { display: grid; grid-template-columns: minmax(110px, 24%) 1fr auto; gap: var(--space-3); align-items: center; font-size: var(--fs-body-sm); }
.bar-track { background: var(--s-tool); border-radius: var(--radius-sm); height: 16px; overflow: hidden; box-shadow: var(--shadow-inner-sunken); }
.bar-fill { height: 100%; border-radius: var(--radius-sm); min-width: 2px; transition: width var(--dur-slow) var(--ease-standard); }

.spark { display: flex; align-items: flex-end; gap: 2px; height: 44px; }
.spark i { flex: 1; background: var(--accent); border-radius: var(--radius-xs) var(--radius-xs) 0 0; min-height: 2px; opacity: .8; }

.confusion td, .confusion th { text-align: center; padding: var(--space-2); font-size: var(--fs-caption); }
.confusion td:first-child, .confusion th:first-child { text-align: left; }
/* Diagonale = richtig erkannt. Fundgrün bestätigt. */
.confusion .diag { background: color-mix(in srgb, var(--fund) 22%, transparent); font-weight: 600; }
.confusion .miss { background: color-mix(in srgb, var(--danger) 14%, transparent); }

/* ---------------------------------------------------------------- Sonstiges */

.split-2 { display: grid; grid-template-columns: 1fr 340px; gap: var(--space-3); align-items: start; }

.hint { font-size: var(--fs-caption); color: var(--fg-faint); margin-top: var(--space-1); }
.divider { height: 1px; background: var(--s-line); margin: var(--space-4) 0; }
.stack > * + * { margin-top: var(--space-3); }
.scroll-x { overflow-x: auto; }

.busy { position: relative; pointer-events: none; opacity: .6; }
/* Ladeanzeige – im System nicht vorgesehen, bewusste Ergänzung. */
.spinner {
  width: 15px; height: 15px;
  border: 2px solid var(--s-tool-line); border-top-color: var(--fg);
  border-radius: 50%; animation: spin .7s linear infinite; display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

.empty-state { text-align: center; padding: var(--space-9) var(--space-4); color: var(--fg-dim); }
.empty-state h3 { color: var(--fg); }

/* ------------------------------------------------------------ Schmale Geräte */

@media (max-width: 900px) {
  .split-2 { grid-template-columns: 1fr; }
  .wrap { padding: var(--space-3); }
  .card { padding: var(--space-4); }
  .spec-frame { height: 46vh; min-height: 240px; }
}

/*
 * Auf dem Telefon passten die Reiter nicht in eine Zeile: die hinteren
 * ("Kategorien", "Datensatz", …) lagen unsichtbar ausserhalb, ohne dass etwas
 * darauf hingedeutet hätte. Sie bekommen deshalb eine eigene Zeile über die
 * volle Breite und brechen um – was man nicht sieht, findet man nicht.
 */
@media (max-width: 760px) {
  .topbar { flex-wrap: wrap; row-gap: var(--space-2); padding-bottom: var(--space-2); }
  .tabs {
    order: 10;
    width: 100%;
    margin-left: 0;
    flex-wrap: wrap;
    overflow-x: visible;
    gap: var(--space-1);
  }
  .tabs a { background: var(--s-shell-tool); }
  .topbar .brand { flex: 1; }
  .brand-app { display: none; }
}

/*
 * Kennzeichnung der Testfassung.
 *
 * Beide Installationen liegen als App auf demselben Startbildschirm und sehen
 * sonst gleich aus. Eine Aufnahme versehentlich in der Testfassung zu machen,
 * bedeutet, dass sie im Trainingsdatensatz fehlt – darum ein Streifen, den man
 * nicht übersehen kann.
 */
body.dev .topbar { border-bottom: 2px solid var(--warn); }
body.dev::before {
  content: '';
  position: fixed;
  inset: 0 0 auto 0;
  height: 3px;
  background: repeating-linear-gradient(135deg, var(--warn) 0 10px, transparent 10px 20px);
  z-index: 200;
  pointer-events: none;
}

/* ------------------------------------------------------ Startklar-Prüfung */

/*
 * Ein Prüfpunkt je Zeile, die Bewertung als Farbstreifen links. Am Mast wird
 * das Telefon in der Sonne gelesen – wichtiger als Feinheit ist, dass man auf
 * einen Blick sieht, welche Zeile die schlechte ist.
 */
.pruefpunkt {
  border-left: 3px solid var(--s-line);
  padding: var(--space-2) 0 var(--space-2) var(--space-3);
}
.pruefpunkt.gut      { border-left-color: var(--ok); }
.pruefpunkt.knapp    { border-left-color: var(--warn); }
.pruefpunkt.schlecht { border-left-color: var(--danger); }
.pruefpunkt.gut      > .row > svg { color: var(--ok); }
.pruefpunkt.knapp    > .row > svg { color: var(--warn); }
.pruefpunkt.schlecht > .row > svg { color: var(--danger); }
.pruefpunkt .hint { margin-top: var(--space-1); }

/*
 * Die Einmessschritte als Liste: Nummer, Titel, Stand, Zeichen. Jede Zeile ist
 * ein Knopf über die volle Breite – am Mast mit dem Daumen zu treffen. Grün
 * heisst erledigt, wie bei .btn.fertig, und bleibt anklickbar.
 */
.schritte { display: flex; flex-direction: column; gap: var(--space-2); }
.schritt {
  appearance: none; font: inherit; color: var(--fg); cursor: pointer;
  display: flex; align-items: center; gap: var(--space-3);
  width: 100%; text-align: left;
  padding: var(--space-3);
  border: 1px solid var(--s-line);
  border-radius: var(--radius-md);
  background: var(--s-shell-tool);
}
.schritt:hover { border-color: var(--accent-strong); }
.schritt > .nr {
  flex: 0 0 28px; height: 28px; line-height: 28px; text-align: center;
  border-radius: 50%; background: var(--s-tool); font-weight: 600;
  font-size: var(--fs-caption);
}
.schritt > .text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.schritt > .text > .small { white-space: normal; }
.schritt > svg { flex: 0 0 auto; color: var(--fg-dim); }
.schritt.fertig {
  border-color: color-mix(in srgb, var(--fund) 60%, transparent);
  background: color-mix(in srgb, var(--fund) 14%, transparent);
}
.schritt.fertig > .nr { background: var(--fund); color: var(--white); }
.schritt.fertig > svg { color: var(--lime-400); }

/* Die zusammengefalteten „in Ordnung"-Punkte. */
details.gute > summary {
  display: flex; align-items: center; gap: var(--space-2);
  cursor: pointer; list-style: none;
  color: var(--ok); font-size: var(--fs-body-sm);
  padding: var(--space-2) 0 var(--space-2) var(--space-3);
  border-left: 3px solid var(--ok);
}
details.gute > summary::-webkit-details-marker { display: none; }
details.gute[open] > summary { margin-bottom: var(--space-2); }
details.gute > .stack { padding-left: var(--space-3); }

/* „Angemeldet bleiben" auf der Anmeldeseite. */
label.bleiben {
  display: flex; align-items: center; gap: var(--space-2);
  justify-content: center; margin: var(--space-3) 0;
  font-size: var(--fs-body-sm); color: var(--fg-muted);
  cursor: pointer;
}
label.bleiben input { width: auto; margin: 0; }

/* ------------------------------------------------- Archiv: Masten und Zeit */

.stationen {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.stationen .zahl {
  margin-left: var(--space-2); opacity: .7;
  font-variant-numeric: tabular-nums; font-size: .9em;
}
.knopfpaar { display: flex; gap: var(--space-1); }

.spuren { display: flex; flex-direction: column; gap: var(--space-3); }
.spur {
  display: grid; grid-template-columns: 150px 1fr; gap: var(--space-3);
  align-items: center;
}
.spurkopf { display: flex; flex-direction: column; line-height: 1.25; }
.bahn {
  position: relative; height: 34px;
  background: var(--s-card); border: 1px solid var(--s-line);
  border-radius: var(--radius-md);
}
.bahn .strich {
  position: absolute; top: 0; bottom: 0; width: 1px;
  background: var(--s-line);
}
/*
 * Die Uhrzeit steht nur unter der untersten Spur. Unter jeder Bahn geschrieben
 * lief die Beschriftung in die naechste Spur hinein – bei drei Tagen
 * untereinander sah das aus, als gehoerte die Zeit zur falschen Zeile.
 */
.bahn .strich span { display: none; }
.spuren .spur:last-child .bahn .strich span {
  display: block;
  position: absolute; top: 100%; left: 2px; margin-top: 2px;
  font-size: 10px; color: var(--fg-faint); white-space: nowrap;
}
.spuren { padding-bottom: 16px; }
.punkt {
  position: absolute; width: 9px; height: 9px; padding: 0;
  margin-left: -4.5px; border-radius: 50%;
  background: var(--accent); border: 1px solid var(--accent);
  cursor: pointer; transition: transform var(--dur-fast) var(--ease-standard);
}
.punkt.offen { background: transparent; border-color: var(--fg-faint); }
.punkt.raus  { opacity: .35; }
.punkt:hover, .punkt:focus-visible {
  transform: scale(1.9); z-index: 2; outline: none;
  box-shadow: 0 0 0 2px var(--s-card), 0 0 0 3px currentColor;
}

/* Am Telefon steht der Tag über der Bahn statt daneben. */
@media (max-width: 700px) {
  .spur { grid-template-columns: 1fr; gap: var(--space-1); }
  .spurkopf { flex-direction: row; gap: var(--space-2); align-items: baseline; }
}


/*
 * Erkennungsmessung: die Spur ist das eigentliche Ergebnis.
 *
 * Zwei Baender, die sich trennen muessen - blau leer, orange mit Objekt. Ob
 * die Erkennung taugt, sieht man daran schneller als an jeder Zahl, und
 * deshalb steht sie gross und nicht als Randnotiz.
 */
.messspur {
  width: 100%;
  height: 90px;
  display: block;
  background: var(--bg-2, #10151c);
  border: 1px solid var(--line, #2d3742);
  border-radius: var(--radius-2, 8px);
  margin: var(--space-2, 8px) 0;
}

.bericht {
  white-space: pre-wrap;
  font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--bg-2, #10151c);
  border: 1px solid var(--line, #2d3742);
  border-radius: var(--radius-2, 8px);
  padding: var(--space-3, 12px);
  overflow-x: auto;
}


/* ---------------------------------------------------------------- Wache */

/*
 * Das Kamerabild ersetzt das Spektrogramm. Höhe begrenzt, damit Knöpfe und
 * Kennzahlen auf dem Telefon ohne Scrollen darunter Platz haben; die Breite
 * folgt dem Seitenverhältnis, damit die Überlagerung deckungsgleich bleibt.
 */
.wache-rahmen { display: flex; justify-content: center; }
.wache-buehne {
  width: 100%;
  max-width: min(100%, calc(58vh * 4 / 3));
}
.wache-buehne video { max-height: 58vh; object-fit: contain; }
.wache-lage {
  position: absolute; left: var(--space-2); top: var(--space-2);
  display: flex; gap: var(--space-2); flex-wrap: wrap;
  pointer-events: none;
}
.wache-lage .pill { background: rgba(9, 15, 30, .72); backdrop-filter: blur(4px); }
.wache-leer {
  width: 100%;
  min-height: 180px;
  display: grid; place-items: center; align-content: center; gap: var(--space-2);
  border: 1px dashed var(--s-line);
  border-radius: var(--radius-lg);
  color: var(--fg-faint);
}
.wache-leer p { margin: 0; }
