/* ==========================================================================
   EWB Radar -- hover_select.css
   Auswahl an einem Feature-Knopf. Der Bauplan steht im Kopf von
   frontend/js/hover_select.js; hier steht allein die Darstellung.

   Drei Dinge, die hier tragen und deshalb erklärt gehören:

   1. Es gibt EINE Bahn für alle Knöpfe, und sie hängt an #map-shell -- nicht in
      der Leiste. Grund: features.js verschiebt die Knöpfe zur Laufzeit zwischen
      Leiste und Dreipunkt-Menü. Alles, was hier an einer Gruppe hinge, wäre nach
      dem ersten Resize an der falschen Stelle.

   2. Weil die Bahn nicht in #controls liegt, greift KEINE der Container-Regeln
      aus tooltips.css. Dort setzt "[data-t-tooltip]::after" nur das Aussehen und
      lässt die Deckkraft auf 0; sichtbar wird eine Blase erst durch eine Regel je
      Container. Ohne die Regeln weiter unten stünde der Text im Attribut, sähe im
      Quelltext vollständig richtig aus und wäre am Bildschirm unsichtbar.
      #map-shell taucht in tooltips.css nicht auf; von dort gilt für die Stufen nur
      die Grundregel.

   3. Der Abstand zwischen Knopf und Bahn steht HIER, nicht im Skript. Das Skript
      setzt nur den Ankerpunkt an der Kante des Knopfes; die Lücke entsteht als
      margin. Damit bleibt der Abstand eine Sache des Stylesheets und ein
      Inline-Wert kann ihn nicht still schlagen.
   ========================================================================== */

#hover-select {
  /* Abstand zwischen Knopf und Bahn, und die Pufferzone rundherum. Beide so
     breit wie der Abstand zwischen zwei Knöpfen in der Leiste (controls.css
     setzt dort gap: var(--space-2)) -- die Bedienung soll sich anfühlen wie die
     Leiste, an der sie hängt. */
  --hs-gap: var(--space-2);
  --hs-buffer: var(--space-2);
  /* Kantenlänge des Zusatzknopfes und der Schalter jenseits der Bahn. Die des
     Zusatzknopfes geht in die Lage der Bahn ein: mit ihm
     rückt sie um seine Kantenlänge plus eine zweite Lücke weiter weg. */
  --hs-extra-size: 40px;

  position: absolute;
  /* Geschlossen ist die Bahn nicht vorhanden -- kein unsichtbares Element, das
     Zeigerereignisse über der Karte abfängt. */
  display: none;
  box-sizing: border-box;
  background: var(--glass-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-sm);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  touch-action: none;
  /* Kein Markieren in der Bahn: eine Auswahl unter dem Finger ist der übliche
     Auslöser dafür, dass der Browser daraus einen eigenen Ziehvorgang macht. */
  user-select: none;
  /* Über allem, was in #map-shell liegt: #controls, #controls-overflow,
     #right-controls und die aufgeklappte Attributionsleiste (right_controls.css).
     Gemessen, nicht geschätzt -- die Bahn geht aus einem dieser Knöpfe auf und
     läge sonst hinter seiner eigenen Leiste. */
  z-index: 20005;
}
#hover-select[data-open="true"] { display: block; }

/* Senkrecht: über dem Knopf, Stufe 0 unten -- die Leseordnung der Skizze.
   48 = Ring 40 + zweimal 3 px Luft + zweimal 1 px Rand. Dieselbe Rechnung führt
   trackLengthPx() in hover_select.js für die LÄNGE der Bahn (RING_SIZE_PX,
   RING_EDGE_PAD_PX, TRACK_BORDER_PX) -- so ist der Rand rundherum gleich breit.
   Wer hier ändert, ändert dort mit.

   Das Skript setzt left auf die MITTE des Knopfes und bottom auf dessen
   Oberkante; die Zentrierung quer dazu und die Lücke stehen hier. */
#hover-select[data-orientation="vertical"] {
  width: 48px;
  transform: translateX(-50%);
  margin-bottom: var(--hs-gap);
}
/* Mit Zusatzknopf steht zwischen Knopf und Bahn noch ein Element: Lücke,
   Zusatzknopf, Lücke. Die Maße stehen HIER und nicht im Skript -- dort wäre der
   Abstand ein Inline-Wert, der jede Regel schlüge. */
#hover-select.hs-track--extra[data-orientation="vertical"] {
  margin-bottom: calc(2 * var(--hs-gap) + var(--hs-extra-size));
}
#hover-select.hs-track--extra[data-orientation="horizontal"] {
  margin-right: calc(2 * var(--hs-gap) + var(--hs-extra-size));
}
/* Waagerecht: links neben dem Knopf, Stufe 0 rechts -- die um 90 Grad gedrehte
   untere Leiste. Gilt für die rechte Leiste und das Dreipunkt-Menü. */
#hover-select[data-orientation="horizontal"] {
  height: 48px;
  transform: translateY(-50%);
  margin-right: var(--hs-gap);
}

/* Das Fenster: füllt den Innenraum von #hover-select, bewegt sich nicht und
   schneidet ab, was LÄNGS der Bahn außerhalb liegt. Damit ist eine weggeblätterte
   Stufe weder zu sehen noch zu treffen -- sie läge sonst über dem Knopf und der
   Leiste und finge deren Druck.

   ⚠️ NUR längs. Quer stehen die Blasen der Stufen außerhalb der Bahn (senkrecht
   links, waagerecht darüber); ein Schnitt quer nähme sie in jedem Menü mit.
   Deshalb `clip` und nicht `hidden`: nur `clip` lässt die andere Achse auf
   `visible`, `hidden` machte daraus `auto` und schnitte quer mit.
   ⚫ `overflow: clip` tragen Browser erst seit 2022 (Safari ab 16).

   NUR bei Überlauf. Ohne Überlauf liegt keine Stufe außerhalb, und ein Schnitt
   träfe dort allein die mittigen Blasen der Randstufen -- die kleinen Menüs
   sähen anders aus als ohne Fenster.

   Am Innenraum und nicht am Außenrand: so behält Stufe 0 am knopfnahen Ende
   dieselbe Luft wie ohne Fenster. */
#hover-select .hs-track-window {
  position: absolute;
  inset: 0;
}
#hover-select[data-overflowing="true"][data-orientation="vertical"] .hs-track-window {
  overflow-x: visible;
  overflow-y: clip;
}
#hover-select[data-overflowing="true"][data-orientation="horizontal"] .hs-track-window {
  overflow-x: clip;
  overflow-y: visible;
}
/* Mit Tiefenvorschau (`data-funnel-peek`) reicht der Schnitt am FERNEN Ende um die
   Vorschau hinaus (`--hs-preview-room`, setPreviewShape()): `clip-path: inset()` mit
   einem negativen Wert auf dieser Seite. Knopfnah schneidet er an der Innenkante wie
   oben, quer ist er weit offen für die Blasen.
   ⚠️ `clip-path` macht das Fenster zum Stapelkontext und begrenzt auch Treffer: was
   außerhalb des Schnitts liegt, ist nicht zu treffen. */
#hover-select[data-funnel-peek="true"][data-overflowing="true"][data-orientation="vertical"] .hs-track-window {
  overflow: visible;
  clip-path: inset(calc(-1 * var(--hs-preview-room, 0px)) -100vw 0 -100vw);
}
#hover-select[data-funnel-peek="true"][data-overflowing="true"][data-orientation="horizontal"] .hs-track-window {
  overflow: visible;
  clip-path: inset(-100vh 0 -100vh calc(-1 * var(--hs-preview-room, 0px)));
}

/* Die innere Bahn: sie trägt die VOLLE Länge, das Fenster darüber zeigt einen
   Ausschnitt. Länge und Verschiebung setzt das Skript (layout(), applyScroll())
   -- hier steht nur, WO sie verankert ist.

   ⚠️ Verankert am knopfnahen Ende: senkrecht unten, waagerecht rechts. Dort
   liegt Stufe 0 (centerOf() in hover_select.js rechnet von diesem Ende her).
   Am anderen Ende verankert zeigte das Fenster beim Öffnen die HÖCHSTEN Stufen
   und Stufe 0 läge außerhalb -- die Bahn ginge scheinbar leer auf.

   Sie ist selbst positioniert, weil Schiene, Griff und Stufen absolut in ihr
   sitzen: ohne eigene Positionierung fielen sie auf das Fenster zurück und
   rechneten gegen dessen Länge statt gegen die volle Bahn.

   Sie selbst schneidet NICHTS: ihre Box enthält alle Stufen und wandert mit der
   Verschiebung. */
#hover-select .hs-track-inner {
  position: absolute;
}
#hover-select[data-orientation="vertical"] .hs-track-inner {
  bottom: 0;
  left: 0;
  width: 100%;
}
#hover-select[data-orientation="horizontal"] .hs-track-inner {
  right: 0;
  top: 0;
  height: 100%;
}

/* Unschärfe an den Fensterenden: sie verdeckt, was eine angeschnittene Stufe über
   die Rundung der Bahn schiebt (eckige Flaggen). Nur bei Überlauf eingehängt und nur
   an einer Seite sichtbar, an der noch etwas kommt (`data-fade-near`/`-far`, gesetzt
   von markVisibleEnds()).

   ⚠️ pointer-events: none -- der Streifen liegt über der Randzone, und Zeiger und Rad
   gehören dort der Bahn.
   ⚠️ Die Maske macht den Einsatz der Unschärfe weich: am Rand voll, nach innen null.

   Radius und Länge des Streifens sind am Gerät abgenommen. */
#hover-select {
  --hs-blur-radius: 3px;
  --hs-blur-zone: 16px;
}
#hover-select .hs-edge-blur {
  position: absolute;
  display: none;
  z-index: 1;
  pointer-events: none;
  border-radius: var(--radius-full);
  backdrop-filter: blur(var(--hs-blur-radius));
  -webkit-backdrop-filter: blur(var(--hs-blur-radius));
}
#hover-select[data-orientation="vertical"] .hs-edge-blur { left: 0; right: 0; height: var(--hs-blur-zone); }
#hover-select[data-orientation="horizontal"] .hs-edge-blur { top: 0; bottom: 0; width: var(--hs-blur-zone); }
#hover-select[data-orientation="vertical"] .hs-edge-blur--near {
  bottom: 0;
  -webkit-mask-image: linear-gradient(to top, black, transparent);
  mask-image: linear-gradient(to top, black, transparent);
}
#hover-select[data-orientation="vertical"] .hs-edge-blur--far {
  top: 0;
  -webkit-mask-image: linear-gradient(to bottom, black, transparent);
  mask-image: linear-gradient(to bottom, black, transparent);
}
#hover-select[data-orientation="horizontal"] .hs-edge-blur--near {
  right: 0;
  -webkit-mask-image: linear-gradient(to left, black, transparent);
  mask-image: linear-gradient(to left, black, transparent);
}
#hover-select[data-orientation="horizontal"] .hs-edge-blur--far {
  left: 0;
  -webkit-mask-image: linear-gradient(to right, black, transparent);
  mask-image: linear-gradient(to right, black, transparent);
}
#hover-select[data-fade-near="true"] .hs-edge-blur--near,
#hover-select[data-fade-far="true"] .hs-edge-blur--far { display: block; }
/* Im Spitzen-Zustand (`data-preview-shape`, unten) ist die Bahn kein Backdrop Root mehr,
   und der knopfnahe Streifen sähe die Karte: er wird auf den Kreis der Bahnrundung
   geschnitten (Innenradius 23 px), sonst unschärften seine Ecken die Karte daneben. */
#hover-select[data-preview-shape="true"][data-orientation="vertical"] .hs-edge-blur--near {
  clip-path: circle(23px at 50% calc(100% - 23px));
}
#hover-select[data-preview-shape="true"][data-orientation="horizontal"] .hs-edge-blur--near {
  clip-path: circle(23px at calc(100% - 23px) 50%);
}

/* Brücke über den Abstand zwischen Knopf und Bahn.

   Ohne sie verlässt der Zeiger auf dem Weg zur Auswahl kurz beide Elemente,
   pointerleave feuert und die Auswahl schließt sich genau in dem Moment, in dem
   man sie benutzen will. Der Nachlauf von 250 ms im Skript fängt den Rest.

   ⚠️ Sie deckt nicht nur den Spalt ab, sondern die ganze Bahn samt Puffer
   rundherum. Zwei Gründe: der Innenraum der Bahn ist um ihren eigenen Rand
   schmaler als der Knopf darunter -- wer an dessen Kante entlangfährt, wäre
   sonst daneben --, und wer beim Wandern über die Stufen seitlich abkommt,
   müsste unten neu ansetzen.

   Sie ist ein ::before und liegt damit in der Baumordnung VOR den Stufen und
   dem Griff. Diese bekommen ihre Klicks also weiterhin selbst; die Pufferzone
   fängt nur, was daneben liegt. Ein ::after läge darüber und schluckte sie. */
#hover-select::before { content: ""; position: absolute; }
#hover-select[data-orientation="vertical"]::before {
  left:   calc(-1 * var(--hs-buffer));
  right:  calc(-1 * var(--hs-buffer));
  top:    calc(-1 * var(--hs-buffer));
  bottom: calc(-1 * (var(--hs-gap) + var(--hs-buffer)));
}
#hover-select[data-orientation="horizontal"]::before {
  top:    calc(-1 * var(--hs-buffer));
  bottom: calc(-1 * var(--hs-buffer));
  left:   calc(-1 * var(--hs-buffer));
  right:  calc(-1 * (var(--hs-gap) + var(--hs-buffer)));
}
/* Mit Zusatzknopf muss die Zone auch ihn und die zweite Lücke überspannen --
   sonst verlässt der Zeiger auf dem Weg zum Knopf die Gruppe und die Auswahl
   schließt sich beim Hingreifen. */
#hover-select.hs-track--extra[data-orientation="vertical"]::before {
  bottom: calc(-1 * (2 * var(--hs-gap) + var(--hs-extra-size) + var(--hs-buffer)));
}
#hover-select.hs-track--extra[data-orientation="horizontal"]::before {
  right: calc(-1 * (2 * var(--hs-gap) + var(--hs-extra-size) + var(--hs-buffer)));
}
/* Mit Schaltern jenseits der Bahn reicht die Zone am FERNEN Ende über alle hinweg:
   je Schalter eine Kantenlänge und eine Lücke, dahinter der Puffer. Sonst verließe
   der Zeiger die Gruppe in der Lücke zwischen zwei Schaltern. Die Zahl der Schalter
   setzt buildToggles() in hover_select.js. */
#hover-select.hs-track--toggles[data-orientation="vertical"]::before {
  top: calc(-1 * (var(--hs-buffer) + var(--hs-toggle-count, 0) * (var(--hs-extra-size) + var(--hs-gap))));
}
#hover-select.hs-track--toggles[data-orientation="horizontal"]::before {
  left: calc(-1 * (var(--hs-buffer) + var(--hs-toggle-count, 0) * (var(--hs-extra-size) + var(--hs-gap))));
}

/* --------------------------------------------------------------------------
   Zusatzknopf -- eine zweite Einstellung derselben Ebene
   -------------------------------------------------------------------------- */

/* Er sitzt ZWISCHEN Knopf und Bahn und sieht aus wie ein Knopf der Leiste, ist
   aber keiner: ein echtes <button> brächte in #controls die Vorgaben aus
   buttons.css mit. Hier liegt er zwar in #map-shell, aber aus demselben Grund
   wie die Stufen bleibt er ein div.

   ⚠️ Über der Bahn (z-index 1 am Griff): die Pufferzone ist ein ::before der
   Bahn und reicht bis zum Hauptknopf hinunter, also über diesen Knopf hinweg.
   Bei gleichem Gewicht entschiede die DOM-Reihenfolge -- er läge darunter und
   bekäme keinen einzigen Klick, während er völlig normal aussieht. */
#hover-select .hs-extra { display: none; }
#hover-select .hs-extra,
#hover-select .hs-toggle {
  position: absolute;
  box-sizing: border-box;
  width: var(--hs-extra-size); height: var(--hs-extra-size);
  align-items: center; justify-content: center;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--glass-bg-2);
  cursor: pointer;
  z-index: 2;
}
#hover-select.hs-track--extra .hs-extra { display: flex; }
#hover-select .hs-extra img,
#hover-select .hs-extra svg { display: block; width: 24px; height: 24px; }

/* Senkrecht sitzt er UNTER der Bahn (Richtung Knopf), waagerecht rechts davon
   -- in beiden Lagen also auf dem Weg vom Knopf zur Bahn. */
#hover-select[data-orientation="vertical"] .hs-extra {
  top: calc(100% + var(--hs-gap));
  left: 50%; transform: translateX(-50%);
}
#hover-select[data-orientation="horizontal"] .hs-extra {
  left: calc(100% + var(--hs-gap));
  top: 50%; transform: translateY(-50%);
}

/* Rückmeldung wie an den Knöpfen der Leiste. Am Gerät gibt es kein :hover --
   dort setzt das Skript data-hover, solange der ziehende Finger auf ihm liegt;
   ohne diese Rückmeldung wäre nicht zu sehen, dass hier etwas zu wählen ist.
   ⚠️ Das scale steht ZUSAMMEN mit dem translate der Zentrierung: transform
   ersetzt, es ergänzt nicht, und der Knopf spränge sonst zur Seite. */
#hover-select .hs-extra:hover,
#hover-select .hs-extra[data-hover="true"] {
  background: var(--color-accent-dim);
  border-color: color-mix(in srgb, var(--color-accent) 30%, transparent);
}
#hover-select[data-orientation="vertical"] .hs-extra:hover,
#hover-select[data-orientation="vertical"] .hs-extra[data-hover="true"] {
  --carrier-scale: 1.06;
  transform: translateX(-50%) scale(var(--carrier-scale));
}
#hover-select[data-orientation="horizontal"] .hs-extra:hover,
#hover-select[data-orientation="horizontal"] .hs-extra[data-hover="true"] {
  --carrier-scale: 1.06;
  transform: translateY(-50%) scale(var(--carrier-scale));
}

/* --------------------------------------------------------------------------
   Schalter jenseits der Bahn -- an und aus für etwas, das zur Ebene gehört
   -------------------------------------------------------------------------- */

/* Gestalt wie der Zusatzknopf: Größe, Rand, Grund und Stapelgewicht stehen in
   der gemeinsamen Regel oben. Der Unterschied ist die Aufgabe -- ein Schalter
   wählt nichts aus, er schaltet nur, und sein Zustand steht in aria-pressed.

   Es gibt sie nur, wo eine Auswahl welche angibt (buildToggles() in
   hover_select.js); deshalb sind sie ohne eigene Bedingung sichtbar. */
#hover-select .hs-toggle {
  display: flex;
  font-size: 20px;
  line-height: 1;
}
#hover-select .hs-toggle img,
#hover-select .hs-toggle svg { display: block; width: 24px; height: 24px; }

/* Sie sitzen HINTER dem fernen Ende der Bahn, senkrecht also über ihr und
   waagerecht links von ihr, in einer Reihe vom Knopf weg: der mit
   `--hs-toggle-index` 0 an der Bahn, jeder weitere eine Kantenlänge und eine
   Lücke dahinter. Der Platz zwischen Knopf und Bahn bleibt dem Zusatzknopf.
   ⚠️ Beide Ausrichtungen, mit derselben Rechnung. */
#hover-select[data-orientation="vertical"] .hs-toggle {
  bottom: calc(100% + var(--hs-gap) + var(--hs-toggle-index, 0) * (var(--hs-extra-size) + var(--hs-gap)));
  left: 50%; transform: translateX(-50%);
}
#hover-select[data-orientation="horizontal"] .hs-toggle {
  right: calc(100% + var(--hs-gap) + var(--hs-toggle-index, 0) * (var(--hs-extra-size) + var(--hs-gap)));
  top: 50%; transform: translateY(-50%);
}

/* Rückmeldung unter dem Zeiger wie am Zusatzknopf, am Gerät über data-hover.
   Ein gesperrter Schalter gibt keine: er lädt nicht zum Drücken ein. */
#hover-select .hs-toggle:not([aria-disabled="true"]):hover,
#hover-select .hs-toggle:not([aria-disabled="true"])[data-hover="true"] {
  background: var(--color-accent-dim);
  border-color: color-mix(in srgb, var(--color-accent) 30%, transparent);
}
#hover-select[data-orientation="vertical"] .hs-toggle:not([aria-disabled="true"]):hover,
#hover-select[data-orientation="vertical"] .hs-toggle:not([aria-disabled="true"])[data-hover="true"] {
  --carrier-scale: 1.06;
  transform: translateX(-50%) scale(var(--carrier-scale));
}
#hover-select[data-orientation="horizontal"] .hs-toggle:not([aria-disabled="true"]):hover,
#hover-select[data-orientation="horizontal"] .hs-toggle:not([aria-disabled="true"])[data-hover="true"] {
  --carrier-scale: 1.06;
  transform: translateY(-50%) scale(var(--carrier-scale));
}

/* EINGESCHALTET: hervorgehoben in der Aktivfarbe der Ebene, wie ihr Knopf in der
   Leiste (buttons.css); das Symbol bleibt dasselbe. Die Farbe reicht
   buildToggles() als `--hs-toggle-color` herein, ohne sie gilt der Akzent.
   Geschlossene Fläche wie bei den Knöpfen des Dreipunkt-Menüs: der Schalter steht
   frei über der Karte, und ein durchsichtiger Grund sähe je nach Wetterlage anders
   aus.
   ⚠️ Mit dem Gewicht der Hover-Regel darüber, deren `:not()` mitzählt, und NACH
   ihr: so bleibt die Hervorhebung auch unter dem Zeiger stehen. */
#hover-select .hs-toggle[aria-pressed="true"]:not([aria-disabled="true"]) {
  background:   color-mix(in srgb, var(--hs-toggle-color, var(--color-accent)) 20%, var(--glass-bg-solid));
  border-color: color-mix(in srgb, var(--hs-toggle-color, var(--color-accent)) 50%, transparent);
  box-shadow:   inset 0 2px 4px rgba(0, 0, 0, 0.35);
}

/* GESPERRT: da, aber gerade ohne Wirkung. Rand und Grund treten zurück, das
   Symbol wird blass; die Sprechblase hängt am Schalter selbst und bleibt lesbar.
   Was beim Drücken geschieht, sagt die Auswahl (`onDisabledPick`). */
#hover-select .hs-toggle[aria-disabled="true"] {
  background: color-mix(in srgb, var(--glass-bg-2) 40%, transparent);
  border-color: color-mix(in srgb, var(--color-border) 40%, transparent);
  cursor: not-allowed;
}
#hover-select .hs-toggle[aria-disabled="true"] .hs-toggle-icon {
  opacity: 0.35;
  filter: grayscale(1);
}

/* Die Linie zwischen den Punkten -- ein Schieberegler, kein Punktehaufen.
   Sie verbindet die Mitten der äußeren Ringe und läuft nicht bis an die Enden;
   Länge und Versatz rechnet das Skript. */
#hover-select .hs-rail {
  position: absolute;
  background: var(--color-border);
  border-radius: var(--radius-full);
}
#hover-select[data-orientation="vertical"]   .hs-rail { left: 50%; width: 2px; transform: translateX(-50%); }
#hover-select[data-orientation="horizontal"] .hs-rail { top: 50%; height: 2px; transform: translateY(-50%); }

/* Ausfaden an der Schiene: derselbe Verlauf wie an den Symbolen, an FESTER
   Fensterposition. Die Positionen setzt markVisibleEnds() in Koordinaten der Schiene;
   eine Zone von 0 px heißt: an dieser Seite steht die Bahn am Anschlag. */
#hover-select[data-overflowing="true"] .hs-rail {
  --hs-rail-dir: to bottom;
  -webkit-mask-image: linear-gradient(var(--hs-rail-dir),
    transparent var(--hs-rail-far),
    calc(var(--hs-rail-far) + var(--hs-rail-far-zone) * (1 - var(--hs-fade-hint))),
    black calc(var(--hs-rail-far) + var(--hs-rail-far-zone)),
    black calc(var(--hs-rail-near) - var(--hs-rail-near-zone)),
    calc(var(--hs-rail-near) - var(--hs-rail-near-zone) * (1 - var(--hs-fade-hint))),
    transparent var(--hs-rail-near));
  mask-image: linear-gradient(var(--hs-rail-dir),
    transparent var(--hs-rail-far),
    calc(var(--hs-rail-far) + var(--hs-rail-far-zone) * (1 - var(--hs-fade-hint))),
    black calc(var(--hs-rail-far) + var(--hs-rail-far-zone)),
    black calc(var(--hs-rail-near) - var(--hs-rail-near-zone)),
    calc(var(--hs-rail-near) - var(--hs-rail-near-zone) * (1 - var(--hs-fade-hint))),
    transparent var(--hs-rail-near));
}
#hover-select[data-overflowing="true"][data-orientation="horizontal"] .hs-rail { --hs-rail-dir: to right; }

/* Trefferfläche einer Stufe: entlang der Bahn ihr voller Abstand, quer dazu der
   ganze Innenraum. Sie ist bewusst viel größer als alles Gezeichnete -- ein
   Punkt von 10 px ist mit dem Finger nicht zuverlässig zu treffen.

   ⚠️ Sie ist quadratisch und sitzt auf ihrer MITTE. Eine Fläche, die stattdessen
   den Innenraum der Bahn spannte, hinge an dessen Rand -- und der Rand der Bahn
   zählt zu ihrer Breite, die Fläche stünde also seitlich über. Die Kantenlänge
   entspricht dem Abstand der Stufen (STOP_SPACING_PX in hover_select.js). */
#hover-select .hs-stop {
  position: absolute;
  box-sizing: border-box;
  width: 48px; height: 48px;
  transform: translate(-50%, -50%);
  border: 0; padding: 0; background: none;
  cursor: pointer;
}
#hover-select[data-orientation="vertical"]   .hs-stop { left: 50%; }
#hover-select[data-orientation="horizontal"] .hs-stop { top: 50%; }

/* Jede Stufe zeigt einen Ring in der Kantenlänge der Knöpfe darunter und darin
   einen Punkt in der Farbe ihrer Stufe.

   ⚠️ Der Ring ist NICHT die Trefferfläche: die spannt quer zur Bahn den ganzen
   Innenraum, ist damit kein Kreis, und ein Ring aus ihrem eigenen Rand wäre eine
   Ellipse. Deshalb zeichnet ein eigenes, mittig gesetztes Element den Ring.

   ⚠️ Der Punkt ist ein echtes Kind und KEIN ::after. Das ::after einer Stufe
   gehört der Sprechblase aus tooltips.css -- beides an derselben Stelle ergäbe
   einen Punkt, der zum Textkasten wird. Der Ring darf ::before bleiben. */
#hover-select .hs-stop::before,
#hover-select .hs-dot {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  border-radius: var(--radius-full);
  box-sizing: border-box;
}
/* Der Ring erscheint NUR unter dem Zeiger. Er ist die Rückmeldung "hier würde
   dein Tipp landen", kein Dauerschmuck -- ständig sichtbar konkurriert er mit
   den Punkten, die die eigentliche Auskunft tragen. Seine Farbe nimmt er vom
   Punkt darunter auf, stark verdünnt; ohne Stufenfarbe (die Grenzen) bleibt es
   beim neutralen Grund der Leiste. */
#hover-select .hs-stop::before {
  width: 40px; height: 40px;
  border: 1px solid color-mix(in srgb, var(--hs-stop-color, var(--color-border)) 45%, transparent);
  background: color-mix(in srgb, var(--hs-stop-color, var(--color-text-muted)) 16%, transparent);
  opacity: 0;
  transition: opacity var(--transition-fast);
}
#hover-select .hs-stop:hover::before,
#hover-select .hs-stop:focus-visible::before { opacity: 1; }

/* Der Punkt der aktiven Stufe wird größer statt andersfarbig -- die Farbe gehört
   der Stufe, nicht dem Zustand. */
#hover-select .hs-dot {
  width: 10px; height: 10px;
  background: var(--hs-stop-color, var(--color-text-muted));
  transition: background var(--transition-fast), width var(--transition-fast), height var(--transition-fast);
}
#hover-select .hs-stop[data-active="true"] .hs-dot {
  width: 14px; height: 14px;
  background: var(--hs-stop-color, var(--color-accent));
}

/* Ausfaden am Fensterrand: Symbol (Punkt, Bild, Flagge) und Ring einer Stufe tragen
   eine Maske -- pixelweise, innen voll, an der Fensterkante durchsichtig. Die Blase ist
   das ::after der Stufe und trägt KEINE Maske. Welche Stufe eine Maske braucht und wie
   weit ihre Mitte von der Kante entfernt ist, setzt markVisibleEnds() (`data-fade`,
   `--hs-fade-dist`) -- nur bei Überlauf und nur an einer Seite, an der noch etwas kommt.

   Das Maskenbild ist längs `--hs-fade-length` lang: 48 px voll (eine Stufe), dann die
   Fade-Zone (`--hs-fade-zone`, gesetzt aus FADE_ZONE_PX) bis durchsichtig am Ende;
   `--hs-fade-hint` legt die Mitte des Übergangs fest. Quer ist es 48 px breit, mittig.

   Bewegt wird nur seine LAGE. Das Element ist mittig auf der Stufe, die Kante liegt
   `--hs-fade-dist` von seiner Mitte entfernt. `calc(50% + k)` setzt das Bild auf
   (Elementlänge − Bildlänge) / 2 + k; mit k = Abstand − Bildlänge / 2 (bzw. umgekehrt)
   liegt sein durchsichtiges Ende genau auf der Kante -- für Punkt, Ring und Bild
   gleich, egal wie groß sie sind.

   ⚠️ Die Maske schneidet am Kasten ihres Elements ab. Ein Symbol muss deshalb IN seinem
   Element stehen, nicht absolut darüber (`.hs-poi svg` unten). */
#hover-select { --hs-fade-hint: 0.5; }
#hover-select[data-overflowing="true"] .hs-stop[data-fade] > *,
#hover-select[data-overflowing="true"] .hs-stop[data-fade]::before {
  --hs-fade-length: calc(48px + var(--hs-fade-zone));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
#hover-select[data-orientation="vertical"][data-overflowing="true"] .hs-stop[data-fade="near"] > *,
#hover-select[data-orientation="vertical"][data-overflowing="true"] .hs-stop[data-fade="near"]::before {
  -webkit-mask-image: linear-gradient(to bottom, black 48px, calc(48px + var(--hs-fade-zone) * var(--hs-fade-hint)), transparent var(--hs-fade-length));
  mask-image: linear-gradient(to bottom, black 48px, calc(48px + var(--hs-fade-zone) * var(--hs-fade-hint)), transparent var(--hs-fade-length));
  -webkit-mask-size: 48px var(--hs-fade-length);
  mask-size: 48px var(--hs-fade-length);
  -webkit-mask-position: center calc(50% + var(--hs-fade-dist) - var(--hs-fade-length) / 2);
  mask-position: center calc(50% + var(--hs-fade-dist) - var(--hs-fade-length) / 2);
}
#hover-select[data-orientation="vertical"][data-overflowing="true"] .hs-stop[data-fade="far"] > *,
#hover-select[data-orientation="vertical"][data-overflowing="true"] .hs-stop[data-fade="far"]::before {
  -webkit-mask-image: linear-gradient(to top, black 48px, calc(48px + var(--hs-fade-zone) * var(--hs-fade-hint)), transparent var(--hs-fade-length));
  mask-image: linear-gradient(to top, black 48px, calc(48px + var(--hs-fade-zone) * var(--hs-fade-hint)), transparent var(--hs-fade-length));
  -webkit-mask-size: 48px var(--hs-fade-length);
  mask-size: 48px var(--hs-fade-length);
  -webkit-mask-position: center calc(50% + var(--hs-fade-length) / 2 - var(--hs-fade-dist));
  mask-position: center calc(50% + var(--hs-fade-length) / 2 - var(--hs-fade-dist));
}
#hover-select[data-orientation="horizontal"][data-overflowing="true"] .hs-stop[data-fade="near"] > *,
#hover-select[data-orientation="horizontal"][data-overflowing="true"] .hs-stop[data-fade="near"]::before {
  -webkit-mask-image: linear-gradient(to right, black 48px, calc(48px + var(--hs-fade-zone) * var(--hs-fade-hint)), transparent var(--hs-fade-length));
  mask-image: linear-gradient(to right, black 48px, calc(48px + var(--hs-fade-zone) * var(--hs-fade-hint)), transparent var(--hs-fade-length));
  -webkit-mask-size: var(--hs-fade-length) 48px;
  mask-size: var(--hs-fade-length) 48px;
  -webkit-mask-position: calc(50% + var(--hs-fade-dist) - var(--hs-fade-length) / 2) center;
  mask-position: calc(50% + var(--hs-fade-dist) - var(--hs-fade-length) / 2) center;
}
#hover-select[data-orientation="horizontal"][data-overflowing="true"] .hs-stop[data-fade="far"] > *,
#hover-select[data-orientation="horizontal"][data-overflowing="true"] .hs-stop[data-fade="far"]::before {
  -webkit-mask-image: linear-gradient(to left, black 48px, calc(48px + var(--hs-fade-zone) * var(--hs-fade-hint)), transparent var(--hs-fade-length));
  mask-image: linear-gradient(to left, black 48px, calc(48px + var(--hs-fade-zone) * var(--hs-fade-hint)), transparent var(--hs-fade-length));
  -webkit-mask-size: var(--hs-fade-length) 48px;
  mask-size: var(--hs-fade-length) 48px;
  -webkit-mask-position: calc(50% + var(--hs-fade-length) / 2 - var(--hs-fade-dist)) center;
  mask-position: calc(50% + var(--hs-fade-length) / 2 - var(--hs-fade-dist)) center;
}

/* ==========================================================================
   Tiefenvorschau am fernen Ende, Abtauchen am knopfnahen (ui.funnel_peek,
   `data-funnel-peek`). Drehung, Perspektive und Blässe sind am Gerät abgenommen.
   Abstand und Größe der Vorschau rechnet das Skript je Stufe (previewOffsetPx(),
   previewScale()), weil es damit auch den Platz bis zur Bildschirmkante rechnet.
   ========================================================================== */
#hover-select {
  --hs-preview-tilt: 24deg;
  --hs-preview-perspective: 160px;
  --hs-preview-alpha: 0.9;
  --hs-preview-fade: 0.15;
  --hs-dive-tilt: 28deg;
}
@media (prefers-reduced-motion: reduce) {
  #hover-select { --hs-preview-tilt: 0deg; --hs-dive-tilt: 0deg; }
}

/* Vorschau-Stufe (`data-preview`, markVisibleEnds()): ihr Kasten liegt ganz hinter der
   fernen Kante, sie trägt keine Maske. Der Transform setzt die Zentrierung FORT --
   translate(-50%, -50%) steht zuerst, gedreht und skaliert wird danach um die eigene
   Mitte. Perspektive: zur Kante hin gezogen (`--hs-preview-pull`) und im selben Maß
   verkleinert (`--hs-preview-scale`) -- jede Lücke kleiner als die davor, schon die
   erste kleiner als auf der Bahn. Mit der Tiefe blasser; eine hinzukommende blendet ein
   (`--hs-preview-enter`). Blase und Tab fallen schon über `data-outside` weg. Sie ist nur
   zum Ansehen: Druck und Klick fängt das Milchglas darüber. `pointer-events: none` sichert
   ab, dass sie auch dort nie selbst getroffen wird, wo ihr Kasten über den Umriss des
   Milchglases ragt -- ihr Klick wählte sonst die Stufe. */
#hover-select[data-orientation="vertical"][data-overflowing="true"] .hs-stop[data-preview="true"] {
  transform: translate(-50%, -50%)
    translateY(var(--hs-preview-pull))
    perspective(var(--hs-preview-perspective))
    rotateX(calc(var(--hs-depth) * var(--hs-preview-tilt)))
    scale(var(--hs-preview-scale));
  opacity: calc(max(0, var(--hs-preview-alpha) - var(--hs-depth) * var(--hs-preview-fade)) * var(--hs-preview-enter, 1));
  pointer-events: none;
}
#hover-select[data-orientation="horizontal"][data-overflowing="true"] .hs-stop[data-preview="true"] {
  transform: translate(-50%, -50%)
    translateX(var(--hs-preview-pull))
    perspective(var(--hs-preview-perspective))
    rotateY(calc(var(--hs-depth) * -1 * var(--hs-preview-tilt)))
    scale(var(--hs-preview-scale));
  opacity: calc(max(0, var(--hs-preview-alpha) - var(--hs-depth) * var(--hs-preview-fade)) * var(--hs-preview-enter, 1));
  pointer-events: none;
}

/* Abtauchen knopfnah (`--hs-dive` 0..1, markVisibleEnds()): Symbol und Ring der Randstufe
   kippen weg, als tauchten sie in den Boden. Über die EIGENE Eigenschaft `rotate`, damit
   das `transform` der Zentrierung stehen bleibt; mit `transform-origin: 0 0` dreht sie um
   die Mitte, auf die das translate den Anfang gelegt hat. Die Perspektive kommt von der
   Stufe.
   ⚠️ Die Maske am Fensterrand sitzt auf denselben Elementen und dreht mit: ihr
   durchsichtiger Rand weicht dabei um wenige Pixel von der Kante ab -- nur zwischen zwei
   Rasten und im Unschärfe-Streifen, am Gerät nicht zu sehen. */
#hover-select[data-funnel-peek="true"][data-overflowing="true"] .hs-stop[data-fade="near"] { perspective: 140px; }
#hover-select[data-funnel-peek="true"][data-overflowing="true"] .hs-stop[data-fade="near"] > *,
#hover-select[data-funnel-peek="true"][data-overflowing="true"] .hs-stop[data-fade="near"]::before {
  transform-origin: 0 0;
}
#hover-select[data-funnel-peek="true"][data-orientation="vertical"][data-overflowing="true"] .hs-stop[data-fade="near"] > *,
#hover-select[data-funnel-peek="true"][data-orientation="vertical"][data-overflowing="true"] .hs-stop[data-fade="near"]::before {
  rotate: x calc(var(--hs-dive, 0) * -1 * var(--hs-dive-tilt));
}
#hover-select[data-funnel-peek="true"][data-orientation="horizontal"][data-overflowing="true"] .hs-stop[data-fade="near"] > *,
#hover-select[data-funnel-peek="true"][data-orientation="horizontal"][data-overflowing="true"] .hs-stop[data-fade="near"]::before {
  rotate: y calc(var(--hs-dive, 0) * var(--hs-dive-tilt));
}

/* Form mit Spitze (`data-preview-shape`, markVisibleEnds()): Bahn und Spitze sind EINE
   Form. Die Bahn legt ihr Glas, ihren Rand, ihren Schatten und ihre Unschärfe ab -- nur
   das Aussehen; Glas und Unschärfe trägt die Hülle, Rand und Schatten entfallen. Treffer,
   Pufferzone (`::before`), Zusatzknopf und die Lage der Blasen bleiben an der Bahn. Ohne
   eigenen backdrop-filter ist sie kein Backdrop Root mehr, und Hülle wie Milchglas sehen
   die Karte. Die Umrisse setzt setPreviewShape() als `clip-path: path()`.

   Hülle: unter allem, knopfnah rund, fern ohne Kante in die Spitze; zur Spitze hin
   dünner werdendes Glas, damit die Tiefe sich wegdreht.
   Milchglas: über der Spitze und den Vorschau-Stufen -- man erahnt sie. Es fängt Druck
   und Klick jenseits der Kante (Skript), der Zeiger bleibt der gewöhnliche.
   Tönung und Unschärfe sind am Gerät abgenommen. */
#hover-select {
  --hs-frost-blur: 3px;
  --hs-frost-near: 12%;
  --hs-frost-far: 28%;
  --hs-hull-tip: 45%;
}
#hover-select .hs-hull,
#hover-select .hs-frost { position: absolute; display: none; }
#hover-select[data-preview-shape="true"] .hs-hull,
#hover-select[data-preview-shape="true"] .hs-frost { display: block; }
#hover-select[data-preview-shape="true"] {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
#hover-select .hs-hull {
  pointer-events: none;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
#hover-select[data-orientation="vertical"] .hs-hull {
  left: -1px; right: -1px; bottom: -1px;
  top: calc(-1px - var(--hs-preview-room, 0px));
  background: linear-gradient(to top,
    var(--glass-bg) calc(100% - var(--hs-preview-room, 0px) - 24px),
    color-mix(in srgb, var(--glass-bg) var(--hs-hull-tip), transparent));
}
#hover-select[data-orientation="horizontal"] .hs-hull {
  top: -1px; bottom: -1px; right: -1px;
  left: calc(-1px - var(--hs-preview-room, 0px));
  background: linear-gradient(to left,
    var(--glass-bg) calc(100% - var(--hs-preview-room, 0px) - 24px),
    color-mix(in srgb, var(--glass-bg) var(--hs-hull-tip), transparent));
}
#hover-select .hs-frost {
  z-index: 1;
  cursor: default;
  -webkit-backdrop-filter: blur(var(--hs-frost-blur)) saturate(0.7);
  backdrop-filter: blur(var(--hs-frost-blur)) saturate(0.7);
}
/* Das Milchglas reicht `--hs-frost-overlap` über die Kante in die Bahn hinein und setzt
   dort bei NULL ein -- die Maske blendet Tönung und Unschärfe bis zur Mitte der Spitze
   stetig ein, sonst stünde am Übergang eine harte Linie. */
#hover-select[data-orientation="vertical"] .hs-frost {
  left: -1px; right: -1px;
  bottom: calc(100% + 1px - var(--hs-frost-overlap, 0px));
  height: calc(var(--hs-preview-room, 0px) + var(--hs-frost-overlap, 0px));
  background: linear-gradient(to top,
    transparent,
    color-mix(in srgb, var(--color-text) var(--hs-frost-near), transparent) 35%,
    color-mix(in srgb, var(--color-text) var(--hs-frost-far), transparent));
  -webkit-mask-image: linear-gradient(to top, transparent, black 55%);
  mask-image: linear-gradient(to top, transparent, black 55%);
}
#hover-select[data-orientation="horizontal"] .hs-frost {
  top: -1px; bottom: -1px;
  right: calc(100% + 1px - var(--hs-frost-overlap, 0px));
  width: calc(var(--hs-preview-room, 0px) + var(--hs-frost-overlap, 0px));
  background: linear-gradient(to left,
    transparent,
    color-mix(in srgb, var(--color-text) var(--hs-frost-near), transparent) 35%,
    color-mix(in srgb, var(--color-text) var(--hs-frost-far), transparent));
  -webkit-mask-image: linear-gradient(to left, transparent, black 55%);
  mask-image: linear-gradient(to left, transparent, black 55%);
}

/* Stufen mit gezeichnetem Symbol statt Punkt: das Skript setzt das Symbol
   anstelle des Punktes ein. Der Ring bleibt. */
#hover-select .hs-stop--icon svg {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}

/* Standorte: der Ring trägt entweder ein Bild, eine Flagge, oder ein Wappen aus
   beiden -- das Bild kleiner und zentriert VOR der Flagge.

   Alle Größen sind am RING nachgerechnet. Er misst 40 px (`.hs-stop::before` oben),
   sein Radius also 20 px. Eine 4:3-Fläche der Höhe h reicht von der Mitte bis zur Ecke
   sqrt((1.333h/2)² + (h/2)²) = 0.833h, eine quadratische 0.707h. Wer den Ring oder eine
   Größe ändert, rechnet hier nach.

   Allein im Ring:  Flagge 26 x 19.5 px -> 16.25 px zur Ecke, 3.75 px Luft -- so groß
                    wie eine 4:3-Flagge über `icon_path` (unten).
                    Emoji  22 px -> 15.6 px, 4.4 px Luft.
                    SVG im 26-px-Kasten: 4:3 wie die Flagge, quadratisch
                    18.4 px, 1.6 px Luft.
   Wappen:          Flagge wie allein, 26 x 19.5 px, also dieselbe Luft zum Ring.
                    Das Bild davor 14 px (Emoji) bzw. 14 x 14 px (SVG), das sind
                    0.72 der Flaggenhöhe: 2.75 px Luft zur Ober- und Unterkante
                    der Flagge, 6 px zu den Seiten. geocoder.css rechnet mit
                    demselben Anteil.

   ⚠️ Der Wappen-Kasten ist die Flagge: sein Umriss ist derselbe wie bei der
   Flagge allein, und die Höhe des Rings ändert sich nicht. */
#hover-select .hs-poi {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
}
/* flag-icons skaliert über em: 1.333em breit, 1em hoch. Die Größe kommt
   deshalb aus dieser einen Zeile.
   ⚠️ So groß wie eine 4:3-Flagge über `icon_path` (`.hs-poi svg` unten, 26 px Kasten ->
   26 x 19.5 px) -- dieselbe Flagge sieht sonst je nach Konfigurationsweg anders aus. */
#hover-select .hs-poi .fi { font-size: 19.5px; }
#hover-select .hs-poi__icon { font-size: 22px; }
/* ⚠️ Größe und Lage des Bildes stehen hier, aus zwei Gründen:
   - Die Größe kommt aus dem CSS und NICHT aus der Vorlage. Eine Vorlage mit `{size}`
     bringt sie zwar mit -- aber eine SVG-Datei, die über `icon_path` hereinkommt, muss
     keine Platzhalter haben. Gemessen an den ausgelieferten Flaggen: keine einzige der
     270 Dateien in vendor/flag-icons/flags/1x1/ trägt width oder height am
     <svg>-Element. Ohne width und height hier zeichnete der Browser sie in seiner
     Vorgabegröße (300x150) in einen Ring von 40.
   - Das Bild steht im Fluss, gegen `.hs-stop--icon svg` oben: `.hs-poi` zentriert sich
     selbst auf der Stufe. Stünde das Bild absolut, wäre `.hs-poi` 0 x 0 px groß -- und
     die Maske am Fensterrand schneidet am Kasten ihres Elements ab, das Symbol
     verschwände ganz. `mask-clip: no-clip` hilft dagegen nicht überall: Safari kennt
     den Wert nicht. */
#hover-select .hs-poi svg { position: static; transform: none; display: block; width: 26px; height: 26px; }
/* Das Bild liegt absolut IN seinem Kasten, nicht darüber hinaus: `.hs-poi` hat
   seine Größe von der Flagge im Fluss, und das kleinere Bild bleibt ganz darin.
   Die Maske am Fensterrand (oben) schneidet es deshalb nicht ab. `.hs-poi` selbst
   ist schon absolut gestellt und damit der Bezugskasten -- ein `position:
   relative` hier nähme ihm die Zentrierung auf der Stufe. */
#hover-select .hs-poi--crest .hs-poi__icon {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  font-size: 14px;
  line-height: 1;
}
/* ⚠️ Eine Vorlage bringt ihre Größe aus `{size}` mit -- vor der Flagge wäre sie
   zu groß. Hier gilt der gerechnete Wert, nicht der aus der Vorlage. */
#hover-select .hs-poi--crest svg { width: 14px; height: 14px; }

/* Der Griff sitzt auf der aktiven Stufe und ist deutlich größer als ein Punkt.

   ⚠️ Quer zur Bahn zentriert er sich per transform, nicht über einen gerechneten
   Abstand: sein Rand zählt bei content-box zur Breite HINZU, der Innenraum der
   Bahn ist um ihren eigenen Rand schmaler, und aus beidem zusammen wurde er
   sichtbar aus der Mitte geschoben. Mit box-sizing und transform hängt die Lage
   an keiner dieser Zahlen mehr. */
#hover-select .hs-knob {
  position: absolute;
  box-sizing: border-box;
  /* ⚠️ ÜBER den Stufen. Beide sind positionierte Geschwister ohne eigene
     Stapelebene, und bei Gleichstand entscheidet die DOM-Reihenfolge -- die
     Stufen entstehen bei JEDEM Öffnen neu und hängen sich damit hinter den
     Griff, der nur einmal gebaut wird. Er läge also unter ihnen, und ein Druck
     auf ihn träfe die Stufe darüber: der Griff sähe normal aus und ließe sich
     nicht ziehen. Das Muster kommt ohne diese Regel aus, weil es den Griff dort
     als LETZTES einhängt; hier trägt sie das Gewicht, nicht die Reihenfolge. */
  z-index: 1;
  width: 30px; height: 30px;
  border-radius: var(--radius-full);
  background: var(--hs-knob-color, var(--color-accent));
  border: 2px solid var(--color-surface);
  box-shadow: var(--shadow-sm);
  transform: translate(-50%, -50%);
  transition: top var(--transition-fast), left var(--transition-fast);

  /* ⚠️ Der Griff ist reine ANZEIGE und nimmt keine Zeigerereignisse an. Er ist
     30 px breit und liegt über der 48 px breiten Stufe -- ohne diese Zeile
     schluckt er deren `:hover`, und der Ring erscheint nur im Randstreifen
     dazwischen: genau dort, wo der Zeiger die Hand der STUFE zeigt statt die
     Greifhand. Gefahrlos, weil kein einziger Behandler am Griff hängt; alle
     liegen an der Bahn und am Knopf (hover_select.js). Der Cursor steht
     deshalb an der Stufe, nicht hier -- an einem Element ohne Zeigerereignisse
     wäre er wirkungslos. */
  pointer-events: none;
}

/* Die Stufe, auf der der Griff steht, ist die Greiffläche -- über ihre ganzen
   48 px, nicht nur über die 30 px des Griffs. Das ist dieselbe Fläche, die auch
   den Ring zeigt: was greifbar aussieht, ist greifbar. */
#hover-select .hs-stop[data-active="true"] { cursor: grab; }

/* Beim Ziehen gilt die geschlossene Hand für die GANZE Bahn, nicht nur für die
   Stufe unter dem Griff. Gezogen wird der Länge nach, und zwischen den Stufen
   liegt blanke Bahn: sie trägt keine eigene Cursor-Regel, dort fiel der Zeiger
   auf den Pfeil zurück. ⚠️ Die Stufen brauchen die Regel ausdrücklich mit --
   ihr eigenes `cursor: pointer` wiegt sonst schwerer als das der Bahn; geerbt
   wird nur, wo nichts Eigenes steht. Gleiches Gewicht wie die Zeile darüber,
   also entscheidet die Reihenfolge: diese steht danach und gewinnt. */
#hover-select[data-dragging="true"],
#hover-select[data-dragging="true"] .hs-stop { cursor: grabbing; }
#hover-select[data-orientation="vertical"]   .hs-knob { left: 50%; }
#hover-select[data-orientation="horizontal"] .hs-knob { top:  50%; }
/* Beim Ziehen folgt der Griff dem Finger ohne Nachlauf -- die Übergangszeit gilt
   dem Einrasten, nicht der Bewegung. */
#hover-select[data-dragging="true"] .hs-knob { transition: none; }

/* Und beim Öffnen SPRINGT er auf seine Stufe. Wer von einem Knopf zum nächsten
   fährt, lässt die Auswahl offen -- der Griff stünde sichtbar da und führe quer
   über die Bahn, weil die Stufen des neuen Knopfes woanders liegen (die Länge
   der Bahn hängt an ihrer ANZAHL). Das Skript setzt die Sperre nur für diesen
   einen Sprung. */
#hover-select[data-jump="true"] .hs-knob { transition: none; }

/* Stufen mit Symbol kommen ohne Griff aus: die gewählte Stufe behält einfach
   ihren Ring, als wäre der Zeiger dort stehen geblieben. Eine gefüllte Scheibe
   deckte genau das zu, worum es geht. */
#hover-select.hs-track--icons .hs-knob { display: none; }
#hover-select.hs-track--icons .hs-stop[data-active="true"]::before { opacity: 1; }

/* Ohne gewählte Stufe gibt es nichts, worauf der Griff sitzen könnte: stünde er
   da, läse er sich als Wahl der Stufe, auf der er steht. Das Skript meldet den
   Zustand an der Bahn, bei jedem Setzen der Stufe. */
#hover-select[data-has-choice="false"] .hs-knob { display: none; }

/* --------------------------------------------------------------------------
   Sprechblase an der Stufe -- siehe Punkt 2 im Kopf dieser Datei
   -------------------------------------------------------------------------- */

/* ⚠️ Mehrzeiliger Text steht mittig, und dafür braucht es hier eine eigene
   Regel. In der Leiste steht keine: die Blase ist ein ::after, ihre Träger sind
   <button>-Elemente, und Buttons bringen die Zentrierung aus dem Browser-
   Standard mit; das Pseudo-Element erbt sie. Die Stufen hier sind divs und erben
   deshalb linksbündig. Ein grep über die Stylesheets sieht den Browser-Standard
   nicht -- gemessen, nicht geschlossen. */
#hover-select .hs-stop[data-t-tooltip]::after,
#hover-select .hs-extra[data-t-tooltip]::after,
#hover-select .hs-toggle[data-t-tooltip]::after { text-align: center; }

/* Lage. Senkrecht steht die Blase LINKS neben ihrer Stufe -- daneben ist Platz,
   über der Stufe säße sie auf der nächsten. Waagerecht steht sie darüber, weil
   links und rechts die Nachbarstufen liegen. */
#hover-select[data-orientation="vertical"] .hs-stop[data-t-tooltip]::after,
#hover-select[data-orientation="vertical"] .hs-extra[data-t-tooltip]::after,
#hover-select[data-orientation="vertical"] .hs-toggle[data-t-tooltip]::after {
  bottom: auto; top: 50%;
  left: auto; right: calc(100% + 10px);
  transform: translateY(var(--tooltip-shift, -50%));
}
/* Der Zusatzknopf zeigt seine Blase nur beim Hover -- sein Zustand steht in
   seinem eigenen Symbol, sie ist die Erklärung, nicht die Auskunft. */
#hover-select[data-open="true"] .hs-extra[data-t-tooltip]:hover::after {
  opacity: 1;
}
/* Ein Schalter jenseits der Bahn ebenso, und am Gerät, solange der ziehende
   Finger auf ihm ruht (data-hover): dort ist die Blase die einzige Auskunft,
   welcher der Schalter unter dem Finger liegt. */
#hover-select[data-open="true"] .hs-toggle[data-t-tooltip]:hover::after,
#hover-select[data-open="true"] .hs-toggle[data-t-tooltip][data-hover="true"]::after {
  opacity: 1;
}
/* Waagerecht -- das gedrehte Layout der rechten Leiste, auf dem Telefon der
   Normalfall -- steht die Blase DARÜBER: links und rechts liegen die
   Nachbarstufen.

   ⚠️ Der Zusatzknopf gehört dazu und fehlte hier. Senkrecht war er gedeckt, in
   dieser Regel nicht -- seine Blase fiel damit auf die Vorgabe aus tooltips.css
   zurück und lag direkt auf dem Knopf. Am Schreibtisch war nichts zu sehen, weil
   dort die senkrechte Lage gilt; gefunden hat es der USER am Telefon. Wer einen
   Träger ergänzt, muss BEIDE Ausrichtungen bedienen. */
#hover-select[data-orientation="horizontal"] .hs-stop[data-t-tooltip]::after,
#hover-select[data-orientation="horizontal"] .hs-extra[data-t-tooltip]::after,
#hover-select[data-orientation="horizontal"] .hs-toggle[data-t-tooltip]::after {
  bottom: calc(100% + 10px); top: auto;
  left: 50%; right: auto;
  transform: translateX(var(--tooltip-shift, -50%));
}

/* Jede Blase einer Stufe steht längs mittig -- waagerecht über ihr, senkrecht neben ihr --
   und bleibt innerhalb ihrer Grenzen: `--tooltip-shift` aus tooltips.css („Klemmen an
   einer Grenze“), gelesen in den zwei Lage-Regeln oben. Die Abstände setzt
   markVisibleEnds() je Stufe über clampTooltip():

   - Waagerecht bei Überlauf gehen die Fensterkanten vor: das Fenster schnitte eine Blase
     an seiner Kante an, eine breite schon an der Nachbarstufe eines Endes. Zwischen zwei
     Rasten rückt so auch die Blase einer überstehenden Randstufe ein.
   - Waagerecht ohne Überlauf endet eine Blase am knopfnahen Ende der Bahn und am Rand
     der Karte. Waagerecht öffnet eine Bahn nur aus der rechten Leiste oder dem
     Dreipunkt-Menü (orientationFor()); über das knopfnahe Ende hinaus stünde die Blase
     über der Spalte der Knöpfe.
   - Senkrecht bleibt die Blase NEBEN ihrer Stufe längs mittig, auch an den sichtbaren
     Enden: bündig an der Stufenkante läge ihre Oberkante auf der Stufenmitte, und sie
     stünde halb neben der Nachbarstufe. Sie rückt nur so weit ein, wie sie längs über
     die Fensterkante ragte; wie weit das ist, hängt an ihrer HÖHE -- eine Zeile oder
     mehrere --, und die kennt nur der Browser.

   Zusatzknopf und Schalter (`.hs-extra`, `.hs-toggle`) lesen dieselbe Verschiebung, damit
   eine Lage-Regel für alle drei Träger gilt. Wo die beiden stehen, legt dieses Stylesheet
   fest und nicht das Modell der Bahn, aus dem markVisibleEnds() die Abstände der Stufen
   nimmt: ihre Abstände misst clampOwnButtonBubbles() beim Öffnen am Bildschirm, gegen den
   Rand der Karte. Ihre Blasen stehen mittig, bis sie diesen Rand erreichen. */

/* Sichtbarkeit: EIN Fokus. Es steht höchstens EINE Blase -- an der Stufe mit
   `data-bubble` (updateBubble() in hover_select.js): unter dem Zeiger, sonst die
   gewählte; keine, solange die Bahn blättert, und nie an einer weggeblätterten Stufe.
   Die Sichtbarkeit hängt allein an diesem Zustand und nicht an `:hover`: nach dem
   Blättern ohne Zeigerbewegung bliebe `:hover` an der alten Stufe hängen, und neben der
   Blase der Stufe, die jetzt unter dem Zeiger liegt, stünde eine zweite.

   Die zwei Regeln tragen auch den Übergang jeder Blase der offenen Bahn -- geschlossen ist
   die Bahn gar nicht vorhanden. Kein Übergang auf `transform`: beim Blättern ändert sich
   die Verschiebung mit jedem Bild, und die Blase liefe ihrer Stufe hinterher. Beim
   Verschwinden gar keiner -- sonst führe sie noch ein Stück mit. Doppelte ID: sie wiegen
   mehr als jede andere Regel an einer Stufenblase, auch eine mit Zustand. */
#hover-select#hover-select[data-open="true"] .hs-stop[data-t-tooltip]::after {
  opacity: 0;
  transition: none;
}
#hover-select#hover-select[data-open="true"] .hs-stop[data-bubble="true"][data-t-tooltip]::after {
  opacity: 1;
  transition: opacity var(--transition-fast);
}
