/*
 * Werkseinstellung der Firmenfarben.
 *
 * Diese Werte gelten, solange in der Maske "Erscheinungsbild" nichts
 * hinterlegt ist. Sobald dort etwas gespeichert wurde, überschreibt sie
 * der <style>-Block im Seitenkopf (siehe branding_style() in
 * inc/settings.php). Deshalb steht hier alles, was dort ebenfalls
 * gesetzt wird — sonst bliebe eine Variable ohne Wert, wenn jemand die
 * Anwendung ohne Einstellungstabelle betreibt.
 */
:root {
  --mb-anthracite: #1c1f22;
  --mb-silver: #c8ced3;
  --mb-blue: #00adef;

  --app-header-fg:    #ffffff;
  --app-header-line:  rgba(255,255,255,.22);
  --app-header-muted: rgba(255,255,255,.72);
  --app-header-dim:   rgba(255,255,255,.60);
  --app-header-hover: rgba(255,255,255,.12);
  --app-header-chip:  rgba(255,255,255,.18);

  --app-auth-1: #2b2f33;
  --app-auth-2: #3f464d;
  --app-auth-3: #55606a;
  --app-auth-fg: #ffffff;
}

.bg-anthracite { background-color: var(--mb-anthracite) !important; }

.brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 2px solid var(--mb-silver);
  border-radius: 50%;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .05em;
}

/* ================================================================== */
/* Grundgerüst: feste Kopfzeile, Seitenleiste links, Inhalt rechts     */
/*                                                                     */
/* Die Breite der Leiste steckt in einer Variablen, die beim Einklappen */
/* umgesetzt wird. Dadurch genügt EIN Umschalter am <body>, und alles   */
/* andere folgt — auch die linke Kante der Kopfzeile.                   */
/* ================================================================== */
:root {
  --nav-width: 16rem;
  --nav-width-collapsed: 3.75rem;
  --header-height: 3.25rem;
}

body.app {
  --nav-current: var(--nav-width);
  margin: 0;
  min-height: 100vh;
}
body.app.nav-collapsed { --nav-current: var(--nav-width-collapsed); }

.skip-link {
  position: fixed; top: .5rem; left: .5rem; z-index: 1100;
  background: var(--bs-body-bg); color: var(--bs-body-color);
  border: 1px solid var(--bs-border-color);
  padding: .5rem .9rem; border-radius: .375rem;
}

/* ------------------------------- Kopfzeile ------------------------ */
.app-header {
  position: sticky; top: 0; z-index: 1030;
  display: flex; align-items: center; gap: .75rem;
  height: var(--header-height);
  padding: 0 .85rem;
  background: var(--mb-anthracite);
  color: var(--app-header-fg);
}
.app-header-spacer { flex: 1 1 auto; }

.app-nav-toggle {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem;
  border: 0; border-radius: .375rem;
  background: transparent; color: var(--app-header-fg); font-size: 1.15rem;
}
.app-nav-toggle:hover  { background: var(--app-header-hover); }
.app-nav-toggle:focus-visible { outline: 2px solid var(--mb-blue); outline-offset: 2px; }

.app-brand {
  display: flex; align-items: center; gap: .55rem;
  color: var(--app-header-fg); text-decoration: none; font-weight: 600; white-space: nowrap;
}
.app-brand:hover { color: var(--app-header-fg); }
.app-brand-text { letter-spacing: .04em; }

/* Das Firmenlogo tritt an die Stelle des runden Markenzeichens. Die Höhe
   ist gedeckelt, die Breite folgt dem Seitenverhältnis — sonst bestimmt
   die hochgeladene Datei, wie hoch die Kopfzeile wird. */
.app-logo {
  display: block;
  height: 1.6rem; width: auto; max-width: 11rem;
  object-fit: contain;
}
.auth-logo {
  display: inline-block;
  max-height: 3.5rem; max-width: 14rem; width: auto; height: auto;
  object-fit: contain;
}

/* Das Haus führt zur eigenen Startseite. Es steht zwischen Markenzeichen
   und Ortsangabe und bleibt auch auf schmalen Geräten sichtbar — es ist
   ein Symbol und kostet keine Breite. */
.app-home {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; flex: 0 0 auto;
  color: var(--app-header-muted); text-decoration: none; font-size: 1.05rem;
  border-radius: .375rem;
}
.app-home:hover, .app-home:focus-visible { color: var(--app-header-fg); }

/* Wo man gerade ist — auf schmalen Geräten ausgeblendet, dort führt
   die Überschrift der Seite selbst durch. */
.app-here {
  padding-left: .85rem; margin-left: .1rem;
  border-left: 1px solid var(--app-header-line);
  color: var(--app-header-muted); font-size: .875rem; white-space: nowrap;
}

/* ------------------------------- Schnellzugriff ------------------- */
/*
 * Der Stern sitzt neben der Ortsangabe. Er ist die einzige Stelle, an
 * der ein Menüpunkt angeheftet und wieder weggenommen wird — deshalb
 * ein Umschalter und kein Knopf, der nur in eine Richtung wirkt.
 */
.app-fav-form { margin: 0; }
.app-fav {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem;
  border: 0; border-radius: .375rem;
  background: transparent; color: var(--app-header-dim); font-size: 1.05rem;
}
.app-fav:hover { background: var(--app-header-hover); color: var(--app-header-fg); }
.app-fav:focus-visible { outline: 2px solid var(--mb-blue); outline-offset: 2px; }
.app-fav.an { color: #ffc107; }

/* ---------------------------------------------------------------------
   Der Einsatzort — eine Gruppe, zwei Gestalten (1.0-260800088)

   Breit:  Firma, Filiale und Lager stehen nebeneinander in der Zeile.
   Schmal: dieselben Felder liegen hinter einem Knopf.

   Umgeschaltet wird nur mit CSS. Das Markup ist bei jeder Breite
   dasselbe, damit eine Prüfung, die `#coSelect` sucht, es immer findet.

   Der Trick ist, dass `.app-orte-felder` IMMER die Klasse
   `dropdown-menu` trägt — Bootstrap braucht sie, um das Auf- und
   Zuklappen zu übernehmen — und breit einfach so umgestellt wird, dass
   sie aussieht und liegt wie eine gewöhnliche Reihe.
   --------------------------------------------------------------------- */
.app-orte { display: contents; }        /* breit: kein eigener Kasten */

/* Mit `.app-header` davor, und das ist kein Zierrat: Der Knopf trägt
   auch `.app-kopfknopf`, und die Regel dafür steht weiter unten in
   dieser Datei und setzt `display: inline-flex`. Bei gleicher
   Spezifität gewinnt die spätere — der Knopf war bei 1600 px sichtbar,
   und die Prüfung hat es gemeldet. */
.app-header .app-orte-knopf { display: none; }      /* breit: kein Knopf */

.app-orte-felder.dropdown-menu {
  position: static;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: .75rem;
  inset: auto;
  transform: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  min-width: 0;
}

.app-warehouse { display: flex; align-items: center; gap: .5rem; margin: 0; }
.app-warehouse-label { color: var(--app-header-dim); font-size: .8rem; margin: 0; white-space: nowrap; }

/* Steht nur eines zur Wahl, steht dort Text statt eines Auswahlfelds.
   Er ist heller als eine Überschrift und dunkler als die Beschriftung —
   eine Angabe, die man liest und nicht anfasst. */
.app-warehouse-fest {
  color: var(--app-header-fg, inherit);
  font-size: .85rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 18rem;
}
.app-warehouse .form-select { min-width: 15rem; }
/* Drei Auswahlfelder nebeneinander passen in 15 rem nicht mehr. Firma und
   Filiale brauchen weniger als das Lager: Dort steht Kennung, Nummer und
   Name, hier nur Kennung und Name. */
#coSelect, #brSelect { min-width: 11rem; }

.app-cart { white-space: nowrap; }

/* Warenkorb und Nachrichten tragen seit 1.0-260800083 nur ihr Sinnbild.
   Ohne Beschriftung wird der Knopf schmal und hoch — quadratisch sieht
   er wie ein Knopf aus und nicht wie ein verrutschtes Etikett. Die Zahl
   sitzt an der oberen rechten Ecke und braucht rechts etwas Luft, sonst
   wird sie vom Nachbarn beschnitten. */
.app-kopfknopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  padding: 0;
  flex: none;
}
.app-kopfknopf + .app-kopfknopf { margin-left: .35rem; }

/* ---------------------------------------------------------------------
   Der geteilte Hilfeknopf
   ---------------------------------------------------------------------
   Innerhalb einer `.btn-group` sollen die beiden Hälften ZUSAMMEN-
   stehen — der Abstand oben würde sie auseinanderreißen und aus einem
   Knopf zwei machen. Gemessen an der Kopfzeile: mit dem Abstand sah
   der Pfeil wie ein eigener Knopf aus, dessen Zweck niemand errät.

   Auf dem Telefon (390 px) lief die Kopfzeile mit der zweiten Hälfte
   um 2 px über den Rand — die Prüfung `kopfzeile` hat es gemeldet.
   Dort fällt der Pfeil weg: Das „?" allein führt weiterhin direkt zum
   Kapitel dieser Maske, und der Rest des Menüs (Handbuch von vorn,
   Suche, Support-Code) steht auf der Handbuchseite ohnehin. Lieber
   eine Hälfte weniger als eine Kopfzeile, die seitlich schiebt.
   --------------------------------------------------------------------- */
.app-hilfe-gruppe { flex: none; }
.app-hilfe-gruppe .app-kopfknopf + .app-kopfknopf { margin-left: 0; }
.app-hilfe-gruppe .dropdown-toggle-split { width: 1.4rem; }

@media (max-width: 575.98px) {
  .app-hilfe-gruppe .dropdown-toggle-split { display: none; }
  /* Ohne den Pfeil ist das „?" wieder ein einzelner Knopf und braucht
     seine runde Ecke rechts zurück — sonst sieht es abgeschnitten aus. */
  .app-hilfe-gruppe > .app-kopfknopf:first-child {
    border-top-right-radius: var(--bs-btn-border-radius);
    border-bottom-right-radius: var(--bs-btn-border-radius);
  }
}

.app-user { display: inline-flex; align-items: center; color: var(--app-header-fg); text-decoration: none; }
.app-user::after { margin-left: .35rem; }

/* ---------------------------------------------------------------------
   Die letzte Sprosse: unter 1300 px rückt der Einsatzort hinter einen
   Knopf. Gemessen war der Überlauf vorher 46 px bei 1200 und 254 px bei
   992 — und draußen lagen Warenkorb, Nachrichten und Benutzermenü.
   --------------------------------------------------------------------- */
@media (max-width: 1299.98px) {
  .app-orte { display: inline-block; position: relative; flex: none; }
  .app-header .app-orte-knopf { display: inline-flex; }

  /* Zurück zum gewöhnlichen Aufklappmenü: Bootstrap zeigt es über
     `.show`, deshalb hier wieder `display: none` als Ausgangslage. */
  .app-orte-felder.dropdown-menu {
    position: absolute;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: .6rem;
    inset: 0 0 auto auto;
    transform: translate(0, var(--header-height));
    padding: .75rem;
    border: 1px solid rgba(0,0,0,.15);
    border-radius: .5rem;
    background: #fff;
    box-shadow: 0 .5rem 1rem rgba(0,0,0,.25);
    min-width: 17rem;
  }
  .app-orte-felder.dropdown-menu.show { display: flex; }

  /* Im Aufklappmenü steht die Beschriftung wieder da — dort ist Platz,
     und ohne sie stünden drei Felder ohne Angabe untereinander. */
  .app-orte-felder .app-warehouse { display: flex; align-items: baseline; gap: .4rem; }
  .app-orte-felder .app-warehouse-label {
    display: inline; color: #6c757d; font-size: .75rem;
    min-width: 4.2rem; flex: none;
  }
  .app-orte-felder .app-warehouse-fest { color: #212529; max-width: none; }
  .app-orte-felder .app-warehouse-form { width: 100%; }
  .app-orte-felder .form-select,
  .app-orte-felder #coSelect,
  .app-orte-felder #brSelect { min-width: 0; max-width: none; width: 100%; }
}

/* Unter 992px weicht zuerst die Beschriftung, dann der Lagername. */
@media (max-width: 991.98px) {
  .app-warehouse-label { display: none; }
  /* Auf dem Telefon fällt die Beschriftung weg — der feste Text bleibt,
     denn ohne ihn wüsste niemand mehr, in welcher Filiale er steht. */
  .app-warehouse-fest { max-width: 9rem; }
  .app-warehouse .form-select { min-width: 9rem; max-width: 11rem; }
  #coSelect, #brSelect { min-width: 7rem; max-width: 9rem; }
}
@media (max-width: 575.98px) {
  .app-brand-text { display: none; }
  .app-header { gap: .5rem; padding: 0 .6rem; }
}

/* ------------------------------ Seitenleiste ---------------------- */
.app-shell { display: flex; align-items: flex-start; min-height: calc(100vh - var(--header-height)); }

.app-sidebar {
  position: sticky; top: var(--header-height);
  flex: 0 0 var(--nav-current);
  width: var(--nav-current);
  height: calc(100vh - var(--header-height));
  overflow-x: hidden; overflow-y: auto;
  background: var(--bs-body-bg);
  border-right: 1px solid var(--bs-border-color);
  transition: flex-basis .18s ease, width .18s ease;
}
@media (prefers-reduced-motion: reduce) { .app-sidebar { transition: none; } }

.app-main { flex: 1 1 auto; min-width: 0; }

.app-nav { padding: .75rem 0 2rem; }
.app-nav-module + .app-nav-module { margin-top: .35rem; }

.app-nav-module-label {
  padding: .85rem 1rem .35rem;
  font-size: .7rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--bs-secondary-color); white-space: nowrap;
}

.app-nav-list, .app-nav-sub { list-style: none; margin: 0; padding: 0; }

/* ---- Der Schnellzugriff in der Leiste ---- */
.app-nav-fav-head { display: flex; align-items: center; }
.app-nav-fav-head .app-nav-module-label { flex: 1 1 auto; }
.app-nav-fav-edit {
  flex: 0 0 auto; margin-right: .6rem; padding: .15rem .35rem;
  border-radius: .25rem; color: var(--bs-secondary-color);
  font-size: .8rem; line-height: 1; text-decoration: none;
}
.app-nav-fav-edit:hover { background: var(--bs-secondary-bg); color: var(--bs-body-color); }
.app-nav-fav-leer {
  margin: 0; padding: .1rem 1rem .6rem;
  font-size: .78rem; line-height: 1.35; color: var(--bs-secondary-color);
}
.app-nav-fav-row { display: flex; align-items: center; }
.app-nav-fav-row > .app-nav-link { flex: 1 1 auto; min-width: 0; }
.app-nav-fav-grip {
  flex: 0 0 auto; padding-left: .35rem;
  color: var(--bs-secondary-color); font-size: .95rem; line-height: 1; cursor: grab;
}
.app-nav-fav-grip:active { cursor: grabbing; }
.app-nav-fav-weg { flex: 0 0 auto; margin: 0; }
.app-nav-fav-weg button {
  border: 0; background: transparent; padding: .15rem .5rem .15rem .25rem;
  color: var(--bs-secondary-color); font-size: .85rem; line-height: 1;
}
.app-nav-fav-weg button:hover { color: var(--bs-danger); }
.app-nav-fav-fertig { padding: .5rem .75rem .25rem; }
.app-nav-fav-mehr {
  display: block; margin-top: .4rem; text-align: center;
  font-size: .78rem; color: var(--bs-secondary-color);
}

/*
 * Eingeklappte Leiste: Der Schnellzugriff zeigt dann nur Sinnbilder, und
 * Stift, Griff und ✕ hätten keinen Platz. Sie verschwinden mit dem Text —
 * bearbeitet wird in der ausgeklappten Leiste.
 */
body.app.nav-collapsed .app-nav-fav-edit,
body.app.nav-collapsed .app-nav-fav-leer,
body.app.nav-collapsed .app-nav-fav-grip,
body.app.nav-collapsed .app-nav-fav-weg,
body.app.nav-collapsed .app-nav-fav-fertig { display: none; }

.app-nav-link {
  display: flex; align-items: center; gap: .7rem;
  width: 100%;
  padding: .5rem 1rem;
  border: 0; border-left: 3px solid transparent;
  background: transparent; color: var(--bs-body-color);
  text-align: left; text-decoration: none; font-size: .925rem; white-space: nowrap;
}
.app-nav-link:hover { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
.app-nav-link:focus-visible { outline: 2px solid var(--mb-blue); outline-offset: -2px; }
.app-nav-link.active {
  border-left-color: var(--mb-blue);
  background: var(--bs-tertiary-bg);
  color: var(--bs-emphasis-color); font-weight: 600;
}
.app-nav-icon { flex: 0 0 1.25rem; font-size: 1.05rem; text-align: center; }
.app-nav-text { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }

.app-nav-caret { font-size: .7rem; transition: transform .18s ease; }
.app-nav-group[aria-expanded="true"] .app-nav-caret { transform: rotate(180deg); }

.app-nav-child { padding-left: 2.1rem; font-size: .88rem; }
.app-nav-child .app-nav-icon { font-size: .95rem; }

/* ------------------------------------------------------------------ */
/* Ein Punkt ohne seinen Bezug                                         */
/* ------------------------------------------------------------------ */
/*
 * Firma, Filiale oder Lager fehlt — siehe inc/navigation.php. Der Punkt
 * bleibt sichtbar und ist nicht anwählbar.
 *
 * Die Sperre steckt im HTML und nicht hier: Gezeichnet wird ein <span>
 * ohne href, und damit gibt es nichts zu klicken, auch nicht per
 * Tastatur. Dieses Regelwerk sagt es nur AN — eine reine CSS-Sperre
 * (`pointer-events: none`) sähe gleich aus und ließe den Punkt für die
 * Tabulatortaste offen.
 *
 * 55 % Deckkraft und nicht weniger: Der Punkt soll lesbar bleiben. Wer
 * ihn nicht mehr entziffern kann, sucht ihn beim nächsten Mal woanders.
 */
.app-nav-link.app-nav-locked {
  opacity: .55;
  cursor: not-allowed;
}
.app-nav-link.app-nav-locked:hover { background: transparent; }
.app-nav-lock { flex: 0 0 auto; font-size: .7rem; opacity: .8; }
/* In der schmalen Symbolleiste ist für das Schloss kein Platz; dort
   trägt die Deckkraft die Aussage allein, und der Tooltip nennt sie. */
.nav-collapsed .app-nav-lock { display: none; }

/* --------------------- Eingeklappt: reine Symbolleiste ------------- */
/* Beschriftungen, Modulüberschriften und Pfeile verschwinden; an ihre
   Stelle tritt der Tooltip, den das Skript aus data-nav-title baut.
   Untermenüs klappen zu, weil eingerückte Einträge ohne Text nicht mehr
   unterscheidbar wären. */
.nav-collapsed .app-nav-text,
.nav-collapsed .app-nav-caret { display: none; }

.nav-collapsed .app-nav-module-label {
  height: 1px; padding: 0; margin: .7rem .75rem;
  overflow: hidden; color: transparent;
  background: var(--bs-border-color);
}
/* Der erste Abschnitt braucht keinen Trennstrich — darüber steht nichts. */
.nav-collapsed .app-nav-module:first-child .app-nav-module-label { display: none; }

.nav-collapsed .app-nav-link { justify-content: center; padding: .6rem 0; gap: 0; }
.nav-collapsed .app-nav-child { padding-left: 0; }
.nav-collapsed .app-nav-sub { display: none; }
.nav-collapsed .app-nav-icon { flex: 0 0 auto; font-size: 1.15rem; }

/* ------------------------- Schmale Geräte ------------------------- */
/* Unterhalb 992px wird aus der Leiste eine Schublade, die über den
   Inhalt fährt. Ohne diese Umschaltung bliebe auf einem Tablet im
   Hochformat kaum Platz für die Tabelle. */
@media (max-width: 991.98px) {
  .app-sidebar {
    position: fixed; left: 0; top: var(--header-height); z-index: 1040;
    width: var(--nav-width); flex-basis: var(--nav-width);
    transform: translateX(-100%);
    transition: transform .2s ease;
    box-shadow: .5rem 0 1.5rem rgba(0,0,0,.18);
  }
  body.app.nav-open .app-sidebar { transform: translateX(0); }

  /* Auf schmalen Geräten ist die Leiste entweder ganz da oder ganz weg —
     eine Symbolleiste wäre neben der Schublade nur verwirrend. */
  body.app.nav-collapsed .app-nav-text,
  body.app.nav-collapsed .app-nav-caret { display: inline; }
  body.app.nav-collapsed .app-nav-link { justify-content: flex-start; padding: .5rem 1rem; gap: .7rem; }
  body.app.nav-collapsed .app-nav-child { padding-left: 2.1rem; }
  body.app.nav-collapsed .app-nav-sub { display: block; }
  body.app.nav-collapsed .app-nav-module-label {
    height: auto; padding: .85rem 1rem .35rem; margin: 0;
    color: var(--bs-secondary-color); background: none;
  }

  .app-sidebar-backdrop {
    position: fixed; inset: var(--header-height) 0 0 0; z-index: 1035;
    background: rgba(0,0,0,.4);
  }
}

/* --------------------------- Druckansicht ------------------------- */
@media print {
  .app-header, .app-sidebar, .app-sidebar-backdrop { display: none !important; }
  .app-shell { display: block; }
  .app-main { width: 100%; }
}

/* Tabellen */
/*
 * Feststehende Spaltenüberschriften — zwei Fehler, beide beim Einbau von
 * DataTables aufgefallen und beide gemessen.
 *
 * ERSTENS stand hier `top: 0`. Die Kopfzeile der Anwendung ist aber
 * selbst klebend und --header-height hoch; die Spaltenzeile schob sich
 * also darunter und war weg. Jetzt beginnt sie darunter.
 *
 * ZWEITENS — und das war der schwerere Fall — wirkt `position: sticky`
 * nur gegenüber dem nächsten scrollenden Vorfahren. `.table-responsive`
 * ist wegen seines `overflow-x: auto` genau so einer, scrollt aber
 * senkrecht nicht mit. In items.php und inventory_edit.php klebte die
 * Zeile deshalb überhaupt nicht: gemessen `top = -858px` nach dem
 * Scrollen, also längst aus dem Bild. Nur in catalog_import.php ging es,
 * weil dort `max-height:420px` am Rahmen steht und er dadurch
 * tatsächlich scrollt — vermutlich der Grund, warum es niemandem
 * aufgefallen ist.
 *
 * Die Zeile unten stellt das für den Fall ohne eigene Höhe richtig: Ein
 * `.table-responsive`, das senkrecht nicht scrollen soll, darf auch kein
 * Sichtfenster aufspannen. Wo eine `max-height` gesetzt ist, greift die
 * Regel nicht — dort ist das Fenster gewollt.
 *
 * Behoben ist hier nur der ERSTE Fehler, und zwar über eine Variable:
 * Klebt die Tabelle gegenüber der Seite, ist die Kopfzeile der
 * Anwendung im Weg und --header-height der richtige Versatz. Klebt sie
 * dagegen in einem eigenen Sichtfenster — catalog_import.php gibt ihrem
 * Rahmen eine max-height —, ist 0 richtig, und der Rahmen setzt
 * --sticky-top selbst.
 *
 * Der ZWEITE Fehler ist mit 0.8-260800015 behoben, und zwar NICHT durch
 * das Aufgeben des waagerechten Scrollens — das wäre auf einer breiten
 * Tabelle keine Verbesserung gewesen, sondern ein Tausch. Behoben ist er
 * durch die Umkehrung: Wenn `.table-responsive` ohnehin ein
 * Sichtfenster aufspannt, soll es eines SEIN. `.table-window` gibt ihm
 * eine Höhe, damit es senkrecht scrollt, und setzt --sticky-top auf 0 —
 * dann klebt die Spaltenzeile am oberen Rand des Fensters, so wie sie es
 * in catalog_import.php seit jeher tut.
 *
 * Der Weg über eine Höhe und nicht über den Wegfall des Rahmens hat drei
 * Vorteile: Das waagerechte Scrollen bleibt in der Tabelle und reißt
 * nicht die ganze Seite mit; die Blätterleiste unter der Tabelle bleibt
 * sichtbar; und der Bezugsrahmen ist derselbe wie der, in dem gescrollt
 * wird — das ist die Bauform, für die `position: sticky` gedacht ist.
 */
.table-sticky thead th {
  position: sticky;
  top: var(--sticky-top, var(--header-height, 0));
  z-index: 2;
  background: var(--bs-body-bg);
  box-shadow: inset 0 -1px 0 var(--bs-border-color);
}

/*
 * Eine Tabelle in einem eigenen Sichtfenster. Zusammen mit
 * .table-responsive und .table-sticky zu verwenden.
 *
 * 70vh und keine feste Pixelzahl: Auf einem Notebook sind 420 px die
 * halbe Liste, auf einem Werkstattmonitor ein Viertel. Wer einen anderen
 * Wert braucht, setzt --table-window-height am Rahmen.
 */
.table-window {
  max-height: var(--table-window-height, 70vh);
  --sticky-top: 0;
}
.table td, .table th { vertical-align: middle; }
.table-compact td, .table-compact th { padding: .35rem .5rem; font-size: .9rem; }

.sort-link { color: inherit; text-decoration: none; white-space: nowrap; }
.sort-link:hover { text-decoration: underline; }

.mono { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; }
.partno { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: .02em; }

.kpi-card .kpi-value { font-size: 1.75rem; font-weight: 600; line-height: 1.1; }
.kpi-card .kpi-label { font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; }

.attr-row .form-control, .attr-row .form-select { font-size: .9rem; }

.filter-card { background: var(--bs-tertiary-bg); }

.diff-plus  { color: #157347; font-weight: 600; }
.diff-minus { color: #b02a37; font-weight: 600; }
[data-bs-theme="dark"] .diff-plus  { color: #4ad07d; }
[data-bs-theme="dark"] .diff-minus { color: #ff7b8a; }

/* Druckansicht der Inventurlisten */
@media print {
  .d-print-none { display: none !important; }
  body { font-size: 11pt; background: #fff; }
  main { padding: 0 !important; }
  .print-sheet { break-inside: auto; }
  table { border-collapse: collapse !important; width: 100%; }
  table th, table td { border: 1px solid #999 !important; padding: 3px 5px !important; }
  thead { display: table-header-group; }
  tr { break-inside: avoid; }
  .count-box { display: inline-block; min-width: 90px; border-bottom: 1px solid #000; height: 1.2em; }
}

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

/*
 * Das Bild liegt UNTER dem Verlauf und nicht an seiner Stelle.
 *
 * Zwei Gründe, und beide sind Betrieb und nicht Geschmack:
 *
 *   * Der Verlauf ist da, BEVOR das Bild geladen ist — und er ist da,
 *     wenn es fehlt. Eine Anmeldeseite, deren Schrift erst lesbar wird,
 *     wenn 50 kB angekommen sind, ist auf einer schmalen Leitung ein
 *     weisser Text auf weissem Grund.
 *   * Der Verlauf ist halbdurchsichtig und dunkelt das Foto ab. Ohne
 *     ihn stünde die weisse Schrift auf einer Werkstatt mit hellen
 *     Leuchten. `tests/sichtbar.py` misst das nach.
 *
 * Reihenfolge in `background`: die oberste Schicht zuerst.
 */
.auth-body {
  /*
   * OHNE `color-mix` — und das ist eine Korrektur (1.0-260800157).
   *
   * Bis 156 stand hier eine zweite `background`-Angabe mit
   * `color-mix(in srgb, …, transparent)`, davor eine undurchsichtige als
   * Rückfall. Der Gedanke war richtig und die Ausführung falsch: Ein
   * Browser, der `color-mix` nicht kennt, verwirft die ganze zweite
   * Angabe — MITSAMT DEM BILD — und behält die erste, in der kein Bild
   * steht. Das Foto verschwand also lautlos, und zwar genau dort, wo
   * niemand nachsieht.
   *
   * Ein Rückfall darf nicht das Wichtigste wegnehmen. Deshalb jetzt
   * `rgba()`: verstanden seit CSS 3, und das Bild steht in derselben
   * Angabe wie der Schleier darüber. Die drei Werte sind dieselben
   * Farben wie --app-auth-1/2/3, nur mit Deckkraft; sie stehen hier
   * ausgeschrieben, weil sich eine Hex-Farbe nicht in ein rgba()
   * einsetzen lässt.
   *
   * Fehlt die Bilddatei, bleibt die Farbe darunter — die Seite ist dann
   * schlichter und lesbar. `tools/assets_check.php` sorgt dafür, dass
   * das nicht unbemerkt passiert.
   */
  background-color: var(--app-auth-1);
  background-image:
    linear-gradient(160deg,
        rgba(43, 47, 51, .55) 0%,     /* #2b2f33 */
        rgba(63, 70, 77, .45) 55%,    /* #3f464d */
        rgba(85, 96, 106, .70) 100%), /* #55606a */
    url("bilder/login-werkstatt.jpg");
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  background-attachment: fixed;
  min-height: 100vh;
}

/*
 * Der Nachweis zum Bild.
 *
 * Er steht IM Bild und nicht im Impressum: Wer die Anmeldeseite sieht,
 * sieht den Hinweis. Klein, unten links, ausserhalb der Karte — er soll
 * niemanden bei der Anmeldung stören und trotzdem dastehen.
 */
.auth-bildnachweis {
  position: fixed;
  left: 1rem;
  bottom: .75rem;
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .72rem;
  line-height: 1.2;
  /*
   * Auch hier rgba() und kein `color-mix`: Ohne Unterstützung fiele die
   * Farbe ersatzlos weg, der Text erbte die dunkle Schrift des Körpers
   * und stünde dunkel auf dunkel. Ein Rechtehinweis, den man nicht
   * lesen kann, ist keiner.
   */
  color: rgba(255, 255, 255, .72);
  pointer-events: none;
}

.auth-bildnachweis img {
  /* 40 px Höhe, wie vom Rechteinhaber verlangt. Die Datei ist doppelt
     so hoch, damit sie auf feinen Bildschirmen nicht ausfranst. */
  height: 40px;
  width: auto;
  opacity: .85;
}

@media (max-width: 575.98px) {
  /* Auf dem Telefon steht der Nachweis unter der Karte statt daneben:
     Fest positioniert liefe er über das Passwortfeld. */
  .auth-bildnachweis { position: static; justify-content: center; margin-top: 1.5rem; }
}

.auth-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 2rem 1rem;
}

.auth-card {
  width: 100%;
  max-width: 27rem;
}

/*
 * Was AUSSERHALB des weissen Kärtchens steht, steht auf dem dunklen
 * Verlauf und muss hell sein. Zwei Fehler steckten hier, beide am
 * 31.08.2026 an einem Bild fürs Handbuch gefunden — nicht an einem
 * Fehler, denn es gab keinen:
 *
 * 1. Ohne das ">" griff die Regel INS Kärtchen hinein. Der Hinweis auf
 *    die Kontosperre unter dem Anmeldeformular trägt `text-center` und
 *    stand deshalb weiss auf weiss: im HTML vorhanden, am Bildschirm
 *    nicht.
 *
 * 2. `.text-body-secondary` ist bei Bootstrap mit `!important`
 *    geschrieben. Diese Regel hatte es nicht — sie war also von Anfang
 *    an WIRKUNGSLOS, und die beiden Zeilen unter dem Schriftzug
 *    („Automotive Repairshop Enterprise Solution", der Firmenname)
 *    standen dunkelgrau auf dunklem Verlauf. Gemessen: Der hellste und
 *    der dunkelste Bildpunkt lagen 30 von 255 Stufen auseinander.
 *
 * Die Ausnahme für das Kärtchen ist damit entfallen: Diese Regeln
 * reichen nicht mehr hinein, und eine Ausnahme von etwas, das nicht
 * mehr eintritt, sieht beim Lesen aus wie ein nötiger Schutz.
 *
 * `tests/sichtbar.py` lichtet beides jetzt ab und misst nach.
 */
.auth-card .brand-mark,
.auth-card h1,
.auth-card > p.text-center {
  color: var(--app-auth-fg);
}

.auth-card > .text-center .text-body-secondary,
.auth-card > p.text-body-secondary {
  color: var(--app-auth-fg) !important;
}

/*
 * Verweise, die AUSSERHALB des Kärtchens auf dem Bild liegen.
 *
 * „Zurück zu ARES" auf der Anmeldeseite von API-Connect trägt
 * `link-secondary` — gedacht für einen hellen Grund. Auf dem
 * Werkstattbild war der Verweis kaum zu erkennen. Dass er unauffällig
 * sein soll, heisst nicht, dass er unsichtbar sein darf.
 *
 * `!important`, weil `.link-secondary` bei Bootstrap ebenfalls so
 * geschrieben ist — dieselbe Lehre wie bei `.text-body-secondary`.
 */
.auth-card > p a,
.auth-card > .text-center a {
  color: rgba(255, 255, 255, .85) !important;
  text-decoration-color: rgba(255, 255, 255, .45);
}

.auth-card > p a:hover,
.auth-card > .text-center a:hover {
  color: #fff !important;
}

.brand-mark-lg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  /* "ARES" statt eines Zwei-Zeichen-Kürzels: kleinere Schrift und keine
     Sperrung, sonst läuft der Schriftzug aus dem Kreis. */
  font-size: .78rem;
  letter-spacing: .02em;
  border-radius: 50%;
}

/* Kürzel des angemeldeten Benutzers in der Navigationsleiste */
.user-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--app-header-chip);
  border: 1px solid var(--app-header-line);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .02em;
}


/* ==================================================================== */
/* Dunkles Farbschema                                                    */
/*                                                                       */
/* Bootstrap dreht mit data-bs-theme="dark" die Grundfarben um, aber     */
/* nicht die kontextbezogenen Zusätze: .table-light behält seine feste   */
/* helle Fläche und schwarze Schrift. Auf dunklem Grund ergibt das       */
/* schwarze Schrift auf fast schwarzer Fläche — der Tabellenkopf ist     */
/* dann schlicht nicht zu lesen. Diese Zusätze werden hier nachgezogen.  */
/* ==================================================================== */

[data-bs-theme="dark"] .table-light {
  --bs-table-color:          var(--bs-emphasis-color);
  --bs-table-bg:             var(--bs-tertiary-bg);
  --bs-table-border-color:   var(--bs-border-color);
  --bs-table-striped-color:  var(--bs-emphasis-color);
  --bs-table-striped-bg:     var(--bs-secondary-bg);
  --bs-table-hover-color:    var(--bs-emphasis-color);
  --bs-table-hover-bg:       var(--bs-secondary-bg);
}

/* Unterschreitung des Mindestbestands und Inventurdifferenz: gedämpftes
   Bernstein statt des hellen Warngelbs, damit die Zeile auffällt, ohne
   als heller Balken aus der Tabelle zu springen. */
[data-bs-theme="dark"] .table-warning {
  --bs-table-color:          #ffe08a;
  --bs-table-bg:             #3a2f10;
  --bs-table-border-color:   #574716;
  --bs-table-striped-color:  #ffe08a;
  --bs-table-striped-bg:     #43370f;
  --bs-table-hover-color:    #fff0c2;
  --bs-table-hover-bg:       #4a3c12;
}

/* Kennzeichnungen wie "CSV", "EXPRESS" oder die Zahl der Eigenschaften */
[data-bs-theme="dark"] .badge.text-bg-light {
  background-color: var(--bs-tertiary-bg) !important;
  color: var(--bs-body-color) !important;
}

/* Das Herstellerabzeichen und alles andere mit .text-bg-dark.
 *
 * Gemessen, nicht vermutet: Im dunklen Design ist der Hintergrund von
 * .text-bg-dark EXAKT die Seitenfarbe — Kontrast 1,00 : 1. Der weiße
 * Text bleibt lesbar, aber das Abzeichen ist keines mehr; aus einem
 * Block wird ein Wort, das zwischen den übrigen Wörtern der Zeile
 * verschwindet.
 *
 * Gedreht wird deshalb dasselbe, was Bootstrap im hellen Design tut,
 * nur andersherum: dort dunkle Fläche mit heller Schrift, hier helle
 * Fläche mit dunkler Schrift. Das erhält die Bedeutung — .text-bg-dark
 * ist die STARKE Kennzeichnung, .text-bg-light die leise —, statt
 * beide auf denselben grauen Kasten zu legen.
 *
 * --bs-secondary-color und nicht --bs-emphasis-color: Letzteres ist
 * reines Weiß, und zwanzig weiße Blöcke in einer Bestandsliste sind
 * lauter als die Zeilen, die sie kennzeichnen. */
[data-bs-theme="dark"] .badge.text-bg-dark {
  background-color: var(--bs-secondary-color) !important;
  color: var(--bs-body-bg) !important;
}

/* Die Filterleiste hebt sich im hellen Design durch eine hellere Fläche
   ab; im dunklen muss sie dafür dunkler werden als der Inhalt. */
[data-bs-theme="dark"] .filter-card { background: var(--bs-secondary-bg); }

/* ==================================================================== */
/* Kopfzeile bei heller Firmenfarbe                                      */
/*                                                                       */
/* .btn-outline-light zeichnet weiß auf durchsichtig — auf einer hellen  */
/* Hausfarbe verschwindet die Schaltfläche damit fast. Sie folgt         */
/* deshalb derselben Vordergrundfarbe wie der übrige Kopfzeilentext.     */
/* ==================================================================== */
.app-header .btn-outline-light {
  --bs-btn-color: var(--app-header-fg);
  --bs-btn-border-color: var(--app-header-line);
  --bs-btn-hover-bg: var(--app-header-hover);
  --bs-btn-hover-color: var(--app-header-fg);
  --bs-btn-hover-border-color: var(--app-header-fg);
  --bs-btn-active-bg: var(--app-header-hover);
  --bs-btn-active-color: var(--app-header-fg);
  --bs-btn-active-border-color: var(--app-header-fg);
}

/* Vorschau des Logos in der Maske "Erscheinungsbild": zeigt den echten
   Untergrund, auf dem das Logo später steht, und nicht ein festes
   Anthrazit — bei heller Hausfarbe wäre das irreführend. */
.logo-preview {
  background: var(--mb-anthracite);
  color: var(--app-header-fg);
}

/* ==================================================================== */
/* Feldbreiten in Prozent (ab Tablet)                                    */
/*                                                                       */
/* Das Zwölfer-Raster von Bootstrap kennt 25, 33⅓, 50 und 75 Prozent,    */
/* aber weder 20, 30 noch 40. Die Kundenanschrift verlangt genau diese   */
/* Aufteilung (PLZ 20 / Ort 50 / Land 30 und Telefon 30 / Mobil 30 /     */
/* E-Mail 40), deshalb diese Handvoll Klassen. Sie greifen erst ab       */
/* 768 px; darunter steht jedes Feld über die ganze Breite, so wie es    */
/* auf einem Telefon auch sein muss.                                     */
/* ==================================================================== */
@media (min-width: 768px) {
  .fw-20 { flex: 0 0 20%; width: 20%; }
  .fw-30 { flex: 0 0 30%; width: 30%; }
  .fw-40 { flex: 0 0 40%; width: 40%; }
  .fw-50 { flex: 0 0 50%; width: 50%; }
  .fw-60 { flex: 0 0 60%; width: 60%; }
}

/* ==================================================================== */
/* Ersetzungskette: der Baum im Informationsfenster                      */
/*                                                                       */
/* Ein Baum ist eine Liste in einer Liste — deshalb <ul>, und nicht       */
/* Eingerückt wird je ZWEIG und nicht je Stufe. Ein Baum rückt sonst je    */
/* Ebene ein; bei der tiefsten echten Kette — 22 Stufen — wäre das eine    */
/* Treppe über 22 Spalten, und die letzte Nummer stünde am rechten Rand.   */
/* Wie weit eine Nummer entfernt ist, sagt die Stufennummer links.         */
/*                                                                        */
/* Die Linien entstehen hier und nicht im Text, damit eine kopierte Kette  */
/* aus Teilenummern besteht und nicht aus Strichen.                       */
/* ==================================================================== */
.kette { --einzug: 1.5rem; --stufeneinzug: .45rem; }

.kette-zeile {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  padding: .25rem .4rem;
  padding-left: calc(.4rem + var(--ebene) * var(--einzug));
  position: relative;
  border-left: 3px solid transparent;
}

/* Die senkrechte Linie des Zweiges, in dem die Zeile steht. */
.kette-zeile::before {
  content: "";
  position: absolute;
  left: calc(1.45rem + var(--ebene) * var(--einzug));
  top: 0;
  bottom: 0;
  border-left: 1px solid var(--bs-border-color);
}

/* Der waagerechte Ast: nur dort, wo ein Zweig ansetzt. */
.kette-zweig::after {
  content: "";
  position: absolute;
  left: calc(1.45rem + (var(--ebene) - 1) * var(--einzug));
  top: .95rem;
  width: calc(var(--einzug) - .1rem);
  border-top: 1px solid var(--bs-border-color);
}

.kette-spur {
  position: relative;
  z-index: 1;
  width: 1.4rem;
  flex: none;
  text-align: center;
  color: var(--bs-secondary-color);
  background: var(--bs-body-bg);
}

.kette-stufennr {
  width: 2.1rem;
  flex: none;
  font-variant-numeric: tabular-nums;
  color: var(--bs-secondary-color);
  font-size: .85em;
  text-align: right;
}

/* Die feine Treppe: Abstand zum aktuellen Artikel.                       */
/*                                                                        */
/* Sie sitzt am INHALT und nicht an der Zeile: Pfeil und Stufennummer      */
/* bleiben dadurch in ihrer Spalte, und die senkrechten Linien des Baumes  */
/* verschieben sich nicht gegen die Zeichen, an denen sie hängen.          */
/*                                                                        */
/* Gedeckelt bei 16 Stufen. Die tiefste gemessene Kette geht über 22; ohne */
/* Deckel wäre eine kranke Kette über 60 Stufen 27 rem weit draußen.       */
/* Wie weit es wirklich ist, sagt weiterhin die Zahl links — der Deckel    */
/* nimmt der Darstellung Genauigkeit, aber keine Auskunft.                 */
.kette-inhalt {
  flex: 1 1 auto;
  min-width: 0;
  padding-left: calc(min(var(--stufe, 0), 16) * var(--stufeneinzug));
}
.kette-zusatz { display: block; font-size: .85em; color: var(--bs-secondary-color); }
.kette-kreis  { display: block; font-size: .85em; color: var(--bs-danger); }

.kette-vermerk {
  font-size: .82em;
  color: var(--bs-secondary-color);
  padding: .1rem .4rem .1rem 0;
  padding-left: calc(3.9rem + var(--ebene) * var(--einzug)
                   + min(var(--stufe, 0), 16) * var(--stufeneinzug));
}

/* Auf dem Telefon ist die Breite knapp: dort eine feinere Treppe. Sie ist
   dann kaum noch zu sehen — die Stufennummer bleibt die verlässliche
   Auskunft, die Einrückung war immer nur die schnelle. */
@media (max-width: 575.98px) {
  .kette { --stufeneinzug: .2rem; }
}

/* Der aktuelle Artikel. Das ist KEINE Aussage über eine Ersetzung,       */
/* sondern die Antwort auf „wo stehe ich".                                */
.kette-aktuell {
  border-left-color: var(--bs-primary);
  background: color-mix(in srgb, var(--bs-primary) 8%, transparent);
  border-radius: .25rem;
  padding-top: .45rem;
  padding-bottom: .45rem;
}
.kette-aktuell .kette-spur { color: var(--bs-primary); background: transparent; }

/* Das Ende eines Zweiges. Bewusst KEIN Grün: Grün hieße „nimm dieses",   */
/* und das wäre eine Empfehlung. Ein Strich sagt, was zutrifft — hier     */
/* hört die hinterlegte Kette auf.                                        */
.kette-ende { border-left-color: var(--bs-secondary-color); }

/* Das Fenster im Modal soll nicht über den Bildschirm hinauslaufen: Eine
   zwölfstufige Kette ist lang, und der Rest der Maske bleibt sichtbar. */
.chain-window {
  max-height: 70vh;
  overflow-y: auto;
}

/* Als eigene Seite gibt es kein Fenster, das begrenzt werden müsste. */
main .chain-window {
  max-height: none;
  overflow-y: visible;
}

/* ==================================================================== */
/* Einsatzplanung                                                        */
/* ==================================================================== */
/* Vier Zeitfelder je Zelle, sieben Zellen je Zeile — das wird breit.    */
/* Die Felder werden deshalb so schmal wie moeglich gehalten; laeuft die */
/* Tabelle trotzdem ueber, schiebt `table-responsive` sie seitlich. Das  */
/* ist besser als Felder, in denen eine Uhrzeit nicht mehr lesbar ist.   */

.einsatz-tabelle td,
.einsatz-tabelle th { vertical-align: top; }

.einsatz-zelle input[type="time"] {
  min-width: 5.6rem;
  padding-left: .25rem;
  padding-right: .25rem;
}
.einsatz-zelle input[type="number"] { max-width: 4.2rem; }

/* Der Wochenplan unter der Zelle. Er bleibt sichtbar, auch wenn eine    */
/* Korrektur gilt — nur so sieht man, WOVON sie abweicht.                */
.einsatz-plan {
  margin-top: .15rem;
  line-height: 1.2;
}

/* Die Anwesenheitszeiten am Einsatzort: eine eigene Zeile unter der     */
/* Zuordnung, ohne trennenden Strich dazwischen — sie gehoert dazu.      */
.einsatz-zeiten > td { border-top: 0; }
.einsatz-zeiten summary { cursor: pointer; }

/* ==================================================================== */
/* Abgeleitete Werte in der Feldzuordnung                                */
/* ==================================================================== */
/* Das Eingabefeld haengt sichtbar unter seiner Auswahlliste — als eine  */
/* Sache und nicht als zwei nebeneinander. Ohne Skript steht es immer    */
/* da; assets/app.js blendet aus, was zur gewaehlten Art nicht gehoert.  */

.regel-feld { margin-bottom: .55rem; }
.regel-label { min-width: 11rem; }
.regel-feld-aktiv > .input-group > .input-group-text {
  background: color-mix(in srgb, var(--bs-primary) 10%, var(--bs-tertiary-bg));
}

/* Der Satz fuer alle, die Regeln sehen, aber nicht aendern duerfen. */
.regel-fest {
  background: var(--bs-tertiary-bg);
  color: var(--bs-secondary-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.regel-eingabe {
  margin-left: 11rem;
  padding: .45rem .6rem;
  border: 1px solid var(--bs-border-color);
  border-top: 0;
  border-radius: 0 0 .25rem .25rem;
  background: var(--bs-tertiary-bg);
}

.regel-hilfe    { font-size: .78em; color: var(--bs-secondary-color); margin-top: .25rem; }
.regel-ergebnis { font-size: .85em; margin-top: .3rem; }
.regel-pfeil    { color: var(--bs-secondary-color); }
.regel-quelle   { font-size: .85em; color: var(--bs-secondary-color); }

/* Auf dem Telefon steht die Beschriftung ueber dem Feld; dann waere ein */
/* Einzug von 11rem der halbe Bildschirm.                                */
@media (max-width: 767.98px) {
  .regel-eingabe { margin-left: 0; }
}

/* ==================================================================== */
/* Anzeigedichte „kompakt"                                               */
/*                                                                       */
/* Bootstrap ist für Webseiten gesetzt, nicht für Erfassungsmasken. Seine */
/* Abstände sind großzügig, und das ist an einer Verkaufsseite richtig —  */
/* an einem Arbeitsplatz, an dem jemand acht Stunden lang Auftragszeilen  */
/* liest, kostet es Zeilen. Gemessen an der Kundenmaske gingen von 1.842  */
/* Pixeln Inhaltshöhe rund ein Drittel auf Zwischenräume.                 */
/*                                                                       */
/* Diese Schicht halbiert die ABSTÄNDE und lässt die ELEMENTE weitgehend  */
/* in Ruhe. Das ist die eigentliche Regel dahinter:                       */
/*                                                                       */
/*   * Ein Eingabefeld geht von 38 auf 32 Pixel — spürbar kleiner, aber   */
/*     weit über der Grenze, ab der Zielen mit der Maus mühsam wird.      */
/*   * Kein anklickbares Element fällt unter 28 Pixel Höhe.               */
/*   * Die Schriftgröße bleibt unverändert. Wer die Abstände zusammen-    */
/*     zieht UND die Schrift verkleinert, spart zweimal und liest nichts  */
/*     mehr; das eine ist eine Platzfrage, das andere eine Sehfrage.      */
/*   * Waagerechte Abstände bleiben größtenteils stehen. Beengt wirkt     */
/*     eine Maske durch enge Zeilen, nicht durch enge Spalten — und ein   */
/*     Text ohne Luft nach links liest sich schlecht.                     */
/*                                                                       */
/* Umgeschaltet wird unter „Mein Konto → Anzeige". Ohne Angabe gilt       */
/* kompakt; „normal" stellt die ursprünglichen Abstände wieder her, indem */
/* diese ganze Schicht nicht greift. Sie hängt deshalb ausnahmslos an     */
/* [data-density="kompakt"] — eine Regel ohne diesen Vorsatz wäre eine    */
/* Regel, die sich nicht mehr abschalten lässt.                           */
/* ==================================================================== */

/* --------------------------- Seitenrahmen -------------------------- */
[data-density="kompakt"] main.container-fluid { padding-top: .75rem; padding-bottom: .75rem; }

[data-density="kompakt"] footer { margin-top: 1rem !important; }
[data-density="kompakt"] footer.py-3 { padding-top: .4rem !important; padding-bottom: .4rem !important; }

/* ------------------------------ Karten ----------------------------- */
[data-density="kompakt"] .card {
  --bs-card-spacer-y: .625rem;
  --bs-card-spacer-x: .75rem;
  --bs-card-cap-padding-y: .4rem;
  --bs-card-cap-padding-x: .75rem;
}
[data-density="kompakt"] .card-body   { padding: .625rem .75rem; }
[data-density="kompakt"] .card-header,
[data-density="kompakt"] .card-footer { padding: .4rem .75rem; }
/* Eine Karte, die nur eine Tabelle enthält, braucht gar keinen Innenraum —
   die Zellen bringen ihren eigenen mit. */
[data-density="kompakt"] .card > .table-responsive > .table { margin-bottom: 0; }

/* ----------------------------- Formulare --------------------------- */
/* 32 px Höhe: 16 px Schrift × 1,5 Zeilenhöhe = 24, dazu 2 × 3 Polster
   und 2 × 1 Rahmen. */
[data-density="kompakt"] .form-control,
[data-density="kompakt"] .form-select,
[data-density="kompakt"] .input-group-text {
  padding-top: .1875rem; padding-bottom: .1875rem;
}
[data-density="kompakt"] .form-control-sm,
[data-density="kompakt"] .form-select-sm {
  padding-top: .125rem; padding-bottom: .125rem;
}
[data-density="kompakt"] textarea.form-control { padding-top: .3rem; padding-bottom: .3rem; }

[data-density="kompakt"] .form-label { margin-bottom: .15rem; }
[data-density="kompakt"] .form-text  { margin-top: .1rem; font-size: .78em; }
[data-density="kompakt"] .col-form-label { padding-top: .1875rem; padding-bottom: .1875rem; }

/* Schaltflächen folgen den Feldern, damit beide in einer Zeile bündig
   stehen; die kleine Ausführung bleibt bei 29 px. */
[data-density="kompakt"] .btn { padding-top: .1875rem; padding-bottom: .1875rem; }
[data-density="kompakt"] .btn-sm { padding-top: .1875rem; padding-bottom: .1875rem; }

[data-density="kompakt"] .form-check     { min-height: 1.25rem; margin-bottom: .1rem; }
[data-density="kompakt"] .form-switch    { min-height: 1.35rem; }

/* ------------------------------ Tabellen --------------------------- */
[data-density="kompakt"] .table {
  --bs-table-cell-padding-y: .25rem;
  --bs-table-cell-padding-x: .45rem;
}
[data-density="kompakt"] .table > :not(caption) > * > * { padding: .25rem .45rem; }
[data-density="kompakt"] .table-sm > :not(caption) > * > * { padding: .15rem .35rem; }
/* Eine Zelle, in der ein Eingabefeld steht, darf nicht enger sein als das
   Feld — sonst schneidet der Rahmen an. */
[data-density="kompakt"] .table td > .form-control,
[data-density="kompakt"] .table td > .form-select { margin: 0; }

/* ------------------------- Weitere Bausteine ----------------------- */
[data-density="kompakt"] .alert      { padding: .5rem .75rem; margin-bottom: .5rem; }
[data-density="kompakt"] .breadcrumb { margin-bottom: .35rem; }
[data-density="kompakt"] .nav-tabs .nav-link { padding: .3rem .75rem; }
[data-density="kompakt"] .modal-header,
[data-density="kompakt"] .modal-footer { padding: .5rem .75rem; }
[data-density="kompakt"] .modal-body   { padding: .625rem .75rem; }
[data-density="kompakt"] .list-group-item { padding: .35rem .625rem; }
[data-density="kompakt"] .pagination    { margin-bottom: 0; }
[data-density="kompakt"] .page-link     { padding-top: .2rem; padding-bottom: .2rem; }
[data-density="kompakt"] h1, [data-density="kompakt"] h2,
[data-density="kompakt"] h3, [data-density="kompakt"] h4 { margin-bottom: .35rem; }
[data-density="kompakt"] p:last-child { margin-bottom: 0; }

/* --------------------------- Seitenleiste -------------------------- */
[data-density="kompakt"] .app-nav { padding: .4rem 0 1rem; }
[data-density="kompakt"] .app-nav-link { padding: .3rem 1rem; }
[data-density="kompakt"] .app-nav-module-label { padding: .5rem 1rem .2rem; }
[data-density="kompakt"] .nav-collapsed .app-nav-link { padding: .45rem 0; }

/* -------------------- Abstandsklassen von Bootstrap ---------------- */
/* Die Klassen m-*, p-* und g-* sind einkompiliert und lassen sich nicht
   über eine Variable umstellen — deshalb werden hier genau die
   überschrieben, die in ARES tatsächlich vorkommen. Sie tragen bei
   Bootstrap !important; die Überschreibung braucht es deshalb auch, und
   sie gewinnt über die höhere Spezifität des Vorsatzes.
   Waagerechte Klassen (ms-*, px-*) fehlen mit Absicht. */
[data-density="kompakt"] .mb-1 { margin-bottom: .15rem !important; }
[data-density="kompakt"] .mb-2 { margin-bottom: .25rem !important; }
[data-density="kompakt"] .mb-3 { margin-bottom: .5rem  !important; }
[data-density="kompakt"] .mb-4 { margin-bottom: .75rem !important; }
[data-density="kompakt"] .mt-1 { margin-top: .15rem !important; }
[data-density="kompakt"] .mt-2 { margin-top: .25rem !important; }
[data-density="kompakt"] .mt-3 { margin-top: .5rem  !important; }
[data-density="kompakt"] .mt-4 { margin-top: .75rem !important; }
[data-density="kompakt"] .mt-5 { margin-top: 1rem   !important; }
[data-density="kompakt"] .my-1 { margin-top: .15rem !important; margin-bottom: .15rem !important; }
[data-density="kompakt"] .my-3 { margin-top: .5rem  !important; margin-bottom: .5rem  !important; }
[data-density="kompakt"] .my-4 { margin-top: .75rem !important; margin-bottom: .75rem !important; }

[data-density="kompakt"] .py-1 { padding-top: .15rem !important; padding-bottom: .15rem !important; }
[data-density="kompakt"] .py-2 { padding-top: .25rem !important; padding-bottom: .25rem !important; }
[data-density="kompakt"] .py-3 { padding-top: .5rem  !important; padding-bottom: .5rem  !important; }
[data-density="kompakt"] .py-4 { padding-top: .75rem !important; padding-bottom: .75rem !important; }
[data-density="kompakt"] .pt-1 { padding-top: .15rem !important; }
[data-density="kompakt"] .pt-4 { padding-top: .75rem !important; }
[data-density="kompakt"] .p-2  { padding: .25rem !important; }
[data-density="kompakt"] .p-3  { padding: .5rem  !important; }

/* Rasterabstände. g-* setzt beide Richtungen; hier wird nur die
   senkrechte halbiert, die waagerechte bleibt fast unverändert — sonst
   kleben zwei Felder nebeneinander aneinander. */
[data-density="kompakt"] .g-1 { --bs-gutter-y: .15rem; }
[data-density="kompakt"] .g-2 { --bs-gutter-y: .3rem;  --bs-gutter-x: .4rem; }
[data-density="kompakt"] .g-3 { --bs-gutter-y: .5rem;  --bs-gutter-x: .75rem; }
[data-density="kompakt"] .g-4 { --bs-gutter-y: .75rem; --bs-gutter-x: 1.1rem; }
[data-density="kompakt"] .gap-1 { gap: .15rem !important; }
[data-density="kompakt"] .gap-2 { gap: .35rem !important; }
[data-density="kompakt"] .gap-3 { gap: .5rem  !important; }

/* ----------------------------- Zeilenabstand ----------------------- */
/* Der Durchschuss ist auch ein Abstand — und in Tabellen der größte, der
   noch übrig war: Eine Zelle mit Teilenummer und Bezeichnung darunter ist
   zwei Zeilen hoch, und 1,5 Zeilenhöhe kostet dort mehr als jedes
   Zellpolster. 1,35 bleibt gut lesbar; die SCHRIFTGRÖSSE ändert sich
   nicht, sonst spart man zweimal und liest nichts mehr. */
[data-density="kompakt"] .table       { line-height: 1.35; }
[data-density="kompakt"] .form-label  { line-height: 1.25; }
[data-density="kompakt"] .form-text   { line-height: 1.3; }
[data-density="kompakt"] .card-header { line-height: 1.35; }

/* Ein Kontrollkästchen ist 1em groß — in einem Bereich mit .small also nur
   14 px. Das ist unabhängig von der Dichte zu klein zum Treffen; die
   Beschriftung daneben schaltet zwar mit, aber wer auf das Kästchen zielt,
   soll es auch erwischen. Feste Größe statt schriftabhängiger. */
.form-check-input { width: 1rem; height: 1rem; margin-top: .25em; }

/* --------------------------- Zehntelbreiten ------------------------ */
/* Bootstrap teilt die Zeile in zwölf Spalten. Drei Felder im Verhältnis
   30/30/40 lassen sich darin nicht abbilden — 12 hat keinen Zehntel. Statt
   die Aufteilung auf 4/4/4 zu runden und dem Hinweistext den Platz zu
   nehmen, den zwei Teilenummern nicht brauchen, zwei zusätzliche Klassen.

   Erst ab der mittleren Breite; darunter bleibt jedes Feld volle Breite,
   wie bei col-md-* auch. Deshalb stehen sie zusammen mit col-12. */
@media (min-width: 768px) {
  .col-md-30 { flex: 0 0 auto; width: 30%; }
  .col-md-40 { flex: 0 0 auto; width: 40%; }
}

/* ====================================================================
 * Serviceplanung — der Annahmekalender
 *
 * Eine Zeile je Serviceberater, waagerecht das Viertelstundenraster.
 * Serverseitig gezeichnet: Der mitgelieferte DayPilot Lite kann den
 * Stundenausschnitt nicht beschneiden (kein `showNonBusiness`, kein
 * `scale: 'Manual'`), und ein Tag von 00:00 bis 24:00 hätte 96 Spalten,
 * von denen die Hälfte grau ist.
 *
 * Die Spaltenzahl kommt als --svc-spalten aus PHP. Ein Raster in CSS und
 * keine Tabelle: Die Balken der Termine liegen prozentual DARÜBER, und
 * das geht über Tabellenzellen hinweg nicht.
 * ==================================================================== */
.svc-gitter {
  --svc-name: 190px;
  overflow-x: auto;
}
.svc-kopf,
.svc-zeile {
  display: flex;
  align-items: stretch;
  min-width: 100%;
}
.svc-zeile { border-top: 1px solid var(--bs-border-color); }
.svc-name {
  flex: 0 0 var(--svc-name);
  width: var(--svc-name);
  padding: .35rem .5rem;
  border-right: 1px solid var(--bs-border-color);
}
/* Das Band trägt die Zellen UND die Balken; deshalb relativ. */
.svc-band {
  position: relative;
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: repeat(var(--svc-spalten), minmax(14px, 1fr));
  min-width: calc(var(--svc-spalten) * 14px);
}
.svc-kopf .svc-band { min-height: 2rem; }

.svc-stunde {
  font-size: .72rem;
  color: var(--bs-secondary-color);
  padding-top: .35rem;
  text-align: left;
  white-space: nowrap;
  overflow: visible;
}
/* Nur die volle Stunde trägt einen Strich — sonst wäre das Band ein
   Zebramuster, in dem man die Stunde nicht mehr findet. */
.svc-vollstunde { border-left: 1px solid var(--bs-border-color); padding-left: 2px; }

.svc-zelle {
  min-height: 2.6rem;
  background: var(--bs-body-bg);
  border-left: 1px solid var(--bs-border-color-translucent);
}
.svc-zelle[data-von] { cursor: pointer; }
.svc-zelle[data-von]:hover { background: var(--bs-primary-bg-subtle); }
.svc-gewaehlt { outline: 2px solid var(--bs-primary); outline-offset: -2px; }

/* Geschlossen. Gedämpft und nicht schraffiert — dass sonntags nicht
   gearbeitet wird, ist keine Meldung. */
.svc-zelle.svc-zu {
  background: var(--bs-secondary-bg);
  cursor: default;
}
/* Offen, aber dieser Berater ist nicht da. HIER ist die Schraffur
   richtig: Ein Termin darf hineingelegt werden, aber es ist eine
   Entscheidung und kein Normalfall.
   Als Verlauf und nicht als Bilddatei — so folgt sie dem Farbschema; ein
   helles Grau als PNG wäre im dunklen Schema ein leuchtender Fleck. */
.svc-zelle.svc-nichtda {
  background: repeating-linear-gradient(
      45deg,
      var(--bs-body-bg), var(--bs-body-bg) 4px,
      var(--bs-secondary-bg) 4px, var(--bs-secondary-bg) 8px);
}

/* Der Termin. Absolut über dem Raster, prozentual gesetzt: Die Tabelle
   ist fließend breit, eine Pixelangabe hinge an der Fensterbreite beim
   Seitenaufbau. */
.svc-balken {
  position: absolute;
  top: .2rem;
  bottom: .2rem;
  display: flex;
  align-items: center;
  gap: .25rem;
  overflow: hidden;
  white-space: nowrap;
  font-size: .78rem;
  text-decoration: none;
  color: var(--bs-body-color);
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-left-width: 4px;
  border-radius: .25rem;
  padding: 0 .3rem;
}
.svc-balken:hover { color: var(--bs-body-color); border-color: var(--bs-primary); }
.svc-balken-zeit { color: var(--bs-secondary-color); font-size: .7rem; }
.svc-balken-text { overflow: hidden; text-overflow: ellipsis; }

.svc-balken.svc-geplant  { border-left-color: var(--bs-primary); }
.svc-balken.svc-da       { border-left-color: var(--bs-success); }
.svc-balken.svc-erledigt { border-left-color: var(--bs-secondary); opacity: .75; }
/* Abgesagt bleibt SICHTBAR und wird durchgestrichen. Ein Zeitraum, der
   einfach verschwindet, sieht aus wie einer, der nie belegt war — und
   dann ruft jemand denselben Kunden noch einmal an. */
.svc-balken.svc-abgesagt {
  border-left-color: var(--bs-danger);
  text-decoration: line-through;
  opacity: .6;
}

.svc-legende {
  display: inline-block;
  width: 1rem;
  height: .9rem;
  vertical-align: -1px;
  border: 1px solid var(--bs-border-color);
  background: var(--bs-body-bg);
}
.svc-legende.svc-zu { background: var(--bs-secondary-bg); }
.svc-legende.svc-nichtda {
  background: repeating-linear-gradient(
      45deg,
      var(--bs-body-bg), var(--bs-body-bg) 3px,
      var(--bs-secondary-bg) 3px, var(--bs-secondary-bg) 6px);
}

[data-density="kompakt"] .svc-zelle { min-height: 2.1rem; }
[data-density="kompakt"] .svc-gitter { --svc-name: 160px; }

/* ==================================================================
   Sichtprüfung einer Fixed-Length-Zeile   (import_format.php)
   ==================================================================
   Die Rohbytes eines Feldes, in Farbe und mit sichtbarem Leerraum.

   Der Zweck ist eng: Man soll SEHEN, wo ein Feld anfängt und aufhört.
   Ein um ein Byte verschobenes Feld zeigt sich dann daran, dass das
   erste Zeichen des Nachbarn mit hineinragt — bei einer einfarbigen
   Ausgabe fällt genau das nicht auf.

   Sechs Farben, dann von vorn. Mehr wären nicht unterscheidbar; sechs
   genügen, weil nur benachbarte Felder verglichen werden.

   Die Farben sind absichtlich hell und tragen keine Bedeutung — grün
   und rot heißen in ARES „gut" und „schlecht", und ein Feld ist keins
   von beidem. Die Bewertung steht in der Zeilenfarbe der Tabelle. */
.fixed-roh {
  font-family: var(--bs-font-monospace);
  font-size: .8125rem;
  white-space: pre;
  padding: .1rem .25rem;
  border-radius: .2rem;
  display: inline-block;
  max-width: 22rem;
  overflow-x: auto;
  vertical-align: middle;
}
.fixed-farbe-0 { background: rgba(13, 110, 253, .10); }
.fixed-farbe-1 { background: rgba(255, 193, 7,  .18); }
.fixed-farbe-2 { background: rgba(25, 135, 84,  .12); }
.fixed-farbe-3 { background: rgba(111, 66, 193, .12); }
.fixed-farbe-4 { background: rgba(214, 51, 132, .10); }
.fixed-farbe-5 { background: rgba(108, 117, 125, .16); }

/* Eine Stelle, die keine Feldbeschreibung abdeckt. Schraffiert und nicht
   nur grau: Grau wäre eine sechste Farbe und sähe aus wie ein Feld. Hier
   soll es auffallen — eine Lücke in der Definition ist meist ein
   Fehler, und die Trennspalte im Iveco-Profil ist die Ausnahme, die
   deshalb einen Namen bekommen hat. */
.fixed-luecke {
  background: repeating-linear-gradient(
    45deg, rgba(220, 53, 69, .10), rgba(220, 53, 69, .10) 3px,
    transparent 3px, transparent 6px);
}

/* Die Sätze der Sichtprüfung dürfen nicht umbrechen — sonst verschieben
   sich die Zeichen und das Abzählen wird unmöglich. Derselbe Grund wie
   beim Eingabefeld darüber. */
.fixed-zeile { white-space: pre; overflow-x: auto; font-size: .75rem; max-width: 100%; }

/* Die eingesetzte Zeile darf nicht umbrechen: Ein Umbruch verschiebt
   die Zeichen optisch und macht das Abzählen unmöglich. */
#probe_zeile { white-space: pre; overflow-x: auto; font-size: .8125rem; }

.fixed-probe td { vertical-align: middle; }

/* Die Proben unbekannter Sätze im Laufprotokoll (import_jobs.php).
   Sie leben davon, dass die Stellen untereinander liegen — also feste
   Breite, kein Umbruch, und bei Bedarf waagerecht scrollen. */
.job-proben {
  font-family: var(--bs-font-monospace);
  white-space: pre;
  overflow-x: auto;
  background: transparent;
  color: inherit;
}

/* ---------------------- Die Ziehharmonika (1.0-260800078) ---------- */
/*
 * Die Bereiche der Seitenleiste sind <details>. Der Browser klappt sie
 * selbst auf — ohne Skript. Was hier steht, ist nur das Aussehen.
 */
.app-nav-zieh > summary.app-nav-module-label{
  cursor: pointer; display: flex; align-items: center; gap: .4rem;
  user-select: none; list-style: none;
}
/* Das Standard-Dreieck weg: Wir zeichnen ein eigenes, das zur Leiste passt. */
.app-nav-zieh > summary.app-nav-module-label::-webkit-details-marker { display: none; }
.app-nav-zieh > summary.app-nav-module-label::marker { content: ""; }

.app-nav-zieh > summary:hover { color: var(--bs-body-color); }
.app-nav-zieh > summary:focus-visible { outline: 2px solid var(--mb-blue); outline-offset: -2px; }

.app-nav-zeiger{
  margin-left: auto; width: 0; height: 0; opacity: .7;
  border-style: solid; border-width: 4px 0 4px 5px;
  border-color: transparent transparent transparent currentColor;
  transition: transform .16s ease;
}
.app-nav-zieh[open] > summary .app-nav-zeiger { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .app-nav-zeiger { transition: none; } }

/*
 * Der Bereich, in dem man GERADE ist. Ein schmaler Strich am linken
 * Rand — damit man ihn beim Überfliegen findet, ohne dass er wie ein
 * angeklickter Punkt aussieht.
 */
.app-nav-hier > summary.app-nav-module-label {
  color: var(--bs-body-color); font-weight: 700;
  box-shadow: inset 3px 0 0 var(--mb-blue);
}

/*
 * In der Symbolleiste ist alles offen — die fünfte Regel.
 *
 * Das lässt sich NICHT im Stylesheet lösen. Zwei Versuche, beide
 * nachgemessen und beide wirkungslos: `display: block !important` und
 * `content-visibility: visible !important` auf den Inhalt eines
 * zugeklappten <details>. Der Browser entscheidet das über das
 * `open`-Attribut, und ein Attribut setzt kein CSS.
 *
 * Es steht deshalb an zwei anderen Stellen:
 *   · `inc/header.php` zeichnet in der Symbolleiste gar kein <details>,
 *   · `assets/app.js` klappt beim Umschalten alle auf — für den
 *     Augenblick, in dem die Seite nicht neu lädt.
 *
 * Hier bleibt nur, den Kopf unklickbar zu machen: Er ist dort nicht
 * sichtbar, und ein unsichtbarer Schalter darf nicht auf die Tastatur
 * reagieren.
 */
body.app.nav-collapsed .app-nav-zieh > summary { pointer-events: none; }

/* ------------------------------------------------------------------ */
/* Support-Code                                                        */
/* ------------------------------------------------------------------ */
/*
 * Die Kennung der Maske, klein über der Überschrift. Sie soll auf einem
 * Screenshot lesbar sein und im Alltag nicht stören — das sind zwei
 * Anforderungen, die sich widersprechen, und der Ausgleich liegt in der
 * Farbe, nicht in der Größe. Unter 11px wird sie auf einem
 * skalierten Screenshot unleserlich.
 *
 * `user-select: all`: Ein Klick markiert den ganzen Code. Ohne das
 * müsste der Anwender elf Pixel genau treffen, um ihn zu kopieren.
 *
 * KEIN `d-print-none`: Im Ausdruck wird er am ehesten gebraucht.
 */
.ares-supportcode{
  font-family: var(--bs-font-monospace, ui-monospace, monospace);
  font-size: 11px;
  line-height: 1.4;
  letter-spacing: .02em;
  color: var(--bs-secondary-color, #6c757d);
  opacity: .75;
  margin-bottom: .15rem;
  user-select: all;
  -webkit-user-select: all;
}
.ares-supportcode:hover{ opacity: 1; }

@media print{
  /* Im Ausdruck darf er ruhig deutlicher stehen — dort stört er nicht,
     und ein ausgedrucktes Formular landet oft genau im Support. */
  .ares-supportcode{ opacity: 1; color: #444; }
}

/* ------------------------------------------------------------------ */
/* Benutzerhandbuch                                                    */
/* ------------------------------------------------------------------ */
/*
 * Der Text bekommt eine LESEBREITE. Über die volle Fensterbreite wäre
 * er auf einem Werkstattbildschirm mit 27 Zoll unlesbar — das Auge
 * verliert beim Zeilenwechsel die Zeile.
 *
 * Die Bilder dürfen breiter sein als der Text: Sie zeigen eine ganze
 * Maske, und auf Lesebreite gestaucht erkennt man nichts mehr.
 */
.hb-abschnitt{ margin-top: 2.6rem; padding-top: 1.6rem; border-top: 1px solid var(--bs-border-color); }
.hb-abschnitt:first-of-type{ border-top: 0; }
.hb-zahl{
  font-variant-numeric: tabular-nums;
  color: var(--bs-primary);
  font-weight: 400;
  min-width: 1.4em;
}
.hb-text{ max-width: 62ch; }
.hb-text p, .hb-text ul{ margin-bottom: .9rem; }
.hb-text code{
  background: var(--bs-tertiary-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 3px;
  padding: 1px 5px;
  font-size: .85em;
}

.hb-bild{ margin: 1.2rem 0 .5rem; }
.hb-bild.hb-mittel{ max-width: 820px; }
.hb-bild img{
  display: block;
  width: 100%; height: auto;
  border: 1px solid var(--bs-border-color);
  border-radius: 4px;
  background: #fff;
}
.hb-bild figcaption{
  font-size: .875rem;
  color: var(--bs-secondary-color);
  margin-top: .5rem;
  max-width: 62ch;
}

.hb-kasten{
  border-left: 3px solid var(--bs-primary);
  background: var(--bs-tertiary-bg);
  border-radius: 0 3px 3px 0;
  padding: .9rem 1.1rem;
  margin: 1.2rem 0;
  max-width: 62ch;
}
.hb-kasten b{ display: block; margin-bottom: .2rem; }
.hb-achtung{ border-left-color: var(--bs-warning); }

/* Sprungmarken dürfen nicht unter der Kopfzeile verschwinden. */
.hb-abschnitt{ scroll-margin-top: 5rem; }

/* ---------------------------------------------------------------------
   Das Inhaltsverzeichnis des Handbuchs bleibt stehen
   ---------------------------------------------------------------------
   Ein Kapitel hat sieben bis neun Abschnitte. Wer im letzten liest, hat
   das Verzeichnis aus dem Bild geschoben — der Weg zum naechsten war
   dann: ganz nach oben, klicken, wieder nach unten.

   Der Abstand von oben haelt die Kopfzeile frei; ohne ihn klebt das
   Verzeichnis darunter und verdeckt sie. Die eigene Hoehe mit eigenem
   Rollbalken ist fuer den Fall, dass das Verzeichnis selbst laenger
   wird als der Bildschirm — bei elf Kapiteln ist das absehbar.

   Nur ab lg: Darunter stehen die Spalten untereinander, und ein
   klebendes Verzeichnis naehme dort die halbe Hoehe weg. */
@media (min-width: 992px) {
  .hilfe-nav {
    position: sticky;
    /* Unter der Kopfzeile, nicht darunter VERSTECKT: Die Kopfzeile bleibt
       selbst stehen (position: sticky, top: 0). Mit top: 1rem lag das
       Verzeichnis bei y=16 und damit hinter einer 52 px hohen Kopfzeile —
       gemessen im Browser, nicht geschaetzt.

       `--header-height` ist dieselbe Variable, an der schon die
       Seitenleiste haengt. Aendert sich die Hoehe der Kopfzeile, zieht
       beides mit. */
    top: calc(var(--header-height) + .75rem);
    align-self: flex-start;
    max-height: calc(100vh - var(--header-height) - 1.5rem);
    overflow-y: auto;
    /* Etwas Luft rechts, damit der eigene Rollbalken nicht auf dem Text
       der Liste sitzt. */
    padding-right: .5rem;
  }
}
