/* ============================================================
   AURORA - makler-frontend stylesheet
   Extracted from docs/design-reference/aurora-clickdummy.html,
   the binding design reference.

   White-label: a tenant sets --brand (and may override any other
   token) in its file under .json/tenants/, injected as an inline
   :root block. Every tint and the aurora companions derive from
   --brand via color-mix, so no component may hard-code a brand
   colour. --on-brand carries text on brand surfaces, for tenants
   whose brand colour is too light for white.

   The bucket colours (--ok/--warn/--err) are meaning, not brand,
   and stay the same for every tenant. Gradients appear ONLY in
   hero surfaces and progress indicators.
   ============================================================ */

:root {
  /* --- White-label: change --brand and the whole draft recolors --- */
  --brand:        #2E5BE3;
  --brand-ink:    color-mix(in srgb, var(--brand) 78%, #0B1B3A);
  --brand-tint:   color-mix(in srgb, var(--brand) 9%, #FFFFFF);
  --brand-tint-2: color-mix(in srgb, var(--brand) 16%, #FFFFFF);
  --brand-soft:   color-mix(in srgb, var(--brand) 30%, #FFFFFF);
  /* Text and icons on brand-coloured surfaces. A tenant with a light brand
     colour overrides this in its tenant file. */
  --on-brand:     #FFFFFF;

  /* Aurora companions, derived from brand so recoloring stays coherent */
  --aurora-teal:   color-mix(in oklch, var(--brand) 42%, #14C7A8);
  --aurora-violet: color-mix(in oklch, var(--brand) 52%, #8B5CF6);
  --aurora-mint:   color-mix(in oklch, var(--brand) 26%, #8CE3A9);
  --aurora: linear-gradient(100deg,
      var(--brand) 0%,
      var(--aurora-violet) 28%,
      var(--aurora-teal) 62%,
      var(--aurora-mint) 88%,
      var(--brand) 100%);

  /* Surfaces */
  --bg:        #F5F7FC;
  --surface:   #FFFFFF;
  --surface-2: #FAFBFE;
  --line:      #E4E9F4;
  --line-soft: #EDF1F9;

  /* Ink */
  --ink:       #17203A;
  --ink-2:     #4A5670;
  --ink-3:     #7C879F;

  /* Semantic buckets (cool-tinted, consistent everywhere) */
  --ok:        #1B8A5A;
  --ok-bg:     #E4F6EC;
  --ok-line:   #BCE6CF;
  --warn:      #A16A07;
  --warn-bg:   #FCF2DC;
  --warn-line: #F0DCAE;
  --err:       #C2373F;
  --err-bg:    #FCE9EA;
  --err-line:  #F3C8CB;

  /* Maschinell erzeugt. Eine Bedeutungsfarbe wie ok/warn/err, KEINE Markenfarbe:
     aus --brand abgeleitet hiesse "vom System vorgeschlagen" bei jedem Mandanten
     etwas anderes. Violett, weil gruen, gelb und rot belegt sind und blau die
     Standardmarke ist. Sie markiert Herkunft, nicht Klugheit - und faellt weg,
     sobald der Nutzer bestaetigt hat. Sie traegt nie allein, immer mit eigenem
     Zeichen, damit sie den Mandanten mit violetter Marke ueberlebt. Und sie
     markiert die Ausnahme: ist der halbe Bildschirm violett, sagt sie nichts mehr. */
  --ki:        #7A3FD4;
  --ki-ink:    #5D2BA8;
  --ki-bg:     #F3EDFD;
  --ki-line:   #DDCBF7;
  --ki-soft:   #EEE5FB;

  /* Shape */
  --radius:    14px;
  --radius-sm: 9px;
  --shadow:    0 1px 2px rgba(23,32,58,.05), 0 8px 24px -12px rgba(23,32,58,.12);
  --shadow-lg: 0 2px 6px rgba(23,32,58,.06), 0 24px 48px -20px rgba(23,32,58,.22);

  --font: -apple-system, BlinkMacSystemFont, system-ui, "Avenir Next", "Segoe UI", sans-serif;
  --mono: "SF Mono", Menlo, ui-monospace, monospace;
  --schriftgroesse: 16px;

  /* Layout density. Paddings that carry the breathing room of the screens are
     multiplied by this, so a tenant can tighten or widen the interface
     without touching type size. */
  --dichte: 1;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Components below set `display`, which outranks the browser's `[hidden]`
   rule and would leave elements marked hidden on screen (the upload step
   showed an empty "Bereit zum Hochladen" row before a file was picked). */
[hidden] { display: none !important; }

html { font-size: var(--schriftgroesse); }

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.5;
  font-size: .9375rem;
  -webkit-font-smoothing: antialiased;
}

svg { display: block; flex-shrink: 0; }

button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 4px;
}

::placeholder { color: var(--ink-3); }

.num { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); font-size: .85em; }

/* ============================================================
   SIGNATURE: the aurora fill (progress + hero only)
   ============================================================ */
.aurora-bar {
  height: 10px;
  border-radius: 999px;
  background: var(--line-soft);
  overflow: hidden;
  position: relative;
}
.aurora-bar.is-slim { height: 6px; }
.aurora-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--aurora);
  background-size: 320% 100%;
  animation: aurora-flow 7s ease-in-out infinite;
  position: relative;
}
.aurora-fill::after {
  /* soft breathing light on top of the gradient */
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  background-size: 200% 100%;
  animation: aurora-glint 3.2s linear infinite;
  border-radius: inherit;
}
@keyframes aurora-flow {
  0%, 100% { background-position: 0% 0; }
  50%      { background-position: 100% 0; }
}
@keyframes aurora-glint {
  from { background-position: 180% 0; }
  to   { background-position: -80% 0; }
}
.aurora-hero {
  background:
    radial-gradient(90rem 30rem at -10% -60%, color-mix(in srgb, var(--aurora-violet) 22%, transparent), transparent 60%),
    radial-gradient(70rem 26rem at 70% -70%, color-mix(in srgb, var(--aurora-teal) 20%, transparent), transparent 60%),
    radial-gradient(50rem 22rem at 110% 40%, color-mix(in srgb, var(--aurora-mint) 18%, transparent), transparent 65%),
    var(--surface);
}
@media (prefers-reduced-motion: reduce) {
  .aurora-fill, .aurora-fill::after { animation: none; }
  * { transition-duration: .01ms !important; }
}

/* ============================================================
   LOGIN
   ============================================================ */
.auth-layout {
  min-height: 100vh;
  display: grid;
  grid-template-columns: minmax(380px, 44%) 1fr;
}
.auth-pane {
  position: relative;
  color: var(--on-brand);
  padding: 3.5rem 3.25rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background:
    radial-gradient(60rem 42rem at 120% -20%, color-mix(in srgb, var(--aurora-teal) 55%, transparent), transparent 60%),
    radial-gradient(50rem 40rem at -30% 110%, color-mix(in srgb, var(--aurora-violet) 60%, transparent), transparent 55%),
    radial-gradient(34rem 26rem at 60% 120%, color-mix(in srgb, var(--aurora-mint) 40%, transparent), transparent 60%),
    linear-gradient(160deg, var(--brand-ink), var(--brand));
}
.auth-pane .brand-row { display: flex; align-items: center; gap: .75rem; }
.auth-pane .brand-row strong { font-size: 1.05rem; letter-spacing: .01em; }
.auth-claim h1 {
  font-size: clamp(1.7rem, 2.6vw, 2.3rem);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.18;
  max-width: 22ch;
}
.auth-claim p { margin-top: .9rem; max-width: 42ch; color: color-mix(in srgb, var(--on-brand) 82%, transparent); }
.auth-stats {
  display: flex; gap: 2.25rem; flex-wrap: wrap;
  padding-top: 1.5rem;
  border-top: 1px solid color-mix(in srgb, var(--on-brand) 22%, transparent);
}
.auth-stats .num { font-size: 1.35rem; font-weight: 700; letter-spacing: -.01em; }

/* ---------- Login motifs ----------
   Both live on the tenant's own tones: the evaluation colours for the states
   they name, --on-brand for everything else. No literal colour appears here,
   so another tenant recolours the motif with the rest of the interface. */

/* Variant A: the portfolio as what it is - many single contracts, ordered by
   the state the portal sorts them into. */
.bestandsspiegel {
  padding-top: 1.6rem;
  border-top: 1px solid color-mix(in srgb, var(--on-brand) 22%, transparent);
}
.bs-feld {
  display: grid;
  grid-template-columns: repeat(18, 1fr);
  gap: 5px;
  max-width: 30rem;
}
.bs-marke {
  aspect-ratio: 1;
  border-radius: 2px;
  opacity: 0;
  animation: bs-setzen .5s ease-out forwards;
  /* left to right, the order the evaluation itself works in */
  animation-delay: calc(var(--nr) * 9ms);
}
.bs-ok { background: color-mix(in srgb, var(--ok) 62%, var(--on-brand)); }
.bs-warn { background: color-mix(in srgb, var(--warn) 55%, var(--on-brand)); }
.bs-err { background: color-mix(in srgb, var(--err) 62%, var(--on-brand)); }
@keyframes bs-setzen {
  from { opacity: 0; transform: translateY(3px); }
  to { opacity: 1; transform: none; }
}
.bs-legende {
  display: flex; flex-wrap: wrap; gap: 1.4rem;
  margin-top: 1.1rem;
  font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
  color: color-mix(in srgb, var(--on-brand) 68%, transparent);
}
.bs-legende span { display: inline-flex; align-items: center; gap: .5rem; }
.bs-punkt { width: 8px; height: 8px; border-radius: 2px; }

/* Variant B: the column header row of a foreign file meeting the fields of
   the Verwaltung - the moment the work happens in. */
.zuordnung {
  display: grid; gap: .5rem;
  padding-top: 1.6rem;
  max-width: 30rem;
  border-top: 1px solid color-mix(in srgb, var(--on-brand) 22%, transparent);
}
.zo-reihe {
  display: grid; grid-template-columns: 1fr 20px 1fr;
  align-items: center; gap: .8rem;
  opacity: 0;
  animation: zo-treffen .45s ease-out forwards;
  animation-delay: calc(var(--nr) * 110ms);
}
.zo-quelle, .zo-ziel {
  padding: .34rem .6rem;
  border-radius: 6px;
  font-size: .78rem;
  border: 1px solid color-mix(in srgb, var(--on-brand) 22%, transparent);
}
.zo-quelle {
  font-family: var(--mono);
  color: color-mix(in srgb, var(--on-brand) 88%, transparent);
  background: color-mix(in srgb, var(--on-brand) 8%, transparent);
}
.zo-ziel {
  font-weight: 600;
  color: var(--on-brand);
  background: color-mix(in srgb, var(--on-brand) 16%, transparent);
}
.zo-pfeil { color: color-mix(in srgb, var(--on-brand) 45%, transparent); }
.zo-offen .zo-ziel {
  border-style: dashed;
  background: none;
  font-weight: 400;
  color: color-mix(in srgb, var(--on-brand) 55%, transparent);
}
@keyframes zo-treffen {
  from { opacity: 0; transform: translateX(-6px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .bs-marke, .zo-reihe { animation: none; opacity: 1; }
}
.auth-stats span { display: block; font-size: .78rem; color: color-mix(in srgb, var(--on-brand) 75%, transparent); margin-top: .1rem; }

.auth-form-pane {
  display: flex; align-items: center; justify-content: center;
  padding: 2.5rem;
  background: var(--bg);
}
.auth-card {
  width: min(400px, 100%);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: calc(var(--radius) + 4px);
  box-shadow: var(--shadow-lg);
  padding: 2.5rem 2.25rem 2rem;
}
.tenant-logo {
  display: flex; align-items: center; gap: .7rem;
  margin-bottom: 1.75rem;
}
/* ONE definition of the mark box. Every place that shows a tenant's mark -
   login card, sidebar, appearance preview, tenant list - uses this class and
   overrides nothing but its size. The preview used to draw a bare SVG with no
   container at all, so a mark without its own surface (a logo file, or form /
   background set to "ohne") appeared there without the tinted box it wears
   everywhere else, and the preview showed something the portal never rendered. */
.mark {
  border-radius: 12px;
  background: var(--brand-tint-2);
  color: var(--brand);
  display: grid; place-items: center;
}
.tenant-logo .mark,
.vorschau-marke .mark { width: 44px; height: 44px; }
/* A configured mark brings its own shape and background - the container
   would only frame it a second time. */
.mark-frei { background: none !important; }
.tenant-logo strong { font-size: 1.06rem; letter-spacing: -.01em; }
.tenant-logo span { display: block; font-size: .76rem; color: var(--ink-3); }
.auth-card h2 { font-size: 1.28rem; font-weight: 700; letter-spacing: -.015em; }
.auth-card > p { color: var(--ink-2); font-size: .88rem; margin: .3rem 0 1.5rem; }

.field { margin-bottom: 1rem; }
.field label {
  display: block;
  font-size: .8rem; font-weight: 600;
  color: var(--ink-2);
  margin-bottom: .35rem;
}
/* --- Auswahl- und Eingabefelder: EINE Basis (#47) --------------------------
   Sieben Bloecke deklarierten dasselbe leicht anders: Hoehen von 30 bis 42px,
   drei Lesarten des Fokus, ein eigener Pfeil hier und der native dort - und
   .bericht-zuschnitt fiel ganz auf den Browser durch. Die Basis steht VOR den
   Sonderbloecken, damit deren Abweichungen (nur noch Groessen und Breiten) per
   Reihenfolge gewinnen. Ein neues Formular braucht keinen eigenen Block:
   in diese Listen aufnehmen genuegt. */
.field input, .field select, .field textarea,
.feld input[type=text], .feld select,
.map-target select,
.vorschlag-leiste select,
.probe-form input[type="text"], .probe-form select,
.filterfelder input, .filterfelder select,
.aktionsleiste-form select,
.hygiene-zeile input, .hygiene-zeile select,
.hygiene-filterzeile select,
.bericht-zuschnitt input, .bericht-zuschnitt select {
  font: inherit; font-size: .88rem; color: var(--ink);
  min-height: 40px; padding: .45rem .7rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background-color: var(--surface);
  transition: border-color .12s, box-shadow .12s;
}
/* Selects tragen ueberall denselben eigenen Pfeil statt des Systempfeils. */
.field select, .feld select, .map-target select, .vorschlag-leiste select,
.probe-form select, .filterfelder select, .aktionsleiste-form select,
.hygiene-zeile select, .hygiene-filterzeile select,
.bericht-zuschnitt select {
  appearance: none; -webkit-appearance: none;
  cursor: pointer; text-overflow: ellipsis;
  padding-right: 2.1rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%234A5670' stroke-width='2.2' 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 .6rem center;
}
.field input:hover, .field select:hover,
.feld input[type=text]:hover, .feld select:hover,
.map-target select:hover,
.vorschlag-leiste select:hover,
.probe-form input[type="text"]:hover, .probe-form select:hover,
.filterfelder input:hover, .filterfelder select:hover,
.aktionsleiste-form select:hover,
.hygiene-zeile input:hover, .hygiene-zeile select:hover,
.hygiene-filterzeile select:hover,
.bericht-zuschnitt input:hover, .bericht-zuschnitt select:hover {
  border-color: var(--brand-soft);
}
/* EIN Fokus: Rahmen plus Ring. Nicht drei Lesarten derselben Frage. */
.field input:focus, .field select:focus, .field textarea:focus,
.feld input[type=text]:focus, .feld select:focus,
.map-target select:focus,
.vorschlag-leiste select:focus,
.probe-form input[type="text"]:focus, .probe-form select:focus,
.filterfelder input:focus, .filterfelder select:focus,
.aktionsleiste-form select:focus,
.hygiene-zeile input:focus, .hygiene-zeile select:focus,
.hygiene-filterzeile select:focus,
.bericht-zuschnitt input:focus, .bericht-zuschnitt select:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-tint-2);
}
.field input, .field select, .field textarea { width: 100%; }
.field .hint { font-size: .76rem; color: var(--ink-3); margin-top: .3rem; }

.auth-meta {
  display: flex; justify-content: space-between; align-items: center;
  margin: .25rem 0 1.25rem;
  font-size: .82rem;
}
.auth-meta a { color: var(--brand); text-decoration: none; font-weight: 600; }
.auth-meta a:hover { text-decoration: underline; }

.auth-foot {
  margin-top: 1.5rem; padding-top: 1.1rem;
  border-top: 1px solid var(--line-soft);
  font-size: .76rem; color: var(--ink-3);
  text-align: center;
}

/* ============================================================
   BUTTONS
   ============================================================ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 42px;
  padding: .55rem 1.15rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-weight: 600; font-size: .9rem;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s, border-color .15s, box-shadow .15s, transform .1s;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
  background: var(--brand); color: var(--on-brand);
  box-shadow: 0 1px 2px rgba(23,32,58,.15), 0 6px 14px -6px color-mix(in srgb, var(--brand) 55%, transparent);
}
.btn-primary:hover { background: var(--brand-ink); }
.btn-secondary {
  background: var(--surface); color: var(--ink);
  border-color: var(--line);
  box-shadow: 0 1px 2px rgba(23,32,58,.05);
}
.btn-secondary:hover { border-color: var(--brand-soft); background: var(--surface-2); }
.btn-ghost { background: transparent; color: var(--brand); }
.btn-ghost:hover { background: var(--brand-tint); }
/* Destructive actions. Deliberately not the brand colour: deleting a bestand
   must not look like the button the user is meant to press. */
.btn-danger { background: var(--err-bg); color: var(--err); border-color: var(--err-line); }
.btn-danger:hover { background: var(--err); color: #fff; border-color: var(--err); }
.btn-block { width: 100%; }

/* ============================================================
   APP SHELL
   ============================================================ */
.shell { display: grid; grid-template-columns: 248px 1fr; min-height: 100dvh; }

.sidebar {
  background: var(--surface);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  padding: 1.25rem 1rem;
  position: sticky; top: 0; height: 100vh;
}
.sidebar .brand {
  display: flex; align-items: center; gap: .65rem;
  padding: .35rem .5rem 1.1rem;
}
.sidebar .brand .mark,
.mandanten-zeichen .mark { width: 36px; height: 36px; border-radius: 10px; }
.sidebar .brand strong { font-size: .96rem; letter-spacing: -.01em; }
.sidebar .brand span { display: block; font-size: .7rem; color: var(--ink-3); }

.nav-group { margin-top: .5rem; }
.nav-label {
  font-size: .68rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3);
  padding: .9rem .6rem .4rem;
}
.nav-item {
  display: flex; align-items: center; gap: .7rem;
  width: 100%;
  padding: calc(.6rem * var(--dichte)) .65rem;
  margin-bottom: 2px;
  border: none; background: none;
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  font-weight: 550; font-size: .9rem;
  cursor: pointer; text-align: left;
  transition: background .12s, color .12s;
}
.nav-item svg { color: var(--ink-3); transition: color .12s; }
.nav-item:hover { background: var(--surface-2); color: var(--ink); }
.nav-item.is-active {
  background: var(--brand-tint);
  color: var(--brand-ink);
  font-weight: 650;
}
.nav-item.is-active svg { color: var(--brand); }
.nav-item .count {
  margin-left: auto;
  font-size: .74rem; font-weight: 650;
  color: var(--ink-3);
  background: var(--line-soft);
  border-radius: 999px;
  padding: .05rem .5rem;
}

.sidebar-foot {
  margin-top: auto;
  border-top: 1px solid var(--line-soft);
  padding-top: .9rem;
  display: flex; align-items: center; gap: .65rem;
}
.avatar {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--brand-tint-2); color: var(--brand-ink);
  display: grid; place-items: center;
  font-size: .78rem; font-weight: 700;
}
.sidebar-foot strong { display: block; font-size: .84rem; }
.sidebar-foot span { font-size: .72rem; color: var(--ink-3); }

/* ---------- Topbar + main ---------- */
.main { display: flex; flex-direction: column; min-width: 0; }
.topbar {
  display: flex; align-items: center; gap: 1rem;
  padding: .9rem 2rem;
  background: color-mix(in srgb, var(--bg) 82%, #FFFFFF);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 10;
  backdrop-filter: blur(8px);
}
.topbar h1 { font-size: 1.02rem; font-weight: 700; letter-spacing: -.01em; }
.topbar .crumb { font-size: .8rem; color: var(--ink-3); }
.topbar-spacer { flex: 1; }
.topbar .btn { min-height: 38px; }

.content {
  padding: calc(1.75rem * var(--dichte)) calc(2rem * var(--dichte)) 3rem;
  max-width: 1240px; width: 100%; margin: 0 auto;
  /* Fills the space left between topbar and footer so the footer sits at the
     bottom of a short page instead of halfway up it. Growing only (never
     shrinking) keeps long pages at their natural height. */
  flex: 1 0 auto;
}

/* ============================================================
   CARDS + GENERIC BLOCKS
   ============================================================ */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.card-pad { padding: calc(1.35rem * var(--dichte)) calc(1.5rem * var(--dichte)); }
.card h3 { font-size: .98rem; font-weight: 700; letter-spacing: -.01em; }
.card .sub { font-size: .82rem; color: var(--ink-2); margin-top: .15rem; }
.card-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  margin-bottom: 1.1rem;
}

.badge {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .76rem; font-weight: 650;
  padding: .18rem .6rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-2);
  white-space: nowrap;
}
.badge .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.badge-ok   { color: var(--ok);   background: var(--ok-bg);   border-color: var(--ok-line); }
.badge-warn { color: var(--warn); background: var(--warn-bg); border-color: var(--warn-line); }
.badge-err  { color: var(--err);  background: var(--err-bg);  border-color: var(--err-line); }
.badge-brand { color: var(--brand-ink); background: var(--brand-tint); border-color: var(--brand-tint-2); }

/* ============================================================
   DASHBOARD
   ============================================================ */
.hero {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.6rem 1.75rem;
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  flex-wrap: wrap;
  margin-bottom: 1.5rem;
}
.hero h2 { font-size: 1.35rem; font-weight: 700; letter-spacing: -.02em; }
.hero p { color: var(--ink-2); margin-top: .25rem; max-width: 56ch; }
.hero .hero-actions { display: flex; gap: .7rem; flex-wrap: wrap; }

.kpi-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.1rem;
  margin-bottom: 1.5rem;
}
/* Tiles in a row are equal height (grid stretch). Laying the tile out as a
   column with the note pushed to the foot keeps label and value at the same
   height in every tile, whether or not it carries a note - otherwise the note
   pulled its neighbour's value out of line. */
.kpi { padding: 1.2rem 1.4rem; display: flex; flex-direction: column; }
.kpi .kpi-label {
  display: flex; align-items: center; gap: .5rem;
  font-size: .8rem; font-weight: 600; color: var(--ink-2);
}
.kpi .kpi-label svg { color: var(--brand); }
.kpi .kpi-value {
  font-size: 1.9rem; font-weight: 700; letter-spacing: -.025em;
  margin-top: .4rem;
  font-variant-numeric: tabular-nums;
}
/* A value the backend does not have is a placeholder, not a figure - it must
   not carry the visual weight of a number. */
.kpi .kpi-value.is-leer { color: var(--ink-3); font-weight: 600; }
.kpi .kpi-note { font-size: .78rem; color: var(--ink-3); margin-top: auto; padding-top: .5rem; }
.kpi .kpi-note .up { color: var(--ok); font-weight: 650; }

.dash-grid {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 1.1rem;
  align-items: start;
}
.dash-col { display: grid; gap: 1.1rem; }

/* Bucket distribution */
.bucket-stack {
  display: flex; height: 14px; border-radius: 999px; overflow: hidden;
  margin: 1rem 0 1.2rem;
}
.bucket-stack .seg-ok   { background: color-mix(in srgb, var(--ok) 78%, #fff); }
.bucket-stack .seg-warn { background: color-mix(in srgb, var(--warn) 62%, #FFD98A); }
.bucket-stack .seg-err  { background: color-mix(in srgb, var(--err) 80%, #fff); }
.bucket-legend { display: grid; gap: .45rem; }
.bucket-row {
  display: flex; align-items: center; gap: .7rem;
  width: 100%;
  padding: .55rem .7rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none; cursor: pointer; text-align: left;
  font-size: .88rem;
  transition: background .12s, border-color .12s;
}
.bucket-row:hover { background: var(--surface-2); border-color: var(--line-soft); }
.bucket-row .swatch { width: 10px; height: 10px; border-radius: 3px; }
.bucket-row .name { font-weight: 600; }
.bucket-row .val { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.bucket-row .pct { color: var(--ink-3); font-size: .8rem; width: 3.6rem; text-align: right; font-variant-numeric: tabular-nums; }
.bucket-row svg { color: var(--ink-3); }

/* Import card */
.import-live .import-title { display: flex; align-items: center; gap: .6rem; font-weight: 700; }
.import-live .pulse {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--aurora-teal);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--aurora-teal) 45%, transparent);
  animation: pulse 2s infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--aurora-teal) 45%, transparent); }
  70%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) { .import-live .pulse { animation: none; } }
.import-meta {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: .82rem; color: var(--ink-2);
  margin: 1rem 0 .5rem;
}
.import-meta .pct-big { font-size: 1.25rem; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }

/* Mini stat bars */
.mini-bars {
  display: flex; align-items: flex-end; gap: .55rem;
  height: 96px; margin-top: 1.1rem;
}
.mini-bars .bar {
  flex: 1;
  background: var(--brand-tint-2);
  border-radius: 6px 6px 3px 3px;
  position: relative;
  min-width: 0;
  transition: background .15s;
}
.mini-bars .bar:hover { background: var(--brand-soft); }
.mini-bars .bar.is-current { background: var(--brand); }
.mini-bars .bar span {
  position: absolute; top: calc(100% + .4rem); left: 50%; transform: translateX(-50%);
  font-size: .68rem; color: var(--ink-3); white-space: nowrap;
}
.mini-caption { margin-top: 2rem; font-size: .78rem; color: var(--ink-3); }

/* ============================================================
   DASHBOARD - die Migrationsstrecke
   The funnel from an uploaded file to a rated contract. Every
   stage is a link to the list behind its number; the stage a
   record gets stuck on carries the loss and the warn colour.
   ============================================================ */
.strecke { display: flex; align-items: stretch; gap: .5rem; flex-wrap: wrap; }
.strecke-pfeil { display: flex; align-items: center; color: var(--ink-3); flex-shrink: 0; }
.strecke-stufe {
  flex: 1 1 12rem; min-width: 0;
  display: flex; flex-direction: column;
  padding: calc(1.1rem * var(--dichte)) calc(1.15rem * var(--dichte));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  text-decoration: none; color: inherit;
  transition: border-color .12s, box-shadow .12s;
}
a.strecke-stufe:hover { border-color: var(--brand-soft); box-shadow: var(--shadow-lg); }
.strecke-stufe .st-label {
  font-size: .72rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3);
}
.strecke-stufe .st-val {
  font-size: 1.75rem; font-weight: 700; letter-spacing: -.03em;
  margin-top: .3rem;
  font-variant-numeric: tabular-nums;
}
/* A stage the backend could not answer is a placeholder, not a figure - same
   rule as the KPI tiles: it must not carry the weight of a number. */
.strecke-stufe .st-val.is-leer { color: var(--ink-3); font-weight: 600; }
.strecke-stufe .st-unit { font-size: .78rem; color: var(--ink-3); }
/* Label, value and unit are one line each, so a fixed gap keeps the bars of
   all stages on the same baseline. The loss line takes the slack instead, and
   a stage without one simply ends after its bar. */
.strecke-stufe .st-bar {
  display: block; height: 5px; margin-top: .85rem;
  border-radius: 999px; background: var(--line-soft); overflow: hidden;
}
.strecke-stufe .st-bar i { display: block; height: 100%; border-radius: 999px; background: var(--brand); }
.strecke-stufe .st-verlust {
  display: inline-flex; align-items: center; gap: .3rem;
  margin-top: auto; padding-top: .55rem;
  font-size: .74rem; font-weight: 650; color: var(--err);
}
.strecke-stufe.is-stau {
  border-color: var(--warn-line);
  background: color-mix(in srgb, var(--warn-bg) 40%, var(--surface));
}
/* The value itself keeps its ink: on the stage records fail to reach, the
   figure shown is the ones that made it, and colouring 25 arrivals like a
   fault reads as though the arrivals were the problem. */
.strecke-stufe.is-stau .st-bar i { background: var(--warn); }
/* The funnel of a portfolio that has not started: shape without figures. */
.strecke-stufe.is-kalt { background: var(--surface-2); box-shadow: none; }

.strecke-leer-zeichen {
  width: 56px; height: 56px; border-radius: 16px;
  background: var(--brand-tint); color: var(--brand);
  display: grid; place-items: center;
  margin: 0 auto 1rem;
}

/* The bottleneck band: what holds records back, and where to clear it. */
.engpass {
  margin-top: 1.1rem;
  padding: calc(1.15rem * var(--dichte)) calc(1.35rem * var(--dichte));
  border: 1px solid var(--warn-line);
  border-left: 3px solid var(--warn);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--warn-bg) 55%, var(--surface));
}
.engpass > strong { display: block; font-size: 1rem; color: var(--warn); }
.engpass > p { font-size: .86rem; color: var(--ink-2); margin-top: .3rem; max-width: 86ch; }
.engpass.is-fertig {
  border-color: var(--ok-line); border-left-color: var(--ok);
  background: color-mix(in srgb, var(--ok-bg) 55%, var(--surface));
}
.engpass.is-fertig > strong { color: var(--ok); }
/* Two more weights for the data quality findings, same band, same structure.
   The default warn colouring stays the middle one, so only the outer two need
   an override. A finding that only informs must not shout in the same red as a
   contract that exists twice. */
.engpass.is-fehler {
  border-color: var(--err-line); border-left-color: var(--err);
  background: color-mix(in srgb, var(--err-bg) 55%, var(--surface));
}
.engpass.is-fehler > strong { color: var(--err); }
.engpass.is-hinweis {
  border-color: var(--line); border-left-color: var(--ink-3);
  background: var(--surface-2);
}
.engpass.is-hinweis > strong { color: var(--ink); }
.engpass.is-hinweis .engpass-einordnung { border-color: var(--line); }
/* The rules that found nothing, as a quiet row of badges - present so the
   findings above can be read as "out of this many checks". */
.befund-rein { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .9rem; }
/* minmax(0,1fr), not the implicit auto track: file names run long enough to
   size the track to their max-content and push the whole band past the
   viewport instead of truncating inside it. */
.engpass-liste { display: grid; grid-template-columns: minmax(0, 1fr); gap: .4rem; margin-top: .9rem; }
.engpass-zeile {
  display: flex; align-items: center; gap: .8rem; min-width: 0;
  padding: .6rem .8rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  text-decoration: none; color: inherit;
  transition: border-color .12s, box-shadow .12s;
}
.engpass-zeile:hover { border-color: var(--brand-soft); box-shadow: var(--shadow); }
.engpass-zeile .ez-name { min-width: 0; flex: 1; font-weight: 650; font-size: .88rem; }
.engpass-zeile .ez-name, .engpass-zeile .cell-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.engpass-zeile .ez-zahl { font-size: .84rem; font-weight: 700; color: var(--warn); white-space: nowrap; }
.engpass-zeile .ez-alter { font-size: .78rem; color: var(--ink-3); white-space: nowrap; }
.engpass-zeile > svg { color: var(--ink-3); }
/* A file nobody has touched in years is still listed, but it must not read
   with the urgency of the one uploaded yesterday. */
.engpass-zeile.is-alt { background: var(--surface-2); border-style: dashed; }
.engpass-zeile.is-alt .ez-name { font-weight: 600; color: var(--ink-2); }
.engpass-zeile.is-alt .ez-zahl { color: var(--ink-3); }
.engpass-zeile.is-alt .ez-alter { color: var(--warn); font-weight: 650; }

.engpass-einordnung {
  font-size: .82rem; color: var(--ink-2);
  margin-top: .6rem; padding: .55rem .8rem;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  border: 1px dashed var(--warn-line);
}
.engpass-durch {
  display: flex; align-items: flex-start; gap: .5rem;
  margin-top: .9rem;
  font-size: .82rem; color: var(--ink-2);
}
.engpass-durch svg { color: var(--ok); margin-top: .18rem; }
.engpass-durch strong { color: var(--ink); }
.engpass-chips { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .9rem; }
.engpass-chips .badge { text-decoration: none; padding: .3rem .75rem; }
.engpass-chips .badge strong { font-variant-numeric: tabular-nums; }
.engpass-aktionen { display: flex; gap: .6rem; flex-wrap: wrap; margin-top: 1rem; }

/* ---------- Maklertafel: one card per broker ---------- */
.tafel-kopf {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  margin: 1.5rem 0 .8rem;
}
.tafel-kopf h3 { font-size: .98rem; font-weight: 700; letter-spacing: -.01em; }
.tafel-kopf .sub { font-size: .82rem; color: var(--ink-2); margin-top: .15rem; max-width: 70ch; }

.makler-tafel {
  display: grid; gap: .8rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.makler-karte {
  display: flex; flex-direction: column; min-width: 0;
  padding: calc(1.05rem * var(--dichte)) calc(1.15rem * var(--dichte));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  text-decoration: none; color: inherit;
  position: relative; overflow: hidden;
  transition: border-color .12s, box-shadow .12s;
}
.makler-karte:hover { border-color: var(--brand-soft); box-shadow: var(--shadow-lg); }
/* A strip in the colour of the state, so the tiles read as a row of states
   before a single number has been read: brand where a portfolio is running,
   the warning tone where something is lying there for somebody to pick up,
   and the plain line where nothing has happened yet. Holding a portfolio is
   not a fault, so it does not get the warning colour. */
.makler-karte .mk-strich { position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--line); }
.makler-karte.is-bestand .mk-strich { background: var(--brand); }
.makler-karte.is-datei .mk-strich { background: var(--warn); }
.makler-karte.is-leer { background: var(--surface-2); box-shadow: none; }
.makler-karte .mk-name {
  font-weight: 700; font-size: .92rem; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.makler-karte .mk-wert {
  font-size: 1.55rem; font-weight: 700; letter-spacing: -.03em;
  margin-top: .5rem; font-variant-numeric: tabular-nums;
}
/* "Noch kein Bestand" is a sentence, not a figure - it must not sit at the
   weight of a number that is not there. */
.makler-karte .mk-wert.is-leer { font-size: .95rem; font-weight: 650; color: var(--ink-3); letter-spacing: 0; }
.makler-karte .mk-einheit { font-size: .78rem; color: var(--ink-3); margin-top: .15rem; }
.makler-karte .mk-stack { height: 8px; margin: .8rem 0 0; }
.makler-karte .mk-fuss { font-size: .78rem; color: var(--ink-2); margin-top: .6rem; }
.makler-karte .mk-aktion {
  display: flex; align-items: center; gap: .25rem;
  margin-top: auto; padding-top: .9rem;
  font-size: .82rem; font-weight: 650; color: var(--brand);
}
.makler-karte .mk-aktion svg { color: currentColor; }

/* The bucket panel is the full content width now that the file table below it
   is gone. One legend row per line would leave most of that width empty, so
   the rows flow into as many columns as fit. */
.card-pad > .bucket-legend {
  /* Wide enough that the longest bucket name of the catalogue keeps its own
     line - a wrapped name made its row taller than its neighbours. */
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  column-gap: 1.2rem;
}
.card-pad > .bucket-legend .name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Premium sum under the bucket panel. */
.netto-zeile {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  margin-top: 1.1rem; padding-top: .9rem;
  border-top: 1px solid var(--line-soft);
  font-size: .85rem; color: var(--ink-2);
}
.netto-zeile strong { font-variant-numeric: tabular-nums; }
.netto-zeile strong.is-leer { color: var(--ink-3); font-weight: 600; }

/* Below this the stages wrap, and a chevron pointing at a stage on the next
   line points at nothing. Stacked, the order alone carries the direction. */
@media (max-width: 640px) {
  .strecke-pfeil { display: none; }
  .strecke-stufe { flex-basis: 100%; }
}

/* ============================================================
   TABLES
   ============================================================ */
.table-wrap { overflow-x: auto; border-radius: var(--radius); }
table { width: 100%; border-collapse: collapse; font-size: .88rem; }
thead th {
  text-align: left;
  font-size: .72rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3);
  padding: calc(.8rem * var(--dichte)) calc(1rem * var(--dichte));
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
  white-space: nowrap;
}
tbody td {
  padding: calc(.85rem * var(--dichte)) calc(1rem * var(--dichte));
  border-bottom: 1px solid var(--line-soft);
  vertical-align: middle;
  white-space: nowrap;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr.is-click { cursor: pointer; transition: background .12s; }
tbody tr.is-click:hover { background: var(--brand-tint); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
.cell-main { font-weight: 650; }
.cell-sub { display: block; font-size: .76rem; color: var(--ink-3); font-weight: 400; }
/* Company and insurer names run long enough to widen the contract table past
   its container, which pushed the premium and the status badge out of sight -
   on a screen whose whole point is the status. They truncate instead and carry
   the full value as a tooltip. */
.zelle-lang { max-width: 15rem; }
.zelle-lang, .zelle-lang .cell-main, .zelle-lang .cell-sub {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Two buttons in one action cell. Side by side they widened the import table
   past its container at 1280px, which is where the deletion button used to sit
   outside the visible area. */
.zeilen-aktionen { display: flex; flex-direction: column; gap: .35rem; align-items: stretch; }
.zeilen-aktionen .btn { padding: .3rem .7rem; font-size: .78rem; justify-content: center; }

/* ============================================================
   MAKLER (list)
   ============================================================ */
.page-head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem;
  margin-bottom: 1.4rem; flex-wrap: wrap;
}
.page-head h2 { font-size: 1.4rem; font-weight: 700; letter-spacing: -.02em; }
.page-head p { color: var(--ink-2); margin-top: .2rem; }

.mini-aurora { width: 130px; }
.mini-aurora .lbl { font-size: .72rem; color: var(--ink-3); margin-top: .3rem; font-variant-numeric: tabular-nums; }

/* ============================================================
   WIZARD (Import)
   ============================================================ */
.wizard {
  display: flex; align-items: center; gap: .4rem;
  margin-bottom: 1.5rem;
  padding: .9rem 1.1rem;
  flex-wrap: wrap;
}
.wstep {
  display: flex; align-items: center; gap: .55rem;
  font-size: .85rem; font-weight: 600; color: var(--ink-3);
  padding: .3rem .6rem; border-radius: 999px;
}
.wstep .wnum {
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: .78rem; font-weight: 700;
  background: var(--line-soft); color: var(--ink-3);
}
.wstep.is-done { color: var(--ok); }
.wstep.is-done .wnum { background: var(--ok-bg); color: var(--ok); }
.wstep.is-active { color: var(--brand-ink); background: var(--brand-tint); }
.wstep.is-active .wnum { background: var(--brand); color: var(--on-brand); }
.wsep { color: var(--line); flex-shrink: 0; }

/* Dropzone */
.dropzone {
  border: 2px dashed var(--brand-soft);
  border-radius: var(--radius);
  background: var(--brand-tint);
  padding: 3rem 2rem;
  text-align: center;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.dropzone:hover, .dropzone.is-over { border-color: var(--brand); background: var(--brand-tint-2); }
.dropzone .dz-icon {
  width: 56px; height: 56px; border-radius: 16px;
  background: var(--surface); color: var(--brand);
  display: grid; place-items: center;
  margin: 0 auto 1rem;
  box-shadow: var(--shadow);
}
.dropzone strong { font-size: 1.02rem; }
.dropzone p { color: var(--ink-2); font-size: .85rem; margin-top: .3rem; }
.dropzone .dz-formats { margin-top: 1rem; font-size: .76rem; color: var(--ink-3); }

.filerow {
  display: flex; align-items: center; gap: .9rem;
  padding: .9rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  margin-top: 1rem;
}
.filerow .file-icon {
  width: 40px; height: 40px; border-radius: 10px;
  background: var(--ok-bg); color: var(--ok);
  display: grid; place-items: center;
}
.filerow .fname { font-weight: 650; font-size: .9rem; }
.filerow .fmeta { font-size: .78rem; color: var(--ink-3); }
.filerow .fstate { margin-left: auto; display: flex; align-items: center; gap: .75rem; }
.iconbtn {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: none; background: none; border-radius: 8px;
  color: var(--ink-3); cursor: pointer;
}
.iconbtn:hover { background: var(--line-soft); color: var(--ink); }

.checklist { list-style: none; display: grid; gap: .55rem; }
.checklist li { display: flex; gap: .6rem; align-items: flex-start; font-size: .86rem; color: var(--ink-2); }
.checklist svg { margin-top: .12rem; }
.checklist .c-ok svg { color: var(--ok); }
.checklist .c-info svg { color: var(--brand); }
.checklist .c-warn svg { color: var(--warn); }

.step-actions {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  margin-top: 1.5rem;
}

/* ============================================================
   MAPPING (the critical screen)
   ============================================================ */
.map-status {
  display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;
  padding: 1.1rem 1.4rem;
  margin-bottom: 1.1rem;
}
.map-status .ms-text { min-width: 240px; flex: 1; }
.map-status .ms-text strong { font-size: .95rem; }
.map-status .ms-text p { font-size: .8rem; color: var(--ink-2); margin-top: .1rem; }
.map-status .aurora-bar { flex: 2; min-width: 220px; }
.req-chips { display: flex; gap: .5rem; flex-wrap: wrap; }
/* Stand frueher als Zeile in der Statuskarte - Flex-Reihe, Trennlinie oben, volle
   Breite als Flex-Kind. Seit die Statuskarte weg ist, ist der Bereich eine eigene
   Karte und braucht keins davon: normaler Fluss, kein Rahmen von oben. */
.vorschlag-leiste { margin-bottom: 1.1rem; }
.vorschlag-leiste .btn { min-height: 34px; padding: .35rem .85rem; }
/* In der Statuskarte von Schritt 3 und 4 sitzt die Leiste weiterhin als eigene
   Zeile: dort gibt es keine klebende Feldleiste, die Karte bleibt berechtigt. */
.map-status .vorschlag-leiste {
  flex: 1 0 100%; margin-bottom: 0;
  display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
  padding-top: .9rem; border-top: 1px solid var(--line-soft);
}
.map-status .vorschlag-leiste > span { font-size: .78rem; color: var(--ink-3); }

/* Die Spaltenwahl in Schritt 4 und 5: Basis aus #47, hier nur die Breite. */
.vorschlag-leiste select {
  max-width: 22rem; min-width: 0;
}
/* Die Vorschau steht vor dem Knopf und bricht bei Bedarf in eine eigene Zeile -
   neun Paare passen nicht neben einen Knopf. */
.map-status .vorschlag-leiste .vw-welche { margin: 0; order: -1; flex: 0 0 auto; }
.map-status .vorschlag-leiste .vw-welche[open] { flex: 1 0 100%; }

/* ---------- Der Vorschlagsbereich: zwei Wege ----------
   Vorher stand hier ein Knopf "9 Vorschläge übernehmen" und ein Satz. Man sah nicht,
   was der Bereich ist, welche neun gemeint sind und was nach dem Klick passiert.
   Jetzt: zwei benannte Wege, die Paare auf Klick, und ein leiser Ausweg.
   Violett heisst durchgehend "das hat das System vorgeschlagen, nicht Sie". */
.btn-ki { background: var(--ki); color: var(--on-brand);
  box-shadow: 0 1px 2px rgba(23,32,58,.15), 0 6px 14px -6px color-mix(in srgb, var(--ki) 55%, transparent); }
.btn-ki:hover { background: var(--ki-ink); }

.vw-titel { font-size: .95rem; font-weight: 700; display: flex; align-items: center; gap: .4rem; }
.vw-titel svg { color: var(--ki); }
.vw-titel + p { font-size: .8rem; color: var(--ink-2); margin-top: .1rem; }
.vw-wege { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: .7rem; margin-top: .85rem; }
.vw-weg { border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .85rem 1rem; background: var(--surface); }
.vw-weg.stark { border-color: color-mix(in srgb, var(--ki) 35%, transparent);
  background: color-mix(in srgb, var(--ki) 5%, var(--surface)); }
.vw-weg h4 { font-size: .86rem; font-weight: 700; margin-bottom: .2rem; }
.vw-weg p { font-size: .78rem; color: var(--ink-2); margin-bottom: .6rem; }

/* "Welche denn?" - die Frage, die ein Sammelknopf immer aufwirft. Zugeklappt, weil
   die Antwort den Bereich groesser machen wuerde als das, worueber er berichtet.
   details/summary, damit es ohne Skript und mit Tastatur geht. */
.vw-welche { margin: 0 0 .7rem; }
.vw-welche > summary { display: inline-flex; align-items: center; gap: .35rem; cursor: pointer;
  font-size: .76rem; font-weight: 650; color: var(--ki-ink); padding: .2rem .55rem;
  border: 1px solid var(--ki-line); background: var(--ki-bg); border-radius: 999px;
  list-style: none; width: fit-content; }
.vw-welche > summary::-webkit-details-marker { display: none; }
.vw-welche > summary::after { content: ""; width: 7px; height: 7px; margin-left: .1rem;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px); transition: transform .15s; }
.vw-welche[open] > summary::after { transform: rotate(-135deg) translate(-1px, -1px); }
.vw-welche > summary:hover { background: var(--ki-soft); }
.vw-paare { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .5rem; }
.vw-paar { display: inline-flex; align-items: center; gap: .3rem; font-size: .74rem;
  padding: .16rem .5rem; border-radius: 6px; border: 1px solid var(--ki-line);
  background: var(--ki-bg); color: var(--ki-ink); white-space: nowrap; }
.vw-paar .q { font-family: var(--mono); font-size: .95em; }
.vw-paar .pf { color: var(--ki); opacity: .7; }
.vw-paar .z { font-weight: 650; }

/* Kein dritter Kasten: selbst zuordnen ist kein dritter Weg durch die Vorschlaege,
   sondern der Verzicht darauf. Die Trennlinie sagt, dass er an ihnen vorbeifuehrt. */
.vw-selbst { margin-top: .85rem; padding-top: .75rem;
  border-top: 1px solid var(--line-soft); text-align: center; }

/* Weggelegt: eine Zeile, die sagt, dass die Vorschlaege noch da sind. Ein Weg, der
   nicht zurueckfuehrt, ist kein Weg, sondern eine Falle. */
.vw-ruhe { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  font-size: .82rem; color: var(--ink-2); }
.vw-ruhe b { color: var(--ki-ink); font-weight: 650; }
.vw-ruhe .btn { margin-left: auto; }

.vw-lauf { margin-top: .85rem; padding: .7rem .9rem; display: flex; align-items: center;
  gap: .8rem; flex-wrap: wrap; border-radius: var(--radius-sm);
  border: 1px solid color-mix(in srgb, var(--ki) 30%, transparent);
  background: color-mix(in srgb, var(--ki) 5%, var(--surface)); }
.vw-lauf .zaehler { font-size: .72rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ki); }
.vw-lauf .frage { font-size: .86rem; }
.vw-lauf .frage b { color: var(--ki-ink); }
.vw-lauf .knoepfe { margin-left: auto; display: flex; gap: .4rem; }

.map-grid { display: grid; gap: .7rem; }
.map-headrow {
  display: grid; grid-template-columns: 1fr 44px 1.15fr;
  gap: .8rem; padding: 0 1.1rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3);
}
.map-row {
  display: grid; grid-template-columns: 1fr 44px 1.15fr;
  gap: .8rem; align-items: center;
  padding: .85rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  transition: border-color .12s, box-shadow .12s;
}
.map-row:hover { border-color: var(--brand-soft); box-shadow: var(--shadow); }
.map-row.is-open { border-color: var(--warn-line); background: color-mix(in srgb, var(--warn-bg) 35%, var(--surface)); }
.excel-col .xc-name {
  font-family: var(--mono); font-size: .82rem; font-weight: 600;
  display: flex; align-items: center; gap: .5rem;
}
.excel-col .xc-name .xtag {
  font-size: .66rem; font-weight: 700;
  background: var(--ok-bg); color: var(--ok);
  border-radius: 4px; padding: .05rem .35rem;
  font-family: var(--font);
}
.excel-col .xc-sample { font-size: .76rem; color: var(--ink-3); margin-top: .2rem; font-variant-numeric: tabular-nums; }
.map-arrow { display: grid; place-items: center; color: var(--ink-3); }
/* Column, not a row: the suggestion belongs under its select, not squeezed in
   beside it where both end up wrapping. */
.map-target { display: flex; flex-direction: column; align-items: stretch; gap: .45rem; }
.map-target .vorschlag { margin-top: 0; padding-top: .45rem; }
/* Ein select waechst mit seiner laengsten Option. Bei den Betriebsarten sind
   das Zeilen wie "WZ 46660 - (Grosshandel mit sonst. Bueromaschinen)", und die
   haben die Seite waagerecht scrollen lassen. Die Zeile gibt die Breite vor,
   nicht ihr Inhalt. */
.map-target { min-width: 0; }
.map-target select {
  flex: 1;
  width: 100%; max-width: 100%; min-width: 0;
}
.map-state { width: 148px; flex-shrink: 0; display: flex; justify-content: flex-end; }

/* Die Karte, mit der man ein Feld ohne Spalte belegt. Gestrichelt, weil sie
   nichts aus der Datei zeigt, sondern eine Annahme aufnimmt. */
.mcol-konst-neu { border-style: dashed; background: var(--surface-2); }
.mcol-konst-neu:hover { border-color: var(--brand-soft); }
.mcol-konst-neu #konst-eingabe { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; width: 100%; }
.mcol-konst-neu #konst-wert {
  flex: 1; min-width: 9rem; font: inherit; font-size: .85rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .35rem .55rem; background: var(--surface);
}
.mcol-konst-neu #konst-wert:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint-2); }

.const-chip {
  display: inline-flex; align-items: center; gap: .45rem;
  font-family: var(--mono); font-size: .78rem; font-weight: 600;
  background: var(--brand-tint); color: var(--brand-ink);
  border: 1px dashed var(--brand-soft);
  border-radius: 8px;
  padding: .32rem .6rem;
}
.const-chip svg { color: var(--brand); }
.no-col {
  font-size: .82rem; color: var(--ink-3); font-style: normal;
  display: flex; align-items: center; gap: .5rem;
}

/* Ein Vorschlag ist maschinell, also violett - vorher trug er den Warnton, was ihn
   zu einer Beanstandung machte. Es ist keine: es ist ein Angebot. */
.suggest-note {
  display: flex; align-items: center; gap: .45rem;
  font-size: .78rem; color: var(--ki-ink); font-weight: 600;
  margin-top: .35rem;
}
.suggest-note svg { color: var(--ki); }
.suggest-note .btn { border-color: var(--ki-line); color: var(--ki-ink); }
.suggest-note .btn:hover { background: var(--ki-bg); border-color: var(--ki); }

/* ============================================================
   MAPPING - drag & drop
   ============================================================ */
.map-dnd { display: block; }
.map-cols { display: grid; gap: .7rem; }
.mcol {
  padding: .85rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  transition: border-color .12s, box-shadow .12s;
}
.mcol:hover { border-color: var(--brand-soft); box-shadow: var(--shadow); }
.mcol.is-open { border-color: var(--warn-line); background: color-mix(in srgb, var(--warn-bg) 35%, var(--surface)); }
.mcol.is-over { border-color: var(--brand); background: var(--brand-tint); box-shadow: var(--shadow); }
.mcol.is-over .drop-slot { border-color: var(--brand); background: color-mix(in srgb, var(--brand-tint) 60%, var(--surface)); }
.drop-slot {
  margin-top: .6rem;
  min-height: 46px;
  border: 1.5px dashed var(--line);
  border-radius: var(--radius-sm);
  display: flex; align-items: center; gap: .6rem;
  padding: .35rem .6rem;
  font-size: .8rem; color: var(--ink-3);
  transition: border-color .12s, background .12s;
}
.drop-slot.is-over { border-color: var(--brand); background: var(--brand-tint); color: var(--brand-ink); }
.drop-slot.is-filled { border-style: solid; border-color: var(--line); background: color-mix(in srgb, var(--brand-tint) 40%, var(--surface)); }
.drop-slot .slot-hint { display: flex; align-items: center; gap: .5rem; }
.achip {
  display: inline-flex; align-items: center; gap: .5rem;
  background: var(--surface);
  border: 1px solid var(--brand-soft);
  border-radius: 999px;
  padding: .35rem .5rem .35rem .8rem;
  font-size: .82rem; font-weight: 650; color: var(--brand-ink);
  box-shadow: var(--shadow);
}
.achip .ax {
  display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: 50%;
  border: 0; background: var(--brand-tint); color: var(--brand-ink);
  cursor: pointer; font-size: .8rem; line-height: 1;
}
.achip .ax:hover { background: var(--brand-soft); }
.achip.is-ignore { border-color: var(--line); color: var(--ink-2); }
.slot-auto { font-size: .72rem; font-weight: 700; color: var(--ok); display: inline-flex; align-items: center; gap: .3rem; }
.fpal {
  position: sticky; top: 84px; padding: 1rem 1rem 1.1rem;
  /* The palette lists every field of the product and is far taller than the
     viewport. A sticky element taller than its viewport does not stick - it
     scrolled out of view above as soon as the user reached the middle of the
     file, leaving the lower columns with nothing to drag onto. Bounding the
     height and giving it its own scrollbar is what makes sticky work. */
  max-height: calc(100dvh - 104px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.fpal h3 { font-size: .85rem; font-weight: 700; margin-bottom: .2rem; }
.fpal .fpal-sub { font-size: .75rem; color: var(--ink-3); margin-bottom: .8rem; }
.fgroup { margin-top: .8rem; }
.fgroup-label {
  font-size: .68rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: .45rem;
}
.fchips { display: flex; flex-wrap: wrap; gap: .45rem; }
.fchip {
  display: inline-flex; align-items: center; gap: .45rem;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: 999px;
  padding: .38rem .75rem;
  font-size: .8rem; font-weight: 600; color: var(--ink);
  cursor: grab; user-select: none;
  transition: border-color .12s, box-shadow .12s, opacity .12s, background .12s;
}
.fchip:hover { border-color: var(--brand); box-shadow: var(--shadow); }
.fchip:active { cursor: grabbing; }
.fchip:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.fchip .grip { color: var(--ink-3); }
.fchip .req-star { color: var(--warn); font-weight: 800; }
.fchip.is-used { opacity: .45; }
.fchip.is-used .grip { visibility: hidden; }
.fchip.is-picked { border-color: var(--brand); background: var(--brand-tint); color: var(--brand-ink); box-shadow: 0 0 0 3px var(--brand-tint-2); }
.fchip.is-dragging { opacity: .35; }
.fchip.fl-aus { display: none; }
.fchip .fchip-gruppe { display: none; font-size: .64rem; color: var(--ink-3); font-weight: 600;
  border-left: 1px solid var(--line); padding-left: .32rem; margin-left: .1rem; }
.fchip.zeigt-gruppe .fchip-gruppe { display: inline; }

/* ---------- Feldleiste am unteren Rand ----------
   Die Palette lag rechts als Spalte und nahm 300px Breite; unten schwebend
   gibt sie die Breite an die Spaltenkarten zurueck. Grundgestaltung: leicht
   durchscheinend mit Unschaerfe, eingerueckt, echter Schatten - die Karten
   laufen sichtbar darunter durch, damit sie als Werkzeug ueber der Seite
   liest und nicht als naechster Abschnitt. Der Verlauf kommt aus --brand,
   in einstelligen Anteilen, damit das White-Labeling traegt und die
   Markenfarbe dem Vorschlag bleibt. */
.fleiste {
  position: sticky; bottom: 0; z-index: 20;
  display: flex; flex-direction: column; max-height: 55vh;
  margin: 1rem 1.6rem 0; padding: .6rem 1rem .7rem;
  background:
    linear-gradient(158deg,
      color-mix(in srgb, var(--brand) 8%, transparent) 0%,
      color-mix(in srgb, var(--brand) 3%, transparent) 46%,
      color-mix(in srgb, var(--brand) 7%, transparent) 100%),
    color-mix(in srgb, var(--surface) 78%, transparent);
  backdrop-filter: blur(18px) saturate(150%);
  border: 1px solid color-mix(in srgb, var(--brand) 20%, transparent);
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: 0 -1px 0 color-mix(in srgb, var(--ink) 6%, transparent),
              0 -8px 22px -4px rgba(23,32,58,.14),
              0 -34px 64px -28px rgba(23,32,58,.38);
}

/* Oben das Etikett, unten die Anleitung - jedes Element eine Aufgabe. */
.fl-kopf { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  margin-bottom: .45rem; font-size: .74rem; line-height: 1.35; }
.fl-marke { display: inline-flex; align-items: center; gap: .38rem; color: var(--brand-ink); }
.fl-marke svg { color: var(--brand); display: block; }
.fl-titel { font-size: .9rem; font-weight: 750; color: var(--ink); letter-spacing: -.005em; }
.fl-strich { width: 1px; align-self: stretch; background: var(--line); margin: 0 .15rem; }
.fl-zusatz { color: var(--ink-2); }
.fl-rechts { margin-left: auto; font-weight: 650; color: var(--ink-2);
  display: inline-flex; align-items: baseline; gap: .5rem; }
.fl-rechts.warnt { color: var(--warn); }
.fl-rechts.ok { color: var(--ok); }
/* Die zweite Pflicht: blockiert den Import nicht, entscheidet aber die Bewertung.
   Deshalb daneben und leiser statt in derselben Zahl - zwei Dinge, zwei Angaben. */
.fl-bewertung { font-weight: 600; color: var(--ink-3);
  padding-left: .5rem; border-left: 1px solid var(--line); }

.fl-oben { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .55rem; }
#fl-zahl { margin-left: auto; }

/* Nur was man anfassen kann, ist eine Pille. Reiter sind Navigation und
   deshalb reiner Text; der aktive traegt Farbe, Gewicht und Strich zugleich. */
.fl-reiter { display: flex; gap: .95rem; flex-wrap: wrap; transition: opacity .15s; }
.fl-reiter.zurueck { opacity: .35; pointer-events: none; }
.flreiter { border: 0; background: none; border-radius: 0; padding: .2rem 0 .28rem;
  border-bottom: 2px solid transparent; font-size: .78rem; font-weight: 600;
  color: var(--ink-3); cursor: pointer; white-space: nowrap; }
.flreiter:hover { color: var(--ink); border-bottom-color: var(--line); }
.flreiter.an { color: var(--ink); font-weight: 750; border-bottom-color: var(--ink); }
/* Der Warnton ist kein neuer Farbwert - er markiert Pflicht schon am Chip. */
.flr-n { font-variant-numeric: tabular-nums; margin-left: .3rem; font-size: .72rem; font-weight: 600; color: var(--warn); }
.flr-stern { font-weight: 800; margin-right: .04em; }

.fl-suche { position: relative; min-width: 13rem; flex: 1; max-width: 22rem; }
.fl-suche input { width: 100%; border: 1px solid var(--line); border-radius: 7px;
  padding: .3rem 2rem .3rem 1.9rem; font-size: .78rem; min-height: 32px;
  background: color-mix(in srgb, var(--surface) 88%, transparent); }
.fl-suche input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint-2); }
.fl-suche > svg { position: absolute; left: .62rem; top: 50%; transform: translateY(-50%); color: var(--ink-3); }
.fl-suche-x { position: absolute; right: .3rem; top: 50%; transform: translateY(-50%); width: 22px; height: 22px;
  border: 0; background: none; color: var(--ink-3); cursor: pointer; border-radius: 50%; display: grid; place-items: center; }
.fl-suche-x[hidden] { display: none; }

/* In dieser Zeile waechst allein die Feldflaeche. Alles daneben hat feste
   Hoehe und sitzt oben, sonst dehnt der Flex-Kasten es auf die hoechste Reihe. */
.fl-zeile { display: flex; align-items: flex-start; gap: .7rem; min-height: 0; }
.fl-zeile > *:not(.fchips) { flex: 0 0 auto; align-self: flex-start; }
.fl-zeile .fchips { flex: 0 1 auto; min-width: 0; overflow-y: auto; }

/* Kacheln statt Pillen: greifbar, und gegen die flachen Reiter auf einen
   Blick etwas anderes. */
.fleiste .fchip { border-radius: 7px; padding: .38rem .68rem;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border-color: color-mix(in srgb, var(--ink) 15%, transparent);
  border-bottom-width: 2px; border-bottom-color: color-mix(in srgb, var(--ink) 24%, transparent);
  box-shadow: 0 1px 2px rgba(23,32,58,.10), 0 2px 5px -2px rgba(23,32,58,.14); }
.fleiste .fchip:hover { background: var(--surface); transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(23,32,58,.12), 0 6px 12px -4px rgba(23,32,58,.20); }
.fleiste .fchip:active { transform: translateY(1px); box-shadow: 0 1px 1px rgba(23,32,58,.12); }
.fleiste .fchip.is-picked { background: var(--surface); border-bottom-color: var(--brand); }

/* "Nicht importieren" ist keine Angabe, sondern eine Handlung, und in Dateien
   ohne passendes Feld das meistgebrauchte Ziel. Fester Platz statt Reiter,
   eigene Form statt eigener Farbe: gestrichelt, weil es verwirft. */
.fverwerfen { height: 32px; padding: 0 .7rem; border-radius: var(--radius-sm);
  border: 1px dashed var(--ink-3); background: transparent; color: var(--ink-2);
  box-shadow: none; font-weight: 650; }
.fleiste .fverwerfen:hover { border-color: var(--ink); color: var(--ink);
  background: color-mix(in srgb, var(--ink) 5%, transparent); transform: none; box-shadow: none; }
.fleiste .fverwerfen.is-picked { border-style: solid; border-color: var(--ink); background: var(--ink); color: var(--surface); }
.fverwerfen svg { display: block; }

.fl-leer { font-size: .78rem; color: var(--ink-3); padding: .5rem .2rem; }
.fl-leer[hidden] { display: none; }
.fl-fuss { margin-top: .5rem; padding-top: .45rem; border-top: 1px solid var(--line-soft);
  font-size: .75rem; color: var(--ink-2); transition: opacity .15s; }
.fl-fuss.zurueck { opacity: .5; }

@media (max-width: 780px) {
  .fleiste { margin-left: 0; margin-right: 0; max-height: 60vh; }
  .fl-zeile { flex-wrap: wrap; }
}

/* A screen that ends in the sticky bottom bar ends WITH it: no footer (the
   shell skips it via $bottomBar) and no content padding below - anything
   after the bar in the scroll flow lifts it off the viewport edge on the
   last few hundred pixels of the page. */
.content-bottombar { padding-bottom: 0; }
/* The step buttons sit directly above the bar at the end of the page; the
   bar's default 1rem gap reads as part of the bar, not as air between two
   different things. */
.step-actions + .fleiste { margin-top: 1.8rem; }
.fpal-help { margin-top: .9rem; font-size: .74rem; color: var(--ink-3); line-height: 1.45; }

/* Suggestions on a column card. The three confidences differ in weight, not in
   wording: a hesitant guess must not look like a decision. */
.vorschlag {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin-top: .55rem; padding-top: .55rem;
  border-top: 1px dashed var(--line);
  font-size: .78rem; color: var(--ink-2);
}
.vorschlag-text { font-weight: 600; }
.vorschlag-hinweis { color: var(--ink-3); }
/* Violett, nicht markenblau: der Vorschlag kommt vom System, nicht vom Nutzer.
   Die drei Sicherheiten unterscheiden sich weiterhin im Gewicht, nicht im Wort -
   nur eben in Abstufungen derselben Bedeutungsfarbe. */
.vorschlag-btn {
  margin-left: auto;
  border: 1px solid var(--ki); background: var(--ki-bg); color: var(--ki-ink);
  border-radius: 999px; padding: .22rem .7rem;
  font-size: .76rem; font-weight: 650; cursor: pointer;
}
.vorschlag-btn:hover { background: var(--ki-soft); }
.vorschlag-btn:focus-visible { outline: 2px solid var(--ki); outline-offset: 2px; }
.vorschlag-sicher .vorschlag-text { color: var(--ki-ink); }
.vorschlag-unsicher { font-size: .74rem; color: var(--ink-3); }
.vorschlag-unsicher .vorschlag-text { font-weight: 600; color: var(--ink-3); }
.vorschlag-unsicher .vorschlag-btn {
  border-color: var(--line); background: var(--surface); color: var(--ink-2); font-weight: 600;
}
@media (max-width: 980px) {
  .map-dnd { grid-template-columns: 1fr; }
  /* In one column the palette follows every column card in the document, so
     it sat below nineteen of them - present in the markup, unreachable in
     practice. It moves above the columns and keeps a bounded scroll area of
     its own so it does not push them off the screen. */
  .fpal { order: -1; top: 8px; max-height: 42dvh; }
}

/* ============================================================
   VERTRÄGE (bucket list)
   ============================================================ */
.toolbar {
  display: flex; gap: .9rem; align-items: center; flex-wrap: wrap;
  margin-bottom: 1.1rem;
}
.search {
  position: relative; flex: 1; min-width: 260px;
}
/* In der Werkzeugleiste nimmt die Suche IMMER die ganze Zeile, die Reiter
   stehen darunter. Vorher entschied die Fensterbreite: bei fuenf Reitern
   brachen sie unter die Suche (Vertragsliste), bei vier passten sie daneben
   (Kundenliste) - zwei Bildschirme, die gleich gebaut sind, sahen zufaellig
   verschieden aus. */
.toolbar > .search { flex-basis: 100%; }
.search svg { position: absolute; left: .8rem; top: 50%; transform: translateY(-50%); color: var(--ink-3); }
.search input {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: .6rem .9rem .6rem 2.5rem;
  min-height: 42px;
}
.search input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint-2); }

.tabs { display: flex; gap: .4rem; flex-wrap: wrap; }
.tab {
  display: inline-flex; align-items: center; gap: .5rem;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: 999px;
  padding: .45rem .95rem;
  min-height: 40px;
  font-size: .85rem; font-weight: 600; color: var(--ink-2);
  cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.tab:hover { border-color: var(--brand-soft); }
.tab .tdot { width: 8px; height: 8px; border-radius: 50%; }
.tab .tcount { font-variant-numeric: tabular-nums; font-weight: 700; }
.tab.is-active { background: var(--ink); border-color: var(--ink); color: #fff; }
.tab.is-active[data-bucket="ok"]   { background: var(--ok); border-color: var(--ok); }
.tab.is-active[data-bucket="warn"] { background: var(--warn); border-color: var(--warn); }
.tab.is-active[data-bucket="err"]  { background: var(--err); border-color: var(--err); }
.tdot-ok { background: var(--ok); } .tdot-warn { background: var(--warn); } .tdot-err { background: var(--err); }
.tab.is-active .tdot { background: #fff; }

.table-foot {
  display: flex; justify-content: space-between; align-items: center;
  padding: .8rem 1.1rem;
  border-top: 1px solid var(--line-soft);
  font-size: .8rem; color: var(--ink-3);
}
.table-foot .pager { display: flex; gap: .3rem; }
/* Pages are links, so every filter state keeps its own URL - same rule as the
   bucket tabs above the table. */
.table-foot .pager button,
.table-foot .pager a {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px; padding: 0 .4rem;
  border: 1px solid var(--line); background: var(--surface);
  border-radius: 8px; cursor: pointer; font-size: .8rem; color: var(--ink-2);
  text-decoration: none; font-variant-numeric: tabular-nums;
}
.table-foot .pager button.is-active,
.table-foot .pager a.is-active { background: var(--brand); border-color: var(--brand); color: var(--on-brand); font-weight: 700; }
.table-foot .pager button:hover:not(.is-active),
.table-foot .pager a:hover:not(.is-active) { border-color: var(--brand-soft); }
.table-foot .pager .is-off,
.table-foot .pager .is-gap {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px; color: var(--ink-3); opacity: .45;
}

/* ============================================================
   VERTRAG (detail)
   ============================================================ */
.backlink {
  display: inline-flex; align-items: center; gap: .4rem;
  border: none; background: none; cursor: pointer;
  color: var(--brand); font-weight: 600; font-size: .85rem;
  padding: .3rem .4rem; margin-left: -.4rem;
  border-radius: 6px;
}
.backlink:hover { background: var(--brand-tint); }

.detail-head {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  margin: .6rem 0 1.4rem;
}
.detail-head h2 {
  font-size: 1.35rem; font-weight: 700; letter-spacing: -.015em;
  display: flex; align-items: baseline; gap: .7rem;
}
.detail-head h2 .mono { font-size: .72em; color: var(--ink-2); font-weight: 600; }
.detail-head .spacer { flex: 1; }

.detail-grid {
  display: grid; grid-template-columns: 1.5fr 1fr; gap: 1.1rem;
  align-items: start;
}
/* min-width: 0 auf Spalte UND Karten, weil ein Grid-Kind sonst nie unter
   seine Inhaltsbreite schrumpft: eine nowrap-Tabelle in der linken Spalte
   schob die rechte aus dem Bild und liess die spaeter gezeichnete Karte
   darueber malen, statt im eigenen .table-wrap zu scrollen (Kundenmaske). */
.detail-col { display: grid; gap: 1.1rem; min-width: 0; }
.detail-col > * { min-width: 0; }

.fgrid { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem 1.2rem; }
.fgrid .field { margin: 0; }
.fgrid .span2 { grid-column: span 2; }
.field input[readonly], .field select:disabled { background: var(--surface-2); color: var(--ink); }

.kv { display: grid; gap: .65rem; }
.kv .kvrow { display: flex; justify-content: space-between; gap: 1rem; font-size: .88rem; }
.kv .kvrow dt { color: var(--ink-2); }
.kv .kvrow dd { font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }

.timeline { list-style: none; display: grid; gap: 0; }
.timeline li {
  position: relative;
  padding: 0 0 1.1rem 1.6rem;
  /* Import filenames are one unbroken token and must not escape the card. */
  min-width: 0;
  overflow-wrap: anywhere;
}
.timeline li::before {
  content: ""; position: absolute; left: 5px; top: 6px; bottom: -2px;
  width: 2px; background: var(--line-soft);
}
.timeline li:last-child::before { display: none; }
.timeline li::after {
  content: ""; position: absolute; left: 0; top: 5px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--surface); border: 3px solid var(--ink-3);
}
.timeline li.t-ok::after   { border-color: var(--ok); }
.timeline li.t-warn::after { border-color: var(--warn); }
.timeline li.t-brand::after { border-color: var(--brand); }
.timeline strong { font-size: .87rem; display: block; }
.timeline .t-meta { font-size: .76rem; color: var(--ink-3); }
.timeline p { font-size: .82rem; color: var(--ink-2); margin-top: .2rem; }

.note-box textarea {
  width: 100%; min-height: 80px; resize: vertical;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .7rem .8rem;
}
.note-box textarea:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint-2); }

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 1080px) {
  .shell { grid-template-columns: 1fr; }
  .sidebar {
    position: static; height: auto;
    flex-direction: row; align-items: center; flex-wrap: wrap;
    border-right: none; border-bottom: 1px solid var(--line);
    gap: .2rem; padding: .8rem 1rem;
  }
  .sidebar .brand { padding: 0 .8rem 0 0; }
  /* flex-wrap, weil 15 Punkte in einer Zeile ~1900px messen und die Seite
     sonst waagerecht scrollt - gemessen 958px Ueberlauf bei 1024px Fenster
     (Review-Befund 8, vorbestehend und mit jedem neuen Punkt schlimmer). */
  .nav-group { display: flex; flex-wrap: wrap; margin: 0; }
  .nav-label { display: none; }
  .nav-item { margin: 0; padding: .5rem .7rem; }
  .nav-item .count { display: none; }
  .sidebar-foot { display: none; }
  .auth-layout { grid-template-columns: 1fr; }
  .auth-pane { min-height: 300px; padding: 2.5rem 2rem; gap: 1.5rem; }
  .kpi-grid { grid-template-columns: 1fr; }
  .dash-grid, .detail-grid { grid-template-columns: 1fr; }
  .map-headrow { display: none; }
  .map-row { grid-template-columns: 1fr; }
  .map-arrow { transform: rotate(90deg); justify-self: start; }
}

/* ============================================================
   APP ADDITIONS
   The reference is a click dummy where navigation is done with
   buttons. The app navigates with real links, so the same look
   has to apply to anchors.
   ============================================================ */
a.nav-item, a.btn, a.iconbtn, a.bucket-row, a.backlink, a.tab, a.fchip { text-decoration: none; }
a.iconbtn { display: grid; }
span.nav-item[aria-disabled="true"] { pointer-events: none; }

/* Marks a screen that is showing fixture data because the API is down. */
.demo-note {
  display: flex; align-items: center; gap: .6rem;
  margin-bottom: 1.25rem;
  padding: .7rem 1rem;
  border: 1px solid var(--warn-line);
  border-radius: var(--radius-sm);
  background: var(--warn-bg);
  color: var(--warn);
  font-size: .84rem;
}
/* A note usually opens a screen, so it only carries a bottom margin. Following
   a card it would sit flush against it - the one gap nobody declared. */
.card + .demo-note { margin-top: 1.1rem; }

/* Developer tenant override marker - never rendered in production. */
.tenant-override {
  position: fixed; bottom: 1rem; right: 1rem; z-index: 50;
  display: flex; align-items: center; gap: .5rem;
  padding: .5rem .8rem;
  border: 1px solid var(--warn-line);
  border-radius: 999px;
  background: var(--warn-bg);
  color: var(--warn);
  font-size: .78rem;
  box-shadow: var(--shadow);
}
.tenant-override a { color: inherit; font-weight: 600; }
/* Design configuration problems - development only, hence the loud styling. */
.tenant-override-fehler {
  bottom: 4rem;
  max-width: 32rem;
  border-radius: var(--radius-sm);
  border-color: var(--err-line);
  background: var(--err-bg);
  color: var(--err);
  align-items: flex-start;
  line-height: 1.5;
}

/* Keyboard hints inside help texts. */
kbd {
  font-family: var(--mono);
  font-size: .78em;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--surface);
  padding: .05em .35em;
  color: var(--ink-2);
  white-space: nowrap;
}

/* The column cards are focusable so the mapping works without a mouse. */
.mcol:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* Visually hidden, still available to screen readers. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* Empty states inside cards and tables. */
.empty-state {
  padding: 2.5rem 1.5rem;
  text-align: center;
  color: var(--ink-3);
  font-size: .88rem;
}

/* File input inside the dropzone stays reachable for keyboard and screen
   readers, the dropzone itself is the visible control. */
.dropzone input[type="file"] {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* Validation report groups (Prüfung). */
.err-group + .err-group { margin-top: 1.1rem; }
.err-group .err-head {
  display: flex; align-items: center; gap: .6rem;
  margin-bottom: .6rem;
}
.err-group .err-head h4 { font-size: .9rem; font-weight: 700; }
.err-rows { display: grid; gap: .4rem; }
.err-row {
  display: grid; grid-template-columns: 5.5rem 1fr;
  gap: .8rem; align-items: baseline;
  padding: .55rem .8rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: .85rem;
}
.err-row .err-line { font-family: var(--mono); font-size: .78rem; color: var(--ink-3); }

/* ============================================================
   EINSTELLUNGEN (Erscheinungsbild)
   ============================================================ */
.einstellungen-grid { display: grid; grid-template-columns: minmax(0,1fr) 320px; gap: 1.1rem; align-items: start; }
.einstellungen-spalte { display: grid; gap: 1.1rem; }
.einstellungen-vorschau { display: grid; gap: 1.1rem; position: sticky; top: 84px; }
.einstellungen .card { padding: 1.1rem 1.3rem 1.3rem; }
.einstellungen h3 { font-size: .95rem; font-weight: 700; margin-bottom: .2rem; }

.feld { display: block; margin-top: .8rem; }
.feld > span { display: block; font-size: .8rem; font-weight: 600; color: var(--ink-2); margin-bottom: .3rem; }
.feld input[type=text], .feld select { width: 100%; }
.feld small { display: block; font-size: .75rem; color: var(--ink-3); margin-top: .3rem; }
.feld-eingerueckt { margin-left: 1.7rem; }
.feld-reihe { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .8rem; }
.feld-hinweis { font-size: .78rem; color: var(--ink-3); margin: .2rem 0 .6rem; }

.radio-zeile { display: flex; align-items: center; gap: .55rem; margin-top: 1rem; font-weight: 600; font-size: .88rem; cursor: pointer; }
.radio-zeile input { accent-color: var(--brand); width: 16px; height: 16px; }

.farb-eingabe { display: flex; align-items: center; gap: .6rem; }
.farb-eingabe input[type=color] { width: 46px; height: 40px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: none; padding: 3px; cursor: pointer; }
.farb-eingabe code { font-size: .78rem; color: var(--ink-3); }

.icon-wahl { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: .5rem; margin-top: .6rem; }
.icon-kachel {
  display: flex; flex-direction: column; align-items: center; gap: .3rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .6rem .3rem; cursor: pointer; font-size: .72rem; color: var(--ink-2);
  transition: border-color .12s, background .12s;
}
.icon-kachel:hover { border-color: var(--brand-soft); }
.icon-kachel input { position: absolute; opacity: 0; width: 0; height: 0; }
.icon-kachel:has(input:checked), .icon-kachel.is-gewaehlt { border-color: var(--brand); background: var(--brand-tint); color: var(--brand-ink); }
.icon-kachel:has(input:focus-visible) { box-shadow: 0 0 0 3px var(--brand-tint-2); }

.vorschau-marke { display: flex; align-items: center; gap: .8rem; margin: .6rem 0 1rem; }
.vorschau-marke strong { display: block; font-size: .95rem; }
.vorschau-marke small { color: var(--ink-3); font-size: .78rem; }
.vorschau-knoepfe { display: flex; gap: .5rem; flex-wrap: wrap; }
.vorschau-knoepfe .btn { cursor: default; }

/* Read-only broker list in the user editor: the same rhythm as the checkbox
   list beside it, so a row nobody may change does not look like a different
   kind of thing. */
/* The user table has to fit a laptop without scrolling sideways, so every
   column that can grow with its content carries a cap. Budget at 1280px:
   240 + 200 + 240 + 150 + 120 plus padding stays under the ~976px of content
   area, and the two capped columns truncate instead of pushing the actions
   button out of sight. */
.benutzer-tabelle .zelle-lang { max-width: 15rem; }
.benutzer-tabelle .zelle-rolle { max-width: 12.5rem; overflow: hidden; text-overflow: ellipsis; }
.benutzer-tabelle .zelle-rolle .cell-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.benutzer-tabelle .zelle-aktion { white-space: nowrap; width: 1%; }

.makler-lese { list-style: none; display: grid; gap: .25rem; margin: .3rem 0 0; }
.makler-lese li { font-size: .86rem; }

.mandanten-zeichen { display: flex; align-items: center; gap: .6rem; }
.mandanten-zeichen strong { display: block; font-size: .9rem; }
.mandanten-zeichen small { color: var(--ink-3); font-size: .74rem; }

/* ============================================================
   VORSCHLAGSWESEN (Regeln)
   ============================================================ */
/* The three sources a suggestion can come from, doubling as the navigation of
   the screen: each card carries its own total and opens its own section. */
.quellen {
  display: grid; gap: .8rem; margin-top: 1.1rem;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
.quelle {
  display: flex; flex-direction: column; min-width: 0;
  padding: calc(1rem * var(--dichte)) calc(1.15rem * var(--dichte));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  text-decoration: none; color: inherit;
  position: relative;
  transition: border-color .12s, background .12s, box-shadow .12s;
}
.quelle:hover { border-color: var(--brand-soft); background: var(--surface); }
.quelle.ist-offen {
  background: var(--surface);
  border-color: var(--brand-soft);
  box-shadow: var(--shadow), inset 0 3px 0 0 var(--brand);
}
.quelle .q-kopf {
  display: flex; align-items: center; gap: .5rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3);
}
.quelle.ist-offen .q-kopf { color: var(--brand-ink); }
.quelle .q-punkt { width: 8px; height: 8px; border-radius: 50%; background: var(--line); border: 1px solid var(--ink-3); flex-shrink: 0; }
.quelle.ist-offen .q-punkt { background: var(--brand); border-color: var(--brand); }
.quelle .q-wert {
  font-size: 1.5rem; font-weight: 700; letter-spacing: -.03em;
  margin-top: .35rem; font-variant-numeric: tabular-nums;
}
.quelle .q-wert.is-leer { font-size: .92rem; font-weight: 650; color: var(--ink-3); letter-spacing: 0; }
.quelle .q-text { font-size: .8rem; color: var(--ink-2); margin-top: .4rem; }

/* Zwei der drei Quellen sind maschinell: das Gelernte, das sich das System aus
   Bestaetigungen gemerkt hat, und die wiedererkannten Dateistrukturen. Die Regeln
   sind von Hand gepflegt und bleiben markenfarben - die Farbe trennt hier
   gepflegt von gelernt, und genau das ist die Auskunft, die man braucht.
   Nie die Farbe allein: der Funke traegt die Aussage mit. */
.quelle.ist-ki:hover { border-color: var(--ki-line); }
.quelle.ist-ki.ist-offen { border-color: var(--ki-line);
  box-shadow: var(--shadow), inset 0 3px 0 0 var(--ki); }
.quelle.ist-ki.ist-offen .q-kopf { color: var(--ki-ink); }
.quelle.ist-ki .q-punkt { display: none; }
.quelle.ist-ki .q-funke { color: var(--ink-3); flex-shrink: 0; }
.quelle.ist-ki.ist-offen .q-funke { color: var(--ki); }
.quelle.ist-ki.ist-offen .q-wert { color: var(--ki-ink); }

/* Eine gelernte Zeile ist eine Maschinenentscheidung - der Herkunftsvermerk sagt
   das ausdruecklich, statt es der Farbe allein zu ueberlassen. */
.ki-herkunft { display: inline-flex; align-items: center; gap: .3rem;
  font-size: .72rem; font-weight: 650; color: var(--ki-ink);
  background: var(--ki-bg); border: 1px solid var(--ki-line);
  border-radius: 999px; padding: .1rem .45rem; white-space: nowrap; }
.ki-herkunft svg { color: var(--ki); }

/* Einmal je Abschnitt, nicht einmal je Zeile: in diesen beiden Tabellen ist
   *jeder* Eintrag maschinell. Zeilenweise eingefaerbt waere der halbe Bildschirm
   violett, und dann sagt die Farbe nichts mehr. Sie markiert die Ausnahme. */
.ki-band { display: flex; align-items: flex-start; gap: .55rem;
  margin-top: 1.1rem; padding: .6rem .9rem;
  font-size: .82rem; color: var(--ki-ink);
  background: var(--ki-bg); border: 1px solid var(--ki-line);
  border-radius: var(--radius-sm); }
.ki-band svg { color: var(--ki); margin-top: .12rem; }
.ki-band b { font-weight: 700; }
.quelle-fuss {
  font-size: .82rem; color: var(--ink-2); line-height: 1.5;
  margin-top: .9rem; padding-left: .8rem;
  border-left: 2px solid var(--line);
  max-width: 88ch;
}

.probe-titel {
  font-size: .74rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3); margin: 1.1rem 0 .5rem;
}
.probe-titel:first-of-type { margin-top: 0; }
/* The rules table needs the whole card width; inside the card padding its last
   column - the only action it has - fell off the edge. It runs to the card
   border instead, which is exactly the padding it gets back. */
.probe-ergebnis .table-wrap {
  margin-left: calc(-1.5rem * var(--dichte));
  margin-right: calc(-1.5rem * var(--dichte));
  border-radius: 0;
}

/* A learned entry whose target no longer exists keeps its row but is marked -
   it is the finding somebody came here for, not a blank. */
tbody tr.ist-verwaist { background: color-mix(in srgb, var(--err-bg) 45%, transparent); }

/* Remembered column pictures of whole files.
   minmax(0,1fr) and min-width:0 throughout: a header line of nineteen column
   names is one long unbreakable string, and grid children sized to their
   max-content push the card - and the page with it - to twice the viewport
   instead of truncating inside. */
.schema-liste { display: grid; grid-template-columns: minmax(0, 1fr); gap: .8rem; margin-top: 1.5rem; }
.schema-liste > .card { min-width: 0; }
.schema-kopf {
  font-size: .8rem; color: var(--ink-2);
  padding: .55rem .7rem; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--line-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.schema-paare { display: grid; gap: .4rem; margin-top: .9rem; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); min-width: 0; }
.schema-paare > * { min-width: 0; }
.schema-paar {
  display: grid; grid-template-columns: minmax(0,1fr) auto minmax(0,1fr);
  gap: .5rem; align-items: center;
  font-size: .82rem;
  padding: .4rem .6rem;
  border: 1px solid var(--line-soft); border-radius: var(--radius-sm);
}
.schema-paar svg { color: var(--ink-3); }
.schema-paar .sp-quelle, .schema-paar .sp-ziel { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.schema-paar .sp-ziel { font-weight: 650; }
.schema-defekt {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  margin-top: .9rem; padding: .6rem .8rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: .82rem; color: var(--ink-2);
}

.probe-form { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; }
/* Basis aus #47; die Suchzeile bleibt bewusst einen Hauch hoeher. */
.probe-form input[type="text"] { flex: 1; min-width: 16rem; min-height: 42px; }
.probe-form select { min-height: 42px; }
.probe-ergebnis { margin-top: 1.1rem; }
.probe-hinweis {
  font-size: .82rem; color: var(--ink-2); line-height: 1.5;
  padding: .7rem .9rem; margin-bottom: .8rem;
  border-radius: var(--radius-sm);
  background: var(--brand-tint);
}
.probe-hinweis strong { color: var(--brand-ink); }

/* Seven columns of which two carry long names. At the shared cell padding the
   row runs past the card and puts the remove button out of sight - on a table
   whose last column is the only action it has. Tighter padding and shorter
   truncation bring it back inside; the full value stays on the title. */
.regel-tabelle th, .regel-tabelle td {
  padding-left: calc(.7rem * var(--dichte));
  padding-right: calc(.7rem * var(--dichte));
}
.regel-tabelle .zelle-lang { max-width: 12.5rem; }

.regel-art { font-size: .82rem; color: var(--ink-2); }
.regel-ohne-ziel, .regel-global { font-size: .82rem; color: var(--ink-3); }
.regel-hinweis-zeile td {
  font-size: .8rem; color: var(--ink-2); white-space: normal;
  background: var(--warn-bg);
}
.regel-hinweis-zeile .badge { margin-right: .5rem; }

.btn-klein { min-height: 30px; padding: .18rem .6rem; font-size: .8rem; }

.regel-neu { margin-top: 1.1rem; }
.regel-neu > summary {
  display: inline-flex; align-items: center; gap: .45rem;
  cursor: pointer; list-style: none;
  font-size: .88rem; font-weight: 650; color: var(--brand);
  padding: .5rem .7rem; margin-left: -.7rem;
  border-radius: var(--radius-sm);
}
.regel-neu > summary::-webkit-details-marker { display: none; }
.regel-neu > summary:hover { background: var(--brand-tint); }
.regel-neu[open] > summary { margin-bottom: .6rem; }
.regel-neu[open] > summary svg { transform: rotate(45deg); }
.regel-neu > summary svg { transition: transform .15s; }

.notice { border-radius: var(--radius-sm); padding: .7rem 1rem; margin-bottom: 1rem; font-size: .86rem; }
.notice-ok { background: var(--ok-bg); color: var(--ok); border: 1px solid var(--ok-line, transparent); }
.notice-error { background: var(--err-bg); color: var(--err); border: 1px solid var(--err-line, transparent); }
.notice-warn { background: var(--warn-bg); color: var(--warn); border: 1px solid var(--warn-line); }

@media (max-width: 980px) { .einstellungen-grid { grid-template-columns: 1fr; } .einstellungen-vorschau { position: static; } }

/* ---------------------------------------- Vertragsliste: Filter und Auswahl */
/* Bulk editing is a capability of the contract list, not a screen of its own.
   Everything below is therefore built to disappear: the filter panel is folded
   away, and the action bar is absent until something is selected. */

.filterblock { margin-bottom: 1rem; }
.filterblock > summary {
  display: inline-flex; align-items: center; gap: .45rem;
  cursor: pointer; list-style: none;
  font-size: .88rem; font-weight: 650; color: var(--brand);
  padding: .5rem .7rem; margin-left: -.7rem;
  border-radius: var(--radius-sm);
}
.filterblock > summary::-webkit-details-marker { display: none; }
.filterblock > summary:hover { background: var(--brand-tint); }
.filterblock > summary .tcount {
  background: var(--brand); color: var(--on-brand);
  border-radius: 999px; padding: .05rem .45rem; font-size: .75rem;
}

.filterform {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.1rem 1.25rem;
  display: grid; gap: 1.1rem;
}
.filtergruppe { border: 0; padding: 0; margin: 0; }
.filtergruppe legend {
  font-size: .84rem; font-weight: 700; color: var(--ink);
  padding: 0; margin-bottom: .5rem;
}
.filterhinweis { font-size: .8rem; color: var(--ink-2); line-height: 1.45; margin: .45rem 0 0; }

.filterchips { display: flex; flex-wrap: wrap; gap: .45rem; }
.filterchip {
  display: inline-flex; align-items: center; gap: .4rem;
  border: 1px solid var(--line); border-radius: 999px;
  padding: .32rem .75rem; font-size: .83rem; cursor: pointer;
  background: var(--surface); color: var(--ink);
}
.filterchip input { margin: 0; }
.filterchip:hover { border-color: var(--brand-soft); }
.filterchip .num { color: var(--ink-2); font-variant-numeric: tabular-nums; font-weight: 650; }
.filterchip.is-an {
  border-color: var(--brand); background: var(--brand-tint); color: var(--brand-ink);
}
.filterchip.is-an .num { color: var(--brand-ink); }
/* Why the greyed-out merkmale cannot be measured, spelled out under the chips.
   The reason used to live only in a title attribute, which is a tooltip nobody
   opens - and the chip showed the raw rule key instead of its name. */
.filtergruende {
  margin: .5rem 0 0; padding-left: 1.1rem;
  font-size: .8rem; color: var(--ink-2); line-height: 1.5;
}
.filtergruende li + li { margin-top: .3rem; }
.filtergruende strong { color: var(--ink); font-weight: 650; }
/* A filter that cannot be answered yet is shown, not hidden - leaving it out
   would read as "the bestand has been checked for this". */
.filterchip.is-aus {
  cursor: help; opacity: .55; border-style: dashed;
  color: var(--ink-2); background: var(--surface-2);
}

.filterfelder {
  display: grid; gap: .7rem;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.filterfelder label { display: grid; gap: .25rem; font-size: .8rem; color: var(--ink-2); min-width: 0; }
/* Basis aus #47, im Filterpanel eine Stufe kompakter. Der ringlose Fokus, den
   dieser Block frueher deklarierte, ist damit weg - ein Fokus, drei Lesarten
   war der Befund. */
/* width/min-width halten das Feld in seiner Rasterspalte. Ein <select> ist von
   sich aus so breit wie seine laengste Option: "HELVETIA Schweizerische
   Versicherungsgesellschaft AG (1)" machte das Gesellschaftsfeld 427px breit in
   einer 219px-Spalte, worauf es unter die Beschriftung des Nachbarfeldes lief
   und seinen Pfeil aus dem sichtbaren Bereich schob. Betraf das Filterpanel der
   Vertragsliste genauso; text-overflow: ellipsis aus der Basis kappt jetzt. */
.filterfelder select, .filterfelder input {
  font-size: .86rem; min-height: 36px; padding-top: .35rem; padding-bottom: .35rem;
  width: 100%; min-width: 0;
}

.filterfuss { display: flex; flex-wrap: wrap; align-items: center; gap: .7rem; }
.filterfuss .filterhinweis { margin: 0; }

.filteraktiv { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: 1rem; }
.filtermarke {
  display: inline-flex; align-items: center; gap: .45rem;
  background: var(--brand-tint); color: var(--brand-ink);
  border: 1px solid var(--brand-soft); border-radius: 999px;
  padding: .25rem .7rem; font-size: .81rem; font-weight: 600; text-decoration: none;
}
.filtermarke:hover { background: var(--err-bg); color: var(--err); border-color: var(--err-line); }

.spalte-wahl { width: 34px; text-align: center; padding-right: 0 !important; }
.spalte-wahl input { cursor: pointer; margin: 0; }
tr.is-gewaehlt > td { background: var(--brand-tint); }

/* Dasselbe Material wie die Feldleiste in der Zuordnung: durchscheinend mit Unschaerfe,
   eingerueckt, Verlauf aus --brand, Schatten nach oben. Zwei klebende Werkzeugleisten im
   selben Produkt duerfen nicht aus verschiedenen Baukaesten kommen - vorher war das hier
   eine dunkle Platte. Der Verlauf kommt aus --brand, damit das White-Labeling traegt. */
.aktionsleiste {
  position: sticky; bottom: 0; z-index: 20;
  margin: 1rem 1.6rem 0;
}
.aktionsleiste[hidden] { display: none; }
/* The list is a bottom-bar screen like the mapping step (no footer, no
   content padding), but its bar only exists while rows are selected. With
   nothing selected the table would end hard at the viewport edge - the
   padding returns until the bar is there to take over. */
.content-bottombar:has(> .aktionsleiste[hidden]) { padding-bottom: 3rem; }
.aktionsleiste-innen {
  color: var(--ink);
  background:
    linear-gradient(158deg,
      color-mix(in srgb, var(--brand) 8%, transparent) 0%,
      color-mix(in srgb, var(--brand) 3%, transparent) 46%,
      color-mix(in srgb, var(--brand) 7%, transparent) 100%),
    color-mix(in srgb, var(--surface) 78%, transparent);
  backdrop-filter: blur(18px) saturate(150%);
  border: 1px solid color-mix(in srgb, var(--brand) 20%, transparent);
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: 0 -1px 0 color-mix(in srgb, var(--ink) 6%, transparent),
              0 -8px 22px -4px rgba(23,32,58,.14),
              0 -34px 64px -28px rgba(23,32,58,.38);
  padding: .7rem 1.1rem .8rem; display: grid; gap: .35rem;
}
.aktionsleiste-zahl {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
  font-size: .88rem;
}
.aktionsleiste-zahl strong { font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.aktionsleiste-zahl .btn-ghost { color: var(--brand-ink); }
.aktionsleiste-zahl .btn-ghost:hover { background: var(--brand-tint); color: var(--brand-ink); }
.aktionsleiste-hinweis { font-size: .8rem; color: var(--ink-2); line-height: 1.45; }

.aktionsleiste-form {
  display: flex; flex-wrap: wrap; align-items: center; gap: .45rem;
  padding-top: .25rem;
}
/* Basis aus #47, in der klebenden Leiste am dichtesten. Auch hier gewinnt der
   eine Fokusring - das outline-Experiment dieses Blocks ist Geschichte. */
.aktionsleiste-form select {
  font-size: .83rem; min-height: 30px; max-width: 17rem;
  padding: .18rem 2.1rem .18rem .5rem;
}

/* Before and after side by side. The old value recedes, the new one does not -
   but neither borrows the red of an error: nothing has gone wrong here, this is
   a preview. */
.wert-vorher { color: var(--ink-2); text-decoration: line-through; }
.wert-nachher { color: var(--brand-ink); font-weight: 650; }
/* The value of a contract that is being skipped. It is not struck through,
   because nothing is being taken away from it - it stays as it is. */
.wert-bleibt { color: var(--ink-2); }

@media (max-width: 720px) {
  .filterfelder { grid-template-columns: 1fr; }
  .aktionsleiste-form select { max-width: 100%; flex: 1 1 100%; }
}

/* ---------------------------------------------------------------------------
   Report per insurer (/report)

   One rule shapes all of it: the qualification of a figure sits inside the
   figure's own block, never beside it. .bz-luecke is therefore attached to the
   card of its insurer and picks up the warning colour of the design - never a
   fixed hex, or the white labelling breaks.
   ------------------------------------------------------------------------- */
.bericht-zuschnitt {
  display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-end;
}
.bericht-zuschnitt label { display: grid; gap: .3rem; min-width: 14rem; }
.bericht-zuschnitt label > span { font-size: .8rem; font-weight: 600; color: var(--ink-2); }
.bericht-zuschnitt-aktionen {
  display: flex; flex-wrap: wrap; gap: .5rem; margin-left: auto;
}

.bericht-kopf { margin-top: 1.1rem; }
.bericht-kopf dl {
  display: grid; grid-template-columns: 11rem 1fr; gap: .55rem 1.2rem;
  margin-top: .9rem; font-size: .87rem; line-height: 1.5;
}
.bericht-kopf dt { font-weight: 650; color: var(--ink-2); }
.bericht-kopf dd { color: var(--ink); margin: 0; }
.bericht-kopf dd a { color: var(--brand); font-weight: 600; }
.bericht-kopf dd.ist-luecke { color: var(--warn); }
/* "Aufgefangen" ist keine Luecke, sondern eine Herkunft: die Gesellschaft hat
   das System gesetzt, nicht der Nutzer. Violett mit Funken, nie Farbe allein -
   und nicht der Warnton, der aus einem Systemvorschlag eine Beanstandung
   machen wuerde. */
.ki-herkunft {
  display: inline-flex; align-items: center; gap: .28rem;
  color: var(--ki-ink); font-weight: 600;
}
.ki-herkunft svg { color: var(--ki); flex-shrink: 0; }
/* The restriction gets its own line so it is not skimmed past as a clause. */
.bericht-kopf .bericht-einschraenkung {
  display: block; margin-top: .3rem; color: var(--warn); font-size: .83rem;
}

.bericht-liste { display: grid; gap: .7rem; margin-top: 1.1rem; }
.bericht-zeile { padding: 1rem 1.2rem; }
.bericht-zeile.hat-luecke { border-color: var(--warn-line); }
.bericht-zeile.ist-offen { box-shadow: var(--shadow-lg); }

/* Drei feste Spalten statt loser Flexbox: Name | Kennzahl | Aktionen. Im
   Flex-Umbruch stand die Kennzahl je Karte woanders - ihr linker Rand hing an
   der Namensbreite, ihr rechter an der Breite der "Fuer <Gesellschaft>"-Zeile,
   und sechs Karten untereinander lasen sich wie verstreut. Im Raster teilen
   alle Karten dieselben Kanten, die Betraege stehen buendig untereinander. */
.bz-kopf {
  display: grid; grid-template-columns: minmax(15rem, 1fr) auto max-content;
  gap: .8rem 1.6rem; align-items: center;
}
.bz-name { min-width: 0; }
.bz-name strong { font-size: 1rem; letter-spacing: -.01em; }
.bz-herkunft {
  display: block; margin-top: .2rem; font-size: .81rem; color: var(--ink-2);
}
.bz-wert { text-align: right; }
.bz-zahl {
  display: block; font-size: 1.35rem; font-weight: 700; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.bz-zahl.is-leer { color: var(--ink-3); font-weight: 600; }
.bz-bezug { display: block; margin-top: .15rem; font-size: .78rem; color: var(--ink-3); }
.bz-aktionen {
  align-self: center; display: grid; gap: .3rem; justify-items: end; white-space: nowrap;
}
.bz-auf {
  font-size: .82rem; font-weight: 600; color: var(--brand); text-decoration: none;
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: .3rem .7rem;
}
.bz-auf:hover { border-color: var(--brand-soft); background: var(--brand-tint); }
/* The Fassung addressed to this insurer. Quieter than the row's own action -
   it is the last step, not the first. */
.bz-fuer { font-size: .76rem; color: var(--ink-3); }
.bz-fuer a { color: var(--brand); font-weight: 600; text-decoration: none; margin-left: .35rem; }
.bz-fuer a:hover { text-decoration: underline; }

.bericht-fassungshinweis {
  margin: .7rem .2rem 0; font-size: .82rem; line-height: 1.5; color: var(--ink-2);
}
.bericht-fassungshinweis strong { color: var(--ink); font-weight: 650; }

.bz-luecke {
  display: flex; align-items: flex-start; gap: .45rem;
  margin-top: .7rem; padding: .5rem .7rem;
  background: var(--warn-bg); border: 1px solid var(--warn-line);
  border-radius: var(--radius-sm);
  color: var(--warn); font-size: .82rem; line-height: 1.45; font-weight: 600;
}
.bz-luecke svg { flex: none; margin-top: .1rem; }

.bz-auffaellig {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: .6rem;
}
.bz-gekuerzt { font-size: .78rem; color: var(--ink-3); }

.bz-vertraege { margin-top: .9rem; border-top: 1px solid var(--line-soft); padding-top: .3rem; }
.bz-vertraege .table-foot { padding-left: 0; padding-right: 0; }

@media (max-width: 860px) {
  .bericht-kopf dl { grid-template-columns: 1fr; gap: .1rem .6rem; }
  .bericht-kopf dd { margin-bottom: .55rem; }
  .bz-kopf { grid-template-columns: 1fr; }
  .bz-wert { text-align: left; }
  .bz-aktionen { justify-items: start; }
  .bericht-zuschnitt-aktionen { margin-left: 0; }
}

/* ---------- Vertragsmaske: alle Felder, die die Verwaltung erwartet ----------
   Gruppiert wie dort - erst Schema, dann Kategorie. Leere Felder bleiben
   stehen; sie sind die eigentliche Auskunft dieser Ansicht. */
.vmaske-schema { margin-top: 1.2rem; }
.vmaske-kopf {
  display: flex; align-items: baseline; gap: .6rem;
  padding-bottom: .4rem; border-bottom: 1px solid var(--line);
}
.vmaske-kopf strong { font-size: .9rem; }
.vmaske-kopf span { font-size: .76rem; color: var(--ink-3); }
.vmaske-kategorie {
  font-size: .72rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3); margin: .9rem 0 .4rem;
}
/* Ein nicht geliefertes Feld sieht leer aus, nicht fehlerhaft: es ist kein
   Fehler, dass etwas fehlt - es ist die Information. */
.vmaske-schema input::placeholder { color: var(--ink-3); font-style: italic; }
.vmaske-pflicht { color: var(--warn); }

/* Vertragsliste: alle Spalten sollen sichtbar sein, auch die letzte.
   Die Sparte war die einzige lange Spalte ohne Deckel und hat die Tabelle
   ueber die Breite gedrueckt - der Status rechts fiel aus dem Bild. Gekuerzt
   mit vollem Namen im Titel ist besser als vollstaendig und unsichtbar. */
.zelle-kurz { max-width: 11rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zelle-schmal { white-space: nowrap; }
/* Kunde und Gesellschaft etwas enger, damit die Summe passt. */
.table-wrap .zelle-lang { max-width: 13rem; }

/* Befunde am Vertrag. Dieselben Saetze wie in der Befundliste - zwei
   Formulierungen fuer denselben Sachverhalt waeren zwei Sachverhalte. */
.befund-block { margin-bottom: 1.1rem; }
.befund-liste { list-style: none; margin: .9rem 0 0; padding: 0; display: grid; gap: .45rem; }
.befund-eintrag {
  display: grid; gap: .1rem; padding: .55rem .8rem;
  border-radius: var(--radius-sm); border-left: 3px solid var(--line);
  background: var(--surface-2);
}
.befund-eintrag.befund-err { border-left-color: var(--err); background: var(--err-bg); }
.befund-eintrag.befund-warn { border-left-color: var(--warn); background: var(--warn-bg); }
.befund-eintrag.befund-ok { border-left-color: var(--line); }
.befund-titel { font-size: .85rem; font-weight: 650; color: var(--ink); }
.befund-grund { font-size: .78rem; color: var(--ink-2); }

/* Quittierte Befunde bleiben stehen und ziehen nur optisch um: wer sie
   abgehakt hat, soll sehen koennen, dass es sie gab. */
.befund-kopf { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.befund-eintrag.befund-quitt { border-left-color: var(--ok-line); background: var(--surface-2); opacity: .85; }
.befund-eintrag.befund-quitt .befund-titel { font-weight: 600; color: var(--ink-2); }
.befund-erneuert { font-size: .76rem; color: var(--warn); margin-top: .15rem; }
.befund-quittung { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin-top: .35rem; font-size: .78rem; color: var(--ink-2); font-style: italic; }
.befund-quittung form { margin: 0; }
.befund-abhaken { display: flex; gap: .45rem; margin-top: .45rem; flex-wrap: wrap; }
.befund-abhaken input[type=text] {
  flex: 1; min-width: 12rem; font: inherit; font-size: .78rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .25rem .5rem; background: var(--surface);
}
.befund-abhaken input[type=text]:focus { outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-tint-2); }

/* ============================================================
   BETRIEBSARTEN - WZ chip and stable row layout
   ============================================================
   The WZ code is the anchor somebody finds an entry by, so it gets a chip of
   its own instead of being text in a cell. Not solved with .badge + .mono:
   .mono sets .85em, which on the badge's .76rem yields a size you have to hunt
   for rather than see. */
.wz-chip {
  display: inline-block;
  font-family: var(--mono); font-size: .78rem; font-weight: 600;
  font-variant-numeric: tabular-nums;
  padding: .18rem .55rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink);
  white-space: nowrap;
}
/* Switching a row from reading to editing must not reflow the table. Without
   binding widths the browser distributes columns by content: the action column
   needs 36px more for two buttons than for one and takes it from the text
   columns. Measured, that was 427/427/176 while reading against 412/405/212
   while editing - half the row moves although only one cell changed. With
   table-layout: fixed the header widths govern, and the action column is sized
   for the wider of the two states. Row height was already stable at 68px: the
   two-line read cell and the 40px input add up to the same height. */
.bt-liste { table-layout: fixed; }

/* ============================================================
   DATENEXPORT - Aufklapper "Was die Formate unterscheiden"
   ============================================================
   Die Erklaerung zu Excel, CSV und GDV ist lang und trotzdem wichtig. Ueber der
   Tabelle ausgeschrieben schob sie den Knopf, um den es auf der Seite geht,
   unter die Falz; als blosses details/summary war sie danach so unscheinbar,
   dass sie niemand als anklickbar erkannte.

   Deshalb eine eigene Klasse statt .filterblock: dessen Zusammenfassung ist
   eine nackte Textzeile in Markenfarbe, was neben einer Tabelle voller Knoepfe
   nicht als Bedienelement liest. Hier traegt die ganze Zeile die Kartenflaeche,
   und Icon links plus Chevron rechts sagen vor dem ersten Klick, dass sich
   etwas oeffnen laesst.

   Reines CSS, kein Skript: details/summary klappt selbst, ist mit der Tastatur
   erreichbar und meldet seinen Zustand von sich aus an die Vorlesesoftware. */
.formathilfe {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-bottom: 1.1rem;
}
.formathilfe > summary {
  display: flex; align-items: center; gap: .7rem;
  padding: calc(.95rem * var(--dichte)) calc(1.5rem * var(--dichte));
  cursor: pointer; list-style: none;
  border-radius: var(--radius);
  transition: background .15s, border-color .15s;
}
.formathilfe > summary::-webkit-details-marker { display: none; }
.formathilfe > summary:hover { background: var(--surface-2); }
.formathilfe > summary:focus-visible {
  outline: none; box-shadow: 0 0 0 3px var(--brand-tint-2);
}
/* Das Info-Zeichen in der Farbe der Marke, damit die Zeile nicht wie ein
   Warnhinweis aussieht - sie erklaert, sie warnt nicht. Der Vorbehalt zu GDV
   steht bewusst am Knopf und nicht hier. */
.formathilfe-icon { color: var(--brand); flex: 0 0 auto; }
.formathilfe-text { display: grid; gap: .1rem; }
.formathilfe-titel { font-size: .92rem; font-weight: 650; color: var(--ink); }
.formathilfe-sub { font-size: .8rem; color: var(--ink-2); }
/* Zeigt nach unten, solange zu ist, und dreht sich beim Oeffnen um. Die
   Drehung ist die Rueckmeldung, dass der Klick angekommen ist. */
.formathilfe-chevron {
  margin-left: auto; flex: 0 0 auto; color: var(--ink-3);
  transition: transform .18s;
}
.formathilfe[open] > summary .formathilfe-chevron { transform: rotate(180deg); }
.formathilfe[open] > summary { border-bottom: 1px solid var(--line-soft); border-radius: var(--radius) var(--radius) 0 0; }
.formathilfe-inhalt { padding: calc(1.1rem * var(--dichte)) calc(1.5rem * var(--dichte)); }
.formathilfe-inhalt p { color: var(--ink-2); }
.formathilfe-inhalt p + p { margin-top: .6rem; }

/* ============================================================
   HERKUNFT - eigener Rhythmus im geliehenen Rahmen
   ============================================================
   Der Herkunftsblock der Vertragsdetailseite (view/vertraege/detail.php)
   benutzt vom Aufklapper der Exportseite nur noch den Rahmen: Karte, Summary,
   Chevron. Innen sind die beiden Verwendungen auseinandergelaufen. Die
   Exportseite erklaert in Absaetzen, die Herkunft zeigt Fakten, zwei Tabellen
   und eine Zeitleiste - also braucht sie den Rhythmus DIESER Seite und nicht
   die Absatztypografie der anderen.

   Nichts davon ist neu erfunden. Die Auszeichnung der Faktenlabels ist die
   Beschriftung, die dieses Stylesheet an sechs Stellen fuehrt (.72rem, .07em,
   700, versal, ink-3 - dieselbe Zeile wie thead th), Titel und Erklaerzeile
   der Abschnitte sind card-head auf h4 heruntergezogen, und die Zeitleiste ist
   unveraendert die .timeline der Status-Historie zwei Karten weiter oben.

   Warum die h4-Regeln von vorher weg sind: sie hingen an .formathilfe-inhalt
   und haetten damit auch die Exportseite getroffen, sobald dort je eine
   Zwischenueberschrift stuende. Die Zustaendigkeit liegt jetzt beim Abschnitt,
   nicht beim Rahmen. */

/* Der Aufklapper traegt wie .demo-note nur einen Abstand nach unten: er
   eroeffnet auf der Exportseite den Bildschirm und braucht oben nichts. Am
   Vertrag steht er unter dem Detailraster und lag deshalb buendig an der Karte
   darueber - dieselbe undeklarierte Luecke, die .card + .demo-note schon einmal
   geschlossen hat, und derselbe Wert. Nur nach Karte und Raster, damit der
   Aufklapper der Exportseite unveraendert bleibt. */
.card + .formathilfe,
.detail-grid + .formathilfe { margin-top: 1.1rem; }

/* Fakten nebeneinander - entstanden als Entstehungsleiste der Herkunft,
   inzwischen das Muster fuer jede Handvoll Name-Wert-Paare (auch der Kopf der
   Import-Zeilen). auto-fit statt fester Spaltenzahl: bei schmalem Fenster
   bricht die Leiste von selbst um, ohne eigenen Umbruchpunkt. */
.fakten-leiste {
  display: grid; gap: .9rem 1.6rem;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  padding-bottom: 1.2rem;
  border-bottom: 1px solid var(--line-soft);
}
/* Ein Rasterfeld ist von sich aus mindestens so breit wie sein laengster
   unteilbarer Inhalt. Der Dateiname ist 40 Zeichen ohne Leerzeichen und schob
   die Leiste damit ueber ihre Spalte hinaus - gemessen 295px Inhalt in 262px
   Zelle, sichtbar als Dateiname, der in die Zeilennummer daneben lief. */
.fakt { min-width: 0; }
.fakt dt {
  font-size: .72rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3);
}
.fakt dd {
  font-size: .88rem; font-weight: 600; color: var(--ink); margin-top: .2rem;
  overflow-wrap: anywhere;
}
/* Der Zusatz unter einem Faktum ist Erlaeuterung, kein zweiter Fakt - er darf
   nicht im selben Gewicht danebenstehen. */
.fakt dd .cell-sub { font-weight: 400; margin-top: .15rem; }
/* Als Kartenkopf bekommt die Leiste das Innenmass der Karte; die Trennlinie
   zur Tabelle darunter bringt sie schon mit. */
.card > .fakten-leiste { padding: 1rem; margin: 0; }
/* Ein kleiner Weiter-Knopf im Zellenmass: die Pille des Sekundaerknopfs, eine
   Nummer kompakter. Ersetzt den nackten Browserlink - und die erste, stille
   Fassung (Markenfarbe ohne Unterstrich), die beim anthrazitfarbenen Mandanten
   wie blosser Text aussah. Eine Flaeche mit Rand bleibt in jeder Markenfarbe
   ein Knopf. */
.pfeil-link {
  display: inline-flex; align-items: center; gap: .35rem;
  color: var(--ink); font-weight: 600; font-size: .8rem;
  text-decoration: none;
  padding: .3rem .7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(23,32,58,.05);
  transition: background .15s, border-color .15s;
}
.pfeil-link:hover { border-color: var(--brand-soft); background: var(--brand-tint); }
.pfeil-link svg { flex-shrink: 0; color: var(--brand); }
/* Unter dem Dateinamen der Faktenleiste braucht die Pille Luft nach oben. */
.fakt .pfeil-link { margin-top: .3rem; }

/* Abschnitt: Titel und Erklaerzeile wie ein card-head, nur eine Stufe kleiner. */
.herkunft-abschnitt { margin-top: 1.7rem; }
.herkunft-abschnitt > h4 {
  font-size: .95rem; font-weight: 700; letter-spacing: -.01em; color: var(--ink);
}
.herkunft-abschnitt > .sub {
  font-size: .82rem; color: var(--ink-2);
  margin-top: .15rem; margin-bottom: .9rem;
}
.herkunft-abschnitt > .sub + .sub { margin-top: .55rem; }
.herkunft-abschnitt > .sub:last-child { margin-bottom: 0; }

/* Nachsatz unter einer Tabelle - der Vorbehalt zur hergeleiteten Spalte. */
.herkunft-satz { font-size: .82rem; color: var(--ink-2); margin-top: .7rem; }

/* Eine Quellspalte kann mehrere Ziele haben. Die gestrichelte Trennung sagt,
   dass es zwei Zuordnungen sind und nicht eine mit Zusatzzeile. */
.herkunft-ziel + .herkunft-ziel {
  margin-top: .5rem; padding-top: .5rem; border-top: 1px dashed var(--line);
}

/* Die Metazeile der Zeitleiste traegt hier ein Abzeichen fuer die Quelle. Nur
   im Herkunftsblock umgestellt: dieselbe .timeline zeigt in der Status-Historie
   reinen Text und soll dort nicht zum Flexcontainer werden. */
.herkunft-abschnitt .timeline .t-meta {
  display: flex; align-items: center; gap: .45rem; flex-wrap: wrap;
  margin-top: .2rem;
}
/* .timeline strong ist der Eintragstitel und deshalb ein Block. Im Fliesstext
   darunter hebt strong nur ein Wort hervor - als Block zerriss es den Satz:
   "Zurueckgenommen" stand allein, und "- der Wert steht wieder wie davor."
   begann als neue Zeile mit einem Bindestrich. */
.herkunft-abschnitt .timeline p strong { display: inline; font-weight: 650; }

/* Kundenmaske "Herkunft und Verlauf": der Kunde hat wenig Eigenschaften,
   aber eine Geschichte - der eine Entstehungssatz oben als gedaempftes Band
   (kein Karten-Auftritt: er beantwortet eine Rueckfrage, er ist nicht der
   Inhalt), rechts daneben die Zeitleiste. Die Zeitleiste selbst ist dieselbe
   .timeline wie an Vertrag und Status-Historie; hier stehen nur ihre
   Meta-Zeile (Flexcontainer wie im Herkunftsblock) und der stille
   Vertrags-Link. */
.kunde-quelle {
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  padding: .85rem 1.1rem; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--line-soft);
  font-size: .85rem; color: var(--ink-2); margin-bottom: 1.2rem;
}
.kunde-quelle svg { color: var(--brand); flex-shrink: 0; }
.kunde-quelle b { color: var(--ink); font-weight: 650; }
/* Der Satz nimmt die Restbreite und bricht IN sich um - sonst wandert er als
   Ganzes unter das Zeichen und laesst es allein auf der ersten Zeile stehen. */
.kunde-quelle > span:not(.spacer) { flex: 1 1 22rem; min-width: 0; }
.kunde-quelle .spacer { flex: 0; }
.kunde-verlauf-meta {
  display: flex; align-items: center; gap: .45rem; flex-wrap: wrap;
  margin-top: .2rem;
}
.kunde-verlauf-vertrag { color: var(--brand); font-weight: 600; text-decoration: none; }
.kunde-verlauf-vertrag:hover { text-decoration: underline; }
/* Die VSN ist der Weg zum Vertrag - wie in der Vertragsliste: Textfarbe,
   kein Unterstrich, Hover zeigt die Marke. */
.kunde-vsn { color: inherit; text-decoration: none; }
.kunde-vsn:hover { color: var(--brand); text-decoration: underline; }
/* Die Vertragstabelle muss in die linke Rasterspalte passen, ohne in sich zu
   scrollen: die Spalte bekommt etwas mehr vom Raster (deutsche Statusworte
   und Gesellschaftsnamen sind lang), die Zellen ruecken zusammen, und die
   langen Zellen kappen frueher - der volle Wert steht im title. */
.kunde-raster { grid-template-columns: 1.75fr 1fr; }
.kunde-vertraege thead th, .kunde-vertraege tbody td {
  padding-left: .6rem; padding-right: .6rem;
}
.kunde-vertraege .zelle-lang { max-width: 11rem; }
.timeline .kunde-verlauf-meta ~ p strong,
.kunde-verlauf-meta + p strong { display: inline; font-weight: 650; }

/* Kompakte Spaltentabelle der Herkunft: 19 Dateizeilen wollen ueberflogen
   werden, nicht gelesen. Halbe Zellhoehe, die Spaltennummer steht klein vor
   dem Namen statt in einer eigenen Spalte, und die Zielgruppe (.hk-gruppe)
   inline neben dem Feldnamen statt als zweite Zeile unter jedem Eintrag. */
.herkunft-tabelle tbody td { padding: calc(.5rem * var(--dichte)) calc(1rem * var(--dichte)); }
.herkunft-tabelle .hk-nr {
  display: inline-block; min-width: 1.7em; margin-right: .4rem;
  color: var(--ink-3); font-size: .8rem; font-variant-numeric: tabular-nums;
}
/* Zeilen, aus denen nichts wurde, treten als Grauwert zurueck. Die Aussage
   der Tabelle ist "was kam an" - acht gleichgewichtige "nicht uebernommen"
   verdeckten sie. */
.herkunft-tabelle tr.hk-leer td { color: var(--ink-3); }
.hk-gruppe { font-size: .76rem; font-weight: 400; color: var(--ink-3); margin-left: .4rem; }

/* Die Konstanten des Imports als Faktenraster wie die Entstehungsleiste,
   keine Tabelle: Feld und Wert gehoeren nebeneinander, nicht an zwei
   Bildschirmraender. Erbt das Raster von .fakten-leiste und nimmt dessen
   Abschlusslinie zurueck; die Feldnamen bleiben in Normalschrift, weil fuenf
   Versalzeilen wie "PRIVATHAFTPFLICHTVERSICHERUNG" keine Fakten mehr sind,
   sondern eine Wand. */
.herkunft-konstanten { border-bottom: none; padding-bottom: 0; }
.herkunft-konstanten dt {
  text-transform: none; letter-spacing: 0;
  font-size: .8rem; font-weight: 600; color: var(--ink-2);
}
.herkunft-konstanten dd { font-weight: 500; margin-top: .25rem; }

/* Zeilen eines Imports: die Nummernspalte schrumpft auf ihren Inhalt, sonst
   verteilt die Tabelle den Platz, den die gekappte Inhaltsspalte freigibt,
   als Leerraum vor einer zweistelligen Zahl. Die Inhaltsspalte darf breit
   sein - sie ist der Bildschirm. */
.zeilen-tabelle .zeilen-nr { width: 1%; }
.zeilen-tabelle .zelle-lang { max-width: 40rem; }

/* ------------------------------------------------------------- Datenhygiene */
/* Die Massenbearbeitung mehrerer Felder borgt sich fast alles: Karten und
   .detail-col als Stapler, .field fuer jede Eingabe, .filterform/.filterchips
   fuer die Auswahl (inhaltlich dasselbe Panel wie in der Vertragsliste), die
   Schrittleiste des Import-Assistenten, die Statusfarben der Badges. Neu ist
   nur die Feldzeile "Feld -> Zielwert", fuer die es noch kein Muster gab. */

/* Der Makler-Filter sitzt im Kopf einer Karte und darf dort nicht die volle
   Breite von .field nehmen. */
.hygiene-filterzeile { display: flex; gap: .5rem; align-items: center; margin: 0; }
.hygiene-filterzeile select { min-width: 14rem; }

/* Die Felder eines Stapels stehen untereinander in einer Tabellenzelle: bei
   drei Feldern ist die Liste die Aussage, nicht das erste Feld. Bewusst ohne
   .zelle-lang - deren Ellipse kappte "Wagnis (Betriebsart und WZ-Code)" mitten
   im Feldnamen, und ein halber Feldname sagt nicht, was gesetzt wurde. */
.hygiene-felderzelle { min-width: 13rem; }
.hygiene-feldzeile + .hygiene-feldzeile { margin-top: .35rem; }
.hygiene-feldzeile .cell-sub { white-space: normal; }

/* Eine Aenderung: Feld, Pfeil, Zielwert. Das Raster haelt die Pfeile
   untereinander, auch wenn die Feldnamen verschieden lang sind. */
.hygiene-zeile {
  display: grid; gap: .6rem; align-items: start;
  grid-template-columns: minmax(11rem, 18rem) auto minmax(11rem, 1fr) auto;
}
.hygiene-zeile + .hygiene-zeile { margin-top: .6rem; }
.hygiene-zeile .field { margin-bottom: 0; }
.hygiene-pfeil { color: var(--ink-3); font-size: 1.05rem; line-height: 40px; }
.hygiene-wert { min-width: 0; }
/* Das Bedienelement, das nicht zum Feld passt, ist disabled UND hidden - ohne
   dies bliebe es als Gitterzelle stehen und schoebe den Rest. */
.hygiene-wert [hidden] { display: none; }
.hygiene-zeile [data-hygiene-zeile-weg] { align-self: center; }

.hygiene-aktionen {
  display: flex; flex-wrap: wrap; gap: .6rem;
  align-items: center; margin-top: 1.1rem;
}
.hygiene-aktionen .filterhinweis { margin: 0; }
.hygiene-warnung { margin: 1rem 0 0; }
.hygiene-weiter p { font-size: .85rem; color: var(--ink-2); line-height: 1.55; margin: 0; }

/* Im Probelauf: je Vertrag eine Zeile pro geaendertem Feld. */
.hygiene-aenderung { display: flex; flex-wrap: wrap; align-items: baseline; gap: .4rem; }
.hygiene-aenderung + .hygiene-aenderung { margin-top: .3rem; }
.hygiene-aenderung .cell-sub { min-width: 7rem; }

.hygiene-schritte { margin: 0 0 1.1rem; padding-left: 1.2rem; }
.hygiene-schritte li { font-size: .86rem; color: var(--ink-2); line-height: 1.55; }
.hygiene-schritte li + li { margin-top: .45rem; }
.hygiene-schritte strong { color: var(--ink); }
.hygiene-schritte span { display: block; }

@media (max-width: 760px) {
  .hygiene-zeile { grid-template-columns: 1fr; }
  .hygiene-pfeil { display: none; }
}

/* Der Weg von der Aktionsleiste in die Datenhygiene. Steht neben dem Hinweis,
   nicht darin - vertraege.js ersetzt dessen textContent bei jeder Auswahl. */
.aktionsleiste-hygiene { white-space: nowrap; width: fit-content; justify-self: start; }
