/* =====================================================================
   ESRS-Viewer -- Präsentationsschicht (viewer.css)
   Referenz: mockups/ui-final-2-versionen-2026-07-17.html, Version 1 "Arbeitsbereich"
   Tokens: 1:1 übernommen aus design-system-viewer/public/brand.css (v4.3;
   checked against the live brand.css on 04.10.2026: all 40 shared tokens equal)
   ============================================================================ */

/* ───── 1. Tokens -- übernommen aus brand.css v4.3 (nur die benötigten) ──── */
:root {
  --jr-primary:        #27C13F;
  --jr-primary-dark:   #1FA033;
  --jr-primary-text:   #187A28;
  --jr-primary-light:  #2DD348;
  --jr-cta-gradient:   linear-gradient(145deg, #0A7A24 0%, #0A7020 55%, #09641C 100%);
  --jr-cta-text:       #FFFFFF;
  --jr-primary-shadow: 0 4px 14px rgba(39, 193, 63, 0.35);
  --jr-primary-shadow-hover: 0 6px 20px rgba(39, 193, 63, 0.45);

  --jr-finance: #2563EB;
  --status-query-open: #7C3AED; /* brand.css; was the --jr-tech pillar alias (design-check B8) */

  --background:       #FAFAF9;
  --foreground:       #1C1917;
  --bg-elevated:      #FFFFFF;
  --muted:            #F5F5F4;
  --muted-foreground: #57534E;
  --border:           #E7E5E4;

  --radius-sm:   6px;
  --radius-md:  10px;
  --radius-lg:  14px;
  --radius-xl:  20px;
  --radius-pill: 100px;

  --jr-duration-fast: 150ms;
  --jr-duration-normal:   200ms; /* Design-System duration.normal: Overlay raus */
  --jr-duration-moderate: 300ms; /* Design-System duration.moderate: Panels, Overlay rein */
  --jr-ease-spring:   cubic-bezier(0.22, 1.05, 0.36, 1);
  --jr-ease-out:      cubic-bezier(0.16, 1, 0.3, 1);
  --jr-ease-in:       cubic-bezier(0.55, 0, 1, 0.45); /* Design-System easing.in: Austritt */
  --shadow-xs:        0 1px 2px rgba(0, 0, 0, 0.04);  /* Design-System shadow.elevation.xs */
  /* 05.10.2026 (design-check F7): the elevations the viewer draws, as
     tokens.json shadow.elevation defines them: cards sm, menus and
     popovers md, the drawers lg (drawn sideways where they stand). */
  --shadow-sm:        0 2px 8px rgba(0, 0, 0, 0.06);  /* Design-System shadow.elevation.sm */
  --shadow-md:        0 4px 16px rgba(0, 0, 0, 0.08); /* Design-System shadow.elevation.md */
  --shadow-lg:        0 8px 32px rgba(0, 0, 0, 0.12); /* Design-System shadow.elevation.lg */

  --status-rework:    #EF4444;

  /* jR footer #1C1917 (design system; council decision 6c, 03.10.2026; was the
     Cupel graphite #353537). Measured on it: links #FFFFFF 17.49:1, text .7
     9.02:1, muted .5 5.23:1, focus ring #1FA033 5.11:1, link hover #2DD348 8.76:1.
     --footer-bg (the old name) is the dark surface of the tooltips and
     popovers; council 2, decision 2 (A6, 04.10.2026) moved it from #353537 to
     the same #1C1917 (white on it 17.49:1, white .7 9.02:1). */
  --site-footer-bg:    #1C1917;
  --footer-bg:         #1C1917;
  --footer-text:       rgba(255, 255, 255, 0.7);
  --footer-border:     rgba(255, 255, 255, 0.1);

  --feedback-info:           #2563EB;
  --feedback-success:        #187A28;
  --feedback-warning:        #B45309;
  --feedback-warning-strong: #ED8B00;
  --feedback-error:          #B91C1C;

  /* ── Komponenten-eigene Aliase (nur Umbenennung bestehender Tokens, keine
     neuen Farben). Diff-Status-Badges im Vergleichsmodus: die mockup-Hex-Werte
     #ED8B00/#27C13F/#EF4444/#7C3AED entsprechen exakt vier brand.css-Tokens.
     AP6 (WCAG 1.4.11, non-text contrast >=3:1): amended/new zeigten als
     Icon-Farbe auf Weiss (Status-Chips) nur 2,53:1 bzw. 2,39:1 -- auf
     --feedback-warning (#B45309, 5,02:1) und --jr-primary-text (#187A28,
     5,45:1, identisch zu --feedback-success) umgehaengt. Geprueft: beide
     Tokens werden sonst nur von zwei toten CSS-Regeln (.diff-badge--*,
     .status-badge.*, ohne jedes Markup-Vorkommen -- s. Grep) sowie als
     Akzent-Border von .para.p-amended/.p-new verwendet; dort ist die neue,
     dunklere Farbe eine rein dekorative Randlinie, keine Verschlechterung.
     Die Status-Badges nutzten eigene --vw-tint-*-Tokens (>5:1); sie gingen
     am 06.10.2026 mit der Vergleichsansicht. */
  --vw-status-amended: var(--feedback-warning); /* #B45309, war --feedback-warning-strong #ED8B00 */
  --vw-status-new:     var(--jr-primary-text);  /* #187A28, war --jr-primary #27C13F */
  --vw-status-deleted: var(--status-rework);            /* #EF4444 */
  --vw-status-moved:   var(--status-query-open);        /* #7C3AED */

  /* ── Tints with their text and border colours. Council 2, decision 2 (A6,
     04.10.2026): the design system's tint pattern, brand green or warning
     amber at 6-10 % for surfaces and 30 % for borders, counts as mapped. It
     is written opaque, as color-mix on white: on white that is the DS rgba
     value pixel for pixel, and a tint inside a tint renders as before.
     Everything else is registered by function in the design system's
     tokens.json group "esrs-viewer" (--ev-*). Moved: brand 8 % #EEFAF0 (was
     #EFF9F1), brand 30 % #BEECC5 (was #BFE8C7), warning 6 % #FEF8F0 (was
     #FFF7EC), warning 30 % #FADCB2 (was #F5DDB8, borders only), the rims
     of green chips and notes brand 30 % #BEECC5 (were #CFEFD6 and #D4EFD9;
     registered first as an app colour "select-fill", but they only ever
     draw 1px rims, so the pattern's border tint applies), amber mark 15 %
     #FCEED9 (was #FBEEDA), warning text #B45309 (was #9A6A00 at 4.46:1 on
     its fill, now 4.76:1). Brand 10 % is #E9F9EC exactly. */
  --ev-mark-fill-amber: color-mix(in srgb, #ED8B00 15%, #FFFFFF); /* #FCEED9 */
  --ev-mark-text-amber: #8A5200; /* 5.59:1 on amber 15 %, 6.05:1 on warning 6 % */
  --ev-mark-fill-red:   #FBE9E9;
  --ev-mark-text-red:   #B42318; /* 5.61:1 on --ev-mark-fill-red */
  --ev-info-fill:       #EFF4FE;
  --ev-info-border:     #D8E4FC;
  --ev-text-disabled:   #C9C5C1; /* disabled buttons and menu entries (exempt under WCAG 1.4.3) */

  --vw-tint-success:              color-mix(in srgb, #27C13F 8%, #FFFFFF);  /* chips, badges, hover; --jr-primary-text 5.08:1 */
  --vw-tint-success-hover:        color-mix(in srgb, #27C13F 10%, #FFFFFF); /* active tree node, xref and glossary hover; 4.99:1 */
  --vw-tint-success-border:       color-mix(in srgb, #27C13F 30%, #FFFFFF); /* sync chip, the notes */
  --vw-tint-success-border-hover: color-mix(in srgb, #27C13F 30%, #FFFFFF); /* standard pager */
  --vw-tint-success-line:         color-mix(in srgb, #27C13F 30%, #FFFFFF); /* cross-reference underline */

  --vw-tint-warning:        color-mix(in srgb, #ED8B00 6%, #FFFFFF);  /* .editorial, .jr-note */
  --vw-tint-warning-border: color-mix(in srgb, #ED8B00 30%, #FFFFFF); /* borders only */
  --vw-tint-warning-text:   var(--feedback-warning); /* labels on --vw-tint-warning, 4.76:1 */

  --vw-tint-amended:        var(--ev-mark-fill-amber); /* status "amended"; no user since 06.10.2026, DS token mirror */
  --vw-tint-amended-text:   var(--ev-mark-text-amber);
  --vw-tint-deleted:        var(--ev-mark-fill-red);   /* status "deleted"; no user since 06.10.2026, DS token mirror */
  --vw-tint-deleted-text:   var(--ev-mark-text-red);
  --vw-tint-deleted-strike: #EF444488; /* strike-through of deleted paragraphs, half-transparent red */

  --vw-tint-info:        var(--ev-info-fill);   /* info surface; no user since 06.10.2026, DS token mirror */
  --vw-tint-info-border: var(--ev-info-border);

  --vw-text-disabled: var(--ev-text-disabled);

  /* ── Layout-Maße (viewer-spezifisch, keine Brand-Tokens) ───────────────── */
  /* --hdr-base is the header's own height, kept in this one place; --hdr-h is
     the room it takes above the sticky panes and drops to 0 on phones and
     while the band is hidden (section 50.5). 64px as in the design
     system's chrome-lock (h-16; 56px is a forbidden value there), council
     decision 2, 04.10.2026. --hdr-room is the same room in the panes'
     max-height; it follows --hdr-h but comes back only once a show has
     ended (section 50.5, council 2, decision 4). */
  --hdr-base: 64px;
  --hdr-h: var(--hdr-base);
  --hdr-room: var(--hdr-h);
  --vw-max: 1680px;
  --vw-side-w: 256px;
  --vw-rail-w: 264px;
  --vw-gap: 20px;

  /* ── Abstands-Token (P-B1) ───────────────────────────────────────────────
     Fuenf Token statt Streuwerten. Die Zahlen darunter sind bewusst NICHT
     mehr einzeln gepflegt -- wer einen Abstand aendert, aendert ihn hier.
     Die Mobil-Fassung steht als :root-Ueberschreibung im Block
     @media (max-width:1023px) weiter unten. Sie MUSS im File nach dieser
     Stelle stehen, sonst bleibt sie wirkungslos (gleiche Spezifitaet, es
     entscheidet die Stellung; siehe Kommentar beim Vollflaechen-Verhalten). */
  --sp-page:  22px; /* Seitenrand: .rzrow, .hdr, .hintbar-row, .site-footer, .layout */
  --sp-col:   16px; /* Spaltenabstand im Dreispalter: Breite des .rzh-Griffs */
  --sp-stack: 16px; /* Vertikalrhythmus gestapelter Inhaltskarten */
  --sp-panel: 14px; /* Innenabstand der Leisten: .side, .rail-card */
  --sp-card:  24px; /* Innenabstand der Inhaltskarten: .page-card */

  /* Randnummern-Gutter: Vorgabe war "~3.5rem, muss AR 999. fassen". Bei 12px/600
     reicht 3.5rem knapp nicht sicher -- auf 4.25rem angehoben (siehe Bericht). */
  --rn-gutter: 4.25rem;

  /* Z-Index-Skala */
  /* Bleibt 100 -- ABSICHTLICH, nach einem Fehlversuch am 04.09.2026.
     Die Leisten .split-cap/.read-cap tragen 120 und liegen damit ueber der
     Kopfzeile; ein Popover in der Kopfzeile kann das nicht ueberstimmen, weil
     .hdr sticky ist und einen eigenen Stapelkontext bildet. Ich hatte den
     Kopf deshalb auf 130 gehoben -- und damit das Verhalten umgedreht:
     BEIDE Leisten sind sticky, im gescrollten Zustand liegen sie
     uebereinander. Vorher deckte die Quellenleiste die Kopfzeile ab, danach
     umgekehrt, und der Knopf .src-pick war an seinen eigenen Kanten nicht
     mehr treffbar (regression-darstellung D5b, vier Seiten). Das Verhalten
     des bestehenden Viewers zu drehen war nicht Teil des Auftrags.
     Das Menue der Werkwahl weicht dem stattdessen geometrisch aus: es oeffnet
     linksbuendig unter der Wortmarke und endet weit vor der Leiste. */
  --z-header: 100;
  --z-drawer-scrim: 150;
  --z-drawer: 160;
  --z-pop: 200;
  --z-selpop: 210;
  --z-tip: 250;
  --z-toast: 300;
}

/* ───── 2. Reset & Basistypografie ─────────────────────────────────────── */
* { box-sizing: border-box; margin: 0; padding: 0; }

/* Das [hidden]-Attribut MUSS verbergen: Autor-Regeln (display:flex/grid an
   .src-chip/.hintbar/…) schlagen sonst die User-Agent-[hidden]-Regel (Cascade-
   Ursprung vor Spezifitaet). Ein !important je serverseitig gesetztem [hidden]
   greift nur solange das Attribut da ist; JS entfernt es zum Einblenden. */
[hidden] { display: none !important; }

/* Glossar-/Xref-Popover auch beim Hover zeigen (Plan: "Hover/Tipp"). Das
   Popover wird beim ersten mouseenter async als Kind angehaengt; solange der
   Zeiger auf dem Trigger steht, blendet es diese Regel ein. Klick/Tastatur
   nutzen zusaetzlich .is-open (JS).
   17e (09.10.2026): the hover state is .is-hover, set by viewer.js
   (hoverPopFolgen) instead of :hover, because the popup must be lifted into
   the top layer and placed inside the window like a clicked one; the CSS
   alone could not place it (measured 279px past the right edge at 768px). */
.pop-trigger.is-hover > .pop { display: block; }

/* 06.08.2026, Befund Jannik: "hier kann man nicht draufklicken, weil das
   popup dann verschwindet". Gemessen auf /de/esrs-1/: das Popover liegt 7px
   UNTER seinem Ausloeser. Die Regel darueber zeigt es nur, solange der Zeiger
   auf dem AUSLOESER steht -- wer zum Knopf "Neben dem Text oeffnen" will,
   faellt auf dem Weg in diese 7px-Luecke, :hover endet, das Popover
   verschwindet (gemessen bei Schritt 2 von 14 des direkten Weges). Die
   Knoepfe waren damit per Maus unerreichbar; nur wer den Ausloeser vorher
   ANKLICKT, haelt das Popover ueber .is-open offen.

   Die Bruecke schliesst die Luecke, ohne die Geometrie zu aendern: ein
   durchsichtiges ::before am Popover, das oben und unten je 10px ueberdeckt.
   Weil das Popover ein DOM-Kind des Ausloesers ist, zaehlt der Zeiger dort
   weiterhin als "auf dem Ausloeser", und :hover haelt. 10px deckt die
   gemessenen 7px mit Rand ab. z-index -1 haelt die Bruecke hinter dem
   Inhalt, damit sie keinen Knopf abfaengt; sie existiert ohnehin nur,
   solange das Popover sichtbar ist. */
.pop::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -10px;
  bottom: -10px;
  z-index: -1;
}

/* Mobil (<1024px): vom Splitter gesetzte Inline-Breiten (min/max-width/flex)
   neutralisieren, damit Drawer-/Vollbild-Layout gilt statt einer eingefrorenen
   Desktop-Breite. */
@media (max-width: 1023px) {
  .rzrow .rzpane { min-width: 0 !important; max-width: none !important; }
}

/* Seite scrollt nie horizontal (Pflicht) -- NUR auf html, nicht zusaetzlich auf
   body: overflow-x auf einem Element, ohne dass overflow-y explizit gesetzt
   ist, macht overflow-y dort per Spezifikation zu "auto" (CSS Overflow §3).
   Mit BEIDEN Elementen wurde body dadurch zu einem zweiten, unabhaengigen
   Scroll-Container -- und "position: sticky" von #p-tree/#p-rail verankerte
   sich an DEM statt am Viewport, sodass die Leisten beim Scrollen einfach
   mitwanderten statt stehenzubleiben (Befund 2, verifiziert per Playwright:
   getBoundingClientRect().top von #p-tree folgte 1:1 dem Scroll-Offset).
   html allein reicht fuer den horizontalen Guard, da sein Overflow laut
   HTML5-Spec auf den Viewport propagiert wird. */
html { overflow-x: hidden; }

/* ───── Self-hosted Fonts (DSGVO) -- unveraendert aus dem Design-System
   (CP_Website_DesignSystem/public/fonts, brand.css v4.3) kopiert, je Familie
   latin UND latin-ext mit denselben unicode-range-Grenzen wie brand.css.
   03.10.2026 (council, decision 1; design-check B6): Plus Jakarta Sans kommt
   dazu, fuer die Rollen, die der Kanon ihr gibt (Ueberschriften unter 20px,
   Versalien, Labels, Knoepfe). Fraunces ist der Schnitt mit gepinntem Gewicht
   600 und variabler opsz-Achse (35 KB statt 37 KB, keine gefaelschte Fettung
   mehr moeglich, weil font-synthesis aus ist). Lizenzen: fonts/LICENSES/ ─── */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/PlusJakartaSans-Variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/PlusJakartaSans-Variable-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/Inter-Variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/Inter-Variable-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* 06.10.2026 (Jannik, C2 of the persona triage; decision log): a real italic
   for the norm text. The ESRS set defined terms in bold italics (ESRS 1
   paragraph 15), the Official Journal markup marks them <em>, and with
   font-synthesis off (body) they read upright. Inter Italic, variable, from
   Google Fonts (Inter v20, OFL 1.1, fonts/LICENSES), self-hosted, latin and
   latin-ext with the ranges of the upright faces; weights 400 to 600, the
   norm text's regular and its bold (#read-card strong: 600). A viewer
   deviation from design-system section 4 ("keine Kursivschnitte"): only the
   norm text sets italics, the interface stays upright (its three notes below
   read upright, as they did with synthesis off). */
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 400 600;
  font-display: swap;
  src: url("fonts/Inter-Italic-Variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 400 600;
  font-display: swap;
  src: url("fonts/Inter-Italic-Variable-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/Fraunces-Variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/Fraunces-Variable-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* 03.10.2026 (council, decision 1): the family roles of the design system as
   three names (llms.txt section 4): Fraunces 600 for headings from 20px,
   Plus Jakarta Sans for headings below 20px, caps, labels and buttons, Inter
   for everything read and every number. */
:root {
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-heading: "Plus Jakarta Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
}

/* Body at the design system's 16px (typography.body, the Cupel-Reviewer
   reading area), line height 1.6. Was 15px/1.65 (design director D3). */
body {
  font-family: var(--font-body);
  background: var(--background);
  color: var(--foreground);
  font-size: 16px;
  line-height: 1.6;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
}

/* Heading steps (council decision 1): h1 30px (display-2 md), 24px on
   phones; h2 24px outside cards (display-2), 20px inside reading cards
   (title-sm, the Fraunces floor); h3, the requirement heading, PJS 700 16px
   (typography.heading) -- below 20px the canon keeps the serif out. */
h1, h2 { font-family: var(--font-display); font-weight: 600 !important; letter-spacing: -0.01em; }
h1 { font-size: 30px; line-height: 1.25; }
h2 { font-size: 24px; line-height: 1.25; }
h3, h4 { font-family: var(--font-heading); font-size: 16px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.25; }
@media (max-width: 639px) { h1 { font-size: 24px; } }

a { color: var(--jr-primary-text); text-decoration: none; }
a:hover { text-decoration: underline; }

button { font: inherit; cursor: pointer; border: none; background: none; color: inherit; }

img, svg { max-width: 100%; display: block; }

/* Icons: Lucide as inline SVG, the only icon system, no emojis. Markup
   <svg class="msym"><use href="#i-NAME"></use></svg> points into the symbol
   block that site/icons.py writes once per page right after <body>.
   Design system: 24 grid, stroke 2, round caps; 16px next to 13-14px text,
   20px next to 16px text, 24px standalone. 16px is the default because every
   label in the viewer is 10.5-15px; the size is the font-size (1em), so a
   context rule only has to set a font-size. Stroke and fill are set here and
   not in the symbols, so each icon takes currentColor from its context. */
.msym {
  width: 1em;
  height: 1em;
  font-size: 16px;
  display: inline-block;
  vertical-align: middle;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  user-select: none;
}
/* Icon-only chrome buttons (rails, panel heads, close buttons): 20px, as in
   the design system's app chrome (16px and 20px); the buttons carry
   aria-label and tooltip. Below 1024px #syncToggle moves into the split cap
   with its text label, so it keeps 16px there; from 1024px #arModus sits
   there with its label "Nur AR" and keeps 16px as well. */
.minipane button .msym,
.side-head button .msym,
.rail-head button .msym,
.split-cap > button:not(.src-pick):not(#syncToggle):not(#arModus) .msym,
.hdr-menu-btn .msym,
.drawer-close .msym,
.hintbar-close .msym { font-size: 20px; }
/* The symbol block itself takes no space and is never painted. Not
   display:none, which can stop <use> from rendering the symbols. */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Fokusring an der Wurzel korrigiert (26.07.): --jr-primary (#27C13F) erreicht
   gegen Weiss nur 2,39:1 und gegen --muted 2,19:1, WCAG 1.4.11 verlangt 3:1
   fuer den Fokusindikator. --jr-primary-text (#187A28) liefert 5,45:1 gegen
   Weiss und 5,00:1 gegen --muted. Selbst nachgerechnet, nicht aus der Doku
   uebernommen -- exakt der 2,39er-Wert ist die dokumentierte Hausfalle. */
:focus-visible {
  outline: 2px solid var(--jr-primary-text);
  outline-offset: 2px;
  border-radius: 2px;
}
/* 03.10.2026 (design-check B4): on the dark footer (then #353537) the ring above
   reached only 2.25:1. There it takes the design system's focus.ring.color
   #1FA033 (--jr-primary-dark, 5.11:1 on today's #1C1917); the light surfaces
   keep the 5.45:1 ring chosen above. */
.site-footer :focus-visible { outline-color: var(--jr-primary-dark); }
/* 04.10.2026 (design-check B4): one ring. The design system's focus.ring
   is #1FA033 (3.42:1 on white); the viewer keeps #187A28 (5.45:1), also a
   design-system colour (the text green), on every light surface, and
   every ring sits 2px from its control. The case-file fields, the brand
   mark and the notice fold had their own colour or offset; they follow
   the root rule now. The dark footer keeps #1FA033 (above). */

/* ───── 3. App-Shell ────────────────────────────────────────────────────── */
.esrs-app { min-height: 100vh; display: flex; flex-direction: column; }

/* ───── 4. Header (sticky, 64px) ───────────────────────────────────────── */
.hdr {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  height: var(--hdr-h);
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 var(--sp-page);
}
.brand {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-weight: 600;
  font-size: 16px;
  white-space: nowrap;
}
.brand .dot { color: var(--jr-primary-text); }
.brand small { color: var(--muted-foreground); font-weight: 500; }

.hdr-menu-btn { display: none; width: 40px; height: 40px; border-radius: var(--radius-md); color: var(--muted-foreground); align-items: center; justify-content: center; flex-shrink: 0; }
.hdr-menu-btn:hover { background: var(--muted); }

.hdr-search {
  flex: 1;
  max-width: 420px;
  /* The header's valve since 04.10.2026 (section 50.24): without it the
     field kept the input's intrinsic width (245px) and the logo shrank.
     Below 1024px it has a floor of 10rem (end of section 50.24). */
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 7px 14px;
  color: var(--muted-foreground);
  font-size: 14px;
}
.hdr-search input {
  border: none;
  background: none;
  outline: none;
  flex: 1;
  font: inherit;
  color: var(--foreground);
  min-width: 0;
}
.hdr-search input::placeholder { color: var(--muted-foreground); }

.hdr-right { margin-left: auto; display: flex; align-items: center; gap: 9px; flex-shrink: 0; }

/* Sekundäre Pillen-Buttons (Filter/Links im Header, Rail-Aktionen). Pill-Radius
   ist ein etabliertes brand.css-Muster (.filter-chip/.tab/.status-badge), daher
   keine Neuerfindung -- nur hier auf einen generischen Link/Button-Baustein
   angewendet, den brand.css so nicht separat führt. */
/* Control type scale (council 2, decision 3, 04.10.2026): 14px for the
   segmented controls, the standard jump and the pill buttons; 13px for
   every other control (language switch, source pickers and the coupling
   switch, pane-caption buttons with "Nur AR", chips, the AR link, the
   Excel copy button, the font-size ladder from 13px); 12px is for
   captions only. Captions and meta lines are 12px too (the coupling
   switch's badges, the dossier's labels and hint, the EFRAG meta line, the
   search scope note, the selection bar's subline, the source menu's "nur
   ESRS" note);
   below that, 11px, stand only badges in capitals and the code chips
   (GOV-1, E1-4), as in the design system's scale. */

.pill-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 6px 13px;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted-foreground);
  background: var(--bg-elevated);
  transition: border-color var(--jr-duration-fast) var(--jr-ease-out),
              color var(--jr-duration-fast) var(--jr-ease-out),
              background var(--jr-duration-fast) var(--jr-ease-out);
  white-space: nowrap;
}
.pill-btn:hover { border-color: var(--jr-primary); color: var(--jr-primary-text); text-decoration: none; }
/* DS: Plus Jakarta Sans for buttons, tabs and chips (council decision 1, 03.10.2026). */
.pill-btn, .cap-btn, .src-chip, .src-pick, .std-jump,
.werk-wahl > summary, .ar-open, .pop-action,
.lang-switch button { font-family: var(--font-heading); font-weight: 600; }

/* 06.10.2026 (persona review, all five reviewers): overflow hidden clipped
   the keyboard ring of DE and EN to an arc. The buttons carry the pill
   radius themselves, so the chosen fill keeps the pill shape without
   clipping, and the ring shows whole (canon K18). */
.lang-switch {
  display: flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
}
.lang-switch button { padding: 5px 11px; color: var(--muted-foreground); border-radius: var(--radius-pill); }
/* 06.08.2026: hier stand background: var(--jr-primary) mit weisser Schrift.
   #FFFFFF auf #27C13F sind nachgerechnet 2,39:1 gegen ein Soll von 4,5:1 --
   genau die Kombination, die die Projektregel seit dem 20.07.2026 ausdruecklich
   verbietet ("weisstragende Flaeche ist #0A7A24, nicht --jr-primary").
   Der Knopf steht in der Kopfleiste JEDER Seite und ist auf jedem
   Bildschirmfoto zu sehen; aufgefallen ist es niemandem, weil keine Suite
   Kontraste nachrechnete (jetzt D10). --jr-primary-text #187A28 traegt Weiss
   mit 5,45:1. ANMERKUNG fuer das Design-System: ein eigenes, benanntes Token
   fuer die weisstragende FLAECHE fehlt dort; #0A7A24 existiert nur als
   erster Stop des CTA-Verlaufs. */
.lang-switch button[aria-pressed="true"] { background: var(--jr-primary-text); color: var(--jr-cta-text); }

/* Abschnitt 5 (Vergleichs-Steuerleiste .cmp-bar mit .cmp-title/.col-pick/
   .swap-btn/.sync-badge/.cmp-hint) und der zugehoerige .mode-toggle sind mit
   dem Zwei-Spalten-Layout entfallen; der Vergleich laeuft heute ueber das
   Zweitpanel (Abschnitt 30). Abschnittsnummern
   bleiben lueckenhaft, damit Verweise auf die uebrigen Abschnitte stimmen. */

/* ───── 6. Layout-Raster (256px | 1fr | 264px) ─────────────────────────── */
.layout {
  display: flex;
  width: 100%; /* siehe .rzrow-Kommentar: Flex-Item + margin:auto ohne width
    stretcht nicht, sondern faellt auf shrink-to-fit-Kinderbreiten zurueck
    (home.html.j2: .layout ist direktes Kind von .esrs-app). */
  gap: var(--vw-gap);
  max-width: var(--vw-max);
  margin: 0 auto;
  padding: 20px var(--sp-page);
  align-items: flex-start;
  min-width: 0;
}
.side, .rail {
  flex: 0 0 var(--vw-side-w);
  width: var(--vw-side-w);
  position: sticky;
  top: calc(var(--hdr-h) + 20px);
  max-height: calc(100vh - var(--hdr-room) - 40px);
  overflow-y: auto;
  /* Opacity only (design-check F16, 05.10.2026): flex-basis, width and
     margin were declared too. The splitter pins inline widths, so they
     never ran, but any change of --vw-side-w would have animated layout
     (llms.txt: only transform and opacity move). */
  transition: opacity var(--jr-duration-fast) var(--jr-ease-out);
}
.rail { flex-basis: var(--vw-rail-w); width: var(--vw-rail-w); }
.content { flex: 1 1 auto; min-width: 0; }

/* Startseite: schmalere Spaltenbreite als der App-Shell-Default (ersetzt eine
   vormals inline gesetzte style="max-width:1100px", CSP: style-src 'self'). */
.layout-narrow { max-width: 1100px; }

.side {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--sp-panel);
  box-shadow: var(--shadow-sm);
}

/* ───── 7. Karten (aus brand.css, Design-System gewinnt gegenüber Mockup) ── */
.page-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl); /* 20px -- NICHT die 14px aus dem Mockup */
  padding: var(--sp-card);          /* 24px -- NICHT 26px/30px/72px aus dem Mockup */
  margin-bottom: var(--sp-stack);
}
.inner-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px;
}

.content h1 { margin-bottom: 4px; }
.std-meta {
  color: var(--muted-foreground);
  font-size: 13px;
  margin: 2px 0 0;
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
}

.rail-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--sp-panel);
  box-shadow: var(--shadow-sm);
  margin-bottom: 12px;
  font-size: 13px;
}
.rail-card h2 {
  font-family: var(--font-heading);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
  margin-bottom: 9px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.toc-item { display: block; padding: 4px 8px; border-radius: var(--radius-sm); color: var(--muted-foreground); }
.toc-item:hover { text-decoration: none; background: var(--muted); }
.toc-item.on { color: var(--jr-primary-text); font-weight: 600; background: var(--vw-tint-success); }
.basket-list { color: var(--muted-foreground); font-size: 13px; display: flex; flex-direction: column; gap: 4px; }
.basket-empty { color: var(--muted-foreground); font-style: normal; } /* 06.10.2026: upright, as rendered (C2) */
.basket-actions { display: flex; gap: 6px; margin-top: 9px; flex-wrap: wrap; }

/* ───── 8. Baum-Menü ────────────────────────────────────────────────────── */
.tree { font-size: 14px; }
.tree ul { list-style: none; }
.tree .node {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--foreground);
}
.tree .node:hover { background: var(--muted); }
.tree .node .msym { color: var(--muted-foreground); flex-shrink: 0; }
.tree .node a { color: inherit; }
.tree .node a:hover { text-decoration: none; }
.tree .lvl2 { padding-left: 22px; color: var(--muted-foreground); }
.tree .lvl3 { padding-left: 40px; color: var(--muted-foreground); font-size: 13px; }
.tree .active-node { background: var(--vw-tint-success-hover); color: var(--jr-primary-text); font-weight: 600; }
.tree .active-node .msym { color: var(--jr-primary-text); }
.tree-sub[hidden] { display: none; }

/* ───── 9. Randnummern -- Kernmechanik "Option A+" ─────────────────────── */
/* Der Normtext bleibt zeichengetreu; der Generator umhüllt nur das Nummern-
   Token mit .rn > .rn-sp (physisches NBSP, darf nie per CSS entfernt werden). */
/* T10 (I7 r2, verdict-VV-r1 Fund 10): ein "/"-Wortlauf ohne Leerzeichen
   (ESRS 1 DE: "Angabepflichten/Anwendungsanforderungen") lief bei 375px 6px
   ueber den vom html-Overflow-Schutz (Zeile 203) beschnittenen Rand, weil
   kein Umbruchmittel griff. Zeichen bleiben unveraendert, nur der
   Zeilenumbruch darf jetzt auch mitten im Wort greifen, wenn kein anderer
   Umbruch reicht (kein Konflikt mit dem Silbentrennungs-Tor: das prueft
   eingebettete weiche Trennstriche im Text, nicht diese CSS-Notbremse). */
.para { position: relative; padding-left: var(--rn-gutter); margin: 0 0 14px; overflow-wrap: break-word; }
.rn {
  position: absolute;
  left: 0;
  top: 2px;
  width: calc(var(--rn-gutter) - 0.75rem);
  text-align: right;
  color: var(--muted-foreground);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* .rn-sp holds the space after the number and stays in the DOM. Set 1's is a
   no-break space, which nothing collapses. P5 (06.10.2026): the text of 2026/1563
   has no no-break space after its numbers (number and text are two cells of the
   Official Journal); the renderer moves the space between them into .rn-sp. Kept
   as written, so a copied selection reads "14. Ziel" and not "14.Ziel" (the space
   collapsed at the end of the .rn box). */
.rn-sp { white-space: pre; }

@media (max-width: 640px) {
  :root { --rn-gutter: 3rem; }
  /* 03.10.2026 (design director, upgrade 10): as an inline number the first
     line's text started wherever "44.\00a0" happened to end (x=44 at 375px)
     while the following lines started at the gutter (x=62) -- the hanging
     indent missed its own edge by 18px. The number now fills the gutter as an
     inline-block, right-aligned like on desktop, so the first line starts on
     the same edge as the rest. min-width, not width: "AR 105." may push the
     first line a few pixels instead of running into the text. text-indent 0:
     an inline-block would inherit the paragraph's negative indent. */
  .rn {
    position: static;
    display: inline-block;
    min-width: var(--rn-gutter);
    width: auto;
    text-align: right;
    padding-right: 0.6em;
    text-indent: 0;
  }
  .para { text-indent: calc(var(--rn-gutter) * -1); }
}

/* ───── 10. Absatz-Hover-Aktionen (genau zwei: Link kopieren, In den Korb) ── */
.para:hover .p-actions, .para:focus-within .p-actions { opacity: 1; }
.p-actions {
  position: absolute;
  right: 0;
  top: -28px;
  /* UI chrome inside the text flow: never part of a text selection, so copying
     across paragraphs cannot pull in button labels (adversarial B2). */
  user-select: none;
  -webkit-user-select: none;
  display: flex;
  gap: 2px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 3px 6px;
  box-shadow: var(--shadow-sm);
  opacity: 0;
  transition: opacity var(--jr-duration-fast) var(--jr-ease-out);
}
.p-actions button {
  display: flex;
  align-items: center;
  padding: 4px 6px;
  border-radius: var(--radius-pill);
  color: var(--muted-foreground);
  font-size: 12px;
  gap: 4px;
}
.p-actions button:hover { background: var(--muted); color: var(--jr-primary-text); }
@media (hover: none) {
  /* Touch: Aktionen ohne Hover erreichbar (JS toggelt .is-open beim Tap) */
  .para.is-open .p-actions { opacity: 1; }
}

/* ───── 11. Markieren-Popup (dunkle Pille an der Selektion) ────────────── */
.sel-pop {
  position: fixed;
  z-index: var(--z-selpop);
  display: none;
  align-items: center;
  gap: 2px;
  background: var(--footer-bg);
  border-radius: var(--radius-pill);
  padding: 4px 6px;
  box-shadow: var(--shadow-md);
  /* 17e (09.10.2026): at 768px the bar's natural width (760px) reached the
     window's edge; it keeps 8px to both edges (viewer.js positionSelPop). */
  max-width: calc(100vw - 16px);
}
.sel-pop.is-open { display: inline-flex; }
.sel-pop button {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--jr-cta-text);
  font-size: 13px;
  font-weight: 500;
  padding: 5px 10px;
  border-radius: var(--radius-pill);
}
.sel-pop button:hover { background: rgba(255,255,255,.14); }
.sel-pop .sep { width: 1px; align-self: stretch; background: rgba(255,255,255,.25); margin: 3px 2px; }
/* 09.10.2026 (run line 12c): an open field hides the bar's buttons; their
   separators stood above it as stray lines. */
.sel-pop .sep:has(+ [hidden]) { display: none; }
/* Persona triage row 3 (decision e, 06.10.2026): after a touch or pen
   selection the bar docks at the bottom of the viewport, inside the safe
   area, off the selection and clear of the phone's own selection menu
   (viewer.js dockSelPop). Two classes, so it wins over the column layout
   below 640px without depending on the order in this file. */
.sel-pop.is-docked {
  top: auto;
  bottom: calc(8px + env(safe-area-inset-bottom, 0px));
  left: 50%;
  transform: translateX(-50%);
}
.sel-pop.is-docked.is-docked-top {
  top: calc(8px + env(safe-area-inset-top, 0px));
  bottom: auto;
}

/* ───── 12. Popover -- eine Mechanik für Fußnoten UND Querverweise ─────── */
.pop-trigger { position: relative; cursor: pointer; }
.pop {
  position: absolute;
  display: none;
  z-index: var(--z-pop);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  font-size: 13px;
  line-height: 1.5;
  /* Waehrend der Anzeige traegt das Popover das Attribut popover (S-2,
     Top-Layer). Der Browser gibt einem [popover] von sich aus einen Rahmen
     und overflow:auto mit. Beides wird schon hier in der Basisregel
     abgeraeumt, damit die spaeteren typbezogenen Regeln ihren eigenen
     Rahmen ungestoert setzen koennen (.xref .pop hat einen, .fn .pop nicht).
     Stuende das Abraeumen in der spaeten [popover]-Regel, naehme es den
     Rahmen von .xref .pop bei gleicher Spezifitaet wieder weg. */
  border: 0;
  overflow: visible;
  /* Ein Popover ist eine eigene Flaeche und darf die Einzugsregeln des
     Absatzes NICHT erben, in dem sein Ausloeser zufaellig steht. Gemessen am
     04.08.2026 bei 390px im Zweitfenster: unter 640px traegt .para ein
     text-indent von -3rem, das die Randziffer in die Zeile zieht. Das erbt
     sich auf die Bloecke im Popover und schob deren jeweils ERSTE Zeile um
     48px nach links, also 33px ausserhalb der weissen Flaeche auf den
     Seitenhintergrund. Sichtbar wurde es erst mit S-2, weil die Popover im
     Zweitfenster vorher gar nicht aufgingen; der Fehler lag aber schon
     vorher im Blatt. */
  text-indent: 0;
  /* 06.10.2026 (point 2a): the same holds for the weight and the slant.
     Since every bold italic term carries its popup, most glossary popups
     hang inside <strong><em>, and the definition read in bold (D12). The
     label and the action set their own weights. */
  font-weight: 400;
  font-style: normal;
}
/* 06.10.2026 (persona p5): focus alone no longer opens a popup. The
   :focus-visible rule opened it on Tab, partly outside the window, and Enter
   then did nothing; Enter and Space open it now (viewer.js popKeydown). */
.pop-trigger.is-open .pop { display: block; }

/* Fußnoten: dunkel, kompakt, unter dem Trigger */
.fn { color: var(--jr-primary-text); font-size: 11px; vertical-align: super; font-weight: 600; }
/* 03.10.2026 (design director, upgrade 4): the marker read "( 38 )" and the
   line under it grew from 25px to 29px. Two causes, both in the rendering, not
   in the text: the generated anchor carries the source's line breaks around
   its <sup> (rendered as spaces), and the <sup> raised itself a second time
   on top of the anchor's own "super". The anchor's own text (only that
   whitespace) gets font-size 0, the <sup> carries the size and is raised
   once -- same bytes in the DOM (K1), steady line height. NOT inline-flex:
   its items are blockified, and copying a paragraph then put line breaks
   around the number ("(\n38\n)"). All 248 markers in the build share this
   markup. */
/* Round 2 (design director): as an inline-block the marker was an atomic box,
   and Chrome breaks before one even right after "(" -- "(" stood alone at the
   end of a line (1 of 34 at 1440px, 2 of 34 at 375px on /de/e1/). Now an
   inline with nowrap: "(", marker and ")" stay together. The <sup> is raised
   by position instead of vertical-align, so the line keeps its height. The
   12px top padding gives the box the marker's height: the popover, placed
   from the trigger's box, still opens above the number and not over it.
   Copying a paragraph gives "( 38 )" again, as on master -- the whitespace is
   still text, only drawn at size 0. text-indent 0 stays: on phones .para
   carries a negative indent for its hanging number (section 9).
   Round 3: vertical-align back to baseline. The base rule above raises .fn
   with "super", and the <sup> was raised a second time -- every number
   floated about 12px above an empty "( )" (all 248 markers). */
.fn { display: inline; white-space: nowrap; font-size: 0; line-height: 0; text-indent: 0; padding-top: 12px; vertical-align: baseline; }
.fn sup { font-size: 12px; line-height: 0; vertical-align: baseline; position: relative; top: -.5em; }
/* 04.10.2026 (design-check N6): the footnote number at 12px, the smallest
   size for mixed-case text (11px is for caps labels), and so is every
   other superscript in the reading text: unclassed <sup> took the
   browser's "smaller", 13.33px, off the type scale. */
#read-card sup, #splitBody sup { font-size: 12px; }
.fn .pop {
  bottom: calc(100% + 6px);
  left: -20px;
  top: auto;
  width: 270px;
  background: var(--footer-bg);
  color: var(--jr-cta-text);
  font-weight: 400;
  padding: 10px 12px;
}
.fn .pop.pop--flip { bottom: auto; top: calc(100% + 6px); }

/* Querverweise (inkl. Glossarbegriffe): hell, mit Auszug + Sprung-Aktion */
.xref {
  color: var(--jr-primary-text);
  font-weight: 500;
  border-bottom: 1px solid var(--vw-tint-success-line);
}
.xref--term { border-bottom-style: dashed; cursor: help; }
/* 07.10.2026 (design director round 1, finding 12): a reference broke at the
   hyphen of its code ("ESRS 2 GDR-|T"), two pointer targets that read as
   two words. A reference is at most 20 characters (1,379 links measured on
   both trees), so it keeps to one line; its popup, appended inside the link
   (viewer.js), wraps again (regression-darstellung D23). */
a.xref:not(.xref--term) { white-space: nowrap; }
a.xref:not(.xref--term) > .pop { white-space: normal; }
/* 09.10.2026 (P2b step 8): nine German VSME references run past that premise, to
   32 characters ("Nummer 24 Buchstabe e Ziffern vi"), and one ran out of the
   320px line. The generator marks such a link xref--long; it wraps at its plain
   spaces, and the source binds each word to its number with a no-break space, so
   a line ends after "Buchstabe e", never inside a pair (regression-vsme-viewer X). */
a.xref.xref--long { white-space: normal; }
.xref:hover, .pop-trigger.is-open .xref-label { background: var(--vw-tint-success-hover); }

/* Externe Zitate von EU-Rechtsakten -> amtliche EUR-Lex-Fassung (neuer Tab).
   Anders als interne Querverweise: kein Vorschau-Popover (EUR-Lex laesst sich
   nicht einbetten), dafuer dezent als extern erkennbar durch ein nachgestelltes
   Lucide-external-link-Icon (reine CSS-mask, kein DOM-Text -> K1 unberuehrt). Das Icon
   erbt die Linkfarbe (currentColor) und traegt damit in beiden Themes. */
.eurlex-ref {
  color: var(--jr-primary-text);
  font-weight: 500;
  border-bottom: 1px solid var(--vw-tint-success-line);
}
.eurlex-ref:hover, .eurlex-ref:focus-visible {
  background: var(--vw-tint-success-hover);
  text-decoration: none;
}
.eurlex-ref::after {
  content: "";
  display: inline-block;
  width: .72em;
  height: .72em;
  margin-left: .18em;
  vertical-align: -0.03em;
  background-color: currentColor;
  opacity: .72;
  -webkit-mask: var(--eurlex-ext-icon) center / contain no-repeat;
  mask: var(--eurlex-ext-icon) center / contain no-repeat;
}
:root {
  /* Lucide external-link, stroke 2 with round caps (design system). */
  --eurlex-ext-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h6v6'/%3E%3Cpath d='M10 14 21 3'/%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3C/svg%3E");
}

/* Befund 3: Inhaltsverzeichnis-Zeilen sind anklickbar (reine Umhuellung, s.
   pipeline/generate.py::link_toc_table) -- gleiche zurueckhaltende Verweis-
   Optik wie .xref statt auffaelliger Standard-Linkfarbe; erbt die Zeilen-
   eigene Textfarbe (z. B. kursive Abschnittstitel bleiben kursiv/grau). */
.toc-link { color: inherit; border-bottom: 1px solid var(--vw-tint-success-line); }
.toc-link:hover, .toc-link:focus-visible { text-decoration: none; background: var(--vw-tint-success-hover); }
.xref .pop {
  top: calc(100% + 8px);
  left: 0;
  width: 340px;
  max-width: min(340px, 82vw);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  color: var(--foreground);
  padding: 14px;
}
.pop-label {
  font-family: var(--font-heading);
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  color: var(--jr-primary-text);
  text-transform: uppercase;
  margin-bottom: 6px;
}
.pop-excerpt { color: var(--foreground); margin-bottom: 10px; }
/* 06.08.2026, Befund Jannik ("popup sieht man teilweise gar nicht, bzw. kann
   man nicht lesen"): .fn .pop traegt die dunkle Flaeche --footer-bg #353537
   mit --jr-cta-text #FFFFFF, aber die Zeile darueber setzt .pop-excerpt hart
   auf --foreground #1C1917 und schlaegt damit die Vererbung. Nachgerechnet
   1,43:1 gegen ein Soll von 4,5:1, also praktisch unlesbar. Fuer die
   Begriffskarte war derselbe Fehler laengst behoben (.term-tip weiter unten),
   nur fuer die Fussnote fehlte die Zeile. Mit color:inherit stehen 12,24:1.
   Die Luecke, durch die das live gehen konnte, schliesst Kriterium D10. */
.fn .pop .pop-excerpt { color: inherit; }
.pop-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--jr-primary-text);
  font-weight: 600;
  font-size: 13px;
  padding: 5px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
}
.pop-action:hover { border-color: var(--jr-primary); background: var(--vw-tint-success); }

/* Konsolidierungsmarken (amtlicher Normtext, dezent) */
.consol-mark { color: var(--muted-foreground); font-size: 0.75em; font-weight: 600; cursor: help; margin: 0 2px; }

/* ───── 13. Tabellen -- Excel-Fokus, keine technischen Hinweise ────────── */
.tbl-wrap {
  margin: 14px 0 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
}
/* 07.10.2026 (design director round 1, finding 6; Jannik: on both trees):
   the head was a grey band whose solid green gradient button was the loudest
   thing on Annex II. Copying is secondary to the norm it copies: the head is
   the card's own surface and the button the design system's outline button
   (brand.css .btn-outline: transparent, 1px border, foreground text, the
   green on hover; radius 10px, no pill) (regression-darstellung D24). */
.tbl-head {
  display: flex;
  align-items: center;
  gap: 10px;
  background: transparent;
  border-bottom: 1px solid var(--border);
  padding: 6px 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
}
.tbl-head .grow { flex: 1; }
.excel-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px; /* control type scale, note above .pill-btn */
  font-weight: 600;
  color: var(--foreground);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-md); /* brand.css .btn: bewusst KEIN Pill */
  padding: 5px 12px;
  transition: border-color var(--jr-duration-fast) var(--jr-ease-out),
              color var(--jr-duration-fast) var(--jr-ease-out);
}
.excel-btn:hover { border-color: var(--jr-primary); color: var(--jr-primary-text); }

/* Einziger horizontal scrollbarer Container der Seite */
.tbl-scroll { overflow-x: auto; }

/* S-3, Entscheidung Jannik vom 04.08.2026: die Tabellen SCROLLEN weiter, die
   amtlichen Spaltenmasse aus dem colgroup bleiben unangetastet (gemessen auf
   ESRS 2: 5 Spalten, 816px in einer 624px breiten Lesespalte). Die Gegenprobe
   "umbrechen" haette die Tabelle um 27 Prozent verlaengert, 12.271 auf 15.559
   Pixel, und Woerter mitten im Wort getrennt.

   Damit bleibt eine Pflicht: der Leser muss SEHEN, dass rechts etwas
   weitergeht. Chrome zeichnet die Ueberlagerungsleiste erst beim Scrollen;
   im Bildschirmfoto vom 04.08. war die fuenfte Spalte deshalb unsichtbar und
   die vierte mitten im Wort gekappt, ohne jeden Hinweis.

   Gemessen wurden vier Schreibweisen, die die klassische, platzbelegende
   Leiste erzwingen sollen (scrollbar-color, ::-webkit-scrollbar,
   overflow-x:scroll und die Kombination): ALLE VIER belegten 0px. Die
   Leiste haengt am Betriebssystem, nicht an uns, und taugt deshalb nicht
   als Signal. Der Hinweis wird darum selbst gezeichnet und ist damit
   plattformunabhaengig.

   Technik: vier Hintergrundschichten. Die beiden deckenden Schichten sind
   an den INHALT geheftet (background-attachment: local) und wandern beim
   Scrollen mit, die beiden Schattenschichten stehen fest (scroll). Ist
   links oder rechts noch etwas da, schaut der Schatten hervor; am Ende
   angekommen deckt ihn die mitgewanderte Schicht zu. Kein JS noetig, CSP
   unberuehrt. scrollbar-width und -color bleiben zusaetzlich stehen: wo das
   System eine klassische Leiste zeichnet, ist sie damit schmal und
   farblich eingepasst.
   09.10.2026: the frames of the flow and chart figures (point a) scroll the
   same way below their drawing's 672px and carry the same hint (D7). */
.tbl-scroll,
.abb-fluss, .abb-diagramm {
  scrollbar-width: thin;
  scrollbar-color: var(--muted-foreground) var(--muted);
  background-image:
    linear-gradient(to right, var(--bg-elevated) 30%, transparent),
    linear-gradient(to left, var(--bg-elevated) 30%, transparent),
    linear-gradient(to right, rgba(28,25,23,.17), rgba(28,25,23,0)),
    linear-gradient(to left, rgba(28,25,23,.17), rgba(28,25,23,0));
  background-position: left center, right center, left center, right center;
  background-repeat: no-repeat;
  background-size: 30px 100%, 30px 100%, 13px 100%, 13px 100%;
  background-attachment: local, local, scroll, scroll;
}

table.norm { width: 100%; border-collapse: collapse; font-size: 13px; }
table.norm th { background: var(--muted); text-align: left; font-weight: 600; padding: 8px 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
table.norm td { padding: 8px 12px; border-bottom: 1px solid var(--border); }
table.norm tr:last-child td { border-bottom: none; }

/* Laengsstriche (Auftrag Jannik, 04.08.2026: "damit man die Spalten besser
   differenzieren kann"). Querstriche gab es schon ueber border-bottom,
   Laengsstriche fehlten ganz: gemessen 458 von 617 Zellen ohne Trennung.
   Gleiche Staerke und gleiches Token wie die Querstriche, damit ein Raster
   entsteht und keine zwei konkurrierenden Linienarten. Die jeweils letzte
   Spalte bleibt ohne, sonst doppelte sich der Strich mit dem Rahmen von
   .tbl-wrap. */
table.norm td, table.norm th { border-right: 1px solid var(--border); }
/* 07.10.2026 (design director round 1, finding 5): a cell starts at the top,
   beside the first line of its neighbour. Centred, a term in Annex II stood
   in the middle of a definition of twenty lines; the Official Journal's own
   tables and the VSME tables (.oj-table) already read from the top
   (regression-darstellung D23). */
table.norm td, table.norm th { vertical-align: top; }
table.norm td:last-child, table.norm th:last-child { border-right: none; }
/* 07.10.2026 (Jannik: "da ist so ein komischer rahmen"): the Official
   Journal sets a definition's items a) to d) as small two-cell tables inside
   the cell (Annex II "Arbeitsfreistellung aus familiären Gründen"). They took
   the outer table's cell lines, a frame beside the items, and each sized its
   marker column on its own, so the text of d) stood 1px off the others. A
   list inside a cell reads as a list: no lines, one marker column. 3em, not
   2.5em: the widest marker, "xviii." in Annex II term-174, needs 27.6px
   of text, and at 2.5em it widened its own column by 3px. */
table.norm td table.norm { margin: 8px 0 0; font-size: inherit; }
table.norm td table.norm td { padding: 0 0 6px; border: 0; }
table.norm td table.norm td:first-child:not(:last-child) { width: 3em; padding-right: 8px; white-space: nowrap; }

/* ───── 14. Hinweisleisten (dezent, schließbar) ────────────────────────── */
.hintbar {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-size: 13px;
  line-height: 1.5;
  margin: 0 0 14px;
}
.hintbar .msym { flex-shrink: 0; margin-top: 1px; }
.hintbar-body { flex: 1; }
.hintbar-close { flex-shrink: 0; width: 26px; height: 26px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; color: inherit; opacity: .7; }
.hintbar-close:hover { opacity: 1; background: rgba(0,0,0,.06); }

/* Sprungziel nicht gefunden */
.notice { color: var(--feedback-warning); border-color: rgba(237,139,0,.30); background: rgba(237,139,0,.07); }
/* 05.10.2026 (design-check F1): warning icons take #B45309 (tokens.json
   color.icon.warning); #ED8B00 drew them at 2.4:1 on the warning tint. */
.notice .msym { color: var(--feedback-warning); }

/* Datenpunkt-Sprung (?dp=) -- Erfolgs-/Kontexthinweis, kein DP-Panel/Chip */
.dp-hint { color: var(--jr-primary-text); border-color: rgba(39,193,63,.30); background: rgba(39,193,63,.07); }
.dp-hint .msym { color: var(--jr-primary-text); }

/* ───── 15. Redaktioneller Hinweis (2025/1416 u.ä.) -- nie wie Normtext ── */
.editorial {
  display: flex;
  gap: 12px;
  /* 04.10.2026 (design-check N5): no 4px left edge; tint, border, icon
     and label say "our note" (llms.txt rule 4, no accent edges). The
     border is the tint pattern's .30 (design-check F15, 05.10.2026). */
  border: 1px solid var(--vw-tint-warning-border);
  border-radius: var(--radius-lg);
  background: var(--vw-tint-warning);
  padding: 14px 16px;
  margin: 0 0 16px;
  font-size: 13px;
  color: var(--foreground);
}
.editorial .msym { color: var(--feedback-warning); flex-shrink: 0; } /* F1 */
.editorial-label {
  font-family: var(--font-heading);
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  /* Selbst nachgerechnet am 27.07.2026: --vw-tint-warning-text (#9A6A00) auf
     --vw-tint-warning (#FFF7EC) erreicht 4,46:1 und verfehlt WCAG 1.4.3 (4,5:1)
     fuer diesen 10,5px-Text knapp. Der Fehler war vorher schon da; Paket 3 hat
     mit dem Absatz "Marken im amtlichen Text" ein fuenftes Label derselben
     Klasse hinzugefuegt und damit einen neuen Verstoss erzeugt, statt nur einen
     alten zu erben. --vw-tint-amended-text (#8A5200) ist ein BESTEHENDES Token
     (keine neue Farbe), erreicht auf derselben Flaeche 6,01:1 und behebt alle
     Labels dieser Klasse zugleich. Der Ton bleibt in der Amber-Sprache; die
     Aenderung ist eine Verdunkelung um zwei Stufen, keine Umfaerbung. */
  color: var(--vw-tint-amended-text);
  margin-bottom: 4px;
}

/* ───── 16. Ziel-Highlight (Ansprung via Anker/DP) ──────────────────────── */
/* 05.10.2026 (design-check F6): the target's wash fades in by opacity over
   --jr-duration-normal and stays until the next jump or click (viewer.js
   markTarget); the 2s fade animated the background colour on a hard-coded
   duration and was gone before a reader had found the spot. It is the
   centre pair's wash (50.3) at the old .18; multiply keeps the text dark.
   On a centre-pair paragraph it stands in for that wash until the click,
   and it sets its own opacity, because the centre pair's rests at 0. */
.target-hit { position: relative; border-radius: var(--radius-sm); }
.target-hit::before,
.pl-focus.target-hit::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(39, 193, 63, .18);
  mix-blend-mode: multiply;
  pointer-events: none;
  opacity: 1;
  animation: targetIn var(--jr-duration-normal) var(--jr-ease-out) both;
}
@keyframes targetIn { from { opacity: 0; } }
@media print { .target-hit::before { display: none; } }
/* 07.10.2026 (Jannik: "es wird komisch eingerückt wenn man dahin springt"):
   on a table row the wash is no pseudo-element. A ::before of a <tr> is laid
   out as an anonymous first cell, and the marked row moved one column right
   (Annex II "Konzept": cells at 33/355px, marked at 353/642px). The cells
   carry the same .18 tint as an image layer over their own background. */
tr.target-hit::before,
tr.pl-focus::before { content: none; }
tr.target-hit > td,
tr.target-hit > th,
html:root tr.pl-focus.target-hit > td { background-image: linear-gradient(rgba(39, 193, 63, .18), rgba(39, 193, 63, .18)); }
@media print { tr.target-hit > td, tr.target-hit > th { background-image: none; } }

/* ───── 17. DR-Überschrift (Angabepflicht) ─────────────────────────────── */
.dr-head { display: flex; align-items: center; gap: 10px; margin: 26px 0 14px; flex-wrap: wrap; }
.dr-head:first-child { margin-top: 0; }
.dr-badge { background: var(--jr-primary-text); color: var(--jr-cta-text); font-size: 12px; font-weight: 600; letter-spacing: .4px; border-radius: var(--radius-sm); padding: 3px 8px; }

/* Diff-Status-Badges im Vergleichsmodus */
.diff-badge {
  font-family: var(--font-heading);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  border-radius: var(--radius-pill);
  padding: 2px 9px;
  color: var(--jr-cta-text);
}
.diff-badge--amended { background: var(--vw-status-amended); }
.diff-badge--new     { background: var(--vw-status-new); }
.diff-badge--deleted { background: var(--vw-status-deleted); }
.diff-badge--moved   { background: var(--vw-status-moved); }

/* Abschnitt 18 (Zwei-Spalten-Vergleichslayout: .workspace, .read-col,
   .compare-col, .cmp-col, .cmp-col-body) ist entfallen -- das Markup erzeugt
   diese Spalten nicht mehr, s. Hinweis bei Abschnitt 5. */

/* ───── 19. Footer ──────────────────────────────────────────────────────── */
.site-footer {
  margin-top: auto;
  background: var(--site-footer-bg);
  color: var(--footer-text);
  font-size: 12px;
  padding: 14px var(--sp-page); /* war 24px und damit 2px neben allen anderen Seitenraendern */
  display: flex;
  gap: 14px;
  align-items: center;
  flex-wrap: wrap;
}
.site-footer .msym { color: var(--footer-text); }
/* Two rows on purpose since 04.10.2026 (design review round 4): the
   statement with its icon, then every link in one row. Before, the
   links ran on after the statement and "Fehler melden" wrapped alone
   onto a second row from 768 to 1440px, its flag flush against the
   text (gap 0). */
.site-footer > span { flex: 1 0 calc(100% - 40px); }
.site-footer .footer-report { display: inline-flex; align-items: center; gap: 6px; }
.site-footer a { color: var(--jr-cta-text); text-decoration: underline; text-underline-offset: 2px; }
.site-footer a:hover { color: var(--jr-primary-light); }

/* Der Schliessen-Knopf gehoert zum Drawer, und den gibt es erst unter 1024px.
   Auf dem Desktop stand er bisher UNGESTYLT im Baumkopf: 18x25px, damit unter
   der WCAG-Zielgroesse 24x24 (2.5.8), und ohne jede Funktion, weil dort kein
   Drawer zu schliessen ist. Die Regel muss VOR dem Mobilblock stehen: beide
   haben dieselbe Spezifitaet, es entscheidet die Stellung im File, und der
   Mobilblock setzt display:flex spaeter und gewinnt damit dort zu Recht. */
.drawer-close { display: none; }

/* ───── 20. Mobile: Sidebar als Drawer ─────────────────────────────────── */
.drawer-scrim { position: fixed; inset: 0; background: rgba(0,0,0,.40); z-index: var(--z-drawer-scrim); display: none; }
.drawer-scrim.is-open { display: block; }

@media (max-width: 1279px) {
  .rail { display: none; }
}

/* Header at medium widths (S-5, 04.08.2026). The pill "Amtliche Fassung"
   gives way when the header row runs short: it is the cheapest loss, since
   the same address stays reachable from the footer link (t.footer_official).
   It made room for the version switch, which left with the comparison view
   on 06.10.2026; the breakpoint is kept so the header does not move. */
/* 1389px since 04.10.2026: the 13 and 14px controls (council 2, decision 3)
   need the room, section 50.24. */
@media (max-width: 1389px) {
  .hdr-right .hide-sm { display: none; }
}

@media (max-width: 1023px) {
  .layout { flex-wrap: wrap; }
  .side {
    position: fixed;
    inset: 0 auto 0 0;
    top: 0;
    height: 100dvh;
    max-height: none;
    width: 300px;
    max-width: calc(100vw - 40px);
    z-index: var(--z-drawer);
    border-radius: 0;
    /* 03.10.2026 (design director, upgrade 16): closed, the drawer's shadow
       reached 40px into the page and left a grey strip at the left edge; its
       links also stayed in the tab order while off screen. Closed it is
       shadowless and hidden -- visibility switches only after the slide-out,
       and at once on opening. */
    box-shadow: none;
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform var(--jr-duration-fast) var(--jr-ease-out),
                visibility 0s linear var(--jr-duration-fast);
    padding-top: calc(var(--hdr-h) + 10px);
  }
  .side.is-open {
    transform: translateX(0);
    box-shadow: 8px 0 32px rgba(0, 0, 0, 0.12); /* shadow.elevation.lg, sideways */
    visibility: visible;
    transition: transform var(--jr-duration-fast) var(--jr-ease-out), visibility 0s;
  }
  .hdr-menu-btn { display: inline-flex; }
  .drawer-close { position: absolute; top: 12px; right: 10px; width: 36px; height: 36px; border-radius: var(--radius-pill); display: flex; align-items: center; justify-content: center; color: var(--muted-foreground); }
  .drawer-close:hover { background: var(--muted); }

  /* Kopfzeile ohne flex-wrap/Umbruch (bewusst, damit .hdr-h fix bleibt) lief
     hier ungebremst breiter als der Viewport: brand + std-jump
     + .fontsize + .lang-switch + .hide-sm passen nicht in eine
     Zeile. .hide-sm war fuer genau diesen Zweck als Klasse im Template
     vorgesehen (base.html.j2 "pill-btn hide-sm"), hatte aber nie eine
     CSS-Regel -- das ist Teil der Root Cause, nicht nur Symptom. Amtliche
     Fassung bleibt über den Footer-Link (t.footer_official) weiter erreichbar,
     daher unkritisch zu verbergen. */
  .hide-sm { display: none; }

  /* KORREKTUR Runde 2 (siehe Review): die feste 4-Zeilen-Hoehe (206px) aus
     Runde 1 hat das Platzproblem nur verschoben -- ein dauerhaft klebender
     Block, der bei 375px ein Viertel des Viewports belegt, ist fuer eine
     Normtext-Leseansicht der falsche Tausch. Loesung an der Wurzel: die
     Kopfzeile klebt auf Mobil gar nicht mehr (position:static), sie
     scrollt mit dem Inhalt weg -- das erzwungene flex-basis:100% auf
     .std-jump/.hdr-search entfaellt damit ersatzlos, normales flex-wrap
     genuegt, die Zeilenzahl darf wieder variieren (unschaedlich, weil
     nichts mehr dauerhaft Platz beansprucht). .hdr-search bleibt trotzdem
     bei allen getesteten Breiten sichtbar/bedienbar (Suche ist der einzige
     Sucheinstieg, siehe Runde-1-Begruendung oben). */
  /* 04.10.2026: the vertical padding is what the chrome-lock's 64px leave
     after the 1px border and the 44px menu button, halved (9.5px), so one
     header row measures 64px as from 1024px, not 65px. */
  .hdr { position: static; height: auto; flex-wrap: wrap; row-gap: 8px;
         padding: calc((var(--hdr-base) - 45px) / 2) var(--sp-page); }
  .hdr-menu-btn { width: 44px; height: 44px; } /* Mindest-Trefferflaeche 44x44, siehe Review */

  /* --hdr-h auf Mobil entkoppelt: 0px statt eines geratenen Fixwerts. Sobald
     die Kopfzeile nicht mehr sticky ist, gibt es keine dauerhaft ueberlappende
     Flaeche mehr, die kompensiert werden muesste -- 0 ist der semantisch
     richtige Wert (nicht nur ein weiterer Schaetzwert), und alle bestehenden
     calc(var(--hdr-h) + X)-Stellen loesen sich dadurch automatisch korrekt
     auf, z. B. table.norm tr[id] (scroll-margin-top) auf einen kleinen
     Standardabstand ohne Sticky-Kompensation. Zwei Stellen haengen NICHT
     sauber an --hdr-h
     (siehe direkt darunter), die werden explizit entkoppelt statt ueber die
     Variable geloest. */
  /* Mobil-Fassung der Abstands-Token (P-B1). Steht bewusst NACH dem :root
     ganz oben im File -- gleiche Spezifitaet, es entscheidet die Stellung.
     --sp-col entfaellt hier ersatzlos: unter 1024px ist .rzh ausgeblendet,
     es gibt keinen Spaltenabstand mehr zu setzen. */
  :root { --hdr-h: 0px; --sp-page: 14px; --sp-card: 18px; }
}

@media (max-width: 720px) {
  /* Der Seitenrand kommt aus --sp-page, nur der Vertikalabstand weicht ab.
     ".page-card { padding: 18px }" stand frueher hier und wird jetzt ueber
     --sp-card bereits ab 1023px gesetzt. */
  .layout { padding: 14px var(--sp-page); }
}

/* ───── 21. Reduced Motion ──────────────────────────────────────────────── */
/* 03.10.2026: transitions are switched off, not shortened. transition-property
   defaults to "all", so "transition-duration: 0.01ms" on every element turned
   EVERY property change into a transition -- including the heights the
   parallel reading engine (viewer.js 21b) writes and re-measures within one
   frame. The engine then read the old geometry and over-corrected: measured on
   /de/esrs-1/ DE <-> EN at 1440px, 79 of 365 pairs off by up to 43px, only
   with reduced motion. No script listens to transitionend, so nothing waits
   for the shortened transitions. Animations keep the short duration: their
   "forwards" fill must still land on the end state. */
@media (prefers-reduced-motion: reduce) {
  * , *::before, *::after { animation-duration: 0.01ms !important; transition: none !important; }
  /* The jump target's wash (section 16) stands at once. */
  .target-hit::before,
  .pl-focus.target-hit::before { animation: none; }
}

/* ═════ 22. Additiv (Generator-Verdrahtung, pipeline/generate.py) ═════════
   Reine Ergänzungen für Blocktypen, die in den obigen Regeln noch keine
   Darstellung hatten (Fließtext ohne Randnummer, Listen, Überschriften ab
   H3/H4, Anlage-II-Tabellenzeilen, Start-/Über-Seite). Keine bestehende
   Regel wird verändert. ─────────────────────────────────────────────── */

/* Fließtext ohne Randnummer (plain_para, Listentext, Tabellenbeschriftung) */
.page-card p:not(.para) { margin: 0 0 10px; }
.page-card p:not(.para):last-child { margin-bottom: 0; }
/* 07.10.2026 (design director round 1, finding 3): in AR reading the AR part
   moves out of its card into the second pane (#splitBody > .ar-teil) and lost
   these two rules: "AR 13" stood flush under the last line of AR 12, on both
   trees. The part keeps the card's spacing (regression-parallel P21). */
.ar-teil p:not(.para) { margin: 0 0 10px; }
.ar-teil p:not(.para):last-child { margin-bottom: 0; }

/* Überschriften ab H2/H3 innerhalb einer Karte (Kapitel/DR/Anlagen). Die
   Standard-Titel-Überschrift (std_heading) ist h1 (AP6, s. generate.py), jede
   Ebene darunter entsprechend um eine Stufe verschoben -- war H3/H4. */
/* 03.10.2026 (design director, upgrade 13; design-check B2): the AR block in
   the second pane is no reading card, so its headings fell back to the
   global 26px/19px while the same headings stood at 19px/16px on the left --
   measured in AR mode on /de/e1/: "Angabepflicht E1-6 ..." 16px left, 19px
   right. Both columns now share one scale. h2 moves from 19 to 20px, the
   design system's lower bound for Fraunces (title-sm). h3 stays at 16px:
   Fraunces 20px or the sans at 16px is a decision for Jannik. */
.page-card h2, .ar-teil h2 { font-family: var(--font-display); font-weight: 600 !important; letter-spacing: -0.01em; font-size: 20px; margin: 26px 0 10px; }
.page-card h3, .ar-teil h3 { font-family: var(--font-heading); font-weight: 700; letter-spacing: -0.02em; font-size: 16px; margin: 20px 0 8px; }
.page-card h2:first-child, .page-card h3:first-child,
.ar-teil h2:first-child, .ar-teil h3:first-child { margin-top: 0; }
/* 07.10.2026 (design director round 1, finding 2), the 2026/1563 tree: each
   "Application requirements" section opens with an h4.ar-head, which touched
   the first AR (no margin). It takes the 12px step. In the second pane the
   ARs, whose label stands inline at the start of their text (span.ar-label,
   render_oj), kept the 68px number gutter empty; there heading and text share
   one left edge. In the reading card the gutter stays, so the ARs keep the
   text edge of the paragraphs they explain (regression-fassung G9).
   Only in AR reading, where the part stands in the pane itself
   (#splitBody > .ar-teil, viewer.js renderSplitAnlageA): the language pane
   mirrors the reading card, gutter included, so both languages of a pair
   keep one geometry. Without the gutter the paragraph box would hold the
   measure plus 68px of text, so the text is capped at the measure
   (regression-layout [37], 07.10.2026: 825px against 758px). */
.ar-teil .ar-head { margin: 0 0 12px; }
#splitBody > .ar-teil:has(.ar-label) { --rn-gutter: 0px; }
#splitBody > .ar-teil:has(.ar-label) .para { max-width: var(--measure); }

/* .p-actions auch an DR-Überschriften (Angabepflicht-Titel): dieselbe
   Hover-Mechanik wie .para, nur zusätzlich auf .dr-head verdrahtet, weil
   dort der Positionierungskontext (.dr-head, nicht .para) sitzt. */
.dr-head { position: relative; }
.dr-head:hover .p-actions, .dr-head:focus-within .p-actions { opacity: 1; }
.dr-head .p-actions { top: -6px; }

/* Anlage-Überschrift: etwas abgesetzt von den Standard-Kapiteln davor */
.annex-head { border-top: 1px solid var(--border); padding-top: 18px; margin-top: 30px; }
.annex-head:first-child { border-top: none; padding-top: 0; margin-top: 0; }
/* 06.10.2026 (persona review p1-p5, darstellung D13): the source opens each
   annex with a separator, which drew the browser's inset rule above the
   heading's own border, an empty band between two rules; the annex title
   under its heading drew a third. The separator is now the one rule; the
   heading after it and the title under a heading take none of their own. */
hr.separator { border: 0; border-top: 1px solid var(--border); margin: 30px 0 18px; }
hr.separator + .annex-head { border-top: none; padding-top: 0; margin-top: 0; }
.annex-head + .annex-head { border-top: none; padding-top: 0; margin-top: 6px; }
/* P5 (06.10.2026), Annex II of the 2026/1563 tree: the amending act opens the
   annex it replaces with its own "ANNEX II" and an opening quotation mark, and
   closes it with the closing one. Verbatim, but the act's frame, not a heading
   of the reproduced annex: set back as one quiet line ("ANNEX II '") right
   above the page's h1, no rule between them; the contents box then stays in
   the first screen at 720x450 as on Set 1 (darstellung D20). */
.oj-rahmen { display: inline; margin: 0; font-size: 12px; line-height: 1.5; color: var(--muted-foreground); }
/* 07.10.2026 (design director round 1, finding 4): 4px above the h1 the line
   read as a stuttered title with a dangling quotation mark. It is a line of the
   source: at the meta size (12px, CLAUDE.md type scale), its text 8px under
   the version fold (2px margin; the line is inline, and its line box adds
   about 6px of half-leading above the text), and the h1 16px below it
   (regression-fassung G8). */
.version-fold:has(+ .oj-rahmen) { margin-bottom: 2px; }
.oj-rahmen + .annex-head, .oj-rahmen + .pl-gap + .annex-head { border-top: none; margin-top: 16px; padding-top: 0; }
/* 07.10.2026: ".page-card" in the first selector. Without it the card's
   ".page-card p:not(.para)" (0,2,1) beat it, the note stood at margin-top 0
   beside its table and at 12px behind a gap (0,3,0); the gap's first pixel
   jumped by the 12px, and the note after Annex II's glossary swung 24px from
   pass to pass in coupled reading. The table's 18px wins the collapse either
   way, so nothing moves outside coupled reading. */
.page-card .tbl-wrap + .oj-rahmen, .tbl-wrap + .pl-gap + .oj-rahmen { display: block; margin-top: 12px; }
/* Coupled reading puts a .pl-gap (viewer.js gapBefore) before a paired
   heading, hidden or not, and the adjacency above broke: the heading took
   its rule, 18px padding and 30px margin back while the panes were being
   levelled, and every pair after the first annex stayed 8px apart
   (regression-parallel P1/P2). The gap is not content; the rule holds
   across it. */
hr.separator + .pl-gap + .annex-head { border-top: none; padding-top: 0; margin-top: 0; }
.annex-head + .pl-gap + .annex-head { border-top: none; padding-top: 0; margin-top: 6px; }

/* Listen (grid-container/grid-list aus der Quelle: Marker- + Textspalte) */
.grid-container.grid-list {
  display: flex;
  gap: 8px;
  margin: 0 0 8px;
  align-items: baseline;
}
.grid-list-column-1 { flex: 0 0 auto; color: var(--muted-foreground); font-variant-numeric: tabular-nums; white-space: nowrap; }
.grid-list-column-2 { flex: 1 1 auto; min-width: 0; }
.grid-list-column-2 p { margin: 0; }

/* D5 (I7 r2, verdict-VV-r1 Fund 1): jeder Sprunganker in #p-content (Anlage-II-
   Zeilen wie bisher, plus Ueberschriften- und Fussnoten-Anker, die bislang gar
   keinen Sprungabstand trugen) raeumt Kopfzeile UND Quellenleiste (#srcBar):
   ab 1024px kleben #p-content > .read-cap UND .hdr gleichzeitig (57px + 64px,
   Zeile ~3040), darunter klebt keins von beiden (--hdr-h wird dort 0, Zeile
   1091). 16px Standardabstand wie zuvor obendrauf. */
#p-content [id] { scroll-margin-top: calc(var(--hdr-h) + 16px); }
/* 03.10.2026 (design-check A5, WCAG 2.2 SC 2.4.11): the sticky band is
   header plus reading bar, 121px since the 64px header (council decision
   2; 113px before). Only targets WITH an id cleared it; with
   Shift+Tab through /de/e1/, 7 of 40 focus stops (e.g. "daneben anzeigen")
   ended up fully under the band. The band height now lives on the scroll
   container, which focus navigation honours, and the id targets keep only
   their 16px on top -- same landing line as before (121 + 16 = 137px).
   A constant, not --hdr-h: the band comes back on every upward scroll, so a
   target placed for the hidden band would end up under it. */
@media (min-width: 1024px) {
  html { scroll-padding-top: calc(var(--hdr-base) + 57px); }
  #p-content [id] { scroll-margin-top: 16px; }
}
/* 04.10.2026 (design review round 5, no. 3): where the DR badge ("E1-6")
   sits on its own row above the heading, a jump from the rail, the TOC
   or a link landed the heading and left the badge under the reading bar
   (badge top 106 against the bar's 121px at 1440). The heading's margin
   adds that row, the 25px badge and the 6px row gap, so the badge lands
   on the old line (137px). A heading with the badge beside it lands
   31px lower. Ids unchanged. */
#p-content .dr-head > [id] { scroll-margin-top: calc(var(--hdr-h) + 47px); }
@media (min-width: 1024px) {
  #p-content .dr-head > [id] { scroll-margin-top: 47px; }
}

/* Startseite: Zwischenüberschrift, ersetzt eine vormals inline gesetzte
   style="margin:0 0 8px" (CSP: style-src 'self'); Größe bleibt wie vorher als
   H3, obwohl das Element jetzt (AP6: eine H1/Seite, keine Sprünge) H2 heißt. */
.home-pick-lang { font-size: 20px; margin: 0 0 8px; }

/* Startseite: Kartenraster je Standard */
.std-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; margin-top: 6px; }
.std-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px;
  background: var(--bg-elevated);
}
.std-card h3 { margin: 0; }
.std-card p { margin: 0; color: var(--muted-foreground); font-size: 13px; flex: 1 1 auto; }
/* S-9, 06.08.2026: Bis hierher standen genau zwei Knoepfe je Karte (DE, EN)
   und passten immer nebeneinander. Mit einem dritten lief die
   Zeile aus der Karte heraus -- im Bild deutlich zu sehen, von keiner
   Zusicherung gefangen, weil die Startseite in KEINER Darstellungspruefung
   stand. Beides ist behoben: die Zeile darf umbrechen, und die Startseite
   steht jetzt in der Messmenge von regression-darstellung.mjs.
   flex-wrap allein genuegt nicht -- ein Knopf, der breiter ist als die
   Karte, bricht nicht um, sondern ragt heraus. Deshalb zusaetzlich
   min-width:0 und Umbruch innerhalb der Beschriftung. */
.std-card .std-card-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.std-card .std-card-links > .pill-btn { min-width: 0; max-width: 100%; }

/* Disabled nav placeholder (node.disabled in the tree data) */
.node.is-disabled { color: var(--muted-foreground); cursor: default; opacity: .6; }
.node.is-disabled a { pointer-events: none; }
.node-soon { font-size: 12px; margin-left: 4px; }

/* ═════════════════════════════════════════════════════════════════════════
   23. v1.1 -- Multi-Panel-Row (Baum | Lesetext | Split-Panel | Rail)
   Ersetzt/ergänzt das v1-.layout-Gerüst additiv. Referenz: Mockup + V11-
   BUILD-BLUEPRINT §3/§6. Breiten werden von viewer.js inline gesetzt
   (style.flexBasis/width); die Regeln hier liefern nur die Startwerte und
   den strukturellen Rahmen. ════════════════════════════════════════════ */
:root {
  --rz-tree-w: 264px;
  --rz-rail-w: 264px;
  /* 460 statt 420: nach dem Auto-Kollaps der Leisten erreicht der Normtext bei
     1440px seinen Deckel von 672px Lesetext und laesst Rest ungenutzt. Die
     zusaetzlichen 40px gehen deshalb an das Zweitfenster, ohne dem Normtext
     etwas zu nehmen (nachgemessen: Lesetext bleibt 672). */
  --rz-split-w: 460px;
  --rz-mini-w: 56px;
}

.rzrow {
  display: flex;
  align-items: flex-start;
  width: 100%; /* .rzrow ist selbst ein Flex-Item von .esrs-app (column). Ohne
    explizite width stretcht ein Flex-Item mit auto-Margins (siehe unten)
    NICHT auf die Cross-Achse -- es faellt auf sein eigenes width:auto
    (shrink-to-fit an den Kinder-Mindestbreiten, hier u.a. der 264px breite
    #p-tree) zurueck und wird dadurch breiter als der Viewport. width:100%
    stellt sicher, dass die Zeile immer auf Viewport-Breite (bzw. max-width)
    begrenzt bleibt; margin:auto zentriert weiterhin oberhalb von max-width. */
  /* 06.10.2026 (point 4, Jannik: "dass wir einfach die fensterbreite
     ausnutzen die da ist"): no cap on the row. The panes' own caps bound it
     (each text column 75ch, the tree 400px, the rail 560px); only what is
     left after every pane reached its cap is centred (justify-content
     below). The cap was --vw-max 1680: 142px stood empty on each side at
     1920, 462px at 2560, in coupled reading as well. --vw-max stays for
     .layout. */
  max-width: none;
  margin: 0 auto;
  padding: 20px var(--sp-page);
  gap: 0;
  min-width: 0;
  /* Letzte Stufe des Spaltenmodells (S-1): was weder die gedeckelte
     Lesespalte noch das Zweitfenster (max 640) aufnimmt, wird symmetrisch
     verteilt statt rechts liegen zu lassen. Ohne diese Zeile stuende der
     Ueberschuss als einseitige Luecke am Zeilenende. */
  justify-content: center;
}
.rzpane { min-width: 0; }

.rzrow > .rzpane#p-tree,
.rzrow > .rzpane#p-rail {
  flex: 0 0 var(--rz-tree-w);
  width: var(--rz-tree-w);
  position: sticky;
  top: calc(var(--hdr-h) + 20px);
  max-height: calc(100vh - var(--hdr-room) - 40px);
  overflow-y: auto;
}
.rzrow > .rzpane#p-rail { flex-basis: var(--rz-rail-w); width: var(--rz-rail-w); }

.rzrow > .rzpane.content#p-content {
  /* Die Basis ist bewusst das VOLLE Lesemass, nicht 0. Sonst waechst das
     Zweitfenster gleichberechtigt mit und nimmt dem Text Breite weg, bevor der
     ueberhaupt sein Mass erreicht hat: mit Basis 0 fiel der Lesetext bei
     1440px auf 510px, obwohl 672px moeglich waren (gemessen). Die Reihenfolge
     des Modells lautet: erst der Text bis zu seinem Mass, DANN der Ueberschuss
     ans Zweitfenster. Genau das drueckt die Basis aus. */
  flex: 1 1 calc(var(--measure) + var(--rn-gutter) + 2 * var(--sp-card) + 2px);
  /* SPALTENMODELL (Paket S-1, 04.08.2026). Die Lesespalte waechst NICHT mehr
     unbegrenzt. Vorher gab es zwei unabhaengige Deckel ohne Verteilregel:
     --vw-max 1680 auf der Zeile und --measure 71ch auf dem Text. Der
     Ueberschuss blieb liegen, wo er anfiel, zuletzt in der Karte: bei 2000px
     Karteninnenmass 1028 gegen Absatzbox 740, also 288px weisse Flaeche
     rechts neben dem Text. Genau das war Janniks "hier ist viel zu viel
     Platz". Umgekehrt war es am 01.08. das andere Extrem (263px Lesetext).
     Beides sind Symptome derselben fehlenden Regel.
     Der Deckel ist die Absatzbox plus das Kartenpolster beidseits, mehr
     braucht die Lesespalte nie. Ueberschuss geht ab hier an das Zweitfenster
     (siehe dessen flex-Regel) und zuletzt in die Zentrierung der Zeile. */
  max-width: calc(var(--measure) + var(--rn-gutter) + 2 * var(--sp-card) + 2px);
  /* Untergrenze, damit das Zweitfenster nur den UEBERSCHUSS bekommt und nicht
     mit der Lesespalte konkurriert. Ohne sie nahm das gewachsene Zweitfenster
     bei 1280px so viel weg, dass der Lesetext auf 350px fiel (gemessen), also
     unter die 480px-Grenze aus viewer.js CONTENT_MIN_PX. Der Wert ist
     dieselbe Rechnung: 480 Lesetext + Randnummern-Gutter + Kartenpolster. */
  min-width: calc(480px + var(--rn-gutter) + 2 * var(--sp-card) + 2px);
  /* Kein eigener Innenabstand mehr (war 0 8px). Der Spaltenabstand steckt
     vollstaendig in der Griffbreite --sp-col, sonst addieren sich zwei
     Quellen zu einem Wert, den niemand mehr benennen kann (gemessen 20px
     aus 8 + 12). Der Seitenrand kommt von .rzrow (--sp-page). */
  padding: 0;
}

.rzrow > .rzpane.splitp#p-split {
  /* Empfaenger des Ueberschusses aus dem Spaltenmodell: die Lesespalte ist
     gedeckelt, was uebrig bleibt, kommt hierher, bis 640px. Darueber hinaus
     bleibt es liegen und die Zeile zentriert es (siehe .rzrow).
     Nicht mehr "0 0", sonst faellt der Ueberschuss wieder ins Nichts.
     Zieht der Nutzer den Griff, setzt viewer.js Inline-Breiten mit
     flex "0 0 Xpx" und uebersteuert diese Regel absichtlich. */
  flex: 1 1 var(--rz-split-w);
  width: var(--rz-split-w);
  max-width: 640px;
  position: sticky;
  top: calc(var(--hdr-h) + 20px);
  max-height: calc(100vh - var(--hdr-room) - 40px);
  overflow-y: auto;
}

/* Scroll-Isolation der Nebenfenster. Ohne diese Regel (Vorgabewert "auto")
   reisst das Rad am oberen oder unteren Ende eines Nebenfensters die ganze
   Seite mit: der Leser scrollt im Zweitfenster bis zum Anschlag und verliert
   im selben Zug seine Stelle im Normtext. Genau das ist ein grosser Teil des
   gemeldeten "Hin-und-her-Springens". "contain" haelt die Kette am Container
   an, ohne den Fensterscroll sonst anzutasten -- der bleibt fuehrend und
   traegt weiterhin Deep-Links, Zuruecktaste und Druck. */
.rzrow > .rzpane#p-tree,
.rzrow > .rzpane#p-rail,
.rzrow > .rzpane.splitp#p-split,
.minipane { overscroll-behavior: contain; }

/* Zweitfenster als Vollflaeche statt als Spalte, unterhalb des Rail-Breakpoints.
   Gemessen (esrs-1, Panel offen, nach dem Auto-Kollaps): bei 1280px bleiben dem
   Normtext 518px Lesetext, bei 1279px nur 381px und bei 1024px 126px. Auch ein
   zusaetzlicher Kollaps des Baums traegt hier nicht: bei 1024px kaeme der
   Normtext auf rund 334px und bliebe unter der Untergrenze von 480px, unterhalb
   derer Gesetzesprosa mit ihren eingeschobenen Klammerverweisen zerfaellt.
   Nebeneinander gibt es deshalb erst ab 1280px; darunter deckt das Zweitfenster
   die Flaeche und der Normtext behaelt dahinter seine volle Breite. Das ist das
   Muster, das unter 1024px schon gilt, hochgezogen auf den Rail-Breakpoint.

   STELLUNG IM FILE, nicht verschieben: die Regel MUSS nach der Basisregel
   ".rzrow > .rzpane.splitp#p-split { position: sticky }" stehen. Beide haben
   dieselbe Spezifitaet (id + 3 Klassen), es entscheidet die Reihenfolge. Der
   erste Anlauf stand oben bei ".rail { display:none }" und blieb wirkungslos:
   die Basisregel weiter unten gewann und das Fenster blieb sticky. Genau diese
   Falle ist im Mobilblock schon einmal dokumentiert. */
@media (max-width: 1279px) {
  .rzrow > .rzpane.splitp#p-split {
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer);
    width: auto !important;
    max-height: none;
    border-radius: 0;
    flex-basis: auto !important;
  }
}

/* W3C-Splitter-Griff. min-height verhindert einen zu kurzen Hit-Bereich auf
   kurzen Seiten; ::before ist der sichtbare, schmale Strich. */
.rzh {
  flex: 0 0 var(--sp-col); /* zugleich der Spaltenabstand, war 12px */
  align-self: stretch;
  cursor: col-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  touch-action: none;
  min-height: 300px;
  position: sticky;
  top: calc(var(--hdr-h) + 20px);
}
.rzh::before {
  content: "";
  width: 3px;
  border-radius: 3px;
  background: var(--border);
  height: 46px;
  transition: background var(--jr-duration-fast) var(--jr-ease-out),
              height var(--jr-duration-fast) var(--jr-ease-out);
}
.rzh:hover::before,
.rzh.is-dragging::before,
.rzh:focus-visible::before { background: var(--jr-primary); height: 90px; }
/* No outline override here: the handle takes the global ring. The bar above
   alone sat far below the fold on long pages (design-check G1, 05.10.2026). */
.rzh[hidden] { display: none; }

/* ── 24. Minipane -- eingeklappte Icon-Spalte für Baum/Rail ────────────── */
.minipane {
  flex: 0 0 var(--rz-mini-w);
  width: var(--rz-mini-w);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 8px 5px;
  box-shadow: var(--shadow-sm);
  position: sticky;
  top: calc(var(--hdr-h) + 20px);
  max-height: calc(100vh - var(--hdr-room) - 40px);
  overflow-y: auto;
}
.minipane button {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  color: var(--muted-foreground);
  flex-shrink: 0;
}
.minipane button:hover { background: var(--muted); color: var(--jr-primary-text); }
.minipane button.on { color: var(--jr-primary-text); background: var(--vw-tint-success); }
.minipane .sep { height: 1px; width: 26px; background: var(--border); margin: 4px 0; flex-shrink: 0; }
/* .minipane deklariert display:flex -- ohne diese Regel würde das im
   Markup gesetzte [hidden] (User-Agent-Regel) von der Autor-Regel oben
   überstimmt und die Icon-Spalte bliebe permanent sichtbar. */
.minipane[hidden] { display: none; }

/* ── 25. Panel-Köpfe (Baum/Rail) + Gruppen-Label + Standard-Icon ────────── */
.side-head, .rail-head {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px 10px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
}
.side-head .t, .rail-head .t {
  font-family: var(--font-heading);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}
/* 06.10.2026 (Jannik: "das einklappen bei den fenster links und rechts muss
   immer sichtbar sein"): the tree and the rail scroll inside their own box,
   and the scroll spy moves the rail to the active entry; the heads with
   their collapse buttons scrolled out of sight with the list (measured on
   /de/e1/ at 1440: the rail head 13px visible under the bar). The heads
   stick to the top of their box. The tree's box has padding (--sp-panel),
   so its head sticks one padding higher and fills that strip with the
   panel's surface; the rail has none and stands on the page. Below 1024px
   the tree is the drawer, whose head carries no collapse button. */
@media (min-width: 1024px) {
  .side-head, .rail-head {
    position: sticky;
    top: 0;
    z-index: 2;
  }
  .side-head {
    top: calc(-1 * var(--sp-panel));
    margin-top: calc(-1 * var(--sp-panel));
    padding-top: calc(var(--sp-panel) + 2px);
    background: var(--bg-elevated);
  }
  .rail-head { background: var(--background); }
}
.side-head .sp { margin-left: auto; }
.rail-head .t { margin-right: auto; }
.side-head button, .rail-head button {
  display: flex;
  color: var(--muted-foreground);
  padding: 4px;
  border-radius: 6px;
  flex-shrink: 0;
}
.side-head button:hover, .rail-head button:hover { background: var(--muted); color: var(--jr-primary-text); }
.side-head button.pin[aria-pressed="true"] { color: var(--jr-primary-text); background: var(--vw-tint-success); }

.tree .grp {
  font-family: var(--font-heading);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
  padding: 12px 8px 4px;
}
.tree .grp:first-child { padding-top: 4px; }
.tree .node .stdi { font-size: 16px; color: var(--muted-foreground); }
.tree .active-node .stdi { color: var(--jr-primary-text); }

/* ── 27. Schriftgrößen-Umschalter -- skaliert nur den Normtext ──────────── */
/* 06.10.2026: no overflow hidden, as for .lang-switch (canon K18). */
.fontsize {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  flex-shrink: 0;
}
.fontsize button {
  border-radius: var(--radius-pill);
  color: var(--muted-foreground);
  font-weight: 600;
  line-height: 1;
  padding: 6px 10px;
  /* Der kleinste der drei Knoepfe kam mit 11px Schrift auf 23px Hoehe und lag
     damit unter der WCAG-Zielgroesse 24x24 (2.5.8). Die Hoehe wird gesetzt,
     nicht das Polster erhoeht, damit die drei Knoepfe gleich hoch bleiben. */
  min-height: 24px;
}
/* 05.10.2026 (design-check N6): the samples sit on the type scale at
   Inter 600: 13, 16 (the reading size "A" stands for) and 18px; 15px was
   off the scale and 700 outside Inter's 400/500/600. */
.fontsize button[data-fs="s"] { font-size: 13px; }
.fontsize button[data-fs="m"] { font-size: 16px; }
.fontsize button[data-fs="l"] { font-size: 18px; }
.fontsize button.on { background: var(--muted); color: var(--jr-primary-text); }
body.fs-s .para,
body.fs-s .ptext { font-size: 14px; line-height: 1.7; }
body.fs-l .para,
body.fs-l .ptext { font-size: 18px; line-height: 1.9; }

/* ── 28. Standard-Springer (Header) ─────────────────────────────────────── */
.std-jump {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  border-radius: var(--radius-md);
  padding: 6px 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--foreground);
  cursor: pointer;
  flex-shrink: 0;
}
.std-jump:hover { border-color: var(--jr-primary); }
.std-jump .msym { color: var(--muted-foreground); }
.std-jump .cur { color: var(--jr-primary-text); }
.std-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: var(--z-pop);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 6px;
  min-width: 220px;
  max-height: 60vh;
  overflow-y: auto;
  display: grid;
  gap: 1px;
}
.std-menu[hidden] { display: none; }
.std-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  color: var(--foreground);
  font-size: 13px;
  font-weight: 500;
}
.std-menu-item:hover { background: var(--muted); text-decoration: none; }
.std-menu-item.on { color: var(--jr-primary-text); font-weight: 600; background: var(--vw-tint-success); }
.std-menu-item .msym { color: var(--muted-foreground); flex-shrink: 0; }
.std-menu-item.on .msym { color: var(--jr-primary-text); }

/* ── 29. Quellen-Picker (links + Zweitpanel), symmetrisch ───────────────── */
.src-chip, .src-pick {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border);
  background: var(--muted);
  border-radius: var(--radius-pill);
  padding: 6px 13px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted-foreground);
  cursor: pointer;
}
.src-pick {
  background: var(--bg-elevated);
  border-radius: var(--radius-md);
  padding: 4px 10px;
  font-size: 13px;
  color: var(--jr-primary-text);
}
.src-chip:hover, .src-pick:hover { border-color: var(--jr-primary); color: var(--jr-primary-text); }
.src-pick .msym:first-child { color: var(--muted-foreground); }
.src-chip.sync-toggle { background: var(--vw-tint-success); border-color: var(--vw-tint-success-border); color: var(--jr-primary-text); }
.src-chip.sync-toggle[data-sync-off] { background: var(--bg-elevated); border-color: var(--border); color: var(--muted-foreground); }
/* Befund 1: fuer Quellen ohne Anwendungsanforderungen (z. B. ESRS 1) gibt es
   keine sinnvolle Verankerung -- der Schalter bleibt sichtbar, aber erkennbar
   deaktiviert (blasser, kein Zeiger, Begruendung im title-Attribut) statt
   stillschweigend nichts zu tun. */
.src-chip.sync-toggle:disabled {
  cursor: not-allowed;
  /* 0.8 statt der urspruenglich erwogenen 0.55 (design-check Hoch-Befund):
     opacity blendet gegen den ECHTEN Panel-Hintergrund (--muted), nicht nur
     die Chip-Farbe selbst -- bei .55 sackte der ohnehin schon blasse "aus"-
     Zustand (7,6:1 Basis) live gemessen auf ~2,6:1 ab. 0.8 haelt die Flaeche
     rechnerisch bei ~4,5:1 (WCAG AA), bleibt aber erkennbar gedaempft. */
  opacity: .8;
  background: var(--bg-elevated);
  border-color: var(--border);
  color: var(--muted-foreground);
}

.src-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: var(--z-pop);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 6px;
  /* 06.10.2026 (Jannik's screenshot 2): the menu is as wide as its longest
     entry, each entry on one line. 240px alone let "Anwendungsanforderungen
     - DE" break in the second pane, whose head sets no nowrap (the reading
     bar's picker did, so the left menu happened to hold). The viewport caps
     it; a label that would still not fit ends in an ellipsis.
     09.10.2026 (CI run 37951280670, Linux font, 320px): the cap held the
     menu, but the grid track kept the widest entry's width, and every entry
     ran 7px past the menu's edge. The track now ends where the menu ends. */
  min-width: 240px;
  width: max-content;
  max-width: calc(100vw - 32px);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1px;
  text-align: left;
}
.src-menu[hidden] { display: none; }
.src-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--foreground);
  font-size: 13px;
  font-weight: 500;
  text-align: left;
  width: 100%;
  white-space: nowrap;
}
.src-menu-item > span:not(.src-menu-note) { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.src-menu-item:hover:not(:disabled) { background: var(--muted); }
.src-menu-item.on { color: var(--jr-primary-text); font-weight: 600; background: var(--vw-tint-success); }
.src-menu-item:disabled { color: var(--vw-text-disabled); cursor: not-allowed; }
.src-menu-item .msym { color: var(--muted-foreground); flex-shrink: 0; }

/* ── 30. Split-Panel (Zweitpanel in der Mitte) ──────────────────────────── */
.splitp {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 0 18px 18px;
}
/* Befund 4: linkes (.read-cap, Lesekarte) und rechtes (.split-cap, Zweitpanel)
   Fenster teilen sich denselben Kopfaufbau -- Quellen-Auswahl, Tausch,
   Schliessen (links ohne Schliessen) -- ueber die gemeinsame .panel-cap-Basis;
   nur die Bleed-Masse unterscheiden sich (unterschiedliches Karten-Padding). */
.panel-cap {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--muted);
  flex-wrap: wrap;
}
.panel-cap .src-pick { margin-right: auto; }
/* U-3 (07.08.2026): Die Leiste bleibt beim Rollen stehen. Sie traegt
   Quellenwahl, Tauschen und SCHLIESSEN und lag bis hierher als gewoehnlicher
   Kasten im scrollenden #p-split. Solange das Zweitfenster immer bei 0 aufging,
   ist das nie aufgefallen; seit ein Querverweis den ganzen Zielstandard laedt
   und an die genannte Stelle springt, faengt es 22022 bis 34324 Pixel oberhalb
   des Sichtfensters an -- der Nutzer sieht beim Oeffnen keinen Weg zurueck.
   top:0 statt eines Versatzes, weil #p-split selbst der Scrollkasten ist und
   seine Oberkante schon unter der Kopfzeile der Seite liegt. Hintergrund traegt
   die Leiste ueber .panel-cap bereits (var(--muted)), sie ist also nicht
   durchscheinend. z-index unter --z-pop, damit Popover weiter darueber liegen. */
.split-cap {
  margin: 0 -18px 14px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  position: sticky;
  top: 0;
  z-index: 120;
}
.read-cap {
  margin: -24px -24px 20px;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
}
.split-cap > button:not(.src-pick) {
  color: var(--muted-foreground);
  display: flex;
  align-items: center;
  justify-content: center;
  /* 36x36 statt der vorherigen 4px-Padding-Groesse (~26x26, design-check
     Mittel-Befund: unter dem 44px-Zielwert und kleiner als vergleichbare
     Icon-Buttons im selben File, z. B. .drawer-close 36x36). */
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  flex-shrink: 0;
}
/* .read-cap-Aktionen ("Zweites Fenster", "DE <-> EN"): kompakte Icon+Label-
   Buttons statt der frueheren freistehenden .pill-btn-Reihe -- gehoeren jetzt
   in den Panel-Kopf, nicht mehr lose ueber die Standard-Pager-Karte gestapelt. */
.panel-cap .cap-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: var(--radius-md);
  font-size: 13px;
  font-weight: 600;
  color: var(--muted-foreground);
  flex-shrink: 0;
  white-space: nowrap;
}
/* 05.10.2026 (design-check F4): hover stays on the bar's own --muted. On
   --border the green label reached 4.34:1 (WCAG 1.4.3 asks 4.5:1); on
   --muted it has 5.00:1, and the label's turn to green is the hover cue.
   White stays the pressed state (section 50.8). */
.panel-cap .cap-btn:hover { background: var(--muted); color: var(--jr-primary-text); }
.split-cap > button:not(.src-pick):hover { background: var(--muted); color: var(--jr-primary-text); }
.split-cap .src-pick { margin-right: auto; }
#splitBody .para { font-size: 16px; }
#splitBody .sv[hidden] { display: none; }
.split-empty { color: var(--muted-foreground); font-size: 13px; padding: 10px 4px; }
.split-note { font-size: 12px; color: var(--muted-foreground); font-style: normal; margin-top: 6px; padding: 0 4px; } /* 06.10.2026: upright (C2) */

/* ── 30d. EFRAG-Erläuterungen im Zweitfenster (Paket F-2) ────────────────────
   Der Non-authoritative-Hinweis steht sichtbar oben in der Quelle, nicht im
   Kleingedruckten (Auftrag). Absätze ohne Erläuterung bleiben als schmale,
   gedämpfte Zeile stehen: sie tragen den data-key, an dem der Scroll-Sync
   hängt, und eine ausdrückliche Leermeldung ist ehrlicher als eine Lücke.
   Farben nur über Token; für Text und Icons --jr-primary-text (#187A28),
   nie --jr-primary (#27C13F erreicht gegen Weiß nur 2,39:1). */
.efrag-head { margin-bottom: 14px; }
.efrag-note {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--foreground);
  background: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 9px 11px;
}
.efrag-note .msym { color: var(--jr-primary-text); flex-shrink: 0; }
.efrag-count { font-size: 12px; color: var(--muted-foreground); margin-top: 7px; padding: 0 2px; }
.efrag-item { padding: 9px 4px; border-bottom: 1px solid var(--border); }
.efrag-item:last-child { border-bottom: 0; }
.efrag-ref {
  font-family: var(--font-heading);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}
.efrag-item.is-empty { padding: 5px 4px; display: flex; align-items: baseline; gap: 10px; }
.efrag-leer { font-size: 12px; color: var(--muted-foreground); }
.efrag-entry { margin-top: 6px; }
.efrag-entry + .efrag-entry { margin-top: 12px; border-top: 1px dashed var(--border); padding-top: 10px; }
.efrag-title { font-size: 14px; font-weight: 600; line-height: 1.35; color: var(--foreground); }
.efrag-meta { font-size: 12px; color: var(--muted-foreground); margin-top: 2px; }
.efrag-kurz { font-size: 13px; line-height: 1.5; margin-top: 5px; }
.efrag-entry .pop-action { margin-top: 7px; }
/* Basisregel zuerst, der Media-Override kommt weiter unten. Umgekehrt bliebe er
   wirkungslos (gleiche Spezifität, Stellung im File entscheidet). */
.efrag-schmal { display: none; }

/* Schmales Fenster (< 1024px): dort liegt das Zweitfenster als Vollbild über
   dem Normtext, die Kopplung ist abgeschaltet (viewer.js SYNC-2). Damit haben
   die Absätze ohne Erläuterung ihren einzigen Zweck verloren, den Ankerpunkt:
   gemessen bei 390px waren es 46.456 px Inhaltshöhe, davon fünf Sechstel
   Leermeldungen. Sie werden hier ausgeblendet, und die Anzeige sagt das. */
@media (max-width: 1023px) {
  .efrag-item.is-empty { display: none; }
  .efrag-schmal {
    display: block;
    font-size: 12px;
    color: var(--muted-foreground);
    margin-top: 5px;
    padding: 0 2px;
  }
}

/* Weicher Übergang beim Öffnen des Zweitpanels (Blueprint "richtig geil"-
   Polish, §8) -- reine Präsentation, keine Scroll-Manipulation. */
.splitp.rzpane {
  transition: opacity var(--jr-duration-fast) var(--jr-ease-out),
              transform var(--jr-duration-fast) var(--jr-ease-out);
}
.splitp.rzpane.is-entering { opacity: 0; transform: translateX(12px); }
@media (prefers-reduced-motion: reduce) {
  .splitp.rzpane.is-entering { opacity: 1; transform: none; }
}

/* Version comparison badges show only when two versions stand side by side
   (.badges-active); otherwise inert, even if imported content carried
   matching classes. Since 06.10.2026 no script sets .badges-active (the
   comparison view left); the rules stay for a later comparison (design-check
   A12). */
.splitp:not(.badges-active) .status-badge,
.splitp:not(.badges-active) .diff-badge { display: none; }
.splitp:not(.badges-active) .para.p-amended,
.splitp:not(.badges-active) .para.p-new {
  background: none;
  box-shadow: none;
  padding-left: var(--rn-gutter);
}

/* ── 30b. Inhaltsverzeichnis als Aufklapper ─────────────────────────────────
   Das Inhaltsverzeichnis gehört zum amtlichen Text jedes Standards und bleibt
   deshalb vollständig und an seiner Stelle im Dokument (K1). Zugeklappt gibt es
   den Leseweg frei: gemessen 1967 px Desktop und 3253 px mobil, die den ersten
   Normsatz auf 2460 bzw. 4450 px gedrückt haben.
   Nur bestehende Token, keine neuen Farben. */
.toc-fold,
.version-fold { margin: 0 0 18px; }
.toc-fold > summary,
.version-fold > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  min-height: 44px;                 /* Touch-Ziel */
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--muted);
  color: var(--foreground);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  transition: background var(--jr-duration-fast) var(--jr-ease-out);
}
.toc-fold > summary::-webkit-details-marker,
.version-fold > summary::-webkit-details-marker { display: none; }
.toc-fold > summary:hover,
.version-fold > summary:hover { background: var(--bg-elevated); }
/* Kein eigener Fokusring: die globale :focus-visible-Regel greift und ist jetzt
   kontraststark. Doppelt gepflegte Ringe laufen sonst auseinander. */
.toc-fold > summary .msym,
.version-fold > summary .msym {
  color: var(--jr-primary-text);
  flex: none;
}
.toc-fold-hint {
  margin-left: auto;
  font-weight: 500;
  font-size: 13px;
  color: var(--muted-foreground);
}
.toc-fold[open] > summary,
.version-fold[open] > summary { margin-bottom: 10px; }
/* 07.10.2026 (design director round 1, finding 11): after a heading the box
   stood 4px (the h1 of 2026/1563) or 10px (the title h2 of Set 1) below it,
   closer than the heading's own lines. 16px on the 4px grid; the margins
   collapse, so the larger one decides (regression-darstellung D23). */
:is(h1, h2, h3) + .toc-fold { margin-top: 16px; }
/* Zustand am Winkel, nicht am verschwindenden Text: ein per visibility
   ausgeblendeter Hinweis wuerde auch den zugaenglichen Namen desselben
   Bedienelements aendern. Der Hinweis bleibt darum stehen und nennt die
   Eintragszahl. */
.toc-fold > summary .msym-state,
.version-fold > summary .msym-state { margin-left: 4px; }
.toc-fold > summary .msym-more,
.version-fold > summary .msym-more { display: inline-flex; }
.toc-fold > summary .msym-less,
.version-fold > summary .msym-less { display: none; }
.toc-fold[open] > summary .msym-more,
.version-fold[open] > summary .msym-more { display: none; }
.toc-fold[open] > summary .msym-less,
.version-fold[open] > summary .msym-less { display: inline-flex; }

/* ── 30b1. Inhalt von Anhang II (06.10.2026, Persona p5) ────────────────────
   Anhang II hatte keinen Weg zu seinen zwei Tabellen: bei 720x450 (200 % Zoom)
   gibt es keine Rail, und die Tabelle 2 beginnt weit unter dem Bildschirm.
   Der Kasten spricht die Sprache des Inhaltsverzeichnisses (Rahmen, Fläche,
   Radius, 44-px-Ziel), ist aber eine schlichte Liste, kein Aufklapper: zwei
   Einträge brauchen keinen Griff. Die Einträge stehen nebeneinander, sonst
   ragt der Kasten bei 720x450 über den ersten Bildschirm (zwei gestapelte
   Zeilen: Unterkante 488 px bei 450 px Fenster); wo die Breite nicht reicht,
   brechen sie von selbst untereinander um. Nur bestehende Token, keine neuen
   Farben. Kein overflow:hidden, damit der Fokusring nicht abgeschnitten wird. */
.annex2-nav { margin: 0 0 18px; }
.annex2-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.annex2-nav li {
  flex: 1 1 auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--muted);
}
.annex2-nav a {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100%;
  box-sizing: border-box;
  padding: 4px 14px;
  min-height: 44px;                 /* Touch-Ziel */
  border-radius: var(--radius-md);
  color: var(--foreground);
  font-size: 14px;
  line-height: 1.3;
  text-decoration: none;
  transition: background var(--jr-duration-fast) var(--jr-ease-out);
}
.annex2-nav a:hover { background: var(--bg-elevated); }
.annex2-nav-num { font-weight: 600; color: var(--jr-primary-text); }
.annex2-nav-cap { font-weight: 600; }
.annex2-nav-count {
  font-weight: 500;
  font-size: 13px;
  color: var(--muted-foreground);
}

/* ── 30b1b. Begriffe filtern, Anhang II Tabelle 2 (06.10.2026, Persona p5) ───
   Das Feld steht über der Tabelle der 200 Begriffsbestimmungen. Sichtbare
   Beschriftung, kein Platzhalter als Ersatz; die Zeile darunter nennt die Zahl
   (aria-live). Ausgeblendete Zeilen tragen hidden: die Regel sichert, dass
   keine Tabellenregel sie wieder einblendet. Nur bestehende Token. */
.term-filter {
  display: grid;
  gap: 6px;
  margin: 0 0 14px;
  max-width: 420px;
}
.term-filter-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--foreground);
}
.term-filter-input {
  box-sizing: border-box;
  width: 100%;
  min-height: 44px;                 /* Touch-Ziel */
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--background);
  color: var(--foreground);
  font: inherit;
  font-size: 15px;
}
.term-filter-status {
  font-size: 13px;
  color: var(--muted-foreground);
}
tr[id^="term-"][hidden] { display: none; }

/* ── 30b2. Fassungsleiste und Ersetzungsvermerk (Paket 3, 27.07.2026) ───────
   Die Leiste teilt Griff und Zustandslogik mit dem Inhaltsverzeichnis (oben
   mitverwendete Selektoren), damit es nur EINEN Aufklapper-Stil gibt. Eigen
   ist nur der Inhalt. Nur bestehende Token, keine neuen Farben. */
.version-fold > summary .version-fold-label {
  font-weight: 500;                 /* die Standangabe ist Beleg, keine Aktion */
  font-size: 13px;
  color: var(--muted-foreground);
}
/* Optisch weg, fuer assistive Technik da: sichtbar traegt der Griff die
   Standangabe, aber wer ihn nur vorgelesen bekommt, erfaehrt daraus nicht, dass
   sich dahinter der Rechtsnachweis aufklappt. Dieselbe Technik wie am
   Pager-Richtungswort weiter unten, NICHT display:none (das nimmt den Text auch
   aus dem Barrierefreiheitsbaum). */
.version-fold > summary .version-fold-purpose {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.version-bar {
  margin: 0;
  display: grid;
  gap: 8px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  font-size: 13px;
}
.version-row { display: grid; gap: 2px; }
.version-row dt {
  font-family: var(--font-heading);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}
.version-row dd { margin: 0; color: var(--foreground); }
.version-bar-note {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--muted-foreground);
}
/* Ab der Lesebreite zweispaltig: Beschriftung links, Wert rechts. Darunter
   bleibt es gestapelt, weil die Werte (Rechtsaktbezeichnungen mit Fundstelle)
   sonst auf drei Zeilen umbrechen. */
@media (min-width: 720px) {
  .version-row { grid-template-columns: 210px 1fr; gap: 12px; align-items: baseline; }
}

/* Ersetzungsvermerk an einer amtlichen Aenderungsmarke. Amber wie .editorial,
   weil es dieselbe Sprechhaltung ist (unsere Zutat am amtlichen Text), aber
   kompakter: er sitzt zwischen Normtext und darf ihn nicht verdraengen. */
.amend-note {
  display: flex;
  gap: 10px;
  border: 1px solid var(--vw-tint-warning-border); /* no left edge (N5) */
  border-radius: var(--radius-md);
  background: var(--vw-tint-warning);
  padding: 10px 14px;
  margin: 14px 0;
  font-size: 13px;
  color: var(--foreground);
}
.amend-note .msym { color: var(--feedback-warning); flex: none; } /* F1 */
.amend-note p { margin: 0; }
.amend-note-label {
  font-family: var(--font-heading);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  /* NICHT --vw-tint-warning-text wie .editorial-label:
     selbst nachgerechnet erreicht #9A6A00 auf #FFF7EC nur 4,46:1 und verfehlt
     damit WCAG 1.4.3 (4,5:1) fuer diesen 10,5px-Text knapp. Das ist ein
     Altbefund an den beiden bestehenden Klassen und im Bericht vermerkt; er
     wird hier nicht wiederholt. --vw-tint-amended-text ist ein bestehendes
     Token (keine neue Farbe), erreicht auf derselben Flaeche 6,01:1 und ist
     zudem das semantisch naechste: es steht im Projekt fuer "geaendert". */
  color: var(--vw-tint-amended-text);
  margin-bottom: 3px;
}

/* Gedruckt wird der amtliche Text vollstaendig. Ein zugeklapptes <details>
   druckt sonst zugeklappt, das Verzeichnis fehlte im Ausdruck und im
   Browser-PDF. */
@media print {
  .toc-fold > summary { display: none; }
  .toc-fold > summary + * { display: block !important; }
  .toc-fold::details-content { content-visibility: visible; }
  /* Die Fassungsleiste wird im Ausdruck aufgeklappt gezeigt, ihr Griff bleibt
     aber sichtbar: er traegt die Standangabe, auf einem Ausdruck die
     wichtigste Zeile der Seite. */
  .version-fold::details-content { content-visibility: visible; }
  .version-fold > summary + * { display: block !important; }
}

/* ── 30c. Lesebreite ───────────────────────────────────────────────────────
   Deckel auf die TEXTSPALTE, damit die Zeile auf breiten Schirmen nicht
   ausufert. Tabellen bleiben ausgenommen, sie brauchen die Breite und haben
   ihren eigenen Scrollbereich (.tbl-scroll).

   Zwei Fallen, beide beim Nachmessen aufgefallen und hier bewusst behandelt:
   1. `ch` ist NICHT "Zeichen". Inter setzt die Null mit 0,631 em, deutsche
      Prosa liegt im Mittel bei 0,520 em. 71ch sind also rund 86 gesetzte
      Zeichen, nicht 71. Der Wert ist nach der gemessenen Kartenbreite
      gewaehlt, nicht nach einer Zeichenzahl-Faustregel.
   2. Global gilt box-sizing:border-box, und .para traegt links den
      Randnummern-Gutter (--rn-gutter, 68 px). Ein nackter Deckel begrenzt
      damit die Absatzbox, nicht die Textspalte, und Listen ohne Gutter
      wuerden BREITER als Absaetze. Deshalb wird der Gutter aufgeschlagen.

   Zielgenau: .para (numerierte Absaetze), p.list (Listenabsaetze) und das
   Listen-Grid, dessen zweite Spalte den eigentlichen Listentext traegt.
   NICHT .normal -- das sind ausschliesslich Absaetze INNERHALB von Tabellen
   (327 von 327 im Build), also genau das, was ausgenommen bleiben soll.
   Container ist .content -- das ist der Lesespalten-Container im heutigen
   Markup. (Diese Regel zielte zunaechst auf .read-col aus dem alten
   Zwei-Spalten-Layout und griff deshalb nie; jener Selektor ist inzwischen
   samt zugehoerigem CSS/JS entfernt.) */
:root { --measure: 71ch; }
.content .para { max-width: calc(var(--measure) + var(--rn-gutter)); }
.content p.list { max-width: var(--measure); }
/* DER AUSGLEICH MUSS AUCH UNTER DEM DECKEL GELTEN.
   Der Absatz traegt links die Randnummernspalte als Polster (--rn-gutter,
   68px, Zeile 502); die Listenzeile traegt nur ihren Marker (gemessen 11,7
   bis 20,1px, dazu 8px Abstand). Der Deckel oben glich das aus: --measure+68
   gegen --measure+28 ergibt beidesmal --measure Textkoerper.
   Das trug aber nur, SOLANGE BEIDE DECKEL GREIFEN. E-2 hat --measure von
   71ch auf 82,5ch gehoben (Zeile 2631) und E-8 laesst ab 1400px beide Leisten
   offen -- seither ist die Karte schmaler als beide Deckel, keiner greift, und
   die Gutter-Differenz schlaegt ungedaempft durch: gemessen 718px Absatztext
   gegen 760px Listentext, 42px Unterschied bei einer zugesicherten Grenze von
   25px.
   Der Aufschlag wird deshalb als Aussenabstand gefuehrt statt nur als Deckel.
   Wo der Deckel greift, aendert sich nichts (verfuegbar - 40 ergibt genau
   --measure + 28); wo er nicht greift, wirkt er weiter.
   Gemessen ueber alle Listenzeilen der Seite, schlechteste Zeile:
       1280 / 1400 / 1440 / 1460 / 1480 / 1600 / 2000  -> je 8px Abweichung.
   Die restlichen 8px sind die Streuung der Markerbreiten gegen die Pauschale
   28px; sie war vorher schon da und liegt unter der Schwelle. */
.content .grid-container.grid-list {
  max-width: calc(var(--measure) + 28px);
  margin-right: calc(var(--rn-gutter) - 28px);
}

/* 03.10.2026 (design director, upgrade 1): the points of a paragraph started
   at the card edge, left of their own paragraph number -- measured on /de/e1/
   at 1440px: number "44." at x=361, its text at 395, points a)-d) at 327. The
   norm's hierarchy read upside down on every page and in both columns. Points
   and the continuation text after them (p.list) now start where the paragraph
   text starts, as in the official layout; the gutter becomes their left
   margin, so the right-hand compensation above is no longer needed. Only
   blocks directly in a reading card or the AR block: nested points already
   sit in their parent's text column, and lists in tables keep their cells. */
.page-card > .grid-container.grid-list,
.page-card > p.list,
.ar-teil > .grid-container.grid-list,
.ar-teil > p.list { margin-left: var(--rn-gutter); }
/* Same right edge as the paragraph text, capped or not: the points live in
   the paragraph's text column and are narrower only by their marker. */
.content .grid-container.grid-list { max-width: var(--measure); margin-right: 0; }

/* ── 31. Standard-Pager (voriger/nächster Standard) ─────────────────────── */
.std-pager-row { display: flex; gap: 12px; margin: 4px 0 16px; flex-wrap: wrap; }
.std-pager-row.top { margin-bottom: 16px; }
.std-pager-row .std-pager { flex: 1 1 240px; }
.std-pager {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px 18px;
  box-shadow: var(--shadow-sm);
  color: var(--foreground);
  transition: transform var(--jr-duration-fast) var(--jr-ease-out),
              box-shadow var(--jr-duration-fast) var(--jr-ease-out),
              border-color var(--jr-duration-fast) var(--jr-ease-out);
}
.std-pager:hover {
  text-decoration: none;
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  border-color: var(--vw-tint-success-border-hover);
}
.std-pager.next { justify-content: flex-end; text-align: right; }
.std-pager .dir { font-family: var(--font-heading); font-size: 12px; font-weight: 700; letter-spacing: .06em; color: var(--muted-foreground); text-transform: uppercase; display: block; }
.std-pager .pg-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.std-pager .nm { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-heading); font-size: 16px; font-weight: 600; letter-spacing: -0.02em; }
.std-pager.next .nm { flex-direction: row-reverse; }
.std-pager .tag { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; background: var(--jr-primary-text); color: var(--jr-cta-text); border-radius: var(--radius-sm); flex-shrink: 0; }
.std-pager > .msym { margin-left: auto; color: var(--jr-primary-text); flex-shrink: 0; }
.std-pager.prev > .msym { margin-left: 0; margin-right: auto; order: -1; }

/* ── 32. AR-Zeile unter der DR-Überschrift ──────────────────────────────── */
.ar-line {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--muted-foreground);
  margin: 0 0 16px;
  flex-wrap: wrap;
}
.ar-line .msym:first-child { color: var(--jr-primary-text); flex-shrink: 0; }
.ar-line .ar-line-label { color: var(--muted-foreground); }
.ar-open {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  border-radius: var(--radius-pill);
  padding: 3px 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--jr-primary-text);
}
.ar-open:hover { border-color: var(--jr-primary); background: var(--vw-tint-success); }

/* ── 33. Glossarbegriffe -- gestrichelte Unterstreichung, cursor:help ───── */
.gloss { border-bottom: 1px dashed var(--jr-primary); cursor: help; }
.gloss:hover, .gloss.pop-trigger.is-open { background: var(--vw-tint-success-hover); }

/* ── 34. Dynamisches Popover (Glossar/Xref, aus .pop-tpl geklont) ───────── */
.pop-dyn {
  top: calc(100% + 8px);
  left: 0;
  width: 340px;
  max-width: min(340px, 82vw);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  color: var(--foreground);
  padding: 14px;
}
.pop-dyn .pop-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 2px; }
.pop-dyn .pop-action { justify-content: flex-start; }
.pop-dyn .pop-hint { font-size: 12px; color: var(--muted-foreground); margin-top: 8px; }

/* ── 35. Ziel-Einheit beim Scroll-Sync -- a tint, no left stripe ───────── */
/* 04.10.2026 (design-check A12): the 3px stripe here never showed (50.3
   sets the tint below); the base rule now says the same, so the stripe
   cannot return when 50.3 changes. */
.sync-active { background: rgba(39, 193, 63, 0.08); border-radius: 2px; }

/* ── 36. Fassungsvergleich -- Status-Farben (nur wenn text ⇄ neu) ───────── */
.status-badge {
  font-family: var(--font-heading);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  border-radius: var(--radius-pill);
  padding: 2px 8px;
  color: var(--jr-cta-text);
  vertical-align: middle;
}
.status-badge.amended { background: var(--vw-status-amended); }
.status-badge.new     { background: var(--vw-status-new); }
.status-badge.deleted { background: var(--vw-status-deleted); }
.status-badge.moved   { background: var(--vw-status-moved); }
/* 04.10.2026 (design-check A12): no generated page carries these classes
   today; should the version comparison mark paragraphs again, it marks
   them by the tint alone, without the 3px stripe (llms.txt rule 4). */
.para.p-amended { background: linear-gradient(90deg, var(--vw-tint-warning), transparent); padding-left: calc(var(--rn-gutter) + 8px); border-radius: 2px; }
.para.p-new     { background: linear-gradient(90deg, var(--vw-tint-success), transparent); padding-left: calc(var(--rn-gutter) + 8px); border-radius: 2px; }
.para.p-deleted { color: var(--muted-foreground); }
.para.p-deleted .ptext { text-decoration: line-through; text-decoration-color: var(--vw-tint-deleted-strike); }
.legend { display: flex; gap: 12px; font-size: 12px; color: var(--muted-foreground); flex-wrap: wrap; align-items: center; }
.legend span { display: inline-flex; align-items: center; gap: 5px; }
.legend .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.legend .dot.amended { background: var(--vw-status-amended); }
.legend .dot.new     { background: var(--vw-status-new); }
.legend .dot.deleted { background: var(--vw-status-deleted); }
.legend .dot.moved   { background: var(--vw-status-moved); }

/* justReporting-Einordnung (nicht amtlich) -- Amber-Optik wie .editorial */
.jr-note {
  background: var(--vw-tint-warning);
  border: 1px solid var(--vw-tint-warning-border);
  border-radius: var(--radius-md);
  padding: 10px 14px;
  font-size: 13px;
  margin: 8px 0 16px;
}
.jr-note .n-label {
  font-family: var(--font-heading);
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--vw-tint-warning-text);
  margin-bottom: 4px;
}

/* ── 37. Such-Filter (Kopfzeile + Rail) ──────────────────────────────────── */
.search-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  z-index: var(--z-pop);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 12px;
  max-height: 70vh;
  overflow-y: auto;
  font-size: 13px;
}
.filter-chiprow { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  font-weight: 500;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 5px 11px;
  color: var(--muted-foreground);
}
.filter-chip.on { background: var(--vw-tint-success); border-color: var(--jr-primary); color: var(--jr-primary-text); }
.search-hit { display: block; padding: 8px 8px; border-radius: var(--radius-sm); color: var(--foreground); border-bottom: 1px solid var(--border); }
.search-hit:last-child { border-bottom: none; }
.search-hit:hover { background: var(--muted); text-decoration: none; }
.search-hit .sh-std { font-family: var(--font-heading); display: block; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--jr-primary-text); margin-bottom: 2px; }
.search-hit .sh-snippet { display: block; font-size: 13px; color: var(--muted-foreground); }
.search-empty { color: var(--muted-foreground); font-size: 13px; padding: 6px 8px; }
/* P-1: der Ausweg aus dem Leertreffer. Steht bewusst direkt unter der
   Leermeldung und traegt einen echten Knopf, keinen Link -- er wechselt den
   Suchumfang, er navigiert nicht. Farbe ist --jr-primary-text (#187A28,
   nachgerechnet 5,45:1 auf Weiss), NICHT --jr-primary (#27C13F, 2,39:1). */
.search-empty-action {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 2px 8px 8px;
  font-size: 13px;
  color: var(--muted-foreground);
}
.search-empty-action button {
  font: inherit;
  color: var(--jr-primary-text);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 12px;
  min-height: 24px;
  cursor: pointer;
}
.search-empty-action button:hover { background: var(--bg-elevated); }
.search-scope-note { font-size: 12px; color: var(--muted-foreground); font-style: normal; padding: 4px 8px 8px; } /* 06.10.2026: upright (C2) */

/* ── 37a. Below 1024px the page recedes behind the results ───────────────
   06.10.2026 (persona p4, search-375): the panel stops at 70vh, and right
   under its edge the page went on at the same weight; a hit line cut by the
   edge met a line of the page, and the two read as text showing through.
   Measured: every point inside the panel hits the panel, so its background
   was never the cause. While the panel is open the page lies under the
   drawer's scrim and the header above it (the split pane's sticky cap at
   120 stays under it too); a tap on the scrim closes the panel through the
   mousedown handler in initSearch, as a tap on the page did. From 1024px
   the panel stays a plain dropdown under the sticky header. */
@media (max-width: 1023px) {
  body:has(#searchPanel:not([hidden]))::after {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,.40);
    z-index: var(--z-drawer-scrim);
  }
  body:has(#searchPanel:not([hidden])) .hdr { z-index: calc(var(--z-drawer-scrim) + 1); }
}

/* ── 37b. Search rows: type and number in one line (triage row 15) ──────────
   06.10.2026: a row reads "ESRS 1 · ABSATZ 37" or "... ABSATZ 14 a)". The type
   keeps its capitals; the number is the page's own text and stays as printed
   (a capital A would turn "14 a)" into "14 A)"). */
.search-hit .sh-head { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 5px; margin-bottom: 2px; }
.search-hit .sh-head .sh-std { display: inline; margin-bottom: 0; }
.search-hit .sh-ref { font-family: var(--font-heading); font-size: 11px; font-weight: 700; letter-spacing: .04em; color: var(--jr-primary-text); }
/* Triage row 17: the count above the rows, the match in a mark, and the live
   region that announces the count (kept out of the panel, which is rebuilt). */
.search-count { font-size: 12px; font-weight: 600; color: var(--muted-foreground); padding: 2px 8px 6px; }
.search-hit mark { background: var(--ev-mark-fill-amber); color: var(--foreground); font-weight: 600; border-radius: 2px; padding: 0 1px; }
/* Triage row 18: the two chip groups sit in the old row; the row the arrows
   are on carries the focus ring, because the focus itself stays in the field. */
.filter-chiprow .filter-chipgroup { display: flex; flex-wrap: wrap; gap: 6px; }
.search-hit.is-active { background: var(--muted); outline: 2px solid var(--jr-primary-text); outline-offset: -2px; }
/* Triage row 19: "All standards" groups the rows by standard, each with its count. */
.search-group + .search-group { margin-top: 6px; }
.search-group-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding: 6px 8px 4px; border-bottom: 1px solid var(--border); font-family: var(--font-heading); font-size: 12px; font-weight: 700; color: var(--foreground); }
.search-group .sg-count { color: var(--muted-foreground); font-weight: 600; }
.search-loading { font-size: 12px; color: var(--muted-foreground); padding: 6px 8px; }
.search-status { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ── 38. content-visibility -- sichere Rendering-Auslagerung ─────────────
   NUR :auto, NIE :hidden (Strg+F/Anker müssen greifen). Sektionsebene
   (.page-card), keine granularere Ebene. */
.page-card {
  content-visibility: auto;
  contain-intrinsic-size: auto 1200px;
}

/* ── 39. Hintbar-Zeile + Panel-Container-Konsistenz ─────────────────────── */
/* width:100% aus demselben Grund wie .rzrow/.layout: direktes Flex-Item von
   .esrs-app (column) mit margin:auto -- ohne width faellt es auf shrink-to-fit
   zurueck statt auf Viewportbreite zu stretchen. */
/* 06.10.2026 (point 4): no cap, like .rzrow, so a hint stands over the row it belongs to. */
.hintbar-row { width: 100%; max-width: none; margin: 0 auto; padding: 0 var(--sp-page); }
.hintbar-row .hintbar:last-child { margin-bottom: 20px; }

/* ── 40. Mobil: v1.1-Panels ausblenden/stapeln (<1024px) ────────────────── */
@media (max-width: 1023px) {
  .rzrow { padding: 10px 0; }
  .rzh { display: none; }
  .minipane { display: none; }
  .rzrow > .rzpane.content#p-content { padding: 0 var(--sp-page); }
  .rzrow > .rzpane#p-rail { display: none; }

  /* Selektor bewusst identisch zur Desktop-Basisregel (Abschnitt 23:
     ".rzrow > .rzpane#p-tree { position: sticky; ... }", Spezifitaet id+2
     Klassen). Der vorherige, einfachere Selektor "#p-tree.rzpane" (id+1
     Klasse) hatte NIEDRIGERE Spezifitaet als die Basisregel und wurde daher
     trotz Media-Query-Gueltigkeit von "position: sticky" ueberstimmt -- der
     Baum blieb dadurch mobil im Fluss (264px breites Flex-Item) statt als
     Off-Canvas-Drawer aus dem Fluss genommen zu werden. Gleiche Spezifitaet
     + spaeter im Stylesheet = diese Regel gewinnt jetzt zuverlaessig. */
  .rzrow > .rzpane#p-tree {
    position: fixed;
    inset: 0 auto 0 0;
    top: 0;
    height: 100dvh;
    max-height: none;
    width: 300px;
    max-width: calc(100vw - 40px);
    z-index: var(--z-drawer);
    border-radius: 0;
    /* Closed: no shadow strip, out of the tab order (see .side above). */
    box-shadow: none;
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform var(--jr-duration-fast) var(--jr-ease-out),
                visibility 0s linear var(--jr-duration-fast);
    /* Bewusst NICHT an --hdr-h gekoppelt (siehe Runde-2-Begruendung oben):
       der Drawer steht bei top:0 ueber der vollen Hoehe, unabhaengig davon,
       ob/wie hoch die (jetzt weggescrollte) Kopfzeile gerade ist. Der Wert
       muss nur den absolut positionierten Schliessen-Button (.drawer-close,
       top:12px, 36px hoch) freihalten: 12+36+8 Luft = 56px. */
    padding-top: 56px;
  }
  .rzrow > .rzpane#p-tree.is-open {
    transform: translateX(0);
    box-shadow: 8px 0 32px rgba(0, 0, 0, 0.12); /* shadow.elevation.lg, sideways */
    visibility: visible;
    transition: transform var(--jr-duration-fast) var(--jr-ease-out), visibility 0s;
  }

  /* Gleicher Spezifitaets-Fix wie oben fuer #p-tree: Basisregel ist
     ".rzrow > .rzpane.splitp#p-split { position: sticky; ... }" (id+3
     Klassen). Der alte Selektor ".splitp.rzpane" (id-los, 2 Klassen) verlor
     dagegen und "position: fixed" griff mobil nie. */
  .rzrow > .rzpane.splitp#p-split {
    position: fixed;
    /* Bewusst NICHT an --hdr-h gekoppelt: eigener .split-cap-Kopf (Zurueck/
       Swap/Schliessen) sitzt im Normalfluss ganz oben in #p-split, es gibt
       also -- anders als beim Drawer -- kein absolut positioniertes Element,
       das Platz braucht. Volle Hoehe ab der echten Viewport-Oberkante. */
    inset: 0;
    z-index: var(--z-drawer);
    width: auto !important;
    max-height: none;
    border-radius: 0;
    flex-basis: auto !important;
  }
  .src-bar { gap: 6px; }
  /* Der obere Pager stapelte hier senkrecht und war damit auf dem Telefon
     492 px hoch, also der zweitgroesste Block vor dem ersten Normsatz (gemessen
     live bei 390x844). Er bleibt oben und unten stehen, wie festgelegt, aber
     nebeneinander und kompakt: Ziel + Richtungspfeil genuegen, das Beiwort
     ("VORIGER STANDARD") ist auf dieser Breite Ballast. */
  .std-pager-row { flex-direction: row; gap: 8px; }
  .std-pager-row .std-pager { flex: 1 1 0; min-width: 0; }
  /* NICHT display:none: das nimmt "Voriger Standard" auch aus dem
     Accessibility-Tree, und die Pfeile sind aria-hidden. Fuer Screenreader und
     Sprachsteuerung bliebe dann nur "ESRS 2" ohne Richtung (WCAG 2.4.4).
     Also optisch weg, fuer assistive Technik weiter vorhanden. */
  .std-pager-row.top .dir {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .std-pager-row.top .std-pager { padding: 8px 10px; }
  .std-pager-row.top .nm {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
}

/* AP5.2: Begriffs-Tooltips (rail-card "Begriffe"/"Terms") -- reine
   Wiederverwendung der .pop-trigger/.pop-Mechanik (viewer.js initPopovers),
   nur eigenes Layout fuer die Trigger-Buttons selbst. */
.term-tip-list { display: flex; flex-direction: column; gap: 2px; }
.term-tip {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  text-align: left;
  padding: 6px 4px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--foreground);
}
.term-tip:hover { background: var(--muted); }
.term-tip .msym { color: var(--muted-foreground); flex-shrink: 0; }
.term-tip .pop { width: 240px; top: calc(100% + 4px); left: 0; background: var(--footer-bg); color: var(--jr-cta-text); padding: 10px 12px; }
.term-tip .pop .pop-label { color: var(--jr-cta-text); }
.term-tip .pop .pop-excerpt { color: inherit; margin-bottom: 0; }

/* AP5.3: Mini-Untertitel je Markieren-Aktion ("Link" vs. "Zitat"). */
.sel-pop button { align-items: flex-start; }
.sel-txt { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.sel-sub { font-size: 12px; font-weight: 400; opacity: .72; }

/* AP5.6's resume offer and its link style left with the stored reading
   position on 09.10.2026 (H2, viewer.js section 31). */

/* ══ 41. Tooltip-Schicht des Bediengeruests (P-C1) ════════════════════════
   REGEL, die diese Schicht traegt: Tooltip = nicht-interaktiver Kurztext,
   Popover (.pop-trigger) = Inhalt und Aktionen. KEIN Element traegt beides.
   Deshalb wurden die 26 Bedien-title NICHT auf .pop-trigger gehoben: das ist
   ein Klick-Dialog mit role="dialog", das falsche Werkzeug fuer einen
   Hover-Hinweis, und haette jede Icon-Schaltflaeche zum Dialogtraeger
   gemacht.

   Warum ueberhaupt: das native title-Attribut ist per Tastatur nicht
   sichtbar, auf Touch gar nicht, nicht gestaltbar und erscheint mit der
   Verzoegerung des Betriebssystems. Diese Schicht ist mit :focus-visible
   auch per Tastatur erreichbar.

   Barrierefreiheit, bewusst zweigeteilt:
   - 23 Icon-Schaltflaechen tragen nur data-tip. Ihr Name steht im
     aria-label; ein zusaetzliches aria-describedby wuerde denselben Text
     ein zweites Mal vorlesen, denn aria-label gewinnt die Namensberechnung.
     Die Blase ist dort ausschliesslich fuer Sehende.
   - Die 3 erklaerenden Traeger (#leftSrc, #splitSrc, #syncToggle) sagen
     mehr als ihr Name. Sie bekommen zusaetzlich einen visuell verborgenen
     Span und aria-describedby, damit der Screenreader die Erklaerung
     ueberhaupt bekommt.

   Kontrast selbst nachgerechnet (nie der Doku glauben): --jr-cta-text
   #FFFFFF auf --footer-bg #353537 = 12,24:1 gegen die Anforderung 4,5.
   Kontrollrechnung derselben Formel: #27C13F auf Weiss 2,39:1 und #187A28
   auf Weiss 5,45:1, beide zeichengleich mit den dokumentierten Werten. */
[data-tip] { position: relative; }

[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  z-index: var(--z-tip);
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 260px;
  padding: 6px 9px;
  border-radius: var(--radius-md);
  background: var(--footer-bg);
  color: var(--jr-cta-text);
  font-family: "Inter", sans-serif;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: 0;
  text-align: left;
  text-transform: none;
  white-space: normal;
  pointer-events: none; /* die Blase darf den Klick auf den Knopf nie abfangen */
  opacity: 0;
  visibility: hidden;
  /* Aus mit 0ms Verzoegerung: das Weggehen darf nicht nachhaengen. */
  transition: opacity var(--jr-duration-fast) var(--jr-ease-out) 0s,
              visibility 0s linear var(--jr-duration-fast);
}

/* On without a delay (design-check F2, 05.10.2026): the 400ms wait was a
   hard-coded delay, which the design system's motion canon forbids
   (chrome-lock motion.forbidden "hardcoded-animationDelay"); the bubble
   fades in over --jr-duration-fast like every UI reaction. */
[data-tip]:hover::after,
[data-tip]:focus-visible::after {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--jr-duration-fast) var(--jr-ease-out) 0s,
              visibility 0s linear 0s;
}

/* Platzierung je Standort. Der Grund ist immer derselbe: die Blase darf den
   Viewportrand nicht ueberlaufen, und am Rand gibt es nur eine Richtung.
   Kopfzeile und Panel-Koepfe behalten die Vorgabe (unten, mittig). */

/* Linke Iconspalte: nach rechts, sonst laege die Blase ausserhalb des
   Fensters. */
#m-tree [data-tip]::after {
  top: 50%;
  left: calc(100% + 8px);
  right: auto;
  transform: translateY(-50%);
}

/* Rechte Iconspalte: spiegelbildlich nach links. */
#m-rail [data-tip]::after {
  top: 50%;
  left: auto;
  right: calc(100% + 8px);
  transform: translateY(-50%);
}

/* Split-Kopf und Rail-Kopf sitzen am rechten Rand der Zeile: unten, aber
   rechtsbuendig statt mittig, damit die Blase nach innen waechst. */
.split-cap [data-tip]::after,
.rail-head [data-tip]::after {
  left: auto;
  right: 0;
  transform: none;
}

/* Auf Touch gibt es kein Ueberfahren. Eine Blase, die dort nur beim
   Antippen erscheint, verdeckt die Schaltflaeche, die man gerade druecken
   wollte. Der Name steht ohnehin im aria-label. */
@media (hover: none) {
  [data-tip]::after { display: none; }
}

/* Visuell verborgener Beschreibungstext fuer die drei erklaerenden Traeger.
   NICHT display:none: das naehme den Text auch aus dem Barrierefreiheits-
   baum, und genau ihn soll aria-describedby vorlesen. Gleiche Technik wie
   .version-fold-purpose weiter oben. position:absolute haelt den Span aus
   dem Flexfluss der Kopfleiste heraus. */
.tip-desc {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── 39b. Markieren-Popup auf schmalen Fenstern (Paket U-4b) ─────────────
   Gemessen am 10.08.2026 auf /de/e1/ bei 390px: die Pille haelt mit
   flex-wrap:nowrap drei Aktionen nebeneinander, jede auf 94px gequetscht.
   "Link zum Text kopieren" brauchte dort 6 Zeilen gegen 2 bei 1440px, das
   ganze Popup 118px Hoehe, und es legte sich 69px weit ueber die markierte
   Stelle. Seit U-4 die Absatz-Aktionsleiste entfallen ist, ist dieses Popup
   der EINZIGE Weg zum Absatzlink -- seine Bedienbarkeit auf dem Telefon ist
   damit keine Kosmetik mehr.

   Eine Spalte statt drei Saeulen: jede Aktion bekommt die volle Breite und
   ihre Beschriftung damit dieselbe Zeilenzahl wie am Schreibtisch. Die Pille
   wird zur Karte, weil ein 100px-Radius an einem hohen Block nicht mehr als
   Pille liest, sondern als Ellipse.

   STELLUNG IM FILE: .sel-pop (Abschnitt 11) und der Untertitel-Block aus
   AP5.3 stehen beide weiter oben und haben dieselbe Spezifitaet (je klassen-
   basiert, id-frei). Bei Gleichstand entscheidet die Reihenfolge, dieser
   Block muss also NACH ihnen kommen. Die Grenze 639px ist dieselbe wie beim
   Bediengeruest weiter oben, kein neuer Haltepunkt. */
@media (max-width: 639px) {
  .sel-pop {
    flex-direction: column;
    align-items: stretch;
    border-radius: var(--radius-md);
    /* Die Saeule ist sonst so breit wie ihr breitestes Kind und zwingt
       "Link zum Text kopieren" in einen zweiten Umbruch. Die Untergrenze
       gibt der Beschriftung dieselbe Zeile wie am Schreibtisch; die
       Obergrenze haelt sie auf schmaleren Geraeten im Fenster. */
    min-width: min(300px, calc(100vw - 16px));
    max-width: calc(100vw - 16px);
  }
  .sel-pop button { width: 100%; }
  .sel-pop .sep { width: auto; height: 1px; align-self: stretch; margin: 2px 6px; }
}

/* ── 40. Popover im Top-Layer (Paket S-2) ────────────────────────────────
   Gemessen am 04.08.2026 auf /de/e1/ bei 1440px: das Glossar-Popover lag
   bei x 906 bis 1246 und wurde ab x 1146 vom Navigationsbaum der rechten
   Leiste ueberdeckt, obwohl es z-index 200 traegt. Der z-index galt nur
   innerhalb seines eigenen Stapelkontexts, waehrend die sticky-Leiste als
   spaeter kommendes positioniertes Element darueber malte. Dazu kappten
   #p-rail und #p-split (beide overflow:auto) das Popover an ihrer Kante.
   Beides loest nur der Top-Layer; position:fixed haette die Ueberdeckung
   nicht behoben, weil sie keine Frage des Beschneidens ist.

   viewer.js setzt das Attribut popover NUR waehrend der Anzeige und
   entfernt es beim Schliessen. Solange es fehlt, gilt unveraendert die
   bisherige absolute Positionierung, also auch die Hover- und
   :focus-visible-Pfade.

   DIESER BLOCK MUSS AM ENDE DER DATEI STEHEN. .fn .pop, .xref .pop und
   .term-tip .pop setzen top bzw. bottom mit derselben Spezifitaet wie
   .pop[popover] (je id-frei, zwei Klassen); bei Gleichstand entscheidet die
   Stellung im File. Weiter oben eingefuegt bliebe das bottom der Fussnote
   stehen und zerrte das Popover an zwei Kanten gleichzeitig. */
.pop[popover] {
  position: fixed;
  inset: auto;      /* raeumt top/right/bottom/left der typbezogenen Regeln */
  margin: 0;        /* der Browser zentriert ein [popover] sonst per margin:auto */
}


/* ═════════════════════════════════════════════════════════════════════════
   44. Aenderungspaket 28.08.2026 -- Entscheidungen E-2, E-6, E-14, E-12, E-5
   Papier: _Global\Logs\handoffs\handoff-esrs-viewer-layout-entscheidungen-
   2026-08-28.md. Jede Zahl hier ist am ausgelieferten Stand gemessen, nicht
   gerechnet. STELLUNG IM FILE: dieser Block steht bewusst am ENDE -- mehrere
   Regeln haben dieselbe Spezifitaet wie ihre Vorgaenger, es entscheidet die
   Reihenfolge. Nicht nach oben verschieben.
   ════════════════════════════════════════════════════════════════════════ */

/* ── E-2: Deckel der Lesespalte 790 -> 900 ─────────────────────────────────
   Ohne diesen Deckel ist der Leisten-Schalter (E-1) folgenlos: Zuklappen
   braechte nur Leerraum statt Lesebreite. Rechnung am gebauten Stand:
   1ch = 9,465px (Inter 15px, LIVE gemessen), 82,5ch = 781px, Lesespalte =
   781 + 68 Randziffer-Gutter + 48 Kartenpolster + 2 Rahmen = 899px.
   ACHTUNG, teuer gelernt: der Wert ist SCHRIFTABHAENGIG. Im lokalen Spiegel
   ohne Webfonts misst dasselbe 1ch nur 8,078px -- wer hier umrechnet statt zu
   messen, liegt um 15 Prozent daneben. Bei jedem Schriftwechsel neu messen.
   Die max-width-Formel der Lesespalte bleibt unberuehrt, sie leitet sich aus
   --measure ab.
   03.10.2026 (council, decision 1): with the body at 16px the cap moves to
   the design system's measure, 75ch (llms.txt 16.3, --measure-body; WCAG
   1.4.8 allows 80). 1ch is now about 10.1px, so the column is about
   757 + 68 + 48 + 2 = 875px: E-2 keeps its purpose (folding the rails still
   buys reading width) at 25px less than before. Re-measure, do not convert. */
:root { --measure: 75ch; }

/* ── E-6: die Rail nimmt den inneren Ueberschuss ───────────────────────────
   Vorher `flex: 0 0` -- was die gedeckelte Lesespalte nicht aufnahm, blieb als
   Leerraum liegen (bei 2000px: 2 x 143px innen plus 2 x 152px ausserhalb des
   Zeilendeckels, zusammen 634px). Jetzt nimmt die Rail den INNEREN Anteil.
   Nur die Rail, NICHT der Baum: der Baum steht links vom Text und wuerde ihn
   optisch nach rechts druecken.
   max-width ist ein Waechter, kein Gestaltungswert -- unter --vw-max 1680 wird
   er nie erreicht: bei 2000px ergibt 1636 innen minus 264 Baum minus 2 x 16
   Griff minus 899 Lesespalte genau 441 fuer die Rail (GEMESSEN). Der Waechter
   greift erst, falls --vw-max je steigt.
   WACHSEN JA, SCHRUMPFEN NEIN -- flex-shrink bleibt 0. Der erste Versuch stand
   auf `flex: 1 1` und hat bei 1440px die Rail auf 246px gedrueckt, also UNTER
   ihre eigene Breite: dort ist die Zeile knapp, und eine schrumpffaehige Rail
   konkurriert dann mit der Lesespalte statt nur Ueberschuss aufzunehmen. Mit
   `1 0` bleibt sie bei 1440 auf 264 und die Lesespalte waechst auf 821
   (Lesetext 672 -> 703), bei 2000 waechst die Rail auf 441 und der innere
   Ueberschuss faellt auf 0. Beides nachgemessen. */
.rzrow > .rzpane#p-rail { flex: 1 0 var(--rz-rail-w); max-width: 560px; }

/* 06.10.2026 (point 4, planner): with the row uncapped the tree takes part
   in the surplus too, at half the rail's share, up to 400px; the rail grows
   up to its 560px as before (docs/SPALTENMODELL.md: past about 640px a side
   column starts to read like a second main text). Growing, never shrinking:
   flex-shrink stays 0 for the reasons of E-6. The order of the model is now
   text to its cap, then the side panes open (viewer.js paneTarget), then
   they grow, and only then does the row centre what is left. */
.rzrow > .rzpane#p-tree { flex: 1 0 var(--rz-tree-w); max-width: 400px; }
.rzrow > .rzpane#p-rail { flex: 2 0 var(--rz-rail-w); }

/* ── E-14: der Ruhezustand des Gleichlaufs wird SICHTBAR ───────────────────
   BEFUND, der diese Regeln ausgeloest hat: viewer.js setzt bei fehlender
   Entsprechung sauber `data-sync-idle="1"` auf #syncToggle -- und dieses File
   trug dafuer bis heute NULL Regeln. Der einzige Hinweis hing an
   [data-tip]::after, das nur bei :hover und :focus-visible erscheint. Der
   Schalter zeigte unveraendert "Gemeinsam scrollen". Der Leser sah nichts.
   Das ist kein Randfall: auf /esrs/de/e1/ liegt der erste Ankerpunkt bei
   y = 17.632 -- die ersten 31,7 Prozent des Dokuments haben gar kein
   Gegenstueck.
   MERKSATZ, ueber diesen Fall hinaus: ein Attribut ohne Regel ist kein
   Hinweis. Eine Suite, die auf das Attribut prueft, waere gruen gewesen.
   ::before, nicht ::after -- ::after gehoert der Tooltip-Schicht. */
.src-chip.sync-toggle[data-sync-idle] {
  background: var(--vw-tint-warning);
  border-color: var(--vw-tint-warning-border);
  color: var(--vw-tint-warning-text);
}
.src-chip.sync-toggle[data-sync-idle]::before {
  content: "ruht hier";
  order: 99;                      /* hinter das Label, .src-chip ist inline-flex */
  margin-left: 2px;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: var(--feedback-warning);
  color: #FFFFFF;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
html[lang="en"] .src-chip.sync-toggle[data-sync-idle]::before { content: "idle here"; }
/* Der Griff des Zweitfensters nimmt den Zustand mit auf, damit der Hinweis
   auch dort steht, wo der Leser gerade hinsieht. */
.rzrow > .rzpane.splitp#p-split:has(~ * [data-sync-idle]),
body:has(.sync-toggle[data-sync-idle]) .rzh { border-color: var(--vw-tint-warning-border); }

/* ── E-12: randlose Lesefaeche unter 640px ─────────────────────────────────
   Auf 390px kostet der Kartenrahmen 28px der knappsten Ressource und trennt
   nichts -- eine Karte grenzt einen Bereich gegen Nachbarn ab, und mobil gibt
   es keine Nachbarn, nur eine Spalte. GEMESSEN am gebauten Stand: Absatzbox
   324 -> 362, Folgezeilen 276 -> 314, also +38px oder knapp 14 Prozent.
   NICHT ANFASSEN, sieht nur falsch aus: der Absatz traegt padding-left 48px
   MIT text-indent -48px -- das ist der gewollte haengende Einzug (erste Zeile
   voll breit, Folgezeilen unter dem Text). Beim Messen sah das zunaechst nach
   einem verlorenen Einzug aus; die Gegenprobe hat es als Fehlalarm verworfen.
   Die Trennung der Abschnitte uebernimmt die
   Typografie. Schwelle 640px, also dieselbe Grenze, an der die Randziffer
   schon heute inline laeuft -- eine Grenze statt zwei. */
@media (max-width: 640px) {
  .rzpane.content .page-card {
    background: none;
    border: 0;
    border-radius: 0;
    padding-left: 0;
    padding-right: 0;
  }
  .rzpane.content .page-card > h2 {
    border-top: 1px solid var(--border);
    padding-top: 18px;
    margin-top: 22px;
  }
  .rzpane.content .page-card > h2:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
}

/* ── E-5: Zweitfenster unter 1280px als Leiste UNTEN statt als Schicht LINKS
   Senkrecht teilen erzwingt bei dieser Breite immer eine Ueberdeckung:
   56 Iconspalte + 790 Lesespalte + 640 Schicht passen bei 1279px nicht
   nebeneinander. Rechts andocken senkt die Ueberdeckung nur von rund 423 auf
   rund 241px, beseitigt sie nicht. Waagerecht geteilt behalten BEIDE Fassungen
   ihre volle Lesebreite von 790px; der Preis ist die halbierte sichtbare Hoehe.
   STELLUNG: muss nach der Basisregel `#p-split { position: sticky }` UND nach
   dem bestehenden 1279er-Block stehen -- gleiche Spezifitaet, es entscheidet
   die Reihenfolge. Genau diese Falle ist im File schon zweimal dokumentiert. */
@media (max-width: 1279px) {
  .rzrow > .rzpane.splitp#p-split {
    inset: auto 0 0 0;
    height: 46vh;
    /* 05.10.2026 (design-check F3): the 320px floor yields to the 60%
       cap. min-height beat max-height, so in a 256px window the sheet
       was 320px tall and its head and close button sat above the top
       edge (WCAG 1.4.10, llms.txt "Fall 320x256"). */
    min-height: min(320px, 60vh);
    max-height: 60vh;
    width: auto !important;
    max-width: none;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-bottom: 0;
    /* 04.10.2026 (design-check N8): shadow.elevation.md, mirrored upwards. */
    box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.08);
    padding-top: 8px;
  }
  /* OFFEN, kosmetisch, VORBESTEHEND: die Leiste sitzt 12px vom linken Rand und
     laeuft rechts 12px ueber die Kante. Gemessen bei 1279px: x = 12, Breite
     1264 = clientWidth. Kein Vorfahr bildet einen Containing Block (geprueft:
     transform/filter/contain/container-type ueberall neutral), margin ist 0,
     eine Inline-Breite von viewer.js liegt NICHT an (style-Attribut null), und
     der berechnete Wert von left ist 0. Der Versatz besteht schon im heutigen
     Bau mit `inset: 0` und ist mit dieser Aenderung weder groesser noch
     kleiner geworden. Vor dem Ausliefern klaeren -- nicht raten. */
  /* Ziehgriff: macht die Leiste als solche lesbar und ersetzt den fehlenden
     oberen Rand als Trennung zum Normtext. */
  .rzrow > .rzpane.splitp#p-split::before {
    content: "";
    display: block;
    width: 44px;
    height: 4px;
    margin: 0 auto 8px;
    border-radius: var(--radius-pill);
    /* 04.10.2026 (design-check N3): tokens color.text.tertiary; #D6D3D1
       (stone-300) is not in tokens.json. */
    background: #A8A29E;
  }
}

/* ── E-10: der Pin ist entfallen ───────────────────────────────────────────
   Sein Versprechen ("bleib offen, auch wenn das Zweitfenster aufgeht") ist bei
   1440px geometrisch nicht einloesbar -- neben einem offenen Zweitfenster ist
   fuer 264px Baum kein Platz. viewer.js legt togglePin still; hier
   verschwindet der Knopf. Nicht aus dem Markup entfernen: der Generator setzt
   ihn, und ein Bau, der ihn nicht mehr schreibt, ist ein eigener Zug. */
.side .pin, [data-pin] { display: none !important; }

/* 04.10.2026 (design review round 6, no. 1): below 1024px the tree is the
   menu drawer, and its head carried the desktop pane control "Einklappen"
   beside the drawer's own close button. A tap collapsed the tree to 0px
   but left the scrim open, and the menu then opened an empty drawer until
   a reload. The drawer closes with its X, the scrim and Escape; the
   control stays from 1024px, where it collapses the pane to its icon
   strip. The rail is no drawer below 1024px (section 40), so its control
   needs no rule. */
@media (max-width: 1023px) {
  .side-head [data-collapse="tree"] { display: none; }
}

/* ── E-13: die Guete des Gleichlaufs steht am Schalter ─────────────────────
   viewer.js schreibt data-sync-quality, sobald die Kopplung an und das
   Zweitfenster offen ist. Reihenfolge beachten: der Ruhezustand kommt WEITER
   UNTEN und gewinnt deshalb -- er ist die Ausnahme und muss die Guete
   ueberschreiben. */
.src-chip.sync-toggle[data-sync-quality]::before {
  content: "exakt";
  order: 99;
  margin-left: 2px;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: var(--jr-primary-text);
  color: #FFFFFF;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.src-chip.sync-toggle[data-sync-quality="gruppe"]::before {
  content: "auf Gruppen";
  background: var(--jr-finance);
}
html[lang="en"] .src-chip.sync-toggle[data-sync-quality]::before { content: "exact"; }
html[lang="en"] .src-chip.sync-toggle[data-sync-quality="gruppe"]::before { content: "by group"; }

/* ── E-3: symmetrischer Vergleich, NUR bei offenem Zweitfenster ────────────
   Beim Vergleich springt das Auge zwischen zwei ungleich breiten Saetzen.
   Gleich breite Spalten setzen beide Randziffern auf dieselbe Hoehe.
   ACHTUNG, kehrt eine dokumentierte Entscheidung um: der lange Kommentar an
   ".rzrow > .rzpane.content#p-content" begruendet, warum die Basis der
   Lesespalte bewusst das VOLLE Lesemass ist und nicht 0 -- mit Basis 0 fiel
   der Lesetext bei 1440px auf 510px. Diese Regel hebt das auf, ABER nur im
   Zustand "Zweitfenster offen", nie als allgemeine Basis. Ausserhalb dieses
   Zustands gilt das Spaltenmodell unveraendert weiter.
   Gemessen bei 1440px: 56 + 626 + 16 + 626 + 56 = 1380 von 1381 Innenbreite;
   Lesetext je Seite 508 statt 672. Das ist der Preis der Symmetrie und er ist
   im Papier ausdruecklich mitentschieden.

   NACHTRAG 06.09.2026 -- DIE UNTERGRENZE BLEIBT STEHEN.
   Hier stand zusaetzlich `min-width: 0 !important`. Das hob nicht nur das
   Lesemass auf (gewollt), sondern auch den BODEN der Lesespalte aus Zeile
   1249: calc(480px + --rn-gutter + 2 * --sp-card + 2px) = 598px. Ohne Boden
   wird die Zeile bei 1280px exakt halbiert, und der Lesetext faellt auf
   436px -- 44px unter eine Grenze, die niemand aufgegeben hat:

     docs/SPALTENMODELL.md Z. 47  Untergrenze der Lesespalte = 598px
     docs/SPALTENMODELL.md Z. 71  | 1280 | offen | 518 | 480 |
     docs/SPALTENMODELL.md Z. 78  "er bleibt auf der Untergrenze von 480px
                                   und damit im zulaessigen Bereich"
     site/assets/viewer.js        CONTENT_MIN_PX = 596 (unveraendert)

   Das Papier ist seit 04.08.2026 unangetastet; die Zusicherung wurde also
   nicht abgeloest, sondern uebersehen. Begruendet ist die 480 fachlich, nicht
   gestalterisch: rund 62 Zeichen je Zeile, "unter etwa 60 Zeichen zerfaellt
   Gesetzesprosa mit ihren eingeschobenen Klammerverweisen".

   Der Boden kostet die Symmetrie NUR dort, wo beide nicht zugleich gehen --
   und das ist allein 1280px. Gemessen nach dem Eingriff:
       1280  598 | 510   Lesetext 480  (Boden bindet, wie im Papier)
       1440  626 | 626   Lesetext 508  (Symmetrie, Boden bindet nicht)
       1680  746 | 746   Lesetext 628  (Symmetrie, Boden bindet nicht)
   E-4 sagt fuer 1280 ohnehin "bleibt wie gebaut", war also nie Gegenstand
   der Symmetrie-Entscheidung. */
/* KLAMMER UM E-3 (Nachtrag 06.09.2026) -- die Symmetrie gilt erst ab 1368px.
   E-3 stand ohne Klammer und griff damit auch bei 1280px. Das Papier vom
   28.08.2026 nimmt genau diese Breite aber ausdruecklich aus:

     E-esrs-layout-4 "1280 bleibt wie gebaut"
       Entscheidung: "Ja, unveraendert (688 | 405, Lesetext 570 bei
       Untergrenze 480)."
     Umsetzungsliste, Z. 199: "Nicht anfassen: 1280 (E-4) und 390 (E-7)
       bleiben wie gebaut."
     Messtabelle, Z. 38: | 1280 | offen | 56 | 688 | 16 | 405 | 56 | 570 |

   Ohne Klammer wurde daraus 554 | 554 mit 436px Lesetext -- 134px unter dem
   entschiedenen Wert und 44px unter der Untergrenze.

   Die Grenze ist 1440 und nicht ein selbst ausgerechneter Wert: das ist die
   Breite, fuer die E-3 entschieden UND gemessen wurde ("Gemessen bei 1440px:
   56 + 626 + 16 + 626 + 56"). Die beiden Entscheidungen des Papiers nennen
   genau zwei Stuetzstellen -- 1280 asymmetrisch (E-4), 1440 symmetrisch
   (E-3) --, und dazwischen ist nichts entschieden. Dort gilt "wie gebaut",
   also die Spaltenlogik ohne Symmetrie.

   Dass der Lesetext an dieser Grenze springt, ist NICHT durch die Klammer
   eingefuehrt, sondern steht so im Papier: es nennt fuer 1280 einen Lesetext
   von 570 und fuer 1440 einen von 508. Die Symmetrie kostet Lesebreite,
   solange die Zeile nicht so weit ist, dass beide Spalten ihren Deckel
   erreichen (rechnerisch ab rund 1970px). Genau das haelt der E-3-Kommentar
   oben als "Preis der Symmetrie" fest.

   Unterhalb von 1440 bleibt die Untergrenze aus Zeile 1249 die Wache; sie
   bindet dort nie, weil die Lesespalte ohne Symmetrie ohnehin breiter
   ausfaellt (gemessen 1280: 728, Lesetext 610). */
@media (min-width: 1440px) {
/* 06.10.2026 (point 4): the basis is the cap, not 0, and so is the maximum.
   Equal bases shrink equally, so both columns stay the same width (1440:
   626 | 626 as before); with the row uncapped they stop at the measure
   instead of stretching (at 2560 they would be about 1190px each), and the
   surplus goes to the side panes (viewer.js paneTarget opens them). */
.rzrow:has(> .rzpane.splitp#p-split:not([hidden])) > .rzpane.content#p-content {
  flex: 1 1 calc(var(--measure) + var(--rn-gutter) + 2 * var(--sp-card) + 2px) !important;
  max-width: calc(var(--measure) + var(--rn-gutter) + 2 * var(--sp-card) + 2px) !important;
}
/* WARUM DIE SPALTE IHR POLSTER ABGIBT -- teuer gemessen, nicht geraten:
   Mit `flex-basis: 0` und `box-sizing: border-box` ist die MINDESTBREITE eines
   Flex-Elements sein Rahmen plus Polster. Das Zweitfenster trug 2 x 18px
   Polster und 2 x 1px Rahmen = 38px; die Lesespalte traegt nichts davon (ihr
   Polster sitzt in der .page-card). Ergebnis: beide bekamen denselben
   Wachstumsanteil, aber das Zweitfenster kam 38px breiter heraus -- gemessen
   607,5 gegen 645,5. Erst als das Polster von der SPALTE in die KARTE wandert,
   sind beide exakt gleich: 626,5 zu 626,5, Differenz 0.
   Zwei falsche Faehrten davor, beide widerlegt: es lag NICHT an einer
   Inline-Breite von viewer.js (style-Attribut war null) und NICHT an
   box-sizing (beide standen bereits auf border-box). */
.rzrow > .rzpane.splitp#p-split:not([hidden]) {
  flex: 1 1 calc(var(--measure) + var(--rn-gutter) + 2 * var(--sp-card) + 2px);
  max-width: calc(var(--measure) + var(--rn-gutter) + 2 * var(--sp-card) + 2px);
  width: auto;
  padding: 0;
  border: 0;
  background: none;
  border-radius: 0;
}
/* Die Karte uebernimmt, was die Spalte abgegeben hat -- und bekommt dabei die
   Bauart der Inhaltskarte statt des schmaleren Sonderzuschnitts. */
.rzrow > .rzpane.splitp#p-split:not([hidden]) > .page-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: var(--sp-card);
  background: var(--bg-elevated);
}
}
/* Ende der Klammer um E-3 */
/* OFFEN, klein: die Karte im Zweitfenster misst 612px gegen 627px in der
   Lesespalte. Die 15px sind die eigene Bildlaufleiste des Zweitfensters -- die
   Lesespalte scrollt mit dem Fenster und hat keine. Die SPALTEN sind exakt
   gleich; nur der Satzspiegel darin steht 15px enger. Behebbar ueber
   scrollbar-gutter, das aber auf der Gegenseite Platz reservieren wuerde --
   bewusst offen gelassen statt einseitig verschlimmbessert. */

/* ── E-14, Nachzug: der Ruhezustand gewinnt gegen die Guete-Anzeige ────────
   Beide schreiben auf ::before. Der Ruhezustand ist die Ausnahme und muss die
   Guete ueberschreiben, deshalb steht er hier ganz am Ende. Gleiche
   Spezifitaet -- es entscheidet die Stellung im File. */
.src-chip.sync-toggle[data-sync-idle]::before {
  content: "ruht hier";
  background: var(--feedback-warning);
}
html[lang="en"] .src-chip.sync-toggle[data-sync-idle]::before { content: "idle here"; }

/* ── E-29b (02.09.2026): das Folgefenster steht am Anschlag ────────────────
   Am Anfang und am Ende eines Dokuments kann das rechte Fenster nicht weiter
   scrollen. Die Kopplung greift dann zwar, kann den Absatz aber nicht mehr auf
   gleiche Hoehe bringen -- gemessen auf /de/e1/ bei scrollTop 0: 37 px auf der
   Sprachachse, 141 px bei den Anwendungsanforderungen, 131 px bei EFRAG.
   Das ist keine Stoerung, sondern Geometrie. Der Schalter sagt es trotzdem an,
   sonst behauptet er eine Genauigkeit, die an dieser Stelle nicht gilt (K4).
   Steht NACH dem Ruhezustand: ruht hier ist der staerkere Befund und gewinnt,
   weil dort ueberhaupt kein Gegenstueck existiert. Deshalb schliesst diese
   Regel [data-sync-idle] ausdruecklich aus. */
.src-chip.sync-toggle[data-sync-limit]:not([data-sync-idle])::before {
  content: "am Anschlag";
  background: var(--feedback-warning);
}
html[lang="en"] .src-chip.sync-toggle[data-sync-limit]:not([data-sync-idle])::before {
  content: "at the end";
}

/* ── E-30 (02.09.2026): deaktiviert heisst deaktiviert, und zwar sichtbar ──
   Auftrag Jannik: wo der Gleichlauf fachlich sinnlos ist, gehoert der Schalter
   "deaktiviert mit Begruendung -- nicht stillschweigend wirkungslos". Die
   Begruendung stand bisher nur in data-tip und war damit erst bei :hover oder
   :focus-visible zu sehen. Das ist derselbe Fall wie E-14: ein Attribut ohne
   Regel ist kein Hinweis. Der Kurzvermerk steht deshalb dauerhaft am Schalter,
   die ausfuehrliche Begruendung bleibt in der Blase.
   Steht ganz am Ende und gewinnt damit gegen Guete, Ruhezustand und Anschlag --
   ein deaktivierter Schalter darf keine Guete behaupten. */
.src-chip.sync-toggle:disabled::before {
  content: "hier nicht möglich";
  order: 99;
  margin-left: 2px;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: var(--muted-foreground);
  color: #FFFFFF;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
}
html[lang="en"] .src-chip.sync-toggle:disabled::before { content: "not possible here"; }

/* ── E-18: die angesprungene Stelle im Zweitfenster ist erkennbar ──────────
   Seit ein Absprung das GANZE oeffnet statt eines Ausschnitts, ist der Sprung
   allein nicht mehr selbsterklaerend: im Verzeichnis stehen 199 Karten, in der
   Anlage 81 Absaetze. Ohne Markierung weiss der Leser nicht, WELCHE davon er
   angeklickt hat -- der Ausschnitt hat das frueher implizit beantwortet.
   Bewusst zurueckhaltend: eine Linie am Rand und ein leichter Grundton, keine
   Volltonflaeche. Der Text soll lesbar bleiben, nicht angestrahlt werden. */
/* 04.10.2026 (design-check N5): the line at the edge became a brand tint
   and a 1px ring drawn inside, as 50.3 did for the sync target. The 16px
   indent stays (3px edge plus 13px before), so nothing moves. */
#splitBody .is-target {
  padding-left: 16px;
  background: rgba(39, 193, 63, 0.08);
  box-shadow: inset 0 0 0 1px rgba(39, 193, 63, 0.30);
  border-radius: var(--radius-md);
}

/* ===================================================================
   E-23 / E-24 (29.08.2026, Ansage Jannik): die zwei mittleren Fenster
   beginnen oben auf gleicher Hoehe, die Quellenleisten lesen sich als
   EINE durchgehende Leiste ueber beiden.

   BEFUND, der das ausgeloest hat (gemessen auf dem eigenen Bau,
   /esrs/en/esrs-1/?cmp=en|de, 1904px):
     Pane-Oberkante links 76, rechts 76   -- gleich
     .page-card          links 174, rechts 240  -- 66px Versatz
     erster Absatz       links 463, rechts 529  -- 66px Versatz
   Ursache: die linke Quellenleiste sass IN der Lesekarte (.read-cap mit
   margin:-24px), die rechte UEBER der Karte (.split-cap, 57px hoch).
   Das Zweitfenster trug die Leiste also zusaetzlich -- daher exakt die
   Differenz von 66px. Zwei Orte fuer dieselbe Sache.

   LOESUNG: .read-cap wandert im Template aus der Karte heraus und wird
   erstes Kind von #p-content, genau wie .split-cap erstes Kind von
   #p-split ist. Beide kleben oben, beide gleich hoch. Darunter beginnen
   beide Karten auf derselben Hoehe.
   =================================================================== */

/* Gleiche Hoehe fuer beide Leisten. Ohne diese Zeile bestimmt der jeweils
   hoechste Knopf die Hoehe: rechts 36px-Icon-Knoepfe, links 29px-.cap-btn
   -- die Leisten waeren verschieden hoch und der Gleichstand waere schon
   in der Leiste selbst verloren. */
.panel-cap {
  min-height: 57px;
  box-sizing: border-box;
}

/* Die Leseleiste sitzt jetzt AUSSERHALB der Karte. Die negativen Margins
   von frueher (margin:-24px -24px 20px) haben sie in das Kartenpolster
   gezogen; ausserhalb der Karte gibt es dieses Polster nicht mehr, sie
   wuerde sonst 24px zu weit nach oben und links ragen. */
#p-content > .read-cap {
  margin: 0 0 14px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
/* Kleben erst ab der Breite, auf der es etwas zu halten gibt. Mobil bricht
   die Leiste auf 92px um (gemessen bei 390px: drei Aktionen passen nicht in
   362px) und traegt weder Tausch noch Schliessen -- eine klebende Leiste
   verdeckt dort also ein Achtel der Sichtflaeche fuer nichts. Unter 1024px
   gibt es zudem gar kein Zweitfenster. */
@media (min-width: 1024px) {
  #p-content > .read-cap {
    position: sticky;
    top: 0;
    z-index: 120;
  }
}

/* Der Standardwechsel weicht, sobald das Zweitfenster offen ist.
   Zwei Gruende, beide gemessen:
   (1) Die Zeile ist 78px hoch und steht NUR links -- sie wuerde den eben
       hergestellten Gleichstand sofort wieder um 78px zerstoeren.
   (2) Bei zwei Dokumenten nebeneinander ist "Naechster Standard"
       missverstaendlich: im Sprachvergleich zeigen beide Seiten denselben
       Standard, es stuenden also zwei gleichlautende Karten nebeneinander.
   Der Weg zum naechsten Standard bleibt ueber den Baum und ueber die
   untere Pager-Zeile erreichbar -- er geht also nicht verloren. */
.rzrow:has(> .rzpane.splitp#p-split:not([hidden])) #p-content > .std-pager-row.top {
  display: none;
}

/* E-24: Das Zweitfenster rendert eine GANZE Seite und bringt deren Beiwerk
   mit -- gemessen: 2 Pager-Zeilen und eine vollstaendige .read-cap. Beides
   gehoert dem Hauptfenster und hat im Zweitfenster nichts zu suchen; es ist
   der Grund, warum dort eine zweite Quellenleiste unter der ersten stand. */
#splitBody > .std-pager-row,
#splitBody .read-cap {
  display: none;
}

/* Damit die beiden Leisten als EINE gelesen werden, duerfen sie an der
   Trennlinie nicht auseinanderfallen: gleiche Grundlinie, gleicher Grund,
   und die Rundung nur an den AUSSEN liegenden Ecken. Innen bleibt es
   eckig, sonst entsteht in der Mitte eine sichtbare Kerbe. */
.rzrow:has(> .rzpane.splitp#p-split:not([hidden])) #p-content > .read-cap {
  border-top-right-radius: 0;
}
.rzrow:has(> .rzpane.splitp#p-split:not([hidden])) #p-split > .split-cap {
  border-top-left-radius: 0;
}


/* ===================================================================
   E-25 (29.08.2026): Lesemodus 2 -- die Anwendungsanforderungen stehen im
   zweiten Fenster, also nicht mehr zusaetzlich links.

   BEFUND, der das ausgeloest hat (gemessen /esrs/de/e1/): vor dem Oeffnen
   235 AR-Elemente sichtbar links, nach dem Oeffnen des Zweitfensters
   weiterhin 235 -- sie standen doppelt da.

   Ausgeblendet wird der ganze AR-Behaelter (pipeline/generate.wrap_ar_teil),
   nicht 235 Einzelabsaetze: sonst blieben die Ueberschriften "Anlage A" und
   "Anwendungsanforderungen" ohne Inhalt stehen.

   WARUM DAS ALLEIN NICHT GENUEGT -- gemessen: display:none erhaelt die
   Kennung (getElementById und data-key finden weiter), vernichtet aber die
   Geometrie (getBoundingClientRect 0/0, scrollIntoView tut nichts, Scroll-
   hoehe der Lesespalte faellt 59.061 -> 32.770 px). Ein Deep-Link auf einen
   AR-Anker liefe also LAUTLOS ins Leere. Die Aufloesung ist deshalb
   modusbewusst: arZielUmleiten() in viewer.js zeigt ihn im rechten Fenster.
   =================================================================== */
:root[data-lesemodus="getrennt"] #p-content .ar-teil {
  display: none;
}

/* ── B-10 (02.09.2026, Sichtprotokoll 390 px): das Rechtsakt-Symbol stand
   allein auf einer Zeile ────────────────────────────────────────────────────
   .std-meta ist ein Flex-Behaelter mit drei Kindern: dem gavel-Symbol, dem
   nackten Textknoten "Anhang I der Delegierten Verordnung ..." (den macht Flex
   zu einem anonymen Element) und dem EUR-Lex-Link. Bei 390 px passt der Text
   nicht mehr neben das Symbol, wandert eine Zeile tiefer -- und das Symbol
   bleibt als einzelnes Zeichen oben stehen. Es sieht dann aus wie ein
   Darstellungsfehler, obwohl es die Beschriftung des darunterliegenden Satzes
   ist.
   Behoben nur fuer schmale Breiten: dort laeuft der Absatz wieder als Text,
   das Symbol steht als Inline-Zeichen davor. Die Flex-Anordnung der breiten
   Layouts bleibt unangetastet -- sie ist dort richtig und wurde mit dem
   Sichtprotokoll bei 1280, 1400, 1440 und 2000 px gegengeprueft. */
@media (max-width: 480px) {
  .std-meta { display: block; }
  .std-meta > .msym { vertical-align: -3px; margin-right: 6px; }
  .std-meta > a { display: inline-flex; align-items: center; gap: 5px; margin-top: 7px; }
}

/* ── Paket 1 (02.09.2026): Bruecke in die Pruefungsakte ────────────────────
   Der Bereich klappt in der Auswahlblase auf, wenn "Fuer die Akte" gewaehlt
   wird. Er speichert nichts; die Felder werden nach dem Erzeugen geleert.
   Keine Inline-Stile -- K8 prueft alle 82 Seiten auf Inline-Code. */
.akte-feld { padding: 10px 12px 12px; min-width: 260px; }
/* 09.10.2026 (run line 12c): the field opens inside the dark selection bar
   (#1C1917), but its title was set in --foreground, the same #1C1917 (1:1,
   invisible), and its labels and note in --muted-foreground (2.3:1). On the
   dark bar the title is white and labels and note are Stone 400 (#A8A29E,
   tokens color.text.tertiary, 6.9:1); the fields stay light. No test opened
   the field, so nobody measured it. */
.akte-titel {
  font-size: 13px; font-weight: 600; color: var(--jr-cta-text);
  margin: 0 0 8px;
}
.akte-zeile { display: block; margin-bottom: 9px; }
.akte-marke {
  display: block; font-size: 12px; font-weight: 600;
  color: #A8A29E; margin-bottom: 3px;
}
.akte-feld input,
.akte-feld textarea {
  width: 100%; box-sizing: border-box;
  font: inherit; font-size: 13px; line-height: 1.45;
  padding: 6px 8px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--bg-elevated);
  color: var(--foreground); resize: vertical;
}
.akte-feld input:focus-visible,
.akte-feld textarea:focus-visible {
  outline: 2px solid var(--jr-primary-text); outline-offset: 2px;
}
.akte-hinweis {
  font-size: 12px; line-height: 1.4; color: #A8A29E;
  margin: 0 0 10px;
}
.akte-hinweis a { color: var(--jr-primary); text-decoration: underline; text-underline-offset: 2px; }
.akte-knoepfe { display: flex; gap: 8px; justify-content: flex-end; }
/* 13px since 09.10.2026 (12c): no control at 12px (type scale, verdict N7 b). */
.akte-knoepfe button {
  font: inherit; font-size: 13px; font-weight: 600;
  padding: 5px 12px; border-radius: var(--radius-sm); cursor: pointer;
  border: 1px solid var(--border); background: var(--bg-elevated);
  color: var(--foreground);
}
/* 03.10.2026, Design-Abgleich (qa/gate_design.py T3): weisser Text auf
   --jr-primary #27C13F hat 2,39:1 und verfehlt WCAG AA. Der Knopf traegt
   jetzt den CTA-Verlauf des Design-Systems (Verlaufsstops 5,49 bis 7,37:1). */
.akte-knoepfe .akte-los {
  background: var(--jr-cta-gradient); border-color: var(--jr-primary-text); color: var(--jr-cta-text);
}
.akte-knoepfe button:hover { border-color: var(--jr-primary); }


/* ── Werkwahl oben links (ESRS / VSME / EU-Taxonomie) ───────────────────
   Bewusst dieselbe Formensprache wie .std-jump daneben, aber eigene Klassen:
   .std-menu-item speist in viewer.js den Katalog der ESRS-Standards.
   Als <details> gebaut -- die Bedienung kommt vom Browser, kein JavaScript. */
/* KEIN position:relative. Das Menue soll sich an der Kopfzeile ausrichten,
   nicht am Schalter: linksbuendig unter der Wortmarke endet es bei rund
   254px und damit vor der Quellenleiste, die bei 1280px erst bei 302px
   beginnt. Am Schalter ausgerichtet (x=148) ragte es bis 380px und damit in
   deren Bereich -- gemessen, nicht geschaetzt. .hdr ist sticky und damit
   selbst der Bezugsrahmen fuer absolut gesetzte Nachfahren. */
.werk-wahl { flex-shrink: 0; }
/* 04.10.2026 (design-check N17): with one work there is no picker, only
   icon and name; the book touched "ESRS" (0px). 6px, as every other
   icon-label pair in the header. */
.werk-solo { display: inline-flex; align-items: center; gap: 6px; }
/* Below 1024px the book gives way first (decoration before function, as
   in 50.24): with it and the 6px, /de/e1/ at 768px left the search field
   158px, under its 10rem floor, and DE/EN wrapped to a second row. */
@media (max-width: 1023px) { .werk-solo > .msym { display: none; } }
.werk-wahl > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  border-radius: var(--radius-md);
  padding: 6px 10px 6px 8px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.werk-wahl > summary::-webkit-details-marker { display: none; }
.werk-wahl > summary::marker { content: ""; }
.werk-wahl > summary:hover { border-color: var(--jr-primary); }
.werk-wahl > summary .msym { color: var(--muted-foreground); }
.werk-wahl .werk-cur { color: var(--jr-primary-text); }
/* 09.10.2026: the revised act's full label ("ESRS, überarbeitet", 159px)
   pushed the header onto a second row at 641 and 768px, where Set 1's "ESRS"
   (73px) left 3px. Below 1024px the picker shows the short name; the version
   fold under the header names the act (generate_korpus.werk_cur_html). */
.werk-cur-kurz { display: none; }
@media (max-width: 1023px) {
  .werk-cur-voll { display: none; }
  .werk-cur-kurz { display: inline; }
}
.werk-wahl[open] > summary .werk-pfeil { transform: rotate(180deg); }
/* 04.10.2026: with VSME shipped there are two works, and the solo label
   (62px) becomes this picker with border and chevron (99px). Between 1089
   and 1452px that left the search field 126 to 149px on the about page,
   under the 150px of regression-layout case 17. Decoration gives way first,
   as for the solo label below 1024px: up to 1599px the picker drops its
   book and runs with 8px padding and a 6px gap (72px). Scanned at every
   width from 1024 to 1700px on the about pages and ESRS 1: the search field
   keeps at least 152px (DE about page at 1089px). From 1452px on the book
   fits again; 1600px keeps a margin. */
@media (max-width: 1599px) {
  .werk-wahl > summary > .msym:first-child { display: none; }
  .werk-wahl > summary { padding: 6px 8px; gap: 6px; }
}
/* 04.10.2026: below 1024px the header is position: static (it scrolls away
   with the text), so it framed none of its popups: the search results and
   the work menu were placed against the viewport and opened at its bottom
   edge. Measured on /de/esrs-1/ at 375 and 768px: search panel top 808 of
   800px, 0px visible (30 hits found, none shown); work menu 4 of 107px.
   relative keeps the header in the flow and not sticky, but makes it the
   frame again, as sticky does from 1024px. A rule of its own and not an edit
   of the static one above, which is the mobile header's layout.
   06.10.2026 (decision C1, Jannik): sticky below 1024px too, so the header
   can slide out and come back as from 1024px (section 50.5). A viewer
   deviation from design-system cell 16.6 ("scrollt unter 1024px mit"):
   three of five personas lost the header and never found it again. Sticky
   is positioned, so the header stays the frame of its popups. Short
   windows keep it in the flow (A13, section 50.5): relative there. */
@media (max-width: 1023px) { .hdr { position: sticky; top: 0; } }
@media (max-width: 1023px) and (max-height: 479px) { .hdr { position: relative; } }

.werk-menu {
  position: absolute;
  top: calc(100% - 4px);
  left: 22px;
  z-index: var(--z-pop);
  min-width: 232px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 6px;
}
.werk-item {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 7px 9px;
  border-radius: var(--radius-sm, 6px);
  font-size: 13px;
  color: inherit;
  text-decoration: none;
}
a.werk-item:hover { background: var(--muted); }
.werk-item.on { background: var(--muted); cursor: default; }
.werk-item .msym { color: var(--muted-foreground); margin-top: 1px; }
.werk-item.on .msym { color: var(--jr-primary-text); }
.werk-txt { display: flex; flex-direction: column; line-height: 1.3; }
.werk-name { font-weight: 600; }
.werk-sub { font-size: 12px; color: var(--muted-foreground); font-weight: 400; }
/* ── E-2026-16 (02.09.2026): Verweise auf voelkerrechtliche Abkommen ───────
   Eigene Klasse, nicht .eurlex-ref -- Entscheidung E-2026-11. Die Messung von
   K6 zaehlt Rechtsakte MIT ELI; das Uebereinkommen von Paris hat keinen. Wer
   beide in einen Topf wirft, macht die K6-Zahl unbrauchbar.

   Optisch bewusst nah an .eurlex-ref: fuer den Leser ist beides "fuehrt aus
   dem Text hinaus in die amtliche Quelle", und ein zweites Aussehen wuerde
   einen Unterschied behaupten, den es beim Lesen nicht gibt. Der Unterschied
   liegt in der Messung, nicht in der Bedeutung fuer den Leser. Unterschieden
   wird nur die Linie -- gestrichelt statt durchgezogen -- weil diese Quelle
   keine ELI-Zitierfestigkeit hat. */
.framework-ref {
  color: var(--jr-primary-text);
  font-weight: 500;
  border-bottom: 1px dashed var(--vw-tint-success-line);
}
.framework-ref:hover, .framework-ref:focus-visible {
  background: var(--vw-tint-success-hover);
  text-decoration: none;
}
.framework-ref::after {
  content: "";
  display: inline-block;
  width: .72em;
  height: .72em;
  margin-left: .18em;
  vertical-align: -0.03em;
  background-color: currentColor;
  opacity: .72;
  -webkit-mask: var(--eurlex-ext-icon) center / contain no-repeat;
  mask: var(--eurlex-ext-icon) center / contain no-repeat;
}

/* 04.10.2026 (design review round 6, no. 3): both icons above are an
   inline-block, and an atomic inline is a break opportunity on both
   sides. On phones the icon or the ")" after it could start a line:
   "(Verordnung (EU) 2020/1818" / "[icon])". In running text the icon is
   inline: it takes its width as padding and is painted through the
   mask, so it stays with the link's last word and the punctuation after
   it. Table cells keep the inline-block: the inline icon changes a
   column's min-content, and a table wrapper on /en/esrs-2/ at 768px
   started to scroll. */
:is(.eurlex-ref, .framework-ref):not(:is(td, th) *)::after {
  display: inline;
  width: auto;
  height: auto;
  padding-left: .72em;
  vertical-align: baseline;
  -webkit-mask-size: .72em .72em;
  mask-size: .72em .72em;
  -webkit-mask-position: right 50%;
  mask-position: right 50%;
}

/* ── Wortmarke in der Kopfzeile ────────────────────────────────────────────
   Das echte Logo als SVG, auf ALLEN drei Werken dieselbe (vorher: Schriftzug
   als Text auf den ESRS, gar nichts auf VSME und Taxonomie).

   width und height stehen im Markup, nicht nur hier: 145 x 26 ist das echte
   Seitenverhaeltnis der Datei (viewBox 1061,3 x 190,3 = 5,577:1). Das
   Designsystem nennt das ausdruecklich -- "Logo immer im echten
   SVG-Seitenverhaeltnis sizen (sonst zentriert preserveAspectRatio es mit
   Leerraum, Letterbox-Falle)". Mit den Attributen im Markup reserviert der
   Browser den Platz vor dem Laden, die Kopfzeile springt also nicht.

   display:block am Bild entfernt den Zeilenabstand unter dem Inline-Element,
   sonst sitzt die Marke zwei Pixel zu hoch in der Zeile. */
.marke {
  display: inline-flex;
  align-items: center;
  /* 22px high are 123px wide; at 26px (145px) .hdr-right ran 21px past the
     edge at 1280px (regression-darstellung D6, regression-ui-nav-sync).
     Until 04.10.2026 the mark was the header's valve and could shrink;
     measured between the test widths it went to 69px at 1366px on ESRS 1
     and to 0px on the about page, and from 1089 to 1199px the page still
     ran up to 102px wide. The mark keeps its size now; the search field
     takes the squeeze and two items give way first (section 50.24). A
     horizontal overflow is no cosmetic flaw in this tool: it pushes the
     norm text out of view. */
  flex: none;
  margin-right: 4px;
  border-radius: var(--radius-sm, 6px);
}
.marke img { display: block; height: 22px; width: auto; max-width: 100%; }
.marke:focus-visible { outline: 2px solid var(--jr-primary-text, #187A28); outline-offset: 2px; }


/* ===================================================================
   49b. Term popup (persona review, 06.10.2026)
   Own section, placed before 50 so that the viewer.css tail stays free for
   other branches. The selectors carry three classes where they must beat
   the type rules of section 12 and 34 (.fn .pop, .xref .pop, .pop-dyn).
   =================================================================== */

/* -- 49b.1 The popup scrolls inside the window ----------------------------
   viewer.js positionierePop limits the height to the larger free side and
   keeps 16px to the window (persona p5, 720x450: the popup stood partly
   outside the window and covered its own trigger line). What does not fit
   scrolls in the popup. The hover bridge (.pop::before, section 12) is for
   the hover path only: a popup in the top layer stays until it is closed,
   and its 10px overhang below would add a scroll range that is not there. */
.pop-trigger .pop[popover] {
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.pop[popover]::before { display: none; }

/* -- 49b.2 Head, source link and close of the term popup ------------------
   The head names the term (the glossary entry's own wording, not the
   reader's inflected form), the link leads to its row in Annex II, Table 2,
   and a close button ends the popup for a reader without Escape. The close
   button is 32px (design system, dense controls); under a finger its hit
   area grows to 44px as an empty ::before, as in 50.29, so the popup's head
   keeps its height. It sits inside the popup's 14px padding, so the
   popup's own scroll does not cut the hit area. */
.gloss > .pop .pop-label { min-height: 24px; }
.pop-close {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  margin: -4px -6px -4px auto;
  padding: 0;
  color: var(--muted-foreground);
  background: transparent;
  border: 0;
  border-radius: var(--radius-pill);
  cursor: pointer;
}
.pop-close:hover { color: var(--foreground); background: var(--vw-tint-success); }
.pop-close:focus-visible { outline: 2px solid var(--jr-primary-text, #187A28); outline-offset: 0; }
.pop-close .msym { width: 18px; height: 18px; }
@media (pointer: coarse) {
  .pop-close::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }
}
.pop-term {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.3;
  color: var(--foreground);
  overflow-wrap: anywhere;
  margin-bottom: 2px;
}
.pop-source {
  display: inline-block;
  font-size: 13px;
  font-weight: 600;
  color: var(--jr-primary-text);
  border-bottom: 1px solid var(--vw-tint-success-line);
  margin-bottom: 8px;
}
.pop-source:hover { background: var(--vw-tint-success-hover); text-decoration: none; }
.pop-source:focus-visible { outline: 2px solid var(--jr-primary-text, #187A28); outline-offset: 2px; }

/* The side action needs a second pane next to the text, which a window under
   1024px does not have (persona review, decision g). */
@media (max-width: 1023px) {
  .gloss > .pop .pop-actions { display: none; }
}

/* -- 49b.3 The definition at reading size -----------------------------------
   The popup sits inside the paragraph that holds the term, so it takes that
   paragraph's size and follows the reader's A/A/A setting (14, 16, 18px)
   instead of the fixed 13px of section 12 (persona review: "a footnote size
   for the definition of a legal term"). The label (12px) and the controls
   (13px) keep their own sizes. At 16px a 340px popup holds about 39
   characters per line, so the glossary popup is 400px wide where the window
   has room (82vw below that, as before). */
.gloss > .pop.pop-dyn {
  font-size: inherit;
  width: 400px;
  max-width: min(400px, 82vw);
}

/* -- 49b.4 No hover popup over selected text --------------------------------
   While text is selected (#app.has-selection, set by initSelectionState) a
   popup that only hover would open stays closed. The ID selector beats the
   hover rules of sections 12 and 50; an open popup (.is-open, by click or
   keyboard) is excluded and stays. */
#app.has-selection .pop-trigger:not(.is-open) > .pop {
  display: none;
}

/* ===================================================================
   50. Parallel-Lesen, Kopfband und Orientierung (03.10.2026)
   Auftrag Jannik: gepaarte Absaetze beginnen links und rechts auf gleicher
   Hoehe, die Fenster ragen nie ueber den Kopf, der obere Bereich weicht beim
   Scrollen nach unten und kommt beim Scrollen nach oben oder mit dem
   Mauszeiger am oberen Rand zurueck. Bau: viewer.js Abschnitte 21b und 21c.
   =================================================================== */

/* -- 50.1 Die Leisten kleben UNTER dem Kopf, nie darueber ----------------
   BEFUND (Screenshot Jannik, preview 39d2072): die Leseleiste klebte mit
   top:0 und z-index 120 ueber dem Kopf (z-index 100) und schnitt das Logo
   ab ("justRe"). Sie gehoert unter den Kopf und unter dessen Ebene. */
@media (min-width: 1024px) {
  #p-content > .read-cap {
    top: var(--hdr-h);
    z-index: calc(var(--z-header) - 10);
  }
}

/* -- 50.2 Parallel-Lesen: das Zweitfenster scrollt mit der Seite ---------
   Kein eigener Scrollkasten mehr, solange der Gleichlauf an ist: beide
   Spalten liegen im selben Fluss, viewer.js setzt die Luecken. Die
   Auslagerung per content-visibility muss dafuer aus -- sie schaetzt die
   Hoehe ungerenderter Karten (1200px), und gegen geschaetzte Hoehen laesst
   sich nichts auf den Pixel ausrichten. */
html[data-parallel="on"] .rzrow > .rzpane.splitp#p-split {
  position: relative;
  top: auto;
  max-height: none;
  overflow: visible;
  align-self: flex-start;
}
html[data-parallel="on"] .page-card {
  content-visibility: visible;
  contain-intrinsic-size: none;
}
/* Die Leiste des Zweitfensters klebt jetzt am Sichtfenster, also wie die
   Leseleiste unter dem Kopf -- sonst laege sie ueber ihm. */
html[data-parallel="on"] #p-split > .split-cap {
  top: var(--hdr-h);
  z-index: calc(var(--z-header) - 10);
}
.pl-gap {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  pointer-events: none;
  /* The engine writes a gap and measures the result in the same frame; a
     transition on the gap would hand it the previous height (see 21.). */
  transition: none;
}
/* 50.1b (07.10.2026): a gap before a table row is a row of empty cells
   (viewer.js gapRow). It keeps the column lines and draws no row line: a
   1px line made every gap at least 1px high, a gap of 0.5px stood 1px, and
   the passes never met (en/s1: 127 pairs 1.4px apart). */
table.norm tr.pl-gap > td { padding: 0; border-bottom: 0; }
/* While coupled, a row line is an inset shadow, not a border. A collapsed
   border is shared half and half by the rows on either side of it; the row
   after a gap row lost its half (37.30px against 37.80px), and every gap
   cost the rows below it 0.5px (Set 1 Annex II DE/EN: 64 rows 1-1.5px
   apart). The line stands where the border stood. */
html[data-parallel="on"] table.norm td,
html[data-parallel="on"] table.norm th { border-bottom: 0; box-shadow: inset 0 -1px 0 var(--border); }
html[data-parallel="on"] table.norm tr:last-child > td,
html[data-parallel="on"] table.norm tr.pl-gap > td,
html[data-parallel="on"] table.norm td table.norm td { box-shadow: none; }
/* A table row in the centre pair or under the pointer: the wash on its cells,
   no pseudo-element (a ::before or ::after of a <tr> is laid out as a cell). */
tr.pl-hover::after { content: none; }
tr.pl-focus > td { background-image: linear-gradient(rgba(39, 193, 63, .06), rgba(39, 193, 63, .06)); }
html[data-pl-zeiger] tr.pl-focus > td { background-image: none; }
@media (hover: hover) and (pointer: fine) {
  html[data-parallel="on"] table.norm tr.pl-hover > td { box-shadow: inset 0 1px 0 rgba(39, 193, 63, .30), inset 0 -1px 0 rgba(39, 193, 63, .30); }
}

/* -- 50.3 Akzentstrich: ein gerader Strich, keine Rundung ----------------
   Auftrag Jannik: "Akzentstrich nur ein Strich, nicht diese Rundung". Der
   eingesetzte Schatten folgte dem border-radius und lief an beiden Enden rund
   aus. Gilt fuer jeden Strich am linken Rand eines Absatzes. */
.sync-active,
.pl-focus,
.para.p-amended,
.para.p-new {
  border-radius: 0;
}
/* The sync target in free scrolling marks itself the same way as the centre
   pair below: a tint instead of the left stripe (design-check A12; the
   design system highlights by fill, never by a left stripe, and #27C13F as a
   stripe reached only 2.39:1). Tints in this section follow the brand.css
   pattern: brand green at .06-.10 for surfaces, .30 for borders (A6). */
.sync-active { box-shadow: none; background: rgba(39, 193, 63, 0.08); }
/* Die Lesemitte: kein Strich, sondern ein Hauch. Auftrag Jannik: "kannst
   du dir was anderes ausdenken als den Strich? Was offensichtlich, aber nicht
   zu prominent ist." Das Paar in der Bildschirmmitte bekommt links und rechts
   einen sehr leichten gruenen Grund, und seine Randziffer wird gruen. Man
   sieht sofort, welche zwei Absaetze zusammengehoeren, ohne dass etwas den
   Text durchschneidet. Nur opacity blendet (Design-System Abschnitt 6). */
.pl-focus { position: relative; }
.pl-focus::before {
  content: "";
  position: absolute;
  inset: -4px -10px;
  background: rgba(39, 193, 63, 0.08);
  mix-blend-mode: multiply;
  pointer-events: none;
  opacity: 0;
  /* 200ms: a highlight is UI feedback, not a panel (motion canon 100-200ms).
     The reduced-motion rule for it stays at the end of section 50 and must
     remain the LAST rule on .pl-focus::before -- a later "animation-name"
     re-armed the animation with fill "none" and left the wash at opacity 0
     under reduced motion (design-check A3, 03.10.2026). */
  animation: plFocus var(--jr-duration-normal) var(--jr-ease-out) forwards;
}
@keyframes plFocus { to { opacity: .75; } }
/* 06.10.2026: not while the pointer leads (50.46). */
html:not([data-pl-zeiger]) .pl-focus > .rn,
html:not([data-pl-zeiger]) .pl-focus .dr-badge {
  color: var(--jr-primary-text);
  transition: color var(--jr-duration-fast) var(--jr-ease-out);
}

/* -- 50.4 Gegenstueck leuchtet beim Zeigen -------------------------------
   Nur opacity wird bewegt (Design-System Abschnitt 6).
   03.10.2026 (design director, upgrade 15): the hover partner used the same
   green fill as the centre pair, so two pairs looked equally active. It is
   now a hairline ring: "this one belongs to the one under your pointer",
   while the fill keeps meaning "you are reading here". */
@media (hover: hover) and (pointer: fine) {
  .pl-hover { position: relative; }
  .pl-hover::after {
    content: "";
    position: absolute;
    inset: -4px -10px;
    border-radius: var(--radius-sm);
    box-shadow: inset 0 0 0 1px rgba(39, 193, 63, 0.30);
    pointer-events: none;
    opacity: 0;
    animation: plGlow var(--jr-duration-fast) var(--jr-ease-out) forwards;
  }
}
@keyframes plGlow { to { opacity: 1; } }

/* -- 50.4a The left cap names where you are (persona review, 06.10.2026) --
   Row 12 of the review: in coupled reading the reader cannot tell which
   Disclosure Requirement the two columns are at. While the second pane is
   open the reading bar carries the code of the requirement under the
   reading line and, where the bar is wide enough, its short title (viewer.js
   markReadCapPlace, fed by the scroll spy). Muted text and the same code
   chip as the context strip (50.15); one line, ellipsis. It takes the free
   room of the bar, so the coupling switch stays at the right end. */
.read-cap .cap-place { display: none; }
@media (min-width: 1024px) {
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .cap-place:not([hidden]) {
    display: flex;
    flex: 1 1 0;
    min-width: 0;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--muted-foreground);
    white-space: nowrap;
    overflow: hidden;
    container: capplace / inline-size;
  }
}
/* The title shows only where it has room for a few words; the code never goes. */
@container capplace (max-width: 189px) {
  .cap-place .cap-place-title { display: none; }
}
.cap-place .cap-place-code {
  flex: 0 1 auto;          /* a long code ("E1.SBM-3") ends in an ellipsis where the bar is tight */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 6px;
  border-radius: var(--radius-sm);
  background: var(--vw-tint-success);
  border: 1px solid var(--vw-tint-success-border);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
  color: var(--jr-primary-text);
}
.cap-place .cap-place-code:empty { display: none; }
.cap-place .cap-place-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* -- 50.4b Alignment gaps name their next block (persona review, 06.10.2026) --
   A blank gap of 160px or more carries a quiet caption at its top (viewer.js
   captionParallelGaps): muted text, 12px (the caption size of the chrome
   scale; 13px until 07.10.2026, design director round 1), no tint. It sits inside the gap,
   out of the flow, so the gap keeps the exact height the engine gave it and
   the pairs stay level. Decoration of a layout gap: not selectable (a copy
   across a gap leaves it out), not on paper. */
.pl-gap { position: relative; }
.pl-gap-cap {
  position: absolute;
  top: 8px;
  left: 0;
  right: 0;
  font-size: 12px;
  line-height: 1.4;
  font-weight: 400;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  user-select: none;
  pointer-events: none;
}
@media print { .pl-gap-cap { display: none; } }
/* The first gap of a pane (viewer.js leadsPane): its caption is a jump to the
   pair, a pill at the chrome's 14px with an arrow (design director round 1,
   finding 1; regression-fassung G10). */
.pl-gap-cap.pl-gap-lead {
  right: auto;
  max-width: 100%;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  font: inherit;
  font-size: 14px;
  line-height: 1.4;
  color: var(--foreground);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  pointer-events: auto;
  cursor: pointer;
}
.pl-gap-lead > span { overflow: hidden; text-overflow: ellipsis; }
.pl-gap-lead .msym { width: 16px; height: 16px; flex: none; }
.pl-gap-lead:hover { background: var(--muted); color: var(--jr-primary-text); }

/* -- 50.5 Kopfband: weicht nach unten, kommt nach oben zurueck -----------
   Kopf, Leseleiste und Leiste des Zweitfensters bilden EIN Band. Beim
   Scrollen nach unten gleitet es hinaus (200ms, easing.in -- Austritt), beim
   Scrollen nach oben oder mit dem Zeiger am oberen Rand herein (300ms,
   easing.out). Nur transform und opacity bewegen sich.
   --hdr-h wird im eingefahrenen Zustand 0: alle Fenster, die unter dem Kopf
   kleben, ruecken nach oben und gewinnen seine Hoehe. Der Kopf selbst behaelt
   seine 64px (sonst verschoebe sich der ganze Fluss).
   Council 2, decision 4 (A8, 04.10.2026): no transition on top or
   max-height any more. The state switches in one frame, so every sticky
   top takes its end value (the geometry reduced motion already shows),
   and viewer.js (section 21c, setBandHidden) slides each element that
   moved from where it was with the Web Animations API (FLIP): translateY
   and opacity only, 300ms ease-out to show, 200ms ease-in to hide, and
   nothing left applied at rest. That covers the header, both bars, the
   panes, the folded strips and the resize handles, which used to
   jump. --hdr-room, the room under
   the band in the panes' max-height, switches at the start of a hide and
   at the end of a show (data-band-room), so no gap opens under a pane.
   From 1024px these elements have no transition at all, as before: the
   old list named only the properties the band moved. */
@media (min-width: 1024px) {
  .hdr,
  #p-content > .read-cap,
  #p-split > .split-cap,
  .rzrow > .rzpane#p-tree,
  .rzrow > .rzpane#p-rail,
  .rzrow > .rzpane.splitp#p-split { transition: none; }
  html[data-band="hidden"] { --hdr-h: 0px; }
  html[data-band-room="hidden"] { --hdr-room: 0px; }
  html[data-band="hidden"] .hdr {
    height: var(--hdr-base);
    transform: translateY(-100%);
  }
  html[data-band="hidden"] #p-content > .read-cap,
  html[data-band="hidden"] #p-split > .split-cap {
    transform: translateY(calc(-100% - 8px));
    opacity: 0;
    pointer-events: none;
  }
}
/* design-check A13 (design system: sticky headers turn static below a 480px
   viewport height): on a short desktop window header and bars took 113px,
   a quarter of the view, until the reader scrolled. There they scroll with
   the page; the header keeps its own height while --hdr-h, the room it
   takes above sticky panes, drops to 0. */
@media (min-width: 1024px) and (max-height: 479px) {
  :root { --hdr-h: 0px; }
  html { scroll-padding-top: 0; }
  .hdr { height: var(--hdr-base); }
  .hdr,
  #p-content > .read-cap,
  html[data-parallel="on"] #p-split > .split-cap { position: static; }
}
/* 06.10.2026 (decision C1, Jannik: council verdict A8 at all widths; a
   viewer deviation from design-system cell 16.6, see section 4 / the
   header's position rule). Below 1024px the band is the header alone: the
   reading bar and the pane caps do not stick there and do not move. Same
   switch and FLIP as above (viewer.js 21c), transform only; --hdr-h stays
   0 here, nothing sticks under the header. The header wraps (116px at
   375px), so the room a jump keeps free above its target is the header's
   own height, measured by viewer.js into --hdr-own (fallback: one row).
   A constant like the 121px from 1024px: the header comes back on every
   upward scroll. Short windows (A13): no band, no padding, the header
   scrolls with the page. */
@media (max-width: 1023px) and (min-height: 480px) {
  html { scroll-padding-top: var(--hdr-own, var(--hdr-base)); }
  .hdr { transition: none; }
  html[data-band="hidden"] .hdr { transform: translateY(-100%); }
}

/* -- 50.6 Lesefortschritt: eine Haarlinie am oberen Rand -----------------
   Bleibt stehen, wenn das Band einfaehrt -- Orientierung, wo man im Standard
   steht. scaleX statt width: nur transform bewegt sich.
   Reduced motion (design-check A18, decided 03.10.2026): the line keeps
   following the scroll. It is a position readout tied 1:1 to the reader's
   own scrolling, not an animation; there is no transition on it to switch
   off. */
.read-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  z-index: calc(var(--z-header) + 1);
  background: var(--jr-primary);
  transform-origin: 0 50%;
  transform: scaleX(0);
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .hdr,
  #p-content > .read-cap,
  #p-split > .split-cap,
  .rzrow > .rzpane#p-tree,
  .rzrow > .rzpane#p-rail,
  .rzrow > .rzpane.splitp#p-split { transition: none; }
  .pl-hover::after { animation: none; opacity: 1; }
  .pl-focus::before { animation: none; opacity: .75; }
}

/* View Transitions (viewer.js withViewTransition: switching between coupled
   and free reading) ran on the browser default of 250ms ease. They now use
   the panel timing of the design system (design-check A16). Reduced motion
   never starts one. */
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
  animation-duration: var(--jr-duration-moderate);
  animation-timing-function: var(--jr-ease-out);
}

/* -- 50.7 Gliederung mit sichtbaren Ebenen -------------------------------
   Auftrag Jannik (Screenshot der rechten Leiste): "man sieht wenig
   Hierarchien bis gar keine". Drei Mittel, alle ruhig:
     Ebene 1  dunkel, 600, die Nummer in einer festen Spalte davor
     Ebene 2+ eingerueckt an einer feinen Fuehrungslinie, gedaempft, kleiner
     Codes    der DR-Code als kleine Marke ("E1-1"), der Titel daneben
   Die Anlagen stehen unter einer eigenen Trennzeile, nicht mehr gleichrangig
   neben den Kapiteln. */
.rail-outline { font-size: 13px; }
.rail-outline .node { align-items: flex-start; padding: 5px 8px; line-height: 1.35; }
.rail-outline .node > a { display: flex; gap: 8px; align-items: baseline; min-width: 0; }
.rail-outline .node:not(.lvl2):not(.lvl3):not(.lvl4) > a { font-weight: 600; color: var(--foreground); }
.rail-outline .node-num {
  flex: 0 0 auto;
  min-width: 1.6em;
  font-variant-numeric: tabular-nums;
  color: var(--muted-foreground);
  font-weight: 600;
}
.rail-outline .node-code {
  flex: 0 0 auto;
  padding: 0 6px;
  border-radius: var(--radius-sm);
  background: var(--muted);
  border: 1px solid var(--border);
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
  color: var(--muted-foreground);
}
/* 03.10.2026 (design director, upgrade 3; design-check A9/A10): titles were
   cut on the server at 61 characters, mid-word ("Anreizs...", "der w..."),
   and a long compound ran out of the card ("nachhaltigkeitsbezog", 220px
   in 170px). Full titles now, hyphenated where the language allows, broken
   anywhere only as a last resort, clamped at three lines -- the active entry
   shows in full. The requirement code sits on its own line above its title:
   chips of different widths (E1-1, E1.SBM-3) no longer push the titles to
   different starting points, and the title gets the full width. Sizes on
   the 11/12/13px steps of the scale (10.5 and 11.5px were off it, 10.5 below
   the floor). */
.rail-outline .node-label {
  min-width: 0;
  overflow-wrap: anywhere;
  hyphens: auto;
  hyphenate-limit-chars: 6 3 3;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}
.rail-outline .active-node .node-label { -webkit-line-clamp: unset; }
.rail-outline .node:has(.node-code) > a { flex-direction: column; align-items: flex-start; gap: 3px; }
.rail-outline .node-sub {
  display: block;
  font-weight: 500;
  font-size: 12px;
  color: var(--muted-foreground);
}
.rail-outline .node:has(.node-sub) > a { flex-wrap: wrap; column-gap: 6px; }
.rail-outline .tree-sub {
  margin: 1px 0 4px 15px;
  padding-left: 8px;
  border-left: 1px solid var(--border);
}
.rail-outline .lvl2, .rail-outline .lvl3, .rail-outline .lvl4 {
  padding-left: 8px;
  font-size: 13px;
  color: var(--muted-foreground);
}
.rail-outline .lvl3, .rail-outline .lvl4 { font-size: 12px; }
.rail-outline .node .tw { margin-left: -4px; margin-top: 1px; }
.rail-outline .active-node,
.rail-outline .active-node > a { color: var(--jr-primary-text); }
.rail-outline .active-node .node-code {
  background: rgba(39, 193, 63, 0.08);
  border-color: rgba(39, 193, 63, 0.30);
  color: var(--jr-primary-text);
}
.tree-divider {
  font-family: var(--font-heading);
  margin: 14px 8px 6px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
  list-style: none;
}

/* -- 50.8 Eine Zeile fuer alle Einstellungen -----------------------------
   Auftrag Jannik: "alle Einstellungen sollen oben in einer Zeile sein und die
   Texte sollen perfekt nebeneinander sein". Bei offenem Zweitfenster bricht
   die Leseleiste nicht mehr um (vorher: "Gemeinsam scrollen" allein in einer
   zweiten Zeile, die linke Leiste damit 40px hoeher als die rechte -- und der
   Text darunter um genau diese 40px versetzt). Kurze Beschriftungen, unter
   1440px nur Symbole mit Tooltip. */
.cap-lbl-short { display: none; }
@media (min-width: 1024px) {
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .panel-cap {
    flex-wrap: nowrap;
    height: 57px;
    overflow: visible;
  }
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .cap-lbl-long { display: none; }
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .cap-lbl-short { display: inline; }
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .src-pick { margin-right: 4px; }
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .sync-toggle { margin-left: auto; }
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .cap-btn[aria-pressed="true"],
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .cap-btn.is-on {
    background: var(--bg-elevated);
    color: var(--jr-primary-text);
    box-shadow: var(--shadow-xs);
  }
}
@media (min-width: 1024px) and (max-width: 1439px) {
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .cap-lbl-short { display: none; }
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .cap-btn { padding: 6px 8px; }
}
/* 03.10.2026 (design director, upgrade 11): in AR mode at 1440px the five
   controls needed 682px of a 634px bar; the source picker was squeezed to
   96px and broke into "ESRS / - DE" (a 50px button next to 33px ones). The
   picker keeps its width. Since 04.10.2026 the AR-mode button sits in the
   head of the second pane from 1024px (section 50.23), which frees the bar. */
.read-cap .src-pick { flex-shrink: 0; white-space: nowrap; }

/* Beide Texte beginnen auf derselben Linie: im Parallel-Lesen bekommen die
   Karten des Zweitfensters denselben Zuschnitt wie die Lesekarte (Rahmen,
   Rundung, Innenabstand). Ohne ihn stand der rechte Text 24px weiter links
   und ohne Rahmen -- zwei Spalten, die nicht zusammengehoeren. */
html[data-parallel="on"] #splitBody > .page-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: var(--sp-card);
  margin: 0 0 var(--sp-stack);
}
html[data-parallel="on"] .rzrow > .rzpane.splitp#p-split > .split-cap {
  margin: 0 0 14px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

/* Perfekt nebeneinander heisst auch: gleich breit. Die Symmetrie (E-3) galt
   bisher erst ab 1440px; gemessen bei 1366px stand links 785px gegen rechts
   390px, der englische Text brach dreimal so oft um wie der deutsche. Im
   Parallel-Lesen teilen sich beide Spalten den Platz zu gleichen Teilen --
   auch gegen eine gezogene Breite, denn ungleiche Spalten heben genau das
   auf, wofuer der Modus da ist. Das Zweitfenster verliert dabei seinen
   eigenen Rahmen: die Karten darin tragen ihn schon (sonst Rahmen im Rahmen). */
html[data-parallel="on"] .rzrow > .rzpane.content#p-content,
html[data-parallel="on"] .rzrow > .rzpane.splitp#p-split {
  flex: 1 1 0 !important;
  width: auto !important;
  max-width: none !important;
  min-width: 0;
}
/* 06.10.2026 (point 4): from 1440px, where the icon strips stand beside the
   pair, the row is uncapped, so the pair takes the cap here as well: equal
   bases at the measure, equal shrinking below it. Below 1440 the strips give
   way (50.10) and the columns never reach the cap, so the rule above holds
   there unchanged. */
@media (min-width: 1440px) {
  html[data-parallel="on"] .rzrow > .rzpane.content#p-content,
  html[data-parallel="on"] .rzrow > .rzpane.splitp#p-split {
    flex: 1 1 calc(var(--measure) + var(--rn-gutter) + 2 * var(--sp-card) + 2px) !important;
    max-width: calc(var(--measure) + var(--rn-gutter) + 2 * var(--sp-card) + 2px) !important;
  }
}
html[data-parallel="on"] .rzrow > .rzpane.splitp#p-split {
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  border-radius: 0;
}
html[data-parallel="on"] #splitBody > .ar-teil {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: var(--sp-card);
  margin: 0 0 var(--sp-stack);
}

/* -- 50.10 Lesebreite im Parallel-Lesen unter 1440px ---------------------
   Zwei gleich breite Spalten kosten Lesebreite. Gemessen bei 1280px: 554px
   je Spalte, 436px Lesetext -- unter der Untergrenze von 480px (D3). Die
   beiden schmalen Symbolleisten (je 56px) geben ihren Platz ab, solange
   beide Texte nebeneinander stehen: 492px Lesetext. Sie kommen zurueck,
   sobald das Zweitfenster schliesst; der Standardwechsel bleibt im Kopf. */
@media (max-width: 1439px) {
  html[data-parallel="on"] .rzrow > .minipane { display: none; }
}

/* -- 50.11 Kopplung im unteren Fenster (unter 1024px) --------------------
   03.10.2026 (design director, upgrade 6): below 1024px the reading bar
   scrolls away, so viewer.js placeSyncToggle() moves the coupling switch into
   the head of the bottom panel, between source picker and swap. There it must
   not take the 36px square of the panel's icon buttons; the quality badge
   ("exakt") stays out of the narrow head. */
#p-split > .split-cap .sync-toggle {
  width: auto;
  height: auto;
  padding: 6px 13px;
  border-radius: var(--radius-pill);
  color: var(--jr-primary-text);
}
#p-split > .split-cap .sync-toggle[data-sync-off] { color: var(--muted-foreground); }
#p-split > .split-cap .sync-toggle[data-sync-quality]::before { display: none; }

/* -- 50.12 Rail entries with a code ---------------------------------------
   03.10.2026 (design director, upgrade 8). A rail entry that carries a
   code shows it as a chip above its title, as in the outline of the
   standard pages (50.7). */
.toc-item.has-code { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.toc-item .node-code {
  padding: 0 6px;
  border-radius: var(--radius-sm);
  background: var(--muted);
  border: 1px solid var(--border);
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
  color: var(--muted-foreground);
}
.toc-item.on .node-code {
  background: rgba(39, 193, 63, 0.08);
  border-color: rgba(39, 193, 63, 0.30);
  color: var(--jr-primary-text);
}

/* -- 50.13 Standardwechsel in der Leseleiste ------------------------------
   03.10.2026 (design director, upgrade 9): previous/next standard as two
   compact actions at the end of the reading bar instead of the full-width
   card above the title. Hidden while the second pane is open (two documents
   side by side make "next standard" ambiguous, and the bar is full) and on
   phones, where the pager at the end of the page and the drawer carry it. */
.read-cap .cap-std-nav {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 4px;
  padding-left: 8px;
  border-left: 1px solid var(--border);
}
.read-cap .cap-std,
.read-cap .cap-std:hover { text-decoration: none; }
.read-cap .cap-std { gap: 4px; }
.rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .read-cap .cap-std-nav { display: none; }
@media (max-width: 640px) {
  .read-cap .cap-std-nav { display: none; }
}

/* -- 50.14 Telefon: der Text beginnt auf dem ersten Bildschirm ------------
   03.10.2026 (design director, upgrade 5): at 375px the H1 sat at y=636 and
   no norm text was on the first 812px screen -- four header rows, a reading
   bar of three stacked buttons, the pager cards, the source line and the
   version box came first. Up to 640px:
   - the standard picker leaves the header (the menu drawer lists all
     standards) and the font size moves into the drawer: two header rows;
   - the reading bar keeps one row with the short labels (50.8);
   - the source line goes when the version box follows it: the box carries
     the same act, the EUR-Lex link and the non-official notice, one tap
     away. */
.fontsize-drawer { display: none; }
@media (max-width: 640px) {
  .hdr .std-jump,
  .hdr-right .fontsize { display: none; }
  .fontsize-drawer { display: inline-flex; margin: 0 14px 12px; }
  #p-content > .read-cap { flex-wrap: nowrap; }
  #p-content > .read-cap .cap-lbl-long { display: none; }
  #p-content > .read-cap .cap-lbl-short { display: inline; }
  :is(#read-card, #cmp-read-card, #act-read-card) > .std-meta:has(+ .version-fold) { display: none; }
  /* In one row the last action sits at the right edge; its centred tooltip
     box reached 12px past the window (page scrollWidth 387 at 375px). Grow
     inwards, as in the panel head (section 41). */
  #p-content > .read-cap [data-tip]::after { left: auto; right: 0; transform: none; }
}
/* 04.10.2026 (design review round 5, no. 2a): from 641 to 767px (iPad
   mini portrait at 744px) the bar kept its long labels and broke into
   two rows, 93px, the source picker alone on row 2 behind a stray
   divider. It takes the short labels of phones and the split view
   (50.8) and holds one row, 57px. On the about page, without the
   standard arrows, "DE/EN nebeneinander" is then the last action, and
   its centred tooltip reached 4px past the window: it opens inwards, as
   the other actions at the bar's right end do. The same holds on every
   page while the second pane is open, which hides the standard arrows
   (50.13): the bubble reached 2px past the window (scrollWidth 643 at
   641px on /de/esrs-1/?panelR=lang, 04.10.2026). */
/* 04.10.2026: from 641 to 767px the standard picker (120-200px) did not
   fit beside the search's 10rem floor and pushed DE/EN alone onto a
   second header row: 106px on standard pages up to 679px, on the about
   pages up to 744px. The picker leaves the header there, as on phones
   (50.14); the menu drawer lists every standard. From 768px every page
   holds one row with it, beside the work picker through the rule below. */
@media (min-width: 641px) and (max-width: 767px) {
  .hdr .std-jump { display: none; }
}
/* 04.10.2026, after the master merge: with VSME shipped the work label is
   a picker (73px), wider than the solo label it replaced, and the about
   pages carry the longest standard label ("Über diese Ausgabe" 207px,
   "About this edition" 191px). One header row then needed 800px: at
   768px DE/EN wrapped to a second row, 106px (regression-layout case 27).
   Decoration gives way first, as for the book of both work labels: the
   standard picker drops its tree icon and takes the work picker's 8px
   padding and 6px gap (32px), and the row's gap goes from 16 to 12px
   (20px). Measured from 641 to 1023px on the about pages (DE and EN),
   E1 and Annex II: one row everywhere; at 768px
   the search field keeps 180px on /de/about/ (floor 10rem). */
@media (min-width: 641px) and (max-width: 1023px) {
  .hdr { column-gap: 12px; }
  .hdr .std-jump > .msym:first-child { display: none; }
  .hdr .std-jump { padding: 6px 8px; gap: 6px; }
}
@media (min-width: 641px) and (max-width: 767px) {
  #p-content > .read-cap { flex-wrap: nowrap; }
  #p-content > .read-cap .cap-lbl-long { display: none; }
  #p-content > .read-cap .cap-lbl-short { display: inline; }
  #p-content > .read-cap:not(:has(.cap-std)) #presetDEEN[data-tip]::after,
  .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) #p-content > .read-cap #presetDEEN[data-tip]::after { left: auto; right: 0; transform: none; }
}

/* -- 50.15 Orientierung bei eingefahrenem Kopfband -----------------------
   03.10.2026 (design director, upgrade 12): with the band hidden in parallel
   reading, a thin strip on top of each column names the heading of the
   centre pair (viewer.js updatePlContext). Opacity only, 150ms; reduced
   motion switches the transition off (section 21). Below the 2px reading
   progress line, above the text, never above a menu or popover. */
.pl-context {
  position: fixed;
  top: 0;              /* round 2: at 2px a slice of the text above showed through */
  z-index: calc(var(--z-header) - 5);
  display: flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 2px 16px 0; /* the 2px reading-progress line draws over this edge */
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  font-weight: 600;
  color: var(--foreground);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--jr-duration-fast) var(--jr-ease-out);
}
.pl-context[hidden] { display: none; }
.pl-context .pl-ctx-code {
  flex: 0 0 auto;
  padding: 0 6px;
  border-radius: var(--radius-sm);
  background: rgba(39, 193, 63, 0.08);
  border: 1px solid rgba(39, 193, 63, 0.30);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  line-height: 1.6;
  color: var(--jr-primary-text);
}
.pl-context .pl-ctx-code[hidden] { display: none; }
.pl-context .pl-ctx-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
html[data-parallel="on"][data-band="hidden"] .pl-context { opacity: 1; }

/* -- 50.16 Sprung zum Text ------------------------------------------------
   03.10.2026 (design-check B7, WCAG 2.4.1): the skip link is the first
   focusable element. Out of sight until it has keyboard focus, then it
   appears top left above everything; no motion, it simply shows. */
.skip-link {
  position: absolute;
  left: 12px;
  top: 8px;
  z-index: var(--z-toast);
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-xs);
  font-size: 13px;
  font-weight: 600;
  color: var(--jr-primary-text);
  transform: translateY(-200%);
}
.skip-link:focus-visible { transform: none; }

/* -- 50.17 Design director, round 2 (03.10.2026) -------------------------- */
/* Bottom panel below 1280px: the panel scrolls itself, and its 8px top
   padding plus the drag handle scrolled with the content, so the sticky head
   stood 9px below the panel edge and panel text showed above it (measured at
   768 and 375px). The panel starts flush, the head sticks at its very top,
   and the handle is drawn inside the head. */
@media (max-width: 1279px) {
  .rzrow > .rzpane.splitp#p-split { padding-top: 0; }
  .rzrow > .rzpane.splitp#p-split::before { content: none; }
  #p-split > .split-cap { position: sticky; top: 0; padding-top: 18px; }
  #p-split > .split-cap::before {
    content: "";
    position: absolute;
    top: 6px;
    left: 50%;
    width: 44px;
    height: 4px;
    margin-left: -22px;
    border-radius: var(--radius-pill);
    background: #A8A29E; /* tokens color.text.tertiary (design-check N3) */
  }
}
/* Reading bar on phones in AR mode: source picker, "Vergleichen", "DE/EN"
   and the AR-mode button needed 468px of 347px, the AR-mode button sat off
   screen. Up to 640px the language preset and the AR mode show their icons;
   names stay in aria-label. */
@media (max-width: 640px) {
  #p-content > .read-cap #presetDEEN .cap-lbl-short,
  #p-content > .read-cap #arModusLabel { display: none; }
}
/* Requirement heading: the chip sat 30px above its own heading (the h3 kept
   its 20px top margin inside .dr-head) but 26px under the paragraph before.
   Chip and heading belong together: 6px between them, in every pane. */
.dr-head { row-gap: 6px; }
.dr-head > h3 { margin: 0; }
/* 07.10.2026 (design director round 1, finding 13; Jannik: on both trees):
   the badge stood beside a one-line title and above a wrapped one, so its
   place changed with the title's length. It always stands above, on the
   title's left edge (regression-darstellung D24). */
.dr-head { flex-direction: column; align-items: flex-start; }
/* A table's number line ("Tabelle 1", the 2026/1563 Annex II) right above its
   title is an overline at the meta size, so the two do not read as two equal
   headings (finding 6, D24). No text-transform: the line is the source's own
   words, and a transformed case can reach a copy. */
.page-card h3.title-table:has(+ h3.title-table) {
  margin-bottom: 2px;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted-foreground);
}
/* Search field: the input drops its outline and nothing replaced it -- the
   fourth focus stop was invisible (WCAG 2.4.7). The ring goes on the field. */
.hdr-search:focus-within { outline: 2px solid var(--jr-primary-text); outline-offset: 2px; }
/* After opening the second pane, the layout moved the coupling switch under
   the resting pointer and its four-line tooltip covered the source line.
   viewer.js mutes tooltips until the pointer moves again. */
html.tips-muted [data-tip]::after { opacity: 0 !important; visibility: hidden !important; }
/* The actions at the right end of the reading bar open their tooltip
   inwards: the centred 260px box of the AR-mode switch reached 51px past the
   window at 768px (page scrollWidth 819). Below 414px "Vergleichen" also
   shows only its icon, so the bar fits a phone in AR mode (until
   04.10.2026 below 375px; with the 13px controls of council 2, decision 3,
   the four actions needed 341px of the 319px a 375px phone gives them). */
#p-content > .read-cap #arModus[data-tip]::after,
#p-content > .read-cap #syncToggle[data-tip]::after,
#p-content > .read-cap .cap-std[data-tip]::after { left: auto; right: 0; transform: none; }
@media (max-width: 413px) {
  #p-content > .read-cap #openCompare .cap-lbl-short { display: none; }
}
/* 04.10.2026 (design director round 7, upgrade 3): only AR mode needs that
   room -- there the AR-mode button joins the bar. In a single pane and in
   DE/EN the 413px rule left two bare icons, so the viewer's main action had
   no name under a finger, which has no hover. From 360px "Vergleichen" keeps
   its word wherever the AR-mode button is not in the bar; the bar stays one
   row (57px) and the last action ends inside it. Below 360px the word does
   not fit (325px needed), so the icon stays alone there. */
@media (min-width: 360px) and (max-width: 413px) {
  #p-content > .read-cap:not(:has(> #arModus:not([hidden]))) #openCompare .cap-lbl-short { display: inline; }
}

/* -- 50.18 Design director, round 3 (03.10.2026) --------------------------
   The folded icon strips are cards of their own but brought no gap: the
   resize handle that separates panes by 16px (--sp-col) is hidden next to a
   strip, so strip and content card touched -- in DE<->EN and AR mode both
   strips sat against the cards. Same 16px as every other pane boundary. */
.rzrow > #m-tree.minipane { margin-inline-end: var(--sp-col); }
.rzrow > #m-rail.minipane { margin-inline-start: var(--sp-col); }

/* -- 50.19 Council decision 6 (03.10.2026) -------------------------------
   (a) Below 1280px the second pane is a bottom panel: one surface with its
   own radius, shadow and head. The reading card inside it drew a second
   frame (card in card). Inside the panel the card gives up frame, fill and
   side padding; the text starts flush with the panel's 18px edge, like the
   head above it. Focus rings are untouched.
   (b) The sliding band (50.5) is approved as a documented viewer exception:
   the playbook keeps the website header identical, the reading tool lets it
   slide away while reading and brings it back on upward scroll, pointer at
   the top edge, focus in the band or Escape. One Escape does one thing: if
   it closes a menu, drawer, popover or the search panel, the band stays
   (viewer.js, initKopfband). DS registration of the exception: owner list.
   (c) Footer #1C1917: token --site-footer-bg, section 1. */
@media (max-width: 1279px) {
  #p-split #splitBody > .page-card,
  #p-split #splitBody > .ar-teil {
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    padding: 16px 0 0;
  }
}

/* -- 50.21 Header: 64px, one primary control (council decision 2) --------
   04.10.2026. The header takes the 64px of the design system's chrome-lock
   (--hdr-base, section 2). No control carries a green fill (the version
   switch that did left on 06.10.2026). Search stays a secondary field. The
   standard picker, the link to the official version, the font size and the
   language switch go quiet: no frame and no fill at rest; hover and the
   chosen state take the design system's selection fill (#F5F5F4, --muted)
   with the text colour, the chosen language also weight 600. The picker
   names its standard in the text colour, its prefix stays muted. The
   transparent 1px border keeps every box at its measured size. */
.hdr .std-jump,
.hdr .pill-btn,
.hdr .fontsize,
.hdr .lang-switch { border-color: transparent; background: transparent; }
.hdr .std-jump,
.hdr .pill-btn,
.hdr .fontsize button,
.hdr .lang-switch button {
  transition: background var(--jr-duration-fast) var(--jr-ease-out),
              color var(--jr-duration-fast) var(--jr-ease-out);
}
.hdr .std-jump { color: var(--muted-foreground); }
.hdr .std-jump .cur { color: var(--foreground); }
.hdr .std-jump:hover,
.hdr .std-jump[aria-expanded="true"],
.hdr .pill-btn:hover { border-color: transparent; background: var(--muted); color: var(--foreground); }
.hdr .fontsize button,
.hdr .lang-switch button { border-radius: var(--radius-pill); }
/* 04.10.2026 (design-check N10): DE and EN sit in the label group above
   (Plus Jakarta Sans 600, both buttons); the chosen language shows by its
   fill alone, no longer by a heavier weight. */
.hdr .fontsize button:hover,
.hdr .lang-switch button:hover { background: var(--muted); color: var(--foreground); }
.hdr .fontsize button.on,
.hdr .lang-switch button[aria-pressed="true"] { background: var(--muted); color: var(--foreground); }

/* -- 50.22 Source line and Stand as one line (council decision 2) ---------
   04.10.2026. From 641px the source line and the Stand box above the H1
   become one line. Where the box's handle carries the Stand (the standard
   pages; on "Ueber diese Ausgabe" the handle names only its purpose and the
   line stays), the line over it goes: the act, the EUR-Lex link and the
   non-official notice sit one click away in the box, as below 640px. The
   handle loses its frame and fill and reads as a quiet line, its text
   flush with the column; hover takes the selection fill, and 44px stays
   the touch height. The council named 1024px; tablets then kept the
   oldest treatment of the three, source line, EUR-Lex link and boxed
   Stand on three rows (H1 at y 310 at 768px, design review round 4).
   Not below 641px: there the card has no padding, and the -14px margin
   would put the handle on the window edge. */
@media (min-width: 641px) {
  :is(#read-card, #cmp-read-card, #act-read-card) > .std-meta:has(+ .version-fold .version-fold-purpose) { display: none; }
  :is(#read-card, #cmp-read-card, #act-read-card) > .version-fold > summary {
    margin-left: -14px;
    margin-right: -14px;
    border-color: transparent;
    background: transparent;
  }
  :is(#read-card, #cmp-read-card, #act-read-card) > .version-fold > summary:hover { background: var(--muted); }
}

/* -- 50.23 AR switch in the head of the second pane (council decision 2) --
   04.10.2026. From 1024px viewer.js placeArModus() puts "Nur AR" between
   the source picker and swap/close of the second pane. It keeps its label
   and its 16px icon (section 2), takes the 36px height of its icon-only
   neighbours but not their square, and shows its pressed state like the
   pressed actions of the reading bar (section 50.8). */
#p-split > .split-cap #arModus {
  width: auto;
  padding: 0 10px;
  justify-content: flex-start;
}
#p-split > .split-cap #arModus[aria-pressed="true"] {
  background: var(--bg-elevated);
  color: var(--jr-primary-text);
  box-shadow: var(--shadow-xs);
}
#p-split > .split-cap #arModus:hover { background: var(--muted); color: var(--jr-primary-text); } /* F4 */

/* -- 50.24 Header give-way order from 1024 to 1439px -----------------------
   04.10.2026, follow-up to council decision 2. Measured between the old
   test widths: the logo was the header's valve and shrank to 69px at
   1366px on ESRS 1 and to 0px on the about page, whose picker names
   "Ueber diese Ausgabe"; from 1089 to 1199px the page still ran up to
   102px wide. The logo now keeps its size and the search field takes the
   squeeze (min-width 0, section 4). Two items give way before the field
   gets too narrow: the picker's "Standard:" prefix shows from 1440px (the
   accessible name keeps the word and adds the standard), and the font size
   from 1280px (browser zoom stays). The official-version pill keeps its
   1366px threshold, the version switch its 1089px one. Since
   04.10.2026 (design review round 5, no. 2b) the prefix also gives way
   from 641 to 1023px, where it pushed DE/EN alone onto a second header
   row (107px; 65px without it from 680px on standard pages).
   Since 04.10.2026 (council 2, decision 3) the header's controls are 13
   and 14px. At the old thresholds the field then measured 136px (1089),
   130px (1366) and 129px (1440) on the about page, under the 150px it
   needs. Each threshold moved up by that growth plus a few pixels: the
   version switch shows from 1110px, the official-version pill from
   1390px, the prefix from 1470px. */
@media (min-width: 641px) and (max-width: 1469px) {
  .hdr .std-jump-pre { display: none; }
}
@media (min-width: 1024px) and (max-width: 1279px) {
  .hdr-right .fontsize { display: none; }
}
/* Below 1024px the header wraps instead of holding one row, and the valve
   needs a floor: without one the field stayed in the logo row and
   collapsed, to an 18px input at 375px ("S" of the placeholder) and 17px
   at 768px (design review round 4). With 10rem it takes a row of its own
   on phones, as before. The font size gives way first, as from 1024 to
   1279px, and the menu drawer carries it, as on phones (section 50.14):
   below 1024px the navigation is that drawer at every width. */
@media (max-width: 1023px) {
  .hdr-search { min-width: 10rem; }
  .hdr-right .fontsize { display: none; }
  .fontsize-drawer { display: inline-flex; margin: 0 14px 12px; }
}

/* -- 50.25 A source line without a link reads as text at every width -------
   04.10.2026. B-10 (02.09.2026, 480px) sets the source line as running
   text only on phones. On the about page the line has no EUR-Lex link, and
   its text ("Fassung: Konsolidierte Fassung, Stand ...") is longer than
   the column at every width: the flex row moved the text one line down and
   left its icon alone above it. A line without a link reads as text
   everywhere, its icon inline before it, as in B-10. */
.std-meta:not(:has(> a)) { display: block; }
.std-meta:not(:has(> a)) > .msym { vertical-align: -3px; margin-right: 6px; }

/* -- 50.26 The Stand handle without its parenthetical where it wraps ------
   04.10.2026. The handle above the H1 ends in "(konsolidierte Fassung,
   CELEX ...)", which is what the first row of the box says. Where the
   line has no room for it, it goes from sight: below 641px, where the
   handle ran to three lines (84px at 375px, design review round 4), and
   while the second pane is open, where the column is about 590px and the
   handle took two lines at 1280 and 1440px (design-check N12). Visually
   hidden, not display:none (the technique of .version-fold-purpose): the
   text stays in the DOM and in the accessible name, byte-identical with
   std_stand_note (generate.py _stand_label). */
.rzrow:has(> .rzpane.splitp#p-split:not([hidden])) .version-fold > summary .version-fold-detail {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
@media (max-width: 640px) {
  .version-fold > summary .version-fold-detail {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
/* 04.10.2026 (design review round 5, no. 2c): "where it wraps" is the
   handle's own width, not a viewport list. From 641 to 899px the handle
   ran to two lines and broke the CELEX number at its hyphen
   ("02023R2772-" / "20250101)"). On one line the parenthetical needs
   748px of the summary's content box (DE; EN 721px), so below 760px it
   goes from sight as above: at 641-768px (573-700px). From 834px and at
   1024-1920px single pane (766-955px) it shows. The summary is the size
   container; it is a flex box already, so the containment changes no
   margins. */
.version-fold > summary { container: stand / inline-size; }
@container stand (max-width: 760px) {
  .version-fold > summary .version-fold-detail {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* -- 50.27 Long words wrap; German text hyphenates -----------------------
   04.10.2026 (design-check N2, WCAG 1.4.10). Only .para had overflow-wrap.
   List text and plain paragraphs ran past the card edge at 375 and 320px
   ("Nachhaltigkeitsberichterstattung", 30px), and the card's
   content-visibility (section 38) clipped the letters; the same compound
   made the AR bottom panel scroll sideways (78px at 320px). break-word, not
   anywhere: it breaks a word only when it cannot fit, and leaves the
   min-content width alone, so tables and flex rows keep their sizes.
   Hyphenation as the design system has it (DESIGN.md, "Silbentrennung
   sprachbewusst"): German text only, hyphenate-limit-chars 6 3 3, the H1
   at manual. The other-language text in the second pane carries its own
   lang (viewer.js renderSplitLang), so :lang(de) never reaches English
   text. Rendering only: the characters stay as they are (K1). */
#read-card, #splitBody { overflow-wrap: break-word; }
#read-card:lang(de), #splitBody:lang(de) {
  hyphens: auto;
  hyphenate-limit-chars: 6 3 3;
}
:is(#read-card, #cmp-read-card, #act-read-card) h1 { hyphens: manual; }
/* 07.10.2026 (design director round 1, finding 10): at 375 the VSME start
   page's h1 broke "Nachhaltigkeitsberichterstatt|ung" without a hyphen: a
   compound longer than the line breaks anyway (overflow-wrap above), so on
   a phone it breaks with its hyphen, and only words of 12 letters or more
   (regression-vsme-viewer N2). Rule set after section 50.32's heading rule
   below, which would otherwise set it back to manual. */
/* Terms and links stay whole: a glossary term or a cross-reference split
   by a hyphen is two targets for the pointer and reads as two words
   (measured: "Geschäftsmodell" on /de/e1/ at 1440px, regression-
   darstellung D4d). A word too long for any line still breaks. */
#read-card :is(a, .gloss), #splitBody :is(a, .gloss) { hyphens: manual; }
/* 07.10.2026 (regression-darstellung D26): the glossary of Annex II reads
   as term beside definition. "Abhilfe(maßnahmen)/Verbesserung/Sanierung" has
   no break opportunity (none after "/"), and break-word above leaves the
   min-content alone, so that one term set the German term column: 322 of
   663px at 1440, 322 against 137px beside the English text in coupled
   reading. The term column gets a fixed share; a term too long for it breaks
   inside the column (hyphenation first, anywhere only as the last resort).
   The second pane carries its rows as "cmp-term-N". Since 07.10.2026
   (review of the P5 tip, finding 5) the build sets a <wbr> after each "/"
   of a term cell (pipeline/nowrap.py), so such a term breaks there first
   instead of "Verbess|erung". */
#read-card table.norm tr[id^="term-"] > td:first-child:not(:last-child),
#splitBody table.norm tr:is([id^="cmp-term-"], [id^="act-term-"]) > td:first-child:not(:last-child) { width: 28%; overflow-wrap: anywhere; }
/* 04.10.2026 (design review round 5, no. 1): the rest of the canon's set
   (design system site.css, "Silbentrennung & Umbruch"). Hyphenation
   alone made the rag choppier: on /de/e1/ at 1440px 88 paragraphs ended
   in a one-word line, hyphenated line ends followed each other, and
   h2/h3 split ("Leistung"). Headings take manual hyphens, running text
   pretty last lines (the canon's p and li), and Safari gets the pair
   that matches hyphenate-limit-chars 6 3 3. Balanced lines first went
   only where a heading carried no disclosure code: Chromium breaks
   after the hyphen of "GOV-1", and balance put that break inside a code
   113 times on ten pages at 320-1440px where plain wrapping does not
   (pretty 16 times; in running text pretty stays even, 84 against 85).
   Council 2, decision 6 (04.10.2026) closes that deviation: the
   generator keeps every code in a heading on one line (.nw-code, 50.32),
   so every heading is balanced. Line breaks only: the characters stay
   as they are (K1). */
#read-card:lang(de), #splitBody:lang(de) {
  -webkit-hyphens: auto;
  -webkit-hyphenate-limit-before: 3;
  -webkit-hyphenate-limit-after: 3;
}
#read-card :is(h1, h2, h3, h4), #splitBody :is(h1, h2, h3, h4) {
  -webkit-hyphens: manual;
  hyphens: manual;
}
#read-card :is(h1, h2, h3, h4), #splitBody :is(h1, h2, h3, h4) { text-wrap: balance; }
@media (max-width: 640px) {
  :is(#read-card, #cmp-read-card, #act-read-card):lang(de) h1 {
    -webkit-hyphens: auto;
    hyphens: auto;
    hyphenate-limit-chars: 12 5 5;
  }
}
#read-card :is(p, li), #splitBody :is(p, li) { text-wrap: pretty; }

/* -- 50.28 Strong text at 600 ---------------------------------------------
   04.10.2026 (design-check N4). strong and b in the reading text took the
   browser's bold, Inter 700 (95 runs on E1 at 1440px); the design system
   sets strong text at 600. In headings they keep the heading's weight: an
   h3 with <strong><em> computed Plus Jakarta Sans 900 and drew 800, and a
   Fraunces heading asked for 900 of a font that loads only 600. */
#read-card :is(strong, b), #splitBody :is(strong, b) { font-weight: 600; }
#read-card :is(h1, h2, h3, h4) :is(strong, b),
#splitBody :is(h1, h2, h3, h4) :is(strong, b) { font-weight: inherit; }

/* -- 50.29 Control sizes: 32px dense, 44px under a finger ----------------
   04.10.2026 (design-check N13). The design system sets 32px for dense
   toolbars and 44px as the touch standard (tokens dimension.target.dense
   and .default). The language and font-size buttons, the source pickers
   and the bar actions were 24 to 31px high, the three font-size buttons
   each a different height. They take 32px: both bars keep their 57px
   (a 36px content box, E-23/E-24 "Gleiche Hoehe"), the header its
   64px. Under a coarse pointer each control gets an invisible hit area
   of at least 44x44px centred on it, so phones get the touch standard
   while the bars and the header keep their height. Buttons that touch
   a neighbour (DE/EN, the font sizes) grow only in height; the bar
   actions sit 8px apart and grow 4px to each side. Both pseudo-elements
   of the coupling switch (.src-chip) carry content (the state badge
   "exakt" and the tooltip), so since 04.10.2026 it carries the hit area
   as an empty child, .sync-hit: 30 to 34px high, a tap 21px above or
   below its centre missed it. Absolute in every mode, so it never takes
   a flex gap; sized only under a finger. */
.sync-hit { position: absolute; }
.hdr .lang-switch button,
.hdr .fontsize button,
.panel-cap .cap-btn,
.panel-cap .src-pick { min-height: 32px; }
@media (pointer: coarse) {
  .hdr .lang-switch,
  .hdr .fontsize { overflow: visible; }
  .hdr .lang-switch button,
  .hdr .fontsize button,
  .panel-cap .cap-btn,
  .panel-cap .src-pick,
  .split-cap > button:not(.src-pick):not(.src-chip) { position: relative; }
  .hdr .lang-switch button::before,
  .hdr .fontsize button::before,
  .panel-cap .cap-btn::before,
  .panel-cap .src-pick::before,
  .split-cap > button:not(.src-pick):not(.src-chip)::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: max(100%, 44px);
    height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }
  .hdr .lang-switch button::before,
  .hdr .fontsize button::before { width: 100%; }
  .src-chip.sync-toggle { position: relative; }
  .sync-toggle > .sync-hit {
    top: 50%;
    left: 50%;
    width: max(100%, 44px);
    height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }
}
/* 04.10.2026 (design review round 5, no. 4): the drawer's font size in a
   row of its own above the "Standards" head, labelled in the drawer's
   overline (section 25). The drawer has the room the header lacks, so
   under a finger its buttons are 44x44px themselves. */
.fontsize-drawer-row { display: none; }
@media (max-width: 1023px) {
  .fontsize-drawer-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 2px 6px 10px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 8px;
  }
  .fontsize-drawer-row .fontsize-drawer { margin: 0; }
}
.fontsize-drawer-lbl {
  font-family: var(--font-heading);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}
.fontsize-drawer button { min-height: 32px; }
@media (pointer: coarse) {
  .fontsize-drawer button { min-width: 44px; min-height: 44px; }
}

/* -- 50.30 The bottom panel's head in one row on phones -----------------
   04.10.2026 (design-check N14). Below 641px the head of the AR bottom
   panel (source picker, coupling switch, swap, close) needed 465px of
   345px at 375 and wrapped to two rows (102px, 105px with 50.29). As the
   reading bar does up to 640px (50.17), the coupling switch shows its
   icon (link or unlink; its name stays in aria-label) and the picker its
   short label ("AR - DE", viewer.js sourceLabel); the full label stays
   in the accessible name. Should a label still not fit (the switch can
   carry a state badge), it ends in an ellipsis instead of wrapping. */
#splitSrc .src-lbl-short { display: none; }
@media (max-width: 640px) {
  #p-split > .split-cap { flex-wrap: nowrap; }
  #p-split > .split-cap #syncLabel { display: none; }
  #p-split > .split-cap .src-pick { min-width: 0; flex-shrink: 1; }
  #p-split > .split-cap .src-pick > .msym { flex-shrink: 0; }
  #splitSrcLabel {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  #splitSrc .src-lbl-short {
    display: block;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* -- 50.31 No-break spans in the norm text (council 2, 04.10.2026) -------
   The generator wraps "1,5 °C" (number, literal U+0020, unit) on the
   standard pages in .nw (pipeline/nowrap.py), so the unit never starts a
   line on its own. Rendering only: no character changes (K1). */
.nw { white-space: nowrap; }

/* -- 50.32 Disclosure codes in headings on one line (council 2, 04.10.2026)
   Decision 6. The generator wraps "GOV-1", "E1-4", "MDR-P" or "S1-17" in
   a heading in .nw-code (pipeline/nowrap.py), after the ids, TOC and
   search index exist, and every heading takes balanced lines (50.27).
   Rendering only: no character changes (K1). */
.nw-code { white-space: nowrap; }

/* -- 50.33 "Nur AR" in the reading bar (council 2, decision 7) -------------
   04.10.2026. From 641 to 1023px the switch shows its icon and "Nur AR"
   ("AR only"), as before. Below 641px its face is the text "AR" instead
   of the icon that changed with the state; the name stays in aria-label,
   the 44px target under a finger stays (50.29). The state therefore shows
   as it does in the head of the second pane (50.23): pressed is the raised
   white face, below 1024px too. */
.ar-face { display: none; }
@media (max-width: 640px) {
  #p-content > .read-cap #arModus .ar-face { display: inline; }
  #p-content > .read-cap #arModus #arModusIcon { display: none; }
}
@media (max-width: 1023px) {
  #p-content > .read-cap #arModus[aria-pressed="true"] {
    background: var(--bg-elevated);
    color: var(--jr-primary-text);
    box-shadow: var(--shadow-xs);
  }
}

/* -- 50.34 Pressed toggles: a cue besides colour (council 2, WCAG 1.4.1) --
   04.10.2026. The search filter chips, the
   current standard in the folded tree column and "Nur AR" showed their
   pressed state by colour alone. Pressed now also draws a 2px border in
   the text green #187A28 (5.45:1 on white, 5.08:1 on the green tint, so
   the cue meets WCAG 1.4.11 too); the padding gives the extra border
   back, so each box keeps its size and nothing in its row moves. The
   chips say "pressed" in aria-pressed; the standard icon opens a page,
   so it says aria-current="page" instead. */
.filter-chip.on { border-width: 2px; border-color: var(--jr-primary-text); padding: 4px 10px; }
.minipane button.on { border: 2px solid var(--jr-primary-text); }
#p-split > .split-cap #arModus[aria-pressed="true"] { border: 2px solid var(--jr-primary-text); padding: 0 8px; }
@media (max-width: 1023px) {
  #p-content > .read-cap #arModus[aria-pressed="true"] { border: 2px solid var(--jr-primary-text); padding: 4px 8px; }
}

/* -- 50.35 Forced colours (council 2, WCAG 1.4.1) --------------------------
   04.10.2026. In a contrast theme the browser paints every surface in
   system colours and drops box-shadow. Three things then vanished: the
   dark bubbles (tooltips, the footnote preview, the selection bar) lost
   their edge against the page; the focused resize handle showed its focus
   only as a green bar, with its outline switched off; and the language
   switch and the font-size ladder showed "pressed" by fill alone. The
   bubbles get a 1px
   CanvasText border, the handle an outline in Highlight, and those
   pressed states the system's selected colours (the header's own pressed
   rules are named too, they are more specific). The pressed chips and
   "Nur AR" keep their 2px border (50.34), which forced colours keep. */
@media (forced-colors: active) {
  [data-tip]::after,
  .fn .pop,
  .sel-pop { border: 1px solid CanvasText; }
  .rzh:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }
  .rzh::before { forced-color-adjust: none; background: CanvasText; }
  .rzh:hover::before,
  .rzh.is-dragging::before,
  .rzh:focus-visible::before { background: Highlight; }
  .fontsize button.on,
  .lang-switch button[aria-pressed="true"],
  .hdr .fontsize button.on,
  .hdr .lang-switch button[aria-pressed="true"] {
    forced-color-adjust: none;
    background: SelectedItem;
    color: SelectedItemText;
  }
}

/* -- 50.36 The footer on paper (council 2, WCAG 1.4.1 print) --------------
   04.10.2026. A print leaves out the dark footer (#1C1917) but not its
   light colours: Chromium greys the white text to #ABABAB (2.2:1 on paper,
   the statement "keine amtliche Fassung, mit KI erstellt" included) and
   draws the links' underline in white, so on paper the six footer links
   had none (measured in the PDFs of two pages, /de/esrs-1/ among them).
   On paper the footer is muted text on white and its links are text green
   with their underline in the same colour. */
@media print {
  .site-footer { background: none; color: var(--muted-foreground); }
  .site-footer .msym { color: var(--muted-foreground); }
  .site-footer a { color: var(--jr-primary-text); }
}

/* -- 50.37 Form fields under a finger --------------------------------------
   04.10.2026. Under a coarse pointer the search field and the dossier's
   two fields (mandate, note) take 16px, the design system's size for form
   fields on touch screens: iOS Safari zooms the page into any field set
   smaller as soon as it takes focus. With a mouse they keep 14 and 13px.
   The search input's line drops to 1.4: 16px at 1.4 is the 22.4px line of
   14px at 1.6, so the field and the header keep their height. */
@media (pointer: coarse) {
  .hdr-search input,
  .akte-feld input,
  .akte-feld textarea { font-size: 16px; }
  .hdr-search input { line-height: 1.4; }
}

/* -- 50.38 Notes and the copy confirmation where the reader is (E6) --------
   04.10.2026. The three notes (jump target not found, data point, resume
   offer) stood in a row after the reading row, at the end of the document:
   on /de/esrs-1/ 51,967px down, out of sight, and focusing "Weiterlesen"
   threw the page there. The copy confirmation (viewer.js showMicroToast)
   had no styles at all and landed after the footer. Both now follow the
   design system: the notes float at the top right like its toast, with its
   edge and opaque tints (the text runs underneath) and the popover shadow
   shadow.elevation.md (the toast's own shadow in brand.css is drawn in
   #171717, a colour outside tokens.json, which the tokens outrank), 12px under
   the lowest head they would cover and at least 20px from the top, the
   toast's place (viewer.js placeNotes sets --note-y, a translate, so the
   notes follow the heads at no layout cost); the confirmation is its "Kopier-Bestaetigung",
   the stone pill at the bottom centre with a 1.7s countdown line (the
   drop-in in brand.css, here with the viewer's tokens). The notes enter
   with opacity and 8px of travel in 200ms ease-out. */
.hintbar-row {
  position: fixed;
  top: 0;
  translate: 0 var(--note-y, calc(var(--hdr-base) + 12px));
  right: var(--sp-page);
  z-index: var(--z-toast);
  width: 356px;
  max-width: calc(100vw - 32px);
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
@media (max-width: 520px) {
  .hintbar-row { left: 16px; right: 16px; width: auto; max-width: none; }
}
.hintbar-row .hintbar,
.hintbar-row .hintbar:last-child {
  margin: 0;
  pointer-events: auto;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); /* shadow.elevation.md */
  animation: noteIn var(--jr-duration-normal) var(--jr-ease-out) both;
}
.hintbar-row .notice { background: var(--vw-tint-warning); border-color: var(--vw-tint-warning-border); }
.hintbar-row .dp-hint,
.hintbar-row .lang-hint { background: var(--vw-tint-success); border-color: var(--vw-tint-success-border); }
.lang-hint,
.lang-hint .msym { color: var(--jr-primary-text); }
@keyframes noteIn { from { opacity: 0; transform: translateY(-8px); } }

.ds-copy-toast {
  position: fixed;
  left: 50%;
  bottom: calc(26px + env(safe-area-inset-bottom, 0px));
  transform: translate(-50%, 12px);
  z-index: var(--z-toast);
  max-width: min(90vw, 440px);
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  background: var(--foreground);
  color: #FFFFFF;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms var(--jr-ease-out), transform 180ms var(--jr-ease-out);
}
.ds-copy-toast.show { opacity: 1; transform: translate(-50%, 0); }
.ds-copy-toast::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: var(--jr-primary);
  transform: scaleX(0);
  transform-origin: left;
}
.ds-copy-toast.show::after { animation: dsCountdown 1700ms linear forwards; }
@keyframes dsCountdown { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@media (prefers-reduced-motion: reduce) {
  .ds-copy-toast { transform: translate(-50%, 0); }
  .ds-copy-toast.show::after { animation: none; }
}

/* -- 50.39 Every header control under a finger ---------------------------
   04.10.2026, after the master merge. 50.29 gives the dense controls a hit
   area of at least 44x44px under a coarse pointer, but names only those
   that were 24 to 31px high. Measured under a finger on four pages at six
   widths (probe_hdr_touch): the work picker that came with VSME (35px),
   the standard picker (36px) and
   the mark (22px) missed a tap 21px from their centre. They take 50.29's
   hit area. Each is wider than 44px, so it grows in height only and
   stays inside its header row (at 375px the first row ends at 54px, the
   search field starts at 62px). The search input is 22px of its 38px field, and
   a tap on the field's icon focused nothing: viewer.js (initSearch) now
   focuses the input on any tap on the field. The input keeps its box,
   which regression-layout cases 19 and 28 measure as the usable width. */
@media (pointer: coarse) {
  .werk-wahl > summary,
  .marke { position: relative; }
  .werk-wahl > summary::before,
  .hdr .std-jump::before,
  .marke::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: max(100%, 44px);
    height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }
}

/* -- 50.39a The rest under a finger (touch audit 06.10.2026) --------------
   probe_touch tapped every visible control 21px from its centre under a
   coarse pointer at 375px, with menus, search and drawer open: the
   drawer's close (36x36), the filter chips (33px), the source menu items
   (37px), the Excel button (33px), the search field (38px), the AR link
   (29px) and the popup action (32px) missed, and DE/EN (39px wide, side
   by side) missed beside the centre. Chips wrap in rows 6px apart and menu
   items stand in a list, so an invisible hit area would land on the
   neighbour; each control takes the 44px itself. The close button keeps
   its centre. DE/EN and the short chips ("DR", "AR", 42px) take 44px of
   width; in the header the search field gives the 9px. */
@media (pointer: coarse) {
  .drawer-close { width: 44px; height: 44px; top: 8px; right: 6px; }
  .hdr .lang-switch button,
  .filter-chip { min-width: 44px; }
  .hdr-search,
  .filter-chip,
  .src-menu-item,
  .excel-btn,
  .ar-open,
  .pop-action,
  .search-empty-action button { min-height: 44px; }
}

/* -- 50.40 Tooltips that leave their box ---------------------------------
   04.10.2026. A bubble is [data-tip]::after, placed against its button,
   and every ancestor that clips or scrolls cuts it. Measured for every
   visible bubble on seven views at four widths (probe_tips): 248 of 365
   were cut, and hover screenshots show them gone, not trimmed.
   - The icon bars (#m-tree, #m-rail) scroll when they are taller than the
     window, and their bubbles sit beside the bar. Since the bubbles came
     (02.08.2026) none of the 13 standard icons showed its name, and the
     bubble text made #m-tree scroll sideways (S-11, regression-darstellung
     D7). The bubble is fixed to the window instead: viewer.js
     (initMiniPaneTips) hands it its button's edges as it shows and while
     the button moves. A fixed bubble still paints in its bar's layer, and
     the sticky bar sits under the reading column and the panel heads that
     come later (the finding of 40, S-2). While one of its bubbles shows,
     the bar rises to the tooltip layer, and keeps it while the bubble
     fades out.
   - The tree's collapse button sits at its panel's right edge, the second
     window's source picker at its pane's left edge: each bubble now grows
     inward. */
#m-tree [data-tip]::after,
#m-rail [data-tip]::after {
  position: fixed;
  top: var(--tip-mid, 0px);
}
#m-tree [data-tip]::after { left: calc(var(--tip-after, 0px) + 8px); }
#m-rail [data-tip]::after { right: calc(var(--tip-before, 0px) + 8px); }
.minipane {
  z-index: 0;
  transition: z-index 0s linear var(--jr-duration-fast);
}
.minipane:has([data-tip]:hover),
.minipane:has([data-tip]:focus-visible) {
  z-index: var(--z-tip);
  transition-delay: 0s;
}
.side-head [data-collapse][data-tip]::after { left: auto; right: 0; transform: none; }
#splitSrc[data-tip]::after { left: 0; right: auto; transform: none; }

/* -- 50.41 The reading bar picks its labels by its own width -------------
   04.10.2026 (design director round 7, upgrade 1). With its long labels
   the bar needs up to 763px of content box on one row (/de/g1/: source
   picker, "Zweites Fenster / vergleichen", "DE/EN nebeneinander" and both
   standard arrows; the English pages up to 722px). At 768px it has 712px:
   from 768 to 819px (iPad portrait) it ran to two rows, 94.59px instead
   of 57px, on every German standard page. With tree and rail open, which
   the viewer remembers per size class, the same happened from 1024 to
   1128px and from 1280 to 1392px, and at 1400px it fitted by 2px. A
   viewport band cannot know which panes are open; as for the Stand handle
   (50.26), "where it wraps" is the bar's own width. Up to 775px of content
   box the bar takes the short labels of phones and the split view (50.8,
   50.14), whatever the window and the panes. The containment changes no
   box (measured from 375 to 1920px, single pane, DE<->EN and AR mode: same
   left edge, width and height) and does not make the bar a containing
   block, so its bubbles keep their layer. The viewport rules of 50.14 stay
   as the fallback where container queries are missing.
   With the short labels "DE/EN" can be the bar's last action: on the about
   pages, and below 1024px with the bottom panel open, which hides the
   standard arrows (50.13). Its bubble then opens inwards, as at the bar's
   right end elsewhere. */
#p-content > .read-cap { container: readcap / inline-size; }
@container readcap (max-width: 775px) {
  #p-content > .read-cap .cap-lbl-long { display: none; }
  #p-content > .read-cap .cap-lbl-short { display: inline; }
  #p-content > .read-cap:not(:has(.cap-std)) #presetDEEN[data-tip]::after { left: auto; right: 0; transform: none; }
  @media (max-width: 1023px) {
    .rzrow:has(> .rzpane.splitp#p-split:not([hidden])) #p-content > .read-cap #presetDEEN[data-tip]::after { left: auto; right: 0; transform: none; }
  }
}

/* -- 50.42 (removed 09.10.2026) ------------------------------------------
   The resume offer at the bottom edge left with the stored reading
   position (H2, viewer.js section 31). */

/* -- 50.43 The bottom sheet reads at the reading column's measure ---------
   06.10.2026 (persona p2, triage row 10). Below 1280px the second pane is a
   bottom sheet across the window (E-5), and its text ran the sheet's full
   width: 986px at 1024 (about 120 characters a line) under a reading column
   of 770, 1241px at 1279 (regression-layout 38). The text column takes the
   reading card's text width, which viewer.js measures (initSheetMeasure),
   and stands centred in the sheet; the head keeps the full width. Without
   the measurement the column falls back to the reading paragraph's cap. */
@media (max-width: 1279px) {
  #p-split > #splitBody {
    max-width: var(--sheet-text-w, calc(var(--measure) + var(--rn-gutter)));
    margin-inline: auto;
  }
}

/* -- 50.44 The notice the reader confirms once -----------------------------
   06.10.2026 (Jannik; viewer.js initHinweis). A modal dialog in the top
   layer, built as the design system builds a modal (section 7): white,
   radius xl, shadow lg, a 1px edge; at most 34rem wide and 16px from every
   window edge, scrolling inside itself when the window is short (720x450 at
   200 %). The backdrop is the drawer scrim (.40). Title in the heading token
   (16px, 700, not Fraunces), text at the reading size, the button as the
   CTA (green gradient, white, radius md; 44px under a finger, 50.29). It
   enters in 300ms ease-out with opacity and transform only, and appears at
   once under reduced motion. Not on paper. */
.hinweis-dlg {
  box-sizing: border-box;
  width: min(34rem, calc(100vw - 32px));
  max-width: none;
  max-height: calc(100dvh - 32px);
  margin: auto;
  padding: 24px;
  overflow: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--bg-elevated);
  color: var(--foreground);
  box-shadow: var(--shadow-lg);
}
.hinweis-dlg::backdrop { background: rgba(0, 0, 0, 0.40); }
.hinweis-dlg h2 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
  font-family: var(--font-heading);
  font-size: 16px;
  font-weight: 700 !important; /* over the display rule for h1 and h2 */
  letter-spacing: -0.02em;
  line-height: 1.25;
}
.hinweis-dlg h2:focus { outline: none; } /* focused on opening, not a control */
.hinweis-dlg h2 .msym { flex: none; width: 20px; height: 20px; color: var(--jr-primary-text); }
.hinweis-dlg p { margin: 0 0 12px; font-size: 16px; line-height: 1.6; }
.hinweis-aktionen { display: flex; justify-content: flex-end; margin-top: 20px; }
.hinweis-ok {
  min-height: 40px;
  padding: 8px 20px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--jr-cta-gradient);
  color: var(--jr-cta-text);
  font-size: 14px;
  font-weight: 600;
  box-shadow: var(--jr-primary-shadow);
  cursor: pointer;
  transition: transform var(--jr-duration-fast) var(--jr-ease-spring),
              box-shadow var(--jr-duration-fast) var(--jr-ease-out);
}
.hinweis-ok:hover { transform: translateY(-2px); box-shadow: var(--jr-primary-shadow-hover); }
.hinweis-ok:active { transform: scale(.97); }
@media (pointer: coarse) { .hinweis-ok { min-height: 44px; } }
.hinweis-dlg[open] { animation: hinweisIn var(--jr-duration-moderate) var(--jr-ease-out); }
.hinweis-dlg[open]::backdrop { animation: hinweisScrim var(--jr-duration-moderate) var(--jr-ease-out); }
@keyframes hinweisIn { from { opacity: 0; transform: translateY(8px); } }
@keyframes hinweisScrim { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .hinweis-dlg[open], .hinweis-dlg[open]::backdrop { animation: none; }
  .hinweis-ok, .hinweis-ok:hover, .hinweis-ok:active { transform: none; transition: none; }
}
@media print { .hinweis-dlg { display: none; } }
/* -- 50.45 VSME text on the ESRS reading metrics -------------------------
   06.10.2026 (Jannik: "vsme soll genauso aussehen wie die esrs vom
   viewer"). The VSME pages render in this shell (site/templates/
   korpus.html.j2) and no longer load korpus.css. Since P2c (09.10.2026)
   their text renders through render_oj as the ESRS pages' text does
   (p.para with .rn, the list grid, table cards, headings), so the rules of
   sections 9 to 22 seat it. The rules that seated the Official Journal's
   layout tables, contents rows and oj-* runs here went with them (P2c
   9b.4, measured: none of the 25 matched an element of the 14 VSME
   pages). What stays is VSME's own. Every selector sits under
   .esrs-app[data-work], which only a second work sets (base.html.j2): the
   ESRS pages carry Official Journal images in the card too, and img
   { height: auto } would resize them. */
/* A level 3 heading is an h4. */
.esrs-app[data-work] .page-card h4.korpus-ti {
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 700;
  margin: 16px 0 6px;
}
.esrs-app[data-work] .korpus-note { font-size: 13px; color: var(--muted-foreground); margin: 4px 0; }
.esrs-app[data-work] .korpus-signature { margin: 16px 0; font-style: italic; }
.esrs-app[data-work] .page-card figure { margin: 8px 0; }
.esrs-app[data-work] .page-card img { max-width: 100%; height: auto; }
/* The non-binding notice, first in the card and in the first viewport
   (gate V5): our note, so it takes the pattern of .editorial (section 15),
   the warning tint with the 30 % amber border, no accent edge. */
.esrs-app[data-work] .korpus-unverbindlich {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  border: 1px solid var(--vw-tint-warning-border);
  border-radius: var(--radius-lg);
  background: var(--vw-tint-warning);
  padding: 14px 16px;
  margin: 0 0 16px;
  font-size: 13px;
  color: var(--foreground);
}
.esrs-app[data-work] .korpus-unverbindlich .msym { color: var(--feedback-warning); flex-shrink: 0; margin-top: 1px; }
/* Imprint and privacy policy (decision D4, 05.10.2026) stand in their own
   <p> for gate A5; in the footer they run on as two of its links. */
.esrs-app[data-work] .site-footer .korpus-recht { display: contents; }

/* -- 50.46 One focus in coupled reading -----------------------------------
   06.10.2026 (Jannik: "wenn die maus bewegt wird und wo anders hingeht ist
   das primär ... so ein hover fokus ... sonst ist aber scrollen maßgeblich").
   While the pointer lights a pair (viewer.js initParallelHover sets
   data-pl-zeiger on the root), the centre tint of 50.3 steps back, so one
   pair is marked, not two. Scrolling without a move of the mouse clears the
   light and the tint fades back in (its animation starts again). The rule
   also sets animation: an animation's value holds over a plain declaration,
   and it must outrank the reduced-motion rule at the end of section 50. */
html[data-pl-zeiger] .pl-focus::before { animation: none; opacity: 0; }

/* -- 50.47 The application line under the version fold (J1) ---------------
   07.10.2026, step 3.5. When the act takes effect, in one meta line of the
   head: 13px like the act line, its icon inline before the running text
   (50.25 sets a .std-meta without a direct link as text; the links sit in
   its span). It belongs to the fold, 6px under it, and the fold's 18px move
   under the line. Before Annex II's frame line the line keeps the fold's 2px
   (design director round 1, finding 4), so "ANHANG II" stays 8px under the
   head (regression-fassung G8). Its links run in the sentence: underlined,
   so they do not rest on colour alone (WCAG 1.4.1), as in the footer, and
   each label stays on one line ("Article" ended one line and "2" opened the
   next at 768px). */
.version-fold:has(+ .application-line) { margin-bottom: 6px; }
:is(#read-card, #cmp-read-card, #act-read-card) > .application-line { margin: 0 0 18px; }
:is(#read-card, #cmp-read-card, #act-read-card) > .application-line:has(+ .oj-rahmen) { margin-bottom: 2px; }
.application-line a { text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; }

/* -- 50.48 Figures rebuilt as our own markup (point (a), 09.10.2026) --------
   Jannik: no images from the standard; every figure of the three acts is
   rebuilt by pipeline/abbildungen.py (gates K27, K28), in the house style
   (Jannik: "ein besseres Design in unserem Stil"). A flowchart or chart is
   drawn at 720px and scales down to 672px at most, so no word falls below 12px
   (design system: charts reflow or scroll, never shrink their labels); below
   that the figure scrolls. Existing tokens only; the connector colour is the
   design system's color.icon.muted. Brand green as the tint pattern (rule 3 of
   the project CLAUDE.md): 8 to 10 % for fills, 30 % for rims. Series carry a
   second channel beside colour (hatching). No tabular figures: Inter's tnum
   widens the hyphen too ("THG - Emissionen"), and the values stand after bars
   of different length, where aligned digits gain nothing. */
.abb { --abb-linie: #78716C; margin: 20px 0 24px; overflow-x: auto; }
.abb-fluss .abb-svg, .abb-diagramm .abb-svg { display: block; width: 100%; max-width: 720px; min-width: 672px; height: auto; overflow: visible; }
.abb-linie { fill: none; stroke: var(--abb-linie); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.abb-gestrichelt { stroke-dasharray: 5 4; }
/* A zone behind boxes: the page tone, its label as an eyebrow. */
.abb-zone { fill: var(--background); stroke: var(--border); stroke-width: 1; }
/* 13px: a drawing scales down to 672/720 of its size before its frame
   scrolls, and 12px words then render at 11.2px (regression-abbildungen B2,
   VSME flow at 712px, 09.10.2026); 13px keeps them at 12.1px and above. */
.abb-zonen-titel { height: 100%; font: 700 13px/18px var(--font-heading); letter-spacing: .06em; text-transform: uppercase; color: var(--muted-foreground); }
.abb-tropfen { display: flex; gap: 2px; margin-top: 6px; color: var(--muted-foreground); }
.abb-tropfen .msym { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; }
.abb-halo { fill: none; stroke: #FFFFFF; stroke-width: 7; }
.abb-spitze { fill: none; stroke: var(--abb-linie); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.abb-kasten { stroke-width: 1; }
.abb-frage { fill: var(--bg-elevated); stroke: var(--border); }
.abb-start { fill: var(--muted); stroke: var(--border); }
.abb-ergebnis { fill: var(--vw-tint-success); stroke: var(--vw-tint-success-border); }
.abb-text { box-sizing: border-box; height: 100%; display: flex; align-items: center; padding: 10px 14px;
  font: 400 14px/1.45 var(--font-body); letter-spacing: -0.005em; color: var(--foreground); hyphens: manual; overflow-wrap: break-word; }
.abb-text strong { font-weight: 600; }
.abb-chipfeld { height: 100%; display: flex; align-items: center; justify-content: center; }
.abb-chip { display: inline-block; padding: 1px 9px; border-radius: var(--radius-pill); border: 1px solid var(--border); background: var(--bg-elevated);
  font: 600 13px/1.25 var(--font-body); color: var(--muted-foreground); }
.abb-chip-ja { color: var(--jr-primary-text); background: var(--vw-tint-success); border-color: var(--vw-tint-success-border); }
.abb-chip-nein { background: var(--muted); }
/* A formula: the number hangs by a negative indent (flex would put it on a copy
   line of its own); a fraction stands as two inline blocks with a hidden slash,
   so a copy reads "€/t CO2e" on one line. */
.abb-formel { display: block; padding-left: 2.25em; text-indent: -2.25em; font: 400 16px/2.1 var(--font-body); color: var(--foreground); }
/* Keyed on the term's class, never on *: a universal right-hand selector is
   checked against every element of the page in every style pass, and with the
   frame rule below it cost coupling on about 20 ms of style time (P13 red at
   104 to 116 ms, run line 8c, 09.10.2026). A formula's only child is its term
   (pipeline/abbildungen.py). */
.abb-formel > .abb-formel-term { text-indent: 0; }
.abb-nr { display: inline-block; min-width: 2.25em; text-indent: 0; }
/* A fraction is as wide as its longer line, at most the line; a word formula
   longer than that wraps inside its numerator and denominator (2026/1563 E1
   AR 22 ran 640px wide and pushed the page past 1280 with the second pane,
   darstellung D6, 09.10.2026). */
/* The fraction's own margins count against its line: at max-width: 100% it
   ended 3px past a 375px formula line (2026/1563 E1, E5; abbildungen B6). */
.abb-bruch { position: relative; display: inline-block; width: max-content; max-width: calc(100% - .2em); vertical-align: middle; text-align: center; line-height: 1.3; margin: 0 .1em; }
.abb-z, .abb-n { display: inline-block; width: 100%; box-sizing: border-box; padding: 0 .35em; }
.abb-z { border-bottom: 1px solid currentColor; padding-bottom: 1px; }
.abb-n { padding-top: 2px; }
/* The slash is there for copying ("a/b"); unseen, it sits at its fraction's
   corner. At its static place after a full-width numerator its glyph stood
   past the card edge at 375px (2026/1563 E1, layout [21]). */
.abb-strich { position: absolute; left: 0; top: 0; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* A structure figure: frames with an eyebrow title, the inner statement on the
   brand tint, tiles on the muted tone, sections white with a muted head; two
   columns from 500px. A group's plain sentence stands before its list (ESRS 1
   Appendix G); a list can sit inside a tile; an empty section keeps a short
   body, as the source draws it as an open box. */
.abb-struktur { font: 400 14px/1.45 var(--font-body); color: var(--foreground); }
.abb-rahmen { border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 12px 14px 14px; }
/* Every node after the frame's first child; its title is always first. Named,
   not "* + *" (see .abb-formel above): the nodes abbildungen._knoten writes. */
.abb-rahmen > :is(.abb-kachel, .abb-raster, .abb-rahmen, .abb-abschnitt):not(:first-child) { margin-top: 12px; }
.abb-rahmen .abb-rahmen { border-color: var(--vw-tint-success-border); background: var(--vw-tint-success); border-radius: var(--radius-md); }
.abb-rahmen-titel { font: 700 12px/1.25 var(--font-heading); letter-spacing: .06em; text-transform: uppercase; color: var(--muted-foreground); }
.abb-rahmen .abb-rahmen .abb-rahmen-titel { color: var(--jr-primary-text); }
.abb-raster { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; align-items: start; }
.abb-spalte { display: flex; flex-direction: column; gap: 10px; }
.abb-kachel { background: var(--muted); border-radius: var(--radius-md); padding: 10px 12px; }
.abb-abschnitt { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; }
.abb-abschnitt-titel { font-weight: 600; padding: 8px 12px; background: var(--muted); border-bottom: 1px solid var(--border); }
.abb-abschnitt-rumpf { padding: 10px 12px 4px; }
.abb-abschnitt-rumpf:empty { padding: 0; height: 16px; }
.abb-gruppe { font-weight: 600; margin: 0 0 4px; }
.abb-gruppe-text { margin: 0 0 4px; }
.abb-abschnitt-rumpf > .abb-gruppe:not(:first-child) { margin-top: 10px; }
:is(.abb-abschnitt, .abb-kachel) ul { margin: 0 0 10px; padding-left: 18px; }
.abb-kachel ul { margin: 4px 0 0; }
:is(.abb-abschnitt, .abb-kachel) li { margin: 2px 0; }
:is(.abb-abschnitt, .abb-kachel) li::marker { color: #A8A29E; /* tokens color.text.tertiary */ }
/* The charts: square bars, no shadow; emissions and shares solid in the
   secondary text tone, growth light, own reductions on the brand tint,
   value-chain reductions and removals hatched; axes in the secondary tone,
   the base level dashed. */
.abb-achse { fill: none; stroke: var(--muted-foreground); stroke-width: 1.5; }
.abb-bezug { fill: none; stroke: var(--abb-linie); stroke-width: 1.5; stroke-dasharray: 5 4; }
.abb-fuehrung { fill: none; stroke: var(--border); stroke-width: 1; }
.abb-mass { fill: none; stroke: var(--abb-linie); stroke-width: 1.5; }
.abb-zielmarke { fill: none; stroke: var(--foreground); stroke-width: 2.5; }
.abb-balken { stroke-width: 1; }
.abb-reihe-emission, .abb-reihe-anteil { fill: var(--muted-foreground); stroke: var(--muted-foreground); }
.abb-reihe-wachstum { fill: var(--border); stroke: var(--abb-linie); }
.abb-reihe-eigen { fill: var(--vw-tint-success-hover); stroke: var(--jr-primary-text); }
.abb-reihe-kette { stroke: var(--jr-primary-text); }
.abb-reihe-abbau { stroke: var(--muted-foreground); }
.abb-schraffur-grund { fill: var(--bg-elevated); }
.abb-schraffur-kette { stroke: var(--jr-primary-text); stroke-width: 2; }
.abb-schraffur-abbau { stroke: var(--abb-linie); stroke-width: 2; }
.abb-dlabel, .abb-dkopf, .abb-dgruppe, .abb-dneben, .abb-dinnen, .abb-dmass, .abb-dachse { box-sizing: border-box; height: 100%; display: flex;
  align-items: center; font: 400 13px/18px var(--font-body); color: var(--foreground); }
.abb-dkopf { font-weight: 600; font-size: 14px; }
.abb-dgruppe { font-weight: 600; color: var(--muted-foreground); padding-left: 18px; }
/* The words inside a bar carry the bar's own fill: the box covers the bar
   exactly, so nothing changes to the eye, but the white text has its dark
   ground in the HTML too (7.6:1), not only in the SVG rect behind it, which
   a contrast check walking up the DOM cannot see (darstellung D10). The
   renderer allows inner words only on these dark series. */
.abb-dinnen { justify-content: center; color: #FFFFFF; font-weight: 600; white-space: nowrap;
  background: var(--muted-foreground); }
.abb-dneben { padding-left: 2px; }
.abb-dziel { height: auto; }
.abb-dmass { justify-content: center; align-items: flex-start; font-weight: 600; }
.abb-dachse { justify-content: flex-end; align-items: flex-end; color: var(--muted-foreground); }
/* A kept image (GHS pictograms, the water-stress map; Jannik 09.10.2026): the
   source image with its words as a caption a reader can copy. A pictogram in a
   table cell stands at 96px. */
.abb-bild img { max-width: 100%; height: auto; }
td .abb-bild { margin: 4px 0; }
td .abb-bild img { width: 96px; }
.abb-bild-text { margin-top: 6px; font: 400 13px/1.4 var(--font-body); color: var(--muted-foreground); }

/* -- 50.49 Feedback to support (line 15 of the run, 09.10.2026) ----------
   The footer's "Fehler melden" switches feedback mode on. Its bar takes the
   bottom slot of the copy pill (26px above the edge, centred from 521px) on
   the brand tint of the notes; while it shows, the paragraph under the
   pointer is outlined, so the reader sees what a click marks. The field in
   the selection bar wears the Akte field's look (.akte-feld). The honeypot
   for bots sits off screen, out of the tab order and hidden from screen
   readers. Light surface, no shadow; only transform moves (none here). */
.melde-leiste {
  position: fixed; z-index: var(--z-toast); left: 16px; right: 16px;
  bottom: calc(26px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 10px;
  padding: 8px 8px 8px 14px; border-radius: var(--radius-md);
  border: 1px solid var(--vw-tint-success-border); background: var(--vw-tint-success);
  color: var(--jr-primary-text); font-size: 14px; line-height: 1.45;
}
.melde-leiste[hidden] { display: none; }
.melde-leiste > span { flex: 1; color: var(--foreground); }
.melde-leiste-ab {
  flex-shrink: 0; font: inherit; font-size: 13px; font-weight: 600;
  padding: 5px 12px; border-radius: var(--radius-sm); cursor: pointer;
  border: 1px solid var(--border); background: var(--bg-elevated); color: var(--foreground);
}
.melde-leiste-ab:hover { border-color: var(--jr-primary); }
@media (min-width: 521px) {
  .melde-leiste { left: 50%; right: auto; width: max-content; max-width: 560px; transform: translateX(-50%); }
}
.melde-modus .page-card [data-cite-label]:hover {
  outline: 2px solid var(--jr-primary-text); outline-offset: 3px; cursor: pointer;
}
/* the marked spot while the field is open (the field's focus clears the selection) */
.melde-markiert { outline: 2px solid var(--jr-primary-text); outline-offset: 3px; }
.melde-honig { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
/* The status line on the dark bar: Stone 400 like the note (12c); an error
   stands on the red mark chip (--ev-mark-text-red on its fill, 5.61:1). */
.melde-status { font-size: 12px; line-height: 1.4; color: #A8A29E; margin: 0 0 10px; }
.melde-status.is-fehler {
  color: var(--ev-mark-text-red); background: var(--ev-mark-fill-red);
  padding: 6px 8px; border-radius: var(--radius-sm);
}
.melde-mail { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.melde-los:disabled { opacity: .6; cursor: progress; }

/* -- 50.50 A restriction the reader sees (P2c 9b.5, 09.10.2026) -----------
   Jannik 09.10.2026: "Einschränkungen ... muss nur transparent sein". Two
   functions were silently missing (inventory checks/p2c/9b5):
   (1) Below 1024px the rail is gone and with it the reading aid for
   Randziffer, AR and DR. The drawer carries it, as it carries the font
   size (50.14); an overline as the font size's, the terms as in the rail.
   (2) The VSME has no application requirements, so its pages have no
   "Vergleichen". The source menu names them, disabled, with the note "nur
   ESRS" (viewer.js buildEsrsOnlyItem), as the transition view's entries
   once said "kommt mit v3". A disabled button in the cap with the note took
   the part links into a second row (95px instead of 57) and pushed DE/EN
   past the bar at 375px; the menu costs no bar space. */
.drawer-aid { display: none; }
@media (max-width: 1023px) {
  .drawer-aid {
    display: block;
    margin-top: 12px;
    padding: 12px 6px 4px;
    border-top: 1px solid var(--border);
  }
  .drawer-aid h2 {
    margin: 0 0 6px;
    font-family: var(--font-heading);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted-foreground);
  }
  .drawer-aid h2 .msym { display: none; }
}
.src-menu-item .src-menu-note { flex-shrink: 0; margin-left: auto; font-size: 12px; color: var(--muted-foreground); }
/* Where the menu is capped (320px, a wider font), the note goes to a
   second line instead of cutting the label it explains. */
.src-menu-item:disabled { flex-wrap: wrap; row-gap: 2px; }

/* -- 50.51 No bubble over its own open menu (P2c 9b.5a, 09.10.2026) -------
   With a source menu open, the picker's bubble ("Was das linke Fenster
   zeigt") covered the menu's first entry while the pointer rested on the
   picker. The open menu answers what the bubble says; the bubble comes back
   once the menu closes. As specific as the bubble's show rule
   ([data-tip]:hover::after) and later, so it wins under the pointer and on
   focus. */
[data-tip][aria-expanded="true"]::after { opacity: 0; visibility: hidden; }

/* -- 50.52 Nothing opens on hover while the page scrolls (09.10.2026) -------
   Jannik: "beim Scrollen, wenn die Maus aus Versehen irgendwo drüber fährt,
   soll sich kein Popup öffnen". From a scroll until the pointer really
   moves, #app carries scroll-muted (viewer.js initScrollHoverMute). A popup
   or bubble that only hover would open stays closed; the ID selector beats
   the hover rules, as in 49b.4. What a click or the keyboard opened
   (.is-open, :focus-visible) stays. .gloss and .xref are named besides
   .pop-trigger because they carry that class only once touched. */
#app.scroll-muted :is(.pop-trigger, .gloss, .xref):not(.is-open) > .pop { display: none; }
#app.scroll-muted [data-tip]:hover:not(:focus-visible)::after { opacity: 0; visibility: hidden; }

/* -- 50.53 The calendar button (Jannik 09.10.2026) -------------------------
   The website's folded Termin-Dock without photo or times: 44px, white,
   1px border, the md shadow, the calendar in brand green, bottom right.
   Its bubble opens upward and ends at the button's right edge, so it stays
   in the window. Under the header and the drawer's scrim, under every popup
   and bubble. It gives way while the footer, with its own booking link, is
   in view (data-away, viewer.js initBookingDock: never two booking elements
   at once, website rule A6) and while the feedback bar shows. */
:root { --z-dock: 90; }
.book-dock {
  position: fixed; z-index: var(--z-dock);
  right: 24px; bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  display: grid; place-items: center; width: 44px; height: 44px;
  border-radius: var(--radius-lg); background: #FFFFFF; color: var(--jr-primary-text);
  box-shadow: inset 0 0 0 1px var(--border), var(--shadow-md);
  transition: opacity var(--jr-duration-normal) var(--jr-ease-in),
              visibility 0s linear var(--jr-duration-normal);
}
.book-dock .msym { font-size: 20px; }
@media (hover: hover) { .book-dock:hover { background: var(--vw-tint-success-hover); } }
@media (max-width: 639.98px) { .book-dock { right: 16px; } }
.book-dock[data-away],
body:has(.melde-leiste:not([hidden])) .book-dock { opacity: 0; visibility: hidden; }
/* Below 1280px the second pane is a sheet over the bottom of the window
   (E-5); the button sat under it, out of sight but still in the tab order
   (layout 32, DE/EN preset at 1024 and 800px). It gives way to the sheet. */
@media (max-width: 1279px) {
  body:has(#p-split:not([hidden])) .book-dock { opacity: 0; visibility: hidden; }
}
.book-dock[data-tip]::after { top: auto; bottom: calc(100% + 8px); left: auto; right: 0; transform: none; }
@media (prefers-reduced-motion: reduce) { .book-dock { transition: none; } }
@media print { .book-dock { display: none; } }

/* -- 50.54 The website's home in words (Jannik 09.10.2026) ---------------
   "im header will ich den link auch haben": the wordmark leads to the
   website since D4 of 05.10.2026 but does not say so. From 1024px a quiet
   text link opened the right-hand group; the search field (flex: 1,
   min-width: 0) gives way, the row keeps its height. Below 1024px the bar
   has 12 to 16px left (measured at 320, 640 and 768px), so the drawer
   carries the link in its top strip, opposite its close button.
   Evening ("einen cooleren Link"): the grey "justreporting.eu" named no
   destination and stood quieter than the pill beside it. Now a door pill
   in the bar's last slot, behind a hairline: "Zur Website" with a trailing
   arrow, the brand tint on the canon's pattern (8 % surface, 30 % border),
   the only tinted pill in the bar, so it stands out by colour, not size.
   arrow-right means onward in this tab; external-link stays with EUR-Lex.
   The drawer carries the same pill. Light only: the opaque color-mix
   values render the same under a dark OS setting. */
.hdr-sep { width: 1px; height: 24px; flex: none; background: var(--border); }
.hdr-home,
.drawer-home {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  min-height: 34px; padding: 0 12px 0 14px;
  border: 1px solid var(--vw-tint-success-border);
  border-radius: var(--radius-pill);
  background: var(--vw-tint-success);
  color: var(--jr-primary-text);
  font: 600 14px/1 var(--font-heading);
  white-space: nowrap; text-decoration: none;
  transition: background-color var(--jr-duration-fast) var(--jr-ease-out),
              transform var(--jr-duration-fast) var(--jr-ease-out);
}
.hdr-home .msym,
.drawer-home .msym {
  width: 16px; height: 16px; flex: none;
  transition: transform var(--jr-duration-fast) var(--jr-ease-spring);
}
@media (hover: hover) {
  .hdr-home:hover,
  .drawer-home:hover { background: var(--vw-tint-success-hover); text-decoration: none; }
  .hdr-home:hover .msym,
  .drawer-home:hover .msym { transform: translateX(2px); }
}
.hdr-home:active,
.drawer-home:active { transform: scale(.97); }
/* The bubble names who is behind the viewer. The pill is the bar's last
   control, so the bubble hangs from its right edge, below the bar. */
.hdr-home[data-tip]::after { left: auto; right: 0; transform: none; }
.drawer-home { display: none; }
@media (max-width: 1023px) {
  .hdr-sep,
  .hdr-home { display: none; }
  .drawer-home { position: absolute; top: 12px; left: 10px; display: inline-flex; min-height: 36px; }
}
@media (max-width: 1023px) and (pointer: coarse) {
  .drawer-home { top: 8px; min-height: 44px; }
}
/* Reduced motion: nothing moves; hover adds an underline, so the state is
   not carried by colour alone. */
@media (prefers-reduced-motion: reduce) {
  .hdr-home, .drawer-home, .hdr-home .msym, .drawer-home .msym { transition: none; }
  .hdr-home:active, .drawer-home:active { transform: none; }
}
@media (prefers-reduced-motion: reduce) and (hover: hover) {
  .hdr-home:hover .msym, .drawer-home:hover .msym { transform: none; }
  .hdr-home:hover, .drawer-home:hover { text-decoration: underline; text-underline-offset: 3px; }
}
