/* ═══════════════════════════════════════════════════════════════════════════
   alike Design System · COMPONENTS  (braucht tokens.css)
   Liquid Glass · Light+Dark · Apple-spring-motion.
   Klassen-namen bewusst nah an den prototypen; ds.js verdrahtet die interaktiven.
   ═══════════════════════════════════════════════════════════════════════════ */

*{box-sizing:border-box;margin:0;padding:0}
/* Bedienelemente erben die Schrift NICHT von selbst — der Browser setzt sie
   auf seine eigene Vorgabe (auf dem Mac Arial). Jede Klasse, die font:inherit
   vergisst, stand dadurch als einzelner Arial-Knopf in einer SF-Pro-App; der
   Laufzeit-Audit fand 16 solche Stellen (.sp-tab, .hub-tab-btn, .doc-view-btn,
   .rka-pauschale-btn, .btn-primary allein). Einmal zentral statt Fall fuer
   Fall — Groesse/Gewicht bleiben bewusst bei den Komponenten. */
button,input,select,textarea,optgroup{font-family:inherit}
/* Link-reset: main.css (das a{text-decoration:none} hatte) lädt auf DS-seiten
   nicht — sonst unterstreicht der browser-default alle <a> (auch a.btn). */
a{color:var(--accent);text-decoration:none}

body{
  min-height:100vh;color:var(--label);font-family:var(--font-ui);
  -webkit-font-smoothing:antialiased;
  background:
    radial-gradient(1000px 720px at 100% -12%, var(--bg-glow-1), transparent 56%),
    radial-gradient(900px 700px at -10% 108%, var(--bg-glow-2), transparent 56%),
    radial-gradient(760px 620px at 62% 122%, var(--bg-glow-3), transparent 55%),
    var(--bg);
  background-attachment:fixed;
}

/* ── Typo-helfer ───────────────────────────────────────────────────────── */
.t-large-title{font-size:var(--fs-large-title);font-weight:var(--fw-large-title);letter-spacing:var(--tr-large-title);line-height:var(--lh-large-title)}
.t-title-2{font-size:var(--fs-title-2);font-weight:var(--fw-title-2);letter-spacing:var(--tr-title-2)}
.t-title-3{font-size:var(--fs-title-3);font-weight:var(--fw-title-3);letter-spacing:var(--tr-title-3)}
.t-headline{font-size:var(--fs-headline);font-weight:var(--fw-headline);letter-spacing:var(--tr-headline)}
.t-body{font-size:var(--fs-body);font-weight:var(--fw-body)}
.t-callout{font-size:var(--fs-callout)}
.t-subhead{font-size:var(--fs-subhead)}
.t-footnote{font-size:var(--fs-footnote)}
.t-secondary{color:var(--label-secondary)}
.t-tertiary{color:var(--label-tertiary)}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}

/* ── Glas-flächen ──────────────────────────────────────────────────────── */
.glass{background:var(--glass-chrome);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);box-shadow:var(--specular)}
.glass-card{background:var(--glass-card);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:1px solid var(--hairline);box-shadow:var(--specular),var(--shadow-card)}

/* ── Layout ────────────────────────────────────────────────────────────── */
.app{display:grid;grid-template-columns:240px minmax(0,1fr);min-height:100vh}
.main{display:flex;flex-direction:column;min-height:100vh;min-width:0}
.content{padding:var(--sp-12) var(--sp-14) var(--sp-24);min-width:0}
.page-head{margin:var(--sp-2) var(--sp-1) var(--sp-9)}

/* ── Sidebar ───────────────────────────────────────────────────────────── */
.sidebar{background:var(--glass-chrome);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);border-right:.5px solid var(--hairline);box-shadow:var(--specular);padding:var(--sp-7) var(--sp-5);display:flex;flex-direction:column;gap:var(--sp-6);position:sticky;top:0;height:100vh}
.brand{display:flex;align-items:center;gap:9px;padding:7px 10px 2px}
.brand__link{display:flex;align-items:center;text-decoration:none}
.brand__logo{height:26px;width:auto;max-width:170px;object-fit:contain;object-position:left center;display:block}
.brand__wort{font-family:var(--font-display);font-size:17px;font-weight:700;letter-spacing:-.01em;color:var(--label);max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.brand__logo--light{display:none}
[data-theme="light"] .brand__logo--dark{display:none}
[data-theme="light"] .brand__logo--light{display:block}
.nav{position:relative;display:flex;flex-direction:column;gap:1px;overflow:visible}
.nav__indicator{position:absolute;left:0;right:0;height:0;border-radius:9px;background:var(--selection-bg);box-shadow:var(--selection-shadow);transition:transform var(--dur) var(--spring-soft),height var(--dur) var(--spring-soft),opacity var(--dur);z-index:0;pointer-events:none}
.nav__header{font-size:var(--fs-footnote);font-weight:600;color:var(--label-tertiary);padding:13px 10px 5px}
.nav__item{position:relative;z-index:1;display:flex;align-items:center;gap:10px;padding:6px 10px;border-radius:9px;color:var(--label);text-decoration:none;font-size:13.5px;font-weight:450;transition:color var(--dur)}
.nav__item .icon{width:17px;height:17px;flex:none;color:var(--label-secondary);transition:color var(--dur)}
.nav__item:hover{background:var(--fill)}
.nav__item.is-active{color:var(--selection-fg);font-weight:550}
.nav__item.is-active .icon{color:var(--blue)}
.nav__badge{margin-left:auto;background:var(--red);color:#fff;font-size:var(--fs-caption);font-weight:600;border-radius:var(--radius-pill);min-width:18px;height:18px;display:grid;place-items:center;padding:0 5px}

/* Nav-gruppen (Sales/Finanzen/HR): aufklappbar, spring-chevron */
.nav-group__toggle{width:100%;border:none;background:none;font:inherit;text-align:left;display:flex;align-items:center;gap:10px;padding:6px 10px;border-radius:9px;color:var(--label);font-size:13.5px;font-weight:450;cursor:pointer;outline:none;transition:background var(--dur-fast)}
.nav-group__toggle:hover{background:var(--fill)}
.nav-group__toggle .icon{width:17px;height:17px;flex:none;color:var(--label-secondary)}
.nav-group__toggle .chev{margin-left:auto}
.nav-group.is-open .nav-group__toggle .chev{transform:rotate(180deg)}
.nav-group__items{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--dur) var(--spring-soft)}
.nav-group.is-open .nav-group__items{grid-template-rows:1fr}
.nav-group__items>div{overflow:hidden;display:flex;flex-direction:column;gap:1px}
.nav__subitem{display:block;padding:5px 10px 5px 37px;border-radius:8px;color:var(--label-secondary);text-decoration:none;font-size:13px;transition:background var(--dur-fast),color var(--dur-fast)}
.nav__subitem:hover{background:var(--fill);color:var(--label)}
.nav__subitem.is-active{color:var(--blue);font-weight:550;background:var(--fill)}
.me{display:flex;align-items:center;gap:9px;padding:7px 9px;border-radius:var(--radius-md)}
/* Sidebar-fuß: controls-zeile + account als kompakte gruppe ganz unten */
/* Frosted-glass-fuß: liegt als overlay über dem unteren nav-ende; der nav-inhalt
   scrollt durchscheinend (geblurrt) dahinter durch (macOS sidebar scroll-edge).
   Full-bleed bis an die sidebar-ränder, hairline + weicher schatten als kante. */
.sidebar-foot{
  /* robustes overlay INNERHALB der sidebar (absolute) — kann nie als grid-item
     brechen. deckend, damit der nav-inhalt nicht durchschlägt (nested blur
     greift hier nicht); hairline + schatten als saubere kante. */
  position:absolute;left:0;right:0;bottom:0;z-index:2;
  display:flex;flex-direction:column;gap:5px;
  padding:13px var(--sp-5) var(--sp-7);
  /* VOLL deckend, sonst schlagen die durchscrollenden Nav-Eintraege durch:
     die Sidebar ist selbst ein backdrop-filter-Container, ein verschachtelter
     Blur greift hier nicht (siehe Kommentar oben). Frueher stand hier ein
     color-mix mit 92% --surface — die restlichen 8% liessen den Nav-Text
     hinter "Test Admin" sichtbar durchscheinen.
     Zwei Lagen: Chrome-Glasfarbe ueber der opaken Seitenfarbe = exakt der
     Ton der Seitenleiste, aber ohne Rest-Transparenz. */
  background:linear-gradient(var(--glass-chrome),var(--glass-chrome)),var(--bg);
  border-top:.5px solid var(--hairline);
  box-shadow:0 -10px 20px -8px rgba(0,0,0,.26);
}
/* Globale controls (Bug/Glocke/Theme) gebündelt über dem account */
.me-controls{display:flex;align-items:center;gap:3px;padding:0 4px}
.me:hover{background:var(--fill)}

/* ── Page-bar (vereinter Header: Titel + Aktionen in einer Zeile, scrollt) ── */
.page-bar{display:flex;align-items:flex-start;gap:12px 20px;flex-wrap:wrap;margin:var(--sp-2) 0 var(--sp-9)}
.page-bar__title{min-width:0;flex:1 1 auto}
.page-bar__title:empty{display:none}
.page-bar__actions{display:flex;align-items:center;gap:9px;flex-shrink:0;margin-left:auto;padding-top:5px}
/* Nav-back-link links in der leiste (detail-seiten) — subtil, kein blau */
.page-bar__back{display:inline-flex;align-items:center;gap:5px;color:var(--label-secondary);text-decoration:none;font-size:14px;font-weight:500;padding-top:5px;transition:color var(--dur-fast)}
.page-bar__back:hover{color:var(--label)}
.page-bar__back svg{flex-shrink:0}
.page-bar:has(.page-bar__title:empty){margin-bottom:var(--sp-3)}
/* Detail-seiten: titel leer, back-link + aktionen im hero, globale controls in
   der sidebar -> page-bar ist leer und kollabiert komplett. */
.page-bar:has(.page-bar__title:empty):not(:has(.page-bar__back)):not(:has(.page-bar__actions > *)){display:none}
.back-link{display:inline-flex;align-items:center;gap:5px;color:var(--blue);text-decoration:none;font-size:14px;margin-bottom:14px}
.back-link:hover{text-decoration:underline}
/* Inline-textlink (im fliesstext) — blau, Apple-konform */
.text-link{color:var(--accent);text-decoration:none}
.text-link:hover{text-decoration:underline}
/* Klickbarer zeilen-/zellen-titel in tabellen — label-farbe (NICHT blau),
   die ganze zeile ist klickbar; hover tönt dezent in den akzent. */
.row-link{color:var(--label);font-weight:600;text-decoration:none}
.row-link:hover{color:var(--accent)}
/* App-weit: klickbare titel/namen in DS-tabellen + karten-listen sind label-
   farbe (NICHT blau). Aktionen (.btn) und echte inline-links (.text-link)
   bleiben ausgenommen. */
.pcard__name, .deal-link, .kanban-card-title, .prof-task-name,
.stcal-studio-name, .ip-task-link,
.data-table td a:not(.btn):not(.text-link):not([class*="badge"]),
.data-table-responsive td a:not(.btn):not(.text-link):not([class*="badge"]){color:var(--label);text-decoration:none}
.pcard__name:hover, .deal-link:hover, .kanban-card-title:hover, .prof-task-name:hover,
.stcal-studio-name:hover, .ip-task-link:hover,
.data-table td a:not(.btn):not(.text-link):not([class*="badge"]):hover,
.data-table-responsive td a:not(.btn):not(.text-link):not([class*="badge"]):hover{color:var(--accent)}

/* ── Avatar ────────────────────────────────────────────────────────────── */
.avatar{width:29px;height:29px;border-radius:50%;background:linear-gradient(180deg,var(--accent-fill),var(--purple));display:grid;place-items:center;color:#fff;font-weight:600;font-size:12px}
.avatar--xs{width:25px;height:25px;font-size:10px;box-shadow:0 0 0 2px var(--glass-card)}
.avatar-stack{display:flex;align-items:center}
.avatar-stack .avatar--xs+.avatar--xs{margin-left:-7px}
.avatar-stack__more{font-size:12.5px;color:var(--label-secondary);margin-left:7px}

/* ── Buttons ───────────────────────────────────────────────────────────── */
.btn{border:none;font:inherit;font-size:13px;font-weight:500;text-decoration:none;border-radius:var(--radius-sm);padding:6px 14px;cursor:pointer;outline:none;color:var(--label);background:var(--fill);box-shadow:inset 0 0 0 .5px var(--hairline-soft);transition:transform var(--dur) var(--spring),background var(--dur-fast),filter var(--dur-fast)}
.btn:hover{background:var(--fill-strong);color:var(--label)}
.btn:active{transform:scale(.95)}
.btn--primary{color:var(--on-accent);background:linear-gradient(180deg,var(--accent-fill-strong),var(--accent-fill));box-shadow:inset 0 1px 0 rgba(255,255,255,.28),0 4px 14px -5px rgba(var(--accent-rgb),.55)}
.btn--primary:hover{filter:brightness(1.08);background:linear-gradient(180deg,var(--accent-fill-strong),var(--accent-fill));color:var(--on-accent)}
.btn--icon{width:30px;height:30px;padding:0;display:grid;place-items:center;color:var(--label-secondary)}
.btn--icon:active{transform:scale(.9)}
.btn--sm{padding:4px 11px;font-size:12px;border-radius:9px}
.btn--ghost{background:transparent;box-shadow:none;color:var(--label-secondary)}
.btn--ghost:hover{background:var(--fill);color:var(--label)}
.btn--danger{color:var(--red)}
.btn--danger:hover{background:color-mix(in srgb,var(--red) 14%,transparent);color:var(--red)}
.field{display:flex;align-items:center;gap:7px;background:var(--fill);border-radius:var(--radius-sm);padding:5px 11px;color:var(--label-secondary);font-size:12.5px;box-shadow:inset 0 0 0 .5px var(--hairline-soft)}

/* ── Segmented control (morphendes glas-pill, s. ds.js) ────────────────── */
.seg{position:relative;display:flex;gap:0;padding:3px;border-radius:var(--radius-md);background:var(--seg-track);box-shadow:var(--seg-track-inset)}
.seg__pill{position:absolute;left:0;top:3px;bottom:3px;border-radius:var(--radius-sm);background:var(--seg-pill);box-shadow:var(--seg-pill-shadow);transition:transform var(--dur) var(--spring),width var(--dur-slow) var(--spring);z-index:0}
.seg button{position:relative;z-index:1;border:none;background:none;font:inherit;font-size:12.5px;font-weight:500;color:var(--seg-fg-off);padding:5px 16px;border-radius:var(--radius-sm);cursor:pointer;outline:none;transition:color var(--dur) var(--smooth),transform .12s var(--spring)}
.seg button:hover{color:var(--label)}
.seg button:active{transform:scale(.93)}
.seg button.is-active{color:var(--seg-fg)}

/* ── Dropdown-trigger + Popover-menü (springt aus ursprung auf) ─────────── */
.dropdown{position:relative;display:inline-flex;align-items:center;gap:7px;padding:var(--ctrl-pad-y) var(--ctrl-pad-x);border-radius:var(--radius-sm);background:var(--fill);box-shadow:inset 0 0 0 .5px var(--hairline-soft);font-size:var(--ctrl-font);color:var(--label);cursor:pointer;transition:background var(--dur-fast),transform var(--dur) var(--spring)}
.dropdown:hover{background:var(--fill-strong)}
.dropdown:active{transform:scale(.96)}
.chev{width:11px;height:11px;color:var(--label-tertiary);stroke-width:2;flex:none;transition:transform var(--dur) var(--spring)}
.is-open>.chev,.is-open .chev{transform:rotate(180deg)}
/* WICHTIG: jedes [data-menu] ist anker fuer sein popover — ohne position:relative
   wuerde das menu am naechsten positionierten vorfahren (z.b. der tabellen-ZEILE)
   haengen und an voellig falscher stelle erscheinen. */
[data-menu]{position:relative}
.menu{position:absolute;z-index:var(--z-popover);top:calc(100% + 6px);left:0;min-width:160px;padding:5px;border-radius:13px;background:var(--glass-popover);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-pop);
  opacity:0;transform:scale(.92) translateY(-6px);transform-origin:top left;pointer-events:none;transition:opacity .2s var(--smooth),transform .2s var(--spring)}
/* offenes dropdown hebt sich ueber karten-stacking-contexts (backdrop-filter) */
[data-menu].is-open{z-index:calc(var(--z-popover) + 1)}
.menu--right{left:auto;right:0;transform-origin:top right}
.is-open>.menu,.is-open .menu{opacity:1;transform:none;pointer-events:auto}
/* portaliertes menü (in <body> verschoben, fixed positioniert via ds.js) —
   sichtbarkeit wird hier per .is-shown getrieben, nicht ueber den host. */
.menu.is-portaled{position:fixed;margin:0;z-index:200}
.menu.is-shown{opacity:1;transform:none;pointer-events:auto}
.menu__item{display:flex;align-items:center;gap:9px;padding:7px 10px;border-radius:9px;font-size:13px;color:var(--label);cursor:pointer;transition:background .12s}
/* button.menu__item: UA-button-styles zurücksetzen (border/fill/appearance),
   damit <button>-menü-items genauso flach rendern wie die <a>/<div>-varianten */
button.menu__item{appearance:none;-webkit-appearance:none;border:none;background:none;font:inherit;font-size:13px;width:100%;text-align:left;margin:0}
.menu__item:hover{background:var(--fill-strong)}
.menu__group{padding:7px 10px 3px;font-size:11px;font-weight:600;color:var(--label);opacity:.5;pointer-events:none;letter-spacing:.01em}
.menu__group:not(:first-child){margin-top:3px;border-top:.5px solid var(--hairline);padding-top:8px}
.menu__item .dot{width:7px;height:7px;border-radius:50%}
.menu__item .check-mark{margin-left:auto;width:13px;height:13px;color:var(--blue);opacity:0}
.menu__item.is-selected .check-mark{opacity:1}
/* auswahl-haekchen css-only (kein svg im markup noetig) — wie macOS-menues */
.menu__item.is-selected::after{content:"";margin-left:auto;width:13px;height:13px;flex:none;background:var(--accent-fill);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5L20 6'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5L20 6'/%3E%3C/svg%3E") center/contain no-repeat}
.menu__item:has(.check-mark).is-selected::after{display:none}

/* ── Status-pill (auch als dropdown-trigger nutzbar) ───────────────────── */
.status{display:inline-flex;align-items:center;gap:6px;padding:4px 9px;border-radius:var(--radius-pill);font-size:var(--fs-footnote);font-weight:500;cursor:default;transition:transform .2s var(--spring),background var(--dur) var(--smooth),color var(--dur) var(--smooth)}
.status[data-menu]{cursor:pointer}
.status[data-menu]:active{transform:scale(.93)}
.status .dot{width:6px;height:6px;border-radius:50%;transition:background var(--dur)}
.status--todo{background:var(--status-todo-bg);color:var(--status-todo-fg)} .status--todo .dot{background:var(--accent-fill)}
.status--progress,.status--in_progress{background:var(--status-progress-bg);color:var(--status-progress-fg)} .status--progress .dot,.status--in_progress .dot{background:var(--purple)}
.status--done{background:var(--status-done-bg);color:var(--status-done-fg)} .status--done .dot{background:var(--green)}
.status--backlog{background:var(--status-backlog-bg);color:var(--status-backlog-fg)} .status--backlog .dot{background:var(--label-tertiary)}
.status--review{background:var(--status-review-bg);color:var(--status-review-fg)} .status--review .dot{background:var(--orange)}

/* Inline „cap"-dropdown (z.b. projekt-zuordnung in tabellen) */
.cap{display:inline-flex;align-items:center;gap:6px;max-width:100%;padding:4px 8px;border-radius:var(--radius-sm);background:var(--fill);box-shadow:inset 0 0 0 .5px var(--hairline-soft);font-size:12.5px;color:var(--label);cursor:pointer;transition:background var(--dur-fast),transform .2s var(--spring)}
.cap:hover{background:var(--fill-strong)} .cap:active{transform:scale(.95)} .cap.is-muted{color:var(--label-secondary)}
.cap__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── Card / Stat-chip / KPI ────────────────────────────────────────────── */
.card{background:var(--glass-card);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:1px solid var(--hairline);border-radius:var(--radius-lg);box-shadow:var(--specular),var(--shadow-card);overflow:hidden}
.card__header{display:flex;align-items:center;justify-content:space-between;padding:15px 18px 11px}
.card__title{font-size:var(--fs-headline);font-weight:600;letter-spacing:-.3px}
.card__action{font-size:13px;color:var(--blue);text-decoration:none;font-weight:400}
.card__count{font-size:13px;color:var(--label-secondary);background:var(--fill);padding:2px 9px;border-radius:var(--radius-pill);font-variant-numeric:tabular-nums}

.stat-chip{display:inline-flex;align-items:center;gap:9px;padding:9px 15px;border-radius:13px;background:var(--glass-card);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-float);transition:transform var(--dur) var(--spring)}
.stat-chip:hover{transform:translateY(-2px)}
.stat-chip .dot{width:8px;height:8px;border-radius:50%}
.stat-chip__label{font-size:var(--fs-footnote);color:var(--label-secondary);font-weight:500}
.stat-chip__value{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}

.kpi{background:var(--glass-card);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);border-radius:var(--radius-lg);box-shadow:var(--specular),var(--shadow-card);padding:16px 18px}
.kpi__label{font-size:var(--fs-subhead);color:var(--label-secondary);font-weight:500;display:flex;align-items:center;gap:7px}
.kpi__label .icon{width:15px;height:15px}
.kpi__value{font-size:36px;font-weight:600;letter-spacing:-1px;margin-top:9px;line-height:1}
.kpi__meta{font-size:var(--fs-footnote);color:var(--label-secondary);margin-top:8px;display:flex;align-items:center;gap:4px}
.kpi__meta--up{color:var(--success-fg)} .kpi__meta--down{color:var(--due-overdue)}

/* ── Tabelle / Listen-zeile ────────────────────────────────────────────── */
.thead{height:34px;border-top:.5px solid var(--hairline);border-bottom:.5px solid var(--hairline);display:grid;align-items:center;gap:14px;padding:0 18px}
.thead span{font-size:var(--fs-caption);color:var(--label-tertiary);font-weight:600}
.row{display:grid;align-items:center;gap:14px;padding:9px 18px;min-height:54px;position:relative;transition:background var(--dur-fast),transform var(--dur) var(--spring)}
.row+.row::before{content:"";position:absolute;left:58px;right:0;top:0;height:.5px;background:var(--hairline-soft)}
.row:hover{background:var(--row-hover)}
.row__title{font-size:14px;font-weight:450;display:flex;align-items:center;gap:7px;transition:color .2s}
.row__title .prio{width:7px;height:7px;border-radius:50%;flex:none}
.due{font-size:12.5px;color:var(--label-secondary);text-align:right;font-variant-numeric:tabular-nums}
.due.is-overdue{color:var(--due-overdue);font-weight:500}

/* Checkbox: spring-fill + haken zeichnen + erledigt-burst (pop + ring) */
.check{position:relative;width:21px;height:21px;border-radius:50%;border:1.6px solid var(--label-tertiary);cursor:pointer;display:grid;place-items:center;transition:border-color var(--dur-fast),background var(--dur) var(--spring),transform var(--dur) var(--spring)}
.check:active{transform:scale(.85)}
.check svg{width:12px;height:12px;stroke:#fff;stroke-width:3;fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:20;stroke-dashoffset:20;transition:stroke-dashoffset var(--dur) var(--smooth) .08s}
.check.is-done{background:var(--green);border-color:var(--green);animation:ds-check-pop .24s var(--spring)}
.check.is-done svg{stroke-dashoffset:0}
.check.is-done::after{content:"";position:absolute;inset:-3px;border-radius:50%;border:2px solid var(--green);opacity:0;animation:ds-check-ring .55s var(--smooth) .06s}
@keyframes ds-check-pop{0%{transform:scale(1)}40%{transform:scale(1.25)}100%{transform:scale(1)}}
@keyframes ds-check-ring{0%{transform:scale(.55);opacity:.7}100%{transform:scale(1.6);opacity:0}}
.row.is-done .row__title{color:var(--label-tertiary);text-decoration:line-through;text-decoration-color:var(--label-tertiary)}

/* Zeilen-collapse nach erledigen: zeile gleitet raus, liste schliesst sich sanft.
   nutzung (js): .row-collapse setzen, hoehe in px fixieren, reflow, .is-collapsing */
.row-collapse{transition:height .2s var(--smooth),padding .2s var(--smooth),opacity .2s var(--smooth),transform .2s var(--smooth);overflow:hidden}
.row-collapse.is-collapsing{height:0!important;padding-top:0!important;padding-bottom:0!important;opacity:0;transform:translateX(16px)}

/* ── Progress-ring (conic, --p prozent / --c farbe) ────────────────────── */
.ring{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;font-size:10.5px;font-weight:600;color:var(--label);position:relative;flex:none}
.ring::before{content:"";position:absolute;inset:0;border-radius:50%;background:conic-gradient(var(--c,var(--blue)) calc(var(--p,0)*1%),var(--fill-strong) 0);-webkit-mask:radial-gradient(circle,transparent 12px,#000 13px);mask:radial-gradient(circle,transparent 12px,#000 13px)}

/* ── Toasts (auch flash-messages) ──────────────────────────────────────── */
/* ── Push-Hinweis ───────────────────────────────────────────────────────────
   Erscheint einmalig fuer angemeldete Nutzer ohne Push-Abo. Kein Toast: der
   Hinweis verlangt eine Entscheidung und darf nicht von selbst verschwinden.
   Uebernimmt bewusst die Glas-Optik der Toasts (gleiche Tokens), damit er
   nicht wie ein Fremdkoerper wirkt. */
.push-prompt{position:fixed;right:22px;bottom:86px;z-index:9001;
  width:330px;max-width:calc(100vw - 44px);padding:14px 15px 12px;
  border-radius:15px;background:var(--glass-popover);
  backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);
  border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-pop);
  color:var(--label)}
.push-prompt[hidden]{display:none}
.push-prompt-title{font-size:14px;font-weight:600;letter-spacing:-.2px;margin-bottom:3px}
.push-prompt-text{font-size:12.5px;line-height:1.5;color:var(--label-secondary)}
.push-prompt-actions{display:flex;gap:7px;justify-content:flex-end;margin-top:11px}
.push-prompt-note{font-size:11.5px;line-height:1.45;color:var(--label-tertiary);
  margin-top:9px;padding-top:8px;border-top:.5px solid var(--hairline-soft)}
/* bottom 86 + right 22 = exakt ueber dem KI-Knopf (fix bei 22/22, 52px hoch)
   und buendig mit dessen rechter Kante. z-index 9001 statt --z-toast (120):
   der Knopf liegt auf 9000 und hat den Hinweis sonst verdeckt.
   Bei geoeffnetem KI-Bereich blendet push-prompt.js den Hinweis aus — der
   Bereich belegt dieselbe Stelle. */
@media (max-width:520px){ .push-prompt{left:14px;right:14px;width:auto} }

.toast-stack{position:fixed;top:14px;right:14px;z-index:var(--z-toast);display:flex;flex-direction:column;gap:8px;pointer-events:none}
.toast{pointer-events:auto;display:flex;align-items:center;gap:9px;min-width:220px;max-width:380px;padding:11px 14px;border-radius:13px;background:var(--glass-popover);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-pop);font-size:13.5px;color:var(--label);
  animation:ds-toast-in .24s var(--spring) both}
.toast .dot{width:8px;height:8px;border-radius:50%;flex:none;background:var(--accent-fill)}
.toast--success .dot{background:var(--green)} .toast--danger .dot{background:var(--red)}
.toast--warning .dot{background:var(--orange)} .toast--info .dot{background:var(--accent-fill)}
.toast.is-leaving{animation:ds-toast-out .25s var(--smooth) forwards}
.push-prompt.is-leaving{animation:ds-toast-out .25s var(--smooth) forwards}
@keyframes ds-toast-in{from{opacity:0;transform:translateY(-10px) scale(.95)}to{opacity:1;transform:none}}
@keyframes ds-toast-out{to{opacity:0;transform:translateY(-8px) scale(.96)}}

/* ── Formular-controls ─────────────────────────────────────────────────── */
.field-group{display:flex;flex-direction:column;gap:6px}
.field-label{font-size:var(--fs-subhead);font-weight:500;color:var(--label-secondary)}
.input,.textarea,.select{width:100%;font:inherit;font-size:14px;color:var(--label);background:var(--fill);border:.5px solid var(--hairline);border-radius:var(--radius-sm);padding:9px 12px;outline:none;transition:border-color var(--dur-fast),box-shadow var(--dur-fast),background var(--dur-fast)}
.input::placeholder,.textarea::placeholder{color:var(--label-tertiary)}
.input:focus,.textarea:focus,.select:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent);background:var(--glass-card)}
.textarea{resize:vertical;min-height:76px;line-height:1.45}
.select{appearance:none;-webkit-appearance:none;cursor:pointer;padding-right:32px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238a8a8e' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 11px center}
.input--sm,.select--sm{padding:6px 10px;font-size:13px}

/* ── Datepicker (datepicker.js) im Liquid-Glass-look ──────────────────────────
   Ersetzt den nativen browser-kalender. JS generiert .dp-*-markup und
   positioniert das popup selbst (position:fixed) — wir geben ihm nur das
   material. Trigger sieht aus wie .input, popup wie .menu. */
.dp-wrap{position:relative;display:block;width:100%}
.dp-trigger{display:flex;align-items:center;gap:8px;width:100%;box-sizing:border-box;font:inherit;font-size:14px;color:var(--label);background:var(--fill);border:.5px solid var(--hairline);border-radius:var(--radius-sm);padding:9px 12px;cursor:pointer;user-select:none;transition:border-color var(--dur-fast),box-shadow var(--dur-fast),background var(--dur-fast)}
.dp-trigger:focus-within{border-color:var(--blue);box-shadow:0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent);background:var(--glass-card)}
.dp-trigger-error{border-color:var(--red)!important}
.dp-icon{color:var(--label-tertiary);display:flex;align-items:center;flex-shrink:0;cursor:pointer;transition:color var(--dur-fast)}
.dp-trigger:focus-within .dp-icon{color:var(--blue)}
.dp-input{flex:1;min-width:0;width:100%;font:inherit;font-size:14px;color:var(--label);background:transparent;border:none;outline:none;padding:0;box-shadow:none}
.dp-input:focus{background:transparent;border-color:transparent;box-shadow:none}
.dp-input::placeholder{color:var(--label-tertiary)}
/* EIN Rahmen: der Rahmen ist der .dp-trigger. Ältere Feldregeln
   (.form-group input, .df-field input, Seitenstile) gaben dem Feld darin
   eigene Fläche, Rand und Höhe — ein weißes Feld im grauen Kasten. */
.dp-trigger .dp-input{background:transparent!important;border:0!important;box-shadow:none!important;padding:0!important;min-height:0!important;height:auto!important;border-radius:0!important}
.dp-error{display:none;font-size:var(--fs-footnote);color:var(--red);margin-top:4px}

.dp-popup{position:fixed;top:0;left:0;z-index:10500;width:278px;padding:12px;border-radius:16px;
  background:var(--glass-popover);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);
  border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-pop);
  opacity:0;transform:translateY(-6px) scale(.96);transform-origin:top center;pointer-events:none;
  transition:opacity .2s var(--smooth),transform .2s var(--spring)}
.dp-popup.dp-above{transform:translateY(6px) scale(.96);transform-origin:bottom center}
.dp-popup.dp-open{opacity:1;transform:none;pointer-events:auto}
.dp-popup-dt{width:430px}
.dp-dt-body{display:flex;gap:10px;align-items:flex-start}
.dp-dt-body .dp-cal{flex:0 0 250px;min-width:0}
.dp-time{display:flex;gap:4px;flex:1 1 auto;min-width:0;border-left:.5px solid var(--hairline);padding-left:10px}
.dp-time-col{flex:1 1 0;min-width:0;max-height:262px;overflow-y:auto;display:flex;flex-direction:column;gap:2px;scrollbar-width:thin}
.dp-time-cell{border:none;background:none;cursor:pointer;font:inherit;font-size:12.5px;color:var(--label);padding:6px 0;border-radius:8px;text-align:center;font-variant-numeric:tabular-nums;transition:background var(--dur-fast),color var(--dur-fast)}
.dp-time-cell:hover:not(.dp-selected){background:var(--fill-strong)}
.dp-time-cell.dp-selected{background:var(--accent-fill);color:#fff;font-weight:600}
/* Glas-zeitpicker (time-only): nur die zwei spalten, ohne datums-grid/divider */
.gtp-popup{width:auto;padding:8px}
.gtp-time{border-left:none;padding-left:0;gap:6px}
.gtp-popup .dp-time-col{flex:0 0 52px;max-height:232px;padding:0 2px}
.gtp-popup .dp-time-cell{padding:7px 0}
/* Glas-autocomplete (ersetzt native datalist) */
.gac-popup{position:fixed;z-index:var(--z-popover);display:none;min-width:160px;max-width:360px;max-height:264px;overflow-y:auto;padding:5px;border-radius:13px;background:var(--glass-popover);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-pop)}
.gac-popup.gac-open{display:block}
.gac-option{display:block;width:100%;text-align:left;border:none;background:none;font:inherit;font-size:13px;color:var(--label);padding:7px 10px;border-radius:8px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gac-option:hover,.gac-option.gac-active{background:var(--row-hover)}

.dp-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
.dp-head-center{font:inherit;font-size:13.5px;font-weight:600;color:var(--label);background:none;border:none;padding:5px 10px;border-radius:8px;cursor:pointer;transition:background var(--dur-fast)}
.dp-head-center:hover{background:var(--fill-strong)}
.dp-year-lbl{color:var(--label-secondary);font-weight:400;margin-left:3px}
.dp-nav{background:none;border:none;cursor:pointer;color:var(--label-tertiary);width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;padding:0;transition:background var(--dur-fast),color var(--dur-fast),transform .2s var(--spring)}
.dp-nav:hover{background:var(--fill-strong);color:var(--label)}
.dp-nav:active{transform:scale(.88)}
.dp-weekdays{display:grid;grid-template-columns:repeat(7,1fr);margin-bottom:2px}
.dp-weekdays span{text-align:center;font-size:10px;font-weight:600;color:var(--label-tertiary);padding:3px 0 5px;letter-spacing:.04em;text-transform:uppercase}
.dp-grid{display:grid;grid-template-columns:repeat(7,1fr)}
.dp-grid-months,.dp-grid-years{grid-template-columns:repeat(3,1fr);gap:6px;padding:4px 0}
.dp-empty{height:34px}
.dp-day,.dp-month,.dp-year{height:34px;border:none;background:none;font:inherit;font-size:12.5px;color:var(--label);cursor:pointer;border-radius:8px;display:flex;align-items:center;justify-content:center;padding:0;position:relative;transition:background var(--dur-fast),color var(--dur-fast),transform .2s var(--spring)}
.dp-month,.dp-year{height:38px}
.dp-day:hover:not(.dp-disabled):not(.dp-selected):not(.dp-range-cap),
.dp-month:hover:not(.dp-selected),.dp-year:hover:not(.dp-selected){background:var(--fill-strong)}
.dp-day:active{transform:scale(.9)}
.dp-day.dp-today::after{content:"";position:absolute;bottom:4px;left:50%;transform:translateX(-50%);width:3px;height:3px;border-radius:50%;background:var(--accent-fill)}
.dp-day.dp-selected,.dp-month.dp-selected,.dp-year.dp-selected,.dp-day.dp-range-cap{background:var(--accent-fill);color:#fff;font-weight:600}
.dp-day.dp-selected.dp-today::after{background:#fff}
.dp-day.dp-in-range{background:color-mix(in srgb,var(--blue) 16%,transparent);border-radius:0;color:var(--blue)}
.dp-day.dp-range-start{border-radius:8px 0 0 8px}
.dp-day.dp-range-end{border-radius:0 8px 8px 0}
.dp-day.dp-disabled{color:var(--label-tertiary);opacity:.35;cursor:not-allowed}

/* ── Modal-Sheet (glas, springt herein; zentriert) ─────────────────────── */
.sheet-backdrop{position:fixed;inset:0;z-index:var(--z-sheet);background:rgba(0,0,0,.35);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:grid;place-items:center;padding:20px;opacity:0;transition:opacity .2s var(--smooth)}
/* WICHTIG: display:grid wuerde das hidden-attribut ueberschreiben — das
   unsichtbare backdrop laege fullscreen ueber der seite und fraesse alle
   klicks (gefunden: theme-toggle auf /tasks nicht klickbar). */
.sheet-backdrop[hidden]{display:none!important}
.sheet-backdrop.is-open{opacity:1}
.sheet{width:min(94vw,520px);max-height:88vh;overflow:auto;border-radius:22px;background:var(--glass-modal);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-pop);
  transform:scale(.93) translateY(14px);opacity:.4;transition:transform .2s var(--spring),opacity .2s var(--smooth)}
.sheet-backdrop.is-open .sheet{transform:none;opacity:1}
.sheet__header{display:flex;align-items:center;justify-content:space-between;padding:18px 20px 12px}
.sheet__title{font-size:var(--fs-title-3);font-weight:var(--fw-title-3);letter-spacing:var(--tr-title-3)}
.sheet__close{width:28px;height:28px;border:none;border-radius:50%;background:var(--fill);color:var(--label-secondary);display:grid;place-items:center;cursor:pointer;outline:none;transition:transform var(--dur) var(--spring),background var(--dur-fast)}
.sheet__close:hover{background:var(--fill-strong)} .sheet__close:active{transform:scale(.88)}
.sheet__body{padding:4px 20px 20px;display:flex;flex-direction:column;gap:14px}
.sheet__actions{display:flex;gap:8px;justify-content:flex-end;padding-top:4px}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media (max-width:520px){.form-grid{grid-template-columns:1fr}}

/* ── Confirm-dialog (glas-sheet, zentriert) ────────────────────────────── */
.dialog-backdrop{position:fixed;inset:0;z-index:var(--z-sheet);background:rgba(0,0,0,.35);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);display:grid;place-items:center;opacity:0;transition:opacity .2s var(--smooth)}
.dialog-backdrop.is-open{opacity:1}
.dialog{width:min(92vw,360px);padding:20px;border-radius:18px;background:var(--glass-modal);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-pop);
  transform:scale(.92) translateY(8px);transition:transform .2s var(--spring)}
.dialog-backdrop.is-open .dialog{transform:none}
.dialog__title{font-size:var(--fs-headline);font-weight:600;letter-spacing:-.3px}
.dialog__message{font-size:var(--fs-callout);color:var(--label-secondary);margin-top:6px;line-height:1.45}
.dialog__actions{display:flex;gap:8px;justify-content:flex-end;margin-top:16px}
/* Eingabefeld im Dialog (appPrompt). Klassenlos gestylt waere es hier falsch —
   der DS setzt Felder ohne Klasse bewusst zurueck, damit zusammengesetzte
   Bedienelemente ihren Rahmen selbst zeichnen. */
.dialog__input{width:100%;margin-top:12px;font:inherit;font-size:var(--fs-callout);
  color:var(--label);background:var(--fill);border:none;border-radius:var(--radius-sm);
  padding:9px 12px;outline:none;box-shadow:inset 0 0 0 .5px var(--hairline-soft)}
.dialog__input:focus{box-shadow:inset 0 0 0 1.5px var(--blue)}
.dialog__input::placeholder{color:var(--label-tertiary)}
.dialog__actions .btn:disabled{opacity:.4;cursor:not-allowed}

/* ── Seiten-Uebergang ──────────────────────────────────────────────────────
   Sanfte Ueberblendung bei jeder same-origin-Navigation. Stand vorher nur in
   main.css — die laden aber bloss 51 der 170 DS-Seiten ueber den
   legacy_css-Block, auf der Mehrheit war der Uebergang also gar nicht
   angemeldet. Hier gilt er ueberall (auch auf den 12 Auth-Seiten, die
   components.css ebenfalls laden).
   Aeltere Safari/Firefox ignorieren die At-Regel stillschweigend. */
@view-transition { navigation: auto; }
::view-transition-old(root),::view-transition-new(root){
  animation-duration:.22s; animation-timing-function:var(--smooth, ease);
  mix-blend-mode:normal}
::view-transition-old(root){z-index:1}
::view-transition-new(root){z-index:2}

/* ── View-Transition (theme-wechsel): kreis-reveal statt default-crossfade ──
   NUR waehrend des Themenwechsels. Vorher galt das animation:none fuer alle
   root-Uebergaenge — und weil Themenwechsel und Navigation dieselben
   Pseudo-Elemente benutzen, erschlug die Regel den Seiten-Uebergang gleich
   mit. ds.js setzt das Attribut fuer die Dauer des Wechsels. */
html[data-vt="theme"]::view-transition-old(root),
html[data-vt="theme"]::view-transition-new(root){animation:none}

/* Seiten-Uebergaenge respektieren prefers-reduced-motion NICHT von allein —
   anders als eine CSS-Animation muss man sie ausdruecklich abschalten. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),::view-transition-new(root){animation:none!important}
}

/* ── Zahl-pop (zaehler-update) ─────────────────────────────────────────── */
.is-pop{display:inline-block;animation:ds-pop .24s var(--spring)}
@keyframes ds-pop{0%{transform:scale(1)}35%{transform:scale(1.16)}100%{transform:scale(1)}}

/* ── Motion: stagger-reveal beim laden ─────────────────────────────────── */
.reveal{opacity:0;transform:translateY(12px) scale(.99);animation:ds-rise var(--dur-slower) var(--spring) forwards}
@keyframes ds-rise{to{opacity:1;transform:none}}
.reveal-1{animation-delay:.03s}.reveal-2{animation-delay:.07s}.reveal-3{animation-delay:.12s}.reveal-4{animation-delay:.17s}.reveal-5{animation-delay:.22s}

/* ═══════════════════════════════════════════════════════════════════════════
   LEGACY-KOMPONENTEN-BRIDGE
   Macht die alten komponenten-klassen der noch-nicht-voll-redesignten seiten
   auf base_ds konsistent (DS-look + richtiges theme). Greift NUR auf alte
   klassennamen — kollidiert nicht mit den DS-klassen (.btn--primary etc.).
   Vollredesign ersetzt diese seiten schrittweise.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Buttons (alt: .btn .btn-primary) — DS-.btn base existiert schon.
   font/padding/radius stehen hier mit drin, weil .btn-primary in der App auch
   ALLEIN vorkommt (z.B. admin/api_quota). Ohne sie erbt so ein <button> die
   Browser-Vorgabe und stand als einziger Arial-Knopf in einer SF-Pro-App. */
.btn-primary{background:var(--accent-fill);color:var(--on-accent);border:none;
  font:inherit;font-size:13px;font-weight:500;border-radius:var(--radius-sm);
  padding:6px 14px;cursor:pointer;
  box-shadow:0 1px 0 rgba(255,255,255,.18) inset,0 1px 2px rgba(0,0,0,.2)}
.btn-primary:hover{filter:brightness(1.06)}
.btn-secondary,.btn-outline{background:var(--fill);color:var(--label);box-shadow:inset 0 0 0 .5px var(--hairline)}
.btn-secondary:hover,.btn-outline:hover{background:var(--fill-strong)}
.btn-ghost{background:none;color:var(--label-secondary);box-shadow:none}
.btn-ghost:hover{background:var(--fill);color:var(--label)}
/* Weisse Schrift braucht die Fuellung, nicht --red selbst: darauf kommt
   sie nur auf 3.4:1 (dunkel) bzw. 3.5:1 (hell). Siehe --danger-fill in
   tokens.css und das Vorbild --accent-fill. */
.btn-danger{background:var(--danger-fill);color:#fff;border:none}
.btn-sm{padding:6px 12px;font-size:13px;border-radius:8px}
.btn-xs{padding:4px 9px;font-size:12px;border-radius:7px}
.btn-lg{padding:11px 20px;font-size:15px}
.text-danger{color:var(--red)} .text-warning{color:var(--warning-fg)} .text-success{color:var(--success-fg)}

/* Badges */
.badge{display:inline-flex;align-items:center;gap:5px;padding:2px 9px;border-radius:var(--radius-pill);font-size:11.5px;font-weight:500;background:var(--fill);color:var(--label-secondary);box-shadow:inset 0 0 0 .5px var(--hairline-soft)}
.badge-primary{background:var(--status-todo-bg);color:var(--status-todo-fg);box-shadow:none}
.badge-success{background:var(--status-done-bg);color:var(--status-done-fg);box-shadow:none}
.badge-warning{background:var(--status-review-bg);color:var(--status-review-fg);box-shadow:none}
.badge-danger{background:color-mix(in srgb,var(--red) 18%,transparent);color:var(--due-overdue);box-shadow:none}
.badge-secondary{background:var(--fill-strong);color:var(--label-secondary);box-shadow:none}
.badge-info{background:var(--status-todo-bg);color:var(--status-todo-fg);box-shadow:none}
.badge-muted{background:var(--fill);color:var(--label-secondary);box-shadow:none}

/* ── Utilities, die bisher nur in main.css lagen → auf DS-Seiten ungestylt ── */
.text-muted{color:var(--text-2)}
.link-muted{color:var(--text-3);text-decoration:none}
.link-muted:hover{color:var(--text-2)}
.avatar-xs{width:22px;height:22px;font-size:9px}
.avatar-sm{width:26px;height:26px;font-size:10px}
.page-title-lg{font-size:26px;font-weight:700;letter-spacing:.01em;line-height:1.2;margin-bottom:3px;color:var(--text)}
.page-header-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.form-row-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px}
.form-actions{display:flex;gap:8px;padding-top:8px}
.form-actions-left{display:flex;gap:8px}
.form-card-body{padding:20px 20px 6px}
.form-page-narrow{max-width:960px}
.empty-state-icon{font-size:36px;opacity:.25;margin-bottom:14px;display:block}
.empty-state-body{font-size:13px;color:var(--text-2);margin-bottom:20px}
@media (max-width:640px){.form-row,.form-row-3{grid-template-columns:1fr}}

/* Formular-controls (alt) */
.form-input,.form-select,.form-textarea,input[type=text].form-control,select.form-control{width:100%;font:inherit;font-size:14px;color:var(--label);background:var(--fill);border:.5px solid var(--hairline);border-radius:var(--radius-sm);padding:9px 12px;outline:none;box-sizing:border-box;transition:border-color var(--dur-fast),box-shadow var(--dur-fast)}
.form-input:focus,.form-select:focus,.form-textarea:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent)}
.form-input::placeholder,.form-textarea::placeholder{color:var(--label-tertiary)}
.form-select{appearance:none;-webkit-appearance:none;cursor:pointer;padding-right:30px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238a8a8e' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center}
/* ── DS-chevron auf ALLEN einzel-<select> (statt nativem OS-pfeil) ────────────
   Greift auch klassenlose selects + .form-group select (die hatten nur bg/border,
   aber appearance:auto → nativer pfeil). Multi-/size-selects bleiben nativ
   (liste muss sichtbar bleiben). Die offene options-liste folgt color-scheme
   (tokens.css setzt dark/light) → konsistent getönt. */
select:not([multiple]):not([size]){
  appearance:none;-webkit-appearance:none;cursor:pointer;padding-right:30px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238a8a8e' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 10px center;
}
/* Klassenlose bare-selects zusätzlich auf DS-feld-look heben */
select:not([multiple]):not([size]):not([class]){
  font:inherit;font-size:14px;color:var(--label);background-color:var(--fill);
  border:.5px solid var(--hairline);border-radius:var(--radius-sm);
  padding-top:9px;padding-bottom:9px;padding-left:12px;outline:none;box-sizing:border-box;
  transition:border-color var(--dur-fast),box-shadow var(--dur-fast);
}
select:not([multiple]):not([size]):not([class]):focus{
  border-color:var(--blue);box-shadow:0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent);
}

/* ── DS-Feld-Floor für JEDEN einzel-<select> + jede such-<input> ──────────────
   Über :where() (Spezifität 0) — greift nur, wo NICHTS anderes stylt, und wird
   von jeder Klasse/jedem Wrapper überschrieben. Damit bekommen auch selects mit
   einer Klasse-ohne-Box und freistehende Suchleisten (außerhalb .form-group /
   ohne Wrapper) den DS-Look, ohne bestehende Styles zu brechen. Der Chevron auf
   den selects kommt bereits aus der Regel oben (select:not([multiple])...). */
:where(select:not([multiple]):not([size])){
  font-family:var(--font-ui);font-size:14px;color:var(--label);
  background-color:var(--fill);border:.5px solid var(--hairline);
  border-radius:var(--radius-sm);min-height:38px;padding-top:8px;padding-bottom:8px;
  padding-left:12px;outline:none;box-sizing:border-box;
  transition:border-color var(--dur-fast),box-shadow var(--dur-fast),background var(--dur-fast);
}
:where(select:not([multiple]):not([size])):focus{
  border-color:var(--blue);background-color:var(--glass-card);
  box-shadow:0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent);
}
:where(input[type=search],input[type=text][role=search]){
  font-family:var(--font-ui);font-size:14px;color:var(--label);
  background:var(--fill);border:.5px solid var(--hairline);border-radius:var(--radius-sm);
  padding:8px 12px;outline:none;box-sizing:border-box;-webkit-appearance:none;appearance:none;
  transition:border-color var(--dur-fast),box-shadow var(--dur-fast),background var(--dur-fast);
}
:where(input[type=search],input[type=text][role=search]):focus{
  border-color:var(--blue);background:var(--glass-card);
  box-shadow:0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent);
}
:where(input[type=search])::placeholder{color:var(--label-tertiary)}

/* Felder mit eigener Fokus-Gestaltung (Rahmen + weicher Schein) schalten den
   globalen :focus-visible-Ring aus main.css ab — sonst liegen zwei Ringe in
   zwei verschiedenen Blautoenen uebereinander (--blue innen, --accent aussen).
   Der Fokus bleibt klar sichtbar, nur eben einmal. */

/* ── Suchfeld ───────────────────────────────────────────────────────────────
   Lag bisher als identische Kopie in SECHS Seiten-Styles und war dort kaum
   sichtbar: der Container nutzte var(--fill), das ueber dem grauen
   Seitenhintergrund rgb(233,235,239) nur rgb(219,221,226) ergibt — ein
   Unterschied von 14 von 255. Der Platzhalter in --label-tertiary kam damit
   auf einen Kontrast von 1,59:1; lesbarer Text braucht 4,5:1.

   Jetzt weiss auf grauer Seite, wie Apple Suchfelder auf gruppierten
   Hintergruenden zeichnet, mit dem kraeftigsten vorhandenen Rahmen-Token und
   --label-secondary im Platzhalter (3,62:1 statt 1,59:1).

   ANMERKUNG: 4,5:1 erreicht das Design-System im hellen Modus mit keinem
   Text-Token ausser --label (16,8:1) — das saehe wie echter Inhalt aus, nicht
   wie ein Hinweis. Wer die Schwelle wirklich treffen will, braucht einen neuen
   Token; das waere eine bewusste Erweiterung, keine Reparatur. */
/* Geometrie EXAKT wie .dropdown (6px 11px, radius 9px, 13px, .5px Rand):
   in jeder Filterleiste stehen beide nebeneinander, und vorher unterschieden
   sie sich in Hoehe (35 zu 30px), Innenabstand, Schriftgroesse UND Randstaerke
   (1px --border-dark gegen .5px --hairline-soft). Nebeneinander lasen sie
   sich als zwei verschiedene Bauteile, nicht als eine Leiste.

   Die weisse Fuellung bleibt — sie ist der Unterschied zwischen Eingabe und
   Knopf und traegt die Lesbarkeit des Platzhalters: --label-secondary kommt
   auf Weiss auf 3,62:1, auf dem grauen --fill der Dropdowns nur auf 2,67:1
   (nachgerechnet). Angleichen ueber die Fuellung waere ein Rueckschritt. */
/* Breite: das Feld waechst in den freien Platz der Leiste, gedeckelt.
   Der Deckel lag bei 320px und war die bindende Grenze — auf der
   Kontaktliste (1280px Fenster, 959px Leiste) blieben daneben 115px
   ungenutzt, waehrend „Neele Förste · Die Bios GmbH" im Feld abgeschnitten
   war. 420px nimmt den freien Platz auf und laesst dem Chip daneben Luft;
   schmalere Fenster regelt weiter flex-shrink. */
.search-field{display:flex;align-items:center;gap:7px;background:var(--surface);
  border-radius:var(--radius-sm);padding:0 var(--ctrl-pad-x);
  box-shadow:inset 0 0 0 .5px var(--hairline-soft);
  flex:1 1 260px;max-width:420px}
.search-field svg{color:var(--label-secondary);flex:none}
.search-field input{border:none;background:none;outline:none;font:inherit;
  font-size:var(--ctrl-font);color:var(--label);padding:var(--ctrl-pad-y) 0;width:100%}
.search-field input::placeholder{color:var(--label-secondary)}
.search-field:focus-within{box-shadow:inset 0 0 0 1px var(--blue),
  0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent)}

/* ── Filterleiste ───────────────────────────────────────────────────────────
   Lag als identische Kopie in ACHT Seiten-Styles (sieben gleich, eine mit
   abweichendem Abstand). Hier einmal, damit neue Seiten sie erben.

   Der zweite Teil ist der eigentliche Punkt: Suchfeld, Auswahlfeld und Knopf
   stehen in dieser Leiste nebeneinander und hatten drei Hoehen (30/33/36px),
   drei Schriftgroessen (13/13.5/14px) und drei Innenabstaende. Nebeneinander
   las sich das als Sammlung fremder Teile — im geteilten Arbeitsplatz, wo
   zwei solche Leisten aneinandergrenzen, doppelt.

   Bewusst NUR innerhalb der Leiste: ein Knopf im Formular darf groesser
   bleiben, dort ist er kein Filter, sondern das Ziel der Seite. */
.tbar{display:flex;align-items:center;gap:10px;margin-bottom:16px;flex-wrap:wrap}
.tbar .btn,.tbar .btn-sm,.tbar button:not(.ap-tab):not(.nav-burger),
.tbar .form-input,.tbar .form-select,.tbar .form-control,
.tbar select,.tbar input[type=text],.tbar input[type=search],.tbar input[type=date]{
  padding:var(--ctrl-pad-y) var(--ctrl-pad-x);
  font-size:var(--ctrl-font);
  border-radius:var(--radius-sm);
  line-height:1.4;
}
/* Das Suchfeld traegt den Innenabstand am Container, nicht am Feld — sonst
   saesse der Text tiefer als im Nachbarn. */
.tbar .search-field{padding:0 var(--ctrl-pad-x)}
.tbar .search-field input{padding:var(--ctrl-pad-y) 0}

/* ── Ein Steuerelement, ein Fokus-Ring ──────────────────────────────────────
   Bündelt ein Container Icon/Knopf/Chips ZUSAMMEN mit einem Eingabefeld zu
   einem Bedienelement (Such-Leisten, Chip-Eingaben, Filterfelder), dann ist
   der CONTAINER das Steuerelement: er trägt Hintergrund, Rahmen und den
   Fokus-Ring (:focus-within). Das klassenlose Feld darin bekam zusätzlich die
   Fallback-Gestaltung für ALLEINSTEHENDE Felder oben — Ergebnis: Rahmen im
   Rahmen und beim Tippen Ring im Ring ("doppelter Rand").

   Greift automatisch über die Struktur, damit es nicht jede Seite einzeln
   mit !important erschlagen muss (vorher: gleiches Problem an fünf Stellen,
   drei verschiedene Lösungen, zwei davon vergessen). Felder MIT eigener
   Klasse bleiben unangetastet — die sind bewusst gestaltet. */
:where(form,div,label,span):has(> svg,> button,> .chip-list,> .icon):has(> :where(input,textarea,select):not([class]))
  > :where(input,textarea):not([class]){
  background-color:transparent;border:none;border-radius:0;padding:0;
  box-shadow:none;outline:none;
}
/* Select genauso — aber background-COLOR statt background, sonst verschwindet
   die Pfeil-Grafik (die steckt als background-image im select-Fallback), und
   padding-right bleibt stehen, damit der Text nicht unter dem Pfeil landet. */
:where(form,div,label,span):has(> svg,> button,> .chip-list,> .icon):has(> :where(input,textarea,select):not([class]))
  > select:not([class]){
  background-color:transparent;border:none;border-radius:0;
  padding-top:0;padding-bottom:0;padding-left:0;box-shadow:none;outline:none;min-width:0;
}
:where(form,div,label,span):has(> svg,> button,> .chip-list,> .icon):has(> :where(input,textarea,select):not([class]))
  > :where(input,textarea,select):not([class]):focus{
  background-color:transparent;border-color:transparent;box-shadow:none;
}

/* ── Chip-Eingabe (Empfänger, Teilnehmer, Tags) ─────────────────────────────
   Lag bisher nur inline in calendar/index.html — dasselbe Markup wird aber
   auch aus _event_modal.html in der Talent-/Social-Kapazitätssicht gerendert,
   wo es dadurch ungestylt blieb. Gehört als geteiltes Bedienelement ins DS. */
.chip-input-wrap{display:flex;flex-wrap:wrap;align-items:center;gap:4px;
  min-height:38px;padding:6px 8px;cursor:text;
  background:var(--fill);border:.5px solid var(--hairline);border-radius:var(--radius-sm);
  transition:border-color var(--dur-fast),box-shadow var(--dur-fast)}
.chip-input-wrap:focus-within{border-color:var(--blue);
  box-shadow:0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent)}
.chip-list{display:contents}
.chip{display:inline-flex;align-items:center;gap:4px;white-space:nowrap;
  padding:2px 8px 2px 10px;border-radius:var(--radius-pill);font-size:12px;
  background:var(--status-todo-bg);color:var(--status-todo-fg)}
.chip-remove{cursor:pointer;font-size:15px;line-height:1;opacity:.6}
.chip-remove:hover{opacity:1}
/* Das Eingabefeld selbst: Rahmen/Ring räumt die Regel für zusammengesetzte
   Steuerelemente oben ab — hier nur Layout. Der zweite :not() hebt die
   Spezifität knapp über jene Regel, damit die Mindestbreite erhalten bleibt
   (sonst kollabiert das Feld neben den Chips auf 0). */
.chip-input-wrap > input:not([class]):not([type=hidden]){
  flex:1;min-width:150px;font-size:13px;padding:2px 0;color:var(--label)}
.chip-input-wrap > input:not([class]):not([type=hidden])::placeholder{color:var(--label-tertiary)}

/* Natives Such-Löschen-Kreuz dezenter (nur wo überhaupt gerendert) */
:where(input[type=search])::-webkit-search-cancel-button{
  -webkit-appearance:none;appearance:none;height:14px;width:14px;cursor:pointer;
  background:var(--label-tertiary);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M18 6 6 18M6 6l12 12'/%3E%3C/svg%3E") center/contain no-repeat;
}
/* Nackte felder in legacy .form-group → DS-feld-look. Sonst rendern sie weiss
   (--surface) + 1px-border, inkonsistent mit den selects/DS-feldern daneben.
   Vereinheitlicht alle legacy-formulare auf die DS-feldsprache (subtiler fill). */
/* .dp-input ausgenommen: das ist das INNERE Feld des Datepickers, dessen
   Rahmen+Ring der .dp-trigger drumherum zeichnet. Ohne die Ausnahme gewinnt
   diese Regel (0,8,1) gegen .dp-input (0,1,0) und jedes Datumsfeld der App
   bekommt Rahmen im Rahmen und beim Tippen Ring im Ring. */
.form-group input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=color]):not([type=submit]):not([type=button]):not(.dp-input),
.form-group select,
.form-group textarea{
  width:100%;font:inherit;font-size:14px;color:var(--label);background:var(--fill);
  border:.5px solid var(--hairline);border-radius:var(--radius-sm);padding:9px 12px;
  outline:none;box-sizing:border-box;
  transition:border-color var(--dur-fast),box-shadow var(--dur-fast),background var(--dur-fast)}
.form-group input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=color]):not([type=submit]):not([type=button]):not(.dp-input):focus,
.form-group select:focus,
.form-group textarea:focus{
  border-color:var(--blue);background:var(--glass-card);
  box-shadow:0 0 0 3.5px color-mix(in srgb,var(--blue) 18%,transparent)}
.form-group input::placeholder,.form-group textarea::placeholder{color:var(--label-tertiary)}
.form-group{margin-bottom:14px}
.form-group>label,.form-label{display:block;font-size:var(--fs-subhead);font-weight:500;color:var(--label-secondary);margin-bottom:6px}

/* ── Detail-/Akte-header + tabs (shared: produktion/podcast/social/internal) ──
   Apple-record-look: grosser SF-large-title auf dem seiten-grund statt flacher
   surface-box, refined underline-tabs, klare status-pill. Lädt nach main.css. */
.project-detail-header{
  background:var(--glass-card);
  -webkit-backdrop-filter:var(--glass-blur-card);
  backdrop-filter:var(--glass-blur-card);
  border:.5px solid var(--hairline);
  border-radius:var(--radius-lg);
  box-shadow:var(--specular),var(--shadow-sm);
  padding:16px 22px 14px;
  margin-bottom:20px;
  /* spalte: identität (titel volle breite) oben, dann eine kompakte meta-bar
     (links + kennzahlen) hairline-getrennt darunter — App-Store-style */
  flex-direction:column;
  align-items:stretch;
  gap:0;
}
/* Der glas-hero bildet via backdrop-filter einen eigenen Stacking-Kontext
   (z-index:auto = Ebene 0). Ein offenes Teilen-/Zugriff-Popover ist darin
   gefangen und wuerde vom spaeteren Tab-Inhalt (kpi-cards etc.) uebermalt.
   Solange ein Popover offen ist, heben wir den Header-Kontext ueber den
   Tab-Inhalt (unter Sheets/Toasts). Siehe projects/_share_panel.html. */
.project-detail-header:has(.sp-panel-open){position:relative;z-index:var(--z-popover)}
/* Eine Vorschlagsliste in einer .card wurde am Kartenrand abgeschnitten: .card
   traegt overflow:hidden (Zeile 227), und Ueberlauf wird unabhaengig von der
   Stapelebene beschnitten — das z-index:50 der Liste half darum nichts. Dazu
   macht das backdrop-filter derselben Karte einen eigenen Stapelkontext auf, in
   dem die Liste gefangen bleibt; die naechste Karte malte darueber.
   Beides wird nur angehoben, SOLANGE die Liste offen ist. Dauerhaft
   overflow:visible naehme der Karte ihre abgerundete Beschneidung.
   Dieselbe Mechanik wie eine Zeile darueber, nur fuer Vorschlagslisten. */
.card:has(.ac-liste:not([hidden])){overflow:visible;position:relative;z-index:var(--z-popover)}
.pdh-identity{min-width:0;flex:1 1 280px}
/* Hero-kopfzeile: identität links, inhalts-aktionen rechts oben (App-Store) */
.pdh-top{display:flex;align-items:flex-start;justify-content:space-between;gap:12px 18px;flex-wrap:wrap}
.pdh-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end;flex-shrink:0}
/* Zurück-link oben IM hero (statt in der page-bar) */
.pdh-back{display:inline-flex;align-items:center;gap:5px;align-self:flex-start;color:var(--label-secondary);text-decoration:none;font-size:13px;font-weight:500;margin-bottom:10px;transition:color var(--dur-fast)}
.pdh-back:hover{color:var(--label)}
.pdh-back svg{flex-shrink:0}
/* Meta-bar: links links, kennzahlen rechts, eine kompakte zeile */
.proj-hero-bar{
  display:flex;align-items:center;flex-wrap:wrap;
  gap:10px 20px;width:100%;
  margin-top:13px;padding-top:12px;
  border-top:.5px solid var(--hairline-soft);
}
/* ── Kennzahlen kompakt am rechten rand ── */
.proj-hero-metrics{
  flex-shrink:0;
  margin-left:auto;
  display:flex;
  align-items:stretch;
}
.phm-cell{
  display:flex;flex-direction:column;justify-content:center;gap:2px;
  padding:0 15px;min-width:0;
  border-left:.5px solid var(--hairline-soft);
}
.phm-cell:first-child{padding-left:15px}
.phm-cell:last-child{padding-right:2px}
.phm-label{font-size:10.5px;font-weight:500;color:var(--label-tertiary);white-space:nowrap}
.phm-value{font-size:16px;font-weight:600;color:var(--label);letter-spacing:-.01em;line-height:1.15;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.phm-value-sm{font-size:14px;font-weight:600}
.phm-unit{font-size:11px;font-weight:500;color:var(--label-secondary)}
.phm-sub{font-size:10.5px;color:var(--label-tertiary);white-space:nowrap}
.phm-danger{color:var(--red)!important}
.phm-warn{color:var(--warning-fg)!important}
.phm-bar{height:2px;border-radius:1px;background:var(--fill-strong);margin-top:5px;max-width:56px;overflow:hidden}
.phm-bar-fill{height:100%;border-radius:1px;background:var(--accent-fill);transition:width .4s var(--smooth)}
.phm-avatars{display:flex;gap:2px;margin-top:4px}
/* Integrations-links als kompakte chips im hero */
.proj-hero-links{display:flex;align-items:center;gap:7px;flex-wrap:nowrap;flex-shrink:0}
.hero-link-chip{
  display:inline-flex;align-items:center;gap:5px;
  font-size:11.5px;font-weight:500;color:var(--label-secondary);text-decoration:none;
  background:var(--fill);border:.5px solid var(--hairline);border-radius:7px;
  padding:3px 9px;cursor:pointer;font-family:var(--font-ui);line-height:1.4;
  transition:background var(--dur-fast),color var(--dur-fast);
}
.hero-link-chip:hover{background:var(--fill-strong);color:var(--label)}
.hero-link-chip svg{flex-shrink:0;opacity:.65}
/* NAS-Ordner im Finder oeffnen: die smb://-Adresse ist eine Mount-Anweisung,
   die nur macOS versteht. Der Knopf steht ueberall im HTML, wird aber erst
   sichtbar, wenn ds.js einen Mac bestaetigt (`is-mountable`) — auf iPhone,
   Android und Windows bliebe ein Klick sonst folgenlos. Die eigene
   Anzeigeform der Klasse (chip oder Knopf) bleibt dabei unberuehrt: die
   Regel greift nur im ausgeblendeten Zustand. */
[data-nas-mount]:not(.is-mountable){display:none}
/* Ausrichtung von Symbol und Beschriftung. Bewusst an `.is-mountable`
   gehaengt und nicht an das Attribut allein: beide Regeln haben dieselbe
   Gewichtung und schliessen einander aus, damit keine von beiden die
   andere ueberstimmt (und kein !important noetig wird). */
[data-nas-mount].is-mountable{display:inline-flex;align-items:center}
/* .btn bringt keinen Abstand zwischen Symbol und Beschriftung mit. Die Chip-
   und Link-Klassen dagegen schon — deren Wert bleibt unangetastet. */
.btn[data-nas-mount]{gap:6px}
.project-detail-title{
  font-size:22px;
  font-weight:600;
  letter-spacing:-.02em;
  color:var(--label);
  line-height:1.2;
}
.project-detail-meta{
  font-size:13.5px;
  color:var(--label-secondary);
  margin-top:6px;
  display:flex;align-items:center;gap:7px;flex-wrap:wrap;
}
/* Status-pill: borderlos, dezent, beide themes lesbar */
.proj-status{
  padding:3px 11px 3px 9px;
  border:none;
  font-size:12px;font-weight:600;letter-spacing:normal;
}
/* Tab-bar: refined Apple underline-tabs */
.proj-tab-bar{
  border-bottom:.5px solid var(--hairline);
  margin-bottom:22px;
  gap:1px;
}
.proj-tab-btn{
  padding:9px 14px;
  font-size:13.5px;
  font-weight:500;
  font-family:var(--font-ui);
  color:var(--label-secondary);
  border-bottom:2px solid transparent;
  margin-bottom:-1px;
  transition:color var(--dur-fast),border-color var(--dur-fast);
}
.proj-tab-btn:hover{color:var(--label)}
.proj-tab-btn.active{color:var(--label);border-bottom-color:var(--blue)}
.proj-tab-gear-btn{color:var(--label-tertiary);border-radius:var(--radius-sm)}
.proj-tab-gear-btn:hover{color:var(--label);background:var(--fill)}
.proj-tab-gear-btn.has-tabs{color:var(--blue)}

/* Tabellen (alt) */
.table,.data-table{width:100%;border-collapse:collapse}
.table thead th,.data-table thead th{text-align:left;font-size:var(--fs-caption);color:var(--label-tertiary);font-weight:600;padding:9px 12px;border-bottom:.5px solid var(--hairline);white-space:nowrap}
.table tbody td,.data-table tbody td{padding:10px 12px;border-top:.5px solid var(--hairline-soft);font-size:13.5px;color:var(--label-secondary);vertical-align:middle}
.table tbody tr:hover,.data-table tbody tr:hover{background:var(--row-hover)}
.data-table-wrap{background:var(--glass-card);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);border-radius:var(--radius-lg);box-shadow:var(--specular),var(--shadow-card);overflow:hidden}

/* Card-subkomponenten (DS-.card existiert schon als glas) */
.card-header,.card-header-inline{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 16px 10px}
.card-header h3,.card-title-sm{font-size:var(--fs-headline);font-weight:600;letter-spacing:-.2px;color:var(--label);margin:0}
.card-body{padding:0 16px 14px}

/* Seiten-/section-header + filter-bar + empty-state (alt) */
.page-header,.section-header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:18px;flex-wrap:wrap}
.page-title,.section-title{font-size:var(--fs-large-title);font-weight:var(--fw-large-title);letter-spacing:var(--tr-large-title);color:var(--label);margin:0}
.page-subtitle{font-size:var(--fs-subhead);color:var(--label-secondary);margin:2px 0 0}
.filter-bar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:16px}
.empty-state,.empty-state-full{text-align:center;padding:48px 24px;color:var(--label-tertiary)}
.empty-state-title{font-size:15px;font-weight:600;color:var(--label-secondary);margin-bottom:4px}

/* KPI / stat-cards (alt) */
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px}
.kpi-grid-3{grid-template-columns:repeat(3,1fr)}
.kpi-card{display:flex;align-items:center;gap:14px;padding:16px 18px;background:var(--glass-card);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);border-radius:var(--radius-lg);box-shadow:var(--specular),var(--shadow-card)}
.kpi-icon{width:42px;height:42px;border-radius:11px;display:flex;align-items:center;justify-content:center;flex:none}
.kpi-label{font-size:12px;color:var(--label-tertiary)}
.kpi-value{font-size:22px;font-weight:700;color:var(--label);font-variant-numeric:tabular-nums;line-height:1.1}

/* Modals (alt: .modal-overlay > .modal) — als glas-overlay */
.modal-overlay{position:fixed;inset:0;z-index:var(--z-sheet);background:rgba(0,0,0,.4);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:none;align-items:center;justify-content:center;padding:20px}
.modal{background:var(--glass-modal);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);border-radius:16px;box-shadow:var(--specular),var(--shadow-pop);width:100%;max-width:520px;max-height:90vh;display:flex;flex-direction:column;overflow:hidden}
.modal-sm{max-width:400px} .modal-lg{max-width:760px}
.modal-header{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:15px 18px;border-bottom:.5px solid var(--hairline)}
.modal-header h2,.modal-header h3,.modal-title{font-size:var(--fs-headline);font-weight:600;margin:0;color:var(--label)}
.modal-body{padding:18px;overflow-y:auto;flex:1}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 18px;border-top:.5px solid var(--hairline)}
.modal-close{background:none;border:none;color:var(--label-tertiary);font-size:21px;line-height:1;cursor:pointer;padding:2px 7px;border-radius:7px;transition:background var(--dur-fast),color var(--dur-fast)}
.modal-close:hover{background:var(--fill-strong);color:var(--label)}

/* ── Benachrichtigungen (notif-bell + portaliertes panel) ──────────────────── */
.notif-bell{position:relative}
.notif-badge{position:absolute;top:-3px;right:-3px;min-width:16px;height:16px;padding:0 4px;border-radius:var(--radius-pill);background:var(--red);color:#fff;font-size:10px;font-weight:700;display:none;align-items:center;justify-content:center;box-shadow:0 0 0 2px var(--glass-chrome)}
.notif-panel{position:fixed;top:auto;right:auto;bottom:112px;left:12px;width:340px;max-width:calc(100vw - 24px);max-height:70vh;z-index:var(--z-toast);display:flex;flex-direction:column;border-radius:16px;background:var(--glass-popover);backdrop-filter:var(--glass-blur-card);-webkit-backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);box-shadow:var(--specular),var(--shadow-pop);opacity:0;transform:scale(.96) translateY(6px);transform-origin:bottom left;pointer-events:none;transition:opacity .2s var(--smooth),transform .2s var(--spring)}
.notif-panel.open{opacity:1;transform:none;pointer-events:auto}
.notif-header{display:flex;align-items:center;justify-content:space-between;padding:13px 16px 10px;border-bottom:.5px solid var(--hairline)}
.notif-header span{font-size:14px;font-weight:600;color:var(--label)}
.notif-allread{background:none;border:none;font:inherit;font-size:12.5px;color:var(--blue);cursor:pointer;padding:2px 4px;border-radius:6px}
.notif-allread:hover{background:var(--fill)}
.notif-list{overflow-y:auto;padding:5px}
.notif-empty{padding:28px 14px;text-align:center;font-size:13px;color:var(--label-tertiary)}
.notif-item{display:flex;gap:11px;padding:10px 11px;border-radius:11px;cursor:pointer;transition:background var(--dur-fast)}
.notif-item:hover{background:var(--fill);padding-left:11px}
.notif-item.unread{background:color-mix(in srgb,var(--blue) 9%,transparent)}
.notif-item.unread:hover{background:color-mix(in srgb,var(--blue) 14%,transparent)}
.notif-icon{width:32px;height:32px;border-radius:9px;background:var(--fill-strong);display:grid;place-items:center;color:var(--label-secondary);flex:none}
.notif-icon svg{width:16px;height:16px}
.notif-body{flex:1;min-width:0}
.notif-text{font-size:13px;color:var(--label);line-height:1.35}
.notif-time{font-size:11px;color:var(--label-tertiary);margin-top:2px}
/* Fortschritt einer laufenden Drive-Übertragung. Die Balken aus main.css
   (.progress-bar-wrap) stehen hier nicht zur Verfügung — main.css ist
   opt-in, die Glocke steht auf JEDER Seite. */
.notif-prog{height:4px;margin-top:6px;border-radius:var(--radius-pill);background:var(--fill-strong);overflow:hidden}
.notif-prog>i{display:block;height:100%;border-radius:var(--radius-pill);background:var(--blue);transition:width .3s var(--smooth)}
.notif-rsvp{display:flex;gap:6px;margin-top:8px}
.btn-rsvp{font:inherit;font-size:12px;font-weight:500;padding:4px 12px;border-radius:8px;border:none;cursor:pointer}
.btn-accept{background:var(--accent-fill);color:#fff} .btn-decline{background:var(--fill-strong);color:var(--label-secondary)}
.notif-rsvp-done{margin-top:8px;font-size:12px;color:var(--status-done-fg)}

/* ═══════════════════════════════════════════════════════════════════════════
   APPLE-VOICE-OVERRIDE für gebrückte seiten

   HIER GEHOERT NUR HINEIN, WAS DER HEAD-BLOCK NICHT ERREICHT. Der arbeitet
   mit Teilstrings — `[class*="label"]`, `[class*="-title"]`, `table th` —,
   deshalb braucht KEINE Klasse mit „label" oder „-title" im Namen einen
   Eintrag hier. Am 27.09.2026 standen elf Klassen in dieser Liste, die in
   keiner Vorlage und in keinem Skript vergeben werden (.deal-summary-label,
   .demo-label, .fin-shared-kpi-label, .finance-stat-label, .kalkulation-table,
   .nav-section-label, .page-toolbar-label, .pipeline-col-title, .pp-label,
   .sm-hero-stat-label, .social-stat-label). Ein Selektor auf eine nie
   vergebene Klasse scheitert lautlos: er kostet nichts, behauptet aber
   Deckung. Entfernt — und falls eine von ihnen je zurueckkehrt, faengt der
   Head-Block sie ohnehin, denn alle elf tragen „label", „-title" oder sind
   eine Tabelle.
   main.css gibt vielen labels/headern text-transform:uppercase + Geist-Mono
   ("Caps-Mono-Voice"). Apple HIG: Title Case + SF. Da components.css NACH
   main.css laedt (legacy_css), gewinnt dieser override. Template-text ist
   bereits Title Case -> "SALES-DEALS" wird automatisch "Sales-Deals".
   Kalender-wochentags-kuerzel (MO/DI) bleiben bewusst uppercase (Apple-style).
   ═══════════════════════════════════════════════════════════════════════════ */
.kpi-label,.stat-label,.detail-label,.section-label,.an-kpi-label,.an-section-label,.form-card-strip-label,.kalpl-kpi-label,.kalpl-footer-label,.th-kpi-label,
.mhub-payday-label,.payday-label,
.entity-picker-group-label,.legend-title,.kanban-col-title,.sm-cal-post-type,
.table th,.data-table th,.an-table th,.kalpl-table th,
.capacity-table thead th,.user-type-badge,.ao-toggle,.tab-gear-popover-header,
/* finance-bereich: eigene mono/uppercase-voice → SF Title Case (alle finance-seiten) */
.fin-sh-title,.fin-tbl th,.fin-stat-label,.fin-status,.fp-shared-kpi-label,.txn-filter-label,.fc-card-label,.fc-table thead th,
.bv-table thead th{
  text-transform:none!important;
  font-family:var(--font-ui)!important;
  letter-spacing:normal!important;
}
/* ── AUSNAHME: die Belegvorschau ist PAPIER, nicht App ──────────────────────
   `.inv-preview-doc` ist das weisse Blatt in den Formularen fuer Rechnung,
   Angebot und Bestellung (background:#fff, color:#1a1a1a, Helvetica Neue) —
   es zeigt, wie das Dokument beim Kunden aussieht. Der echte Beleg setzt
   seinen Tabellenkopf auf uppercase (templates/finance/pdf/invoice.html:149,
   quote.html:153, po.html:53), und die drei Vorschauen erklaeren genau
   dasselbe.

   Der Apple-Voice-Override oben hatte `.ipv-items thead th` in seiner Liste,
   und der Head-Block von base_ds.html trifft mit dem pauschalen `table th`
   ohnehin jede Tabelle. Damit stand im Formular „Beschreibung", waehrend beim
   Kunden „BESCHREIBUNG" ankam: die Vorschau log ueber das Dokument.

   Diese Regel gewinnt ueber BEIDE, weil sie spezifischer ist (0,2,2 gegen
   0,1,2 und 0,0,2) — nicht wegen der Ladereihenfolge. Wer `.ipv-items`
   wieder in eine Voice-Liste aufnimmt, macht
   tests/test_ds_stimme.py::TestPapierVorschau rot. */
.inv-preview-doc .ipv-items thead th{
  text-transform:uppercase!important;
  letter-spacing:.08em!important;
  font-family:'Helvetica Neue',Arial,sans-serif!important;
}

/* Tab-gear-popover (+ Tab / + Eigene Tabelle) auf DS-glas (legacy main.css war solid).
   WICHTIG: eigene regel — NICHT an die label-liste oben hängen, sonst erben alle
   labels den popover-hintergrund (war ein bug). */
.tab-gear-popover{background:var(--glass-popover);-webkit-backdrop-filter:var(--glass-blur-card);backdrop-filter:var(--glass-blur-card);border:.5px solid var(--hairline);border-radius:13px;box-shadow:var(--specular),var(--shadow-pop)}
.tab-gear-option{border-radius:8px}
/* labels: Apple-eyebrow = sekundär, normal-gewicht (kein mono-fett) */
.kpi-label,.stat-label,.detail-label,.section-label,.finance-stat-label,
.an-kpi-label,.deal-summary-label,.form-card-strip-label,.kalpl-kpi-label,
.th-kpi-label,.social-stat-label,.sm-hero-stat-label,.pp-label,
.nav-section-label,.page-toolbar-label{
  font-weight:500!important;color:var(--label-secondary)!important;
}
/* sektions-überschriften: Title Case Headline statt Caps-Mono */
.section-title,.form-section-title,.card-header h2,.card-header h3,
.mhub-card-title,.card-title-sm{
  text-transform:none!important;font-family:var(--font-ui)!important;
  letter-spacing:-.2px!important;font-weight:600!important;color:var(--label)!important;
}
/* tabellen-header: Apple-stil = Title Case, sekundär, normal */
.table th,.data-table th,.an-table th,.kalkulation-table th,.kalpl-table th,
.capacity-table thead th{font-weight:600!important;color:var(--label-tertiary)!important}

/* ── Responsive: Off-canvas-sidebar (B) ────────────────────────────────────
   Unter 900px wird die sidebar zur eingeschobenen overlay-leiste; ein fixed
   hamburger oben links toggelt sie, ein backdrop dimmt den inhalt. */
.nav-burger{display:none}
.nav-backdrop{display:none}
@media (max-width:900px){
  .app{grid-template-columns:1fr}
  .sidebar{
    position:fixed;top:0;left:0;bottom:0;height:100vh;width:min(82vw,280px);z-index:100;
    transform:translateX(-100%);transition:transform .2s var(--spring);
    box-shadow:0 0 50px rgba(0,0,0,.35);will-change:transform;
  }
  html.nav-open .sidebar{transform:none}
  .nav-backdrop{
    display:block;position:fixed;inset:0;z-index:99;background:rgba(0,0,0,.45);
    opacity:0;pointer-events:none;transition:opacity .2s;
  }
  html.nav-open .nav-backdrop{opacity:1;pointer-events:auto}
  .nav-burger{
    display:inline-flex;position:fixed;top:11px;left:11px;z-index:101;
    width:40px;height:40px;align-items:center;justify-content:center;
    border-radius:11px;background:var(--glass-chrome);
    -webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);
    border:.5px solid var(--hairline);box-shadow:var(--specular);
    color:var(--label);cursor:pointer;
  }
  .nav-burger:active{transform:scale(.94)}
  /* schmaleres seiten-padding + platz für den fixed-burger */
  .content{padding-top:62px;padding-left:var(--sp-8);padding-right:var(--sp-8)}

  /* fixe 3er-stat-grids → 2 spalten (schlägt main.css' !important per source-order) */
  .kpi-grid-3{grid-template-columns:repeat(2,1fr)!important}

  /* detail-hero: aktionen unter die identität, links & voll statt rechtsbündig
     gequetscht — hält u.a. die projektnummer-badge sichtbar */
  .pdh-top{flex-direction:column;align-items:stretch}
  .pdh-actions{justify-content:flex-start}

  /* daten-dichte DS-listen (.thd + .crow/.trow): horizontal im card scrollen
     statt die ganze seite breit zu machen. !important schlägt das inline
     overflow:visible einzelner list-cards. */
  .card:has(.thd),.tcard:has(.thd){overflow-x:auto!important;-webkit-overflow-scrolling:touch}
  .card:has(.thd) .thd,.card:has(.thd) .crow,.card:has(.thd) .trow,
  .tcard:has(.thd) .thd,.tcard:has(.thd) .crow,.tcard:has(.thd) .trow{min-width:560px}

  /* Kopfzeilen-Aktionen umbrechen lassen. Sie standen in EINER nicht
     umbrechenden Reihe mit flex-shrink:0 — auf /finanzen waren das 729px
     Knöpfe in einem 375px-Fenster, und die ganze Seite liess sich seitlich
     schieben. Der Laufzeit-Audit fand das auf 30 Seiten.
     margin-left bleibt bei breiten Fenstern rechtsbuendig (Regel oben). */
  .page-bar{flex-direction:column;align-items:stretch;min-width:0}
  .page-bar__title,.page-bar__actions{min-width:0;max-width:100%}
  .page-bar__actions{flex-wrap:wrap;margin-left:0;padding-top:0}

  /* Aufklapp-Menues nach LINKS oeffnen. Sie haengen an rechtsbuendigen
     Knoepfen; mit dem Standard-left:0 ragten sie ueber den rechten Rand
     hinaus, vergroesserten die Scrollbreite des Dokuments und waren zur
     Haelfte nicht erreichbar. .menu--right macht genau das schon — auf
     schmalen Schirmen gilt es fuer alle. */
  .menu{left:auto;right:0;transform-origin:top right}

  /* Breite Tabellen scrollen in ihrer eigenen Box statt die Seite zu dehnen.
     Gilt fuer die Legacy-Tabellen ohne .data-table-responsive-Huelle. */
  .content table{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
}

/* ── Responsive: phone-feinschliff ─────────────────────────────────────────── */
@media (max-width:560px){
  .content{padding-top:58px}
  .page-bar{margin-bottom:var(--sp-6)}
  .page-bar__title.t-large-title{font-size:25px;line-height:1.15}
  .kpi-grid-3{grid-template-columns:1fr!important}
}

/* ── Micro-Interaktionen (Timer-Sprache: Spring-Pop, Glow-Flash, Slide-in) ──── */
@keyframes ds-pop        { 0%{transform:scale(1)} 34%{transform:scale(var(--ds-pop-scale,1.16))} 100%{transform:scale(1)} }
@keyframes ds-saved      { 0%{background:color-mix(in srgb,var(--green) 13%,transparent)} 100%{background:transparent} }
@keyframes ds-saved-ring { 0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--green) 55%,transparent)} 70%{box-shadow:0 0 0 7px transparent} 100%{box-shadow:0 0 0 0 transparent} }
@keyframes ds-slide-in   { 0%{opacity:0;transform:translateY(8px) scale(.985)} 100%{opacity:1;transform:translateY(0) scale(1)} }
.ds-pop         { animation: ds-pop .24s var(--spring, cubic-bezier(.34,1.56,.64,1)); }
.ds-saved       { animation: ds-saved 1s var(--smooth, ease); }
tr.ds-saved > td { animation: ds-saved 1s var(--smooth, ease); }   /* Flash auf Tabellenzeilen */
.ds-saved-ring  { animation: ds-saved-ring .9s var(--smooth, ease); }
.ds-slide-in    { animation: ds-slide-in .24s var(--spring, cubic-bezier(.34,1.56,.64,1)); }
.ds-removing    { opacity: 0 !important; transition: opacity .2s var(--smooth, ease) !important; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .ds-pop,.ds-saved,.ds-saved-ring,.ds-slide-in { animation: none !important; }
  /* ds-rise fehlte hier — wer Bewegung abgeschaltet hat, bekam sie trotzdem.
     Wichtig: NICHT nur animation:none. .reveal startet mit opacity:0 und
     transform; ein blosses Abschalten liesse den Inhalt dauerhaft
     unsichtbar — schlimmer als die Animation. Endzustand also explizit. */
  .reveal { animation: none !important; opacity: 1 !important; transform: none !important; }
}

/* ── Kontakt-Schnellerfassung ─────────────────────────────────────────────
   Ein Feld, in das ein ganzer Name, eine Adresse oder ein Signaturblock
   fliegt; die Einzelfelder darunter fuellen sich sichtbar. Nichts passiert
   still: was uebernommen wurde, steht im Bericht, und jedes Feld bleibt
   von Hand aenderbar. Nutzt ausschliesslich bestehende Tokens. */
.ct-smart { margin-bottom: 16px; }
.ct-smart__field { min-height: 62px; }
.ct-smart__row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 8px;
}
.ct-smart__hint { font-size: var(--fs-caption); color: var(--label-tertiary); }
.ct-smart__report,
.ct-smart__dup {
  margin-top: 10px; padding: 9px 11px;
  border-radius: var(--radius-md);
  font-size: var(--fs-footnote); line-height: 1.45;
}
.ct-smart__report {
  background: color-mix(in srgb, var(--green) 10%, transparent);
  border: .5px solid color-mix(in srgb, var(--green) 32%, transparent);
}
.ct-smart__report--leer {
  background: var(--fill);
  border: .5px solid var(--hairline);
}
.ct-smart__dup {
  background: color-mix(in srgb, var(--orange) 12%, transparent);
  border: .5px solid color-mix(in srgb, var(--orange) 35%, transparent);
}
.ct-smart__title { display: block; font-weight: 600; margin-bottom: 3px; }
.ct-smart__note { display: block; margin-top: 4px; color: var(--label-secondary); }
.ct-smart__dup a { color: inherit; text-decoration: underline; }

/* ── CRM-Mail-Verlauf (Unternehmen, Vertriebs-Deal, Kooperation) ──────────
   Eine Darstellung fuer alle drei Seiten. Vorher stand dort entweder eine
   Tabelle mit dem rohen From-Header oder eine einzeilige Liste nur mit
   Betreff. Nutzt ausschliesslich bestehende Tokens; die Knoepfe sind die
   normalen .btn-ghost.btn-sm. */
.crm-mails__head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 10px;
}
.crm-mails__title { font-size: var(--fs-headline); font-weight: var(--fw-headline); letter-spacing: var(--tr-headline); }
.crm-mails__count { font-variant-numeric: tabular-nums; }
.crm-mails__hint { font-size: var(--fs-caption); color: var(--label-tertiary); }
/* Hinweise der Karte: warum sie leer ist, warum gekappt wurde. Kein eigenes
   Warn-Aussehen erfunden — dieselbe Fussnoten-Sprache wie .crm-mails__leer,
   nur als Liste. */
.crm-mails__notes {
  list-style: none; margin: 0 0 10px; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.crm-mails__notes li {
  font-size: var(--fs-footnote); color: var(--label-secondary);
  padding-left: 13px; position: relative;
}
.crm-mails__notes li::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: 5px; height: 5px; border-radius: var(--radius-pill);
  background: var(--orange);
}
.crm-mails__list { list-style: none; margin: 0; padding: 0; }
.crm-mail { padding: 12px 0; border-top: .5px solid var(--hairline); }
.crm-mail:first-child { border-top: 0; padding-top: 0; }
.crm-mail__row { display: flex; gap: 11px; align-items: flex-start; }
.crm-mail__avatar {
  width: 30px; height: 30px; flex: none;
  border-radius: var(--radius-pill);
  background: var(--fill); color: var(--label-secondary);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-caption); font-weight: 600;
}
.crm-mail--raus .crm-mail__avatar {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
}
.crm-mail__main { min-width: 0; flex: 1; }
.crm-mail__line { display: flex; align-items: baseline; gap: 10px; }
.crm-mail__from {
  font-size: var(--fs-subhead); font-weight: 600;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crm-mail__dir { color: var(--label-tertiary); font-weight: 400; }
.crm-mail__date {
  margin-left: auto; flex: none;
  font-size: var(--fs-caption); color: var(--label-tertiary);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.crm-mail__subject {
  display: block; margin-top: 1px;
  font-size: var(--fs-callout); font-weight: 600; color: var(--label);
  text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crm-mail__subject:hover { color: var(--accent); }
.crm-mail__snippet {
  margin-top: 2px;
  font-size: var(--fs-footnote); color: var(--label-secondary);
  line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crm-mail__atts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.crm-mail__att {
  display: inline-flex; align-items: center; gap: 5px;
  max-width: 100%;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  background: var(--fill); color: var(--label-secondary);
  font-size: var(--fs-caption); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crm-mail__att:hover { background: var(--fill-strong); color: var(--label); }
.crm-mail__actions {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px;
  margin-top: 7px;
}
.crm-mail__tag {
  font-size: var(--fs-caption); color: var(--label-tertiary);
  padding: 2px 8px; border-radius: var(--radius-pill); background: var(--fill);
}
.crm-mail__body {
  margin: 10px 0 2px 41px;
  padding: 12px 14px;
  border: .5px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--fill);
  font-size: var(--fs-footnote); line-height: 1.5;
  max-height: 460px; overflow: auto;
}
.crm-mail__body img { max-width: 100%; height: auto; }
.crm-mail__body table { max-width: 100%; }
.crm-mail__plain {
  margin: 0; white-space: pre-wrap; word-break: break-word;
  font-family: var(--font-ui); font-size: var(--fs-footnote);
}
.crm-mail__note { margin: 8px 0 0; color: var(--label-tertiary); font-size: var(--fs-caption); }
.crm-mails__leer { color: var(--label-tertiary); font-size: var(--fs-footnote); margin: 0; }

/* ── CRM-Aktivitaeten auf der Unternehmensseite ───────────────────────────
   Der Strom laeuft ueber ALLE Vertriebs-Deals der Firma; jede Zeile traegt
   deshalb den Deal, zu dem sie gehoert. */
.crm-akt { display: flex; gap: 11px; padding: 11px 0; border-top: .5px solid var(--hairline); }
.crm-akt:first-child { border-top: 0; padding-top: 0; }
.crm-akt__icon {
  width: 26px; height: 26px; flex: none;
  border-radius: var(--radius-pill); background: var(--fill);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-footnote);
}
.crm-akt__main { min-width: 0; flex: 1; }
.crm-akt__title { font-size: var(--fs-callout); font-weight: 600; }
.crm-akt__text {
  margin-top: 2px; font-size: var(--fs-footnote); color: var(--label-secondary);
  line-height: 1.45; white-space: pre-wrap; word-break: break-word;
}
.crm-akt__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin-top: 5px;
  font-size: var(--fs-caption); color: var(--label-tertiary);
  font-variant-numeric: tabular-nums;
}
.crm-akt__deal { color: var(--accent); text-decoration: none; font-weight: 600; }
.crm-akt__deal:hover { text-decoration: underline; }
.crm-akt__due { color: var(--label-secondary); }
.crm-akt__due--spaet { color: var(--due-overdue); }
.crm-akt--erledigt .crm-akt__title { text-decoration: line-through; color: var(--label-tertiary); }
.crm-akt__check {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 6px; font-size: var(--fs-caption); color: var(--label-secondary);
}
.crm-akt-neu { margin-bottom: 14px; }
.crm-akt-neu__tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 8px; }
.crm-akt-neu__zeile { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.crm-akt-neu__zeile > input[type="text"] { flex: 1; min-width: 180px; }
.crm-akt-neu__faellig {
  margin-top: 8px; display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
}
/* „Noch zu erledigen" — gleiche Stimme wie der Abhak-Haken in der Zeile
   darunter, damit Anlegen und Abhaken erkennbar dasselbe meinen. */
.crm-akt-neu__aufgabe {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-caption); color: var(--label-secondary); cursor: pointer;
}

/* ═══════════════════════════════════════════════════════════════════
   Icon-Gewicht — ein System statt zwölf
   ═══════════════════════════════════════════════════════════════════
   Gemessen am 20.08.2026 an 956 Icons: zwoelf verschiedene
   `stroke-width`-Werte im Quelltext. Sichtbar ist davon aber etwas
   anderes — die Angabe steht im 24er-Raster und skaliert mit der
   Anzeigegroesse. Ein Icon mit `stroke-width="2"` hat bei 11px einen
   Strich von 0,92 Bildschirmpixeln, bei 18px einen von 1,5. Ueber die
   ganze App lagen die Striche zwischen 0,73 und 3,15 Pixeln, und
   nebeneinander wirkte das eine blass und das andere fett.

   `vector-effect: non-scaling-stroke` nimmt den Strich aus dem Raster
   heraus: die Angabe zaehlt dann in Bildschirmpixeln, unabhaengig von
   viewBox und Groesse. Damit ist das Gewicht eine Entscheidung statt
   ein Nebenprodukt zweier Zahlen.

   Konstant waere falsch. SF Symbols werden mit der Groesse schwerer,
   nur langsamer als linear — deshalb die Staffelung unten. Sie folgt
   0,8 + 0,03 x Groesse: bei 12px 1,15 / bei 24px 1,45 / bei 40px 2,0.

   Beruehrt werden nur die kleinen quadratischen Raster. Marken-Logos
   mit eigenem Raster (z.B. viewBox="0 0 256 218") bleiben aussen vor —
   dort waere ein Strich in Bildschirmpixeln sinnlos.

   Zwei Auswege:
     * `data-strich="eigen"` am <svg> — das ganze Icon bleibt, wie es ist.
     * Ein Kind mit eigenem `stroke-width` behaelt seins. So bleiben die
       fuenf Icons heil, die absichtlich zwei Gewichte tragen
       (Aufzaehlung, Durchstreichen im Editor).
   ═══════════════════════════════════════════════════════════════════ */

/* Grundwert fuer Icons, deren Groesse aus CSS kommt (308 Stueck) — die
   liegen praktisch alle zwischen 15 und 18 Pixeln.

   In `:where()`, also mit Spezifitaet null: sonst schlaegt diese Regel
   (drei Attribute) die Groessenstufen darunter (zwei Attribute), und alle
   Icons bekaemen denselben Wert. Genau das ist beim ersten Versuch
   passiert und im Browser aufgefallen. */
:where(
  svg[viewBox="0 0 24 24"][stroke], svg[viewBox="0 0 20 20"][stroke],
  svg[viewBox="0 0 18 18"][stroke], svg[viewBox="0 0 16 16"][stroke],
  svg[viewBox="0 0 14 14"][stroke], svg[viewBox="0 0 12 12"][stroke],
  svg[viewBox="0 0 10 10"][stroke]
) {
  --icon-strich: 1.3px;
}
/* Staffelung nach der Anzeigegroesse. Gruppiert statt 25 Einzelregeln:
   feiner als 0,05px unterscheidet das Auge hier ohnehin nichts. */
svg[stroke][width="8"],  svg[stroke][width="9"],
svg[stroke][width="10"], svg[stroke][width="11"] { --icon-strich: 1.1px }
svg[stroke][width="12"], svg[stroke][width="13"],
svg[stroke][width="14"]                          { --icon-strich: 1.2px }
svg[stroke][width="15"], svg[stroke][width="16"],
svg[stroke][width="17"], svg[stroke][width="18"] { --icon-strich: 1.3px }
svg[stroke][width="19"], svg[stroke][width="20"],
svg[stroke][width="22"], svg[stroke][width="24"] { --icon-strich: 1.45px }
svg[stroke][width="26"], svg[stroke][width="28"],
svg[stroke][width="30"], svg[stroke][width="32"] { --icon-strich: 1.7px }
svg[stroke][width="36"], svg[stroke][width="38"],
svg[stroke][width="40"], svg[stroke][width="42"],
svg[stroke][width="44"], svg[stroke][width="48"] { --icon-strich: 2px }

/* Gezeichnet wird auf den Formen, nicht auf dem <svg> — `vector-effect`
   wirkt nur dort. Kinder mit eigenem `stroke-width` bleiben unberuehrt. */
svg[viewBox="0 0 24 24"][stroke]:not([data-strich="eigen"]) :is(path,circle,rect,line,polyline,polygon,ellipse):not([stroke-width]),
svg[viewBox="0 0 20 20"][stroke]:not([data-strich="eigen"]) :is(path,circle,rect,line,polyline,polygon,ellipse):not([stroke-width]),
svg[viewBox="0 0 18 18"][stroke]:not([data-strich="eigen"]) :is(path,circle,rect,line,polyline,polygon,ellipse):not([stroke-width]),
svg[viewBox="0 0 16 16"][stroke]:not([data-strich="eigen"]) :is(path,circle,rect,line,polyline,polygon,ellipse):not([stroke-width]),
svg[viewBox="0 0 14 14"][stroke]:not([data-strich="eigen"]) :is(path,circle,rect,line,polyline,polygon,ellipse):not([stroke-width]),
svg[viewBox="0 0 12 12"][stroke]:not([data-strich="eigen"]) :is(path,circle,rect,line,polyline,polygon,ellipse):not([stroke-width]),
svg[viewBox="0 0 10 10"][stroke]:not([data-strich="eigen"]) :is(path,circle,rect,line,polyline,polygon,ellipse):not([stroke-width]) {
  vector-effect: non-scaling-stroke;
  stroke-width: var(--icon-strich, 1.3px);
}

/* ═══════════════════════════════════════════════════════════════════════════
   TELEFON: FINANZFORMULARE, MODALS, PROFIL-FORMULARE
   Uebernommen am 27.09.2026 aus static/css/responsive-enhance.css, die
   danach entfernt wurde. Diese Datei wurde von `templates/base.html`
   geladen — und die gibt es seit der DS-Umstellung nicht mehr, base_ds.html
   hat sie ersetzt. Ihre 2076 Zeilen lagen also im Baum und wirkten nirgends.

   Uebernommen ist NICHT alles. Gemessen wurde pro Abschnitt, ob seine
   Klassen noch vergeben werden und ob das DS die Sache nicht schon loest:

     §15 Finanzformulare aufs Telefon  → hier (42 von 44 Klassen leben)
     §17 Modals als Bottom-Sheet       → hier, gekuerzt (s. u.)
     §19 Anmeldung/Profil              → nur zwei Regeln (s. u.)
     §16 Belegdetails                  → gegenstandslos: seine einzige
         Zielklasse `.fin-lineitems` gibt es nur in invoice_detail.html,
         und die versteckt ihre Tabelle auf dem Telefon laengst selbst und
         zeigt `.inv-items-mobile`.
     §14 Tabelle→Karte                 → tot: der Haken `.mobile-card-table`
         wird in keiner Vorlage vergeben.

   Nicht uebernommen und bewusst offen: §8 und §10 („Mobile app-feel polish",
   zusammen 889 Zeilen) haben ebenfalls lebende Ziele, aber sie sind vor dem
   Glas-DS geschrieben und fassen `.card`, `.btn` und `.content-grid` breit
   an. Die unbesehen auf jede Seite unter 767px zu legen waere ein optisches
   Gluecksspiel. Der Wortlaut steht in der Versionsgeschichte, falls er
   gebraucht wird.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── §15 · Die drei Finanzformulare auf dem Telefon ─────────────────────────
   Rechnung, Angebot und Bestellung teilen das `.inv-*`-Vokabular und haben
   alle drei dieselben sechs Spalten (Position, Menge, Einheit, Einzelpreis,
   Gesamt, Loeschen) — nachgeprueft, denn die `nth-child`-Regeln unten haengen
   daran. Die Positionstabelle wird zu einer Karte je Zeile.

   Eine Korrektur gegenueber dem Wortlaut: drei Regeln setzten
   `background:var(--bg-2)`, und `--bg-2` ist im ganzen Projekt nirgends
   definiert. Ohne Ersatzwert ist die Deklaration ungueltig — diese drei
   Flaechen blieben also schon farblos, als die Datei noch geladen wurde.
   Jetzt `var(--fill)`, das DS-Token fuer eine abgesetzte Flaeche. */
@media (max-width: 767px) {

  /* Page chrome */
  /* Randlos: die Formularkarten sollen bis an die Bildschirmkante. Der
     Wortlaut von §15 sprach `.main-content` an — so heisst der Inhaltsbereich
     nicht, base_ds.html vergibt `class="content"`. Die Regel lief ins Leere.

     Und nur die SEITLICHE Polsterung faellt weg, nicht `padding: 0`: unter
     900px traegt `.content` ein `padding-top:62px`, das dem festen
     Hamburger-Knopf oben links Platz macht (weiter oben in dieser Datei). Wer
     hier pauschal auf Null setzt, schiebt das Formular unter den Knopf. */
  body:has(.inv-grid) .content { padding-left: 0 !important; padding-right: 0 !important; }

  .inv-grid {
    gap: 0 !important;
    padding: 0 !important;
    grid-template-columns: 1fr !important;
  }

  /* Card rhythm: edge-to-edge cards with gaps */
  .inv-card {
    border-radius: 0 !important;
    border-left: none !important;
    border-right: none !important;
    margin-bottom: 8px !important;
  }
  .inv-card-head { padding: 12px 14px !important; }
  .inv-card-body { padding: 14px !important; }

  /* All inline row grids stack */
  .inv-row-2,
  .inv-row-3,
  .inv-row-4 {
    grid-template-columns: 1fr !important;
    gap: 12px !important;
  }

  /* ── Line items: kill table, use block cards ── */
  .inv-items-wrap {
    margin: 0 !important;
    overflow-x: hidden !important;
  }
  .inv-items-table,
  .inv-items-table thead,
  .inv-items-table tbody,
  .inv-items-table tr,
  .inv-items-table td {
    display: block !important;
    width: 100% !important;
    box-sizing: border-box;
  }
  .inv-items-table thead,
  .inv-items-table colgroup { display: none !important; }

  .inv-items-table tbody tr.inv-item-row {
    position: relative;
    padding: 12px 14px 10px !important;
    border-bottom: 1px solid var(--border) !important;
    background: var(--surface);
  }
  .inv-items-table tbody tr.inv-item-row:hover {
    background: var(--surface) !important;
  }
  .inv-items-table td {
    padding: 0 !important;
    border: none !important;
    width: auto !important;
  }
  .inv-items-table td:first-child,
  .inv-items-table td:last-child { padding: 0 !important; }

  /* Row 1: description (full width) */
  .inv-items-table tr.inv-item-row td:nth-child(1) {
    display: block !important;
    margin-bottom: 10px;
  }
  .inv-items-table tr.inv-item-row td:nth-child(1) input[type=text] {
    font-size: 15px !important;
    padding: 10px 12px !important;
    min-height: 44px;
    border: 1px solid var(--border) !important;
    background: var(--surface-2) !important;
    border-radius: 10px !important;
    margin-bottom: 6px;
    width: 100% !important;
  }
  .inv-items-table tr.inv-item-row td:nth-child(1) .inv-item-note {
    font-size: 13px !important;
    padding: 8px 12px !important;
    min-height: 36px;
    border: 1px solid var(--border) !important;
    background: var(--surface-2) !important;
    border-radius: 10px !important;
    width: 100% !important;
  }

  /* Row 2: qty + unit side-by-side; price full-width below */
  .inv-items-table tr.inv-item-row td:nth-child(2),
  .inv-items-table tr.inv-item-row td:nth-child(3) {
    display: inline-block !important;
    width: calc(50% - 4px) !important;
    vertical-align: top;
  }
  .inv-items-table tr.inv-item-row td:nth-child(2) { margin-right: 8px; }
  .inv-items-table tr.inv-item-row td:nth-child(4) {
    display: block !important;
    width: 100% !important;
    margin-top: 8px;
  }

  /* Micro-labels above small inputs */
  .inv-items-table tr.inv-item-row td:nth-child(2)::before { content: 'Menge'; }
  .inv-items-table tr.inv-item-row td:nth-child(3)::before { content: 'Einheit'; }
  .inv-items-table tr.inv-item-row td:nth-child(4)::before { content: 'Einzelpreis'; }
  .inv-items-table tr.inv-item-row td:nth-child(2)::before,
  .inv-items-table tr.inv-item-row td:nth-child(3)::before,
  .inv-items-table tr.inv-item-row td:nth-child(4)::before {
    display: block;
    font-family: var(--font-ui); font-variant-numeric: tabular-nums;
    font-size: 9px;
    font-weight: 700;
    /* KEIN uppercase. Der Inhalt sind feste Woerter („Menge", „Einheit",
       „Einzelpreis") — das sind die Spaltenkoepfe derselben Tabelle, nur
       gestapelt. Auf dem Schreibtisch liest die Spalte „Einheit", weil der
       Apple-Voice-Override sie erreicht; mit dem uppercase aus dem Wortlaut
       von §15 stuende auf dem Telefon „EINHEIT". Eine Tabelle, zwei Stimmen.
       Auch das Tracking faellt weg: es war fuer die Grossbuchstaben da. */
    color: var(--text-3);
    margin-bottom: 4px;
  }
  .inv-items-table tr.inv-item-row td:nth-child(2) input,
  .inv-items-table tr.inv-item-row td:nth-child(3) input,
  .inv-items-table tr.inv-item-row td:nth-child(4) input {
    font-size: 16px !important;
    padding: 10px 12px !important;
    min-height: 44px;
    border: 1px solid var(--border) !important;
    background: var(--surface-2) !important;
    border-radius: 10px !important;
    width: 100% !important;
    text-align: right !important;
  }
  .inv-items-table tr.inv-item-row td:nth-child(3) input {
    text-align: left !important;
  }
  /* Einzelpreis input: show € suffix via pseudo-label */
  .inv-items-table tr.inv-item-row td:nth-child(4) {
    position: relative;
  }
  .inv-items-table tr.inv-item-row td:nth-child(4)::after {
    content: '€';
    position: absolute;
    right: 14px;
    bottom: 11px;
    font-size: 14px;
    color: var(--text-3);
    pointer-events: none;
    font-variant-numeric: tabular-nums;
  }
  .inv-items-table tr.inv-item-row td:nth-child(4) input {
    padding-right: 28px !important;
  }

  /* Row 3: total + delete, dashed separator */
  .inv-items-table tr.inv-item-row td.item-total {
    display: inline-block !important;
    width: calc(100% - 50px) !important;
    margin-top: 10px;
    padding-top: 10px !important;
    border-top: 1px dashed var(--border) !important;
    font-size: 16px !important;
    font-weight: 700 !important;
    text-align: left !important;
    vertical-align: middle;
  }
  .inv-items-table tr.inv-item-row td.item-total::before {
    content: 'Gesamt ';
    font-family: var(--font-ui); font-variant-numeric: tabular-nums;
    font-size: 10px;
    font-weight: 600;
    /* Dieselbe Begruendung: der Inhalt ist „Gesamt “, kein Kuerzel. */
    color: var(--text-3);
    margin-right: 6px;
  }
  .inv-items-table tr.inv-item-row td:last-child {
    display: inline-block !important;
    width: 42px !important;
    margin-top: 10px;
    padding-top: 10px !important;
    border-top: 1px dashed var(--border) !important;
    vertical-align: middle;
    text-align: right;
  }

  /* Delete button always visible on mobile */
  .inv-items-table .inv-del-btn {
    opacity: 1 !important;
    width: 38px !important;
    height: 38px !important;
    /* Hausmuster fuer eine getoente Gefahr-Flaeche, wie .btn--danger:hover
       (oben in dieser Datei). Der Wortlaut von §15 hatte hier
       `rgba(239,68,68,.08)` und `#ef4444` — feste Modus-Farben, die die
       Hardcode-Regel von tokens.css bricht und die tests/test_glass_tokens.py
       auch prompt gemeldet hat. Der Anteil bleibt bei den 8 % von damals. */
    background: color-mix(in srgb,var(--red) 8%,transparent);
    color: var(--danger) !important;
    border-radius: 10px;
  }

  /* Hide drag handles (no touch DnD) */
  .inv-drag-handle,
  .inv-section-drag { display: none !important; }

  /* ── Section rows ── */
  .inv-items-table tr.inv-section-row {
    padding: 8px 0 !important;
    background: var(--fill) !important;
  }
  .inv-items-table tr.inv-section-row td {
    display: block !important;
    padding: 8px 14px !important;
    background: var(--fill) !important;
  }
  .inv-items-table tr.inv-section-row .inv-section-title {
    font-size: 15px !important;
    min-height: 40px;
    padding: 6px 10px !important;
    background: var(--surface-2) !important;
    border: 1px solid var(--border) !important;
    border-radius: 10px !important;
    width: 100%;
  }

  /* Section subtotal */
  .inv-items-table tr.inv-section-subtotal {
    padding: 10px 14px !important;
    background: var(--fill) !important;
    display: flex !important;
    align-items: center;
    justify-content: space-between;
  }
  .inv-items-table tr.inv-section-subtotal td {
    display: inline !important;
    width: auto !important;
    padding: 0 !important;
    text-align: left !important;
    font-size: 13px !important;
  }
  .inv-items-table tr.inv-section-subtotal td:last-child {
    display: none !important;
  }
  .inv-items-table tr.inv-section-subtotal td.item-total {
    font-size: 15px !important;
    border-top: none !important;
    margin-top: 0 !important;
    padding-top: 0 !important;
    width: auto !important;
    margin-left: auto;
  }
  .inv-items-table tr.inv-section-subtotal td.item-total::before {
    content: '';
    margin: 0;
  }

  /* Add-row bar */
  .inv-add-bar {
    padding: 12px 14px !important;
    flex-wrap: wrap;
    gap: 8px !important;
  }
  .inv-add-bar .inv-product-sel {
    flex: 1 1 100%;
    max-width: 100%;
    min-height: 44px;
    padding: 10px 12px !important;
    font-size: 14px !important;
    border-radius: 10px;
  }
  .inv-add-bar .btn {
    flex: 1 1 calc(50% - 4px);
    min-height: 44px;
    font-size: 13.5px !important;
  }

  /* Totals row */
  .inv-totals {
    padding: 14px !important;
    justify-content: stretch !important;
  }
  .inv-totals-inner { width: 100%; min-width: 0 !important; }
  .inv-totals-row { font-size: 14px !important; }
  .inv-totals-row.gross { font-size: 1.1rem !important; }

  /* Entity picker (client/project) */
  .entity-picker-trigger {
    font-size: 15px !important;
    padding: 11px 12px !important;
    min-height: 44px;
    border-radius: 10px !important;
  }
  .entity-picker-dropdown {
    position: fixed !important;
    left: 12px !important;
    right: 12px !important;
    width: auto !important;
    max-width: none !important;
    top: 70px !important;
    max-height: 70vh;
  }

  /* Card inputs: 16px for iOS */
  .inv-card-body select,
  .inv-card-body input[type=text],
  .inv-card-body input[type=date],
  .inv-card-body input[type=number],
  .inv-notes {
    font-size: 16px !important;
    padding: 11px 12px !important;
    min-height: 44px;
    border-radius: 10px !important;
  }
  .inv-notes { min-height: 84px; }

  /* Summary card: static, full-width, above bottom submit */
  .inv-summary-card {
    position: static !important;
    border-radius: 14px !important;
    border: 1px solid var(--border) !important;
    margin: 8px 12px 90px !important;
  }
  .inv-summary-head { padding: 12px 14px !important; }
  .inv-summary-body { padding: 14px !important; }
  .inv-summary-gross {
    font-size: 1.9rem !important;
    margin-bottom: 12px !important;
  }
  .inv-summary-total-label {
    font-size: 10px !important;
    margin-bottom: 6px !important;
  }
  .inv-summary-line { font-size: 13px !important; }
  .inv-summary-breakdown { gap: 6px !important; padding-top: 10px !important; }

  /* ── Sticky bottom submit bar ── */
  .inv-submit-bar {
    position: fixed !important;
    left: 0; right: 0;
    /* Am unteren Rand, nicht 62px darueber: der Wortlaut von §15 rechnete mit
       `calc(62px + …)` fuer eine mobile Tab-Leiste. Die gibt es nicht —
       `.bottom-nav` wird in keiner Vorlage vergeben, und schmale Schirme
       bekommen die eingeschobene Seitenleiste mit Hamburger oben links
       (components.css, @media max-width:900px). Mit dem alten Versatz stand
       die Leiste 62px ueber der Kante und darunter nichts.

       Der schwebende Assistenten-Knopf kollidiert nicht: `.ds-assistant-fab`
       sitzt unter 900px auf `bottom:78px` (base_ds.html), diese Leiste ist
       rund 66px hoch. Der alte Kommentar versprach dafuer ~58px Platz rechts
       und setzte dann doch `padding-right:12px` — er widersprach sich selbst. */
    bottom: env(safe-area-inset-bottom, 0);
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0));
    /* Dasselbe Material wie Seitenleiste und Kopfleiste. Der Wortlaut von §15
       hatte hier ein Hell/Dunkel-Paar aus festen Werten
       (`rgba(247,247,248,.94)` plus eine `[data-theme="dark"]`-Regel mit
       `rgba(17,17,19,.94)`) — zwei Modus-Farben in components.css, was die
       Hardcode-Regel im Kopf von tokens.css ausdruecklich verbietet: wer so
       schreibt, pflegt jeden Modus einzeln und vergisst einen. Das Token
       kennt beide. */
    background: var(--glass-chrome);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    border-top: .5px solid var(--hairline);
    margin: 0 !important;
    z-index: 80;
    gap: 8px !important;
    flex-wrap: nowrap !important;
    align-items: center;
  }
  .inv-submit-bar .btn-primary {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 46px !important;
    font-size: 14px !important;
    padding: 11px 12px !important;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* Vorschau + Abbrechen: both collapse to icon-only 46px square */
  .inv-submit-bar .btn-outline,
  .inv-submit-bar .btn-ghost {
    flex: 0 0 44px !important;
    width: 44px !important;
    min-height: 44px !important;
    min-width: 44px !important;
    padding: 0 !important;
    font-size: 0 !important;
    overflow: hidden;
    position: relative;
    color: transparent !important;
    border-radius: 10px !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
  }
  /* Draw an "X" for ghost buttons that lack an SVG (Abbrechen) */
  .inv-submit-bar .btn-ghost:not(:has(svg))::before,
  .inv-submit-bar .btn-ghost:not(:has(svg))::after {
    content: '';
    position: absolute;
    left: 50%; top: 50%;
    width: 16px; height: 2px;
    background: var(--text-2);
    border-radius: 1px;
    transform: translate(-50%, -50%) rotate(45deg);
  }
  .inv-submit-bar .btn-ghost:not(:has(svg))::after {
    transform: translate(-50%, -50%) rotate(-45deg);
  }
  .inv-submit-bar .btn-outline svg,
  .inv-submit-bar .btn-ghost svg {
    font-size: 14px;
    margin: 0 !important;
    stroke: var(--text-2) !important;
    width: 18px !important;
    height: 18px !important;
  }

  /* Card step badges */
  .inv-step { width: 20px !important; height: 20px !important; font-size: 10px !important; }
  .inv-card-title { font-size: 11px !important; letter-spacing: .1em !important; }

  /* Kill inline 18px spacers */
  .inv-card [style*="height:18px"],
  .inv-card [style*="height: 18px"] { display: none !important; }

  /* Push last card content above the fixed submit bar */
  form:has(.inv-submit-bar) { padding-bottom: 80px; }
}

/* Tiny phones */
@media (max-width: 380px) {
  .inv-add-bar .btn {
    font-size: 12.5px !important;
    padding: 10px 8px !important;
  }
  .inv-items-table tbody tr.inv-item-row { padding: 10px 12px !important; }
}

/* ── §17 · Modals docken auf dem Telefon unten an (≤480px) ─────────────────
   Viele Modals tragen ein Inline-`max-width:420…560px`. Auf einem 390px-
   Schirm blieb dazu das 20px-Padding von `.modal-overlay` stehen: der Inhalt
   wurde eng oder ragte heraus. Als Bottom-Sheet nutzt er die ganze Breite.

   Gekuerzt gegenueber dem Wortlaut von §17: `.modal` bringt im DS schon
   `max-height:90vh`, Flex-Spalte und `overflow:hidden` mit, und `.modal-body`
   scrollt selbst — der Sticky-Kopf und das eigene Scrollen von dort sind fuer
   `.modal` ueberfluessig. Sie bleiben nur fuer den Legacy-Fall
   `div[style*="max-width"]`, der diesen Aufbau nicht hat.

   `!important` steht genau dort, wo ein Inline-`style` zu schlagen ist —
   nicht auf `.modal-overlay` selbst, dessen Werte oben in dieser Datei
   stehen und die diese spaeter folgende Regel ohnehin gewinnt. */
@media (max-width:480px){
  .modal-overlay{align-items:flex-end;padding:0}
  .modal-overlay > .modal,
  .modal-overlay > div[style*="max-width"]{
    max-width:100%!important;width:100%!important;margin:0!important;
    border-radius:16px 16px 0 0!important;max-height:92dvh;
  }
  .modal-overlay > div[style*="max-width"]{overflow-y:auto}
  .modal-overlay > div[style*="max-width"] > .modal-header{
    position:sticky;top:0;z-index:2;background:var(--glass-modal);
  }
}

/* ── §19 · Profil: Formulare mit Passwortfeld NEBEN dem Knopf (≤480px) ─────
   In auth/profile.html stehen drei Formulare als `display:inline-flex` mit
   einem 220px breiten Passwortfeld und einem Knopf daneben. Auf 390px
   quetscht sich das; gestapelt passt es.

   Der Rest von §19 ist uebrigens gegenstandslos: die `.auth-*`-Regeln von
   dort zielen auf Werte („40px Padding, max-width 420"), die base_auth.html
   nicht mehr hat — es bringt seine eigene `@media (max-width:520px)` mit.
   Und profile.html erbt base_ds.html, nicht base_auth.html. */
@media (max-width:480px){
  .mfa-pwd-input{max-width:100%!important;width:100%!important}
  form[style*="display:inline-flex"][style*="gap:8px"][style*="align-items:center"]{
    display:flex!important;flex-direction:column;align-items:stretch!important;width:100%;
  }
  form[style*="display:inline-flex"][style*="gap:8px"][style*="align-items:center"] > .btn{
    width:100%;justify-content:center;
  }
}

/* ── Formular-Karten (df-*) — Design-Politur Paket 2, 30.10.2026 ──────────
   Projekt, Podcast und Kooperation trugen dieselben Regeln je in Kopie: 680 px
   breit, Abschnittstitel und Feldbeschriftungen als winzige gesperrte
   Großbuchstaben, eigene Feld- und Kartenoptik. Jetzt EINMAL hier, in der
   Sprache der übrigen App (.card, .field-label, .input); die Seiten behalten
   nur ihre eigenen Teile (Statusfarben, Richtung, Teamauswahl). */
.df-form{display:flex;flex-direction:column;gap:0;max-width:960px}
.df-section{background:var(--surface);border:.5px solid var(--hairline);border-radius:var(--radius-lg);box-shadow:var(--specular),var(--shadow-card);margin-bottom:14px;overflow:hidden}
.df-section-head{padding:16px 18px 4px;display:flex;align-items:center;gap:8px}
.df-section-icon{width:16px;height:16px;color:var(--label-tertiary);flex-shrink:0}
.df-section-title{font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--label)}
.df-section-body{padding:10px 18px 18px;display:grid;grid-template-columns:1fr 1fr;gap:14px 18px}
.df-section-body.single{grid-template-columns:1fr}
.df-section-body.triple{grid-template-columns:1fr 1fr 1fr}
@media (max-width:540px){.df-section-body,.df-section-body.triple{grid-template-columns:1fr}}
.df-col-full{grid-column:1/-1}
.df-field>label{display:block;font-size:var(--fs-subhead);font-weight:500;color:var(--label-secondary);margin-bottom:6px}
.df-field input:not([type=radio]):not([type=checkbox]):not([type=hidden]):not(.dp-input),.df-field select,.df-field textarea{width:100%;box-sizing:border-box;font:inherit;font-size:14px;color:var(--label);background:var(--fill);border:.5px solid var(--hairline);border-radius:var(--radius-sm);padding:9px 12px;outline:none;transition:border-color var(--dur-fast),box-shadow var(--dur-fast),background var(--dur-fast)}
.df-field input:not(.dp-input):focus,.df-field select:focus,.df-field textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3.5px color-mix(in srgb,var(--accent) 18%,transparent);background:var(--glass-card)}
.df-field input::placeholder,.df-field textarea::placeholder{color:var(--label-tertiary)}
.df-field input[type=number]{font-variant-numeric:tabular-nums}
.df-field textarea{resize:vertical;line-height:1.45}
.df-field input[readonly]{opacity:.5;cursor:default}
.df-hint{font-size:var(--fs-footnote);color:var(--label-tertiary);margin-top:5px}
.df-status-group{display:flex;flex-wrap:wrap;gap:6px}
.df-status-group input[type=radio]{display:none}
.df-status-pill{padding:6px 12px;border-radius:20px;font-size:12.5px;font-weight:600;border:1px solid var(--hairline);background:var(--fill);color:var(--label-secondary);cursor:pointer;transition:all var(--dur-fast);user-select:none}

/* Auswahl-Chips für Kästchengruppen (Abteilungen im Team-Formular u. a.) —
   vorher nur in admin.css, das die Team-Seite nicht lädt: dort standen die
   Kästchen nackt in einer Zeile. */
.dept-chip-wrap{display:flex;flex-wrap:wrap;gap:6px}
.dept-chip-wrap input[type=checkbox]{display:none}
.dept-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:1px solid var(--hairline);border-radius:20px;background:var(--fill);cursor:pointer;font-size:13px;font-weight:500;color:var(--label-secondary);transition:border-color var(--dur-fast),background var(--dur-fast),color var(--dur-fast);user-select:none}
.dept-chip:hover{color:var(--label)}
.dept-chip-wrap input[type=checkbox]:checked+.dept-chip{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.checkbox-label{display:inline-flex;align-items:center;gap:8px;font-size:14px;color:var(--label);cursor:pointer}
/* Abschnittstitel in Formularkarten: überall 15 px halbfett — wie .df-section-title
   und .form-card-strip-label (gemessen 30.10.: 11,5 / 14 / 15 px nebeneinander). */
.form-page .card-header h2{font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--label);text-transform:none}
