:root{--accent:#4f46e5;--font:'Inter',system-ui,sans-serif;
  --bg:#f6f7f9;--panel:#fff;--ink:#101828;--muted:#5d6778;--line:#e6e8ec;
  /* --muted war #667085. Auf reinem Weiss reichte das (4,97:1), aber Nebentext
     steht selten auf reinem Weiss: in getoenten Tabellenzeilen, auf grauen
     Reitern und in Code-Kaesten fiel er auf 4,19 bis 4,36 und damit unter die
     4,5:1 der WCAG. Eine Stufe dunkler haelt ueberall Abstand und sieht
     gegenueber dem Fliesstext immer noch deutlich zurueckgenommen aus. */
  /* --line trennt Flaechen (Karten, Listenzeilen) und darf zart sein.
     --line-ctl umrandet alles, was man anklicken kann. Ein Knopf mit
     weissem Grund auf weisser Karte war vorher nur an einer 1,14:1-Kante
     zu erahnen — man hat schlicht nicht gesehen, dass da ein Knopf ist.
     Deshalb hier ein deutlich dunklerer Ton, plus --ctl-bg als leichte
     Fuellung, damit die Knopfform auch ohne die Kante lesbar bleibt. */
  --line-ctl:#b9c0cd;--ctl-bg:#f4f6f9;
  /* Eine einzige Radienskala fuer die gesamte Oberflaeche. Vorher standen
     hier neun verschiedene Werte zwischen 6 und 20 Pixeln nebeneinander —
     nebeneinanderliegende Elemente hatten dadurch sichtbar unterschiedlich
     runde Ecken. Vier Stufen reichen: klein (Chips, Menuepunkte), mittel
     (Knoepfe, Felder), gross (Karten) und Pille (Fortschritt, Kennzeichen). */
  --r-sm:8px;--r-md:10px;--r-lg:12px;--r-xl:16px;--r-pill:999px;
  /* Der Akzentschleier war nur im dunklen Thema definiert. Im hellen Thema
     lief damit jede Regel, die ihn als Hintergrund benutzt (ausgewaehlte
     Wahlfelder, Vorschlagslisten, Zeilen unter dem Zeiger), ins Leere und
     blieb durchsichtig — daher die glasige Kontaktliste. */
  --accent-soft:color-mix(in srgb,var(--accent) 10%,#fff);
  --radius:var(--r-lg)}
*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%;overflow:hidden;overscroll-behavior:none}
body{font-family:var(--font);background:var(--bg);color:var(--ink);font-size:14.5px;line-height:1.5}
a{color:inherit}
.link{color:var(--accent-text);text-decoration:none;font-weight:500}
.link:hover{text-decoration:underline}
/* Ein Knopf, der wie ein Textlink aussieht. Wird fuer Aktionen gebraucht,
   die das Formular abschicken muessen (Loeschen in einer Tabellenzeile) —
   ein echter Link koennte das nicht. */
.linkbtn{border:0;background:none;padding:0;font:inherit;font-weight:500;color:var(--accent-text);cursor:pointer}
.linkbtn:hover{text-decoration:underline}
.linkbtn-danger{color:#b42318}
.muted{color:var(--muted)}
.small{font-size:12.5px}
code{background:#eef0f3;padding:1px 6px;border-radius:var(--r-sm);font-size:13px}

/* Login */
.login-body{display:grid;place-items:center;min-height:100vh;background:linear-gradient(135deg,#0b1020,#1e293b)}
.login-card{background:#fff;width:360px;padding:34px;border-radius:var(--r-xl);box-shadow:0 20px 60px rgba(0,0,0,.35)}
.login-logo{width:46px;height:46px;margin:0 auto;border-radius:var(--r-xl);background:#eef2ff;color:#4f46e5;display:grid;place-items:center}
.login-card h1{margin:8px 0 2px;font-size:22px;text-align:center}
.login-sub{margin:0 0 20px;text-align:center;color:var(--muted);font-size:13px}
.login-card label{display:block;font-size:12.5px;color:var(--muted);margin-bottom:12px}
.login-card input{width:100%;margin-top:5px;padding:11px 12px;border:1px solid var(--line);border-radius:var(--r-md);font-size:14px}
.login-card button{width:100%;margin-top:6px;padding:12px;border:0;border-radius:var(--r-md);background:#4f46e5;color:#fff;font-weight:600;font-size:15px;cursor:pointer}
.alert{background:#fef2f2;color:#b42318;padding:9px 12px;border-radius:var(--r-sm);font-size:13px;margin-bottom:14px}

/* Shell */
.shell{display:grid;grid-template-columns:248px 1fr;height:100vh;overflow:hidden}
/*
 * Die Seitenleiste: Profil unten bleibt stehen, der Rest schiebt.
 *
 * Vorher schob die ganze Leiste als ein Stück. Bei vielen Menüpunkten oder auf
 * einem flachen Bildschirm wanderte damit das Profil aus dem Bild — und mit
 * ihm „Abmelden", „Profil bearbeiten" und die Helligkeit. Man musste erst
 * scrollen, um an das zu kommen, was immer da sein sollte.
 *
 * Also schiebt jetzt nur noch die Menüliste. Marke oben und Profil unten
 * stehen fest (`flex:0 0 auto`), die Leiste selbst schiebt gar nicht mehr
 * (`overflow:hidden`).
 *
 * `min-height:0` an der Liste ist der Teil, den man vergisst: ein Flex-Element
 * wird von sich aus nie kleiner als sein Inhalt. Ohne das wüchse die Liste
 * über die Leiste hinaus, statt in sich zu schieben — und das Profil wäre
 * wieder weg.
 *
 * Ohne sichtbaren Schieberegler: er säße mitten in der dunklen Fläche und
 * wäre der einzige helle Strich darin. Dass man dort schieben kann, sagt der
 * Inhalt, der am Rand abgeschnitten ist.
 */
.sidebar{background:#0f172a;color:#cbd5e1;display:flex;flex-direction:column;padding:18px 14px;height:100vh;overflow:hidden;position:sticky;top:0}
.sidebar>.brand-area,.sidebar>.side-foot{flex:0 0 auto}
.logo-mark{width:34px;height:34px;border-radius:var(--r-md);background:var(--accent);color:var(--accent-ink);display:grid;place-items:center;font-weight:700;flex-shrink:0}
.logo-img{width:34px;height:34px;border-radius:var(--r-md);object-fit:contain;background:#fff;padding:3px;flex-shrink:0}
.brand-name{font-weight:600;color:#fff;font-size:15px}
.brand-area{padding:4px 2px 14px;margin-bottom:6px;border-bottom:1px solid #1e293b}
.brand-solo{display:flex;align-items:center;gap:10px;padding:8px 6px}
.role-line{margin:10px 6px 0}
.nav{display:flex;flex-direction:column;gap:2px;flex:1 1 auto;min-height:0;
  overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:none;-ms-overflow-style:none}
.nav::-webkit-scrollbar{width:0;height:0;display:none}
.nav-item{display:flex;align-items:center;gap:11px;padding:9px 10px;border-radius:var(--r-md);color:#cbd5e1;text-decoration:none;font-weight:500;font-size:14px;transition:background .13s ease,color .13s ease}
.nav-item svg{width:18px;height:18px;opacity:.8}
.nav-item:hover{background:#1e293b;color:#fff}
.nav-item.is-active{background:var(--accent);color:var(--accent-ink)}
.nav-item.is-active svg{opacity:1}
.side-foot{border-top:1px solid #1e293b;padding-top:12px;margin-top:12px}
.role-tag{display:inline-block;font-size:10px;text-transform:uppercase;letter-spacing:.04em;background:#1e293b;color:#93c5fd;border:1px solid #334155;border-radius:var(--r-sm);padding:1px 6px;margin:2px 0 0 6px;font-weight:600}

/* Animierte Dropdowns (Firma oben + Profil unten) */
.dd{position:relative}
.dd-trigger{display:flex;align-items:center;gap:10px;width:100%;background:transparent;border:0;cursor:pointer;padding:8px;border-radius:var(--r-md);text-align:left;transition:background .13s ease}
.dd-trigger:hover{background:#1e293b}
.dd-txt,.who-txt{flex:1;min-width:0}
.dd-name,.who-name{color:#fff;font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dd-sub,.who-mail{font-size:11.5px;color:#94a3b8;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dd-caret,.who-caret{color:#94a3b8;display:inline-flex;align-items:center;flex:0 0 auto;transition:transform .18s ease}
.dd.open .dd-caret,.dd.open .who-caret{transform:rotate(180deg)}
.avatar{width:32px;height:32px;border-radius:50%;background:var(--accent);color:var(--accent-ink);display:grid;place-items:center;font-weight:600;text-transform:uppercase;flex-shrink:0;object-fit:cover}
/* Das gerechnete Standardbild trägt zwei Buchstaben statt einem — bei der
   Grundschrift stünden die zu eng am Rand. Farbe und Schriftfarbe kommen als
   Stilangabe aus R.avatarHtml und stehen deshalb hier bewusst nicht. */
.avatar-vor{font-size:12.5px;letter-spacing:.02em}
.dd-menu{position:absolute;left:0;right:0;background:#1e293b;border:1px solid #334155;border-radius:var(--r-md);padding:6px;box-shadow:0 14px 34px rgba(0,0,0,.45);z-index:30;
  opacity:0;visibility:hidden;transform:translateY(6px) scale(.98);transform-origin:top center;pointer-events:none;
  transition:opacity .16s ease,transform .16s cubic-bezier(.2,.8,.2,1),visibility .16s}
.dd-down{top:calc(100% + 6px)}
.dd-up{bottom:calc(100% + 6px);transform-origin:bottom center}
.dd.open .dd-menu{opacity:1;visibility:visible;transform:translateY(0) scale(1);pointer-events:auto}
.dd-item{display:flex;align-items:center;gap:9px;width:100%;text-align:left;padding:9px 10px;border-radius:var(--r-sm);color:#e2e8f0;text-decoration:none;font-size:13px;background:transparent;border:0;cursor:pointer}
.dd-lbl{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dd-mark{margin-left:auto;flex:0 0 auto;color:#93c5fd}
.dd-item:hover .dd-mark{color:inherit}
.dd-item:hover{background:var(--accent);color:var(--accent-ink)}
.dd-item.is-cur{color:#93c5fd;font-weight:600}
/* Bestimmt die Adresse die Firma, führt der Eintrag auf deren eigene Adresse
   statt auf ein wirkungsloses Formular (siehe lib/render.js). Die Adresse steht
   mit im Eintrag: sonst sieht man erst nach dem Klick, wo man landet — und dort
   steht eine Anmeldemaske. */
.dd-hin{flex:0 0 auto;font-size:11px;opacity:.55}
.dd-fuss{padding:9px 10px 3px;margin-top:4px;border-top:1px solid #334155;font-size:11px;line-height:1.45;color:#94a3b8}
span.dd-item{cursor:default}
.dd-item.is-aus{opacity:.5}
.dd-item.is-aus:hover::before,span.dd-item:hover::before{clip-path:circle(0% at 50% 50%)}
.dd-item.is-aus:hover,span.dd-item:hover{background:transparent;color:#e2e8f0}
span.dd-item.is-cur:hover{color:#93c5fd}
.dd form{margin:0}
/* Profilknopf unten links, wenn man sich gerade auf einer Seite aus dem
   Profilmenue befindet (z.B. /profile). Dieselbe Akzentflaeche wie ein
   aktiver Menuepunkt oben — so ist immer genau eine Stelle in der Leiste
   markiert, und zwar die richtige. Der Avatar traegt selbst die Akzentfarbe
   und wuerde in der Flaeche verschwinden, darum dreht er sich hier um. */
.who.is-active,.who.is-active:hover{background:var(--accent)}
.who.is-active .who-name,.who.is-active .who-mail,.who.is-active .who-caret{color:var(--accent-ink)}
.who.is-active .who-mail{opacity:.8}
.who.is-active .avatar{background:var(--accent-ink);color:var(--accent)}

/* Main */
.main{padding:26px 30px;height:100vh;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column}
/* Volle Breite nutzen – nur sehr breite Monitore bekommen ein Maximum,
   damit Fliesstext nicht ueber 2000px laeuft. */
.main>*{max-width:none;width:100%}
/* .main ist eine Spalte mit fester Hoehe. Ein Flex-Element darf darin
   normalerweise nicht unter seinen Inhalt schrumpfen — diese Sperre gilt aber
   nur, solange `overflow:visible` ist. Alles, was hier `overflow` setzt,
   verliert sie und wird zusammengedrueckt: .klappk stand deshalb als 2 Pixel
   hohe Linie da, mit einer Kopfzeile, die man weder sah noch anklicken
   konnte. Darum steht es hier mit in der Reihe. */
.main>.crm-cols,.main>.grid-2,.main>.klappk{flex:0 0 auto}
@media(min-width:2100px){.main{align-items:center}.main>*{max-width:2000px}}

/*
 * ── Eine Seite, die aus EINEM Bereich besteht ──────────────────────────────
 *
 * Manche Seiten sind keine Liste von Karten untereinander, sondern ein
 * einziger Bereich, der den Platz fuellt und in sich schiebt: der Kalender
 * ist der Fall. Dort schoben bisher ZWEI Ebenen uebereinander — `.main` und
 * der Bereich darin. Welche man gerade erwischt, haengt davon ab, wo der
 * Mauszeiger steht, und das ist der Grund, warum es sich falsch anfuehlt: das
 * Rad tut mal das eine und mal das andere.
 *
 * Die Seite sagt es selbst, indem sie ihren fuellenden Block `fuellt` nennt.
 * `.main` hoert darauf und schiebt dann gar nicht mehr; uebrig bleibt genau
 * ein Schiebebereich.
 *
 * `min-height:0` ist der Teil, den man vergisst: ein Flex-Element wird von
 * sich aus nie kleiner als sein Inhalt. Ohne das wuechse der Block ueber
 * `.main` hinaus, statt in sich zu schieben.
 *
 * WAS DAS ABLOEST
 * ──────────────
 *
 * Vorher hat app.js gemessen, wie viel Platz bis zum unteren Fensterrand
 * uebrig ist, und das Ergebnis als `--kal-hoehe` ins Stilattribut geschrieben.
 * Das funktionierte, war aber empfindlich: eine Animation mit
 * `clearProps:'all'` hat genau dieses Attribut mitsamt der Variablen
 * weggeraeumt, und der Kalender sprang eine Sekunde nach dem Laden auf zwei
 * Drittel zusammen. Kein Fehler in der Konsole — eine geloeschte CSS-Variable
 * sieht aus wie eine, die es nie gab.
 *
 * Flexbox rechnet dasselbe aus, ohne dass jemand misst, und es gibt nichts,
 * was ein Dritter versehentlich loeschen koennte.
 *
 * `:has()` und kein zweiter Klassenname an `.main`: die Seite soll EINE Sache
 * sagen muessen, nicht zwei, die zueinander passen. Und wo `:has()` fehlt —
 * Browser vor 2023 —, faellt es auf den heutigen Zustand zurueck: `.main`
 * schiebt weiter. Unschoen, aber nicht kaputt.
 *
 * Nur am breiten Schirm. Am Telefon schiebt die ganze Seite, und ein
 * Schiebebereich darin waere dort die eigentliche Zumutung — Begruendung
 * unten beim Kalender.
 */
@media(min-width:1101px){
  .main:has(>.fuellt){overflow:hidden}
  /* Die zweite Regel ist fuer die Kontaktseite: dort steht die Listenkarte in
     einem <form> (die Sammelaktionen brauchen es). Ohne Durchreichen bekam die
     Karte keine Hoehe, die Liste wuchs wieder ueber den Bildschirm hinaus und
     die Sammelleiste war beim Auswaehlen wieder weg — genau der Fehler, den
     das hier abstellen soll. */
  .main>.fuellt,.fuellt>.fuellt{flex:1 1 auto;min-height:0}

  /*
   * ── Eine Listenkarte: Kopf bleibt, Liste schiebt ──
   *
   * Bisher schob die ganze Seite, und mit ihr wanderten Suchleiste,
   * Sammelaktionen und Reiter aus dem Bild. Wer in Zeile 200 einen Knopf von
   * oben braucht, musste erst wieder hoch und danach wieder hinunter.
   *
   * Was schiebt, sagt die Seite selbst — `R.listenbereich()` in lib/render.js
   * umschliesst genau den Teil. Alles davor in der Karte bleibt stehen, und
   * die Reiter ueber der Karte ohnehin: sie sind Navigation und nicht Inhalt.
   *
   * `min-height:0` an jeder Ebene der Kette, sonst schiebt nichts, sondern der
   * Block waechst ueber die Karte hinaus.
   */
  /* Zwei Ausfuehrungen desselben Bauteils: die Listenkarte (eine Tabelle
     darin) und der freie Block. Den freien Block braucht die Vorlagenseite —
     sie reiht selbst Karten auf, und eine Karte um Karten waere ein zweiter
     Rahmen um denselben Inhalt.
     Warum nicht schlicht `.fuellt`: die Kalenderflaeche traegt dieselbe Marke,
     ist aber nebeneinander gesetzt. Ein `flex-direction:column` fuer alle
     haette sie ohne Vorwarnung untereinander geworfen. */
  .fuellt:is(.card,.liste-frei,form){display:flex;flex-direction:column;overflow:hidden}
  .card.fuellt{margin-bottom:0}
  .fuellt:is(.card,.liste-frei)>.listen-scroll{flex:1 1 auto;min-height:0;
    overflow:auto;overscroll-behavior:contain}

  /* Innen wird nicht noch einmal geschoben. `.tblwrap` bekommt von app.js
     einen eigenen waagerechten Bereich — hier uebernimmt der Listenbereich
     beide Richtungen, sonst haette man zwei Leisten fuer dieselbe Bewegung. */
  .listen-scroll .tblwrap{overflow:visible}

  /* Die Kopfzeile bleibt an der Oberkante des schiebenden Bereichs stehen.
     Ohne Hintergrund waeren die Zeilen darunter durchgeschienen; die Linie
     kommt als Innenschatten, weil ein `border-bottom` an einer klebenden
     Zelle beim Schieben mitwandert und dabei flimmert. */
  .listen-scroll .tbl thead th{position:sticky;top:0;z-index:2;
    background:var(--panel);box-shadow:inset 0 -1px 0 var(--line)}
}
.pagehead{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:20px;gap:16px}
.pagehead h1{margin:0;font-size:24px}
.pagehead p{margin:3px 0 0;color:var(--muted);font-size:13.5px}
.head-actions{display:flex;gap:8px;flex-shrink:0;align-items:center;flex-wrap:wrap}
.head-chan{display:inline-flex;align-items:center;margin-right:2px}

/* Cards & layout */
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;margin-bottom:18px}
/* Dauerhaft sichtbarer Erklaerkasten (R.help). Farbe kommt aus der Akzentfarbe,
   aber stark aufgehellt, damit der Text darauf sicher lesbar bleibt. */
.helpbar{display:flex;gap:10px;align-items:flex-start;background:color-mix(in srgb,var(--accent) 7%,var(--panel));
  border:1px solid color-mix(in srgb,var(--accent) 24%,var(--line));border-left:3px solid var(--accent);
  border-radius:var(--radius);padding:12px 14px;margin-bottom:16px}
.helpbar p{margin:0;font-size:13.5px;line-height:1.55;color:var(--text)}
.helpbar-ic{flex:0 0 auto;width:18px;height:18px;margin-top:1px;color:var(--accent-text)}
.card h3{margin:0 0 14px;font-size:15px}
/* Zwischenüberschrift innerhalb einer Karte (z. B. Postfächer je Abschnitt) */
.card h4{margin:22px 0 10px;font-size:13px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
/* Trennlinie zwischen gleichartigen Blöcken (mehrere Postfächer untereinander) */
hr.sep{border:0;border-top:1px solid var(--line);margin:18px 0}
/* minmax(0,…) statt 1fr: "1fr" heisst genau genommen minmax(auto,1fr) — die
   Spalte waechst notfalls bis zur Mindestbreite ihres Inhalts. Eine breite
   Tabelle in einer Karte zog damit auf dem Telefon das ganze Raster
   auseinander, und die Seite liess sich seitlich schieben, obwohl die Tabelle
   laengst einen eigenen Schiebebereich hat. */
.grid-2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:18px}
.grid-2>*{min-width:0}
.gap{gap:12px}
@media(max-width:900px){.grid-2{grid-template-columns:minmax(0,1fr)}.shell{grid-template-columns:1fr;height:auto;overflow:visible}.sidebar{position:static;height:auto;overflow:visible}.main{height:auto;overflow:visible}
}
.mt{margin-top:14px}

/* Stats */
.stats-row{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:18px}
@media(max-width:900px){.stats-row{grid-template-columns:1fr 1fr}}
.stat{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px}
.stat-val{font-size:28px;font-weight:700}
.stat-label{color:var(--muted);font-size:13px;margin-top:2px}
.stat-sub{color:var(--muted);font-size:11.5px;margin-top:1px}

/* Table */
.tbl{width:100%;border-collapse:collapse;font-size:14px}
.tbl th{text-align:left;font-weight:600;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.03em;padding:8px 10px;border-bottom:1px solid var(--line)}
.tbl td{padding:10px;border-bottom:1px solid var(--line);vertical-align:middle}
.tbl tr:last-child td{border-bottom:0}

/* Badges */
.badge{display:inline-block;padding:2px 9px;border-radius:var(--r-pill);font-size:12px;font-weight:600}
.badge-gray{background:#eef0f3;color:#475467}
.badge-blue{background:#eaf0ff;color:#3b5bdb}
.badge-green{background:#e6f6ec;color:#177245}
.badge-amber{background:#fef3e2;color:#9a5108}
.badge-red{background:#fdecec;color:#c0362c}
/* Zustandsmeldung ueber mehrere Zeilen. Die Pille daneben bleibt, wofuer sie
   gedacht ist: ein Wort. */
.zustand{display:flex;gap:9px;align-items:flex-start;padding:10px 13px;border-radius:var(--r-md);
  font-size:13px;line-height:1.5;border:1px solid var(--line);background:var(--ctl-bg);color:var(--text)}
.zustand svg{flex:0 0 auto;margin-top:2px}
.zustand-green{border-color:#a7d8b4;background:#f0fbf3;color:#14532d}
.zustand-amber{border-color:#fcd9a4;background:#fff8ee;color:#8a4b06}
.zustand-red{border-color:#f4b7b1;background:#fdf1f0;color:#a32b21}
html[data-theme="dark"] .zustand{background:#151c29;border-color:#2a3446;color:#e2e8f0}
html[data-theme="dark"] .zustand-green{background:#12271c;border-color:#2f5c3f;color:#a7e8bd}
html[data-theme="dark"] .zustand-amber{background:#2a2113;border-color:#6b4d1c;color:#f3cf94}
html[data-theme="dark"] .zustand-red{background:#2a1618;border-color:#6b2f2f;color:#f0b4ae}

/* Buttons */
.btn{position:relative;isolation:isolate;display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;padding:9px 14px;border-radius:var(--r-md);border:1px solid var(--line-ctl);background:var(--ctl-bg);color:var(--ink);font-weight:600;font-size:13.5px;cursor:pointer;text-decoration:none;line-height:1.2;--fill:#e2e7ef;
  transition:transform .22s cubic-bezier(.2,.8,.2,1),box-shadow .2s ease,color .2s ease}
/* Hier stand `will-change:transform` ohne Bedingung — und damit auf JEDEM
   Knopf der Seite. Das ist keine Kleinigkeit: die Angabe hebt das Element
   dauerhaft und im Voraus auf eine eigene Ebene im Compositor. Auf der
   Kalenderseite waren das gut zwei Dutzend Ebenen, auf einem Retina-Schirm mit
   der vierfachen Pixelzahl. Chrome warnt ausdruecklich davor, das breit zu
   streuen; gedacht ist es fuer den Einzelfall, nicht als Grundzustand.
   Ersatzlos gestrichen und nicht etwa auf `:hover` verschoben: bei einer
   Knopfreihe wuerde dabei im Vorbeifahren ein Dutzend Mal eine Ebene angelegt
   und wieder verworfen — vom Regen in die Traufe. Gebraucht wird sie ohnehin
   nicht: eine Ueberblendung von `transform` laeuft im Compositor, und die
   Ebene dafuer legt der Browser von sich aus an, solange sie laeuft. */
/* Magnetische Farbausbreitung ab Mausposition (--mx/--my via JS); durch border-radius sauber begrenzt */
.btn::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:var(--fill);
  clip-path:circle(0% at var(--mx,50%) var(--my,50%));transition:clip-path .5s cubic-bezier(.2,.8,.2,1)}
.btn:hover{box-shadow:0 6px 18px rgba(16,24,40,.14)}
.btn:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.btn:active{transform:scale(.97)!important}
.btn-primary{background:var(--accent);color:var(--accent-ink);border-color:transparent;--fill:var(--accent-hover)}
.btn-primary:hover{color:var(--accent-hover-ink);box-shadow:0 8px 22px color-mix(in srgb,var(--accent) 42%,transparent)}
/* gleiche Magnet-/Fülleffekte auch für Tabs und Dropdown-Items */
.tab{position:relative;isolation:isolate}
.tab::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:var(--accent-soft);clip-path:circle(0% at var(--mx,50%) var(--my,50%));transition:clip-path .45s cubic-bezier(.2,.8,.2,1)}
.tab:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.tab.is-active::before{display:none}
/* Aktionsreihen sauber ausgerichtet */
.btnrow{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
/* Gestylte Selects (native Selects werden per JS ersetzt) */
.selectx{position:relative;display:block;margin-top:5px}
.selectx.inline{display:inline-block;margin-top:0}
.selectx-native{display:none}
.selectx>select{display:none}
.selectx-btn{width:100%;justify-content:space-between;gap:10px;font-weight:500;background:#fff;border-color:var(--line-ctl)}
.selectx.inline .selectx-btn{width:auto}
.selectx-caret{color:var(--muted);display:inline-flex;align-items:center;flex:0 0 auto;transition:transform .2s ease}
.selectx.open .selectx-caret{transform:rotate(180deg)}
/* Am Fenster ausgerichtet und nicht am Knopf: eine Auswahl in einer breiten
   Tabelle steckt sonst in deren Schiebebereich fest und verschwindet darunter.
   Ort und Breite setzt das Skript beim Oeffnen; z-index bleibt hoch, damit es
   auch ueber einem Fenster liegt. */
/* Kein `min-width:100%` mehr: bei `position:fixed` bezieht sich Prozent auf
   das Fenster, und das Menue waere so breit wie der Bildschirm. Die Breite
   setzt das Skript aus dem Knopf. */
.selectx-menu{position:fixed;background:#fff;border:1px solid var(--line);border-radius:var(--r-md);padding:5px;box-shadow:0 14px 34px rgba(16,24,40,.16);z-index:400;max-height:280px;overflow:auto;
  opacity:0;visibility:hidden;transform:translateY(6px) scale(.98);transform-origin:top;pointer-events:none;transition:opacity .16s ease,transform .16s cubic-bezier(.2,.8,.2,1),visibility .16s}
.selectx.open .selectx-menu{opacity:1;visibility:visible;transform:translateY(0) scale(1);pointer-events:auto}
.selectx-item{display:block;width:100%;text-align:left;padding:9px 11px;border:0;background:transparent;border-radius:var(--r-sm);cursor:pointer;font-size:13.5px;color:var(--ink);white-space:nowrap;position:relative;isolation:isolate;overflow:hidden}
.selectx-item::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:var(--accent-soft);clip-path:circle(0% at var(--mx,50%) var(--my,50%));transition:clip-path .4s cubic-bezier(.2,.8,.2,1)}
.selectx-item:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.selectx-item.sel{color:var(--accent-text);font-weight:600}

/* Autosave: Speicherbutton ausblenden, Status zeigen */
form[data-autosave] button.btn-primary{display:none}
.autosave-status{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;color:var(--muted);margin-top:4px}
.autosave-status.saving{color:var(--muted)}
.autosave-status.saved{color:#177245}
.autosave-status.err{color:#c0362c}
/* Ergebnisfeld der Prüf-Buttons: die Antwort erscheint an Ort und Stelle,
   die Seite springt nicht mehr nach oben. Leer nimmt es keinen Platz weg. */
.probe-out:empty{display:none}
.probe-out>.badge{display:inline-block}
.btn.busy{opacity:.65;pointer-events:none}
/* Auszug einer gefundenen Rechtsseite: umbrechend, damit lange Absaetze die
   Karte nicht seitlich aufreissen. */
.pre-wrap{white-space:pre-wrap;background:#f8f9fb;border:1px solid var(--line);border-radius:var(--r-sm);padding:10px;max-height:260px;overflow:auto;margin:6px 0 0}
/* Dropdown-Trigger: gleicher Magnet-Fülleffekt wie Buttons */
.dd-trigger{overflow:hidden;--fill:#243244;transition:transform .22s cubic-bezier(.2,.8,.2,1),box-shadow .2s ease}
.dd-trigger::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:var(--fill);clip-path:circle(0% at var(--mx,50%) var(--my,50%));transition:clip-path .5s cubic-bezier(.2,.8,.2,1)}
.dd-trigger:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.chip,.proflink{overflow:hidden}
.chip::before,.proflink::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:var(--accent);clip-path:circle(0% at var(--mx,50%) var(--my,50%));transition:clip-path .45s cubic-bezier(.2,.8,.2,1)}
.chip:hover::before,.proflink:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.chip,.proflink{position:relative;isolation:isolate}
/* Nav-Items & Dropdown-Menüpunkte: gleicher Magnet-Fülleffekt */
.nav-item{position:relative;isolation:isolate;overflow:hidden;transition:color .13s ease,transform .22s cubic-bezier(.2,.8,.2,1)}
.nav-item::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:#1e293b;clip-path:circle(0% at var(--mx,50%) var(--my,50%));transition:clip-path .5s cubic-bezier(.2,.8,.2,1)}
.nav-item:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.nav-item.is-active::before{display:none}
.dd-item{position:relative;isolation:isolate;overflow:hidden;transition:color .13s ease,transform .18s cubic-bezier(.2,.8,.2,1)}
.dd-item::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:var(--accent);clip-path:circle(0% at var(--mx,50%) var(--my,50%));transition:clip-path .45s cubic-bezier(.2,.8,.2,1)}
.dd-item:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
/* Tabs bekommen auch die leichte Magnet-Annäherung (Transform via JS) */
.tab{transition:color .13s ease,background .13s ease,transform .22s cubic-bezier(.2,.8,.2,1)}
/* Drag-and-drop-Upload */
.dropzone{position:relative;border:2px dashed var(--line-ctl);border-radius:var(--r-lg);background:#f8f9fb;margin:6px 0 4px;transition:border-color .15s ease,background .15s ease}
.dropzone:hover,.dropzone.drag{border-color:var(--accent);background:var(--accent-soft)}
.dz-input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}
.dz-inner{display:flex;align-items:center;justify-content:center;gap:10px;padding:18px 16px;color:var(--muted);font-size:13.5px;pointer-events:none;text-align:center;flex-wrap:wrap}
.dz-ic{color:var(--accent-text)}
.dz-file{font-weight:600;color:var(--ink)}
.btn-sm{padding:6px 11px;font-size:12.5px}

/* Forms */
label{display:block;font-size:13px;margin-bottom:12px}
/*
 * Alle Eingabefelder, nicht nur die, an die jemand gedacht hat.
 *
 * Hier stand eine Aufzaehlung: text, email, password, number. Alles andere —
 * Datum, Uhrzeit, Suche, Telefon — sah aus wie vom Browser mitgeliefert und
 * damit wie aus einem anderen Werkzeug. Aufgefallen ist es bei den
 * Gutscheinen („Gueltig ab" und die Codesuche), aber es betraf jede Stelle
 * mit einem Datumsfeld.
 *
 * Jetzt andersherum: alles ist ein Eingabefeld, ausser den Faellen, die
 * ihre eigene Form haben (Haken, Auswahlknopf, Farbe, Datei, Regler) oder
 * gar keine Eingabe sind (Knoepfe). Eine Ausnahmeliste vergisst man einmal
 * und merkt es sofort; eine Positivliste vergisst man staendig und merkt es
 * erst, wenn ein Feld schief aussieht.
 *
 * Die Ausnahmen stehen in :where() und das ist der Punkt, an dem es beim
 * ersten Anlauf schiefging. Neun :not() mit je einem Attributwaehler darin
 * ergeben ein Gewicht von (0,9,1) — damit schlug diese eine Regel jede
 * spaetere Feinheit: .suche-feld verlor seinen linken Abstand, und die Lupe
 * lag ploetzlich auf dem Platzhaltertext. :where() zaehlt null, also wiegt
 * die Regel wie ein blosses `input` und laesst sich ueberall ueberschreiben,
 * ohne dass jemand !important schreiben muss.
 */
input:where(:not([type=checkbox]):not([type=radio]):not([type=color]):not([type=file]):not([type=range]):not([type=submit]):not([type=button]):not([type=image]):not([type=hidden])),
select,textarea{
  width:100%;margin-top:5px;padding:9px 11px;border:1px solid var(--line-ctl);border-radius:var(--r-md);font-size:14px;font-family:inherit;background:#fff;color:var(--ink)}
/* Das kleine Kalender-/Uhr-Symbol im Feld ist im dunklen Modus sonst schwarz
   auf dunkel und praktisch unsichtbar. */
html[data-theme="dark"] input::-webkit-calendar-picker-indicator{filter:invert(1) opacity(.6)}
html[data-theme="dark"] input::-webkit-calendar-picker-indicator:hover{filter:invert(1) opacity(1)}
textarea{resize:vertical}
.inline-form{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px}
.inline-form input,.inline-form select{width:auto;margin-top:0}
.filterbar{display:flex;gap:8px;align-items:center;margin-bottom:14px}
.filterbar select{width:auto;margin-top:0}
.bulkbar{display:flex;gap:10px;align-items:center;margin-bottom:12px}
.bulkbar select{width:auto;margin-top:0}
.colorrow{display:flex;gap:8px;align-items:center;margin-top:5px}
.colorrow input[type=color]{width:44px;height:38px;padding:2px;margin-top:0}
.hex{width:110px!important;margin-top:0!important}
.logo-preview img{max-height:48px;margin:6px 0}
.logo-preview{margin-bottom:10px}
fieldset.perms{border:1px solid var(--line);border-radius:var(--r-md);padding:12px 14px;margin-bottom:14px}
fieldset.perms legend{font-size:12px;color:var(--muted);padding:0 6px}
.chk{display:inline-flex;align-items:center;gap:6px;margin:4px 14px 4px 0;font-size:13.5px}
.chk input{width:auto;margin:0}
.permgrid{display:grid;grid-template-columns:1fr 1fr;gap:6px 18px}
@media(max-width:640px){.permgrid{grid-template-columns:1fr}}
.permrow{display:flex;align-items:flex-start;gap:9px;margin:0;padding:7px 8px;border-radius:var(--r-sm);font-size:13px}
.permrow:hover{background:var(--accent-soft)}
.permrow input{width:auto;margin:2px 0 0}
.permrow span{display:flex;flex-direction:column}
.permrow em{font-style:normal;color:var(--muted);font-size:11.5px}
.permrow input:disabled + span{opacity:.5}

/* Misc */
/* Unterpunkte in der Seitenleiste. Sie sitzen eingerueckt unter ihrem
   Hauptpunkt und tragen eine Fuehrungslinie — ohne die schwebt die Gruppe
   frei und liest sich wie eine zweite Menueebene ohne Zugehoerigkeit. */
.nav-unter{display:flex;flex-direction:column;gap:1px;margin:2px 0 6px 20px;
  padding-left:11px;border-left:1px solid #26364b}
.nav-sub{display:block;padding:6px 10px;border-radius:var(--r-sm);text-decoration:none;
  color:#94a3b8;font-size:13px;font-weight:500;transition:background .13s ease,color .13s ease}
.nav-sub:hover{background:#1e293b;color:#fff}
.nav-sub.is-active{color:#fff;background:#1e293b;font-weight:600}

/* Dieselbe Gliederung noch einmal als Reiterzeile auf der Seite. Am Telefon,
   wo die Seitenleiste zugeklappt ist, ist sie der einzige Weg zwischen den
   Unterseiten — deshalb schiebt sie dort seitlich statt umzubrechen. */
/* Untertabs sind Knöpfe. Sie waren einmal eine eigene Form mit eigenem
   Radius und eigenem Rand — und standen damit als einziges Element auf der
   Seite außerhalb der Formensprache, in der alles andere gebaut ist. Jetzt
   erben sie sie: dieselbe Höhe, derselbe Radius, dieselben Ränder, dieselbe
   Hervorhebung für den offenen Bereich wie bei einem primären Knopf. */
.untertabs{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 18px;align-items:center}
.untertab{position:relative;isolation:isolate;display:inline-flex;align-items:center;gap:8px;
  padding:8px 14px;border-radius:var(--radius);border:1px solid var(--line-ctl,var(--line));
  background:var(--ctl-bg,#fff);color:var(--text);font-size:13.5px;font-weight:500;
  text-decoration:none;will-change:transform;
  transition:transform .22s cubic-bezier(.2,.8,.2,1),border-color .15s ease,color .15s ease,
    background .15s ease,box-shadow .15s ease}
/* Dieselbe magnetische Füllung wie bei den Knöpfen: sie breitet sich von der
   Mausposition aus und wird vom Radius sauber beschnitten. */
.untertab::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;
  background:var(--accent-soft);clip-path:circle(0% at var(--mx,50%) var(--my,50%));
  transition:clip-path .45s cubic-bezier(.2,.8,.2,1)}
.untertab:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.untertab.is-active::before{display:none}
.untertab:active{transform:scale(.97)!important}
.untertab svg{width:16px;height:16px;opacity:.7}
.untertab:hover{border-color:var(--accent);color:var(--accent)}
.untertab:hover svg{opacity:1}
.untertab.is-active{background:var(--accent);color:var(--accent-ink);border-color:transparent;
  box-shadow:0 4px 14px rgba(0,0,0,.12)}
.untertab.is-active svg{opacity:1}

/* Reiterleisten sitzen jetzt in derselben Form wie die Untertabs und die
   Knöpfe: gleicher Radius, gleiche Höhe, gleiche Hervorhebung. Vorher waren
   es drei Formensprachen auf einer Seite. */
.tabs{display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap;align-items:center}
/* `transform` muss in der Überblendung stehen bleiben — sonst springt der
   Magneteffekt, statt zu gleiten. Genau das war passiert: eine neuere Regel
   hatte die Überblendung ersetzt und `transform` dabei stillschweigend
   herausgeworfen. */
.tab{padding:8px 14px;border-radius:var(--radius);text-decoration:none;color:var(--text);
  font-weight:500;font-size:13.5px;background:var(--ctl-bg);border:1px solid var(--line-ctl);
  will-change:transform;
  transition:transform .22s cubic-bezier(.2,.8,.2,1),border-color .15s ease,color .15s ease,
    background .15s ease,box-shadow .15s ease}
.tab:hover{border-color:var(--accent);color:var(--accent)}
.tab.is-active{background:var(--accent);color:var(--accent-ink);border-color:transparent;
  box-shadow:0 4px 14px rgba(0,0,0,.12)}
.feed{list-style:none;margin:0;padding:0}
.feed li{display:flex;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid var(--line);font-size:13.5px}
.feed li:last-child{border-bottom:0}
.feed time{color:var(--muted);font-size:12px;white-space:nowrap}
.kv{width:100%;border-collapse:collapse}
.kv td{padding:7px 0;border-bottom:1px solid var(--line);font-size:13.5px}
.kv td:first-child{color:var(--muted);width:38%}
.tpl-head{display:flex;justify-content:space-between;align-items:center}
.tpl-body{background:#f8f9fb;border:1px solid var(--line);border-radius:var(--r-sm);padding:12px;white-space:pre-wrap;font-size:13px;margin:0;font-family:ui-monospace,monospace}
dialog{border:0;border-radius:var(--r-xl);padding:0;box-shadow:0 30px 80px rgba(0,0,0,.3);max-width:560px;width:92%}
dialog::backdrop{background:rgba(15,23,42,.5)}
/*
 * Ein Formularfenster schiebt IN SICH, und Titel und Knopfreihe bleiben.
 *
 * Vorher gab es weder eine Hoehenbegrenzung noch einen inneren
 * Schiebebereich: gescrollt wurde das ganze <dialog> ueber den Grundstil des
 * Browsers. Am laengsten Fall — „Mitglied hinzufuegen" mit fuenf Feldern, dem
 * Gruppenfeld und zwei Kaestchenblocken — waren „Hinzufuegen" und „Abbrechen"
 * erst nach dem Durchscrollen des gesamten Inhalts sichtbar. Und sobald man
 * in ein Feld tippte, schob die Tastatur sie zusaetzlich weg.
 *
 * Der Kalender macht es an derselben Stelle richtig vor (`.kf-leib` weiter
 * unten). Hier steht dasselbe Muster, nur allgemein: Kopf und Fuss stehen,
 * die Mitte schiebt.
 *
 * `dvh` und nicht `vh` — aus demselben Grund wie beim Assistentenfenster: am
 * Telefon ist `100vh` die grosse Ansichtshoehe ohne Adressleiste.
 */
dialog{max-height:min(88dvh,760px)}
/* Das Fenster selbst schiebt, und Titel und Knopfreihe kleben darin fest.
   Nicht jeder Block einzeln: `overflow` an jedem Kind haette jedem Feld
   seine eigene Bildlaufleiste gegeben. Sticky wirkt innerhalb des
   schiebenden Elternteils — genau das ist hier `.modal`. */
.modal{padding:22px 24px;overflow-y:auto;max-height:inherit}
.modal h3{margin:0 0 14px;font-size:17px;
  position:sticky;top:-22px;z-index:2;background:var(--panel);padding:22px 0 8px;margin-top:-22px}
.modal-foot{display:flex;justify-content:flex-end;gap:8px;margin-top:8px;
  position:sticky;bottom:-22px;z-index:2;background:var(--panel);
  padding:12px 0 22px;margin-bottom:-22px;border-top:1px solid var(--line)}
/* Vorschau einer hochgeladenen Datei. Breiter als ein Formulardialog, weil
   hier ein Bild zu sehen sein soll und kein Text zu lesen. */
dialog.vorschau{max-width:min(900px,94vw);width:auto}
.vorschau-kopf{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:12px 16px;border-bottom:1px solid var(--line);background:var(--card-bg)}
.vorschau-leib{padding:16px;display:flex;align-items:center;justify-content:center;background:var(--ctl-bg)}
.vorschau-leib img{display:block;max-width:100%;max-height:70vh;border-radius:var(--r-sm)}
.vorschau-leib video{display:block;max-width:100%;max-height:70vh;border-radius:var(--r-sm);background:#000}
.vorschau-leib audio{width:min(520px,80vw)}
.vorschau-ton{padding:26px 20px}
details summary{cursor:pointer;display:inline-block;list-style:none}
details summary::-webkit-details-marker{display:none}

.login-legal{margin-top:16px;text-align:center;font-size:12px;color:#98a2b3}
.login-legal a{color:#98a2b3}
.ai-row{display:flex;gap:8px;align-items:center;margin-bottom:6px}
.ai-row input{margin-top:0}
.avatar.big{width:56px;height:56px;font-size:22px}
/* Variablen-Chips */
.varchips{display:flex;flex-wrap:wrap;gap:6px;margin:2px 0 8px}
/* Die Schriftfarbe war frueher die Akzentfarbe. Weil der Akzent frei
   waehlbar ist, konnte das Ergebnis alles zwischen gut lesbar und 3,7:1
   sein — bei Rosa auf hellem Grund war es unlesbar. Jetzt traegt die
   Kante den Akzent, der Text bleibt auf der sicheren Textfarbe. */
.chip{border:1px solid color-mix(in srgb,var(--accent) 42%,var(--line-ctl));background:var(--ctl-bg);color:var(--ink);border-radius:var(--r-pill);padding:4px 11px;font-size:12.5px;font-weight:600;cursor:pointer;font-family:ui-monospace,monospace;transition:all .13s ease}
.chip:hover{background:var(--accent);color:var(--accent-ink);transform:translateY(-1px)}
.chip-spin{color:var(--muted)}
.stars{color:#f59e0b;font-size:14px;letter-spacing:1px}
/* Frueher stand hier `.stars .muted`. Das sollte die leeren Sterne treffen,
   erwischte aber auch den Ersatztext „zu wenig Daten“ — die Vorlagenliste
   verpackt das Ergebnis von stars() noch einmal in ein .stars, also landete
   grauer Fuellstern-Ton auf normalem Text (dunkel gemessene 1,52:1).
   Zustaendig fuer leere Sterne ist .star-off, und nur das. */
.stars .star-off{color:#e6e8ec}
.tpl-perf{margin-top:8px}
.owner-warn{display:flex;gap:10px;align-items:center;background:#fff7ed;border:1px solid #fed7aa;color:#9a3412;border-radius:var(--r-md);padding:11px 14px;margin-bottom:16px;font-size:13.5px}
/* CRM Kundenprofil */
.rowlink{cursor:pointer;transition:background .12s ease}
.rowlink:hover{background:var(--accent-soft)}
/* CRM 3-Spalten mit mobil aufklappbaren Karten */
.crm-cols{display:grid;grid-template-columns:minmax(300px,1.05fr) minmax(320px,1.25fr) minmax(300px,1fr);gap:18px;align-items:stretch;width:100%}
.crm-cols>.col-card{display:flex;flex-direction:column;margin-bottom:0;min-width:0}
.crm-cols .col-body{flex:1 1 auto;min-width:0}
@media(max-width:1400px){.crm-cols{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}
@media(max-width:1100px){.crm-cols{grid-template-columns:minmax(0,1fr)}}
.col-card{padding:0;overflow:hidden}
.col-head{display:flex;align-items:center;justify-content:space-between;width:100%;background:transparent;border:0;padding:16px 20px;cursor:default;text-align:left}
.col-head h3{margin:0;font-size:15px}
.col-caret{display:none;color:var(--muted);transition:transform .2s ease}
.col-body{padding:0 20px 18px}
.fieldcol label{display:block}
.subhd{margin:0 0 10px;font-size:14px}
@media(max-width:1100px){
  .col-head{cursor:pointer}
  .col-caret{display:inline-flex}
  .col-card.open .col-caret{transform:rotate(45deg)}
  .col-body{display:none}
  .col-card.open .col-body{display:block}
}
.profile-head{display:flex;gap:16px;align-items:center;margin-bottom:12px}
.profile-name{font-size:20px;font-weight:700}
.profile-badges{margin-top:6px;display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.proflinks{display:flex;flex-wrap:wrap;gap:8px;padding:12px 0;border-top:1px solid var(--line)}
.proflink{display:inline-flex;align-items:center;gap:6px;background:var(--accent-soft);color:var(--accent-text);border-radius:var(--r-sm);padding:7px 12px;text-decoration:none;font-weight:600;font-size:13px;transition:all .13s ease}
.proflink:hover{background:var(--accent);color:var(--accent-ink);transform:translateY(-1px)}
.avatar.tiny{width:24px;height:24px;font-size:11px;display:inline-grid;vertical-align:middle}
/* Notizen & To-dos */
.note-form textarea{margin-bottom:8px}
.notelist{list-style:none;margin:14px 0 0;padding:0}
.noteitem{padding:10px 12px;border-radius:var(--r-md);border:1px solid var(--line);margin-bottom:8px;background:#fff}
.noteitem.note-system{background:#f8f9fb;border-style:dashed}
.noteitem.note-todo{border-left:3px solid var(--accent)}
.note-top{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:4px}
.note-who{font-size:12px;font-weight:600;color:var(--muted);display:inline-flex;align-items:center;gap:5px}
.note-top time{font-size:11.5px;color:var(--muted)}
.note-text{font-size:13.5px;line-height:1.5}
.note-text.done{text-decoration:line-through;color:var(--muted)}
.note-actions{margin-top:5px}
.small{font-size:12px}
/* Gamification */
.is-me{background:var(--accent-soft)}
.rank{font-size:18px;text-align:center}
.badgegrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:14px}
.badge-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-xl);padding:18px 14px;text-align:center;transition:transform .15s ease,box-shadow .15s ease}
.badge-card.unlocked{border-color:var(--accent)}
.badge-card.unlocked:hover{transform:translateY(-3px);box-shadow:0 10px 24px rgba(16,24,40,.12)}
.badge-card.locked{opacity:.5;filter:grayscale(1)}
.badge-emoji{width:56px;height:56px;margin:0 auto;border-radius:var(--r-xl);display:grid;place-items:center;color:var(--accent-text);background:color-mix(in srgb,var(--accent) 12%,transparent)}
.badge-card.locked .badge-emoji{color:var(--muted);background:#eef0f3}
.badge-name{font-weight:700;margin-top:8px;font-size:14px}
.badge-status{margin-top:8px;font-size:12px;font-weight:600;color:var(--accent-text)}
.badge-card.locked .badge-status{color:var(--muted)}
.rewardgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px}
.reward-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-xl);padding:18px}
.reward-card.reached{border-color:#17a34a;background:#f0fdf4}
.reward-ic{color:var(--accent-text);margin-bottom:8px;width:40px;height:40px;border-radius:var(--r-lg);display:grid;place-items:center;background:color-mix(in srgb,var(--accent) 12%,transparent)}
.reward-card.reached .reward-ic{color:#17a34a;background:#dcfce7}
.reward-amt{font-size:22px;font-weight:800;color:var(--accent-text)}
.rankmedal{display:inline-flex}
.rankmedal.r0{color:#d4a017}.rankmedal.r1{color:#94a3b8}.rankmedal.r2{color:#b45309}
/* ---------- Icons (lib/icons.js) ----------
   Ein einziges Regelwerk fuer alle Symbole. Frueher trug jedes Icon eigene
   Inline-Stile und jeder Container eigene margin-right-Werte; das ergab
   unterschiedliche Abstaende und Grundlinien — genau der schiefe Eindruck.
   Jetzt: .ico sitzt optisch auf der Textgrundlinie, Abstaende macht gap. */
.ico{flex:0 0 auto;vertical-align:-.14em}
.badge{display:inline-flex;align-items:center;gap:5px}
.btn,.tab{gap:6px}
.tab,.chip{display:inline-flex;align-items:center;gap:5px}
.link .ico,.link svg{vertical-align:-.16em}
.reward-title{font-weight:700;margin:6px 0 4px}
.progress{height:12px;background:#eef0f3;border-radius:var(--r-pill);overflow:hidden;margin-top:8px}
.progress-bar{height:100%;background:var(--accent);border-radius:var(--r-pill);transition:width .5s ease}
/* Quests & Streak */
.questlist{display:flex;flex-direction:column;gap:10px}
.quest{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid var(--line);border-radius:var(--r-md)}
.quest.done{border-color:#17a34a;background:#f0fdf4}
.quest-ic{color:var(--accent-text);width:34px;height:34px;flex:0 0 auto;border-radius:var(--r-md);display:grid;place-items:center;background:color-mix(in srgb,var(--accent) 12%,transparent)}
.quest.done .quest-ic{color:#17a34a;background:#dcfce7}
.quest-mid{flex:1}
.quest-label{font-size:13.5px;font-weight:600;margin-bottom:5px}
.qbar{height:8px;background:#eef0f3;border-radius:var(--r-pill);overflow:hidden}
.qbar-fill{height:100%;background:var(--accent);border-radius:var(--r-pill);transition:width .5s ease}
.quest-cnt{font-weight:700;font-size:13px;white-space:nowrap}
/* Konfetti */
.confetti-canvas{position:fixed;inset:0;pointer-events:none;z-index:9999}

/* Seitenkopf mit Info-Icon + Popover (kein Layout-Shift) */
.head-left{position:relative}
.title-row{display:flex;align-items:center;gap:8px}
.info-btn{width:20px;height:20px;border-radius:50%;border:1.5px solid var(--muted);background:#fff;color:var(--muted);font-size:12px;font-weight:700;font-style:italic;cursor:pointer;line-height:1;display:inline-grid;place-items:center;flex-shrink:0;transition:all .13s ease}
.info-btn:hover{border-color:var(--accent);color:var(--accent-text);transform:scale(1.1)}
.info-pop{position:absolute;top:calc(100% + 8px);left:0;z-index:40;max-width:520px;background:#0f172a;color:#e6e8ec;border-radius:var(--r-md);padding:12px 14px;font-size:13px;line-height:1.55;box-shadow:0 16px 40px rgba(0,0,0,.28);
  opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity .15s ease,transform .15s ease,visibility .15s}
.info-pop.open{opacity:1;visibility:visible;transform:translateY(0)}
.info-pop::before{content:"";position:absolute;top:-6px;left:14px;width:12px;height:12px;background:#0f172a;transform:rotate(45deg)}

/* Geführte Onboarding-Tour: Spotlight + Pfeil + Tooltip */
#tour-mask{position:fixed;inset:0;z-index:1000;pointer-events:auto}
#tour-mask .veil{position:absolute;background:rgba(15,23,42,.55);transition:all .25s ease}
#tour-ring{position:absolute;z-index:1001;border-radius:var(--r-lg);box-shadow:0 0 0 3px var(--accent),0 0 0 9999px rgba(15,23,42,.55);transition:all .28s cubic-bezier(.2,.8,.2,1);pointer-events:none}
#tour-tip{position:absolute;z-index:1002;width:340px;max-width:86vw;background:#fff;border-radius:var(--r-xl);padding:20px 22px;box-shadow:0 30px 80px rgba(0,0,0,.4);transition:all .28s cubic-bezier(.2,.8,.2,1)}
#tour-tip .tour-step{font-size:12px;color:var(--muted);font-weight:600}
#tour-tip h2{margin:5px 0 8px;font-size:19px}
#tour-tip p{margin:0 0 18px;color:#344054;line-height:1.6;font-size:14px}
.tour-foot{display:flex;justify-content:space-between;align-items:center;gap:8px}
.tour-foot>div{display:flex;gap:8px}
#tour-arrow{position:absolute;z-index:1002;color:var(--accent-text);line-height:0;display:grid;place-items:center;filter:drop-shadow(0 2px 4px rgba(0,0,0,.3));transition:all .28s ease;animation:tourbob 1s ease-in-out infinite}
#tour-arrow .ico{stroke-width:2.6;vertical-align:0}
@keyframes tourbob{0%,100%{transform:translateX(0)}50%{transform:translateX(-6px)}}
/* Steht die Blase unter dem Element (schmale Bildschirme), zeigt der Pfeil
   nach oben — dann muss er auch nach oben wippen, nicht zur Seite. */
#tour-arrow.up{animation:tourbobv 1s ease-in-out infinite}
@keyframes tourbobv{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
#tour-center{position:fixed;inset:0;z-index:1002;display:grid;place-items:center;pointer-events:none}
#tour-center #tour-tip{position:relative;pointer-events:auto}

/* Rueckmeldungen (Erfolg/Fehler) */
.ok-msg{background:#ecfdf5;border:1px solid #a7f3d0;color:#065f46;padding:9px 12px;border-radius:var(--r-md);font-size:13px;margin:0 0 12px}
.err-msg{background:#fef2f2;border:1px solid #fecaca;color:#991b1b;padding:9px 12px;border-radius:var(--r-md);font-size:13px;margin:0 0 12px}
.selectx.invalid .selectx-btn{border-color:#dc2626;box-shadow:0 0 0 3px rgba(220,38,38,.14)}

/* CRM: Massenauswahl + Stufen */
.bulkbar{display:none;align-items:center;gap:10px;flex-wrap:wrap;background:var(--accent-soft);border:1px solid var(--line);border-radius:var(--r-md);padding:9px 12px;margin-bottom:12px}
.bulkbar.on{display:flex}
.bulkcount{font-size:13px;color:var(--ink)}
.stagesel{padding:5px 8px;border:1px solid var(--line-ctl);border-radius:var(--r-sm);font-size:12.5px;background:#fff}
.stagepick{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:14px}
.stagepick form{margin:0}
.stagepick-lbl{font-size:12px;text-transform:uppercase;letter-spacing:.03em;color:var(--muted);font-weight:600;margin-right:4px}
.stage-btn.is-cur{background:var(--accent);color:var(--accent-ink);border-color:transparent}
.dossier{border:1px solid var(--line);border-radius:var(--r-md);padding:12px 14px;background:#fbfcfd}
.dossier-top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px}
.dossier-line{margin:0 0 6px}
.dossier-list{margin:6px 0 8px;padding-left:18px;font-size:13px;color:var(--ink)}
.dossier-list li{margin-bottom:4px}
/* Schwachstellenliste im CRM-Dossier: Titel fett, Dringlichkeit als kleines
   Woertchen daneben. Dieselbe Farblogik wie auf der Landingpage, damit ein
   Befund im Werkzeug und beim Kunden gleich aussieht. */
.painlist li{margin-bottom:8px}
.sevtag{display:inline-block;margin-left:8px;font-style:normal;font-size:10.5px;font-weight:700;
  letter-spacing:.4px;text-transform:uppercase;padding:1px 7px;border-radius:var(--r-pill);border:1px solid;vertical-align:1px}
.sevtag.s3{color:#9a3412;border-color:#fed7aa;background:#fff7ed}
.sevtag.s2{color:#854d0e;border-color:#fde68a;background:#fffbeb}
.sevtag.s1{color:#475569;border-color:#e2e8f0;background:#f8fafc}

/* Sterne-Bewertung (Vorlagen) */
.stars{display:inline-flex;align-items:center;gap:2px;color:#f0a500}
.stars .star-off{color:#cbd5e1}

/* Auswahlfenster fuer Sonderzeichen beim langen Tastendruck.
   Bewusst nah an der macOS-Vorlage: helle Leiste, ein Feld je Zeichen,
   kleine Ziffer darunter. Es liegt ueber allem (auch ueber Dialogen), weil es
   immer direkt an der Schreibmarke steht und nur Sekunden sichtbar ist. */
.acc-pop{position:fixed;z-index:9999;display:flex;gap:4px;padding:5px;
  background:var(--panel,#fff);border:1px solid var(--line,#e6e8ec);border-radius:var(--r-md);
  box-shadow:0 10px 28px rgba(15,23,42,.18);animation:accIn .12s ease-out}
@keyframes accIn{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
.acc-opt{display:flex;flex-direction:column;align-items:center;gap:1px;min-width:30px;
  padding:4px 3px 2px;border:0;border-radius:var(--r-sm);background:transparent;cursor:pointer;
  font:inherit;color:var(--ink,#101828);line-height:1}
.acc-opt .acc-ch{font-size:18px}
.acc-opt .acc-no{font-size:9px;opacity:.55}
.acc-opt:hover{background:#eef1f6}
.acc-opt.on{background:var(--accent,#4f46e5);color:var(--accent-ink,#fff)}
.acc-opt.on .acc-no{opacity:.8}

/* ===================================================================
   Bedienung am Telefon
   ===================================================================
   Am Rechner ist das Fenster in zwei feste Spalten geteilt: links die
   Seitenleiste, rechts der Inhalt, jede fuer sich scrollbar. Auf einem
   Telefon geht das nicht auf — 248px Leiste sind dort ein Drittel des
   Bildschirms, und zwei getrennte Scrollbereiche fuehlen sich falsch an.

   Deshalb wird unterhalb von 900px umgebaut:
     * eine schmale Kopfleiste oben mit Menueknopf, Seitentitel und Profil
     * die Seitenleiste faehrt als Schublade von links ein, mit Abdunklung
     * die Seite selbst scrollt wieder ganz normal am Dokument
   =================================================================== */

/* Handlungen sind Formulare, keine Verweise — Begruendung bei `tuKnopf()` in
   lib/render.js. Damit sie trotzdem aussehen duerfen wie ein Verweis, wenn
   sie in einer Zeile mit anderen Verweisen steht, bekommt der Knopf hier
   seine Knopf-Natur abgeraeumt. Ohne `display:inline` am Formular saesse
   jede solche Handlung in einer eigenen Zeile. */
.tu-form{display:inline}
button.link{background:none;border:0;padding:0;margin:0;font:inherit;cursor:pointer;
  color:var(--accent-text);text-decoration:none}
button.link:hover{text-decoration:underline}
/* Dieselbe Farbe wie `.link-danger` weiter unten — geschrieben und nicht
   geerbt, weil die Regel dort nur `color` setzt und ein <button> seine eigene
   Farbe mitbringt, die staerker waere. */
button.link.link-danger{color:#b42318}
button.link.link-danger:hover{color:#8f1d13}
html[data-theme="dark"] button.link.link-danger{color:#f4a4a0}

/* Die Wahl der Telefonleiste im Profil. Kaestchen als Kacheln statt als
   Liste: vier aus zwoelf sucht man mit den Augen, nicht mit dem Finger an
   einer Spalte entlang. Das echte Kaestchen bleibt sichtbar — ein Haken, den
   nur die Faerbung anzeigt, ist bei zwei aehnlichen Toenen geraten. */
.tabwahl{display:flex;flex-wrap:wrap;gap:8px;margin:4px 0 10px}
.tabwahl-item{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;
  border:1px solid var(--line);border-radius:var(--r-md);cursor:pointer;
  font-size:13.5px;background:var(--panel)}
.tabwahl-item.is-on{border-color:var(--accent);background:var(--accent-soft);color:var(--accent-text)}
.tabwahl-item input{margin:0;flex:0 0 auto}

.nav-scrim{display:none}
.mb-close{display:none}
.tabbar{display:none}

/*
 * Wie hoch die feste Leiste unten ist — an EINER Stelle.
 *
 * Drei Regeln rechneten mit `var(--tabbar-h,62px)`: der Assistentenkreis, sein
 * Fenster und dessen Hoehe. Gesetzt wurde die Variable nirgends. Es galt also
 * immer der Ersatzwert 62px, waehrend die Leiste auf einem Telefon mit
 * Home-Anzeige rund 96px hoch ist. Der Kreis sass mit seiner unteren Haelfte
 * auf der Leiste — nicht anklickbar, weil der Tipp den Menuepunkt darunter
 * traf.
 *
 * Der Ersatzwert war dabei das Tueckische: `var(--x, 62px)` sieht aus wie
 * „nimm die Variable", ist aber „nimm 62px, solange sie niemand setzt". Ein
 * Wert, der plausibel aussieht und nie stimmt, faellt in keiner Probe auf.
 *
 * Deshalb steht die Zahl jetzt hier und die Leiste bekommt ihre Hoehe daraus
 * zugewiesen, statt sie aus ihrem Inhalt zu beziehen. Damit kann die Variable
 * gar nicht mehr von der Wirklichkeit abweichen: sie IST die Wirklichkeit.
 * Am Rechner gibt es keine Leiste, dort ist sie null.
 */
:root{--tabbar-inhalt:62px;--tabbar-h:0px}
@media(max-width:900px){
  :root{--tabbar-h:calc(var(--tabbar-inhalt) + env(safe-area-inset-bottom,0px))}
}

/* Breite Tabellen bekommen einen eigenen Schiebebereich (per JS umschlossen),
   damit die Seite selbst nie seitlich verrutscht. */
/* Der Schiebebereich galt bisher nur am Telefon — auf dem Rechner war die
   Zeile darüber ein Versprechen ohne Regel. Solange die Tabellen schmal genug
   waren, fiel das nicht auf; mit den zusätzlichen Spalten schob sich die ganze
   Seite zur Seite, samt Kopfzeile und Seitenleiste. Jetzt schiebt sich die
   Tabelle in ihrer Karte, und der Rest der Seite steht still. */
.tblwrap{width:100%;min-width:0;overflow-x:auto;scrollbar-width:thin}
.tblwrap>.tbl{min-width:100%}

@media(max-width:900px){
  /* Der Bildschirm scrollt wieder als Ganzes. Ohne diese Zeile bleibt die
     Sperre aus der Rechner-Ansicht stehen und man kommt am Telefon keinen
     Millimeter nach unten. */
  html,body{height:auto;overflow:visible;overscroll-behavior:auto}
  .shell{display:block;height:auto;overflow:visible}

  /* Die Schublade. Sie liegt ueber allem, bis auf die Tour. */
  /* Auch die Schublade schiebt nicht als Ganzes: `overflow:hidden` hier, und
     das Schieben liegt wie am Rechner in der Menueliste. Damit bleibt das
     Profil auch auf einem kurzen Telefonbildschirm unten stehen. */
  .sidebar{position:fixed;top:0;left:0;bottom:0;z-index:200;
    width:min(84vw,300px);height:100%;max-height:100dvh;overflow:hidden;
    padding:16px 14px calc(16px + env(safe-area-inset-bottom,0px));
    transform:translateX(-102%);visibility:hidden;
    box-shadow:14px 0 44px rgba(15,23,42,.35);
    transition:transform .26s cubic-bezier(.2,.8,.2,1),visibility .26s}
  body.nav-open .sidebar{transform:none;visibility:visible}
  .mb-close{display:inline-grid;place-items:center;position:absolute;top:12px;right:12px;
    width:32px;height:32px;border:0;border-radius:var(--r-md);background:#1e293b;color:#cbd5e1;cursor:pointer}
  .brand-area{padding-right:40px}

  .nav-scrim{display:block;position:fixed;inset:0;z-index:190;background:rgba(15,23,42,.55);
    opacity:0;visibility:hidden;transition:opacity .26s ease,visibility .26s}
  body.nav-open .nav-scrim{opacity:1;visibility:visible}
  /* Solange die Schublade offen ist, soll der Inhalt dahinter nicht mitscrollen. */
  body.nav-open{overflow:hidden}

  /* Der untere Abstand macht Platz fuer die feste Leiste am Bildschirmrand,
     sonst liegt der letzte Kasten dauerhaft darunter und ist nicht bedienbar.
     Oben kommt der sichere Bereich dazu, seit die Kopfleiste weg ist: sie hat
     die Kerbe des Geraets mit abgedeckt, ohne sie steht die Ueberschrift sonst
     unter der Uhr. */
  .main{height:auto;overflow:visible;
    padding:calc(18px + env(safe-area-inset-top,0px)) 16px calc(var(--tabbar-h) + 34px)}

  /* Die Spaltenzahl stand fest auf fuenf. Seit jeder selbst waehlt, welche
     Bereiche unten stehen, koennen es auch drei sein — dann blieben zwei
     leere Spalten stehen und die Knoepfe klebten links, statt die Breite zu
     teilen. `grid-auto-columns` zaehlt, was da ist. */
  .tabbar{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
    height:var(--tabbar-h);
    position:fixed;left:0;right:0;bottom:0;z-index:150;
    background:rgba(255,255,255,.94);-webkit-backdrop-filter:saturate(180%) blur(14px);backdrop-filter:saturate(180%) blur(14px);
    border-top:1px solid var(--line);
    padding:6px 4px calc(6px + env(safe-area-inset-bottom,0px));
    box-shadow:0 -6px 20px rgba(15,23,42,.08)}
  .tabbar-item{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
    min-width:0;padding:5px 2px;border:0;background:none;font:inherit;cursor:pointer;
    text-decoration:none;color:var(--muted);border-radius:var(--r-md)}
  .tabbar-item span{font-size:10.5px;font-weight:600;letter-spacing:.1px;
    max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .tabbar-ico{width:21px;height:21px}
  .tabbar-item.is-active{color:var(--accent-text)}
  .tabbar-item:active{transform:scale(.94)}
  /* Solange die Schublade offen ist, waere die Leiste doppelt gemoppelt
     und wuerde ueber der Abdunklung liegen. */
  body.nav-open .tabbar{display:none}

  /* Kopfzeile der Seite: Titel und Aktionen untereinander statt nebeneinander —
     nebeneinander bleibt vom Titel sonst ein Wort uebrig. */
  .pagehead{flex-direction:column;align-items:stretch;gap:12px;margin-bottom:16px}
  .pagehead h1{font-size:20px}
  .head-actions{flex-wrap:wrap}
  .head-actions .btn{flex:1 1 auto;justify-content:center}
  .info-pop{max-width:calc(100vw - 32px)}

  .card{padding:15px 16px;margin-bottom:14px}
  .modal{padding:18px 18px}
  .modal h3{top:-18px;padding-top:18px;margin-top:-18px}
  .modal-foot{bottom:-18px;padding-bottom:18px;margin-bottom:-18px}
  dialog{width:94%}

  /* Trefferflaechen fuer den Daumen.
     Der Telefonblock hat bisher `.btn`, `.nav-item`, `.dd-item` und
     `.permrow` vergroessert — die kleinen Bedienelemente in Listen standen
     nicht in dieser Liste. Ein Auswahlkaestchen ist rund 16px breit und hat
     keine Beschriftung daneben, an der man es mittreffen koennte; man
     erwischt es erst im zweiten oder dritten Anlauf.

     Vergroessert wird die FLAECHE, nicht das Bild: `padding` an der Zelle
     und ein groesseres Kaestchen, aber keine Zeile, die dadurch doppelt so
     hoch wird. 40px ist die Zahl, die Apple und Google beide nennen. */
  .tbl input[type=checkbox]{width:22px;height:22px}
  .tbl td:has(> input[type=checkbox]),
  .tbl th:has(> input[type=checkbox]){padding:6px 10px}
  .rmenu-knopf{width:40px;height:40px}
  .hakenknopf{width:36px;height:36px}
  .kb-plus{width:36px;height:36px}
  .suche-leer{width:32px;height:32px}
}

/* -------------------------------------------------------------------
   Reihen, die am Rechner untereinander stehen, liegen hier nebeneinander
   und lassen sich seitlich schieben. Man sieht auf einen Blick, wie viele
   es sind, statt an jedem einzelnen vorbeizuwischen. Die naechste Karte
   ragt sichtbar ins Bild — das ist der Hinweis, dass es weitergeht.
   ------------------------------------------------------------------- */
@media(max-width:760px){
  /* width:auto ist noetig, weil der Inhaltsbereich eine Flexspalte ist: dort
     bekaeme die Reihe sonst die Breite ihres Elternteils und die negativen
     Aussenabstaende zoegen sie nur nach links, statt sie auf beiden Seiten
     bis an den Bildschirmrand zu ziehen.
     scroll-padding-left setzt den Fangpunkt auf den Innenabstand: sonst
     springt die erste Karte beim Einrasten buendig an die Bildschirmkante,
     waehrend der Rest der Seite 16px Rand hat. */
  .stats-row,.badgegrid,.rewardgrid{
    display:flex;grid-template-columns:none;gap:12px;width:auto;
    overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;
    scroll-padding-left:16px;
    -webkit-overflow-scrolling:touch;
    padding:2px 16px 12px;margin-left:-16px;margin-right:-16px;
    scrollbar-width:none;-ms-overflow-style:none}
  .stats-row::-webkit-scrollbar,.badgegrid::-webkit-scrollbar,.rewardgrid::-webkit-scrollbar{width:0;height:0;display:none}
  .stats-row>*,.badgegrid>*,.rewardgrid>*{scroll-snap-align:start}
  .stats-row>.stat{flex:0 0 62%}
  .badgegrid>*{flex:0 0 46%}
  .rewardgrid>*{flex:0 0 78%}
  /* Karten in einer Schiebereihe duerfen beim Beruehren nicht anspringen —
     das machte die Reihe kurzzeitig breiter als den Bildschirm. */
  .badge-card.unlocked:hover{transform:none;box-shadow:none}

  /* Reiter: schieben statt umbrechen, sonst wird aus vier Reitern ein Block
     ueber drei Zeilen. */
  .untertabs{flex-wrap:nowrap;overflow-x:auto;width:auto;
    margin-left:-16px;margin-right:-16px;padding:0 16px 4px}
  .untertab{flex:0 0 auto}
  .tabs{flex-wrap:nowrap;overflow-x:auto;scroll-snap-type:x proximity;width:auto;
    scroll-padding-left:16px;
    padding-bottom:4px;margin-left:-16px;margin-right:-16px;padding-left:16px;padding-right:16px;
    scrollbar-width:none}
  .tabs::-webkit-scrollbar{width:0;height:0;display:none}
  .tab{flex:0 0 auto;scroll-snap-align:start}

  /* Tabellen bleiben Tabellen — sie bekommen nur einen eigenen Schiebebereich,
     der bis an beide Bildschirmkanten reicht. Umgebaute Tabellen (Zeile wird
     zur Karte) verlieren den Spaltenvergleich, den man hier gerade braucht. */
  .tblwrap{overflow-x:auto;-webkit-overflow-scrolling:touch;width:auto;
    margin-left:-16px;margin-right:-16px;padding-left:16px;padding-right:16px;
    scrollbar-width:none}
  .tblwrap::-webkit-scrollbar{width:0;height:0;display:none}
  .tblwrap>.tbl{min-width:620px}

  /* Eingabefelder: 16px, weil iOS bei kleinerer Schrift beim Antippen
     hineinzoomt und die Seite danach schief steht. */
  input[type=text],input[type=email],input[type=password],input[type=number],
  input:not([type]),select,textarea{font-size:16px;padding:11px 12px}
  label{margin-bottom:14px}
  .inline-form,.filterbar,.bulkbar,.stagepick,.proflinks{flex-wrap:wrap}
  .inline-form input,.inline-form select,.filterbar select{width:100%}
  .selectx.inline,.selectx.inline .selectx-btn{width:100%}
  .selectx-menu{max-height:60vh}
  .selectx-item{padding:12px 12px;font-size:15px;white-space:normal}

  /* Groessere Trefferflaechen fuer den Daumen. */
  .btn{padding:11px 16px;font-size:14px}
  .btn-sm{padding:8px 12px;font-size:13px}
  .nav-item{padding:12px 12px;font-size:15px}
  .dd-item{padding:12px 11px;font-size:14px}
  .dd-trigger{padding:10px 8px}
  .info-btn{width:24px;height:24px}
  .permrow{padding:10px 8px}
  .chk{margin:6px 14px 6px 0}

  .feed li{flex-direction:column;gap:2px}
  .kv td:first-child{width:44%}
  .profile-head{gap:12px}
  .profile-name{font-size:18px}
  .stat-val{font-size:24px}
  .dropzone .dz-inner{padding:22px 14px}
}

/* Ohne Mauszeiger bleibt ein Hover-Zustand nach der Beruehrung haengen: der
   Knopf behielte seine Fuellung und seinen Versatz, bis man woanders tippt.
   Am Telefon zaehlt darum nur noch das kurze Eindruecken beim Antippen. */
@media(hover:none){
  .btn:hover{box-shadow:none}
  .btn:hover::before,.tab:hover::before,.nav-item:hover::before,
  .dd-item:hover::before,.dd-trigger:hover::before,
  .chip:hover::before,.proflink:hover::before,.selectx-item:hover::before{clip-path:circle(0% at 50% 50%)}
  .chip:hover,.proflink:hover,.badge-card.unlocked:hover{transform:none}
  .info-btn:hover{transform:none}
  .rowlink:hover{background:transparent}
  .btn:active::before{clip-path:circle(150% at 50% 50%)}
}

/* ---------- Charakter-Werkstatt -----------------------------------------
   Eigener Block am Dateiende, weil hier bewusst mit der Kaskade gearbeitet
   wird: eine spaeter stehende Regel gewinnt gegen eine gleich spezifische
   weiter oben — auch gegen eine in einem @media-Block. Der Mobilteil steht
   deshalb unter den normalen Regeln und nicht davor. */
.persona-top{display:flex;gap:18px;align-items:flex-start;flex-wrap:wrap;margin-top:12px}
.persona-prevwrap{text-align:center}
.persona-form{flex:1;min-width:280px}
.persona-prev{width:96px;height:96px;object-fit:cover;border-radius:50%;border:3px solid var(--accent);display:block}
.persona-prev-empty{background:var(--line);display:grid;place-items:center;color:var(--muted);font-size:11px;border-color:var(--line)}
.persona-shop{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px;align-items:start}
.persona-shop>.card{margin:0}

.scriptwrap{border:1px solid var(--line);border-radius:var(--radius);padding:10px 12px;margin-top:10px;background:var(--bg)}
.scriptwrap>summary{cursor:pointer;list-style:none;font-size:13.5px}
.scriptwrap>summary::-webkit-details-marker{display:none}
.scriptwrap>summary::before{content:'▸';display:inline-block;width:14px;color:var(--muted)}
.scriptwrap[open]>summary::before{content:'▾'}
.guide{margin:12px 0 0;padding-left:20px;font-size:13px;color:var(--muted);line-height:1.65}
.guide li{margin-bottom:7px}
.scripthd{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:14px 0 6px;flex-wrap:wrap}
.scriptbox{white-space:pre-wrap;font:400 13px/1.7 var(--font);background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-md);padding:12px 14px;margin:0;max-height:260px;overflow:auto;color:var(--ink)}

@media(max-width:900px){
  .persona-top{gap:12px}
  .persona-shop{grid-template-columns:minmax(0,1fr)}
  .scriptbox{max-height:200px;font-size:12.5px}
  .persona-prevwrap{margin:0 auto}
}

/* Werkstatt-Karten */
.wk-hd{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.wk-files{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.wk-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}

/* ==========================================================================
   Dunkler Modus
   --------------------------------------------------------------------------
   Bewusst als einzelner Block ganz am Ende und ausschliesslich ueber
   html[data-theme="dark"]. Das hat zwei Gruende:

   1. Spezifitaet. `html[data-theme="dark"] .foo` liegt bei 0,2,0 und schlaegt
      damit jede vorhergehende Klassenregel und auch jede Regel in einem
      @media-Block — es muss also nirgends oben im Stylesheet etwas
      umgeschrieben werden. Wer spaeter eine helle Regel ergaenzt, bekommt sie
      hier unten nachgezogen und nicht an fuenf verstreuten Stellen.
   2. Nachvollziehbarkeit. Der helle Modus bleibt die Wahrheit; hier steht nur
      die Abweichung. Bei einem Fehler ist sofort klar, wo man sucht.

   Der Grossteil erledigt sich ueber die Variablen: Karten, Tabellen, Trenner
   und Texte greifen bereits auf --bg/--panel/--ink/--muted/--line zu. Darunter
   stehen nur die Stellen, an denen frueher eine feste helle Farbe eingetragen
   wurde. --accent bleibt unangetastet: die Akzentfarbe gehoert dem Unternehmen
   und darf sich nicht je nach Tageszeit aendern. Nur der sehr helle
   Akzentschleier --accent-soft wird in die dunkle Flaeche eingemischt, sonst
   leuchtete er als weisser Block. */
html[data-theme="dark"]{
  --bg:#0b1220;
  --panel:#151d2c;
  --ink:#e7ecf5;
  --muted:#94a3b8;
  --line:#28334a;
  --line-ctl:#4a5871;--ctl-bg:#1b2436;
  --accent-soft:color-mix(in srgb,var(--accent) 26%,#151d2c);
  /* Der Server rechnet zwei Schriftvarianten des Akzents aus, eine gegen die
     helle und eine gegen die dunkle Karte. Hier wird auf die dunkle
     umgeschaltet — ohne das steht der reine Akzent als Text auf #151d2c und
     bleibt bei manchen Kundenfarben unter 4,5:1. */
  --accent-text:var(--accent-text-dark);
  color-scheme:dark;
}
/* Formularfelder, Knoepfe, Listen: alles, was vorher schlicht weiss war. */
html[data-theme="dark"] input:where(:not([type=checkbox]):not([type=radio]):not([type=color]):not([type=file]):not([type=range]):not([type=submit]):not([type=button]):not([type=image]):not([type=hidden])),
html[data-theme="dark"] select,
html[data-theme="dark"] textarea{background:#0f1727;color:var(--ink)}
html[data-theme="dark"] input::placeholder,
html[data-theme="dark"] textarea::placeholder{color:#64748b}
/* ACHTUNG beim Aendern: dieses Dunkel-Grau darf NUR den schlichten Knopf treffen.
   Frueher stand hier `.btn` ohne Ausnahmen — das hat wegen der hoeheren
   Spezifitaet (0,2,0 gegen 0,1,0) die Akzentfarbe von .btn-primary ueberschrieben,
   waehrend die Schriftfarbe --accent-ink (bei hellem Akzent fast schwarz) blieb.
   Ergebnis: dunkle Schrift auf dunklem Knopf, praktisch unlesbar.

   `.is-cur` gehoert aus demselben Grund in die Ausnahmeliste: der aktive Knopf
   holt sich seine Flaeche weiter unten aus dem Akzent, aber diese Regel hier
   ist spezifischer (0,5,1 gegen 0,3,1) und hat ihm nur den Hintergrund wieder
   weggenommen — die Schriftfarbe --accent-ink blieb. Genau so war die aktive
   Vertriebsstufe im CRM dunkel auf dunkel. */
html[data-theme="dark"] .btn:not(.btn-primary):not(.btn-danger):not(.btn-ghost):not(.is-cur){background:var(--ctl-bg);--fill:#2b3852;border-color:var(--line-ctl)}
html[data-theme="dark"] .btn:hover{box-shadow:0 6px 18px rgba(0,0,0,.45)}
html[data-theme="dark"] .selectx-btn,
html[data-theme="dark"] .selectx-menu,
html[data-theme="dark"] .stagesel,
html[data-theme="dark"] .info-btn,
html[data-theme="dark"] .tab,
html[data-theme="dark"] .noteitem{background:var(--panel)}
html[data-theme="dark"] .acc-opt:hover{background:#1f293c}
html[data-theme="dark"] code,
html[data-theme="dark"] .pre-wrap,
html[data-theme="dark"] .tpl-body,
html[data-theme="dark"] .chip,
html[data-theme="dark"] .dropzone,
html[data-theme="dark"] .dossier,
html[data-theme="dark"] .noteitem.note-system,
html[data-theme="dark"] .progress,
html[data-theme="dark"] .qbar,
html[data-theme="dark"] .badge-card.locked .badge-emoji{background:#111a2a}
html[data-theme="dark"] code{color:#dbe4f2}
/* Kennzeichnungen: gleiche Bedeutung, gedaempfte Flaeche, hellere Schrift —
   auf dunklem Grund braucht Farbe weniger Saettigung, aber mehr Helligkeit,
   sonst verschwindet die Schrift in der Flaeche. */
html[data-theme="dark"] .badge-gray{background:#243046;color:#c2cde0}
html[data-theme="dark"] .badge-blue{background:#1b2c50;color:#9ec0ff}
html[data-theme="dark"] .badge-green{background:#13341f;color:#7fdba2}
html[data-theme="dark"] .badge-amber{background:#3a2a10;color:#f3c07a}
html[data-theme="dark"] .badge-red{background:#3d1c1c;color:#f4a4a0}
html[data-theme="dark"] .ok-msg{background:#12321f;border-color:#1c5c38;color:#8fe3b4}
html[data-theme="dark"] .err-msg,
html[data-theme="dark"] .alert{background:#3a1a1a;border-color:#6b2b2b;color:#f6b0ab}
html[data-theme="dark"] .owner-warn{background:#3a2a10;border-color:#7a5416;color:#f0c98a}
html[data-theme="dark"] .sevtag.s3{background:#3a2010;border-color:#7c4a1c;color:#f0b183}
html[data-theme="dark"] .sevtag.s2{background:#33290e;border-color:#6d5a1a;color:#e8cf85}
html[data-theme="dark"] .sevtag.s1{background:#1c2536;border-color:#2f3d55;color:#aebdd3}
html[data-theme="dark"] .reward-card.reached,
html[data-theme="dark"] .quest.done{background:#12301e;border-color:#1f6b3d}
html[data-theme="dark"] .reward-card.reached .reward-ic,
html[data-theme="dark"] .quest.done .quest-ic{background:#17402a;color:#7fdba2}
html[data-theme="dark"] .stars .star-off{color:#2f3c54}
html[data-theme="dark"] .linkbtn-danger{color:#f4a4a0}
/* Erklaerblase und Tour: auf dunklem Grund war die dunkle Blase nicht mehr
   vom Hintergrund zu unterscheiden — sie wird deshalb eine Stufe heller als
   die Karte, statt eine Stufe dunkler. */
html[data-theme="dark"] .info-pop{background:#243046;color:#e7ecf5}
html[data-theme="dark"] .info-pop::before{background:#243046}
html[data-theme="dark"] #tour-tip{background:var(--panel);color:var(--ink);box-shadow:0 30px 80px rgba(0,0,0,.7)}
html[data-theme="dark"] #tour-tip p{color:#b6c2d6}
/* Mobile Leiste am unteren Rand: der milchige weisse Schleier wird dunkel. */
html[data-theme="dark"] .tabbar{background:rgba(15,23,42,.94);box-shadow:0 -6px 20px rgba(0,0,0,.5)}
/* Die Seitenleiste war schon immer dunkel. Im dunklen Modus wuerde sie mit der
   Arbeitsflaeche verschmelzen — deshalb bekommt sie hier eine Spur mehr Tiefe
   und eine sichtbare Kante. */
html[data-theme="dark"] .sidebar{background:#080d18;border-right:1px solid var(--line)}
/* Scrollbalken. Ohne diese Zeile bleiben sie hell und stechen heraus.
   Gemacht wird das mit `scrollbar-color` und nicht mit `::-webkit-scrollbar`:
   Letzteres schaltet auf einem Mac vom ueberlagernden auf den klassischen
   Balken um, der dauerhaft Platz belegt. Die dunkle Ansicht waere damit zehn
   Pixel schmaler als die helle — auf demselben Bildschirm, mit demselben
   Inhalt. Die Begruendung ausfuehrlich steht weiter unten beim Rollbalken. */
html[data-theme="dark"]{scrollbar-color:#2b3852 transparent}

/* Umschalter im Profilmenue: drei Felder nebeneinander, das gewaehlte in der
   Akzentfarbe. Absichtlich kein Kippschalter — „System" ist ein eigener,
   gleichwertiger Zustand und liesse sich mit zwei Stellungen nicht abbilden. */
.theme-seg{display:flex;gap:4px;padding:6px 4px 4px;border-top:1px solid #334155;margin-top:4px}
.theme-seg button{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;padding:7px 2px;border:1px solid #334155;
  border-radius:var(--r-sm);background:transparent;color:#cbd5e1;font:inherit;font-size:10.5px;font-weight:600;cursor:pointer;
  transition:background .13s ease,color .13s ease,border-color .13s ease}
.theme-seg button:hover{background:#334155;color:#fff}
.theme-seg button.is-cur{background:var(--accent);color:var(--accent-ink);border-color:transparent}
.theme-seg svg{width:15px;height:15px}

/* ==========================================================================
   Korrekturen dunkler Modus: aktive Zustaende und Lesbarkeit
   --------------------------------------------------------------------------
   Ursache des Problems: die dunklen Regeln stehen am Ende der Datei und haben
   dieselbe Gewichtung wie `.tab.is-active` bzw. `.btn.is-cur`. Bei gleicher
   Gewichtung gewinnt die spaetere Regel — der aktive Reiter verlor also im
   dunklen Modus seine Akzentfarbe und war vom inaktiven kaum zu unterscheiden.
   Deshalb nehmen die dunklen Flaechenregeln die aktiven Zustaende jetzt
   ausdruecklich aus, statt sie zu ueberschreiben.
   ========================================================================== */
html[data-theme="dark"] .tab.is-active{background:var(--accent);color:var(--accent-ink);border-color:transparent}
html[data-theme="dark"] .btn.is-cur,
html[data-theme="dark"] .stage-btn.is-cur,
html[data-theme="dark"] .theme-seg button.is-cur{background:var(--accent);color:var(--accent-ink);border-color:transparent}
html[data-theme="dark"] .tab.is-active svg,
html[data-theme="dark"] .btn.is-cur svg,
html[data-theme="dark"] .stage-btn.is-cur svg{color:var(--accent-ink)}

/* Eigene Zeile in der Rangliste. Die Flaeche ist eingefaerbt, deshalb muss
   auch die gedaempfte Schrift darin heller werden — sonst steht grauer Text
   auf farbigem Grund und faellt unter die Lesbarkeitsschwelle. Die Medaille
   bekommt zusaetzlich Helligkeit, weil dunkles Gold auf dunklem Rot praktisch
   verschwindet. */
html[data-theme="dark"] .is-me{background:color-mix(in srgb,var(--accent) 22%,#151d2c)}
html[data-theme="dark"] .is-me td,
html[data-theme="dark"] .is-me strong{color:#f4f7fb}
html[data-theme="dark"] .is-me .muted{color:#d7c2c9}
html[data-theme="dark"] .rankmedal.r0{color:#ffd257}
html[data-theme="dark"] .rankmedal.r1{color:#cbd5e1}
html[data-theme="dark"] .rankmedal.r2{color:#e39a4e}
html[data-theme="dark"] .tbl th{color:#9fb0c9}

/* Die hervorgehobene Zeile lief bisher mit rechtwinkligen Ecken bis an die
   abgerundete Kante der Karte — genau die Unstimmigkeit, die auffaellt, ohne
   dass man sie benennen kann. Jetzt folgt sie der Rundung der Tabelle. */
.tbl tr.is-me td:first-child{border-top-left-radius:var(--r-sm);border-bottom-left-radius:var(--r-sm)}
.tbl tr.is-me td:last-child{border-top-right-radius:var(--r-sm);border-bottom-right-radius:var(--r-sm)}

/* ---------------------------------------------------------------- Assistent
   Ein Gespraech, kein Formular. Deshalb Blasen statt Tabellenzeilen und ein
   Eingabefeld, das mitwaechst. Die eigene Wortmeldung steht rechts in der
   Akzentfarbe, die Antwort links neutral — so ist ohne Beschriftung klar,
   wer gerade spricht. Farben kommen aus den Variablen, damit der Dunkelmodus
   und das Branding je Unternehmen ohne Sonderregel mitziehen. */
.chat{display:flex;flex-direction:column;gap:14px;max-height:min(58vh,620px);overflow-y:auto;padding:2px 2px 6px;scroll-behavior:smooth}
.chat-row{display:flex;gap:10px;align-items:flex-start;max-width:100%}
/* Bewusst „is-self" und nicht „is-me": letzteres faerbt in der Rangliste
   ganze Tabellenzeilen ein und wuerde hier einen Balken hinter die Blase
   legen. Zwei Bedeutungen fuer einen Klassennamen sind ein Fehler, der erst
   im Dunkelmodus auffaellt. */
.chat-row.is-self{justify-content:flex-end}
.chat-ava{flex:0 0 28px;width:28px;height:28px;border-radius:var(--r-pill);display:flex;align-items:center;justify-content:center;background:var(--accent);color:var(--accent-ink);margin-top:2px}
.chat-bubble{background:#f4f5f8;border:1px solid var(--line);border-radius:var(--r-lg);padding:10px 14px;max-width:min(78%,720px)}
.chat-row.is-self .chat-bubble{background:var(--accent);border-color:transparent;color:var(--accent-ink)}
.chat-bubble p{margin:0 0 8px}
.chat-bubble p:last-child{margin:0}
.chat-empty{text-align:center;color:var(--muted);padding:26px 16px 20px;max-width:640px;margin:0 auto}
.chat-empty p{margin:8px 0 0}
.chat-result{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:10px;padding:8px 11px;border-radius:var(--r-md);font-size:13px;border:1px solid var(--line);background:#fff}
.chat-result.is-ok{border-color:#a7d8b4;background:#f0fbf3;color:#14532d}
.chat-result.is-warn{border-color:#fed7aa;background:#fff7ed;color:#9a3412}
/* Vorbereitet, aber noch nicht getan. Bewusst weder gruen noch rot: gruen
   hiesse „erledigt", rot „schiefgelaufen" — hier wartet etwas auf einen
   Klick, und genau das soll die Farbe sagen. */
.chat-result.is-tun{border-color:var(--accent);background:var(--accent-soft);color:var(--text);
  flex-direction:column;align-items:flex-start;gap:9px}
.chat-tun{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin:0}
.chat-sugg{display:flex;gap:8px;flex-wrap:wrap;margin:16px 0 10px}
.chat-sugg .chip{font-family:inherit;font-weight:500}
.chat-form{display:flex;gap:10px;align-items:flex-end}
.chat-form textarea{flex:1;margin:0;resize:none;min-height:46px}
.chat-form .btn{flex:0 0 auto;height:46px}
.chat-typing{display:inline-flex;gap:4px;align-items:center}
.chat-typing i{width:5px;height:5px;border-radius:50%;background:var(--muted);animation:chatdot 1s infinite ease-in-out}
.chat-typing i:nth-child(2){animation-delay:.16s}
.chat-typing i:nth-child(3){animation-delay:.32s}
@keyframes chatdot{0%,60%,100%{opacity:.25;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}}
html[data-theme="dark"] .chat-bubble{background:#1a2233;border-color:#2a3446}
html[data-theme="dark"] .chat-result{background:#151c29;border-color:#2a3446}
html[data-theme="dark"] .chat-result.is-ok{background:#12271c;border-color:#2f5c3f;color:#a7e8bd}
html[data-theme="dark"] .chat-result.is-tun{background:#141d2b;border-color:var(--accent);color:#e2e8f0}
html[data-theme="dark"] .chat-result.is-warn{background:#2a1c10;border-color:#6b4522;color:#f3c294}
@media (max-width:720px){
  .chat-bubble{max-width:88%}
  .chat-form{flex-direction:column;align-items:stretch}
  .chat-form .btn{width:100%}
}

/* Ein Knopf, der nichts tun kann, muss auch so aussehen. Ohne diese Regel
   sah ein deaktivierter Knopf wie ein ganz normaler aus — man klickt, nichts
   passiert, und sucht den Fehler bei sich. */
.btn:disabled,.btn[disabled]{opacity:.45;cursor:not-allowed;filter:grayscale(.4)}
.btn:disabled:hover,.btn[disabled]:hover{transform:none}

/* ---- LinkedIn verbinden ---------------------------------------------- */
/* Der Statuskasten ist bewusst gross und einzeilig lesbar: „verbunden oder
   nicht" ist die einzige Frage, die auf dieser Seite wirklich zaehlt. */
.li-state{display:flex;gap:12px;align-items:center;padding:14px 16px;margin-bottom:10px;
  border:1px solid var(--line);border-radius:var(--r-md);background:var(--panel)}
.li-state > div{flex:1;line-height:1.45}
.li-state svg{flex:0 0 auto;color:var(--accent-text)}
.li-live{margin-top:14px;padding:14px;border:1px solid var(--line);border-radius:var(--r-md);
  background:color-mix(in srgb,var(--accent) 5%,var(--panel))}
.li-live-head{display:flex;gap:10px;align-items:center;margin-bottom:8px}
.li-shot{display:block;width:100%;max-width:520px;margin:10px 0;border:1px solid var(--line);
  border-radius:var(--r-md)}
.spin{width:15px;height:15px;flex:0 0 auto;border-radius:50%;border:2px solid var(--line);
  border-top-color:var(--accent);animation:lispin .8s linear infinite}
@keyframes lispin{to{transform:rotate(360deg)}}
label.check{display:flex;gap:9px;align-items:flex-start;font-weight:400;font-size:13.5px;
  line-height:1.45;margin:10px 0}
label.check input{width:auto;margin:2px 0 0}
html[data-theme="dark"] .li-state{background:#151c29;border-color:#2a3446}

/* --- LinkedIn: Schritt-fuer-Schritt-Anleitung fuer den li_at-Weg --- */
.li-howto{border:1px solid var(--line);border-radius:var(--r-md);padding:12px 14px;margin:12px 0;background:var(--panel-2,var(--panel))}
.li-howto>summary{cursor:pointer;list-style:none;font-size:13.5px;padding:2px 0}
.li-howto>summary::-webkit-details-marker{display:none}
.li-howto>summary::before{content:"▸";display:inline-block;width:14px;color:var(--accent-text);transition:transform .15s ease}
.li-howto[open]>summary::before{transform:rotate(90deg)}
.li-steps{margin:10px 0 4px;padding-left:20px}
.li-steps li{font-size:13.5px;line-height:1.55;margin-bottom:8px}
.li-steps code,.li-howto code{background:var(--chip,rgba(127,127,127,.14));border-radius:5px;padding:1px 5px;font-size:12.5px}
html[data-theme="dark"] .li-howto{background:#151c29;border-color:#2a3446}

/* ------------------------------------------------------------------
   Knopf-Varianten vollstaendig definiert
   ------------------------------------------------------------------
   .btn-danger und .btn-ghost wurden im Markup benutzt, waren aber nie
   gestaltet — sie sahen deshalb exakt aus wie ein normaler Knopf. Wer
   "Verbindung trennen" oder "Loeschen" anklickt, muss das vorher sehen.
   Alle Farbpaare hier liegen ueber 4.5:1 Kontrast (WCAG AA). */
.btn-danger{background:#fff;color:#b42318;border-color:#f0c2bd;--fill:#fdecec}
.btn-danger:hover{color:#8f1d13;box-shadow:0 6px 18px rgba(180,35,24,.18)}
.btn-ghost{background:transparent;color:var(--muted);border-color:transparent;--fill:var(--accent-soft)}
.btn-ghost:hover{color:var(--ink)}
html[data-theme="dark"] .btn-danger{background:#2a1616;color:#f4a4a0;border-color:#5d2a26;--fill:#3d1c1c}
html[data-theme="dark"] .btn-danger:hover{color:#ffc9c5}
html[data-theme="dark"] .btn-ghost{color:#a9b6ca}
html[data-theme="dark"] .btn-ghost:hover{color:#e7ecf5}

/* Der Hauptknopf behaelt seine Akzentfarbe in JEDEM Theme. Die hohe
   Spezifitaet ist hier Absicht: sie schuetzt gegen kuenftige pauschale
   Dunkelmodus-Regeln, die sonst wieder dazwischenfunken wuerden. */
html[data-theme="dark"] .btn.btn-primary{background:var(--accent);color:var(--accent-ink);border-color:transparent;--fill:var(--accent-hover)}
html[data-theme="dark"] .btn.btn-primary:hover{color:var(--accent-hover-ink)}

/* Deaktivierte Knoepfe: klar erkennbar, aber nicht unsichtbar. Reines
   opacity:.45 auf dunklem Grund war zu wenig zum Lesen. */
.btn:disabled,.btn[disabled]{opacity:.55;cursor:not-allowed;filter:grayscale(.35);box-shadow:none}
html[data-theme="dark"] .btn:disabled,
html[data-theme="dark"] .btn[disabled]{opacity:.75;color:#b6c2d4;background:#171f2f;border-color:#2d3850}

/* Tastaturbedienung: jeder Knopf braucht einen sichtbaren Fokusring,
   sonst ist das Tool ohne Maus nicht benutzbar. */
.btn:focus-visible,.tab:focus-visible,.chip:focus-visible,.dd-item:focus-visible,.nav-item:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px}
html[data-theme="dark"] .btn:focus-visible{outline-color:#8ab4ff}

/* ---------- Schwebender Assistent -----------------------------------------
   Ein Kreis unten rechts, auf jeder Seite. Er liegt ueber allem, aber unter
   der Menue-Schublade und dem Tour-Overlay — sonst laege er im Weg, wenn die
   Tour genau ueber ihn spricht. Am Telefon rueckt er ueber die Tab-Leiste,
   damit er keinen Menuepunkt verdeckt. */
.ass-fab{position:fixed;right:22px;bottom:22px;z-index:70;width:54px;height:54px;border-radius:var(--r-pill);
  border:1px solid transparent;background:var(--accent);color:var(--accent-ink);cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 10px 28px rgba(15,23,42,.22);transition:transform .16s ease,box-shadow .16s ease,background .16s ease}
.ass-fab:hover{transform:translateY(-2px) scale(1.04);box-shadow:0 14px 34px rgba(15,23,42,.28);background:var(--accent-hover);color:var(--accent-hover-ink)}
.ass-fab:active{transform:translateY(0) scale(.97)}
.ass-fab-off{display:none}
.ass-fab.is-open .ass-fab-on{display:none}
.ass-fab.is-open .ass-fab-off{display:flex}

.ass-panel{position:fixed;right:22px;bottom:88px;z-index:69;width:min(392px,calc(100vw - 32px));
  max-height:min(620px,calc(100vh - 130px));display:flex;flex-direction:column;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:0 24px 60px rgba(15,23,42,.24);overflow:hidden;
  transform-origin:100% 100%;animation:assPop .16s ease-out}
@keyframes assPop{from{opacity:0;transform:translateY(10px) scale(.97)}to{opacity:1;transform:none}}
.ass-panel[hidden]{display:none}
.ass-head{display:flex;align-items:center;gap:9px;padding:11px 12px;border-bottom:1px solid var(--line);flex:0 0 auto}
.ass-ava{flex:0 0 26px;width:26px;height:26px;border-radius:var(--r-pill);display:flex;align-items:center;
  justify-content:center;background:var(--accent);color:var(--accent-ink)}
.ass-ttl{flex:1;min-width:0;font-weight:600;font-size:14px;line-height:1.25}
.ass-sub{display:block;font-weight:400;font-size:11.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ass-ico{flex:0 0 auto;width:30px;height:30px;border-radius:var(--r-md);border:0;background:transparent;color:var(--muted);
  cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .14s ease,color .14s ease}
.ass-ico:hover{background:var(--accent-soft);color:var(--ink)}
.ass-chat{flex:1 1 auto;min-height:110px;max-height:none;padding:12px;gap:11px}
.ass-chat .chat-bubble{max-width:88%;font-size:13.5px}
.ass-chat .chat-empty{padding:14px 8px 6px}
.ass-chat .chat-empty p{font-size:13px}
.ass-sugg{margin:0;padding:0 12px 10px;gap:6px;flex:0 0 auto}
.ass-sugg .chip{font-size:12px;padding:5px 10px}
.ass-form{flex:0 0 auto;padding:10px 12px 12px;border-top:1px solid var(--line);gap:8px}
.ass-form textarea{min-height:40px;font-size:13.5px;padding:9px 11px}
.ass-send{flex:0 0 auto;height:40px;width:44px;padding:0;justify-content:center}

html[data-theme="dark"] .ass-panel{box-shadow:0 24px 60px rgba(0,0,0,.55)}
html[data-theme="dark"] .ass-fab{box-shadow:0 10px 28px rgba(0,0,0,.5)}
html[data-theme="dark"] .ass-chat .chat-bubble{background:#1b2436}

/* Ab hier steht die feste Tab-Leiste am unteren Rand (siehe oben, gleicher
   Umbruchpunkt) — der Kreis muss darueber rutschen, sonst verdeckt er einen
   Menuepunkt. */
@media (max-width:900px){
  /* Ueber die Leiste, nicht darunter: sie liegt auf z-index 150. Vorher stand
     der Kreis auf 70 und wurde von ihr verdeckt — man sah ihn durchscheinen
     und traf beim Tippen den Menuepunkt dahinter. */
  .ass-fab{right:14px;bottom:calc(var(--tabbar-h) + 14px);width:48px;height:48px;z-index:160}
  /* `dvh` und nicht `vh`. `100vh` ist am Telefon die GROSSE Ansichtshoehe,
     also die ohne Adressleiste — die tatsaechlich sichtbare ist 60 bis 90
     Pixel kleiner. Das Fenster ist unten verankert, der Ueberschuss ging
     deshalb oben verloren: Titel und Schliessen-Kreuz standen ausserhalb des
     Bildes, und zumachen ging nur noch ueber den Kreis unten. */
  .ass-panel{right:10px;left:10px;width:auto;bottom:calc(var(--tabbar-h) + 72px);
    max-height:calc(100dvh - var(--tabbar-h) - 96px);z-index:159}
  /* Bei offener Schublade waeren beide nur im Weg — die Leiste blendet sich
     dort ebenfalls aus. */
  body.nav-open .ass-fab,body.nav-open .ass-panel{display:none}
  /* Bei offener Menue-Schublade hat der Kreis nichts zu suchen — er laege
     ueber der Abdunklung und wuerde beim Zuklappen angeklickt. */
  body.nav-open .ass-fab,body.nav-open .ass-panel{display:none}
}
@media print{.ass-fab,.ass-panel{display:none}}

/* ------------------------------------------------------------------
   Zwei Stellen, an denen erst das Ueberfahren mit der Maus den Kontrast
   kaputt gemacht hat — im Ruhezustand war beides in Ordnung, deshalb
   faellt es beim blossen Ansehen der Seite nicht auf.
   ------------------------------------------------------------------
   1) Im Unternehmensmenue faerbt `.dd-item.is-cur` den aktuellen Eintrag
      hellblau. Diese Regel steht NACH `.dd-item:hover` und ist gleich
      gewichtet, gewinnt also — beim Ueberfahren blieb das Hellblau auf der
      Akzentflaeche stehen (2,6:1). Jetzt zieht der Hover-Zustand nach.
   2) Reiter tragen im Ruhezustand die gedaempfte Schriftfarbe. Auf dem
      hellen Akzentschleier des Hover-Effekts kam die nur auf 4,0:1. */
.dd-item.is-cur:hover{color:var(--accent-ink)}
.tab:hover:not(.is-active){color:var(--ink)}

/* --------------------------------------------------------------------------
   Angebotsbogen
   --------------------------------------------------------------------------
   Links wird geklickt, rechts steht das Ergebnis. Die Vorschau bleibt beim
   Scrollen stehen, weil sonst genau das passiert, was den Bogen unbrauchbar
   macht: man waehlt unten eine Option und sieht nicht, was sie oben im
   Dokument anrichtet. */
/* Der Bogen fuellt das Fenster, statt es zu verlaengern: die Seite selbst
   rollt nicht mehr, nur noch die Fragenspalte in sich. Das Kleben der rechten
   Spalte war vorher nur eine Naeherung — buendig stand sie erst, nachdem man
   einmal ganz nach unten gerollt hatte, und davor ragte sie um die Hoehe der
   Kopfzeile aus dem Bild. Jetzt endet sie in jedem Zustand auf derselben
   Linie wie jede andere Seite. */
.ang-form{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.ang-cols{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:18px;
  align-items:stretch;flex:1 1 auto;min-height:0}
.ang-cols>*{min-width:0}
/* Nur diese Spalte rollt. Der kleine Innenrand rechts haelt den Rollbalken von
   den Karten fern, sonst schneidet er ihren Schatten an. */
.ang-links{overflow-y:auto;overscroll-behavior:contain;min-height:0;padding-right:6px}
/* Die rechte Spalte ist genau ein Fenster hoch und teilt sich diese Hoehe
   selbst auf: oben die Knoepfe und Summen in ihrer natuerlichen Hoehe, unten
   die Vorschau mit allem, was uebrig bleibt. Damit steht das Dokument sofort
   in voller Groesse da — frueher musste man erst die ganze Seite herunter-
   rollen, bis der Rahmen den Bildschirm fuellte. */
/* Keine eigene Hoehenrechnung mehr: die Spalte bekommt vom Raster genau die
   Hoehe, die zwischen Kopfzeile und unterem Seitenrand uebrig ist. Jede
   Rechnung mit `100vh` musste vorher raten, wie hoch die Kopfzeile gerade ist,
   und lag bei zweizeiligen Titeln daneben. */
.ang-rechts{min-height:0;display:flex;flex-direction:column;gap:18px}
.ang-rechts>.card{margin-bottom:0;flex:0 0 auto}
/* Der Rahmen traegt selbst kein Innenmass: das Dokument im iframe bringt
   seine eigenen Raender mit, ein zweiter Rand daneben sieht nach Fehler aus. */
/* Erst die zweite Klasse holt den Rahmen aus der starren Kartenzeile heraus:
   `.ang-rechts>.card` waere sonst spezifischer und wuerde ihn auf seine
   Inhaltshoehe festnageln — der iframe hat ohne Zuweisung nur seine 150px
   Standardhoehe und die Spalte bliebe halbleer. */
.ang-rechts>.card.ang-rahmen{flex:1 1 auto}
.ang-rahmen{padding:0;overflow:hidden;min-height:0;display:flex}
.ang-rahmen iframe{display:block;width:100%;height:100%;flex:1 1 auto;border:0;background:#fff}
/* Formular links, Liste rechts. Halbe/halbe waere hier falsch: das Formular
   hat eine natuerliche Breite, die Tabelle daneben braucht jeden Rest — bei
   1fr/1fr steht das Formular unnoetig weit auseinander und die Spalten der
   Liste kleben aneinander. Beide Spalten fangen oben an, statt sich auf
   dieselbe Hoehe zu ziehen. */
.ang-cols-form{display:grid;grid-template-columns:minmax(0,400px) minmax(0,1fr);
  gap:18px;align-items:start}
.ang-cols-form>*{min-width:0}
@media(max-width:1100px){
  .ang-cols-form{grid-template-columns:minmax(0,1fr)}
}
@media(max-width:1100px){
  /* Schmal steht alles untereinander und die Seite rollt wieder als Ganzes —
     zwei getrennte Rollbereiche nebeneinander gibt es hier nicht mehr. */
  .ang-form{display:block;min-height:auto}
  .ang-cols{grid-template-columns:minmax(0,1fr);display:block;min-height:auto}
  .ang-links{overflow:visible;padding-right:0}
  .ang-rechts{position:static;height:auto;display:block}
  .ang-rechts>.card{margin-bottom:18px}
  .ang-rahmen{display:block}
  .ang-rahmen iframe{height:60vh}
}

/* Ausgeblendete Fragen: `hidden` allein verliert gegen jedes display aus einer
   Klassenregel, deshalb hier ausdruecklich. */
.ang-frage[hidden],.ang-gruppe[hidden]{display:none!important}

/* ─────────────────────────── Reiter im Fragebogen
   Die Leiste bleibt beim Rollen der Fragenspalte oben stehen. Wer in
   „Konditionen“ nach unten rollt, soll nicht erst zurueckrollen muessen, um
   in „Recht“ zu wechseln. Der volle Hintergrund ist noetig, weil die Karten
   sonst unter der Leiste durchscheinen. */
.ang-reiterleiste{position:sticky;top:0;z-index:5;display:flex;flex-wrap:wrap;gap:6px;
  padding:0 0 12px;background:var(--bg)}
.ang-reiter{position:relative;display:inline-flex;align-items:center;gap:7px;
  padding:7px 13px;border:1px solid var(--line);border-radius:var(--r-pill);
  background:var(--panel);color:var(--muted);font:inherit;font-size:13px;font-weight:600;
  cursor:pointer;transition:background .15s,border-color .15s,color .15s}
.ang-reiter:hover{color:var(--ink);border-color:var(--ink-soft,var(--line))}
.ang-reiter.is-aktiv{background:var(--accent-soft);border-color:var(--accent);color:var(--ink)}
.ang-reiter[hidden]{display:none!important}
/* Der Zaehler sitzt in der Pille, nicht als Kreis darueber: die Leiste rollt
   mit und ein ueberstehender Kreis wuerde an der Kante abgeschnitten. */
.ang-reiter-zaehler{min-width:17px;height:17px;padding:0 5px;display:inline-flex;
  align-items:center;justify-content:center;border-radius:var(--r-pill);
  font-size:11px;font-weight:700;line-height:1;font-variant-numeric:tabular-nums;
  background:#d97706;color:#fff}
.ang-reiter-zaehler[hidden]{display:none!important}
/* Ein Reiter mit offenen Punkten faellt auch geschlossen auf — sonst muesste
   man die Zahl suchen, statt sie zu sehen. */
.ang-reiter.hat-offen:not(.is-aktiv){color:var(--ink);border-color:#fcd34d}
/* Rot statt Gelb, sobald unter dem Reiter eine Pflichtangabe fehlt. Die beiden
   Farben bedeuten dasselbe wie an den Schaltern rechts: Gelb heisst „jemand
   sollte hinsehen“, Rot heisst „ohne das laesst sich das Angebot nicht
   anlegen“. Reiter mit beidem faerbt das Skript rot, weil sonst die haertere
   Bedingung hinter der weicheren verschwaende. */
.ang-reiter.hat-pflicht .ang-reiter-zaehler{background:#dc2626}
.ang-reiter.hat-pflicht:not(.is-aktiv){border-color:#fca5a5}
.ang-reiter-feld[hidden]{display:none!important}

.ang-gruppe-titel{margin:0 0 14px;font-size:15px;display:flex;align-items:center;gap:7px}
.ang-frage{margin-bottom:18px}
.ang-frage:last-child{margin-bottom:0}
.ang-titel{display:block;font-size:13px;font-weight:600;margin-bottom:7px}
/* Der Stern hinter einer Pflichtangabe. In der Akzentfarbe, weil er sonst im
   Fliesstext untergeht — und weil er im Bogen die einzige Stelle ist, an der
   ueberhaupt etwas eingefordert wird. */
.ang-pflicht{color:var(--accent-text);font-weight:700}

/* Auswahl: die ganze Kachel ist anklickbar, nicht nur das kleine Kaestchen.
   Ein Angebot besteht aus zwei Dutzend solcher Entscheidungen; auf Radios von
   14 Pixeln zu zielen ist bei der Menge eine Zumutung. */
.ang-wahlen{display:grid;gap:8px}
.ang-wahl{display:flex;gap:10px;align-items:flex-start;margin:0;padding:11px 13px;
  border:1px solid var(--line-ctl);border-radius:var(--r-md);background:var(--ctl-bg);
  cursor:pointer;font-weight:400;transition:border-color .13s ease,background .13s ease}
.ang-wahl:hover{border-color:var(--accent)}
.ang-wahl input{width:auto;margin:2px 0 0;flex:0 0 auto;accent-color:var(--accent)}
/* :has statt einer Klasse aus JavaScript — der gewaehlte Zustand steht damit
   schon beim ersten Zeichnen richtig, auch wenn das Skript noch laedt. */
.ang-wahl:has(input:checked){border-color:var(--accent);background:var(--accent-soft)}
.ang-wahl-body{display:block;flex:1 1 auto;min-width:0}
.ang-wahl-titel{display:flex;gap:10px;justify-content:space-between;align-items:baseline;
  font-weight:600;font-size:13.5px}
.ang-wahl-text{display:block;color:var(--muted);font-size:12.5px;margin-top:3px;line-height:1.45}
.ang-preis{flex:0 0 auto;font-variant-numeric:tabular-nums;color:var(--muted);font-weight:600;white-space:nowrap}
.ang-wahl:has(input:checked) .ang-preis{color:var(--ink)}

/* Ja/Nein: eine Zeile, Haken vorn, Frage daneben — eine zweite Ueberschrift
   darueber waere dieselbe Aussage zweimal. */
.ang-schalter{display:flex;gap:9px;align-items:flex-start;margin:0;font-weight:500;font-size:13.5px;cursor:pointer}
.ang-schalter input{width:auto;margin:2px 0 0;accent-color:var(--accent)}

/* „Immer enthalten“: eine Liste ohne Kaestchen. Absichtlich nicht als
   ausgegraute Haken dargestellt — abgehakte Felder laden zum Klicken ein, und
   ein Klick, der nichts tut, wirkt wie ein Fehler. */
.ang-immer{margin:12px 0 0;padding:0;list-style:none;display:grid;gap:6px}
.ang-immer li{position:relative;padding-left:20px;font-size:13.5px;color:var(--ink)}
.ang-immer li::before{content:"";position:absolute;left:4px;top:8px;width:6px;height:6px;
  border-radius:var(--r-pill);background:var(--accent)}

.ang-summe{display:grid;gap:4px}
.ang-summe-zeile{display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  font-size:14px;padding:5px 0;border-bottom:1px solid var(--line)}
.ang-summe-zeile strong{font-variant-numeric:tabular-nums;font-size:16px}
.ang-summe p{margin:6px 0 0}

/* Die Zusammensetzung der Summen. Sie steht unter dem Ergebnis, nicht
   anstelle: erst was unterm Strich steht, dann woraus es besteht — in dieser
   Reihenfolge liest man im Kundengespraech. */
/* Auf- und zuklappen ueber die Zeilenhoehe des Rasters: 0fr auf 1fr laesst
   sich weich uebergehen, eine Hoehe von `auto` nicht. Das innere Feld muss
   dafuer ueberstehenden Inhalt abschneiden und `min-height:0` tragen, sonst
   bleibt es auf seiner Mindesthoehe stehen und nichts bewegt sich. */
/* Der wiedergefundene Entwurf steht oben im Bogen und ist am Akzentrand als
   Angebot zum Weitermachen erkennbar, nicht als Fehlermeldung. */
.ang-entwurf{border-color:var(--accent);background:var(--accent-soft)}
.ang-entwurf .btnrow{margin-top:10px}

/* Die drei Schalter nebeneinander. Der Zaehlerkreis haengt oben rechts ueber
   der Ecke des Knopfes, deshalb braucht die Reihe oben etwas Luft — sonst
   schneidet die Karte ihn ab. */
.ang-klappreihe{display:flex;flex-wrap:wrap;gap:8px;margin:18px 0 0;padding-top:8px}
.ang-klapp{position:relative;gap:6px}
.ang-klapp[hidden]{display:none!important}
.ang-klapp.is-offen{border-color:var(--accent)}
.ang-zaehler{position:absolute;top:-8px;right:-8px;min-width:11px;height:17px;padding:0 5px;
  display:inline-flex;align-items:center;justify-content:center;border-radius:var(--r-pill);
  font-size:11px;font-weight:700;line-height:1;font-variant-numeric:tabular-nums;
  background:var(--ink);color:var(--panel);border:2px solid var(--panel)}
/* Rot heisst: hier geht es ohne nicht weiter. Gelb heisst: nachdenken, dann
   selbst entscheiden. Die Toene sind dieselben wie in den frueheren Kaesten,
   damit niemand zwei Farbsprachen lernen muss. */
.ang-klapp-fehler{background:#fef2f2;border-color:#fca5a5;color:#b42318;--fill:#fee2e2}
.ang-klapp-fehler .ang-zaehler{background:#dc2626;color:#fff}
.ang-klapp-warnung{background:#fffbeb;border-color:#fcd34d;color:#92400e;--fill:#fef3c7}
.ang-klapp-warnung .ang-zaehler{background:#d97706;color:#fff}

.ang-klappfeld{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .32s cubic-bezier(.2,.8,.2,1)}
.ang-klappfeld.is-offen{grid-template-rows:1fr}
.ang-klappinnen{overflow:hidden;min-height:0}
/* Ein langer Zahlungsplan darf die Vorschau nicht wieder aus dem Bild
   schieben: das Feld hoert bei einem Drittel der Fensterhoehe auf und rollt
   in sich selbst weiter. */
.ang-klapp-scroll{max-height:32vh;overflow:auto;overscroll-behavior:contain}
.ang-klapp-kopf{margin:12px 0 0}
.ang-auf-fuss{margin-top:12px;display:flex;justify-content:flex-end}
@media (prefers-reduced-motion:reduce){.ang-klappfeld{transition:none}}

/* Was fehlt, steht als Zeile mit dem Weg dorthin daneben. */
.ang-fehltliste{display:grid;gap:6px;margin-top:10px}
.ang-fehltzeile{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:7px 10px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--ctl-bg)}
.ang-fehlttitel{display:block;font-size:13px;font-weight:600;line-height:1.35}
.ang-fehltgruppe{display:block;font-size:11.5px;color:var(--muted)}
.ang-fehltknopf{flex:0 0 auto}
.ang-warnliste{margin:10px 0 0;padding-left:18px;display:grid;gap:7px;font-size:13px}
/* Auch ein Hinweis nennt jetzt sein Feld und bekommt denselben Sprungknopf
   wie eine fehlende Angabe: „Zum Sonderpreis fehlt eine Begruendung“ zu lesen
   und die Frage dann suchen zu muessen, war die haeufigere Haelfte der Arbeit. */
.ang-warnliste li{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.ang-warnliste li>span{min-width:0}

.ang-aufstellung{margin-top:14px;display:grid;gap:14px}
.ang-auf-gruppe h4{margin:0 0 5px;font-size:12px;text-transform:uppercase;
  letter-spacing:.04em;color:var(--muted)}
.ang-pos{display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  font-size:13px;padding:3px 0;line-height:1.4}
.ang-pos span:last-child{flex:0 0 auto;font-variant-numeric:tabular-nums}
.ang-pos-summe{border-top:1px solid var(--line);margin-top:3px;padding-top:5px;font-weight:600}
.ang-pos-leise{color:var(--muted);text-decoration:line-through}
.ang-pos-gut span:last-child{color:#15803d}

.ang-hinweis{border-radius:var(--r-sm);padding:9px 12px;font-size:13px}
/* Fehler- und Warnblock standen Kante an Kante und sahen aus wie ein einziger
   zweifarbiger Kasten. */
.ang-hinweis+.ang-hinweis{margin-top:8px}
.ang-hinweis ul{margin:0;padding-left:18px;display:grid;gap:3px}
.ang-hinweis-kopf{margin:0 0 6px}
.ang-hinweis-fehler{background:#fef2f2;color:#b42318;border:1px solid #fca5a5}
.ang-hinweis-warnung{background:#fffbeb;color:#92400e;border:1px solid #fcd34d}
/* Was noch fehlt, bevor jemand etwas falsch gemacht hat: derselbe Inhalt,
   aber im Ton einer Wegbeschreibung statt einer Ruege. */
.ang-hinweis-offen{background:var(--accent-soft);color:var(--ink);border:1px solid var(--line)}

/* Offene Pflichtangabe direkt an der Frage. Der Streifen links reicht — ein
   roter Rahmen um jedes noch unbeantwortete Feld sieht beim Oeffnen des
   Bogens aus, als waere schon alles schiefgegangen. */
.ang-frage.is-offen{border-left:2px solid var(--line);padding-left:11px;margin-left:-13px}
.ang-frage.is-fehlt{border-left-color:#dc2626}
.ang-frage.is-fehlt .ang-titel::after,
.ang-frage.is-fehlt .ang-schalter>span::after{content:" — fehlt noch";color:#b42318;font-weight:500}
/* Nach einem Sprung aus der Liste: kurz aufleuchten, damit man die Frage
   zwischen den anderen sofort findet. */
.ang-frage.is-gezielt{background:var(--accent-soft);border-radius:var(--r-sm);
  box-shadow:0 0 0 8px var(--accent-soft)}
.ang-frage{transition:background .4s ease,box-shadow .4s ease}

.ang-preis-frei{font-weight:500;opacity:.75}
.ang-preis-gut{color:#15803d}

.ang-luecken{margin:12px 0 0;padding-left:18px;display:grid;gap:5px;font-size:13.5px}

/* Kontaktsuche: die Vorschlaege liegen ueber dem Formular, nicht darin —
   sonst ruckt beim Tippen alles darunter nach unten. */
.ang-such{position:relative}
.ang-vorschlaege{position:absolute;z-index:20;left:0;right:0;top:calc(100% + 4px);
  margin:0;padding:4px;list-style:none;max-height:260px;overflow:auto;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r-sm);
  box-shadow:0 10px 30px rgba(0,0,0,.14)}
.ang-vorschlaege[hidden]{display:none}
.ang-vorschlaege li{padding:7px 9px;border-radius:var(--r-sm);cursor:pointer;line-height:1.35}
.ang-vorschlaege li:hover,.ang-vorschlaege li.is-marke{background:var(--accent-soft)}
.ang-vor-titel{display:block;font-size:13.5px;font-weight:600}
.ang-vor-zusatz{display:block;font-size:12px;color:var(--muted)}
.ang-kontaktwahl{padding-bottom:14px;border-bottom:1px dashed var(--line)}

.ang-kopf{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}
/* Waehrend die Vorschau laeuft: der Rahmen wird blass, der Rest bleibt
   bedienbar. Ein Sperrbalken ueber dem ganzen Formular waere schlimmer als
   die Wartezeit selbst. */
.is-busy .ang-rahmen{opacity:.55;transition:opacity .2s ease}

/* Kleinkram, den der Bogen braucht und der noch nirgends stand. */
.mt-xs{margin-top:4px}
.ta-r{text-align:right}
form.inline{display:inline}

html[data-theme="dark"] .ang-rahmen iframe{background:#fff}
html[data-theme="dark"] .ang-hinweis-fehler{background:#2a1518;color:#fca5a5;border-color:#7f1d1d}
html[data-theme="dark"] .ang-hinweis-warnung{background:#2a2213;color:#fcd34d;border-color:#78500f}
/* Die Schalter tragen dieselben Farbwelten wie die Hinweisboxen, nur eine Stufe
   dunkler: der Zaehlerkreis sitzt auf dem Schalterrand und braucht seinen Ring
   in der Panel-Farbe, sonst schwimmt er im Dunkeln. */
/* Die :not-Kette steht hier nicht aus Ziererei: die allgemeine Dunkelregel fuer
   Knoepfe traegt genau diese drei Ausschluesse und waere sonst spezifischer —
   die Schalter kaemen grau statt rot und gelb heraus. */
html[data-theme="dark"] .ang-klapp-fehler:not(.btn-primary):not(.btn-danger):not(.btn-ghost){background:#2a1518;border-color:#7f1d1d;color:#fca5a5;--fill:#3a1d20}
html[data-theme="dark"] .ang-klapp-warnung:not(.btn-primary):not(.btn-danger):not(.btn-ghost){background:#2a2213;border-color:#78500f;color:#fcd34d;--fill:#3a2f18}
html[data-theme="dark"] .ang-zaehler{background:#e2e8f0;color:#0f1727;border-color:var(--panel)}
/* Das hellere #ef4444 traegt weissen Text nur mit 3,76:1 — fuer 11 px fett zu
   wenig. #dc2626 kommt auf 4,83:1 und sieht auf dunklem Grund kaum anders aus. */
html[data-theme="dark"] .ang-klapp-fehler .ang-zaehler{background:#dc2626;color:#fff}
html[data-theme="dark"] .ang-klapp-warnung .ang-zaehler{background:#f59e0b;color:#231a05}
html[data-theme="dark"] .ang-reiter-zaehler{background:#f59e0b;color:#231a05}
html[data-theme="dark"] .ang-reiter.hat-offen:not(.is-aktiv){border-color:#a16207}
html[data-theme="dark"] .ang-reiter.hat-pflicht .ang-reiter-zaehler{background:#dc2626;color:#fff}
html[data-theme="dark"] .ang-reiter.hat-pflicht:not(.is-aktiv){border-color:#7f1d1d}
html[data-theme="dark"] .ang-pos-gut span:last-child{color:#4ade80}
html[data-theme="dark"] .ang-preis-gut{color:#4ade80}
html[data-theme="dark"] .ang-frage.is-fehlt .ang-titel::after,
html[data-theme="dark"] .ang-frage.is-fehlt .ang-schalter>span::after{color:#fca5a5}

/* ====================================================================
   Ansicht als jemand anderes

   Der Streifen liegt ueber der ganzen Anwendung und nicht in der Seite,
   weil er nicht zu einem Bereich gehoert, sondern zum Zustand des
   Fensters. Er faehrt nicht mit, sondern bleibt oben stehen — wer im CRM
   nach unten scrollt, soll nicht vergessen, dass er fremd schaut.

   Warnfarbe statt Akzentfarbe: der Akzent gehoert der Firma und wechselt
   je nach Branding, ausgerechnet dieser Hinweis darf aber nicht in der
   Hausfarbe untergehen. Bernstein liest sich als „Achtung, kein
   Normalbetrieb", ohne wie ein Fehler auszusehen.

   Die Hoehe steht in einer Variablen, weil die drei 100vh-Boxen darunter
   (shell, sidebar, main) genau um diesen Betrag kuerzer werden muessen —
   sonst haengt unten ein Streifen aus dem Fenster, den niemand erreicht. */
.viewas-bar{--viewas-h:46px;position:sticky;top:0;z-index:70;display:flex;align-items:center;gap:12px;
  min-height:var(--viewas-h);padding:6px 16px;background:#b45309;color:#fff;
  box-shadow:0 1px 0 rgba(0,0,0,.18)}
.viewas-ico{flex:0 0 auto;opacity:.95}
.viewas-txt{display:flex;flex-direction:column;line-height:1.25;min-width:0}
.viewas-txt strong{font-size:13.5px;font-weight:600}
.viewas-txt span{font-size:12px;opacity:.9}
.viewas-end{margin-left:auto;flex:0 0 auto}
/* Der Knopf sitzt auf gesaettigtem Bernstein. Die uebliche weisse Flaeche
   wuerde dort schreien und wie die Hauptaktion der Seite wirken — er ist
   aber nur der Rueckweg. */
.viewas-end .btn{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.45);color:#fff}
.viewas-end .btn:hover{background:rgba(255,255,255,.24)}
body.is-viewas .shell,
body.is-viewas .sidebar,
body.is-viewas .main{height:calc(100vh - 46px)}
@media (max-width:720px){
  /* Auf dem Telefon bricht der Text um; der Knopf rutscht in die zweite
     Zeile, statt die Ueberschrift auf zwei Zeichen zusammenzudruecken. */
  .viewas-bar{flex-wrap:wrap;--viewas-h:76px}
  .viewas-end{margin-left:26px}
  body.is-viewas .shell,
  body.is-viewas .sidebar,
  body.is-viewas .main{height:calc(100vh - 76px)}
}
html[data-theme="dark"] .viewas-bar{background:#92400e}

/* ── Aufklappbare Erklärtexte ─────────────────────────────────────────────
   Die Überschrift trägt den Knopf rechts; der Text darunter wächst und
   schrumpft weich. Die Animation läuft über grid-template-rows, weil das
   ohne bekannte Zielhöhe funktioniert — eine feste Höhe wäre nach der
   nächsten Textänderung falsch, und „auto" lässt sich nicht überblenden. */
.klapp{margin:0}
.klapp-kopf{display:flex;align-items:center;justify-content:space-between;gap:12px}
.klapp-kopf .subhd{margin:0}
.klapp-knopf{position:relative;isolation:isolate;display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;
  background:none;border:1px solid var(--line-ctl,#d8dde6);border-radius:999px;
  padding:3px 10px 3px 12px;font:inherit;font-size:12px;line-height:1.6;
  color:var(--muted,#667085);cursor:pointer;--fill:none;
  will-change:transform;
  transition:transform .22s cubic-bezier(.2,.8,.2,1),border-color .18s ease,color .18s ease,background .18s ease}
.klapp-knopf::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;
  background:var(--accent-soft);clip-path:circle(0% at var(--mx,50%) var(--my,50%));
  transition:clip-path .45s cubic-bezier(.2,.8,.2,1)}
.klapp-knopf:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.klapp-knopf:hover{color:var(--ink,#111827);border-color:var(--ink,#111827)}
.klapp-pfeil{width:14px;height:14px;transition:transform .28s ease}
.klapp-knopf[aria-expanded="true"] .klapp-pfeil,
.klappz-kopf[aria-expanded="true"] .klapp-pfeil,
.klappk-kopf[aria-expanded="true"] .klapp-pfeil{transform:rotate(180deg)}
.klapp-leib{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .28s ease,opacity .2s ease,margin-top .28s ease;
  opacity:0;margin-top:0}
.klapp-leib.is-offen{grid-template-rows:1fr;opacity:1;margin-top:8px}
.klapp-inhalt{overflow:hidden;min-height:0}
.klapp-inhalt > :first-child{margin-top:0}
.klapp-inhalt > :last-child{margin-bottom:0}
html[data-theme="dark"] .klapp-knopf{border-color:var(--line-ctl,#2b3852)}
html[data-theme="dark"] .klapp-knopf:hover{color:#e8edf7;border-color:#4a5a78}
/* Wer Bewegung im System abgestellt hat, bekommt hier auch keine. */
@media (prefers-reduced-motion: reduce){
  .klapp-leib,.klapp-pfeil{transition:none}
}

/* Aufklappbarer Kasten, bei dem die ganze Kopfzeile schaltet. Optisch der
   Nachfolger von .scriptwrap — nur dass die Höhe jetzt weich läuft statt zu
   springen. Der Rahmen liegt außen, der Pfeil dreht sich mit. */
.klappz{border:1px solid var(--line);border-radius:var(--radius);margin-top:10px;background:var(--bg);
  transition:border-color .18s ease}
.klappz:hover{border-color:var(--line-ctl,var(--line))}
.klappz-kopf{display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  background:none;border:0;padding:10px 12px;font:inherit;font-size:13.5px;color:inherit;cursor:pointer;--fill:none}
.klappz-kopf strong{font-weight:600}
.klappz .klapp-leib{padding:0 12px}
.klappz .klapp-leib.is-offen{margin-top:0;padding-bottom:12px}

/* Dieselbe Mechanik als ganze Karte (siehe R.klappKarte).
   Die Polsterung der Karte wird auf 0 gesetzt und wandert in Kopf und Leib —
   sonst bliebe rings um die Kopfzeile ein toter Rand, auf dem ein Klick
   nichts auslöst, obwohl er sichtbar in der Kopfzeile landet. */
.klappk{padding:0;overflow:hidden}
.klappk-kopf{display:flex;align-items:center;gap:10px;width:100%;text-align:left;
  background:none;border:0;padding:14px 20px;font:inherit;color:inherit;cursor:pointer;--fill:none;
  transition:background .16s ease}
.klappk-kopf:hover{background:rgba(17,24,39,.035)}
.klappk-titel{font-size:15px;font-weight:600;flex:0 0 auto}
.klappk .klapp-pfeil{flex:0 0 auto;color:var(--muted);width:15px;height:15px}
/* Die Kurzfassung schiebt sich nach rechts und darf schrumpfen, aber nie den
   Titel verdrängen — deshalb steht das min-width:0 hier und nicht am Titel. */
.klappk-kurz{margin-left:auto;display:flex;align-items:center;gap:8px;min-width:0;
  font-size:13px;color:var(--muted);overflow:hidden}
.klappk-kurz > .avatar{width:26px;height:26px;font-size:10px}
.klappk-kurz .klappk-name{color:var(--ink);font-weight:600;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.klappk .klapp-leib{padding:0 20px}
.klappk .klapp-leib.is-offen{margin-top:0;padding-bottom:18px}
.klappk .klapp-inhalt > :first-child{margin-top:0}
html[data-theme="dark"] .klappk-kopf:hover{background:rgba(255,255,255,.045)}
@media(max-width:640px){
  .klappk-kopf{padding:12px 14px}
  .klappk .klapp-leib{padding:0 14px}
  .klappk .klapp-leib.is-offen{padding-bottom:14px}
}

/* ── Suchleiste ───────────────────────────────────────────────────────────
   Eine für alle Bereiche. Sie sitzt in derselben Formensprache wie die
   übrigen Bedienelemente: gleiche Höhe, gleicher Radius, gleiche Ränder —
   die bisherige Suche bei den Rechnungen war ein nacktes Eingabefeld und
   sah aus, als gehöre sie nicht dazu. */
.suche{position:relative;display:flex;align-items:center;gap:8px;margin-bottom:14px;max-width:520px}
.suche-ic{position:absolute;left:11px;width:16px;height:16px;pointer-events:none;
  color:var(--muted);opacity:.75}
.suche-feld{width:100%;margin:0;padding-left:34px;padding-right:112px;height:38px;
  border-radius:999px;-webkit-appearance:none;appearance:none}
.suche-feld::-webkit-search-cancel-button{display:none}
.suche-leer{position:absolute;right:12px;display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;border:0;border-radius:50%;background:var(--ctl-bg);cursor:pointer;
  color:var(--muted);--fill:none;padding:0}
.suche-leer[hidden]{display:none}
.suche-leer svg{width:13px;height:13px}
.suche-leer:hover{color:var(--ink)}
.suche-zahl{position:absolute;right:42px;font-size:11.5px;color:var(--muted);
  pointer-events:none;white-space:nowrap;font-variant-numeric:tabular-nums}
.suche-leerzeile td{text-align:center;color:var(--muted);padding:18px 12px}
@media (max-width:720px){ .suche{max-width:none} }
/* Vom Filter ausgeblendet. Eigene Klasse statt des hidden-Attributs, weil
   dessen Wirkung von jeder display-Regel im Stylesheet überschrieben wird. */
.suche-weg{display:none!important}

/* ── Zeilenmenü (drei Punkte) ─────────────────────────────────────────────
   Die Liste wird per JS auf feste Bildschirmkoordinaten gesetzt, statt im
   Fluss der Tabelle zu stehen. Grund: eine Tabelle steckt in einem Rahmen
   mit eigenem Scroll, und ein absolut positioniertes Menü darin wird an
   dessen Kante abgeschnitten — ausgerechnet in der letzten Zeile, wo man es
   am häufigsten braucht. */
.rmenu{display:inline-block;position:relative}
.rmenu-knopf{position:relative;isolation:isolate;display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;padding:0;border:1px solid transparent;border-radius:var(--r-sm);
  background:transparent;color:var(--muted);cursor:pointer;--fill:var(--accent-soft);
  will-change:transform;transition:transform .22s cubic-bezier(.2,.8,.2,1),color .15s ease,border-color .15s ease}
.rmenu-knopf::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:var(--fill);
  clip-path:circle(0% at var(--mx,50%) var(--my,50%));transition:clip-path .45s cubic-bezier(.2,.8,.2,1)}
.rmenu-knopf:hover{color:var(--ink);border-color:var(--line-ctl)}
.rmenu-knopf:hover::before{clip-path:circle(150% at var(--mx,50%) var(--my,50%))}
.rmenu-knopf[aria-expanded="true"]{color:var(--ink);border-color:var(--line-ctl);background:var(--ctl-bg)}
/*
 * Zwei Angaben, die am Telefon beide gebraucht werden — und beide fehlten.
 *
 * DAS DVH. `100vh` ist am Telefon die GROSSE Ansicht: die Höhe, die der
 * Bildschirm hätte, wenn die Adresszeile des Browsers eingeklappt wäre. Sie
 * ist also grösser als das, was man wirklich sieht. Damit durfte das Menü
 * höher werden als das sichtbare Fenster — und weil es innerhalb seiner
 * eigenen Begrenzung dann gar nicht überlief, gab es nichts zu scrollen. Der
 * Finger erwischte stattdessen die Seite dahinter, und die unteren Einträge
 * blieben unerreichbar. Genau so gemeldet: „Löschen" liess sich nicht
 * antippen. `100dvh` ist die Höhe, die gerade wirklich da ist.
 *
 * Und die feste Leiste unten geht ab. Ihre Höhe steht schon in
 * `--tabbar-h` (am Rechner 0px, am Telefon Inhalt plus sicherer Bereich) —
 * dieselbe Quelle, aus der sich `unterkante()` in app.js bedient. Zwei
 * Rechnungen für dieselbe Kante, die auseinanderlaufen können, wären der
 * nächste Fehler dieser Art.
 *
 * DAS OVERSCROLL-BEHAVIOR. Auch ein Menü, das richtig scrollt, gibt am
 * oberen und unteren Ende weiter — der Browser scrollt dann die Seite
 * dahinter. Beim Lesen einer langen Liste ist das jedes Mal ein Sprung.
 * `contain` lässt die Bewegung an der Kante enden.
 */
.rmenu-liste{position:fixed;z-index:80;min-width:216px;padding:6px;
  max-height:calc(100dvh - var(--tabbar-h) - 24px);
  overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  background:var(--card,#fff);border:1px solid var(--line);border-radius:var(--r-md);
  box-shadow:0 18px 44px rgba(16,24,40,.18)}
.rmenu-liste[hidden]{display:none}
.rmenu-liste form{margin:0}
.rmenu-eintrag{display:flex;align-items:center;gap:9px;width:100%;box-sizing:border-box;
  padding:8px 10px;border:0;border-radius:var(--r-sm);background:transparent;color:var(--text);
  font:inherit;font-size:13px;text-align:left;text-decoration:none;cursor:pointer;--fill:none}
.rmenu-eintrag svg{width:15px;height:15px;opacity:.7;flex:0 0 auto}
.rmenu-eintrag:hover{background:var(--accent-soft);color:var(--ink)}
.rmenu-eintrag:hover svg{opacity:1}
.rmenu-eintrag.is-rot{color:#b42318}
.rmenu-eintrag.is-rot:hover{background:#fdecec;color:#8f1d13}
.rmenu-trenner{height:1px;margin:5px 6px;background:var(--line)}
html[data-theme="dark"] .rmenu-liste{background:#111a2b;border-color:#2b3852;box-shadow:0 18px 44px rgba(0,0,0,.5)}
html[data-theme="dark"] .rmenu-eintrag.is-rot{color:#f4a4a0}
html[data-theme="dark"] .rmenu-eintrag.is-rot:hover{background:#3d1c1c;color:#ffc9c5}

/* ── Pipeline-Zeilen ──────────────────────────────────────────────────────
   Feste Spaltenbreiten statt einer Tabelle je Stufe. Vorher rechnete jede
   Stufe ihre Spalten selbst aus — der längste Firmenname in „Gewonnen"
   verschob die Zuständigen dort weiter nach rechts als in „Kontaktiert",
   und die Namen standen von Block zu Block auf anderer Höhe. */
.pipe-liste{list-style:none;margin:0;padding:0}
.pipe-zeile{display:grid;grid-template-columns:minmax(0,1fr) 170px 110px 40px;
  align-items:center;gap:12px;padding:9px 0;border-bottom:1px solid var(--line);font-size:13.5px}
.pipe-zeile:last-child{border-bottom:0}
.pipe-wer{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pipe-firma{color:var(--muted);font-weight:400}
.pipe-zu{color:var(--muted);font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pipe-wert{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.pipe-zeile .rmenu{justify-self:end}
.pipe-kopf{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:6px}
@media (max-width:720px){
  .pipe-zeile{grid-template-columns:minmax(0,1fr) 90px 36px}
  .pipe-zu{display:none}
}

/* ── Abschnitte in der Seitenleiste ───────────────────────────────────────
   Vierzehn gleichrangige Punkte sagen einem Neuling nicht, womit er anfängt.
   Die Überschriften gliedern den Blick und folgen dem Weg eines Auftrags:
   Start, Akquise, Abschluss, Team, System. Klein und leise gehalten — sie
   sollen ordnen, nicht mit den Einträgen konkurrieren. */
.nav-gruppe{display:flex;flex-direction:column;gap:2px}
.nav-gruppe + .nav-gruppe{margin-top:14px}
.nav-gruppe-titel{padding:0 10px 5px;font-size:10.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:#64748b}

/* ── Kanban-Brett ─────────────────────────────────────────────────────────
   Eine Stufe je Spalte, waagerecht scrollbar. Die Spalten haben eine feste
   Breite: gleich breite Spalten machen die Höhe der Stapel vergleichbar, und
   genau darum geht es bei einem Brett — man sieht, wo sich etwas staut. */
.kanban{display:flex;gap:14px;align-items:flex-start;overflow-x:auto;padding-bottom:10px;
  scrollbar-width:thin}
.kb-spalte{flex:0 0 288px;display:flex;flex-direction:column;gap:10px;
  background:var(--ctl-bg);border:1px solid var(--line);border-radius:var(--r-lg,14px);padding:12px;
  max-height:calc(100vh - 260px)}
.kb-kopf{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}
.kb-kopf h3{margin:0;font-size:13.5px;letter-spacing:.01em}
.kb-zahl{display:block;margin-top:2px;font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.kb-plus{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  border-radius:var(--r-sm);color:var(--muted);text-decoration:none;--fill:none;flex:0 0 auto;
  border:1px solid transparent;transition:color .15s ease,border-color .15s ease,background .15s ease}
.kb-plus:hover{color:var(--accent);border-color:var(--line-ctl);background:var(--card,#fff)}
.kb-karten{display:flex;flex-direction:column;gap:8px;overflow-y:auto;min-height:52px;
  border-radius:var(--r-md);transition:background .15s ease,box-shadow .15s ease}
.kb-spalte.is-ziel .kb-karten{background:var(--accent-soft);box-shadow:inset 0 0 0 2px var(--accent)}
.kb-karte{background:var(--card,#fff);border:1px solid var(--line);border-radius:var(--r-md);
  padding:10px 11px;cursor:grab;transition:box-shadow .15s ease,transform .15s ease,opacity .15s ease}
.kb-karte:hover{box-shadow:0 6px 18px rgba(16,24,40,.10)}
.kb-karte.is-zieht{opacity:.45;cursor:grabbing}
.kb-karte-kopf{display:flex;align-items:center;justify-content:space-between;gap:6px}
.kb-name{font-weight:600;font-size:13.5px;color:var(--text);text-decoration:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kb-name:hover{color:var(--accent)}
.kb-firma{color:var(--muted);font-size:12.5px;margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kb-fuss{display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin-top:8px;font-size:11.5px}
.kb-wert{font-variant-numeric:tabular-nums;font-weight:600}
.kb-zu{color:var(--muted);margin-left:auto}
.kb-leer{margin:0;padding:14px 8px;text-align:center;color:var(--muted);font-size:12.5px;
  border:1px dashed var(--line-ctl);border-radius:var(--r-md)}
html[data-theme="dark"] .kb-karte{background:#0f1725}
html[data-theme="dark"] .kb-plus:hover{background:#0f1725}
@media (max-width:720px){ .kb-spalte{flex-basis:82vw;max-height:none} }

/* Das Zeilenmenü war zu leise — als reines Symbol ohne Rahmen hat es
   schlicht niemand gesehen. Jetzt trägt es dieselbe Umrandung wie ein
   kleiner Knopf und ist damit als Bedienelement erkennbar. */
.rmenu-knopf{border-color:var(--line-ctl);background:var(--ctl-bg)}
.rmenu-knopf svg{opacity:.85}
.rmenu-knopf:hover svg{opacity:1}
/* Auswahlfeld im Zeilenmenü — für Angaben, die man wechselt statt auslöst. */
.rmenu-feld{padding:6px 10px 8px}
.rmenu-feld label{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--muted);margin-bottom:5px}
.rmenu-feld label svg{width:15px;height:15px;opacity:.7}
.rmenu-feld select{margin:0;height:32px;font-size:12.5px}
.rmenu-eingabe{display:flex;gap:6px;align-items:center}
.rmenu-eingabe input{margin:0;height:32px;font-size:12.5px}
.rmenu-eingabe .btn{flex:0 0 auto;height:32px}

/* ── Aufgaben und Kalender ────────────────────────────────────────────────
   Der Haken ist ein Knopf, kein Kästchen: er löst etwas aus, statt einen
   Zustand einzustellen, den man danach noch abschicken müsste. */
.hakenknopf{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;
  border:1.5px solid var(--line-ctl);border-radius:50%;background:transparent;color:transparent;
  cursor:pointer;padding:0;transition:border-color .15s ease,background .15s ease,color .15s ease}
.hakenknopf:hover{border-color:var(--accent);color:var(--accent)}
.hakenknopf.is-an{background:var(--accent);border-color:transparent;color:var(--accent-ink)}
.ist-erledigt td:nth-child(2){text-decoration:line-through;opacity:.6}
.zeitpaar{display:flex;gap:8px}
.zeitpaar input{margin-top:0}

.kal-kopf{display:flex;align-items:center;gap:14px;margin-bottom:12px}
.kal-kopf h3{margin:0;font-size:15px}
/* Ganz links eine schmale Spalte für die Kalenderwoche. `auto` und nicht eine
   feste Breite: zweistellig ist der Normalfall, aber die Spalte soll auch bei
   „53" nicht die Tage zusammendrücken. */
.kal-gitter{display:grid;grid-template-columns:auto repeat(7,minmax(0,1fr));gap:6px}
.kal-wt{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);padding:2px 4px}
.kal-kw-kopf{text-align:center;padding-left:0;padding-right:0}
.kal-kw{display:flex;align-items:center;justify-content:center;min-width:26px;
  font-size:11.5px;font-weight:700;color:var(--muted);text-decoration:none;
  font-variant-numeric:tabular-nums;border-radius:var(--r-sm)}
.kal-kw:hover{color:var(--accent-text);background:var(--accent-soft)}
.kal-tag{min-height:92px;border:1px solid var(--line);border-radius:var(--r-md);padding:6px;
  display:flex;flex-direction:column;gap:3px;background:var(--card,#fff)}
.kal-tag.ist-leer{border-style:dashed;opacity:.35;background:transparent}
.kal-tag.ist-heute{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
.kal-nr{font-size:11.5px;font-weight:700;color:var(--muted)}
.kal-tag.ist-heute .kal-nr{color:var(--accent)}
/* Ein Eintrag ist jetzt ein Knopf und kein Verweis: er öffnet das Fenster
   über der Seite, statt eine Unterseite zu laden. Damit er trotzdem aussieht
   wie vorher, muss ihm die Knopf-Grundform ausgetrieben werden. */
.kal-eintrag{display:block;width:100%;text-align:left;border:0;cursor:pointer;font-family:inherit;
  font-size:11.5px;line-height:1.35;padding:3px 5px;border-radius:var(--r-sm);
  background:var(--accent-soft);color:var(--ink);text-decoration:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kal-eintrag:hover{background:var(--accent);color:var(--accent-ink)}
.kal-eintrag.ist-aufgabe{background:transparent;border:1px solid var(--line-ctl)}
.kal-eintrag.ist-aufgabe svg{width:11px;height:11px;vertical-align:-1px;opacity:.7}
.kal-eintrag.ist-fertig{opacity:.5;text-decoration:line-through}
.kal-mehr{display:block;font-size:11px;color:var(--muted);text-decoration:none;padding:1px 5px}
.kal-mehr:hover{color:var(--accent-text)}
.kal-tag[data-neu]{cursor:pointer}
.kal-tag[data-neu]:hover{border-color:var(--accent)}
html[data-theme="dark"] .kal-tag{background:#0f1725}
@media (max-width:720px){
  .kal-tag{min-height:64px}
  .kal-eintrag{font-size:10.5px}
}

/* Löschen ist rot, nicht in der Akzentfarbe. Ein Verweis, der aussieht wie
   jeder andere, wird angeklickt wie jeder andere — und danach ist etwas weg.
   Bei den Vorlagen war das so; die Klasse gilt jetzt überall. */
.link-danger{color:#b42318}
.link-danger:hover{color:#8f1d13;text-decoration:underline}
html[data-theme="dark"] .link-danger{color:#f4a4a0}
html[data-theme="dark"] .link-danger:hover{color:#ffc9c5}
/* Ein Pfeil ohne Nachbarn bleibt stehen, statt zu verschwinden — sonst
   springen die übrigen Knöpfe bei jedem Datensatz an eine andere Stelle. */
.nachbarn{display:inline-flex;gap:4px;vertical-align:middle}
.btn.is-aus{opacity:.35;pointer-events:none;cursor:default}

/* Spaltenwähler — sitzt rechts über der Tabelle, in derselben Zeile wie die
   Suche. Er ist ein Zahnrad und kein Text: er wird selten benutzt und soll
   die Suche daneben nicht überstrahlen. */
/* Suche links, Zahnrad ganz rechts — auf einer Hoehe, aber nicht aneinander
   geklebt. Das Zahnrad gehoert zur Tabelle als Ganzes und nicht zur Suche;
   steht es direkt daneben, liest es sich wie eine Einstellung der Suche. */
/* `flex-wrap` und `min-width:0` — die beiden Eigenschaften, ohne die sich
   Kontakte, Angebote, Rechnungen und das CRM am Telefon seitlich verschieben
   liessen. Die Suche konnte nicht unter ihre Eigenbreite schrumpfen (das
   Feld traegt 34px Platz fuer die Lupe plus Innenabstand, und die Schrift
   wird am Telefon auf 16px hochgesetzt, damit iOS nicht hineinzoomt). Was
   nicht schrumpfen kann und nicht umbrechen darf, schiebt — und zwar die
   ganze Seite mitsamt Kopfzeile. */
.tabellenkopf{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:14px}
.tabellenkopf .suche{margin-bottom:0;flex:1 1 260px;min-width:0;max-width:520px;margin-right:auto}
.spaltenwahl{position:relative;flex:0 0 auto;margin-left:auto}
.spalten-liste{min-width:240px;max-height:min(70vh,420px)}
.spalten-kopf{padding:6px 10px 8px;font-size:11px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted)}
.spalten-zeile{display:flex;align-items:center;gap:9px;padding:7px 10px;border-radius:var(--r-sm);
  font-size:13px;cursor:pointer}
.spalten-zeile:hover{background:var(--accent-soft)}
.spalten-zeile input{width:auto;margin:0}
.spalten-zeile.ist-pflicht{opacity:.55;cursor:default}
.spalten-zeile.ist-pflicht:hover{background:transparent}
.spalten-fuss{padding:8px 10px 4px;border-top:1px solid var(--line);margin-top:5px}

/* ── Sortieren per Klick auf den Spaltenkopf ──────────────────────────────
   Der Pfeil steht immer im Fluss, auch unsortiert — nur dann durchsichtig.
   Erschiene er erst beim Sortieren, spraenge die Spaltenbreite beim ersten
   Klick, und die halbe Tabelle rueckte zur Seite. */
th[data-sortier]{cursor:pointer;user-select:none;white-space:nowrap}
th[data-sortier]:hover{color:var(--ink)}
th[data-sortier] .sort-pfeil{display:inline-block;width:11px;margin-left:5px;
  opacity:0;transition:opacity .15s ease;font-size:10px;vertical-align:1px}
th[data-sortier]:hover .sort-pfeil{opacity:.4}
th[data-sortier][aria-sort] .sort-pfeil{opacity:1;color:var(--accent-text)}
th[data-sortier][aria-sort]{color:var(--accent-text)}

/* ── Belege am Kontakt ────────────────────────────────────────────────────
   Die Zeile über der Liste beantwortet die zweite Frage sofort: steht hier
   noch Geld aus? Ohne sie müsste man die Spalte „Offen" im Kopf addieren. */
.belegsummen{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 12px;
  font-size:13px;color:var(--muted)}
.ist-spaet{color:var(--rot,#e5484d);font-weight:600}

/* ══════════════════════════════════════════════════════════════════════════
   Kalender: Leiste, Zeitgitter, Fenster
   ══════════════════════════════════════════════════════════════════════════ */

/*
 * Die Tagesansicht ist eine Sache fürs Telefon.
 *
 * Am grossen Schirm ist ein einzelner Tag eine Spalte in der Mitte und
 * daneben Leere; die Woche zeigt dasselbe und sechs Tage mehr, ohne dass
 * etwas kleiner würde. Am Telefon ist es umgekehrt.
 *
 * Dieselbe Grenze steht im Skript, das den Merkzettel setzt, und im Server,
 * der eine Adresse mit `ansicht=tag` daraufhin auf die Woche umleitet. Wer
 * sie hier ändert, ändert sie dort mit — sonst blendet das CSS den Reiter aus
 * und der Server schickt einen trotzdem hin.
 */
@media (min-width:1101px){ .untertab.nur-schmal{display:none} }

/* Der Tag, der in der Woche gemeint war. Ein Rahmen und kein Farbklecks: die
   Farbe ist schon für „heute" vergeben, und zwei Farben nebeneinander sagen
   weniger als eine Farbe und eine Kante. */
.zg-tagkopf.ist-gewaehlt .zg-nr{box-shadow:inset 0 0 0 2px var(--accent)}
.zg-spalte.ist-gewaehlt,.zg-obenspalte.ist-gewaehlt{
  background:color-mix(in srgb,var(--accent) 4%,transparent)}
.zg-spalte.ist-gewaehlt{box-shadow:inset 1px 0 0 var(--accent),inset -1px 0 0 var(--accent)}

.kal-leiste{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:12px}
.kal-titel{margin:0;font-size:18px;flex:1 1 auto;min-width:180px}
.kal-leiste .untertabs{margin:0}
.kal-dauer{margin:0}
.kal-dauer label{display:flex;align-items:center;gap:8px;margin:0;font-size:12px;color:var(--muted)}
.kal-dauer select{width:auto;margin:0;height:32px;font-size:12.5px}

/* Kalender und Seitenspalte nebeneinander — und untereinander, sobald es eng
   wird. Die Spalte ist kein Beiwerk: dort stehen die Aufgaben ohne Datum, die
   sonst in keiner Ansicht auftauchen. */
.kal-flaeche{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:16px;align-items:start}
@media (max-width:1100px){ .kal-flaeche{grid-template-columns:minmax(0,1fr)} }
.kal-neben{display:flex;flex-direction:column;gap:16px}

/*
 * ── Beides so hoch wie der Bildschirm, und beide gleich hoch ──
 *
 * Vorher war die Spalte rechts so hoch wie ihr Inhalt: bei zwei Aufgaben ein
 * Stummel neben dem Monatsgitter, bei fünfzehn stand sie unten weit darüber
 * hinaus. Und unter dem Kalender blieb auf einem grossen Schirm Platz leer,
 * während das Monatsgitter oben eng war.
 *
 * Deshalb: die Fläche bekommt die Höhe, die bis zum unteren Rand des Fensters
 * übrig ist, beide Spalten füllen sie (`stretch`), und was rechts nicht
 * hineinpasst, wird dort gescrollt und nicht ausgeschoben.
 *
 * Woher die Höhe kommt: die Fläche trägt `fuellt`, `.main` schiebt auf dieser
 * Seite deshalb nicht und gibt her, was übrig ist. Eine Zahl im CSS wäre hier
 * falsch — über der Fläche stehen Kopfzeile, Leiste und Reiter, und die
 * werden bei schmalem Fenster oder langem Firmennamen zwei Zeilen hoch.
 * Früher hat app.js das gemessen; warum das weg ist, steht oben bei `.fuellt`.
 *
 * Unterhalb von 1100px stehen die beiden untereinander — dort ist eine feste
 * Höhe sinnlos, und zwei Schiebebereiche übereinander wären am Telefon eine
 * Zumutung. Deshalb gilt das alles nur am grossen Schirm: `.fuellt` wirkt erst
 * ab 1101px, und darunter schiebt wieder die ganze Seite als Ganzes.
 */
@media (min-width:1101px){
  /* Die Hoehe kommt aus `.fuellt` weiter oben — `.main` gibt her, was uebrig
     ist, und die Flaeche nimmt es. Frueher stand hier `height:var(--kal-hoehe)`
     und app.js hat gemessen; warum das weg ist, steht oben bei `.fuellt`. */
  .kal-flaeche{align-items:stretch;min-height:420px}
  /* Der Abstand unter einer Karte ist sonst genau der Betrag, um den sie
     niedriger wird als die Spalte daneben — und um den unten Platz frei
     bleibt, den die Fläche schon für sich beansprucht hat. */
  .kal-flaeche>.card,.kal-neben>.card:last-child{margin-bottom:0}
  .kal-flaeche>.card{display:flex;flex-direction:column;min-height:0;overflow:hidden}
  .kal{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
  /* Der Monat darf schieben, wenn der Schirm für sechs Zeilen zu flach ist —
     ein abgeschnittener letzter Wochentag wäre schlimmer. */
  .kal[data-ansicht="monat"]{overflow:auto}
  .kal-gitter{flex:1 1 auto;min-height:0;grid-template-rows:auto;grid-auto-rows:minmax(76px,1fr)}
  .kal-tag{min-height:0}
  .zeitgitter{flex:1 1 auto;display:flex;flex-direction:column;min-height:0}
  .zg-koerper{flex:1 1 auto;height:auto;min-height:0}
  .kal-neben{min-height:0;overflow-y:auto;overscroll-behavior:contain;padding-right:4px}
}
.kal-aufliste,.kal-naechste{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;
  min-width:0}
.kal-auf{display:flex;align-items:flex-start;gap:8px;padding:5px 0;border-bottom:1px solid var(--line);
  min-width:0}
.kal-auf:last-child{border-bottom:0}
.kal-auf form{margin:0;flex:0 0 auto;padding-top:2px}
.kal-auf-text{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:3px;text-align:left;
  background:none;border:0;padding:0;cursor:pointer;font-family:inherit;font-size:13px;color:var(--ink)}
.kal-auf-text:hover>span:first-child{color:var(--accent-text)}
.kal-auf-unten{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}
.kal-auf.ist-fertig .kal-auf-text>span:first-child{text-decoration:line-through;opacity:.55}
.kal-naechste li{padding:6px 0;border-bottom:1px solid var(--line);min-width:0}
.kal-naechste li:last-child{border-bottom:0}
.kal-naechst{display:flex;flex-direction:column;gap:2px;width:100%;min-width:0;text-align:left;background:none;
  border:0;padding:0;cursor:pointer;font-family:inherit;color:var(--ink)}
.kal-naechst-wann{font-size:11.5px;color:var(--muted)}
.kal-naechst-was{font-size:13px;font-weight:600}
.kal-naechst:hover .kal-naechst-was{color:var(--accent-text)}
.kal-naechst-ort{font-size:12px;margin-top:2px;min-width:0}

/*
 * Nichts in der Spalte läuft über ihren Rand hinaus.
 *
 * Der Auslöser war ein Videolink: eine Teams-Adresse ist ein einziges Wort
 * von zweihundert Zeichen, und ein Wort bricht von sich aus nirgends um. Es
 * lief quer über den Kalender und aus der Seite heraus. Dasselbe gilt für
 * einen Termintitel, den jemand ohne Leerzeichen tippt.
 *
 * `anywhere` und nicht `break-word`: break-word bricht ein zu langes Wort
 * erst um, wenn es allein in seiner Zeile steht — steht ein kurzes Wort
 * davor, läuft es trotzdem hinaus. anywhere bricht, sobald es sein muss.
 *
 * Die Kette aus `min-width:0` darüber gehört dazu und ist nicht Beiwerk: ein
 * Flex-Element ist von sich aus nie schmaler als sein längstes Wort. Ohne das
 * würde die Spalte breiter statt der Text kürzer, und der Umbruch käme nie
 * zum Zug.
 */
.kal-auf-text>span,.kal-naechst-wann,.kal-naechst-was,.kal-naechst-ort,
.kal-naechst-ort a,.kal-naechst-ort span{overflow-wrap:anywhere}
/* Der Titel darf zwei Zeilen haben, danach sagt „…" den Rest. Ein Titel, der
   die halbe Spalte füllt, drückt den nächsten Termin aus dem Bild. */
.kal-naechst-was{display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden}
/* Ein Verweis ist von sich aus inline und ignoriert deshalb die Breite seines
   Kastens; als inline-block hält er sich daran. */
.kal-naechst-ort .link{display:inline-block;max-width:100%;vertical-align:bottom}

/* ── Zeitgitter (Tag und Woche) ───────────────────────────────────────────
   Eine Minute ist ein fester Bruchteil eines Pixels. Server und Skript
   rechnen mit derselben Zahl; zwei Umrechnungen, die auseinanderlaufen
   könnten, wären ein Fehler, den man erst bei krummen Zeiten sieht. */
.zeitgitter{--zg-min:0.9px;--zg-gasse:56px}
.zg-kopf{display:grid;grid-template-columns:var(--zg-gasse) repeat(var(--zg-tage,7),minmax(0,1fr));
  gap:1px;position:sticky;top:0;z-index:2;background:var(--card,#fff);padding-bottom:6px}
html[data-theme="dark"] .zg-kopf{background:#0f1725}
.zg-tagkopf{display:flex;flex-direction:column;align-items:center;gap:1px;padding:4px 0}
.zg-wt{font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.zg-nr{font-size:16px;font-weight:700;color:var(--ink);text-decoration:none;
  width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:50%}
.zg-nr:hover{background:var(--accent-soft)}
.zg-tagkopf.ist-heute .zg-nr{background:var(--accent);color:var(--accent-ink)}
.zg-tagkopf.ist-heute .zg-wt{color:var(--accent-text)}

/* Eigener Schiebebereich: 24 Stunden sind knapp 1300 Pixel, und eine Seite,
   die deshalb komplett so lang wird, verliert ihren Kopf aus dem Blick. */
.zg-koerper{position:relative;display:grid;grid-template-columns:var(--zg-gasse) minmax(0,1fr);
  gap:1px;height:min(66vh,700px);overflow-y:auto;overscroll-behavior:contain}
.zg-stunden{position:relative;height:calc(1440 * var(--zg-min))}
.zg-stunde{position:absolute;right:8px;transform:translateY(-50%);font-size:11px;color:var(--muted);
  font-variant-numeric:tabular-nums}
.zg-spalten{position:relative;display:grid;grid-template-columns:repeat(var(--zg-tage,7),minmax(0,1fr));gap:1px}
.zg-spalte{position:relative;height:calc(1440 * var(--zg-min));border-left:1px solid var(--line);
  touch-action:pan-y}
.zg-spalte.ist-heute{background:var(--accent-soft);background:color-mix(in srgb,var(--accent) 6%,transparent)}
.zg-linie{position:absolute;left:0;right:0;height:0;border-top:1px solid var(--line);pointer-events:none}
.zg-termin{position:absolute;overflow:hidden;display:flex;flex-direction:column;gap:1px;
  border:0;border-left:3px solid var(--accent);border-radius:var(--r-sm);
  background:var(--accent-soft);color:var(--ink);padding:2px 5px;text-align:left;cursor:pointer;
  font-family:inherit;font-size:11.5px;line-height:1.25}
.zg-termin:hover{background:var(--accent);color:var(--accent-ink)}
.zg-zeit{font-variant-numeric:tabular-nums;opacity:.75;font-size:10.5px}
.zg-titel{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zg-ort{opacity:.7;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Die Zeile für Ganztägiges steht über dem Schiebebereich und wandert damit
   nicht aus dem Bild, wenn das Gitter zur aktuellen Stunde springt. */
.zg-oben{display:grid;grid-template-columns:var(--zg-gasse) repeat(var(--zg-tage,7),minmax(0,1fr));
  gap:1px;padding:4px 0 6px;border-bottom:1px solid var(--line);margin-bottom:4px}
.zg-obenlabel{font-size:10px;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);
  align-self:center;text-align:right;padding-right:8px}
.zg-obenspalte{display:flex;flex-direction:column;gap:2px;min-height:22px;padding:0 2px;
  border-left:1px solid var(--line)}
.zg-obenspalte.ist-heute{background:color-mix(in srgb,var(--accent) 6%,transparent)}
.zg-ganztags{border:0;border-radius:var(--r-sm);background:var(--accent);color:var(--accent-ink);
  padding:2px 6px;font-size:11px;font-family:inherit;text-align:left;cursor:pointer;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zg-ganztags.ist-aufgabe{background:transparent;border:1px solid var(--line-ctl);color:var(--ink)}
.zg-ganztags.ist-fertig{opacity:.5;text-decoration:line-through}
/* Der Kasten, der beim Ziehen entsteht. */
.zg-zug{position:absolute;left:2px;right:2px;border-radius:var(--r-sm);pointer-events:none;
  background:var(--accent);opacity:.28;border:1px dashed var(--accent);
  display:flex;align-items:flex-start;justify-content:center;font-size:11px;color:var(--accent-ink);
  font-variant-numeric:tabular-nums;padding-top:1px}
/* Die Linie „jetzt". Sie beantwortet die Frage, die man beim Blick auf einen
   Tagesplan als erstes hat: wo stehe ich gerade? */
.zg-jetzt{position:absolute;left:0;right:0;height:0;border-top:2px solid var(--rot,#e5484d);
  pointer-events:none;z-index:1}
.zg-jetzt::before{content:'';position:absolute;left:-4px;top:-5px;width:8px;height:8px;border-radius:50%;
  background:var(--rot,#e5484d)}

/* ── Das Fenster ─────────────────────────────────────────────────────────── */
.kfenster{border:0;padding:0;border-radius:var(--r-lg,14px);width:min(560px,94vw);
  background:var(--card,#fff);color:var(--ink);box-shadow:0 24px 60px rgba(0,0,0,.28)}
html[data-theme="dark"] .kfenster{background:#111a2b}
.kfenster::backdrop{background:rgba(8,12,20,.55);backdrop-filter:blur(2px)}
.kf-kopf{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:16px 18px 10px;border-bottom:1px solid var(--line)}
.kf-kopf h3{margin:0;font-size:16px}
.kf-zu{border:0;background:transparent;color:var(--muted);cursor:pointer;padding:4px;border-radius:var(--r-sm)}
.kf-zu:hover{color:var(--ink);background:var(--accent-soft)}
.kf-leib{padding:14px 18px;display:flex;flex-direction:column;gap:2px;max-height:min(64vh,560px);overflow-y:auto}
.kf-reihe{display:flex;gap:10px;flex-wrap:wrap}
.kf-reihe>label{flex:1 1 150px;margin-bottom:0}
.kf-reihe>label.kf-eng{flex:0 0 120px}
.kf-haken{display:flex;align-items:center;gap:8px;margin:2px 0 10px}
.kf-haken input{width:auto;margin:0}

/* ── Wer ist dabei ─────────────────────────────────────────────────────────
   Zwei Kästchenlisten nebeneinander, jede mit eigenem Schiebebereich. Knapp
   fünf Zeilen hoch: genug, um zu sehen, dass es eine Liste ist, und wenig
   genug, dass darunter die Notiz noch ins Bild passt. */
.kf-wer{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px;margin:2px 0 10px}
@media (max-width:560px){ .kf-wer{grid-template-columns:minmax(0,1fr)} }
.kf-werblock{margin:0;display:flex;flex-direction:column;gap:4px;min-width:0}
.wahlsuche{margin:0}
.wahlkasten{border:1px solid var(--line-ctl);border-radius:var(--r-md);padding:4px;
  max-height:150px;overflow-y:auto;overscroll-behavior:contain;background:var(--card,#fff)}
html[data-theme="dark"] .wahlkasten{background:#0f1725}
.wahlzeile{display:flex;align-items:center;gap:7px;margin:0;padding:4px 6px;border-radius:var(--r-sm);
  cursor:pointer;font-size:13px;font-weight:400;min-width:0}
.wahlzeile:hover{background:var(--accent-soft)}
.wahlzeile input{width:auto;margin:0;flex:0 0 auto}
.wahlzeile>span:first-of-type{overflow-wrap:anywhere;min-width:0}
.wahlzeile>span:nth-of-type(2){margin-left:auto;white-space:nowrap;flex:0 0 auto;padding-left:8px;
  overflow:hidden;text-overflow:ellipsis;max-width:45%}
.wahlzeile[hidden]{display:none}
/* Wer dabei ist, in der Spalte „Als Nächstes". */
.kal-naechst-wer{display:flex;align-items:center;gap:4px;font-size:11.5px;color:var(--muted);
  overflow-wrap:anywhere}
.kal-naechst-wer svg{flex:0 0 auto;opacity:.7}

.kf-fuss{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:12px 18px 16px;border-top:1px solid var(--line)}
.kf-rechts{display:flex;gap:8px;margin-left:auto}
.kf-loeschen[hidden]{display:none}
.kf-ort{display:inline-block;margin-top:5px}
.kf-ort[hidden]{display:none}

/* ══════════════════════════════════════════════════════════════════════════
 * Bewegung: Scrollen, Schatten, Ruhe
 * ══════════════════════════════════════════════════════════════════════════
 *
 * Das Gegenstück zu public/bewegung.js. Dort steht, WARUM Lenis und nicht
 * ScrollSmoother; hier steht nur, was das Aussehen davon braucht.
 * ══════════════════════════════════════════════════════════════════════════ */

/* Lenis rechnet die Scrollstelle selbst aus und setzt sie Bild für Bild.
   Läuft daneben noch `scroll-behavior:smooth` des Browsers, glättet der die
   gesetzten Werte ein zweites Mal — und aus zwei Glättungen wird ein
   Nachschwimmen, das sich anfühlt, als hinge die Seite. */
.lenis.lenis-smooth{scroll-behavior:auto!important}
.lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}
.lenis.lenis-stopped{overflow:hidden}
/* Ein iframe verschluckt das Mausrad, sobald der Zeiger darüber steht — die
   Seite bleibt dann mitten im Scrollen stehen. */
.lenis.lenis-smooth iframe{pointer-events:none}

/* Solange die Seite ganz oben steht, gibt es unter einer stehenbleibenden
   Kopfzeile nichts zu beschatten. Erst wenn Inhalt darunter durchläuft, wird
   der Schatten zur Auskunft: „hier ist noch mehr". */
.viewas-bar,.ang-reiterleiste,.kal-kopfzeile{transition:box-shadow .22s ease}
body.ist-gescrollt .viewas-bar{box-shadow:0 6px 18px rgba(15,23,42,.10)}
body.ist-gescrollt .ang-reiterleiste{box-shadow:0 6px 14px rgba(15,23,42,.07)}
html[data-theme="dark"] body.ist-gescrollt .viewas-bar{box-shadow:0 6px 18px rgba(0,0,0,.45)}

/* Hier stand ein selbstgebauter Rollbalken — und der war ein Fehler, der sich
   erst auf einem Mac zeigte.
   `::-webkit-scrollbar` schaltet den Balken von der ueberlagernden Bauform
   (macOS-Standard: null Pixel Breite, erscheint nur beim Scrollen) auf die
   klassische um, die dauerhaft Platz im Layout belegt. `.main` verlor damit
   zehn Pixel Breite, `.zg-koerper` noch einmal zehn — der Kalender wurde
   sichtbar schmaler und die abgestimmten Hoehen von Raster und Seitenleiste
   stimmten nicht mehr. Dazu kommt, dass Chrome selbstgebaute Rollbalken auf
   dem Hauptfaden zeichnet statt im Compositor; auf langen Listen kostet das
   genau dort Bilder, wo es auffaellt.
   Geblieben sind die zwei Standardangaben. Die sind ein Hinweis und keine
   Umschaltung: wo der Balken ohnehin Platz belegt (Windows, Linux), wird er
   schmaler und bekommt eine passende Farbe — wo er ueberlagert, bleibt er
   ueberlagernd. */
.main,.tblwrap,.zg-koerper,.kal-neben,.chat,.ang-links,.selectx-menu,.rmenu-liste,.kb-karten{
  scrollbar-width:thin;scrollbar-color:#d5dbe6 transparent}
html[data-theme="dark"] .main,html[data-theme="dark"] .tblwrap,html[data-theme="dark"] .zg-koerper,
html[data-theme="dark"] .kal-neben,html[data-theme="dark"] .chat,html[data-theme="dark"] .ang-links,
html[data-theme="dark"] .selectx-menu,html[data-theme="dark"] .rmenu-liste,html[data-theme="dark"] .kb-karten{
  scrollbar-color:#2b3852 transparent}
/* Zustandswechsel an Karten und Zeilen laufen, statt zu springen — aber nur
   das, was ohnehin schon umschaltet: Rahmenfarbe, Schatten,
   Zeilenhintergrund. Kein Anheben beim Überfahren: in einer Liste mit vierzig
   Zeilen ist das kein Hinweis mehr, sondern Unruhe. */
.card{transition:box-shadow .22s ease,border-color .22s ease}
.rowlink{transition:background .16s ease}

/* Und das hier hebt alles davon wieder auf. Wer „weniger Bewegung" gesetzt
   hat, hat es aus einem Grund gesetzt — bei manchen Menschen löst gleitende
   Bewegung echte Übelkeit aus. bewegung.js startet dann gar nicht erst;
   diese Regel fängt ab, was rein aus CSS käme. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important}
}

/* Pflichtangabe nach § 14 UStG im Rechnungsentwurf. Ein Sternchen mit
   Erklaerung dahinter — kein blosses Rot: wer die Regel nicht kennt, sieht
   sonst nur, DASS etwas besonders ist, und nicht warum. Fehlt eine dieser
   Angaben, ist die Rechnung nicht vorsteuerabzugsfaehig, und den Aerger hat
   der Kunde. */
abbr.pflicht{color:#b42318;text-decoration:none;font-weight:700;cursor:help;
  border-bottom:1px dotted currentColor}
html[data-theme="dark"] abbr.pflicht{color:#f4a4a0}

/* Zwei Klassennamen, die im Markup vergeben, aber nie geschrieben wurden.
   Ein toter Klassenname sieht aus wie eine gepflegte Ausnahme und ist doch
   nur eine Zeile, die nichts tut — gefunden beim Durchgang, hier nachgetragen. */

/* members.js: „bearbeiten" und „entfernen" sollen nebeneinander stehen und
   nicht untereinander umbrechen. */
.nowrap{white-space:nowrap}

/* organisation.js: die Ecke ueber der Stundenspalte im Zeitgitter. Stand in
   voller Grundschrift zwischen 10px-Nachbarn und lief bei groesserer
   Systemschrift ueber die 56px breite Spalte hinaus. */
.zg-ecke{display:flex;align-items:flex-end;justify-content:center;padding:0 4px 4px;
  font-size:10.5px;font-weight:700;letter-spacing:.04em;color:var(--muted);
  white-space:nowrap;overflow:hidden}

/* ══════════════════════════════════════════════════════════════════════════
 * Knöpfe, die etwas anstoßen, das dauert.
 * ══════════════════════════════════════════════════════════════════════════
 *
 * Zwei Zustände, und der Unterschied zwischen ihnen ist der ganze Punkt:
 *
 *   .laeuft          „ich arbeite" — eine Füllung, die von links nach rechts
 *                    durchwandert und wieder von vorn beginnt. Sie behauptet
 *                    KEINE Prozentzahl, weil keine bekannt ist.
 *   .laeuft[style="--fortschritt:…"]
 *                    „ich bin bei 40 %" — die Füllung steht wirklich bei
 *                    40 %, weil der Server das gemeldet hat.
 *
 * Warum nicht überall ein echter Balken: die Prozentzahl müsste vom Server
 * kommen. Wo er sie nicht kennt — und das ist bei den meisten Handgriffen so
 * — wäre jeder Balken geraten. Ein Balken, der bei 90 % stehenbleibt, ist
 * eine Lüge mit Fortschrittsanzeige; er ist schlimmer als ein Rädchen, weil
 * man ihm glaubt.
 *
 * Deshalb: wandernde Füllung, wo wir nichts wissen. Echte Füllung, wo wir
 * etwas wissen. Dieselbe Optik, unterschiedliche Aussage.
 */
/* ::after und ausdruecklich NICHT ::before.
   Der Fehler, der hier verschwindet, hat mich zwei Anlaeufe gekostet und war
   nicht im Quelltext zu sehen, sondern nur im Vergleich zweier Regeln:
   `.btn::before` (Zeile 317) ist seit jeher der Hover-Effekt und traegt
   `clip-path:circle(0%)`. Ein Element hat GENAU EIN ::before. Meine
   Ladeanzeige hat also kein zweites Element angelegt, sondern dasselbe
   umlackiert — und die Beschneidung auf null aus der Grundregel geerbt, weil
   ich sie nicht zuruecknahm. Der Schleier war jedes Mal vorhanden, in den
   berechneten Werten korrekt, und auf die Groesse null geschnitten. Genau
   danach hat Rino gesucht und nichts gefunden.
   ::after ist auf .btn frei — geprueft, nicht angenommen. */
.btn.laeuft{position:relative;overflow:hidden;pointer-events:none;opacity:.92}
/* Ein DUNKLER Schleier und nicht `currentColor`. Auf einem Knopf mit
   Akzentfarbe ist die Schriftfarbe hell — die Fuellung waere dort eine helle
   auf hellem Grund gewesen und praktisch unsichtbar. */
.btn.laeuft::after{
  content:'';position:absolute;top:0;bottom:0;left:0;width:100%;
  z-index:2;pointer-events:none;
  background:rgba(15,23,42,.26);
  transform-origin:left center;
  transform:scaleX(var(--fortschritt,0));
  transition:transform .3s cubic-bezier(.2,.8,.2,1)}
/* z-index:2 legt den Schleier UEBER die Beschriftung. Das geht, weil `.btn`
   selbst `isolation:isolate` traegt und damit ein eigener Stapel ist — der
   Schleier kann also nichts ausserhalb des Knopfes ueberdecken. */
html[data-theme="dark"] .btn.laeuft::after{background:rgba(255,255,255,.24)}
/* Ohne gemeldeten Fortschritt wandert die Fuellung. `--fortschritt` setzt die
   Animation ausser Kraft, sobald der Server eine Zahl liefert. */
.btn.laeuft:not([style*="--fortschritt"])::after{
  transform:none;width:40%;animation:laeuft-wandert 1.1s ease-in-out infinite}
@keyframes laeuft-wandert{
  0%{transform:translateX(-110%)}
  100%{transform:translateX(300%)}
}
/* Wer Bewegung abgestellt hat, bekommt die Fuellung ohne Wandern — der
   Zustand bleibt sichtbar, nur ruhig. */
@media (prefers-reduced-motion:reduce){
  .btn.laeuft:not([style*="--fortschritt"])::after{animation:none;width:100%;opacity:.55}
  .btn.laeuft::after{transition:none}
}

/* ── Der Balken oben ───────────────────────────────────────────────────────
   Der Knopf allein reicht nicht, und zwar aus einem Grund, der nichts mit
   CSS zu tun hat: das Werkzeug schickt echte Formulare ab. Zwischen Klick und
   neuer Seite steht die alte Seite still — der Knopf ist dann ein Standbild.
   Bei der LinkedIn-Suche sind das schnell zwanzig Sekunden Stillstand.
   Der Balken liegt am oberen Rand, ausserhalb jeder Karte, und ist bis zum
   Seitenwechsel sichtbar. Er zeigt ebenfalls KEINEN Prozentwert — er wandert.
   Ein Balken, der bei 90 % stehenbleibt, ist eine Luege mit Fortschritts-
   anzeige; man glaubt ihm, und deshalb ist er schlimmer als gar nichts. */
#ladebalken{position:fixed;top:0;left:0;right:0;height:3px;z-index:9999;
  pointer-events:none;overflow:hidden;display:none}
#ladebalken.an{display:block}
#ladebalken::after{content:'';position:absolute;top:0;bottom:0;left:0;width:32%;
  background:var(--accent);
  animation:laeuft-wandert 1.1s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){
  #ladebalken::after{animation:none;width:100%;opacity:.6}
}
