/* ============================================================================
   girokonto-diagramm.min.css  ?v=6  — eigene Diagramm-Buehne des Profil-Panoramas
   (Girokonto DE, 3. Vergleichsansicht). Namespace .panorama-/.pan-.

   Politur 4 (19.07.2026): Detail-Reiter-Metrik in rem (2px-Unterstrich sichtbar,
   Listen-Parität statt sub-pixel-em); Preiszeile (.pan-detail-preis) im Panel-Kopf
   entfernt; EB-Icon-Klickfalle behoben (pointer-events:none, Phantom-Trefferfeld des
   Icon-Fonts) und Icon-Farbe explizit gepinnt (#A9F6DB / Hell #00528D); Mobile-
   Sparkline auf 35% Zeilenbreite.

   Politur 3 (19.07.2026): Bewertungspunkte Gold #f5d564 statt Teal #1FD99B
   (Kontrast-Hell #0070C0 unveraendert); Positionszahlen erscheinen beim Bahn-Hover
   an allen Punkten (data-hervor-Regel); Detail-Reiter exakt wie Listenansicht
   (Aktiv-Reiter Text + Unterstrich in var(--accent, #A9F6DB)); Mobile-Rangnummer
   auf .produkt-rang-Optik; Geschenk-Icon im Panel auf 2.97em; EB-Icon-Position
   entzerrt; "-" nach der Bewertung entfernt.

   Politur 2 (19.07.2026): Detail-Schliessknopf auf Tagesgeld-DE-Optik (randlos,
   transluzentes Weiss); Trennstrich unter der Bewertung entfernt; Detail-Reiter als
   durchgehendes Band mit Akzent-Unterstreichung (#09578F bzw. hellere Ableitung im
   Dunkel-Modus) statt Pills; Positionszahl an den Punkten der aktiven Spalte
   (.pan-punkt-zahl); Spark-Zoom-Overlay volle Viewport-Breite; Mobile-
   Einstellungsbaender in eigenen Container vor die .filter-section (zwei
   .panorama-mobil-Container: -oben Baender, -unten Liste).

   Politur 1 (19.07.2026, Mobile): Profilauswahl als die zwei Bestands-Baender der
   Girokonto-Liste (laufzeit-nav/laufzeit-pill + filter-group/toggle-group/toggle-btn
   aus vergleich.min.css) statt Pill-Wolke; Zeile in Tap-Button + Sparkline-Button
   geteilt; Sparkline-Zoom-Overlay (.panorama-spark-*, body-level, z-index 1300).

   Phase 2: Buehne (Rahmen/Flaeche/Scroll-Huelle), SVG-Skalierung, Typografie der
   SVG-Beschriftungen, Leerzustand, Hochkontrast-Overrides. Der Slopegraph selbst
   (Spaltenbaender, Linien, Punkte, Chips, Achsentexte) wird von girokonto-diagramm-
   race.js als Inline-SVG gezeichnet — alle FARBEN stehen dort als SVG-Attribute
   (zwei Paletten, umgeschaltet ueber #vergleich.kontrast-hell), nicht hier. Diese
   Datei setzt daher bewusst KEINE fill/stroke auf .pan-*-Knoten: sonst gaebe es zwei
   konkurrierende Farbquellen.

   Detailpanel-/Chip-Interaktions-Optik und das Mobile-Bottom-Sheet folgen Phase 3/4.
   Konsistenz-CSS (Leiste/Panel/#hilfe/Hochkontrast der Chrome) liegt weiterhin inline
   im Core, wie in der Tagesgeld-Blaupause.

   Konventionen: em/rem — KEIN px (Coden-Regel; Haarlinie = 0.0625em). SVG-Geometrie
   ist unitless und lebt im JS (SVG-Nutzereinheiten sind kein CSS-px).
   ============================================================================ */

/* Lesehilfe ueber dem Panorama, in Bestands-Typografie. */
.panorama-intro {
    margin: 0.25em 0 1em;
    max-width: 52em;
    line-height: 1.5;
}

/* Breite Buehne: vergleich.min.css (geteilt mit Liste/Tabelle, darf nicht
   modifiziert werden) kappt .results-container — das Panorama braucht mehr Raum,
   mit sanfter Obergrenze gegen Riesen-Skalierung auf sehr breiten Monitoren. */
.vergleich-dashboard.panorama-dashboard .results-container {
    max-width: 100em;
}

/* Buehne = Rahmen fuer das SVG. Farbwelt aus dem Bestand geerbt (#dcebf8-Familie);
   die Spaltenbaender im SVG legen sich darauf. Ohne JS ausgeblendet — dann uebernimmt
   die server-gerenderte Fallback-Tabelle (<noscript> im Core). */
.panorama-buehne {
    position: relative;
    width: 100%;
    margin: 1em 0 1.25em;
    border-radius: 0.375rem;
    border: 0.0625em solid #b9cfe2;
    background: #dcebf8;
    overflow: hidden;
}
html.no-js .panorama-buehne { display: none; }

/* Scroll-Huelle. In Phase 2 skaliert das SVG schlicht auf die Buehnenbreite
   (preserveAspectRatio="xMidYMid meet"); die Huelle ist der Anker fuer das
   horizontale Ausweichen auf schmalen Viewports in Phase 4. */
.panorama-scroll {
    position: relative;
    width: 100%;
    overflow: hidden;
}

/* Das SVG traegt die Buehnenbreite; die Hoehe folgt der viewBox (1280 x 640).
   font-family wird hier gesetzt, weil SVG-<text> sonst auf die Browser-Serife
   faellt — die Beschriftungen sollen die Seitentypografie tragen. */
.panorama-svg {
    display: block;
    width: 100%;
    height: auto;
    font-family: inherit;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

/* Kanten der Spaltenbaender und der Achse duerfen nicht verwischen. */
.panorama-svg .pan-band,
.panorama-svg .pan-heat,
.panorama-svg .pan-achse-linie {
    shape-rendering: crispEdges;
}

/* Die Chip-Karten liegen in der obersten Lage und sind deckend — Linien laufen
   dahinter durch. Ein weicher Schatten hebt sie vom Band ab. */
.panorama-svg .pan-chip-box {
    filter: drop-shadow(0 0.0625em 0.125em rgba(51, 70, 92, 0.18));
}

/* Leerzustand ("keine Treffer in diesem Profil") in Kursiv, damit er sich von
   den Spaltenkoepfen absetzt. */
.panorama-svg .pan-leer {
    font-style: italic;
}

/* Trefferflaechen in Phase 2. Es gibt genau EINEN treffbaren Datenknoten: den
   Positionspunkt. Seit Politur 3 traegt er KEIN natives <title> mehr (der
   Browser-Tooltip war ein zweiter, unstilisierter Text neben der gestylten
   Schwebkarte): die Maus-Info liefert die Schwebkarte, den barrierefreien Namen
   das aria-label des aktiven Punktes.
   Alles andere ist ausgenommen:
   - .pan-chip: die Karte zeigt ihre Angaben bereits im Klartext.
   - .pan-ende/.pan-ende-stummel: die Raute liegt exakt auf cx/cy des Punktes und
     wird NACH ihm eingehaengt. Bliebe sie treffbar, kaperte sie das Hit-Testing
     des Punktes. Sie ist deshalb von der Trefferflaeche ausgenommen; die Luecke
     bleibt visuell ueber Stummel + Raute eindeutig markiert.
   - .pan-lage-koepfe: die oberste Lage (Spaltenkoepfe + Leerzustands-Texte) liegt
     UEBER den Punkten. Der Leerzustands-Text steht auch im versteckten Zustand
     mittig im Plot und traegt nur opacity:0 — das unterdrueckt kein Hit-Testing
     und fing messbar Punkte ab (dieselbe Falle wie bei der Raute). */
.panorama-svg .pan-ende,
.panorama-svg .pan-ende-stummel,
.panorama-svg .pan-lage-koepfe {
    pointer-events: none;
}
.panorama-svg .pan-punkt {
    pointer-events: auto;
}
/* Positionszahl an den Punkten. Sichtbar (opacity 1) ist sie per
   Praesentationsattribut nur in der aktiven Spalte (Politur 2); die
   Nachbarspalten-Zahlen stehen auf opacity 0. Politur 3: beim Hover einer Bahn
   (= Spalte/Kontoprofil) werden ALLE Zahlen dieser Spalte eingeblendet — race.js
   schaltet ihnen die Klasse .pan-zahl-spalte-an zu (erste Regel unten). Die
   CSS-opacity schlaegt das Praesentationsattribut opacity:0. pointer-events:none ist
   Pflicht: die Zahl darf das Hit-Testing des Punktes nicht kapern UND faellt so im
   "unsichtbar+treffbar"-Scan nicht auf (bleibt auch nach dem Einblenden untreffbar).
   Farbe: ruhiges Ink, palettenkonform, mit Kontrast-Pendant. */
.panorama-svg .pan-punkt-zahl {
    pointer-events: none;
    fill: #33465C;
    font-weight: 600;
    paint-order: stroke;
    stroke: #dcebf8;
    stroke-width: 0.6;
    stroke-linejoin: round;
}
#vergleich.kontrast-hell .panorama-svg .pan-punkt-zahl {
    fill: #1A1A1A;
    stroke: #ffffff;
}
/* Spalten-Hover (die eigentliche Politur-3-Anforderung): race.js setzt die Klasse
   .pan-zahl-spalte-an auf alle Positionszahlen der gehoverten Spalte (data-spalte-
   Match, generisch — keine per-Key-Regeln, weil die Profil-Keys je Wrapper-Seite
   variieren). So sieht man alle Positionen einer Bahn, ohne die Spalte zu aktivieren. */
.panorama-svg .pan-punkt-zahl.pan-zahl-spalte-an {
    opacity: 1;
    transition: opacity 0.14s ease-out;
}
/* Ergaenzung: Linien-Hervorhebung. Faehrt man eine einzelne Konto-LINIE an, traegt
   deren pan-punkte-Knoten data-hervor (setzeHervorhebung) — dann werden die Zahlen
   genau dieses Kontos ueber ALLE Spalten sichtbar (Verlauf der Linie). Harmonische
   Zugabe zum Spalten-Hover, nicht die Kern-Anforderung. */
.panorama-svg .pan-punkte[data-hervor] .pan-punkt-zahl {
    opacity: 1;
    transition: opacity 0.14s ease-out;
}

/* ---------------------------------------------------------------------------
   PHASE 3, ETAPPE B — Trefferflaechen der Interaktion.

   Der Chip war in Phase 2 von der Trefferflaeche ausgenommen (die Karte zeigt
   ihre Angaben ja im Klartext). Ab Etappe B ist er ein OEFFNER des Detailpanels
   und deshalb wieder treffbar — Chip, Positionspunkt und Bahn oeffnen alle drei
   (Vorentscheidung: ~35 der ~50 Konten haben keine permanente Karte und waeren
   sonst mit der Maus unerreichbar).

   AUSGENOMMEN bleibt der Chip-LEADER: der gestrichelte Strich laeuft von der
   Karte zurueck zum Positionspunkt und ueberquert dabei die Punktespalte. Als
   treffbarer Knoten in einer Lage UEBER den Punkten kaperte er deren
   Hit-Testing — dieselbe Falle wie bei der Luecken-Raute in Phase 2.
   --------------------------------------------------------------------------- */
.panorama-svg .pan-chip {
    pointer-events: auto;
    cursor: pointer;
}
.panorama-svg .pan-chip-leader {
    pointer-events: none;
}

/* Die unsichtbare Trefferbahn. Sie ist ueber `stroke="transparent"` gemalt und
   damit treffbar, ohne sichtbar zu sein — `pointer-events: stroke` beschraenkt
   die Flaeche exakt auf den Strich, damit die (leere) Innenflaeche eines
   zurueckspringenden Bahnzugs nichts abfaengt. */
.panorama-svg .pan-hit {
    pointer-events: stroke;
    cursor: pointer;
}

/* Die schwebende Karte folgt dem Zeiger und liegt zwangslaeufig unter ihm.
   Waere sie treffbar, loeste sie beim Erscheinen sofort ein mouseout auf dem
   Knoten aus, der sie hervorgerufen hat — die Karte wuerde flackern. Sie ist
   deshalb durchgehend inert, in der Lage UND am Knoten (Gurt und Hosentraeger:
   opacity:0 allein unterdrueckt kein Hit-Testing). */
.panorama-svg .pan-lage-schweb,
.panorama-svg .pan-schweb {
    pointer-events: none;
}
.panorama-svg .pan-schweb-box {
    filter: drop-shadow(0 0.125em 0.25em rgba(51, 70, 92, 0.28));
}
#vergleich.kontrast-hell .panorama-svg .pan-schweb-box {
    filter: drop-shadow(0 0.125em 0.25em rgba(0, 58, 102, 0.3));
}

/* HERVORHEBUNG. Die uebrigen Bahnen treten ueber die Gruppen-Deckkraft zurueck;
   die hervorgehobene traegt data-hervor und bleibt voll. Deckkraft ist die
   einzige animierte Eigenschaft (kostet kein Layout), und sie ist hier
   ungefaehrlich fuer das Hit-Testing: die gedaempften Punkte SOLLEN treffbar
   bleiben, damit der Zeiger von Bahn zu Bahn wandern kann.

   Die Farben stehen bewusst NICHT hier — Linien-/Punktfarbe der hervorgehobenen
   Bahn setzt die Engine aus PALETTE (hervorLinie/hervorPunkt/hervorRand, beide
   Sets). Diese Datei regelt nur das Zuruecktreten. */
.panorama-svg[data-hervor] .pan-lage-linien .pan-konto,
.panorama-svg[data-hervor] .pan-lage-punkte .pan-punkte {
    opacity: 0.22;
    transition: opacity 0.14s ease-out;
}
.panorama-svg[data-hervor] .pan-konto[data-hervor],
.panorama-svg[data-hervor] .pan-punkte[data-hervor] {
    opacity: 1;
}

/* Die Chips daempft ausdruecklich ein FILTER und keine opacity-Regel.
   Grund, und das ist keine Stilfrage: die Engine schaltet die Sichtbarkeit
   jedes Chips ueber das PRAESENTATIONSATTRIBUT opacity (0 fuer die ~44 Konten
   ausserhalb der Top 12). Ein Praesentationsattribut hat die niedrigste
   Prioritaet ueberhaupt — eine CSS-opacity-Regel schlaegt es. Eine Regel
   `.pan-chip { opacity: .35 }` haette also ALLE ausgeblendeten Karten
   gleichzeitig sichtbar gemacht, sobald der Zeiger irgendeine Bahn beruehrt.
   `filter: opacity()` multipliziert dagegen mit dem Attributwert: 0 bleibt 0. */
.panorama-svg[data-hervor] .pan-lage-chips .pan-chip {
    filter: opacity(0.4);
}
.panorama-svg[data-hervor] .pan-lage-chips .pan-chip[data-hervor] {
    filter: none;
}

/* Die Spaltenkoepfe SIND ab Phase 3 der Profilwechsel (E4) und muessen deshalb
   wieder treffbar sein — ENG ausgenommen, nur die Kopfgruppen. Die Ausnahme
   gilt ausdruecklich NICHT fuer .pan-leer: der Leerzustands-Text liegt in
   derselben Lage, steht auch versteckt mittig im Plot und fing als treffbarer
   Knoten messbar Positionspunkte ab (der B1-Befund aus Phase 2).
   pointer-events:all statt auto auf der Trefferflaeche, weil sie fill=transparent
   traegt: `auto` (= visiblePainted) wuerde eine durchsichtige Fuellung nicht als
   getroffen werten, und der Kopf-Band-Rect ist in inaktiven Spalten fill=none. */
.panorama-svg .pan-kopf {
    pointer-events: auto;
    cursor: pointer;
}
.panorama-svg .pan-kopf-hit {
    pointer-events: all;
}
/* Der aktive Kopf ist kein Ziel mehr — der Zeiger soll das zeigen. */
.panorama-svg .pan-kopf[aria-current="true"] {
    cursor: default;
}
.panorama-svg .pan-kopf:focus {
    outline: 0.125em solid #0070C0;
    outline-offset: 0.125em;
}
#vergleich.kontrast-hell .panorama-svg .pan-kopf:focus {
    outline-color: #0070C0;
}
/* M4 Swipe-Verweilzeit — Vorschau der eingerasteten Spalte. JS setzt die Klasse
   pan-kopf-vorschau am <g class="pan-kopf">, waehrend die Orientierungsphase
   laeuft (Kopf-Band-Rect ist in inaktiven Spalten fill=none). Bewusst UNTER dem
   aktiven Zustand (kopfBand-Fuellung 0.16): schwaechere Fuellung + gestrichelter
   Akzent-Rahmen liest "eingerastet, gleich aktiv", ohne ein zweites aktives Profil
   vorzutaeuschen. Kein transition/animation -> auch unter prefers-reduced-motion
   unauffaellig (Anwender-Entscheid: Verweilzeit bleibt, nur der Morph ist hart).
   stroke-width in SVG-User-Units (wie bandRahmen), nicht em. */
.panorama-svg .pan-kopf-vorschau .pan-kopf-band {
    fill: rgba(0, 112, 192, 0.09);
    stroke: #0070C0;
    stroke-width: 1;
    stroke-dasharray: 3 2;
}
.panorama-svg .pan-kopf-vorschau .pan-kopf-1,
.panorama-svg .pan-kopf-vorschau .pan-kopf-2 {
    fill: #003A66;
    font-weight: 600;
}
#vergleich.kontrast-hell .panorama-svg .pan-kopf-vorschau .pan-kopf-band {
    fill: rgba(0, 112, 192, 0.10);
    stroke: #00528D;
}
#vergleich.kontrast-hell .panorama-svg .pan-kopf-vorschau .pan-kopf-1,
#vergleich.kontrast-hell .panorama-svg .pan-kopf-vorschau .pan-kopf-2 {
    fill: #00528D;
}

/* Chips blenden beim Spaltenwechsel weich ein/aus (der Morph selbst laeuft im
   JS ueber Attribute). Deckkraft ist die einzige animierte Eigenschaft — sie
   kostet kein Layout.

   ACHTUNG, hier stand bis Etappe B die Entwarnung "Hit-Testing ist unkritisch,
   .pan-chip steht ohnehin dauerhaft auf pointer-events:none". Das gilt NICHT
   mehr: seit der Chip das Detailpanel oeffnet, ist er treffbar (siehe oben).
   Damit ist die Deckkraft-Ausblendung sehr wohl kritisch geworden — genau die
   B1-Falle aus Phase 2, nur an neuer Stelle. Die Regel darunter schliesst sie. */
.panorama-svg .pan-chip {
    transition: opacity 0.18s ease-out;
}

/* AUSGEBLENDETE CHIPS SIND NICHT TREFFBAR.

   Die Engine versteckt Chips ausschliesslich ueber opacity:0 — in zeichneChips()
   (alle ausser den Top 12 der aktiven Spalte) und in zeichneMorphBild() (waehrend
   der Bewegung alle). opacity:0 unterdrueckt KEIN Hit-Testing. GEMESSEN nach
   einem Spaltenwechsel 3 -> 6: von 44 versteckten Chips waren 10 treffbar, weil
   sie aus dem vorigen Profil noch eine Position und damit eine gesetzte
   Geometrie trugen. Ein Klick auf eine optisch LEERE Stelle der Buehne oeffnete
   das Detailpanel eines fremden Kontos — mit der Positionsangabe des vorigen
   Profils.

   Beide Versteck-Pfade setzen konsistent aria-hidden="true" mit; daran haengt
   die Regel. Die Kopplung ist bewusst und muss bewusst bleiben: WER EINEN
   DRITTEN VERSTECK-PFAD BAUT, MUSS aria-hidden MITSETZEN, sonst ist die Karte
   unsichtbar und trotzdem klickbar. Semantisch passt es — was fuer
   Screenreader nicht existiert, soll auch die Maus nicht treffen.

   Warum nicht visibility: die Ein-/Ausblendung ist eine opacity-Transition;
   visibility haette den zusaetzlichen Verzoegerungs-Trick gebraucht (wie im
   Panel-CSS), ohne hier etwas zu gewinnen — pointer-events wirkt sofort und
   stoert die Blende nicht. */
.panorama-svg .pan-chip[aria-hidden="true"] {
    pointer-events: none;
}

/* Pill-Nav-Ruecknahme bei aktivem JS. Das Attribut setzt die Render-Engine
   EINMAL am <html> (nicht am Fragment): die Pill-Nav steht innerhalb der
   Partial-Swap-Zone und kaeme sonst bei jedem Filter-Swap ungefiltert zurueck.
   Ohne JS fehlt das Attribut, die Pills bleiben der No-JS-Profilwechsel. */
html[data-pan-js="1"] .panorama-dashboard > .filter-label:first-child,
html[data-pan-js="1"] .panorama-dashboard .nav-scroll-wrapper {
    display: none;
}

/* Fokus-Sichtbarkeit fuer die ab Phase 3 fokussierbaren Datenknoten — bereits hier
   angelegt, damit die Tastaturbedienung nicht nachtraeglich Optik nachziehen muss. */
.panorama-svg .pan-chip:focus,
.panorama-svg .pan-punkt:focus {
    outline: 0.125em solid #0070C0;
    outline-offset: 0.125em;
}

/* ---------------------------------------------------------------------------
   Hochkontrast-Hell (#vergleich.kontrast-hell). Die SVG-Inhaltsfarben schaltet
   die Render-Engine (PALETTE.hell); hier nur die Buehnen-Chrome, analog zum
   Bestandsmuster (#0070C0 / #00528D / #003A66).
   --------------------------------------------------------------------------- */
#vergleich.kontrast-hell .panorama-buehne {
    background: #ffffff;
    border-color: #b7c6d4;
}
#vergleich.kontrast-hell .panorama-svg .pan-chip-box {
    filter: drop-shadow(0 0.0625em 0.125em rgba(0, 58, 102, 0.22));
}
#vergleich.kontrast-hell .panorama-svg .pan-chip:focus,
#vergleich.kontrast-hell .panorama-svg .pan-punkt:focus {
    outline-color: #0070C0;
}

/* ===========================================================================
   PHASE 3, ETAPPE B — DETAILPANEL (Glas-Panel von rechts, E8/E11)

   Geruest im Core (body-level, ausserhalb des Partial-Fragments):
     .panorama-overlay#panoramaOverlay > .panorama-panel#panoramaPanel
       > .panorama-panel-body#panoramaPanelBody
   Den Schliess-Knopf und die Reiterleiste erzeugt die Engine; den Inhalt
   liefert der Endpoint ?partial=detail&ids=N.
   =========================================================================== */

/* BESTANDSKLASSEN IM PANEL — der entscheidende Befund dieser Etappe.

   Der Endpoint liefert Bestands-Markup (.merkmal-grid/.merkmal-row/
   .merkmal-label/.merkmal-wert/.anbieter-link) aus vergleich.min.css. GEMESSEN
   am gerenderten Panel (computed styles, nicht im Quelltext gelesen — ein
   fluechtiger Blick auf die Datei taeuscht hier, weil die Selektoren minifiziert
   aneinanderkleben): saemtliche Regeln sind auf einen Vorfahren
   `.vergleich-dashboard` gescopet, und derselbe Block traegt die CSS-Variablen,
   aus denen sie ihre Werte ziehen. Das Panel haengt am <body>, ausserhalb des
   Dashboards — dort kam .merkmal-grid mit display:block statt flex an, ohne
   Trennlinien, ohne Abstaende, mit geerbter Schriftgroesse.

   Geloest wird das NICHT hier, sondern indem die Engine dem Panel-Body die
   Klasse `vergleich-dashboard` gibt (siehe fuellePanel in race.js): dann greifen
   Grid, Zeilenabstaende, Trennlinien, Typografie und Token unveraendert wie in
   Liste und Tabelle, und ein spaeteres Bestands-Update wirkt automatisch mit.
   vergleich.min.css bleibt unangetastet.

   Diese Datei nimmt nur die Kosmetik zurueck, die der Klassenblock selbst
   mitbringt und die im Panel falsch waere (eigene Flaeche, Aussenabstand,
   Rundung, Innenpolster) — das Glas ist bereits die Flaeche. */
.panorama-panel .panorama-panel-body.vergleich-dashboard {
    background: none;
    margin: 0;
    padding: 0;
    border-radius: 0;
    /* Normal-Modus-Kontrast auf dem Glas (P4 Etappe B): der Bestands-Token
       --text-secondary (rgba(255,255,255,0.7)) trug .merkmal-label bei 3.97:1 —
       auf dem dunkelblauen Glas knapp unter 4.5. Hier auf 0.85 gehoben; das
       betrifft NUR das Panel (Liste/Tabelle behalten ihren Token). Der
       Hell-Satz weiter unten (html[data-pan-hell] …) ueberschreibt das durch
       spaetere Quellposition bei gleicher Spezifitaet. --text-primary (Werte)
       lag bereits bei 6.28:1 und bleibt. */
    --text-secondary: rgba(255, 255, 255, 0.85);
}

.panorama-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1200;
    background: rgba(9, 30, 48, 0.5);
    /* visibility statt display: display:none macht den Ein-/Ausflug des Panels
       untransitionierbar (der Wechsel passiert in einem Bild). visibility
       unterdrueckt das Hit-Testing genauso zuverlaessig — was opacity allein
       NICHT taete (der Phase-2-Blocker: ein nur durchsichtiges Overlay haette
       die gesamte Seite unklickbar gemacht). */
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.24s ease-out, visibility 0s linear 0.24s;
}
.panorama-overlay[data-offen] {
    visibility: visible;
    opacity: 1;
    transition: opacity 0.24s ease-out, visibility 0s linear 0s;
}

/* Das Glas-Panel selbst (E11): halbdurchsichtiges Dunkelblau mit Weichzeichner
   dahinter, damit das Panorama als Kontext durchscheint und der Nutzer nicht
   den Ort verliert, an dem er geklickt hat. */
.panorama-panel {
    position: absolute;
    top: 0;
    right: 0;
    height: 100%;
    width: 34em;
    max-width: 100%;
    box-sizing: border-box;
    /* Margin-Reset: der Bestand gibt <aside> einen Aussenabstand (style.css,
       margin-bottom 3.6em). Auf dem Desktop-Panel (top-verankert, height:100%)
       folgenlos, aber als Bottom-Sheet (bottom:0) schoebe er das Sheet um ~57px
       ueber den unteren Rand — gemessener Live-Fund P4/A. */
    margin: 0;
    padding: 1.5em 1.5em 2em;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: rgba(9, 87, 143, 0.92);
    -webkit-backdrop-filter: blur(1.25em);
    backdrop-filter: blur(1.25em);
    border-left: 0.0625em solid rgba(76, 181, 160, 0.45);
    box-shadow: -0.5em 0 2em rgba(0, 26, 48, 0.4);
    color: #ffffff;
    transform: translateX(100%);
    transition: transform 0.28s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.panorama-overlay[data-offen] .panorama-panel {
    transform: translateX(0);
}
.panorama-panel:focus {
    outline: none;
}

/* Schliess-Knopf (von der Engine erzeugt, der Core liefert ihn nicht mit).
   Politur 2: Optik 1:1 der Tagesgeld-DE-Referenz (.skyline-panel-close) —
   abgerundetes Quadrat, randlos, transluzentes Weiss; Klassenname und JS-Logik
   unveraendert. */
.panorama-panel-schliessen {
    position: absolute;
    top: 0.85em;
    right: 0.85em;
    width: 2.1em;
    height: 2.1em;
    padding: 0;
    border: 0;
    border-radius: 0.5em;
    background: rgba(255, 255, 255, 0.16);
    color: #ffffff;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 130ms ease;
}
.panorama-panel-schliessen:hover {
    background: rgba(255, 255, 255, 0.30);
}
.panorama-panel-schliessen:focus-visible,
.panorama-panel-schliessen:focus {
    outline: 0.125em solid #ffffff;
    outline-offset: 0.125em;
}

/* --- Kopf des Fragments --- */
/* Politur 2: Trennstrich unter der Bewertung entfernt; der Freiraum (padding)
   bleibt als ruhiger Abstand erhalten. */
.pan-detail-kopf {
    padding: 0 2.5em 1em 0;
}
.pan-detail-name {
    margin: 0 0 0.15em;
    font-size: 1.375em;
    line-height: 1.2;
    color: #ffffff;
}
.pan-detail-produkt {
    font-size: 0.9375em;
    /* 0.72 -> 0.85: auf dem Glas (rgba(9,87,143,0.92)) lag 0.72 bei 4.10:1
       (P4 Etappe B Kontrast-Feinschliff, gemessen). */
    color: rgba(255, 255, 255, 0.85);
}
.pan-detail-position {
    margin-top: 0.5em;
    font-size: 0.875em;
    font-weight: 600;
    /* #5fd4b8 (E11-Hover-Token) lag auf dem Glas bei 3.47:1. Auf #9ff0dd
       aufgehellt (gleiche Teal-Familie, nur heller) -> >= 4.5. Betrifft nur
       das Panel; der #5fd4b8-Token in Buehne/Bestand bleibt unberuehrt. */
    color: #9ff0dd;
}
/* Politur 4: .pan-detail-preis (Preiszeile unter der Bewertung) entfernt — der
   Kontopreis steht als Vergleichskriterium im Reiter "Kontofuehrung". preisText/
   panPreisText() speist weiterhin Chips, Mobile-Zeilen, Fallback-Tabelle und JSON. */

/* BEWERTUNGSPUNKTE. .stern-aktiv/.stern-inaktiv stehen NICHT in
   vergleich.min.css, sondern inline im Listen-Core — den die Panorama-Seite
   nicht einbindet. Gemessen: die Marken kamen ohne diese Regeln als
   nulldimensionale <span> an, die Bewertung war schlicht unsichtbar. Der
   Bestands-Konstruktion nachgebaut (runde Punkte, 0.625em), nicht als
   Stern-Glyphen. Aktiv-Farbe seit Politur 3 Gold #f5d564 (zweite Akzentfarbe,
   Tagesgeld-Diagramm-Goldton) statt des Bestands-Teal #1FD99B. */
.panorama-panel .sterne-display {
    display: flex;
    align-items: center;
    gap: 0.5em;
    margin-top: 0.6em;
    font-size: 0.8125em;
}
.panorama-panel .sterne-wert {
    font-weight: 700;
    color: #ffffff;
}
.panorama-panel .sterne-wert-max {
    font-weight: 400;
    color: rgba(255, 255, 255, 0.6);
}
.panorama-panel .sterne-zeile {
    display: inline-flex;
    gap: 0.25em;
}
.panorama-panel .stern-aktiv,
.panorama-panel .stern-inaktiv {
    display: inline-block;
    width: 0.625em;
    height: 0.625em;
    border-radius: 50%;
}
.panorama-panel .stern-aktiv {
    background: #f5d564;
}
.panorama-panel .stern-inaktiv {
    background: rgba(255, 255, 255, 0.22);
}
.panorama-panel .sterne-label {
    /* 0.7 -> 0.85: auf dem Glas lag 0.7 bei 3.97:1 (P4 Etappe B). */
    color: rgba(255, 255, 255, 0.85);
}

/* --- Reiterleiste (von der Engine ueber die vier <section> gelegt). Politur 2:
   durchgehendes Band mit Unterstreichung statt Pills (Muster der Listenansicht
   .details-tabs/.details-tab): duenne Unterkante am Container, Reiter transparent,
   aktiver Reiter mit Akzent-Unterstreichung. nowrap + overflow-x, damit die Leiste
   im Bottom-Sheet nicht bricht (wie in der Liste). --- */
.pan-detail-tabs {
    display: flex;
    flex-wrap: nowrap;
    /* Politur 4: gap 0 wie in der Liste (.details-tabs) — die Reiter bilden eine
       durchgehende Basislinie, auf der der Aktiv-Unterstrich sitzt. */
    gap: 0;
    margin: 1em 0 0.75em;
    /* rem statt em: 0.0625rem = 1px wie .details-tabs (border-bottom 1px). */
    border-bottom: 0.0625rem solid rgba(255, 255, 255, 0.16);
    overflow-x: auto;
    /* Politur 3: Scrollbalken dezent ausblenden, Scrollbarkeit erhalten. overflow-x:auto
       zwingt overflow-y auf auto; der aktive Reiter ragt ueber die Unterkante 1px in die
       Box -> Chromium blendete rechts einen 15px breiten vertikalen Scrollbalken ("Spinner"
       an der Reiterleiste, gemessen Desktop+Mobile) ein. Ausgeblendet fallen beide
       Balken weg und die vier Reiter gewinnen die 15px zurueck (passen dann ohne Scroll). */
    scrollbar-width: none;
    -ms-overflow-style: none;
}
.pan-detail-tabs::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
}
.pan-detail-tab {
    flex: 0 0 auto;
    /* Politur 4: Metrik in rem statt em — 1:1 zur Listen-Referenz .details-tab
       (padding 12px/16px, font-size 13px, border-bottom 2px). Vorher loeste
       border-bottom:0.125em gegen die kleine Panel-Font (Reiter ~11px) zu einem
       sub-pixel-Strich (~1px) auf, der auf dem Glas-Grund praktisch unsichtbar war
       ("kein Unterstrich"). rem macht ihn zum satten 2px-Strich wie in der Liste. */
    padding: 0.75rem 1rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.78);
    background: transparent;
    border: 0;
    border-bottom: 0.125rem solid transparent;
    margin-bottom: -0.0625rem;
    white-space: nowrap;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.pan-detail-tab:hover {
    color: #ffffff;
}
/* Politur 3: exakt wie die Listenansicht (.details-tab.active { color: var(--accent);
   border-bottom-color: var(--accent) }). Aktiv-Reiter traegt Text UND Unterstrich im
   Akzent var(--accent, #A9F6DB) — das helle Teal liegt gut lesbar auf dem dunkelblauen
   Panel-Grund (rgba(9,87,143,0.92)). Im Kontrast-Hell-Modus setzt der Override unten
   #09578F pur (heller Grund). */
.pan-detail-tab[aria-selected="true"] {
    color: var(--accent, #A9F6DB);
    border-bottom-color: var(--accent, #A9F6DB);
}
.pan-detail-tab:focus-visible,
.pan-detail-tab:focus {
    outline: 0.125em solid #5fd4b8;
    outline-offset: 0.125em;
}
.pan-detail-gruppe[hidden] {
    display: none;
}
.pan-detail-gruppe:focus {
    outline: none;
}

/* Bild-Marken in den Merkmalswerten (Neukundenaktion) duerfen die Zeile nicht
   sprengen. */
.panorama-panel .merkmal-wert img {
    max-width: 1.25em;
    height: auto;
    vertical-align: -0.15em;
}
.panorama-panel .merkmal-wert a {
    color: #5fd4b8;
}
/* Erfahrungsberichte-Icon (Politur 3). Das Bestands-Icon-Font <i class="icon
   icon-chat-empty"> ist position:absolute mit grossem negativem left-margin (~-1,6x
   der font-size) — in der Liste faengt ein position:relative-Wrapper (.service-link)
   das ab; im Panel fehlt der, sodass das Icon aus dem Merkmal-Wert ausbrach und (auf
   Mobile gemessen: x16 ueber Label bis x160) sein eigenes Kriterium ueberlagerte.
   Hier zuruecksetzen: statisch, ohne Negativ-Margin, inline im Wert rechtsbuendig.

   Politur 4: ZWEI Ergaenzungen.
   (1) pointer-events:none — der Icon-Font gewann trotz korrekter Border-Box (unten
       rechts) den elementFromPoint-Hit-Test ueber die GESAMTE Reiterleiste (live
       gemessen: x817..x1177, ~340px links + ~530px ueber seiner Box). Da das <i>
       Kind von <a href="erfahrungsberichte-...">target=portrait ist, landete jeder
       Reiter-Klick in den Erfahrungsberichten (Projekt-Memory: Icon-Fonts gewinnen
       elementFromPoint fern ihrer Border-Box). pointer-events:none nimmt das <i> aus
       dem Hit-Testing; der EB-Link bleibt ueber seine eigene <a>-Box klickbar
       (live verifiziert: Reiter treffen wieder den Button, EB-Link erreichbar).
   (2) color explizit gepinnt. Die Farbe kam bisher nur per Vererbung von der Bestands-
       .icon-Regel (#A9F6DB); faellt die weg, kippt das Icon auf Weiss. Listen-Messwert
       ist #A9F6DB (var(--accent)) — hier fest gesetzt, Hell-Override unten. */
.panorama-panel .erfahrungsberichte-row .merkmal-wert i.icon {
    position: static;
    margin: 0;
    display: inline-block;
    font-size: 1.75rem;
    line-height: 1;
    vertical-align: middle;
    pointer-events: none;
    color: var(--accent, #A9F6DB);
}
/* Geschenk-Icon der Neukundenaktion (Politur 3). Der Panel-Body traegt selbst die
   Klasse .vergleich-dashboard, also greift die Bestands-Regel
   `.vergleich-dashboard a.cardgifta img { width: 2.97em }` auch hier — sie wird nur
   von der generischen max-width:1.25em oben gedeckelt. Deckel fuer genau dieses Icon
   aufheben, damit es so gross wie in der Liste erscheint. */
.panorama-panel .merkmal-wert a.cardgifta img,
.panorama-panel .merkmal-wert img[src*="cardgift"] {
    max-width: 2.97em;
    width: 2.97em;
}

.pan-detail-cta {
    display: flex;
    justify-content: flex-end;
    margin-top: 1.5em;
    padding-top: 1em;
    border-top: 0.0625em solid rgba(255, 255, 255, 0.16);
}
.pan-detail-warte,
.pan-detail-error {
    margin: 2em 0;
    font-size: 0.9375em;
    color: rgba(255, 255, 255, 0.8);
}

/* --- Hochkontrast-Hell: das Glas wird weiss, die Schrift dunkel. --------- */
/* Im Kontrastmodus setzt der Bestand seine hellen Token ueber
   `#vergleich.kontrast-hell .vergleich-dashboard` — ein Selektor, der das
   body-level haengende Panel nicht erreicht. Der helle Satz wird deshalb hier
   am Panel-Body nachgezogen, mit denselben Werten wie im Bestand. */
html[data-pan-hell] .panorama-panel-body.vergleich-dashboard {
    --accent: #00528D;
    --accent-light: #0070C0;
    --primary-dark: #00528D;
    --primary-darker: #003A66;
    --bg-card: rgba(0, 82, 141, 0.05);
    --bg-card-hover: rgba(0, 82, 141, 0.10);
    --border: rgba(0, 82, 141, 0.30);
    --border-light: rgba(0, 82, 141, 0.14);
    --text-primary: #111;
    --text-secondary: rgba(0, 0, 0, 0.88);
    --text-muted: #404040;
}
html[data-pan-hell] .panorama-overlay {
    background: rgba(0, 26, 48, 0.35);
}
html[data-pan-hell] .panorama-panel {
    background: #ffffff;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-left: 0.0625em solid #00528D;
    color: #111111;
}
html[data-pan-hell] .pan-detail-name {
    color: #111111;
}
html[data-pan-hell] .pan-detail-produkt {
    color: #404040;
}
html[data-pan-hell] .pan-detail-position {
    color: #00528D;
}
html[data-pan-hell] .pan-detail-cta {
    border-color: rgba(0, 82, 141, 0.24);
}
html[data-pan-hell] .panorama-panel-schliessen {
    /* Heller Panel-Grund -> transluzentes Dunkel + dunkle Glyphe statt Weiss auf
       Weiss (randlose Politur-2-Optik). */
    color: #003A66;
    background: rgba(0, 82, 141, 0.12);
}
html[data-pan-hell] .panorama-panel-schliessen:hover {
    background: rgba(0, 82, 141, 0.22);
}
html[data-pan-hell] .panorama-panel-schliessen:focus-visible,
html[data-pan-hell] .panorama-panel-schliessen:focus {
    outline-color: #00528D;
}
html[data-pan-hell] .pan-detail-tabs {
    border-bottom-color: rgba(0, 82, 141, 0.24);
}
html[data-pan-hell] .pan-detail-tab {
    color: #00528D;
    background: transparent;
    border-bottom-color: transparent;
}
html[data-pan-hell] .pan-detail-tab:hover {
    color: #003A66;
}
/* Heller Grund -> #09578F pur traegt fuer Unterstreichung UND Aktiv-Text. */
html[data-pan-hell] .pan-detail-tab[aria-selected="true"] {
    color: #09578F;
    border-bottom-color: #09578F;
}
html[data-pan-hell] .stern-aktiv {
    background: #0070C0;
}
html[data-pan-hell] .stern-inaktiv {
    background: rgba(0, 82, 141, 0.18);
}
html[data-pan-hell] .sterne-wert {
    color: #111111;
}
html[data-pan-hell] .sterne-wert-max,
html[data-pan-hell] .sterne-label {
    color: #404040;
}
/* CTA im Kontrastmodus. Der Bestand faerbt .anbieter-link ueber
   background:var(--accent) + color:var(--primary-darker); im hellen Token-Satz
   sind das #00528D auf #003A66 — dunkel auf dunkel, gemessen unlesbar. Der
   Bestand hat dafuer keine Kontrast-Regel (geprueft: kein kontrast-hell-Selektor
   fuer .anbieter-link in vergleich.min.css). Da vergleich.min.css tabu ist und
   das Panel unsere Flaeche, wird die Schrift hier im PANEL-KONTEXT auf Weiss
   gezogen — eine bewusste Abweichung vom Bestands-Token, begruendet mit
   Lesbarkeit. Gilt nur innerhalb von .panorama-panel, faerbt Liste und Tabelle
   also nicht um. */
html[data-pan-hell] .panorama-panel .anbieter-link {
    background: #00528D;
    color: #ffffff;
}
html[data-pan-hell] .panorama-panel .anbieter-link:hover {
    background: #0070C0;
}
html[data-pan-hell] .panorama-panel .anbieter-link .link-arrow {
    background: #ffffff;
    color: #003A66;
}
html[data-pan-hell] .merkmal-wert a {
    color: #00528D;
}
/* Politur 4: EB-Icon im Hell-Modus dunkel (das gepinnte #A9F6DB waere auf dem
   weissen Panel-Grund unlesbar). #00528D wie die uebrige .merkmal-wert-Verlinkung. */
html[data-pan-hell] .panorama-panel .erfahrungsberichte-row .merkmal-wert i.icon {
    color: #00528D;
}
html[data-pan-hell] .pan-detail-warte,
html[data-pan-hell] .pan-detail-error {
    color: #111111;
}

/* ===========================================================================
   PHASE 4, ETAPPE A — MOBILE-VARIANTE (E7)

   Unter dem Mobile-Breakpoint (48em, s.u.) tritt an die Stelle des SVG-Panoramas
   eine Positions-Liste des AKTIVEN Profils: je Konto eine Zeile (Positions-Badge,
   Name, effektiver Preis, Bewertung als runde Bestands-Punkte, 7-Punkte-Profil-
   Sparkline) plus Profil-Pills oben. Das Detailpanel wird zum Bottom-Sheet.

   Die Liste haengt IMMER im DOM (die Render-Engine baut sie); der Desktop blendet
   sie per display:none aus — das nimmt sie aus Tab-Folge UND A11y-Baum (der
   aria-hidden-Vertrag in seiner staerksten Form). Umgekehrt wird die SVG-Buehne
   unter dem Breakpoint per display:none versteckt.

   FARBEN: die Liste erbt die Bestands-Tokens des Dashboards (var(--text-primary)/
   --bg-card/--border/--accent). Die kippen unter #vergleich.kontrast-hell bereits
   im Bestand (vergleich.min.css) von hell-auf-blau nach dunkel-auf-weiss — damit
   folgt die Liste BEIDEN Paletten ohne zweiten Farbsatz. Nur wo kein Token passt
   (Bewertungspunkte, aktiver Pill-/Badge-Text auf Akzentflaeche), steht ein
   kontrast-hell-Zusatz. GROESSEN bleiben em/rem (Coden-Regel); Tokens NUR fuer Farben.
   =========================================================================== */
.panorama-mobil { display: none; }

/* MOBILE-PROFILAUSWAHL (Politur 1): die ZWEI Bestands-Baender der Girokonto-Liste
   statt der frueheren Pill-Wolke. Band 1 (.panorama-mobil-band-profil) nutzt die
   geteilte .laufzeit-nav/.laufzeit-pill-Optik, Band 2 (.stufe/.alter) die geteilte
   .filter-group/.toggle-group/.toggle-btn-Optik aus vergleich.min.css (beide unter
   .vergleich-dashboard gescopet, das die Baender umschliesst). Hier nur der Rahmen:
   Abstaende, die Umschaltung von Band 2 (hidden) und die zwei Kontrast-Zusaetze, die
   die geteilten Klassen im Panorama-Kontext (Kontrast-Hell / dunkelblauer Grund)
   nicht selbst mitbringen. */
.panorama-mobil-baender { margin: 0 0 1em; }
.panorama-mobil-band { margin: 0 0 0.6em; }
.panorama-mobil-band[hidden] { display: none; }
/* Band-Buttons sind <button> (nicht <a>/<span> wie teils in der Liste): Schrift
   explizit erben, statt auf einen globalen Button-Reset zu vertrauen. */
.panorama-mobil-band .laufzeit-pill,
.panorama-mobil-band .toggle-btn { font-family: inherit; }
.panorama-mobil-band .filter-label { display: block; margin-bottom: 0.35em; }
/* Band 1: die .laufzeit-nav bringt Hintergrund/Radius selbst mit; nur den grossen
   Bestands-margin-bottom hier auf das Band-Mass zuruecknehmen. */
.panorama-mobil-band-profil .laufzeit-nav { margin-bottom: 0; }
.panorama-mobil-band-stufe .filter-group,
.panorama-mobil-band-alter .filter-group { margin: 0 auto; }

/* Normal-Modus-Kontrast (analog zum frueheren Pill-Override): der Bestands-Token
   --text-secondary (rgba(255,255,255,0.7)) traf auf dem blauen Panorama-Grund die
   inaktive Toggle-/Pill-Beschriftung bei nur ~3.6:1. Panorama-gescopet angehoben,
   ohne Cross-View-Divergenz (Liste/Tabelle tragen kein #vergleich-Panorama). */
#vergleich:not(.kontrast-hell) .panorama-mobil .toggle-btn:not(.active) {
    color: rgba(255, 255, 255, 0.92);
}
/* Kontrast-Hell: die Bestands-Toggle-Aktiv-Optik (var(--text-primary) -> #111 als
   Flaeche) waere dunkel-auf-dunkel. Wie die .laufzeit-pill.active im Core (Z.598)
   auf Marken-Blau/weiss ziehen; die inaktiven auf dunkelblau. Nur im Panorama. */
#vergleich.kontrast-hell .panorama-mobil .toggle-group { background: rgba(0,82,141,0.10); }
#vergleich.kontrast-hell .panorama-mobil .toggle-btn { color: #003A66; }
#vergleich.kontrast-hell .panorama-mobil .toggle-btn:hover { background: rgba(0,82,141,0.08); color: #003A66; }
#vergleich.kontrast-hell .panorama-mobil .toggle-btn.active { background: #0070C0; color: #fff; }

.panorama-mobil-liste {
    display: flex;
    flex-direction: column;
    gap: 0.5em;
    margin: 0;
    padding: 0;
    touch-action: pan-y pinch-zoom;
}
.panorama-mobil-leer {
    margin: 1.5em 0;
    font-style: italic;
    color: var(--text-secondary, rgba(255,255,255,0.7));
}
/* Zeile = Wrapper (Karte) mit ZWEI Bedienelementen: .panorama-mobil-tap (Karten-
   Tap, oeffnet das Detail-Sheet) und .panorama-mobil-spark-btn (Sparkline, oeffnet
   das Zoom-Overlay). Die Kartenoptik (Rand/Flaeche/Radius) liegt am Wrapper; die
   Sub-Buttons sind transparent. Zwei getrennte Buttons statt eines geschachtelten
   (nicht erlaubt) — so bleibt die Sparkline ein eigenes Tap-Ziel. */
.panorama-mobil-row {
    display: flex;
    align-items: stretch;
    width: 100%;
    background: var(--bg-card, rgba(255,255,255,0.05));
    border: 0.0625em solid var(--border, rgba(255,255,255,0.12));
    border-radius: 0.5em;
    overflow: hidden;
}
.panorama-mobil-row:hover { background: var(--bg-card-hover, rgba(255,255,255,0.09)); }
.panorama-mobil-tap {
    -webkit-appearance: none;
    appearance: none;
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.75em;
    min-height: 2.75em;              /* Touch-Target-Mindestmass (E7) */
    padding: 0.6em 0.75em;
    text-align: left;
    font-family: inherit;
    color: var(--text-primary, #fff);
    background: transparent;
    border: none;
    cursor: pointer;
    touch-action: pan-y pinch-zoom;
    -webkit-tap-highlight-color: transparent;
}
.panorama-mobil-tap:focus-visible,
.panorama-mobil-tap:focus,
.panorama-mobil-spark-btn:focus-visible,
.panorama-mobil-spark-btn:focus {
    outline: 0.125em solid #4cb5a0;
    outline-offset: -0.125em;
}
/* Sparkline-Bedienelement: eigenes Tap-Ziel rechts, durch eine feine Kante
   abgesetzt; >= 2,75em Touch-Target-Breite. */
.panorama-mobil-spark-btn {
    -webkit-appearance: none;
    appearance: none;
    /* Politur 4: die Sparkline ist das praegende Element -> feste 35% der Zeilenbreite
       (statt der bisherigen inhaltsbreiten ~4,4em). min-width bleibt als Touch-Floor. */
    flex: 0 0 35%;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 2.75em;
    padding: 0.4em 0.7em;
    background: transparent;
    border: none;
    border-left: 0.0625em solid var(--border, rgba(255,255,255,0.12));
    cursor: pointer;
    touch-action: pan-y pinch-zoom;
    -webkit-tap-highlight-color: transparent;
}
.panorama-mobil-spark-btn:hover { background: var(--bg-card-hover, rgba(255,255,255,0.09)); }
/* Rangnummer im Mobile-Kontext (Politur 3): exakt die Basis-Optik der
   Listen-Rangnummer .produkt-rang (Bestands-CSS: bg rgba(255,255,255,0.05),
   color var(--text-secondary), rund, fett; Mobile-Groesse 2rem/0.875rem, rem wie in
   der Liste fuer font-size-unabhaengige Touch-Targets). Die Panorama-Mobilzeile
   klappt nicht auf -> immer die ruhige Grund-Optik, nicht die gefuellte Aktiv-/
   Expanded-Variante (Akzent). */
.panorama-mobil-badge {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--text-secondary, rgba(255,255,255,0.7));
    background: rgba(255, 255, 255, 0.05);
}
.panorama-mobil-haupt {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.2em;
}
.panorama-mobil-name {
    font-size: 0.9375em;
    font-weight: 600;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.panorama-mobil-meta {
    display: flex;
    align-items: center;
    gap: 0.6em;
    font-size: 0.8125em;
    color: var(--text-secondary, rgba(255,255,255,0.7));
}
.panorama-mobil-preis { font-weight: 600; }
.panorama-mobil-preis.gratis { color: var(--accent, #A9F6DB); }
.panorama-mobil-bewertung {
    display: inline-flex;
    gap: 0.25em;
    flex: 0 0 auto;
}
.panorama-mobil-punkt {
    width: 0.7em;
    height: 0.7em;
    border-radius: 50%;
}
.panorama-mobil-punkt.an  { background: #f5d564; }
.panorama-mobil-punkt.aus { background: rgba(255,255,255,0.22); }
/* Sparkline: Profil-Fingerabdruck ueber alle 7 Spalten. Rein dekorativ
   (aria-hidden + pointer-events:none); die Angaben stehen textlich im aria-label
   der Zeile. Faerbung ueber currentColor -> var(--accent), kippt mit dem
   Kontrastmodus mit — keine zweite Farbquelle noetig. */
.panorama-mobil-spark {
    /* Politur 4: fuellt die 35%-Breite des Buttons (width:100% statt fester 4,4em);
       Hoehe leicht groesser, damit die breitere viewBox (104x34, race.js) mit
       preserveAspectRatio meet die Flaeche verzerrungsfrei ausfuellt. */
    flex: 1 1 auto;
    width: 100%;
    height: 2.4em;
    color: var(--accent, #A9F6DB);
    pointer-events: none;
    overflow: visible;
}

/* KONTRAST NORMAL-MODUS (P4 Etappe B). Der Bestands-Token --text-secondary ist
   im Normalmodus rgba(255,255,255,0.7) und traf auf dem blauen Seitengrund
   (#0070C0, ueber .bg-card) den Preis-/Meta-Text bei nur 3.60:1. Da .panorama-mobil-*
   Panorama-EIGENE Klassen sind (in Liste/Tabelle nicht vorhanden), hebt dieser
   Normal-nur-Override sie auf ~4.7:1, ohne irgendeine Cross-View-Divergenz: der
   Token selbst bleibt unangetastet, Liste/Tabelle unberuehrt. Im Hell-Modus greift
   die Regel NICHT — dort liefert der Token bereits dunklen Text auf hellem Grund.
   (Die Band-Beschriftungen decken die Politur-1-Baender-Overrides oben ab.) */
#vergleich:not(.kontrast-hell) .panorama-mobil-preis:not(.gratis) {
    color: rgba(255, 255, 255, 0.92);
}

/* Bewertungspunkte + Text auf Akzentflaeche: kein Dashboard-Token passt (der
   Akzent ist im Kontrastmodus #00528D — dunkel, dunkler Text waere unlesbar). */
#vergleich.kontrast-hell .panorama-mobil-punkt.an  { background: #0070C0; }
#vergleich.kontrast-hell .panorama-mobil-punkt.aus { background: rgba(0,82,141,0.18); }
/* Rangnummer im Kontrast-Hell: Basis-Optik der Listen-Rangnummer
   (#vergleich.kontrast-hell .produkt-rang { background: rgba(0,82,141,0.06) }, Text ueber
   var(--text-secondary) = rgba(0,0,0,0.88) auf hellem Grund). */
#vergleich.kontrast-hell .panorama-mobil-badge {
    background: rgba(0, 82, 141, 0.06);
    color: var(--text-secondary, rgba(0,0,0,0.88));
}

/* ---------------------------------------------------------------------------
   SPARKLINE-ZOOM-OVERLAY (Mobile, Politur 1). Body-level, EIGENE dunkle Optik
   (Marken-Dunkelblau #002A45 + Teal #A9F6DB) unabhaengig vom Kontrastmodus — die
   Karte ist eine eigene dunkle Flaeche, ein dunkler Kontrast-Akzent waere darauf
   unlesbar. z-index ueber dem Detail-Overlay (1200). Kein Ein-/Ausflug noetig; ein
   dezenter Fade reicht. --------------------------------------------------------- */
.panorama-spark-overlay {
    position: fixed;
    inset: 0;
    z-index: 1300;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Politur 2: schmaler Rand, damit die Karte nahezu die volle Viewport-Breite
       nutzt (mehr Platz fuer die sprechenden Stufenlabels). */
    padding: 0.6em;
    background: rgba(4, 20, 34, 0.62);
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.18s ease-out, visibility 0s linear 0.18s;
}
.panorama-spark-overlay[data-offen] {
    visibility: visible;
    opacity: 1;
    transition: opacity 0.18s ease-out, visibility 0s linear 0s;
}
.panorama-spark-karte {
    /* Politur 2: volle Viewport-Breite (max-width aufgehoben); das Overlay bleibt
       fixed/zentriert, die Karte fuellt die Breite bis auf den schmalen Rand. */
    width: 100%;
    max-width: none;
    background: #002A45;
    border: 0.0625em solid rgba(169, 246, 219, 0.35);
    border-radius: 0.85em;
    padding: 1em 1.1em 1.15em;
    box-shadow: 0 0.75em 2.5em rgba(0, 12, 24, 0.55);
}
.panorama-spark-kopf {
    display: flex;
    flex-direction: column;
    gap: 0.15em;
    margin-bottom: 0.6em;
}
.panorama-spark-name {
    font-size: 1em;
    font-weight: 700;
    color: #ffffff;
    line-height: 1.25;
}
.panorama-spark-cap {
    font-size: 0.75em;
    color: rgba(255, 255, 255, 0.72);
}
.panorama-spark-gross {
    display: block;
    width: 100%;
    height: auto;
}
.panorama-spark-gross-linie { opacity: 0.95; }
/* Schriftgroessen als SVG-Praesentationsattribut in JS gesetzt (Nutzereinheiten,
   kein CSS-px am DOM); hier nur Farbe/Gewicht/Familie. */
.panorama-spark-num {
    fill: #EAF6FF;
    font-family: inherit;
    font-weight: 600;
}
.panorama-spark-num.aktiv { fill: #A9F6DB; font-weight: 700; }
.panorama-spark-xlabel {
    fill: rgba(255, 255, 255, 0.72);
    font-family: inherit;
}
.panorama-spark-xlabel.aktiv { fill: #A9F6DB; font-weight: 700; }
@media (prefers-reduced-motion: reduce) {
    .panorama-spark-overlay { transition: none; }
}

/* ---------------------------------------------------------------------------
   MOBILE-BREAKPOINT (E7). 48em = der Punkt, an dem die geteilte Bestands-Chrome
   (vergleich.min.css + Listen-Core: Dashboard-Padding, laufzeit-nav, Filter-
   Section) selbst auf Mobile-kompakt umschaltet; der SVG-Panorama (viewBox 1280
   breit) ist hier ohnehin an der Lesbarkeitsgrenze. Ersetzt die fruehere
   36em-Notbremse (die war nur Defektschutz gegen ein 34em-Panel, kein Layout).
   --------------------------------------------------------------------------- */
@media (max-width: 48em) {
    /* AUSBAUSTUFE M1 — SCROLL-SNAP-PANORAMA.
       Die Buehne bleibt mobil sichtbar; .panorama-scroll wird zum horizontalen
       Snap-Container (das SVG ist breiter als der Viewport). aria-hidden auf der
       Buehne haelt den A11y-Pfad bis M2 bei der Liste; touch-action:pan-x gibt
       vertikale Gesten an die Seite zurueck (kein Gesten-Hijack). Die Mobile-Liste
       bleibt in M1 unveraendert sichtbar (Rueckbau erst M2). */
    .panorama-scroll {
        overflow-x: auto;
        overflow-y: hidden;
        scroll-snap-type: x mandatory;
        overscroll-behavior-x: contain;
        -webkit-overflow-scrolling: touch;
        touch-action: pan-x;
        scrollbar-width: none;
    }
    .panorama-scroll::-webkit-scrollbar { display: none; }
    /* Waehrend der programmatischen Zentrier-Korrektur (Morph) Snap aus. */
    .panorama-scroll[data-pan-snapoff] { scroll-snap-type: none; }
    /* Unsichtbare Snap-Punkte je Spalte (x-Position setzt das JS in vw). */
    .panorama-snap-anker {
        position: absolute;
        top: 0;
        width: 0.0625em;
        height: 100%;
        pointer-events: none;
        scroll-snap-align: center;
    }
    /* Projekt-Fehlerklasse "unsichtbar-aber-treffbar": die ganze SVG-Buehne ist in
       M1 inert. WICHTIG - pointer-events:none NUR auf .panorama-svg genuegt NICHT:
       nach CSS-Spec blockt ein none-Vorfahr keine NACHFAHREN, die selbst ein
       hittbares pointer-events setzen - und genau das tun .pan-hit (stroke, die
       breite Trefferbahn), .pan-kopf-hit (all) und .pan-punkte (auto). Ein Tap
       fast ueberall auf der Buehne loeste sonst ueber datenTreffer()/.pan-hit
       Hervorhebung/Schwebchip/Panel auf einer aria-hidden-Buehne aus. Deshalb der
       Nachfahren-Selektor: er ueberschreibt das eigene pointer-events JEDES
       SVG-Knotens (hoehere Spezifitaet + spaeter in der Quelle). Die einzige
       M1-Bedienung ist das native Scrollen der .panorama-scroll-Huelle (der Vorfahr
       des SVG) - das bleibt unberuehrt. (M2 macht die Buehne zum Primaerpfad;
       deshalb hier per CSS am aria-hidden-Zustand, kein JS-Guard in datenTreffer.) */
    .panorama-buehne[aria-hidden="true"] .panorama-svg,
    .panorama-buehne[aria-hidden="true"] .panorama-svg * { pointer-events: none; }

    /* AUSBAUSTUFE M2 — Buehne als Primaerpfad (Voll-Chips).
       Die Buehne ist NICHT mehr aria-hidden; die Voll-Chips der aktiven Spalte sind
       bedienbar. Nur die passiven Bedienspuren werden stillgelegt (Modus-Klasse
       .pan-mobil): Hitbahnen, Punkte, Koepfe, Kopf-Trefferflaechen, Endmarker,
       Positionszahlen. Die R1-Falle (.pan-hit treffbar) bleibt damit geschlossen;
       versteckte Chips deckt die Bestandsregel .pan-chip[aria-hidden]{pe:none} ab. */
    .panorama-buehne.pan-mobil .pan-hit,
    .panorama-buehne.pan-mobil .pan-punkt,
    .panorama-buehne.pan-mobil .pan-kopf,
    .panorama-buehne.pan-mobil .pan-kopf-hit,
    .panorama-buehne.pan-mobil .pan-ende,
    .panorama-buehne.pan-mobil .pan-ende-stummel,
    .panorama-buehne.pan-mobil .pan-punkt-zahl { pointer-events: none; }

    .panorama-mobil { display: block; }
    /* M2: die Voll-Chips ERSETZEN die Mobile-Liste -> den (leeren) Listen-Container
       ausblenden. Die Pill-Baender (.panorama-mobil-oben) und der Treffer-Zaehler
       bleiben sichtbar. Bei M1-Rollback (kein data-pan-chips) bleibt die Liste da. */
    html[data-pan-chips] .panorama-mobil-unten { display: none; }

    /* Detailpanel = Bottom-Sheet von unten (statt Glas von rechts). Endpoint,
       Cache, Fokusfalle, Escape, Overlay-Klick bleiben identisch — nur Geometrie. */
    .panorama-panel {
        top: auto;
        bottom: 0;
        left: 0;
        right: 0;
        width: 100%;
        max-width: 100%;
        height: auto;
        max-height: 85vh;
        border-left: none;
        border-top: 0.0625em solid rgba(76, 181, 160, 0.45);
        border-radius: 1em 1em 0 0;
        padding: 1.25em 1.15em 2em;
        box-shadow: 0 -0.5em 2em rgba(0, 26, 48, 0.4);
        transform: translateY(100%);
    }
    /* Griff-Andeutung oben am Sheet. */
    .panorama-panel::before {
        content: "";
        display: block;
        width: 2.5em;
        height: 0.3em;
        margin: -0.4em auto 0.9em;
        border-radius: 0.3em;
        background: rgba(255, 255, 255, 0.35);
    }
    .panorama-overlay[data-offen] .panorama-panel { transform: translateY(0); }

    /* Touch-Targets im Sheet ebenfalls >= 2,75em (E7). Politur-2-Referenzmasse. */
    .panorama-panel-schliessen {
        width: 2.75rem;
        height: 2.75rem;
        font-size: 1.25rem;
        top: 0.9em;
        right: 0.75em;
    }
    .pan-detail-tab { min-height: 2.75em; }
    .pan-detail-cta .anbieter-link {
        min-height: 2.75em;
        display: inline-flex;
        align-items: center;
    }

    /* Kontrast-Hell: heller Sheet -> dunkle Kante + dunkler Griff. */
    html[data-pan-hell] .panorama-panel { border-top-color: #00528D; }
    html[data-pan-hell] .panorama-panel::before { background: rgba(0, 82, 141, 0.35); }
}

/* ---------------------------------------------------------------------------
   prefers-reduced-motion: Phase 2 war statisch. Ab Etappe B gibt es echte
   Uebergaenge (Panel-Einflug, Hervorhebungs-Blende) — sie werden hier
   stillgelegt. Das Panel wird damit zum harten Schnitt (Vorgabe): es ist
   sofort da und sofort weg, statt einzuschweben.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .panorama-svg *,
    .panorama-buehne *,
    .panorama-overlay,
    .panorama-overlay * {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
    }
    /* Der Einflug wird uebersprungen, nicht bloss beschleunigt: eine auf 0.01ms
       verkuerzte Transform-Transition ist zwar unsichtbar, laesst das Panel aber
       weiterhin einen Frame lang ausserhalb des Bildes stehen. */
    .panorama-panel {
        transform: translateX(0);
    }
    .panorama-overlay:not([data-offen]) .panorama-panel {
        transform: translateX(100%);
    }
}

/* Bottom-Sheet unter reduced-motion: harter Schnitt auf der Y-Achse. Der Block
   oben setzt translateX (Glas von rechts) — auf Mobile faehrt das Sheet aber von
   UNTEN, deshalb hier translateY nachgezogen. Gleiche Spezifitaet wie oben, spaeter
   in der Quelle -> gewinnt unter dem Breakpoint. */
@media (prefers-reduced-motion: reduce) and (max-width: 48em) {
    .panorama-overlay[data-offen] .panorama-panel {
        transform: translateY(0);
    }
    .panorama-overlay:not([data-offen]) .panorama-panel {
        transform: translateY(100%);
    }
}
