/* ==========================================================================
   SEITENSCHALE UND WERTEVORRAT

   Die Marke von conve (www.conve.at) in Tokens gegossen. Die NAMEN sind
   dieselben geblieben, die die rund 1500 Zeilen Fachschicht darunter benutzen
   - nur ihre WERTE sind jetzt Conve. Wer einen Namen ändert, macht aus einer
   Farbanpassung eine Umschreibung der ganzen Datei.

   >> WO DIE MARKENWERTE NICHT UEBERNOMMEN WURDEN, UND WARUM.

   Die Website ist ein Marketingauftritt: große Flächen, kurze Texte, viel
   Weiss. Dieses Werkzeug ist eine Maske, vor der jemand stundenlang sitzt und
   Kleingedrucktes liest. Drei Markenfarben erreichen dort den geforderten
   Kontrast nicht (WCAG 1.4.3: 4,5:1 im Fliesstext). Sie sind abgedunkelt,
   Farbton und Wiedererkennung bleiben. Nachgerechnet, nicht geschätzt:

     Marke              auf Weiss   verwendet         auf Weiss
     --primary  #007DA9   4,66:1     #005F82 (Marke:   7,10:1
                                     --primary-dark)
     Fehler     #E74C3C   3,82:1     #C0392B           5,44:1
     Erfolg     #28CA42   2,18:1     #146C33           6,52:1
     --text-muted #8891A4 3,17:1     #616B7F           5,36:1

   #007DA9 ist nicht verloren: Es steht als --akzent-hell für alles, was
   nicht gelesen, sondern gesehen wird - Fokusring, Überfahren, Kanten - und
   als <meta name="theme-color"> in allen drei Layouts.

   Der Grund für #005F82 statt #007DA9 im Fliesstext ist eng: Ein Verweis in
   Markenblau auf der Seitenfläche --grund erreicht 4,26:1 und liegt damit
   knapp unter der Schwelle. "Knapp" heißt hier: bei jedem zweiten Link auf
   jeder Seite.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Inter, aus dem eigenen Haus

   Die Hausschrift liegt unter assets/vendor/inter/ - zwei variable Schnitte
   (Achse wght 100-900) in genau den Teilmengen, die Google Fonts ausliefert.
   Nachgesehen, nicht angenommen: `latin` trägt 230 Zeichen einschließlich
   ae/oe/ue/ss, Gedankenstrich und Mittelpunkt; `latin-ext` trägt 733 und
   fängt an, wo `latin` aufhört. Die unicode-range-Angaben unten sind
   deshalb keine Zierde - ohne sie lädt der Browser die falsche der beiden
   Dateien und setzt Kästchen statt Buchstaben.

   Zwei url() und keine dritte: Die CSP lautet font-src 'self', und das System
   sagt nach außen genau drei Ausgänge zu. Ein Schriftabruf wäre ein
   vierter.
   -------------------------------------------------------------------------- */
@font-face {
    font-family: 'Inter';
    src: url("../vendor/inter/inter-latin-Gz7AlRl.woff2") format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
                   U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Inter';
    src: url("../vendor/inter/inter-latin-ext-1Br77OV.woff2") format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    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;
}

/* >> DER ERSATZSCHNITT IST KEINE ZIERDE.
   font-display:swap heißt: Der Browser setzt die Seite erst mit der
   Ersatzschrift und tauscht dann. Arial ist deutlich schmaler und
   kurzbäuchiger als Inter - ohne Angleichung springt beim Tausch die ganze
   Maske, und zwar sichtbar. Die vier Werte sind die Metriken von Inter,
   umgerechnet auf Arial; sie verändern nur den Ersatz, nie Inter selbst.
   local() ist kein Netzabruf und von der CSP nicht berührt. */
@font-face {
    font-family: 'Inter Ersatz';
    src: local('Arial'), local('Helvetica'), local('Liberation Sans');
    size-adjust: 107.12%;
    ascent-override: 90.2%;
    descent-override: 22.48%;
    line-gap-override: 0%;
}

/* ==========================================================================
   DER WERTEVORRAT

   >> BIS HIERHER WAR NUR DIE FARBE ENTSCHIEDEN.

   Die erste Fassung dieses Blattes fuehrte siebzehn Farbtoken mit
   nachgerechneten Kontrasten - und keinen einzigen Abstand, keine
   Schriftgroesse, keine Zeilenhoehe, keine Bedienhoehe. Nachgezaehlt, bevor
   hier etwas geaendert wurde:

     Dimension       Token   im Umlauf   in Deklarationen
     Farbe             17        2            (vorbildlich)
     Radius             5        4            (vorbildlich)
     Abstand            0       39                 589
     Schriftgroesse     0       30                 166
     Zeilenhoehe        0        8                  --
     Bedienhoehe        0        7                  --

   Das ist die Ursache dessen, was der Auftraggeber "schlecht dargestellt"
   genannt hat: Nichts hatte zweimal denselben Wert, also sah nichts
   absichtlich gesetzt aus. Neununddreissig Abstandsstufen sind keine
   Gestaltung, sondern neununddreissig Einzelentscheidungen, von denen keine
   die anderen kennt.

   >> WARUM LEITERN UND NICHT NUR NAMEN.

   Ein Token, das einen vorgefundenen Wert nur umbenennt, aendert nichts. Die
   Leitern unten sind deshalb GESCHLOSSEN und grob: acht Abstaende, sechs
   Schriftgroessen, drei Zeilenhoehen, drei Bedienhoehen. Wer eine neunte
   Stufe braucht, muss sie hier eintragen - und sieht dann beim Lesen dieser
   Datei, wie viele es geworden sind. Das ist dieselbe Vorkehrung, die weiter
   unten die neunzehn Prozentbreiten der CSP-Ersatzklassen zusammenhaelt.

   >> DIE FARBEN SIND UNVERAENDERT. Ihre Namen, ihre Werte, ihre
   Kontrastrechnungen. Sie waren die einzige Dimension, die bereits ein
   System hatte; sie anzufassen haette Substanz zerstoert und nichts geloest.
   Dazugekommen sind sieben, und zwar ABGELEITET statt gegriffen - siehe
   unten.
   ========================================================================== */

:root {
    /* ------------------------------------------------------------------
       FLAECHEN. Reihenfolge wie in der ersten Fassung: --grund ist die
       dunkelste, --flaeche das Papier, --flaeche-2 liegt dazwischen. Die
       Fachschicht rechnet damit (eine Karte auf --grund, eine Einlassung
       auf --flaeche-2 in der Karte); eine Umkehrung liesse Kacheln
       verschwinden.
       ------------------------------------------------------------------ */
    --grund:#eef2f6; --flaeche:#fff; --flaeche-2:#f6f9fb;

    /* NEU: die vierte Stufe, eingelassen. Sie fehlte, und deshalb sahen
       Rollbehaelter, Vorschaufenster und der Grund eines Dateifelds aus wie
       eine Karte statt wie eine Vertiefung. */
    --flaeche-3:#e9eff5;

    /* ------------------------------------------------------------------
       SCHRIFT. --tinte und --tinte-2 sind die Markenwerte --text und
       --text-secondary. --tinte-3 ist die abgedunkelte Fassung von
       --text-muted: Der Markenwert erreicht 3,17:1 und traegt in dieser
       Anwendung Fliesstext (die unveraenderten Zeilen im Wortlautdiff).
       ------------------------------------------------------------------ */
    --tinte:#1a1a2e; --tinte-2:#4a5568; --tinte-3:#616b7f;

    /* ------------------------------------------------------------------
       KANTEN. --rand ist der Markenwert, leicht abgedunkelt, weil er hier
       gegen eine getoente statt gegen eine weisse Seite steht. --rand-stark
       erreicht 3,28:1 auf Weiss - die Schwelle fuer die Umrandung eines
       Bedienelements (WCAG 1.4.11).
       ------------------------------------------------------------------ */
    --rand:#dce2ea; --rand-weich:#ebeff4; --rand-stark:#838fa0;

    /* ------------------------------------------------------------------
       AKZENT. --akzent traegt Schrift und muss lesbar sein; --akzent-hell
       ist das Markenblau und traegt, was gesehen und nicht gelesen wird.
       ------------------------------------------------------------------ */
    --akzent:#005f82; --akzent-hell:#007da9; --akzent-weich:#c8e8fb;

    /* NEU. Der gefuellte Hauptknopf brauchte einen Zustand fuer den Zeiger.
       app.css:3580 schrieb `var(--akzent-dunkel, var(--akzent))` - mit
       Rueckfall, also folgenlos, aber eben auch wirkungslos: Der wichtigste
       Knopf jeder Maske antwortete nicht auf das Ueberfahren. */
    --akzent-dunkel:#004a66;

    /* ------------------------------------------------------------------
       SEMANTIK. Farbe traegt nie allein eine Aussage (WCAG 1.4.1) - alle
       drei stehen in der Fachschicht neben einem Wort.
       ------------------------------------------------------------------ */
    --warn:#c0392b; --hinweis:#96610d; --gut:#146c33;

    /* >> DIE SECHS GETOENTEN WERTE SIND GERECHNET, NICHT GEGRIFFEN.

       Sie standen zwoelfmal als `color-mix(in srgb, var(--warn) 6%,
       transparent)` mitten in der Fachschicht - jedes Mal mit einem anderen
       Prozentsatz (6, 7, 8, 12), weil niemand nachsah, was daneben stand.

       Als Ableitung geschrieben loesen sie zwei Aufgaben auf einmal:
       Sie sind EIN Wert statt zwoelf, und sie kippen im Dunkelmodus von
       selbst mit - `--warn` und `--flaeche` sind dort andere Farben, die
       Mischung folgt. Deshalb steht unten im Dunkelmodusblock keine
       Wiederholung dieser sechs Zeilen.

       `var(--flaeche)` und nicht `transparent`: Eine durchscheinende Toenung
       nimmt die Farbe dessen an, was zufaellig dahinterliegt - unter einem
       haftenden Tabellenkopf ist das die durchrollende Zeile. */
    --warn-weich:color-mix(in srgb, var(--warn) 8%, var(--flaeche));
    --hinweis-weich:color-mix(in srgb, var(--hinweis) 9%, var(--flaeche));
    --gut-weich:color-mix(in srgb, var(--gut) 8%, var(--flaeche));

    /* Die Kante desselben Kastens. 40 Prozent, damit sie sich von der
       Flaeche abhebt, ohne die Lautstaerke der Vollfarbe zu haben. */
    --warn-rand:color-mix(in srgb, var(--warn) 40%, var(--rand));
    --hinweis-rand:color-mix(in srgb, var(--hinweis) 40%, var(--rand));
    --gut-rand:color-mix(in srgb, var(--gut) 40%, var(--rand));

    /* Die Kopfleiste des Portals. Eigene Token, damit die Flaeche im
       Dunkelmodus mitkippen kann, statt als heller Balken stehen zu bleiben. */
    --portalband:#005f82; --portalband-tinte:#fff;

    /* ==================================================================
       DIE RAUMLEITER — acht Stufen auf dem 4px-Raster

       Ersetzt 39 freie Werte in 589 Deklarationen, davon 19 Stufen allein
       unterhalb von 1rem (.15 .2 .25 .3 .32 .35 .4 .45 .5 .55 .6 .65 .7
       .75 .8 .9). Vier Pixel sind die kleinste Einheit, die man auf einem
       Bildschirm noch als Absicht liest.

       In rem und nicht in px: Ein fester Pixelwert uebergeht die im Browser
       eingestellte Grundschrift. Wer sie auf 20px stellt, bekommt hier
       groessere Abstaende mit - genau das ist der Zweck.
       ================================================================== */
    --raum-0:0;
    --raum-1:.25rem;   /*  4px  innerhalb einer Zeile: Marke zu Wort        */
    --raum-2:.5rem;    /*  8px  Zellpolsterung senkrecht, Knopfluecke       */
    --raum-3:.75rem;   /* 12px  Zellpolsterung waagrecht, Feldpolsterung    */
    --raum-4:1rem;     /* 16px  zwischen Geschwistern                       */
    --raum-5:1.5rem;   /* 24px  zwischen Abschnitten, Rasterluecke          */
    --raum-6:2rem;     /* 32px  zwischen Bloecken                           */
    --raum-7:3rem;     /* 48px  zwischen Kapiteln                           */
    --raum-8:4rem;     /* 64px  Seitenfuss                                  */

    /* ==================================================================
       DIE SCHRIFTLEITER — sechs Stufen

       Ersetzt 30 Werte in 166 Angaben. 98 davon lagen im Band .82rem bis
       .98rem: dreizehn Stufen fuer einen einzigen Zweck, naemlich "etwas
       kleiner als Fliesstext". Das ist jetzt --schrift-sm, und es ist EIN
       Wert.

       Die Stufen sind bewusst weit auseinander. Zwei Groessen, die sich um
       0,03rem unterscheiden, sind keine Hierarchie - sie sind ein Fehler,
       den niemand bemerkt.
       ================================================================== */
    --schrift-xs:.75rem;       /* Marke, Tabellenkopf, Gruppentitel, Pfad   */
    --schrift-sm:.875rem;      /* ARBEITSWERT: Zelle, Beitext, Beschriftung */
    --schrift-md:1rem;         /* Fliesstext                                */
    --schrift-lg:1.125rem;     /* h2                                        */
    --schrift-xl:1.375rem;     /* h1 im Seitenkopf                          */
    --schrift-2xl:1.75rem;     /* Kachelziffer                              */

    /* >> WARUM h1 KLEINER WIRD (1.75rem -> 1.375rem).

       Ein Fachwerkzeug braucht keinen Plakattitel. Die alte Groesse stammt
       aus einem Satzspiegel fuer Fliesstext; auf einer Maske, deren
       Ueberschrift "12 Lohnverrechnung" lautet, kostet sie nur senkrechten
       Platz. Die Ordnung leistet der Seitenkopf, nicht die Punktgroesse. */

    /* ==================================================================
       ZEILENHOEHE — drei Stufen statt acht Werten von 1.1 bis 1.7

       Der groesste Einzelhebel fuer Dichte. Die Grundzeile faellt von 1.6
       auf 1.5; zusammen mit der Zellpolsterung aus der Raumleiter sinkt die
       Tabellenzeile von 45,3 auf rund 35 Pixel. In der Fristenliste stehen
       damit elf Zeilen im Bild statt sieben.
       ================================================================== */
    --zeile-eng:1.3;      /* Ueberschriften, Tabellenzellen, Marken         */
    --zeile-normal:1.5;   /* Grundzeile                                     */
    --zeile-weit:1.65;    /* Erlaeuterungen, Portal                         */

    /* ==================================================================
       SCHRIFTGEWICHT

       Vorgefunden: 400, 600, 650, 700 - wobei 650 in einer variablen
       Schrift eine eigene Strichstaerke ist und in der Ersatzschrift auf
       700 einrastet. Beim Tausch sprang die Seite. Vier benannte Stufen,
       alle in der Achse von Inter (100-900) und in Arial vorhanden.
       ================================================================== */
    --fett-normal:400; --fett-halb:500; --fett-stark:600; --fett-voll:700;

    /* ==================================================================
       BEDIENHOEHE — drei Stufen statt sieben ungeordneten

       Knopf, Feld, Auswahl, Filterreiter und Blaetterschritt waren sieben
       verschiedene Hoehen. Nebeneinander in einer Werkzeugleiste sah das
       aus, als sei es aus Teilen zusammengesetzt - was es auch war.

       2,25rem ist der Regelfall und kein Kompromiss: Es ist die Hoehe, bei
       der --schrift-sm mit --raum-2 Innenabstand senkrecht sitzt.
       ================================================================== */
    --hoehe-1:1.75rem;   /* 28px  Nebenhandlung in einer Tabellenzelle      */
    --hoehe-2:2.25rem;   /* 36px  REGELFALL                                 */
    --hoehe-3:2.75rem;   /* 44px  Anmeldung, Hauptabsenden, Beruehrungsziel */

    /* ==================================================================
       RADIUS

       Die fuenf Stufen standen schon da und wurden benutzt. Dazu kommt die
       Pille: Sie stand viermal als `border-radius:999px` im Blatt.
       ================================================================== */
    --radius-xs:4px;
    --radius-sm:8px; --radius-md:12px; --radius-lg:16px; --radius-xl:20px;
    --radius-voll:999px;

    /* ==================================================================
       SCHATTEN

       Die drei vorhandenen bleiben. Dazu einer fuer das, was ueber der
       Seite schwebt - Dialog und Aufklappmenue. Er ist deutlich staerker,
       weil ein Element ohne Abhebung nicht als "davor" gelesen wird.
       ================================================================== */
    --schatten-sm:0 1px 3px rgba(0,125,169,.06);
    --schatten-md:0 4px 20px rgba(0,125,169,.08);
    --schatten-lg:0 8px 40px rgba(0,125,169,.10);
    --schatten-schwebend:0 16px 48px rgba(16,24,32,.18), 0 2px 8px rgba(16,24,32,.10);

    /* ==================================================================
       BREITEN

       >> DIE AUSNAHME WIRD ZUR REGEL (und umgekehrt).

       Bisher galt ueberall 70rem, und ab 90rem Fensterbreite durfte die
       Arbeitsspalte auf 100rem wachsen. Das ist andersherum richtig: 58
       Prozent der Masken sind Datenmasken, und eine Tabelle mit siebzehn
       Spalten in 1120 Pixeln bricht auf vier Zeilen je Datensatz um,
       waehrend links und rechts je 276 Pixel leer bleiben.

       --breite-text bleibt der Deckel fuer alles, was gelesen wird. Eine
       Erlaeuterung ueber 1600 Pixel ist nicht lesbar, egal wie breit das
       Fenster ist.
       ================================================================== */
    --breite-text:70ch;    /* Fliesstext, Beitexte, Hilfetexte             */
    --breite-masse:70rem;  /* Formular- und Lesemasken                     */
    --breite-weit:100rem;  /* Listenmasken                                 */

    /* ==================================================================
       DAUER UND VERLAUF

       Vorgefunden: .1s, .12s, .15s, 120ms, .2s, 200ms - sechs Werte fuer
       zwei Absichten. Die Zeitkurve war ueberall `ease`; sie startet zu
       traege fuer einen Zustandswechsel unter dem Zeiger.

       Jede Bewegung dieses Blattes hat ein Gegenstueck in
       `prefers-reduced-motion` - das ist die Regel und keine Zugabe.
       ================================================================== */
    --dauer-schnell:.1s;
    --dauer-normal:.18s;
    --stufe:cubic-bezier(.2,0,.2,1);

    /* ==================================================================
       DIE EBENEN

       Vorgefunden: 1, 2, 3, 60 - ohne Namen, an vier Stellen im Blatt
       verteilt. Wer eine fuenfte brauchte, riet.

       Die Abstaende sind gross genug, dass ein Bauteil dazwischenpasst.
       ================================================================== */
    --ebene-haftend:2;         /* Tabellenkopf, haftende Zeile             */
    --ebene-gliederung:10;     /* die Gliederung beim Rollen               */
    --ebene-kopfleiste:60;     /* Kopf, Ebenenstreifen, Banner             */
    --ebene-ueberlagerung:100; /* Dialog, Aufklappmenue, Sprunglink        */
}

/* --------------------------------------------------------------------------
   DER DUNKELMODUS KIPPT AUSSCHLIESSLICH TOKEN.

   Jede Regel weiter unten, die eine feste Farbe setzt, bricht ihn - deshalb
   steht hier kein Hex, das nicht auch oben steht. Die Kontraste sind gegen
   --flaeche (#161e25) gerechnet: --tinte 14,2:1, --tinte-2 8,1:1,
   --tinte-3 4,6:1, --akzent 9,6:1, --warn 6,9:1, --hinweis 7,8:1,
   --gut 8,8:1.

   >> WAS HIER NICHT STEHT UND WARUM.

   Die sechs getoenten Semantikwerte und die drei Semantikkanten fehlen in
   diesem Block mit Absicht: Sie sind oben als Mischung aus --warn/--hinweis/
   --gut und --flaeche geschrieben. Beide Bestandteile kippen hier, also
   kippt die Mischung mit. Wer sie hier noch einmal auffuehrte, haette zwei
   Wahrheiten - und die zweite wuerde beim naechsten Farbwechsel vergessen.

   Ebenso fehlen Raum, Schrift, Zeile, Gewicht, Hoehe, Radius, Dauer und
   Ebene: Ein Abstand hat keinen Dunkelmodus.
   -------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
    :root:not([data-thema="hell"]) {
        --grund:#10161b; --flaeche:#161e25; --flaeche-2:#1c262e;
        /* Eingelassen heisst im Dunkeln TIEFER, nicht heller. */
        --flaeche-3:#0d1318;

        --tinte:#e6ecf2; --tinte-2:#a8b6c4; --tinte-3:#78889a;
        --rand:#2a3742; --rand-weich:#202b34; --rand-stark:#5a6c7b;

        --akzent:#84cde8; --akzent-hell:#a8dcf2; --akzent-weich:#10323f;
        /* Der gefuellte Knopf traegt hier helle Flaeche und dunkle Schrift.
           "Dunkler" beim Ueberfahren waere ein Rueckschritt in der
           Aufmerksamkeit - er wird heller, wie jede erhellte Flaeche. */
        --akzent-dunkel:#a8dcf2;

        --warn:#f08a80; --hinweis:#e0a64a; --gut:#6bd08a;
        --portalband:#0e2c3a; --portalband-tinte:#dceef7;

        /* Ein blaeulicher Schlagschatten ist auf dunklem Grund unsichtbar. */
        --schatten-sm:0 1px 3px rgba(0,0,0,.45);
        --schatten-md:0 4px 20px rgba(0,0,0,.5);
        --schatten-lg:0 8px 40px rgba(0,0,0,.55);
        --schatten-schwebend:0 16px 48px rgba(0,0,0,.65), 0 2px 8px rgba(0,0,0,.5);
    }
}


/* ==========================================================================
   GRUNDSCHICHT
   ========================================================================== */

* { box-sizing:border-box; }

body {
    /* 1rem und nicht 16px: Ein fester Pixelwert übergeht die im Browser
       eingestellte Grundschrift, und weil der Rest der Datei in rem rechnet,
       wäre die Einstellung für die ganze Anwendung wirkungslos. */
    margin:0; min-height:100dvh;
    display:flex; flex-direction:column;
    background:var(--grund); color:var(--tinte);
    font-family:'Inter','Inter Ersatz',-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans",sans-serif;
    font-size:var(--schrift-md); line-height:var(--zeile-normal);
    -webkit-font-smoothing:antialiased;
}

/* >> DER UNTERSTRICH GEHOERT IN DEN FLIESSTEXT, NICHT IN DIE BEDIENUNG.
   
   Bis AP-H17 war jeder Verweis unterstrichen - auch die Kachelzahl im
   Cockpit, auch jeder Spaltenkopf, auch jeder Filter. Eine Oberflaeche, in
   der alles unterstrichen ist, sieht nicht nach Anwendung aus, sondern nach
   Dokument.

   WCAG 1.4.1 verlangt, dass ein Verweis IM TEXT nicht allein an der Farbe
   haengt. Genau dort steht der Unterstrich weiter: in Absaetzen, Beitexten
   und Aufzaehlungen. Ein Verweis, der allein in einer Tabellenzelle, auf
   einer Kachel oder in der Gliederung steht, ist von umgebendem Text nicht zu
   unterscheiden - es gibt keinen -, und er bekommt den Unterstrich beim
   Ueberfahren. */
a { color:var(--akzent); text-decoration:none; text-underline-offset:2px; }
a:hover { text-decoration:underline; }

p a, li a, dd a, caption a, .unterzeile a, .hilfe a, .hinweis a, .warnung a,
.leerfall a, .help-text a, small a, .klein a {
    text-decoration:underline;
}

/* Der Fokusring ist das Markenblau: Er wird gesehen und nicht gelesen, und er
   soll sich von der Schriftfarbe unterscheiden, damit man ihn nicht für eine
   Auszeichnung hält. 4,66:1 gegen Weiss und 4,26:1 gegen --grund - die
   Schwelle für ein Bedienelement liegt bei 3:1 (WCAG 1.4.11). Genau diese
   4,26 waren der Grund, ihn NICHT auch zur Schriftfarbe zu machen: Für
   Fliesstext gilt 4,5:1. */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, summary:focus-visible,
[tabindex]:focus-visible {
    outline:2px solid var(--akzent-hell); outline-offset:2px;
}



/* ==========================================================================
   SCHALE UND RASTER
   ========================================================================== */

/* ==========================================================================
   FAMILIE: RASTER, SCHALE UND BREITEN

   Diese Familie legt fest, WO etwas steht. Drei Dinge, die das Blatt bisher
   an Ort und Stelle handgeschrieben hat:

     1. ein benanntes Raster, damit nicht jede Maske ihr eigenes erfindet
        (24 handgeschriebene `grid-template-columns` standen im Blatt),
     2. eine Schale mit GEMESSENEN Massen statt geschaetzten Zahlen,
     3. eine Breitensteuerung, die Liste und Formular unterscheidet.

   >> DIE LEITREGEL DIESER FAMILIE.

   Eine Medienabfrage misst das FENSTER. Fast alles, was hier zu bemessen
   ist, steht aber in `main`, und `main` steht in `.rumpf`, dem die
   Gliederung `--gliederung-breite` wegnimmt. Bei 90rem Fenster hat die
   Arbeitsspalte 72rem Inhalt, nicht 90. Das Blatt hat diesen Unterschied
   bisher an drei Stellen von Hand nachgerechnet (`.werkbank` bei 105rem,
   `.beleg-und-arbeit` und `.durchsicht-paar` bei 90rem) und die Rechnung
   jedes Mal in einen Kommentar geschrieben.

   Deshalb: Die SCHALE misst das Fenster (Medienabfragen), der INHALT misst
   seine eigene Spalte (`auto-fit` mit `minmax`). Das ist der Grund, warum
   unten vier Bruchpunkte reichen, wo vorher acht standen - drei davon
   verschwinden nicht durch Zusammenlegen, sondern weil die Regel dahinter
   gar keinen Bruchpunkt braucht.
   ========================================================================== */


/* --------------------------------------------------------------------------
   DIE MASSE DER SCHALE

   ACHTUNG BEIM ZUSAMMENFUEGEN: Dieser :root-Block ERGAENZT den Wertevorrat
   ganz oben im Blatt, er ersetzt ihn nicht. Er muss NACH den Bloecken der
   Familien Raum/Schrift/Radius stehen, weil er `--raum-*` und `--hoehe-3`
   benutzt.

   Die Hoehenwerte sind gemessen - und sie sind unten mit `min-height` an den
   Bauteilen FESTGENAGELT. Das ist der Grund, aus dem sie stimmen duerfen:
   Eine Zahl, die nur einmal nachgemessen wurde, ist beim naechsten Eingriff
   falsch. Genau das ist passiert: `--kopfleiste-hoehe` stand seit AP-H15 auf
   4rem (app.css:2769, mitten im Blatt), AP-H23 setzte den Ebenenstreifen
   darunter und brachte die Leiste auf 7,5rem. Der feststehende Tabellenkopf
   klebte seither 3,5rem zu hoch und verschwand unter dem Streifen.
   -------------------------------------------------------------------------- */
:root {
    /* Kopfzeile: Kontozeile (--schrift-sm, .3rem Innenabstand) plus zweimal
       --raum-2 Innenabstand plus die 1px-Kante unten. */
    --kopf-hoehe:3.5rem;

    /* Ebenenstreifen: Reitertitel, Beitext, zweimal --raum-2 und die
       3px-Kante, die den offenen Reiter traegt. */
    --streifen-hoehe:4rem;

    /* Der Unterstuetzungsmodus ist nicht immer da - vorgabemaessig traegt er
       deshalb nichts zur Hoehe bei. */
    --banner-hoehe:0rem;

    /* Was oben feststeht. Aus den Teilen GERECHNET und nirgends abgeschrieben:
       Wer eine Zeile in den Kopf legt, aendert einen Wert und nicht sieben. */
    --kopfleiste-hoehe:calc(var(--banner-hoehe) + var(--kopf-hoehe) + var(--streifen-hoehe));

    /* 15rem statt der bisherigen 15.5rem. Der laengste Punkt der Gliederung
       ist "Dublettenpruefung"; mit Zeichen, Luecke und Pillenrand braucht er
       bei --schrift-sm 13,4rem. Der Rest war Luft. */
    --gliederung-breite:15rem;

    /* Zwoelf Spalten sind kein Ritual: Sie teilen sich durch 2, 3, 4 und 6.
       Ein Raster mit zehn Spalten kann kein Drittel. */
    --spalten:12;
    --raster-luecke:var(--raum-5);
}

/* Der Unterstuetzungsmodus schaltet seine Hoehe zu. --hoehe-3 und kein
   eigener Wert: Das Banner ist eine Bedienzeile mit einem Verweis darin, und
   2,75rem ist die Hoehe, die es bei --raum-2 Innenabstand ohnehin hat.

   `:has()` und keine zweite Klasse am <body>: Das Banner steht in einem
   Teilstueck, das drei Layouts einbinden - eine Klasse am <body> muesste in
   allen dreien bedingt gesetzt werden, und eines wuerde sie vergessen.
   `:has()` benutzt das Blatt seit AP-F15 an acht Stellen. */
:root:has(.impersonate-banner) { --banner-hoehe:var(--hoehe-3); }

/* Das Portal hat keinen Ebenenstreifen - dort ist die Leiste nur der Kopf. */
:root:has(> body.welt-portal) {
    --kopfleiste-hoehe:calc(var(--banner-hoehe) + var(--kopf-hoehe));
}

/* Anmeldung und Mandantenauswahl haben ueberhaupt keine Kopfleiste. Ohne
   diese Zeile schoebe `scroll-padding-top` dort 7,5rem Nichts vor jedes
   Sprungziel. */
:root:has(> body.welt-schlank) { --kopfleiste-hoehe:0rem; }


/* --------------------------------------------------------------------------
   ERSETZT app.css:163-167  (`html { scroll-padding-top:5.5rem }`)

   Die Begruendung bleibt: Die Kopfleiste steht fest, und ohne diese Angabe
   landet jedes Sprungziel (#id) darunter und ist nicht zu sehen. Neu ist,
   dass die Zahl nicht mehr danebensteht, sondern aus derselben Variablen
   kommt wie die Leiste selbst. 5,5rem war die Hoehe VOR dem Ebenenstreifen;
   seit AP-H23 war sie um 2rem zu klein, und der Sprunglink unten braucht sie
   auf den Millimeter.

   --raum-4 obendrauf, damit das Sprungziel nicht an der Kante klebt.
   -------------------------------------------------------------------------- */
html { scroll-padding-top:calc(var(--kopfleiste-hoehe) + var(--raum-4)); }


/* --------------------------------------------------------------------------
   DER SPRUNGLINK  (WCAG 2.4.1 "Bypass Blocks") - NEU, fehlte vollstaendig

   Wer die Anwendung mit der Tastatur bedient, lief auf JEDER der 228 Masken
   zuerst durch Wortmarke, Kontozeile, drei Ebenenreiter und bis zu siebzehn
   Gliederungspunkte, bevor der erste Bedienpunkt der Maske kam - zwei Dutzend
   Tabulatorschritte, auf jeder Seite, immer dieselben.

   Er ist SICHTBAR, sobald er den Fokus hat, und nur dann. Die Umschrift von
   `.nurvorlesen` waere hier falsch: Ein Sprunglink, den man nicht sieht,
   wenn man auf ihm steht, ist kein Sprunglink. `position:fixed` und nicht
   `absolute`, damit er auch dann im Bild steht, wenn die Seite schon
   gerollt war.
   -------------------------------------------------------------------------- */
.sprunglink {
    position:fixed; z-index:var(--ebene-ueberlagerung);
    top:var(--raum-2); left:var(--raum-2);
    display:inline-flex; align-items:center;
    min-height:var(--hoehe-2); padding:var(--raum-2) var(--raum-4);
    color:var(--akzent); background:var(--flaeche);
    border:1px solid var(--akzent-hell); border-radius:var(--radius-sm);
    box-shadow:var(--schatten-lg);
    font-size:var(--schrift-sm); font-weight:var(--fett-stark);
    text-decoration:none;
    /* Aus dem Bild geschoben statt `display:none`: Ein Element ohne
       Darstellung ist auch nicht fokussierbar - dann gaebe es den Link
       genau fuer die Nutzer nicht, fuer die er da ist. */
    transform:translateY(-300%);
    transition:transform var(--dauer-schnell) var(--stufe);
}
.sprunglink:focus { transform:translateY(0); }
.sprunglink:hover { text-decoration:none; }

/* Das Sprungziel. `tabindex="-1"` macht `main` fokussierbar, ohne es in den
   Tabulatorlauf zu legen; ohne das springt zwar die Ansicht, der Fokus aber
   bleibt oben stehen und der naechste Tabulatorschritt faengt wieder von
   vorn an. Die Kante liegt INNEN (negativer Versatz), weil ein Ring um die
   volle Arbeitsspalte sonst aus dem Fenster ragt. */
main[tabindex]:focus-visible {
    outline:2px solid var(--akzent-hell); outline-offset:-2px;
}


/* ==========================================================================
   DIE KOPFLEISTE - ERSETZT app.css:221-232 UND app.css:329-332

   Banner, Kopf und Ebenenstreifen stehen zusammen fest. Zwei getrennt
   klebende Elemente ueberdecken sich beim Rollen gegenseitig; die Klammer
   loest das ohne Hoehenrechnerei.

   Neu ist nur, dass die drei Teile jetzt die Hoehe HABEN, die der
   Wertevorrat ihnen zuschreibt. Das ist die Bedingung dafuer, dass die
   haftende Gliederung, der feststehende Tabellenkopf und
   `scroll-padding-top` aus derselben Variablen rechnen duerfen.
   ========================================================================== */
.kopfleiste {
    position:sticky; top:0; z-index:var(--ebene-kopfleiste);
    background:var(--flaeche);
    box-shadow:var(--schatten-sm);
}

.kopf {
    display:flex; align-items:center; gap:var(--raum-4); flex-wrap:wrap;
    /* min-height statt eines groesseren Innenabstands: Bei umbrechendem
       Inhalt darf die Zeile wachsen, bei normalem Inhalt ist sie auf den
       Millimeter --kopf-hoehe. `box-sizing:border-box` (app.css:161) rechnet
       die 1px-Kante unten mit hinein. */
    min-height:var(--kopf-hoehe);
    padding:var(--raum-2) var(--raum-5);
    background:var(--flaeche);
    border-bottom:1px solid var(--rand);
}

/* >> DER UNTERSTUETZUNGSMODUS.

   Teil des Sicherheitsmechanismus, nicht Zierde: Er darf nicht wegrollen und
   muss auffallen. Die Schriftfarbe ist --grund und nicht #fff - im
   Dunkelmodus kippt --warn nach hell, und weisse Schrift stuende dort mit
   2,4:1 auf ihr. So sind es 5,0:1 im hellen und 7,5:1 im dunklen Modus.

   Die Hoehe ist neu festgenagelt, weil `--banner-hoehe` oben mit ihr
   rechnet: Wuerde das Banner 3rem hoch, saesse die haftende Gliederung
   darunter um denselben Betrag zu hoch. */
.impersonate-banner {
    display:flex; align-items:center; flex-wrap:wrap; gap:var(--raum-1);
    min-height:var(--hoehe-3);
    padding:var(--raum-2) var(--raum-5);
    font-size:var(--schrift-sm); font-weight:var(--fett-stark);
    color:var(--grund); background:var(--warn);
}

/* ERSETZT app.css:3430-3436. Nur Hoehe und Tokens; Farbe, Reiter und die
   WCAG-1.4.1-Begruendung des offenen Reiters bleiben unberuehrt.

   `border-top:1px solid var(--linie)` stand hier, und `--linie` ist im
   ganzen Blatt nirgends definiert. Eine Kantenangabe mit einem unbekannten
   Wert ist zur Rechenzeit ungueltig und faellt auf `border:none` zurueck -
   die Kante war nicht blass, sie war gar nicht da. Sie heisst `--rand`. */
.ebenenstreifen {
    display:flex; align-items:stretch;
    gap:var(--raum-1);
    min-height:var(--streifen-hoehe);
    padding:0 var(--raum-5);
    border-top:1px solid var(--rand);
    background:var(--flaeche-2);
}


/* Das Portalband war mit .9rem gepolstert und damit 3,6rem hoch - 1,6px mehr,
   als --kopf-hoehe sagt. Auf --raum-3 gebracht greift dort dieselbe
   min-height, und die Zahl im Wertevorrat stimmt in BEIDEN Welten. Ohne das
   klebte der feststehende Tabellenkopf im Portal um diesen Betrag zu hoch. */
.welt-portal .kopf { padding:var(--raum-3) var(--raum-5); }

/* ==========================================================================
   DER SEITENRUMPF - ERSETZT app.css:348-352, app.css:362 UND app.css:371-376

   Zwei Spalten: die Gliederung links, die Arbeit rechts. Unter 64rem wird
   daraus eine Spalte mit zusammengeklappter Gliederung.
   ========================================================================== */

.rumpf {
    flex:1;
    display:grid;
    grid-template-columns:var(--gliederung-breite) minmax(0,1fr);
}

/* >> DIE TRENNLINIE GEHOERT NICHT AN DIE GLIEDERUNG (neu).

   Bis hierher trug `.hauptnavigation` `border-right:1px solid var(--rand)`,
   und weil ein Rasterelement vorgabemaessig `align-self:stretch` hat, lief
   die Linie ueber die volle Seitenhoehe. Genau das geht verloren, sobald die
   Gliederung haftet: Haften verlangt `align-self:start` und eine
   `max-height` - und dann reisst die Linie nach einem Bildschirm ab, und
   unter der Gliederung steht statt der weissen Spalte der graue Grund.

   Drei Loesungen standen zur Wahl:

     a) Farbverlauf als Hintergrund auf `.rumpf`. VERWORFEN: Er schriebe die
        Spaltenbreite ein ZWEITES Mal fest - wer `--gliederung-breite`
        aendert, verschoebe die Linie nicht mit, und die zwei Zahlen liefen
        beim naechsten Eingriff auseinander. Ausserdem malte er auch hinter
        der Arbeitsspalte.
     b) Kante an `.rumpf` selbst. GEHT NICHT: `.rumpf` ist das ganze
        Zweispaltenraster, seine Kante liegt aussen.
     c) Ein Pseudoelement in Rasterzelle 1/1. GEWAEHLT.

   Das Pseudoelement ist ein Rasterelement wie jedes andere: Es liegt in der
   Spur der Gliederung, es streckt sich vorgabemaessig ueber die volle Hoehe,
   und es folgt `--gliederung-breite` von selbst. Es traegt beides - die
   Flaeche der Spalte UND die Linie an ihrem Rand -, und die Gliederung
   darueber darf dabei so hoch oder so kurz sein, wie sie will.

   Die drei Rasterplaetze stehen ausdruecklich da. Ohne sie legte die
   automatische Platzierung das Pseudoelement auf 1/1, die Gliederung auf 1/2
   und `main` in eine zweite Zeile. */
.welt-backoffice .rumpf::before {
    content:""; grid-area:1 / 1;
    background:var(--flaeche);
    border-right:1px solid var(--rand);
}
.welt-backoffice .rumpf > .hauptnavigation { grid-area:1 / 1; }
.welt-backoffice .rumpf > main             { grid-area:1 / 2; }

/* Das Portal bekommt nichts davon ab: `.welt-portal .rumpf { display:block }`
   (app.css:2827, AP-H15) bleibt unveraendert stehen, und das Pseudoelement
   oben ist ausdruecklich auf `.welt-backoffice` begrenzt. */

/* >> width:100% IST HIER KEINE ZIERDE (AP-H17).

   `main` ist ein Rasterelement in `.rumpf`. Auf einem Rasterelement schaltet
   `margin:0 auto` die Selbstausrichtung von "stretch" auf "auto-Raender" um -
   und dann bemisst es sich nach seinem INHALT. Die Folge: Die Ueberschrift
   stand auf der Uebersicht bei x=307 und auf den Textbausteinen bei x=594.
   Jede Maske hatte ihren eigenen linken Rand, und beim Wechseln sprang die
   Seite. `width:100%` bindet es wieder an die Spur; der Deckel bleibt. */
main {
    max-width:var(--breite-masse); width:100%; min-width:0;
    margin:0 auto; padding:var(--raum-5);
}


/* --------------------------------------------------------------------------
   DIE HAFTENDE GLIEDERUNG - ERSETZT app.css:371-376

   Fuenf Gruppen statt siebzehn gleichrangiger Punkte. Die Gruppenueberschrift
   ist kein Verweis: Sie benennt einen Bereich, sie fuehrt nirgendwohin. Wer
   sie klickbar macht, erzeugt eine Seite, die es nicht gibt.

   NEU: Sie haftet. Die Fristenliste hat 21 Spalten und beliebig viele
   Zeilen; wer dort nach unten rollt, hat die Gliederung nicht mehr und muss
   fuer jeden Wechsel erst wieder ganz nach oben. Der feststehende
   Tabellenkopf loest dasselbe Problem seit AP-H15 waagrecht - senkrecht
   blieb es offen.

   `align-self:start` ist die Bedingung dafuer: Ein gestrecktes
   Rasterelement ist so hoch wie seine Zeile und kann deshalb nirgendwohin
   haften. Flaeche und Trennlinie hat es an das Pseudoelement oben abgegeben;
   die Begruendung steht dort.
   -------------------------------------------------------------------------- */
.hauptnavigation {
    grid-area:1 / 1;
    align-self:start;
    position:sticky; top:var(--kopfleiste-hoehe);
    z-index:var(--ebene-gliederung);

    /* Siebzehn Punkte in fuenf Gruppen sind hoeher als ein kleiner Laptop.
       Ohne den Deckel schoebe die Gliederung ihr unteres Ende aus dem Bild,
       und die letzten Punkte waeren beim Rollen NIE zu erreichen. */
    max-height:calc(100dvh - var(--kopfleiste-hoehe));
    overflow-y:auto;
    /* Ist die Gliederung zu Ende gerollt, soll das Rad die SEITE
       weiterrollen und nicht in der Spalte haengenbleiben. */
    overscroll-behavior:contain;

    min-width:0;
    padding:var(--raum-4) 0 var(--raum-6);
    background:transparent;
    border-right:0;
}


/* ==========================================================================
   DIE BREITE DER MASKE  (loest die Regel aus AP-H15 ab)

   Nachgemessen, bevor etwas geaendert wurde: Das Blatt gab JEDER
   Backoffice-Maske ab 90rem Fensterbreite 100rem Arbeitsspalte - der
   Fristenliste mit 21 Spalten ebenso wie dem Anlegeformular mit vier
   Feldern. Beides ist falsch, und zwar in verschiedene Richtungen:

     - Ein Formular in 100rem Breite hat ein Feld links und 80rem Nichts
       rechts. Wer es ausfuellt, wandert mit den Augen ueber eine leere
       Flaeche, weil Beschriftung und Feld auseinandergezogen sind.
     - Eine Liste mit 21 Spalten hatte UNTERHALB von 90rem Fenster 70rem -
       den Satzspiegel einer Textspalte. Sie rollte waagrecht, obwohl der
       Bildschirm daneben leer war.

   Also andersherum als bisher: Die Liste bekommt die Breite, die da ist, das
   Formular behaelt das Textmass. Und zwar OHNE Medienabfrage - `max-width`
   greift von sich aus erst, wenn das Fenster breiter ist als der Deckel.

   Die Klasse steht am `<main>` und kommt aus einem Twig-Block im Layout
   (siehe "braucht_vorlagenaenderung"). Am `<main>` und nicht am Inhalt, weil
   nur `main` die Spur ausfuellt: Eine Klasse weiter innen kann den Deckel
   darueber nicht anheben.
   ========================================================================== */

/* Listen-, Tabellen- und Matrixmasken. `.welt-backoffice` davor, damit die
   Regel das Portal nicht erreicht: Dort ist die schmale Spalte Absicht
   (`.welt-portal main { max-width:54rem }`) - der Mandant liest dort. */
.welt-backoffice main.maske-weit { max-width:var(--breite-weit); }

/* Formular- und Lesemasken. Steht der Vollstaendigkeit halber da, obwohl sie
   nur wiederholt, was `main` ohnehin traegt: Wer die Vorlage liest, soll die
   Breite dort ablesen koennen und nicht raten muessen. */
.welt-backoffice main.maske-masse { max-width:var(--breite-masse); }

/* Ein Absatz OHNE Klasse steht in 34 Masken. Bis hierher war er so breit wie
   die Spalte; das fiel bei 70rem nicht auf und faellt bei 100rem sofort auf.

   `:not([class])` ist keine Feinheit, sondern notwendig: Ein Elementselektor
   bringt Gewicht mit, und `.welt-backoffice main > section > p` (0,1,2)
   schluege `.unterzeile` (0,1,0) - die Beitexte waeren gewachsen, obwohl
   ihre eigene Regel etwas anderes sagt. Mit dem Ausschluss trifft die Regel
   genau das, wofuer sie gedacht ist.

   Der Deckel ist jetzt --breite-text (70ch) statt der bisherigen 78ch: Der
   Wertevorrat kennt EIN Textmass, und zwei Textmasse im selben Blatt sind
   eines zu viel. */
.welt-backoffice main > p:not([class]),
.welt-backoffice main > section > p:not([class]),
.welt-backoffice main > .karte > p:not([class]) { max-width:var(--breite-text); }


/* ==========================================================================
   DAS RASTER

   Zwoelf Spalten in Hausschreibweise. Es ersetzt keine bestehende Regel - es
   ist das, was neue Masken benutzen sollen, statt sich ein eigenes
   `grid-template-columns` zu schreiben. Genau daraus sind die 24
   handgeschriebenen Raster im Blatt entstanden.
   ========================================================================== */

.raster {
    display:grid;
    grid-template-columns:repeat(var(--spalten), minmax(0,1fr));
    gap:var(--raster-luecke);
    /* Zwei Kaesten nebeneinander sollen oben buendig stehen und nicht beide
       so hoch werden wie der laengere. */
    align-items:start;
}

.spalte-1  { grid-column:span 1;  }
.spalte-2  { grid-column:span 2;  }
.spalte-3  { grid-column:span 3;  }
.spalte-4  { grid-column:span 4;  }
.spalte-5  { grid-column:span 5;  }
.spalte-6  { grid-column:span 6;  }
.spalte-7  { grid-column:span 7;  }
.spalte-8  { grid-column:span 8;  }
.spalte-9  { grid-column:span 9;  }
.spalte-10 { grid-column:span 10; }
.spalte-11 { grid-column:span 11; }
.spalte-12 { grid-column:span 12; }

/* Jedes Kind bekommt `min-width:0` mit. Ohne das ist das Mindestmass eines
   Rasterelements sein INHALT, und ein langer Hash oder eine breite Tabelle
   zieht die Spur auf, statt in ihrer `.tabellenrolle` zu rollen. Dieselbe
   Falle hat das Blatt bisher an sechs Stellen einzeln behoben
   (`.werkbank__arbeit`, `.beleg-und-arbeit > *`, `.spalte`, `main`, ...). */
.raster > * { min-width:0; }


/* --------------------------------------------------------------------------
   DIE SELBSTMESSENDE SPUR - EINE FORMEL FUER SIEBEN BAUTEILE

   >> auto-fit UND NICHT auto-fill (AP-H17).

   `auto-fill` legt so viele Spuren an, wie hineinpassen - auch leere. Auf
   einem 1920er Bildschirm standen drei Kacheln zu je 250px links in einer
   1600px breiten Spalte, und rechts daneben lagen drei leere Spuren.
   `auto-fit` faltet die leeren zusammen, und die vorhandenen Kacheln nehmen
   den Platz.

   Der Kommentar stand seit AP-H17 im Blatt, die Regel darunter (app.css:1237)
   sagte `auto-fill`. Er beschrieb also einen Zustand, den es nie gab - und
   dreimal daneben, bei `.befundliste`, `.ersatzcodes` und `.vorlagenfelder`,
   stand derselbe Fehler ohne Kommentar.

   `min(100%, ...)` ist die zweite Haelfte: Ohne sie ragt eine Kachel mit
   18rem Mindestbreite aus einer 16rem schmalen Spalte heraus, statt
   mitzuschrumpfen.

   Dies ist die Stelle, an der diese Familie die Bruchpunkte SPART: Ein
   `auto-fit`-Raster misst seine eigene Spalte. Es braucht keine
   Medienabfrage, es kennt die Gliederung daneben, und es bleibt richtig,
   wenn `--gliederung-breite` sich aendert. Jedes Bauteil unten sagt nur noch
   ZWEI Zahlen: ab welcher Spurbreite es teilt und - wenn noetig - wie breit
   eine Spur hoechstens werden darf.
   -------------------------------------------------------------------------- */
.raster--auto,
.kachelliste,
.zweispaltig,
.beleg-und-arbeit,
.werkbank,
.aktenblatt,
.befundliste,
.vorlagenfelder {
    grid-template-columns:repeat(
        auto-fit,
        minmax(min(100%, var(--mindestbreite, 18rem)), var(--hoechstbreite, 1fr))
    );
}


/* --------------------------------------------------------------------------
   DIE ZWEI GRUNDFORMEN

   `.stapel` und `.reihe` ersetzen den senkrechten Abstand, den das Blatt
   bisher als `margin-bottom` an jedes einzelne Bauteil geschrieben hat. Der
   Unterschied ist nicht Geschmack: Ein Abstand, der am KIND haengt, ist beim
   letzten Kind falsch - deshalb stehen im Blatt zwoelf Regeln der Form
   `> :last-child { margin-bottom:0 }` - und er faellt weg, sobald das Kind
   in einer Bedingung steht und nicht gerendert wird. Eine Luecke am
   BEHAELTER hat beide Fehler nicht.
   -------------------------------------------------------------------------- */

/* Senkrechte Reihung. `--luecke` ist der Regler; die Vorgabe ist der
   uebliche Abstand zwischen zwei Bloecken einer Maske. */
.stapel {
    display:grid;
    gap:var(--luecke, var(--raum-4));
    align-content:start;
}
/* `margin-block` und nicht `margin`: Der seitliche Einzug bleibt erhalten -
   `article.beratungseintrag.nachtrag` lebt davon. */
.stapel > * { margin-block:0; min-width:0; }

.stapel--eng  { --luecke:var(--raum-2); }
.stapel--weit { --luecke:var(--raum-6); }

/* Waagrechte Reihung mit Umbruch. Das ist die Form der Werkzeugleiste, der
   Filterzeile und jeder Knopfgruppe: nebeneinander, mittig ausgerichtet, und
   UMBRECHEND statt die Spalte sprengend. */
.reihe {
    display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--luecke, var(--raum-3));
}
.reihe > * { margin-block:0; }

.reihe--eng  { --luecke:var(--raum-2); }
.reihe--weit { --luecke:var(--raum-5); }

/* Ein Textfeld und sein Knopf gehoeren an die Oberkante, wenn eines von
   beiden mehrzeilig ist - mittig ausgerichtet schwimmt der Knopf. */
.reihe--oben { align-items:flex-start; }

/* "Alles links, das Letzte rechts" ohne einen zweiten Behaelter. */
.reihe--auseinander { justify-content:space-between; }
.reihe__schub { margin-inline-start:auto; }


/* ==========================================================================
   DIE HANDGESCHRIEBENEN RASTER, AUF DIE FORMEL ZURUECKGEFUEHRT

   Alle Bloecke hier ersetzen ein eigenes `grid-template-columns` (und meist
   eine Medienabfrage dazu) durch die Formel oben. Sie behalten ihre
   Klassennamen - 228 Vorlagen zeigen darauf - und ihre Begruendung; was
   wegfaellt, ist die Zahl im Medienausdruck. Jede Zahl unten ist aus der
   bisherigen Schwelle nachgerechnet, und die Rechnung steht daneben.
   ========================================================================== */

/* --- Die Kacheln des Cockpits (ERSETZT app.css:1231-1238) --------------
   Zaehlwerte, keine Bewertung. Nach oben gedeckelt: Eine Kachel mit einer
   Ziffer und zwei Zeilen Text sieht in 780px Breite leer aus. 22rem ist die
   Breite, in der die laengste Bezeichnung zweizeilig steht. Beide Zahlen
   sind unveraendert; nur `auto-fill` ist jetzt `auto-fit`, wie es der
   Kommentar von AP-H17 immer schon behauptet hat. */
.kachelliste {
    list-style:none; margin:0; padding:0;
    display:grid; gap:var(--raum-4);
    --mindestbreite:17rem;
    --hoechstbreite:22rem;
}

/* --- Pruefansicht einer Meldung (ERSETZT app.css:2033-2037, AP-F15) -----
   Links der Wortlaut des Mandanten, rechts die Arbeit. Der Unterschied ist
   nicht Zierde: Links steht Nachweis und kein Eingabefeld, und die ruhige
   Flaeche sagt das, bevor jemand hineinzuklicken versucht.

   26rem ist genau die Spaltenbreite, die die bisherige Schwelle von 56rem
   Fensterbreite ergab (56rem Fenster minus 2rem Innenabstand, geteilt durch
   zwei). Der Bruchpunkt entfaellt trotzdem, und er entfaellt zu Recht: Er
   war FALSCH. Bei 56rem Fenster ist die Gliederung zusammengeklappt und die
   Spalte 54rem breit; bei 64rem klappt sie auf und nimmt 15rem weg - die
   beiden Spalten schrumpften also von 26rem auf 22rem, waehrend das Fenster
   BREITER wurde. `auto-fit` misst die Spalte und kennt diesen Sprung. */
.zweispaltig {
    display:grid; gap:var(--raum-5); align-items:start;
    --mindestbreite:26rem;
}
.spalte { min-width:0; }

/* --- Zwei Faktenbloecke nebeneinander (ERSETZT app.css:3180-3184) -------
   Hier stehen zwei TABELLEN nebeneinander, und eine Tabelle, die umbricht,
   ist schlechter lesbar als eine, die untereinander steht - deshalb teilt
   dieser Fall spaeter als `.zweispaltig`. 34rem entspricht der bisherigen
   Schwelle von 90rem Fenster (90 minus 15 Gliederung minus 3 Innenabstand =
   72rem Spalte, minus --raum-5 Luecke, geteilt durch zwei = 35,25rem).

   Doppelte Klasse im Selektor, damit die Reihenfolge im Blatt egal ist. */
.zweispaltig.zweispaltig--weit { --mindestbreite:34rem; }
.zweispaltig--weit .spalte > h2:first-child { margin-top:0; }

/* --- Beleg links, Arbeit rechts (ERSETZT app.css:3212-3217) ------------
   In der Drittlandmaske steht links, WORAUS entschieden wird - der
   festgehaltene Stand und die Zeitachse der Rechtsakte -, rechts das
   Formular, das entscheidet. Untereinander liegt der Beleg ausserhalb des
   Bildschirms, sobald jemand das Formular ausfuellt: Er ist dann genau in
   dem Augenblick weg, in dem er gebraucht wird.

   35rem statt der Schwelle 90rem, aus derselben Rechnung wie oben. */
.beleg-und-arbeit {
    display:grid; gap:var(--raum-5); align-items:start;
    --mindestbreite:35rem;
}
.beleg-und-arbeit > * { min-width:0; }
/* Derselbe Deckel wie fuer den Fliesstext der Arbeitsspalte: Eine
   Erlaeuterung ueber die volle Spaltenbreite ist nicht lesbar. */
.beleg-und-arbeit p { max-width:var(--breite-text); }

/* --- Werkbank und Nachschlagewerk (ERSETZT app.css:3253-3266) ----------
   Zwei Dinge gehoeren NEBENEINANDER und nicht untereinander: die Zuordnung
   ("welche Klasse bekommt diese Datenkategorie?") und der Bestand der
   eigenen Klassen. Das Auswahlfeld der Zuordnung zeigt nur Schluessel und
   Bezeichnung - Frist, Belegstelle und Verwendungszahl stehen im Bestand.
   Untereinander scrollt der Berater bei jeder einzelnen Zeile.

   >> HIER STAND DIE RECHNUNG, DIE DIESE FAMILIE UEBERFLUESSIG MACHT.

   Der bisherige Kommentar rechnete vor, warum `.werkbank` erst bei 105rem
   FENSTER teilen darf: "Eine Medienabfrage misst das FENSTER, `.werkbank`
   steht aber in `main` - und `main` steht in `.rumpf`, das ab 64rem 15.5rem
   fuer die Gliederung abzieht." Die Rechnung war richtig, ihr Ergebnis war
   ein achter Bruchpunkt, den sonst niemand benutzte.

   Die BEDINGUNG aus dem alten Kommentar war: Die schmalere der beiden
   Spalten braucht 566px fuer Frist, Verwendungszahl und den Knopf
   "Durchsicht vermerken". Sie steht jetzt als Zahl da, wo sie hingehoert -
   als Mindestbreite der Spur. Bei --raum-4 Luecke teilt die Werkbank ab
   71rem Spurbreite, und beide Spalten haben dann 35,5rem = 568px.

   Der Preis: 3fr/2fr wird 1fr/1fr. Bei 568px trug die schmalere Spalte
   ohnehin alles, was in ihr steht; das Verhaeltnis war fuer ein 105rem
   breites Fenster gewaehlt und nicht fuer die Sache. */
.werkbank {
    display:grid; gap:var(--raum-4); align-items:start;
    --mindestbreite:35rem;
}
/* Ohne min-width:0 sprengt eine breite Tabelle ihre Rasterspalte, statt im
   Behaelter `.tabellenrolle` zu rollen. Beide Kinder stehen ausdruecklich da
   und nicht als `> *`: Eine Klasse aus einer Vorlage soll im Blatt
   auffindbar sein (AP-H15). */
.werkbank__arbeit, .werkbank__bestand { min-width:0; }

/* --- Die Mandantenakte (ERSETZT app.css:3478-3486) ---------------------
   27rem entspricht der bisherigen Schwelle von 75rem Fenster (75 minus 15
   minus 3 = 57rem Spalte, minus --raum-5 Luecke, geteilt durch zwei =
   27,75rem). Auch hier faellt ein Verhaeltnis weg (1.2fr/1fr): Es sind zwei
   unabhaengige Bloecke, keine Haupt- und keine Nebenspalte. */
.aktenblatt {
    display:grid; gap:var(--raum-5); align-items:start;
    --mindestbreite:27rem;
}
.aktenblatt__spalte { min-width:0; }

/* --- Zwei weitere auto-fill, dieselbe Ursache -------------------------
   (ERSETZT die Zeilen app.css:3012 und app.css:3527)

   Die Befundliste des Cockpits und die Felderliste der Vorlagenebene tragen
   den Fehler von `.kachelliste` ohne dessen Kommentar. Bei EINEM Befund
   stand er in 19rem, und daneben lagen zwei leere Spuren.

   `.ersatzcodes` (app.css:3069) bleibt bewusst `auto-fill` und steht
   deshalb nicht in der Formel oben: Die zehn Ersatzcodes werden
   ABGESCHRIEBEN, nicht gelesen. Feste Spuren halten sie in derselben
   Rasterlage, auch wenn einer verbraucht ist; `auto-fit` liesse die
   verbleibenden auf halbe Seitenbreite wachsen. Das ist der einzige
   begruendete auto-fill im Blatt. */
.befundliste    { --mindestbreite:19rem; }
.vorlagenfelder { --mindestbreite:20rem; }


/* ==========================================================================
   DER SCHALTER FUER SCHMALE BILDSCHIRME

   Ohne JavaScript, ohne <details>. Die Begruendung fuer das
   Kontrollkaestchen steht in layout/backoffice.html.twig: Die verbergende
   Regel liegt ausschliesslich im Medienausdruck weiter unten. Faellt CSS aus
   oder greift der Medienausdruck nicht, ist die Navigation sichtbar - nicht
   unerreichbar.

   >> DAS MENUE WAR AUF SCHMALEN SCHIRMEN NUR MIT DER MAUS ZU OEFFNEN.

   AP-H17 nahm das Kaestchen aus dem Tabulatorlauf, weil es oberhalb von
   64rem als ERSTES Element jeder Maske den Fokus bekam - auf einem
   Bedienelement, das dort `display:none` ist (WCAG 2.4.3). Der Kommentar
   daneben versprach: "Sichtbar gemacht wird es erst im schmalen
   Medienausdruck unten." Der Medienausdruck unten hat es nie wieder
   hergestellt.

   Die Folge: `display:none` nimmt ein Element aus dem Tabulatorlauf, und die
   zugehoerige `<label>` ist kein Bedienelement und bekommt nie Fokus. Auf
   jedem Schirm unter 64rem - Telefon, Tablett, geteiltes Fenster - liess
   sich die Navigation mit der Tastatur weder oeffnen noch schliessen. Sie
   war zu, und dahinter lag jeder Arbeitsbereich der Anwendung (WCAG 2.1.1).

   Behoben im Bruchpunkt "breit" weiter unten: Das Kaestchen kommt zurueck,
   aber ausser Sicht - mit derselben Umschrift, die `.nurvorlesen`
   (app.css:2746) benutzt. Sein Fokusring wird auf die Beschriftung
   uebertragen; die Regel dafuer stand schon immer da und lief bisher ins
   Leere.
   ========================================================================== */
.navigationsschalter { display:none; }

.navigationsknopf {
    display:none; align-items:center; gap:var(--raum-2);
    margin:0; padding:var(--raum-2) var(--raum-3);
    min-height:var(--hoehe-2);
    font-size:var(--schrift-sm); font-weight:var(--fett-stark);
    color:var(--tinte-2);
    background:var(--flaeche-2);
    /* --rand-stark und nicht --rand: Die Kante eines Bedienelements braucht
       3:1 (WCAG 1.4.11); --rand traegt 1,3:1 und ist eine Trennlinie, keine
       Umrandung. */
    border:1px solid var(--rand-stark); border-radius:var(--radius-sm);
    cursor:pointer;
}
.navigationsknopf::after {
    content:""; width:.4rem; height:.4rem;
    border-right:2px solid currentColor; border-bottom:2px solid currentColor;
    transform:translateY(-.12em) rotate(45deg);
    transition:transform var(--dauer-normal) var(--stufe);
}
.navigationsschalter:checked ~ .kopfleiste .navigationsknopf::after {
    transform:translateY(.06em) rotate(-135deg);
}
.navigationsschalter:focus-visible ~ .kopfleiste .navigationsknopf {
    outline:2px solid var(--akzent-hell); outline-offset:2px;
}


/* ==========================================================================
   DIE VIER BRUCHPUNKTE

   Vorher acht: 30, 34, 40, 56, 63.99, 75, 90 und 105rem. Acht Schwellen
   heissen acht Zustaende, die jemand nachsehen muss, und keine zwei davon
   lagen auf demselben Wert.

   Es sind jetzt vier, und sie haben Namen:

     schmal  34rem   Telefon hochkant
     mittel  48rem   Telefon quer, kleines Tablett
     breit   64rem   ab hier steht die Gliederung neben der Arbeit
     weit    90rem   ab hier ist Platz fuer zwei volle Spalten

   Was wohin gefallen ist:

     30rem  -> schmal (33.99)  Mandantenchip; um 4rem nach oben.
     34rem  -> schmal (34)     `.angaben`. Unveraendert, lag schon richtig.
     40rem  -> mittel (47.99)  `.beratungseintrag dl`, `li.stufe`; um 8rem
                               nach oben. Zwischen 34 und 48rem hat die
                               zweispaltige Beschreibungsliste 11rem
                               Beschriftung und darunter knapp 20rem Wert -
                               eine Spalte liest sich dort besser.
     56rem  -> ENTFAELLT       `.zweispaltig`, jetzt selbstmessend. Der
                               Bruchpunkt war falsch, nicht nur ueberzaehlig;
                               die Begruendung steht oben bei der Regel.
     63.99  -> breit (63.99)   Die Schale. Unveraendert.
     75rem  -> ENTFAELLT       `.aktenblatt`, jetzt selbstmessend.
     90rem  -> weit (90)       `.durchsicht-paar`. Bleibt Medienabfrage: Es
                               ist das einzige Paar, dessen VERHAELTNIS
                               traegt - links der Wortlaut, rechts die
                               Entscheidung darueber -, und ein Verhaeltnis
                               kann `auto-fit` nicht.
     105rem -> ENTFAELLT       `.werkbank`, jetzt selbstmessend.

   Die drei entfallenen sind nicht zusammengelegt, sondern weggerechnet: Ihre
   Regeln messen jetzt ihre eigene Spalte. Das ist der Unterschied zwischen
   weniger Bruchpunkten und weniger Wahrheit.

   >> DIE REIHENFOLGE IM BLATT IST TEIL DER REGEL.
   Die `max-width`-Bloecke stehen ABSTEIGEND (64, dann 48, dann 34). Sie
   ueberlappen sich - unter 34rem gelten alle drei -, und bei gleichem
   Gewicht gewinnt der letzte. Andersherum sortiert setzte der 64er-Block die
   Angaben des 34er-Blocks wieder zurueck.
   ========================================================================== */

/* --- schmal: ab 34rem --------------------------------------------------- */
@media (min-width:34rem) {
    .angaben { grid-template-columns:minmax(0,max-content) minmax(0,1fr); }
}

/* --- weit: ab 90rem -----------------------------------------------------
   Annahme und Vermerk nebeneinander (AP-H15). Links steht, was zu pruefen
   ist, rechts die Entscheidung darueber. Der Absendeknopf steht damit neben
   dem Wortlaut, ueber den er entscheidet, und nicht sieben Tabellenzeilen
   darunter. Die einzige verbliebene Medienabfrage fuer einen INHALT, mit
   Grund: Das Verhaeltnis 3fr/2fr ist die Aussage. */
@media (min-width:90rem) {
    .durchsicht-paar {
        display:grid; grid-template-columns:minmax(0,3fr) minmax(0,2fr);
        gap:0 var(--raum-5); align-items:start;
    }
    .durchsicht-paar > * { min-width:0; }
}

/* --- breit: unter 64rem -------------------------------------------------
   Die Gliederung klappt zu und wandert unter den Kopf. Ab hier ist der
   Schalter das Einzige, was sie oeffnet - deshalb muss er hier auch mit der
   Tastatur erreichbar sein. */
@media (max-width:63.99rem) {
    .rumpf { grid-template-columns:minmax(0,1fr); }

    /* Die Spurzuweisungen des Zweispaltenrasters zuruecknehmen: Spalte 2
       gibt es hier nicht, und `grid-area:1 / 2` legte `main` in eine
       Ersatzspur neben der Seite. */
    .welt-backoffice .rumpf::before { display:none; }
    .welt-backoffice .rumpf > .hauptnavigation { grid-area:1 / 1; }
    .welt-backoffice .rumpf > main             { grid-area:2 / 1; }

    /* >> DAS KAESTCHEN KOMMT ZURUECK - AUSSER SICHT, ABER IM TABULATORLAUF.
       Dieselbe Umschrift wie `.nurvorlesen`: aus dem Bild geschnitten, nicht
       aus dem Baum genommen. `display:none` waere hier genau der Fehler, den
       diese Regel behebt. */
    .navigationsschalter {
        display:block;
        position:absolute; width:1px; height:1px;
        margin:-1px; padding:0; border:0;
        clip-path:inset(50%); overflow:hidden; white-space:nowrap;
    }

    .navigationsknopf { display:inline-flex; }

    /* Waagrecht gelegt traegt die Gliederung Flaeche und Kante wieder selbst
       - das Pseudoelement oben ist hier abgeschaltet. Und sie haftet NICHT:
       Quer ueber dem halben Telefonschirm klebend waere sie kein Hilfsmittel,
       sondern ein Vorhang. */
    .hauptnavigation {
        position:static; max-height:none; overflow:visible;
        padding:var(--raum-4) 0;
        background:var(--flaeche);
        border-right:0; border-bottom:1px solid var(--rand);
    }

    /* DIE EINZIGE REGEL, DIE DIE NAVIGATION VERBIRGT. Sie steht hier drin und
       nirgends sonst. */
    .navigationsschalter:not(:checked) ~ .rumpf .hauptnavigation { display:none; }

    /* Die Kontozeile bekommt eine eigene Zeile; der Kopf ist damit zweizeilig.
       --kopf-hoehe wird nachgezogen, weil sonst der feststehende
       Tabellenkopf und jedes Sprungziel unter der Leiste verschwaenden.
       6,25rem gemessen: --raum-2 oben und unten, Zeile 1 in Knopfhoehe
       (--hoehe-2), --raum-3 Luecke, Zeile 2 in Kontozeilenhoehe. Lieber ein
       Achtel rem zu viel als zu wenig - zu viel laesst einen Spalt frei, zu
       wenig verdeckt die erste Zeile. */
    :root { --kopf-hoehe:6.25rem; }

    .kopf { padding:var(--raum-2) var(--raum-4); gap:var(--raum-3); }
    .kontozeile { width:100%; margin-left:0; order:3; }
    .ebenenstreifen { padding:0 var(--raum-4); }
    main { padding:var(--raum-4) var(--raum-4) var(--raum-7); }

    .welt-portal .kopf { padding:var(--raum-2) var(--raum-4); }
    .welt-portal main  { padding:var(--raum-5) var(--raum-4) var(--raum-7); }

    /* Zwoelf Spalten auf einem Telefon sind zwoelf Spalten zu viel. Die
       zwoelf Namen stehen einzeln da und nicht als `[class*="spalte-"]`:
       Dieser Teilstring traefe auch `.spalte--original`,
       `.spalte--vorschlaege` und `.spalte--gewaehlt`, und die sind etwas
       ganz anderes. */
    .raster { grid-template-columns:minmax(0,1fr); }
    .spalte-1, .spalte-2, .spalte-3, .spalte-4,
    .spalte-5, .spalte-6, .spalte-7, .spalte-8,
    .spalte-9, .spalte-10, .spalte-11, .spalte-12 { grid-column:auto; }
}

/* --- mittel: unter 48rem ------------------------------------------------
   Die Beschreibungsliste des Beratungseintrags und die Stufenleiter sind die
   einzigen zweispaltigen Gebilde ihrer Familie. Sie werden hier einspaltig;
   die Tabellen bleiben, wie sie sind. */
@media (max-width:47.99rem) {
    .beratungseintrag dl { grid-template-columns:1fr; gap:var(--raum-1); }
    .beratungseintrag dd { margin:0 0 var(--raum-2); }
    article.beratungseintrag.nachtrag { margin-left:var(--raum-3); }
    li.stufe { grid-template-columns:1.6rem 1fr; gap:var(--raum-3); }
    .stufe__nummer { width:1.6rem; height:1.6rem; font-size:var(--schrift-xs); }
    li.stufe:not(:last-child)::before { left:.8rem; top:1.8rem; }
}

/* --- schmal: unter 34rem ------------------------------------------------
   Der Mandantenname bekommt eine eigene Zeile - lieber umbrechen als
   abschneiden. Ein halber Mandantenname ist schlimmer als keiner:
   "Ordination Dr. M..." passt auf mehr als einen Mandanten. */
@media (max-width:33.99rem) {
    .kopf .mandant { width:100%; max-width:none; order:2; }
    .mandant__name { white-space:normal; }
    main { padding:var(--raum-4) var(--raum-3) var(--raum-7); }
}


/* ==========================================================================
   PAPIER

   Gedruckt wird hier oft - eine Maske als Beleg, ein Verzeichnis zur
   Durchsicht. Gliederung und Kontozeile fallen weg, Wortmarke, Mandant und
   das Banner des Unterstuetzungsmodus bleiben: Ein Ausdruck, dem man nicht
   ansieht, zu welchem Mandanten er gehoert, ist im Aktenordner wertlos.
   ========================================================================== */
@media print {
    body { background:#fff; }
    .kopfleiste { position:static; box-shadow:none; }
    .hauptnavigation, .navigationsknopf, .kontozeile, .kopfnavigation,
    .sprunglink { display:none; }

    /* >> DER EBENENSTREIFEN DARF NICHT WEG (AP-H23).
       Seit AP-H23 steht der MANDANTENNAME am offenen Reiter und nicht mehr
       im Kopf. Den Streifen zu verbergen naehme dem Ausdruck genau die
       Angabe, die der Absatz hier oben fuer unverzichtbar erklaert. Er
       verliert nur sein Bedienaussehen: Was nicht offen ist, war auf Papier
       ohnehin nie eine Wahl. */
    .ebenenstreifen {
        min-height:0; padding:0; border-top:0; background:none;
    }
    .ebenenstreifen__reiter:not(.ebenenstreifen__reiter--offen) { display:none; }
    .ebenenstreifen__reiter--offen { border-bottom:0; padding-left:0; }

    /* Das Pseudoelement der Trennlinie muss mit weg. `.rumpf { display:block }`
       nimmt ihm die Rasterzelle, nicht seine Flaeche - stehen bliebe ein
       leerer Kasten von einer Zeile Hoehe vor dem Text. */
    .rumpf { display:block; }
    .welt-backoffice .rumpf::before { display:none; }

    main { max-width:none; padding:var(--raum-4) 0; }

    /* Die beiden festen #fff in diesem Block sind die einzigen Farbwerte der
       Schale ausserhalb des Wertevorrats. Sie stehen mit Absicht hier: Papier
       hat keinen Dunkelmodus, und ein Markenband in Volltonfarbe kostet Toner,
       ohne auf dem Ausdruck etwas zu sagen. */
    .welt-portal .kopf, .welt-portal .kopfleiste { color:inherit; background:#fff; }
}

/* Die Bewegungen der Schale sind drei Zustandsuebergaenge und kein Effekt. */
@media (prefers-reduced-motion: reduce) {
    .hauptnavigation a, .navigationsknopf::after, .sprunglink { transition:none; }
}


/* ==========================================================================
   FLAECHEN, SEITENKOPF UND GLIEDERUNGSBAUTEILE
   ========================================================================== */

/* ==========================================================================
   FAMILIE: FLÄCHEN, SEITENKOPF UND GLIEDERUNGSBAUTEILE

   Diese Familie beantwortet auf jeder der 228 Masken drei Fragen, die das
   Blatt bisher nirgends gemeinsam beantwortet hat:

     1. WO BIN ICH?          -> .pfad
     2. WAS IST DAS HIER,
        UND WAS KANN ICH TUN? -> .seitenkopf
     3. WIE IST DAS GEGLIEDERT? -> .abschnitt / .aufklapper / .reiter

   Bis hierher war die Antwort auf (1) gar keine, auf (2) ein klassenloses
   <h1> (126 Stück) mit einem Absatz darunter, und auf (3) siebzehnmal
   dieselbe wortgleich ausgeschriebene Karte.

   >> DIE REGEL, DIE DIESER FAMILIE ZUGRUNDE LIEGT.

   Eine Fläche hat in dieser Anwendung genau vier Zustände, und jeder hat
   eine eigene Bedeutung:

     --grund      die Seite selbst, auf der etwas liegt
     --flaeche    das Blatt: Karte, Kachel, Tabelle - ein GEGENSTAND
     --flaeche-2  die Einlassung IM Blatt: Kopf, Fuß, Zeigerspur
     --flaeche-3  die tiefergelegte Rinne: die Bahn eines Segmentschalters

   Wer eine fünfte Stufe braucht, braucht in Wahrheit eine Kante.
   ========================================================================== */


/* ==========================================================================
   1. ÜBERSCHRIFTEN - EINE STUFUNG STATT ZWANZIG

   Ersetzt app.css:968-971 und löst die sechzehn örtlichen
   h2-Überschreibungen sowie die elf h3-Überschreibungen auf.

   >> WARUM ES DIE ZWANZIG ÜBERSCHREIBUNGEN ÜBERHAUPT GAB.

   Nicht aus Geschmack. Die alte Grundregel lautete

       h2 { font-size:1.15rem; margin:2.25rem 0 .7rem; }

   und diese 2,25rem Vorabstand sind falsch, sobald ein h2 das ERSTE Kind
   einer Karte ist - der Abstand schiebt die Überschrift von der Kartenkante
   weg und reißt ein Loch in die Polsterung. Statt die Ursache zu beheben,
   hat jede Fachfamilie den Vorabstand örtlich weggeschrieben und dabei die
   Größe gleich mit angefasst: 1rem, 1.02rem, 1.05rem, 1.1rem, 1.15rem.
   Fünf Stufen für eine Ebene.

   Die Ursache wird jetzt einmal behoben (Regel ".. :first-child" weiter
   unten), und die Größen kommen aus der Schriftskala.

   >> ÜBERSCHRIFTEN STEHEN IN TINTE, NICHT IN DER MARKENFARBE (AP-H17).

   Übernommen aus der abgelösten Regel, weil die Begründung unverändert
   gilt: Jede Überschrift war blau - dieselbe Farbe wie jeder Verweis. Damit
   hatte die Seite zwei Sorten Blau, die nichts miteinander zu tun haben, und
   die Frage "ist das anklickbar?" war an der Farbe nicht zu beantworten. Die
   Akzentfarbe gehört der BEDIENUNG. Eine Überschrift ist keine Bedienung;
   sie trägt Gewicht und Größe.

   >> UND h3 IST NICHT MEHR KLEINER ALS DER TEXT, DEN ES ÜBERSCHREIBT.

   Es stand auf .98rem, der Fließtext auf 1rem. Eine Überschrift, die
   kleiner ist als das, was sie überschreibt, ordnet nicht mehr. h3 steht
   jetzt auf --schrift-md, also GENAU auf der Textgröße, und unterscheidet
   sich durch Gewicht und Sperrung. Das ist die unterste Stufe, die es noch
   sein kann - eine vierte Größe darunter gäbe es nicht.
   ========================================================================== */

h1 {
    margin:0 0 var(--raum-3);
    font-size:var(--schrift-xl);
    font-weight:var(--fett-voll);
    line-height:var(--zeile-eng);
    /* Negative Sperrung nur auf den großen Graden: Inter läuft ab etwa
       1.25rem optisch zu weit. Ein em-Wert und kein rem - er soll mit der
       Schriftgröße mitgehen und nicht mit dem Raster. */
    letter-spacing:-.02em;
    color:var(--tinte);
    text-wrap:balance;
}

h2 {
    /* Der Vorabstand ist die Trennung zweier Abschnitte und deshalb --raum-6;
       der Nachabstand gehört zur Überschrift und ist --raum-3. Beides
       stammt aus dem 4px-Raster und ersetzt die 2.25rem/.7rem, die auf
       keinem Raster lagen. */
    margin:var(--raum-6) 0 var(--raum-3);
    font-size:var(--schrift-lg);
    font-weight:var(--fett-stark);
    line-height:var(--zeile-eng);
    letter-spacing:-.01em;
    color:var(--tinte);
    text-wrap:balance;
}

h3 {
    margin:var(--raum-5) 0 var(--raum-2);
    font-size:var(--schrift-md);
    font-weight:var(--fett-stark);
    line-height:var(--zeile-eng);
    color:var(--tinte);
    text-wrap:balance;
}

/* >> DIE EINE REGEL, DIE DIE SECHZEHN AUFLÖST.

   Eine Überschrift ganz oben in einem Behälter braucht keinen Vorabstand -
   die Polsterung des Behälters ist der Abstand. `:where()` hält die
   Gewichtung bei (0,0,0), damit jede Fachregel diese hier weiterhin schlagen
   kann, ohne dass jemand Gewichtungen nachzählen muss. */
:where(h1, h2, h3):first-child { margin-top:0; }

/* Dasselbe für die letzte Überschrift vor dem Ende eines Behälters
   (kommt in .karte__kopf vor, wo nur die Überschrift steht). */
:where(h1, h2, h3):last-child { margin-bottom:0; }

/* Eine Überschrift IM Klickkopf eines Aufklappers bleibt eine Überschrift,
   verliert aber ihre Blockform - sonst schiebt sie den Zustandstext daneben
   in die nächste Zeile und reißt ihn aus der Klickfläche.
   Zusammengefasst aus `details.feldgruppe > summary > h2` (app.css:3224) und
   `.vorgangsschritt > summary h2` (app.css:3127); beide sagten dasselbe. */
summary > h1, summary > h2, summary > h3 {
    display:inline; margin:0;
    font-size:inherit; font-weight:inherit; letter-spacing:0;
}

/* Wo eine Überschrift eine RECHTSFOLGE trägt, gewinnt die Semantikfarbe -
   .konflikt h2 und .dse-lueckenliste > h2 setzen --warn und stehen weiter
   unten im Blatt, also später. Hier steht nur die Umkehrung für die Fälle,
   in denen eine Überschrift auf farbigem Grund liegt (übernommen aus
   app.css:977-978, unverändert gültig). */
.portalband h1, .portalband h2, .portalband h3,
div.fehler h1, div.fehler h2, div.fehler h3 { color:inherit; }


/* ==========================================================================
   2. DER PFAD

   Brotkrume. Sie beantwortet die Frage, die der Ebenenstreifen (AP-H23) nur
   grob beantwortet: Der Streifen sagt "Mandantenebene", der Pfad sagt
   "Mandanten / Musterwerk GmbH / Verzeichnis 2026".

   >> DAS TRENNZEICHEN IST CSS-INHALT UND KEIN TEXTZEICHEN IN DER VORLAGE.

   Zwei Gründe, beide praktisch. Erstens: Ein Schrägstrich, der in der
   Vorlage steht, wird vom Lesegerät mitgelesen - "Mandanten Schrägstrich
   Musterwerk". Zweitens: Er wird beim Kopieren mitgenommen und beim Umbruch
   an die falsche Stelle geschoben. Als ::before des zweiten und jedes
   weiteren Gliedes gehört er zum Glied und wandert mit ihm.

   Die Schreibweise `content:"/" / ""` setzt einen LEEREN Ersatztext für das
   Lesegerät - das Zeichen wird gesehen und nicht vorgelesen. Wo ein
   älterer Browser die Kurzform nicht versteht, fällt er auf "kein Inhalt"
   zurück; dann fehlt der Strich, und der Pfad bleibt lesbar. Das ist der
   richtige Ausfall.

   Das letzte Glied trägt KEINEN Verweis und `aria-current="page"`. Ein
   Verweis auf die Seite, auf der man steht, ist eine Sackgasse mit
   Ankündigung.
   ========================================================================== */

.pfad {
    /* Versalien auf der kleinsten Stufe. Der Pfad ist eine Ortsangabe und
       kein Text - er soll erkannt und nicht gelesen werden. */
    margin:0 0 var(--raum-2);
    font-size:var(--schrift-xs);
    line-height:var(--zeile-normal);
    letter-spacing:.06em;
    text-transform:uppercase;
    color:var(--tinte-3);
}

.pfad ol,
.pfad ul {
    display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--raum-1);
    margin:0; padding:0; list-style:none;
}

.pfad li { display:flex; align-items:center; gap:var(--raum-1); }

.pfad li + li::before {
    content:"/" / "";
    color:var(--rand-stark);
    font-weight:var(--fett-normal);
}

.pfad a {
    color:var(--tinte-3);
    text-decoration:none;
    border-radius:var(--radius-xs);
}

/* Der Unterstrich kommt erst beim Überfahren: Ein Pfad, in dem jedes Glied
   unterstrichen ist, sieht aus wie eine Fußnotenzeile. Er ist außerdem
   nicht "ein Verweis im Fließtext" im Sinne von WCAG 1.4.1 - er steht in
   einer eigenen Zeile, in der es keinen umgebenden Text gibt, von dem er
   sich unterscheiden müsste (dieselbe Begründung wie in app.css für
   Kachel, Spaltenkopf und Gliederung). */
.pfad a:hover { color:var(--akzent); text-decoration:underline; }

/* Das letzte Glied: kein Verweis, aber die kräftigere Tinte - es ist die
   Stelle, an der man steht. */
.pfad [aria-current="page"] {
    color:var(--tinte-2);
    font-weight:var(--fett-halb);
}

/* Ein sehr langer Mandantenname darf den Pfad nicht über die Seite ziehen. */
.pfad li > :is(a, span) {
    max-width:24ch;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

/* Auf schmalen Schirmen bleibt vom Pfad nur das letzte Glied stehen. Drei
   abgeschnittene Ortsangaben über zwei Zeilen sind keine Ortsangabe mehr;
   der Weg zurück ist dort ohnehin der Zurück-Knopf des Browsers. */
@media (max-width:34rem) {
    .pfad li:not(:nth-last-child(-n+2)) { display:none; }
    .pfad li:nth-last-child(2)::before { content:none; }
}


/* ==========================================================================
   3. DER SEITENKOPF

   Das Bauteil, das es nicht gab. Bis hierher begann jede Maske mit einem
   klassenlosen <h1> und, wenn es gut lief, einem <p class="unterzeile">
   darunter; die Handlungen standen mal als .wegleiste darüber, mal als
   .werkzeugleiste darunter, mal als loser Absatz mit Mittelpunkten dazwischen
   (templates/backoffice/vt/verzeichnis.html.twig führt acht Verweise in
   einem einzigen <p>). Es gab keinen festen Ort für die Frage "was kann ich
   auf dieser Maske tun?".

   AUFBAU

     .seitenkopf
       .pfad                     Wo bin ich
       .seitenkopf__zeile        Titel links, Handlungen rechts
         .seitenkopf__titelgruppe
           h1 / .seitenkopf__titel
           .marke                Zustand des Gegenstandes
         .seitenkopf__handlungen
       .seitenkopf__beitext      Ein Satz, was das hier ist

   >> DIE HANDLUNGEN STEHEN AUF DER GRUNDLINIE DES TITELS.

   `align-items:baseline` und nicht `center`: Der Titel ist mit --schrift-xl
   deutlich höher als ein Knopf mit --hoehe-2. Auf Mitte gestellt schwebt der
   Knopf über der Zeile und sieht aus, als gehöre er zum nächsten Block.
   Auf der Grundlinie liest sich die Zeile als EINE Zeile.

   >> UND SIE BRECHEN NACH UNTEN UM, NICHT NACH RECHTS.

   Unterhalb von 48rem steht die Handlungsgruppe in voller Breite unter dem
   Titel und rollt waagrecht, falls sie mehr als drei Knöpfe trägt. Der
   Titel wird NICHT gekürzt - er ist die Auskunft darüber, was man vor sich
   hat.
   ========================================================================== */

.seitenkopf {
    display:grid;
    gap:var(--raum-2);
    margin:0 0 var(--raum-5);
    padding:0 0 var(--raum-4);
    border-bottom:1px solid var(--rand-weich);
}

/* Ohne Trennlinie, wo der Kopf unmittelbar auf einer Karte oder einem
   Reiterstreifen sitzt - dort trägt die Kante der Fläche schon. */
.seitenkopf--nackt { padding-bottom:0; border-bottom:0; }

.seitenkopf__zeile {
    display:flex; flex-wrap:wrap;
    align-items:baseline;
    justify-content:space-between;
    gap:var(--raum-2) var(--raum-5);
}

.seitenkopf__titelgruppe {
    display:flex; flex-wrap:wrap;
    align-items:baseline;
    gap:var(--raum-2) var(--raum-3);
    /* min-width:0 ist keine Feinheit: Ein Flex-Element hat min-width:auto,
       und ein langer Titel zöge die Zeile sonst über die Spalte hinaus,
       statt umzubrechen. Dieselbe Falle wie bei .mandant__name. */
    min-width:0;
}

/* Der Titel wirkt auch ohne eigene Klasse: 126 Masken tragen ein klassenloses
   <h1>, und diese Familie soll sich Maske für Maske einführen lassen, ohne
   dass vorher 126 Vorlagen angefasst werden müssen. */
.seitenkopf h1,
.seitenkopf__titel {
    margin:0;
    font-size:var(--schrift-xl);
    font-weight:var(--fett-voll);
    line-height:var(--zeile-eng);
    letter-spacing:-.02em;
    color:var(--tinte);
}

/* Die Zustandsmarke steht NEBEN dem Titel und nicht darunter. Sie erbt ihr
   Aussehen von `main .marke` aus app.css - hier steht nur, dass sie in der
   Titelzeile nicht umbricht und ihre Grundlinie behält. */
.seitenkopf__titelgruppe .marke,
.seitenkopf__titelgruppe .marke-gesetzlich { white-space:nowrap; }

.seitenkopf__handlungen {
    display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--raum-2);
    /* Schiebt die Gruppe nach rechts, auch wenn links nur ein kurzer Titel
       steht. `justify-content:space-between` allein genügt nicht, sobald
       die Zeile umbricht. */
    margin-left:auto;
}

.seitenkopf__beitext {
    margin:0;
    max-width:var(--breite-text);
    font-size:var(--schrift-sm);
    line-height:var(--zeile-weit);
    color:var(--tinte-2);
}

/* Ein h1 aus dem Bestand, dem noch kein .seitenkopf untergeschoben wurde,
   trägt seine .unterzeile weiterhin direkt darunter. Die Regel aus
   app.css:971 (`h1 + .unterzeile { margin-top:-.5rem }`) rechnete einen
   negativen Abstand gegen den h1-Nachabstand - im Raster ist das eine
   Korrektur, die keine sein muss. */
h1 + .unterzeile { margin-top:calc(var(--raum-2) * -1); }

@media (max-width:48rem) {
    .seitenkopf__handlungen {
        margin-left:0;
        flex:1 0 100%;
        flex-wrap:nowrap;
        /* Vier Knöpfe passen auf einem Telefon in keine Zeile. Sie rollen
           waagrecht IN IHRER GRUPPE - der Seitenrumpf darf nie waagrecht
           rollen, weil das die feste Kopfleiste mitverschiebt. */
        overflow-x:auto;
        padding-bottom:var(--raum-1);
    }
    .seitenkopf__handlungen > * { flex:none; }
}


/* ==========================================================================
   4. DIE KARTE - EINE DEFINITION STATT SIEBZEHN

   Im Blatt stand dieselbe Fläche siebzehnmal ausgeschrieben:

       background:var(--flaeche); border:1px solid var(--rand);
       border-radius:var(--radius-sm);

   nämlich in .karte, .kachel, section.vollstaendigkeit, section.kandidat,
   section.pruefblock, .dse-vorschau, .rueckfrage, .vorschlag, .versandstand,
   article.beratungseintrag, section.offboarding, section.ansprechpartner,
   form.vertretung, .zustandsbild, .assistent-knopf, .aktenblatt__spalte und
   .vorlagenfeld. Siebzehn Stellen, an denen jemand eine Radiusänderung
   nachziehen müsste - und drei davon haben sie schon nicht mitgemacht
   (--radius-xs statt --radius-sm bei .rueckfrage, .vorschlag, .versandstand).

   Die Namen bleiben alle stehen: 228 Vorlagen zeigen darauf. Was
   verschwindet, sind die siebzehn Abschriften der Fläche.

   >> DIE KARTE HAT DREI TEILE UND BRAUCHT KEINEN DAVON.

   Eine Karte ohne .karte__rumpf polstert sich selbst (das ist der Fall der
   Anmeldemaske und der sechzehn Fachkarten oben). Sobald sie einen benannten
   Teil enthält, gibt sie die Polsterung an die Teile ab - nur so kann ein
   Kopf eine eigene Fläche tragen und bis an die Kante laufen.
   ========================================================================== */

.karte,
section.vollstaendigkeit,
section.kandidat,
section.pruefblock,
.dse-vorschau,
.rueckfrage,
.vorschlag,
.versandstand,
article.beratungseintrag,
section.offboarding,
section.ansprechpartner,
form.vertretung,
.zustandsbild,
.aktenblatt__spalte,
.vorlagenfeld {
    background:var(--flaeche);
    border:1px solid var(--rand);
    border-radius:var(--radius-md);
    box-shadow:var(--schatten-sm);
}

/* Die Polsterung steht getrennt, weil die Karte sie unter Umständen abgibt
   (siehe unten) - die Fläche behält sie in jedem Fall. */
.karte,
section.vollstaendigkeit,
section.kandidat,
section.pruefblock,
.vorschlag,
.versandstand,
article.beratungseintrag,
section.offboarding,
section.ansprechpartner,
form.vertretung,
.zustandsbild,
.aktenblatt__spalte,
.vorlagenfeld {
    padding:var(--raum-5);
}

/* Der Innenabstand der Karte darf am ersten und letzten Kind nicht durch
   deren Außenabstand verdoppelt werden. Das stand bisher vierfach
   ausgeschrieben (.hinweis, .vorschlag, .versandstand, .karte-Fachregeln). */
.karte > :first-child,
.karte__rumpf > :first-child,
.karte__kopf > :first-child,
.karte__fuss > :first-child { margin-top:0; }
.karte > :last-child,
.karte__rumpf > :last-child,
.karte__kopf > :last-child,
.karte__fuss > :last-child { margin-bottom:0; }

/* Sobald die Karte benannte Teile hat, gehört die Polsterung den Teilen.
   `:has()` ist im Blatt bereits in Gebrauch (.dse-vorschau:has(...)); wo es
   ausfällt, polstert die Karte doppelt - hässlich, aber lesbar. */
.karte:is(:has(> .karte__kopf), :has(> .karte__rumpf), :has(> .karte__fuss)) {
    padding:0;
    /* Ein Kopf mit eigener Fläche muss am Radius abgeschnitten werden,
       sonst steht seine Ecke über der Rundung der Karte. */
    overflow:clip;
}

.karte__kopf {
    display:flex; flex-wrap:wrap; align-items:baseline;
    justify-content:space-between;
    gap:var(--raum-2) var(--raum-4);
    padding:var(--raum-4) var(--raum-5);
    background:var(--flaeche-2);
    border-bottom:1px solid var(--rand-weich);
}

/* Der Kartentitel ist eine h2/h3-Stufe, aber ohne Außenabstand - der Kopf
   hat seine Polsterung. Er wirkt auch auf die klassenlose Überschrift. */
.karte__titel,
.karte__kopf > :is(h2, h3) {
    margin:0;
    font-size:var(--schrift-md);
    font-weight:var(--fett-stark);
    line-height:var(--zeile-eng);
    color:var(--tinte);
}

.karte__beitext {
    margin:0;
    font-size:var(--schrift-sm);
    line-height:var(--zeile-normal);
    color:var(--tinte-2);
}

.karte__rumpf { padding:var(--raum-5); }

.karte__fuss {
    display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--raum-2) var(--raum-4);
    padding:var(--raum-3) var(--raum-5);
    background:var(--flaeche-2);
    border-top:1px solid var(--rand-weich);
    font-size:var(--schrift-sm);
    color:var(--tinte-2);
}

/* --- Die anklickbare Karte ---------------------------------------------
   Der ganze Kasten ist das Ziel; der Unterstrich zerschnitte ihn. Dieselbe
   Begründung wie bei a.kachel in app.css, hier für die Karte. */
a.karte,
.karte--verweis {
    display:block;
    color:inherit; text-decoration:none;
    transition:border-color var(--dauer-normal) var(--stufe),
               box-shadow   var(--dauer-normal) var(--stufe),
               transform    var(--dauer-normal) var(--stufe);
}
a.karte:hover, a.karte:focus-visible,
.karte--verweis:hover, .karte--verweis:focus-visible {
    border-color:var(--akzent-hell);
    box-shadow:var(--schatten-md);
    /* Ein Pixel Hub. Mehr lässt ein Feld aus acht Karten wackeln, weniger
       sieht man nicht. Der Wert ist eine optische Größe und keine
       Rasterstrecke - deshalb kein --raum-Token. */
    transform:translateY(-1px);
    text-decoration:none;
}

/* --- Kartenzustände ---------------------------------------------------
   Die Kante links trägt den Zustand. Sie trägt ihn NIE allein: In jeder
   dieser Karten steht das Zustandswort im Kopf (WCAG 1.4.1). Die Breite ist
   --raum-1 (4px) und damit dieselbe Strecke wie im Raster - die 3px und 4px,
   die im Blatt nebeneinander standen, waren zwei Werte für eine Sache. */
.karte--warn    { border-left:var(--raum-1) solid var(--warn-rand);    background:var(--warn-weich); }
.karte--hinweis { border-left:var(--raum-1) solid var(--hinweis);      background:var(--hinweis-weich); }
.karte--gut     { border-left:var(--raum-1) solid var(--gut-rand);     background:var(--gut-weich); }
.karte--dran    { border-left:var(--raum-1) solid var(--akzent); }

/* Eine Karte, die nur eine Auskunft trägt und keine Arbeit, tritt zurück. */
.karte--still { background:var(--flaeche-2); box-shadow:none; }

/* >> DIE AKZENTKANTE DER ANMELDEKARTE BLEIBT.

   Sie ist die Marke dieser Seite. Ein Wort wäre hier falsch: Dasselbe Layout
   trägt die Anmeldung des Beraters UND die des Portalnutzers (siehe
   Kommentarkopf von layout/schlank.html.twig) - eine Beschriftung müsste also
   für beide stimmen und stimmte dann für keinen.

   Sie steht jetzt auf .huelle > .karte und nicht mehr auf .karte selbst: Als
   Regel der Grundkarte trüge inzwischen JEDE der siebzehn Fachkarten eine
   blaue Oberkante. Die Kantenstärke ist --raum-1 statt der bisherigen 3px -
   dieselbe Strecke wie alle übrigen Zustandskanten dieser Familie. */
.huelle > .karte {
    border-top:var(--raum-1) solid var(--akzent);
    box-shadow:var(--schatten-md);
}

/* --- Kartenfelder ------------------------------------------------------
   Das Raster für nebeneinanderstehende Karten. `auto-fit` UND NICHT
   `auto-fill` - dieselbe Begründung wie bei .kachelliste (AP-H17):
   `auto-fill` legt so viele Spuren an, wie hineinpassen, auch leere; auf
   einem breiten Bildschirm standen die Karten links und rechts daneben lag
   Nichts. `auto-fit` faltet die leeren Spuren zusammen.

   Die Mindestbreite steht als Bauteilgröße in der Klasse selbst und nicht
   als globales Token: Sie ist keine Rasterstrecke, sondern das Maß, ab dem
   der Inhalt DIESER Karte zweizeilig wird - eine Vorlage darf sie umsetzen. */
.kartenfeld {
    --mindestbreite:20rem;
    display:grid;
    gap:var(--raster-luecke);
    /* Die Rasterformel steht genau einmal, im Abschnitt RASTER. Hier steht
       nur das Mass, ab dem der Inhalt DIESER Karte zweizeilig wird. */
    align-items:start;
    margin:0 0 var(--raum-6);
}

@media (prefers-reduced-motion: reduce) {
    a.karte, .karte--verweis { transition:none; }
    a.karte:hover, a.karte:focus-visible,
    .karte--verweis:hover, .karte--verweis:focus-visible { transform:none; }
}


/* ==========================================================================
   5. DIE KACHEL

   Eine Kachel ist eine Karte, deren Inhalt EINE ZAHL ist. Sie steht im
   Cockpit (AP-E43) und in der Mandantenakte (AP-H23).

   >> ZÄHLWERTE, KEINE BEWERTUNG.

   Übernommen und unverändert gültig: Die Kacheln bekommen keine Ampel und
   keinen Reifegrad. "offen" und "leer" unterscheiden sich in Randstärke und
   Sattheit, und die Aussage steht in der Zahl und im Text darunter -
   CockpitTest prüft die gerenderte Antwort gegen eine Sperrliste.

   >> .kachel__titel HAT ES IM BLATT NIE GEGEBEN.

   templates/backoffice/mandant/akte.html.twig benutzt den Namen viermal -
   "Fällige Fristen", "Offene Vorgänge", "Verarbeitungstätigkeiten",
   "Portalkonten". Die vier Zeilen standen in der Größe des Fließtextes und
   im Gewicht 400 unter einer 2,1rem-Ziffer; auf dem Bildschirm sah das aus
   wie ein Beitext, nicht wie die Bezeichnung der Zahl. Er ist jetzt da und
   heißt dasselbe wie .kachel__bezeichnung im Cockpit - beide Namen bleiben,
   weil beide in Vorlagen stehen.
   ========================================================================== */

.kacheln { margin:0 0 var(--raum-6); }

.kachelliste {
    --mindestbreite:17rem;
    list-style:none; margin:0; padding:0;
    display:grid;
    gap:var(--raum-4);
    /* Nach oben gedeckelt: Eine Kachel mit einer Ziffer und zwei Zeilen Text
       sieht in 780px Breite leer aus. Die Obergrenze ist die Breite, in der
       die längste Bezeichnung zweizeilig steht. */
    --hoechstbreite:22rem;
    align-items:start;
}

.kachel {
    display:grid;
    gap:var(--raum-1);
    padding:var(--raum-4) var(--raum-5);
    background:var(--flaeche);
    border:1px solid var(--rand-weich);
    border-radius:var(--radius-md);
    box-shadow:var(--schatten-sm);
    /* Kante im Ruhezustand, bläulicher Schatten beim Überfahren - das ist
       die Handschrift der Marke. Ein Feld aus acht Kacheln, von denen keine
       auf den Zeiger antwortet, sieht aus wie ein Bild und nicht wie acht
       Verweise. */
    transition:box-shadow  var(--dauer-normal) var(--stufe),
               border-color var(--dauer-normal) var(--stufe),
               transform    var(--dauer-normal) var(--stufe);
}

a.kachel, a.kachel:hover { color:inherit; text-decoration:none; }

a.kachel:hover, a.kachel:focus-visible {
    border-color:var(--akzent-hell);
    box-shadow:var(--schatten-md);
    transform:translateY(-1px);
}

@media (prefers-reduced-motion: reduce) {
    .kachel { transition:none; }
    a.kachel:hover, a.kachel:focus-visible { transform:none; }
}

/* Die Zustandskante. --raum-1 statt der bisherigen 3px - dieselbe Strecke
   wie bei .karte--warn, damit nicht zwei Kantenstärken nebeneinander stehen.

   Der Ausgleich in der Polsterung bleibt und wird gerechnet statt geschätzt:
   Ohne ihn steht die Ziffer einer markierten Kachel um die Kantenstärke
   weiter rechts als die der Nachbarkachel, und in einem Feld aus acht
   Kacheln sieht man das. Bisher stand dort `calc(1rem - 2px)` gegen eine
   Polsterung von 1.2rem - der Ausgleich glich etwas anderes aus, als die
   Kachel hatte. */
.kachel--offen,
.kachel--warnung { padding-left:calc(var(--raum-5) - var(--raum-1)); }
.kachel--offen   { border-left:var(--raum-1) solid var(--hinweis); }
.kachel--warnung { border-left:var(--raum-1) solid var(--warn-rand); }
.kachel--leer    { background:var(--flaeche-2); box-shadow:none; }

.kachel__zahl {
    font-size:var(--schrift-2xl);
    font-weight:var(--fett-voll);
    line-height:var(--zeile-eng);
    letter-spacing:-.02em;
    /* Ziffern gleicher Breite: Acht Kacheln nebeneinander werden verglichen,
       und im Proportionalsatz stehen sie nicht untereinander. */
    font-variant-numeric:tabular-nums;
    color:var(--akzent);
}
.kachel--offen   .kachel__zahl { color:var(--hinweis); }
.kachel--warnung .kachel__zahl { color:var(--warn); }
.kachel--leer    .kachel__zahl { color:var(--tinte-3); }

/* Die Bezeichnung der Zahl. Zwei Namen, eine Regel: .kachel__bezeichnung
   kommt aus dem Cockpit, .kachel__titel aus der Mandantenakte. Beide bleiben
   stehen - eine Umbenennung hieße, fünf Vorlagen anzufassen, und der
   Gewinn wäre ein Name weniger. */
.kachel__bezeichnung,
.kachel__titel {
    font-size:var(--schrift-sm);
    font-weight:var(--fett-stark);
    line-height:var(--zeile-normal);
    color:var(--tinte);
}

.kachel__mandate,
.kachel__norm {
    font-size:var(--schrift-xs);
    line-height:var(--zeile-normal);
    color:var(--tinte-2);
}

/* Der Fuß nennt, wohin die Kachel führt und mit welchem Umfang. Er steht
   abgesetzt: Er ist eine Angabe über den WEG, nicht über die Zahl. */
.kachel__fuss {
    display:grid; gap:var(--raum-0);
    margin-top:var(--raum-2);
    padding-top:var(--raum-2);
    border-top:1px solid var(--rand-weich);
}
.kachel__weg    { font-size:var(--schrift-sm); font-weight:var(--fett-stark); color:var(--akzent); }
.kachel__umfang { font-size:var(--schrift-xs); color:var(--tinte-2); }

/* Die Hülle trägt das Sprungziel (#kachel-...) und sonst nichts; die Kachel
   darin füllt sie ganz aus, damit die Fläche zwischen zwei Kacheln kein
   totes Stück Verweis ist. */
.kachel-huelle { display:flex; }
.kachel-huelle > .kachel { flex:1; }

/* Eine Tabelle in einer Kachel ist eine Aufzählung, kein zweites Blatt. */
.kachel table { background:none; border:0; box-shadow:none; }


/* ==========================================================================
   6. DER ABSCHNITT

   Das gliedernde Element zwischen Seitenkopf und Karte. Es trägt eine
   Überschrift, einen erklärenden Satz und - wo eine Gruppe eigene
   Handlungen hat - eine Knopfgruppe auf derselben Zeile.

   Bis hierher hat jede Fachfamilie diese Gliederung selbst gebaut:
   .kachelgruppe, .ohne-befund, section.offene-punkte, .dse-gruppe,
   .werkbank__bestand - fünf Bauformen für dieselbe Sache, jede mit einer
   eigenen h2-Größe. Der Abschnitt macht daraus eine.

   Er hat KEINE eigene Fläche. Das ist Absicht: Wenn jeder Abschnitt eine
   Karte wäre, bestünde die Maske aus Kästen in Kästen, und der
   Auftraggeber hat genau dazu "es erschlägt einen" gesagt. Der Abschnitt
   gliedert durch Abstand und eine Kopfzeile, nicht durch einen Rahmen.
   ========================================================================== */

.abschnitt { margin:0 0 var(--raum-6); }
.abschnitt:last-child { margin-bottom:0; }

.abschnitt__kopf {
    display:flex; flex-wrap:wrap;
    align-items:baseline; justify-content:space-between;
    gap:var(--raum-1) var(--raum-4);
    margin:0 0 var(--raum-3);
}

/* Wirkt auch auf die klassenlose Überschrift - dieselbe Begründung wie
   beim Seitenkopf: 229 Masken tragen ein klassenloses <h2>. */
.abschnitt__titel,
.abschnitt__kopf > :is(h2, h3) {
    margin:0;
    font-size:var(--schrift-lg);
    font-weight:var(--fett-stark);
    line-height:var(--zeile-eng);
    letter-spacing:-.01em;
    color:var(--tinte);
}

.abschnitt__beitext {
    /* Volle Breite der Kopfzeile: Der erklärende Satz gehört unter den
       Titel und nicht neben ihn. */
    flex:1 0 100%;
    margin:0;
    max-width:var(--breite-text);
    font-size:var(--schrift-sm);
    line-height:var(--zeile-weit);
    color:var(--tinte-2);
}

.abschnitt__handlungen {
    display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--raum-2);
    margin-left:auto;
}

/* Eine Zählung neben dem Titel: "12" hinter "Offene Vorgänge". Sie steht
   in einer Pille und trägt IMMER ein Wort im Titel daneben - allein ist eine
   Zahl in einer Pille keine Aussage. */
.abschnitt__zahl {
    display:inline-block;
    padding:0 var(--raum-2);
    min-width:var(--hoehe-1);
    font-size:var(--schrift-xs);
    font-weight:var(--fett-stark);
    font-variant-numeric:tabular-nums;
    text-align:center;
    color:var(--tinte-2);
    background:var(--flaeche-3);
    border-radius:var(--radius-voll);
}

/* --- Der faltbare Abschnitt --------------------------------------------
   Dasselbe Bauteil als <details>. Der Kopf wird zum <summary>; das Zeichen
   kommt aus .aufklapper (siehe unten), damit es nur einmal im Blatt steht. */
details.abschnitt > summary.abschnitt__kopf {
    cursor:pointer;
    list-style:none;
    border-radius:var(--radius-sm);
}
details.abschnitt > summary.abschnitt__kopf::-webkit-details-marker { display:none; }


/* ==========================================================================
   7. DER AUFKLAPPER

   <details> mit einer ordentlichen Zusammenfassungszeile. Im Bestand gibt es
   ihn dreimal in drei Bauformen: details.feldgruppe (die 48-Felder-Maske),
   [class^="durchsicht-"] (die Durchsichtsliste) und .anlegen (das gefaltete
   Anlegeformular am Fuß einer Liste). Alle drei bleiben, wie sie sind -
   .aufklapper ist der Name für alles, was neu dazukommt, und die drei
   können ihn später übernehmen.

   >> DAS ZEICHEN IST GEZEICHNET UND KEIN BUCHSTABE.

   Ein Dreieck aus der Schrift (U+25B8) liegt nicht in den beiden
   Inter-Teilmengen, die dieses System ausliefert; der Browser holte es aus
   einer Systemschrift, und die Größe stimmte dann auf keinem zweiten
   Rechner. Eine Symbolschrift kommt nicht in Frage (font-src 'self', und
   jede weitere Datei wäre ein vierter Ausgang). Der Winkel unten ist aus
   zwei Kanten gebaut - er kostet kein Byte und sitzt überall gleich.

   >> UND DAS BROWSEREIGENE DREIECK MUSS AUSDRÜCKLICH WEG.

   `display:flex` auf einem <summary> nimmt es Chrome und Safari ohnehin
   (deshalb warnt app.css bei der Durchsichtsliste davor). Hier ist das
   gewollt, weil ein eigenes Zeichen an seiner Stelle steht - `list-style:none`
   und der ::-webkit-details-marker sorgen dafür, dass nicht zwei Zeichen
   nebeneinander stehen.
   ========================================================================== */

.aufklapper {
    margin:0 0 var(--raum-4);
    background:var(--flaeche);
    border:1px solid var(--rand);
    border-radius:var(--radius-sm);
}

/* Ein Aufklapper, der nur gliedert und keine eigene Fläche braucht. */
.aufklapper--nackt {
    background:none; border:0; border-radius:0;
    border-top:1px solid var(--rand-weich);
}

.aufklapper__kopf,
.aufklapper > summary {
    display:flex; align-items:center;
    gap:var(--raum-3);
    min-height:var(--hoehe-2);
    padding:var(--raum-2) var(--raum-4);
    font-size:var(--schrift-sm);
    font-weight:var(--fett-stark);
    line-height:var(--zeile-normal);
    color:var(--tinte);
    cursor:pointer;
    list-style:none;
    border-radius:var(--radius-sm);
    transition:background-color var(--dauer-schnell) var(--stufe);
}
.aufklapper > summary::-webkit-details-marker { display:none; }

.aufklapper > summary:hover { background:var(--flaeche-2); }

/* Der Winkel. Er zeigt zu und dreht sich beim Öffnen nach unten.
   Die 2px sind die Strichstärke eines ZEICHENS und keine Rasterstrecke -
   sie darf nicht mit --raum-1 (4px) mitwachsen, sonst wird aus dem Winkel
   ein Balken. Das em-Maß lässt ihn mit der Schrift skalieren. */
.aufklapper > summary::before,
details.abschnitt > summary.abschnitt__kopf::before {
    content:"";
    flex:none;
    width:.4em; height:.4em;
    border-right:2px solid var(--tinte-3);
    border-bottom:2px solid var(--tinte-3);
    /* -45deg zeigt nach rechts (zu), 45deg nach unten (offen). Der Versatz
       hält den optischen Mittelpunkt auf der Textmitte. */
    transform:translateY(-.1em) rotate(-45deg);
    transition:transform var(--dauer-normal) var(--stufe);
}
.aufklapper[open] > summary::before,
details.abschnitt[open] > summary.abschnitt__kopf::before {
    transform:translateY(-.15em) rotate(45deg);
}

@media (prefers-reduced-motion: reduce) {
    .aufklapper > summary,
    .aufklapper > summary::before,
    details.abschnitt > summary.abschnitt__kopf::before { transition:none; }
}

/* Der Titel nimmt den Platz, der Zustand steht rechts davon. Untereinander
   wäre eine zugeklappte Liste sofort doppelt so lang - dieselbe Begründung
   wie bei .durchsicht-stand (AP-H16). */
.aufklapper__titel { flex:1 1 auto; min-width:0; }

.aufklapper__stand {
    flex:none;
    font-size:var(--schrift-xs);
    font-weight:var(--fett-normal);
    color:var(--tinte-2);
}

/* Der Zustand trägt Farbe UND Wort. Die Klasse färbt nur; das Wort steht
   in der Vorlage (WCAG 1.4.1). */
.aufklapper__stand--offen { color:var(--hinweis); }
.aufklapper__stand--warn  { color:var(--warn); }
.aufklapper__stand--gut   { color:var(--gut); }

.aufklapper[open] > summary { border-bottom:1px solid var(--rand-weich); }

/* Nur seitlicher Einzug plus ein Nachabstand: Den senkrechten Abstand
   bringen Tabelle und Formular selbst mit - dieselbe Lösung wie bei
   details.feldgruppe und .durchsicht-falt. */
.aufklapper__rumpf,
.aufklapper > :not(summary) {
    margin:0;
    padding:var(--raum-4);
}
.aufklapper__rumpf > :first-child { margin-top:0; }
.aufklapper__rumpf > :last-child  { margin-bottom:0; }


/* ==========================================================================
   8. REITER UND SEGMENTSCHALTER

   Zwei Umschalter für zwei Fälle, die heute beide in .filterleiste stecken:

     .reiter          Ansichtswechsel, der die Maske wechselt (viele Punkte,
                      Beschriftungen unterschiedlich lang) - Unterstreichung.
     .segmentschalter Umschaltung EINER Angabe zwischen zwei bis vier
                      gleichrangigen Werten - Pillen in einer Bahn.

   >> WARUM .filterleiste BLEIBT, WIE SIE IST.

   Sie steht in 41 Masken und kommt aus dem Makro `liste.filterleiste()`. Sie
   trägt seit AP-H28 zweierlei: Verweise, wo alles in die Adresse darf, und
   Knöpfe, wo ein Suchbegriff im Rumpf mitfährt (CLAUDE.md § 10). Sie sieht
   deshalb aus wie ein Segmentschalter, ist aber KEINER - sie hat beliebig
   viele Punkte und einen "alle"-Eintrag. Die Regeln unten fassen beide unter
   denselben Selektorblock, damit es eine Beschreibung gibt und nicht zwei.

   >> DER AKTIVE PUNKT TRÄGT NIE NUR FARBE.

   Er trägt Gewicht (--fett-stark), Fläche UND `aria-current`. Die Reiter
   tragen zusätzlich eine Unterstreichung. Farbe allein ist für farbenblinde
   Leser keine Aussage (WCAG 1.4.1) - dieselbe Regel wie im Ebenenstreifen.

   >> UND DIE KANTE ERREICHT 3:1.

   Die Bahn des Segmentschalters ist ein Bedienelement; ihre Umrandung steht
   auf --rand-stark und nicht auf --rand (WCAG 1.4.11).
   ========================================================================== */

/* --- Reiter (Unterstreichung) ------------------------------------------ */

.reiter {
    display:flex; flex-wrap:wrap;
    gap:var(--raum-1);
    margin:0 0 var(--raum-5);
    border-bottom:1px solid var(--rand);
}

.reiter > a,
.reiter > button {
    display:inline-flex; align-items:center;
    gap:var(--raum-2);
    min-height:var(--hoehe-2);
    padding:0 var(--raum-3);
    /* Die Linie liegt UNTER der Trennlinie der Leiste - der aktive Reiter
       deckt sie. Deshalb 1px negativer Versatz und kein Abstand. */
    margin-bottom:-1px;
    border:0; border-bottom:2px solid transparent;
    background:none;
    font:inherit;
    font-size:var(--schrift-sm);
    font-weight:var(--fett-halb);
    color:var(--tinte-2);
    text-decoration:none;
    cursor:pointer;
    white-space:nowrap;
    transition:color var(--dauer-schnell) var(--stufe),
               border-color var(--dauer-schnell) var(--stufe);
}

.reiter > a:hover,
.reiter > button:hover {
    color:var(--tinte);
    border-bottom-color:var(--rand-stark);
    text-decoration:none;
}

.reiter > .aktiv,
.reiter > [aria-current] {
    color:var(--akzent);
    border-bottom-color:var(--akzent);
    font-weight:var(--fett-stark);
}

/* --- Segmentschalter und Filterleiste (Pillen) ------------------------- */

.segmentschalter {
    display:inline-flex; flex-wrap:wrap;
    gap:var(--raum-1);
    /* Die Bahn liegt tiefer als das Blatt: --flaeche-3 ist genau dafür da. */
    padding:var(--raum-1);
    background:var(--flaeche-3);
    border:1px solid var(--rand-stark);
    border-radius:var(--radius-voll);
}

.filterleiste {
    display:flex; flex-wrap:wrap;
    gap:var(--raum-1);
    margin:0 0 var(--raum-5);
}

.segmentschalter > a,
.segmentschalter > button,
.filterleiste a,
.filterleiste button {
    display:inline-flex; align-items:center;
    gap:var(--raum-1);
    min-height:var(--hoehe-1);
    padding:0 var(--raum-3);
    border:1px solid transparent;
    border-radius:var(--radius-voll);
    background:none;
    font:inherit;
    font-size:var(--schrift-sm);
    font-weight:var(--fett-halb);
    color:var(--tinte-2);
    text-decoration:none;
    cursor:pointer;
    white-space:nowrap;
    transition:background-color var(--dauer-schnell) var(--stufe),
               color            var(--dauer-schnell) var(--stufe);
}

.segmentschalter > a:hover,
.segmentschalter > button:hover,
.filterleiste a:hover,
.filterleiste button:hover {
    background:var(--flaeche-2);
    border-color:var(--rand-weich);
    color:var(--tinte);
    text-decoration:none;
}

/* Der gewählte Punkt liegt auf dem Blatt und nicht in der Rinne - er ist
   der einzige, der hervorsteht. Im Segmentschalter trägt er deshalb
   --flaeche und einen Schatten, in der Filterleiste die Akzentfläche. */
.segmentschalter > .aktiv,
.segmentschalter > [aria-current] {
    background:var(--flaeche);
    border-color:var(--rand);
    box-shadow:var(--schatten-sm);
    color:var(--akzent);
    font-weight:var(--fett-stark);
}

.filterleiste .aktiv,
.filterleiste [aria-current] {
    background:var(--akzent-weich);
    border-color:transparent;
    color:var(--akzent);
    font-weight:var(--fett-stark);
}

/* Die Zählung hinter einem Filterwort bleibt Nebenangabe. */
.segmentschalter .nr,
.filterleiste .nr { font-weight:var(--fett-normal); color:inherit; opacity:.75; }

@media (prefers-reduced-motion: reduce) {
    .reiter > a, .reiter > button,
    .segmentschalter > a, .segmentschalter > button,
    .filterleiste a, .filterleiste button { transition:none; }
}

/* Auf schmalen Schirmen rollt die Reiterzeile waagrecht, statt in drei
   Zeilen umzubrechen: Umgebrochene Reiter sehen aus wie eine Liste. Die
   Filterleiste bricht weiterhin um - sie IST eine Liste. */
@media (max-width:48rem) {
    .reiter {
        flex-wrap:nowrap;
        overflow-x:auto;
        /* Der Seitenrumpf darf nie waagrecht rollen; die Leiste rollt in
           sich. */
        scrollbar-width:thin;
    }
    .reiter > a, .reiter > button { flex:none; }
}


/* ==========================================================================
   9. KENNZAHLEN - EINE DEFINITION FÜR ZWEI BAUFORMEN

   >> WAS HIER KAPUTT WAR, UND WARUM ES NIEMANDEM AUFFIEL.

   Die Klasse war ZWEIMAL definiert:

     app.css:671   .kennzahlen { display:flex; ... }   für <div> mit <p>
     app.css:3515  .kennzahlen { display:grid;
                                 grid-template-columns:auto 1fr; }  für <dl>

   Bei gleicher Gewichtung (0,1,0) gewinnt die spätere. Die Grid-Fassung aus
   der Mandantenakte hat damit ALLE anderen Kennzahlenzeilen übernommen -
   sieben Masken, in denen <p>- und <span>-Kinder in ein zweispaltiges Raster
   gefallen sind: "0" in Spalte eins, "Datenkategorien ohne Löschklasse" in
   Spalte zwei, nächster Absatz eine Zeile tiefer. Aus einer Zeile mit drei
   Kennzahlen wurden drei Zeilen mit je einer halben.

   Gefunden wurde es nicht, weil beide Fassungen für sich richtig aussehen -
   nur eben nicht gleichzeitig.

   >> DIE LÖSUNG IST NICHT "EINE VON BEIDEN GEWINNT".

   Es sind wirklich zwei Bauformen, und beide sind richtig:

     div.kennzahlen > p         eine Reihe gezählter Aussagen
     p.kennzahlen  > span       dieselbe Reihe, in einem Absatz
     dl.kennzahlen > dt + dd    ein Steckbrief: Merkmal und Wert

   Die Reihe ist der Regelfall und bekommt die klassenlose Regel. Der
   Steckbrief ist an seinem Element erkennbar - `dl.kennzahlen` trägt (0,1,1)
   und gewinnt, ohne dass die Reihenfolge im Blatt etwas entscheidet. Wer den
   Block verschiebt, zerlegt nichts mehr.
   ========================================================================== */

/* Bauform 1 und 2: die Reihe. */
.kennzahlen {
    display:flex; flex-wrap:wrap;
    gap:var(--raum-2) var(--raum-5);
    margin:var(--raum-4) 0 var(--raum-5);
    font-size:var(--schrift-sm);
    line-height:var(--zeile-normal);
    color:var(--tinte-2);
}
.kennzahlen > p,
.kennzahlen > span { margin:0; }

/* Die Zahl steht in jeder dieser Masken in einem <strong>. Sie trägt
   Ziffern gleicher Breite und die volle Tinte - der Text daneben bleibt
   Beitext, sonst hat die Zeile kein Gefälle. */
.kennzahlen strong {
    font-weight:var(--fett-stark);
    font-variant-numeric:tabular-nums;
    color:var(--tinte);
}
/* >> IN DER KENNZAHLENZEILE IST EIN MELDUNGSKASTEN EIN FEHLER.

   templates/backoffice/frist/uebersicht.html.twig setzt <p class="fehler">
   MITTEN in die Kennzahlenzeile - "3 gesetzliche Fristen überschritten"
   neben zwei gewöhnlichen Zählwerten. p.fehler ist aber der Flash-Kasten mit
   Polsterung, Fläche und Kante links: Aus einer Zeile mit vier Zahlen wurde
   eine Zeile mit drei Zahlen und einem Kasten dazwischen.

   Es ist genau die Begründung, mit der .warnung schon bisher reine
   Textauszeichnung geblieben ist: Ein Kasten würde die Kennzahlenzeile
   zerreißen - und die Aussage steht ohnehin im Wortlaut, die Farbe hebt sie
   nur hervor (WCAG 1.4.1 ist damit erfüllt, weil die Farbe nichts trägt, was
   der Wortlaut nicht sagt). */
.kennzahlen > :is(.fehler, .hinweis, .erfolg, .warnung) {
    margin:0; padding:0; border:0; border-radius:0; background:none;
    font-size:inherit;
}
.kennzahlen > .fehler, .kennzahlen .warnung { color:var(--warn); }
.kennzahlen > .hinweis { color:var(--hinweis); }
.kennzahlen > .erfolg  { color:var(--gut); }

/* Eine Kennzahl mit Rechtsfolge färbt ihre Zahl mit - sie steht dann nicht
   in Tinte, sondern in der Farbe ihrer Zeile. */
.kennzahlen .warnung strong,
.kennzahlen > :is(.fehler, .hinweis, .erfolg) strong { color:inherit; }

/* app.css:1621 (`.kennzahlen p.warnung { margin:0; padding:0; ... }`) war der
   erste Versuch derselben Behebung - nur für EINE der vier Klassen und nur
   für <p>. Er geht in der Regel darüber auf. */

/* Bauform 3: der Steckbrief. */
dl.kennzahlen {
    display:grid;
    grid-template-columns:max-content minmax(0, 1fr);
    gap:var(--raum-2) var(--raum-4);
    margin:0;
    align-items:baseline;
}
dl.kennzahlen dt {
    font-size:var(--schrift-sm);
    color:var(--tinte-2);
}
dl.kennzahlen dd {
    margin:0;
    font-size:var(--schrift-sm);
    font-weight:var(--fett-stark);
    color:var(--tinte);
}
dl.kennzahlen dd .nr,
dl.kennzahlen dd .klein {
    margin-left:var(--raum-2);
    font-weight:var(--fett-normal);
}

/* Unter 34rem hat ein zweispaltiger Steckbrief keine zwei Spalten mehr:
   "Stand des Verzeichnisses" nimmt allein die halbe Breite. Merkmal und
   Wert stehen dort untereinander. */
@media (max-width:34rem) {
    dl.kennzahlen { grid-template-columns:minmax(0, 1fr); gap:var(--raum-0); }
    dl.kennzahlen dd { margin-bottom:var(--raum-2); }
}


/* ==========================================================================
   10. ZWEI TOKEN, DIE ES NIE GAB

   `--linie` (sechs Verwendungen) und `--rundung` (drei) stehen in den
   Blöcken "Mandantenakte" und "Vorlagenebene" (app.css:3491-3550). Im
   Wertevorrat gibt es sie nicht - und ein `var()` ohne Ersatzwert und ohne
   Deklaration macht die GANZE Deklaration ungültig:

       border:1px solid var(--linie);   ->  border wird auf den Anfangswert
                                            zurückgesetzt: KEINE Kante
       border-radius:var(--rundung);    ->  0

   Die Karten der Mandantenakte und der Vorlagenebene standen also rahmenlos
   und mit rechten Ecken auf --grund; die Trennlinien der Terminliste und der
   Vorlagenliste fehlten ganz. Auf dem Bildschirm sah das aus wie ein
   Gestaltungsentscheid, es war ein Tippfehler.

   Die Verwendungen sind oben mit aufgelöst (.aktenblatt__spalte und
   .vorlagenfeld liegen im Kartenblock); was hier steht, sind die
   Listentrenner, die sonst niemand erbt.
   ========================================================================== */

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

.terminliste li {
    display:grid;
    grid-template-columns:10rem minmax(0, 1fr);
    gap:var(--raum-3);
    padding:var(--raum-3) 0;
    border-bottom:1px solid var(--rand-weich);
}
.terminliste li:last-child { border-bottom:0; }

/* Die 10rem sind die Breite von "01.09.2026" plus "seit 12 Tagen
   überschritten" in --schrift-xs - gemessen, nicht geschätzt. Unterhalb
   von 34rem fällt die Spalte weg, weil daneben kein Platz mehr für den
   Bezugstext bleibt. */
@media (max-width:34rem) {
    .terminliste li { grid-template-columns:minmax(0, 1fr); gap:var(--raum-1); }
}

.terminliste__zeile--offen { background:var(--warn-weich); }

.terminliste__termin { font-variant-numeric:tabular-nums; }
.terminliste__termin .warnung,
.terminliste__termin .nr { display:block; font-size:var(--schrift-xs); }

.vorlagenfelder {
    --mindestbreite:20rem;
    display:grid;
    /* Die Rasterformel steht genau einmal, im Abschnitt RASTER. Hier steht
       nur das Mass, ab dem der Inhalt DIESER Karte zweizeilig wird. */
    gap:var(--raster-luecke);
    align-items:start;
}

.vorlagenfeld__zweck {
    margin:0 0 var(--raum-3);
    font-size:var(--schrift-sm);
    line-height:var(--zeile-normal);
    color:var(--tinte-2);
}

.vorlagenfeld__liste { list-style:none; margin:0; padding:0; }
.vorlagenfeld__liste li {
    padding:var(--raum-2) 0;
    border-top:1px solid var(--rand-weich);
}
.vorlagenfeld__liste li .nr {
    display:block;
    margin-top:var(--raum-1);
    font-size:var(--schrift-xs);
}

/* Ein Bestand, den nur eine Migration ändert, sieht nicht aus wie ein Link. */
.vorlagenfeld__fest { color:var(--tinte-2); }

.aktenblatt {
    display:grid;
    grid-template-columns:minmax(0, 1fr);
    gap:var(--raster-luecke);
}

/* Zwei Spalten erst, wenn beide breit genug sind. 64rem ist der dritte
   Bruchpunkt des Wortschatzes; die früheren 75rem waren ein Wert, den es
   nur hier gab. Der Ebenenstreifen und die Gliederung nehmen links Platz -
   deshalb der breite und nicht der mittlere Bruchpunkt. */
/* Das Aktenblatt teilt sich nach seiner EIGENEN Spurbreite und nicht nach
   der Fensterbreite - es steht in main, und main ist um --gliederung-breite
   schmaler als das Fenster. Die Rasterzeile dazu steht im Abschnitt RASTER;
   hier bleibt nur die Mindestbreite. Ein Verhaeltnis 1.2fr/1fr faellt damit
   weg: Es sind zwei unabhaengige Bloecke, keine Haupt- und keine Nebenspalte. */


/* Der Ebenenstreifen stand hier im Entwurf und steht jetzt im Abschnitt
   SCHALE: Seine Hoehe ist --streifen-hoehe und geht in --kopfleiste-hoehe
   ein. Wer den Streifen bemisst, muss auch die Leiste bemessen - sonst
   klebt der Tabellenkopf wieder 3,5rem zu hoch. Eine Hand, eine Stelle. */


/* ==========================================================================
   12. WAS DIE FAMILIE AN VORHANDENEN LEISTEN MITNIMMT

   .wegleiste (zwei Masken) und .werkzeugleiste (vier) sind beide "eine Zeile
   mit den Handlungen einer Maske". Sie sind das, was .seitenkopf__handlungen
   jetzt richtig macht - solange sie in Vorlagen stehen, bekommen sie
   dieselben Maße, damit nicht zwei Handlungszeilen verschieden aussehen.
   ========================================================================== */

.wegleiste {
    display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--raum-2) var(--raum-3);
    margin:0 0 var(--raum-5);
    font-size:var(--schrift-sm);
}

/* Ein Verweis in der Handlungszeile bricht nicht mitten im Wort um -
   "Ausgabe je Unternehmen" über zwei Zeilen liest sich als zwei Punkte. */
.wegleiste a, .werkzeugleiste a { white-space:nowrap; }

/* Ein Anlegeformular am Fuß einer Liste: gefaltet, weil das Bearbeiten der
   häufige Fall ist und das Anlegen der seltene (AP-H24). */
.anlegen {
    margin-top:var(--raum-5);
    padding-top:var(--raum-4);
    border-top:1px solid var(--rand-weich);
}
.anlegen > summary {
    cursor:pointer;
    font-size:var(--schrift-sm);
    font-weight:var(--fett-stark);
    color:var(--akzent);
}
.anlegen[open] > summary { margin-bottom:var(--raum-4); }

/* Die zuletzt gewählten Mandate stehen oben und heben sich ab - sie sind der
   häufige Fall, die vollständige Liste der seltene (AP-H23). */
.liste--zuletzt { margin-bottom:var(--raum-5); }

/* Die Lagezeile ist die erste Aussage des Cockpits: wie viele Auswertungen
   überhaupt etwas gefunden haben. Sie steht als Zeile und nicht als Kasten -
   ein Kasten wäre ein weiterer Block in einer Seite aus Blöcken. */
.lagezeile {
    margin:0 0 var(--raum-5);
    padding:var(--raum-2) 0;
    border-bottom:1px solid var(--rand-weich);
    font-size:var(--schrift-md);
    font-variant-numeric:tabular-nums;
}
.lagezeile strong {
    font-size:var(--schrift-lg);
    font-weight:var(--fett-stark);
    color:var(--akzent);
}

/* Die Gruppen tragen die Gliederung des Cockpits. Sie sind Abschnitte und
   bekommen deshalb dieselben Maße - .kachelgruppe bleibt als Name stehen,
   weil die Vorlage darauf zeigt. */
.kachelgruppe,
.ohne-befund { margin:0 0 var(--raum-6); }
.kachelgruppe > .unterzeile,
.ohne-befund > .unterzeile { margin:0 0 var(--raum-4); }


/* --------------------------------------------------------------------------
   Der Freigabestand im Cockpit

   Eine dreizeilige Zaehltabelle. Ohne Deckel liefe sie ueber die volle
   Arbeitsspalte - seit die Listenmasken auf --breite-weit stehen, waeren das
   1600 Pixel fuer drei Zahlen.
   -------------------------------------------------------------------------- */
.freigabestand { margin:0 0 var(--raum-6); }
.freigabestand table { max-width:36rem; }


/* ==========================================================================
   TABELLEN, LISTEN UND BLAETTERUNG
   ========================================================================== */

/* ==========================================================================
   FAMILIE: TABELLEN, LISTEN UND BLÄTTERUNG

   Ersetzt app.css 607-660, 706, 2091-2108, 2758-2793, 2855-2959,
   3020-3030 und 3039-3051. Die Begründungen dieser Blöcke (AP-H17,
   AP-H15, AP-H28, WCAG 1.4.1 / 1.4.11) sind mitgenommen und fortgeschrieben,
   nicht ersetzt.

   >> WAS GEMESSEN WURDE, BEVOR ETWAS GEÄNDERT WURDE.

   Zeilenhöhe 1,6 mal Schrift 0,92rem = 23,6px, dazu Polsterung 0,65rem oben
   und unten = 20,8px, dazu die Haarlinie = 45,3px je Zeile. In den 317px, die
   in der Fristenliste zwischen Trefferzeile und Blätterung liegen, stehen
   damit sieben Zeilen. Sieben Zeilen sind keine Arbeitsliste, sondern ein
   Ausschnitt.

   Neu: --schrift-sm (14px) mal --zeile-eng (1,3) = 18,2px, dazu --raum-2 oben
   und unten = 16px, dazu die Haarlinie = 35,2px. Das sind neun Zeilen im
   selben Fenster; mit `.tabelle--eng` (27,2px) sind es elf.

   >> DIE DICHTE IST EINE EIGENSCHAFT, KEINE ZWEITE REGELMENGE.

   `.tabelle--eng` und `.tabelle--luftig` setzen zwei Custom Properties um.
   Sie wiederholen keine einzige Deklaration - wären es doppelte Regeln,
   müsste jede spätere Änderung an drei Stellen nachgezogen werden, und
   genau so driften Stilblätter auseinander.
   ========================================================================== */

:root {
    /* Die Polsterung der Zelle. Senkrecht trägt sie die Dichte, waagrecht
       die Lesbarkeit - deshalb zwei Namen und nicht einer: Eine enge Liste
       soll flacher werden, nicht schmaler. */
    --tabelle-polster:      var(--raum-2);
    --tabelle-polster-quer: var(--raum-3);

    /* Wie weit der haftende Kopf von oben absteht. Außerhalb eines
       Rollbehälters ist das die Höhe der Seitenkopfleiste; im
       Rollbehälter ist es null (siehe dort). */
    --tabelle-kopf-oben: var(--kopfleiste-hoehe);

    /* Der Deckel des Rollbehälters. Ohne ihn rollt die SEITE und nicht der
       Behälter - und ein haftender Tabellenkopf in einem Behälter, der
       selbst nie rollt, haftet an nichts. --raum-8 ist der Platz, den
       Trefferzeile und Blätterung über und unter der Tabelle brauchen. */
    --tabelle-rolle-hoehe: calc(100dvh - var(--kopfleiste-hoehe) - var(--raum-8));
}

/* Die Dichte lässt sich seitenweit stellen (ein Stimulus-Controller auf
   <body>, der die Wahl in localStorage behält) und je Tabelle übersteuern.
   Die Reihenfolge ist Absicht: die Tabellenklasse gewinnt über die
   Seitenklasse, weil sie näher am Gegenstand steht. */
.dichte--eng    { --tabelle-polster:var(--raum-1); --tabelle-polster-quer:var(--raum-2); }
.dichte--luftig { --tabelle-polster:var(--raum-3); --tabelle-polster-quer:var(--raum-4); }


/* --------------------------------------------------------------------------
   Die Tabelle als Arbeitsfläche

   >> EINE TABELLE IST EIN BLATT, KEIN GITTER (AP-H17, fortgeschrieben).

   Die Begründung von AP-H17 gilt unverändert: Rahmen außen, getönte
   Kopfleiste und eine Linie unter jeder Zelle sind die Optik einer
   Tabellenkalkulation. Eine Arbeitsliste liest man zeilenweise - sie braucht
   waagrechte Haarlinien und sonst nichts.

   Was dazugekommen ist: Das Blatt liegt jetzt am Rollbehälter, wo es einen
   gibt (siehe `.tabellenrolle`). Ein Schlagschatten am Tabellenkasten wird
   von `overflow:auto` des Behälters abgeschnitten, sobald jemand rollt -
   der Kasten sah dann an drei Seiten anders aus als an der vierten.

   `border-collapse:separate` statt `collapse`: Ein Radius greift an einer
   zusammengelegten Tabellenkante nicht. Bei `border-spacing:0` sieht die
   Trennlinie genauso aus wie bei `collapse`, weil jede Zelle ihre eigene
   untere Linie trägt.
   -------------------------------------------------------------------------- */
table {
    width:100%;
    font-size:var(--schrift-sm);
    line-height:var(--zeile-eng);
    border-collapse:separate; border-spacing:0;
    background:var(--flaeche);
    border-radius:var(--radius-sm);
    box-shadow:0 0 0 1px var(--rand-weich), var(--schatten-sm);
}

/* Der Kopf trägt keine Fläche mehr, sondern eine kräftigere Linie
   darunter - außer wenn er feststeht. Dort MUSS er decken, sonst scheinen
   die Zeilen darunter durch (siehe "Der Kopf bleibt stehen"). */
th {
    text-align:left; vertical-align:bottom;
    font-size:var(--schrift-xs); letter-spacing:.04em; text-transform:uppercase;
    font-weight:var(--fett-stark); color:var(--tinte-2);
    padding:var(--tabelle-polster) var(--tabelle-polster-quer);
    border-bottom:1px solid var(--rand);
}

/* `vertical-align:top`, weil viele Zellen eine Nebenzeile tragen
   (`.nr`, `.restzeit`, `.zeilennorm`): Bei `middle` hängt die Hauptangabe
   dann zwischen zwei Zeilen statt auf der ersten. */
td {
    padding:var(--tabelle-polster) var(--tabelle-polster-quer);
    border-bottom:1px solid var(--rand-weich);
    vertical-align:top;
}

.tabelle--eng    { --tabelle-polster:var(--raum-1); --tabelle-polster-quer:var(--raum-2); }
.tabelle--luftig { --tabelle-polster:var(--raum-3); --tabelle-polster-quer:var(--raum-4); }

/* >> DIE ZEILE UNTER DEM ZEIGER IST EIN SCHLEIER, KEINE FARBE.

   Vorher: `background:var(--flaeche-2)`. Das ist deckend und löschte damit
   jede Zeilenfärbung, über die es lief - eine überfällige Zeile verlor
   beim Überfahren genau die Auszeichnung, wegen der sie gefärbt ist.

   `--tinte` mit 4% über der Zellenfläche dunkelt im Hellmodus ab und
   hellt im Dunkelmodus auf, weil `--tinte` dort hell ist. Ein Wert, zwei
   richtige Ergebnisse - und die Zeilenfarbe darunter bleibt sichtbar. */
tbody tr td { background-color:var(--zeile-flaeche, transparent); }
tbody tr:hover td {
    background-image:linear-gradient(
        color-mix(in srgb, var(--tinte) 4%, transparent),
        color-mix(in srgb, var(--tinte) 4%, transparent));
}

/* Zahlen stehen rechts und untereinander vergleichbar. */
td.rechts, th.rechts { text-align:right; }
td.rechts, .zahl, .restzeit { font-variant-numeric:tabular-nums; }

/* Eine Spalte mit Datumsangaben ist eine Zahlenspalte, auch wenn sie
   linksbündig steht: "01.09." und "11.09." sind nur untereinander
   vergleichbar, wenn die Ziffern gleich breit sind. */
.zelle--ziffern { font-variant-numeric:tabular-nums; }
.tabelle--ziffern td { font-variant-numeric:tabular-nums; }

/* Die Restzeit bricht nicht um: "3 Tage" und "12 Tage" gehören in eine
   Zeile, sonst springt die Zeilenhöhe der ganzen Liste. */
.restzeit { white-space:nowrap; }
/* Der Normbezug in der Zeile ist eine Nebenangabe und steht darunter. */
.zeilennorm { display:block; }

/* Die Ecken. Ohne diese vier Regeln steht der Kopfstreifen über den Radius
   hinaus - `overflow:hidden` ist auf einem Tabellenkasten nicht verlässlich. */
thead tr:first-child th:first-child { border-top-left-radius:var(--radius-sm); }
thead tr:first-child th:last-child  { border-top-right-radius:var(--radius-sm); }
tbody tr:last-child td:first-child  { border-bottom-left-radius:var(--radius-sm); }
tbody tr:last-child td:last-child   { border-bottom-right-radius:var(--radius-sm); }
tbody tr:last-child td { border-bottom:0; }

/* Eine Tabelle in einer Zelle ist eine Aufzählung, kein zweites Blatt. */
td table, .kachel table { background:none; border:0; box-shadow:none; }

/* `.datenliste` ist die gewöhnliche Arbeitstabelle dieser Anwendung - sie
   steht in fünfzehn Masken und trägt nur, was sie von einer beliebigen
   Tabelle unterscheidet: ihren Abstand nach unten. Alles andere kommt aus
   den Grundregeln oben. */
.datenliste { margin:0 0 var(--raum-4); }
.datenliste--schmal { max-width:var(--breite-masse); }


/* --------------------------------------------------------------------------
   Der Rollbehälter

   Er stand seit AP-E31 in den Vorlagenkommentaren und wurde bei AP-H15
   geschrieben - mit `overflow-x:auto` und sonst nichts. Damit rollte die
   Tabelle zwar waagrecht, senkrecht aber rollte die SEITE: Der haftende
   Kopf klebte am Fensterrand, während die Blätterung unter der Tabelle
   außer Sicht geriet.

   Ein Behälter mit Deckel löst beides. `overscroll-behavior:contain`
   gehört dazu: Ohne die Angabe rollt die Seite weiter, sobald die Tabelle
   unten angekommen ist, und der Blick springt aus der Liste heraus.
   -------------------------------------------------------------------------- */
.tabellenrolle {
    /* Der Kopf haftet jetzt IM Behälter, also bei null.
       (AP-H17: `top:4rem` schob ihn dort vier Zentimeter nach UNTEN, mitten
       in die erste Zeile - und zwar ohne dass irgendetwas gerollt war.) */
    --tabelle-kopf-oben:0;

    overflow:auto;
    /* Ohne dvh-Unterstützung greift die erste Angabe; ohne beide bleibt der
       Behälter ungedeckelt und verhält sich wie vor dieser Fassung. */
    max-height:calc(100vh - var(--kopfleiste-hoehe) - var(--raum-8));
    max-height:var(--tabelle-rolle-hoehe);
    overscroll-behavior:contain;
    /* Der Rollbalken nimmt Platz, sobald er erscheint. `stable` hält ihn
       frei, damit die Spalten beim Filtern nicht um seine Breite springen. */
    scrollbar-gutter:stable;

    /* Das Blatt liegt am Behälter, nicht an der Tabelle - siehe oben. */
    margin:0 0 var(--raum-4);
    background:var(--flaeche);
    border-radius:var(--radius-sm);
    box-shadow:0 0 0 1px var(--rand-weich), var(--schatten-sm);
}
.tabellenrolle > table {
    table-layout:fixed;
    margin:0; border-radius:0; box-shadow:none;
}

/* Eine Liste, die kürzer ist als ihr Deckel, soll keinen Deckel haben:
   Für die Nebentabellen im Cockpit und in der Mandantenakte ist ein zweiter
   Rollbereich auf einer ohnehin rollenden Seite eine Zumutung. */
.tabellenrolle--frei { max-height:none; overscroll-behavior:auto; }

/* Ein fokussierbarer Bereich muss zeigen, dass er den Fokus hat. Der Umriss
   liegt INNEN (`outline-offset` negativ), weil ein äußerer Umriss an einem
   Element mit `overflow:auto` an der Nachbarspalte abgeschnitten wird. */
.tabellenrolle:focus-visible { outline:2px solid var(--akzent); outline-offset:-2px; }


/* --------------------------------------------------------------------------
   Der Kopf bleibt stehen

   In 2.343 Zeilen kam `position:sticky` genau einmal vor - auf der
   Kopfleiste. Die Fristenliste, das AV-Register und die Löschklassen tragen
   14 bis 21 Spalten und beliebig viele Zeilen; wer dort nach unten rollt,
   liest Werte ohne Spaltennamen.

   Wo der Kopf haftet, entscheidet jetzt EINE Eigenschaft statt zweier
   Regeln: `--tabelle-kopf-oben`. Außerhalb eines Rollbehälters ist das die
   Höhe der Seitenkopfleiste, im Behälter null - und wer eine dritte Lage
   braucht (ein Dialog mit eigener Kopfzeile), setzt die Eigenschaft und
   schreibt keine vierte Regel.

   Kein `prefers-reduced-motion`-Gegenstück: Ein feststehender Tabellenkopf
   ist keine Bewegung, sondern eine Position. Ihn dort abzuschalten nähme
   genau den Lesern die Orientierung, die sie am ehesten brauchen.
   -------------------------------------------------------------------------- */
thead th {
    position:sticky; top:var(--tabelle-kopf-oben); z-index:var(--ebene-haftend);
    /* Ohne eigene Fläche scheinen die Zeilen darunter durch. Die Linie
       kommt als `inset`-Schatten und nicht als `border`, weil ein Rahmen an
       einer haftenden Zelle beim Rollen mitwandert und dabei flimmert. */
    background:var(--flaeche);
    box-shadow:inset 0 -1px 0 var(--rand);
}

/* Die erste Spalte der Matrix steht schon waagrecht fest; an der Kreuzung
   müssen beide gelten, sonst überdeckt eine die andere. */
.matrix thead th:first-child { left:0; z-index:calc(var(--ebene-haftend) + 1); }


/* --------------------------------------------------------------------------
   Der sortierbare Spaltenkopf

   `templates/_bausteine/liste.html.twig` steht seit AP-H04 fertig im Baum.
   Ein sortierbarer Spaltenkopf, der aussieht wie ein Spaltenkopf, wird nicht
   angeklickt - deshalb trägt der Verweis darin die ganze Zelle und ihre
   Polsterung.
   -------------------------------------------------------------------------- */

/* Der Kopf bleibt ein Kopf; das Bedienelement darin trägt die Polsterung.
   Anders stünde der Text des sortierbaren Kopfes um die Polsterung versetzt
   neben dem des unsortierbaren. */
th.sortierbar { padding:0; }

/* >> DER SPALTENKOPF IST MAL EIN <a>, MAL EIN <button> (AP-H28).

   Wo die Liste im Rumpf sucht, schickt der Kopf das Formular ab statt eine
   Adresse zu bauen - sonst ginge der Suchbegriff bei jedem Sortierklick
   verloren (CLAUDE.md § 10). Ein <button> erbt aber `background:var(--akzent)`
   aus der allgemeinen Knopfregel: Jeder Sortierkopf einer POST-Liste erschien
   als ausgefüllter Akzentblock mit dunkler Schrift darin.

   Beide Auswahlformen stehen deshalb nebeneinander, und die Regel nennt
   AUSDRÜCKLICH, was sie sonst erben würde. */
.spaltensortierung {
    display:flex; align-items:center; gap:var(--raum-2);
    width:100%; min-height:var(--hoehe-1);
    padding:var(--tabelle-polster) var(--tabelle-polster-quer);
    color:inherit; font:inherit;
    letter-spacing:inherit; text-transform:inherit;
    text-align:left; text-decoration:none;
    background:none; border:0; border-radius:var(--radius-xs);
    cursor:pointer;
    transition:background-color var(--dauer-schnell) var(--stufe);
}

/* >> DER SELEKTOR HEISST NICHT MEHR `button.spaltensortierung`, UND DAS IST
      KEINE VERSCHLANKUNG.

   Die Doppelung war eine Falle: `button.spaltensortierung` trägt (0,1,1) und
   schlug damit `.spaltensortierung--aktiv` (0,1,0). Der aktive Sortierkopf
   einer POST-Liste bekam sein `font-weight` aus dem `font:inherit` der
   Grundregel zurück und stand ungefettet neben acht anderen - die Liste
   sagte nicht mehr, wonach sie sortiert ist.

   Nötig war die Doppelung nie: Die allgemeine Knopfregel ist ein
   Elementselektor (0,0,1), und jede Klasse schlägt sie. Was AP-H28
   tatsächlich gebraucht hat, war nicht der Selektor, sondern die
   Deklaration - deshalb NENNT die Klasse Hintergrund, Rahmen und Schrift
   ausdrücklich, statt sie zu erben. */
.spaltensortierung:hover {
    background:var(--flaeche-2); color:var(--tinte);
    /* `button:hover` legt einen Schlagschatten auf. An einer Kopfzelle sieht
       das aus, als löste sich die Spalte von der Tabelle. */
    box-shadow:none;
}

/* Innen, aus demselben Grund wie beim Rollbehälter: Ein äußerer Umriss an
   einer haftenden Kopfzelle wird von der Nachbarspalte beschnitten. */
.spaltensortierung:focus-visible { outline:2px solid var(--akzent); outline-offset:-2px; }

.spaltensortierung--aktiv { color:var(--tinte); font-weight:var(--fett-voll); }

/* >> DAS ZEICHEN IST EINE FORM AUS RÄNDERN UND KEINE GLYPHE.

   Die Pfeile liegen außerhalb der beiden Inter-Teilmengen unter
   assets/vendor/inter/, und der Browser holte sie sich sonst aus einer
   beliebigen Ersatzschrift - in einer Zeile aus neun Köpfen sind das neun
   Zeichen in einer fremden Schrift.

   Drei Zustände, drei erkennbare Formen: unsortiert zeigt BEIDE Richtungen
   leise an (das ist das Angebot), sortiert zeigt EINE kräftig (das ist die
   Aussage). Vorher war unsortiert dasselbe Dreieck wie "absteigend", nur
   blasser - der Unterschied zwischen "kann man sortieren" und "ist absteigend
   sortiert" hing damit allein an einer Deckkraft.

   Die Maße stehen in `em` und nicht in der Raumleiter: Das Zeichen ist Teil
   der Schrift des Kopfes und muss mit ihr wachsen, nicht mit dem Raster. */
.spaltensortierung__zeichen {
    flex:0 0 auto; position:relative;
    width:.62em; height:1em;
}
/* Die beiden Formen selbst. Sie tragen hier nur die Waagrechte; welche von
   ihnen sichtbar wird und in welcher Farbe, entscheidet die Zustandsklasse -
   so hat jede der drei Klassen eine eigene Aussage und keine davon ist bloß
   eine gedimmte Fassung einer anderen. */
.spaltensortierung__zeichen::before,
.spaltensortierung__zeichen::after {
    content:""; position:absolute; left:0;
    border-left:.31em solid transparent;
    border-right:.31em solid transparent;
}

/* Unsortiert: BEIDE Richtungen, leise. Sichtbar genug, um als Angebot
   erkannt zu werden, leise genug, um in einer Zeile aus neun Köpfen nicht
   zu flimmern. --rand-stark hält gegen --flaeche 3,28:1 und damit die
   Schwelle für die Kennzeichnung eines Bedienelements (WCAG 1.4.11). */
.zeichen--offen::before { top:.04em;    border-bottom:.34em solid var(--rand-stark); }
.zeichen--offen::after  { bottom:.04em; border-top:.34em solid var(--rand-stark); }

/* Sortiert: EINE Richtung, mittig, in der Akzentfarbe (7,1:1 auf --flaeche).
   Die Gegenrichtung fällt ganz weg - sie stünde sonst als zweites Zeichen
   neben dem, das die Aussage trägt. */
.zeichen--auf::before,
.zeichen--ab::after { top:50%; transform:translateY(-50%); }
.zeichen--auf::before { border-bottom:.34em solid var(--akzent); }
.zeichen--ab::after   { border-top:.34em solid var(--akzent); }
.zeichen--auf::after,
.zeichen--ab::before  { display:none; }


/* --------------------------------------------------------------------------
   Zeilenhandlungen

   Eine Spalte ganz rechts. Sie erscheint beim Überfahren, weil vier Knöpfe
   mal sechzig Zeilen eine Liste in ein Schaltpult verwandeln - und sie ist
   per Tastatur IMMER erreichbar, weil sie sonst für jeden, der nicht mit der
   Maus arbeitet, gar nicht existierte.

   >> DESHALB `opacity` UND NICHT `display:none` ODER `visibility:hidden`.

   Beide nähmen das Element aus der Tabulatorfolge und aus dem Lesegerät.
   Mit `opacity:0` bleibt es fokussierbar; `:focus-within` an der Zeile holt
   es hervor, sobald jemand hineintabbt.

   Die Verdeckung gilt nur, wo es einen Zeiger gibt, der schweben kann. Auf
   einem Berührbildschirm gibt es kein "Überfahren" - dort stünden die
   Knöpfe unsichtbar und unerreichbar in der Zeile.
   -------------------------------------------------------------------------- */
th.zeilenhandlungen, td.zeilenhandlungen {
    text-align:right; white-space:nowrap; vertical-align:middle;
}
.zeilenhandlung {
    display:inline-flex; align-items:center; justify-content:flex-end;
    gap:var(--raum-2);
}

@media (hover:hover) and (pointer:fine) {
    .zeilenhandlung {
        opacity:0;
        transition:opacity var(--dauer-schnell) var(--stufe);
    }
    tbody tr:hover .zeilenhandlung,
    tbody tr:focus-within .zeilenhandlung,
    /* Eine gewählte Zeile zeigt, was mit ihr geschehen kann. */
    tbody tr.zeile--gewaehlt .zeilenhandlung { opacity:1; }
}

@media (prefers-reduced-motion: reduce) {
    .zeilenhandlung, .spaltensortierung { transition:none; }
}


/* --------------------------------------------------------------------------
   Zeilenzustände

   Vier Färbungen lagen bis hierher als vier Regelpaare im Blatt
   (`tr.ueberfaellig`, `tr.zeile--offen`, `tr.zustand-bestaetigt`,
   `tr.zustand-begonnen`), jede mit eigenem `color-mix`. Sie sind auf zwei
   Eigenschaften zusammengezogen: die Fläche und die Marke am linken Rand.
   Wer einen fünften Zustand braucht, setzt zwei Werte und schreibt keine
   zwei Regeln.

   >> FARBE TRÄGT HIER NIE ALLEIN DIE AUSSAGE (WCAG 1.4.1).

   Die Marke am linken Rand ist die Zugabe für den Blick über die ganze
   Liste; das WORT liefert die Vorlage - "N Tage überschritten",
   "erledigt", "bestätigt". Eine Zeile, die nur gefärbt ist, ist für
   farbenblinde Leser eine Zeile.

   Die Marke steht als `inset`-Schatten und nicht als `border-left`: Ein
   Rahmen verschöbe den Text der ersten Zelle um drei Pixel, und die Spalte
   stände bei gefärbten und ungefärbten Zeilen verschieden weit innen.
   -------------------------------------------------------------------------- */
tbody td:first-child {
    box-shadow:inset 3px 0 0 var(--zeile-marke, transparent);
    font-weight:var(--zeile-erst-gewicht, inherit);
}

/* Überfällig - die Frist ist abgelaufen. `.ueberfaellig` und
   `.zeile--offen` sind die beiden Namen, unter denen dieser Zustand in
   fünfzehn Vorlagen bereits steht; `.zeile--ueberfaellig` ist der Name, den
   eine neue Vorlage nimmt. Alle drei meinen dasselbe und sehen deshalb
   gleich aus. */
tr.zeile--ueberfaellig,
tr.ueberfaellig,
tr.zeile--offen {
    --zeile-flaeche:var(--warn-weich, color-mix(in srgb, var(--warn) 8%, var(--flaeche)));
    --zeile-marke:var(--warn);
    --zeile-erst-gewicht:var(--fett-stark);
}

/* Gewählt - die Zeile ist Teil der Mehrfachauswahl. Der Zustand steht
   zusätzlich im Kästchen, das gesetzt ist, und in der Zahl der
   Sammelleiste; die Färbung sagt nur, WELCHE Zeilen es sind. */
tr.zeile--gewaehlt {
    --zeile-flaeche:var(--akzent-weich);
    --zeile-marke:var(--akzent);
}

/* Gedämpft - erledigt, storniert, außer Kraft. Die Zeile bleibt lesbar:
   `--tinte-2` hält gegen `--flaeche` 6,4:1. Keine Deckkraft und kein
   Ausgrauen - beides senkt den Kontrast unkontrolliert, und was hier steht,
   wird im Streitfall gelesen. */
tr.zeile--gedaempft td,
tr.zeile--erledigt td { color:var(--tinte-2); }
tr.zeile--gedaempft, tr.zeile--erledigt { --zeile-flaeche:var(--flaeche-2); }
/* Ein Verweis bleibt ein Verweis, auch in einer gedämpften Zeile. */
tr.zeile--gedaempft a, tr.zeile--erledigt a { color:var(--akzent); }

/* Erfüllt - der Punkt der Portalcheckliste ist abgehakt. */
tr.zeile--ok {
    --zeile-flaeche:var(--gut-weich, color-mix(in srgb, var(--gut) 8%, var(--flaeche)));
    --zeile-marke:var(--gut);
}

/* Erfassungsstand der 57 Mandanten. Die letzte Spalte nennt den Zustand als
   Wort; die Färbung ist die Zugabe für den Blick über die ganze Liste.
   "offen" bleibt ungefärbt - es ist der Ausgangszustand und kein Befund.
   Keine Marke am Rand: Ein Erfassungsstand ist kein Befund, der die Zeile
   aus der Liste heraushebt. */
tr.zustand-bestaetigt { --zeile-flaeche:var(--gut-weich, color-mix(in srgb, var(--gut) 8%, var(--flaeche))); }
tr.zustand-begonnen   { --zeile-flaeche:var(--hinweis-weich, color-mix(in srgb, var(--hinweis) 10%, var(--flaeche))); }


/* --------------------------------------------------------------------------
   Mehrfachauswahl und Sammelleiste

   >> NICHT ÜBERALL, UND DAS IST EINE FACHLICHE UND KEINE GESTALTERISCHE
      ENTSCHEIDUNG.

   Die TOM-Liste bekommt sie nicht. Dort trägt jede Maßnahme ein eigenes
   Formular (AP-H12), weil der Endpunkt je Maßnahme arbeitet und weil ein
   Sammelhaken über vierzig Maßnahmen kein Prüfvermerk wäre, sondern ein
   Klick. Dieselbe Überlegung steht in `_kontrollmassnahmen.html.twig` und
   bei der Sammelübernahme (ADR 0038). Die Klassen hier stehen bereit; wo
   sie NICHT hingehören, entscheidet die Vorlage.

   Die Leiste erscheint erst, wenn etwas gewählt ist. Eine leere
   Sammelleiste ist ein Balken, der Platz nimmt und nichts sagt.
   -------------------------------------------------------------------------- */

/* Die Auswahlspalte ist so schmal wie ihr Inhalt. --raum-7 statt einer
   Prozentangabe, weil `table-layout:fixed` im Rollbehälter Prozente wörtlich
   nimmt und die Spalte damit an der Tabellenbreite hängen würde. */
th.auswahlzelle, td.auswahlzelle {
    width:var(--raum-7);
    padding-right:var(--raum-0);
    text-align:center; vertical-align:middle;
}
.auswahlkaestchen {
    width:var(--raum-4); height:var(--raum-4);
    margin:0; accent-color:var(--akzent); cursor:pointer;
}
/* Die Zelle ist das Ziel, nicht das Kästchen: 16px sind ein zu kleines
   Ziel (WCAG 2.5.8 nennt 24px). Das Label spannt die ganze Zelle auf. */
.auswahlzelle label {
    display:flex; align-items:center; justify-content:center;
    min-height:var(--hoehe-1); margin:0; cursor:pointer;
}

/* >> DIE LEISTE SCHALTET SICH SELBST EIN.

   `:has()` liest den Zustand der Kästchen; es braucht dafür kein
   JavaScript und keinen Ereignisknoten. Wo `:has()` fehlt, setzt der
   Stimulus-Controller `.sammelleiste--offen` - deshalb steht beides hier
   und nicht nur eines. */
.sammelleiste { display:none; }
.auswahlbereich:has(.auswahlkaestchen:checked) > .sammelleiste,
.sammelleiste--offen {
    display:flex; flex-wrap:wrap; align-items:center; gap:var(--raum-3);

    /* Sie haftet am unteren Rand des Auswahlbereichs: Wer in einer langen
       Liste unten etwas anhakt, soll nicht nach oben rollen müssen, um zu
       sehen, was er damit tun kann. */
    position:sticky; bottom:var(--raum-0); z-index:var(--ebene-haftend);

    margin:var(--raum-3) 0 0;
    padding:var(--raum-3) var(--raum-4);
    color:var(--tinte);
    background:var(--flaeche);
    border:1px solid var(--rand-stark);
    border-radius:var(--radius-md);
    box-shadow:var(--schatten-md);
    font-size:var(--schrift-sm);
}
.sammelleiste__zahl {
    margin:0; font-weight:var(--fett-stark);
    font-variant-numeric:tabular-nums;
}
/* Die Handlungen stehen rechts, damit die Zahl links den Anfang der Leiste
   hält, auch wenn die Zahl von "1" auf "12" wächst. */
.sammelleiste__handlungen {
    display:flex; flex-wrap:wrap; align-items:center; gap:var(--raum-2);
    margin-left:auto;
}


/* --------------------------------------------------------------------------
   Die Trefferzeile

   Sie steht über der Tabelle und beantwortet die häufigste stumme Frage vor
   einer Liste: Sind das alle? Ohne sie heißt "sechs Zeilen" entweder "es
   gibt sechs" oder "ein Filter greift" oder "die Abfrage deckelt" - und man
   sieht der Liste nicht an, welches davon.
   -------------------------------------------------------------------------- */
.trefferzeile {
    margin:0 0 var(--raum-2);
    color:var(--tinte-2);
    font-size:var(--schrift-sm);
    font-variant-numeric:tabular-nums;
}


/* --------------------------------------------------------------------------
   Die Blätterung

   >> SIE IST MAL EINE REIHE VON <a>, MAL EINE REIHE VON <button> (AP-H28).

   Derselbe Grund wie beim Spaltenkopf: Wer auf Seite 2 blättert und dabei
   den Suchbegriff verliert, sieht Seite 2 von etwas anderem. Deshalb gibt es
   `blaetterknoepfe()` neben `blaetterung()`.

   Und dieselbe Falle: Die bisherige Fassung nannte `.blaetterung__seiten a`
   und nicht `.blaetterung__seiten button`. In jeder Liste, die im Rumpf
   sucht, standen die Seitenzahlen damit als ausgefüllte Akzentblöcke
   nebeneinander - dieselbe Optik wie die laufende Seite, nur alle davon.

   Die Ziele sind mindestens --hoehe-2 hoch und breit: 36px, und damit über
   den 24px, die WCAG 2.5.8 für ein Klickziel nennt.
   -------------------------------------------------------------------------- */
.blaetterung {
    display:flex; flex-wrap:wrap; align-items:center; gap:var(--raum-2);
    margin:var(--raum-4) 0 0;
    font-size:var(--schrift-sm);
}
.blaetterung__seiten {
    display:flex; flex-wrap:wrap; align-items:center; gap:var(--raum-1);
    list-style:none; margin:0; padding:0;
}

.blaetterung__schritt,
.blaetterung__seiten a,
.blaetterung__seiten button,
.blaetterung__laufend {
    display:inline-flex; align-items:center; justify-content:center;
    min-height:var(--hoehe-2); min-width:var(--hoehe-2);
    padding:var(--raum-0) var(--raum-3);
    color:var(--tinte); background:var(--flaeche);
    border:1px solid var(--rand-stark); border-radius:var(--radius-xs);
    font:inherit; font-variant-numeric:tabular-nums;
    text-decoration:none; cursor:pointer;
    transition:background-color var(--dauer-schnell) var(--stufe),
               border-color var(--dauer-schnell) var(--stufe);
}
.blaetterung__schritt:hover,
.blaetterung__seiten a:hover,
.blaetterung__seiten button:hover {
    background:var(--akzent-weich); border-color:var(--akzent);
    /* Wie beim Sortierkopf: `button:hover` bringt einen Schlagschatten mit,
       den ein Blätterknopf neben einem Blätterverweis nicht haben darf -
       sonst sehen die beiden Fassungen desselben Bausteins verschieden aus. */
    box-shadow:none;
}

/* Kein Verweis, sondern die laufende Seite. Sie ist kein Ziel - deshalb
   Fläche statt Kante und kein Zeiger.

   `--flaeche` und nicht `#fff`: Ein festes Weiß unterhalb von :root bricht
   den Dunkelmodus. Dort ist --akzent ein helles Blau, und weiße Schrift
   darauf hält 1,6:1. Mit --flaeche kippt die Schrift mit der Fläche mit
   und hält in beiden Modi über 7:1. */
.blaetterung__laufend {
    color:var(--flaeche); background:var(--akzent); border-color:var(--akzent);
    font-weight:var(--fett-stark); cursor:default;
}

/* "Zurück" auf Seite 1 bleibt stehen und wird nicht entfernt: Eine Leiste,
   die ihre Breite ändert, springt beim Blättern unter dem Zeiger weg.
   Der `disabled`-Fall der Knopffassung sieht gleich aus - er ist derselbe
   Sachverhalt in anderem Markup. */
.blaetterung__schritt--aus,
.blaetterung__schritt:disabled,
.blaetterung__seiten button:disabled {
    color:var(--tinte-3); background:var(--flaeche-2);
    border-color:var(--rand); cursor:default;
}
.blaetterung__schritt--aus:hover,
.blaetterung__schritt:disabled:hover,
.blaetterung__seiten button:disabled:hover {
    background:var(--flaeche-2); border-color:var(--rand);
}

.blaetterung__luecke {
    display:inline-flex; align-items:center;
    min-height:var(--hoehe-2); padding:var(--raum-0) var(--raum-1);
    color:var(--tinte-3);
}

@media (prefers-reduced-motion: reduce) {
    .blaetterung__schritt,
    .blaetterung__seiten a, .blaetterung__seiten button { transition:none; }
}


/* --------------------------------------------------------------------------
   Die zwei Leerfälle

   Sie dürfen nicht gleich aussehen: "nichts zu tun" ist eine Aussage über
   die SACHE, "diese Auswahl ist leer" eine über den FILTER. Wer beides
   gleich färbt, meldet dem Berater Ruhe, wo er nur einen Filter falsch
   gesetzt hat.

   Der eine hat keinen Weg - es gibt nichts zu tun, und ein Verweis wäre
   eine Einladung, sich Arbeit zu suchen. Der andere hat genau einen: Eine
   leere Liste ohne Angebot ist eine Sackgasse.
   -------------------------------------------------------------------------- */
.leerfall {
    position:relative;
    margin:0 0 var(--raum-5);
    padding:var(--raum-4) var(--raum-5);
    max-width:var(--breite-text);
    color:var(--tinte);
    background:var(--flaeche-2);
    border:1px solid var(--rand);
    border-radius:var(--radius-md);
    line-height:var(--zeile-normal);
}

/* "Nichts zu tun". Der Haken ist eine CSS-Form und keine Glyphe - aus
   demselben Grund wie das Sortierzeichen: Ein Haken liegt außerhalb der
   beiden Inter-Teilmengen. Er ist ZUGABE; die Aussage steht als Satz daneben
   (WCAG 1.4.1).

   Absolut gesetzt und nicht als Flex-Kind: Der Absatz enthält einen
   Textknoten und möglicherweise einen Verweis - in einem Flex- oder
   Rastercontainer würden daraus zwei Kästen nebeneinander statt eines
   Satzes. */
.leerfall--erledigt {
    padding-left:var(--raum-8);
    background:var(--gut-weich, color-mix(in srgb, var(--gut) 8%, var(--flaeche)));
    border-color:var(--gut-rand, var(--gut));
}
.leerfall--erledigt::before {
    content:""; position:absolute;
    left:var(--raum-5); top:calc(var(--raum-4) + .28em);
    width:.34em; height:.66em;
    border-right:2px solid var(--gut); border-bottom:2px solid var(--gut);
    transform:rotate(45deg);
}

/* "Diese Auswahl ist leer". Neutral - und der Rückweg ist der wichtigere
   Teil, deshalb steht er als Ziel da und nicht als Wort im Satz. */
.leerfall--offen a {
    display:inline-flex; align-items:center;
    min-height:var(--hoehe-2); margin-left:var(--raum-2);
    padding:var(--raum-0) var(--raum-3);
    color:var(--akzent); background:var(--flaeche);
    border:1px solid var(--rand-stark); border-radius:var(--radius-xs);
    font-weight:var(--fett-halb); text-decoration:none;
}
.leerfall--offen a:hover { background:var(--akzent-weich); border-color:var(--akzent); }


/* --------------------------------------------------------------------------
   Die Wertliste - Schlüssel und Wert

   Zwei Spalten, keine Sortierung, keine Zeilenhandlung: Was hier steht, wird
   GELESEN. Eine <table> dafür ist ein Kreuzverweis ohne zweite Achse -
   Lesegeräte kündigen sie als Tabelle an und zählen Spalten, die niemand
   vergleicht. Ein <dl> sagt, was es ist.

   `max-content` in der ersten Spalte und keine feste Breite: Der längste
   Schlüssel bestimmt die Spalte, und "Verantwortlicher" und "Zweck" stehen
   in derselben Flucht, ohne dass jemand eine Prozentzahl raten muss.
   -------------------------------------------------------------------------- */
.wertliste {
    display:grid;
    grid-template-columns:1fr;
    gap:var(--raum-1) var(--raum-5);
    margin:0 0 var(--raum-5);
    max-width:var(--breite-text);
    font-size:var(--schrift-sm);
    line-height:var(--zeile-normal);
}
.wertliste dt {
    color:var(--tinte-2);
    font-weight:var(--fett-halb);
}
.wertliste dd {
    margin:0;
    overflow-wrap:break-word;
}

/* Erst ab dem Bruchpunkt "schmal" (34rem) stehen Schlüssel und Wert
   nebeneinander. Darunter untereinander: Zwei Spalten auf einem 320px
   breiten Gerät ließen dem Wert vier Wörter Platz, und ein Zweck nach
   Art. 30 Abs. 1 lit. b ist länger als vier Wörter.

   34rem steht als Zahl da und nicht als Token: Eine Medienabfrage wertet
   keine Custom Property aus - der Bruchpunkt muss dort wörtlich stehen. */
@media (min-width:34rem) {
    .wertliste { grid-template-columns:minmax(0,max-content) minmax(0,1fr); }
}

/* Mit Trennlinien, wo die Liste lang ist und der Blick eine Führung
   braucht. Die Linie liegt UNTER dem Paar und nicht zwischen Schlüssel und
   Wert - sie trennt Angaben, nicht Spalten. */
.wertliste--getrennt dt,
.wertliste--getrennt dd {
    padding-bottom:var(--raum-2);
    border-bottom:1px solid var(--rand-weich);
}
.wertliste--getrennt > :nth-last-child(-n+2) { border-bottom:0; padding-bottom:0; }

/* Die eingelassene Fassung - für eine Wertliste, die in einer Karte steht
   und sich von deren Fläche absetzen muss. */
.wertliste--eingelassen {
    padding:var(--raum-4);
    background:var(--flaeche-3, var(--flaeche-2));
    border-radius:var(--radius-sm);
}


/* --------------------------------------------------------------------------
   Auf Papier

   Ein feststehender Kopf, ein gedeckelter Rollbehälter und eine Spalte, die
   beim Überfahren erscheint, sind Eigenschaften des Bildschirms. Auf dem
   Ausdruck haben sie kein Gegenstück: Der Rollbehälter schnitte die
   Tabelle nach der ersten Seite ab, und die Zeilenhandlungen druckten sich
   als leere Spalte mit.
   -------------------------------------------------------------------------- */
@media print {
    .tabellenrolle {
        max-height:none; overflow:visible;
        box-shadow:none; border:1px solid var(--rand);
    }
    thead th { position:static; box-shadow:none; border-bottom:1px solid var(--rand); }
    /* Der Kopf wiederholt sich auf jeder Papierseite - sonst stehen ab
       Seite 2 Werte ohne Spaltennamen. */
    thead { display:table-header-group; }
    tbody tr { break-inside:avoid; }
    table { box-shadow:none; }
    .zeilenhandlungen, .auswahlzelle, .sammelleiste, .blaetterung { display:none; }
}

/* ==========================================================================
   KNOEPFE UND HANDLUNGEN
   ========================================================================== */

/* ==========================================================================
   KNÖPFE UND HANDLUNGEN

   Ersetzt: app.css:578 (.huelle button), 708 (.knopf-klein Größe),
   1047-1090 (Grundknopf, .knopf-klein, .knopf-schlicht, .zurueck, .weiter),
   1282-1284 (Bewegungsruhe), 2175-2198 und 2205-2208 (a./button.knopf-klein,
   .haupt, Übergänge), 2546-2560 (.assistent-knopf), 3564-3585
   (.werkzeugleiste, .knopf, .zeilenformular), 3604-3608
   (button.spaltensortierung - entfällt ersatzlos), 3657 (.knopf-klein--aktiv).

   >> DREI FEHLER, DIE HEUTE AUF DEM BILDSCHIRM STEHEN.

   1. `.knopf` setzt `border-radius:var(--rundung)`. Dieses Token gibt es
      nicht. Eine undefinierte Variable macht die ganze Deklaration ungültig,
      und der Knopf fällt auf den Anfangswert 0 zurück: Alle vier
      `.knopf`-Verweise haben rechte Winkel, während jede Karte, jedes Feld
      und jede Marke daneben gerundet ist.
   2. `.knopf:hover` setzt `var(--akzent-dunkel, var(--akzent))`. Auch dieses
      Token gibt es nicht, der Ersatzwert ist die Ausgangsfarbe - das
      Überfahren tut seit AP-H24 nichts.
   3. Alle vier `.knopf` stehen in `<p class="werkzeugleiste">`. Damit greift
      `p a { text-decoration:underline }` aus Zeile 201, und `.knopf` (0,1,0)
      verliert gegen `p a` (0,1,1): ein gefüllter Knopf mit unterstrichener
      Schrift. Die Regeln unten benennen den Träger (`a.knopf`) und gewinnen.

   Beide fehlenden Token stehen jetzt im Wortschatz. Der Unterstrich ist
   ausgeräumt.

   >> WARUM `:where()` UM DIE ELEMENTREGEL.

   199 <button> stehen in den Vorlagen, 28 davon tragen eine Klasse. Die
   Elementregel `button { background:var(--akzent) }` beansprucht deshalb
   alles - und fünf Stellen im Blatt bestehen nur daraus, sie wieder
   abzuräumen: `.knopf-klein` ("muss den Grundknopf oben abschalten"),
   `button.knopf-klein`, `button.spaltensortierung` ("erbt aber
   background:var(--akzent) aus der allgemeinen Knopfregel"), `.filterleiste
   button` ("wären alle Reiter gleichzeitig aktiv") und `.assistent-knopf`.
   Vier davon stehen doppelt im Blatt, weil der Fehler zweimal auftrat.

   `:where()` hat Spezifität null. Die Elementregel bleibt damit die
   Vorgabe - ein Absendeknopf ohne Klasse ist die Handlung seines Formulars
   und soll wie eine aussehen -, aber JEDE Klasse gewinnt gegen sie, ohne
   etwas abschalten zu müssen. Die Abräumregeln entfallen; die Ursache
   ist weg, nicht das Symptom.

   `:where()` ist älter als das `color-mix()`, das dieses Blatt bereits
   benutzt. Es kostet keine Verträglichkeit.

   >> WARUM GENAU EIN GEFÜLLTER KNOPF JE MASKE.

   Ein gefüllter Knopf ist kein Schmuck, sondern eine Antwort auf die Frage
   "und was mache ich hier jetzt". Die Füllung ist der einzige Reiz auf der
   Maske, den das Auge vor dem Lesen findet - sie wirkt nur, solange sie
   einmal vorkommt. Zwei gefüllte Knöpfe beantworten die Frage nicht mehr,
   sie stellen sie erneut; acht beantworten sie gar nicht.

   Die Verzeichnismaske ist der Beleg für den umgekehrten Fehler: Acht
   gleichrangige Textverweise, mit Mittelpunkt getrennt, in einer Zeile.
   "Freigeben" - unumkehrbar, mit Hashkette und Grabstein - sieht darin aus
   wie "Karteikarte als PDF". Wo alles gleich aussieht, ist nichts
   hervorgehoben; das ist derselbe Verlust wie bei acht gefüllten Knöpfen,
   nur von der anderen Seite.

   Und es ist gezählt, kein Gefühl: 54 Vorlagen tragen genau einen
   Absendeknopf, 42 tragen zwei bis neun. Die Regel beschreibt also die
   Mehrheit und benennt die Ausnahmen - sie erfindet nichts.

   Deshalb vier Ausprägungen und nicht mehr:
     .knopf--haupt        gefüllt    - die eine Handlung. EINE je Maske.
     .knopf--umriss       umrandet   - jede Nebenhandlung.
     .knopf--leise        nur Text   - Abbrechen, Zurück, Umschalten.
     .knopf--folgenreich  Warnkante  - was man nicht zurücknehmen kann.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Die Grundform

   Eine Höhe für alles, was in einer Maske steht: --hoehe-2. Sieben freie
   Bedienhöhen standen vorher im Blatt (.45rem, .5rem, .6rem, .7rem, .25rem
   Innenabstand in wechselnden Kombinationen); keine davon war eine
   Entscheidung, jede war eine Gelegenheit.

   `min-height` und nicht `height`: Eine lange deutsche Beschriftung
   ("Wirksamkeitsprüfungen") darf umbrechen, statt aus dem Knopf zu laufen.
   --zeile-eng hält den Umbruch dann kompakt.

   Die Schriftgröße ist --schrift-sm und bleibt es auch im kleinen Knopf.
   Der Unterschied zwischen einem Knopf in der Tabellenzelle und einem in der
   Werkzeugleiste ist seine Trefferfläche (WCAG 2.5.8), nicht seine
   Schriftgröße - das meistgeklickte Bedienelement der Anwendung darf nicht
   das am schlechtesten lesbare sein. .82rem, wie es .knopf-klein bisher
   trug, liegt unter dem Arbeitswert dieses Blattes.
   -------------------------------------------------------------------------- */
.knopf,
.knopf-klein,
:where(button, input[type="submit"]) {
    display:inline-flex; align-items:center; justify-content:center;
    gap:var(--raum-2);
    min-height:var(--hoehe-2);
    padding:var(--raum-1) var(--raum-4);
    font:inherit; font-size:var(--schrift-sm); font-weight:var(--fett-halb);
    line-height:var(--zeile-eng);
    text-align:center; text-decoration:none;
    cursor:pointer;
    border:1px solid transparent; border-radius:var(--radius-sm);
    /* Ein Radius für die ganze Familie. Zwei Radien ließen einen kleinen
       Knopf neben einem großen wie ein anderes Bauteil aussehen. */
    transition:background-color var(--dauer-schnell) var(--stufe),
               border-color     var(--dauer-schnell) var(--stufe),
               color            var(--dauer-schnell) var(--stufe),
               box-shadow       var(--dauer-normal)  var(--stufe);
}

/* Der Unterstrich aus `p a`/`li a` (Zeile 201) trifft jeden Knopf, der in
   einem Absatz oder einer Liste steht - und alle vier heutigen `.knopf`
   stehen in `<p class="werkzeugleiste">`. Der Träger im Selektor hebt die
   Spezifität auf 0,1,1 und damit auf dieselbe Stufe; die spätere Regel
   gewinnt. Ohne diese Zeile bleibt der gefüllte Knopf unterstrichen. */
a.knopf, a.knopf-klein,
a.knopf:hover, a.knopf-klein:hover { text-decoration:none; }

/* --------------------------------------------------------------------------
   Ausprägung 1: die eine Handlung (gefüllt)

   --flaeche als Schriftfarbe und nicht ein festes Weiß - die Begründung ist
   die alte und gilt unverändert: Im Dunkelmodus kippt --akzent nach hell,
   die Schrift muss dann dunkel werden. Ein festes #fff bliebe hell auf hell
   stehen. (Genau dieser Fehler steht heute in .knopf-klein--aktiv, Zeile
   3657, und wird weiter unten ausgeräumt.)

   Ein <button> ohne Klasse bekommt dieselbe Füllung: Er ist der
   Absendeknopf seines Formulars, und in 54 der 96 Vorlagen mit Absendeknopf
   ist er der einzige. Wo er es nicht ist, trägt die Vorlage die Klasse -
   siehe die Liste der Vorlagenänderungen.
   -------------------------------------------------------------------------- */
/* >> DIE REIHENFOLGE DIESER BLÖCKE IST TRAGEND.

   `.knopf` ist die gefüllte Form, weil vier Vorlagen `class="knopf"` ohne
   Ausprägung schreiben und einen gefüllten Knopf erwarten. Alle vier
   Ausprägungen haben dieselbe Spezifität (0,1,0) wie `.knopf` selbst - sie
   gewinnen ausschließlich dadurch, dass sie SPÄTER stehen. Wer die Blöcke
   umsortiert, macht aus jedem `.knopf knopf--leise` wieder einen gefüllten
   Knopf. */
.knopf,
.knopf--haupt,
:where(button, input[type="submit"]) {
    color:var(--flaeche);
    background:var(--akzent);
    border-color:var(--akzent);
    font-weight:var(--fett-stark);
}
.knopf:hover,
.knopf--haupt:hover,
:where(button, input[type="submit"]):hover {
    background:var(--akzent-dunkel);
    border-color:var(--akzent-dunkel);
    box-shadow:var(--schatten-sm);
}
/* Beim Drücken fällt der Schatten weg. Der Knopf geht in die Fläche
   hinein, statt darüber zu schweben - das ist die einzige Rückmeldung, die
   ein Zeigegerät ohne Verzögerung liefert. */
.knopf:active,
.knopf--haupt:active,
:where(button, input[type="submit"]):active {
    background:var(--akzent-dunkel);
    box-shadow:none;
    transform:translateY(1px);
}

/* --------------------------------------------------------------------------
   Ausprägung 2: die Nebenhandlung (umrandet)

   --rand-stark und nicht --rand. Das ist eine Korrektur, keine Vorliebe:
   --rand (#dce2ea) erreicht auf Weiß 1,3:1. WCAG 1.4.11 verlangt für die
   Umrandung eines Bedienelements 3:1, und genau dafür wurde --rand-stark
   angelegt (3,28:1, siehe Wertevorrat). `.knopf-klein` trug bis hierher
   --rand - 48 Vorlagen benutzen die Klasse, und ihre Kante war auf keinem
   Bildschirm sicher zu sehen.
   -------------------------------------------------------------------------- */
.knopf-klein,
.knopf--umriss {
    color:var(--akzent);
    background:var(--flaeche);
    border-color:var(--rand-stark);
    font-weight:var(--fett-halb);
}
.knopf-klein:hover,
.knopf--umriss:hover {
    background:var(--akzent-weich);
    border-color:var(--akzent);
    color:var(--akzent);
}
.knopf-klein:active,
.knopf--umriss:active { transform:translateY(1px); }

/* --------------------------------------------------------------------------
   Ausprägung 3: leise (nur Text)

   Abbrechen, Zurück, ein Umschalter. Sie hat keine Kante, und das ist
   erlaubt: WCAG 1.4.11 gilt für Bedienelemente, die ihre Grenze brauchen,
   um erkannt zu werden. Diese hier wird an ihrer Schrift erkannt, und die
   trägt --akzent mit 7,10:1 - deutlich über den 4,5:1 für Fließtext.

   Die Überfahrfläche ist --flaeche-3 und nicht --flaeche-2: Auf einer
   weißen Karte ist --flaeche-2 kaum ein Unterschied, und ein Überfahren,
   das man nicht sieht, ist keins.
   -------------------------------------------------------------------------- */
.knopf--leise {
    color:var(--akzent);
    background:none;
    border-color:transparent;
    font-weight:var(--fett-halb);
}
.knopf--leise:hover {
    background:var(--flaeche-3);
    border-color:var(--rand-weich);
    color:var(--akzent);
}
.knopf--leise:active { transform:translateY(1px); }

/* --------------------------------------------------------------------------
   Ausprägung 4: folgenreich

   Freigeben, Löschen, Akte schließen, Endgültig löschen, Widerrufen,
   Verwerfen - elf Knöpfe in den Vorlagen, die etwas tun, was niemand
   zurücknimmt. Eine Freigabe erzeugt einen Wurzelhash und einen Grabstein;
   ein geschlossener Vorfall ist geschlossen.

   >> WARUM KANTE UND SCHRIFT UND NICHT DIE FLÄCHE.

   Zwei Gründe, und der zweite ist der stärkere:

   Erstens der Dunkelmodus. --warn ist dort #f08a80, ein heller Lachston. Eine
   ganze Fläche davon leuchtet auf #10161b wie eine Fehlermeldung - der Knopf
   schriee, bevor jemand ihn gelesen hat, und ein Bildschirm, auf dem etwas
   dauernd schreit, wird nicht vorsichtiger bedient, sondern taub.

   Zweitens trägt die Farbe die Aussage ohnehin nicht. Das tut das Wort
   "Löschen". WCAG 1.4.1 verlangt genau das, und wenn das Wort die Aussage
   trägt, muss die Fläche sie nicht wiederholen - sie darf sich darauf
   beschränken, den Knopf von seinen Nachbarn zu unterscheiden. Dafür
   reichen Kante und Schrift.

   Die gefüllte Fassung bleibt dem Bestätigungsschritt vorbehalten: Wer
   "Endgültig löschen" in einem aufgeklappten <details> anklickt, hat die
   Frage schon gelesen. Dort ist Füllung Antwort und nicht Alarm.
   -------------------------------------------------------------------------- */
/* >> `.knopf-gefahr` HATTE KEINE EINZIGE REGEL.

   Zwei Stellen in templates/backoffice/tom/liste.html.twig tragen sie - ein
   <summary> "löschen" und ein <button> "Endgültig löschen". Im ganzen Blatt
   stand dazu nichts: Beide sahen aus wie jede andere Nebenhandlung, und der
   Knopf, der einen Baustein unwiederbringlich entfernt, war von "Verlauf"
   nicht zu unterscheiden. Der Name bleibt und bekommt endlich seine Regel;
   neue Vorlagen schreiben `.knopf--folgenreich`. */
.knopf--folgenreich,
.knopf-gefahr {
    color:var(--warn);
    background:var(--flaeche);
    border-color:var(--warn-rand);
    font-weight:var(--fett-halb);
}
.knopf--folgenreich:hover,
.knopf-gefahr:hover {
    background:var(--warn-weich);
    border-color:var(--warn);
    color:var(--warn);
}
.knopf--folgenreich:active,
.knopf-gefahr:active { transform:translateY(1px); }

/* Der Bestätigungsschritt: gefüllt, weil hier die Frage schon gestellt
   wurde. Nie als erster Knopf einer Maske. */
.knopf--folgenreich.knopf--haupt {
    color:var(--flaeche);
    background:var(--warn);
    border-color:var(--warn);
    font-weight:var(--fett-stark);
}
/* Es gibt kein --warn-dunkel, und es soll auch keins geben: Die Familie
   braucht die dunklere Warnfarbe an genau dieser einen Stelle. Das
   Aufhellen per color-mix ist die Wendung, die dieses Blatt für den
   Grundknopf bereits benutzt - dieselbe Bewegung, dieselbe Stärke. */
.knopf--folgenreich.knopf--haupt:hover {
    background:color-mix(in srgb, var(--warn) 85%, transparent);
    border-color:var(--warn);
    box-shadow:var(--schatten-sm);
}

/* --------------------------------------------------------------------------
   Größen

   Drei Höhen statt sieben. --hoehe-2 ist der Regelfall und braucht keine
   Klasse.
   -------------------------------------------------------------------------- */

/* In der Tabellenzelle. Die Zeile darf nicht auseinandergehen, nur weil in
   einer Spalte ein Knopf steht - deshalb --hoehe-1 und der schmalere
   Innenabstand. Die Schrift bleibt --schrift-sm (siehe oben).

   `.knopf-klein` steht mit in dieser Regel, und zwar zwingend: Der Name sagt
   "klein", 48 Vorlagen setzen ihn in Tabellenzellen, und die Klasse ist
   damit BEIDES - die Nebenhandlung aus Ausprägung 2 UND diese Größe. Ohne
   diese Zeile wüchse jede Zeile jeder Liste dieser Anwendung um einen
   halben Zentimeter, weil die Grundform --hoehe-2 mitbrächte.

   Neue Vorlagen schreiben die beiden Eigenschaften getrennt hin
   (`knopf knopf--umriss knopf--klein`), damit auch ein kleiner HAUPTknopf
   möglich bleibt. --hoehe-1 sind 28px und liegen über den 24px, die WCAG
   2.5.8 als Mindestziel verlangt. */
.knopf--klein,
.knopf-klein {
    min-height:var(--hoehe-1);
    padding:var(--raum-0) var(--raum-3);
    gap:var(--raum-1);
}

/* Anmelden, Absenden, "Zugang abschließen". --hoehe-3 ist die Höhe, die
   man trifft, ohne hinzusehen, und sie kommt genau einmal je Maske vor.

   `.haupt` steht in derselben Regel, weil es derselbe Knopf ist: "Genau ein
   Absendeknopf je Stammdatenmaske - er darf aussehen wie die Handlung, um
   die es geht" (AP-D09). Diese Begründung von damals ist genau die Regel,
   die die Familie jetzt für jede Maske aufstellt. Der Name bleibt, weil
   templates/backoffice/migration/stammdaten.html.twig darauf zeigt; neue
   Vorlagen schreiben `.knopf--gross`. */
.knopf--gross,
.haupt {
    min-height:var(--hoehe-3);
    padding:var(--raum-2) var(--raum-5);
    font-size:var(--schrift-md);
    border-radius:var(--radius-md);
}

/* Über die volle Breite - der Anmeldeknopf in der schmalen Hülle. */
.knopf--breit { display:flex; inline-size:100%; }

/* --------------------------------------------------------------------------
   Der Umschalter

   Zwei Ansichten derselben Liste ("Liste"/"Gruppen" in der
   Stammdatenübersicht). Der gewählte Zustand darf nicht allein an der
   Farbe hängen (WCAG 1.4.1): Er trägt zusätzlich das volle Schriftgewicht
   und wird vom Lesegerät über aria-pressed bzw. aria-current gemeldet.

   >> HIER STAND EIN FESTES #fff (Zeile 3657).

   `.knopf-klein--aktiv { background:var(--akzent); color:#fff }` ist die
   einzige feste Farbe unterhalb von :root außerhalb des Druckblocks. Im
   Dunkelmodus wird --akzent zu #84cde8, einem hellen Blau; weiße Schrift
   darauf erreicht 1,4:1 und ist unlesbar. --flaeche kippt mit und löst das.
   Der Name bleibt - zwei Vorlagen zeigen darauf.
   -------------------------------------------------------------------------- */
.knopf--aktiv,
.knopf-klein--aktiv,
.knopf[aria-pressed="true"],
.knopf-klein[aria-pressed="true"],
.knopf[aria-current="page"],
.knopf-klein[aria-current="page"] {
    color:var(--flaeche);
    background:var(--akzent);
    border-color:var(--akzent);
    font-weight:var(--fett-voll);
}
.knopf--aktiv:hover,
.knopf-klein--aktiv:hover,
.knopf[aria-pressed="true"]:hover,
.knopf-klein[aria-pressed="true"]:hover {
    color:var(--flaeche);
    background:var(--akzent-dunkel);
    border-color:var(--akzent-dunkel);
}

/* --------------------------------------------------------------------------
   Das Symbol im Knopf

   Der Satz liegt in layout/_symbole.html.twig - ein <svg> mit <symbol>, auf
   das <use href="#i-..."> zeigt. Er ist als Strichzeichnung auf 24x24 mit
   Strichstärke 1.75 gezeichnet; diese Regel setzt genau das und nichts
   anderes, damit ein Symbol im Knopf und dasselbe Symbol in der Gliederung
   nicht zwei verschiedene Zeichnungen sind.

   `em` und nicht `rem`: Das Symbol soll mit seinem Knopf wachsen. Im
   großen Anmeldeknopf ist es größer als in der Tabellenzelle, ohne dass
   es dafür eine zweite Regel braucht.

   `currentColor` und `fill:none`: Das Zeichen wandert mit der Schriftfarbe
   durch alle vier Ausprägungen und alle Zustände. Im gefüllten Knopf ist
   es --flaeche, im folgenreichen --warn - ohne eine einzige weitere Zeile.
   -------------------------------------------------------------------------- */
.knopf__symbol {
    flex:0 0 auto;
    inline-size:1.15em; block-size:1.15em;
    fill:none; stroke:currentColor; stroke-width:1.75;
    stroke-linecap:round; stroke-linejoin:round;
    /* Die Grundlinie der Schrift liegt nicht in der Mitte der Zeichenfläche.
       Ohne diese Verschiebung sitzt das Zeichen sichtbar zu hoch neben
       seinem Wort. */
    margin-block-start:-0.05em;
}

/* Nur ein Symbol, kein Wort. Quadratisch: Breite gleich Höhe, kein
   waagrechter Innenabstand - sonst wird aus dem Knopf ein Rechteck mit einem
   Punkt darin. */
.knopf--nursymbol {
    inline-size:var(--hoehe-2);
    padding-inline:var(--raum-0);
    gap:var(--raum-0);
}
.knopf--nursymbol.knopf--klein { inline-size:var(--hoehe-1); }
.knopf--nursymbol.knopf--gross { inline-size:var(--hoehe-3); }

/* >> EIN KNOPF OHNE WORT BRAUCHT EINEN NAMEN (WCAG 4.1.2, 1.1.1).

   Das <svg> im Knopf trägt aria-hidden - es ist Zierde, wie in der
   Gliederung. Damit hat ein Knopf ohne Beschriftung überhaupt keinen
   zugänglichen Namen: Das Lesegerät sagt "Schaltfläche" und sonst nichts.

   Die gestrichelte Warnkante unten ist kein Entwurf, sondern eine Falle: Ein
   solcher Knopf soll auf dem Bildschirm des Entwicklers auffallen, bevor er
   auf dem des Beraters landet. Die eigentliche Absicherung gehört in
   VorlagenTest - CSS kann nur zeigen, nicht verhindern. */
.knopf--nursymbol:not([aria-label]):not([aria-labelledby]):not([title]) {
    outline:2px dashed var(--warn);
    outline-offset:2px;
}

/* Farbe trägt nie allein eine Aussage. Ein folgenreicher Knopf ohne Wort
   wäre genau das - die Warnfarbe als einziger Träger. Dieselbe Falle. */
.knopf--folgenreich.knopf--nursymbol {
    outline:2px dashed var(--warn);
    outline-offset:2px;
}

/* --------------------------------------------------------------------------
   Zustände

   Sie stehen am Ende der Familie, weil sie gewinnen müssen: Ein gesperrter
   Knopf sieht gesperrt aus, ganz gleich welche Ausprägung er trägt. Der
   Träger im Selektor (`button[disabled]`, 0,1,1) schlägt jede
   Ausprägungsklasse (0,1,0), und `[aria-disabled]` deckt das <a> ab, das
   kein `disabled` kennt.
   -------------------------------------------------------------------------- */
button[disabled], input[type="submit"][disabled],
.knopf[disabled], .knopf-klein[disabled],
.knopf[aria-disabled="true"], .knopf-klein[aria-disabled="true"],
a.knopf[aria-disabled="true"], a.knopf-klein[aria-disabled="true"] {
    cursor:not-allowed;
    color:var(--tinte-3);
    background:var(--flaeche-2);
    border-color:var(--rand);
    box-shadow:none;
    transform:none;
}

/* >> DER LADEPUNKT (htmx).

   Sieben Vorlagen schicken mit hx-post/hx-get ab. Zwischen Klick und Antwort
   sagt heute nichts, dass etwas läuft - auf einer Liste mit 57 Mandaten
   sind das mehrere hundert Millisekunden, in denen ein zweites Mal geklickt
   wird.

   Der Punkt ist eine Form aus Rändern und keine Glyphe - dieselbe
   Begründung wie beim Sortierzeichen: Ein Kreissymbol läge außerhalb der
   beiden Inter-Teilmengen unter assets/vendor/inter/, und der Browser holte
   es sich aus einer beliebigen Ersatzschrift. Eine Symbolschrift ist
   ausgeschlossen (CSP font-src 'self', und sie wäre ein vierter Ausgang).

   `pointer-events:none` sperrt den zweiten Klick mit dem Zeigegerät. Den
   Tastaturweg sperrt es NICHT - dafür gehört hx-disabled-elt an das
   Element. Die Regel ersetzt das nicht, sie ergänzt es.

   `input[type=submit]` steht bewusst NICHT in dieser Selektorenliste: Ein
   ersetztes Element trägt kein ::after, der Punkt bliebe aus - und weil die
   Regel die Beschriftung ausblendet, wäre der Knopf dann leer statt
   beschäftigt. Es kostet nichts: Die 228 Vorlagen enthalten keinen einzigen
   `<input type="submit">`, alle 199 Absendeknöpfe sind `<button>`. */
[aria-busy="true"].knopf,
[aria-busy="true"].knopf-klein,
button[aria-busy="true"] {
    cursor:progress;
    pointer-events:none;
    color:transparent;
    position:relative;
}
[aria-busy="true"].knopf::after,
[aria-busy="true"].knopf-klein::after,
button[aria-busy="true"]::after {
    content:"";
    position:absolute; inset-block-start:50%; inset-inline-start:50%;
    inline-size:1em; block-size:1em;
    margin-block-start:-0.5em; margin-inline-start:-0.5em;
    /* 2px ist die Stärke, die dieses Blatt bereits für den Fokusring
       benutzt. Eine Haarlinie darunter verschwindet auf einem 1x-Bildschirm. */
    border:2px solid currentColor;
    border-block-start-color:transparent;
    border-radius:var(--radius-voll);
    /* Kein eigenes Dauertoken: --dauer-normal wäre als Umlauf viel zu
       schnell. Das Vierfache ist abgeleitet und keine neue freie Zahl. */
    animation:knopf-laden calc(var(--dauer-normal) * 4) linear infinite;
}
/* Der Ladepunkt braucht eine Farbe, die der Knopf gerade nicht mehr hat:
   `color:transparent` oben blendet die Schrift aus, und currentColor würde
   mit ihr verschwinden. Je Ausprägung eine Zeile. */
[aria-busy="true"].knopf::after,
button[aria-busy="true"]::after { border-color:var(--flaeche);
    border-block-start-color:transparent; }
[aria-busy="true"].knopf-klein::after,
[aria-busy="true"].knopf--umriss::after,
[aria-busy="true"].knopf--leise::after { border-color:var(--akzent);
    border-block-start-color:transparent; }
[aria-busy="true"].knopf--folgenreich::after { border-color:var(--warn);
    border-block-start-color:transparent; }

@keyframes knopf-laden { to { transform:rotate(360deg); } }

/* --------------------------------------------------------------------------
   Die Knopfgruppe

   Zusammenhängende Knöpfe mit geteilten Kanten - der Umschalter zwischen
   zwei Ansichten derselben Liste. Er ist ein Bauteil und keine Reihe: Die
   Knöpfe berühren sich, weil sie EINE Frage beantworten ("welche
   Ansicht"). Wo zwei Knöpfe zwei Fragen beantworten, gehören sie in die
   Werkzeugleiste und nicht in die Gruppe.

   Das -1px ist die einzige feste Zahl hier und unvermeidlich: Es ist die
   Breite genau einer Kante. Ohne sie stehen zwischen zwei Knöpfen zwei
   Linien statt einer.
   -------------------------------------------------------------------------- */
.knopfgruppe {
    display:inline-flex; align-items:stretch;
    /* isolation, damit das z-index des Fokusrings innerhalb der Gruppe
       bleibt und nicht mit der Kopfleiste um Ebenen streitet. */
    isolation:isolate;
}
.knopfgruppe > * {
    border-radius:0;
    margin-inline-start:-1px;
}
.knopfgruppe > :first-child {
    margin-inline-start:var(--raum-0);
    border-start-start-radius:var(--radius-sm);
    border-end-start-radius:var(--radius-sm);
}
.knopfgruppe > :last-child {
    border-start-end-radius:var(--radius-sm);
    border-end-end-radius:var(--radius-sm);
}
/* Der gewählte und der überfahrene Knopf legen sich über ihre Nachbarn,
   damit seine Kante ringsum sichtbar bleibt und nicht halb verdeckt ist.

   Die 1 ist keine Ebene im Sinne des Wertevorrats: Die Gruppe hat mit
   `isolation:isolate` ihren eigenen Stapel, und darin heißt 1 schlicht
   "eine Kante über dem Nachbarn". Der Fokusring liegt mit --ebene-haftend
   darüber, damit er auch über einem überfahrenen Nachbarn sichtbar ist. */
.knopfgruppe > :hover,
.knopfgruppe > .knopf--aktiv,
.knopfgruppe > .knopf-klein--aktiv,
.knopfgruppe > [aria-pressed="true"] { position:relative; z-index:1; }

/* Der Fokusring steht weiter oben im Blatt in der gemeinsamen Regel für
   a, button, input, select, textarea und summary und trägt dort seine
   Begründung (--akzent-hell, 4,66:1 gegen Weiß, Schwelle 3:1 nach WCAG
   1.4.11). Hier kommt nur dazu, was dort fehlt: In einer Knopfgruppe liegt
   der Ring sonst unter dem Nachbarn, weil sich die Kanten überlappen.

   Diese Regel steht NACH der Regel darüber und nicht davor. Beide haben
   dieselbe Spezifität (0,2,0); ein Knopf, der zugleich überfahren und
   tastaturfokussiert ist, bekäme sonst die niedrigere Ebene - und der
   Fokusring verschwände genau in dem Moment, in dem die Maus danebensteht. */
.knopfgruppe > :focus-visible { position:relative; z-index:var(--ebene-haftend); }

/* --------------------------------------------------------------------------
   Die Werkzeugleiste

   Die Handlungszeile über einer Liste (AP-H24). Sie stand bisher als
   `display:flex; gap:.6rem` da und trug genau einen Knopf; sie ist der Ort,
   an dem die acht Mittelpunktverweise der Verzeichnismaske hingehören.

   >> WAS DER TRENNER LEISTET.

   Acht Handlungen in einer Zeile sind acht Handlungen, ganz gleich wie sie
   aussehen. Der Trenner macht daraus Gruppen: was man mit dem Verzeichnis
   TUT (bearbeiten, anlegen), was man daraus ANSIEHT (Matrix, Ausgabe, PDF)
   und was man damit ENTSCHEIDET (freigeben). Drei Gruppen von zwei bis drei
   Punkten liest man; acht gleichrangige Punkte zählt man ab.

   --raum-2 senkrecht und --raum-3 waagrecht: Bricht die Leiste auf einem
   schmalen Bildschirm um, sollen die Zeilen enger stehen als die Knöpfe
   nebeneinander - sonst zerfällt die Gruppe in Einzelteile.
   -------------------------------------------------------------------------- */
.werkzeugleiste {
    /* Aus dem Entwurf der Flaechenfamilie uebernommen: Die Leiste steht
       ueber einer Liste und damit im Arbeitswert, nicht im Fliesstext. */
    font-size:var(--schrift-sm);
    display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--raum-2) var(--raum-3);
    margin:var(--raum-4) var(--raum-0) var(--raum-5);
}

/* Ein Formular in der Leiste ist ein Knopf und kein Eingabebogen. */
.werkzeugleiste form {
    display:flex; align-items:center; gap:var(--raum-2);
    margin:var(--raum-0); max-width:none;
}

/* Der senkrechte Strich zwischen zwei Gruppen. `align-self:stretch` statt
   einer Höhenangabe: Er ist so hoch wie die Knöpfe daneben, auch wenn eine
   Beschriftung umbricht. aria-hidden gehört an das Element in der Vorlage -
   ein Strich ist für das Lesegerät nichts. */
.werkzeugleiste__trenner {
    flex:0 0 auto; align-self:stretch;
    inline-size:1px; margin-inline:var(--raum-1);
    background:var(--rand);
}

/* Was rechts steht, steht abseits: die Ausgabe, der Druck, das Verlassen.
   Nicht "weniger wichtig", sondern "gehört nicht zur Arbeit an dieser
   Liste". Die Klasse sitzt am ERSTEN Element der rechten Gruppe und schiebt
   sich samt allem, was danach kommt, an den Rand. */
.werkzeugleiste__rechts { margin-inline-start:auto; }

/* Ein Hinweis in der Leiste ("3 von 57 gewählt"), kein Bedienelement. */
.werkzeugleiste__vermerk {
    color:var(--tinte-2); font-size:var(--schrift-sm);
    line-height:var(--zeile-eng);
}

@media (max-width:34rem) {
    /* Auf dem schmalen Bildschirm fällt der Trenner weg: Ein senkrechter
       Strich zwischen zwei umgebrochenen Zeilen trennt nichts, er steht nur
       herum. Die Gruppen bleiben trotzdem beieinander - die Reihenfolge im
       Quelltext macht das ohne eine weitere Regel. */
    .werkzeugleiste__trenner { display:none; }
    .werkzeugleiste__rechts  { margin-inline-start:var(--raum-0); }
}

/* --------------------------------------------------------------------------
   Das Formular in der Tabellenzelle (AP-H24)

   Feld und Knopf nebeneinander, ohne den Zeilenabstand einer Maske. Die
   Begründung ist die alte und gilt weiter; nur die Zahlen sind jetzt Token.
   -------------------------------------------------------------------------- */
.zeilenformular {
    display:flex; align-items:center; gap:var(--raum-1);
    margin:var(--raum-0); max-width:none;
}
.zeilenformular input[type="text"],
.zeilenformular input[type="date"],
.zeilenformular select { margin:var(--raum-0); }

/* --------------------------------------------------------------------------
   Der Anmeldeknopf (layout/schlank.html.twig)

   Ersetzt `.huelle button { width:100%; margin-top:1.5rem; padding:.7rem;
   font-size:1rem }`. Es ist der einzige Knopf seiner Maske und der einzige,
   den jemand trifft, ohne hinzusehen - er bekommt --hoehe-3 und die volle
   Breite. Die Vorlage braucht dafür keine Klasse; die Maske hat nur diesen
   einen Knopf.
   -------------------------------------------------------------------------- */
.huelle button {
    display:flex; inline-size:100%;
    min-height:var(--hoehe-3);
    margin-block-start:var(--raum-5);
    padding:var(--raum-2) var(--raum-5);
    font-size:var(--schrift-md);
    border-radius:var(--radius-md);
}

/* --------------------------------------------------------------------------
   Der Knopf in Kartenform (Portalassistent, AP-F12)

   Hier wählt der Mandant eine Aufgabe, keine Werkzeugleistenfunktion.
   Fragenzahl und Zeitangabe stehen mit im Knopf - "wie lange dauert das"
   muss vor dem Klick beantwortet sein, sonst wird nicht geklickt. Deshalb
   bricht er aus der Familie aus: linksbündig, hoch, mit Innenleben.
   Er behält seinen Namen, eine Vorlage zeigt darauf.
   -------------------------------------------------------------------------- */
.assistent-knopf {
    display:block; inline-size:100%; text-align:left;
    padding:var(--raum-3) var(--raum-4);
    font:inherit; font-size:var(--schrift-md); font-weight:var(--fett-normal);
    line-height:var(--zeile-normal);
    color:var(--tinte); background:var(--flaeche);
    border:1px solid var(--rand-stark); border-radius:var(--radius-md);
}
.assistent-knopf:hover {
    background:var(--flaeche-2); border-color:var(--akzent);
    box-shadow:var(--schatten-sm);
}
.assistent-knopf strong {
    display:block; font-size:var(--schrift-lg); font-weight:var(--fett-stark);
    color:var(--tinte);
}
.assistent-knopf small {
    display:block; margin-block-start:var(--raum-1);
    color:var(--tinte-2); font-size:var(--schrift-sm);
}

/* --------------------------------------------------------------------------
   Die zerstörende Nebenhandlung in einer Zeile

   "Gespeicherten Wert entfernen", "Zweiten Faktor abschalten". Bewusst kein
   Knopfrelief: Sie soll auffindbar sein, nicht einladen. Die Begründung ist
   die alte; der Unterschied zu .knopf--leise ist die Absicht - dort ein
   Bedienelement, das nur leise auftritt, hier eines, das gar nicht wie eines
   aussehen soll.

   Die Trefferfläche ist trotzdem --hoehe-1 hoch. Ein Ziel von einer
   Textzeile Höhe trifft niemand zuverlässig (WCAG 2.5.8); "unauffällig"
   heißt nicht "schwer zu treffen".
   -------------------------------------------------------------------------- */
.knopf-schlicht {
    display:inline-flex; align-items:center;
    min-height:var(--hoehe-1);
    padding:var(--raum-0);
    font:inherit; font-size:var(--schrift-sm); font-weight:var(--fett-normal);
    cursor:pointer;
    color:var(--akzent); background:none; border:0;
    text-decoration:underline; text-underline-offset:2px;
}
.knopf-schlicht:hover { color:var(--warn); text-decoration-thickness:2px; }

/* --------------------------------------------------------------------------
   Wege, keine Handlungen

   .zurueck und .weiter sind Verweise und bleiben es. Sie stehen hier, weil
   sie in derselben Zeile wie ein Knopf vorkommen und dieselbe Schriftgröße
   brauchen - nicht, weil sie zur Familie gehören.
   -------------------------------------------------------------------------- */
.zurueck { display:inline-block; font-size:var(--schrift-sm); margin:var(--raum-0) var(--raum-0) var(--raum-4); }
.weiter  { margin:var(--raum-6) var(--raum-0) var(--raum-0); font-size:var(--schrift-sm); }

/* --------------------------------------------------------------------------
   Bewegungsruhe

   Ersetzt die drei verstreuten Fassungen dieser Regel (Zeile 1282, 2206,
   und die in der Assistentenfamilie). Der Ladepunkt bleibt sichtbar - er
   sagt "es läuft noch" -, er dreht sich nur nicht mehr.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .knopf, .knopf-klein, .knopf-schlicht, .assistent-knopf,
    button, input[type="submit"] { transition:none; }

    .knopf:active, .knopf-klein:active, .knopf--leise:active,
    .knopf--umriss:active, .knopf--folgenreich:active,
    button:active, input[type="submit"]:active { transform:none; }

    [aria-busy="true"].knopf::after,
    [aria-busy="true"].knopf-klein::after,
    button[aria-busy="true"]::after { animation:none; }
}

/* --------------------------------------------------------------------------
   Papier

   Gedruckt wird hier oft - eine Maske als Beleg, ein Verzeichnis zur
   Durchsicht. Eine Handlungszeile hat auf einem Ausdruck nichts zu suchen:
   "Freigeben" auf Papier ist kein Knopf, sondern eine Zeile, die jemand
   verwirrt. Die Leiste fällt deshalb weg.

   Einzelne Knöpfe bleiben stehen - sie können mitten in einem Abschnitt
   sitzen, dessen Zusammenhang ohne sie nicht mehr stimmt -, aber ohne
   Füllung: Ein Volltonfeld kostet Toner und sagt auf Papier nichts.
   -------------------------------------------------------------------------- */
@media print {
    .werkzeugleiste, .knopfgruppe { display:none; }

    .knopf, .knopf-klein, .assistent-knopf,
    button, input[type="submit"] {
        color:inherit; background:none;
        border:1px solid var(--rand-stark);
        box-shadow:none;
    }
    [aria-busy="true"]::after { display:none; }
}

/* ==========================================================================
   FORMULARELEMENTE
   ========================================================================== */

/* ==========================================================================
   FORMULARELEMENTE — DER EINE BLOCK

   Ersetzt app.css:1092-1199 ("--- Formulare ---") und app.css:1294-1377 sowie
   1384-1386 ("Grundstil der Formularelemente"). Der zweite Block trug selbst
   die Warnung „Der Block gehört fachlich in den Grundteil von app.css und
   darf nur EINMAL vorkommen." — er kam trotzdem ein zweites Mal, 202 Zeilen
   später, und hat den ersten in Teilen erschlagen.

   >> WAS DIE DOPPELUNG GEKOSTET HAT. Die Kaskade entscheidet je EIGENSCHAFT,
      nicht je Block, und die Spezifität wird je Selektor einer Liste
      gerechnet — nicht für die Liste als Ganzes. Daraus folgte:

      * `label` (0,0,1) gegen `form label` (0,0,2): Die begründete
        Beschriftungsluft aus AP-H17 — 1,9rem oben gegen 0,35rem unten, damit
        der Hilfetext zum FELD DARÜBER gelesen wird — war in JEDEM Formular
        wirkungslos. Übrig blieb 0 oben / 0,25rem unten, also genau der
        symmetrische Abstand, den AP-H17 abgeschafft hatte.
      * In der Liste `input[type=text], …, select, textarea` haben die
        Typselektoren (0,1,1), `select` und `textarea` aber nur (0,0,1).
        `form select` (0,0,2) hat sie geschlagen. Ergebnis: Die Kante nach
        WCAG 1.4.11 (--rand-stark, 3,28:1) galt für Textfelder, während
        Auswahlfeld und Textbereich auf --rand zurückfielen — 1,30:1 gegen
        Weiß. Genau die zwei Elemente, deren Umriss das einzige Merkmal ist,
        hatten keinen sichtbaren Umriss.
      * Weitere stille Verluste: `textarea` 44rem -> 34rem, `min-height` 6rem
        -> 4,5rem, `input[type=number]` 9rem -> 14rem, die versalgesetzte
        `legend` aus AP-H17 -> gewöhnlicher Fließtext.

   Es gibt ab hier genau EINEN Formularblock. Wer einen zweiten anlegt, holt
   alles davon zurück.
   ========================================================================== */


/* --------------------------------------------------------------------------
   Drei Feldbreiten

   Die Breite eines Feldes ist eine AUSSAGE: Sie sagt, wie viel hineingehört.
   Bis hierher sagte sie, welcher Selektor gewonnen hat — ein Datumsfeld war
   14rem breit, weil `form input[type=date]` (0,1,2) den Wert 12rem aus
   `input[type=date]` (0,1,1) geschlagen hat, und nicht, weil ein Datum
   14rem braucht.

   Die drei Werte gehören zur Formularfamilie und stehen deshalb hier. Wenn
   der Wertevorrat sie später aufnimmt, wandern sie unverändert nach oben.
   -------------------------------------------------------------------------- */
:root {
    /* 10rem: "31.12.2026" braucht bei --schrift-sm rund 70px, dazu zweimal
       --raum-3 Innenabstand und der Kalenderknopf des Browsers (~20px).
       160px liegt darüber, ohne dass ein achtstelliges Datum in einem
       Feld von Adressbreite steht. Gilt auch für Uhrzeit, Zahl und
       kurze Kennungen. */
    --feldbreite-kurz:10rem;

    /* 22rem ~ 44 Zeichen bei --schrift-sm. Die Länge einer Bezeichnung,
       eines Namens, einer Anschriftzeile, einer E-Mail-Adresse. */
    --feldbreite-mittel:22rem;

    /* Ein Freitextfeld wird GELESEN, nicht überflogen - seine Breite ist die
       Lesebreite und kein eigener Wert. Der alte Wert 44rem lag deutlich
       darüber; genau dagegen ist --breite-text angelegt. */
    --feldbreite-breit:var(--breite-text);
}


/* --------------------------------------------------------------------------
   Das Formular als Ganzes
   -------------------------------------------------------------------------- */

/* Vorher 60rem, fest. --breite-masse ist derselbe Gedanke mit Namen: die
   Breite, in der eine Arbeitsmaske steht. Sie ist etwas weiter als vorher,
   weil .feldraster darin zwei bis drei Spalten stellt statt einer. */
form { max-inline-size:var(--breite-masse); }


/* --------------------------------------------------------------------------
   Die Feldzeile

   Beschriftung, Feld, Hilfetext, Fehlertext — in DIESER Reihenfolge, mit
   festen Abständen aus der Raumleiter.

   >> DAS FORMULARTHEMA LIEFERT EINE ANDERE REIHENFOLGE.
      `form_div_layout.html.twig` baut form_row als
      <div> label, errors, widget, help </div>. Der Fehler steht dort ZWISCHEN
      Beschriftung und Feld — man liest die Rüge, bevor man weiß, wozu.
      `order` räumt das im Raster gerade, ohne dass eine Vorlage sich ändert:
      Reihenfolge im Quelltext bleibt, wie Symfony sie schreibt, Reihenfolge
      auf dem Bildschirm ist die von oben.

   >> UND WARUM DIE ZEILE DEN ABSTAND TRÄGT UND NICHT DAS FELD.
      Bis hierher hing der Zeilenabstand am `margin-bottom` des Feldes
      (`form input { margin:0 0 .9rem }`). Deshalb musste `form fieldset`
      unten `.1rem` Innenabstand haben — sonst hätte sich beides addiert.
      Das ist eine Kopplung über zwei Bauteile hinweg: Wer den Feldabstand
      anfasst, verrückt den Rahmen. Der Abstand gehört der ZEILE.

   >> DIE ZUORDNUNG DES HILFETEXTES BLEIBT (AP-H17).
      `.help-text` steht UNTER seinem Feld und damit direkt über der
      nächsten Beschriftung. Bei gleichem Abstand nach oben und unten liest
      man ihn als Einleitung zum FOLGENDEN Feld - in der Tätigkeitsmaske mit
      ihren 48 Feldern vierundvierzigmal falsch herum. Deshalb 4px innerhalb
      der Zeile gegen 16px zwischen zwei Zeilen: Nähe ist die Zuordnung.
      Das ist dasselbe Verhältnis wie vorher (1,9rem : 0,35rem), nur auf dem
      4px-Raster und an der Zeile statt an zwei Rand-Angaben.
   -------------------------------------------------------------------------- */
.feld {
    display:grid;
    gap:var(--raum-1);
    margin:0 0 var(--raum-4);
    min-inline-size:0;
}
.feld:last-child { margin-block-end:0; }

.feld > label                        { order:1; }
.feld > input, .feld > select,
.feld > textarea, .feld > .suchfeld,
.feld > .schalter, .feld > div       { order:2; }
.feld > .help-text, .feld > small,
.feld > .hilfe                       { order:3; }
.feld > ul:has(> li[id*="_error"]),
.feld > .feldfehler                  { order:4; }

/* Die Abstände, die die Zeile ihren Kindern abnimmt, stehen NICHT hier,
   sondern unter „Was die Zeile ihren Kindern abnimmt" - hinter den Regeln,
   die sie zurücknehmen. Bei gleicher Spezifität gewinnt die spätere
   Regel; `.feld > small` hier oben hätte gegen `form small` weiter unten
   verloren. Genau diese Verwechslung von Reihenfolge und Spezifität hat
   die beiden alten Blöcke unbrauchbar gemacht. */

/* Eine Zeile, die über die volle Breite eines Rasters gehen soll - der
   Freitext neben zwei kurzen Feldern. */
.feld--ganz { grid-column:1 / -1; }


/* --------------------------------------------------------------------------
   Die Beschriftung

   >> DER ABSTAND ORDNET DEN HILFETEXT ZU (AP-H17) - hier für die Masken,
      die KEINE .feld-Zeile haben. 152 Vorlagen schreiben Beschriftung und
      Feld ohne Umhüllung hintereinander; nimmt man dem `label` seinen
      Vorlauf, klebt die ganze Maske zusammen. Die Regel bleibt deshalb
      stehen - jetzt allerdings wirksam, weil `form label` sie nicht mehr
      überschreibt.

   >> DIE FARBE IST GEDÄMPFT UND BLEIBT ES.
      --tinte-2 gegen --flaeche: 8,6:1. Die Beschriftung ist die Frage, die
      Eingabe ist die Antwort - die Antwort steht in Lesetinte, die Frage
      leiser. Das Kästchen bringt seine Beschriftung selbst mit; die steht
      deshalb weiter unten in --tinte.
   -------------------------------------------------------------------------- */
label {
    display:block;
    margin:var(--raum-5) 0 var(--raum-1);
    font-size:var(--schrift-sm);
    font-weight:var(--fett-stark);
    line-height:var(--zeile-normal);
    color:var(--tinte-2);
}

/* Die erste Beschriftung einer Gruppe braucht den Vorlauf nicht - der Rahmen
   des Fieldsets hat ihn schon. */
fieldset > label:first-of-type,
.feldgruppe > label:first-of-type { margin-block-start:var(--raum-2); }


/* --------------------------------------------------------------------------
   Die Bedienelemente — EINE Höhe, EINE Kante

   >> DIE KANTE IST --rand-stark UND NICHT --rand (WCAG 1.4.11).
      1.4.11 verlangt 3:1 für die Umrandung eines Bedienelements. --rand
      erreicht gegen Weiß 1,30:1 - das Feld war als Feld nicht zu erkennen,
      man sah nur den Text darin. --rand-stark ist für genau diesen Zweck
      angelegt (3,28:1). Bis hierher galt das nur für Textfelder; Auswahlfeld
      und Textbereich fielen über `form select` auf --rand zurück. Jetzt
      tragen alle dieselbe Kante.

   >> ACHTUNG, HIER LIEGT DIE FALLE VON VORHIN.
      Diese Selektorliste mischt (0,1,1) für die Typselektoren mit (0,0,1)
      für `select` und `textarea`. Solange es nur DIESEN einen Block gibt,
      ist das folgenlos. Ein zweiter Block mit `form select` (0,0,2) hätte
      den Auswahlfeldern die Kante wieder genommen - das ist genau das, was
      passiert war.

   >> DIE HÖHE IST --hoehe-2 UND WIRD GESETZT, NICHT GERECHNET.
      Vorher ergab sie sich aus Schriftgröße mal Zeilenhöhe plus zweimal
      Innenabstand und war deshalb je Feldart eine andere. `block-size` setzt
      sie fest; den Text zentriert der Browser im einzeiligen Feld von selbst.
      `padding-block:0` ist die Bedingung dafür - sonst rechnet border-box
      den Text aus dem Feld heraus.

   >> `background-color` UND NICHT `background`.
      Das Auswahlfeld bekommt weiter unten seinen Pfeil als Farbverlauf.
      Die Kurzform `background` in einer späteren Regel würde ihn löschen.
   -------------------------------------------------------------------------- */
input[type=text], input[type=password], input[type=email], input[type=url],
input[type=tel], input[type=search], input[type=number], input[type=date],
input[type=datetime-local], input[type=month], input[type=week],
input[type=time], input[type=file], input:not([type]),
select, textarea {
    inline-size:100%;
    max-inline-size:var(--feldbreite, var(--feldbreite-mittel));
    block-size:var(--hoehe-2);
    padding-block:0;
    padding-inline:var(--raum-3);

    /* Der Abstand nach unten ist die ÜBERGANGSREGEL für Zeilen ohne
       `.feld`-Umhüllung - das Formularthema liefert die Zeile bis auf
       Weiteres ohne Klasse (siehe Vorlagenänderung). Innerhalb von
       .feld, in den Zeilenformularen und im Raster wird er wieder auf 0
       gesetzt. */
    margin:0 0 var(--raum-4);

    font-family:inherit;
    font-size:var(--schrift-sm);
    font-weight:var(--fett-normal);
    line-height:var(--zeile-eng);
    color:var(--tinte);
    background-color:var(--flaeche);

    border:1px solid var(--rand-stark);
    border-radius:var(--radius-sm);
    transition:border-color var(--dauer-schnell) var(--stufe),
               box-shadow var(--dauer-schnell) var(--stufe),
               background-color var(--dauer-schnell) var(--stufe);
}

/* Der Textbereich ist mehrzeilig: feste Höhe wäre hier falsch, und die
   Zeilenhöhe ist die des Fließtextes und nicht die der Eingabezeile.
   Drei Zeilen Mindesthöhe - das ist die Höhe, in der man sieht, dass man
   in einem Textbereich steht und nicht in einem Feld. */
textarea {
    block-size:auto;
    min-block-size:calc(var(--hoehe-2) * 3);
    max-inline-size:var(--feldbreite, var(--feldbreite-breit));
    padding-block:var(--raum-2);
    line-height:var(--zeile-normal);
    resize:vertical;
}

/* Datum, Uhrzeit, Zahl: kurz, weil der Inhalt kurz ist. Ein Datumsfeld in
   Adressbreite behauptet, es passe eine Adresse hinein. */
input[type=date], input[type=datetime-local], input[type=month],
input[type=week], input[type=time], input[type=number] {
    max-inline-size:var(--feldbreite, var(--feldbreite-kurz));
}

/* Zahlen stehen rechtsbündig und mit gleich breiten Ziffern - wie in der
   Tabelle. Zwei Beträge untereinander sind sonst nicht vergleichbar. */
input[type=number] {
    text-align:end;
    font-variant-numeric:tabular-nums;
}


/* --- Das Auswahlfeld ---------------------------------------------------
   >> DER PFEIL IST EIN FARBVERLAUF UND KEIN BILD.
      Die Inhaltsrichtlinie lässt `url()` nur für die zwei Inter-Dateien zu
      (ADR 0046), eine Symbolschrift ist ausgeschlossen, und der Symbolsatz
      `#i-…` steht als <use> im Markup und nicht im Stilblatt. Bleibt der
      alte Weg: zwei diagonal geteilte Quadrate, nebeneinander gesetzt,
      ergeben ein Dreieck. Es trägt --tinte-2 und kippt damit im
      Dunkelmodus mit.

      5px Kantenlänge je Quadrat, also ein Dreieck von 10x5px: --raum-1 (4px)
      franst auf einfach auflösenden Bildschirmen aus, --raum-2 (8px) ergäbe
      ein 16px breites Dreieck neben einem 14px hohen Text. Die zwei
      Positionen unterscheiden sich um genau diese 5px - so stoßen die
      Quadrate aneinander.
   ---------------------------------------------------------------------- */
select {
    -webkit-appearance:none;
    appearance:none;
    /* Platz für den Pfeil: --raum-6 rechts, damit ein langer Eintrag nicht
       darunter läuft. */
    padding-inline-end:var(--raum-6);
    background-image:
        linear-gradient(45deg, transparent 50%, var(--tinte-2) 50%),
        linear-gradient(135deg, var(--tinte-2) 50%, transparent 50%);
    background-position:
        right var(--raum-3) center,
        right calc(var(--raum-3) + 5px) center;
    background-size:5px 5px, 5px 5px;
    background-repeat:no-repeat;
}

/* Die Mehrfachauswahl ist eine Liste und kein Feld: keine feste Höhe, kein
   Pfeil, und der Innenabstand gehört an die Einträge. */
select[multiple] {
    -webkit-appearance:auto;
    appearance:auto;
    block-size:auto;
    min-block-size:calc(var(--hoehe-2) * 3);
    padding:var(--raum-1);
    background-image:none;
}
select[multiple] option { padding:var(--raum-1) var(--raum-2); border-radius:var(--radius-xs); }


/* --- Das Dateifeld -----------------------------------------------------
   Es trägt einen Knopf in sich, den kein Stilblatt vollständig fassen
   kann. Was sich fassen lässt: Höhe, Kante und der Knopf selbst - der
   sonst als graues Systemrelief in einer sonst durchgestalteten Maske steht.
   `line-height` ist hier die einzige Handhabe, den eingebauten Knopf
   senkrecht zu setzen; die 2px sind die beiden 1px-Kanten, die border-box
   von der Höhe abzieht.
   ---------------------------------------------------------------------- */
input[type=file] {
    padding-inline:var(--raum-2);
    line-height:calc(var(--hoehe-2) - 2px);
    background-color:var(--flaeche-2);
    cursor:pointer;
}
input[type=file]::file-selector-button {
    margin-inline-end:var(--raum-3);
    padding:0 var(--raum-3);
    block-size:var(--hoehe-1);
    font-family:inherit;
    font-size:var(--schrift-sm);
    font-weight:var(--fett-stark);
    color:var(--akzent);
    background:var(--flaeche);
    border:1px solid var(--rand-stark);
    border-radius:var(--radius-xs);
    cursor:pointer;
}
input[type=file]:hover::file-selector-button {
    border-color:var(--akzent-hell);
    background:var(--akzent-weich);
}


/* --------------------------------------------------------------------------
   Feldbreite nach INHALT

   Drei Klassen, drei Aussagen. Sie stehen wahlweise an der ZEILE (.feld) oder
   direkt am Feld: Der Wert wandert als eigene Eigenschaft die Vererbung
   hinunter, und die Regeln oben lesen ihn mit `var(--feldbreite, …)`. Steht
   keine der drei Klassen im Weg, greift der Rückfallwert - und das ist die
   Breite, die zur Feldart passt.

   .feld--kurz    Datum, Uhrzeit, Zahl, Kennung, Postleitzahl
   .feld--mittel  Bezeichnung, Name, E-Mail, Anschrift  (Vorgabe)
   .feld--breit   Freitext, Zweck, Begründung, Textbereich
   -------------------------------------------------------------------------- */
.feld--kurz   { --feldbreite:var(--feldbreite-kurz); }
.feld--mittel { --feldbreite:var(--feldbreite-mittel); }
.feld--breit  { --feldbreite:var(--feldbreite-breit); }


/* --------------------------------------------------------------------------
   Zustände

   >> DER FOKUSRING IST DER DES HAUSES, ER BEKOMMT HIER NUR EINEN ZWEITEN
      TRÄGER. app.css setzt `outline:2px solid var(--akzent-hell)` für a,
      button, input, select, textarea und summary. Der Ring liegt AUSSERHALB
      des Feldes; auf --flaeche-2 (Gruppenrahmen, Sammlungszeile) verliert er
      an Deutlichkeit. Die Kante wandert deshalb zusätzlich auf --akzent -
      innen und außen, damit der Fokus in jeder Umgebung steht.
   -------------------------------------------------------------------------- */
input:focus-visible, select:focus-visible, textarea:focus-visible {
    border-color:var(--akzent);
}

/* Der Zeiger sagt vorher, was anklickbar ist. --akzent-hell und nicht
   --akzent: Es wird gesehen und nicht gelesen. */
input:hover:not([disabled]):not([readonly]),
select:hover:not([disabled]):not([readonly]),
textarea:hover:not([disabled]):not([readonly]) {
    border-color:var(--akzent-hell);
}

/* Gesperrt: eingelassene Fläche, gedämpfte Tinte, und der Zeiger sagt es
   noch einmal. --flaeche-3 ist die eingelassene Fläche des Wortschatzes;
   solange sie im Wertevorrat fehlt, ist --flaeche-2 der Rückfall. */
input[disabled], select[disabled], textarea[disabled] {
    color:var(--tinte-3);
    background-color:var(--flaeche-3, var(--flaeche-2));
    border-color:var(--rand);
    cursor:not-allowed;
}
select[disabled] {
    background-image:
        linear-gradient(45deg, transparent 50%, var(--tinte-3) 50%),
        linear-gradient(135deg, var(--tinte-3) 50%, transparent 50%);
}

/* >> NUR LESEN IST NICHT GESPERRT.
      Ein freigegebenes Verzeichnis wird nicht geändert, es ist der Nachweis -
      aber es wird GELESEN, oft und lange. Ein [readonly]-Feld behält deshalb
      die Lesetinte und verliert nur die Bedienkante: Es ist Text, kein
      abgewiesenes Feld. Das ist die Entsprechung zu „GESPERRT IST NICHT
      VERWEIGERT" aus der Tätigkeitsmaske. */
input[readonly], textarea[readonly] {
    color:var(--tinte);
    background-color:var(--flaeche-2);
    border-color:var(--rand);
    cursor:default;
}
input[readonly]:focus-visible, textarea[readonly]:focus-visible {
    border-color:var(--rand-stark);
}

::placeholder { color:var(--tinte-3); opacity:1; }


/* --- Pflichtangabe -----------------------------------------------------
   Pflichtangaben tragen WORT und Farbe. Eine rote Umrandung allein wäre
   für farbenblinde Leser keine Aussage (WCAG 1.4.1) - und ausgerechnet
   hier entscheidet sie darüber, ob die Freigabe später scheitert.

   >> EIN LEERES PFLICHTFELD IST KEIN FEHLER (AP-H17).
      Vorher: das Wort "(Pflichtangabe)" in Warnrot und dazu eine rote Kante
      am Feld - an JEDEM Pflichtfeld, vom ersten Aufschlagen an. Ein frisch
      geöffnetes Formular sah aus, als hätte man schon etwas falsch gemacht.
      Die Angabe bleibt, sie wird nur leiser: gewöhnliche Beitextfarbe für
      das Wort, eine ruhige Marke am Feld. Rot ist danach wieder das, was es
      sein soll - die Farbe eines tatsächlichen Fehlers.

   >> DIE MARKE IST EIN INNENSCHATTEN UND KEINE KANTE.
      `border-left:3px` hat dem Feld drei Pixel Innenraum genommen: Ein
      Pflichtfeld war zwei Pixel schmaler bedruckt als das Feld daneben, und
      der Text saß nicht mehr auf derselben Achse. Der Innenschatten liegt
      über der Fläche und rührt an keiner Kante.
   ---------------------------------------------------------------------- */

/* Beide Träger: `label.required` kommt aus dem Formularthema, die
   :has()-Formen aus den handgeschriebenen Masken. Ein Wortlaut, nicht zwei. */
label.required::after,
label:has(+ input[required])::after,
label:has(+ select[required])::after,
label:has(+ textarea[required])::after,
.feld:has(> input[required]) > label::after,
.feld:has(> select[required]) > label::after,
.feld:has(> textarea[required]) > label::after {
    content:" (Pflichtangabe)";
    font-size:var(--schrift-xs);
    font-weight:var(--fett-normal);
    color:var(--tinte-2);
}

input[required], select[required], textarea[required] {
    box-shadow:inset 3px 0 0 0 var(--rand-stark);
}


/* --- Der gemeldete Fehler ----------------------------------------------
   Erst der gemeldete Fehler färbt. Die zweite Kante entsteht als
   Außenschatten von 1px - so wird der Umriss sichtbar stärker, ohne dass
   das Feld um zwei Pixel wächst und die Zeile darunter verrutscht.
   ---------------------------------------------------------------------- */
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"],
.feld--fehler > input, .feld--fehler > select, .feld--fehler > textarea {
    border-color:var(--warn-rand, var(--warn));
    background-color:var(--warn-weich, color-mix(in srgb, var(--warn) 6%, transparent));
    box-shadow:inset 3px 0 0 0 var(--warn), 0 0 0 1px var(--warn-rand, var(--warn));
}
input[aria-invalid="true"]:focus-visible,
select[aria-invalid="true"]:focus-visible,
textarea[aria-invalid="true"]:focus-visible { border-color:var(--warn); }


/* --------------------------------------------------------------------------
   Hilfetext und Fehlertext — AM FELD

   `.help-text` erzeugt das Formularthema, `<small>` und `.hilfe` schreiben
   die handgeschriebenen Masken. Alle drei sind dieselbe Sache und sehen
   deshalb gleich aus.
   -------------------------------------------------------------------------- */
.help-text,
form small,
form .hilfe {
    display:block;
    margin:var(--raum-1) 0 var(--raum-4);
    max-inline-size:var(--breite-text);
    font-size:var(--schrift-sm);
    line-height:var(--zeile-normal);
    color:var(--tinte-2);
}

/* >> DER FEHLER STEHT AM FELD UND NICHT ALS KLUMPEN OBEN.
      Eine Liste von acht Rügen über einer Maske mit 48 Feldern nennt zwar
      alles, zeigt aber auf nichts: Man liest "Zweck fehlt" und sucht danach
      den Zweck. Die Rüge gehört unter ihr Feld - dort, wo die Hand schon
      ist. Der Klumpen oben behält seinen Sinn als ÜBERSICHT, wenn ein Feld
      in einer zugeklappten Gruppe steht (AP-H12); er ersetzt die Rüge am
      Feld aber nicht.

      Das Ausrufezeichen steht dort, weil die Fehlerzeile sonst nur an ihrer
      Farbe als Fehler erkennbar wäre (WCAG 1.4.1). Es sitzt in einer
      runden Marke: Der Sinn ist auf einen Blick abzulesen, ohne den Satz zu
      lesen. --raum-5 ist ihr Durchmesser, weil sie damit die Höhe einer
      Textzeile bei --schrift-sm hat und die Zeile nicht auseinanderdrückt. */
form ul:has(> li[id*="_error"]) {
    list-style:none;
    margin:var(--raum-1) 0 var(--raum-3);
    padding:0;
}
form li[id*="_error"],
.feldfehler {
    display:flex;
    align-items:start;
    gap:var(--raum-2);
    margin:var(--raum-1) 0 var(--raum-3);
    max-inline-size:var(--breite-text);
    font-size:var(--schrift-sm);
    font-weight:var(--fett-halb);
    line-height:var(--zeile-normal);
    color:var(--warn);
}
form li[id*="_error"]::before,
.feldfehler::before {
    content:"!";
    flex:0 0 auto;
    inline-size:var(--raum-5);
    block-size:var(--raum-5);
    font-size:var(--schrift-xs);
    font-weight:var(--fett-voll);
    line-height:var(--raum-5);
    text-align:center;
    color:var(--flaeche);
    background:var(--warn);
    border-radius:var(--radius-voll);
}


/* --------------------------------------------------------------------------
   Was die Zeile ihren Kindern abnimmt

   Der Abstand gehört der ZEILE (siehe oben). Diese Regeln nehmen ihn den
   Kindern wieder ab - und sie stehen HINTER allen Regeln, die ihn setzen.
   `.feld > small` (0,1,1) und `form small` (0,1,1) sind gleich spezifisch;
   entschieden hätte die Reihenfolge, und die falsche Reihenfolge ist der
   Fehler, an dem die beiden alten Blöcke gescheitert sind.
   -------------------------------------------------------------------------- */
.feld > label { margin:0; }
.feld > input, .feld > select, .feld > textarea { margin-block-end:0; }
.feld > .help-text, .feld > small, .feld > .hilfe { margin:0; }
.feld > ul:has(> li[id*="_error"]) { margin:0; }
.feld li[id*="_error"], .feld > .feldfehler { margin:0; }


/* --------------------------------------------------------------------------
   Die Feldgruppe

   >> `.feldgruppe` STEHT SEIT AP-B29 AUF <details> - IN ACHTZEHN VORLAGEN.
      Der Name bleibt und bekommt eine zweite Bauform: `fieldset.feldgruppe`.
      Die Regeln des aufklappbaren Kastens stehen weiter unten unter
      `details.feldgruppe` und sind hier nicht angetastet; die Selektoren
      tragen das Element mit, damit sich beide nicht in die Quere kommen.

   >> DER RAHMEN IST EIN BLATT, KEIN UMRISS AUF DEM GRUND (AP-H17).
      Wie die Tabelle. Eine Gruppe INNERHALB einer Gruppe ist eine Einlassung
      und liegt tiefer - zwei Stufen, mehr braucht die längste Maske nicht.

   >> DER INNENABSTAND UNTEN IST WIEDER DA.
      `form fieldset { padding:.9rem 1.1rem .1rem }` hatte unten fast keinen -
      der Abstand kam vom `margin-bottom` des letzten Feldes. Nimmt man dem
      Feld den Rand, klebt der Rahmen am Feld. Jetzt hat der Rahmen seinen
      eigenen Innenabstand, und die letzte Zeile gibt ihren Rand ab.
   -------------------------------------------------------------------------- */
fieldset, fieldset.feldgruppe {
    margin:0 0 var(--raum-5);
    padding:var(--raum-5);
    background:var(--flaeche);
    border:1px solid var(--rand);
    border-radius:var(--radius-md);
}
fieldset fieldset { background:var(--flaeche-2); }
fieldset fieldset fieldset { background:var(--flaeche-3, var(--flaeche-2)); }
fieldset > *:last-child { margin-block-end:0; }

/* >> DER GRUPPENTITEL STEHT IN VERSALIEN UND KLEIN (AP-H17).
      Er ist eine Beschriftung für einen Bereich und keine Überschrift: Er
      soll die Gruppe abgrenzen und nicht mit der Maskenüberschrift um den
      Blick streiten. Diese Regel war durch `form legend` (0,0,2) außer
      Kraft - die Versalien standen im Blatt und auf keiner Seite. */
legend {
    padding:0 var(--raum-2);
    margin-inline-start:calc(var(--raum-2) * -1);
    font-size:var(--schrift-xs);
    font-weight:var(--fett-stark);
    line-height:var(--zeile-normal);
    letter-spacing:.05em;
    text-transform:uppercase;
    color:var(--tinte-2);
}


/* --------------------------------------------------------------------------
   Das Feldraster

   >> DREIZEHN FELDER IN DREIZEHN ZEILEN BEI 28 PROZENT GENUTZTER BREITE.
      Die Personenmaske (templates/backoffice/person/detail.html.twig) stellt
      Anrede, Titel, Vorname, Nachname, Grad, Telefon, E-Mail, Funktion,
      Rechtsträger, Bereich, Eintritt und Bemerkung untereinander. Kein
      einziges dieser Felder braucht mehr als 22rem; rechts daneben bleiben
      auf einem gewöhnlichen Schirm über 40rem leer. Wer damit täglich
      arbeitet, scrollt durch Luft.

   >> auto-fill UND NICHT auto-fit - UMGEKEHRT ALS BEI DER KACHELLISTE.
      Dort faltet `auto-fit` die leeren Spuren zusammen, damit drei Kacheln
      die Breite nehmen statt links zu kleben. Hier ist genau das falsch:
      Fällt eine Spur weg, wächst das letzte Feld einer Zeile auf die
      doppelte Breite, und die Felder stehen nicht mehr untereinander. Ein
      Formular lebt von der senkrechten Achse. `auto-fill` hält die Spur
      leer und die Achse gerade.

   >> `min()` GEGEN DEN ÜBERLAUF.
      `minmax(18rem, 1fr)` allein lässt das Raster auf einem Schirm unter
      18rem breiter werden als die Seite - die Spur unterschreitet ihre
      Mindestbreite nicht. `min(var(--mindestbreite), 100%)` gibt sie unter
      der Schwelle frei.

   >> DIE MINDESTBREITE STEHT IN EINER KLASSE UND NICHT IN style="".
      `StilblattTest::keineWebVorlageTraegtEinInlineStilattribut` verbietet
      jedes Stilattribut in einer Web-Vorlage. Es gibt deshalb drei Stufen
      statt eines freien Wertes.
   -------------------------------------------------------------------------- */
.feldraster {
    --mindestbreite:18rem;
    display:grid;
    grid-template-columns:repeat(auto-fill, minmax(min(var(--mindestbreite), 100%), 1fr));
    gap:var(--raum-4) var(--raum-5);
    margin:0 0 var(--raum-5);
    align-items:start;
}
/* Kurze Felder - Datum, Zahl, Kennung, Postleitzahl. */
.feldraster--eng  { --mindestbreite:12rem; }
/* Felder mit langen Werten - Firmenwortlaut, Anschrift, Zweck in einer Zeile. */
.feldraster--weit { --mindestbreite:26rem; }

/* Im Raster trägt die LÜCKE den Abstand, nicht die Zeile - sonst steht
   zwischen zwei Reihen doppelt so viel Raum wie zwischen zwei Spalten. */
.feldraster > .feld { margin-block-end:0; }
/* Die Personenmaske und ihresgleichen hüllen jedes Feld in ein <p>. Bis die
   Vorlage auf .feld umgestellt ist, nimmt das Raster ihnen den Absatzrand ab. */
.feldraster > p { margin:0; }
.feldraster > .feld > input, .feldraster > .feld > select,
.feldraster > .feld > textarea, .feldraster > p > input,
.feldraster > p > select, .feldraster > p > textarea { margin-block-end:0; }


/* --------------------------------------------------------------------------
   Kontrollkästchen und Optionsfelder

   Beide Schreibweisen kommen vor - Beschriftung um das Feld herum
   (handgeschriebene Masken UND `checkbox_radio_label` des Formularthemas)
   und Feld vor Beschriftung.

   >> DIE GRÖSSE IST 20px UND NICHT DIE DES BROWSERS.
      Ein Kästchen in Systemgröße (13px) neben einer 14px-Beschriftung ist
      kleiner als der Buchstabe daneben. 20px = --raum-5 minus --raum-1 ist
      so groß wie die Zeile hoch ist und lässt sich auch mit dem Finger
      treffen.

   >> `align-items:start` UND NICHT `center`.
      Eine Beschriftung über zwei Zeilen mit `center` setzt das Kästchen in
      die Mitte des Absatzes - es zeigt dann auf nichts. Bei `start` steht es
      an der ersten Zeile. Dass es dort ohne Nachhilfe sitzt, ist Rechnung:
      Die Zeile ist --schrift-sm mal --zeile-normal = 21px hoch, das Kästchen
      20px - ein halbes Pixel Unterschied.

   >> DAS BERÜHRUNGSZIEL IST DIE GANZE ZEILE.
      Die Beschriftung neben dem Kästchen ist anklickbar, weil sie ein
      <label> ist; --hoehe-2 als Mindesthöhe macht daraus ein Ziel, das man
      auch mit dem Finger trifft (WCAG 2.5.8 verlangt 24px, hier sind es 36).
   -------------------------------------------------------------------------- */
input[type=checkbox], input[type=radio] {
    flex:0 0 auto;
    inline-size:calc(var(--raum-5) - var(--raum-1));
    block-size:calc(var(--raum-5) - var(--raum-1));
    margin:0;
    accent-color:var(--akzent);
    cursor:pointer;
}

label:has(> input[type=checkbox]),
label:has(> input[type=radio]),
.ankreuzfeld {
    display:flex;
    align-items:start;
    gap:var(--raum-2);
    min-block-size:var(--hoehe-2);
    margin:0;
    padding-block:var(--raum-1);
    max-inline-size:var(--breite-text);
    font-size:var(--schrift-sm);
    font-weight:var(--fett-normal);
    line-height:var(--zeile-normal);
    /* Ein Kästchen bringt seine Beschriftung selbst mit - die steht dann in
       Lesefarbe und nicht in der gedämpften Feldbeschriftungsfarbe. */
    color:var(--tinte);
    cursor:pointer;
}
label:has(> input[type=checkbox][disabled]),
label:has(> input[type=radio][disabled]) { color:var(--tinte-3); cursor:not-allowed; }

input[type=checkbox] + label, input[type=radio] + label {
    display:inline;
    margin:0 var(--raum-5) 0 var(--raum-2);
    font-size:var(--schrift-sm);
    font-weight:var(--fett-normal);
    color:var(--tinte);
    cursor:pointer;
}

/* Die Gruppe. Ohne sie stehen fünf Optionsfelder mit dem Abstand von fünf
   Absätzen untereinander und lesen sich als fünf Fragen statt als eine.
   `.feld > div` fängt die aufgefaltete Auswahl des Formularthemas mit ab -
   sie kommt als klassenloses <div> mit den <label>-Kindern. */
.ankreuzgruppe,
.feld > div:has(> label > input[type=checkbox]),
.feld > div:has(> label > input[type=radio]) {
    display:grid;
    gap:var(--raum-1);
}
/* Der Abstand nach unten steht nur an der frei gesetzten Gruppe - in der
   .feld-Zeile trägt ihn die Zeile. */
.ankreuzgruppe { margin:0 0 var(--raum-4); }
/* Zwei bis drei kurze Antworten stehen nebeneinander besser als
   untereinander - "ja / nein / unklar" ist eine Zeile und keine Liste. */
.ankreuzgruppe--waagrecht {
    display:flex;
    flex-wrap:wrap;
    gap:var(--raum-2) var(--raum-5);
}


/* --------------------------------------------------------------------------
   Der Schalter

   Ja/Nein an einem Zustand, der sofort gilt - "Portalzugang aktiv",
   "AV-Vertrag vereinbart". Er entsteht aus einem <input type=checkbox>: Das
   Feld bleibt, was es ist, und geht mit dem Formular hinaus wie jedes andere.
   Nur das Kästchen wird versteckt und durch Spur und Knopf ersetzt.

   >> DIE FARBE TRÄGT DIE AUSSAGE NICHT ALLEIN (WCAG 1.4.1).
      Ein Schalter sagt seinen Zustand dreifach: STELLUNG des Knopfes (links
      oder rechts), ZEICHEN im Knopf (Punkt oder Haken) und Farbe der Spur.
      Die ersten beiden sind farbunabhängig. Das Lesegerät bekommt den
      Zustand ohnehin vom Kästchen - deshalb ist die Spur aria-hidden und
      trägt kein eigenes Wort.

   >> WARUM DAS KÄSTCHEN NICHT `display:none` IST.
      Ein ausgeblendetes Feld ist für die Tastatur nicht erreichbar und
      schickt in manchen Browsern nichts mit. Es liegt deshalb durchsichtig
      über der Spur - anklickbar, fokussierbar, im Formular.
   -------------------------------------------------------------------------- */
.schalter {
    --schalter-spur:calc(var(--raum-5) * 1.75);   /* 42px */
    --schalter-hoehe:var(--raum-5);               /* 24px */
    --schalter-knopf:var(--raum-4);               /* 16px */

    position:relative;
    display:inline-flex;
    align-items:center;
    gap:var(--raum-3);
    min-block-size:var(--hoehe-2);
    margin:0;
    padding-block:var(--raum-1);
    font-size:var(--schrift-sm);
    font-weight:var(--fett-normal);
    line-height:var(--zeile-normal);
    color:var(--tinte);
    cursor:pointer;
}

.schalter > input[type=checkbox] {
    position:absolute;
    inset-block-start:0;
    inset-inline-start:0;
    inline-size:var(--schalter-spur);
    block-size:100%;
    margin:0;
    opacity:0;
    cursor:pointer;
}

.schalter__spur {
    position:relative;
    flex:0 0 auto;
    inline-size:var(--schalter-spur);
    block-size:var(--schalter-hoehe);
    background:var(--flaeche-3, var(--flaeche-2));
    border:1px solid var(--rand-stark);
    border-radius:var(--radius-voll);
    transition:background-color var(--dauer-normal) var(--stufe),
               border-color var(--dauer-normal) var(--stufe);
}

/* Der Knopf. --raum-1 Spiel ringsum, so bleibt er in der Spur.
   `calc(… - 1px)` zieht die Kante ab, die border-box mitrechnet. */
.schalter__spur::after {
    content:"·";
    position:absolute;
    inset-block-start:calc(var(--raum-1) - 1px);
    inset-inline-start:calc(var(--raum-1) - 1px);
    inline-size:var(--schalter-knopf);
    block-size:var(--schalter-knopf);
    font-size:var(--schrift-sm);
    font-weight:var(--fett-voll);
    line-height:var(--schalter-knopf);
    text-align:center;
    color:var(--tinte-3);
    background:var(--flaeche);
    border-radius:var(--radius-voll);
    box-shadow:var(--schatten-sm);
    transition:transform var(--dauer-normal) var(--stufe),
               color var(--dauer-normal) var(--stufe);
}

.schalter > input[type=checkbox]:checked ~ .schalter__spur {
    background:var(--akzent);
    border-color:var(--akzent-dunkel, var(--akzent));
}
.schalter > input[type=checkbox]:checked ~ .schalter__spur::after {
    content:"✓";
    color:var(--akzent);
    /* Weg = Spurbreite minus Knopf minus zweimal Spiel. */
    transform:translateX(calc(var(--schalter-spur) - var(--schalter-knopf) - var(--raum-2)));
}

.schalter > input[type=checkbox]:focus-visible ~ .schalter__spur {
    outline:2px solid var(--akzent-hell);
    outline-offset:2px;
}
.schalter > input[type=checkbox][disabled] ~ .schalter__spur {
    background:var(--flaeche-2);
    border-color:var(--rand);
}
.schalter:has(> input[type=checkbox][disabled]) { color:var(--tinte-3); cursor:not-allowed; }

.schalter__text { min-inline-size:0; }


/* --------------------------------------------------------------------------
   Das Suchfeld

   >> DER SUCHBEGRIFF GEHT MIT POST (§ 10, AP-H19).
      Was in der Adresse steht, steht im Zugriffsprotokoll des Webservers, und
      wonach hier gesucht wird, ist im Regelfall ein Name. Enumerierte Werte
      dürfen in die Adresse, Eingaben nicht. Das Suchfeld ist deshalb KEIN
      eigenes Bauteil mit eigenem Weg nach draußen, sondern die Bauform eines
      POST-Formulars - `VorlagenTest::keinFreitextGehtInDieAdresse` prüft das
      für jede Vorlage.

      Auch der Löschknopf ist deshalb ein `type=submit` und kein `type=reset`:
      Zurücksetzen lässt den Server im alten Stand stehen, die Liste zeigt
      weiter die alten Treffer, und niemand sieht warum. Der Knopf schickt
      `leeren=1` im RUMPF; ohne JavaScript, ohne Adresse, ohne Umweg.

   >> DAS SYMBOL KOMMT AUS DEM SYMBOLSATZ, NICHT AUS EINER SCHRIFT.
      `<use href="#i-suche">` schöpft aus `layout/_symbole.html.twig`. Keine
      Symbolschrift, kein url(), kein zweiter Ausgang (§ 1).

   >> DIE KANTE LIEGT AM MANTEL UND NICHT AM FELD.
      Symbol, Eingabe und Löschknopf sollen wie EIN Bedienelement aussehen.
      Der Mantel trägt deshalb Kante, Fläche und Höhe; die Eingabe darin
      ist blank. Der Fokusring wandert mit `:focus-within` an den Mantel -
      sonst umringt er ein unsichtbares Feld in einem sichtbaren Rahmen.
   -------------------------------------------------------------------------- */
.suchfeld {
    display:grid;
    grid-template-columns:auto 1fr auto;
    align-items:center;
    gap:var(--raum-2);
    inline-size:100%;
    max-inline-size:var(--feldbreite, var(--feldbreite-mittel));
    block-size:var(--hoehe-2);
    padding-inline:var(--raum-3);
    background-color:var(--flaeche);
    border:1px solid var(--rand-stark);
    border-radius:var(--radius-voll);
    transition:border-color var(--dauer-schnell) var(--stufe);
}
.suchfeld:hover { border-color:var(--akzent-hell); }
.suchfeld:focus-within {
    border-color:var(--akzent);
    outline:2px solid var(--akzent-hell);
    outline-offset:2px;
}

/* Strichzeichnung wie in der Gliederung: Sie erbt die Schriftfarbe und steht
   leiser als das Wort daneben. */
.suchfeld__symbol {
    inline-size:var(--raum-4);
    block-size:var(--raum-4);
    fill:none;
    stroke:var(--tinte-2);
    stroke-width:1.75;
    stroke-linecap:round;
    stroke-linejoin:round;
}

/* `.suchfeld > input` und nicht `.suchfeld__eingabe` allein: Die Klasse hat
   (0,1,0) und hätte gegen `input[type=search]` (0,1,1) aus dem Grundblock
   verloren - die Eingabe hätte ihre eigene Kante behalten und im Mantel
   ein zweites Feld gezeichnet. */
.suchfeld > input, input.suchfeld__eingabe {
    inline-size:100%;
    max-inline-size:none;
    block-size:100%;
    margin:0;
    padding:0;
    font-family:inherit;
    font-size:var(--schrift-sm);
    color:var(--tinte);
    background:none;
    border:0;
    border-radius:0;
}
/* Der Ring sitzt am Mantel, nicht am Feld darin - sonst umringt er ein
   unsichtbares Feld in einem sichtbaren Rahmen. */
.suchfeld > input:focus-visible, input.suchfeld__eingabe:focus-visible { outline:none; }
/* Der Browser bringt sein eigenes Löschkreuz mit. Es antwortet nur auf die
   Maus, kennt kein POST und lässt den Server im alten Stand - der Knopf
   daneben tut beides. Zwei Kreuze nebeneinander wären eine Frage zu viel. */
.suchfeld > input::-webkit-search-cancel-button {
    -webkit-appearance:none;
    appearance:none;
}

.suchfeld__leeren {
    display:grid;
    place-items:center;
    inline-size:var(--raum-5);
    block-size:var(--raum-5);
    padding:0;
    font-family:inherit;
    font-size:var(--schrift-md);
    line-height:1;
    color:var(--tinte-2);
    background:none;
    border:0;
    border-radius:var(--radius-voll);
    cursor:pointer;
}
.suchfeld__leeren:hover {
    color:var(--tinte);
    background:var(--flaeche-2);
    box-shadow:none;
}


/* --------------------------------------------------------------------------
   Zeilenformulare

   Ein Formular in einer Zeile - Filter über einer Liste, ein Knopf mit einem
   Feld daneben, ein Vermerk in einer Tabellenzelle. Es ist keine Maske und
   soll nicht wie eine aussehen.

   >> `.formular-zeile` STAND IN SECHS VORLAGEN UND IN KEINER REGEL.
      Die Klasse gab es nur im Markup; ausgesehen hat sie wie gar nichts -
      Feld unter Beschriftung unter Knopf, in voller Breite. Sie ist der
      gleiche Gegenstand wie `.formular-inline` und bekommt dieselben Regeln.
   -------------------------------------------------------------------------- */
.formular-inline, .formular-zeile {
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:var(--raum-2);
    margin:0 0 var(--raum-4);
    max-inline-size:none;
}
.formular-inline > label, .formular-zeile > label { margin:0; }
.formular-inline input, .formular-inline select, .formular-inline textarea,
.formular-zeile input, .formular-zeile select, .formular-zeile textarea {
    inline-size:auto;
    margin-block-end:0;
}

/* Formular in einer Tabellenzelle: eine Zeile, keine Spalte. Die Felder
   laufen auf --hoehe-1 - das ist die Bedienhöhe der Zelle, und eine Zeile
   mit einem Feld darin soll nicht doppelt so hoch sein wie die daneben. */
td form {
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:var(--raum-1);
    margin:0;
    max-inline-size:none;
}
td form label { margin:0; }
/* `input[type]` und nicht `input`: `td form input` wäre (0,0,3) und hätte
   gegen `input[type=text]` (0,1,1) verloren - das Feld in der Zelle wäre
   auf voller Maskenhöhe stehen geblieben. Ein Eingabefeld ohne
   type-Attribut kommt in einer Zelle nicht vor. */
td form input[type], td form select, td form textarea {
    block-size:var(--hoehe-1);
    margin-block-end:0;
    /* 16rem: die Breite, in der eine Zelle noch eine Zelle bleibt. Der Wert
       stand schon vorher hier und hat sich bewährt. */
    max-inline-size:16rem;
    font-size:var(--schrift-sm);
}
td form textarea { block-size:auto; min-block-size:var(--hoehe-1); }

/* Die Anmeldung ist die eine Maske, in der ein Feld groß sein darf: Sie hat
   zwei davon, sie steht auf einer leeren Seite, und sie ist der erste
   Eindruck. --hoehe-3 ist dafür da. Die übrigen Angaben zu .huelle stehen
   in der Seitenschale und bleiben dort. */
.huelle input[type=text], .huelle input[type=password],
.huelle input[type=email], .feld--gross > input, .feld--gross > select {
    block-size:var(--hoehe-3);
    padding-block:0;
    font-size:var(--schrift-md);
}


/* --------------------------------------------------------------------------
   Sammlungen

   Das Formularthema hängt `data-prototype` an den Behälter. Jede Zeile
   bekommt einen eigenen Rahmen, sonst laufen mehrere Untereinträge optisch
   ineinander - und man sieht nicht, wo ein Empfänger aufhört und der
   nächste anfängt.
   -------------------------------------------------------------------------- */
form [data-prototype] > div {
    margin:0 0 var(--raum-3);
    padding:var(--raum-4);
    background:var(--flaeche-2);
    border:1px solid var(--rand-weich);
    border-radius:var(--radius-sm);
}
form [data-prototype] > div > *:last-child { margin-block-end:0; }


/* --------------------------------------------------------------------------
   Bewegung

   Die einzigen Bewegungen im Formular sind Zustandsübergänge an Kante,
   Fläche und Schalterknopf. Wer sie abbestellt hat, bekommt sie nicht.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    input, select, textarea, .suchfeld,
    .schalter__spur, .schalter__spur::after { transition:none; }
}


/* ==========================================================================
   MARKEN, MELDUNGEN, DIALOGE, LADEZUSTAND
   ========================================================================== */

/* ==========================================================================
   MARKEN, MELDUNGEN, DIALOGE, LADEZUSTAND

   Vier Bauteile mit derselben Aufgabe: Sie sagen, was gerade der Fall ist.
   Bis hierher lagen sie an neun Stellen des Blattes verstreut und
   widersprachen sich dabei:

     - `.marke` war viermal definiert (Zeile 700, 1039, 2019, 2259), und
       `marke--offen` bedeutete in einer Tabellenzelle Rot (Gefahr) und einen
       Absatz weiter Ocker (Reihenfolge). Dieselbe Marke, zwei Aussagen.
     - `.meldung` war zweimal wortgleich definiert (Zeile 1026 und 2238).
     - `.fortschrittsbalken` war zweimal WIDERSPRÜCHLICH definiert (Zeile 867
       überlagernd, Zeile 2118 nebeneinander). Die zweite gewann, die erste
       stand als toter Text im Blatt.
     - Das Ladezeichen von htmx hatte seit AP-H15 eine Regel, aber keinen
       Körper: `.htmx-indicator` schaltet Sichtbarkeit, und sichtbar wurde
       nichts, weil es nichts zu sehen gab.

   Die Begründungen der ersetzten Regeln sind mitgenommen und fortgeschrieben,
   nicht weggeworfen — sie stehen jeweils über ihrem Nachfolger.
   ========================================================================== */


/* ==========================================================================
   1. MARKEN — das Zustandskürzel

   >> EINE FAMILIE STATT VIER EINZELREGELN.

   Eine Marke ist ein Wort mit Rahmen. Sie steht in Tabellenzellen, in
   Vorschlagsköpfen und hinter Überschriften; sie ist nie ein Bedienelement und
   trägt deshalb auch keine Bedienhöhe.

   >> DIE FARBE TRÄGT NIE ALLEIN (WCAG 1.4.1).
   Jede Marke enthält ihr Wort — „erfüllt", „offen", „als Nächstes",
   „entfallen", „gesetzlich". Die Farbe ordnet ein, was der Wortlaut bereits
   sagt; wer sie nicht unterscheidet, verliert nichts.

   >> WARUM `:is(main, .karte)` UND NICHT NUR `main`.
   `.marke` heißt im Seitenkopf auch die Wortmarke der Anwendung (Zeile 241).
   Der Nachfahrenselektor hält die Zustandsmarke von ihr fern — das war schon
   die Absicht der alten Regel. `main` allein reichte aber nicht:
   `layout/schlank.html.twig` hat kein `<main>`, sondern eine `.karte`, und die
   elf Masken darauf (Anmeldung, Mandantenauswahl, beide Zwei-Faktor-Wege, die
   drei Einladungsmasken) zeigten ihre Marken bisher gänzlich ungestaltet.

   Die früher nötige Absicherung `:not(.marke-gesetzlich)` entfällt: Sie stand
   nur da, weil die Rechtsfolgen-Marke 340 Zeilen VOR der Grundregel lag und
   deshalb verlor. Jetzt steht sie dahinter und gewinnt ohne Kunstgriff.
   ========================================================================== */

:is(main, .karte) .marke {
    display:inline-flex; align-items:center; gap:var(--raum-1);
    padding:var(--raum-1) var(--raum-2);
    font-size:var(--schrift-xs); font-weight:var(--fett-stark);
    line-height:var(--zeile-eng); letter-spacing:.04em; text-transform:uppercase;
    white-space:nowrap; vertical-align:middle;
    color:var(--tinte-2); background:var(--flaeche-2);
    border:1px solid var(--rand); border-radius:var(--radius-voll);
}

/* Marken stehen fast immer zu mehreren nebeneinander (Tabellenzelle,
   Vorschlagskopf). Die Lücke gehört an die Marke: In der Vorlage stünde sie
   als `&nbsp;` und wäre weder auffindbar noch änderbar. */
:is(main, .karte) .marke + .marke { margin-left:var(--raum-1); }

/* >> DER ZUSTANDSPUNKT ERSETZT KEIN WORT.
   Er beschleunigt das Auffinden beim Blick über eine lange Liste; die Aussage
   steht weiter im Text der Marke. Der Punkt mißt drei Viertel von `--raum-2`
   (6px): auf voller Höhe wirkte er wie ein Aufzählungszeichen, auf halber wie
   ein Staubkorn. */
:is(main, .karte) .marke--punkt::before {
    content:""; flex:none;
    width:calc(var(--raum-2) * .75); height:calc(var(--raum-2) * .75);
    border-radius:var(--radius-voll); background:currentColor;
}

/* Die fünf Zustände. Kante UND getönte Fläche — eine Marke, die nur eine Kante
   hat, verschwindet in einer Tabelle mit einundzwanzig Spalten. */
:is(main, .karte) .marke--gut     { color:var(--gut);     background:var(--gut-weich);     border-color:var(--gut-rand); }
:is(main, .karte) .marke--warn    { color:var(--warn);    background:var(--warn-weich);    border-color:var(--warn-rand); }
:is(main, .karte) .marke--hinweis { color:var(--hinweis); background:var(--hinweis-weich); border-color:var(--hinweis); }
:is(main, .karte) .marke--akzent  { color:var(--akzent);  background:var(--akzent-weich);  border-color:var(--akzent); }
:is(main, .karte) .marke--ruhig   { color:var(--tinte-3); background:var(--flaeche-2);     border-color:var(--rand-weich); }

/* >> DIE BESTEHENDEN NAMEN BLEIBEN. Sechzehn Fundstellen zeigen auf sie.
   `--ok` und `--offen` sind die Namen aus dem Bestand; sie sind jetzt
   Zweitnamen von `--gut` und `--hinweis`.

   `--offen` ist mit Absicht HINWEIS und nicht WARN. Die alte Sonderregel
   `td .marke--offen` färbte dieselbe Marke in der Tabellenzelle rot. „Als
   Nächstes" ist aber keine Störung, sondern eine Reihenfolge — wer sie rot
   färbt, erzieht zum Wegsehen. */
:is(main, .karte) .marke--ok    { color:var(--gut);     background:var(--gut-weich);     border-color:var(--gut-rand); }
:is(main, .karte) .marke--offen { color:var(--hinweis); background:var(--hinweis-weich); border-color:var(--hinweis); }

/* `.warnung` auf einer Marke (zehn Fundstellen). Sie färbte bisher nur die
   Schrift und ließ die Kante grau — die Marke sah aus wie ein Fehldruck. */
:is(main, .karte) .marke.warnung { color:var(--warn); background:var(--warn-weich); border-color:var(--warn-rand); }

/* „entfallen" in der TOM-Liste. Der Durchstrich ist die zweite, farbfreie
   Aussage neben der gedämpften Tinte (WCAG 1.4.1). */
:is(main, .karte) .marke-abgelaufen {
    color:var(--tinte-3); background:var(--flaeche-2); border-color:var(--rand-weich);
    text-decoration:line-through; text-decoration-thickness:1px;
}

/* >> DIE RECHTSFOLGEN-MARKE MACHT EINE STÄRKERE AUSSAGE ALS JEDE ZUSTANDSMARKE.
   „gesetzlich" heißt: Hier steht eine Pflicht und keine Einstellung. Sie steht
   deshalb in voller Warnfarbe auf getönter Fläche und nicht in der gedämpften
   Grundfassung. Drei Vorlagen setzen sie OHNE `.marke` daneben — der Selektor
   trägt deshalb die ganze Gestalt und nicht bloß die Farbe. */
:is(main, .karte) .marke-gesetzlich {
    display:inline-flex; align-items:center; gap:var(--raum-1);
    margin-left:var(--raum-1); padding:var(--raum-1) var(--raum-2);
    font-size:var(--schrift-xs); font-weight:var(--fett-stark);
    line-height:var(--zeile-eng); letter-spacing:.04em; text-transform:uppercase;
    white-space:nowrap; vertical-align:middle;
    color:var(--warn); background:var(--warn-weich);
    border:1px solid var(--warn); border-radius:var(--radius-voll);
}

/* Im Vorschlagskopf steht die Marke allein über dem Titel und braucht Luft
   nach unten. Die früher hier stehende Vollfassung (Zeile 2019) war eine
   wortgleiche Kopie der Grundregel und ist entfallen. */
.vorschlag .marke { margin:0 0 var(--raum-2); }


/* ==========================================================================
   2. DER KASTEN IN DER MASKE

   `p.hinweis` (144 Fundstellen), `p.warnung` (63), `p.fehler` (38),
   `p.erfolg` (11), dazu `div.hinweis` und `div.fehler`: Das ist NICHT die
   Rückmeldung nach dem Absenden, sondern die Erläuterung an Ort und Stelle.
   Sie gehört dorthin, wo sie etwas erklärt, und wandert nicht an den
   Seitenkopf.

   >> DER KASTEN IST FARBIG, DER TEXT NICHT (AP-H17).

   Vorher stand der ganze Absatz in der Meldungsfarbe — ein Hinweis war ein
   olivbrauner Block über sechs Zeilen. Bei mehreren Kästen auf einer Maske
   wird daraus eine Wand aus Farbe, und die Aussage geht in ihr unter.

   Die Farbe trägt die Kante und die Fläche; der Text steht in der gewöhnlichen
   Tinte und ist damit lesbar wie jeder andere. Die Zuordnung bleibt doppelt
   gesichert — Kante UND Wortlaut (WCAG 1.4.1).

   NEU dazu: eine feine Kante rundherum. Ohne sie schwebte die getönte Fläche
   randlos in der Seite und war bei sechs Prozent Tönung kaum vom Papier zu
   unterscheiden.

   Drei Kategorien, nicht zwei. „Fehler" und „Erfolg" reichen nicht für den
   Fall, den AP-F16 häufig erzeugt: Es ist etwas ABSICHTLICH stehen geblieben.
   Das ist kein Fehlschlag — es ist die Regel, die greift. Wer es rot färbt,
   erzieht zum Wegklicken.
   ========================================================================== */

p.fehler, p.erfolg, p.hinweis, p.warnung,
div.fehler, div.hinweis, .hinweiskasten {
    margin:0 0 var(--raum-5); padding:var(--raum-3) var(--raum-4);
    max-width:var(--breite-text);
    font-size:var(--schrift-sm); line-height:var(--zeile-weit);
    color:var(--tinte); background:var(--flaeche-2);
    border:1px solid var(--rand);
    border-left:3px solid var(--rand-stark);
    border-radius:0 var(--radius-sm) var(--radius-sm) 0;
}

p.fehler, div.fehler   { border-left-color:var(--warn);    background:var(--warn-weich); }
p.warnung              { border-left-color:var(--warn);    background:var(--warn-weich); }
p.erfolg               { border-left-color:var(--gut);     background:var(--gut-weich); }
p.hinweis, div.hinweis { border-left-color:var(--hinweis); background:var(--hinweis-weich); }

/* Doppelte Klasse, damit der Modifikator gegen `p.hinweis` gewinnt, ohne daß
   dessen Regel angefaßt werden muß. Beide Schreibweisen liegen im Bestand:
   `hinweis--warnung` (sechs Fundstellen) und `hinweis-warnung` (zwei). */
.hinweis.hinweis--warnung, .hinweis.hinweis-warnung {
    border-left-color:var(--warn); background:var(--warn-weich);
}
.hinweis.hinweis--gut { border-left-color:var(--gut); background:var(--gut-weich); }

/* Die fetten Stellen darin tragen die Meldungsfarbe — dort ist sie eine
   Auszeichnung und keine Fläche. */
p.fehler strong, div.fehler strong, p.warnung strong { color:var(--warn); }
p.erfolg strong { color:var(--gut); }
p.hinweis strong, div.hinweis strong { color:var(--tinte); font-weight:var(--fett-stark); }

/* Der Freigabe-Abweis (`vt/freigeben`) ist ein `div.fehler` mit Überschrift.
   Die Überschrift ist eine Auszeichnung wie `strong` und darf farbig sein. */
div.fehler > h2, div.hinweis > h2 {
    margin:0 0 var(--raum-2);
    font-size:var(--schrift-lg); line-height:var(--zeile-eng);
}
/* Die Ueberschrift steht in Tinte, nicht in Warnrot: Der Kasten traegt
   seit AP-H17 die Farbe in Kante und Flaeche, der Text ist lesbar wie
   jeder andere. Warnrot auf warngetoenter Flaeche waere der Rueckfall. */

/* Ein Kasten mit mehreren Absätzen darf innen keine doppelten Ränder sammeln —
   den Abstand setzt der Kasten, nicht sein Inhalt. */
.hinweis > :first-child, .hinweiskasten > :first-child { margin-top:0; }
.hinweis > :last-child,  .hinweiskasten > :last-child  { margin-bottom:0; }
div.hinweis p { margin:0 0 var(--raum-2); }
div.hinweis p:last-child { margin:0; }
div.hinweis ul, .hinweiskasten ul { margin:var(--raum-2) 0; padding-left:var(--raum-5); }
div.hinweis li, .hinweiskasten li { margin:var(--raum-1) 0; }

/* In den Hinweisen stehen Konsolenaufrufe (`portal/rollout`, `vertretung`). */
.hinweis code, .hinweiskasten code {
    font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
    font-size:.88em; color:var(--tinte);
    padding:0 var(--raum-1); border-radius:var(--radius-xs);
    background:var(--flaeche-3);
}

/* >> `.warnung` UND `.hinweis` SIND AUCH REINE TEXTAUSZEICHNUNGEN.
   Sie sitzen in Kennzahlen und in Tabellenzellen. Ein Kasten würde die
   Kennzahlenzeile zerreißen — und die Aussage steht ohnehin im Text, die Farbe
   hebt sie nur hervor (WCAG 1.4.1 ist damit erfüllt, weil die Farbe nichts
   trägt, was der Wortlaut nicht sagt). */
.warnung { color:var(--warn); }
strong.warnung, span.warnung { font-weight:var(--fett-stark); }
span.hinweis { color:var(--hinweis); font-weight:var(--fett-halb); }
/* Die Kennzahlenzeile raeumt ihre Meldungsklassen selbst ab - siehe
   Abschnitt FLAECHEN. Dort sind es alle vier Klassen und beide Traeger. */


/* ==========================================================================
   3. DIE MELDUNG UND IHR HAFTENDER STAPEL

   >> DIE RÜCKMELDUNG ERSCHIEN ZWEITAUSEND PIXEL ÜBER DER ARBEITSSTELLE.

   `app.flashes()` gibt oben in `<main>` aus. Wer in der Fristenliste bei Zeile
   180 einen Knopf drückt, landet nach der Umleitung wieder bei Zeile 1 — und
   rollt zurück an seine Stelle, wobei die Meldung aus dem Bild verschwindet.
   Er weiß dann nicht, ob gespeichert wurde. Genau deshalb haftet der Stapel
   jetzt unter der Kopfleiste.

   >> ER DECKT DABEI DEN FESTSTEHENDEN TABELLENKOPF ZU, UND ZWAR ABSICHTLICH.
   `thead th` haftet auf derselben Höhe (Zeile 2771). Eine Rückmeldung, die ein
   Mensch noch nicht gelesen hat, ist wichtiger als eine Spaltenüberschrift, die
   er lesen kann, sobald er die Meldung geschlossen hat. Deshalb liegt der
   Stapel eine Ebene darüber — und deshalb hat er einen Schließknopf.

   Der Untergrund ist `--grund`: Der Stapel steht im Inhaltsfeld von `main`,
   und dessen Polsterung ist leer — dort kann nichts durchscheinen.

   ZUORDNUNG DER ROLLEN, verbindlich für jede Vorlage:
     `--fehler` / `--warn`    → `role="alert"`   (unterbricht das Lesegerät)
     `--erfolg` / `--hinweis` → `role="status"`  (wird eingereiht)
   Ein `role="alert"` auf einer Erfolgsmeldung unterbricht den Vorleser bei
   jedem Speichern; ein `role="status"` auf einem Fehler geht unter.
   ========================================================================== */

.meldungen {
    position:sticky; top:var(--kopfleiste-hoehe);
    z-index:calc(var(--ebene-haftend) + 1);
    display:grid; gap:var(--raum-2);
    margin:0 0 var(--raum-5); padding:var(--raum-2) 0;
    background:var(--grund);
}

.meldung {
    display:flex; flex-wrap:wrap; align-items:flex-start; gap:var(--raum-3);
    margin:0 0 var(--raum-4); padding:var(--raum-3) var(--raum-4);
    font-size:var(--schrift-sm); line-height:var(--zeile-normal);
    color:var(--tinte); background:var(--flaeche-2);
    border:1px solid var(--rand); border-left-width:3px;
    border-radius:var(--radius-sm);
    box-shadow:var(--schatten-sm);
}
/* Im Stapel setzt die Lücke den Abstand, nicht der Außenrand. */
.meldungen > .meldung { margin:0; }

/* Das Zeichen ist Zierde und wird vom Lesegerät nicht gelesen
   (`aria-hidden="true"` in der Vorlage). Es trägt `--flaeche` als Schriftfarbe
   und nicht ein festes Weiß: Im Dunkelmodus kippt die Füllfarbe nach hell, die
   Schrift muß dann dunkel werden. Dieselbe Vorkehrung wie beim Grundknopf. */
.meldung__zeichen {
    flex:none; display:grid; place-items:center;
    width:var(--raum-5); height:var(--raum-5);
    font-size:var(--schrift-xs); font-weight:var(--fett-voll); line-height:1;
    color:var(--flaeche); background:var(--tinte-3);
    border-radius:var(--radius-voll);
}

/* `20rem` ist keine Raumangabe, sondern die Umbruchschwelle: Darunter passen
   Text und Handlung nicht mehr nebeneinander, und die Handlung rutscht in die
   nächste Zeile. Dieselbe Bauart wie `form.tom-zeile textarea`. */
.meldung__text { flex:1 1 20rem; min-width:0; display:grid; gap:var(--raum-1); }
.meldung__text > p { margin:0; max-width:var(--breite-text); }
.meldung__titel {
    font-size:var(--schrift-md); font-weight:var(--fett-stark);
    line-height:var(--zeile-eng); color:var(--tinte);
}

/* Die Handlung in der Meldung ist der eigentliche Gewinn: „Nicht gespeichert"
   ohne Weg zurück zwingt zum Suchen. Sie sieht aus wie ein zurückhaltender
   Knopf und nicht wie ein Verweis im Fließtext — deshalb kein Unterstrich. */
.meldung__handlung {
    flex:none; align-self:center;
    display:inline-flex; align-items:center;
    min-height:var(--hoehe-2); padding:0 var(--raum-3);
    font-size:var(--schrift-sm); font-weight:var(--fett-stark);
    white-space:nowrap; text-decoration:none;
    color:var(--tinte); background:var(--flaeche);
    border:1px solid var(--rand-stark); border-radius:var(--radius-xs);
    transition:background-color var(--dauer-schnell) var(--stufe);
}
.meldung__handlung:hover { background:var(--flaeche-2); text-decoration:none; }

/* Der Schließknopf ist eine Nebenhandlung und trägt deshalb `--hoehe-1`. Alle
   Farben stehen ausdrücklich da: Der Grundknopf des Blattes ist gefüllt,
   dieser hier darf es nicht sein. */
.meldung__schliessen {
    flex:none; align-self:flex-start;
    display:grid; place-items:center;
    width:var(--hoehe-1); height:var(--hoehe-1); padding:0;
    font-size:var(--schrift-md); font-weight:var(--fett-normal); line-height:1;
    color:var(--tinte-2); background:transparent;
    border:1px solid transparent; border-radius:var(--radius-xs);
    cursor:pointer;
}
.meldung__schliessen:hover {
    color:var(--tinte); background:var(--flaeche); border-color:var(--rand);
}

/* Die vier Zustände. Sie stehen NACH der Grundregel und gewinnen dadurch; die
   Reihenfolge `border-color` vor `border-left-color` ist tragend. */
.meldung--fehler, .meldung--warn {
    border-color:var(--warn-rand); border-left-color:var(--warn);
    background:var(--warn-weich);
}
.meldung--fehler .meldung__zeichen, .meldung--warn .meldung__zeichen { background:var(--warn); }

.meldung--erfolg, .meldung--gut {
    border-color:var(--gut-rand); border-left-color:var(--gut);
    background:var(--gut-weich);
}
.meldung--erfolg .meldung__zeichen, .meldung--gut .meldung__zeichen { background:var(--gut); }

.meldung--hinweis {
    border-color:var(--hinweis); border-left-color:var(--hinweis);
    background:var(--hinweis-weich);
}
.meldung--hinweis .meldung__zeichen { background:var(--hinweis); }

/* Das schlanke Layout (Anmeldung, Mandantenauswahl, Zwei-Faktor-Wege) hat
   keine Kopfleiste, an der etwas haften könnte — `--kopfleiste-hoehe` wäre
   dort ein Abstand ins Nichts, und die Meldung stünde beim Rollen unter dem
   Kartenkopf statt darüber. */
.welt-schlank .meldungen { position:static; }

/* Der Auftritt ist kurz und einmalig. Er sagt: Das hier ist neu und stand eben
   noch nicht da. Wer Bewegung abbestellt hat, bekommt sie nicht. */
@keyframes meldung-auftritt {
    from { opacity:0; transform:translateY(calc(var(--raum-2) * -1)); }
}
.meldungen > .meldung { animation:meldung-auftritt var(--dauer-normal) var(--stufe); }

@media (prefers-reduced-motion: reduce) {
    .meldungen > .meldung { animation:none; }
    .meldung__handlung { transition:none; }
}


/* ==========================================================================
   4. DER DIALOG

   >> `<dialog>` UND KEINE ÜBERLAGERUNG VON HAND.

   Ein selbstgebautes Overlay müßte vier Dinge nachbauen, die der Browser schon
   kann: den Fokusfang, das Schließen mit Esc, die oberste Ebene über der
   feststehenden Kopfleiste und das Verbergen des Hintergrunds für Lesegeräte.
   Jedes davon einzeln ist eine Fehlerquelle; zusammen sind sie der Grund,
   warum selbstgebaute Dialoge mit der Tastatur unbedienbar sind.

   `showModal()` bringt alle vier mit. Was bleibt, ist ein Stimulus-Controller
   mit zwei Methoden: `assets/controllers/dialog_controller.js`.

   >> `.dialog[open]` UND NICHT `.dialog`.
   Der Browser verbirgt einen geschlossenen `<dialog>` mit `display:none` aus
   seinem eigenen Stilblatt. Jede Autorenregel gewinnt dagegen — ein
   `.dialog { display:flex }` ließe den Dialog dauerhaft offen stehen.

   >> DER HINTERGRUND IST EIN SCHLEIER AUS `--grund` UND KEIN FESTES SCHWARZ.
   Im Hellmodus wäscht er die Seite nach Weiß aus, im Dunkelmodus nach Schwarz —
   beides richtig, und der Dunkelmodus kippt weiterhin allein über Tokens.
   Fällt bei `::backdrop` die Vererbung der Variablen aus (Browser vor Chrome
   122, Firefox 118, Safari 17.4), bleibt der Schleier weg; der Dialog steht
   dann auf seinem Schatten. Kein Ausfall, nur weniger Trennung.
   ========================================================================== */

.dialog {
    width:min(var(--breite-text), calc(100vw - var(--raum-6)));
    max-height:calc(100dvh - var(--raum-8));
    padding:0; margin:auto;
    color:var(--tinte); background:var(--flaeche);
    border:1px solid var(--rand); border-radius:var(--radius-lg);
    box-shadow:var(--schatten-schwebend);
    z-index:var(--ebene-ueberlagerung);
}
.dialog[open] { display:flex; flex-direction:column; }
.dialog--breit { width:min(var(--breite-masse), calc(100vw - var(--raum-6))); }

.dialog::backdrop {
    background:color-mix(in srgb, var(--grund) 78%, transparent);
    backdrop-filter:blur(3px);
}

/* Kopf und Fuß stehen fest, der Rumpf rollt. Ein Dialog, dessen Absendeknopf
   unter dem Bildschirmrand liegt, ist einer, den niemand absendet. */
.dialog__kopf {
    flex:none; display:flex; align-items:flex-start; gap:var(--raum-3);
    padding:var(--raum-4) var(--raum-5);
    border-bottom:1px solid var(--rand-weich);
}
.dialog__kopf > h2 {
    margin:0; font-size:var(--schrift-lg); font-weight:var(--fett-stark);
    line-height:var(--zeile-eng); color:var(--tinte);
}
.dialog__beitext {
    margin:var(--raum-1) 0 0;
    font-size:var(--schrift-sm); line-height:var(--zeile-normal); color:var(--tinte-2);
}

.dialog__rumpf {
    flex:1 1 auto; min-height:0; overflow-y:auto;
    padding:var(--raum-5);
    font-size:var(--schrift-md); line-height:var(--zeile-normal);
}
.dialog__rumpf > :first-child { margin-top:0; }
.dialog__rumpf > :last-child  { margin-bottom:0; }

/* Der Abbruch steht links, die Tat rechts — dieselbe Richtung wie in jeder
   Maske dieses Systems. `row-reverse` und nicht `justify-content:flex-end`:
   In der Quelltextreihenfolge steht die Tat zuerst und ist damit für die
   Tastatur die nächste Station nach dem Rumpf. */
.dialog__fuss {
    flex:none; display:flex; flex-direction:row-reverse;
    align-items:center; gap:var(--raum-3);
    padding:var(--raum-4) var(--raum-5);
    background:var(--flaeche-2);
    border-top:1px solid var(--rand-weich);
    border-radius:0 0 var(--radius-lg) var(--radius-lg);
}
.dialog__fuss form { margin:0; }
/* Ein Beitext im Fuß („Das läßt sich nicht rückgängig machen.") schiebt die
   Knöpfe nach rechts, statt selbst nach rechts zu rutschen. */
.dialog__fuss .hilfe, .dialog__fuss .klein { margin:0 auto 0 0; }

/* Das Kreuz sitzt im Kopf und ist eine Nebenhandlung: `--hoehe-1`, keine
   Füllung. Es steht in einem `<form method="dialog">` und braucht dafür kein
   einziges Byte JavaScript. */
.dialog__schliessen {
    flex:none; display:grid; place-items:center;
    width:var(--hoehe-1); height:var(--hoehe-1); padding:0;
    font-size:var(--schrift-md); font-weight:var(--fett-normal); line-height:1;
    color:var(--tinte-2); background:transparent;
    border:1px solid transparent; border-radius:var(--radius-xs);
    cursor:pointer;
}
.dialog__schliessen:hover {
    color:var(--tinte); background:var(--flaeche-2); border-color:var(--rand);
}
.dialog__schliessform { margin:0 0 0 auto; }

/* Die Seite darunter darf nicht mitrollen — sonst verliert der Benutzer beim
   Schließen seine Stelle. */
html:has(.dialog[open]) { overflow:hidden; }

@keyframes dialog-auftritt {
    from { opacity:0; transform:translateY(var(--raum-3)) scale(.98); }
}
.dialog[open] { animation:dialog-auftritt var(--dauer-normal) var(--stufe); }

@media (prefers-reduced-motion: reduce) {
    .dialog[open] { animation:none; }
    .dialog::backdrop { backdrop-filter:none; }
}


/* ==========================================================================
   5. DER LADEZUSTAND

   >> DAS LADEZEICHEN VON HTMX (AP-H15) HATTE EINE REGEL, ABER KEINEN KÖRPER.

   Die zwei Regeln unten kommen aus htmx selbst: `insertIndicatorStyles()`
   schrieb sie beim Laden als `<style>`-Block in den `<head>` JEDER Seite.
   `style-src 'self'` verwirft ihn, und der Browser meldete auf jeder Seite
   einen Richtlinienverstoß — die Anwendung verletzte ihre eigene Zusage, und
   das Ladezeichen wirkte nirgends.

   Abgeschaltet wird der Block über `<meta name="htmx-config">` in den beiden
   Layouts, die die Importmap laden. Der Wortlaut hier ist bewußt derselbe wie
   der von htmx: Wer die Vendor-Datei liest, findet ihn wieder. Deshalb steht
   in der Übergangsangabe auch `200ms ease-in` und kein Token — es ist ein
   Zitat, kein Entwurf.

   Was fehlte, war das Zeichen selbst. `.htmx-indicator` schaltet nur
   Sichtbarkeit; sichtbar wurde nichts, weil nichts da war. `.ladeanzeige` ist
   der Körper dazu — sie trägt die Klasse `htmx-indicator` mit und wird damit
   von htmx gesteuert, ohne daß eine Vorlage etwas dazutun muß.
   ========================================================================== */

.htmx-indicator { opacity:0; visibility:hidden; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
    opacity:1; visibility:visible; transition:opacity 200ms ease-in;
}
@media (prefers-reduced-motion: reduce) {
    .htmx-request .htmx-indicator,
    .htmx-request.htmx-indicator { transition:none; }
}

/* Drei Punkte und kein Kreisel: Ein Kreisel dreht sich endlos und behauptet
   damit Arbeit, auch wenn die Antwort längst hängt. Drei Punkte sind klein
   genug, um neben einem Feld zu stehen, ohne die Zeile zu sprengen.

   Die Laufzeit ist aus `--dauer-normal` abgeleitet und nicht geraten: Ein
   wiederkehrender Takt ist keine Bediendauer, aber er soll zu ihr passen. */
.ladeanzeige {
    display:inline-flex; align-items:center; gap:var(--raum-1);
    min-height:var(--hoehe-1); vertical-align:middle;
}
.ladeanzeige__punkt {
    width:calc(var(--raum-2) * .75); height:calc(var(--raum-2) * .75);
    border-radius:var(--radius-voll); background:var(--akzent);
    animation:ladepunkt calc(var(--dauer-normal) * 6) var(--stufe) infinite;
}
.ladeanzeige__punkt:nth-child(2) { animation-delay:var(--dauer-schnell); }
.ladeanzeige__punkt:nth-child(3) { animation-delay:calc(var(--dauer-schnell) * 2); }

@keyframes ladepunkt {
    0%, 70%, 100% { opacity:.25; transform:translateY(0); }
    35%           { opacity:1;   transform:translateY(calc(var(--raum-1) * -1)); }
}

/* Ohne Bewegung bleiben die Punkte stehen — sichtbar, aber still. Das Wort
   „Wird geladen" steht ohnehin daneben (`.nur-lesegeraet` in der Vorlage); die
   Bewegung trägt die Aussage also nicht (WCAG 1.4.1 und 2.3.3). */
@media (prefers-reduced-motion: reduce) {
    .ladeanzeige__punkt { animation:none; opacity:1; }
}

/* --- Die Platzhalterfläche ---------------------------------------------
   Für nachgeladene Ausschnitte, die größer sind als eine Zeile: die
   Vorschlagsliste, die Arbeitsliste, ein Tabellenausschnitt. Sie behält die
   Höhe, die der Inhalt bekommen wird — sonst springt die Maske beim Eintreffen
   der Antwort, und der Benutzer klickt daneben.

   Sie ist `aria-hidden="true"`: Ein Lesegerät soll graue Balken nicht
   vorlesen. Die Ansage macht die `.ladeanzeige` daneben.

   Der Glanz läuft zwischen `--flaeche-2` und `--rand-weich`. Beide kippen im
   Dunkelmodus mit, und der Unterschied bleibt in beiden Richtungen sichtbar —
   ein Verlauf gegen ein festes Weiß wäre auf dunklem Grund ein Blitz. */
.geruest { display:grid; gap:var(--raum-3); margin:0 0 var(--raum-4); }
.geruest__zeile {
    height:var(--raum-4); border-radius:var(--radius-xs);
    background:linear-gradient(90deg,
        var(--flaeche-2) 0 35%, var(--rand-weich) 50%, var(--flaeche-2) 65% 100%);
    background-size:280% 100%;
    animation:geruest-glanz calc(var(--dauer-normal) * 9) linear infinite;
}
.geruest__zeile--titel { height:var(--raum-5); width:35%; }
.geruest__zeile--kurz  { width:45%; }
.geruest__zeile--halb  { width:65%; }

@keyframes geruest-glanz {
    from { background-position:140% 0; }
    to   { background-position:-40% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .geruest__zeile { animation:none; background:var(--rand-weich); }
}


/* ==========================================================================
   6. DER FORTSCHRITT

   Zwei Gesichter derselben Sache, und sie dürfen nicht verwechselt werden:

     - Die SCHRITTANZEIGE sagt, wo in einer Folge man steht („Schritt 2 von
       6"). Sie zählt Stationen.
     - Der BALKEN sagt, welcher Anteil eines Bestandes erledigt ist. Er mißt
       eine Menge.

   >> DER BALKEN WAR ZWEIMAL UND WIDERSPRÜCHLICH DEFINIERT.
   Zeile 867 legte die zwei Abschnitte ÜBEREINANDER (`position:absolute`),
   Zeile 2118 stellte sie NEBENEINANDER (`display:flex`). Die zweite gewann,
   die erste war toter Text. Nebeneinander ist richtig: „bestätigt" und
   „begonnen" sind disjunkte Mengen, ihre Summe ist nie größer als hundert.

   >> DIE 5er-STUFEN `.anteil-*` BLEIBEN, WO SIE STEHEN.
   Der Anteil ist eine Zahl aus den Daten und müßte als Inline-Breite gesetzt
   werden — genau das läßt die CSP nicht durch. Die Vorlage rundet deshalb nach
   UNTEN auf 5er-Stufen und setzt eine Klasse; ein Balken, der drei Prozent auf
   fünf aufrundet, behauptet mehr Fortschritt als da ist. Die genaue Zahl steht
   im Satz darüber und im `aria-label` — die Farbe trägt hier keine Aussage
   allein (WCAG 1.4.1).
   ========================================================================== */

/* Der Behälter (`backoffice/migration/_fortschritt`). */
.fortschritt { margin:0 0 var(--raum-5); }

/* Die Schrittanzeige als Satz (`portal/assistent/rahmen`). Sie war ein
   gewöhnlicher Absatz und ging im Kopf des Assistenten unter; als Plakette ist
   sie die Angabe, nach der man beim Wiedereinstieg zuerst sucht. */
p.fortschritt {
    display:inline-flex; align-items:center; gap:var(--raum-2);
    margin:0 0 var(--raum-4); padding:var(--raum-1) var(--raum-3);
    font-size:var(--schrift-xs); font-weight:var(--fett-stark);
    line-height:var(--zeile-eng); letter-spacing:.04em; text-transform:uppercase;
    color:var(--akzent); background:var(--akzent-weich);
    border-radius:var(--radius-voll);
}

/* --- Die Schiene ------------------------------------------------------
   Sechs Stationen als `<ol>`. Der laufende Schritt trägt `aria-current="step"`
   — das ist die Aussage für das Lesegerät.

   >> DIE FARBE TRÄGT AUCH HIER NICHT ALLEIN (WCAG 1.4.1).
   Die drei Zustände unterscheiden sich in der FORM: erledigt ist gefüllt,
   laufend ist doppelt umrandet und fett, offen ist flach. Wer keine Farbe
   sieht, sieht den Unterschied trotzdem — und den Satz „Schritt 2 von 6"
   darüber. */
.fortschritt__schiene {
    display:flex; flex-wrap:wrap; align-items:center;
    gap:var(--raum-2) var(--raum-3);
    margin:0 0 var(--raum-5); padding:0; list-style:none;
}
.fortschritt__schritt {
    display:flex; align-items:center; gap:var(--raum-2);
    font-size:var(--schrift-sm); line-height:var(--zeile-eng);
    color:var(--tinte-3);
}
.fortschritt__ziffer {
    flex:none; display:grid; place-items:center;
    width:var(--hoehe-1); height:var(--hoehe-1);
    font-size:var(--schrift-xs); font-weight:var(--fett-stark); line-height:1;
    color:var(--tinte-3); background:var(--flaeche-2);
    border:1px solid var(--rand); border-radius:var(--radius-voll);
}

.fortschritt__schritt--fertig { color:var(--tinte-2); }
.fortschritt__schritt--fertig .fortschritt__ziffer {
    color:var(--flaeche); background:var(--gut); border-color:var(--gut);
}

.fortschritt__schritt--jetzt { color:var(--tinte); font-weight:var(--fett-stark); }
.fortschritt__schritt--jetzt .fortschritt__ziffer {
    color:var(--akzent); background:var(--akzent-weich);
    border-color:var(--akzent); border-width:2px;
}

/* Der Verbindungsstrich entsteht aus dem Element und nicht aus einem weiteren
   `<li>` — ein Strich ist kein Listeneintrag und hat im Lesegerät nichts
   verloren. Unter dem mittleren Bruchpunkt fällt er weg: Dort bricht die
   Schiene um, und ein Strich ins Leere ist schlimmer als keiner. */
@media (min-width:48rem) {
    .fortschritt__schiene { flex-wrap:nowrap; }
    .fortschritt__schritt:not(:last-child)::after {
        content:""; flex:1 0 var(--raum-5);
        min-width:var(--raum-5); height:1px;
        background:var(--rand);
    }
    .fortschritt__schritt--fertig:not(:last-child)::after { background:var(--gut); }
}

/* --- Der Balken -------------------------------------------------------
   Er ist `role="img"` mit Beschriftung, und die Zahlen stehen im Satz darüber.
   Er ist damit Zugabe und nicht Träger der Aussage.

   NEU: Der begonnene Abschnitt trägt zusätzlich eine Schraffur. Zwei
   Abschnitte, die sich nur in der Farbe unterscheiden, sind für einen
   Rot-Grün-Blinden ein einziger Balken (WCAG 1.4.1) — mit Schraffur sind es
   zwei. */
.fortschrittsbalken {
    display:flex; height:var(--raum-2); overflow:hidden;
    background:var(--rand-weich); border-radius:var(--radius-voll);
}
.balken-bestaetigt { background:var(--gut); }
.balken-begonnen {
    background:var(--hinweis);
    background-image:repeating-linear-gradient(135deg,
        transparent 0 3px, var(--flaeche-2) 3px 5px);
}


/* ==========================================================================
   7. DER HINWEISKASTEN

   Für die längere Erläuterung im Fließtext: drei Absätze zur Rechtsgrundlage,
   die Erklärung eines Verfahrens, der Warum-Text über einem Formular.
   `p.hinweis` ist dafür zu klein — er ist ein Satz mit Rand.

   Der Unterschied ist keine Zierde. Ein Hinweis will überflogen, eine
   Erläuterung will gelesen werden: deshalb Fließtextgröße statt Arbeitsgröße
   und ein Titel, der sagt, worum es geht, bevor jemand anfängt.

   Als `<details class="hinweiskasten">` ist er zugeklappt und kostet keinen
   Platz. ZUGEKLAPPT HEISST NICHT ERLEDIGT: Die Zusammenfassung nennt den
   Inhalt wörtlich, damit niemand aufklappen muß, um zu wissen, ob es ihn
   angeht — dieselbe Regel wie beim Vorgangsschritt (AP-E26). */

.hinweiskasten {
    font-size:var(--schrift-md);
    border-left-color:var(--akzent);
    background:var(--flaeche-2);
}
.hinweiskasten__titel {
    display:block; margin:0 0 var(--raum-2);
    font-size:var(--schrift-sm); font-weight:var(--fett-stark);
    letter-spacing:.04em; text-transform:uppercase;
    color:var(--tinte-2);
}
.hinweiskasten p { margin:0 0 var(--raum-3); }
.hinweiskasten p:last-child { margin:0; }

.hinweiskasten--warn    { border-left-color:var(--warn);       background:var(--warn-weich); }
.hinweiskasten--gut     { border-left-color:var(--gut);        background:var(--gut-weich); }
.hinweiskasten--hinweis { border-left-color:var(--hinweis);    background:var(--hinweis-weich); }
.hinweiskasten--ruhig   { border-left-color:var(--rand-stark); background:var(--flaeche-2); }

/* Der Klappkasten. `summary` bringt Zeiger und Fokusring schon aus dem Blatt
   mit; hier kommt nur die Gestalt dazu. Die Polsterung wandert vom Kasten in
   seine Teile, sonst steht die Zusammenfassung doppelt eingerückt. */
details.hinweiskasten { padding:0; }
details.hinweiskasten > summary {
    padding:var(--raum-3) var(--raum-4);
    font-size:var(--schrift-sm); font-weight:var(--fett-stark);
    line-height:var(--zeile-normal); color:var(--tinte);
    cursor:pointer; list-style-position:inside;
}
details.hinweiskasten[open] > summary { border-bottom:1px solid var(--rand-weich); }
details.hinweiskasten > :not(summary) { padding-left:var(--raum-4); padding-right:var(--raum-4); }
details.hinweiskasten > summary + * { padding-top:var(--raum-3); }
details.hinweiskasten > :last-child:not(summary) { padding-bottom:var(--raum-3); }


/* ==========================================================================
   8. DER LEERFALL, DRITTES GESICHT

   Die zwei Leerfälle der Listenfamilie bleiben unangetastet: „nichts zu tun"
   (`--erledigt`) ist eine Aussage über die Sache, „diese Auswahl ist leer"
   (`--offen`) eine über den Filter. Wer beides gleich färbt, meldet Ruhe, wo
   nur ein Filter falsch steht.

   Hier kommt der Fall dazu, der KEINE Liste betrifft, sondern eine ganze
   Maske: ein Mandant ohne ein einziges Verzeichnis, ein Register am ersten
   Tag. Dort ist der Weg die Hauptsache und nicht ein nachgestellter Verweis —
   deshalb ein Knopf und nicht ein Link in der Zeile.
   ========================================================================== */

.leerfall--einladend {
    display:grid; justify-items:start; gap:var(--raum-3);
    padding:var(--raum-6) var(--raum-5);
    max-width:var(--breite-text);
}
.leerfall--einladend .leerfall__titel {
    margin:0; font-size:var(--schrift-lg); font-weight:var(--fett-stark);
    line-height:var(--zeile-eng); color:var(--tinte);
}
.leerfall--einladend p { margin:0; color:var(--tinte-2); line-height:var(--zeile-weit); }
.leerfall__weg { margin:var(--raum-1) 0 0; }


/* ==========================================================================
   9. AUF PAPIER

   Ein haftender Meldungsstapel druckt sich an der Stelle, an der er gerade
   klebt, und deckt dabei die Tabelle zu. Ladezeichen und Platzhalterflächen
   sagen auf Papier gar nichts.
   ========================================================================== */
@media print {
    .meldungen { position:static; padding:0; background:none; }
    .meldung { box-shadow:none; }
    .meldung__schliessen, .ladeanzeige, .geruest { display:none; }
}

/* ==========================================================================
   FACHSCHICHT

   Was den Bauteilen oben eine Abweichung hinzufuegt, und die
   CSP-Ersatzklassen, die kein Bauteil sind, sondern die Uebersetzung
   von 107 geloeschten style-Attributen.
   ========================================================================== */

/* >> DIE WORTMARKE IST KEIN VERWEIS UNTER VIELEN (AP-H17).

   Sie stand in derselben Blaufarbe wie jeder Verweis und bekam beim
   Ueberfahren einen Unterstrich. Sie steht jetzt in Tinte mit einem kleinen
   Markenquadrat davor - das ist die Stelle, an der eine Anwendung sagt, wie
   sie heisst, und nicht eine Stelle, an der man klickt. Der Verweis bleibt
   trotzdem: Er fuehrt ins Cockpit. */
.kopf .marke {
    display:flex; align-items:center; gap:.55rem;
    font-size:1.02rem; font-weight:700; letter-spacing:-.015em;
    color:var(--tinte); text-decoration:none;
}
.kopf a.marke:hover { text-decoration:none; color:var(--akzent); }
.kopf .marke::before {
    content:""; flex:none; width:1.35rem; height:1.35rem;
    border-radius:var(--radius-xs);
    background:linear-gradient(135deg, var(--akzent-hell), var(--akzent));
}

/* Zustandswechsel, keine Arbeitsbereiche - deshalb rechts außen und nicht in
   der Gliederung. */
.kontozeile {
    margin-left:auto; display:flex; gap:1.1rem;
    font-size:.88rem;
}
.kontozeile a {
    color:var(--tinte-2); padding:.3rem .6rem; border-radius:var(--radius-xs);
}
.kontozeile a:hover { color:var(--akzent); background:var(--flaeche-2); text-decoration:none; }

/* Die kurze Navigationsleiste des Portals sitzt weiterhin IM Kopf. */
.kopfnavigation {
    margin-left:auto; display:flex; flex-wrap:wrap; gap:1.2rem;
    font-size:.92rem;
}

/* --------------------------------------------------------------------------
   Der Unterstützungsmodus

   Teil des Sicherheitsmechanismus, nicht Zierde: Er darf nicht wegrollen und
   muss auffallen. Die Schriftfarbe ist --grund und nicht #fff - im
   Dunkelmodus kippt --warn nach hell, und weiße Schrift stünde dort mit
   2,4:1 auf ihr. So sind es 5,0:1 im hellen und 7,5:1 im dunklen Modus.
   -------------------------------------------------------------------------- */
.impersonate-banner a { color:var(--grund); }

/* >> DER FOKUSRING IM BANNER WAR PRAKTISCH UNSICHTBAR.
   --akzent-hell auf --warn trägt 1,17:1 hell und 1,64:1 dunkel; verlangt
   sind 3:1 (WCAG 1.4.11). --grund gegen --warn trägt 4,83:1 - dieselbe
   Farbe, die die Schrift des Banners ohnehin führt. */
.impersonate-banner a:focus-visible { outline-color:var(--grund); }

/* --------------------------------------------------------------------------
   Die Gliederung

   Fünf Gruppen statt siebzehn gleichrangiger Punkte. Die Gruppenüberschrift
   ist kein Verweis: Sie benennt einen Bereich, sie führt nirgendwohin. Wer
   sie klickbar macht, erzeugt eine Seite, die es nicht gibt.
   -------------------------------------------------------------------------- */

.navigationsgruppe + .navigationsgruppe { margin-top:var(--raum-5); }

.navigationsgruppe__titel {
    /* Die drei Pixel sind die Kante, die der laufende Punkt darunter trägt -
       ohne sie steht die Gruppenüberschrift um genau diese Kante versetzt. */
    margin:0 0 .35rem; padding:0 1.25rem 0 calc(1.25rem + 3px);
    font-size:.7rem; font-weight:650; letter-spacing:.1em;
    text-transform:uppercase; color:var(--tinte-3);
}

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

/* >> DER PUNKT IST EINE PILLE, KEIN VOLLER STREIFEN (AP-H17).

   Vorher lief die Fläche des laufenden Punktes von Rand zu Rand und stiess
   an die Trennlinie zur Arbeitsspalte. Ein Streifen quer durch die Seite ist
   ein Balken; eine Pille mit Luft ringsum ist ein ausgewaehlter Punkt. */
.hauptnavigation a {
    display:flex; align-items:center; gap:var(--raum-3);
    /* Der meistbenutzte Bedienpunkt der Anwendung. --hoehe-2 nimmt ihm die
       Abhaengigkeit von der Zeilenhoehe und erfuellt zugleich WCAG 2.5.8
       (24x24 CSS-Pixel) mit Abstand - vorher ergab sich die Hoehe aus
       Polsterung plus Textzeile und lag knapp darueber. */
    min-height:var(--hoehe-2);
    margin:0 var(--raum-2); padding:var(--raum-2) var(--raum-3);
    border-radius:var(--radius-sm);
    font-size:var(--schrift-sm); color:var(--tinte-2); text-decoration:none;
    transition:background-color var(--dauer-schnell) var(--stufe),
               color var(--dauer-schnell) var(--stufe);
}
.hauptnavigation a:hover {
    background:var(--flaeche-2); color:var(--tinte); text-decoration:none;
}

/* Der laufende Punkt trägt DREI Merkmale: Auszeichnung, Fläche und das
   Zeichen in der Akzentfarbe. Farbe allein wäre für farbenblinde Leser keine
   Aussage (WCAG 1.4.1), und aria-current sagt es zusätzlich dem Lesegerät. */
.hauptnavigation a[aria-current] {
    font-weight:650; color:var(--akzent);
    background:var(--akzent-weich);
}

/* --- Das Zeichen vor dem Punkt ---------------------------------------
   Strichzeichnung, keine Fläche: Sie erbt die Schriftfarbe und wandert
   damit im laufenden Punkt und beim Ueberfahren mit. Sie steht leiser als
   das Wort - sie hilft beim Wiedererkennen und soll es nicht überstimmen. */
.navigationspunkt__symbol {
    flex:0 0 auto; width:1.15rem; height:1.15rem;
    fill:none; stroke:currentColor; stroke-width:1.75;
    stroke-linecap:round; stroke-linejoin:round;
    opacity:.75;
}
.hauptnavigation a[aria-current] .navigationspunkt__symbol { opacity:1; }
.navigationspunkt__text { min-width:0; }

/* Der Satz selbst wird nie gezeigt - er ist nur der Vorrat, aus dem <use>
   schoepft. `display:none` waere falsch: Manche Browser loesen daraus keine
   Verweise mehr auf. */
.symbolsatz { position:absolute; width:0; height:0; overflow:hidden; }

/* "alle Mandate" - die Gegenprobe zum großen Mandantennamen im Kopf. Diese
   drei Masken tragen `#[OhneMandant]`; der Name oben gilt für sie nicht. */
.navigationspunkt__umfang {
    display:block;
    font-size:var(--schrift-xs); font-weight:400; color:var(--tinte-3);
}
.hauptnavigation a[aria-current] .navigationspunkt__umfang { color:var(--tinte-2); }

/* --------------------------------------------------------------------------
   Der Schalter für schmale Bildschirme

   Ohne JavaScript, ohne <details>. Die Begründung für das Kontrollkästchen
   steht in layout/backoffice.html.twig: Die verbergende Regel liegt
   ausschließlich im Medienausdruck unten. Fällt CSS aus oder greift der
   Medienausdruck nicht, ist die Navigation sichtbar - nicht unerreichbar.

   Das Kästchen selbst liegt aus dem Bild, bleibt aber mit der Tastatur
   erreichbar; sein Fokusring wird auf die Beschriftung übertragen.
   -------------------------------------------------------------------------- */

@media (max-width:63.99rem) {
    .rumpf { grid-template-columns:minmax(0,1fr); }

    .navigationsknopf { display:inline-flex; }

    .hauptnavigation {
        padding:var(--raum-4) 0 var(--raum-4);
        border-right:0; border-bottom:1px solid var(--rand);
    }

    /* DIE EINZIGE REGEL, DIE DIE NAVIGATION VERBIRGT. Sie steht hier drin und
       nirgends sonst. */
    .navigationsschalter:not(:checked) ~ .rumpf .hauptnavigation { display:none; }

    .kopf { padding:var(--raum-2) var(--raum-4); gap:var(--raum-3); }
    .kontozeile { width:100%; margin-left:0; order:3; }
    main { padding:var(--raum-4) var(--raum-4) var(--raum-7); }
}

/* Unter 30rem hat der Mandantenname eine eigene Zeile - lieber umbrechen als
   abschneiden. Ein halber Mandantenname ist schlimmer als keiner: "Ordination
   Dr. M…" passt auf mehr als einen Mandanten. */
@media (max-width:30rem) {
    .kopf .mandant { width:100%; max-width:none; order:2; }
    .mandant__name { white-space:normal; }
}

/* Das Portal ist ruhiger und weiter: Der Mandant liest hier, er arbeitet
   nicht in Tabellen. Eine schmalere Spalte und ein Grad mehr Schrift sind der
   ganze Unterschied im Satz. */
.welt-portal { font-size:1.0625rem; line-height:1.65; }
.welt-portal main { max-width:54rem; padding:2.25rem 1.5rem 4rem; }
/* >> DIE FLAECHE DER PORTALKOPFZEILE.

   `.kopf` liegt INNERHALB von `.kopfleiste` und traegt seine eigene Flaeche
   in --flaeche. Ohne diese Regel steht die Wortmarke in --portalband-tinte
   (im Hellmodus #fff) auf #fff: Kontrast 1,00:1, der Mandant sieht eine leere
   Leiste. Im Dunkelmodus faellt es nicht auf - dort ist die Tinte #dceef7. */
.welt-portal .kopf {
    color:var(--portalband-tinte);
    background:var(--portalband);
    border-bottom-color:transparent;
}
.welt-portal .kopf .marke { color:var(--portalband-tinte); font-size:var(--schrift-lg); }
.welt-portal .kopfnavigation a { color:var(--portalband-tinte); }
.welt-portal .kopfleiste { background:var(--portalband); }
.welt-portal .kopf a:focus-visible { outline-color:var(--portalband-tinte); }

@media (max-width:63.99rem) {
    .welt-portal .kopf { padding:.8rem 1rem; }
    .welt-portal main { padding:1.5rem 1rem 3rem; }
}

/* Das Backoffice bleibt dicht und tabellarisch. Die Klasse steht am <body>,
   damit es das Gegenstück zu .welt-portal gibt und niemand die eine Welt aus
   Versehen über die Abwesenheit der anderen definiert. */
.welt-backoffice .kopf { background:var(--flaeche); }

/* ==========================================================================
   ANMELDUNG UND MANDANTENAUSWAHL (layout/schlank.html.twig)

   Keine Kopfleiste, keine Navigation, kein Mandant. Keine Regel hier darf
   .kopf voraussetzen.
   ========================================================================== */

.welt-schlank { display:block; }

.huelle { max-width:27rem; margin:12vh auto; padding:0 1rem; }

/* Die Akzentkante ist die Marke dieser Seite. Ein Wort wäre hier falsch:
   Dasselbe Layout trägt die Anmeldung des Beraters UND die des
   Portalnutzers - siehe Kommentarkopf der Vorlage. */
.huelle h1 { margin:0 0 .35rem; }
.huelle .unterzeile { margin:0 0 1.5rem; }

/* ==========================================================================
   PAPIER

   Gedruckt wird hier oft - eine Maske als Beleg, ein Verzeichnis zur
   Durchsicht. Gliederung und Kontozeile fallen weg, Wortmarke, Mandant und
   das Banner des Unterstützungsmodus bleiben: Ein Ausdruck, dem man nicht
   ansieht, zu welchem Mandanten er gehört, ist im Aktenordner wertlos.
   ========================================================================== */
@media print {
    body { background:#fff; }
    .kopfleiste { position:static; box-shadow:none; }
    .hauptnavigation, .navigationsknopf, .kontozeile, .kopfnavigation { display:none; }
    .rumpf { display:block; }
    main { max-width:none; padding:var(--raum-4) 0; }
    /* Die beiden festen #fff in diesem Block sind die einzigen Farbwerte der
       Schale ausserhalb des Wertevorrats. Sie stehen mit Absicht hier: Papier
       hat keinen Dunkelmodus, und ein Markenband in Volltonfarbe kostet Toner,
       ohne auf dem Ausdruck etwas zu sagen. */
    .welt-portal .kopf, .welt-portal .kopfleiste { color:inherit; background:#fff; }
}

/* Die einzigen Bewegungen der Schale sind zwei Zustandsübergänge. */
@media (prefers-reduced-motion: reduce) {
    .hauptnavigation a, .navigationsknopf::after { transition:none; }
}


/* Die Zeile unter dem Zeiger. Sie ist die billigste Lesehilfe in einer
   Liste mit sieben Spalten und kostet eine Regel. */
tbody tr { transition:background-color .1s ease-out; }
tbody tr:hover { background:var(--flaeche-2); }

/* Die Filterleiste traegt seit AP-H28 zweierlei: Verweise, wo alles in die
 * Adresse darf, und Knoepfe, wo ein Suchbegriff im Rumpf mitfaehrt. Sie
 * sehen gleich aus - der Unterschied ist eine Frage von CLAUDE.md § 10 und
 * keine der Gestaltung. */

.marke-gesetzlich {
    display:inline-block; margin-left:var(--raum-2); padding:var(--raum-1) var(--raum-2);
    font-size:var(--schrift-xs); letter-spacing:.04em; text-transform:uppercase;
    color:var(--warn); border:1px solid var(--warn); border-radius:var(--radius-xs);
}

tr.ueberfaellig td { background:color-mix(in srgb, var(--warn) 7%, transparent); }

.formular-schmal { max-width:26rem; display:grid; gap:var(--raum-1); margin:var(--raum-4) 0 var(--raum-6); }
.formular-schmal small { color:var(--tinte-2); font-size:var(--schrift-sm); margin-bottom:var(--raum-2); }

/* Nur für Lesegeräte: eine Spaltenüberschrift, die sichtbar leer bleibt,
   wäre für einen Screenreader eine Spalte ohne Namen. */
.nur-lesegeraet {
    position:absolute; width:1px; height:1px; overflow:hidden;
    clip-path:inset(50%); white-space:nowrap;
}

/* --------------------------------------------------------------------
   Bausteinbibliothek (AP-G01)

   Der Diff ist die eigentliche Vorkehrung gegen das Durchwinken am
   Folgetag. Er trägt deshalb ZUSAETZLICH zur Farbe ein Zeichen (+ / −):
   Eine Farbe allein ist für farbenblinde Leser keine Aussage (WCAG 1.4.1),
   und ausgerechnet hier hängt an ihr, ob jemand einen geänderten
   Rechtssatz bemerkt.
   -------------------------------------------------------------------- */
blockquote.wortlaut {
    margin:0 0 var(--raum-4); padding:var(--raum-3) var(--raum-4); background:var(--flaeche-2);
    border-left:3px solid var(--akzent); border-radius:0 var(--radius-xs) var(--radius-xs) 0;
}

ul.diff { list-style:none; padding:0; margin:0 0 var(--raum-5); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:var(--schrift-sm); }
ul.diff li { padding:var(--raum-1) var(--raum-2); border-left:3px solid transparent; white-space:pre-wrap; }
ul.diff .diff--gleich { color:var(--tinte-3); }
ul.diff .diff--hinzu { color:var(--gut); border-left-color:var(--gut);
    background:color-mix(in srgb, var(--gut) 8%, transparent); }
ul.diff .diff--weg { color:var(--warn); border-left-color:var(--warn);
    background:color-mix(in srgb, var(--warn) 8%, transparent);
    text-decoration:line-through; text-decoration-thickness:1px; }

/* Die Ampel der Datenschutzerklärung (AP-G05). Farbe UND Zeichen: Eine
   Farbe allein ist für farbenblinde Leser keine Aussage (WCAG 1.4.1). */
tr.ampel--rot td:first-child { color:var(--warn); font-weight:650; }
tr.ampel--gelb td:first-child { color:var(--hinweis); font-weight:650; }
tr.ampel--gruen td:first-child { color:var(--gut); }


/* Spaltenbreiten für Tabellenköpfe.

   ".breite-14" und nicht ".spalte-14": ".spalte" ist bereits die Spalte des
   zweispaltigen Prüfbildschirms (AP-F15). Zwei Dinge, die gleich anfangen und
   Verschiedenes meinen, verwechselt früher oder später jemand. */
.breite-10 { width:10%; }
.breite-11 { width:11%; }
.breite-12 { width:12%; }
.breite-14 { width:14%; }
.breite-15 { width:15%; }
.breite-16 { width:16%; }
.breite-17 { width:17%; }
.breite-18 { width:18%; }
.breite-20 { width:20%; }
.breite-22 { width:22%; }
.breite-24 { width:24%; }
.breite-26 { width:26%; }
.breite-30 { width:30%; }
.breite-32 { width:32%; }
.breite-34 { width:34%; }
.breite-40 { width:40%; }
.breite-46 { width:46%; }
.breite-50 { width:50%; }
.breite-55 { width:55%; }

/* Zahlenspalten. Rechtsbündig, damit Stellen untereinander stehen -
   bei Fristen und Beträgen ist das kein Geschmack, sondern Lesbarkeit. */
.rechts { text-align:right; }

/* --------------------------------------------------------------------------
   Der Fortschrittsbalken der Stammdatenerfassung (AP-D09)

   Der Anteil ist eine Zahl aus den Daten und müsste als Inline-Breite gesetzt
   werden - genau das lässt die CSP nicht durch. Die Vorlage rundet deshalb
   auf 5er-Stufen ab und setzt eine Klasse.

   Die Rundung ist ehrlich nach UNTEN: Ein Balken, der 3 Prozent auf 5
   aufrundet, behauptet mehr Fortschritt als da ist. Die genaue Zahl steht
   ohnehin im Text darüber und im aria-label - die Farbe trägt hier keine
   Aussage allein (WCAG 1.4.1).
   -------------------------------------------------------------------------- */
.fortschrittsbalken span { position:absolute; top:0; left:0; height:100%; }
/* Die 5er-Stufen. Geschlossene Liste, 0 bis 100. */
.anteil-0 { width:0%; }
.anteil-5 { width:5%; }
.anteil-10 { width:10%; }
.anteil-15 { width:15%; }
.anteil-20 { width:20%; }
.anteil-25 { width:25%; }
.anteil-30 { width:30%; }
.anteil-35 { width:35%; }
.anteil-40 { width:40%; }
.anteil-45 { width:45%; }
.anteil-50 { width:50%; }
.anteil-55 { width:55%; }
.anteil-60 { width:60%; }
.anteil-65 { width:65%; }
.anteil-70 { width:70%; }
.anteil-75 { width:75%; }
.anteil-80 { width:80%; }
.anteil-85 { width:85%; }
.anteil-90 { width:90%; }
.anteil-95 { width:95%; }
.anteil-100 { width:100%; }

/* --------------------------------------------------------------------------
   Einrückung der Unterauftragskette (AP-E07)

   Vorher `padding-left:{{ (u.tiefe - 1) * 6 }}mm` - Millimeter in einer
   Bildschirmtabelle, übernommen aus der PDF-Vorlage. Sechs Stufen reichen:
   Eine Unterauftragskette, die tiefer als sechs geht, ist kein Darstellungs-,
   sondern ein Vertragsproblem.
   -------------------------------------------------------------------------- */
.tiefe-1 { padding-left:.7rem; }
.tiefe-2 { padding-left:2.1rem; }
.tiefe-3 { padding-left:3.5rem; }
.tiefe-4 { padding-left:4.9rem; }
.tiefe-5 { padding-left:6.3rem; }
.tiefe-6 { padding-left:7.7rem; }

/* --------------------------------------------------------------------------
   Etwas, das abgetippt oder verglichen wird

   Der Faktorschlüssel, ein Wurzelhash, eine Fassungsnummer. Dickte Schrift,
   weite Sperrung, umbruchfähig - `word-break:break-all`, weil ein Hash sonst
   die Tabelle sprengt und `overflow-wrap` an einer Zeichenkette ohne
   Trennstelle nichts ausrichtet.
   -------------------------------------------------------------------------- */
.pruefsumme {
    font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
    font-size:1.05rem; letter-spacing:.08em; word-break:break-all;
    background:var(--flaeche-2); border:1px solid var(--rand);
    border-radius:var(--radius-xs); padding:.7rem;
}

.kleingedruckt { color:var(--tinte-2); font-size:var(--schrift-sm); }

/* Sichtbare Tabellenüberschrift (Cockpit). Sie trägt dort die Einschränkung
   "gezählt, nicht bewertet" und darf deshalb nicht wie Zierde aussehen. */
caption { text-align:left; color:var(--tinte-2); font-size:var(--schrift-sm);
          padding:0 0 var(--raum-2); max-width:70ch; }

code { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:.9em;
       /* 64 Hexzeichen sprengen sonst jede Tabellenzelle. */
       overflow-wrap:anywhere; padding:var(--raum-1) var(--raum-1); background:var(--flaeche-2);
       border:1px solid var(--rand-weich); border-radius:var(--radius-xs); }

/* --- Beitexte ----------------------------------------------------------
   Drei Abstufungen, die im ganzen Bestand vorkommen: ".unterzeile" erklärt
   eine Maske, ".hilfe" ein Feld, ".nr" und ".klein" tragen Nebenangaben. */

.unterzeile { color:var(--tinte-2); font-size:var(--schrift-sm); margin:0 0 var(--raum-5); max-width:70ch; }
.hilfe      { color:var(--tinte-2); font-size:var(--schrift-sm); max-width:70ch; }
.nr         { color:var(--tinte-2); font-size:var(--schrift-sm); }
.klein      { font-size:var(--schrift-sm); color:var(--tinte-2); line-height:1.45;
              overflow-wrap:break-word; }

/* .nr steht auch unter mehrzeiligen Erläuterungen (Dokumentgestaltung) -
   dort ist es ein Absatz, kein Kürzel. */
p.nr, p.hilfe { max-width:70ch; margin:var(--raum-1) 0 var(--raum-4); }

/* --- Knöpfe -----------------------------------------------------------
   Der Grundknopf trägt Papierfarbe auf Akzent. --fläche statt eines festen
   Weiss: im Dunkelmodus kippt der Akzent nach hell, die Schrift muss dann
   dunkel werden. Ein festes #fff bliebe hell auf hell stehen. */

button, input[type=submit] {
    font:inherit; font-size:var(--schrift-sm); font-weight:600; cursor:pointer;
    padding:var(--raum-2) var(--raum-4); border-radius:var(--radius-xs);
    color:var(--flaeche); background:var(--akzent); border:1px solid var(--akzent);
    transition:background-color .12s ease, border-color .12s ease;
}

/* Die erste Beschriftung einer Gruppe braucht den Vorlauf nicht. */
input:hover:not([disabled]), select:hover:not([disabled]), textarea:hover:not([disabled]) {
    border-color:var(--akzent-hell);
}

/* Sammlungen: das Formularthema hängt data-prototype an den Behälter. Jede
   Zeile bekommt einen eigenen Rahmen, sonst laufen mehrere Untereinträge
   optisch ineinander. */
.formular-inline label { margin:0; }

/* --- Listen ------------------------------------------------------------ */

ul.liste { list-style:none; margin:0; padding:0; }
ul.liste li { border-bottom:1px solid var(--rand); }
ul.liste li:last-child { border-bottom:0; }
ul.liste a { display:block; padding:var(--raum-3) var(--raum-1); color:inherit; text-decoration:none; }
ul.liste a:hover { color:var(--akzent); }

/* Schaltet bedingte Blöcke ab. Wird vom Stimulus-Controller "bedingung"
   gesetzt und ist damit kein Aussehen, sondern Funktion: Die Regel muss jede
   Anzeigeregel des Blocks schlagen, sonst bleibt ein abgewähltes Feld
   sichtbar und wird mitgeschickt. */
.verborgen { display:none !important; }

/* >> auto-fit UND NICHT auto-fill (AP-H17).
   
   `auto-fill` legt so viele Spuren an, wie hineinpassen - auch leere. Auf
   einem 1920er Bildschirm standen drei Kacheln zu je 250px links in einer
   1600px breiten Spalte, und rechts daneben lagen drei leere Spuren. `auto-fit`
   faltet die leeren zusammen, und die vorhandenen Kacheln nehmen den Platz. */
@media (prefers-reduced-motion: reduce) {
    .kachel { transition:none; }
    a.kachel:hover, a.kachel:focus-visible { transform:none; }
}
/* Die Kachel ist ein Verweis, aber sie soll nicht wie einer aussehen - der
   ganze Kasten ist das Ziel, und der Unterstrich zerschnitte ihn. */

@media (prefers-reduced-motion: reduce) {
    button, input[type=submit], .knopf-klein { transition:none; }
}

/* Formular in einer Tabellenzelle: eine Zeile, keine Spalte. */
td form input, td form select, td form textarea { margin-bottom:0; max-width:16rem; }
pre {
    overflow-x:auto; margin:0 0 var(--raum-4); padding:var(--raum-3) var(--raum-4);
    background:var(--flaeche-2); border:1px solid var(--rand); border-radius:var(--radius-xs);
}
pre code { background:none; border:0; padding:0; }

@media (prefers-reduced-motion: reduce) {
    form input, form select, form textarea, form button { transition:none; }
}
p.unterzeile { margin:-.2rem 0 var(--raum-4); max-width:70ch; }
h1 .unterzeile { font-size:.6em; font-weight:400; }
span.nr { font-size:.85em; }

/* --------------------------------------------------------------------
   Feldgruppen der langen Maske (AP-B29, ADR 0018)

   Acht aufklappbare Gruppen statt einer flachen Liste über 48 Felder. Die
   Gruppe trägt ihre Überschrift als <summary>; ohne sichtbaren Kopf wäre
   der Aufklappmechanismus nur eine weitere Zeile.
   -------------------------------------------------------------------- */
details.feldgruppe {
    margin:0 0 var(--raum-3); background:var(--flaeche);
    border:1px solid var(--rand); border-radius:var(--radius-sm);
}
details.feldgruppe > summary {
    padding:var(--raum-3) var(--raum-4); font-weight:650; cursor:pointer;
    border-radius:var(--radius-sm);
}
details.feldgruppe[open] { padding-bottom:var(--raum-4); }
details.feldgruppe[open] > summary {
    margin-bottom:var(--raum-2); border-radius:var(--radius-sm) var(--radius-sm) 0 0;
    border-bottom:1px solid var(--rand-weich);
}
details.feldgruppe > :not(summary) { margin-left:var(--raum-4); margin-right:var(--raum-4); }

/* Der naechste Schritt. Aufgeklappt steht immer genau ein Abschnitt; die
   Kante sagt beim Ueberfliegen, welcher. Die Aussage traegt das WORT
   "naechster Schritt" in der Zusammenfassung allein (WCAG 1.4.1), die Farbe
   ist die Zugabe - dieselbe Kante wie .offboarding__naechste. */
details.feldgruppe--naechster { border-left:3px solid var(--akzent); }

details.feldgruppe--dran { border-left:4px solid var(--akzent); }
details.feldgruppe--dran > summary { color:var(--akzent); }

/* Ein gesetzter Folgetermin, der verstrichen ist. Steht nach der Regel
   darüber, weil beide dieselbe Spezifität haben und die spätere gewinnt. */
details.feldgruppe--verstrichen { border-left-color:var(--warn); }
details.feldgruppe--verstrichen > summary { color:var(--warn); }

/* Bedingte Sichtbarkeit: Die Einrückung sagt, dass dieser Block an einer
   Bedingung hängt. Verborgen wird über BEIDES - der Controller setzt das
   hidden-Attribut und die Klasse; eine display-Angabe auf .bedingter-block
   würde hidden aushebeln, deshalb steht sie hier ausdrücklich nicht. */
.bedingter-block { margin-bottom:var(--raum-4); padding-left:var(--raum-3); border-left:2px solid var(--akzent-weich); }
.bedingter-block.verborgen, .bedingter-block[hidden] { display:none; }

/* Was noch nicht gebaut ist, steht sichtbar da - eine stille Lücke vermisst
   niemand. Gestrichelt, weil hier nichts einzugeben ist. */
.platzhalter {
    margin-bottom:var(--raum-4); padding:var(--raum-2) var(--raum-3); font-size:var(--schrift-sm); color:var(--tinte-2);
    background:var(--flaeche-2); border:1px dashed var(--rand); border-radius:var(--radius-xs);
}
.platzhalter strong { display:block; color:var(--tinte); }

/* --------------------------------------------------------------------
   Art. 9 und Art. 10 (AP-B21)

   An besonderen Kategorien hängt eine ANDERE RECHTSFOLGE als am Rest der
   Maske, und der Block wandert unverändert ins PDF. Er bekommt deshalb einen
   eigenen Rahmen mit warnfarbenem Rücken. Träger der Aussage bleibt der Text
   in den enthaltenen Absätzen - sie nennen Art. 9 bzw. Art. 10 ausdrücklich
   (WCAG 1.4.1); die Farbe macht den Block nur auffindbar.
   -------------------------------------------------------------------- */
.art9-block {
    margin:var(--raum-3) 0 var(--raum-4); padding:var(--raum-4) var(--raum-4) 0;
    background:var(--flaeche-2);
    border:1px solid var(--rand); border-left:4px solid var(--warn);
    border-radius:0 var(--radius-xs) var(--radius-xs) 0;
}

/* --------------------------------------------------------------------
   Kontrollmassnahmen (AP-B22, § 12 Abs. 4 DSG)

   Die drei Ziffern stehen EINZELN mit je einer bewussten Bestätigung. Jede
   bekommt eine eigene Fläche - ein Haken in einer Absatzwüste ist optisch
   ein Sammelhaken, und genau das soll er nicht sein.
   -------------------------------------------------------------------- */
fieldset.kontrollmassnahmen { background:var(--flaeche); }
fieldset.kontrollmassnahmen h4 { margin:var(--raum-5) 0 var(--raum-2); font-size:var(--schrift-md); }

label.ziffer {
    position:relative; display:block; margin:0 0 var(--raum-2);
    padding:var(--raum-2) var(--raum-3) var(--raum-2) var(--raum-6);
    font-weight:400; color:var(--tinte); font-size:var(--schrift-sm);
    background:var(--flaeche-2); border:1px solid var(--rand-weich); border-radius:var(--radius-xs);
}
label.ziffer input { position:absolute; top:.7rem; left:.7rem; }
label.ziffer strong { color:var(--tinte-2); }

/* Der nicht zutreffende Nachweisweg bleibt sichtbar und erklärt sich. Die
   Ausgrauung ist nicht der Träger der Aussage - der eingeschlossene .nr-Text
   sagt in Worten, warum dieser Weg hier nicht gilt. */
label.ausgegraut {
    display:block; margin:var(--raum-2) 0 var(--raum-4); padding:var(--raum-2) var(--raum-3);
    font-weight:400; color:var(--tinte-3);
    border:1px dashed var(--rand); border-radius:var(--radius-xs);
}
label.ausgegraut input { opacity:.6; cursor:not-allowed; }

/* --------------------------------------------------------------------
   Sammlungen: Betroffenengruppe > Datenart > Empfänger (AP-B28)

   Drei Ebenen ineinander. Die Verschachtelung muss man SEHEN, sonst weiß
   niemand mehr, zu welcher Gruppe eine Datenart gehört. Jede Ebene tiefer
   wechselt die Fläche und rückt ein.
   -------------------------------------------------------------------- */
.datenkategorie {
    margin:0 0 var(--raum-4); padding:var(--raum-4) var(--raum-4);
    background:var(--flaeche); border:1px solid var(--rand); border-radius:var(--radius-sm);
}

details.datenarten { margin:var(--raum-2) 0 var(--raum-4); border-top:1px solid var(--rand-weich); }
details.datenarten > summary {
    padding:var(--raum-2) 0; font-size:var(--schrift-sm); font-weight:650;
    color:var(--akzent); cursor:pointer;
}

.datenart-zeile {
    margin:var(--raum-2) 0; padding:var(--raum-3) var(--raum-4);
    background:var(--flaeche-2);
    border:1px solid var(--rand-weich); border-left:3px solid var(--akzent-weich);
    border-radius:0 var(--radius-xs) var(--radius-xs) 0;
}

/* Die Verknüpfungen hängen an der Datenart, nicht an der Gruppe - die
   hellere Fläche hält sie als eigene Ebene auseinander. */
fieldset.verknuepfungen { background:var(--flaeche); }

/* --------------------------------------------------------------------
   Pflichtangaben und offene Punkte (AP-B36)

   Dieselbe Liste erscheint in der Maske, vor der Freigabe und im
   Kontrollblock. Sie sieht überall gleich aus, weil es dieselbe Aussage ist.
   -------------------------------------------------------------------- */
section.vollstaendigkeit h3 { margin:0 0 var(--raum-2); font-size:var(--schrift-md); }
section.vollstaendigkeit .kennzahl { margin:0 0 var(--raum-3); font-size:var(--schrift-md); color:var(--tinte-2); }
section.vollstaendigkeit .kennzahl strong { color:var(--tinte); }

p.erfuellt {
    margin:0 0 var(--raum-4); padding:var(--raum-2) var(--raum-3); font-size:var(--schrift-md);
    color:var(--gut); background:color-mix(in srgb, var(--gut) 7%, transparent);
    border-left:3px solid currentColor; border-radius:var(--radius-xs);
}

ul.offene-punkte { list-style:none; display:grid; gap:var(--raum-2); margin:0 0 var(--raum-4); padding:0; }
ul.offene-punkte li {
    padding:var(--raum-2) var(--raum-3); font-size:var(--schrift-sm);
    background:var(--flaeche-2);
    border-left:3px solid var(--rand); border-radius:0 var(--radius-xs) var(--radius-xs) 0;
}
ul.offene-punkte li.warnung, ul.offene-punkte li.blockiert {
    color:var(--warn); border-left-color:var(--warn);
    background:color-mix(in srgb, var(--warn) 7%, transparent);
}
ul.offene-punkte li.hinweis {
    color:var(--hinweis); border-left-color:var(--hinweis);
    background:color-mix(in srgb, var(--hinweis) 8%, transparent);
}

/* Das Normzitat steht VOR der Pflichtangabe und trägt einen eigenen Rahmen:
   "Feld fehlt" ist eine Aufforderung, "Art. 30 Abs. 1 lit. f" eine
   Begründung - und die soll man auf einen Blick als solche erkennen. */
ul.offene-punkte .norm {
    display:inline-block; margin-right:var(--raum-2); padding:var(--raum-1) var(--raum-1);
    font-size:var(--schrift-xs); letter-spacing:.03em; color:var(--tinte-2);
    border:1px solid var(--rand); border-radius:var(--radius-xs);
}
ul.offene-punkte .pflichtangabe { font-weight:650; }
ul.offene-punkte .begruendung { margin:var(--raum-1) 0 0; font-size:var(--schrift-sm); color:var(--tinte-2); }

/* Der Vorbehalt aus ADR 0023 steht am Fuß und bleibt dort stehen. Klein, aber
   nicht versteckt: Vor Gericht zählt, was tatsächlich dastand. */
p.vorbehalt {
    margin:0; padding:var(--raum-3) 0 var(--raum-4); font-size:var(--schrift-sm); color:var(--tinte-2);
    border-top:1px solid var(--rand-weich);
}

/* --------------------------------------------------------------------
   Konflikt bei gleichzeitiger Bearbeitung (AP-B24)

   Der Kasten muss den Blick halten: Der Benutzer entscheidet hier, welche
   Fassung gilt. Ein weggeklickter Konfliktdialog kostet die Eingaben.
   -------------------------------------------------------------------- */
.konflikt {
    margin:0 0 var(--raum-5); padding:var(--raum-4) var(--raum-4) var(--raum-1);
    background:var(--flaeche);
    border:1px solid var(--rand); border-left:4px solid var(--warn);
    border-radius:0 var(--radius-sm) var(--radius-sm) 0;
}
.konflikt h2 { margin:0 0 var(--raum-2); font-size:var(--schrift-md); color:var(--warn); }
.konflikt label {
    display:inline-block; margin:0 var(--raum-3) var(--raum-1) 0;
    font-weight:400; color:var(--tinte); font-size:var(--schrift-sm);
}

/* In der Kennzahlenzeile ist die Warnung eine Zahl in einer Reihe, kein
   Kasten - sonst bricht die Zeile aus app.css auseinander. */
.kennzahlen p.warnung { margin:0; padding:0; background:none; border:0; }
div.hinweis-warnung { color:var(--warn); background:color-mix(in srgb, var(--warn) 7%, transparent); }

/* --------------------------------------------------------------------
   Kataloge: Vorschläge, Dubletten, Prüfblöcke
   -------------------------------------------------------------------- */
ul.vorschlaege {
    list-style:none; max-width:34rem; margin:var(--raum-1) 0 var(--raum-4); padding:0;
    background:var(--flaeche); border:1px solid var(--rand);
    border-radius:var(--radius-xs); overflow:clip; overflow-clip-margin:3px;
}
ul.vorschlaege li { padding:var(--raum-2) var(--raum-3); font-size:var(--schrift-sm); border-bottom:1px solid var(--rand-weich); }
ul.vorschlaege li:last-child { border-bottom:0; }
ul.vorschlaege li:hover { background:var(--flaeche-2); }
ul.vorschlaege li[data-katalog-id] { cursor:pointer; }

/* >> DER GEWAEHLTE VORSCHLAG BRAUCHT EINE ANZEIGE, DIE NICHT NUR FARBE IST.
   
   Der Fokus bleibt beim Combobox-Muster im Eingabefeld; sichtbar bewegt sich
   nur aria-activedescendant. Ein Fokusring kann hier also gar nicht
   erscheinen - diese Regel ist sein Ersatz. Deshalb Fläche UND Kante: Wer
   den Farbunterschied nicht sieht, erkennt die Kante an der Kontur
   (WCAG 1.4.1, 2.4.7). */
ul.vorschlaege li[aria-selected="true"] {
    background:var(--akzent-weich);
    box-shadow:inset 3px 0 0 var(--akzent);
}
ul.vorschlaege a { font-weight:600; text-decoration:none; }
ul.vorschlaege a:hover { text-decoration:underline; }
section.kandidat h2 { margin:0 0 var(--raum-3); font-size:var(--schrift-md); }
section.kandidat dl {
    display:grid; grid-template-columns:max-content 1fr; gap:var(--raum-1) var(--raum-4);
    margin:0 0 var(--raum-4); font-size:var(--schrift-sm);
}
section.kandidat dt {
    padding-top:var(--raum-1); font-size:var(--schrift-xs); letter-spacing:.04em;
    text-transform:uppercase; color:var(--tinte-2);
}
section.kandidat dd { margin:0; }

/* Je Maßnahme ein Block mit eigenem Formular (AP-E12). Es gibt bewusst
   keinen Sammelknopf "alle geprüft" - die Gestaltung darf deshalb auch nicht
   nach einer Liste aussehen, die man von oben nach unten durchhäkelt. */
section.pruefblock h3 { margin:0 0 var(--raum-1); font-size:var(--schrift-md); }
section.pruefblock > p { font-size:var(--schrift-sm); }

/* app.css gibt .formular-schmal ein Raster mit eigenem Abstand; die
   Aussenabstände der Felder würden sich darin verdoppeln. */
.formular-schmal label { margin-top:var(--raum-2); }
.formular-schmal input, .formular-schmal select, .formular-schmal textarea { margin-bottom:0; }
.formular-schmal button { justify-self:start; margin-top:var(--raum-3); }

/* === Datenschutzerklärung, Bausteine, Durchsicht ===
   Vorlagen: templates/dse/ (12), templates/backoffice/dse/ (7),
   templates/backoffice/baustein/ (4), templates/backoffice/durchsicht/ (2).

   Ergänzt den Grundstil aus app.css; nichts von dort wird hier ersetzt.
   Ausnahmen sind zwei eng gefasste Regeln in .dse-angaben, jede mit
   Begründung an Ort und Stelle. Es bewegt sich nichts - deshalb steht
   hier auch keine Regel für prefers-reduced-motion. */

dl.angaben { margin:0 0 var(--raum-5); max-width:44rem; }
dl.angaben dt { margin-top:var(--raum-4); font-weight:650; }
dl.angaben dd { margin:var(--raum-1) 0 0; color:var(--tinte-2); }

/* --------------------------------------------------------------------
   Der Rechtstext (.dse)

   Das Fragment aus templates/dse/ ist kein Verwaltungsformular: Ein
   Mensch muss es lesen und verantworten, bevor es als Information nach
   Art. 13 hinausgeht. Deshalb begrenzte Zeilenlänge, größere
   Zeilenhöhe und sichtbare Abschnittsgrenzen - und nicht die dichte
   Setzung der übrigen Masken.
   -------------------------------------------------------------------- */
.dse { max-width:52rem; line-height:1.7; }

/* Fliesstext schmaler als die Tabellen: 38rem sind rund 75 Zeichen. Die
   Angabentabelle braucht mehr Breite und bekommt sie. */
.dse p, .dse-kurzuebersicht li { max-width:38rem; }

.dse h2 { margin:0 0 var(--raum-3); font-size:var(--schrift-lg); letter-spacing:-.01em; }
.dse h3 { margin:var(--raum-5) 0 var(--raum-2); font-size:var(--schrift-md); }
.dse strong { font-weight:650; }

.dse-abschnitt { margin:0 0 var(--raum-6); }

/* Wer prüft, muss sehen, wo eine Pflichtangabe aufhört und die
   nächste beginnt. Übersicht und Lückenliste tragen eine eigene
   Fläche und brauchen die Linie nicht. */
.dse-abschnitt + .dse-abschnitt:not(.dse-uebersicht):not(.dse-lueckenliste) {
    padding-top:var(--raum-5); border-top:1px solid var(--rand-weich);
}

.dse-rahmen p, .dse-typ p { margin:0 0 var(--raum-4); }

/* Verantwortlicher und Anschrift sind die eine Angabe, die eine
   betroffene Person abschreibt, um sich zu wenden. */
.dse-verantwortlicher {
    margin:0 0 var(--raum-4); padding-left:var(--raum-4); line-height:1.5;
    border-left:2px solid var(--akzent);
}

.dse-normen p { font-size:var(--schrift-md); color:var(--tinte-2); }

/* --------------------------------------------------------------------
   Erste Schicht: die Kurzübersicht (WP260 rev.01)

   Sie ordnet und ersetzt nichts. Eigene Fläche, damit sie als Einstieg
   erkennbar ist - aber ohne Rahmen, der sie zu einem Kasten NEBEN dem
   Text machen würde; sie gehört in den Text.
   -------------------------------------------------------------------- */
.dse-uebersicht {
    margin:0 0 var(--raum-6); padding:var(--raum-4) var(--raum-5);
    background:var(--flaeche-2); border-radius:var(--radius-xs);
}
.dse-kurzuebersicht { margin:0; padding:0; list-style:none; }
.dse-kurzuebersicht li {
    padding:var(--raum-2) 0 var(--raum-2) var(--raum-4); border-left:2px solid var(--rand);
}
.dse-kurzuebersicht li + li { margin-top:var(--raum-1); }
.dse-grundlage { color:var(--tinte-2); font-size:.9em; }

/* --------------------------------------------------------------------
   Zweite Schicht: die Einzelheiten je Verarbeitung
   -------------------------------------------------------------------- */
.dse-einzelheiten { margin:0 0 var(--raum-6); }
.dse-gruppe { margin:0 0 var(--raum-6); }
.dse-gruppe > h2 { padding-bottom:var(--raum-1); border-bottom:1px solid var(--rand); }

.dse-verarbeitung { margin:0 0 var(--raum-5); }

/* Nur die Überschrift einer Verarbeitung trägt den Akzentstrich. Die
   Zwischenüberschriften im Typabschnitt (.dse-typ) sind Rahmentext -
   mit demselben Strich ließe sich ein Rahmenkapitel als Verarbeitung
   lesen. */
.dse-verarbeitung > h3 { padding-left:var(--raum-3); border-left:3px solid var(--akzent); }

/* --------------------------------------------------------------------
   Die Angaben je Verarbeitung (.dse-angaben)

   Die Zeilenköpfe sind hier keine Spaltenetiketten, sondern Wörter im
   Text ("Wie lange wir speichern"). Sie stehen deshalb in normaler
   Schreibweise: Die Versalien des Grundstils machten aus einer Angabe
   eine Rubrik - und aus dem Rechtstext eine Maske.
   -------------------------------------------------------------------- */
.dse-angaben { margin:0; font-size:var(--schrift-md); }
.dse-angaben th[scope="row"] {
    width:12rem; padding:var(--raum-2) var(--raum-4) var(--raum-2) 0; vertical-align:top;
    font-size:var(--schrift-md); font-weight:650; letter-spacing:0; text-transform:none;
    color:var(--tinte-2);
    /* Gleiche Linienstärke wie die Datenzelle daneben - zwei Stärken in
       einer Zeile lesen sich wie eine kaputte Tabelle. */
    border-bottom:1px solid var(--rand-weich);
}
.dse-angaben td { padding:var(--raum-2) 0; }

/* --------------------------------------------------------------------
   Lücken (AP-G07)

   Die Lückenliste steht IM Wortlaut, nicht daneben. Sie ist der
   Unterschied zwischen einem Vorschlag und einer Datenschutzerklärung
   und muss das Erste sein, was auffällt. Die Aussage selbst ist Text -
   "Dieser Entwurf ist noch nicht vollständig"; Rahmen und Farbe
   wiederholen sie nur (WCAG 1.4.1).
   -------------------------------------------------------------------- */
.dse-lueckenliste {
    margin:0 0 var(--raum-6); padding:var(--raum-4) var(--raum-5); border-radius:0 var(--radius-xs) var(--radius-xs) 0;
    border:1px solid var(--warn); border-left-width:4px;
    background:color-mix(in srgb, var(--warn) 6%, transparent);
}
.dse-lueckenliste > h2 { color:var(--warn); }
.dse-luecken { margin:var(--raum-4) 0 0; font-size:var(--schrift-sm); }

/* Erste Spalte ist das Normzitat - der Einstieg beim Nacharbeiten. */
.dse-luecke-zeile td:first-child { color:var(--warn); font-weight:650; }

/* Inline im Wortlaut. Der Text beginnt mit "Offen"; die Einfärbung
   macht die Stelle auffindbar, trägt die Aussage aber nicht allein. */
.dse-luecke {
    padding:var(--raum-1) var(--raum-1); border-radius:var(--radius-xs);
    color:var(--warn); font-weight:600;
    background:color-mix(in srgb, var(--warn) 8%, transparent);
    -webkit-box-decoration-break:clone; box-decoration-break:clone;
}

/* Ein Vorschlag darf nicht wie eine geltende Fassung aussehen. Die
   Aussage tragen die Worte - p.warnung über der Vorschau und die
   Lückenliste im Wortlaut; der Rahmen macht sie nur aus der Entfernung
   sichtbar. Eine lückenlose Fassung, die trotzdem Vorschlag ist,
   erreicht diese Regel nicht - dafür fehlt der Vorlage die Klasse. */
.dse-vorschau:has(.dse-lueckenliste) {
    border-color:var(--warn); border-top-width:4px;
}

/* --------------------------------------------------------------------
   Das Fragment zum Einbetten (.dse-einbettung)

   Es wird zum Kopieren gezeigt: dicktengleiche Schrift, umbruchfähig an
   jeder Stelle - Prüfsummen und Adressen haben keine Leerzeichen - und
   auswählbar. Die Route liefert es heute als text/plain aus; dort
   erreicht es kein Stilblatt. Die Regeln greifen, sobald es in einer
   Seite steht.
   -------------------------------------------------------------------- */
.dse-einbettung {
    padding:var(--raum-4) var(--raum-4); border-radius:var(--radius-xs);
    background:var(--flaeche-2); border:1px solid var(--rand);
    font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
    font-size:var(--schrift-sm); line-height:1.6;
    overflow-wrap:anywhere;
    -webkit-user-select:text; user-select:text;
}

/* Steht im Fragment selbst und geht damit auf die Mandantenwebsite: Dort
   gibt es diese Variablen nicht, und die Farbe fällt aus. Die Aussage
   trägt deshalb der fette Satz davor ("Diese Fassung ist
   zurückgezogen."), nicht der Streifen. */
.dse-hinweis {
    margin:0 0 var(--raum-4); padding:var(--raum-2) var(--raum-4); font-size:var(--schrift-md);
    border-left:3px solid var(--hinweis);
    background:color-mix(in srgb, var(--hinweis) 8%, transparent);
}

.dse-fassungsvermerk {
    margin:var(--raum-5) 0 0; padding-top:var(--raum-2);
    border-top:1px solid var(--rand-weich);
    color:var(--tinte-2); font-size:var(--schrift-sm); overflow-wrap:anywhere;
}

/* --------------------------------------------------------------------
   Erzeugen je Erklärungstyp (.dse-typen)

   Die nationalen Normen stehen NEBEN dem Knopf und nicht darunter: Sie
   sagen, was dieser Knopf erzeugt.
   -------------------------------------------------------------------- */
.dse-typen { margin:0 0 var(--raum-5); padding:0; list-style:none; display:grid; gap:var(--raum-2); }
.dse-typen form { display:flex; flex-wrap:wrap; align-items:center; gap:var(--raum-3); }

/* --------------------------------------------------------------------
   Fachliche Durchsicht

   Vier Zustände. In jeder Legende steht das Wort dazu ("- bestätigt",
   "- veraltet"), die Farbe kommt hinzu und trägt nichts allein
   (WCAG 1.4.1). "Veraltet" ist der gefährliche Zustand: Es gibt einen
   Vermerk, aber er gilt einem Wortlaut, der sich seither geändert hat -
   er steht deshalb in der Warnfarbe und auf getönter Fläche.

   [class^="durchsicht-"] trifft genau die vier Zustandsklassen; die
   Klasse wird in der Vorlage aus p.zustand gebildet.
   -------------------------------------------------------------------- */
.durchsicht-offen, .durchsicht-veraltet,
.durchsicht-bestaetigt, .durchsicht-zu_aendern {
    margin:0 0 var(--raum-5); padding:var(--raum-4) var(--raum-4) var(--raum-4); border-radius:0 var(--radius-xs) var(--radius-xs) 0;
    border:1px solid var(--rand); border-left-width:4px;
    background:var(--flaeche);
}
.durchsicht-offen { border-left-color:var(--tinte-3); }
.durchsicht-veraltet {
    border-left-color:var(--warn);
    background:color-mix(in srgb, var(--warn) 6%, transparent);
}
.durchsicht-zu_aendern { border-left-color:var(--hinweis); }
.durchsicht-bestaetigt { border-left-color:var(--gut); background:var(--flaeche-2); }

/* >> DER KOPF EINER POSITION IST EIN <summary> UND KEINE <legend> (AP-H16).

   Die Maske trug 48 vollständig ausgeklappte Formulare untereinander; nichts
   sagte, welches als nächstes dran ist. Jede Position ist jetzt ein
   <details>, und aufgeschlagen ist genau eines. Die Zustandsfarbe bleibt am
   Kasten, das Zustandswort steht im Kopf und trägt die Aussage allein
   (WCAG 1.4.1).

   KEIN display:flex auf dem <summary>. Chrome und Safari nehmen ihm damit das
   Dreieck - und das ist der einzige Hinweis darauf, dass hier etwas aufgeht.
   Aus demselben Grund steht der Stand in einem <span> und nicht in einer
   eigenen Zeile. */
[class^="durchsicht-"] > summary {
    padding:var(--raum-2) var(--raum-2); font-size:var(--schrift-md); font-weight:650;
    cursor:pointer; border-radius:var(--radius-xs);
}
/* Getönte Fläche als Zeigerspur scheidet aus: .durchsicht-bestaetigt liegt
   selbst auf --fläche-2, dort wäre sie unsichtbar. */
[class^="durchsicht-"] > summary:hover { text-decoration:underline; }
.durchsicht-offen > summary { color:var(--tinte-2); }
.durchsicht-veraltet > summary { color:var(--warn); }
.durchsicht-zu_aendern > summary { color:var(--hinweis); }
.durchsicht-bestaetigt > summary { color:var(--gut); }

/* Der Stand steht NEBEN dem Namen. Untereinander wäre die zugeklappte Liste
   sofort wieder 96 Zeilen lang. */
.durchsicht-stand { font-weight:400; font-size:var(--schrift-sm); }

[class^="durchsicht-"] table { margin-bottom:var(--raum-4); }

/* size="80" sprengt sonst die Spalte auf schmalen Geräten. */
[class^="durchsicht-"] input[type="text"] { max-width:100%; }

/* Feldpfad und Belegstelle sind Zitate aus dem Quelltext: Sie müssen
   sich von der Prosa daneben unterscheiden, sonst prüft man das
   falsche. */
.hilfe code,
[class^="durchsicht-"] code {
    padding:var(--raum-1) var(--raum-1); border-radius:var(--radius-xs);
    background:var(--flaeche-2); border:1px solid var(--rand-weich);
    font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
    font-size:.9em; overflow-wrap:anywhere;
}

/* --- Zugeklappt ist der Regelfall (AP-H16) -----------------------------
   Die Kastenmaße oben gelten dem AUFGESCHLAGENEN Kasten: 1,2rem Polsterung,
   1,5rem Abstand. Bei 48 zugeklappten Köpfen wäre die Liste allein daraus
   wieder zwei Bildschirme lang.

   Gleiche Gewichtung wie .durchsicht-offen (0,1,0) - diese Regel gewinnt nur,
   weil sie WEITER UNTEN steht. Wer den Block nach oben schiebt, holt sich die
   alte Polsterung zurück. */
.durchsicht-falt { margin:0 0 var(--raum-1); padding:0; }
.durchsicht-falt[open] { margin-bottom:var(--raum-5); padding-bottom:var(--raum-4); }
.durchsicht-falt[open] > summary { border-bottom:1px solid var(--rand-weich); }
/* Wie details.feldgruppe (app.css:1219): nur seitlicher Einzug, den
   senkrechten Abstand bringen Tabelle und Formular selbst mit. */
.durchsicht-falt > :not(summary) { margin:0 var(--raum-4); }

/* --- Annahme und Vermerk nebeneinander (AP-H15) ------------------------
   Links steht, was zu prüfen ist, rechts die Entscheidung darüber. Der
   Absendeknopf steht damit neben dem Wortlaut, über den er entscheidet, und
   nicht sieben Tabellenzeilen darunter.

   Erst ab 90rem: Darunter ist die Arbeitsspalte eine Textspalte, und zwei
   Spalten wären zwei zu schmale. Es ist dieselbe Schwelle, an der
   .welt-backoffice main auf 100rem wächst - eine zweite Schwelle wäre eine
   zweite Wahrheit über die Fensterbreite. */
@media (min-width:90rem) {
    .durchsicht-paar {
        display:grid; grid-template-columns:minmax(0,3fr) minmax(0,2fr);
        gap:0 var(--raum-5); align-items:start;
    }
}

/* Der Monatsauszug trägt seinen SHA-256 in einer .klein-Zelle. Klein ja,
   aber nicht kleiner: Er wird Zeichen für Zeichen verglichen. */
.klein code { font-size:var(--schrift-sm); }

/* Maskiert wird im Server (AP-E30). Diese Regel versteckt nichts - sie macht
   nur den Platzhalter als solchen kenntlich. */
.maskiert { margin:0 0 var(--raum-1); }
.maskiert code { color:var(--tinte-2); letter-spacing:.08em; }
span.unterzeile { display:inline; margin:0; }
small.hilfe, span.hilfe { display:block; margin-top:var(--raum-1); line-height:1.45; }
caption.nr { text-align:left; padding:0 0 var(--raum-2); }
span.klein { display:block; margin-top:var(--raum-1); }

/* "Vorschau - kein Nachweis" in dokument/liste und "N Tage überschritten" in
   der Fristenliste sind dieselbe Aussage in zwei Spalten: Was hier steht,
   trägt im Streitfall nicht. */
td.warnung { color:var(--warn); }
td.fehler  { color:var(--warn); font-weight:650;
    background:color-mix(in srgb, var(--warn) 7%, transparent); }
div.hinweis > :first-child { margin-top:0; }
div.hinweis > :last-child  { margin-bottom:0; }


/* --------------------------------------------------------------------
   Prüfansicht einer Meldung (AP-F15)

   Links der Wortlaut des Mandanten, rechts die Arbeit. Der Unterschied ist
   nicht Zierde: Links steht Nachweis und kein Eingabefeld, und die ruhige
   Fläche sagt das, bevor jemand hineinzuklicken versucht.
   -------------------------------------------------------------------- */
@media (min-width:56rem) {
    .zweispaltig { grid-template-columns:minmax(0,1fr) minmax(0,1fr); }
}

.spalte--original {
    padding:var(--raum-4) var(--raum-4); background:var(--flaeche-2);
    border:1px solid var(--rand-weich); border-radius:var(--radius-xs);
}
.spalte--original > :first-child { margin-top:0; }
.spalte--original > :last-child  { margin-bottom:0; }

.antworten { margin:0; }
.antworten dt { margin-top:var(--raum-3); font-size:var(--schrift-xs); letter-spacing:.05em;
    text-transform:uppercase; color:var(--tinte-2); }
.antworten dt:first-child { margin-top:0; }
.antworten dd { margin:var(--raum-1) 0 0; overflow-wrap:break-word; }
/* Beide stehen in der Flaechenliste (Hintergrund, Rahmen, Radius), aber nicht
   in der Polsterungsliste. Die Vorschau braucht sie am Element; die
   Rueckfrage ist ein <details> und darf sie dort NICHT tragen - sonst
   verschiebt sich ihr summary. Sie bekommt nur den Aussenabstand. */
.dse-vorschau { margin:var(--raum-4) 0 var(--raum-6); padding:var(--raum-6); }
.rueckfrage   { margin:0 0 var(--raum-5); }

.rueckfrage > summary { padding:var(--raum-2) var(--raum-3); font-size:var(--schrift-sm);
    font-weight:600; cursor:pointer; }
.rueckfrage[open] > summary { border-bottom:1px solid var(--rand-weich); }
/* Nur seitlicher Einzug: Den senkrechten Abstand bringt .formular-schmal aus
   app.css bereits mit, und der wird hier nicht überschrieben. */
.rueckfrage > form { padding:0 var(--raum-3); }
.vorschlag > :first-child { margin-top:0; }
.vorschlag > :last-child  { margin-bottom:0; }
.vorschlag h3 { margin:0 0 var(--raum-1); font-size:var(--schrift-md); }

/* Der Normbezug ist der Grund, aus dem der Vorschlag folgt. Er steht abgesetzt
   und nicht im Fliesstext der Begründung - der Berater verantwortet ihn und
   muss dafür sehen, woraus er sich ergibt. */
.vorschlag .norm {
    margin:var(--raum-2) 0 0; padding-left:var(--raum-2);
    border-left:2px solid var(--akzent);
    color:var(--tinte-2); font-size:var(--schrift-sm);
}

/* Der einzige der neun Typen, den die Sammelübernahme nicht mitnimmt
   (ADR 0038, UebernahmeDienst::NICHT_SAMMELBAR): eine Rechtsfrage, die
   einzeln zu entscheiden ist. Der Rand ist die Zugabe - die Typbezeichnung
   steht als Wort in der .marke darüber. */
.vorschlag--pflichtpruefung { border-left:3px solid var(--hinweis); }
@media (min-width:34rem) {
    .angaben { grid-template-columns:minmax(0,max-content) minmax(0,1fr); }
}
.angaben dt { color:var(--tinte-2); font-size:var(--schrift-sm); }
.angaben dd { margin:0; overflow-wrap:break-word; }


/* --------------------------------------------------------------------
   Listen mit Zeilenzustand
   -------------------------------------------------------------------- */
table.liste tbody tr:hover { background:var(--flaeche-2); }

/* Sofort-Priorität in der Meldungsliste. Zusätzlich zur Färbung ein Balken
   an der ersten Zelle, damit die Zeile nicht allein an der Farbe hängt
   (WCAG 1.4.1) - inset, damit sie nicht verspringt. Das WORT "sofort" liefert
   die Vorlage nicht; siehe Anmerkung. */
tr.zeile--offen td { background:color-mix(in srgb, var(--warn) 6%, transparent); }
tr.zeile--offen td:first-child { box-shadow:inset 3px 0 0 var(--warn);
    font-weight:650; }

/* Erfassungsstand der 57 Mandanten. Die letzte Spalte nennt den Zustand als
   Wort; die Färbung ist die Zugabe für den Blick über die ganze Liste.
   "offen" bleibt ungefärbt - es ist der Ausgangszustand und kein Befund. */
tr.zustand-bestaetigt td { background:color-mix(in srgb, var(--gut) 5%, transparent); }
tr.zustand-begonnen td   { background:color-mix(in srgb, var(--hinweis) 6%, transparent); }


/* --------------------------------------------------------------------
   Namensvorschlag und Kandidaten (AP-D09)
   -------------------------------------------------------------------- */
.kandidaten { display:grid; gap:var(--raum-1); margin:var(--raum-2) 0 0; padding:0;
    list-style:none; }
.kandidaten li { display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--raum-2); }

/* Der Kandidat trägt nichts ein, er schlägt vor - er sieht deshalb aus wie
   eine Schaltfläche und nicht wie ein bereits gefuelltes Feld. */
button.kandidat {
    padding:var(--raum-1) var(--raum-2); font:inherit; font-size:var(--schrift-sm); text-align:left;
    color:var(--akzent); background:var(--flaeche);
    border:1px solid var(--rand); border-radius:var(--radius-xs); cursor:pointer;
}
button.kandidat:hover { background:var(--akzent-weich); }


/* --------------------------------------------------------------------
   Anhänge, Einstellungen, Aufbewahrung
   -------------------------------------------------------------------- */
.anhaenge { margin:var(--raum-5) 0; padding-top:var(--raum-4);
    border-top:1px solid var(--rand); }
.anhaenge h3 { margin:0 0 var(--raum-2); font-size:var(--schrift-md); }
.versandstand > :first-child { margin-top:0; }
.versandstand > :last-child  { margin-bottom:0; }

.einstellungsgruppe { background:var(--flaeche); }

.einstellungsgruppe .feld { display:grid; gap:var(--raum-1); margin:0 0 var(--raum-4); max-width:34rem; }
.einstellungsgruppe .feld > label { font-size:var(--schrift-sm); font-weight:600; }

/* Eine fehlende Pflichtangabe ist kein Fehler, sondern eine offene Stelle:
   Sie fällt am Rand auf und behält daneben den Stern im Label - die Farbe
   trägt die Aussage nicht allein (WCAG 1.4.1). */
.feld--fehlt { padding-left:var(--raum-3); border-left:3px solid var(--hinweis); }
.pflicht { margin-left:var(--raum-1); color:var(--warn); }

.hinweisliste { margin:0 0 var(--raum-5); padding:0; max-width:52rem;
    list-style:none; }
.hinweisliste li { margin:0 0 var(--raum-3); padding-left:var(--raum-4);
    border-left:2px solid var(--rand-weich); color:var(--tinte-2); }
.hinweisliste strong { color:var(--tinte); }


/* >> `button.knopf-klein` STEHT NICHT MEHR HIER.

   Die Regel nahm mit (0,1,1) und 3.500 Zeilen Vorsprung genau die Korrektur
   zurueck, die der Knopfabschnitt begruendet: --rand erreicht 1,30:1, verlangt
   sind 3:1 (WCAG 1.4.11). Von 39 Fundstellen bekamen die 15 <a> die starke
   Kante und die 24 <button> nicht - in loeschklasse/liste stehen beide Formen
   in derselben Zelle.

   Seit der Umstellung auf `:where(button, input[type="submit"])` mit
   Spezifitaet null braucht es das Abraeumen nicht mehr: Jede Klasse schlaegt
   den Grundknopf von selbst. */

/* Genau ein Absendeknopf je Stammdatenmaske (AP-D09) - er darf aussehen wie
   die Handlung, um die es geht. */
input::placeholder, textarea::placeholder { color:var(--tinte-2); }

label > input[type=checkbox] { margin-right:var(--raum-2); }
form > label   { margin-bottom:var(--raum-3); }
form p > label { font-size:var(--schrift-sm); font-weight:600; }

a.knopf-klein, button, button.kandidat { transition:background-color .12s ease-out; }
@media (prefers-reduced-motion: reduce) {
    a.knopf-klein, button, button.kandidat { transition:none; }
}
/* === Anfragen, Vorfälle, Beratung, Mandanten, Personen ===
   Betroffenenanfragen (Art. 15-22), Datenpannen (Art. 33/34), Beratungslog,
   Mandantenstammdaten, Portalzugänge, Vertretungsregel.

   Zwei Gestaltungsentscheidungen ziehen sich durch diesen Abschnitt:

   1. Jede Fläche, die Daten der Kunden, Mitarbeiter oder Patienten eines
      Mandanten zeigt, bekommt eine sichtbare Umrandung. Wer bei einer
      Bildschirmübergabe scrollt, soll sehen, wo die Akte anfängt und wo sie
      aufhört.
   2. Wo eine Farbe einen Zustand meint, steht der Zustand bereits als Wort in
      der Vorlage ("erfuellt", "offen", "Vollzogen am", "nicht erhoben"). Die
      Farbe verstärkt, sie trägt nicht (WCAG 1.4.1). Wo die Vorlage kein Wort
      liefert, bleibt die Farbe hier weg.

   Nichts in diesem Abschnitt bewegt sich, deshalb gibt es keinen Block für
   prefers-reduced-motion. */

p.klein { margin:var(--raum-2) 0 var(--raum-4); max-width:52rem; }

/* --------------------------------------------------------------------
   Meldungen und Hinweisblöcke

   app.css kennt p.fehler / p.erfolg / p.hinweis. Diese Familie schreibt
   dieselbe Aussage an zwei Stellen anders: als p.meldung mit Modifikator
   (portal/checkliste, vertretung/erfassen) und als div.hinweis mit mehreren
   Absätzen. Ein Elementselektor p.hinweis trifft ein <div> nicht - deshalb
   hier die Ergänzung, nicht die Neufassung.
   -------------------------------------------------------------------- */
p.meldung {
    margin:0 0 var(--raum-4); padding:var(--raum-2) var(--raum-3); border-radius:var(--radius-xs);
    border-left:3px solid currentColor; font-size:var(--schrift-md);
    color:var(--tinte-2); background:var(--flaeche-2);
}
p.meldung--erfolg { color:var(--gut);  background:color-mix(in srgb, var(--gut) 7%, transparent); }
p.meldung--fehler { color:var(--warn); background:color-mix(in srgb, var(--warn) 7%, transparent); }

/* In den Hinweisen stehen Konsolenaufrufe (portal/rollout, vertretung). */
td .marke--ok {
    color:var(--gut); border-color:var(--gut);
    background:color-mix(in srgb, var(--gut) 8%, transparent);
}
td .marke--offen {
    color:var(--warn); border-color:var(--warn);
    background:color-mix(in srgb, var(--warn) 8%, transparent);
}

table.liste { margin:var(--raum-2) 0 var(--raum-5); }
table.liste td small { font-size:var(--schrift-sm); color:var(--tinte-2); }

/* Ergänzung zu .formular-schmal aus app.css: den Prüfvermerk nach
   Paragraf 96a ArbVG in portal/checkliste umschliesst ein fieldset. */
.formular-schmal fieldset {
    display:grid; gap:var(--raum-1); margin:var(--raum-4) 0 var(--raum-2);
    padding:var(--raum-2) var(--raum-4) var(--raum-4); border:1px solid var(--rand); border-radius:var(--radius-xs);
}
.formular-schmal legend {
    padding:0 var(--raum-1); font-size:var(--schrift-xs); letter-spacing:.05em;
    text-transform:uppercase; color:var(--tinte-2);
}

/* --------------------------------------------------------------------
   Beratungseintrag (backoffice/beratung/_eintrag.html.twig)

   Der Eintrag ist eine Karte mit Rand, weil im Feld "Sachverhalt" Angaben
   über Beschäftigte und Kunden des Mandanten stehen - beim internen Eintrag
   zusätzlich die Beschreibung eines Hinweisgebers. Der Rand sagt, wo dieser
   Bestand endet.

   Der Nachtrag ist eingerückt und trägt eine Akzentkante: Er gehört zu
   einem früheren Eintrag, ersetzt ihn aber nicht. Die Zuordnung steht
   zusätzlich im Text ("Nachtrag vom ... zum Eintrag vom ...").
   -------------------------------------------------------------------- */
article.beratungseintrag.nachtrag {
    margin-left:var(--raum-5); background:var(--flaeche-2);
    border-left:3px solid var(--akzent);
}
.beratungseintrag header h3 { margin:0 0 var(--raum-1); font-size:var(--schrift-md); }
.beratungseintrag header h3 .nr { font-weight:400; }
.beratungseintrag header .unterzeile { margin:0 0 var(--raum-1); }
.beratungseintrag header .nr { margin:0; }

.beratungseintrag dl {
    display:grid; grid-template-columns:11rem 1fr; gap:var(--raum-2) var(--raum-4);
    margin:var(--raum-4) 0 0; padding:var(--raum-3) 0 0; border-top:1px solid var(--rand-weich);
}
.beratungseintrag dt {
    font-size:var(--schrift-xs); letter-spacing:.05em; text-transform:uppercase;
    color:var(--tinte-2);
}
.beratungseintrag dd { margin:0; }

.beratungseintrag form {
    display:flex; flex-wrap:wrap; align-items:end; gap:var(--raum-4);
    margin:var(--raum-4) 0 0; padding:var(--raum-4) 0 0; border-top:1px solid var(--rand-weich);
}
.beratungseintrag form label {
    display:grid; gap:var(--raum-1); font-size:var(--schrift-sm); color:var(--tinte-2);
}
.beratungseintrag form input[type=text] { min-width:20rem; }

/* --------------------------------------------------------------------
   Mandatsende (backoffice/mandant/offboarding.html.twig)

   Die Leiter zeigt zehn Jahre auf einen Blick. Vollzogene und offene Stufe
   unterscheiden sich am Rand der Ziffer (durchgezogen gegen gestrichelt) und
   nicht nur an der Farbe; der Zustand steht ausserdem als Satz darunter
   ("Vollzogen am ..." / "Offen.").
   -------------------------------------------------------------------- */
section.offboarding > h2 { margin:0 0 var(--raum-3); font-size:var(--schrift-lg); }

ol.stufenleiter { list-style:none; margin:var(--raum-4) 0; padding:0; }

li.stufe {
    position:relative; display:grid; grid-template-columns:2rem 1fr;
    gap:var(--raum-4); padding:0 0 var(--raum-5);
}
li.stufe:last-child { padding-bottom:0; }

/* Die Linie zwischen den Ziffern macht aus Einzelpunkten eine Reihenfolge. */
li.stufe:not(:last-child)::before {
    content:""; position:absolute; left:1rem; top:2.2rem; bottom:.2rem;
    width:1px; background:var(--rand);
}

.stufe__nummer {
    position:relative; z-index:1;
    display:grid; place-items:center; width:2rem; height:2rem;
    font-size:var(--schrift-sm); font-weight:650;
    color:var(--tinte-2); background:var(--flaeche);
    border:1px solid var(--rand); border-radius:50%;
}
.stufe--vollzogen .stufe__nummer {
    color:var(--gut); border-color:var(--gut);
    background:color-mix(in srgb, var(--gut) 12%, transparent);
}
.stufe--offen .stufe__nummer { border-style:dashed; color:var(--tinte-2); }

.stufe__inhalt h3 { margin:var(--raum-1) 0 var(--raum-1); font-size:var(--schrift-md); }
.stufe--offen .stufe__inhalt h3 { color:var(--tinte-2); }

.stufe__stand { margin:0; font-size:var(--schrift-sm); }
.stufe__bemerkung { margin:var(--raum-1) 0 0; font-size:var(--schrift-sm); color:var(--tinte-2); }
.stufe__bedingung { margin:var(--raum-1) 0 0; font-size:var(--schrift-sm); color:var(--hinweis); }

/* Die Grundlage steht klein unter jeder Stufe - sie wird gelesen, wenn gefragt
   wird, worauf sich der Schritt stützt, nicht beim Überfliegen. */
.stufe__grundlage { margin:var(--raum-1) 0 0; font-size:var(--schrift-sm); color:var(--tinte-2); }

.offboarding__naechste {
    margin:var(--raum-4) 0 0; padding:var(--raum-2) var(--raum-3); font-size:var(--schrift-md);
    background:var(--flaeche-2); border-left:3px solid var(--akzent);
    border-radius:0 var(--radius-xs) var(--radius-xs) 0;
}

/* --------------------------------------------------------------------
   Ansprechpartner (backoffice/mandant/_ansprechpartner.html.twig)

   Fragment ohne eigenes Layout, per HTMX nachgeladen. Der Rand ist nötig,
   damit die Namensliste nicht in die umgebende Mandantenmaske ausfranst - und
   weil hier Namen, Funktionen und Rufnummern natürlicher Personen stehen.
   -------------------------------------------------------------------- */
section.ansprechpartner > h3 { margin:0 0 var(--raum-2); font-size:var(--schrift-md); }

/* --------------------------------------------------------------------
   Vertretungsregel (backoffice/vertretung/erfassen.html.twig)

   Je Rechtsträger ein eigenes Formular, deshalb je Rechtsträger eine eigene
   Karte: Zwei untereinander stehende Formulare ohne Rand sehen aus wie eines,
   und dann wird die Angabe des zweiten Trägers am ersten gespeichert.
   -------------------------------------------------------------------- */
form.vertretung h2 { margin:0 0 var(--raum-1); font-size:var(--schrift-md); }
form.vertretung h2 small {
    margin-left:var(--raum-2); font-size:var(--schrift-sm); font-weight:400; color:var(--tinte-2);
}
form.vertretung label { margin-top:var(--raum-2); font-size:var(--schrift-sm); font-weight:600; }
form.vertretung button { justify-self:start; margin-top:var(--raum-4); }

p.stand {
    margin:0 0 var(--raum-2); padding:var(--raum-2) var(--raum-3); font-size:var(--schrift-sm);
    background:var(--flaeche-2); border-left:3px solid var(--rand);
    border-radius:0 var(--radius-xs) var(--radius-xs) 0;
}

/* Ein <strong> steht in dieser Zeile nur in den beiden Fällen, die die
   Freigabe blockieren oder unbelegt lassen: "nicht erhoben" und "ohne
   Abrufdatum". Beide sind ausgeschrieben - die Färbung holt sie nur nach
   vorn. Ohne :has() bleibt die Zeile lesbar, nur ruhiger. */
p.stand:has(strong) {
    border-left-color:var(--warn);
    background:color-mix(in srgb, var(--warn) 6%, transparent);
}

/* --------------------------------------------------------------------
   Schmale Bildschirme

   Die Beschreibungsliste des Beratungseintrags und die Stufenleiter sind die
   einzigen zweispaltigen Gebilde dieser Familie. Unter 40rem wird aus beiden
   eine Spalte; die Tabellen bleiben, wie sie sind.
   -------------------------------------------------------------------- */
@media (max-width:40rem) {
    .beratungseintrag dl { grid-template-columns:1fr; gap:var(--raum-1); }
    .beratungseintrag dd { margin:0 0 var(--raum-2); }
    article.beratungseintrag.nachtrag { margin-left:var(--raum-2); }
    li.stufe { grid-template-columns:1.6rem 1fr; gap:var(--raum-2); }
    .stufe__nummer { width:1.6rem; height:1.6rem; font-size:var(--schrift-xs); }
    li.stufe:not(:last-child)::before { left:.8rem; top:1.8rem; }
}

/* -- Zustandsbild (AP-F03) ----------------------------------------------- */
.zustandsbild h2 { margin:0 0 var(--raum-4); font-size:var(--schrift-lg); }

/* DIE STUFE BLEIBT ABSICHTLICH OHNE FARBABSTUFUNG.
   Die vier Werte kommen als .stufe--nicht_dokumentiert, --in_arbeit,
   --dokumentiert und --dokumentiert_und_freigegeben an. Sie rot/gelb/grün zu
   färben wäre genau die Ampel, die AP-F03 ausschließt und die
   tests/Golden/portal/sperrliste_scheingenauigkeit.txt bei jedem Lauf
   nachhält. Die Aussage trägt der ausgeschriebene Satz.
   Eingegrenzt auf .zustandsbild, weil .stufe im Backoffice-Offboarding eine
   andere Bedeutung hat. */
.zustandsbild .stufe {
    margin:0 0 var(--raum-4); padding:var(--raum-3) var(--raum-4); font-size:var(--schrift-md);
    background:var(--flaeche-2); border-left:3px solid var(--akzent);
    border-radius:0 var(--radius-xs) var(--radius-xs) 0;
}

.zaehlwerte { list-style:none; margin:0; padding:0; }
.zaehlwerte li {
    padding:var(--raum-2) 0 var(--raum-2) var(--raum-4); border-left:2px solid var(--rand-weich);
}

/* Der Vorbehalt ist die wichtigste Aussage der Seite und keine Fußnote: volle
   Schriftgrösse, eigener Block. Keine Warnfarbe - er meldet keinen Fehler,
   sondern begrenzt die Reichweite des Bildes. Backoffice benutzt dieselbe
   Klasse an einem <p>; die Regeln passen auf beides. */
div.vorbehalt {
    max-width:48rem; margin:var(--raum-6) 0 0; padding:var(--raum-4) var(--raum-5);
    background:var(--flaeche-2);
    border:1px solid var(--rand); border-left:4px solid var(--akzent);
    border-radius:0 var(--radius-sm) var(--radius-sm) 0;
}
div.vorbehalt h2 { margin:0 0 var(--raum-2); font-size:var(--schrift-md); }
div.vorbehalt p { margin:0 0 var(--raum-3); }
div.vorbehalt p:last-child { margin-bottom:0; }

/* -- Freigegebene Fassung, Blätter (AP-F04) ------------------------------ */

.blatt {
    max-width:48rem; margin:0 0 var(--raum-5); padding-top:var(--raum-4);
    border-top:1px solid var(--rand-weich);
}
.blatt h2 { margin:0 0 var(--raum-3); font-size:var(--schrift-lg); }

/* Der Blattinhalt ist Klartext aus dem Snapshot: Er behält seine Zeilenform
   (pre-wrap), bricht aber innerhalb langer Zeichenketten um, damit er die
   Seite nicht aufzieht. Ein waagrechter Rollbalken auf Seitenebene würde die
   Kopfleiste mitverschieben. */
.blattinhalt {
    margin:0; padding:var(--raum-4);
    background:var(--flaeche-2); border:1px solid var(--rand-weich); border-radius:var(--radius-sm);
    font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
    font-size:var(--schrift-sm); line-height:1.55;
    white-space:pre-wrap; overflow-wrap:anywhere;
}

/* Angefangenes zuerst und sichtbar abgesetzt. Steht es im selben Weiss wie die
   Neu-Liste, sucht der Mandant seinen unterbrochenen Lauf nicht dort, sondern
   fängt neu an. */
.angefangen {
    max-width:48rem; margin:0 0 var(--raum-6); padding:var(--raum-4) var(--raum-4);
    background:var(--akzent-weich); border-radius:var(--radius-sm);
}
.angefangen h2 { margin:0 0 var(--raum-2); font-size:var(--schrift-md); }

.liste-schlicht { list-style:none; margin:0; padding:0; }
.liste-schlicht li { padding:var(--raum-2) 0; }
.liste-schlicht li + li {
    border-top:1px solid color-mix(in srgb, var(--rand) 60%, transparent);
}
.liste-schlicht small { display:block; color:var(--tinte-2); font-size:var(--schrift-sm); }

.assistentenliste { max-width:48rem; }
.assistentenliste h2 { margin:0 0 var(--raum-3); font-size:var(--schrift-md); }
.assistentenliste form { margin:0 0 var(--raum-3); }

/* -- Assistentenrahmen (AP-F12) ------------------------------------------ */

.assistent { max-width:44rem; accent-color:var(--akzent); }

.assistent__kopf {
    margin:0 0 var(--raum-6); padding-bottom:var(--raum-4); border-bottom:1px solid var(--rand);
}
.assistent__kopf h1 { margin:0 0 var(--raum-1); }

/* "Schritt 2 von 6", kein Balken und kein Prozentwert. Die Zeile ist eine
   Ortsangabe, keine Fortschrittsanzeige - sie steht deshalb klein und ruhig
   und nicht als Grafik. */
.assistent .fortschritt {
    margin:0; color:var(--tinte-2);
    font-size:var(--schrift-sm); letter-spacing:.04em; text-transform:uppercase;
}

/* Eingegrenzt auf .assistent: .feld und .hilfe kommen im Backoffice mit
   anderer Bedeutung vor. */
.assistent .feld { margin:0 0 var(--raum-5); }
.assistent .feld > label { display:block; margin:0 0 var(--raum-2); font-weight:600; }
.assistent .pflicht { color:var(--warn); }
.assistent .hilfe {
    display:block; margin-top:var(--raum-2); color:var(--tinte-2); font-size:var(--schrift-sm);
}

.assistent input[type=text],
.assistent input[type=date],
.assistent input[type=file],
.assistent textarea {
    width:100%; max-width:34rem; padding:var(--raum-2) var(--raum-3); font:inherit;
    color:var(--tinte); background:var(--flaeche);
    border:1px solid var(--rand); border-radius:var(--radius-xs);
}
.assistent textarea { min-height:6.5rem; resize:vertical; }

/* Radiobuttons statt Auswahlliste, und die Beschriftung ist die ganze Zeile:
   Eine Antwort, die man aufklappen muss, um sie zu sehen, ist für den
   Antwortenden keine. */
.assistent .optionen { margin:0; padding:0; border:0; }
.assistent .optionen legend { padding:0; }
.assistent .option {
    display:flex; align-items:flex-start; gap:var(--raum-2);
    padding:var(--raum-2) var(--raum-3); cursor:pointer;
    background:var(--flaeche); border:1px solid var(--rand-weich); border-radius:var(--radius-xs);
    transition:border-color 120ms ease;
}
.assistent .option + .option { margin-top:var(--raum-2); }
.assistent .option:hover { border-color:var(--rand); }
.assistent .option input { margin:var(--raum-1) 0 0; }

/* "Weiss ich nicht" ist eine gültige Antwort und kein Fehler: abgesetzt,
   damit man sie findet, aber ohne Warnfarbe. Wer sie rot färbt, erzieht zum
   Raten - und ein geratener Wert steht anschließend im Verzeichnis. */
.assistent .option.option--unbekannt {
    margin-top:var(--raum-3); border-style:dashed; color:var(--tinte-2);
}

.assistent__fuss {
    display:flex; flex-wrap:wrap; align-items:center; gap:var(--raum-4);
    margin-top:var(--raum-6); padding-top:var(--raum-4); border-top:1px solid var(--rand-weich);
}
/* "Später fortsetzen" ans andere Ende: Es ist der Ausstieg, nicht die
   Zweitfassung des Weiter-Knopfes. */
.assistent__fuss .spaeter { margin-left:auto; }
.spaeter { color:var(--tinte-2); font-size:var(--schrift-sm); }

/* Der Stand wechselt per aria-live, wenn der Stimulus-Controller gesichert
   hat. Feste Zeilenhöhe, damit der Text darunter beim Wechsel nicht springt. */
.sicherung {
    margin:var(--raum-4) 0 0; min-height:1.6rem;
    color:var(--tinte-2); font-size:var(--schrift-sm);
}

/* Ganze Sätze, kein Formular - und darum größer gesetzt als der übrige
   Fliesstext. Das ist der letzte Text, den jemand vor dem Absenden liest. */
.zusammenfassung {
    max-width:44rem; margin:0 0 var(--raum-5); padding:var(--raum-5) var(--raum-5);
    background:var(--flaeche); border:1px solid var(--rand); border-radius:var(--radius-sm);
}
.zusammenfassung p { margin:0 0 var(--raum-4); font-size:var(--schrift-lg); line-height:1.65; }
.zusammenfassung p:last-child { margin-bottom:0; }

/* Offen Gebliebenes erzeugt eine Rückfrage, keinen Fehler: Hinweisfarbe,
   nicht Warnfarbe. Der entlastende Satz steht in der Vorlage darüber. */
section.offene-punkte {
    max-width:44rem; margin:0 0 var(--raum-5); padding:var(--raum-4) var(--raum-4);
    background:color-mix(in srgb, var(--hinweis) 8%, transparent);
    border-left:3px solid var(--hinweis); border-radius:0 var(--radius-sm) var(--radius-sm) 0;
}
section.offene-punkte h2 { margin:0 0 var(--raum-2); font-size:var(--schrift-md); }
section.offene-punkte p { margin:0 0 var(--raum-2); }
section.offene-punkte ul { margin:0; padding-left:var(--raum-4); }
section.offene-punkte li { margin:var(--raum-1) 0; }

/* Der Wortlaut steht auf der Seite, nicht hinter einem Link. Der Abschnitt
   rahmt ihn und gibt ihm Luft, damit er auch gelesen wird;
   blockquote.wortlaut selbst kommt aus app.css. */
.erklaerung { max-width:44rem; margin:var(--raum-5) 0; }
.erklaerung h2 { margin:0 0 var(--raum-3); font-size:var(--schrift-md); }

/* Die Liste ZEIGT AN, sie entscheidet nichts - die Sperre sitzt im Endpunkt.
   Erfuellt und offen unterscheiden sich in Randfarbe, Fläche UND Wortlaut;
   der offene Punkt trägt zusätzlich ein <strong> aus der Vorlage. Die Farbe
   allein trägt die Aussage damit nicht (WCAG 1.4.1). Ein Zeichen (Haken,
   Punkt) wäre deutlicher, steht aber nicht im Markup - siehe Anmerkungen. */
.sperren { list-style:none; max-width:44rem; margin:0 0 var(--raum-6); padding:0; }
.sperren li { margin:0 0 var(--raum-2); padding:var(--raum-3) var(--raum-4); border-radius:0 var(--radius-xs) var(--radius-xs) 0; }
.sperren .erfuellt {
    color:var(--tinte-2); background:var(--flaeche-2);
    border-left:3px solid var(--gut);
}
.sperren .offen {
    background:color-mix(in srgb, var(--hinweis) 8%, transparent);
    border-left:3px solid var(--hinweis);
}
.sperren .offen strong { display:block; margin-bottom:var(--raum-1); }

/* Drei Wege, nicht einer: Freigabe, Freigabe mit Anmerkung, Ablehnung stehen
   gleichrangig untereinander. Die Textfelder sind volle Breite - das
   cols="60" der Vorlage wäre auf einem Telefon breiter als der Bildschirm. */
.zeichnen { max-width:44rem; accent-color:var(--akzent); }
.zeichnen fieldset {
    margin:0 0 var(--raum-5); padding:var(--raum-4) var(--raum-5);
    background:var(--flaeche); border:1px solid var(--rand); border-radius:var(--radius-sm);
}
.zeichnen legend { padding:0 var(--raum-2); font-weight:650; }
.zeichnen label { display:block; margin:var(--raum-3) 0 var(--raum-1); }
.zeichnen textarea {
    width:100%; max-width:100%; margin:0 0 var(--raum-4); padding:var(--raum-2) var(--raum-3); font:inherit;
    color:var(--tinte); background:var(--flaeche-2);
    border:1px solid var(--rand); border-radius:var(--radius-xs); resize:vertical;
}

/* Die einzigen Bewegungen dieses Abschnitts sind zwei Randfarbwechsel. */
@media (prefers-reduced-motion: reduce) {
    .assistent-knopf, .assistent .option { transition:none; }
}
/* ==========================================================================
   Die Geltungsmatrix (AP-H08)

   Tätigkeiten mal Unternehmen. Bei fünfzehn Spalten ist die Tabelle breiter
   als die Seite — sie scrollt deshalb in ihrer eigenen Hülle und nicht mit
   dem Dokument. Die erste Spalte bleibt dabei stehen; ohne sie ist eine Zeile
   im rechten Drittel nicht mehr zuzuordnen.
   ========================================================================== */

.matrixhuelle { overflow-x:auto; margin:0 0 var(--raum-5); }

table.matrix { width:auto; min-width:100%; font-size:var(--schrift-sm); }

.matrix__kopf {
    /* Firmenkürzel stehen aufrecht - gedrehte Spaltenköpfe sind schick und
       unlesbar, und dieses Werkzeug wird gelesen, nicht angeschaut. */
    min-width:5rem; text-align:center; vertical-align:bottom;
}

.matrix__zeile {
    position:sticky; left:0; z-index:1;
    min-width:16rem; max-width:22rem;
    text-align:left; font-weight:600; text-transform:none;
    letter-spacing:normal; font-size:var(--schrift-sm);
    background:var(--flaeche);
    border-right:1px solid var(--rand);
}
tr.zeile--offen .matrix__zeile { background:color-mix(in srgb, var(--warn) 6%, var(--flaeche)); }

.matrix__feld {
    text-align:center;
    font-variant-numeric:tabular-nums;
    /* Das Zeichen ist die Aussage - es darf nicht in der Zeile untergehen. */
    font-weight:600;
}
.matrix__feld a { color:var(--warn); text-decoration:none; padding-left:var(--raum-1); }
.matrix__feld a:hover, .matrix__feld a:focus-visible { text-decoration:underline; }

/* Für Screenreader vorhanden, für das Auge nicht. Ein Zeichen wie "±" allein
   ist keine Aussage (WCAG 1.4.1) - die Fassung daneben ist die Aussage. */
.nurvorlesen {
    position:absolute; width:1px; height:1px;
    margin:-1px; padding:0; border:0;
    clip-path:inset(50%); overflow:hidden; white-space:nowrap;
}

/* Ein Formular je Tabellenzeile (TOM-Liste, AP-H12). Die Felder stehen
   nebeneinander und brechen um, statt die Spalte zu sprengen. */
form.tom-zeile { display:flex; flex-wrap:wrap; align-items:flex-start; gap:var(--raum-2); margin:0; }
form.tom-zeile textarea { flex:1 1 22rem; min-height:3.5rem; max-width:none; }
form.tom-zeile select   { flex:0 0 10rem; }
form.tom-zeile input[type=date] { flex:0 0 9rem; }

/* Der Konfliktdialog ist eine Seite ohne Gerüst — er entsteht als Körper einer
   409-Antwort. Die Auflösung steht deshalb daneben und nicht im Kasten. */
.konflikt-aufloesung { margin:0 0 var(--raum-5); }

/* --- Das Portal stand im Navigationsstreifen ---------------------------
   `.rumpf` ist ein Zweispaltenraster (15.5rem für die Gliederung, der Rest für
   die Arbeit). Im Portal hat es genau EIN Kind — und ein einzelnes Kind landet
   in Spalte 1. Der ganze Portalinhalt stand damit in 248px, während
   `.welt-portal main { max-width:54rem }` (864px) nie greifen konnte.

   Zu sehen war es nur ab 1024px: Darunter schaltet die Abfrage weiter unten auf
   eine Spalte, und die Maske wurde breit. Das Portal war auf einem Laptop also
   fast fünfmal breiter als auf einem großen Monitor.

   Betroffen waren alle 13 Portalmasken, darunter die Freigabezeichnung — die
   Maske, auf der der Mandant unterschreibt. */
.welt-portal .rumpf { display:block; }

/* --- Das Backoffice bekommt die Breite, die da ist ----------------------
   70rem ist das Maß einer Textspalte. 58% der Masken sind aber Datenmasken:
   Tabellen, Listen, Formulare nebeneinander. Sie tragen den Satzspiegel eines
   Fließtextes mit, obwohl sie ihn nicht brauchen.

   Ab 90rem Fensterbreite (1440px, der erste Schritt oberhalb des bisherigen
   Deckels) darf die Arbeitsspalte deshalb bis 100rem wachsen. Der Fließtext
   wächst NICHT mit: Die Absatzklassen sind seit jeher auf 70ch gedeckelt, und
   die Regel darunter zieht die Absätze ohne Klasse nach. Ohne sie liefe eine
   Erläuterung über 1500px — lesbar ist das nicht. */
@media (min-width:90rem) {
    .welt-backoffice main { max-width:100rem; }
}

/* >> DER SPALTENKOPF IST MAL EIN <a>, MAL EIN <button> (AP-H28).
 *
 * Wo die Liste im Rumpf sucht, schickt der Kopf das Formular ab statt eine
 * Adresse zu bauen - sonst ginge der Suchbegriff bei jedem Sortierklick
 * verloren. Ein <button> erbt aber `background:var(--akzent)` aus der
 * allgemeinen Knopfregel, und diese Klasse hier nannte weder Hintergrund
 * noch Rahmen: Jeder Sortierkopf einer POST-Liste erschien als ausgefuellter
 * Akzentblock mit dunkler Schrift darin.
 *
 * Beide Auswahlformen stehen deshalb nebeneinander, und die Regel nennt
 * jetzt AUSDRUECKLICH, was sie vorher erbte. */
.spaltensortierung,
button.spaltensortierung {
    display:flex; align-items:center; gap:var(--raum-1);
    padding:var(--raum-2) var(--raum-3); width:100%;
    color:inherit; font:inherit; text-align:left;
    background:none; border:0; cursor:pointer;
    text-decoration:none;
    border-radius:var(--radius-xs);
}
.spaltensortierung:hover,
button.spaltensortierung:hover { background:var(--flaeche-2); text-decoration:underline; }

/* >> DIE ALTEN .zeichen--*-REGELN STEHEN NICHT MEHR HIER.

   Sie waren die Spitze eines CSS-Dreiecks: Das Element hatte width:0 und
   height:0, der Rand war die Form. Der Umbau hat daraus einen Kasten mit
   Ausdehnung gemacht und die Pfeile nach ::before/::after verlegt - auf einem
   Kasten mit Groesse zeichnet derselbe Rand keinen Pfeil, sondern einen
   durchgehenden Balken ueber die volle Breite. Auf JEDEM sortierbaren
   Spaltenkopf der Anwendung.

   Die drei Zustaende stehen vollstaendig im Abschnitt TABELLEN. */

/* Die Gruppen tragen die Gliederung der Seite. Ohne Abstand zwischen ihnen
   steht ein Kachelfeld aus vier Gruppen als eine einzige Fläche da. */
.kachelgruppe h2 { margin:0 0 var(--raum-1); font-size:var(--schrift-lg); }
.kachelgruppe .unterzeile { margin:0 0 var(--raum-4); }

/* --- Ohne Befund -------------------------------------------------------
   Die leeren Auswertungen bleiben anklickbar, aber sie treten zurück. Eine
   Null in Kachelgröße nimmt einer Zahl daneben das Gewicht. */
.ohne-befund h2 { font-size:var(--schrift-md); margin:0 0 var(--raum-1); }
.befundliste li {
    display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--raum-2);
    padding:var(--raum-1) 0; border-bottom:1px solid var(--rand-weich);
    font-size:var(--schrift-sm);
}

/* Die Einrichtung des zweiten Faktors: drei nummerierte Schritte, kein
   Fließtext. Die Nummer trägt die Reihenfolge, die Abstände die Trennung. */
.schritte { margin:0 0 var(--raum-5) var(--raum-4); padding:0; }
.schritte > li { margin:0 0 var(--raum-4); padding-left:var(--raum-1); }
.schritte > li > p:first-child { margin-top:0; }

/* Der QR-Code kommt als SVG aus endroid/qr-code und bringt keine eigene
   Größe mit. Ohne Deckel füllte er die ganze Spalte. */
.qr { max-width:15rem; margin:var(--raum-2) 0; }
.qr svg { display:block; width:100%; height:auto; }

/* Die Ersatzcodes werden abgeschrieben, nicht gelesen: mehrspaltig, in
   Festbreitensatz (den `.pruefsumme` je Zeile mitbringt), mit Luft dazwischen. */
.ersatzcodes {
    list-style:none; margin:0 0 var(--raum-5); padding:0;
    display:grid; gap:var(--raum-2) var(--raum-4);
    grid-template-columns:repeat(auto-fill, minmax(11rem, 1fr));
}
.ersatzcodes li {
    padding:var(--raum-2) var(--raum-2); background:var(--flaeche-2);
    border:1px solid var(--rand-weich); border-radius:var(--radius-xs);
    text-align:center;
}

/* ==========================================================================
   DAS LADEZEICHEN VON HTMX (AP-H15)

   Diese zwei Regeln kommen aus htmx selbst: `insertIndicatorStyles()` schrieb
   sie beim Laden als <style>-Block in den <head> JEDER Seite. `style-src
   'self'` verwirft ihn, und der Browser meldete auf jeder Seite einen
   Richtlinienverstoss — die Anwendung verletzte ihre eigene Zusage, und das
   Ladezeichen wirkte nirgends.

   Abgeschaltet wird der Block ueber `<meta name="htmx-config">` in den beiden
   Layouts, die die Importmap laden. Der Wortlaut hier ist bewusst derselbe
   wie der von htmx: Wer die Vendor-Datei liest, findet ihn wieder.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
    .htmx-request .htmx-indicator,
    .htmx-request.htmx-indicator { transition:none; }
}

/* ==========================================================================
   DIE ABSCHNITTE EINES VORFALLS (AP-E26, backoffice/vorfall/detail)

   >> OFFEN STEHT GENAU EIN ABSCHNITT: DER, DER ALS NAECHSTES DRAN IST.

   Vier Formulare mit vier Absendeknoepfen standen ausgeklappt untereinander,
   und zwar in JEDEM Zustand - beim frisch angelegten Vorfall genauso wie beim
   vollstaendig entschiedenen. Die Maske sagte damit nichts darueber, was
   zuerst zu tun ist, und bei einer 72-Stunden-Frist ist das die einzige Frage.

   ZUGEKLAPPT HEISST NICHT ERLEDIGT. Der Standtext im Kopf nennt den Zustand
   woertlich; eine Farbe traegt er nicht. Gruen waere bei der Nachtragspflicht
   nach Art. 33 Abs. 4 eine Aussage, die dieses System nicht machen darf: Die
   Pflicht ist wiederkehrend und hat keinen Endzustand.
   ========================================================================== */

.vorgangsschritt {
    margin:0 0 var(--raum-3); background:var(--flaeche);
    border:1px solid var(--rand); border-radius:var(--radius-sm);
}
.vorgangsschritt > summary {
    padding:var(--raum-3) var(--raum-4); cursor:pointer; border-radius:var(--radius-sm);
}

/* Die Ueberschrift bleibt eine Ueberschrift - im <summary> ist sie erlaubt,
   und ohne sie verloere die Maske ihre Sprungmarken fuer Lesegeraete. Sie
   wird nur eingereiht, damit der Aufklappwinkel neben ihr steht. */
.vorgangsschritt > summary h2 { display:inline; margin:0; font-size:var(--schrift-md); }

.vorgangsschritt__stand {
    display:block; margin-top:var(--raum-1);
    font-size:var(--schrift-sm); font-weight:400; color:var(--tinte-2);
}

.vorgangsschritt[open] { padding-bottom:var(--raum-4); }
.vorgangsschritt[open] > summary {
    margin-bottom:var(--raum-2); border-radius:var(--radius-sm) var(--radius-sm) 0 0;
    border-bottom:1px solid var(--rand-weich);
}
.vorgangsschritt > :not(summary) { margin-left:var(--raum-4); margin-right:var(--raum-4); }

/* Der naechste Schritt traegt die Akzentkante - die Marke dieser Seite und
   NICHT eine Ampelfarbe. Er ist der einzige Abschnitt, der offen steht. */
.vorgangsschritt--naechster {
    border-color:var(--akzent); border-left:3px solid var(--akzent);
}
.vorgangsschritt--naechster > summary { background:var(--flaeche-2); }

/* >> DER NAECHSTE SCHRITT.
   
   Zwei Masken benutzen ihn, in zwei Formen: In `vorfall/detail` ist er eine
   ZEILE ueber den Abschnitten, die den naechsten nennt und auf ihn verweist;
   in `dse/fassung` ist er der aufgeklappte BLOCK selbst, mit Ueberschrift und
   Formular darin. Dieselbe Aussage, deshalb dieselbe Form: Akzentkante links,
   ruhige Flaeche, kein Rahmen ringsum.

   Kein Gruen, kein Haken, kein "erledigt". Was hier steht, ist der naechste
   Schritt DIESES Vorgangs. Die Nachtragspflicht nach Art. 33 Abs. 4 und die
   Informationspflicht aus Art. 13/14 enden mit keiner Handlung, und eine
   Maske, die das Gegenteil behauptet, macht eine Aussage, die dieses System
   nicht machen darf.

   Die Aussage traegt der TEXT, nicht die Kante (WCAG 1.4.1): Ohne Stilblatt
   steht dieselbe Reihenfolge da, nur ohne Rand. */
.naechster-schritt {
    margin:0 0 var(--raum-5); padding:var(--raum-3) var(--raum-4); max-width:78ch;
    background:var(--flaeche-2); border-left:3px solid var(--akzent);
    border-radius:0 var(--radius-sm) var(--radius-sm) 0;
}
/* Die Blockform: Ueberschrift oben, letztes Kind ohne Abstand nach unten. */
.naechster-schritt > h3 { margin:0 0 var(--raum-2); font-size:var(--schrift-md); }
.naechster-schritt > :last-child { margin-bottom:0; }

/* Zwei Faktenbloecke nebeneinander. .zweispaltig (AP-F15) bricht schon bei
   56rem um; hier erst bei 90rem - das ist die Schwelle, ab der die
   Arbeitsspalte auf 100rem waechst (Abschnitt "DIE BREITE DES FENSTERS").
   Darunter stuenden zwei Tabellen in je gut 20rem, und eine Tabelle, die
   umbricht, ist schlechter lesbar als eine, die untereinander steht.
   Doppelte Klasse im Selektor, damit die 56rem-Abfrage weiter oben nicht
   von der Reihenfolge abhaengt. */
@media (min-width:90rem) {
    .zweispaltig.zweispaltig--weit {
        grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    }
}

/* Derselbe Deckel wie für den Fliesstext der Arbeitsspalte: Eine Erläuterung
   über die volle Spaltenbreite ist nicht lesbar. */

@media (min-width:90rem) {
    .beleg-und-arbeit {
        display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
        gap:var(--raum-5); align-items:start;
    }
}

/* --- Der Kopf eines aufklappbaren Abschnitts --------------------------
   Die Zusammenfassung trägt jetzt die Überschrift des Abschnitts und darunter
   eine Zustandszeile. Ohne diese zwei Regeln schöbe der 2rem-Vorabstand aus
   der h2-Regel den Text aus der Klickfläche heraus, und die Zustandszeile
   käme im Gewicht der Überschrift. */
details.feldgruppe > summary > h2 {
    display:inline; margin:0; font-size:var(--schrift-md); letter-spacing:0;
}
details.feldgruppe > summary > .klein { font-weight:400; }

/* Ohne min-width:0 sprengt eine breite Tabelle ihre Rasterspalte, statt im
   Behälter `.tabellenrolle` zu rollen. Beide Kinder stehen ausdrücklich da
   und nicht als `> *`: Eine Klasse aus einer Vorlage soll im Blatt
   auffindbar sein (AP-H15). */

@media (min-width:105rem) {
    .werkbank { grid-template-columns:minmax(0,3fr) minmax(0,2fr); }
}

/* Der Bestand ist ein Nachschlagewerk. Schlüssel, Bezeichnung, Belegstelle
   und Ausnahmen stehen in EINER Zelle untereinander - mit je einer eigenen
   Spalte bräuchte die Tabelle sieben und passte nicht mehr neben die
   Arbeit. */
.werkbank__bestand .nr { display:block; }
.werkbank__bestand h2 { margin-top:0; }

/* ==========================================================================
   DIE KANZLEIÜBERSICHT (AP-H18)

   Eine Zeile je Mandant, acht Zahlenspalten. Die Tabelle ist breit und wird
   quer gelesen — sie braucht deshalb genau zwei Dinge, die eine gewöhnliche
   Liste nicht braucht: schmale Zahlenspalten und eine sichtbare Spur, welche
   Spalte gerade gefiltert ist.
   ========================================================================== */

.lagetabelle { font-variant-numeric:tabular-nums; }

/* >> HIER NICHT `table-layout:fixed` (AP-H18).
   
   `.tabellenrolle > table` setzt es fuer die langen Arbeitslisten - dort ist
   es richtig, weil gleich breite Spalten das Lesen tragen. Diese Tabelle hat
   elf Spalten, von denen zehn eine Zahl enthalten und eine einen Namen. Mit
   fester Aufteilung bekam der Name ein Elftel und die Zahlen wurden zu einem
   unlesbaren Streifen am rechten Rand. */
.tabellenrolle > table.lagetabelle { table-layout:auto; }

/* Die Zahlenspalten so schmal wie ihr Inhalt. Der Mandantenname bekommt, was
   übrig bleibt - er ist die einzige Spalte, in der gelesen wird. */
.lagetabelle th:not(:first-child), .lagetabelle td:not(:first-child) {
    white-space:nowrap;
}

/* Ein Mandantenname ist kein Spaltenkopf. Die Grundregel setzt `th` in
   Versalien - richtig fuer eine Kopfzeile, falsch fuer "Musterwerk GmbH". */
.lagetabelle th[scope="row"] {
    width:auto; font-weight:600; font-size:var(--schrift-sm);
    text-transform:none; letter-spacing:normal; color:var(--tinte);
}

/* Die Zahl ist der Verweis, nicht ein Wort daneben: Die ganze Zelle ist das
   Ziel, damit man sie in einer Reihe aus acht Spalten trifft. */
.lagetabelle td.zahl a {
    display:block; padding:var(--raum-1) var(--raum-1); margin:-.15rem -.35rem;
    border-radius:var(--radius-xs); font-weight:650;
}
.lagetabelle td.zahl a:hover { background:var(--akzent-weich); text-decoration:none; }

/* Ein Strich statt einer Null. Er sagt dasselbe und drängt sich nicht auf -
   in einer Tabelle mit 456 Zellen ist das der Unterschied zwischen "acht
   Zahlen" und "achtundvierzig Nullen". */
.ohne-befund-zeichen { color:var(--tinte-3); }

/* Die gefilterte Spalte. Kein Farbfleck, sondern eine Kante links und rechts -
   sie soll die Spalte fassen, nicht die Zeilen einfärben. */
.spalte--gewaehlt {
    background:var(--flaeche-2);
    box-shadow:inset 1px 0 0 var(--rand), inset -1px 0 0 var(--rand);
}

/* --- Die Zustandswege einer Anfrage (AP-H18) ---------------------------
   Je Kante der Übergangstabelle ein Punkt: Was mit einer schlichten Handlung
   erreichbar ist, trägt einen Knopf; was eine Fachzeile verlangt, einen Satz
   mit Sprungziel. Die Aufzählungszeichen fallen weg — es ist eine Reihe von
   Angeboten und keine Liste von Merkmalen. */
.zustandswege { list-style:none; margin:var(--raum-2) 0 var(--raum-4); padding:0;
                display:flex; flex-wrap:wrap; gap:var(--raum-2); align-items:center; }
.zustandswege form { margin:0; max-width:none; }

/* --- Mein Tag (AP-H18) --------------------------------------------------

   >> AUCH HIER NICHT `table-layout:fixed`.

   Zum zweiten Mal dieselbe Falle: `.tabellenrolle > table` setzt die feste
   Aufteilung, und `white-space:nowrap` auf einer Zelle sprengt sie dann nach
   RECHTS - die Marke „gesetzlich" stand quer ueber dem Bezugstext der
   Nachbarspalte. Feste Spaltenbreiten und unumbrechbare Inhalte vertragen
   sich nicht; eines von beiden muss weichen, und hier ist es die Aufteilung.

   Die Terminspalte bleibt schmal, damit der Bezug - die einzige Spalte, in
   der gelesen wird - den Platz bekommt. Die Art bricht um: Ihre
   Bezeichnungen sind Saetze („Meldung einer Verletzung an die
   Aufsichtsbehoerde"), keine Woerter. */
.tabellenrolle > table.tagesliste { table-layout:auto; }
.tagesliste td:first-child { white-space:nowrap; }
.tagesliste td:last-child { white-space:nowrap; }

/* Die Marke steht am Ende ihrer Zeile und nicht mitten im Satz. */
.tagesliste .marke-gesetzlich { white-space:nowrap; }

/* --- Der Mandantenwechsel im Seitenkopf (AP-H18) -----------------------
   Der Chip ist ein <details>. Die Zusammenfassung sieht aus wie der Chip
   vorher; das Aufklappfeld haengt darunter und deckt, was darunter liegt. */
.mandant--wechsel { padding:0; overflow:visible; }
.mandant--wechsel > summary {
    display:flex; align-items:baseline; gap:var(--raum-2);
    padding:var(--raum-1) var(--raum-3); cursor:pointer; border-radius:999px;
    list-style:none;
}
/* Der Aufklappwinkel des Browsers passt nicht in eine Pille; das Zeichen
   dahinter setzt ihn selbst - und dreht sich beim Oeffnen. */
.mandant--wechsel > summary::-webkit-details-marker { display:none; }
.mandant--wechsel > summary::after {
    content:""; flex:none; width:0; height:0; margin-left:var(--raum-1);
    border-left:.28rem solid transparent; border-right:.28rem solid transparent;
    border-top:.32rem solid var(--tinte-2);
    transition:transform .12s ease;
}
.mandant--wechsel[open] > summary::after { transform:rotate(180deg); }

.mandantenwechsel {
    position:absolute; z-index:70; margin-top:var(--raum-2);
    min-width:18rem; max-width:24rem; padding:var(--raum-2);
    background:var(--flaeche);
    border:1px solid var(--rand); border-radius:var(--radius-md);
    box-shadow:var(--schatten-lg);
}
.mandantenwechsel__titel {
    margin:0 0 var(--raum-1); padding:0 var(--raum-2);
    font-size:var(--schrift-xs); font-weight:650; letter-spacing:.08em;
    text-transform:uppercase; color:var(--tinte-2);
}
.mandantenwechsel__liste { list-style:none; margin:0 0 var(--raum-2); padding:0; }
.mandantenwechsel__liste a {
    display:flex; align-items:baseline; gap:var(--raum-2);
    padding:var(--raum-2) var(--raum-2); border-radius:var(--radius-xs);
    color:var(--tinte); text-decoration:none; font-size:var(--schrift-sm); font-weight:600;
}
.mandantenwechsel__liste a:hover { background:var(--flaeche-2); text-decoration:none; }
.mandantenwechsel__fuss {
    margin:0; padding:var(--raum-2) var(--raum-2) 0;
    border-top:1px solid var(--rand-weich); font-size:var(--schrift-sm);
}

/* --- Filter und Handlung in der Arbeitsliste (AP-H18) -------------------
   Der Filter steht in einer Zeile: drei Angaben, kein Formular ueber die
   halbe Seite. Die Beschriftungen sind klein und stehen ueber ihrem Feld. */
.fristenfilter {
    display:flex; flex-wrap:wrap; align-items:flex-end; gap:var(--raum-4);
    margin:0 0 var(--raum-4); max-width:none;
}
.fristenfilter > span { display:flex; flex-direction:column; gap:var(--raum-1); }
.fristenfilter label { margin:0; font-size:var(--schrift-xs); }
.fristenfilter select { max-width:16rem; margin:0; }
.fristenfilter button, .fristenfilter .knopf-klein { margin:0; }

/* Die Handlungsspalte: zwei kurze Formulare untereinander, kein Umbruch. */
.tagesliste__handlung form {
    display:flex; align-items:center; gap:var(--raum-1); margin:0 0 var(--raum-1); max-width:none;
}
.tagesliste__handlung form:last-child { margin-bottom:0; }
.tagesliste__handlung input[type=date] { max-width:9.5rem; margin:0; }

/* ---------------------------------------------------------------------------
   DIE DREI EBENEN (AP-H23)

   Der Streifen ist das erste Bedienelement der Seite und beantwortet die
   Frage, die vorher auf jeder Maske offen war: Sehe ich hier alle Kunden oder
   einen? Er sitzt deshalb in der Kopfleiste und nicht in der Spalte - was
   ueber allem steht, gehoert nach oben.
   --------------------------------------------------------------------------- */

.ebenenstreifen__reiter {
    display:flex;
    flex-direction:column;
    gap:var(--raum-1);
    padding:var(--raum-2) var(--raum-4) var(--raum-2);
    border-bottom:3px solid transparent;
    color:var(--tinte-2);
    font-weight:600;
    text-decoration:none;
    white-space:nowrap;
}

.ebenenstreifen__reiter:hover { color:var(--tinte); background:var(--flaeche); }

/* Die offene Ebene traegt Farbe UND Linie: Farbe allein ist fuer farbenblinde
   Leser keine Aussage (WCAG 1.4.1). */
.ebenenstreifen__reiter--offen {
    color:var(--akzent);
    border-bottom-color:var(--akzent);
    background:var(--flaeche);
}

.ebenenstreifen__beitext {
    font-size:var(--schrift-xs);
    font-weight:400;
    color:var(--tinte-3);
    letter-spacing:.01em;
}

.ebenenstreifen__reiter--offen .ebenenstreifen__beitext { color:var(--tinte-2); }

/* ---------------------------------------------------------------------------
   DIE MANDANTENAKTE
   --------------------------------------------------------------------------- */

.kachelliste--akte { margin-bottom:var(--raum-5); }

@media (min-width:75rem) {
    .aktenblatt { grid-template-columns:1.2fr 1fr; }
}

.aktenblatt__spalte h2 { margin-top:0; }

/* ---------------------------------------------------------------------------
   DIE VORLAGENEBENE
   --------------------------------------------------------------------------- */

.vorlagenfeld h2 { margin-top:0; }

/* ==========================================================================
   EINE LISTE, DIE MIT POST SCHICKT (AP-H28)

   Trägt eine Liste ein Suchfeld, darf ihr Zustand nicht in der Adresse
   stehen: Der Begriff ist in diesem System ein Personenname, und der
   Webserver protokolliert jede Adresse (CLAUDE.md § 10). Spaltenkopf und
   Filterknopf schicken deshalb ein Formular ab - sie sind <button> und
   nicht <a>.

   Damit erben sie den Grundknopf: Fläche auf Akzent, Kante, fette Schrift.
   Im Tabellenkopf sieht das aus wie ein Bedienfeld und nicht wie eine
   Überschrift, und in der Filterleiste wären alle Reiter gleichzeitig
   "aktiv". Die Regeln unten schalten das ab, damit beide Träger derselben
   Klasse gleich aussehen - der Unterschied zwischen GET- und POST-Liste
   soll im Quelltext stehen und nicht auf dem Bildschirm.
   ========================================================================== */

button.spaltensortierung {
    background:none; border:0; text-align:left;
    font-weight:inherit; font-size:inherit;
}
button.spaltensortierung--aktiv { font-weight:650; }
.filterleiste button.aktiv {
    font-weight:650; color:var(--akzent);
    background:var(--akzent-weich); border-color:transparent;
}

/* Suchfeld, Knopf und Filterleisten sind EIN Formular - sonst verlöre der
   Sortierklick den Begriff. Sichtbar bleibt es trotzdem eine Zeile mit zwei
   Reitern darunter und kein Eingabebogen. */
.listensuche { margin:0 0 var(--raum-4); }
.listensuche__zeile { display:flex; flex-wrap:wrap; align-items:center; gap:var(--raum-2); }
.listensuche__zeile label { margin:0; }
.listensuche__zeile input[type="search"] { margin:0; min-width:18rem; }
.listensuche .hilfe { margin:var(--raum-1) 0 var(--raum-4); }

/* Die Stellung in einer Firmengruppe. Ein Fieldset, damit die drei Knöpfe
   als eine Frage lesbar sind - und nicht als drei Ankreuzfelder unter
   zwei Textfeldern. */
.gruppenstellung { margin:var(--raum-4) 0; }
.gruppenstellung p { margin:var(--raum-2) 0; }
.gruppenstellung select { margin-top:var(--raum-1); }

/* Ausgetragene Ansprechpartner bleiben stehen - eine Freigabe aus dem
   Vorjahr braucht ihren Zeichner. Sie sollen aber nicht wie aktive
   aussehen: kein display:none, nur zurückgenommen. */
tr.ausgetragen td { color:var(--tinte-2); }
tr.ausgetragen td:first-child { font-style:italic; }

/* Der Gruppenbaum der Mandantenverwaltung (AP-H30). Zwei Ebenen, mehr laesst
   kern.mandanten_gruppenregel() nicht zu - die Einrueckung braucht deshalb
   keine Tiefenstufen. */
.gruppenzweig { margin:var(--raum-5) 0; }
.gruppendach { display:flex; align-items:baseline; gap:var(--raum-2); flex-wrap:wrap; }
.gruppendach .marke { font-size:var(--schrift-xs); }
table.eingerueckt { margin-left:var(--raum-5); border-left:3px solid var(--rand-stark); }

/* Der Vorlagenbereich (AP-H33). Die Knoepfe stehen in der Zeile, zu der sie
   gehoeren - ein "entfernen" unter einer Liste trifft im Zweifel das Falsche. */
.vorlagengruppe { margin:var(--raum-5) 0; }
.vorlagengruppe h3 { display:flex; align-items:baseline; gap:var(--raum-3); flex-wrap:wrap; }
.vorlagengruppe h3 form { display:inline; }
.vorlagengruppe ul.datenarten li { display:flex; align-items:baseline; gap:var(--raum-2); }
.vorlagengruppe ul.datenarten form { display:inline; }


/* ==========================================================================
   DAS STILBUCH (templates/backoffice/stilbuch.html.twig)

   Die einzigen Klassen dieses Blattes, die nichts Fachliches tragen: Sie
   zeigen den Wertevorrat her, statt ihn zu benutzen. Eine Raumstufe sieht
   man sonst nirgends - man sieht nur ihre Wirkung.

   Sie stehen hier unten und nicht bei den Bauteilen, damit beim Lesen klar
   bleibt, was Werkzeug ist und was Vorfuehrung.
   ========================================================================== */

.raumleiter { list-style:none; margin:0 0 var(--raum-5); padding:0;
              display:grid; gap:var(--raum-2); font-size:var(--schrift-sm); }
.raumleiter li { display:flex; align-items:center; gap:var(--raum-3); }

/* Der Balken IST die Stufe: Seine Breite ist der Wert, den er benennt.
   Deshalb acht Regeln und keine Custom Property am Element - ein
   style-Attribut verwuerfe die CSP (siehe Abschnitt CSP-ERSATZKLASSEN). */
.raumleiter__probe { flex:none; height:var(--raum-3); background:var(--akzent-hell);
                     border-radius:var(--radius-xs); }
.raumleiter__probe--1 { width:var(--raum-1); }
.raumleiter__probe--2 { width:var(--raum-2); }
.raumleiter__probe--3 { width:var(--raum-3); }
.raumleiter__probe--4 { width:var(--raum-4); }
.raumleiter__probe--5 { width:var(--raum-5); }
.raumleiter__probe--6 { width:var(--raum-6); }
.raumleiter__probe--7 { width:var(--raum-7); }
.raumleiter__probe--8 { width:var(--raum-8); }

/* Dieselbe Zeile in jeder Stufe. Nur so sieht man, dass die Leiter
   Abstaende hat und nicht dreizehn Werte im Band .82 bis .98rem. */
.schriftprobe { color:var(--tinte); line-height:var(--zeile-eng); }
.schriftprobe--xs { font-size:var(--schrift-xs); }
.schriftprobe--sm { font-size:var(--schrift-sm); }
.schriftprobe--md { font-size:var(--schrift-md); }
.schriftprobe--lg { font-size:var(--schrift-lg); font-weight:var(--fett-halb); }
.schriftprobe--xl { font-size:var(--schrift-xl); font-weight:var(--fett-halb);
                    letter-spacing:-.01em; }

/* Die Spurbelegung sichtbar machen. Sonst zeigt ein Raster aus leeren
   Kaesten genau nichts. */
.stilbuch-raster { margin:0 0 var(--raum-5); }
.stilbuch-feld {
    padding:var(--raum-3);
    font-size:var(--schrift-xs); font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
    color:var(--akzent); text-align:center;
    background:var(--akzent-weich); border:1px dashed var(--akzent-hell);
    border-radius:var(--radius-xs);
}


/* ==========================================================================
   NEUN KLASSEN OHNE REGEL (AP-H32)

   Gefunden von `keineWebVorlageBenutztEineKlasseOhneRegel` - dem Testfall,
   der `dasStilblattDecktDasSeitengeruestAb` von `templates/layout/` auf ALLE
   Web-Vorlagen ausdehnt. Die alte Fassung sah nur ins Seitengeruest; genau
   durch diese Luecke standen `.kachel__titel` (viermal in der Mandantenakte)
   und `.formular-zeile` (in sieben Vorlagen) jahrelang ohne eine Zeile da.

   Es ist derselbe Fehler wie `var(--linie)`, nur andersherum: Dort benutzte
   das Blatt einen Namen, den es nicht gab; hier benutzt eine Vorlage einen.
   Beide Richtungen sind jetzt bewacht.
   ========================================================================== */

/* Eine Zeile, die unter ihre Zeile gehoert: das Teilnahmeformular unter der
   Schulung, ueber die volle Tabellenbreite. Eingelassen, damit sie als
   Fortsetzung der Zeile darueber gelesen wird und nicht als eigene. */
.einschub {
    padding:var(--raum-3) var(--raum-4);
    background:var(--flaeche-3);
    border-top:1px dashed var(--rand);
}

/* Die TOM nach Schutzziel gruppiert. Abstand statt Kante: Die Tabelle in der
   Gruppe traegt bereits eine Flaeche, zwei Kaesten ineinander waeren einer
   zu viel. */
.ziel-gruppe { margin:0 0 var(--raum-6); }
.ziel-gruppe > h2 { margin-top:0; }

/* Der ersetzte Wert im Verlauf. Durchgestrichen UND gedaempft: Die
   Durchstreichung traegt die Aussage, die Farbe nur die Nebenrolle - eine
   Farbe allein waere fuer farbenblinde Leser keine Aussage (WCAG 1.4.1). */
.alt-wert {
    color:var(--tinte-3);
    text-decoration:line-through;
    text-decoration-thickness:1px;
}

/* Ein Aufklapper ohne eigene Flaeche - er steht schon in einer Karte.
   `.aufklapper--nackt` waere der neue Name; `.ausklapp` steht in der Vorlage
   und bekommt deshalb dieselbe Bauform. */
.ausklapp { margin:var(--raum-4) 0; }
.ausklapp > summary {
    cursor:pointer;
    font-size:var(--schrift-sm); font-weight:var(--fett-stark);
    color:var(--akzent);
}
.ausklapp[open] > summary { margin-bottom:var(--raum-3); }

/* Der Gegenstand eines Termins in der Mandantenakte - die zweite Spalte der
   Terminliste. Sie darf umbrechen; der Termin daneben nicht. */
.terminliste__sache { min-width:0; }

/* Das Formular fuer die Nachtragspflicht nach Art. 33 Abs. 3. Es steht in
   einem aufgeklappten Abschnitt und braucht dort keinen zweiten Kasten. */
.abs3-formular { margin:0; }

/* Das Gegenstueck zu `.formular-schmal`: eine Maske, deren Felder in einer
   Tabelle stehen und die volle Arbeitsspalte brauchen. */
.formular-breit { max-width:none; }

/* Die zwanzigste Prozentbreite. Die Liste in "Was die CSP erzwingt" ist
   geschlossen und sagt das ausdruecklich - hier ist der Eintrag, der beim
   Aufraeumen der style-Attribute uebersehen wurde. */
.breite-6 { width:6%; }

/* Der Text des amtlichen GISA-Auszugs: abgetippt aus einem PDF, deshalb
   Festbreitensatz mit Umbruch und einer Hoehe, die die Maske nicht sprengt. */
.auszugstext {
    max-height:24rem; overflow:auto;
    white-space:pre-wrap; word-break:break-word;
    font-size:var(--schrift-sm); line-height:var(--zeile-normal);
}
