/* =========================================================
   QS-Modul – Musterseite (Stufe 1a, Design-Review)
   Nur das, was die QS-Seiten ZUSÄTZLICH zur bestehenden style.css
   brauchen. Die 79 KB von style.css werden hier nicht kopiert.
   =========================================================

   Vorausgesetzt aus C:\Entwicklung\Projekt-Leitstand\Leitstand-Online-Probe\style.css
   (diese Datei liegt in der echten Auslieferung neben qs.css und wird VOR
   qs.css eingebunden – siehe <link> in qs-muster.html):

   Farb-/Schrift-Variablen (:root):
     --brand-primary --brand-accent --font-heading --font-body
     --surface-1 --page-plane --text-primary --text-secondary --text-muted
     --gridline --baseline --border --weekend-bg --urgent --danger
     --success-text

   Basis-Regeln:
     * { box-sizing: border-box; }
     html, body  (Schrift, Grundfarbe, Hintergrund)
     [hidden] { display: none !important; }   -- Zeile 909 in style.css

   Bausteine (unverändert weiterverwendet, hier NICHT neu definiert):
     .toolbar  .brand-mark  .toolbar h1
     .page-nav  .page-nav-link  .page-nav-link:hover  .page-nav-link.active
     .ansicht-schalter  .ansicht-btn  .ansicht-btn:hover  .ansicht-btn.active
       (wiederverwendet für den Büro/Tablet-Schalter dieser Seite)
     .btn  .btn:hover  .btn-primary  .btn-primary:hover
     .btn-danger  .btn-danger:hover
     .dialog-actions  .spacer  .hint

   Alles unten mit Präfix "qs-" ist neu und nur für QS-Seiten gedacht. Ob es
   später nach style.css wandert, entscheidet sich erst mit dem Datenmodell –
   diese Seite zeigt bewusst nur das Aussehen.

   Abweichungen von der Leitstand-Optik und warum, siehe Bericht
   design-muster-report.md. Kurzfassung: kein .app{height:100vh} (diese Seite
   ist eine lang scrollende Dokumentseite, keine Ein-Bildschirm-Tafel wie der
   Monitor); .btn.klein ist hier neu definiert, weil style.css keine kleine
   Knopf-Variante kennt (wartung.css hat sie, aber die gilt nicht als
   Grundlage für dieses Modul).

   Farben: es werden ausschließlich vorhandene Variablen wiederverwendet,
   keine neuen Farbwerte. Kontrastwerte für die neu KOMBINIERTEN Stellen
   stehen im Bericht (IO/NIO-Knöpfe, roter Rahmen bei Grenzverletzung,
   „keine Aussage"-Text).
   ========================================================= */

/* ---------- Seitenrahmen ---------- */

.qs-app { min-height: 100%; }

.qs-seite {
  max-width: 1180px;
  margin: 0 auto;
  padding: 22px 20px 60px;
}

/* ⚠️ EINE SEITE DARF DIE 1180 PX VERLASSEN - ueber diese Klasse, nicht global
   (14.09.2026). Die Freigabemaske traegt bis zu 99 Teilspalten nebeneinander;
   gemessen bei 1920 x 1080 mit Umfang 20: die Seitenspalte war 1180 px breit,
   die Tabelle 2567 px - also 1471 px zu verschieben, mehr als eine Bildschirm-
   breite, waehrend 740 px Fensterrand leer blieben. Thomas am 14.09.2026:
   "so breit es geht wie auf dem Bild" (das Altsystem nutzt die volle Breite).

   ⚠️ NUR MIT DER KLASSE, und das ist der Punkt. Ohne sie waeren IPC-Maske,
   Kartenliste und Pruefplan gleich mitgeaendert - danach hat niemand gefragt,
   und ein Fliesstext ueber 2560 px ist schlechter lesbar, nicht besser. Wer
   eine weitere Seite breit haben will, setzt die Klasse dort ans <main>. */
.qs-seite.ist-breit { max-width: none; }

.qs-kopf { padding: 20px 0 4px; }
.qs-kopf h1 { font-size: 22px; }
.qs-platzhalter-hinweis {
  margin: 6px 0 18px;
  font-size: 13px;
  font-style: italic;
  color: var(--text-muted);
}

/* Kurznavigation zu den Bausteinen weiter unten auf der Seite */
.qs-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 26px;
  padding: 0;
  list-style: none;
}
.qs-toc a {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--weekend-bg);
  color: var(--text-secondary);
  text-decoration: none;
}
.qs-toc a:hover { background: var(--border); color: var(--text-primary); text-decoration: none; }

/* ---------- Bausteinblöcke ---------- */
.qs-block {
  margin: 0 0 40px;
  padding: 20px 0 0;
  border-top: 1px solid var(--border);
}
.qs-block:first-of-type { border-top: none; padding-top: 0; }
.qs-block h2 {
  font-family: var(--font-heading);
  font-size: 17px;
  margin: 0 0 4px;
  color: var(--text-primary);
}
.qs-block .qs-block-hinweis {
  font-size: 12.5px;
  color: var(--text-muted);
  margin: 0 0 14px;
}

/* ---------- Karte (fehlt in style.css, dort gibt es nur die Zeitstrahl-Optik) ---------- */
.qs-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 18px 20px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.06);
}

/* ---------- 1. Kopf einer Laufkarte ---------- */
.qs-laufkarte-kopf {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  align-items: flex-start;
}
.qs-lk-feld { display: flex; flex-direction: column; gap: 3px; min-width: 130px; }
.qs-lk-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.qs-lk-wert { font-size: 15px; font-weight: 600; color: var(--text-primary); }

/* Zustandspille des Kartenkopfes. UMBENANNT am 26.08.2026 (Aufgabe 3):
   ist-laeuft / ist-gesperrt / ist-wartend stammten aus der Musterseite und
   sind auf KEINE Spalte abbildbar - qs.laufkarte hat keine Statusspalte und es
   gibt keine Status-Nachschlagetabelle. Geblieben sind die zwei Werte, die die
   Spalte `abgeschlossen` wirklich hergibt. Ein dritter Wert waere eine
   erfundene Wahrheit auf dem Bildschirm.

   ist-offen ist UMRANDET, nicht gefuellt. Grund, gemessen am 26.08.2026:
   weiss auf --brand-primary ergibt 3,67 und reisst damit die 4,5 fuer Text
   (12,5 px fett ist kein Grosstext). Als Rahmen genuegen 3,0, und der Text
   steht mit --text-primary bei 19,17. Gefuellt bleibt nur ist-abgeschlossen:
   --text-secondary auf --gridline ist gemessen 6,00. */
.qs-status {
  display: inline-block;
  padding: 3px 12px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 700;
}
.qs-status.ist-offen {
  background: var(--surface-1);
  color: var(--text-primary);
  box-shadow: inset 0 0 0 1.5px var(--brand-primary);
}
.qs-status.ist-abgeschlossen {
  background: var(--gridline);
  color: var(--text-secondary);
}

/* ---------- Tabellen (fehlen generisch in style.css; table.liste gibt es nur in wartung.css) ---------- */
.qs-tabelle-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-1);
  box-shadow: 0 1px 2px rgba(0,0,0,0.06);
}
.qs-tabelle { width: 100%; border-collapse: collapse; font-size: 13px; }
.qs-tabelle th {
  text-align: left;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  padding: 9px 12px;
  border-bottom: 1px solid var(--baseline);
  white-space: nowrap;
  background: var(--surface-1);
}
.qs-tabelle td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--gridline);
  color: var(--text-primary);
  white-space: nowrap;
}
.qs-tabelle tr:last-child td { border-bottom: none; }
.qs-tabelle tr:hover td { background: var(--weekend-bg); }
.qs-tabelle td.qs-grenzwert { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
/* --text-secondary statt --text-muted: die Fussnote sagt, WAS eine Spalte
   zaehlt, und im Altsystem ist genau diese Spalte nachweislich falsch. Ein
   Satz, der einen Zahlenwert erklaert, darf nicht der schwaechste Text der
   Seite sein. Gemessen: 3,50 gegen 7,73. */
.qs-tabelle-fussnote { font-size: 11.5px; color: var(--text-secondary); margin: 8px 2px 0; }

/* Ergebnisfarben in Tabellenzellen (Text, keine Fläche – siehe Kontrastwerte im Bericht)

   ⚠️ DIE ZWEITE ZEILE JE REGEL IST DER EIGENTLICHE PUNKT und war bis zum
   26.08.2026 nicht da. Gemessen an qs-muster.html: `.qs-io` allein hat die
   Spezifität (0,1,0), `.qs-tabelle td` hat (0,1,1) und setzt `color:
   var(--text-primary)`. Eine Zustandsklasse AN einer Zelle wurde damit
   schwarz — `rgb(11, 11, 11)` statt `rgb(0, 99, 0)`, gemessen, nicht
   überlegt.

   Es war kein theoretischer Mangel: das Freigaberaster der Musterseite trägt
   `qs-tabelle qs-freigabe-tabelle` und setzt die Klassen an die Zellen. Sein
   EINER absichtlicher n.i.O.-Ausreißer war nie rot, sondern schwarz wie alle
   anderen — eine Musterseite, die etwas anderes zeigte, als sie behauptete.

   Die Hausregel bleibt: die Marke gehört in ein `<span>` IN der Zelle. Die
   qualifizierte Fassung ist das Netz darunter, damit eine Klasse an der Zelle
   nicht mehr lautlos schwarz wird. Vorbild: `.qs-tabelle td.qs-grenzwert`. */
.qs-io  { color: var(--success-text); font-weight: 700; }
.qs-tabelle td.qs-io  { color: var(--success-text); }
.qs-nio { color: var(--urgent);       font-weight: 700; }
.qs-tabelle td.qs-nio { color: var(--urgent); }

/* ---------- 3. Erfassungsmaske ---------- */
.qs-fortschritt {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
}
.qs-fortschritt-balken {
  display: inline-block;
  width: 180px;
  height: 6px;
  border-radius: 999px;
  background: var(--gridline);
  overflow: hidden;
}
/* ⚠️ DIE BREITE IST 0 UND KOMMT SONST AUS DEM ZÄHLER. Hier stand
   `width: 4.2%` mit der Begründung „12 von 288 – fest, weil diese Seite
   ohne Daten läuft". Zwei Dinge daran waren falsch:

   1. **288 ist die Zahl einer ANDEREN Maske** (Freigabemessung). Für
      `qs-ipc` lautet sie 28. Ein Balken, der immer auf 4,2 % steht, sieht
      dabei nicht kaputt aus, sondern plausibel — die schlimmste Art
      Platzhalter.
   2. Der naheliegende Ersatz `width: var(--qs-anteil, 0%)` ist eine
      FALLE. Am 27.08.2026 an einer 200-px-Bahn gemessen:
          nicht gesetzt   ->   0 px    (der Ausweichwert greift)
          `10.7%`         ->  21 px
          `NaN%`          -> 200 px    -- die GANZE Bahn
          `Infinity%`     -> 200 px
          `undefined`     -> 200 px
      Der Ausweichwert einer `var()`-Funktion greift nur, wenn die
      Eigenschaft ungesetzt oder leer ist. Bei einem UNGÜLTIGEN Wert wird
      die Deklaration erst bei der Wertberechnung ungültig, und `width`
      fällt auf seinen Anfangswert `auto` — ein Blockelement füllt damit
      seinen Elternknoten. Aus „keine Daten" würde „alles fertig".

      Und `NaN` ist genau, was `0/0` liefert: eine Karte ohne Merkmale.

   Deshalb steht hier `0`, und nur eine GEPRÜFTE Prozentzahl wird nach
   `style.width` geschrieben. Ungültiges erreicht das CSS nie.
   Der Prüffall dazu steht in `qs-erfassung-probe.js` und misst die Falle
   selbst nach — sonst wäre dieser Verzicht eine Behauptung. */
.qs-fortschritt-anteil {
  display: block;
  height: 100%;
  width: 0;
  background: var(--brand-primary);
}

.qs-checkbox-feld {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-secondary);
  margin: 0 0 14px;
  cursor: pointer;
}
.qs-ankreuzfeld {
  width: 16px;
  height: 16px;
  accent-color: var(--brand-primary);
  cursor: pointer;
}

.qs-merkmal-liste { display: flex; flex-direction: column; gap: 14px; }
.qs-merkmal-zeile {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-1);
}
.qs-merkmal-kopf {
  display: flex;
  flex-direction: column;
  min-width: 190px;
  flex: 0 0 190px;
}
.qs-merkmal-nr {
  font-family: var(--font-heading);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
}
.qs-merkmal-name { font-size: 13.5px; color: var(--text-primary); }
/* Die Pruefmittelnummer unter P-Nummer und Namen (08.09.2026, Punkt 2 der
   To-Do-Liste). `display: block` steht mit Absicht da: in der IPC-Maske
   sitzt sie in einem Spalten-Flexkasten und braeuchte es nicht, im
   Freigaberaster aber in einem <th> neben zwei Inline-Spans - ohne die
   Angabe stuende sie dort HINTER dem Namen statt darunter. Eine Regel fuer
   beide Masken, nicht zwei. */
.qs-merkmal-mittel {
  display: block;
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
}

.qs-messwert { display: flex; align-items: center; gap: 10px; flex: 1 1 260px; }
.qs-messwert-eingabe {
  width: 130px;
  font: inherit;
  font-size: 14px;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--page-plane);
  color: var(--text-primary);
}
/* Mangel 1, behoben am 26.08.2026: hier stand `outline: 2px solid
   var(--weekend-bg)`, und --weekend-bg ist rgba(11,11,11,0.035) - 3,5 %
   Deckung, auf --surface-1 praktisch nicht zu sehen. Ein Messwertfeld, dessen
   Fokus man nicht findet, ist im Messraum ein Bedienfehler mit Nachweis.
   --brand-primary steht gemessen bei 3,57 gegen --surface-1: fuer Text zu
   wenig, fuer einen Umriss genug (Schwelle 3,0). */
.qs-messwert-eingabe:focus { outline: 2px solid var(--brand-primary); outline-offset: 1px; border-color: var(--brand-primary); }

/* Die Einheit neben dem Zahlenfeld (Plan 1d, Aufgabe 5). Sie war nicht zu
   sehen: die Spalte `einheit` wird geholt und stand im Bild nirgends - eine
   Spalte zu holen und nicht zu zeigen ist entweder Verschwendung oder ein
   Vergessen, und ein Mass ohne Einheit ist unvollstaendig. Gefunden am
   27.08.2026 im Bildschirmfoto, nicht in einer der 20 Messungen.

   Kraeftiger als .qs-grenzen: die Einheit gehoert zum Wert, die Grenzen sind
   Beiwerk. */
.qs-einheit {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
}
.qs-grenzen { font-size: 12px; color: var(--text-secondary); white-space: nowrap; }

.qs-io-nio { display: flex; gap: 10px; flex: 1 1 auto; }
.qs-btn-io, .qs-btn-nio {
  min-width: 64px;
  min-height: 36px;
  padding: 8px 18px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 14px;
  border-radius: 20px;
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
  cursor: pointer;
}
.qs-btn-io:hover  { border-color: var(--brand-primary); }
.qs-btn-nio:hover { border-color: var(--urgent); }
.qs-btn-io.is-aktiv  { background: var(--brand-primary); border-color: var(--brand-primary); color: #fff; }
.qs-btn-nio.is-aktiv { background: var(--urgent);        border-color: var(--urgent);        color: #fff; }

/* Kleine Knopf-Variante – style.css kennt sie nicht, wartung.css schon
   (dort padding 5px 12px / 12px), hier bewusst als eigene, für QS gedachte
   Definition, bis geklärt ist, ob sie gemeinsam wandert. */
.btn.klein { padding: 5px 12px; font-size: 12px; }

.qs-bemerkung-feld { flex: 1 1 100%; display: flex; flex-direction: column; gap: 4px; }
.qs-bemerkung-feld label { font-size: 12px; font-weight: 600; color: var(--text-secondary); }
.qs-bemerkung {
  width: 100%;
  min-height: 64px;
  font: inherit;
  font-size: 13px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--page-plane);
  color: var(--text-primary);
  resize: vertical;
}

/* Grenzverletzung: roter Rahmen statt roter Fläche, damit der Wert selbst
   lesbar bleibt. Kontrast Rand/Untergrund siehe Bericht (rund 4,7:1).

   ⚠️ SIE STEHT HIER UNTEN, und das ist der Fehler, den sie vorher hatte.
   Gemessen am 27.08.2026: an einer `textarea.qs-bemerkung.qs-feld-verletzt`
   blieb der Rand bei 1 px. Beide Regeln haben die Spezifität (0,1,0), also
   entscheidet allein die Reihenfolge — und `.qs-feld-verletzt` stand VOR
   `.qs-bemerkung`. Am Zahlenfeld wirkte sie (das steht davor), an der Textarea
   versagte sie LAUTLOS: das Feld sah aus wie ein gültiges.

   Verschoben, nicht verdoppelt. Eine qualifizierte Zweitfassung
   `.qs-bemerkung.qs-feld-verletzt` wäre die zweite Stelle für dieselbe Sache —
   und die erste, die abtreibt. Wer künftig ein Feldformat NACH dieser Regel
   einfügt, nimmt ihr die Wirkung an genau diesem Feld. */
.qs-feld-verletzt {
  border: 2px solid var(--urgent);
  background: color-mix(in srgb, var(--urgent) 6%, var(--page-plane));
}

/* ---------- PIN-Tastenfeld (Plan 1d, Aufgabe 1) ----------
   Neu, weil es im ganzen Leitstand keinen Baustein dafür gibt: gemessen am
   27.08.2026 null Treffer für `keypad`, `tastenfeld`, `ziffernblock`, `numpad`
   und `pin-taste`. Vorhanden sind nur die Nachbarteile `.scan-input`
   (7 Dateien), `.btn-touch` (4) und `.scan-dialog-touch` (3).

   ⚠️ `.btn` ist KEINE Grundlage: es kommt mit `padding: 7px 14px` und
   `border-radius: 20px` und ist damit eine Pille, keine Taste.

   ⚠️ DAS FINGERMASS GILT UNBEDINGT und steht deshalb NICHT in den zwei
   Touch-Blöcken. Ein PIN-Feld ist nie eine Bürobedienung — es wird in der
   Halle bedient, mit Handschuh, von jemandem, der in der anderen Hand ein
   Messmittel hält. Ein Maß, das nur am Tablet gilt, wäre hier ein Fehler,
   und die Doppelung wäre sinnlos. Ein Prüffall hält das fest. */
.qs-tastenfeld {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  max-width: 240px;
}
.qs-taste {
  min-width: 48px;
  min-height: 48px;
  font-family: var(--font-body);
  font-size: 20px;
  font-weight: 600;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--page-plane);
  color: var(--text-primary);
  cursor: pointer;
}
/* ⚠️ DIE NULL GEHOERT IN DIE MITTE, gefunden am 27.08.2026 im
   Bildschirmfoto. Ohne diese Regel landet die zehnte Taste in Zeile 4,
   Spalte 1 - also LINKS unten. Auf jedem Telefon- und
   Geldautomatentastenfeld steht die 0 mittig unter der 8, und wer sie dort
   erwartet, greift daneben. Keine Messung zeigt das: zehn Tasten von je
   75x48 px sind zehn Tasten von je 75x48 px, egal wo sie liegen.

   Die Bedingung ist ausdruecklich `:last-child:nth-child(10)` - sie gilt
   also GENAU dann, wenn zehn Tasten da sind und die Null die letzte ist.
   Kommen spaeter "loeschen" und "OK" dazu, greift die Regel nicht mehr, und
   das ist richtig: dann ist die vierte Zeile voll. */
.qs-tastenfeld > .qs-taste:last-child:nth-child(10) { grid-column: 2; }
.qs-taste:hover  { background: var(--weekend-bg); }
.qs-taste:active { background: var(--gridline); }
/* Sichtbar, und NICHT `--weekend-bg`: das misst 1,08 gegen den Untergrund und
   war Mangel 1 aus Plan 1c, Aufgabe 3. */
.qs-taste:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}

/* ---------- Maßnahmenfeld (Plan 1d, Aufgabe 1) ----------
   Die Steuer ist `.qs-bemerkung` — kein zweites Textfeldformat. Damit gilt für
   sie auch die eigene 96-px-Regel des coarse-Blocks, die man nicht mit der
   44-px-Eingaberegel zusammenlegen darf (sonst schrumpft sie am Tablet).

   Neu ist nur die sichtbare PFLICHT, und die ist nicht Zierde: die Datenbank
   erzwingt `massnahme` mit ABSICHT nicht — ein CHECK, der n.i.O. ohne Maßnahme
   abweist, führt dazu, dass gar nichts erfasst wird. Die Maske verlangt es,
   also muss die Maske es auch zeigen. Das Feld erscheint ohnehin nur bei
   n.i.O., die Marke ist dort immer wahr. */
.qs-massnahme-feld {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.qs-massnahme-feld label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
}
.qs-massnahme-feld label::after {
  content: '\00A0(Pflicht)';
  font-weight: 700;
  color: var(--urgent);
}

/* ⚠️ HIER STAND `.qs-massnahme-feld.ist-freiwillig` (27.08.2026, Aufgabe 8):
   ein Feld, das nach einer Korrektur von n.i.O. auf i.O. mit seinem Text
   stehen blieb, aber ohne die Pflichtmarke. Am 28.08.2026 entfernt — Aufgabe 8
   ist zurückgenommen (`qs-ipc` verlangt keine Maßnahme mehr, Schlechtteile
   gehören zur Freigabemessung), und damit gibt es den Fall nicht mehr.

   ⚠️ DER BLOCK DARÜBER BLEIBT. Er ist ein Baustein aus Aufgabe 1, und die
   FREIGABEMESSUNG wird ihn brauchen. Heute benutzt ihn keine Seite. */

/* ---------- Fortsetzung, Gerät und gespeicherte Zelle (Plan 1d, Aufgaben 9–11) ----------

   Vier Bausteine, und drei davon sagen etwas ÜBER die Daten statt Daten zu
   zeigen. Deshalb ist ihre Farbe eine Aussage:

   - Die Sitzungszeile ist INFORMATION („begonnen von MK“) und bleibt leise.
   - Der Gerätehinweis ist eine WARNUNG und steht nur da, wenn etwas nicht
     stimmt. Er darf --urgent tragen: ein Gerät, das nicht sichert, kostet
     Messungen.
   - Der Zeilenhinweis ist eine ABWEISUNG („nichts zu übernehmen“) und
     ebenfalls --urgent.
   - Der gespeicherte Wert ist ein WERT und trägt gar keine Zustandsfarbe. */
.qs-sitzung-zeile {
  margin: 0 0 10px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-secondary);
}
.qs-geraet-hinweis {
  margin: 0 0 12px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--urgent);
}

/* ⚠️ EINE GESPEICHERTE ZELLE SIEHT AUS WIE EIN WERT, NICHT WIE EIN GESPERRTES
   FELD. Kein Rahmen, kein Kasten, kein Grau: sie ist FERTIG, nicht verboten.

   Das ist der Unterschied, auf den Schritt 8 sieht. Ein ausgegrautes Feld an
   dieser Stelle hieße „hier darfst du nicht“, und der Prüfer sucht den Grund.
   Richtig ist „hier steht schon etwas“ — der Wert ist gemessen, gespeichert
   und über Storno korrigierbar (Auftragsblatt, Abschnitt 4.5). Ein Feld wäre
   hier ohnehin sinnlos: der unique index über
   (messsitzung_id, laufkarte_merkmal_id, teil_nr) lässt eine zweite Zelle
   nicht zu, seine Benutzung könnte nur mit 23505 abbrechen.

   Ziffernbreite fest (tabular-nums): darunter stehen die Grenzen mit
   denselben Stellen, und springende Ziffernbreiten machen den Vergleich
   schwer. */
.qs-gespeicherter-wert {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Der Hinweis an der Zeile bekommt die GANZE Breite, damit er nicht zwischen
   Feld und Grenzen gequetscht wird - er ist ein Satz, keine Marke. */
.qs-zeilen-hinweis {
  flex: 1 1 100%;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--urgent);
}
/* Derselbe Platz, andere Bedeutung: eine ABWEISUNG ist rot, eine AUSKUNFT
   nicht. „Diese Zelle ist von TM belegt“ ist kein Fehler des Prüfers - es ist
   der Grund, warum seine Bewertung eine alte Zelle storniert. --urgent würde
   ihn nach einem Fehler suchen lassen, den er nicht gemacht hat. */
.qs-zeilen-hinweis.ist-sachlich {
  font-weight: 400;
  color: var(--text-secondary);
}

/* ---------- 4. Freigaberaster ---------- */
.qs-freigabe-wrap { max-width: 100%; overflow-x: auto; }
/* ⚠️ KEINE FESTE MINDESTBREITE MEHR (war 1300px, 14.09.2026). Sie war der
   Grund, warum der Balken auch bei DREI Teilen erschien, wo vier Spalten
   locker in die Huelle passen: die Tabelle forderte 1300 px, die Spalte gab
   1096. Die Breite kommt jetzt aus den Spalten selbst. */
.qs-freigabe-tabelle { min-width: 100%; }
.qs-freigabe-tabelle th:first-child,
.qs-freigabe-tabelle td:first-child {
  position: sticky;
  left: 0;
  min-width: 150px;
  /* ⚠️ DIE MERKMALSPALTE DARF UMBRECHEN (14.09.2026). Sie war 462 px breit,
     weil .qs-tabelle th white-space: nowrap setzt und die Zeile
     "Soll 120,000 · UTG 119,900 · OTG 120,100" eben so lang ist. Das sind
     drei Teilspalten, die dafuer draufgehen. Im Altsystem ist dieselbe
     Spalte schmal - weil sie dort umbricht. Der Deckel begrenzt sie nach
     oben, min-width: 150px haelt sie nach unten. */
  max-width: 200px;
  white-space: normal;
  background: var(--surface-1);
  border-right: 1px solid var(--border);
  z-index: 1;
}
.qs-freigabe-tabelle th:first-child { z-index: 2; }
/* ⚠️ 82 PX STATT 92, und die Zahl ist gemessen, nicht geschaetzt: der
   laengste Wert, der hier vorkommen kann, ist ein negatives Mass mit drei
   Nachkommastellen ("-120,000"). Bei 13 px Poppins sind das 54 px Text,
   dazu 12 px Polster und 2 px Rahmen = 68 px - und genau 68 waeren
   RANDVOLL. Deshalb 70 px Eingabe (unten) mit 2 px Luft, plus 12 px
   Zellpolster = 82 px. Wer die Eingabe weiter verschmaelert, schneidet
   Messwerte ab - und ein abgeschnittener Messwert ist schlimmer als ein
   Balken. Dagegen steht ein eigener Pruefall in qs-freigabe-probe.js. */
.qs-freigabe-tabelle th:not(:first-child),
.qs-freigabe-tabelle td:not(:first-child) {
  min-width: 82px;
  text-align: center;
}

/* ---------- 5. Urwertkarte ---------- */
.qs-urwertkarte-svg { display: block; width: 100%; height: auto; }
/* Die Legende der Sammelansicht. Bis zum 13.09.2026 war sie ein einzelnes
   <p>; seither traegt sie die Zuordnung der Linien, die vorher als „P3" am
   rechten Bildrand stand. Deshalb ein <div> mit einer Reihenliste und zwei
   Absaetzen. */
.qs-urwertkarte-legende {
  margin: 10px 2px 0;
  font-size: 12px;
  color: var(--text-secondary);
}
.qs-urwertkarte-legende p { margin: 6px 0 0; }

/* Die Reihen liegen NEBENEINANDER und brechen um. Untereinander braechte bei
   sieben Merkmalen sieben Zeilen unter einem 220 px hohen Bild - die Legende
   waere dann hoeher als das, was sie erklaert. */
.qs-legende-reihen {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.qs-legende-reihe {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--text-primary);
}
/* ⚠️ flex: none. Ohne die Angabe staucht der Flexkasten den Musterstrich,
   sobald eine Zeile eng wird - und ein gestauchtes Strichmuster ist nicht
   mehr dasselbe Muster wie im Bild, also keine Zuordnung mehr. */
.qs-legende-muster { flex: none; }
/* Farbe UND Fettschrift, und im Text steht zusaetzlich „außerhalb der
   Toleranz": --urgent steht gemessen bei 4,69 (ueber der Textschwelle 4,5),
   aber Farbe allein trennt nicht, wenn jemand Rot und Gruen nicht
   unterscheidet. */
.qs-legende-nio {
  color: var(--urgent);
  font-weight: 700;
}

/* Tabellenueberschrift. NEU am 26.08.2026 fuer den Kennzahlenblock: die
   Stueckzahltabelle braucht einen zugaenglichen Namen, und <caption> ist
   dafuer das richtige Element - eine Ueberschrift daneben ist keine Bindung.
   Ohne Regel stellte der Browser sie zentriert und in Tabellenschrift dar.
   --text-secondary, NICHT --text-muted: --text-muted steht gemessen bei 3,50
   und reisst die 4,5, die dieses Projekt selbst verlangt. Dieselbe
   Entscheidung wie bei .qs-keine-aussage. */
.qs-tabelle caption {
  caption-side: top;
  text-align: left;
  padding: 0 0 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-secondary);
}

/* ---------- 6. Kennzahlenblock ---------- */
.qs-kennzahlen { display: flex; flex-wrap: wrap; gap: 14px; }
.qs-kennzahl { flex: 1 1 220px; text-align: center; }
.qs-kennzahl h3 {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.qs-kennzahl-wert {
  font-family: var(--font-heading);
  font-size: 32px;
  font-weight: 700;
  color: var(--text-primary);
  margin: 4px 0;
}
.qs-kennzahl-formel {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px;
  color: var(--text-secondary);
}
.qs-kennzahl-hinweis { font-size: 11.5px; color: var(--text-muted); }

/* „keine Aussage" bewusst klein/kursiv/gedämpft statt einer erfundenen
   Zahl – siehe Auftrag: zwei von drei Faktoren fehlen noch.
   --text-secondary statt --text-muted (26.08.2026): das ist der Urtyp der
   urteilsfreien Marke, und gedaempft heisst nicht unlesbar. Gemessen 3,50
   gegen 7,73 auf --surface-1. Kursiv und klein tragen die Zurueckhaltung
   schon, dafuer braucht es keinen Kontrastverstoss. */
.qs-kennzahl-unbekannt .qs-kennzahl-wert {
  font-size: 19px;
  font-weight: 600;
  font-style: italic;
  color: var(--text-secondary);
}

/* ---------- 7. Arbeitsliste ---------- */
/* UMBENANNT am 26.08.2026: hiess .qs-kein-intervall und war damit an einen
   einzigen Anwendungsfall gebunden, obwohl die Regel neutral ist. Der alte
   Name bleibt als Zwilling stehen, solange qs-muster.html ihn benutzt.
   --text-secondary statt --text-muted: gemessen 7,73 gegen 3,50, und 3,50
   reisst die 4,5, die dieses Projekt selbst verlangt. */
.qs-keine-aussage,
.qs-kein-intervall { color: var(--text-secondary); font-style: italic; }

/* Mangel 3, behoben am 26.08.2026. .qs-dringend und .qs-nio waren am Gerät
   NICHT unterscheidbar - beide `rgb(230, 0, 0)` bei Fettgrad 700, gemessen.
   In einer Liste heisst das: NIO und "dringend" sehen gleich aus, und wer
   die Liste ueberfliegt, haelt eine Faelligkeit fuer einen Fehler.
   Unterschieden wird jetzt ueber die FORM, nicht ueber eine neue Farbe: die
   Dringlichkeit bekommt einen linken Balken, das Urteil bleibt blanker Text.

   ⚠️ Diese Marke hat in v_laufkarte_liste KEINE Quelle. Es gibt kein
   Faelligkeitsfeld, und die Vorfahrtsregel fuer `messintervall` ist einer der
   vier offenen Blocker. Sie ist gebaut, damit sie unterscheidbar IST, wenn es
   die Quelle gibt - keine Seite darf sie vorher setzen. */
.qs-dringend {
  color: var(--urgent);
  font-weight: 700;
  border-left: 3px solid var(--urgent);
  padding-left: 6px;
}

/* =========================================================
   9. Zustandsmarken der Kartenliste  (neu am 26.08.2026, Aufgabe 3)
   =========================================================

   SIEBEN Marken, aus Spezifikation 4.3: fuenf IPC-Faelle (n.i.O. · i.O. ·
   abgeschlossen ohne Wert · gemessen ohne errechenbares Urteil · nie
   gemessen), quer dazu `abgeschlossen`, und `storniert`.

   ⚠️ qs-laufkarten benutzt davon SECHS. `storniert` hat in
   v_laufkarte_liste keine Spalte, und qs.laufkarte ist nicht stornierbar -
   storniert werden Messwert, Messsitzung und Mengenmeldung. Die Marke steht
   hier fuer die Messungsliste in qs-laufkarte, nicht fuer die Kartenliste.

   DREI FARBEN, KEINE NEUE. Gemessen am 26.08.2026 gegen --surface-1
   (#fcfcfb), Schwelle 4,5 fuer Text:
     --success-text   #006300   7,35   ✓   nur i.O.
     --urgent         #e60000   4,69   ✓   nur n.i.O.
     --text-secondary #52514e   7,73   ✓   alle vier urteilsfreien Faelle
     --text-muted     #898781   3,50   ✗   reisst die eigene Schwelle
   Deshalb steht --text-secondary hier und nicht --text-muted.

   Vier der sieben Marken tragen damit DIESELBE Farbe. Das ist Absicht - sie
   sagen alle "keine Aussage", und aus Abwesenheit wird nie Gruen. Unterschieden
   werden sie ueber FORM und WORTLAUT, nicht ueber eine erfundene Farbe:
     ist-nie-gemessen     kursiv, ohne Rahmen   - es ist nichts geschehen
     ist-ohne-wert        gepunktete Unterlinie - es ist etwas geschehen, aber
                                                  nichts dabei herausgekommen
     ist-ohne-urteil      gepunkteter Rahmen    - gemessen, nicht beurteilbar
     ist-abgeschlossen    geschlossener Rahmen  - die Karte ist zu
     ist-storniert        durchgestrichen       - das einzige allgemein
                                                  verstaendliche Storno-Zeichen

   ABNAHMEPUNKT der Aufgabe: eine Marke OHNE Zustandsklasse sieht nicht gruen
   aus. Die Grundregel setzt --text-secondary, nicht --success-text - wer eine
   Zustandsklasse vergisst, bekommt "keine Aussage" und keine falsche Ampel. */
.qs-marke {
  display: inline-block;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.4;
  white-space: nowrap;
  color: var(--text-secondary);
}
/* Qualifiziert wird NUR die Klasse AN der Zelle (`td.qs-marke`), nie der
   Nachfahre (`td .qs-marke`).

   ⚠️ Das ist keine Feinheit, sondern ein Fehler, den die Gegenprobe am
   26.08.2026 aufgedeckt hat. Hier stand zuerst auch `.qs-tabelle td
   .qs-marke` - ein Nachfahrenselektor mit der Spezifitaet (0,2,1). Der
   ueberstimmt JEDE unqualifizierte Zustandsregel `.qs-marke.ist-io` mit
   (0,2,0): eine Marke im Span wurde grau statt gruen. Gemessen
   rgb(82, 81, 78) statt rgb(0, 99, 0).

   Es fiel nur nicht auf, weil daneben die qualifizierten Zwillinge standen
   und den Schaden ausglichen. Wer eine achte Marke ergaenzt und den Zwilling
   vergisst, bekommt in einer Tabelle lautlos Grau - genau die Fehlerklasse,
   gegen die diese Aufgabe angetreten ist.

   Ein Span BRAUCHT keine qualifizierte Fassung: `.qs-tabelle td` faerbt die
   Zelle, nicht das Kind, und `.qs-marke` am Span gewinnt dort immer. */
.qs-tabelle td.qs-marke { color: var(--text-secondary); }

.qs-marke.ist-io  { color: var(--success-text); }
.qs-tabelle td.qs-marke.ist-io { color: var(--success-text); }

.qs-marke.ist-nio { color: var(--urgent); }
.qs-tabelle td.qs-marke.ist-nio { color: var(--urgent); }

.qs-marke.ist-nie-gemessen { font-style: italic; font-weight: 600; }
.qs-marke.ist-ohne-wert {
  font-weight: 600;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}
.qs-marke.ist-ohne-urteil {
  font-weight: 600;
  border: 1px dotted var(--baseline);
  border-radius: 4px;
  padding: 0 6px;
}
.qs-marke.ist-abgeschlossen {
  font-weight: 600;
  border: 1px solid var(--baseline);
  border-radius: 999px;
  padding: 0 8px;
}
.qs-marke.ist-storniert { font-weight: 600; text-decoration: line-through; }

/* Zwei Marken für die ÜBERTRAGUNG, nicht für das Urteil (Plan 1d,
   Aufgabe 1). Sie sitzen auf derselben Achse wie `ist-abgeschlossen` und
   `ist-storniert` — „was ist mit dieser Zeile passiert" —, nicht auf der
   Achse `ist-io`/`ist-nio`.

   ⚠️ KEINE URTEILSFARBE, und das ist der Kern. Grün heißt in diesem Modul
   „Maß in Ordnung". Ein gespeicherter n.i.O.-Wert ist gespeichert UND
   n.i.O. — zwei Achsen, und die Farbe ist für die andere vergeben. Beide
   bleiben deshalb auf `--text-secondary` aus der Grundregel und
   unterscheiden sich durch FORM: gefüllter gegen offenen Ring.

   Und die laute ist die UNFERTIGE. In der Halle muss auffallen, was noch
   im Gerät liegt, nicht was durch ist.

   ⚠️ Kein qualifizierter Zwilling nötig, und das ist nachgesehen, nicht
   vergessen: der Zwilling `.qs-tabelle td.qs-marke.X` braucht es nur,
   wenn die Marke `color` setzt — diese zwei tun es nicht. Den Rahmen
   nimmt ihnen die generische Regel `.qs-tabelle td.qs-marke` (border-left:
   none) schon ab, also zerreißt keine von beiden das Tabellengitter. Ein
   Prüffall misst genau das. */
/* ⚠️ DIE ZEICHEN WAREN VERTAUSCHT, gefunden am 27.08.2026 im
   Bildschirmfoto - Schritt 6 der Aufgabe 1, und von KEINER der 19 Messungen
   gezeigt.

   Zuerst stand hier: gespeichert = gefuellter Ring, nicht gesendet = offener
   Ring plus gestrichelter Rand. Die Messung sagte, die zweite sei die
   lautere - Schriftgewicht 700 gegen 600, dazu ein Rahmen. Das war richtig
   gemessen und im Bild trotzdem falsch:

     - Ein GEFUELLTER Punkt zieht den Blick, ein offener Ring nicht. Die
       fertige Zeile war damit auffaelliger als die unfertige.
     - Der GESTRICHELTE Rand liest sich bei 12,5 px nicht als Betonung,
       sondern wie ein Darstellungsfehler - drei kurze Striche neben einem
       Wort sehen aus wie Schmutz.

   Jetzt: fertig = Haekchen und leise, unfertig = gefuellter Punkt, volles
   Gewicht und ein DURCHGEHENDER linker Balken. Der durchgehende Balken ist
   dieselbe Sprache wie `.qs-band` - vier Pixel links heisst dort schon
   "diese Zeile ist markiert".

   ⚠️ Eine Messung kann "lauter" nicht pruefen. Der Prueffall haelt
   deshalb die ENTSCHEIDUNG fest: welches der zwei Zeichen wo steht. Sonst
   dreht es jemand still zurueck. */
.qs-marke.ist-gespeichert { font-weight: 600; }
.qs-marke.ist-gespeichert::before { content: '✓ '; }
.qs-marke.ist-nicht-gesendet {
  font-weight: 700;
  border-left: 3px solid var(--baseline);
  padding-left: 7px;
}
.qs-marke.ist-nicht-gesendet::before { content: '● '; }

/* ⚠️ DIE FORM GEHOERT IN DEN SPAN, das Netz an der Zelle traegt nur Farbe und
   Schriftbild. Am Bild gefunden, nicht an den Zahlen (26.08.2026): ein
   `border` an einem `td` ersetzt die ZEILENTRENNLINIE der Tabelle. Gemessen an
   der Probeseite, jeweils border-bottom des Zellenfalls:
     ist-ohne-urteil    dotted 1px statt solid 1px  - Gitter gestrichelt
     ist-abgeschlossen  solid 1px --baseline        - Gitter dunkler
     ist-storniert      none 0px                    - Trennlinie WEG
   Eine Liste mit stellenweise fehlender Trennlinie sieht aus wie ein
   Darstellungsfehler, und der Grund dafuer steht drei Regeln weiter oben.

   Zurueckgenommen wird nur der KASTEN. Kursiv, Unterstrich und Durchstreichung
   bleiben - sie tragen Bedeutung und beruehren das Gitter nicht. Die zwei
   Ringmarken verlieren im Zellenfall ihren Ring; genau die zwei sind es, deren
   Ring das Gitter zerreisst. Das Netz soll nicht schoen sein, sondern
   verhindern, dass etwas lautlos falsch aussieht. */
.qs-tabelle td.qs-marke {
  /* ⚠️ DAS SCHWERSTE ZUERST: `display: table-cell` zurueckholen. Die
     Grundregel .qs-marke setzt `inline-block`, und an einem `td` heisst das,
     dass die Zelle KEINE Tabellenzelle mehr ist. Gemessen am 26.08.2026 an
     der Probeseite: 44,6 px breit statt 281,9 px, die Spalte faellt aus dem
     Gitter. Das war im Bild als zu kurze Trennlinie zu sehen und in keiner
     einzigen Farbmessung. */
  display: table-cell;
  border-top: none;
  border-left: none;
  border-right: none;
  border-bottom: 1px solid var(--gridline);
  border-radius: 0;
  padding: 9px 12px;
}
.qs-tabelle tr:last-child td.qs-marke { border-bottom: none; }

/* =========================================================
   10. Tastaturmarkierung  (Mangel 2, behoben am 26.08.2026)
   =========================================================

   Gemessen am 26.08.2026 an der geladenen Seite: im ganzen Projekt gibt es
   DREI Regeln, die `focus` nennen, und alle drei sind ein blankes `:focus`.
   `:focus-visible` kommt in style.css und qs.css nicht ein einziges Mal vor.
   .qs-btn-io und .qs-btn-nio hatten damit keine Tastaturmarkierung - im
   Messraum wird mit Tastatur gearbeitet, und die IO/NIO-Knoepfe sind der
   Weg, auf dem ein Urteil entsteht.

   :focus-visible statt :focus, damit ein Mausklick keinen Rahmen stehen
   laesst. Der Umriss sitzt AUSSERHALB (outline-offset), sonst verdeckt er
   bei einem gefuellten Knopf seine eigene Kante. */
.qs-btn-io:focus-visible,
.qs-btn-nio:focus-visible,
.qs-ankreuzfeld:focus-visible,
.qs-marke a:focus-visible,
.qs-tabelle a:focus-visible,
.qs-band a:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* =========================================================
   11. Drei Bausteine, die die Kartenliste braucht
        (Aufgabe 3 baut sie, Aufgabe 4 benutzt sie)
   ========================================================= */

/* Meldeband ueber der Liste. Drei Auspraegungen nach e.qsArt, NICHT nach
   Meldungstext: 'netz' und 'unbekannt' laufen als ist-fehler, 'recht' und
   'anmeldung' als ist-recht, 'einstellung' und 'aufbau' als ist-einstellung.
   Der Grund fuer die Trennung ist nicht Farbe, sondern was der Bediener tun
   kann: nochmal versuchen, sich anmelden, oder jemanden holen.

   Alle drei tragen --text-primary auf einer sehr blassen Flaeche (19,17
   gemessen). Ein Band mit weissem Text auf --urgent waere 4,81 und damit
   knapp - und der Text eines Fehlerbandes ist die Stelle, an der man nicht
   knapp sein will. Getragen wird die Bedeutung vom linken Balken. */
.qs-band {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 14px;
  margin: 0 0 12px;
  border-radius: 8px;
  font-size: 13px;
  color: var(--text-primary);
  background: var(--weekend-bg);
  border-left: 4px solid var(--baseline);
}
.qs-band.ist-fehler      { border-left-color: var(--urgent); }
.qs-band.ist-recht       { border-left-color: var(--brand-primary); }
.qs-band.ist-einstellung { border-left-color: var(--baseline); }
.qs-band-text { margin: 0; }
.qs-band-grund { margin: 4px 0 0; font-size: 12px; color: var(--text-secondary); }

/* Leerzustand. Steht in keiner gelesenen Datei des Projekts.
   ⚠️ Er gehoert AUSSCHLIESSLICH zu `gesamt === 0`. Bei `gesamt === null`
   heisst es "nicht gezaehlt", und dann darf hier nichts stehen - sonst
   behauptet die Seite Leere, wo nur der Zaehler fehlt. */
.qs-leer {
  padding: 28px 16px;
  text-align: center;
  color: var(--text-secondary);
  font-size: 14px;
}
.qs-leer-titel { display: block; font-weight: 700; margin-bottom: 4px; color: var(--text-primary); }

/* Filterzeile (Aufgabe 6). Sie uebernimmt .parts-kopf und .part-search aus
   style.css; hier steht nur, was dort fehlt: der Umbruch (die Zeile traegt
   neun Bedienelemente, .parts-kopf ist fuer drei gebaut) und die Beschriftung
   UEBER dem Feld. Ein nacktes <select> hat im ganzen Projekt kein Format -
   das, und die Fingerhoehe am Tablet, ist Aufgabe 8. */
.qs-filterzeile { flex-wrap: wrap; align-items: flex-end; }
.qs-filter-feld {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
}
/* ⚠️ DIESE REGEL IST KEIN FEINSCHLIFF. `.part-search` aus style.css traegt
   `flex: 0 1 420px`. Die Beschriftung steht hier UEBER dem Feld, `.qs-filter-feld`
   ist also ein SPALTEN-Flexkasten - und dort ist die Hauptachse senkrecht. Aus
   den 420 px wird eine HOEHE. Am Bild gemessen am 26.08.2026: das Suchfeld war
   420 px hoch und schob die halbe Seite nach unten. Keine Farb- und keine
   Wertmessung hat das gemeldet.
   Deshalb `flex: 0 0 auto` und eine ausdrueckliche Breite - fuer alle drei
   Arten von Bedienelement, nicht nur fuer die Textfelder. */
.qs-filter-feld .part-search,
.qs-filter-feld select,
.qs-filter-feld input[type="date"] {
  flex: 0 0 auto;
  width: 190px;
}
.qs-filter-feld .part-search.qs-filter-breit { width: 320px; }

/* ---------- Anlegemaske (Aufgabe 5) ----------
   Sie ist gesperrt, solange QSDB.schreibe() fehlt. Das Aussehen sagt das
   NICHT durch Ausgrauen der Felder: die Felder sind bedienbar, damit die drei
   Waechter zu sehen sind. Gesperrt ist der Knopf, und darueber steht der
   Grund als Satz.

   ⚠️ Keine neue Farbe. `.qs-anlegen-zu` nimmt --text-secondary und NICHT
   --text-muted: das misst hell 3,50 und reisst den eigenen 4,5-Anspruch
   dieses Projekts. Gemessen am 26.08.2026, gilt fuer alle acht Fundstellen.

   ⚠️ `.qs-stamm-hinweis.ist-da` wird NICHT gruen. Es ist keine Beurteilung,
   sondern eine Auskunft - "diese Nummer liegt schon vor" ist weder gut noch
   schlecht. Gruen waere hier genau die Verwechslung, die dieses Modul
   sonst bekaempft. */

.qs-anlegen {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-1);
  padding: 0 14px;
  margin: 14px 0 4px;
}

.qs-anlegen[open] { padding-bottom: 12px; }

.qs-anlegen-griff {
  cursor: pointer;
  padding: 11px 0;
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
}

/* Der Fokusrahmen ist SICHTBAR. Der Mangel, den Aufgabe 3 an vier Stellen
   behoben hat, wird hier nicht neu gemacht: --weekend-bg misst 1,08. */
.qs-anlegen-griff:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}

.qs-anlegen-zu {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 400;
  color: var(--text-secondary);
}

.qs-anlegen-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin: 10px 0 0;
}

.qs-anlegen-form input[type="number"] { flex: 0 0 auto; width: 90px; }

.qs-vorschlag { margin-top: 8px; }

.qs-stamm-hinweis {
  font-size: 12.5px;
  color: var(--text-secondary);
  margin: 8px 2px 0;
  min-height: 1.2em;
}

.qs-stamm-hinweis.ist-da { color: var(--text-primary); font-weight: 600; }

/* ---------- Anlegen in zwei Schritten (Scheibe 3, 05.09.2026) ----------
   Die Form ist nur noch der Rahmen; jeder Schritt ist die Flex-Zeile, die
   die Form bis dahin selbst war. Die alte Regel `.qs-anlegen-form { display:
   flex }` oben bleibt stehen und wird hier auf block gestellt - gap und
   align-items sind auf einem Block wirkungslos, stoeren aber nicht.

   ⚠️ [hidden] steht hier AUSDRUECKLICH, obwohl style.css `[hidden] {
   display: none !important }` fuehrt: qs.css muss auch ohne style.css richtig
   sein (Probeseiten aus Seiten\ heraus), und display:flex an einer Klasse
   gewaenne sonst gegen das Attribut - dieselbe Falle wie .netz-hinweis. */
.qs-anlegen-form { display: block; }
.qs-anlegen-schritt {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
}
.qs-anlegen-schritt[hidden] { display: none; }

/* Scheibe 8 (06.09.2026): die Maske nach dem Altsystem-Screenshot.

   Drei Formen, drei Gruende:

   .qs-feld-schmal  Spannung und Kalenderwoche sind ein- bis zweistellig. Ein
                    Feld in voller Breite fuer eine "1" sieht aus, als fehle
                    etwas - und es draengt die naechste Zeile um.

   .qs-zeitfeld     Stunden : Minuten : Sekunden gehoeren ZUSAMMEN und muessen
                    das auch aussehen. Ein <fieldset> statt drei einzelner
                    Beschriftungen: die drei sind EIN Wert, und ein
                    Bildschirmleser soll das hoeren, nicht raten.

   .qs-anlegen-riegel  Die Bestaetigung steht auf einer EIGENEN Zeile ueber dem
                    Knopf, nicht neben ihm. Im Screenshot steht sie links vom
                    Knopf; in einer Zeile, die umbrechen darf, landete sie bei
                    schmalem Fenster irgendwo - und ein Riegel, den man
                    uebersieht, ist ein Aergernis ohne Nutzen.

   ⚠️ KEIN eigenes Format fuer die Zahlenfelder darin: sie erben die 90 px aus
   .qs-anlegen-form input[type="number"] weiter oben. Eine zweite Breite hier
   liefe bei der naechsten Aenderung neben der ersten her. */
.qs-filter-feld.qs-feld-schmal .part-search { width: 90px; }
.qs-zeitfeld {
  display: flex;
  /* ⚠️ flex-direction MUSS HIER STEHEN. Das <fieldset> traegt AUCH
     .qs-filter-feld, und die ist ein SPALTEN-Flexkasten (flex-direction:
     column, Zeile 918). `display: flex` allein ueberschreibt die Richtung
     nicht - die drei Zeitfelder standen deshalb UNTEREINANDER, mit zwei
     einsamen Doppelpunkten dazwischen. Am 06.09.2026 am Bild gemessen: die
     drei Eingaben lagen auf y=155, 231 und 307 statt nebeneinander.

     Es ist dieselbe Falle, vor der der Kommentar bei .qs-filter-feld seit
     dem 26.08.2026 warnt: wer die Hauptachse nicht mitliest, bekommt aus
     einer Breite eine Hoehe - oder aus einer Zeile eine Spalte. */
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 4px;
  margin: 0;
  padding: 0;
  border: 0;
  /* ⚠️ DIE BREITE STEHT AUSDRUECKLICH DA, und das ist am 06.09.2026 am
     Bild gemessen worden, nicht geschaetzt. Ohne sie bemisst sich das
     <fieldset> als Flex-Element nach seinem Inhalt, die Beschriftung darin
     verlangt aber 100 % genau dieser Breite - die Rechnung dreht sich im
     Kreis, und der Browser loest sie auf, indem er die drei Felder
     UNTEREINANDER stellt. Aus "0 : 24 : 00" wurde eine Spalte mit drei
     Kaestchen und zwei einsamen Doppelpunkten daneben.
     3 x 72 px + 2 x 4 px Luecke + 2 Doppelpunkte = 248 px. */
  flex: 0 0 248px;
}
.qs-zeitfeld legend {
  /* Ein <legend> sitzt von Haus aus IM Rahmen. Der Rahmen ist hier weg; als
     Flex-Element nimmt es die ganze Zeile und die drei Felder ruecken
     darunter - genau so, wie es sein soll. KEIN float: in einem
     Flex-Behaelter wirkt float nicht, und die Regel taeuschte nur. */
  flex: 0 0 100%;
  padding: 0;
  margin: 0 0 4px;
  font-size: 12px;
  color: var(--text-secondary, #555);
}
.qs-zeitfeld .part-search { width: 72px; }
.qs-zeit-punkt {
  padding-bottom: 8px;
  font-weight: 600;
  color: var(--text-secondary, #555);
}
.qs-anlegen-riegel {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 4px 0 0;
  /* Fingerhoehe am Tablet: die Kaestchen des Browsers sind 13 px gross, und
     13 px trifft niemand mit dem Daumen. */
  min-height: 32px;
  cursor: pointer;
}
.qs-anlegen-riegel input[type="checkbox"] {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  cursor: pointer;
}
.qs-anlegen-kopf {
  width: 100%;
  margin: 4px 0 0;
  font-weight: 600;
  color: var(--text-primary);
}
.qs-anlegen-leiste {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  width: 100%;
}
.qs-anlegen-leiste .btn[hidden] { display: none; }

/* Die Punkttabelle. Die Felder sind schmal, aber nie unter 64 px - eine
   Toleranz wie 12,345678 muss ganz zu sehen sein. Gesperrte Felder (die
   andere Messart) sind grau, nicht weg: die Spalte bleibt lesbar. */
.qs-punkte-wrap { width: 100%; }
.qs-punkte th { white-space: nowrap; }
.qs-punkte td { padding: 4px 6px; vertical-align: middle; }
.qs-punkte input[type="text"],
.qs-punkte input[type="number"],
.qs-punkte select {
  box-sizing: border-box;
  width: 100%;
  min-width: 64px;
  padding: 6px 8px;
  font-size: 13px;
  font-family: var(--font-body);
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-1);
  color: var(--text-primary);
}
.qs-punkte input.qs-punkt-kurz,
.qs-punkte input[type="number"] { width: 64px; min-width: 64px; }
.qs-punkte input.qs-punkt-breit { min-width: 160px; }
.qs-punkte input:disabled {
  background: var(--gridline);
  color: var(--text-secondary);
}
.qs-punkte input[type="checkbox"] { width: 20px; height: 20px; }
.qs-punkte input:focus-visible,
.qs-punkte select:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 1px;
}

/* ---------- Auswahlliste (Aufgabe 8) ----------
   Fuer ein nacktes <select> gibt es im ganzen Projekt KEIN Format - gemessen
   am 26.08.2026 in style.css: die sechs Treffer sind `user-select`, ein
   Dialog-Sammelselektor und zwei seitenlokale Regeln der Maschinenzeile. Ein
   ungeformtes select neben .part-search sieht aus wie ein Fremdkoerper.

   Der Pfeil bleibt der des Systems. `appearance: none` wuerde ihn entfernen und
   verlangte, einen eigenen zu zeichnen - ein Bild mehr, das in zwei Themen
   stimmen muss, fuer nichts. Geformt wird der Kasten, nicht der Pfeil. */
.qs-auswahl,
.qs-filter-feld select {
  font-family: inherit;
  font-size: 15px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--page-plane);
  color: var(--text-primary);
}
.qs-auswahl:focus-visible,
.qs-filter-feld select:focus-visible,
.qs-filter-feld input[type="date"]:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 1px;
}

/* Datumsfelder: dieselbe Huelle wie die Auswahlliste, damit die Zeile nicht
   aus drei verschiedenen Kaesten besteht. */
.qs-filter-feld input[type="date"] {
  font-family: inherit;
  font-size: 15px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--page-plane);
  color: var(--text-primary);
}

/* ---------- Gekuerzt angezeigte Maszahl (Aufgabe 9) ----------
   Grenzen werden mit VIER Nachkommastellen angezeigt, gespeichert wird mit
   sechs. Stehen hinter der vierten Stelle noch Ziffern ausser Null, traegt der
   Wert dieses Kreuz und den genauen Wert im Hinweistext.

   ⚠️ Das ist keine Zierde. Eine still auf vier Stellen gerundete Grenze ist
   eine ANDERE Grenze als die gespeicherte, und ein Pruefer, der die angezeigte
   fuer die gueltige haelt, beurteilt gegen einen Wert, den die Datenbank nicht
   kennt. --urgent waere hier trotzdem falsch: die Zahl ist nicht falsch, nur
   kuerzer. --text-secondary steht gemessen bei 7,73. */
.qs-gekuerzt-marke {
  color: var(--text-secondary);
  font-weight: 700;
  margin-left: 2px;
  cursor: help;
}

/* Eine Zeile, deren Toleranz SCHMALER ist als eine angezeigte Stelle. Sie
   entstand mit der Umstellung auf drei Nachkommastellen (Ansage Thomas,
   26.08.2026): weil Grenzen nach innen gerundet werden, liegt die angezeigte
   untere Grenze dann UEBER der oberen. Die Zeile traegt deshalb eine Marke im
   Klartext - und diesen leisen Untergrund, damit sie beim Ueberfliegen einer
   langen Tabelle auffaellt. Kein --urgent: die Zeile ist nicht fehlerhaft,
   nur feiner als die Anzeige. */
.qs-tabelle tr.ist-zu-fein td { background: var(--weekend-bg); }

/* ---------- Messwerte einer aufgeklappten Sitzung (Aufgabe 10) ----------
   Die eingebettete Tabelle sitzt in einer Zelle der Messungsliste. Sie braucht
   einen eigenen Rahmen, sonst laufen ihre Zeilen optisch in die aeussere
   Tabelle hinein und man sieht nicht, wo die Sitzung endet. */
.qs-werte-zeile > td { padding: 0 12px 12px; background: var(--weekend-bg); }
.qs-werte-tabelle { font-size: 12.5px; background: var(--surface-1); }
.qs-werte-tabelle th { background: var(--surface-1); }

/* Eine stornierte Wertzeile. Durchgestrichen ist das einzige allgemein
   verstaendliche Storno-Zeichen - dieselbe Entscheidung wie an der Marke
   ist-storniert aus Aufgabe 3.
   ⚠️ Die Ansicht v_messwert filtert Stornos NICHT heraus. Sie laesst die Zeile
   stehen und rechnet die Spalte `storniert` dazu - damit ein Storno sichtbar
   BLEIBT statt lautlos zu verschwinden. Wer die Zeile hier ausblendet, nimmt
   dem Nachweis genau das. */
.qs-werte-tabelle tr.ist-storniert-zeile td {
  text-decoration: line-through;
  color: var(--text-secondary);
}

/* Eine Wertzeile, die eine Urwertkarte oeffnen kann. Der Zeiger sagt es -
   sonst ist nicht zu erkennen, dass die Zeile ueberhaupt etwas tut. */
.qs-werte-tabelle tr[data-merkmal] { cursor: pointer; }
.qs-werte-tabelle tr[data-merkmal]:hover td { background: var(--weekend-bg); }
/* Das gewaehlte Merkmal. Der linke Balken und NICHT eine Farbe: die Zeile
   traegt schon ein Urteil in Gruen oder Rot, und eine zweite Farbe daneben
   waere nicht mehr zu lesen. */
.qs-werte-tabelle tr.ist-gewaehlt td:first-child {
  box-shadow: inset 3px 0 0 var(--brand-primary);
}

/* ---------- Die zwei Bilder (Aufgabe 11) ----------
   Nebeneinander, wenn Platz ist, sonst untereinander. Sie beantworten zwei
   verschiedene Fragen und gehoeren deshalb zusammen ins Bild: die
   Sammelansicht "welches Merkmal wandert", die Urwertkarte "um wie viel". */
.qs-bilder {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0 0 12px;
}

/* ⚠️ UNTEREINANDER, nicht nebeneinander. Hier stand `flex: 1 1 420px`, und
   damit standen die zwei Bilder nebeneinander. Gegenpruefung vom 26.08.2026,
   drei von drei Stimmen, nachgerechnet: .qs-seite hat 1180 px, minus Polster
   und Abstand bleiben rund 564 px je Karte, minus Kastenpolster 524 - das SVG
   mit viewBox 720 wird also auf 0,72 skaliert. Die x-Beschriftung mit 10
   Nutzereinheiten erscheint dann mit rund 7 px. Untereinander ist der Faktor
   ueber 1,5 und die Schrift ueber 15 px.

   Die Bilder verlieren dadurch nichts: sie beantworten zwei verschiedene
   Fragen und werden nacheinander gelesen, nicht verglichen. */
.qs-bilder > .qs-card { flex: 1 1 100%; min-width: 0; }
/* Das SVG skaliert mit dem Kasten. Ohne width:100% bleibt es bei seiner
   viewBox-Breite stehen und ragt aus dem Kasten. */
.qs-urwertkarte-svg { width: 100%; height: auto; display: block; }
.qs-urwertkarte-einzel { display: flex; flex-direction: column; }

/* ---------- Ladezustand (Aufgabe 8) ----------
   Steht in keiner gelesenen Datei des Projekts.

   OHNE BEWEGUNG, und das ist eine Entscheidung: style.css fuehrt zwar zwei
   @keyframes, aber ein Balken ohne Ende sagt nur "irgendwas laeuft" und sieht
   nach einem Fehler aus, wenn eine Anfrage haengt. Was diesen Zustand nuetzlich
   macht, steht nicht im Aussehen, sondern in qs-laufkarten.js: er erscheint
   erst nach 150 ms - eine oertliche Antwort kommt in wenigen Millisekunden, und
   ein Kasten, der dabei aufblitzt, ist schlimmer als keiner - und solange er
   steht, sind die Blaetterknoepfe zu. Ein doppelter Klick auf Weiter feuert
   sonst zwei Anfragen, und die zweite kann zuerst antworten: dann steht die
   falsche Seite da, mit der richtigen Seitenzahl darunter. */
.qs-laden {
  padding: 10px 14px;
  margin: 0 0 12px;
  border-radius: 8px;
  background: var(--weekend-bg);
  color: var(--text-secondary);
  font-size: 13px;
  font-style: italic;
}

/* ---------- Blaetterung (Aufgabe 7 angelegt, Aufgabe 8 geformt) ----------
   Im ganzen style.css gibt es sie nicht: 0 Treffer fuer blaetter, seitenwahl
   und pagination. Ohne den Flex-Kasten tut `margin-left: auto` am Zaehler
   nichts, und der Zaehler stuende links unter den Knoepfen.

   Keine Sprungziele: der Umschaltpunkt in qs-laufkarten.js geht spaeter auf
   Keyset, und Keyset laesst keine zu. */
.qs-blaetterung {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 12px 2px 0;
  padding-top: 10px;
  border-top: 1px solid var(--gridline);
}

/* ⚠️ EIN GESPERRTER KNOPF SAH AUS WIE EIN OFFENER. Gemessen am 26.08.2026:
   style.css hat KEINE generische Regel fuer `.btn:disabled` - die einzige im
   Haus ist `.saw-choice-btn:disabled { cursor: not-allowed; opacity: 0.55 }`,
   seitenlokal am Saegeplatz. Auf Seite 1 war "Zurueck" also gesperrt und sah
   trotzdem druckbar aus.

   Hier steht NICHT opacity, obwohl das die Hausform waere: Deckung multipliziert
   den Kontrast herunter, und was dabei herauskommt, haengt am Untergrund. Ein
   ausdrueckliches Farbpaar laesst sich messen - --text-secondary auf --gridline
   ergibt gemessen 6,00. */
/* ⚠️ Zwei Fundstellen, EINE Regel. style.css kennt kein allgemeines
   .btn:disabled - nur .saw-choice-btn:disabled, und das gilt woanders.
   Ohne diese Regel sieht ein gesperrter Knopf aus wie ein bedienbarer,
   und genau davor warnt die Projektregel "eine gesperrte Schaltflaeche
   faellt erst in der Halle auf". Gefunden am 27.08.2026, nicht durch
   eine Messung, sondern durch den Blick auf das Bildschirmfoto. */
.qs-blaetterung .btn:disabled,
.qs-anlegen-form .btn:disabled {
  background: var(--gridline);
  border-color: var(--baseline);
  color: var(--text-secondary);
  box-shadow: none;
  cursor: not-allowed;
}

/* Zaehlzeile der Blaetterung, dreiwertig. Die dritte Form - Seitenzahl ohne
   Gesamtzahl - ist der Grund fuer .qs-zaehler-ohne: sie darf sich sichtbar
   von einer echten Zahl unterscheiden, damit "von 7" und "nicht gezaehlt"
   nicht gleich aussehen. NIE "von 0". */
.qs-zaehler {
  font-size: 12.5px;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  /* margin-left: auto schiebt ihn im Flex-Kasten nach rechts - dasselbe
     Mittel wie .parts-anzahl in style.css. Oben und unten 0, sonst traegt
     der Absatz seine Vorgabehoehe in die Blaetterzeile. */
  margin: 0 0 0 auto;
}
.qs-zaehler-ohne { font-style: italic; }

/* ---------- 8. Schiebe-Bestätigung ---------- */
/* ⚠️ AUSGEZOGEN am 03.09.2026 (Aufgabe 1c/14) nach
   Leitstand-Online-Probe\schieber.css. Sie liegt dort, weil
   werkzeugwechsel.html sie ebenfalls braucht und weil
   deploy-erstellen.ps1 genau diesen einen Ordner in das Paket
   kopiert - eine Datei aus Projekt-QS\Seiten kaeme in der
   Auslieferung nicht an.

   Wer eine Seite mit Schieber baut, bindet schieber.css UND
   schieber.js ein. Diese Zeilen bleiben als Zeiger stehen:
   ein leerer Abschnitt 8 waere schwerer zu finden als
   keiner. */

/* =========================================================
   Tablet-Ansicht (Finger statt Maus). Zwei Auslöser mit ABSICHTLICH
   identischen Werten:
   1) @media (pointer: coarse)   – echte Touch-Hardware
   2) .qs-app.ansicht-tablet     – vom Büro/Tablet-Schalter erzwungen,
      damit Thomas beide Ansichten auf seinem Maus-Rechner sieht.
   Die Werte sind vorgegeben und werden hier NICHT nachgemessen:
   IO/NIO 48 px · Navigation/.btn 44 px · .btn.klein 40 px ·
   einzeilige Felder 44 px/16 px · Textfelder 96 px/16 px (eigene Regel,
   siehe Falle unten) · Ankreuzfelder 22×22 px · Tabellenzellen 14 px.
   ========================================================= */

@media (pointer: coarse) {
  .qs-btn-io, .qs-btn-nio { min-height: 48px; padding: 10px 22px; font-size: 15px; }

  .page-nav-link, .ansicht-btn, .btn {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .btn.klein { min-height: 40px; padding: 6px 14px; font-size: 13px; }
  /* ⚠️ 48 px, und die Begruendung ist gemessen (27.08.2026, Schritt 8):
     in der Tablet-Ansicht war `.qs-zeile-uebernehmen` mit 40 px das
     KLEINSTE Ziel der Zeile - kleiner als die IO/NIO-Knoepfe (48) und
     kleiner als das Eingabefeld (44). Und es ist die Taste, die der
     Pruefer bei 28 Merkmalen 28-mal drueckt.

     Die Spezifikation nennt 48 px nur fuer IO/NIO. Der GRUND dafuer - ein
     Finger an einer Maschine, oft im Handschuh - gilt hier genauso, und
     eine Taste, die man oefter trifft als jede andere, darf nicht die
     kleinste sein. Als Erweiterung der Spezifikation festgehalten, nicht
     als Auslegung. */
  .qs-zeile-uebernehmen.btn.klein { min-height: 48px; padding: 10px 18px; font-size: 14px; }

  .qs-messwert-eingabe { min-height: 44px; font-size: 16px; }

  /* Falle (dokumentiert, wörtlich übernommen): eine gemeinsame 44-px-Regel
     für Eingaben würde die Textarea hier KLEINER machen, weil dieser Block
     später in der Datei steht als ihre Grundregel. Deshalb eigene, größere
     Regel statt sie oben mitlaufen zu lassen. */
  .qs-bemerkung { min-height: 96px; font-size: 16px; }

  .qs-ankreuzfeld { width: 22px; height: 22px; }

  .qs-tabelle td { padding: 14px; }

  /* NACHGETRAGEN am 26.08.2026 (Aufgabe 8). Die Spezifikation nennt die Luecke
     ausdruecklich: der Block deckt sieben Ziele, und Auswahllisten,
     Tabellenkoepfe und der Schiebergriff sind NICHT dabei - "fuer die
     Filterzeile fehlt die 44-px-Regel also vollstaendig".

     16 px und nicht 15: unter 16 px zoomt der Browser am Telefon beim
     Hineintippen die ganze Seite. Derselbe Wert wie in den Regeln darueber.

     ⚠️ Die Falle darueber gilt weiter: das ist eine EIGENE Regel fuer die drei
     Bedienelemente der Filterzeile, keine gemeinsame fuer alle Eingaben. Eine
     gemeinsame wuerde die Textarea auf 44 px schrumpfen. */
  .qs-filter-feld select,
  .qs-filter-feld input[type="date"],
  .qs-filter-feld .part-search { min-height: 44px; font-size: 16px; }

  /* Anlegemaske (Aufgabe 5). `input[type="number"]` steckt in KEINER der
     Regeln oben - die zaehlen select, date und .part-search auf. Ohne diese
     Zeile bliebe das Spannungsfeld am Tablet das einzige zu kleine Feld der
     Seite. */
  .qs-anlegen-griff { min-height: 44px; font-size: 15px; }
  .qs-anlegen-form input[type="number"] { min-height: 44px; font-size: 16px; }
}

.qs-app.ansicht-tablet .qs-btn-io,
.qs-app.ansicht-tablet .qs-btn-nio { min-height: 48px; padding: 10px 22px; font-size: 15px; }

.qs-app.ansicht-tablet .page-nav-link,
.qs-app.ansicht-tablet .ansicht-btn,
.qs-app.ansicht-tablet .btn {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.qs-app.ansicht-tablet .btn.klein { min-height: 40px; padding: 6px 14px; font-size: 13px; }
/* Dieselbe Regel wie im Block darueber - die Doppelung ist Absicht (siehe Kopf). */
.qs-app.ansicht-tablet .qs-zeile-uebernehmen.btn.klein {
  min-height: 48px; padding: 10px 18px; font-size: 14px;
}

.qs-app.ansicht-tablet .qs-messwert-eingabe { min-height: 44px; font-size: 16px; }
.qs-app.ansicht-tablet .qs-bemerkung { min-height: 96px; font-size: 16px; }

/* ⚠️ DIE BESCHRIFTUNG WUCHS BISHER NICHT MIT - Punkt 2 der Freigabeliste
   ("Allgemein und Freigabemessung Ansicht zu klein, muss groesser sein").
   Am 13.09.2026 in der Freigabemaske GEMESSEN, in beiden Ansichten:
   Merkmalsname 13,5 px, Grenzenzeile 11,5 px, Mengenfeld 15 px - Buero und
   Tablet auf den Zehntelpunkt GLEICH. Der Schalter hob nur die
   Eingabefelder und die Knoepfe; alles, was man LIEST, blieb
   Schreibtischgroesse. Deshalb fiel der Unterschied niemandem auf, und
   deshalb ist die Maske am Automaten zu klein.

   Die Zahlen sind der Wandmonitor-Faktor 1,5 aus qs-start, hier auf die
   Tablet-Ansicht angewandt und auf halbe Punkte gerundet. Wer nachjustieren
   will, aendert sie hier - sie stehen bewusst beieinander.

   ⚠️ KEIN --takt. Das Merkmal gehoert der Indexseite und haengt dort an
   `.ist-wandmonitor`; es hier mitzubenutzen hiesse, zwei verschiedene
   Absichten an eine Zahl zu haengen. Ein Monitor an der Wand und ein Tablet
   in der Hand sind nicht derselbe Leseabstand. */
.qs-app.ansicht-tablet .qs-merkmal-nr { font-size: 17px; }
.qs-app.ansicht-tablet .qs-merkmal-name { font-size: 18px; }
.qs-app.ansicht-tablet .qs-merkmal-mittel { font-size: 15px; }
.qs-app.ansicht-tablet .qs-grenzen { font-size: 15px; }
.qs-app.ansicht-tablet .qs-einheit { font-size: 15px; }
.qs-app.ansicht-tablet .qs-marke,
.qs-app.ansicht-tablet .qs-zeilen-hinweis { font-size: 14px; }

/* Das Freigaberaster hat eigene, kleinere Werte fuer denselben Inhalt
   (.qs-freigabe-tabelle th[scope="row"] ...) - ohne diese Zeilen schlagen
   die die Regeln darueber, und die Zeilenkoepfe blieben als EINZIGES klein.
   Zwei Stellen fuer dieselbe Aussage, und das ist hier nicht vermeidbar:
   die Tabellenfassung ist enger ausgewaehlt. */
.qs-app.ansicht-tablet .qs-freigabe-tabelle th[scope="row"] .qs-grenzen,
.qs-app.ansicht-tablet .qs-freigabe-tabelle th[scope="row"] .qs-merkmal-mittel {
  font-size: 15px;
}

/* Die Mengenfelder unter dem Raster - Gutteile ist ein Pflichteintrag und
   stand mit 15 px genauso klein da wie im Buero. */
/* ⚠️ `.qs-anlegen-griff span`, NICHT `.qs-mengen-zeile` - die Klasse gibt es
   nicht. Beim ersten Anlauf stand sie hier, und die Regel haette schweigend
   nichts getroffen: eine Auswahl ohne Treffer ist in CSS kein Fehler.
   Nachgesehen in qs-freigabe.html, nicht geraten. */
.qs-app.ansicht-tablet .qs-mengen input[type="number"] {
  min-height: 44px;
  font-size: 16px;
}
.qs-app.ansicht-tablet .qs-mengen .qs-anlegen-griff span { font-size: 16px; }
.qs-app.ansicht-tablet .qs-ankreuzfeld { width: 22px; height: 22px; }
.qs-app.ansicht-tablet .qs-tabelle td { padding: 14px; }
/* Die Zwillinge der drei Zeilen aus dem coarse-Block. ABSICHTLICH identische
   Werte - wer die zwei Bloecke zusammenlegt, nimmt dem Buero/Tablet-Schalter
   die Wirkung. */
.qs-app.ansicht-tablet .qs-filter-feld select,
.qs-app.ansicht-tablet .qs-filter-feld input[type="date"],
.qs-app.ansicht-tablet .qs-filter-feld .part-search {
  min-height: 44px;
  font-size: 16px;
}

/* Anlegemaske (Aufgabe 5) - dieselben zwei Zeilen wie im coarse-Block. Die
   Doppelung ist Absicht (Aufgabe 15): wer sie "aufraeumt", nimmt dem
   Buero/Tablet-Schalter die Wirkung. */
.qs-app.ansicht-tablet .qs-anlegen-griff { min-height: 44px; font-size: 15px; }
.qs-app.ansicht-tablet .qs-anlegen-form input[type="number"] {
  min-height: 44px;
  font-size: 16px;
}

/* Der gesperrte "Messung erfassen"-Knopf.

   ⚠️ KEIN opacity. Die erste Fassung hatte 0.55, und das drueckt den Text von
   rgb(11,11,11) auf rund rgb(118,118,117) - gemessen etwa 3,4:1 gegen die
   Flaeche. Eine Sperre, deren Beschriftung man kaum lesen kann, sagt nicht,
   dass sie gesperrt ist, sondern nur, dass hier irgendetwas Blasses steht.
   Statt dessen: gestrichelter Rand (das SIEHT nach "nicht anklickbar" aus) und
   ein gedaempfter, aber lesbarer Ton.

   Der Grund steht als eigener Text daneben, nicht nur im title - auf dem
   Tablet gibt es keinen title, und dort wird gemessen. */
.qs-erfassen-wrap {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.qs-app .qs-erfassen-zu {
  border-style: dashed;
  border-color: var(--border);
  background: transparent;
  color: var(--text-muted);
  cursor: not-allowed;
}
/* ⚠️ Der GRUND traegt --text-primary, nicht --text-muted. Er ist Information,
   kein gesperrtes Bedienelement: --text-muted misst gegen die Flaeche 3,41,
   und das ist der Wert, den Thomas am 27.08.2026 bewusst bei 3,5 belassen hat
   (Abweichung K1) - fuer eine Marke tragbar, fuer den Satz, der erklaert warum
   etwas nicht geht, nicht. Die BESCHRIFTUNG des Knopfes darf gedaempft
   bleiben: dass sie schwer lesbar ist, ist dort sogar die Aussage. */
.qs-erfassen-grund {
  font-size: 12px;
  color: var(--text-primary);
}

/* ---------- 12. Storno-Dialog (Aufgabe 1c/13) ----------
   Er sitzt in einer eigenen Tabellenzeile unter der Zeile, der er gehoert -
   wie die aufgeklappten Werte. KEINE IDs, nur Klassen: Aufgabe 14 soll den
   Leitstand auf diese Form umstellen, nicht umgekehrt. */
.qs-storno-dialog {
  border: 1px solid var(--border);
  border-left: 3px solid var(--urgent);
  border-radius: 6px;
  padding: 12px 14px;
  margin: 6px 0;
  background: var(--surface-1);
  max-width: 640px;
}
.qs-storno-titel { margin: 0 0 4px; font-size: 14px; }
.qs-storno-was {
  margin: 0 0 10px;
  font-size: 12.5px;
  color: var(--text-secondary);
}
.qs-storno-grund-feld {
  display: block;
  font-size: 12.5px;
  color: var(--text-secondary);
  margin: 0 0 8px;
}
.qs-storno-grund {
  display: block;
  width: 100%;
  margin-top: 4px;
  font: inherit;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-0);
  color: var(--text-primary);
  box-sizing: border-box;
}
.qs-storno-grund:disabled { color: var(--text-muted); }
.qs-storno-gruende { margin: 0 0 8px; }
.qs-storno-vorlaeufig {
  margin: 0 0 6px;
  font-size: 12px;
  font-style: italic;
  color: var(--text-muted);
}
.qs-storno-vorschlag { margin: 0 6px 6px 0; }
.qs-storno-grund-fest {
  margin: 0 0 8px;
  font-size: 12px;
  color: var(--text-muted);
}
.qs-storno-kennung {
  margin: 0 0 8px;
  font-size: 11.5px;
  color: var(--text-muted);
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  word-break: break-all;
}
.qs-storno-meldung { margin: 10px 0 0; font-size: 12.5px; }
.qs-storno-meldung.ist-io { color: var(--io); }
.qs-storno-meldung.ist-fehler { color: var(--urgent); }
.qs-storno-meldung.ist-recht { color: var(--urgent); }
.qs-storno-meldung.ist-hinweis { color: var(--text-primary); }
.qs-storno-fuss { margin-top: 10px; display: flex; gap: 8px; flex-wrap: wrap; }
.qs-storno-zeile > td { background: var(--surface-2); }
/* ---------- Zuweisen (Scheibe 2, 05.09.2026) ----------
   Das Formular unter dem Kartenkopf: Maschine, Start, Knopf, Grund. Es
   uebernimmt .qs-filter-feld und .part-search der Kartenliste, damit die
   Felder auf beiden Seiten gleich aussehen. [hidden] ausdruecklich, aus
   demselben Grund wie bei .qs-anlegen-schritt. */
.qs-zuweisen {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.qs-zuweisen[hidden] { display: none; }
.qs-zuweisen input[type="datetime-local"] {
  min-width: 210px;
  min-height: 36px;
  padding: 6px 10px;
  font-family: var(--font-body);
  font-size: 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-1);
  color: var(--text-primary);
}
.qs-zuweisen input[type="datetime-local"]:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 1px;
}
.qs-zuweisen .btn:disabled {
  background: var(--gridline);
  border-color: var(--baseline);
  color: var(--text-secondary);
  box-shadow: none;
  cursor: not-allowed;
}
/* Der Grund: Auskunft (grau), Erfolg (gruen) oder Abbruch (rot) - dieselben
   drei Farben wie die Baender, keine neue. */
.qs-zuweisen-grund { font-size: 12.5px; color: var(--text-secondary); flex-basis: 100%; }
.qs-zuweisen-grund.ist-io { color: var(--success-text); }
.qs-zuweisen-grund.ist-fehler { color: var(--urgent); }

/* ---------- Abschluss (Scheibe 5, 05.09.2026) ----------
   Der Block unter dem Zuweisen: Titel, Satz mit der Lage, die Spur fuer den
   Schieber (schieber.css), der Grund nach dem Senden. Gesperrt heisst
   sichtbar: der Satz steht immer, nur der Schieber fehlt. Die Spur ist
   begrenzt, damit der Zug bis 92 % kein Weg quer ueber den Bildschirm ist. */
.qs-abschluss {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.qs-abschluss[hidden] { display: none; }
.qs-abschluss-titel { margin: 0 0 6px; font-size: 15px; font-weight: 600; }
.qs-abschluss-satz { margin: 0 0 10px; font-size: 13.5px; color: var(--text-primary); }
.qs-abschluss-satz.ist-gesperrt { color: var(--text-secondary); }
.qs-abschluss-spur { max-width: 480px; }
.qs-abschluss-grund { margin: 8px 0 0; font-size: 12.5px; color: var(--text-secondary); }
.qs-abschluss-grund.ist-io { color: var(--success-text); }
.qs-abschluss-grund.ist-fehler { color: var(--urgent); }

/* ---------- Scheibe 4b (05.09.2026): die Mengenmeldung ----------
   In der Freigabemaske: der Block "Mengen des Loses" unter dem Raster, vier
   schmale Zahlenfelder in einer Zeile, der Hinweis darunter. Auf der
   Kartenseite: die Liste der einzelnen Meldungen unter den Summen; eine
   stornierte Zeile bleibt durchgestrichen stehen (ist-storniert, wie die
   Marke), der Knopf sagt "storniert". */
.qs-mengen {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0 8px;
  margin: 14px 0 6px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.qs-mengen-titel { flex-basis: 100%; margin: 0 0 4px; font-size: 15px; font-weight: 600; }
.qs-mengen .qs-anlegen-griff .part-search { width: 130px; }
.qs-mengen .qs-zeilen-hinweis { flex-basis: 100%; margin: 6px 0 0; }
.qs-meldungen-tabelle tr.ist-storniert td:not(:last-child) {
  text-decoration: line-through;
  color: var(--text-secondary);
}

/* ---------- Scheibe 7 (06.09.2026): die Pruefplan-Pflege ----------
   Der Merkmal-Zeileneditor ist qs-punkte/qs-punkt/qs-punkt-feld aus der
   Anlegemaske - dieselbe Tabelle, dieselben Felder. Neu ist nur die
   Aktionsspalte (Speichern/Entfernen bzw. die Marke "gespeichert") und die
   Grundzeile darunter, die einen Fehler NEBEN statt IN der letzten Spalte
   zeigt - sonst waere die Tabelle beim ersten Fehler seitlich unlesbar breit. */
.qs-merkmal-aktion { display: flex; gap: 4px; white-space: nowrap; }
.qs-merkmal-grund-zelle { padding: 0; border: none; }
.qs-merkmal-grund-zelle[hidden] { display: none; }
.qs-merkmal-grund {
  margin: 0;
  padding: 4px 8px;
  font-size: 12.5px;
  color: var(--urgent);
}

/* ---------- Scheibe 4 (05.09.2026): das Raster der Freigabemessung ----------
   Die Huelle (.qs-freigabe-wrap) und die feste erste Spalte
   (.qs-freigabe-tabelle th:first-child) stehen seit der Musterseite weiter
   oben (Abschnitt 4). Hier kommt dazu, was die ECHTE Maske braucht: die zwei
   Schritte, der Merkmalskopf mit Grenzen, die dichte Zelle mit Feld oder zwei
   kleinen Knoepfen, und die drei Zustaende einer Zelle (im Geraet, gespeichert
   mit Urteil, gespeichert ohne Urteil). Keine neue Farbe - die vorhandenen
   Variablen reichen (Spezifikation der Oberflaeche 6.3). */
.qs-freigabe-schritt { display: block; }
.qs-freigabe-schritt[hidden] { display: none; }
.qs-freigabe-schritt .qs-anlegen-griff {
  display: inline-flex; flex-direction: column; gap: 4px; margin: 6px 16px 6px 0;
  vertical-align: bottom;
}
/* ⚠️ GEFUNDEN AM BILD (05.09.2026): .part-search traegt `flex: 0 1 420px`, und
   in einem SPALTEN-Flexkasten ist flex-basis die HOEHE - die zwei Zahlenfelder
   waren 420 px hoch. Hier ist die Breite gemeint, also flex aus. */
.qs-freigabe-schritt .qs-anlegen-griff .part-search {
  flex: 0 0 auto; width: 170px;
}
/* Das Label des Hakens. NICHT .qs-ankreuzfeld: die ist die Regel fuer das
   Kaestchen selbst (16 x 16 px) und machte am Label den Text 16 px breit. */
.qs-freigabe-haken {
  display: inline-flex; align-items: center; gap: 8px; margin: 6px 16px 6px 0;
  vertical-align: bottom; font-size: 14px; cursor: pointer;
}
.qs-freigabe-tabelle th[scope="row"] { text-align: left; font-weight: 600; }
.qs-freigabe-tabelle th[scope="row"] .qs-merkmal-nr { margin-right: 6px; }
.qs-freigabe-tabelle th[scope="row"] .qs-grenzen {
  display: block; font-size: 11.5px; font-weight: 400;
  color: var(--text-secondary); white-space: nowrap;
}
/* Wie die Grenzenzeile daneben. ⚠️ `font-weight: 400` ist hier PFLICHT und
   keine Kosmetik: th[scope="row"] steht auf 600, und ohne diese Zeile saehe
   die Pruefmittelnummer schwerer aus als der Merkmalsname darueber. */
.qs-freigabe-tabelle th[scope="row"] .qs-merkmal-mittel {
  font-size: 11.5px; font-weight: 400;
}
.qs-freigabe-tabelle td.qs-zelle { padding: 4px 6px; vertical-align: middle; }
/* ⚠️ 70 PX STATT 84 (14.09.2026) - hergeleitet, nicht gerundet.
   "-120,000" misst bei 13 px Poppins 54 px; mit 12 px Polster und 2 px
   Rahmen waeren 68 px RANDVOLL - eine Zeile ohne Reserve, und bei einer
   anderen Schriftdarstellung ist der Messwert abgeschnitten. 70 px geben
   2 px Luft und kosten auf 20 Spalten 40 px, also nichts.
   Die Schriftgroesse bleibt bei 13 px: hier wird an einer Messmaschine
   abgelesen, kleiner ist keine Option. Siehe die Rechnung an
   .qs-freigabe-tabelle th:not(:first-child). */
.qs-freigabe-tabelle td.qs-zelle .qs-messwert-eingabe {
  width: 70px; padding: 5px 6px; font-size: 13px;
}
.qs-freigabe-tabelle td.qs-zelle .qs-io-nio { justify-content: center; gap: 4px; }
.qs-btn-io.klein, .qs-btn-nio.klein {
  min-width: 40px; min-height: 30px; padding: 3px 8px; font-size: 12px;
  border-radius: 14px;
}
/* Im Geraet gesichert, nicht gesendet: ein Strich unter der Zelle - die
   Marke aus qs-ipc (ist-nicht-gesendet) als Zellenrand, weil im Raster kein
   Platz fuer den Text ist. Der Hinweistext traegt den Satz. */
.qs-freigabe-tabelle td.ist-nicht-gesendet { box-shadow: inset 0 -3px 0 var(--brand-primary); }
.qs-freigabe-tabelle td.ist-gespeichert { font-variant-numeric: tabular-nums; }
.qs-freigabe-tabelle td.ist-ohne-urteil { color: var(--text-muted); font-style: italic; }
.qs-freigabe-tabelle td.qs-io  { color: var(--success-text); }
.qs-freigabe-tabelle td.qs-nio { color: var(--urgent); font-weight: 700; }

/* ---------- 12. Anstehende Messungen (qs-start, Scheibe 6) ----------

   Der Mess-Timer. Farben ausschliesslich aus den vorhandenen Merkmalen:
   --brand-primary fuer den laufenden Balken, --urgent/--urgent-fill fuer
   ueberfaellig, --baseline fuer die Teilstriche. Der Zeitstrahl des
   Leitstands benutzt dieselben - der Balken hier ist damit derselbe
   Bildgedanke, nicht ein zweiter. */

/* ⚠️ DIESE SEITE HAENGT IN DER HALLE, an einem Monitor, der aus mehreren
   Metern gelesen wird (Ansage 08.09.2026: "bitte alles etwas groesser").
   Die Schriftgrade von 12 bis 14 px waren fuer einen Schreibtisch gebaut.

   ALLE Groessen dieser Liste haengen an EINER Zahl. Wer sie nachjustieren
   will, aendert --takt und sonst nichts - sonst wandern beim naechsten Mal
   drei Werte mit und zwei bleiben stehen, und die Zeile faellt auseinander.
   1 waere der alte Schreibtisch-Stand.

   ⚠️ SIE HAENGT AN `.ist-wandmonitor`, NICHT AN `.qs-app`. Im ersten
   Versuch stand sie an `.qs-app` - damit trug JEDE QS-Seite den Faktor.
   Heute faellt das nicht auf, weil nur qs-start die Takt-Klassen benutzt;
   die erste Zeile, die sie anderswo verwendet, waere still um die Haelfte
   zu gross geworden.

   ⚠️ DER VORGABEWERT 1 IST PFLICHT, kein Schmuck. Ohne ihn waere --takt auf
   jeder anderen Seite UNGESETZT, und `calc(14px * var(--takt))` ist dann
   keine Groesse, sondern eine UNGUELTIGE Deklaration: die Zeile faellt weg,
   und die Schrift erbt irgendetwas. Genau die var()-Falle, die dieses
   Projekt an den Fortschrittsbalken schon einmal bezahlt hat - dort wurde
   aus "keine Daten" ein voller Balken.

   ⚠️ KEIN vw-Mass. Ein Monitor mit 1920 px und ein Bueroschirm mit 1920 px
   sind dieselbe Zahl und ein ganz anderer Leseabstand; die Schrift waere
   damit genau dort falsch, wo sie stimmen muss. */
.qs-app { --takt: 1; }
.qs-app.ist-wandmonitor { --takt: 1.5; }

/* Der Seitenkopf und die Leiste gehen mit - "alles etwas groesser" heisst
   nicht "die Liste, und die Ueberschrift bleibt kleiner als ihre eigenen
   Gruppen". Nur auf dem Wandmonitor: die Leiste kommt aus style.css und
   gehoert dem ganzen Leitstand. */
.qs-app.ist-wandmonitor .qs-kopf h1 { font-size: calc(22px * var(--takt)); }
.qs-app.ist-wandmonitor .toolbar h1 { font-size: calc(19px * var(--takt)); }
.qs-app.ist-wandmonitor .page-nav-link,
.qs-app.ist-wandmonitor .ansicht-btn { font-size: calc(13px * var(--takt)); }

.qs-takt-gruppe h2 {
  display: flex;
  align-items: baseline;
  gap: calc(8px * var(--takt));
  font-size: calc(17px * var(--takt));
}
.qs-takt-zahl {
  font-family: var(--font-body);
  font-size: calc(13px * var(--takt));
  font-weight: 600;
  color: var(--text-muted);
}
.qs-takt-gruppe.ist-dringend h2 { color: var(--urgent); }
/* SACHLICH, NICHT ALARM. Die Klasse stand seit dem 06.09.2026 an der
   M-4-Gruppe im HTML und hatte KEINE Regel - die Absicht "diese Gruppe ist
   Auskunft, kein Handlungsgrund" landete also nie im Bild. Gefunden beim
   Gegenlesen am 15.09.2026; nachgetragen, weil die neue Gruppe
   "Fertig gemeldet - Laufkarte noch offen" dieselbe Klasse traegt und
   dieselbe Aussage braucht: hier ist nichts zu messen.

   Bewusst nur die Ueberschrift und nur die Farbe. Die Zeilen darunter
   bleiben unveraendert lesbar - eine ganze Gruppe blass zu setzen hiesse,
   sie auf einem Wandmonitor aus fuenf Metern unlesbar zu machen, und genau
   das verbietet M-4: verschwinden darf hier nichts. */
.qs-takt-gruppe.ist-sachlich h2 { color: var(--text-muted); }

.qs-takt-liste { list-style: none; margin: 0; padding: 0; }

/* Drei Spalten: Beschriftung - Balken - Faelligkeit. Der Balken nimmt, was
   uebrig ist; die Beschriftung bekommt eine feste Breite, damit die Balken
   untereinander an derselben Kante beginnen und vergleichbar sind. */
.qs-takt-zeile {
  display: grid;
  /* Die Beschriftungsspalte waechst mit: eine Maschinenkennung in 21 px
     passt nicht mehr in 200 px, und sie umbrechen zu lassen kostet die
     gemeinsame Kante, an der die Balken beginnen. */
  grid-template-columns:
    minmax(calc(200px * var(--takt)), calc(260px * var(--takt))) 1fr auto;
  align-items: center;
  gap: calc(16px * var(--takt));
  padding: calc(10px * var(--takt)) calc(12px * var(--takt));
  border-bottom: 1px solid var(--gridline);
}
.qs-takt-zeile:last-child { border-bottom: none; }
.qs-takt-zeile.ist-dringend { background: color-mix(in srgb, var(--urgent) 6%, transparent); }

.qs-takt-kopf {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: calc(4px * var(--takt)) calc(10px * var(--takt));
}
.qs-takt-maschine {
  font-family: var(--font-heading);
  font-size: calc(14px * var(--takt));
  font-weight: 700;
  color: var(--text-primary);
  flex-basis: 100%;
}
.qs-takt-maschine.ist-leer {
  font-weight: 600;
  font-style: italic;
  color: var(--text-muted);
}
.qs-takt-auftrag {
  font-size: calc(13px * var(--takt));
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--brand-primary);
  text-decoration: none;
}
.qs-takt-auftrag:hover, .qs-takt-auftrag:focus-visible { text-decoration: underline; }
.qs-takt-artikel { font-size: calc(12px * var(--takt)); color: var(--text-muted); }

/* Die Bahn. position: relative, weil die Teilstriche als ::after DARUEBER
   liegen - unter der Fuellung waeren genau die Striche verdeckt, die sagen,
   der wievielte Takt laeuft. */
.qs-takt-mitte { min-width: 0; }
.qs-takt-bahn {
  position: relative;
  display: block;
  width: 100%;
  height: calc(14px * var(--takt));
  border-radius: 999px;
  background: var(--blocked-bg);
  overflow: hidden;
}
/* ⚠️ 0, NICHT var(--anteil, 0%). Der Ausweichwert einer var()-Funktion greift
   nur bei ungesetzt oder leer; bei NaN% wird die Deklaration ungueltig, width
   faellt auf auto, und das Element fuellt seinen Elternknoten - aus "keine
   Daten" wuerde "alles fertig". Am 27.08.2026 an einer 200-px-Bahn gemessen
   (siehe .qs-fortschritt-anteil). qs-start.js schreibt hier nur eine
   geprueft endliche Prozentzahl hinein. */
.qs-takt-fuellung {
  display: block;
  height: 100%;
  width: 0;
  background: var(--brand-primary);
  /* Die rechte Kante IST "jetzt". Sie wird abgesetzt, damit man sie auch
     dann findet, wenn der Balken fast voll ist. */
  box-shadow: inset -2px 0 0 var(--brand-accent);
}
.qs-takt-fuellung.ist-dringend {
  background: var(--urgent-fill);
  box-shadow: inset -2px 0 0 var(--urgent);
}
/* UEBER DEM PLAN (Festlegung M-6, gebaut am 14.09.2026). Die Festlegung
   verlangt woertlich, dass der Balken die Ueberschreitung zeigt; bis dahin
   tat er das Gegenteil. `anteil` wird bei Ueberschreitung auf 1 gekappt -
   der Balken stand also VOLL, und ein voller Balken liest sich aus fuenf
   Metern als "fertig". An der echten Karte 916877 sah man das am
   14.09.2026: Planende war der 12.09., der Auftrag lief noch, Balken voll.

   Eine SCHRAFFUR, keine andere Farbe. Die Farbe ist schon vergeben - sie
   trennt "ueberfaellig" (rot) von "laeuft" (blau), und das ist die
   wichtigere Aussage. Das Muster legt sich darueber, ohne sie zu stoeren:
   dieselbe Fuellfarbe, nur nicht mehr glatt.

   ⚠️ background-image, NICHT background. Das Kurzwort wuerde die Farbe aus
   .ist-dringend mit loeschen, und eine ueberzogene UND ueberfaellige Karte
   verloere ihr Rot - genau die Karte, die man am ehesten sehen muss.

   ⚠️ DIE STRICHBREITE HAENGT AN --takt. Die Seite haengt in der Halle
   (Ansage 08.09.2026); ein Muster in festen Pixeln waere auf dem
   Wandmonitor kaum noch zu erkennen.

   ⚠️ .ist-nio SCHLAEGT DIES HIER, und das ist so gewollt. Die Regel
   .qs-takt-bahn.ist-nio .qs-takt-fuellung hat die hoehere Spezifitaet
   (0,3,0 gegen 0,2,0): bei n.i.O. blinkt der ganze Balken, und der
   Fortschritt tritt zurueck - so steht es dort schon seit dem 07.09.2026. */
.qs-takt-fuellung.ist-ueberzogen {
  background-image: repeating-linear-gradient(
    135deg,
    rgba(0, 0, 0, 0.26) 0 calc(4px * var(--takt)),
    rgba(0, 0, 0, 0) calc(4px * var(--takt)) calc(9px * var(--takt)));
}
/* n.i.O. der letzten Sitzung: der ganze Balken blinkt rot, nicht nur die
   kleine Marke im Kopf (Befund Thomas, 07.09.2026). Dieselben rgba-Werte und
   derselbe Takt wie .ipc-alarm.ipc-toleranz im Leitstand (style.css) - kein
   var(--urgent), aus demselben Grund wie dort: der Puls liegt als
   Hintergrund hinter der Fuellung, das braucht eine abgestimmte Deckkraft. */
@keyframes qs-takt-blink-nio {
  0%, 100% { background-color: rgba(230, 0, 0, 0.12); }
  50%      { background-color: rgba(230, 0, 0, 0.50); }
}
.qs-takt-bahn.ist-nio { animation: qs-takt-blink-nio 1.1s ease-in-out infinite; }
/* Die Fuellung liegt UEBER der Bahn und wuerde den Puls dahinter zudecken -
   beim Alarm soll der ganze Balken gleichmaessig blinken, nicht nur der
   unausgefuellte Rest. Der Fortschritt tritt hier bewusst zurueck. */
.qs-takt-bahn.ist-nio .qs-takt-fuellung { background: transparent; box-shadow: none; }

.qs-takt-bahn.hat-striche::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: linear-gradient(to right, var(--baseline) 0 1px, transparent 1px);
  background-size: var(--qs-takt-breite) 100%;
  background-repeat: repeat-x;
  pointer-events: none;
}

.qs-takt-rechts {
  display: flex;
  align-items: center;
  gap: calc(12px * var(--takt));
  justify-content: flex-end;
}
/* Zwei Zeilen uebereinander: oben die Faelligkeit, darunter die letzte
   Messung. `align-items: flex-end` haelt beide rechtsbuendig - sonst haengt
   die kuerzere Zeile in der Mitte und die Spalte franst aus. */
.qs-takt-zeiten {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(2px * var(--takt));
}
.qs-takt-faellig {
  font-size: calc(13px * var(--takt));
  font-weight: 600;
  color: var(--text-secondary);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.qs-takt-faellig.ist-dringend { color: var(--urgent); }

/* Die letzte Messung. Bewusst KLEINER und ruhiger als die Faelligkeit: sie
   ist die Auskunft daneben, nicht der Handlungsgrund. Wer sie gleich gross
   setzt, macht aus jeder Zeile zwei gleich laute Aussagen. */
.qs-takt-zuletzt {
  font-size: calc(11.5px * var(--takt));
  color: var(--text-muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* "noch nicht gemessen" ist keine Uhrzeit und wird auch nicht wie eine
   gesetzt - aber es ist auch kein Fehler und bekommt darum keine
   Warnfarbe, nur Kursivschrift. Dieselbe Sprache wie `.ist-leer` an der
   Maschinenkennung darueber. */
.qs-takt-zuletzt.ist-nie { font-style: italic; }

/* ⚠️ `.btn.klein.qs-takt-knopf`, NICHT nur `.qs-takt-knopf`. Der Knopf traegt
   `btn klein` aus style.css - zwei Klassen schlagen eine, und der erste
   Versuch mit einer Klasse ist wirkungslos geblieben: gemessen am
   08.09.2026 stand der Knopf weiter auf 12 px, waehrend alles um ihn herum
   auf 21 px gewachsen war. Aufgefallen NUR, weil die berechnete Groesse
   nachgesehen wurde - im verkleinerten Bildschirmfoto sah er unauffaellig
   aus. */
.btn.klein.qs-takt-knopf {
  white-space: nowrap;
  font-size: calc(13px * var(--takt));
  padding: calc(6px * var(--takt)) calc(14px * var(--takt));
  min-height: calc(30px * var(--takt));
}

/* Am Tablet und am schmalen Bildschirm untereinander: drei Spalten mit einem
   brauchbaren Balken brauchen mehr Breite, als ein Tablet hochkant hat. */
@media (max-width: 860px) {
  .qs-takt-zeile { grid-template-columns: 1fr; gap: 8px; }
  .qs-takt-rechts { justify-content: space-between; }
}

/* Ohne geplante Laufzeit hat der Balken kein Ende. Er zeigt dann den
   LAUFENDEN TAKT, und die Bahn sagt das: rechts ausblendend statt mit
   Kante. Ein leerer Balken waere hier die schlechteste Anzeige - die
   Rechnung stimmt, aber er saehe aus wie ein Fehler. */
.qs-takt-bahn.ist-offen {
  border-radius: 999px 0 0 999px;
  -webkit-mask-image: linear-gradient(to right, #000 82%, transparent 100%);
          mask-image: linear-gradient(to right, #000 82%, transparent 100%);
}

/* Die zuklappbare Gruppe. Die Zahl in der Zusammenfassung bleibt sichtbar,
   auch zugeklappt - das ist die Bedingung, unter der Zuklappen erlaubt ist. */
.qs-takt-klappe > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
.qs-takt-klappe > summary::-webkit-details-marker { display: none; }
.qs-takt-klappe > summary::before {
  content: '▸';
  color: var(--text-muted);
  font-size: 12px;
  transition: transform 120ms ease;
}
.qs-takt-klappe[open] > summary::before { transform: rotate(90deg); }
.qs-takt-klappe > summary h2 { margin: 0; }
.qs-takt-klappe > summary:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ---- Wandseite Messwerte (14.09.2026) ----
   ⚠️ DIE SCHRIFTGRÖSSE IST DIE VORGABE, die Kachelhöhe folgt daraus. Nicht
   umgekehrt - der erste Entwurf hat eine Kachelgröße festgeschrieben und die
   Schrift daraus abgeleitet, und die Gegenprüfung hat das widerlegt.
   Gerechnet für 42 Zoll (930 mm Bildbreite) bei 1920 px = 0,484 mm je Pixel,
   Leseabstand 4 m, Arbeitsregel 2,5-4 mm Versalhöhe je Meter:
     46 px = 22,3 mm = 19,2'   Zielwert Maschinenname
     29 px = 14,0 mm = 12,0'   Mindestmaß
   Die Arbeitsregel ist NICHT aus einer Norm belegt und gehört am
   aufgestellten Schirm nachgemessen. */
.qs-messwerte-raster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  gap: 12px;
}
.qs-messwerte-kachel {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.qs-messwerte-maschine { font-size: 46px; font-weight: 700; line-height: 1.1; }
.qs-messwerte-auftrag  { font-size: 29px; color: var(--text-secondary); }
.qs-messwerte-status   { font-size: 29px; font-weight: 700; }
.qs-messwerte-nio      { color: var(--urgent); }
.qs-messwerte-leer     { font-size: 29px; color: var(--text-muted); }
.qs-messwerte-meldung  { font-size: 29px; color: var(--text-secondary); }

/* Kopfzeile und Fußzeile.
   ⚠️ AUCH DIESE DREI BRAUCHEN 29 px. Ungestylt stünden sie bei ~16 px, also
   7,7 mm - unter dem Mindestmaß. Ausgerechnet die Störungszeile macht Zustand
   D sichtbar; wäre sie auf 4 m unlesbar, behauptete der Schirm wieder
   zehnmal "Kein laufender Auftrag", ohne dass jemand den Grund sähe. */
.qs-messwerte-stand    { font-size: 29px; color: var(--text-secondary); margin: 0; }
.qs-messwerte-stoerung { font-size: 29px; color: var(--urgent); font-weight: 700; margin: 0; }
.qs-messwerte-fuss     { font-size: 29px; color: var(--text-secondary); margin: 12px 0 0; }

/* Zustand C: die ganze Kachelfläche wechselt. Ein Balken von 3 px trägt auf
   4 m nicht (1,25'), eine Fläche schon. Keine neue Farbe - --blocked-bg ist
   die vorhandene Marke für "hier stimmt etwas nicht". */
.qs-messwerte-c { background: var(--blocked-bg); }

/* Die Feinschrift des Bildes verschwindet NUR auf dem Wandmonitor und NUR in
   einer Kachel.
   ⚠️ visibility, NICHT display:none: die Probe misst Textkästen über getBBox
   und filtert w>0 && h>0 - mit display:none liefen zwei Prüffälle lautlos
   leer und einer rot. fill:transparent ist ebenfalls verboten, es höhlt den
   Durchsichtigkeits-Wächter aus (Farbregel qs.css:42-45).
   ⚠️ Der Selektor ist geschachtelt. Unbedingt auf .qs-urwertkarte-svg
   geschrieben, träfe er die Probeseite qs-urwertkarte-probe.html mit. */
.qs-app.ist-wandmonitor .qs-messwerte-kachel .qs-urwertkarte-svg text {
  visibility: hidden;
}


/* ==================================================================== */
/* Wandseite Messwerte: dunkel, nach dem Muster des Maschinen-Dashboards */
/* -------------------------------------------------------------------- */
/* (15.09.2026, Vorgabe Thomas: "nach dem Design von dem Dashboard")      */
/*                                                                        */
/* ⚠️ ALLES HAENGT AN `body.qs-wand` bzw. `.ist-wandmonitor`. qs.css wird  */
/* von 26 Seiten geladen - eine ungescopte Regel hier faerbt das ganze     */
/* QS-Modul dunkel. Die Gegenprobe dazu: qs-laufkarten muss hell bleiben.  */
/*                                                                        */
/* ⚠️ WARUM DIE TOKEN AUF `body` STEHEN UND NICHT AUF `.qs-app`:           */
/* `html, body` holt sich seinen eigenen Grund aus `background:            */
/* var(--page-plane)` (style.css:122-127). Eine Definition weiter innen    */
/* wuerde der Body nicht mehr sehen - die Kacheln waeren dunkel und die    */
/* Flaeche darunter hell. Auf `body` gesetzt, sieht sie auch der Body.     */
/*                                                                        */
/* 🔑 DIE WERTE SIND KEINE ERFINDUNG. Sie sind der Dunkelmodus, den        */
/* style.css in `@media (prefers-color-scheme: dark)` (Zeile 79-118) schon */
/* fuehrt - derselbe, aus dem auch das Maschinen-Dashboard seine Farben    */
/* nimmt (--page-plane #0d0d0d = dessen --seite, --surface-1 #1a1a19 =     */
/* dessen --kachel, die drei Textstufen sind identisch). Der Wandrechner   */
/* laeuft im Hellmodus, deshalb greift der Media-Block dort nicht; hier    */
/* gilt der Dunkelmodus unabhaengig von der Einstellung des Rechners.      */
/* ⚠️ Das ist eine KOPIE. Wer den Dunkelmodus in style.css aendert, zieht  */
/* hier nach - sonst laufen die beiden Staende auseinander.                */
/*                                                                        */
/* 🔑 Die Urwertkarte braucht KEINE eigene Behandlung: qs-urwertkarte.js   */
/* zeichnet mit `var(--urgent)`, `var(--text-secondary)`, `var(--gridline)`*/
/* usw. statt mit festen Farben (qs-urwertkarte.js:1329-1333). Sie faerbt  */
/* sich also mit um, sobald die Token hier stehen.                         */
/* ==================================================================== */

body.qs-wand {
  --brand-primary:  #1baf8f;
  --brand-accent:   #1be0af;
  --surface-1:      #1a1a19;
  --page-plane:     #0d0d0d;
  --text-primary:   #ffffff;
  --text-secondary: #c3c2b7;
  --text-muted:     #898781;
  --gridline:       #2c2c2a;
  --baseline:       #383835;
  --border:         rgba(255, 255, 255, 0.10);
  --weekend-bg:     rgba(255, 255, 255, 0.045);
  --blocked-bg:     rgba(255, 255, 255, 0.05);
  --success-text:   #0ca30c;
  --urgent:         #ff4040;
  color-scheme: dark;
}

/* Kopfzeile im Dashboard-Muster: Marke links, Titel mittig, Uhr rechts.
   Die 3-px-Markenkante oben faellt hier weg - das Dashboard traegt sie
   nicht, und der Kopf soll wie dort mit einer Haarlinie abschliessen. */
.qs-app.ist-wandmonitor .toolbar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0 24px;
  border-top: 0;
  border-bottom: 1px solid var(--gridline);
  background: var(--page-plane);
  padding: 10px 21px;
}

.qs-wand-links { display: flex; align-items: center; gap: 22px; min-width: 0; }

/* Die Wortmarke ist WEISS auf durchsichtig - sie traegt nur auf dunklem
   Grund. Wer diese Seite je aufhellt, braucht eine zweite Bilddatei. */
.qs-wand-marke { flex: none; display: flex; align-items: center; }
.qs-wand-marke img { height: 34px; width: auto; display: block; }

/* Haarlinie zwischen Marke und Systemnamen - neutral, nicht im Markengruen:
   Gruen heisst auf den Wandseiten "in Ordnung". */
.qs-wand-text {
  min-width: 0;
  padding-left: 22px;
  border-left: 1px solid rgba(255, 255, 255, 0.18);
}

.qs-app.ist-wandmonitor .toolbar h1 {
  margin: 0;
  font-size: 26px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-primary);
}

/* Der Seitenname steht mittig und ist die Zeile, die man im Vorbeigehen
   liest - deshalb groesser als der Systemname, aber ohne Sperrung. */
.qs-wand-titel {
  margin: 0;
  font-size: 34px;
  font-weight: 600;
  line-height: 1.05;
  text-align: center;
  white-space: nowrap;
  color: var(--text-primary);
}

.qs-wand-rechts { text-align: right; min-width: 0; }

.qs-wand-uhr {
  margin: 0;
  font-size: 40px;
  font-weight: 700;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

/* Stand und Stoerung ruecken unter die Uhr und werden leiser - in der
   alten Leiste standen sie in 29 px neben dem Titel. */
.qs-app.ist-wandmonitor .qs-wand-rechts .qs-messwerte-stand,
.qs-app.ist-wandmonitor .qs-wand-rechts .qs-messwerte-stoerung {
  font-size: 16px;
  margin: 2px 0 0;
}

/* Navigation: leise unter dem Systemnamen, wie die Legenden im Dashboard. */
.qs-app.ist-wandmonitor .qs-wand-text .page-nav {
  display: flex;
  gap: 16px;
  margin-top: 4px;
}

.qs-app.ist-wandmonitor .qs-wand-text .page-nav-link {
  font-size: 15px;
  color: var(--text-muted);
  background: none;
  border: 0;
  padding: 0;
}

.qs-app.ist-wandmonitor .qs-wand-text .page-nav-link.active {
  color: var(--text-primary);
  background: none;
}

/* Kachelflaeche und Rand wie im Dashboard: gefuellte Flaeche, weicher Rand,
   keine Schlagschatten. */
.qs-app.ist-wandmonitor .qs-messwerte-kachel {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: none;
}
