/* ============================================================
   Kontingo — App-Stylesheet
   Fonts: Inter (Body/UI) + Space Grotesk (Headings), selbst-gehostet
   (DSGVO, kein Google-CDN) — siehe assets/fonts.css.

   MARKENFARBEN (K4): die --brand-*-Tokens unten sind der PRODUKT-DEFAULT.
   Jeder Mandant kann sie ueberschreiben; layout.php gibt dafuer einen
   :root-Block direkt nach diesem Stylesheet aus (App\Branding::cssOverride()).
   Deshalb NIE eine Markenfarbe als Literal in eine Regel schreiben --
   immer var(--brand...), sonst faellt sie aus dem Branding heraus.
   Die Werte hier stammen aus dem Theme digit-xperts-2026 und bleiben als
   Default stehen; digit xperts bekommt sie zusaetzlich als Mandanten-Wert,
   damit das Aussehen dort nicht vom Zufall des Defaults abhaengt.
   ============================================================ */
:root{
  --brand:#1AB085; --brand-bright:#02E0A1; --brand-dark:#308B71; --brand-darker:#316153;
  --brand-tint:#E8F7F1; --brand-tint-2:#D6F0E6;
  /* P1.4: Button-FILL-Token. --brand (#1AB085) auf weiss = nur 2.77:1 (Fail).
     --brand-btn #177a5d = 5.28:1, Hover --brand-btn-dark #12664e = 6.92:1 (AA).
     --brand bleibt fuer Flaechen/Akzente/Tints. --petrol-ink loest --blue als
     TEXT auf hellem Petrol ab (4.33:1 -> 5.77:1). */
  --brand-btn:#177a5d; --brand-btn-dark:#12664e; --petrol-ink:#2C5F73;
  --blue:#36738B; --magenta:#B01A47;
  --ink:#171D1A; --ink-2:#39413C; --ink-3:#5B635D; --ink-4:#68706A;
  --bg:#F7F8F7; --surface:#F1F1F1; --surface-2:#E7E8E7; --line:#E2E4E2; --white:#fff;
  --slate-900:#171D1A; --slate-800:#253631;
  --font-sans:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  --font-display:"Space Grotesk",var(--font-sans);
  --r-sm:6px; --r:10px; --r-lg:14px; --r-full:999px;
  --shadow-sm:0 1px 2px rgba(20,23,27,.04),0 1px 3px rgba(20,23,27,.06);
  --shadow:0 4px 12px rgba(20,23,27,.06),0 12px 28px rgba(20,23,27,.07);
  --shadow-lg:0 18px 50px rgba(20,23,27,.10);
  --shadow-brand:0 10px 30px rgba(26,176,133,.28);
  --container:1180px;
}
*,*::before,*::after{box-sizing:border-box} *{margin:0}
html{-webkit-text-size-adjust:100%}
body{font-family:var(--font-sans);font-size:15px;line-height:1.5;color:var(--ink-2);
  background:var(--bg);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
h1,h2,h3,h4{font-family:var(--font-display);color:var(--ink);line-height:1.14;font-weight:600;letter-spacing:-.02em}
h1{font-size:clamp(1.5rem,2.4vw,1.75rem);font-weight:700}
h2{font-size:1.25rem} h3{font-size:1.05rem}
a{color:var(--brand-dark);text-decoration:none;transition:color .18s} a:hover{color:var(--brand-darker)}
img,svg{display:block;max-width:100%;height:auto}
code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em;background:var(--surface);padding:.1em .4em;border-radius:6px}
.eyebrow{display:inline-flex;align-items:center;gap:.5em;font-size:.75rem;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--brand-dark)}
.eyebrow::before{content:"";width:1.6em;height:2px;border-radius:2px;background:var(--brand)}
.muted{color:var(--ink-3)}

/* Buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.55em;font-family:var(--font-sans);
  font-weight:600;font-size:.92rem;padding:.62em 1.15em;border-radius:var(--r);background:var(--brand-btn);
  color:#fff;border:1px solid transparent;cursor:pointer;box-shadow:var(--shadow-sm);
  transition:transform .18s,box-shadow .18s,background .18s}
.btn:hover{background:var(--brand-btn-dark);color:#fff;box-shadow:var(--shadow-sm)}
.btn--ghost{background:transparent;color:var(--ink);border-color:var(--line);box-shadow:none}
.btn--ghost:hover{background:var(--white);border-color:var(--brand);color:var(--brand-btn);box-shadow:var(--shadow-sm)}
.btn--block{width:100%} .btn--sm{padding:.5em .9em;font-size:.9rem}

/* Topbar */
/* S11: eine Nav-Zeile traegt jetzt Brand+Bereichs-Links+Suche+Rolle+Logout
   (vorher zusaetzlich eine zweite _subnav.php-Zeile) -- KEINE feste Hoehe/
   Breite mehr, flex-wrap auf allen Ebenen, damit die Zeile bei mehr Links
   (admin: 7, consultant: 5) auf schmalem Viewport umbricht statt seitlich
   ueberzulaufen (Lektion S9b.2: kein horizontaler Seiten-Scroll). */
.topbar{position:sticky;top:0;z-index:100;background:rgba(251,253,255,.82);
  backdrop-filter:saturate(180%) blur(14px);border-bottom:1px solid var(--line)}
/* Die Leiste darf breiter laufen als der Seiteninhalt (--container 1180px):
   Nav (6 Punkte, seit "Rechnungseingang" 757px) + Marke + Avatar brauchen mehr
   Platz als 1180px. Der Inhalt darunter bleibt bei --container, nur die
   App-Shell nutzt die volle Fensterbreite. Seit S15 zaehlt die Suche hier
   NICHT mehr mit -- sie lebt in einer eigenen Zeile (.searchbar) darunter. */
.topbar-inner{max-width:min(1360px,100%);margin-inline:auto;padding:.5rem clamp(1rem,4vw,2rem);
  min-height:54px;display:flex;align-items:center;gap:.5rem 1rem;
  /* nowrap ab Tablet: Flexbox entscheidet den Zeilenumbruch anhand der
     BASIS-Groessen -- flex-shrink wirkt erst danach, pro Zeile. Mit wrap floss
     die Nav (756px Basis) voll in die Rechnung, die Summe riss den Container
     (1200 > 1180px) und das letzte Kind, der Avatar, rutschte in Zeile 2.
     Mit nowrap schrumpfen stattdessen Nav und Suchfeld, der Avatar bleibt oben
     rechts. Unter 640px stellt die Media-Query unten wieder auf wrap. */
  flex-wrap:nowrap}
.topbar .brand{flex:0 0 auto}
.topbar .brand img{height:26px;width:auto}
/* flex:1 1 auto + min-width:0 = die Nav gibt bei Platzmangel nach und bricht
   INTERN um (sie ist selbst flex-wrap). Ohne das schiebt sie als starrer Block
   das letzte Topbar-Kind -- den Avatar -- in eine zweite Zeile, sobald die
   Summe den Container (1180px) reisst. Genau das passierte, als der Link
   "Rechnungseingang" dazukam: 1200px Bedarf bei 1180px Platz (User 19.07.). */
.topbar nav{display:flex;flex-wrap:wrap;align-items:center;gap:.15rem;margin-left:.75rem;
  flex:1 1 auto;min-width:0}
.topbar nav a{display:inline-flex;align-items:center;gap:.35em;color:var(--ink-2);font-weight:500;font-size:.94rem;
  padding:.5em .8em;border-radius:var(--r-sm);white-space:nowrap;transition:color .15s,background .15s}
.topbar nav a:hover,.topbar nav a.active{color:var(--ink);background:var(--surface-2)}
/* Nav-Dropdown (Welle 3: "Stammdaten ▾") -- natives <details>, kein JS.
   Panel absolut positioniert, damit es die flex-Nav-Zeile nicht umbricht. */
.navdd{position:relative;display:inline-flex;align-items:center}
.navdd>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:.35em;
  color:var(--ink-2);font-weight:500;font-size:.94rem;padding:.5em .8em;border-radius:var(--r-sm);
  white-space:nowrap;user-select:none;transition:color .15s,background .15s}
.navdd>summary::-webkit-details-marker{display:none}
.navdd>summary::after{content:"▾";font-size:.72em;opacity:.65;transition:transform .15s}
.navdd[open]>summary::after{transform:rotate(180deg)}
.navdd>summary:hover,.navdd[open]>summary,.navdd>summary.active{color:var(--ink);background:var(--surface-2)}
.navdd-pop{position:absolute;top:calc(100% + .35rem);left:0;z-index:120;min-width:190px;
  display:flex;flex-direction:column;gap:.15rem;padding:.35rem;background:var(--white);
  border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow)}
.navdd-pop a{display:block;width:100%;padding:.5em .6em;border-radius:var(--r-sm);
  font-size:.9rem;font-weight:500;color:var(--ink);white-space:nowrap;text-decoration:none}
.navdd-pop a:hover,.navdd-pop a.active{background:var(--surface)}
/* Avatar-Konto-Menue (Welle 3b): Initialen-Kreis rechts -> Dropdown mit
   E-Mail+Rolle, Einstellungen/Benutzer (superadmin), Logout. */
.navdd-pop--right{left:auto;right:0}
.navdd>summary.avatar{width:34px;height:34px;padding:0;border-radius:var(--r-full);
  background:var(--brand-btn);color:#fff;font-weight:700;font-size:.82rem;
  justify-content:center;letter-spacing:.02em;flex:0 0 auto;overflow:hidden}
.navdd>summary.avatar::after{display:none}
/* S15: echtes Profilfoto statt Initialen, sobald users.avatar_path gesetzt ist
   -- Initialen bleiben der Fallback (siehe layout.php-Bedingung). */
.navdd>summary.avatar img{width:100%;height:100%;object-fit:cover;display:block}
.navdd>summary.avatar:hover,.navdd[open]>summary.avatar{background:var(--brand-btn-dark);color:#fff}
.user-menu-head{display:flex;flex-direction:column;gap:.3rem;padding:.4rem .6rem .55rem;
  margin-bottom:.2rem;border-bottom:1px solid var(--line)}
.user-menu-email{font-size:.82rem;font-weight:600;color:var(--ink-2);word-break:break-all}
.user-menu-head .badge{align-self:flex-start}
.navdd-logout{display:block;width:100%;text-align:left;font:inherit;font-size:.9rem;font-weight:500;
  padding:.5em .6em;border:none;border-radius:var(--r-sm);background:transparent;color:var(--ink);cursor:pointer}
.navdd-logout:hover{background:var(--surface)}
/* Der Spacer darf NICHT mehr wachsen: er teilte sich den freien Raum mit der
   Nav (beide flex-grow:1), wodurch der Nav 40px fehlten und "Stammdaten"
   umbrach -- obwohl in der Leiste noch Platz war. Das Rechtsbuendigen des
   Avatars uebernimmt .user-menu{margin-left:auto}. */
.topbar .spacer{flex:0 0 0;min-width:0}
/* Das Konto-Menue bleibt IMMER in der ersten Zeile ganz rechts: nie schrumpfen,
   nie umbrechen. margin-left:auto haelt es auch dann rechts, wenn der .spacer
   (leeres Element, Basisbreite 0) bei der Umbruch-Berechnung nichts beitraegt. */
.topbar .user-menu{flex:0 0 auto;margin-left:auto}
/* S15: Suche steht seit hier NICHT mehr in der Nav-Zeile, sondern in einer
   eigenen .searchbar-Zeile direkt darunter (siehe layout.php) -- konkurriert
   also nicht mehr um denselben Platz wie Marke/Nav/Avatar. Der vormalige
   210px-Deckel war eine Notloesung GEGEN genau diesen Platzkonflikt; in der
   eigenen Zeile darf das Feld wieder komfortabel breit sein. */
.searchbar{border-top:1px solid var(--line)}
.searchbar-inner{max-width:min(1360px,100%);margin-inline:auto;padding:.5rem clamp(1rem,4vw,2rem);display:flex}
.topbar-search{display:flex;align-items:center;flex:0 1 360px;min-width:0;max-width:400px}
.topbar-search input{width:100%;min-width:0;font:inherit;font-size:.86rem;padding:.5em .95em;
  border:1px solid var(--line);border-radius:var(--r-full);background:var(--surface);color:var(--ink);
  transition:border-color .15s,box-shadow .15s,background .15s}
.topbar-search input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-tint);background:var(--white)}
.topbar .user{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;font-size:.9rem;color:var(--ink-3);min-width:0}
.badge{display:inline-block;font-size:.68rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  padding:.25em .6em;border-radius:var(--r-full);background:var(--brand-tint);color:var(--brand-darker)}

/* Page */
.page{max-width:var(--container);margin-inline:auto;padding:clamp(1.25rem,3vw,1.9rem) clamp(1rem,4vw,1.9rem)}
.page-head{margin-bottom:1.75rem}
.page-head .eyebrow{margin-bottom:.6rem}
.page-head h1{margin-bottom:.3rem}

/* Cards */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:1.1rem}
.card{background:var(--white);border:1px solid var(--line);border-radius:var(--r);padding:1.05rem;
  box-shadow:var(--shadow-sm);transition:transform .18s,box-shadow .18s,border-color .18s}
a.card:hover{transform:translateY(-1px);box-shadow:var(--shadow);border-color:var(--brand-tint-2)}
.card h3{margin-bottom:.35rem}
.card-ico{width:34px;height:34px;border-radius:9px;background:var(--brand-tint);color:var(--brand-dark);
  display:flex;align-items:center;justify-content:center;font-weight:700;font-size:1.02rem;
  font-family:var(--font-display);margin-bottom:.85rem}
.card .soon{display:inline-block;font-size:.7rem;color:var(--ink-4);font-weight:600;
  text-transform:uppercase;letter-spacing:.08em}

/* Auth */
.auth-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:1.5rem;
  background:radial-gradient(60% 80% at 85% 8%,var(--brand-tint) 0%,transparent 55%),
             radial-gradient(50% 60% at 5% 92%,var(--surface-2) 0%,transparent 50%),var(--bg)}
.auth-card{width:100%;max-width:400px;background:var(--white);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--shadow-lg);padding:2.2rem}
.auth-card .brand{display:flex;justify-content:center;margin-bottom:1.5rem}
.auth-card .brand img{height:32px}
.auth-card h1{font-size:1.4rem;text-align:center;margin-bottom:.3rem}
.auth-card .sub{text-align:center;color:var(--ink-3);font-size:.92rem;margin-bottom:1.6rem}

/* Forms */
.field{margin-bottom:1rem}
.field label{display:block;font-size:.85rem;font-weight:600;color:var(--ink-2);margin-bottom:.35rem}
.field input{width:100%;font:inherit;font-size:.98rem;padding:.7em .85em;border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--white);color:var(--ink);transition:border-color .15s,box-shadow .15s}
.field input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-tint)}
.alert{padding:.7em .9em;border-radius:var(--r-sm);font-size:.9rem;margin-bottom:1.1rem}
.alert--error{background:#FBE9EE;color:var(--magenta);border:1px solid #F3C9D5}
/* P1.4: alert--ok GRUEN = Erfolgs-Flash (mint-tint/mint-darker = 6.41:1 AA).
   alert--info NEUTRAL = Hinweis/Fallback (surface/ink-2 = 9.32:1), damit ok
   und info sich farblich unterscheiden (info war zuvor faelschlich mint-gruen). */
.alert--ok{background:var(--brand-tint);color:var(--brand-darker);border:1px solid var(--brand-tint-2)}
.alert--info{background:var(--surface);color:var(--ink-2);border:1px solid var(--line)}
.alert--warn{background:#FCF1DC;color:#8A5B08;border:1px solid #F2DDA8}

.foot{margin-top:2.5rem;color:var(--ink-4);font-size:.8rem;text-align:center}
/* S11: nav ist jetzt die EINZIGE Navigation (keine _subnav.php mehr als
   Mobile-Fallback) -- darf auf schmalem Viewport nicht mehr komplett
   verschwinden wie vorher. flex:1 1 100% zwingt sie auf eine eigene volle
   Zeile (bricht danach selbst per flex-wrap in mehrere Link-Zeilen um),
   statt seitlich abgeschnitten zu werden oder Navigation zu verlieren. */
@media(max-width:640px){
  /* wrap zurueck: hier SOLL die Nav auf eine eigene volle Zeile umbrechen. */
  .topbar-inner{padding:.55rem 1rem;flex-wrap:wrap}
  .topbar nav{flex:1 1 100%;margin-left:0;gap:.1rem;order:3}
  .topbar nav a{padding:.42em .6em;font-size:.86rem}
  /* S15: Suche ist bereits ihre eigene Zeile (.searchbar) -- hier nur noch
     das Innenpadding an die schmalen Ansichten angleichen, kein order-Hack
     mehr noetig (der galt der alten Position INNERHALB von .topbar-inner). */
  .searchbar-inner{padding:.55rem 1rem}
  .topbar-search{flex:1 1 auto;max-width:none}
}

/* Admin Sub-Nav */
.subnav{display:flex;align-items:center;gap:.2rem;margin-bottom:1.5rem;border-bottom:1px solid var(--line);
  padding-bottom:0;flex-wrap:wrap}
.subnav a{color:var(--ink-3);font-weight:600;font-size:.88rem;padding:.6em 1em;border-radius:var(--r-sm) var(--r-sm) 0 0;
  transition:color .15s,background .15s;border-bottom:2px solid transparent;margin-bottom:-1px}
.subnav a:hover{color:var(--ink);background:var(--surface)}
.subnav a.active{color:var(--brand-dark);background:var(--brand-tint);border-bottom-color:var(--brand)}

/* Tables (Admin-Listen) */
.table-wrap{overflow-x:auto;border-radius:var(--r);box-shadow:var(--shadow-sm)}
.table{width:100%;border-collapse:collapse;background:var(--white);border:1px solid var(--line);
  border-radius:var(--r);font-size:.92rem}
.table th,.table td{padding:.5em .7em;border-bottom:1px solid var(--line);text-align:left;vertical-align:middle}
.table th{background:var(--surface);font-weight:600;color:var(--ink-2);font-size:.72rem;
  text-transform:uppercase;letter-spacing:.05em;white-space:nowrap}
.table tbody tr:last-child td{border-bottom:none}
.table tbody tr:hover{background:var(--brand-tint)}
.table tr.is-inactive{opacity:.55}
.table .actions{display:flex;gap:.4rem;flex-wrap:wrap;white-space:nowrap}
.table input[type=number],.table input[type=text]{font:inherit;font-size:.88rem;padding:.4em .55em;
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--white);color:var(--ink)}
.table input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 2px var(--brand-tint)}

/* Row-Aktionsmenue (Admin-Listen): buendelt Nebenaktionen hinter einem
   ⋯-Toggle, damit die Aktions-Spalte nicht mehr aus dem Bildschirm laeuft.
   Native Popover API (kein JS, kein <details> mehr) rendert das Popover im
   Top-Layer -> .table-wrap{overflow-x:auto} kann es NICHT mehr abschneiden
   (das war der Bug mit <details>: Last-Row-Clipping durch den scrollbaren
   Wrapper). Positionierung per CSS Anchor Positioning: jede Zeile bekommt
   per Inline-Style einen eigenen anchor-name/position-anchor (dashed ident
   aus der Entitaets-ID, da anchor-name je Anker eindeutig sein muss).
   Fallback fuer Browser ohne Anchor-Support: die @supports-Klammer unten
   greift dann nicht, anchor-name/position-anchor werden als unbekannte
   Properties ignoriert, und das Popover faellt auf das UA-Default fuers
   [popover]-Element zurueck (zentriert im Viewport) -- unschoen, aber
   NICHT geclippt. */
.rowmenu-btn{cursor:pointer;padding:.5em .7em;border-radius:var(--r-sm);
  border:1px solid var(--line);font-size:.9rem;line-height:1;color:var(--ink-2);
  background:var(--white);user-select:none}
.rowmenu-btn:hover{border-color:var(--brand);color:var(--brand-btn);background:var(--brand-tint)}
.rowmenu-pop[popover]{min-width:170px;padding:.35rem;background:var(--white);
  border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);
  flex-direction:column;gap:.15rem;white-space:nowrap}
/* display NUR wenn geoeffnet -- ein unbedingtes display:flex wuerde die
   UA-Regel [popover]:not(:popover-open){display:none} ueberschreiben, dann
   stehen ALLE Menues dauerhaft offen (Bug v0.9.x). */
.rowmenu-pop:popover-open{display:flex}
@supports (anchor-name: --a){
  .rowmenu-pop[popover]{position-area:bottom span-left;position-try-fallbacks:flip-block;margin-top:.3rem}
}
.rowmenu-item{display:block;width:100%;text-align:left;font:inherit;font-size:.86rem;
  padding:.5em .6em;border:none;border-radius:var(--r-sm);background:transparent;color:var(--ink);
  cursor:pointer}
.rowmenu-item:hover{background:var(--surface)}
.rowmenu-item--danger{color:var(--magenta)}
.rowmenu-item--danger:hover{background:#FBE9EE}

/* Badges (Status/Warnungen) */
.badge--danger{background:#FBE9EE;color:var(--magenta)}
.badge--muted{background:var(--surface-2);color:var(--ink-3)}
/* Timesheet-Lifecycle-Badges (S6): draft=muted(oben), submitted/internal=amber,
   sent=petrol, confirmed=default(mint), rejected=danger(oben) */
.badge--amber{background:#FCF1DC;color:#8A5B08}
.badge--petrol{background:#DEEBF0;color:var(--petrol-ink)}
/* Kontingent-Ampel (S9c): green=badge--ok (mint-tint/mint-darker statt dem
   Default-Badge mint-tint/mint-dark -- Default liegt bei ~3.76:1 Kontrast,
   unter AA-Text 4.5:1; mint-darker schafft ~6.4:1), orange=badge--amber
   (bereits oben, ~5.24:1), red=badge--danger (bereits oben, ~5.83:1) --
   siehe App\Quota::warnLevel(). Ampel-Dot zusaetzlich zum Text fuer
   Farbschwache (.dot--*). */
.badge--ok{background:var(--brand-tint);color:var(--brand-darker)}
.dot{display:inline-block;width:.55em;height:.55em;border-radius:50%;margin-right:.4em;vertical-align:middle}
.dot--green{background:var(--brand-darker)}
.dot--orange{background:#8A5B08}
.dot--red{background:var(--magenta)}

/* Timesheet-Grid (S6): kompakte Wochen-Tabelle, Zelle = Stunden + Kommentar */
/* fixed-Layout: sonst bestimmt jede Wochen-Tabelle ihre Spaltenbreiten selbst und
   Rand-Wochen mit "–"-Zellen (Monatsanfang/-ende) fluchten nicht mit den Vollwochen. */
.tsgrid{table-layout:fixed;min-width:56em}
/* nur die thead-Zeile bestimmt bei fixed-Layout die Breiten — td NICHT mitstylen,
   sonst trifft td:last-child in der Remote-Zeile die So-Spalte (Summen-td hat rowspan=2). */
.tsgrid th:first-child{width:8em}
.tsgrid th:last-child{width:6.5em}
.tsgrid th,.tsgrid td{text-align:center}
.tsgrid td:first-child,.tsgrid th:first-child{text-align:left;white-space:nowrap}
.tsgrid-cell{padding:.35em .3em!important}
.tsgrid-cell--outside{background:var(--surface);opacity:.5}
/* Sa/So optisch zurueckgenommen, aber voll bedienbar (Wochenend-Einsaetze kommen vor).
   Kein disabled/opacity -- nur Flaeche + Feld-Hintergrund grau. */
.tsgrid-col--weekend{background:var(--surface)}
.tsgrid th.tsgrid-col--weekend{background:var(--surface-2)}
/* .tsgrid-Prefix noetig: `.table input[type=text]` ist (0,2,1) und schlaegt sonst diese Regel. */
.tsgrid .tsgrid-col--weekend .ts-hours,.tsgrid .tsgrid-col--weekend .ts-note-input{
  background:var(--surface-2);color:var(--ink-2)}
.tsgrid .tsgrid-col--weekend .ts-hours:focus,.tsgrid .tsgrid-col--weekend .ts-note-input:focus{
  background:var(--white)}
.tsgrid-cell--outside .ts-hours,.tsgrid-cell--outside .ts-note-input{cursor:not-allowed}
.ts-hours{width:3.4em;font:inherit;font-size:.9rem;padding:.35em .3em;text-align:center;
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--white);color:var(--ink)}
.ts-hours:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 2px var(--brand-tint)}
.ts-hours.is-warn{background:#FCF1DC;border-color:#F2DDA8;color:#8A5B08}
.tsgrid-daywarn{display:block;font-size:.68rem;font-weight:700;color:#8A5B08;white-space:nowrap;margin-top:.15em}
/* Kommentarfeld je Zelle: gleiches Problem + gleiche Loesung wie beim
   Row-Aktionsmenue oben (.rowmenu-*) -- das aufgeklappte Notizfeld (9em) ist
   ~6.7x breiter als eine Tagesspalte (~1.34em bei 31 Tagen) und ragt ueber
   mehrere Nachbarzellen, die im DOM danach stehen und darueber gezeichnet
   werden. Native Popover API + CSS Anchor Positioning wie bei .rowmenu-pop:
   Top-Layer-Rendering entzieht das Feld dem Zellen-Stacking-Context, das
   <input> bleibt aber im <form>-DOM-Baum (Top-Layer ist reines Rendering,
   kein DOM-Move) und wird ganz normal mitgesendet. Anker-Ident je Zelle aus
   Datum+Modus (--tsn<date-ohne-bindestriche><mode>), muss eindeutig sein. */
.ts-note-btn{cursor:pointer;padding:0;border:none;background:transparent;font-size:.85rem;
  color:var(--ink-4);margin-left:.25em;line-height:1}
.ts-note-btn:hover{color:var(--brand-dark)}
.ts-note-pop[popover]{padding:.3em;background:var(--white);border:1px solid var(--line);
  border-radius:var(--r-sm);box-shadow:var(--shadow)}
@supports (anchor-name: --a){
  .ts-note-pop[popover]{position-area:bottom span-left;position-try-fallbacks:flip-block;margin-top:.3rem}
}
.ts-note-input{display:block;width:9em;font:inherit;font-size:.8rem;padding:.3em .5em;
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--white);color:var(--ink)}
.tsgrid-weeksum{font-weight:700;color:var(--brand-dark);white-space:nowrap}
/* .totals-bar = dieselbe Summenzeile ausserhalb des Timesheet-Grids (z.B.
   Offen/Bezahlt in der Berater-Rechnungsliste). Gemeinsamer Selektor statt
   Zweitdefinition -- der Name tsgrid-totals bleibt fuer Bestandscode gueltig. */
.tsgrid-totals,.totals-bar{display:flex;gap:1.6rem;flex-wrap:wrap;padding:.9rem 1.1rem;background:var(--brand-tint);
  border-radius:var(--r);font-size:.95rem}
.ts-reject-form{display:inline-block;position:relative}
.ts-reject-form[open] summary{color:var(--magenta)}
.ts-reject-form form{display:flex;gap:.4rem;align-items:center;margin-top:.4rem}
.ts-reject-form input[type=text]{font:inherit;font-size:.85rem;padding:.4em .6em;border:1px solid var(--line);
  border-radius:var(--r-sm);min-width:14em}

/* Load-% Pille (Verfuegbarkeit/Ueberbuchung) */
.pill-load{display:inline-block;font-size:.72rem;font-weight:700;padding:.15em .55em;border-radius:var(--r-full);
  background:var(--brand-tint);color:var(--brand-darker)}
.pill-load--over{background:#FBE9EE;color:var(--magenta)}

/* Verfuegbarkeits-Kalender (S8a): Wochen-Tabelle, Zelle = Status-Select.
   Farben reusen die bestehenden Badge-Tokens (petrol=onsite, mint=remote,
   amber=urlaub, muted=unavailable) fuer visuelle Konsistenz. */
/* Gleiche Ursache wie beim tsgrid: Wochen sind einzelne Tabellen, auto-Layout
   laesst Rand-Wochen mit "-"-Zellen anders fluchten als Vollwochen. */
.availcal{table-layout:fixed;min-width:44em}
.availcal th,.availcal td{text-align:center}
.avail-cell{padding:.35em .3em!important}
.avail-legend{display:flex;gap:1.2rem;flex-wrap:wrap;margin:.9rem 0 1.2rem;font-size:.85rem;color:var(--ink-3)}
.avail-legend .badge{margin-right:.35em}
.avail-select{width:5.6em;font:inherit;font-size:.85rem;padding:.35em .3em;text-align:center;
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--white);color:var(--ink)}
.avail-select:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 2px var(--brand-tint)}
.avail-select--onsite{background:#DEEBF0;border-color:#B9D6E1;color:var(--petrol-ink)}
.avail-select--remote{background:var(--brand-tint);border-color:var(--brand-tint-2);color:var(--brand-dark)}
.avail-select--urlaub{background:#FCF1DC;border-color:#F2DDA8;color:#8A5B08}
.avail-select--unavailable{background:var(--surface-2);border-color:var(--line);color:var(--ink-3)}

/* S24 Verfuegbarkeits-Plan (Projekt-Stunden pro Tag): reuse der .tsgrid-Optik
   (gleiche Zellbreiten/Farben wie das Timesheet-Grid) -- nur die
   Schnellwahl-Buttons ("8"/"4") und die Tagessummen-Zeile sind neu, beide
   nutzen ausschliesslich bestehende Tokens, keine neuen Farben. */
.availcal-plan{min-width:50em}
.availcal-plan th:first-child{width:9em}
.plan-row-label{display:block;line-height:1.25}
.plan-row-label small{display:block;font-weight:400;color:var(--ink-3);font-size:.72rem}
.plan-quick{display:flex;gap:.15em;justify-content:center;margin-top:.2em}
.plan-quick-btn{font:inherit;font-size:.62rem;line-height:1.3;padding:.05em .4em;border-radius:4px;
  border:1px solid var(--line);background:var(--surface);color:var(--ink-3);cursor:pointer}
.plan-quick-btn:hover{background:var(--brand-tint);border-color:var(--brand-tint-2);color:var(--brand-dark)}
.plan-quick-btn:disabled{opacity:.4;cursor:not-allowed}
.plan-daysum{font-weight:700;color:var(--brand-dark);white-space:nowrap}
.plan-daysum.is-warn{color:#8A5B08}

/* Formulare: Select/Textarea im gleichen Look wie Input; Grid fuer Feldpaare */
.field select,.field textarea{width:100%;font:inherit;font-size:.98rem;padding:.7em .85em;border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--white);color:var(--ink);transition:border-color .15s,box-shadow .15s;
  resize:vertical}
.field select:focus,.field textarea:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-tint)}
.field input[type=checkbox]{width:auto;margin-right:.5em;vertical-align:middle}
.field-error{color:var(--magenta);font-size:.8rem;margin-top:.35rem}
.form-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:0 1.2rem}
.actions{display:flex;gap:.7rem;flex-wrap:wrap;align-items:center;margin-top:.4rem}
.card--section{margin-top:1.5rem}
.mini-form{display:flex;gap:.8rem;flex-wrap:wrap;align-items:flex-end}

/* ============================================================
   Detail-Seiten: Beschreibungsliste, Inline-Edit-Felder, Disclosure
   (Kunden-Detailseite Tab-Welle 2026-07-19)
   ============================================================ */

/* Label/Wert-Paare der Uebersichts-Karte. Zweispaltig ab Tablet, darunter
   gestapelt -- eine feste Grid-Breite laesst lange Werte sonst umbrechen. */
.detail-list{display:grid;grid-template-columns:1fr;gap:.15rem .9rem;margin:0}
.detail-list dt{color:var(--ink-3);font-size:.88rem}
.detail-list dd{margin:0 0 .7rem;color:var(--ink)}
@media (min-width:640px){
  .detail-list{grid-template-columns:11rem 1fr;gap:.55rem .9rem}
  .detail-list dd{margin:0}
}

/* Inline-Felder in Edit-Tabellen. Ersetzt die frueheren style="width:8em"-
   Inline-Styles: die ergaben pro Spalte leicht abweichende Hoehen/Kanten und
   liessen das Grid unruhig wirken. Groessen als Modifier statt frei gesetzt. */
.inline-input{
  font:inherit;font-size:.92rem;color:var(--ink);background:var(--white);
  border:1px solid var(--line);border-radius:var(--r-sm);
  padding:.35em .5em;max-width:100%;
}
.inline-input:focus{outline:2px solid var(--brand);outline-offset:-1px;border-color:var(--brand)}
.inline-input--xs{width:6.5em}
.inline-input--sm{width:8.5em}
.inline-input--md{width:9.5em}
/* E-Mail: nimmt den freien Platz auf. Mit fester Breite (vormals 14em)
   schnitten realistische Adressen sichtbar ab; ein zu grosses min-width
   drueckt dafuer die Aktionsspalte in die zweite Zeile -- deshalb flexibel
   wachsend mit moderatem Minimum, kombiniert mit nowrap auf .actions. */
.inline-input--lg{width:100%;min-width:15em}
/* Aktions-Buttons einer Tabellenzeile bleiben nebeneinander -- umbrechende
   Buttons verdoppeln die Zeilenhoehe und machen das Grid unruhig. */
.table td.actions{white-space:nowrap}
/* Tabellen-Helfer (Rechnungseingang): zwei gestapelte Angaben in EINER Zelle
   statt zwei Spalten -- bei vielen Spalten brechen sonst Namen, Projekte und
   sogar Betraege mitten im Wort um. */
.cell-stack{line-height:1.3}
.cell-stack>span,.cell-stack>strong{display:block}
.cell-stack>.muted{font-size:.8rem;margin-top:.1em}
.nowrap{white-space:nowrap}
/* Ein <form> ist per Default block -- in einer Aktionszelle stellt es seinen
   Button sonst UNTER den Nachbar-Button statt daneben. */
.inline-form{margin:0}
/* Aktionszelle mit mehreren Bedienelementen: display am <form> greift im
   Tabellen-Layoutkontext nicht zuverlaessig (selbst ein Inline-Style bleibt
   "block"), deshalb wird die ZELLE zum Flex-Container -- damit stehen Link und
   Formular-Button verlaesslich nebeneinander statt untereinander. Eigene Klasse
   statt .actions global, um andere Tabellen nicht zu veraendern.
   nowrap statt wrap: so fliesst die Breite beider Bedienelemente in die
   Spaltenberechnung ein. Mit wrap bemass die Tabelle die Spalte nach der
   kuerzesten Zeile, und die Zeile mit dem laengeren Button brach um. */
.table td.actions--inline{display:flex;flex-wrap:nowrap;gap:.4rem;align-items:center}
/* Betragsspalten rechtsbuendig mit Ziffern gleicher Laufweite -- Summen sind
   so untereinander vergleichbar. */
.table th.num,.table td.num{text-align:right;font-variant-numeric:tabular-nums}

/* Icon-Buttons fuer wiederkehrende Zeilen-Aktionen. Quadratisch, damit eine
   Reihe davon ein ruhiges Raster ergibt. Das Label steckt in aria-label +
   title (siehe icon_button() in functions.php) -- nie nur im Icon. */
.btn--icon{padding:.42em;line-height:0;border-radius:var(--r-sm)}
.btn--icon .icon{display:block}
.btn--icon:hover{background:var(--surface-2);color:var(--ink)}
/* Destruktive Aktionen (Deaktivieren/Loeschen) erst beim Hover einfaerben --
   dauerhaft rote Icons in jeder Zeile waeren visuelles Dauerrauschen. */
.btn--icon.is-danger:hover{background:#FCE8EE;color:var(--magenta);border-color:#F3C9D6}
/* Fokus muss sichtbar bleiben: ohne Textlabel ist der Ring die einzige
   Ruecklmeldung fuer Tastatur-Navigation. */
.btn--icon:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
/* Vor-/Nachname teilen sich eine Zelle -- als Paar mit eigenem Abstand,
   damit sie nicht am Spaltenrand kleben. */
.inline-pair{white-space:nowrap}
.inline-pair .inline-input+.inline-input{margin-left:.35rem}

/* Aufklappbares Anlege-Formular. Zusammengeklappt ist es eine Zeile statt
   einer Reihe dauerhaft leerer Felder. */
.disclosure{border-top:1px solid var(--line);padding-top:.9rem;margin-top:.2rem}
.disclosure>summary{
  cursor:pointer;color:var(--ink-2);font-weight:500;font-size:.94rem;
  padding:.4em .6em;border-radius:var(--r-sm);display:inline-block;list-style:none;
}
.disclosure>summary::-webkit-details-marker{display:none}
.disclosure>summary:hover{color:var(--ink);background:var(--surface-2)}
.disclosure[open]>summary{color:var(--ink)}

/* ============================================================
   S7 Analytics — Stat-Kacheln, Budget-Balken, Burndown-Chart (inline SVG)
   Scoped Custom-Properties (--az-*) als Alias auf die globalen Tokens.
   P1.4: Der vormalige @media(prefers-color-scheme:dark)-Block themte NUR
   .analytics-block dunkel -> die restliche (light-only) App blieb hell =
   halbseitig-dunkles "Flicken"-Theme. Entfernt, bis die gesamte App dark-
   faehig ist; dann via explizitem :root[data-theme=dark] (nicht OS-Media)
   wieder-einfuehren, damit das ganze Theme umschaltet.
   ============================================================ */
.analytics-block{
  --az-ink:var(--ink); --az-ink-2:var(--ink-2); --az-ink-3:var(--ink-3); --az-ink-4:var(--ink-4);
  --az-surface:var(--white); --az-grid:var(--line);
  --az-brand:var(--brand); --az-brand-dark:var(--brand-dark); --az-brand-tint:var(--brand-tint);
  --az-magenta:var(--magenta); --az-blue:var(--blue);
}

/* Stat-Kacheln (Maximum / Spend to Date / Remaining) */
.stat-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1rem;margin-bottom:1.4rem}
.stat-tile{background:var(--az-surface);border:1px solid var(--az-grid);border-radius:var(--r);padding:1.1rem 1.3rem}
.stat-tile .stat-label{display:block;font-size:.72rem;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--az-ink-3);margin-bottom:.4rem}
.stat-tile .stat-value{display:block;font-family:var(--font-display);font-size:1.5rem;font-weight:700;color:var(--az-ink);font-variant-numeric:tabular-nums}
.stat-tile .stat-value.is-negative{color:var(--az-magenta)}
.stat-tile .stat-sub{display:block;margin-top:.25rem;font-size:.8rem;color:var(--az-ink-4)}

/* Budget-/Auslastungs-Balken (schlanker Fortschrittsbalken) */
.budget-bar{position:relative;height:.55rem;border-radius:var(--r-full);background:var(--az-grid);overflow:hidden;min-width:6rem}
/* P1.4: Fill von --az-brand (#1AB085, 2.16:1 ggue. Track, Fail UI-3:1) auf
   --brand-darker (5.54:1). is-warn #C99A2E->#8A5B08 (4.59:1). is-danger magenta
   bleibt (5.33:1). Balken-Farb-Logik jetzt konsistent mit .quota-bar__fill. */
.budget-bar__fill{position:absolute;inset:0 auto 0 0;height:100%;border-radius:var(--r-full);background:var(--brand-darker);transition:width .25s}
.budget-bar__fill.is-warn{background:#8A5B08}
.budget-bar__fill.is-danger{background:var(--magenta)}
.budget-bar-wrap{display:flex;align-items:center;gap:.6rem;min-width:10rem}
.budget-bar-wrap .budget-bar{flex:1}
.budget-bar-pct{font-size:.78rem;font-weight:600;color:var(--az-ink-3);font-variant-numeric:tabular-nums;white-space:nowrap}

/* Burndown-Chart (inline SVG) */
.burndown-chart-wrap{overflow-x:auto;background:var(--az-surface);border:1px solid var(--az-grid);border-radius:var(--r);padding:1rem 1.2rem 0.4rem}
.burndown-chart{display:block;min-width:520px;color:var(--az-ink-3)}
.burndown-chart .bd-grid{stroke:var(--az-grid);stroke-width:1}
.burndown-chart .bd-axis-label{fill:var(--az-ink-4);font-size:10px;font-family:var(--font-sans)}
.burndown-chart .bd-ideal{fill:none;stroke:var(--az-ink-4);stroke-width:1.5;stroke-dasharray:2 3}
.burndown-chart .bd-actual{fill:none;stroke:var(--az-brand-dark);stroke-width:2.5}
.burndown-chart .bd-actual-area{fill:var(--az-brand-tint);opacity:.55}
.burndown-chart .bd-forecast{fill:none;stroke:var(--az-brand-dark);stroke-width:2;stroke-dasharray:5 4;opacity:.85}
.burndown-chart .bd-budget-line{stroke:var(--az-magenta);stroke-width:1.25;stroke-dasharray:1 3}
.burndown-chart .bd-dot{fill:var(--az-brand-dark)}
.burndown-chart .bd-dot-forecast{fill:var(--az-surface);stroke:var(--az-brand-dark);stroke-width:1.5}
/* S7.4: "erwartet, noch nicht erfasst" -- vergangener Monat mit gepflegter
   Verfuegbarkeit, aber ohne time_entries. Offener, gestrichelter Punkt
   (KEINE verbundene Linie/Flaeche wie bd-actual), bewusst optisch von
   bd-dot (Ist, gefuellt) UND bd-dot-forecast (heller Ring, durchgezogen)
   unterschieden -- gedaempfte Ink-Farbe statt Mint/Magenta. */
.burndown-chart .bd-dot-estimated{fill:none;stroke:var(--az-ink-4);stroke-width:1.5;stroke-dasharray:2 2}
/* Welle B: Fallback-Annahme (Prognose-Stufe 5, `settings`-Pauschale statt
   echter Datenbasis) -- eigener, zurueckhaltender Punkt-Stil, bewusst NICHT
   die durchgezogene bd-forecast-Ringfarbe (Mint): heller Ring in Petrol
   (--az-blue) mit engerer Strichelung, damit ein Account Manager eine
   Annahme nie mit einer datenbasierten Prognose verwechselt. */
.burndown-chart .bd-dot-annahme{fill:var(--az-surface);stroke:var(--az-blue);stroke-width:1.5;stroke-dasharray:1.5 1.5}
/* Teil 5 (Review 2026-07-20): vertikale Markierung des massgeblichen Runout-
   Monats (Plan- ODER Trend-Prognose, je nachdem wer pessimistischer war --
   Analytics::resolveRunout()). Gleiche Farbe wie .bd-budget-line/badge--
   danger (--az-magenta, bereits als AA-konform gegen den Chart-Hintergrund
   im Einsatz, siehe .bd-budget-line oben) -- aber SOLIDE mit eigenem Dash-
   Muster statt der gepunkteten .bd-budget-line, und VERTIKAL statt
   horizontal, damit beide magenta-Linien trotz gleicher Farbe klar
   unterscheidbar bleiben. Die kleine Flaggen-Raute oben ist der Hover-/
   Tooltip-Ankerpunkt (SVG <title> traegt das Tagesdatum).*/
.burndown-chart .bd-runout-line{stroke:var(--az-magenta);stroke-width:1.75;stroke-dasharray:5 3;opacity:.9}
.burndown-chart .bd-runout-flag{fill:var(--az-magenta)}
.burndown-chart .bd-legend text{fill:var(--az-ink-2);font-size:11px;font-family:var(--font-sans)}
.burndown-chart-foot{display:flex;flex-wrap:wrap;gap:.5rem 1.4rem;align-items:center;padding:.7rem .2rem 1rem;font-size:.78rem;color:var(--az-ink-4)}
.burndown-chart-foot .legend-swatch{display:inline-block;width:1.1em;height:.35em;border-radius:2px;margin-right:.35em;vertical-align:middle}

/* S7.3 — Burndown-Chart + Verfuegbarkeit (aktueller Monat) nebeneinander
   (Projekt-Detail, Budget-Tab). Grid statt Flex, damit die schmalere Spalte
   bei knappem Platz sauber UNTEREINANDER faellt statt seitlich abgeschnitten
   zu werden (Lektion S9b.2: kein horizontaler Seiten-Scroll) -- NUR der
   Chart selbst behaelt sein eigenes overflow-x:auto (.burndown-chart-wrap),
   das Grid selbst scrollt nie seitlich. */
.burndown-availability-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(220px,300px);gap:1.2rem;align-items:start}
@media(max-width:860px){.burndown-availability-row{grid-template-columns:1fr}}
.availability-col{background:var(--az-surface);border:1px solid var(--az-grid);border-radius:var(--r);padding:1rem 1.2rem}
/* S7.4: Monats-Pulldown im Verfuegbarkeits-Panel-Header -- flex-wrap statt
   fester Breite, damit der Select bei knappem Platz sauber UNTER die
   Ueberschrift faellt statt das Panel horizontal zu sprengen (Lektion S9b.2). */
.availability-col-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem .7rem;flex-wrap:wrap;margin-bottom:.7rem}
.avail-month-form select{max-width:100%;font-size:.8rem;padding:.25rem .45rem;border-radius:var(--r);border:1px solid var(--az-grid);background:var(--az-surface);color:var(--az-ink)}
.avail-compact-list{list-style:none;display:flex;flex-direction:column;gap:.65rem}
.avail-compact-list li{display:flex;flex-direction:column;gap:.25rem;padding-bottom:.55rem;border-bottom:1px solid var(--az-grid);font-size:.86rem}
.avail-compact-list li:last-child{border-bottom:none;padding-bottom:0}
.avail-compact-counts{display:flex;flex-wrap:wrap;gap:.15rem .65rem;font-size:.8rem;color:var(--az-ink-3);font-variant-numeric:tabular-nums}

/* ============================================================
   S9b.2 — Kontingent-Cards (ersetzt die vormalige 12-Spalten-Tabelle mit
   Inline-Edit-Inputs auf projects_show.php). Je Berater-Einsatz eine
   ".quota-timeline": nummerierte, per Connector-Linie verbundene Kette von
   ".quota-card" (Erstauftrag→Verlängerungen), Karten gestapelt statt
   nebeneinander-Spalten -> kein Breiten-Overflow, sauberes Umbrechen auf
   schmalem Viewport (".quota-kv"/".quota-edit form" nutzen auto-fit-Grid
   statt fixer px-Spalten). Bearbeiten-Felder stecken in einem <details>-
   Toggle je Card (Muster wie .ts-note/.ts-reject-form) statt dauerhaft
   sichtbarer Tabellenzellen-Inputs.
   ============================================================ */
.quota-timeline{display:flex;flex-direction:column;margin-bottom:1.2rem}
.quota-item{position:relative;padding-left:2.5rem}
.quota-item + .quota-item{margin-top:1.1rem}
.quota-item::before{content:"";position:absolute;left:.68rem;top:1.9rem;bottom:-1.1rem;width:2px;background:var(--line)}
.quota-item:last-child::before{display:none}
.quota-item__marker{position:absolute;left:0;top:.1rem;width:1.4rem;height:1.4rem;border-radius:50%;
  background:var(--brand-tint);color:var(--brand-dark);font-size:.72rem;font-weight:700;font-family:var(--font-display);
  display:flex;align-items:center;justify-content:center;box-shadow:0 0 0 3px var(--bg)}
.quota-item.is-closed .quota-item__marker{background:var(--surface-2);color:var(--ink-3)}

.quota-card{background:var(--white);border:1px solid var(--line);border-radius:var(--r);padding:1.1rem 1.3rem;
  box-shadow:var(--shadow-sm);max-width:100%}
.quota-card.is-closed{opacity:.62}
.quota-card__head{display:flex;justify-content:space-between;align-items:flex-start;gap:.7rem;flex-wrap:wrap;margin-bottom:.8rem}
.quota-card__title{font-family:var(--font-display);font-weight:700;color:var(--ink);font-size:1.02rem}
.quota-card__badges{display:flex;gap:.4rem;flex-wrap:wrap;align-items:center}

/* Fortschrittsbalken je Kontingent: Fuellgrad = combinedPct (S9c), Farbe =
   Ampel-Level; sichtbarer %-Text daneben (nicht nur Farbe, Farbschwaeche). */
.quota-bar-row{display:flex;align-items:center;gap:.7rem;margin-bottom:.9rem}
.quota-bar{position:relative;flex:1;height:.6rem;border-radius:var(--r-full);background:var(--surface-2);overflow:hidden;min-width:0}
.quota-bar__fill{position:absolute;inset:0 auto 0 0;height:100%;border-radius:var(--r-full);background:var(--brand-darker);transition:width .25s}
/* P1.4: is-green explizit (war tote Klasse) = gleicher gruener Default-Fill
   (mint-darker, 5.76:1 ggue. Track). is-orange von #C99A2E (2.02:1, Fail UI)
   auf #8A5B08 (4.59:1 ggue. surface-2-Track). */
.quota-bar__fill.is-green{background:var(--brand-darker)}
.quota-bar__fill.is-orange{background:#8A5B08}
.quota-bar__fill.is-red{background:var(--magenta)}
.quota-bar-pct{font-size:.82rem;font-weight:700;color:var(--ink-2);white-space:nowrap;font-variant-numeric:tabular-nums}
.quota-bar-pct.is-danger{color:var(--magenta)}

/* Werte kompakt als Key-Value-Grid statt breiter Spaltenreihe */
.quota-kv{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:.6rem 1.1rem;margin-bottom:.7rem}
.quota-kv dt{font-size:.68rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-4);margin-bottom:.15rem}
.quota-kv dd{font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums;line-height:1.4}
.quota-kv dd.field-error{color:var(--magenta)}

/* S9b.1 — Schaetz-Pille fuer die jeweils nicht beauftragte Dimension:
   Pastell-Hellgruen, deutlich vom echten Wert abgesetzt (~-Praefix,
   title-Tooltip). Reuse der bereits fuer .badge--ok verifizierten
   Kontrast-Paarung mint-tint/mint-darker (~6.4:1, AA-Text-tauglich) statt
   eines neuen Farbpaars -- konsistent mit der S9c-Ampel-Farblogik. */
.quota-estimate{display:inline-block;margin-top:.2rem;font-size:.78rem;font-weight:600;
  color:var(--brand-darker);background:var(--brand-tint);border-radius:var(--r-sm);padding:.1em .5em;cursor:help}

.quota-meta{font-size:.82rem;color:var(--ink-3);margin-bottom:.6rem}

/* Bearbeiten-Toggle: Inputs nur bei Bedarf sichtbar (behebt den Breiten-
   Overflow der vormaligen Dauer-Inline-Inputs), Muster wie .ts-note. */
.quota-edit{margin-top:.4rem;border-top:1px dashed var(--line);padding-top:.65rem}
.quota-edit summary{cursor:pointer;font-size:.85rem;font-weight:600;color:var(--brand-dark);list-style:none}
.quota-edit summary::-webkit-details-marker{display:none}
.quota-edit summary::before{content:"▸";display:inline-block;margin-right:.35em;transition:transform .15s}
.quota-edit[open] summary::before{transform:rotate(90deg)}
.quota-edit form{margin-top:.8rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:.7rem 1rem}
.quota-edit .field label{font-size:.78rem}
.quota-edit .field input{width:100%}

.quota-card__actions{display:flex;gap:.6rem;flex-wrap:wrap;margin-top:.8rem}

/* ============================================================
   P1.4 A11y — sichtbarer Tastatur-Fokus (WCAG 2.4.7 / 1.4.11)
   Der bisherige Fokus war nur der Tint-Ring (~1.10:1, Fail). Jetzt globaler
   solider Outline in --brand-dark (#308B71): 4.15:1 ggue. weiss, 3.90:1 ggue.
   --bg -> >=3:1 (Non-Text-UI). Der Tint-Ring (box-shadow) bleibt ADDITIV als
   Fuellakzent. :focus-visible statt :focus -> kein Outline bei Maus-Klick,
   nur bei Tastatur/programmatischem Fokus.
   Die Input-Regeln oben setzen selbst outline:none via :focus; die folgenden
   :focus-visible-Overrides stehen spaeter in der Quelle und holen den Outline
   bei Tastatur-Fokus zurueck (gleiche Spezifitaet -> Source-Order gewinnt).
   ============================================================ */
:focus-visible{outline:2px solid var(--brand-dark);outline-offset:2px}
.topbar-search input:focus-visible,
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible,
.table input:focus-visible,
.ts-hours:focus-visible,
.ts-note-input:focus-visible,
.avail-select:focus-visible,
.ts-reject-form input:focus-visible{outline:2px solid var(--brand-dark);outline-offset:2px}

/* ============================================================
   Footer + Cookie-Hinweis-Layer + Rechtsseiten (2026-07-19)
   Cookie-Hinweis ist INFORMIEREND, nicht einwilligend -- digit-tnx setzt
   genau ein technisch notwendiges Session-Cookie (kein Consent-Gate noetig,
   siehe app/views/public/cookie_hinweis.php). Layer ist ein nicht-
   blockierender fixed-bottom-Balken, kein Modal/Overlay, kein Fokus-Trap.
   ============================================================ */
.site-footer{border-top:1px solid var(--line);margin-top:2rem;
  padding:1.4rem clamp(1rem,4vw,2rem) 1.6rem}
.site-footer-inner{max-width:var(--container);margin-inline:auto;display:flex;
  flex-wrap:wrap;gap:.5rem 1.4rem;align-items:center;justify-content:space-between;
  font-size:.82rem;color:var(--ink-4)}
.site-footer-links{display:flex;flex-wrap:wrap;gap:.3rem 1.1rem}
.site-footer-links a{color:var(--ink-3);font-weight:500}
.site-footer-links a:hover{color:var(--brand-dark)}

.cookie-notice{position:fixed;left:0;right:0;bottom:0;z-index:90;
  background:var(--white);border-top:1px solid var(--line);box-shadow:var(--shadow-lg);
  padding:.9rem clamp(1rem,4vw,1.6rem);display:flex;flex-wrap:wrap;gap:.7rem 1.4rem;
  align-items:center;justify-content:space-between}
.cookie-notice[hidden]{display:none}
.cookie-notice-text{flex:1 1 320px;margin:0;font-size:.85rem;line-height:1.5;color:var(--ink-2)}
.cookie-notice-actions{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem 1rem}
.cookie-notice-actions a{font-size:.85rem;font-weight:500;white-space:nowrap}
@media(max-width:640px){
  .cookie-notice{flex-direction:column;align-items:stretch;text-align:left}
  .cookie-notice-actions{justify-content:space-between}
}

/* Rechtsseiten (/datenschutz, /cookie-hinweis): sichtbar markierter
   Platzhalter fuer Angaben, die NICHT erfunden werden duerfen (siehe
   app/views/public/datenschutz.php) -- gestrichelte Box statt Fliesstext-
   Optik, damit ein unfertiger Abschnitt auch beim ueberfliegen auffaellt. */
.placeholder{background:#FCF1DC;color:#8A5B08;border:1px dashed #D9AE4E;
  border-radius:var(--r-sm);padding:.7em .9em;font-size:.87rem;line-height:1.55;margin:.5em 0}
.prefilled{background:var(--surface);color:var(--ink-2);border:1px solid var(--line);
  border-radius:var(--r-sm);padding:.7em .9em;font-size:.87rem;line-height:1.55;margin:.5em 0}
.prefilled strong{color:var(--ink)}

/* ============================================================
   Rechtsseiten-Overlay (Datenschutz / Cookie-Hinweis / Impressum)
   Die Seiten sollen den Arbeitskontext nicht ersetzen -- wer sie mitten aus
   einem Formular heraus oeffnet, soll ohne Browser-Back zurueckkommen.
   Ohne JS/<dialog> bleiben es normale Seiten (mit eigenem Zurueck-Link).
   ============================================================ */
.legal-modal{
  width:min(760px,92vw);max-height:86vh;padding:0;border:none;
  border-radius:var(--r-lg);box-shadow:var(--shadow-lg);background:var(--white);
  color:var(--ink-2);overflow:hidden;
  /* margin:auto zentriert den Dialog im Viewport. Ohne das klebt er in der
     linken oberen Ecke, sobald eine feste Breite gesetzt ist -- die
     UA-Default-Zentrierung von <dialog> greift dann nicht mehr. */
  margin:auto;
}
.legal-modal::backdrop{background:rgba(23,29,26,.45)}
.legal-modal-bar{
  position:sticky;top:0;z-index:2;display:flex;justify-content:flex-end;
  padding:.7rem .9rem;background:var(--white);border-bottom:1px solid var(--line);
}
.legal-modal-close{
  font:inherit;font-size:.9rem;font-weight:600;color:var(--ink);cursor:pointer;
  padding:.45em .9em;border:1px solid var(--line);border-radius:var(--r-sm);background:transparent;
}
.legal-modal-close:hover{background:var(--surface-2)}
.legal-modal-close:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.legal-modal-body{
  padding:1.2rem 1.5rem 1.8rem;overflow-y:auto;max-height:calc(86vh - 3.4rem);
}
.legal-modal-body:focus{outline:none}
/* Die Seiten-Ueberschrift ist im Overlay eine Ebene kleiner -- sie steht dort
   nicht als Seitentitel, sondern als Abschnittstitel im Dialog. */
.legal-modal-body h1{font-size:1.35rem}
.legal-modal-body .page-head{margin-bottom:1.1rem}
/* Der Zurueck-Link der Vollseite ist im Overlay redundant (es gibt den
   Schliessen-Button) -- ausblenden statt doppelt anbieten. */
.legal-modal-body .legal-back{display:none}

/* Zurueck-Link auf den Vollseiten (Fallback ohne JS / Direktaufruf) */
.legal-back{display:inline-flex;align-items:center;gap:.4em;margin-bottom:1.1rem;
  font-size:.92rem;font-weight:500;color:var(--brand-dark)}
.legal-back:hover{color:var(--brand-darker)}
.page--legal{max-width:820px}

/* ============================================================
   S18 — Session-Timeout-Warndialog (public/assets/js/session-timeout.js)
   Gleiches natives <dialog>-Pattern wie .legal-modal (kostenloser Fokus-Trap
   + Backdrop vom Browser), aber eigene Klasse: inhaltlich ein Warn-Ton
   (Countdown, dringlicher), keine Wiederverwendung von .legal-modal.
   ============================================================ */
.timeout-modal{width:min(420px,92vw);padding:0;border:none;border-radius:var(--r-lg);
  box-shadow:var(--shadow-lg);background:var(--white);color:var(--ink-2);margin:auto}
.timeout-modal::backdrop{background:rgba(23,29,26,.45)}
.timeout-modal-body{padding:1.4rem 1.5rem}
.timeout-modal-body h2{font-size:1.1rem;margin-bottom:.6rem;color:var(--ink)}
.timeout-modal-countdown{font-family:var(--font-display);font-weight:700;color:var(--magenta);
  font-variant-numeric:tabular-nums}
/* Gleiches Farbpaar wie .alert--warn (bereits AA-verifiziert) -- der Hinweis
   auf ungespeicherte Eingaben ist eine WARNUNG, kein Fehler. */
.timeout-modal-dirty{margin-top:.8rem;padding:.6em .8em;border-radius:var(--r-sm);
  background:#FCF1DC;color:#8A5B08;border:1px solid #F2DDA8;font-size:.85rem}
.timeout-modal-actions{display:flex;gap:.6rem;margin-top:1.2rem;flex-wrap:wrap}

/* "Naechster Schritt" im Berater-Dashboard (Timesheet::consultantNextAction()).
   Kompakter als .btn, weil pro Tabellenzeile eine Aktion steht -- volle Buttons
   wuerden die Zeile dominieren. Drei Varianten nach Dringlichkeit:
   primary = jetzt faellig (Rechnung stellen), warn = Handlungsbedarf nach
   Ablehnung, ghost = moeglich, aber nicht dringend. */
.next-action{display:inline-flex;align-items:center;gap:.4em;white-space:nowrap;
  padding:.34em .7em;border-radius:var(--r-full);font-size:.82rem;font-weight:600;
  text-decoration:none;border:1px solid transparent;transition:background .15s,border-color .15s}
.next-action svg{flex:none}
.next-action--primary{background:var(--brand);color:#fff}
.next-action--primary:hover{background:var(--brand-dark)}
.next-action--warn{background:#FCF1DC;color:#8A5B08;border-color:#F2DDA8}
.next-action--warn:hover{background:#F8E7C6}
.next-action--ghost{color:var(--ink-2);border-color:var(--line)}
.next-action--ghost:hover{background:var(--surface)}
/* Nicht-modaler Hinweis nach abgelaufener Frist, wenn ungespeicherte Eingaben
   auf der Seite stehen. Bewusst KEIN <dialog>/Modal: die Eingaben sind hier
   das Schuetzenswerte, ein Modal wuerde den Zugriff darauf blockieren. */
.timeout-expired-banner{position:fixed;left:50%;bottom:1.2rem;transform:translateX(-50%);
  z-index:1000;width:min(560px,92vw);padding:.75em 1em;border-radius:var(--r-sm);
  background:#FCF1DC;color:#8A5B08;border:1px solid #F2DDA8;font-size:.88rem;
  box-shadow:0 8px 28px rgba(23,29,26,.18)}
.timeout-expired-banner a{color:inherit;text-decoration:underline;font-weight:600}

/* ============================================================
   Verfuegbarkeits-Kalender (Analytics/Projekt-Detail, S7.3)
   7-Spalten-Raster nach der Skizze im Angebot: Tageszahl + Status-Kuerzel,
   Wochenenden gedaempft, offene Werktage sichtbar markiert.
   ============================================================ */
.avail-cal-block + .avail-cal-block{margin-top:1.1rem;padding-top:1.1rem;border-top:1px solid var(--line)}
.avail-cal-name{font-weight:600;color:var(--ink);font-size:.92rem;margin-bottom:.5rem}
.avail-cal{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}
.avail-cal-dow{font-size:.62rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-3);text-align:center;padding-bottom:.2rem}
.avail-cal-cell{position:relative;aspect-ratio:1;border-radius:var(--r-sm);border:1px solid var(--line);
  background:var(--white);display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:1px;min-height:30px;overflow:hidden}
.avail-cal-cell.is-empty{border:none;background:transparent}
.avail-cal-n{font-size:.62rem;color:var(--ink-3);line-height:1}
.avail-cal-s{font-size:.6rem;font-weight:700;line-height:1}
/* Status-Farben: bestehende Tokens, keine neuen Werte erfinden. */
.avail-cal-cell.cal-o{background:var(--brand-tint);border-color:var(--brand-tint-2)}
.avail-cal-cell.cal-o .avail-cal-s{color:var(--brand-darker)}
.avail-cal-cell.cal-r{background:#EAF1F4;border-color:#D6E3E9}
.avail-cal-cell.cal-r .avail-cal-s{color:var(--petrol-ink)}
.avail-cal-cell.cal-u{background:#FDF3E3;border-color:#F5E2C4}
.avail-cal-cell.cal-u .avail-cal-s{color:#9A6B12}
.avail-cal-cell.cal-nv{background:var(--surface-2);border-color:var(--line)}
.avail-cal-cell.cal-nv .avail-cal-s{color:var(--ink-3);font-size:.5rem}
.avail-cal-cell.is-weekend{background:var(--surface);border-color:transparent}
.avail-cal-cell.is-weekend .avail-cal-n{color:var(--ink-4);opacity:.6}
/* Offener Werktag: gestrichelt statt farbig -- soll auffallen, aber nicht wie
   ein eigener Status aussehen. */
.avail-cal-cell.is-open{border-style:dashed;border-color:#E0C9A0;background:#FEFCF8}
.avail-cal-legend{display:flex;flex-wrap:wrap;gap:.5rem .9rem;margin-top:.7rem;font-size:.72rem;color:var(--ink-3)}
.avail-cal-legend b{font-weight:700}
.avail-cal-legend b.cal-o{color:var(--brand-darker)}
.avail-cal-legend b.cal-r{color:var(--petrol-ink)}
.avail-cal-legend b.cal-u{color:#9A6B12}
.avail-cal-legend b.cal-nv{color:var(--ink-3)}
.avail-cal-note{margin-top:.55rem;font-size:.75rem;color:var(--ink-3);line-height:1.45}
.avail-cal-open{color:#9A6B12;font-weight:600}
