/* ==========================================================================
   Inventaris — Gestaltung

   Bewusst handgeschrieben und ohne Build-Schritt: die Datei wird so
   ausgeliefert, wie sie hier steht. Auf dem Server ist damit weder Node
   noch ein Übersetzungslauf nötig.

   Aufbau: 1) Farben  2) Grundlagen  3) Bausteine  4) Seitenaufbau
   ========================================================================== */

/* --- 0) Schrift --------------------------------------------------------- */

/*
  Red Hat Display, selbst gehostet. Bewusst nicht über Google Fonts:
  so werden beim Seitenaufruf keine IP-Adressen an Dritte übermittelt.
  Lizenz und Herkunft siehe assets/fonts/LIESMICH.txt.
*/
@font-face {
  font-family: "Red Hat Display";
  src: url("fonts/redhatdisplay-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Red Hat Display";
  src: url("fonts/redhatdisplay-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Red Hat Display";
  src: url("fonts/redhatdisplay-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Red Hat Display";
  src: url("fonts/redhatdisplay-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}

/* --- 1) Farben ---------------------------------------------------------- */

/*
  Zwei Farben, zwei Aufgaben — mehr nicht.

    Blau (#1257e5) ist beides zugleich: die Farbe des Logos UND die Farbe
    fuer „hier kann man etwas tun“ — Knoepfe, Verweise, aktive Zustaende,
    Fokus, Fortschritt, Reiterunterstrich. Wo Blau steht, ist etwas
    bedienbar oder aktiv, sonst nirgends. Eine eigene Markenfarbe daneben
    gibt es nicht mehr; frueher war das Bernstein, und solange das Logo
    seine eigene Farbwelt mitbrachte, stritten die beiden.

    Schwarz (#101423, in den Marken --indigo-*) traegt das Gewicht:
    Ueberschriften, Kennzahlen, dunkle Flaechen, Hinweiskaesten. Es ist das
    Schwarz des Logos, mit einem Hauch Blau darin.

  In den Abschnitten 2-7 stehen nur noch die Rollenmarken (--accent,
  --heading, --rule …), nie eine Zahl aus einer Skala. Wer die Anmutung
  aendern will, aendert diesen Block — und nur diesen.

  Das Markenzeichen selbst ist kein CSS mehr, sondern liegt als Datei unter
  assets/logo/. Umgeschaltet wird ueber .brand-lockup.is-light / .is-dark.

  Alle Kontrastwerte sind nachgerechnet und erfuellen mindestens WCAG AA.
*/

:root {
  /* Marke — direkt aus dem Logo: Schwarz plus Blau als Akzent (#1257e5).
     Damit fällt die frühere Trennung „Marke gelb, Bedienung blau“ weg: die
     Marke IST blau. Das ist keine Vereinfachung aus Bequemlichkeit, sondern
     die Folge daraus, dass das Logo seine Farbwelt mitbringt. */
  --brand-50:  #eef3fe;
  --brand-100: #d8e4fd;
  --brand-300: #8fb0f7;
  --brand-400: #4d80ef;
  --brand-500: #1257e5;          /* Logo-Blau */
  --brand-600: #0f49c0;
  --brand-700: #0d3d9f;
  --brand-900: #0a2a6d;
  --on-brand:  #ffffff;          /* auf --brand-500: 5,97:1 */

  /* Bedienfarbe — dieselbe Skala wie die Marke, damit im Bild nur ein
     Blau vorkommt. #1257e5 ist der Ton des Logos; die dunkleren Stufen
     tragen Text und Zustände. */
  --blue-50:  #eef3fe;
  --blue-100: #d8e4fd;
  --blue-200: #b6ccfb;
  --blue-300: #8fb0f7;
  --blue-400: #4d80ef;
  --blue-500: #2668e9;
  --blue-600: #1257e5;
  --blue-700: #0f49c0;
  --blue-800: #0d3d9f;
  --blue-900: #0a2a6d;

  /* Gewicht — das Schwarz des Logos, mit einem Hauch Blau darin, damit es
     neben dem Akzent nicht kalt und tot wirkt. Liest sich als Schwarz.
     Die Marken heissen weiterhin --indigo-*: sie stehen an vierzig Stellen
     in dieser Datei, und der Name beschreibt die Rolle, nicht den Farbton. */
  --indigo-50:  #f3f4f7;
  --indigo-100: #e5e7ee;
  --indigo-200: #c9ccd9;
  --indigo-300: #9298ad;
  --indigo-400: #5d637a;
  --indigo-500: #3b4157;
  --indigo-600: #2a3046;
  --indigo-700: #1c2135;
  --indigo-800: #101423;         /* dunkle Flächen, Überschriften */
  --indigo-900: #080b16;
  --indigo-on-dark: #b7bccb;     /* Text auf #101423, 9,6:1 */

  /* --- Rollen. Nur diese kommen weiter unten vor. --- */
  --accent:        #1257e5;      /* Logo-Blau, 5,97:1 mit Weiss */
  --accent-hover:  #0f49c0;
  --accent-active: #0d3d9f;
  --on-accent:     #ffffff;
  --accent-text:   #0d3d9f;      /* Verweise, 10,6:1 auf Weiss */
  --accent-soft:      #d8e4fd;   /* aktiver Menuepunkt */
  --accent-soft-text: #0d3d9f;   /* 9,7:1 darauf */
  --accent-line:   #1257e5;
  --focus:         #1257e5;
  --heading:       #101423;

  --danger-solid:       #b91c1c; /* 6,47:1 mit Weiss */
  --danger-solid-hover: #991b1b;
  --on-danger:          #ffffff;

  /* Der Grund unter einer fremden Bildmarke.

     Die Armbrust von Swiss Label ist eine geschuetzte Marke: sie wird
     gefuehrt, wie sie ist, und nicht an unser Farbschema angepasst. Sie
     braucht darum ein weisses Feld — auch im dunklen Modus, wo dieser
     Wert als einziger NICHT umgestellt wird. Deshalb eine eigene Marke
     und nicht `--surface`: die wird dunkel, und das Weiss im Zeichen
     verschwaende auf dem Rot. */
  --fremdmarke-grund: #ffffff;

  /* Der Grund unter einem Code zum Scannen (QR, Strichcode) — wie die
     fremde Marke in beiden Erscheinungsbildern Weiss. Ein Scanner liest
     dunkle Striche auf hellem Grund; umgekehrt liest er gar nichts. */
  --code-grund: #ffffff;
  /* Der Rahmen um das Scanfeld (seit 11.10.2026): auf dem hellen Ausweis
     sonst Weiss auf Fast-Weiss. Im dunklen Bild trägt das Weiss selbst. */
  --code-rand: #c6d0e6;

  /* Was nur in einem Erscheinungsbild zu sehen ist — die Wortmarke gibt
     es dunkel (für hellen Grund) und invers (für dunklen). Als Rolle,
     damit Gerät und Teams dieselbe Umschaltung benutzen. */
  --nur-hell:   inline-block;
  --nur-dunkel: none;

  /* Der Pfeil im Auswahlfeld, in der Farbe von --muted. */
  --auswahl-pfeil: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235b6480' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

  /* Der Schatten unter einem Bildschirmfoto: eine Ebene, sehr zurueckhaltend.

     Am 11.09.2026 stand hier kurz ein gestufter aus vier Ebenen, der die
     Bilder deutlich abhob. Auf Wunsch des Betreibers wieder heraus — die
     Seite ist ruhiger ohne. Was bleibt, ist der Wert von vorher, nur als
     Marke statt als Zahl mitten im Regelwerk. */
  --bild-schatten: 0 18px 44px rgba(16, 20, 35, .10);

  /* Flaechen und Linien */
  --bg:            #ffffff;
  --surface:       #ffffff;
  --surface-muted: #f6f7fb;
  --rail:          #fafbfe;      /* Seitenleiste, ruhiger als reines Weiss */
  --border:        #e4e7f0;      /* Bauteilkanten */
  /* Rand eines Bedienelements (Feld, Erledigt-Kreis) — seit 04.10.2026.
     --border hat auf Weiss nur 1,24:1; ein Feld in einer weissen Karte
     zeigt sich aber allein durch seinen Rand. WCAG 1.4.11 will 3:1. */
  --field-border:       #7d8499; /* 3,73:1 auf --surface, 3,48:1 auf --surface-muted */
  --field-border-hover: #5d637a; /* 5,95:1 */
  --head-rule:     #d7dced;      /* Tabellenkopf */
  --rule:          #eceff6;      /* Zeilentrenner */
  --scroll-schatten: rgba(10,37,64,.10);  /* «hier geht es seitwaerts weiter» */
  --row-hover:     #f4f6fb;      /* ueberfahrene Zeile */

  --text:    #14173f;
  --muted:   #5b6480;
  --nav-fg:  #3c4363;            /* Menuepunkte in Ruhe, 9,33:1 auf --rail */

  /* Statusfarben — Warnung orange, Hinweis indigo statt blau, damit ein
     Hinweiskasten nicht wie ein Knopf aussieht. */
  --success-bg: #ecfdf5; --success-fg: #047857; --success-bd: #a7f3d0;
  --warning-bg: #fff4ed; --warning-fg: #c2410c; --warning-bd: #fed7aa;
  --danger-bg:  #fef2f2; --danger-fg:  #b91c1c; --danger-bd:  #fecaca;
  --info-bg:    #f2f3f9; --info-fg:    #22276f; --info-bd:    #c6cae5;
  /* Markierter Hinweis — wie ein Textmarker. 8,1:1 auf --note-bg. */
  --note-bg:    #fdf6d8; --note-fg:    #63500a; --note-bd:    #f2dd93;
  /* Akzenttöne der Webseite (seit 30.09.2026). Nur für Zeichen und Flächen
     der Verkaufsseiten — Modul-Icons, Zielgruppen, Bänder. Blau bleibt die
     Bedienfarbe; Knöpfe und Verweise nehmen nie einen dieser Töne.
     Jedes -fg hat mindestens 4,5:1 auf seinem -bg. */
  --ton-blau-bg:    #e3edff; --ton-blau-fg:    #1250d0;
  --ton-gruen-bg:   #dff5e9; --ton-gruen-fg:   #0b6b40;
  --ton-orange-bg:  #ffecdc; --ton-orange-fg:  #a8480a;
  --ton-violett-bg: #ede6fe; --ton-violett-fg: #5b30c4;
  --ton-tuerkis-bg: #d9f3f4; --ton-tuerkis-fg: #0a6770;
  /* Kennzahlenband der Übersicht (Test 16.10.2026): Grün und Blau im Verlauf,
     eine graue Spur für den Rest. Text auf Grün bleibt in beiden Modi dunkel. */
  --kz-hell:     #7cc4ff;
  --kz-blau:      #1257e5;
  --kz-spur:      #7d889c;
  --kz-auf-hell: #101423;
  --kz-auf-blau:  #ffffff;
  --kz-rahmen:    #4d7fe0;
  --ton-rosa-bg:    #fde4ee; --ton-rosa-fg:    #ad2860;

  /* Die dunkle Flaeche der Verkaufsseite: Kopfzeile, Aufmacher, Aufruf.
     Sie bleibt in beiden Erscheinungsbildern dieselbe — ein Aufmacher, der
     je nach Systemeinstellung hell oder dunkel ist, ist kein Aufmacher,
     sondern ein Zufall. */
  --ink:           #0b0f1c;
  --ink-2:         #141b30;
  --on-ink:        #f2f4fa;
  --on-ink-muted:  #9aa3bd;      /* 7,4:1 auf --ink */
  --on-ink-accent: #8fb0f7;      /* «AI» in «Swyron AI» auf dunklem Grund, 7,9:1 auf --ink */
  --ink-border:    rgba(255, 255, 255, .12);
  --ink-card:      rgba(255, 255, 255, .05);

  --radius:    12px;             /* Karten */
  --radius-sm: 8px;              /* Knoepfe, Felder */

  /*
    Abstandsreihe (seit 26.10.2026). Vorher hatte jede Kachel und jeder
    Abschnitt der Webseite einen eigenen Wert (20, 24, 26, 28 px; Abschnitte
    56 bis 84 px). Jetzt gibt es sechs Stufen und drei Abschnittshöhen;
    ein neuer Abstand nimmt eine davon. Keine Farbe, darum nur hier und
    nicht im dunklen Block.
  */
  --abstand-1: 6px;              /* Zeichen zu Text, enge Paare */
  --abstand-2: 12px;             /* Titel zu Vorspann */
  --abstand-3: 18px;             /* Vorspann im Hero, Gruppen */
  --abstand-4: 24px;             /* Innenabstand von Karten und Kacheln */
  --abstand-5: 32px;             /* zwischen Blöcken */
  --abstand-6: 44px;             /* grosse Blöcke */
  --abschnitt: 72px;             /* Abschnitte der Webseite, oben und unten */
  --abschnitt-tablet: 44px;
  --abschnitt-telefon: 40px;
  --rail-pad:  14px;             /* eine linke Kante in der Seitenleiste */
  --kopf-hoehe: 64px;            /* Kopfzeile der Webseite; unter 720 px 58 */
  --topbar-h:  56px;             /* Kopfzeile der Anwendung, ab 1024 px abwärts */
  --shadow:    0 1px 2px rgba(10, 37, 64, .06), 0 1px 3px rgba(10, 37, 64, .04);
  --shadow-lg: 0 4px 12px rgba(10, 37, 64, .08), 0 2px 4px rgba(10, 37, 64, .04);

  /* Anmeldeseiten: die getönte Arbeitsfläche, ihre Welle und die
     Abbildung darauf. Eigene Rollen, weil keine vorhandene «hellblau,
     aber nicht aktiv» meint — --accent-soft ist der aktive Menüpunkt. */
  --auth-flaeche:     #edf3fe;
  --auth-welle:       #dfe9fd;
  --auth-bild-grund:  #d8e4fd;
  --auth-bild-strich: #c9d6f3;
  /* Das Terminal am Schalter (`/kiosk`, seit 10.10.2026, `kiosk.css`).
     Der ganze Bildschirm wird grün, wenn gebucht ist — Weiss darauf
     5,48:1. Der Puls um das Scanziel und der Schleier hinter «Bist du
     noch da?» sind Flächen ohne Text. */
  --kiosk-erfolg:     #047857;
  --on-kiosk-erfolg:  #ffffff;
  --kiosk-scan-puls:  rgba(18, 87, 229, .16);
  --kiosk-schleier:   rgba(16, 20, 35, .55);
  --font: "Red Hat Display", ui-sans-serif, -apple-system, BlinkMacSystemFont,
          "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  color-scheme: light;
}

/*
  DUNKLES ERSCHEINUNGSBILD (seit 08.10.2026 wieder, auf Wunsch des Betreibers)

  Die Anwendung folgt still dem Gerät: steht es auf dunkel, wird sie
  dunkel, ohne Schalter. Es werden ausschliesslich Rollen neu belegt —
  keine Regel ab Abschnitt 2 kennt das dunkle Bild.

  Wo es NICHT gilt:
    .hell            Verkaufsseite, Handbuch, Druck und Fehlerseite
                     (`$hellesLayout` in head.php). Die Verkaufsseite lebt
                     vom Gegensatz dunkler Aufmacher / heller Rest; ganz
                     dunkel wäre sie ein schwarzer Block. Gedrucktes ist Papier.
    [data-teams]     Im Teams-Reiter entscheidet Teams (hell, dunkel,
                     starker Kontrast) — `teams.css`. Das Gerät kann hell
                     sein und Teams dunkel, und umgekehrt.

  Die Farben sind das Schwarz des Logos mit einem Hauch Blau, kein reines
  Schwarz und kein reines Weiss — reines Weiss auf Schwarz flimmert beim
  Lesen. Nachgerechnet (WCAG 2.2):

    --text auf --surface        14,2:1     --muted auf --surface   7,6:1
    --nav-fg auf --rail         11,8:1     --muted auf --row-hover 7,0:1
    --accent-text auf --surface  8,1:1     Weiss auf --accent      5,2:1
    --field-border auf --surface 4,2:1     --focus auf --surface   6,3:1
    Statusfarben fg auf bg     8,9–11,9:1  Weiss auf --danger-solid 4,8:1

  Knöpfe bleiben Blau mit weisser Schrift wie im hellen Bild — ein
  helleres Blau mit dunkler Schrift sah 2026 schon einmal abgeschaltet aus.
  Überfahren geht darum nach dunkler, nicht nach heller.
*/
@media (prefers-color-scheme: dark) {
  :root:not(.hell):not([data-teams]) {
    /* Skalen, die einzelne Bauteile direkt benutzen (Kästchen der
       Kennzahlen, Initialen, getönte Flächen): die hellen Stufen werden
       dunkle Tönungen, die dunklen Textstufen hell. */
    --code-rand: #ffffff;
    --brand-50:  #131c33;
    --brand-100: #1b2848;
    --brand-600: #8fb0f7;
    --brand-700: #b6ccfb;
    --brand-900: #c3d4fc;
    --indigo-50:  #1c2130;
    --indigo-100: #252b3c;
    --indigo-200: #363d54;
    --indigo-700: #c9cddb;

    --accent:        #2563eb;
    --accent-hover:  #1d55d6;
    --accent-active: #1847b0;
    --on-accent:     #ffffff;
    --accent-text:   #8fb0f7;
    --accent-soft:      #1b2848;
    --accent-soft-text: #c3d4fc;
    --accent-line:   #4d80ef;
    --focus:         #6f9af3;
    --heading:       #f3f5fa;

    --danger-solid:       #dc2626;
    --danger-solid-hover: #b91c1c;
    --on-danger:          #ffffff;

    --bild-schatten: 0 18px 44px rgba(0, 0, 0, .45);

    --bg:            #0b0e17;
    --surface:       #151925;
    --surface-muted: #10131d;
    --rail:          #0f121b;
    --border:        #282e40;
    --field-border:       #737c99;
    --field-border-hover: #9aa1b8;
    --head-rule:     #343b50;
    --rule:          #20253a;
    --scroll-schatten: rgba(0, 0, 0, .55);
    --row-hover:     #1b2030;

    --text:    #e4e7f0;
    --muted:   #a3aabf;
    --nav-fg:  #c9cddb;

    --success-bg: #082a20; --success-fg: #6ee7b7; --success-bd: #0f5a44;
    --warning-bg: #33200c; --warning-fg: #fdba74; --warning-bd: #7c3a12;
    --danger-bg:  #361011; --danger-fg:  #fca5a5; --danger-bd:  #7f1d1d;
    --info-bg:    #191d33; --info-fg:    #c3c8ee; --info-bd:    #343a66;
    --note-bg:    #2e270c; --note-fg:    #fde68a; --note-bd:    #6b5512;

    --shadow:    0 1px 2px rgba(0, 0, 0, .5);
    --shadow-lg: 0 6px 18px rgba(0, 0, 0, .45);

    --kz-hell:     #7cc4ff;
    --kz-blau:      #2f6ff0;
    --kz-spur:      #3c4458;
    --kz-auf-hell: #101423;
    --kz-auf-blau:  #ffffff;
    --kz-rahmen:    #3b5fae;

    /* Die Arbeitsfläche hinter den Karten (hell: zartes Blau). */
    --auth-flaeche:     #0c101b;
    --auth-welle:       #121a2f;
    --auth-bild-grund:  #1b2848;
    --auth-bild-strich: #2a3556;

    /* Terminal: dunkleres Grün, Weiss darauf 7,6:1. */
    --kiosk-erfolg:     #065f46;
    --on-kiosk-erfolg:  #ffffff;
    --kiosk-scan-puls:  rgba(111, 154, 243, .22);
    --kiosk-schleier:   rgba(0, 0, 0, .65);

    --nur-hell:   none;
    --nur-dunkel: inline-block;
    --auswahl-pfeil: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a3aabf' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

    color-scheme: dark;
  }
}

/*
  Hoher Kontrast (seit 26.10.2026). Wer am Gerät «Kontrast erhöhen»
  einschaltet (macOS, iOS, Windows), bekommt Kanten, die man sieht, und
  gedämpfte Schrift näher an der Hauptschrift. Vorher lagen Bauteilkanten
  bei 1,24:1 und die halbtransparenten Kanten auf dunklem Grund unter 3:1.

  Nur Rollen werden neu belegt, wie beim dunklen Modus. Der Teams-Reiter
  hat seinen eigenen Kontrastmodus (teams.css) und bleibt ausgenommen.
  Hell gilt für die Verkaufsseiten mit (.hell), dunkel nur, wo das
  Gerät dunkel ist.
*/
@media (prefers-contrast: more) {
  :root:not([data-teams]) {
    --border:        #7d8499;      /* 3,7:1 auf Weiss, wie --field-border */
    --head-rule:     #7d8499;
    --rule:          #9298ad;
    --muted:         #3c4363;      /* 10:1 auf Weiss */
    --on-ink-muted:  #c9cfe0;      /* 12:1 auf --ink */
    --ink-border:    rgba(255, 255, 255, .55);
    --ink-card:      rgba(255, 255, 255, .14);
  }
}
@media (prefers-contrast: more) and (prefers-color-scheme: dark) {
  :root:not(.hell):not([data-teams]) {
    --border:        #737c99;      /* 4,2:1 auf --surface dunkel */
    --head-rule:     #737c99;
    --rule:          #4a526b;
    --muted:         #c9cddb;
  }
}

/* --- 2) Grundlagen ------------------------------------------------------ */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* Sprünge zu einem Anker — Sprunglink, Fehlermeldung, Reiter — laufen
     weich statt hart. Wer Bewegung abgestellt hat, bekommt sie nicht. */
  scroll-behavior: smooth;
  /* Ein Ziel klebt sonst unter der klebenden Kopfzeile. */
  scroll-padding-top: 76px;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font: 0.9375rem/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ul, ol, dl, dd, figure { margin: 0; }
/*
  Überschriften bekommen einen eigenen, engeren Zeilenabstand (seit
  26.10.2026). Vorher erbten sie 1,55 vom Fliesstext, und zweizeilige
  Titel fielen auseinander. Je grösser die Schrift, desto enger: die
  grossen Titel setzen ihren Wert unten selbst.
*/
h1, h2, h3 { color: var(--heading); letter-spacing: -.015em; line-height: 1.25; }
ul, ol { padding: 0; list-style: none; }

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

img { max-width: 100%; height: auto; }

/* Der Fokusring wird ergaenzt, nie ersetzt: `outline: none` kommt in dieser
   Datei nirgends vor. Im Zwangskontrastmodus waere ein box-shadow unsichtbar,
   ein Umriss nicht. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: inherit;
}

/* Nur für Hilfsmittel sichtbar — z. B. Sprunglinks und Beschriftungen. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: -9999px; top: 8px; z-index: 100;
  background: var(--indigo-800); color: #fff; padding: 10px 16px; border-radius: var(--radius-sm);
}
.skip-link:focus { left: 8px; }

/*
  Das Sprachband.

  Ein Hinweis, keine Umleitung — und darum auch kein Balken, der die
  halbe Seite nimmt. Eine Zeile ueber der Kopfzeile, in der ruhigen
  Flaeche, mit dem Verweis als einzigem farbigem Element.
*/
.sprachband {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  padding: 8px 20px;
  background: var(--surface-muted); border-bottom: 1px solid var(--border);
  font-size: 0.8125rem; color: var(--muted);
}
.sprachband a         { color: var(--brand-600); text-decoration: underline; }
/* Das Kreuz ist klein, die Fläche zum Antippen nicht: 44 px, nach aussen
   gezogen, damit das Band nicht höher wird (seit 26.10.2026). */
.sprachband-zu        { margin: -14px -14px -14px auto; display: inline-grid; place-items: center;
                        min-width: 44px; min-height: 44px; text-decoration: none; font-size: 1rem; line-height: 1; }
.sprachband-zu:hover  { color: var(--text); }

/*
  Der Cookie-Hinweis: ein schmaler Balken unten, kein halbes Bild.

  Fest am unteren Rand, damit er beim Lesen nicht mitscrollt; nach dem
  Wegklicken ist er ein Jahr fort. Der Knopf ist bewusst schlicht — es
  gibt nichts zu entscheiden, nur zur Kenntnis zu nehmen. Kein «Ablehnen»,
  weil die Seite ohnehin nur technisch notwendige Cookies setzt.
*/
.cookie-hinweis {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 50;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px;
  max-width: 640px; margin: 0 auto;
  padding: 12px 16px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg), 0 12px 32px -16px rgba(10, 37, 64, .28);
  font-size: 0.8125rem; color: var(--muted);
}
.cookie-hinweis p     { margin: 0; flex: 1 1 260px; }
.cookie-hinweis p a   { color: var(--brand-600); text-decoration: underline; }
.cookie-hinweis-ok {
  flex: 0 0 auto; margin-left: auto;
  padding: 7px 16px; border-radius: 999px;
  background: var(--accent); color: #fff; text-decoration: none;
  font-weight: 600; font-size: 0.8125rem; white-space: nowrap;
}
.cookie-hinweis-ok:hover { opacity: .92; }

/*
  DIE SPRACHWAHL — ZWEI KUERZEL, EINES AKTIV.

  Sie steht im Kopf neben zwei Knoepfen und darf darum kein dritter
  Knopf sein: ein Rahmen um das Paar, kein Rahmen um jedes Kuerzel.
  Die aktive Sprache traegt eine Flaeche und die Textfarbe, die andere
  bleibt still — wer sucht, findet sie; wer nicht sucht, sieht einen
  ruhigen Kopf.

  Die Sprachen stehen ausgeschrieben nebeneinander — «Deutsch»,
  «Français», «English» —, getrennt durch einen dezenten Mittelpunkt.
  Kein Kasten, keine Umrandung: eine ruhige Zeile aus Verweisen, die
  aktive Sprache traegt Gewicht statt eines Verweises.
*/
.sprachwahl {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  font-size: 0.8125rem; font-weight: 500;
}
.sprachwahl > a,
.sprachwahl > .ist-da {
  padding: 4px 2px; line-height: 1;
  text-decoration: none; color: var(--muted);
}
.sprachwahl > a:hover    { color: var(--text); text-decoration: underline; }
.sprachwahl > .ist-da    { color: var(--text); font-weight: 600; cursor: default; }
/* Ein Mittelpunkt zwischen den Sprachen, aber nicht vor der ersten. */
.sprachwahl > * + *::before {
  content: "·"; margin: 0 8px; color: var(--border);
  font-weight: 400; text-decoration: none;
}

/*
  Im Klappmenue am Telefon steht sie unter den Knoepfen und ueber die
  ganze Breite: dort ist Platz. Dieselbe Zeile, nur mit groesseren
  Tippzielen.
*/
.sprachwahl.ist-menu       { display: flex; flex-wrap: wrap; margin-top: 10px; }
.sprachwahl.ist-menu > a,
.sprachwahl.ist-menu > .ist-da { padding: 10px 2px; }

/*
  Der Globus-Sprachwähler im Kopf. Kompakt: Globus, das aktive Kürzel und
  ein Pfeil. Die Liste klappt ohne JavaScript auf (:hover/:focus-within)
  und steht als helle Fläche — auf dem dunklen Verkaufskopf wie auf dem
  hellen Anmeldekopf gleich lesbar. Rechtsbündig, damit sie am Telefon
  nicht über den Rand läuft.
*/
.sprachwahl-drop { position: relative; display: inline-flex; }
.sprachwahl-knopf {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 8px; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 0.8125rem; font-weight: 600; line-height: 1;
  color: var(--muted); border-radius: var(--radius-sm);
}
.sprachwahl-knopf:hover { color: var(--text); }
.sprachwahl-globus { width: 18px; height: 18px; }
.sprachwahl-code   { letter-spacing: .03em; }
.sprachwahl-pfeil  {
  width: 13px; height: 13px; opacity: .6; transform: rotate(90deg);
  transition: transform .16s ease;
}
.sprachwahl-drop:hover .sprachwahl-pfeil,
.sprachwahl-drop:focus-within .sprachwahl-pfeil { transform: rotate(270deg); opacity: 1; }

.sprachwahl-panel {
  position: absolute; top: 100%; right: 0; z-index: 30;
  display: flex; flex-direction: column; gap: 2px;
  min-width: 150px; margin-top: 6px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg), 0 16px 40px -18px rgba(10, 37, 64, .3);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .14s ease, transform .14s ease, visibility .14s;
}
.sprachwahl-drop:hover > .sprachwahl-panel,
.sprachwahl-drop:focus-within > .sprachwahl-panel {
  opacity: 1; visibility: visible; transform: translateY(0);
}
.sprachwahl-panel a,
.sprachwahl-panel .ist-hier {
  display: block; padding: 8px 12px; border-radius: var(--radius-sm);
  font-size: 0.875rem; text-decoration: none; white-space: nowrap;
}
.sprachwahl-panel a { color: var(--muted); }
.sprachwahl-panel a:hover { background: var(--surface-muted); color: var(--text); }
.sprachwahl-panel .ist-hier { font-weight: 600; color: var(--text); cursor: default; }

/* Hilfsklassen, sparsam eingesetzt. */
.muted      { color: var(--muted); }
.small      { font-size: 0.8125rem; }
.tiny       { font-size: 0.75rem; }
.strong     { font-weight: 600; }
.nowrap     { white-space: nowrap; }
.right      { text-align: right; }
/*
  Kein einzelnes Wort auf der letzten Zeile.

  Die Bildunterschrift auf den Zielgruppenseiten brach nach „… und die
  Revision" um und liess „verlangen." allein stehen. Das sieht aus, als
  waere der Satz abgeschnitten — gefragt wurde genau danach. `pretty`
  laesst den Browser die vorletzte Zeile kuerzen, damit auf der letzten
  mehr als ein Wort steht; `balance` verteilt kurze Bloecke wie
  Ueberschriften gleichmaessig auf ihre Zeilen.

  Wo es der Browser nicht kennt, bleibt alles wie zuvor — es gibt
  nichts zu ersetzen und keinen Ausweichweg zu pflegen.
*/
/*
  `balance` gehoert auf Ueberschriften und NUR auf Ueberschriften.

  Es stand auch auf `.lead`, `.sec-head p`, `.cta p` und `blockquote` —
  also auf Absaetzen, die laenger werden koennen. Der Browser verteilt
  dann alle Zeilen auf dieselbe Laenge, und ein vierzeiliger Vorspann in
  einer schmalen Spalte wird zu vier kurzen Zeilen mit einem breiten
  leeren Streifen rechts. Auf der Sicherheitsseite sah das aus, als sei
  der Text falsch gesetzt; gemeldet wurde genau das.

  Ueberschriften sind kurz genug, dass `balance` tut, wofuer es gedacht
  ist. Alles, was ein Absatz werden kann, bekommt `pretty`: das loest
  das urspruengliche Problem — kein einzelnes Wort auf der letzten Zeile
  — ohne die Zeilen zu verkuerzen.
*/
h1, h2, h3, .eyebrow {
  text-wrap: balance;
}
p, li, dd, figcaption, blockquote, .lead, .desc, .hint, .muted {
  text-wrap: pretty;
}

.center     { text-align: center; }
.nums       { font-variant-numeric: tabular-nums; }
.mt-0 { margin-top: 0; }    .mt-1 { margin-top: var(--abstand-1); }
.mt-2 { margin-top: var(--abstand-2); } .mt-3 { margin-top: var(--abstand-3); }
.mt-4 { margin-top: 24px; } .mt-5 { margin-top: 32px; }
.mt-6 { margin-top: 44px; }
.mb-2 { margin-bottom: 12px; } .mb-3 { margin-bottom: 18px; }
.mb-4 { margin-bottom: 24px; }
.hidden { display: none; }
.block  { display: block; }

.row   { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.row-b { display: flex; gap: 12px; align-items: baseline; justify-content: space-between; }
.spread{ display: flex; gap: 12px; align-items: center; justify-content: space-between; }
.stack > * + * { margin-top: 12px; }

/* --- 3) Bausteine ------------------------------------------------------- */

/* Knöpfe */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 40px; padding: 0 16px;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  font: 500 0.875rem/1 var(--font); cursor: pointer;
  background: var(--accent); color: var(--on-accent);
  transition: background-color .15s, border-color .15s, box-shadow .15s, transform .1s ease-out;
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(10, 37, 64, .08);
}
.btn:hover { background: var(--accent-hover); text-decoration: none; }
.btn:active { background: var(--accent-active); }
.btn:disabled { opacity: .55; cursor: not-allowed; }
/*
  Ein Knopf, der kein Knopf ist.

  „Reservieren" bei einer fest vergebenen Einheit fuehrt nirgendwohin —
  ein <span> statt eines Verweises, damit die Tastatur nicht darauf
  landet und kein Klick etwas ausloest. Sieht aus wie ein gesperrter
  Knopf, weil es einer ist.
*/
.btn.is-disabled {
  opacity: .55; cursor: not-allowed; pointer-events: auto;
  user-select: none;
}

.btn-secondary {
  background: var(--surface); color: var(--text); border-color: var(--border);
}
.btn-secondary:hover { background: var(--surface-muted); }

.btn-ghost { background: transparent; color: var(--muted); }
.btn-ghost:hover { background: var(--surface-muted); color: var(--text); }
/* Swyron AI auf der Ticketseite: ruhig, aber als eigener Weg erkennbar. */
.btn-ghost[data-sai-ticket] { color: var(--accent); }
.btn-ghost[data-sai-ticket]:disabled { opacity: .6; cursor: progress; }
/* Der Knopf, der gerade arbeitet, bleibt voll sichtbar — sein Zeichen läuft. */
.btn-ghost[data-sai-ticket].arbeitet { opacity: 1; background: var(--brand-50); }
.btn-ghost[data-sai-ticket] .sai-zeichen { margin-right: 2px; }
.input.sai-feld-wartet, .input.sai-feld-wartet[readonly] { border-color: var(--accent); background: var(--brand-50); color: var(--text); cursor: progress; }

.btn-danger { background: var(--danger-solid); color: var(--on-danger); }
.btn-danger:hover { background: var(--danger-solid-hover); }

/*
  Getönte Knöpfe (seit 03.10.2026): sichtbar, aber nicht laut. Weiss auf
  Weiss ging «Alle ansehen» und «Mahnen» in der Übersicht unter
  (Rückmeldung vom 03.10.2026); voll rot wären zehn überfällige Zeilen
  zehn rote Blöcke. Hell getönt mit kräftiger Schrift, wie die Abzeichen.
*/
.btn-soft { background: var(--accent-soft); color: var(--accent-soft-text); border-color: transparent; }
.btn-soft:hover { background: var(--brand-100); filter: brightness(.96); color: var(--accent-soft-text); }
.btn-soft-danger { background: var(--danger-bg); color: var(--danger-fg); border-color: var(--danger-bd); }
.btn-soft-danger:hover { background: var(--danger-bd); color: var(--danger-fg); }
/* «Anrufen» neben «Mahnen» (20.10.2026): Grün wie ein Anrufknopf, zart, damit «Mahnen» vorne bleibt. */
.btn-soft-success { background: var(--success-bg); color: var(--success-fg); border-color: var(--success-bd); }
.btn-soft-success:hover { background: var(--success-bd); color: var(--success-fg); }

.btn-sm  { height: 32px; padding: 0 12px; font-size: 0.8125rem; }
.btn-lg  { height: 48px; padding: 0 24px; font-size: 1rem; }
.btn-block { width: 100%; }
/* inline-flex, damit ein <a class="btn-link"> dieselbe Höhe bekommt wie ein
   <button class="btn-link">. Ohne das wirkte die 44-px-Regel für Tippziele
   nur auf die Knöpfe, und in derselben Zelle standen 44-px- neben
   20-px-Zielen. */
.btn-link { display: inline-flex; align-items: center; justify-content: center;
            background: none; border: none; color: var(--muted); cursor: pointer;
            padding: 6px 8px; font: 0.875rem/1.3 var(--font); border-radius: var(--radius-sm); }
.btn-link:hover { background: var(--surface-muted); color: var(--text); }
.btn-link.danger:hover { background: var(--danger-bg); color: var(--danger-fg); }
.btn-link { transition: background-color .15s, color .15s, transform .1s ease-out; }

/*
  Druckzustand (seit 26.10.2026). Rückmeldung im Moment des Drückens,
  nicht erst beim Loslassen und ohne Einblenden: der Knopf gibt ein wenig
  nach und dunkelt in seinem eigenen Ton nach. Vorher hatte nur der blaue
  Knopf einen Druckzustand, und der blendete in 150 ms ein; Zweit-,
  Gefahr- und getönte Knöpfe zeigten beim Drücken gar nichts.
*/
.btn:active, .btn-link:active { transform: scale(.97); transition-duration: 0s; }
.btn-secondary:active, .btn-ghost:active { background: var(--border); color: var(--text); }
.btn-danger:active { background: var(--danger-solid-hover); filter: brightness(.92); }
.btn-soft:active, .btn-soft-danger:active, .btn-soft-success:active,
.btn-link:active { filter: brightness(.92); }
.btn:disabled:active, .btn.is-disabled:active { transform: none; filter: none; }
@media (prefers-reduced-motion: reduce) { .btn:active, .btn-link:active { transform: none; } }

/* Formularfelder */
.field { display: block; margin-bottom: 16px; }
.field > .label { display: block; font-size: 0.8125rem; font-weight: 600; color: var(--muted);
                  letter-spacing: .01em; margin-bottom: 6px; }
.field .req { color: var(--danger-fg); margin-left: 2px; }
.hint  { display: block; font-size: 0.8125rem; line-height: 1.45; color: var(--muted); margin-top: 6px; }

/* Markierter Hinweis: für die Stellen, an denen der Satz nicht überlesen
   werden darf — etwa „freiwillig", wo sonst jeder ein Pflichtfeld vermutet.
   Wie mit dem Textmarker gezogen, deshalb nur so breit wie der Text. */
.hint.is-note {
  display: inline-block;
  background: var(--note-bg);
  color: var(--note-fg);
  border: 1px solid var(--note-bd);
  border-radius: var(--radius-sm);
  padding: 5px 9px;
  font-weight: 500;
}
.error { display: flex; align-items: center; gap: 5px;
         font-size: 0.75rem; color: var(--danger-fg); margin-top: 5px; }
.error svg { flex: 0 0 13px; width: 13px; height: 13px; }

.input, .select, .textarea {
  width: 100%; padding: 9px 11px;
  border: 1px solid var(--field-border); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font: 0.9375rem/1.4 var(--font);
  transition: border-color .12s;
}
.input:hover, .select:hover, .textarea:hover { border-color: var(--field-border-hover); }
/* Der Rand faerbt zusaetzlich zum Fokusring — nicht statt seiner. */
.input:focus, .select:focus, .textarea:focus { border-color: var(--accent); }

/* Der eigene Pfeil sieht in jedem Browser gleich aus. */
.select {
  appearance: none; -webkit-appearance: none;
  padding-right: 34px;
  background-image: var(--auswahl-pfeil);
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 16px 16px;
}
.input, .select { height: 40px; }
/*
  Datum und Zeit wie jedes andere Feld. Safari auf iPhone und iPad (auch
  in Teams) zeichnet sie sonst selbst: weisser Grund auch im dunklen
  Modus, eigene Höhe, Text in der Mitte — im Fenster «Mahnung senden» und
  im Filter des Archivs sichtbar (Rückmeldung vom 02.10.2026).
  `min-height`, weil ein leeres Datumsfeld auf iOS sonst zusammenfällt.
*/
.input[type="date"], .input[type="time"],
.input[type="datetime-local"], .input[type="month"] {
  -webkit-appearance: none; appearance: none;
  min-height: 40px; line-height: 20px;
  display: block;
}
.input-lg[type="date"] { min-height: 48px; }
.input[type="date"]::-webkit-date-and-time-value,
.input[type="time"]::-webkit-date-and-time-value,
.input[type="datetime-local"]::-webkit-date-and-time-value,
.input[type="month"]::-webkit-date-and-time-value { text-align: left; margin: 0; }
/* Das Kalenderzeichen in der Farbe der Schrift, auch im dunklen Modus. */
.input::-webkit-calendar-picker-indicator { opacity: .7; cursor: pointer; }
.textarea { min-height: 92px; resize: vertical; }
.input:disabled, .select:disabled { opacity: .6; }
.input.is-error, .select.is-error, .textarea.is-error { border-color: var(--danger-fg); }
/* Schon beim Verlassen des Felds, nicht erst nach dem Absenden (seit
   26.10.2026): :user-invalid greift erst, wenn die Person im Feld war und
   es leer oder falsch verlassen hat; ein frisches Formular bleibt ruhig. */
.input:user-invalid, .select:user-invalid, .textarea:user-invalid { border-color: var(--danger-fg); }
.input-lg { height: 48px; font-size: 1rem; }

.grid > .field, .grid > fieldset { margin-bottom: 0; }

/* Eine Spalte, die nicht die ganze Breite braucht — Einstellungen etwa. */
.col-narrow { max-width: 720px; }
.input-narrow { max-width: 140px; }
/* Ankreuzfeld in einer Liste: der Abstand kommt vom Listeneintrag. */
.check.check-plain { margin: 0; }

.check { display: flex; align-items: flex-start; gap: 10px; font-size: 0.875rem; margin-bottom: 12px; }
.check input { margin-top: 3px; width: 16px; height: 16px; accent-color: var(--accent); flex-shrink: 0; }
/* Zuständigkeiten (Einstellungen → Benutzer, seit 28.10.2026): die Meldungen
   eines Bereichs eingerückt darunter, nur solange der Bereich angekreuzt ist. */
/* Eigene Felder nur bei bestimmten Kategorien (seit 28.10.2026): ein ruhiger
   Kasten, oben die Wahl als Marken, aufgeklappt Pillen zum Antippen. */
.cf-kategorien {
  margin: var(--abstand-3) 0 var(--abstand-2);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-muted);
}
.cf-kategorien > summary {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--abstand-1) var(--abstand-2);
  padding: 10px 40px 10px 14px; position: relative;
  list-style: none; cursor: pointer; border-radius: var(--radius-sm);
}
.cf-kategorien > summary::-webkit-details-marker { display: none; }
.cf-kategorien > summary::after {
  content: ""; position: absolute; right: 14px; top: 50%; width: 14px; height: 14px; margin-top: -7px;
  background: var(--auswahl-pfeil) center / 14px no-repeat; transition: transform .15s ease;
}
.cf-kategorien[open] > summary::after { transform: rotate(180deg); }
.cf-kategorien > summary:hover { background: var(--row-hover); }
.cf-kategorien-titel { font-size: 0.8125rem; font-weight: 600; color: var(--heading); }
.cf-kategorien-wahl { display: flex; flex-wrap: wrap; gap: 6px; }
.cf-kategorien-alle { font-size: 0.8125rem; color: var(--muted); }
.cf-marke {
  padding: 2px 9px; border-radius: 999px; font-size: 0.75rem; font-weight: 500;
  background: var(--accent-soft); color: var(--accent-soft-text);
}
.cf-kategorien-inhalt { padding: 4px 14px 14px; border-top: 1px solid var(--rule); }
.cf-pillen { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.cf-pille { position: relative; cursor: pointer; }
.cf-pille input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.cf-pille span {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 14px; border-radius: 999px; font-size: 0.8125rem;
  background: var(--surface); color: var(--text); border: 1px solid var(--field-border);
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.cf-pille:hover span { border-color: var(--field-border-hover); }
.cf-pille:active span { transform: scale(.97); transition: none; }
.cf-pille input:checked + span {
  background: var(--accent-soft); color: var(--accent-soft-text); border-color: var(--accent-line); font-weight: 600;
}
.cf-pille input:checked + span::before { content: "✓"; font-weight: 700; }
.cf-pille input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 2px; }
.cf-kategorien-hinweis { margin: 12px 0 0; }
.zust-bereich { margin-bottom: var(--abstand-1); }
.zust-meldungen { margin: calc(-1 * var(--abstand-1)) 0 var(--abstand-2) 26px;
                  padding-left: var(--abstand-2); border-left: 2px solid var(--rule); }
.zust-meldungen .check { margin-bottom: 8px; }
.zust-bereich:not(:has(> .check input:checked)) .zust-meldungen { display: none; }

fieldset { border: 0; padding: 0; margin: 0 0 16px; }
legend { font-size: 0.875rem; font-weight: 500; padding: 0; margin-bottom: 8px; }

/* Karten */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-bottom: 24px;
  overflow: hidden;
}
.card-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; padding: 16px 22px; border-bottom: 1px solid var(--border);
}
.card-head h2 { font-size: 0.875rem; font-weight: 600; letter-spacing: 0; }
.card-head .desc { font-size: 0.875rem; color: var(--muted); margin-top: 2px; }
.card-body { padding: 22px; }
.card-foot { padding: 16px 22px; border-top: 1px solid var(--border); }

/* Die Probeknoepfe im Betreiberbereich: eine Reihe, die umbricht statt
   ueber den Rand zu laufen — es sind neun Vorlagen, und ihre Namen sind
   verschieden lang. */
.proben-knoepfe { display: flex; flex-wrap: wrap; gap: 8px; }
.proben-knoepfe .btn { flex: none; }
/* Die Sprachwahl darueber steht nebeneinander, nicht untereinander. */
.field .check { display: inline-flex; margin-right: 18px; margin-bottom: 0; }
.card-danger { border-color: var(--danger-bd); }

/* Listen innerhalb von Karten */
/* 22 px wie Kopf und Inhalt der Karte: vorher 20, und die linken Kanten
   standen 2 px versetzt untereinander (seit 26.10.2026). */
.list > li { padding: 12px 22px; border-bottom: 1px solid var(--border); }
.list > li:last-child { border-bottom: 0; }

.dl > div {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 10px 22px; border-bottom: 1px solid var(--border); font-size: 0.875rem;
}
.dl > div:last-child { border-bottom: 0; }
.dl dt { color: var(--muted); flex-shrink: 0; }
.dl dd { margin: 0; text-align: right; font-weight: 500; }

/*
  Eine Kennung, die abgetippt wird: UDID, MAC-Adresse, IMEI.

  Schreibmaschinenschrift, weil in einer Proportionalschrift 0 und O
  gleich aussehen — und diese Zeichenfolgen werden Zeichen für Zeichen
  in eine Firewall oder ein Supportformular übertragen, nie gelesen.

  `user-select: all` macht aus dem Klick eine vollständige Markierung:
  ein Doppelklick auf «aa:bb:cc:dd:ee:01» erwischt sonst nur ein Paar.
*/
.kennung {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.7812rem; font-weight: 400;
  padding: 1px 6px; border-radius: var(--radius-sm);
  background: var(--surface-muted); border: 1px solid var(--border);
  user-select: all; overflow-wrap: anywhere;
}

/* Tabellen — dürfen nur sich selbst scrollen, nie die Seite */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; font-size: 0.875rem; line-height: 1.45;
        font-variant-numeric: tabular-nums; }
th {
  text-align: left; padding: 9px 16px;
  font-size: 0.6875rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
  border-bottom: 1px solid var(--head-rule); white-space: nowrap;
}
td { padding: 10px 16px; border-bottom: 1px solid var(--rule); vertical-align: middle; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--row-hover); }
/* In der Tabelle traegt der Verweis die Textfarbe — sonst leuchtet jede
   zweite Zelle blau. Bedienbar wird er beim Ueberfahren. */
table a { color: inherit; }
table a:hover, table a:focus-visible { color: var(--accent-text); }
/* Zweitrangige Angaben in einer Datenzelle — nicht die ganze Spalte. */
.cell-sub { color: var(--muted); font-size: 0.8125rem; }
/* Zelle mit mehreren Aktionen: rechtsbündig, darf aber umbrechen — drei
   Knöpfe mit 44 px Tippziel passen am Telefon sonst nicht nebeneinander. */
.cell-actions { text-align: right; white-space: nowrap; }
.cell-actions > * { vertical-align: middle; }
/* Drei Aktionen untereinander machen die Zeile dreimal so hoch — und eine
   Liste, die man scrollen muss, obwohl sechs Namen darin stehen. */
.cell-actions > * + * { margin-left: 14px; }
@media (max-width: 720px) {
  .cell-actions { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; }
}
/* Ueberfaellig: ein Balken an der Kante statt einer roten Flaeche.
   Damit bleibt die Zeile lesbar und das Ueberfahren sichtbar. */
tr.is-overdue > td:first-child { box-shadow: inset 3px 0 0 var(--danger-fg); }

/* Statuszeichen */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  height: 22px; padding: 0 9px; border-radius: 999px; line-height: 1;
  font-size: 0.75rem; font-weight: 500; white-space: nowrap;
  border: 1px solid var(--border); background: var(--surface-muted); color: var(--muted);
}
.badge.success { background: var(--success-bg); color: var(--success-fg); border-color: var(--success-bd); }
.badge.warning { background: var(--warning-bg); color: var(--warning-fg); border-color: var(--warning-bd); }
.badge.danger  { background: var(--danger-bg);  color: var(--danger-fg);  border-color: var(--danger-bd); }
.badge.info    { background: var(--info-bg);    color: var(--info-fg);    border-color: var(--info-bd); }

/* Hinweise */
.alert {
  padding: 12px 16px; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface-muted);
  font-size: 0.875rem; margin-bottom: 20px;
}
.alert .title { font-weight: 600; margin-bottom: 2px; }
/* Im farbigen Kasten traegt der Verweis dessen Farbe — Blau waere dort
   entweder unlesbar oder eine zweite Aussage. */
.alert a { color: inherit; text-decoration: underline; }
.alert ul { margin-top: 4px; }
.alert li + li { margin-top: 2px; }
.alert.success { background: var(--success-bg); color: var(--success-fg); border-color: var(--success-bd); }
.alert.warning { background: var(--warning-bg); color: var(--warning-fg); border-color: var(--warning-bd); }
.alert.danger  { background: var(--danger-bg);  color: var(--danger-fg);  border-color: var(--danger-bd); }
.alert.info    { background: var(--info-bg);    color: var(--info-fg);    border-color: var(--info-bd); }
/* Rückfrage bei der Verlängerung: ein Knopf im Kasten ist ein Knopf,
   kein Verweis — `.alert a` oben würde ihn unterstreichen und färben. */
.verlaengerung-rueckfrage .btn-secondary { color: var(--text); text-decoration: none; }

/* Leerer Zustand */
.empty { padding: 56px 24px; text-align: center; }
.empty .t { font-weight: 500; }
.empty .d { color: var(--muted); font-size: 0.875rem; margin: 6px auto 0; max-width: 380px; }
.empty-note { padding: 28px 22px; text-align: center; color: var(--muted); font-size: 0.875rem; }

/* Fortschritt */
.progress { height: 8px; border-radius: 999px; background: var(--surface-muted); overflow: hidden; }
.progress > span { display: block; height: 100%; background: var(--accent); border-radius: 999px; }
.progress.low > span { background: var(--danger-solid); }

/* Raster */
.grid { display: grid; gap: 20px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-side { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); align-items: start; }

/* Statt fester Spaltenzahlen bricht das Raster von selbst um, sobald eine
   Spalte zu schmal wuerde. Das erspart drei Sonderregeln je Breite. */
@media (max-width: 1100px) {
  .grid-4 { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
  .grid-3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
  .grid-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
  .grid-side { grid-template-columns: minmax(0, 1fr); }
}

/* Auf schmalen Geraeten gehoert die Randspalte mit dem Erfassungsformular
   nach oben — sonst scrollt man an der ganzen Liste vorbei. */
@media (max-width: 1024px) {
  .grid-side.side-first > *:last-child { order: -1; }
}

/* Buchen-Leiste: auf Telefon und Tablet hochkant fest am unteren Rand
   (Rückgabe, neue Ausleihe). Am Computer steht der Knopf ohnehin im Bild.
   `ist-verdeckt` setzt app.js, solange der eigentliche Knopf sichtbar ist. */
.buchen-leiste, .buchen-leiste-platz { display: none; }
@media (max-width: 1024px) {
  .buchen-leiste {
    display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
    background: var(--surface); border-top: 1px solid var(--rule);
    box-shadow: var(--shadow-lg);
  }
  .buchen-leiste.ist-verdeckt { display: none; }
  .buchen-leiste-platz { display: block; height: calc(76px + env(safe-area-inset-bottom)); }
  /*
    Seit 04.10.2026: Die Leiste liegt über dem Stapel der Kopfzeile und
    damit über dem offenen Menü — ein Tipp auf «Profil» buchte die
    Ausleihe. Solange das Menü offen ist, tritt sie zurück.
  */
  body:has(.app-menu[open]) .buchen-leiste { display: none; }
  /* Ein fokussiertes Feld scrollt über die Leiste, nicht darunter.
     Den Rest besorgt app.js, wo der Browser scroll-padding übergeht. */
  html:has(.buchen-leiste:not(.ist-verdeckt)) {
    scroll-padding-bottom: calc(84px + env(safe-area-inset-bottom));
  }
  /* Der Hinweis «Neue Einträge» steht über der Leiste, nicht auf ihr. */
  body:has(.buchen-leiste:not(.ist-verdeckt)) .puls-hinweis {
    bottom: calc(96px + env(safe-area-inset-bottom));
  }
}
.leiste-zahl {
  display: inline-block; min-width: 1.6em; margin-left: 6px; padding: 0 6px;
  border-radius: 999px; background: var(--surface); color: var(--accent);
  font-size: 0.875rem; font-weight: 600; line-height: 1.6; text-align: center;
}

/* Kennzahl */
.stat {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 18px 20px; text-decoration: none; color: inherit;
}
.stat:hover { text-decoration: none; }
/*
  `flex: 1` ist hier Pflicht und nicht Geschmack.

  `.stat-body` traegt weiter unten ein `container-type: inline-size`, und
  das enthaelt auch `contain: inline-size`: die Eigenbreite des Elements
  wird dann OHNE seinen Inhalt gerechnet. Als blosses Flex-Element mit
  Inhaltsbreite schrumpfte es damit auf das Minimum, und «CHF, wie
  bezahlt» stand vierzeilig untereinander. Mit `flex: 1` kommt die
  Breite aus der Flex-Zeile statt aus dem Inhalt, und die Enthaltung
  stoert nicht mehr.
*/
.stat-body { min-width: 0; flex: 1 1 auto; }

/* Das Symbol trägt die Bedeutung mit — Farbe allein genügt nicht. */
.stat-icon {
  flex-shrink: 0;
  width: 40px; height: 40px; border-radius: 11px;
  display: grid; place-items: center; font-size: 1.1875rem;
  background: var(--indigo-50); color: var(--indigo-700);
}
.stat-icon.is-brand   { background: var(--brand-100); color: var(--brand-900); }
.stat-icon.is-success { background: var(--success-bg); color: var(--success-fg); }
.stat-icon.is-danger  { background: var(--danger-bg);  color: var(--danger-fg); }

a.card-stat { transition: border-color .15s, box-shadow .15s, transform .15s; }
a.card-stat:hover {
  border-color: var(--accent-line); box-shadow: var(--shadow-lg); transform: translateY(-1px);
}
@media (prefers-reduced-motion: reduce) { a.card-stat:hover { transform: none; } }
/* Die Auszeichnungen sind <span>, damit ein ganzes Feld verlinkbar bleibt —
   deshalb muss der Blocksatz hier ausdrücklich gesetzt werden. */
.stat .k { display: block; font-size: 0.875rem; color: var(--muted); }
.stat .v { display: block; font-size: 1.875rem; font-weight: 700; letter-spacing: -.02em;
           font-variant-numeric: tabular-nums; margin-top: 4px; line-height: 1.1;
           color: var(--heading); }
.stat .s { display: block; font-size: 0.75rem; color: var(--muted); margin-top: 3px; }

/*
  DIE ZAHL VERLOR IHRE LETZTE STELLE.

  Auf «/app/werte» standen vier Kacheln nebeneinander, und in zweien
  davon steht Geld. Bei 1200 px Fensterbreite blieb jeder Kachel rund
  200 px, davon gehen Innenabstand, Symbol und Luecke ab — der Zahl
  blieben etwa 106 px. «52’523.00» braucht bei 30 px aber gut 155, und
  weil `.card` ein `overflow: hidden` traegt (fuer die runden Ecken),
  wurde sie nicht umgebrochen, sondern ABGESCHNITTEN. Auf dem Schirm
  stand «52’523.0».

  Das ist der schlimmste Fehler, den eine Zahl haben kann: sie sieht
  vollstaendig aus. Wer den Betrag der Versicherung meldet, meldet eine
  Zehnerpotenz zu wenig, und nichts an der Darstellung sagt ihm das.

  Zwei Massnahmen, weil eine davon nur die Gestalt rettet und die
  andere die Richtigkeit:

  1. Geldkacheln bekommen breitere Spalten (`.grid-geld`). Damit bleibt
     die Zahl gross, und auf einem breiten Schirm stehen weiterhin vier
     nebeneinander.
  2. Wird es trotzdem eng — kleines Fenster, laengere Zahl, dritte
     Sprache —, verkleinert sich die Zahl, statt zu verschwinden. Der
     Behaeltervergleich misst dabei den Platz, den die Zahl WIRKLICH
     hat, und nicht die Fensterbreite.
*/
.stat-body { container-type: inline-size; }

@container (max-width: 150px) {
  .stat .v { font-size: 1.5rem; }
}
@container (max-width: 120px) {
  .stat .v { font-size: 1.1875rem; }
}

/*
  Vier Geldbetraege brauchen mehr Spalte als vier Stueckzahlen. Der Wert
  ist an «52’523.00» bei 30 px gemessen und nicht geraten.
*/
/*
  Zwei oder vier, nie drei.

  `auto-fit` ergab bei 1200 px genau drei Spalten — die vierte Kachel
  rutschte allein in die naechste Zeile, und eine 3+1-Reihe sieht aus
  wie ein Fehler. Darum ausgeschriebene Spaltenzahlen: zwei mal zwei
  mit grossen Zahlen, und erst auf einem breiten Schirm alle vier.
*/
.grid-4.grid-geld { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 1500px) {
  .grid-4.grid-geld { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/*
  Reiter.

  Sie **umbrechen**, sie scrollen nicht. Ein Scrollbalken unter acht
  Reitern versteckt genau die, die man sucht — und man sieht ihm nicht an,
  dass da noch etwas kommt. Umgebrochen steht alles da.

  Die Linie gehört unter die letzte Zeile, nicht unter den Kasten: bei
  einem Umbruch liefe sie sonst quer durch die Reiter. Deshalb trägt jede
  Zeile ihre eigene über den Innenschatten des Behälters — der folgt der
  Höhe des Inhalts, auch wenn sie sich verdoppelt.
*/
.tabs {
  /* Etwas Luft zwischen den Zeilen, falls umgebrochen wird. */
  display: flex; flex-wrap: wrap; gap: 4px 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 24px;
  /*
    Die Linie endet nach dem letzten Reiter, nicht am Rand der Seite. Über
    die halbe Breite weitergezogen sieht sie aus wie eine Trennung, die
    etwas abschneidet — dabei gehört sie zu den Reitern.
  */
  width: fit-content;
  max-width: 100%;
}
.tabs a {
  padding: 9px 14px; font-size: 0.875rem; color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
}

@media (max-width: 560px) {
  /*
    Am Telefon ist Umbrechen keine Hilfe — acht Reiter würden vier Zeilen
    hoch. Dort also doch schieben, aber sichtbar: der letzte Reiter wird
    angeschnitten, und daran erkennt man, dass es weitergeht.
  */
  .tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
}
.tabs a:hover { color: var(--text); text-decoration: none; }
.tabs a[aria-current="page"] { color: var(--text); font-weight: 500; border-bottom-color: var(--accent); }
/*
  Jeder Reiter ist von Anfang an so breit wie in Fett (16.10.2026). Sonst
  rückt beim Wechsel alles rechts vom aktiven Reiter um ein paar Pixel —
  die Leiste springt bei jedem Klick an eine andere Stelle.
*/
.tabs [data-label] { display: inline-flex; flex-direction: column; align-items: center; }
.tabs [data-label]::after {
  content: attr(data-label); font-weight: 500;
  height: 0; overflow: hidden; visibility: hidden; pointer-events: none;
}

/* Werkzeugleiste über Listen */
.toolbar { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 20px; }
.toolbar .input, .toolbar .select { width: auto; min-width: 180px; }

/* Seitenblättern */
.pager { display: flex; justify-content: space-between; align-items: center; gap: 12px;
         padding: 12px 20px; border-top: 1px solid var(--border); font-size: 0.75rem; color: var(--muted); }
.pager a { display: inline-flex; align-items: center; min-height: 34px; padding: 4px 12px;
           border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); }
.pager a:hover { background: var(--surface-muted); text-decoration: none; }

/* --- 4) Seitenaufbau ---------------------------------------------------- */

.page-head { display: flex; justify-content: space-between; align-items: flex-end;
             gap: 16px; flex-wrap: wrap; margin-bottom: 24px; }
.page-head h1 { font-size: 1.5rem; font-weight: 600; letter-spacing: -.02em; line-height: 1.2; }
.page-head .desc { color: var(--muted); font-size: 0.875rem; margin-top: 4px; }

/* Kopfzeile der Marketingseiten */
/*
  Kein backdrop-filter mehr.

  Er erzeugt einen eigenen Bezugsrahmen: alles darin mit `position: fixed`
  — also das Klappmenue am Telefon — richtet sich dann an der Kopfzeile
  aus statt am Bildschirm und wird auf ihre Hoehe zugeschnitten. Das Menue
  war deshalb schlicht unsichtbar.

  Verloren geht nichts: die Kopfzeile ist seit dem Umbau deckend dunkel,
  der Weichzeichner hatte ohnehin nichts mehr zu tun. Derselbe Stolperstein
  wie beim Menue der Anwendung, an derselben Eigenschaft.
*/
.site-head {
  position: sticky; top: 0; z-index: 20;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.site-head .inner { max-width: 1200px; margin: 0 auto; padding: 0 24px;
                    height: var(--kopf-hoehe); display: flex; align-items: center;
                    justify-content: space-between; gap: 16px; }
.site-nav { display: flex; gap: 24px; font-size: 0.875rem; }
.site-nav a { color: var(--muted); }
.site-nav a:hover { color: var(--text); }
.site-nav > a, .nav-drop-top { white-space: nowrap; }

/*
  Unter 1100 px (bis 06.10.2026: 880) tritt das Klappmenue an die Stelle der Leiste.

  Die Grenze lag bei 760 px, als die Leiste vier Verweise trug. Mit
  fuenfen und zwei Klappkaesten wird es auf einem Tablet quer eng: „Fuer
  wen" bricht auf zwei Zeilen, die beiden Knoepfe rechts stapeln sich
  uebereinander. Das Klappmenue traegt ohnehin dieselben Wege — auf dem
  Tablet ist es die ruhigere Loesung, keine Notloesung.
*/
/* Seit 06.10.2026 bei 1100 px: mit sechs Verweisen, Sprachwahl und zwei
   Knöpfen brach «Kostenlos testen» bei 1024 px (iPad quer) in eine zweite
   Zeile. */
@media (max-width: 1100px) { .site-nav { display: none; } }
.site-head .row { flex-wrap: nowrap; }
.site-head .row > .btn { white-space: nowrap; }

/* Unter 880 px liegt die Seitennavigation hinter einem Knopf, statt zu
   verschwinden — vorher waren Preise und Funktionen am Telefon unerreichbar. */
.site-menu { display: none; position: relative; }
.site-menu > summary {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: var(--radius-sm);
  /* Auf der dunklen Kopfzeile ein Umriss, kein weisser Block: der Block
     zog mehr Aufmerksamkeit als der Knopf daneben, der etwas verkauft. */
  border: 1px solid var(--ink-border); background: var(--ink-card); color: var(--on-ink);
  cursor: pointer; list-style: none;
}
.site-menu > summary::-webkit-details-marker { display: none; }
.site-menu > summary::marker { content: ""; }
.site-menu[open] > summary { background: rgba(255, 255, 255, .16); }
/*
  Das Menue am Telefon nimmt die ganze Flaeche.

  Vorher hing ein kleiner Klappkasten unter dem Knopf — ein
  Schreibtischmenue in klein. Mit siebzehn Seiten passt das nicht mehr:
  die Eintraege waeren winzig, der Kasten haette gescrollt, und was
  dahinter liegt, blieb halb sichtbar und lenkte ab.

  Jetzt liegt es ueber der Seite, mit eigenem Bildlauf und Tippzielen von
  vierundvierzig Pixeln. Derselbe Aufbau wie in der Anwendung — wer beides
  benutzt, lernt es einmal.
*/
.site-menu-panel {
  /* Die Kopfhoehe steht an EINER Stelle: `--kopf-hoehe`. Sie wird dort
     gesetzt, wo auch die Kopfzeile ihre Hoehe bekommt — vorher standen
     64 und 58 je zweimal im Regelwerk, und ein Menue, das um sechs Pixel
     danebenliegt, faellt erst am Geraet auf. */
  position: fixed; inset: var(--kopf-hoehe) 0 0; z-index: 40;
  display: flex; flex-direction: column;
  padding: 6px 0 0;
  background: var(--bg);
  border-top: 1px solid var(--border);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}


.site-menu-panel nav { flex: 1; padding: 14px 16px 4px; }

.menu-title {
  margin: 16px 0 6px; padding: 0 6px;
  font-size: 0.7188rem; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.menu-title:first-child { margin-top: 4px; }

/*
  Der Pfeil an «Funktionen» und «Fuer wen».

  Er sagt: hier geht es auf eine eigene Seite weiter, auf der mehr steht.
  Ohne ihn saehen die sechs Zeilen gleich aus, und man wuerde die beiden
  Uebersichtsseiten fuer Endstationen halten.
*/
.menu-weiter::after {
  content: ""; margin-left: auto;
  width: 7px; height: 7px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg);
}

/* Sechs Zeilen duerfen groesser sein als siebzehn: mehr Hoehe, mehr
   Schrift, ein ruhigeres Bild — und ein Tippziel, das man nicht sucht.

   `nav` IM WEG — DIE ZEILE, DIE DIE KNOEPFE RETTET.

   Die Regel stand vorher auf `.site-menu-panel a` und traf damit ALLES,
   was im Menue ein Verweis ist. Unten im Menue sind das aber die beiden
   Knoepfe und die Sprachwahl, und gegen deren eigene Regeln gewann sie:
   eine Klasse plus ein Element schlaegt `.btn`, zwei Klassen plus ein
   Element schlagen `.sprachwahl.ist-menu > *`.

   Was man sah: der blaue Knopf behielt seine blaue Flaeche, bekam aber
   `--text` als Schriftfarbe — dunkelblaue Schrift auf blauem Grund, am
   Telefon nicht zu lesen. Und in der Sprachwahl stand «FR» als
   52 Pixel hohe Zeile in 16,5 Pixeln neben einem «DE» in 12.

   Der Fussbereich hat seine eigenen Bauteile, mit eigenen Regeln. Die
   Menueregel gilt darum dort, wo die Menuepunkte stehen: in `nav`. Das
   ist eine Grenze und kein Wettlauf um die staerkere Auswahl — der
   waere beim naechsten Bauteil im Fuss wieder zu fuehren. */
.site-menu-panel nav a {
  display: flex; align-items: center; gap: 11px;
  min-height: 52px; padding: 12px 10px;
  border-radius: var(--radius-sm);
  font-size: 1.0312rem; color: var(--text); text-decoration: none;
}
.site-menu-panel nav a:active { background: var(--surface-muted); }
.site-menu-panel nav a:hover { background: var(--surface-muted); text-decoration: none; }

/* Ein Oberpunkt traegt kein Zeichen — sonst saehe er aus wie ein
   Unterpunkt, und die Ordnung waere weg. */
.menu-top { font-weight: 500; }

/* Wo man gerade ist. Ohne das sind siebzehn Ziele siebzehn gleiche
   Zeilen, und man klickt auf die Seite, auf der man schon steht. */
.site-menu-panel nav a[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent-soft-text);
  font-weight: 600;
}
.site-menu-panel nav a[aria-current="page"] svg { color: var(--accent-soft-text); }

.site-menu-panel .menu-foot {
  position: sticky; bottom: 0;
  display: grid; gap: 8px;
  padding: 14px 16px calc(14px + env(safe-area-inset-bottom));
  background: var(--bg);
  border-top: 1px solid var(--border);
}
.site-menu-panel .menu-foot .btn { min-height: 46px; }

/*
  Die Seite darunter haelt still, solange das Menue offen ist.

  UND DIE KOPFZEILE MUSS DABEI FEST WERDEN.

  Das Festhalten setzt `position: fixed` an den Koerper und schiebt ihn
  um den Scrollstand nach oben. Eine `sticky` Kopfzeile klebt aber am
  KOERPER, nicht am Fenster — sie wanderte mit ihm aus dem Bild. Wer auf
  halber Seite das Menue oeffnete, sah oben einen Streifen Seiteninhalt
  und keinen Knopf zum Schliessen mehr.

  `fixed` bezieht sich auf das Fenster und nicht auf den Koerper: die
  Zeile bleibt oben stehen, wo sie hingehoert. Am 12.09.2026 eingebaut,
  zusammen mit dem Fehler, der sie noetig machte.
*/
body:has(.site-menu[open]),
body:has(.app-menu[open]) { overflow: hidden; }

/*
  Beide Kopfzeilen bleiben stehen, solange ihr Menue offen ist.

  `fixed` und nicht `sticky`: das Skript setzt den Koerper auf
  `position: fixed` mit einem negativen `top`, um den Lauf anzuhalten.
  Eine klebende Kopfzeile klebte dann am verschobenen Koerper und waere
  mit ihm aus dem Bild gewandert.
*/
body:has(.site-menu[open]) .site-head,
body:has(.app-menu[open])  .app-topbar {
  position: fixed; top: 0; left: 0; right: 0;
}

/*
  Der Brenner wird zum Kreuz, solange das Menue offen ist.

  Gemeldet als «die Schliess-Knoepfe sind nicht da»: drei Striche sehen
  aus wie «oeffnen», auch wenn schon offen ist. Zwei gedrehte Striche
  sehen aus wie «schliessen». Dieselben drei Elemente, keine neuen.
*/
.site-menu[open] .burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.site-menu[open] .burger span:nth-child(2) { opacity: 0; }
.site-menu[open] .burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
.burger span { transition: transform .16s ease, opacity .16s ease; }
@media (prefers-reduced-motion: reduce) { .burger span { transition: none; } }

@media (max-width: 1100px) {
  .site-menu { display: block; }
}

@media (max-width: 760px) {

  /*
    Sobald das Menue da ist, verschwinden die Knoepfe aus der Kopfzeile.

    Beide Wege — testen und anmelden — stehen im Menue unten als grosse
    Knoepfe, am Daumen statt am oberen Rand. Oben drangten sie die
    Wortmarke auf ein Drittel der Breite zusammen; jetzt hat sie den Platz,
    den ein Absender braucht.
  */
  .site-head .row > .btn { display: none; }
}
@media (max-width: 720px) {
  /* Die Kopfzeile schrumpft hier — `--kopf-hoehe` zieht das Menue mit. */
  :root { --kopf-hoehe: 58px; }
}

.brand { display: inline-flex; align-items: center; gap: 9px;
         font-weight: 600; letter-spacing: -.01em; color: var(--text); }
.brand:hover { text-decoration: none; }
.brand .mark {
  width: 30px; height: 30px; flex: 0 0 30px;
  display: block; border-radius: 9px;
}
/*
  Das vollständige Logo als Bild.

  Es liegt zweimal im Markup — einmal für hellen, einmal für dunklen Grund —
  und die Gestaltung blendet die unpassende Fassung aus. Der Umweg über zwei
  Bilder statt einer Datei mit `prefers-color-scheme` darin ist Absicht: was
  in einem eingebetteten SVG steht, wertet nicht jeder Browser aus, und die
  Wortmarke darf auf keinem verschwinden.

  Ausgeblendet wird der ganze Verweis, nicht nur das Bild — sonst bliebe ein
  leerer Kasten samt Innenabstand stehen.
*/
/* Die Wortmarke traegt die Marke allein — es gibt kein Zeichen mehr
   daneben, das sie stuetzt. Deshalb darf sie groesser sein als das alte
   Doppelgespann: 34 px statt 30. */
.brand-lockup { display: inline-block; height: 34px; }
.brand-lockup img { display: block; height: 100%; width: auto; }
.brand-lockup.is-light { display: var(--nur-hell); }
.brand-lockup.is-dark { display: var(--nur-dunkel); }

/*
  Fussbereich der Verkaufsseite.

  Drei Baender uebereinander: Herkunft, Verweise, Kleingedrucktes. Vorher
  stand hier eine Zeile mit drei Verweisen — das war ein Abschluss, aber
  keine Auskunft. Wer bis hierher liest, entscheidet gerade.
*/
.site-foot { border-top: 1px solid var(--border); background: var(--surface-muted); margin-top: var(--abschnitt); }
.site-foot .inner { max-width: 1200px; margin: 0 auto; padding: 26px 24px;
                    font-size: 0.875rem; color: var(--muted); }

.foot-trust { border-bottom: 1px solid var(--border); }

.foot-grid {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, 1fr);
  gap: 28px 24px;
}
.foot-brand p { margin-top: 12px; max-width: 30em; line-height: 1.6; }
.foot-logo { height: 30px; width: auto; display: block; }
.foot-logo.is-dark { display: none; }
.foot-col { display: flex; flex-direction: column; gap: 9px; align-items: flex-start; }
.foot-col h3 {
  margin: 0 0 3px; font-size: 0.75rem; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--heading);
}
.foot-col a { color: var(--muted); }
.foot-col a:hover { color: var(--text); }

.foot-base {
  border-top: 1px solid var(--border);
  display: flex; justify-content: space-between; align-items: center;
  gap: 16px 24px; flex-wrap: wrap;
  font-size: 0.8125rem;
}
.foot-base p { margin: 0; }
.foot-base-text { display: flex; flex-direction: column; gap: 2px; }

/* Die Armbrust von Swiss Label.

   EIN GUETEZEICHEN ERKENNT MAN AN DER SILHOUETTE

   Erst stand es mit 72 Pixeln im Hero, damit das senkrecht gesetzte Wort
   MADE lesbar wird. Das liest niemand — und dafuer wurde aus dem Zeichen
   ein weisser Block, der mit dem einen blauen Knopf um die
   Aufmerksamkeit stritt, die dort nur einem gehoert. Jetzt ist es klein
   und ruhig: ein Vermerk, keine Anzeige.

   KEIN WEISSES FELD, AUSSER WO ES NOETIG IST

   Das Zeichen ist durchsichtig hinterlegt. Auf hellem Grund steht es
   darum direkt auf der Seite; jede Umrandung waere eine Kiste um etwas,
   das keine braucht. Nur auf dem dunklen Hero bekommt es ein helles
   Feld — dort ist das rote Wort SWISS unter dem Quadrat sonst kaum zu
   sehen. Die Marke selbst wird nie umgefaerbt: sie wird gefuehrt, wie
   sie ist. */
.swisslabel { display: inline-flex; line-height: 0; text-decoration: none; }
.swisslabel img { height: 40px; width: auto; display: block; }
.swisslabel:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Fuss: Zeichen «Bildungssoftware» und Swiss Label nebeneinander, gleich hoch. Das
   Zeichen «Bildungssoftware» ist ein Rahmen mit Schild und zwei Zeilen wie auf
   swyron-flow.com, in den Farben der Seite (27.10.2026). */
.foot-zeichen { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.edu-zeichen {
  display: inline-flex; align-items: center; gap: 10px;
  height: 40px; padding: 0 14px 0 11px; box-sizing: border-box;
  border: 1px solid var(--muted); border-radius: 10px;
  color: var(--text); text-decoration: none; line-height: 1.15;
}
.edu-zeichen:hover { border-color: var(--text); color: var(--text); }
.edu-zeichen:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.edu-zeichen svg { flex: none; width: 20px; height: auto; color: var(--ton-gruen-fg); }
.edu-zeichen .edu-haken { stroke: var(--surface); }
.edu-zeichen strong { display: block; font-size: 0.875rem; font-weight: 600; }
.edu-zeichen small { display: block; font-size: 0.6875rem; color: var(--muted); white-space: nowrap; }

/* Im Hero: helles Feld, aber knapp. Etwas abgesetzt vom Kleingedruckten
   darüber, damit die Herkunft als eigene Zeile gelesen wird (29.09.2026). */
.hero-label {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 28px;
}
.hero-label p { margin: 0; color: var(--muted); }
.hero-label .swisslabel {
  padding: 5px 7px; border-radius: 5px;
  background: var(--fremdmarke-grund);
}
.hero-label .swisslabel img { height: 34px; }

/* Der Beleg auf der Sicherheitsseite.

   Hier ist die Marke nicht Beiwerk, sondern der Gegenstand: je Zeile ein
   Zeichen, sein Name und der Satz, den es behauptet. Darunter, durch eine
   Linie getrennt, wer sie fuehren darf und wo das nachzulesen ist. */
.swisslabel-beleg {
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface);
  padding: 24px 26px;
  display: flex; flex-direction: column; gap: 20px;
}
.swisslabel-beleg > h3 { margin: 0; font-size: 1.0625rem; color: var(--heading); }
.swisslabel-zeilen {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 18px 28px;
}
.swisslabel-zeile { display: flex; align-items: center; gap: 14px; }
.swisslabel-zeile .swisslabel { flex: none; }
.swisslabel-zeile .swisslabel img { height: 52px; }
.swisslabel-zeile strong {
  display: block; color: var(--heading); font-size: 0.9375rem; margin-bottom: 2px;
}
.swisslabel-zeile span { color: var(--muted); font-size: 0.875rem; }
.swisslabel-fuss {
  border-top: 1px solid var(--rule); padding-top: 16px;
  display: flex; justify-content: space-between; gap: 10px 24px; flex-wrap: wrap;
  align-items: baseline;
  font-size: 0.875rem; color: var(--muted);
}
.swisslabel-fuss p { margin: 0; }

@media (max-width: 860px) {
  .foot-grid { grid-template-columns: 1fr 1fr; }
  .foot-brand { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  /* Auf dem Telefon steht der Text oben und das Zeichen darunter. */
  .foot-base { justify-content: flex-start; }
  .swisslabel-beleg { padding: 18px; }
}

@media (max-width: 480px) {
  /* Zwei schmale Spalten statt einer langen: elf Verweise untereinander
     sind ein Bildschirm fuer sich. */
  .foot-grid { grid-template-columns: 1fr 1fr; gap: 22px 18px; }
  .foot-brand { grid-column: 1 / -1; }
  .foot-col { gap: 8px; }
}
@media (max-width: 360px) {
  .foot-grid { grid-template-columns: 1fr; }
}

/*
  Das Vertrauensband.

  Im Fussbereich vier ruhige Zeilen nebeneinander, auf der Sicherheitsseite
  dieselben Punkte als Karten. Dasselbe Bauteil, damit die Aussagen nicht
  an zwei Stellen auseinanderlaufen.
*/
.trust { display: grid; gap: 18px 26px; }
.trust-band { grid-template-columns: repeat(4, 1fr); }
.trust-gross { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 16px; }
/* Sechs Punkte in 4 + 2 lassen rechts eine Luecke, die wie ein Fehler
   aussieht. Zu dritt gehen sie glatt auf. */
@media (min-width: 900px) {
  .trust-drei { grid-template-columns: repeat(3, 1fr); }
}

.trust-item { display: flex; align-items: flex-start; gap: 11px; }
.trust-gross .trust-item {
  padding: 18px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.trust-mark { flex: 0 0 auto; line-height: 0; margin-top: 1px; color: var(--accent); }
.trust-mark svg { width: 18px; height: 18px; }
/* Auf der Sicherheitsseite steht das Karten-Icon in einem runden, leicht
   getönten Chip — der Badge-Look angedeutet, ohne die schweren Embleme
   des Footers (und ohne sie dort doppelt zu zeigen). Nur `gross`. */
.trust-gross .trust-mark {
  width: 46px; height: 46px; margin-top: 0; line-height: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--accent-soft); color: var(--accent-soft-text);
}
.trust-gross .trust-mark svg { width: 22px; height: 22px; }
.trust-text { min-width: 0; }
.trust-text strong { display: block; font-size: 0.8438rem; color: var(--heading); }
.trust-text span { display: block; margin-top: 2px; font-size: 0.8125rem; line-height: 1.5; }

@media (max-width: 860px) { .trust-band { grid-template-columns: 1fr 1fr; } }
@media (max-width: 460px) { .trust-band { grid-template-columns: 1fr; } }

/* Vertrauens-Siegel im Fussbereich — siehe partials/footer-badges.php.
   Selbst gezeichnet; die Fahnenfarben stehen als Hexwerte. */
.foot-badges {
  /* Sechs gleiche Spalten verteilen die Siegel gleichmässig über die
     ganze Breite — als Raster, damit nie ein einzelnes in eine zweite
     Reihe rutscht (bei `space-between` wäre das bei sechs passiert). */
  display: grid; grid-template-columns: repeat(4, 1fr);
  align-items: center; gap: 18px 20px;
  padding: 2px 0 4px;
}
@media (max-width: 860px) { .foot-badges { grid-template-columns: repeat(2, 1fr); } }
.foot-badge { display: flex; justify-content: center; align-items: center; gap: 11px; }
.foot-badge-emblem { width: 50px; height: 50px; flex: none; color: var(--heading); }
.foot-badge-text {
  font-size: 0.8125rem; font-weight: 600; line-height: 1.25;
  color: var(--heading); max-width: 9em; overflow-wrap: break-word;
}

/* Kopf ohne Vorschaubild — fuer die Unterseiten. */
/* Mehr Luft nach unten, weil auf diesen Seiten etwas hineinragt — das
   Bildschirmfoto, die Preistafeln, die Beleg-Karten. Ohne den Zuschlag
   schoebe sich der Rahmen ueber die letzte Textzeile. */
.hero-slim { padding: var(--abstand-6) 0 var(--abschnitt); }
.hero-slim h1 { max-width: 16em; }

/*
  Harte Umbrueche nur am Schreibtisch.

  Das <br> in einer Ueberschrift setzt die Zeile dort, wo sie bei 1280 px
  gut sitzt. Bei 390 px sitzt sie dann falsch — „Der ganze Ablauf, / von
  der Erfassung bis zur / Rueckgabe" hat drei Zeilen, von denen die
  mittlere aus dem Umbruch stammt und nicht aus der Breite.
*/
@media (max-width: 720px) {
  /* Im Markup steht ein Leerzeichen vor dem Umbruch. Sichtbar faellt es
     mit dem Umbruch zusammen; verborgen bleibt es als Wortabstand — sonst
     stuende hier „Ablauf,von der“. */
  .hero h1 br, .cta h2 br { display: none; }
}

/*
  Angaben fuer die IT: Begriff links, Erklaerung rechts. Eine Tabelle waere
  richtiger, sieht aber nach Datenblatt aus; hier soll man es lesen.
*/
.spec { display: grid; gap: 0; }
/*
  Zwei Masse, beide gemessen und nicht geschaetzt.

  Die Begriffsspalte stand auf 190 Pixeln, „Passwoerter und Zugangsdaten"
  braucht 207 — der laengste Begriff brach also zwischen Konjunktion und
  Substantiv um. Und die Erklaerung daneben lief ueber neunhundert Pixel,
  bei vierzehn Pixeln Schrift rund hundertfuenfzig Zeichen je Zeile.
*/
.spec > div {
  display: grid; grid-template-columns: 210px minmax(0, 46em); gap: 20px;
  padding: 15px 0; border-bottom: 1px solid var(--border);
}
.spec > div:last-child { border-bottom: 0; }
.spec dt { font-weight: 600; color: var(--heading); font-size: 0.875rem; }
.spec dd { margin: 0; color: var(--muted); font-size: 0.875rem; line-height: 1.6; }
@media (max-width: 640px) {
  .spec > div { grid-template-columns: 1fr; gap: 4px; }
}

/* Aufzaehlung, die wie eine Karte steht. */
.card-list {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); padding: 6px 20px; margin: 0; list-style: none;
}
.card-list li { padding: 15px 0; border-bottom: 1px solid var(--border); }
.card-list li:last-child { border-bottom: 0; }
.card-list strong { display: block; color: var(--heading); }
.card-list span { display: block; margin-top: 3px; font-size: 0.875rem; line-height: 1.6; }

/*
  Lesemass — aber links, nicht mittig.

  Eine Zeile ueber zwoelfhundert Pixel findet das Auge am Ende nicht
  mehr zum Anfang der naechsten zurueck; darum die Begrenzung auf 46em.

  Begrenzt wird aber der INHALT, nicht die Huelle. Vorher war die Huelle
  selbst schmal — und weil `.wrap` mittig steht, ruckte damit die ganze
  Spalte in die Seitenmitte. Auf jeder dieser fuenf Seiten sprang die
  linke Kante: die Abschnitte darueber begannen bei 64 Pixeln, dieser
  bei 319, mit breiten leeren Streifen zu beiden Seiten. Es sah nach
  einem Fehler aus, und es war einer.

  Eine Seite hat eine linke Kante. Das Lesemass verkuerzt die Zeile nach
  rechts und ruehrt den Anfang nicht an.

  Der doppelte Selektor bleibt noetig: `.narrow-prose` steht in der
  Vorlage immer zusammen mit `.wrap`, und `.wrap { max-width: 1200px }`
  kommt in dieser Datei spaeter — bei gleicher Gewichtung gewinnt das
  Spaetere.
*/
.narrow-prose,
.wrap.narrow-prose { max-width: 1200px; }
.narrow-prose > *,
.wrap.narrow-prose > * { max-width: 46em; }

/*
  Ein Kartenraster ist kein Fliesstext.

  Ueberschrift, Vorspann und Fragenliste bekommen das Lesemass; Karten
  nicht. Auf 46em gestutzt standen die beiden Karten unter «Der Bund
  stellt das Inventar an den Anfang» schmal links und liessen die halbe
  Seite leer — waehrend dasselbe Raster im Abschnitt darueber die volle
  Breite nutzt. Zweimal dieselbe Bauform, zwei Breiten: das liest sich
  als Fehler.
*/
.narrow-prose > .grid,
.wrap.narrow-prose > .grid { max-width: none; }

/*
  Eine nummerierte Schrittfolge — und der eine Schritt, um den es geht.

  Die fuenf Funktionen des IKT-Minimalstandards standen vorher als
  Komma-Reihe mitten im Vorspann. Als Liste sind sie lesbar, und der
  erste laesst sich hervorheben: die Behauptung «das Inventar steht im
  ersten» steht dann nicht nur da, man sieht sie.

  Die Nummern sind hier ausnahmsweise Information und nicht Zierrat —
  es IST eine Reihenfolge, und genau darauf kommt es an.
*/
.schrittfolge { list-style: none; margin: 0; padding: 0; }
.schrittfolge li {
  display: flex; gap: 14px; align-items: baseline;
  padding: 13px 0; border-bottom: 1px solid var(--border);
}
.schrittfolge li:last-child { border-bottom: 0; }
.schrittfolge .nr {
  flex: none; width: 26px;
  font-variant-numeric: tabular-nums; font-weight: 600;
  color: var(--muted); font-size: 0.875rem;
}
.schrittfolge .txt { display: block; }
.schrittfolge strong { display: block; color: var(--heading); }
.schrittfolge span.muted { display: block; margin-top: 3px; font-size: 0.875rem; line-height: 1.6; }

/* Der Schritt, den Inventaris abdeckt. Ein einziger hervorgehobener
   Eintrag; waeren es zwei, hoerte es auf, etwas zu bedeuten. */
.schrittfolge .ist-unser .nr { color: var(--accent); }
.schrittfolge .ist-unser strong { color: var(--accent); }

/* Ein Abschluss ist ein Aufruf, kein Lesestoff: mittig, mit Mass. */
.section-schluss .wrap { text-align: center; }
.section-schluss h2 { margin-bottom: 0; }
.section-schluss p { margin-inline: auto; max-width: 44em; }
.section-schluss .row { justify-content: center; }

/* Funktionen in Gruppen: die Ueberschrift traegt die Karten darunter. */
.feature-group { margin-top: 44px; }
.feature-group:first-of-type { margin-top: 34px; }
.feature-group-head { margin-bottom: 18px; }
.feature-group-head h3 {
  margin: 0; font-size: 1.1875rem; font-weight: 600; color: var(--heading);
  letter-spacing: -.01em;
}
.feature-group-head p { margin: 5px 0 0; color: var(--muted); font-size: 0.9375rem; }

/*
  Bildschirmfotos mit Reitern — ohne JavaScript.

  Die Auswahlknoepfe sind unsichtbar, die Beschriftungen sind die Reiter.
  Welches Bild sichtbar ist, entscheidet :checked ueber die Geschwister.
  Gezaehlt wird mit nth-of-type: Knoepfe sind <input>, Bilder <figure> —
  zwei Typen, zwei unabhaengige Zaehlungen. Damit haengt hier keine Regel
  an einem Dateinamen.

  Mit der Tastatur bedienbar und von der Sprachausgabe ansagbar, weil es
  echte Auswahlknoepfe sind und keine nachgebauten.
*/
.shots { --shot-radius: 12px; }
.shot-tabs { display: flex; flex-wrap: wrap; gap: 8px; }
.shot-radio { position: absolute; opacity: 0; pointer-events: none; }

.shot-tab {
  padding: 7px 14px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--muted);
  font-size: 0.875rem; font-weight: 500; cursor: pointer;
  user-select: none;
}
.shot-tab:hover { border-color: var(--indigo-200); color: var(--text); }
.shot-radio:checked + .shot-tab {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
/* Sichtbarer Fokus — sonst weiss man bei der Tastatur nicht, wo man ist. */
.shot-radio:focus-visible + .shot-tab { outline: 2px solid var(--accent); outline-offset: 2px; }

.shot { display: none; width: 100%; margin: 22px 0 0; }
/* Zwölf Paare — mehr Reiter passen ohnehin nicht auf einen Bildschirm.
   Gezaehlt wird je Typ: Knoepfe sind <input>, Bilder <figure>. */
.shot-radio:nth-of-type(1):checked ~ .shot:nth-of-type(1),
.shot-radio:nth-of-type(2):checked ~ .shot:nth-of-type(2),
.shot-radio:nth-of-type(3):checked ~ .shot:nth-of-type(3),
.shot-radio:nth-of-type(4):checked ~ .shot:nth-of-type(4),
.shot-radio:nth-of-type(5):checked ~ .shot:nth-of-type(5),
.shot-radio:nth-of-type(6):checked ~ .shot:nth-of-type(6),
.shot-radio:nth-of-type(7):checked ~ .shot:nth-of-type(7),
.shot-radio:nth-of-type(8):checked ~ .shot:nth-of-type(8),
.shot-radio:nth-of-type(9):checked ~ .shot:nth-of-type(9),
.shot-radio:nth-of-type(10):checked ~ .shot:nth-of-type(10),
.shot-radio:nth-of-type(11):checked ~ .shot:nth-of-type(11),
.shot-radio:nth-of-type(12):checked ~ .shot:nth-of-type(12) { display: block; }

.shot a[data-lightbox] { display: block; }
.shot img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--border); border-radius: var(--shot-radius);
  /* Der Schatten hebt das Bild von der Flaeche ab, ohne es zu rahmen. */
  box-shadow: var(--bild-schatten);
  background: var(--surface);
}
.shot figcaption {
  margin-top: 14px; color: var(--muted); font-size: 0.9062rem; line-height: 1.6;
  max-width: 46em;
}
/*
  Unter einem Bild ueber die ganze Breite darf die Unterschrift laenger
  laufen.

  Auf 46em brach ein Satz von anderthalb Zeilen um, obwohl rechts die
  halbe Breite leer blieb — „… und die Revision / verlangen." liest sich
  wie abgeschnitten. Es ist eine Bildunterschrift und kein Fliesstext:
  sie steht einmal, wird einmal gelesen und darf dafuer breiter sein.
*/
.shot-solo figcaption { max-width: 62em; }

@media (max-width: 640px) {
  /* Ein Bildschirmfoto einer ganzen Anwendung ist auf einem Telefon klein.
     Es bleibt trotzdem stehen — es zeigt die Anmutung, nicht die Schrift —,
     und wer es genau sehen will, tippt es an: dann geht es gross auf. */
  /*
    Zehn Reiter brauchen am Telefon vier Zeilen. Sie bleiben alle sichtbar
    — waagrechtes Schieben haette zwar eine Zeile gespart, aber die Haelfte
    der Reiter unter den Rand geschoben, und welcher fehlt, sieht man
    nicht. Also lieber kleiner und vollstaendig.
  */
  .shot-tabs { gap: 6px; }
  .shot-tab { padding: 6px 11px; font-size: 0.8125rem; }
  .shot { margin-top: 16px; }
  .shot img { border-radius: 8px; box-shadow: 0 10px 24px rgba(16, 20, 35, .10); }
  .shot figcaption { margin-top: 10px; font-size: 0.875rem; }
}

/* Marketing */
/* Ohne Farbverlauf: eine ruhige Flaeche und eine Kante. Der Verlauf hat den
   Text nur schlechter lesbar gemacht und je nach Bildschirm gestreift. */
.hero { border-bottom: 1px solid var(--border); background: var(--surface-muted); }
/*
  1200 statt 1120.

  Auf einem gewoehnlichen Bildschirm mit 1440 oder 1600 px stand der
  Inhalt in einer schmalen Saeule mit viel Leerraum daneben — das wirkt
  nicht ruhig, sondern unfertig. Achtzig Pixel mehr sind kein anderer
  Aufbau, aber drei Kacheln nebeneinander bekommen davon je gut
  fuenfundzwanzig, und der Text im Aufmacher liest sich weiterhin
  angenehm, weil er ohnehin auf 34em begrenzt ist.
*/
.wrap { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
.section { padding: var(--abschnitt) 0; }
.section-muted { background: var(--surface-muted);
                 border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
/* Getönter Abschnitt (seit 30.09.2026): hellblau auslaufend, ohne Kanten. */
.section-blau { background: linear-gradient(180deg, var(--ton-blau-bg), var(--surface-muted) 70%); }

/*
  Der Werbefilm auf der Startseite (seit 15.10.2026): rechts im Aufmacher
  ein stummer Ausschnitt im Fensterrahmen, darunter der Knopf, der den
  ganzen Film in einem Fenster öffnet. Das Bild steht im Format 16:9
  bereit, bevor etwas geladen ist — so springt nichts, wenn das Standbild
  kommt. Dunkler Grund, weil Anfang und Schluss des Films dunkel sind.
*/
/* Der Rahmen wie das Zeichen: kräftige blaue Kante, weiche Rundung, ohne
   Adressleiste — nur die Vorführung. */
.hero-film { overflow: hidden; border: 4px solid var(--accent); border-radius: 24px; background: var(--surface); box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .8); }

.hero-anim-huelle { position: relative; }
/*
  Die Vorführung: die Bühne des Werbefilms (1920 × 1080) liegt in
  .vf-rahmen und wird auf den Ausschnitt des Anwendungsfensters gesetzt
  (1120 × 700, ab 112/237 der Bühne). app.js rechnet den Massstab aus der
  Breite. Darunter das Standbild, bis die Bühne läuft.
*/
.vf { position: relative; aspect-ratio: 1120 / 700; overflow: hidden; background: var(--surface-muted); }
.vf-standbild { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.vf-rahmen { position: absolute; left: 0; top: 0; width: 1120px; height: 700px; overflow: hidden; transform-origin: 0 0; }
.vf .vf-rahmen #buehne { position: absolute; left: -112px; top: -237px; }
.vf .vf-rahmen .tafel, .vf .vf-rahmen #kopf, .vf .vf-rahmen #fortschritt { display: none; }
.vf .vf-rahmen .fenster { box-shadow: none; border-radius: 0; }

/* Halteknopf auf hellem Bild: dunkler, voller Grund, deutlicher Fokus */
.hero-dark .bewegung-knopf.hero-anim-knopf {
  position: absolute; right: 10px; top: 10px; width: 34px; height: 34px; z-index: 2;
  background: var(--ink); color: var(--on-ink); border: 2px solid var(--on-ink);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .35);
}
.hero-dark .bewegung-knopf.hero-anim-knopf:hover { background: var(--ink-2); border-color: var(--on-ink); }
.hero-dark .bewegung-knopf.hero-anim-knopf:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.hero-film-knopf { margin-top: 18px; gap: 10px; }
.hero-film-knopf .ic { width: 18px; height: 18px; }

.film-fenster {
  width: min(1100px, calc(100vw - 32px)); max-width: none;
  padding: 0; border: 0; border-radius: 18px; overflow: hidden;
  background: var(--ink); color: var(--on-ink);
  box-shadow: 0 40px 100px -20px rgba(0, 0, 0, .7);
}
.film-fenster::backdrop { background: rgba(8, 12, 24, .78); }
.film-fenster-kopf { display: flex; justify-content: flex-end; padding: 8px 8px 0; }
.film-zu { color: var(--on-ink); width: 40px; height: 40px; padding: 0; justify-content: center; }
.film-zu:hover { background: var(--ink-card); color: var(--on-ink); }
.film-zu .ic { width: 20px; height: 20px; }
.film-video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; background: #000; }
.film-hinweis { margin: 0; padding: 10px 16px 14px; font-size: 0.8125rem; color: var(--on-ink-muted); }
@media (max-width: 640px) {
  .film-fenster { border-radius: 12px; }
  .hero-film { border-width: 3px; border-radius: 18px; }
  .hero-dark .bewegung-knopf.hero-anim-knopf { width: 28px; height: 28px; right: 8px; top: 8px; }
  .hero-film-knopf { width: 100%; justify-content: center; }
}

/*
  Preise und Sicherheit als zwei Flächen (Startseite, seit 30.09.2026):
  eine blau, eine dunkel. Vorher zwei Textspalten auf Grau — das Wichtigste
  vor dem Abschluss sah aus wie Kleingedrucktes.
*/
.start-karten { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.start-karte {
  position: relative; overflow: hidden;
  padding: 40px; border-radius: calc(var(--radius) + 6px);
  color: var(--on-ink);
}
.start-karte.is-blau   { background: linear-gradient(145deg, var(--brand-500), var(--brand-700)); }
.start-karte.is-dunkel { background: linear-gradient(145deg, var(--ink-2), var(--ink)); }
.start-karte::after {
  content: ""; position: absolute; right: -60px; bottom: -60px; width: 220px; height: 220px;
  border-radius: 50%; background: rgba(255, 255, 255, .07); pointer-events: none;
}
.start-karte h2 { color: var(--on-ink); }
.section .start-karte .lead { color: var(--on-ink); opacity: .9; }
.section.start-karten-abschnitt { padding-top: 8px; }
.start-karte .sec-eyebrow { background: rgba(255, 255, 255, .14); color: var(--on-ink); }
.start-karte .sec-eyebrow b { color: var(--on-ink); }
.start-karte .btn { position: relative; z-index: 1; background: var(--surface); color: var(--accent-text); border-color: transparent; }
.start-karte .btn:hover { background: var(--brand-50); }
.start-karte .btn-secondary { background: transparent; color: var(--on-ink); border: 1px solid rgba(255, 255, 255, .45); }
.start-karte .btn-secondary:hover { background: rgba(255, 255, 255, .1); }
@media (max-width: 860px) {
  .start-karten { grid-template-columns: minmax(0, 1fr); }
  .start-karte { padding: 28px 22px; }
}

.hero h1 { font-size: 2.625rem; line-height: 1.1; letter-spacing: -.025em; font-weight: 600; margin: 20px 0 0; }
.hero .lead { font-size: 1.0625rem; color: var(--muted); margin-top: var(--abstand-3); max-width: 34em; line-height: 1.6; }
.hero .eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--brand-300);
  background: color-mix(in srgb, var(--brand-50) 80%, transparent);
  color: var(--brand-900); border-radius: 999px;
  padding: 6px 14px; font-size: 0.75rem; font-weight: 500;
}
@media (max-width: 640px) { .hero h1 { font-size: 2rem; } }

/*
  Am Telefon liegen die Funktionskarten waagrecht.

  Achtzehn Karten mit dem Zeichen ueber der Ueberschrift ergaben eine
  Spalte von rund dreieinhalbtausend Pixeln — man scrollt an der Haelfte
  vorbei, ohne sie zu lesen. Zeichen links, Ueberschrift daneben, Text
  darunter: dieselbe Aussage auf gut der halben Hoehe.
*/
@media (max-width: 640px) {
  .grid { gap: 12px; }

  .feature {
    display: grid;
    grid-template-columns: 38px minmax(0, 1fr);
    column-gap: 12px; row-gap: 5px;
    padding: 15px 16px 17px;
  }
  .feature .icon {
    grid-column: 1; grid-row: 1;
    width: 38px; height: 38px; margin: 0; font-size: 1.0625rem;
  }
  .feature h3 { grid-column: 2; grid-row: 1; align-self: center; margin: 0; }
  /* Der Text laeuft unter dem Zeichen durch ueber die ganze Breite. Eingerueckt
     verschenkte er fuenfzig Pixel je Zeile — auf einem Telefon ein Wort. */
  .feature p  { grid-column: 1 / -1; grid-row: 2; margin: 0; }

  .feature-group { margin-top: 32px; }
  .feature-group:first-of-type { margin-top: 26px; }
  .feature-group-head { margin-bottom: 12px; }
  .feature-group-head h3 { font-size: 1.0625rem; }
  .feature-group-head p { font-size: 0.875rem; }
}

.section h2 { font-size: 1.75rem; letter-spacing: -.02em; font-weight: 600; line-height: 1.15; }
.section .lead { color: var(--muted); margin-top: var(--abstand-2); max-width: 40em; }

/* Kein Anheben beim Ueberfahren: die Kachel ist kein Verweis, und die
   Bewegung hat ein Klickziel versprochen, das es nicht gibt. */
.feature { padding: var(--abstand-4); }
.feature .icon {
  width: 44px; height: 44px; border-radius: var(--radius);
  background: var(--accent-soft); color: var(--accent-soft-text);
  display: grid; place-items: center; margin-bottom: 16px; font-size: 1.25rem;
}
.feature h3 { font-size: 0.9375rem; font-weight: 600; letter-spacing: 0; }
.feature p { font-size: 0.875rem; color: var(--muted); margin-top: 6px; line-height: 1.6; }

/* Der Rahmen der empfohlenen Tafel ist Auszeichnung, also Marke; der Knopf
   darin ist Bedienung, also blau. `overflow: visible` ueberschreibt die
   Karte — sonst schneidet sie die Auszeichnung oben ab. */
/*
  Die drei Tafeln sind verschieden lang, die Knoepfe stehen trotzdem auf
  einer Linie. Ohne das haengt „Testphase starten" bei Starter mitten in
  der Karte und bei Pro am Boden — und das liest sich, als waere bei
  Starter etwas vergessen worden.
*/
.plan { padding: var(--abstand-4); position: relative; overflow: visible;
        display: flex; flex-direction: column; }
.plan ul { flex: 1 1 auto; }
.plan .btn-block { margin-top: auto; }
.plan.featured { border-color: var(--brand-500); box-shadow: 0 0 0 2px var(--brand-500), var(--shadow-lg); }
.plan .tag { position: absolute; top: -11px; left: 26px;
             background: var(--brand-500); color: var(--on-brand); border-radius: 999px;
             padding: 4px 12px; font-size: 0.75rem; font-weight: 600; }
/* Karten im Raster tragen ihren Abstand nicht selbst — das Raster tut es.
   Das erspart ein `style="margin-bottom:0"` an jeder einzelnen Kachel. */
.grid > .card { margin-bottom: 0; }
.grid-top { align-items: start; }
.card-prose { padding: var(--abstand-4); }
.card-prose h3 { font-size: 1.1875rem; font-weight: 600; }

.plan .price { font-size: 1.875rem; font-weight: 600; letter-spacing: -.02em; line-height: 1.15; margin-top: 18px; }
.plan .per { font-size: 0.875rem; color: var(--muted); margin-left: 6px; font-weight: 400; }
.plan ul { margin-top: 20px; }
.plan li { display: flex; gap: 10px; font-size: 0.875rem; color: var(--text); margin-bottom: 9px;
           line-height: 1.5; }
.plan li svg { width: 17px; height: 17px; flex: 0 0 17px; margin-top: 3px; color: var(--accent); }

/* Anmeldeseiten */
/*
  Zwei Flächen: links eine ruhige Spalte mit Marke und Leitsatz, rechts
  die getönte Arbeitsfläche mit Formular, Abbildung und einer Welle am
  Fuss. Das Formular steht direkt auf der Fläche, nicht in einer Karte —
  weisse Felder auf hellem Blau sind Rahmen genug.

  Unter 1024 Pixeln fällt die Spalte weg und die Marke rückt in eine
  Kopfzeile; die Abbildung erscheint erst ab 1200, wo neben dem Formular
  wirklich Platz ist.
*/
.auth-page { min-height: 100vh; min-height: 100dvh; display: flex; background: var(--auth-flaeche); }

.auth-seite {
  flex: 0 0 360px; display: flex; flex-direction: column;
  padding: 36px 40px 28px; background: var(--surface);
  border-right: 1px solid var(--border);
}
.auth-seite-marke .brand-lockup { height: 30px; }
.auth-leitsatz {
  margin: auto 0; max-width: 16em;
  font-size: 1.625rem; line-height: 1.3; font-weight: 600; letter-spacing: -.015em;
  color: var(--heading);
}
.auth-seite-fuss { display: flex; flex-direction: column; gap: 6px; font-size: 0.7812rem; color: var(--muted); }
.auth-seite-links { display: flex; gap: 14px; }
.auth-seite-links a { color: var(--muted); }
.auth-seite-links a:hover { color: var(--text); }

.auth-haupt { position: relative; flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }
/* Oben 36 px wie die Spalte daneben, 30 px hoch wie die Wortmarke: so steht
   die Sprachwahl auf einer Linie mit dem Logo. */
.auth-kopf { position: relative; z-index: 2; display: flex; align-items: center; justify-content: flex-end; min-height: 30px; box-sizing: content-box; padding: 36px 40px 12px; }
.auth-kopf-marke { display: none; }
.auth-sprache { position: relative; z-index: 5; }

.auth-inhalt {
  position: relative; z-index: 1; flex: 1 1 auto;
  display: flex; align-items: center; justify-content: center; gap: 72px;
  padding: 8px 32px 140px;
}
.auth-box { position: relative; z-index: 1; width: 100%; max-width: 400px; }
.auth-box > .alert { margin-bottom: 16px; }

.auth-card { background: none; border: 0; padding: 0; }
.auth-oberzeile { font-size: 0.9375rem; font-weight: 600; color: var(--muted); margin-bottom: 2px; }
.auth-card h1 { font-size: 1.875rem; line-height: 1.2; font-weight: 700; letter-spacing: -.02em; color: var(--heading); }
.auth-card .desc { color: var(--muted); font-size: 0.9375rem; margin-top: 8px; }
.auth-card .input, .auth-card .select { background-color: var(--surface); }
/* Ohne eigene Farbe sah ein Beispiel im Feld aus wie ein schon eingetragener
   Wert — in der ganzen Anwendung, nicht nur hier. Ohne Deckkraft
   (seit 04.10.2026): mit .6 waren es 2,54:1, --muted allein hat 5,87:1. */
.input::placeholder, .textarea::placeholder { color: var(--muted); opacity: 1; }
/* Feld → Knopf überall 24 px (16 vom Feld + 8), auch wo der Passwortschritt
   dazwischen noch verborgen ist. Die allgemeine Regel gäbe hier 36. */
.auth-card form > .btn-block { margin-top: 8px; }
.auth-foot { margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--auth-bild-strich);
             font-size: 0.875rem; display: flex; justify-content: space-between; gap: 12px; }
.auth-card.center .auth-foot { justify-content: center; }
/* Das Zeichen über einer Bestätigung: Strichzeichnung im getönten Kreis,
   wie im Rest der Anwendung — keine Emoji, die je nach System anders aussehen. */
.auth-zeichen {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; margin-bottom: 18px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
}
.auth-zeichen svg { width: 26px; height: 26px; }
.auth-zeichen.success { background: var(--success-bg); color: var(--success-fg); }
.auth-zeichen.warning { background: var(--warning-bg); color: var(--warning-fg); }
.auth-adresse { background: var(--surface); border: 1px solid var(--auth-bild-strich); padding: 9px 12px; border-radius: var(--radius-sm); }
.auth-foot-rechts { margin-left: auto; }

/*
  Der Umschalter «Microsoft 365 | E-Mail».

  Zwei Radioknöpfe VOR den Beschriftungen und den beiden Wegen, alle als
  Geschwister — nur so erreicht `:checked ~` beide ohne `:has()`. Die
  Knöpfe sind unsichtbar, aber fokussierbar: Pfeiltasten wechseln den
  Weg, und der Fokusring erscheint an der Beschriftung.
*/
.auth-weg-wahl { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.auth-weg {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
  margin-top: 26px; padding: 4px; border-radius: var(--radius-sm);
  background: var(--auth-bild-grund);
  border: 1px solid var(--auth-bild-strich);
}
.auth-weg label {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 40px; padding: 8px 12px; border-radius: 6px;
  font-size: 0.875rem; font-weight: 500; color: var(--muted); cursor: pointer;
}
.auth-weg label:hover { color: var(--text); }
#weg-ms:checked   ~ .auth-weg label[for="weg-ms"],
#weg-mail:checked ~ .auth-weg label[for="weg-mail"] {
  background: var(--surface); color: var(--text); box-shadow: var(--shadow);
}
#weg-ms:focus-visible   ~ .auth-weg label[for="weg-ms"],
#weg-mail:focus-visible ~ .auth-weg label[for="weg-mail"] {
  outline: 2px solid var(--focus); outline-offset: 2px;
}
#weg-ms:checked   ~ .auth-weg-mail,
#weg-mail:checked ~ .auth-weg-ms,
#weg-ms:checked   ~ .auth-nur-mail,
#weg-ms:checked   ~ .auth-foot .auth-nur-mail { display: none; }

.auth-hinweis { margin: 18px 0 16px; font-size: 0.875rem; line-height: 1.55; color: var(--muted); }

/* Der Weg zu Microsoft als Zeile: Zeichen, Wort, Pfeil — wie ein Eintrag,
   den man antippt, nicht wie ein zweiter Hauptknopf. */
.btn-weg { justify-content: flex-start; min-height: 48px; padding-left: 18px; padding-right: 16px; }
.btn-weg .btn-weg-pfeil { margin-left: auto; color: var(--accent); }

/*
  Das Karussell der Anmeldeseite.

  Fünf Ausschnitte der Anwendung (1520 × 950, aus scripts/abbildungen.php)
  als Stapel: die aktuelle Karte vorne, zwei angedeutete dahinter — man
  sieht, dass mehr kommt. Darunter Titel und Satz zur Folge, darunter die
  Striche, von denen sich der aktuelle füllt.

  Ein Takt: 5 Folgen × 6 s = 30 s. Alle laufen dieselbe Animation, um
  i × 6 s versetzt; die erste beginnt schon sichtbar (negativer Versatz).
  Mit der Maus darüber hält alles an — wer liest, soll nicht gehetzt werden.
*/
.auth-bild {
  display: none; position: relative; flex: 0 0 auto;
  width: clamp(360px, calc(100vw - 360px - 64px - 400px - 72px - 48px), 620px);
  --takt: 30s; --folge: 6s;
}
.auth-stapel { position: relative; }
/* Die beiden Karten dahinter. */
.auth-stapel::before,
.auth-stapel::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; bottom: 0;
  border-radius: 16px; background: var(--surface); border: 1px solid var(--auth-bild-strich);
}
.auth-stapel::before { transform: translateY(16px) scale(.94); opacity: .8; z-index: -1; box-shadow: var(--shadow); }
.auth-stapel::after  { transform: translateY(32px) scale(.88); opacity: .5; z-index: -2; }

.auth-bilder {
  position: relative; aspect-ratio: 1520 / 950; overflow: hidden;
  border-radius: 16px; background: var(--auth-flaeche);
  border: 1px solid var(--auth-bild-strich); box-shadow: var(--bild-schatten);
}
.auth-bilder img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
/* Der Ausschnitt ist rechts und unten angeschnitten; ein weicher Rand in
   der Farbe der Anwendung macht daraus Absicht statt Schnittkante. */
/* Im dunklen Bild kein Verlauf: die Ausschnitte bleiben hell, und ein
   Rand in die dunkle Fläche sähe aus wie ein Schatten (`--nur-hell`). */
.auth-bilder::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; display: var(--nur-hell);
  background:
    linear-gradient(to right, transparent 86%, var(--auth-flaeche)),
    linear-gradient(to bottom, transparent 84%, var(--auth-flaeche));
}

.auth-texte { position: relative; height: 64px; margin-top: 44px; }
.auth-text { position: absolute; inset: 0; margin: 0; text-align: center; }
.auth-text strong { display: block; font-size: 1.0625rem; font-weight: 600; color: var(--heading); letter-spacing: -.01em; }
.auth-text span { display: block; margin-top: 4px; font-size: 0.875rem; line-height: 1.45; color: var(--muted); }

.auth-folge {
  opacity: 0;
  animation: auth-folge var(--takt) cubic-bezier(.4, 0, .2, 1) infinite;
  animation-delay: calc(var(--i) * var(--folge) - .6s);
}
/* 0–3 %: herein (≈ 0,9 s), bis 18 %: stehen, 21 %: hinaus. Bild und Satz
   gleiten dabei ein Stück — sie kommen von rechts und gehen nach links. */
@keyframes auth-folge {
  0%   { opacity: 0; transform: translateX(18px); }
  3%   { opacity: 1; transform: translateX(0); }
  18%  { opacity: 1; transform: translateX(0); }
  21%  { opacity: 0; transform: translateX(-18px); }
  100% { opacity: 0; transform: translateX(-18px); }
}

.auth-punkte { display: flex; justify-content: center; gap: 8px; margin-top: 14px; }
.auth-punkte i {
  position: relative; width: 28px; height: 3px; overflow: hidden;
  border-radius: 2px; background: var(--auth-bild-strich);
}
.auth-fuell {
  position: absolute; inset: 0; background: var(--accent);
  transform: scaleX(0); transform-origin: left center;
  animation: auth-fuell var(--takt) linear infinite;
  animation-delay: calc(var(--i) * var(--folge) - .6s);
}
@keyframes auth-fuell {
  0%     { transform: scaleX(0); opacity: 1; }
  20%    { transform: scaleX(1); opacity: 1; }
  21%    { transform: scaleX(1); opacity: 0; }
  100%   { transform: scaleX(0); opacity: 0; }
}
.auth-bild:hover .auth-folge,
.auth-bild:hover .auth-fuell,
.bewegung-aus .auth-folge,
.bewegung-aus .auth-fuell { animation-play-state: paused; }

/*
  Anhalten von Hand (seit 04.10.2026) — Anmeldeseite und Aufmacher der
  Startseite. `aria-pressed` schaltet das Zeichen: zwei Striche heisst
  «anhalten», das Dreieck «weiter». Gezeichnet mit Rändern statt mit
  Schriftzeichen, damit nichts vorgelesen wird als der Name.
*/
.bewegung-knopf {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  border: 1px solid var(--field-border); border-radius: 999px;
  background: var(--surface); color: var(--heading); cursor: pointer;
}
.bewegung-knopf:hover { border-color: var(--field-border-hover); }
.bewegung-knopf::before {
  content: ""; box-sizing: border-box; width: 10px; height: 12px;
  border-left: 3px solid currentColor; border-right: 3px solid currentColor;
}
.bewegung-knopf[aria-pressed="true"]::before {
  width: 0; height: 0; margin-left: 3px;
  border-left: 10px solid currentColor; border-right: 0;
  border-top: 6px solid transparent; border-bottom: 6px solid transparent;
}
.auth-bild .bewegung-knopf { display: flex; margin: 12px auto 0; }
.hero-dark .bewegung-knopf {
  position: absolute; right: 16px; bottom: 16px; z-index: 1;
  background: var(--ink-card); border-color: var(--on-ink-muted); color: var(--on-ink);
}

/* Weniger Bewegung gewünscht: die erste Folge, stehend. */
@media (prefers-reduced-motion: reduce) {
  .auth-folge, .auth-fuell { animation: none; }
  .auth-folge[style*="--i: 0"] { opacity: 1; }
  .auth-punkte { display: none; }
  /* Es bewegt sich nichts — dann gibt es auch nichts anzuhalten. */
  .auth-bild .bewegung-knopf { display: none; }
}
/* Im dunklen Modus bleiben die Ausschnitte hell — ein Rand in die dunkle
   Fläche sähe aus wie ein Schatten. */
.auth-welle {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 0;
  width: 100%; height: 160px; fill: var(--auth-welle); pointer-events: none;
}
.auth-fuss-klein { display: none; }

@media (min-width: 1280px) {
  .auth-bild { display: block; }
}

@media (max-width: 1023px) {
  .auth-seite { display: none; }
  .auth-kopf {
    justify-content: space-between; min-height: 0; padding: 14px 20px;
    background: var(--surface); border-bottom: 1px solid var(--border);
  }
  .auth-kopf-marke { display: block; }
  .auth-kopf-marke .brand-lockup { height: 28px; }
  .auth-inhalt { align-items: flex-start; padding: 36px 20px 150px; }
  .auth-welle { height: 110px; }
  .auth-fuss-klein {
    display: block; position: absolute; left: 0; right: 0; bottom: 18px; z-index: 1;
    text-align: center; font-size: 0.75rem; color: var(--muted);
  }
}
@media (max-width: 480px) {
  .auth-card h1 { font-size: 1.625rem; }
}
/*
  Herausgeberzeile — dezent, auf jeder Seite der Anwendung und der
  Anmeldung. Die Anwendung heisst «Inventaris» (Wortmarke im Kopf, Name
  im Manifest); wer sie herausgibt, steht hier. Muted und klein: ein
  Vermerk, keine Anzeige.
*/
.betreiber-fuss {
  flex: 0 0 auto; margin-top: 8px;
  display: flex; justify-content: center;
  padding: 18px 0;
  font-size: 0.75rem; color: var(--muted);
}
/* Kurze Seiten: der Inhalt wächst, damit die Herausgeberzeile unten am
   Fenster steht und nicht mitten im Bild hinter dem letzten Kasten. */
.content { display: flex; flex-direction: column; }
/* Hinter den Kacheln der Ton der Anmeldeseite, die Kacheln selbst bleiben
   weiss (--surface). Nur in der Anwendung, das Backoffice bleibt, wie es ist. */
body:not(.ist-backoffice) .content { background: var(--auth-flaeche); }
.content > .inner { flex: 1 0 auto; width: 100%; box-sizing: border-box; }

/* Anwendungsrahmen */
/*
  `dvh` und nicht `vh`.

  Auf iPad und iPhone meint `100vh` den *grossen* Bildschirm — den, der
  gaelte, wenn die Leisten des Browsers eingefahren waeren. Sie sind es
  aber meistens nicht. Die Seitenleiste wird damit hoeher als das, was
  man sieht, und ihr Fussbereich mit Person und Organisation rutscht
  unter den unteren Rand, ohne dass man ihn erreichen kann: sie klebt
  ja, also scrollt sie nicht mit.

  `dvh` meint den Bildschirm, der gerade da ist. `vh` bleibt als
  Rueckfall fuer Browser davor stehen — wer beide kennt, nimmt den
  zweiten.
*/
/*
  Zwei Laufflaechen statt einer.

  Bisher scrollte das Dokument als Ganzes, und die Seitenleiste klebte
  dabei fest. Das sieht fast richtig aus und ist es nicht: wer im Menue
  nach unten will, bewegt in Wahrheit die Seite daneben, und auf dem
  iPad kommt der Gummiband-Effekt dazu — man zieht am Menue und die
  Arbeitsflaeche wandert.

  Jetzt hat jede Seite ihren eigenen Lauf. Das Dokument selbst scrollt
  nicht mehr; `.shell` ist genau bildschirmhoch und haelt zwei
  Bereiche, die einander nichts angehen.

  `dvh` und nicht `vh`: auf iPad und iPhone meint `100vh` den Bildschirm,
  der gaelte, wenn die Leisten des Browsers eingefahren waeren. Sie sind
  es meistens nicht, und die Leiste waere dann hoeher als das Sichtbare.
  `vh` bleibt als Rueckfall fuer Browser davor stehen.

  Gemeldet am 22.09.2026: «das Menü und die Seite rechts müssten separat
  scrollen».
*/
.shell {
  display: flex;
  /*
    Fest an allen vier Rändern statt `height: 100dvh` (seit 11.10.2026).
    Manche Browser rechnen `dvh` kleiner als das Fenster — mit Seitenzoom,
    als installierte Web-App oder nach einer Grössenänderung —, und die
    ganze Anwendung endete achtzig Pixel über dem Rand, darunter eine
    leere Fläche (gemeldet mit Bildschirmfoto, auf allen Seiten).
    `inset` misst nichts aus, es heftet an. Die seitlichen Einzüge
    ersetzen das `padding` am Körper, das ein fester Kasten nicht sieht.
  */
  position: fixed;
  inset: 0 env(safe-area-inset-right) 0 env(safe-area-inset-left);
  overflow: hidden;
  /*
    `clip`, nicht nur `hidden`: ein Kasten mit `hidden` schneidet ab, ist
    aber weiter verschiebbar. Ein Sprung zu einem Anker (`#liste` nach dem
    Speichern in der Akquise), den der Inhaltsbereich nicht ganz nach oben
    bringt, schob den Rest über `.shell` nach — die ganze Seite rutschte
    im Rahmen hoch, oben ein weisser Streifen, die Marke abgeschnitten.
    `clip` lässt sich nicht verschieben. `hidden` bleibt als Rückfall.
  */
  overflow: clip;
}
/*
  Kein Nachfedern des ganzen Fensters (seit 11.10.2026).

  Das Dokument scrollt in der Anwendung nicht — `.shell` ist genau
  fensterhoch. Auf dem Mac federt Chrome es trotzdem, sobald man über
  das Ende hinaus wischt, etwa mit dem Zeiger über dem Fuss der
  Seitenleiste: die ganze Anwendung rutscht hoch, darunter ein weisser
  Streifen (gemeldet mit Bildschirmfoto). Die inneren Laufflächen fangen
  ihren Schwung schon selbst ab (`overscroll-behavior: contain`).
*/
@media (min-width: 1025px) {
  /* Nur wo `.shell` fest steht; darunter scrollt das Dokument selbst,
     und dort gehört das Nachfedern zum Browser (seit 11.10.2026). */
  html:has(body > .shell),
  html:has(body > .shell) body { overscroll-behavior: none; }
}
html:has(body > .shell) { background: var(--auth-flaeche); }
/* Gedruckt fliesst die Seite: ein fester Rahmen druckte nur die erste. */
@media print { .shell { display: block; position: static; inset: auto; height: auto; overflow: visible; } }
.sidebar {
  width: 272px; flex-shrink: 0; background: var(--rail);
  border-right: 1px solid var(--border); padding: 22px 0 10px;
  display: flex; flex-direction: column;
  height: 100%; min-height: 0;
  /*
    Ueberlaufen wird hier nicht: das Menue in der Mitte laeuft fuer
    sich (`.sidebar nav`), Marke oben und Fussbereich unten bleiben
    stehen. Wer sonst wohin will, erreicht beide immer.
  */
  overflow: hidden;
}
/*
  Eine einzige linke Kante: Marke, Organisation, Symbole und Fussbereich
  beginnen alle bei 24 px. Das Menue selbst sitzt um --rail-pad eingerueckt,
  der Menuepunkt noch einmal um 10 px — zusammen wieder 24 px.
*/
/* Die Marke steht in einem eigenen Block mit Luft nach allen Seiten.
   Die Linie darunter trennt sie vom Menue — vorher tat das der Name der
   Organisation, der jetzt unten bei der Person steht. */
.rail-brand {
  padding: 4px 24px 20px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.sidebar .brand,
.sidebar .brand-lockup { padding: 0; font-size: 1rem; }
.sidebar .brand-lockup { height: 32px; }
/* In der Kopfzeile für Tablet und Telefon steht das Logo etwas kleiner —
   daneben muss der Menüknopf mit 44 px Höhe noch Platz haben. */
.app-topbar .brand-lockup { height: 30px; }
/*
  `min-height: 0` ist hier nicht Zierrat.

  Ein Flex-Kind schrumpft von sich aus nicht unter die Hoehe seines
  Inhalts. Ohne diese Zeile waere das Menue so hoch wie seine Eintraege,
  der eigene Lauf griffe nie, und der Fussbereich mit Person und
  Organisation wuerde unten hinausgedrueckt.
*/
.sidebar nav {
  flex: 1; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 16px var(--rail-pad);
}

.sidebar .foot { border-top: 1px solid var(--border); padding: 12px 12px 6px; flex-shrink: 0; }
/*
  Streifen zur Testphase, quer über der Arbeitsfläche.

  Er steht im Fluss, nicht klebend: eine dauerhaft klebende Leiste würde auf
  jedem Bildschirm Höhe kosten, und der Hinweis ist wichtig, aber nicht
  dringend. Der Ton wird mit der Zeit dringlicher — ruhiges Indigo, ab einer
  Woche eine Warnung, nach Ablauf ein Fehler.
*/
.trial-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
  padding: 10px 28px;
  border-bottom: 1px solid var(--info-bd);
  background: var(--info-bg); color: var(--info-fg);
  font-size: 0.875rem;
}
.trial-bar p { display: flex; align-items: center; gap: 9px; min-width: 0; }
.trial-bar svg { width: 17px; height: 17px; flex: 0 0 17px; }
/* Ohne Deckkraft (seit 04.10.2026): mit .75 fiel der Nachsatz in den
   Zuständen «bald» und «abgelaufen» unter 4,5:1 — und gerade dort trägt
   er die Folge. Abgestuft wird über das Gewicht. */
.trial-bar .trial-hint { color: inherit; font-weight: 400; }
.trial-bar .btn { flex-shrink: 0; }

.trial-bar.is-soon { background: var(--warning-bg); color: var(--warning-fg); border-bottom-color: var(--warning-bd); }
.trial-bar.is-over { background: var(--danger-bg);  color: var(--danger-fg);  border-bottom-color: var(--danger-bd); }

@media (max-width: 720px) {
  .trial-bar { padding: 10px 16px; gap: 10px; }
  /* Am Telefon zählt die Zahl, nicht die Erläuterung. */
  .trial-bar .trial-hint { display: none; }
  .trial-bar .btn { height: 44px; padding: 0 16px; }
}
@media (max-width: 420px) {
  .trial-bar { padding: 10px 12px; }
  .trial-bar .btn { width: 100%; }
}

/* ---------------------------------------------------------------------------
   Das Menue — gemeinsam fuer die feste Seitenleiste und das Klappmenue.

   Vorher war es eine graue Textliste: alle dreizehn Ziele in --muted, also
   alle gleich weit weg. Jetzt tragen drei Stufen die Hierarchie —
   Gruppentitel schwach, Ziele normal, aktives Ziel blau — und jedes Ziel hat
   ein Symbol, an dem man es erkennt, statt es lesen zu muessen.
   --------------------------------------------------------------------------- */

.group + .group { margin-top: 18px; }
.group-title {
  padding: 0 10px 6px; font-size: 0.6875rem; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
}

.nav-item {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 10px; border-radius: var(--radius-sm);
  font-size: 0.875rem; color: var(--nav-fg);
  transition: background-color .12s, color .12s;
}
/* Hover und aktiver Punkt aus derselben Tonfamilie wie der Grund der
   Anwendung (--auth-flaeche) und die Welle (--auth-welle) — vorher ein
   eigenes, kräftigeres Blau, das neben dem Grund fremd wirkte. */
.nav-item:hover { background: var(--auth-flaeche); color: var(--text); text-decoration: none; }
.nav-item[aria-current="page"] {
  background: var(--auth-welle); color: var(--accent-soft-text); font-weight: 500;
  box-shadow: inset 3px 0 0 var(--accent);
}

/* Ohne feste Groesse waeren die Zeichnungen wegen width="1em" nur 14 px
   gross und wuerden im Flexcontainer zusammengedrueckt. */
.nav-item svg { width: 18px; height: 18px; flex: 0 0 18px; opacity: .7; }
.nav-item[aria-current="page"] svg, .nav-item:hover svg { opacity: 1; }
.nav-item .nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Die Zahl ist Arbeitsvorrat, kein Alarm — nur Ueberfaelliges wird rot. */
.nav-item .count {
  margin-left: auto; flex-shrink: 0;
  background: var(--surface-muted); color: var(--muted);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 0 7px; font-size: 0.6875rem; font-weight: 600;
  font-variant-numeric: tabular-nums; line-height: 18px;
}
.nav-item .count.is-danger {
  background: var(--danger-bg); color: var(--danger-fg); border-color: var(--danger-bd);
}

/*
  Fussbereich: wer angemeldet ist, und der Weg hinaus.

  Eine Zeile — Gesicht, Name, Organisation, ganz rechts das Abmelden.
  Vorher standen Name und Abmelden untereinander; das Abmelden nahm damit
  eine ganze Zeile fuer die Handlung ein, die man am seltensten braucht,
  und stand ausgerechnet an der Stelle, an der man am ehesten hinsieht.
*/
.nav-foot { display: flex; align-items: center; gap: 4px; }

.nav-who {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px; border-radius: var(--radius-sm);
  color: var(--text);
}
.nav-who:hover { background: var(--surface-muted); text-decoration: none; }
/* Das Gesicht kommt aus demselben Bauteil wie in den Listen; hier nur der
   feste Platz und der kraeftigere Ton, damit die Initialen auf dem ruhigen
   Grund der Seitenleiste nicht verschwinden. */
.nav-who .avatar-img { flex: 0 0 38px; }
.nav-who .avatar-img.is-initials {
  background: var(--indigo-100); color: var(--heading); font-weight: 700;
}
.nav-who-text { min-width: 0; }
.nav-who .n { display: block; font-size: 0.875rem; font-weight: 600; line-height: 1.35;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-who .r { display: block; font-size: 0.7812rem; color: var(--muted); line-height: 1.3;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Nur das Zeichen. Beschriftet ueber aria-label und title — sichtbar
   beschriftet waere es wieder eine ganze Zeile. */
.nav-signout {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 34px; height: 34px;
  padding: 0; border: 0; border-radius: 50%;
  background: none; color: var(--muted);
  cursor: pointer;
}
.nav-signout:hover { background: var(--surface-muted); color: var(--text); }
.nav-signout svg { width: 19px; height: 19px; opacity: .75; }


/*
  Die Sprachwahl auf der Profilseite.

  Wahlfelder untereinander und nicht als Ausklappliste: es sind wenige,
  und eine Liste, die man erst öffnen muss, verbirgt, dass es überhaupt
  eine Wahl gibt. Die ganze Zeile ist anklickbar — ein Punkt von zwölf
  Pixeln ist auf einem Telefon kein Ziel.
*/
.sprache-wahl { display: flex; flex-direction: column; gap: 2px; margin-top: 14px; }
.sprache-wahl-feld {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 12px; border-radius: var(--radius-sm); cursor: pointer;
}
.sprache-wahl-feld:hover { background: var(--surface-muted); }
.sprache-wahl-feld input { margin-top: 3px; flex: 0 0 auto; }
.sprache-wahl-feld .n { display: block; font-size: 0.875rem; font-weight: 500; }
.sprache-wahl .btn { align-self: flex-start; margin-top: 12px; }

/* Die Trennlinie steht vor „Verwaltung“ — aber nur, wenn es ueberhaupt
   mehr als eine Gruppe gibt. Ausleiher sehen sonst einen Strich ueber dem
   ersten Menuepunkt. */
.sidebar .group + .group:last-child {
  margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--border);
}

.content {
  flex: 1; min-width: 0; min-height: 0;
  overflow-y: auto;
  /* Platz für die Bildlaufleiste immer frei halten (16.10.2026): sonst rückt
     der ganze Inhalt zur Seite, sobald eine Seite länger ist als die vorige. */
  scrollbar-gutter: stable;
  /*
    Bezugsrahmen für alles, was darin absolut steht — etwa die
    unsichtbaren Beschriftungen `.sr-only` der Suchleiste. Ohne ihn hingen
    sie am Dokument, an ihrer Stelle weit unten im Inhalt, und machten das
    Dokument höher als das Fenster. Ein Sprung zu einem Anker (`#liste`)
    scrollte dann das Dokument mit, und die ganze Seite rutschte im
    Rahmen nach oben.
  */
  position: relative;
  /*
    Ein Wisch, der am Ende der Liste ankommt, soll nicht die Flaeche
    dahinter weiterschieben — auf iOS ist genau das der Ruck, den man
    fuer einen Fehler haelt.
  */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.content .inner { max-width: 1180px; margin: 0 auto; padding: 28px 28px 64px; }

/* Die Regeln für Tablet und Telefon stehen gesammelt in Abschnitt 6. */

/* Backoffice */
/*
  Dieselbe Seitenleiste wie die Anwendung (.shell, .sidebar, .nav-item);
  hier nur, was das Backoffice mehr hat: den Vermerk neben der Marke und
  das Untermenü unter «Plattform».
*/
.admin-marke {
  display: inline-block; margin-left: 10px; padding: 2px 8px; border-radius: 999px;
  vertical-align: middle; font-size: 0.7188rem; font-weight: 600; letter-spacing: .02em;
  background: var(--accent-soft); color: var(--accent-soft-text);
}
.admin-kopfmarke { display: flex; align-items: center; }
.rail-brand .admin-marke { display: table; margin: 8px 0 0; }

.nav-sub { margin: 2px 0 6px 29px; padding-left: 12px; border-left: 1px solid var(--border); }
.nav-sub a {
  display: block; padding: 5px 10px; border-radius: 6px;
  font-size: 0.8438rem; color: var(--muted);
}
.nav-sub a:hover { background: var(--surface-muted); color: var(--text); text-decoration: none; }
.nav-sub a[aria-current="page"] { color: var(--accent-soft-text); font-weight: 600; }

/* Ein Bereich der Einstellungen: Formular links, Anleitung rechts. */
.einstellungen-bereich {
  display: grid; grid-template-columns: minmax(0, 720px) minmax(0, 1fr);
  gap: 20px; align-items: start;
}
@media (max-width: 1180px) { .einstellungen-bereich { grid-template-columns: minmax(0, 1fr); } }

/* Ein Formular allein in einem Reiter: nicht über die ganze Breite ziehen. */
.ist-backoffice .schmal { max-width: 760px; }

/* Sprungziele des Untermenüs nicht unter den oberen Rand schieben. */
.ist-backoffice [id] { scroll-margin-top: 24px; }
.admin-login { min-height: 100vh; background: var(--indigo-900); display: grid; place-items: center; padding: 24px; }
.admin-login .box { width: 100%; max-width: 380px; }
.admin-login .box > .card { margin-bottom: 0; }
.admin-login .admin-mark { display: inline-block; width: 44px; height: 44px; }
.admin-login h1 { color: #fff; font-size: 1.25rem; font-weight: 600; text-align: center; margin-top: 16px; }
.admin-login .sub { color: var(--indigo-on-dark); font-size: 0.875rem; text-align: center;
                    margin-top: 4px; margin-bottom: 24px; }

/* Fehlerseite */
/*
  DIE SCHMALE FASSUNG — DER AUSWEICHWEG.

  Sie greift nur noch, wenn die Fehlerseite im Gewand der Webseite
  SELBST scheitert (`View::renderError()` faengt das). Sie braucht
  darum nichts als eine Mitte und Text.
*/
.error-page { min-height: 100vh; display: grid; place-items: center; padding: 24px; text-align: center; }
.error-page .code { font-size: 3.5rem; font-weight: 600; color: var(--muted); letter-spacing: -.03em; }
.error-page h1 { font-size: 1.375rem; font-weight: 600; margin-top: 8px; }
.error-page p { color: var(--muted); margin-top: 8px; max-width: 34em; }

/*
  DIE FEHLERSEITE IM GEWAND DER WEBSEITE.

  Die Zahl steht gross, aber still: sie ist die Erklaerung und nicht die
  Nachricht. Wer «404» liest, weiss es schon; wer es nicht weiss, liest
  die Ueberschrift. Darum `--border` als Farbe und nicht `--text` — ein
  dreistelliges Schwarz auf halber Seitenhoehe schreit, und es gibt
  nichts zu schreien.

  Kein `min-height: 100vh` mehr: die Seite hat jetzt Kopf und Fuss, und
  eine volle Bildschirmhoehe dazwischen schiebt beides aus dem Bild.
*/
.fehler-seite { padding-block: 72px 88px; text-align: center; }
.fehler-nr {
  font-size: clamp(4.5rem, 16vw, 8.25rem); font-weight: 700; line-height: .9;
  letter-spacing: -.04em; color: var(--border);
  font-variant-numeric: tabular-nums;
}
.fehler-seite h1 {
  font-size: clamp(1.625rem, 4vw, 2.125rem); font-weight: 650; margin-top: 8px;
  text-wrap: balance;
}
.fehler-seite .lead {
  color: var(--muted); margin: 12px auto 0; max-width: 34em; font-size: 1.0625rem;
}
.fehler-uber {
  margin-top: 44px; font-size: 0.8125rem; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
}

/*
  Die vier Wege: dasselbe Muster wie im Klappmenue des Kopfes —
  Zeichen, Name, ein Satz. Wer die Seite von dort kennt, erkennt es
  wieder. Zwei Spalten, weil vier Kacheln in einer Reihe auf einem
  Notebook je zweihundert Pixel breit waeren und der Satz darunter
  dreimal umbrechen muesste.
*/
.fehler-wege {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px; margin: 16px auto 0; max-width: 680px; text-align: left;
}
.fehler-wege > a {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 16px 18px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); text-decoration: none; color: inherit;
  transition: border-color .12s, background-color .12s;
}
.fehler-wege > a:hover { border-color: var(--brand-600); background: var(--surface-muted); }
.fehler-wege svg { width: 20px; height: 20px; flex: none; margin-top: 1px; color: var(--brand-600); }
.fehler-wege .weg-name { display: block; font-weight: 600; }
.fehler-wege .weg-text { display: block; margin-top: 2px; font-size: 0.8125rem; color: var(--muted); }
.fehler-knopf {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: center;
  margin-top: 36px;
}
@media (max-width: 620px) {
  .fehler-seite   { padding-block: 48px 64px; }
  .fehler-wege    { grid-template-columns: minmax(0, 1fr); }
}

/* Scan-Bereich */

/*
  Eine Scanzeile: breites Feld, Knopf gleicher Höhe daneben.

  Die alte Fassung liess den Knopf seine natürliche Breite behalten und in
  der Höhe abweichen — neben einem `input-lg` sah er aus, als wäre er
  hineingerutscht. Jetzt bestimmt das Raster beide: das Feld nimmt den
  Platz, der Knopf so viel wie seine Beschriftung braucht, und beide sind
  gleich hoch.
*/
.scan-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: stretch;
}
.scan-row > .btn { white-space: nowrap; }
.scan-row > .btn svg { width: 17px; height: 17px; }
@media (max-width: 560px) {
  .scan-row { grid-template-columns: minmax(0, 1fr); }
}

/*
  Kamerasymbol neben dem Scanfeld. Es wird von app.js eingesetzt und nur
  dort, wo der Browser Barcodes erkennen kann — deshalb die eigene
  Rasterspalte, die erst mit `.has-cam` entsteht.
*/
.scan-row.has-cam { grid-template-columns: minmax(0, 1fr) auto auto; }
@media (max-width: 560px) {
  .scan-row.has-cam { grid-template-columns: minmax(0, 1fr) auto; }
  /* Der Absendeknopf rückt unter das Feld, das Kamerasymbol bleibt daneben:
     auf dem Telefon ist die Kamera der übliche Weg. */
  .scan-row.has-cam > .btn:not(.scan-cam) { grid-column: 1 / -1; }
}
.scan-cam { padding: 0 14px; }

/* Scanzeile ohne Absendeknopf — etwa in den Vorgangsformularen, wo nach dem
   Scannen weitergeschrieben wird. */
.scan-row:not(.has-cam) { grid-template-columns: minmax(0, 1fr) auto; }
.scan-row > .scan-hint-slot { display: none; }

/*
  Der Sucher.

  Grosses Bild, ein Rahmen als Zielhilfe — mehr braucht es nicht. Der
  Rahmen ist bewusst nur eine Andeutung: die Erkennung liest das ganze
  Bild, nicht nur den Ausschnitt, und ein Rahmen, der etwas verspricht, was
  er nicht hält, führt zu Ärger.
*/
.scanner-dialog { width: min(520px, calc(100vw - 24px)); }
.scanner-stage {
  position: relative; background: #000;
  border-radius: var(--radius) var(--radius) 0 0; overflow: hidden;
  aspect-ratio: 4 / 3;
}
.scanner-stage video { width: 100%; height: 100%; object-fit: cover; display: block; }
.scanner-frame {
  position: absolute; inset: 18% 12%;
  border: 3px solid rgba(255, 255, 255, .9);
  border-radius: 10px;
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .35);
}
.scanner-hint { padding: 14px 20px; font-size: 0.875rem; color: var(--muted); text-align: center; }
.scanner-hint.is-error { color: var(--danger-fg); }

/* Ältere Fassung, noch von der Inventarkontrolle benutzt. */
.scan-form { display: flex; gap: 10px; }
.scan-form .input { flex: 1; }

/*
  Nummerierter Schritt in einer Überschrift. Die drei Schritte der neuen
  Ausleihe sind eine Reihenfolge, keine Sammlung von Karten — die Ziffer
  sagt das, ohne dass es jemand erklären muss.
*/
.step-nr {
  display: inline-grid; place-items: center;
  width: 22px; height: 22px; margin-right: 8px;
  border-radius: 50%;
  background: var(--accent); color: var(--on-accent);
  font-size: 0.75rem; font-weight: 700; vertical-align: 1px;
}

/* Der gefundene Ausleiher: Nummer, Angaben, Wechselknopf. */
/*
  Die Karte des erkannten Ausleihers.

  Sie ist der bestaetigte Zustand von Schritt 1 und darf das zeigen: ein
  ruhig getoenter Grund sagt «erledigt», ohne dass ein Haken noetig waere.
  Der Rest der Seite bleibt weiss, damit der Unterschied traegt.
*/
.borrower-card {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  background: var(--info-bg);
  border-top: 1px solid var(--info-bd);
}

/*
  Das Bild des Ausleihers.

  Es sass hier vorher als Nummernkachel — dieselbe Stelle, andere
  Auskunft. 64 Pixel sind gross genug, um am Schalter ein Gesicht zu
  erkennen, und klein genug, dass die Karte eine Zeile bleibt.
*/
.borrower-bild { flex: 0 0 auto; display: block; line-height: 0; border-radius: 50%; }
.borrower-bild:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
.borrower-card > .avatar-img,
.borrower-card > .borrower-bild { flex: 0 0 auto; }

/* Ein heller Ring hebt das Bild vom getoenten Grund ab, ohne einen Rahmen
   zu ziehen: zwei Schatten statt einer Linie, damit der Kreis rund bleibt. */
.borrower-card .avatar-img {
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 4px var(--info-bd);
}

.borrower-body { flex: 1; min-width: 200px; }
.borrower-name {
  font-size: 1.1875rem; font-weight: 600; color: var(--heading);
  line-height: 1.25; letter-spacing: -.01em;
}

/* Nummer und Zugehoerigkeit, eine Zeile darunter. */
.borrower-zeile {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 5px; font-size: 0.8125rem;
}

/* Telefon und E-Mail als das, was sie sind: anklickbar. */
.borrower-kontakt {
  display: flex; gap: 6px 16px; flex-wrap: wrap;
  margin-top: 4px; font-size: 0.8125rem;
}
.borrower-kontakt a { color: var(--accent-text); text-decoration: none; }
.borrower-kontakt a:hover { text-decoration: underline; }

/*
  Die gescannte Nummer, jetzt als Kürzel neben dem Namen.

  Sie bleibt einstellig lesbar — Schreibmaschinenschrift, damit 0 und O
  sich nicht gleichen — und tritt in der Grösse zurück. Sie beantwortet
  nur noch eine Frage: ging der richtige Ausweis über den Scanner?
*/
.borrower-id {
  padding: 3px 9px; border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--accent-soft-text);
  font: 600 0.75rem/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .04em; white-space: nowrap;
}

/*
  Ein Gegenstand als Zeile — im Korb, im Formular, in einer Tabelle.

  Es gibt EINE Zeile fuer einen Gegenstand, und sie steht hier. Vorher gab
  es zwei fast gleiche Regelsaetze (.korb-* und .sach-*); zwei Fassungen
  derselben Sache laufen auseinander, sobald jemand eine davon anfasst.

  Das Bild traegt seine Kantenlaenge am Element, nicht in dieser Datei: im
  Korb 56 Pixel, in einer Tabellenzeile 40. Eingepasst wird das Motiv und
  nicht beschnitten — ein Beamer, dem die Haelfte fehlt, hilft beim
  Wiedererkennen nicht.
*/
.sach-bild {
  flex: 0 0 auto;
  border-radius: var(--radius-sm);
  object-fit: contain;
  background: var(--surface-muted);
  border: 1px solid var(--border);
}
.sach-bild.is-leer {
  display: grid; place-items: center;
  color: var(--muted); opacity: .55;
}
/* Das Zeichen waechst mit der Flaeche, sonst steht es im Korb verloren. */
.sach-bild.is-leer svg { width: 18px; height: 18px; }
.korb-zeile .sach-bild.is-leer svg { width: 22px; height: 22px; }

.sach-text { flex: 1; min-width: 0; }
.sach-nummer {
  font: 600 0.9375rem/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .02em; color: var(--heading);
}
.sach-serie {
  display: block; margin-top: 2px;
  font-size: 0.75rem; color: var(--muted);
}

/*
  Der Korb: eine Zeile je Gegenstand, untereinander.

  Feste Hoehe fuer das Bild, damit alle Zeilen gleich hoch beginnen und die
  Nummern untereinander stehen. Ein Raster waere huebscher und hier falsch:
  am Schalter zaehlt man ab, und zaehlen tut man in einer Spalte.
*/
.korb { list-style: none; margin: 0; padding: 0; }
.korb-zeile {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 20px;
  border-top: 1px solid var(--rule);
}
.korb-zeile:first-child { border-top: 0; }

/*
  Am Telefon in zwei Zeilen: Bild links über beide, rechts oben Nummer und
  Produkt über die volle Breite, darunter Frist und «Entfernen». In einer
  Zeile nahmen Marke und Knopf die Breite, und Nummer wie Name brachen
  Buchstabe für Buchstabe um (Rückgabe im Teams-Reiter, 03.10.2026).
*/
@media (max-width: 720px) {
  .korb-zeile {
    display: grid; align-items: center; gap: 8px 12px;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "bild text text" "bild marke aktion";
    padding: 12px 16px;
  }
  .korb-zeile > .sach-bild     { grid-area: bild; align-self: start; }
  .korb-zeile > .sach-text     { grid-area: text; }
  .korb-zeile > .badge         { grid-area: marke; justify-self: start; }
  .korb-zeile > .confirm-form  { grid-area: aktion; justify-self: end; }
}

/*
  «Weitere Exemplare dieses Titels» (Lehrmittel, seit 27.10.2026): eine
  schmale Zeile unter dem letzten Exemplar des Titels, eingerückt auf die
  Höhe der Nummer — sie gehört zur Zeile darüber.
*/
.korb-mehr { padding: 0 20px 12px calc(20px + 56px + 14px); }
.korb-mehr .row-form { flex-wrap: wrap; }
.korb-mehr .korb-mehr-zahl { width: 80px; }
@media (max-width: 720px) {
  .korb-mehr { padding: 0 16px 12px; }
  .korb-mehr .korb-mehr-zahl { width: 100%; }
}

/*
  Dieselbe Zeile, aber allein stehend: das gewaehlte Geraet im Formular.
  Sie steht nicht in einer Liste, darum traegt sie ihren eigenen Rahmen
  statt einer Trennlinie nach oben.
*/
.sach-karte {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
}
.sach-karte .sach-bild { background: var(--surface); }

/*
  Die Zubehoerliste bei der Rueckgabe.

  Abgesetzter Grund, damit die Haken darin nicht mit denen der Positionen
  daneben verschwimmen.
*/
.zubehoer-kasten {
  background: var(--surface-muted);
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  margin-bottom: 12px;
}

/*
  Meine Ausleihen: Zubehör und Anleitungen je Gerät (30.09.2026).

  Eine eigene Zeile unter dem Gerät, über die ganze Breite. Zugeklappt ist
  sie eine leise Zeile «3 Zubehörteile · 2 Anleitungen» unter dem Namen;
  aufgeklappt ein Feld mit zwei Spalten — links, was zurückkommen muss,
  rechts, wie es geht. Die Gerätezeile darüber verliert ihre Trennlinie,
  damit beides als eines gelesen wird.
*/
tbody tr.hat-mehr > td { border-bottom: 0; padding-bottom: 4px; }
tbody tr.ausleihe-mehr-zeile:hover { background: none; }
.ausleihe-mehr-zeile > td { padding: 0 16px 12px 72px; }

.ausleihe-mehr > summary {
  display: inline-flex; align-items: center; gap: 14px;
  padding: 4px 10px 4px 6px; margin-left: -6px;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem; color: var(--muted);
  cursor: pointer; list-style: none; user-select: none;
}
.ausleihe-mehr > summary::-webkit-details-marker { display: none; }
.ausleihe-mehr > summary::marker { content: ""; }
.ausleihe-mehr > summary:hover { background: var(--surface-muted); color: var(--accent-text); }
.ausleihe-mehr[open] > summary { color: var(--accent-text); }
.ausleihe-mehr-teil { display: inline-flex; align-items: center; gap: 5px; }
.ausleihe-mehr-teil + .ausleihe-mehr-teil::before {
  content: ""; width: 3px; height: 3px; margin-right: 9px;
  border-radius: 50%; background: currentColor; opacity: .5;
}
.ausleihe-mehr-pfeil { transition: transform .15s; }
.ausleihe-mehr[open] .ausleihe-mehr-pfeil { transform: rotate(90deg); }

.ausleihe-mehr-feld {
  display: grid; gap: 14px; align-items: start;
  margin-top: 10px;
}
.ausleihe-mehr-feld.is-zweispaltig { grid-template-columns: minmax(200px, 2fr) minmax(0, 3fr); }
@media (max-width: 720px) {
  .ausleihe-mehr-zeile > td { padding-left: 16px; }
  .ausleihe-mehr-feld.is-zweispaltig { grid-template-columns: 1fr; }
  /* Die Tabelle ist hier breiter als der Schirm und scrollt seitwärts;
     das Feld bleibt im sichtbaren Teil, statt rechts abgeschnitten. */
  .ausleihe-mehr-feld { position: sticky; left: 16px; max-width: calc(100vw - 88px); }
}

/* Eine Karte: Kopf mit Zeichen, Titel, Unterzeile und Zahl; darunter Zeilen. */
.ausleihe-karte {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); overflow: hidden;
}
.ausleihe-karte-kopf {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--rule);
}
.ausleihe-karte-kopf > div { flex: 1 1 auto; min-width: 0; }
.ausleihe-karte-kopf h3 { margin: 0; font-size: 0.875rem; font-weight: 600; color: var(--heading); }
.ausleihe-karte-kopf p  { margin: 1px 0 0; font-size: 0.7812rem; line-height: 1.4; color: var(--muted); }
.ausleihe-karte-zeichen {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-soft-text);
  font-size: 1rem;
}
.ausleihe-karte-zahl {
  flex: 0 0 auto; min-width: 22px; padding: 0 7px;
  border-radius: 999px; background: var(--surface-muted);
  font-size: 0.75rem; font-weight: 600; line-height: 22px; text-align: center; color: var(--muted);
}

.ausleihe-karte-liste { margin: 0; padding: 0; list-style: none; }
.ausleihe-karte-liste li {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px;
  font-size: 0.875rem; color: var(--text);
}
.ausleihe-karte-liste li + li { border-top: 1px solid var(--rule); }
.ausleihe-karte-liste li::before {
  content: ""; flex: 0 0 auto;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
}

/* Die Lesefassung der Anleitungen, in die Karte eingepasst: keine Karten
   in der Karte, sondern Zeilen mit denselben Trennlinien wie links. */
.ausleihe-karte .guides { gap: 0; }
.ausleihe-karte .guide { padding: 12px 16px; border: 0; border-radius: 0; background: none; }
.ausleihe-karte .guide + .guide { border-top: 1px solid var(--rule); }
.ausleihe-karte .guide h3 { margin-bottom: 4px; font-size: 0.875rem; }
.ausleihe-karte .guide-body p { font-size: 0.8438rem; line-height: 1.6; }
.ausleihe-karte .guide-dateien { margin-top: 10px; }
.ausleihe-karte .faq { margin: 0; border: 0; border-radius: 0; background: none; }
.ausleihe-karte .guides + .faq { border-top: 1px solid var(--rule); }
.ausleihe-karte .faq-item > summary,
.ausleihe-karte .faq-item-flach { padding: 9px 16px; min-height: 48px; font-size: 0.875rem; font-weight: 500; }
.ausleihe-karte .faq-body { padding: 0 16px 14px; }
.ausleihe-karte .faq-body p { font-size: 0.8438rem; }
.ausleihe-karte .faq-knopf { padding: 4px 11px; font-size: 0.8125rem; }
.ausleihe-karte .faq-knopf::after { content: "\2197"; margin-left: 5px; font-size: 0.75rem; }
@media (prefers-reduced-motion: reduce) { .ausleihe-mehr-pfeil { transition: none; } }

/*
  Ein Feld, das der Server fuehrt.

  `readonly` allein sieht aus wie ein gewoehnliches Feld — man tippt hinein
  und wundert sich, dass nichts geschieht. Der ruhigere Grund und der
  Mauszeiger sagen vorher, woran man ist. Gilt auch fuer die Stammdaten aus
  dem Verzeichnis, wo dieselbe Sperre schon laenger steht.
*/
.input[readonly], .select[readonly], textarea.input[readonly] {
  background: var(--surface-muted);
  color: var(--muted);
  cursor: not-allowed;
}
.input[readonly]:focus, textarea.input[readonly]:focus {
  border-color: var(--border); box-shadow: none;
}

.pointer { cursor: pointer; }

/*
  Buchungszeile beim Verbrauchsmaterial: Menge, Empfänger, Bemerkung, zwei
  Knöpfe. Feste Breiten statt Inline-Stilen, damit die Zeile in jeder
  Tabellenspalte gleich aussieht — und unter 1024 px umbricht, statt die
  Tabelle in den Seitwärtslauf zu zwingen.
*/
/*
  Ein gesperrter Felderblock. `disabled` allein macht die Felder nur
  unbedienbar — man sieht es kaum. Die halbe Deckkraft sagt, dass hier
  bewusst nichts einzutragen ist.
*/
fieldset.is-locked { opacity: .55; }
fieldset.is-locked .input,
fieldset.is-locked .select,
fieldset.is-locked .textarea { background: var(--surface-muted); cursor: not-allowed; }

.book-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* Verbrauchsmaterial: eine Zeile je Artikel (seit 11.10.2026). Oben Foto,
   Name mit Nummer, Bestand; darunter die Buchung als eine Leiste. */
.mat-liste { list-style: none; margin: 0; padding: 0; }
.mat-zeile {
  display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; gap: 6px 14px; align-items: center;
  padding: 14px 18px; border-bottom: 1px solid var(--border);
}
.mat-zeile:last-child { border-bottom: 0; }
.mat-text { min-width: 0; }
.mat-name { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.mat-nummer {
  font: 500 0.75rem/1 var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace); color: var(--muted);
  padding: 3px 6px; border-radius: 6px; background: var(--surface-muted); border: 1px solid var(--border);
}
.mat-bestand { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; text-align: right; }
.mat-buchen {
  grid-column: 2 / -1; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 4px;
}
/* Felder so hoch wie die kleinen Knöpfe daneben: eine Leiste, keine Treppe. */
.mat-buchen .input, .mat-buchen .select { height: 34px; min-height: 34px; padding-top: 0; padding-bottom: 0; font-size: 0.875rem; }
.mat-buchen .btn-sm { height: 34px; }
.mat-buchen .mat-menge { width: 64px; }
.mat-buchen .mat-wer   { width: 180px; }
.mat-buchen .mat-notiz { flex: 1 1 110px; min-width: 100px; max-width: 220px; }
.mat-knoepfe { display: flex; gap: 8px; flex: none; }
@media (max-width: 640px) {
  .mat-zeile { grid-template-columns: 48px minmax(0, 1fr); }
  /* Die Kantenlänge steht inline am Bild (56 px) — die Spalte ist hier 48. */
  .mat-zeile > .sach-bild { width: 48px !important; height: 48px !important; }
  .mat-bestand { grid-column: 2; align-items: flex-start; text-align: left; }
  .mat-buchen { grid-column: 1 / -1; }
  .mat-buchen .mat-wer { flex: 1 1 160px; width: auto; }
}
.book-row .book-qty  { width: 76px; }
.book-row .book-who  { width: 190px; }
.book-row .book-note { width: 140px; }
@media (max-width: 1200px) {
  .book-row .book-who { width: 150px; }
  .book-row .book-note { width: 110px; }
}
.scan-count { text-align: center; padding: 18px; border-radius: var(--radius); background: var(--surface-muted); }
.scan-count .v { font-size: 2rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.scan-count .k { font-size: 0.875rem; color: var(--muted); }

/* Beim Drucken bleibt nur der Inhalt. */
@media print {
  .sidebar, .site-head, .site-foot, .toolbar, .btn, .pager, .admin-head { display: none !important; }
  /* Reiner Bildschirm-Zierrat, gehört nicht ins gedruckte Handbuch. */
  .cookie-hinweis, .sprachband, .hb-rail, .hb-hoch { display: none !important; }
  /* Ein A4-Blatt ist rund 794 px breit — dort greift die Telefonansicht,
     und mit ihr Kopfzeile und Herausgeberzeile (seit 11.10.2026). */
  .app-topbar, .betreiber-fuss { display: none !important; }
  .content { overflow: visible !important; min-height: 0 !important; }
  .content .inner { padding: 0; }
  .card { border: 1px solid #ccc; box-shadow: none; }
  /*
    Nur kleine Karten bleiben ganz (seit 11.10.2026). Eine Karte mit
    Tabelle ist oft länger als ein Blatt; mit `break-inside: avoid` schob
    der Druck sie ganz auf Seite 2 und liess Seite 1 fast leer.
  */
  .card:not(:has(.table-wrap)) { break-inside: avoid; }
  tr { break-inside: avoid; }
  /* Papier scrollt nicht: was rechts hinausragte, war im Druck weg. */
  .table-wrap { overflow: visible !important; background: none; }
  .table-wrap > table { width: 100% !important; min-width: 0 !important; font-size: 0.6875rem; }
  /* Engere Zellen und umbrechende Köpfe, damit zehn Spalten auf A4 passen;
     die Karte schneidet im Druck nichts ab. */
  .table-wrap th, .table-wrap td { padding: 5px 6px; white-space: normal; }
  .card:has(.table-wrap) { overflow: visible; }
}

/* --- 5) Vorschau im Hero ------------------------------------------------ */

.hero-grid {
  display: grid;
  /* Der Filmausschnitt bekommt etwas mehr als die Haelfte: ein Film im
     Format 16:9 braucht Breite, sonst liest man im Bild nichts. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 44px;
  align-items: center;
  padding-top: var(--abschnitt);
  padding-bottom: var(--abschnitt);
}

/*
  Der Filmausschnitt gehoert auch aufs Telefon: er rueckt unter den Titel,
  in voller Breite, statt daneben.
*/
@media (max-width: 1000px) {
  /*
    EINSPALTIG — TITEL, DANN DIE VORSCHAU, DANN DER REST.

    Auf dem Telefon steht zuerst die Aussage «Inventar und Ausleihe
    endlich ohne Excel», gleich darunter der Filmausschnitt, und
    erst danach Vorspann, Knoepfe und Guetezeichen. So sieht man in den
    ersten zwei Bildschirmen die Botschaft UND was das Ding IST, ohne
    eine Textwand dazwischen.

    Der Kniff: `.hero-text` wird hier `display: contents`, damit H1 und
    der uebrige Textblock (`.hero-body`) zu eigenen Rasterzellen werden
    und sich einzeln um die Vorschau herum ordnen lassen. Auf dem Desktop
    bleibt `.hero-text` eine normale Spalte neben der Vorschau — die
    zweispaltige Aufteilung ist unberuehrt.

    (Geschichte: bis 12.09.2026 Vorschau ganz unten; dann ganz oben; seit
    20.09.2026 diese Zwischenloesung auf Wunsch des Betreibers.)
  */
  .hero-grid { grid-template-columns: minmax(0, 1fr); gap: 40px;
               padding-top: 48px; padding-bottom: 60px; }
  .hero-text { display: contents; }
  .hero-text > h1         { order: 1; }
  .hero-preview           { margin: 0 -4px; order: 2; }
  .hero-text > .hero-body { order: 3; }
}

/*
  Weniger Bewegung, für alles auf einmal (seit 26.10.2026 neu gefasst).

  Vorher stand hier nur `animation-duration: .01ms`. Endlose Animationen
  liefen damit weiter, nur tausendfach schneller, und flackerten; die
  eigenen Ersatzanimationen (Ladepunkt, Swyron AI) gingen genauso unter.
  Und jede Überblendung fiel weg, obwohl gerade sie beim Verstehen hilft.

  Jetzt: jede Animation läuft höchstens einmal und sofort zu Ende, und
  Übergänge bleiben nur für Deckkraft und Farben. Verschieben, Drehen und
  Vergrössern springen ohne Weg an ihr Ziel. Ausgenommen sind Anzeigen,
  die melden, dass etwas läuft: sie pulsieren dann nur in der Deckkraft.
*/
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-property: opacity, color, background-color, border-color, outline-color, box-shadow, fill, stroke !important;
  }
  .spinner,
  .ladeseite-balken > span,
  .sai-zeichen.denkt .sai-kern {
    animation-duration: 1.6s !important;
    animation-iteration-count: infinite !important;
  }
}

/* ==========================================================================
   6) Tablet und Telefon

   Die Anwendung wird am Schaltertisch bedient, im Materialraum und
   unterwegs — auf Telefonen genauso wie am Bildschirm. Diese Regeln sind
   deshalb kein Zusatz, sondern gehören zum Kern.

   Drei Stufen:
     bis 1024 px  Tablet: Seitenleiste weicht dem Menüknopf
     bis  720 px  Telefon: einspaltig, grössere Tippziele
     bis  420 px  schmale Telefone: noch enger
   ========================================================================== */

/* Nichts darf die Seite waagrecht scrollen lassen. */
html, body { max-width: 100%; overflow-x: clip; }
img, svg, video { max-width: 100%; height: auto; }

/* Lange Wörter (Inventarnummern, Adressen) dürfen umbrechen. */
/* Lange Woerter duerfen umbrechen — in Tabellenzellen aber erst am Wortende,
   sonst zerfaellt jede Inventarnummer in Silben. */
h1, h2, h3, p, dd, li, summary { overflow-wrap: anywhere; }
td, th { overflow-wrap: break-word; }

/* --- Kopfzeile für Tablet und Telefon ---------------------------------- */

.app-topbar { display: none; }

.app-menu { position: relative; }
.app-menu > summary {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 44px; min-width: 44px; padding: 0 14px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font: 500 0.875rem/1 var(--font); cursor: pointer;
  list-style: none;
}
.app-menu > summary::-webkit-details-marker { display: none; }
.app-menu > summary::marker { content: ""; }

.burger { display: inline-grid; gap: 3px; width: 16px; }
.burger span { display: block; height: 2px; background: currentColor; border-radius: 2px; }
.app-menu[open] > summary { background: var(--surface-muted); }

.app-menu-panel {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 40;
  width: min(320px, calc(100vw - 32px));
  max-height: calc(100dvh - 90px); overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
  padding: 14px 12px;
}

/*
  Ein Vorhang hinter dem Menue: ein Tipp daneben schliesst es wieder.
  Er liegt als ::after am summary, also im selben Stapelkontext, und
  bleibt mit z-index 35 unter dem Panel (40) und ueber allem sonst.
*/
.app-menu[open] > summary::after {
  content: ""; position: fixed; inset: 0; z-index: 35;
  background: rgba(10, 15, 40, .3);
}

/* Das Menü fährt auf, statt zu erscheinen. Kurz genug, dass es nicht
   im Weg ist — lang genug, dass das Auge folgen kann. */
.app-menu[open] > .app-menu-panel,
.site-menu[open] > .site-menu-panel {
  /* Von unten statt von oben: die Flaeche kommt aus der Richtung, in der
     der Daumen liegt. */
  animation: menu-hoch .18s ease-out;
}
@keyframes menu-hoch {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes menu-auf {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .app-menu[open] > .app-menu-panel,
  .site-menu[open] > .site-menu-panel { animation: none; }
}
/* Am Tablet ist das Menü kein Vollbild, sondern ein Kasten unter dem Knopf
   oben rechts. Dort klappt es aus dem Knopf heraus, wie die Klappkästen
   der Webseite (seit 26.10.2026); von unten kam es aus dem Nichts. */
@media (min-width: 721px) and (max-width: 1024px) {
  .app-menu[open] > .app-menu-panel { animation-name: menu-auf; transform-origin: top right; }
}
/* Am Telefon etwas grosszuegiger — die Tippziele sollen 44 px hoch sein. */
.app-menu-panel .nav-item { padding: 11px 10px; font-size: 0.9375rem; }
.app-menu-panel .menu-foot {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border);
}

/* --- bis 1024 px: Tablet ------------------------------------------------ */

@media (max-width: 1024px) {
  /*
    Deckende Fläche statt Weichzeichner. `backdrop-filter` erzeugt einen
    eigenen Bezugsrahmen; alles darin mit `position: fixed` — Menüfläche und
    Vorhang — richtete sich danach an der 64 px hohen Kopfzeile aus statt am
    Bildschirm. Die Fläche war ohnehin zu 92 % deckend: der Weichzeichner
    kostete mehr, als er zeigte.
  */
  .app-topbar {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    position: sticky; top: 0; z-index: 30;
    /*
      Die Hoehe steht fest und wird nicht geraten. Das Vollbild-Menue am
      Telefon setzt darunter an; stimmten die Zahlen nicht ueberein,
      bliebe dort ein Spalt oder eine Ueberdeckung.
    */
    min-height: var(--topbar-h);
    padding: 10px 16px;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
  }
  .sidebar { display: none; }
  /*
    Ohne Seitenleiste gibt es nichts zu trennen. Hier scrollt wieder
    das Dokument selbst — sonst haette die Seite eine feste Hoehe und
    die Adressleiste des Browsers faehre beim Wischen nie ein.
  */
  .shell { display: block; position: static; inset: auto; height: auto; overflow: visible; }
  /* Mindestens bildschirmhoch, damit die Welle auch auf kurzen Seiten
     unten steht und nicht mitten im Bild. */
  .content { overflow: visible; min-height: calc(100vh - var(--topbar-h)); min-height: calc(100dvh - var(--topbar-h)); }
  .content .inner { padding: 22px 16px 56px; }
  /* Streifen und Überschrift beginnen an derselben Kante. */
  .trial-bar { padding-left: 16px; padding-right: 16px; }

  /* Zweispaltige Seiten werden einspaltig — die Randspalte rutscht nach unten. */
  .grid-side { grid-template-columns: minmax(0, 1fr); }
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- bis 720 px: Telefon ------------------------------------------------ */

@media (max-width: 720px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: minmax(0, 1fr); }

  /*
    Am Telefon nimmt das Menue die ganze Flaeche ein statt in einem
    Klappkasten zu stehen: dreizehn Ziele in einem 320-px-Kasten haben
    dauernd gescrollt werden muessen. Zwischen 721 und 1024 px bleibt der
    Kasten — dort ist genug Platz.
  */
  .app-menu-panel {
    position: fixed; inset: var(--topbar-h) 0 0; width: auto;
    max-height: none; height: calc(100dvh - var(--topbar-h));
    border: 0; border-top: 1px solid var(--border); border-radius: 0;
    box-shadow: none; padding: 16px 14px calc(24px + env(safe-area-inset-bottom));
  }

  .page-head { gap: 12px; margin-bottom: 18px; }
  .page-head h1 { font-size: 1.3125rem; }
  .page-head > .btn,
  .page-head > .row { width: 100%; }
  .page-head > .row .btn { flex: 1; }

  /* Tippziele: mindestens 44 px hoch — ausnahmslos. */
  .btn { height: 44px; padding: 0 18px; }
  .btn-sm { height: 44px; }
  .input, .select { height: 44px; font-size: 1rem; }  /* 16 px verhindert das
                                                          Zoomen beim Antippen in iOS */
  .textarea { font-size: 1rem; }
  .btn-link { min-height: 44px; padding: 10px 12px; }
  .pager a { min-height: 44px; padding: 8px 14px; }
  .tabs a { min-height: 44px; display: inline-flex; align-items: center; }

  /* Such- und Filterleiste stapeln */
  /*
    Suchleiste kompakt (seit 03.10.2026): Suchfeld und Knopf in einer Zeile,
    die Filter zu zweit darunter. Untereinander in voller Breite füllten
    Feld, zwei Filter und Knopf den halben Bildschirm, bevor die Liste kam.
  */
  .toolbar {
    display: grid; gap: 8px;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  }
  .toolbar .input, .toolbar .select { width: 100%; min-width: 0; }
  .toolbar .input[type="search"] { grid-column: 1 / 3; grid-row: 1; }
  .toolbar > button[type="submit"] { grid-column: 3; grid-row: 1; width: auto; }
  .toolbar .select:nth-of-type(odd) { grid-column: 1; }
  .toolbar .select:nth-of-type(even) { grid-column: 2 / 4; }
  .toolbar .select:nth-of-type(odd):last-of-type { grid-column: 1 / -1; }
  .toolbar .btn-ghost { grid-column: 1 / -1; width: 100%; }
  /* Ohne Suchfeld (nur Filter): die Knöpfe in eine eigene Zeile. */
  .toolbar:not(:has(.input[type="search"])) > button[type="submit"] { grid-column: 1 / -1; grid-row: auto; width: 100%; }

  /* Karten dichter am Rand, aber nicht randlos */
  .card { border-radius: 10px; }
  .card-head { padding: 14px 16px; flex-wrap: wrap; }
  .card-body { padding: 16px; }
  .card-foot { padding: 14px 16px; }
  .list > li { padding: 12px 16px; }
  .dl > div { padding: 10px 16px; }
  th, td { padding: 10px 12px; }

  /* Beschreibungslisten: Etikett links, Wert rechts in einer Zeile — wie
     die Einstellungen am iPhone. Untereinander gestapelt brauchte jede
     Angabe zwei Zeilen und «Angaben» zwei Bildschirmhöhen (03.10.2026).
     Ein langer Wert bricht rechts um, das Etikett bleibt stehen. */
  .dl > div { gap: 16px; align-items: baseline; }
  .dl dt { max-width: 45%; }
  .dl dd { flex: 1 1 auto; min-width: 0; text-align: right; overflow-wrap: anywhere; }

  /* Kennzahlen kleiner, damit vier Karten nicht die halbe Seite füllen */
  .stat { padding: 14px 16px; }
  .stat .v { font-size: 1.625rem; }
  /*
    Die Behälterabfragen aus Abschnitt 3 noch einmal, und zwar DANACH
    (seit 04.10.2026). Die 26 px darüber haben dieselbe Spezifität und
    stehen weiter unten — sie gewannen am Telefon immer, und «152’523.00»
    verlor wieder seine letzten Stellen.
  */
  @container (max-width: 150px) { .stat .v { font-size: 1.5rem; } }
  @container (max-width: 120px) { .stat .v { font-size: 1.1875rem; } }
  /* Geldkacheln am Telefon einzeln: zu zweit bleiben einem Betrag
     keine 130 px, und `.card` schneidet ab, statt umzubrechen. */
  .grid-4.grid-geld { grid-template-columns: minmax(0, 1fr); }

  /* Formularraster einspaltig */
  .card-body .grid-2, .card-body .grid-3 { grid-template-columns: minmax(0, 1fr); }

  /* Reiter waagrecht scrollbar statt umbrechend */
  .tabs { gap: 0; -webkit-overflow-scrolling: touch; }
  .tabs a { padding: 10px 12px; }

  /* Seitenblättern gestapelt */
  .pager { flex-direction: column; align-items: stretch; gap: 8px; text-align: center; }
  .pager .row { justify-content: center; }
}

/* --- bis 420 px: schmale Telefone --------------------------------------- */

@media (max-width: 420px) {
  .content .inner { padding: 16px 12px 48px; }
  .card-head, .card-body, .card-foot, .list > li, .dl > div { padding-left: 14px; padding-right: 14px; }
  /* Der Knopf zeigt nur noch das Symbol — behaelt seinen Namen aber fuer
     die Sprachausgabe. Ein `display: none` haette ihn namenlos gemacht. */
  .menu-word {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .app-menu > summary { padding: 0 12px; }
  .page-head h1 { font-size: 1.1875rem; }
}

/* Ein Fenster, das ohne Skript über seinen Anker erscheint (siehe app.js,
   `data-dialog-open`). Mit Skript ist es ein echtes modales Fenster. */
dialog.dialog:target:not([open]) {
  display: block; position: static; margin: 16px auto; max-width: 520px;
}

/* --- Im Teams-Reiter ---------------------------------------------------- */

/*
  Teams zeigt am Telefon schon einen eigenen Kopf mit Zeichen und Namen
  der App. Unsere Kopfzeile darunter wiederholte beides gross — zwei
  Logos übereinander und ein Viertel des Bildschirms weg, bevor der
  Inhalt beginnt (Rückmeldung vom 02.10.2026). Im Reiter (`body.im-teams`,
  gesetzt in `layout/app.php`) wird sie darum zur schmalen Leiste: statt
  der Wortmarke das App-Zeichen und der Name der Seite, Menüknopf als ruhige
  Fläche, kein Rahmen. `--topbar-h` zieht
  das Vollbild-Menü mit, das darunter ansetzt.
*/
.im-teams { --topbar-h: 48px; }
@media (max-width: 1024px) {
  .im-teams .app-topbar {
    padding: 6px 12px 6px 16px;
    background: var(--surface);
    border-bottom: 0;
    box-shadow: 0 1px 0 var(--border);
  }
  .im-teams .reiter-marke {
    display: flex; align-items: center; gap: 10px; min-width: 0;
    color: var(--heading); text-decoration: none;
  }
  .im-teams .reiter-marke img {
    flex: none; width: 30px; height: 30px; border-radius: 8px;
  }
  .im-teams .reiter-ort {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font: 600 1.0625rem/1.2 var(--font);
  }
  .im-teams .app-menu > summary {
    min-height: 36px; padding: 0 12px;
    border-color: transparent; background: var(--surface-muted);
    font-size: 0.8125rem;
  }
  .im-teams .content .inner { padding-top: 16px; }
  .im-teams .page-head h1.ist-doppelt {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
}

/*
  Kein Zoomen im Reiter (siehe `layout/head.php`). `user-scalable=no`
  allein reicht nicht überall: `touch-action` sperrt das Aufziehen mit zwei
  Fingern und den Doppeltipp, Wischen bleibt. Eingabefelder mit 16 px
  Schrift, sonst zoomt iOS beim Antippen von selbst hinein.
*/
.im-teams { touch-action: pan-x pan-y; }
@media (pointer: coarse) {
  .im-teams input, .im-teams select, .im-teams textarea { font-size: 1rem; }
}
/* Einzelreiter: ohne Kopfzeile und Seitenleiste, der Inhalt beginnt oben. */
.im-teams-einzel { --topbar-h: 0px; }

/* --- Tabellen ----------------------------------------------------------- */

/*
  Tabellen bleiben Tabellen — der Vergleich Zeile für Zeile ist genau das,
  was hier gebraucht wird. Sie scrollen innerhalb ihrer Karte, nie die
  ganze Seite. Der Schatten am rechten Rand zeigt an, dass es weitergeht.
*/
.table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  background:
    linear-gradient(to right, var(--surface) 30%, transparent),
    linear-gradient(to left,  var(--surface) 30%, transparent) 100% 0,
    radial-gradient(farthest-side at 0 50%, var(--scroll-schatten), transparent),
    radial-gradient(farthest-side at 100% 50%, var(--scroll-schatten), transparent) 100% 0;
  background-repeat: no-repeat;
  background-size: 36px 100%, 36px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}
@media (max-width: 720px) {
  table { min-width: 520px; font-size: 0.8125rem; }
  /* Die erste Spalte bleibt stehen, damit beim Wischen erkennbar bleibt,
     zu welcher Zeile der Wert gehoert. */
  .table-wrap.sticky-first th:first-child,
  .table-wrap.sticky-first td:first-child {
    position: sticky; left: 0; z-index: 1; background: var(--surface);
  }
  .table-wrap.sticky-first tbody tr:hover td:first-child { background: var(--row-hover); }
}

/* Ab Tablet darf die Tabelle wieder breiter werden als der Kasten. */
@media (min-width: 721px) and (max-width: 1024px) {
  table { min-width: 680px; }
}

/* --- Marketing auf kleinen Bildschirmen --------------------------------- */

@media (max-width: 860px) {
  /*
    Die Kopfzeile trägt vier Dinge: Logo, Navigation, zwei Knöpfe. Ab hier
    geht das nicht mehr nebeneinander auf. Das Logo wird kleiner, statt dass
    etwas aus dem Bild läuft — 167 px sind auf einem Telefon fast die halbe
    Breite.
  */
  .site-head .brand-lockup { height: 34px; }
}

@media (max-width: 720px) {
  .site-head .inner { padding: 0 16px; gap: 8px; }
  .site-head .brand { font-size: 0.9375rem; }
  /*
    Die Wortmarke bleibt gross.

    Die alten Stufen stammen aus der Zeit des breiten Logos: Zeichen plus
    Wortmarke waren 167 px, und auf einem Telefon war das fast die halbe
    Breite. Die reine Wortmarke ist 129 px — es ist Platz da, und ein
    Logo, das man kaum sieht, ist als Absender wertlos.
  */
  .site-head .brand-lockup { height: 34px; }
  .site-head .row { gap: 6px; }
  .site-head .btn { height: 38px; padding: 0 12px; font-size: 0.8125rem; }

  .wrap { padding-left: 16px; padding-right: 16px; }
  .section { padding: var(--abschnitt-tablet) 0; }
  .hero-grid { padding-top: 34px; padding-bottom: 48px; gap: 36px; }
  .hero h1 { font-size: 1.75rem; }
  .hero .lead { font-size: 1rem; }

  .hero .row { flex-direction: column; align-items: stretch; }
  .hero .row .btn { width: 100%; }
  .section h2 { font-size: 1.5rem; }

  .plan { padding: 22px; }
  .site-foot .inner { flex-direction: column; gap: 12px; padding: 22px 16px; }
}

/*
  Auf schmalen Geräten weicht der Anmeldeknopf aus der Kopfzeile — er steht
  ohnehin im Klappmenü darunter, und „Kostenlos testen“ ist der wichtigere
  Weg. Ab 560 px statt erst ab 420 px: darunter lief die Zeile über.
*/
@media (max-width: 560px) {
  .site-head .btn-ghost { display: none; }
  .site-head .brand-lockup { height: 32px; }
  .site-head .inner { padding: 0 14px; }
}
@media (max-width: 380px) {
  /* Ganz schmal wird sie etwas kleiner — aber nicht klein: „Anmelden“
     ist hier ohnehin schon weg, der Platz reicht. */
  .site-head .brand-lockup { height: 30px; }
  .site-head .btn { padding: 0 10px; font-size: 0.75rem; }
}

/* --- Anmeldeseiten ------------------------------------------------------ */

@media (max-width: 480px) {
  .auth-page > header { padding: 32px 16px 22px; }
  .auth-box { padding: 0 16px 40px; }
  .auth-card { padding: 20px; border-radius: 12px; }
  .auth-sprache { top: 14px; right: 26px; }
  .auth-foot { flex-direction: column; gap: 10px; align-items: flex-start; }
}

/* --- Backoffice --------------------------------------------------------- */

@media (max-width: 720px) {
  .admin-head .inner { height: auto; padding: 10px 16px; flex-wrap: wrap; gap: 10px; }
  .admin-head .row { gap: 12px; }
  .admin-head .who { display: none; }
  .admin-body .inner { padding: 20px 16px 48px; }
}

/* Kundennummer — soll abgeschrieben und vorgelesen werden können. */
.reference-code {
  font: 600 1.25rem/1.2 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .06em; color: var(--heading);
  -webkit-user-select: all; user-select: all;
}

/* Erfassungsformular oben in einer Karte — abgesetzt von der Liste darunter. */
.form-panel {
  background: var(--surface-muted);
  border-bottom: 1px solid var(--border);
}
/* Ein erklärender Satz über einer Liste. */
.panel-note {
  padding: 14px 22px; border-bottom: 1px solid var(--border);
  font-size: 0.8125rem; color: var(--muted);
}
.panel-note strong { color: var(--text); font-weight: 600; }

/* --- Abstand zwischen Eingabe und Knopf ---------------------------------- */

/*
  Eine Knopfzeile darf nie an den Feldern kleben.

  Das ist eine Folge davon, dass Felder im Raster ihren eigenen Abstand
  abgeben (`.grid > .field { margin-bottom: 0 }`) — richtig fürs Raster,
  falsch für das, was danach kommt. Statt es in jedem Formular von Hand zu
  setzen, steht der Abstand hier einmal, und zwar überall gleich: 20 px.
*/
.field + .row,      .grid + .row,      fieldset + .row,      .check + .row,
.field + .btn,      .grid + .btn,      fieldset + .btn,      .check + .btn,
.field + .form-actions, .grid + .form-actions,
.field + .scan-form,    .grid + .scan-form,
.grid + .field,     .grid + fieldset,
.textarea + .row,   .input + .row,     .select + .row {
  margin-top: 20px;
}
/* In der Karte hat der Fussbereich seinen Abstand schon durch die Linie. */
.card-foot > .row:first-child, .card-foot > .btn:first-child { margin-top: 0; }

/* --- Inventarkontrolle --------------------------------------------------- */

.check-list > li { display: grid; gap: 10px; }
.check-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.check-actions .btn { flex: 1; min-width: 108px; }
/* Das gewählte Ergebnis bleibt sichtbar — ein zweiter Druck nimmt es zurück. */
.check-actions .btn.is-on {
  background: var(--accent-soft); color: var(--accent-soft-text);
  border-color: var(--accent); font-weight: 600;
}

/* --- Rückfrage vor einer nicht umkehrbaren Aktion ------------------------ */

/*
  Statt des Browserkastens von `confirm()` — der auf jedem Betriebssystem
  anders aussieht, die Adresse der Seite anzeigt und sich nicht gestalten
  lässt — ein eigenes Fenster. Es benutzt das eingebaute <dialog>: der
  Browser regelt Stapelreihenfolge, Escape und den Fokus selbst.

  Ohne JavaScript wird der Dialog nie geöffnet; das Formular sendet dann
  direkt ab. Der Knopf funktioniert also in jedem Fall.
*/
.confirm-form { display: inline; }

/* Browser, die <dialog> nicht kennen (Safari bis 15.3, also das Ende der
   Fahnenstange auf älteren iPads), stellen den Inhalt sonst inline dar —
   in jeder Tabellenzeile stünden Warnsymbol, Überschrift und zwei weitere
   Knöpfe. Diese Zeile verhindert das. */
dialog:not([open]) { display: none; }

.dialog {
  width: min(440px, calc(100vw - 32px));
  padding: 0; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text);
  box-shadow: 0 20px 48px -12px rgba(8, 10, 20, .35);
}
.dialog::backdrop { background: rgba(8, 10, 20, .5); }
.dialog-body { padding: 22px 24px 18px; }
.dialog-body h2 { font-size: 1.0625rem; font-weight: 600; letter-spacing: -.005em; }
.dialog-body p  { margin-top: 8px; color: var(--muted); font-size: 0.875rem; line-height: 1.55; }
.dialog-icon {
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center; margin-bottom: 14px;
  background: var(--danger-bg); color: var(--danger-fg);
}
.dialog-icon svg { width: 20px; height: 20px; }
.dialog.is-neutral .dialog-icon { background: var(--info-bg); color: var(--info-fg); }
.dialog-actions {
  display: flex; gap: 10px; justify-content: flex-end;
  padding: 14px 24px; border-top: 1px solid var(--border);
  background: var(--surface-muted);
  border-radius: 0 0 var(--radius) var(--radius);
}
@media (max-width: 480px) {
  .dialog-actions { flex-direction: column-reverse; }
  .dialog-actions .btn { width: 100%; }
}

/* --- Absendeleiste in langen Formularen --------------------------------- */

/*
  Bis 1024 px klebt die Leiste mit „Speichern“ am unteren Rand — bei einem
  Formular mit zwanzig Feldern war der Knopf sonst ausser Sicht. Auf dem
  Desktop steht sie fest: dort ist er ohnehin im Blick, und eine klebende
  Leiste wuerde nur Hoehe stehlen.
*/
.form-actions {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  padding: 14px 22px; border-top: 1px solid var(--border);
  background: var(--surface);
}
@media (max-width: 1024px) {
  .form-actions {
    position: sticky; bottom: 0; z-index: 5;
    padding-bottom: calc(14px + env(safe-area-inset-bottom));
  }
  .form-actions .btn { flex: 1; }
}

/* ==========================================================================
   8) IT-Dokumentation — Rackansicht

   Die Rackansicht ist massstäblich: eine Höheneinheit ist immer 92
   Zeicheneinheiten hoch, und die Frontblenden der Geräte sind in genau
   diesem Raster gezeichnet. Deshalb SVG und kein HTML-Raster — in HTML
   wäre das ein Kampf gegen Zeilenhöhen.
   ========================================================================== */

.rack-view {
  /* Ein hohes Rack wird sonst so klein, dass die Portnummern verschwinden.
     Lieber innerhalb der Karte scrollen als unleserlich schrumpfen. */
  max-height: 78vh;
  overflow: auto;
  overscroll-behavior: contain;
  padding: 4px;
  background: var(--surface-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.rack-view svg { min-width: 560px; display: block; }

.rack-slot-bg   { fill: var(--surface); }
.rack-slot.is-free .rack-slot-bg { fill: var(--surface-muted); }
.rack-slot-line { stroke: var(--border); stroke-width: 1.5; }
.rack-slot-nr   { fill: var(--muted); font: 600 26px/1 var(--font); font-variant-numeric: tabular-nums; }
.rack-rail      { fill: var(--indigo-200); }

.rack-device { cursor: pointer; }
.rack-device:hover { opacity: .88; }
.rack-device-name { fill: var(--heading); font: 600 24px/1 var(--font); }
.rack-device-ip   { fill: var(--accent); font: 500 20px/1 var(--font); font-variant-numeric: tabular-nums; }
.rack-schild-linie { stroke: var(--rule); stroke-width: 2; stroke-dasharray: 4 4; }
.rack-device:hover .rack-device-name { fill: var(--accent); }
.rack-device-focus {
  fill: none; stroke: var(--accent); stroke-width: 6;
}

/* Kacheln der Rackübersicht */
.rack-cards { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.rack-card { margin-bottom: 0; display: block; color: inherit; text-decoration: none;
             transition: border-color .15s, box-shadow .15s; }
.rack-card:hover { border-color: var(--accent-line); box-shadow: var(--shadow-lg); text-decoration: none; }
.rack-card-head { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start;
                  padding: 16px 18px; border-bottom: 1px solid var(--border); }
.rack-card-name { font-size: 0.9375rem; font-weight: 600; color: var(--heading); }
.rack-card-body { padding: 14px 18px 16px; }

/* Wertübersicht */

/*
  Filterkarte mit sichtbaren Beschriftungen. Die Felder wachsen und
  schrumpfen mit der Breite; die Knopfzeile sitzt darunter, abgesetzt durch
  eine Linie — so kann kein Ankreuzfeld mehr zwischen zwei Auswahllisten
  rutschen und dort schief stehen.
*/
.filter-panel .card-body { padding-bottom: 0; }
.filter-grid {
  display: grid; gap: 14px 16px;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.filter-grid .field { margin-bottom: 0; }

/*
  Ein Feld, das keinen Filter setzt, sondern eine Annahme.

  «Nutzungsdauer ohne eigene Angabe» stand zwischen den Auswahlfeldern
  und sah aus wie eines davon — dabei schraenkt es nichts ein, sondern
  legt fest, womit gerechnet wird, wo nichts gepflegt ist. Dazu sind
  Beschriftung und Erklaerung laenger als bei jedem Nachbarn, was die
  Rasterzeile ungleich hoch machte.

  Darum eine eigene Zeile ueber die volle Breite, durch eine Haarlinie
  abgesetzt, und die drei Teile nebeneinander statt uebereinander: die
  Breite ist ohnehin da, und so bleibt die Zeile flach.
*/
.filter-grid .field-weit {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px;
  margin-top: 4px; padding-top: 16px;
  border-top: 1px solid var(--border);
}
.filter-grid .field-weit > .label { margin-bottom: 0; flex: 0 0 auto; }
/* Schmal genug, dass «5 Jahre» nicht in einem halbleeren Feld steht. */
.filter-grid .field-weit .select { width: auto; min-width: 120px; flex: 0 0 auto; }
/*
  Die Erklaerung nimmt den Rest. `flex-basis` gross genug, dass sie auf
  einem Telefon umbricht statt sich auf drei Woerter je Zeile zu
  quetschen.
*/
.filter-grid .field-weit .hint { flex: 1 1 260px; margin-top: 0; }
.filter-actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
  margin: 18px -22px 0; padding: 14px 22px;
  border-top: 1px solid var(--border);
}
.filter-actions .check { margin: 0; align-items: center; }

/*
  Umschalter als Kachel.

  Ein Ankreuzfeld in einer Reihe von Knöpfen steht immer etwas verloren da —
  andere Höhe, andere Anmutung, und man sieht aus zwei Metern nicht, ob es
  gesetzt ist. Als eingefärbte Kachel mit Haken ist der Zustand eindeutig.

  Das Eingabefeld bleibt im Markup und bedienbar; es ist nur nicht sichtbar.
  Tastatur und Sprachausgabe arbeiten damit unverändert, und ohne CSS
  funktioniert das Formular ebenfalls.
*/
.toggle-chip { display: inline-flex; cursor: pointer; }
.toggle-chip input {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  margin: 0; pointer-events: none;
}
.toggle-chip > span {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 40px; padding: 0 16px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--muted);
  font: 500 0.875rem/1 var(--font);
  transition: background-color .12s, border-color .12s, color .12s;
}
.toggle-chip:hover > span { border-color: var(--indigo-200); color: var(--text); }

/* Der Haken ist immer da, aber nur im eingeschalteten Zustand zu sehen —
   so springt die Breite der Kachel beim Umlegen nicht. */
.toggle-chip > span svg {
  width: 16px; height: 16px; flex: 0 0 16px;
  opacity: 0; transform: scale(.7);
  transition: opacity .12s, transform .12s;
}
.toggle-chip input:checked + span {
  background: var(--accent-soft); border-color: var(--accent);
  color: var(--accent-soft-text); font-weight: 600;
}
.toggle-chip input:checked + span svg { opacity: 1; transform: none; }
.toggle-chip input:focus-visible + span {
  outline: 2px solid var(--focus); outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .toggle-chip > span, .toggle-chip > span svg { transition: none; }
}
@media (max-width: 720px) {
  .filter-actions { margin-left: -16px; margin-right: -16px; padding: 14px 16px;
                    flex-direction: column; align-items: stretch; }
  .filter-actions .row { justify-content: flex-end; }
  .filter-actions .btn { flex: 1; }
}
tfoot tr.is-total td {
  border-top: 2px solid var(--head-rule);
  background: var(--surface-muted);
  padding-top: 12px; padding-bottom: 12px;
}
/* Der Anteilsbalken in der Tabelle ist schmaler als der in einer Karte. */
td .progress { height: 6px; min-width: 90px; }

/* Beim Drucken bleibt die Auswertung, alles Bedienbare geht.
   Das Formular heisst `.filter-panel` (seit 11.10.2026; vorher stand hier
   ein Klassenname, den es nirgends gab, und der Filter druckte mit). */
@media print {
  .filter-panel, .page-head .row { display: none !important; }
}

/* Rechtstexte: Impressum, Datenschutz, AGB. Eine Spalte, ruhig gesetzt. */
/*
  Rechtstexte: engeres Mass, groessere Schrift.

  Vorher vierzehn Pixel ueber sechshundertzweiundsiebzig — hundertzehn
  Zeichen je Zeile, und darueber eine Ueberschrift von dreissig Pixeln.
  Ein Vertragstext wird nicht ueberflogen, sondern gelesen; er bekommt
  deshalb dasselbe Mass wie jeder andere Fliesstext hier und nicht das
  einer Fussnote.
*/
.prose-page { max-width: 620px; padding-top: 64px; padding-bottom: 64px; }
.prose-page h1 { font-size: 1.875rem; font-weight: 600; letter-spacing: -.02em; }
.prose-page h2 { font-size: 0.9375rem; font-weight: 600; letter-spacing: 0; }
.prose-page p, .prose-page li { font-size: 0.9375rem; color: var(--muted); line-height: 1.7; }
.prose-page strong { color: var(--text); }
@media (max-width: 720px) { .prose-page { padding-top: 40px; padding-bottom: 40px; } }

/*
  Der Knopf mit Wartefenster steht in einer Reihe mit den anderen.

  Ein <form> ist ein Blockelement — in einer Zeile mit Knoepfen reisst es
  die Reihe auseinander. Vorher trugen diese Formulare die Klasse
  `confirm-form`, die genau das schon regelte; der eigene Name sagt jetzt,
  worum es geht.
*/
.busy-form { display: inline-flex; }

/*
  Eine zweite Reiterleiste unter der ersten.

  Sie gehoert zur ersten und darf ihr nicht Konkurrenz machen: kleiner,
  ohne eigene Linie darunter, etwas eingerueckt. Wer zwei gleich starke
  Leisten uebereinander setzt, hat keine Ordnung mehr, sondern zwei
  Wahlen ohne Rangfolge.
*/
.tabs-unter { margin: -6px 0 18px; }
.tabs-unter .tabs { border-bottom: 0; gap: 4px; padding-top: 4px; }
.tabs-unter .tabs a { font-size: 0.8438rem; padding: 6px 10px; }
.tabs-unter .tabs a[aria-current="page"] {
  background: var(--accent-soft); color: var(--accent-soft-text);
  border-radius: 6px; box-shadow: none;
}

/*
  Das Bestaetigungsfeld im Rueckfragefenster.

  Links ausgerichtet, obwohl der Rest des Fensters mittig steht: ein
  Eingabefeld mit mittigem Etikett sieht aus wie eine Zierde, nicht wie
  etwas, das man ausfuellen soll.
*/
.dialog-eingabe { margin-top: 18px; text-align: left; }
.dialog-eingabe label {
  display: block; margin-bottom: 6px;
  font-size: 0.8438rem; color: var(--muted);
}
.dialog-eingabe label b {
  color: var(--heading); font-weight: 600;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .04em;
}
.dialog-eingabe .input { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

/* --- Mehrere Zeilen auswaehlen --------------------------------------------- */

/*
  Die Spalte mit den Kaestchen bleibt schmal und stoert die Flucht der
  uebrigen nicht. Ein gesperrtes Kaestchen bleibt sichtbar — es sagt
  „diese Zeile geht nicht", und das ist eine Auskunft.
*/
.spalte-haken { width: 34px; padding-right: 0 !important; }
.spalte-haken input[disabled] { opacity: .4; cursor: not-allowed; }

.auswahl-leiste {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  border-top: 1px solid var(--border); background: var(--surface-muted);
}
.auswahl-zahl { font-size: 0.875rem; color: var(--text); }
.auswahl-zahl b { color: var(--heading); font-variant-numeric: tabular-nums; }
.auswahl-leiste .hint { margin: 0; }

/* --- Herkunft eines Geraets ------------------------------------------------ */

/*
  Der Namenszug des MDM. Kein Logo — siehe partials/mdm-marke.php.

  Die Farbe kommt als Inline-Stil aus der Vorlage und nicht von hier: es
  ist die Hausfarbe eines fremden Systems und damit keine Rollenmarke
  unserer Gestaltung. Sie gehoert zu den Daten, nicht zum Stil.
*/
.mdm-marke { display: inline-flex; align-items: center; gap: 10px; }
.mdm-marke-zug {
  display: inline-flex; align-items: center;
  padding: 5px 11px; border-radius: 7px;
  font-size: 0.8125rem; font-weight: 600; letter-spacing: -.005em;
  white-space: nowrap;
}
.mdm-marke-unter { font-size: 0.8125rem; color: var(--muted); }

/* --- Karten der Integrationen ---------------------------------------------- */

/*
  Drei Karten nebeneinander, und der Knopf steht bei allen dreien auf
  derselben Linie — die Beschreibungen sind verschieden lang, und ein
  Knopf, der bei einer Karte in der Mitte haengt, sieht aus wie ein
  Fehler.
*/
.integ-karte { display: flex; flex-direction: column; }
.integ-karte .card-body { flex: 1 1 auto; }
.integ-karte h2 { font-size: 1rem; }
.integ-karte .muted { font-size: 0.875rem; line-height: 1.6; }
.integ-zeichen {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 10px;
  background: linear-gradient(160deg, var(--accent-soft), var(--surface));
  border: 1px solid var(--border); color: var(--accent);
}
.integ-zeichen svg { width: 19px; height: 19px; }
.integ-karte .card-foot {
  padding: 14px 20px 18px; border-top: 1px solid var(--border);
}

@media (max-width: 900px) {
  .integ-karte .card-foot { padding: 12px 16px 16px; }
}

/* --- Rechtstexte mit Verzeichnis ------------------------------------------ */

/*
  Die Datenschutzerklaerung ist kein Absatz mehr, sondern ein Dokument.

  Achtzehn Abschnitte auf einer Spalte ohne Verzeichnis liest niemand —
  man scrollt, verliert die Stelle und gibt auf. Derselbe Aufbau wie im
  Handbuch: ein heller Kopf, links das Verzeichnis, das beim Scrollen
  stehen bleibt, rechts der Text auf Lesemass.
*/
.recht-kopf {
  border-bottom: 1px solid var(--border);
  padding: 54px 0 34px;
}
.recht-kopf h1 {
  font-size: clamp(1.75rem, 4vw, 2.375rem); letter-spacing: -.025em; margin: 10px 0 0;
}
.recht-kopf .lead { max-width: 42em; margin-top: 14px; }
.krume { font-size: 0.8125rem; color: var(--muted); margin: 0; }

.recht-layout {
  display: grid; grid-template-columns: 250px minmax(0, 1fr);
  gap: 56px; align-items: start;
  padding-top: 40px; padding-bottom: 72px;
}
.recht-rail { position: sticky; top: 88px; }
.recht-rail-titel {
  margin: 0 0 10px; font-size: 0.75rem; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
}
.recht-rail ol {
  margin: 0; padding: 0; list-style: none;
  counter-reset: recht;
  max-height: calc(100vh - 140px); overflow-y: auto;
}
.recht-rail li { counter-increment: recht; }
.recht-rail a {
  display: block; padding: 5px 0 5px 26px; position: relative;
  font-size: 0.8438rem; line-height: 1.45; color: var(--muted);
  text-decoration: none; border-radius: 4px;
}
.recht-rail a::before {
  content: counter(recht) "."; position: absolute; left: 0;
  font-variant-numeric: tabular-nums; color: var(--muted); /* seit 11.10.2026 direkt: der Rückfall zeigte auf ein Token, das es nie gab */
  font-size: 0.7812rem;
}
.recht-rail a:hover { color: var(--accent-text); }

.recht { max-width: 42em; }
/* Ohne Verzeichnis — neun Abschnitte findet man auch so. */
.recht-einspaltig { padding-top: 40px; padding-bottom: 72px; }
.recht section + section { margin-top: 40px; }
.recht h2 {
  font-size: 1.25rem; letter-spacing: -.015em; margin: 0 0 12px;
  /* Damit die Ueberschrift beim Sprung aus dem Verzeichnis nicht unter
     der Kopfleiste klebt. */
  scroll-margin-top: 96px;
}
.recht h3 { font-size: 0.9688rem; margin: 24px 0 8px; color: var(--heading); }
.recht p { margin: 0 0 12px; font-size: 0.9375rem; line-height: 1.7; color: var(--muted); }
.recht strong { color: var(--text); }
.recht ul { margin: 0 0 14px; padding-left: 20px; list-style: disc; }
.recht li { font-size: 0.9375rem; line-height: 1.7; color: var(--muted); margin-bottom: 6px; }
.recht code {
  font: 0.8125rem/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--surface-muted); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 5px; color: var(--text);
}

/* Der Kasten ganz oben: die Antwort fuer die, die nicht achtzehn
   Abschnitte lesen wollen — und das sind die meisten. */
.recht-kasten {
  background: var(--surface-muted); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 20px 22px; margin-bottom: 40px;
}
.recht-kasten-titel {
  margin: 0 0 8px !important; font-size: 0.75rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.recht-kasten p:last-child { margin-bottom: 0; }

.recht-anschrift {
  background: var(--surface-muted); border-left: 3px solid var(--accent);
  padding: 14px 18px; border-radius: 0 6px 6px 0; line-height: 1.7;
}

.recht-dl { margin: 0 0 14px; }
.recht-dl > div { padding: 10px 0; border-bottom: 1px solid var(--border); }
.recht-dl > div:last-child { border-bottom: 0; }
.recht-dl dt { margin-bottom: 3px; }
.recht-dl dd { margin: 0; font-size: 0.9062rem; line-height: 1.6; color: var(--muted); }

.recht-tab { width: 100%; border-collapse: collapse; margin: 4px 0 16px; }
.recht-tab th, .recht-tab td {
  text-align: left; vertical-align: top; padding: 11px 14px 11px 0;
  border-bottom: 1px solid var(--border); font-size: 0.875rem; line-height: 1.6;
}
.recht-tab th {
  font-size: 0.75rem; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
.recht-tab td { color: var(--muted); }
.recht-tab td:first-child { color: var(--text); font-weight: 500; padding-right: 20px; }

@media (max-width: 900px) {
  /* Das Verzeichnis wandert nach oben und klappt zusammen: eine
     angeheftete Spalte auf einem Telefon waere der halbe Bildschirm. */
  .recht-layout { grid-template-columns: 1fr; gap: 28px; }
  .recht-rail {
    position: static; border: 1px solid var(--border);
    border-radius: var(--radius); padding: 16px 18px;
    background: var(--surface);
  }
  .recht-rail ol { max-height: none; columns: 2; column-gap: 24px; }
  .recht { max-width: none; }
}
@media (max-width: 560px) {
  .recht-rail ol { columns: 1; }
  .recht-kopf { padding: 34px 0 26px; }
}

/* Filterleiste des Archivs — mehr Felder als die gewöhnliche Werkzeugleiste. */
.archive-filter .input[type="date"] { width: auto; min-width: 150px; }
@media (max-width: 720px) {
  .archive-filter .input[type="date"] { width: 100%; }
}

/* Freie Dokumentationsseiten */
.doc-body h2 { font-size: 1.25rem; margin: 22px 0 8px; }
.doc-body h3 { font-size: 1.0625rem; margin: 18px 0 6px; }
.doc-body h4 { font-size: 0.9375rem; margin: 16px 0 6px; }
.doc-body > *:first-child { margin-top: 0; }
.doc-body p { margin-bottom: 10px; line-height: 1.65; }
.doc-list { list-style: disc; padding-left: 22px; margin-bottom: 12px; }
.doc-list li { margin-bottom: 4px; }
.doc-body code {
  font: 0.8125rem/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--surface-muted); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 5px;
}
.doc-code {
  background: var(--indigo-900); color: #e6e8f2; border-radius: var(--radius-sm);
  padding: 14px 16px; overflow-x: auto; margin-bottom: 14px;
}
.doc-code code { background: none; border: 0; padding: 0; color: inherit; }

/* Eine Zeile, die nicht mehr gilt — abgeschalteter Port etwa. */
tr.is-muted td { opacity: .55; }

/* Reiter mit Symbol */
.tabs a svg { width: 16px; height: 16px; margin-right: 6px; opacity: .7; }
.tabs a[aria-current="page"] svg { opacity: 1; }

/* --- 7) Anhänge ---------------------------------------------------------- */

.attach-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 14px;
  padding: 18px 22px;
}

.attach-item { margin: 0; }
.attach-item a { display: block; }
.attach-item img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: 10px; border: 1px solid var(--border);
  background: var(--surface-muted);
  transition: border-color .15s;
}
.attach-item a:hover img { border-color: var(--accent); }

.attach-item figcaption { margin-top: 7px; }
.attach-name {
  display: block; font-size: 0.8125rem; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.attach-meta { display: block; font-size: 0.6875rem; color: var(--muted); }

/* Dateiauswahl sieht sonst je nach Browser sehr unterschiedlich aus. */
input[type="file"] {
  padding: 9px 11px; height: auto; cursor: pointer;
}
input[type="file"]::file-selector-button {
  margin-right: 12px; padding: 7px 14px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-muted); color: var(--text);
  font: 500 0.8125rem var(--font); cursor: pointer;
}
input[type="file"]::file-selector-button:hover { background: var(--border); }

@media (max-width: 720px) {
  .attach-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); padding: 16px; }
}

/* --- 8) Beleg ------------------------------------------------------------ */
/*
  Die Rechnung als Blatt.

  Am Bildschirm liegt sie auf grauem Grund wie Papier auf einem Tisch, auf
  dem Drucker füllt sie die Seite. Die Masse sind Millimeter, nicht Pixel:
  ein Beleg wird gedruckt, und der Zahlteil unten muss auf den Zehntel
  stimmen — die Bank misst nach.

  Farben: schwarz auf weiss, ein einziger blauer Strich als Herkunftszeichen.
  Ein bunter Beleg wirkt nicht freundlicher, sondern unseriös.
*/
.sheet-body { background: var(--surface-muted); }

.sheet-bar {
  display: flex; gap: 10px; align-items: center; justify-content: flex-end;
  max-width: 210mm; margin: 12px auto; padding: 0 6px;
}

/*
  Ein Blatt ist ein Blatt: 210 × 297 mm, nicht mehr und nicht weniger.

  Aufgebaut als Spalte — der Inhalt oben wächst, der Zahlteil unten bleibt
  am Rand kleben. Ohne diese Aufteilung müsste der Zahlteil absolut
  positioniert werden, und langer Text liefe darüber.
*/
.sheet {
  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  width: 210mm; min-height: 297mm;
  margin: 0 auto 24px;
  padding: 18mm 18mm 0;
  background: #fff;
  color: #101423;
  box-shadow: var(--shadow-lg);
}

/* Der Inhalt nimmt allen Platz, der nicht dem Zahlteil gehört. */
.sheet-main { flex: 1 1 auto; min-height: 0; }

/*
  Der eine Strich in Markenfarbe — oben quer über das Blatt.

  Zweieinhalb Millimeter, nicht vier: bei vier wirkte er wie ein Balken
  und nahm dem Logo darunter die Aufmerksamkeit. Ein Beleg soll seine
  Herkunft zeigen, nicht sie ausrufen.
*/
.sheet::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 2.5mm;
  background: var(--accent);
}

.sheet-head { display: flex; justify-content: space-between; gap: 20mm; margin-bottom: 14mm; }
.sheet-logo { display: block; height: 9mm; width: auto; margin-bottom: 5mm; }
.sheet-issuer { margin: 0; font-size: 9pt; line-height: 1.5; color: #5b6480; }

/* Der Anschriftblock sitzt dort, wo das Fenster im Couvert ist. */
.sheet-to { margin: 16mm 0 0; font-style: normal; font-size: 11pt; line-height: 1.5; }

.sheet-meta { display: flex; justify-content: space-between; align-items: flex-end; gap: 12mm;
              padding-bottom: 4mm; border-bottom: 1px solid #d7dced; }
.sheet-meta h1 { margin: 0; font-size: 17pt; letter-spacing: -.01em; }
.sheet-meta dl { display: grid; gap: 1.5mm; margin: 0; font-size: 9pt; }
.sheet-meta dl > div { display: flex; gap: 6mm; justify-content: space-between; }
.sheet-meta dt { color: #5b6480; }
.sheet-meta dd { margin: 0; font-weight: 600; }

.sheet-site { margin: 4mm 0 0; font-size: 9pt; color: #5b6480; }
.sheet-site .k { display: inline-block; min-width: 30mm; font-weight: 600; color: #101423; }

/*
  Die Tabelle steht bewusst nicht auf den Tabellenregeln der Anwendung: dort
  sind Zeilen anklickbar, hier ist eine Zeile eine Position auf einem Beleg.
  Alles wird deshalb neu gesetzt — auch das, was gleich aussieht.
*/
.sheet-table { width: 100%; border-collapse: collapse; margin-top: 10mm;
               font-size: 10pt; line-height: 1.4; font-variant-numeric: tabular-nums; }
.sheet-table th,
.sheet-table td { padding: 2.5mm 4mm 2.5mm 0; text-align: left; vertical-align: top;
                  background: none; text-transform: none; letter-spacing: 0;
                  white-space: normal; }
.sheet-table th { font-size: 8.5pt; font-weight: 600; color: #5b6480;
                  border-bottom: 1px solid #101423; padding-bottom: 2mm; }
.sheet-table td { border-bottom: 1px solid #eceff6; }
.sheet-table th:last-child,
.sheet-table td:last-child { padding-right: 0; }
.sheet-table th.right, .sheet-table td.right { text-align: right; }
.sheet-table tbody tr:hover { background: none; }
.sheet-table tbody tr:last-child td { border-bottom: 1px solid #eceff6; }
/* „Gesamtbetrag CHF" darf nicht umbrechen — zweizeilig sieht es aus wie
   ein Fehler und schiebt die Zahl daneben aus dem Blatt. */
.sheet-table tfoot td { border: 0; background: none; padding-top: 2mm; padding-bottom: 0;
                        color: #5b6480; white-space: nowrap; }
.sheet-table tfoot .is-total td { padding-top: 3mm; font-size: 12pt; font-weight: 700;
                                  color: #101423; border-top: 1px solid #101423;
                                  background: none; }
/* Die leere Zelle trägt keinen Strich — sonst liefe er über das ganze Blatt. */
.sheet-table tfoot td.is-blank { border: 0; }

.sheet-note  { margin: 8mm 0 0; font-size: 9.5pt; white-space: pre-wrap; }
.sheet-terms { margin: 8mm 0 0; font-size: 9pt; line-height: 1.5; color: #5b6480; }

/*
  Der Zahlteil: 105 mm hoch, über die volle Blattbreite. Der negative
  Aussenabstand hebt den Seitenrand des Blattes wieder auf — der Zahlteil
  geht bis an die Kante, so verlangt es die Norm.
*/
/*
  DER ZAHLTEIL IST 210 x 105 MM. IMMER.

  Das ist keine Gestaltungsfrage, sondern die Richtlinie von SIX: der
  QR-Code misst 46 x 46 mm, und ein Lesegeraet bei der Bank rechnet
  damit. Schrumpft das Blatt — weil der Drucker einen Rand erzwingt oder
  im Druckfenster «an Seitengroesse anpassen» steht —, schrumpft sonst
  alles mit. Gemessen: bei einer Seitenbreite von 200 statt 210 mm wurde
  aus dem Code einer von 43.81 mm. Das faellt niemandem auf, bis eine
  Zahlung nicht eingelesen werden kann.

  Zwei Regeln verhindern das:

    * `max-width: none` haelt die allgemeine Regel `img, svg, video {
      max-width: 100% }` von diesem einen SVG fern. Sie ist fuer Bilder
      im Fliesstext gedacht und richtig — hier macht sie aus einem
      genormten Beleg eine Abbildung, die sich dem Platz anpasst.
    * `flex-shrink: 0`, damit die Spalte des Blattes ihn nicht zusammen-
      druecken kann.

  Lieber laeuft der Zahlteil ueber den Papierrand hinaus, als dass er
  verkleinert wird: ein abgeschnittener Rand ist sichtbar und wird
  behoben, ein um vier Prozent zu kleiner QR-Code nicht.
*/
.sheet-slip {
  flex: 0 0 105mm;
  height: 105mm;
  margin: 6mm -18mm 0;
  /*
    KEIN `border-top` mehr.

    Die Trennlinie zeichnet das SVG selbst (`M0 0 H210`), gestrichelt,
    wie es die Richtlinie fuer die Abtrennkante vorsieht. Die zusaetzliche
    Linie hier war erstens doppelt und zweitens der Grund fuer ein zweites
    Blatt: bei `box-sizing: border-box` nahm sie 0.26 mm von der Hoehe
    weg, das SVG ragte um genau diesen Betrag hinaus, und der Drucker
    warf dafuer eine leere Seite aus.
  */
  break-inside: avoid;
  page-break-inside: avoid;
}
.sheet-slip svg {
  display: block;
  width: 210mm; height: 105mm;
  max-width: none; flex-shrink: 0;
}

/* Auf dem eigenen Blatt: wozu der Zahlteil gehört. */
.sheet-slip-ref { margin: 0; text-align: right; font-size: 10pt; line-height: 1.5; }
.sheet-slip-ref .muted { color: #5b6480; }

/* Ein storniertes Blatt trägt es quer über der Fläche. */
.sheet-stamp {
  position: absolute; top: 90mm; left: 0; right: 0; margin: 0;
  transform: rotate(-14deg);
  font-size: 44pt; font-weight: 700; letter-spacing: .08em; text-align: center;
  color: var(--danger-fg); opacity: .16; pointer-events: none;
}

@media (max-width: 230mm) {
  /* Auf dem Telefon wird das Blatt geschoben, nicht gestaucht: ein
     zusammengedrückter Beleg ist keiner mehr. */
  .sheet-body { overflow-x: auto; }
  .sheet, .sheet-bar { margin-left: 8px; margin-right: 8px; }
}

@media print {
  /* Papier bringt seinen eigenen Rand mit — hier steht nur der Inhalt. */
  /*
    Das Mass ausgeschrieben statt «A4».

    `size: A4` uebersetzt Chrome in 595 x 842 Punkt — das sind 209.90 x
    296.98 mm und nicht 210 x 297. Ein Blatt, das 210 mm breit ist, ragt
    dann um einen Zehntelmillimeter hinaus, und der Druck warf dafuer
    eine zweite, leere Seite aus. Ein Zehntelmillimeter sieht kein Mensch,
    eine leere Seite im Couvert jeder.
  */
  @page { size: 210mm 297mm; margin: 0; }
  .sheet-body { background: #fff; }
  .no-print { display: none !important; }

  /*
    DAS WURZELELEMENT DARF IM DRUCK KEIN SCROLLKASTEN SEIN.

    Weiter oben steht `html, body { max-width: 100%; overflow-x: clip }`.
    Auf dem Bildschirm ist die Regel richtig und wichtig — sie verhindert,
    dass ein zu breites Element die ganze Seite auf einem Telefon
    seitwaerts schiebbar macht.

    Im Druck macht `overflow` aus `html` einen eigenen Scrollkasten, und
    ein Scrollkasten wird nicht auf Seiten umbrochen, sondern als Ganzes
    gesetzt. Das Ergebnis war eine zweite, leere Seite hinter JEDER
    Rechnung — also ein leeres Blatt in jedem Couvert.

    Gefunden wurde es, indem im Druck nacheinander Regeln abgeschaltet
    wurden: mit `overflow: visible` auf `html` blieb es bei einer Seite,
    mit allem anderen nicht. Die Hoehe des Blattes war nie die Ursache;
    an ihr war vorher schon von 297 auf 296 mm gedreht worden, ohne dass
    es half — ein Hinweis darauf, dass die Erklaerung nicht stimmte.
  */
  html, body { overflow: visible !important; max-width: none; }

  /*
    297 mm — das volle Blatt.

    Hier stand 296 mm, mit der Begruendung, ein randloses Blatt kippe
    sonst durch Rundung auf eine zweite Seite. Die Beobachtung stimmte,
    die Erklaerung nicht: schuld war `overflow-x: clip` auf `html` (siehe
    oben), und der fehlende Millimeter half nicht dagegen. Er hat nur den
    Zahlteil einen Millimeter vom unteren Rand weggezogen.
  */
  /*
    210 mm, ausgeschrieben — nicht `auto`.

    `auto` heisst «so breit wie der Kasten darum», und wie breit der ist,
    entscheidet der Druckertreiber: randlos sind es 210 mm, mit Rand
    weniger. Damit haengt die Groesse des Zahlteils an einer Einstellung
    im Druckfenster, und der QR-Code ist mal genormt und mal nicht.
  */
  .sheet { width: 210mm; min-height: 297mm; margin: 0; box-shadow: none;
           padding: 18mm 18mm 0; }

  /* Jedes weitere Blatt beginnt auf einer neuen Seite. */
  .sheet + .sheet { break-before: page; page-break-before: always; }

  /* Farbflächen sollen gedruckt werden — sonst fehlt der Markenstrich und
     der Zahlteil verliert seine Trennlinien. */
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* --- Passkeys ------------------------------------------------------------ */
/*
  Der Trenner zwischen Passwort und Passkey.

  Eine Linie mit einem Wort darin — nicht bloss ein Abstand. Zwei
  Anmeldewege untereinander ohne Trennung liest man als einen Ablauf
  («erst tippen, dann klicken»); mit dem Wort «oder» ist auf einen Blick
  klar, dass es zwei Wege sind.
*/
.passkey-trenner {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 0; color: var(--muted); font-size: 0.8125rem;
}
.passkey-trenner::before,
.passkey-trenner::after {
  content: ""; flex: 1 1 auto; height: 1px; background: var(--border);
}

/*
  Die Rueckmeldung steht IMMER an derselben Stelle.

  Waehrend der Browser auf den Fingerabdruck wartet, steht hier «Warten
  auf Ihre Bestaetigung am Geraet». Springt der Text je nach Zustand
  woanders hin, sucht man ihn — und drueckt derweil ein zweites Mal.
*/
.passkey-meldung {
  margin: 10px 0 0; font-size: 0.8125rem; line-height: 1.45; color: var(--muted);
}
.passkey-meldung.is-ok     { color: var(--success-fg); }
.passkey-meldung.is-warn   { color: var(--warning-fg); }
.passkey-meldung.is-fehler { color: var(--danger-fg); }

/*
  Der Passkey-Teil der Anmeldung.

  Er steht jetzt ganz oben und fragt beim Oeffnen von selbst. Der Satz
  darueber erklaert, warum sich gerade ein Fenster meldet — ohne ihn
  sieht es aus, als verlange die Seite etwas Unerwartetes.
*/
.passkey-start { margin-bottom: 4px; }
.passkey-hinweis {
  margin: 0 0 14px; font-size: 0.875rem; line-height: 1.5; color: var(--muted);
}
/* Das zugeklappte Passwortformular bekommt Abstand, wenn es aufgeht. */
[data-passwort-form]:not([hidden]) { margin-top: 18px; }

/* Name und Knopf nebeneinander, solange Platz ist. */
.passkey-anlegen {
  display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap;
  margin-top: 16px;
}
.passkey-anlegen .field { flex: 1 1 240px; }
/* Der Knopf steht auf der Grundlinie des Feldes, nicht der Beschriftung. */
.passkey-anlegen .btn { margin-top: 22px; }
@media (max-width: 520px) {
  .passkey-anlegen .btn { margin-top: 0; width: 100%; }
}

/* --- 9) Backoffice-Übersicht --------------------------------------------- */
/*
  Was jetzt ansteht.

  Steht ganz oben, vor allen Zahlen: eine Übersicht soll nicht berichten,
  sondern zum Handeln bringen. Erscheint nur, wenn es wirklich etwas zu tun
  gibt — eine Liste, in der immer dasselbe steht, wird nach einer Woche
  überlesen.

  Der Ton kommt von links: ein Balken an der Kante statt einer farbigen
  Fläche. Damit bleiben drei Punkte untereinander lesbar, und der Text
  behält seinen normalen Kontrast.
*/
.todo-list { display: grid; gap: 10px; margin-bottom: 28px; }

.todo {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.todo-body { flex: 1 1 auto; min-width: 0; }
.todo-title { margin: 0; font-weight: 600; color: var(--heading); }
.todo-text  { margin: 2px 0 0; font-size: 0.8125rem; color: var(--muted); }
.todo .btn  { flex-shrink: 0; }

.todo-icon {
  flex-shrink: 0;
  width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center; font-size: 1.0625rem;
  background: var(--surface-muted); color: var(--muted);
}

.todo.is-danger  { border-left-color: var(--danger-fg); }
.todo.is-warning { border-left-color: var(--warning-fg); }
.todo.is-info    { border-left-color: var(--accent); }
.todo.is-danger  .todo-icon { background: var(--danger-bg);  color: var(--danger-fg); }
.todo.is-warning .todo-icon { background: var(--warning-bg); color: var(--warning-fg); }
.todo.is-info    .todo-icon { background: var(--accent-soft); color: var(--accent-soft-text); }

@media (max-width: 640px) {
  /* Am Telefon steht der Knopf unter dem Text statt daneben. */
  .todo { flex-wrap: wrap; }
  .todo-body { flex-basis: 100%; }
  .todo .btn { margin-left: 48px; }
}

/* Zwischenüberschrift über einer Reihe Kacheln. */
.section-title {
  margin: 0 0 12px;
  font-size: 0.8125rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted);
}

/*
  Die Verteilung auf die Pläne als ein Balken.

  Das Verhältnis ist die Aussage, nicht die einzelne Zahl — vier Zeilen
  untereinander muss man erst im Kopf ins Verhältnis setzen.
*/
.plan-bar { display: flex; height: 10px; border-radius: 999px; overflow: hidden;
            background: var(--surface-muted); margin-bottom: 14px; }
.plan-seg { display: block; min-width: 3px; }

.plan-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; }

/* Dieselben Farben wie die Plan-Abzeichen — sonst gehören Balken und
   Beschriftung optisch nicht zusammen. */
.plan-seg.is-trial,      .plan-dot.is-trial      { background: var(--warning-fg); }
.plan-seg.is-starter,    .plan-dot.is-starter    { background: var(--muted); }
.plan-seg.is-pro,        .plan-dot.is-pro        { background: var(--accent); }
.plan-seg.is-enterprise, .plan-dot.is-enterprise { background: var(--success-fg); }


/*
  Das Zeichen für einen Datensatz aus dem Verzeichnis.

  Bewusst schmaler und ruhiger als ein Statusabzeichen: es steht neben
  einem Namen und beantwortet eine Nebenfrage — woher kommt dieser
  Datensatz. Die Statusabzeichen daneben tragen die Hauptaussage und
  dürfen davon nicht überstrahlt werden.

  Der gepunktete Rahmen sagt „gebunden, nicht frei" — dieselbe Sprache wie
  ein gesperrtes Feld.
*/
.badge-ad {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px dashed var(--accent-line);
  border-radius: 5px;
  background: var(--accent-soft);
  color: var(--accent-soft-text);
  font-size: 0.625rem; font-weight: 700; letter-spacing: .06em;
  vertical-align: 2px;
  cursor: help;
}

/*
  Gesicht neben dem Namen.

  Rund, weil ein Mensch kein Datensatz ist — die Bauteile daneben sind
  alle eckig, und genau darum liest sich der Kreis sofort als Person.
  Ohne Bild die Initialen: sie sagen wenigstens, wer gemeint ist, und
  zwanzig Zeilen mit Initialen sind ruhiger als zwanzig gleiche graue
  Silhouetten.
*/
.with-avatar { display: flex; align-items: center; gap: 12px; min-width: 0; }

/* Mit Bild braucht die Namensspalte etwas mehr Raum — sonst bricht
   „Brunner, Peter" auf zwei Zeilen und die Zeile wird doppelt hoch. */
.table-wrap td:has(> .with-avatar) { min-width: 210px; }

.avatar-img {
  flex-shrink: 0;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-muted);
}

.avatar-img.is-initials {
  display: inline-grid; place-items: center;
  background: var(--indigo-50);
  color: var(--indigo-700);
  font-weight: 600; letter-spacing: .02em;
}


/*
  Das Wartefenster.

  Eine Drehscheibe aus einem Rand — kein Bild, keine Schrift, nichts
  nachzuladen. Sie muss auch dann laufen, wenn gerade die Verbindung das
  Problem ist.
*/
.dialog.is-busy .dialog-body { text-align: center; }

.spinner {
  width: 34px; height: 34px;
  margin: 4px auto 14px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .8s linear infinite;
}

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

/*
  Wer sich an Bewegung stört, bekommt keine. Der Punkt pulsiert dann nur
  noch schwach — ganz ohne Zeichen wüsste niemand, ob überhaupt etwas läuft.
*/
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: pulse 1.6s ease-in-out infinite; border-top-color: var(--border); }
  @keyframes pulse { 50% { opacity: .35; } }
}

/*
  Das Personalformular.

  Acht Eingaben nebeneinander sind eine Wand — man liest sie nicht, man
  arbeitet sie ab. Nach Bedeutung gruppiert und mit Luft dazwischen findet
  das Auge, was es sucht.

  Der Abstand zwischen den Gruppen ist doppelt so gross wie der zwischen
  den Feldern einer Gruppe: **daran** erkennt man, dass sie zusammengehören,
  nicht an einer Linie.
*/
.person-form { display: grid; gap: 28px; }

.person-form-row { display: flex; align-items: flex-start; gap: 24px; }

/* Die Überschrift einer Feldgruppe — leise, aber vorhanden. */
.form-section {
  margin: 0 0 12px;
  font-size: 0.75rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted);
}

/* Das Bild neben den Namensfeldern. */
.person-portrait {
  flex-shrink: 0;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding-top: 26px;          /* auf Höhe der ersten Eingabe, nicht des Etiketts */
  text-align: center;
  max-width: 110px;
}
.person-portrait .cell-sub { font-size: 0.6875rem; line-height: 1.3; }


/* Das eigene Konto: Bild links, Angaben rechts. Auf schmalen Fenstern
   untereinander — 88 Pixel plus zwei Spalten Angaben passen dort nicht. */
.me-card {
  display: flex; align-items: flex-start; gap: 24px;
  padding: 18px 20px 20px;
}
.me-portrait {
  flex-shrink: 0;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  text-align: center; max-width: 110px;
}
.me-portrait .cell-sub { font-size: 0.6875rem; line-height: 1.3; }

/*
  Das Bild in gross, ueber der Seite statt an ihrer Stelle.

  Kein Rahmen, kein Hintergrund: das Bild soll den Platz haben, nicht das
  Fenster darum. Der abgedunkelte Grund kommt von ::backdrop.
*/
.lightbox {
  padding: 0; border: 0; background: transparent;
  max-width: none; max-height: none;
  width: 100%; height: 100%;
  display: none;
  place-items: center;
  overflow: hidden;
}
.lightbox[open] { display: grid; }
.lightbox::backdrop { background: rgba(11, 15, 25, .82); }
.lightbox img {
  max-width: min(92vw, 1100px); max-height: 88vh;
  width: auto; height: auto;
  object-fit: contain;
  border-radius: var(--radius-sm);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .45);
  background: var(--surface);
}
.lightbox-close {
  position: fixed; top: 14px; right: 18px;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .14); color: #fff;
  font: 400 1.625rem/1 var(--font); cursor: pointer;
}
.lightbox-close:hover { background: rgba(255, 255, 255, .26); }

/* Ein Bild, das sich anklicken laesst, sagt das auch. */
a[data-lightbox] { display: inline-block; cursor: zoom-in; }
a[data-lightbox]:hover img { opacity: .92; }

/*
  Zwei-Schritt-Anmeldung einrichten.

  QR-Code links, die drei Schritte rechts. Untereinander waere der Code
  gross und die Anleitung weit weg von ihm — man scannt und liest hier
  gleichzeitig.
*/
.totp-setup { display: flex; align-items: flex-start; gap: 26px; flex-wrap: wrap; }
.totp-qr {
  flex: 0 0 auto; padding: 10px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: #fff;
}
.totp-steps { flex: 1; min-width: 240px; }
/*
  Eine nummerierte Liste braucht Nummern.

  Weiter oben steht `ul, ol { list-style: none }` — richtig, denn die
  meisten Listen hier sind Aufzaehlungen ohne Punkte. `.steps` ist die
  Ausnahme: es ist eine Reihenfolge («erst die App oeffnen, dann
  scannen»), und ohne Nummern liest sie sich wie drei unverbundene
  Saetze. Der Einzug von 20px war die ganze Zeit fuer Marken reserviert,
  die nie kamen.
*/
.steps { margin: 0 0 14px; padding-left: 20px; font-size: 0.875rem; line-height: 1.7;
         list-style: decimal; }
.steps li { padding-left: 2px; }
.totp-secret {
  display: inline-block; margin-top: 4px; padding: 7px 10px;
  border-radius: var(--radius-sm); background: var(--surface-muted);
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.875rem; letter-spacing: .08em; user-select: all;
}
/* Die Ersatzcodes stehen untereinander und werden abgetippt oder gedruckt. */
.totp-codes {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.875rem; letter-spacing: .06em; line-height: 1.8;
}
.me-card .dl { flex: 1; min-width: 0; }
/* Die Zeilen bringen ihren eigenen Rand mit; hier stellt ihn schon die
   Karte, sonst rückte die Liste doppelt ein. */
.me-card .dl > div { padding-left: 0; padding-right: 0; }
.me-card .dl > div:first-child { padding-top: 0; }

@media (max-width: 560px) {
  .me-card { flex-direction: column; gap: 16px; }
}

@media (max-width: 640px) {
  /* Am Telefon steht das Bild über den Feldern statt daneben. */
  .person-form-row { flex-direction: column; align-items: flex-start; }
  .person-portrait { flex-direction: row; padding-top: 0; max-width: none; }
}

/* ==========================================================================
   10) Verkaufsseite — Aufmacher, Abschnitte, Aufruf

   Die Seite war ordentlich und darum austauschbar: helle Flaeche, helle
   Karten, eine blaue Schaltflaeche. Sie sagte nichts darueber, was fuer
   ein Ding dahinter steht.

   Drei Eingriffe, mehr nicht:

     * Eine dunkle Flaeche traegt Kopfzeile, Aufmacher und Schlussaufruf.
       Sie klammert die Seite und gibt dem Hellen dazwischen einen Rahmen.
     * Die Bildschirmfotos stehen in einem Fensterrahmen. Ein Foto ohne
       Rahmen ist ein Bild; mit Rahmen ist es Software.
     * Die Abschnitte sind nummeriert. Das ordnet eine lange Seite, ohne
       dass eine Zeile Text dazukommt.

   Alles andere bleibt: dieselben Farben, dieselbe Schrift, dieselben
   Bauteile. Es ist kein neues Kleid, es ist Haltung.
   ========================================================================== */

/* --- Kopfzeile auf der dunklen Flaeche ----------------------------------- */

.site-head {
  background: var(--ink);
  border-bottom: 1px solid var(--ink-border);
}
/* Die Wortmarke braucht hier immer die helle Fassung — unabhaengig davon,
   was das Betriebssystem gerade will. */
.site-head .brand-lockup.is-light { display: none; }
.site-head .brand-lockup.is-dark  { display: inline-block; }

.site-nav a { color: var(--on-ink-muted); }
.site-nav a:hover { color: var(--on-ink); text-decoration: none; }

/* Der Globus-Knopf im dunklen Verkaufskopf braucht helle Farben. Das
   aufgeklappte Panel bleibt hell (siehe .sprachwahl-panel) und liest sich
   auf dunklem wie hellem Kopf gleich. */
.site-head .sprachwahl-knopf { color: var(--on-ink-muted); }
.site-head .sprachwahl-knopf:hover,
.site-head .sprachwahl-drop:hover .sprachwahl-knopf,
.site-head .sprachwahl-drop:focus-within .sprachwahl-knopf { color: var(--on-ink); }

/* --- Klappmenues in der Kopfzeile ---------------------------------------
   Damit am Schreibtisch dieselben Wege offenstehen wie am Telefon.

   Vorher trug die Kopfzeile vier Verweise und das Klappmenue fuenfzehn:
   eine Modulseite war nur ueber den Umweg der Uebersicht erreichbar, und
   „Hilfe" fehlte am grossen Bildschirm ganz. Beide Menues speisen sich
   jetzt aus Marketing::MODULES und ::AUDIENCES und koennen nicht mehr
   auseinanderlaufen.

   Ohne JavaScript: :hover fuer die Maus, :focus-within fuer die Tastatur.
   Der Oberpunkt bleibt ein echter Verweis — wer klickt statt zu warten,
   landet auf der Uebersichtsseite.

   Die Leiste spannt sich ueber die volle Hoehe der Kopfzeile, damit
   zwischen Verweis und Klappkasten keine Luecke bleibt: ein Zeiger, der
   durch eine solche Luecke faehrt, schliesst das Menue mitten im Weg. */
.site-head .site-nav { align-self: stretch; align-items: stretch; gap: 4px; }
.site-head .site-nav > a,
.nav-drop-top { display: inline-flex; align-items: center; padding: 0 10px; }

.nav-drop { position: relative; display: flex; }
.nav-drop-top { gap: 5px; cursor: pointer; }
.nav-drop-arrow { width: 14px; height: 14px; transform: rotate(90deg);
                  opacity: .6; transition: transform .16s ease, opacity .16s ease; }
.nav-drop:hover .nav-drop-arrow,
.nav-drop:focus-within .nav-drop-arrow { transform: rotate(270deg); opacity: 1; }
.nav-drop:hover > .nav-drop-top,
.nav-drop:focus-within > .nav-drop-top { color: var(--on-ink); }

/* Wo bin ich? Die aktuelle Seite ist hell und unten blau unterstrichen,
   wie im Menü der Anwendung (seit 26.10.2026). Die Linie sitzt am
   unteren Rand der Kopfzeile, weil die Leiste deren volle Höhe hat. */
.site-head .site-nav > a[aria-current="page"],
.site-head .nav-drop-top[aria-current="page"] {
  color: var(--on-ink); box-shadow: inset 0 -2px 0 var(--on-ink-accent);
}

.nav-drop-panel {
  position: absolute; top: 100%; left: -8px; z-index: 30;
  display: grid; grid-template-columns: 1fr 1fr; gap: 2px;
  width: max-content; max-width: min(680px, calc(100vw - 48px));
  padding: 8px; border-radius: var(--radius);
  background: var(--ink); border: 1px solid var(--ink-border);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .45);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .14s ease, transform .14s ease, visibility .14s;
}
.nav-drop-panel.is-narrow { grid-template-columns: 1fr; }
.nav-drop:hover > .nav-drop-panel,
.nav-drop:focus-within > .nav-drop-panel {
  opacity: 1; visibility: visible; transform: translateY(0);
}

.nav-drop-panel a {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 9px 11px; border-radius: var(--radius-sm); color: var(--on-ink);
}
.nav-drop-panel a:hover { background: var(--ink-card); text-decoration: none; }
.nav-drop-panel a > svg { width: 17px; height: 17px; flex: none;
                          margin-top: 1px; color: var(--accent); }
.nav-drop-panel .drop-name { display: block; font-weight: 500; font-size: 0.8438rem; }
.nav-drop-panel .drop-text { display: block; margin-top: 1px;
                             font-size: 0.75rem; line-height: 1.4;
                             color: var(--on-ink-muted); }

/* Zwischen 760 und 900 px wird es in der Leiste eng: der Klappkasten
   bleibt, die zwei einzelnen Verweise ruecken enger zusammen. */
@media (max-width: 900px) {
  .site-head .site-nav { font-size: 0.8438rem; }
  .site-head .site-nav > a, .nav-drop-top { padding: 0 7px; }
}

.site-head .btn-ghost {
  color: var(--on-ink);
  border-color: var(--ink-border);
  background: var(--ink-card);
}
.site-head .btn-ghost:hover { background: rgba(255, 255, 255, .12); }

.site-menu > summary { color: var(--on-ink); }
.site-menu .burger span { background: var(--on-ink); }

/* --- Aufmacher ----------------------------------------------------------- */

.hero-dark {
  position: relative;
  background: var(--ink);
  border-bottom: 0;
  color: var(--on-ink);
  overflow: hidden;
  /* Isolierung, damit der Schein darunter bleibt und nicht ueber die
     Kopfzeile der naechsten Sektion greift. */
  isolation: isolate;
}

/*
  Der Schein hinter dem Text.

  Zwei weiche Kreise in der Markenfarbe, sehr schwach — sie sollen Tiefe
  geben, nicht leuchten. Dazu ein Punktraster, das nach unten ausblendet:
  es macht die Flaeche zu einem Ort statt zu einem Rechteck. Beides rein
  dekorativ, deshalb aria-hidden im Markup und pointer-events: none hier.
*/
.hero-glow {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(58% 68% at 10% 4%,  rgba(18, 87, 229, .30), transparent 62%),
    radial-gradient(48% 58% at 90% 26%, rgba(77, 128, 239, .16), transparent 64%);
}
/*
  VERSUCH: Video hinter dem Hero.  ——  NICHT FUER DIE PRODUKTION
  Siehe den Block in pages/marketing/home.php. Zum Entfernen: diese drei
  Regeln, den Block dort und den Eintrag in .deploy-exclude loeschen.

  DIE SCHICHTUNG

    -3  das Video
    -2  der Schleier
    -1  Schein und Punktraster (schon da)
     0  der Text

  Der Schein bleibt oben drauf, und das ist der Trick: er zieht das
  fremde Material ins Markenblau, statt dass ein Fremdvideo neben der
  Marke steht. Dazu entsaettigt und abgedunkelt — Stockmaterial sieht
  sonst nach Stockmaterial aus.
*/
.hero-dark.hat-bild { background: var(--ink); }
/*
  Das Standbild (seit 15.10.2026 statt des Stockvideos) ist schon
  weichgezeichnet und abgedunkelt abgelegt; hier nur noch die leichte
  Entsättigung, die fremdes Material zur Marke passen lässt.
*/
.hero-bild {
  position: absolute; inset: 0; z-index: -3; pointer-events: none;
  background: var(--ink) url("hero/hero-standbild.webp") center / cover no-repeat;
  filter: grayscale(.3) contrast(1.05);
}
@media (max-width: 960px) {
  .hero-bild { background-image: url("hero/hero-standbild-960.webp"); }
}
/*
  Zwei Verlaeufe uebereinander: einer quer (links dunkel, wo der Text
  steht), einer nach unten (damit die Kante zum naechsten Abschnitt
  nicht schneidet). Der Text braucht seinen Kontrast, nicht seinen
  Schatten — ein Schlagschatten auf 52px-Schrift sieht nach 2009 aus.
*/
.hero-scrim {
  position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background:
    linear-gradient(100deg,
      rgba(16, 20, 35, .92) 0%,
      rgba(16, 20, 35, .74) 34%,
      rgba(16, 20, 35, .28) 62%,
      rgba(16, 20, 35, .12) 100%),
    linear-gradient(to bottom, transparent 0%, rgba(16, 20, 35, .35) 72%, var(--ink) 99%);
}
/* Wer weniger Bewegung eingestellt hat, sieht die Vorführung still —
   dann gibt es nichts anzuhalten. */
@media (prefers-reduced-motion: reduce) {
  .hero-dark .bewegung-knopf { display: none; }
}

.hero-grid-lines {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, .05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 56px 56px;
  /* Nach unten ausblenden, damit die Kante zum naechsten Abschnitt weich ist. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 78%);
          mask-image: linear-gradient(to bottom, #000 0%, transparent 78%);
}

.hero-dark .eyebrow {
  background: var(--ink-card);
  border-color: var(--ink-border);
  color: var(--on-ink);
}
.hero-dark h1 {
  color: var(--on-ink);
  /* Waechst mit dem Fenster statt in drei Stufen zu springen. */
  font-size: clamp(1.875rem, 5.2vw, 3.25rem);
  line-height: 1.06;
  letter-spacing: -.03em;
  font-weight: 700;
}
.hero-dark .lead { color: var(--on-ink-muted); font-size: 1.0938rem; }
.hero-dark .small.muted { color: var(--on-ink-muted); }

/* Der Satz neben der Plakette steht auf dem dunklen Grund und braucht
   darum dieselbe helle Marke wie das uebrige Kleingedruckte im Hero. Der
   Verweis aufs Zertifikat wird hell unterstrichen statt blau: das
   Akzentblau ist auf --ink zu dunkel. */
.hero-dark .hero-label p { color: var(--on-ink-muted); }
.hero-dark .hero-label a { color: var(--on-ink); text-decoration: underline; }

/* Der zweite Knopf ist auf dunklem Grund ein Umriss, kein weisser Block:
   sonst streiten zwei Flaechen um dieselbe Aufmerksamkeit. */
.hero-dark .btn-secondary {
  background: var(--ink-card);
  border-color: var(--ink-border);
  color: var(--on-ink);
}
.hero-dark .btn-secondary:hover { background: rgba(255, 255, 255, .12); }

/* --- Fensterrahmen ------------------------------------------------------- */

/*
  Ein Bildschirmfoto ohne Rahmen ist ein Bild. Mit Rahmen ist es Software.
  Die drei Punkte und die Adresszeile sind Zierrat mit Funktion: sie sagen
  in einer Zehntelsekunde, dass man hier in ein Programm schaut.
*/
.browser {
  /* Bezugspunkt fuer den Zeiger der Selbstvorfuehrung. */
  position: relative;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: var(--surface);
  overflow: hidden;
  box-shadow: 0 24px 60px -20px rgba(10, 20, 45, .28);
}
.browser-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 13px;
  background: var(--surface-muted);
  border-bottom: 1px solid var(--border);
}
.browser-dots { display: flex; gap: 6px; flex: 0 0 auto; }
.browser-dots i {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--border);
}
.browser-url {
  flex: 1; min-width: 0;
  padding: 3px 10px; border-radius: 999px;
  background: var(--bg); border: 1px solid var(--border);
  font-size: 0.7188rem; color: var(--muted);
  text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.browser > .card { border: 0; border-radius: 0; box-shadow: none; margin: 0; }
.browser img { display: block; width: 100%; height: auto; }

/*
  Im Fensterrahmen gilt wieder die gewoehnliche Textfarbe.

  Ohne diese Zeile erbt der Inhalt das Weiss der dunklen Flaeche — und die
  Inventarnummern standen weiss auf weissem Grund. Ein Rahmen ist ein
  eigener Raum; er faengt die Vererbung ab.
*/
.browser { color: var(--text); }

/* Im Aufmacher steht der Rahmen auf dunklem Grund und braucht seine
   eigene Kante — die helle Bauteilkante verschwindet dort. */
.hero-dark .browser {
  border-color: rgba(255, 255, 255, .14);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .8), 0 0 0 1px rgba(255, 255, 255, .04);
}

/* --- Abschnittsköpfe ----------------------------------------------------- */

/*
  Nummer, Name, Linie. Eine lange Seite bekommt damit eine Ordnung, die
  man im Vorbeiscrollen mitliest — ohne dass ein einziges Wort dazukommt.
*/
.sec-head { max-width: 46em; }
.sec-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 0 0 16px; padding: 5px 12px; border-radius: 999px;
  font-size: 0.75rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase;
  background: var(--accent-soft); color: var(--accent-soft-text);
}
.sec-eyebrow b {
  font-weight: 800; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
/*
  Seit dem 30.09.2026 ein farbiges Schild statt «Nummer, Name, Linie»: die
  graue Linie war auf einer weissen Seite das Gegenteil eines Wegweisers.
*/
.section h2 { letter-spacing: -.025em; }
@media (min-width: 900px) { .sec-head h2 { font-size: 2.25rem; line-height: 1.15; } }

/* --- Systemstatus -------------------------------------------------------- */

/*
  Eine Zeile je Bauteil: Punkt, Name mit Erklaerung, Zustand rechts.

  Der Punkt traegt dieselbe Farbe wie die Marke daneben — doppelt gemoppelt
  mit Absicht. Wer die Seite ueberfliegt, sucht nach Rot und liest kein
  einziges Wort; wer sie liest, will den Zustand ausgeschrieben.
*/
.status-liste { list-style: none; margin: 0; padding: 0; }
.status-liste > li {
  display: flex; align-items: center; gap: 14px;
  padding: 16px 0;
  border-bottom: 1px solid var(--rule);
}
.status-liste > li:last-child { border-bottom: 0; }

.status-punkt {
  flex: none; width: 10px; height: 10px; border-radius: 50%;
  background: var(--muted);
}
.status-punkt.is-success { background: var(--success-fg); }
.status-punkt.is-warning { background: var(--warning-fg); }
.status-punkt.is-danger  { background: var(--danger-fg); }
.status-punkt.is-info    { background: var(--accent); }

.status-text { display: grid; gap: 2px; min-width: 0; flex: 1; }
.status-text strong { color: var(--heading); }
.status-text .muted { font-size: 0.875rem; }

/* Eine Notiz am Bauteil steht hervorgehoben: sie ist der Grund, warum
   jemand die Seite ueberhaupt geoeffnet hat. */
.status-notiz {
  margin-top: 4px; font-size: 0.875rem;
  color: var(--warning-fg);
}

.status-liste .badge { flex: none; }
.status-titel { margin: 0; font-size: 1.0625rem; }

/*
  Der Verlauf einer Stoerung: Zeit links, Meldung rechts.

  Meldungen werden nie ueberschrieben — wer spaeter fragt, was wann
  gesagt wurde, liest nach. Darum eine Liste und kein Feld, das sich
  aendert.
*/
.status-verlauf { list-style: none; margin: 0; padding: 0; }
.status-verlauf > li {
  display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 14px;
  padding: 12px 0; border-top: 1px solid var(--rule);
}
.status-zeit {
  font-size: 0.8125rem; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.status-meldung { font-size: 0.9062rem; }
.status-meldung strong { display: block; color: var(--heading); margin-bottom: 2px; }

@media (max-width: 560px) {
  .status-liste > li { flex-wrap: wrap; }
  .status-liste .badge { margin-left: 24px; }
  .status-verlauf > li { grid-template-columns: minmax(0, 1fr); gap: 4px; }
}

/* --- Aufruf am Schluss --------------------------------------------------- */

.cta {
  position: relative; overflow: hidden; isolation: isolate;
  background: var(--ink); color: var(--on-ink);
  border-top: 1px solid var(--ink-border);
}
.cta .wrap { padding-top: var(--abschnitt); padding-bottom: var(--abschnitt); text-align: center; }
.cta h2 {
  color: var(--on-ink); font-size: clamp(1.625rem, 3.6vw, 2.375rem);
  letter-spacing: -.025em; line-height: 1.15; margin: 0;
}
.cta p { color: var(--on-ink-muted); margin: var(--abstand-2) auto 0; max-width: 40em; font-size: 1.0312rem; }
.cta .row { justify-content: center; margin-top: 28px; }
.cta .btn-secondary {
  background: var(--ink-card); border-color: var(--ink-border); color: var(--on-ink);
}
.cta .btn-secondary:hover { background: rgba(255, 255, 255, .12); }
.cta .small { color: var(--on-ink-muted); }

/* --- Kennzahlenband ------------------------------------------------------ */

/*
  Vier Zahlen unter dem Aufmacher. Nicht als Erfolgsmeldung — dafuer ist
  das Haus zu jung —, sondern als Antwort auf die Fragen, die sonst erst
  im Gespraech kommen: Was kostet der Einstieg, wie lange dauert er, wo
  liegen die Daten, was passiert danach.
*/
.facts {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--ink-border);
}
/* Die erste Spalte beginnt an derselben Kante wie die Ueberschrift darueber,
   die letzte endet an derselben rechts — sonst steht das Band eingerueckt
   unter einem Text, mit dem es eine Flucht bilden sollte. */
.facts > div { padding: 26px 24px 30px; }
.facts > div:first-child { padding-left: 0; }
.facts > div:last-child { padding-right: 0; }
.facts > div + div { border-left: 1px solid var(--ink-border); }
.facts dt { font-size: 0.7812rem; letter-spacing: .06em; text-transform: uppercase;
            color: var(--on-ink-muted); font-weight: 600; }
.facts dd { margin: 8px 0 0; color: var(--on-ink); font-size: 1.375rem; font-weight: 600;
            letter-spacing: -.02em; line-height: 1.2; }
.facts dd span { display: block; margin-top: 5px; font-size: 0.8438rem; font-weight: 400;
                 color: var(--on-ink-muted); letter-spacing: 0; line-height: 1.45; }

@media (max-width: 860px) {
  .facts { grid-template-columns: 1fr 1fr; }
  .facts > div:nth-child(3) { border-left: 0; }
  .facts > div:nth-child(n+3) { border-top: 1px solid var(--ink-border); }
}
@media (max-width: 860px) {
  /* Die Flucht gilt auch zweispaltig: linke Spalte an der linken Kante,
     rechte an der rechten. */
  .facts > div:nth-child(odd)  { padding-left: 0; }
  .facts > div:nth-child(even) { padding-right: 0; }
}
@media (max-width: 480px) {
  .facts { grid-template-columns: 1fr; }
  .facts > div + div { border-left: 0; border-top: 1px solid var(--ink-border); }
  /* Einspaltig steht alles an derselben Kante wie der Text darueber. */
  .facts > div { padding: 20px 0 22px; }
}

/* --- Karten mit etwas mehr Haltung --------------------------------------- */

/*
  Das Zeichen bekommt einen leichten Verlauf und eine Kante. Flach wirkte
  es wie ein Platzhalter; so sieht man, dass es gesetzt wurde.
*/
.feature .icon {
  background: linear-gradient(160deg, var(--accent-soft), var(--surface));
  border: 1px solid var(--border);
}
.feature { transition: border-color .15s ease; }

@media (max-width: 720px) {
  .cta .wrap { padding-top: 52px; padding-bottom: 56px; }
  .browser-url { font-size: 0.6875rem; }
}

/* --- Preistafeln ---------------------------------------------------------- */

/*
  Die empfohlene Tafel wird blau ausgezeichnet, nicht schwarz.

  Ein blauer Rahmen allein ist eine Auszeichnung, die man suchen muss —
  deshalb stand die Tafel eine Zeit lang auf schwarzem Grund. Das war zu
  viel: ein schwarzer Block zwischen zwei weissen Blaettern liest sich
  wie ein Fremdkoerper, und der Preis, um den es geht, verliert dabei
  seine Ruhe.
*/
/*
  Rollenmarke statt Skalenwert — und das ist hier kein Schoenheitsfehler.

  Hier stand `var(--brand-50)`. Das ist ein Wert aus der Skala, und die
  Skala wird im dunklen Block nicht neu belegt: der Verlauf blieb hell,
  waehrend `--text` und `--heading` auf helle Schrift umsprangen. Auf der
  Karte «Am haeufigsten gewaehlt» waren damit «Pro», «pro Monat» und der
  Jahrespreis unlesbar — genau der Preis, um den es auf dieser Seite geht.

  `--accent-soft` ist die Rollenmarke fuer eine leicht eingefaerbte
  Flaeche und in beiden Modi belegt. Das ist der Grund, warum die Regel
  «ab Abschnitt 2 nur Rollenmarken» ueberhaupt existiert.
*/
.plan.featured {
  background: linear-gradient(170deg, var(--accent-soft), var(--surface) 62%);
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 24px 60px -26px rgba(18, 87, 229, .38);
  color: var(--text);
}
.plan.featured .price { color: var(--heading); }
.plan.featured .tag { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

/* Die Tafel ist etwas groesser als ihre Nachbarn — das ist die
   Auszeichnung, die man ohne Legende versteht. */
/* Das Anheben nur, solange die drei nebeneinander stehen — untereinander
   waere eine angehobene Tafel nur ein Versatz ohne Aussage. */
@media (min-width: 980px) {
  .plan.featured { transform: translateY(-10px); padding-bottom: 36px; }
}

/*
  Der Aufmacher der Startseite im mittleren Band.

  Zwischen 1000 und 1240 Pixeln steht das Raster noch zweispaltig — die
  Textspalte misst dann keine 500 Pixel —, waehrend die Ueberschrift ueber
  `clamp(…, 5.2vw, 52px)` am **Fenster** haengt und laengst auf ihren
  vollen 52 Pixeln steht. „Inventar und / Ausleihe, / endlich ohne Excel."
  bricht dann mitten in der Fuegung, mit der Konjunktion am Zeilenende.
  Hier wird nicht die Spalte breiter gemacht, sondern die Schrift kleiner:
  sie ist es, die nicht zur Spalte passt.
*/
@media (min-width: 1001px) and (max-width: 1240px) {
  .hero-grid h1 { font-size: 2.875rem; }
}

/* Der Schlussaufruf grenzt direkt an den Fussbereich — der uebliche
   Abstand davor liesse einen weissen Streifen zwischen zwei Flaechen,
   die zusammengehoeren. */
body:has(.cta) .site-foot { margin-top: 0; }

/* Verweise auf der dunklen Flaeche: das dunkle Verweisblau ist dort
   nicht mehr zu lesen. */
.cta a, .hero-dark a:not(.btn) { color: var(--blue-300); }
.cta a:hover, .hero-dark a:not(.btn):hover { color: var(--on-ink); }

/* Ein Abschnitt, dessen Inhalt in die Flaeche darueber hineinragt. */
.section-lift { padding-top: 0; }
.section-lift .trust-gross { margin-top: -52px; position: relative; z-index: 1; }
.section-lift .trust-item { box-shadow: 0 14px 34px -18px rgba(10, 20, 45, .40); }
@media (max-width: 640px) {
  .section-lift .trust-gross { margin-top: -34px; }
}

/* --- Reservationen: die Tagesübersicht ----------------------------------- */

/*
  Was heute bereitliegen muss.

  Bewusst keine Tabelle: eine Tabelle liest man spaltenweise, und hier
  liest man zeilenweise — „BEA-0001, Beamer, Frau Rossi, nur heute“ ist
  ein Satz. Die Nummer steht vorn in fester Breite, damit die Sätze
  untereinander an derselben Stelle beginnen.
*/
.today-card { border-color: var(--info-bd); }
.today-card > .card-head { background: var(--info-bg); border-bottom-color: var(--info-bd); }

/* Die Listen der Übersicht für Ausleiher und SuS (seit 05.10.2026):
   Nummer, Gegenstand, Zustand — drei Spalten, auch am Telefon. */
.start-liste { list-style: none; margin: 0; padding: 0; }
.start-liste li {
  display: grid; grid-template-columns: minmax(72px, auto) minmax(0, 1fr) auto;
  align-items: center; gap: 12px; padding: 12px 20px; border-bottom: 1px solid var(--rule);
}
.start-liste li.ohne-nr { grid-template-columns: minmax(0, 1fr) auto; }
.start-liste li:last-child { border-bottom: 0; }
.start-liste .badge { white-space: nowrap; }

.today-list { list-style: none; margin: 0; padding: 0; }
.today-list li {
  display: grid;
  grid-template-columns: 108px minmax(0, 1.4fr) minmax(0, 1fr) auto auto;
  align-items: center; gap: 14px;
  padding: 13px 20px;
  border-bottom: 1px solid var(--rule);
}
.today-list li:last-child { border-bottom: 0; }

.today-nr { font-weight: 600; font-variant-numeric: tabular-nums; }
.today-what, .today-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.today-what .strong, .today-who { overflow: hidden; text-overflow: ellipsis; }
.today-when {
  font-size: 0.8125rem; color: var(--muted); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 860px) {
  /* Am Telefon untereinander: fünf Spalten auf 390 px sind fünf Wörter. */
  .today-list li {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 4px 12px;
    padding: 14px 16px;
  }
  .today-nr { grid-column: 1; }
  .today-when { grid-column: 2; grid-row: 1; text-align: right; }
  .today-what { grid-column: 1 / -1; }
  .today-who  { grid-column: 1 / -1; font-size: 0.875rem; }
  .today-list .btn { grid-column: 1 / -1; justify-self: start; margin-top: 6px; }
}

/* --- Eigene Felder verwalten ---------------------------------------------- */

/*
  Jedes Feld ist ein eigenes kleines Formular. Der Rahmen macht sichtbar,
  wo eines aufhoert und das naechste anfaengt — sonst liest sich die Seite
  wie ein einziges langes Formular, und man weiss beim Speichern nicht,
  was man gerade speichert.
*/
.cf-row {
  padding: 16px 20px 18px;
  border-bottom: 1px solid var(--border);
}
.cf-row:last-child { border-bottom: 0; }
/* Nach dem Speichern bleibt die Seite beim Feld (seit 28.10.2026): Platz für
   den Kopf beim Hinspringen, und die Zeile leuchtet kurz grün nach. */
.cf-row { scroll-margin-top: 96px; }
.cf-row.is-saved { animation: cf-gespeichert 1.8s ease-out 1; }
@keyframes cf-gespeichert { from { background: var(--success-bg); } to { background: transparent; } }
.cf-row.is-off { background: var(--surface-muted); }

.cf-row-head {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin-bottom: 12px;
  font-size: 0.7812rem; color: var(--muted);
}
.cf-type { font-weight: 600; color: var(--heading); }
.cf-key {
  padding: 2px 7px; border-radius: 5px;
  background: var(--surface-muted); border: 1px solid var(--border);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.7188rem;
}
.cf-count { margin-left: auto; white-space: nowrap; }

.cf-switches { display: flex; gap: 20px; flex-wrap: wrap; margin: 4px 0 14px; }
.cf-switches .check { margin: 0; }

.cf-row-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cf-row-foot .confirm-form { margin: 0; }

/* Der Jahresbetrag unter dem Monatsbetrag: leiser, aber nicht versteckt. */
.plan-jahr { margin: -6px 0 14px; font-size: 0.7812rem; color: var(--muted); }
.plan.featured .plan-jahr { color: var(--accent-text); }

/*
  Der Umfang zwischen Preis und Aufzaehlung.

  „Bis 10 Benutzer" ist keine Funktion, sondern eine Grenze — und die
  Angabe, die auf einer Preisseite zuerst gesucht wird. Als Haekchen
  zwischen „Reservationen" und „E-Mail-Support" ging sie unter. Zwischen
  zwei Linien ist sie das Erste, was das Auge nach dem Preis findet, und
  die Aufzaehlung darunter besteht danach nur noch aus Funktionen.
*/
.plan-umfang {
  display: grid; grid-template-columns: 1fr 1fr;
  margin: 0 0 4px; padding: 13px 0;
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.plan-umfang > div + div { padding-left: 16px; border-left: 1px solid var(--border); }
.plan-umfang dt {
  font-size: 0.7188rem; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.plan-umfang dd {
  margin: 4px 0 0; font-size: 1.125rem; font-weight: 600; letter-spacing: -.015em;
  color: var(--heading); font-variant-numeric: tabular-nums;
}
/* Auf der blauen Tafel darf die Linie kraeftiger sein — auf hellblauem
   Grund verschwindet die gewoehnliche sonst. */
.plan.featured .plan-umfang,
.plan.featured .plan-umfang > div + div { border-color: var(--brand-100); }

/*
  Die Stufenwahl auf der Preisseite: drei Karten statt einer Liste.

  Untereinander lief jede Beschreibung ueber die volle Breite — bei 1440
  Pixeln eine einzige Zeile von tausend Pixeln, die niemand mehr am
  Stueck liest. Nebeneinander bekommt jede ihr eigenes Mass, und die
  drei stehen in derselben Ordnung wie die Preistafeln darueber.
*/
.wahl-karte { padding: 20px 22px; }
.wahl-kopf {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 0 0 8px; padding-bottom: 10px; border-bottom: 1px solid var(--border);
}
.wahl-kopf strong { color: var(--heading); font-size: 0.9688rem; }
.wahl-karte .muted { margin: 0; font-size: 0.875rem; line-height: 1.6; }
.plan-mini {
  font-size: 0.8125rem; font-weight: 500; color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Ein mittig gesetzter Hinweis braucht ein Mass, sonst zieht er als
   einzelne Zeile quer unter drei Karten durch. */
.mitte-schmal { max-width: 46em; margin-left: auto; margin-right: auto; }

/* --- Das Rechnungsbeispiel ------------------------------------------------ */

/*
  Kein Bild eines Belegs, sondern der Beleg in klein.

  Ein Bildschirmfoto waere eine Behauptung, die beim naechsten
  Steuersatz falsch ist. Hier stehen dieselben Positionen, die
  `Billing::totals()` auch auf die echte Rechnung schreibt — aendert
  sich der Satz, aendert sich das Beispiel mit.
*/
.beleg-mini {
  margin: 0; padding: 22px 24px 20px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.beleg-mini-kopf {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding-bottom: 14px; margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.beleg-mini-kopf .strong { color: var(--heading); font-size: 0.9375rem; }
.beleg-mini-kopf .muted  { font-size: 0.7812rem; }
.beleg-mini dl { margin: 0; }
.beleg-mini dl > div {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding: 11px 0; border-bottom: 1px solid var(--border);
}
.beleg-mini dt { font-size: 0.875rem; color: var(--text); }
.beleg-mini dd {
  margin: 0; font-size: 0.875rem; color: var(--heading); font-weight: 500;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.beleg-mini-summe { border-bottom: 0 !important; }
.beleg-mini-summe dt { font-weight: 600; color: var(--heading); }
.beleg-mini-summe dd { font-size: 1.0625rem; font-weight: 600; letter-spacing: -.015em; }

/* Der Zahlteil unten: angedeutet, nicht nachgebaut. Ein echter QR-Code
   hier waere ein scannbarer Einzahlungsschein auf einer Verkaufsseite. */
.beleg-mini-fuss {
  display: flex; align-items: center; gap: 14px;
  margin-top: 16px; padding-top: 16px;
  border-top: 1px dashed var(--border);
  font-size: 0.7812rem; line-height: 1.55; color: var(--muted);
}
.beleg-mini figcaption {
  margin-top: 14px; font-size: 0.7812rem; line-height: 1.55; color: var(--muted);
}

@media (max-width: 640px) {
  .beleg-mini { padding: 18px 18px 16px; }
  .plan-umfang dd { font-size: 1.0625rem; }
}

/* --- Die ersten Schritte als Karten -------------------------------------
   Auf den Zielgruppenseiten. Eine nummerierte Liste waere dasselbe in
   grau; drei Karten nebeneinander sagen zusaetzlich, dass es genau drei
   sind und dass sie eine Reihenfolge haben. */

.schritt-karten {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.schritt-karten > li {
  margin: 0; padding: 22px 22px 24px;
  display: flex; flex-direction: column; gap: 6px;
}
.schritt-nr {
  width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent-soft-text);
  font-size: 0.875rem; font-weight: 500; margin-bottom: 6px;
}
.schritt-karten strong { color: var(--heading); font-weight: 500; font-size: 0.9688rem; }
/*
  Die Fussnote unter den drei Schritten war der einzige Textblock der
  Seite ohne Mass: dreizehn Pixel Schrift ueber elfhundert Pixel Zeile,
  rund hundertfuenfundsiebzig Zeichen. Das Auge findet den Anfang der
  naechsten Zeile nicht mehr.
*/
.schritt-karten + .small { max-width: 46em; }
.schritt-karten .muted { font-size: 0.875rem; line-height: 1.55; }

/* --- Dokumentation: die Übersicht ---------------------------------------
   Die Racks bekommen die ganze Breite, das Formular klappt auf. Vorher
   besetzte ein Formular, das man alle paar Monate braucht, die Hälfte
   einer Seite, die man täglich ansieht. */

.docs-flaeche { display: block; }

/* Angaben, Anhänge und Adressen nebeneinander — der Platz ist da, seit
   die Porttabelle darüber die ganze Breite hat. Der aufklappbare Kasten
   spannt über alles: ein halbbreites Formular liest sich schlechter. */
.docs-spalten {
  display: grid; gap: 0 18px;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  align-items: start;
}
.docs-spalten > .docs-form { grid-column: 1 / -1; }

@media (max-width: 760px) {
  .docs-spalten { grid-template-columns: minmax(0, 1fr); }
}

.docs-form {
  margin-top: 22px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.docs-form > summary {
  display: flex; align-items: center; gap: 9px;
  padding: 14px 20px; cursor: pointer; list-style: none;
  font-size: 0.9375rem; font-weight: 500; color: var(--heading);
}
.docs-form > summary::-webkit-details-marker { display: none; }
.docs-form > summary:hover { background: var(--surface-muted); }
.docs-form > summary svg { width: 17px; height: 17px; color: var(--accent); }
.docs-form[open] > summary { border-bottom: 1px solid var(--rule); }
.docs-form .card { border: 0; box-shadow: none; margin: 0; }

/*
  Die Kacheln: Zeichnung links, Angaben rechts.

  Ein Rack ist hoch und schmal. Die Zeichnung darüberzulegen hiesse, ein
  Bild im Verhältnis 1:2 in einen Kasten im Verhältnis 3:2 zu zwängen —
  beim ersten Versuch war genau das der Fehler, und sichtbar waren die
  obersten zwei leeren Höheneinheiten.
*/
.rack-cards {
  display: grid; gap: 18px;
  /*
    Dreihundertzwanzig waren zu wenig.

    Von der Kachel gehen 104 Pixel an die Zeichnung und rund 34 an die
    Innenabstaende — fuer den Text blieben knapp zweihundert. „Serverschrank
    EG" brach dann nach dem ersten Wort um, und die Standortzeile stand
    vierzeilig da. Mit vierhundertzwanzig bleiben knapp dreihundert fuer
    den Text, und ein gewoehnlicher Rackname passt in eine Zeile.

    `auto-fill` und nicht `auto-fit`: bei einem einzigen Rack soll die
    Kachel ihre Groesse behalten und nicht ueber die ganze Breite laufen
    — eine Kachel als Banner sieht aus wie ein Fehler.
  */
  grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
}
.rack-card {
  display: grid; grid-template-columns: 150px minmax(0, 1fr);
  overflow: hidden; margin: 0; align-items: stretch;
}
.rack-card:hover { text-decoration: none; border-color: var(--accent-soft); }

.rack-card-bild {
  background: var(--indigo-800);
  padding: 12px 10px;
  display: flex; align-items: center; justify-content: center;
  /* Feste Höhe, damit die Kacheln in einer Reihe gleich hoch sind: ein
     12-HE-Wandgehäuse neben einem 42-HE-Vollrack sähe sonst aus wie ein
     Fehler. Die Zeichnung wird darin auf die Höhe gepasst, nicht auf die
     Breite — sonst wird sie unten abgeschnitten. */
  /* Feste Höhe, nicht Mindesthöhe: `height: 100%` an der Zeichnung
     braucht einen Bezug. Mit `min-height` hätte sie keinen, würde ihre
     natürliche Grösse annehmen — und die Kachel auf 600 Pixel wachsen
     lassen. Genau das ist beim ersten Versuch passiert. */
  height: 188px;
}
.rack-card-bild .rack-view { display: flex; height: 100%; width: 100%;
                             align-items: center; justify-content: center; }
/* `min-width: 0`: die 560 px der grossen Ansicht (Ports lesbar) galten
   auch hier — ein Rack mit einer belegten HE wurde breiter als seine
   Spalte und lief über die Kachel (Rückmeldung vom 03.10.2026). */
.rack-card-bild .rack-view svg { width: auto; height: 100%; max-width: 100%; min-width: 0; overflow: hidden; }
/* In der Miniatur ein Schrank und keine weisse Säule: dunkles Inneres,
   darauf heben sich die Frontblenden ab wie im Serverraum. */
.rack-view.is-mini .rack-slot-bg,
.rack-view.is-mini .rack-slot.is-free .rack-slot-bg { fill: var(--indigo-700); }
.rack-view.is-mini .rack-slot-line { stroke: var(--indigo-600); }
.rack-view.is-mini .rack-rail { fill: var(--indigo-500); }
.rack-card-bild .rack-view { background: none; border: 0; padding: 0; border-radius: 0; overflow: visible; }
.rack-card-leer {
  margin: 0; font-size: 0.6875rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--indigo-on-dark);
}
.rack-card-text { padding: 15px 17px; display: flex; flex-direction: column;
                  justify-content: center; }

@media (max-width: 470px) {
  .rack-cards { grid-template-columns: minmax(0, 1fr); }
  .rack-card { grid-template-columns: 84px minmax(0, 1fr); }
  .rack-card-bild { height: 156px; }
}

/* --- Geräteverwaltung (MDM) ---------------------------------------------- */

/*
  Das Verbinden von Hand steht in der Zeile, nicht auf einer eigenen Seite.

  Wer die Liste der nicht zugeordneten Geräte durchgeht, hat das Etikett am
  Gerät vor sich und tippt die Inventarnummer ab. Eine Unterseite je Gerät
  hiesse: klicken, tippen, speichern, zurück, nächste Zeile suchen.
*/
.row-form { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; }
.row-form .input-sm {
  width: 132px; height: 32px; padding: 0 10px; font-size: 0.8125rem;
}

/*
  Gerätename und Modell untereinander, nicht ineinander.

  `.cell-sub` ist von Haus aus inline — in den meisten Tabellen steht es
  in einem eigenen <div>. Hier ist es ein <span> in derselben Zelle, und
  ohne diese Zeile lief „iPad Air (5. Gen.) · iPads (Jamf)" direkt hinter
  dem Namen weiter und schob die Spalte auf fünf Zeilen auseinander.
*/
.mdm-sub { display: block; line-height: 1.35; margin-top: 1px; }
[data-mdm-name] { min-width: 190px; }

/* Die Karte des verwalteten Geräts auf dem Inventarblatt. */
.mdm-quelle { display: flex; align-items: center; gap: 8px;
              font-size: 0.75rem; color: var(--muted); }
.mdm-quelle .badge { flex: none; }

@media (max-width: 720px) {
  /* In der Zeile wird es zu eng; dann untereinander. */
  .row-form { display: flex; }
  /* 44 px und 16 px wie jedes Feld am Telefon (seit 04.10.2026) — die
     13 px oben schlugen die Telefonregel, und iOS zoomte beim Antippen. */
  .row-form .input-sm { width: 100%; height: 44px; font-size: 1rem; }
}
@media (pointer: coarse) {
  .im-teams .row-form .input-sm { font-size: 1rem; }
}

/* --- Anleitungen und häufige Fragen -------------------------------------- */

/*
  Eine Anleitung steht offen da, eine Frage ist zugeklappt. Der Unterschied
  ist die ganze Gestaltung: zwanzig offene Antworten waeren eine Wand, in
  der man die eine nicht findet.
*/
.guides { display: grid; gap: 14px; }

.guide {
  padding: 20px 22px 22px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.guide h3 {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 10px; font-size: 1rem; font-weight: 600; color: var(--heading);
}
.guide h3 svg { color: var(--accent); flex: 0 0 auto; }

.guide-body p { margin: 0 0 10px; font-size: 0.9062rem; line-height: 1.7; color: var(--text); }
.guide-body p:last-child { margin-bottom: 0; }
.guide-body .guide-link { margin-top: 14px; }

/* Dateien am Eintrag: eine Zeile je Datei, Name vorn, Art und Grösse
   leise dahinter — wie ein Verweis, den man vor dem Tippen einschätzen kann. */
.guide-dateien {
  display: grid; gap: 6px;
  margin: 14px 0 0; padding: 0; list-style: none;
}
.guide-datei {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-muted);
  font-size: 0.875rem; color: var(--text); text-decoration: none;
}
.guide-datei:hover { border-color: var(--accent-soft); background: var(--accent-soft); color: var(--accent-soft-text); }
.guide-datei svg { flex: 0 0 auto; color: var(--accent); }
.guide-datei-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; font-weight: 500; }
.guide-datei-meta { flex: 0 0 auto; font-size: 0.75rem; color: var(--muted); }

/* Pflegeansicht: die Dateien unter dem Formular des Eintrags. */
.guide-pflege-dateien {
  display: grid; gap: 8px;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px dashed var(--border);
}
.guide-pflege-datei { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 0.8438rem; }
.guide-pflege-datei .confirm-form { margin: 0; }

/* Was nur die Verwaltung sieht, traegt eine Kante — damit niemand
   versehentlich davon ausgeht, die Klasse laese dasselbe. */
.guide.is-internal,
.faq-item.is-internal { border-left: 3px solid var(--warning-fg); }

/*
  Die Fragen: ein <details> je Frage. Ohne JavaScript, mit der Tastatur
  bedienbar, und die Sprachausgabe sagt „auf- und zuklappbar“ von selbst.
*/
.faq {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); overflow: hidden;
}
.faq-item + .faq-item { border-top: 1px solid var(--rule); }

.faq-item > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 15px 20px;
  font-size: 0.9375rem; font-weight: 500; color: var(--heading);
  cursor: pointer; list-style: none;
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary:hover { background: var(--row-hover); }
.faq-item > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

.faq-arrow {
  flex: 0 0 auto; color: var(--muted);
  transform: rotate(90deg);
  transition: transform .16s ease;
}
.faq-item[open] > summary { color: var(--accent-text); }
.faq-item[open] .faq-arrow { transform: rotate(-90deg); }
@media (prefers-reduced-motion: reduce) { .faq-arrow { transition: none; } }

/* Der Verweis steht in der Zeile neben dem Titel; ohne weiteren Inhalt
   ist die Zeile flach, ohne Pfeil (siehe partials/guides-list.php). */
.faq-titel { flex: 1 1 auto; min-width: 0; }
.faq-arrow-platz { visibility: hidden; }
.faq-knopf { flex: 0 0 auto; min-width: 104px; justify-content: center; }
.faq-item-flach {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 11px 20px; min-height: 52px;
  font-size: 0.9375rem; font-weight: 500; color: var(--heading);
}

.faq-body { padding: 0 20px 18px; }
.faq-body p { margin: 0 0 10px; font-size: 0.9062rem; line-height: 1.7; color: var(--text); }
.faq-body p:last-child { margin-bottom: 0; }

/* Ein Pfad über der Überschrift — „zurück zum Produkt“ ohne einen Knopf
   dafür zu brauchen. */
.crumb { margin: 0 0 6px; font-size: 0.8125rem; }
.crumb a { color: var(--muted); }
.crumb a:hover { color: var(--accent-text); }

/* --- Anmeldung: der Microsoft-Knopf --------------------------------------- */

/*
  Er steht zuoberst und ist der Weg, den die meisten nehmen sollen — aber
  er ist nicht blau. Blau heisst in dieser Anwendung „das ist die Aktion“,
  und das waere hier gelogen: welcher Weg richtig ist, entscheidet das
  Haus, nicht wir. Also ein ruhiger Knopf mit dem Zeichen, das man kennt —
  das Zeichen traegt die Aussage, nicht die Farbe.
*/
.btn-ms {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  font-weight: 500;
}
.btn-ms:hover { background: var(--surface-muted); border-color: var(--indigo-200); }
.btn-ms svg { flex: 0 0 auto; }

/* Der zweite Schritt erscheint, statt zu springen. Wer Bewegung
   abgestellt hat, bekommt sie nicht. */
#login-form [data-step-2] { animation: step-auf .18s ease; }
@keyframes step-auf {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  #login-form [data-step-2] { animation: none; }
}

/*
  Der weiche Abschluss unter einem Bildschirmfoto.

  Ein Foto endet mitten in einer Tabellenzeile — es zeigt einen
  Ausschnitt, keine ganze Seite. Hart abgeschnitten liest sich das wie ein
  Fehler; ausgeblendet liest es sich als „hier geht es weiter“, was
  stimmt.

  Als Ueberlagerung und nicht als Maske: eine Maske am Bild machte den
  Rahmen darunter durchsichtig, und dann saehe man die Seitenfarbe
  hindurchscheinen.
*/
.shot .browser { position: relative; }
.shot .browser::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 90px;
  pointer-events: none;
  /* In den Grund der Anwendung, nicht ins Weisse: die Abbildungen enden
     seit dem 24.09.2026 hellblau. */
  background: linear-gradient(to bottom, transparent, var(--auth-flaeche));
}

/* --- Kacheln, die weiterfuehren ------------------------------------------- */

/*
  Der Ersatz fuer die lange Kartenwand.

  Anders als eine Karte ist eine Kachel ein Verweis — deshalb hebt sie
  sich beim Ueberfahren. Die Bewegung verspricht ein Klickziel, und hier
  gibt es eines; genau darum durften die Funktionskarten sich frueher
  nicht bewegen.
*/
/*
  Kacheln brauchen mehr Breite als Karten.

  Das allgemeine Raster bricht bei 230 px um — das reicht fuer eine Karte
  mit Text, nicht fuer eine Kachel: die hat links ein Zeichen und rechts
  einen Pfeil, dem Text bleiben davon noch gut 150 px. Bei 768 px standen
  deshalb drei Kacheln nebeneinander, in denen „Microsoft 365“ auf zwei
  Zeilen brach und keine zwei Kacheln gleich hoch waren.

  Die Stufen stehen hier ausdruecklich statt als auto-fit: bei den
  Zielgruppen sollen es hoechstens zwei Spalten sein, auch auf einem
  breiten Bildschirm — vier Kacheln in drei Spalten waeren drei und eine.
*/
.tiles { gap: 14px; grid-template-columns: minmax(0, 1fr); }

@media (min-width: 620px) {
  .grid-3.tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1000px) {
  .grid-3.tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 640px) {
  .grid-2.tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.tile {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) auto;
  align-items: start;
  gap: 4px 14px;
  padding: 20px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
  color: inherit; text-decoration: none;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.tile:hover {
  text-decoration: none;
  border-color: var(--accent-line);
  box-shadow: var(--shadow-lg);
  transform: translateY(-2px);
}
.tile:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .tile:hover { transform: none; } }

.tile-icon {
  grid-column: 1; grid-row: 1;
  width: 42px; height: 42px; border-radius: var(--radius);
  display: grid; place-items: center; font-size: 1.1875rem;
  background: var(--ton-bg, var(--accent-soft));
  color: var(--ton-fg, var(--accent-soft-text));
}
/*
  Jede Kachel ihr Ton (seit 30.09.2026, partials/tiles reihum). Zehn gleich
  blaue Zeichen in zehn gleich weissen Kacheln lasen sich als eine Fläche;
  mit Farbe findet das Auge «Werte» wieder, ohne zu lesen.
*/
.tile.ton-blau    { --ton-bg: var(--ton-blau-bg);    --ton-fg: var(--ton-blau-fg); }
.tile.ton-gruen   { --ton-bg: var(--ton-gruen-bg);   --ton-fg: var(--ton-gruen-fg); }
.tile.ton-orange  { --ton-bg: var(--ton-orange-bg);  --ton-fg: var(--ton-orange-fg); }
.tile.ton-violett { --ton-bg: var(--ton-violett-bg); --ton-fg: var(--ton-violett-fg); }
.tile.ton-tuerkis { --ton-bg: var(--ton-tuerkis-bg); --ton-fg: var(--ton-tuerkis-fg); }
.tile.ton-rosa    { --ton-bg: var(--ton-rosa-bg);    --ton-fg: var(--ton-rosa-fg); }
.tile[class*="ton-"]:hover { border-color: var(--ton-fg); }
.tile[class*="ton-"]:hover .tile-arrow { color: var(--ton-fg); }
/* Farbige Fläche statt weisser Karte — für wenige, grosse Kacheln. */
.tiles.is-farbig .tile { padding: var(--abstand-4); background: var(--ton-bg); border-color: transparent; }
.tiles.is-farbig .tile-icon { background: var(--surface); width: 48px; height: 48px; }
.tiles.is-farbig .tile-name { font-size: 1.125rem; }
.tiles.is-farbig .tile-text { color: var(--text); }
.tiles.is-farbig .tile { grid-template-columns: 48px minmax(0, 1fr) auto; }
/*
  Oben ausgerichtet, nicht mittig.

  Die Kacheln einer Zeile sind gleich hoch, ihr Inhalt aber verschieden
  lang. Mittig gesetzt rutschte der Text einer kurzen Kachel nach unten,
  waehrend das Zeichen daneben oben blieb — zwei Kacheln nebeneinander,
  und in der einen stand die Ueberschrift auf Hoehe des Zeichens, in der
  anderen darunter.
*/
.tile-body { grid-column: 2; grid-row: 1; min-width: 0; align-self: start; padding-top: 2px; }
.tile-name { display: block; font-size: 1rem; font-weight: 600; color: var(--heading); }
.tile-text { display: block; margin-top: 4px; font-size: 0.875rem; line-height: 1.6; color: var(--muted); }

.tile-arrow {
  grid-column: 3; grid-row: 1; align-self: center;
  color: var(--muted); line-height: 0;
  transition: transform .15s, color .15s;
}
.tile:hover .tile-arrow { color: var(--accent); transform: translateX(2px); }
@media (prefers-reduced-motion: reduce) { .tile:hover .tile-arrow { transform: none; } }

@media (max-width: 640px) {
  .tile { padding: 16px; gap: 4px 12px; grid-template-columns: 38px minmax(0, 1fr) auto; }
  .tile-icon { width: 38px; height: 38px; font-size: 1.0625rem; }
  .tile-name { font-size: 0.9375rem; }
}

/* Ein einzelnes Bildschirmfoto ausserhalb der Galerie — auf den
   Modulseiten. Es ragt in die dunkle Flaeche darueber hinein. */
.shot-solo { display: block; margin: -52px 0 0; }
@media (max-width: 640px) { .shot-solo { margin-top: -34px; } }

/* Die Preistafeln ragen ebenfalls hinein — die empfohlene steht ohnehin
   schon hoeher, das passt zusammen. */
/*
  Preistafeln: entweder alle drei nebeneinander oder alle untereinander.

  Dazwischen entstand bei 768 px „zwei und eine“ — die dritte stand allein
  in der zweiten Zeile, und ausgerechnet die teuerste sah dadurch aus wie
  ein Nachtrag. Vergleichen kann man ohnehin nur, was nebeneinander steht
  oder was gleich breit untereinander steht.
*/
.plans-lift { margin-top: -52px; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 980px) {
  .plans-lift { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 640px) { .plans-lift { margin-top: -34px; } }

/* Verweise im Aufmacher — der Pfad ueber der Ueberschrift. */
.hero-dark .eyebrow a { color: var(--on-ink); text-decoration: none; }
.hero-dark .eyebrow a:hover { text-decoration: underline; }

/* --- Am Telefon: die Seite atmet anders ----------------------------------- */

@media (max-width: 640px) {
  /*
    Das Bildschirmfoto ueber die ganze Breite.

    Bei 390 px sind die seitlichen 16 px des Rasters acht Prozent des
    Bildes — und ein Bild einer ganzen Anwendung braucht jeden Pixel. Der
    Rahmen verliert dafuer seine Rundung an den Seiten; das sieht nach
    Absicht aus und nicht nach Fehler, weil er die Kante wirklich beruehrt.
  */
  .shot-solo .browser,
  .shot .browser {
    margin-left: -16px; margin-right: -16px;
    border-left: 0; border-right: 0;
    border-radius: 0;
  }

  /* Das Zeichen etwas kleiner: es bestimmt die Hoehe der ersten Zeile, und
     die Luecke zwischen Ueberschrift und Text stammt aus genau dieser
     Hoehe. */
  .feature .icon { width: 32px; height: 32px; font-size: 0.9375rem; }
  .feature { grid-template-columns: 32px minmax(0, 1fr); row-gap: 7px; }

  /* Abschnitte etwas enger — bei sechs Abschnitten untereinander summiert
     sich jeder Zwischenraum zu einem Bildschirm. */
  .section { padding: var(--abschnitt-telefon) 0; }
  .sec-head { margin-bottom: 4px; }
  .tiles { gap: 10px; }
}

/* Der Aufmacher der Unterseiten: am Telefon weniger Zuschlag nach unten,
   weil das Hineinragen dort ohnehin kleiner ist. */
@media (max-width: 640px) {
  .hero-slim { padding: 40px 0 62px; }
}

/* --- Fortschrittsbalken der Projekte ------------------------------------- */
/* Rollenmarken statt Hexwerte: der Balken trägt die Bedienfarbe, die Bahn
   die stille Fläche. */
.fortschritt {
  display: block;
  width: 120px;
  max-width: 100%;
  height: 6px;
  border-radius: 999px;
  background: var(--surface-muted);
  overflow: hidden;
}
.fortschritt-bar {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: 999px;
}
/* Umbruchtreuer Fliesstext — Beschreibungen behalten ihre Zeilen. */
.prewrap { white-space: pre-wrap; }

/* --- Verknüpfungen der Projekte ------------------------------------------ */
.mini-head {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 16px 0 8px;
}
.mini-head:first-child { margin-top: 0; }
.link-list { list-style: none; margin: 0 0 4px; padding: 0; }
.link-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 8px 0;
  border-bottom: 1px solid var(--rule);
}
.link-row:last-child { border-bottom: 0; }
.inline-form { display: inline; }
/* Das nachgestellte Entfernen-Kreuz rechts an die Zeile — aber NUR das
   nachgestellte, nicht der vorangestellte Erledigt-Haken in der Plantabelle. */
.link-row > .inline-form { margin-left: auto; }
/* Das kleine Wegnehmen-Kreuz: rot mit weisser Schrift wie jeder
   Lösch-Knopf (seit 30.09.2026; vorher grau, bis man darauf zeigte). */
.btn-link-danger.btn-xs {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0;
  background: var(--danger-solid);
  border: 0;
  color: var(--on-danger);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  border-radius: 6px;
}
.btn-link-danger.btn-xs:hover { background: var(--danger-solid-hover); color: var(--on-danger); }

/* --- Aufgaben der Projekte ----------------------------------------------- */
.task-list { list-style: none; margin: 0 0 14px; padding: 0; }
.task-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 9px 0;
  border-bottom: 1px solid var(--rule);
}
.task-row:first-child { border-top: 1px solid var(--rule); }
.task-title { flex: 1 1 auto; min-width: 140px; font-weight: 500; }
.task-row.is-done .task-title { text-decoration: line-through; color: var(--muted); font-weight: 400; }
/* Der runde Haken links: leer, bis die Aufgabe erledigt ist. */
.task-check {
  flex: none;
  width: 22px;
  height: 22px;
  border: 2px solid var(--field-border);
  border-radius: 999px;
  background: none;
  color: var(--on-accent);
  font-size: 0.8125rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.task-check:hover { border-color: var(--accent); }
/* Im Projektplan heisst die Zeile .plan-task — ohne sie stand dort ein
   weisser Haken auf Weiss (04.10.2026). */
.task-row.is-done .task-check,
.plan-task.is-done .task-check { background: var(--accent); border-color: var(--accent); }
/* Die Zeile zum Anlegen: Titel nimmt den Platz, der Rest bleibt schmal. */
.task-add { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.task-add .input:first-of-type { flex: 1 1 200px; }

/* --- Projektplan (Strukturplan + Aufwand) -------------------------------- */
.plan-table { width: 100%; border-collapse: collapse; }
.plan-table th, .plan-table td { padding: 7px 10px; text-align: left; vertical-align: middle; }
.plan-table thead th { font-size: 0.75rem; color: var(--muted); border-bottom: 1px solid var(--rule); white-space: nowrap; }
.plan-table td.num, .plan-table th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.plan-nr { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; width: 1%; }
/* Die Phase als kräftige Trennzeile über ihren Aufgaben. */
.plan-phase td { background: var(--surface-muted); font-weight: 700; border-top: 1px solid var(--rule); }
.plan-task td { border-bottom: 1px solid var(--rule); }
.plan-task.is-done .plan-title a { text-decoration: line-through; color: var(--muted); }
.plan-title { display: flex; align-items: center; gap: 8px; }
.plan-akt { text-align: right; white-space: nowrap; }
/* Die Formulare unter der Tabelle: gestapelt, mit Luft. */
.plan-forms { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.plan-forms .task-add .input:first-of-type { flex: 1 1 180px; }
.input-h { width: 92px; flex: none; }

/* --- Projekt-Budget ------------------------------------------------------ */
/* Über Budget: der Balken schlägt in die Warnfarbe um. */
.fortschritt-bar.is-over { background: var(--danger-solid); }
.ref-item { margin-right: 12px; white-space: nowrap; }
.ref-item + .ref-item { border-left: 1px solid var(--rule); padding-left: 12px; }
.text-danger { color: var(--danger-fg); }

/* --- Terminplan / Gantt (read-only, reines CSS) -------------------------- */
.gantt { min-width: 680px; }
.gantt-row { display: flex; align-items: stretch; min-height: 28px; }
.gantt-label {
  flex: 0 0 210px;
  width: 210px;
  padding: 5px 12px 5px 0;
  border-right: 1px solid var(--rule);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8125rem;
}
.gantt-track { flex: 1 1 auto; position: relative; min-width: 440px; border-bottom: 1px solid var(--rule); }
/* Kopfzeile mit den Monaten. */
.gantt-axis .gantt-track { height: 22px; border-bottom: 1px solid var(--border); }
.gantt-month {
  position: absolute; top: 3px;
  font-size: 0.6875rem; color: var(--muted);
  border-left: 1px solid var(--rule); padding-left: 4px;
  white-space: nowrap; overflow: hidden;
}
/* Phasenzeile — kräftig, ohne Balken. */
.gantt-phase .gantt-label { padding-top: 7px; }
.gantt-phase .gantt-track { background: var(--surface-muted); }
/* Feine senkrechte Monatslinien in jeder Zeile. */
.gantt-grid { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px solid var(--rule); opacity: .5; }
/* Der Balken. */
.gantt-bar {
  position: absolute; top: 50%; transform: translateY(-50%);
  height: 12px; border-radius: 6px; min-width: 4px;
  background: var(--accent);
}
.gantt-bar.status-done { background: var(--success-fg); }
.gantt-bar.status-in_progress { background: var(--warning-fg); }
.gantt-bar.status-open { background: var(--accent); }
/* Der Meilenstein — eine Raute. */
.gantt-milestone {
  position: absolute; top: 50%; width: 12px; height: 12px;
  transform: translate(-50%, -50%) rotate(45deg);
  background: var(--heading);
}

/* --- Projekt-Verlauf (Infoboard) ----------------------------------------- */
.verlauf-form { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-start; }
.verlauf-form select { flex: none; }
.verlauf-form textarea { flex: 1 1 260px; min-height: 44px; }
.verlauf-form button { flex: none; }
.verlauf-list { list-style: none; margin: 0; padding: 0; }
.verlauf-item { padding: 12px 0; border-bottom: 1px solid var(--rule); }
.verlauf-item:last-child { border-bottom: 0; }
.verlauf-kopf { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
.verlauf-kopf .inline-form { margin-left: auto; }
.verlauf-text { margin: 0; }

/* --- Projekt: mehr Luft und Ruhe ---------------------------------------- */
/* Kleinere Zahl, wenn ein Geldbetrag doch in eine Zähl-Kachel muss. */
.stat .v-sm { display: block; font-size: 1.3125rem; font-weight: 700; letter-spacing: -.01em;
              font-variant-numeric: tabular-nums; margin-top: 6px; line-height: 1.15; color: var(--heading); }
.muted-body { color: var(--muted); line-height: 1.62; }

/* Die Plan-Tabelle atmet: höhere Zeilen, mehr Rand. */
.plan-table th, .plan-table td { padding: 11px 14px; }
.plan-phase td { padding-top: 12px; padding-bottom: 12px; }

/* Die Erfassen-Zeilen als ruhig abgesetzter Bereich, nicht angeklebt. */
.plan-forms { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--rule); gap: 12px; }

/* Listenzeilen und Verlauf grosszügiger. */
.link-row { padding: 12px 0; gap: 12px; }
.verlauf-item { padding: 16px 0; }
.verlauf-list .verlauf-item:first-child { padding-top: 6px; }
.mini-head { margin: 24px 0 10px; }
.mini-head:first-child { margin-top: 4px; }

/* Etwas Abstand unter der Reiterleiste. */
.tabs + .card, .tabs + .grid { margin-top: 4px; }

/* Projekt-Kacheln: 2×2, erst auf breitem Schirm vier — nie 3+1. */
.grid.projekt-kacheln { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 1180px) {
  .grid.projekt-kacheln { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Kacheln gleich hoch und mit Abstand zum Block darunter. */
.grid.projekt-kacheln { align-items: stretch; margin-bottom: 24px; }
.grid.projekt-kacheln > .card { height: 100%; display: flex; }
.grid.projekt-kacheln > .card .stat { width: 100%; }

/* --- Projekt: die Erfass-Zeile kompakt statt gestapelt ------------------- */
.task-add { align-items: center; }
.task-add > .input, .task-add > .select { width: auto; }
/* Der Titel/die Bezeichnung wächst; Auswahl und Datum bleiben schmal. */
.task-add > .input:not(.input-h):not([type="date"]) { flex: 1 1 200px; min-width: 160px; }
.task-add > .select { flex: 1 1 150px; min-width: 130px; }
.task-add > .input[type="date"] { flex: 0 1 150px; }
.task-add > .input-h { flex: 0 0 90px; width: 90px; }
.task-add > .btn { flex: 0 0 auto; }

/* --- Terminplan / Gantt: schöner und luftiger --------------------------- */
.gantt { min-width: 760px; }
.gantt-row { min-height: 42px; }
.gantt-label {
  flex: 0 0 244px; width: 244px;
  padding: 9px 16px 9px 0; font-size: 0.8438rem;
}
.gantt-track { min-width: 500px; }

/* Kopfzeile mit Monaten — ruhiger, etwas höher. */
.gantt-axis { min-height: 34px; }
.gantt-axis .gantt-track { height: 34px; border-bottom: 2px solid var(--border); }
.gantt-month { top: 9px; font-size: 0.75rem; letter-spacing: .01em; color: var(--muted);
               border-left: 1px solid var(--rule); padding-left: 6px; }

/* Phasenzeile: eine klare Bandzeile. */
.gantt-phase { min-height: 40px; }
.gantt-phase .gantt-label { padding-top: 11px; color: var(--heading); }
.gantt-phase .gantt-track { background: var(--surface-muted); }

/* Feine Monatslinien. */
.gantt-grid { border-left: 1px solid var(--rule); opacity: .45; }

/* Der Balken — hoch, gerundet, mit sanftem Relief. */
.gantt-bar {
  height: 20px; border-radius: 10px; min-width: 8px;
  background: var(--accent); z-index: 2;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .28), 0 1px 3px rgba(16, 20, 35, .14);
}
.gantt-bar.status-done { background: var(--success-fg); }
.gantt-bar.status-in_progress { background: var(--warning-fg); }
.gantt-bar.status-open { background: var(--accent); }

/* Der Meilenstein — eine kräftige Raute mit hellem Rand. */
.gantt-milestone {
  width: 16px; height: 16px; z-index: 3;
  background: var(--heading);
  border: 2px solid var(--surface);
  box-shadow: 0 1px 3px rgba(16, 20, 35, .22);
}

/* Die Heute-Linie — dezent gestrichelt durch alle Zeilen. */
.gantt-heute {
  position: absolute; top: 0; bottom: 0; width: 0;
  border-left: 2px dashed var(--danger-fg); opacity: .5; z-index: 1;
}

/* Legende im Kartenkopf. */
.gantt-legende { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
.gantt-legende .lg { display: inline-flex; align-items: center; gap: 7px; font-size: 0.75rem; color: var(--muted); }
.gantt-legende .lg::before { content: ''; width: 13px; height: 13px; border-radius: 4px; background: var(--muted); }
.gantt-legende .lg-done::before { background: var(--success-fg); }
.gantt-legende .lg-prog::before { background: var(--warning-fg); }
.gantt-legende .lg-open::before { background: var(--accent); }
.gantt-legende .lg-mile::before { width: 12px; height: 12px; border-radius: 2px; transform: rotate(45deg); background: var(--heading); }

/* --- Terminplan: Kopfaktionen ----------------------------------------- */
.gantt-head-actions { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; justify-content: flex-end; }

/* Lesende Projektansicht: der Haken ist nur Anzeige, kein Knopf. */
.task-check.is-static { cursor: default; }
.task-check.is-static:hover { border-color: var(--field-border); }

/* Namen und Nummern in Tabellen brechen nicht an jedem Bindestrich
   («sw-/bvk-/01», Rückmeldung vom 03.10.2026). Reicht der Platz nicht,
   wird die Tabelle zur Liste (siehe unten). */
table:not(.karten-aktiv) td a.strong,
table:not(.karten-aktiv) td > .strong { white-space: nowrap; }

/* --- Eine eigene Ausleihe (Ziel der Teams-Mitteilung, 03.10.2026) ------- */
.frist-karte { border-left: 4px solid var(--info-fg); }
.frist-karte.is-warning { border-left-color: var(--warning-fg); }
.frist-karte.is-danger  { border-left-color: var(--danger-fg); }
.frist-karte-inhalt { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; padding: 18px 20px; }
.frist-karte-etikett { flex: 1 0 100%; font-size: 0.8125rem; color: var(--muted); }
.frist-karte-datum { font-size: 1.75rem; font-weight: 700; letter-spacing: -.02em; color: var(--heading);
                     font-variant-numeric: tabular-nums; line-height: 1.1; }
.frist-karte-mahnung { flex: 1 0 100%; margin-top: 4px; font-size: 0.875rem; font-weight: 600; color: var(--danger-fg); }
.ausleihe-geraete > li { display: flex; gap: 14px; align-items: flex-start; padding-top: 14px; padding-bottom: 14px; }
.ausleihe-geraet { flex: 1 1 auto; min-width: 0; }
.ausleihe-geraet .strong { font-size: 0.9375rem; }
.ausleihe-zubehoer { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 8px; }

/* --- Verlauf als Zeitleiste (Erinnerungen und Mahnungen, 03.10.2026) ---- */
.verlauf { list-style: none; margin: 0; padding: 14px 20px 6px; }
.verlauf-eintrag { position: relative; display: flex; gap: 14px; padding-bottom: 16px; }
/* Die Linie verbindet die Punkte; beim letzten Eintrag endet sie. */
.verlauf-eintrag:not(:last-child)::before {
  content: ""; position: absolute; left: 15px; top: 34px; bottom: 2px;
  width: 2px; border-radius: 2px; background: var(--border);
}
.verlauf-punkt {
  flex: none; width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center; font-size: 0.9375rem;
  background: var(--info-bg, var(--indigo-50)); color: var(--info-fg, var(--indigo-700));
}
.verlauf-eintrag.is-warning .verlauf-punkt { background: var(--warning-bg); color: var(--warning-fg); }
.verlauf-eintrag.is-danger  .verlauf-punkt { background: var(--danger-bg);  color: var(--danger-fg); }
.verlauf-inhalt { flex: 1 1 auto; min-width: 0; padding-top: 5px; }
.verlauf-kopf { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px 12px; }
.verlauf-kopf time { font-size: 0.8125rem; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.verlauf-text { margin-top: 2px; font-size: 0.8125rem; color: var(--muted); overflow-wrap: anywhere; }
.verlauf-marken { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
@media (max-width: 720px) { .verlauf { padding: 12px 14px 4px; } }

/* --- Tabellen am Telefon als Liste (seit 03.10.2026) --------------------- */
/*
Jede Tabelle, die nicht in ihre Breite passt (am Telefon jede), wird
zur Liste: app.js beschriftet sie (Etikett aus dem Kopf, Rolle der
Zelle) und setzt `.karten-aktiv`, solange sie nicht passt — gemessen,
nicht an einer festen Breite: ein iPad hochkant ist breiter als ein
Telefon, und eine achtspaltige Tabelle passt dort trotzdem nicht. Aufbau eines Eintrags, als Raster mit zwei Spalten:

   Titel (erste Spalte, fett)          [Zustand]
   ETIKETT            ETIKETT
   Wert               Wert
   [ Knopf in voller Breite ]

Vorbild sind die Listen von Stripe, Linear und GitHub am Telefon: eine
Zeile ist ein Gegenstand, nicht ein Streifen Zellen. Der ganze Eintrag
ist antippbar, wenn der Titel auf eine Seite verweist (`.karte-ziel`
spannt sich über den Eintrag; Knöpfe und Felder liegen darüber).
*/
.table-wrap:has(> .karten-aktiv) {
  overflow: visible; background: none;
}
.karten-aktiv { min-width: 0 !important; width: 100%; display: block; font-size: 0.875rem; }
.karten-aktiv thead { display: none; }
.karten-aktiv tbody { display: block; }
.karten-aktiv tr {
  position: relative;
  display: grid;
  /* So viele Spalten, wie Platz haben: am Telefon zwei, am iPad mehr.
     Nie weniger als zwei (seit 04.10.2026): Titel und Zustand stehen in
     Spalte 1 bis -2 und -2 bis -1 — bei einer einzigen Spalte lagen beide
     übereinander, auf jedem iPhone unter 398 px. */
  grid-template-columns: repeat(auto-fill, minmax(min(150px, calc(50% - 8px)), 1fr));
  column-gap: 16px; row-gap: 12px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--rule);
  transition: background-color .15s;
}
.karten-aktiv tbody tr:last-child { border-bottom: 0; }
.karten-aktiv tr.hat-ziel { cursor: pointer; }
.karten-aktiv tr.hat-ziel:active { background: var(--row-hover); }
.karten-aktiv td {
  display: block; min-width: 0; max-width: none !important;
  padding: 0; border: 0; text-align: left; white-space: normal;
  overflow-wrap: anywhere;
  position: static !important; background: none !important;
}
/* Etikett über dem Wert. */
.karten-aktiv td[data-rolle="angabe"]::before {
  content: attr(data-label);
  display: block; margin-bottom: 3px;
  font-size: 0.75rem; font-weight: 500; line-height: 1.3;
  color: var(--muted);
}
/* Erst der Wert, dann das Etikett — der Wert trägt die Auskunft. */
.karten-aktiv td[data-rolle="angabe"] { font-weight: 500; color: var(--heading); }
.karten-aktiv td[data-rolle="angabe"].strong { font-weight: 700; }
.karten-aktiv td[data-rolle="angabe"] .tiny,
.karten-aktiv td[data-rolle="angabe"] .cell-sub,
.karten-aktiv td[data-rolle="angabe"] .muted { font-weight: 400; }

/* Antippbar: ein Pfeil rechts, wie in den Listen von iOS. */
.karten-aktiv tr.hat-ziel { padding-right: 38px; }
.karten-aktiv tr.hat-ziel::after {
  content: ""; position: absolute; right: 16px; top: 50%;
  width: 8px; height: 8px; margin-top: -4px;
  border-top: 2px solid var(--field-border);
  border-right: 2px solid var(--field-border);
  border-radius: 1px; transform: rotate(45deg);
  pointer-events: none;
}
.karten-aktiv td[data-rolle="angabe"] { order: 10; }
.karten-aktiv td[data-breit] { grid-column: span 2; }
.karten-aktiv td[data-leer] { display: none; }

/* Titel: erste Zeile, links; ohne Zustand über die ganze Breite. */
.karten-aktiv td[data-rolle="titel"] {
  grid-column: 1 / -1; grid-row: 1; order: 0;
  font-size: 0.9375rem; line-height: 1.35;
}
.karten-aktiv tr.hat-status td[data-rolle="titel"] { grid-column: 1 / -2; }
.karten-aktiv td[data-rolle="titel"] a { font-weight: 600; color: var(--heading); }
/* Der Verweis des Titels deckt den ganzen Eintrag. */
.karten-aktiv .karte-ziel::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.karten-aktiv tr.hat-ziel a:not(.karte-ziel),
.karten-aktiv tr.hat-ziel button,
.karten-aktiv tr.hat-ziel input,
.karten-aktiv tr.hat-ziel select,
.karten-aktiv tr.hat-ziel label,
.karten-aktiv tr.hat-ziel form { position: relative; z-index: 2; }

/* Zustand: oben rechts. Die Zelle löst sich auf, damit ein Knopf
   darin (etwa «Mahnen») unten bei den übrigen Knöpfen landet. */
.karten-aktiv td[data-rolle="status"] { display: contents; }
.karten-aktiv td[data-rolle="status"] > .badge,
.karten-aktiv td[data-rolle="status"] > :first-child:not(.btn):not(form) {
  grid-column: -2 / -1; grid-row: 1; justify-self: end; align-self: start;
  text-align: right; max-width: 100%;
}
.karten-aktiv td[data-rolle="status"] > .btn,
.karten-aktiv td[data-rolle="status"] > form {
  grid-column: 1 / -1; order: 90; margin: 0 !important; justify-self: start;
}
.karten-aktiv td[data-rolle="status"] > :not(.badge):not(.btn):not(form):not(:first-child) {
  grid-column: 1 / -1; order: 5;
}

/* Knöpfe: unten, nebeneinander, gross genug für den Finger. */
.karten-aktiv td[data-rolle="aktion"] {
  grid-column: 1 / -1; order: 99;
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  white-space: normal;
}
.karten-aktiv td[data-rolle="aktion"]:empty { display: none; }
.karten-aktiv td[data-rolle="aktion"] > * + * { margin-left: 0; }
.karten-aktiv td[data-rolle="aktion"] .btn,
.karten-aktiv td[data-rolle="status"] > .btn { min-height: 38px; padding-left: 16px; padding-right: 16px; }

/* Auswahlkästchen links neben dem Titel. */
.karten-aktiv tr.hat-auswahl { padding-left: 48px; }
.karten-aktiv td[data-rolle="auswahl"] { position: absolute !important; left: 16px; top: 15px; }

/* Überfällig: der rote Streifen links am ganzen Eintrag. */
.karten-aktiv tr.is-overdue { box-shadow: inset 3px 0 0 var(--danger-fg); }
.karten-aktiv tr.is-overdue > td:first-child { box-shadow: none; }

/* Zeilen, die über alle Spalten gehen (Leerhinweis, Zwischentitel). */
.karten-aktiv tr.karte-voll { display: block; }
.karten-aktiv tr.karte-voll td { padding: 4px 0; }

@media (max-width: 720px) {
  /* Kennzahlen am Telefon zu zweit statt einzeln untereinander — sechs
     Kacheln kosteten sonst zwei Bildschirmhöhen, bevor eine Liste kam.
     Symbol und Zahl nebeneinander, die Beschriftung darunter. */
  .grid:has(> .card-stat) { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .grid > .card-stat { margin-bottom: 0; }
  .card-stat .stat { padding: 14px; gap: 10px; flex-wrap: wrap; align-items: center; }
  .card-stat .stat-icon { width: 34px; height: 34px; border-radius: 10px; font-size: 1rem; }
  .card-stat .stat-body { display: contents; }
  .card-stat .stat .v { order: 1; margin-top: 0; font-size: 1.625rem; }
  .card-stat .stat .k { order: 2; flex: 1 0 100%; font-size: 0.8125rem; line-height: 1.3; }
}

/* Roter Hinweis-Kasten — für unwiderrufliche Aktionen (endgültig löschen). */
.alert.danger { background: var(--danger-bg); color: var(--danger-fg); border-color: var(--danger-bd, var(--border)); }

/* Kritische Aufgaben (Phasen-Tor) und gesperrte Phasen im Plan-Reiter. */
.krit-chip { display: inline-block; margin-left: 8px; padding: 1px 8px; border-radius: 999px;
             font-size: 0.6875rem; font-weight: 600; background: var(--danger-bg); color: var(--danger-fg); vertical-align: 1px; }
.gesperrt-chip { display: inline-block; margin-left: 8px; padding: 1px 8px; border-radius: 999px;
                 font-size: 0.6875rem; font-weight: 600; background: var(--surface-muted); color: var(--muted); vertical-align: 1px; }

/* Live-Zähler: dezenter Hinweis, wenn neue Einträge aufgelaufen sind.
   Mittig über `left`/`right` und `margin: auto` statt `left: 50%` (seit
   04.10.2026): so blieb einem festen Element nur die halbe Breite, und am
   Telefon brach der Satz in einen Klumpen von sechs Zeilen um. */
.puls-hinweis {
  position: fixed; left: 16px; right: 16px; bottom: calc(20px + env(safe-area-inset-bottom));
  margin: 0 auto; width: max-content; max-width: calc(100vw - 32px);
  z-index: 60; display: flex; align-items: center; gap: 12px;
  /* Umgekehrt zur Seite: hell dunkel auf weiss, dunkel hell auf schwarz. */
  background: var(--heading); color: var(--surface);
  padding: 10px 12px 10px 18px; border-radius: 999px;
  box-shadow: 0 6px 24px rgba(16, 20, 35, .28); font-size: 0.875rem;
}
@media (prefers-reduced-motion: no-preference) { .puls-hinweis { animation: puls-auf .25s ease-out; } }
@keyframes puls-auf { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }




/* --- Veranstaltungen und Beratung (Webseite) ----------------------------- */
/*
  Karten wie ein Aushang: Art oben als kleines Schild, Titel, Zielgruppe
  oder Ort, darunter Datum und Zeit. Die Farbe sagt die Art — Online blau,
  vor Ort und Messe gelb, Tagung rot — und kommt aus den Rollen, damit sie
  auch dunkel stimmt. Die ganze Karte ist der Verweis.
*/
/*
  Seit dem 30.09.2026 ein Raster mit Detailfeld (partials/events-tabs):
  vier Kacheln je Zeile, umbrechend wie ein Aushang. Das Feld steht im
  Quelltext hinter seiner Kachel und spannt über alle Spalten; `dense`
  füllt die Zeile der Kachel mit den folgenden auf, das Feld landet
  darunter. Die gewählte Kachel ist blau umrandet und zeigt mit einem
  Pfeil auf ihr Feld.
*/
.event-reiter { margin-top: 24px; }
.event-raster {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-flow: row dense; gap: 14px;
}
.event-raster > .event-feld { grid-column: 1 / -1; scroll-margin-top: calc(var(--kopf-hoehe) + 16px); }
@media (max-width: 1080px) { .event-raster { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px)  { .event-raster { grid-template-columns: minmax(0, 1fr); } }
.event-tab {
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
  padding: 16px 18px 18px;
  border: 1px solid var(--info-bd); border-radius: var(--radius-sm);
  background: var(--info-bg); color: var(--text); text-decoration: none;
  transition: background .12s ease, border-color .12s ease;
}
.event-tab:hover { text-decoration: none; border-color: var(--accent); }
.event-tab:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.event-tab.is-note   { background: var(--note-bg);   border-color: var(--note-bd); }
.event-tab.is-danger { background: var(--danger-bg); border-color: var(--danger-bd); }
.event-tab[aria-expanded="true"] {
  position: relative;
  background: var(--surface); border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
/* Ein Pfeil unter der gewählten Kachel zeigt auf ihr Feld. Vorher lief die
   Kachel weiss ins Feld hinein; in der ersten Spalte stiess sie dabei auf
   dessen runde Ecke, und der Übergang sah nach einem Riss aus. */
.event-tab[aria-expanded="true"]::after {
  content: ""; position: absolute; left: 50%; bottom: -9px;
  width: 16px; height: 16px; transform: translateX(-50%) rotate(45deg);
  background: var(--surface);
  border-right: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
}
.event-typ {
  align-self: flex-start; margin-bottom: 6px; padding: 2px 8px; border-radius: 4px;
  font-size: 0.7188rem; font-weight: 700; letter-spacing: .02em;
  background: var(--accent); color: var(--on-brand);
}
.is-note .event-typ   { background: var(--warning-fg); color: var(--on-brand); }
.is-danger .event-typ { background: var(--danger-solid); color: var(--on-danger); }
.event-titel { font-size: 1.125rem; line-height: 1.3; color: var(--heading); }
.event-unter { font-size: 0.9062rem; color: var(--text); }
.event-wann  { margin-top: auto; padding-top: 16px; font-size: 0.9062rem; line-height: 1.5; color: var(--text); }

.event-feld {
  position: relative;
  display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 36px; align-items: start;
  padding: 44px 32px 32px; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface);
}
.event-feld[hidden] { display: none; }
.event-feld-text p { font-size: 1rem; line-height: 1.65; margin: 0 0 14px; color: var(--text); }
.event-feld-text .event-einstieg { font-weight: 600; color: var(--heading); }
.event-kasten {
  display: flex; flex-direction: column; gap: 10px;
  padding: 22px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.event-kasten h3 { margin: 0; font-size: 1.25rem; color: var(--heading); }
.event-kasten-ort, .event-kasten-wann { margin: 0; font-size: 0.9375rem; line-height: 1.5; color: var(--text); }
.event-kasten-titel {
  margin: 8px 0 0; padding-bottom: 6px; border-bottom: 1px solid var(--rule);
  font-size: 0.8438rem; font-weight: 600; color: var(--muted);
}
.event-kasten-leute { display: grid; gap: 12px; margin: 4px 0 6px; padding: 0; list-style: none; }
.event-kasten-leute li { display: flex; align-items: center; gap: 12px; }
.event-kasten-leute strong { display: block; font-size: 0.9375rem; color: var(--heading); }
.event-kasten-funktion { display: block; font-size: 0.8125rem; color: var(--muted); }
.event-kasten-leute a { font-size: 0.8125rem; }
.event-anmelden { display: inline-flex; align-items: center; justify-content: center; gap: 8px; margin-top: 6px; }

/* Referenten (seit 30.09.2026): Foto rund, ohne Foto der erste Buchstabe. */
.referent-foto { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.referent-foto.is-gross { width: 48px; height: 48px; }
.referent-foto.is-vorschau { width: 88px; height: 88px; }
.referent-foto.is-vorschau.is-leer svg { width: 40px; height: 40px; }
.referent-foto.is-leer {
  display: inline-grid; place-items: center; background: var(--accent-soft); color: var(--accent-soft-text);
  font-weight: 700; font-size: 0.875rem;
}
.referent-foto.is-gross.is-leer { font-size: 1.125rem; }
/* Vorschau und Dateiwahl untereinander: die rechte Spalte ist schmal, und
   nebeneinander schnitt sie «Datei auswählen» und den Hinweis ab. */
.referent-foto-feld { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; margin-bottom: 14px; }
.referent-foto-wahl { margin: 0; width: 100%; min-width: 0; }
.referent-foto-wahl input[type="file"] { width: 100%; max-width: 100%; }
.referent-wahl { display: grid; gap: 6px; padding: 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); }
.referent-wahl-zeile { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 0.875rem; }
.referent-wahl-zeile > label { display: flex; align-items: center; gap: 10px; min-width: 0; cursor: pointer; }
.referent-wahl-pfeile { display: inline-flex; gap: 2px; flex: 0 0 auto; }
.referent-wahl-pfeile .btn { width: 28px; height: 28px; padding: 0; justify-content: center; }
.referent-wahl-pfeile .btn:disabled { opacity: .35; }
.referent-liste { list-style: none; margin: 0; padding: 0; }
.referent-liste li + li { border-top: 1px solid var(--rule); }
.referent-liste a { display: flex; align-items: center; gap: 12px; padding: 12px 18px; color: var(--text); text-decoration: none; }
.referent-liste a:hover { background: var(--row-hover); }
.referent-liste li[aria-current="true"] a { background: var(--accent-soft); }
.referent-liste strong { display: block; color: var(--heading); }

/* Backoffice, Liste der Veranstaltungen: Aktionen untereinander. */
.event-admin-aktionen { width: 1%; }
.event-admin-aktionen > * { display: flex; justify-content: flex-end; margin: 0 0 6px; white-space: nowrap; }
.event-admin-aktionen > *:last-child { margin-bottom: 0; }
.event-admin-aktionen form { display: flex; justify-content: flex-end; }

/* Orange heisst «Achtung, aber nichts wird gelöscht» — etwa «Ausgebucht». */
.btn-warning { background: var(--warning-fg); color: var(--on-brand); }
.btn-warning:hover { filter: brightness(.92); }

/* «Schliessen» oben rechts im Feld. */
.event-feld-zu {
  position: absolute; top: 12px; right: 16px;
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 0.8125rem; color: var(--muted); text-decoration: none;
}
.event-feld-zu:hover { color: var(--accent-text); }
.event-feld-zu-pfeil { transform: rotate(-90deg); }

/* Die Anmeldekarte unter der Beschreibung. */
.event-anmeldekarte {
  margin-top: 26px; padding: 22px 24px 24px;
  border: 1px solid var(--accent-soft); border-radius: var(--radius);
  background: linear-gradient(180deg, var(--auth-flaeche), var(--surface) 120px);
}
.event-anmeldekarte.is-voll { border-color: var(--warning-bd); background: var(--surface); }
/* Felder erst nach «Jetzt anmelden» (Anker, :target) — partials/event-anmeldung. */
.event-anmeldekarte { scroll-margin-top: calc(var(--kopf-hoehe) + 16px); }
.event-oeffnen { display: none; }
.event-anmeldekarte.is-zu:not(:target) .event-oeffnen { display: inline-flex; }
.event-anmeldekarte.is-zu:not(:target) .event-formular { display: none; }
.event-anmeldekarte-kopf { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 6px 14px; margin-bottom: 16px; }
.event-anmeldekarte-kopf h3 { margin: 0; font-size: 1.25rem; color: var(--heading); }
.event-platzbalken { height: 6px; margin: -8px 0 18px; border-radius: 999px; background: var(--accent-soft); overflow: hidden; }
.event-platzbalken span { display: block; height: 100%; border-radius: 999px; background: var(--accent); }
.event-anmeldekarte.is-voll .event-platzbalken span { background: var(--warning-fg); }
.event-anmeldekarte-kopf .event-plaetze { white-space: nowrap; }
.event-formular-raster { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
.event-formular-fuss { display: flex; align-items: center; justify-content: space-between; gap: 18px; margin-top: 6px; }
.event-formular-fuss .event-datenschutz,
.event-feld-text .event-formular-fuss .event-datenschutz,
.event-seite-inhalt .event-formular-fuss .event-datenschutz { margin: 0; max-width: 340px; font-size: 0.7812rem; line-height: 1.5; color: var(--muted); }
.event-feld-text .event-hakenliste li { font-size: 0.9375rem; }
.event-danke { display: flex; align-items: center; gap: 14px; padding: 16px; border-radius: var(--radius-sm); background: var(--success-bg); color: var(--success-fg); }
.event-danke strong { font-size: 1.0625rem; }
.event-danke p { margin: 2px 0 0; font-size: 0.875rem; }
.event-danke-zeichen { display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; background: var(--success-fg); color: var(--surface); font-size: 1.375rem; flex: 0 0 auto; }
.event-kasten-status { display: flex; align-items: center; gap: 6px; margin: 6px 0 0; padding: 10px 12px; border-radius: var(--radius-sm); font-weight: 600; font-size: 0.875rem; }
.event-kasten-status.is-ok { background: var(--success-bg); color: var(--success-fg); }
.event-kasten-status.is-voll { background: var(--warning-bg); color: var(--warning-fg); }
@media (max-width: 720px) {
  .event-formular-raster { grid-template-columns: minmax(0, 1fr); }
  .event-formular-fuss { flex-direction: column; align-items: stretch; }
}

/* Plätze auf der Karte und die direkte Anmeldung im Kasten (seit 30.09.2026). */
.event-platz {
  align-self: flex-start; margin-top: 10px; padding: 2px 9px; border-radius: 999px;
  font-size: 0.75rem; font-weight: 600; background: var(--success-bg); color: var(--success-fg);
  border: 1px solid var(--success-bd);
}
.event-platz.is-voll { background: var(--warning-bg); color: var(--warning-fg); border-color: var(--warning-bd); }
.event-anmeldung { display: flex; flex-direction: column; gap: 10px; margin-top: 6px; padding-top: 14px; border-top: 1px solid var(--rule); }
.event-plaetze { margin: 0; font-size: 0.8438rem; font-weight: 600; color: var(--success-fg); }
.event-plaetze.is-voll { color: var(--warning-fg); }
.event-formular .field { margin-bottom: 10px; }
.event-formular .btn { margin-top: 4px; }
.event-datenschutz { margin: 8px 0 0; font-size: 0.75rem; line-height: 1.5; color: var(--muted); }
.event-rueckmeldung {
  display: flex; flex-direction: column; gap: 2px; padding: 12px 14px; border-radius: var(--radius-sm);
  font-size: 0.875rem; background: var(--info-bg); color: var(--info-fg); border: 1px solid var(--info-bd);
}
.event-rueckmeldung.is-ok { background: var(--success-bg); color: var(--success-fg); border-color: var(--success-bd); }
.event-ausgebucht {
  display: flex; flex-direction: column; gap: 4px; padding: 14px; border-radius: var(--radius-sm);
  background: var(--warning-bg); color: var(--warning-fg); border: 1px solid var(--warning-bd); font-size: 0.875rem;
}
.event-ausgebucht strong { font-size: 1rem; }
.event-ausgebucht a { color: inherit; text-decoration: underline; }
.event-abmelden { padding: 32px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.event-abmelden h1 { font-size: 1.625rem; margin-bottom: 12px; }
.event-abmelden-was { padding: 12px 14px; border-radius: var(--radius-sm); background: var(--surface-muted); }
.event-kasten-link { display: inline-flex; align-items: center; justify-content: center; gap: 6px; font-size: 0.8438rem; }
.event-kasten-link svg { width: 15px; height: 15px; }

@media (max-width: 860px) {
  .event-feld { grid-template-columns: minmax(0, 1fr); padding: 22px 18px; }
  .event-kasten { order: -1; }
}
@media (prefers-reduced-motion: reduce) { .event-tab { transition: none; } }

/*
  Die Seite eines Anlasses (neu gestaltet 30.09.2026): Kopf mit Schild,
  Datum, Zeit, Ort und Plätzen; darunter die Beschreibung als weisse
  Fläche, rechts der Kasten, der beim Scrollen stehen bleibt.
*/
.event-liste { margin: 0 0 18px; padding-left: 20px; }
.event-liste li { margin-bottom: 8px; line-height: 1.55; }
.event-zwischentitel { margin: 32px 0 14px; font-size: 1.25rem; }

.event-kopf .event-typ { margin: 6px 0 12px; font-size: 0.7812rem; }
.event-kopf h1 { margin-bottom: 18px; }
.event-kopf-fakten { display: flex; flex-wrap: wrap; gap: 10px; margin: 0; padding: 0; list-style: none; }
.event-kopf-fakten li {
  display: inline-flex; align-items: center; gap: 8px; padding: 7px 12px; border-radius: 999px;
  background: rgba(255, 255, 255, .1); color: var(--on-ink); font-size: 0.9062rem;
}
.event-kopf-fakten svg { width: 17px; height: 17px; opacity: .85; }
.event-kopf-fakten .event-kopf-platz { background: var(--success-bg); color: var(--success-fg); font-weight: 600; }
.event-kopf-fakten .event-kopf-platz.is-voll { background: var(--warning-bg); color: var(--warning-fg); }

.event-seite-raster { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 28px; align-items: start; }
.event-seite-inhalt {
  padding: 34px 36px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.event-seite-inhalt p { font-size: 1.0312rem; line-height: 1.7; margin: 0 0 16px; color: var(--text); }
.event-seite-inhalt .event-einstieg { font-size: 1.1875rem; line-height: 1.55; font-weight: 600; color: var(--heading); }
.event-hakenliste { display: grid; gap: 10px; margin: 4px 0 20px; padding: 0; list-style: none; }
.event-hakenliste li { display: flex; align-items: flex-start; gap: 10px; font-size: 1rem; line-height: 1.5; color: var(--text); }
.event-hakenliste svg {
  flex: 0 0 auto; width: 22px; height: 22px; padding: 3px; margin-top: 1px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-soft-text); stroke-width: 2.4;
}
.event-leute { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; margin: 0; padding: 0; list-style: none; }
.event-leute li { display: flex; align-items: center; gap: 14px; padding: 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.event-leute strong { display: block; font-size: 0.9688rem; color: var(--heading); }
.event-leute a { font-size: 0.8125rem; }
.referent-foto.is-seite { width: 72px; height: 72px; font-size: 1.625rem; }

.event-seite-kasten { position: sticky; top: 90px; }
.event-kasten-fakten { display: grid; gap: 10px; margin: 4px 0 8px; padding: 0; list-style: none; }
.event-kasten-fakten li { display: flex; align-items: flex-start; gap: 10px; font-size: 0.9375rem; color: var(--heading); }
.event-kasten-fakten svg { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 2px; color: var(--accent); }

.event-weitere-titel { font-size: 1.375rem; margin-bottom: 16px; }
.event-weitere { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; margin: 0; padding: 0; list-style: none; }
.event-weitere .event-tab { height: 100%; margin: 0; }

@media (max-width: 860px) {
  .event-seite-raster { grid-template-columns: minmax(0, 1fr); }
  .event-seite-kasten { position: static; order: -1; }
  .event-seite-inhalt { padding: 22px 18px; }
}

/*
  «Wir beraten dich gerne!» (neu gestaltet 30.09.2026).

  Kopf mittig, darunter die Wege als Karten mit gezeichneter Abbildung.
  Das Raster richtet sich nach der Zahl der Wege (`is-anzahl-N`, siehe
  partials/beratung.php): drei nebeneinander, zwei mittig und breiter,
  einer als breite Karte mit Bild links. So bleibt das Bild ruhig, wenn
  im Backoffice ein Weg abgeschaltet wird.
*/
.beratung {
  padding: 40px 36px; border-radius: var(--radius);
  background: var(--accent-soft);
}
.beratung-kopf { max-width: 620px; margin: 0 auto 28px; text-align: center; }
.beratung-kopf h2 { font-size: 1.75rem; color: var(--heading); margin-bottom: 8px; }
.beratung-kopf p { color: var(--text); margin: 0; font-size: 1rem; }

.beratung-wege { list-style: none; margin: 0 auto; padding: 0; display: grid; gap: 18px; }
.beratung.is-anzahl-3 .beratung-wege { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.beratung.is-anzahl-2 .beratung-wege { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 780px; }
.beratung.is-anzahl-1 .beratung-wege { grid-template-columns: minmax(0, 1fr); max-width: 780px; }

.beratung-weg {
  display: flex; flex-direction: column; height: 100%;
  border-radius: var(--radius); background: var(--surface); border: 1px solid var(--border);
  color: var(--heading); text-decoration: none; overflow: hidden;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.beratung-weg:hover { text-decoration: none; border-color: var(--accent); box-shadow: var(--shadow-lg); transform: translateY(-2px); }
.beratung-weg:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.beratung-bild { display: block; padding: 14px 14px 0; }
.beratung-bild svg { display: block; width: 100%; height: auto; }
.beratung-weg-text { position: relative; display: flex; flex-direction: column; gap: 4px; padding: 16px 48px 20px 20px; flex: 1 1 auto; }
.beratung-weg-titel { font-size: 1.0312rem; font-weight: 600; color: var(--heading); }
.beratung-weg-unter { font-size: 0.875rem; line-height: 1.5; color: var(--muted); }
.beratung-weg-pfeil {
  position: absolute; right: 16px; bottom: 18px;
  display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-soft-text);
  transition: background .15s, color .15s;
}
.beratung-weg-pfeil svg { width: 16px; height: 16px; }
.beratung-weg:hover .beratung-weg-pfeil { background: var(--accent); color: var(--on-brand); }

/* Ein Weg: breit, Bild links, Text rechts. */
.beratung.is-anzahl-1 .beratung-weg { flex-direction: row; align-items: stretch; }
.beratung.is-anzahl-1 .beratung-bild { flex: 0 0 300px; padding: 14px; }
.beratung.is-anzahl-1 .beratung-weg-text { justify-content: center; padding: 24px 64px 24px 12px; }
.beratung.is-anzahl-1 .beratung-weg-titel { font-size: 1.25rem; }
.beratung.is-anzahl-1 .beratung-weg-pfeil { top: 50%; bottom: auto; right: 24px; transform: translateY(-50%); width: 36px; height: 36px; }

/* Die Zeichnungen: nur Rollenmarken, keine Hexwerte. */
.bz-flaeche   { fill: var(--auth-flaeche); }
.bz-weiss     { fill: var(--surface); }
.bz-rand      { stroke: var(--border); stroke-width: 1.5; }
.bz-leiste    { fill: var(--surface-muted); }
.bz-punkt     { fill: var(--border); }
.bz-zeile     { fill: var(--heading); opacity: .85; }
.bz-zeile-hell{ fill: var(--accent-soft); }
.bz-mittel    { fill: var(--accent); opacity: .45; }
.bz-akzent, .bz-knopf { fill: var(--accent); }
.bz-haken     { fill: none; stroke: var(--on-brand); stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }
.bz-play      { fill: var(--on-brand); }
.bz-linie     { fill: none; stroke: var(--border); stroke-width: 3; stroke-linecap: round; }
.bz-welle     { fill: none; stroke: var(--accent); stroke-width: 3; stroke-linecap: round; }

@media (max-width: 860px) {
  .beratung { padding: 28px 18px; }
  .beratung.is-anzahl-3 .beratung-wege,
  .beratung.is-anzahl-2 .beratung-wege { grid-template-columns: minmax(0, 1fr); max-width: 480px; }
}
@media (max-width: 600px) {
  .beratung.is-anzahl-1 .beratung-weg { flex-direction: column; }
  .beratung.is-anzahl-1 .beratung-bild { flex-basis: auto; padding: 14px 14px 0; }
  .beratung.is-anzahl-1 .beratung-weg-text { padding: 16px 48px 20px 20px; }
  .beratung.is-anzahl-1 .beratung-weg-pfeil { top: auto; bottom: 18px; right: 16px; transform: none; width: 28px; height: 28px; }
}
@media (prefers-reduced-motion: reduce) { .beratung-weg, .beratung-weg-pfeil { transition: none; } .beratung-weg:hover { transform: none; } }

/* Akquise. Zwei Feldreihen untereinander brauchen denselben Abstand wie
   Feld und Reihe (siehe oben) — nur hier gesetzt, damit Formulare mit
   eigenem Abstand zwischen ihren Reihen unberührt bleiben. */
.akquise-form .grid + .grid { margin-top: 20px; }
.akquise-form h3 { font-size: 0.9375rem; font-weight: 600; color: var(--heading); }
/* Die Liste bleibt bei Laptopbreite ohne Seitwärtsscrollen: Stand, Notiz
   und Handgriffe stehen untereinander in EINER Spalte. */
.akquise-wer { min-width: 200px; }
.akquise-stand-zelle { width: 300px; }
.akquise-stand { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; }
.akquise-stand .select, .akquise-stand .input { width: 100%; min-width: 0; }
.akquise-stand .select { grid-column: 1 / -1; }
.akquise-aktionen { display: flex; align-items: center; gap: 4px; margin-top: 6px; }
.akquise-fehler { max-width: 240px; color: var(--danger-fg); overflow-wrap: anywhere; }

/* --- Webseite: der Reiter in Microsoft Teams ------------------------------ */

/*
  Auf der Modulseite Microsoft 365. Text links, rechts ein gezeichnetes
  Teams-Fenster um das Bildschirmfoto des Reiters. Der Rahmen ist neutral
  (dunkle Leiste, Reiterkopf) — man erkennt Teams, ohne dass wir Microsofts
  Zeichen nachbauen. Die Fläche ist leicht getönt, damit der Abschnitt
  sich vom Raster der Punkte darüber absetzt.
*/
.section-teams {
  background: linear-gradient(180deg, var(--brand-50), var(--bg));
  border-top: 1px solid var(--border);
}
.teams-split {
  display: grid; gap: 40px; align-items: center;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
}
.teams-text .lead { color: var(--muted); font-size: 1.0625rem; line-height: 1.6; margin-top: var(--abstand-2); }
.teams-punkte { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 16px; }
.teams-punkte li { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; line-height: 1.55; color: var(--text); }
.teams-punkte strong { color: var(--heading); font-weight: 600; }
.teams-punkt-icon {
  display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 8px;
  background: var(--accent-soft); color: var(--accent);
}
.teams-punkt-icon svg { width: 16px; height: 16px; }

.teams-shot { margin: 0; }
.teams-fenster {
  display: grid; grid-template-columns: 52px minmax(0, 1fr);
  border-radius: 14px; overflow: hidden;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  box-shadow: 0 24px 60px -20px rgba(10, 20, 45, .28);
}
.teams-leiste {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 16px 0; background: var(--ink);
}
.teams-leiste i {
  width: 22px; height: 22px; border-radius: 6px; background: var(--ink-card);
  border: 1px solid var(--ink-border);
}
.teams-app {
  display: grid; place-items: center; width: 34px; height: 34px; border-radius: 9px;
  background: var(--accent); position: relative;
}
/* Der Strich links: die gewählte App, wie Teams es zeigt. */
.teams-app::before {
  content: ""; position: absolute; left: -9px; top: 7px; bottom: 7px; width: 3px;
  border-radius: 2px; background: var(--on-ink);
}
.teams-haupt { min-width: 0; }
/* Nicht `.teams-kopf`: so heisst der Kopf des echten Reiters (`teams.css`),
   und `app.css` gilt dort mit — er bekam diesen grauen Grund ab. */
.teams-fensterkopf {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px 0; border-bottom: 1px solid var(--border);
  background: var(--surface-muted); font-size: 0.875rem; color: var(--heading);
}
.teams-fensterkopf img { flex: 0 0 auto; margin-bottom: 10px; }
.teams-fensterkopf strong { font-weight: 600; margin-bottom: 10px; }
.teams-reitername {
  margin-left: 12px; padding: 0 2px 9px; font-size: 0.8125rem; color: var(--heading);
  border-bottom: 2px solid var(--accent);
}
.teams-haupt a[data-lightbox] { display: block; }
.teams-haupt a img { display: block; width: 100%; height: auto; }
.teams-shot figcaption { margin-top: 14px; color: var(--muted); font-size: 0.9062rem; line-height: 1.6; }

@media (max-width: 1000px) {
  .teams-split { grid-template-columns: minmax(0, 1fr); gap: 32px; }
}
@media (max-width: 640px) {
  .teams-fenster { grid-template-columns: 36px minmax(0, 1fr); }
  .teams-leiste { gap: 10px; padding: 12px 0; }
  .teams-leiste i { width: 16px; height: 16px; }
  .teams-app { width: 26px; height: 26px; }
  .teams-app img { width: 14px; height: 14px; }
  .teams-app::before { left: -5px; }
}

/*
  Die Checkliste unter einem neuen Passwort (partials/passwort-regeln,
  app.js). Leere Kreise, die beim Tippen grün werden; ohne Skript bleibt
  es eine Liste der Regeln.
*/
.passwort-regeln {
  margin: -4px 0 16px; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface);
}
.passwort-regeln-titel { margin: 0 0 8px; font-size: 0.8125rem; font-weight: 600; color: var(--heading); }
.passwort-regeln ul { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.passwort-regeln li { display: flex; align-items: center; gap: 9px; font-size: 0.8438rem; color: var(--muted); }
.passwort-regel-zeichen {
  position: relative; flex: 0 0 auto;
  width: 18px; height: 18px; border-radius: 50%;
  border: 1.5px solid var(--muted); opacity: .55;
  transition: background .15s, border-color .15s, opacity .15s;
}
.passwort-regel-zeichen::after {
  content: ""; position: absolute; left: 5px; top: 2px;
  width: 4px; height: 8px;
  border: solid var(--muted); border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}
.passwort-regeln li.is-ok { color: var(--text); }
.passwort-regeln li.is-ok .passwort-regel-zeichen { background: var(--success-fg); border-color: var(--success-fg); opacity: 1; }
.passwort-regeln li.is-ok .passwort-regel-zeichen::after { border-color: var(--surface); }
@media (prefers-reduced-motion: reduce) { .passwort-regel-zeichen { transition: none; } }

/* --- Die Webseite in Farbe (seit 30.09.2026) ------------------------------ */
/*
  Was die Startseite bekam, gilt auf allen Verkaufsseiten (body.webseite,
  layout/marketing.php): graue Abschnitte werden hellblau getönt, die
  Zeichen der Karten und die Nummern der Schritte nehmen reihum einen
  Akzentton. Über nth-child und nicht im Template, damit jede neue Karte
  ihren Ton ohne Zutun bekommt.
*/
.webseite .section-muted {
  background: linear-gradient(180deg, var(--ton-blau-bg), var(--surface-muted) 75%);
  border-color: transparent;
}
.webseite .grid > .feature:nth-child(6n+1) .icon { background: var(--ton-blau-bg); color: var(--ton-blau-fg); }
.webseite .grid > .feature:nth-child(6n+2) .icon { background: var(--ton-gruen-bg); color: var(--ton-gruen-fg); }
.webseite .grid > .feature:nth-child(6n+3) .icon { background: var(--ton-orange-bg); color: var(--ton-orange-fg); }
.webseite .grid > .feature:nth-child(6n+4) .icon { background: var(--ton-violett-bg); color: var(--ton-violett-fg); }
.webseite .grid > .feature:nth-child(6n+5) .icon { background: var(--ton-tuerkis-bg); color: var(--ton-tuerkis-fg); }
.webseite .grid > .feature:nth-child(6n+6) .icon { background: var(--ton-rosa-bg); color: var(--ton-rosa-fg); }
.webseite .schritt-karten > li:nth-child(6n+1) .schritt-nr { background: var(--ton-blau-bg); color: var(--ton-blau-fg); border-color: transparent; }
.webseite .schritt-karten > li:nth-child(6n+2) .schritt-nr { background: var(--ton-gruen-bg); color: var(--ton-gruen-fg); border-color: transparent; }
.webseite .schritt-karten > li:nth-child(6n+3) .schritt-nr { background: var(--ton-orange-bg); color: var(--ton-orange-fg); border-color: transparent; }
.webseite .schritt-karten > li:nth-child(6n+4) .schritt-nr { background: var(--ton-violett-bg); color: var(--ton-violett-fg); border-color: transparent; }
.webseite .schritt-karten > li:nth-child(6n+5) .schritt-nr { background: var(--ton-tuerkis-bg); color: var(--ton-tuerkis-fg); border-color: transparent; }
.webseite .schritt-karten > li:nth-child(6n+6) .schritt-nr { background: var(--ton-rosa-bg); color: var(--ton-rosa-fg); border-color: transparent; }

/* --- Seitliche Safe-Area (seit 04.10.2026) -------------------------------- */
/*
  `viewport-fit=cover` (layout/head.php) nimmt Safari die Ränder an der
  Kamera-Aussparung ab. Unten war das bedacht, seitlich nicht: im
  Querformat lagen Logo, Überschriften und Felder links unter der
  Aussparung. Hochkant sind beide Einzüge 0, dort ändert sich nichts.
  Die festen Flächen hängen nicht am Körper und brauchen es eigens.
*/
body {
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}
.site-menu-panel {
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}
@media (max-width: 1024px) {
  .buchen-leiste {
    padding-left: max(16px, env(safe-area-inset-left));
    padding-right: max(16px, env(safe-area-inset-right));
  }
}
@media (max-width: 720px) {
  .app-menu-panel {
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }
}

/* ===========================================================================
   Swyron AI (seit 04.10.2026)

   Das Zeichen (partials/swyron-ai-zeichen.php) in drei Zuständen:
   still, `lebt` (Ruhe mit Leben) und `denkt` (antwortet gerade).

   Die Trabanten laufen über `stroke-dashoffset` auf der Bahn selbst
   (pathLength 100 → eine Runde = 100), der Schweif läuft mit. Das System
   dreht über transform, Kern und Wellen über transform und opacity —
   kein Skript, kein SMIL, flüssig auch auf alten Tablets. Wer im System
   weniger Bewegung eingestellt hat, sieht nur ein ruhiges Atmen.
   =========================================================================== */
.sai-zeichen { color: var(--accent); flex: none; overflow: visible; }
.sai-zeichen .sai-system,
.sai-zeichen .sai-kern,
.sai-zeichen .sai-welle { transform-box: view-box; transform-origin: 50% 50%; }
.sai-zeichen ellipse { fill: none; stroke: currentColor; stroke-linecap: round; }
.sai-zeichen .sai-ring { stroke-width: 2.2; transition: opacity .6s ease; }
.sai-zeichen .sai-bahn-1 .sai-ring { stroke-dasharray: 82 18; stroke-dashoffset: -9; }
.sai-zeichen .sai-bahn-2 .sai-ring { stroke-dasharray: 74 26; stroke-dashoffset: -62; }
.sai-zeichen .sai-bahn-3 .sai-ring { stroke-dasharray: 66 34; stroke-dashoffset: -66; }
.sai-zeichen .sai-trabant { stroke-dasharray: .001 99.999; }
.sai-zeichen .sai-schweif { opacity: 0; stroke-width: 2.2; transition: opacity .6s ease; }
.sai-zeichen .sai-schweif-lang { stroke-dasharray: 26 74; }
.sai-zeichen .sai-schweif-kurz { stroke-dasharray: 11 89; stroke-width: 2.8; }
.sai-zeichen .sai-welle { opacity: 0; }

/* Wo die Trabanten stehen (still): 0, 50 und 50 von 100 — wie im
   gedruckten Zeichen am äusseren Ende jeder Bahn — und von dort
   laufen sie los. Der Schweif endet am Trabanten. */
.sai-zeichen .sai-bahn-1 .sai-trabant { stroke-dashoffset: 0; }
.sai-zeichen .sai-bahn-2 .sai-trabant { stroke-dashoffset: -50; }
.sai-zeichen .sai-bahn-3 .sai-trabant { stroke-dashoffset: -50; }

/* Unterwegs: Bahnen treten zurück, Schweife erscheinen. */
.sai-zeichen.lebt .sai-ring,
.sai-zeichen.denkt .sai-ring { opacity: .28; }
.sai-zeichen.lebt .sai-schweif-lang,
.sai-zeichen.denkt .sai-schweif-lang { opacity: .28; }
.sai-zeichen.lebt .sai-schweif-kurz,
.sai-zeichen.denkt .sai-schweif-kurz { opacity: .65; }

.sai-zeichen.lebt .sai-bahn-1 > *:not(.sai-ring) { animation-duration: 7s; }
.sai-zeichen.lebt .sai-bahn-2 > *:not(.sai-ring) { animation-duration: 9.5s; }
.sai-zeichen.lebt .sai-bahn-3 > *:not(.sai-ring) { animation-duration: 12s; }
.sai-zeichen.denkt .sai-bahn-1 > *:not(.sai-ring) { animation-duration: 1.15s; }
.sai-zeichen.denkt .sai-bahn-2 > *:not(.sai-ring) { animation-duration: 1.5s; }
.sai-zeichen.denkt .sai-bahn-3 > *:not(.sai-ring) { animation-duration: 1.9s; }

.sai-zeichen:is(.lebt, .denkt) .sai-bahn-1 .sai-trabant      { animation-name: sai-lauf-1; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn-1 .sai-schweif-lang { animation-name: sai-lauf-1l; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn-1 .sai-schweif-kurz { animation-name: sai-lauf-1k; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn-2 .sai-trabant      { animation-name: sai-lauf-2; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn-2 .sai-schweif-lang { animation-name: sai-lauf-2l; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn-2 .sai-schweif-kurz { animation-name: sai-lauf-2k; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn-3 .sai-trabant      { animation-name: sai-lauf-3; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn-3 .sai-schweif-lang { animation-name: sai-lauf-3l; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn-3 .sai-schweif-kurz { animation-name: sai-lauf-3k; }
.sai-zeichen:is(.lebt, .denkt) .sai-bahn > *:not(.sai-ring) {
  animation-timing-function: linear; animation-iteration-count: infinite;
}
/* Trabant bei p, Schweif von p − Länge bis p; eine Runde = 100. */
@keyframes sai-lauf-1  { from { stroke-dashoffset: 0; }   to { stroke-dashoffset: -100; } }
@keyframes sai-lauf-1l { from { stroke-dashoffset: 26; }  to { stroke-dashoffset: -74; } }
@keyframes sai-lauf-1k { from { stroke-dashoffset: 11; }  to { stroke-dashoffset: -89; } }
@keyframes sai-lauf-2  { from { stroke-dashoffset: -50; } to { stroke-dashoffset: -150; } }
@keyframes sai-lauf-2l { from { stroke-dashoffset: -24; } to { stroke-dashoffset: -124; } }
@keyframes sai-lauf-2k { from { stroke-dashoffset: -39; } to { stroke-dashoffset: -139; } }
@keyframes sai-lauf-3  { from { stroke-dashoffset: -50; } to { stroke-dashoffset: -150; } }
@keyframes sai-lauf-3l { from { stroke-dashoffset: -24; } to { stroke-dashoffset: -124; } }
@keyframes sai-lauf-3k { from { stroke-dashoffset: -39; } to { stroke-dashoffset: -139; } }

/* Kern: atmet in Ruhe, pulsiert beim Denken. Wellen nur beim Denken. */
.sai-zeichen.lebt .sai-kern  { animation: sai-atmen 3.6s ease-in-out infinite; }
.sai-zeichen.denkt .sai-kern { animation: sai-puls .9s ease-in-out infinite; }
.sai-zeichen.denkt .sai-system { animation: sai-dreh 9s linear infinite; }
.sai-zeichen.denkt .sai-welle { animation: sai-welle 1.8s ease-out infinite; }
.sai-zeichen.denkt .sai-welle-2 { animation-delay: .9s; }
@keyframes sai-dreh   { to { transform: rotate(360deg); } }
@keyframes sai-atmen  { 50% { transform: scale(.86); } }
@keyframes sai-puls   { 50% { transform: scale(.7); opacity: .75; } }
@keyframes sai-welle  { from { transform: scale(.9); opacity: .55; } to { transform: scale(3.6); opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .sai-zeichen .sai-bahn > *, .sai-zeichen .sai-system, .sai-zeichen .sai-welle { animation: none !important; }
  .sai-zeichen .sai-ring { opacity: 1 !important; }
  .sai-zeichen .sai-schweif { opacity: 0 !important; }
  .sai-zeichen.lebt .sai-kern { animation: none; }
  .sai-zeichen.denkt .sai-kern { animation: sai-ruhig 1.6s ease-in-out infinite; }
}
@keyframes sai-ruhig { 50% { opacity: .45; } }

.sai-kopf { display: flex; align-items: center; gap: 14px; }
/*
  Die Gesprächsseite (seit 04.10.2026 neu): ein Fenster in Bildschirmhöhe.
  Nur das Gespräch scrollt, Kopf und Eingabe bleiben stehen. Die Höhe
  setzt app.js als --sai-hoehe (Abstand nach oben gemessen — Browser,
  Telefon und Teams-Reiter haben verschieden hohe Köpfe); ohne Skript gilt
  die Schätzung hier.
*/
.sai-seite { --sai-hoehe: calc(100dvh - 150px); }
.sai-karte {
  display: flex; flex-direction: column; overflow: hidden;
  height: var(--sai-hoehe); min-height: 440px; margin: 0;
}
.sai-karte-kopf {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 20px; border-bottom: 1px solid var(--rule); flex: none;
}
.sai-karte-kopf .btn { display: inline-flex; align-items: center; gap: 6px; }
.sai-karte-kopf .btn svg { width: 16px; height: 16px; }
.sai-titel { font-size: 1.125rem; margin: 0; line-height: 1.2; }
.sai-unter { margin: 2px 0 0; }
.sai-hinweis { margin: 12px 20px 0; flex: none; }
.sai-verlauf { display: flex; flex-direction: column; gap: 16px; padding: 20px; }
.sai-karte .sai-verlauf {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  scroll-behavior: smooth; scroll-padding: 16px;
}
@media (prefers-reduced-motion: reduce) { .sai-karte .sai-verlauf { scroll-behavior: auto; } }
.sai-karte .sai-verlauf > :first-child:not(.sai-leer) { margin-top: auto; }
.sai-karte .sai-frage, .sai-karte .sai-antwort { animation: sai-auftauchen .25s ease-out both; }

.sai-leer { margin: auto; text-align: center; max-width: 640px; padding: 12px 0; }
.sai-leer h2 { margin: 14px 0 6px; font-size: 1.375rem; }
.sai-leer > p { margin: 0 auto; max-width: 480px; }
.sai-vorschlaege {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-top: 22px; text-align: left;
}
.sai-vorschlag {
  display: flex; align-items: center; gap: 12px; width: 100%;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  border-radius: var(--radius); padding: 12px 14px; font: inherit; font-size: 0.875rem; line-height: 1.35;
  cursor: pointer; text-align: left; transition: border-color .15s, box-shadow .15s, transform .15s;
}
.sai-vorschlag:hover:not(:disabled) { border-color: var(--accent); box-shadow: var(--shadow-lg); transform: translateY(-1px); }
.sai-vorschlag:disabled { opacity: .55; cursor: default; }
/* Schritte mit Haken «probiert» (nummerierte Liste in einer Antwort). */
.sai-text .sai-haken-hinweis { margin: 10px 0 4px; font-size: 0.8125rem; color: var(--muted); }
/* Unter jeder Antwort: Kopieren und Melden als Symbole (seit 15.10.2026) */
.sai-text .sai-werkzeug { display: flex; align-items: center; gap: 2px; margin: 8px 0 0 -6px; }
.sai-symbol { width: 28px; height: 28px; display: inline-grid; place-items: center; border: 0; border-radius: 7px; background: none; color: var(--muted); cursor: pointer; padding: 0; }
.sai-symbol:hover { background: var(--row-hover); color: var(--text); }
.sai-symbol .sai-symbol-fertig { display: none; }
.sai-symbol.ist-kopiert .sai-symbol-normal { display: none; }
.sai-symbol.ist-kopiert .sai-symbol-fertig { display: inline; color: var(--success-fg); }
.sai-symbol.ist-gemeldet { color: var(--text); cursor: default; }
.sai-symbol.ist-gemeldet:hover { background: none; }
.sai-gemeldet { font-size: 0.75rem; color: var(--muted); margin-left: 4px; }
.sai-melden summary { list-style: none; }
.sai-melden summary::-webkit-details-marker { display: none; }
.sai-melden[open] summary { background: var(--row-hover); color: var(--text); }
/* Die Gründe klappen in der Antwort auf, unter den Symbolen — kein schwebendes
   Fenster, das am Rand des Gesprächs abgeschnitten würde. */
.sai-text .sai-werkzeug:has(.sai-melden[open]) { flex-wrap: wrap; }
.sai-melden[open] { display: contents; }
.sai-melden form { flex: 1 0 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 6px 0 0 6px; font-size: 0.75rem; color: var(--muted); }
.sai-grund { font: inherit; font-size: 0.75rem; line-height: 1.4; padding: 2px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--surface); color: var(--text); cursor: pointer; }
.sai-grund:hover { border-color: var(--accent); color: var(--accent); }
.sai-ki-zeile { flex: 1 1 auto; text-align: left; }
.sai-text ol.sai-schritte { list-style: none; padding-left: 0; counter-reset: sai-schritt; }
.sai-text ol.sai-schritte > li { display: flex; align-items: flex-start; gap: 10px; counter-increment: sai-schritt; }
.sai-text ol.sai-schritte > li > span::before { content: counter(sai-schritt) ". "; font-weight: 600; }
.sai-haken {
  flex: none; width: 22px; height: 22px; margin-top: 1px; padding: 0; cursor: pointer;
  border: 1.5px solid var(--accent); border-radius: 6px; background: var(--surface);
  display: inline-grid; place-items: center; transition: background-color .15s;
}
.sai-haken::after { content: ""; width: 10px; height: 5px; border: solid transparent; border-width: 0 0 2px 2px; transform: translateY(-1px) rotate(-45deg); }
.sai-haken:hover:not(:disabled) { background: var(--accent-soft); }
.sai-haken[aria-pressed="true"] { background: var(--accent); }
.sai-haken[aria-pressed="true"]::after { border-color: var(--on-accent); }
.sai-haken:disabled { cursor: default; }
.sai-haken:disabled:not([aria-pressed="true"]) { border-color: var(--border); }
.sai-schritt:has(.sai-haken[aria-pressed="true"]) > span { color: var(--muted); }
/* Antworten zur Auswahl unter einer Antwort ([[…]] im Text): eine Liste
   untereinander wie die Vorschläge der Startseite, nicht Pillen in einer
   Zeile — die lasen sich als ein zusammengeklebter Satz. */
.sai-auswahl { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; }
.sai-auswahl:last-child { margin-bottom: 2px; }
.sai-wahl {
  display: flex; align-items: center; gap: 10px; width: 100%;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  border-radius: var(--radius); padding: 10px 14px; font: inherit; font-size: 0.875rem; line-height: 1.35;
  cursor: pointer; text-align: left; transition: border-color .15s, background-color .15s;
}
.sai-wahl::before {
  content: ""; flex: none; width: 7px; height: 7px; margin-right: 2px;
  border: solid var(--accent); border-width: 2px 2px 0 0; transform: rotate(45deg);
}
.sai-wahl:hover:not(:disabled) { border-color: var(--accent); background: var(--brand-50); }
.sai-wahl.ist-gewaehlt { border-color: var(--accent); background: var(--brand-50); font-weight: 600; }
.sai-wahl:disabled { cursor: default; }
.sai-wahl:disabled:not(.ist-gewaehlt) { color: var(--muted); }
.sai-wahl:disabled:not(.ist-gewaehlt)::before { border-color: var(--border); }
.sai-vorschlag-icon {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 9px;
  background: var(--ton-blau-bg); color: var(--accent);
}
.sai-vorschlag-icon svg { width: 17px; height: 17px; }

.sai-frage {
  align-self: flex-end; max-width: 80%;
  background: var(--accent); color: var(--surface);
  border-radius: var(--radius) var(--radius) var(--radius-sm) var(--radius);
  padding: 10px 14px;
}
.sai-frage p { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.sai-antwort { display: flex; gap: 10px; align-items: flex-start; max-width: 92%; }
.sai-antwort > .sai-zeichen { margin-top: 2px; }
.sai-text {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius) var(--radius) var(--radius) var(--radius-sm);
  box-shadow: var(--shadow); padding: 12px 16px; min-width: 0; overflow-wrap: anywhere; line-height: 1.55;
}
.sai-text p { margin: 0 0 10px; }
.sai-text > :last-child { margin-bottom: 0; }
.sai-text strong { color: var(--heading); }
/* Der Weg weiter nach der Gerätehilfe: «Schaden an … melden» (seit 05.10.2026). */
.sai-text .sai-aktionen { margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--rule);
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.sai-antwort.ist-fehler .sai-text { background: var(--danger-bg); border-color: transparent; box-shadow: none; }

/* Antworten von Swyron AI: aufbereitet in SwyronAi::alsHtml (seit 05.10.2026). */
.sai-text ul { list-style: none; margin: 0 0 10px; padding: 0; }
.sai-text ul > li { position: relative; padding-left: 16px; margin: 0 0 5px; }
.sai-text ul > li::before {
  content: ""; position: absolute; left: 2px; top: .62em; width: 6px; height: 6px;
  border-radius: 50%; background: var(--accent);
}
.sai-text ol { list-style: decimal; margin: 0 0 10px; padding-left: 22px; }
.sai-text ol > li { margin: 0 0 5px; padding-left: 2px; }
.sai-text ol > li::marker { color: var(--accent); font-weight: 700; }
.sai-zwischentitel { margin: 14px 0 6px; font-size: 0.875rem; font-weight: 700; color: var(--heading); }
.sai-text > .sai-zwischentitel:first-child { margin-top: 0; }
/* Geräte-Chip: die Inventarnummer, anklickbar. */
.sai-nr {
  display: inline-block; padding: 0 7px; border-radius: 6px;
  background: var(--ton-blau-bg); color: var(--accent-text);
  font-size: .9em; font-weight: 650; line-height: 1.6; letter-spacing: .01em;
  font-variant-numeric: tabular-nums; white-space: nowrap; text-decoration: none; vertical-align: baseline;
}
a.sai-nr:hover { background: var(--accent-soft); text-decoration: none; }
.sai-betrag { font-weight: 650; color: var(--heading); font-variant-numeric: tabular-nums; white-space: nowrap; }
.sai-person { font-weight: 600; color: var(--heading); }
.sai-frage .sai-betrag, .sai-frage .sai-person { color: inherit; }
/* Tabellen: kompakt, Zahlen rechts, am Telefon seitlich scrollbar. */
.sai-tabelle-huelle {
  margin: 4px 0 10px; overflow-x: auto; border: 1px solid var(--rule); border-radius: 10px;
  -webkit-overflow-scrolling: touch;
}
.sai-tabelle { width: 100%; min-width: 0; border-collapse: collapse; font-size: 0.875rem; }
.sai-tabelle th {
  text-align: left; padding: 7px 12px; background: var(--surface-muted); color: var(--muted);
  font-size: 0.75rem; font-weight: 650; white-space: nowrap;
}
.sai-tabelle td { padding: 7px 12px; border-top: 1px solid var(--rule); vertical-align: top; }
.sai-tabelle tbody tr:hover td { background: color-mix(in srgb, var(--accent) 4%, transparent); }
.sai-tabelle .zahl { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.sai-denkt-text { color: var(--muted); }

/* Der Name «Swyron AI», überall gleich (View.php `swyronAiName`): halbfett,
   nie kursiv, «AI» im Markenblau. Wo der Grund schon Farbe hat — Knöpfe,
   blaue Sprechblasen, dunkle Flächen —, nimmt «AI» die Schriftfarbe an. */
.sai-name { font-weight: 650; font-style: normal; white-space: nowrap; letter-spacing: -.005em; }
.sai-name-ai { color: var(--accent); }
:is(h1, h2, h3, h4, strong, b, th) .sai-name { font-weight: inherit; }
:is(.sai-buehne, .start-karte, .hero-dark) .sai-name-ai { color: var(--on-ink-accent); }
:is(.btn, button, .sai-frage, .badge, .alert, a) .sai-name-ai { color: inherit; }
.sai-buehne .sai-demo .sai-name-ai { color: var(--accent); }
/* Kleine Überschriften (Eyebrow) stehen in Versalien — der Name nicht. */
.sec-eyebrow .sai-name { text-transform: none; letter-spacing: 0; font-size: 1.08em; }
/* In Knöpfen (Flex mit Abstand) wäre der Name ein eigenes Stück mit
   grossem Zwischenraum; dort genügt der Abstand eines Wortes. */
:is(.btn, button):has(> .sai-name) { gap: .28em; }
.sai-eingabe { flex: none; padding: 12px 20px 14px; border-top: 1px solid var(--rule); background: var(--surface); }
.sai-feld {
  display: flex; align-items: flex-end; gap: 8px;
  border: 1px solid var(--field-border); border-radius: 14px; background: var(--surface);
  padding: 6px 6px 6px 14px; transition: border-color .15s, box-shadow .15s;
}
.sai-feld:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); }
.sai-feld textarea {
  flex: 1 1 auto; min-width: 0; border: 0; background: transparent; resize: none;
  font: inherit; font-size: 1rem; line-height: 1.45; padding: 7px 0; max-height: 180px; color: var(--text);
}
.sai-feld textarea:focus { outline: 2px solid transparent; }
.sai-senden {
  flex: none; display: grid; place-items: center; width: 38px; height: 38px; border-radius: 10px;
  border: 0; background: var(--accent); color: var(--surface); cursor: pointer;
}
.sai-senden svg { width: 18px; height: 18px; stroke-width: 2.2; }
.sai-senden:hover:not(:disabled) { filter: brightness(1.08); }
.sai-senden:disabled { opacity: .45; cursor: default; }
.sai-fuss { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin-top: 8px; }
.sai-stand { display: inline-flex; align-items: center; gap: 8px; }
.sai-meter { display: inline-block; width: 64px; height: 5px; border-radius: 3px; background: var(--surface-muted); overflow: hidden; }
.sai-meter > span { display: block; height: 100%; background: var(--accent); border-radius: 3px; }

/* Auf der Übersicht: eine Leiste, die nach Eingabe aussieht (seit
   05.10.2026). Rand im Verlauf Blau → Violett, der langsam wandert; der
   Platzhalter tippt Beispielfragen (app.js). Beim Fokus hebt sie sich. */
.sai-start {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 20px; padding: 8px 8px 8px 12px; border-radius: 18px;
  border: 2px solid transparent; cursor: text;
  background:
    linear-gradient(var(--surface), var(--surface)) padding-box,
    linear-gradient(110deg, var(--accent), var(--ton-violett-fg), var(--ton-tuerkis-fg), var(--accent)) border-box;
  background-size: 100% 100%, 300% 100%;
  box-shadow: 0 10px 30px -18px color-mix(in srgb, var(--accent) 70%, transparent);
  animation: sai-rand 9s linear infinite;
  transition: box-shadow .2s ease, transform .2s ease;
}
.sai-start:hover { box-shadow: 0 14px 34px -16px color-mix(in srgb, var(--accent) 75%, transparent); }
.sai-start:focus-within {
  transform: translateY(-1px);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 16%, transparent),
              0 16px 36px -16px color-mix(in srgb, var(--accent) 80%, transparent);
}
@keyframes sai-rand { to { background-position: 0 0, 300% 0; } }
.sai-start-zeichen { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px;
  background: var(--ton-blau-bg); flex: none; cursor: text; }
.sai-start input {
  flex: 1 1 auto; min-width: 0; border: 0; background: transparent; color: var(--text);
  font: inherit; font-size: 1rem; padding: 10px 0;
}
.sai-start input::placeholder { color: var(--muted); opacity: 1; }
.sai-start input:focus { outline: 2px solid transparent; }
.sai-start .sai-senden { width: 42px; height: 42px; border-radius: 13px; }
.sai-start-feld { position: relative; flex: 1 1 auto; min-width: 0; display: flex; }
.sai-start-feld input { width: 100%; }
.sai-start-geist {
  position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%);
  display: block; pointer-events: none; color: var(--muted); font-size: 1rem; line-height: 1.4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sai-start-geist[hidden] { display: none; }
.sai-start-geist .sai-name { color: var(--text); }
.sai-start-geist .sai-demo-cursor { vertical-align: -2px; margin-left: 1px; }
@media (prefers-reduced-motion: reduce) { .sai-start { animation: none; } }

@media (max-width: 720px) {
  .sai-seite { --sai-hoehe: calc(100dvh - 120px); }
  .sai-karte { min-height: 360px; border-radius: var(--radius); }
  .sai-karte-kopf { padding: 10px 14px; }
  .sai-unter { display: none; }
  .sai-ki-zeile { order: -1; flex-basis: 100%; }
  .sai-verlauf { padding: 14px; }
  .sai-frage { max-width: 92%; }
  .sai-antwort { max-width: 100%; }
  .sai-eingabe { padding: 10px 12px 12px; }
  .sai-vorschlaege { grid-template-columns: minmax(0, 1fr); }
  .sai-leer h2 { font-size: 1.1875rem; }
}

/* Swyron AI auf der Webseite: das gezeichnete Beispielgespräch. */
.sai-vorschau { background: var(--surface); padding: 6px 0 10px; text-align: left; }
.sai-vorschau-kopf { padding: 14px 20px 0; color: var(--heading); }
.sai-vorschau .sai-verlauf { min-height: 0; }
.sai-link { color: var(--accent-text); text-decoration: underline; text-underline-offset: 2px; } /* alt, siehe .sai-nr */

/* ===========================================================================
   Swyron AI auf der Startseite: dunkle Bühne mit Live-Vorführung
   (seit 04.10.2026). Links Text, rechts das Gespräch auf weisser Karte.
   =========================================================================== */
.sai-buehne {
  background:
    radial-gradient(60% 80% at 85% 20%, color-mix(in srgb, var(--accent) 35%, transparent), transparent 70%),
    linear-gradient(180deg, var(--ink), var(--ink-2));
  color: var(--on-ink);
}
.sai-buehne h2 { color: var(--on-ink); }
.sai-buehne .lead { color: var(--on-ink-muted); }
.sai-buehne .sec-eyebrow { background: rgba(255, 255, 255, .14); color: var(--on-ink); }
.sai-buehne-raster {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 48px; align-items: center;
}
.sai-buehne-punkte { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 10px; }
.sai-buehne-punkte li { position: relative; padding-left: 26px; color: var(--on-ink); }
.sai-buehne-punkte li::before {
  content: ""; position: absolute; left: 0; top: .5em; width: 12px; height: 12px;
  border-radius: 50%; border: 2px solid var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent);
}
.sai-buehne-knoepfe { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.btn-ghost-hell { background: transparent; color: var(--on-ink); border: 1px solid var(--ink-border); }
.btn-ghost-hell:hover { background: var(--ink-card); color: var(--on-ink); }
/* Karte zu Swyron AI rechts im Aufmacher einer Modulseite (seit 06.10.2026). */
.hero-mit-karte { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 380px); gap: 48px; align-items: center; }
.sai-teaser {
  position: relative; display: block; border-radius: 22px; padding: 1.5px; overflow: hidden; isolation: isolate;
  text-decoration: none; color: var(--on-ink);
  box-shadow: 0 24px 60px -24px var(--accent), 0 0 0 1px var(--ink-border);
  transition: transform .25s ease, box-shadow .25s ease;
}
.sai-teaser:hover { transform: translateY(-4px); box-shadow: 0 32px 70px -22px var(--accent), 0 0 0 1px var(--on-ink-accent); }
/* Der leuchtende Rand: ein Farbverlauf, der hinter der Karte umläuft. */
.sai-teaser-rand {
  position: absolute; inset: -60%; z-index: -1;
  background: conic-gradient(from 0deg, transparent 0deg, var(--accent) 70deg, var(--on-ink-accent) 110deg, transparent 170deg,
                             transparent 190deg, var(--accent) 250deg, var(--on-ink-accent) 290deg, transparent 350deg);
  animation: sai-teaser-lauf 7s linear infinite;
}
@keyframes sai-teaser-lauf { to { transform: rotate(360deg); } }
.sai-teaser-inhalt {
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  border-radius: 21px; padding: 28px 28px 26px;
  background: radial-gradient(120% 80% at 100% 0%, var(--ink-card) 0%, var(--ink) 70%);
}
.sai-teaser-zeichen { color: var(--on-ink-accent); filter: drop-shadow(0 0 18px var(--accent)); margin-bottom: 4px; }
.sai-teaser-zeichen .sai-zeichen { color: var(--on-ink-accent); }
.sai-teaser-eyebrow { font-size: 0.75rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--on-ink-muted); }
.sai-teaser-titel { font-size: 2.125rem; line-height: 1.05; font-weight: 600; letter-spacing: -.02em; color: var(--on-ink); }
.sai-teaser-titel span { color: var(--on-ink-accent); }
.sai-teaser-text { font-size: 0.9375rem; line-height: 1.55; color: var(--on-ink-muted); }
.sai-teaser-punkte { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 8px; font-size: 0.875rem; color: var(--on-ink); }
.sai-teaser-punkte > span { display: flex; align-items: center; gap: 8px; }
.sai-teaser-punkte svg { width: 16px; height: 16px; color: var(--on-ink-accent); flex: none; }
/* Die Karte ist ein Link: ohne Unterstreichung, auch beim Darüberfahren
   (17.10.2026: sonst war jede Zeile unterstrichen). */
.sai-teaser, .sai-teaser:hover, .sai-teaser:focus-visible { text-decoration: none; }
.sai-teaser-knopf { pointer-events: none; }
/* Nur der Pfeil rückt nach. «Swyron AI» im Knopf ist selbst ein span
   (View::saiName) und rutschte sonst doppelt in «entdecken» hinein. */
.sai-teaser-knopf > span[aria-hidden] { display: inline-block; transition: transform .2s; }
.sai-teaser:hover .sai-teaser-knopf > span[aria-hidden] { transform: translateX(4px); }
/* Tablet hochkant: unter dem Text, aber breit und quer — Zeichen links,
   Inhalt rechts, die Zusagen nebeneinander. Schmal und links stand sie
   neben einer Leere (Rückmeldung vom 06.10.2026). */
@media (max-width: 960px) {
  .hero-mit-karte { grid-template-columns: 1fr; gap: 32px; }
  .sai-teaser-inhalt {
    display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 32px; row-gap: 8px;
    align-items: start; padding: 30px 32px;
  }
  .sai-teaser-zeichen { grid-row: 1 / span 5; align-self: center; margin: 0; }
  .sai-teaser-zeichen svg { width: 112px; height: 112px; }
  .sai-teaser-inhalt > :not(.sai-teaser-zeichen) { grid-column: 2; }
  .sai-teaser-punkte { flex-direction: row; flex-wrap: wrap; gap: 6px 20px; margin: 6px 0 10px; }
  .sai-teaser-knopf { justify-self: start; }
}
/* Telefon: wieder untereinander, über die ganze Breite. */
@media (max-width: 600px) {
  .sai-teaser-inhalt { display: flex; flex-direction: column; padding: 26px 22px 24px; }
  .sai-teaser-zeichen { align-self: flex-start; }
  .sai-teaser-zeichen svg { width: 72px; height: 72px; }
  .sai-teaser-punkte { flex-direction: column; }
}
@media (prefers-reduced-motion: reduce) {
  .sai-teaser-rand { animation: none; }
  .sai-teaser, .sai-teaser:hover { transform: none; }
}

.sai-demo {
  background: var(--surface); color: var(--text);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
  overflow: hidden; display: flex; flex-direction: column;
}
.sai-demo .sai-verlauf { height: 330px; overflow: hidden; justify-content: flex-end; }
.sai-demo .sai-frage, .sai-demo .sai-antwort { animation: sai-auftauchen .35s ease-out both; }
.sai-demo .sai-text li, .sai-demo .sai-text tbody tr { animation: sai-auftauchen .3s ease-out both; }
@keyframes sai-auftauchen { from { opacity: 0; transform: translateY(6px); } }
.sai-demo-feld {
  display: flex; align-items: center; gap: 2px; min-height: 48px;
  margin: 0 16px 16px; padding: 10px 14px;
  border: 1px solid var(--field-border); border-radius: var(--radius-sm);
  color: var(--text); font-size: 0.9375rem;
}
.sai-demo-cursor { display: inline-block; width: 2px; height: 1.1em; background: var(--accent); animation: sai-blinken 1s steps(1) infinite; }
@keyframes sai-blinken { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .sai-demo .sai-frage, .sai-demo .sai-antwort, .sai-demo .sai-text li, .sai-demo .sai-text tbody tr { animation: none; }
  .sai-demo-cursor { animation: none; }
}
@media (max-width: 1024px) {
  .sai-buehne-raster { grid-template-columns: minmax(0, 1fr); gap: 32px; }
}
@media (max-width: 720px) {
  .sai-demo .sai-verlauf { height: 360px; }
}

/* --- Der virtuelle Ausweis (seit 07.10.2026) ------------------------------

  Im Format der Plastikkarte, seit 08.10.2026 hell: weisser Kopf mit
  Wortmarke und blauem Punktfeld, das blaue Band, darunter Weiss mit einem
  Hauch Blau. Der dunkle Kopf biss sich mit der hellen Übersicht. Zwei Seiten liegen
  nebeneinander in einem Wischbereich — `scroll-snap` macht das Blättern,
  das Skript hält nur die Punkte nach. Die Codes stehen immer auf Weiss
  und mit Ruhezone: sonst liest der Scanner am Schalter schlecht.
*/
.ausweis-dialog { width: min(540px, calc(100vw - 24px)); border: 0; }
/* Das Fenster bekommt beim Öffnen den Fokus — sein Ring lag als blauer
   Rahmen um den Ausweis. Durchsichtig statt entfernt: im
   Zwangskontrastmodus zeichnet der Browser ihn trotzdem. Die Bedienelemente
   darin behalten ihren Ring. */
.ausweis-dialog:focus, .ausweis-dialog:focus-visible { outline-color: transparent; }
/* Kein Titel, kein Kreuz: das Fenster ist ein gleichmässiger weisser Rand
   um den Ausweis. Geschlossen wird mit einem Tipp daneben oder Escape. */
.ausweis-dialog-inhalt { padding: 14px; }
.ausweis-laden { padding: 40px 0; text-align: center; color: var(--muted); font-size: 0.875rem; }

.ausweis-seite-rahmen { max-width: 540px; }

/* Alle Masse im Ausweis in cqw: er skaliert als Ganzes, wie eine Karte. */
.ausweis { container-type: inline-size; }

/* Das Format einer Bankkarte: ISO/IEC 7810 ID-1, 85,6 × 53,98 mm.
   Ecken wie ISO 7810 (3,18 mm auf 85,6 mm). Gemessen an `.ausweis` —
   ein Element misst `cqw` nie an sich selbst; ohne Behälter darüber gälte
   die Fensterbreite, und am Laptop wurden die Ecken riesig. */
.ausweis-karte {
  /* Höhe des Körpers: Kartenhöhe ID-1 minus Kopf samt blauem Band. */
  --ausweis-koerper: calc(100cqw * 53.98 / 85.6 - 15.1cqw);
  --ausweis-radius: 3.7cqw;
  position: relative;
  display: flex; flex-direction: column;
  border-radius: var(--ausweis-radius); overflow: hidden;
  /* WebKit (iPhone, Teams, Safari) beschneidet einen Wischbereich auf
     eigener Ebene nicht an den runden Ecken des Elternteils — je nachdem,
     ob er gerade eine Ebene bekommt, kamen die Ecken unter dem Kopf mal,
     mal nicht. Eine Maske zwingt den Zuschnitt. */
  -webkit-mask-image: -webkit-radial-gradient(white, black);
  isolation: isolate;
  /* Kante als Rahmen, nicht als Schatten: die Maske oben schneidet alles
     ausserhalb der Karte weg, ein Schatten käme nie an. */
  border: 1px solid var(--border);
  background: var(--surface);
}

.ausweis-kopf {
  flex: 0 0 auto; width: 100%;
  border-top: 0; border-left: 0; border-right: 0; font: inherit; text-align: left;
  display: flex; align-items: center; justify-content: space-between; gap: 3cqw;
  height: 14cqw; padding: 0 4cqw 0 5cqw;
  background: var(--surface); color: var(--heading);
  border-bottom: 1.1cqw solid var(--accent);
}
.ausweis-marke { display: grid; gap: .8cqw; }
.ausweis-marke img { display: block; width: 25cqw; height: auto; }
.ausweis-marke img.is-light { display: var(--nur-hell); }
.ausweis-marke img.is-dark { display: var(--nur-dunkel); }
.ausweis-titelzeile { display: flex; align-items: center; gap: 2.4cqw; }
/* Neben der Wortmarke wie eine Produktbezeichnung: hinter einem feinen
   Strich, klein und gedämpft — sie darf mit der Marke nicht wetteifern. */
.ausweis-titel {
  padding-left: 2.4cqw; border-left: 1px solid var(--border);
  font-size: 3.1cqw; font-weight: 500; line-height: 1.5; letter-spacing: .04em;
  color: var(--muted); white-space: nowrap;
}
.ausweis-hinweis { font-size: 2.5cqw; letter-spacing: .02em; white-space: nowrap; color: var(--muted); }

/* Das Punktfeld: ruhiges Raster, einzelne Kreuze leuchten nacheinander auf. */
.ausweis-punktfeld { height: 9.5cqw; width: auto; fill: var(--brand-300); }
.ausweis-punktfeld .funkel { stroke: var(--accent); stroke-width: 1.4; stroke-linecap: round;
  opacity: 0; animation: ausweis-funkel 6.6s ease-in-out infinite; transform-box: fill-box; }
@keyframes ausweis-funkel {
  0%, 100% { opacity: 0; }
  4%       { opacity: 1; }
  12%      { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .ausweis-punktfeld .funkel { animation: none; } }

/* Der Körper unter dem Kopf: so hoch, dass die ganze Karte das Format
   ID-1 hat (Kartenhöhe minus Kopf samt blauem Band). Feste Höhe statt
   Seitenverhältnis — so lässt er sich am Telefon auf- und zuklappen. */
.ausweis-koerper {
  position: relative;
  height: var(--ausweis-koerper);
  overflow: hidden;
  /* Eigene runde Ecken unten, zusätzlich zu denen der Karte: während der
     Animation zeichnet WebKit neu und schnitt am Elternteil allein die
     unteren Ecken nicht jedes Mal sauber. So ist jede Ebene selbst rund. */
  border-radius: 0 0 var(--ausweis-radius) var(--ausweis-radius);
  -webkit-mask-image: -webkit-radial-gradient(white, black);
  background: linear-gradient(160deg, var(--surface) 45%, var(--brand-50));
  /* Öffnen gemächlich, schliessen zügig — der Übergang gilt immer für den
     Zustand, in den es geht. */
  transition: height .62s cubic-bezier(.22, .9, .25, 1);
}
/* Der Inhalt hat IMMER die volle Höhe — beim Auf- und Zuklappen wird er
   nur aufgedeckt, nicht neu gesetzt. Mit `height: 100%` wuchs er mit, der
   QR-Code rutschte während der Animation über den Namen und die Punkte
   wanderten mit. Dazu blendet er weich ein und aus. */
.ausweis-seiten, .ausweis-punkte { transition: opacity .45s ease .08s; }
.ausweis-karte.is-zu .ausweis-seiten, .ausweis-karte.is-zu .ausweis-punkte { opacity: 0; transition: opacity .25s ease; }
.ausweis-seiten {
  height: var(--ausweis-koerper);
  border-radius: 0 0 var(--ausweis-radius) var(--ausweis-radius);
  display: flex; overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scrollbar-width: none;
  cursor: pointer;
}
.ausweis-seiten::-webkit-scrollbar { display: none; }
.ausweis-seite {
  flex: 0 0 100%; scroll-snap-align: start; scroll-snap-stop: always;
  display: flex; gap: 4cqw;
  padding: 4.5cqw 5cqw 7cqw;
}

.ausweis-label { margin-top: 2.6cqw; font-weight: 600; font-size: 2.1cqw; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.ausweis-nr { font-size: 5.4cqw; font-weight: 600; line-height: 1.1; color: var(--heading); letter-spacing: .01em; }
/* QR- und Strichcode als dasselbe Scanfeld (seit 11.10.2026, Wunsch des
   Betreibers): immer weiss, mit Rahmen und runden Ecken, auch im dunklen
   Bild — der Scanner braucht helles Grund, und man sieht sofort, wohin
   man das Telefon hält. */
.ausweis-qr {
  background: var(--code-grund);
  border: 1px solid var(--code-rand); border-radius: 1.4cqw;
  box-shadow: 0 .4cqw 1.6cqw rgb(16 20 35 / .10);
}
.ausweis-qr svg { display: block; width: 100%; height: auto; }

/* Vorderseite: Foto links, rechts Name, Funktion, Organisation, unten die
   Nummer. Ohne QR-Code — der nahm der Schrift ein Drittel der Breite, und
   Funktion wie Organisation brachen mit «…» ab. Jetzt darf jede Angabe
   auf zwei Zeilen umbrechen. Raster mit festen Spalten: als Flex-Reihe
   kürzte WebKit (iPhone, Teams) die Textspalte nicht. */
.ausweis-seite.ausweis-vorne {
  display: grid; grid-template-columns: 28cqw minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr) auto;
  align-items: start; column-gap: 4.5cqw;
}
.ausweis-foto {
  /* Über die ganze Höhe, bündig mit der Unterkante der Nummer (seit 11.10.2026);
     28cqw breit ergibt etwa das Verhältnis eines Passfotos. */
  grid-row: 1 / span 2; align-self: stretch;
  width: 28cqw; height: auto; min-height: 30cqw;
  border-radius: 1.6cqw; overflow: hidden;
  background: linear-gradient(180deg, var(--brand-50), var(--accent-soft));
  display: grid; place-items: center;
}
.ausweis-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ausweis-initialen { font-size: 9.5cqw; font-weight: 700; color: var(--accent-soft-text); }
.ausweis-wer { min-width: 0; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }
.ausweis-name {
  font-size: 4.7cqw; font-weight: 700; line-height: 1.15; color: var(--heading);
  margin-bottom: 1.2cqw;
  /* Höchstens zwei Zeilen, ohne -webkit-box: das misst WebKit in der Breite falsch. */
  max-height: 2.3em; overflow: hidden; overflow-wrap: anywhere;
}
/* Vor- und Nachname je als Block: umgebrochen wird zwischen ihnen, im Namen
   nur, wenn ein Teil allein nicht in die Zeile passt. */
.ausweis-namensteil { display: inline-block; max-width: 100%; }
.ausweis-zeile {
  font-size: 3cqw; line-height: 1.35; color: var(--muted);
  max-height: 2.7em; overflow: hidden; overflow-wrap: anywhere;
}
.ausweis-zeile + .ausweis-zeile { margin-top: .8cqw; }
.ausweis-org { color: var(--text); }
/* Seit «Mitarbeiter Nr.» über der Nummer steht, fehlt vorne eine Zeile: die
   Organisation bleibt einzeilig, sonst lief sie bei langen Namen in die Nummer. */
.ausweis-zeile.ausweis-org { white-space: nowrap; text-overflow: ellipsis; max-height: 1.35em; }
/* Vorne «Mitarbeiter Nr.» über der Nummer (seit 11.10.2026, Wunsch des Betreibers). */
.ausweis-nr-feld { display: flex; flex-direction: column; align-items: flex-start; gap: .5cqw; min-width: 0; }
.ausweis-nr-feld .ausweis-label { margin-top: 0; }

/* Rückseite: Nummer und Strichcode links, grosser QR rechts. */
.ausweis-hinten { align-items: center; }
/* Die linke Spalte ist so hoch wie das QR-Feld (29cqw, seit 11.10.2026):
   oben bündig mit ihm, und der Strichcode füllt den Rest, sodass er auf
   derselben Höhe endet wie der QR-Code. Der QR-Code bleibt, wo er war. */
.ausweis-scan { flex: 1; min-width: 0; display: flex; flex-direction: column; height: 29cqw; }
.ausweis-scan .ausweis-label { margin-top: 0; }
/* Kleiner seit 11.10.2026 (Wunsch des Betreibers), passend zur Kiosk-Nr. darunter. */
.ausweis-scan .ausweis-nr { font-size: 4.6cqw; }
/* Die Kiosk-Nr. hat 18 Zeichen — kleiner, damit sie neben dem QR auf eine Zeile passt. */
.ausweis-scan .ausweis-label-kiosk { margin-top: 1.4cqw; }
.ausweis-scan .ausweis-nr.is-kiosk { font-size: 3.5cqw; letter-spacing: .02em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ausweis-strich {
  margin-top: 1.6cqw; flex: 1 1 auto; min-height: 0; display: flex;
  padding: 1.6cqw 2cqw; border: 1px solid var(--code-rand); border-radius: 1.4cqw; background: var(--code-grund);
  box-shadow: 0 .4cqw 1.6cqw rgb(16 20 35 / .10);
}
.ausweis-strich svg { display: block; width: 100%; height: 100%; min-height: 6cqw; }
.ausweis-qr.is-gross { flex: 0 0 auto; width: 29cqw; padding: 1.2cqw; }

.ausweis-punkte {
  position: absolute; left: 0; right: 0;
  top: calc(var(--ausweis-koerper) - max(24px, 6cqw) - .6cqw);
  display: flex; justify-content: center; gap: 0;
}
.ausweis-punkt {
  width: max(24px, 6cqw); height: max(24px, 6cqw); padding: 0; border: 0; background: none; cursor: pointer;
  display: grid; place-items: center;
}
.ausweis-punkt::before {
  content: ""; width: max(7px, 1.9cqw); height: max(7px, 1.9cqw); border-radius: 50%; background: var(--field-border);
  transition: background .15s, transform .15s;
}
.ausweis-punkt[aria-current="true"]::before { background: var(--accent); transform: scale(1.15); }
@media (prefers-reduced-motion: reduce) { .ausweis-punkt::before { transition: none; } }

.ausweis-wallet { display: grid; gap: 8px; margin-top: 14px; }
.wallet-knopf {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 46px; padding: 0 16px; border-radius: 10px;
  /* Schwarz in beiden Erscheinungsbildern, wie Apple und Google ihre
     Knöpfe zeigen — mit --heading wäre er im dunklen Bild weiss auf weiss. */
  background: var(--ink); color: var(--on-ink); border: 1px solid var(--ink-border);
  font-size: 0.9375rem; font-weight: 600;
}
.wallet-knopf:hover { background: var(--ink-2); color: var(--on-ink); text-decoration: none; }
.wallet-knopf svg { width: 20px; height: 20px; }


/* Der Ausweis-Knopf in der Knopfreihe der Übersicht: quadratisch, so hoch
   wie die Knöpfe daneben, nur das Zeichen. */
.btn.btn-ausweis { padding-left: 0; padding-right: 0; aspect-ratio: 1; justify-content: center; }
.btn.btn-ausweis svg { width: 22px; height: 22px; }
/* Am Telefon wachsen die Knöpfe der Kopfreihe in die Breite — der
   Ausweis-Knopf nicht: er bleibt ein Quadrat, die anderen teilen sich den Rest. */
.page-head > .row .btn.btn-ausweis { flex: 0 0 auto; width: 44px; }

/* --- Der Ausweis zum Aufklappen, nur am Telefon (seit 07.10.2026) ------

  Wie in der SBB-App: auf der Übersicht steht zunächst nur der Kopf; ein
  Tipp darauf klappt Vorder- und Rückseite auf. Ab 721 px bleibt es beim
  Knopf neben «Ticket eröffnen» und dem Fenster.
*/
.ausweis-klapp { display: none; }
.ausweis-karte.is-zu .ausweis-koerper { height: 0; transition: height .38s cubic-bezier(.2, .8, .2, 1); }
/* Zugeklappt kein blaues Band: an den runden Ecken bog es sich krumm.
   Es kommt mit dem Aufklappen, als Naht zum weissen Teil. */
.ausweis-karte.is-zu .ausweis-kopf { border-bottom-color: transparent; }
/* Zugeklappt ist der Kopf die ganze Karte — er rundet sich unten selbst. */
/* Die Ecken springen, statt zu gleiten: beim Öffnen sofort eckig, beim
   Schliessen erst rund, wenn der Körper ganz zu ist. Gleitend lief beim
   Öffnen eine Kante an den Seiten nach unten mit. */
button.ausweis-kopf { border-radius: var(--ausweis-radius) var(--ausweis-radius) 0 0; transition: border-color .2s, border-radius 0s; }
.ausweis-karte.is-zu button.ausweis-kopf { border-radius: var(--ausweis-radius); transition: border-color .2s, border-radius 0s .38s; }
button.ausweis-kopf { cursor: pointer; }
/* Kein grauer Blitz von iOS beim Antippen — der Kopf antwortet mit dem Aufklappen. */
button.ausweis-kopf, .ausweis-seiten, .ausweis-punkt { -webkit-tap-highlight-color: transparent; }
@media (prefers-reduced-motion: reduce) {
  .ausweis-koerper, .ausweis-seiten, .ausweis-punkte,
  .ausweis-karte.is-zu .ausweis-koerper, .ausweis-karte.is-zu .ausweis-seiten,
  .ausweis-karte.is-zu .ausweis-punkte { transition: none; }
}
@media (max-width: 720px) {
  .ausweis-klapp { display: block; margin-bottom: 20px; }
  .page-head > .row .btn.btn-ausweis { display: none; }
}
/* Zugeklappt keine Wallet-Knöpfe — sie gehören zur offenen Karte. */
.ausweis:has(> .ausweis-karte.is-zu) > .ausweis-wallet { display: none; }
@media (max-width: 720px) {
  .im-teams .reiter-marke img { display: none; }
}
/* Der Hinweis im Kopf: zugeklappt «Zum Öffnen tippen», offen «Zum Schliessen tippen». */
.ausweis-karte.is-zu .ausweis-marke .nur-offen,
.ausweis-karte:not(.is-zu) .ausweis-marke .nur-zu { display: none; }

/* --- Schlichter Rahmen und Abholseite des Wallet-Ausweises (seit 08.10.2026) --

  `layout/schlicht`: ohne Menü und Konto, für Seiten in einem fremden
  Browser. Die Abholseite (`pages/karte/wallet-abholen`) öffnet Apple Wallet
  von selbst und bestätigt danach — statt einer leeren weissen Seite.
*/
body.schlicht { background: var(--auth-flaeche); }
.schlicht-mitte {
  min-height: 100vh; min-height: 100dvh;
  display: grid; place-items: center;
  padding: 32px 16px calc(32px + env(safe-area-inset-bottom));
}
.wallet-abholen {
  width: 100%; max-width: 400px; text-align: center;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); padding: 28px 24px 26px;
}
.wallet-abholen-marke { height: 26px; width: auto; margin: 0 auto 26px; }
.wallet-abholen-marke.is-light { display: var(--nur-hell); }
.wallet-abholen-marke.is-dark { display: var(--nur-dunkel); }
.wallet-abholen-zeichen {
  width: 56px; height: 56px; border-radius: 16px; margin: 0 auto 16px;
  display: grid; place-items: center;
  background: var(--brand-100); color: var(--brand-900);
}
.wallet-abholen-zeichen svg { width: 28px; height: 28px; }
.wallet-abholen-zeichen.is-fertig { background: var(--success-bg); color: var(--success-fg); }
.wallet-abholen-zeichen.is-aus { background: var(--surface-muted); color: var(--muted); }
.wallet-abholen h1 { font-size: 1.25rem; line-height: 1.3; margin-bottom: 8px; }
.wallet-abholen p { color: var(--muted); font-size: 0.9375rem; line-height: 1.5; }
.wallet-abholen .wallet-knopf { margin-top: 22px; }

/* ---------------------------------------------------------------------------
   Kennzahlenband (seit 16.10.2026, partials/kz-band)
   Vier Felder mit Trennlinien in einem Rahmen; jedes Feld: Titel oben,
   Bild in der Mitte, Verweis unten — auf gleicher Höhe über alle vier.
   --------------------------------------------------------------------------- */
.kz-band {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  background: var(--surface); border: 2px solid var(--kz-rahmen); border-radius: 16px;
  box-shadow: var(--shadow-lg); padding: 26px 0 18px; margin: 0 0 20px;
}
.kz-band.kz-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.kz-band.kz-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.kz-feld {
  container-type: inline-size;
  display: grid; grid-template-rows: auto 1fr auto; justify-items: center;
  gap: 14px; padding: 0 18px; min-width: 0; text-align: center;
}
.kz-feld + .kz-feld { border-left: 1px solid var(--muted); }
.kz-titel { margin: 0; font-size: 1.0625rem; font-weight: 600; line-height: 1.3; color: var(--heading); }
.kz-bild  { display: flex; align-items: center; justify-content: center; min-height: 210px; width: 100%; }
.kz-unter { font-size: 0.875rem; color: var(--text); }
.kz-fuss  { font-size: 0.8125rem; color: var(--muted); }
a.kz-fuss::after { content: " \203A"; }
.kz-fuss:hover { color: var(--accent-text); }

/* 1 · Pillenbalken, unten Blau, oben Grün */
.kz-balken { align-items: flex-end; gap: min(34px, 7cqi); }
.kz-saeule { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.kz-wert   { white-space: nowrap; font-size: min(1.25rem, 6.5cqi); font-weight: 600; color: var(--heading); font-variant-numeric: tabular-nums; }
.kz-pille  {
  width: 24px; border-radius: 999px;
  background: linear-gradient(to top, var(--kz-blau) 0%, var(--kz-blau) 35%, var(--kz-hell) 85%);
  box-shadow: 2px 3px 6px rgba(10, 37, 64, .18);
}
.kz-balken .kz-unter { font-size: clamp(0.75rem, 4.4cqi, 0.875rem); max-width: 10ch; line-height: 1.25; min-height: 2.5em; }

/* 2 · Zwei Kreise, versetzt wie in der Vorlage */
.kz-kreise { position: relative; align-items: stretch; }
.kz-kreis-a, .kz-kreis-b { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.kz-kreis-a { align-self: flex-start; margin-right: -4px; position: relative; z-index: 1; }
.kz-kreis-b { align-self: flex-end; }
.kz-kreis {
  display: grid; place-items: center; border-radius: 50%;
  width: min(var(--d, 80px), 40cqi); height: min(var(--d, 80px), 40cqi);
  font-size: 1.625rem; font-weight: 600; font-variant-numeric: tabular-nums;
  box-shadow: 3px 5px 10px rgba(10, 37, 64, .22);
}
.kz-kreis.is-hell { background: var(--kz-hell); color: var(--kz-auf-hell); border: 1px solid var(--kz-rahmen); }
.kz-kreis.is-blau  { background: var(--kz-blau);  color: var(--kz-auf-blau); font-size: 2.125rem; }

/* 3 · «1 von N» mit Leiste */
.kz-verhaeltnis { flex-direction: column; gap: 18px; }
.kz-gross {
  font-size: 4rem; font-weight: 500; letter-spacing: -.02em; line-height: 1; color: var(--heading);
  font-variant-numeric: tabular-nums;
}
/* Beträge sind länger als «1 von 4»: die Zahl richtet sich nach der Feldbreite. */
.kz-gross { font-size: min(4rem, 17cqi, calc(165cqi / var(--z, 4))); white-space: nowrap; }
.kz-gross.is-warn { color: var(--danger-fg); }
.kz-gross small { font-size: .55em; font-weight: 400; margin: 0 .25em; }
.kz-leiste {
  display: block; width: min(210px, 90%); height: 24px; border-radius: 999px;
  background: var(--kz-spur); overflow: hidden; box-shadow: 2px 3px 6px rgba(10, 37, 64, .18);
}
.kz-leiste > span { display: block; height: 100%; min-width: 24px; border-radius: 999px; background: var(--kz-hell); }

/* 4 · Ring mit Punkt am Ende */
.kz-ring { flex-direction: column; gap: 10px; }
.kz-ring svg { overflow: visible; }
.kz-ring-spur  { fill: none; stroke: var(--kz-spur); stroke-width: 14; }
.kz-ring-bogen { fill: none; stroke: var(--kz-hell); stroke-width: 14; stroke-linecap: round; }
.kz-ring-punkt { fill: var(--kz-blau); stroke: var(--surface); stroke-width: 3; }
.kz-ring-zahl  { fill: var(--heading); font-size: 30px; font-weight: 600; }

@media (max-width: 1100px) {
  .kz-band, .kz-band.kz-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 26px; }
  .kz-feld:nth-child(3) { border-left: 0; }
}
@media (max-width: 560px) {
  .kz-band, .kz-band.kz-2, .kz-band.kz-3 { grid-template-columns: minmax(0, 1fr); }
  .kz-feld + .kz-feld { border-left: 0; border-top: 1px solid var(--rule); padding-top: 22px; }
}
/* Überschrift über einem Kennzahlenband (Auswertungen › Archiv) */
.kz-abschnitt { margin: 26px 0 2px; font-size: 1.125rem; color: var(--heading); }
.kz-abschnitt-text { margin: 0 0 12px; }
.kz-pille.is-leer { height: 24px; background: var(--kz-spur); opacity: .35; box-shadow: none; }
.kz-balken .kz-unter { overflow-wrap: anywhere; }
/* Balkenbeschriftungen nie umbrechen (16.10.2026): «fest vergeben» auf zwei
   Zeilen las sich wie zwei Angaben. Lieber kleiner und enger. */
.kz-balken { gap: min(22px, 4cqi); }
.kz-balken .kz-unter {
  white-space: nowrap; overflow-wrap: normal; max-width: none; min-height: 0;
  font-size: clamp(0.6875rem, 3.6cqi, 0.875rem);
}

/* Querbalken (16.10.2026, Wunsch des Betreibers): Beschriftung links auf
   einer Zeile, Balken in der Mitte, Wert rechts. Ersetzt die stehenden
   Pillen — vier Werte haben untereinander Platz, nebeneinander nicht. */
.kz-balken {
  display: grid; grid-template-columns: max-content minmax(40px, 1fr) max-content;
  align-content: center; align-items: center; gap: 14px 12px; width: 100%;
}
.kz-zeile { display: contents; }
.kz-balken .kz-unter {
  font-size: clamp(0.75rem, 4cqi, 0.875rem); text-align: left; white-space: nowrap; min-height: 0; max-width: none;
}
.kz-balken .kz-wert { font-size: clamp(0.875rem, 5.2cqi, 1.125rem); text-align: right; }
.kz-spur { display: block; height: 22px; }
.kz-balken .kz-pille {
  display: block; height: 22px; border-radius: 999px;
  background: linear-gradient(to right, var(--kz-blau) 0%, var(--kz-blau) 30%, var(--kz-hell) 90%);
}
.kz-balken .kz-pille.is-leer { width: 22px; height: 22px; }
/* Mehrzeilige Sätze gleichmässig verteilen, kein Wort allein in der letzten Zeile. */
.kz-titel, .kz-unter { text-wrap: balance; }
/* Die Spur hinter dem Balken zeigt, wovon er ein Teil ist. */
.kz-spur { border-radius: 999px; background: color-mix(in srgb, var(--kz-spur) 16%, transparent); }
.kz-balken .kz-pille.is-leer { opacity: .25; }

/* ---------------------------------------------------------------------------
   Ladeseite der Anmeldung (seit 16.10.2026, layout/auth.php, app.js).
   Erscheint erst nach 450 ms, blendet in 180 ms ein; bewegt sich nur,
   wenn das Gerät Bewegung zulässt.
   --------------------------------------------------------------------------- */
.ladeseite {
  position: fixed; inset: 0; z-index: 1000;
  display: grid; place-items: center;
  background: var(--auth-flaeche, var(--surface-muted));
  opacity: 0; transition: opacity .18s ease;
}
.ladeseite[hidden] { display: none; }
.ladeseite.is-sichtbar { opacity: 1; }
.ladeseite-inhalt { display: grid; justify-items: center; gap: 18px; padding: 24px; text-align: center; }
.ladeseite-zeichen { width: 64px; height: 64px; border-radius: 15px; box-shadow: var(--shadow-lg); }
.ladeseite-text { margin: 0; font-size: 1.0625rem; font-weight: 500; color: var(--heading); }
.ladeseite-zusatz { margin: 0; min-height: 1.4em; font-size: 0.875rem; color: var(--muted); }
.ladeseite-balken {
  position: relative; display: block; width: 180px; height: 4px; overflow: hidden;
  border-radius: 999px; background: var(--accent-soft);
}
.ladeseite-balken > span {
  position: absolute; inset: 0 auto 0 0; width: 40%; border-radius: 999px; background: var(--accent);
  animation: ladeseite-lauf 1.1s ease-in-out infinite;
}
@keyframes ladeseite-lauf { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
@media (prefers-reduced-motion: no-preference) {
  .ladeseite-zeichen { animation: ladeseite-atmen 1.8s ease-in-out infinite; }
}
@media (prefers-reduced-motion: reduce) {
  .ladeseite-balken > span { width: 100%; animation: ladeseite-ruhig 1.6s ease-in-out infinite; }
}
@keyframes ladeseite-ruhig { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@keyframes ladeseite-atmen { 50% { transform: scale(1.06); } }
@media (prefers-reduced-motion: reduce) {
  .ladeseite-balken > span { animation: none; width: 100%; opacity: .6; }
}

/* ---------------------------------------------------------------------------
   Kennzahlenband am Telefon (16.10.2026): zwei Felder je Zeile, kleinere
   Bilder. Vorher stand jedes Feld einzeln mit voller Bildhöhe untereinander —
   vier Felder füllten mehr als einen Bildschirm, bevor die Liste kam.
   Welches Feld die ganze Breite nimmt, rechnet kz-band.php: `kz-breit` für
   Balken, `kz-quer` für ein Feld, das allein in seiner Zeile stünde (Bild
   links, Text rechts) — eine CSS-Regel kann das nicht zählen, weil breite
   Felder die Reihenfolge verschieben.
   --------------------------------------------------------------------------- */
@media (max-width: 720px) {
  .kz-band, .kz-band.kz-2, .kz-band.kz-3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    padding: 6px 0; row-gap: 0; border-radius: 14px; margin-bottom: 16px;
  }
  .kz-feld, .kz-feld + .kz-feld, .kz-feld:nth-child(3) { border-left: 0; border-top: 0; }
  .kz-feld { gap: 6px; padding: 10px 12px 8px; box-shadow: inset 0 1px 0 var(--rule); }
  .kz-feld.kz-oben { box-shadow: none; }
  .kz-feld.kz-breit, .kz-feld.kz-quer { grid-column: 1 / -1; }

  .kz-titel { font-size: 0.875rem; line-height: 1.25; }
  .kz-titel br { display: none; }
  .kz-bild { min-height: 0; }
  .kz-unter { font-size: 0.7812rem; }
  .kz-fuss { font-size: 0.75rem; }

  .kz-gross { font-size: min(2.125rem, 15cqi, calc(150cqi / var(--z, 4))); }
  .kz-leiste { height: 14px; width: min(160px, 90%); }
  .kz-verhaeltnis { gap: 8px; }
  .kz-ring svg { width: 80px; height: 80px; }
  .kz-ring { gap: 6px; }
  .kz-kreis { width: min(var(--d, 80px) * .55, 72px); height: min(var(--d, 80px) * .55, 72px); font-size: 1.1875rem; }
  .kz-kreis.is-blau { font-size: 1.375rem; }
  .kz-kreise .kz-unter { font-size: 0.75rem; }
  .kz-balken { gap: 8px 10px; }
  .kz-spur, .kz-balken .kz-pille { height: 16px; }
  .kz-balken .kz-pille.is-leer { width: 16px; }
  .kz-abschnitt { margin-top: 18px; font-size: 1rem; }

  /* Allein in der Zeile: quer, Bild links. */
  .kz-feld.kz-quer {
    grid-template-columns: fit-content(46%) minmax(0, 1fr); grid-template-rows: auto auto 1fr;
    column-gap: 16px; row-gap: 4px; justify-items: start; text-align: left; align-items: center;
  }
  .kz-quer > .kz-bild { grid-row: 1 / 4; grid-column: 1; width: auto; min-width: 0; }
  .kz-quer .kz-verhaeltnis .kz-unter { white-space: normal; }
  .kz-quer > .kz-titel { grid-column: 2; align-self: end; }
  .kz-quer > .kz-fuss { grid-column: 2; align-self: start; }
  .kz-quer .kz-ring .kz-unter { display: none; }
}

/*
  Die Zahl wächst mit ihrem Kreis (16.10.2026). Vorher hatte sie eine feste
  Grösse: im kleinen Kreis stiess eine «0» an den Rand, im grossen wirkte
  die «4» verloren. `--g` ist der Durchmesser, die Schrift ein Teil davon;
  zwei- und dreistellige Zahlen werden etwas kleiner (`--stellen`).
*/
.kz-kreis {
  --g: min(var(--d, 80px), 40cqi);
  width: var(--g); height: var(--g);
  font-size: max(1rem, calc(var(--g) * .4 / max(1, (var(--stellen, 1) - 1) * .45 + 1)));
  line-height: 1; padding: 0; text-align: center;
}
.kz-kreis.is-blau { font-size: max(1rem, calc(var(--g) * .42 / max(1, (var(--stellen, 1) - 1) * .45 + 1))); }
@media (max-width: 720px) {
  .kz-kreis { --g: clamp(40px, calc(var(--d, 80px) * .55), 72px); }
  .kz-kreis, .kz-kreis.is-blau { width: var(--g); height: var(--g); }
}

/* ---------------------------------------------------------------------------
   Kennzahlen am Telefon als Karten (16.10.2026, «darfst es verschönern»):
   jedes Feld eine eigene weiche Karte mit Hauch Blau oben, Abstand statt
   Linien, Titel als kleine Kopfzeile, Kreise nebeneinander, Verweis als Pille.
   --------------------------------------------------------------------------- */
@media (max-width: 720px) {
  .kz-band, .kz-band.kz-2, .kz-band.kz-3 {
    background: none; border: 0; box-shadow: none; padding: 0; gap: 10px;
  }
  .kz-feld, .kz-feld.kz-oben {
    background: linear-gradient(180deg, color-mix(in srgb, var(--kz-blau) 7%, var(--surface)) 0, var(--surface) 70px);
    border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border));
    border-radius: 16px; box-shadow: var(--shadow);
    padding: 12px 12px 10px; gap: 8px; justify-items: stretch;
  }
  .kz-titel {
    text-align: left; font-size: 0.8125rem; font-weight: 600; letter-spacing: .005em;
    color: var(--heading); text-wrap: balance;
  }
  .kz-bild { justify-content: center; }
  .kz-fuss {
    justify-self: start; display: inline-flex; align-items: center;
    padding: 3px 10px; border-radius: 999px; font-size: 0.75rem;
    background: var(--accent-soft); color: var(--accent-soft-text);
  }
  span.kz-fuss { display: none; }
  .kz-fuss:hover { text-decoration: none; filter: brightness(.97); }

  /* Kreise nebeneinander, jeder mit seiner Beschriftung. */
  .kz-kreise { gap: 14px; align-items: flex-end; }
  .kz-kreis-a, .kz-kreis-b { align-self: auto; margin: 0; }
  .kz-kreise .kz-unter { text-align: center; max-width: 11ch; line-height: 1.25; }

  /* Zahl und Ring bekommen die Bühne. */
  .kz-verhaeltnis .kz-unter, .kz-ring .kz-unter { text-align: center; color: var(--muted); }
  .kz-gross { font-weight: 600; letter-spacing: -.02em; }

  /* Querkarte: Bild links, Titel oben rechts, Pille darunter. */
  .kz-feld.kz-quer { padding: 12px 14px; }
  .kz-quer > .kz-titel { font-size: 0.875rem; }
  .kz-quer .kz-verhaeltnis { justify-items: start; }

  /* Balkenkarte etwas luftiger. */
  .kz-breit .kz-balken { gap: 10px 10px; padding-top: 2px; }
  .kz-balken .kz-unter { color: var(--text); }
}
@media (max-width: 720px) { a.kz-fuss::after { content: "\203A"; margin-left: 5px; } }

/* Score als Halbkreis (seit 16.10.2026, Ausleiher-Übersicht): Blau nach Grün, Punkt bei der Marke. */
.kz-score { flex-direction: column; gap: 4px; }
.kz-score svg { overflow: visible; }
.kz-score-spur, .kz-score-bogen { fill: none; stroke-width: 14; stroke-linecap: round; }
.kz-score-spur { stroke: color-mix(in srgb, var(--kz-spur) 30%, transparent); }
.kz-score-blau  { stop-color: var(--kz-blau); }
.kz-score-hell { stop-color: var(--kz-hell); }
.kz-score-zahl  { fill: var(--heading); font-size: 34px; font-weight: 600; letter-spacing: -.02em; }
.kz-score-skala { fill: var(--muted); font-size: 11px; }
.kz-score-stufe {
  display: inline-block; padding: 3px 12px; border-radius: 999px; font-size: 0.8125rem; font-weight: 600;
  background: var(--ton-blau-bg); color: var(--ton-blau-fg);
}
.kz-score-stufe.is-mitte { background: var(--info-bg); color: var(--info-fg); }
.kz-score-stufe.is-tief  { background: var(--warning-bg); color: var(--warning-fg); }
@media (max-width: 720px) { .kz-score svg { width: 150px; height: 94px; } .kz-score-zahl { font-size: 2rem; } }

/* ---------------------------------------------------------------------------
   Kennzahlen als Karten auch am Bildschirm und am Tablet (16.10.2026,
   Wunsch des Betreibers): das Kartenbild vom Telefon statt des einen
   Rahmens mit Trennlinien. Vier Spalten, am Tablet zwei; wie breit eine
   Karte ist, rechnet kz-band.php (`--sp`, `--sp-m`), damit keine Lücke
   bleibt.
   --------------------------------------------------------------------------- */
@media (min-width: 721px) {
  .kz-band, .kz-band.kz-2, .kz-band.kz-3 {
    background: none; border: 0; box-shadow: none; padding: 0; gap: 14px;
  }
  .kz-band.kz-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .kz-feld, .kz-feld + .kz-feld, .kz-feld:nth-child(3) {
    grid-column: span var(--sp, 1);
    background: linear-gradient(180deg, color-mix(in srgb, var(--kz-blau) 6%, var(--surface)) 0, var(--surface) 90px);
    border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border));
    border-radius: 16px; box-shadow: var(--shadow);
    padding: 16px 18px 14px; gap: 12px; justify-items: stretch;
  }
  .kz-titel { text-align: left; font-size: 0.9375rem; }
  .kz-titel br { display: none; }
  .kz-bild { min-height: 170px; }
  .kz-unter { color: var(--muted); }
  .kz-balken .kz-unter { color: var(--text); }
  .kz-fuss {
    justify-self: start; display: inline-flex; align-items: center;
    padding: 4px 12px; border-radius: 999px; font-size: 0.8125rem;
    background: var(--accent-soft); color: var(--accent-soft-text);
  }
  a.kz-fuss::after { content: "\203A"; margin-left: 6px; }
  span.kz-fuss { visibility: hidden; }
  .kz-fuss:hover { text-decoration: none; color: var(--accent-soft-text); filter: brightness(.97); }
  .kz-gross { font-size: min(3.5rem, 17cqi, calc(165cqi / var(--z, 4))); font-weight: 600; }
  .kz-ring svg { width: 130px; height: 130px; }
  .kz-verhaeltnis .kz-unter, .kz-ring .kz-unter, .kz-score .kz-unter { max-width: 32ch; }
}
@media (min-width: 721px) and (max-width: 1100px) {
  .kz-band, .kz-band.kz-3, .kz-band.kz-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 14px; }
  .kz-feld, .kz-feld + .kz-feld, .kz-feld:nth-child(3) { grid-column: span var(--sp-m, 1); }
}

/* Score mit Zahlen daneben: Tacho links, «im Zeitplan» und «überfällig» rechts. */
.kz-score { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
.kz-score-feld { display: flex; align-items: center; justify-content: center; gap: 28px; flex-wrap: wrap; }
.kz-neben { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.kz-neben-zahl {
  display: flex; align-items: center; gap: 12px; padding: 10px 16px 10px 12px; border-radius: 14px;
  background: color-mix(in srgb, var(--kz-hell) 16%, var(--surface)); text-align: left;
}
.kz-neben-wert {
  display: grid; place-items: center; min-width: 46px; height: 46px; padding: 0 8px; border-radius: 999px;
  background: var(--kz-hell); color: var(--kz-auf-hell);
  font-size: 1.375rem; font-weight: 600; font-variant-numeric: tabular-nums;
}
.kz-neben-zahl .kz-unter { color: var(--text); font-size: 0.875rem; }
.kz-neben-zahl.is-warn { background: color-mix(in srgb, var(--kz-blau) 10%, var(--surface)); }
.kz-neben-zahl.is-warn .kz-neben-wert { background: var(--kz-blau); color: var(--kz-auf-blau); }
@media (max-width: 720px) {
  .kz-score-feld { gap: 14px; flex-wrap: nowrap; justify-content: space-between; }
  .kz-neben { gap: 8px; }
  .kz-neben-zahl { padding: 6px 10px 6px 6px; gap: 8px; }
  .kz-neben-wert { min-width: 34px; height: 34px; font-size: 1.0625rem; }
  .kz-neben-zahl .kz-unter { font-size: 0.7812rem; }
  .kz-mit-neben .kz-score svg { width: 136px; height: 85px; }
}

/* In der Karte stehen Beschriftung und Wert über dem Balken: so bleibt
   dem Balken die ganze Breite, auch bei Beträgen wie «CHF 52'523». */
@media (min-width: 721px) {
  .kz-balken { display: flex; flex-direction: column; justify-content: center; align-items: stretch; gap: 12px; width: 100%; }
  .kz-zeile { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 5px 10px; }
  .kz-zeile > .kz-spur { grid-column: 1 / -1; grid-row: 2; height: 14px; }
  .kz-balken .kz-pille, .kz-balken .kz-pille.is-leer { height: 14px; }
  .kz-balken .kz-pille.is-leer { width: 14px; }
  .kz-balken .kz-unter { font-size: 0.875rem; }
  .kz-balken .kz-wert { font-size: 1rem; }
}
/* Am Telefon stehen die zwei Zahlen unter dem Tacho nebeneinander. */
@media (max-width: 720px) {
  .kz-score-feld { flex-direction: column; align-items: stretch; gap: 10px; }
  .kz-neben { flex-direction: row; }
  .kz-neben-zahl { flex: 1 1 0; }
}

/* ---------------------------------------------------------------------------
   Listen der Ausleihenden im Kartenstil (seit 16.10.2026, home.php):
   gleiche Karte wie die Kennzahlen, Titel als Frage, ein Satz darunter.
   --------------------------------------------------------------------------- */
.kz-listen { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); gap: 14px; margin-top: 14px; }
.kz-karte {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--kz-blau) 6%, var(--surface)) 0, var(--surface) 90px);
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border));
  border-radius: 16px; box-shadow: var(--shadow); padding: 16px 18px 14px;
}
.kz-karte .kz-titel { text-align: left; font-size: 0.9375rem; }
.kz-karte > .kz-unter { margin: 0; color: var(--muted); font-size: 0.875rem; max-width: none; text-wrap: wrap; }
.kz-karte .start-liste { margin: 4px 0 6px; }
.kz-karte .start-liste li { padding-left: 0; padding-right: 0; }
.kz-karte > .kz-fuss {
  margin-top: auto; align-self: flex-start; display: inline-flex; align-items: center;
  padding: 4px 12px; border-radius: 999px; font-size: 0.8125rem;
  background: var(--accent-soft); color: var(--accent-soft-text);
}
.kz-karte > a.kz-fuss::after { content: "\203A"; margin-left: 6px; }
.kz-karte > .kz-fuss:hover { text-decoration: none; filter: brightness(.97); }

/* Fragefeld von Swyron AI im Kartenstil (16.10.2026): gleicher Rand und
   gleicher Hauch Blau wie die Kennzahlen; ohne wandernden Verlauf und
   ohne Violett (Swyron AI ist blau). */
.sai-start {
  animation: none; margin-bottom: 14px; padding: 10px 10px 10px 14px; border-radius: 16px;
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border));
  background: linear-gradient(180deg, color-mix(in srgb, var(--kz-blau) 6%, var(--surface)) 0, var(--surface) 100%);
  box-shadow: var(--shadow);
}
.sai-start:hover { box-shadow: var(--shadow); border-color: color-mix(in srgb, var(--kz-rahmen) 55%, var(--border)); }
.sai-start:focus-within {
  transform: none; border-color: var(--kz-blau);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--kz-blau) 14%, transparent), var(--shadow);
}
.sai-start-zeichen { background: color-mix(in srgb, var(--kz-blau) 10%, var(--surface)); }

/* Einträge in den Listenkarten (16.10.2026): Name in einer Zeile, die
   Nummer klein darunter, Datum oder Stand rechts. Vorher standen Nummer,
   Name und Datum nebeneinander, und lange Namen brachen auf dem iPad um. */
.kz-eintraege { list-style: none; margin: 2px 0 6px; padding: 0; }
.kz-eintraege li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--rule);
}
.kz-eintraege li:last-child { border-bottom: 0; }
.kz-e-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; color: inherit; }
a.kz-e-text:hover { text-decoration: none; }
a.kz-e-text:hover .kz-e-name { color: var(--accent-text); }
.kz-e-name { font-weight: 600; color: var(--heading); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kz-e-nr { font-size: 0.8125rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.kz-eintraege .badge { white-space: nowrap; }
/* Am Telefon steht der Stand unter dem Namen, damit der Name die ganze Breite hat. */
@media (max-width: 480px) {
  .kz-eintraege li { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .kz-eintraege .badge { justify-self: start; }
}
/* Mit Produktbild (16.10.2026): Bild links, Name und Nummer, Stand rechts. */
.kz-eintraege li:has(> .sach-bild) { grid-template-columns: 40px minmax(0, 1fr) auto; }
@media (max-width: 480px) {
  .kz-eintraege li:has(> .sach-bild) { grid-template-columns: 40px minmax(0, 1fr); column-gap: 12px; }
  .kz-eintraege li:has(> .sach-bild) > .badge { grid-column: 2; }
}
@media (max-width: 480px) {
  .kz-eintraege li:has(> .sach-bild) > .sach-bild { grid-row: span 2; align-self: start; }
  .kz-eintraege li:has(> .sach-bild) .kz-e-text { flex-direction: column; align-items: flex-start; gap: 1px; }
}
/* Übersicht der Verwaltung (16.10.2026): Stand und Knopf rechts nebeneinander. */
.kz-e-rechts { display: inline-flex; align-items: center; gap: 8px; justify-self: end; }
.kz-e-knopf {
  display: inline-flex; align-items: center; padding: 3px 10px; border-radius: 999px; font-size: 0.7812rem; font-weight: 500;
  background: var(--danger-bg); color: var(--danger-fg); border: 1px solid var(--danger-bd); white-space: nowrap;
}
.kz-e-knopf:hover { text-decoration: none; filter: brightness(.97); }
/* Anzahl je Produkt beim Reservieren (seit 26.10.2026). */
.input.input-anzahl { width: 4.5rem; min-height: 2.25rem; padding: 0 var(--abstand-1); text-align: center; }
.kz-eintraege li > .badge, .kz-eintraege li > .kz-e-rechts { justify-self: end; }
@media (max-width: 480px) {
  .kz-eintraege li > .badge, .kz-eintraege li > .kz-e-rechts { justify-self: start; }
}
/* Höchstens zwei Karten nebeneinander, jede so hoch wie ihr Inhalt; die
   Nebenzeile (Nummern, Abteilung) bleibt auf einer Zeile. */
.kz-listen { grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); align-items: start; }
@media (min-width: 1100px) { .kz-listen { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.kz-e-nr { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
/* Spaltenweise statt im Raster: eine kurze Karte lässt neben einer langen
   keine Lücke, die nächste rückt in derselben Spalte nach. */
.kz-listen { display: block; columns: 2 420px; column-gap: 14px; }
.kz-listen > .kz-karte { break-inside: avoid; margin-bottom: 14px; }
/* Einheiten, die heute bereitliegen müssen (16.10.2026): jede Zeile gelb
   wie mit dem Textmarker, damit man sie beim ersten Blick sieht. Die
   Karte selbst bleibt wie die anderen. */
.kz-karte.is-aufgabe .kz-eintraege li {
  background: var(--note-bg); border: 1px solid var(--note-bd); border-radius: 12px;
  padding: 10px 12px; margin-bottom: 8px;
}
.kz-karte.is-aufgabe .kz-eintraege li:last-child { border-bottom: 1px solid var(--note-bd); margin-bottom: 0; }
.kz-karte.is-aufgabe .kz-e-name { color: var(--note-fg); }
.kz-karte.is-aufgabe .kz-e-nr { color: color-mix(in srgb, var(--note-fg) 75%, var(--muted)); }
.kz-karte.is-aufgabe .badge { background: var(--surface); border-color: var(--note-bd); color: var(--note-fg); }
.kz-karte.is-aufgabe .sach-bild { background: var(--surface); }

/* Telefon (16.10.2026, iPhone in Teams): Safari machte die Score-Karte im
   Raster niedriger als ihren Inhalt, die nächste Karte schob sich darüber.
   Am Telefon steht jede Karte darum als einfache Spalte, so hoch wie ihr
   Inhalt; die zwei Zahlenfelder dürfen schrumpfen und umbrechen. */
@media (max-width: 720px) {
  .kz-band { align-items: start; }
  .kz-feld:not(.kz-quer) { display: flex; flex-direction: column; align-items: stretch; height: auto; }
  .kz-feld:not(.kz-quer) > .kz-bild { flex: none; }
  .kz-feld:not(.kz-quer) > .kz-fuss { align-self: flex-start; margin-top: 4px; }
  .kz-score svg { height: auto; aspect-ratio: 160 / 100; }
  .kz-neben-zahl { min-width: 0; }
  .kz-neben-zahl .kz-unter { min-width: 0; overflow-wrap: anywhere; white-space: normal; text-wrap: balance; }
  .kz-score > .kz-unter { max-width: 34ch; }
}

/* ---------------------------------------------------------------------------
   Katalog zum Reservieren (seit 16.10.2026, reservations/katalog.php):
   Karten wie in einem Laden, ankreuzen, unten die Leiste mit «Weiter».
   --------------------------------------------------------------------------- */
.katalog-filter { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; position: relative; }
.katalog-suche {
  flex: 1 1 auto; min-width: 0; max-width: 560px; padding: 11px 14px; border-radius: 12px; font: inherit; font-size: 0.9375rem;
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border)); background: var(--surface); color: var(--text);
}
.katalog-suche:focus { outline: 2px solid transparent; border-color: var(--kz-blau); box-shadow: 0 0 0 4px color-mix(in srgb, var(--kz-blau) 14%, transparent); }

.katalog-raster { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr)); gap: 14px; padding-bottom: 90px; }
.katalog-karte {
  position: relative; display: flex; flex-direction: column; cursor: pointer; overflow: hidden;
  background: var(--surface); border-radius: 16px; box-shadow: var(--shadow);
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border));
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.katalog-karte:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--kz-rahmen) 60%, var(--border)); }
.katalog-karte[hidden] { display: none; }
.katalog-wahl { position: absolute; opacity: 0; pointer-events: none; }
.katalog-karte:has(.katalog-wahl:checked) { border-color: var(--kz-blau); box-shadow: 0 0 0 3px color-mix(in srgb, var(--kz-blau) 25%, transparent), var(--shadow); }
.katalog-karte:has(.katalog-wahl:focus-visible) { outline: 2px solid var(--kz-blau); outline-offset: 2px; }
.katalog-bild {
  position: relative; display: grid; place-items: center; aspect-ratio: 4 / 3;
  background: linear-gradient(180deg, color-mix(in srgb, var(--kz-blau) 5%, var(--surface)), var(--surface));
  border-bottom: 1px solid var(--rule);
}
/* Bild fest im Rahmen und mittig (16.10.2026): Safari auf dem iPad löste
   `height: 100%` im Rahmen mit Seitenverhältnis nicht auf, das Bild stand
   oben links in seiner eigenen Grösse. */
.katalog-bild { overflow: hidden; }
.katalog-bild img {
  position: absolute; inset: 0; width: 100%; height: 100%; box-sizing: border-box;
  padding: 14px; object-fit: contain; object-position: center;
}
.katalog-bild-leer svg { width: 46px; height: 46px; color: color-mix(in srgb, var(--muted) 60%, transparent); }
.katalog-haken {
  position: absolute; top: 10px; right: 10px; display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  background: var(--surface); border: 2px solid color-mix(in srgb, var(--kz-rahmen) 40%, var(--border)); color: transparent;
}
.katalog-haken svg { width: 16px; height: 16px; stroke-width: 2.6; }
.katalog-karte:has(.katalog-wahl:checked) .katalog-haken { background: var(--kz-blau); border-color: var(--kz-blau); color: var(--kz-auf-blau); }
.katalog-text { display: flex; flex-direction: column; gap: 4px; padding: 12px 14px 14px; flex: 1; }
.katalog-kat { font-size: 0.75rem; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--accent-text); }
.katalog-name { font-size: 1rem; font-weight: 600; color: var(--heading); line-height: 1.3; }
.katalog-beschrieb { font-size: 0.8438rem; color: var(--muted); line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.katalog-fuss { margin-top: auto; padding-top: 8px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 10px; }
.katalog-ort { display: inline-flex; align-items: center; gap: 4px; font-size: 0.8125rem; color: var(--text); min-width: 0; }
.katalog-ort svg { width: 14px; height: 14px; flex: none; color: var(--muted); }
/* «Bescheid geben» bei Produkten ohne freies Gerät (seit 27.10.2026); an = blau umrandet. */
.katalog-bescheid { position: relative; z-index: 1; }
.katalog-bescheid.ist-an { color: var(--accent); border-color: var(--accent); }
.katalog-nichts { margin: 20px 0 100px; }

.katalog-leiste {
  position: sticky; bottom: 14px; z-index: 5; display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: -76px; padding: 12px 14px 12px 18px; border-radius: 16px;
  background: color-mix(in srgb, var(--surface) 92%, transparent); backdrop-filter: blur(8px);
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 40%, var(--border)); box-shadow: var(--shadow-lg);
}
.katalog-zahl { font-weight: 600; color: var(--heading); }
.katalog-leiste .btn[disabled] { opacity: .5; pointer-events: none; }
.kz-e-knopf.ist-ruhig { background: var(--surface); color: var(--muted); border-color: var(--border); }
.kz-e-knopf.ist-anruf { gap: 5px; background: var(--success-bg); color: var(--success-fg); border-color: var(--success-bd); }

/* Gleicher Rand für jede Kennzahlkarte am Telefon (16.10.2026). Eine ältere
   Regel (`.kz-feld + .kz-feld`) nahm ab der zweiten Karte den oberen und
   linken Rand weg — die Karten sahen anders aus als die Listenkarten. */
@media (max-width: 720px) {
  .kz-feld, .kz-feld + .kz-feld, .kz-feld:nth-child(3), .kz-feld.kz-oben {
    border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border));
    box-shadow: var(--shadow);
  }
}

/* Gleich hohe Karten am Telefon (16.10.2026, Wunsch des Betreibers): zwei
   Karten nebeneinander werden so hoch wie die höhere, der Verweis steht
   bei beiden unten und auf einer Zeile. */
@media (max-width: 720px) {
  .kz-band { align-items: stretch; }
  .kz-feld:not(.kz-quer) > .kz-fuss { margin-top: auto; }
  .kz-fuss { max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}

/* Filter im Katalog (16.10.2026): Knopf neben der Suche. Am Bildschirm ein
   Feld darunter, am Telefon ein Blatt von unten. */
.katalog-menue { position: static; }
.katalog-menue > summary { list-style: none; }
.katalog-menue > summary::-webkit-details-marker { display: none; }
.katalog-filterknopf {
  display: inline-flex; align-items: center; gap: 8px; padding: 11px 16px; border-radius: 12px; cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border)); background: var(--surface);
  color: var(--text); font-weight: 500; white-space: nowrap; user-select: none;
}
.katalog-filterknopf svg { width: 17px; height: 17px; color: var(--accent-text); }
.katalog-menue[open] > .katalog-filterknopf { border-color: var(--kz-blau); box-shadow: 0 0 0 4px color-mix(in srgb, var(--kz-blau) 14%, transparent); }
.katalog-filterzahl {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px;
  background: var(--kz-blau); color: var(--kz-auf-blau); font-size: 0.75rem; font-weight: 600;
}
.katalog-filterzahl[hidden] { display: none; }
.katalog-panel {
  position: absolute; z-index: 20; top: calc(100% + 8px); left: 0; width: min(560px, 100%);
  display: flex; flex-direction: column; gap: 16px; padding: 16px 18px 18px; border-radius: 16px;
  background: var(--surface); border: 1px solid color-mix(in srgb, var(--kz-rahmen) 35%, var(--border)); box-shadow: var(--shadow-lg);
}
.katalog-panel-kopf { display: flex; align-items: center; justify-content: space-between; }
.katalog-panel-kopf strong { font-size: 1rem; color: var(--heading); }
.katalog-zuruecksetzen { border: 0; background: none; font: inherit; font-size: 0.875rem; color: var(--accent-text); cursor: pointer; padding: 4px 0; }
.katalog-gruppe { border: 0; margin: 0; padding: 0; min-width: 0; }
.katalog-gruppe legend { padding: 0; margin-bottom: 8px; font-size: 0.75rem; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
.katalog-optionen { display: flex; flex-wrap: wrap; gap: 8px; }
.katalog-option {
  display: inline-flex; align-items: center; gap: 8px; padding: 7px 12px; border-radius: 999px; cursor: pointer; font-size: 0.875rem;
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border)); background: var(--surface); color: var(--text);
}
.katalog-option input { position: absolute; opacity: 0; pointer-events: none; }
.katalog-option:has(input:checked) { background: color-mix(in srgb, var(--kz-blau) 10%, var(--surface)); border-color: var(--kz-blau); color: var(--accent-text); font-weight: 500; }
.katalog-option:has(input:focus-visible) { outline: 2px solid var(--kz-blau); outline-offset: 2px; }
.katalog-anzahl { font-size: 0.75rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.katalog-schalter { display: flex; align-items: center; gap: 12px; cursor: pointer; font-size: 0.9375rem; color: var(--text); }
.katalog-schalter input { position: absolute; opacity: 0; pointer-events: none; }
.katalog-schalter-bahn { position: relative; flex: none; width: 42px; height: 24px; border-radius: 999px; background: color-mix(in srgb, var(--kz-spur) 35%, var(--surface)); transition: background .15s ease; }
.katalog-schalter-bahn::after { content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: var(--surface); box-shadow: 0 1px 3px rgba(10, 37, 64, .3); transition: transform .15s ease; }
.katalog-schalter:has(input:checked) .katalog-schalter-bahn { background: var(--kz-blau); }
.katalog-schalter:has(input:checked) .katalog-schalter-bahn::after { transform: translateX(18px); }
.katalog-schalter:has(input:focus-visible) .katalog-schalter-bahn { outline: 2px solid var(--kz-blau); outline-offset: 2px; }
@media (max-width: 720px) {
  .katalog-filterknopf span:not(.katalog-filterzahl) { display: none; }
  .katalog-filterknopf { padding: 11px 13px; }
  .katalog-menue[open]::before {
    content: ""; position: fixed; inset: 0; z-index: 40; background: rgba(10, 20, 45, .35);
  }
  .katalog-panel {
    position: fixed; z-index: 41; top: auto; left: 0; right: 0; bottom: 0; width: auto; max-height: 80vh; overflow-y: auto;
    border-radius: 20px 20px 0 0; padding: 10px 18px calc(18px + env(safe-area-inset-bottom));
  }
  .katalog-panel::before { content: ""; align-self: center; width: 40px; height: 4px; border-radius: 999px; background: var(--border); }
}

/* Leiste unten im Katalog (16.10.2026): runder Zähler, Namen der Auswahl,
   ohne Auswahl ein Tipp; mit Auswahl blau. */
.katalog-leiste { padding: 10px 10px 10px 12px; gap: 12px; transition: background .2s ease, border-color .2s ease; }
.katalog-leiste-zahl {
  flex: none; display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%;
  background: color-mix(in srgb, var(--kz-blau) 10%, var(--surface)); color: var(--accent-text);
  font-size: 1.125rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.katalog-leiste-zahl svg { width: 20px; height: 20px; }
.katalog-leiste-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.katalog-leiste .katalog-zahl { font-size: 0.9375rem; }
.katalog-namen { font-size: 0.8125rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.katalog-weiter { flex: none; display: inline-flex; align-items: center; gap: 6px; border-radius: 12px; }
.katalog-weiter svg { width: 16px; height: 16px; }
.katalog-leiste .katalog-weiter[disabled] { opacity: 1; background: var(--surface-muted); color: var(--muted); border-color: var(--border); box-shadow: none; }
.katalog-leiste.is-gewaehlt {
  background: linear-gradient(110deg, var(--kz-blau), color-mix(in srgb, var(--kz-blau) 75%, var(--kz-hell)));
  border-color: transparent; backdrop-filter: none;
}
.katalog-leiste.is-gewaehlt .katalog-zahl { color: #fff; }
.katalog-leiste.is-gewaehlt .katalog-namen { color: rgba(255, 255, 255, .85); }
.katalog-leiste.is-gewaehlt .katalog-leiste-zahl { background: #fff; color: var(--kz-blau); }
.katalog-leiste.is-gewaehlt .katalog-weiter { background: #fff; color: var(--kz-blau); border-color: #fff; }
@media (max-width: 720px) {
  .katalog-leiste { bottom: calc(10px + env(safe-area-inset-bottom)); border-radius: 18px; }
  .katalog-leiste-zahl { width: 38px; height: 38px; font-size: 1rem; }
  .katalog-weiter { padding-left: 14px; padding-right: 12px; }
}
/* Leiste nicht Kante auf Kante mit den Karten (16.10.2026): eingerückt,
   undurchsichtig und mit weichem Schatten — sie schwebt über dem Raster. */
.katalog-leiste {
  margin-left: auto; margin-right: auto; width: min(720px, calc(100% - 48px));
  background: var(--surface); backdrop-filter: none;
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 25%, var(--border));
  box-shadow: 0 18px 40px -12px rgba(10, 37, 64, .35), 0 2px 6px rgba(10, 37, 64, .08);
}
@media (max-width: 720px) { .katalog-leiste { width: calc(100% - 20px); } }
/* Filterblatt am Telefon (16.10.2026): bei vielen Kategorien wurde der
   Inhalt zusammengedrückt — nichts im Blatt schrumpft mehr, es scrollt.
   Geschlossen wird mit einem Tipp auf den Grund daneben. */
@media (max-width: 720px) {
  .katalog-panel > * { flex: none; }
}
/* Produktbilder ohne weissen Kasten (16.10.2026): die meisten Fotos haben
   einen weissen Hintergrund. Auf weissem Grund und mit `multiply` wird Weiss
   unsichtbar — ohne das Bild zu verändern. */
.katalog-bild { background: #fff; }
.katalog-bild img { mix-blend-mode: multiply; }
.sach-bild:not(.is-leer) { background: #fff; }
img.sach-bild { mix-blend-mode: multiply; }
/* Fotos der Einheiten und Produkte (16.10.2026): ganz gezeigt statt
   beschnitten, auf weissem Grund, Weiss im Foto verschwindet darin — wie im
   Katalog. Die Grossansicht zeigt weiterhin das unveränderte Original. */
.attach-item img {
  object-fit: contain; padding: 8px; box-sizing: border-box;
  background: #fff; mix-blend-mode: multiply;
}
/* Hintergrund wie entfernt (16.10.2026): das Foto nimmt die Farbe seiner
   Fläche an — Weiss im Foto wird zum Hauch Blau der Karte, im Kästchen
   zum Grau. Im Dunkelmodus bliebe ein Foto so fast schwarz; dort steht es
   darum auf einer hellen Fläche. */
.katalog-bild { background: linear-gradient(180deg, color-mix(in srgb, var(--kz-blau) 6%, var(--surface)), var(--surface)); }
.sach-bild:not(.is-leer) { background: var(--surface-muted); }
.attach-item img { background: var(--surface-muted); }
@media (prefers-color-scheme: dark) {
  :root:not(.hell):not([data-teams]) .katalog-bild,
  :root:not(.hell):not([data-teams]) .sach-bild:not(.is-leer),
  :root:not(.hell):not([data-teams]) .attach-item img { background: #f4f6fb; }
}
[data-teams="dark"] .katalog-bild, [data-teams="dark"] .sach-bild:not(.is-leer), [data-teams="dark"] .attach-item img,
[data-teams="contrast"] .katalog-bild, [data-teams="contrast"] .sach-bild:not(.is-leer), [data-teams="contrast"] .attach-item img { background: #f4f6fb; }

/* Flüssig scrollen (16.10.2026): `multiply` mischte jedes Foto mit der
   ganzen Seite, Safari rechnete beim Scrollen jedes Mal alles neu. Jetzt
   mischt jedes Bild nur mit seiner eigenen Fläche (`isolation`), Karten
   ausserhalb des Bildschirms werden erst gezeichnet, wenn sie kommen, und
   auf Touch-Geräten hebt sich keine Karte beim Überfahren. */
.katalog-bild, .attach-item a, .kz-eintraege li, .sach-bild { isolation: isolate; }
.katalog-bild, .attach-item a { contain: paint; }
.katalog-karte { content-visibility: auto; contain-intrinsic-size: auto 340px; }
@media (hover: none) {
  .katalog-karte, .katalog-karte:hover { transform: none; transition: border-color .15s ease; }
}
/* Kasten unter den Tagen, wenn für einige Geräte keins frei ist (16.10.2026). */
.res-belegt {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 14px; padding: 14px 16px; border-radius: 14px;
  background: var(--danger-bg); border: 1px solid var(--danger-bd); color: var(--danger-fg);
}
.res-belegt[hidden] { display: none; }
.res-belegt p { margin: 0; font-weight: 500; }
.kz-e-rechts .badge[hidden] { display: none; }
/* Wann die Geräte eines belegten Produkts belegt sind (27.10.2026): klein
   und gedämpft unter der Produktzeile, ohne Namen. */
.res-wann { grid-column: 1 / -1; list-style: none; margin: -4px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 2px; font-size: 0.8125rem; color: var(--muted);
  font-variant-numeric: tabular-nums; text-wrap: pretty; }
.kz-eintraege li:has(> .sach-bild) > .res-wann { grid-column: 2 / -1; }
.kz-eintraege .res-wann > li { display: block; padding: 0; border: 0; }
.res-wann[hidden] { display: none; }
.res-wann-nr { font-weight: 500; color: var(--text); }
/* Swyron AI: Fragen pro Person in den Funktionen (16.10.2026). */
.ai-grenze { align-items: end; }
.ai-grenze + .ai-grenze { margin-top: 6px; }
.ai-grenze-wer { margin: 0 0 12px; }

/* ---------------------------------------------------------------------------
   Grafiken zu Swyron AI auf der Webseite (seit 16.10.2026, partials/ki-schutz):
   der Weg einer Frage und die Wache. Am Bildschirm in einer Reihe, am
   Telefon untereinander; die Pfeile drehen mit.
   --------------------------------------------------------------------------- */
.ki-grafik { margin: 28px 0 0; padding: 26px; border-radius: 20px; background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 30%, var(--border)); box-shadow: var(--shadow); }
.ki-grafik-titel { margin: 0 0 20px; font-size: 1.125rem; font-weight: 600; color: var(--heading); }
.ki-knoten { position: relative; display: flex; flex-direction: column; gap: 6px; padding: 16px; border-radius: 16px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--kz-blau) 6%, var(--surface)), var(--surface));
  border: 1px solid color-mix(in srgb, var(--kz-rahmen) 28%, var(--border)); min-width: 0; }
.ki-knoten strong { color: var(--heading); font-size: 0.9375rem; }
.ki-knoten > span:not(.ki-symbol):not(.ki-zurueck) { color: var(--muted); font-size: 0.8438rem; line-height: 1.45; }
.ki-symbol { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px;
  background: color-mix(in srgb, var(--kz-blau) 12%, var(--surface)); color: var(--kz-blau); }
.ki-symbol svg { width: 20px; height: 20px; }

/* Der Weg einer Frage */
.ki-weg-schritte { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 28px; align-items: start; }
.ki-weg-schritte > li + li::before {
  content: ""; position: absolute; left: -24px; top: 34px; width: 20px; height: 2px; background: var(--kz-blau);
}
.ki-weg-schritte > li + li::after {
  content: ""; position: absolute; left: -10px; top: 29px; border: 6px solid transparent; border-left-color: var(--kz-blau);
}
.ki-waechter { border-color: var(--kz-blau); box-shadow: 0 0 0 3px color-mix(in srgb, var(--kz-blau) 16%, transparent); }
.ki-waechter .ki-symbol, .ki-modell .ki-symbol { background: var(--kz-blau); color: #fff; }
.ki-pruefung { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.ki-pruefung li { display: flex; gap: 7px; align-items: baseline; font-size: 0.8125rem; line-height: 1.35; color: var(--text); }
.ki-pruefung li::before { flex: none; font-weight: 700; }
.ki-pruefung li.is-ja::before { content: "✓"; color: var(--success-fg); }
.ki-pruefung li.is-nein::before { content: "✕"; color: var(--danger-fg); }
.ki-zurueck { margin-top: 6px; align-self: flex-start; padding: 4px 10px; border-radius: 999px; font-size: 0.7812rem;
  background: var(--danger-bg); color: var(--danger-fg); border: 1px solid var(--danger-bd); }
.ki-zurueck::before { content: "↩ "; }

/* Die Wache */
.ki-wache-raster { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 14px; }
.ki-wache-mitte { grid-column: 1 / -1; flex-direction: row; align-items: center; gap: 14px; border-color: var(--kz-blau);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--kz-blau) 16%, transparent); margin-bottom: 18px; }
.ki-wache-mitte .ki-symbol { background: var(--kz-blau); color: #fff; flex: none; }
.ki-wache-mitte strong { flex: none; }
.ki-wache-mitte::after { content: ""; position: absolute; left: 10%; right: 10%; bottom: -19px; height: 18px;
  border: 2px solid var(--kz-blau); border-top: 0; border-radius: 0 0 14px 14px; opacity: .5; }
.ki-alarm .ki-symbol { background: var(--danger-bg); color: var(--danger-fg); }

@media (max-width: 960px) {
  .ki-weg-schritte, .ki-wache-raster { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .ki-weg-schritte > li + li::before { left: 34px; top: -20px; width: 2px; height: 16px; }
  .ki-weg-schritte > li + li::after { left: 29px; top: -8px; border-left-color: transparent; border-top-color: var(--kz-blau); }
  .ki-wache-raster { gap: 10px; }
  .ki-wache-mitte { flex-direction: column; align-items: flex-start; margin-bottom: 6px; }
  .ki-wache-mitte::after { display: none; }
  .ki-grafik { padding: 18px; }
}
.ki-waechter .ki-symbol.ki-guard { background: color-mix(in srgb, var(--kz-blau) 10%, var(--surface)); width: 44px; height: 44px; }
.ki-guard svg { width: 30px; height: 30px; }
@media (min-width: 961px) {
  .ki-weg-schritte { grid-template-columns: 1fr 1fr 1.35fr 1fr 1fr; }
}
@media (max-width: 960px) {
  .ki-wache-raster { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ki-wache-mitte { grid-column: 1 / -1; }
  .ki-wache-raster .ki-knoten:not(.ki-wache-mitte) { padding: 12px; }
  .ki-wache-raster .ki-knoten:not(.ki-wache-mitte) > span:not(.ki-symbol) { font-size: 0.7812rem; }
  .ki-wache-raster .ki-symbol { width: 34px; height: 34px; }
}
/* Am Telefon (17.10.2026): die Wache als Baum. Eine Linie läuft von der Wache
   an ihren vier Aufgaben vorbei, je mit Pfeil, und endet mit einem Pfeil im
   Alarm an Swyron — wie im Diagramm am Bildschirm. Die Pfeilspitze ist eine
   Maske, damit sie die Farbe aus der Rolle nimmt. */
@media (max-width: 860px) {
  .ki-wache-raster { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .ki-wache-mitte { margin-bottom: 0; }
  .ki-wache-raster .ki-knoten:not(.ki-wache-mitte):not(.ki-alarm) { margin-left: 44px; }
  .ki-wache-raster .ki-knoten:not(.ki-wache-mitte)::before {
    content: ""; position: absolute; left: -21px; top: -13px; bottom: -1px; width: 2px; background: var(--kz-blau);
  }
  .ki-wache-raster .ki-knoten:not(.ki-wache-mitte):not(.ki-alarm)::after,
  .ki-wache-raster .ki-knoten.ki-alarm::after {
    content: ""; position: absolute; left: -20px; top: 21px; width: 19px; height: 12px; background: var(--kz-blau);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 19 12'%3E%3Cpath d='M0 6H16M11 1.5L16.5 6L11 10.5' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center / contain;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 19 12'%3E%3Cpath d='M0 6H16M11 1.5L16.5 6L11 10.5' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center / contain;
  }
  /* Der Alarm steht voll breit; die Linie kommt von oben und endet als Pfeil. */
  .ki-wache-raster .ki-alarm { margin-top: 10px; }
  .ki-wache-raster .ki-knoten.ki-alarm::before { left: 23px; top: -23px; bottom: auto; height: 16px; }
  .ki-wache-raster .ki-knoten.ki-alarm::after { left: 16px; top: -14px; width: 16px; height: 12px; transform: rotate(90deg); }
}
/* Das Zeichen von Swyron AI auf blauer Kachel ist weiss (sonst Blau auf Blau). */
.ki-modell .ki-symbol .sai-zeichen { color: inherit; width: 24px; height: 24px; }
.ki-modell .ki-symbol .sai-zeichen.lebt .sai-ring { opacity: .6; }

/* Liniendiagramme zu Swyron AI (16.10.2026, KiGrafik): am Bildschirm das
   Diagramm, am Telefon die Karten untereinander. */
.kg-svg { display: block; width: 100%; height: auto; font-family: inherit; }
.kg-linie { stroke: #5b8ff5; stroke-width: 2.2; }
.kg-gross { font-size: 22px; font-weight: 600; fill: #0f1b33; }
.kg-mittel { font-size: 19px; fill: #1257e5; }
.kg-dunkel { fill: #0f1b33; }
.kg-klein { font-size: 15px; fill: #5a6a85; }
.kg-titel { font-size: 20px; font-weight: 600; fill: #0f1b33; }
.kg-pille-text { font-size: 15px; font-weight: 600; fill: #1257e5; }
.ki-grafik-diagramm { display: block; }
.ki-grafik-diagramm + .ki-grafik-karten { display: none; }
@media (max-width: 860px) {
  .ki-grafik-diagramm { display: none; }
  .ki-grafik-diagramm + .ki-grafik-karten { display: block; }
}
.kg-ai { fill: #1257e5; }
.kg-pille-text { font-size: 0.875rem; }
/* Wortmarke «Swyron Guard» (16.10.2026): Guard fett im dunklen Blau des Schilds. */
.sg-name { white-space: nowrap; }
.sg-name-guard { font-weight: 800; color: #0a2f8a; letter-spacing: .01em; }
:is(.hero-dark, .section-dark) .sg-name-guard { color: #a9c2f9; }
.kg-guard { font-weight: 800; fill: #0a2f8a; }
.kg-kasten-titel { font-size: 15px; font-weight: 800; fill: #0a2f8a; letter-spacing: .02em; }
.kg-ai-zeichen { color: #1257e5; }

/* «Film ansehen» zurückhaltend (16.10.2026, Wunsch des Betreibers): Blau
   bleibt dem Testen vorbehalten. Dunkel-durchsichtig mit hellem Rand, das
   Abspielzeichen im blauen Kreis. */
.hero-dark .hero-film-knopf {
  background: rgba(255, 255, 255, .07); color: #fff; border: 1px solid rgba(255, 255, 255, .32);
  box-shadow: none; backdrop-filter: none;
}
.hero-dark .hero-film-knopf:hover { background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .5); color: #fff; }
.hero-dark .hero-film-knopf .ic {
  width: 30px; height: 30px; padding: 8px 7px 8px 9px; border-radius: 50%; box-sizing: border-box;
  background: var(--accent); color: #fff;
}

/*
  Swyron AI auf der Funktionsseite: die Beispiele aus Inventaris
  (seit 17.10.2026, partials/swyron-ai-seite.php, vorher auf swyron.com).
  Fragen-Wand, zwei gezeichnete Fenster (Gerätehilfe, Ticket) und der
  Weg eines Namens. Nur Rollen; die Verkaufsseiten sind immer hell, die
  Fenster nehmen trotzdem keine Hexwerte, damit sie im Reiter stimmen.
*/
.sai-wand {
  display: grid; gap: 18px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 960px) { .sai-wand { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .sai-wand { grid-template-columns: minmax(0, 1fr); } }
.sai-wand-gruppe {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 18px 20px 16px;
}
.sai-wand-gruppe h3 { display: flex; align-items: center; gap: 10px; margin: 0 0 12px; font-size: 0.9375rem; font-weight: 650; color: var(--heading); }
.sai-wand-ic {
  flex: none; display: grid; place-items: center; width: 30px; height: 30px; border-radius: 8px;
  background: var(--ton-blau-bg); color: var(--accent);
}
.sai-wand-ic svg { width: 16px; height: 16px; }
.sai-wand-gruppe ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.sai-wand-gruppe li {
  position: relative; padding: 7px 12px 7px 26px; border-radius: 10px;
  background: var(--surface-muted); color: var(--text); font-size: 0.875rem; line-height: 1.45;
}
/* Eine Sprechblase als Zeichen davor: das sind Fragen, keine Funktionen. */
.sai-wand-gruppe li::before {
  content: ""; position: absolute; left: 11px; top: 14px; width: 7px; height: 7px;
  border-radius: 50% 50% 50% 0; background: var(--accent);
}

.sai-split {
  display: grid; gap: 44px; align-items: center;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
}
.sai-split-umgekehrt > .sai-split-text { order: 2; }
.sai-split-text .lead { color: var(--muted); font-size: 1.0625rem; line-height: 1.6; margin-top: 14px; }
@media (max-width: 900px) {
  .sai-split { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .sai-split-umgekehrt > .sai-split-text { order: 0; }
}

.sai-fenster {
  margin: 0; background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
  box-shadow: 0 24px 60px -24px rgba(10, 20, 45, .3); overflow: hidden; text-align: left;
}
.sai-fenster .sai-vorschau-kopf { padding: 14px 20px 12px; border-bottom: 1px solid var(--rule); }
.sai-fenster .sai-vorschau-kopf small { margin-left: auto; color: var(--muted); font-size: 0.8125rem; }
.sai-fenster .sai-verlauf { padding: 18px 20px; }
.sai-fenster figcaption {
  padding: 10px 20px; border-top: 1px solid var(--rule); background: var(--surface-muted);
  color: var(--muted); font-size: 0.8125rem;
}
.sai-text ol.sai-mock-schritte { list-style: none; padding: 0; margin: 0 0 10px; display: grid; gap: 7px; }
.sai-text ol.sai-mock-schritte > li { display: flex; align-items: flex-start; gap: 10px; padding: 0; margin: 0; }
.sai-mock-haken {
  flex: none; display: grid; place-items: center; width: 20px; height: 20px; margin-top: 1px;
  border: 1.5px solid var(--border); border-radius: 6px; background: var(--surface);
}
.sai-mock-haken svg { width: 13px; height: 13px; }
.ist-probiert .sai-mock-haken { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.sai-mock-schritte .ist-probiert { color: var(--muted); }
.sai-mock-klein { font-size: 0.8125rem; color: var(--muted); }
.sai-mock-knoepfe { display: flex; flex-wrap: wrap; gap: 8px; }
.sai-mock-knopf {
  display: inline-flex; align-items: center; gap: 7px; padding: 8px 14px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent); font-size: 0.875rem; font-weight: 600; line-height: 1.2;
}
.sai-mock-knopf-zweit { background: var(--surface); color: var(--accent-text); border: 1px solid var(--border); }
.sai-mock-knopf-ai { background: var(--ton-blau-bg); color: var(--accent-text); }
.sai-mock-vorschau {
  display: flex; align-items: center; gap: 8px; margin: 0; padding: 9px 12px; border-radius: 10px;
  background: var(--success-bg); color: var(--success-fg); font-size: 0.8125rem; font-weight: 600;
}
.sai-mock-vorschau svg { flex: none; width: 16px; height: 16px; }

.sai-ticket-kopf {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  padding: 14px 20px; border-bottom: 1px solid var(--rule);
}
.sai-ticket-kopf strong { color: var(--heading); font-size: 0.9375rem; }
.sai-ticket-status {
  margin-left: auto; padding: 2px 10px; border-radius: 999px; font-size: 0.75rem; font-weight: 650;
  background: var(--ton-blau-bg); color: var(--accent-text);
}
.sai-ticket-feld {
  margin: 16px 20px 0; padding: 14px 16px; border: 1px solid var(--accent); border-radius: 12px;
  box-shadow: 0 0 0 3px var(--ton-blau-bg); color: var(--text); line-height: 1.6; font-size: 0.9375rem;
}
.sai-ticket-feld p { margin: 0 0 10px; }
.sai-ticket-feld p:last-child { margin: 0; }
.sai-ticket-hinweis { display: flex; align-items: center; gap: 8px; margin: 10px 20px 0; color: var(--muted); font-size: 0.8125rem; }
.sai-ticket-hinweis > :first-child { flex: none; }
.sai-ticket .sai-mock-knoepfe { padding: 14px 20px 18px; }

.sai-fluss {
  list-style: none; margin: 28px 0 0; padding: 0; display: grid; gap: 14px;
  grid-template-columns: repeat(3, minmax(0, 1fr)); counter-reset: none;
}
.sai-fluss li {
  position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px 18px;
}
/* Ein Pfeil zum nächsten Schritt, nur nebeneinander. */
.sai-fluss li:not(:last-child)::after {
  content: "→"; position: absolute; right: -13px; top: 50%; transform: translateY(-50%);
  width: 24px; height: 24px; display: grid; place-items: center; border-radius: 50%;
  background: var(--accent); color: var(--on-accent); font-size: 0.8125rem; font-weight: 700; z-index: 1;
}
.sai-fluss-schritt { display: block; margin-bottom: 8px; color: var(--accent-text); font-size: 0.75rem; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; }
.sai-fluss p { margin: 0; color: var(--text); line-height: 1.6; }
.sai-fluss strong { color: var(--heading); }
.sai-platzhalter {
  display: inline-block; padding: 0 7px; border-radius: 6px; border: 1px dashed var(--accent);
  color: var(--accent-text); font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap;
}
@media (max-width: 760px) {
  .sai-fluss { grid-template-columns: minmax(0, 1fr); }
  .sai-fluss li:not(:last-child)::after { content: "↓"; right: auto; left: 50%; top: auto; bottom: -13px; transform: translateX(-50%); }
}

/* Hinweis zur PHP-Sicherheitslücke (partials/php-hinweis.php, bis 31.10.2026).
   Feste Farben statt Variablen: dieselbe Leiste steht hell und dunkel, in
   Teams und auf allen Swyron-Seiten gleich. */
.php-hinweis { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 9px 16px; background: #0a2a6d; color: #fff; font-size: .875rem; line-height: 1.45; text-align: left; position: relative; z-index: 60; }
.php-hinweis p { margin: 0; max-width: 980px; color: #fff; }
.php-hinweis strong { color: #fff; font-weight: 700; }
.php-hinweis-ic { flex: none; color: #8fb0f7; }
@media print { .php-hinweis { display: none; } }
.php-hinweis-erledigt { background: #0d5e33; }
.php-hinweis-erledigt .php-hinweis-ic { color: #8fe3ae; }

/* Statusmeldungen aus Swyron SOC (partials/status-leiste.php, seit 21.10.2026).
   Feste Farben wie bei der PHP-Leiste: dieselbe Leiste steht hell und
   dunkel, in Teams und in allen Swyron-Anwendungen gleich (Vorgabe
   «Swyron Leitstelle/doku/status.md»). Höchstens drei übereinander. */
.status-leisten { position: relative; z-index: 60; }
.status-leiste { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 9px 16px; background: #0a2a6d; color: #fff; font-size: .875rem; line-height: 1.45; text-align: left; }
.status-leiste + .status-leiste { border-top: 1px solid rgba(255, 255, 255, .18); }
.status-leiste p { margin: 0; max-width: 980px; min-width: 0; color: #fff; }
.status-leiste strong { color: #fff; font-weight: 700; }
.status-leiste-text { margin-left: .35em; }
.status-leiste a { margin-left: .5em; color: #fff; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; }
.status-leiste a:hover { text-decoration-thickness: 2px; }
.status-leiste a:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.status-leiste-ic { flex: none; color: #8fb0f7; }
.status-leiste-rot { background: #8f1d1d; }
.status-leiste-rot .status-leiste-ic { color: #fecaca; }
.status-leiste-gruen { background: #0d5e33; }
.status-leiste-gruen .status-leiste-ic { color: #8fe3ae; }
@media print { .status-leisten { display: none; } }

/* Statusseite: Verfügbarkeit der letzten 90 Tage, ein Balken je Tag. */
.status-balken { display: flex; gap: 2px; height: 34px; margin: 0; padding: 0; list-style: none; }
.status-balken > li { flex: 1 1 0; min-width: 0; border-radius: 2px; background: var(--rule); }
.status-balken > li.is-success { background: var(--success-fg); }
.status-balken > li.is-warning { background: var(--warning-fg); }
.status-balken > li.is-danger  { background: var(--danger-fg); }
.status-balken-achse { display: flex; justify-content: space-between; margin-top: 6px; font-size: 0.8125rem; color: var(--muted); }
.status-wert { font-size: 0.9375rem; color: var(--muted); }
.status-wert strong { color: var(--heading); font-variant-numeric: tabular-nums; }
.status-verlauf-auf { margin-top: 10px; }
.status-verlauf-auf summary { cursor: pointer; font-size: 0.875rem; color: var(--accent); }
@media (max-width: 560px) { .status-balken { gap: 1px; height: 28px; } }

/* Bildflächen wie im Mockup des Katalogs (22.10.2026, Wunsch Betreiber):
   hinter jedem Produkt- und Einheitenfoto ein sanfter Verlauf vom hellen
   Inventaris-Blau zu Weiss, hell wie dunkel gleich. Weiss im Foto nimmt den
   Verlauf an (multiply), weisse Geräte verschwinden nicht mehr im Dunkelmodus. */
:root { --bild-grund: linear-gradient(180deg, #e9effd 0%, #f6f8fe 55%, #ffffff 100%); }
.katalog-bild,
.sach-bild:not(.is-leer),
.attach-item img,
:root .katalog-bild, :root .sach-bild:not(.is-leer), :root .attach-item img { background: var(--bild-grund); }
@media (prefers-color-scheme: dark) {
  :root:not(.hell):not([data-teams]) .katalog-bild,
  :root:not(.hell):not([data-teams]) .sach-bild:not(.is-leer),
  :root:not(.hell):not([data-teams]) .attach-item img { background: var(--bild-grund); }
}
[data-teams] .katalog-bild, [data-teams] .sach-bild:not(.is-leer), [data-teams] .attach-item img { background: var(--bild-grund); }

/* Das Foto liegt in einem Rahmen mit dem Verlauf und mischt sich hinein
   (22.10.2026): auf dem <img> selbst konnte sich Weiss nicht mit der eigenen
   Fläche mischen und blieb ein weisses Kästchen. */
.sach-bild.ist-foto { display: inline-block; overflow: hidden; box-sizing: border-box; }
.sach-bild-foto {
  display: block; width: 100%; height: 100%; box-sizing: border-box; padding: 3px;
  object-fit: contain; background: transparent; mix-blend-mode: multiply;
}
.attach-item a { border-radius: 10px; background: var(--bild-grund); isolation: isolate; }
:root .attach-item img,
:root:not(.hell):not([data-teams]) .attach-item img,
[data-teams] .attach-item img { display: block; background: transparent; mix-blend-mode: multiply; object-fit: contain; }

/* Etiketten (seit 22.10.2026): ein Bogen 210 × 297 mm ohne Rand, drei mal
   acht Etiketten zu 70 × 37 mm (z. B. Avery Zweckform 3474). Der Bogen ist
   ein `.sheet` wie ein Beleg; hier nur Raster und Etikett. Masse in mm,
   damit der QR-Code bei Skalierung 100 % seine 25 mm behält. */
.sheet.etiketten-bogen {
  display: grid; grid-template-columns: repeat(3, 70mm); grid-auto-rows: 37mm;
  align-content: start; padding: 0.5mm 0 0; min-height: 297mm; height: 297mm; overflow: hidden;
}
.etikett {
  box-sizing: border-box; display: flex; align-items: center; gap: 3mm;
  padding: 3mm 3.5mm; overflow: hidden; break-inside: avoid;
}
.etikett-qr { flex: 0 0 25mm; width: 25mm; height: 25mm; }
.etikett-text { display: flex; flex-direction: column; gap: 1mm; min-width: 0; }
.etikett-nummer { font-size: 13pt; line-height: 1.1; letter-spacing: .02em; overflow-wrap: anywhere; }
.etikett-produkt {
  font-size: 8.5pt; line-height: 1.2;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.etikett-org { font-size: 7pt; line-height: 1.2; opacity: .7; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.etiketten-hinweis { justify-content: flex-start; }
/* Der Markenstrich der Belege läge sonst quer über der ersten Reihe. */
.sheet.etiketten-bogen::before { content: none; display: none; }
.etiketten-hinweis .hint { margin: 0; }
/* Avery L6011-20 (seit 28.10.2026, `Etiketten`): 63,5 × 29,6 mm, drei mal neun
   je A4. Oben und unten 15,3 mm, seitlich 7,25 mm, zwischen den Spalten
   2,5 mm, zwischen den Reihen nichts. Kleinere Schrift und QR-Code, damit
   alles auf die 29,6 mm Höhe passt. */
.sheet.etiketten-bogen.v-avery-l6011 {
  grid-template-columns: repeat(3, 63.5mm); grid-auto-rows: 29.6mm; column-gap: 2.5mm;
  padding: 15.3mm 7.25mm 0;
}
.v-avery-l6011 .etikett { gap: 2.5mm; padding: 2mm 2.5mm; }
.v-avery-l6011 .etikett-qr { flex-basis: 22mm; width: 22mm; height: 22mm; }
.v-avery-l6011 .etikett-text { gap: 0.6mm; }
.v-avery-l6011 .etikett-nummer { font-size: 11pt; }
.v-avery-l6011 .etikett-produkt { font-size: 7.5pt; }
.v-avery-l6011 .etikett-org { font-size: 6.5pt; }
@media print { .sheet.etiketten-bogen.v-avery-l6011 { padding: 15.3mm 7.25mm 0; } }
/* Gestaltung «Eigentum» (seit 28.10.2026, nach dem Foto eines Kunden): Text
   links, oben wem es gehört, unten Telefon und Inventarnummer; der QR-Code
   rechts unten. Normale Schrift, kein Fett — wie auf dem Vorbild. */
/* Masse nach dem Foto (L6011, 63,5 × 29,6 mm), mit etwas mehr Luft zum Rand
   (Wunsch des Betreibers: klebte zu sehr am Rahmen): oben 4,5, links 7, rechts
   6,5, unten 4 mm; Schrift 9 pt, zwei Blöcke über die Höhe verteilt; QR
   11,5 mm rechts unten, mit festem Abstand unter dem Namen (`row-gap`),
   auch wenn der Name bis über den QR-Code reicht. 70 × 37: 10 pt, QR 14 mm. */
.etikett.etikett-eigentum {
  display: grid; grid-template-columns: 1fr auto; grid-template-rows: auto 1fr;
  grid-template-areas: "wer wer" "angaben qr"; column-gap: 3mm; row-gap: 1.8mm;
  align-items: end; padding: 5.25mm 6.5mm 5.25mm 7.5mm;
}
.etikett-eig-wer {
  grid-area: wer; align-self: start; font-size: 10pt; line-height: 1.2;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.etikett-eig-angaben {
  grid-area: angaben; display: flex; flex-direction: column; gap: 0; min-width: 0;
  font-size: 10pt; line-height: 1.2;
}
/* Volles Schwarz: Grau wird auf Silberfolie gerastert und wirkt fleckig (Probedruck 28.10.2026). */
.etikett-eig-produkt { font-size: 7.5pt; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.etikett-eigentum .etikett-qr { grid-area: qr; width: 14mm; height: 14mm; margin-bottom: 0.3mm; }
.v-avery-l6011 .etikett.etikett-eigentum { padding: 4.25mm 6.5mm 4.25mm 7mm; column-gap: 2.5mm; row-gap: 1.3mm; }
.v-avery-l6011 .etikett-eig-wer,
.v-avery-l6011 .etikett-eig-angaben { font-size: 9pt; }
.v-avery-l6011 .etikett-eig-produkt { font-size: 6.5pt; }
.v-avery-l6011 .etikett-eigentum .etikett-qr { width: 11.5mm; height: 11.5mm; }
.etiketten-wahl-zahl .input { width: 110px; }
/* Druckkorrektur (seit 28.10.2026): der Inhalt jedes Etiketts wandert um den
   eingestellten Versatz; das Raster bleibt, wo der Bogen es verlangt. */
.etiketten-bogen > .etikett { transform: translate(var(--versatz-x, 0mm), var(--versatz-y, 0mm)); }
.etiketten-summe { align-self: flex-end; margin-bottom: 10px; }
/* Ein schon benutztes Feld bleibt leer; am Bildschirm schraffiert, gedruckt nichts. */
@media screen {
  .etikett.etikett-frei { background: repeating-linear-gradient(45deg, transparent 0 6px, var(--rule) 6px 7px); }
}
.etiketten-wahl-haken { align-self: flex-end; margin: 0 0 11px; }
/* Die Wahl der Vorlage über dem Bogen. */
.etiketten-hinweis { flex-wrap: wrap; gap: var(--abstand-2) var(--abstand-4); }
.etiketten-wahl { display: flex; align-items: flex-end; flex-wrap: wrap; gap: var(--abstand-2); }
.etiketten-wahl-feld { display: flex; flex-direction: column; gap: 4px; }
.etiketten-wahl-feld .select { min-width: 300px; }
/* Am Bildschirm zeigt eine feine Linie, wo die Etiketten liegen; gedruckt wird sie nicht. */
@media screen { .etikett { outline: 1px dashed var(--border); outline-offset: -1px; } }
@media print { .sheet.etiketten-bogen { padding: 0.5mm 0 0; height: 297mm; } }

/* Status prüfen (seit 28.10.2026): oben das Scanfeld, darunter eine Karte —
   Kopf mit Bild und Nummer, ein farbiger Zustandsblock mit einem Satz und der
   Frist in Worten, dann die Angaben als Kacheln (am Telefon und im schmalen
   Teams-Reiter zu zweit). Farben nur über Rollen, hell, dunkel und Teams. */
.status-scan { margin-bottom: var(--abstand-4); }
.status-karte { overflow: hidden; }
.status-kopf { display: flex; align-items: center; gap: var(--abstand-3); padding: var(--abstand-4) var(--abstand-4) var(--abstand-3); }
.status-kopf-text { flex: 1 1 auto; min-width: 0; }
.status-kopf-text h2 { margin: 2px 0 4px; font-size: 1.25rem; line-height: 1.2; }
.status-kopf-text p { margin: 0; }
.status-nummer { font-size: 0.9375rem; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: .02em; color: var(--heading); }
.status-held {
  display: flex; align-items: center; gap: var(--abstand-3);
  margin: 0 var(--abstand-4) var(--abstand-3); padding: 14px 16px; border-radius: var(--radius-sm);
  background: var(--info-bg); color: var(--info-fg);
}
.status-held.ton-success { background: var(--success-bg); color: var(--success-fg); }
.status-held.ton-danger  { background: var(--danger-bg);  color: var(--danger-fg); }
.status-held.ton-warning { background: var(--warning-bg); color: var(--warning-fg); }
.status-held.ton-neutral { background: var(--surface-muted); color: var(--text); }
.status-held.ton-info    { background: var(--accent-soft); color: var(--accent-soft-text); }
.status-held-icon {
  flex: 0 0 auto; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  background: var(--surface); color: inherit;
}
.status-held-icon svg { width: 20px; height: 20px; }
.status-held-satz { margin: 0; font-size: 1.0625rem; font-weight: 700; line-height: 1.3; }
.status-held-unter { margin: 2px 0 0; font-size: 0.875rem; font-weight: 500; opacity: .9; }
.status-fakten {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: var(--abstand-2);
  margin: 0; padding: 0 var(--abstand-4) var(--abstand-3);
}
.status-fakten > div { padding: 10px 12px; border: 1px solid var(--rule); border-radius: var(--radius-sm); background: var(--surface); min-width: 0; }
.status-fakten dt { margin: 0 0 2px; font-size: 0.75rem; color: var(--muted); }
.status-fakten dd { margin: 0; font-size: 0.9375rem; font-weight: 600; color: var(--heading); overflow-wrap: anywhere; }
.status-block { padding: var(--abstand-3) var(--abstand-4); border-top: 1px solid var(--rule); }
.status-block h3 { margin: 0 0 var(--abstand-1); font-size: 0.9375rem; }
.status-nebenbei p { margin: 0 0 4px; font-size: 0.875rem; }
.status-nebenbei p:last-child { margin-bottom: 0; }
.status-reservationen { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.status-reservationen li { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.status-aktionen { display: flex; flex-wrap: wrap; gap: var(--abstand-2); padding: var(--abstand-3) var(--abstand-4) var(--abstand-4); border-top: 1px solid var(--rule); }
.status-liste { list-style: none; margin: 0; padding: 0; }
.status-liste a { display: flex; align-items: center; gap: var(--abstand-3); padding: 10px var(--abstand-4); border-top: 1px solid var(--rule); color: inherit; text-decoration: none; }
.status-liste a:hover { background: var(--row-hover); }
.status-liste-text { flex: 1 1 auto; display: flex; flex-direction: column; min-width: 0; }
@media (max-width: 720px) {
  .status-fakten { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .status-kopf { padding: var(--abstand-3); }
  .status-held, .status-fakten { margin-left: var(--abstand-3); margin-right: var(--abstand-3); }
  .status-fakten { padding: 0 0 var(--abstand-3); }
  .status-aktionen .btn { flex: 1 1 0; justify-content: center; }
}

/* Ratgeber (seit 22.10.2026): Fliesstext mit Beispielen und Schritten. */
.ratgeber h2 { margin-top: 2.2rem; }
.ratgeber h2:first-child { margin-top: 0; }
.ratgeber h3 { margin-top: 1.6rem; }
.ratgeber p, .ratgeber li { line-height: 1.65; }
.ratgeber p { margin: 0 0 .9em; }
.ratgeber-beispiele { display: grid; grid-template-columns: repeat(auto-fill, minmax(185px, 1fr)); gap: 10px; margin: 1.2rem 0; padding: 0; }
.ratgeber-beispiele > div { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 10px 14px; background: var(--surface); }
.ratgeber-beispiele dt { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--heading); }
.ratgeber-beispiele dd { margin: 2px 0 0; color: var(--muted); }
.ratgeber-liste { list-style: disc; padding-left: 1.3em; margin: 0 0 1em; }
.ratgeber-liste li::marker { color: var(--accent); }
.ratgeber-liste li { margin: .5em 0; }
/* Schritte mit Nummer im Kreis, wie im Handbuch. */
.ratgeber-schritte { list-style: none; counter-reset: schritt; padding: 0; margin: .4em 0 1em; }
.ratgeber-schritte li { counter-increment: schritt; position: relative; padding-left: 2.4em; margin: .7em 0; }
.ratgeber-schritte li::before {
  content: counter(schritt); position: absolute; left: 0; top: .1em;
  width: 1.7em; height: 1.7em; border-radius: 50%; display: grid; place-items: center;
  font-size: .85em; font-weight: 700; background: var(--accent); color: var(--on-accent);
}
.ratgeber-weiter { display: flex; flex-wrap: wrap; gap: 8px 24px; margin-top: 1.6rem; }

/* Geheimnisfelder vor der Passkey-Bestätigung (schritt.js, seit 22.10.2026). */
[data-schritt-gesperrt]:disabled { background: var(--surface-muted); color: var(--muted); cursor: not-allowed; opacity: .75; }
/* Die Leiste über jedem Abschnitt mit Geheimnissen (schritt.js, seit 22.10.2026):
   gesperrt mit Knopf «Mit Passkey freigeben», freigegeben für ein Speichern. */
.schritt-leiste {
  display: flex; align-items: center; justify-content: space-between; gap: 10px 14px; flex-wrap: wrap;
  margin: 0 0 16px; padding: 10px 14px; font-size: 0.875rem;
  border: 1px dashed var(--border); border-radius: var(--radius-sm);
  background: var(--surface-muted); color: var(--muted);
}
.schritt-leiste.is-frei { border-style: solid; border-color: var(--accent); background: var(--accent-soft); color: var(--accent-soft-text); }
.schritt-leiste.is-fehler { border-style: solid; border-color: var(--danger-solid); background: var(--danger-bg); }
.schritt-leiste [hidden] { display: none; }

/* Supportzugang (seit 22.10.2026): Leiste in der App und Code beim Inhaber. */
.support-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; flex-wrap: wrap; }
.support-bar form { margin: 0; }
.support-code { font-size: 2rem; font-weight: 700; letter-spacing: .12em; color: var(--heading); margin: 0; }
.support-code-eingabe { width: 12em; font-size: 1.125rem; letter-spacing: .12em; font-variant-numeric: tabular-nums; }
.support-code-eingabe::placeholder { letter-spacing: normal; font-size: 0.9375rem; }
.row > .input.input-sm { width: auto; flex: 1 1 140px; min-width: 0; height: 36px; }

/* ==========================================================================
   Berührung (seit 26.10.2026)

   Auf iPad und iPhone gibt es kein Darüberfahren. Ein angetipptes Feld
   behält dort seinen :hover-Zustand, bis man woanders tippt: Kacheln
   blieben angehoben, das Bild in der Lightbox blass. Ohne Maus heben sich
   die Flächen darum nicht, sie geben stattdessen beim Drücken nach.
   ========================================================================== */
@media (hover: none) {
  a.card-stat:hover, .tile:hover, .beratung-weg:hover, .sai-teaser:hover, .katalog-karte:hover,
  .tile:hover .tile-arrow, .sai-teaser:hover .sai-teaser-knopf > span[aria-hidden] { transform: none; }
  a[data-lightbox]:hover img { opacity: 1; }
}
a.card-stat:active, .tile:active, .beratung-weg:active, .katalog-karte:active, .sai-teaser:active {
  transform: scale(.99); transition-duration: 0s;
}
@media (prefers-reduced-motion: reduce) {
  a.card-stat:active, .tile:active, .beratung-weg:active, .katalog-karte:active, .sai-teaser:active { transform: none; }
}

/* ==========================================================================
   Fenster erscheinen weich (seit 26.10.2026)

   Rückfragen, Lightbox und Filmfenster sprangen auf, und der Grund wurde
   schlagartig dunkel. Jetzt blendet der Grund in 180 ms ab, und das
   Fenster kommt leicht vergrössert dazu. Bei «weniger Bewegung» stehen
   beide sofort da (siehe die allgemeine Regel in Abschnitt 5).
   ========================================================================== */
.dialog[open], .film-fenster[open], .lightbox[open] img {
  animation: fenster-auf .18s cubic-bezier(.2, .8, .2, 1);
}
.dialog[open]::backdrop, .film-fenster[open]::backdrop, .lightbox[open]::backdrop {
  animation: grund-auf .18s ease-out;
}
@keyframes fenster-auf { from { opacity: 0; transform: scale(.96); } }
@keyframes grund-auf { from { opacity: 0; } }

/* «Alle Geräte ansehen ›» ist der einzige Weg aus einer Kennzahlkarte und
   als Pille nur gut 24 px hoch. Am Finger bekommt sie eine unsichtbar
   grössere Tippfläche, ohne grösser auszusehen (seit 26.10.2026). */
@media (pointer: coarse) {
  a.kz-fuss { position: relative; }
  a.kz-fuss::before { content: ""; position: absolute; inset: -10px -6px; }
}
