* { box-sizing: border-box; }

/* Vue-Template bis zum Mount ausblenden – verhindert das kurze Aufblitzen von
   Roh-Markup (z.B. der Reset-Dialog/Modals) beim Browser-Refresh. */
[v-cloak] { display: none !important; }

/* Das Farbschema: ein BLAUGRAU in drei Stufen plus die beiden Neutralen. Es loest das
   WhatsApp-Gruen/Teal ab - jenes gehoerte zum Web-Chat, nicht zu einer Lohnverrechnung, und ein
   WebUI in Messenger-Farben sah aus wie ein fremder Gast im eigenen Haus.

   Die Namen hier sagen den ZWECK (--header, --line, --flaeche), die Kommentare die STUFE der
   Vorlage. Es gibt bewusst KEINE weiteren Abstufungen: wo bisher ein Dutzend hartkodierter
   Grautoene stand (#f5f6f6, #f0f2f5, #eef1f4, #e4e6eb, #e9ebef ...), steht jetzt je nach Aufgabe
   --flaeche oder --line. Zwei Farben bleiben ausgenommen, weil sie BEDEUTUNG tragen
   und keine Marke sind: das Rot des Loeschens und das Orange der Zeilen-Hervorhebung.
   Symbole bleiben Schwarz/Weiss-SVG (Allgemeine Regel). */
:root {
  --bg: #f9fafb;            /* Seitenhintergrund */
  --panel: #ffffff;
  --flaeche: #eef3f6;       /* Stufe 100: gedaempfte Flaeche (Chips, Aktionsleiste, Hover) */
  /* Stufe 200/300 - EINE Linienfarbe. Es waren ZWEI (#dbe5eb fuer die feine Trennlinie, #b6c9d5
     fuer den kraeftigen Rand von Eingaben, Ref-Control und Dropdown), und der Unterschied war
     keine Aussage, sondern eine Entscheidung, die jede neue Regel erneut treffen musste - eine
     Linie ist eine Linie. Der Ton liegt zwischen den beiden. */
  --line: #b9c8d3;
  --accent: #3a6982;        /* Aktionen/aktiv */
  /* Stufe 600 - AUSSCHLIESSLICH der Hover der Primaeraktion. Sie ist dort keine Zierde,
     sondern die einzige Rueckmeldung: der Knopf RUHT auf --accent, und mit derselben Farbe
     im Hover geschaehe beim Ueberfahren sichtbar nichts. Als TEXTfarbe wird sie nicht mehr
     verwendet - dort standen beide Toene nebeneinander und sagten dasselbe (der aktive
     Reiter faerbte seine Beschriftung dunkler als seine eigene Unterkante). */
  --accent-dark: #325a70;
  --header: #3a6982;        /* Kopfzeile - derselbe Ton wie --accent */
  --muted: #667781;
  --text: #101828;
}

/* Schriftart immer Roboto (Allgemeine Regel); Emojis kommen direkt vom Font. */
body {
  margin: 0;
  font-family: "Roboto", Arial, Helvetica, sans-serif;
  background: var(--bg);
  color: var(--text);
}

/* Symbole ausschliesslich Schwarz/Weiss im SVG-Format; Farbe folgt currentColor. */
.icon {
  width: 18px; height: 18px;
  vertical-align: -3px;
  color: currentColor; flex: 0 0 auto;
}

/* Die MARKE ist kein Symbol des Satzes, sondern eine BILDVORLAGE: Kristall und Schriftzug stehen
   als EIN freigestelltes PNG. Es gibt nur EINE Fassung - den dunkelblauen Schriftzug der Vorlage -,
   und sie steht IMMER auf einer weissen Platte mit abgerundeten Ecken. Das loest die zweite Datei
   mit weissem Schriftzug ab: die war ein Eingriff in die Marke, waehrend die Platte sie unveraendert
   laesst und ihr auf dem Akzent-Grund nur den hellen Grund gibt, fuer den sie gezeichnet ist.
   Gesteuert wird die HOEHE des BILDES (content-box, damit die Polsterung sie nicht auffrisst) - die
   Breite folgt dem Seitenverhaeltnis, sonst verzerrte eine geaenderte Kopfzeile den Schriftzug.
   Die Hoehe ist am SCHRIFTZUG bemessen und nicht am Kristall: der ist in der Vorlage fast dreimal so
   hoch wie die Buchstaben, sodass ein auf 24 px (die alte Symbolgroesse) gesetztes Logo einen
   Schriftzug von 9 px Hoehe haette - lesbar nur noch als grauer Strich. */
.logo-bild {
  box-sizing: content-box;
  height: 38px; width: auto; display: block;
  background: #ffffff; border-radius: 8px; padding: 6px 10px;
}

/* DEN RUNDEN MARKEN-KNOPF (.marke-knopf) GIBT ES NICHT MEHR - in KEINER der beiden Oberflaechen.
   Er stand oben links in der Toolbar und, seit die dort dem Wasserzeichen wich, noch am Mobile in
   der Kopfzeile; dort belegte er eine ganze 52-px-Zeile fuer sich, waehrend das Wasserzeichen der
   Toolbar hinter dem Hamburger lag und gar nicht zu sehen war - auf dem Telefon war also genau
   der Knopf zurueck, dessentwegen es das Wasserzeichen gibt. Die Marke ist jetzt AUSSCHLIESSLICH
   ein Wasserzeichen: am Desktop im Hintergrund der Toolbar, am Mobile im Hintergrund der Kopfzeile
   (siehe .toolbar bzw. die Medienabfrage weiter unten).

   MIT IHM ENTFAELLT DER GOLDENE SCHEIN. Er machte aus der weissen Scheibe eine Schaltflaeche - ein
   Hover sagt "hier kann man klicken", und ein Wasserzeichen kann man nicht anklicken; ein Schein
   ohne Scheibe haette ueberdies nichts zu umgeben. Er lebt im ConnectorService ebensowenig weiter,
   dort ist die Marke seit jeher keine Schaltflaeche.

   SEINE BEIDEN AUFGABEN BLEIBEN ERREICHBAR, und das ist die Bedingung des Wegfalls: ein fehlender
   Knopf faellt auf, eine fehlende MOEGLICHKEIT nicht. Das AKTUALISIEREN liegt am Kreispfeil neben
   dem Breadcrumb (ansichtNeuLaden ruft auf der obersten Ebene dasselbe laden()), das WECHSELN der
   Organisation im Benutzermenue (ein Klick auf die gewaehlte waehlt sie ab).

   Das LOGO MIT SCHRIFTZUG bleibt unberuehrt der Anmeldeseite vorbehalten (.logo-bild darueber),
   wo die Marke sich tatsaechlich nennt. */

.topbar {
  display: flex; align-items: center; gap: 16px;
  background: var(--header); color: #ffffff;
  padding: 12px 20px; position: sticky; top: 0; z-index: 10;
}
.topbar-user-wrap { position: relative; flex: 0 0 auto; margin-left: auto; }
.topbar-user {
  display: inline-flex; align-items: center; gap: 6px;
  background: transparent; border: none; cursor: pointer; padding: 4px 6px; border-radius: 6px;
  color: rgba(255,255,255,.85); font-size: 13px; font-family: inherit;
  /* 240 px reichten fuer eine gewoehnliche Adresse NICHT: christian.distelberger@gmail.com sind
     32 Zeichen und bei 13 px rund 200 px, dazu Symbol, Pfeil, Abstaende und Innenmass von
     zusammen ~55 px - die Adresse wurde also im Regelfall abgeschnitten, obwohl daneben Platz
     frei war. 340 px tragen rund 45 Zeichen; der Deckel bleibt, damit eine ungewoehnlich lange
     Adresse den Breadcrumb daneben nicht verdraengt. Am MOBILE hebt die Media Query ihn ohnehin
     ganz auf (dort steht der Breadcrumb in einer eigenen Zeile). */
  max-width: 340px;
}
.topbar-user:hover { background: rgba(255,255,255,.12); color: #ffffff; }
.topbar-user .tu-mail { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Der Pfeil zeigt nach unten (das Symbol selbst weist nach rechts). */
.topbar-user .tu-caret { width: 13px; height: 13px; transform: rotate(90deg); flex: 0 0 auto; opacity: .8; }

/* Aufklapp-Menue des Benutzers (Konto/System/Abmelden). */
.benutzer-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 60;
  min-width: 180px; padding: 4px;
  background: #ffffff; border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 8px 22px rgba(0, 0, 0, .18);
}
.bm-eintrag {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; cursor: pointer;
  padding: 8px 12px; border-radius: 6px;
  font-family: inherit; font-size: 14px; color: var(--text);
}
.bm-eintrag:hover { background: var(--flaeche); }
/* Abmelden abgesetzt: es verlaesst die Anwendung, die beiden anderen bleiben darin. */
.bm-abmelden { border-top: 1px solid var(--line); border-radius: 0 0 6px 6px; margin-top: 4px; }
/* Der Organisations-Wechsel (nur bei mehreren Betrieben): eine eigene Gruppe mit
   Ueberschrift, damit die Betriebsnamen nicht wie weitere Menuepunkte aussehen. Das Hakerl steht
   in einer festen Spalte, sodass die Namen untereinander fluchten – mit und ohne Haken. */
/* Die angemeldete Adresse als Kopf des Menues - AM MOBILE, wo der Chip daneben kein Wort mehr
   traegt (die Medienabfrage blendet .tu-mail aus). Am Desktop bleibt sie hier verborgen: dort
   steht sie im Chip, und zweimal untereinander waere sie eine Wiederholung. `overflow-wrap`, weil
   eine Adresse keine Leerzeichen hat und sonst das Menue aufspannen wuerde. */
.bm-mail {
  display: none;
  padding: 6px 12px 8px; font-size: 12.5px; color: var(--muted);
  border-bottom: 1px solid var(--line); margin-bottom: 4px; overflow-wrap: anywhere;
}
.bm-titel { padding: 6px 12px 2px; font-size: 12px; color: var(--muted); font-weight: 500; }
.bm-org { display: flex; align-items: center; gap: 6px; }
.bm-org.aktiv { font-weight: 500; }
.bm-haken { flex: 0 0 12px; color: var(--accent); }
.bm-trenner { height: 1px; background: var(--line); margin: 4px 0; }

/* --- Organisationsauswahl (Kacheln) ---------------------------------------------------------- */
/* Sie steht ANSTELLE des Dashboards und nicht darueber: es ist der Weg hinein und kein Overlay. */
.org-auswahl { max-width: 860px; margin: 48px auto; padding: 0 16px; }
.org-auswahl h2 { font-size: 20px; font-weight: 500; margin: 0 0 6px; }
.org-auswahl p { margin: 0 0 20px; font-size: 14px; }
.org-kacheln { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
.org-kachel {
  display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
  padding: 22px; cursor: pointer; text-align: left;
  background: #ffffff; border: 1px solid var(--line); border-radius: 10px;
  font-family: inherit; font-size: 16px; color: var(--text);
}
.org-kachel:hover { border-color: var(--accent); box-shadow: 0 2px 10px rgba(0, 0, 0, .08); }
.org-kachel .icon { width: 32px; height: 32px; color: var(--muted); }
.org-kachel .ok-name { font-weight: 500; }
/* Die EIGENEN Betriebe stehen groesser: sie sind das, was man beim Anmelden am ehesten meint.
   Groesser heisst hier mehr Luft und ein groesseres Symbol – die Kachel bleibt dieselbe, nur ihr
   Massstab ist ein anderer; eine zweite Kachel-Bauart daneben liefe frueher oder spaeter
   auseinander. */
.org-kacheln.eigene { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.org-kachel.gross { padding: 32px; font-size: 20px; gap: 16px; }
.org-kachel.gross .icon { width: 46px; height: 46px; }
/* Der waagrechte Trenner zwischen den eigenen und den betreuten Betrieben. Er steht NUR da, wenn
   es betreute gibt (v-if am Block darunter) – ein Strich unter der letzten Kachel truege sonst
   die Ankuendigung von etwas, das nicht kommt. */
.org-trenner { height: 1px; background: var(--line); margin: 28px 0; }

/* --- Linke Toolbar (Abmelden u.a.); am Desktop dauerhaft, am Mobile per Hamburger ----------- */
.toolbar {
  position: fixed; top: 0; left: 0; bottom: 0; width: 200px; z-index: 30;
  color: #ffffff;
  display: flex; flex-direction: column; gap: 10px; padding: 68px 14px 14px;
  box-sizing: border-box;

  /* OBEN 68 px statt 14 - jetzt als MINDESTABSTAND und nicht mehr als Setzung. Er sagt, wie weit
     die Knoepfe im ENGSTEN Fall nach oben duerfen: bis 14 px unter die Kopfzeile. Daran haengt,
     dass der erste Knopf nicht neben dem Breadcrumb steht - beide Flaechen tragen denselben
     Akzent-Ton, und die Zeile laese sich dann als eine. GEMESSEN ist die Kopfzeile 54 px hoch;
     54 + 14 ist die Zahl.
     ER SETZT DIE KNOEPFE NICHT MEHR: sie haengen am Trenner in der Mitte (das auto am ersten
     Element weiter unten) und beruehren dieses Innenmass erst, wenn der freie Platz
     AUFGEBRAUCHT ist - GEMESSEN bei 370 px Fensterhoehe; ab 360 laeuft die Toolbar ueber und
     scrollt. Bis dahin steht die Marke ueber ihnen frei.
     DIE ZAHL HAENGT AN DER KOPFZEILE: waechst deren Innenmass oder ihre Schrift, laufen die beiden
     auseinander - das faellt an nichts auf ausser am Blick. Eine gemeinsame Variable gaebe es
     nicht umsonst: die Hoehe der Kopfzeile ergibt sich aus ihrem Inhalt und stuende dann ein
     zweites Mal als Zahl da, nur an einer anderen Stelle. */

  /* DIE MARKE ALS WASSERZEICHEN - dieselbe Bauart wie im Chat (ConnectorService, .messages):
     zwei Background-Lagen, und die REIHENFOLGE ist die Transparenz. In CSS liegt die ERSTE Lage
     OBEN, der Schleier DECKT die Marke also AB, statt sie abzudunkeln - das Bild bleibt
     unangetastet, so wie es die Regel fuer diese Bildvorlage verlangt.

     SIE STEHT HIER UND NICHT AUF DER SEITENFLAECHE, und das ist GEMESSEN: .content ist zu 98 %
     von undurchsichtigen Karten, Reitern und Zeilen bedeckt, und der Rest traegt #f9fafb - fast
     dieselbe Helligkeit wie der helle Kristall. Dort gerendert war der Unterschied zur Seite
     OHNE Wasserzeichen groesster Einzelwert 1 von 255 und KEIN Bildpunkt oberhalb der
     Wahrnehmungsschwelle: buchstaeblich unsichtbar. Auf dem Listenpapier (.liste) war es
     sichtbar, aber von den undurchsichtigen Zeilen in Streifen zerschnitten - das liest sich als
     Darstellungsfehler. Die Toolbar ist die einzige grosse freie Flaeche der Oberflaeche
     (gemessen 66 % ihrer Hoehe, 591 px), und ihr Akzent-Ton gibt dem hellen Kristall denselben
     Kontrast, den im Chat das Beige gibt.

     SIE STEHT OBEN, und dort ist sie FREI - kein Knopf und keine Linie beruehrt sie. Das gilt
     erst, seit die Knoepfe von ihr WEGWACHSEN (siehe das auto am ersten Element weiter unten):
     die obere Gruppe haengt am Trenner in der Mitte und waechst nach oben, die untere waechst
     nach unten, und der freie Platz liegt damit ueber der einen und unter der anderen statt
     zwischen ihnen. GEMESSEN bei 1280x800: der einzige Knopf ueber dem Trenner steht bei
     280-318, der Trenner bei 336 - die Marke (0 bis 220) bleibt unberuehrt.

     SIE STAND DAFUER UNTEN, mit der Begruendung, dass die Zahl der Schaltflaechen mit der
     geoeffneten Klasse wechselt und sie mittig gesetzt mal frei und mal hinter ihnen laege. Das
     war richtig, solange die Knoepfe am oberen Rand klebten und nach unten wuchsen; jetzt loest
     dieselbe Beobachtung sich auf, weil sie von der Marke wegwachsen. Der eine Zustand, in dem
     sie sie noch beruehren, ist das BEARBEITEN (Abbrechen, Speichern, Umbenennen): die Gruppe
     waechst dann auf 232-366 und schneidet die untere Spitze des Kristalls an - ein Zustand, in
     dem man ohnehin auf die Knoepfe schaut.

     Sie laeuft nach LINKS aus - bei 200 px Breite ist "gross" nur so zu haben, und angeschnitten
     wirkt sie wie ein Wasserzeichen und nicht wie ein Symbol, das zu klein geraten ist; nach OBEN
     laeuft sie aus demselben Grund ueber den Rand hinaus (top -40px). */
  background-color: var(--header);
  background-image:
    linear-gradient(rgba(58,105,130,.75), rgba(58,105,130,.75)),
    url("salaria-marke.png");
  background-repeat: repeat, no-repeat;
  background-position: 0 0, right -30% top -40px;
  background-size: auto, 260px auto;
}
/* DIE OBERE GRUPPE WAECHST VON DER MITTELLINIE WEG NACH OBEN. Ein auto-Aussenmass am ERSTEN
   Element der Toolbar schiebt sie hinunter, bis sie am Trenner anstoesst; das Drop-Panel traegt
   ohnehin schon eines, und ZWEI autos in einer Flex-Spalte teilen den freien Platz GLEICH auf.
   Damit liegt er ueber der oberen und unter der unteren Gruppe statt zwischen ihnen - genau das
   macht die Marke oben frei.

   WARUM AM ERSTEN ELEMENT UND NICHT AM TRENNER: an ihm gesetzt bliebe die obere Gruppe am oberen
   Rand kleben und der freie Platz laege ZWISCHEN ihr und der Linie - die Marke waere dann
   weiterhin von ihr verdeckt. Das erste Element ist dabei nicht immer dasselbe (im
   Bearbeiten-Modus "Abbrechen" statt "Bearbeiten"); :first-child trifft, was Vue tatsaechlich
   rendert.

   DER TRENNER LANDET DADURCH IN DER MITTE, ohne dass eine Zahl dafuer dasteht - GEMESSEN bei
   1280x800 auf 336, waehrend die Mitte der Flaeche bei 427 liegt: die beiden autos teilen den
   FREIEN Platz und nicht die Flaeche, und der Block unter der Linie ist hoeher als der darueber.
   Eine feste Proportion traefe die Mitte genau und kollidierte auf einem niedrigen Fenster mit
   dem Drop-Panel; so schrumpft der Abstand von selbst mit - GEMESSEN steht der erste Knopf bei
   800 px Fensterhoehe auf 280, bei 600 auf 180, bei 460 auf 110 und bei 370 auf 68, also am
   Innenmass. */
.toolbar > *:first-child { margin-top: auto; }
.toolbar-btn {
  display: inline-flex; align-items: center; gap: 8px; width: 100%;
  background: rgba(255,255,255,.15); color: #ffffff; border: none;
  padding: 10px 12px; border-radius: 6px; cursor: pointer; font: inherit; font-size: 14px; font-weight: 500;
  text-align: left;
}
.toolbar-btn:hover { background: rgba(255,255,255,.28); }
/* Speichern ist die PRIMAERE Aktion und daher deckend statt durchscheinend. Weiss auf Weiss geht
   nicht, der Text nimmt deshalb die Farbe der Kopfzeile - dieselbe Umkehrung wie beim aktiven
   Reiter. */
.toolbar-btn.primary { background: #ffffff; color: var(--header); font-weight: 600; }
.toolbar-btn.primary:hover { background: rgba(255,255,255,.88); }
/* Trenner zwischen den Aktionen des Dashboards (Bearbeiten/Speichern) und den Kontextaktionen
   darunter. Er traegt die negativen Aussenmasse des Toolbar-Innenmasses, damit er durchgeht und
   nicht als kurzer Strich in der Mitte schwebt; die 10 px Abstand der Toolbar stehen ohnehin
   darueber und darunter - der Trenner nimmt sich oben etwas mehr, damit er zur Gruppe DARUNTER
   gehoert und nicht mittig zwischen beiden schwebt. */
.toolbar-trenner { height: 1px; background: rgba(255,255,255,.28); margin: 8px -14px 0; }
/* Drop-Target zum Hochladen von Dokumenten: nur AKTIV (.aktiv), wenn das angezeigte Objekt eine
   Dokumente-Liste hat; sonst ausgegraut. .dragover hebt es hervor, während eine Datei darüber schwebt. */
.toolbar-drop {
  /* margin-top:auto schiebt das Panel (und das direkt darunter folgende Abmelden) an den unteren Rand. */
  margin-top: auto;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  width: 100%; box-sizing: border-box; min-height: 84px;
  padding: 14px 12px; border: 1.5px dashed rgba(255,255,255,.3); border-radius: 6px;
  color: rgba(255,255,255,.65); font-size: 14px; text-align: center; cursor: default; user-select: none;
  transition: border-color .15s, background .15s, color .15s;
}
.toolbar-drop.aktiv { color: #ffffff; cursor: pointer; }
.toolbar-drop.aktiv:hover { background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.6); }
.toolbar-drop.dragover { background: rgba(0,168,132,.25); border-color: var(--accent); border-style: solid; color: #ffffff; }
.toolbar-drop .icon { flex: 0 0 auto; }

/* Abmelden als letzter Eintrag ganz unten – direkt unter dem Drop-Panel (das margin-top:auto trägt). */
.toolbar-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 25; }
/* Hamburger nur am Mobile sichtbar (siehe Media Query). */
.hamburger { display: none; background: transparent; border: none; color: #ffffff; cursor: pointer; padding: 6px; flex: 0 0 auto; }

/* Desktop: Toolbar dauerhaft links, die App-Shell entsprechend nach rechts versetzt. */
@media (min-width: 769px) {
  .app-shell { margin-left: 200px; }
  .toolbar-backdrop { display: none; }
}
/* Mobile: Toolbar off-canvas, per Hamburger ein-/ausblendbar (Slide-in mit Backdrop). */
@media (max-width: 768px) {
  .toolbar { transform: translateX(-100%); transition: transform .2s ease; box-shadow: 2px 0 10px rgba(0,0,0,.25); }
  .toolbar.open { transform: translateX(0); }
  .hamburger { display: inline-flex; }
}

/* --- DIE ANMELDEMASKE ---------------------------------------------------------------------
   SIE STEHT IN BEIDEN OBERFLAECHEN GLEICH, Regel fuer Regel und Wert fuer Wert - so wie das
   Markup daneben (index.html). Es ist DIESELBE Maske desselben Produkts: wer sich am WebUI
   anmeldet, meldet sich am Web-Chat mit DEMSELBEN Konto an, und zwei verschiedene Masken sagten
   ihm vor allem, dass er zwei Programme vor sich hat.

   SELBSTTRAGEND, und das ist die Bedingung dafuer: der Block darf nichts voraussetzen, was nur
   EINE der beiden Oberflaechen hat. Das WebUI hing mit seinen Knoepfen an `.btn`, dem
   Knopf-Satz seines Formulars - der ConnectorService kennt ihn nicht, und dasselbe Markup haette
   dort ein nacktes Browser-Element ergeben. `.login-btn` traegt seine Form daher selbst, samt
   `font: inherit`: ein Knopf erbt die Schriftart NICHT von sich aus, und das WebUI hat -
   anders als der ConnectorService - keine globale Regel dafuer.

   DAS SYMBOL DER BEIDEN FREMDKONTO-KNOEPFE IST ENTFALLEN. `.icon` ist hier 18 px und dort 22 px;
   dasselbe Markup ergaebe also zwei verschiedene Knoepfe, und eine dritte Groesse eigens fuer die
   Anmeldung waere eine Groesse mehr im Satz. Es kostet nichts: das Zeichen war das allgemeine
   Personen-Symbol und nicht die Marke des jeweiligen Anbieters - es sagte nichts, was nicht
   danebensteht.

   DER GRUND UNTER DEM BAND IST `--bg` und nicht `--line`: die Karte schwebt darauf, und genau das
   benennt `--bg`. Der ConnectorService nahm dort seine Linienfarbe, weil sie auch sein
   `body`-Grund ist - eine Linienfarbe als halbe Bildschirmflaeche ist die Verwendung, vor der die
   Palette warnt. DER PREIS: die weisse Karte hebt sich unterhalb des Bandes weniger ab als auf
   dem Blaugrau; ihr Schlagschatten traegt sie.

   NICHT dazu gehoert der Ladezustand DAVOR ("Anmeldung wird geprueft ..."): er heisst hier
   `.loading` und dort `.wa-loading`, und die hiesige Regel hat einen ZWEITEN Verwender
   ("Lade Organisation ...") - sie anzugleichen aenderte das Dashboard mit.

   Ein gemeinsames Stylesheet gibt es nicht (siehe die Farbpalette); die Doppelung muss also
   bleiben, und ein Nachweis haelt sie zusammen. */
.login-screen {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center; padding: 16px;
  /* Band im Akzent-Ton oben, darunter der Grund der Anwendung. */
  background: linear-gradient(var(--header) 0 220px, var(--bg) 220px);
}
.login-card {
  background: var(--panel); border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0,0,0,.18);
  padding: 36px 40px; max-width: 380px; width: 100%; text-align: center;
}
/* Auf der Anmeldeseite steht die Marke GROSS: die Karte hat den Platz, und sie ist dort das
   Einzige, was die Anwendung benennt. */
.login-logo { display: flex; justify-content: center; margin-bottom: 18px; }
.login-logo .logo-bild { height: 88px; }
.login-card h1 { font-size: 17px; font-weight: 700; margin: 0 0 8px; color: var(--text); }
.login-text { color: var(--muted); font-size: 14px; margin: 0 0 20px; }
.login-form { display: flex; flex-direction: column; gap: 10px; }
.login-input {
  width: 100%; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 6px;
  font: inherit; font-size: 14px; color: var(--text); background: var(--panel);
}
.login-input:focus { outline: none; border-color: var(--accent); }
.login-btn {
  width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--panel); color: var(--text); border: 1px solid var(--line);
  padding: 10px 14px; border-radius: 6px; cursor: pointer;
  font: inherit; font-size: 15px;
}
.login-btn:hover { background: var(--flaeche); }
.login-btn.primary { background: var(--accent); border-color: var(--accent); color: #ffffff; }
.login-btn.primary:hover { background: var(--accent-dark); }
.login-btn:disabled { opacity: .5; cursor: not-allowed; }
.login-link {
  background: none; border: none; padding: 0; margin: 10px 0 0;
  color: var(--accent); font: inherit; font-size: 13px; cursor: pointer;
}
.login-link:hover { text-decoration: underline; }
/* Trenner „oder" zwischen E-Mail/Passwort und den Anmeldungen ueber ein fremdes Konto. */
.login-trenner {
  display: flex; align-items: center; gap: 10px;
  margin: 16px 0; color: var(--muted); font-size: 12px;
}
.login-trenner::before, .login-trenner::after {
  content: ""; flex: 1; border-top: 1px solid var(--line);
}
.login-info { color: var(--accent); font-size: 13px; margin: 14px 0 0; }
.login-fehler { color: #d33a3a; font-size: 13px; margin: 14px 0 0; }
/* Pflichtfeld-Markierung (*) und sprechende Fehlermeldung beim Speichern. */
.pflicht { color: #d33a3a; font-weight: 700; margin-left: 2px; }
/* Kennzeichnung eines HISTORISIERTEN Feldes: eine kleine Uhr hinter der Beschriftung. DEZENT –
   sie ist ein Hinweis und keine Warnung: gedämpfte Farbe, kleiner als die Schrift daneben und auf
   der Grundlinie ausgerichtet, damit sie die Zeilenhöhe nicht verändert. Der rote Stern des
   Mussfeldes bleibt das auffälligere Zeichen, denn nur er verlangt etwas vom Benutzer. */
.hist-marke { display: inline-flex; align-items: center; margin-left: 4px; vertical-align: -1px;
  color: var(--muted); cursor: help; }
.hist-marke .icon { width: 13px; height: 13px; }
/* Die Aktionsspalte der Historie-Tabelle: sie trägt keine Überschrift und soll auch keine Breite
   beanspruchen – die beiden Symbole stehen nebeneinander, die Spalte schrumpft auf ihren Inhalt.
   Sie behält die Polsterung von `.arr-table td` und damit die Oberkante der ersten Textzeile; eine
   eigene wäre wirkungslos, weil jene Regel dieselbe Spezifität hat und weiter unten steht. */
/* Die Feld-Auswahl des Historie-Reiters stand hier als eigene Zeile UEBER der Tabelle (.hist-filter,
   ein natives <select>). Sie ist in den SPALTENKOPF gewandert: die Spalte, auf die der Filter
   wirkt, ist die, die er beschriftet - und dort ist er zugleich die Anzeige dessen, was gerade
   gilt. Siehe .kopf-menu-knopf weiter unten. */

td.hist-akt { white-space: nowrap; width: 1%; text-align: right; }
/* `inline-grid` statt `grid`: der Icon-Button ist sonst block-level – überall sonst steht er in
   einem Flex-Container, hier aber unmittelbar in der Zelle, und die beiden Symbole stünden
   UNTEREINANDER statt nebeneinander (gemessen: die Zeile war dadurch 68 statt 44 px hoch).
   Er ist kleiner als der übliche 34er, damit er die Zeilenhöhe nicht bestimmt; der negative obere
   Abstand hebt ihn um die halbe Differenz zur Textzeile ((24 − 16) / 2), sodass sein Symbol auf der
   Mitte der ERSTEN Zeile sitzt statt 4 px darunter. Auf die Zellmitte zentriert stünde es sogar
   17 px unter dem Text, zu dem es gehört – die Beschriftung bricht um. */
td.hist-akt .icon-btn { display: inline-grid; width: 24px; height: 24px;
  vertical-align: top; margin-top: -4px; }
td.hist-akt .icon-btn .icon { width: 15px; height: 15px; }
.speicher-fehler { color: #d33a3a; font-size: 13px; text-align: center; padding: 8px 12px;
  margin: 4px auto; border: 1px solid #d33a3a; border-radius: 6px; background: #fdecec; }

/* Rein lesender Chat-Verlauf (Mitarbeiter) */
.chat-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 4px 8px; font-size: 13px;
}
/* Der Behaelter bleibt eigen (das WebUI zeigt den Verlauf in einem Reiter und nicht
   als ganze Seite, daher die Hoehenbegrenzung); die BLASEN darin kommen aus dem
   geteilten Block darunter. */
.chat-verlauf {
  padding: 12px 14px; max-height: 60vh; overflow-y: auto;
  background: var(--bg); border-radius: 6px;
  display: flex; flex-direction: column; gap: 6px;
}

/* === Chat-Blasen: GETEILT von den ZWEI Sichten =============================
   Dieser Block gehoert BEIDEN Chat-Sichten dieser Oberflaeche: dem CHAT-Reiter am
   eigenen Datensatz (lebend, mit Eingabezeile) und dem PROTOKOLL-Reiter an einem
   beliebigen Mitarbeiter (rein lesend).
   WARUM sie geteilt sind: es ist DASSELBE Gespraech. Der Mitarbeitende schreibt es,
   die Lohnverrechnung liest es nach - saehe es dort anders aus, muesste man beim
   Nachsehen erst uebersetzen, welche Blase von wem ist. Was sich unterscheiden DARF,
   sind die Tool-Aufrufe und der Gedankengang: die sieht nur das Protokoll.
   ER STAND ZWEIMAL DA, wortgleich hier und im Stylesheet des ConnectorService, und
   ein Nachweis hielt die beiden gegeneinander. Seit der Chat ein Reiter ist, steht er
   EINMAL da; gehalten wird jetzt die BENUTZUNG durch beide Sichten
   (FrontendTests.DieBeidenChatSichtenTeilenDieselbenBlasen). */
.bubble-row { display: flex; }
.bubble-row.from-user { justify-content: flex-end; }
.bubble-row.from-contact { justify-content: flex-start; }

.bubble {
  position: relative;
  max-width: 75%;
  padding: 6px 9px 18px;
  border-radius: 8px;
  box-shadow: 0 1px .5px rgba(0, 0, 0, .13);
  font-size: 14.5px;
  line-height: 1.35;
  color: var(--text);
  word-wrap: break-word;
}
.from-user .bubble { background: var(--flaeche); }
.from-contact .bubble { background: var(--panel); }

.bubble .text { white-space: normal; }
.bubble .meta {
  position: absolute;
  right: 9px; bottom: 4px;
  font-size: 10.5px;
  color: var(--muted);
}

.bubble .photo {
  max-width: 100%;
  border-radius: 6px;
  display: block;
  margin-bottom: 4px;
}
.bubble .voice { display: block; margin-bottom: 4px; max-width: 240px; }

/* Anhang, den es nur als Hinweis gibt: ein PDF zum Oeffnen bzw. - wo die Datei nicht
   (mehr) vorliegt - die blosse Angabe, dass hier ein Foto oder eine Sprachnachricht
   stand. Im WebUI ist das der Regelfall: der Anhang wird nur auf dem Peer-Pfad
   persistiert, und Peer-Chats gibt es nicht (siehe CLAUDE.md, "Die WIEDERHERSTELLUNG
   des Chat-Zustands"). */
.doc-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: 8px;
  background: var(--flaeche); color: var(--text); text-decoration: none;
  font-size: 0.9rem; max-width: 100%;
}
/* === Ende Chat-Blasen ======================================================== */

/* Function-Call als kleines Symbol/Chip - er ist das EINE, was das WebUI mehr zeigt
   als der Web-Chat, und darf daher anders aussehen. */
.cv-fc {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--flaeche); color: var(--text); border: 1px solid var(--line);
  padding: 4px 8px; border-radius: 12px; cursor: pointer; font: inherit; font-size: 12px;
}
.cv-fc:hover { background: var(--line); }
.cv-fc .icon { width: 15px; height: 15px; }

/* DER GEDANKENGANG (kind=reasoning) - das ZWEITE, was das WebUI mehr zeigt als der Web-Chat,
   und daher wie .cv-fc AUSSERHALB des geteilten Blocks. Er ist eine BLASE und kein Chip: es ist
   etwas, das das Modell in diesem Zug hervorgebracht hat, und es steht an der Stelle des
   Gespraechs, an der es entstanden ist.

   IN RUHE nennt sie nur die ART, beim HOVERN erscheint der Inhalt als POPUP - ueberlagernd und
   nicht aufklappend: die Blase behaelt ihre Groesse, und der Verlauf darunter bleibt stehen, wo er
   steht. Er klappte zuerst UNTER der Blase auf; das kostete jedesmal die Hoehe des Gedankengangs
   (gemessen wuchs der Behaelter von 167 auf 433 px, und ohne Deckel waeren es 783 gewesen), und
   alles Folgende sprang beim blossen Ueberfahren weg.

   FIXED ist dabei die BEDINGUNG und keine Vorliebe, und das ist gemessen: .chat-verlauf traegt
   overflow-y: auto, und das macht overflow-x zu 'auto' statt 'visible' - eine ABSOLUT positionierte
   Tafel wird darin BESCHNITTEN, und was ueber den Rand hinausragt, waere nur durch Scrollen zu
   erreichen; dabei faehrt der Zeiger von der Blase, und die Tafel verschwindet wieder. Gegen das
   FENSTER positioniert ist kein Vorfahr mehr eine Grenze - genau die Ueberlegung, aus der
   td.rgz .rg-pop fixed liegt; die Koordinaten setzt dasselbe Mixin (Ankerpanel) als Inline-Stil,
   links/oben hier nur als Ausgangswert, bis gemessen wurde.

   Der DECKEL ist kein Schoenheitsmass: ein Gedankengang ist regelmaessig laenger als die ganze
   Antwort, und ungedeckelt reichte das Popup ueber den Bildschirm hinaus. Er misst gegen das
   FENSTER (60vh) und nicht gegen einen Container - das Popup liegt ueber allen. */
.bubble-reasoning .reasoning-titel { color: var(--muted); font-style: italic; }
.bubble-reasoning .reasoning-pop {
  position: fixed; left: 0; top: 0; z-index: 70;
  /* Die Breite folgt dem INHALT, weil das Popup sonst per shrink-to-fit auf die Blasenbreite
     schrumpfte und den Deckel darunter nie erreichte - die Blase misst gemessen 87 px. */
  width: max-content; min-width: 320px; max-width: min(680px, 92vw);
  padding: 8px 10px;
  background: var(--panel); color: var(--text); border: 1px solid var(--line); border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
  font-size: 12.5px; line-height: 1.45; font-weight: 400; text-align: left;
  /* pre-wrap: der Gedankengang kommt mit eigenen Absaetzen aus dem Modell und wird nicht
     ausgezeichnet - die Zeilenumbrueche sind das einzige, was er an Gliederung hat. */
  white-space: pre-wrap;
  max-height: 60vh; overflow-y: auto; overscroll-behavior: contain;
}

/* JSON-Overlay (Function-Call-Kommunikation).

   ES IST DAS GROESSTE OVERLAY DER OBERFLAECHE und muss es sein: hier steht die ROHE
   Kommunikation mit dem Modell - ein aufgefaltetes leseArbeitszeitModellDetails ist gemessen
   ueber 120 Zeilen lang, und wer nachsieht, warum das Modell etwas getan hat, liest sie am Stueck.

   .modal.modal-json UND NICHT .modal-json - das ist der eigentliche Befund. Die Regel stand hier
   mit derselben Gewichtung wie .modal (je 0,1,0) und WEITER OBEN in der Datei; bei Gleichstand
   gewinnt die spaetere, also .modal mit seinen 380px. GEMESSEN war das Overlay damit 380 statt
   1120 px breit - die Angabe hier stand seit jeher da und hat nie gewirkt, und weil ein JSON mit
   white-space: pre nicht umbricht, wurde in BEIDE Richtungen gescrollt. Die drei uebrigen
   Groessenklassen (.modal-gehalt, .modal-scheiben, .modal-zulagen) wirken nur deshalb, weil sie
   zufaellig HINTER .modal stehen; die hoehere Gewichtung macht die Wirkung von der Reihenfolge
   unabhaengig. Gehalten von FrontendTests.DieGroessenklassenDerDialogeGewinnenGegenDieGrundform. */
.modal.modal-json {
  max-width: min(96vw, 1900px);
  width: 100%;
  /* Die HOEHE steht am DIALOG und der Deckel des Inhalts folgt daraus (flex + min-height:0) -
     dieselbe Bauart wie .modal-gehalt. Am <pre> gesetzt musste sie das Beiwerk (Innenmass,
     Titelzeile, Abstand) erraten: 84vh plus 68px Beiwerk passt bei 900px Fensterhoehe knapp und
     ragt bei 1000px darueber hinaus. So bekommt der Inhalt genau, was uebrig bleibt.

     94vh und NICHT der ganze Platz: ein Overlay ist eine KARTE auf dem abgedunkelten Grund und
     kein Vollbild - der abgedunkelte Rand ist es, der es als Dialog kenntlich macht (gehalten von
     DatenmodellTests.KeinOverlayIstVollbild, das 100vw/100vh an JEDER Modal-Regel abweist).

     Die 94 sind HERGELEITET und nicht gewaehlt: die alten 84vh standen am <pre>, und mit dem
     Beiwerk (Innenmass 40, Titelzeile 25, Abstand 8, zusammen 76px) war der DIALOG damit bei
     900px Fensterhoehe bereits 93,4vh hoch. Mit 90vh am Dialog waere die Ansicht also KUERZER
     geworden als zuvor (gemessen 34 statt 35 Zeilen) - 94vh haelt den alten Stand und legt zwei
     Zeilen zu. Der abgedunkelte Rand bleibt: 16px Innenmass des Overlays plus rund 24px. */
  max-height: 94vh;
  display: flex; flex-direction: column;
}
.json-pre {
  margin: 8px 0 0; padding: 12px; overflow: auto;
  flex: 1; min-height: 0;
  background: var(--text); color: var(--flaeche); border-radius: 6px;
  font-family: "Roboto Mono", Consolas, monospace; font-size: 12.5px; line-height: 1.45;
  white-space: pre; word-break: normal;
}

/* Leeres Dashboard (kein Mitarbeiter zur angemeldeten E-Mail) */
.empty-dashboard {
  max-width: 960px; margin: 64px auto; padding: 32px 16px;
  text-align: center; color: var(--muted);
}
.empty-dashboard .icon.big { width: 56px; height: 56px; color: var(--line); }
.empty-dashboard h2 { font-size: 18px; margin: 12px 0 6px; color: var(--text); font-weight: 500; }
.empty-dashboard p { margin: 0; font-size: 14px; }
/* DER GRUND EINES GESCHEITERTEN LADENS – EINE Form für jede Stelle, an der ein lazy geladener
   Bestand ausfällt (Drilldown-Liste, Historie, Kalender, Chat-Nachrichten, Gemeinden-Suche) und
   für das leere Dashboard. Sie steht ANSTELLE des „keine Einträge"-Hinweises und nicht daneben:
   die beiden Aussagen schließen einander aus.

   BYTE-GLEICH mit der Regel des ConnectorService, und zwar aus demselben Grund wie bei der
   Anmeldemaske und dem Benutzer-Chip: es ist DIESELBE Aussage desselben Produkts – „warum die
   Liste leer bleibt". Rot, weil das die Bedeutungsfarbe für „etwas geht nicht" ist (dieselbe wie
   beim Löschen); sie ist neben dem Orange der Zeilen-Hervorhebung die eine Farbe, die die
   Palette bewusst nicht führt. Ein gemeinsames Stylesheet gibt es nicht, die Doppelung muss also
   bleiben und der Nachweis sie halten. */
.lade-fehler {
  margin: 8px; padding: 8px 10px; font-size: 13px; overflow-wrap: anywhere;
  color: #d33a3a; background: #fdecec; border: 1px solid #d33a3a; border-radius: 6px;
}
/* Die DREI KINDER des Blocks: was ausfiel, warum, und ein Weg zurück. Sie stehen jetzt in
   BEIDEN Oberflächen und damit unter derselben Deckungsgleichheit wie die Regel darüber - der
   Chat kam zunächst mit einer Zeile aus, bis auch dort ein leerer Zustand vom Ausfall zu
   unterscheiden war. Der GRUND bricht um: der Text kommt vom Dienst und kann lang sein (die
   Kennung der Anfrage, ein Pfad) - dagegen steht das overflow-wrap der Regel darüber.
   DER KNOPF TRÄGT SEINE FORM SELBST, und das ist die Bedingung dafür, dass der Block in beiden
   Oberflächen derselbe ist: `.btn` kennt nur das WebUI, `.login-btn` gehört zur Anmeldemaske
   und ist 100 % breit - derselbe Block hinge sonst je Oberfläche an einem anderen Knopf-Satz und
   sähe zweimal anders aus. Dieselbe Lehre wie bei der Anmeldemaske, die aus genau diesem Grund
   ihr eigenes `.login-btn` bekommen hat. */
.lade-fehler .lf-kopf { font-weight: 500; }
.lade-fehler .lf-grund { margin: 4px 0 10px; }
.lade-fehler .lf-knopf {
  display: inline-flex; align-items: center; gap: 6px;
  background: #ffffff; color: #d33a3a; border: 1px solid #d33a3a; border-radius: 6px;
  padding: 6px 12px; cursor: pointer; font: inherit; font-size: 13px;
}
.lade-fehler .lf-knopf:hover { background: #fbdada; }
.empty-dashboard .lade-fehler { margin: 0 auto; max-width: 640px; text-align: left; }
.empty-dashboard p + p { margin-top: 16px; }

/* Die uebrigen `.login-*`-Regeln standen hier verstreut (Formular, Eingabefelder, Verweis,
   Trenner, Hinweiszeile) und sind in den EINEN Block der Anmeldemaske weiter oben gewandert:
   nur beisammen laesst er sich gegen den des ConnectorService halten. */

/* Breadcrumb im Header */
/* Hamburger + Breadcrumb in einer Zeile; am Desktop fuellt sie den mittleren Topbar-Bereich. */
.bc-row { flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px; }
.breadcrumb {
  flex: 1; min-width: 0;
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px;
  font-size: 14px; color: rgba(255,255,255,.85);
}
.breadcrumb .crumb { cursor: pointer; color: rgba(255,255,255,.85); }
.breadcrumb .crumb:hover { text-decoration: underline; }
.breadcrumb .crumb.current { color: #ffffff; font-weight: 500; cursor: default; text-decoration: none; }
.breadcrumb .sep { width: 14px; height: 14px; color: rgba(255,255,255,.5); }

/* Die beiden ANSICHTS-AKTIONEN am rechten Ende der Breadcrumb-Zeile (nach oben, neu laden).
   Sie sind Symbolknoepfe im Stil des Hamburgers und des Benutzersymbols - eine Beschriftung
   truege in der Kopfzeile nur Breite bei, und der Titel nennt beim Pfeil ohnehin das ZIEL. */
.bc-aktionen { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }
.bc-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  background: transparent; border: none; border-radius: 6px; cursor: pointer;
  color: rgba(255,255,255,.85);
}
.bc-btn:hover { background: rgba(255,255,255,.12); color: #ffffff; }
/* AUSGEGRAUT und nicht ausgeblendet: ein Knopf, der verschwindet, laesst die Zeile springen -
   und der Pfeil ist an der Wurzel jedes Dashboards wirkungslos. */
.bc-btn[disabled] { opacity: .35; cursor: default; }
.bc-btn[disabled]:hover { background: transparent; color: rgba(255,255,255,.85); }
.bc-btn.laeuft svg { animation: bc-dreh 900ms linear infinite; }
@keyframes bc-dreh { to { transform: rotate(360deg); } }
/* Der Trenner zum Benutzermenue: die beiden gehoeren zur ANSICHT, jenes zum BENUTZER. */
.bc-aktionen::after {
  content: ''; width: 1px; height: 18px; margin-left: 6px; background: rgba(255,255,255,.25);
}

/* KEINE Lesespalte mehr. Sie war es zweimal: erst 960 px fuer Fliesstext, dann 1280 px, weil das
   WebUI ueberwiegend TABELLEN zeigt und die bei 960 px durchgaengig nicht passten (die
   Erfassungen eines Arbeitstages brauchen 1132 px, die Kennzahlen/Positionen/Abgeltungen einer
   Abrechnung 926/925/1162 px). Damit war die Begruendung schon aufgebraucht: eine Lesespalte
   bemisst sich am FLIESSTEXT, und den gibt es hier nicht. Bei 1280 px blieb auf einem breiten
   Schirm links und rechts ein Streifen, der nichts traegt, waehrend dieselbe Tabelle daneben in
   ihrem eigenen Container scrollen musste. Die Breite kommt daher jetzt vom Fenster; die
   Metadaten-Formulare bleiben lesbar, weil table.meta ihre vier Spalten per colgroup verteilt
   (1 %/49 %/1 %/49 %) und die Beschriftungsspalten shrink-to-fit bleiben. */
.content { padding: 16px; }

/* Dashboard-Kopf mit Bearbeiten/Abbrechen/Speichern */
.dash { margin-bottom: 18px; }

/* Der Block sitzt OHNE Zwischenraum zwischen der Kopfzeile und den Listen-Reitern: oben hebt das
   negative Aussenmass das Innenmass von .content auf (der Streifen dort trennte nichts, er stand
   nur zwischen zwei Flaechen, die ohnehin zusammengehoeren), unten tritt an die Stelle des
   Abstandes eine Linie im AKZENT. Damit ist der Block oben und unten von derselben Farbe gefasst -
   er steht als ein Stueck da, statt oben anzudocken und unten auszufransen. EIN Pixel und nicht
   drei: die Grenze soll die Haelften trennen, nicht den Blick auf sich ziehen - der Akzent traegt
   sie auch in Haarstaerke. Sie nahm
   dafuer --header und nennt jetzt --accent: die beiden tragen denselben Wert (#3a6982), aber die
   Linie gehoert zum AKZENT und nicht zur Kopfzeile - sie steht mitten im Inhalt, und der aktive
   Reiter darunter zieht seine Unterkante aus derselben Variablen. Sie ist die eigentliche Grenze: darueber
   steht das Objekt selbst, darunter die Listen seiner Kinder - und ein Strich sagt das
   unmissverstaendlich, waehrend ein Abstand es nur andeutet. Die 1-px-Kanten, die dort sonst
   zusammentraefen (die Unterkante der Karte und die Oberkante der Reiter), entfallen dafuer -
   sonst laegen drei Linien uebereinander, wo eine gemeint ist. */
.content > .dash { margin-top: -16px; margin-bottom: 0; border-bottom: 1px solid var(--accent); }
.content > .dash > .card { border-bottom: none; }
.content > .tabs { border-top: none; }

/* Der Dashboard-Block laeuft ueber die GANZE Breite von main.content und aussen eckig aus: die
   negativen Aussenmasse heben genau dessen Innenmass (16 px) wieder auf, und die Rundungen fallen
   weg, weil eine abgerundete Ecke unmittelbar am Rand wie abgeschnittener Inhalt aussieht.
   MITGEZOGEN wird die Reiter-/Listen-Kette darunter: sie ist derselbe Baustein eine Ebene tiefer
   (nav.tabs + section.liste sind GESCHWISTER von section.dash, nicht ihre Kinder), und nur den
   oberen Block umzustellen liesse die beiden Haelften verschieden aussehen. Die SEITENRAENDER
   bleiben - ohne sie verloere der Block seine Kante zum Seitenhintergrund. */
.content > .dash,
.content > .tabs,
.content > .liste { margin-left: -16px; margin-right: -16px; border-radius: 0; }
.content > .dash > .tabs,
.content > .dash > .tabs.ober,
.content > .dash > .card { border-radius: 0; }
/* Eine Aktionsleiste UNTER dem Inhalt (.dash-actions) gibt es nicht mehr: Bearbeiten, Abbrechen
   und Speichern stehen in der linken Toolbar, wo sie unabhaengig von der Laenge des Formulars
   immer an derselben Stelle sitzen. */

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--panel); color: var(--text); border: 1px solid var(--line);
  padding: 8px 14px; border-radius: 6px; cursor: pointer; font: inherit; font-size: 14px;
}
.btn:hover { background: var(--flaeche); }
/* Knopf, der NUR sein Symbol traegt: die 14px seitliche Polsterung gehoerte zum Text und
   liesse ihn ohne diesen breit und leer wirken. Was er tut, sagt sein title. */
.btn.nur-icon { padding: 8px 10px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #ffffff; }
.btn.primary:hover { background: var(--accent-dark); }
.btn.ghost { background: transparent; }
.btn.danger { background: #d33a3a; border-color: #d33a3a; color: #ffffff; }
.btn.danger:hover { background: #b92e2e; }

/* Lösch-Nachfrage als Overlay (Modal) */
.modal-overlay {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(0,0,0,.4);
  display: flex; align-items: center; justify-content: center; padding: 16px;
}
/* Solange ein Overlay offen ist, scrollt NUR der Dialog: der SEITEN-Scrollbalken wird
   stillgelegt, damit ein Rad-Dreh ueber dem Overlay nicht den Hintergrund verschiebt (der
   Dialog liegt fixiert darueber, der Hintergrund wanderte sonst unbemerkt weg). Der
   wegfallende Balken wuerde den Inhalt um seine Breite nach rechts springen lassen –
   --sb-breite (in app.js beim Oeffnen gemessen) gleicht ihn als padding-right aus. */
body.modal-offen { overflow: hidden; padding-right: var(--sb-breite, 0px); }

/* Overlay, das AUS einem anderen Overlay heraus geoeffnet wird (Zulagen-Detailliste aus der
   Stundenbewertung). Ohne eigenen z-index entscheidet allein die DOM-Reihenfolge unter den
   gleichrangigen .modal-overlay – und ein Dialog, der weiter oben im Markup steht, verschwindet
   unter dem, aus dem er geoeffnet wurde. */
.modal-overlay-top { z-index: 60; }

/* Kurzlebige Rueckmeldung am unteren Rand. Sie traegt, was ein sich schliessender Dialog sonst
   mitnaehme. Ueber den Overlays (z-index 70), weil sie erscheint, WAEHREND eines schliesst -
   sonst blitzt sie eine Bildfrequenz lang darunter auf. Sie faengt keine Klicks ausser den
   eigenen ab, denn sie liegt nur ueber ihrem eigenen Kasten. */
.app-hinweis {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 70;
  max-width: min(90vw, 640px); padding: 10px 18px; border-radius: 8px; cursor: pointer;
  background: var(--header); color: #fff; font-size: 14px; line-height: 1.4;
  box-shadow: 0 4px 16px rgba(0,0,0,.28);
}
.modal {
  position: relative;
  background: var(--panel); border-radius: 10px; width: 100%; max-width: 380px;
  padding: 20px; box-shadow: 0 8px 30px rgba(0,0,0,.25);
}
/* Das X rechts oben ist der EINZIGE Knopf zum Verlassen – einen "Abbrechen"/"Schließen" in der
   Knopfzeile gibt es nicht mehr, dort steht nur noch, was etwas TUT. Daneben schließt die
   Escape-Taste (schliesseOberstenDialog) und ein Klick auf den Hintergrund. Es liegt ABSOLUT im
   Dialog und nicht in der Titelzeile: manche Dialoge haben einen mehrzeiligen Titel, manche gar
   keinen, und an derselben Stelle soll es in allen sitzen. */
.modal-x {
  position: absolute; top: 8px; right: 10px; z-index: 1;
  width: 30px; height: 30px; padding: 0; border: 0; border-radius: 6px;
  background: transparent; color: var(--muted); cursor: pointer;
  font-size: 22px; line-height: 1; font-family: inherit;
}
.modal-x:hover:not(:disabled) { background: var(--hover, rgba(0,0,0,.06)); color: var(--text); }
.modal-x:disabled { opacity: .4; cursor: default; }
/* Platz fuer das X, damit ein langer Titel nicht darunter laeuft. */
.modal-title { font-size: 17px; font-weight: 700; margin-bottom: 8px; padding-right: 34px; }
/* Titelzeile MIT einer Bedienung rechts (Geldabgeltung: der Auszahlungsmodus). Er gilt fuer das
   ganze Overlay und gehoert daher neben die Ueberschrift - nicht mitten ins Blatt. Das
   padding-right der Titelzeile haelt ihn vom X frei; er schrumpft nicht (flex-shrink: 0), damit
   ein langer Titel ihn nicht zusammendrueckt, und die Zeile bricht auf schmalen Fenstern um. */
.modal-title-zeile {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
}
.modal-title-zeile .titel-auswahl { flex: 0 0 auto; font-weight: 400; }
.modal-title-zeile .titel-auswahl select { font-family: inherit; font-size: 13px; padding: 3px 6px; }
.modal-body { font-size: 14px; color: var(--text); margin-bottom: 18px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* Fortschritt eines Laufs ueber die ganze Belegschaft: der NAME dessen, der gerade gerechnet wird,
   und daneben der Zaehler. Der Name kann lang werden und wird dann abgeschnitten – der Zaehler
   nicht, er ist die Angabe, die man sucht. Tabellenziffern, damit er beim Hochzaehlen nicht wackelt. */
.fortschritt-zeile { display: flex; align-items: baseline; gap: 12px; margin-bottom: 10px; }
.fortschritt-name { flex: 1 1 auto; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fortschritt-zaehler { flex: 0 0 auto; color: var(--muted); font-variant-numeric: tabular-nums; }
.fortschritt-balken { height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; }
.fortschritt-fuellung { height: 100%; background: var(--header); transition: width .15s linear; }

.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 10px; margin-bottom: 0; padding: 8px 22px; overflow: visible;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
}

/* Reiter (Listen der untergeordneten Klassen) innerhalb des Dashboards */
.tabs {
  display: flex; flex-wrap: wrap; gap: 0; background: var(--panel);
  border: 1px solid var(--line); border-radius: 8px 8px 0 0; border-bottom: none;
  overflow: hidden;
}
.tabs button {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none; border-bottom: 4px solid transparent;
  padding: 12px 18px; cursor: pointer; font: inherit; font-size: 15px; color: var(--muted);
}
/* Der Reiter unter dem Zeiger bekommt die FLAECHE und eine angedeutete Unterkante. Er hatte
   zuvor nur die Textfarbe (--muted -> --text), und das war GEMESSEN 1,0 % des Reiterstreifens
   gegen jetzt 12,8 % - nur die Buchstaben wurden dunkler, waehrend die Flaeche gleich blieb.
   Die FLAECHE ist dabei das Haus-Idiom fuer "hier kann man klicken" und stand an vier Stellen
   schon so da (.btn:hover, .erf-table tbody tr:hover td, table.arr-table thead th:hover,
   .erf-table th.sortable:hover); der Reiter war die Ausnahme. Die UNTERKANTE traegt daneben
   eine eigene Aussage: sie steht genau dort, wo gleich der Akzentstrich stuende, und sagt damit
   "hierhin wandert die Auswahl" statt bloss "hier ist der Zeiger" - sie kostet nichts, weil die
   4 px ohnehin als transparent reserviert sind, und laesst das Layout unbewegt.
   NICHT die AKZENTFARBE, und das ist die eigentliche Entscheidung: mit Akzent-Text und
   Akzent-Kante saehe der ueberfahrene Reiter aus wie der AKTIVE. So bleibt der Unterschied
   eindeutig - der aktive traegt Akzent, font-weight 600 und den kraeftigen Strich, der
   ueberfahrene eine helle Flaeche und eine helle Kante.
   :not(.active) und nicht blosses :hover: die beiden Regeln haben DIESELBE Spezifitaet, es
   entscheidet also die Reihenfolge in der Datei - eine spaeter eingefuegte Hover-Regel
   ueberschriebe still den Akzentstrich des aktiven Reiters. Die Ausnahme macht es davon
   unabhaengig. Die gerundete Ecke des ERSTEN Reiters haelt dabei von selbst: .tabs traegt
   overflow: hidden. */
.tabs button:not(.active):hover {
  background: var(--flaeche); color: var(--text); border-bottom-color: var(--line);
}
/* Der AKTIVE Reiter traegt GEWICHT und STRICH und nicht bloss Akzentfarbe. Er stand mit
   font-weight 500 und 3 px da, und das war GEMESSEN 13,2 % seiner eigenen Flaeche gegenueber
   demselben Reiter ohne .active - waehrend ein ueberfahrener seit der Hover-Aenderung darueber
   99,5 % aendert: der FLUECHTIGE Zustand war lauter als der DAUERHAFTE, und damit sah man
   besser, wo der Zeiger steht, als wo man ist. Die Schieflage ist eine Folge jener Aenderung -
   davor stand es 13,2 zu 1,0 und damit richtig herum.
   ZWEI Griffe, und beide sind schon vorhandene Stellschrauben: 600 statt 500 (das Wort selbst
   traegt den Zustand, auch neben einem hell aufleuchtenden Nachbarn) und 4 statt 3 px Strich -
   die Breite steht an .tabs button und gilt damit fuer JEDEN Reiter, sodass das Layout
   unbewegt bleibt und die Hover-Kante mitwaechst.
   NICHT die FLAECHE, obwohl sie mit 97,8 % das deutlichste Mittel waere (der Streifen getoent,
   der aktive weiss - die Karteireiter-Umkehr): der ueberfahrene Reiter traegt seit der
   Hover-Aenderung genau diese Flaeche, und die beiden saehen dann bis auf Akzent und Strich
   gleich aus - dieselbe Verwechslung, an der zuvor schon die Akzent-Variante des Hovers
   gescheitert ist. Der Zugewinn ist damit der kleinere (16,0 % statt 13,2), aber er kostet den
   Unterschied zum Hover nicht. */
.tabs button.active { color: var(--accent); font-weight: 600; border-bottom-color: var(--accent); }
.tabs .count { margin-left: 2px; }

.liste {
  border: 1px solid var(--line); border-top: none; border-radius: 0 0 8px 8px;
  padding: 10px; background: var(--panel);
}

/* Erzeugen-Dropdown (Abwesenheiten: Urlaubs- vs. Zeitausgleichsantrag). */
.erzeugen-dropdown { position: relative; }
/* Der Pfeil zeigt NACH UNTEN, weil das Menue dorthin aufklappt - dieselbe 90deg-Drehung
   des Rechts-Chevrons wie am Benutzermenue (.topbar-user .tu-caret). */
.erzeugen-dropdown .chev { width: 16px; height: 16px; margin-left: 2px; transform: rotate(90deg); }
/* Die FLAECHE eines aufklappbaren Menues - EINE Regel fuer beide Menues des Dashboards. Sie
   unterscheiden sich nur darin, WORAN sie haengen: das Erzeugen-Menue absolut am Knopf, das
   Feld-Menue der Historie FIXED an gerechneten Koordinaten (sein Spaltenkopf steht in zwei
   abschneidenden Elementen, siehe .kopf-menu-liste). Zwei getrennte Regeln liefen frueher oder
   spaeter auseinander, und dann saehen zwei Menues derselben Oberflaeche verschieden aus. */
.erzeugen-menu, .kopf-menu-liste {
  z-index: 20; min-width: 200px; background: #fff;
  border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 4px 16px rgba(11, 20, 26, .15); padding: 4px; display: flex; flex-direction: column;
}
.erzeugen-menu { position: absolute; right: 0; top: calc(100% + 4px); }
/* Ein Eintrag bleibt EINZEILIG (white-space: nowrap) und das Menue richtet sich in der Breite
   nach ihm (min-width statt einer festen Breite): "Sachbezug Firmenfahrzeug" brach sonst um, und
   eine zweizeilige Zeile in einer Auswahlliste liest sich wie zwei Eintraege. */
.erzeugen-item, .kopf-menu-item {
  font: inherit; text-align: left; padding: 8px 12px; border: 0; background: transparent;
  border-radius: 6px; cursor: pointer; color: inherit; white-space: nowrap;
}
.erzeugen-item:hover, .kopf-menu-item:hover { background: var(--flaeche); }

/* DAS FELD-MENUE IM SPALTENKOPF der Historie. Der Kopf beschriftet die Spalte und WAEHLT sie
   zugleich aus - die Filterzeile darueber ist damit entfallen; sie sagte dasselbe ein zweites Mal
   und nahm eine ganze Zeile dafuer.

   Der KNOPF sieht aus wie der Kopf, in dem er steht (font/color/letter-spacing erben von
   table.arr-table thead th) - er soll nicht als Schaltflaeche auffallen, sondern als Kopf, der
   sich anklicken laesst; das sagt der Chevron. */
.kopf-menu-th { position: relative; }
.kopf-menu-knopf {
  font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit;
  border: 0; background: transparent; padding: 0; cursor: pointer;
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
}
.kopf-menu-knopf > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Der Pfeil zeigt NACH UNTEN, weil das Menue dorthin aufklappt - dieselbe 90deg-Drehung wie am
   Erzeugen-Knopf und am Benutzermenue. */
.kopf-menu-knopf .chev { width: 14px; height: 14px; flex: 0 0 auto; transform: rotate(90deg); }
/* GEFILTERT: der Kopf traegt dann den Feldnamen statt "Feld", und der Punkt sagt, dass die Tabelle
   nicht alles zeigt - ohne ihn saehe eine eingeschraenkte Liste wie eine vollstaendige aus. */
.kopf-menu-knopf.gefiltert::after {
  content: ''; width: 5px; height: 5px; border-radius: 50%;
  background: var(--accent); flex: 0 0 auto;
}
/* FIXED und nicht absolut: der Spaltenkopf liegt in .arr-wrap (overflow-x: auto) und in
   .arr-table (overflow: hidden), und beide schnitten ein absolut positioniertes Menue ab. Die
   Koordinaten rechnet oeffneHistorieFeldMenu aus dem Rechteck des Knopfes; ein Scrollen schliesst
   es, weil es sonst neben seinem Knopf haengen bliebe. */
.kopf-menu-liste { position: fixed; max-height: 60vh; overflow-y: auto; }
.kopf-menu-item {
  display: flex; align-items: center; gap: 12px; justify-content: space-between;
  font-size: 14px; text-transform: none; letter-spacing: normal;
}
.kopf-menu-item.aktiv { background: var(--flaeche); font-weight: 600; color: var(--accent); }
/* Die ANZAHL der Zeilen hinter dem Feld: sie sagt VOR dem Klick, ob dahinter eine Zeile steht oder
   zwanzig. Gedaempft, damit sie den Namen nicht ueberstimmt. */
.kopf-menu-zahl { color: var(--muted); font-size: 12.5px; font-variant-numeric: tabular-nums; }

/* Namensfilter; Eingabe links, die beiden Listen-Aktionen rechtsbündig. Das margin-left
   haengt an der GRUPPE und nicht am einzelnen Knopf: an .btn traefe es beide und schoebe
   den zweiten vom ersten weg. */
.liste-filter { margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
.liste-filter .liste-aktionen { margin-left: auto; flex: 0 0 auto; display: flex; align-items: center; gap: 8px; }
.filter-input {
  width: 100%; max-width: 320px; font: inherit; font-size: 14px;
  /* Dasselbe Polster wie '.edit-input' - es ist dieselbe Sache: ein einzeiliges Eingabefeld.
     Es stand auf 7/10 und damit auf einem dritten Wert neben den 7/11 des Formularfeldes und den
     6/8 des Details-Reiters; welcher galt, entschied allein, wo man gerade hinsah. */
  border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px; background: #fff;
}
.filter-input:focus { outline: none; border-color: var(--accent); }

/* Das Suchfeld des GEMEINDEN-Reiters. Dieselbe Eingabe wie der Namensfilter der Zeilenlisten –
   den Abstand traegt dort die Gruppe .liste-filter, die es hier nicht gibt (das Feld steht allein
   ueber der Tabelle). */
.gemeinden-tab .filter-input { margin-bottom: 8px; }

/* SORTIER-CHIPS der Zeilen-Listen. Chips und keine Spaltenkoepfe: die Zeilenliste hat keinen Kopf,
   und am Mobile waere ein Klickziel in der Zeile selbst nicht zu treffen. Der aktive Chip traegt
   die Akzentfarbe und den Richtungspfeil - beides sagt zusammen, wonach und wie sortiert ist. */
.sort-chips { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.sort-chip {
  font: inherit; font-size: 12.5px; padding: 5px 11px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 999px; background: #fff; color: var(--muted);
  display: inline-flex; align-items: center; gap: 5px;
}
/* Der Hover faerbte den Rahmen von --line auf --line-stark. Seit die beiden EINE Farbe sind,
   geschaehe damit beim Ueberfahren sichtbar nichts - derselbe Grund, aus dem --accent-dark der
   Primaeraktion vorbehalten ist. Er nimmt statt dessen die Flaeche, wie jedes andere Hover-Ziel
   des Formulars (.ref-option, .cv-fc, die Tabellenkoepfe). */
.sort-chip:hover { background: var(--flaeche); }
.sort-chip.aktiv {
  border-color: var(--accent); background: var(--flaeche);
  color: var(--accent); font-weight: 500;
}
/* Der Chip OHNE Wort (die REIHENFOLGE: gar nicht sortieren). Er traegt nur sein Symbol, und die
   seitliche Polsterung geht daher von 11 auf 9 px zurueck - mit der Wort-Polsterung sitzt ein
   18-px-Symbol in einem schlauchfoermigen Feld. Sein NAME steht im title und im aria-label. */
.sort-chip.nur-symbol { padding: 5px 9px; }
.sort-chip .icon { width: 18px; height: 18px; }

/* ArbeitszeitErfassungen als Tabelle (Spaltenheader sortierbar) */
.erf-table { width: 100%; border-collapse: collapse; background: var(--panel); }
.erf-table thead th {
  text-align: left; font-size: 12px; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase; color: var(--accent);
  background: var(--flaeche); padding: 11px 12px; border-bottom: 2px solid var(--line);
}
/* Sortierbare Header klar als klickbar markieren. */
.erf-table th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.erf-table th.sortable:hover { background: var(--line); color: var(--text); }
.erf-table th.sortable:first-child { border-top-left-radius: 8px; }
/* Sortier-Indikator: gemeinsam fuer beide Tabellen-Varianten (erf-table = list-table, arr-table). */
.erf-table th .sort, .arr-table th .sort { margin-left: 4px; font-size: 11px; color: var(--muted); }
.erf-table th .sort.aktiv, .arr-table th .sort.aktiv { color: var(--accent); }
.erf-table .col-aktion { cursor: default; }

/* Abschnitts-Ueberschrift einer Array-Tabelle (Adressen / Bankverbindungen / Kinder / Pausen).
   Sie steht seit jeher im KOPF der Tabelle (.arr-kopf) und traegt deshalb selbst keinen Abstand
   mehr - den setzt der Kopf, der auch den Erzeugen-Knopf haelt. Eine :first-child-Regel gibt es
   dafuer NICHT (mehr): die Ueberschrift ist innerhalb des Kopfes IMMER das erste Kind, die Regel
   griffe also ausnahmslos und haette den Abstand zwischen zwei Tabellen zunichte gemacht. */
.details-titel {
  margin: 0; font-size: 13px; font-weight: 600; color: var(--text);
  text-transform: uppercase; letter-spacing: .04em;
}

/* Ein Monat der Abrechnungs-/Lohnset-Auswahl, der bereits ABGERECHNET ist oder sich hier gar nicht
   abrechnen laesst. GRAU und NICHT gesperrt: die Aufrollung ist der vorgesehene Weg, eine falsche
   Abrechnung zu korrigieren – ein disabled-Monat naehme ihn. Was die Farbe bedeutet, sagt der
   Hinweis darunter; die Farbe allein warnt, der Satz nennt den Grund. */
.df-input option.monat-grau { color: var(--muted); }
.monat-hinweis { margin: 8px 2px 0; }

/* Zwei Detail-Felder als Paar nebeneinander (am Mobile umbrechend). */
.details-paar { display: flex; gap: 16px; flex-wrap: wrap; }
.details-paar > .details-feld { flex: 1 1 220px; min-width: 0; }

/* Einzelnes Detail-Feld (z.B. Grundgehalt) im Details-Reiter. */
.details-feld { display: flex; align-items: center; gap: 10px; padding: 6px 0; font-size: 14px; }
.details-feld .df-label { min-width: 140px; color: var(--muted); }
.details-feld .df-wert { font-weight: 600; }
.details-feld .df-input {
  /* Polster wie '.edit-input' (siehe dort) - waagrecht stand es laengst auf 8, senkrecht auf 6. */
  padding: 4px 8px; border: 1px solid var(--border); border-radius: 6px; font: inherit; max-width: 200px;
}

/* Gehaltsabrechnung-Overlay: Tabelle der Kennzahl-Ergebnisse (Monatlich/13./14./Jahr). */
/* Höhe auf 90vh begrenzt und als Flex-Spalte aufgebaut, damit die (potenziell langen) Inhalte
   – Kennzahlen-Tabelle UND Formel-Baum – INNERHALB des Dialogs vertikal scrollen (Titel/Kopf/
   Aktionen bleiben sichtbar). Gilt für Gehaltsabrechnung, Stundenbewertung und Scheibe-Detail. */
.modal-gehalt { max-width: 860px; width: 100%; max-height: 90vh; display: flex; flex-direction: column; }
/* Scheiben-Bewertung-Overlay: breiter (14 Spalten) – bis 96 % der Viewport-Breite, gedeckelt. */
.modal-scheiben { max-width: min(98vw, 1900px); }
.scheiben-kopf { margin-bottom: 10px; }
.modal-gehalt .tbl-scroll { overflow: auto; flex: 1 1 auto; min-height: 0; }
/* Gehaltsabrechnung (ohne Scheiben-Tabelle): die Kennzahlen-Tabelle nimmt ihre natürliche Höhe
   ein (kein eigener Scrollbalken); der Formel-Baum darunter füllt den Rest und scrollt. */
.modal-gehalt:not(.modal-scheiben) .tbl-scroll { flex: 0 1 auto; }
/* Formel-Baum (Scheibe-Detail bzw. Gehaltsabrechnung) ist ein scrollendes Kind. */
.modal-gehalt .formel-baum { overflow-y: auto; flex: 1 1 auto; min-height: 0; }
/* Kopfzeile der Tabelle beim vertikalen Scrollen fixieren. */
.tbl-scheiben thead th { position: sticky; top: 0; z-index: 1; background: var(--panel); }
/* Gesamtsummen-Zeile (tfoot) klar abgesetzt. */
.tbl-scheiben tfoot td { border-top: 2px solid var(--border); font-weight: 700; background: var(--bg); }
/* Trennzeile pro Arbeitstag (Datum + KW), abgesetzt wie ein Abschnittskopf. */
/* Aufklappbarer Tages-Kopf (Summe des Tages; klickbar, klappt die Minuten auf/zu). */
.tbl-scheiben tr.scheiben-tag td {
  font-weight: 700; background: transparent; color: var(--text);
  border-top: 2px solid var(--border); white-space: nowrap;
}
/* Einrückung der Nesting-Ebenen in gleichmäßigen 16px-Stufen:
   Woche 0 > Tag 16 > zeitart-Block 32 > Block gleicher Minuten 48 > Minute 64. */
.tbl-scheiben tr.scheiben-tag td:first-child { padding-left: 16px; }
/* Kopf eines Blocks gleicher Minuten: dieselbe Zeile wie eine Minute (inkl. rg-Popups), nur
   eine Ebene tiefer eingerueckt und mit Aufklapp-Caret. Der Zeiger zeigt, dass sie klickbar ist. */
.tbl-scheiben tbody tr.scheiben-gruppe { cursor: pointer; }
.tbl-scheiben tbody tr.scheiben-gruppe td:first-child { padding-left: 48px; }
.tbl-scheiben tr.scheiben-tag-klick { cursor: pointer; }
/* Hover: die Zeile NICHT umfärben (die zeitart-Tönung soll sichtbar bleiben), sondern orange
   einrahmen – oben/unten an jeder Zelle, links an der ersten, rechts an der letzten Zelle der Zeile. */
.tbl-scheiben tr.scheiben-tag-klick:hover td,
.tbl-scheiben tr.scheiben-woche:hover td,
.tbl-scheiben tbody tr.scheiben-klick:hover td { box-shadow: inset 0 2px 0 #f57c00, inset 0 -2px 0 #f57c00; }
.tbl-scheiben tr.scheiben-tag-klick:hover td:first-child,
.tbl-scheiben tr.scheiben-woche:hover td:first-child,
.tbl-scheiben tbody tr.scheiben-klick:hover td:first-child { box-shadow: inset 0 2px 0 #f57c00, inset 0 -2px 0 #f57c00, inset 2px 0 0 #f57c00; }
.tbl-scheiben tr.scheiben-tag-klick:hover td:last-child,
.tbl-scheiben tr.scheiben-woche:hover td:last-child,
.tbl-scheiben tbody tr.scheiben-klick:hover td:last-child { box-shadow: inset 0 2px 0 #f57c00, inset 0 -2px 0 #f57c00, inset -2px 0 0 #f57c00; }
/* Aufklappbarer Wochen-Kopf (Summe der KW; leichter als der Tages-/Gesamtkopf). */
.tbl-scheiben tr.scheiben-woche { cursor: pointer; }
.tbl-scheiben tr.scheiben-woche td {
  font-weight: 600; background: var(--panel); border-top: 1px solid var(--border);
}
.tbl-scheiben .kw-caret { display: inline-block; width: 1em; color: var(--muted); }
/* Klammer-Zusatz (KW-Datumsspanne bzw. zeitart-Block-Zeitraum): gedämpft und NICHT fett. */
.tbl-scheiben .kw-spanne { color: var(--muted); font-weight: 400; }
/* zeitart-Gruppen-Kopf (unter dem Tag): eingerueckt und mit der zeitart-Farbe hinterlegt - aber
   NICHT halbfett. Er trug 600 und damit DASSELBE Gewicht wie die WOCHE, also eine Ebene ZWEI
   Stufen ueber ihm; nach unten gelesen lief die Reihe 600 (Woche) -> 700 (Tag) -> 600
   (zeitart-Block), stieg also an und fiel wieder auf den Ausgangswert zurueck. Ein Gewicht hebt
   nur so lange etwas hervor, wie es die Ebene benennt; wiederholt es eine hoehere, sagt es gar
   nichts mehr. Ohne es faellt die Reihe monoton (700/600 fuer die Koepfe, darunter nichts), und
   unterschieden ist der Block ohnehin doppelt - durch seine Stufe der Einrueckung und durch seine
   eigene Farbe. */
.tbl-scheiben tr.scheiben-zeitart td { border-top: 1px solid var(--border); }
.tbl-scheiben tr.scheiben-zeitart td:first-child { padding-left: 32px; }
/* Minuten-Detailzeile am tiefsten eingerückt – eine Stufe unter dem Kopf ihres Blocks gleicher
   Minuten. Der Kopf traegt selbst .scheiben-klick; die Regel darueber ist spezifischer
   (tbody + .scheiben-gruppe) und haelt ihn daher auf seiner eigenen Ebene. */
.tbl-scheiben tr.scheiben-klick td:first-child { padding-left: 64px; }
/* Der Monatsabschluss steht auf der Ebene der WOCHEN (ganz aussen, keine Einrueckung) und ist wie ein
   Wochenkopf halbfett abgesetzt. Er nutzt sonst die Minuten-Zeile, weil er Werte samt Rechtsgrundlagen-
   Popups und Detail-Symbol traegt; nur Einrueckung und Gewicht unterscheiden ihn. tbody im Selektor,
   damit er die 64px-Regel der Minuten-Zeile schlaegt. */
.tbl-scheiben tbody tr.scheiben-monatsabschluss td:first-child { padding-left: 10px; }
.tbl-scheiben tbody tr.scheiben-monatsabschluss td { font-weight: 600; border-top: 1px solid var(--border); }
/* Der Dienstabschluss steht auf der Ebene der zeitart (32px) und zeigt seine Werte direkt –
   ohne Aufklappen, weil ein Tag hoechstens EINEN Dienst und damit einen Marker traegt. */
.tbl-scheiben tbody tr.scheiben-dienstabschluss td:first-child { padding-left: 32px; }
.tbl-scheiben tbody tr.scheiben-dienstabschluss td { font-weight: 600; border-top: 1px solid var(--border); }
/* Datum und Von–Bis sind die beschreibenden Spalten und duerfen NIE umbrechen: "07:00–07:01" auf
   zwei Zeilen zu brechen macht die Zeile doppelt hoch, ohne etwas zu gewinnen. Der Klammer-Zusatz
   des Gruppenkopfs ("(3 gleiche Minuten)") darf hingegen weiterhin in die naechste Zeile rutschen. */
.tbl-scheiben tbody td:first-child,
.tbl-scheiben tbody td:nth-child(2) { white-space: nowrap; }
.tbl-scheiben tbody td .kw-spanne { white-space: nowrap; display: inline-block; }
/* Legende der zeitart-Farben (über der Stundenbewertungs-Tabelle). */
.scheiben-legende { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 6px 0 10px; font-size: 12px; }
.zeitart-chip { display: inline-flex; align-items: center; gap: 5px; color: var(--muted); }
.zeitart-swatch { display: inline-block; width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--border); }
/* Fakten-Spalte: schmal halten (IDs umbrechen lassen). */
/* Rechtsgrundlage als Hover-Popup je Zelle (statt eigener Spalte): erscheint beim Ueberfahren der
   Zelle, reine Anzeige. Bewusst an der KLASSE td.rgz (nicht an einer Tabelle) haengend – die
   Stundenbewertung und die Zulagen-Detailliste nutzen dieselbe Komponente rg-td; ohne den
   allgemeinen Selektor bliebe das Popup in der zweiten Tabelle ungestylt und damit als statischer
   Text IN der Zelle stehen (die Spalte wuerde auf die Popup-Breite aufgehen). */
td.rgz { position: relative; }
/* Das Popup liegt als FIXED positionierte Schicht ueber allem: so kann es kein Vorfahr mit
   overflow (der .tbl-scroll der Tabelle, der Dialog) abschneiden, und es erzeugt dort auch keinen
   Scrollbalken mehr. Seine Koordinaten setzt rg-td als Inline-Stil (Fenster-Koordinaten aus der
   Zellposition); links/oben hier nur als Ausgangswert, bis gemessen wurde.
   z-index ueber dem obersten Overlay (.modal-overlay-top = 60), damit es auch im Dialog obenauf
   liegt. Voraussetzung fuer fixed ist, dass kein Vorfahr transform/filter/perspective traegt –
   das gilt hier (nur die mobile .toolbar wird transformiert, sie enthaelt keine Tabelle). */
td.rgz .rg-pop {
  position: fixed; left: 0; top: 0; z-index: 70;
  /* Breit genug fuer den Originalwortlaut. width:max-content ist noetig, weil das Popup sonst per
     shrink-to-fit schmal bliebe und die max-width nie erreichte. */
  width: max-content; min-width: 320px; max-width: min(760px, 92vw);
  padding: 8px 10px;
  background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18); font-size: 12px; line-height: 1.5;
  white-space: normal; text-align: left; font-weight: 400;
  /* Deckel gegen sehr lange Zitatlisten – jetzt gegen das FENSTER, nicht gegen einen Container. */
  max-height: 60vh; overflow-y: auto; overscroll-behavior: contain;
}
/* Das §-Zitat als eigene Zeile – reine Anzeige, nicht klickbar. */
td.rgz .rg-pop-quelle { display: block; }
/* Der Originalwortlaut als eigene Zeile unter dem Zitat, in "…" als Auszug gekennzeichnet.
   Er steht in der NORMALEN Textfarbe und nicht in --muted: er ist der GRUND, aus dem die Zeile
   darueber gilt - der Wortlaut der Vorschrift, wegen dessen man das Popup ueberhaupt oeffnet.
   Gedaempft las er sich wie eine Nebenbemerkung zur Fundstelle, waehrend es umgekehrt ist. Die
   KURSIVE bleibt: sie kennzeichnet ihn als ZITAT, und dafuer braucht es keine zweite Auszeichnung. */
td.rgz .rg-pop-zitat {
  display: block; font-style: italic; color: var(--text); margin: 2px 0 6px;
}
td.rgz .rg-pop-zitat:last-child { margin-bottom: 0; }
/* Spalte "Zulage %": ein Klick oeffnet die Zulagen-Detailliste (auch bei nur einer Zulage). */
.tbl-scheiben td.zul-klick { cursor: pointer; }
.tbl-scheiben td.zul-klick:hover { text-decoration: underline; }
/* Anzahl-Marker der Zulagen dieser Zeile (Detail im Klick-Dialog). */
.tbl-scheiben .zul-badge {
  display: inline-block; margin-left: 4px; padding: 0 4px; border-radius: 8px;
  background: var(--border); color: var(--muted); font-size: 10px; line-height: 15px; font-weight: 600;
}
/* Schmale letzte Spalte mit dem Symbol, das das Scheiben-Detail oeffnet. */
.tbl-scheiben td.detail-sp, .tbl-scheiben th.detail-sp { width: 1%; padding: 0 6px; text-align: center; }
/* Zentrierte Wertspalte (Grundverg. abgegolten): das kurze Ja/Nein bzw. X steht sonst linksbuendig
   weit weg vom Spaltenkopf. Nur die Werte – der Kopf behaelt seine Ausrichtung. */
.tbl-scheiben td.mid { text-align: center; }
/* Zentrierte Ja/Nein-Spalte auch in den beiden Detail-Dialogen (Zulagen/Zuschlaege). */
.tbl-zulagen th.mid, .tbl-zulagen td.mid { text-align: center; }
/* Dieselbe zentrierte Ja/Nein-Spalte in der Geldabgeltung (Auszahlung verpflichtend). */
.tbl-scheiben th.mid, .tbl-scheiben td.mid { text-align: center; }
.tbl-scheiben td.detail-sp .icon-btn { padding: 2px; }
/* Zulagen-Detailliste im Overlay: Tabelle wie die Stundenbewertung (Hover-Rahmen s.o.).
   Der Dialog richtet sich nach der BREITE SEINER TABELLE (width: max-content) statt nach einer festen
   Zahl: bei 10 bzw. 11 Spalten brauchte sie rund 1.160 px und scrollte in den frueheren 860 px
   grundsaetzlich horizontal. Nach oben deckelt ihn der Viewport (96 vw) bzw. 1.600 px – dort bleibt es
   beim Scrollbalken, etwa auf einem schmalen Fenster oder bei sehr langen Kurznamen. Nach unten haelt
   ihn min-width auf der frueheren Breite, damit eine Tabelle mit wenigen kurzen Spalten den Dialog
   nicht zu einem schmalen Streifen zusammenzieht. */
.modal-zulagen { width: max-content; min-width: min(96vw, 860px); max-width: min(96vw, 1600px); }
.tbl-zulagen tfoot td { border-top: 2px solid var(--border); font-weight: 700; background: var(--bg); }
/* Die Rechtsgrundlage ist hier KEINE Spalte, sondern das Hover-Popup jeder Wertzelle (rg-td). Es
   liegt als fixed positionierte Schicht ueber allem und wird daher von diesem Wrapper nicht mehr
   abgeschnitten – das fruehere overflow:visible als Notbehelf ist entfallen. */
.modal-gehalt .modal-actions { margin-top: 12px; }
.gehalt-grund { margin-bottom: 10px; }
/* Die übrigen Bezüge des Monats im Geldabgeltungs-Overlay: abgesetzter Abschnitt UNTER den
   Gruppen. */
.gehalt-abschnitt { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
/* Flag "Stundenbewertung uebernehmen" – zwischen den Positionen und der Gehaltsabrechnung. */
/* Die FOLGE der Modus-Wahl (die Auswahl selbst steht in der Titelzeile, siehe .modal-title-zeile). */
.gehalt-uebernehmen { margin-top: 16px; }
/* Geldabgeltungs-Overlay: es traegt zwei Tabellen plus den Formel-Baum untereinander, die zusammen
   laenger sind als der Dialog. Statt mehrerer verschachtelter Scrollbereiche (die sich gegenseitig
   die Hoehe nehmen) scrollt hier GENAU EIN Bereich – .modal-scroll –, waehrend Titel, Kopfzeile und
   Aktionen stehen bleiben. Genau das sagt der Klassenname, und mehr tut er auch nicht: die GROESSE
   kommt wie bei jedem anderen Overlay aus .modal-gehalt (bis 90vh hoch) und .modal-scheiben (bis
   98vw breit). Er war eine Zeit lang VOLLBILD (100vw/100vh, ohne Ecken) – das riss ihn aus der Reihe
   der uebrigen Dialoge, ohne dass er dadurch mehr zeigte: was er traegt, scrollt ohnehin, und die
   gewonnenen Randstreifen blieben leer. */
.modal-einscroll .modal-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* Die inneren Container nehmen darin ihre natuerliche Hoehe ein (kein zweiter vertikaler
   Scrollbalken); .tbl-scroll behaelt overflow:auto NUR fuer das horizontale Scrollen breiter Tabellen. */
.modal-einscroll .modal-scroll .tbl-scroll { flex: 0 0 auto; }
.modal-einscroll .formel-baum { flex: 0 0 auto; overflow-y: visible; }
/* Zeilen-Hover im Geldabgeltungs-Overlay: dieselbe orange Umrahmung wie in der Stundenbewertung –
   die Zeile wird NICHT umgefaerbt (Werte bleiben lesbar), sondern oben/unten an jeder Zelle und
   links/rechts an der ersten bzw. letzten Zelle eingerahmt. Gilt fuer BEIDE Tabellen des Dialogs:
   die gruppierten Positionen wie die Gehaltsabrechnung darunter. */
.modal-einscroll .gehalt-tabelle tbody tr:hover td,
.tbl-zulagen tbody tr:hover td {
  box-shadow: inset 0 2px 0 #f57c00, inset 0 -2px 0 #f57c00;
}
.modal-einscroll .gehalt-tabelle tbody tr:hover td:first-child,
.tbl-zulagen tbody tr:hover td:first-child {
  box-shadow: inset 0 2px 0 #f57c00, inset 0 -2px 0 #f57c00, inset 2px 0 0 #f57c00;
}
.modal-einscroll .gehalt-tabelle tbody tr:hover td:last-child,
.tbl-zulagen tbody tr:hover td:last-child {
  box-shadow: inset 0 2px 0 #f57c00, inset 0 -2px 0 #f57c00, inset -2px 0 0 #f57c00;
}
/* Zwischenergebnis-Baum (Kollektivvertrag): read-only, aufklappbarer Formel-Baum (steuerberatung.json). */
.formel-baum { font-size: 14px; }
.formel-baum .ze-kopf { margin-bottom: 10px; }

/* KV-Reiter am Arbeitszeitmodell: Eingabeoptionen-Liste. */
.kv-eingaben { font-size: 14px; }
.kv-eingaben .ze-kopf { margin-bottom: 12px; }
/* Auswahl des angezeigten Kollektivvertrags (nur bei mehreren ein Dropdown, sonst sein Name). */
.kv-wahl { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.kv-wahl-label { font-weight: 600; }
.kv-wahl-name { color: var(--text); }
.kv-wahl select { max-width: 100%; }
.kv-opt { padding: 10px 0; border-top: 1px solid var(--border); }
.kv-opt:first-of-type { border-top: none; }
.kv-opt-kopf { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.kv-opt-id { font-weight: 600; font-family: var(--mono, monospace); }
/* Ebene einer KV-Option (Mitarbeiter/Arbeitszeitmodell/Organisation): kleiner grauer Chip neben der
   Kennung – sagt, WO der Wert festgelegt wird, ohne die Zeile zu dominieren. */
.kv-opt-ebene { font-size: .72rem; line-height: 1.4; padding: 0 .45em; border-radius: 999px;
  background: var(--line); color: var(--muted); white-space: nowrap; }
.kv-opt-wert { color: var(--text); }
.kv-opt-desc { margin: 4px 0 6px; }
/* Die AUSWAHL einer KV-Option nimmt die Breite, die ihre Eintraege brauchen - bis zur Zeile.
   Sie erbt von .edit-input `width: 100%; max-width: 400px` und stand damit in einer Flex-Zeile
   (.kv-opt-kopf) neben Kennung und Ebenen-Chip: sie SCHRUMPFTE auf den Rest und war bei 400 px
   gedeckelt, ihre Eintraege sind aber viel laenger - der Server setzt das Etikett einer
   Tabellen-Auswahl als "<Wert> - <Bezeichnung>" zusammen. GEMESSEN an kv_taetigkeitsmerkmale
   (Gastgewerbe-KV, sieben Zeilen): der laengste Eintrag braucht 721 px und bekam 400 - jede Zeile
   war rechts abgeschnitten, und die Bezeichnung, die den Eintrag ueberhaupt lesbar macht, stand
   hinten.

   `width: auto` laesst ein natives <select> auf seinen breitesten Eintrag wachsen, `max-width:
   100%` deckelt es an der Zeile, und weil .kv-opt-kopf umbricht, rutscht es dann auf eine eigene
   Zeile statt ueberzulaufen. Das `min-width` bleibt: eine Auswahl mit lauter kurzen Werten (ja/nein,
   A/B) waere sonst ein Knopf, den man kaum trifft. GEMESSEN danach: 764 px bei 1100 px
   Fensterbreite und 528 px bei 560 px - der Deckel greift also und laesst die Zeile nicht
   ueberlaufen.

   SIE HEISST `select.kv-select` UND NICHT `.kv-select`, und das ist der eigentliche Befund: die
   Regel stand mit derselben Spezifitaet (0,1,0) wie `.edit-input`, aber WEITER OBEN in dieser
   Datei - bei Gleichstand gewinnt die spaetere, also `.edit-input`. GEMESSEN war damit auch das
   `min-width: 220px` nie wirksam: `.edit-input` setzt `min-width: 0` und ueberschrieb es. Das
   Element-Praefix hebt sie auf 0,1,1 und damit ueber die Klasse allein.

   EINE HOEHE STEHT HIER NICHT (mehr). `select.kv-select[multiple] { min-height: 80px }` stand
   daneben und war TOTES RECHT: ein natives <select multiple> ohne `size` ist in Chrome vier
   Zeilen hoch, gemessen 4 x 17,39 + 14 Polster + 2 Rahmen = 85,6 px - der Deckel von 80 kam damit
   nie zum Zug. Er haette es auch nicht gesollt: eine Hoehe in Bildpunkten trifft keine ganze
   Zeilenzahl und schneidet die letzte an. Die Hoehe zaehlt jetzt ZEILEN und steht als `size` am
   Element (app.js, kv-eingaben). */
select.kv-select { min-width: 220px; width: auto; max-width: 100%; }
.formel-baum .fk-sektion { margin-top: 18px; border-top: 1px solid var(--border); padding-top: 12px; }
.fk-node > .fk-row {
  display: flex; align-items: center; gap: 6px; padding: 3px 4px; border-radius: 6px;
}
.fk-node > .fk-row:not(.leaf) { cursor: pointer; }
.fk-node > .fk-row:not(.leaf):hover { background: var(--bg); }
.fk-chev { width: 14px; height: 14px; transition: transform .12s ease; color: var(--muted); flex: 0 0 auto; }
.fk-chev.open { transform: rotate(90deg); }
.fk-bullet { color: var(--muted); width: 14px; text-align: center; flex: 0 0 auto; }
.fk-kennung {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px;
  color: var(--accent); padding: 0 5px; border-radius: 4px; flex: 0 0 auto;
}
.fk-label { font-weight: 600; }
.fk-typ { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; }
.fk-kinder { margin-left: 16px; border-left: 1px solid var(--border); padding-left: 8px; }
.fk-rg { margin: 0 0 4px; padding-left: 20px; }
.fk-rg-zeile { font-size: 12px; color: var(--text); line-height: 1.5; }
/* Rechtsgrundlage-Zelle eines Tabellen-Literals: lesbares §-Zitat (nicht als JSON). */
.fk-rg-zitat { font-size: 12px; color: var(--muted); font-style: italic; padding-left: 12px; }
.fk-infix { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; color: var(--muted); overflow-wrap: anywhere; }
.fk-eq { color: var(--muted); }
.fk-node > .fk-row .fk-infix { min-width: 0; }
/* Nachschlagetabellen (Regeln-Reiter): waagrecht scrollbar, kompakt. */
.tab-scroll { overflow-x: auto; margin: 4px 0 2px; }
.tbl-tabelle { border-collapse: collapse; font-size: 12.5px; border: 1px solid var(--line); }
.tbl-tabelle th, .tbl-tabelle td {
  padding: 4px 8px; border: 1px solid var(--line); text-align: left; vertical-align: top;
}
.tbl-tabelle thead th { position: sticky; top: 0; background: var(--panel); font-weight: 600; white-space: nowrap; }
/* Zellen umbrechen und breite Textspalten (z.B. beschreibung) deckeln, statt endlos breit zu werden. */
.tbl-tabelle td { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; max-width: 360px; white-space: normal; overflow-wrap: anywhere; }
/* "beschreibung" als eigene, über die Restspalten gespannte Zeile: normale Schrift, volle Breite, gedämpft. */
.tbl-tabelle td.tab-beschr { max-width: none; font-family: inherit; color: var(--text); }
/* id-Spalte breiter (eine Zeile, nicht umbrechen), bezeichnung-Spalte schmäler (umbricht). */
.tbl-tabelle .tab-col-id { white-space: nowrap; max-width: none; }
.tbl-tabelle .tab-col-bezeichnung { max-width: 200px; }
.fk-infix-clip { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fk-ref-link { color: var(--accent); cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.fk-ref-link:hover { color: var(--accent); }
.fk-highlight { background: rgba(0, 168, 132, .18); border-radius: 6px; transition: background .3s ease; }
/* Berechneter Wert einer Variable (Scheibe-Detail): inline am benannten Knoten + Hover-Hinweis an refs. */
.fk-wert { margin-left: 8px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; color: var(--text); }
.fk-infix.fk-hat-wert { border-bottom: 1px dotted var(--muted); cursor: help; }
/* Anklickbare Zeile der Stundenbewertung (öffnet das Scheibe-Detail). */

.gehalt-tabelle { width: 100%; border-collapse: collapse; font-size: 14px; }
.gehalt-tabelle th, .gehalt-tabelle td { padding: 6px 10px; border-bottom: 1px solid var(--border); text-align: left; }
.gehalt-tabelle th.num, .gehalt-tabelle td.num { text-align: right; white-space: nowrap; }
.gehalt-tabelle thead th { color: var(--muted); font-weight: 600; }

/* Tabellen-Wrapper: horizontal scrollbar statt aus dem Viewport ragend (v.a. am Mobile). Der
   overflow-x:auto-Block hat min-width 0 -> die umgebende Metadaten-Tabelle/Karte waechst NICHT mit. */
.arr-wrap, .tbl-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }

/* Array-Felder als sortierbare Tabelle (Adressen, Bankverbindungen) */
.arr-table {
  /* max-content statt fester 100 %: wird der Platz zu schmal, quetscht die Tabelle die Spalten nicht
     mehr zusammen (bis die Zellen umbrechen), sondern behaelt ihre natuerliche Breite – der
     .arr-wrap darum scrollt dann horizontal. min-width haelt sie im Normalfall auf volle Breite. */
  width: max-content; min-width: 100%; border-collapse: collapse; background: #fff;
  margin: 6px 0; border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
}
/* table.arr-table erhöht die Spezifität, damit der Spaltenheader auch INNERHALB einer
   table.meta (eingebettete Pausen-Tabelle) gleich aussieht (sonst gewinnt table.meta th). */
table.arr-table thead th {
  text-align: left; font-size: 12px; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase; color: var(--accent);
  background: var(--flaeche); padding: 9px 12px; border-bottom: 2px solid var(--line);
  cursor: pointer; user-select: none;
  /* Die SPALTE richtet sich nach ihren DATEN, nicht nach ihrer Beschriftung: eine Kopfzeile wie
     "AUSZAHLUNG VERPFLICHTEND" ist 200 px breit, waehrend darunter ein einzelnes "X" steht. Bis
     120 px bleibt sie einzeilig (nowrap waere sonst der Normalfall), darueber bricht sie um.
     Gemessen an den Abgeltungen der Abrechnung: 1170 -> 1162 px, womit sie in die breite Ansicht
     passen; die Gemeinden bekommen dadurch eine zweizeilige Kopfzeile (34 -> 48 px), die Adressen
     bleiben unberuehrt. */
  max-width: 120px;
}
table.arr-table thead th:hover { background: var(--line); color: var(--text); }
/* Deckel gegen eine ausufernd breite Tabelle: bis hierher waechst eine Spalte mit ihrem laengsten
   Inhalt, danach bricht GENAU DIESE Zelle um (z.B. eine Gemeinde mit 16 weiteren Postleitzahlen). */
.arr-table td { padding: 9px 12px; font-size: 14px; border-bottom: 1px solid var(--flaeche); vertical-align: top; max-width: 320px; }
.arr-table tbody tr:last-child td { border-bottom: none; }
.arr-table .edit-input { max-width: 220px; }
.arr-table .col-aktion { width: 44px; text-align: right; background: var(--flaeche); cursor: default; }
.arr-table td.col-aktion { background: transparent; }
/* Der KOPF einer Array-Tabelle: Ueberschrift und Erzeugen-Knopf in EINER Zeile, ausserhalb des
   Scroll-Containers. Der Knopf stand zuvor als beschrifteter Button UNTER der Tabelle - bei einer
   langen Adressliste also ausser Sicht, und bei mehreren Tabellen untereinander (Adressen,
   Bankverbindungen) war nicht mehr abzulesen, zu WELCHER er gehoert. Neben der Ueberschrift sagt
   die Stellung es von selbst. Sichtbar bleibt er wie gehabt nur im Bearbeiten-Modus. */
.arr-block > .arr-kopf { display: flex; align-items: center; gap: 8px; margin: 14px 0 2px; }
.arr-block:first-child > .arr-kopf { margin-top: 4px; }
/* Ohne Ueberschrift (der Schichten-Reiter) steht der Knopf allein - dann darf der Kopf nicht die
   volle Breite beanspruchen, sonst faenge ein Klick daneben ihn mit ab. */
.arr-kopf { width: max-content; max-width: 100%; }
.arr-plus { width: 26px; height: 26px; color: var(--accent); }
.arr-plus .icon { width: 17px; height: 17px; }
.hinweis { margin: 8px 2px 0; }

/* Lokations-Link (öffnet die Karte) */
.map-link { color: var(--accent); text-decoration: underline; cursor: pointer; }
.map-link:hover { color: var(--accent); }

/* Eingebettete Karte als letzte (volle Breite) Zeile der Metadaten-Tabelle */
.map-embed {
  width: 100%; height: 280px;
  border: 1px solid var(--line); border-radius: 10px; display: block;
}
table.meta tr.map-row td { padding-top: 4px; }

/* Obere Reiter (Metadaten/Adressen/Bankverbindungen), direkt mit der Karte verbunden. */
.tabs.ober { border-radius: 10px 10px 0 0; }
.card.untertabs { border-top: none; border-top-left-radius: 0; border-top-right-radius: 0; }
.erf-table td { padding: 8px 10px; font-size: 14px; border-bottom: 1px solid var(--flaeche); }
.erf-table tbody tr { cursor: pointer; }
.erf-table tbody tr:hover td { background: var(--flaeche); }
.erf-table .col-aktion { width: 44px; text-align: right; }

/* Listenzeilen */
.list-row {
  display: flex; align-items: center; gap: 8px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 10px 8px 14px; margin-bottom: 8px;
}
.list-row:last-child { margin-bottom: 0; }
.list-row:hover { background: var(--flaeche); }
.list-main { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; cursor: pointer; }
.list-text { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.list-text strong { font-weight: 500; font-size: 15px; }
/* Die ZEITSTEMPEL-Spalte schiebt sich mit margin-left:auto ans rechte Ende; das Chevron dahinter
   verliert dafuer sein eigenes auto, sonst blieben die beiden nicht beieinander. Ein Raster aus
   zwei Spalten (Beschriftung, Wert) statt zweier Zeilen mit Doppelpunkt: so stehen die Werte
   untereinander buendig, gleich wie lang "Erzeugt" und "Geändert" sind. */
.list-main .list-meta {
  margin-left: auto; flex: 0 0 auto;
  display: grid; grid-template-columns: auto auto; column-gap: 8px; row-gap: 2px;
  font-size: 11.5px; color: var(--muted); white-space: nowrap; text-align: right;
}
.list-meta .lm-label { text-align: left; opacity: .75; }
.list-main .chev { margin-left: 0; color: var(--muted); }

/* STORNIERT: die Marke am Zeilen-Symbol und der Name durchgestrichen.
   Ohne sie steht ein storniertes Objekt in der Liste wie jedes andere - der Status stand nur im
   Formular dahinter, also erst NACH dem Öffnen.
   ZWEI Signale, die dasselbe sagen: der Durchstrich fällt beim Überfliegen der Titelspalte auf,
   die Marke benennt den Grund. Der Durchstrich ist dabei das treffende Bild - stornieren IST
   durchstreichen -, und er trifft NUR den Titel: der Untertitel trägt bei mehreren Typen den
   Status im Wortlaut ("Urlaub · Storniert"), und den durchzustreichen nähme die Auskunft weg,
   die man gerade sucht. */
.zeilen-symbol { position: relative; display: flex; flex: 0 0 auto; }
/* GEFÜLLTE Scheibe mit weissem Strich und einem Ring in der Zeilenfarbe: ein blosser Umriss ist
   auf 13 px Brei. Der Ring trennt sie vom Symbol darunter und wechselt beim Hover mit. */
.storno-marke {
  position: absolute; right: -6px; bottom: -5px;
  width: 13px; height: 13px; border-radius: 50%;
  background: #d33a3a; color: #ffffff;
  box-shadow: 0 0 0 2px var(--panel);
  display: flex; align-items: center; justify-content: center;
}
.storno-marke .icon { width: 9px; height: 9px; vertical-align: 0; }
.list-row:hover .storno-marke { box-shadow: 0 0 0 2px var(--flaeche); }
.list-row.storniert .list-text strong { text-decoration: line-through; text-decoration-thickness: 1px; }
/* Am Desktop steht die MOBILE Zeile nicht da (und umgekehrt) - siehe die Media-Query unten. */
.list-text .list-meta-mobil { display: none; }

/* Runder Icon-Button (z.B. Entfernen) – Symbol bleibt Schwarz/Weiß. */
.icon-btn {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 34px; height: 34px; border: none; border-radius: 50%;
  background: transparent; color: var(--text); cursor: pointer;
}
.icon-btn:hover { background: var(--flaeche); }

/* Generische Metadaten-Tabelle (auch verschachtelt). */
table.meta { width: 100%; border-collapse: collapse; }
/* Spaltenaufteilung der Paar-Zeilen: die Beschriftungen so schmal wie ihr Text, die beiden WERTE
   je zur Haelfte. Ohne die Vorgabe verteilt der Browser die Restbreite nach dem Inhalt, und das
   linke Feld bekommt deutlich mehr (gemessen 521 gegen 338 px). */
table.meta > colgroup > col.c-label { width: 1%; }
table.meta > colgroup > col.c-wert { width: 49%; }
/* Luftigere Metadaten: mehr vertikale Polster, ruhige Zeilen-Trenner. */
table.meta th, table.meta td {
  text-align: left; vertical-align: top;
  padding: 11px 0; font-size: 15px; line-height: 1.55;
  border-top: 1px solid var(--flaeche);
}
table.meta > tbody > tr:first-child > th,
table.meta > tbody > tr:first-child > td { border-top: none; }
table.meta th {
  white-space: nowrap; width: 1%; padding-right: 28px;
  color: var(--muted); font-weight: 500; font-size: 13px;
}
/* overflow-wrap:anywhere (statt word-break:break-word) verkleinert auch die intrinsische
   Mindestbreite -> lange, ununterbrochene Strings (z.B. die objID/ULID) brechen um und die
   Tabelle bleibt bei 100% (kein horizontaler Ueberlauf, v.a. auf schmalen Viewports). */
table.meta td { overflow-wrap: anywhere; }
/* Member-Felder der MCP-ID (objID/objNAME/objTYPE) sind label-los -> Wert zentriert;
   nur der Objektname (objNAME) zusaetzlich fett. */
table.meta td.id-cell { text-align: center; }
table.meta td.id-cell.id-name { font-weight: 700; }
/* DIE ECKDATEN der Namenszeile: erzeugtAm links, geaendertAm rechts, der Name zentriert
   dazwischen. Sie standen als eigene Paar-Zeile darunter - GEMESSEN 41 px fuer zwei Beschriftungen
   und zwei kurze Werte ueber die volle Breite; in den Ecken kosten sie GAR KEINEN zusaetzlichen
   Platz, der Block wird dadurch kuerzer (107 -> 66 px) statt hoeher.

   DER FLEX-CONTAINER IST DAS DIV UND NICHT DAS td: ein display:flex an einer Tabellenzelle nimmt
   ihr das Zellen-Layout, und der Name bricht dann Zeichen fuer Zeichen um - eine Falle, in die der
   erste Anlauf prompt gelaufen ist.

   NACHGEBEN MUSS DER NAME und nicht der Zeitstempel: die Ecken sind starr (flex: 0 0 auto) und
   tragen white-space:nowrap, der Name ist schrumpfbar (1 1 auto samt min-width:0, ohne das greift
   das Schrumpfen an einem Flex-Kind gar nicht erst). Ein langer objNAME UMBRICHT damit - wie er es
   in dieser Zelle seit jeher tut (table.meta td { overflow-wrap: anywhere }) - statt die Ecken
   auseinanderzudruecken.

   NICHT per ELLIPSIS, und das ist GEMESSEN: eine Tabellenzelle nimmt mindestens ihre
   min-content-Breite an, und mit nowrap ist die der GANZE Name - der Block lief bei einem
   hundert Zeichen langen objNAME ueber den rechten Rand hinaus und schnitt den zweiten Zeitstempel
   ab. Umbrechen kostet im Ausnahmefall eine zweite Zeile und ist trotzdem kuerzer als die eigene
   Paar-Zeile davor; abgeschnitten waere dagegen genau die Angabe, um derentwillen es die Ecken
   gibt. align-items:center haelt die Ecken dabei mittig zum mehrzeiligen Namen. */
table.meta td.id-cell.eckdaten { padding-left: 10px; padding-right: 10px; }
.eckdaten-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.eck {
  flex: 0 0 auto; display: flex; flex-direction: column; line-height: 1.3;
  color: var(--muted); font-weight: 500; text-align: left; white-space: nowrap;
}
.eck-rechts { text-align: right; }
.eck-label { padding-top: 4px; font-size: 9px; letter-spacing: .07em;
             text-transform: uppercase; opacity: .85; }
.eck-wert { font-size: 11.5px; }
/* DER NAME IST DIE UEBERSCHRIFT DES BLOCKS und wird so gesetzt: 20 px gegen die 9 px des
   Eckenlabels und die 11,5 px seines Wertes. Er stand in der geerbten Groesse der Tabelle und war
   damit von den Zeitstempeln neben ihm kaum zu unterscheiden - drei Angaben in einer Zeile, von
   denen eine sagt, WAS man vor sich hat, und zwei, wann es geschrieben wurde. Die 500 daneben
   bleibt: sie hebt ihn gegen den Fliesstext, ohne dass eine zweite Stufe noetig waere.
   SCHRUMPFBAR bleibt er trotzdem (flex 1 1 auto, min-width 0) - er ist der einzige, der nachgeben
   darf, die Ecken sind starr. */
.eck-name { flex: 1 1 auto; min-width: 0; text-align: center; font-weight: 500; font-size: 20px; }
/* AM MOBILE nimmt der Name seine eigene Zeile und die beiden Ecken ruecken darunter - links und
   rechts, wie am Desktop. Nebeneinander bliebe ihm dort kaum Breite, und die Ellipsis fraesse
   genau die Angabe weg, die den Block ueberschreibt. Es bleibt trotzdem kuerzer als zuvor: dort
   paart FELD_PAARE am Mobile gar nicht, die beiden Zeitstempel standen also als ZWEI volle
   Formularzeilen da. */
@media (max-width: 768px) {
  .eckdaten-row { flex-wrap: wrap; row-gap: 4px; }
  .eck-name { order: -1; flex: 1 0 100%; }
}
/* Zweites Label in Paar-Zeilen etwas einrücken. */
table.meta td + th { padding-left: 28px; }
/* Verschachtelte Objekte: eigene, weiche Karte mit etwas mehr Luft.
   Horizontales Padding über die Zellen, da table-padding bei border-collapse ignoriert wird. */
table.meta table.meta {
  margin: 6px 0; border: 1px solid #fff; border-radius: 8px; background: var(--flaeche);
  /* border-collapse:separate (statt des geerbten collapse), damit der Radius gerendert
     wird; overflow:hidden klippt die Ecken sauber. */
  border-collapse: separate; border-spacing: 0; overflow: hidden;
}
table.meta table.meta th { padding-left: 14px; }
table.meta table.meta td:last-child { padding-right: 14px; }
/* MCP-ID-Block im Formular: der RAHMEN traegt den AKZENT. Er umfasst den KOPF des Objekts (objNAME,
   Typ und Status), und derselbe Ton fasst darueber den Dashboard-Block ein und markiert den aktiven
   Reiter - was das Objekt benennt, gehoert damit in eine Farbe.
   EINEN EIGENEN GRUND SETZT ER NICHT: hier stand --line, eine Stufe tiefer als die --flaeche der
   verschachtelten Karten, damit er sich von ihnen abhebt - der Rahmen leistet das bereits, und die
   zweite Stufe machte aus einer Hervorhebung einen Kasten. Uebrig bleibt der Grund, den die Stelle
   ohnehin traegt: --flaeche als verschachtelte Karte, sonst gar keiner. */
table.meta table.meta.meta-mcpid, table.meta.meta-mcpid {
  border: 1px solid var(--accent);
}
/* Verschachtelte Tabelle nimmt die volle Breite der aeusseren Tabelle ein (eigene Karte,
   daher keine zusaetzliche obere Trennlinie der aeusseren Zeile). */
table.meta td.obj-cell { padding: 4px 0; border-top: none; }
/* Tabellen-Feld (Pausen) full-width in den Metadaten; Überschrift + Tabelle übernimmt die Zelle. */
table.meta td.tab-cell { padding: 2px 0 6px; border-top: none; }
/* Data-Feld (extrahiertes JSON) full-width: Label darüber, Inhalt mehrzeilig als <pre>/<textarea>. */
table.meta td.data-cell { padding: 4px 0 8px; border-top: none; }
table.meta td.data-cell .data-label { color: var(--muted); font-weight: 500; font-size: 13px; margin-bottom: 4px; }
table.meta td.data-cell .data-pre {
  margin: 0; padding: 10px 12px; background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px;
  white-space: pre-wrap; word-break: break-word; max-height: 320px; overflow: auto;
}
table.meta td.data-cell .data-edit {
  width: 100%; box-sizing: border-box; min-height: 160px; resize: vertical;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px;
}
/* Quellen (Provenance): je Quelle der objTYPE und darunter das McpID-Ref-Control (objNAME, Rahmen,
   Springen-Symbol). Der Chip ist nur noch der STAPEL – das graue Kästchen bringt das Control selbst
   mit; ohne diese Trennung säße ein Kästchen im Kästchen. */
table.meta td.sources-cell { padding: 6px 0 8px; border-top: none; }
table.meta td.sources-cell .sources-label { color: var(--muted); font-weight: 500; font-size: 13px; margin-bottom: 6px; }
.sources-chip { display: inline-block; margin: 0 8px 6px 0; vertical-align: top; }
.sources-chip .src-typ { display: block; font-size: 12px; margin-bottom: 2px; }

/* Titel (Feld-Label) einer verschachtelten Tabelle: rechts oben, dezent und flach. */
table.meta td.meta-titel {
  color: var(--muted); font-weight: 500; font-size: 13px;
  padding: 4px 14px 0;
}
/* objTYPE linksbündig, Feld-Label bleibt rechts (wie bisher "rechts oben"); dazwischen der
   Status-Chip. flex-wrap, damit die objID auf schmalen Viewports in eine zweite Zeile fällt,
   statt den Chip vor sich herzuschieben. */
.meta-titel-row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.meta-titel-typ { flex: 0 0 auto; }
.meta-titel-label { margin-left: auto; flex: 0 0 auto; }
/* Der STATUS im Kopf des MCP-ID-Blocks. Er stand zuvor als eigene Formularzeile darunter – für
   einen rein lesenden Enum-Wert eine volle Zeile (Label + Wert, rund 45 px), und zwar in jedem
   Formular; fünf Klassen hatten dafür je eine eigene Paarung in FELD_PAARE bekommen, was nur dort
   geht, wo zufällig ein zweites kurzes Feld danebensteht. Im Kopf steht er immer an derselben
   Stelle und kostet keine.

   LINKS neben der objID und nicht rechts: die ULID bricht auf schmalen Viewports um
   (word-break: break-all), ein Chip daneben spränge mit.

   Ohne Beschriftung – "Erfasst"/"Storniert" sagen sich selbst, und die Pill-Form unterscheidet
   ihn vom objTYPE daneben; das title-Attribut fängt den Rest. */
.status-chip {
  flex: 0 0 auto;
  display: inline-block; padding: 1px 9px 2px;
  border: 1px solid var(--line); border-radius: 999px;
  font-size: 11.5px; font-weight: 500; line-height: 1.5;
  color: var(--muted); background: var(--panel);
  white-space: nowrap;
}
/* Die einzige Stufe, die BEDEUTUNG trägt: das Objekt gilt nicht mehr (Storniert/Abgelehnt/
   Inaktiv, STATUS_UNGUELTIG in app.js). Sie bekommt das Rot, das die Palette ohnehin dafür führt
   – keine elfte Farbe und kein Grün für "Genehmigt": der Unterschied zu "Aktiv" ist am Wort
   ablesbar, und würde jeder Status eingefärbt, leuchtete jedes Formular. */
.status-chip.ungueltig { color: #d33a3a; border-color: #d33a3a; }
/* Steht dort die objID statt des Feld-Labels, wird sie wie die Quellen-Chips monospaced gesetzt –
   eine ULID liest sich als Fließtext schlecht, und die gleiche Schrift macht sie als Kennung
   erkennbar. Sie darf umbrechen: auf schmalen Viewports passt sie sonst nicht neben den objTYPE. */
.meta-titel-label.meta-titel-id {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px; flex: 0 1 auto; word-break: break-all; text-align: right;
}
/* Keine Trennlinie und kein oberer Abstand in der Zeile direkt unter der Titel-Zeile. */
/* Gruppen-Ueberschrift im Details-Reiter (Person, Entgelt und Arbeitszeit, Lehrverhaeltnis, ...).
   Der Reiter rendert seine Felder ueber DIESELBE table.meta wie der Metadaten-Reiter - vorher waren
   es handgeschriebene .details-feld-Bloecke mit eigenem CSS, weshalb Zeilenabstand, Schriftgroessen,
   Label-Stil und Trennlinien zwischen den beiden Reitern auseinanderliefen und die Werte nicht in
   einer Spalte fluchteten. */
table.meta tr.gruppe > th {
  padding: 22px 0 7px; color: var(--text); font-weight: 700;
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
}
table.meta tr.gruppe:first-child > th { padding-top: 4px; }
/* Der KOPF eines eingebetteten EINZELOBJEKTS (meta-objekt, z.B. der Partner): Ueberschrift und
   Plus bzw. Entfernen in EINER Zeile - dieselbe Stellung wie der Erzeugen-Knopf einer
   Array-Tabelle (.arr-kopf) und aus demselben Grund: neben der Ueberschrift sagt die Stellung von
   selbst, wozu der Knopf gehoert. Die Knopfgroesse ist die des .arr-plus, damit die beiden Faelle
   im selben Formular gleich aussehen. */
table.meta tr.gruppe > th .obj-kopf { display: flex; align-items: center; gap: 8px; }
.obj-kopf .icon-btn { width: 26px; height: 26px; }
.obj-kopf .icon { width: 17px; height: 17px; }
table.meta tr.gruppe + tr > th,
table.meta tr.gruppe + tr > td { border-top: none; }

table.meta tr.titel-zeile + tr > th,
table.meta tr.titel-zeile + tr > td { border-top: none; padding-top: 0; }
.arr-item { padding: 6px 0; }
.arr-item + .arr-item { border-top: 1px dashed var(--line); }

/* Inline-Eingabefelder im Bearbeitungsmodus.

   DAS POLSTER EINES FELDES IST 4 px OBEN/UNTEN UND 8 px LINKS/RECHTS, und das gilt fuer JEDES
   einzeilige Eingabefeld der Oberflaeche - hier, an seiner Lese-Fassung ('span.ref-read'), am
   Listenfilter ('.filter-input') und am Feld des Details-Reiters ('.df-input'). Es waren VIER
   Werte fuer dieselbe Sache (7/11, 6/11, 7/10, 6/8), und welcher galt, entschied allein, wo man
   gerade hinsah; nebeneinander sieht man sie nie, und genau deshalb konnten sie auseinanderlaufen
   - dieselbe Klasse von Drift, gegen die die Farbpalette ihre neun benannten Variablen setzt.

   ES GILT OHNE AUSNAHME, auch fuer die Eintraege des Ref-Dropdowns ('.ref-option'). Dort stand
   eine Zeitlang die senkrechte 7 mit dem Klickziel als Begruendung; zurueckgenommen, weil eine
   Ausnahme, die man beim Bedienen nicht bemerkt, mehr kostet als sie bringt.

   ZWEI Stellen haengen daran und sind MITGEZOGEN, beide gerechnet und nicht geraten: der Einzug
   fuer das Sprung-Symbol (8 + 15 + 8 = 31, siehe '.edit-input.mcpid-ref.has-open') und der
   Zellen-Ausgleich der Lese-Referenz (gemessen 6 px, siehe dort). */
.edit-input {
  font: inherit; font-size: 14.5px; color: var(--text);
  border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px;
  width: 100%; max-width: 400px; min-width: 0; background: #fff;
}
.edit-input:focus { outline: none; border-color: var(--accent); }
/* Die beiden NeuFoeG-Datumsfelder stehen INNERHALB einer Zeile neben ihren Beschriftungen
   ("von … bis …") und duerfen daher nicht wie ein Formularfeld die volle Breite nehmen. */
.nfoeg-feld { width: auto; margin: 0 10px; }
/* Allein in der Zeile stehende Bearbeitenfelder (colspan-Zelle) nutzen die volle Breite. */
table.meta td[colspan="3"] .edit-input { max-width: none; }
/* MCP-ID-Referenzfelder (Ansprechperson, Arbeitszeitmodell): Rahmen, KEIN eigener Hintergrund. Der
   Rahmen traegt den AKZENT wie der MCP-ID-Block darueber, und zwar aus demselben Grund: beide
   umfassen eine McpID — dort die des Objekts selbst, hier die eines fremden. Derselbe Ton sagt
   damit ueberall im Formular „hier steht ein Objekt und nicht ein Wert".
   Der HINTERGRUND ist entfallen: er stand in --flaeche und damit in derselben Stufe wie die Karte,
   auf der das Feld liegt - er sagte also nichts, was der Rahmen nicht schon sagt, und INNERHALB
   einer verschachtelten Karte verschwand er ohnehin. Ohne eigene Angabe faellt das EDIT-Feld auf das
   Weiss von '.edit-input' zurueck, die Lesebox auf den Grund, auf dem sie steht. */
.mcpid-ref { border: 1px solid var(--accent); border-radius: 6px; }
/* DIE GANZE LESEBOX SPRINGT, nicht nur das Symbol davor. Das Symbol sagt, DASS hier ein Sprung
   moeglich ist; ein Klickziel von 15 Bildpunkten neben einer Box, die die volle Feldbreite einnimmt,
   ist aber genau die Sorte Ziel, die man verfehlt - und wer den Namen anklickt, meint das Objekt.
   NUR in der LESE-Fassung: im Edit-Modus oeffnet derselbe Klick das Such-Dropdown, und ein Sprung
   dorthin naehme dem Feld die Bearbeitung; dort bleibt das Symbol das Klickziel. */
span.ref-read.ref-springbar { cursor: pointer; }
span.ref-read.ref-springbar:hover { background: var(--flaeche); }
/* DER FOKUS MUSS DESHALB ANDERS SPRECHEN. '.edit-input:focus' faerbt den Rahmen von
   --line auf --accent; ein Ref-Feld traegt den Akzent jetzt schon in Ruhe, und damit
   veraenderte sich beim Hineinklicken NICHTS — ausgerechnet das eine Feld im Formular gaebe keine
   Rueckmeldung mehr, dass die Eingabe dort landet. Der Fokus verstaerkt statt dessen, was ohnehin
   dasteht: ein zwei Bildpunkte breiter Saum in demselben Ton (#3a6982 = --accent, dieselbe Bauart
   wie beim Marken-Knopf). Ein KRAEFTIGERER Rahmenton waere die Alternative und scheidet aus —
   --accent-dark ist ausschliesslich der Primaeraktion beim Hovern vorbehalten. */
.edit-input.mcpid-ref:focus { box-shadow: 0 0 0 2px rgba(58, 105, 130, .3); }
/* BLOCK und nicht inline-block: die Lesebox nimmt IMMER die verfuegbare Breite, gleichgueltig ob
   sie einen Namen traegt oder leer ist. Zuvor schrumpfte sie auf ihren Inhalt, sodass dasselbe Feld
   je nach Datenlage anders aussah — mit Wert eine Box, ohne Wert ein Stummel neben dem "–". Und sie
   folgt in der Breite genau dem EDIT-Feld, das sie vertritt (dieselben VIER Regeln wie
   '.edit-input': 400 im Formular, ohne Deckel in der colspan-Zelle, 220 in einer Array-Tabelle
   und ohne Deckel im KV-Reiter); sonst spraenge die Box beim Umschalten zwischen Lesen und
   Bearbeiten in der Breite. */
span.ref-read { display: block; max-width: 400px; padding: 4px 8px; }
table.meta td[colspan="3"] span.ref-read { max-width: none; }
.arr-table span.ref-read { max-width: 220px; }
/* Die VIERTE Ausnahme, und sie ist der Beleg fuer den Satz darueber: seit 'select.kv-select' auf
   die Breite seiner Eintraege waechst, muss die LESE-Fassung mitgehen - sonst sieht dasselbe Feld
   beim Umschalten zweimal anders aus. GEMESSEN an kv_taetigkeitsmerkmale mit drei gewaehlten
   Werten (der Server fuegt sie mit ", " zusammen): die Box bekam 400 px und brach den Text auf
   DREI Zeilen (94 px hoch), waehrend rechts daneben die halbe Zeile frei blieb; jetzt sind es
   1068 px auf einer Zeile bei 1100 px Fensterbreite und 528 px auf zwei bei 560 px. */
.kv-opt-kopf span.ref-read { max-width: none; }
/* Eine LISTE liest sich zeilenweise. Die Box bleibt EINE - der Rahmen ist das Feld -, aber jeder
   Wert bekommt seine eigene Zeile; genau die Aufteilung, die das Edit-Feld daneben ohnehin zeigt.
   Als reiner Text mit ", " war bei kv_taetigkeitsmerkmale nicht mehr zu sehen, wo ein Eintrag
   endet: die Etiketten sind Saetze und tragen selbst Beistriche. */
.kv-wert-liste > span { display: block; }
/* Die Box der Lese-Referenz bringt eigenes Polster + Rahmen mit -> td-Polster entsprechend
   reduzieren, damit die Gesamthoehe der Zeile derjenigen normaler Felder entspricht. Der Wert ist
   GEMESSEN und nicht gewaehlt: er haengt am Polster der Box, und als das von 6 auf 4 px ging,
   stimmte er nicht mehr - die Referenz-Zeile war 43 px hoch gegen 46 px einer gewoehnlichen
   Lesezeile. Durchprobiert (4/5/6/7 px) trifft GENAU 6 px die 46 wieder. */
table.meta td:has(> span.ref-read) { padding-top: 6px; padding-bottom: 6px; }
/* Eigenes, durchsuchbares McpID-Referenz-Dropdown (Combobox). */
.ref-combo { position: relative; }
.ref-panel {
  /* FIXED und ueber allem (wie das Rechtsgrundlagen-Popup, z-index 70 > .modal-overlay-top 60): in der
     Adressen-/Bankverbindungs-TABELLE schnitt ein absolut positioniertes Panel an
     '.arr-table { overflow: hidden }' ab und war praktisch unsichtbar. Die Koordinaten setzt RefSelect
     als Inline-Stil (platzieren()) und fuehrt sie beim Scrollen/Resize nach. */
  position: fixed; left: 0; top: 0; z-index: 70;
  max-height: 240px; overflow-y: auto;
  /* In einer schmalen Tabellenspalte (z.B. "Land" der Adressen) waere das Panel sonst nur so breit wie
     die Zelle und schnitte lange Eintraege ab ("Amerikanische Jungferninseln"). Die Mindestbreite des
     Feldes setzt platzieren() zusaetzlich inline. */
  min-width: 260px; max-width: 90vw; width: max-content;
  background: #fff; border: 1px solid var(--line); border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .12);
}
/* DASSELBE POLSTER WIE DAS FELD, in BEIDEN Richtungen (4/8, siehe '.edit-input'). Waagrecht muss
   es das ohnehin sein: das Panel steht unmittelbar unter dem Eingabefeld, und liefe der Text der
   Eintraege eingerueckt gegen den getippten, ruckte er beim Aufklappen zur Seite. Senkrecht stand
   hier eine Zeitlang 7 px als benannte AUSNAHME - das Polster als KLICKZIEL, gemessen 34 px
   Zeilenhoehe gegen 28 px. Sie ist ZURUECKGENOMMEN: eine Ausnahme, die man beim Bedienen nicht
   bemerkt, kostet mehr, als sie bringt - sie ist die eine Zahl, die jeder kuenftige Eingriff
   erklaeren muss. 28 px bleiben ein taugliches Ziel fuer eine Mausbedienung, und getroffen wird
   ueber die volle Breite des Panels (mindestens 260 px). */
.ref-option { padding: 4px 8px; cursor: pointer; font-size: 14.5px; line-height: 1.4; }
.ref-option:hover { background: var(--flaeche); }
.ref-leer { padding: 4px 8px; color: var(--muted); font-size: 13.5px; }
/* Open-Symbol des McpID-Ref-Controls: springt zum referenzierten Objekt. */
.ref-open { display: inline-flex; align-items: center; cursor: pointer; color: var(--muted); vertical-align: middle; margin-right: 5px; }
.ref-open:hover, .ref-springbar:hover .ref-open { color: var(--text); }
.ref-open .icon { width: 15px; height: 15px; }
/* Edit-Modus: Symbol links im Eingabefeld überlagern; Input bekommt Platz dafür. Die 8 px des
   Symbols sind jetzt GENAU das Polster des Feldes - es sitzt damit dort, wo sonst der Text
   beginnt, statt 3 px davor. Der Einzug daneben ist daraus GERECHNET und keine gewaehlte Zahl:
   8 (Rand) + 15 (Symbolbreite) + 8 (derselbe Abstand noch einmal) = 31. */
.ref-open-edit { position: absolute; left: 8px; top: 50%; transform: translateY(-50%); z-index: 2; margin-right: 0; }
.edit-input.mcpid-ref.has-open { padding-left: 31px; }

.muted { color: var(--muted); font-size: 13px; }
.loading { text-align: center; color: var(--muted); padding: 80px 0; }

/* --- Inhalt-Reiter (Dokument): PDF/Bild inline mit Zoom ------------------- */
.inhalt-wrap { padding: 4px 2px; }
.inhalt-toolbar { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 10px; }
.inhalt-pdf { width: 100%; height: 77vh; border: 1px solid var(--line); border-radius: 6px; background: var(--bg); }
.inhalt-bild-scroll { max-height: 72vh; overflow: auto; border: 1px solid var(--line); border-radius: 6px; background: var(--bg); }
.inhalt-bild { display: block; height: auto; }
.inhalt-wrap .hinweis a { color: var(--accent); }
/* Text-/JSON-Inhalt (z.B. steuerberatung.json des Kollektivvertrags) im Inhalt-Reiter. */
.inhalt-text {
  margin: 0; padding: 10px 12px; background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px;
  white-space: pre; word-break: normal; max-height: 72vh; overflow: auto;
}

/* --- Kalender-Reiter (Mitarbeiter): Urlaube + erfasste Zeiten ------------- */
.kal-wrap { padding: 4px 2px; }
/* Der Urlaubsstand ueber dem Monatsraster: er gilt fuer das ganze Urlaubsjahr und nicht fuer den
   gezeigten Monat. Die beiden Zahlen tragen, die Aufschluesselung darunter erklaert. */
.url-stand {
  display: flex; align-items: baseline; gap: 24px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 12px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--panel);
}
.url-zahl { display: flex; flex-direction: column; gap: 2px; }
.url-wert { font-size: 20px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.url-label { font-size: 12px; color: var(--muted); }
.url-detail { margin-left: auto; font-size: 12px; color: var(--text); cursor: help; }
.kal-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.kal-nav .icon { width: 18px; height: 18px; }
.kal-prev .icon { transform: rotate(180deg); }
.kal-monat { font-size: 15px; font-weight: 500; color: var(--text); min-width: 130px; text-align: center; }
.kal-legende { display: flex; gap: 14px; margin-left: auto; }
.kal-leg { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 12px; }
.kal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.kal-kopf { margin-bottom: 4px; }
.kal-wt { text-align: center; font-size: 12px; color: var(--muted); font-weight: 500; padding: 2px 0; }
.kal-cell {
  min-height: 52px; border: 1px solid var(--line); border-radius: 6px;
  background: var(--panel); padding: 4px 5px; display: flex; flex-direction: column;
}
.kal-leer { border-color: transparent; background: transparent; }
.kal-heute { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.kal-arbeit-bg { background: rgba(0, 168, 132, 0.12); }
.kal-urlaub-bg { background: rgba(240, 160, 32, 0.16); }
.kal-arbeit-bg.kal-urlaub-bg {
  background: linear-gradient(135deg, rgba(0, 168, 132, 0.16) 50%, rgba(240, 160, 32, 0.18) 50%);
}
.kal-tagnr { font-size: 12px; color: var(--text); }
.kal-marker { margin-top: auto; display: flex; gap: 4px; }
.kal-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.kal-dot-arbeit { background: var(--accent); }
.kal-dot-urlaub { background: #f0a020; }

/* --- Mobil: EINE Kopfzeile, der Breadcrumb darin scrollbar ------------------------------------ */
/* ES WAREN ZWEI ZEILEN: Marken-Knopf und Benutzer oben, Hamburger und Breadcrumb darunter. Der
   Inhalt begann damit GEMESSEN bei 114 px - auf einem Telefon (390x844) ein Achtel der Hoehe fuer
   eine Kopfzeile, deren obere Haelfte allein den Marken-Knopf trug.
   Mit dem Wegfall des Knopfes passt alles in EINE Zeile: Hamburger, Breadcrumb, die beiden
   Ansichts-Aktionen und der Benutzer. Der Inhalt beginnt jetzt bei 54 px - 60 px gewonnen.
   Der PREIS steht hier, damit ihn niemand sucht: der Breadcrumb wird bei tiefen Pfaden
   angeschnitten (er scrollt dafuer waagrecht, das erste Element bleibt links fixiert), und der
   Benutzer-Chip traegt kein Wort mehr - seine Adresse steht im aufgeklappten Menue (.bm-mail). */
@media (max-width: 768px) {
  /* NICHT MEHR UMBRECHEN - eine Zeile, und die Breite verteilt der Breadcrumb (er schrumpft,
     min-width: 0 laesst ihn das auch tatsaechlich). Ohne das nowrap braeche die Zeile weiterhin
     um, sobald der Breadcrumb seine Wunschbreite nicht bekommt. */
  .topbar { flex-wrap: nowrap; column-gap: 8px; padding: 12px 12px; }
  .bc-row { flex: 1 1 auto; min-width: 0; gap: 6px; }
  .topbar-user-wrap { flex: 0 0 auto; margin-left: 0; }

  /* DIE MARKE ALS WASSERZEICHEN DER KOPFZEILE - dieselbe Bauart wie in der Toolbar und im Chat:
     zwei Background-Lagen, und die REIHENFOLGE ist die Transparenz; die erste Lage liegt oben,
     der Schleier DECKT die Marke also AB, statt sie abzudunkeln.
     SIE STEHT HIER, weil die Toolbar am Mobile hinter dem Hamburger liegt: ihr Wasserzeichen ist
     zu gar nicht zu sehen, und die Kopfzeile ist die einzige Flaeche im Akzent-Ton, die immer
     dasteht. RECHTS, weil links der Hamburger sitzt und in der Mitte der Breadcrumb laeuft; sie
     liegt damit hinter den Symbolknoepfen und wird von ihnen angeschnitten - genau das macht sie
     zum Wasserzeichen statt zu einem Symbol, das zu klein geraten ist.
     Der Schleier steht auf .75 wie an den beiden anderen Stellen - die Marke ist ueberall
     gleich sichtbar. Er war hier eine Stufe duenner als in der Toolbar (.82 gegen .80), weil
     die Kopfzeile nur 54 px hoch ist und die Marke oben und unten hinausragt; drei verschiedene
     Werte fuer dasselbe Wasserzeichen liessen sich allerdings nicht nebeneinander beurteilen -
     man sieht sie nie zugleich. */
  .topbar {
    background-color: var(--header);
    background-image:
      linear-gradient(rgba(58,105,130,.75), rgba(58,105,130,.75)),
      url("salaria-marke.png");
    background-repeat: repeat, no-repeat;
    background-position: 0 0, right 6px center;
    background-size: auto, 108px auto;
  }

  /* Der Chip ist am Mobile ein SYMBOL-Knopf: die Adresse braucht gemessen 178 px, und die hat
     diese Zeile nicht - gekuerzt stuende dort "christi…", was niemandem etwas sagt und trotzdem
     den Platz naehme. Sie steht im aufgeklappten Menue (.bm-mail), und der Pfeil entfaellt mit
     ihr: er zeigte an, dass sich etwas aufklappt, und tut das neben einem nackten Symbol nicht
     mehr besser als das Symbol selbst. */
  .topbar-user .tu-mail, .topbar-user .tu-caret { display: none; }
  /* Der Deckel ist hier gegenstandslos: er begrenzt die Breite der ADRESSE, und die steht am
     Mobile gar nicht mehr in der Zeile. */
  .topbar-user { padding: 4px; max-width: none; }
  .benutzer-menu .bm-mail { display: block; }

  .topbar .breadcrumb {
    flex: 1 1 auto; min-width: 0;
    flex-wrap: nowrap;    /* nicht mehrzeilig umbrechen ... */
    overflow-x: auto;     /* ... sondern bei Bedarf horizontal scrollen */
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }
  .topbar .breadcrumb .crumb { white-space: nowrap; }
  /* Der Trenner zwischen Ansichts-Aktionen und Benutzer entfaellt am Mobile: die Zeile ist eng,
     und er kostet 7 px fuer eine Trennung, die der Abstand ohnehin leistet. Er stand einmal
     deshalb hier, weil das Benutzermenue in der Zeile DARUEBER lag und er nichts traennte - jetzt
     steht es wieder daneben, und die Begruendung ist eine andere. */
  .bc-aktionen::after { display: none; }
  /* Organisation (erstes Element) beim horizontalen Scrollen links fixieren. */
  .topbar .breadcrumb .crumb:first-child {
    position: sticky; left: 0; z-index: 1;
    background: var(--header); padding-right: 6px;
    box-shadow: 6px 0 6px -4px var(--header);
  }

  /* LISTE am Mobile: fuer eine dritte Spalte ist kein Platz - die Zeitstempel ruecken als EINE
     Zeile unter den Untertitel, wo sie den Titel nicht zusammenquetschen. Die Sortier-Chips
     bekommen eine eigene Zeile unter Filter und Aktionen (order:3), sonst waere das Filterfeld
     auf wenige Zeichen geschrumpft. */
  .list-main .list-meta { display: none; }
  .list-text .list-meta-mobil { display: block; font-size: 11.5px; }
  .liste-filter { flex-wrap: wrap; }
  .liste-filter .sort-chips { order: 3; width: 100%; }
  .liste-filter .filter-input { max-width: none; flex: 1 1 auto; min-width: 0; }
}

/* Das erste Breadcrumb-Element (Organisation) bleibt IMMER anklickbar – auch wenn es
   zugleich das aktuelle (current) Element ist (z.B. im Organisations-Dashboard). */
.breadcrumb .crumb:first-child { cursor: pointer; }
.breadcrumb .crumb:first-child:hover { text-decoration: underline; }

/* Schichten-Reiter des Arbeitszeitmodells: Wechselschichten-Flag über der McpSchicht-Tabelle. */
.schichten-tab .schicht-flag { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; font-weight: 500; }
.schichten-tab .small { font-size: 0.85em; margin-top: 8px; }

/* SV-Reiter: die Ergaenzungen als Mehrfachauswahl. Eine Spalte je Eintrag, damit die (teils langen)
   Bezeichnungen nicht nebeneinander gequetscht werden; das Ankreuzfeld bleibt oben buendig, wenn
   ein Text umbricht. */
.sv-erg { display: flex; flex-direction: column; gap: 6px; }
.sv-erg-eintrag { display: flex; align-items: flex-start; gap: 8px; cursor: pointer; }
.sv-erg-eintrag input[disabled] { cursor: default; }
.sv-erg-eintrag input { margin-top: 3px; flex: 0 0 auto; }

/* Rueckmeldung des Feststellens in der Aktionsleiste des Geldabgeltungs-Overlays: sie steht LINKS
   neben den Schaltflaechen und schiebt sie nicht weg (die Leiste ist ein Flex-Container). */
.feststellen-hinweis { margin-right: auto; align-self: center; }

/* === DER CHAT-REITER =========================================================
   Der LEBENDE Chat des angemeldeten Mitarbeiters - bis dahin eine eigene Oberflaeche im
   wwwroot des ConnectorService, jetzt ein Reiter an SEINEM Datensatz.

   WAS DABEI WEGFAELLT, ist die SEITENLEISTE samt ihrer Schublade am Mobile. Sie trug dort die
   Chatliste, die Anmeldung und den Benutzer-Chip - alles drei hat dieser Dienst bereits, und
   die Liste selbst hat hoechstens ZWEI Eintraege (Personal und Company). Eine Schublade fuer
   zwei Knoepfe waere ein Muster, das mehr verspricht als es traegt; sie stehen daher als
   KANALWAHL ueber dem Verlauf.

   DIE BLASEN kommen unveraendert aus dem geteilten Block weiter oben (.bubble-row/.bubble/
   .text/.meta/.doc-chip) - es ist DASSELBE Gespraech, das der Chat-Reiter des Mitarbeiters
   rein lesend zeigt; nur die EINGABE ist hier dazugekommen. */

.chat-live { display: flex; flex-direction: column; gap: 0; }

/* --- Die Kanalwahl ---------------------------------------------------------
   Zwei Knoepfe nebeneinander statt einer Liste. Der AKTIVE traegt die Akzentfarbe, weil die
   Auswahl sonst allein am Hintergrund haengt und der ist derselbe wie der des Reiters. */
.cl-kanaele { display: flex; gap: 8px; padding: 0 0 10px; flex-wrap: wrap; }
.cl-kanal {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--panel); color: var(--text); cursor: pointer; font: inherit; font-size: 13px;
}
.cl-kanal:hover { background: var(--flaeche); }
.cl-kanal.aktiv { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.cl-kanal .icon { width: 18px; height: 18px; }
/* Die ZAHL der ungelesenen Nachrichten - dieselbe Scheibe wie in der fruehereren Chatliste. */
.cl-unread {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--accent); color: #ffffff; font-size: 11px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}

/* --- Der Verlauf -----------------------------------------------------------
   Er traegt das WASSERZEICHEN wie der fruehere Chat: dieselbe Bildvorlage, derselbe Schleier
   (#ede9e4 bei .75 Deckkraft) und dieselbe Ausrichtung - rechtsbuendig, senkrecht zentriert,
   NICHT mitscrollend. Die Marke ist eine Bildvorlage und wird nicht gedimmt; abgedeckt wird sie
   von einer Lage darueber (in CSS liegt die ERSTE Lage oben).

   GEDECKELT auf 60vh wie der rein lesende Verlauf daneben: er steht in einem Reiter und nicht
   als ganze Seite, und ohne Deckel schoebe ein langes Gespraech die Eingabezeile aus dem Bild. */
.cl-verlauf {
  position: relative;
  padding: 14px 16px 30px; height: 60vh; overflow-y: auto;
  border: 1px solid var(--line); border-radius: 6px;
  display: flex; flex-direction: column; gap: 6px;
  background-color: #ede9e4;
  background-image:
    linear-gradient(rgba(237,233,228,.75), rgba(237,233,228,.75)),
    url("salaria-marke.png");
  background-repeat: repeat, no-repeat;
  background-position: 0 0, right 0 center;
  background-size: auto, min(420px, 56%) auto;
}

/* --- Schnellantworten ------------------------------------------------------
   Die Leiste beim Hovern ueber der LETZTEN Antwort. Sie steht AUSSERHALB des geteilten
   Chat-Blocks weiter oben, und das ist Bedingung und nicht Ordnungsliebe: jener Block traegt
   die Blasen BEIDER Sichten, und der rein lesende Chat-Reiter des Mitarbeiters hat nichts zu
   senden - hineingeschrieben truege er Knoepfe, die nichts tun.

   UNTEN RECHTS an der Blase - dort, wo bei einer Antwort der Zeiger ohnehin hinlaeuft und wo
   sie keine Zeile verdeckt: an der OBERKANTE laege sie ueber der VORIGEN Nachricht.
   IN RUHE unsichtbar und OHNE Zeigerfang: ein unsichtbares Element, das Klicks abfaengt, macht
   den Text darunter unmarkierbar. */
.schnellantworten {
  position: absolute;
  right: 0;
  top: calc(100% - 2px);
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: var(--panel);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .18);
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease;
}
/* Auch beim Hovern der LEISTE selbst sichtbar bleiben - sie liegt ausserhalb der Blase, und
   ohne diese Zeile verschwaende sie unter dem Zeiger, sobald man sie erreicht.
   :focus-within traegt die Tastatur: die Knoepfe sind erreichbar, also muessen sie sichtbar
   werden, wenn einer den Fokus hat. */
.bubble:hover .schnellantworten,
.schnellantworten:hover,
.schnellantworten:focus-within {
  opacity: 1;
  pointer-events: auto;
}
.schnellantwort {
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: 17px;
  line-height: 1;
  padding: 4px 5px;
  border-radius: 999px;
}
.schnellantwort:hover { background: var(--flaeche); }
.schnellantwort:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Tipp-Indikator */
.bubble.typing { display: flex; gap: 4px; padding: 12px; }
.bubble.typing span {
  width: 7px; height: 7px; border-radius: 50%; background: var(--muted);
  animation: blink 1.2s infinite both;
}
.bubble.typing span:nth-child(2) { animation-delay: .2s; }
.bubble.typing span:nth-child(3) { animation-delay: .4s; }
@keyframes blink { 0%, 80%, 100% { opacity: .3; } 40% { opacity: 1; } }

/* --- Standortabfrage und Anhang-Vorschau -----------------------------------
   Zwei Zeilen ueber der Eingabezeile. Beide tragen denselben Grund: es ist ein ZUSTAND der
   Eingabe und keine Nachricht - Blasen bleiben dem Gespraech vorbehalten. */
.standort-status {
  padding: 8px 14px;
  background: var(--flaeche);
  border: 1px solid var(--line); border-top: none;
  color: var(--muted);
  font-size: 13px;
}
.attachment-preview {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 14px;
  background: var(--flaeche);
  border: 1px solid var(--line); border-top: none;
}
.attachment-preview img { max-height: 80px; border-radius: 6px; }

/* --- Die Eingabezeile ------------------------------------------------------ */
.composer {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  background: var(--flaeche);
  border: 1px solid var(--line); border-top: none;
  border-radius: 0 0 6px 6px;
}
/* Der AUFNAHME-Knopf pulsiert, solange aufgenommen wird - ohne diese Rueckmeldung ist einem
   laufenden Mikrofon nichts anzusehen. */
.icon-btn.recording { background: #ffd4d4; animation: pulse 1s infinite; }
@keyframes pulse { 50% { background: #ffb0b0; } }

.text-input {
  flex: 1; min-width: 0;
  border: 1px solid var(--line); border-radius: 20px;
  padding: 9px 14px;
  font: inherit; font-size: 14px;
  background: var(--panel); color: var(--text);
  outline: none;
}
.text-input:focus { border-color: var(--accent); }

.send-btn {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 38px; height: 38px;
  border: none; border-radius: 50%;
  background: var(--accent); color: #ffffff;
  cursor: pointer;
}
.send-btn:hover:not(:disabled) { background: var(--accent-dark); }
.send-btn:disabled { background: var(--line); cursor: default; }
.send-btn .icon { width: 18px; height: 18px; }

/* AM MOBILE wird der Verlauf flacher: 60vh sind dort mehr als der halbe Bildschirm, und die
   Eingabezeile soll ohne Scrollen erreichbar bleiben. */
@media (max-width: 640px) {
  .cl-verlauf { height: 52vh; padding: 12px 10px 26px; }
}
