/* ════════════════════════════════════════════════════════════════════════
   components.css — Wiederverwendbare UI-Bausteine (Layer: components)
   Reihenfolge: Header-Teile → Sidebar → Content-Bausteine
   ════════════════════════════════════════════════════════════════════════ */

@layer components {

  /* ══ Logo ═══════════════════════════════════════════════════════════════ */
  .logo {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-family: var(--font-head);
    font-size: var(--fs-base);
    font-weight: 700;
    letter-spacing: 0.08em;
    color: var(--accent-bright);
    white-space: nowrap;
  }
  .logo:hover { color: var(--accent-bright); }

  /* Schriftzug „EV LOVE PW" (Cinzel) — bewusstes Wortspiel auf „Evolved PW" (= Evolved
     liebt PW), KEIN Tippfehler. EV und PW in Gold (Marke), LOVE in Weiß, mit Freiraum zu
     beiden Seiten. Echter Name bleibt im aria-label des Logo-Links (header.php). */
  .logo-text {
    font-family: var(--font-head);
    font-size: var(--fs-md);
    letter-spacing: 0.06em;
    line-height: 1;
    white-space: nowrap;
    /* Cinzel ist ein Versalien-Font: die Großbuchstaben sitzen (leere Unterlänge)
       optisch zu hoch in der Zeilenbox → trotz align-items:center wirkt die Schrift
       gegenüber dem geometrisch mittigen Emblem nach oben versetzt. Kleiner Ausgleich. */
    transform: translateY(2px);
  }

  .logo-ev,
  .logo-pw { color: var(--accent-bright); }

  .logo-mid {
    margin: 0 0.35em;
    color: var(--text-1);
  }

  /* Geflügeltes Wappen-Emblem (Inline-SVG in header.php), links vom Schriftzug.
     Höhe an den Schriftzug gekoppelt; align-items:center der .logo richtet aus. */
  .logo-emblem {
    height: 1.6rem;
    width: auto;
    flex-shrink: 0;
  }

  /* Gold-Verlauf des Emblems aus Tokens (einzige Farbquelle, kein Hex im Markup). */
  .logo-grad-0 { stop-color: var(--accent); }
  .logo-grad-1 { stop-color: var(--accent-bright); }

  /* ══ Haupt-Navigation ═══════════════════════════════════════════════════ */
  .main-nav {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-left: var(--sp-6);
  }

  .main-nav a {
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--radius);
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--text-2);
    transition: color var(--t-fast), background var(--t-fast);
  }

  .main-nav a:hover {
    color: var(--text-1);
    background: var(--bg-hover);
  }
  .main-nav a[aria-current='page'] { color: var(--accent-bright); }

  /* Entwurfs-Hub in der Nav — nur für Editoren sichtbar (evpw_nav_hubs lädt Entwürfe editor-only, wie
     Entwurfs-Seiten). Gedämpft, damit Live von Entwurf unterscheidbar bleibt (kein Icon; Tooltip erklärt). */
  .main-nav a.nav-draft { color: var(--text-3); }

  /* Desktop: das Logo füllt die volle Sidebar-Spalte (Header-Start bei --sp-5 bis
     zum Sidebar-Trenner bei --sidebar-w) → die Hauptnav beginnt bündig am Trenner,
     fluchtet also mit dem Content statt über der Sidebar zu kleben. Mobile (≤900px,
     Sidebar ist Off-Canvas-Drawer) bleibt unverändert (margin-left: --sp-6). */
  @media (width > 900px) {
    .logo {
      width: calc(var(--sidebar-w) - var(--sp-5));
      flex-shrink: 0;
    }
    /* Kürzel schwebt mittig im Raum zwischen Emblem und Trenner (statt am Emblem
       zu kleben): margin-inline:auto zentriert es im Restplatz. */
    .logo-text { margin-inline: auto; }
    .main-nav { margin-left: 0; }
  }

  /* ── Seitentitel mittig im Header (Gear-Seiten) ───────────────────────────
     Absolut zentriert über die volle Headerbreite (unabhängig von Logo-/Nav-/
     Account-Breite). pointer-events: none → liegt nur „über" dem Header, fängt
     keine Klicks ab. Im Hochformat verborgen (dort bleibt der Hero-H1). */
  .header-title {
    position: absolute;
    /* Mittig über dem INHALTSBEREICH, nicht über dem ganzen Viewport: die feste
       Sidebar (var(--sidebar-w)) liegt links unter dem Header → um deren halbe
       Breite nach rechts versetzen, sonst wirkt der Titel nach links gerückt. */
    left: calc(50% + var(--sidebar-w) / 2);
    transform: translateX(-50%);
    font-family: var(--font-head);
    font-size: var(--fs-lg);
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--text-1);
    white-space: nowrap;
    pointer-events: none;
  }

  @media (width <= 900px) {
    /* Sidebar ist Off-Canvas-Drawer → kein Offset, echtes Viewport-Zentrum. */
    .header-title { left: 50%; }
  }

  @media (width <= 900px) and (orientation: portrait) {
    .header-title { display: none; }
  }

  /* ══ Hamburger ═════════════════════════════════════════════════════════
     Öffnet den Sidebar-Drawer. Desktop: Sidebar ist fest → Toggle versteckt.
     Sichtbar erst ab ≤900px (Umschaltung bleibt in diesem Layer). */
  .nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    margin-right: var(--sp-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card-2);
    color: var(--text-2);
  }

  .nav-toggle:hover { color: var(--text-1); }

  .nav-toggle-bars,
  .nav-toggle-bars::before,
  .nav-toggle-bars::after {
    display: block;
    width: 18px;
    height: 2px;
    border-radius: 1px;
    background: currentcolor;
  }

  .nav-toggle-bars {
    position: relative;
  }

  .nav-toggle-bars::before,
  .nav-toggle-bars::after {
    content: '';
    position: absolute;
    left: 0;
  }

  .nav-toggle-bars::before { top: -6px; }
  .nav-toggle-bars::after { top: 6px; }

  @media (width <= 900px) {
    .nav-toggle { display: flex; }
  }

  /* ══ Header-rechts: Sprachumschalter + User ════════════════════════════ */
  .header-right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
  }

  /* Aufnahme-Slot für den Editier-Umschalter (js/page/writer.js hängt ihn ein). Ohne Toggle (kein
     Editier-Recht) leer → aus dem Flow (kein Gap). */
  .header-edit {
    display: flex;
    align-items: center;
  }

  .header-edit:empty {
    display: none;
  }

  /* Editieren ist Desktop-only: der jetzt SERVER-gerenderte Toggle (header.php) bleibt auf Touch ohne
     Handler (bootstrap.js entfernt dort data-editor → kein initPageWriter) → den Slot ganz ausblenden. */
  @media (hover: none) and (pointer: coarse) {
    .header-edit {
      display: none;
    }
  }

  .lang-toggle {
    display: flex;
    align-items: center;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-card);
  }

  .lang-toggle button {
    padding: 5px var(--sp-3);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text-3);
    transition: color var(--t-fast), background var(--t-fast);
  }

  .lang-toggle button[aria-pressed='true'] {
    background: var(--accent);
    color: #000;
  }
  .lang-toggle button:hover:not([aria-pressed='true']) { color: var(--text-1); }

  .user-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    padding: 5px 0;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-card-2);
    color: var(--text-2);
    font-size: var(--fs-sm);
  }

  .user-btn:hover {
    color: var(--text-1);
    border-color: var(--border-accent);
  }

  /* ══ Benutzerrollen-Farben (global: Auth-Popup, Sidebar-User, Account, Benutzerverwaltung) ══
     Quelle der Klasse: evpw_role_class() in includes/auth.php. */
  .role-admin {
    color: var(--accent);
  }

  .role-coadmin {
    color: var(--c-purple);
  }

  .role-editor {
    color: var(--c-cyan);
  }

  .role-user {
    color: var(--text-3);
  }

  /* ══ Sidebar-Bausteine ══════════════════════════════════════════════════ */
  .sidebar-label {
    padding: var(--sp-3) var(--sp-2) 6px;
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-3);
  }

  .sidebar-item {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    position: relative;
    padding: 7px var(--sp-2);
    border-radius: var(--radius);
    font-size: var(--fs-sm);
    color: var(--text-2);
    transition: color var(--t-fast), background var(--t-fast);
  }

  /* <button> als Sidebar-Item streckt nicht von selbst (Form-Element = fit-content) — wie die <a>-Varianten
     auf volle Breite ziehen, sonst wirken kurze Labels „abgeschnitten" (aktiver Hintergrund nur textbreit). */
  button.sidebar-item {
    width: 100%;
  }

  .sidebar-item:hover {
    color: var(--text-1);
    background: var(--bg-hover);
  }

  /* Generisch [aria-current] (nicht nur ='page'): deckt die server-gesetzten Route-Nav-Fälle
     ('page') UND den ToC-Scroll-Spy ab, der die In-Page-Leseposition mit aria-current='true'
     markiert (js/page/toc-scrollspy.js). aria-current='false' wird nie gesetzt (immer entfernt). */
  .sidebar-item[aria-current] {
    color: var(--accent-bright);
    background: var(--accent-glow);
  }

  .sidebar-item[aria-current]::before {
    content: '';
    position: absolute;
    left: 0; top: 20%; bottom: 20%;
    width: 2px;
    border-radius: 2px;
    background: var(--accent);
  }

  .sidebar-item.sub {
    padding-left: 22px;
    font-size: var(--fs-sm);
  }

  /* „Nach oben"-Steuerung (ToC S4): runder Pfeil-Knopf unten rechts, Stil wie .legend-fab. Erscheint erst
     nach etwas Scrollen (.is-visible via js/page/back-to-top.js); Fade über opacity (kein Layout-Sprung). */
  .back-to-top {
    position: fixed;
    right: var(--sp-4);
    bottom: var(--sp-4);
    z-index: 140;
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    color: var(--accent);
    background: var(--bg-card);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius);
    box-shadow: 0 4px 16px rgb(0 0 0 / 45%);
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t-fast), background var(--t-fast);
  }

  .back-to-top svg {
    width: 1.25rem;
    height: 1.25rem;
  }

  .back-to-top.is-visible {
    opacity: 1;
    pointer-events: auto;
  }

  .back-to-top:hover {
    background: var(--bg-hover);
  }

  /* Offener Nav-Drawer verdeckt den Inhalt → Steuerung raus. */
  .nav-open .back-to-top {
    opacity: 0;
    pointer-events: none;
  }

  /* Editier-Modus: „Nach oben" (und Störendes generell) raus — es säße sonst auf der unteren Werkzeugleiste. */
  .page-editing .back-to-top {
    display: none;
  }

  /* Mobil sitzt unten rechts der Legenden-„?"-FAB (.legend-fab, 2.75rem) → „Nach oben" DARÜBER stapeln. */
  @media (width <= 900px) {
    .back-to-top {
      bottom: calc(var(--sp-4) + 2.75rem + var(--sp-2));
    }
  }

  /* S5: mobiler „aktuelle Sektion"-Zugang (js/page/toc-current.js). Schlanke sticky Leiste unter dem fixen
     Header; zeigt den gelesenen Abschnitt (Scroll-Spy S1) + Chevron, Tap öffnet das ToC-Drawer. Default aus;
     .is-visible (JS) blendet ein. NUR ≤900px — am Desktop steht die ToC dauerhaft. Bei offenem Drawer raus. */
  .toc-current {
    display: none;
  }

  @media (width <= 900px) {
    .toc-current {
      position: fixed;
      inset: var(--header-h) 0 auto;
      z-index: 90;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: var(--sp-2);
      width: 100%;
      padding: var(--sp-2) var(--sp-5);
      background: rgb(8 11 19 / 92%);
      backdrop-filter: blur(16px);
      border-bottom: 1px solid var(--border);
      color: var(--text-2);
      font-size: var(--fs-sm);
      text-align: left;
      cursor: pointer;
      opacity: 0;
      pointer-events: none;
      transition: opacity var(--t-fast);
    }

    .toc-current.is-visible {
      opacity: 1;
      pointer-events: auto;
    }

    .nav-open .toc-current {
      opacity: 0;
      pointer-events: none;
    }

    .toc-current-label {
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }

    .toc-current-caret {
      flex: none;
      width: 1rem;
      height: 1rem;
      color: var(--text-3);
    }
  }

  .sidebar-divider {
    height: 1px;
    margin: var(--sp-2);
    background: var(--border);
  }

  /* ══ Breadcrumb ═════════════════════════════════════════════════════════ */
  .breadcrumb {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: var(--sp-6);
    font-size: var(--fs-xs);
    color: var(--text-3);
  }
  .breadcrumb a { color: var(--text-3); }
  .breadcrumb a:hover { color: var(--text-2); }
  .breadcrumb [aria-current='page'] { color: var(--text-2); }

  /* ══ Hero ═══════════════════════════════════════════════════════════════ */
  .hero {
    margin-bottom: var(--sp-8);
    padding-bottom: var(--sp-8);
    border-bottom: 1px solid var(--border);
    text-align: center;
  }

  /* Hero zentriert (Port-Treue zu main). .hero-desc ist geteilt (auch im
     „Was ist?"-Absatz) → Zentrierung hier gescopet, nicht global.
     max-width aufgehoben: Tagline soll am Desktop einzeilig stehen (der 760px-
     Deckel zwang sonst einen Umbruch) und erst auf schmalen Screens umbrechen. */
  .hero .hero-desc {
    max-width: none;
    margin-inline: auto;
  }

  .hero h1 {
    font-size: var(--fs-xl);
    font-weight: 700;
    margin-bottom: var(--sp-3);
  }
  /* Gold-Akzent gilt für beide Anzeigeorte desselben Titels: Hero-H1 und der in
     die Top-Nav gescrollte Header-Titel (Startseite). Eine Regel, zwei Empfänger. */
  .hero h1 .accent,
  .header-title .accent { color: var(--accent-bright); }

  /* Projekt-Standard „Titel = Top-Nav": Seiten mit Header-Titel (Markierung aus
     header.php) blenden ihr Hero-H1 am Desktop aus — der Titel sitzt im Header.
     Nur im engen Hochformat (Header-Titel verborgen) bleibt der H1 als Fallback.
     AUSNAHME `hero-scroll` (Content-Seiten): dort bleibt der Hero-H1 am Desktop
     sichtbar und rückt erst beim Wegscrollen in die Nav (s. .hero-scroll-Block unten). */
  .has-header-title:not(.hero-scroll) .hero h1 { display: none; }

  /* „Titel scrollt in die Nav" (Content-Seiten, Desktop): der Hero-H1 steht groß im
     Inhalt; der Nav-Titel ist zunächst unsichtbar und wird per IntersectionObserver
     (js/shared/hero-nav-title.js → <html>.hero-passed) sanft eingeblendet, sobald der
     Hero-H1 nach oben aus dem Bild scrollt. Mobile: hero-passed wird nie gesetzt →
     Nav-Titel bleibt unsichtbar (Hero-H1 trägt den Titel, Kopfleiste ist eng). */
  .hero-scroll .header-title {
    opacity: 0;
    transition: opacity 0.2s ease;
  }
  .hero-scroll.hero-passed .header-title { opacity: 1; }

  /* Eingeloggter Account-Hero enthält NUR den (am Desktop versteckten) Titel → ganzen
     Hero am Desktop einklappen, damit kein leerer Rahmen bleibt. Im Hochformat trägt er den H1. */
  .page-account .acc-hero-titleonly { display: none; }

  @media (width <= 900px) and (orientation: portrait) {
    .has-header-title .hero h1 { display: block; }
    .page-account .acc-hero-titleonly { display: block; }
  }

  .hero-desc {
    max-width: 760px;
    color: var(--text-2);
    font-size: var(--fs-base);
    line-height: 1.7;
  }

  .hero-tags {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-3);
  }

  /* ══ Tags / Badges ══════════════════════════════════════════════════════ */
  .tag {
    padding: 3px 9px;
    border-radius: var(--radius);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
  }

  .tag-accent {
    background: var(--accent-glow);
    color: var(--accent-bright);
    border: 1px solid var(--border-accent);
  }

  .tag-muted {
    background: var(--bg-card);
    color: var(--text-3);
    border: 1px solid var(--border);
  }

  .badge-unverified {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-left: var(--sp-1);
    padding: 1px 6px;
    border: 1px solid color-mix(in srgb, var(--c-amber) 25%, transparent);
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--c-amber) 10%, transparent);
    color: var(--c-amber);
    font-size: var(--fs-xs);
    font-weight: 600;
    cursor: help;
  }

  /* ══ Section-Titel ══════════════════════════════════════════════════════ */
  /* Section-Rhythmus wie main: großzügiger Abstand + dezente Trennlinie. */
  .section {
    margin-bottom: var(--sp-10);
    padding-bottom: var(--sp-10);
    border-bottom: 1px solid var(--border);
  }

  .section:last-child {
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom: none;
  }

  .section-title {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-4);
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--border);
    font-family: var(--font-head);
    font-size: var(--fs-md);
    font-weight: 600;
  }

  .section-title::before {
    content: '';
    width: 3px; height: 16px;
    flex-shrink: 0;
    border-radius: 2px;
    background: var(--accent);
  }

  /* Unterüberschrift im Fluss (h3..h6, U4) — kein ToC, kein Sektions-Balken; absteigende Größe.
     Vertikalen Rhythmus übernimmt die Block-Abstandsregel ([data-block-id] + [data-block-id]).
     Font = --font-body (Inter), NICHT die Cinzel-Marken-Serif (2026-07-14): all-caps-Capitalis ist bei
     kleinen Größen (fs-md/base/sm = 18/16/14 px) schwer lesbar; Cinzel bleibt Seitentitel (h1) +
     Sektions-Überschrift (h2/.section-title). weight 600 = gleich wie section-title (keine Inversion). */
  .sub-heading {
    font-family: var(--font-body);
    font-weight: 600;
    line-height: 1.25;
  }

  .sub-heading[data-level="3"] { font-size: var(--fs-md); }
  .sub-heading[data-level="4"] { font-size: var(--fs-base); }

  .sub-heading[data-level="5"],
  .sub-heading[data-level="6"] { font-size: var(--fs-sm); }

  /* ══ Block-Sektionen (Block-Engine, section--grid) ════════════════════════
     Top-Level-Blöcke stapeln vertikal in voller Breite (Nebeneinander-Konvergenz K.3): das frühere 12-Spalten-
     Grid mit half/third-Breiten ist entfernt — Nebeneinander entsteht AUSSCHLIESSLICH über columns-Blöcke
     (ein Mechanismus: gleich hohe Karten + Container-Query-Responsiv). Die Sektion bleibt der Query-Container
     für TOP-LEVEL .cols (N.4): ein columns-Block direkt in der Sektion reagiert auf die Content-Breite
     (verschachtelte .cols messen stattdessen ihre Slot-Hülle). */
  .section--grid { container-type: inline-size; }

  /* Bild-Umfluss (vorbild-gegenstuecke.md #6): eine Sektion mit floatendem Bild bekommt einen eigenen
     Block-Formatierungs-Kontext (flow-root) → der Float bleibt IN der Sektion, läuft nicht in die nächste. */
  .section--grid:has(> [data-align="float-left"], > [data-align="float-right"]) {
    display: flow-root;
  }

  /* ══ Spalten-Container (Layout-Block `columns`, tasks/layout-container-block.md) ════════════
     Eigenes Grid IM Container (unabhängig vom Sektions-Block-Grid oben): 2..6 Spalten via data-cols.
     Jede .col-Hülle stapelt ihre echten Kind-Blöcke vertikal. Mobile-First: mobil gestapelt (1 Spalte) ·
     kleines Tablet/großes Handy (≥560px) max. 2 (lesbar) · Desktop/breites Tablet (≥920px) die gewählte
     Anzahl 2..6. Jede Anzahl braucht eine eigene Regel (CSS kann data-cols nicht „rechnen"; Besucher führen
     kein JS aus, CSP verbietet Inline-Styles) → endliche Liste 2..6 (= MAX_COLS, block-registry.js). */
  .cols {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-4) var(--sp-3);
    align-items: start;
  }

  .col {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
    min-width: 0;
    /* Query-Container (rekursive-verschachtelung-container.md N.4): ein .cols IN dieser Spalte misst die
       Spaltenbreite (nicht den Viewport) → es klappt zusammen, wenn die Spalte selbst zu schmal wird. */
    container-type: inline-size;
  }

  /* Box-Blöcke (Karte, Hinweis) in Spalten gleich hoch — Gegenstück zu `.section--grid > .card` (oben),
     aber sie sitzen in `.col` (Flex-Spalte), nicht direkt im Grid, und wurden darum vom Sektions-Stretch
     nicht erfasst (User-Befund). Lösung: die Spalte MIT Box streckt sich auf die Reihenhöhe (align-self
     überschreibt das align-items:start der .cols), die Box füllt die Spalte (flex:1). NUR Spalten mit einer
     Box (:has) — nackte Prosa-/Tabellen-/Bild-Spalten bleiben natürlich hoch (Strecken wäre da unsichtbar).
     Nur Kästen (eigener Hintergrund/Rahmen) profitieren optisch → card + callout, kein Prosa/Bild. */
  .col:has(> .card),
  .col:has(> .callout) {
    align-self: stretch;
  }

  .col > .card,
  .col > .callout {
    flex: 1;
  }

  /* …auch über mehrere Reihen hinweg: kollabiert der Block (z. B. 3-Spalten → 2 auf dem Tablet), rutscht die
     letzte Box allein in eine neue Reihe und hätte ohne dies ihre natürliche Höhe. grid-auto-rows:1fr macht
     ALLE Reihen gleich hoch (= höchste Reihe) → jede Box gleich hoch, egal in welcher Reihe. Nur für
     columns-Blöcke MIT direkten Box-Blöcken (sonst würden Prosa-/Tabellen-Reihen unnötig gestreckt). */
  .cols:has(> .col > .card),
  .cols:has(> .col > .callout) {
    grid-auto-rows: 1fr;
  }

  /* Responsive über CONTAINER-Queries statt Viewport (N.4): ein .cols reagiert auf die Breite SEINES nächsten
     Query-Containers — bei verschachtelten .cols die Slot-Hülle (.col/.tabs-panel/.acc-item), bei Top-Level die
     Block-Sektion (.section--grid). So klappt ein .cols in einem schmalen Slot zusammen, auch wenn das Fenster
     breit ist. Schwellen INTRINSISCH (≈300px Mindestbreite je Spalte) → unabhängig von --content-max.
     GESTUFT: data-cols ist die MAX-Spaltenzahl bei voller Breite und degradiert sauber (… → 3 → 2 → 1), wenn der
     Container schmaler wird, statt hart auf 1 zu springen. So bleiben Karten lesbar — z. B. 3 Text-Karten auf
     einem 10″-Tablet im Hochformat (~768px) werden 2 statt gequetschter 3; je Stufe braucht es ~300px mehr.
     Mechanik: bei jeder Schwelle bekommen ALLE data-cols ≥ k genau k Spalten; höhere/spätere Regel (mehr Breite)
     ist spezifischer/später → gewinnt. data-cols=2 bleibt bei 2 (keine höhere Regel zielt darauf). Schmal = 1. */
  @container (width >= 600px) {
    .cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }

    /* Breitenverhältnis 2 Spalten (ziehbarer Trenner, §10) — gilt, sobald 2 Spalten stehen. Stufenlos ginge
       nur per Inline-Style (CSP verbietet) → endliche Preset-Liste: je fr-Token eine Regel. '1-1' = gleich =
       kein data-ratio (Default repeat(2,1fr)). Deckungsgleich mit COL_RATIOS_2 (block-registry.js) + PHP. */
    .cols[data-cols="2"][data-ratio="1-3"] { grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); }
    .cols[data-cols="2"][data-ratio="1-2"] { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
    .cols[data-cols="2"][data-ratio="2-1"] { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
    .cols[data-cols="2"][data-ratio="3-1"] { grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); }
  }

  @container (width >= 900px) {
    .cols[data-cols="3"],
    .cols[data-cols="4"],
    .cols[data-cols="5"],
    .cols[data-cols="6"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  }

  @container (width >= 1200px) {
    .cols[data-cols="4"],
    .cols[data-cols="5"],
    .cols[data-cols="6"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  }

  @container (width >= 1500px) {
    .cols[data-cols="5"],
    .cols[data-cols="6"] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  }

  @container (width >= 1800px) {
    .cols[data-cols="6"] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  }

  /* Block-Ausrichtung „Zentrieren" (Block-Setting, Renderer → data-align). Zentriert den Block-
     Inhalt (Text + Inline-Bausteine wie .metric-inline/CTA). Generisch an jedem Block-Wrapper. */
  [data-block-id][data-align="center"] { text-align: center; }

  /* Flex-Blöcke (callout = display:flex): text-align allein zentriert das Flex-Item NICHT (es sitzt
     am Zeilenanfang) — das Item muss zusätzlich über justify-content zentriert werden. Spiegelt, was
     .callout--centered fest macht, nun generisch für den „Zentrieren"-Schalter. */
  [data-block-id][data-align="center"].callout { justify-content: center; }

  /* Bild-Umfluss links/rechts (Block-Setting, nur image — vorbild-gegenstuecke.md #6): die Figure floatet
     mit begrenzter Breite, die Folgeblöcke der Sektion umfließen sie (Gutenberg align-left/right). Die
     Sektion enthält den Float via flow-root (Regel oben). Maße aus Tokens, keine Magic-Values. */
  [data-block-id][data-align="float-left"],
  [data-block-id][data-align="float-right"] {
    width: min(42%, 20rem);
    max-width: 100%;
  }

  [data-block-id][data-align="float-left"] {
    float: left;
    margin: 0 var(--sp-4) var(--sp-3) 0;
  }

  [data-block-id][data-align="float-right"] {
    float: right;
    margin: 0 0 var(--sp-3) var(--sp-4);
  }

  /* Mobil ist neben einem Bild kein Platz zum Umfließen → Float aufheben, Bild volle Breite. */
  @media (width < 560px) {
    [data-block-id][data-align="float-left"],
    [data-block-id][data-align="float-right"] {
      float: none;
      width: 100%;
      margin: 0;
    }
  }

  /* Writer-Edit-Chrome (Sektions-Leiste, Leer-Hinweis) spannt im Grid voll — sonst schrumpft es
     auf eine Zelle. Das Einfügen-„+" ist grid-nativ (schwebend am body, Teil 4) → kein Grid-Kind. */
  .section--grid > .page-sec-bar,
  .section--grid > .page-empty-sec { grid-column: 1 / -1; }

  /* ══ Cards ══════════════════════════════════════════════════════════════ */
  .card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: var(--sp-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
    transition: border-color var(--t-fast);
  }
  .card:hover { border-color: var(--border-accent); }

  /* Card-Raster: mobil 1, dann 2, ab Desktop max. 3 nebeneinander (wie main). */
  .card-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-3);

    @media (width >= 560px) {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    @media (width >= 920px) {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
  }

  /* Klickbare Karte (ganze Kachel = Link, z. B. Guides-Hub). */
  .card--link {
    color: inherit;
    text-decoration: none;
  }

  /* „Folgt bald"-Platzhalter: gestrichelt + gedimmt, kein Hover-Akzent. */
  .card--placeholder {
    border-style: dashed;
  }
  .card--placeholder:hover { border-color: var(--border); }

  /* Members-only-Card für Gäste: sichtbar, aber deaktiviert — kein Klick, kein
     Hover-Akzent. Titel + Text stark gedimmt, das lila Badge bleibt voll an. */
  .card--locked {
    cursor: default;
  }
  .card--locked:hover { border-color: var(--border); }

  .card--locked .card-title,
  .card--locked .card-body { color: var(--text-3); }

  /* „Ziel fehlt": das Karten-Ziel löst auf KEINE Seite auf (Tippfehler/gelöscht). Nur der Editor sieht die
     Karte (Gäste → evpw_card_hidden); sie ist nicht klickbar (kein 404), erkennbar am „Ziel fehlt"-Chip.
     Kein Hover-Akzent. */
  .card--missing { cursor: default; }
  .card--missing:hover { border-color: var(--border); }

  /* „Entwurf": Zielseite existiert, ist aber noch nicht live. NUR Editoren sehen die Karte (Gäste bleiben
     via evpw_card_hidden ausgeschlossen); sie bleibt klickbar (Editor darf den Entwurf öffnen), ist aber
     dezent als Entwurf markiert (gestrichelte Kante) + trägt den „Entwurf"-Chip. */
  .card--draft { border-style: dashed; }

  .card--placeholder .card-title,
  .card--placeholder .card-body { color: var(--text-3); }

  /* ══ Hub-Karte als Block (card-Block, NORDSTERN v2 U3) ════════════════════
     Generische Karte für die Hubs (Guides ab S2, Klassen ab S3) — ganze Kachel
     klickbar via Stretch-Link: der Titel-Link deckt per ::after die Karte ab, ein
     optionaler Unterseiten-Link liegt darüber und bleibt eigenständig klickbar
     (kein <a> im <a>). Ersetzt das frühere .cls-card-Muster (in S3 abgelöst). */
  .hub-card { position: relative; }

  .hub-card .card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-2);
  }

  .hub-card-link {
    color: inherit;
    text-decoration: none;
  }

  .hub-card-link::after {
    content: "";
    position: absolute;
    inset: 0;
  }
  .hub-card.card--link:hover .hub-card-link { color: var(--accent-bright); }

  /* Optionale Unterseiten-Links am Kopf — über der Stretch-Fläche (z-index), daher klickbar. */
  .hub-sublinks {
    position: relative;
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--sp-1) var(--sp-2);
  }

  .hub-sublink {
    font-size: var(--fs-sm);
    font-weight: 600;
    text-decoration: underline dashed var(--accent);
    text-underline-offset: 3px;
  }

  /* Meta-Zeilen (z. B. Rüstungstyp + Rolle bei Klassen-Karten) zwischen Kopf und Text. */
  .card-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    margin: var(--sp-1) 0 var(--sp-2);
  }

  .card-meta-line {
    color: var(--text-2);
    font-size: var(--fs-sm);
  }
  .card--locked .card-meta-line { color: var(--text-3); }

  /* ══ Such-Box (geteilt: Guides-Hub, Titel-Tracker, …) ═════════════════════ */
  .search-box {
    margin-bottom: var(--sp-6);
  }

  .search-input {
    width: 100%;
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    color: var(--text-1);
    font: inherit;
    font-size: var(--fs-base);
  }

  .search-input::placeholder { color: var(--text-3); }

  /* Klappbares „Leeren"-X (geteilt: js/shared/search.js wickelt das Input in
     .search-field und hängt .search-clear an). Funktionales X per CSS, kein Emoji. */
  .search-field {
    position: relative;
    display: flex;
  }

  /* Beide Such-Inputs (Hub/Tracker = .search-input, Workspace = .ws-search-input)
     wachsen im Feld und lassen rechts Platz für das X. */
  .search-field > input {
    flex: 1;
    min-width: 0;
    padding-right: calc(var(--sp-4) + 1.5rem);
  }

  /* Chromium/WebKit zeigt an type="search" ein eigenes ✕ — hier weg, das geteilte .search-clear ist
     die eine Wahrheit (sonst Doppel-X). Für type="text"-Felder ein No-op. */
  .search-field > input::-webkit-search-cancel-button {
    display: none;
  }

  .search-clear {
    position: absolute;
    top: 50%;
    right: var(--sp-2);
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 1.7rem;
    height: 1.7rem;
    padding: 0;
    border: none;
    border-radius: var(--radius);
    background: transparent;
    color: var(--text-3);
    font-size: var(--fs-md);
    line-height: 1;
    cursor: pointer;
    transition: color var(--t-fast), background var(--t-fast);
  }

  .search-clear::before {
    content: '✕';
  }

  .search-clear:hover {
    color: var(--text-1);
    background: var(--bg-hover);
  }

  .search-count {
    min-height: 1em;
    margin-top: var(--sp-2);
    color: var(--text-3);
    font-size: var(--fs-sm);
    font-variant-numeric: tabular-nums;
  }

  .search-hint {
    margin-top: var(--sp-1);
    color: var(--text-3);
    font-size: var(--fs-sm);
  }

  .search-hint code {
    padding: 0 4px;
    border-radius: var(--radius);
    background: var(--bg-hover);
    font-size: 0.9em;
  }

  .search-noresults {
    margin-top: var(--sp-2);
    color: var(--text-2);
    font-size: var(--fs-base);
  }

  /* ══ Callouts ═══════════════════════════════════════════════════════════ */
  .callout {
    display: flex;
    gap: var(--sp-3);
    margin: var(--sp-4) 0;
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid transparent;
    border-radius: var(--radius);
    font-size: var(--fs-base);
  }

  .callout-title {
    margin-bottom: 3px;
    font-size: var(--fs-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }

  .callout-text {
    color: var(--text-2);
    line-height: 1.6;
  }

  .callout.tip {
    background: var(--tip-dim);
    border-color: rgb(77 217 192 / 20%);
  }
  .callout.tip .callout-title { color: var(--jade); }

  /* Zentrierter Hinweis (z. B. Guide-Verweis unter den Einsteiger-Steps). */
  .callout--centered {
    justify-content: center;
    text-align: center;
  }

  .callout.warning {
    background: var(--danger-dim);
    border-color: rgb(248 113 113 / 20%);
  }
  .callout.warning .callout-title { color: var(--danger); }

  .callout.info {
    background: rgb(155 125 248 / 8%);
    border-color: rgb(155 125 248 / 20%);
  }

  /* Editor-Hinweis „Seite im Wartungsmodus" (gold/accent, wie das Dashboard-Badge). */
  .callout.maint {
    background: var(--accent-glow);
    border-color: var(--border-accent);
  }
  .callout.maint .callout-title { color: var(--accent-bright); }
  .callout.info .callout-title { color: var(--violet); }

  /* Akzent-Hinweis (U6/H-S4): Gold-Skin — Pendant zur früheren home-`.note-amber`. */
  .callout.amber {
    background: var(--accent-glow);
    border-color: var(--border-accent);
  }
  .callout.amber .callout-title { color: var(--accent-bright); }
  .callout.amber strong { color: var(--accent-bright); }

  /* Neutraler Hervorhebungs-Kasten (U6/H-S4): Pendant zur früheren home-`.highlight-box`. */
  .callout.note {
    background: var(--bg-card);
    border-color: var(--border);
  }
  .callout.note .callout-title { color: var(--text-1); }

  /* ══ Inline-Marks in Guide-Inhalten (Bubble/Toolbar) ═════════════════════════
     code = Monospace-Chip für Skill-/Item-Namen, Werte, Befehle, Pfade · s = durchgestrichen
     (alter Wert nach Patch/Nerf). Gelten in JEDEM Rich-Feld (`.page-md`), nicht pro Modul. */
  .page-md code {
    font-family: var(--font-mono);
    font-size: 0.9em;
    color: var(--accent-bright);
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 1px 6px;
  }

  .page-md :is(s, del, strike) {
    color: var(--text-3);
    text-decoration: line-through;
  }

  /* ══ Aufzählungen in Guide-Inhalten — EINE Darstellung für ALLE ═══════════════
     Listen werden via „/"-Menü in IRGENDEIN Rich-Feld eingefügt (`.page-md`: Fließtext,
     Hinweis-Box, Karte, Akkordeon, Vergleich, Schritte, Timeline). KEINE pro-Modul-
     Sonderregeln mehr (früher .step-body/.rm-card-body je eigen — das war Murks). Der
     globale Reset nullt ul/ol-Padding → Einzug/Marker hier. Vom umgebenden Text absetzen.
       • ul: hängendes Akzent-● (FARBKONZEPT: Gold als Leitfarbe), wie compare ✓/✗.
       • ol: hierarchische Nummer („2.1") über CSS-Counter (auch verschachtelt, via Tab). */
  .page-md :is(ul, ol) {
    margin-block: var(--sp-2);
  }

  .page-md ul {
    list-style: none;
  }

  .page-md ul > li {
    position: relative;
    padding-inline-start: var(--sp-4);
  }

  .page-md ul > li::before {
    content: '●';
    position: absolute;
    inset-inline-start: 0;
    top: 0.2em;
    color: var(--accent);
    font-size: var(--fs-xs);
  }

  .page-md ol {
    padding-inline-start: var(--sp-5);
    counter-reset: page-ol;
  }

  .page-md ol > li {
    counter-increment: page-ol;

    &::marker {
      content: counters(page-ol, ".") ". ";
    }
  }

  /* Liste als Tabellenzell-Inhalt (td ist selbst `.page-md`): keine Außen-Margin —
     die Zelle gibt schon Padding, sonst sitzt die Liste tiefer als reiner Zelltext. */
  td.page-md > :is(ul, ol) {
    margin-block: 0;
  }

  /* ══ Akkordeon (Guide-Block, Typ 'accordion') ════════════════════════════════
     Native <details>/<summary> → ohne JS auf-/zuklappbar, barrierearm. */
  .acc-item {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    /* Query-Container (N.4): ein .cols in dieser Eintrags-Antwort reagiert auf die Eintrags-Breite. */
    container-type: inline-size;

    & + .acc-item {
      margin-top: var(--sp-2);
    }
  }

  .acc-q {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-4);
    font-family: var(--font-head);
    font-weight: 600;
    color: var(--text-1);
    list-style: none;
    cursor: pointer;

    &::-webkit-details-marker {
      display: none;
    }
  }

  /* Aufklapp-Pfeil nur im Lese-Zustand (.acc-q = <summary>). Im Writer-Mode ist .acc-q ein <div>
     ohne Pfeil — dort nutzt ::before stattdessen den Frage-Platzhalter (components-gear.css). */
  summary.acc-q::before {
    content: '▾';
    flex: none;
    margin-top: 0.1em;
    font-size: 0.8em;
    color: var(--accent);
    transition: transform var(--t-fast);
  }

  .acc-item[open] > summary.acc-q::before {
    transform: rotate(180deg);
  }

  /* Eintrags-Antwort = echte Kind-Blöcke direkt im .acc-item (Phase 4.3 Container, statt früherem .acc-a-Feld).
     Horizontaler Einzug auf Fragenhöhe (hinter dem Aufklapp-Pfeil), Abstand unten am letzten Block. Gilt in
     View UND Edit (gleiche Optik; Markup ist in beiden Fällen <details>/<summary>). */
  .acc-item > [data-block-id] {
    padding-inline: calc(var(--sp-4) + var(--sp-3)) var(--sp-4);
  }

  .acc-item > [data-block-id]:last-child {
    padding-bottom: var(--sp-4);
  }

  /* ══ Optionen-Vergleich (Guide-Block 'compare') ═══════════════════════════
     N Optionen nebeneinander (Desktop), gestapelt (schmal). Bewusst KEINE
     main-Farbränder/Karten-Akzente — Gold nur am Titel (Leitfarbe), ✓/✗ als
     einzige bedeutungstragende Signalfarben (Grün/Rot) je Pro-/Contra-Zeile. */
  .compare {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--sp-3);
  }

  .compare-card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    padding: var(--sp-4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
  }

  .compare-title {
    margin: 0;
    font-family: var(--font-head);
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--accent);
  }

  /* Meta/Formel: gedimmte Kennwert-Zeilen ohne Aufzählungszeichen. */
  .compare-meta {
    margin: 0;
    padding: 0;
    list-style: none;
    color: var(--text-2);
    font-size: var(--fs-sm);

    & li {
      padding: 2px 0;
    }
  }

  /* Pro/Contra: ✓/✗-Marker als einzige Signalfarbe, hängender Einzug. */
  .compare-pros,
  .compare-cons {
    margin: 0;
    padding: 0;
    list-style: none;

    & li {
      position: relative;
      padding: 2px 0 2px var(--sp-5);
      line-height: 1.6;
    }

    & li::before {
      position: absolute;
      left: 0;
      font-weight: 700;
    }
  }

  .compare-pros li::before {
    content: '✓';
    color: var(--success);
  }

  .compare-cons li::before {
    content: '✗';
    color: var(--danger);
  }

  /* ══ Tabellen ═══════════════════════════════════════════════════════════ */
  .data-table {
    width: 100%;
    /* table-layout:fixed → Spalten teilen die Breite GLEICHMÄSSIG auf (3 Spalten = je 33 %,
       4 = je 25 % …) statt sich am Inhalt zu orientieren. Beseitigt die „Lücke“, wenn eine
       Spalte dünn/leer ist, und hält DE/EN pixel-identisch. Tabellen mit explizitem <colgroup>
       (Home-Tabellen) honorieren weiterhin ihre col-Prozente. */
    table-layout: fixed;
    /* separate + spacing 0 (statt collapse): nur so greifen border-radius +
       overflow:hidden zuverlässig — bei collapse ragen die th-Hintergründe
       eckig über die gerundete Außenkante (sichtbare Ecken). Zell-Trennlinien
       laufen weiter über border-bottom je Zelle. */
    border-collapse: separate;
    border-spacing: 0;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
    font-size: var(--fs-sm);
  }

  /* ── Vergleichs-Affordances (table als Vergleichstabelle, vorbild-gegenstuecke.md #3) ──────────
     Empfohlene Spalte hervorheben (data-recommended an Kopf+Zellen) + ✓/✗-Zellen farbcodiert. So
     deckt der generische `table`-Block die Comparison-Table mit ab — KEIN eigener Block. */
  .data-table [data-recommended] {
    background: var(--accent-glow);
  }

  .data-table th[data-recommended] {
    color: var(--accent-bright);
  }

  .data-table .ct-yes {
    color: var(--success);
    text-align: center;
    font-weight: 700;
  }

  .data-table .ct-no {
    color: var(--text-3);
    text-align: center;
  }

  /* Manuelle Spaltenbreiten (Guide-Editor: Ziehen rastet auf 5 % → Klasse am <col>). CSP-sauber
     (Klasse statt inline-style); table-layout:fixed ehrt sie, % bleibt responsiv. Ohne colw-Klassen
     → gleiche Breiten (s. o.). Schritte 5–95 %. */
  .data-table col.cw-5 { width: 5%; }
  .data-table col.cw-10 { width: 10%; }
  .data-table col.cw-15 { width: 15%; }
  .data-table col.cw-20 { width: 20%; }
  .data-table col.cw-25 { width: 25%; }
  .data-table col.cw-30 { width: 30%; }
  .data-table col.cw-35 { width: 35%; }
  .data-table col.cw-40 { width: 40%; }
  .data-table col.cw-45 { width: 45%; }
  .data-table col.cw-50 { width: 50%; }
  .data-table col.cw-55 { width: 55%; }
  .data-table col.cw-60 { width: 60%; }
  .data-table col.cw-65 { width: 65%; }
  .data-table col.cw-70 { width: 70%; }
  .data-table col.cw-75 { width: 75%; }
  .data-table col.cw-80 { width: 80%; }
  .data-table col.cw-85 { width: 85%; }
  .data-table col.cw-90 { width: 90%; }
  .data-table col.cw-95 { width: 95%; }

  .data-table th {
    padding: var(--sp-3) var(--sp-4);
    text-align: left;
    border-bottom: 1px solid var(--border);
    background: var(--bg-card-2);
    color: var(--text-3);
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
  }

  .data-table td {
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
  }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tbody tr:hover td { background: var(--bg-hover); }

  /* Linien-Modus (Editor-Option data-lines, sprachneutral): 'frame' = nur Außenrahmen (innere
     Trennlinien weg) · 'none' = nackt (kein Rahmen/Hintergrund, keine Linien). Default (kein Attribut)
     = volles Gitter. Scope auf Datenzellen (.page-i18n) → die Editor-Steuerzellen (it-corner/it-colctrl/
     it-rowctrl) behalten ihre Linien. So lassen sich Tabellen als sauberes Listen-Raster nutzen. */
  .data-table[data-lines="frame"] th.page-i18n,
  .data-table[data-lines="frame"] td.page-i18n,
  .data-table[data-lines="none"] th.page-i18n,
  .data-table[data-lines="none"] td.page-i18n {
    border-bottom: none;
  }

  .data-table[data-lines="none"] {
    border-color: transparent;
    background: transparent;
  }
  .data-table[data-lines="none"] th.page-i18n { background: transparent; }
  .data-table[data-lines="none"] tbody tr:hover td { background: transparent; }

  /* Invite-Tabelle: Link-Spalte schluckt den freien Platz (breites Feld),
     Status/Läuft-ab/Aktion huggen ihren Inhalt → Aktions-Buttons bündig rechts.
     table-layout:auto (statt des globalen fixed) ist hier Pflicht: unter fixed
     beansprucht die erste Spalte width:100% den ganzen Platz, die übrigen Spalten
     kollabieren auf ~0 und die nowrap-Buttons quellen aus ihrer Zelle aufs Feld. */
  .data-table--invites {
    table-layout: auto;
  }

  .data-table--invites th:first-child,
  .data-table--invites td:first-child {
    width: 100%;
  }

  /* Die geschrumpften Spalten (Status/Läuft ab/Aktion) nicht umbrechen lassen —
     auf min-content bräche sonst „Läuft ab" am Leerzeichen um. */
  .data-table--invites th:not(:first-child),
  .data-table--invites td:not(:first-child) {
    white-space: nowrap;
  }

  .data-table--invites td:last-child .acc-inline {
    flex-wrap: nowrap;
    justify-content: flex-end;
  }

  /* Benutzer-Tabelle: feste Spaltenbreiten — Rollen breit, Aktionen schmal. */
  .usr-table {
    table-layout: fixed;
  }

  .usr-table td {
    overflow-wrap: anywhere;
  }

  .usr-table .col-user {
    width: 16%;
  }

  .usr-table .col-status {
    width: 10%;
  }

  .usr-table .col-last {
    width: 18%;
  }

  .usr-table .col-factions {
    width: 20%;
  }

  .usr-table .col-actions {
    width: 36%;
  }

  /* ══ Buttons ════════════════════════════════════════════════════════════ */
  .btn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    block-size: var(--control-h);
    padding-inline: var(--sp-4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card-2);
    color: var(--text-1);
    font-size: var(--fs-sm);
    font-weight: 500;
    transition: border-color var(--t-fast), background var(--t-fast);
  }

  .btn:hover:not(:disabled) {
    border-color: var(--border-accent);
    background: var(--bg-hover);
    color: var(--text-1);
  }

  .btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
  }

  .btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #000;
    font-weight: 600;
  }

  .btn-primary:hover:not(:disabled) {
    background: var(--accent-bright);
    border-color: var(--accent-bright);
    color: #000;
  }

  /* ══ Globale Legende / Abkürzungs-Panel (footer.php + js/shared/legend.js) ══
     Desktop: seitlich mitlaufender Tab (fixed, rechts mittig). Mobile: Floating-
     Button unten rechts. Beide öffnen dasselbe Modal-Panel über dem Content-Bereich. */
  .legend-tab {
    position: fixed;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    z-index: 150;
    padding: var(--sp-3) 6px;
    writing-mode: vertical-rl;
    border: 1px solid var(--border-accent);
    border-right: none;
    border-radius: var(--radius) 0 0 var(--radius);
    background: var(--accent-glow);
    color: var(--accent);
    font-family: var(--font-head);
    font-size: var(--fs-sm);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background var(--t-fast), color var(--t-fast);

    &:hover {
      background: var(--accent);
      color: #000;
    }
  }

  .legend-fab {
    position: fixed;
    right: var(--sp-4);
    bottom: var(--sp-4);
    z-index: 150;
    display: none;
    width: 2.75rem;
    height: 2.75rem;
    border: 1px solid var(--border-accent);
    border-radius: var(--radius);
    background: var(--bg-card);
    color: var(--accent);
    font-family: var(--font-head);
    font-size: var(--fs-md);
    cursor: pointer;
    box-shadow: 0 4px 16px rgb(0 0 0 / 45%);
  }

  .legend-overlay {
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: rgb(0 0 0 / 65%);
    opacity: 0;
    transition: opacity var(--t-fast);

    &.open { opacity: 1; }
  }

  /* Spiegelt die Geometrie der .content-Spalte (layout.css): Insets = Sidebar +
     Content-Padding, max-width = Content-Innenbreite, margin-auto zentriert im
     Restraum — Panel liegt exakt über dem Content-Bereich darunter. */
  .legend-panel {
    position: fixed;
    top: 50%;
    right: var(--sp-10);
    left: calc(var(--sidebar-w) + var(--sp-10));
    z-index: 1001;
    max-width: calc(var(--content-max) - 2 * var(--sp-10));
    max-height: 82vh;
    margin-inline: auto;
    padding: var(--sp-5) var(--sp-6);
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
    box-shadow: 0 16px 60px rgb(0 0 0 / 70%);
    transform: translateY(-48%);
    opacity: 0;
    transition: opacity var(--t-fast), transform var(--t-fast);

    &.open {
      opacity: 1;
      transform: translateY(-50%);
    }
  }

  .legend-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--border-accent);
  }

  .legend-panel-title {
    font-family: var(--font-head);
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--accent);
  }

  /* Schließen-× der Legende = der geteilte .evpw-close (evpw-ui.css); .legend-panel-head ist space-between
     → rutscht von selbst nach rechts, kein eigener Hook nötig. */

  .legend-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-1) var(--sp-6);

    @media (width >= 620px) {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  .legend-item {
    display: flex;
    gap: var(--sp-2);
    padding: var(--sp-1) 0;
    border-bottom: 1px solid var(--border);
    font-size: var(--fs-sm);
    line-height: 1.5;
  }

  .legend-term {
    flex: none;
    min-width: 5.5rem;
    color: var(--accent);
    font-family: var(--font-head);
    font-weight: 600;
  }

  .legend-def { color: var(--text-2); }

  /* Mobile (kein Hover, schmal): seitlicher Tab raus, Floating-Button rein.
     Sidebar ist off-canvas + Content-Padding schrumpft auf --sp-4 (layout.css)
     → Panel-Insets ziehen mit. */
  @media (width < 900px) {
    .legend-tab { display: none; }
    .legend-fab { display: block; }

    .legend-panel {
      right: var(--sp-4);
      left: var(--sp-4);
    }
  }

  /* ══ Tooltip — GLOBALES System (js/shared/tooltip.js, global via bootstrap.js) ══
     „?"/ⓘ-Trigger neben dem Wort (bewusst KEIN unterstrichenes Wort — das wäre nicht
     von gestrichelt-goldenen Links unterscheidbar). Klasse NICHT `.tip` (kollidiert mit
     dem Callout-Modifier `.callout.tip`). Markup via evpw_tip() in config.php. */
  .tip-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    margin-left: var(--sp-1);
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: none;
    color: var(--jade);
    font-size: var(--fs-sm);
    line-height: 1;
    cursor: help;

    &:hover { color: var(--accent-bright); }
  }

  .tip-pop {
    position: fixed;
    z-index: 9999;
    max-width: 260px;
    padding: var(--sp-2) var(--sp-3);
    border: 1px solid var(--violet-dim);
    border-radius: var(--radius-sm);
    background: var(--bg-surface);
    color: var(--text-2);
    font-size: var(--fs-sm);
    line-height: 1.6;
    box-shadow: 0 8px 24px rgb(0 0 0 / 60%);
    pointer-events: none;
  }

  .tip-pop[hidden] { display: none; }

  /* ══ Fußnoten / Anmerkungen (.footnotes — evpw_block_footnotes + js/editor/blocks/footnotes.js) ══════
     Gegenstück zu .legend (vorbild-gegenstuecke.md #2): semantische, abgesetzte Notizen-Sektion nach
     MediaWiki-References-Muster (kleiner, gedämpft, oben abgetrennt) — bewusst anders als die Farb-Tags. */
  .footnotes {
    margin-top: var(--sp-4);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--border);
    color: var(--text-2);
    font-size: var(--fs-sm);
  }

  .footnotes-list {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .footnote {
    display: flex;
    gap: var(--sp-2);
    padding: var(--sp-1) 0;
    position: relative;
  }

  .fn-marker {
    flex-shrink: 0;
    min-width: 1.2em;
    color: var(--accent-bright);
    font-weight: 700;
    line-height: 1.2;
  }

  .fn-note {
    min-width: 0;
  }

  /* In-Text-Fußnoten-Marker (.fn-ref — <span>-Atom vom Sanitizer; Nummer + Verlinkung von shared/footnotes.js).
     Hochstellung per CSS (KEIN <sup>, das würde der Browser beim Tippen fortsetzen). .is-orphan = Note fehlt. */
  .fn-ref {
    font-size: 0.72em;
    vertical-align: super;
    line-height: 0;
    color: var(--accent-bright);
    font-weight: 700;
  }

  .fn-ref-link {
    color: var(--accent-bright);
    font-weight: 700;
    text-decoration: none;
  }

  .fn-ref-link:hover,
  .fn-ref-link:focus-visible {
    text-decoration: underline;
  }

  /* Verwaister Marker (Note gelöscht): rot = sichtbar „kaputte Referenz" (nicht gedämpft-übersehbar),
     kein navigierender Link — aber NIE inhaltsleer (sonst Cursor-Falle), trägt „?" (shared/footnotes.js). */
  .fn-ref.is-orphan {
    color: var(--danger);
    font-weight: 700;
  }

  /* Rücksprung-„↑" in der Note (separates Element, NICHT der editierbare .fn-marker). */
  .fn-back {
    flex-shrink: 0;
    color: var(--accent-bright);
    font-weight: 700;
    text-decoration: none;
  }

  /* Sprung-Hervorhebung (Marke ↔ Note) beim Anspringen über die Anker: sanfter Gold-Hintergrund — bewusst
     KEIN outline, das sähe aus wie der Editor-Fokus (.footnotes.is-editing [contenteditable]:focus). */
  .footnote:target,
  .fn-ref:target {
    background: var(--accent-glow);
    border-radius: var(--radius-sm);
  }

  /* Sprung-Hervorhebung eines Block-Permalinks (#block-<id>, Block-Menü „Link kopieren"): sanfter Gold-
     Hintergrund, wenn Besucher/Editor den Anker anspringen — analog zu Fußnoten. Jeder Nicht-Heading-Block
     trägt id="block-<id>" (page-render.php); h3-Headings landen über ihren eigenen Anker (id="<anchor>"). */
  [data-block-id]:target {
    background: var(--accent-glow);
    border-radius: var(--radius-sm);
  }

  /* Leser-seitiger Überschriften-Anker (shared/heading-anchors.js): „#" hinter verankerten Überschriften
     (Abschnitts-Titel/h3), beim Hover/Fokus sichtbar → Klick kopiert einen teilbaren Deep-Link. Nur die
     öffentliche Ansicht (Editoren nutzen das Block-Menü). Inline-Button, erbt die Schriftgröße; dezent gold. */
  .heading-anchor {
    padding: 0;
    border: 0;
    margin-left: 0.35em;
    background: none;
    color: var(--accent);
    font: inherit;
    font-weight: 700;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s ease;
  }

  .section-title:hover > .heading-anchor,
  .sub-heading:hover > .heading-anchor,
  .heading-anchor:focus-visible {
    opacity: 0.7;
  }

  .heading-anchor:hover {
    opacity: 1;
    text-decoration: underline;
  }

  /* Touch/kein Hover: dezent dauerhaft sichtbar, sonst unerreichbar. */
  @media (hover: none) {
    .heading-anchor {
      opacity: 0.5;
    }
  }

  /* Editor-Affordances (in-place). */
  .footnotes.is-editing [data-ph]:empty::before {
    content: attr(data-ph);
    color: var(--text-3);
    pointer-events: none;
  }

  .footnotes.is-editing [contenteditable]:focus {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
  }

  .footnotes.is-editing .fn-marker {
    min-width: 1.6em;
  }

  .fn-del {
    margin-left: auto;
    padding: 0 var(--sp-1);
    color: var(--text-3);
    background: transparent;
    border: 0;
    cursor: pointer;
    transition: color var(--t-fast);

    &:hover {
      color: var(--danger);
    }
  }

  /* ══ Modul-Fußleiste (.block-tools — die EINE Werkzeugleiste ALLER Editor-Module) ══════════════
     Ersetzt die früher 7 verstreuten Klassen (it-/cta-/card-edit-/fn-/ib-/lg-/rm-routine-tools).
     Erzeugt ausschließlich über js/editor/module-options.js `moduleToolbar()` (Wächter lint:modules).
     Volle Fußzeile in JEDEM Eltern-Layout: `grid-column:1/-1` (Grid-Eltern, z. B. compare),
     `flex-basis:100%` (Flex-Eltern, z. B. legend), sonst block-level = ohnehin volle Breite. */
  .block-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: 1px dashed var(--border);
    grid-column: 1 / -1;
    flex-basis: 100%;
  }

  /* ══ Kennzahl — Inline-Baustein (Editor: writer.js „123"; Server: evpw_guide_build_metric) ══
     Eine hervorgehobene Zahl über kleiner Beschriftung, inline in Rich-Text einfügbar. Mehrere
     nebeneinander ergeben das Kennzahlen-Band (z. B. Startseiten-Hero). Optik = hero-stat. Reine
     Präsentation aus zwei festen Spans; der Sanitizer baut sie beim Speichern atomar neu auf. */
  .metric-inline {
    display: inline-flex;
    flex-direction: column;
    gap: 2px;
    margin: 0 var(--sp-3);
    text-align: center;
    vertical-align: middle;
  }

  .metric-val {
    font-family: var(--font-head);
    font-size: var(--fs-lg);
    font-weight: 700;
    line-height: 1.1;
    color: var(--accent-bright);
  }

  .metric-label {
    font-size: var(--fs-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-3);
  }

  /* ══ Text-Einfärben — Inline-Mark (Editor: writer.js „A"; Server: Sanitizer-Allowlist) ══
     Reine Farbe auf einer Textauswahl, CSP-konform als Klassen-Span (kein Inline-Style).
     Palette bewusst auf die vorhandenen Leit-/Signalfarben begrenzt — siehe FARBKONZEPT.md
     (dekorative Nutzung im Editor ist eine bewusste Ausnahme der „nur bedeutungstragend"-Regel). */
  .mark-accent { color: var(--accent-bright); }
  .mark-jade   { color: var(--jade); }
  .mark-violet { color: var(--violet); }
  .mark-danger { color: var(--danger); }

  /* Fett INNERHALB einer Farb-Mark erbt deren Farbe: sonst überschreibt strong{color} (base) die Mark-Farbe,
     wenn das <strong> in der Farb-Span sitzt → fett gemachter farbiger Text erschiene weiß. Analog zu
     „a strong" (base.css). em braucht das nicht (setzt keine eigene Farbe). */
  .mark-accent strong,
  .mark-jade strong,
  .mark-violet strong,
  .mark-danger strong {
    color: inherit;
  }

  /* ══ Hervorheben — Inline-Textmarker (Editor: Auswahl-Menü „Hervorheben ▸"; Server: Sanitizer-Allowlist) ══
     Farbiger HINTERGRUND hinter der Auswahl (≠ .mark-* Schriftfarbe) — der klassische Leuchtmarker. Palette =
     dieselben Leit-/Signalfarben wie .mark-* (FARBKONZEPT: dekorative Editor-Ausnahme). Halbtransparent, damit
     die Schrift lesbar bleibt; darum keine eigene Schriftfarbe (Text/mark-* schimmert durch). */
  .hl-accent { background: rgb(255 176 48 / 30%); }
  .hl-jade   { background: rgb(77 217 192 / 30%); }
  .hl-violet { background: rgb(155 125 248 / 32%); }
  .hl-danger { background: rgb(248 113 113 / 30%); }

  /* ══ Abstand — Inline-Baustein (Editor: „/"-Menü → Abstand; Server: Sanitizer-Allowlist) ══
     Horizontaler, manuell dosierter Leerraum mitten im Text (ersetzt grobe &nbsp;-Ketten). EINE feste
     Breite (User 2026-06-20, analog zum Block-Spacer); mehr Abstand = mehrere nebeneinander. Breite in
     em → skaliert mit der Schriftgröße. Leeres, atomares inline-block-Element. */
  .spacer {
    display: inline-block;
    width: 1.5em;
  }

  /* ══ Inline-Bild — WYSIWYG-Bild im Fließtext (Editor: „/"-Menü → Bild + inline-image.js;
     Server: page-sanitize.php evpw_page_build_img) ════════════════════════════════════════════
     Bild MITTEN im Textabsatz, frei skalierbar (width-Attribut, px) — Gegenstück zum Bild-BLOCK
     (.page-figure, ganze Spalte). Einheitlich gerahmt wie der Block. Breite via width-Attribut;
     max-width:100% deckelt auf die Spalte, height:auto hält das Verhältnis. */
  .prose-img {
    display: inline-block;
    max-width: 100%;
    height: auto;
    vertical-align: middle;
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }

  /* Umfluss links/rechts (Whitelist-Klassen): Text fließt um das Bild (Word/Confluence/Gutenberg). */
  .prose-img--left {
    float: left;
    margin: var(--sp-1) var(--sp-4) var(--sp-2) 0;
  }

  .prose-img--right {
    float: right;
    margin: var(--sp-1) 0 var(--sp-2) var(--sp-4);
  }

  /* Umflossenes Inline-Bild EINSCHLIESSEN: das Rich-Feld (.page-md) wird zur BFC (display:flow-root),
     sobald es ein floatendes Bild enthält. Sonst „leckt" ein hohes float-Bild aus dem Block heraus —
     der nächste Block (z. B. eine Karte) flösse daneben statt darunter. Greift NUR bei vorhandenem
     Umfluss-Bild (kein Eingriff in normale Felder). */
  .page-md:has(.prose-img--left, .prose-img--right) {
    display: flow-root;
  }

  /* Schmale Viewports: Umfluss aufheben (wie der Bild-Block) — sonst quetscht der Text neben dem Bild. */
  @media (width <= 40rem) {
    .prose-img--left,
    .prose-img--right {
      float: none;
      display: block;
      margin: var(--sp-3) 0;
    }
  }

  /* ══ Bild-Block (.page-figure — evpw_block_image + js/editor/blocks/image.js) ════════════
     Globaler Medien-Block: Bild aus der Bibliothek + optionale Bildunterschrift. Einheitlich
     gerahmt (Design-Lock L2 → wirkt als System, nicht als Fremdkörper). Die Ausrichtung
     kommt vom generischen Block-Grid (data-align) — hier nur das Innenleben. */
  .page-figure {
    /* Box hugt das Bild (etablierter <figure>-Standard: Gutenberg/Notion/HTML5-Figure) → Box-Breite =
       Bildbreite. Ohne fit-content bliebe die Box spaltenbreit und ein untergroßes Bild klebte links,
       und data-align=center könnte es nicht echt zentrieren. max-width:100% = nie breiter als die Spalte. */
    width: fit-content;
    max-width: 100%;
    margin: 0;
  }

  /* Unbefülltes Bild (kein <img>, keine Unterschrift) für Besucher unsichtbar. Im Editor trägt
     der Block Werkzeuge → nie :empty (refreshEditable setupt jeden Block). */
  .page-figure:empty {
    display: none;
  }

  .page-figure-img {
    display: block;
    max-width: 100%;
    height: auto;
    /* Passepartout: Bild sitzt mit Rand im Rahmen (--bg-card füllt den Padding-Streifen, sonst schiene der
       Seiten-Hintergrund durch). box-sizing:border-box → max-width:100% bleibt inkl. Padding gedeckelt. */
    padding: var(--sp-3);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }

  .page-figure-cap {
    margin-top: var(--sp-2);
    color: var(--text-2);
    font-size: var(--fs-sm);
    text-align: center;
  }

  /* Anzeigegröße = das width/height am <img> (px, frei per Eck-Anfasser, geteiltes Bild-System
     tasks/bild-bearbeitung-vereinheitlichen.md). Das frühere %-Stufen-System (data-img-size) ist entfernt. */
  .page-figure[data-align="center"] { margin-inline: auto; }

  /* ── Bild-Editor (in-place, js/editor/blocks/image.js) ────────────────────────
     Werkzeugleiste unter dem Bild: Alt-Text + Ersetzen/Entfernen (im Leerzustand
     Hochladen/Bibliothek). Platzhalter in leeren Edit-Feldern (Alt/Unterschrift). */
  .page-figure.is-editing [data-ph]:empty::before {
    content: attr(data-ph);
    color: var(--text-3);
    pointer-events: none;
  }

  .page-figure.is-editing [contenteditable]:focus {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
  }

  .img-file {
    display: none;
  }

  .img-edit {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: 1px dashed var(--border);
  }

  /* Die Bild-Picker-Knöpfe (Hochladen · Bibliothek · + Ordner) sind evpw-btn--sm (evpwButton() in
     media-picker.js) — kein eigener .img-btn-Look mehr. */

  /* Alt-Text-Feld (zweisprachig, contenteditable). */
  .img-alt-row {
    display: inline-flex;
    flex: 1 1 16rem;
    align-items: center;
    gap: var(--sp-2);
  }

  .img-alt-label {
    color: var(--text-3);
    font-size: var(--fs-xs);
    white-space: nowrap;
  }

  .img-alt {
    flex: 1;
    min-width: 8rem;
    padding: var(--sp-1) var(--sp-2);
    color: var(--text-1);
    font-size: var(--fs-sm);
    background: var(--bg-base);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-sm);
  }

  .img-err {
    flex-basis: 100%;
    margin: 0;
    color: var(--danger);
    font-size: var(--fs-sm);
  }

  /* ══ Video-Block (.page-video — evpw_block_video + js/editor/blocks/video.js) ════════════
     Video Guides als CMS-Block: lokal gecachtes YouTube-Thumbnail (320×180) + Play-Overlay +
     Titel/Beschreibung, verlinkt auf YouTube. Ein Leaf-Block, der in eine columns-Spalte wandert;
     das Raster macht das Spaltenmodul (kein eigener Grid-Container). Optik aus dem main-Vorbild,
     in v1-Tokens gespiegelt. Das Play-Dreieck ist CSS (kein Textzeichen). */
  .page-video {
    width: 100%;
    /* Karten-Obergrenze (main-Größe ~280–350 px): ein einzelner video-Block wird nicht seitenbreit;
       in einer schmaleren columns-Spalte greift die Grenze nicht → die Karte füllt die Spalte. */
    max-width: 22rem;
    margin: 0;
  }

  .page-video-card {
    display: block;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
    text-decoration: none;
    transition:
      border-color var(--t-fast),
      transform var(--t-fast);
  }

  .page-video-card:hover {
    border-color: var(--border-accent);
    transform: translateY(-2px);
  }

  /* Thumb = Grid-Stapel: Bild + Play-Overlay liegen in DERSELBEN Zelle (grid-area 1/1). Robuster als
     position:absolute — die Overlay-Zentrierung hängt nicht an einer aufgelösten Container-Höhe, die in
     einer schmalen Spalte kippen kann (Ursache des „Play sitzt oben links"-Bugs). aspect-ratio hält im
     Leerzustand (ohne Bild) die 16:9-Fläche. */
  .page-video-thumb {
    display: grid;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--bg-surface);
  }

  .page-video-img,
  .page-video-play {
    grid-area: 1 / 1;
  }

  .page-video-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* Play-Overlay: dunkler Scrim, darüber ein goldener Kreis (::before) mit CSS-Play-Dreieck (::after,
     border-Trick — kein Textzeichen). Overlay selbst ist ein Grid mit place-items:center; beide Pseudo-
     Elemente in derselben Zelle → das Dreieck liegt mittig auf dem Kreis, unabhängig von der Thumb-Größe. */
  .page-video-play {
    display: grid;
    place-items: center;
    background: rgb(0 0 0 / 35%);
    transition: background var(--t-fast);
  }

  .page-video-play::before,
  .page-video-play::after {
    content: "";
    grid-area: 1 / 1;
  }

  .page-video-play::before {
    width: 48px;
    height: 48px;
    border-radius: var(--radius-pill);
    background: var(--accent);
    box-shadow: var(--shadow-pop);
    transition:
      transform var(--t-fast),
      background var(--t-fast);
  }

  .page-video-play::after {
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 8px 0 8px 13px;
    border-color: transparent transparent transparent var(--bg-base);
    /* optische Mitte: das Dreieck etwas nach rechts aus der geometrischen Kreismitte */
    margin-left: var(--sp-1);
  }

  .page-video-card:hover .page-video-play {
    background: rgb(0 0 0 / 15%);
  }

  .page-video-card:hover .page-video-play::before {
    transform: scale(1.1);
    background: var(--accent-bright);
  }

  .page-video-info {
    display: block;
    padding: var(--sp-3) var(--sp-4);
  }

  .page-video-title {
    display: block;
    margin-bottom: var(--sp-1);
    color: var(--accent-bright);
    font-family: var(--font-head);
    font-size: var(--fs-sm);
    line-height: 1.4;
  }

  .page-video-desc {
    display: block;
    color: var(--text-2);
    font-size: var(--fs-sm);
    line-height: 1.5;
  }

  /* Leerzustand im Editor (noch keine gültige ID): kein <img> → der Thumb (bg-surface) zeigt nur den
     Scrim + Play-Kreis als klaren Video-Platzhalter (kein Sonderfall nötig; die is-empty-Klasse bleibt
     als Haken für künftige Feinheiten). */

  /* ── Video-Editor (in-place, js/editor/blocks/video.js) ───────────────────────
     Titel/Beschreibung editierbar (Platzhalter in leeren Feldern); ID/Link-Feld in der Fußleiste. */
  .page-video.is-editing [data-ph]:empty::before {
    content: attr(data-ph);
    color: var(--text-3);
    pointer-events: none;
  }

  .page-video.is-editing [contenteditable]:focus {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
  }

  .page-video-id-row {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
  }

  .page-video-id-label {
    color: var(--text-3);
    font-size: var(--fs-sm);
  }

  .page-video-id-input {
    flex: 1;
    min-width: 0;
    padding: var(--sp-1) var(--sp-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-surface);
    color: var(--text-1);
    font-size: var(--fs-sm);
  }

  /* ── Bibliotheks-Picker (Overlay-Modal) ──────────────────────────────────────
     Raster der hochgeladenen Bilder; Klick wählt. Backdrop-Muster wie .calc-modal-bg. */
  .img-lib-overlay {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 1000;
    align-items: flex-start;
    justify-content: center;
    padding: var(--sp-8) var(--sp-4);
    overflow-y: auto;
    background: rgb(0 0 0 / 60%);
  }

  .img-lib-panel {
    width: 100%;
    max-width: var(--content-max); /* Editor-Picker ist Desktop-only → auf Content-Breite (wie die Seite/Dashboard), mehr Thumbnail-Spalten; bricht via width:100% + Overlay-Padding auf schmalen Viewports um */
    margin: auto;
    padding: var(--sp-6);
    background: var(--bg-card);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-lg);
  }

  .img-lib-head {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
    font-family: var(--font-head);
    font-size: var(--fs-md);
    color: var(--accent);
  }

  /* Suchfeld im Picker-Kopf (S1) — nimmt die Mitte ein; Ansicht-Umschalter (margin-left:auto) + × rechts. */
  .img-lib-search {
    flex: 1 1 200px;
    min-width: 8ch;
  }

  /* Picker-Spalten: Ordner-Rail (links) | Raster (Mitte) | Vorschau (rechts) — Vorbild WordPress-„Add Media". */
  .img-lib-cols {
    display: grid;
    grid-template-columns: 160px minmax(0, 1fr) 260px;
    gap: var(--sp-5);
    align-items: start;
  }

  .img-lib-rail {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: 60vh;
    overflow-y: auto;
    padding: var(--sp-2);
    background: var(--bg-base);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
  }

  /* Baum-Zeile = [Aufklapp-Pfeil | Name]. Die Zeile ist das Flex-Element der Rail (flex-shrink:0 → nicht
     stauchen, Rail scrollt). Einrückung je Ebene an der Zeile (Ebene 0/1 ohne Extra-Einzug). */
  .img-lib-rail-row {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    gap: 2px;
  }

  .img-lib-rail-row[data-depth="2"] {
    padding-inline-start: var(--sp-4);
  }

  .img-lib-rail-row[data-depth="3"] {
    padding-inline-start: var(--sp-6);
  }

  .img-lib-rail-row[data-depth="4"] {
    padding-inline-start: var(--sp-8);
  }

  .img-lib-rail-row[data-depth="5"] {
    padding-inline-start: var(--sp-10);
  }

  .img-lib-rail-row[data-depth="6"] {
    padding-inline-start: var(--sp-14);
  }

  .img-lib-rail-caret {
    flex: 0 0 auto;
    width: 1.25rem;
    padding: 0;
    background: transparent;
    border: 0;
    color: var(--text-3);
    font-size: var(--fs-xs);
    line-height: 1;
    text-align: center;
    cursor: pointer;
  }

  .img-lib-rail-caret:hover {
    color: var(--accent);
  }

  .img-lib-rail-caret.is-leaf {
    visibility: hidden;
    cursor: default;
  }

  .img-lib-rail-item {
    overflow: hidden;
    flex: 1 1 auto;
    border: 0;
    border-radius: var(--radius-sm);
    padding: var(--sp-1) var(--sp-2);
    background: transparent;
    color: var(--text-2);
    font: inherit;
    text-align: start;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: pointer;
  }

  .img-lib-rail-item:hover {
    background: var(--bg-hover);
    color: var(--text-1);
  }

  .img-lib-rail-item.is-active {
    background: var(--bg-hover);
    color: var(--accent);
    font-weight: 600;
  }

  /* Fund bei der Suche: Ordner, der einen Treffer enthält — dezenter Gold-Ton (schwächer als „aktiv"). */
  .img-lib-rail-item.is-match {
    background: rgb(232 150 10 / 12%);
    color: var(--accent);
  }

  /* Vorschau-Spalte (rechts): großes Bild + Name/Maße + „Einfügen". Klick auf eine Kachel füllt sie. */
  .img-lib-preview {
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    padding: var(--sp-4);
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
  }

  .img-lib-preview-empty {
    margin: 0;
    padding: var(--sp-6) 0;
    color: var(--text-3);
    font-size: var(--fs-sm);
    text-align: center;
  }

  .img-lib-preview-img {
    text-align: center;

    & img {
      max-width: 100%;
      max-height: 240px;
      border-radius: var(--radius-sm);
    }
  }

  .img-lib-preview-meta {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--sp-1) var(--sp-3);
    margin: 0;
    font-size: var(--fs-sm);

    & dt {
      color: var(--text-3);
    }

    & dd {
      margin: 0;
      color: var(--text-1);
      overflow-wrap: anywhere;
    }
  }

  .img-lib-preview-actions {
    margin-top: var(--sp-1);
  }

  /* Ausgewählte Kachel/Zeile im Raster hervorheben (Gold-Rahmen). */
  .img-lib-item.is-selected,
  .img-lib-flow-item.is-selected,
  .img-lib-row.is-selected {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
  }

  /* Mehrfach-Auswahl (Verwaltung): Checkbox-Overlay auf Kacheln + Auswahl-Markierung. */
  .img-lib-item-wrap {
    position: relative;
  }

  .img-lib-check {
    position: absolute;
    top: var(--sp-1);
    left: var(--sp-1);
    z-index: 1;
    width: 1.15rem;
    height: 1.15rem;
    cursor: pointer;
    accent-color: var(--accent);
  }

  .img-lib-item-wrap.is-checked > .img-lib-item,
  .img-lib-item-wrap.is-checked > .img-lib-flow-item {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
  }

  .img-lib-col-check {
    width: 1.5rem;
  }

  @media (width <= 720px) {
    .img-lib-cols {
      grid-template-columns: 1fr;
    }

    .img-lib-rail {
      flex-flow: row wrap;
      max-height: none;
    }
  }

  /* Schließen-× = der geteilte .evpw-close (evpw-ui.css); .img-lib-close trägt nur die Positionierung
     (rechts neben dem Ansicht-Umschalter, der das margin-left:auto trägt). */
  .img-lib-close {
    margin-left: var(--sp-1);
  }

  /* Verstecktes Datei-Feld des Pickers (Klick kommt über den gestylten Knopf). */
  .img-lib-file {
    display: none;
  }

  /* Breadcrumb-Pfad (Datei-Explorer-Modell): Wurzel › Ordner › Unterordner + Ordner-Aktionen. */
  .img-lib-crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-3);
  }

  /* Pfad-Segment (anklickbar = öffnen; auch Drop-Ziel zum Verschieben). */
  .img-lib-crumb {
    padding: var(--sp-1) var(--sp-2);
    color: var(--text-2);
    font-size: var(--fs-sm);
    background: transparent;
    border: 0;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: color var(--t-fast), background var(--t-fast);

    &:hover {
      color: var(--accent);
      background: var(--accent-glow);
    }

    /* Drop-Ziel beim Verschieben eines Bildes. */
    &.is-drop {
      color: var(--accent);
      background: var(--accent-glow);
    }
  }

  .img-lib-sep {
    color: var(--text-3);
  }

  /* Aktuelles (letztes) Pfad-Segment — der offene Ordner. */
  .img-lib-cur {
    font-family: var(--font-head);
    color: var(--accent);
  }

  /* Umbenennen/Löschen des offenen Ordners + Lösch-Bestätigung (dezent). */
  .img-lib-ftool {
    padding: var(--sp-1) var(--sp-2);
    color: var(--text-3);
    font-size: var(--fs-xs);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    cursor: pointer;

    &:hover {
      color: var(--text-1);
    }
  }

  .img-lib-del:hover {
    color: var(--danger);
    border-color: var(--danger);
  }

  .img-lib-warn {
    color: var(--text-2);
    font-size: var(--fs-xs);
  }

  /* Inline-Eingabefeld für Ordnernamen (Anlegen/Umbenennen — kein Modal, Vorbild Datei-Explorer). */
  .img-lib-folderinp {
    width: 100%;
    padding: var(--sp-1) var(--sp-2);
    color: var(--text-1);
    font-size: var(--fs-sm);
    background: var(--bg-base);
    border: 1px solid var(--accent-bright);
    border-radius: var(--radius-sm);
  }

  /* Toolbar: „+ Ordner" + „Bild hochladen". */
  .img-lib-toolbar {
    display: flex;
    gap: var(--sp-2);
    margin-bottom: var(--sp-4);
  }

  /* Ordner-Kachel im Raster (Klick = öffnen; Bild darauf ziehen = einsortieren). Folder-Optik per ::before. */
  .img-lib-foldertile {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    padding: var(--sp-3);
    color: var(--text-1);
    background: var(--bg-card-2);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--t-fast), border-color var(--t-fast);

    &::before {
      content: "";
      position: absolute;
      top: 10px;
      left: 12px;
      width: 34%;
      height: 7px;
      background: var(--accent);
      border-radius: 2px 2px 0 0;
      opacity: 0.65;
    }

    &:hover {
      background: var(--bg-hover);
    }

    &.is-drop {
      border-color: var(--accent-bright);
      background: var(--accent-glow);
    }
  }

  .img-lib-foldername {
    overflow: hidden;
    font-size: var(--fs-sm);
    text-align: center;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .img-lib-err {
    margin: 0 0 var(--sp-3);
    color: var(--danger);
    font-size: var(--fs-sm);
  }

  /* Upload-Fortschritt (Mehrfach-Upload) — Spinner + „x/n" in einer Box (nicht nackt); teilt Picker + Dashboard. */
  .img-lib-upstatus {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    margin: 0 0 var(--sp-3);
    padding: var(--sp-1) var(--sp-3);
    background: var(--bg-base);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--accent);
    font-size: var(--fs-sm);
  }

  .img-lib-upstatus.is-done {
    color: var(--success);
    border-color: rgb(63 185 80 / 30%);
  }

  .img-lib-spin {
    width: 0.85rem;
    height: 0.85rem;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: img-lib-spin 0.7s linear infinite;
  }

  @keyframes img-lib-spin {
    to {
      transform: rotate(360deg);
    }
  }

  .img-lib-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: var(--sp-3);
  }

  /* Verwaltung: Kacheln NICHT dehnen (fixe Obergrenze) — sonst springen sie größer, sobald die Detail-
     Sidebar aufgeht und das Raster schmaler wird. Rest-Platz bleibt rechts (justify-content: start). */
  .acc-media-lib .img-lib-grid {
    grid-template-columns: repeat(auto-fill, minmax(112px, 132px));
    justify-content: start;
  }

  .img-lib-item {
    padding: 0;
    background: var(--bg-base);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    cursor: grab; /* anklicken = wählen; ziehen = in einen Ordner verschieben */
    transition: border-color var(--t-fast);

    &:hover {
      border-color: var(--border-accent);
    }
  }

  .img-lib-thumb {
    display: block;
    width: 100%;
    aspect-ratio: 1;
    border-radius: var(--radius-sm);
    object-fit: cover;
  }

  .img-lib-empty {
    grid-column: 1 / -1;
    margin: 0;
    padding: var(--sp-6);
    color: var(--text-2);
    text-align: center;
  }

  /* ══ Dashboard „Medien" (account-media.js — manage-Modus, tasks/medien-verwaltungsseite.md) ═══════
     Bettet das geteilte Kern-Modul (img-lib-*) im Panel ein; hier nur die Zusatz-Chrome (Such-/Sortier-
     Leiste + Detail-Panel). Editieren ist Desktop-only: auf Touch (@media hover:none) nur Ansicht. */

  /* Titel-Zeile: „Medien-Verwaltung" links, „Unbenutzte löschen (N)" rechts (stabile, prominente Stelle —
     verschwindet der Button bei 0 Waisen, springt der Titel NICHT, weil er links verankert bleibt). */
  .acc-media-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
  }

  .acc-media-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
  }

  /* Suchfeld = evpw-input; hier nur die Breite (füllt die Werkzeugleiste, weicht Sortier-Selects). */
  .acc-media-search {
    flex: 1 1 220px;
  }

  .acc-media-sort {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    color: var(--text-2);
    font-size: var(--fs-sm);
  }

  /* Filter-Chips (Alle / Ohne Alt / Unbenutzt) statt Dropdown — Mockup §6.2. */
  .acc-media-filterchips {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--sp-1);
  }

  .acc-media-chip {
    padding: var(--sp-1) var(--sp-3);
    color: var(--text-2);
    font-size: var(--fs-sm);
    background: var(--bg-base);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    cursor: pointer;
  }

  .acc-media-chip:hover {
    color: var(--text-1);
  }

  .acc-media-chip.is-active {
    color: var(--on-accent);
    font-weight: 600;
    background: var(--accent);
    border-color: var(--accent);
  }

  /* „Unbenutzte löschen (N)" + Inline-Bestätigung — ganz rechts in der Werkzeugleiste.
     Der Button selbst ist evpw-btn--sm--danger (rote Schrift, roter Fond bei Hover). */
  .acc-media-bulk {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    margin-left: auto;
  }

  /* Mehrfach-Auswahl-Leiste (N ausgewählt · Löschen · Aufheben) im Kopf; steht links neben „Unbenutzte löschen". */
  .acc-media-sel {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    margin-left: auto;
  }

  .acc-media-sel:empty {
    margin-left: 0;
  }

  .acc-media-sel-count {
    color: var(--text-2);
    font-size: var(--fs-sm);
  }

  /* Detail-Panel (Klick auf ein Bild): inline unter dem Raster (kein Modal), große Vorschau + Metadaten. */
  /* Verwaltung: Raster + Detail nebeneinander. Ohne Auswahl eine Spalte (Detail hidden); mit Auswahl
     wird das Detail zur rechten Sidebar (kein Scroll-Sprung nach unten mehr). Editieren ist Desktop-only;
     auf schmalen Breiten fällt das Detail wieder unter das Raster. */
  .acc-media-body {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-4);
    align-items: start;
  }

  .acc-media-body.has-detail {
    grid-template-columns: minmax(0, 1fr) minmax(240px, 340px);
  }

  @media (width <= 720px) {
    .acc-media-body.has-detail {
      grid-template-columns: 1fr;
    }
  }

  .acc-media-detail {
    position: sticky;
    top: var(--sp-4);
    padding: var(--sp-5);
    background: var(--bg-card);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-lg);
  }

  .acc-media-detail-head {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
    font-family: var(--font-head);
    font-size: var(--fs-md);
    color: var(--accent);
  }

  /* Schließen-× = der geteilte .evpw-close (evpw-ui.css); .acc-media-detail-close trägt nur die Positionierung. */
  .acc-media-detail-close {
    margin-left: auto;
  }

  .acc-media-detail-preview {
    margin-bottom: var(--sp-4);
    text-align: center;

    & img {
      max-width: 100%;
      max-height: 320px;
      border-radius: var(--radius-sm);
    }
  }

  .acc-media-detail-meta {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--sp-1) var(--sp-4);
    margin-bottom: var(--sp-4);
    font-size: var(--fs-sm);
  }

  .acc-media-meta-k {
    color: var(--text-2);
  }

  .acc-media-meta-v {
    color: var(--text-1);
    overflow-wrap: break-word;
  }

  .acc-media-field {
    display: block;
    margin-bottom: var(--sp-3);
  }

  .acc-media-field-lbl {
    display: block;
    margin-bottom: var(--sp-1);
    color: var(--text-2);
    font-size: var(--fs-sm);
  }

  /* Feld = evpw-input; hier nur die volle Breite im Detail-Panel. */
  .acc-media-field-inp {
    inline-size: 100%;
  }

  .acc-media-field-hint {
    margin: 0 0 var(--sp-3);
    color: var(--text-3);
    font-size: var(--fs-xs);
  }

  .acc-media-detail-actions {
    display: flex;
    gap: var(--sp-2);
    margin-bottom: var(--sp-4);
  }

  .acc-media-usage {
    margin-bottom: var(--sp-4);
    font-size: var(--fs-sm);
  }

  .acc-media-usage-none {
    margin: var(--sp-1) 0 0;
    color: var(--text-3);
  }

  .acc-media-usage-list {
    margin: var(--sp-1) 0 0;
    padding-left: var(--sp-4);
  }

  .acc-media-detail-delete {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
  }

  .acc-media-del-confirm {
    color: var(--danger);
    font-size: var(--fs-sm);
  }

  .acc-media-detail-msg {
    margin: var(--sp-2) 0 0;
    font-size: var(--fs-sm);
  }

  /* Leer (keine inlineMsg aktiv) → kein Rand; der Anker ist NICHT `hidden` (sonst bliebe die Kind-Meldung
     unsichtbar), sondern kollabiert hier per :empty. */
  .acc-media-detail-msg:empty {
    margin: 0;
  }

  /* Listen-Ansicht (§9.1): derselbe geteilte Grid-Container (img-lib-grid) wird zur vertikalen Liste —
     Ordner als umbrechende Chip-Reihe oben (Variante A, Google-Drive-Weg), die Bilder rendert
     renderMediaTable als Tabelle. GETEILT von Picker (schlanke Spalten) UND Dashboard (Alt-/Verwendung dazu). */
  .img-lib-grid.is-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
  }

  /* Variante A: Ordner als kompakte, umbrechende Kachel-Reihe ÜBER der Bild-Tabelle. */
  .img-lib-folderchips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin-bottom: var(--sp-2);
  }

  .img-lib-folderchip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    color: var(--text-1);
    font: inherit;
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--t-fast);

    /* Ordner-Icon = geteiltes img-lib-flow-ico (wie im Kompakt-Modus), als eigenes Kind-Element VOR dem Namen. */
    &:hover {
      background: var(--bg-hover);
    }
  }

  .img-lib-folderchip-name {
    max-width: 16ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Kompakt-Ansicht (Variante B, Windows „Liste"): Spaltenfluss — Ordner + Bilder als schmale Einträge, die
     per CSS-Spalten erst nach unten, dann in die nächste Spalte fließen. Viele Einträge auf wenig Höhe. */
  .img-lib-grid.is-flow {
    display: block;
    columns: 3 14rem;
    column-gap: var(--sp-4);
  }

  .img-lib-flow-item {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    width: 100%;
    padding: var(--sp-1) var(--sp-2);
    color: var(--text-1);
    font: inherit;
    text-align: left;
    background: transparent;
    border: 0;
    border-radius: var(--radius-sm);
    cursor: pointer;
    break-inside: avoid;
    transition: background var(--t-fast);

    &:hover {
      background: var(--bg-hover);
    }
  }

  .img-lib-flow-thumb {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border-radius: var(--radius-sm);
    object-fit: cover;
  }

  .img-lib-flow-ico {
    flex: 0 0 auto;
    position: relative;
    width: 22px;
    height: 22px;
    background: var(--bg-card-2);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-sm);

    &::before {
      content: "";
      position: absolute;
      top: 6px;
      left: 4px;
      width: 12px;
      height: 4px;
      background: var(--accent);
      border-radius: 2px 2px 0 0;
      opacity: 0.65;
    }
  }

  .img-lib-flow-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .img-lib-grid.is-list .img-lib-foldertile {
    aspect-ratio: auto;
    justify-content: flex-start;
    padding: var(--sp-2) var(--sp-3) var(--sp-2) var(--sp-6);

    &::before {
      width: 18px;
    }
  }

  .img-lib-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--fs-sm);
  }

  .img-lib-table thead th {
    padding: var(--sp-1) var(--sp-2);
    color: var(--text-2);
    font-weight: 600;
    text-align: left;
    border-bottom: 1px solid var(--border);
  }

  .img-lib-row {
    cursor: pointer;
    border-bottom: 1px solid var(--border);
    transition: background var(--t-fast);

    &:hover {
      background: var(--bg-hover);
    }

    & td {
      padding: var(--sp-2);
      color: var(--text-1);
      vertical-align: middle;
    }
  }

  .img-lib-col-thumb {
    width: 52px;
  }

  .img-lib-row-thumb {
    display: block;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-sm);
    object-fit: cover;
  }

  /* Namen-Zelle = Button (Tastatur-Fokus/Enter); der Klick bubblet zum Zeilen-Handler (Detail bzw. Auswahl). */
  .img-lib-row-name {
    padding: 0;
    color: var(--accent);
    font: inherit;
    text-align: left;
    background: transparent;
    border: 0;
    cursor: pointer;

    &:hover {
      text-decoration: underline;
    }
  }

  /* Ordner-Zeilen stehen mit in der Tabelle (erste Zeilen). Mini-Ordner-Marker in der Thumb-Spalte
     (CSS-Deko wie die Ordner-Kachel), übrige Spalten „—". */
  .img-lib-row-foldermark {
    display: block;
    position: relative;
    width: 40px;
    height: 40px;
    background: var(--bg-card-2);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-sm);

    &::before {
      content: "";
      position: absolute;
      top: 8px;
      left: 8px;
      width: 14px;
      height: 5px;
      background: var(--accent);
      border-radius: 2px 2px 0 0;
      opacity: 0.65;
    }
  }

  .img-lib-row-dim {
    color: var(--text-3);
  }

  .img-lib-list-empty {
    padding: var(--sp-6);
    color: var(--text-2);
    text-align: center;
  }

  /* Ansicht-Umschalter im Picker-Kopf (Dashboard nutzt das PHP-Select in seiner Toolbar). */
  /* Ansicht-Umschalter als Icon-Segmente (Raster/Liste/Kompakt) — GETEILT von Picker-Kopf UND Dashboard-
     Toolbar (mediaViewSwitch). Icons sind reine CSS (mask-image je data-view), aktiver Zustand via aria-pressed. */
  .img-lib-viewseg {
    display: inline-flex;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
  }

  .img-lib-head .img-lib-viewseg {
    margin-left: auto;
  }

  .img-lib-view-btn {
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 28px;
    padding: 0;
    background: var(--bg-base);
    border: 0;
    border-right: 1px solid var(--border);
    cursor: pointer;
    transition: background var(--t-fast);

    &:last-child {
      border-right: 0;
    }

    &::before {
      content: "";
      width: 17px;
      height: 17px;
      background-color: var(--text-2);
      mask: var(--vico) center / contain no-repeat;
    }

    &:hover::before {
      background-color: var(--text-1);
    }

    &[aria-pressed="true"] {
      background: var(--bg-hover);
    }

    &[aria-pressed="true"]::before {
      background-color: var(--accent);
    }
  }

  .img-lib-view-btn[data-view="grid"] {
    --vico: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Crect%20x='3'%20y='3'%20width='8'%20height='8'%20rx='1.5'/%3E%3Crect%20x='13'%20y='3'%20width='8'%20height='8'%20rx='1.5'/%3E%3Crect%20x='3'%20y='13'%20width='8'%20height='8'%20rx='1.5'/%3E%3Crect%20x='13'%20y='13'%20width='8'%20height='8'%20rx='1.5'/%3E%3C/svg%3E");
  }

  .img-lib-view-btn[data-view="list"] {
    --vico: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Crect%20x='3'%20y='4'%20width='6'%20height='6'%20rx='1'/%3E%3Crect%20x='11'%20y='5.5'%20width='10'%20height='3'%20rx='1'/%3E%3Crect%20x='3'%20y='14'%20width='6'%20height='6'%20rx='1'/%3E%3Crect%20x='11'%20y='15.5'%20width='10'%20height='3'%20rx='1'/%3E%3C/svg%3E");
  }

  .img-lib-view-btn[data-view="flow"] {
    --vico: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Crect%20x='3'%20y='4'%20width='8'%20height='2.4'%20rx='1'/%3E%3Crect%20x='3'%20y='11'%20width='8'%20height='2.4'%20rx='1'/%3E%3Crect%20x='3'%20y='18'%20width='8'%20height='2.4'%20rx='1'/%3E%3Crect%20x='13'%20y='4'%20width='8'%20height='2.4'%20rx='1'/%3E%3Crect%20x='13'%20y='11'%20width='8'%20height='2.4'%20rx='1'/%3E%3Crect%20x='13'%20y='18'%20width='8'%20height='2.4'%20rx='1'/%3E%3C/svg%3E");
  }

  /* Dashboard-Extra-Spalten der Listen-Ansicht (Alt-Status/Verwendung) — nur im manage-Modus vorhanden. */
  .acc-media-alt-ok {
    color: var(--text-2);
  }

  .acc-media-alt-miss {
    color: var(--danger);
  }

  .acc-media-unused {
    color: var(--text-3);
  }

  @media (hover: none) {
    .acc-media-detail-edit,
    .acc-media-detail-actions,
    .acc-media-detail-delete {
      display: none;
    }
  }

  /* ══ Versionsverlauf-Panel (.rev-* — js/editor/revisions-panel.js, Punkt 2) ═════════════════════
     Overlay wie der Medien-Picker: Seiten-Revisionen-Liste links, read-only Vorschau rechts. */
  .rev-overlay {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 1000;
    align-items: flex-start;
    justify-content: center;
    padding: var(--sp-3);
    overflow-y: auto;
    background: rgb(0 0 0 / 60%);
  }

  /* Nimmt fast die ganze sichtbare Fläche ein (Editor = Desktop-only): so breit wie möglich, damit der
     Vergleich zwei Versionen samt Spalten-Layout nebeneinander zeigt, ohne dass die columns-Module
     (Container-Query ab ~600px Zellenbreite) fälschlich stapeln. */
  .rev-panel {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 98vw;
    max-height: 96vh;
    margin: auto;
    padding: var(--sp-5);
    background: var(--bg-card);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-lg);
  }

  .rev-head {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
    font-family: var(--font-head);
    font-size: var(--fs-md);
    color: var(--accent);
  }

  /* Schließen-× = der geteilte .evpw-close (evpw-ui.css); .rev-close trägt nur noch die Positionierung
     (rechts in der rev-head, die kein space-between hat). */
  .rev-close {
    margin-left: auto;
  }

  .rev-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin-bottom: var(--sp-4);
  }

  /* Die Revisions-Buttons sind evpw-btn--sm (evpwButton() in revisions-panel.js) — kein eigener .rev-btn-
     Look mehr. Hook-Overrides (Lösch-×-Glyph, Vergleichen-Hinweis) stehen in utilities.css (@layer utilities
     schlägt @layer evpw). Der Schließen-× nutzt den geteilten .evpw-close (unten nur Positionierung). */

  .rev-cinput {
    flex: 1 1 16rem;
    padding: var(--sp-1) var(--sp-2);
    color: var(--text-1);
    background: var(--bg-card-2);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-sm);
  }

  /* Liste (links) + Vorschau (rechts) nebeneinander; beide scrollen eigenständig (Editor = Desktop). */
  .rev-body {
    display: flex;
    gap: var(--sp-4);
    min-height: 0;
    overflow: hidden;
  }

  /* Feste Breite, großzügig genug, dass die drei Eintrags-Buttons (Vorschau · Wiederherstellen · ×)
     in EINER Zeile bleiben — kein browser-abhängiger Umbruch/Überlauf (war der Vivaldi-Bug). */
  .rev-list {
    display: flex;
    flex: 0 0 21rem;
    flex-direction: column;
    gap: var(--sp-2);
    overflow-y: auto;
  }

  .rev-item {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    padding: var(--sp-2) var(--sp-3);
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
  }

  .rev-meta {
    display: flex;
    justify-content: space-between;
    gap: var(--sp-2);
    font-size: var(--fs-xs);
    color: var(--text-2);
  }

  .rev-author {
    color: var(--text-3);
  }

  .rev-comment {
    font-size: var(--fs-sm);
    color: var(--text-1);
  }

  .rev-btns {
    display: flex;
    gap: var(--sp-2);
    margin-top: var(--sp-1);
  }

  .rev-preview {
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--sp-4);
    overflow-y: auto;
    background: var(--bg-card-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
  }

  /* Gerendertes Snapshot-Dokument: auf die echte Inhaltsbreite begrenzt + zentriert → das Spalten-Layout
     (Container-Query an der .section--grid) bricht 1:1 wie auf der Live-Seite um, statt im Panel zu stapeln. */
  .rev-preview-doc {
    width: 100%;
    max-width: var(--content-max);
    margin-inline: auto;
  }

  .rev-empty {
    margin: 0;
    padding: var(--sp-6);
    color: var(--text-2);
    text-align: center;
  }

  /* GitHub-Split: zeilen-ausgerichtetes Grid. Kopf (Zeit/Autor je Seite) + Zeilen; jede Op = zwei
     Grid-Zellen (links alt | rechts neu). Unveränderte Blöcke stehen auf DERSELBEN Zeile; eine Seiten-
     Lücke streckt sich mit (align-items:stretch) → hinzugefügt/entfernt hinterlässt einen leeren Platz. */
  .rev-diff-head,
  .rev-diff-aligned {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-3);
  }

  .rev-diff-head {
    margin-bottom: var(--sp-3);
  }

  .rev-diff-aligned {
    align-items: stretch;
  }

  .rev-compare-cap {
    display: flex;
    justify-content: space-between;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    font-size: var(--fs-xs);
    color: var(--text-2);
    background: var(--bg-card);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-sm);
  }

  /* Eine Split-Zelle = reiner Layout-Container. KEIN eigener Kasten/Radius — das Modul behält seine
     natürliche Rundung (Karte = --radius-lg). KEIN +/−-Gutter (fraß Breite → Text-Umbruch); den Zustand
     tragen Flächen-Farbe + Label. min-width:0 → breite Blöcke brechen um statt zu überlaufen. */
  .rev-diff-cell {
    min-width: 0;
    padding: var(--sp-2);
  }

  /* Wrapper-Section + Block sitzen im Diff ISOLIERT in einer Zelle → ihre normalen Außenabstände
     (Section-Abstand/-Linie, Block-margin) machten die Zelle höher als das Modul, sodass die Lücke größer
     als das Modul wirkte (User-Befund). Hier neutralisiert → Zelle umschließt das Modul exakt, Lücke =
     Modulgröße. Die .section--grid-Hülle bleibt (Container-Query fürs Spalten-Layout). */
  .rev-diff-cell > .section {
    margin: 0;
    padding: 0;
    border: 0;
  }

  .rev-diff-cell > .section > [data-block-id] {
    margin: 0;
  }

  /* Lücke: die Zelle behält das normale Polster (wie eine Modul-Zelle), die INNERE Füllung spiegelt das
     FEHLENDE Modul der Gegenseite — gleiche Einrückung, gleiche Höhe (flex:1 = Zellhöhe = Modulhöhe der
     Gegenseite), gleiche Rundung; nur leer/schraffiert, KEINE (weiße) Umrandung. Nicht die ganze Zelle. */
  .rev-diff-cell.is-gap {
    display: flex;
  }

  .rev-diff-gap-fill {
    flex: 1;
    background-color: rgb(255 255 255 / 3%);
    background-image: repeating-linear-gradient(
      135deg,
      transparent,
      transparent 7px,
      rgb(255 255 255 / 7%) 7px,
      rgb(255 255 255 / 7%) 9px
    );
    border-radius: var(--radius-lg);
  }

  /* Spalten-Module IM Vergleich IMMER in voller Anzahl nebeneinander: eine Vergleichs-Zelle ist nur ~halb
     so breit, sodass die Container-Query-Schwellen (600/900/1200/1500px) sonst stapeln würden. Hier bewusst
     überschrieben (höhere Spezifität als die @container-Regeln) → z. B. 3 Karten bleiben auch bei zwei
     Ansichten nebeneinander, nur schmaler (minmax(0,1fr) verhindert Überlauf). Ratios für 2 Spalten bleiben. */
  .rev-diff-aligned .cols[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rev-diff-aligned .cols[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .rev-diff-aligned .cols[data-cols="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .rev-diff-aligned .cols[data-cols="5"] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .rev-diff-aligned .cols[data-cols="6"] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .rev-diff-aligned .cols[data-cols="2"][data-ratio="1-3"] { grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); }
  .rev-diff-aligned .cols[data-cols="2"][data-ratio="1-2"] { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
  .rev-diff-aligned .cols[data-cols="2"][data-ratio="2-1"] { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .rev-diff-aligned .cols[data-cols="2"][data-ratio="3-1"] { grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); }

  /* Vergleichs-Checkbox links in der Zeilen-Kopfzeile. */
  .rev-pick {
    margin-right: var(--sp-1);
    cursor: pointer;
  }

  /* Linke Verlaufs-Liste weggeklappt (Umschalter im Kopf) → Vorschau/Vergleich bekommt die volle
     Panel-Breite (zwei Versionen mit je bis zu drei Spalten-Karten passen erst so nebeneinander). */
  .rev-body.is-list-collapsed .rev-list {
    display: none;
  }

  /* „Vergleichen" hebt den Umschalter hervor (Gold + Pulsen) — Regel .rev-list-toggle.is-hint steht in
     utilities.css (muss @layer evpw schlagen); die Animation ist hier definiert (Keyframe-Name global). */
  @keyframes rev-hint-pulse {
    0%,
    100% {
      box-shadow: 0 0 0 0 var(--accent-glow);
    }

    50% {
      box-shadow: 0 0 0 4px var(--accent-glow);
    }
  }

  /* Legende in der (nicht scrollenden) Aktionsleiste, rechts neben den Buttons (margin-left:auto). Der
     Farb-Chip = ::before-Quadrat. Bleibt so beim Scrollen im Vergleich sichtbar. */
  .rev-diff-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-4);
    align-items: center;
    margin-left: auto;
    font-size: var(--fs-xs);
    color: var(--text-2);
  }

  .rev-diff-key {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);

    &::before {
      display: inline-block;
      width: 0.9em;
      height: 0.9em;
      border-radius: var(--radius-sm);
      content: "";
    }

    &.is-diff-added::before {
      background: var(--success);
    }

    &.is-diff-changed::before {
      background: var(--accent);
    }

    &.is-diff-removed::before {
      background: var(--danger);
    }
  }

  /* Diff-Markierung auf BLOCK-Ebene (hinzugefügt/entfernt/geändert): KEINE Umrandung, nur leichte Flächen-
     Färbung der Region + ein LABEL (Ecken-Marke). KEIN eigener border-radius → das Modul behält SEINE
     Rundung (Karte = --radius-lg), die Farbfläche folgt ihr. position:relative trägt das Label (::before). */
  .rev-diff-aligned [data-block-id].is-diff-added,
  .rev-diff-aligned [data-block-id].is-diff-removed,
  .rev-diff-aligned [data-block-id].is-diff-changed {
    position: relative;
  }

  .rev-diff-aligned [data-block-id].is-diff-added {
    background: var(--success-dim);
  }

  .rev-diff-aligned [data-block-id].is-diff-removed {
    background: var(--danger-dim);
  }

  .rev-diff-aligned [data-block-id].is-diff-changed {
    background: var(--accent-glow);
  }

  /* Label (Ecken-Marke): KLARTEXT, was mit dem Block ist („+ neu“ / „− entfernt“ / „geändert: Bild,
     Breite“). Farbige Pille oben rechts, überlappt die obere Kante; Farbe = Zustand. */
  .rev-diff-aligned [data-diff-label]::before {
    content: attr(data-diff-label);
    position: absolute;
    top: 0;
    right: 0;
    z-index: 1;
    padding: 0.05rem 0.45rem;
    color: var(--bg-base);
    font-family: var(--font-body);
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
    background: var(--text-2);
    border-radius: var(--radius);
    transform: translateY(-55%);
    pointer-events: none;
  }

  .rev-diff-aligned .is-diff-added::before {
    background: var(--success);
  }

  .rev-diff-aligned .is-diff-removed::before {
    background: var(--danger);
  }

  .rev-diff-aligned .is-diff-changed::before {
    background: var(--accent);
  }

  /* Zwei-Ton, Stufe 1 (schwach): die geänderte Zeile/Zelle (td/li/p/…), NICHT der ganze Block — so bleibt
     der Ton auch bei Tabelle/Callout sichtbar. Schnelles Scannen „wo“; das Wort (Stufe 2) sagt „was“. */
  .rev-diff-aligned .is-diff-line-add {
    background: rgb(63 185 80 / 12%);
  }

  .rev-diff-aligned .is-diff-line-del {
    background: rgb(248 113 113 / 12%);
  }

  /* Zwei-Ton, Stufe 2 (kräftig): geändertes Wort. <ins> = neu (rechts), <del> = entfernt (links).
     Box-Ton + 1px-Ring + (bei del) Durchstreichen → auch auf farbigem Inhalt eindeutig als Diff-Marke. */
  .rev-diff-aligned .rev-diff-ins,
  .rev-diff-aligned .rev-diff-del {
    border-radius: 2px;
    padding: 0 0.1em;
    color: inherit;
  }

  .rev-diff-aligned .rev-diff-ins {
    background: rgb(63 185 80 / 34%);
    text-decoration: none;
  }

  .rev-diff-aligned .rev-diff-del {
    background: rgb(248 113 113 / 32%);
    text-decoration: line-through;
    text-decoration-color: var(--danger);
    text-decoration-thickness: 2px;
  }

  /* ══ Infobox (.infobox — evpw_block_infobox + js/editor/blocks/infobox.js) ══════════════════════
     MediaWiki/Fandom-Eckdaten-Kasten: Titelleiste + optionales Bild + Key/Value-Zeilen (<dl>). Die
     Ausrichtung kommt vom generischen Block-Grid (data-align) — schmal wird die Box nur in einer columns-Spalte. */
  .infobox {
    /* Prinzip pwpedia/Fandom Portable Infobox: die BOX bestimmt die Breite, Bild + Text richten sich nach ihr
       (nicht die Box nach dem Bild). ABER die Breite kommt aus UNSEREM Layout — die Box füllt ihre Grid-Zelle/
       Spalte wie jedes andere Modul (Breite via columns-Spalte + ziehbarer Trenner), KEIN fester
       Deckel → in derselben Spalte gleich breit wie Nachbarmodule, folgt dem Trenner. Bild = 100 % der Box. */
    width: 100%;
    max-width: 100%;
    margin: 0;
    overflow: hidden;
    background: var(--bg-card);
    border: 1px solid var(--border-accent);
    border-radius: var(--radius-lg);
    font-size: var(--fs-sm);
  }

  /* Titelleiste: optionales kleines Icon + Titel, zusammen zentriert (die Leisten-Optik — Padding/
     Hintergrund/Trenner — lebt am Wrapper, damit Icon und Titel EINE Leiste bilden). */
  .ib-head {
    display: flex;
    gap: var(--sp-2);
    align-items: center;
    justify-content: center;
    padding: var(--sp-3) var(--sp-4);
    background: var(--bg-card-2);
    border-bottom: 1px solid var(--border);
  }

  .ib-title {
    font-family: var(--font-head);
    font-size: var(--fs-md);
    font-weight: 700;
    color: var(--accent-bright);
    text-align: center;
    /* Optischer Ausgleich (Cinzel = Versalienschrift): Kleinschreibung wird als Kapitälchen auf DERSELBEN
       Grundlinie wie die Versalien gerendert, nur niedriger. Dadurch sitzt der Wortkörper (die Kapitälchen)
       ~0.05em über der Leisten-Mitte (gemessen .devscripts/ib-gaps.mjs: oben 20.17 / unten 21.81px). translateY
       schiebt die Kapitälchen mittig; ein evtl. großes Initial ragt font-bedingt weiter hoch (nicht behebbar
       durch Verschieben — echte Lösung wäre eine Titelschrift MIT Kleinbuchstaben). Font-relativ in em. */
    transform: translateY(0.05em);
  }

  /* Icon auf Zeilenhöhe deckeln (1.5 × Titel-Schriftgröße ≈ die Zeilenhöhe der Leiste) — die Leiste
     bestimmt das Icon, keine freie Skalierung (imgCaps 'ibicon': nicht scalable). */
  .ib-icon {
    width: auto;
    height: calc(var(--fs-md) * 1.5);
  }

  /* Leerzustand im Bearbeiten-Modus: kompakter „+"-Slot vor dem Titel (öffnet den Bibliotheks-Picker). */
  .ib-icon-add {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: calc(var(--fs-md) * 1.5);
    height: calc(var(--fs-md) * 1.5);
    padding: 0;
    color: var(--text-3);
    cursor: pointer;
    background: none;
    border: 1px dashed var(--border-accent);
    border-radius: var(--radius-sm);

    &:hover {
      color: var(--accent-bright);
      border-color: var(--accent-bright);
    }
  }

  .ib-img {
    display: block;
    /* Bild rundum eingerückt (Padding spiegelt die Titelleiste --sp-3/--sp-4) statt full-bleed: die seitliche
       Kante fluchtet mit Titel + Key/Value-Zeilen, das Bild sitzt als Teil der Karte statt randlos an den Box-
       Rändern. box-sizing:border-box → width:100% bleibt die Box-Breite, der Padding-Rand zeigt --bg-card. So
       sind alle Infobox-Bilder gleich breit; freie Bild-Skalierung entfällt bewusst (Eck-Anfasser/„Breite %" aus). */
    width: 100%;
    height: auto;
    padding: var(--sp-3) var(--sp-4);
  }

  .ib-rows {
    margin: 0;
    padding: 0;
  }

  .ib-row {
    display: grid;
    grid-template-columns: 40% 1fr;
    gap: var(--sp-2);
    align-items: baseline;
    padding: var(--sp-2) var(--sp-4);
    border-bottom: 1px solid var(--border);
  }

  .ib-row:last-child {
    border-bottom: 0;
  }

  /* Bearbeiten-Modus: die Zeile bekommt zwei Zusatz-Elemente — Drag-Griff (links) + ×-Löschen (rechts). Ohne
     eigene Spalten fielen sie als Extra-Grid-Kinder auf eine zweite Zeile → vier Spalten: Griff · Key · Value · ×. */
  .infobox.is-editing .ib-row {
    grid-template-columns: auto 40% 1fr auto;
  }

  .ib-drag {
    align-self: center;
    color: var(--text-3);
    cursor: grab;
    user-select: none;

    &:active {
      cursor: grabbing;
    }
  }

  .ib-row.ib-dragging {
    opacity: 0.5;
  }

  .ib-key {
    margin: 0;
    color: var(--text-2);
    font-weight: 600;
  }

  .ib-val {
    margin: 0;
    color: var(--text-1);
  }

  /* ── Infobox-Editor (in-place) ──────────────────────────────────────────────── */
  .infobox.is-editing [data-ph]:empty::before {
    content: attr(data-ph);
    color: var(--text-3);
    pointer-events: none;
  }

  .infobox.is-editing [contenteditable]:focus {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
  }

  .ib-file {
    display: none;
  }

  /* Bild-Aktionsleiste (eigene Leiste, KEINE Modul-Fußleiste → bleibt ib-img-tools). */
  .ib-img-tools {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-4);
  }

  /* Infobox = umrandeter Kasten: die Fußleiste folgt der Zeilen-Einrückung (sp-4), kein Außenabstand. */
  .infobox .block-tools {
    margin-top: 0;
    padding: var(--sp-2) var(--sp-4);
  }

  .ib-del {
    padding: 0 var(--sp-1);
    color: var(--text-3);
    background: transparent;
    border: 0;
    cursor: pointer;
    transition: color var(--t-fast);

    &:hover {
      color: var(--danger);
    }
  }

  /* ══ Tabs / Reiter (.tabs — evpw_block_tabs + js/editor/blocks/tabs.js + js/shared/tabs.js) ═══════════
     Vorbild Docusaurus/GitBook/Confluence-Tabs (vorbild-gegenstuecke.md #5): Reiter-Leiste oben + ein
     Panel je Reiter darunter; der aktive Reiter trägt die Leitfarbe (Gold, FARBKONZEPT), der Rest ist
     gedämpft. Umschaltung clientseitig (js/shared/tabs.js) — inaktive Panels sind `hidden`. */
  .tabs-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-1);
    border-bottom: 1px solid var(--border);
  }

  .tabs-tab {
    padding: var(--sp-2) var(--sp-4);
    margin-bottom: -1px;
    color: var(--text-2);
    font-family: var(--font-head);
    font-size: var(--fs-sm);
    font-weight: 600;
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition:
      color var(--t-fast),
      border-color var(--t-fast);

    &:hover {
      color: var(--text-1);
    }

    &.is-active {
      color: var(--accent-bright);
      border-bottom-color: var(--accent-bright);
    }
  }

  .tabs-panel {
    padding-top: var(--sp-3);
    /* Query-Container (N.4): ein .cols in diesem Reiter-Panel reagiert auf die Panel-Breite, nicht den Viewport. */
    container-type: inline-size;
  }

  /* ── Tabs-Editor (in-place): flache Reiter (alle offen) ──────────────────────── */
  .tabs.is-editing .tabs-edit-item + .tabs-edit-item {
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: 1px dashed var(--border);
  }

  .tabs-edit-head {
    display: flex;
    align-items: baseline;
    gap: var(--sp-2);
  }

  .tabs-label {
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--font-head);
    font-weight: 600;
    color: var(--accent-bright);
  }

  .tabs.is-editing [data-ph]:empty::before {
    content: attr(data-ph);
    color: var(--text-3);
    pointer-events: none;
  }

  .tabs.is-editing [contenteditable]:focus {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
  }

  .tabs-del {
    flex-shrink: 0;
    padding: 0 var(--sp-1);
    color: var(--text-3);
    background: transparent;
    border: 0;
    cursor: pointer;
    transition: color var(--t-fast);

    &:hover {
      color: var(--danger);
    }
  }
}

