/* ==========================================================================
   leomore ops — Design-System
   Tokens und Anmutung portiert aus site/assets/css/style.css (leomore.de):
   Papier-Grund, weisse Karten mit feiner Linie, Clash Display + General Sans,
   Verlauf Gelb->Rot nur als schmaler Akzent.

   Eine Datei, mobile-first, Desktop-Breakpoint 1024px.
   Kein Inline-CSS moeglich (CSP: style-src 'self') — alles hier.

   1  Fonts
   2  Tokens
   3  Reset & Basis
   4  Typografie
   5  Shell: Topbar, Nav, Main, Seiten-Kopf
   6  Karte
   7  Tabelle
   8  Buttons
   9  Formular
   10 Badge
   11 Meldungen: Fehler, Meldungsbox, Toast
   12 Modal
   13 Skeleton & Leer-Zustand
   14 Login
   15 Utilities
   16 Gemeinsame Reste der Pipeline-Ansicht
   17 Reduced Motion
   18 Dashboard & Kunden-Detail (F2)
   19 Konfigurator & Katalog (F3)
   20 Statistik (F4)
   ========================================================================== */


/* ==========================================================================
   1  Fonts
   ========================================================================== */
@font-face {
  font-family: 'Clash Display';
  src: url('/fonts/clash-display-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Clash Display';
  src: url('/fonts/clash-display-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('/fonts/general-sans-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('/fonts/general-sans-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('/fonts/general-sans-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}


/* ==========================================================================
   2  Tokens
   ========================================================================== */
:root {
  /* Flaechen */
  --bg: #FBF8F3;
  --card: #FFFFFF;
  --flaeche-alt: #F4EFE6;

  /* Typo-Farben */
  --ink: #211A12;
  --ink-soft: #5C544A;
  --ink-faint: #6F6659;   /* abgesetzt und AA-fest (>=4.5:1 auf bg, card, flaeche-alt) */

  /* Linien: --line/--line-strong sind Trenner (Karten, Tabellen) — dekorativ,
     kein Kontrast-Ziel. Bedienelemente brauchen mehr, siehe --line-field. */
  --line: rgba(33, 26, 18, .10);
  --line-strong: rgba(33, 26, 18, .16);
  --ring: inset 0 0 0 1px rgba(33, 26, 18, .12);
  --ring-strong: inset 0 0 0 1px rgba(33, 26, 18, .22);

  /* Feld-Rand: einzige Kennzeichnung eines leeren Eingabefeldes, deshalb
     WCAG 1.4.11 mit 3:1 gegen JEDE Nachbarflaeche. Solide Farbe, nicht rgba —
     bei Transparenz haengt das Ergebnis am Untergrund und kippt.
     Gemessen: 3,73:1 auf --card, 3,52:1 auf der Feldfuellung --bg,
     3,26:1 auf --flaeche-alt (Tabellen-Hover).
     Untergrenze: Luminanz <= 0,2556 — heller heisst Verstoss.
     Bewusst kraeftiger als leomore.de (dort rgba(33,26,18,.10) = 1,2:1). */
  --line-field: #8C8378;

  /* Marke: Verlauf nur als schmaler Akzent, nie als Flaeche */
  --c1: #F9DD00;
  --c2: #F8950A;
  --c3: #F85701;
  --c4: #F70806;
  --c3-text: #BC4200;     /* AA-feste Text-Variante des Verlaufs */
  --grad: linear-gradient(100deg, #F9DD00 0%, #F8950A 38%, #F85701 70%, #F70806 100%);

  /* Signal */
  --ok: #1F6B3A;
  --warn: #A32118;

  /* Schatten: immer ink-getoent, nie generisches Schwarz */
  --shadow-sm: 0 1px 2px rgba(33, 26, 18, .04), 0 2px 8px rgba(33, 26, 18, .04);
  --shadow-md: 0 4px 14px rgba(33, 26, 18, .06), 0 14px 40px rgba(33, 26, 18, .07);
  --shadow-lg: 0 8px 24px rgba(33, 26, 18, .08), 0 28px 70px rgba(33, 26, 18, .10);

  /* Radien */
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-pill: 999px;

  /* Abstaende (Basis 4px) */
  --space-1: .25rem;
  --space-2: .5rem;
  --space-3: .75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;

  /* Schriftgroessen */
  --fs-mikro: 11px;
  --fs-klein: 13px;
  --fs-basis: 15px;
  --fs-gross: 17px;

  /* Layout */
  --maxw: 1240px;
  --gutter: clamp(16px, 4vw, 32px);
  --topbar-h: 60px;

  /* Bewegung */
  --ease: cubic-bezier(.22, .61, .36, 1);

  /* Papier-Grain (SVG-Noise, kein Fremd-Asset) */
  --grain-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");

  /* Status-Enum: interview | freigegeben | gebaut | build-fehler | abgenommen | live */
  --st-interview-bg: #FDF3CC;
  --st-interview-ink: #6B4E00;
  --st-freigegeben-bg: #E4EDFB;
  --st-freigegeben-ink: #1B4B8F;
  --st-gebaut-bg: #DFF3E4;
  --st-gebaut-ink: #1F6B3A;
  --st-fehler-bg: #FBE4E2;
  --st-fehler-ink: #A32118;
  --st-abgenommen-bg: #ECE3FB;
  --st-abgenommen-ink: #55379A;
}


/* ==========================================================================
   3  Reset & Basis
   ========================================================================== */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* Muss die Komponenten-Regeln schlagen: Seiten schalten Schritte und Panels
   ueber das hidden-Attribut, nicht ueber Klassen. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: 'General Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: var(--fs-basis);
  font-weight: 400;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, iframe {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
  text-decoration: none;
}

button, input, select, textarea {
  font: inherit;
  color: inherit;   /* iOS Safari faerbt Buttons sonst systemblau */
}

button {
  background: none;
  border: none;
  cursor: pointer;
}

ul[class], ol[class] {
  list-style: none;
}

/* Markierter Text: ink auf --c2 = 7,6:1 (weiss waere 2,3:1 und damit unter AA) */
::selection {
  background: var(--c2);
  color: var(--ink);
}

/* Nur der Ring, keine Form: border-radius hier wuerde Komponenten-Ecken umbiegen */
:focus-visible {
  outline: 2px solid var(--c4);
  outline-offset: 2px;
}


/* ==========================================================================
   4  Typografie
   ========================================================================== */
h1, h2, h3, h4 {
  font-family: 'Clash Display', 'General Sans', sans-serif;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -.02em;
}

h1 {
  font-size: clamp(24px, 3.2vw, 31px);
}
h2 {
  font-size: clamp(18px, 2.2vw, 21px);
}
h3 {
  font-size: var(--fs-gross);
}

p {
  max-width: 68ch;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: var(--fs-mikro);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c3-text);
}
.eyebrow::before {
  content: "";
  width: 20px;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
  flex-shrink: 0;
}

.dezent {
  color: var(--ink-faint);
}

.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-klein);
  word-break: break-all;
}

/* Textlink im Fliesstext: Verlaufs-Underline wandert beim Hover */
.link {
  font-weight: 600;
  color: var(--c3-text);
  background: var(--grad) no-repeat left calc(100% - .05em) / 0% 2px;
  transition: background-size .3s var(--ease);
  padding-bottom: .1em;
  cursor: pointer;
}
.link:hover,
.link:focus-visible {
  background-size: 100% 2px;
}


/* ==========================================================================
   5  Shell: Topbar, Nav, Main, Seiten-Kopf
   ========================================================================== */
.topbar {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-3) var(--gutter) 0;
  background: rgba(251, 248, 243, .88);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}

.topbar-inner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
}

/* Wortmarke: klein, klein geschrieben, Verlauf nur als Punkt */
.brand,
.wortmarke {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  font-family: 'Clash Display', sans-serif;
  font-weight: 600;
  font-size: 19px;
  letter-spacing: -.02em;
  text-transform: lowercase;
  line-height: 1;
  color: var(--ink);
  flex-shrink: 0;
}
.brand-punkt {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--grad);
  align-self: center;
  flex-shrink: 0;
}
.brand-sub {
  font-family: 'General Sans', sans-serif;
  font-weight: 600;
  font-size: var(--fs-klein);
  letter-spacing: .01em;
  color: var(--ink-faint);
}
/* Bestandsseiten setzen die Wortmarke ohne Punkt-Element */
.wortmarke::after {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin-left: 4px;
  background: var(--grad);
}

/* Nav: mobil eine horizontale Scroll-Leiste, kein Hamburger */
.hub-nav {
  order: 3;
  flex: 1 0 100%;
  display: flex;
  align-items: center;
  gap: var(--space-1);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.hub-nav::-webkit-scrollbar {
  display: none;
}
.hub-nav a {
  position: relative;
  flex-shrink: 0;
  padding: 12px 12px 13px;
  font-size: var(--fs-klein);
  font-weight: 500;
  white-space: nowrap;
  color: var(--ink-faint);
  transition: color .2s var(--ease);
}
.hub-nav a:hover {
  color: var(--ink);
}
.hub-nav a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
}
/* Aktiver Punkt: 2px-Verlaufskante unter dem Label */
.hub-nav a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
}

.topbar-rechts {
  order: 2;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-left: auto;
}
.topbar-wer {
  font-size: var(--fs-klein);
  color: var(--ink-faint);
  white-space: nowrap;
}

main {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--space-6) var(--gutter) var(--space-12);
}

/* Seiten-Kopf: H1 links, Aktionen rechts */
.seiten-kopf {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--space-6);
}
.seiten-kopf-text {
  flex: 1 1 240px;
}
.seiten-kopf p {
  margin-top: 6px;
  font-size: var(--fs-klein);
  color: var(--ink-faint);
}
.seiten-kopf-aktionen {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

@media (min-width: 1024px) {
  .topbar {
    /* min-height traegt auch die Bestandsseiten ohne .topbar-inner */
    min-height: var(--topbar-h);
    padding: 0 var(--gutter);
  }
  .topbar-inner {
    flex-wrap: nowrap;
    height: var(--topbar-h);
    gap: var(--space-6);
  }
  .hub-nav {
    order: 0;
    flex: 1 1 auto;
    gap: var(--space-2);
    overflow-x: visible;
  }
  .hub-nav a {
    padding: 19px 10px 20px;
    font-size: 14px;
  }
  .topbar-rechts {
    order: 0;
  }
  main {
    padding-top: var(--space-8);
  }
}


/* ==========================================================================
   6  Karte
   ========================================================================== */
.card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--space-5);
}
.card + .card {
  margin-top: var(--space-4);
}
/* Layout-Container liefern ihren Abstand per gap — Geschwister-Margin raus */
.karten-grid .card + .card,
.stack .card + .card,
.detail-grid .card + .card {
  margin-top: 0;
}
.card-kopf {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-4);
}
.card-kopf h2,
.card-kopf h3 {
  margin-right: auto;
}
/* Karte ohne Innenabstand: Tabellen sitzen bis an die Kante */
.card-blank {
  padding: 0;
  overflow: hidden;
}
/* Schmale Verlaufskante als Akzent — Marke, nicht Flaeche.
   overflow-hidden schneidet die Kante exakt auf die Karten-Rundung. */
.card-akzent {
  overflow: hidden;
}
.card-akzent::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--grad);
}
.card-hover {
  transition: box-shadow .25s var(--ease), transform .25s var(--ease);
}
.card-hover:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* Kennzahl-Kachel (Dashboard) */
.kpi {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.kpi-wert {
  font-family: 'Clash Display', sans-serif;
  font-weight: 600;
  font-size: 30px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.kpi-label {
  font-size: var(--fs-klein);
  color: var(--ink-faint);
}

.karten-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}
@media (min-width: 1024px) {
  .card {
    padding: var(--space-6);
  }
  .karten-grid {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  }
}


/* ==========================================================================
   7  Tabelle
   ========================================================================== */
.tabelle-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
/* Mobil lieber scrollen als Spalten zerquetschen */
.tabelle-wrap table {
  min-width: 520px;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-klein);
}

th {
  text-align: left;
  font-size: var(--fs-mikro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
}

td {
  padding: 12px;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

tbody tr:last-child td {
  border-bottom: none;
}

tr.klickbar {
  cursor: pointer;
}
tr.klickbar:hover td {
  background: var(--flaeche-alt);
}
tr.klickbar:focus-visible {
  outline: 2px solid var(--c4);
  outline-offset: -2px;
}

.num {
  font-variant-numeric: tabular-nums;
}


/* ==========================================================================
   8  Buttons
   ========================================================================== */
/* button.primary = Alias der Bestandsseiten (bis F2-F4) */
.btn,
button.primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 11px 20px;
  border: 1.5px solid transparent;
  border-radius: var(--r-pill);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background .2s var(--ease), border-color .2s var(--ease),
              box-shadow .2s var(--ease), transform .2s var(--ease);
}
.btn:active,
button.primary:active {
  transform: scale(.97);
  transition-duration: 90ms;
}
.btn[disabled],
.btn:disabled,
button.primary:disabled {
  opacity: .45;
  cursor: not-allowed;
  transform: none;
}

.btn-primary,
button.primary {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}
.btn-primary:hover,
button.primary:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}

.btn-sekundaer {
  background: transparent;
  color: var(--ink);
  border-color: var(--line-strong);
}
.btn-sekundaer:hover {
  border-color: var(--ink);
  background: var(--card);
}

.btn-gefahr {
  background: transparent;
  color: var(--warn);
  border-color: rgba(163, 33, 24, .35);
}
.btn-gefahr:hover {
  background: var(--warn);
  border-color: var(--warn);
  color: #fff;
}

.btn-klein {
  min-height: 36px;
  padding: 7px 14px;
  font-size: var(--fs-klein);
}

.btn-block {
  width: 100%;
}

.btn-reihe {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}


/* ==========================================================================
   9  Formular
   ========================================================================== */
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.field + .field,
.field + .fehler,
.field + .btn,
.field + .meldung {
  margin-top: var(--space-4);
}

label {
  font-size: var(--fs-klein);
  font-weight: 600;
  color: var(--ink-soft);
}

input[type=text],
input[type=password],
input[type=number],
input[type=email],
input[type=search],
input[type=date],
select,
textarea {
  width: 100%;
  padding: 11px 14px;
  background: var(--bg);
  color: var(--ink);
  /* --line waere 1,2:1 auf der weissen Karte: das Feld liest als Geisterkasten.
     --line-field ist die Kontrast-feste Variante (Werte im Token-Block). */
  border: 1.5px solid var(--line-field);
  border-radius: var(--r-sm);
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
/* Zeiger-Affordanz: 5,6:1, zieht an, ohne den Fokus-Zustand zu imitieren.
   Absichtlich auf Element-Ebene (0,1,1) und VOR den Zustands-Regeln: so
   gewinnen :focus (gleiche Spezifitaet, spaeter) und .ungueltig (hoeher). */
input:hover,
select:hover,
textarea:hover {
  border-color: var(--ink-faint);
}
/* Volle ink-faint-Farbe, keine Zusatz-Transparenz — Platzhalter bleiben AA-fest */
input::placeholder,
textarea::placeholder {
  color: var(--ink-faint);
  opacity: 1;
}
/* Fokus-Zustand: Rand in --c3-text = 5,1:1 auf der Feldflaeche (--c2 waere 2,3:1) */
input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--c3-text);
  box-shadow: 0 0 0 3px rgba(188, 66, 0, .12);
}
/* Der Ring wieder her: :focus-visible impliziert :focus, die Regel oben schlaegt
   sonst die globale (:focus-visible ist 0,1,0 gegen input:focus 0,1,1). 2px --c4 = 4,2:1 */
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--c4);
  outline-offset: 2px;
}
textarea {
  resize: vertical;
  min-height: 96px;
}
select {
  cursor: pointer;
}

.field-hinweis {
  font-size: var(--fs-klein);
  font-weight: 400;
  color: var(--ink-faint);
}

.field.ungueltig input,
.field.ungueltig select,
.field.ungueltig textarea,
input[aria-invalid="true"] {
  border-color: var(--warn);
}

/* Nebeneinander liegende Felder */
.field-reihe {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: flex-start;   /* Labels auf einer Linie, auch mit Hinweistext */
}
.field-reihe > .field {
  flex: 1 1 160px;
  margin-top: 0;
}
/* Abstand zwischen gestapelten Formular-Bloecken */
.field-reihe + .field-reihe,
.field-reihe + .btn-reihe,
.field-reihe + .check,
.btn-reihe + .field-reihe {
  margin-top: var(--space-4);
}

/* Checkbox/Radio-Zeile */
.check {
  display: flex;
  align-items: center;
  gap: 9px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
}
.check input {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--c3);
  flex-shrink: 0;
}

/* Ziffern-Code (TOTP/Recovery) */
.input-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 21px;
  letter-spacing: .22em;
  text-align: center;
  font-variant-numeric: tabular-nums;
  padding: 13px 14px;
}


/* ==========================================================================
   10  Badge
   ========================================================================== */
.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-strong);
  background: var(--card);
  font-size: var(--fs-mikro);
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
}

/* Status-Enum */
.badge.interview {
  background: var(--st-interview-bg);
  color: var(--st-interview-ink);
  border-color: rgba(107, 78, 0, .22);
}
.badge.freigegeben {
  background: var(--st-freigegeben-bg);
  color: var(--st-freigegeben-ink);
  border-color: rgba(27, 75, 143, .22);
}
.badge.gebaut {
  background: var(--st-gebaut-bg);
  color: var(--st-gebaut-ink);
  border-color: rgba(31, 107, 58, .22);
}
.badge.build-fehler {
  background: var(--st-fehler-bg);
  color: var(--st-fehler-ink);
  border-color: rgba(163, 33, 24, .24);
}
.badge.abgenommen {
  background: var(--st-abgenommen-bg);
  color: var(--st-abgenommen-ink);
  border-color: rgba(85, 55, 154, .22);
}
.badge.live {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}

/* Katalog: Auswahl-Typ */
.badge.single {
  background: var(--st-freigegeben-bg);
  color: var(--st-freigegeben-ink);
  border-color: rgba(27, 75, 143, .22);
}
.badge.multi {
  background: var(--st-interview-bg);
  color: var(--st-interview-ink);
  border-color: rgba(107, 78, 0, .22);
}

/* Konfigurator: Angebots-Status */
.badge.entwurf {
  background: var(--flaeche-alt);
  color: var(--ink-soft);
}
.badge.angebot {
  background: var(--st-freigegeben-bg);
  color: var(--st-freigegeben-ink);
  border-color: rgba(27, 75, 143, .22);
}
.badge.angenommen {
  background: var(--st-gebaut-bg);
  color: var(--st-gebaut-ink);
  border-color: rgba(31, 107, 58, .22);
}

/* Preis-Chip im Konfigurator */
.badge.preis {
  background: var(--bg);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}


/* ==========================================================================
   11  Meldungen: Fehler, Meldungsbox, Toast
   ========================================================================== */
/* Inline-Fehler unter einem Feld */
.fehler {
  min-height: 20px;
  font-size: var(--fs-klein);
  font-weight: 500;
  color: var(--warn);
}
.fehler:empty {
  min-height: 0;
}

/* Meldungsbox: Hinweis, Warnung, Erfolg. max-width raus — als <p> gaebe die
   Typo-Regel sonst 68ch vor, die Box soll ihren Container fuellen. */
.meldung {
  max-width: none;
  padding: 13px 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--flaeche-alt);
  font-size: var(--fs-klein);
  font-weight: 500;
  color: var(--ink);
}
.meldung-warn {
  background: rgba(163, 33, 24, .06);
  border-color: rgba(163, 33, 24, .28);
  color: var(--warn);
}
.meldung-ok {
  background: rgba(31, 107, 58, .07);
  border-color: rgba(31, 107, 58, .26);
  color: var(--ok);
}
.meldung-info {
  background: rgba(249, 221, 0, .13);
  border-color: rgba(248, 87, 1, .22);
  color: var(--ink);
}

/* Toast: rechts unten, JS setzt/entfernt die Elemente.
   pointer-events: none ist Pflicht — der Stack liegt sechs Sekunden ueber der
   Seite und darf keinen Klick verschlucken (Toasts sind reine Meldungen, nichts
   darin ist bedienbar). Er kann kurz eine Leiste ueberdecken; klickbar bleibt
   alles darunter. Etwas Klickbares im Toast braeuchte pointer-events: auto. */
.toast-stack {
  position: fixed;
  right: var(--gutter);
  bottom: var(--gutter);
  z-index: 90;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: min(360px, calc(100vw - 2 * var(--gutter)));
  pointer-events: none;
}
.toast {
  padding: 12px 16px;
  border-radius: var(--r-sm);
  background: var(--ink);
  color: var(--bg);
  font-size: var(--fs-klein);
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  animation: toast-auf .25s var(--ease);
}
.toast-warn {
  background: var(--warn);
  color: #fff;
}
.toast-ok {
  background: var(--ok);
  color: #fff;
}
@keyframes toast-auf {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}


/* ==========================================================================
   12  Modal
   ========================================================================== */
dialog.modal {
  /* margin:auto zentriert — der *-Reset oben kassiert den UA-Default */
  margin: auto;
  width: min(520px, calc(100vw - 2 * var(--gutter)));
  max-height: calc(100vh - 2 * var(--gutter));
  overflow-y: auto;
  padding: var(--space-6);
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
}
dialog.modal::backdrop {
  background: rgba(33, 26, 18, .38);
  backdrop-filter: blur(2px);
}
.modal-kopf {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}
.modal-kopf h2 {
  margin-right: auto;
}
.modal-schliessen {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: var(--ink-faint);
  font-size: 18px;
  line-height: 1;
}
.modal-schliessen:hover {
  background: var(--flaeche-alt);
  color: var(--ink);
}
.modal-aktionen {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-6);
}


/* ==========================================================================
   13  Skeleton & Leer-Zustand
   ========================================================================== */
.skeleton {
  border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--flaeche-alt) 25%, #EFE8DC 50%, var(--flaeche-alt) 75%);
  background-size: 200% 100%;
  animation: skeleton 1.3s linear infinite;
}
.skeleton-zeile {
  height: 14px;
  margin-bottom: 10px;
}
.skeleton-zeile:last-child {
  width: 60%;
  margin-bottom: 0;
}
@keyframes skeleton {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

.leer {
  padding: var(--space-10) var(--space-4);
  text-align: center;
}
.leer h2 {
  font-size: var(--fs-gross);
}
.leer p {
  margin: 8px auto 0;
  max-width: 40ch;
  font-size: var(--fs-klein);
  color: var(--ink-faint);
}
.leer .btn {
  margin-top: var(--space-5);
}


/* ==========================================================================
   14  Login
   ========================================================================== */
.login-wrap {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  /* Login-Seite tragt die Flaeche selbst — keine main-Breitenbegrenzung */
  max-width: none;
  margin: 0;
  padding: var(--space-6) var(--gutter);
  /* Warmer Marken-Schimmer, kein Verlauf als Flaeche */
  background:
    radial-gradient(60% 42% at 78% 4%, rgba(248, 149, 10, .10), transparent 70%),
    radial-gradient(50% 38% at 8% 96%, rgba(249, 221, 0, .10), transparent 72%),
    var(--bg);
}

.login-shell {
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.login-marke {
  align-self: center;
  font-size: 24px;
}

.login-card {
  padding: var(--space-6) var(--space-5) var(--space-5);
  box-shadow: var(--shadow-md);
}
.login-card h1 {
  margin: 10px 0 0;
}
.login-card .login-text {
  margin-top: 8px;
  font-size: var(--fs-klein);
  color: var(--ink-faint);
}
.login-card form + .login-fuss,
.login-card .btn + .login-fuss {
  margin-top: var(--space-4);
}
.login-step > .eyebrow + h1 {
  margin-top: 10px;
}
.login-step .field:first-of-type {
  margin-top: var(--space-5);
}
.login-step h1 + .meldung,
.login-step .login-text + .meldung {
  margin-top: var(--space-4);
}
.login-step .meldung + .recovery-liste {
  margin-top: var(--space-4);
}
.login-step .fehler {
  margin-top: var(--space-3);
}
.login-step .fehler + .btn {
  margin-top: var(--space-2);
}
.login-fuss {
  text-align: center;
  font-size: var(--fs-klein);
}

/* 2FA-Einrichtung */
.qr {
  width: 180px;
  height: 180px;
  margin: var(--space-5) auto var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #fff;
}
.login-manuell {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-5);
}
.login-manuell summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 11px 0;
  font-size: var(--fs-klein);
  font-weight: 600;
  color: var(--ink-soft);
  cursor: pointer;
  list-style: none;
}
.login-manuell summary::-webkit-details-marker {
  display: none;
}
.login-manuell summary::after {
  content: "+";
  font-size: var(--fs-gross);
  line-height: 1;
  color: var(--c3-text);
}
.login-manuell[open] summary::after {
  content: "–";
}
.login-manuell .mono {
  padding: 0 0 12px;
  color: var(--ink-soft);
}

/* Recovery-Codes */
.recovery-liste {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px var(--space-4);
  margin: var(--space-4) 0 var(--space-5);
  padding: var(--space-4);
  background: var(--flaeche-alt);
  border-radius: var(--r-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-klein);
  letter-spacing: .04em;
}

@media (min-width: 1024px) {
  .login-card {
    padding: var(--space-8) var(--space-8) var(--space-6);
  }
}


/* ==========================================================================
   15  Utilities
   ========================================================================== */
.spacer {
  flex: 1;
}
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.nur-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* Papier-Textur, opt-in wie auf leomore.de */
.grain {
  position: relative;
}
.grain::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--grain-url);
  opacity: .05;
  mix-blend-mode: multiply;
  border-radius: inherit;
  pointer-events: none;
}


/* ==========================================================================
   16  Gemeinsame Reste der Pipeline-Ansicht
   Katalog und Konfigurator sind in F3 neu gebaut (Abschnitt 19) — hier steht
   nur noch, was das Dashboard/Kunden-Detail (Abschnitt 18) mitbenutzt.
   ========================================================================== */
#suche {
  max-width: 420px;
  margin-bottom: var(--space-4);
}

.detail-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.detail-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  margin-top: var(--space-4);
}
.detail-grid pre {
  white-space: pre-wrap;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-klein);
  max-height: 420px;
  overflow-y: auto;
}
.warn-flag {
  font-size: var(--fs-mikro);
  font-weight: 700;
  color: var(--warn);
}

.chat {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-height: 420px;
  overflow-y: auto;
}
.chat .msg {
  max-width: 85%;
  padding: 9px 13px;
  border-radius: var(--r-md);
  font-size: var(--fs-klein);
  white-space: pre-wrap;
}
.chat .user {
  align-self: flex-end;
  background: var(--ink);
  color: var(--bg);
}
.chat .assistant {
  align-self: flex-start;
  background: var(--flaeche-alt);
}

@media (min-width: 1024px) {
  .detail-grid {
    grid-template-columns: 1fr 1fr;
  }
}


/* ==========================================================================
   17  Reduced Motion
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .btn:active {
    transform: none;
  }
}


/* ==========================================================================
   18  Dashboard & Kunden-Detail (F2)
   Ergaenzt die Komponenten, die in 1-15 fehlen: Kennzahl-Zusatz, Karten-Leiste,
   Schluessel/Wert-Liste, Anfragen-Zeile, Rohtext, Tabs, Akte-Typografie.
   ========================================================================== */

.klein {
  font-size: var(--fs-klein);
}

/* Abschnitt unterhalb der Kennzahlen (Kunden, Anfragen) */
.abschnitt {
  margin-top: var(--space-6);
}

/* --- Kennzahl-Kacheln ---------------------------------------------------- */
.kpi-note {
  font-size: var(--fs-mikro);
  color: var(--ink-faint);
}
/* Nur ein Problem-Wert wird rot — sonst schreit die ganze Reihe */
.kpi-warn {
  border-color: rgba(163, 33, 24, .28);
}
.kpi-warn .kpi-wert {
  color: var(--warn);
}
/* Sechs Kacheln: 2 / 3 / 6 Spalten — auf dem Desktop EINE Kennzahlen-Leiste,
   damit die Pipeline-Tabelle ohne Scrollen anfaengt. Schon auf dem Handy zwei
   Spalten: sechs gestapelte Kacheln waeren eine halbe Bildschirmseite Scrollen. */
#kpis {
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
}
@media (min-width: 768px) {
  #kpis {
    grid-template-columns: repeat(3, 1fr);
  }
}
@media (min-width: 1024px) {
  #kpis {
    grid-template-columns: repeat(6, 1fr);
    gap: var(--space-3);
  }
  .card.kpi {
    padding: var(--space-4);
  }
  .card.kpi .kpi-wert {
    font-size: 26px;
  }
}

/* --- Karten-Leiste: Kopf einer randlosen Karte (Titel + Filter) ---------- */
.karte-leiste {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--line);
}
.karte-leiste h2 {
  font-size: var(--fs-gross);
}
/* Suche + Status bleiben zusammen: mobil eine eigene Zeile, auf dem Desktop
   rechts in der Leiste. */
.filter-gruppe {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 1 1 100%;
}
/* #suche traegt in Abschnitt 16 noch max-width + margin fuer die Alt-Seiten —
   in der Leiste sitzt es im Flex-Fluss, deshalb hier per id ueberschrieben. */
.filter-gruppe #suche {
  flex: 1 1 140px;
  min-width: 0;
  max-width: none;
  margin-bottom: 0;
}
.filter-gruppe select {
  flex: 0 1 150px;
  width: auto;
  min-width: 0;
}
@media (min-width: 1024px) {
  .filter-gruppe {
    flex: 0 1 460px;
  }
  .filter-gruppe #suche {
    flex: 1 1 200px;
  }
}

/* --- Pipeline-Zeile ------------------------------------------------------ */
/* Der Knopf traegt Fokus und Screenreader-Semantik, sieht aber wie Text aus. */
.zeile-knopf {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
}
.zeile-knopf:focus-visible {
  outline-offset: 3px;
}
.zeile-name {
  display: block;
  font-weight: 600;
}
.zeile-slug {
  display: block;
  margin-top: 2px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-mikro);
  color: var(--ink-faint);
}
.zeile-pfeil {
  width: 1%;
  text-align: right;
  font-size: var(--fs-gross);
  color: var(--ink-faint);
}

/* --- Schluessel/Wert-Liste (Meta, Funnel, Anfragen, Akte-Kopf) ----------- */
.kv {
  display: grid;
  grid-template-columns: 1fr;
  font-size: var(--fs-klein);
}
.kv dt {
  padding-top: 10px;
  font-size: var(--fs-mikro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.kv dd {
  padding: 2px 0 10px;
  border-bottom: 1px solid var(--line);
  overflow-wrap: anywhere;
}
.kv dt:first-of-type {
  padding-top: 0;
}
.kv dd:last-of-type {
  padding-bottom: 0;
  border-bottom: none;
}
/* Zwei Spalten: dt und dd werden auf Zeilenhoehe gestreckt, damit die
   Trennlinien beider Spalten auf einer Linie liegen (kein align-items!). */
@media (min-width: 1024px) {
  .kv {
    grid-template-columns: minmax(110px, 200px) 1fr;
  }
  /* Kein column-gap: sonst reisst die Trennlinie zwischen den Spalten auf.
     Der Abstand kommt aus padding-right der Beschriftung. */
  .kv dt {
    padding: 10px var(--space-4) 10px 0;
    border-bottom: 1px solid var(--line);
  }
  .kv dd {
    padding: 10px 0;
  }
  .kv dt:first-of-type,
  .kv dd:first-of-type {
    padding-top: 0;
  }
  .kv dt:last-of-type {
    padding-bottom: 0;
    border-bottom: none;
  }
}

/* --- Anfragen-Zeile ----------------------------------------------------- */
.anfrage {
  padding: var(--space-5);
}
.anfrage + .anfrage {
  border-top: 1px solid var(--line);
}
.anfrage-kopf {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
}
.anfrage-kopf h3 {
  font-size: var(--fs-basis);
}

/* --- Rohtext (Log-Bloecke, Akte im Original) ---------------------------- */
.roh {
  max-width: none;
  max-height: 420px;
  overflow: auto;
  padding: var(--space-4);
  border-radius: var(--r-sm);
  background: var(--flaeche-alt);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-klein);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- Tabs (Chat | Akte) ------------------------------------------------- */
.tabs {
  display: flex;
  gap: var(--space-1);
  padding: 0 var(--space-5);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar {
  display: none;
}
.tab {
  position: relative;
  flex-shrink: 0;
  padding: 14px 12px;
  font-size: var(--fs-klein);
  font-weight: 600;
  white-space: nowrap;
  color: var(--ink-faint);
  transition: color .2s var(--ease);
}
.tab:hover,
.tab[aria-selected="true"] {
  color: var(--ink);
}
/* Aktiver Tab: dieselbe 2px-Verlaufskante wie die Nav */
.tab[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
}
.tab-panel {
  padding: var(--space-5);
}
/* Der Chat im Tab bekommt KEIN eigenes Scroll-Fenster (anders als die
   Alt-Ansicht in Abschnitt 16): die Seite ist die einzige Scroll-Ebene,
   sonst sitzt auf dem Handy eine Scroll-Falle mitten im Inhalt. */
.tab-panel .chat {
  max-height: none;
  overflow: visible;
}
.tab-panel:focus-visible {
  outline-offset: -3px;
}

/* --- Akte (Mini-Markdown) ----------------------------------------------
   Bewusst OHNE eigene Scroll-Hoehe: die Akte ist eine Leseansicht, sie waechst
   mit der Seite. Nur der Chat (Abschnitt 16) und Rohtext-Bloecke scrollen selbst. */
.akte h3 {
  margin-top: var(--space-5);
  font-size: var(--fs-gross);
}
.akte h4 {
  margin-top: var(--space-4);
  font-size: var(--fs-basis);
}
.akte p,
.akte ul,
.akte ol {
  margin-top: var(--space-2);
  font-size: var(--fs-klein);
}
.akte ul,
.akte ol {
  padding-left: var(--space-5);
}
.akte li + li {
  margin-top: 4px;
}
.akte hr {
  margin: var(--space-4) 0;
  border: none;
  border-top: 1px solid var(--line);
}
.akte code {
  padding: 1px 5px;
  border-radius: 6px;
  background: var(--flaeche-alt);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92em;
}
.akte > :first-child {
  margin-top: 0;
}
.akte .kv {
  margin-bottom: var(--space-5);
}
.akte-leiste {
  justify-content: flex-end;
  margin-bottom: var(--space-3);
}

/* --- Detail: Abstaende, Zurueck, Kopier-Zeile --------------------------- */
.zurueck {
  margin-bottom: var(--space-4);
}
#detail > .meldung {
  margin-bottom: var(--space-4);
}
.detail-grid + .card {
  margin-top: var(--space-4);
}
.kopier-zeile {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.kopier-zeile input {
  flex: 1 1 240px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-klein);
}
.kopier-zeile + .field-hinweis {
  display: block;
  margin-top: var(--space-3);
}

/* --- Formular: fehlende Nachbar-Kombination aus Abschnitt 9 -------------- */
/* Dort sind .field + .field und .field-reihe + .field-reihe gesetzt, die
   Mischung aus Einzelfeld und Feld-Reihe (Modal „Neuer Kunde") fehlt. */
.field + .field-reihe,
.field-reihe + .field {
  margin-top: var(--space-4);
}

/* --- Badges ohne Status-Bezug (Zustellung, Zaehler) --------------------- */
.badge-ok {
  background: var(--st-gebaut-bg);
  color: var(--st-gebaut-ink);
  border-color: rgba(31, 107, 58, .22);
}
.badge-warn {
  background: var(--st-fehler-bg);
  color: var(--st-fehler-ink);
  border-color: rgba(163, 33, 24, .24);
}


/* ==========================================================================
   19  Konfigurator & Katalog (F3)
   Ergaenzt die Komponenten, die 1-15 nicht abdecken: Options-Karten,
   Summenleiste, Praesentationsmodus, Katalog-Pflegeblocks.
   ========================================================================== */

/* --- Konfigurator: Gruppe ------------------------------------------------ */
/* Ueberschrift + Auswahl-Typ liegen im .card-kopf (Abschnitt 6). */
.konf-gruppe-name {
  font-size: var(--fs-gross);
}

/* --- Options-Karten ------------------------------------------------------
   Eine Reihe fuer single, dasselbe Gitter fuer multi: der Unterschied ist der
   Input-Typ, nicht das Layout. Nicht gewaehlt = Papierton auf der weissen
   Karte, gewaehlt = weiss mit ink-Rand. */
.konf-optionen {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2);
}
.konf-option {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--bg);
  cursor: pointer;
  transition: border-color .2s var(--ease), background .2s var(--ease);
  /* Die Karte IST ein label — die Formular-Regel aus Abschnitt 9 (13px, 600,
     ink-soft) wuerde sonst Name und Beschreibung fett und flau machen. */
  font-size: var(--fs-basis);
  font-weight: 400;
  color: var(--ink);
}
.konf-option:hover {
  border-color: var(--ink-faint);
}
/* Der Ring gehoert um die ganze Karte, nicht nur um das 18px-Kaestchen. */
.konf-option:focus-within {
  outline: 2px solid var(--c4);
  outline-offset: 2px;
}
.konf-option:has(input:checked) {
  border-color: var(--ink);
  background: var(--card);
}
.konf-option:has(input:checked) .konf-option-name {
  font-weight: 600;
}
/* Gesperrt heisst still, nicht blass: kein Flaechen-Alpha auf der Karte. Name
   und Beschreibung sind genau das, was der Kunde in der Praesentation lesen
   soll — ein Dimmen zieht sie unter AA. Die stummen Kaestchen, der
   zurueckgenommene Rand und das Banner tragen die Aussage. */
.konf-option:has(input:disabled) {
  cursor: default;
  border-color: var(--line);
}
/* Die getroffene Wahl bleibt sichtbar die getroffene Wahl — auch gesperrt.
   :has(input:disabled) hat dieselbe Spezifitaet wie :has(input:checked) und
   wuerde deren Rand sonst allein durch die Reihenfolge zuruecknehmen. */
.konf-option:has(input:checked:disabled) {
  border-color: var(--ink-soft);
}
.konf-option .auswahl-input {
  width: 18px;
  height: 18px;
  margin: 2px 0 0;
  accent-color: var(--c3);
  flex-shrink: 0;
}
.konf-option-text {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1 1 auto;
  min-width: 0;
}
.konf-option-name {
  font-weight: 500;
}
.konf-option-beschreibung {
  font-size: var(--fs-klein);
  color: var(--ink-faint);
}
/* Preis-Chip: --bg waere auf der Papier-Karte unsichtbar. */
.konf-option .badge.preis {
  align-self: flex-start;
  background: var(--card);
  border-color: var(--line-strong);
}
.konf-option-leer .konf-option-name {
  color: var(--ink-faint);
}

@media (min-width: 700px) {
  .konf-optionen {
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  }
}

/* --- Summenleiste --------------------------------------------------------
   Klebt am unteren Rand, solange gescrollt wird. Die negativen Seitenmargen
   ziehen die Flaeche bis an die main-Kante, sonst schauen die Karten links und
   rechts an der Leiste vorbei. */
.konf-leiste {
  position: sticky;
  bottom: 0;
  z-index: 50;
  margin: var(--space-5) calc(-1 * var(--gutter)) 0;
  padding: var(--space-2) var(--gutter) var(--space-3);
  background: rgba(251, 248, 243, .93);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-top: 1px solid var(--line-strong);
}
.konf-leiste-inner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
}
.konf-summe {
  display: flex;
  gap: var(--space-5);
}
.konf-summe-block {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.konf-summe dt {
  font-size: var(--fs-mikro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.konf-summe dd {
  font-family: 'Clash Display', sans-serif;
  font-weight: 600;
  font-size: 22px;
  line-height: 1.1;
}
.konf-stand {
  max-width: none;
  font-size: var(--fs-klein);
  color: var(--ink-faint);
}
.konf-stand-offen {
  color: var(--c3-text);
  font-weight: 500;
}
.konf-leiste-aktionen {
  flex: 1 0 100%;
}
@media (min-width: 1024px) {
  .konf-leiste {
    padding: var(--space-3) var(--gutter) var(--space-4);
  }
  .konf-leiste-aktionen {
    flex: 0 0 auto;
    margin-left: auto;
  }
}

/* --- Demo-Vorschau ------------------------------------------------------- */
.konf-demo {
  width: 100%;
  height: min(58vh, 520px);
  margin-bottom: var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--card);
}

/* --- Praesentationsmodus -------------------------------------------------
   Vor dem Kunden: kein Preis, keine Summe, keine internen Kennungen. Gewaehlt
   wird weiter — die Demo zieht live mit. */
/* Slug, Status und Auswahl-Typ sind interne Kennungen — vor dem Kunden weg.
   Genauso jede Meldung im Seiteninhalt (Sperr-Banner, Lade-Fehler) und der
   Toast-Stack: beide sprechen intern und tragen rohe Server-Fehler. Nichts
   geht dabei verloren — ein gescheiterter Speicherversuch holt die Auswahl
   ohnehin vom Server zurueck, und die Lade-Fehler-Box steht nach dem Ausstieg
   wieder da.
   Bewusst auf `main` begrenzt: die Meldung im Angebots-Dialog gehoert zum
   Arbeitsmodus, Dialoge liegen ausserhalb von main. */
.praesentation .topbar,
.praesentation .seiten-kopf-aktionen,
.praesentation .konf-leiste,
.praesentation .badge.preis,
.praesentation .konf-gruppe-typ,
.praesentation .konf-sub,
.praesentation .eyebrow,
.praesentation main .meldung,
.praesentation .toast-stack {
  display: none;
}
/* Oben Platz fuer den Ausstieg, der als fixes Element ueber der Seite liegt. */
.praesentation main {
  padding-top: var(--space-12);
  padding-bottom: var(--space-10);
}
@media (min-width: 700px) {
  .praesentation main {
    padding-top: var(--space-10);
  }
}
.praesentation .seiten-kopf {
  margin-bottom: var(--space-8);
}
.praesentation h1 {
  font-size: clamp(30px, 4.4vw, 44px);
}
.praesentation .konf-gruppe {
  padding: var(--space-6);
}
.praesentation .konf-gruppe-name {
  font-size: clamp(19px, 2.4vw, 23px);
}
.praesentation .konf-optionen {
  gap: var(--space-3);
}
.praesentation .konf-option {
  padding: var(--space-5);
  gap: var(--space-4);
  border-radius: var(--r-md);
}
.praesentation .konf-option-name {
  font-size: var(--fs-gross);
}
.praesentation .konf-option-beschreibung {
  font-size: var(--fs-basis);
  color: var(--ink-soft);
}
.praesentation .konf-option .auswahl-input {
  width: 21px;
  height: 21px;
  margin-top: 3px;
}
/* Ausstieg: liegt oben rechts und bleibt dort, gibt aber keinen Ton dazu. */
.praes-ende {
  position: fixed;
  top: var(--space-4);
  right: var(--gutter);
  z-index: 70;
  padding: 6px 10px;
  border-radius: var(--r-pill);
  font-size: var(--fs-klein);
  font-weight: 500;
  color: var(--ink-faint);
}
.praes-ende:hover {
  background: var(--card);
  color: var(--ink);
}

/* --- Katalog ------------------------------------------------------------- */
/* Sechs Spalten inkl. Beschreibung: enger als das wird die Zeile zehn Zeilen
   hoch. Mobil scrollt die Tabelle lieber seitwaerts (Pflege ist Desktop-Arbeit). */
.tabelle-wrap .kat-tabelle {
  min-width: 780px;
}
.kat-option-name {
  font-weight: 600;
}
.kat-option-beschreibung {
  display: block;
  margin-top: 3px;
  max-width: 56ch;
  font-size: var(--fs-klein);
  color: var(--ink-faint);
}
.kat-rechts {
  text-align: right;
}
.kat-aktionen {
  width: 1%;
  text-align: right;
  white-space: nowrap;
}
/* Pflege-Bloecke (Gruppe bearbeiten, neue Option) sitzen abgesetzt in der
   randlosen Karte — die Tabelle daneben bleibt ruhig. */
.kat-block {
  padding: var(--space-5);
  background: var(--flaeche-alt);
  border-bottom: 1px solid var(--line);
}
.kat-neu {
  border-bottom: none;
  border-top: 1px solid var(--line);
}
.kat-neu h3 {
  margin-bottom: var(--space-3);
  font-size: var(--fs-basis);
}
.kat-edit-zeile > td {
  padding: var(--space-4);
  background: var(--flaeche-alt);
}
.kat-form-aktionen {
  margin-top: var(--space-4);
}
.kat-form .fehler:empty {
  display: none;
}

/* --- Formular: fehlende Nachbar-Kombinationen aus Abschnitt 9 ------------- */
/* Dort stehen .field + .field und .field-reihe + .field-reihe; gestapelte
   Schalter (Dialog „Angebot erzeugen“) fehlen. */
.check + .check,
.check + .field-hinweis {
  margin-top: var(--space-2);
}
.check + .field,
.field-hinweis + .field {
  margin-top: var(--space-4);
}
/* Zahlenfelder mit zwei Ziffern brauchen keine Dialogbreite. */
.field-schmal input {
  max-width: 140px;
}
/* Erklaersatz und Werteliste im Dialog kleben sonst aneinander. */
.modal p + .kv {
  margin-top: var(--space-4);
}


/* ==========================================================================
   20  Statistik (F4)
   Zeitraum-Schalter und das handgezeichnete Balkendiagramm. Farben und
   Schriftgroessen des Diagramms stehen HIER — das Skript setzt nur Geometrie
   (CSP: style-src 'self', also kein Inline-Style).
   ========================================================================== */

/* --- Zeitraum-Schalter ---------------------------------------------------- */
/* Ein Segment-Schalter, kein Select: drei Werte, immer alle sichtbar.
   Gedrueckt = ink-Flaeche, wie der primaere Knopf. */
.zeitraum {
  display: inline-flex;
  padding: 3px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background: var(--card);
}
.zeitraum-taste {
  min-height: 30px;
  padding: 5px 14px;
  border-radius: var(--r-pill);
  font-size: var(--fs-klein);
  font-weight: 500;
  white-space: nowrap;
  color: var(--ink-faint);
  transition: background .2s var(--ease), color .2s var(--ease);
}
.zeitraum-taste:hover {
  color: var(--ink);
}
.zeitraum-taste[aria-pressed="true"] {
  background: var(--ink);
  color: var(--bg);
  font-weight: 600;
}
.zeitraum-taste:disabled {
  cursor: progress;
}

/* --- Diagramm-Flaeche ----------------------------------------------------- */
/* Das SVG kommt in echten Pixeln aus dem Skript (Beschriftung soll nicht
   mitskalieren). auto statt hidden: sollte der Container beim Zeichnen noch
   keine Breite haben, ist die Ersatzbreite scrollbar statt abgeschnitten. */
.diagramm {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.diagramm svg {
  display: block;
}
/* Platzhalter genau so hoch wie das Diagramm danach — kein Sprung beim Wechsel. */
.dg-skelett {
  height: 200px;
}
@media (min-width: 560px) {
  .dg-skelett {
    height: 240px;
  }
}

/* Eine Farbe fuer alle Balken, Akzent nur unter dem Zeiger — das Diagramm
   zeigt eine Reihe, keine Kategorien. */
.dg-balken {
  fill: var(--ink);
  transition: fill .15s var(--ease);
}
.dg-balken:hover {
  fill: var(--c3-text);
}

.dg-raster {
  stroke: var(--line);
  stroke-width: 1;
  shape-rendering: crispEdges;
}
.dg-achse {
  stroke: var(--line-strong);
  stroke-width: 1;
  shape-rendering: crispEdges;
}

/* SVG-Text faerbt ueber fill, nicht ueber color. */
.dg-tick,
.dg-datum {
  fill: var(--ink-faint);
  font-size: var(--fs-mikro);
  font-variant-numeric: tabular-nums;
}

/* --- Leer-Zustand: Pfade im Satz ------------------------------------------ */
/* .mono traegt word-break: break-all fuer lange Tokens — in einem Fliesstext
   zerlegt das "ops/README.md" mitten im Wort. Im Satz bricht nur der Satz. */
.leer .mono {
  word-break: normal;
}

/* --- Kennzahl-Kacheln ----------------------------------------------------- */
/* Zwei Kacheln nebeneinander, auch auf dem Handy — und auf dem Desktop
   gedeckelt: ueber die ganze Inhaltsbreite gezogen waeren zwei Zahlen verloren. */
#kacheln {
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
}
@media (min-width: 1024px) {
  #kacheln {
    grid-template-columns: repeat(2, minmax(0, 260px));
    gap: var(--space-4);
  }
}


/* ==========================================================================
   21  Jobs (J2)
   Build-Queue im Kunden-Detail: Status-Badges der jobs-Tabelle, die Job-Zeile,
   der Hinweis auf einen laufenden Build und der Log-Dialog.
   ========================================================================== */

/* Job-Status (queued | running | done | failed | cancelled) — dieselben
   Signalfarben wie das Status-Enum in Abschnitt 10, eigene Klassen, damit sich
   die beiden Wertebereiche nicht ins Gehege kommen. */
.badge.job-queued {
  background: var(--st-interview-bg);
  color: var(--st-interview-ink);
  border-color: rgba(107, 78, 0, .22);
}
.badge.job-running {
  background: var(--st-freigegeben-bg);
  color: var(--st-freigegeben-ink);
  border-color: rgba(27, 75, 143, .22);
}
.badge.job-done {
  background: var(--st-gebaut-bg);
  color: var(--st-gebaut-ink);
  border-color: rgba(31, 107, 58, .22);
}
.badge.job-failed {
  background: var(--st-fehler-bg);
  color: var(--st-fehler-ink);
  border-color: rgba(163, 33, 24, .24);
}
.badge.job-cancelled {
  background: var(--flaeche-alt);
  color: var(--ink-soft);
}

/* Laufender Build: im Detail-Kopf als Badge, in der Pipeline-Zeile als
   Textzeile unter dem Status — dort steht schon die Push-Warnung, und ein
   zweites Badge in derselben Zelle waere eine Farbe zu viel. */
.badge.job-laeuft {
  background: var(--st-freigegeben-bg);
  color: var(--st-freigegeben-ink);
  border-color: rgba(27, 75, 143, .22);
}
.job-flag {
  font-size: var(--fs-mikro);
  font-weight: 700;
  color: var(--st-freigegeben-ink);
}

/* --- Job-Zeile ----------------------------------------------------------- */
.job {
  padding: var(--space-3) 0;
}
.job:first-child {
  padding-top: 0;
}
.job:last-child {
  padding-bottom: 0;
}
.job + .job {
  border-top: 1px solid var(--line);
}
.job-kopf {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
}
.job-typ {
  font-size: var(--fs-klein);
  font-weight: 600;
}
.job-phase,
.job-zeit {
  font-size: var(--fs-klein);
  color: var(--ink-faint);
}
.job-zeit {
  font-variant-numeric: tabular-nums;
}
/* Fehlertext kommt aus dem Build-Log: beliebig lang, ohne Umbruchstellen. */
.job-fehler {
  max-width: none;
  margin-top: var(--space-2);
  font-size: var(--fs-klein);
  color: var(--warn);
  overflow-wrap: anywhere;
}

/* --- Dialoge: Build-Bestaetigung und Log --------------------------------- */
.modal .kv + .meldung {
  margin-top: var(--space-4);
}
/* Log-Zeilen sind lang — die 520px des Standard-Dialogs zerhacken sie. */
dialog.modal.modal-breit {
  width: min(860px, calc(100vw - 2 * var(--gutter)));
}
.modal .roh {
  margin-top: var(--space-2);
}
