/*
 * Gemeinsames Stylesheet fuer alle Widgets aus diesem Ordner. Eine Seite,
 * die Widgets nutzt, bindet nur diese eine Datei ein - unabhaengig davon,
 * wie viele einzelne Widgets (button/, combobox/, ...) es gibt.
 *
 * Button braucht kein eigenes Styling (nutzt die bestehenden
 * Bootstrap-Klassen). Ab hier: ComboBox.
 *
 * TESTTEST
 * ---------------------------------------------------------------------
 * LESEHILFE fuer die Selektoren in dieser Datei (kommt immer wieder vor):
 *
 *   .a .b      MIT Leerzeichen: ein Element .b, das IRGENDWO INNERHALB von .a liegt
 *   .a > .b    MIT ">":         ein Element .b, das DIREKTES Kind von .a ist
 *   .a.b       OHNE Leerzeichen: EIN Element, das BEIDE Klassen gleichzeitig traegt
 *   .a, .b     MIT Komma:       gilt fuer .a UND fuer .b (zwei Selektoren, eine Regel)
 *   .a:hover   Zustand:         gilt nur, solange die Maus darueber ist
 *   .a:not(.b) Ausnahme:        gilt fuer .a, aber NUR wenn es nicht auch .b traegt
 *   .a::after  Pseudo-Element:  ein von CSS erzeugtes Extra-Element (siehe Timeline unten)
 *
 * Farben/Abstaende stammen wo moeglich aus Bootstraps eigenen CSS-Variablen
 * (var(--bs-...)) statt aus festen Hex-Werten - dadurch passt sich alles
 * automatisch an data-bs-theme="dark" an, ohne eigene Dark-Mode-Regeln.
 * ---------------------------------------------------------------------
 */ 
 

/*
 * "position: relative" macht dieses Element zum BEZUGSRAHMEN fuer alle
 * "position: absolute"-Kinder darin (hier: die Vorschlagsliste unten). Ohne
 * das wuerde sich die absolut positionierte Liste an irgendeinem weiter
 * aussen liegenden Element orientieren und nicht direkt unter dem Eingabefeld
 * erscheinen. Faustregel: Kind "absolute" -> Eltern "relative", immer als Paar.
 */
.ws-combobox {
  position: relative;
}

/*
 * Der Wrapper nimmt das Input einmal aus dem direkten Kind-Verhaeltnis zu
 * .input-group heraus (siehe jquery.combobox.js: _createWrapper). Damit ein
 * innerhalb eines Bootstrap-.input-group platziertes ComboBox-Feld (z.B.
 * mit vorangestelltem Icon) trotzdem korrekt mitwaechst, braucht der
 * Wrapper dieselbe Flex-Regel, die Bootstrap sonst .form-control gibt.
 *
 *   flex: 1 1 auto  = "darf wachsen (1), darf schrumpfen (1), Ausgangsgroesse
 *                      ergibt sich aus dem Inhalt (auto)" - fuellt also den
 *                      restlichen Platz der .input-group.
 *   min-width: 0    = Flex-Kinder schrumpfen standardmaessig NIE unter ihre
 *                      Inhaltsbreite; 0 hebt diese Sperre auf, sonst wuerde
 *                      ein langer Text das Feld ueber den Rand hinaus druecken.
 */
.input-group > .ws-combobox {
  flex: 1 1 auto;
  min-width: 0;
}

/*
 * Die Vorschlagsliste (dropdown), die unter dem Eingabefeld aufklappt.
 *
 *   position: absolute + top: 100%   = frei platziert, und zwar mit der
 *                                       Oberkante genau UNTER dem Bezugsrahmen
 *                                       (100% seiner Hoehe von oben gerechnet)
 *   left: 0; right: 0                = gleich breit wie das Eingabefeld
 *   z-index: 1000                    = liegt ueber normalem Seiteninhalt
 *   max-height + overflow-y: auto    = bei vielen Eintraegen scrollt die Liste,
 *                                       statt endlos nach unten zu wachsen
 *   list-style: none                 = die Liste ist ein <ul>, die Aufzaehlungs-
 *                                       punkte sollen nicht erscheinen
 *   box-shadow                       = weicher Schatten, hebt die Liste optisch ab
 *
 * Bootstraps eigene, theme-abhaengige CSS-Variablen statt fester Hex-Werte -
 * passt sich automatisch an data-bs-theme="dark" an (siehe README/global.css),
 * ohne eigene @media/[data-bs-theme]-Regeln pflegen zu muessen.
 */
.ws-combobox-list {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 1000;
  margin: 0.125rem 0 0;
  padding: 0.25rem 0;
  max-height: 15rem;
  overflow-y: auto;
  list-style: none;
  background-color: var(--bs-body-bg);
  color: var(--bs-body-color);
  border: 1px solid var(--bs-border-color);
  border-radius: 0.375rem;
  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.35);
}

/* Ein einzelner Vorschlag in der Liste - cursor: pointer zeigt die Haendchen-Maus ("anklickbar"). */
.ws-combobox-option {
  padding: 0.375rem 0.75rem;
  cursor: pointer;
}

/* Hervorhebung unter der Maus (":hover" = Zustand, kein eigenes Element). */
.ws-combobox-option:hover {
  background-color: var(--bs-tertiary-bg);
}

/* Ab hier: MultiSelect. Dropdown-Optik teilt sich bewusst .ws-combobox-list/
   .ws-combobox-option (siehe jquery.multiselect.js) - visuell identischer
   Baustein wie bei ComboBox, keine doppelten Regeln dafuer. */

/* Bezugsrahmen fuer die Vorschlagsliste (siehe .ws-combobox oben); min-width verhindert ein zu schmales Feld. */
.ws-multiselect {
  position: relative;
  min-width: 12rem;
}

/*
 * Das eigentliche Tipp-Feld INNERHALB des MultiSelect-Rahmens: der Rahmen
 * (.ws-multiselect, sieht aus wie ein Bootstrap-Eingabefeld) enthaelt die
 * ausgewaehlten Tags UND dieses Feld nebeneinander - das Feld selbst soll
 * deshalb unsichtbar sein (kein eigener Rand/Hintergrund), sonst saehe man
 * ein Feld im Feld. color: inherit uebernimmt die Textfarbe vom Rahmen.
 */
.ws-multiselect-input {
  border: none;
  outline: none;
  background: transparent;
  flex: 1 1 auto;
  min-width: 6rem;
  padding: 0;
  color: inherit;
}

/* Ab hier: Table. */

/*
 * Klickbarer Spaltenkopf. user-select: none verhindert, dass ein schneller
 * Doppelklick zum Umsortieren versehentlich den Spaltentitel markiert.
 */
.ws-table-sortierbar {
  cursor: pointer;
  user-select: none;
}

/*
 * Der Sortier-Pfeil im Spaltenkopf steht NICHT im HTML - das Widget setzt
 * nur die Klasse (ws-table-sort-asc / -desc) auf das <th>, und CSS haengt
 * per ::after einen Pfeil-Text an dessen Ende an. So muss das Widget beim
 * Umsortieren nur eine Klasse wechseln, keinen Text. (Mehr zu ::before/
 * ::after siehe Timeline unten.) Das fuehrende Leerzeichen in content
 * sorgt fuer Abstand zum Titel.
 */
.ws-table-sort-asc::after {
  content: ' ▲';
  font-size: 0.7em;
}

.ws-table-sort-desc::after {
  content: ' ▼';
  font-size: 0.7em;
}

/*
 * Option header_vertical: Spaltenkopf bleibt beim Scrollen oben stehen.
 * position: sticky haftet am naechsten scrollenden Vorfahren (top: 0 = an
 * dessen Oberkante). Die Zellen brauchen einen deckenden Hintergrund, sonst
 * scheinen die darunter durchlaufenden Zeilen durch. Bootstraps Tabellen-
 * Rahmen (border-collapse) laeuft beim Scrollen NICHT mit den th mit -
 * deshalb die Trennlinie als inset-box-shadow direkt am th. Der Selektor ist
 * bewusst spezifischer als Bootstraps ".table > :not(caption) > * > *".
 */
.ws-table-header-sticky > thead > tr > th {
  position: sticky;
  top: 0;
  z-index: 1;
  background-color: var(--bs-body-bg);
  box-shadow: inset 0 -1px 0 var(--bs-border-color);
}

/* Ab hier: Notification. */

/*
 * Container fuer die Toast-Meldungen.
 *
 *   position: fixed        = haengt am Browserfenster, nicht an der Seite -
 *                            bleibt beim Scrollen stehen (oben rechts)
 *   z-index: 1080          = ueber allem anderen
 *   width: min(a, b)       = nimmt den KLEINEREN der beiden Werte: hoechstens
 *                            24rem, auf schmalen Bildschirmen aber nie breiter
 *                            als das Fenster minus 2rem Rand
 *   display: flex + column = mehrere Meldungen stapeln sich untereinander
 *   pointer-events: none   = der (durchsichtige) Container selbst faengt keine
 *                            Klicks ab - man kann durch die Luecken hindurch
 *                            auf die Seite dahinter klicken. Die Meldungen
 *                            selbst schalten das unten mit "auto" wieder ein.
 */
.ws-notification {
  position: fixed;
  top: 1rem;
  right: 1rem;
  z-index: 1080; /* oberhalb von Bootstrap-Modals (1055) und -Dropdowns (1000+) */
  width: min(24rem, calc(100vw - 2rem));
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  pointer-events: none; /* Luecken zwischen den Meldungen klicken durch */
}

/* pointer-events: auto = die Meldung selbst ist wieder klickbar (Schliessen-Knopf), obwohl der Container es nicht ist. */
.ws-notification .alert {
  margin-bottom: 0;
  pointer-events: auto;
  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.35);
}

/* Bootstraps Alert-Farben sind im Dark-Mode (data-bs-theme="dark", siehe
   global.css/README) bewusst gedaempft/entsaettigt - das wirkt fuer eine
   Meldung, die auffallen soll, zu dezent. Hier stattdessen die vollen
   Bootstrap-Markenfarben als kraeftiger, deutlich sichtbarer Hintergrund. */
.ws-notification .alert-danger {
  background-color: #dc3545;
  border-color: #dc3545;
  color: #fff;
}

.ws-notification .alert-success {
  background-color: #198754;
  border-color: #198754;
  color: #fff;
}

.ws-notification .alert-warning {
  background-color: #ffc107;
  border-color: #ffc107;
  color: #000;
}

.ws-notification .alert-info {
  background-color: #0dcaf0;
  border-color: #0dcaf0;
  color: #000;
}

/* ====================================================================
   Ab hier: Timeline.
   ====================================================================

   Optik angelehnt an Kendos "alternatingMode" (siehe jquery.timeline.js
   Kopfkommentar): eine durchgehende Linie mit einem Punkt pro Eintrag,
   Gruppen als Pill-Marker.

   AUFBAU EINER ZEILE (vom Widget erzeugt, siehe jquery.timeline.js):

     .ws-timeline-eintrag-zeile        <- ein 3-Spalten-Grid, eine Zeile pro Eintrag
        .ws-timeline-seite             <- Spalte 1: das Datum neben dem Punkt
        .ws-timeline-punkt             <- Spalte 2: Linie + Punkt (im HTML LEER!)
        .ws-timeline-seite             <- Spalte 3: die Karte (Titel, Datum, Inhalt)

   Welche Seite die Karte traegt, steuert NICHT die Reihenfolge dieser drei
   Spalten im HTML (die bleibt immer Datum-zuerst), sondern eine SPIEGELUNG
   der ganzen Zeile per "direction: rtl" (siehe .ws-timeline-zeile-gespiegelt).
   Vorteil: der Schmal-Fallback ganz unten kann die Spiegelung fuer ALLE Zeilen
   pauschal abschalten, ohne pro Zeile wissen zu muessen, wo die Karte
   urspruenglich gelandet ist.

   CSS-EIGENE VARIABLEN ("Custom Properties"):
   Ein Name mit zwei Bindestrichen (--ws-timeline-punkt-farbe) ist eine selbst
   definierte Variable, benutzt wird sie mit var(--ws-timeline-punkt-farbe).
   Variablen VERERBEN sich nach unten: hier oben am Timeline-Element gesetzt,
   gelten sie fuer alles darin. Wer z.B. nur den Punkt groesser haben will,
   ueberschreibt einfach --ws-timeline-punkt-groesse auf einem eigenen
   Selektor (z.B. #meine-timeline { --ws-timeline-punkt-groesse: 1.2rem; }),
   statt die ganze .ws-timeline-punkt::after-Regel duplizieren zu muessen.
   Vollstaendige Liste samt Beispielen: "CSS anpassen" in timeline/doku.html. */
.ws-timeline-darstellung-rechts,
.ws-timeline-darstellung-links,
.ws-timeline-darstellung-abwechselnd {
  --ws-timeline-punkt-groesse: 0.75rem;
  --ws-timeline-punkt-farbe: var(--bs-primary);
  --ws-timeline-linie-farbe: var(--bs-border-color);
  --ws-timeline-karte-bg: var(--bs-tertiary-bg);
  --ws-timeline-gruppe-bg: var(--bs-emphasis-color, #212529);
  --ws-timeline-gruppe-farbe: var(--bs-body-bg);
  --ws-timeline-pfeil-groesse: 0.4rem;
  --ws-timeline-chevron-groesse: 1.3rem;
}

/*
 * Die Zeile mit dem Gruppen-Marker ("Juni 2026").
 * display: flex + justify-content: center = der Marker steht waagerecht mittig.
 * margin: 1.5rem 0 1rem (oben / links+rechts / unten) = Luft ueber und unter dem Marker.
 */
.ws-timeline-gruppe-zeile {
  display: flex;
  justify-content: center;
  margin: 1.5rem 0 1rem;
}

/* Die allererste Gruppe braucht oben keinen Abstand (":first-child" = erstes Kind seines Elternelements). */
.ws-timeline-gruppe-zeile:first-child {
  margin-top: 0;
}

/*
 * Der Pill-Marker selbst. border-radius: 999px = "so rund wie moeglich":
 * ein Radius, der groesser als die halbe Hoehe ist, rundet die schmalen Seiten
 * vollstaendig ab - es entsteht eine Kapsel-Form ohne feste Breite.
 */
.ws-timeline-gruppe-titel {
  background-color: var(--ws-timeline-gruppe-bg);
  color: var(--ws-timeline-gruppe-farbe);
  font-weight: 600;
  font-size: 0.8rem;
  padding: 0.3rem 1rem;
  border-radius: 999px;
}

/*
 * Eine Eintrags-Zeile = ein eigenes Grid.
 *
 *   display: grid                    = Kinder werden in Spalten/Zeilen angeordnet
 *   grid-template-columns: auto auto 1fr
 *       Spalte 1 (Datum)  = "auto": so breit wie ihr Inhalt
 *       Spalte 2 (Punkt)  = "auto": so breit wie ihr Inhalt
 *       Spalte 3 (Karte)  = "1fr":  bekommt den GESAMTEN Rest ("fr" = Anteil
 *                                   am uebrigen Platz)
 *   align-items: center              = alle drei vertikal mittig zueinander
 *   column-gap: 1rem                 = Abstand zwischen den Spalten
 *   min-height: 2.75rem              = auch eine sehr kleine Karte hat genug Platz fuer den Punkt
 */
.ws-timeline-eintrag-zeile {
  display: grid;
  align-items: center;
  column-gap: 1rem;
  min-height: 2.75rem;
  /* Default (darstellung: 'rechts'): schmale Datumsspalte, breite Kartenspalte -
     siehe darstellung-Varianten unten fuer 'links'/'abwechselnd'. */
  grid-template-columns: auto auto 1fr;
}

/*
 * "container-type: inline-size" macht dieses Element zu einem "Container",
 * dessen BREITE weiter unten von "@container"-Regeln abgefragt werden kann.
 * Container Query statt @media - reagiert auf die tatsaechliche Breite
 * DIESES Elements, nicht auf die Browser-Viewport-Breite. Wichtig, wenn die
 * Timeline (z.B. in einer schmalen Dashboard-Spalte) auf einem ansonsten
 * breiten Bildschirm sitzt - @media haette das faelschlich nicht erkannt
 * (per Screenshot-Test verifiziert).
 */
.ws-timeline-darstellung-abwechselnd {
  container-type: inline-size;
}

/*
 * Bei 'abwechselnd' sollen beide Seiten der Linie gleich breit sein:
 * "1fr auto 1fr" = links und rechts je gleich viel Restplatz, in der Mitte
 * nur so viel wie der Punkt braucht. Symmetrisch statt auto/1fr: bei echtem
 * Seitenwechsel sollen beide Seiten gleich breit sein, nicht mal schmal
 * (Datum) / mal breit (Karte).
 */
.ws-timeline-darstellung-abwechselnd .ws-timeline-eintrag-zeile {
  grid-template-columns: 1fr auto 1fr;
}

/*
 * SPIEGELN mit "direction: rtl" (right-to-left = Schreibrichtung von rechts
 * nach links, wie Arabisch). Bei einem Grid dreht das die REIHENFOLGE der
 * Spalten um: Spalte 1 landet ganz rechts, die letzte ganz links. Dadurch
 * rutscht die Karte (im HTML immer letzte Spalte) auf die linke Seite - ohne
 * dass am HTML irgendetwas geaendert werden muss.
 */
.ws-timeline-darstellung-links .ws-timeline-eintrag-zeile {
  direction: rtl; /* spiegelt ALLE Zeilen: Karte rutscht auf die linke Seite */
}

/* Dasselbe nur fuer EINE Zeile ("abwechselnd": jede zweite Zeile wird vom Widget so markiert). */
.ws-timeline-eintrag-zeile.ws-timeline-zeile-gespiegelt {
  direction: rtl; /* spiegelt NUR diese eine Zeile (darstellung: 'abwechselnd') */
}

/* direction:rtl auf der Zeile dreht nur die GRID-Spaltenreihenfolge um -
   der eigentliche Inhalt (Karte, Datumstext) soll trotzdem ganz normal
   lesbar bleiben, deshalb hier wieder auf ltr zurueckgesetzt.
   ("> *" = alle direkten Kinder der Zeile, egal welche Klasse.) */
.ws-timeline-eintrag-zeile > * {
  direction: ltr;
}

/*
 * min-width: 0 - Grid-Kinder schrumpfen standardmaessig nie unter ihre
 * Inhaltsbreite. Ein langer, unumbrechbarer Titel wuerde die Karte sonst
 * ueber den Rand hinaus druecken; mit 0 darf sie schmaler werden und der
 * Text bricht um.
 */
.ws-timeline-seite {
  min-width: 0;
}

/*
 * Das Datum neben dem Punkt.
 * white-space: nowrap = niemals umbrechen (sonst "14.08." / "26" in zwei Zeilen).
 * text-align: end (statt "right") = folgt der Schreibrichtung der Zeile:
 * bei gespiegelten Zeilen steht das Datum links vom Punkt und ist
 * automatisch LINKSbuendig zur Linie - es klebt so immer direkt am Punkt.
 */
.ws-timeline-achsen-datum {
  font-size: 0.85rem;
  color: var(--bs-secondary-color);
  white-space: nowrap;
  /* "end" statt "right": folgt der (ggf. gespiegelten) direction der
     Elternzeile, das Datum haengt dadurch immer direkt am Punkt, egal auf
     welcher Seite es gerade sitzt. */
  text-align: end;
}

/*
 * PUNKT UND LINIE - im HTML steht hier nur ein LEERES <div class="ws-timeline-punkt">.
 * Alles, was man sieht, zeichnen die beiden Pseudo-Elemente weiter unten.
 *
 *   position: relative   = Bezugsrahmen fuer die absolut positionierten
 *                          Pseudo-Elemente (Linie/Punkt) darin
 *   align-self: stretch  = ueberschreibt das "align-items: center" der Zeile
 *                          nur fuer dieses eine Kind: der Punkt-Bereich ist so
 *                          HOCH WIE DIE GANZE ZEILE - erst dadurch kann die
 *                          Linie darin von ganz oben bis ganz unten reichen
 *   width: 0.9rem        = schmaler Streifen, in dessen Mitte Linie + Punkt sitzen
 */
.ws-timeline-punkt {
  position: relative;
  align-self: stretch;
  width: 0.9rem;
}

/*
 * ::before und ::after - MERKHILFE
 * --------------------------------
 * Das sind Pseudo-Elemente: unsichtbare Extra-Elemente, die CSS selbst
 * INNERHALB eines Elements erzeugt. ::before sitzt vor dem Inhalt, ::after
 * dahinter. Sie stehen NICHT im HTML/DOM (jQuery findet sie nicht, man kann
 * sie nicht einzeln anklicken), lassen sich aber wie normale Elemente stylen.
 *
 * Ohne "content: ''" wird gar nichts erzeugt - das leere content ist der
 * Schalter, der das Pseudo-Element ueberhaupt entstehen laesst.
 *
 * Warum hier ZWEI? Ein Element kann nur EINE Form zeichnen; wir brauchen
 * Linie UND Kreis. ::before wird zuerst gezeichnet (liegt hinten), ::after
 * danach (liegt vorne) - deshalb sitzt der Punkt ueber der Linie und nicht
 * darunter. "before"/"after" beschreibt also nur die Zeichen-Reihenfolge,
 * nicht links/rechts.
 *
 * ZENTRIEREN mit left/top 50% + transform (Standardmuster, hier zweimal):
 *   left: 50%             setzt nur die LINKE KANTE des Elements in die Mitte
 *   translateX(-50%)      schiebt es um die Haelfte SEINER EIGENEN Breite
 *                         zurueck -> jetzt liegt sein MITTELPUNKT in der Mitte
 * (Dasselbe senkrecht mit top: 50% + translateY(-50%).)
 */

/*
 * ::before = die LINIE.
 * Die durchgehende Linie: jede Zeile zeichnet nur IHR eigenes Segment
 * (top:0 bis bottom:0 relativ zur eigenen Zeilenhoehe) - aneinandergereiht
 * ergeben die Segmente aufeinanderfolgender Zeilen eine durchgehende Linie,
 * ohne dass das Widget die Gesamthoehe im Voraus kennen muesste.
 */
.ws-timeline-punkt::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  background-color: var(--ws-timeline-linie-farbe);
  transform: translateX(-50%);
}

/*
 * ::after = der PUNKT (liegt ueber der Linie).
 *
 *   width/height aus der Variable      = Durchmesser (--ws-timeline-punkt-groesse)
 *   border-radius: 50%                 = macht aus dem Quadrat einen Kreis
 *   background-color                   = Fuellfarbe (--ws-timeline-punkt-farbe)
 *   border: 2px solid <Seitenfarbe>    = ein Ring in Hintergrundfarbe um den
 *                                        Punkt: sieht aus, als waere die Linie
 *                                        an dieser Stelle rund um den Punkt
 *                                        freigeschnitten
 */
.ws-timeline-punkt::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--ws-timeline-punkt-groesse);
  height: var(--ws-timeline-punkt-groesse);
  border-radius: 50%;
  background-color: var(--ws-timeline-punkt-farbe);
  border: 2px solid var(--bs-body-bg);
  transform: translate(-50%, -50%);
}

/*
 * Die Karte. position: relative wird gebraucht, weil der Sprechblasen-Pfeil
 * (::before/::after unten) an der Kartenkante "absolute" platziert wird.
 */
.ws-timeline-karte {
  position: relative;
  padding: 0.6rem 0.9rem;
  background-color: var(--ws-timeline-karte-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 0.5rem;
}

/*
 * SPRECHBLASEN-PFEIL, zeigt zur Linie/zum Punkt hin (siehe Kendo-Vorbild-
 * Screenshot). ZWEI uebereinanderliegende Rahmen-Dreiecke statt nur eines -
 * mit nur einer einfarbigen Spitze (Kartenfarbe) verschwand die Spitze
 * optisch fast komplett vor dem aehnlich dunklen Seitenhintergrund, sichtbar
 * blieb nur eine Luecke im Kartenrahmen (so gemeldet). Jetzt: ::before etwas
 * GROESSER in Rahmenfarbe (liegt hinten), ::after etwas KLEINER in
 * Kartenfarbe (liegt vorne) - der schmale Rahmenfarbe-Rand, der dadurch
 * rundherum sichtbar bleibt, zeichnet die Spitze klar gegen JEDEN
 * Hintergrund ab, genau wie der 1px-Rahmen der Karte selbst.
 *
 * WIE ENTSTEHT EIN DREIECK AUS CSS? (der "Border-Trick")
 * Eine Box mit width: 0 und height: 0, aber dicken Raendern, besteht NUR aus
 * ihren vier Raendern. An den Ecken treffen die Raender schraeg aufeinander,
 * dadurch sieht jeder Rand aus wie ein Dreieck:
 *
 *           border-top
 *              \    /
 *   border-left  \/  border-right
 *                /\
 *              /    \
 *           border-bottom
 *
 * Macht man drei Raender durchsichtig (transparent) und faerbt nur EINEN ein,
 * bleibt genau ein Dreieck sichtbar. Nur "border-right" gefaerbt = ein Dreieck,
 * dessen breite Seite rechts liegt und dessen SPITZE NACH LINKS zeigt - genau
 * die Richtung, die wir fuer eine Karte rechts der Linie brauchen.
 *
 * Richtung folgt exakt derselben Spiegel-Logik wie das Zeilen-Layout selbst
 * (siehe .ws-timeline-zeile-gespiegelt oben): Standardmaessig zeigt die
 * Spitze nach links (Linie sitzt links von der Karte, wie bei darstellung
 * 'rechts'), auf gespiegelten Zeilen nach rechts.
 *
 * Gemeinsam fuer beide Dreiecke: absolut positioniert, senkrecht zur
 * Kartenmitte zentriert, Groesse 0x0 (die Groesse kommt allein aus dem Rand).
 */
.ws-timeline-karte::before,
.ws-timeline-karte::after {
  content: '';
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 0;
  height: 0;
}

/*
 * Positionierung: eine 0x0-Box mit Rahmen B wird optisch B breit/hoch nach
 * ALLEN Seiten (also insgesamt 2*B x 2*B) - "left" ist die Position der
 * linken Boxkante, die rechte liegt dann bei "left + 2*B". Damit die
 * eingefaerbte Seite (border-right, die "Basis" des Dreiecks) buendig an der
 * Kartenkante (x=0) sitzt und die Spitze komplett NACH AUSSEN zeigt (nicht
 * zur Haelfte in der Karte verschwindet), muss "left" bei -2*B liegen, nicht
 * nur -B - das war der urspruengliche Fehler (Spitze nur angedeutet, Basis
 * in der Karte verdeckt).
 *
 * ::before = das GROESSERE Dreieck in Rahmenfarbe (Rand = Pfeilgroesse + 1px),
 * liegt hinten und bildet die sichtbare Kontur.
 * "--ws-timeline-pfeil-rand" ist eine Hilfsvariable, die nur hier definiert
 * und weiter unten (gespiegelte Variante) mitbenutzt wird.
 */
.ws-timeline-karte::before {
  --ws-timeline-pfeil-rand: calc(var(--ws-timeline-pfeil-groesse) + 1px);
  left: calc(var(--ws-timeline-pfeil-rand) * -2);
  border: var(--ws-timeline-pfeil-rand) solid transparent;
  border-right-color: var(--bs-border-color);
}

/* ::after = das KLEINERE Dreieck in Kartenfarbe, liegt vorne und "fuellt" das groessere aus. */
.ws-timeline-karte::after {
  left: calc(var(--ws-timeline-pfeil-groesse) * -2);
  border: var(--ws-timeline-pfeil-groesse) solid transparent;
  border-right-color: var(--ws-timeline-karte-bg);
}

/*
 * GESPIEGELTE Variante (Karte links der Linie): alles seitenverkehrt -
 * Position rechts statt links, eingefaerbt ist border-LEFT statt border-right,
 * dadurch zeigt die Spitze nach RECHTS zum Punkt. Gilt bei darstellung
 * 'links' fuer alle Karten, bei 'abwechselnd' fuer die als "gespiegelt"
 * markierten Zeilen.
 */
.ws-timeline-darstellung-links .ws-timeline-karte::before,
.ws-timeline-eintrag-zeile.ws-timeline-zeile-gespiegelt .ws-timeline-karte::before {
  left: auto;
  right: calc(var(--ws-timeline-pfeil-rand) * -2);
  border-right-color: transparent;
  border-left-color: var(--bs-border-color);
}

.ws-timeline-darstellung-links .ws-timeline-karte::after,
.ws-timeline-eintrag-zeile.ws-timeline-zeile-gespiegelt .ws-timeline-karte::after {
  left: auto;
  right: calc(var(--ws-timeline-pfeil-groesse) * -2);
  border-right-color: transparent;
  border-left-color: var(--ws-timeline-karte-bg);
}

/* Karten, die sich auf-/zuklappen lassen (collapsibleEvents), zeigen die Haendchen-Maus. */
.ws-timeline-karte-einklappbar {
  cursor: pointer;
}

/*
 * Kopfzeile der Karte: Titel links, Chevron (aufklapp-Pfeil) rechts.
 * justify-content: space-between = erstes Kind ganz links, letztes ganz
 * rechts, der Rest der Breite dazwischen. align-items: baseline = beide
 * stehen auf derselben Textgrundlinie.
 */
.ws-timeline-karte-kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.ws-timeline-karte-titel {
  font-weight: 600;
}

/*
 * Der Aufklapp-Pfeil "›".
 *   flex: none          = weder wachsen noch schrumpfen: behaelt seine Groesse,
 *                         auch wenn ein langer Titel Platz beansprucht
 *   line-height: 1      = keine zusaetzliche Zeilenhoehe rund um das Zeichen
 *   transition          = die Drehung unten wird in 0,15 s weich animiert
 *                         statt hart umzuspringen
 */
.ws-timeline-chevron {
  flex: none;
  font-size: var(--ws-timeline-chevron-groesse);
  line-height: 1;
  opacity: 0.6;
  transition: transform 0.15s ease-in-out;
}

/*
 * Aufgeklappt: Pfeil um 90 Grad drehen (› wird zu einem Pfeil nach unten).
 * ">" = direkte Kinder: nur der Chevron im Kopf DIESER Karte, nicht in
 * irgendeiner verschachtelten anderen.
 */
.ws-timeline-karte-offen > .ws-timeline-karte-kopf > .ws-timeline-chevron {
  transform: rotate(90deg);
}

/*
 * Die Untertitel-Zeile unter dem Titel (Default: das Datum; per Option
 * untertitelTemplate frei belegbar, z.B. Datum + Betriebsstunden).
 * white-space: pre-line = Zeilenumbrueche (\n) im Text werden dargestellt,
 * mehrfache Leerzeichen dagegen zusammengezogen (Unterschied zu pre-wrap
 * beim Inhalt darunter, wo auch Leerzeichen erhalten bleiben).
 */
.ws-timeline-karte-untertitel {
  font-size: 0.8rem;
  color: var(--bs-secondary-color);
  white-space: pre-line;
}

/*
 * Der Beschreibungs-Text der Karte.
 * white-space: pre-wrap = Zeilenumbrueche aus der Notiz bleiben erhalten
 * (normaler HTML-Text wuerde sie zu einem Leerzeichen zusammenziehen),
 * lange Zeilen werden trotzdem umgebrochen.
 */
.ws-timeline-karte-inhalt {
  margin-top: 0.5rem;
  font-size: 0.9rem;
  opacity: 0.9;
  white-space: pre-wrap;
}

/* Eingeklappt (siehe collapsibleEvents in jquery.timeline.js): Inhalt
   ausblenden, nur Kopf/Datum sichtbar. Gelesen: "eine einklappbare Karte,
   die NICHT auch .ws-timeline-karte-offen traegt" -> ihr Inhalt verschwindet.
   Das Widget schaltet nur die Klasse -offen um; alles Weitere macht CSS. */
.ws-timeline-karte-einklappbar:not(.ws-timeline-karte-offen) .ws-timeline-karte-inhalt {
  display: none;
}

/* Unter 576px EIGENER Breite (Bootstraps "sm"-Grenze, siehe global.css)
   faellt 'abwechselnd' automatisch auf die sichere, einspaltige 'rechts'-
   Optik zurueck - zwei Kartenspalten nebeneinander waeren auf einem
   schmalen Touch-Bildschirm (oder einer schmalen Dashboard-Spalte, siehe
   container-type oben) zu eng (siehe darstellung-Option in
   jquery.timeline.js). Betrifft NUR 'abwechselnd' - 'links'/'rechts' sind
   bereits einspaltig und brauchen keinen Fallback.

   "@container (max-width: ...)" ist wie "@media", fragt aber die Breite des
   naechsten Elements mit "container-type" ab (siehe oben), nicht die des
   Browserfensters. "!important" ist hier noetig, um die spezifischeren
   Regeln weiter oben (z.B. die Spiegelung per Zeilen-Klasse) zu uebertrumpfen. */
@container (max-width: 575.98px) {
  .ws-timeline-darstellung-abwechselnd .ws-timeline-eintrag-zeile {
    grid-template-columns: auto auto 1fr !important;
    direction: ltr !important;
  }

  /* Die Zeilen-Spiegelung wird oben zwar abgeschaltet, die Klasse
     .ws-timeline-zeile-gespiegelt bleibt aber auf der Haelfte der Zeilen
     stehen - ohne diese Regel wuerden deren Karten-Pfeile weiter nach
     rechts zeigen, obwohl die Karte jetzt (wie bei allen anderen Zeilen)
     rechts von der Linie liegt und die Pfeile deshalb nach links zeigen muessen. */
  .ws-timeline-darstellung-abwechselnd .ws-timeline-zeile-gespiegelt .ws-timeline-karte::before {
    left: calc(var(--ws-timeline-pfeil-rand) * -2);
    right: auto;
    border-right-color: var(--bs-border-color);
    border-left-color: transparent;
  }

  .ws-timeline-darstellung-abwechselnd .ws-timeline-zeile-gespiegelt .ws-timeline-karte::after {
    left: calc(var(--ws-timeline-pfeil-groesse) * -2);
    right: auto;
    border-right-color: var(--ws-timeline-karte-bg);
    border-left-color: transparent;
  }
}
