/* TB Web – Kundenportal von TRIOBILD.
 *
 * Farben, Schrift und Bausteine stammen aus TB BauCam (Mac-App und Webfassung)
 * und der CityCam-Landingpage. Nichts davon ist neu erfunden.
 *
 * Die eine Regel, die über allem steht und aus dem Stylesheet von TB BauCam
 * übernommen ist: Gelb steht für Bedienung und Herkunft, nie für Zustände.
 * Ob eine Kamera erreichbar ist, bleibt grün bzw. rot – sonst verwechselt man
 * Markenfarbe mit einer Meldung.
 */

/* ------------------------------------------------------------ Farbwerte */

:root {
  /* Pantone 3955 · CMYK 15/0/100/0 · RGB 210/215/0 – der verbindliche Wert
   * aus Farbwerte_Logo_TRIOBILD.docx. */
  --gelb: #d2d700;
  --auf-gelb: #0f1208;
  /* Auf hellem Grund ist reines Gelb als Schrift unlesbar. Dann dieser Ton. */
  --gelb-schrift: #d2d700;
  --orange: #d75a1e;          /* Wetterstation, wie auf livebild.triobild.de */

  --tinte: #080808;          /* das Schwarz aus den Markenvorlagen */
  --grund: #0a0b0c;
  --grund-tief: #000;
  /* Flächen liegen jetzt näher am Grund. Vorher hoben sich die Karten
   * deutlich ab und zerlegten jede Seite in Kästen; jetzt trägt die Linie
   * die Gliederung, nicht der Helligkeitssprung. */
  --karte: #101113;
  --karte-hell: #17181a;
  /* Feinere Linien: 1 px bleibt 1 px, aber sie drängt sich nicht mehr auf. */
  --linie: #212327;
  --linie-leise: #16171a;
  --schrift: #e9eae5;
  --schrift-leise: #86887f;
  --gut: #64c07a;
  --schlecht: #e0655b;
  --achtung: #d99a3c;
  /* Schatten sind fast weg. Auf dunklem Grund tragen sie ohnehin wenig und
   * machen die Oberfläche schwer. */
  --schatten: 0 4px 16px rgba(0, 0, 0, .28);
  --schatten-klein: 0 1px 2px rgba(0, 0, 0, .12);

  --titelschrift: Montserrat, "Helvetica Neue", system-ui, sans-serif;
  --textschrift: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --zahlschrift: ui-monospace, SFMono-Regular, Menlo, monospace;

  --rund: 7px;
  --rund-gross: 12px;
  --breite: 1600px;
  color-scheme: dark;
}

:root[data-thema="hell"] {
  --gelb-schrift: #5f6300;
  --tinte: #080808;
  --grund: #ffffff;
  --grund-tief: #0b0c0d;      /* Bildflächen bleiben schwarz, auch im Hellen */
  --karte: #fbfbf6;
  --karte-hell: #ffffff;
  --linie: #e8e9de;
  --linie-leise: #f2f3ea;
  --schrift: #121409;
  --schrift-leise: #6b6e5f;
  --gut: #3f8f56;
  --schlecht: #c0392f;
  --achtung: #a56b12;
  --schatten: 0 9px 18px rgba(17, 19, 8, .12);
  --schatten-klein: 0 1px 3px rgba(17, 19, 8, .08);
  color-scheme: light;
}

/* ----------------------------------------------------------- Grundlagen */

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--grund);
  color: var(--schrift);
  font: 15px/1.6 var(--textschrift);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Überschriften waren halbfett. Auf dunklem Grund wirkt das schnell klobig –
 * dort trägt schon der Helligkeitsunterschied. Leichteres Gewicht, dafür
 * etwas engerer Buchstabenabstand: wirkt feiner, bleibt gut lesbar. */
h1, h2, h3, h4 {
  font-family: var(--titelschrift);
  font-weight: 500;
  letter-spacing: -.012em;
  line-height: 1.25;
}
h1 { font-size: 1.55rem; }
h2 { font-size: 1.08rem; }
h1 { font-size: 1.35rem; margin: 0 0 .2rem; }
h2 { font-size: 1.05rem; margin: 0 0 .75rem; }
h3 { font-size: .95rem; margin: 0 0 .5rem; }

a { color: var(--gelb-schrift); text-decoration: none; }
a:hover { text-decoration: underline; }

.sinnbild { display: block; flex: 0 0 auto; }
.leise { color: var(--schrift-leise); }
.klein { font-size: .82rem; }
.zahlen { font-variant-numeric: tabular-nums; }
.dehnen { flex: 1 1 auto; }
.trenner { width: 1px; align-self: stretch; background: var(--linie); }

main {
  max-width: var(--breite);
  margin: 0 auto;
  padding: 1.5rem 1.5rem 4rem;
}

/* ------------------------------------------------------------ Kopfzeile */

.kopf {
  position: sticky;
  top: 0;
  z-index: 20;
  /* Leicht durchscheinend statt massiv schwarz: Beim Blättern schimmert der
   * Inhalt darunter durch, die Leiste wirkt dünner, als sie ist. */
  background: color-mix(in srgb, var(--grund-tief) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--linie-leise);
}
:root[data-thema="hell"] .kopf {
  background: color-mix(in srgb, #fff 88%, transparent);
}

.kopfzeile {
  max-width: var(--breite);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: .65rem 1.5rem;
}

.marke { display: flex; align-items: baseline; gap: .5rem; flex: 0 0 auto; }
.marke:hover { text-decoration: none; }
.marke svg { height: 15px; width: auto; color: var(--gelb); display: block; }
:root[data-thema="hell"] .marke svg { color: #22240f; }
.marke em {
  font-style: normal;
  font-family: var(--titelschrift);
  font-weight: 500;
  font-size: .9rem;
  letter-spacing: .08em;
  color: var(--schrift-leise);
}

/* Baustelle links neben den Modulen: erst der Ort, dann was man dort tut. */
.ortwahl { position: relative; flex: 0 0 auto; }
.ortknopf {
  display: flex;
  align-items: center;
  gap: .45rem;
  background: var(--karte);
  border: 1px solid var(--linie);
  color: var(--schrift);
  border-radius: var(--rund);
  padding: .4rem .7rem;
  font: 500 .88rem var(--textschrift);
  cursor: pointer;
  max-width: 15rem;
}
.ortknopf:hover { border-color: var(--gelb); }
.ortknopf .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ortknopf .sinnbild { color: var(--schrift-leise); }
.ortfest {
  display: flex;
  align-items: center;
  gap: .45rem;
  font-size: .88rem;
  font-weight: 500;
  color: var(--schrift-leise);
  white-space: nowrap;
}

.ortliste {
  position: absolute;
  top: calc(100% + .4rem);
  left: 0;
  min-width: 16rem;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  box-shadow: var(--schatten);
  padding: .3rem;
  z-index: 30;
}
.ortliste a {
  display: block;
  padding: .45rem .6rem;
  border-radius: 4px;
  color: var(--schrift);
  font-size: .88rem;
}
.ortliste a:hover { background: var(--karte-hell); text-decoration: none; }
.ortliste a.hier { color: var(--gelb-schrift); font-weight: 600; }
.ortliste a small { display: block; color: var(--schrift-leise); font-size: .74rem; }

/* Modulleiste. Sieben Punkte – deshalb umbruchfähig, aber nie mittig
 * ausgerichtet: eine umgebrochene Leiste, die zentriert steht, wirkt wie ein
 * Absatz und nicht mehr wie eine Navigation. */
.module {
  display: flex;
  flex-wrap: wrap;
  gap: .15rem;
  margin-right: auto;
}
.module a, .module span {
  display: block;
  padding: .4rem .65rem;
  border-radius: 5px;
  font-size: .875rem;
  font-weight: 400;
  color: var(--schrift-leise);
  white-space: nowrap;
  transition: color .13s ease;
}
.module a:hover { color: var(--schrift); background: none; text-decoration: none; }
.module a.hier { color: var(--gelb-schrift); font-weight: 500; }
.module a.hier::after {
  content: "";
  display: block;
  height: 2px;
  margin-top: .3rem;
  border-radius: 1px;
  background: var(--gelb);
}
/* Nicht freigeschaltet: bleibt sichtbar, ist aber taub. */
.module span.aus { opacity: .32; cursor: not-allowed; }

.kopfwerkzeuge { display: flex; align-items: center; gap: .5rem; flex: 0 0 auto; }

.thema {
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  padding: 0;
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  background: none;
  color: var(--schrift-leise);
  cursor: pointer;
}
.thema:hover { color: var(--gelb-schrift); border-color: var(--gelb); }

.kontowahl { position: relative; }
.kontoknopf {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: none;
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  padding: .3rem .5rem .3rem .35rem;
  color: var(--schrift);
  font: 500 .85rem var(--textschrift);
  cursor: pointer;
}
.kontoknopf:hover { border-color: var(--gelb); }
.kuerzel {
  display: grid;
  place-items: center;
  width: 24px; height: 24px;
  border-radius: 4px;
  background: var(--gelb);
  color: var(--auf-gelb);
  font: 600 .7rem var(--titelschrift);
}
.kontoliste {
  position: absolute;
  top: calc(100% + .4rem);
  right: 0;
  min-width: 15rem;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  box-shadow: var(--schatten);
  padding: .3rem;
  z-index: 30;
}
.kontoliste .wer { padding: .5rem .6rem; border-bottom: 1px solid var(--linie); margin-bottom: .3rem; }
.kontoliste .wer strong { display: block; font-size: .88rem; }
.kontoliste .wer span { color: var(--schrift-leise); font-size: .78rem; }
.kontoliste a, .kontoliste button {
  display: block;
  width: 100%;
  text-align: left;
  padding: .45rem .6rem;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--schrift);
  font: .88rem var(--textschrift);
  cursor: pointer;
}
.kontoliste a:hover, .kontoliste button:hover { background: var(--karte-hell); text-decoration: none; }

/* --------------------------------------------------------- Formularteile */

input, select, textarea {
  /* Deckend, nicht durchscheinend. Ein halbdurchsichtiger Hintergrund sah im
   * dunklen Thema gut aus – im hellen drückten Auswahlfelder und Zeitfelder
   * ihren eigenen grauen Grund durch und wirkten wie gesperrt. Die Feinheit
   * trägt hier der Rahmen, nicht die Füllung. */
  background: var(--karte-hell);
  color: var(--schrift);
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  padding: .52rem .7rem;
  font: inherit;
  width: 100%;
  transition: border-color .13s ease, background-color .13s ease;
}
input:hover, select:hover, textarea:hover { border-color: var(--schrift-leise); }
/* Platzhalter sind Beispiele, kein Inhalt.
 *
 * Standardmäßig zeichnet der Browser sie fast so kräftig wie echten Text –
 * dann hält man ein leeres Feld für ein ausgefülltes und traut sich nicht,
 * hineinzuschreiben. Deutlich blasser und leicht kursiv: sofort als Beispiel
 * zu erkennen. */
input::placeholder, textarea::placeholder {
  color: var(--schrift-leise);
  opacity: .45;
  font-style: italic;
}
:root[data-thema="hell"] input::placeholder,
:root[data-thema="hell"] textarea::placeholder { opacity: .55; }

/* Kein dicker Rahmen beim Anklicken – eine feine gelbe Linie genügt und
 * bleibt im Bild, statt es zu sprengen. */
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--gelb);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--gelb) 18%, transparent);
}
label { display: block; }
.feld { display: flex; flex-direction: column; gap: .3rem; margin-bottom: .8rem; }
.feld > span { color: var(--schrift-leise); font-size: .82rem; }

button, .knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  background: var(--gelb);
  color: var(--auf-gelb);
  border: 0;
  border-radius: var(--rund);
  padding: .58rem 1.1rem;
  /* 600 war fett genug für eine Baustelle, aber nicht fein. 550 gibt es
   * nicht überall, deshalb 500 plus etwas Buchstabenabstand – das liest
   * sich ruhiger und bleibt auf gelbem Grund gut zu erkennen. */
  font: 500 .875rem var(--textschrift);
  letter-spacing: .005em;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .13s ease, border-color .13s ease,
              color .13s ease, opacity .13s ease;
}
button:hover, .knopf:hover { filter: brightness(1.12); text-decoration: none; }
button:disabled { opacity: .45; cursor: default; filter: none; }

.knopf.umrandet, button.umrandet {
  background: none;
  border: 1px solid var(--linie);
  /* Vorher `--schrift` – auf hellem Grund wirkten diese Knöpfe dadurch blass
   * und wie gesperrt. Etwas gedeckter, aber klar lesbar. */
  color: var(--schrift);
  font-weight: 450;
}
.knopf.umrandet:hover, button.umrandet:hover {
  border-color: var(--gelb);
  color: var(--gelb-schrift);
  filter: none;
}
.knopf.flach, button.flach {
  background: none;
  color: var(--schrift-leise);
  font-weight: 500;
  padding: .4rem .55rem;
}
.knopf.flach:hover, button.flach:hover {
  color: var(--gelb-schrift);
  background: var(--karte);
  filter: none;
}
.knopf.wetter { background: var(--orange); color: #fff; }

.ankreuz {
  display: flex;
  align-items: center;
  gap: .5rem;
  cursor: pointer;
  font-size: .88rem;
}
.ankreuz input { width: auto; flex: 0 0 auto; accent-color: var(--gelb); }

/* Schalter für „an / aus" – ein Ankreuzfeld sagt nicht deutlich genug,
 * dass hier eine Freigabe erteilt wird. */
.schalter { display: flex; align-items: center; gap: .7rem; cursor: pointer; }
.schalter input { position: absolute; opacity: 0; width: 0; height: 0; }
.schalter .bahn {
  flex: 0 0 auto;
  width: 38px; height: 22px;
  border-radius: 999px;
  background: var(--linie);
  border: 1px solid var(--linie);
  position: relative;
  transition: background .15s;
}
.schalter .bahn::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--schrift-leise);
  transition: transform .15s, background .15s;
}
.schalter input:checked + .bahn { background: var(--gelb); border-color: var(--gelb); }
.schalter input:checked + .bahn::after { transform: translateX(16px); background: var(--auf-gelb); }
.schalter input:focus-visible + .bahn { outline: 2px solid var(--gelb); outline-offset: 2px; }

/* -------------------------------------------------------------- Hinweise */

.hinweis {
  border-left: 3px solid var(--gelb);
  background: var(--karte);
  padding: .7rem 1rem;
  border-radius: 0 4px 4px 0;
  margin: 0 0 1rem;
}
.hinweis.gut { border-color: var(--gut); }
.hinweis.schlecht { border-color: var(--schlecht); }

/* Jede Fläche mit erfundenen Daten schreibt das sichtbar dazu. Ein
 * ausgedachter Messwert, den jemand für echt hält, ist schlimmer als eine
 * leere Fläche. Die Regel stammt aus TB BauCam. */
.beispielhinweis {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: 2rem;
  padding: .6rem .9rem;
  border: 1px dashed var(--linie);
  border-radius: var(--rund);
  color: var(--schrift-leise);
  font-size: .82rem;
}
.beispielhinweis strong { color: var(--schrift); font-weight: 600; }

.leer {
  color: var(--schrift-leise);
  padding: 4rem 1rem;
  text-align: center;
  border: 1px dashed var(--linie);
  border-radius: var(--rund-gross);
}
.leer .sinnbild { margin: 0 auto .8rem; color: var(--linie); }

/* ------------------------------------------------------------- Anmeldung */

.anmeldeseite {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 2rem 1.25rem 4rem;
}
.anmeldekarte { width: 100%; max-width: 23rem; }
.anmeldekarte .marke { justify-content: center; margin-bottom: 2rem; }
.anmeldekarte .marke svg { height: 22px; }
.anmeldekarte form {
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  padding: 1.75rem;
}
.anmeldekarte h1 { font-size: 1.15rem; margin-bottom: 1.25rem; }
.anmeldekarte button[type="submit"] { width: 100%; margin-top: .6rem; }
.anmeldefuss {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 1rem;
  font-size: .82rem;
}
.anmeldeseite .thema { position: fixed; top: 1.25rem; right: 1.25rem; }

.demokasten {
  margin-top: 1.25rem;
  border: 1px dashed var(--linie);
  border-radius: var(--rund);
  padding: .8rem .9rem;
  font-size: .8rem;
  color: var(--schrift-leise);
}
.demokasten strong { color: var(--schrift); display: block; margin-bottom: .4rem; }
.demokasten button {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 1px solid var(--linie);
  color: var(--schrift);
  font-weight: 400;
  padding: .35rem .5rem;
  margin-top: .3rem;
  font-size: .78rem;
}
.demokasten button { white-space: normal; line-height: 1.4; }
.demokasten button:hover { border-color: var(--gelb); filter: none; }
.demokasten code { font-family: var(--zahlschrift); color: var(--gelb-schrift); }

/* ------------------------------------------------------ Seitenkopf innen */

.seitenkopf {
  display: flex;
  align-items: flex-end;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}
.seitenkopf .titel { margin-right: auto; }
/* Sinnbilder sind `display: block` – in einem Rücklink muss das Zeichen neben
 * der Schrift stehen, nicht darüber. */
.zurueck {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .8rem;
  font-weight: 500;
  margin-bottom: .2rem;
}
.seitenkopf p { margin: 0; color: var(--schrift-leise); font-size: .88rem; }

/* ------------------------------------------------------ Baustellenwahl */

.ortkacheln {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: 1.25rem;
}
.ortkachel {
  display: block;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  overflow: hidden;
  color: inherit;
  transition: box-shadow .15s ease-out, border-color .15s ease-out;
}
.ortkachel:hover {
  text-decoration: none;
  box-shadow: var(--schatten);
  border-color: rgba(210, 215, 0, .6);
}
.ortkachel .bild { display: block; height: 11rem; background: #000; }
.ortkachel .bild img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ortkachel .text { padding: .9rem 1rem 1rem; }
.ortkachel h2 { margin: 0 0 .15rem; font-size: 1rem; }
.ortkachel .ort { color: var(--schrift-leise); font-size: .82rem; }
.ortkachel .zeile {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: .7rem;
  padding-top: .7rem;
  border-top: 1px solid var(--linie);
  font-size: .78rem;
  color: var(--schrift-leise);
}

/* ------------------------------------------------------------- Bildbühne
 *
 * Der Aufbau von livebild.triobild.de: Kopf mit Name und Wortmarke, darunter
 * eine schmale Zeile mit Live-Punkt und Zeitstempel, dann das Bild auf
 * Schwarz, unten die Bedienleiste. Bauarchiv, BauCam, Live Video und
 * Wiedergabe teilen sich diese Bühne.
 */

.buehne {
  display: grid;
  grid-template-columns: 22rem minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}
.buehne.ohne-spalte { grid-template-columns: minmax(0, 1fr); }

.tafel {
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  overflow: hidden;
}

.tafelkopf {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .9rem 1.15rem;
  border-bottom: 1px solid var(--linie-leise);
}
.tafelkopf .sinnbild { color: var(--gelb); }
.tafelkopf h1, .tafelkopf h2 { margin: 0; font-size: 1rem; }
.tafelkopf .wortmarke { margin: 0 auto; }
.tafelkopf .wortmarke svg { height: 17px; width: auto; color: var(--schrift); display: block; }

.umschalter {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--karte-hell);
  border: 1px solid var(--linie);
  border-radius: 7px;
}
.umschalter button {
  background: none;
  color: var(--schrift-leise);
  font-weight: 500;
  padding: .3rem .8rem;
  border-radius: 5px;
}
.umschalter button.an { background: var(--gelb); color: var(--auf-gelb); font-weight: 600; }
.umschalter button:not(.an):hover { color: var(--schrift); background: none; filter: none; }

.standzeile {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .45rem 1.15rem;
  border-bottom: 1px solid var(--linie-leise);
  background: var(--grund-tief);
  font-size: .78rem;
  color: var(--schrift-leise);
}
:root[data-thema="hell"] .standzeile { background: var(--karte-hell); }
.standzeile .dateiname {
  margin: 0 auto;
  font-family: var(--zahlschrift);
  font-size: .76rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.livepunkt { display: inline-flex; align-items: center; gap: .4rem; color: var(--schrift); }
.livepunkt::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--schlecht);
  animation: pochen 2.4s ease-in-out infinite;
}
@keyframes pochen { 0%, 100% { opacity: 1 } 50% { opacity: .35 } }
@media (prefers-reduced-motion: reduce) { .livepunkt::before { animation: none } }

/* Die Bildfläche legt sich um das Bild, nicht umgekehrt.
 *
 * Vorher war sie so breit wie die Tafel und schwarz hinterlegt – bei jedem
 * Bild, das nicht zufällig dieses Verhältnis hatte, standen links und rechts
 * schwarze Streifen. Unsere Kameras liefern 4:3, 16:9 und bei den
 * Doppelsensoren 32:9; ein festes Maß passt für höchstens eines davon.
 * `fit-content` braucht das Verhältnis gar nicht erst zu kennen. */
.bildflaeche {
  position: relative;
  display: grid;
  place-items: center;
  background: #000;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  overflow: hidden;
}
.bildflaeche img, .bildflaeche video {
  display: block;
  max-width: 100%;
  max-height: 68vh;
}
/* Solange kein Bild da ist, gibt es nichts, woran sich die Fläche halten
 * könnte – dann doch ein Mindestmaß, sonst klappt die Tafel zusammen. */
.bildflaeche.laedt, .bildflaeche:has(.platzhalter) { width: 100%; min-height: 18rem; }

/* Der Vergleichsschieber legt seine Bilder absolut übereinander und hat
 * deshalb keine eigene Größe – er verlangt `width: 100%`. In einer Fläche mit
 * `fit-content` sind 100 % von „so breit wie der Inhalt“ genau null, und die
 * Tafel blieb leer. Hier also volle Breite. */
.bildflaeche:has(.vergleich) { width: 100%; }

/* Vollbild: alle Begrenzungen der Seite aufheben.
 *
 * `width: fit-content` und `max-height: 68vh` sind für die Tafel richtig –
 * dort soll neben dem Bild noch die Bedienung Platz haben. Im Vollbild sind
 * sie falsch: Die Fläche schmiegte sich weiter ans Bild, und das Bild blieb
 * bei 68 % der Bildschirmhöhe stehen. Beides muss hier ausdrücklich zurück,
 * sonst erbt der Vollbildmodus die Maße der Seite.
 *
 * Zwei Schreibweisen, weil ältere Safari-Fassungen nur die mit `-webkit-`
 * kennen und eine Regel mit einer unbekannten Auswahl ganz verwerfen. */
.bildflaeche:fullscreen {
  width: 100%;
  height: 100%;
  max-width: none;
  margin: 0;
  display: grid;
  place-items: center;
  background: #000;
}
.bildflaeche:fullscreen img,
.bildflaeche:fullscreen video {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}
.bildflaeche:-webkit-full-screen {
  width: 100%;
  height: 100%;
  max-width: none;
  margin: 0;
  display: grid;
  place-items: center;
  background: #000;
}
.bildflaeche:-webkit-full-screen img,
.bildflaeche:-webkit-full-screen video {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}

/* Was im Vollbild nichts zu suchen hat: Startdecke und Ladehinweis liegen
 * über dem Bild und würden es verdecken, sobald es läuft. */
.bildflaeche:fullscreen .startdecke,
.bildflaeche:-webkit-full-screen .startdecke { position: absolute; inset: 0; }

/* Ein Video, das für sich allein ins Vollbild geht (Zeitraffer), soll den
 * Bildschirm ebenfalls ausfüllen. */
video:fullscreen { width: 100%; height: 100%; max-height: none; }
video:-webkit-full-screen { width: 100%; height: 100%; max-height: none; }
.bildflaeche .platzhalter {
  display: grid;
  justify-items: center;
  gap: .8rem;
  padding: 4rem 2rem;
  text-align: center;
  color: var(--schrift-leise);
}
.bildflaeche .platzhalter .sinnbild { color: rgba(139, 141, 133, .45); }
.bildflaeche .platzhalter p { margin: 0; max-width: 24rem; }

/* Blättern durch die Archivbilder unter dem Bild – mittig, damit die beiden
 * Richtungen gleich weit weg liegen. */
.blaetterzeile {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .8rem;
  flex-wrap: wrap;
  padding: .7rem 1rem;
  border-top: 1px solid var(--linie);
}
.blaetterzeile #blaetterstand {
  min-width: 9rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.tafelfuss {
  display: flex;
  align-items: center;
  gap: .65rem;
  flex-wrap: wrap;
  padding: .9rem 1.15rem;
  border-top: 1px solid var(--linie-leise);
}
.tafelfuss .klein { display: inline-flex; align-items: center; gap: .4rem; }
.tafelfuss .rechts { margin-left: auto; display: flex; gap: .5rem; flex-wrap: wrap; }
/* Auswahlfelder erben sonst `width: 100%` aus dem Formularteil und sprengen
 * die Bedienleiste auf eine eigene Zeile. */
/* Auflösungswahl: drei Knöpfe nebeneinander, der gewählte leuchtet. Eine
 * Auswahlliste versteckt, was möglich ist – hier soll man auf einen Blick
 * sehen, was es gibt und was gerade läuft. */
.groessenwahl { display: inline-flex; gap: 0; }
.groessenwahl button {
  border-radius: 0;
  border: 1px solid var(--linie);
  border-right-width: 0;
  background: none;
  color: var(--schrift-leise);
  font-size: .85rem;
  padding: .35rem .8rem;
}
.groessenwahl button:first-child { border-radius: var(--rund) 0 0 var(--rund); }
.groessenwahl button:last-child {
  border-radius: 0 var(--rund) var(--rund) 0;
  border-right-width: 1px;
}
.groessenwahl button:hover { color: var(--schrift); filter: none; }
.groessenwahl button.an {
  background: var(--gelb);
  /* `--auf-gelb`, nicht `--gelb-schrift`: Letzteres ist das Gelb für Text auf
   * dunklem Grund – auf gelbem Knopf wäre das gelb auf gelb. */
  color: var(--auf-gelb);
  border-color: var(--gelb);
  font-weight: 600;
}

.tafelfuss select, .tafelfuss input, .spaltenkopf select { width: auto; font-size: .85rem; padding: .35rem .5rem; }

/* Kameraauswahl als Streifen unter dem Bild – bei zwei Kameras ist ein
 * Auswahlmenü zu viel, bei acht wird eine Kachelwand zu laut. */
.kamerastreifen {
  display: flex;
  gap: .5rem;
  overflow-x: auto;
  padding: .8rem 1rem;
  border-top: 1px solid var(--linie);
  scrollbar-width: thin;
}
.kameraknopf {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: .5rem;
  background: none;
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  padding: .35rem .6rem .35rem .4rem;
  color: var(--schrift-leise);
  font: 500 .82rem var(--textschrift);
  cursor: pointer;
}
.kameraknopf img { width: 44px; height: 26px; object-fit: cover; border-radius: 3px; display: block; }
.kameraknopf:hover { color: var(--schrift); border-color: var(--schrift-leise); filter: none; }
.kameraknopf.an { border-color: var(--gelb); color: var(--gelb-schrift); background: none; }

.punkt { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.punkt.gut { background: var(--gut); }
.punkt.schlecht { background: var(--schlecht); }
.punkt.unbekannt { background: rgba(139, 141, 133, .5); }

/* --------------------------------------------------------- Archivspalte */

.spalte { display: flex; flex-direction: column; max-height: calc(100vh - 8rem); }
.spaltenkopf {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .9rem 1.15rem;
  border-bottom: 1px solid var(--linie-leise);
}
.spaltenkopf .sinnbild { color: var(--gelb); }
.spaltenkopf h2 { margin: 0; font-size: .95rem; margin-right: auto; }
.spaltenkopf input[type="date"] { width: auto; font-size: .82rem; padding: .35rem .5rem; }

.bildraster {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .6rem;
  padding: .8rem;
  overflow-y: auto;
  scrollbar-width: thin;
  /* Feste Reihenhöhe, und zwar aus einem bestimmten Grund: Die Spalte hat eine
   * begrenzte Höhe, damit sie für sich scrollt. Damit steht auch die Höhe des
   * Rasters fest – und ein Raster mit fester Höhe drückt Reihen der Größe
   * `auto` zusammen, bis alles hineinpasst. Weil die Kacheln `overflow: hidden`
   * tragen, ist ihre Mindesthöhe null: Sie fielen zu Streifen zusammen. */
  align-content: start;
  grid-auto-rows: 6.9rem;
}
.bildraster button {
  position: relative;
  /* Muss `flex` sein, nicht `block`: Ein <button> legt seinen Inhalt sonst in
   * eine anonyme Box, die nicht von einem Bild mit `aspect-ratio` mitwächst –
   * die Kacheln standen dann als Streifen da. Gilt genauso für die Filmliste. */
  display: flex;
  flex-direction: column;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--rund);
  overflow: hidden;
  background: #000;
  cursor: pointer;
}
.bildraster button { height: 100%; }
.bildraster button:hover { filter: none; border-color: var(--schrift-leise); }
.bildraster button.an { border-color: var(--gelb); }
.bildraster img { display: block; width: 100%; height: 5.4rem; object-fit: cover; flex: 0 0 auto; }
.bildraster .stempel {
  display: block;
  flex: 0 0 auto;
  padding: .3rem .4rem;
  background: rgba(0, 0, 0, .55);
  color: #f2f2ee;
  font-size: .7rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* ------------------------------------------------------------ Zeitraffer */

/* Vergleich im Bauarchiv: je Seite ein Tag und eine Uhrzeit. */
.vglwahl {
  display: flex;
  align-items: flex-end;
  gap: 1.2rem;
  flex-wrap: wrap;
  padding: .8rem 1rem;
  border-top: 1px solid var(--linie);
}
.vglseite { display: flex; align-items: center; gap: .5rem; }
.vglseite .marke {
  font-size: .82rem;
  font-weight: 600;
  color: var(--schrift-leise);
  min-width: 3.4rem;
}
.vglseite input, .vglseite select {
  width: auto;
  font-size: .85rem;
  padding: .35rem .5rem;
  height: 2.2rem;
  box-sizing: border-box;
}
.vglwahl .rechts { margin-left: auto; }

/* Startseite: Baustellen mit ihren Kameras.
 *
 * Oben der Name der Baustelle, darunter je Kamera eine Kachel mit dem Bild,
 * das auch unter BauCam steht. Die Kacheln sind bewusst groß – man soll die
 * Baustelle erkennen, nicht einen Namen entziffern. */
.baustellenblock { margin-bottom: 2rem; }

.baustellenkopf {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: 0 0 .7rem;
  margin-bottom: .9rem;
  border-bottom: 1px solid var(--linie);
}
.baustellenkopf h2 { margin: 0; font-size: 1.1rem; }
.baustellenkopf .sinnbild { color: var(--gelb); flex: 0 0 auto; }
.baustellenkopf .dehnen { flex: 1 1 auto; }

.kamerakacheln {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: 1rem;
}

.kamerakachel {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  overflow: hidden;
  background: var(--karte);
  color: var(--schrift);
  transition: border-color .12s ease, transform .12s ease;
}
.kamerakachel:hover {
  border-color: var(--gelb);
  transform: translateY(-2px);
}
/* Im Raster müssen die Kacheln gleich hoch sein, sonst steht die Reihe
 * schief. Ein festes 16:9-Fenster, und das Bild **füllt** es – die Vorschau
 * darf beschneiden, das ganze Bild ist einen Klick entfernt. Nur die sehr
 * breiten Panoramen (32:9) bekämen so nur ihre Mitte gezeigt; sie werden
 * per Skript als `breit` gekennzeichnet und ganz eingepasst.
 * Solange das Bild lädt, schimmert die Fläche leise, statt schwarz zu
 * starren – so sieht man: hier kommt gleich etwas. */
.kamerakachel .bild {
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: linear-gradient(100deg, var(--karte) 40%,
              var(--karte-hell) 50%, var(--karte) 60%);
  background-size: 300% 100%;
  animation: schimmer 1.6s ease-in-out infinite;
}
@keyframes schimmer {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}
/* Das Bild liegt **über** dem Fenster, nicht darin: `aspect-ratio` ist nur
 * ein Wunsch, den ein 4:3-Bild im Fluss überstimmen würde – die Kachel wüchse
 * dann doch in die Höhe. Herausgenommen aus dem Fluss bestimmt allein das
 * Fenster die Größe. */
.kamerakachel img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.kamerakachel img.breit { object-fit: contain; background: #000; }

.kamerakachel .fuss {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .7rem .85rem;
  font-weight: 500;
}
.kamerakachel .fuss .sinnbild { color: var(--schrift-leise); flex: 0 0 auto; }
.kamerakachel:hover .fuss .sinnbild { color: var(--gelb); }
.kamerakachel .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Zeitrafferliste.
 *
 * Das Bild bestimmt seine Höhe selbst. Vorher stand hier `height: 6.5rem` mit
 * `object-fit: cover` – bei einer Kachel, die breiter als 16:9 ist, schnitt
 * das oben und unten ab, und man sah von der Baustelle nur einen Streifen.
 *
 * Die Beschriftung liegt jetzt unter dem Bild statt als schwarzer Balken
 * darüber: Das Bild bleibt ganz, und die Liste wirkt ruhiger.
 */
.filmliste {
  display: flex;
  flex-direction: column;
  gap: .9rem;
  padding: .9rem;
  overflow-y: auto;
}
.filmliste button {
  flex: 0 0 auto;                        /* sonst quetscht die Spalte die Vorschau platt */
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 0;
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  overflow: hidden;
  background: var(--karte);
  cursor: pointer;
  text-align: left;
  transition: border-color .12s ease, transform .12s ease;
}
.filmliste button:hover {
  filter: none;
  border-color: var(--schrift-leise);
  transform: translateY(-1px);
}
.filmliste button.an { border-color: var(--gelb); }

.filmliste img {
  display: block;
  width: 100%;
  height: auto;                          /* ganzes Bild, nichts beschnitten */
  background: #000;
  flex: 0 0 auto;
}

.filmliste .beschriftung {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .55rem .7rem;
  color: var(--schrift);
  font-size: .82rem;
  font-weight: 500;
  line-height: 1.3;
}
.filmliste button.an .beschriftung { color: var(--gelb-schrift); }
.filmliste .beschriftung .sinnbild { color: var(--schrift-leise); flex: 0 0 auto; }
.filmliste button.an .beschriftung .sinnbild { color: var(--gelb); }
.filmliste .beschriftung .dauer {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  color: var(--schrift-leise);
  flex: 0 0 auto;
}

/* Wartefläche über dem Video.
 *
 * Vorher lag sie halbdurchsichtig über einem Abspieler, dessen Bedienleiste
 * schon da war, aber nichts tat – Knopf, Regler und Zeitleiste schienen durch
 * und überlagerten den Text. Das sah nach Fehler aus, nicht nach Warten.
 *
 * Jetzt: Die Bedienleiste kommt erst mit dem Bild (siehe wiedergabe.html),
 * dahinter steht das Standbild der Stelle, und darüber liegt ein weicher
 * Schleier mit Ring und zwei Zeilen. Der Schleier ist immer dunkel, deshalb
 * ist die Schrift hier fest hell – sonst wäre sie im hellen Thema grau auf
 * grau. */
.ueberdeckung {
  position: absolute; inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: .75rem;
  padding: 1.5rem;
  text-align: center;
  background: radial-gradient(ellipse at center,
              rgba(10, 11, 12, .82) 0%, rgba(10, 11, 12, .94) 100%);
  backdrop-filter: blur(2px);
  color: rgba(255, 255, 255, .72);
}
.ueberdeckung p { margin: 0; max-width: 24rem; }
.ueberdeckung .hauptzeile {
  color: #fff;
  font-size: 1.02rem;
  font-weight: 500;
  letter-spacing: .01em;
}
.ueberdeckung .klein { font-size: .84rem; line-height: 1.45; }
.ueberdeckung .sinnbild { color: var(--gelb); }

/* Der Ring dreht sich – ohne das sieht ein Aufbau, der ein paar Sekunden
 * dauert, aus wie ein Programm, das nichts tut. Ein starres Sinnbild genügt
 * dafür nicht. */
.ladekreis {
  width: 38px; height: 38px;
  border: 3px solid rgba(255, 255, 255, .16);
  border-top-color: var(--gelb);
  border-radius: 50%;
  animation: kreisel .85s linear infinite;
}
@keyframes kreisel { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .ladekreis { animation-duration: 2.4s; }
}

/* Aufnahmeknopf: ruhiger Punkt, im Betrieb rot und pulsend. Rot bleibt hier
 * dem Zustand vorbehalten – wie das Gelb sonst der Bedienung. */
.aufnahme { gap: .5rem; }
.aufnahme .punkt {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--schrift-leise);
  flex: 0 0 auto;
}
.aufnahme.laeuft { border-color: #c0392b; color: #e05a4a; }
.aufnahme.laeuft .punkt { background: #e04030; animation: blinken 1.1s ease-in-out infinite; }
@keyframes blinken { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .aufnahme.laeuft .punkt { animation: none; }
}

.abspielknopf {
  position: absolute;
  display: grid;
  place-items: center;
  width: 74px; height: 74px;
  border-radius: 50%;
  background: rgba(210, 215, 0, .92);
  color: var(--auf-gelb);
  border: 0;
  cursor: pointer;
}
.abspielknopf:hover { filter: brightness(1.1); }

/* ------------------------------------------------------------ Wiedergabe */

.zeitleiste {
  position: relative;
  height: 46px;
  margin: 0 1rem 1rem;
  background: var(--karte-hell);
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  overflow: hidden;
  cursor: pointer;
}
.zeitleiste .abschnitt {
  position: absolute;
  top: 8px;
  height: 18px;
  background: rgba(210, 215, 0, .55);
  border-radius: 2px;
}
.zeitleiste .abschnitt.bewegung { background: rgba(215, 90, 30, .6); }
.zeitleiste .marke {
  position: absolute;
  top: 0; bottom: 0;
  width: 2px;
  background: var(--schrift);
}
.zeitleiste .stunden {
  position: absolute;
  left: 0; right: 0; bottom: 2px;
  display: flex;
  justify-content: space-between;
  padding: 0 .3rem;
  font-size: .62rem;
  color: var(--schrift-leise);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

.abschnittsliste { list-style: none; margin: 0; padding: 0; overflow-y: auto; }
.abschnittsliste li { flex: 0 0 auto; }
.abschnittsliste li {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .55rem .8rem;
  border-bottom: 1px solid var(--linie-leise);
  font-size: .85rem;
}
.abschnittsliste li:hover { background: var(--karte-hell); }
.abschnittsliste .spanne { display: flex; flex-direction: column; margin-right: auto; }
.abschnittsliste .spanne strong { font-variant-numeric: tabular-nums; font-weight: 600; }
.abschnittsliste .spanne span { color: var(--schrift-leise); font-size: .74rem; }
.ausloeser {
  background: var(--karte-hell);
  border: 1px solid var(--linie);
  border-radius: 999px;
  padding: .1rem .55rem;
  font-size: .7rem;
  font-weight: 600;
  color: var(--orange);
}
.ausloeser.dauer { color: var(--schrift-leise); }

/* ------------------------------------------------------------- Downloads */

.tabelle { width: 100%; border-collapse: collapse; font-size: .88rem; }
.tabelle th {
  text-align: left;
  color: var(--schrift-leise);
  font-weight: 500;
  font-size: .8rem;
  border-bottom: 1px solid var(--linie);
  padding: .5rem .7rem;
}
.tabelle td { padding: .6rem .7rem; border-bottom: 1px solid var(--linie-leise); vertical-align: middle; }
.tabelle tr:hover td { background: var(--karte); }
.tabelle .rechts { text-align: right; }

.balken {
  position: relative;
  height: 6px;
  width: 8rem;
  background: var(--linie);
  border-radius: 3px;
  overflow: hidden;
}
.balken i { position: absolute; inset: 0 auto 0 0; background: var(--gelb); border-radius: 3px; }
.fertig { display: inline-flex; align-items: center; gap: .35rem;
          color: var(--gut); font-weight: 600; font-size: .8rem; }

/* ---------------------------------------------------------- Wetterstation
 *
 * Eine Kachel je Modul der Station – Basisstation, Außenmodul, Regenmesser,
 * Windmesser –, darin die Größen, die dieses Modul misst. Aufbau wie in der
 * Netatmo-App, damit sich beides deckt.
 */

.modulkacheln {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
  margin-bottom: 1.25rem;
}
.modulkachel {
  display: flex;
  flex-direction: column;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  padding: .9rem 1rem 1rem;
}
/* Heißt `messkopf` und nicht `kopf`: So heißt die Kopfzeile der Seite, und die
 * trägt schwarzen Grund samt `position: sticky`. */
.modulkachel .messkopf {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .88rem;
  margin-bottom: .8rem;
}
.modulkachel .messkopf .sinnbild { color: var(--schrift-leise); }
.modulkachel .messkopf strong { font-weight: 600; }
.batterie { display: flex; }
.batterie.gut { color: rgba(100, 192, 122, .55); }
.batterie.schlecht { color: var(--schlecht); }

/* Ein stummes Modul bleibt stehen und wird nicht ausgeblendet: Dass ein Wert
 * fehlt, ist selbst eine Auskunft – und eine Null hieße Windstille. */
.modulkachel.stumm { border-style: dashed; }
.modulkachel .keine {
  margin: 0;
  padding: .9rem 0;
  color: var(--schrift-leise);
  font-style: italic;
  font-size: .9rem;
}

.werteliste { display: flex; flex-wrap: wrap; gap: .9rem 1.4rem; }
.messwert { display: flex; flex-direction: column; }
.messwert .zahl {
  display: flex;
  align-items: center;
  gap: .35rem;
  font: 600 1.5rem/1.1 var(--titelschrift);
  font-variant-numeric: tabular-nums;
}
.messwert .zahl small { font-size: .78rem; font-weight: 500; color: var(--schrift-leise); }
.messwert .was { font-size: .74rem; color: var(--schrift-leise); margin-top: .15rem; }

/* Ampel für CO₂ – grün, gelb, rot. Das ist ein Zustand, deshalb ausdrücklich
 * nicht die Hausfarbe. */
.ampel { width: 9px; height: 9px; border-radius: 50%; display: block; }
.ampel.gut { background: var(--gut); }
.ampel.achtung { background: var(--achtung); }
.ampel.schlecht { background: var(--schlecht); }

.modulfuss { margin-top: auto; padding-top: .8rem; font-size: .74rem; color: var(--schrift-leise); }

.verlauf { display: block; width: 100%; height: 30px; margin-top: .6rem; }

/* Anleitung, die dauerhaft auf der Seite steht.
 *
 * Nicht als Hinweis, der nach dem ersten Mal verschwindet: Wer eine Station
 * alle paar Wochen einbindet, weiß es beim zweiten Mal nicht mehr. Also
 * bleibt sie da – ruhig genug, dass sie im Weg nicht stört. */
.anleitung .schritte { padding-left: 1.2rem; margin: .6rem 0 0; }
.anleitung .schritte > li {
  margin-bottom: 1.1rem;
  padding-left: .3rem;
  line-height: 1.55;
}
.anleitung .schritte > li > strong { color: var(--schrift); }
.anleitung .schritte p { margin: .3rem 0 .4rem; }
.anleitung .schritte ol[type="a"] {
  padding-left: 1.1rem;
  margin: .4rem 0 0;
  color: var(--schrift-leise);
  font-size: .88rem;
}
.anleitung .schritte ol[type="a"] li { margin-bottom: .35rem; }
.anleitung .linkfeld { margin-top: .3rem; }

/* Werte, die zur Technik gehören, nicht zum Wetter: die Basisstation im
 * Bauwagen. Eine Zeile statt einer Kachel – da, aber untergeordnet. */
.nebenwerte {
  display: flex;
  align-items: center;
  gap: 1.4rem;
  flex-wrap: wrap;
  padding: .7rem 1rem;
  margin-bottom: 1.25rem;
  border: 1px solid var(--linie-leise);
  border-radius: var(--rund);
  background: var(--karte);
}
.nebenwerte > .klein { display: inline-flex; align-items: center; gap: .4rem; }
.nebenwerte em { font-style: normal; opacity: .7; }
.nebenwert {
  display: inline-flex;
  align-items: baseline;
  gap: .25rem;
  font-variant-numeric: tabular-nums;
}
.nebenwert strong { font-weight: 500; font-size: .95rem; }
.nebenwert small { color: var(--schrift-leise); font-size: .72rem; }
.nebenwert .was { color: var(--schrift-leise); font-size: .78rem; margin-left: .2rem; }
.nebenwert .ampel { margin-right: .1rem; }

.diagrammtafel {
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  padding: 1rem 1.1rem 1.25rem;
  margin-bottom: 1.25rem;
}
.diagrammkopf { display: flex; align-items: center; gap: .75rem; margin-bottom: 1rem; flex-wrap: wrap; }
.diagrammkopf h2 { margin: 0; margin-right: auto; font-size: .95rem; }

.urteile { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 1rem; }
.urteil {
  display: flex;
  gap: .75rem;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-left: 3px solid var(--gut);
  border-radius: 0 var(--rund) var(--rund) 0;
  padding: .85rem 1rem;
}
.urteil.achtung { border-left-color: var(--achtung); }
.urteil.schlecht { border-left-color: var(--schlecht); }
.urteil > .sinnbild { color: var(--schrift-leise); margin-top: .1rem; }
.urteil strong { display: block; font-size: .88rem; margin-bottom: .15rem; }
.urteil p { margin: 0; font-size: .82rem; color: var(--schrift-leise); }

#dbild { display: block; width: 100%; height: auto; }
#dbild .dtitel {
  font: 600 13px var(--titelschrift);
  fill: var(--schrift);
}
#dbild .dachse {
  font: 11px var(--textschrift);
  fill: var(--schrift-leise);
  font-variant-numeric: tabular-nums;
}

.diagrammtafel {
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  padding: 1rem 1.1rem 1.25rem;
  margin-bottom: 1.25rem;
}
.diagrammkopf { display: flex; align-items: center; gap: .75rem; margin-bottom: 1rem; }
.diagrammkopf h2 { margin: 0; margin-right: auto; font-size: .95rem; }
.legende { display: flex; gap: 1rem; flex-wrap: wrap; font-size: .78rem; color: var(--schrift-leise); }
.legende span { display: inline-flex; align-items: center; gap: .35rem; }
.legende i { width: 10px; height: 3px; border-radius: 2px; display: block; }

.urteile { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 1rem; }
.urteil {
  display: flex;
  gap: .75rem;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-left: 3px solid var(--gut);
  border-radius: 0 var(--rund) var(--rund) 0;
  padding: .85rem 1rem;
}
.urteil.achtung { border-left-color: var(--achtung); }
.urteil.schlecht { border-left-color: var(--schlecht); }
.urteil strong { display: block; font-size: .88rem; margin-bottom: .15rem; }
.urteil p { margin: 0; font-size: .82rem; color: var(--schrift-leise); }

/* ----------------------------------------------------------------- Konto */

.karten { display: grid; grid-template-columns: repeat(auto-fit, minmax(21rem, 1fr)); gap: 1.25rem; align-items: start; }
.karte {
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  padding: 1.4rem 1.5rem 1.5rem;
}
.karte > h2 { display: flex; align-items: center; gap: .5rem; }
.karte > h2 .sinnbild { color: var(--gelb); }

dl.angaben { display: grid; grid-template-columns: auto 1fr; gap: .5rem 1.25rem; margin: 0; }
dl.angaben dt { color: var(--schrift-leise); font-size: .84rem; }
dl.angaben dd { margin: 0; font-size: .9rem; }

.freigabeliste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .45rem; }
.freigabeliste li { display: flex; align-items: center; gap: .55rem; font-size: .88rem; }
.freigabeliste .sinnbild { color: var(--gut); }
.freigabeliste li.aus { color: var(--schrift-leise); }
.freigabeliste li.aus .sinnbild { color: var(--linie); }

/* ----------------------------------------------------------------- Admin */

.adminleiste {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}
.adminleiste input[type="search"] { width: 16rem; }

.merkmal {
  display: inline-block;
  background: var(--karte-hell);
  border: 1px solid var(--linie);
  border-radius: 999px;
  padding: .1rem .55rem;
  font-size: .72rem;
  font-weight: 600;
  color: var(--schrift-leise);
  margin: 1px;
}
.merkmal.an { color: var(--gelb-schrift); border-color: rgba(210, 215, 0, .5); }

.gruppe {
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  padding: .8rem 1rem 1rem;
  margin-bottom: 1rem;
}
.gruppe > legend, .gruppe > h3 {
  font-size: .82rem;
  color: var(--schrift-leise);
  font-family: var(--textschrift);
  font-weight: 500;
  padding: 0 .3rem;
  margin: 0 0 .6rem;
}
.wahlreihe { display: flex; flex-wrap: wrap; gap: .5rem 1.25rem; }
.unterwahl {
  margin: .5rem 0 .8rem 1.6rem;
  padding-left: .9rem;
  border-left: 2px solid var(--linie);
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 1.1rem;
}
.schalterliste { display: flex; flex-direction: column; gap: .8rem; }
.schalterliste .zeile { display: flex; align-items: center; gap: .75rem; }
.schalterliste .zeile .beschriftung { margin-right: auto; }
.schalterliste .zeile strong { display: block; font-size: .88rem; font-weight: 600; }
.schalterliste .zeile span { font-size: .78rem; color: var(--schrift-leise); }

.vorschau {
  background: var(--karte-hell);
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  padding: .9rem 1rem;
  font-size: .85rem;
}
.vorschau strong { display: block; margin-bottom: .4rem; font-size: .82rem; color: var(--schrift-leise); font-weight: 500; }

.aktionsleiste {
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-top: 1.5rem;
  padding: .9rem 1.25rem;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  box-shadow: var(--schatten);
}


/* ---------------------------------------------------------------- Kalender
 *
 * Aufbau wie auf livebild.triobild.de: Knopf mit Datum, darunter das
 * Monatsblatt. Hier zusätzlich ein Punkt an jedem Tag, für den Aufnahmen
 * vorliegen – sonst sucht man sich durch leere Tage.
 */

.datumsknopf {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  background: var(--grund-tief);
  border: 1px solid rgba(210, 215, 0, .5);
  color: var(--schrift);
  border-radius: var(--rund);
  padding: .35rem .7rem;
  font: 500 .85rem var(--textschrift);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
:root[data-thema="hell"] .datumsknopf { background: var(--karte-hell); }
.datumsknopf:hover { border-color: var(--gelb); filter: none; }
.datumsknopf .sinnbild { color: var(--schrift-leise); }

.kalender {
  position: absolute;
  top: calc(100% + .4rem);
  right: 0;
  z-index: 40;
  width: 16.5rem;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: var(--rund-gross);
  box-shadow: var(--schatten);
  padding: .7rem;
}
.kalenderkopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .5rem;
}
.kalenderkopf strong { font: 500 .88rem var(--textschrift); }
.kalenderkopf button { font-size: 1.1rem; line-height: 1; padding: .1rem .5rem; }

.kalendergitter {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  justify-items: center;
}
.kalendergitter .wtag {
  font-size: .72rem;
  color: var(--schrift-leise);
  padding-bottom: .3rem;
}
.kalendergitter .tag {
  position: relative;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: var(--rund);
  background: none;
  color: var(--schrift);
  font: .85rem var(--textschrift);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.kalendergitter .tag:hover:not(:disabled) { background: var(--karte-hell); filter: none; }
.kalendergitter .tag.gewaehlt { background: var(--gelb); color: var(--auf-gelb); font-weight: 600; }
.kalendergitter .tag:disabled { color: var(--linie); cursor: default; }
.kalendergitter .tag.fremd { color: var(--linie); font-size: .8rem; }
/* Der Punkt sitzt unter der Zahl, nicht daneben: In einer 2-rem-Zelle ist
 * seitlich kein Platz, ohne dass die Ziffer verrutscht. */
.kalendergitter .tag.voll::after {
  content: "";
  position: absolute;
  bottom: 3px;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--gelb);
}
.kalendergitter .tag.gewaehlt.voll::after { background: var(--auf-gelb); }

.kalenderfuss {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin-top: .6rem;
  padding-top: .5rem;
  border-top: 1px solid var(--linie);
  font-size: .72rem;
  color: var(--schrift-leise);
}
.punkt-voll { width: 4px; height: 4px; border-radius: 50%; background: var(--gelb); }

/* ------------------------------------------------------------------- Fuß */

.seitenfuss {
  border-top: 1px solid var(--linie);
  margin-top: 3rem;
  background: var(--grund-tief);
}
:root[data-thema="hell"] .seitenfuss { background: var(--karte); }
.fusszeile {
  max-width: var(--breite);
  margin: 0 auto;
  padding: 1.25rem 1.5rem 2rem;
  display: flex;
  flex-wrap: wrap;
  gap: .75rem 2rem;
  align-items: flex-start;
  font-size: .8rem;
  color: var(--schrift-leise);
}
.fusszeile .verweise { display: flex; gap: 1.1rem; flex-wrap: wrap; }
.fusszeile .verweise a { color: var(--schrift-leise); text-decoration: underline; }
.fusszeile .verweise a:hover { color: var(--gelb-schrift); }
/* Der Hinweis auf die Verpixelung steht bewusst im Fuß jeder Seite und nicht
 * nur unter dem Bild: Wer Bilder weitergibt, muss die Zusage zur Hand haben. */
.fusszeile .schutz {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  max-width: 44rem;
  margin-left: auto;
}
.fusszeile .schutz .sinnbild { color: var(--gut); margin-top: .1rem; }


/* -------------------------------------------------------------- Vergleich
 *
 * Zwei Aufnahmen liegen deckungsgleich übereinander; der Schieber beschneidet
 * die obere. So wandert nur die Kante, das Motiv bleibt an Ort und Stelle –
 * nebeneinandergestellt müsste das Auge springen und sähe die kleinen
 * Unterschiede nicht.
 */

.vergleich {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: 68vh;
  overflow: hidden;
  cursor: ew-resize;
  touch-action: none;   /* sonst scrollt das Tablet, statt zu schieben */
  user-select: none;
}
.vergleich .lage {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.vergleich .klipp { clip-path: inset(0 calc(100% - var(--schnitt)) 0 0); }

.vergleich .griff {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--schnitt);
  width: 2px;
  margin-left: -1px;
  background: var(--gelb);
  pointer-events: none;
}
.vergleich .griff span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--gelb);
  color: var(--auf-gelb);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .45);
}
.zeitmarke {
  position: absolute;
  top: 10px;
  padding: .15rem .5rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, .6);
  color: #f2f2ee;
  font-size: .74rem;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.zeitmarke.links { left: 10px; }
.zeitmarke.rechts { right: 10px; }

/* --------------------------------------------------- Öffentliche Seite */

body.oeffentlich main {
  max-width: 1400px;
  padding-top: 2rem;
}
.oeffentlichtafel .tafelkopf h1 { font-size: 1rem; }
.oeffentlichtafel .kamerastreifen .kameraknopf { font-size: .76rem; }

/* -------------------------------------------------------------- Personen */

.personenliste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.personenliste li {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .7rem 0;
  border-bottom: 1px solid var(--linie-leise);
}
.personenliste li:last-child { border-bottom: 0; }
.personenliste .wer { margin-right: auto; min-width: 0; }
.personenliste .wer strong { display: block; font-size: .9rem; font-weight: 600; }
.personenliste .wer span { font-size: .78rem; color: var(--schrift-leise); }
.personenliste li.gesperrt { opacity: .5; }
.rollenmarke {
  background: var(--karte-hell);
  border: 1px solid var(--linie);
  border-radius: 999px;
  padding: .1rem .55rem;
  font-size: .7rem;
  font-weight: 600;
  color: var(--schrift-leise);
  white-space: nowrap;
}
.rollenmarke.haupt { color: var(--gelb-schrift); border-color: rgba(210, 215, 0, .5); }

/* ---------------------------------------------------------------- Alarme */

.alarmliste { display: flex; flex-direction: column; gap: 1rem; }
.alarmzeile {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
}
.alarmzeile .beschriftung { margin-right: auto; min-width: 12rem; }
.alarmzeile .beschriftung strong { display: block; font-size: .88rem; }
.alarmzeile .beschriftung span { font-size: .78rem; color: var(--schrift-leise); }
.alarmzeile .grenze {
  display: flex;
  align-items: center;
  gap: .35rem;
  font-size: .82rem;
  color: var(--schrift-leise);
}
.alarmzeile .grenze input { width: 4.5rem; text-align: right; font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------- Öffentlicher Link */

.linkfeld {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: var(--karte-hell);
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  padding: .4rem .5rem .4rem .7rem;
  margin-top: .6rem;
}
.linkfeld code {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .78rem;
  color: var(--gelb-schrift);
}

/* Alter des Bildes. Orange, wenn es deutlich älter ist als der Takt – nicht
 * rot: Es ist kein Fehler, nur ein Hinweis. Regel aus TB BauCam. */
.bildalter { font-style: normal; color: var(--schrift-leise); margin-left: .4rem; }
.bildalter.alt { color: var(--achtung); font-weight: 600; }
.kameraknopf .bildalter { margin-left: 0; font-size: .72rem; }

/* -------------------------------------------------------------- Nachweis
 *
 * Ein Dokument, kein Bildschirm: heller Grund, ruhige Typografie, alles auf
 * eine A4-Seite. Ein Screenshot taugt vor einem Gutachter wenig; ein Blatt mit
 * Herkunft, Zeitpunkt und Prüfsumme schon eher.
 */

body.nachweisseite { background: var(--karte); }
body.nachweisseite main { max-width: 62rem; padding-top: 1.5rem; }

.nachweisleiste {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: 1.25rem;
}

.nachweis {
  background: #fff;
  color: #111308;
  border-radius: var(--rund-gross);
  box-shadow: var(--schatten);
  padding: 2.4rem 2.6rem 2rem;
  max-width: 52rem;
  margin: 0 auto;
}
.nachweis header {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding-bottom: 1rem;
  border-bottom: 2px solid #d2d700;
  margin-bottom: 1.5rem;
}
.nachweis header .marke { display: flex; align-items: baseline; gap: .5rem; margin-right: auto; }
.nachweis header .marke svg { height: 17px; width: auto; color: #22240f; display: block; }
.nachweis header .marke em {
  font-style: normal;
  font-family: var(--titelschrift);
  font-weight: 500;
  letter-spacing: .08em;
  font-size: .9rem;
  color: #66695a;
}
.nachweis header .rechts { text-align: right; }
.nachweis header .rechts strong { display: block; font-family: var(--titelschrift); font-size: 1.05rem; }
.nachweis header .rechts span { font-size: .8rem; color: #66695a; }

.nachweis figure { margin: 0 0 1.5rem; }
.nachweis figure img {
  display: block;
  width: 100%;
  border-radius: 4px;
  background: #000;
}
.nachweis figcaption {
  margin-top: .5rem;
  font-size: .82rem;
  color: #66695a;
  font-variant-numeric: tabular-nums;
}

.nachweis dl.angaben {
  grid-template-columns: 11rem 1fr;
  gap: .5rem 1.5rem;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid #e3e4d8;
  margin-bottom: 1.25rem;
}
.nachweis dl.angaben dt { color: #66695a; font-size: .84rem; }
.nachweis dl.angaben dd { font-size: .9rem; }

.nachweis .vermerk {
  font-size: .82rem;
  line-height: 1.6;
  color: #3a3d2c;
  margin: 0 0 1.75rem;
}
.nachweis footer {
  padding-top: 1rem;
  border-top: 1px solid #e3e4d8;
  font-size: .74rem;
  color: #66695a;
}

@media print {
  body.nachweisseite { background: #fff; }
  body.nachweisseite main { padding: 0; max-width: none; }
  .nachweisleiste, .beispielhinweis, .seitenfuss { display: none !important; }
  .nachweis { box-shadow: none; border-radius: 0; padding: 0; max-width: none; }
  .nachweis figure img { max-height: 12cm; object-fit: contain; }
}

/* Decke über dem Standbild, solange kein Strom läuft. Das Bild bleibt
 * sichtbar – nur so lässt sich beurteilen, wie groß es später steht. */
.startdecke {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: .9rem;
  padding: 2rem;
  text-align: center;
  background: rgba(8, 8, 8, .55);
}
.startdecke p {
  margin: 0;
  max-width: 24rem;
  color: #d8d9d2;
  font-size: .82rem;
}
.grossstart {
  padding: .7rem 1.4rem;
  font-size: .95rem;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
}

/* Wortmarke in der Verwaltung: als Bild eingebunden statt inline, weil die
 * Seiten dort vom Server kommen und kein JavaScript zum Einsetzen brauchen.
 * Der Preis: Sie dreht im hellen Modus nicht mit, deshalb der Filter. */
.marken-logo { height: 15px; width: auto; display: block; }
:root[data-thema="hell"] .marken-logo { filter: brightness(.3) saturate(1.6); }


/* ============================================================== Übersicht
 *
 * Wörtlich übernommen aus TB BauCam Web, damit beides gleich aussieht: ein
 * durchgehender gelber Strich neben allem, was zu einer Baustelle gehört,
 * davor ein weißes Namensschild mit Balken. Der Strich grenzt ab, ohne Flächen
 * einzufärben – getönte Kacheln würden mit den Vorschaubildern streiten.
 *
 * Einzige Änderung: Die waagerecht laufende Kachelreihe heißt hier
 * `.kamerareihe`. `.reihe` ist in TB Web schon die Formularzeile.
 */

/* -------------------------------------------------------------- Übersicht
 *
 * Aufbau wie in der Mac-App: ein durchgehender gelber Strich neben allem, was
 * zu einer Baustelle gehört, davor ein weißes Namensschild mit Balken. Der
 * Strich grenzt ab, ohne Flächen einzufärben – getönte Kacheln würden mit den
 * Vorschaubildern streiten.
 */

.baustelle { display: flex; gap: 14px; align-items: stretch; margin-bottom: 3rem; }
.strich { flex: 0 0 3px; border-radius: 2px; background: rgba(210, 215, 0, .5); }
.gruppe { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1.4rem; }

/* Die Fläche umschließt nur ihren Inhalt. Ein Band über die ganze Breite liefe
 * bei den waagerecht laufenden Reihen weit aus dem Fenster hinaus. */
.namensschild {
  /* `align-self: flex-start` in der Flexspalte darüber: Das Schild bleibt so
   * breit wie sein Inhalt und läuft nicht über die Reihe.
   *
   * Kein `width: fit-content` – das klingt richtiger, fällt hier aber in sich
   * zusammen: Die Kinder sind selbst Flexelemente und schrumpfen dann auf
   * null, übrig bleibt die Polsterung. Einmal ausprobiert, 26 Pixel breit. */
  align-self: flex-start;
  max-width: 100%;
  display: flex;
  align-items: center;
  gap: .65rem;
  background: #fff;
  border-radius: 11px;
  padding: .5rem 1rem .5rem .6rem;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .35);
  max-width: 100%;
}
.namensschild .balken {
  flex: 0 0 4px; height: 24px; border-radius: 2px; background: var(--gelb);
}
/* Auf Weiß ist das Marken-Gelb als Schrift zu hell – der Name steht dunkel,
 * das Gelb übernimmt der Balken davor. */
.namensschild h2 { margin: 0; font-size: 17px; color: var(--tinte); }
.namensschild .anzahl { font-size: .85rem; color: rgba(8, 8, 8, .55); white-space: nowrap; }
.namensschild .archivlink { display: flex; color: rgba(8, 8, 8, .5); }
.namensschild .archivlink:hover { color: #777b00; }

.block { display: flex; flex-direction: column; gap: .7rem; min-width: 0; }
.blockkopf {
  display: flex;
  align-items: center;
  gap: .45rem;
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--gelb);
}
.blockkopf .sinnbild { color: rgba(210, 215, 0, .8); }
.blockkopf em {
  font-style: normal;
  font-family: var(--textschrift);
  font-size: .85rem;
  color: var(--schrift-leise);
}

/* Kanäle eines Rekorders laufen nach rechts weiter, statt umzubrechen – so
 * bleibt zusammen, was zu einem Gerät gehört. */
.kamerareihe {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding-bottom: 10px;
  scrollbar-width: thin;
  scrollbar-color: var(--linie) transparent;
}

/* Feste Bildhöhe, Breite aus dem Seitenverhältnis: alle Kacheln einer Reihe
 * stehen damit auf einer Linie, ohne dass ein Bild verzerrt oder gerahmt wird. */
.kachel {
  --bildhoehe: 170px;
  position: relative;
  flex: 0 0 auto;
  /* Der Rückfallwert ist kein Schmuck: Fehlt die Angabe, wäre `calc()`
   * ungültig und die Kachel fiele auf `min-width` zurück – oder, je nach
   * Umgebung, auf die volle Breite. Genau das ist schon passiert. */
  width: calc(var(--bildhoehe) * var(--verhaeltnis, 1.7778));
  min-width: 15rem;
  background: var(--karte);
  border: 1px solid var(--linie);
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .15);
  transition: box-shadow .15s ease-out, border-color .15s ease-out;
}
.kachel:hover { box-shadow: 0 9px 18px rgba(0, 0, 0, .35); border-color: rgba(210, 215, 0, .6); }

/* Innerhalb einer Kachel ist `.bildflaeche` die **kleine** Fläche mit fester
 * Höhe – draußen ist es die große Bühne der Kameraseite. Beide heißen in
 * TB BauCam so; hier müssen die Kachelregeln deshalb genauer sein, sonst
 * gewinnt die Bühne und die Kachel wird doppelt so hoch. */
.kachel .bildflaeche {
  display: block;
  height: var(--bildhoehe);
  min-height: 0;
  max-height: none;
  background: #000;
}
.kachel .bildflaeche img {
  display: block;
  width: 100%;
  height: 100%;
  max-height: none;
  /* `contain`, nicht `cover`: Die Kachelbreite folgt dem Seitenverhältnis der
   * Kamera (`--verhaeltnis`), deshalb passt das Bild genau hinein. Mit `cover`
   * wäre ein Panorama oben und unten abgeschnitten – und dort steht die
   * Baustelle. */
  object-fit: contain;
}
.bildflaeche.laedt { animation: puls 1.6s ease-in-out infinite; }
@keyframes puls {
  0%, 100% { background-color: #111214; }
  50%      { background-color: #1d1f22; }
}
@media (prefers-reduced-motion: reduce) {
  .bildflaeche.laedt { animation: none; background-color: #17181a; }
}

.neuladen {
  position: absolute;
  top: 6px; right: 6px;
  display: grid; place-items: center;
  width: 26px; height: 26px; padding: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  opacity: 0;
  transition: opacity .15s;
}
.kachel:hover .neuladen, .neuladen:focus-visible { opacity: 1; }

.fuss { display: flex; align-items: flex-start; gap: .5rem; padding: .65rem .75rem; }
.punkt { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; margin-top: .35rem; }
.punkt.gut { background: var(--gut); }
.punkt.schlecht { background: var(--schlecht); }
.punkt.unbekannt { background: rgba(139, 141, 133, .5); }

.namen { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.namen a { color: var(--schrift); font-weight: 600; font-size: .92rem; }
.namen a:hover { color: var(--gelb); text-decoration: none; }
.namen .adresse, .namen .stand {
  font-size: .74rem;
  color: var(--schrift-leise);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Orange, wenn das Bild deutlich älter ist als der Takt – nicht rot: Es ist
 * kein Fehler, nur ein Hinweis, dass gerade nichts Neues ankam. */
.namen .stand.alt { color: #d99a3c; }

.werkzeuge {
  margin-left: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .4rem;
}
.symbole { display: flex; gap: .7rem; color: var(--schrift-leise); }
.symbole a { display: flex; color: inherit; }
.kachel:hover .symbole { color: var(--schrift); }
.symbole a:hover { color: var(--gelb); }

/* Ampel für den Livestream. Grau, solange nichts geprüft wurde – eine rote
 * Anzeige, die nur „noch nicht nachgesehen“ meint, wäre schlimmer als keine. */
.stromampel {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .6px;
  color: rgba(139, 141, 133, .5);
}
.stromampel.gut { color: var(--gut); }
.stromampel.schlecht { color: var(--schlecht); }

.beispielhinweis {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: 2rem;
  padding: .6rem .9rem;
  border: 1px dashed var(--linie);
  border-radius: 6px;
  color: var(--schrift-leise);
  font-size: .82rem;
}
.beispielhinweis strong { color: var(--schrift); }


/* Sortieren mit Pfeilen. Im Namensschild sitzen sie auf Weiß, an der Kachel
 * auf dem Bild – deshalb zwei Fassungen derselben Sache. */
.namensschild .ordnen { display: flex; align-items: center; gap: .15rem; }
.namensschild .ordnen form { margin: 0; }
.namensschild .ordnen button,
.namensschild .ordnen a {
  display: grid;
  place-items: center;
  width: 22px; height: 22px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: rgba(8, 8, 8, .45);
  font-size: .9rem;
  line-height: 1;
  cursor: pointer;
}
.namensschild .ordnen button:hover,
.namensschild .ordnen a:hover {
  background: rgba(8, 8, 8, .08);
  color: var(--tinte);
  filter: none;
  text-decoration: none;
}
.namensschild .ordnen button:disabled { opacity: .25; cursor: default; }
.namensschild .ordnen button.weg:hover { background: rgba(224, 101, 91, .18); color: #a3271c; }

.kachel .schieben {
  position: absolute;
  top: 6px; left: 6px;
  display: flex;
  gap: 2px;
  opacity: 0;
  transition: opacity .15s;
}
.kachel:hover .schieben, .kachel .schieben:focus-within { opacity: 1; }
.kachel .schieben form { margin: 0; }
.kachel .schieben button {
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.kachel .schieben button:hover { background: rgba(0, 0, 0, .8); filter: none; }
.kachel .schieben button:disabled { opacity: .3; cursor: default; }

/* Kachel ohne Passwort: sagt, was fehlt, statt ein Ersatzbild zu zeigen, das
 * man für ein Kamerabild halten könnte. */
.kachel .bildflaeche.kein-bild {
  display: grid;
  place-items: center;
  text-align: center;
  color: var(--schrift-leise);
  background: #111214;
}
.kachel .bildflaeche.kein-bild span {
  display: grid;
  justify-items: center;
  gap: .4rem;
  font-size: .82rem;
}
.kachel .bildflaeche.kein-bild em {
  font-style: normal;
  font-size: .74rem;
  color: var(--achtung);
}

/* Kurzer Überblick unter der Überschrift. Zahlen, die eine Handlung nach sich
 * ziehen, stehen in Orange – die übrigen bleiben ruhig. */
.ueberblick { display: flex; flex-wrap: wrap; gap: .4rem; margin: .5rem 0 0 !important; }
.ueberblick span {
  border: 1px solid var(--linie);
  border-radius: 999px;
  padding: .1rem .6rem;
  font-size: .76rem;
  color: var(--schrift-leise);
}
.ueberblick span.warnt { color: var(--achtung); border-color: rgba(217, 154, 60, .45); }

/* Die eigene Gruppe hebt sich ab – sie steht oben und gehört nicht zu den
 * Kunden. Ein gelber Rand genügt; eine eingefärbte Fläche wäre zu laut. */
.karte.eigene { border-color: rgba(210, 215, 0, .45); }
.karte.eigene > h2 .sinnbild { color: var(--gelb); }

/* Suchzeile bei Downloads.
 *
 * Auswahllisten, Zeitfelder und ein Knopf haben von Haus aus verschiedene
 * Höhen – nebeneinander sieht das nach Zufall aus. Deshalb hier eine feste
 * Höhe für alles, was in der Zeile steht, und eine gemeinsame Grundlinie. */
.suchzeile {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .9rem;
}
/* Vorher wuchs das erste Feld (Kamera) ins Unendliche, während Tag, Von und
 * Bis schmal danebenstanden – das sah aus wie ein Versehen. Jetzt wächst nur
 * das Kamerafeld, und auch das nur bis zu einem vernünftigen Maß. */
.suchzeile .feld { flex: 0 1 auto; margin: 0; }
.suchzeile .feld:first-child { flex: 1 1 16rem; max-width: 26rem; }
.suchzeile select,
.suchzeile input,
.suchzeile button,
.suchzeile .knopf {
  height: 2.6rem;
  box-sizing: border-box;
  width: 100%;
}
.suchzeile button { justify-content: center; }
.suchzeile .datumsknopf { justify-content: flex-start; }

/* Gefundene Aufzeichnungen: Vorschaubild, Angaben, Ladeknopf. */
.listenkopf {
  display: flex;
  align-items: center;
  gap: .9rem;
  flex-wrap: wrap;
  margin: 0 0 1rem;
}
.listenkopf button { margin-left: auto; }

.dateiliste { display: flex; flex-direction: column; gap: .6rem; }
.dateikachel {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: .6rem;
  border: 1px solid var(--linie);
  border-radius: var(--rund);
  background: var(--karte);
}
.dateikachel img {
  width: 8rem;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: calc(var(--rund) - 2px);
  background: #000;
  flex: 0 0 auto;
  display: block;
}
.dateiangaben { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.dateikachel > .knopf { margin-left: auto; flex: 0 0 auto; }

@media (max-width: 640px) {
  .dateikachel { flex-wrap: wrap; }
  .dateikachel > .knopf { margin-left: 0; width: 100%; }
}

/* Vorschaurahmen im Kameraformular.
 *
 * Keine feste Höhe: Die Kameras liefern 16:9, 4:3 und – bei den
 * Doppelsensor-Geräten – 32:9. Jede feste Höhe passt für höchstens eine davon
 * und schneidet den Rest ab oder lässt Balken stehen. Die Breite ist bekannt,
 * die Höhe ergibt sich aus dem Bild. */
.vorschaurahmen {
  background: #000;
  line-height: 0;          /* sonst steht unter dem Bild ein Zeilenrest */
  min-height: 4rem;
}
.vorschaurahmen img { width: 100%; height: auto; display: block; }

/* ---------------------------------------------------------------- Tablet */

@media (max-width: 1100px) {
  .buehne { grid-template-columns: minmax(0, 1fr); }
  .spalte { max-height: 26rem; }
  .bildraster { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 900px) {
  .kopfzeile { flex-wrap: wrap; gap: .6rem .9rem; padding: .6rem 1rem; }
  .module { order: 3; width: 100%; margin-right: 0; }
  .kopfwerkzeuge { margin-left: auto; }
  main { padding: 1.25rem 1rem 3rem; }
  .tafelkopf .wortmarke { display: none; }
  .bildraster { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 640px) {
  .bildraster { grid-template-columns: 1fr; }
  .ortknopf { max-width: 10rem; }
}

@media print {
  .kopf, .tafelfuss, .aktionsleiste { display: none; }
}

/* ------------------------------------------------------------------ Export
 *
 * Faltet sich unter dem Verlauf auf. Bewusst kein eigenes Fenster: Der
 * Zeitraum gehoert sichtbar neben das Diagramm, dessen Ausschnitt er meint. */
.exportfeld {
  margin: -.4rem 0 1.1rem;
  padding: .95rem 1.05rem;
  background: var(--karte-hell);
  border: 1px solid var(--linie);
  border-radius: var(--rund);
}
.exportzeile { display: flex; gap: .8rem; align-items: flex-end; flex-wrap: wrap; }
.exportzeile .feld { margin: 0; flex: 0 1 11rem; }
.exportzeile .feld input { width: 100%; }
.exportschnell {
  display: flex; gap: .4rem; align-items: center;
  flex-wrap: wrap; margin-top: .75rem;
}
.exportschnell .knopf { padding: .25rem .6rem; font-size: .78rem; }
#exportauf.an { background: var(--karte-hell); color: var(--schrift); }

/* -------------------------------------------------------------- Blaettern
 *
 * Sitzt zwischen Kopfzeile und Diagramm: Der Zeitraum gehoert dorthin, wo
 * das Auge ohnehin hinwandert, bevor es die Kurve liest. */
.zeitblaetter {
  display: flex; align-items: center; justify-content: center;
  gap: .5rem; margin: 0 0 .9rem;
}
.zeitblaetter strong {
  min-width: 13rem; text-align: center;
  font-size: .85rem; font-weight: 500;
}
.zeitblaetter .knopf { padding: .3rem .55rem; line-height: 1; }
.zeitblaetter .knopf[disabled] { opacity: .3; pointer-events: none; }

/* ----------------------------------------------------------- Adressbuch
 *
 * Über hundert Einträge: Die Liste muss sich auf einen Blick überfliegen
 * lassen, deshalb je Zeile nur Name, Anschrift und Nummern. Die vollen
 * Felder klappen erst beim Anklicken auf. */
.kontaktkarte { padding: .85rem 1.1rem; margin-bottom: .5rem; }
.kontaktkarte > summary {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1.6fr) auto auto auto;
  gap: .9rem; align-items: baseline;
  cursor: pointer; list-style: none;
}
.kontaktkarte > summary::-webkit-details-marker { display: none; }
.kontaktkarte > summary::before {
  content: "›"; position: absolute; margin-left: -.85rem;
  color: var(--schrift-leise); transition: transform .12s ease;
}
.kontaktkarte[open] > summary::before { transform: rotate(90deg); }
.kontaktkarte .kfirma { font-weight: 500; }
.kontaktkarte .kort,
.kontaktkarte .knummern { color: var(--schrift-leise); font-size: .85rem; }
.kontaktkarte[data-still] > summary { opacity: .55; }
.kontaktkarte:hover { border-color: var(--linie-hell, var(--gelb)); }

.kontaktgitter {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .7rem .9rem;
}
.kontaktgitter .feld { margin: 0; }

@media (max-width: 800px) {
  .kontaktkarte > summary { grid-template-columns: 1fr; gap: .2rem; }
}
.auftraggeber {
  display: flex; align-items: center; gap: .5rem;
  margin: .4rem 0 0; flex-wrap: wrap;
}
.auftraggeber select {
  width: auto; max-width: 26rem;
  padding: .25rem .5rem; font-size: .82rem;
}
