/* Additions on top of ci.css (copied verbatim from the zaehlapp_monitor
 * deployment at 192.168.4.4:8810 so this app matches its look exactly). Every
 * new class here follows ci.css's own rule: declare a token, don't hardcode a
 * color, so both themes stay correct. Nothing in ci.css itself is touched
 * beyond the two logo filenames (unhashed here — no static manifest yet).
 */

.zaehlstand.fehlt{background:var(--schlecht-weich); color:var(--schlecht)}

.punkt.gut{background:var(--gut)}
.punkt.warn{background:var(--warn)}
.punkt.schlecht{background:var(--schlecht)}
.ipc-speicher{display:inline-flex; align-items:center; gap:4px; cursor:help}
.batterie{position:relative; display:inline-block; width:22px; height:11px; border:1.5px solid currentColor; border-radius:2px; box-sizing:border-box}
.batterie::after{content:""; position:absolute; right:-4px; top:2.5px; width:2px; height:4px; background:currentColor; border-radius:0 1px 1px 0}
.batterie-fuellung{position:absolute; left:1px; top:1px; bottom:1px; max-width:calc(100% - 2px); border-radius:1px; background:currentColor}
.ipc-speicher.gut .batterie-fuellung{background:var(--gut)}
.ipc-speicher.warn{color:var(--warn); font-weight:600}
.ipc-speicher.schlecht{color:var(--schlecht); font-weight:600}
.wann.schlecht{color:var(--schlecht); font-weight:600}
.ipc-speicher.veraltet{opacity:.55}

.stufenpunkte{display:flex; gap:10px; flex-wrap:wrap; align-items:center}
.stufenpunkt{display:flex; align-items:center; font-size:12.5px; color:var(--schrift2)}

/* The click-to-mark overlay.
   display lives in a :not([hidden]) rule, not inline — an inline display
   would outrank [hidden]'s own display:none and the panel could never
   actually be hidden by setting the attribute, which is exactly the bug
   this was written to fix. Toggle with el.hidden, nothing else. */
.markerueberlagerung{position:fixed; inset:0; background:rgba(0,0,0,.6); z-index:50}
.markerueberlagerung:not([hidden]){display:flex; align-items:center; justify-content:center}

/* Finish/Discard sit there greyed out until they would do something, rather
   than appearing and disappearing as points are clicked — buttons that come
   and go move the row under the cursor, and while they were gone nothing
   said the two steps existed. ci.css styles .knopf but has no disabled
   state, so it is declared here. */
.knopf[disabled]{opacity:.4; cursor:not-allowed}
.knopf[disabled]:hover{background:var(--feld); color:var(--schrift2)}

/* Finish, once the shape has enough points to be saved. This is the only
   prompt the panel gives now: it used to print a sentence naming the frame,
   which changed length on every click and shifted the toolbar row under the
   cursor. A button that lights up in place says the same thing and moves
   nothing. */
.knopf.betont{background:var(--gut); border-color:var(--gut); color:#fff; font-weight:600}
.knopf.betont:hover{background:var(--gut); color:#fff; filter:brightness(1.08)}

/* The colour swatch on a label button in the marker panel — the same colour
   that label is drawn in over the picture. Added because every typed label
   used to share one orange, so three custom defects on a frame were
   indistinguishable. */
.marker-klasse .labelfarbe{display:inline-block; width:8px; height:8px; border-radius:50%;
  margin-right:5px; vertical-align:baseline; border:1px solid rgba(0,0,0,.35)}

/* The Incoming filter controls. Was four copies of the same inline style
   block; one class instead, so they cannot drift apart. */
.feld{background:var(--feld); color:var(--schrift); border:1px solid var(--linie2);
  border-radius:8px; padding:6px 10px; font:inherit}

/* An empty date input still shows the browser's own dd.mm.yyyy placeholder,
   in normal text colour, which reads as a date that has been set - so the
   From/To pair looked like an active range when nothing was filtered. Faded
   while empty, full strength the moment a date is picked.
   The webkit rule is needed as well as `color`: Chrome paints the date parts
   through those pseudo-elements and ignores the field's own colour. */
.datumsfeld.leer{color:var(--schrift2); opacity:.55}
.datumsfeld.leer::-webkit-datetime-edit{color:var(--schrift2)}
.datumsfeld:focus{opacity:1; color:var(--schrift)}

/* Native form controls have to follow the app's own theme, not just the
   operating system's.
   The document declares color-scheme "light dark", which tells the browser to
   render its built-in widgets from the OS preference. The theme switcher sets
   data-thema instead, so someone on a light OS who picks dark got a page
   painted dark with Chrome still drawing light-mode controls into it — and
   the date field's calendar button is a dark glyph, which on our dark field
   is invisible. The picker was always there; it could not be seen or aimed
   at, so the field looked type-only.
   Mirrors ci.css's own three-state logic: system by default, data-thema wins
   when set. */
:root[data-thema="dunkel"]{color-scheme:dark}
:root[data-thema="hell"]{color-scheme:light}

/* Fixed width, because a date input sizes itself to its content and browsers
   disagree about how much room that needs — the same field is visibly wider
   in Safari than in Chrome. Pinned so the four filter controls line up, with
   border-box so the padding above is inside the number rather than added to
   it. Comfortably more than "dd.mm.yyyy" plus the picker button needs. */
.datumsfeld{width:10.5em; box-sizing:border-box}

/* The author badge in the marker list. Monospace so two initials always
   occupy the same width and the column does not jitter as the list is
   redrawn, and tabular figures on the timestamp beside it for the same
   reason. */
.perle.wer-kuerzel{background:var(--feld); color:var(--schrift2); border:1px solid var(--linie2);
  font-family:"Source Code Pro", ui-monospace, monospace; font-size:11px; letter-spacing:.04em}

/* The per-clip status dropdown. Coloured by state so a column of 180 rows
   can be scanned rather than read: "ready" is the one somebody is looking
   for when deciding what to send to CVAT. Narrow, because it sits between
   two columns that matter more. */
.standwahl{font-size:12px; padding:4px 8px; width:9.5em}
.standwahl[data-stand="fertig"]{background:var(--gut-weich); color:var(--gut); border-color:var(--gut)}
.standwahl[data-stand="laeuft"]{background:var(--warn-weich); color:var(--warn); border-color:var(--warn)}

/* The Labelling tab. */
/* Section headings with room above them: the tab is four sections on one
   page, and ci.css's h2 is sized for a heading that follows a paragraph. */
h2.abschnitt{margin:28px 0 10px}
/* Tables of names and words read left to right. table.diagnose right-aligns
   every column but the first because it was made for figures; here only the
   counts (.n) keep that. */
table.diagnose.links th,table.diagnose.links td{text-align:left}
table.diagnose.links th.n,table.diagnose.links td.n{text-align:right}
table.diagnose.schmal{min-width:0}
table.diagnose td.meldung{color:var(--schrift2); font-size:12.5px; max-width:52ch; white-space:normal}
/* Two small tables beside each other, stacked on a phone. */
.nebeneinander{display:grid; gap:16px; grid-template-columns:repeat(auto-fit,minmax(min(100%,360px),1fr))}
/* A job-progress bar: CVAT gives completed-of-total, nothing finer, so this
   is that fraction and the figure stays beside it. */
.fortschritt{display:inline-block; width:70px; height:6px; border-radius:99px; background:var(--feld2);
  vertical-align:middle; margin-right:6px; overflow:hidden}
.fortschritt i{display:block; height:100%; background:var(--gut)}
/* Something is happening: a small spinner inside an active upload's badge. */
.dreher{display:inline-block; width:9px; height:9px; margin-right:5px; vertical-align:-1px;
  border:2px solid currentColor; border-right-color:transparent; border-radius:50%;
  animation:dreher .9s linear infinite}
@keyframes dreher{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.dreher{animation:none; border-right-color:currentColor; opacity:.6}}
table.diagnose td.klein{font-size:12.5px; color:var(--schrift2); white-space:nowrap}

/* The labelling tool. The frame gets all the room the window has; the
   sidebar keeps a fixed width so the controls do not move as you work. */
.werkzeughuelle{max-width:1700px}
.wz-kopf{display:flex; flex-wrap:wrap; gap:10px; align-items:center; margin:0 0 12px}
.wz-titel{display:grid; gap:1px}
.wz-titel .unterzeile{margin:0; font-size:12.5px}
.wz-kopf .luft{flex:1 1 auto}
.wz-feldname{display:flex; gap:6px; align-items:center; font-size:12px; color:var(--schrift2)}
.wz-speicher{margin:0; font-size:12px; min-width:9ch}
.wz-speicher.schlecht{color:var(--schlecht)}
.wz-raster{display:grid; gap:16px; grid-template-columns:minmax(0,1fr) 310px; align-items:start}
@media (max-width:900px){.wz-raster{grid-template-columns:1fr}}
.wz-buehnenspalte{min-width:0}
.wz-buehne{position:relative; line-height:0; background:#000; border-radius:var(--rund); overflow:hidden;
  user-select:none; touch-action:none; max-width:min(100%, calc(100vh - 230px)); margin:0 auto}
.wz-buehne img{display:block; width:100%; height:auto}
.wz-buehne svg{position:absolute; inset:0; width:100%; height:100%; cursor:crosshair}
.wz-buehne[data-werkzeug="auswahl"] svg{cursor:default}
.wz-buehne .wz-spur .wz-koerper{cursor:move}
.wz-buehne .wz-spur.gesendet .wz-koerper{cursor:not-allowed}
.wz-buehne .wz-griff{cursor:nwse-resize}
.wz-buehne[data-anbau="1"] svg, .wz-buehne[data-anbau="1"] svg *{cursor:copy}
.wz-buehne .wz-spur.geist{opacity:.55}
.wz-buehne .wz-schild{font-family:"Source Code Pro",monospace; font-weight:600; paint-order:stroke;
  stroke:rgba(0,0,0,.7); stroke-width:3px; pointer-events:none}
.wz-buehne .wz-hinweis{cursor:pointer}
.wz-laden,.wz-meldung{position:absolute; left:10px; line-height:1.35; font-size:12.5px; padding:5px 9px;
  border-radius:6px; background:rgba(0,10,50,.78); color:#fff}
.wz-laden{top:10px}
.wz-meldung{bottom:10px; right:10px}
.wz-meldung.warn{background:rgba(138,90,16,.92)}
/* "Running inference… 45 %" on the frame while the page waits for the ONNX
   model, top right so it never covers "loading frame…". */
.wz-inferenz{position:absolute; top:10px; right:10px; min-width:180px; line-height:1.35; font-size:12.5px;
  padding:5px 9px 7px; border-radius:6px; background:rgba(0,10,50,.78); color:#fff; pointer-events:none}
.wz-inferenz-balken{display:block; height:3px; margin-top:5px; border-radius:2px; background:rgba(255,255,255,.25);
  overflow:hidden}
.wz-inferenz-balken[hidden]{display:none}
.wz-inferenz-balken i{display:block; height:100%; width:0; background:#fff; transition:width .2s}
.wz-transport{display:flex; gap:6px; align-items:center; margin:10px 0 6px; flex-wrap:wrap}
.wz-transport input[type=range]{flex:1 1 200px; min-width:120px}
.wz-framezahl{font-size:12.5px; color:var(--schrift2); min-width:15ch; text-align:center}
.wz-spielen{min-width:38px}
.wz-zeitleiste{display:block; width:100%; cursor:pointer; border-radius:6px}
.wz-zl-grund{fill:var(--feld)}
.wz-zl-kf{fill:var(--schrift)}
.wz-zl-jetzt{fill:var(--akzent)}
.wz-seite{display:grid; gap:12px}
.wz-block{background:var(--feld); border:1px solid var(--linie); border-radius:var(--rund); padding:10px 12px}
.wz-block h3{font-size:11.5px; text-transform:uppercase; letter-spacing:.06em; color:var(--schrift3); margin:0 0 8px; font-weight:600}
.wz-block p{margin:0 0 8px; font-size:13px}
.wz-block .gruppe{display:flex; flex-wrap:wrap; gap:6px}
.wz-block kbd{font:600 10px "Source Code Pro",monospace; opacity:.6; margin-left:3px}
.wz-block .labelfarbe{display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:5px;
  border:1px solid rgba(0,0,0,.35)}
.wz-eigenes{display:flex; gap:6px; margin-top:8px}
.wz-eigenes .feld{flex:1 1 auto; min-width:0; padding:4px 9px; font-size:13px}
.wz-objekte{display:grid; gap:4px; max-height:280px; overflow:auto}
.wz-objekt{display:flex; gap:6px; align-items:center; width:100%; text-align:left; font:inherit; font-size:13px;
  background:var(--grund); color:var(--schrift); border:1px solid var(--linie); border-radius:7px; padding:5px 8px; cursor:pointer}
.wz-objekt > span:nth-child(2){flex:1 1 auto}
.wz-objekt.sichtbar{border-color:var(--linie2)}
.wz-objekt.gewaehlt{border-color:var(--akzent); box-shadow:inset 3px 0 0 var(--akzent)}
.wz-hilfe summary{cursor:pointer; font-size:13px; font-weight:600}
.wz-hilfe ol{margin:8px 0; padding-left:18px; font-size:13px; color:var(--schrift2)}
.wz-hilfe li{margin:0 0 5px}
.wz-hilfe p{font-size:11.5px; color:var(--schrift3)}

/* Incoming: a row is clickable and opens its preview underneath. */
tr.clipzeile{cursor:pointer}
tr.clipzeile:focus-visible{outline:2px solid var(--akzent); outline-offset:-2px}
tr.clipzeile.offen td{background:var(--feld)}
/* Relevant clips: labelled before the others, so they stand out in the list. */
tr.clipzeile.relevant td{background:var(--akzent-weich)}
tr.clipzeile.relevant td:first-child{box-shadow:inset 3px 0 0 var(--akzent)}
tr.clipzeile .relevantzelle{text-align:center}
tr.clipzeile .relevantwahl{width:16px; height:16px; cursor:pointer; accent-color:var(--akzent)}
tr.clipzeile .clipname{font-size:12.5px; white-space:nowrap}
tr.clipzeile .aufklapper{display:inline-block; transition:transform .15s; color:var(--schrift3)}
tr.clipzeile.offen .aufklapper{transform:rotate(90deg); color:var(--akzent)}
tr.vorschauzeile > td{background:var(--feld); padding:12px 14px 16px !important; text-align:left !important}
.vorschaufeld{display:flex; gap:18px; align-items:flex-start; flex-wrap:wrap}
.vorschaufeld video{width:min(640px,100%); max-height:46vh; background:#000; border-radius:8px; display:block}
.vorschauseite{display:grid; gap:10px; max-width:320px; justify-items:start}
.vorschauseite .unterzeile{margin:0}
.knopf.vorschaulabel{font-size:15px; padding:9px 18px}
.wz-zl-zahl{fill:var(--schrift3); font:10px "Source Code Pro",monospace}
.wz-auto{display:flex; gap:7px; align-items:center; margin-top:10px; font-size:13px; font-weight:600; cursor:pointer}
.wz-auto input{width:16px; height:16px; accent-color:var(--gut)}

/* Labels over the Incoming preview. */
.vorschaubuehne{position:relative; line-height:0}
.vorschauebene{position:absolute; pointer-events:none; overflow:visible}
.vorschauebene .ebene-schild{font:600 3.2px "Source Code Pro",monospace; paint-order:stroke;
  stroke:rgba(0,0,0,.75); stroke-width:.6px}
.vorschauframe{position:absolute; top:8px; left:8px; line-height:1.3; font-size:11.5px; padding:2px 7px;
  border-radius:5px; background:rgba(0,10,50,.7); color:#fff; pointer-events:none}
.vorschauframe:empty{display:none}
.vorschaulabels{display:grid; gap:6px; font-size:13px; color:var(--schrift2)}
.vorschauperlen{display:flex; flex-wrap:wrap; gap:5px}
.vorschauperlen .perle{display:inline-flex; align-items:center; gap:5px; background:var(--grund); color:var(--schrift)}
.vorschauperlen .perle i{width:8px; height:8px; border-radius:50%}
.vorschauschalter{display:flex; gap:6px; align-items:center; font-size:13px; color:var(--schrift2); cursor:pointer}

/* View filters in the labelling tool. The filtered picture lies exactly over
   the frame (under the shapes), scaled from its 512-px working size. */
.wz-buehne .wz-filterbild{position:absolute; inset:0; width:100%; height:100%; pointer-events:none}
.wz-buehne .wz-filterbild[hidden]{display:none}
.wz-filterwahl{display:flex; flex-wrap:wrap; gap:6px}
.wz-filterhinweis{margin:8px 0 0; font-size:12px}

/* The ONNX filter's legend under the filter buttons: each class in its label
   colour with its share of the frame, then the model and how long it took. */
.wz-modell{display:grid; gap:6px; margin-top:8px}
.wz-modell[hidden]{display:none}
.wz-modell-klassen{display:flex; flex-wrap:wrap; gap:5px}
.wz-modell-klassen .perle{display:inline-flex; align-items:center; gap:5px; background:var(--grund); color:var(--schrift)}
.wz-modell-klassen .perle i{width:8px; height:8px; border-radius:50%}
.wz-modell .unterzeile{margin:0; font-size:12px; overflow-wrap:anywhere}
.wz-modell .unterzeile.schlecht{color:var(--schlecht)}
/* The ONNX model dropdown, under the filter buttons whenever there is a model. */
.wz-modellwahl{margin-top:8px}
.wz-modellwahl select{flex:1; min-width:0}

/* The line's health label in the header (monitor/ziel.py). */
.ziel{display:inline-flex; align-items:center; gap:.4em; margin-left:1em; padding:.15em .6em; border-radius:999px; border:1px solid currentColor; font-size:.85em; font-weight:600; text-decoration:none; white-space:nowrap}
.ziel .punkt{width:.6em; height:.6em; margin-right:0; border-radius:50%; background:currentColor}
.ziel-gesund{color:var(--gut); background:var(--gut-weich)}
.ziel-gestoert{color:var(--warn); background:var(--warn-weich)}
.ziel-weg{color:var(--schlecht); background:var(--schlecht-weich)}

/* ---------- Events (monitor/ereignisse.py) ---------- */
/* The filter row: labelled fields side by side, the tag ticks as one group. */
.eg-filter{align-items:flex-end}
.eg-feldname{display:grid; gap:4px; font-size:12px; color:var(--schrift2)}
.eg-tags{border:0; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:4px 12px; align-items:center}
.eg-tags legend{padding:0; margin-bottom:4px; float:left; width:100%}
/* Cards: the frame on top, the figures under it. */
.eg-raster{display:grid; gap:12px; grid-template-columns:repeat(auto-fill,minmax(250px,1fr))}
.eg-bilder{grid-template-columns:repeat(auto-fill,minmax(220px,1fr))}
.eg-karte{margin:0; background:var(--grund); border:1px solid var(--linie);
  border-top:3px solid var(--linie2); border-radius:var(--rund); overflow:hidden;
  box-shadow:var(--schatten); display:flex; flex-direction:column}
.eg-karte.eg-modell_verpasst{border-top-color:var(--schlecht)}
.eg-karte.eg-beide{border-top-color:var(--warn)}
.eg-karte.eg-nur_modell{border-top-color:var(--akzent)}
.eg-karte.eg-titel{outline:2px solid var(--gut); outline-offset:-2px}
.eg-bild{position:relative; display:block; aspect-ratio:1; background:var(--feld2)}
.eg-bild img{display:block; width:100%; height:100%; object-fit:cover}
/* The 32x32 grid cell that triggered the local score, drawn over the frame. */
.eg-feld{position:absolute; box-sizing:border-box; border:2px solid #ff2fbf;
  box-shadow:0 0 0 1px #000a; pointer-events:none}
.eg-text{padding:9px 11px 11px; display:grid; gap:7px; font-size:13px}
.eg-oben{display:flex; gap:8px; align-items:baseline; flex-wrap:wrap}
.eg-zeit{font:600 14px "Source Code Pro",monospace; font-variant-numeric:tabular-nums; color:var(--schrift)}
.eg-perlen{display:flex; gap:4px; flex-wrap:wrap}
.perle.eg-tag-modell_verpasst{background:var(--schlecht-weich); color:var(--schlecht); border-color:var(--schlecht)}
.perle.eg-tag-beide{background:var(--warn-weich); color:var(--warn); border-color:var(--warn)}
.perle.eg-tag-nur_modell{background:var(--akzent-weich); color:var(--akzent); border-color:var(--akzent)}
.perle.eg-tag-normal{background:var(--feld2); color:var(--schrift2); border-color:var(--linie2)}
.eg-werte{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:4px 8px; margin:0}
.eg-werte dt{color:var(--schrift3); font-size:10.5px; text-transform:uppercase; letter-spacing:.05em}
.eg-werte dd{margin:0; font-family:"Source Code Pro",monospace; font-variant-numeric:tabular-nums; font-size:12.5px}
.eg-schnell{display:flex; gap:4px; flex-wrap:wrap}
.eg-wer{margin:0; color:var(--schrift3); font-size:12px; overflow-wrap:anywhere}
.knopf.eg-wahl-defekt[aria-pressed="true"]{background:var(--schlecht); border-color:var(--schlecht)}
.knopf.eg-wahl-normal[aria-pressed="true"]{background:var(--gut); border-color:var(--gut)}
.knopf.eg-wahl-unklar[aria-pressed="true"]{background:var(--warn); border-color:var(--warn)}
.eg-karte.eg-entschieden-defekt .eg-wer{color:var(--schlecht)}
.eg-karte.eg-entschieden-normal .eg-wer{color:var(--gut)}
.eg-zaehler em{display:block; margin-top:2px}
.eg-zaehler.eg-modell_verpasst b{color:var(--schlecht)}
.eg-zaehler.eg-beide b{color:var(--warn)}
.eg-zaehler.eg-nur_modell b{color:var(--akzent)}
.eg-seiten,.eg-schritte{display:flex; gap:8px; align-items:center; margin:14px 0}
.eg-schritte{margin-top:0}
.eg-schritte .luft{flex:1 1 auto}
/* Detail: the maxima beside the decision form. */
.eg-kopfzeile{display:grid; gap:14px; grid-template-columns:minmax(0,1fr) minmax(280px,380px); align-items:start; margin-bottom:12px}
@media (max-width:760px){.eg-kopfzeile{grid-template-columns:1fr}}
.eg-maxima{margin:0}
.eg-entscheidung{background:var(--feld); border:1px solid var(--linie); border-radius:var(--rund);
  padding:12px 14px; display:grid; gap:8px}
.eg-entscheidung h3{margin:0; font-size:14px}
.eg-entscheidung textarea{width:100%; box-sizing:border-box; resize:vertical; font:inherit; font-size:13px}
.eg-wahl{display:flex; gap:6px; flex-wrap:wrap}
.eg-wahl label.knopf{display:inline-flex; gap:5px; align-items:center}
.eg-wahl label.eg-wahl-defekt:has(input:checked){background:var(--schlecht); border-color:var(--schlecht); color:#fff}
.eg-wahl label.eg-wahl-normal:has(input:checked){background:var(--gut); border-color:var(--gut); color:#fff}
.eg-wahl label.eg-wahl-unklar:has(input:checked){background:var(--warn); border-color:var(--warn); color:#fff}

/* The offline analysis' verdict per clip (monitor/urteil.py): Incoming's
   column and counts, the labelling tool's jump points. */
.perle.urteil-pruefen{background:color-mix(in srgb, var(--reihe-bild) 12%, var(--grund)); color:var(--reihe-bild); border-color:var(--reihe-bild)}
.urteil-zahlen{margin:0 0 10px; font-size:13px; color:var(--schrift2)}
.urteilzelle .unterzeile{font-size:11.5px; margin-top:3px; max-width:16em}
.wz-urteil h3 .perle{text-transform:none; letter-spacing:0; margin-left:4px; font-weight:500}
.wz-sprungzeile{display:flex; flex-wrap:wrap; gap:4px; align-items:center; margin-top:6px}
.wz-sprungzeile > .unterzeile:first-child{flex-basis:100%}
