
    /* === Tabellenansicht: spezifische Styles === */
    /* Filter-Section-Styles aus Listen-Core spiegeln (Anpassen-Overlay etc.) */
    /* 50.01em statt 50em (Audit A-7.2 / K6-Port DE 2026-08-12): zusammen mit dem
       `max-width: 50em`-Block darunter traf exakt 800px BEIDE Blocks — Panel gestapelt
       UND mit Desktop-Links-Border. Der Offset sitzt bewusst auf der min-width-Seite,
       damit 800px zur schmalen Variante gehoert. `.01em` statt `.0625em`, weil letzteres
       exakt 801px waere und damit eine volle Pixel-Breite unversorgt liesse; so bleibt
       die Luecke bei 0,16px und ist mit ganzzahligen Viewports nicht erreichbar.
       Aus AT/K6 portiert — das dort zitierte Bestands-Vorbild `min-width: 72.01em`
       gibt es in den DE-Cores nicht. */
    @media (min-width: 50.01em) {
        .filter-row-separator[style] .filter-column-separator { border-top: none; padding-top: 0; margin-top: 0; border-left: 1px solid var(--border); padding-left: var(--space-lg); margin-left: var(--space-md); }
    }
    @media (max-width: 50em) {
        .filter-row-separator[style] { grid-template-columns: 1fr !important; }
    }
    .filter-checkbox {
        display: flex; align-items: center; gap: 0.5em;
        padding: 0.375em 0; min-height: 2.25rem;
        cursor: pointer; font-size: 0.85rem;
        color: var(--text-secondary, #aab);
        transition: color 150ms ease; line-height: 1.35;
    }
    .filter-checkbox:hover { color: var(--text-primary, #fff); }
    .filter-checkbox input[type="checkbox"] {
        width: 1.25rem; height: 1.25rem; min-width: 1.25rem;
        accent-color: #00528d; cursor: pointer;
    }
    .filter-checkbox input[type="checkbox"]:checked + span {
        color: var(--text-primary, #fff); font-weight: 600;
    }
    /* Politur 2026-05-14: Anlagebetrag-Buttons ("bis EUR 4.999" / "EUR 5.000
       bis EUR 9.999" / "ab EUR 10.000") bleiben einzeilig — konsistent zum
       gleichnamigen Patch in der Listenansicht (`festgeld-vergleich-core.
       inc.php` Z. ~250 im 52em-Block). Hier global gesetzt, weil der
       Anwender den Fix "fuer alle Displaygroessen" angefordert hat. Der
       Ausland-Filter (`.ausland-filter-group`) bleibt ausgenommen — dort
       sind zwei laengere Strings ("Ja" / "Nein") in einem schmalen
       2-Button-Layout, die kein nowrap brauchen.
       max-width: 34em am Gruppen-Container greift nur im 52em-Block,
       damit nowrap auf schmaleren Viewports nicht ueber den Filter-
       Container hinausragt. */
    .vergleich-dashboard .filter-section .filter-group:not(.ausland-filter-group) .toggle-btn {
        white-space: nowrap;
    }
    @media (max-width: 52em) {
        .vergleich-dashboard .filter-section .filter-group:not(.ausland-filter-group) {
            max-width: 34em;
        }
    }
    /* Politur 2026-06-11c: wrap bleibt fuer den Mobile-Zweizeiler
       (result-count auf voller Breite, Pager + Sort in Zeile 2); auf
       Desktop sitzt der Pager inline zwischen Treffer-Zaehler und
       Sort-Buttons in EINER Zeile (Anwender-Feedback: keine
       zusaetzlichen Zeilen). */
    /* Politur 2026-05-07i: Result-Count bekommt 5% Linksabstand;
       Sort-Buttons sind in jeder Ansicht rechtsbuendig. 3-Klassen-Selektor
       (`.vergleich-dashboard.tabelle-dashboard ...`) schlaegt das
       2-Klassen-Default aus `vergleich.min.css`.
       Im Desktop-Modus ist `align-items: center` auf `.results-header`
       schon korrekt — `justify-content: flex-end` reicht aus. Erst im
       Mobile-Block (Site-CSS `max-width: 48em`: `flex-direction: column`,
       `align-items: stretch` auf dem Header + `justify-content: center`
       auf den Sort-Buttons) wird mit `align-self: flex-end` der Container
       aus dem Stretch geloest und rechts positioniert. */
    /* Politur 2026-05-18b: ehemaliger Mobile-Override fuer .sort-buttons
       entfernt — Pager-Mobile-Block weiter unten ueberschreibt. */
    /* === Anbieter-Pager "Fenster auf der Skala" (Politur 2026-06-11, gespiegelt von Festgeld AT) ============ */
    /* pager.hidden=true (Empty-State / Pool kleiner als ein Slot) muss
       gegen das Author-`display: flex` gewinnen — die UA-[hidden]-Regel
       allein verliert die Kaskade. */
    /* 11h: Slash nur in der Mobile-Kurzform "X–Y / N" sichtbar. */
    /* Politur 2026-06-11d: Ziffern-Sprung-Fix — beim Wechsel der Range
       von Einer- auf Zweierwerte (9 -> 10) wuerde der Text breiter und
       der Skala-Balken springt horizontal. inline-block + min-width: 2ch
       reserviert pro Zahl die Breite von zwei Ziffern (einstellige
       zentriert in der 2ch-Box) — gleicher Fix wie im Vorgaenger-Pager
       (Politur 2026-05-22). tabular-nums (oben) haelt die Ziffern selbst
       gleich breit. */
    /* Politur 2026-06-11d: Klickflaeche der Pfeile vergroessert
       (2.25em -> 2.75em, Glyph 1.5em -> 1.75em); 11e: Breite der
       Klickflaeche verdreifacht (2.75em -> 8.25em, Hoehe bleibt) —
       unsichtbare Pill-Hit-Area, Chevron bleibt zentriert. Auf Mobile
       gilt weiter der kompakte Override im 48em-Block (3em-Quadrat),
       sonst wuerde die einzeilige Pager+Sort-Zeile ueberlaufen. */
    /* Politur 2026-06-11g: Pfeil am Anschlag komplett AUSBLENDEN statt
       dimmen (Anwender-Entscheidung — ein sichtbarer, aber wirkungsloser
       Pfeil frustriert). visibility: hidden statt display: none, damit
       der Platz reserviert bleibt und Skala/Layout nicht springen;
       nimmt das Element zugleich aus dem Hit-Testing. */
    /* 11f: Glyph im 3:1-Format (viewBox 0 0 72 24) — langer Pfeil mit
       Schaft fuellt die 8.25em-Klickflaeche sichtbar aus (5.25em breit),
       statt als kleiner Chevron mit Leerraum zur Skala zu wirken. */
    /* Track-Hit-Area bleibt komfortabel (1.5em), die sichtbare Skala
       liegt schlank (6px) als ::before vertikal zentriert darin.
       touch-action: none, damit Touch-Scrubbing nicht mit dem
       Page-Scroll konkurriert. Tick-Raster-Hairlines im repeating-
       Gradient bewusst in px (analog border-width-Ausnahme). */
    /* Fenster: left/width setzt das JS in Prozent (Anbieter-Index-
       anteilig am Gesamtpool, Mindestbreite 8%). pointer-events: none —
       Klicks/Drags gehen an den Track. */
    /* Tooltip am Sortierbutton "Vergleichswert" — erklaert, was der Modus tut.
       Gleiches data-tooltip/::after-Muster wie der Zinszellen-Tooltip und die
       Listen-Schwester: reines CSS, kein JS, kein natives title. Das Attribut
       kommt mit jedem Server-Render mit und uebersteht damit sowohl den
       Clone-and-Replace der Sort-Buttons (kloneUndBinde in
       festgeld-tabelle-race.js) als auch den Cross-Fade-Tausch. Attribut-
       Selektor statt eigener Klasse: nur der Vergleichswert-Button traegt
       data-tooltip, Anbieter und Zinssatz bleiben bewusst ohne. */
    .vergleich-dashboard .sort-btn[data-tooltip],
    .vergleich-dashboard .sort-tooltip-btn { position: relative; }
    .vergleich-dashboard .sort-btn[data-tooltip]::after,
    .vergleich-dashboard .sort-tooltip-btn::after {
        content: attr(data-tooltip);
        position: absolute;
        top: calc(100% + 0.5em);
        right: 0;
        width: max-content;
        max-width: 22em;
        padding: 0.5em 0.75em;
        background: rgba(15, 20, 30, 0.95);
        color: #fff;
        /* font-weight zuruecksetzen: .sort-btn.active erbt sonst 700 in den Tooltip. */
        font-weight: 400;
        font-size: 0.75rem;
        line-height: 1.4;
        border-radius: 0.375em;
        box-shadow: 0 0.25em 0.75em rgba(0, 0, 0, 0.3);
        backdrop-filter: blur(8px);
        white-space: normal;
        text-align: left;
        pointer-events: none;
        opacity: 0;
        transform: translateY(-0.25em);
        transition: opacity 0.15s ease, transform 0.15s ease;
        z-index: 100;
    }
    .vergleich-dashboard .sort-btn[data-tooltip]:hover::after,
    .vergleich-dashboard .sort-btn[data-tooltip]:focus::after,
    .vergleich-dashboard .sort-btn[data-tooltip]:focus-visible::after {
        opacity: 1;
        transform: translateY(0);
    }
    /* Stacking: der Tooltip ragt ueber die Tabelle darunter. Deren Sticky-
       Zellen liegen bei z-index 3 (.ab-zelle-Header) bzw. 4 (.vp-spalte), der
       per JS an den body gehaengte Info-Tooltip bei 200. Der z-index sitzt am
       Button selbst (position: relative), damit der ::after mit ihm nach oben
       wandert. */
    .vergleich-dashboard .sort-btn[data-tooltip]:hover,
    .vergleich-dashboard .sort-btn[data-tooltip]:focus,
    .vergleich-dashboard .sort-btn[data-tooltip]:focus-visible,
    .vergleich-dashboard .sort-tooltip-btn.is-tooltip-open,
    .vergleich-dashboard .sort-tooltip-btn:focus,
    .vergleich-dashboard .sort-tooltip-btn:focus-visible {
        z-index: 300;
    }
    /* ⓘ-Trigger fuer Touch. Default unsichtbar — nur der (hover: none)-Block
       weiter unten blendet ihn ein, Desktop bleibt damit unveraendert.
       Sichtbar bleibt das Glyph klein; die Trefferflaeche vergroessert ein
       unsichtbares ::before (Bestandsmuster, siehe .ab-zins-balken::before) —
       padding wuerde das Glyph mitvergroessern. Der Slop waechst bewusst
       asymmetrisch nach oben/unten/rechts: nach links liegt der
       Vergleichswert-Button, dort wuerde eine breite Zone Sortier-Taps
       abfangen. */
    .vergleich-dashboard .sort-tooltip-btn {
        display: none;
        align-items: center;
        justify-content: center;
        padding: 0;
        border: 0;
        background: transparent;
        color: var(--text-secondary, rgba(255,255,255,0.7));
        font-size: 1.5em;
        line-height: 1;
        cursor: pointer;
    }
    .vergleich-dashboard .sort-tooltip-btn::before {
        content: '';
        position: absolute;
        top: -0.55em;
        bottom: -0.55em;
        left: -0.15em;
        right: -0.55em;
    }
    .vergleich-dashboard .sort-tooltip-btn.is-tooltip-open { color: var(--accent, #A9F6DB); }
    .vergleich-dashboard .sort-tooltip-btn.is-tooltip-open::after {
        opacity: 1;
        transform: translateY(0);
    }
    /* Geraete ohne :hover — ⓘ einblenden und den Hover-Tooltip des
       Sortierbuttons abschalten. Sonst zeigt "sticky hover" nach einem
       Sortier-Tap beide Tooltips gleichzeitig. Bewusst nur (hover: none)
       ohne pointer-Zusatz: die Bedingung "Hover funktioniert nicht" ist
       genau das Kriterium, an dem der Ersatz haengt. */
    @media (hover: none) {
        .vergleich-dashboard .sort-tooltip-btn { display: inline-flex; }
        .vergleich-dashboard .sort-btn[data-tooltip]::after { content: none; }
    }
    @media (max-width: 48em) {
        .vergleich-dashboard .sort-btn[data-tooltip]::after,
        .vergleich-dashboard .sort-tooltip-btn::after {
            max-width: 16em;
            font-size: 0.7rem;
        }
        /* Politur 2026-06-11d: EINZEILIGER Header auf Mobile. Der
           Treffer-Zaehler ("X Treffer · Laufzeit Y") ist ausgeblendet —
           Anwender-Entscheidung: Treffer-Anzahl steckt bereits im Pager
           ("von N"), die gewaehlte Laufzeit in den Einstellungen.
           display:none entfernt nur die Darstellung; die Trefferzahl
           bleibt fuer Crawler im separaten meta-Element daneben erhalten
           (K7 2026-08-13 - der sichtbare Zaehler traegt die Auszeichnung
           seitdem nicht mehr).
           Zeile: Pager links (kompakt — Skala-Track ausgeblendet, Platz
           reicht neben den Sort-Buttons nicht; Chevron-Paar bleibt) +
           `.sort-buttons` rechts (margin-left: auto). Site-CSS-Default
           (`flex-direction: column; align-items: stretch`) wird mit
           `row` + `flex-wrap: wrap` ueberschrieben — Spezifizitaet
           `.vergleich-dashboard.tabelle-dashboard .results-header`
           (0,3,0) schlaegt das Site-Default sauber. */
        .vergleich-dashboard.tabelle-dashboard .results-header {
            flex-direction: row;
            flex-wrap: wrap;
            align-items: center;
            row-gap: 0.4em;
        }
        .vergleich-dashboard.tabelle-dashboard .result-count {
            display: none;
        }
        .vergleich-dashboard.tabelle-dashboard .sort-buttons {
            align-self: center;
            margin-left: auto;
            /* 11h: 2.5%-Desktop-Randabstand auf Mobile opfern —
               jeder Pixel zaehlt fuer den Einzeiler. */
            margin-right: 0;
        }
        .vergleich-dashboard.tabelle-dashboard .tabelle-pager {
            flex: 0 1 auto;
            margin-inline: 0;
        }
        .tabelle-pager-track { display: none; }
        .tabelle-pager-leiste { flex: 0 0 auto; gap: 0; }
        /* 11h: Kurz-Range "X–Y / N" — "Anbieter" und "von" ausgeblendet,
           Slash an. Pfeil-Flaechen schmaler (2.25em breit, Hoehe 3em
           bleibt als Touch-Ziel), Glyph entsprechend kompakter, Gap enger. */
        .tabelle-pager { gap: 0.5em; }
        .tabelle-pager-prefix,
        .tabelle-pager-von-wort { display: none; }
        .tabelle-pager-slash { display: inline; }
        .tabelle-pager-btn { width: 2.25em; height: 3em; }
        .tabelle-pager-glyph { width: 2em; height: 0.7em; }
    }
    /* Zweizeiliger Sort-Pill (Cross-View 2026-06-26): wie Festgeld-DE-Liste.
       Richtung (`.sort-richtung`) bricht im Inline-Wrapper (.sort-kurz/.sort-label)
       auf Zeile 2 um — groessere Touch-Flaeche, einheitlich mit Tagesgeld/Girokonto. */
    @media (max-width: 38em) {
        .vergleich-dashboard.tabelle-dashboard .sort-btn .sort-richtung { display: block; }
    }
    /* Sortierbutton-Touchgroesse bis 48em (Cross-View 2026-06-26b): aus 38em-Block ausgelagert, Rollout des Tagesgeld-Patches */
    @media (max-width: 48em) {
        .vergleich-dashboard.tabelle-dashboard .sort-btn { font-size: 0.75rem; line-height: 1.2; text-align: center; }
    }
    .vergleich-dashboard .laufzeit-nav {
        flex-wrap: nowrap; overflow-x: auto;
        -webkit-overflow-scrolling: touch; scrollbar-width: none;
        scroll-snap-type: x mandatory;
        /* Fallback-Deklaration zuerst (Audit A-7.1 / K6-Port DE 2026-08-12): Engines ohne
           das `safe`-Keyword (WebKit/Safari, Chrome < 115) verwerfen die naechste
           Deklaration komplett. Ohne diese Zeile greift dort das zentrale `center` aus
           vergleich.min.css — bei Overflow werden die linken Laufzeit-Pills dann
           unerreichbar, weil scrollLeft nicht negativ werden kann. In Chromium aendert
           die Zeile nichts: dort gewinnt weiterhin das gueltige `safe center` danach. */
        justify-content: flex-start;
        justify-content: safe center; gap: 0.25em;
    }
    .vergleich-dashboard .laufzeit-nav::-webkit-scrollbar { display: none; }
    .vergleich-dashboard .laufzeit-nav .laufzeit-pill {
        min-height: 2.75em; scroll-snap-align: center;
        flex-shrink: 0; padding-left: 0.75em; padding-right: 0.75em;
    }
    /* Auto-Margins als Zentrier-Fallback (Audit A-7.1b / A-7.1b-Port DE 2026-08-12).
       NICHT ENTFERNEN und nicht mit der Fallback-Zeile oben "aufraeumen" - die
       beiden gehoeren zusammen. Auf Engines ohne `safe`-Keyword (WebKit/Safari,
       Chrome < 115) gewinnt oben die `flex-start`-Fallbackzeile; dort stuende
       die Leiste auch dann linksbuendig, wenn alle Pills in eine Zeile passen.
       (Der Deklarationstext wird hier bewusst NICHT woertlich zitiert, damit
       Zaehl-Sweeps ueber die Fallbackzeile eindeutig bleiben.)
       Auto-Margins zentrieren genau in diesem Fall und kollabieren bei Overflow
       auf 0 - die K6-Wirkung (linke Pills per scrollLeft erreichbar) bleibt
       damit erhalten. Live gemessen 2026-08-12 (Chromium 151, dpr 1, Alt-Engine
       simuliert per erzwungenem flex-start): bei 1200px Offset der ersten Pill
       8,00px -> 45,52px; bei Overflow (800/640/375px) computed margin exakt 0px
       und erste Pill erreichbar. Sweep 1260->1100px in 5px-Schritten: Kipppunkt
       bei ~1135px - oberhalb zentriert (margin > 0), unterhalb margin exakt 0,
       erste Pill in jeder Stufe erreichbar.
       In modernen Engines unveraendert bis auf 1/64px - und das nur in Chromium,
       Firefox und WebKit messen 0,000px: `center` legt die ungerade
       Rest-LayoutUnit rechts ab, die Auto-Margins links - sichtbar nur als
       Antialiasing-Nuance, `gap` und Snap-Punkte bleiben identisch.
       `:first-child`/`:last-child` sind zwingend - `:first-of-type` traefe wegen
       des gemischten Markups (aktive Pill = <span>, uebrige = <a>) ZWEI Elemente
       und risse die Leiste auseinander. */
    .vergleich-dashboard .laufzeit-nav .laufzeit-pill:first-child { margin-inline-start: auto; }
    .vergleich-dashboard .laufzeit-nav .laufzeit-pill:last-child { margin-inline-end: auto; }
    @media (hover: hover) and (pointer: fine) {
        .vergleich-dashboard .laufzeit-nav { cursor: grab; }
        .vergleich-dashboard .laufzeit-nav.is-dragging { cursor: grabbing; scroll-behavior: auto; user-select: none; }
        .vergleich-dashboard .laufzeit-nav.is-dragging .laufzeit-pill { pointer-events: none; }
    }
    .nav-scroll-wrapper {
        -webkit-mask-image: linear-gradient(to right, transparent, black 1.5em, black calc(100% - 1.5em), transparent);
        mask-image: linear-gradient(to right, transparent, black 1.5em, black calc(100% - 1.5em), transparent);
    }
    .nav-scroll-wrapper.scroll-start {
        -webkit-mask-image: linear-gradient(to right, black, black calc(100% - 1.5em), transparent);
        mask-image: linear-gradient(to right, black, black calc(100% - 1.5em), transparent);
    }
    .nav-scroll-wrapper.scroll-end {
        -webkit-mask-image: linear-gradient(to right, transparent, black 1.5em, black);
        mask-image: linear-gradient(to right, transparent, black 1.5em, black);
    }
    .nav-scroll-wrapper.scroll-start.scroll-end { -webkit-mask-image: none; mask-image: none; }
    /* Anlagebetrag-Toggle: interner Scroller analog Laufzeit-Nav. Verhindert
       horizontalen Dokument-Overflow auf schmalen Viewports (z.B. 390px): die drei
       nicht-umbrechenden Stufen-Buttons scrollen intern, statt das Dokument zu
       weiten. min-width:0 gibt dem Flex-Kind frei, unter die Inhaltsbreite zu
       schrumpfen (sonst erzwingen die nowrap-Buttons die volle Min-Content-Breite). */
    .vergleich-dashboard .filter-group:not(.ausland-filter-group) .toggle-scroll-wrapper { min-width: 0; }
    /* "Anlagebetrag"-Label + Band durchgaengig linksbuendig (Label buendig zum Band-Anfang in ALLEN
       Groessen): align-items:stretch hebt die geteilte Mobile-Regel `.filter-group{align-items:center}` auf,
       sodass der Band-Wrapper die filter-group fuellt statt zentriert/eingerueckt zu werden, wenn die fg
       breiter als das Band ist (z.B. ~700px, Breakpoint mit umgebrochenem Ausland-Toggle). min-width:0 +
       interner Scroll des Wrappers bleibt erhalten (kein Dokument-Overflow auf sehr schmalen Viewports).
       text-align:left rueckt den Label-Text linksbuendig. Ausland-balken-toggle (.ausland-filter-group)
       ausgenommen (Label+Toggle zentriert gewollt). Cross-Produkt-Sync 2026-06-28 (Folge-Politur). */
    .vergleich-dashboard .filter-group:not(.ausland-filter-group) { align-items: stretch; }
    .vergleich-dashboard .filter-group:not(.ausland-filter-group) .filter-label { text-align: left; }
    .vergleich-dashboard .filter-group:not(.ausland-filter-group) .toggle-group {
        flex-wrap: nowrap;
        min-width: 0;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        scroll-snap-type: x mandatory;
    }
    .vergleich-dashboard .filter-group:not(.ausland-filter-group) .toggle-group::-webkit-scrollbar { display: none; }
    .vergleich-dashboard .filter-group:not(.ausland-filter-group) .toggle-btn {
        flex-shrink: 0;
        scroll-snap-align: center;
        white-space: nowrap;
        /* Mehr horizontales Padding als die min.css-Basis (mobil nur 4-6px),
           damit die Stufen-Texte im Scroller nicht ineinanderlaufen. */
        padding-left: var(--space-md);
        padding-right: var(--space-md);
    }
    @media (hover: hover) and (pointer: fine) {
        .vergleich-dashboard .filter-group:not(.ausland-filter-group) .toggle-group { cursor: grab; }
        .vergleich-dashboard .filter-group:not(.ausland-filter-group) .toggle-group.is-dragging {
            cursor: grabbing;
            scroll-behavior: auto;
            user-select: none;
        }
        .vergleich-dashboard .filter-group:not(.ausland-filter-group) .toggle-group.is-dragging .toggle-btn { pointer-events: none; }
    }
    .toggle-scroll-wrapper {
        -webkit-mask-image: linear-gradient(to right, transparent, black 1.5em, black calc(100% - 1.5em), transparent);
        mask-image: linear-gradient(to right, transparent, black 1.5em, black calc(100% - 1.5em), transparent);
    }
    .toggle-scroll-wrapper.scroll-start {
        -webkit-mask-image: linear-gradient(to right, black, black calc(100% - 1.5em), transparent);
        mask-image: linear-gradient(to right, black, black calc(100% - 1.5em), transparent);
    }
    .toggle-scroll-wrapper.scroll-end {
        -webkit-mask-image: linear-gradient(to right, transparent, black 1.5em, black);
        mask-image: linear-gradient(to right, transparent, black 1.5em, black);
    }
    .toggle-scroll-wrapper.scroll-start.scroll-end {
        -webkit-mask-image: none;
        mask-image: none;
    }
    .vergleich-dashboard .filter-section { position: relative; margin-top: -1.1em; margin-bottom: 5em; overflow: visible; }
    .anpassen-panel {
        position: relative; z-index: 101; width: 90%; max-width: 60rem;
        margin: -3em auto 1em; background: rgba(9, 87, 143, 0.92);
        backdrop-filter: blur(1.25em); -webkit-backdrop-filter: blur(1.25em);
        border-radius: var(--radius-md, 12px); padding: 1.75em 1.5em 1.25em;
        border: 1px solid rgba(255,255,255,0.12);
        box-shadow:
            0 0.5em 2.5em rgba(0, 0, 0, 0.35),
            0 0.125em 0.5em rgba(0, 0, 0, 0.2),
            inset 0 1px 0 rgba(255,255,255,0.08);
        opacity: 0; transform: translateY(-0.75em);
        transition: opacity 125ms ease, transform 125ms ease;
    }
    .filter-panel-titel {
        display: block;
        font-size: 0.7rem;
        font-weight: 600;
        color: rgba(255, 255, 255, 0.7);
        text-transform: uppercase;
        letter-spacing: 0.5px;
        padding-bottom: 0.5em;
        margin-bottom: 0.75em;
        border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    }
    /* Politur 2026-05-21: Auf Mobile bricht das Panel aus dem Site-Container
       (`.vergleich-dashboard` mit seitlichem Site-Padding) per Full-Bleed-Pattern
       aus. `width: 95vw` plus `margin-left: calc(50% - 47.5vw)` laesst das Panel
       mit 2,5 % Sicherheitsabstand je Seite (~9 px auf 375-px-Viewport) bis nahe
       an den Viewport-Rand heranruecken, damit Ländernamen wie "Liechtenstein"
       oder "Großbritannien" nicht mehr ueber das Panel hinausragen (Screenshot
       2026-05-20 20:26). Border-Radius bleibt sichtbar. Desktop unveraendert
       (90 % mit max-width 60rem cap). */
    .panel-close-btn {
        position: absolute; top: 0; right: 0;
        width: 1.85em; height: 1.85em; padding: 0;
        background: rgba(48, 55, 61, 0.85); color: rgba(255, 255, 255, 0.85);
        border: none; border-top-right-radius: var(--radius-md, 12px);
        border-bottom-left-radius: 0; font-size: 1.5rem; line-height: 1;
        cursor: pointer; display: flex; align-items: center; justify-content: center;
        transition: background 125ms ease, color 125ms ease; z-index: 102;
    }
    /* Kontrast-Politur 2026-06-12 (Schwester-Rollout): Akzent-Texte #4cb5a0 ->
       Smaragdgruen #1FD99B; Hover-/Fokus-Stand der Akzentfamilie einheitlich
       #8FF6D5 (siehe Referenz-Core Festgeld AT). */
    /* Kontrast-Politur 2026-06-12 (Schwester-Rollout): Die Footer-Link-Farben
       (Ruhe #1FD99B / Hover #8FF6D5) sind ZENTRAL in vergleich.min.css definiert
       (`.vergleich-dashboard .footer-line a` bzw. `a:hover`). Anwender-Entscheidung
       gegen verteilte Definitionen: die frueheren Core-Overrides
       (.vergleich-footer a:link/:visited/:hover) sind entfernt. Bei
       min.css-Aenderungen den ?v=-Parameter am <link> oben bumpen (v=9). */

    /* === Eigentliches Tabellen-Layout === */
    /* Full-Bleed ab Tablet aufwaerts: Sortier-Bar, Tabelle und "mehr anzeigen"
       brechen aus dem zentrierten Site-Container aus und nutzen die volle
       Viewport-Breite. Schalterleiste und Filter-Bar bleiben oben im normalen
       Container — visuell ein klarer Datenbereich.
       Klassisches "left: 50%; margin-left: -50vw"-Pattern.
       Politur 2026-06-11 (Doc-Overflow-Fix): 100vw umfasst per CSS-Spec die
       vertikale Scrollbar — sobald die Seite vertikal scrollt, war der
       Container um die Scrollbar-Breite (6-17 px je nach Browser) zu breit
       und erzeugte horizontalen Doc-Overflow. `--viewport-w` wird per IIFE
       (tabelleViewportBreiteIIFE) auf documentElement.clientWidth gesetzt
       (= Viewport OHNE Scrollbar) und an :root vererbt; 100vw bleibt nur
       als No-JS-Fallback. */
    /* Vier-Stufen-Layout: gleichbreite Slots ueber den gesamten Nicht-Mobile-Bereich
       (analog DE-Hauptnav `#nav li { width: 11.111% }` = 100/9). Drei prozentuale
       Stufen, monoton fallende Anbieter-Anzahl ohne Spruenge zwischen den Schwellen
       (Politur 2026-05-09: untere Schwelle von 72em auf 38.0625em vorgezogen — der
       frueher dazwischenliegende Default-12em-Bereich 52-72em liess die Spaltenzahl
       beim Verkleinern wieder auf 4-5 anwachsen, weil weder min-width:72em noch
       max-width:52em griff. Folge: max-width:52em-Block setzt die Variablen nicht
       mehr, dort nur noch Font-/Padding-Politur):
         - >= 124em (4K + ueberbreit, ~1984px+):     9 Slots = 1 VP + 8 Anbieter à 11.111%
         -  76-124em (Full-HD-Standard, ~1216px):    6 Slots = 1 VP + 5 Anbieter à 16.667%
         -  38.0625-76em (Tablet-/Notebook-Bereich): 4 Slots = 1 VP + 3 Anbieter à 25%
         -  <= 38em:                                 Mobile-Block (3 Anbieter à 30vw, VP unsichtbar)
       Cascade: bei jedem Viewport greifen alle min-width-Regeln, die <= der
       Viewport-Breite sind — die letzte gewinnt (= naechstgroesserer Modus).
       Container-Innenbreite = 100vw - 1.5em links - 1.5em rechts = 100vw - 3em.
       Politur 2026-06-11 (Doc-Overflow-Fix): 100vw in den Stufen-Formeln durch
       var(--viewport-w, 100vw) ersetzt — selbe Begruendung wie am Full-Bleed-
       Block oben (100vw enthaelt die vertikale Scrollbar; die Slots haetten
       sonst weiter ueber den korrigierten Container hinausgehangen). */
    /* Politur 2026-05-11 (Sticky-Mini-Header): --slot-breite und --vp-breite
       jetzt am .tabelle-wrapper statt am .tabelle-scroller. Grund: CSS-Custom-
       Properties vererben nur an Descendants, nicht an Geschwister. Der
       Sticky-Mini-Header (.tabelle-sticky-mini) ist Sibling des Scrollers und
       konnte vorher die Variablen nicht lesen — Mini-Spalten waren auf den
       12em/14em-Fallback gefangen, Misalignment auf Desktop-mittel/breit.
       Migration auf den gemeinsamen Wrapper loest das. Der Scroller bleibt
       Descendant des Wrappers und erbt die Werte weiter. */
    .tabelle-wrapper {
        margin-top: 1em;
        position: relative;
        /* Default-Werte fuer --slot-breite/--vp-breite: greifen praktisch nur,
           wenn keine Media-Query matcht (siehe Z. ~840+). Migration vom
           .tabelle-scroller auf .tabelle-wrapper im Zuge der Sticky-Mini-
           Header-Einfuehrung (Politur 2026-05-11), damit der Mini-Track als
           Sibling des Scrollers die Variablen erbt. */
        --slot-breite: 12em;
        --vp-breite: 14em;
    }
    /* Scroll-Ende-Indikator: schmaler heller Schimmer-Gradient am rechten Rand
       der Tabelle deutet an, dass nach dem letzten sichtbaren Anbieter weitere
       folgen — der naechste Anbieter ist gerade ausserhalb des Viewports, sein
       Vorhandensein wird durch einen weichen Hell-Verlauf an der Container-Kante
       visuell signalisiert. Pseudo-Element sitzt auf dem nicht-scrollenden
       .tabelle-wrapper — bleibt beim horizontalen Scrollen am Container-Rand
       fixiert. Wird per JS-Klasse `.is-scroll-ende` ausgeblendet, sobald der
       Nutzer das Scroll-Ende erreicht (= alle Anbieter sichtbar gewesen) oder
       die Tabelle gar nicht horizontal scrollen muss (alle Anbieter passen rein).
       2026-05-07d: schmaler (3em → 2em) und in helle Farbe gewechselt
       (rgba(0,40,90,0.65) → rgba(255,255,255,0.20)) — Schimmer statt Schatten. */
    /* Phase 14 (A9): Linker Schimmer als Pendant zum rechten ::after.
       Default unsichtbar (User ist am Anfang = scrollLeft 0); sobald nach
       rechts gescrollt wurde, wird die Klasse `.is-scroll-anfang` per JS
       gesetzt und der Schimmer fadet ein — Hinweis darauf, dass es nach
       links zurueck noch Inhalt gibt. */
    .tabelle-scroller {
        /* Politur 2026-05-11 (Folgepatch): --hdr-logo-h von 11rem auf 12rem
           erhoeht. Begruendung: mit `flex-shrink: 0` am .ab-logo-wrap (siehe
           Z. ~1244) wird das Logo bei langen Anbieter-/Produktnamen nicht mehr
           gestaucht. Damit der Stack `Logo (max 8em) + Anbieter (max 2 Zeilen
           per line-clamp) + Produkt (1 Zeile per line-clamp) + Padding/Gap`
           ohne Ueberlauf in die Badge-Reihe passt, braucht die Reihe 12rem
           statt 11rem (Rechnung: 128 + 30 + 13 + 16 = 187 px ≤ 192 px). */
        --hdr-logo-h: 12rem;
        --hdr-badge-h: 2rem;
        --hdr-zins-h: 3rem;
        --row-data-h: 2.75rem;
        /* Politur 2026-05-10e: eigene Mindesthoehe fuer Bereichstitel-Reihen
           (.ab-gruppe-spacer + button.vp-gruppentitel), getrennt von
           --row-data-h. Auf Desktop deckt 2.75rem (~44 px) den VP-Gruppentitel-
           Button (padding 1.125em + line-height 1.15) — _vpRowSync zwingt sonst
           die VP-Tracks auf einen zu kleinen Wert und der Button overflowt.
           Auf Mobile ist die VP-Spalte display:none, der gleiche 2.75rem-Wert
           gibt den Bereichsbezeichnungen Atemluft ueber dem Toggle-Overlay
           (~30 px Inhalt) und bleibt deutlich kompakter als --row-data-h: 5rem
           (= 80 px Daten-Reihen). */
        --row-titel-h: 2.75rem;
        /* Politur 2026-05-13: Eigene Mindesthoehe fuer CTA-Footer-Reihen
           (Anbieterlinks). 80% von --row-data-h — Anwender-Wunsch: Felder
           mit Anbieterlinks niedriger als die Daten-Reihen, weil sie weniger
           Inhalt tragen und ohne Mini-Label oben keinen extra Padding-Raum
           brauchen. `minmax(--row-cta-h, auto)` laesst die Reihe weiter
           auto-wachsen, falls der Linktext laenger ist als 2.2rem (35 px). */
        --row-cta-h: 2.2rem;
        /* Vergleichswert-Sortierung: die Zins-Zelle traegt dann eine zusaetzliche
           Nominal-Zeile (.ab-zins-nominal). Die feste Track-Hoehe --hdr-zins-h
           (3rem) reicht dafuer nicht.
           Rechnung Desktop nach VRT-Nacharbeit A/B (Zellenschrift 1.5rem = 24 px,
           Padding 0.25em = 6 px, Nominal-Zeile 0.6875rem * 1.2 = 13,2 px, absolut
           gesetzt mit bottom: 0.25em = 2,75 px):
             Fluss-Inhalt  = Zahl 24 + Gap 9 + Balken 4 = 37 px (wie JEDE andere
                             Spalte — die Nominal-Zeile ist aus dem Fluss raus)
             bei T = 80 px  zentriert -> Zahl-Oberkante 21,5 / Balken-Unterkante 58,5
             Nominal        = Oberkante 64,05 / Unterkante 77,25
             Abstand Balken -> Nominal = 5,6 px, kollisionsfrei.
           Die Klasse .is-vergleichswert hebt die Variable nur in diesem Modus an.
           Sie sitzt bewusst an .vp-spalte und .tabelle-grid — den beiden einzigen
           Konsumenten der Variable — und NICHT am .tabelle-scroller: der Scroller-
           Knoten bleibt beim Cross-Fade dauerhaft im DOM (tauscheInnerenScroller-
           Inhalt ersetzt nur die zwei Grids und kopiert eine feste Liste von
           CSS-Vars), ein Flag an ihm wuerde beim Sortierwechsel per AJAX also
           weder ankommen noch je wieder verschwinden. An den Grids kommt es mit
           jedem Server-Render frisch mit. Klasse statt Inline-Style, damit die
           zwei Mobile-Stufen (1.25rem / 1.05rem Zellenschrift, siehe 52em- und
           38em-Block) eigene, kleinere Werte setzen koennen. */
        /* --slot-breite/--vp-breite definiert jetzt der .tabelle-wrapper
           (Politur 2026-05-11, Sticky-Mini-Migration). Default 12em/14em
           und Media-Query-Stufen (Z. ~840+ und Z. ~1700+) wirken via
           Inheritance auf den Scroller, der weiterhin grid-template-columns
           damit baut. Die calc-Logik ist analog zur DE-Hauptnav
           `#nav li { width: 11.111% }` (= 100/9). */
    }
    .vp-spalte.is-vergleichswert,
    .tabelle-grid.is-vergleichswert { --hdr-zins-h: 5rem; }
    /* Vergleichspunkt-Spalte: Flex-Item mit Sticky-Left, eigenes Grid (nicht mehr Subgrid) */
    .vp-spalte {
        flex-shrink: 0;
        width: var(--vp-breite, 14em);
        position: sticky;
        left: 0;
        z-index: 4;
        background: rgba(9, 87, 143, 0.92);
        border-right: 1px solid rgba(255,255,255,0.18);
        box-shadow: 0.25em 0 0.5em rgba(0,0,0,0.2);
        display: grid;
        /* Single-Track-Spalte, die der Outer-Width folgt. Ohne explizite Track-
           Definition fällt der Track auf grid-auto-columns: auto (= max-content)
           zurück — lange Labels weiten den Inner-Track dann über die Outer-
           Width aus. Mobile-Overrides setzen nur `width`, nicht den Track —
           Folge wäre VP-Zellen-Schimmer in die erste Anbieter-Spalte. minmax(0, 1fr)
           bindet den Track an den verfügbaren Platz und cappt min-content. */
        grid-template-columns: minmax(0, 1fr);
        /* Politur 2026-05-10e: --tabelle-data-rows enthaelt die explizite
           Daten-Track-Liste pro sichtbarer Reihe (Server: PHP-Loop ueber $reihen,
           JS-Toggle: updateGridTracks). Fallback ist die alte uniforme repeat()-
           Definition, falls die Variable mal nicht gesetzt ist. */
        grid-template-rows:
            var(--hdr-logo-h)
            var(--hdr-badge-h)
            var(--hdr-zins-h)
            var(--tabelle-data-rows, repeat(var(--anzahl-reihen-rest, 30), minmax(var(--row-data-h), auto)));
    }
    .tabelle-grid {
        flex-shrink: 0;
        display: grid;
        grid-template-columns: repeat(var(--anzahl-anbieter, 8), var(--slot-breite, 12em));
        grid-template-rows:
            var(--hdr-logo-h)
            var(--hdr-badge-h)
            var(--hdr-zins-h)
            var(--tabelle-data-rows, repeat(var(--anzahl-reihen-rest, 30), minmax(var(--row-data-h), auto)));
        align-items: stretch;
    }
    /* Anbieter-Spalte (article, subgrid in tabelle-grid) */
    /* Allgemeine Zell-Styles */
    /* Header-Stapel-Reihen — sticky oben, opaker Hintergrund.
       Logo-Reihe hat seit 2026-05-07 einen einfarbigen Hintergrund #0070C0
       (Anwender-Wunsch: Logo-Raender sollen nicht mehr sichtbar sein) —
       siehe eigene Regel weiter unten. badge/zins/balken behalten den
       semitransparenten Block-Background. */
    .vp-zelle.vp-header,
    .ab-zelle[class*="ab-badge"], .ab-zelle[class*="ab-zins"] {
        background: rgba(9, 87, 143, 0.92);
    }
    /* === Phase 8: Sticky-Header oben ===
       position: sticky stand urspruenglich fuer Vertikal-Scrolling im
       Scroll-Container (max-height + overflow-y: auto). Seit Politur
       2026-05-04 / 08l ist der Container ohne eigenen Vertikal-Scrollport
       (overflow-y: visible) — die top-Werte sind also funktional inaktiv.
       position: sticky bleibt trotzdem stehen, weil das ::after-Tooltip an
       .ab-zelle.ab-zins darauf als Containing-Block-Anker angewiesen ist
       (siehe Tooltip-Block ~Z. 1280). Stolperstein-Pflege fuer kuenftige
       top-Werte: rem-Variablen, niemals em (Phase-2-Stolperstein 3). */
    .ab-zelle.ab-logo,
    .ab-zelle.ab-badge,
    .ab-zelle.ab-zins,
    .vp-zelle.vp-header {
        position: sticky;
        z-index: 3;
    }
    .ab-zelle.ab-badge,
    .vp-zelle.vp-header.vp-badge  { top: var(--hdr-logo-h); }
    .ab-zelle.ab-zins,
    .vp-zelle.vp-header.vp-zins   { top: calc(var(--hdr-logo-h) + var(--hdr-badge-h)); }

    /* Phase 8 / 14e Sticky-Mini-Header (.tabelle-scroller.is-mini) wurde
       am 2026-05-11 durch den externen, fixed-positionierten Sticky-Mini-
       Header (siehe .tabelle-sticky-mini am Ende dieser Datei)
       abgeloest. Die alte Mechanik war auf einen vertikal scrollenden
       .tabelle-scroller angewiesen (max-height + overflow-y: auto), die
       seit Politur 2026-05-04 / 08l aus dem Container raus sind. Dadurch
       triggerte die is-mini-Klasse nie mehr. Die zugehoerigen CSS-Bloecke
       sind entfernt, ebenso die IIFE stickyHeaderSetup und die race.js-
       Hooks tabelleStickyHeaderReset/Setup. */

    /* Position-Badge im Logo-Feld (Anwender-Wunsch 2026-05-07; Politur
       2026-05-22 Schwester-Sync von Festgeld AT): Kreisform auf eine
       textuelle `#NN`-Notation umgestellt — passt besser zur uebrigen
       Tabellenoptik und spiegelt die Mobile-Variante im Meta-Strip.
       Position bleibt unveraendert (oben-links direkt am Logo, ueber
       `.ab-logo-wrap` als Containing-Block, NICHT am Spaltenrand wie auf
       Mobile). Inland-/Ausland-Pille bleibt in der separaten Badge-Reihe.
       tabular-nums fixiert die Ziffernbreite, white-space: nowrap haelt
       das Krueckchen `#` und Ziffern in einer Zeile. */
    /* Politur 2026-05-13: kompakter Meta-Strip oben links — Default Desktop
       unsichtbar. Mobile-Block (siehe @media (max-width: 38em) weiter unten)
       schaltet ihn sichtbar und positioniert ihn an der oberen linken Ecke
       der Logo-Zelle. Auf Desktop laeuft die Positionsnummer seit Politur
       2026-05-22 ueber den textuellen `.ab-pos-badge` (#NN-Notation)
       direkt am Logo; die Inland-/Ausland-Pille bleibt in der separaten
       Badge-Reihe. */
    .ab-meta-strip { display: none; }
    /* Politur 2026-05-07e: Hover ueber den Logo-Link darf KEINEN Farb-/
       Border-/Outline-Effekt erzeugen (Anwender-Wunsch — bisher zeigte sich
       beim Hover ein hellblauer Rahmen ueber das Logo). Site-globale
       Default-Hover-/Active-Effekte fuer a-Tags werden hier explizit
       ueberschrieben. Keyboard-Fokus (.ab-logo-link:focus-visible) bleibt
       fuer Accessibility erhalten. */
    .ab-zelle.ab-badge { padding-top: 0.25em; padding-bottom: 0.25em; }
    /* Politur 2026-05-07h: Trennlinie zwischen Badge-Reihe und Zins-Reihe
       entfaellt — Inland-/Auslandsanlage-Pille und Zinszahl fliessen optisch
       ineinander. Generelle `.vp-zelle, .ab-zelle { border-bottom: 1px ... }`
       (Z. ~750) bleibt fuer alle anderen Reihen aktiv. */
    .ab-zelle.ab-badge,
    .vp-zelle.vp-header.vp-badge {
        border-bottom: 0;
    }
    /* Kontrast-Politur 2026-06-12 (Schwester-Rollout): nur die Pill-TEXTE aufgehellt
       (#f5d678 -> #ffe49a; #8fdcc6 -> #b9f0e1). Die transparenten Hintergruende
       (alpha 0.18) bleiben — Transparenz-Look unveraendert. */
    /* Phase 14 (A8): Inland-Flagge auf Desktop versteckt (Default-Auslandsanlagen
       zeigen die Sitz-Flagge weiter neben dem Pill-Text). Auf Mobile uebernimmt
       die Mobile-Override-Regel: Pill-Text aus, Flagge fuer beide Varianten an. */
    /* Zinszelle: Zinszahl + Prozent oben (Baseline-Ausrichtung), horizontaler
       Balken am unteren Rand. Layout via flex-column. */
    /* Horizontaler Zinsbalken am unteren Rand der Zinszelle — analog zur Liste.
       Fill waechst von links nach rechts (`width: X%`).
       Tooltip via data-tooltip-Attribut + ::after-Pseudo-Element (Listen-Pattern).
       Hover-Zone via ::before vergroessert (Trefferflaeche um den 4px-hohen Balken). */
    /* Vergroesserte unsichtbare Hover-Zone (analog zur Liste): macht den
       4px-hohen Balken besser triffer- und tippbar. Oben bewusst kleiner
       (-0.35em) als unten (-0.75em), damit cursor:help nicht ueber die
       Zinszahl reicht — die Zahl gehoert nicht zur Klickflaeche. */
    /* Politur 2026-05-10: Tooltip-Pseudo-Element vom 7em-breiten .ab-zins-balken
       auf die Spalten-breite Zelle .ab-zelle.ab-zins verlagert. Damit kann
       max-width: 100% verwendet werden — der Tooltip ist nie breiter als die
       Anbieter-Spalte und ragt nicht ueber den linken/rechten Spaltenrand
       hinaus. Vorher: rechts-buendiger Balken (align-items: flex-end) plus
       right:0 + max-width:18em am Tooltip liessen den Tooltip um bis zu ~9em
       links ueber die Spaltenkante hinausragen — vom .tabelle-scroller
       (overflow-x: auto) wurde er dann visuell abgeschnitten.
       Hover/Focus-Trigger ist die ganze Zinszelle (ueber Zinszahl und Balken). */
    /* Zellen ohne data-tooltip (z.B. ab-zins-staffel oder ab-zins-leer) zeigen
       kein Pseudo-Element. */
    /* Vergleichswert-Sortierung: Nominalzins klein unter der Hauptzahl der
       Zinszelle — kompakter als in der Liste, weil die Anbieter-Spalte schmal
       ist. Details zur Positionierung und Schriftgroesse im Kommentar in der
       Regel selbst (VRT-Nacharbeiten A und B). */
    .ab-zelle.ab-zins .ab-zins-nominal {
        /* VRT-Nacharbeit A (2026-07-31): absolut positioniert statt im Flex-Fluss.
           Im Fluss schob die Zeile in der vertikal zentrierten Zelle
           (justify-content: center) die Zinszahl nach oben und den Balken nach
           unten — gemessen 11 px Versatz gegenueber den Nachbarspalten. Absolut
           positioniert traegt sie nichts mehr zur Flow-Hoehe bei: im Fluss
           bleiben Zahl + Balken mit genau einem Gap dazwischen, also exakt die
           Geometrie jeder anderen Spalte — auch in per Lazyload nachgelieferten
           Spalten, die dieselbe Zellstruktur erben.
           Containing Block ist die Zinszelle selbst (ihr position: sticky zaehlt
           als positioniert). padding-right: inherit uebernimmt den COMPUTED
           px-Wert des Zellen-Paddings; dadurch sitzt die Nominal-Zeile auf allen
           drei Breakpoints buendig auf der rechten Kante von Zahl und Balken,
           ohne die drei Padding-Stufen (0.625em/0.5em/0.4375em je eigener
           Zellenschrift) hier spiegeln zu muessen.
           VRT-Nacharbeit B: font-size in rem statt 0.45em — die em-Kaskade ergab
           auf 375px nur 7,56 px fuer die Kernaussage. 0.6875rem = 11 px auf
           allen Stufen. */
        position: absolute;
        right: 0;
        bottom: 0.25em;
        padding-right: inherit;
        font-size: 0.6875rem;
        font-weight: 400;
        line-height: 1.2;
        white-space: nowrap;
        color: rgba(255, 255, 255, 0.72);
    }
    /* Vergleichspunkt-Spalte: spezifische Header-Zellen */
    .vp-zelle.vp-header.vp-logo, .vp-zelle.vp-header.vp-badge { font-size: 0.62rem; }
    /* Politur 2026-05-07h: "Zinssatz p. a." in gemischter Klein-/Gross-
       schreibung statt uppercase — Spezifitaet (3 Klassen) ueberschreibt
       den `.vp-zelle.vp-header { text-transform: uppercase }`-Default
       (2 Klassen) gezielt nur fuer die Zins-Reihe. */
    /* Gruppen-Titel-Reihen.
       Politur 2026-05-07g: vertikales Padding erhoeht (0.75/0.5em → 1.125/1em)
       und line-height: 1.15 — bei zweizeiligen Titeln wie "Ausschuettung/
       Auszahlung" stehen die zwei Worte enger zusammen, der Block hat dafuer
       mehr Luft nach oben und unten. Bleibt visuell bei einzeiligen Titeln
       unauffaellig (line-height greift nur, wenn Text umbricht). */
    /* Spacer-Zellen in Anbieter-Spalten an Stelle des VP-Gruppentitels.
       Redesign 2026-06-19 (Expander-Band "Feine Koernung", Handoff Variante 02):
       Das Band ist jetzt eine eigene, ruhige Flaeche mit feiner Koernung statt
       der frueheren flachen var(--bg-card)-Zelle. Diese Spacer setzen die
       Koernungs-Flaeche des VP-Gruppentitel-Buttons (siehe button.vp-gruppentitel
       weiter unten) ueber alle Anbieter-Spalten fort, sodass das Band als eine
       durchgehende texturierte Oberflaeche ueber die volle Tabellenbreite laeuft.
       Basis-Toenung rgba(0,82,141,0.40) (Anwender-Wahl 2026-06-19 "ruhig
       integriert" statt solidem #0070C0). Die Koernung ist bewusst in px statt
       em — eine Material-Textur hat eine feste physische Rasterweite und darf
       NICHT mit der Schriftgroesse skalieren (zulaessige Ausnahme zur em-Regel,
       analog box-shadow). Koernung/Borders/Sheen sind byte-gleich zum
       button.vp-gruppentitel, damit Label-Zelle und Fortsetzung nahtlos sind. */
    /* Merkmal-Zellen (lange Texte werden umgebrochen).
       Phase 14 (A3): position: relative als Containing-Block fuer das
       Mini-Label-Overlay (Mobile). Default Desktop ist das Label per
       `display: none` ausgeblendet — kein Layout-Effekt.
       Politur 2026-05-11 (Werte-Hierarchie): expliziter `--text-primary`
       (= reines Weiss) statt geerbter `--text-secondary` aus `.ab-zelle`
       (Z. ~993). Damit die Werte gegenueber den gedimmten Mini-Labels
       (`rgba(255,255,255,0.55)` an `.ab-mini-label`, siehe Mobile-Block)
       die dominantere Schriftfarbe sind. Konsistent mit `.ab-anbieter`
       (Z. ~1293) und `.ab-zelle.ab-zins` (Z. ~1345) — Werte stehen jetzt
       im selben Primaer-Layer wie Anbietername und Zinszahl. Die
       spezifischere Regel `.ab-merkmal.ab-leer` (rgba 0.3, naechste Zeile)
       behaelt Vorrang per Source-Order — leere Zellen bleiben gedimmt. */
    /* Phase 14 (A7): Truncate-Spans und Info-Icon — Default Desktop sichtbar
       der Volltext, Kurz-Variante und Info-Icon ausgeblendet. Mobile-Switch
       weiter unten im 38em-Block. */
    .ab-merkmal-voll { display: inline; }
    .ab-merkmal-kurz { display: none; }
    /* Geschenk-Icon Neukundenaktion (cardgift-m.svg): wie Tagesgeld-Schwester —
       Hover haelt Tuerkis (Site-Default `a.cardgifta:hover img` schoebe das gruene
       Icon per hue-rotate ins Gelbe), Icon +10% (2.97em ggue. Site-Default 2.7em
       aus style.css). Hoehere Spezifitaet als die Site-Defaults, Position unkritisch. */
    .ab-merkmal-html a.cardgifta:hover img { filter: brightness(1.12); }
    .ab-merkmal-html a.cardgifta img { width: 2.97em; }
    /* Tooltip fuer Info-Icon (Mobile-Truncate). Wird per JS-IIFE
       `infoTooltipSetup()` an document.body angehaengt. */
    .ab-info-tooltip {
        display: none;
        position: absolute;
        z-index: 200;
        max-width: 18em;
        padding: 0.5em 0.75em;
        background: rgba(15, 20, 30, 0.95);
        color: #fff;
        font-size: 0.75rem;
        font-weight: 400;
        line-height: 1.4;
        border-radius: 0.4em;
        box-shadow: 0 0.25em 0.75em rgba(0, 0, 0, 0.35);
        pointer-events: auto;
    }
    .ab-info-tooltip.is-visible { display: block; }
    /* Politur 2026-05-11: i-Button in der Logo-Zelle bei truncated
       Anbieter-/Produktnamen. PHP rendert den Button immer als Sibling am
       Ende von .ab-produktname; die Sichtbarkeit wird ueber die `.is-
       truncated`-Klasse gesteuert, die JS-IIFE `tabelleLogoTruncateSetup`
       per `scrollHeight > clientHeight`-Test setzt (siehe Z. ~3640).
       Default ist `display: none` — Button ist nur sichtbar, wenn der
       Text-Stack im DOM truncated wurde.
       Spezifizitaet `.ab-zelle.ab-logo .ab-info-icon-logo` (0,3,0) schlaegt
       die Mobile-Block-Regel `.ab-info-icon` (0,1,0) — Layout konsistent
       Desktop + Mobile. Inline-Positionierung (margin-left an .ab-
       produktname-Ende) statt Overlay oben rechts: das Logo traegt bereits
       ein i-Glyph in der SVG und ist per .ab-logo-link.iframe mit der
       Anbieterinformation verlinkt — ein zweites Symbol oben rechts wirkte
       doppelt; inline klebt der Volltext-Hinweis am Ort der unvollstaendigen
       Information. */
    /* Sichtbarmach-Regel: Button bekommt `.is-truncated` von JS,
       sobald .ab-anbieter ODER .ab-produktname truncated ist. */
    /* Hitbox-Slop fuer Touch-Targets. 0.8em ringsum bei 1em-Button-
       Schrift = 0.8 * 11.2 ≈ 9 px Slop, zusammen mit ~16 px Button-Visual
       ergibt ~34 px Hitbox auf Mobile. Unter AAA-44px, aber praktikabel
       fuer den sekundaeren Button. */
    /* Footer-CTA */
    /* CTA-Footer-Zellen mit dem Anbieter-Button.
       Politur 2026-05-07j: Hintergrund von dunkelblau-gesaettigt
       (rgba(9,87,143,0.96)) auf var(--bg-card) umgestellt — selbe Farbe
       wie .vergleich-dashboard .filter-section und seit 2026-05-07e auch
       die .ab-gruppe-spacer. Wirkt heller und konsistent zum Filter-Bereich. */
    /* CTA-Link selbst (`.anbieter-link` + `.link-arrow`) erbt vollstaendig
       aus vergleich.min.css (`.vergleich-dashboard .anbieter-link…`).
       Dort ist auch `::after { content:none !important }` definiert, das
       das vom globalen Theme injizierte Linksymbol fuer externe Links unterdrueckt.
       Phase 14 (A6): Externer-Link-Icon Default unsichtbar, Mobile-Switch
       weiter unten im 38em-Block. Spezifizitaet `.vergleich-dashboard …`
       schlaegt das Listen-globale `.anbieter-link`-Styling. */
    /* Politur 2026-05-08i (A4): Zusatzinfos-Fussnoten unterhalb der Tabelle.
       Greift auf allen Display-Groessen. Hintergrund analog zu .ab-gruppe-
       spacer und .ab-cta auf var(--bg-card) — fuegt sich nahtlos in das
       Tabellen-Visual ein. Hanging-Indent macht den Anbieter-Marker links
       sichtbar bei Mehrzeilern.
       Politur 2026-05-08j: margin-top von 1.5em auf 4.5em erhoeht (= +3em
       Atemluft zwischen Tabelle/Mehr-anzeigen-Knopf und Fussnoten-Sektion).
       Plus Viewport-Filter: .is-out-of-view blendet Eintraege aus, deren
       Anbieter-Spalte gerade nicht im horizontalen Scroll-Viewport liegt;
       .is-leer blendet die ganze Sektion aus, wenn kein Eintrag passt. */
    /* Mobile: schmaler padden, kleinere Schrift. */
    @media (max-width: 38em) {
        .tabelle-fussnoten {
            padding: 0.875em 1em;
            font-size: 0.8rem;
        }
    }
    /* Empty State */
    /* Responsive */
    @media (max-width: 52em) {
        /* Politur 2026-05-09: --slot-breite und --vp-breite werden ab dem
           38.0625em-Block (oben) per calc((100vw - 3em) / 4) gesetzt — hier
           nur Font-Size/Padding-Politur fuer Tablet/kleinere Notebooks.
           Vorher: --slot-breite: 10em und --vp-breite: 12em fix; das fuehrte
           zu 2-4 sichtbaren Anbietern je nach Bruchteil und nicht zur klaren
           3-Anbieter-Stufung. */
        .vp-zelle, .ab-zelle { font-size: 0.78rem; padding: 0.4375em 0.5em; }
        .ab-zelle.ab-zins { font-size: 1.25rem; }
        /* Vergleichswert-Modus, Rechnung wie im Default-Block (Zellenschrift
           1.25rem = 20 px, Padding 5 px, Nominal absolut 13,2 px + 2,75 px):
             Fluss-Inhalt = 20 + Gap 7,5 + Balken 4 = 31,5 px
             bei T = 72 px -> Balken-Unterkante 51,75 / Nominal-Oberkante 56,05
             Abstand 4,3 px, kollisionsfrei. Der Wert steigt gegenueber der
             ersten Fassung (4rem), weil die Nominal-Zeile seit Nacharbeit B
             nicht mehr mit der Zellenschrift schrumpft, sondern fest 11 px hat. */
        .vp-spalte.is-vergleichswert,
        .tabelle-grid.is-vergleichswert { --hdr-zins-h: 4.5rem; }
    }
    /* Mobile-Hauptblock (Politur 2026-05-08, Phase 14, weiter angepasst in
       Folgepatch 14c):
       Drei Anbieter-Spalten mit je 1/3 Viewport. VP-Spalte ist auf Mobile
       komplett unsichtbar (`display: none`) — die Reihen-Labels uebernehmen
       die Mini-Labels, die Bereichsbezeichnungen rendern in der ersten
       Anbieter-Spalte (siehe Mini-Label-Block plus mb-gruppentitel-Block
       weiter unten). `--vp-breite: 0px` bleibt fuer die Variable, weil
       `.tabelle-scroller { scroll-padding-left: var(--vp-breite, 14em); }`
       sie verwendet — `0px` vermeidet ein vp-Breite-grosses Snap-Padding,
       das sonst die linkste Spalte zu weit nach rechts wegschneiden wuerde
       (Stolperstein 13). --hdr-logo-h auf 8rem statt 11rem reduziert die
       Logo-Reihe. font-size/padding-Werte aus dem alten 38em-Block uebernommen.
       Die alte 29em-Stufe (3-Slot-Layout fuer Smartphones im Hochkant) entfaellt,
       weil dieses Mobile-Layout ohnehin durchgaengig 3 Spalten zeigt.

       Vertikal-Scroll-Port (Phase 14, A2) entfaellt im Folgepatch 08l
       (2026-05-08): Auf Anwender-Wunsch hat die Tabelle auf Mobile keinen
       eigenen Y-Scrollbalken mehr — `max-height`, `overflow-y: auto` und
       `overscroll-behavior-y` wurden entfernt. Die Tabelle wird in voller
       Hoehe sichtbar und ueber den Page-Scrollbar erreicht.
       Politur 2026-05-11: Der frueher hier verankerte Mini-Sticky-Header
       (`.tabelle-scroller.is-mini`) ist durch den externen, fixed-positio-
       nierten Sticky-Mini-Header (.tabelle-sticky-mini) ersetzt — siehe
       eigener CSS-Block am Ende dieser Datei. */
    @media (max-width: 38em) {
        .tabelle-wrapper {
            /* Politur 2026-05-08h (B1): Anbieter-Spalten auf 30vw reduziert
               (vorher calc((100vw - 0.5em) / 3) ≈ 33.3vw). Bei 375 px
               Viewport ergibt 30vw = 112.5 px je Spalte; 3 Spalten = 337.5 px.
               Plus Site-Container-Offset (~21 px) plus rechte Schimmer-Gradient/
               Scrollbar (~12 px) bleiben rund 5 px Atemluft — drei Anbieter-
               Spalten passen jetzt vollstaendig in den Viewport, das vorherige
               Anschneiden der dritten Spalte am rechten Rand entfaellt.
               Politur 2026-05-11 (P1): von Viewport-vw auf Scroller-clientWidth
               umgestellt. 30vw rechnete gegen den Viewport, der Scroller-
               Container ist wegen Site-Section-Padding aber schmaler als
               100vw — auf einem Samsung S25 (~393 px Viewport, ~343 px
               Scroller-clientWidth) ueberhing die 3. Anbieter-Spalte um
               ~10-15 px nach rechts (Logos, Flaggen-Pille, "AG"-Suffix
               und Texte sichtbar abgeschnitten). `--scroller-w` wird per
               IIFE auf scroller.clientWidth gesetzt UND zusaetzlich am
               Wrapper gespiegelt (tabelleMiniLabelSetupIIFE/syncBreite),
               damit auch der .tabelle-sticky-mini-track als Wrapper-
               Descendant denselben Wert erbt.
               Politur 2026-05-11 (Sticky-Mini-Migration): Selektor vom
               .tabelle-scroller auf .tabelle-wrapper umgestellt (CSS-Custom-
               Properties vererben nur an Descendants, der Sticky-Mini-Track
               als Sibling des Scrollers brauchte den gemeinsamen Vorfahren). */
            --slot-breite: calc((var(--scroller-w, 100vw) - 1.5em) / 3);
            --vp-breite: 0px;
        }
        .tabelle-scroller {
            /* Politur 2026-05-08e (P1): --hdr-logo-h von 8rem auf 10rem
               erhoeht — bei der bisherigen 8rem-Reihe wurde das Logo
               (max-height 8em ≈ 5.76rem bei 0.72rem font-size) plus
               Anbietername (0.78rem * 1.2 line-height) plus Produktname
               (0.7rem * 1.15 line-height) am oberen Rand abgeschnitten,
               weil der Stack flex-flex-start arbeitet und keine Atemluft
               oben hatte. 10rem (~160 px) gibt dem Logo + 2 Textzeilen
               sauberen Platz, das Logo wird nicht mehr beschnitten.
               Politur 2026-05-11 (Folgepatch): von 10rem auf 11rem
               erhoeht. Logo-Wrap ist jetzt flex-shrink: 0 (siehe
               Z. ~1244), das Logo wird nicht mehr gestaucht — bei
               Mobile-30vw-Spalten gerendert mit ~100 px Hoehe. Stack:
               100 + 30 (Anbieter 2-Zeilen-Clamp) + 13 (Produkt
               1-Zeile-Clamp) + 16 (Padding/Gap) = 159 px, passt in
               11rem (176 px) ohne Ueberlauf in die Badge-Reihe. */
            --hdr-logo-h: 11rem;
            /* Politur 2026-05-13: Badge-Reihe (Inland/Auslandsanlage-Pille)
               auf Mobile entfaellt — die Information wandert kompakt in den
               .ab-meta-strip in der linken oberen Ecke der Logo-Zelle
               (Positionsnummer + Landesflagge). Track-Hoehe auf 0px setzt
               die Subgrid-Reihe inaktiv; .ab-zelle.ab-badge + .ab-badge-pill
               werden im Mobile-Block weiter unten zusaetzlich auf
               padding/min-height/display: none kollabiert. Sticky-Top der
               .ab-zelle.ab-zins (calc(--hdr-logo-h + --hdr-badge-h)) klebt
               damit direkt unterhalb der Logo-Reihe — auf Mobile ohnehin
               nur als Containing-Block-Anker relevant. */
            --hdr-badge-h: 0px;
            /* Folgepatch 14d: --row-data-h auf Mobile von 2.75rem auf 5rem
               erhoeht. Mehrzeilige Werte (Einlagensicherung, Hoechstanlage,
               PostIdent/VideoIdent, Zinsausschuettungs-Sonderfaelle) brauchen
               bei 122-px-Spaltenbreite und 12.8-px-Mini-Label-Reservierung
               (padding-top: 1.7em) mehr Platz, sonst ueberragen sie die
               44-px-Cell-Box visuell. 5rem = 80 px abzueglich padding ergibt
               etwa 54 px Inhaltsraum (~3-3.5 Textzeilen); `minmax(min, auto)`
               im Subgrid laesst die Reihe bei laengeren Inhalten weiter
               auto-wachsen. */
            --row-data-h: 5rem;
            /* Politur 2026-05-10e: Spacer-Reihen auf Mobile etwas hoeher als
               Desktop (Toggle-Overlay 30 px + Atemluft). Default 2.75rem
               (~44 px) wirkte noch knapp, 3rem (~48 px) gibt dem Banner sicht-
               bare Luft und bleibt deutlich kompakter als --row-data-h: 5rem
               (~80 px Daten-Reihen). VP-Spalte ist auf Mobile display:none —
               der VP-Gruppentitel-Button spielt keine Rolle. */
            --row-titel-h: 3rem;
            /* Politur 2026-05-13: CTA-Footer-Reihe auf Mobile von 5rem
               (--row-data-h) auf 4rem reduziert — 80% (Anwender-Wunsch).
               Inner-Link (font-size 0.7rem, padding 0.4375em) plus Zellen-
               padding 0.625em ergibt ca. 37-40 px Inhaltshoehe — passt
               bequem in 64 px (4rem). minmax laesst auch hier auto-Wachstum
               zu, wenn der CTA mehr Hoehe braucht. */
            --row-cta-h: 4rem;
            /* Politur 2026-05-11 (M2): Scroll-Snap auf Mobile abschalten. Der
               x-proximity-Snap des Default-Blocks cappte das echte
               scrollLeft-Maximum um ~14 px, sodass die letzte Anbieter-Spalte
               rechts angeschnitten blieb. Auf Touch ist Snap ohnehin eher
               hinderlich (schwungvolles Drag-Scrolling springt zurueck).
               scroll-padding-right schiebt zusaetzlich den Atemraum zum
               Schimmer-Gradient ein. */
            scroll-snap-type: none;
            scroll-padding-right: 0.5em;
        }
        /* Politur 2026-05-11 (P3): column-gap zwischen Anbieter-Spalten auf
           Mobile. Auf Smartphones (Samsung S25-Screenshots) stiessen die
           Spalten ohne sichtbaren Abstand aneinander, Texte (z.B.
           "Einlagensicherung AUSTRIA Ges.m.b.H.") wirkten ineinander
           uebergehend. Subgrid uebernimmt nur Tracks, nicht Gaps — die
           Reihen-Sync zwischen VP-Spalte und Anbieter-Spalten bleibt
           intakt. --slot-breite (P1) kompensiert die 2 × 0.5em-Gaps via
           1.5em-Reserve. */
        .tabelle-grid { column-gap: 0.5em; }
        /* Politur 2026-05-11 (P2): Schimmer-Gradient auf Mobile schmaler und
           halbtransparent. Default 2em × opacity 1 wirkte auf 30vw-Spalten
           als heller Streifen ueber fast einem Drittel der letzten Spalte —
           im Samsung-Screenshot als "Schattierung am rechten Rand der
           Bereiche-Banner" beanstandet. Auf Touch ist Drag-Scrolling auch
           ohne visuellen Scroll-Hinweis intuitiv, der Schimmer kann dezenter
           bleiben. ::before bleibt am Default-opacity-0 (linker Schimmer
           wird erst per .is-scroll-anfang aktiv), nur der dann sichtbare
           Wert wird angepasst. */
        .tabelle-wrapper::after,
        .tabelle-wrapper::before { width: 0.75em; }
        .tabelle-wrapper::after { opacity: 0.5; }
        .tabelle-wrapper.is-scroll-anfang::before { opacity: 0.5; }
        .vp-zelle, .ab-zelle { font-size: 0.72rem; padding: 0.375em 0.4375em; }
        .ab-zelle.ab-zins { font-size: 1.05rem; }
        /* Politur 2026-05-10f: 0.2em Abstand zwischen Zins-Header-Reihe und
           erstem Bereich (MERKMALE-Bezeichnung). Grid-Default `align-self:
           stretch` macht die Zinszelle 0.2em kuerzer als ihre fixe Track-Hoehe
           (--hdr-zins-h: 3rem), die Differenz wirkt als Luecke direkt unter
           dem Zinszahl-Block. Nur auf Mobile — auf Desktop kleben Header und
           Bereichstitel weiter direkt aneinander. */
        .ab-zelle.ab-zins,
        .vp-zelle.vp-header.vp-zins {
            margin-bottom: 0.2em;
        }
        /* Vergleichswert-Modus, Rechnung wie im Default-Block (Zellenschrift
           1.05rem = 16,8 px, Padding 4,2 px, Nominal absolut 13,2 px + 2,75 px).
           Die 0.2em margin-bottom der Zinszelle (Block darueber) geht vom Track
           ab, die Zelle selbst ist also T - 3,36 px hoch:
             Fluss-Inhalt = 16,8 + Gap 6,3 + Balken 4 = 27,1 px
             bei T = 72 px (Zelle 68,64) -> Balken-Unterkante 47,87 /
             Nominal-Oberkante 52,69, Abstand 4,8 px, kollisionsfrei. */
        .vp-spalte.is-vergleichswert,
        .tabelle-grid.is-vergleichswert { --hdr-zins-h: 4.5rem; }
        .ab-cta-link { font-size: 0.7rem; padding: 0.4375em 0.625em; }
        /* Politur 2026-05-08e (P1): Logo-Stack vertikal zentrieren, damit
           das Logo nicht oben am Rand klebt. justify-content: center auf
           der flex-direction:column-Zelle zentriert vertikal Logo + Anbieter-
           name + Produktname als Block in der 10rem-Reihe — das Logo bekommt
           damit oben automatisch Atemluft. */
        .ab-zelle.ab-logo {
            justify-content: center;
        }
        /* Sticky-Header-Reaktivierung: Background der Sticky-Zellen muss
           solid sein, sonst scheint die scrollende Datenreihe darunter durch.
           Site-Site-Variable `--bg-card` wird hier wegen Subgrid-Hintergrund-
           Vererbung explizit als solid `#0a3a5c`-Aequivalent ausgedrueckt. */
        .ab-zelle.ab-badge,
        .ab-zelle.ab-zins,
        .vp-zelle.vp-header.vp-badge,
        .vp-zelle.vp-header.vp-zins {
            background: rgb(9, 87, 143);
        }
        /* Phase 14 (A3): Mini-Label als Banner ueber jeder Wert-Reihe.
           padding-top reserviert Platz, der Inhalt darunter bleibt zentriert.
           Mini-Label ist position: absolute — keine zusaetzliche Grid-Reihe,
           daher bleiben _vpRowSync und Track-Hoehen unangetastet
           (Stolperstein 12 vermieden). gruppe-zu wirkt durch das Eltern-
           opacity automatisch auch auf das Label.
           Folgepatch 14a-5: font-size von 0.6rem auf 0.7rem (~11.2 px),
           padding-top der Eltern-Zelle von 1.55em auf 1.7em entsprechend
           nachgezogen. Sekundaerer Text traegt damit ueber dem WCAG-
           Mindestwert von 11 px.
           Politur 2026-05-14 (Pass 1): padding-top um 0.2em auf 1.9em
           erhoeht — der Anwender hat gemeldet, dass die Vergleichskriterien
           direkt am unteren Rand des Mini-Labels aufsitzen. Pass 2 (2026-
           05-14, nach Live-Verifikation): noch zu eng — Anwender hat weitere
           0.1em nachverlangt. Endwert 2em. Der :has()-Override fuer
           truncated Labels (siehe naechster Block) wandert mit auf 2.8em. */
        .ab-zelle.ab-merkmal {
            padding-top: 2em;
            /* Politur 2026-05-13: Trennlinie nach jedem Paar aus Mini-Label
               und Datenzeile (Anwender-Wunsch). Default
               `.vp-zelle, .ab-zelle { border-bottom: 1px solid rgba(255,255,255,0.06) }`
               (Z. ~1082) ist zu zart — auf 0.14 verstaerkt (gleiche Staerke
               wie die Trennlinie zur Vorgruppe am .ab-gruppe-spacer border-top).
               Subgrid-Reihen-Subgrid: die Border fluchtet horizontal ueber
               alle drei Anbieter-Spalten zu einer durchgehenden Linie. */
            border-bottom: 1px solid rgba(255, 255, 255, 0.14);
        }
        /* Politur 2026-05-11 (Mini-Label-Truncate, Visual-Pass): bei Reihen
           mit sichtbarem Volltext-Button (`.is-truncated`) waechst das
           Mini-Label-Banner von ~20 auf ~30 px durch den groesseren Button.
           padding-top adaptiv per :has() von 1.7em auf 2.5em hochziehen,
           damit der Banner-Bereich kollisionsfrei zum Wert-Bereich endet.
           Reihen ohne Truncate-Button (kurze Labels, Banner bleibt schmal)
           behalten die schmale Reservierung — verhindert ueberfluessigen
           Leerraum bei kurzen Bezeichnungen. :has() ist seit Chrome 105 /
           Safari 15.4 / Firefox 121 stabil verfuegbar.
           Politur 2026-05-14 (Pass 1+2): +0.3em parallel zur Basis-Regel
           (oben). Pass 1 bewegte den Trennraum von 2.5em auf 2.7em, Pass 2
           nach Live-Verifikation auf 2.8em. */
        .ab-zelle.ab-merkmal:has(.ab-info-icon-mini-label.is-truncated) {
            padding-top: 2.8em;
        }
        /* Politur 2026-05-13: border-bottom der letzten merkmal-Zelle einer
           Gruppe unterdruecken, weil der direkt nachfolgende .ab-gruppe-spacer
           selbst eine border-top: 1px solid rgba(255,255,255,0.14) traegt
           (Default-Regel Z. ~1462). Ohne dieses Override summieren sich
           beide Linien zu einer optischen 2 px-Doppellinie am Gruppen-
           Uebergang. `:has(+ .ab-gruppe-spacer)` greift nur dann, wenn der
           DIREKTE DOM-Sibling ein gruppe-spacer ist — also genau bei der
           letzten merkmal-Zelle vor jedem Bereichstitel-Wechsel.
           Browser-Support analog zur Truncate-:has()-Regel oben. */
        .ab-zelle.ab-merkmal:has(+ .ab-gruppe-spacer) {
            border-bottom: none;
        }
        /* Folgepatch 14b: Pro Wert-Reihe nur EIN Mini-Label, mittig ueber die
           drei sichtbaren Anbieter-Spalten. Verankert in der ersten Anbieter-
           Spalte (DOM-first-child), absolut positioniert mit Viewport-Breite,
           horizontal per JS sticky am linken Viewport-Rand (siehe IIFE
           tabelleMiniLabelSetup, Variable --mini-label-x). Andere Anbieter-
           Spalten rendern weiter ein <span class="ab-mini-label"> im HTML
           (Render-Symmetrie, kein PHP-Index-Param noetig), das aber per
           Default-Mobile-Display:none unsichtbar bleibt. */
        .ab-mini-label { display: none; }
        .tabelle-grid > .anbieter-spalte:first-child .ab-mini-label {
            /* Politur 2026-05-11 (Mini-Label-Truncate): display: flex statt
               block. Damit Text-Span und Volltext-i-Button als Flex-Children
               nebeneinander zentriert sitzen koennen. Ellipsis-Eigenschaften
               (white-space/overflow/text-overflow) wandern auf .ab-mini-
               label-text — der Container kuemmert sich nur um Breite,
               Position und Sticky-Sync. */
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 0.25em;
            position: absolute;
            /* Politur 2026-05-13: 0.2em Abstand zur Top-Kante der Datenzelle
               (Anwender-Wunsch) — Label klebt nicht mehr direkt an der
               Trennlinie der Vorgaenger-Zeile. em bezieht sich auf die
               eigene Schriftgroesse 0.8rem ≈ 12.8 px, ergibt ca. 2.6 px
               Abstand. */
            top: 0.2em;
            left: 0;
            /* Politur 2026-05-10e: Breite an die tatsaechlich sichtbare
               Tabellen-Breite gebunden (`--mini-label-w`, gesetzt von der
               IIFE `tabelleMiniLabelSetupIIFE` als `min(scroller.clientWidth,
               grid.offsetWidth)`). Der Scroller ist wegen Section-Padding
               schmaler als 100vw — vorher ragte das Mini-Label rechts ueber
               die letzte Anbieter-Spalte hinaus. Fallback auf den alten
               100vw-Wert, falls die IIFE nicht laeuft. */
            width: var(--mini-label-w, calc(100vw - 0.5em));
            box-sizing: border-box;
            padding: 0.15em 0.5em;
            font-size: 0.8rem;
            line-height: 1.25;
            /* Politur 2026-05-11 (Label-Hierarchie): Label-Schrift von
               0.78 → 0.55 Deckkraft gedimmt. Damit die Werte in den
               Daten-Zellen die dominantere Schriftfarbe sind und die
               Mini-Labels als sekundaere Tonstufe zuruecktreten
               (Anwender-Wunsch 2026-05-11). Gleiche Farb-Familie wie die
               Werte (reines Weiss), nur Helligkeit reduziert — keine
               eigene Toenung. */
            color: rgba(255, 255, 255, 0.55);
            /* Politur 2026-05-13: Hintergrund von var(--bg-card) auf transparent
               umgestellt (Anwender-Wunsch) — Mini-Label teilt jetzt den Page-
               Hintergrund mit der Datenzelle darunter, beide wirken als eine
               durchgehende Flaeche. Vorher (08e/P2) war hier var(--bg-card) als
               einheitliche Header-System-Optik gemeinsam mit .ab-gruppe-spacer
               und .ab-cta gesetzt. Trennung zur naechsten Reihe sitzt jetzt
               an .ab-zelle.ab-merkmal border-bottom (1 px, 0.14 Opacity). */
            background: transparent;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            text-align: center;
            /* Politur 2026-05-11 (Mini-Label-Truncate): white-space, overflow
               und text-overflow wandern auf das innere .ab-mini-label-text.
               Der Container ist jetzt Flex — Ellipsis greift am Inner-Span,
               der per `min-width: 0` schrumpfen darf.
               Politur 2026-05-13: border-bottom entfernt — die Linie zwischen
               Label und Wert ist nicht mehr gewuenscht (Anwender-Wunsch:
               Label und Wert als zusammengehoeriges Paar). Trennung zur
               naechsten Reihe sitzt jetzt an .ab-zelle.ab-merkmal border-
               bottom. */
            border-bottom: none;
            /* Politur 2026-05-11 (Mini-Label-Truncate): `pointer-events: none`
               entfernt. Mini-Label traegt selbst keinen Click-Handler — die
               Eigenschaft war eine Vorbeugung ohne sichtbares Verhalten,
               blockierte aber Click-Events des Inline-i-Buttons in manchen
               Browser-/Touch-Konstellationen (Anwender-Meldung: Hand-Cursor
               sichtbar, Klick reagierte nicht). Ohne diese Eigenschaft
               faengt der Button seine eigenen Klicks regulaer ueber die
               Event-Delegation in `infoTooltipSetup()`. */
            /* Politur 2026-05-11 (A): translateX → translate3d zwingt den
               Browser, das Element auf eine eigene GPU-Compositor-Layer zu
               promoten. Touch-Scrolling laeuft auf dem Compositor-Thread; ohne
               eigenen Layer wird der translateX-Update vom Main-Thread
               (CSS-Custom-Property setzen → Style-Recalc → Paint) 1-2 Frames
               verzoegert sichtbar — der User berichtete ein "Springen" der
               Legende beim horizontalen Daumen-Scroll. backface-visibility
               ist ein zusaetzlicher Compositor-Hint, der das Layer-Promote
               noch deterministischer macht. */
            transform: translate3d(var(--mini-label-x, 0px), 0, 0);
            backface-visibility: hidden;
            will-change: transform;
            /* Politur 2026-05-11 (Mini-Label-Truncate, Hit-Test-Fix):
               z-index: 2 ueber den nachfolgenden Anbieter-Spalten-Geschwistern
               (die per DOM-Order ohne explizites z-index stapeln). Hintergrund:
               das Mini-Label-Banner sitzt absolute in der first-child-Anbieter-
               Spalte und wird per `transform: translate3d(--mini-label-x)`
               visuell ueber alle drei Spalten gezogen. Ohne z-index lag das
               Banner im Stacking-Kontext der first-child-Spalte und wurde von
               second/third-child `.ab-zelle.ab-merkmal` (jeweils
               position: relative, z-auto) im Hit-Test ueberlagert — Klicks
               auf den Inline-i-Button landeten in der jeweils darunter-
               liegenden Wert-Zelle statt am Button. Unter dem Sticky-Header
               (z-index: 3) und ueber den Geschwistern (z-auto) ist `2` die
               richtige Stufe. Analog am `.mb-gruppentitel`-Bereichstitel-
               Toggle (gleiche transformierte Banner-Mechanik). */
            z-index: 2;
        }
        /* Politur 2026-05-11 (Mini-Label-Truncate): Inner-Span traegt die
           Ellipsis-Eigenschaften, die zuvor am Container lagen. min-width: 0
           ist Pflicht, damit der Flex-Child wirklich schrumpfen kann
           (Default min-width: auto an Flex-Items = min-content) — sonst
           greift text-overflow: ellipsis nicht. flex: 0 1 auto erlaubt das
           Schrumpfen, behaelt aber die Content-Breite als Bevorzugung,
           damit kurze Labels nicht den Platz fuellen. */
        .ab-mini-label-text {
            min-width: 0;
            flex: 0 1 auto;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        /* Folgepatch 14c: VP-Spalte auf Mobile komplett unsichtbar.
           Reihen-Labels uebernehmen die Mini-Labels in der ersten Anbieter-
           Spalte (siehe oben), Bereichsbezeichnungen mit Toggle rendern
           als zweite Form/Button-Pair in der .ab-gruppe-spacer (siehe
           weiter unten). VP-Drawer-Mechanik ist komplett rueckgebaut. */
        .vp-spalte { display: none; }

        /* Phase 14 (A6): CTA Icon-only auf Mobile.
           SVG sichtbar, Text ausgeblendet, 48-px-Tap-Target via min-w/h.
           Spezifizitaet `.vergleich-dashboard .anbieter-link` schlaegt
           das Listen-globale Styling aus vergleich.min.css. */
        /* Politur 2026-05-10d: Rechteckiger Button mit zwei Fontello-Icons
           (Bank + Externer-Link-Pfeil) — exakt wie die alte Tabellenansicht.
           Override gegen `.icon`-Defaults aus style.css (font-size: 3em;
           position: absolute; margin-left: -1.6em) und `.icon-bank`-Mobile-
           Override (position: absolute) per hoeherer Spezifizitaet
           (`.vergleich-dashboard .anbieter-link i.icon-bank` = 3 Klassen + 1 Tag). */
        .vergleich-dashboard .anbieter-link {
            display: flex;
            align-items: center;
            justify-content: center;
            min-width: 4rem;
            min-height: 2rem;
            padding: 0.25rem 0.5rem;
            gap: 0.25rem;
        }
        .vergleich-dashboard .anbieter-link i.icon-bank,
        .vergleich-dashboard .anbieter-link i.icon-link-ext {
            display: inline-block;
            position: relative;
            top: 0;
            font-size: 1.25rem;
            margin: 0;
            line-height: 1;
            color: inherit;
            width: auto;
            height: auto;
        }
        .vergleich-dashboard .anbieter-link-text {
            display: none;
        }
        /* Phase 14 (A7): Mobile-Switch fuer Truncate. Volltext aus, Kurzform
           plus Info-Icon ein. Info-Icon mit ausreichend grosser Hitbox. */
        .ab-merkmal-voll { display: none; }
        .ab-merkmal-kurz { display: inline; }
        .ab-info-icon {
            position: relative;
            /* Politur 2026-05-11 (M1b): eigener Stacking-Kontext, damit der
               unsichtbare `::before`-Slop im Hit-Test ueber dem textfuehrenden
               Eltern-DIV `.ab-zelle.ab-merkmal` liegt. Ohne diesen Kontext
               lieferte `elementFromPoint(iconCx, iconY ± 5)` die Elternzelle
               statt des Icons — die vertikale Slop-Region war faktisch
               wirkungslos (VRT-Befund 2026-05-11 C2). */
            isolation: isolate;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 1.4em;
            height: 1.4em;
            margin-left: 0.35em;
            padding: 0;
            /* Politur 2026-05-11 (i-Buttons transparent): Anwender-Wunsch —
               i-Buttons generell ohne eigenen Hintergrund. Glyph + Hand-
               Cursor tragen das visuelle Feedback. */
            background: transparent;
            color: rgba(255, 255, 255, 0.85);
            border: none;
            border-radius: 50%;
            /* Politur 2026-05-11 (M1b): Icon visuell verdoppelt — 0.85em → 1.7em
               Schrift, width/height von 1.4em skaliert mit auf ~27 px Visual
               (vorher ~14 px). Anwender meldete, dass das Icon zu klein zum
               Erkennen sei. Doppelte Schrift macht das ⓘ-Glyph deutlich
               sichtbar; bei `--row-data-h: 5rem` (80 px) und 30vw-Spalten
               (~112 px) bleibt im Layout genug Platz fuer Text + Icon. */
            font-size: 1.7em;
            line-height: 1;
            cursor: pointer;
            vertical-align: baseline;
        }
        /* Folgepatch 14a-1: Pseudoelement-Slop fuer 44-px-Tap-Target.
           Politur 2026-05-11 (M1b): Slop in max(em, rem)-Mix umgestellt, damit
           er bei Icon-font-size-Aenderungen nicht ueberproportional waechst —
           der absolute rem-Boden deckelt die em-Berechnung. Hitbox bleibt
           damit unabhaengig vom Icon-Visual-Faktor in einem stabilen Korridor
           (Visual + 2 × Slop): bei 1.7em-Icon ≈ 27 + 28 = 55 px vertikal,
           27 + 25 = 52 px horizontal — sicher ueber dem 44-px-AAA-Wert.
           Plus z-index: 1 im neuen Stacking-Kontext des Icons (siehe
           `isolation: isolate` oben) — Slop liegt im Hit-Test ueber der
           Eltern-Zelle, der vertikale Tap-Lift wirkt jetzt auch praktisch. */
        .ab-info-icon::before {
            content: '';
            position: absolute;
            top: max(-1.4em, -0.875rem);
            bottom: max(-1.4em, -0.875rem);
            left: max(-1.25em, -0.78125rem);
            right: max(-1.25em, -0.78125rem);
            z-index: 1;
        }
        .ab-info-icon:hover,
        .ab-info-icon:focus-visible {
            color: #fff;
        }
        .ab-info-icon:focus-visible {
            outline: 2px solid var(--accent, #A9F6DB);
            outline-offset: 2px;
        }
        /* Politur 2026-05-11 (Mini-Label-Truncate): Volltext-Button im Mini-
           Label. Spezifizitaet `.ab-info-icon.ab-info-icon-mini-label` (0,2,0)
           schlaegt die generische `.ab-info-icon`-Regel (0,1,0) im Mobile-
           Block. Default unsichtbar — JS-IIFE `tabelleMiniLabelTruncateSetup`
           setzt `.is-truncated`, sobald die Text-Span-Ellipsis gegriffen hat
           (`text.scrollWidth > text.clientWidth`). font-size kleiner als der
           generische 1.7em-Icon, weil das Mini-Label nur 0.8rem traegt —
           ein 1.7em-Button waere zu hoch fuer das schmale Banner. Hitbox-
           Slop entsprechend reduziert. background: transparent — Anwender-
           Wunsch 2026-05-11 (i-Buttons generell ohne eigenen Hintergrund);
           der ⓘ-Glyph plus Hand-Cursor traegt das visuelle Feedback. */
        .ab-info-icon.ab-info-icon-mini-label {
            display: none;
            /* Politur 2026-05-11 (Mini-Label-Truncate, Visual-Pass):
               font-size: 2em statt 1em — Anwender-Wunsch: i-Button im
               Mini-Label-Banner doppelt so gross, damit er in etwa die
               Groesse der Merkmal-Truncate-Buttons (`.ab-info-icon` Mobile,
               font-size: 1.7em an 0.85rem-Schrift) erreicht. width/height
               von 1.2em auf 1em reduziert — kompakterer Quad (25.6 × 25.6 px
               statt 30.7 × 30.7 px), Glyph fuellt die Box. Damit die Banner-
               Hoehe nur moderat (~30 px statt ~35 px) waechst und nicht zu
               sehr in den Werte-Bereich der Zelle ragt. */
            font-size: 2em;
            width: 1em;
            height: 1em;
            margin-left: 0;
            background: transparent;
            /* Politur 2026-05-11 (Mini-Label-Truncate, Visual-Pass): Idle-Color
               an die Mini-Label-Schriftfarbe `rgba(255,255,255,0.55)` (Z. 1949)
               angeglichen — Anwender-Wunsch: der Button soll farblich nicht
               heller als der Label-Text wirken. Hover/Focus boostet weiter
               auf #fff als Feedback. */
            color: rgba(255, 255, 255, 0.55);
        }
        .ab-info-icon.ab-info-icon-mini-label.is-truncated {
            display: inline-flex;
        }
        .ab-info-icon.ab-info-icon-mini-label::before {
            /* Slop kleiner als generisches Icon — ~28 px Hitbox bei
               ~12 px Visual. Wert in max(em, rem) analog zu generischem
               Icon, aber etwa halbiert. Slop reicht weiter als die
               Banner-Hoehe, was OK ist: nur der Klick zaehlt, nicht das
               visuelle Pseudoelement. */
            top: max(-0.8em, -0.5rem);
            bottom: max(-0.8em, -0.5rem);
            left: max(-0.6em, -0.4rem);
            right: max(-0.6em, -0.4rem);
        }
        .ab-info-icon.ab-info-icon-mini-label:hover,
        .ab-info-icon.ab-info-icon-mini-label:focus-visible {
            color: #fff;
        }
        /* Politur 2026-05-13: Anlageland-Pille und runder Pos-Badge auf Mobile
           durch den kompakten Meta-Strip in der linken oberen Logo-Ecke ersetzt.
           Die Subgrid-Badge-Reihe (--hdr-badge-h: 0px, weiter oben) ist track-
           hoehenfrei; die Zelle selbst kollabiert hier zusaetzlich (padding 0,
           min-height 0, overflow hidden). Inhalt der Pille per display: none
           inaktiv — die Inland/Ausland-Information wandert in den Strip.
           .ab-pos-badge (Desktop-Kreis am Logo) wird auf Mobile ebenfalls
           unsichtbar geschaltet, weil die Positionsnummer ueber den Strip
           gezeigt wird. */
        .ab-zelle.ab-badge {
            padding: 0;
            min-height: 0;
            overflow: hidden;
        }
        .ab-badge-pill { display: none; }
        .ab-pos-badge { display: none; }

        /* Politur 2026-05-13: kompakter Meta-Strip — Positionsnummer (#NN) plus
           Landesflagge in der oberen linken Ecke der Logo-Zelle. `.ab-zelle.ab-
           logo` ist `position: sticky` (Z. ~1131) und dient damit als
           Containing-Block fuer das `position: absolute`-Element. `pointer-
           events: none` verhindert, dass der Strip Klicks auf das darunter-
           liegende `.ab-logo-link` blockiert. */
        .ab-meta-strip {
            display: flex;
            align-items: center;
            gap: 0.35em;
            position: absolute;
            top: 0.4em;
            left: 0.4em;
            z-index: 2;
            pointer-events: none;
            line-height: 1;
        }
        .ab-meta-pos {
            font-size: 0.7rem;
            font-weight: 600;
            color: rgba(255, 255, 255, 0.92); /* Kontrast-Politur 2026-06-12 (Schwester-Rollout): 0.6 -> 0.92 */
            letter-spacing: 0.02em;
            line-height: 1;
            font-variant-numeric: tabular-nums;
            /* Platz fuer "#NN" reservieren — bleibt auch bei Sport-Ranking-Tie
               (gleicher Zins wie Vorgaenger, $rang leer) erhalten, damit die
               Flagge in allen Spalten an derselben x-Position startet. Wert
               so gewaehlt, dass zweistellige Nummern sicher passen
               (`#99` ≈ 1.55em); dreistellige (>= 100, theoretisch) wachsen
               den Slot intrinsisch ueber das min-width hinaus. */
            min-width: 1.7em;
            display: inline-block;
        }
        /* Flagge im klassischen Flaggen-Seitenverhaeltnis (ca. 20:14 nativ).
           Keine Abrundung — Anwender-Wunsch 2026-05-13: Flagge soll nicht
           zusaetzlich rund maskiert werden. Das Image bekommt fixe Hoehe
           und proportional auto-Breite, sodass das natuerliche Seitenverhaeltnis
           erhalten bleibt. Die Emoji-Variante wird per Site-globalem JS je nach
           Browser-Support gegen das `<img>` getauscht (Default: Emoji sichtbar,
           Image `display: none`; bei .no-emoji-flags umgekehrt).
           Folgepatch 2026-05-13: `display`-Override am Image entfernt — die
           Site-globale Verstecken-Logik (Z. 689-692) wurde sonst aufgehoben
           und beide Varianten erschienen parallel. Groesse beider Varianten
           auf Mittelwert harmonisiert (zwischen vorherigem Emoji 0.95rem
           und Image 0.9rem). */
        .ab-meta-flag {
            display: inline-flex;
            align-items: center;
            line-height: 1;
        }
        .ab-meta-flag .flag-img-variant {
            width: auto;
            height: 0.85rem;
        }
        .ab-meta-flag .flag-emoji-variant {
            font-size: 1.05rem;
            line-height: 1;
        }
        /* Folgepatch 14c: Bereichsbezeichnung mit Toggle in der ersten
           Anbieter-Spalte. Der Button wird in der .ab-gruppe-spacer-Reihe
           absolut positioniert (volle Viewport-Breite), nutzt dieselbe
           --mini-label-x-Variable wie das Mini-Label fuer den Sticky-Sync
           am linken Viewport-Rand. min-height an allen .ab-gruppe-spacer,
           damit die Subgrid-Reihe Platz fuer den Button reserviert (Subgrid
           uebernimmt die maximale Reihen-Hoehe ueber alle Anbieter-Spalten,
           also wirkt das min-height ueber alle drei sichtbaren Spalten). */
        .tabelle-grid .ab-gruppe-spacer {
            min-height: 2.5em;
        }
        .tabelle-grid > .anbieter-spalte:first-child .ab-gruppe-spacer {
            position: relative;
        }
        .tabelle-grid > .anbieter-spalte:first-child .mb-gruppentitel {
            display: flex;
            position: absolute;
            top: 0;
            left: 0;
            /* Politur 2026-05-10e: Breite an die tatsaechlich sichtbare
               Tabellen-Breite gebunden (siehe Kommentar an .ab-mini-label
               weiter oben). */
            width: var(--mini-label-w, calc(100vw - 0.5em));
            box-sizing: border-box;
            /* Politur 2026-05-11 (A): translate3d + backface-visibility analog
               zum .ab-mini-label-Block (siehe oben). Erzwingt eigene
               GPU-Compositor-Layer, sodass der Bereichsbezeichnungs-Toggle
               nicht hinter dem Touch-Scroll herhinkt. */
            transform: translate3d(var(--mini-label-x, 0px), 0, 0);
            backface-visibility: hidden;
            will-change: transform;
            /* Politur 2026-05-11 (Mini-Label-Truncate, Hit-Test-Fix):
               analog zum .ab-mini-label-Block — z-index 2 ueber den
               nachfolgenden Spalten-Geschwistern, damit der Bereichstitel-
               Toggle-Button im transformierten Banner-Bereich klickbar
               bleibt (Vorbeugung gegen den Stacking-Konflikt, den Anwender
               am Mini-Label-Volltext-Button gemeldet hat). */
            z-index: 2;
            /* z-index/translate3d sind die Sticky-Sync-Mechanik (Banner folgt
               dem Horizontal-Scroll). Padding und Chevron-Position liegen in
               der .mb-gruppentitel-Regel unten (space-between, padding-right
               5% — Chevron am rechten Banner-Rand). */
        }
        /* Politur 2026-05-13 / Redesign 2026-06-19: Bereichstitel-Optik auf
           Mobile — Hintergrund auf transparent (selbe Farbe wie die
           Vergleichskriterien-Zellen, die ebenfalls keinen expliziten
           Background haben und auf den dunklen Page-Hintergrund durch-
           scheinen; der Default-Block liefert die Koernungs-Flaeche darunter).
           Label (links) und einzelner SVG-Chevron (rechts) sitzen per
           space-between an den Banner-Raendern — der fruehere gepunktete
           Fueller und das +/−- bzw. ▼-Glyph sind entfernt. Trennlinie zur
           vorigen Gruppe liefert jetzt die .ab-gruppe-spacer-Koernung
           (border-top); die Button-eigene Border bleibt hier ausgeschaltet,
           damit auf Mobile nur eine durchgehende Bandflaeche liest. */
        .tabelle-grid > .anbieter-spalte:first-child .mb-gruppentitel {
            background: transparent;
            border-top: none;
            border-bottom: none;
            /* Politur 2026-05-14 (Pass 1): Inneres Padding auf 2.5% links und
               rechts gesetzt — konsistent zur 2.5%-Site-Konvention der
               Header-Zeile (`.result-count { padding-left: 2.5% }`,
               `.sort-buttons { margin-right: 2.5% }`, Z. ~750/755). Vorher:
               0.625em vom Default-Block `button.vp-gruppentitel { padding:
               1.125em 0.625em 1em }`. Pass 2 (2026-05-14, nach Live-
               Verifikation durch den Anwender): rechter Abstand reichte
               visuell noch nicht. Anwender hat `padding-right: 5%`
               nachverlangt; `padding-left: 2.5%` bleibt (die Beschriftung
               sass schon richtig). Der per space-between rechtsbuendige
               Chevron (Default-Caret-Regel) bekommt damit etwas mehr Abstand
               zum Banner-Rand. Prozentwerte beziehen sich auf die
               Banner-Breite, die ueber `--mini-label-w` an `min(scroller.
               clientWidth, grid.offsetWidth)` gebunden ist. */
            padding-left: 2.5%;
            padding-right: 5%;
        }
        /* Hover (2026-06-19b): Koernung bleibt unveraendert; der Chevron hellt
           auf (wie Desktop). Touch-Geraete zeigen kaum Hover. */
        .tabelle-grid > .anbieter-spalte:first-child .mb-gruppentitel:hover .vp-gruppentitel-caret {
            color: #BFDBEF;
        }
        /* Redesign 2026-06-19: Der fruehere Mobile-Transparent-Reset der
           .ab-gruppe-spacer ist entfallen — auf Mobile gilt jetzt dieselbe
           Koernungs-Flaeche wie auf Desktop (Default-Block oben), sodass das
           Band auch auf kleinen Displays als eigene Struktur liest. */
        /* Mobile-Chevron etwas groesser fuer bessere Tap-Sichtbarkeit auf
           kleinen Displays (Desktop nutzt die 15px aus dem SVG-Attribut). */
        .tabelle-grid > .anbieter-spalte:first-child .mb-gruppentitel .vp-gruppentitel-caret svg {
            width: 18px;
            height: 18px;
        }
    }
    /* Subgrid-Fallback (sehr alte Browser) */

    /* === Phase 3: Klappbare Vergleichspunkt-Gruppen === */
    /* Form ist transparent — Button wird direktes Grid-Item der vp-Spalte */

    /* Hover (Anwender-Wunsch 2026-06-19b/c): Die Koernungs-Flaeche bleibt
       UNVERAENDERT — kein Aufhellen, kein Schleier, keine Struktur-Aenderung.
       Den Hover-Zustand signalisiert allein der Chevron durch eine hellere
       Farbe (#6699CC -> #BFDBEF, weich ueber die color-Transition am Caret).
       Greift beim direkten VP-Button-Hover (:hover) UND wenn die ganze
       Bereichs-Zeile gehovert wird (.is-row-hover, von JS gesetzt — die
       Spacer-Zellen liegen in einem anderen DOM-Teilbaum als der Chevron). */
    /* Label: nimmt nur seine intrinsische Breite (flex: 0 1 auto); space-between
       am Button schiebt den Chevron an den rechten Rand.
       `min-width: 0` + `overflow-wrap: break-word` als Sicherheitsnetz: Edge/
       Chromium brechen Labels ohne interne Bruchstelle (z.B. "KONTOEROEFFNUNG")
       sonst nicht um — der Flex-Item-min-width-Default `auto` (= min-content)
       sperrt den Shrink unter die Wort-Breite, das Label wuerde den Chevron aus
       der Spalte druecken. Firefox bricht "AUSSCHUETTUNG/AUSZAHLUNG" bereits
       ueber `<wbr>` (Politur 19e); break-word greift dort nur als Last-Resort. */
    /* Chevron-Toggle (Redesign 2026-06-19, Handoff Variante 02): ein einzelner
       SVG-Chevron statt +/--Glyph und gepunktetem Leader (beide entfernt). Zeigt
       nach UNTEN wenn zugeklappt, rotiert um 180 Grad (zeigt nach OBEN) wenn
       offen. Gedaempftes Blau #6699CC statt Akzentgruen — bewusst zurueckhaltend
       ("weniger ins Auge fallen"). currentColor faerbt den SVG-Stroke. */
    /* prefers-reduced-motion: Rotation ohne Tween (Zustands-Sprung statt
       Animation). race.js injiziert dieselbe Regel zusaetzlich — hier nochmal
       lokal, falls race.js nicht laedt. */

    /* Folgepatch 14c: Default Desktop — der Mobile-Toggle-Button (zweite
       Form/Button-Pair pro Gruppe in der ersten Anbieter-Spalte) ist
       unsichtbar. Mobile-Block schaltet ihn sichtbar. */

    /* Soft-Fade: Daten-Reihen einer Gruppe.
       Spacer (.ab-gruppe-spacer) ausnehmen — bleibt sichtbar als Teil des Headers. */
    /* Nach Fade-Out komplett aus dem Grid raus — JS setzt diese Klasse nach transitionend. */
    /* No-JS-Fallback: ohne JS direkt verstecken (kein Soft-Fade) */

    /* Hoehen-Animation beim Auf-/Zuklappen (2026-06-19c): Akkordeon-Geste, damit
       erlebbar wird, WELCHER Bereich sich oeffnet/schliesst. Die Trigger-Klasse
       .gruppe-anim setzt toggleGruppe NUR fuer die Dauer des px-Tweens an
       .tabelle-grid UND .vp-spalte (beide tweenen synchron per CSS). Permanent
       darf die Transition nicht stehen, weil die Default-Track-Liste
       var(--tabelle-data-rows) `auto` enthaelt und `auto` nicht interpolierbar ist
       (sie wuerde springen). Laeuft parallel zum opacity-Soft-Fade (180 ms). */
    /* Hoehere Spezifitaet (0,3,0) als race.js' `.tabelle-scroller .tabelle-grid`
       (0,2,0): race injiziert sein `transition: opacity 180ms` per appendChild
       NACH diesem Stylesheet in den <head> und gewaenne sonst den
       Spezifitaets-Gleichstand — da `transition` ein Shorthand ist, wuerde es
       die grid-template-rows-Transition KOMPLETT ersetzen (Hoehe spraenge statt
       zu tweenen, transitionend feuerte nie). opacity 180ms (= race FADE_MS)
       wird mitgefuehrt, damit ein Cross-Fade-Overlap die Opazitaets-Transition
       nicht verliert. */
    /* Band-Puls beim Klick (2026-06-19c): kurzer heller Inset-Schein auf dem
       geklickten Band (VP-Button + Spacer-Fortsetzung derselben Gruppe), damit
       sofort sichtbar ist, WELCHES Band reagiert hat. Bewusst als box-shadow
       UEBER der Koernungs-Textur statt background-Wechsel (der wuerde mit den
       radial-gradients konkurrieren). Die erste box-shadow-Komponente repliziert
       den bestehenden Inset-Sheen, damit er waehrend der Animation nicht
       wegblitzt. Feste rgba (Akzent #5fd4b8 @ 0.10) statt var() — der Live-Wert
       von --accent-light (#00ffcc) waere greller als gewuenscht. JS setzt
       .band-puls in toggleGruppe und entfernt sie per animationend/Timeout. */
    /* prefers-reduced-motion: Hoehen-Tween + Band-Puls aus (Zustands-Sprung statt
       Animation). toggleGruppe ueberspringt zusaetzlich den px-Tween im JS. */

    /* === Phase 4: Drag-to-Scroll, Snap, Mini-Scrollbar === */
    /* Drag-Cursor nur fuer Maus-Nutzer (Touch behaelt natives Momentum) */
    /* Mini-Scrollbar-Indikator (Frage 20 = C) */
    .tabelle-scrollbar-indikator {
        position: relative;
        height: 0.25em;
        margin: 0.5em 0.25em 0;
        background: rgba(255,255,255,0.08);
        border-radius: 999px;
        overflow: hidden;
        transition: opacity 150ms ease;
    }
    .tabelle-scrollbar-thumb {
        position: absolute;
        top: 0;
        left: var(--thumb-x, 0%);
        height: 100%;
        width: var(--thumb-width, 100%);
        background: rgba(255,255,255,0.6); /* Kontrast-Politur 2026-06-12 (Schwester-Rollout): 0.4 -> 0.6 */
        border-radius: inherit;
    }
    @media (hover: hover) and (pointer: fine) {
        .tabelle-scrollbar-thumb { transition: background 125ms ease; }
        .tabelle-scroller:hover ~ .tabelle-scrollbar-indikator .tabelle-scrollbar-thumb,
        .tabelle-scroller.is-dragging ~ .tabelle-scrollbar-indikator .tabelle-scrollbar-thumb {
            background: rgba(255,255,255,0.75); /* Kontrast-Politur 2026-06-12 (Schwester-Rollout): Hover mit angehoben */
        }
    }
    /* ============================================================
       Sticky-Mini-Header — extern, fixed-positioniert.
       Faedet beim Page-Scroll oben ein, sobald die echten Header-
       Reihen (Logo + Badge + Zins) oben aus dem Viewport scrollen,
       und faedet wieder aus, wenn der .tabelle-wrapper-Bottom unter
       den Viewport-Top kommt. JS-IIFE tabelleStickyMiniSetup setzt
       .is-active auf Basis getBoundingClientRect-Pruefungen.
       ScrollLeft-Sync: --mini-label-x wird vom Mini-Label-IIFE im
       .tabelle-scroller gesetzt und am .tabelle-wrapper gespiegelt,
       der Mini-Track erbt sie und uebernimmt sie als translate3d.
       Stolperstein 10 (Bounding-Box-Aufblaeh) ist hier irrelevant,
       weil der Mini-Header AUSSERHALB des .tabelle-scroller lebt und
       dessen scrollWidth nicht beeinflusst.
       ============================================================ */
    /* Politur 2026-05-12: Sticky-Mini-Header zeigt nur noch das Anbieterlogo —
       Zinssatz raus (Spalten-Identifikation reicht). Logo wird gedanklich
       rechtsbuendig in der Spalte ausgerichtet (align-items: flex-end an der
       Spalte + justify-content: flex-end im Logo-Wrap) — spiegelt die Position
       des Originallogos in .ab-zelle.ab-logo (flex-direction: column;
       align-items: flex-end). Logo-Hoehe (max-height: 6em) = 75 % der normalen
       Header-Logos (.ab-logo-wrap max-height 8em, Z. ~1197) — der Anwender
       wollte die Sticky-Logos kompakter, damit der Mini-Header beim Page-
       Scroll weniger Viewport blockiert. */
    .ab-mini-logo {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        max-height: 6em;
        max-width: 100%;
    }
    @media (max-width: 38em) {
        /* Mobile: VP-Spalte ist display:none — kein Container-Offset noetig
           (JS liefert vpBreitePx = 0). Mini-Spalten in der Breite des
           3-Anbieter-Mobile-Grids; column-gap muss zum Original-Grid passen
           (Z. ~1770) — sonst driften Mini-Spalten gegen Original-Spalten
           beim Horizontal-Scroll (~5.75 px/Spalte Versatz, vom visuellen
           Regressionstest 2026-05-11 detektiert).
           Politur 2026-05-12: font-size der Mini-Spalte auf 0.72rem (analog
           Mobile-`.ab-zelle`, Z. ~1785). Damit ergibt `max-height: 6em` am
           .ab-mini-logo die gleiche relativen Skalierung wie auf Desktop —
           ~69 px Logo-Hoehe (6 * 0.72rem). */
        .tabelle-sticky-mini-track {
            column-gap: 0.5em;
        }
        .anbieter-spalte-mini {
            font-size: 0.72rem;
            padding: 0.375em 0.4375em;
        }
    }

    /* ────────────────────────────────────────────────────────────
       Bar-Indikator-Toggle "Auslandsanlagen berücksichtigen?"
       (ersetzt die fruehere Slider-Switch-Mechanik). Markup-Spiegel
       der Tagesgeld-Tabelle (dort gibt es zusaetzlich einen
       Sonderzins-Toggle; Festgeld nutzt nur die Dash-Variante).
       Masse px->em (1em=16px); nur font-size, border-radius-Hairline
       und SVG-Dimensionen bleiben px. Fuellung/Hoehe laufen rein ueber
       data-state am Button -> CSS, der Klick schaltet optimistisch um.
       ──────────────────────────────────────────────────────────── */

    /* Auslandsanlagen — Dash-Indikator: Fuellstand (8/13 -> 13/13) */

    /* Tooltip-Hinweis auf die Umschalt-Moeglichkeit — Stil wie der
       Zinsbalken-Tooltip (dunkle Glas-Sprechblase, Fade-in), rechtsbuendig
       (rechte Kante am Pfeil). */

    /* Touch-Geraete (kein Hover): Umschalt-Hinweis nicht einblenden, damit die
       Sprechblase nach dem Antippen nicht stehen bleibt. Maus-Hover und Tastatur-
       Fokus (:focus-visible) zeigen den Hinweis weiterhin. */
    @media (hover: none) {
        .vergleich-dashboard .balken-toggle[data-tooltip]:hover::after { opacity: 0; }
    }

    /* Mobile (gestapelt): groesserer Abstand ueber dem Toggle-Band, optisch wie
       der Abstand zwischen Laufzeit- und Anlagebetrag-Band (ca. --space-lg). */
    @media (max-width: 48em) {
        .vergleich-dashboard .filter-section .ausland-filter-group { margin-top: var(--space-sm); }
    }

    @media (prefers-reduced-motion: reduce) {
        .vergleich-dashboard .balken-toggle-bar,
        .vergleich-dashboard .balken-toggle-arrow { transition: none; }
    }
    /* ── Europakarte (Länderfilter) ── */
    /* display:flex (column) ueberschreibt das auto-fit-Grid der zentralen .filter-row —
       sonst laegen .ek-kopf und .ek-spalten als Grid-Items nebeneinander. */
    /* Buehne: eine Nuance dunkler als das mittelblaue Panel (rgba(9,87,143)),
       aber bewusst NICHT navy-dunkel — der urspruengliche Handelsblatt-Ton war
       fuer die Seite zu dunkel (Anwender-Feedback 2026-07-07). min-height
       gibt der Karte (meet, zentriert) Raum, damit sie als Buehne wirkt.
       Full-Bleed (2026-07-09): margin -1.5em = horizontales Padding der
       .anpassen-panel — die Buehne laeuft bis an die Panelkante, nur der
       hell→dunkel→hell-Uebergang bleibt sichtbar; deshalb keine Rundung und
       keine Seiten-Border. Das horizontale Padding gleicht die 1.5em wieder
       aus, damit die Inhalte buendig zu den uebrigen Panel-Zeilen stehen. */
    .vergleich-dashboard .ek-sektion { position: relative; overflow: hidden; margin-left: -1.5em; margin-right: -1.5em; padding: var(--space-md) calc(var(--space-md) + 1.5em); background: linear-gradient(160deg, rgba(10,48,82,0.88), rgba(14,64,108,0.78)); border: 1px solid var(--border); border-left: 0; border-right: 0; min-height: 27em; display: flex; flex-direction: column; justify-content: center; }
    .ek-kopf { flex: 0 0 auto; }
    /* Karte liegt hinter den Spalten; Wrapper faengt keine Klicks, aber die
       Landflaechen/Marker schon — so klicken freie Flaechen zu den Checkboxen durch. */
    .ek-karte-wrap { position: absolute; inset: 0; z-index: 0; pointer-events: none; display: flex; align-items: center; justify-content: center; }
    .ek-karte-wrap svg { width: 100%; height: 100%; }
    .ek-karte-wrap .ek-land, .ek-karte-wrap .ek-marker { pointer-events: auto; }
    .ek-kopf, .ek-spalten { position: relative; z-index: 1; }
    /* Die vollbreiten Container fangen sonst Klicks im freien Korridor ab —
       durchlassen, nur ihre Inhalte (Pills, Zaehler, Glas-Spalten) fangen. */
    .ek-kopf, .ek-spalten { pointer-events: none; }
    .ek-kopf > *, .ek-spalten .filter-column { pointer-events: auto; }
    /* Karten-Zustaende (Land-Stroke = Buehnenfarbe, wirkt als Laendergrenze) */
    .ek-silhouette path { fill: rgba(255,255,255,0.07); }
    .ek-land { fill: rgba(255,255,255,0.2); stroke: rgba(10,48,82,0.9); stroke-width: .5; cursor: pointer; transition: fill var(--transition-base), filter var(--transition-base); }
    .ek-land.ek-gewaehlt { fill: var(--primary); filter: drop-shadow(0 0 6px rgba(0,112,192,0.55)); }
    .ek-land:not(.ek-gesperrt):not(.ek-gewaehlt):hover { fill: rgba(0,112,192,0.45); }
    .ek-land.ek-gesperrt { fill: rgba(255,255,255,0.02); cursor: default; }
    .ek-marker { fill: rgba(255,255,255,0.14); stroke: rgba(255,255,255,0.55); stroke-width: .5; cursor: pointer; transition: fill var(--transition-base), filter var(--transition-base); }
    .ek-marker.ek-gewaehlt { fill: var(--primary); filter: drop-shadow(0 0 6px rgba(0,112,192,0.55)); }
    .ek-marker:not(.ek-gesperrt):not(.ek-gewaehlt):hover { fill: rgba(0,112,192,0.45); }
    .ek-marker.ek-gesperrt { fill: rgba(255,255,255,0.05); cursor: default; }
    /* Sanfter Puls beim Zustandswechsel (JS setzt .ek-pop kurz) */
    @keyframes ekPop { 0% { opacity: .55; } 100% { opacity: 1; } }
    .ek-pop { animation: ekPop 250ms ease; }
    /* Kopf: nur noch Schnellauswahl + Zaehler. Der Gruppen-Umschalter liegt
       nicht mehr hier, sondern auf den Glas-Karten selbst (.ek-spalte) —
       die aktive Karte zeigt, was die Karte gerade darstellt. */
    .ek-kopf { display: flex; flex-wrap: wrap; gap: .5em .75em; margin-bottom: .75em; align-items: center; }
    .ek-presets { display: inline-flex; flex-wrap: wrap; gap: .3em; align-items: center; }
    .ek-presets-label { color: var(--text-secondary); font-size: .75em; margin-right: .2em; }
    .ek-preset-btn {
        cursor: pointer; font: inherit; font-size: .75em;
        padding: .3em .85em; border-radius: 1.4em; color: rgba(255,255,255,0.85);
        background: transparent; border: 1px solid rgba(255,255,255,0.3);
        transition: background var(--transition-base), border-color var(--transition-base);
    }
    .ek-preset-btn:hover { background: rgba(169,246,219,0.25); border-color: rgba(169,246,219,0.5); }
    .ek-zaehler { color: var(--text-secondary); font-size: .85em; margin-left: auto; align-self: center; }
    /* Checkbox-Spalten als Glas ueber der Karte */
    /* Mittel-Korridor zwischen den Spalten: die Karte (meet, zentriert) wird
       dort sichtbar — Kerneuropa liegt genau in der Mitte. */
    .ek-spalten { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(2em, 24%, 16em); row-gap: var(--space-md); }
    /* Bewusst duenn (Alpha .26, blur 1px), damit die Karte durchscheint. */
    .ek-spalten .filter-column { background: rgba(10,48,82,0.26); backdrop-filter: blur(1px); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .75em; }
    /* Die Karten SIND der Gruppen-Umschalter: ganze Flaeche aktivierbar.
       Aktiv-Markierung = dasselbe Muster wie die gewaehlte Laufzeit im
       "alle Zinsen"-Tab (.zins-item.highlight): Akzent-Border + transparente
       Akzentflaeche. */
    .ek-spalte { cursor: pointer; transition: background var(--transition-base), border-color var(--transition-base); }
    .ek-spalte:not(.ek-spalte-aktiv):hover { border-color: rgba(255,255,255,0.35); }
    .ek-spalten .ek-spalte-aktiv { background: rgba(169,246,219,0.15); border-color: var(--accent); }
    /* Karten-Titel als echter Button (Tastatur-Zugang zum Umschalten),
       optisch unveraendert — der .filter-label-Span behaelt den zentralen Stil. */
    .ek-spalte-kopf { display: block; width: 100%; background: none; border: none; padding: 0; margin: 0; font: inherit; color: inherit; text-align: left; cursor: pointer; }
    /* Glas-Karten trennen sich selbst — zentrale Separator-Raender/-Margins neutralisieren
       (die frueheren .filter-row-separator[style]-Regeln greifen ohne Inline-style nicht mehr). */
    .ek-spalten .filter-column-separator { margin: 0; }
    /* Tooltip */
    .ek-tooltip { position: absolute; z-index: 2; pointer-events: none; background: rgba(10,37,64,0.92); color: #fff; padding: .3em .6em; border-radius: .4em; font-size: .8em; white-space: nowrap; opacity: 0; transition: opacity 150ms ease; }
    .ek-tooltip.ek-sichtbar { opacity: 1; }
    /* Tablet-Zwischenbereich (50–64em): die Tafeln sind wegen des Karten-
       Korridors schmal — Checkboxen einspaltig, sonst laeuft das zentrale
       repeat(2,1fr)-Grid ueber den Tafelrand (VRT-Befund 2026-07-07). */
    /* Untere Kante 50.01em statt 50em (Audit A-7.2 / K6-Port DE 2026-08-12): exakt 800px
       traf sonst diesen Block UND den `max-width: 50em`-Block darunter gleichzeitig. */
    @media (min-width: 50.01em) and (max-width: 64em) {
        .ek-spalten .checkbox-group-wrap { grid-template-columns: 1fr; }
    }
    /* Schmale Viewports: Spalten untereinander, Karte wird dezente Textur.
       Gleicher Breakpoint wie die alte Sitz-Zeile (50em). */
    @media (max-width: 50em) {
        .ek-spalten { grid-template-columns: 1fr; }
        .ek-karte-wrap { opacity: .18; }
    }

    /* --- Diagramm-Glyphe im #hilfe: eigenes Inline-SVG "Gebirgskette" (Verdrahtung 2026-07-18) ---
       Fontello-icon-chart-area rendert hier verschoben/uebergross (unscoped Fremd-Styles der
       zentralen .icon-Regel: font-size:3em, position:absolute, margin-left:-1.6em). Das SVG erbt
       currentColor, die zentralen #hilfe-Farbregeln (Ruhe/Hover) greifen unveraendert. Live vermessen
       (Liste+Tabelle+Seitenhilfe, 1920/1280/1024/375): inline-block + vertical-align:middle richtet
       die Glyphe an der line-box-Mitte der Fontello-Nachbarn aus (Mittellinien-Abweichung <=1.9px
       ueber alle Regime; die Diagrammseiten-Referenz mit display:block versagte hier mit 5.2px bei
       1280). Das gescopte a[href^='diagramm']{display:block;text-align:center} zentriert die in-flow-
       Glyphe im li, OHNE die absolut positionierten Fontello-Nachbarn zu verschieben. */
    #hilfe li a[href^='diagramm'] { display: block; text-align: center; }
    /* position MUSS relative sein, nicht static: style.css vergroessert die
       Tap-Targets mit "a > .icon::after { position:absolute; inset:-5px }".
       Bei static faellt der Bezugsrahmen dieses ::after auf einen Vorfahren
       zurueck — die unsichtbare Trefferflaeche wird ~330px breit und verdeckt
       die Nachbar-Icons: oberhalb 72em sind Tabellen- und Listen-Icon dann
       nicht mehr klickbar, ohne dass man etwas sieht (live gemessen 18.07.2026
       auf AT und DE). relative behaelt die Position im Fluss und stellt den
       Bezugsrahmen wieder her. Beim Portieren nicht auf static zuruecksetzen. */
    /* Vertikal-Politur 2026-07-18: symmetrischer top-Nudge zieht den Link-Zustand (hier)
       UND den current-Zustand auf der Diagrammseite auf die Mitte ihrer frueheren Positionen
       (der Link lag ~1.5px @Basis / ~3.8px @<=88em zu tief, die Diagrammseite spiegelbildlich
       hoch — Gegenwert im Diagramm-Core +1.5px / +3.8px). <=72em: beide nativ schon
       deckungsgleich, top:0 ueberschreibt dort nur die geerbten 88em-Werte. Live gemessen
       |A-B| <= 1px ueber 1920/1280/1024/375 (max 0.92px; <=72em nativ), beide nahe der Alt-Mitte. */
    #hilfe .zg-view-icon { display: inline-block; position: relative; margin: 0; width: 1.3em; line-height: inherit; vertical-align: middle; font-size: 1.85em; top: -1.5px; }
    #hilfe .zg-view-icon svg { width: 1.3em; height: 0.91em; vertical-align: middle; display: inline-block; }
    @media (max-width: 88em) { #hilfe .zg-view-icon { font-size: 1.3em; top: -3.8px; } }
    @media (max-width: 72em) { #hilfe .zg-view-icon { font-size: 1.2em; top: 0; } }

    /* === Hochkontrast-Hell-Modus — Ebene C (view-spezifische Farb-Overrides) =========
       Ebene A (weisse Karte, h1, #hilfe-Icons, Toggle-Hell), Ebene B (.vergleich-dashboard-
       Variablen-Remap), die Toggle-Basis (.kontrast-zeile/.kontrast-toggle/.ecke-*) und der
       geteilte Mobile-Anteil (weisses Vollband, #hilfe mobil) liegen ZENTRAL in
       vergleich.min.css?v=18 (Schwester-Rollout 2026-07-10) — hier NICHT dupliziert. Dieser
       Block enthaelt nur die hartkodierten, tabellen-spezifischen Farben, die kein zentraler
       Block abdecken kann. Aktiv nur bei #vergleich.kontrast-hell; alle Overrides per
       ID+Klasse-Spezifitaet (NIE !important), em-Konvention (px nur border-width/box-shadow/
       outline/gradient/@media), keine Geometrie-/transform-Aenderung (FLIP unberuehrt).
       Akzente konsequent Blau statt Tuerkis. Port aus der AT-FG-Tabellen-Schwester. Bewusste
       Ausnahmen: das Sticky-Header-Band (Logo/Badge/Zins) bleibt Marken-Blau (weisse Logos/
       Zinszahlen bleiben lesbar); die Europakarte (.ek-*) bleibt dunkle Marken-Buehne. */

    /* -- Sticky-VP-Spalte (Merkmal-Labels) hell, blaue Trennkante -- */
    #vergleich.kontrast-hell .vp-spalte { background: #fff; border-right-color: rgba(0,82,141,0.28); box-shadow: 0.25em 0 0.5em rgba(0,82,141,0.10); }
    #vergleich.kontrast-hell .vp-zelle { color: #003A66; background: #fff; }
    #vergleich.kontrast-hell .vp-zelle, #vergleich.kontrast-hell .ab-zelle { border-bottom-color: rgba(0,82,141,0.12); }
    #vergleich.kontrast-hell .ab-merkmal.ab-leer { color: rgba(0,0,0,0.65); }

    /* -- Sticky-Header-Stapel (Logo/Badge/Zins) bleibt als Marken-Blau-Band (bewusste
          Ausnahme). Badge/Zins sind im Dunkelmodus rgba(9,87,143,0.92) (auf Blau opak
          wirkend) -> auf der weissen Karte auf die opake Variante setzen (sonst scheint die
          weisse Karte durch). Logo-Reihe traegt bereits ihr eigenes #0070C0. Schrift/Zinszahl
          weiss (var(--text-primary) wuerde sie auf #111 kippen). -- */
    #vergleich.kontrast-hell .vp-zelle.vp-header,
    #vergleich.kontrast-hell .ab-zelle.ab-badge,
    #vergleich.kontrast-hell .ab-zelle.ab-zins { background: rgb(9,87,143); }
    #vergleich.kontrast-hell .vp-zelle.vp-header { color: rgba(255,255,255,0.9); }
    #vergleich.kontrast-hell .ab-anbieter { color: #fff; }
    #vergleich.kontrast-hell .ab-zelle.ab-zins { color: #fff; }

    /* -- Geschenk-Icon (cardgift-g.svg, Neukundenaktion): Tuerkis -> Marken-Hellblau.
          SVG kommt als <img> -> Filterkette faerbt exakt auf #0070C0; eigener Hover,
          weil der Basis-Hover (brightness/saturate) den Filter ersetzen wuerde. -- */
    #vergleich.kontrast-hell .ab-merkmal-html a.cardgifta img {
        filter: brightness(0) saturate(100%) invert(26%) sepia(98%) saturate(946%) hue-rotate(176deg) brightness(110%) contrast(113%);
    }
    #vergleich.kontrast-hell .ab-merkmal-html a.cardgifta:hover img {
        filter: brightness(0) saturate(100%) invert(26%) sepia(98%) saturate(946%) hue-rotate(176deg) brightness(110%) contrast(113%) brightness(125%);
    }

    /* -- Footer-CTA-Reihe / Empty-State -- */
    #vergleich.kontrast-hell .vp-zelle.vp-footer { background: #fff; border-top-color: rgba(0,82,141,0.15); color: #003A66; }
    #vergleich.kontrast-hell .ab-zelle.ab-cta { border-top-color: rgba(0,82,141,0.15); }
    #vergleich.kontrast-hell .tabelle-keine-ergebnisse { color: #111; }
    #vergleich.kontrast-hell .vergleich-dashboard .footer-line a { color: #00528D; }
    #vergleich.kontrast-hell .vergleich-dashboard .footer-line a:hover { color: #0070C0; }

    /* -- CTA-Button "Zum Anbieter" (var(--accent)+var(--primary-darker) -> Dunkel-auf-Dunkel):
          explizit blaue Fuellung, weisse Schrift; Pfeil-Chip invertiert. -- */
    #vergleich.kontrast-hell .vergleich-dashboard .anbieter-link { background: #0070C0; color: #fff; }
    #vergleich.kontrast-hell .vergleich-dashboard .anbieter-link:hover { background: #00528D; }
    #vergleich.kontrast-hell .vergleich-dashboard .anbieter-link .link-arrow { background: #fff; color: #00528D; }

    /* -- Fussnoten (tabelle.min.css: hartkodiert Weiss-Text + Tuerkis-Links) -- */
    #vergleich.kontrast-hell .tabelle-fussnoten { background: rgba(0,82,141,0.05); color: #333; }
    #vergleich.kontrast-hell .tabelle-fussnoten li strong { color: #111; }
    #vergleich.kontrast-hell .tabelle-fussnoten a { color: #00528D; }
    #vergleich.kontrast-hell .tabelle-fussnoten a:hover { color: #0070C0; }

    /* -- Gruppen-Titel-Baender (Koernung) hell-blau statt Schwarz/Weiss-Transparenz -- */
    #vergleich.kontrast-hell .ab-gruppe-spacer, #vergleich.kontrast-hell button.vp-gruppentitel {
        background-color: rgba(0,82,141,0.06);
        background-image: radial-gradient(circle, rgba(0,82,141,0.10) 0 0.7px, transparent 1.1px);
        border-top-color: rgba(0,82,141,0.16); border-bottom-color: rgba(0,82,141,0.10);
        box-shadow: inset 0 1px 0 rgba(255,255,255,0.6);
    }
    #vergleich.kontrast-hell button.vp-gruppentitel { color: #00528D; }
    #vergleich.kontrast-hell .vp-gruppentitel-caret { color: #00528D; }
    #vergleich.kontrast-hell button.vp-gruppentitel:hover .vp-gruppentitel-caret,
    #vergleich.kontrast-hell button.vp-gruppentitel.is-row-hover .vp-gruppentitel-caret { color: #0070C0; }

    /* -- Laufzeit-Pills / Anlagebetrag-Toggle: helle Leisten, blaue Akzente. Aktive
          Pill/Toggle nutzen background:var(--text-primary) -> im Hell-Modus #111 (dunkel);
          darum explizit blau fuellen, Schrift weiss. -- */
    #vergleich.kontrast-hell .vergleich-dashboard .laufzeit-nav { background: rgba(0,82,141,0.06); }
    #vergleich.kontrast-hell .vergleich-dashboard .laufzeit-pill { color: #003A66; }
    #vergleich.kontrast-hell .vergleich-dashboard .laufzeit-pill:hover { background: rgba(0,82,141,0.08); color: #003A66; }
    #vergleich.kontrast-hell .vergleich-dashboard .laufzeit-pill.active { background: #0070C0; color: #fff; }
    #vergleich.kontrast-hell .vergleich-dashboard .toggle-group,
    #vergleich.kontrast-hell .vergleich-dashboard .filter-group .toggle-group { background: rgba(0,82,141,0.06); }
    #vergleich.kontrast-hell .vergleich-dashboard .toggle-btn { color: #003A66; }
    #vergleich.kontrast-hell .vergleich-dashboard .toggle-btn:hover { background: rgba(0,82,141,0.08); color: #003A66; }
    #vergleich.kontrast-hell .vergleich-dashboard .toggle-btn.active { background: #0070C0; color: #fff; }
    #vergleich.kontrast-hell .vergleich-dashboard .filter-label,
    #vergleich.kontrast-hell .vergleich-dashboard .filter-column-title { color: #003A66; }

    /* -- Europakarte-Buehne (Laenderfilter): bewusste dunkle Marken-Ausnahme (nicht
          umfaerben). Die Buehne ist ein dunkles Navy-Gradient-Panel; Ebene-B-Variablen +
          die generische filter-label-Hell-Regel oben wuerden die hellen Karten-
          Beschriftungen darauf ins Dunkle kippen. Darum die Schrift-Variablen lokal auf
          Dunkelmodus-Werte zuruecksetzen und die Beschriftungen wieder aufhellen
          (Quellreihenfolge schlaegt die gleichspezifische Regel oben). Land-/Marker-/
          Preset-/Spalten-Farben bleiben komplett unveraendert. -- */
    #vergleich.kontrast-hell .ek-sektion {
        --text-primary: #fff; --text-secondary: rgba(255,255,255,0.85); --text-muted: rgba(255,255,255,0.6);
        --accent: #00d4aa; --accent-light: #00d4aa;
    }
    #vergleich.kontrast-hell .ek-sektion .filter-label,
    #vergleich.kontrast-hell .ek-sektion .filter-column-title { color: rgba(255,255,255,0.85); }

    /* -- Auslandsanlagen-Balken-Toggle (Festgeld-spezifisch, tabelle.min.css: helle Bars
          #DCEBF8, State/Arrow #F1F6FC/#DCEBF8 -> auf Weiss unsichtbar). Blaue Umfaerbung;
          aktive Bars = Marken-Blau (wie laufzeit-pill.active). -- */
    #vergleich.kontrast-hell .vergleich-dashboard .balken-toggle-state { color: #00528D; }
    #vergleich.kontrast-hell .vergleich-dashboard .balken-toggle-arrow { color: #00528D; }
    #vergleich.kontrast-hell .vergleich-dashboard .balken-toggle-bars-dash .balken-toggle-bar { background: rgba(0,82,141,0.30); }
    #vergleich.kontrast-hell .vergleich-dashboard .balken-toggle[data-state="off"] .balken-toggle-bars-dash .balken-toggle-bar:nth-child(-n+8),
    #vergleich.kontrast-hell .vergleich-dashboard .balken-toggle[data-state="on"] .balken-toggle-bars-dash .balken-toggle-bar { background: #0070C0; }

    /* -- "weitere Filter"-Button (Floating): dunkelblau/tuerkis -> Weiss + Blau -- */
    #vergleich.kontrast-hell .anpassen-filter-btn { background: #fff; box-shadow: 0 0.125em 0.5em rgba(0,82,141,0.25); }
    #vergleich.kontrast-hell .anpassen-filter-btn:hover, #vergleich.kontrast-hell .anpassen-filter-btn.open { background: rgba(0,112,192,0.14); }
    #vergleich.kontrast-hell .anpassen-filter-btn:focus-visible { outline-color: #0070C0; }
    #vergleich.kontrast-hell .anpassen-filter-btn .ecke-tl { border-top-color: #0070C0; border-left-color: #0070C0; }
    #vergleich.kontrast-hell .anpassen-filter-btn .ecke-tr { border-top-color: #0070C0; border-right-color: #0070C0; }
    #vergleich.kontrast-hell .anpassen-filter-btn .ecke-bl { border-bottom-color: #0070C0; border-left-color: #0070C0; }
    #vergleich.kontrast-hell .anpassen-filter-btn .ecke-br { border-bottom-color: #0070C0; border-right-color: #0070C0; }
    #vergleich.kontrast-hell .anpassen-filter-btn .icon-wrap .icon-sliders { color: #00528D; }
    #vergleich.kontrast-hell .anpassen-badge { background: #0070C0; color: #fff; }

    /* -- Filter-Overlay-Panel: dunkelblau -> weisses Panel, blauer Rahmen; Backdrop bleibt.
          Titel/Hints nutzen var(--text-secondary) (Ebene B deckt sie ab) — nur die
          hartkodierten Weiss-Werte (.filter-panel-titel Farbe+Border, panel-close-btn)
          brauchen Overrides. Checkboxen sind native accent-color:#00528d (bereits blau). -- */
    #vergleich.kontrast-hell .anpassen-panel {
        background: #fff; border-color: rgba(0,82,141,0.35);
        box-shadow: 0 0.5em 2.5em rgba(0,0,0,0.25), 0 0.125em 0.5em rgba(0,0,0,0.15);
    }
    #vergleich.kontrast-hell .filter-panel-titel { color: #00528D; border-bottom-color: rgba(0,82,141,0.18); }
    #vergleich.kontrast-hell .filter-checkbox { color: #333; }
    #vergleich.kontrast-hell .filter-checkbox:hover { color: #003A66; }
    #vergleich.kontrast-hell .panel-close-btn { background: rgba(0,82,141,0.10); color: #00528D; }
    #vergleich.kontrast-hell .panel-close-btn:hover, #vergleich.kontrast-hell .panel-close-btn:focus { background: rgba(0,82,141,0.18); color: #003A66; }

    /* -- Pager (Skala/Chevrons): Tuerkis -> Blau -- */
    #vergleich.kontrast-hell .tabelle-pager-range { color: #111; }
    #vergleich.kontrast-hell .tabelle-pager-bereich, #vergleich.kontrast-hell .tabelle-pager-bereich strong { color: #00528D; }
    #vergleich.kontrast-hell .tabelle-pager-rest { color: #333; }
    #vergleich.kontrast-hell .tabelle-pager-btn { color: #0070C0; }
    #vergleich.kontrast-hell .tabelle-pager-btn:not(:disabled):hover, #vergleich.kontrast-hell .tabelle-pager-btn:focus-visible { color: #00528D; }
    #vergleich.kontrast-hell .tabelle-pager-btn:focus-visible { outline-color: #0070C0; }
    #vergleich.kontrast-hell .tabelle-pager-track::before { background: repeating-linear-gradient(90deg, rgba(0,82,141,0.20) 0 1px, transparent 1px 11px), rgba(0,82,141,0.08); }
    #vergleich.kontrast-hell .tabelle-pager-track:focus-visible { outline-color: #0070C0; }
    #vergleich.kontrast-hell .tabelle-pager-fenster { background: rgba(0,112,192,0.18); border-color: #0070C0; }

    /* -- Scroll-Indikator / native Scrollbar / Scroll-Fade-Kanten: Weiss -> Blau -- */
    #vergleich.kontrast-hell .tabelle-scrollbar-indikator { background: rgba(0,82,141,0.10); }
    #vergleich.kontrast-hell .tabelle-scrollbar-thumb { background: rgba(0,82,141,0.55); }
    #vergleich.kontrast-hell .tabelle-scroller:hover ~ .tabelle-scrollbar-indikator .tabelle-scrollbar-thumb,
    #vergleich.kontrast-hell .tabelle-scroller.is-dragging ~ .tabelle-scrollbar-indikator .tabelle-scrollbar-thumb { background: rgba(0,82,141,0.75); }
    #vergleich.kontrast-hell .tabelle-scroller { scrollbar-color: rgba(0,82,141,0.55) rgba(0,82,141,0.10); }
    #vergleich.kontrast-hell .tabelle-scroller::-webkit-scrollbar-track { background: rgba(0,82,141,0.10); }
    #vergleich.kontrast-hell .tabelle-scroller::-webkit-scrollbar-thumb { background: rgba(0,82,141,0.55); }
    #vergleich.kontrast-hell .tabelle-scroller::-webkit-scrollbar-thumb:hover { background: rgba(0,82,141,0.75); }
    #vergleich.kontrast-hell .tabelle-wrapper::after { background: linear-gradient(to right, transparent 0%, rgba(0,82,141,0.14) 100%); }
    #vergleich.kontrast-hell .tabelle-wrapper::before { background: linear-gradient(to left, transparent 0%, rgba(0,82,141,0.14) 100%); }

    /* -- Mobile (<=38em): nur die tabellen-spezifischen Merkmal-/Mini-Label-/Info-Icon-
          Overrides (weisses Vollband + #hilfe-Basisfarben liegen zentral). -- */
    @media (max-width: 38em) {
        #vergleich.kontrast-hell .ab-zelle.ab-merkmal { border-bottom-color: rgba(0,82,141,0.14); }
        #vergleich.kontrast-hell .ab-mini-label { color: #00528D; }
        #vergleich.kontrast-hell .ab-info-icon { color: #00528D; }
        #vergleich.kontrast-hell .ab-info-icon:hover, #vergleich.kontrast-hell .ab-info-icon:focus-visible { color: #003A66; }
        #vergleich.kontrast-hell .ab-info-icon.ab-info-icon-mini-label { color: #00528D; }
        #vergleich.kontrast-hell .ab-info-icon.ab-info-icon-mini-label:hover, #vergleich.kontrast-hell .ab-info-icon.ab-info-icon-mini-label:focus-visible { color: #003A66; }
        #vergleich.kontrast-hell .tabelle-grid > .anbieter-spalte:first-child .mb-gruppentitel:hover .vp-gruppentitel-caret { color: #0070C0; }
    }
    /* === Ende Hochkontrast-Hell-Modus Ebene C === */

    /* Absatzwechsel innerhalb einer Fussnote (siehe .fn-absatz im PHP-Block):
       definierter Abstandshalter statt der vollen Leerzeile aus <br><br>.
       0.35em ergibt gemessene 7,4 px — unterhalb der 8,8 px zwischen zwei
       Anbieter-Eintraegen, damit die Absaetze sichtbar zum selben Eintrag
       gehoeren. Herkunft der Messreihe: fussnoten-absatzabstand-rollout-
       uebergabe.md (Tabellendarstellung/Festgeld DE). */
    .tabelle-fussnoten .fn-absatz { display: block; height: 0.35em; }
    