/* Die Gestaltungssprache des Hauses.
   ==================================

   Vorbild ist das cube-Frontend (git@git.rz.anduro.de:cubeEvaluation/cube.git). Dort ist die
   Sprache in docs/docs/cubeEvaluation/frontend/dark-elevation-color-system.md beschrieben, hier
   steht die Kurzfassung, damit niemand dafuer in ein fremdes Repository schauen muss.

   Das offene Projekt dahinter ist Radix Themes (radix-ui.com/themes). Radix selbst ist React und
   laesst sich hier nicht einbinden, uebernommen wird deshalb die Bildsprache und nicht der Code.
   Zwei Gedanken tragen alles:

   1. Durchscheinende Flaechen. Eine Karte ist eine halbdurchsichtige Auflage ueber einem sanften
      Farbverlauf, dazu eine Weichzeichnung des Hintergrundes. Die Seite scheint durch, die Karte
      entsteht durch ihre Kante und nicht durch eine eigene Fuellfarbe.
   2. Hoehe entsteht aus Ring und Schatten, nicht aus einem Rahmen. Statt eines harten 1px-Randes
      traegt eine Karte einen haarfeinen durchscheinenden Ring und einen weichen Schlagschatten.

   Inhalt bleibt flach. Gruppen werden durch getrennte Karten, Kopfbaender und Trennlinien
   auseinandergehalten, nie durch Kaesten in Kaesten. Eingabefelder sind gerahmte durchscheinende
   Felder und keine schwarzen Loecher.

   Grundlage ist Bootstrap 5.3 in der Fassung, die unter static/vendor liegt. Alles hier setzt nur
   Farbmarken und einige wenige Regeln darauf. Kein zweites Rahmenwerk, keine Bauteilbibliothek. */

/* --- Schriften der Eventvorlagen ------------------------------------------------------------
   Zwoelf Schriften, jede als Datei unter static/fonts. Geholt wird vom Portal selbst und nicht
   von einem fremden Server, die Regel aus OBERFLAECHE.md bleibt unangetastet.

   **Auch die vier gewoehnlichen sind dabei**, und das ist der Punkt: der Server hat kein Arial
   und kein Georgia, im Container liegt ueberhaupt keine Schrift. Solange der Browser Arial nahm
   und Pillow raten musste, konnten Vorschau und Ausdruck gar nicht dasselbe zeigen. Jetzt steht
   in jeder Kette die mitgelieferte Familie vorn, beide Seiten lesen dieselbe Datei.

   Die Quelle dieser Liste ist bestand.SCHRIFTEN. Wer dort eine Schrift ergaenzt, ergaenzt sie
   hier mit, test_vorlagen_editor.py prueft, dass beide Seiten dieselben Dateien nennen.

   `font-display: block` und kein `swap`: eine Vorlage wird nach dem Augenmass gesetzt, und ein
   kurzer Umbruch von der Ersatzschrift auf die echte waehrend des Ziehens verschiebt genau das,
   worauf man gerade zielt. Lieber einen Wimpernschlag nichts sehen. */

@font-face {
  font-family: "Arimo";
  src: url("fonts/Arimo-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "LatoFett";
  src: url("fonts/Lato-Bold.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Tinos";
  src: url("fonts/Tinos-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Cousine";
  src: url("fonts/Cousine-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Allura";
  src: url("fonts/Allura-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "ChunkFive";
  src: url("fonts/ChunkFive-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Kaushan Script";
  src: url("fonts/KaushanScript-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Caveat";
  src: url("fonts/Caveat-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Caveat Brush";
  src: url("fonts/CaveatBrush-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Architects Daughter";
  src: url("fonts/ArchitectsDaughter-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Shadows Into Light";
  src: url("fonts/ShadowsIntoLight-Regular.ttf") format("truetype");
  font-display: block;
}
@font-face {
  font-family: "Sacramento";
  src: url("fonts/Sacramento-Regular.ttf") format("truetype");
  font-display: block;
}

/* --- Farbmarken -------------------------------------------------------------------------- */

:root,
[data-bs-theme="dark"] {
  --bs-body-bg: #1a1a1c;
  --bs-card-bg: #262c34;
  --bs-border-color: rgba(255, 255, 255, 0.09);

  /* Bootstraps gedaempftes Grau liegt auf dunklem Grund bei rund 2,8 zu 1 und damit unter der
     Lesbarkeitsschwelle von 4,5 zu 1. Beide Marken werden angehoben. */
  --bs-secondary-color: #adb5bd;
  --bs-tertiary-color: #969ca3;

  --cube-surface: rgba(255, 255, 255, 0.032);
  --cube-surface-2: rgba(255, 255, 255, 0.05);
  --cube-surface-3: rgba(255, 255, 255, 0.08);
  --cube-field: rgba(0, 0, 0, 0.22);
  --cube-ring: rgba(255, 255, 255, 0.09);
  --cube-ring-soft: rgba(255, 255, 255, 0.05);
  --cube-header-bg: rgba(255, 255, 255, 0.025);
  --cube-blur: blur(20px);
  --cube-shadow-card:
    0 0 0 1px var(--cube-ring),
    0 1px 2px rgba(0, 0, 0, 0.45),
    0 6px 18px -8px rgba(0, 0, 0, 0.6);

  /* Das Kupfer aus dem Logo. Es ist die Farbe der Marke und wird nie zu einem Zustand, sonst
     stuende neben Gruen, Gelb, Rot und Blau eine fuenfte Farbe, die etwas zu bedeuten scheint.
     Gesetzt wird es im Logo selbst, am Streifen der geoeffneten Box in der Seitenleiste und am
     Knopf der Anmeldeseite, siehe .btn-marke. Die Ausnahme steht weiter unten beim Standband. */
  --marke-kupfer: #c08c62;

  /* Radix Indigo als Akzent. */
  --bs-primary: #3e63dd;
  --bs-primary-rgb: 62, 99, 221;
  --bs-link-color: #93a8fb;
  --bs-link-color-rgb: 147, 168, 251;
  --bs-link-hover-color: #b3c2fd;

  /* --- Die vier Toene und wofuer sie stehen ---------------------------------------------------

     Ein Ton besteht aus drei Werten und nie aus einem: eine durchscheinende Flaeche, ein Ring in
     derselben Farbe und eine Schrift, die darauf lesbar ist. Genau so baut Radix seine weichen
     Marken, und genau daran hing die Uneinheitlichkeit vorher. Bootstrap kennt nur die volle
     Farbe, also stand neben einer durchscheinenden Karte eine giftgruene Pille.

     Die Schriftwerte sind Stufe 11 der Radix-Palette im dunklen Modus. Sie sind dafuer gemacht,
     auf der zugehoerigen Flaeche zu liegen, und halten dort die 4,5 zu 1.

     Was welcher Ton sagt, ist festgelegt und wird nicht je Seite neu entschieden:
     gruen  laeuft, verbunden, erkannt
     gelb   eingerichtet werden muesste etwas, es laeuft aber weiter
     rot    hier faellt gerade etwas aus
     blau   der Akzent, eine Auswahl oder ein Verweis
     grau   eine Angabe ohne Wertung, etwa eine Anzahl

     **Und ein vierter Wert, aber nur beim Gruen.** Der Dreiklang gilt fuer Marken, also fuer
     etwas, das neben einem Text steht und ihn einordnet. Es gibt daneben Flaechen, die selbst die
     Aussage sind und keinen Text tragen: das Segment eines Verfuegbarkeitsbalkens, der Punkt einer
     Leuchte. Die brauchen die volle Farbe, denn ein Balken aus sechzehn Prozent Deckung ist auf
     dem dunklen Grund kein Balken mehr.

     Beide standen bis zum 05.09.2026 mit einem eigenen Wert da: die Leuchte mit #30a46c von Hand,
     der Balken mit Bootstraps --bs-success, also #198754. Der Balken war damit stumpfer als jedes
     gruene Zeichen daneben. Jetzt ziehen beide aus derselben Zeile.

     Die uebrigen Toene bekommen einen solchen Wert erst, wenn sie eine solche Flaeche haben.
     Rot hat seit dem 13.09.2026 eine, siehe weiter unten. */
  --ton-gruen-voll: #30a46c;
  --ton-gruen-flaeche: rgba(48, 164, 108, 0.16);
  --ton-gruen-rand: rgba(48, 164, 108, 0.34);
  --ton-gruen-schrift: #3dd68c;

  --ton-gelb-flaeche: rgba(255, 197, 61, 0.15);
  --ton-gelb-rand: rgba(255, 197, 61, 0.32);
  --ton-gelb-schrift: #ffca16;
  /* Der vierte Wert beim Gelb, aus demselben Grund wie der beim Gruen: ein Rahmen ist selbst die
     Aussage und traegt keinen Text. Bei 32 Prozent Deckung verschwindet er neben dem Ring, den
     jede Karte ohnehin hat. Gesetzt wird er an einer Stelle, siehe .karte-warnung. */
  --ton-gelb-rahmen: rgba(255, 197, 61, 0.55);

  --ton-rot-flaeche: rgba(229, 72, 77, 0.17);
  --ton-rot-rand: rgba(229, 72, 77, 0.36);
  --ton-rot-schrift: #ff9592;
  /* Der volle Ton, aus demselben Grund wie der beim Gruen: seit dem 13.09.2026 gibt es eine
     Flaeche, die ihn traegt, naemlich den Gesamtbalken eines fehlgeschlagenen Vorgangs. */
  --ton-rot-voll: #e5484d;

  --ton-blau-flaeche: rgba(62, 99, 221, 0.2);
  --ton-blau-rand: rgba(62, 99, 221, 0.4);
  --ton-blau-schrift: #9eb1ff;

  --ton-grau-flaeche: rgba(255, 255, 255, 0.06);
  --ton-grau-rand: rgba(255, 255, 255, 0.11);
  --ton-grau-schrift: #b0b4ba;

  /* Bootstraps Rosa fuer <code> stammt aus einem hellen Entwurf und ist die einzige Farbe im
     Portal, die in keiner Palette steht. Gesetzt wird es an einer Stelle: dem Passwort einer
     Cloudfreigabe, und das soll auffallen, weil es abgeschrieben wird. */
  --bs-code-color: #9eb1ff;
}

/* --- Grundflaeche ------------------------------------------------------------------------ */

/* `hidden` schlaegt jede Anzeigeklasse.

   Die Regel des Browsers zu `[hidden]` ist schwach, und `.d-flex` von Bootstrap traegt ein
   `!important`. Ein Element mit beidem stand deshalb sichtbar da, obwohl es verborgen sein
   sollte. Am 09.09.2026 gefunden am Knopfpaar Speichern und Verwerfen im Eventformular: es
   sollte erst auftauchen, sobald jemand etwas geaendert hat, und stand von Anfang an da. */
[hidden] {
  display: none !important;
}

body {
  background: linear-gradient(168deg, #313135 0%, #202023 46%, #141416 100%);
  background-attachment: fixed;
  min-height: 100vh;
}

body,
input,
select,
textarea,
button,
.card,
.form-control {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans",
    "Helvetica Neue", Arial, sans-serif;
}

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

.card {
  background-color: var(--cube-surface);
  -webkit-backdrop-filter: var(--cube-blur);
  backdrop-filter: var(--cube-blur);
  border: 0;
  border-radius: 14px;
  box-shadow: var(--cube-shadow-card);
}

/* Kopfband einer Karte: links der Name, rechts die Marke oder der eine Knopf, der dazugehoert.
   Es bricht um, statt den Knopf zusammenzuquetschen. Auf 320 Bildpunkten stand "Zur Kenntnis
   genommen" sonst zweizeilig neben einem einzeiligen Titel, und beide waren zu schmal. */
.card > .card-header {
  background: var(--cube-header-bg);
  border-bottom: 0;
  box-shadow: inset 0 -1px 0 var(--cube-ring);
  padding: 11px 16px;
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  font-weight: 600;
}

.card > .card-header:first-child {
  border-top-left-radius: 14px;
  border-top-right-radius: 14px;
}

/* --- Die vier Dateikarten im Reiter Bilder -----------------------------------------------------

   Am 14.09.2026 beanstandet: "die tabs mit bildern, papierkorb und hochladen haben nicht die
   gleiche hoehe der titelleiste. das muss korrekt sein."

   Fotos und Originale tragen den Ansichtsschalter, der Papierkorb einen Verweis und einen Haken,
   das Hochladen nur seinen Namen. Solange die Leiste umbrechen darf, haengt ihre Hoehe daran, was
   zufaellig darin steht und wie breit die Karte gerade ist. Beim Umschalten zwischen den Reitern
   springt dann die ganze Seite.

   Sie bricht deshalb nicht um. Der Name bleibt ganz, und was daneben Platz braucht, ohne
   gebraucht zu werden, faellt bei schmaler Karte heraus: das ist `kopfnebensache`.

   **Gemessen wird die Karte und nicht das Fenster.** Die Karte steht in einer Spalte neben der
   Seitenleiste, und wie breit sie ist, weiss das Fenster nicht. Dasselbe gilt fuer die Tabellen
   darin, siehe `stapeltabelle` weiter unten. */
.dateikarte {
  container-type: inline-size;
}

.card > .card-header.dateileiste {
  flex-wrap: nowrap;
}

.card > .card-header.dateileiste > :first-child {
  flex: none;
  white-space: nowrap;
}

.card > .card-header.dateileiste > :last-child {
  min-width: 0;
  flex-wrap: nowrap;
}

/* **Der Ansichtsschalter fuegt sich in die Leiste ein, statt sie zu dehnen.** Ein Knopf mit den
   Vorgaben von Bootstrap ist 31 Bildpunkte hoch, das Kopfband bietet zwischen seinen Polstern 26.
   Damit standen Fotos und Originale auf 53 und der Papierkorb und das Hochladen auf 48.

   Am 14.09.2026 beanstandet: "fotos und orginale sind hoeher als papierkorb und upload." Nicht zu
   messen war es an einem Entwurf, der die Karte nachbaut: dort trug der Knopf eine andere
   Zeilenhoehe. Gefunden hat es erst ein Abzug der wirklichen Seite. */
.card > .card-header.dateileiste .btn-group-sm > .btn {
  padding-top: 2px;
  padding-bottom: 2px;
  line-height: 1.25;
}

@container (max-width: 560px) {
  .card > .card-header.dateileiste .kopfnebensache {
    display: none;
  }
}

/* **Eine Tabelle wird zur Karte, statt zu wandern.** Am 14.09.2026 verlangt: "die tabelle mobil
   und bei schmaleren ansichten nicht nutzbar. horizontales scrolling muss verhindert werden."

   Es ist derselbe Schnitt wie bei `table-stapelbar` weiter unten, nur an der Breite der Karte
   statt an der des Fensters gemessen. Beides nebeneinander ist kein Versehen: `table-stapelbar`
   gilt fuer Tabellen, die die ganze Seitenbreite haben, `stapeltabelle` fuer die, die in einer
   Karte stehen, deren Breite das Fenster nicht kennt. */
@container (max-width: 620px) {
  .dateikarte .table-responsive {
    overflow-x: visible;
  }

  .dateikarte .stapeltabelle > thead {
    display: none;
  }

  .dateikarte .stapeltabelle > tbody > tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.75rem;
    padding: 0.7rem 0.75rem;
    box-shadow: inset 0 -1px 0 var(--cube-ring-soft);
  }

  .dateikarte .stapeltabelle > tbody > tr:last-child {
    box-shadow: none;
  }

  .dateikarte .stapeltabelle > tbody > tr > td {
    display: block;
    width: auto;
    max-width: none;
    border: 0;
    padding: 0;
  }

  /* Der Dateiname bekommt eine eigene Zeile. Abgeschnitten waere er wertlos: er ist das, wonach
     jemand sucht. */
  .dateikarte .stapeltabelle > tbody > tr > td[data-breit] {
    flex: 1 1 100%;
  }

  /* Die Knoepfe stehen rechts in der Zeile mit den Zahlen und nicht in einer eigenen. Eine
     vierte Zeile je Datei macht aus hundert Bildern eine sehr lange Seite. */
  .dateikarte .stapeltabelle > tbody > tr > td[data-knoepfe] {
    margin-left: auto;
    text-align: right;
  }
}

/* Ein buendiger Rumpf mit einer Tabelle darin muss auf die runde Unterkante beschnitten werden,
   sonst deckt der eckige Hintergrund der Tabelle die Ecken ab und die Rundung sieht kaputt aus.
 *
 * **overflow: hidden gehoert hier nicht hin.** Es stand bis zum 29.08.2026 in dieser Regel und
 * hat auf schmalen Bildschirmen Spalten verschluckt: `.card > .table-responsive:last-child` wiegt
 * schwerer als Bootstraps `.table-responsive`, das overflow-x: auto setzt. Auf einem Telefon von
 * 375 Bildpunkten lagen damit 400 Bildpunkte der Statistiktabelle hinter der Kante, unerreichbar,
 * ohne Balken und ohne Wischen. Die Tabelle sah aus, als endete sie dort.
 *
 * Die Rundung braucht kein Beschneiden. `border-radius` allein beschneidet den Hintergrund der
 * Tabelle bereits, weil er hinter dieser Kante liegt. */
.card > .card-body.p-0:last-child,
.card > .table-responsive:last-child {
  border-bottom-left-radius: 14px;
  border-bottom-right-radius: 14px;
}

.card > .card-body.p-0:last-child {
  overflow: hidden;
}

/* Eine Tabelle, die breiter ist als ihre Karte, wird gewischt. Damit das jemand merkt, liegt an
   der Kante ein Schatten, und zwar nur an der Seite, an der noch etwas kommt.
 *
 * Der Schatten steckt im Hintergrund und nicht in einem Pseudoelement. `background-attachment:
 * scroll` heisst bei einem scrollenden Element: die Flaeche klebt an dessen Kante und wandert
 * nicht mit dem Inhalt. Genau das ist hier gesucht, und es braucht dafuer weder eine zusaetzliche
 * Ebene noch position: sticky in einem Element, dessen einziges Kind eine Tabelle ist.
 *
 * Welche Seite leuchtet, setzt das Skript in base.html an data-wischbar. Ohne Skript bleibt das
 * Wischen selbst erhalten, es fehlt nur der Hinweis darauf. */
.table-responsive {
  scrollbar-width: thin;
  background-repeat: no-repeat;
  background-attachment: scroll;
  background-size: 22px 100%;
}

.table-responsive[data-wischbar="rechts"] {
  background-image: linear-gradient(270deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  background-position: right center;
}

.table-responsive[data-wischbar="links"] {
  background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  background-position: left center;
}

.table-responsive[data-wischbar="beide"] {
  background-image:
    linear-gradient(90deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)),
    linear-gradient(270deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  background-position: left center, right center;
}

/* Eine abgesetzte Flaeche innerhalb einer Karte. Genau eine Stufe, nie geschachtelt. */
.abgesetzt {
  background-color: var(--cube-surface-2);
  border: 0;
  border-radius: 10px;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

/* --- Tabellen ---------------------------------------------------------------------------- */

.card .table > thead > tr > th,
.card .table-responsive > .table > thead > tr > th {
  background: var(--cube-header-bg);
  color: var(--bs-secondary-color);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
  border-top: 0;
  border-bottom: 0;
  box-shadow: inset 0 -1px 0 var(--cube-ring);
  padding: 8px 12px;
  white-space: nowrap;
}

.card .table {
  --bs-table-border-color: var(--cube-ring-soft);
  --bs-table-bg: transparent;
}

.card .table > tbody > tr > td {
  font-size: 0.875rem;
  padding-top: 12px;
  padding-bottom: 12px;
  vertical-align: middle;
}

/* Der Inhalt einer Tabelle steht links auf derselben Linie wie die Ueberschrift ihrer Karte.

   Eine Tabelle liegt in der Karte neben dem Rumpf und nicht darin, sie reicht also bis an den
   Rand. Ohne eigene Angabe nimmt eine Zelle das Mass von Bootstrap, bei `.table-sm` sind das
   vier Bildpunkte, und dann klebt die erste Spalte am Rand. Am 09.09.2026 beanstandet: "der
   tabelleninhalt links kein abstand". Gemessen an der Karte Druckauftraege: Kartenrand bei 290,
   Ueberschrift bei 306, Kopfzeile bei 302, Zelle bei 294. Drei Linien in einer Karte.

   Sechzehn Bildpunkte aussen, das ist das Polster der Kartenueberschrift, und zwoelf zwischen
   den Spalten. Fuer schmale Bildschirme steht weiter unten ein eigenes, engeres Mass. */
.card .table > thead > tr > th,
.card .table > tbody > tr > td {
  padding-left: 12px;
  padding-right: 12px;
}

.card .table > thead > tr > th:first-child,
.card .table > tbody > tr > td:first-child {
  padding-left: 16px;
}

.card .table > thead > tr > th:last-child,
.card .table > tbody > tr > td:last-child {
  padding-right: 16px;
}

/* Eine Spalte, in der eine Zahl steht. Rechtsbuendig und mit gleich breiten Ziffern: nur so
   stehen Einer unter Einern, und die Spalte laesst sich von oben nach unten vergleichen.

   Am 15.09.2026 fuer den Kalender gebraucht, verlangt: "splate 'gefahren' soll umbenant werden zu
   'Bilder' und nur bilder zeigen. dazu eine spalte drucke die nur die druckanzahl zeigt." */
.zahlenspalte {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Ein Verweis in einer Tabelle traegt den Akzent und keinen Unterstrich. Bootstrap unterstreicht
   jeden Verweis, und in einer Spalte mit dreissig Eventnamen untereinander wird daraus ein
   Streifenmuster. Der Unterstrich kommt beim Ueberfahren, dort ist er die Auskunft, dass es sich
   um einen Verweis handelt. */
.card .table a {
  text-decoration: none;
}

.card .table a:hover,
.card .table a:focus-visible {
  text-decoration: underline;
}

/* --- Eingaben ---------------------------------------------------------------------------- */

.form-control,
.form-select {
  background-color: var(--cube-field);
  border-color: var(--cube-ring);
}

.form-control:focus,
.form-select:focus {
  background-color: var(--cube-field);
  border-color: var(--bs-primary);
  box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.25);
}

/* **Die aufgeklappte Liste braucht einen eigenen, deckenden Grund.** Am 15.09.2026 beanstandet:
   "dropdowns haben weisse schrift und hellgruen hintergrund da stimmt was nicht."

   Der Grund ist `--cube-field`, also `rgba(0, 0, 0, 0.22)`. Im Feld selbst liegt das auf der
   dunklen Karte und ergibt die gewuenschte Vertiefung. Die aufgeklappte Liste zeichnet das
   Betriebssystem, und dort liegt dieselbe Farbe auf hellem Grund: aus 22 Prozent Schwarz wird ein
   helles Grau, darauf die weisse Schrift aus dem dunklen Thema, und die hervorgehobene Zeile
   traegt die Akzentfarbe des Systems. Lesbar ist davon nichts.

   Deckende Werte an `option` und `optgroup` loesen es, und zwar in jedem Browser, der die Liste
   selbst zeichnet. Genommen wird der Grund der Karte, denn dort steht das Feld. */
.form-select option,
.form-select optgroup {
  background-color: var(--bs-card-bg);
  color: var(--bs-body-color);
}

.form-check-input:checked {
  background-color: var(--bs-primary);
  border-color: var(--bs-primary);
}

/* Eine Reihe aus Feldern, deren Eingaben auf einer Linie stehen.

   Bis zum 09.09.2026 stand an diesen Reihen `align-items-end` von Bootstrap. Das legt die
   unteren Raender der Spalten auf eine Linie. Steht unter einem Feld ein Hinweis, ist seine
   Spalte um dessen Zeile hoeher, und das Feld daneben rutscht genau um diese Zeile nach unten.
   Am selben Tag beanstandet: "eingabefelder verschoben (Blatt)". Neun Reihen auf vier Seiten
   waren betroffen, der Versatz lag bei 21 bis 25 Bildpunkten.

   Ausgerichtet wird deshalb oben. Jede Spalte beginnt mit ihrer Beschriftung, die Beschriftung
   ist ueberall gleich hoch, und damit stehen die Felder auf einer Linie. Der Hinweis haengt
   darunter und darf so lang sein, wie er will.

   Eine eigene Klasse und nicht die Bootstrap-Klasse mit anderer Wirkung: `align-items-end`
   heisst, was es heisst, und wer es liest, soll sich darauf verlassen koennen. */
.feldreihe {
  align-items: flex-start;
}

/* Eine Spalte, in der statt eines Feldes ein Knopf steht. Ueber ihm fehlt die Beschriftung,
   also bekommt er ihre Hoehe als Abstand: 24 Bildpunkte Zeile und 8 Bildpunkte Abstand
   darunter, zusammen 2rem. Nur an einem Knopf, der die Zeile mit Feldern teilt. Ein Knopf in
   einer eigenen Zeile darunter traegt sie nicht. */
.feldreihe > .feldreihe-knopf {
  margin-top: 2rem;
}

/* --- Marken ---------------------------------------------------------------------------------

   Eine Marke ist eine weiche Pille und keine Signalfarbe. Bootstrap liefert `text-bg-success` und
   Verwandte als volle Flaeche mit weisser Schrift, und daneben steht in diesem Portal eine Karte,
   die durchscheint. Das passte nicht zusammen: eine Box, die einfach nur laeuft, trug eine
   Leuchtpille, waehrend die Karte darunter fast unsichtbar war.

   Uebersetzt wird an dieser einen Stelle und nicht in vierzig Vorlagen. Die Klassen bleiben, wie
   sie sind, nur ihr Aussehen wechselt. Wer eine neue Marke setzt, schreibt weiter
   `badge text-bg-success` und bekommt die Hausform.

   Die Auswahl ist absichtlich klein. Fuenf Toene reichen fuer alles, was dieses Portal zu sagen
   hat, und mehr Toene heissen nur, dass niemand mehr weiss, was welcher bedeutet. */

.badge {
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.01em;
  border-radius: 6px;
  padding: 0.3em 0.6em;
}

/* Das !important ist hier keine Nachlaessigkeit. Bootstrap setzt `text-bg-*` selbst mit
   !important, und ohne dieselbe Stufe bliebe die volle Farbe stehen, egal wie genau der Selektor
   ist. Genau daran ist der erste Anlauf am 29.08.2026 gescheitert. */
.badge.text-bg-success {
  color: var(--ton-gruen-schrift) !important;
  background-color: var(--ton-gruen-flaeche) !important;
  box-shadow: inset 0 0 0 1px var(--ton-gruen-rand);
}

.badge.text-bg-warning {
  color: var(--ton-gelb-schrift) !important;
  background-color: var(--ton-gelb-flaeche) !important;
  box-shadow: inset 0 0 0 1px var(--ton-gelb-rand);
}

.badge.text-bg-danger {
  color: var(--ton-rot-schrift) !important;
  background-color: var(--ton-rot-flaeche) !important;
  box-shadow: inset 0 0 0 1px var(--ton-rot-rand);
}

.badge.text-bg-primary {
  color: var(--ton-blau-schrift) !important;
  background-color: var(--ton-blau-flaeche) !important;
  box-shadow: inset 0 0 0 1px var(--ton-blau-rand);
}

.badge.text-bg-secondary,
.badge.text-bg-light,
.badge.text-bg-dark {
  color: var(--ton-grau-schrift) !important;
  background-color: var(--ton-grau-flaeche) !important;
  box-shadow: inset 0 0 0 1px var(--ton-grau-rand);
}

/* Dieselben Toene fuer die Hinweiskaesten. Ein Hinweis ist eine breite Marke und soll nicht
   anders aussehen als eine schmale. */
.alert-success {
  --bs-alert-color: var(--ton-gruen-schrift);
  --bs-alert-bg: var(--ton-gruen-flaeche);
  --bs-alert-border-color: var(--ton-gruen-rand);
  box-shadow: inset 0 0 0 1px var(--ton-gruen-rand);
}

.alert-warning {
  --bs-alert-color: var(--ton-gelb-schrift);
  --bs-alert-bg: var(--ton-gelb-flaeche);
  --bs-alert-border-color: var(--ton-gelb-rand);
  box-shadow: inset 0 0 0 1px var(--ton-gelb-rand);
}

.alert-danger {
  --bs-alert-color: var(--ton-rot-schrift);
  --bs-alert-bg: var(--ton-rot-flaeche);
  --bs-alert-border-color: var(--ton-rot-rand);
  box-shadow: inset 0 0 0 1px var(--ton-rot-rand);
}

/* Eine Karte, an deren Gegenstand etwas fehlt: gelber Rahmen, Rumpf wie immer.
 *
 * Am 09.09.2026 verlangt: "wenn der drucker nicht verbunden ist soll der gesamte block eingefärbt
 * werden wie der banner." Die erste Fassung faerbte die ganze Flaeche gelb. Am selben Tag am
 * Entwurf entschieden: "gelber rahmen. innen normal grau." Eine durchgehend gelbe Karte liest sich
 * wie ein Alarm, und ein fehlendes Kabel ist keiner. Der Rahmen sagt dasselbe und laesst den
 * Inhalt in Ruhe.
 *
 * Zwei Bildpunkte und nicht einer: bei einem verschwindet der Rahmen neben dem Ring, den jede
 * Karte ohnehin traegt. */
.card.karte-warnung {
  box-shadow: inset 0 0 0 2px var(--ton-gelb-rahmen);
}

/* Der Schleier ueber dem Rumpf und das Zeichen darauf.
 *
 * Am 09.09.2026 am Entwurf entschieden: der Rumpf wird abgedunkelt, darauf steht das Zeichen in
 * Gelb, "aber der letzte wert muss sichtbar bleiben".
 *
 * Deshalb liegt der Schleier hinter allem und nicht ueber allem: er ist das erste Kind und
 * absolut gesetzt, jedes weitere Kind steht relativ und damit darueber. Der Papierstand bleibt so
 * ungetruebt lesbar, und das ist die eine Zahl, die auch ohne Kabel gilt. Wie viele Blatt in der
 * Kassette liegen, aendert sich nicht dadurch, dass jemand am USB zieht. */
.fehlrumpf {
  position: relative;
}

.fehlschleier {
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 12, 0.62);
}

.fehlrumpf > *:not(.fehlschleier) {
  position: relative;
}

.fehlmeldung {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 6px 0 16px;
  color: var(--ton-gelb-schrift);
}

.fehlmeldung i {
  font-size: 56px;
  line-height: 1;
}

.fehlmeldung span {
  font-weight: 600;
}

.alert-secondary,
.alert-info {
  --bs-alert-color: var(--bs-body-color);
  --bs-alert-bg: var(--cube-surface-2);
  --bs-alert-border-color: var(--cube-ring);
}

/* Den Ton tragen das Symbol und die Ueberschrift, nicht der ganze Kasten. Vier Zeilen durchgehend
   in Bernstein lesen sich wie ein Alarm, und eine Box, die gerade nichts sendet, ist keiner. */
.alert .small {
  color: var(--bs-secondary-color);
}

/* Farbige Schrift ohne Flaeche, etwa die Meldung einer Box im Stoerungskasten. Bootstraps
   Vollwerte sind auf hellem Grund gerechnet und liegen auf diesem hier zu dunkel. */
.text-success { color: var(--ton-gruen-schrift) !important; }
.text-warning { color: var(--ton-gelb-schrift) !important; }
.text-danger { color: var(--ton-rot-schrift) !important; }

/* --- Schaltflaechen ---------------------------------------------------------------------- */

.btn {
  background-image: none;
  text-shadow: none;
  box-shadow: none;
  border-radius: 8px;
}

.btn-primary {
  --bs-btn-bg: #3e63dd;
  --bs-btn-border-color: #3e63dd;
  --bs-btn-hover-bg: #3656c4;
  --bs-btn-hover-border-color: #3656c4;
  --bs-btn-active-bg: #2f4aa8;
  --bs-btn-active-border-color: #2f4aa8;
  --bs-btn-disabled-bg: #3e63dd;
  --bs-btn-disabled-border-color: #3e63dd;
}

/* Der Knopf in der Farbe der Marke. Am 20.09.2026 verlangt: "färbe mal den anmeldebutton des
   portal in prtalfarbe."
 *
 * Das Kupfer aus dem Logo, und damit die dritte Stelle, an der es steht: im Logo, am Streifen der
 * geoeffneten Box in der Seitenleiste, und hier. Die Anmeldeseite ist die Seite der Marke, dort
 * sagt die Farbe nichts ueber einen Zustand und bricht die Regel oben bei --marke-kupfer nicht.
 *
 * **Dunkle Schrift darauf.** Weiss auf diesem Ton kommt auf knapp 3:1 und ist zu wenig, dieselbe
 * Rechnung wie beim laufenden Feld des Standbandes. */
.btn-marke {
  --bs-btn-bg: var(--marke-kupfer);
  --bs-btn-border-color: var(--marke-kupfer);
  --bs-btn-color: #1a1a1c;
  --bs-btn-hover-bg: #cd9d76;
  --bs-btn-hover-border-color: #cd9d76;
  --bs-btn-hover-color: #1a1a1c;
  --bs-btn-active-bg: #b37d53;
  --bs-btn-active-border-color: #b37d53;
  --bs-btn-active-color: #1a1a1c;
  --bs-btn-disabled-bg: var(--marke-kupfer);
  --bs-btn-disabled-border-color: var(--marke-kupfer);
  --bs-btn-disabled-color: #1a1a1c;
  /* Der Ring beim Tastaturfokus traegt dieselbe Farbe. Ohne diese Angabe bliebe er im Indigo von
     Bootstrap stehen, und das ist neben Kupfer die fuenfte Farbe auf einer Seite, die zwei
     kennt. */
  --bs-btn-focus-shadow-rgb: 192, 140, 98;
}

/* Weiche neutrale Schaltflaeche nach Radix-Art statt eines Umrisses. */
.btn-secondary,
.btn-outline-secondary {
  --bs-btn-bg: rgba(255, 255, 255, 0.05);
  --bs-btn-border-color: transparent;
  --bs-btn-color: #ced4da;
  --bs-btn-hover-bg: rgba(255, 255, 255, 0.09);
  --bs-btn-hover-border-color: transparent;
  --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: rgba(255, 255, 255, 0.12);
  --bs-btn-active-border-color: transparent;
}

/* Radix kennt drei Staerken und dieses Portal deshalb auch: voll fuer die eine Haupthandlung
   einer Karte, weich fuer alles Uebrige, weich und farbig fuer das, was einen Ton braucht.
 *
 * Am 29.08.2026 standen in der Steuerungskarte drei Formen nebeneinander: zwei volle Indigoknoepfe,
 * ein blau umrandeter und ein grauer. Ein Umriss ist in dieser Sprache nicht vorgesehen, er kommt
 * aus Bootstrap und sieht neben einer durchscheinenden Karte aus wie ein Fremdkoerper. Die
 * Umrissklassen behalten ihren Namen und tragen ab hier die weiche Form. */
.btn-outline-primary {
  --bs-btn-bg: var(--ton-blau-flaeche);
  --bs-btn-border-color: var(--ton-blau-rand);
  --bs-btn-color: var(--ton-blau-schrift);
  --bs-btn-hover-bg: rgba(62, 99, 221, 0.3);
  --bs-btn-hover-border-color: var(--ton-blau-rand);
  --bs-btn-hover-color: #d3ddff;
  --bs-btn-active-bg: rgba(62, 99, 221, 0.38);
  --bs-btn-active-border-color: var(--ton-blau-rand);
  --bs-btn-active-color: #d3ddff;
}

.btn-outline-danger {
  --bs-btn-bg: var(--ton-rot-flaeche);
  --bs-btn-border-color: var(--ton-rot-rand);
  --bs-btn-color: var(--ton-rot-schrift);
  --bs-btn-hover-bg: rgba(229, 72, 77, 0.28);
  --bs-btn-hover-border-color: var(--ton-rot-rand);
  --bs-btn-hover-color: #ffd1cf;
  --bs-btn-active-bg: rgba(229, 72, 77, 0.36);
  --bs-btn-active-border-color: var(--ton-rot-rand);
  --bs-btn-active-color: #ffd1cf;
}

.btn-outline-warning {
  --bs-btn-bg: var(--ton-gelb-flaeche);
  --bs-btn-border-color: var(--ton-gelb-rand);
  --bs-btn-color: var(--ton-gelb-schrift);
  --bs-btn-hover-bg: rgba(255, 197, 61, 0.26);
  --bs-btn-hover-border-color: var(--ton-gelb-rand);
  --bs-btn-hover-color: #ffe7a0;
  --bs-btn-active-bg: rgba(255, 197, 61, 0.34);
  --bs-btn-active-border-color: var(--ton-gelb-rand);
  --bs-btn-active-color: #ffe7a0;
}

/* Rot bleibt voll, wo wirklich etwas verschwindet. Ein Loeschknopf soll sich von einem weichen
   Knopf daneben unterscheiden lassen, ohne dass man die Beschriftung liest. */
.btn-danger {
  --bs-btn-bg: #e5484d;
  --bs-btn-border-color: #e5484d;
  --bs-btn-hover-bg: #cf3d42;
  --bs-btn-hover-border-color: #cf3d42;
  --bs-btn-active-bg: #b93337;
  --bs-btn-active-border-color: #b93337;
}

/* --- Reiter ------------------------------------------------------------------------------ */

.nav-tabs {
  border-bottom: 0;
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 3px;
  background: var(--cube-surface-2);
  border-radius: 10px;
}

.nav-tabs .nav-item {
  margin: 0;
}

.nav-tabs .nav-link {
  border: 0;
  border-radius: 7px;
  color: var(--bs-secondary-color);
  padding: 6px 14px;
  font-weight: 500;
  margin: 0;
}

.nav-tabs .nav-link:hover {
  color: var(--bs-body-color);
  background: var(--cube-surface);
  border-color: transparent;
}

.nav-tabs .nav-link.active {
  background: var(--cube-surface-3);
  color: var(--bs-body-color);
  box-shadow: inset 0 0 0 1px var(--cube-ring), 0 1px 2px rgba(0, 0, 0, 0.3);
}

/* --- Listen ------------------------------------------------------------------------------ */

.list-group {
  border-radius: 14px;
  overflow: hidden;
  box-shadow: var(--cube-shadow-card);
}

.list-group-item {
  background-color: var(--cube-surface);
  -webkit-backdrop-filter: var(--cube-blur);
  backdrop-filter: var(--cube-blur);
  border: 0;
  box-shadow: inset 0 -1px 0 var(--cube-ring-soft);
}

.list-group-item-action:hover,
.list-group-item-action:focus {
  background-color: var(--cube-surface-3);
  color: var(--bs-body-color);
}

/* --- Hinweise und Kopfleiste ------------------------------------------------------------- */

.alert {
  border: 0;
  border-radius: 10px;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.breadcrumb {
  --bs-breadcrumb-divider-color: var(--bs-tertiary-color);
  font-size: 0.875rem;
}

.tooltip-inner {
  background-color: #26262a;
  color: #e7eaee;
  border-radius: 7px;
  padding: 6px 10px;
  font-size: 0.8rem;
  text-align: left;
  white-space: pre-line;
  max-width: 320px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
}

/* --- Eigene Bauteile ---------------------------------------------------------------------
   Alles ab hier gibt es in Bootstrap nicht und laesst sich auch nicht aus vorhandenen Klassen
   zusammensetzen. */

/* --- Die Boxauswahl ---------------------------------------------------------------------------

   Eine Box zum Oeffnen auswaehlen, als Liste oder als Kacheln. Am 19.09.2026 verlangt:
   "ueberarbeite die fotoboxen ansicht und gleiche sie der event ansicht an."

   Die Liste steht seitdem in einer `list-group` wie die Eventliste und traegt Bild, Namen und
   Zustand, sonst nichts: "rechts nichts hin. merh infos als online soll auch nicht rein. das ist
   zu massiv cluttered." Weg sind damit die rechte Spalte mit Modus und Eventnamen, die Zahlen zu
   Fotos, Drucken und Ortung, das Netzzeichen und die Marken fuer Stoerung, fehlende Kamera und
   Testmodus. Alles Weitere steht auf der Seite der Box, und dorthin fuehrt die Zeile.

   Hier standen bis zum 20.09.2026 die Regeln zu `.auswahlzeile`, ein eigener Zeilenbau, den es
   nur auf dieser Seite gab, samt `.auswahlkopf` fuer die vier Zahlen. Die Zahlen stehen jetzt in
   `.seitenkopf-lage` unter der Ueberschrift, wie die Beiwerte jeder anderen Seite.

   Die bunte Fassung steht weiter unten unter `.boxenliste` und ist aufgehoben, ihre Vorlage liegt
   in templates/uebersicht/_liste_bunt.html. Sie erwartet den alten Zeilenbau und laesst sich
   nicht mehr durch einen Zeileneinsatz in dashboard.html zurueckholen.

   Der Entwurf liegt in mockups/fotoboxenliste.html. */

/* --- Der Zustand als Linie an der Kante -------------------------------------------------------

   Am 19.09.2026 verlangt: "online soll die kachel/ zeile farblich hervorheben bzw ausgrauen", am
   20.09.2026 genauer: "es sollte eher eine linie mit leichtem auslauf haben an der seite. in der
   kachel von unten nach oben. bei der liste links", und dazu "3px linie. feste breite auslauf.
   sollte aber in der staerke des verlaufs noch einstellbar sein."

   Die Kante traegt die Farbe, und der Ton dahinter laeuft aus. Drei Bildpunkte Linie und 5 rem
   Auslauf, in der Zeile wie in der Kachel dasselbe Mass. Eine Tiefe in Prozent war beides nicht:
   18 Prozent der Zeilenbreite sind auf einem breiten Schirm 200 Bildpunkte und auf einem Telefon
   60, und 18 Prozent der Kachelhoehe sind wieder etwas anderes.

   Die Deckung des Tons an der Linie steht bei 6 Prozent, am 20.09.2026 aus dem Regler des
   Entwurfs heraus gewaehlt. Damit steht die Linie fast allein da, und der Verlauf hinter ihr ist
   nur noch zu ahnen.

   Gruen heisst, die Box meldet sich. Grau heisst, sie schweigt. Einen dritten Ton gibt es nicht:
   eine Stoerung traegt die Leuchte, und einen zweiten Farbverlauf dafuer hatte die bunte Fassung
   schon und hat ihn am 29.08.2026 wieder verloren. */
.boxeintrag-online,
.boxkachel-online {
  --zustandlinie: var(--ton-gruen-voll);
  --zustandston: rgba(48, 164, 108, 0.06);
}

/* Offline ist grau und nicht rot. Eine Box, die nachts aus ist, hat keine Stoerung.
   Weiss traegt bei gleicher Deckung weiter als Gruen, der Ton nimmt deshalb knapp ein Drittel. */
.boxeintrag-offline,
.boxkachel-offline {
  --zustandlinie: rgba(255, 255, 255, 0.3);
  --zustandston: rgba(255, 255, 255, 0.02);
}

/* Ausgegraut heisst mehr als eine graue Linie. Eine graue Linie allein waere neben einer gruenen
   zu wenig Unterschied, und das Geraet ist ja gerade nicht da. */
.boxeintrag-offline .boxlistenbild img,
.boxkachel-offline .boxkachel-bild img {
  opacity: 0.45;
  filter: grayscale(1);
}

.boxeintrag-offline .boxeintrag-name,
.boxkachel-offline .boxkachel-name {
  color: var(--bs-secondary-color);
}

/* `overflow: hidden` haelt Linie und Auslauf in der Rundung. Die erste und die letzte Zeile einer
   `list-group` sind oben und unten abgerundet, eine Kachel rundherum. */
.boxeintrag,
.boxkachel {
  position: relative;
  overflow: hidden;
}

/* Der Inhalt liegt ueber dem Auslauf. Ein gestelltes ::before malt sonst ueber den Text, der
   selbst nicht gestellt ist. */
.boxeintrag > span,
.boxkachel > * {
  position: relative;
}

/* Die Zeile: Linie an der linken Kante, der Ton laeuft nach rechts aus. */
.boxeintrag::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 5rem;
  border-left: 3px solid var(--zustandlinie);
  background: linear-gradient(90deg, var(--zustandston), transparent);
  pointer-events: none;
}

/* Die Kachel: Linie an der unteren Kante, der Ton laeuft nach oben aus. Dort steht der Zustand
   ohnehin, und ein Streifen an der linken Kante saehe in einer fast quadratischen Flaeche aus wie
   ein Fehler. */
.boxkachel::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 5rem;
  border-bottom: 3px solid var(--zustandlinie);
  background: linear-gradient(0deg, var(--zustandston), transparent);
  pointer-events: none;
}

/* --- Die Zeile -------------------------------------------------------------------------------

   Das Bild der Box an der linken Kante, so gross wie das Eventbild in der Eventliste, aber
   quadratisch und mit `contain`: ein freigestelltes Geraet wird gezeigt und nicht beschnitten.

   Die Meldeleuchte sitzt in seiner unteren Ecke und steht nicht daneben. Nebeneinander waere die
   Zeile um eine Leuchtenbreite laenger, und das Bild sagt ohnehin, um welches Geraet es geht,
   waehrend die Leuchte sagt, wie es ihm geht. */
.boxlistenbild {
  position: relative;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.boxlistenbild img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Ohne Bild dieselbe Flaeche mit einem grauen Zeichen. Sonst begaenne der Name der einen Zeile
   weiter links als der der naechsten. */
.boxlistenbild.leer {
  border-radius: 0.5rem;
  background: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  color: var(--bs-tertiary-color);
}

/* Der Ring um die Leuchte traegt die Farbe des Grundes. Ohne ihn verschwimmt sie auf einem hellen
   Geraetebild. */
.boxlistenbild .leuchte {
  position: absolute;
  right: -2px;
  bottom: -2px;
  box-shadow: 0 0 0 2px var(--bs-body-bg);
}

/* Der Textblock nimmt den freien Platz und misst sich nicht an seinem Inhalt. `flex-grow-1` von
   Bootstrap laesst die Grundbreite bei `auto`, und damit rutschte der Block auf einem Telefon
   unter das Bild, sobald der Name lang wurde. */
.boxeintrag > span > .boxeintrag-text {
  flex: 1 1 0;
  min-width: 0;
}

/* Die Kennung steht hinter dem Namen und nur dann, wenn die Box einen eigenen Namen traegt. */
.boxeintrag .kennung,
.boxkachel .kennung {
  font-weight: 400;
  font-size: 0.8125rem;
  color: var(--bs-tertiary-color);
  margin-left: 0.4rem;
}

/* Wort und Dauer sind eine Angabe, "Online seit 3 h 12 min", siehe dashboard.zustandsangabe. */
.boxeintrag-wort,
.boxkachel-wort {
  font-weight: 600;
}

.boxeintrag-online .boxeintrag-wort,
.boxkachel-online .boxkachel-wort { color: var(--ton-gruen-schrift); }
.boxeintrag-offline .boxeintrag-wort,
.boxkachel-offline .boxkachel-wort { color: var(--bs-tertiary-color); }

/* --- Die Kachel ------------------------------------------------------------------------------

   Am 19.09.2026 verlangt: "ich wil auch eine weitere ansicht in kachelfrom die das bild geross
   anzeigt." Dieselben Angaben wie in der Zeile, nur andersherum gewichtet: dort traegt der Name
   und das Bild ist ein Zeichen daneben, hier traegt das Bild und der Name steht darunter.

   Umgeschaltet wird im Seitenkopf, mit derselben Knopfgruppe wie im Reiter Bilder einer Box. Die
   Wahl merkt sich der Browser unter einem eigenen Schluessel, siehe static/js/bilderansicht.js:
   wie jemand Bilder ansieht und wie er Geraete ansieht, sind zwei Fragen. */
.boxkachel {
  display: block;
  height: 100%;
  padding: 0.75rem;
  border-radius: var(--bs-border-radius-lg);
  background: var(--cube-surface);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  color: var(--bs-body-color);
  text-decoration: none;
}

.boxkachel:hover,
.boxkachel:focus-visible {
  background: var(--cube-surface-2);
  color: var(--bs-body-color);
}

/* Das Bild bekommt die Flaeche. Quadratisch, weil eine Saeule hoch und ein Doppelaufbau breit
   ist: nur ein Quadrat traegt beide ohne Beschnitt. `contain` und ein eigener, dunklerer Grund,
   damit ein freigestelltes PNG nicht auf der Kachelfarbe schwimmt. */
.boxkachel-bild {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  border-radius: var(--bs-border-radius);
  background: rgba(0, 0, 0, 0.22);
  margin-bottom: 0.6rem;
  overflow: hidden;
}

.boxkachel-bild img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  padding: 0.5rem;
}

.boxkachel-bild.leer {
  color: var(--bs-tertiary-color);
  font-size: 2rem;
}

.boxkachel-name {
  display: block;
  font-weight: 600;
  margin-bottom: 0.1rem;
}

/* Die Leuchte steht in der Kachel neben dem Wort und nicht im Bild. Im Bild saesse sie an einer
   Ecke, die je nach Geraet leer oder voll ist, und wanderte damit von Kachel zu Kachel auf einen
   anderen Grund.
 *
 * `baseline` und nicht `center`: auf einem Telefon bricht die Zeile um, und mittig ausgerichtet
 * stuende die Leuchte dann zwischen den beiden Zeilen. */
.boxkachel-lage {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-size: 0.875rem;
  color: var(--bs-secondary-color);
}

/* --- Die Boxenliste, bunte Fassung -----------------------------------------------------------

   **Nicht mehr eingebunden**, siehe oben. Die Regeln bleiben stehen, damit ein Zeileneinsatz in
   dashboard.html genuegt, um zurueckzuschalten.


   Eine Zeile je Box, in zwei Haelften: links die Box, rechts ihr Event. Getrennt durch einen
   Verlauf ueber 45 Grad und nicht durch einen Strich.

   Der Zustand steckt im Verlauf an der linken Kante. Bis zum 28.08.2026 stand dort ein farbiger
   Punkt und rechts zwei Marken, also drei Zustaende an zwei Orten. Das Wort steht jetzt links
   daneben, denn eine Farbe allein ist keine Auskunft: Grau und Gruen unterscheiden sich fuer
   manche Augen nicht, und ein Punkt sagt ohnehin nicht, was er bedeutet. */

/* Die Zeilen stehen einzeln und nicht aneinandergeklebt. Bootstrap baut eine Liste als einen
   Block mit Trennlinien, hier traegt jede Box ihre eigene Karte. Zwei Verlaeufe je Zeile, der
   Zustand links und das Event rechts, laufen sonst ohne Pause in den der naechsten Zeile.
   Am 28.08.2026 beanstandet. */
.boxenliste {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  /* Rundung und Schatten wandern von der Liste auf die einzelne Zeile. Blieben sie hier, zoege
     der Schatten eine Kante um die Zwischenraeume mit. */
  border-radius: 0;
  overflow: visible;
  box-shadow: none;
}

.boxzeile {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1rem;
  /* Gleiche Hoehe fuer jede Zeile. Eine Box ohne Event traegt zwei Zeilen weniger, und eine Liste,
     in der die Zeilen springen, liest sich unruhig. */
  min-height: 6.5rem;
  overflow: hidden;
}

/* Die Trennlinie der Liste faellt weg, jede Zeile bekommt Rundung und Schatten. Die Rundung
   schneidet dabei beide Verlaeufe mit ab, dafuer sorgt overflow: hidden oben. */
.boxenliste > .boxzeile {
  border-radius: 14px;
  box-shadow: var(--cube-shadow-card);
}

/* Die linke Flaeche: der Verbindungszustand, gruen oder grau, und sonst nichts.
 *
 * Sie laeuft ueber 135 Grad aus und nicht mehr waagerecht. Am 29.08.2026 verlangt: "der verlauf
 * soll in 45 grad uhrzeigersinn auslaufen." Von den vorherigen 90 Grad im Uhrzeigersinn um 45
 * gedreht sind das 135, und damit steht die auslaufende Kante parallel zu der des Events rechts
 * und zu der des Stoerungsbandes dazwischen.
 *
 * Etwas breiter als vorher: eine Diagonale ueber 35 Prozent Breite und 6,5 rem Hoehe waere so
 * steil, dass sie wie eine Kante aussieht statt wie ein Verlauf. */
.boxzeile::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 42%;
  background: linear-gradient(135deg, var(--zustandston), transparent 72%);
  /* Dieselbe Geometrie wie beim Event rechts, nur spiegelverkehrt: die obere rechte Ecke liegt
     bei 50 Prozent des Verlaufs und traegt damit noch Farbe, obwohl er dort auslaufen soll. Die
     Maske blendet die rechte Kante waagerecht aus. */
  -webkit-mask-image: linear-gradient(90deg, #000 55%, transparent);
  mask-image: linear-gradient(90deg, #000 55%, transparent);
  pointer-events: none;
}

.boxzeile-online {
  --zustandston: rgba(48, 164, 108, 0.28);
}

/* Offline ist grau und nicht rot. Eine Box, die nachts aus ist, hat keine Stoerung. */
.boxzeile-offline {
  --zustandston: rgba(255, 255, 255, 0.07);
}

/* Einen zweiten Farbton fuer die Stoerung gibt es nicht mehr. Am 29.08.2026 verworfen: "lass den
 * orangenen verlauf weg." Die Zahl der offenen Vorfaelle steht als Marke unter dem Boxnamen, und
 * eine Box, die wirklich haengt, faellt ohnehin ueber den Verbindungszustand auf. */

.boxzeile-box {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
}

.boxzeile-wort {
  font-weight: 600;
}

/* Die Angaben einer Zeile nebeneinander, mit Trennpunkt dazwischen. Ohne ihn steht dort eine
   Reihe ohne Gliederung, mit einem festen Zeichen im Text braeche sie an der falschen Stelle um. */
.boxzeile-lage {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.5rem;
  min-width: 0;
}

/* Der Trennpunkt haengt am vorigen Wort und steht nicht vor dem naechsten.
 *
 * Vorher stand er als ::before am folgenden Glied, und auf einem Telefon brach die Reihe genau
 * dort um. Die neue Zeile fing dann mit einem einzelnen Punkt an und sah aus wie ein Tippfehler.
 * Am Ende der vorigen Zeile faellt derselbe Punkt kaum auf. Am 29.08.2026 bei der Durchsicht auf
 * 375 Bildpunkten gefunden.
 *
 * Eine Marke bekommt keinen, und vor einer steht auch keiner. Sie traegt ihre eigene Kante, ein
 * Punkt davor waere ein zweiter Trenner an derselben Stelle.
 *
 * Zwei Regeln und nicht eine. Ein Browser ohne :has() verwirft den ganzen Selektor, in dem es
 * steht. Getrennt faellt dort nur die zweite Regel weg, und die Reihe hat weiterhin Trennpunkte,
 * einen davon an einer Stelle zu viel. Zusammengefasst haette sie gar keine mehr. */
.boxzeile-lage > *:not(:last-child):not(.badge)::after,
/* **Die Leuchte bekommt keinen Trennpunkt.** Am 11.09.2026 beanstandet: "neben dem roten
   zustandlicht ist ein punkt, der muss weg."

   Er war keiner, der irgendwo im Text stand: die Regel haengt einen Punkt an jedes Kind der Reihe,
   und die Leuchte ist eines. Gerendert stand dort "● · Online · vor 7 s". Ein Trennzeichen
   zwischen einem Zeichen und dem Wort, das es erklaert, trennt nichts. */
.seitenkopf-lage > *:not(:last-child):not(.badge):not(.leuchte)::after {
  content: "·";
  margin-left: 0.5rem;
  color: var(--bs-tertiary-color);
}

/* Dieselben drei Bedingungen noch einmal. Ohne sie waere diese Regel schwaecher als die obige und
   bliebe wirkungslos: :has() zaehlt so viel wie sein Inhalt, hier eine einzige Klasse. */
.boxzeile-lage > *:not(:last-child):not(.badge):has(+ .badge)::after,
.seitenkopf-lage > *:not(:last-child):not(.badge):has(+ .badge)::after {
  content: none;
}

/* Kein Punkt hinter dem letzten Eintrag, der zu sehen ist. Am 18.10.2026 in der Fotobox UI
   gesehen: "Online seit 1 h 2 min ·". Dahinter standen nur verborgene Felder, etwa "noch nie
   gemeldet", und :last-child zaehlt die mit. */
.boxzeile-lage > *:not(:last-child):not(.badge):not(:has(~ :not([hidden])))::after,
.seitenkopf-lage > *:not(:last-child):not(.badge):not(:has(~ :not([hidden])))::after {
  content: none;
}

/* Die rechte Haelfte. Sie traegt seit dem 28.08.2026 eine eigene Farbe, Indigo nach Violett aus
   der Radix-Palette, und nicht mehr dasselbe Grau wie jede andere Flaeche. Der Zustand links ist
   gruen, gelb oder grau, das Event blau. Damit sagt schon die Farbe, welche Haelfte man ansieht.

   Der Verlauf blendet ueber 135 Grad ein und endet nicht an einer Kante, sondern verliert sich
   schraeg im Grund der Zeile. Dieselbe Neigung wie die Flaeche links und das Stoerungsband in der
   Mitte. Am 29.08.2026 verlangt: "und der eventverlauf auch in 45 grad einblenden."

   Vorher standen hier 45 Grad, also die Gegendiagonale. Die beiden Kanten liefen damit
   aufeinander zu, und die Zeile sah in der Mitte aus wie ein Trichter. Parallel gelesen ist sie
   ruhiger.

   Das negative margin holt die Flaeche bis an den Rand der Zeile heran, die Polsterung der Liste
   bleibt als Innenabstand erhalten. */
.boxzeile-event {
  position: relative;
  flex: 0 0 auto;
  width: 46%;
  max-width: 26rem;
  min-width: 0;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.15rem;
  margin: -1rem -1rem -1rem 0;
  /* Links mehr Polsterung als rechts. Der Text beginnt erst dort, wo der Verlauf traegt, sonst
     stuende er im durchsichtigen Teil und sae aus wie ein Ausrutscher. */
  padding: 1rem 1rem 1rem 3.5rem;
}

/* Der Verlauf steckt seit dem 29.08.2026 in einem eigenen Element und nicht mehr im Hintergrund
   der Flaeche. Der Grund ist die Maske darunter: sie wuerde sonst den Text mit ausblenden.
 *
 * **Warum ueberhaupt eine Maske.** Beanstandet: "der event verlauf ist links am anfang noch
 * abgeschnitten." Genau so war es, und es lag nicht am Winkel, sondern an der Geometrie einer
 * Diagonale. Bei 135 Grad liegt die Startecke oben links, die Endecke unten rechts, und **beide
 * anderen Ecken liegen bei 50 Prozent**. Die untere linke Ecke traegt damit die halbe Farbe,
 * obwohl der Verlauf dort erst anfangen soll. Die Elementkante schneidet ihn dort hart ab.
 *
 * Am Winkel laesst sich das nicht beheben, jede Diagonale trifft eine Ecke. Ein groesserer
 * durchsichtiger Anteil auch nicht: er muesste bis 50 Prozent reichen und liesse nur noch ein
 * Dreieck uebrig. Die Maske blendet stattdessen die linke Kante ueber ein Viertel der Breite
 * waagerecht aus, unabhaengig vom Winkel. Der 45-Grad-Charakter bleibt, die Kante ist weg. */
.boxzeile-event::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Die Deckung bleibt unter 40 Prozent. Darueber faellt der gedaempfte Text der zweiten Zeile
     unter das Lesbarkeitsmass von 4,5 zu 1, gemessen gegen #adb5bd auf dem Grund der Zeile. */
  background: linear-gradient(135deg,
                              rgba(110, 86, 207, 0) 8%,
                              rgba(110, 86, 207, 0.22) 52%,
                              rgba(62, 99, 221, 0.38) 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 26%);
  mask-image: linear-gradient(90deg, transparent 0, #000 26%);
  pointer-events: none;
}

/* Der Text liegt ueber dem Verlauf. Ohne das deckte das Pseudoelement ihn ab, es ist das letzte
   Kind und steht damit in derselben Ebene weiter oben. */
.boxzeile-event > * {
  position: relative;
}

/* Auf einem schmalen Bildschirm stehen die beiden Haelften untereinander. Ein 45-Grad-Verlauf
   ueber eine Zeile von 320 Bildpunkten Breite waere ein Strich, kein Verlauf. */
@media (max-width: 767.98px) {
  .boxzeile {
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .boxzeile-event {
    /* Die zwei Zentimeter sind die Polsterung der Zeile links und rechts. Mit width: 100% waere
       die Flaeche nur so breit wie der Inhalt und endete vor der rechten Kante. */
    width: calc(100% + 2rem);
    max-width: none;
    margin: 0 -1rem -1rem;
    padding: 0.6rem 1rem;
  }

  /* Untereinander laeuft der Verlauf fast senkrecht und nicht ueber die Diagonale. Die Maske
     faellt weg: sie blendet eine linke Kante aus, die es hier nicht gibt, denn die Flaeche
     beginnt am Rand der Zeile und nicht neben einer zweiten Haelfte. */
  .boxzeile-event::before {
    background: linear-gradient(160deg,
                                rgba(110, 86, 207, 0.05),
                                rgba(62, 99, 221, 0.3) 70%);
    -webkit-mask-image: none;
    mask-image: none;
  }
}

/* --- Es laedt ---------------------------------------------------------------------------------

   Rueckmeldung auf einen Klick, der die Seite wechselt. Am 28.08.2026 beanstandet: zwischen dem
   Klick und der neuen Seite passierte nichts, und wer nichts sieht, klickt ein zweites Mal.

   Zwei Anzeigen, ein Schalter. Der Balken am oberen Rand faellt aus dem Augenwinkel auf, auch
   wenn der Blick unten in der Liste liegt. Der Spinner daneben sagt, was er bedeutet. */

.ladeleiste {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 2000;
  overflow: hidden;
  background: var(--cube-ring-soft);
  pointer-events: none;
}

.ladeleiste-balken {
  height: 100%;
  width: 30%;
  background: linear-gradient(90deg, transparent, var(--bs-primary), transparent);
  animation: ladeleiste-lauf 1.1s linear infinite;
}

@keyframes ladeleiste-lauf {
  from { transform: translateX(-100%); }
  to { transform: translateX(430%); }
}

.ladezeichen {
  position: fixed;
  top: 0.9rem;
  right: 0.9rem;
  z-index: 2001;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  font-size: 0.875rem;
  background-color: var(--bs-card-bg);
  box-shadow: var(--cube-shadow-card);
  pointer-events: none;
}

/* Bootstrap setzt [hidden] auf display: none !important. Die Regel steht hier trotzdem: ohne sie
   haengt die Anzeige an einer fremden Datei, und display: flex wuerde sie sonst wieder sichtbar
   machen. */
.ladeleiste[hidden],
.ladezeichen[hidden] {
  display: none;
}

/* Der Zeiger sagt dasselbe noch einmal, dort wo die Maus gerade steht. */
body.laedt,
body.laedt a,
body.laedt button {
  cursor: progress;
}

/* Wer Bewegung abgestellt hat, bekommt den Balken als ruhige Flaeche. Die Auskunft bleibt, die
   Animation faellt weg. */
@media (prefers-reduced-motion: reduce) {
  .ladeleiste-balken {
    width: 100%;
    animation: none;
    background: var(--bs-primary);
  }
}

/* --- Die Haken im Meldungsblock -------------------------------------------------------------

   Je Anlass eine Reihe Haken, einer je Adresse. Nebeneinander und umbrechend: untereinander
   waeren es bei fuenf Anlaessen und fuenf Adressen fuenfundzwanzig Zeilen. */
.meldungshaken {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem 1.25rem;
}

.meldungshaken .form-check {
  margin-bottom: 0;
}

/* Chart.js braucht einen Eltern mit fester Hoehe, sonst waechst die Leinwand bei jedem
   Neuzeichnen weiter. maintainAspectRatio: false allein reicht dafuer nicht. */
.diagramm-flaeche {
  position: relative;
  height: 260px;
}

@media (max-width: 575.98px) {
  .diagramm-flaeche {
    height: 180px;
  }
}

/* Erreichbarkeitsbalken. Ein Balken aus Abschnitten mit Prozentbreiten.
   Offline ist grau und nicht rot: eine Box, die nachts aus ist, hat keine Stoerung. Rot bleibt
   dem vorbehalten, was wirklich schiefgegangen ist. */
.verfuegbarkeit-balken {
  height: 1.75rem;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  background-color: var(--cube-surface-2);
}

.verfuegbarkeit-segment {
  height: 100%;
  cursor: default;
}

.verfuegbarkeit-segment:hover {
  filter: brightness(1.35);
}

.verfuegbarkeit-online {
  background-color: var(--ton-gruen-voll);
}

.verfuegbarkeit-offline {
  background-color: #4a4d52;
}

.verfuegbarkeit-legende {
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 3px;
  vertical-align: middle;
}

/* Platzhalter, solange von einer Box noch kein Livebild vorliegt. Feste Hoehe, damit die Karte
   nicht springt, sobald das erste Bild da ist. */
/* Kachel der Bildergalerie. Feste Hoehe, damit das Raster nicht nach jedem geladenen Bild
   springt, und ein Ring statt eines Rahmens. */
/* Eine Kachel in der Galerie zeigt das ganze Bild und schneidet nichts ab. Am 29.08.2026
   beanstandet: "die galerie soll die bilder ohne abrundung anzeigen und vollständig."

   `cover` fuellte die Kachel und schnitt dafuer oben und unten weg. Bei einer Collage im
   Querformat verschwand damit die halbe Aufnahme, und wer nachsehen wollte, was auf dem Bild ist,
   musste es erst oeffnen. `contain` zeigt alles und laesst links und rechts Grund stehen. Die
   Rundung faellt weg: ein Foto hat gerade Kanten. */
.kachelbild {
  width: 100%;
  height: 130px;
  object-fit: contain;
  border-radius: 0;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  background-color: rgba(0, 0, 0, 0.35);
}

/* Der Wartehinweis, solange ein Befehl unterwegs ist.
 *
 * **Er steht oben rechts bei den Toasts.** Am 09.09.2026 beanstandet: "die art von meldungen will
 * ich oben rechts haben, da unten sieht man sie nicht gut." Bis dahin sass er fest und mittig am
 * unteren Rand, also im toten Winkel und weit weg von dem Knopf, den man gerade gedrueckt hat.
 *
 * Keine eigene Lage mehr: er ist das erste Kind der Toastecke und steht in deren Spalte, siehe
 * .toastecke und base.html. Dieselbe Flaeche wie ein Toast, damit die Ecke eine Sprache spricht. */
.laeuft-leiste {
  pointer-events: auto;
  width: 100%;
  background: rgba(30, 30, 34, 0.94);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-radius: 12px;
  box-shadow: 0 0 0 1px var(--cube-ring), 0 10px 30px -10px rgba(0, 0, 0, 0.8);
  padding: 0.65rem 1rem;
}

/* Ein Formular, dessen Knopf gerade wartet, nimmt keine weitere Eingabe an. */
.wartet {
  pointer-events: none;
  opacity: 0.6;
}

/* Ein Formular, dessen Anfrage gerade laeuft. htmx setzt die Klasse und nimmt sie danach wieder
   weg, deshalb kann der Kreisel hier stehen statt im Skript: von Hand gesetzt bliebe er stehen,
   denn die Seite wechselt seit dem 30.08.2026 nicht mehr. */
form.htmx-request {
  pointer-events: none;
  opacity: 0.6;
}

form.htmx-request button[type="submit"]::before {
  content: "";
  display: inline-block;
  width: .875rem;
  height: .875rem;
  margin-right: .5rem;
  vertical-align: -2px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: .75s linear infinite spinner-border;
}

/* --- Ausgegraut, solange die Box nicht verbunden ist -------------------------------------------

   Die Werte bleiben lesbar, die Knoepfe nicht bedienbar. Eine weggefallene Box zeigte vorher
   dieselbe Seite wie eine laufende, und ein Klick legte einen Befehl an, den niemand abholte.

   Gesperrt wird an data-befehl. Das traegt jedes Formular, das einen Auftrag an die Box anlegt,
   und nur diese. Das Verwerfen der Bilderkopie im Portal, das Quittieren einer Stoerung und das
   Leeren der Warteschlange bleiben bedienbar, sie wirken hier und nicht dort.

   pointer-events sperrt den Zeiger, den Rest erledigt das Skript mit dem echten disabled. Ohne
   Skript bleibt der Riegel im Dienst, siehe befehle.BoxNichtErreichbar. */
.befehle-gesperrt form[data-befehl] {
  opacity: 0.45;
}

.befehle-gesperrt form[data-befehl] button,
.befehle-gesperrt form[data-befehl] input,
.befehle-gesperrt form[data-befehl] select,
.befehle-gesperrt form[data-befehl] textarea,
.befehle-gesperrt form[data-befehl] label {
  pointer-events: none;
}

.befehle-gesperrt form[data-befehl] button {
  cursor: not-allowed;
}

/* Balken fuer den Papiervorrat und den Abgleich mit der Cloud. */
.fortschritt-schmal {
  height: 0.5rem;
  border-radius: 4px;
  background-color: var(--cube-surface-2);
}

/* Der Balken in der Kachel "Drucke". Er traegt dort die Aussage und steht nicht daneben, deshalb
   ist er hoeher als der schmale oben. Am 09.09.2026 am Entwurf entschieden. */
.fortschritt-druckstand {
  height: 0.625rem;
  border-radius: 5px;
  background-color: var(--cube-surface-2);
}

/* Jeder Balken liegt in derselben Rinne. Bootstraps Vorgabe ist ein flaches Grau, das auf dieser
   Grundflaeche wie ein Fremdkoerper wirkt: die Rinne gehoert zur Karte und nicht auf sie. */
.progress {
  background-color: var(--cube-field);
  box-shadow: inset 0 0 0 1px var(--cube-ring-soft);
  border-radius: 4px;
}

/* --- Seitenleiste und Pfad ----------------------------------------------------------------

   Die Navigation stand bis zum 31.08.2026 als Band oben. Sechs Punkte in derselben Farbe, und
   der Unterschied zwischen den Orten, an denen gearbeitet wird, und dem, wo nur nachgesehen
   wird, war nur Leerraum. Links tragen die Punkte Gruppen mit Ueberschrift, und darunter passen
   die Boxen selbst hin, jede mit ihrer Meldeleuchte.

   Unterhalb von lg wird die Leiste zur Schublade. Das macht `offcanvas-lg` aus Bootstrap, kein
   eigenes Skript. Darum die zwei Medienabfragen: unter lg legt Bootstrap die Leiste fest an den
   Rand, ab lg ist sie ein gewoehnlicher Kasten und wird hier zur Spalte gemacht. */

.portalrahmen {
  min-height: 100vh;
}

.seitenleiste {
  --bs-offcanvas-width: 272px;
  /* **Das !important gehoert hierhin.** Sobald die Leiste ab lg kein Offcanvas mehr ist, setzt
     Bootstrap ihr `background-color: transparent !important`. Ohne dieselbe Waffe haette sie auf
     dem Bildschirm keine eigene Flaeche: links staende nur der Grundverlauf der Seite, getrennt
     durch einen Haarstrich. Am 31.08.2026 beim Nachmessen gefunden, auf dem Bild war es kaum zu
     sehen, weil der Verlauf links ohnehin dunkler ist. */
  background-color: rgba(15, 15, 18, 0.88) !important;
  -webkit-backdrop-filter: var(--cube-blur);
  backdrop-filter: var(--cube-blur);
  box-shadow: inset -1px 0 0 var(--cube-ring);
}

/* Die eigene Klasse steht mit im Selektor, sonst gewinnt Bootstraps `.offcanvas-lg
   .offcanvas-body` mit seinem `flex-direction: row`. */
.seitenleiste-innen.offcanvas-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 14px 12px 12px;
  overflow-y: auto;
}

.leistenmarke {
  display: flex;
  align-items: center;
  padding: 2px 8px 12px;
}

.leistenmarke img {
  width: 148px;
  height: auto;
  display: block;
}

/* Die Suche steht in der Leiste und nicht im Inhalt. Die Leiste ist die einzige Flaeche, die auf
   jeder Seite an derselben Stelle steht. */
.leistensuche {
  position: relative;
  margin-bottom: 6px;
}

.leistensuche i {
  position: absolute;
  left: 11px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.8125rem;
  color: var(--bs-tertiary-color);
  pointer-events: none;
}

.leistensuche input {
  width: 100%;
  border: 0;
  border-radius: 9px;
  padding: 8px 11px 8px 32px;
  background: var(--cube-field);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  color: var(--bs-body-color);
  font-size: 0.875rem;
}

.leistensuche input:focus {
  outline: 0;
  box-shadow: inset 0 0 0 1px rgba(var(--bs-primary-rgb), 0.6);
}

.leistengruppe {
  font-size: 0.65rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--bs-tertiary-color);
  padding: 15px 10px 7px;
}

.leistenpunkt,
.leistenbox {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  border-radius: 9px;
  color: var(--bs-secondary-color);
  text-decoration: none;
  min-width: 0;
}

.leistenpunkt {
  padding: 9px 12px;
  font-size: 0.9375rem;
}

.leistenpunkt > i {
  width: 17px;
  text-align: center;
  flex: none;
}

.leistenpunkt:hover,
.leistenbox:hover {
  color: var(--bs-body-color);
  background: var(--cube-surface-2);
}

.leistenpunkt.active {
  color: var(--bs-body-color);
  background: rgba(var(--bs-primary-rgb), 0.2);
  box-shadow: inset 0 0 0 1px rgba(var(--bs-primary-rgb), 0.45);
}

.leistenpunkt.active > i {
  color: var(--bs-link-color);
}

/* Der Streifen an der Kante sagt, wo man ist, ohne dass die Flaeche dafuer kraeftiger werden
   muss. Indigo fuer den Ort, Kupfer aus der Marke fuer die geoeffnete Box: zwei Marken, zwei
   Bedeutungen, und keine davon kommt den vier Zustandstoenen in die Quere. */
.leistenpunkt.active::before,
.leistenbox.active::before {
  content: "";
  position: absolute;
  left: -12px;
  top: 7px;
  bottom: 7px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--bs-primary);
}

.leistenzahl {
  margin-left: auto;
  font-size: 0.7rem;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--cube-surface-2);
  color: var(--bs-tertiary-color);
}

.leistenpunkt.active .leistenzahl {
  background: rgba(var(--bs-primary-rgb), 0.32);
  color: var(--bs-link-hover-color);
}

.leistenbox {
  padding: 7px 12px 7px 14px;
  font-size: 0.875rem;
}

.leistenbox.active {
  color: var(--bs-body-color);
  background: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.leistenbox.active::before {
  background: var(--marke-kupfer);
}

/* Die Geraete haengen unter ihrem Menuepunkt und nicht in einer eigenen Gruppe daneben. Am
   02.09.2026 verlangt. Die Einrueckung und die Haarlinie sagen, wozu sie gehoeren, und ersetzen
   damit die Ueberschrift, die vorher darueber stand. */
.leistenunterbau {
  margin: 2px 0 4px;
  padding-left: 13px;
  border-left: 1px solid var(--cube-ring);
  margin-left: 18px;
}

/* Statt der Gruppenueberschriften "Arbeit" und "Nachsehen". Am 02.09.2026 verlangt: "eine
   trennlinie oder einfach nur optischer abstand reichen." */
.leistentrenner {
  height: 1px;
  background: var(--cube-ring);
  margin: 14px 4px 10px;
}

/* Die Meldeleuchte. Drei Zustaende, nicht mehr: sie laeuft, sie laeuft mit offenen Vorfaellen,
   sie ist weg.

   **Bis zum 02.09.2026 stand das Wort daneben**, mit der Begruendung, eine Farbe allein sei
   keine Auskunft. Beanstandet: "in der sidebar ist kein 'läuft' und 'aus' nötig bei den boxen,
   dafür ist der farbindikator". In einer Leiste mit zwei Geraeten stimmt das, und das Wort
   kostete die halbe Zeilenbreite.

   Die Begruendung von damals gilt trotzdem weiter, deshalb steht der Zustand als Titel am
   Verweis und noch einmal fuer einen Vorleser, siehe base.html. */
.leuchte {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

.leuchte-an { background: var(--ton-gruen-voll); box-shadow: 0 0 0 3px rgba(48, 164, 108, 0.18); }
/* Gelb heisst Problem: es war da, danach lief es weiter. Rot heisst Stoerung: sie besteht jetzt,
   der Betrieb ist betroffen. Am 06.09.2026 beanstandet, dass beides in einer Farbe stand und
   dasselbe Wort trug. Welche gilt, entscheidet dashboard.stufe und nicht die Vorlage. */
.leuchte-warn { background: #ffc53d; box-shadow: 0 0 0 3px rgba(255, 197, 61, 0.16); }
.leuchte-stoerung { background: #e5484d; box-shadow: 0 0 0 3px rgba(229, 72, 77, 0.18); }
.leuchte-aus { background: #4a4d54; }

.leistenfuss {
  margin-top: auto;
  padding-top: 10px;
  box-shadow: inset 0 1px 0 var(--cube-ring);
}

/* Unter welchem Namen hier gearbeitet wird, siehe base.html. */
.leistenkonto {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  font-size: 0.8rem;
  color: var(--bs-secondary-color);
}

.leistenkonto i {
  width: 16px;
  text-align: center;
}

/* Impressum und Datenschutz, ganz unten in der Leiste. Ohne Anmeldung gibt es keine Leiste, dann
   stehen sie im Fuss unter dem Inhalt, siehe base.html. Zu finden muessen sie sein, wichtig sind
   sie im Alltag nicht. */
.leistenrecht {
  display: flex;
  gap: 14px;
  padding: 8px 12px 2px;
  font-size: 0.75rem;
}

.rechtsfuss {
  display: flex;
  justify-content: center;
  gap: 18px;
  padding: 0 12px 24px;
  font-size: 0.8rem;
}

.leistenrecht a,
.rechtsfuss a {
  color: var(--bs-secondary-color);
  text-decoration: none;
}

.leistenrecht a:hover,
.rechtsfuss a:hover {
  color: var(--bs-body-color);
  text-decoration: underline;
}

/* Die drei Zahlen unter einem Event: gemeldet, hier, in der Cloud. */
.eventzahlen {
  display: flex;
  gap: 14px;
}

/* Der Verlauf steht in der Eventliste rechts. Am 05.09.2026 verlangt: "der balkenfortschritt soll
   rechts positioniert sein." Er stand bis dahin unter dem Namen und schob Termin, Ort und
   Ansprechpartner eine Zeile nach unten. Die Form der Kette selbst steht weiter unten.

   **Diese Regel gehört vor die Medienabfragen.** Weiter unten im Blatt hätte sie dieselbe
   Genauigkeit wie die Fassung fürs Telefon und würde sie schlagen, ganz gleich, ob die Abfrage
   passt. Der Verlauf lief damit auf einem Telefon aus der Karte heraus. */
.eventverlauf {
  flex: 0 0 auto;
  margin-left: auto;
}

/* Wie weit der Termin weg ist, neben dem Datum. Etwas heller als das Datum selbst: die Zahl davor
   ist die Angabe, das hier ist die Rechnung dazu. */
.terminabstand {
  color: var(--bs-body-color);
}

/* Das Melden unter einer Kachel im Gaestealbum.

   Es ist der seltene Fall und stand vierzehn Mal unter vierzehn Bildern, also lauter als das,
   worum es geht. An einem Zeigergeraet erscheint es jetzt erst beim Darueberfahren.

   Auf einem Telefon gibt es kein Darueberfahren, und dort kommen die Gaeste her. `(hover: hover)`
   greift deshalb nur an Geraeten mit Zeiger, ueberall sonst steht es wie zuvor da. */
.kachelmelden {
  opacity: 0.5;
  transition: opacity 0.15s;
  text-align: right;
  font-size: 0.75rem;
  line-height: 1;
}

@media (hover: hover) {
  .kachelkasten .kachelmelden {
    opacity: 0;
  }

  .kachelkasten:hover .kachelmelden,
  .kachelkasten:focus-within .kachelmelden {
    opacity: 0.8;
  }
}

/* Die Vorlagenkacheln auf der Gestaltungsseite des Kunden.

   Das Bild ist die Auswahl, nicht der Knopf daneben. Wer eine Vorlage aussucht, klickt auf das,
   was er sieht. Der Radioknopf bleibt trotzdem im Baum: ohne ihn gibt es keine Tastaturbedienung
   und keinen Namen für das Formular. */
.vorlagenkachel {
  display: block;
  cursor: pointer;
  padding: 8px;
  border-radius: 10px;
  border: 2px solid transparent;
}

.vorlagenkachel:hover {
  background-color: var(--cube-surface-2);
}

.vorlagenkachel:has(input:checked) {
  border-color: var(--bs-primary);
  background-color: var(--cube-surface-2);
}

.vorlagenkachel input {
  float: right;
}

/* Ein Konto, das nur nachsehen darf. Das Kennzeichen setzt base.html an den body, siehe
   app/auth.py bei schreibrecht_pruefen.

   Rein ueber CSS und ohne Skript, und zwar aus einem Grund: die Reiter einer Boxseite kommen
   ueber htmx nach. Ein einmaliger Durchgang beim Laden erwischt sie nicht, die Knoepfe stuenden
   danach wieder offen da. Ein Nachfahrenselektor greift auch auf allem, was spaeter dazukommt.

   Dieselbe Machart wie .befehle-gesperrt weiter oben, nur mit einem anderen Anlass. Auch
   dieselbe Grenze: pointer-events sperrt den Zeiger und nicht die Tastatur. Der Riegel sitzt im
   Dienst, das hier ist die Auskunft davor. */
body[data-nurlesen] form[method="post" i],
body[data-nurlesen] [data-hochladen],
body[data-nurlesen] [data-ordner-hochladen] {
  opacity: 0.45;
}

body[data-nurlesen] form[method="post" i] button,
body[data-nurlesen] form[method="post" i] input,
body[data-nurlesen] form[method="post" i] select,
body[data-nurlesen] form[method="post" i] textarea,
body[data-nurlesen] form[method="post" i] label,
body[data-nurlesen] [data-hochladen],
body[data-nurlesen] [data-ordner-hochladen] {
  pointer-events: none;
}

body[data-nurlesen] form[method="post" i] button {
  cursor: not-allowed;
}

/* Die Kopfzeile gibt es nur unterhalb von lg, siehe base.html. */
.mobilkopf {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: rgba(16, 16, 19, 0.9);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: inset 0 -1px 0 var(--cube-ring);
}

.mobilmarke img {
  width: 104px;
  height: auto;
  display: block;
}

.mobilknopf {
  width: 36px;
  height: 36px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 9px;
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  color: var(--bs-secondary-color);
  text-decoration: none;
}

.mobilknopf:hover {
  color: var(--bs-body-color);
  background: var(--cube-surface-2);
}

/* Ab lg steht die Leiste fest und der Inhalt daneben. Sie bleibt beim Blaettern stehen und
   scrollt notfalls in sich, damit auch zwanzig Boxen hineinpassen. */
@media (min-width: 992px) {
  .portalrahmen {
    display: flex;
    align-items: flex-start;
  }

  .seitenleiste {
    position: sticky;
    top: 0;
    flex: 0 0 260px;
    width: 260px;
    height: 100vh;
  }

  .seitenleiste-innen.offcanvas-body {
    height: 100%;
  }

  /* Der Inhalt braucht Luft zur Leiste. Die `.container` von Bootstrap richtet ihre Breite nach
     dem Fenster und nicht nach der Spalte, in der sie steht: neben einer 260 Bildpunkte breiten
     Leiste blieben von ihrer Rinne nur die eigenen 12 uebrig, und die Ueberschrift klebte an der
     Kante. */
  .portalinhalt {
    flex: 1 1 auto;
    min-width: 0;
    padding-inline: 18px;
  }
}

/* Der Pfad sitzt in einem eigenen Band ueber dem Inhalt. Vorher stand er als lose Zeile
   ueber der Ueberschrift, in der Vorgabefarbe von Bootstrap und auf jeder Seite anders weit
   eingerueckt. */
.pfadleiste {
  box-shadow: inset 0 -1px 0 var(--cube-ring);
  background: rgba(255, 255, 255, 0.015);
  padding: 0.5rem 0;
}

.breadcrumb {
  --bs-breadcrumb-divider: "›";
  --bs-breadcrumb-divider-color: var(--bs-tertiary-color);
  --bs-breadcrumb-item-active-color: var(--bs-body-color);
  font-size: 0.875rem;
}

.breadcrumb-item + .breadcrumb-item::before {
  padding-right: 0.5rem;
  padding-left: 0.5rem;
}

.breadcrumb-item a {
  color: var(--bs-secondary-color);
  text-decoration: none;
}

.breadcrumb-item a:hover {
  color: var(--bs-body-color);
  text-decoration: underline;
}

.breadcrumb-item.active {
  font-weight: 500;
}

/* --- Fehlerseite -------------------------------------------------------------------------- */

.fehlerseite {
  max-width: 34rem;
  margin: 3rem auto;
}

/* --- Frischezaehler ----------------------------------------------------------------------- */

/* Laeuft im Browser mit und sagt, seit wann der Zustand gilt. Bis zum 14.09.2026 stand hier,
   wann die Box zuletzt gehoert wurde, siehe dashboard.zustandsangabe. */
.frischezaehler {
  font-variant-numeric: tabular-nums;
}

/* **Wort und Dauer sind eine Angabe.** Die Reihe des Seitenkopfes setzt zwischen ihre Teile einen
   Trennpunkt, siehe .seitenkopf-lage. Zwischen "Online" und "seit 3 h 12 min" gehoert keiner hin,
   das ist ein Satz. Die Huelle macht aus beiden ein Teil der Reihe. */
.zustandsangabe {
  white-space: nowrap;
}

/* Auf dem Telefon darf der Satz doch umbrechen. Zusammengehalten drueckt er die rechte Haelfte
   des Boxkopfs so weit zusammen, dass der Eventname buchstabenweise umbricht. */
@media (max-width: 575.98px) {
  .zustandsangabe {
    white-space: normal;
  }
}

/* Die ausbleibende Meldung, in der Farbe, die der Frischezaehler bis zum 14.09.2026 als
   `.veraltet` trug. Kein Abzeichen: die Marken daneben tragen Zustaende, die jemand abstellen
   muss, und eine ausbleibende Meldung geht von allein vorbei. */
.ueberfaellig {
  color: var(--bs-warning);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* --- Bildteile eines Events --------------------------------------------------------------- */

/* Immer dieselben fuenf Reihen, immer untereinander, je Reihe die Auswahl aus dem Bestand und
   der Weg, etwas Neues hochzuladen. */
.bildteil {
  padding: 0.9rem 0;
  box-shadow: inset 0 -1px 0 var(--cube-ring-soft);
}

.bildteil:last-child {
  box-shadow: none;
  padding-bottom: 0;
}

.bildteil:first-child {
  padding-top: 0;
}

/* Die beiden Knoepfe fuer mehrere Dateien im Kopf des Editors, mit ihrer Standmeldung daneben. */
.editor-einlesen {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Die Uebersicht: vier Bilder nebeneinander, Titel darunter. Sie steht ueberall dort, wo die
   Karte nur zeigt und der Editor die Arbeit macht, siehe event/_design.html. Vier Reihen
   untereinander waren eine Liste, deren rechte Haelfte leer stand. */
.bildteile-uebersicht {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1rem;
}

.bildteile-uebersicht .bildteil {
  padding: 0;
  box-shadow: none;
}

/* **Die Reihe stand ueber ihrer Kachel.** Eine Reihe von Bootstrap zieht ihre Raender um den
   halben Zwischenraum nach aussen, und die Spalte darin polstert um denselben Betrag zurueck.
   Das geht auf, solange der Elternteil diese Polsterung hat. Die Kachel hier hat sie nicht, die
   Zeile darueber setzt sie auf null. Damit stand die Reihe acht Bildpunkte links und rechts
   ueber ihrer Kachel, und auf einem Telefon ragte die Uebersicht aus der Karte heraus.

   Am 14.09.2026 verlangt: "horizontales scrolling muss verhindert werden." Alle Spalten in
   dieser Uebersicht sind `col-12`, sie liegen also untereinander. Ein waagerechter Zwischenraum
   hat hier nichts zu trennen. Der senkrechte aus `g-3` bleibt, er trennt Bild und Beschriftung.

   Nur hier und nicht an jeder `.bildteil`: auf der Canvaseite steht die Reihe mehrspaltig, dort
   traegt derselbe Zwischenraum den Abstand zwischen den Spalten. */
.bildteile-uebersicht .bildteil > .row {
  --bs-gutter-x: 0;
}

.bildteile-uebersicht .teilbild {
  max-height: 120px;
  margin-inline: auto;
}

.bildteile-uebersicht .teilbild-leer {
  height: 120px;
}

@media (max-width: 767.98px) {
  .bildteile-uebersicht {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Auch die Vorlagenwahl im Editor. Dort brennt der Klick vier Bilder neu, das dauert spuerbar,
   und ohne diesen Zustand sieht der Nutzer bis zum Neuladen der Seite gar nichts. */
.bildteile.laedt,
.bildteil.laedt,
[data-vorlage-setzen].laedt {
  opacity: 0.55;
  pointer-events: none;
}

/* Das gewaehlte Bild. Der Platzhalter daneben ist genauso hoch, damit die Reihe beim Auswaehlen
   nicht springt.

   **Der Rahmen sitzt auf der Bildkante.** Am 05.09.2026 verlangt: "die bildteile sind ohne
   abgerundeten ecken anzuzeigen [...] und der rahmen hat genau die bildgroesse zu sein, kein
   whitespace." Bis dahin sass jedes Bild in einem Kasten fester Hoehe und voller Breite. Ein
   Hintergrund ist 16 zu 9, ein Collagerahmen 3 zu 2, ein Streifen hochkant, und was nicht in den
   Kasten passte, wurde weisser Rand daneben. Jetzt bestimmt das Bild seine Groesse, die Hoehe ist
   nur noch die Obergrenze.

   Der Schatten ohne `inset`: bei einem Bild laege er sonst unter dem Bildinhalt und waere nicht zu
   sehen. Aussen liegt er genau auf der Kante. */
.teilbild {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 74px;
  object-fit: contain;
  border-radius: 0;
  background-color: #fff;
  box-shadow: 0 0 0 1px var(--cube-ring);
}

/* Der Platzhalter ist kein Bild und braucht seine Masse deshalb ausdruecklich. */
.teilbild-leer {
  display: flex;
  width: 100%;
  height: 74px;
  align-items: center;
  justify-content: center;
  background-color: var(--cube-surface-2);
  color: var(--bs-tertiary-color);
  font-size: 0.75rem;
}

/* Die Karte nimmt hineingezogene Dateien an. Kein eigener Kasten dafuer: der staende die meiste
   Zeit leer herum. Stattdessen faerbt sich die Flaeche, die ohnehin da ist. */
[data-ablage] {
  position: relative;
  border-radius: 12px;
  transition: box-shadow 0.12s ease, background-color 0.12s ease;
}

[data-ablage].ablage-offen {
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 2px var(--bs-primary);
}

/* Der Hinweis liegt ueber der Karte und nimmt keine Zeigerereignisse an. Sonst loeste er beim
   Erscheinen ein dragleave aus, und die Flaeche flackerte. */
.ablagehinweis {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  border-radius: 12px;
  background-color: rgba(26, 26, 28, 0.72);
  color: var(--bs-body-color);
  font-size: 0.9rem;
}

/* Was die Automatik nicht unterbringen konnte. Es liegt noch im Browser und wartet darauf, dass
   ein Mensch die Reihe nennt. Weggeworfen wird nichts. */
.uebrigbereich {
  padding: 0.75rem;
  border-radius: 10px;
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.uebrigstueck {
  flex: 0 0 auto;
  width: 140px;
}

.uebrigstueck img {
  width: 100%;
  height: 78px;
  object-fit: contain;
  border-radius: 8px;
  background-color: #fff;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  display: block;
}

.uebrigname {
  font-size: 0.7rem;
  color: var(--bs-tertiary-color);
  margin: 0.3rem 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Der Vorrat einer Reihe. Waechst er, wird gescrollt, statt die Zeile umzubrechen. */
/* Kacheln brechen um, sie scrollen nicht. Am 04.09.2026 verlangt: "horizontales scrollen von
   irgendwelchen bildern hat von der gesamten seite zu verschwinden". Ein waagerechter Balken
   versteckt, was hinter der Kante liegt: auf einem Telefon lagen zwanzig Bildteile dort, und
   nichts sagte, dass es sie gibt. Dieselbe Begruendung wie bei den Tabellen weiter oben. */
.kachelstreifen {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding-bottom: 0.35rem;
}

/* --- Die Vorlagenwahl ------------------------------------------------------------------------
   Karten statt einer Liste, weil an einer Vorlage das Bild die Auskunft ist und nicht der Name.
   Sie brechen um, sie scrollen nicht. */
/* Ein Raster, das die Breite fuellt, statt einer Reihe fester Kacheln. Am 04.09.2026 verlangt:
   "der name der voralge ist nicht so wichtig und kann bei der auswalsansicht weggelassen werden
   zuhunsten groesserer thumbnails." Ohne Namen traegt die Karte nur noch das Bild, und auf einem
   breiten Schirm wird es dann auch breit. */
/* **Eine Zeile je Vorlage.** Am 05.09.2026 verlangt: "vorlagenansicht soll nur eine zeile pro
   vorlage darstellen das die bilder entsprechend gross sind." Die Karte traegt seit demselben Tag
   alle vier Bilder nebeneinander, und in einem Raster aus zwei oder drei Spalten blieben davon je
   107 Bildpunkte. Darauf ist ein Design nicht zu beurteilen. */
.vorlagenwahl {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}

.vorlagenkarte {
  position: relative;
  display: block;
  padding: 0.35rem;
  border: 0;
  border-radius: 12px;
  background-color: var(--cube-surface);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  color: inherit;
  cursor: pointer;
}

/* Die Marke einer Vorlage, der noch Bildteile fehlen. Sie liegt in der Ecke auf den Bildern und
   nicht daneben: die Karte trägt sonst keinen Text, siehe event/_vorlagenwahl.html. */
.vorlagenmarke {
  position: absolute;
  top: 0.6rem;
  left: 0.6rem;
  z-index: 1;
}

.vorlagenkarte:hover {
  background-color: var(--cube-surface-2);
}

.vorlagenkarte.gewaehlt {
  box-shadow: inset 0 0 0 2px var(--bs-primary);
}

/* Alle Bilder einer Vorlage in einer Zeile. Am 05.09.2026 verlangt: "es soll ein block jeweils
   horizontal alle bilder der vorlage zeigen um direkt alle designs zu sehen."
   Hier stand bis dahin .vorlagenkarte-bild, ein Kasten im Verhaeltnis 3 zu 2 fuer genau ein Bild.

   Jedes Bild bekommt denselben Anteil der Breite und behaelt sein eigenes Verhaeltnis, die Hoehen
   fallen deshalb verschieden aus. Das ist richtig so: ein Hintergrund ist 16 zu 9 und ein Streifen
   steht hochkant, und wer sie auf eine Hoehe zwingt, zeigt sie falsch oder mit Rand daneben. */
.vorlagenbilder {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.vorlagenbild {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  justify-content: center;
}

/* Die Hoehe ist gedeckelt, sonst zieht der Streifenrahmen die ganze Reihe auf das Dreifache: er
   steht hochkant, die anderen drei liegen quer. Seit der Umstellung auf eine Zeile je Vorlage ist
   die Grenze doppelt so hoch, denn jedes Bild hat jetzt ein Viertel der ganzen Breite. */
.vorlagenbild img {
  display: block;
  max-width: 100%;
  max-height: 150px;
  width: auto;
  height: auto;
}


.kachel {
  flex: 0 0 auto;
  width: 78px;
  height: 54px;
  padding: 0;
  border: 0;
  border-radius: 8px;
  overflow: hidden;
  background-color: #fff;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  cursor: pointer;
}

.kachel img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* --- Die Vorlagenliste ------------------------------------------------------------------------
   Eine Reihe je Vorlage, und die Bilder haben sie fuer sich. Am 08.09.2026 verlangt: "die
   vorschaubilder bei den vorlagen muessen groesser und dann nur eine zeile pro vorlage
   einnehmen."

   Die erste Antwort darauf war eine waagerechte Zeile aus drei Spalten: Name, Bilder, Knoepfe.
   Der Name nahm 15rem, die vier Knoepfe rund fuenfhundert Bildpunkte, und den Bildern blieb der
   Rest. Sie duerfen schrumpfen, also schrumpften sie: statt der gedachten 110 Bildpunkte Hoehe
   standen gut vierzig auf dem Schirm, weniger als in den Karten davor. Beanstandet am selben Tag.

   Der Fehler war die Lesart von "eine Zeile". Gemeint ist eine Vorlage je Reihe der Liste, damit
   die Bilder die volle Breite bekommen, und nicht alles nebeneinander auf einer Textzeile. Jetzt
   sitzen Name und Knoepfe oben, die Bilder liegen darunter und teilen die Breite mit nichts. */
.vorlagenliste {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* Die ganze Reihe ist seit dem 09.09.2026 ein Verweis auf die Ansicht der Vorlage. Verlangt:
   "man soll die bilder direkt klicken können um die vorlagenansicht zu öffnen." Sie sieht deshalb
   aus wie vorher und nicht wie ein Link: die Fläche ist der Knopf, nicht der Name darauf. */
.vorlagenzeile {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 0.875rem 1rem 1rem;
  border-radius: 10px;
  background-color: var(--cube-surface-1);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  color: inherit;
  text-decoration: none;
}

.vorlagenzeile:hover,
.vorlagenzeile:focus-visible {
  color: inherit;
  background-color: var(--cube-surface-2);
}

/* Links der Name, rechts die Knoepfe. Der Kopf steht ueber den Bildern und nicht neben ihnen,
   sonst nimmt er ihnen genau die Breite, um die es hier geht. */
.vorlagenzeile-kopf {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

.vorlagenzeile-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  min-width: 0;
}

/* Die Bilder tragen die Hoehe der Reihe. 250 Bildpunkte sind die Obergrenze und nicht das Mass:
   die vier nebeneinander brauchen dann rund 1310 Punkte, und so breit wird der Inhaltsbereich
   auch auf einem 1920er Schirm gerade nicht. In der Praxis schrumpfen sie also immer ein Stueck
   und fuellen die Reihe genau aus. Der Deckel steht trotzdem hier, denn die Vorschauen liegen mit
   480 Punkten auf der langen Kante vor, siehe bestand.VORSCHAU_KANTE, und ein Hintergrund in 16:9
   ist bei 250 genau 444 breit. Darueber waere das Bild groesser als seine Quelle.

   **Sie brechen nicht um, sie schrumpfen gemeinsam.** Die Breite jedes Bildes steht als
   `ratio * --zeilenbild`, die Hoehe folgt aus dem Formatattribut. Wird der Platz knapp, kuerzt
   der Flexkasten alle vier im selben Verhaeltnis, und die Reihe bleibt eine Reihe. Erst im
   schmalen Fenster darf sie umbrechen, siehe unten: zwei Zeilen sind besser als Briefmarken. */
.teilereihe {
  --zeilenbild: 250px;
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 0.625rem;
  min-width: 0;
}

/* `flex: 0 0 auto` ist Absicht und nicht die Vorgabe: die Breite kommt aus dem Formatattribut je
   Rolle, und ein wachsendes Flexelement haette sie ueberschrieben. Genau daran ist die erste
   Fassung gescheitert, alle vier Bilder standen gleich breit da.

   Die Klasse hiess bis zum 09.09.2026 `.vorlagenzeile-bild`. Sie zeichnet seitdem an zwei Orten:
   in der Vorlagenliste und im Reiter Event einer Box, wo dasselbe Bild dasselbe zeigen soll.
   `.vorlagenbild` ohne Praefix gibt es daneben, es gehoert zur Vorlagenwahl in
   event/_vorlagenwahl.html. */
.teilereihe-bild {
  /* Schrumpfen erlaubt, wachsen nicht: die Breite kommt aus dem Verhaeltnis der Rolle, siehe
     oben. Ein wachsendes Element haette sie ueberschrieben, und alle vier staenden gleich breit
     da. Genau daran ist die erste Fassung gescheitert. */
  flex: 0 1 auto;
  min-width: 0;
  height: auto;
  border-radius: 6px;
  background-color: #fff;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  object-fit: cover;
  display: block;
}

.teilereihe-bild-leer {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--cube-surface-2);
  color: var(--bs-tertiary-color);
}

/* Hier stand bis zum 09.09.2026 .vorlagenzeile-knoepfe, die vier Knoepfe in der Ecke einer Reihe.
   Sie stehen jetzt in der Ansicht der Vorlage, siehe vorlagen.html. */

/* Im schmalen Fenster reicht die Breite fuer die vier Bilder nebeneinander nicht mehr. Ohne
   Umbruch schrumpften sie auf Briefmarkengroesse, deshalb hier der Umbruch und ein kleineres
   Grundmass: lieber zwei Zeilen Bilder, die man noch erkennt. */
@media (max-width: 991.98px) {
  .teilereihe {
    --zeilenbild: 150px;
    flex-wrap: wrap;
  }
}

.kachel:hover {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);
}

.kachel.gewaehlt {
  box-shadow: 0 0 0 2px var(--bs-primary);
}

/* Die erste Kachel ist keine Auswahl, sondern der Weg, etwas Neues hineinzulegen. */
.kachel-neu {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--cube-surface-2);
  color: var(--bs-secondary-color);
  margin-bottom: 0;
}

.kachel-neu:hover {
  color: var(--bs-body-color);
  background-color: var(--cube-surface-3);
}

/* --- Die Eventauswahl im Reiter der Box ---------------------------------------------------- */

/* Kacheln und kein Auswahlmenue. Am 30.08.2026 verlangt: "es soll dort auch die auswahl
   verschwinden mit dem dropdown." Ein Event unterscheidet sich fuer das Auge am Rahmen, und ein
   Menue zeigt Namen. */
.eventwahl {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.eventkachel {
  width: 190px;
  padding: 0;
  border: 0;
  border-radius: 10px;
  overflow: hidden;
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.eventkachel img {
  display: block;
  width: 100%;
  height: 107px;
  object-fit: cover;
  background-color: var(--cube-surface-3);
}

.eventkachel-name {
  display: block;
  padding: 8px 10px;
  font-size: .8125rem;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

.eventkachel:hover {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);
  background-color: var(--cube-surface-3);
}

.eventkachel:focus-visible {
  outline: 2px solid var(--bs-primary);
  outline-offset: 2px;
}

/* Eine gesperrte Box laesst sich nicht bespielen. Der Knopf sagt es, statt ins Leere zu fuehren. */
.eventkachel:disabled {
  opacity: .5;
  cursor: default;
}

/* --- Das Bild eines Events in der Liste -------------------------------------------------- */

/* Nicht jedes Event hat einen Hintergrund. Am 30.08.2026 verlangt: "events die kein bild
   verfuegbar haben brauchen eine platzhaltericon in der event ansicht." Vorher stand dort das
   kaputte Bildsymbol des Browsers, und das sieht nach einem Fehler aus. */
.eventbild {
  flex: 0 0 auto;
  width: 64px;
  height: 40px;
  object-fit: cover;
}

.eventbild-leer {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--cube-surface-2);
  color: var(--bs-tertiary-color);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

/* --- Das Bild einer Box ------------------------------------------------------------------------

   Zwei Orte, dieselbe Datei: der Kopf der Boxseite, links neben Name und Zustand, und die Karte
   "Bild" unter dem Zahnrad. Das kleine Bild in der Boxauswahl steht weiter oben bei
   .boxlistenbild, das grosse in der Kachel bei .boxkachel-bild.

   **Kein Grund unter dem Bild und keine Kachel darum.** Ein freigestelltes Geraet ist als PNG
   durchsichtig, und genau so soll es dastehen. Der Bestand macht es anders und legt seine
   Vorschauen auf ein Schachbrett, dort ist das richtig: ein Rahmen ist fast vollstaendig
   durchsichtig und waere sonst eine leere Kachel. Ein Geraet ist es nicht.

   Am 10.09.2026 vormittags stand es als erste Kachel im Reiter Uebersicht. Am Nachmittag
   verlangt: "setz das bild der box ohne kachel groesser als jetzt links von dem namen und den
   'nicht verbunden' block". */

/* Zwei Spalten und zwei Zeilen: das Bild links ueber beide Zeilen, oben rechts der Seitenkopf,
   darunter die Karten. Ein Raster und kein Nebeneinander aus zwei Kaesten, denn auf einem Telefon
   fallen die Karten unter das Bild und nehmen dort die ganze Breite. Mit zwei Kaesten waeren sie
   auf 260 Bildpunkte eingezwaengt, siehe die Regel weiter unten. */
/* --- Der Kopf einer Boxseite -----------------------------------------------------------------

   **Links das Geraet, rechts die Veranstaltung.** Am 11.09.2026 verlangt: "quasi das was links die
   fotobox ist, soll rechts das event sein." Beide Seiten tragen dieselben drei Zeilen in derselben
   Groesse, beide Bilder sind gleich gross, und die Anordnung ist gespiegelt.

   Der Block davor hiess `.kopfmitbild` und war ein Raster aus zwei Spalten und zwei Zeilen: Bild
   links ueber beide Zeilen, Kopf oben rechts, Stoerungskarte und Hinweis darunter. Die
   Stoerungskarte steht seit demselben Tag hinter ihrer Marke, damit ist die zweite Zeile leer
   geworden. */
.kopfreihe {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

/* **Das Zahnrad steht ausserhalb.** Am 11.09.2026 beanstandet: "das das einstellungs icon mit
   eingefaerbt wird ist mist." Es liegt jetzt neben dem Block auf dem gewoehnlichen Grund der
   Seite und nicht mehr darin. */
.kopfzahnrad {
  flex: none;
}

.boxkopf {
  position: relative;
  flex: 1;
  min-width: 0;
  border-radius: var(--bs-border-radius-lg);
  overflow: hidden;
}

/* **Der Verlauf laeuft schraeg und setzt bei der Haelfte an.** Am 11.09.2026 verlangt: "nur 45
   grad starten. verlauf einfarbig." 135 Grad und nicht 45: dieselbe Neigung fuehrt das Portal
   schon an der Boxzeile der Uebersicht und am Stoerungsband, und dort steht dieselbe Ansage von
   damals im Kommentar. Zwei verschiedene Schraegen im selben Haus waeren ein Fehler.

   Links von der Mitte ist nichts. Er steht nur, solange ein Event auf der Box liegt: er sagt
   genau das.

   **Am 13.09.2026 auf ein Band zurueckgeschnitten.** Beanstandet: "der verlauf soll auch nur die
   hoehe des bildes haben", nach dem Entwurf dann "weniger sieht gut aus, aber der verlauf soll
   mit dem bild enden".

   Er lag bis dahin auf der ganzen Flaeche der Karte, und die ist so hoch wie das Boxbild links.
   Seit das Eventbild kleiner ist, lief er oben und unten an ihm vorbei und faerbte Flaeche, auf
   der nichts steht. Jetzt ist er ein Band: fuenf Rem hoch, mittig, und **er endet am linken Rand
   des Eventbildes**. Damit fuehrt er auf das Bild zu, statt darunter durchzulaufen.

   Als Pseudo-Element und nicht als Hintergrund der Karte, denn ein Hintergrund kennt keine eigene
   Hoehe. Der Inhalt liegt darueber, sonst legte sich das Band ueber die Schrift. */
.boxkopf-event { background: none; }

.boxkopf-event::before {
  content: "";
  position: absolute;
  left: 0;
  /* Die Breite des Eventbildes plus der Rand der Reihe. Ohne Bild steht dort das gestrichelte
     Feld in derselben Breite, siehe .kopfeventbild-leer. */
  right: calc(7rem + 0.5rem);
  top: 50%;
  transform: translateY(-50%);
  height: 5rem;
  background: linear-gradient(135deg, transparent 50%, rgba(255, 255, 255, 0.1) 100%);
  pointer-events: none;
}

/* **Ohne Event dasselbe Band.** Am 14.09.2026 verlangt: "der verlauf soll auch dazu." Es steht
   seit dem 11.09.2026 nur, solange ein Event auf der Box liegt, und sagte damit genau das. Eine
   Box ohne Event sah deshalb aus, als fehle ihr die rechte Haelfte.

   Es laeuft hier bis an den Rand und endet nicht am Feld. Mit Event fuehrt es auf das Bild zu,
   ohne Event deckt das graue Feld es ab, siehe .kopfeventbild-grau. Endete es davor, staende
   eine Kante mitten im Kopf. */
.boxkopf-leer { background: none; }

.boxkopf-leer::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 5rem;
  background: linear-gradient(135deg, transparent 50%, rgba(255, 255, 255, 0.1) 100%);
  pointer-events: none;
}

.boxkopf-reihe {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 0.5rem;
}

/* Auf einem Telefon stehen die drei Teile untereinander. Nebeneinander blieben dem Namen rund
   80 Bildpunkte. */
@media (max-width: 767.98px) {
  .boxkopf-reihe {
    flex-wrap: wrap;
  }
}

.kopfbild {
  flex: none;
  width: 11rem;
  height: 11rem;
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

.kopfbild img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Ohne Bild ein gestricheltes Feld. Es sagt, dass hier eines hingehoert, und fuehrt dorthin, wo
   es hochgeladen wird. Striche und keine Flaeche: eine Kachel war ausdruecklich nicht gewollt. */
.kopfbild-leer {
  flex-direction: column;
  gap: 0.5rem;
  border-radius: 0.75rem;
  border: 1px dashed var(--cube-ring);
  color: var(--bs-tertiary-color);
  font-size: 0.8125rem;
}

.kopfbild-leer i {
  font-size: 1.5rem;
}

.kopfbild-leer:hover,
.kopfbild-leer:focus-visible {
  border-color: var(--bs-tertiary-color);
  color: var(--bs-body-color);
}

/* Auf einem Telefon bleibt das Bild links neben dem Namen stehen, nur kleiner. Ueber den Namen
   gesetzt schoebe es den Zustand unter die Falz, und der ist die erste Frage an eine Box.

   Die Karten darunter nehmen die ganze Breite. Neben dem Bild blieben ihnen 260 Bildpunkte, und
   darin steht ein Zeitpunkt wie "10.09.2026 13:07:24" dreizeilig. */
@media (max-width: 639.98px) {
  .kopfmitbild {
    column-gap: 0.875rem;
  }

  .kopfbild {
    grid-row: 1;
    width: 6rem;
    height: 6rem;
  }

  .kopfmitbild-breit {
    grid-column: 1 / -1;
  }
}

/* --- Der Kopf der Eventseite auf dem Telefon --------------------------------------------------
   Am 15.09.2026 beanstandet: "die mobile ansicht der eventseite ist aktuell nicht nutzbar."

   Gemessen bei 390 Bildpunkten: die Kopfreihe war 591 hoch, und der erste Reiter fing bei 759 an.
   Ein Telefon zeigt 844. Wer die Seite öffnete, sah das Eventbild, den Namen und das Boxfeld,
   und alles andere lag unter der Falz.

   Der Grund war das Umbrechen: die drei Teile standen untereinander, jeder mit einem Bild von
   sieben rem. Jetzt steht das Eventbild klein neben dem Namen, und das Boxfeld nimmt als eigene
   Zeile darunter die volle Breite, ebenfalls mit kleinem Bild. Das ist dieselbe Anordnung wie
   auf der Boxseite, wo das Bild seit dem 11.09.2026 bei 639 Bildpunkten auf sechs rem geht. */
@media (max-width: 639.98px) {
  .boxkopf-reihe {
    gap: 0.75rem;
    padding: 0.5rem 0.25rem;
  }

  /* Das Eventbild links neben dem Namen. Über den Namen gesetzt schöbe es den Verlauf nach
     unten, und der ist die erste Frage an ein Event. */
  .boxkopf-reihe > .kopfeventbild {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--bs-border-radius);
  }

  /* Der Name nimmt, was neben dem Bild bleibt. Ohne das legt sich das Boxfeld in dieselbe
     Zeile, und dem Namen bleiben achtzig Bildpunkte. */
  .boxkopf-reihe > .seitenkopf-name {
    flex: 1 1 0;
  }

  .boxkopf-reihe > .seitenkopf-name h1 {
    font-size: 1.125rem;
  }

  /* Das Verlaufsband wird eine Stufe kleiner. Neben dem Bild bleiben ihm 302 Bildpunkte, und
     mit der Schrift von 0.6875rem brauchte es 317: die Stationen hießen dann "Freigege...",
     "Been..." und "Cl...", und ein Verlauf, dessen Stationen man raten muss, ist keiner. */
  /* Zwei Klassen, damit die Regel trifft: .standband steht weiter unten in dieser Datei, und
     bei gleicher Spezifität gewinnt die spätere. */
  .standzeile .standband {
    font-size: 0.625rem;
  }

  .standzeile .standband li {
    padding-inline: 0.3rem;
  }

  .standzeile .standband .jetzt {
    padding-inline: 0.45rem;
  }

  .standzeile .standband .ende {
    padding-inline: 0.4rem;
  }

  /* Das Boxfeld als eigene Zeile unter dem Namen, linksbündig wie alles darüber. Rechtsbündig
     stünde der Name der Box unter dem Verlaufsband und sähe aus wie dessen Ende. */
  .eventkopf {
    flex: 1 0 100%;
    margin-left: 0;
    gap: 0.625rem;
  }

  .eventkopf-text {
    text-align: left;
  }

  .eventkopf-name {
    font-size: 1.0625rem;
  }

  .eventkopf .kopfeventbild {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--bs-border-radius);
  }

  /* Das leere Feld mit dem Aufspielknopf: der Knopf zuerst, das graue Feld daneben. Es trägt
     nur ein Wort und braucht keine Fläche von sieben rem. */
  .eventkopf-leer .kopfeventbild-grau {
    width: 2.75rem;
    height: 2.75rem;
  }

  .kopfeventbild-wort {
    font-size: 0.625rem;
  }
}

/* Die Karte unter dem Zahnrad: Vorschau links, Angaben und Knoepfe rechts. */
.bildkarte {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
}

.bildkarte-vorschau {
  flex: none;
  width: 8rem;
  height: 8rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.bildkarte-vorschau img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.bildkarte-vorschau.leer {
  border-radius: 0.5rem;
  background: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  color: var(--bs-tertiary-color);
  font-size: 1.5rem;
}

.bildkarte-text {
  flex: 1 1 12rem;
  min-width: 0;
}

.bildkarte-knoepfe {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

/* --- Engere Tabellen ---------------------------------------------------------------------- */

/* Die Vorgabe von 12 px oben und unten ist fuer eine Uebersicht mit fuenf Zeilen zu viel Luft.
   Am 26.08.2026 beanstandet: "der bestand hat zu grosse abstaende". */
.card .table-eng > tbody > tr > td {
  padding-top: 5px;
  padding-bottom: 5px;
}

.card .table-eng > thead > tr > th {
  padding-top: 5px;
  padding-bottom: 5px;
}

/* --- Die aktive Leitung ------------------------------------------------------------------- */

/* Welche Leitung gerade traegt, ist die Auskunft der Karte und steht deshalb gross oben, nicht
   als ein Feld unter vielen. */
.aktive-leitung {
  display: flex;
  align-items: center;
  padding: 0.6rem 0.9rem;
  border-radius: 10px;
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

/* --- Kleinere Galeriekachel --------------------------------------------------------------- */

.kachelbild-klein {
  height: 84px;
}

/* --- Galerie: was liegt wo -----------------------------------------------------------------
   Die Galerie zeigt jede Aufnahme der Box, auch die ohne Vorschau hier. Wo das Bild fehlt,
   steht eine Flaeche mit dem Ladeknopf statt einer Luecke. */
.kachel-ohne {
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  background-color: var(--cube-surface-2);
}

.kachelzeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .25rem;
  margin-top: .2rem;
}

.kachelname {
  font-size: .72rem;
  color: var(--bs-secondary-color);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Ein Stueck einer Aufnahme in einem von drei Zustaenden. Das Symbol bleibt dasselbe, nur die
   Deutlichkeit wechselt: im Portal ist es da, auf der Box ist es holbar, sonst gibt es nichts. */
.stueck {
  display: inline-flex;
  align-items: center;
  font-size: .72rem;
  line-height: 1;
  padding: .15rem;
  border-radius: 4px;
  text-decoration: none;
}

/* Der Hauston und nicht Bootstraps Grün. `--bs-success` ist #198754 und stand damit stumpfer da
   als jede grüne Marke daneben, siehe die Töne im Kopf des Blattes.

   Grün heißt "in der Cloud" und damit gesichert. Bis zum 13.09.2026 hieß es auch "liegt im
   Portal", beide Zustände trugen diese eine Klasse. Beanstandet: "die aufnahmenliste zeigt nicht
   den sync status einzelner bilder." Ein Bild, das nur im Portal lag und auf der Box längst
   gelöscht war, sah damit aus wie eines im Bestand.

   `.stueck-hier` steht weiter daneben, aber nur noch auf der Bestandsseite. Dort heißt sie "in
   Gebrauch" und hat mit der Cloud nichts zu tun, siehe templates/bestand.html. */
.stueck-cloud,
.stueck-hier {
  color: var(--ton-gruen-schrift);
}

/* Gelb heißt "nur hier". Die Datei ist da, aber sie ist nicht im Bestand, und das Portal ist
   kein Lager. Nicht rot: verloren ist nichts, es steht nur nicht dort, wo es hingehört. */
.stueck-portal {
  color: var(--ton-gelb-schrift);
}

.stueck-box {
  color: var(--bs-secondary-color);
}

/* Die Dateien, die nur im Portal liegen, mit Namen und Grund. Ohne eigenen Aufzählungspunkt und
   ohne Einzug: sie stehen in einer Warnung und nicht in einem Fließtext. Ab der sechsten Zeile
   wird gescrollt, sonst schiebt ein Abend mit vierhundert Bildern die halbe Seite beiseite. */
.liegengeblieben {
  list-style: none;
  padding-left: 0;
  max-height: 9rem;
  overflow-y: auto;
}

.liegengeblieben li {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.stueck-fehlt {
  color: var(--bs-secondary-color);
  opacity: .35;
}

/* Die Oberflaeche der Box in einem Rahmen. Feste Hoehe statt automatisch: der Rahmen liegt auf
   einer fremden Herkunft, seine Hoehe ist von hier aus nicht auszulesen. 78vh laesst die
   Reiterleiste stehen und fuellt den Rest. */
.oberflaechenrahmen {
  position: relative;
  height: 78vh;
  min-height: 420px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--cube-field);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.oberflaechenrahmen iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Die Sitzung auf der Box. Etwas niedriger als die Oberflaeche: ein Terminal braucht Zeilen und
   keine Bildflaeche, und darunter steht noch, was zu tun ist, wenn es nicht traegt. Der Grund ist
   schwarz und nicht durchscheinend, ttyd zeichnet auf eigenem Grund. */
.terminalrahmen {
  position: relative;
  height: 62vh;
  min-height: 360px;
  border-radius: 10px;
  overflow: hidden;
  background: #000;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.terminalrahmen iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Das Einsatzband stand hier bis zum 08.09.2026, eine Zeile je zusammenhaengendem Einsatz ueber
   dem Diagramm. Es ist mit der Einsatzkachel zusammen weggefallen, siehe box/_uebersicht.html. */

/* Ausgabe eines Befehls im Hinweis nach dem Klick. Am 29.08.2026 beanstandet: "befehl auf der box
   ausfuehren ist nutzlos wenn die antwort als unformatierter hinweis kommt." Die Ausgabe von
   `ip r` oder `systemctl status` lebt von ihren Spalten. */
.ausgabeblock {
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 22rem;
  overflow: auto;
  padding: 0.6rem 0.75rem;
  border-radius: 8px;
  font-size: 0.8125rem;
  background: rgba(0, 0, 0, 0.28);
}

/* --- Der Weg eines Bildes: Box, Uebertragung, Cloud --------------------------------------------

   Drei Bloecke nebeneinander, der mittlere traegt die Knoepfe. Am 30.08.2026 standen zwischen
   ihnen kurzzeitig Pfeile, und die waren falsch: sie zeigten auf eine Zwischenstation, die es
   nicht gibt. Die Bilder gehen durch den Dienst hindurch in die Cloud, er haelt sie nicht. */
.bilderweg {
  display: flex;
  align-items: stretch;
  gap: 0.75rem;
}

.bilderweg-block {
  flex: 1 1 0;
  min-width: 0;
}

/* Unter 1200 Bildpunkten stehen die drei untereinander. */
@media (max-width: 1199.98px) {
  .bilderweg {
    flex-direction: column;
  }

}

/* Eine Ueberschrift innerhalb einer Karte, gebaut wie ein Kopfband, nur ohne eigene Flaeche.
   Sie traegt einen Abschnitt, der zur selben Sache gehoert und trotzdem eine eigene Marke und
   einen eigenen Knopf hat. Am 30.08.2026 fuer den Sicherungsstick verlangt: "der sicherungsstick
   sollte in den selbem block sein, am besten mit einer linie getrennt." */
.blockkopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
}

/* --- Das Vorschaubild in der Aufnahmetabelle ---------------------------------------------------

   Am 30.08.2026 verlangt: "die kleinen bilder kommen einfach links in die tabelle, so das die
   bilder einfach untereinenader angezeigt werden." Eine feste Hoehe haelt die Zeilen gleich hoch,
   `contain` zeigt ein Hochformat vollstaendig statt es zu beschneiden. */
.zeilenbild {
  width: 4.5rem;
  height: 3rem;
  object-fit: contain;
  background-color: rgba(0, 0, 0, 0.35);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.zeilenbild-ohne {
  background: var(--cube-field);
}

/* --- Der Kasten mit einem Link nach draussen ---------------------------------------------------

   Album und Gestaltung. Seit dem 02.09.2026 steht der Link dauerhaft da, mit Kopierknopf und
   einem Knopf, der die Seite oeffnet. Er ist der Grund, aus dem jemand diesen Reiter aufmacht,
   und deshalb hebt er sich vom Grund der Karte ab, ohne wie eine Warnung auszusehen. */
.linkkasten {
  padding: 0.75rem;
  border-radius: 10px;
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

/* --- Dieselben Aufnahmen als Kacheln -----------------------------------------------------------

   Am 02.09.2026 verlangt: "unter bilder soll die bilderansicht von tabelle in grössere thumbnails
   ansicht gewechselt werden können." Die Tabelle beantwortet "was liegt wo", die Kacheln
   beantworten "wie sieht der Abend aus".

   `auto-fill` und nicht `auto-fit`: bei drei uebrig gebliebenen Bildern zoege `auto-fit` sie auf
   Drittelbreite auseinander, und dieselbe Aufnahme waere je nach Zahl der Nachbarn verschieden
   gross. */
.bilderkacheln {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.75rem;
}

.bilderkachel .kachelbild {
  height: 170px;
}

/* On a phone two tiles per row. With 11rem only one fitted at 390 pixels, measured on
   19.10.2026 in the gallery of the Fotobox UI, and a day of sixty photos became a long road. */
@media (max-width: 575.98px) {
  .bilderkacheln {
    grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  }

  .bilderkachel .kachelbild {
    height: 130px;
  }
}

/* Die Flaeche einer Aufnahme ohne Vorschaubild. Sie bleibt genauso hoch wie ein Bild, sonst
   springt das Raster an jeder Luecke. */
.kachelbild-ohne {
  width: 100%;
  background: var(--cube-field);
}

/* --- Kontrollbilder in der Steuerung -----------------------------------------------------------

   Drei Blicke nebeneinander, und sie zeigen Verschiedenes: das Livebild kommt aus dem
   Vorschaustrom, das Kamerabild durch das Objektiv der Spiegelreflexkamera, das Probebild ist
   das fertige Ergebnis einer Probeausloesung. Jedes traegt ein Kreuz, mit dem es wieder
   verschwindet. Am 30.08.2026 verlangt, am 10.09.2026 um das dritte erweitert.

   Das Raster bleibt bei auto-fit: in der schmalen Karte fallen die drei untereinander, in einer
   breiten stehen sie nebeneinander. */
.kontrollbilder {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.75rem;
}

.kontrollbild {
  position: relative;
  min-width: 0;
}

/* Das Kreuz liegt in der Ecke des Bildes und nicht daneben. Daneben waere es eine zweite Zeile,
   und die Karte ist ohnehin die vollste der Uebersicht. */
.kontrollbild-weg {
  position: absolute;
  top: 0.35rem;
  right: 0.35rem;
  margin: 0;
  border-radius: 6px;
  padding: 0.15rem;
  background: rgba(20, 20, 22, 0.72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  line-height: 0;
}

/* Ein Knopf in der Ecke einer Kopfzeile: nur das Zeichen, quadratisch, in der Hoehe einer Marke.
   Am 30.08.2026 fuer den Drucker verlangt, gilt fuer jede Karte, die sich auffrischen laesst. */
.kopfknopf {
  --bs-btn-padding-y: 0.15rem;
  --bs-btn-padding-x: 0.4rem;
  line-height: 1;
}

/* --- Rueckmeldung in der Ecke ------------------------------------------------------------------

   Am 30.08.2026 verlangt: "erfolgreiche aktionen sollen direkt mit timeout als overlay toast in
   der ecke angezeigt werden." Vorher stand jede Rueckmeldung als Banner ueber der Seite und schob
   den Inhalt nach unten. Nach drei Klicks war der obere Bildschirmrand voll Text, und der Reiter,
   an dem gearbeitet wurde, lag ausserhalb des Bildes.

   Geglueckt geht von selbst weg, fehlgeschlagen bleibt stehen. Ein Fehler, der nach fuenf Sekunden
   verschwindet, ist ein Fehler, den niemand gelesen hat. */
/* **Oben rechts und nicht unten.** Am 09.09.2026 beanstandet: "die art von meldungen will ich
   oben rechts haben, da unten sieht man sie nicht gut."

   Unten rechts liegt im toten Winkel: der Blick steht beim Klicken oben, und die Antwort erschien
   am anderen Ende des Schirms. Oben rechts steht sie da, wo der Knopf war, der sie ausgeloest hat.

   Die Warteleiste steht seitdem in derselben Ecke, siehe .laeuft-leiste. Damit faellt die Regel
   weg, die die Toasts ueber sie schob. */
.toastecke {
  position: fixed;
  right: 1rem;
  top: 1rem;
  z-index: 1090;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.5rem;
  max-width: min(92vw, 26rem);
  pointer-events: none;
}

.hinweistoast {
  pointer-events: auto;
  width: 100%;
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.7rem 0.85rem;
  border-radius: 10px;
  font-size: 0.9375rem;
  background: rgba(30, 30, 34, 0.96);
  -webkit-backdrop-filter: var(--cube-blur);
  backdrop-filter: var(--cube-blur);
  box-shadow: 0 0 0 1px var(--cube-ring), 0 12px 32px -12px rgba(0, 0, 0, 0.85);
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 0.18s ease, transform 0.18s ease;
}

.hinweistoast.sichtbar {
  opacity: 1;
  transform: none;
}

.hinweistoast-gut {
  box-shadow: inset 0 0 0 1px var(--ton-gruen-rand),
    0 12px 32px -12px rgba(0, 0, 0, 0.85);
}

.hinweistoast-gut .hinweistoast-symbol { color: var(--ton-gruen-schrift); }

.hinweistoast-schlecht {
  box-shadow: inset 0 0 0 1px var(--ton-rot-rand),
    0 12px 32px -12px rgba(0, 0, 0, 0.85);
}

.hinweistoast-schlecht .hinweistoast-symbol { color: var(--ton-rot-schrift); }

.hinweistoast-text {
  flex: 1 1 auto;
  min-width: 0;
  word-break: break-word;
}

.hinweistoast .btn-close {
  flex: 0 0 auto;
  margin-top: 0.15rem;
}

/* Eine mehrzeilige Befehlsausgabe passt nicht in eine Ecke. Sie bleibt lesbar und bekommt eine
   eigene Rinne, statt den Toast ueber den halben Bildschirm zu ziehen. */
.hinweistoast .ausgabeblock {
  max-height: 12rem;
  font-size: 0.75rem;
}

/* Die Warteleiste steht seit dem 09.09.2026 als erstes Kind derselben Ecke. Die Regel, die die
   Toasts ueber sie schob, ist damit weggefallen: sie stehen jetzt untereinander. */

@media (max-width: 575.98px) {
  .toastecke {
    left: 0.75rem;
    right: 0.75rem;
    top: 0.75rem;
    max-width: none;
  }
}

/* --- Der Kopf einer Seite --------------------------------------------------------------------

   Links der Name und sein Zustand, darunter die Beiwerte, rechts die Knoepfe. Bis zum 29.08.2026
   baute jede Seite das mit eigenen Bootstrap-Klassen nach, und auf einem Telefon kam bei jeder
   etwas anderes heraus. Auf der Boxseite stand der Zahnradknopf allein auf einer dritten Zeile.

   Eine Klasse fuer alle. Sie legt die Knoepfe auf schmalen Bildschirmen neben den Titel statt
   darunter, denn sie sind schmal und der Titel ist es nicht. */
/* Der Weg zurueck, oben links ueber dem Seitenkopf. Am 09.09.2026 verlangt, siehe base.html.
 *
 * Ein Verweis und kein Knopf mit Rahmen: er nimmt nichts weg und loest nichts aus, er geht eine
 * Station zurueck. Ein gerahmter Knopf stuende in einer Reihe mit denen rechts oben, und die tun
 * etwas. Der Pfeil traegt die Aussage, der Name daneben sagt wohin. */
.zurueck {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
  font-size: 0.875rem;
  color: var(--bs-secondary-color);
  text-decoration: none;
}

.zurueck:hover,
.zurueck:focus-visible {
  color: var(--bs-body-color);
  text-decoration: underline;
}

.seitenkopf {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  margin-bottom: 1rem;
}

.seitenkopf-name {
  min-width: 0;
  flex: 1 1 auto;
}

.seitenkopf-name h1 {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}

/* Die Beiwerte unter dem Namen. Dieselbe Reihe mit Trennpunkt wie in der Boxenliste. */
.seitenkopf-lage {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.15rem 0.5rem;
  min-width: 0;
  font-size: 0.9375rem;
  color: var(--bs-secondary-color);
}

/* Der Trennpunkt der Reihe steht bei der Boxenliste, beide teilen ihn sich. */

.seitenkopf-knoepfe {
  display: flex;
  flex: 0 0 auto;
  gap: 0.5rem;
}

/* Der mitlaufende Zaehler bricht nicht um. "vor 1 min 9 s" auf zwei Zeilen mit einem einzelnen
   "s" unten sah aus wie ein Fehler. */
.frischezaehler {
  white-space: nowrap;
}

/* --- Schmale Bildschirme ---------------------------------------------------------------------

   Am 29.08.2026 beauftragt: "optimiere die mobile ansicht des portals." Nachgesehen wurde bei
   375 Bildpunkten, der Breite eines iPhone im Hochformat. Was dabei auffiel, steht hier, jeweils
   mit dem Befund davor.

   Der Ort dafuer ist diese eine Stelle und nicht jede Vorlage. Eine Regel, die an einer Vorlage
   haengt, gilt fuer die naechste nicht mehr, und dann sieht wieder jede Seite anders aus. */

@media (max-width: 767.98px) {

  /* **Die Reiter der Boxseite brachen auf drei Zeilen um.** Acht Reiter zu je rund 130
     Bildpunkten passen nicht in 375, und umgebrochen frassen sie 220 Bildpunkte, bevor der erste
     Inhalt kam. Sie standen deshalb bis zum 14.09.2026 in einer Reihe, die gewischt wird.

     **Gewischt wird nicht mehr.** Am 14.09.2026 verlangt: "horizontales scrolling muss verhindert
     werden, auch bei den tabs." Eine Reihe, die aus dem Bild ragt, verbirgt ihre eigenen
     Schaltflaechen, und ob jemand den Reiter Wartung findet, haengt daran, wie weit er gezogen
     hat.

     Stattdessen faellt der Text der nicht gewaehlten Reiter weg. Das Zeichen und die Zahl
     bleiben, und der offene Reiter behaelt seinen Namen. Damit steht in einer Zeile, wo man ist
     und was es sonst gibt. Zehn Reiter zu je rund 44 Bildpunkten passen so in 375, und reicht es
     doch nicht, bricht die Reihe um, statt zu verschwinden.

     Voraussetzung ist, dass der Name in einer eigenen Huelle steht, siehe `reitername` in
     templates/_reiterreihe.html. Ein Reiter ohne Zeichen behaelt seinen Text, sonst bliebe eine
     leere Flaeche stehen. */
  .nav-tabs {
    display: flex;
    flex-wrap: wrap;
    overflow-x: visible;
    max-width: 100%;
  }

  .nav-tabs .nav-link {
    white-space: nowrap;
  }

  /* Unsichtbar und nicht weg: der Name bleibt fuer Vorleseprogramme der Name des Reiters. Mit
     display: none stand dort am 18.10.2026 ein Knopf ohne Namen, siehe Lighthouse button-name. */
  .nav-tabs .nav-link:not(.active):not(.dropdown-toggle) > .fas + .reitername {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  /* Ohne Text stuende das Zeichen mit seinem Abstand nach rechts allein da. Die Marke daneben
     behaelt ihren, sie braucht die Luft zum Zeichen. */
  .nav-tabs .nav-link:not(.active):not(.dropdown-toggle) > .fas.me-2 {
    margin-right: 0 !important;
  }

  /* Das Menue rueckt an die anderen heran. Der Abstand nach links trennt auf einer breiten Reihe
     das Arbeiten vom Nachsehen. Auf einer umgebrochenen Reihe schoebe er es allein in eine zweite
     Zeile, und dann trennt er nichts mehr. */
  .nav-tabs > .nav-item.dropdown.ms-auto {
    margin-left: 0 !important;
  }

  /* **Tabellen mit vielen Spalten.** Sie werden gewischt, siehe oben. Enger gesetzt passt eine
     Spalte mehr ins Bild, bevor ueberhaupt gewischt werden muss. */
  .card .table > tbody > tr > td,
  .card .table > thead > tr > th {
    padding-left: 8px;
    padding-right: 8px;
  }

  .card .table > tbody > tr > td {
    font-size: 0.8125rem;
  }

  /* **Der Anteilsbalken in "Nach Jahr" war ein Punkt.** Am 07.09.2026 beanstandet. In der
     Tabelle stehen vier Zahlenspalten und dazwischen der Balken. Gemessen bei 375 Bildpunkten:
     die Zahlen belegen 333 der 351 verfuegbaren, weil jede Spalte so breit wird wie ihre
     Kopfzeile und nicht wie ihre Zahl. Fuer den Balken blieben 24 Bildpunkte uebrig, und drei
     Auftraege von zehn sind davon sieben. Das ist ein Punkt und keine Auskunft.

     Eine feste Mindestbreite haette es nicht geloest, sie haette nur die Tabelle ueber den Rand
     geschoben: ein Balken, den man erst herwischen muss, vergleicht nichts mehr.

     Der Balken verlaesst deshalb die Zeile und legt sich als Strich darunter, ueber die ganze
     Breite. Der Anteil kommt als --anteil an der Zeile an, ::before ist die Rinne und ::after
     die Fuellung. Ab 768 Bildpunkten steht er wieder als Spalte zwischen den Zahlen.

     Gezeichnet wird an der ersten Zelle und nicht an der Zeile. Ein Pseudoelement an einem tr
     bekommt vom Browser eine anonyme Tabellenzelle untergeschoben, und die verbreitert die
     Tabelle um zwei Spalten. Erst gemessen, dann verschoben. Die Zeile ist nur der Bezugspunkt:
     sie steht auf relative, deshalb spannt der Strich ueber ihre ganze Breite. */
  .jahrtabelle > thead > tr > th.jahrbalken,
  .card .jahrtabelle > tbody > tr > td.jahrbalken {
    display: none;
  }

  .jahrtabelle > tbody > tr {
    position: relative;
  }

  .card .jahrtabelle > tbody > tr > td {
    padding-bottom: 0.85rem;
  }

  .jahrtabelle > tbody > tr > td:first-child::before,
  .jahrtabelle > tbody > tr > td:first-child::after {
    content: "";
    position: absolute;
    left: 8px;
    bottom: 6px;
    height: 3px;
    border-radius: 2px;
  }

  .jahrtabelle > tbody > tr > td:first-child::before {
    right: 8px;
    background-color: var(--cube-field);
  }

  .jahrtabelle > tbody > tr > td:first-child::after {
    width: calc((100% - 16px) * var(--anteil, 0) / 100);
    background-color: var(--bs-primary);
  }

  /* **Eine Tabelle mit einer langen Textspalte ist auf einem Telefon keine Tabelle.**
     Im Portalprotokoll standen vier Spalten, und die vierte trug den eigentlichen Satz. Bei 375
     Bildpunkten lag genau die ausserhalb des Bildes, waehrend die Zeile ihre Hoehe trotzdem
     danach bemass. Sichtbar waren drei kurze Angaben und viel Leere.

     Eine Zeile wird deshalb zur Karte. Die Kopfzeile faellt weg, die kurzen Angaben stehen
     nebeneinander, und was mit data-breit ausgezeichnet ist, bekommt eine eigene Zeile darunter.
     Beschriftungen braucht es dafuer keine: eine Uhrzeit, eine Marke und ein Boxname sagen von
     selbst, was sie sind.

     Zahlenraster wie in der Statistik bleiben Tabellen. Dort traegt die Kopfzeile die Bedeutung,
     und ohne sie waeren die Zahlen wertlos. Die werden gewischt, siehe oben. */
  .table-stapelbar > thead {
    display: none;
  }

  .table-stapelbar > tbody > tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.75rem;
    padding: 0.7rem 0.75rem;
    box-shadow: inset 0 -1px 0 var(--cube-ring-soft);
  }

  .table-stapelbar > tbody > tr:last-child {
    box-shadow: none;
  }

  .card .table-stapelbar > tbody > tr > td {
    display: block;
    width: auto;
    border: 0;
    padding: 0;
  }

  .card .table-stapelbar > tbody > tr > td[data-breit] {
    flex: 1 1 100%;
  }

  /* **Der Name eines Events war auf drei Silben zusammengeschnitten.** Er stand neben dem
     Freigabeblock, und der brauchte 180 der 375 Bildpunkte fuer sich. Untereinander bekommt
     jeder, was er braucht.

     Der Freigabeblock selbst ist seit dem 05.09.2026 aus der Liste heraus, mit ihm die Regel
     .eventzeile-freigabe. Der Umbruch bleibt: die Zeile traegt jetzt den Verlauf. */
  .eventzeile {
    flex-wrap: wrap;
  }

  /* Der Verlauf steht auf einem Telefon nicht rechts, sondern unter dem Namen. Nebeneinander
     bliebe von "2026-08-28_Felicia-und-Timo" nichts uebrig.

     Die ganze Zeilenbreite und nicht die natuerliche: ohne `flex-basis` nimmt das Band seine
     Wunschbreite und schiebt die letzten Stationen aus der Karte heraus. Mit ihr kuerzt es die
     Namen der Stationen, siehe .standband li. */
  .eventzeile > a {
    flex-wrap: wrap;
  }

  .eventverlauf {
    flex: 1 1 100%;
    min-width: 0;
    margin-left: 0;
  }

  /* Abschneiden hat auf einer Seite ohne Nachbarspalte keinen Zweck mehr. Was nicht in die Zeile
     passt, bricht um, statt hinter drei Punkten zu verschwinden. */
  .eventzeile .text-truncate {
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
  }

  /* **Der Ladehinweis lag ueber dem Knopf fuer die Navigation.** Beide sitzen fest an der oberen
     rechten Ecke. Unten ist er ohnehin naeher am Daumen. */
  .ladezeichen {
    top: auto;
    bottom: 1rem;
    right: 50%;
    transform: translateX(50%);
  }

  /* **Fingerbreite.** Ein Knopf von 28 Bildpunkten Hoehe trifft man auf einem Touchscreen nur
     mit Glueck. Die Empfehlung liegt bei 44, das sprengt hier die Zeilen, 38 sind der Kompromiss
     zwischen Treffsicherheit und einer Karte, die noch aufs Bild passt. */
  .btn-sm {
    --bs-btn-padding-y: 0.375rem;
    --bs-btn-padding-x: 0.75rem;
    min-height: 2.375rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* **Die Oberflaeche der Box in einem Rahmen.** 78 Prozent der Fensterhoehe sind auf einem
     Telefon fast die ganze Seite, und darueber steht schon der Kopf. Etwas weniger laesst
     erkennen, dass die Seite weitergeht. */
  .oberflaechenrahmen {
    height: 62vh;
    min-height: 320px;
  }

  .terminalrahmen {
    height: 55vh;
    min-height: 280px;
  }

  /* Der Wartehinweis brauchte hier eine eigene Lage, solange er mittig am unteren Rand sass. Seit
     dem 09.09.2026 steht er in der Toastecke, und die bringt ihre Ränder selbst mit. */
}

/* Auf einem Bildschirm, der mit dem Finger bedient wird, bekommen auch die kleinen Ziele in den
   Kacheln der Galerie Platz. Gemessen wird am Zeigegeraet und nicht an der Breite: ein Tablet im
   Querformat ist breit und wird trotzdem angetippt. */
@media (pointer: coarse) {
  .stueck {
    padding: 0.4rem;
  }

  .kachelzeile {
    gap: 0.5rem;
  }
}

/* Die Ablage fuer die Bilder eines Events. Bewusst eine eigene Klasse und nicht [data-ablage]:
   das damalige bildteile.js griff sich mit document.querySelector("[data-ablage]") das erste
   Element dieser Art, und die Bildteile-Karte stand auf derselben Seite weiter oben. Zwei Ablagen
   mit demselben Merkmal haetten sich gegenseitig die Ereignisse weggenommen. Die zweite gibt es
   seit dem 10.09.2026 nicht mehr, die eigene Klasse bleibt: sie beschreibt, was sie ist. */
.ablage {
  transition: box-shadow 0.12s ease, background-color 0.12s ease;
}

.ablage.ablage-offen {
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 2px var(--bs-primary);
}

/* --- Vorlagen-Editor --------------------------------------------------------------------------
   Hintergrund, Rahmen, Logo und Text einer Vorlage auf einer Flaeche, im Bedienbild eines
   Aufkleber-Editors: eine Marke wird gezogen, am Punkt oben gedreht, am Punkt unten rechts
   skaliert, ein Doppelklick auf Text schreibt hinein. */
/* Die Bühne: der Platz, den die Fläche bekommt, und die Rollbalken, wenn sie darüber hinauswächst.

   Am 13.09.2026 beanstandet: "der designe zeigt die beim steifen die bilder viel zu gross an weil
   nach breite skaliert wird. das muss ich ändern. man kann die vorlagenansicht nicht vergroessern
   und auch nicht die volle bildschirmbreite nutzen."

   Die Fläche stand auf der Breite ihrer Spalte, die Höhe kam aus dem Format der Rolle. Das geht
   auf, solange das Format breiter als hoch ist. Beim Streifen (602 zu 1804) wurden aus 700
   Bildpunkten Breite 2100 in der Höhe, also drei Bildschirme voll für eine Fläche.

   Gerechnet wird jetzt aus der Höhe. Die Fläche bekommt die Breite, die bei der erlaubten Höhe
   herauskommt, höchstens aber die der Bühne. Ein Hintergrund (1920 zu 1080) bleibt damit so breit
   wie vorher, ein Streifen passt ins Bild. */
.editor-buehne {
  /* Wie hoch die Fläche höchstens sein darf. Der Wert hier gilt ohne Skript. Sonst misst
     vorlageneditor.js, was unter der Oberkante der Bühne wirklich im Fenster steht, und setzt ihn
     an jeder Bühne: über ihr stehen Seitenkopf, Werkzeugleiste und die Reiterreihe, und wie hoch
     die zusammen sind, hängt an der Fensterbreite. */
  --buehne-hoehe: max(480px, 70vh);
  max-height: var(--buehne-hoehe);
  overflow: auto;
  display: flex;
  border-radius: 10px;
  /* Ein Rollbalken, der beim Vergrößern erscheint, soll die Fläche nicht im selben Augenblick
     schmaler rechnen und damit wieder verschieben. */
  scrollbar-gutter: stable;
}

/* Die Fläche selbst ist ein CSS-Containment, damit die Schriftgroesse einer Ebene (in cqw,
   Bruchteil der Flaechenbreite) bei jeder Bildschirmbreite mitwaechst, ohne dass ein Skript bei
   jedem Grössenwechsel nachrechnen muss. */
.editor-flaeche {
  position: relative;
  /* Nicht schrumpfen und nicht wachsen: die Breite steht hier und nicht im Flexverteiler. */
  flex: none;
  /* Zentriert, und zwar so, dass eine übergroße Fläche oben und links erreichbar bleibt.
     `justify-content: center` schneidet in diesem Fall den Anfang ab. */
  margin: auto;
  /* `--fb` und `--fh` sind das Mass der Rolle, siehe bestand.FLAECHENMASS und editor.html.
     `--ansicht` ist der Faktor der Leiste über der Bühne, Vorgabe 1: eingepasst. Die vier
     Bildpunkte Abzug halten den waagerechten Rollbalken weg, der sonst bei genauer Passung
     erscheint und den senkrechten nach sich zieht. */
  width: calc(var(--ansicht, 1) * min(100%, (var(--buehne-hoehe) - 4px) * var(--fb) / var(--fh)));
  aspect-ratio: var(--fb) / var(--fh);
  border-radius: 10px;
  overflow: hidden;
  background-color: #fff;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  container-type: inline-size;
  /* Ohne das liest ein Ziehen auf einem Touchscreen als Bildlaufgeste, und die Marke bleibt
     stehen, waehrend die Seite scrollt. */
  touch-action: none;
}

/* Kleiner, größer, einpassen. Sie steht über der Bühne und gilt für die Fläche darunter: jede
   Rolle hat ein eigenes Format, ein gemeinsamer Faktor für alle vier wäre für drei davon falsch. */
.editor-ansichtsleiste {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.editor-ansichtwert {
  min-width: 4.5ch;
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--bs-secondary-color);
}

/* Das Grundbild liegt seit dem 08.09.2026 als Ebene auf der Flaeche und bestimmt sie nicht mehr.
   Breite und Mitte kommen als eigene Werte aus dem Skript, gerechnet in Anteilen der Flaeche, und
   dieselben drei Zahlen brennt der Server spaeter in das Bild, siehe ebenen.grundbild_lage. */
.editor-flaeche img.editor-grundbild {
  display: block;
  position: absolute;
  /* `left` und `top` messen in der Flaeche, `translate` im Bild selbst. Zusammen heisst das:
     die Mitte des Bildes liegt auf (x, y) der Flaeche. Ohne Skript und ohne Umrechnung in
     Bildpunkte, es bleibt also auch bei jeder Bildschirmbreite richtig. */
  left: calc(var(--grund-x, 0.5) * 100%);
  top: calc(var(--grund-y, 0.5) * 100%);
  width: calc(var(--grund-breite, 1) * 100%);
  height: auto;
  /* Die Drehung kam am 10.09.2026 dazu: der Hintergrund ist seither eine Bildebene wie jede
     andere und kann alles, was die anderen koennen, siehe ebenen._grundebene. */
  transform: translate(-50%, -50%) rotate(var(--grund-drehung, 0deg));
  pointer-events: none;
  /* Nur die Vorgabe. Auf welcher Stufe der Hintergrund wirklich liegt, setzt das Skript, siehe
     zIndex in static/js/vorlageneditor.js. */
  z-index: 10;
}

/* Ohne gewaehltes Bild steht die Flaeche leer da, mit derselben Aufforderung wie eine leere
   Bildteil-Reihe im Formular: hochladen oder aus dem Bestand waehlen. Das Seitenverhaeltnis
   kommt aus dem Mass der Rolle und steht im Formatattribut, siehe editor.html. */
.editor-flaeche.editor-leer {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--bs-tertiary-color);
  background-color: var(--cube-surface-2);
}

/* Waehrend die Pipette auf einen Klick wartet, siehe farbeAusBildAufnehmen. */
.editor-flaeche.faerbt {
  cursor: crosshair;
}

/* Solange das Grundbild gezogen wird. */
.editor-flaeche.schiebt {
  cursor: grabbing;
}

/* Die erfundenen Aufnahmen, eingeblendet ueber den Schalter oben. Am 04.09.2026 verlangt: "ich
   kann beim editieren einer collage zb, nicht wie gefordert mit einem switch das beispielbild
   drueberlgen um zu sehen was verdeckt wird."

   Bis zum 08.09.2026 lag hier das fertige Beispielbild aus dem Bestand, also Rahmen und Aufnahmen
   in einem Stueck. Das passte nicht mehr, sobald das Grundbild verschiebbar wurde, und beim
   Streifen passte es nie: dort war es der verdoppelte Druckbogen. Jetzt sind es nur die
   Aufnahmen, auf durchsichtigem Grund und in der Groesse der Flaeche, siehe bestand.auflage.

   Sie liegen ueber dem Rahmen oder darunter, so wie auf der Box. Ohne den Schalter sind sie nicht
   da, nicht nur durchsichtig: ein unsichtbares Bild ueber der Flaeche finge Klicks der Pipette
   ab. */
.editor-auflage {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  pointer-events: none;
}

.editor-auflage-unter { z-index: 0; }
.editor-auflage-ueber { z-index: 2; }

.editor-flaeche.zeigt-beispiel .editor-auflage {
  display: block;
}

/* Die Lage des Grundbildes: Schieber und zwei Knoepfe, direkt unter der Flaeche. */
.editor-grundleiste {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.editor-grundleiste .form-range {
  flex: 1 1 auto;
  min-width: 4rem;
}

.editor-grundleiste [data-grundwert] {
  min-width: 3.5rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Waehrend der Probe steht auf der Flaeche der gefuellte Text und nicht der gespeicherte.
   Bearbeitet wird er dann nicht, siehe textMarkeBauen. */
.editor-flaeche.probelauf .editor-inhalt-text {
  cursor: default;
}

/* Die Stapelreihenfolge auf der Flaeche, von unten nach oben: die Auflage, die unter den Rahmen
   gehoert (0), das Grundbild (1), die Auflage, die darueber gehoert (2), Bedienleiste und
   Hochkant-Ausschnitt (3), das Raster (4), und ganz oben die Marken. Sie bleiben greifbar,
   gleich was gerade eingeblendet ist. */
.editor-marke {
  position: absolute;
  z-index: 5;
  cursor: grab;
  user-select: none;
  /* Ohne das haengt die Breite einer Textmarke am freien Platz bis zum rechten Rand der
     Flaeche, nicht an ihrem eigenen Inhalt: mit nur "left" gesetzt rechnet ein Absatz seine
     Schrumpfbreite aus dem verbleibenden Raum, und nahe am rechten Rand wird sie schmaler und
     bricht um, obwohl an Text und Schrift nichts geaendert wurde. Beanstandet am 03.09.2026:
     "wenn man das textfeld verschiebt veraendert sich die breite des textfelds". Ein Bild setzt
     seine Breite ohnehin per Inline-Stil, der sticht diese Regel. */
  width: max-content;
}

.editor-marke:active {
  cursor: grabbing;
}

/* Der Text steht in seiner echten Schrift, Groesse und Farbe direkt auf der Flaeche, kein
   Platzhalter-Etikett mehr. --sg ist der Bruchteil der Flaechenbreite, je Marke gesetzt. Ein
   feiner gestrichelter Rahmen macht die sonst unsichtbare Klickflaeche greifbar, ohne im Weg zu
   stehen: er verschwindet beim Drucken der fertigen Vorlage laengst, hier ist er Werkzeug. */
.editor-inhalt-text {
  padding: 0.15em 0.4em;
  border-radius: 4px;
  border: 1px dashed rgba(255, 255, 255, 0.35);
  white-space: pre-wrap;
  font-size: calc(var(--sg, 0.08) * 100cqw);
  line-height: 1.15;
  outline: none;
  min-width: 1.5em;
  /* Der Umriss gehoert unter die Fuellung. Ohne paint-order legt der Browser ihn darueber und
     frisst die halbe Strichstaerke von innen weg, waehrend Pillow beim Brennen aussen bleibt. */
  paint-order: stroke fill;
}

.editor-inhalt-text[contenteditable="true"] {
  cursor: text;
  border-color: var(--bs-primary);
  background-color: rgba(255, 255, 255, 0.08);
}

.editor-marke-bild {
  width: 100%;
  border-radius: 6px;
  border: 1px dashed rgba(255, 255, 255, 0.65);
  box-shadow: 0 0 0 2px rgba(20, 22, 26, 0.35);
}

.editor-marke-bild img {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
}

.editor-marke.aktiv .editor-inhalt-text,
.editor-marke.aktiv .editor-marke-bild {
  border-style: solid;
  border-color: var(--bs-primary);
  box-shadow: 0 0 0 2px rgba(62, 99, 221, 0.45);
}

/* Die Griffe: ein Punkt oben zum Drehen, ein Punkt unten rechts zum Skalieren. Nur an der
   ausgewaehlten Marke zu sehen, sonst waere die Flaeche bei mehreren Ebenen ein Punktefeld. */
.editor-griffe {
  display: none;
}

.editor-marke.aktiv .editor-griffe {
  display: block;
}

.editor-griff {
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background-color: var(--bs-primary);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85);
  touch-action: none;
}

.editor-griff-drehen {
  top: -28px;
  left: 50%;
  transform: translateX(-50%);
  cursor: grab;
}

.editor-griff-drehen::before {
  content: "";
  position: absolute;
  top: 16px;
  left: 50%;
  width: 1px;
  height: 12px;
  background-color: rgba(255, 255, 255, 0.6);
}

.editor-griff-drehen:active {
  cursor: grabbing;
}

.editor-griff-groesse {
  bottom: -8px;
  right: -8px;
  cursor: nwse-resize;
}

/* Die Liste steht seit dem 03.09.2026 neben der Flaeche und nicht mehr darunter, beide zusammen
   mit dem Design sichtbar. Jede Ebene traegt, was sich schlecht ziehen laesst: Schriftart,
   Ausrichtung, Farbe, dazu Schriftgroesse und Drehung als genaue Zahl neben dem Griff auf der
   Flaeche. Eine eigene Flaeche pro Zeile haelt mehrere Ebenen in der schmaleren Spalte
   auseinander, sonst liefen sie zu einem Block zusammen. */
.ebene-zeile {
  padding: 0.6rem;
  border-radius: 8px;
  background-color: var(--cube-surface-2);
}

/* Die Wahl fuer eine neue Bildebene. Sie steht zu, bis der Knopf "+ Bild" sie oeffnet, siehe
   static/js/vorlageneditor.js, und hebt sich als eigener Kasten von der Liste darunter ab. */
.bildwahlkasten {
  padding: 0.6rem;
  border-radius: 8px;
  background-color: var(--cube-surface-2);
}

/* Bildformat, Aufloesung und Seitenverhaeltnis ueber den Kacheln, seit dem 13.10.2026, siehe
   bestand.bildvorgabe. Eine Zeile, die auf schmalem Schirm umbricht. */
.bildvorgabe {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1.25rem;
  margin: 0 0 0.6rem;
  font-size: 0.8rem;
}

.bildvorgabe div {
  display: flex;
  gap: 0.4rem;
}

.bildvorgabe dt {
  font-weight: 400;
  color: var(--bs-secondary-color);
}

.bildvorgabe dd {
  margin: 0;
}

.ebene-zeile + .ebene-zeile {
  margin-top: 0.5rem;
}

.ebene-zeile.aktiv {
  box-shadow: 0 0 0 1px var(--bs-primary);
}

/* --- Die Karte fuer den Ort ------------------------------------------------------------------
   Kacheln von OpenStreetMap, ein Fadenkreuz in der Mitte, zwei Zoomknoepfe. Das Programm liegt
   unter static/js/karte.js, dort steht auch, warum es keine Kartenbibliothek gibt. */
.karte {
  position: relative;
  height: 260px;
  border-radius: 10px;
  overflow: hidden;
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  cursor: grab;
  /* Ohne das liest ein Ziehen auf einem Touchscreen als Bildlaufgeste. */
  touch-action: none;
  user-select: none;
}

.karte.zieht {
  cursor: grabbing;
}

.karte-kacheln {
  position: absolute;
  inset: 0;
}

.karte-kacheln img {
  position: absolute;
  width: 256px;
  height: 256px;
  pointer-events: none;
}

/* Der Punkt liegt immer in der Mitte. Ein Kreuz und kein Stecknadelkopf: die Spitze einer Nadel
   sitzt am unteren Ende, und wer sie mittig legt, trifft den Ort um ihre halbe Hoehe daneben. */
.karte-fadenkreuz {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  border: 2px solid #fff;
  background-color: rgba(var(--bs-primary-rgb), 0.75);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45);
  pointer-events: none;
}

.karte-knoepfe {
  position: absolute;
  right: 0.5rem;
  top: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.karte-knoepfe .btn {
  width: 2rem;
  padding: 0 0.25rem;
  font-weight: 700;
  line-height: 1.6;
}

/* Die Namensnennung verlangt die Lizenz der Kartendaten. Sie steht deshalb auf der Karte und
   nicht in einem Impressum. */
.karte-quelle {
  position: absolute;
  right: 0;
  bottom: 0;
  padding: 0.1rem 0.4rem;
  font-size: 0.7rem;
  color: #333;
  background-color: rgba(255, 255, 255, 0.75);
  border-top-left-radius: 6px;
  pointer-events: none;
}

/* --- Die Karte mit der Spur einer Box --------------------------------------------------------
   Am 07.09.2026 dazugekommen. Sie zeigt, wo die Box steht und wo sie war, und sie laesst sich nur
   ansehen. Das Programm liegt unter static/js/ortungskarte.js.

   Gezeichnet wird auf eine Leinwand und nicht in Bildelemente wie bei der Eventkarte. Der Grund
   ist die Spur: eine Linie durch zweihundert Punkte ist auf einer Leinwand ein Zug und in HTML
   zweihundert gedrehte Kaestchen. */
.ortungskarte {
  position: relative;
  height: 300px;
  border-radius: 10px;
  overflow: hidden;
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  cursor: grab;
  /* Ohne das liest ein Ziehen auf einem Touchscreen als Bildlaufgeste. */
  touch-action: none;
  user-select: none;
}

.ortungskarte:active {
  cursor: grabbing;
}

.ortungskarte canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.ortungskarte-knoepfe {
  position: absolute;
  right: 0.5rem;
  top: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.ortungskarte-knoepfe .btn {
  width: 2rem;
  padding: 0 0.25rem;
  font-weight: 700;
  line-height: 1.6;
}

/* Die Trefferliste der Ortssuche. Sie rollt senkrecht, nicht waagerecht: die Regel vom
   04.09.2026 gilt Bildern, und hier stehen Zeilen. */
.ortstreffer {
  max-height: 12rem;
  overflow-y: auto;
}

/* Das Bild in der Lupe, siehe "Bild gross" in static/js/portal.js. Es fuellt die Breite, wird
   aber nicht ueber die Bildschirmhoehe hinaus gezogen: ein Collagerahmen ist 1800 Bildpunkte
   hoch, und dann stuende der Schliessknopf ausserhalb des Sichtbaren. */
/* Die Flaeche, auf der das Bild und die beiden Pfeile liegen. Am 14.09.2026 verlangt: "die
   bildervorschau soll pfeile bekommen um das naechste zu oeffnen und das soll auch mit der
   links/rechts pfeiltaste gehen."

   Die Pfeile liegen ueber dem Bild und nicht darunter. Wer durch hundert Bilder blaettert, laesst
   den Zeiger stehen, und ein Knopf unter dem Bild wanderte mit jedem Hochformat weg. */
.lupenflaeche {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 12rem;
}

.lupenpfeil {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 3rem;
  height: 3rem;
  border: 0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  color: #fff;
  background: rgba(0, 0, 0, 0.55);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}

.lupenpfeil:hover {
  background: rgba(0, 0, 0, 0.8);
}

/* Am Anfang und am Ende der Reihe abgeblendet und nicht weg. Ein Knopf, der verschwindet,
   verschiebt das Bild darunter. */
.lupenpfeil:disabled {
  opacity: 0.25;
}

.lupenpfeil-links { left: 0.5rem; }
.lupenpfeil-rechts { right: 0.5rem; }

/* Die Stelle in der Reihe, im Kopf neben dem Dateinamen. Damit ist beim Blaettern zu sehen, wie
   weit es noch ist. */
.lupenstelle {
  font-variant-numeric: tabular-nums;
  color: var(--bs-secondary-color);
}

.lupenbild {
  max-width: 100%;
  max-height: 75vh;
  object-fit: contain;
  /* Ein Rahmen mit Alphakanal ist auf dunklem Grund nicht zu sehen. Die Lupe zeigt ihn deshalb
     auf Weiss, so wie er spaeter auf dem Papier liegt. */
  background-color: #fff;
  border-radius: 8px;
}

/* --- Die Bedienleiste der Box auf dem Hintergrund ---------------------------------------------
   Am 04.09.2026 verlangt: "der hintergrund muss wie bei der collage die icons unten anzeigen
   (ausgerichtet auf 1920x1080)."

   **Am 08.09.2026 an der Box gemessen und dabei verworfen, was hier stand.** Beanstandet: "die
   buttons die beim hintergrund gezeigt werden sind weder die die es bei der fotobox sind (kein
   preview) noch stimmt die position und groesse wie bei einem 1920x1080 monitor wie wir sie im
   einsatz haben. der gallerie button fehlt auch."

   Die Werte davor waren aus Photobooths `framework.css` gerechnet und lagen um mehr als das
   Dreifache daneben: der Fork legt eigene Knoepfe darueber (`btb-button`), und die stehen in
   dieser Rechnung nicht.

   **Am 16.09.2026 neu gemessen: zwei Knoepfe, und sie liegen in einer Nische.** Seither waehlt
   der Gast das Format erst hinter dem Collage-Knopf, der dritte Startknopf "Streifen" ist
   entfallen. Dazu kam am 12.09.2026 die Nische, ein halbdurchsichtiges Feld, das die Knoepfe
   einfasst. Sie ist hier das Wichtigste: verdeckt wird nicht mehr nur das Band unter den
   Knoepfen, sondern das ganze Feld darum.

   Gemessen im Entwicklungscontainer am Stand btb-neu, bei genau 1920 mal 1080:

     Nische          671 x 281, mittig, 44 ueber dem unteren Rand, Radius 26
     Aufnahmeknopf   292 x 229, zwei Stueck, 26 Abstand, mittig in der Nische
     Vorschaufeld    240 x 160 im Knopf, 26 von links und 17 von oben
     Galerie         150 x 64, oben links bei 32 / 32
     Platte          rgb(243, 244, 246), Radius 12
     Nische          rgb(18, 20, 26) mit 12 Prozent Deckung

   Die Werte davor (320 x 243, drei Stueck, 8 Abstand, 32 ueber dem Rand) stammten vom 08.09.2026
   von fotobox5 und galten fuer die Leiste ohne Nische.

   Dieselben Zahlen stehen in beispielbild.py fuer die gezeichnete Fassung in den Kacheln.

   **Prozent und nicht cqh.** `.editor-flaeche` traegt `container-type: inline-size`, und das
   stellt nur einen Container fuer die Inline-Achse. `cqh` faellt dort auf den Sichtbereich
   zurueck und liefert Unsinn. Senkrechte Masse stehen deshalb als Prozent (die Flaeche ist der
   umgebende Block), waagerechte als Prozent oder cqw. */
.editor-bedienleiste {
  display: none;
  position: absolute;
  left: 50%;
  translate: -50% 0;
  bottom: 4.074%;          /* 44 von 1080 */
  width: 34.948%;          /* 671 von 1920 */
  height: 26.019%;         /* 281 von 1080 */
  border-radius: 1.354cqw; /* 26 von 1920. cqw und nicht Prozent: ein Prozentwert liefe auf beiden
                              Achsen getrennt und zoege die Ecke zu einer Ellipse. */
  background-color: rgba(18, 20, 26, 0.12);
  justify-content: center;
  align-items: center;
  gap: 3.875%;             /* 26 von 671, also von der Nische und nicht von der Flaeche */
  pointer-events: none;
  z-index: 300;  /* Werkzeug, immer sichtbar: die Ebenen liegen seit dem 10.09.2026 frei zwischen 10 und 208, siehe vorlageneditor.js */
}

.editor-flaeche.zeigt-beispiel .editor-bedienleiste {
  display: flex;
}

/* Die Knoepfe liegen in der Nische, ihre Anteile beziehen sich deshalb auf sie und nicht mehr auf
   die ganze Flaeche. */
.editor-boxknopf {
  position: relative;
  flex: 0 0 43.517%;       /* 292 von 671 */
  height: 81.495%;         /* 229 von 281 */
  display: flex;
  flex-direction: column;
  align-items: center;
  border-radius: 0.625cqw; /* 12 von 1920 */
  background-color: rgb(243, 244, 246);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.22);
  color: #111;
  font-size: 1.1cqw;
  line-height: 1;
  overflow: hidden;
}

/* Das Vorschaufeld im Knopf. Auf der Box liegt darin das Beispielbild der Aufnahmeart, und genau
   dieses Feld fehlte hier ganz. Es nimmt gut zwei Drittel der Knopfhoehe ein. */
.editor-boxknopf-vorschau {
  position: absolute;
  left: 8.904%;            /* 26 von 292 */
  top: 7.424%;             /* 17 von 229 */
  width: 82.192%;          /* 240 von 292 */
  height: 69.869%;         /* 160 von 229 */
  border-radius: 0.313cqw;
  background-color: rgba(206, 206, 206, 0.95);
  box-shadow: inset 0 0 0 1px rgba(120, 120, 120, 0.4);
}

.editor-boxknopf-wort {
  position: absolute;
  left: 8.904%;
  top: 81.2%;              /* unter dem Vorschaufeld, das bei 77,3 Prozent endet */
  width: 82.192%;
  text-align: center;
  /* Die Zeile braucht mehr als die Schrifthoehe. Mit `line-height: 1` schnitt `overflow: hidden`
     die Unterlaenge ab, und aus "Collage" wurde "Collaqe". */
  line-height: 1.25;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: clip;
}

/* Die Galerie steht nicht in der Leiste, sie sitzt oben links fuer sich. */
.editor-galerieknopf {
  display: none;
  position: absolute;
  left: 1.667%;            /* 32 von 1920 */
  top: 2.963%;             /* 32 von 1080 */
  width: 7.8125%;          /* 150 von 1920 */
  height: 5.926%;          /* 64 von 1080 */
  align-items: center;
  justify-content: center;
  border-radius: 0.52%;
  background-color: rgba(248, 248, 248, 0.9);
  box-shadow: inset 0 0 0 1px rgba(120, 120, 120, 0.55);
  color: #111;
  font-size: 0.83cqw;
  line-height: 1;
  pointer-events: none;
  z-index: 300;  /* Werkzeug, immer sichtbar: die Ebenen liegen seit dem 10.09.2026 frei zwischen 10 und 208, siehe vorlageneditor.js */
}

.editor-flaeche.zeigt-beispiel .editor-galerieknopf {
  display: flex;
}

/* --- Was eine hochkant stehende Box sieht ----------------------------------------------------
   Photobooth legt den Hintergrund formatfuellend. Auf 1080x1920 bleibt vom 16:9-Bild der
   mittlere Streifen, und der ist (1080/1920) / (1920/1080) = 31,64 Prozent breit. Aussen liegt
   ein Schleier, damit der Unterschied ins Auge faellt. */
.editor-hochkant {
  display: none;
  position: absolute;
  left: 34.18%;
  width: 31.64%;
  top: 0;
  bottom: 0;
  box-shadow: 0 0 0 100vmax rgba(10, 12, 16, 0.55);
  border-left: 2px dashed rgba(255, 255, 255, 0.85);
  border-right: 2px dashed rgba(255, 255, 255, 0.85);
  pointer-events: none;
  z-index: 300;  /* Werkzeug, immer sichtbar: die Ebenen liegen seit dem 10.09.2026 frei zwischen 10 und 208, siehe vorlageneditor.js */
}

.editor-flaeche.zeigt-hochkant .editor-hochkant {
  display: block;
}

.editor-hochkant-wort {
  position: absolute;
  left: 50%;
  top: 0.6rem;
  transform: translateX(-50%);
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
  background-color: rgba(10, 12, 16, 0.75);
  color: #fff;
  font-size: 0.7rem;
  white-space: nowrap;
}

/* --- Das Raster --------------------------------------------------------------------------------
   Drei senkrechte und drei waagerechte Linien: ein Viertel, die Mitte, drei Viertel. Sie
   erscheinen, solange gezogen wird, und werden kräftig, sobald die Marke eingefangen ist.

   Am 04.09.2026 verlangt, am 05.09.2026 erweitert: "erweitere die raster im editor noch um 1/4
   und 3/4 markern."

   Die Mitte steht stärker als die Viertel. Sechs Linien gleicher Stärke wären ein Gitter, und in
   einem Gitter findet das Auge keine Mitte mehr. Die Stelle steht als `--anteil` am Element
   selbst, damit dieselbe Regel alle drei Linien einer Richtung trägt. */
.editor-mitte {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.1s linear;
  z-index: 310;
}

.editor-flaeche.zieht .editor-mitte {
  opacity: 1;
}

/* Zweifarbig gestrichelt und nicht weiß. Ein Hintergrund im Editor ist ein Foto und kann hell
   oder dunkel sein, und eine weiße Linie verschwindet auf einem hellen Aquarell so vollständig
   wie eine schwarze auf einer Nachtaufnahme. Der Wechsel aus hellen und dunklen Strichen trägt
   auf beidem. Denselben Weg gehen die Hilfslinien in Bildbearbeitungen.

   Die Abstufung liegt in der Deckkraft und nicht in der Farbe: die Mitte steht ganz, die Viertel
   zur Hälfte. */
.editor-rasterlinie {
  position: absolute;
  opacity: 0.5;
}

.editor-rasterlinie-senkrecht {
  left: var(--anteil);
  top: 0;
  bottom: 0;
  width: 1px;
  margin-left: -0.5px;
  background: repeating-linear-gradient(
    to bottom, rgba(255, 255, 255, 0.9) 0 4px, rgba(0, 0, 0, 0.55) 4px 8px
  );
}

.editor-rasterlinie-waagerecht {
  top: var(--anteil);
  left: 0;
  right: 0;
  height: 1px;
  margin-top: -0.5px;
  background: repeating-linear-gradient(
    to right, rgba(255, 255, 255, 0.9) 0 4px, rgba(0, 0, 0, 0.55) 4px 8px
  );
}

.editor-rasterlinie-stark {
  opacity: 1;
}

/* Die eingefangene Linie steht durchgezogen im Akzent. Sie ist die einzige, die gerade etwas
   aussagt, und der Strichwechsel würde diese Aussage nur verwässern. */
.editor-rasterlinie.gefangen {
  opacity: 1;
  background: var(--bs-primary);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
}

/* Die Reiterreihe über den Textblöcken. Sie steht in einer schmalen Spalte neben dem Knopf und
   muss deshalb umbrechen dürfen, statt ihn aus der Zeile zu schieben. */
.textreiter {
  min-width: 0;
  max-width: 100%;
}

.textreiter .nav-link {
  max-width: 11rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8rem;
  padding: 4px 10px;
}

/* Die Nummer vor dem Text. Sie steht zurück: gesucht wird nach dem Text, die Nummer hält nur
   zwei gleich beschriftete Blöcke auseinander. */
.textreiter-nummer {
  opacity: 0.55;
  margin-right: 0.4em;
}

/* Ein Bild, das sich vergroessern laesst, sagt das mit dem Zeiger. Ohne den Hinweis probiert es
   niemand, siehe "Bild gross" in static/js/portal.js. */
[data-grossbild] {
  cursor: zoom-in;
}

/* Die Vorschau eines Bildteils im Design-Block darf hoeher werden als die 74 Bildpunkte, die
   .teilbild sonst zulaesst. Am 04.09.2026 im Browser gesehen: in der flachen Vorgabehoehe lag ein
   3:2-Rahmen als schmaler Streifen, und zu erkennen war daran nichts. Das Verhaeltnis haelt seit
   dem 05.09.2026 .teilbild selbst, hier steht nur noch die Obergrenze. */
img.teilbild-lupe {
  max-height: 150px;
}

/* Ein Bildteil in der Form seiner Flaeche und nicht in der der Datei. Das Formatattribut kommt je
   Rolle aus bestand.FLAECHENMASS, `cover` schneidet mittig wie der Editor bei einem Bild ohne
   eigene Lage. Am 08.09.2026 beanstandet: "seitenverhaeltnis des streifen wird nicht
   beibehalten." */
img.teilbild-flaeche {
  /* Die Hoehe steht fest, die Breite rechnet das Formatattribut. Beides auf `auto` ergibt bei
     einem ersetzten Element mit gesetztem `aspect-ratio` keine Groesse, das Bild verschwindet.
     Genau daran ist die erste Fassung gescheitert. */
  height: 120px;
  width: auto;
  object-fit: cover;
}

/* --- Der Verlauf eines Events ------------------------------------------------------------------
   Hier stand bis zum 15.09.2026 die Kette aus sieben abgerundeten Marken, `.schrittkette`. Sie
   war die Zeichnung der Eventliste, waehrend die Eventseite ihren Stand seit demselben Tag als
   Band im Kopf traegt, siehe `.standband` weiter unten.

   Am 15.09.2026 beanstandet: "das neue fortschrittbalkendesign ist nicht in der event überischt
   umgesetzt worden." Berechtigt: zwei Zeichnungen fuer denselben Weg, und die aeltere stand an
   dem Ort, an dem man sechsunddreissig davon untereinander sieht. Die Liste traegt jetzt
   dasselbe Band, siehe event/_standband.html. Damit ist dieser Abschnitt weggefallen. */

/* Eine Fläche im Editor mit ungespeicherten Änderungen. Gespeichert wird alles auf einmal, oben
   rechts, gearbeitet wird je Reiter. Ohne diese Marke wäre nicht zu sehen, wo etwas liegt, das
   noch nicht gesichert ist. */
.nav-tabs .nav-link.reiter-offen::after {
  content: "•";
  margin-left: 0.35rem;
}


/* --- Das Zeichen im Feld ----------------------------------------------------------------------
   Wie das Kalenderblatt, das der Browser in ein `type="date"` zeichnet: innen rechts, ohne
   Rahmen, ohne Farbe. Am 04.09.2026 verlangt: "ich will genausoeinen button wie beim datum auch."
   Gebraucht wird es für die Uhrzeit, siehe event/_zeiten_felder.html. */
.feld-mit-zeichen {
  position: relative;
}

.feld-mit-zeichen .form-control {
  padding-right: 2.2rem;
}

.feldzeichen {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--bs-secondary-color);
  cursor: pointer;
}

.feldzeichen:hover {
  color: var(--bs-body-color);
}


/* --- Die Marke an der Karte, deren Felder in die Vorlage gehen ---------------------------------
   Fünf Angaben eines Events landen sichtbar auf dem Ausdruck: der Tag, der Anlass mit seinem
   Bindewort und die beiden Namen. Sie füllen die Platzhalter der Textebenen, die aus der Vorlage
   mitgekommen sind, siehe app/ebenen.py und bestand.PLATZHALTER. Anlass und Bindewort füllen
   dabei denselben Platzhalter.

   Sie stehen alle in der Karte Basisdaten, und außerhalb davon gibt es kein Vorlagenfeld mehr.
   Die Marke steht deshalb am Kopf der Karte und gilt für alles darin.

   **Keine Kante mehr am einzelnen Feld.** Am 15.09.2026 verlangt: "die gelbe markierung kommt aus
   den einzelnen eingabefeldern auch wieder raus." Sie sagte fünfmal dasselbe wie die Marke
   darüber, und im Formular blieb kein Feld ohne Farbe.

   Das Gelb kommt aus den Tönen, die das Portal schon führt. */
.feldmarke {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0 0.35rem;
  border: 1px solid var(--ton-gelb-rand);
  border-radius: 0.25rem;
  background: var(--ton-gelb-flaeche);
  color: var(--ton-gelb-schrift);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  vertical-align: 1px;
}


/* --- Der Lesemodus -----------------------------------------------------------------------------
   Am 15.09.2026 verlangt: "arbeite einen edit modus ein. wenn nicht im edit modus sollen die
   felder an der selben stelle bleiben aber nicht mehr in einem eingabefeld."

   Ein Event wird einmal ausgefüllt und danach oft nur angesehen. Die Felder standen dabei offen
   da, und eine Seite aus dreißig Kästen sieht aus wie Arbeit, auch wenn niemand etwas ändern
   will.

   Der Wert steht jetzt an der Stelle seines Feldes, mit demselben Etikett darüber, nur ohne
   Rahmen. Die Höhe hält die Zeile ruhig, damit beim Umschalten nichts springt.

   **Nur am bestehenden Event.** Beim Anlegen gibt es nichts zu lesen, dort ist immer Bearbeitung,
   siehe static/js/eventfelder.js. */
.feldwert {
  min-height: 2.375rem;
  display: flex;
  align-items: center;
  padding-block: 0.375rem;
}

.feldwert-mehrzeilig {
  display: block;
  white-space: pre-wrap;
}

.feldwert-leer {
  color: var(--bs-secondary-color);
}

.feldwert-gross {
  font-size: 1.125rem;
  font-weight: 600;
}


/* --- Name und Datum ----------------------------------------------------------------------------
   Das Ergebnis der Zeile darüber: der Name, unter dem das Event durch das Portal läuft, und der
   Tag, an dem es stattfindet. Eine Linie trennt beide von den Bausteinen, und sie tragen eine
   Stufe mehr Schrift.

   Die Linie sitzt an beiden Spalten und ergibt eine durchgehende Kante, solange sie nebeneinander
   stehen. Brechen sie um, bekommt jede ihre eigene. */
.hauptzeile {
  margin-top: 0.25rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--bs-border-color);
}

/* Im Lesemodus stehen die Bausteine nicht da, und dann trennt die Linie nichts mehr. */
#eventfelder[data-modus="lesen"] .hauptzeile {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.hauptfeld {
  font-size: 1.125rem;
  font-weight: 600;
}


/* --- Die Abschnitte der Karte Zeiten ------------------------------------------------------------
   Die Karte trug bis zum 15.09.2026 eine Reihe aus Tag, Uhrzeit und Ort. Mit Aufbau und Abbau
   sind es zwei Zeiten in einer Karte, und zwei Zeilen Felder ohne Gliederung sind eine Wand. Das
   Etikett ist dasselbe, das das Portal in seinen Fenstern führt, siehe .fensterabschnitt. */
.terminabschnitt {
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--bs-border-color);
}


/* --- Der Kalender am Datumsfeld ------------------------------------------------------------------
   flatpickr bringt sein dunkles Thema mit, und das färbt den gewählten Tag türkis. Im Portal ist
   eine Auswahl blau. Dieselbe Handvoll Regeln, die timepicker-ui-dark.css für die Uhr trägt. */
.flatpickr-day.selected,
.flatpickr-day.selected:hover,
.flatpickr-day.startRange,
.flatpickr-day.endRange {
  background: var(--bs-primary);
  border-color: var(--bs-primary);
  color: #fff;
}

.flatpickr-day.today {
  border-color: var(--bs-primary);
}

.flatpickr-day.today:hover {
  background: var(--bs-primary);
  color: #fff;
}

/* --- Die Uhr in den Farben des Portals ---------------------------------------------------------
   timepicker-ui traegt sein dunkles Thema als CSS-Variablen, siehe vendor/timepicker-ui-dark.css.
   Es ist violett, das Portal ist blau. Am 04.09.2026 beanstandet: "die farbgebung stimmt nicht."

   Ueberschrieben wird an derselben Stelle, nur genauer: `.tp-ui-modal[data-theme="dark"]` sticht
   das `[data-theme=dark]` der Bibliothek, unabhaengig davon, welche Datei zuerst geladen wird. */
/*
   **Deckende Farben und nicht die Flaechen der Karten.** `--cube-surface` ist ein Schleier von
   drei Prozent Weiss, gedacht fuer eine Karte, die mit `backdrop-filter` auf dem Grund der Seite
   liegt. Der Uhr direkt zugewiesen war sie fast durchsichtig, und die Seite schien hindurch. Die
   Werte hier sind deshalb ausgerechnet: der Grund der Seite plus derselbe Schleier, aber als
   feste Farbe. */
.tp-ui-modal[data-theme="dark"] {
  --tp-bg: #232326;
  --tp-surface: #2b2b2f;
  --tp-surface-hover: #35353a;
  --tp-input-bg: #17171a;
  --tp-text: var(--bs-body-color);
  --tp-text-secondary: var(--bs-secondary-color);
  --tp-text-type-time: var(--bs-secondary-color);
  --tp-text-icon: var(--bs-secondary-color);
  --tp-on-surface: var(--bs-body-color);
  --tp-primary: var(--bs-primary);
  --tp-on-primary: #fff;
  --tp-primary-container: var(--bs-primary);
  --tp-on-primary-container: #fff;
  --tp-tertiary-container: var(--bs-primary);
  --tp-on-tertiary-container: #fff;
  --tp-am-pm-active: var(--bs-primary);
  --tp-am-pm-text-selected: #fff;
  --tp-border: rgba(255, 255, 255, 0.12);
  --tp-outline: rgba(var(--bs-primary-rgb), 0.65);
  --tp-hover-bg: #35353a;
  --tp-dropdown-option-bg: #2b2b2f;
  --tp-dropdown-option-text: var(--bs-body-color);
}

/* Die drei Knoepfe passten nicht nebeneinander, seit sie deutsch heissen: "Leeren Abbrechen
   Übernehmen" ist breiter als das Feld, die Reihe lief links aus der Karte heraus, und "Leeren"
   stand daneben statt darin. Beanstandet am 04.09.2026. Kuerzere Woerter loesen es, diese Regel
   sorgt dafuer, dass es auch bei einem laengeren nicht wieder passiert. */
.tp-ui-modal .tp-ui-wrapper-btn {
  max-width: 100%;
  flex-wrap: wrap;
}

/* Die Karte in der Ansicht eines Events. Sie zeigt den Punkt und wird nicht bedient, gezogen wird
   im Formular, siehe event/_ansicht.html. */
.karte-lesen {
  cursor: default;
  pointer-events: none;
}

/* --- Der Ansichtsmodus eines Events -----------------------------------------------------------
   Am 05.09.2026 verlangt: "grundlegend hat die ansicht sich im ansichts und editiermodus nicht zu
   ändern! die felder reichen wenn sie ausgegraut sind."

   Deshalb `fieldset disabled` um dieselben Karten statt einer eigenen Ansichtsvorlage. Zwei
   Fassungen derselben Karten laufen auseinander, und beim Umschalten springt alles.

   Das `fieldset` bringt von Haus aus Rahmen und Innenabstand mit. Beides muss weg, sonst zöge es
   eine Linie um die Karten, die es vorher nicht gab. */
.ansichtsmodus {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* Ein gesperrtes Feld bleibt ein sichtbares Feld: gedaempfte Flaeche, feiner Rand, Text in voller
   Farbe. Bootstraps Vorgabe blendet den Text so weit ab, dass ein eingetragener Name kaum zu
   entziffern ist, und angesehen wird hier vor allem.

   **Es steht bewusst noch da, auch leer.** Bis zum 05.09.2026 lag es flach und randlos auf dem
   Kartengrund, und ein leeres Feld war damit unsichtbar: unter "Ort", "E-Mail" und "Telefon" stand
   nichts, nicht einmal ein Kasten. Beanstandet: "ach komm schon. textfelder kannst du ja wohl
   nicht einfach ausblenden." Ein leeres Feld ist die Auskunft, dass dort nichts eingetragen ist,
   und diese Auskunft braucht eine sichtbare Form.

   Anders als bei den Knoepfen darueber: ein Knopf ohne Wirkung sagt nichts, ein Feld ohne Inhalt
   schon. */
.ansichtsmodus .form-control:disabled,
.ansichtsmodus .form-select:disabled {
  background-color: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring-soft);
  border-color: transparent;
  color: var(--bs-body-color);
  opacity: 1;
}

/* Die Karte wird in der Ansicht nicht gezogen. Sie ist kein Formularfeld, das `fieldset` erreicht
   sie also nicht. */
.ansichtsmodus .karte {
  cursor: default;
  pointer-events: none;
}

/* Ein gesperrter Knopf steht gar nicht erst da. Am 05.09.2026 verlangt: "buttons die nicht
   auswählbar sind sollen auch nicht gezeigt werden!"

   Bis dahin blieben sie stehen und wurden entfaerbt, damit sich der Aufbau zwischen Ansehen und
   Bearbeiten nicht verschiebt. Das galt fuer Felder und gilt dort weiter: ein leeres Feld ist die
   Auskunft, dass nichts eingetragen ist. Ein Knopf ohne Wirkung ist keine Auskunft, er ist ein
   Versprechen, das nicht eingeloest wird.

   Absichtlich `display: none` und nicht `visibility: hidden`: der Platz soll mit weg. Sonst
   klaffen in der Ansicht Luecken, in denen einmal Knoepfe waren. */
.ansichtsmodus .btn:disabled,
.ansichtsmodus .btn.disabled,
.ansichtsmodus label.btn:has(input:disabled) {
  display: none;
}

/* **Kein Zeichen ohne Wirkung.** Am 05.09.2026 verlangt: "es ist kein uhrzeit picker icon nötig
   wenn keine uhrzeit im lesemodus ausgewählt werden kann."

   Dieselbe Regel wie bei den Knöpfen darüber, und aus demselben Grund: das Kalenderblatt, das der
   Browser in ein gesperrtes Datumsfeld zeichnet, nimmt er dort auch weg. Ein Uhrensymbol daneben,
   das nichts öffnet, sagt das Gegenteil.

   Mit dem Zeichen geht der Platz, den es rechts im Feld freihielt. */
.ansichtsmodus .feldzeichen {
  display: none;
}

.ansichtsmodus .feld-mit-zeichen .form-control {
  padding-right: 0.75rem;
}

/* --- Abweichende Einstellungen ------------------------------------------------------------- */

/* Eine Zeile der Abweichungsliste am Eventformular. Neutral gerahmt: hier ist jede gewaehlte
   Zeile eine Abweichung, eine Farbe saegte dieselbe Aussage doppelt. Farbe traegt die Boxseite. */
.parameterzeile {
  position: relative;
  border: 1px solid var(--cube-ring-soft);
  border-radius: 0.5rem;
  padding: 0.6rem 0.75rem;
  background: rgba(255, 255, 255, 0.018);
}
.parameterzeile + .parameterzeile { margin-top: 0.45rem; }
.parameterzeile.gewaehlt {
  border-color: var(--cube-ring);
  background: var(--cube-surface-2);
}

/* **Der Schluessel steht grau in der oberen rechten Ecke.** Am 15.09.2026 verlangt: "der
   parameterkey name soll in grau rechts oben stehen und die kategorie links vor der
   beschreibung."

   Er stand bis dahin in einer eigenen Zeile ueber dem Feld, `.parameterzeile-kopf`, zusammen mit
   der Kategorie. Zwei Kennungen vor der Beschriftung, und beide sagen weniger als sie.

   Freigestellt und nicht in der Reihe: die Zeile beginnt damit wieder mit dem Feld selbst, und
   die Ecke rechts oben ist ohnehin leer. Die Knoepfe stehen unten rechts. Der Platz darunter ist
   reserviert, sonst laeuft eine kurze Beschriftung unter den Schluessel. */
.parameterpfad {
  position: absolute;
  top: 0.55rem;
  right: 0.75rem;
  max-width: 45%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.75rem;
  color: var(--bs-tertiary-color);
}

/* Die Kategorie vor der Beschreibung, siehe box/_feld.html. Etwas heller als der Satz dahinter:
   sie ist die Einordnung und nicht die Auskunft. */
.parameterquelle { color: var(--bs-secondary-color); }

.parameterzeile-leib {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
}
.parametereingabe { flex: 1 1 16rem; min-width: 0; border: 0; padding: 0; margin: 0; }
.parameterzeile-knoepfe { display: flex; align-items: center; gap: 0.5rem; }
.parameterboxwert {
  font-size: 0.8rem;
  color: var(--bs-tertiary-color);
  font-variant-numeric: tabular-nums;
}

/* Gewaehlt heisst Entfernen, nicht gewaehlt heisst Hinzufuegen. Immer nur einer der beiden. */
.parameterzeile [data-abwaehlen] { display: none; }
.parameterzeile.gewaehlt [data-waehlen] { display: none; }
.parameterzeile.gewaehlt [data-abwaehlen] { display: inline-flex; }
/* Der Boxwert steht nur an einer Zeile, die ihn noch nicht ueberschreibt. */
.parameterzeile.gewaehlt .parameterboxwert { display: none; }

/* Eine Einstellung, die ein laufendes Event angepasst hat.
   Der Rahmen liegt um die ganze Zeile und nicht nur um das Feld: beim Rollen ueber 262 Parameter
   im Reiter "Selten gebraucht" findet das Auge die Flaeche und nicht die Marke am rechten Rand.
   Am 08.09.2026 verlangt: "geaenderte einstellungen sollen durch komplette einrahmung kenntlich
   gemacht werden, nicht nur durch den hinweis ... nur da macht es sinn um direkt zu sehen was
   angepasst wurde." */
.einstellungszeile {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.6rem;
}
.einstellung-abweichend {
  border: 1px solid var(--ton-gelb-rand);
  background: var(--ton-gelb-flaeche);
  border-radius: 0.5rem;
  padding: 0.55rem 0.7rem;
  margin: 0.3rem 0;
}

/* Die Netzliste in der Karte "WLAN am Einsatzort". Zwei Spalten statt drei, das Signal steht
   unter dem Namen. Am 10.09.2026 in der Karte gemessen: mit drei Spalten lief die Tabelle in
   einen waagerechten Bildlauf und der Knopf stand abgeschnitten da. */
.netzliste li {
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--bs-border-color);
}

.netzliste li:last-child {
  border-bottom: 0;
}

/* Ohne das laesst ein Flex-Kind sich nicht unter seine Inhaltsbreite druecken, und ein langer
   Netzname schiebt den Knopf aus der Karte. */
.min-w-0 {
  min-width: 0;
}

/* --- Die Kachelwand der Boxuebersicht --------------------------------------------------------
   Am 10.09.2026 verlangt: "die fotobox übersichtseite muss massiv abnehmen und die wichtigesten
   infos zeigen. die kachel soll man anklicken können und ein modal öffnet mit details."

   Eine Kachel ist ein Knopf und sieht aus wie eine Karte. Sie traegt den haarfeinen Ring und den
   Schatten aus der Hausform, siehe .card weiter oben, und keinen eigenen Rahmen. Der Unterschied
   zur Karte ist, dass sie auf einen Klick wartet: sie hebt sich beim Ueberfahren an, und rechts
   oben steht das Zeichen, das sagt, dass dahinter etwas liegt.

   Warum ein <button> und kein <div> mit Klickbehandlung: Tastatur, Vorleser und der Fokusrahmen
   kommen damit von selbst. Ein <div data-bs-toggle> waere fuer alles davon unsichtbar. */
.kachel {
  width: 100%;
  height: 100%;
  min-height: 6rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  text-align: left;
  padding: 0.7rem 0.8rem;
  border: 0;
  border-radius: var(--bs-border-radius-lg);
  color: var(--bs-body-color);
  background-color: var(--cube-surface);
  -webkit-backdrop-filter: var(--cube-blur);
  backdrop-filter: var(--cube-blur);
  box-shadow: var(--cube-shadow-card);
  position: relative;
  transition: background-color 0.12s ease-out, transform 0.12s ease-out;
}

.kachel:hover,
.kachel:focus-visible {
  background-color: var(--cube-surface-2);
}

/* **Eine einzelne Kachel neben Knoepfen.** Am 15.09.2026 verlangt: "der ganze block soll
   zusammengelegt werden mit den bilder statistiken. so dass es nur einen block dafür gibt."

   Die Kachel steht seitdem im Block "Was jetzt zu tun ist" und nicht mehr in einer eigenen Wand
   darunter, siehe event/_schritte.html. Das Raster von Bootstrap gaebe ihr dort die halbe
   Kartenbreite, denn `col-6` rechnet in Zwoelfteln der Reihe. Hier zaehlt nicht der Anteil,
   sondern das Mass: eine Kachel, so breit wie die in der Wand einer Boxseite. */
.kachelreihe-eine {
  flex: 0 0 auto;
  margin: 0;
}

.kachelreihe-eine > [class*="col-"] {
  flex: 0 0 auto;
  width: 11rem;
  padding: 0;
}

/* Nur beim Ueberfahren mit dem Zeiger. Wer mit der Tastatur durch die Wand geht, soll die Kacheln
   nicht springen sehen. */
@media (hover: hover) {
  .kachel:hover {
    transform: translateY(-1px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .kachel {
    transition: none;
  }
  .kachel:hover {
    transform: none;
  }
}

.kachel-kopf {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.75rem;
  line-height: 1.3;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--bs-secondary-color);
  padding-right: 1rem;
}

/* **Das Zeichen in der Ecke.** Dort stand bis zum 11.09.2026 ein Pfeil an jeder Kachel, der
   sagen sollte, dass sich etwas oeffnet. Er ist gestrichen: "diese neuen pfeile sind alle zu
   entfernen." Dass eine Kachel etwas oeffnet, sagt ihr Verhalten beim Ueberfahren.

   An seiner Stelle steht jetzt das gerissene Kettenglied, wenn kein Drucker haengt. Verlangt:
   "link ICON! so wie es vorher in der kachel war soll oben rechts in die ecke. in gelb."

   Die Groesse ist das Mass von 37 Bildpunkten bei 30 Prozent Deckung, am 11.09.2026 aus drei
   Vorschlaegen gewaehlt: "groesse von b1 und deckkraft von b3". Es liegt damit hinter der Zahl
   wie ein Wasserzeichen und verdeckt nichts. */
.kachel-ecke {
  position: absolute;
  top: 0.3rem;
  right: 0.45rem;
  font-size: 2.3rem;
  line-height: 1;
  color: var(--ton-gelb-schrift);
  opacity: 0.3;
  pointer-events: none;
}

.kachel-wert {
  font-size: 1.35rem;
  font-weight: 600;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}

/* Woerter statt Zahlen. "Nicht verbunden" in der Groesse einer Kennzahl sprengt jede Kachel, und
   zwei Kacheln nebeneinander stehen dann verschieden hoch da. */
.kachel-wert-klein {
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.kachel-einheit {
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--bs-secondary-color);
}

/* Der Nachsatz steht unten an der Kante, auch wenn der Wert nur eine Zeile hoch ist. Sonst
   stuenden die Nachsaetze der Wand auf verschiedenen Hoehen. */
.kachel-fuss {
  margin-top: auto;
  padding-top: 0.3rem;
  font-size: 0.78rem;
  line-height: 1.3;
  color: var(--bs-secondary-color);
  overflow-wrap: anywhere;
}

.kachel .progress {
  margin-top: 0.35rem;
}

/* Die Kante faerbt sich, wenn wirklich etwas zu tun ist. Dieselbe Regel wie .karte-warnung weiter
   oben, nur an einer Kachel. Ausdruecklich sparsam: eine Wand, in der die Haelfte gelb ist, sagt
   nichts mehr. */
.kachel-warn {
  box-shadow:
    0 0 0 1px var(--ton-gelb-rand),
    0 1px 2px rgba(0, 0, 0, 0.35);
}

.kachel-fehl {
  box-shadow:
    0 0 0 1px var(--ton-rot-rand),
    0 1px 2px rgba(0, 0, 0, 0.35);
}

/* **Eine Karte mit offenem Klappmenue steht ueber der Kachelwand.** Am 11.09.2026 im Bild
   beanstandet: das Menue "Pruefen" klappte auf und die Kacheln darunter malten darueber.

   Der Grund ist die Hausform selbst. Eine Karte traegt `backdrop-filter`, und das macht aus ihr
   einen eigenen Stapelzusammenhang. Das Menue darin kann daraus nicht heraus, egal welchen
   Stapelrang Bootstrap ihm gibt: es liegt im Rang der Karte, und die Karte steht im Baum vor den
   Kacheln, wird also zuerst gemalt. Angehoben werden muss deshalb die Karte und nicht das Menue.

   `:has()` und kein Skript: der Zustand steht im Baum, sobald Bootstrap `show` setzt. */
.card:has(.dropdown-menu.show),
.kachelwand:has(.dropdown-menu.show) {
  position: relative;
  z-index: 3;
}

/* Das Menue "Pruefen" in der Steuerung und jedes andere, das Knoepfe traegt statt Verweisen.
   Bootstrap richtet ein Klappmenue auf Eintraege aus, hier stehen fuenf Formulare darin.

   **Die Regel haengt an `.show` und nicht an `.knopfmenue` allein.** Am 10.09.2026 beim ersten
   Bildschirmfoto aufgefallen: das Menue stand offen ueber der Kachelwand, ohne dass jemand darauf
   geklickt hatte. Bootstrap versteckt ein Klappmenue mit `display: none` an `.dropdown-menu`,
   und ein `display: flex` an einer eigenen Klasse weiter unten in derselben Datei sticht das bei
   gleicher Spezifitaet einfach aus. */
.knopfmenue {
  min-width: 14rem;
}

.dropdown-menu.knopfmenue.show {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.knopfmenue form {
  margin: 0;
}

/* Der geteilte Knopf der Steuerung: links "Kamerabild holen", rechts der Pfeil zur zweiten
   Kamera. Am 14.09.2026 beanstandet: "der button links davon darf auf der rechten seite dann
   keine rundung haben."

   Berechtigt, und der Grund liegt eine Ebene tiefer. Jeder Befehl an eine Box ist ein Formular,
   siehe box/_knopf.html, und in der Gruppe steht deshalb ein `<form>` und nicht der Knopf
   selbst. Bootstrap nimmt für seine Ecken die direkten Kinder der Gruppe, trifft also das
   Formular und lässt den Knopf darin gerundet. Er stieß damit rund an den Pfeil, und zwischen
   beiden stand eine Sichel Hintergrund. */
.btn-group > form:not(:last-child) > .btn {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.btn-group > form:not(:first-child) > .btn {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

/* Die Naht zwischen beiden. Am 14.09.2026 nachgetragen: "der pfeil sollte aber noch eine
   vertikale trennlinie zum andern button haben." Beide tragen dieselbe Farbe, und ohne Linie
   ist der Pfeil ein Anhängsel derselben Fläche statt ein zweiter Knopf. Bootstrap lässt an
   dieser Stelle sonst den Rahmen des rechten Knopfes stehen, und den gibt es bei einem
   gefüllten Knopf nicht. */
.btn-group > form + .btn.dropdown-toggle-split {
  border-left: 1px solid rgba(255, 255, 255, 0.28);
}

/* Der Knopf des Reiter-Ueberlaufmenues traegt dieselbe Form wie ein Reiter, auch wenn er offen
   ist. Ohne das setzt Bootstrap ihm die Rahmenfarbe eines Klappmenues auf. */
.nav-tabs .dropdown-toggle::after {
  margin-left: 0.4rem;
}

/* --- Die Aktionszentrale ---------------------------------------------------------------------
   Am 10.09.2026 verlangt: "eine zweite grosse aufgabe ist es aktionen an der fotobox global
   anzuzeigen und zu handlen." Der Punkt in der Leiste, die Leiste in der Ecke und das Fenster
   dahinter, siehe app/aktionen.py und static/js/aktionen.js. */

/* Der Punkt ist ein Knopf und kein Verweis: er wechselt die Seite nicht, er klappt ein Fenster
   auf. Ein <a href="#"> waere fuer die Tastatur dasselbe und fuer den Vorleser eine Luege. */
.leistenpunkt-knopf {
  width: 100%;
  border: 0;
  background: transparent;
  font: inherit;
  text-align: left;
}

/* Blau, solange etwas laeuft. Grau waere hier falsch: die Zahl neben "Fotoboxen" sagt, wie viele
   es gibt, diese sagt, dass gerade gearbeitet wird. */
.leistenzahl-laeuft {
  background: rgba(var(--bs-primary-rgb), 0.85);
  color: #fff;
}

.leistenzahl-fehler {
  margin-left: 0.35rem;
  background: #e5484d;
  color: #fff;
}

/* Ein Sicherheitsnetz gegen eine Leiste, die die halbe Seite verdeckt. Wie viele Zeilen sie
   traegt, entscheidet static/js/aktionen.js, und das ist die eigentliche Regel. Bleibt sie
   trotzdem einmal zu hoch, etwa weil ein Fehlertext ueber acht Zeilen laeuft, wird darin
   gescrollt statt die Seite zugedeckt. */
#laeuft-text {
  max-height: 40vh;
  overflow-y: auto;
}

/* Auf einem Telefon steht die Ecke unter der Kopfzeile und nicht darauf. Die Kopfzeile traegt den
   Knopf fuer die Schublade und die Marke, und beides ist der einzige Weg zur Navigation, solange
   die Seitenleiste eingefahren ist. Am 10.09.2026 bei 390 Bildpunkten gemessen: die Leiste deckte
   sie zu. Die Grenze ist dieselbe wie die, an der die Leiste zur Schublade wird. */
@media (max-width: 991.98px) {
  .toastecke {
    top: 3.6rem;
  }
}

/* Steht in der Leiste nur noch ein Fehlschlag, traegt sie seine Kante. Sie bleibt dann stehen,
   bis jemand ihn abhakt. */
.laeuft-leiste-fehler {
  box-shadow: 0 0 0 1px var(--ton-rot-rand), 0 10px 30px -10px rgba(0, 0, 0, 0.8);
}

/* Mehrere Aktionen untereinander in derselben Leiste brauchen eine Trennung. Ein Abstand allein
   reicht nicht, wenn jede zwei Zeilen hoch ist. */
#laeuft-text > div + div {
  margin-top: 0.55rem;
  padding-top: 0.55rem;
  border-top: 1px solid var(--cube-ring-soft);
}

.aktionsgruppe {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bs-secondary-color);
  margin: 1rem 0 0.5rem;
}

.aktionsgruppe:first-child {
  margin-top: 0;
}

.aktionszeile {
  background: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  border-radius: 9px;
  padding: 0.6rem 0.75rem;
  margin-bottom: 0.5rem;
}

/* Was schon durch ist, steht ruhiger da als das, was noch laeuft. */
.aktionszeile-still {
  background: transparent;
  box-shadow: none;
  padding: 0.25rem 0;
  margin-bottom: 0.25rem;
}

.aktionsfehler {
  background: var(--ton-rot-flaeche);
  box-shadow: inset 0 0 0 1px var(--ton-rot-rand);
  border-radius: 9px;
  padding: 0.6rem 0.75rem;
  margin-bottom: 0.5rem;
}

/* Angehaltenes traegt seine eigene Zahl. Es laeuft nicht, und es ist auch kein Fehlschlag: es
   liegt und wartet auf eine Entscheidung. Am 11.09.2026 dazugekommen. */
/* --- Die Zahl am Reiter Protokoll ------------------------------------------------------------
   Am 13.09.2026 verlangt: "protokoll soll oben im tab die fehleranzahl zeigen. wenn man auf den
   tab klickt sollen der indikator im tab entfernt werden."

   Sie zaehlt die Fehler, die dazugekommen sind, seit jemand zuletzt in das Protokoll gesehen hat.
   Das ist ein Lesezeichen und keine zweite Buchfuehrung ueber die Stoerung der Box: die Marke im
   Kopf zaehlt weiter, was unquittiert ist, und ein Blick in das Protokoll raeumt sie nicht weg.
   Dieselbe Form wie .leistenzahl-fehler in der Seitenleiste. */
.reiterzahl {
  margin-left: 0.45rem;
  font-size: 0.7rem;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: 999px;
  background: #e5484d;
  color: #fff;
  vertical-align: 1px;
}

/* Der Kopf der Protokollkarte traegt jetzt zwei Gruppen: den Filter und das Aufraeumen. */
.protokollkopf {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

/* Das Kreuz je Protokollzeile. Es steht am rechten Rand und tritt zurueck, bis jemand die Zeile
   ueberfaehrt: geloescht wird selten, gelesen wird immer. */
.protokollweg {
  width: 1px;
  white-space: nowrap;
}

.protokollweg .btn-close {
  opacity: 0.25;
  transition: opacity 0.12s ease;
}

tr:hover .protokollweg .btn-close,
.protokollweg .btn-close:focus-visible { opacity: 0.9; }

/* --- Was eine Aktionszeile sagt --------------------------------------------------------------
   Am 13.09.2026 beanstandet: "dann stehen im portal aktuell aktionen 'Befehl auf der box
   ausfuehrn' das hat null kontent fuer den leser."

   Der Titel eines Auftrags nennt seine Art, nicht seine Sache. Zwoelf Terminalbefehle heissen
   alle gleich. Der Gegenstand steht deshalb als eigene Zeile darunter, in einer Zeile und
   abgeschnitten, wenn er laenger ist: der volle Text steht im Titelattribut und im Protokoll. */
.aktionsgegenstand {
  font-size: 0.875rem;
  color: var(--bs-body-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Eine Befehlszeile in der Schrift, in der sie eingetippt wurde. */
.aktionsgegenstand code {
  font-size: 0.8125rem;
  color: var(--bs-body-color);
  background: var(--cube-field);
  border-radius: 4px;
  padding: 0.05rem 0.35rem;
}

/* Die Restfrist an einem wartenden Auftrag, siehe befehle.verfallene_abweisen. Unter zwei Minuten
   gelb: ab da entscheidet sich, ob jemand eingreift. Sie bricht nicht um, sonst stuende die
   Minute am Ende der einen und die Sekunde am Anfang der naechsten Zeile. */
.aktionsfrist { white-space: nowrap; }
.aktionsfrist-knapp { color: var(--ton-gelb-schrift); }

/* Dieselben zwei Zeilen im Toast. Er traegt seit dem 13.09.2026 den Gegenstand und Knoepfe,
   siehe static/js/portal.js. */
.toastgegenstand {
  font-size: 0.875rem;
  color: var(--bs-body-color);
  margin-top: 0.25rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

.toastknoepfe {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.5rem;
}

.leistenzahl-ruht {
  margin-left: 0.35rem;
  background: var(--ton-gelb-flaeche);
  color: var(--ton-gelb-schrift);
  box-shadow: inset 0 0 0 1px var(--ton-gelb-rand);
}

.aktionszeile-ruht {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--ton-gelb-rand);
}

/* Das Kreuz an der Warteleiste. Kleiner als das einer Karte: es raeumt eine Anzeige weg und
   schliesst kein Fenster. */
.btn-close-sm {
  --bs-btn-close-opacity: 0.5;
  padding: 0.2rem;
  background-size: 0.7em;
}

/* --- Das Event im Kopf der Boxseite ----------------------------------------------------------
   Gespiegelt zur Box: dort das Bild links und der Name daneben, hier der Name und das Bild
   dahinter. Dieselben drei Zeilen, dieselben Groessen. Am 11.09.2026 verlangt: "erst das event,
   darunter der status darunter seit. so wie es bei der box auch angeordnet und formatiert ist." */
.eventkopf {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 1rem;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}

.eventkopf-text {
  text-align: right;
  min-width: 0;
}

/* Dieselbe Groesse wie der Boxname, also h4. Die Vorlage setzt dort ein <h1 class="h4">, hier
   steht kein zweites h1: eine Seite hat eine Ueberschrift, und das ist der Name der Box. */
.eventkopf-name {
  display: block;
  font-size: calc(1.275rem + 0.3vw);
  font-weight: 500;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

@media (min-width: 1200px) {
  .eventkopf-name { font-size: 1.5rem; }
}

/* Die Zustandszeile rechtsbuendig. Der Trennpunkt der Reihe faellt hier nicht an, es steht nur
   ein Paar darin. */
.eventkopf-lage {
  justify-content: flex-end;
}

/* Das Etikett ueber dem Eventnamen. Am 13.09.2026 verlangt: "ueber der textzeile einen hinweis
   bekomen wie 'Aktuelles Event:'".

   Dieselbe Form wie .kopfeventbild-wort im leeren Feld, also die Form, die dieses Portal fuer
   ein Etikett ueber einem Wert schon hat. Ohne Doppelpunkt: der Wert steht darunter und nicht dahinter.

   Die Zeile ".eventkopf-seit" stand hier bis dahin und ist weggefallen. Verlangt: "entferne die
   'seit..' linie". Wann ein Paket aufgespielt wurde, steht im Reiter Event. */
.eventkopf-etikett {
  display: block;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bs-secondary-color);
  margin-bottom: 0.1rem;
}

/* **Das Eventbild ist kleiner als das Boxbild.** Am 13.09.2026 verlangt: "das event bild rechts
   auf der box uebersicht soll kleiner dargestellt werden".

   Bis dahin waren beide 11 rem und die Spiegelung galt Zeile fuer Zeile. Links steht das Geraet,
   und um das geht die Seite. Es ist 16:9 und wird weiter quadratisch beschnitten: wer es ganz
   sehen will, klickt auf das Event. */
.kopfeventbild {
  position: relative;
  flex: none;
  width: 7rem;
  height: 7rem;
  border-radius: var(--bs-border-radius-lg);
  overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  background: var(--cube-surface-2);
}

.kopfeventbild img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Ohne Event steht rechts kein Name, sondern der Knopf und das graue Feld. Ohne Erklärsatz
   darunter: am 11.09.2026 ausdrücklich verlangt, "Diese unsinnigen hinweise duerfen nie mehr
   verwendet werden".

   **Am 14.09.2026 auf Knopf und Feld umgebaut.** Verlangt: "der eventbanner rechts bei der
   fotobox soll wenn kein event drauf ist die grauen umrisse des quadrats zeigen in dem kein
   event steht. der verlauf soll auch dazu", danach nachgeschärft: "text gibt es links nicht,
   nur der button. das bild wird in grau ohne transparenz angezeigt und dort steht kein event
   drin."

   Hier standen bis dahin zwei Zeilen übereinander, das Wort "Kein Event" und darunter der
   Knopf, dazu `flex-direction: column` und ein Rand rechts. Das Feld fehlte ganz, und mit ihm
   fiel die rechte Hälfte des Kopfes weg, sobald eine Box nichts geladen hatte.

   Eine eigene Regel braucht der leere Kopf seitdem nicht mehr: er ist dieselbe Reihe wie mit
   Event, also links der Weg und rechts das Quadrat in derselben Größe und an derselben Stelle.
   Die Klasse bleibt als Haken für die Telefonansicht weiter unten. */

/* --- Das Feld ohne Bild ----------------------------------------------------------------------
   Eine deckende Fläche und keine Hausfläche. Die Flächen des Portals sind weiß mit wenigen
   Prozent Deckung, siehe --cube-surface-2, und nehmen damit an, was unter ihnen liegt. Unter
   diesem Feld liegt das Band, an seiner hellsten Stelle rund #313133. Ein Feld in #232326 sähe
   dort aus wie ein Loch in der Karte, deshalb steht hier ein fester Ton darüber.

   Der radiale Verlauf ist die Erinnerung an ein Bild: eine Fläche mit einer Mitte, so wie ein
   Eventbild eine hat. Am 14.09.2026 verlangt: "könnte noch einen leichten radialen verlauf aus
   der mitte beim 'bild' bekommen." */
.kopfeventbild-grau {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem;
  text-align: center;
  box-shadow: none;
  background: radial-gradient(circle at 50% 50%, #3f3f45 0%, #2f2f34 72%);
}

/* Das Wort im Feld. Es steht an der Stelle, an der sonst das Eventbild steht, und sagt, dass
   dort keines liegt. Dieselbe Form wie das Etikett über einem Eventnamen, also klein, gesperrt
   und grau. */
.kopfeventbild-wort {
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.3;
  color: var(--bs-secondary-color);
}

/* --- Der Zustandsbanner ----------------------------------------------------------------------
   Am 11.09.2026 verlangt: "ZUSAETZLICH soll ein weiterer banner darunter. dieser soll keinen
   hinweis text enthalten! und etwas hoeher sein."

   Ein Wort und sonst nichts. Voll in der Mitte, zu den Seiten hin durchscheinend: "c1 mit
   leichtem transparent verlauf links und rechts". */
.zustandsbanner {
  background: linear-gradient(90deg,
    rgba(255, 197, 61, 0.18) 0%, #ffc53d 18%, #ffc53d 82%, rgba(255, 197, 61, 0.18) 100%);
  color: #1a1a1c;
  font-weight: 700;
  font-size: 0.9rem;
  letter-spacing: 0.06em;
  text-align: center;
  padding: 0.62rem;
  border-radius: var(--bs-border-radius);
  margin-bottom: 1rem;
}

/* Eine Marke, die sich anklicken laesst. Sie sieht aus wie jede andere Marke und traegt keinen
   Knopfrahmen: was sie oeffnet, ist eine Auskunft und kein Eingriff. */
.marke-knopf {
  border: 0;
  cursor: pointer;
  font-family: inherit;
}

.marke-knopf:hover,
.marke-knopf:focus-visible {
  filter: brightness(1.18);
}

/* Die Zwischenueberschrift in einem Kachelfenster. Seit dem 11.09.2026 tragen zwei Fenster
   mehrere Themen: "Drucke und Drucker" den Zaehler und das Geraet, "Verbindung" die Leitung, das
   WLAN des Einsatzortes und den Hotspot. Ohne Ueberschrift waeren das drei Listen hintereinander
   ohne Bezug. */
.fensterabschnitt {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bs-secondary-color);
  margin-bottom: 0.5rem;
}

/* Das gestrichelte Feld hinter dem Eventbild im Kopf der Boxseite. Es steht immer im Baum und tritt zurueck, sobald
   ein Bild darin liegt. Dieselbe Sprache wie .kopfbild-leer links. */
.kopfeventbild-leer {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--bs-border-color);
  border-radius: inherit;
  color: var(--bs-secondary-color);
  font-size: 1.6rem;
}
.kopfeventbild:has(img) .kopfeventbild-leer { display: none; }

/* --- Der Stand im Kopf der Eventseite --------------------------------------------------------
   Die dritte Zeile des Eventkopfes. Sie sagt, auf welcher der sieben Stationen das Event steht,
   siehe app/eventschritte.py.

   Am 15.09.2026 verlangt: "der event zustandbanner sollte ueber den tabs sein", danach "mach den
   zustand mal unter das datum also mit neben das bild" und "der text der stationen bliebt drin".

   Der Kopf der Eventseite ist damit derselbe wie der einer Box: Bild, Name, Lage, und in der
   dritten Zeile die Kennung. Links steht dort die Kennung der Box, hier der Stand des Events.
   Kein Bauteil ueber die ganze Seite und kein zweiter Streifen unter dem Kopf.

   Die Zeichnung ist in mockups/eventkopf-zustand.html entstanden, aus vier Fassungen gewaehlt
   und dreimal nachgeschaerft. Sie steht seit dem 15.09.2026 auch in der Eventliste, siehe
   event/_standband.html: zwei Verlaufsanzeigen fuer denselben Weg sind eine zu viel. */
.standzeile {
  margin-top: 0.4rem;
  min-width: 0;
}

/* **Das Band ist so breit wie seine Namen und nicht breiter.** Sieben gleich breite Felder
   richten sich nach dem laengsten Wort, und "Freigegeben" gab damit auch dem Wort "Live" 113
   Bildpunkte. Inhaltsbreite Felder nehmen ein Drittel davon: gemessen 318 von 1168, also 27
   Prozent des Kopfes.

   max-width haelt das Band im Textblock, und schrumpfen duerfen die Felder weiter
   (flex: 0 1 auto): auf dem Telefon kuerzt die Zeile die Namen, statt aus dem Kopf zu laufen. */
.standband {
  display: flex;
  width: fit-content;
  max-width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--cube-ring);
  background: var(--cube-surface);
  font-size: 0.6875rem;
}

.standband li {
  flex: 0 1 auto;
  min-width: 0;
  padding: 0.25rem 0.45rem;
  text-align: center;
  color: var(--bs-tertiary-color);
  border-left: 1px solid var(--cube-ring);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.standband li:first-child { border-left: 0; }

/* Die beiden Enden. Der Weg beginnt mit dem Anlegen und endet mit dem Abschluss, und beide sind
   Randpunkte und keine Arbeit: angelegt ist jedes Event, das es gibt, und abgeschlossen ist es,
   wenn nichts mehr kommt. Sie tragen deshalb ein Zeichen und keine Spalte, und sie schrumpfen
   nicht mit: ein Zeichen laesst sich nicht kuerzen. */
.standband .ende {
  flex: 0 0 auto;
  padding-inline: 0.5rem;
  color: var(--bs-secondary-color);
}

/* Der Punkt am Anfang. Ein Punkt ist der Anfang einer Linie. Kleiner als die Schrift: ein Kreis
   in Schriftgroesse ist eine Scheibe und kein Punkt. */
.standband .fa-circle {
  font-size: 0.5rem;
  vertical-align: 0.12em;
}

.standband .fertig {
  background: var(--cube-surface-3);
  color: var(--ton-grau-schrift);
}

/* **Das laufende Feld traegt das Kupfer der Marke.** Am 15.09.2026 verlangt: "der aktuell step
   soll portal logo farbe bekommen anstatt blau."

   Das hebt die Regel auf, die --marke-kupfer weiter oben in dieser Datei traegt, naemlich nie
   ein Zustand zu sein. Hier ist die Farbe auch keiner: der Zustand steht als Wort im Feld, und
   das Kupfer sagt nur, wo der Weg gerade steht. Gruen, Gelb und Rot bleiben damit frei fuer die
   Meldungen der Box. Dunkle Schrift darauf, der Ton ist zu hell fuer Weiss. */
.standband .jetzt {
  flex: 0 0 auto;
  background: var(--marke-kupfer);
  color: #1a1a1c;
  font-weight: 600;
  padding-inline: 0.6rem;
}

/* Eine Station, an der etwas schiefging. Seit dem 07.10.2026 die Station Cloud, wenn die
   Kundenmail als unzustellbar zurückkam, siehe eventschritte._mailfehler. Rot ist hier ein
   Zustand, den jemand beheben muss, und nicht die Stelle, an der der Weg steht. Deshalb nicht
   das Kupfer und nicht das Grau der erledigten Felder. */
.standband .fehler {
  flex: 0 0 auto;
  background: var(--bs-danger);
  color: #fff;
  font-weight: 600;
}

/* Auf dem Telefon steht das Event unter der Box und nicht daneben. Die Spiegelung braucht zwei
   Spalten, und die gibt es dort nicht: bei 420 Pixeln stand der Eventname rechtsbuendig am Rand,
   waehrend der Boxname linksbuendig darueber lag, und die beiden sahen aus, als gehoerten sie zu
   verschiedenen Seiten.

   Untereinander gilt dieselbe Ordnung wie links: Bild, dann Name, Zustand und Zeile. Die Bilder
   werden kleiner, elf Rem sind auf einem Telefon zwei Drittel der Breite. */
@media (max-width: 767.98px) {
  .boxkopf-reihe { flex-wrap: wrap; }

  /* Auf dem Telefon stehen Box und Event untereinander, und ein Band in der Mitte laege quer
     durch beide. Dort bleibt es der Hintergrund der ganzen Karte wie vor dem 13.09.2026. */
  .boxkopf-event::before,
  .boxkopf-leer::before {
    right: 0;
    height: 100%;
  }

  .kopfbild,
  .kopfeventbild {
    width: 7rem;
    height: 7rem;
  }

  .eventkopf {
    margin-left: 0;
    width: 100%;
    flex-direction: row-reverse;
    justify-content: flex-end;
  }

  .eventkopf-text { text-align: left; }
  .eventkopf-lage { justify-content: flex-start; }

  /* Auch ohne Event steht das Feld zuerst, so wie dort das Bild. Die Reihe dreht sich mit
     .eventkopf um, hier bleibt nur der Abstand kleiner. */
  .eventkopf-leer {
    gap: 0.75rem;
  }
}

/* Der Weg von der Box in die Cloud. **Am 11.09.2026 aus drei Karten zu einer gemacht.** Verlangt:
   "es soll eine einfache ansicht sein, am besten ein breiter block mit pfeil in der mitte der
   symbolisiert was links auf der box ist und rechts was in der cloud ist."

   Drei Spalten in einer Karte. Die mittlere ist so breit wie ihr Inhalt und trägt die Trennlinien,
   damit die beiden Seiten ohne eigenen Rahmen auskommen. */
.bilderweg {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
}
.bilderweg-seite { padding: 1rem 1.25rem; min-width: 0; }
.bilderweg-mitte {
  padding: 1rem 1.25rem;
  border-left: 1px solid var(--bs-border-color);
  border-right: 1px solid var(--bs-border-color);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-width: 16rem;
}
/* Auf dem Telefon untereinander. Die Trennlinien wandern dann nach oben und unten, sonst stünden
   sie quer zur Leserichtung. */
@media (max-width: 767.98px) {
  .bilderweg { grid-template-columns: 1fr; }
  .bilderweg-mitte {
    border-left: 0;
    border-right: 0;
    border-top: 1px solid var(--bs-border-color);
    border-bottom: 1px solid var(--bs-border-color);
  }
}
.bilderweg-kopf {
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bs-secondary-color);
  margin-bottom: 0.35rem;
}
.bilderweg-zahl {
  font-size: 1.9rem;
  font-weight: 600;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.bilderweg-arten {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  margin-top: 0.85rem;
}
/* Der Pfeil ist der Balken. Die Spitze sitzt an seinem Ende und zeigt in die Richtung, in die die
   Bilder gehen. */
.bilderweg-pfeil { position: relative; width: 100%; }
.bilderweg-spitze {
  position: absolute;
  right: -0.5rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.1rem;
  color: var(--bs-primary);
}
/* Eine Seite ohne Gegenstand. Die Cloudseite gilt einem Ordner, und der heisst wie das Event.
   Liegt keines auf der Box, steht dort nichts zu lesen und nichts zu bedienen, siehe
   templates/box/_bilder.html. Am 14.09.2026 verlangt: "der gesamte rechte teil des bilder blocks
   [soll] ausgegraut oder ausgeblendet werden wenn kein event aktiv ist."

   Ausgegraut und nicht ausgeblendet: die Aufteilung links Box, rechts Cloud bleibt damit stehen,
   und wer sie kennt, sieht auf einen Blick, welche Haelfte gerade nichts sagt. */
.bilderweg-ohne-event {
  background: var(--bs-tertiary-bg);
  opacity: 0.75;
}

.zahlspalte { font-variant-numeric: tabular-nums; }

/* --- Der Vorgang und seine Schritte -----------------------------------------------------------

   Am 13.09.2026 verlangt: "es soll eine liste mit aktionen zeigen und links davon häkschen wenn
   fertig und spinner wenn er da gerade ist." Was ein Vorgang ist, steht in app/vorgaenge.py, wie
   das Fenster aufgebaut ist in templates/_vorgang.html.

   Die Liste ist ein Weg von oben nach unten. Die senkrechte Linie zwischen den Marken macht aus
   zehn Zeilen genau das und ist der einzige Zierat hier. */

.ablauf {
  list-style: none;
  margin: 0;
  padding: 0;
}

.ablaufschritt {
  position: relative;
  display: grid;
  grid-template-columns: 1.75rem 1fr;
  column-gap: 0.85rem;
  padding: 0.55rem 0.6rem;
  border-radius: 10px;
}

.ablaufschritt::before {
  content: "";
  position: absolute;
  left: calc(0.6rem + 0.875rem - 1px);
  top: 1.85rem;
  bottom: -0.2rem;
  width: 2px;
  background: var(--cube-ring);
}

.ablaufschritt:last-child::before { display: none; }

.ablaufmarke {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.5rem;
  position: relative;
  z-index: 1;
}

/* Der leere Ring eines Schrittes, der noch nicht dran war. Er traegt die Grundflaeche und nicht
   nichts: sonst liefe die Linie mitten durch ihn hindurch. */
.ablaufring {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 50%;
  box-shadow: inset 0 0 0 2px var(--cube-ring);
  background: var(--bs-body-bg);
}

.ablauftitel {
  font-weight: 600;
  line-height: 1.5rem;
}

.ablaufsatz {
  font-size: 0.875rem;
  color: var(--bs-secondary-color);
}

.ablaufschritt-offen .ablauftitel {
  font-weight: 400;
  color: var(--bs-secondary-color);
}

.ablaufschritt-laeuft {
  background: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.ablaufschritt-fertig .ablaufmarke { color: var(--ton-gruen-schrift); }
.ablaufschritt-fehler .ablaufmarke { color: var(--ton-rot-schrift); }
.ablaufschritt-fehler .ablauftitel { color: var(--ton-rot-schrift); }
.ablaufschritt-weg .ablaufmarke,
.ablaufschritt-weg .ablauftitel { color: var(--ton-grau-schrift); }

.ablaufschritt .progress { margin-top: 0.35rem; max-width: 22rem; }

.vorgangskopf {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}

.vorgangsgegenstand {
  font-size: 0.875rem;
  color: var(--bs-secondary-color);
  margin-top: 0.15rem;
}

.vorgangszaehler {
  font-size: 0.875rem;
  color: var(--bs-secondary-color);
  white-space: nowrap;
  margin-top: 0.2rem;
}

/* Der Gesamtbalken liegt als Haarlinie zwischen Kopf und Liste. Die Zahl dazu steht im Kopf, ein
   Balken mit Beschriftung waere dieselbe Auskunft zweimal. */
.vorgangsbalken {
  height: 3px;
  background: var(--cube-surface-2);
}

.vorgangsbalken > div {
  height: 100%;
  width: 0;
  background: var(--bs-primary);
  transition: width 0.4s ease;
}

.vorgangsbalken-fehler > div { background: var(--ton-rot-voll); }
.vorgangsbalken-fertig > div { background: var(--ton-gruen-voll); }

.vorgangsfuss-satz {
  font-size: 0.875rem;
  color: var(--bs-secondary-color);
  margin-right: auto;
}

/* Die Zeile in der Ecke ist bei einem Vorgang ein Knopf: ein Klick holt das Fenster zurueck. */
.vorgangsverweis {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
}

.vorgangsverweis:hover .vorgangsverweis-name { text-decoration: underline; }

/* === Die Belichtungskarte ======================================================================
   Segmente fuer Messung und ISO, ein Stufenschalter fuer die Korrektur. Der Entwurf steht in
   server/mockups/belichtung.html, das Skript in static/js/belichtung.js. Das gewaehlte Segment
   traegt den blauen Ton des Portals, nicht die volle Farbe. */
.segmente { display: flex; flex-wrap: wrap; gap: .25rem; }
.segmente .bel-segment { flex: 1 1 auto; }
.btn-check:checked + .bel-segment {
  color: #9eb1ff;
  background: rgba(62, 99, 221, .2);
  box-shadow: inset 0 0 0 1px rgba(62, 99, 221, .5);
}

.korrektur { display: flex; align-items: center; gap: .75rem; }
.korrektur .wert { font-size: 1.5rem; font-weight: 600; min-width: 3.5rem; text-align: center;
  font-variant-numeric: tabular-nums; }
.korrektur .stufe { width: 2.5rem; height: 2.5rem; border-radius: 999px; flex: none;
  display: inline-flex; align-items: center; justify-content: center; font-size: 1.1rem; }
.korrektur .skala { height: 6px; border-radius: 999px; background: var(--cube-field);
  box-shadow: inset 0 0 0 1px var(--cube-ring); position: relative; margin: .9rem .25rem .25rem; }
.korrektur .skala .null { position: absolute; left: 50%; top: -3px; bottom: -3px; width: 2px;
  background: var(--cube-ring); transform: translateX(-50%); }
.korrektur .skala .zeiger { position: absolute; top: 50%; width: 14px; height: 14px;
  border-radius: 999px; background: var(--bs-primary); transform: translate(-50%, -50%);
  box-shadow: 0 0 0 4px rgba(62, 99, 221, .2); }
.korrektur .skala-enden { display: flex; justify-content: space-between;
  color: var(--bs-secondary-color); font-size: .75rem; padding: 0 .1rem; }

/* --- Die Werkzeuge des Editors am Telefon ---------------------------------------------------

   Am 13.10.2026 als Entwurf 3 und 4 abgenommen: "3 wenn platz ist und 4 mobil". Wo Platz ist,
   stehen Fläche und Werkzeuge nebeneinander, siehe editor/_flaechen.html. Darunter steht die Fläche
   oben fest, die Werkzeuge laufen darunter durch, und die Reiter Texte und Bilder stehen als Leiste
   am unteren Rand. Eine Regel und kein zweiter Aufbau, sie gilt im Portal wie beim Kunden.

   `--buehne-hoehe` setzt vorlageneditor.js aus dem Platz bis zum Fensterrand, und am Telefon wäre
   das der ganze Bildschirm. Hier gehört die untere Hälfte den Werkzeugen, deshalb `!important`
   gegen den Wert des Skripts. */
@media (max-width: 1199.98px) {
  .editor-flaechenspalte {
    position: sticky;
    top: var(--editor-oben, 0px);
    z-index: 15;
    background: var(--bs-body-bg);
    padding-bottom: 0.5rem;
  }

  .editor-flaechenspalte .editor-buehne {
    --buehne-hoehe: 48svh !important;
  }

  .editor-werkzeuge {
    padding-bottom: 4.5rem;
  }

  .editor-werkzeuge > .nav-tabs {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    display: flex;
    margin: 0 !important;
    padding: 0.4rem 0.6rem calc(0.4rem + env(safe-area-inset-bottom));
    border-radius: 0;
    background: var(--bs-body-bg);
    box-shadow: 0 -1px 0 var(--cube-ring), 0 -10px 30px -20px rgba(0, 0, 0, 0.6);
  }

  .editor-werkzeuge > .nav-tabs .nav-item {
    flex: 1;
  }

  .editor-werkzeuge > .nav-tabs .nav-link {
    width: 100%;
    padding: 0.7rem 0.5rem;
  }
}


/* --- Der Designer beim Kunden -----------------------------------------------------------------

   Seit dem 13.10.2026 steht der Editor auch beim Kunden, als Designer seiner Tischkarte, siehe
   albumverwaltung/designer.html. Am selben Tag dunkel geworden wie das Portal: bis dahin trug er
   unter `html[data-rahmen="kunde"]` helle Farbmarken im Farbton des Events. Verlangt zur ganzen
   Verwaltung: "das theming wird entfernt. egal welches theme gewählt wird sieht die admin seite
   gleich aus und soll am portal orientiert sein." */
.designer-kopf {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.6rem 1rem;
  background: rgba(20, 20, 22, 0.92);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: inset 0 -1px 0 var(--cube-ring);
}

.designer-zurueck {
  padding-left: 0;
  color: var(--bs-secondary-color);
  text-decoration: none;
}

.designer-titel {
  flex: 1;
  margin: 0;
  font-weight: 600;
  font-size: 1.15rem;
}

.designer-haupt {
  --editor-oben: 3.6rem;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0.75rem 1rem 1.5rem;
}

.designer-haupt .card-body {
  padding: 0;
}

/* --- Die Verwaltung eines Albums ---------------------------------------------------------------

   Dieselben sechs Reiter beim Kunden (album_verwaltung.html) und im Reiter Album des Portals,
   aus albumverwaltung/_bloecke.html. Neu gestaltet am 13.10.2026 nach dem Entwurf
   "Gästealbum-Verwaltung", siehe server/mockups/README.md: Karten, Reiter und Knöpfe des Portals,
   kein Farbton des Events. Den tragen nur die kleinen Nachbauten der Gästeseite im Reiter
   Aussehen, über `--ton` an ihrem Abschnitt.

   Die Klassen fangen mit `vw-` an. Bis zu diesem Tag waren es die der Gästeseiten unter `.vw`,
   beim Kunden gestaltet von gast.css, im Portal von hier. */

/* Die Schriften der drei Stile, nur für die Nachbauten im Reiter Aussehen. Die Dateien liegen
   bei den Gästeseiten, siehe static/gast/grund.css. */
@font-face { font-family: "Fraunces"; font-style: italic; font-weight: 500; font-display: swap; src: url("gast/schriften/fraunces-latin-500-italic.woff2") format("woff2"); }
@font-face { font-family: "Pinyon Script"; font-style: normal; font-weight: 400; font-display: swap; src: url("gast/schriften/pinyon-script-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Bricolage Grotesque"; font-style: normal; font-weight: 800; font-display: swap; src: url("gast/schriften/bricolage-grotesque-latin-800-normal.woff2") format("woff2"); }

/* Die Seite des Kunden: oben eine Leiste, darunter das Album, alles in einer Spalte. */
.vw-rahmen {
  max-width: 1160px;
  margin: 0 auto;
  padding-left: 1.25rem;
  padding-right: 1.25rem;
}

.vw-oben {
  background: rgba(20, 20, 22, 0.85);
  box-shadow: inset 0 -1px 0 var(--cube-ring-soft);
}

.vw-obenleiste {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
}

.vw-marke {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-weight: 600;
}

.vw-marke i {
  color: var(--marke-kupfer);
}

.vw-luecke {
  flex: 1;
}

.vw-hauptteil {
  padding-top: 1.5rem;
  padding-bottom: 2.5rem;
}

.vw-albumkopf {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.vw-albumbild {
  width: 64px;
  height: 64px;
  flex: none;
  border-radius: 12px;
  object-fit: cover;
  box-shadow: 0 0 0 1px var(--cube-ring);
}

.vw-albumtext {
  min-width: 0;
}

.vw-albumtext h1 {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 600;
}

.vw-albumort {
  margin: 0.1rem 0 0.45rem;
  color: var(--bs-secondary-color);
}

.vw-albumstand {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.vw-fuss {
  display: flex;
  gap: 1rem;
  padding-bottom: 2rem;
  font-size: 0.85rem;
}

.vw-fuss a {
  color: var(--bs-secondary-color);
}

/* Die Reiter, wie die Reiter des Portals. Sie brechen nicht um, sondern scrollen. Am Telefon
   stünden sechs Reiter sonst auf drei Zeilen. */
.vw-reiter {
  position: relative;
  display: flex;
  gap: 2px;
  padding: 3px;
  margin-bottom: 1.25rem;
  background: var(--cube-surface-2);
  border-radius: 10px;
  overflow-x: auto;
  scrollbar-width: none;
}

.vw-reiter::-webkit-scrollbar {
  display: none;
}

.vw-reiterknopf {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 7px 14px;
  border-radius: 7px;
  color: var(--bs-secondary-color);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.vw-reiterknopf:hover {
  color: var(--bs-body-color);
  background: var(--cube-surface);
}

.vw-reiterknopf.aktiv {
  background: var(--cube-surface-3);
  color: var(--bs-body-color);
  box-shadow: inset 0 0 0 1px var(--cube-ring), 0 1px 2px rgba(0, 0, 0, 0.3);
}

.vw-reiterknopf i {
  font-size: 0.85rem;
  opacity: 0.8;
}

.vw-anzahl {
  padding: 0 0.45rem;
  border-radius: 999px;
  background: var(--cube-surface-3);
  color: var(--bs-secondary-color);
  font-size: 0.72rem;
  line-height: 1.15rem;
}

/* Ohne Skript stehen alle Bereiche untereinander, siehe verwaltung.js. */
.vw-bereich + .vw-bereich {
  margin-top: 1.25rem;
}

/* Bausteine */
.vw-spalten {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.25rem;
}

.vw-haupt {
  flex: 999 1 520px;
  min-width: 0;
}

.vw-neben {
  flex: 1 1 280px;
  min-width: 0;
}

.vw-stapel {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.vw-stapel-eng {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.vw-kopfrechts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  font-weight: 400;
}

.vw-kopfzusatz {
  font-weight: 400;
  font-size: 0.85rem;
  color: var(--bs-secondary-color);
}

.vw-klein {
  margin: 0;
  font-size: 0.8rem;
  color: var(--bs-secondary-color);
}

.vw-leer {
  color: var(--bs-secondary-color);
}

.vw-feldname {
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.78rem;
  color: var(--bs-secondary-color);
}

.vw-paar {
  display: flex;
  gap: 0.5rem;
  width: 100%;
}

.vw-paar > * {
  flex: 1;
}

.vw-paar form {
  margin: 0;
}

.vw-paar-links {
  flex-wrap: wrap;
}

.vw-paar-links > * {
  flex: 0 0 auto;
}

.vw-unsichtbar {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Was nur ohne Skript gebraucht wird, etwa "Senden" neben einer Dateiwahl. */
.vw.mit-skript [data-ohne-skript] {
  display: none;
}

/* Filter als Pillen, ein Segment für Hoch und Quer. */
.vw-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.vw-chip {
  appearance: none;
  padding: 0.2rem 0.7rem;
  border: 1px solid var(--cube-ring);
  border-radius: 999px;
  background: transparent;
  color: var(--bs-secondary-color);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
}

.vw-chip:hover {
  color: var(--bs-body-color);
}

.vw-chip.aktiv {
  background: var(--ton-blau-flaeche);
  border-color: var(--ton-blau-rand);
  color: #d3dcfd;
}

.vw-chipzahl {
  margin-left: 0.15rem;
  font-size: 0.75rem;
  opacity: 0.75;
}

.vw-segment {
  display: inline-flex;
  padding: 3px;
  border-radius: 8px;
  background: var(--cube-field);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.vw-segment form {
  display: contents;
}

.vw-segment button {
  appearance: none;
  padding: 0.2rem 0.7rem;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--bs-secondary-color);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
}

.vw-segment button.aktiv {
  background: var(--cube-surface-3);
  color: var(--bs-body-color);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

/* Tischkarte: die Vorlagen als Raster, die gewählte mit Rahmen und Haken. */
.vw-vorlagen {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  gap: 1.1rem 1rem;
}

.vw-vorlagen.quer {
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}

.vw-vorlagen form {
  margin: 0;
}

.vw-vorlage {
  appearance: none;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.vw-vorlagenbild {
  position: relative;
  display: block;
  border-radius: 6px;
  outline: 2px solid transparent;
  outline-offset: 3px;
  transition: outline-color 0.15s;
}

.vw-vorlagenbild img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 6px;
  background: var(--cube-surface-2);
  box-shadow: 0 10px 24px -14px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(255, 255, 255, 0.06);
}

.vw-vorlage:hover .vw-vorlagenbild {
  outline-color: var(--cube-ring);
}

.vw-vorlage.aktiv .vw-vorlagenbild {
  outline-color: var(--bs-primary);
}

.vw-haken {
  position: absolute;
  top: -7px;
  right: -7px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--bs-primary);
  color: #fff;
  font-size: 0.7rem;
  box-shadow: 0 0 0 2px #232327;
}

.vw-vorlagenname {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.85rem;
}

.vw-vorlagenname .badge {
  font-size: 0.65rem;
}

.vw-kartenfeld {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
}

.vw-karte {
  width: 15rem;
  max-width: 100%;
  height: auto;
  border-radius: 6px;
  box-shadow: 0 14px 30px -16px rgba(0, 0, 0, 0.9);
}

.vw-karte.quer {
  width: 100%;
}

.vw-qr {
  width: 12rem;
  height: auto;
  padding: 0.6rem;
  border-radius: 12px;
  background: #fff;
}

.vw-druck {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem;
  width: 100%;
  margin: 0;
  padding-top: 0.85rem;
  border-top: 1px dashed var(--cube-ring);
}

.vw-druck label {
  margin: 0;
}

.vw-druckbox {
  flex: 1 1 8rem;
}

.vw-druckzahl {
  width: 5rem;
}

.vw-linkzeile {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.vw-linkzeile .form-control {
  flex: 1 1 16rem;
  width: auto;
}

/* Aussehen: Wahlkarten mit einem Bild darüber. */
.vw-optionen {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 1rem;
}

.vw-optionen form {
  display: flex;
  margin: 0;
}

.vw-option {
  appearance: none;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--cube-ring);
  border-radius: 12px;
  background: var(--cube-surface);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.vw-option:hover {
  border-color: rgba(255, 255, 255, 0.22);
}

.vw-option.aktiv {
  border-color: var(--bs-primary);
  box-shadow: 0 0 0 1px var(--bs-primary);
}

.vw-buehne {
  display: flex;
  justify-content: center;
  padding: 1.1rem 0;
  background: rgba(0, 0, 0, 0.2);
}

.vw-optionfuss {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0.85rem;
  border-top: 1px solid var(--cube-ring-soft);
}

.vw-punkt {
  flex: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.35);
}

.vw-option.aktiv .vw-punkt {
  background: #fff;
  box-shadow: inset 0 0 0 5px var(--bs-primary);
}

.vw-optionname {
  font-weight: 600;
}

.vw-optiontext {
  display: flex;
  flex-direction: column;
}

/* Die kleinen Nachbauten der Gästeseite. Die Farben sind die der Stilblätter unter
   static/gast/, gerechnet aus `--ton`, das der Abschnitt Aussehen setzt. */
.vw-tel {
  --grund: hsl(var(--ton, 215) 26% 96%);
  --tinte: hsl(var(--ton, 215) 56% 13%);
  --akzent: hsl(var(--ton, 215) 70% 28%);
  --akzentschrift: #fff;
  --flaeche: #fff;
  position: relative;
  display: flex;
  flex-direction: column;
  width: 150px;
  height: 290px;
  overflow: hidden;
  border: 5px solid #0b0b0d;
  border-radius: 22px;
  background: var(--grund);
  color: var(--tinte);
  line-height: 1.2;
  box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.9);
}

.vw-tel-papier {
  --grund: #faf6ef;
  --tinte: #2d2a26;
  --akzent: hsl(var(--ton, 215) 40% 32%);
  --flaeche: #fffdf9;
}

.vw-tel-nacht {
  --grund: #0d1417;
  --tinte: #f2f7f8;
  --akzent: hsl(var(--ton, 215) 68% 62%);
  --akzentschrift: hsl(var(--ton, 215) 70% 9%);
  --flaeche: #172226;
}

.vw-tel-bild {
  display: block;
  height: 118px;
  margin: 6px 6px 0;
  border-radius: 12px;
  background: hsl(var(--ton, 215) 30% 75%) center / cover no-repeat;
}

.vw-tel-papier .vw-tel-bild {
  width: 104px;
  height: 92px;
  margin: 16px auto 0;
  border: 5px solid #fff;
  border-bottom-width: 16px;
  border-radius: 0;
  box-shadow: 0 6px 12px -6px rgba(45, 42, 38, 0.5);
  transform: rotate(-3deg);
}

.vw-tel-nacht .vw-tel-bild {
  height: 140px;
  margin: 0;
  border-radius: 0;
  -webkit-mask-image: linear-gradient(#000 60%, transparent);
  mask-image: linear-gradient(#000 60%, transparent);
}

.vw-tel-titel {
  display: block;
  overflow: hidden;
  margin-top: 0.55rem;
  padding: 0 0.5rem;
  font-family: "Fraunces", Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: 1rem;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.vw-tel-papier .vw-tel-titel {
  font-family: "Pinyon Script", cursive;
  font-style: normal;
  font-weight: 400;
  font-size: 1.15rem;
}

.vw-tel-nacht .vw-tel-titel {
  position: relative;
  margin-top: -0.7rem;
  font-family: "Bricolage Grotesque", system-ui, sans-serif;
  font-style: normal;
  font-weight: 800;
  text-align: left;
}

.vw-tel-tag {
  display: block;
  margin-top: 0.1rem;
  padding: 0 0.5rem;
  font-size: 0.6rem;
  text-align: center;
  opacity: 0.7;
}

.vw-tel-nacht .vw-tel-tag {
  text-align: left;
}

.vw-tel-knopf {
  display: block;
  margin: 0.6rem 0.7rem 0;
  padding: 0.35rem 0;
  border-radius: 8px;
  background: var(--akzent);
  color: var(--akzentschrift);
  font-size: 0.6rem;
  font-weight: 700;
  text-align: center;
}

.vw-tel-papier .vw-tel-knopf {
  border-radius: 0;
  background: #2d2a26;
  color: #faf6ef;
  font-size: 0.52rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vw-tel-nacht .vw-tel-knopf {
  border-radius: 999px;
}

.vw-tel-reihe,
.vw-tel-raster {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 3px;
  margin: 0.6rem 0.7rem 0;
}

.vw-tel-raster {
  gap: 2px;
  margin: 0 4px;
}

.vw-tel-reihe i,
.vw-tel-raster i,
.vw-tel-foto {
  display: block;
  aspect-ratio: 1;
  border-radius: 3px;
  background: linear-gradient(150deg, #f3c58f, #d9785d 55%, #5b3a4a);
}

.vw-tel-reihe i:nth-child(2),
.vw-tel-raster i:nth-child(3n + 2) {
  background: linear-gradient(120deg, #9fd3c7, #4f8a8b 60%, #25424a);
}

.vw-tel-reihe i:nth-child(3),
.vw-tel-raster i:nth-child(3n) {
  background: radial-gradient(30% 30% at 70% 30%, #ffd1dc, transparent 70%),
    linear-gradient(160deg, #e9b3c0, #8e4b62);
}

.vw-tel-raster i:nth-child(4n) {
  background: radial-gradient(40% 40% at 30% 35%, #ffe6b0, transparent 70%),
    linear-gradient(200deg, #38446b, #151a2e);
}

.vw-tel-raster i {
  border-radius: 1px;
}

.vw-tel-leiste {
  display: flex;
  justify-content: space-around;
  margin-top: auto;
  padding: 0.45rem 0 0.55rem;
  background: var(--flaeche);
}

.vw-tel-leiste i {
  width: 12px;
  height: 12px;
  border-radius: 4px;
  background: currentColor;
  opacity: 0.22;
}

.vw-tel-leiste i.an {
  background: var(--akzent);
  opacity: 1;
}

.vw-tel-klein {
  width: 128px;
  height: 230px;
  padding-top: 6px;
  border-width: 4px;
  border-radius: 18px;
}

.vw-tel-beitrag {
  display: block;
  margin: 0 6px 6px;
  overflow: hidden;
  border-radius: 7px;
  background: var(--flaeche);
}

.vw-tel-kopf {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 5px;
  font-size: 0.5rem;
  font-weight: 600;
}

.vw-tel-kopf i {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--akzent);
}

.vw-tel-foto {
  aspect-ratio: 4 / 5;
  border-radius: 0;
}

.vw-tel-beitrag + .vw-tel-beitrag .vw-tel-foto {
  background: radial-gradient(20% 20% at 20% 30%, rgba(255, 220, 120, 0.9), transparent 70%),
    radial-gradient(18% 18% at 70% 60%, rgba(255, 120, 160, 0.8), transparent 70%), #1b1626;
}

/* Titelbild und Primärfarbe */
.vw-titelbild {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.25rem;
}

.vw-titelbild > .vw-stapel-eng {
  flex: 1 1 16rem;
  min-width: 0;
}

.vw-titelbildbild {
  width: 22rem;
  max-width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 10px;
  box-shadow: 0 0 0 1px var(--cube-ring);
}

.vw-ohnebild {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--cube-surface-2);
  color: var(--bs-secondary-color);
}

.vw-hochladen {
  display: flex;
  gap: 0.5rem;
  margin: 0;
}

.vw-bildwahl {
  display: grid;
  flex-basis: 100%;
  grid-template-columns: repeat(auto-fill, minmax(86px, 1fr));
  gap: 0.4rem;
  max-height: 22rem;
  overflow-y: auto;
  padding: 0.25rem;
}

.vw-bildwahl form {
  margin: 0;
}

.vw-bildwahlknopf {
  appearance: none;
  display: block;
  width: 100%;
  aspect-ratio: 1;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: 6px;
  background: var(--cube-surface-2);
  outline: 2px solid transparent;
  outline-offset: 2px;
  cursor: pointer;
}

.vw-bildwahlknopf:hover,
.vw-bildwahlknopf:focus-visible {
  outline-color: var(--bs-primary);
}

.vw-bildwahlknopf img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.vw-farben {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.vw-farben form {
  margin: 0;
}

.vw-farbe {
  appearance: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  color: #fff;
  font-size: 0.8rem;
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}

.vw-farbe.aktiv {
  box-shadow: 0 0 0 2px #232327, 0 0 0 4px var(--bs-body-color);
}

.vw-trenner {
  width: 1px;
  height: 28px;
  background: var(--cube-ring);
}

.vw-eigenfarbe {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 3px;
  border: 1px solid transparent;
  border-radius: 999px;
}

.vw-eigenfarbe.aktiv {
  border-color: var(--bs-primary);
}

.vw-eigenfarbe input[type="color"] {
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
}

.vw-eigenfarbe input[type="color"]::-webkit-color-swatch-wrapper {
  padding: 0;
}

.vw-eigenfarbe input[type="color"]::-webkit-color-swatch {
  border: 0;
  border-radius: 50%;
}

.vw-eigenfarbe input[type="color"]::-moz-color-swatch {
  border: 0;
  border-radius: 50%;
}

/* Funktionen: je Schalter eine Kachel mit seiner Beschreibung, Fassung 5 des Entwurfs. */
.vw-kacheln {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.1rem;
  margin-bottom: 1.25rem;
}

.vw-schaltkachel .card-body {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  height: 100%;
}

.vw-schaltkachel.an {
  box-shadow: var(--cube-shadow-card), inset 0 0 0 1px var(--ton-blau-rand);
}

.vw-schaltkopf {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
}

.vw-symbol {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 10px;
  background: var(--cube-surface-3);
  color: var(--bs-secondary-color);
  box-shadow: inset 0 0 0 1px var(--cube-ring);
}

.vw-schaltkachel.an .vw-symbol {
  background: var(--ton-blau-flaeche);
  color: var(--ton-blau-schrift);
  box-shadow: inset 0 0 0 1px var(--ton-blau-rand);
}

.vw-schaltname {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  font-weight: 600;
}

.vw-schalter {
  appearance: none;
  position: relative;
  flex: none;
  width: 44px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.2);
  cursor: pointer;
  transition: background 0.15s;
}

.vw-schalter::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  transition: left 0.15s;
}

.vw-schalter.an {
  background: var(--bs-primary);
}

.vw-schalter.an::after {
  left: 21px;
}

.vw-schalter:focus-visible {
  outline: 2px solid var(--ton-blau-schrift);
  outline-offset: 2px;
}

.vw-info {
  display: flex;
  flex: 1;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0;
  padding: 0.7rem 0.8rem;
  border-radius: 8px;
  background: var(--cube-surface-2);
  color: var(--bs-secondary-color);
  font-size: 0.85rem;
  box-shadow: inset 0 0 0 1px var(--cube-ring-soft);
}

.vw-info i {
  margin-top: 0.2rem;
  color: var(--ton-blau-schrift);
}

.vw-zeitraum {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2.5rem;
}

/* Bilder: Kacheln mit Marken oben und den Handlungen unten rechts, immer sichtbar, denn auf
   einem Telefon gibt es kein Darüberfahren. */
.vw-bilder {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.6rem;
}

.vw-bild {
  position: relative;
  aspect-ratio: 1;
  margin: 0;
  overflow: hidden;
  border-radius: 8px;
  background: var(--cube-surface-2);
}

.vw-bild img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.vw-bild.verborgen img,
.vw-bild.verborgen .vw-ohnekachel {
  opacity: 0.38;
}

.vw-ohnekachel {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: var(--bs-secondary-color);
  font-size: 0.85rem;
}

.vw-marken {
  position: absolute;
  top: 6px;
  left: 6px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.vw-grund {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 1.4rem 2.6rem 0.4rem 0.5rem;
  background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.82));
  color: #fff;
  font-size: 0.75rem;
}

.vw-bildtaten {
  position: absolute;
  right: 6px;
  bottom: 6px;
  display: flex;
  gap: 4px;
}

.vw-bildtaten form {
  margin: 0;
}

.vw-rund {
  appearance: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 8px;
  background: rgba(10, 10, 12, 0.75);
  color: #fff;
  font-size: 0.8rem;
  cursor: pointer;
}

.vw-rund:hover {
  background: rgba(62, 99, 221, 0.9);
}

/* Gästebuch: die Einträge in Spalten, schmal in einer. */
.vw-buch {
  columns: 2 22rem;
  column-gap: 1rem;
}

.vw-eintrag {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1rem;
  padding: 1rem;
  border-radius: 10px;
  background: var(--cube-surface-2);
  box-shadow: inset 0 0 0 1px var(--cube-ring-soft);
  break-inside: avoid;
}

.vw-eintrag.verborgen > :not(.vw-paar) {
  opacity: 0.45;
}

.vw-eintragskopf {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
}

.vw-wer {
  font-weight: 600;
}

.vw-wann {
  font-size: 0.8rem;
  color: var(--bs-secondary-color);
}

.vw-was {
  margin: 0;
  white-space: pre-line;
}

.vw-seite {
  width: 11rem;
  max-width: 100%;
  border-radius: 6px;
}

.vw-eintragsbilder {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.vw-eintragsbilder img {
  width: 64px;
  height: 64px;
  object-fit: cover;
  border-radius: 6px;
}

/* Am Telefon: schmalerer Rand, die Wahlkarten nebeneinander zum Wischen statt untereinander. */
@media (max-width: 575.98px) {
  .vw-rahmen {
    padding-left: 1rem;
    padding-right: 1rem;
  }

  .vw-vorlagen {
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  }

  .vw-optionen {
    grid-auto-columns: 47%;
    grid-auto-flow: column;
    grid-template-columns: none;
    overflow-x: auto;
    padding-bottom: 0.25rem;
  }

  .vw-bilder {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.35rem;
  }

  .vw-tel {
    width: 132px;
    height: 256px;
  }
}

/* Die Knöpfe der oberen Leiste tragen ihr Wort neben dem Symbol, am Telefon nur das Symbol. Sonst
   bricht die Leiste dort auf zwei Zeilen. */
.vw-knopftext {
  margin-left: 0.5rem;
}

@media (max-width: 575.98px) {
  .vw-knopftext {
    display: none;
  }
}

/* The Fotobox UI, the portal on the box itself, since 17.10.2026. See app/fotoboxui.py.
   Until 19.10.2026 it had a square grid of its own that cropped every picture with
   `object-fit: cover`. aj: "bilder sollten in der bilder gallerie nicht abgeschnitten sein". The
   gallery now uses the tiles of the portal (.bilderkacheln, `contain`), see
   fotoboxui/_gallery.html. The test mark sits in the top left corner of the tile. */
.bilderkachel {
  position: relative;
}
.bilderkachel .bildmarke {
  position: absolute;
  top: .25rem;
  left: .25rem;
  font-size: .65rem;
}
/* The statistics of the Fotobox UI, since 19.10.2026, see fotoboxui/_statistik.html. The chart
   needs a box of fixed height, Chart.js fills it. The period field keeps its width, otherwise a
   select for "September 2026" pushes the arrows into the next line on a phone. */
.statistikflaeche {
  position: relative;
  height: 220px;
}
.statistikfeld {
  width: 11rem;
}
/* The sum stands as last row of the table body and is set apart by a line. */
.card .table > tbody > tr.statistiksumme > td {
  border-top: 2px solid var(--bs-border-color);
}
.bildgross {
  max-height: 70vh;
}
.card.schmal {
  max-width: 32rem;
}

/* --- Einstellungen der Fotobox UI ----------------------------------------------------------
   Seit dem 18.10.2026: die Gruppen links, die gewaehlte rechts, wie die Weboberflaeche eines
   Druckers. Unterhalb von lg stehen die Gruppen als umbrechende Reihe ueber dem Inhalt. Am
   14.09.2026 verlangt: "horizontales scrolling muss verhindert werden". Die Punkte sehen aus wie
   die der Seitenleiste, siehe .leistenpunkt. */
.einstellungsrahmen {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
}

.einstellungsgruppen {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.einstellungsgruppe {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-radius: 9px;
  color: var(--bs-secondary-color);
  text-decoration: none;
  font-size: 0.9375rem;
}

.einstellungsgruppe > i {
  width: 17px;
  text-align: center;
  flex: none;
}

.einstellungsgruppe:hover {
  color: var(--bs-body-color);
  background: var(--cube-surface-2);
}

.einstellungsgruppe.active {
  color: var(--bs-body-color);
  background: rgba(var(--bs-primary-rgb), 0.2);
  box-shadow: inset 0 0 0 1px rgba(var(--bs-primary-rgb), 0.45);
}

.einstellungsgruppe.active > i {
  color: var(--bs-link-color);
}

.einstellungsinhalt {
  min-width: 0;
}

@media (min-width: 992px) {
  .einstellungsrahmen {
    grid-template-columns: 190px minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
  }

  .einstellungsgruppen {
    flex-direction: column;
    flex-wrap: nowrap;
    position: sticky;
    top: 1rem;
  }
}

/* --- Livestream, since 19.10.2026, see templates/box/_livestream.html ----------------------------

   The panel stands above the tabs and outside every hull. The camera delivers portrait at
   640 x 960, the picture keeps its own proportion and stays inside the window. */
.livestream-kopf {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.6rem 0.9rem;
}

.livestream-titel {
  font-weight: 600;
}

.livestream-werte {
  color: var(--bs-secondary-color);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
}

.livestream-knoepfe {
  display: flex;
  gap: 0.5rem;
  margin-left: auto;
}

.livestream-bild {
  position: relative;
  display: flex;
  justify-content: center;
  background: #000;
  border-bottom-left-radius: inherit;
  border-bottom-right-radius: inherit;
  min-height: 12rem;
}

.livestream-bild img {
  display: block;
  max-width: 100%;
  max-height: min(70vh, 960px);
  object-fit: contain;
}

.livestream-bild img:not([src]) {
  visibility: hidden;
}

/* ================================================================================================
   Aufteilungen, seit dem 08.10.2026. Siehe app/aufteilungen.py und mockups/bildaufteilung.html.
   ================================================================================================ */

/* Ein Fotofeld auf einer Flaeche. Lage und Groesse in Anteilen, wie jede Ebene im Editor, die
   Drehung in Grad, wie Photobooth sie kennt. */
.fotofeld {
  position: absolute;
  left: calc(var(--x) * 100%);
  top: calc(var(--y) * 100%);
  width: calc(var(--b) * 100%);
  height: calc(var(--h) * 100%);
  transform: rotate(var(--d, 0deg));
  border-radius: 3px;
  background:
    radial-gradient(circle at 30% 35%, rgba(255, 214, 170, 0.95), transparent 55%),
    radial-gradient(circle at 70% 65%, rgba(120, 150, 190, 0.85), transparent 60%),
    radial-gradient(circle at 55% 20%, rgba(200, 140, 150, 0.8), transparent 50%),
    #8d8f97;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
  z-index: 5;
  touch-action: none;
}

.fotofeld:nth-child(2n) {
  background:
    radial-gradient(circle at 65% 30%, rgba(240, 200, 160, 0.95), transparent 55%),
    radial-gradient(circle at 25% 70%, rgba(110, 160, 140, 0.8), transparent 60%),
    #868a86;
}

.fotofeld:nth-child(3n) {
  background:
    radial-gradient(circle at 40% 60%, rgba(250, 220, 190, 0.95), transparent 50%),
    radial-gradient(circle at 80% 25%, rgba(160, 130, 190, 0.8), transparent 55%),
    #8e8794;
}

.fotofeld-nummer {
  position: absolute;
  left: 6px;
  top: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background-color: rgba(20, 22, 26, 0.72);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
}

/* Die Fotofelder im Design-Editor. Sie ersetzen dort die gerechnete Auflage aus
   bestand.auflage und stehen wie sie nur mit dem Schalter da, siehe .editor-auflage. */
.editor-fotofelder {
  display: none;
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
}

.editor-flaeche.zeigt-beispiel .editor-fotofelder {
  display: block;
}

/* Die kleine Zeichnung einer Aufteilung: der Bogen weiss, die Fotos grau. */
.aufteilungsbild .bogen { fill: #fbfaf7; }
.aufteilungsbild .foto { fill: #9aa1b2; }
.aufteilungsbild text { fill: #fff; font-weight: 600; font-family: system-ui, sans-serif; }

/* Die Wahl im Design: Kacheln mit Namen, drei je Reihe. */
.aufteilungsreihe {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.6rem;
}

.aufteilungswahl {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.5rem 0.25rem 0.4rem;
  border-radius: 8px;
  border: 1px solid var(--bs-border-color);
  background-color: rgba(255, 255, 255, 0.03);
  color: var(--bs-secondary-color);
  font-size: 0.75rem;
  min-width: 0;
}

.aufteilungswahl:hover {
  border-color: var(--bs-primary);
}

.aufteilungswahl.aktiv {
  border-color: var(--bs-primary);
  box-shadow: 0 0 0 1px var(--bs-primary);
  color: var(--bs-body-color);
}

.aufteilungswahl .aufteilungsbild {
  display: block;
  height: 64px;
  width: auto;
  max-width: 100%;
}

.aufteilungswahl.aktiv .aufteilungsbild .foto { fill: var(--bs-primary); }

.aufteilungswahl span {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Die Wahl der Collagen an der Box in den Eventeinstellungen. */
.collagewahl .aufteilungsbild {
  height: 48px;
  width: auto;
}

/* What ends up in the photo, laid over the whole picture by static/js/livestream.js. Two pixels,
   aj on 19.10.2026: "rahmen kann duenner sein". One pixel looked grey: on a fractional edge the
   browser blends it with the picture. The faint dark hairline outside keeps the red visible on a
   red shirt. */
.livestream-rahmen {
  position: absolute;
  box-sizing: border-box;
  border: 2px solid #ff2d2d;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3);
  pointer-events: none;
}
