:root {
  --bg: #f5f6fa;
  --text: #1a2233;
  --muted: #6b7385;
  --muted-soft: #b6bbc8;
  --line: #dfe3ec;
  --line-soft: #eaedf4;
  --line-strong: #c7cedb;
  --panel: #ffffff;
  --primary: #2f5fe0;
  --primary-hover: #2450c2;
  --primary-soft: #eef2fe;
  --danger-bg: #fff1f0;
  --danger: #b42318;
  --success-bg: #eefaf1;
  --success: #1f7a3a;
  --warn-bg: #fff7df;
  --warn: #8a5a00;
  --info-bg: #edf5ff;
  --info: #245ea8;

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;

  --shadow-sm: 0 1px 2px rgba(20, 29, 51, 0.05), 0 1px 1px rgba(20, 29, 51, 0.04);
  --shadow-md: 0 4px 12px rgba(20, 29, 51, 0.07), 0 1px 2px rgba(20, 29, 51, 0.05);
  --shadow-lg: 0 12px 28px rgba(20, 29, 51, 0.10), 0 2px 6px rgba(20, 29, 51, 0.06);

  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", Roboto,
    Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html {
  scrollbar-color: #c3cadb transparent;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--primary); }

::selection {
  background: var(--primary-soft);
}

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

.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  justify-content: space-between;
  align-items: center;
  min-height: 64px;
  padding: 12px 24px;
  background: #ffffff;
  border-bottom: 1px solid var(--line-soft);
  box-shadow: var(--shadow-sm);
}

.brand {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  row-gap: 4px;
  font-weight: 600;
  font-size: 17px;
  letter-spacing: -0.003em;
  color: var(--text);
}

.brand::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 20px;
  border-radius: 3px;
  background: var(--primary);
}

.mandant-badge {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  white-space: nowrap;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  color: #ffffff;
}

.mandant-badge-warn {
  background: var(--warn, #b5540c);
}

.mandant-badge-danger {
  background: var(--danger);
}

.subtle,
.muted {
  color: var(--muted);
}

.subtle {
  font-size: 12.5px;
}

nav {
  display: flex;
  gap: 3px;
  flex-wrap: wrap;
}

nav a,
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #ffffff;
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease,
    color .15s ease, box-shadow .15s ease, transform .1s ease;
}

nav a {
  min-height: 26px;
  padding: 4px 10px;
  font-size: 12.5px;
  font-weight: 600;
  border-color: transparent;
  color: var(--muted);
}

nav a:hover {
  background: var(--primary-soft);
  color: var(--primary);
}

nav a.active {
  background: var(--primary);
  color: #ffffff;
  box-shadow: var(--shadow-sm);
}

.nav-group {
  position: relative;
  display: inline-flex;
}

.nav-group-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 26px;
  padding: 4px 10px;
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  cursor: default;
  user-select: none;
  transition: background-color .15s ease, color .15s ease;
}

.nav-caret {
  font-size: 9px;
  opacity: 0.7;
}

.nav-group:hover .nav-group-label,
.nav-group:focus-within .nav-group-label {
  background: var(--primary-soft);
  color: var(--primary);
}

.nav-group.active > .nav-group-label {
  background: var(--primary);
  color: #ffffff;
  box-shadow: var(--shadow-sm);
}

.nav-dropdown {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 150;
  flex-direction: column;
  min-width: 200px;
  margin-top: 4px;
  padding: 6px;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md, 0 4px 16px rgba(0,0,0,.12));
}

.nav-group:hover .nav-dropdown,
.nav-group:focus-within .nav-dropdown {
  display: flex;
}

.nav-dropdown a {
  min-height: 30px;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}

.nav-dropdown a:hover {
  background: var(--primary-soft);
  color: var(--primary);
}

.nav-dropdown a.active {
  background: var(--primary);
  color: #ffffff;
}

.button:hover {
  border-color: #c7cee0;
  box-shadow: var(--shadow-sm);
}

.button:active {
  transform: translateY(1px);
}

.nav-sep {
  flex: 1;
}

.nav-operator {
  font-size: 12px;
  color: var(--color-muted, #888);
  padding: 0 6px;
  align-self: center;
}

.nav-logout {
  border-color: transparent;
  background: transparent;
  color: var(--color-muted, #888);
  font-size: 12px;
}

.nav-logout:hover {
  color: var(--text);
  border-color: var(--line);
  background: #ffffff;
}

/* primary — Hauptaktion (blau gefüllt) */
.button.primary {
  background: var(--primary);
  border-color: var(--primary);
  color: #ffffff;
  box-shadow: 0 1px 2px rgba(47, 95, 224, 0.25);
}
.button.primary:hover {
  background: var(--primary-hover);
  border-color: var(--primary-hover);
  box-shadow: 0 4px 10px rgba(47, 95, 224, 0.3);
}

/* secondary — Abbrechen / Zurück (grau, zurückhaltend) */
.button.secondary {
  background: #f0f0f0;
  border-color: #d0d0d0;
  color: #555555;
}
.button.secondary:hover {
  background: #e4e4e4;
}

/* danger — Destruktive Aktion (rote Umrandung) */
.button.danger {
  border-color: var(--danger);
  color: var(--danger);
}
.button.danger:hover {
  background: var(--danger-bg);
}

.button.small {
  min-height: 28px;
  padding: 4px 8px;
  font-size: 12px;
}

.button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

.page {
  max-width: 1380px;
  margin: 0 auto;
  padding: 24px;
}

.section {
  margin-bottom: 24px;
}

.section.narrow {
  max-width: 900px;
}

h1 {
  margin: 0 0 12px;
  font-size: 25px;
  font-weight: 600;
  letter-spacing: -0.003em;
  display: flex;
  align-items: center;
  gap: 10px;
}

h1::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--primary);
}

h2 {
  margin: 0 0 12px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.002em;
}

.grid {
  display: grid;
  gap: 16px;
}

.grid.two {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.grid.two.compact {
  gap: 10px;
}

.grid.four {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* .grid.three — fixed 3 columns (see media queries below for the 2/1-column reflow at
   narrower widths). Used by the Datenqualitaet dashboard cards (report.html) -- neither
   .grid.two nor .grid.four give a clean 3-column layout.
   Previously auto-fit(minmax(220px,1fr)): on a wide viewport that fit 5 of the 6 fixed
   dashboard cards per row, leaving the 6th stranded alone on its own row with a large
   empty gap next to it -- auto-fit sizes the column COUNT to the container width, which
   is wrong for a fixed-count grid where 3-per-row (2 even rows) is always the intended
   shape, not "as many as fit". */
.grid.three {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.grid .span-all {
  grid-column: 1 / -1;
}

/* Datenqualitaet dashboard (report.html) -- hexagon overview + per-dimension cards. */
.dq-run-select {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
}

.dq-run-select label {
  display: flex;
  align-items: center;
  gap: 8px;
}

.dq-run-label {
  margin: 0 0 16px;
}

.dq-overview {
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.dq-hexagon {
  flex: 0 0 auto;
}

.dq-legend {
  margin: 0;
}

.dq-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.dq-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.dq-card-score {
  font-size: 1.6rem;
  font-weight: 650;
  color: var(--text);
  line-height: 1.1;
}

.dq-gauge,
.dq-sparkline {
  width: 100%;
  display: block;
}

.dq-gauge {
  height: 8px;
}

.dq-sparkline {
  height: 34px;
}

.dq-card-detail {
  margin: 0;
  font-size: 11.5px;
  line-height: 1.4;
}

.stat-card {
  text-align: center;
  padding: 20px 16px;
  transition: box-shadow .15s ease, transform .15s ease;
}

.stat-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}

.stat-card .stat-value {
  font-size: 1.8rem;
  font-weight: 650;
  color: var(--text);
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.stat-card .stat-label {
  font-size: 12px;
  color: var(--muted);
  margin-top: 6px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.stat-card {
  border-left: 3px solid var(--primary);
}

.panel {
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-left: 3px solid #c3cef2;
  border-radius: var(--radius-md);
  padding: 16px;
  box-shadow: var(--shadow-sm);
}

.progress-panel {
  margin-bottom: 16px;
}

.title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.form .actions {
  padding-top: 14px;
  margin-top: 18px;
  border-top: 1px solid var(--line-soft);
}

.actions.compact {
  margin-top: -4px;
  margin-bottom: 14px;
}

.job-action {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 34px;
}

.job-status-pair {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.job-status-icon {
  display: inline-grid;
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  place-items: center;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 800;
  line-height: 1;
}

.job-status-icon.ready {
  color: var(--success);
  background: var(--success-bg);
  box-shadow: inset 0 0 0 1px #8fd19e;
}

.job-status-icon.success {
  color: #ffffff;
  background: var(--success);
}

.job-status-icon.blocked {
  color: var(--warn);
  background: var(--warn-bg);
  box-shadow: inset 0 0 0 1px var(--warn);
}

.job-status-icon.failed {
  color: #ffffff;
  background: var(--danger);
}

.job-status-icon.running {
  color: var(--primary);
  background: var(--info-bg);
  box-shadow: inset 0 0 0 1px var(--primary);
}

.job-status-icon.not-run {
  color: var(--muted);
  background: #f2f4f7;
  box-shadow: inset 0 0 0 1px var(--line);
}

.job-progress {
  margin: 12px 0 14px;
}

.job-progress-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}

.job-progress-track {
  height: 8px;
  overflow: hidden;
  border-radius: 999px;
  background: var(--line);
}

.job-progress-fill {
  width: var(--job-progress);
  height: 100%;
  border-radius: inherit;
  background: var(--success);
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.form-actions form {
  margin: 0;
}

.compact-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
}

.compact-actions form {
  margin: 0;
}

.notice {
  margin-bottom: 16px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}

.notice.success {
  background: var(--success-bg);
  color: var(--success);
}

.notice.danger {
  background: var(--danger-bg);
  color: var(--danger);
}

.notice.info {
  background: var(--info-bg);
  color: var(--info);
}

.notice.warn {
  background: var(--warn-bg);
  color: var(--warn);
  border-color: #e8c56a;
}

/* ── Text-/Erklärblöcke ──────────────────────────────────────────────────
   Persistente, erklärende Inhalte (Hilfetexte, Legenden, "was bedeutet das").
   Unterscheidet sich von .notice (transiente Aktions-Rückmeldung: Flash,
   Fehler) durch getönten Hintergrund + linken Akzentstreifen statt
   Vollton-Rahmen, und durch eigene Überschrift (h3). */
.explain {
  margin-bottom: 16px;
  padding: 14px 16px;
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--info);
  border-radius: var(--radius-md);
  background: var(--info-bg);
  font-size: 13px;
  line-height: 1.65;
}

.explain:last-child {
  margin-bottom: 0;
}

.explain h3 {
  margin: 0 0 0.6rem;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--info);
}

.explain p {
  margin: 0 0 0.5rem;
}

.explain p:last-child {
  margin-bottom: 0;
}

.explain.warn {
  border-left-color: var(--warn);
  background: var(--warn-bg);
}

.explain.warn h3 {
  color: var(--warn);
}

.explain.neutral {
  border-left-color: var(--line);
  background: #fbfcfe;
}

.explain.neutral h3 {
  color: var(--text);
}

/* Rein informeller Beschreibungstext (Seiten-/Sektions-Untertitel) —
   dezenter Info-Marker statt reinem .muted, damit erkennbar ist:
   "das ist Erklärung, keine Warnung/Aktion". Seit 2026-09-03 nur noch der
   Marker ist permanent sichtbar (.info-icon unten) — der eigentliche Text
   erscheint per Mouseover/Fokus, um die Seiten weniger überladen wirken zu
   lassen (Team-Feedback: zu viel Dauertext). .info-text-icon ist der
   schlanke Wrapper, der an der Stelle des frueheren <p class="info-text">
   steht (gleiche Position im Layout, gleicher minimaler Abstand). */
p.info-text-icon {
  margin: 0 0 10px;
}

/* Wiederverwendbarer Mouseover-Info-Marker: ein kleiner "i"-Kreis, der auf
   Hover/Fokus (Tastatur) eine Tooltip-Blase mit dem eigentlichen Erklaertext
   einblendet. Reiner CSS-Mechanismus (kein JS) -- funktioniert ueberall im
   Fliesstext, in Tabellenzellen und in <label>-Feldhinweisen. Der Tooltip-
   Inhalt (.info-icon-tip) darf beliebiges HTML enthalten (Links, <code>,
   <strong>, ...), deshalb kein title-Attribut/content:attr() -- die volle
   Formatierung muss erhalten bleiben. */
.info-icon {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--info-bg);
  color: var(--info);
  font-size: 10.5px;
  font-weight: 700;
  font-style: italic;
  font-family: Georgia, "Times New Roman", serif;
  cursor: help;
  vertical-align: -3px;
  outline: none;
}

.info-icon:focus-visible {
  box-shadow: 0 0 0 2px var(--info-bg), 0 0 0 4px var(--info);
}

.info-icon-tip {
  display: none;
  position: absolute;
  z-index: 60;
  left: 0;
  bottom: calc(100% + 7px);
  width: max-content;
  max-width: 360px;
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: #fff;
  box-shadow: 0 6px 20px rgba(20, 30, 60, 0.16);
  color: var(--text);
  font-size: 12.5px;
  font-weight: 400;
  font-style: normal;
  font-family: inherit;
  line-height: 1.55;
  white-space: normal;
  text-align: left;
  cursor: auto;
}

.info-icon:hover .info-icon-tip,
.info-icon:focus .info-icon-tip,
.info-icon:focus-within .info-icon-tip {
  display: block;
}

/* In einer Tabellenzelle/am rechten Rand kann die Blase sonst abgeschnitten
   werden -- rechtsbuendig statt linksbuendig oeffnen. */
.info-icon.align-right .info-icon-tip {
  left: auto;
  right: 0;
}

.info-icon-tip code {
  font-size: 11.5px;
}

.badge {
  display: inline-flex;
  align-items: center;
  min-height: 22px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
}

a.badge {
  text-decoration: none;
}

.badge.ok {
  background: var(--success-bg);
  color: var(--success);
}

.badge.warn {
  background: var(--warn-bg);
  color: var(--warn);
}

.badge.mapping-open {
  background: var(--info-bg);
  color: var(--info);
}

.badge.implementation-open {
  background: var(--warn-bg);
  color: var(--warn);
}

.badge.documented-open {
  background: #f2f4f7;
  color: var(--muted);
}

.badge.danger {
  background: var(--danger-bg);
  color: var(--danger);
}

.badge.info {
  background: var(--info-bg);
  color: var(--info);
}

.badge.key {
  background: var(--primary);
  color: #ffffff;
}

/* Pipeline: two-row progress display with explicit wrap connector */

.pipeline {
  position: relative;
  margin-top: 20px;
}

.pipeline-row {
  position: relative;
  height: 76px;
  padding-top: 10px;
}

.pipeline-connector-bar {
  display: none;
}

.pipeline-row-track {
  display: none;
}

.pipeline-wrap-connector {
  position: relative;
  height: 34px;
  margin-top: -12px;
  pointer-events: none;
}

.pipeline-wrap-connector span {
  position: absolute;
  background: var(--line);
}

.pipeline-wrap-connector .wrap-right {
  top: -40px;
  right: 0;
  width: 4px;
  height: 57px;
}

.pipeline-wrap-connector .wrap-back {
  top: 17px;
  left: calc(100% / 12);
  right: 0;
  height: 4px;
}

.pipeline-wrap-connector .wrap-left {
  top: 17px;
  left: calc(100% / 12);
  width: 4px;
  height: 41px;
  transform: translateX(-2px);
}

.progress-steps {
  position: relative;
  display: flex;
  flex-wrap: nowrap;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.progress-step {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  color: var(--muted);
}

/* Horizontal line segment running through the full step width */
.progress-step::before {
  content: "";
  position: absolute;
  top: 14px; /* half of 28px marker */
  left: 0;
  right: 0;
  height: 4px;
  background: var(--line);
  z-index: 0;
}

/* First step in any row: line begins at marker center */
.progress-step:first-child::before {
  left: 50%;
}

/* Last step in any row: line ends at marker center */
.progress-step:last-child::before {
  right: 50%;
}

/* Row before a wrap: extend line to the right edge before the return connector. */
.pipeline-row-has-next .progress-step:last-child::before {
  right: 0;
}

/* Row after a wrap starts its own left-to-right track at the first marker. */
.pipeline-row:not(.pipeline-row-has-next) .progress-step:first-child::before {
  left: 50%;
}


.progress-marker {
  position: relative;
  z-index: 1;
  width: 28px;
  height: 28px;
  margin: 0 auto;
  border: 2px solid #ffffff;
  border-radius: 50%;
  background: var(--line);
  box-shadow: 0 0 0 1px var(--line);
}

.progress-step.complete .progress-marker {
  box-shadow: 0 0 0 1px var(--success);
  background: var(--success);
}

.progress-step.complete .progress-marker::after {
  content: "";
  position: absolute;
  left: 8px;
  top: 5px;
  width: 7px;
  height: 11px;
  border: solid #ffffff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.progress-step.current .progress-marker {
  background: #ffffff;
  box-shadow: 0 0 0 2px var(--primary), 0 0 0 6px var(--info-bg);
}

.progress-step.current .progress-marker::after {
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: 50%;
  background: var(--primary);
}

.progress-step.blocked .progress-marker {
  background: var(--warn-bg);
  box-shadow: 0 0 0 2px var(--warn), 0 0 0 6px var(--warn-bg);
}

.progress-step.blocked .progress-marker::after {
  content: "!";
  position: absolute;
  inset: 0;
  color: var(--warn);
  font-weight: 800;
  line-height: 24px;
  text-align: center;
}

.progress-label {
  width: 100%;
  min-width: 0;
  overflow: hidden;
  text-align: center;
}

.progress-label strong {
  display: block;
  color: var(--text);
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.progress-phase-tag {
  display: block;
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  opacity: 0.75;
}

/* .table-wrap — the one container every <table> in the app sits in.
   overflow:auto gives horizontal scroll always, and vertical scroll once
   content exceeds max-height (short tables never hit that height, so they
   render exactly as before — no visual change for small tables). Header +
   filter row stick to the top of that scroll area so long tables stay
   readable while scrolling. */
.table-wrap {
  overflow: auto;
  max-height: 70vh;
  background: #ffffff;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.table-wrap thead tr:first-child th {
  position: sticky;
  top: 0;
  z-index: 3;
  background: #fbfcfe;
  box-shadow: 0 1px 0 var(--line);
}
.table-wrap .col-filter-row td {
  position: sticky;
  top: 39px;
  z-index: 2;
}

tr.col-filter-row td {
  padding: 4px 8px;
  background: #f0f3f8;
  border-bottom: 2px solid var(--line);
}

/* Structural/control BOM fields (semantic_role in PROTECTED_FIELD_SEMANTIC_ROLES,
   see app/queries.py) are framework-injected, never operator-mapped -- muted so
   the real business fields stand out in a field table, without the reduced
   opacity used for genuinely inactive rows (that means "disabled", not "system"). */
tr.field-row-system td {
  color: var(--muted-soft);
}

tr.col-filter-row input[type="search"] {
  width: 100%;
  box-sizing: border-box;
  font-size: 0.78rem;
  padding: 3px 6px;
  min-height: 26px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: #fff;
  font-family: inherit;
}

tr.col-filter-row input[type="search"]:focus {
  outline: 2px solid #3b82f6;
  outline-offset: -1px;
}

table {
  width: 100%;
  border-collapse: collapse;
}

/* BOM Versionen table (bom.html): version.description is free-text of unbounded
   length. Under the default nowrap/auto-layout table, a long description grows
   the Version column until Status/Aktion are pushed out of the table-wrap
   viewport and only reachable via horizontal scroll. Fixed layout with explicit
   column widths keeps the whole table within its container instead, so those
   columns stay visible at all times; the Version column wraps long text rather
   than growing. */
.bom-version-table {
  table-layout: fixed;
}
.bom-version-table .col-version { width: 30%; }
.bom-version-table .col-status { width: 10%; }
.bom-version-table .col-aktiv { width: 8%; }
.bom-version-table .col-objekte { width: 7%; }
.bom-version-table .col-felder { width: 7%; }
.bom-version-table .col-beziehungen { width: 9%; }
.bom-version-table .col-validation { width: 13%; }
.bom-version-table .col-aktion { width: 16%; }

.bom-version-table td:first-child {
  white-space: normal;
  word-break: break-word;
}

.bom-version-table .compact-actions {
  flex-wrap: wrap;
}

/* Custom Transform backlog panels (backlog.html, custom_transforms.html): same
   table reused in both places -- "Custom Transform" carries a free-text
   beschreibung that would otherwise grow wide enough to push the Art badge
   column out of view. */
.custom-transform-backlog-table {
  table-layout: fixed;
}
.custom-transform-backlog-table .col-objekt { width: 18%; }
.custom-transform-backlog-table .col-feld { width: 17%; }
.custom-transform-backlog-table .col-transform { width: 45%; }
.custom-transform-backlog-table .col-art { width: 20%; }
.custom-transform-backlog-table td:nth-child(1),
.custom-transform-backlog-table td:nth-child(2),
.custom-transform-backlog-table td:nth-child(3) {
  white-space: normal;
  word-break: break-word;
}

/* Registrierte API Steps (api_steps.html): Name carries a free-text
   Beschreibung, Input/Erfasste Antwortwerte are joined field lists of
   unbounded length -- any of these can push the Aktionen buttons out of view. */
.api-steps-table {
  table-layout: fixed;
}
.api-steps-table .col-name { width: 20%; }
.api-steps-table .col-objekt { width: 10%; }
.api-steps-table .col-reihenfolge { width: 6%; }
.api-steps-table .col-input { width: 16%; }
.api-steps-table .col-antwortwerte { width: 14%; }
.api-steps-table .col-idempotent { width: 6%; }
.api-steps-table .col-status { width: 12%; }
.api-steps-table .col-aktion { width: 16%; }
.api-steps-table td:nth-child(1),
.api-steps-table td:nth-child(2),
.api-steps-table td:nth-child(4),
.api-steps-table td:nth-child(5) {
  white-space: normal;
  word-break: break-word;
}
.api-steps-table .compact-actions {
  flex-wrap: wrap;
}

/* Registrierte Custom Transforms (custom_transforms.html): same shape as
   .api-steps-table above -- Name/Input/Output are unbounded free text or
   joined field lists that would otherwise push the Aktionen buttons offscreen. */
.custom-transforms-table {
  table-layout: fixed;
}
.custom-transforms-table .col-name { width: 22%; }
.custom-transforms-table .col-art { width: 10%; }
.custom-transforms-table .col-input { width: 16%; }
.custom-transforms-table .col-output { width: 16%; }
.custom-transforms-table .col-erstellt { width: 12%; }
.custom-transforms-table .col-status { width: 12%; }
.custom-transforms-table .col-aktion { width: 12%; }
.custom-transforms-table td:nth-child(1),
.custom-transforms-table td:nth-child(3),
.custom-transforms-table td:nth-child(4) {
  white-space: normal;
  word-break: break-word;
}
.custom-transforms-table .compact-actions {
  flex-wrap: wrap;
}

/* Unregistered Custom Transform files (custom_transforms.html): a repo file
   path of unbounded length would otherwise push the "Registrieren" button
   out of view. */
.unregistered-transforms-table {
  table-layout: fixed;
}
.unregistered-transforms-table .col-datei { width: 70%; }
.unregistered-transforms-table .col-aktion { width: 30%; }
.unregistered-transforms-table td:first-child {
  white-space: normal;
  word-break: break-word;
}

/* Migrationsstatus (infrastructure.html): Migrationsdatei is a repo file path
   of variable length that would otherwise push Status/Angewendet am out of view. */
.migration-status-table {
  table-layout: fixed;
}
.migration-status-table .col-datei { width: 55%; }
.migration-status-table .col-status { width: 25%; }
.migration-status-table .col-angewendet { width: 20%; }
.migration-status-table td:first-child {
  white-space: normal;
  word-break: break-word;
}

/* E2E Lineage Details (field_lineage_e2e.html): the existing colgroup only
   hinted at widths under auto layout, so a long S1/Ziel identifier could
   still grow the table and push the Status badge column out of view. */
.e2e-lineage-table {
  table-layout: fixed;
}
.e2e-lineage-table td:nth-child(3),
.e2e-lineage-table td:nth-child(5) {
  white-space: normal;
  word-break: break-word;
}

/* Portal Kundenliste (portal_admin_customers.html): Anzeigename is a free-text
   customer name that would otherwise push Status/Aktion out of view. */
.portal-customers-table {
  table-layout: fixed;
}
.portal-customers-table .col-username { width: 20%; }
.portal-customers-table .col-anzeigename { width: 35%; }
.portal-customers-table .col-scope { width: 15%; }
.portal-customers-table .col-status { width: 15%; }
.portal-customers-table .col-aktion { width: 15%; }
.portal-customers-table td:nth-child(1),
.portal-customers-table td:nth-child(2) {
  white-space: normal;
  word-break: break-word;
}

/* Portal Anomalie-Regeln (portal_rules.html): Beschreibung/Wert are free-text
   operator input that would otherwise push Erstellt von/Aktiv out of view. */
.portal-rules-table {
  table-layout: fixed;
}
.portal-rules-table .col-objekt { width: 10%; }
.portal-rules-table .col-feld { width: 10%; }
.portal-rules-table .col-bedingung { width: 13%; }
.portal-rules-table .col-wert { width: 13%; }
.portal-rules-table .col-schwere { width: 8%; }
.portal-rules-table .col-beschreibung { width: 26%; }
.portal-rules-table .col-erstellt { width: 10%; }
.portal-rules-table .col-aktion { width: 10%; }
.portal-rules-table td:nth-child(1),
.portal-rules-table td:nth-child(2),
.portal-rules-table td:nth-child(3),
.portal-rules-table td:nth-child(4),
.portal-rules-table td:nth-child(6) {
  white-space: normal;
  word-break: break-word;
}

/* Authority Codes (stages.html): Bezeichnung is a free-text label that would
   otherwise push Status/Aktion out of view. */
.authority-codes-table {
  table-layout: fixed;
}
.authority-codes-table .col-farbe { width: 10%; }
.authority-codes-table .col-code { width: 18%; }
.authority-codes-table .col-bezeichnung { width: 37%; }
.authority-codes-table .col-status { width: 15%; }
.authority-codes-table .col-aktion { width: 20%; }
.authority-codes-table td:nth-child(2),
.authority-codes-table td:nth-child(3) {
  white-space: normal;
  word-break: break-word;
}

/* Offene Staging-Gate-Treffer (staging_exclusions.html): Hinweis is a free-text
   note that would otherwise push the Ausschliessen button out of view. */
.staging-gap-table {
  table-layout: fixed;
}
.staging-gap-table .col-objekt { width: 20%; }
.staging-gap-table .col-spalte { width: 25%; }
.staging-gap-table .col-hinweis { width: 35%; }
.staging-gap-table .col-aktion { width: 20%; }
.staging-gap-table td:nth-child(1),
.staging-gap-table td:nth-child(2),
.staging-gap-table td:nth-child(3) {
  white-space: normal;
  word-break: break-word;
}

/* Aktive Staging-Ausschluesse (staging_exclusions.html): Begruendung is a
   mandatory free-text explanation that would otherwise push Erstellt/Aktion
   out of view. */
.staging-exclusions-table {
  table-layout: fixed;
}
.staging-exclusions-table .col-objekt { width: 15%; }
.staging-exclusions-table .col-spalte { width: 18%; }
.staging-exclusions-table .col-begruendung { width: 35%; }
.staging-exclusions-table .col-erstellt { width: 17%; }
.staging-exclusions-table .col-aktion { width: 15%; }
.staging-exclusions-table td:nth-child(1),
.staging-exclusions-table td:nth-child(2),
.staging-exclusions-table td:nth-child(3) {
  white-space: normal;
  word-break: break-word;
}

/* Target Mapping Bulk-Accept review table (target_bulk_accept.html): Quelle
   holds a <select> whose options carry a full schema.table.column target
   (unbounded), and Ziel is that same identifier as <code> -- either can push
   the UPSERT-Key badge out of view. */
.target-bulk-review-table {
  table-layout: fixed;
}
.target-bulk-review-table .col-select { width: 4%; }
.target-bulk-review-table .col-objekt { width: 12%; }
.target-bulk-review-table .col-feld { width: 12%; }
.target-bulk-review-table .col-quelle { width: 28%; }
.target-bulk-review-table .col-mapping-typ { width: 12%; }
.target-bulk-review-table .col-ziel { width: 22%; }
.target-bulk-review-table .col-upsert { width: 10%; }
.target-bulk-review-table td:nth-child(2),
.target-bulk-review-table td:nth-child(3),
.target-bulk-review-table td:nth-child(4),
.target-bulk-review-table td:nth-child(6) {
  white-space: normal;
  word-break: break-word;
}
.target-bulk-review-table select {
  max-width: 100%;
}

/* Registrierte Target Custom Transforms (target_custom_transforms.html): same
   shape as .custom-transforms-table -- Name/Input/Output are unbounded free
   text or joined field lists that would otherwise push Aktionen offscreen. */
.target-custom-transforms-table {
  table-layout: fixed;
}
.target-custom-transforms-table .col-name { width: 24%; }
.target-custom-transforms-table .col-input { width: 16%; }
.target-custom-transforms-table .col-output { width: 16%; }
.target-custom-transforms-table .col-erstellt { width: 14%; }
.target-custom-transforms-table .col-status { width: 12%; }
.target-custom-transforms-table .col-aktion { width: 18%; }
.target-custom-transforms-table td:nth-child(1),
.target-custom-transforms-table td:nth-child(2),
.target-custom-transforms-table td:nth-child(3) {
  white-space: normal;
  word-break: break-word;
}
.target-custom-transforms-table .compact-actions {
  flex-wrap: wrap;
}

/* Target Preflight (target_preflight.html): Meldung is a free-text gate
   message that would otherwise push the Aktion link out of view. */
.target-preflight-table {
  table-layout: fixed;
}
.target-preflight-table .col-schwere { width: 10%; }
.target-preflight-table .col-issue { width: 15%; }
.target-preflight-table .col-objekt { width: 13%; }
.target-preflight-table .col-feld { width: 13%; }
.target-preflight-table .col-meldung { width: 34%; }
.target-preflight-table .col-aktion { width: 15%; }
.target-preflight-table td:nth-child(2),
.target-preflight-table td:nth-child(3),
.target-preflight-table td:nth-child(4),
.target-preflight-table td:nth-child(5) {
  white-space: normal;
  word-break: break-word;
}

/* BOM-Change aus Run (run_detail.html): Grund is a free-text operator reason
   that would otherwise push Erstellt/Aktion out of view. */
.bom-change-request-table {
  table-layout: fixed;
}
.bom-change-request-table .col-draft { width: 18%; }
.bom-change-request-table .col-status { width: 12%; }
.bom-change-request-table .col-grund { width: 35%; }
.bom-change-request-table .col-erstellt { width: 15%; }
.bom-change-request-table .col-aktion { width: 20%; }
.bom-change-request-table td:nth-child(3) {
  white-space: normal;
  word-break: break-word;
}

/* Blob Hash Reconciliation (run_detail.html): Datei is a source file name of
   variable length that would otherwise push the Status badge out of view
   (Source/Target Hash are already truncated to 16 chars in the template). */
.blob-hash-recon-table {
  table-layout: fixed;
}
.blob-hash-recon-table .col-blobid { width: 12%; }
.blob-hash-recon-table .col-datei { width: 38%; }
.blob-hash-recon-table .col-sourcehash { width: 20%; }
.blob-hash-recon-table .col-targethash { width: 20%; }
.blob-hash-recon-table .col-status { width: 10%; }
.blob-hash-recon-table td:nth-child(2) {
  white-space: normal;
  word-break: break-word;
}

tr[id^="bom-"] {
  scroll-margin-top: 16px;
}

tr[id^="e2e-"] {
  scroll-margin-top: 80px;
}

th,
td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-soft);
  text-align: left;
  vertical-align: top;
  white-space: nowrap;
}

th {
  color: var(--muted);
  background: #fbfcfe;
  font-weight: 600;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

tbody tr {
  transition: background-color .1s ease;
}

tbody tr:hover {
  background: var(--primary-soft);
}

td.right {
  text-align: right;
}

.empty {
  color: var(--muted);
  text-align: center;
}

code {
  font-family: Consolas, monospace;
}

.log-output {
  background: #1a2233;
  color: #e6e9f2;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  padding: 12px;
  font-family: Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  max-height: 65vh;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

.form {
  background: #ffffff;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  padding: 16px;
  box-shadow: var(--shadow-sm);
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 16px;
}

.form-grid .actions {
  grid-column: 1 / -1;
}

label:not(.check):not(.check-row) {
  display: grid;
  gap: 6px;
  margin-bottom: 14px;
  font-weight: 700;
}

input,
select,
textarea {
  width: 100%;
  min-height: 36px;
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font: inherit;
  color: var(--text);
  background: #ffffff;
  transition: border-color .15s ease, box-shadow .15s ease;
}

input:hover,
select:hover,
textarea:hover {
  border-color: #c7cee0;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

textarea {
  resize: vertical;
}

.fieldset {
  margin: 4px 0 14px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}

.fieldset legend {
  padding: 0 6px;
  font-weight: 700;
}

.checkbox-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 14px;
}

.check {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  min-height: 54px;
  margin: 0;
  font-weight: 500;
}

.check input {
  width: auto;
  min-height: auto;
  margin-top: 3px;
}

.checkbox-row-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin: 2px 0 14px;
}

.check-row {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 24px;
  margin: 0;
  font-weight: 700;
  white-space: nowrap;
}

.check-row input {
  appearance: auto;
  width: 16px;
  height: 16px;
  min-height: 16px;
  margin: 0;
  padding: 0;
  flex: 0 0 auto;
}

.inline-form {
  display: grid;
  gap: 8px;
  min-width: 560px;
  max-width: 760px;
}

.inline-form .form-actions {
  margin: 0;
}

.inline-form label:not(.check):not(.check-row) {
  gap: 4px;
  margin-bottom: 0;
  min-width: 0;
  font-size: 12px;
}

.inline-form label span {
  color: var(--muted);
}

.mini-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(120px, 1fr));
  gap: 8px;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.type-mismatch-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.type-mismatch-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
}

.type-mismatch-summary {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  font-size: 13px;
}

.type-mismatch-object {
  font-weight: 600;
}

.type-mismatch-arrow {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: 8px;
}

.type-mismatch-form {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 420px;
  min-width: 320px;
}

.type-mismatch-form input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
}

.mini-grid.two {
  grid-template-columns: repeat(2, minmax(140px, 1fr));
}

.check-title,
.check-help {
  display: block;
}

.check-title {
  font-weight: 700;
}

.check-help {
  margin-top: 2px;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.35;
}

.graph-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  color: var(--muted);
  font-size: 12px;
}

.graph-legend span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.legend-node {
  width: 14px;
  height: 14px;
  border: 1px solid var(--primary);
  border-radius: 4px;
  background: var(--info-bg);
}

.legend-node.ok {
  border-color: var(--success);
  background: var(--success-bg);
}

.legend-node.warn {
  border-color: var(--warn);
  background: var(--warn-bg);
}

.legend-node.mapping-open {
  border-color: var(--info);
  background: var(--info-bg);
}

.legend-node.implementation-open {
  border-color: var(--warn);
  background: var(--warn-bg);
}

.legend-node.documented-open {
  border-color: var(--muted);
  background: #f2f4f7;
}

.legend-node.danger {
  border-color: var(--danger);
  background: var(--danger-bg);
}

.legend-edge {
  width: 20px;
  height: 2px;
  background: var(--muted);
}

.legend-edge.blocking {
  background: var(--primary);
}

.legend-edge.warn-rel {
  background: var(--warn);
}

.graph-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex: 1 1 auto;
}

.graph-zoom-controls {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.graph-zoom-controls .button.small {
  padding: 2px 9px;
  line-height: 1.4;
}

.graph-zoom-level {
  min-width: 3.5em;
  text-align: center;
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.bom-graph-wrap {
  max-height: 70vh;
  overflow: auto;
  border-radius: var(--radius-md);
}

.bom-graph {
  position: relative;
  min-height: 360px;
  overflow: auto;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  background: #fbfcfe;
  box-shadow: var(--shadow-sm);
}

.bom-graph-svg {
  display: block;
  min-width: 900px;
  width: 100%;
  height: 420px;
}

.bom-graph-empty {
  padding: 24px;
}

.bom-graph.thumbnail {
  min-height: 150px;
}

.bom-graph.thumbnail .bom-graph-svg {
  min-width: 0;
}

.bom-graph.thumbnail .graph-node .graph-node-title {
  font-size: 11px;
}

.bom-graph.thumbnail .graph-edge text {
  font-size: 9px;
}

.lineage-graph {
  position: relative;
  min-height: 360px;
  overflow: auto;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  background: #fbfcfe;
  box-shadow: var(--shadow-sm);
}

.lineage-graph-svg {
  display: block;
  min-width: 980px;
  width: 100%;
  height: 420px;
}

.lineage-graph-empty {
  padding: 24px;
}

.graph-arrow {
  fill: var(--muted);
}

.graph-edge {
  cursor: pointer;
}

.graph-edge path {
  fill: none;
  stroke: var(--muted);
  stroke-width: 1.8;
}

.graph-edge.blocking path {
  stroke: var(--primary);
  stroke-width: 2.3;
}

.graph-edge.warn-rel path {
  stroke: var(--warn);
  stroke-width: 2;
}

.graph-edge text {
  fill: var(--muted);
  font-size: 11px;
  text-anchor: middle;
  paint-order: stroke;
  stroke: #fbfcfe;
  stroke-width: 5px;
  stroke-linejoin: round;
}

.graph-edge:hover path,
.graph-edge:focus path {
  stroke: var(--warn);
}

.graph-node {
  cursor: pointer;
}

.graph-node rect {
  fill: #ffffff;
  stroke: var(--primary);
  stroke-width: 1.5;
}

.graph-node text {
  fill: var(--muted);
  font-size: 12px;
}

.graph-node .graph-node-title {
  fill: var(--text);
  font-size: 13px;
  font-weight: 700;
}

.graph-node:hover rect,
.graph-node:focus rect {
  fill: var(--info-bg);
  stroke: var(--warn);
}

.lineage-column-label {
  fill: var(--muted);
  font-size: 12px;
  font-weight: 700;
  text-anchor: middle;
}

.lineage-edge {
  fill: none;
  stroke: var(--muted);
  stroke-width: 1.8;
}

.lineage-edge.ok {
  stroke: var(--success);
}

.lineage-edge.warn {
  stroke: var(--warn);
}

.lineage-edge.mapping-open {
  stroke: var(--info);
}

.lineage-edge.implementation-open {
  stroke: var(--warn);
}

.lineage-edge.documented-open {
  stroke: var(--muted);
}

.lineage-edge.danger {
  stroke: var(--danger);
}

.lineage-node {
  cursor: pointer;
}

.lineage-node rect {
  fill: #ffffff;
  stroke: var(--line);
  stroke-width: 1.4;
}

.lineage-node.ok rect {
  stroke: var(--success);
}

.lineage-node.warn rect {
  stroke: var(--warn);
  fill: var(--warn-bg);
}

.lineage-node.mapping-open rect {
  stroke: var(--info);
  fill: var(--info-bg);
}

.lineage-node.implementation-open rect {
  stroke: var(--warn);
  fill: var(--warn-bg);
}

.lineage-node.documented-open rect {
  stroke: var(--muted);
  fill: #f2f4f7;
}

.lineage-node.danger rect {
  stroke: var(--danger);
  fill: var(--danger-bg);
}

.lineage-node text {
  fill: var(--muted);
  font-size: 12px;
}

.lineage-node .lineage-node-kind {
  fill: var(--text);
  font-weight: 700;
}

.lineage-node:hover rect,
.lineage-node:focus rect {
  stroke: var(--primary);
  stroke-width: 2;
}

.row-highlight {
  animation: row-highlight 1.5s ease-out;
}
.row-danger td { background: var(--danger-bg); }
.row-warn td   { background: var(--warn-bg); }

@keyframes row-highlight {
  0% { background: var(--warn-bg); }
  100% { background: transparent; }
}

/* Mapping form — two-panel source / target layout */
.mapping-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 16px;
}

.mapping-col-header {
  padding: 10px 14px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: var(--info-bg);
  color: var(--info);
  border-bottom: 2px solid #c3d9f5;
  border-right: 1px solid var(--line);
}

.mapping-col-header.target {
  background: #f0f2f5;
  color: var(--muted);
  border-bottom: 2px solid var(--line);
  border-right: none;
}

.mapping-cell {
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
}

.mapping-split > *:nth-last-child(1),
.mapping-split > *:nth-last-child(2) {
  border-bottom: none;
}

.mapping-cell:nth-child(odd) {
  background: #f4f8ff;
  border-right: 1px solid var(--line);
}

.mapping-cell:nth-child(even) {
  background: #ffffff;
}

.mapping-cell label:not(.check):not(.check-row):last-child {
  margin-bottom: 0;
}

.bom-readonly {
  width: 100%;
  min-height: 36px;
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #f6f7f9;
  color: var(--text);
  font: inherit;
  cursor: default;
  display: flex;
  align-items: center;
  gap: 6px;
}

.bom-readonly.mono {
  font-family: Consolas, monospace;
  font-size: 13px;
}

.mapping-typ-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 16px;
}

.mapping-typ-row label:not(.check):not(.check-row) {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 0;
  white-space: nowrap;
}

.mapping-typ-row select {
  width: auto;
  min-width: 200px;
  max-width: 320px;
  text-overflow: ellipsis;
  overflow: hidden;
}

/* ── Utility classes used across portal and admin views ───────────────── */

.mono { font-family: Consolas, "Courier New", monospace; font-size: 13px; }
.hint { font-size: 12px; color: var(--muted); margin-top: 3px; font-weight: 400; }

/* .card — styled box (alias for .panel with bottom margin) */
.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 20px 24px;
  margin-bottom: 1.5rem;
}

/* .btn — alias for .button; .btn-sm = .button.small; .btn-danger = .button.danger */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 7px 14px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #ffffff;
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  white-space: nowrap;
}
.btn:hover { background: #f6f7f9; }
.btn.primary { background: var(--primary); border-color: var(--primary); color: #ffffff; }
.btn.primary:hover { background: var(--primary-hover); }
.btn-sm { min-height: 28px; padding: 4px 10px; font-size: 12px; }
.btn-danger { border-color: var(--danger); color: var(--danger); }
.btn-danger:hover { background: var(--danger-bg); }

/* .form-row — labelled form field */
.form-row {
  display: grid;
  gap: 5px;
  margin-bottom: 14px;
  font-weight: 700;
  font-size: 13px;
}
.form-row input,
.form-row select,
.form-row textarea { margin: 0; }

/* .kv-grid — two-column key/value display, used inside an already-boxed .panel */
.kv-grid { display: grid; grid-template-columns: 160px 1fr; gap: 8px 12px; align-items: baseline; }
.kv-label { color: var(--muted); font-size: 13px; }
.kv-value { font-weight: 600; }

/* .context-bar — boxed run/stage/BOM identity strip for page headers.
   Etikett-style chips inside one bordered box (same visual weight as
   .panel.stat-card on report.html), instead of bare kv-grid text floating
   in the header with no container. */
.context-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 10px 0 4px;
  padding: 10px 14px;
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

.context-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  font-size: 12.5px;
  color: var(--text);
  white-space: nowrap;
}

/* Field chip input (API Steps Input-Felder) — chip tags + free-text entry in one box */

.chip-input {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  background: var(--panel);
}

.chip-input input[type="text"] {
  flex: 1 1 120px;
  min-width: 120px;
  border: none;
  outline: none;
  padding: 2px 4px;
  background: transparent;
  font-size: 13px;
}

.field-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 4px 3px 10px;
  background: var(--info-bg);
  color: var(--info);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.field-chip button {
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0 4px;
  border-radius: 999px;
  opacity: 0.65;
}

.field-chip button:hover {
  opacity: 1;
  background: rgba(0, 0, 0, 0.08);
}

.context-chip .context-chip-label {
  color: var(--muted);
  font-weight: 700;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Portal data table — anomaly row highlight */
tr.has-anomaly td { background: #fffbf0; }
.anomaly-item {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12px;
  margin-bottom: 3px;
  white-space: normal;
}
.anomaly-item:last-child { margin-bottom: 0; }

/* Login page centering (shared by operator and portal) */
.login-centered {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: var(--bg);
}
.login-box {
  width: 100%;
  max-width: 400px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 2.5rem 2rem;
}
.login-box .login-product { font-size: 0.8rem; color: var(--muted); margin-bottom: 1.5rem; }
.login-box h1 { font-size: 1.25rem; margin: 0 0 1.5rem; }

@media (max-width: 1100px) {
  .grid.three {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 800px) {
  .topbar,
  .title-row {
    align-items: flex-start;
    flex-direction: column;
  }

  nav,
  .grid.two,
  .grid.three,
  .checkbox-grid {
    width: 100%;
    grid-template-columns: 1fr;
  }

  nav {
    flex-wrap: wrap;
  }

  .progress-steps {
    flex-wrap: wrap;
    gap: 0;
  }
}

@media (max-width: 560px) {
  .mapping-split {
    grid-template-columns: 1fr;
  }
  .mapping-col-header,
  .mapping-cell:nth-child(odd) {
    border-right: none;
  }
}
