/* =========================================================================
   In2Logic — Extraction Workbench (look-and-feel mock)
   Light technical theme · engineering / CAD / PDM aesthetic
   ========================================================================= */

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');

/* ---- Design tokens ---------------------------------------------------- */
:root {
  --bg:           #EEF1F4;
  --surface:      #FFFFFF;
  --surface-2:    #F7F9FB;
  --surface-3:    #EFF3F6;
  --border:       #DCE2E8;
  --border-strong:#C4CDD6;

  --ink:          #16202B;
  --ink-2:        #4A5A6A;
  --ink-3:        #7B8A98;

  --accent:       #0B7FC7;
  --accent-ink:   #0A6AA6;
  --accent-bg:    #E7F2FB;

  --ok:   #1E9E68; --ok-bg:   #E4F4EC;
  --warn: #C9810A; --warn-bg: #FBF0DB;
  --bad:  #CC3D3D; --bad-bg:  #FBE7E7;
  --neutral:#7B8A98; --neutral-bg:#EAEEF2;
  /* One colour for everything AI — badges, pulses, and AI action buttons. Indigo, not
     blue: clearly distinct from --accent (a teal-blue) at a glance, and it was already
     the app's own latent "secondary" colour (dozens of var(--accent,#6366f1)
     fallbacks throughout the codebase never resolve because --accent is set — this
     makes that dormant identity the real, visible AI colour instead of dead CSS).
     --ai-light is the SAME hue lightened for readability on dark surfaces (hero,
     dark modals) — never a different hue, so light-context and dark-context AI
     markers still read as "the same colour", just adapted for contrast. */
  --ai: #6366F1; --ai-ink: #4F46E5; --ai-bg: rgba(99,102,241,.12); --ai-border: rgba(99,102,241,.4); --ai-light: #A5B4FC;

  --mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
  --sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --r:    6px;
  --r-sm: 4px;
  --shadow:    0 1px 2px rgba(16,32,43,.05), 0 1px 1px rgba(16,32,43,.03);
  --shadow-md: 0 4px 14px rgba(16,32,43,.08);

  --rail-w: 76px;
  --topbar-h: 56px;

  --grid: linear-gradient(rgba(11,127,199,.055) 1px, transparent 1px),
          linear-gradient(90deg, rgba(11,127,199,.055) 1px, transparent 1px);
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
/* Global link hover fallback — deliberately a bare element selector (not
   a:not(.btn)) so its low specificity always loses to any classed hover rule
   (.btn:hover, .rail__item:hover, etc: class beats element regardless of order).
   Anything more specific overrides this safely; anything untouched still gets a
   real, visible hover instead of "nothing happens". */
a { color: var(--accent); text-decoration: none; border-radius: 4px; transition: background-color .12s ease, color .12s ease; }
a:hover { color: var(--accent-ink); background: var(--accent-bg); }
/* Links on the dark Quality hero keep their own (light) ink — the global light hover
   background would hide that near-white text. Use a translucent-white hover instead. */
.q-hero-link:hover { background: rgba(255,255,255,.14); text-decoration: underline; }
.mono { font-family: var(--mono); font-feature-settings: "tnum" 1; }

/* ---- App shell -------------------------------------------------------- */
.app { display: grid; grid-template-columns: var(--rail-w) 1fr; grid-template-rows: 100vh; height: 100vh; overflow: hidden; }

/* Left icon rail */
.rail {
  background: #122231;
  display: flex; flex-direction: column; align-items: stretch;
  padding: 10px 0; gap: 2px;
}
.rail__logo {
  display: grid; place-items: center;
  height: 46px; margin-bottom: 10px; color: #fff;
}
.rail__logo svg { width: 26px; height: 26px; }
.rail__item {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 4px; margin: 0 8px; border-radius: var(--r-sm);
  color: #9FB2C2; font-size: 10.5px; font-weight: 500; letter-spacing: .01em;
  position: relative; cursor: pointer; transition: background .12s, color .12s;
}
.rail__item svg { width: 20px; height: 20px; stroke-width: 1.7; }
.rail__item:hover { background: rgba(255,255,255,.06); color: #D6E2EC; }
.rail__item.is-active { color: #fff; background: rgba(11,127,199,.22); }
.rail__item.is-active::before {
  content: ""; position: absolute; left: -8px; top: 8px; bottom: 8px;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--accent);
}
.rail__spacer { flex: 1; }

/* Main column */
.main { display: flex; flex-direction: column; min-width: 0; min-height: 0; }

/* Top bar */
.topbar {
  height: var(--topbar-h); flex: none;
  background: var(--surface); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 18px; padding: 0 18px;
}
.project {
  display: flex; align-items: center; gap: 9px; padding: 6px 12px;
  border: 1px solid var(--border); border-radius: var(--r); cursor: default;
  background: var(--surface-2);
}
.project__mark {
  width: 24px; height: 24px; border-radius: var(--r-sm);
  background: var(--accent); color: #fff; display: grid; place-items: center;
  font-weight: 700; font-size: 12px;
}
.project__name { font-weight: 600; font-size: 13px; }
.project__sub  { font-size: 11px; color: var(--ink-3); }
/* The pill is a plain workspace label now — hide the dropdown chevron (the only
   svg in .project; the "IN" mark is a text div). */
.project svg { display: none; }

.search {
  flex: 1; max-width: 560px; display: flex; align-items: center; gap: 8px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r); padding: 7px 12px; position: relative;
}
/* Global search live-results dropdown */
.gsearch-menu {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 60;
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 10px 30px rgba(15,30,55,.16); max-height: 380px; overflow-y: auto; padding: 4px;
}
.gsearch-item { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 6px; text-decoration: none; color: var(--ink); }
.gsearch-item:hover, .gsearch-item.is-active { background: var(--surface-2); }
.gsearch-kind { font-family: var(--mono); font-size: 9.5px; font-weight: 700; letter-spacing: .05em;
  color: var(--ink-3); border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; }
.gsearch-kind.is-asm { color: var(--accent); border-color: var(--accent); }
.gsearch-nm { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gsearch-pn { font-family: var(--mono); font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.gsearch-empty { padding: 12px; font-size: 12.5px; color: var(--ink-3); text-align: center; }
.search:focus-within { border-color: var(--accent); background: #fff; box-shadow: 0 0 0 3px var(--accent-bg); }
.search svg { width: 16px; height: 16px; color: var(--ink-3); flex: none; }
.search input { border: 0; outline: 0; background: transparent; flex: 1; font: inherit; color: var(--ink); }
.search kbd {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; background: #fff;
}
.topbar__right { margin-left: auto; display: flex; align-items: center; gap: 14px; }
.iconbtn {
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: var(--r); background: var(--surface);
  color: var(--ink-2); cursor: pointer; position: relative;
}
.iconbtn:hover { border-color: var(--border-strong); color: var(--ink); }
.iconbtn svg { width: 17px; height: 17px; }
.iconbtn .dot { position: absolute; top: 6px; right: 7px; width: 7px; height: 7px; border-radius: 50%; background: var(--bad); border: 1.5px solid #fff; }
.avatar { width: 34px; height: 34px; border-radius: 50%; background: linear-gradient(135deg,#0B7FC7,#15A3D6); color:#fff; display:grid; place-items:center; font-weight:600; font-size:13px; }

/* Content area */
.content { flex: 1; min-height: 0; overflow: auto; }
.page { padding: 22px 26px 40px; }
.page--flush { padding: 0; max-width: none; height: 100%; }

/* ---- Generic bits ----------------------------------------------------- */
.page-head { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 20px; }
.page-head__titles { flex: 1; min-width: 0; }
.page-title { font-size: 19px; font-weight: 700; letter-spacing: -.01em; margin: 0; }
.page-sub { color: var(--ink-3); font-size: 13px; margin: 3px 0 0; }
.breadcrumb { font-size: 12px; color: var(--ink-3); margin-bottom: 6px; display: flex; gap: 6px; align-items: center; }
.breadcrumb svg { width: 13px; height: 13px; }

/* ══ Button system — one rule per category, used everywhere, no exceptions. ══
   Every clickable action in the app is one of these. If a new action doesn't fit
   a category below, it's a sign the action itself needs reconsidering, not a
   reason to invent a one-off style.

   .btn                (base)     — shape shared by every button below.
   .btn--secondary      white/bordered — Cancel, Refresh, Close: neutral, no verdict implied.
   .btn--primary        solid blue     — the ONE main forward action in a dialog (Save, Import, Download).
   .btn--ai             solid AI blue  — triggers an AI call (Classify/Generate/Run/Use AI suggestions).
                                         Always paired with the sparkle icon. This blue (--ai) is reserved
                                         for AI — distinct from --accent — so it always means "AI".
   .btn--approve        solid green    — accepts/confirms a proposal (Approve, Confirm, Trust value).
   .btn--reject         amber outline  — overrides/reassigns without deleting anything (Override, Reassign).
   .btn--danger         red outline    — deletes or permanently discards (Delete, Ignore, Remove).
   .link                text, no box  — pure navigation to another view (Reuse graph, Open part,
                                         Show in tree, View all). Never a bordered box that only
                                         LOOKS like a button on hover — if it navigates, it reads as
                                         a link at rest, not after the fact.
   Icon-only actions use .icon-btn (defined separately) — never .btn--ghost, which is retired. ══ */
.btn {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--ink); font: inherit; font-weight: 500; font-size: 13px;
  padding: 8px 13px; border-radius: var(--r); transition: .12s;
}
.btn:hover { border-color: var(--ink-3); }
.btn svg { width: 20px; height: 20px; flex-shrink: 0; }
.btn--secondary { background: var(--surface); border-color: var(--border-strong); color: var(--ink); }
.btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn--primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); color: #fff; }
.btn--ai { background: var(--ai); border-color: var(--ai); color: #fff; }
.btn--ai:hover { background: var(--ai-ink); border-color: var(--ai-ink); color: #fff; }
.btn--approve { background: var(--ok); border-color: var(--ok); color: #fff; }
.btn--approve:hover { background: #178055; border-color: #178055; color: #fff; }
.btn--reject { background: var(--warn-bg); border-color: var(--warn); color: var(--warn); }
.btn--reject:hover { background: var(--warn); color: #fff; }
.btn--danger { background: transparent; border-color: var(--bad); color: var(--bad); }
.btn--danger:hover { background: var(--bad); color: #fff; }
/* Deprecated — do not use in new code. Kept only so any straggling reference still
   renders instead of breaking; every real usage has been converted to .btn--secondary,
   .btn--ai, or .link depending on what the button actually does (see rule above). */
.btn--ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn--ghost:hover { background: var(--surface-3); }
.btn--sm { padding: 5px 9px; font-size: 12px; }
.btn:disabled, .btn[disabled] { opacity: .38; cursor: not-allowed; pointer-events: none; }

/* Dark-hero neutral chip — navigation/info/cancel on a dark hero background (e.g.
   Model's hero, Quality's "not configured" gate panel), never an AI action or an
   approve/primary action. Those use .btn--ai / .btn--approve, which read the same on
   light and dark backgrounds because they're solid colour, not translucent-on-navy. */
.btn--hero-secondary {
  background: rgba(255,255,255,.1);
  border: 1px solid rgba(255,255,255,.2);
  color: rgba(255,255,255,.85);
  font-size: 13px;
  line-height: 1.45;
  padding: 8px 13px;
  border-radius: var(--r);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
  text-decoration: none;
}
.btn--hero-secondary:hover { background: rgba(255,255,255,.18); }

/* Pure navigation — text at rest, everywhere. One hover treatment for every link
   in the app: a soft background chip fades in and the text darkens slightly — no
   underline anywhere (deliberately dropped; a growing/appearing underline still
   reads as "old web", the chip reads as an actual interactive surface). The
   negative margin cancels the added padding so the chip doesn't shift surrounding
   layout. Applies to .link (explicit navigation), .rowlink/.q-issue-fix/.q-gt-row
   (table + list row links), and any bare <a> the global fallback below catches. */
.link, .rowlink, .q-issue-fix {
  transition: background-color .12s ease, color .12s ease;
  border-radius: 5px;
}
.link:hover, .rowlink:hover, .q-issue-fix:hover {
  background: var(--accent-bg);
  color: var(--accent-ink);
}
.link { color: var(--accent); text-decoration: none; font-size: 13px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; padding: 1px 5px; margin: -1px -5px; }
.link--sm { font-size: 12px; }

.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r); box-shadow: var(--shadow);
}
/* Opt-in height cap: standalone page sections that can get very tall add
   .card--capped so their body scrolls with the header pinned. NOT applied to
   cards inside an already-scrolling panel (e.g. the detail panel) — that would
   create a second scrollbar. */
.card--capped { max-height: 560px; overflow: auto; }
.card--capped .card__head { position: sticky; top: 0; z-index: 3; background: var(--surface); }
.card__head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; border-bottom: 1px solid var(--border);
}
.card__title { font-size: 13px; font-weight: 600; }
.card__title .count { color: var(--ink-3); font-weight: 500; }
.card__body { padding: 16px; }
.card__head .right { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* Status chips */
.chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 500;
  padding: 3px 9px 3px 7px; border-radius: 100px; border: 1px solid transparent; white-space: nowrap;
}
.chip .dot { width: 7px; height: 7px; border-radius: 50%; }
.chip--ok   { background: var(--ok-bg);   color: #157A4F; } .chip--ok .dot{ background: var(--ok); }
.chip--warn { background: var(--warn-bg); color: #9C6406; } .chip--warn .dot{ background: var(--warn); }
.chip--bad  { background: var(--bad-bg);  color: #A92F2F; } .chip--bad .dot{ background: var(--bad); }
.chip--neutral { background: var(--neutral-bg); color: #5A6B7B; } .chip--neutral .dot{ background: var(--neutral); }
.chip--accent { background: var(--accent-bg); color: var(--accent-ink); } .chip--accent .dot{ background: var(--accent); }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.35} }
.chip--warn .dot.spin { animation: pulse 1.1s ease-in-out infinite; }

.tag { font-family: var(--mono); font-size: 11px; padding: 2px 6px; border-radius: var(--r-sm);
       background: var(--surface-3); color: var(--ink-2); border: 1px solid var(--border); }

/* Blueprint grid surface */
.blueprint { background-color: #FBFDFE; background-image: var(--grid); background-size: 22px 22px; }

/* ---- Dashboard -------------------------------------------------------- */
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 20px; }
.stat {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  padding: 15px 16px; box-shadow: var(--shadow); position: relative; overflow: hidden;
  /* Flex column so the last line (delta) can pin to the bottom — with equal-height
     tiles that gives every tile the same bottom padding, whatever its content height. */
  display: flex; flex-direction: column;
}
.stat__label { font-size: 12px; color: var(--ink-3); display: flex; align-items: center; gap: 7px; }
.stat__label svg { width: 15px; height: 15px; color: var(--accent); }
.stat__value { font-family: var(--mono); font-size: 28px; font-weight: 600; margin-top: 8px; letter-spacing: -.01em; }
.stat__value small { font-size: 14px; color: var(--ink-3); font-weight: 500; }
.stat__delta { font-size: 11.5px; margin-top: auto; padding-top: 4px; color: var(--ok); }
.stat__delta.flat { color: var(--ink-3); }
.stat__bar { height: 5px; border-radius: 3px; background: var(--surface-3); margin-top: 12px; overflow: hidden; }
.stat__bar > i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }

/* Equal-height cards per row so a short card (e.g. Make-vs-buy) matches its
   taller neighbour and the row gaps stay uniform instead of leaving a big
   trailing gap under the shorter one. */
.cols-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: stretch; }

.file-row {
  display: grid; grid-template-columns: 26px 1fr minmax(72px,auto) auto; align-items: center; gap: 10px;
  padding: 11px 16px; border-bottom: 1px solid var(--border);
}
/* Overview "Recent sources" variant — icon · name · arrow (no progress/status
   column); the arrow sits in the last column, flush right. */
.file-row--simple { grid-template-columns: 26px 1fr auto; }
.file-row:last-child { border-bottom: 0; }
.file-row:hover { background: var(--surface-2); }
.file-ic { width: 26px; height: 26px; border-radius: var(--r-sm); background: var(--accent-bg); color: var(--accent); display: grid; place-items: center; }
.file-ic svg { width: 15px; height: 15px; }
.file-name { font-weight: 500; font-size: 13px; }
.file-meta { font-size: 11.5px; color: var(--ink-3); font-family: var(--mono); }
.mini-prog { width: 90px; height: 5px; border-radius: 3px; background: var(--surface-3); overflow: hidden; }
.mini-prog > i { display: block; height: 100%; background: var(--warn); }

/* Ingest queue icon action button */
.iq-icon-btn { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--r-sm); border: 1px solid var(--border); background: transparent; color: var(--ink-3); cursor: pointer; text-decoration: none; transition: border-color .1s, color .1s, background .1s; }
.iq-icon-btn svg { width: 14px; height: 14px; flex-shrink: 0; }
.iq-icon-btn:hover { border-color: var(--accent); color: var(--accent); background: rgba(11,127,199,.06); }
.iq-icon-btn--warn { border-color: rgba(201,129,10,.35); color: var(--warn, #C9810A); }
.iq-icon-btn--warn:hover { border-color: var(--warn, #C9810A); background: var(--warn-bg, rgba(201,129,10,.07)); }

.attn-item { display: flex; gap: 11px; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.attn-item:last-child { border: 0; }
.attn-ic { width: 28px; height: 28px; border-radius: var(--r-sm); display: grid; place-items: center; flex: none; }
.attn-ic svg { width: 16px; height: 16px; }
.attn-ic--warn { background: var(--warn-bg); color: var(--warn); }
.attn-ic--bad  { background: var(--bad-bg);  color: var(--bad); }
.attn-body { font-size: 13px; }
.attn-body .sub { font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }

.coverage-row { display: flex; align-items: center; gap: 12px; padding: 9px 0; }
.coverage-row .lbl { width: 92px; font-size: 12.5px; font-family: var(--mono); color: var(--ink-2); }
.coverage-row .track { flex: 1; height: 8px; border-radius: 4px; background: var(--surface-3); overflow: hidden; }
.coverage-row .track > i { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.coverage-row .pct { width: 40px; text-align: right; font-family: var(--mono); font-size: 12.5px; color: var(--ink-2); }

/* Overview's make-vs-buy tile — a summary, not the ranked list (that lives on the
   Quality page's reuse graph, #bubble-chart). */
.mvb-summary { padding: 14px 16px; }
.mvb-summary-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 12px; }
.mvb-summary-stat { display: flex; flex-direction: column; gap: 2px; }
.mvb-summary-val { font-size: 22px; font-weight: 800; line-height: 1; letter-spacing: -.01em; }
.mvb-summary-lbl { font-size: 11px; color: var(--ink-3); }
.mvb-summary-foot { font-size: 12px; color: var(--ink-2); }
.mvb-summary-foot a { color: var(--accent); font-weight: 600; }

/* ---- Ingest ----------------------------------------------------------- */
.dropzone {
  border: 2px dashed var(--border-strong); border-radius: var(--r);
  padding: 44px 24px; text-align: center; cursor: pointer; transition: .15s;
}
.dropzone:hover { border-color: var(--accent); }
.dropzone__ic { width: 56px; height: 56px; border-radius: 50%; background: var(--accent-bg); color: var(--accent); display: grid; place-items: center; margin: 0 auto 14px; }
.dropzone__ic svg { width: 26px; height: 26px; }
.dropzone h3 { margin: 0 0 5px; font-size: 16px; }
.dropzone p { margin: 0; color: var(--ink-3); font-size: 13px; }
.formats { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }

/* ---- Tables ----------------------------------------------------------- */
.toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.toolbar .sep { width: 1px; height: 22px; background: var(--border); }
.filterbar { display: flex; gap: 6px; }
.filter {
  font-size: 12.5px; padding: 6px 11px; border-radius: 100px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--ink-2);
}
.filter:hover { border-color: var(--border-strong); }
.filter.is-active { background: var(--ink); color: #fff; border-color: var(--ink); }

/* Card clips at the viewport edge on narrow windows unless the table itself scrolls
   horizontally — without this wrapper, wide rows spilled outside the (shorter) card
   background instead of being contained. */
.table-scroll { overflow-x: auto; }
table.data { width: 100%; min-width: 760px; border-collapse: collapse; font-size: 13px; }
table.data th, table.data td { text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--border); }
table.data thead th {
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3);
  font-weight: 600; background: var(--surface); position: sticky; top: 0; user-select: none;
}
table.data thead th.sortable { cursor: pointer; }
table.data thead th.sortable:hover { color: var(--ink); }
table.data thead th .arrow { opacity: .35; font-size: 10px; }
table.data thead th.sorted .arrow { opacity: 1; color: var(--accent); }
table.data tbody tr:hover { background: var(--surface-2); }
table.data td.num { font-family: var(--mono); }
.colcheck { width: 38px; text-align: center !important; }
.rowlink { font-weight: 500; color: var(--ink); }
.rowlink:hover { color: var(--accent); }
input[type=checkbox].ck { width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; }
.table-foot { display: flex; align-items: center; justify-content: space-between; padding: 11px 16px; font-size: 12.5px; color: var(--ink-3); }

/* ---- Workbench (3-pane) ----------------------------------------------- */
.wb { --tree-w: 25%; display: grid; grid-template-columns: var(--tree-w) 5px 1fr 40%; grid-template-rows: 1fr; height: 100%; min-height: 0; }
.wb__pane { display: flex; flex-direction: column; min-height: 0; background: var(--surface); }
.wb__pane + .wb__pane { border-left: 1px solid var(--border); }
.wb__resize {
  display: flex; align-items: center; justify-content: center;
  cursor: col-resize; background: var(--border); transition: background .15s; z-index: 1;
  width: 5px; min-width: 5px;
}
.wb__resize::after {
  content: ''; display: block; width: 1px; height: 32px;
  background: var(--ink-3); border-radius: 1px; opacity: .4;
}
.wb__resize:hover, .wb__resize.is-dragging { background: var(--accent); }
.wb__resize:hover::after, .wb__resize.is-dragging::after { opacity: 1; background: white; }
.wb__head {
  height: 42px; flex: none; display: flex; align-items: center; gap: 8px; padding: 0 14px;
  border-bottom: 1px solid var(--border); font-size: 12px; font-weight: 600; color: var(--ink-2);
  text-transform: uppercase; letter-spacing: .04em; background: var(--surface-2);
}
.wb__head .right { margin-left: auto; display: flex; gap: 4px; }
.wb__scroll { flex: 1; overflow: auto; }

/* Tree */
.tree { padding: 6px 0; font-size: 13px; }
.tree__node { display: flex; align-items: center; gap: 7px; padding: 5px 12px; cursor: pointer; border-radius: 0; }
.tree__node:hover { background: var(--surface-2); }
.tree__node.is-sel { background: var(--accent-bg); color: var(--accent-ink); font-weight: 500; }
.tree__node.is-sel::before { content:""; position:absolute; }
.tree__node .caret { width: 14px; color: var(--ink-3); display: grid; place-items: center; }
.tree__node .caret svg { width: 12px; height: 12px; transition: transform .12s; }
.tree__node.collapsed .caret svg { transform: rotate(-90deg); }
.tree__node .pic { width: 16px; height: 16px; color: var(--ink-3); }
.tree__node.is-sel .pic { color: var(--accent); }
.tree__node .lbl { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tree__node .pn { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.tree .lvl1 { padding-left: 12px; }
.tree .lvl2 { padding-left: 30px; }
.tree .lvl3 { padding-left: 48px; }

/* CAD viewport */
.viewport { flex: 1; position: relative; display: grid; place-items: center; overflow: hidden; }
.viewport__toolbar {
  position: absolute; top: 12px; left: 12px; display: flex; gap: 4px;
  background: rgba(255,255,255,.92); border: 1px solid var(--border); border-radius: var(--r);
  padding: 4px; box-shadow: var(--shadow); backdrop-filter: blur(4px);
}
.vt-btn { width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--r-sm); color: var(--ink-2); cursor: pointer; }
.vt-btn:hover { background: var(--surface-3); color: var(--ink); }
.vt-btn.is-active { background: var(--accent-bg); color: var(--accent); }
.vt-btn svg { width: 17px; height: 17px; }
.viewcube {
  position: absolute; top: 12px; right: 12px; width: 58px; height: 58px;
  border: 1px solid var(--border); border-radius: var(--r); background: rgba(255,255,255,.92);
  box-shadow: var(--shadow); display: grid; place-items: center; font-size: 10px; color: var(--ink-3);
}
.viewport__foot {
  position: absolute; bottom: 0; left: 0; right: 0; height: 32px; display: flex; align-items: center; gap: 16px;
  padding: 0 14px; background: rgba(255,255,255,.92); border-top: 1px solid var(--border);
  font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); backdrop-filter: blur(4px);
}
.viewport__foot .sp { margin-left: auto; }

/* Data panel (right) */
.dp { padding: 0; }
.dp__overall {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.dp__ring {
  --p: 91; width: 46px; height: 46px; border-radius: 50%; flex: none;
  background: conic-gradient(var(--ok) calc(var(--p)*1%), var(--surface-3) 0);
  display: grid; place-items: center;
}
.dp__ring > span { width: 34px; height: 34px; border-radius: 50%; background: #fff; display: grid; place-items: center; font-family: var(--mono); font-size: 12px; font-weight: 600; }
.dp__overall .t1 { font-size: 13px; font-weight: 600; }
.dp__overall .t2 { font-size: 11.5px; color: var(--ink-3); }

.dp__section { padding: 6px 0; border-bottom: 1px solid var(--border); }
.dp__section h4 {
  margin: 0; padding: 11px 16px 6px; font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); font-weight: 600;
}
.field { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; padding: 7px 16px; align-items: center; }
.field:hover { background: var(--surface-2); }
.field__k { font-size: 12px; color: var(--ink-3); }
.field__v { font-family: var(--mono); font-size: 13px; font-weight: 500; text-align: right; }
.field__c { grid-column: 2; justify-self: end; }
.field__act { grid-column: 1 / -1; display: none; gap: 6px; padding-top: 4px; }
.field:hover .field__act { display: flex; }

.dp__foot { padding: 14px 16px; display: flex; gap: 8px; }
.dp__foot .btn { flex: 1; justify-content: center; }

/* ---- Part detail ------------------------------------------------------ */
.detail-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; align-items: start; }
.prop-row { display: grid; grid-template-columns: 160px 1fr auto; gap: 12px; padding: 10px 16px; border-bottom: 1px solid var(--border); align-items: center; }
.prop-row:last-child { border: 0; }
.prop-row .k { font-size: 12.5px; color: var(--ink-3); }
.prop-row .v { font-family: var(--mono); font-size: 13px; }
.prov-item { display: flex; gap: 11px; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.prov-item:last-child { border: 0; }
.prov-ic { width: 30px; height: 30px; border-radius: var(--r-sm); background: var(--surface-3); color: var(--ink-2); display: grid; place-items: center; flex: none; }
.prov-ic svg { width: 16px; height: 16px; }
.prov-item .t1 { font-size: 13px; font-weight: 500; }
.prov-item .t2 { font-size: 11.5px; color: var(--ink-3); font-family: var(--mono); margin-top: 2px; }
.prov-item--active { background: var(--surface-2); cursor: default; pointer-events: none; }
.thumb { aspect-ratio: 4/3; border-radius: var(--r); border: 1px solid var(--border); overflow: hidden; }

/* ---- Preview thumbnail (bitmap extracted from the CAD file) ----------- */
.preview-img { display: block; object-fit: contain; background: #fff; }
.thumb .preview-img { width: 100%; height: 100%; border-radius: inherit; }

/* Workbench centre viewport: show the preview clear of the floating toolbar
   (top-left) and the info footer (bottom); cap size so it stays crisp. */
#vp-svg { position: absolute; inset: 0; display: grid; place-items: center; padding: 56px 28px 44px; }
#vp-svg .preview-img {
  max-width: min(100%, 560px); max-height: 100%;
  border: 1px solid var(--border); border-radius: var(--r-sm); box-shadow: var(--shadow);
}

/* Honest empty state — shown when the source file has no embedded thumbnail. */
.preview-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; text-align: center; color: var(--ink-3); width: 100%; height: 100%;
}
.preview-empty svg { width: 42px; height: 42px; opacity: .45; }
.preview-empty span { font-size: 13px; font-weight: 600; color: var(--ink-2); }
.preview-empty small { font-size: 11.5px; color: var(--ink-3); max-width: 240px; }

/* ---- Interactive drawing viewer (real extracted geometry, pan + zoom) --- */
.dgm-loading { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; width: 100%; height: 100%; color: var(--ink-3); font-size: 12.5px; }
.dgm-spin { width: 22px; height: 22px; border: 3px solid var(--surface-3); border-top-color: var(--accent);
  border-radius: 50%; animation: dgm-spin .8s linear infinite; }
@keyframes dgm-spin { to { transform: rotate(360deg); } }

.dgm { position: absolute; inset: 0; display: flex; flex-direction: column; background: #fff; }
.dgm__sheets { flex: none; display: flex; gap: 4px; padding: 6px 8px; border-bottom: 1px solid var(--border);
  background: var(--surface-2); z-index: 2; }
.dgm__tab { font: inherit; font-size: 11px; font-weight: 600; color: var(--ink-2); background: #fff;
  border: 1px solid var(--border); border-radius: var(--r-sm); padding: 3px 9px; cursor: pointer; }
.dgm__tab:hover { background: var(--surface-3); }
.dgm__tab.is-active { color: var(--accent); background: var(--accent-bg); border-color: transparent; }

.dgm__stage { position: relative; flex: 1; min-height: 0; overflow: hidden; cursor: grab; touch-action: none; }
.dgm__stage.is-dragging { cursor: grabbing; }
.dgm__canvas { position: absolute; inset: 0; transform-origin: 0 0; will-change: transform; }
.dgm__canvas svg { width: 100%; height: 100%; display: block; }
/* Balloon overlay stacks on top of the geometry SVG, sharing its viewBox. */
.dgm__canvas .dgm__balloons { position: absolute; inset: 0; pointer-events: none; overflow: visible; }

/* Exploded-view balloons (BOM callouts). vector-effect keeps strokes/markers a
   constant on-screen size through the canvas zoom transform. */
.dgm-bln { pointer-events: none; }
.dgm-bln__hit { fill: transparent; pointer-events: all; cursor: default; }
.dgm-bln.is-link .dgm-bln__hit { cursor: pointer; }
.dgm-bln__dot { fill: #fff; stroke: #16213e; vector-effect: non-scaling-stroke; }
.dgm-bln__txt { fill: #16213e; font-family: var(--mono, monospace); font-weight: 700;
  text-anchor: middle; dominant-baseline: central; pointer-events: none; }
/* Leader lines + tips are shown for every balloon at rest (subtle grey) so the
   whole pos->part mapping is legible without hovering; hover/cross-highlight
   promotes one balloon to the accent colour. */
.dgm-bln__lead { stroke: #7b8a98; vector-effect: non-scaling-stroke; opacity: .55; }
.dgm-bln__tip { fill: #7b8a98; opacity: .7; }
.dgm-bln.is-hot .dgm-bln__lead { stroke: var(--accent, #2f6df6); opacity: 1; }
.dgm-bln.is-hot .dgm-bln__tip { fill: var(--accent, #2f6df6); opacity: 1; }
.dgm-bln.is-hot .dgm-bln__dot { fill: var(--accent, #2f6df6); stroke: var(--accent, #2f6df6); }
.dgm-bln.is-hot .dgm-bln__txt { fill: #fff; }
/* Raise the hovered balloon above its neighbours so its leader/label win. */
.dgm-bln.is-hot { pointer-events: all; }

.dgm__tip { position: absolute; z-index: 4; max-width: 220px; pointer-events: none;
  background: rgba(22,33,62,.96); color: #fff; border-radius: var(--r-sm, 6px); padding: 7px 10px;
  box-shadow: var(--shadow, 0 4px 14px rgba(0,0,0,.2)); font-size: 12px; line-height: 1.35; }
.dgm__tip[hidden] { display: none; }
.dgm__tip-pos { display: inline-block; min-width: 18px; padding: 0 5px; margin-right: 6px;
  background: var(--accent, #2f6df6); border-radius: 999px; font-weight: 700; text-align: center; }
.dgm__tip-no { font-family: var(--mono, monospace); font-weight: 600; }
.dgm__tip-name { display: block; margin-top: 3px; color: #cdd6f4; }
.dgm__tip-go { display: block; margin-top: 4px; color: #9ec1ff; font-size: 11px; }

.dgm__hint { position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%);
  font-size: 11px; color: var(--ink-3); background: rgba(255,255,255,.85); border: 1px solid var(--border);
  border-radius: 999px; padding: 3px 10px; pointer-events: none; opacity: .9; }
.dgm__ctrls { position: absolute; right: 12px; bottom: 12px; display: flex; align-items: center; gap: 3px;
  background: rgba(255,255,255,.94); border: 1px solid var(--border); border-radius: var(--r);
  padding: 4px; box-shadow: var(--shadow); backdrop-filter: blur(4px); }
.dgm__btn { width: 28px; height: 28px; display: grid; place-items: center; border: 0; background: transparent;
  color: var(--ink-2); border-radius: var(--r-sm); cursor: pointer; font-size: 17px; line-height: 1; }
.dgm__btn:hover { background: var(--surface-3); color: var(--ink); }
.dgm__btn svg { width: 15px; height: 15px; }
.dgm__pct { min-width: 40px; text-align: center; font-family: var(--mono); font-size: 11px; color: var(--ink-3); }

/* Workbench centre viewport: let the diagram fill it, hide the decorative 3D
   chrome (orbit/viewcube imply features we don't have), keep clear of the foot. */
#vp-svg.dgm-has { padding: 0; }
.viewport.has-dgm .viewport__toolbar,
.viewport.has-dgm .viewcube { display: none; }
#vp-svg .dgm__ctrls { bottom: 42px; }
#vp-svg .dgm__hint { bottom: 40px; }

/* Part-detail preview card hosts the same viewer. */
.thumb { position: relative; }
.thumb.dgm-has { background: #fff; }

.kv-inline { display: flex; gap: 22px; flex-wrap: wrap; margin-top: 10px; }
.kv-inline .kv .k { font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em; }
.kv-inline .kv .v { font-family: var(--mono); font-size: 14px; font-weight: 500; margin-top: 2px; }

.muted { color: var(--ink-3); }
.hr { height: 1px; background: var(--border); border: 0; margin: 18px 0; }

/* ---- Tree cross-highlight (balloon hover -> matching node) ------------- */
.tree__node.is-hot { background: var(--accent-bg); box-shadow: inset 3px 0 0 var(--accent); }
.tree__node.is-hot .pic { color: var(--accent); }

/* Prominent "open detail" link in the workbench viewport header. */
.vp-detail { margin-left: 10px; font-size: 12px; font-weight: 600; text-transform: none;
  letter-spacing: 0; display: inline-flex; align-items: center; gap: 4px; }
.vp-detail svg { width: 13px; height: 13px; }

/* ---- Project pill quick-jump dropdown ---------------------------------- */
.project { position: relative; }
.proj-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 60; width: 320px;
  max-height: min(70vh, 520px); display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  box-shadow: var(--shadow-md); overflow: hidden;
}
.proj-menu[hidden] { display: none; }
.proj-menu__head { padding: 9px 12px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.proj-menu__head .t1 { font-size: 12px; font-weight: 700; }
.proj-menu__head .t2 { font-size: 11px; color: var(--ink-3); font-family: var(--mono); margin-top: 1px; }
.proj-menu__search { padding: 8px; border-bottom: 1px solid var(--border); }
.proj-menu__search input { width: 100%; border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 6px 9px; font: inherit; font-size: 13px; outline: none; }
.proj-menu__search input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
.proj-menu__list { overflow: auto; padding: 4px; }
.proj-menu__item { display: flex; align-items: center; gap: 8px; padding: 7px 9px;
  border-radius: var(--r-sm); cursor: pointer; color: var(--ink); }
.proj-menu__item:hover, .proj-menu__item.is-active { background: var(--surface-2); }
.proj-menu__item svg { width: 15px; height: 15px; color: var(--accent); flex: none; }
.proj-menu__item .nm { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.proj-menu__item .pn { margin-left: auto; padding-left: 8px; font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.proj-menu__empty { padding: 16px; color: var(--ink-3); font-size: 12.5px; text-align: center; }

/* ---- Edit-field modal (shared: part.html + workbench.html) ------------- */
.ed-modal {
  position: fixed; inset: 0; z-index: 9000; display: none;
  align-items: center; justify-content: center;
  background: rgba(15,23,42,.48); backdrop-filter: blur(2px);
}
.ed-modal.is-open { display: flex; }
.ed-modal__box {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; padding: 24px 24px 20px; width: 400px; max-width: calc(100vw - 32px);
  box-shadow: 0 20px 60px rgba(0,0,0,.28); font-family: inherit;
}
.ed-modal__title { margin: 0 0 4px; font-size: 15px; font-weight: 600; color: var(--ink); }
.ed-modal__sub { margin: 0 0 12px; font-size: 12px; color: var(--ink-3); }
.ed-modal__candidates { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.ed-modal__cand-hd { font-size: 10.5px; font-weight: 600; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em; width: 100%; margin-bottom: 2px; }
.ed-modal__cand {
  display: flex; flex-direction: column; align-items: flex-start;
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px;
  font-size: 12.5px; cursor: pointer; background: var(--surface-2);
  color: var(--ink); font-family: inherit; text-align: left;
  transition: border-color .12s, background .12s;
}
.ed-modal__cand:hover { border-color: var(--accent); background: var(--accent-bg); color: var(--accent); }
.ed-modal__cand--rec { border-color: var(--ok, #10b981); background: #f0fdf4; }
.ed-modal__cand--rec:hover { border-color: var(--ok, #10b981); background: #dcfce7; color: var(--ink); }
.ed-modal__cand--rec small { color: var(--ok, #10b981); font-weight: 600; }
.ed-modal__cand small { font-size: 10px; color: var(--ink-3); margin-bottom: 2px; }
.ed-modal__input {
  width: 100%; box-sizing: border-box;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px;
  font-size: 13px; font-family: inherit; color: var(--ink); background: var(--surface);
  outline: none; transition: border-color .15s;
}
.ed-modal__input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37,99,235,.12); }
.ed-modal__foot { margin-top: 16px; display: flex; gap: 8px; justify-content: flex-end; }

/* ---- Make-vs-buy badge (shared: Workbench tree, node inspector, Part Detail) --- */
.tree-mvb { font-size: 9.5px; padding: 1px 5px; border-radius: 3px; margin-left: 4px; font-weight: 600; flex-shrink: 0; }
.tree-mvb--buy { background: rgba(34,197,94,.15); color: #15803d; }
.tree-mvb--make { background: rgba(11,127,199,.12); color: #0B7FC7; }
.tree-mvb--uncertain { background: rgba(245,158,11,.12); color: #b45309; }
/* Assembly subtree make/buy rollup — a neutral count summary (not a single verdict), so no
   pill outline; the coloured numbers carry the meaning, the tooltip names the parts. */
.tree-mvb-roll { font-size: 9.5px; font-weight: 600; margin-left: 6px; flex-shrink: 0; color: var(--ink-3); white-space: nowrap; }

/* ---- Reuse-count chip — a plain number, always shown, tooltip carries the words --- */
.tree-reuse {
  font-size: 9.5px; font-weight: 700; padding: 1px 6px; border-radius: 9px; margin-left: 4px;
  background: var(--surface-3); color: var(--ink-3); flex-shrink: 0;
}

/* ---- Duplicate chips (Phase 2) — same scale as .tree-mvb. Pending = warn tint
   ("⧉ duplicate?" linking to the part's resolve section); merged = accent tint
   ("⧉ N dwgs" on the canonical, tooltip lists the collapsed aliases). ---- */
.tree-dup {
  /* Same pill metrics as .ai-badge-pulse so the "variant?" chip and the "✦ AI n%"
     badge sit beside each other as a matched pair (equal height + shape). */
  display: inline-flex; align-items: center; gap: 3px;
  font-family: inherit; font-size: 9.5px; padding: 1px 8px; border-radius: 20px; margin-left: 4px;
  font-weight: 600; line-height: 15px; flex-shrink: 0; text-decoration: none;
  border: 1px solid transparent; /* match .ai-badge-pulse box height */
}
.tree-dup--pending { background: var(--warn-bg, rgba(201,129,10,.12)); color: var(--warn, #C9810A); }
a.tree-dup--pending:hover { background: rgba(201,129,10,.22); color: var(--warn, #C9810A); }
.tree-dup--merged { background: var(--accent-bg, #E7F2FB); color: var(--accent, #0B7FC7); }

/* THE shared relation chip — "⧉ <label>", used identically on the tree, the detail
   panel and the Quality review queue. Colour comes inline from In2.relationMeta, so
   text + border track the verdict; the pill metrics match .ai-badge-pulse. */
.rel-chip {
  display: inline-flex; align-items: center; gap: 3px; vertical-align: middle;
  font-family: inherit; font-size: 9.5px; font-weight: 600; line-height: 15px;
  padding: 1px 8px; border-radius: 20px; margin-left: 4px; flex-shrink: 0;
  text-decoration: none; white-space: nowrap;
  border: 1px solid currentColor; background: transparent;
}
button.rel-chip { cursor: pointer; }
button.rel-chip:hover { background: rgba(0,0,0,.05); }

/* THE make-vs-buy badge — same pill grammar as .rel-chip (outlined, coloured by verdict),
   with a small icon. One renderer (In2.mvbBadge) → identical on tree, bubble map, detail
   panel, Quality grid. */
.mvb-badge {
  display: inline-flex; align-items: center; gap: 3px; vertical-align: middle;
  font-size: 9.5px; font-weight: 600; line-height: 15px;
  padding: 1px 7px; border-radius: 20px; margin-left: 4px; flex-shrink: 0;
  white-space: nowrap; border: 1px solid currentColor; background: transparent;
}
button.mvb-badge { cursor: pointer; }

/* Non-AI confidence badge — a % OUR code computed (geometry / fuzzy match), not an
   AI call. Deliberately unlike .ai-badge-pulse: teal, no ✦ star, no pulse. */
.auto-badge {
  display: inline-flex; align-items: center; gap: 3px; vertical-align: middle;
  font-size: 9.5px; font-weight: 600; line-height: 15px; letter-spacing: .03em;
  padding: 1px 7px; border-radius: 20px; margin-left: 4px; white-space: nowrap;
  color: var(--auto-ink, #0F766E); background: var(--auto-bg, rgba(15,118,110,.10));
  border: 1px solid var(--auto-border, rgba(15,118,110,.28));
}
.auto-badge svg { width: 11px; height: 11px; flex-shrink: 0; }

/* ---- Flat tree list (workbench global mode) ----------------------------- */
.tree-list { padding: 4px 0; }
.tree-item {
  display: flex; align-items: center; gap: 6px;
  padding: 3px 12px; cursor: pointer; font-size: 12.5px;
  user-select: none; border-radius: 0; position: relative;
  transition: opacity .2s, background .1s;
}
/* Same hover grammar as groups/categories (.tree-cat): blue tint + a 3px accent
   line at the row's left edge. Drawn on ::after because ::before is the guide rail. */
.tree-item:hover { background: var(--accent-bg, rgba(11,127,199,.07)); }
.tree-item:hover::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--accent, #0B7FC7);
}
.tree-item.is-sel { background: var(--accent-bg); }
.tree-item.is-sel .tree-num,
.tree-item.is-sel .tree-name { color: var(--accent); }
.tree-item.is-hot { outline: 2px solid var(--warn, #f59e0b); outline-offset: -2px; background: var(--surface-2); }
.tree-toggle {
  width: 16px; height: 16px; padding: 0; border: none; background: none;
  cursor: pointer; color: var(--ink-3); font-size: 10px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; border-radius: 3px;
}
.tree-toggle:hover { background: var(--surface-3); color: var(--ink); }
.tree-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.tree-num { font-family: var(--mono); font-size: 11px; color: var(--ink-2); flex-shrink: 0; }
.tree-name { color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; }
.tree-children { display: none; }
.tree-children.is-open { display: block; }

/* ---- Review icon buttons (part.html) ----------------------------------- */
.rv-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border: 1px solid var(--border);
  border-radius: 5px; background: var(--surface); cursor: pointer;
  color: var(--ink-3); transition: border-color .12s, color .12s; flex: none;
}
.rv-btn:hover { border-color: var(--accent); color: var(--accent); }
.rv-btn:disabled { opacity: .4; cursor: default; pointer-events: none; }
.rv-btn svg { width: 13px; height: 13px; stroke-width: 2; }
.rv-btn--ok:hover  { border-color: var(--ok,#22c55e);  color: var(--ok,#22c55e); }
.rv-btn--bad:hover { border-color: var(--bad,#dc3545); color: var(--bad,#dc3545); }


/* =========================================================================
   Shared conformance UI — used by all pages via In2.confScoreBadge(),
   In2.importGatePill(), In2.fieldScoreChip(). Single definition here.
   ========================================================================= */

/* Score badge */
.conf-badge { display:inline-flex; align-items:baseline; gap:2px; font-weight:700; line-height:1; }
.conf-badge__score { font-size:2.4em; }
.conf-badge__pct   { font-size:1.1em; }
.conf-badge__band  { font-size:0.55em; font-weight:600; letter-spacing:.04em; text-transform:uppercase; margin-left:6px; opacity:.8; }
.conf-badge--unknown { color:var(--ink-3); }

/* Band colours (applied to .conf-badge and other elements) */
.band--excellent { color:var(--ok,#22c55e); }
.band--review    { color:var(--warn,#C9810A); }
.band--critical  { color:var(--bad,#CC3D3D); }
.band--unknown    { color:var(--ink-3); }

/* Import gate pill */
.gate-pill { display:inline-flex; align-items:center; gap:5px; padding:3px 10px; border-radius:20px; font-size:12px; font-weight:600; white-space:nowrap; }
.gate-pill::before { content:''; width:7px; height:7px; border-radius:50%; flex-shrink:0; }
.gate-pill--ready   { background:rgba(34,197,94,.12);  color:var(--ok,#22c55e);   border:1px solid rgba(34,197,94,.25); }
.gate-pill--ready::before { background:var(--ok,#22c55e); }
.gate-pill--blocked { background:rgba(204,61,61,.12);  color:var(--bad,#CC3D3D);  border:1px solid rgba(204,61,61,.25); }
.gate-pill--blocked::before { background:var(--bad,#CC3D3D); }
.gate-pill--partial { background:rgba(201,129,10,.12); color:var(--warn,#C9810A); border:1px solid rgba(201,129,10,.25); }
.gate-pill--partial::before { background:var(--warn,#C9810A); }
.gate-pill--setup   { background:rgba(255,255,255,.08); color:rgba(255,255,255,.5); border:1px solid rgba(255,255,255,.15); }
.gate-pill--setup::before   { background:rgba(255,255,255,.35); }

/* Field score chip */
.field-chip { display:inline-block; padding:1px 7px; border-radius:4px; font-size:11.5px; font-weight:600; font-variant-numeric:tabular-nums; }
.field-chip--ok   { background:rgba(34,197,94,.12);  color:var(--ok,#22c55e); }
.field-chip--warn { background:rgba(201,129,10,.12); color:var(--warn,#C9810A); }
.field-chip--bad  { background:rgba(204,61,61,.12);  color:var(--bad,#CC3D3D); }
.field-chip--null { color:var(--ink-3); background:transparent; }

/* Auto-defaulted state (amber, distinct from normal/error) */
.field-defaulted { display:inline-flex; align-items:center; gap:4px; padding:2px 8px; border-radius:4px; background:rgba(201,129,10,.1); color:var(--warn,#C9810A); font-size:11px; font-weight:600; border:1px solid rgba(201,129,10,.2); }

/* ── Shared empty state (no model / no data) ── */
.empty-state { display:flex; flex-direction:column; align-items:center; padding:52px 48px; gap:18px; text-align:center; background:var(--surface); border:1px solid var(--border); border-radius:16px; max-width:560px; margin:48px auto; box-shadow:0 2px 12px rgba(0,0,0,.06); }
.empty-state__icon { color:var(--accent,#0B7FC7); opacity:.75; }
.empty-state__title { font-size:20px; font-weight:700; color:var(--ink); margin:0; }
.empty-state__body { font-size:14px; color:var(--ink-3); max-width:400px; line-height:1.65; margin:0; }
.empty-state__cta { display:inline-block; padding:12px 28px; background:var(--accent,#0B7FC7); color:#fff; border-radius:50px; font-size:14px; font-weight:600; text-decoration:none; border:none; cursor:pointer; margin-top:4px; }
.empty-state__cta:hover { opacity:.88; }
.empty-state__hint { font-size:12px; color:var(--ink-3); margin:0; }

/* ── Shared AI modal ── */
.ai-modal-overlay { position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:1000; display:flex; align-items:center; justify-content:center; padding:24px; }
.ai-modal { background:var(--surface); border:1px solid var(--border); border-radius:12px; width:100%; max-width:760px; max-height:90vh; display:flex; flex-direction:column; overflow:hidden; box-shadow:0 24px 60px rgba(0,0,0,.25); }
.ai-modal--sm { max-width:520px; }
.ai-modal__head { display:flex; align-items:center; justify-content:space-between; padding:16px 20px; border-bottom:1px solid var(--border); font-size:14px; font-weight:600; gap:8px; }
.ai-modal__head svg { vertical-align:middle; color:var(--accent); }
.ai-modal__close { background:none; border:none; cursor:pointer; color:var(--ink-3); font-size:16px; padding:4px 8px; border-radius:4px; line-height:1; }
.ai-modal__close:hover { background:var(--surface-2); color:var(--ink); }
.ai-modal__body { padding:20px; overflow-y:auto; flex:1; display:flex; flex-direction:column; gap:12px; }
.ai-modal__step { display:flex; align-items:flex-start; gap:12px; }
.ai-modal__num { width:24px; height:24px; border-radius:50%; background:var(--accent); color:#fff; font-size:12px; font-weight:700; flex-shrink:0; display:flex; align-items:center; justify-content:center; }
.ai-modal__hint { font-size:12px; color:var(--ink-2); margin:4px 0 0; line-height:1.5; }
.ai-modal__hint a { color:var(--accent); }
.ai-modal__prompt-wrap { position:relative; flex:0 0 auto; }
.ai-modal__loading { font-size:13px; color:var(--ink-3); padding:12px 0; }
.ai-modal__error { font-size:13px; color:var(--bad); padding:8px 0; }
.ai-modal__prompt { width:100%; height:180px; flex-shrink:0; font-family:var(--mono); font-size:11.5px; background:var(--surface-2); border:1px solid var(--border); border-radius:6px; padding:10px 12px; resize:vertical; color:var(--ink-2); line-height:1.5; }
.ai-modal__prompt:focus { outline:none; border-color:var(--accent); }
.ai-modal__copy { margin-top:6px; font-size:12px; padding:5px 12px; border-radius:5px; border:1px solid var(--border); background:var(--surface); cursor:pointer; color:var(--ink-2); }
.ai-modal__copy:hover { background:var(--accent); color:#fff; border-color:var(--accent); }

/* Direct AI run button (§9.1, second transport) — same .btn--ai every other AI
   action uses; this positions it next to "Copy to clipboard". Only ever inserted
   when an API key is configured. */
.ai-run-btn { margin-top:6px; margin-left:8px; }
.ai-run-btn__cancel { text-decoration:underline; cursor:pointer; margin-left:4px; }
.ai-run-btn__error { font-size:12px; color:var(--bad,#dc2626); margin-top:6px; }
.ai-modal__response { width:100%; height:150px; flex-shrink:0; font-family:var(--mono); font-size:11.5px; background:var(--surface-2); border:1px solid var(--border); border-radius:6px; padding:10px 12px; resize:vertical; color:var(--ink); line-height:1.5; }
.ai-modal__response:focus { outline:none; border-color:var(--accent); }
.ai-modal__status { font-size:12.5px; padding:6px 0; }
.ai-modal__status--ok { color:var(--ok,#16a34a); }
.ai-modal__status--warn { color:var(--warn,#C9810A); }
.ai-modal__status--err { color:var(--bad,#dc2626); }
.ai-modal__foot { display:flex; justify-content:flex-end; gap:8px; padding:14px 20px; border-top:1px solid var(--border); }

/* ── AI suggestion badge (pulsing indigo) — the one AI marker, everywhere. ──
   Default styling assumes a light surface (dark indigo text on a light indigo
   tint). --on-dark re-tints for dark surfaces (hero, dark modals, AI Insights
   banner) with the SAME hue, just lightened for contrast — never a different
   colour. Auto-applies inside .q-gate-config / .q-hero / .q-ai-banner so a plain
   X.aiBadge() call never needs to know its own background. */
@keyframes aiPulse { 0%,100%{opacity:1;box-shadow:0 0 0 0 rgba(99,102,241,.35)} 60%{opacity:.85;box-shadow:0 0 0 4px rgba(99,102,241,0)} }
.ai-badge-pulse { display:inline-flex; align-items:center; gap:3px; padding:1px 7px; border-radius:20px; font-size:9.5px; font-weight:600; line-height:15px; letter-spacing:.03em; color:var(--ai-ink); background:var(--ai-bg); border:1px solid var(--ai-border); animation:aiPulse 2.2s ease-in-out infinite; vertical-align:middle; margin-left:4px; white-space:nowrap; }
.ai-badge-pulse svg { width:11px; height:11px; flex-shrink:0; }
/* The review-count pill inside an AI badge — a bordered rounded chip so the number
   reads as a count ("3 to review"), not an opaque suffix. Inherits the badge ink; the
   border is a low-contrast tint of it and the number is a touch smaller and softened. */
.ai-badge__count { display:inline-block; min-width:14px; padding:0 3px;
  border:1px solid color-mix(in srgb, currentColor 40%, transparent);
  border-radius:999px; font-size:8px; font-weight:700; line-height:13px; text-align:center;
  opacity:.85; font-variant-numeric:tabular-nums; }
.ai-badge-pulse--lg { font-size:11px; padding:2px 9px; }
.ai-badge-pulse--lg svg { width:13px; height:13px; }
.ai-badge-pulse--on-dark,
.q-gate-config .ai-badge-pulse,
.q-hero .ai-badge-pulse,
.q-ai-banner .ai-badge-pulse {
  color: var(--ai-light); background: rgba(99,102,241,.2); border-color: rgba(165,180,252,.4);
}

/* ── Export modal ── */
.export-section-label { font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.06em; color:var(--ink-3); margin-bottom:8px; }
/* Subheading separating the business/facet columns from the data fields, in both the
   completeness selector and the export modal. */
.q-gate-group-label { font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:var(--ink-3); margin:10px 0 4px; padding-top:8px; border-top:1px solid var(--border); }
.export-worklist { margin-top:10px; }
.export-worklist-summary { font-size:12px; color:var(--ink-2); }
.export-blocked-list { margin-top:6px; max-height:120px; overflow-y:auto; border:1px solid var(--border); border-radius:6px; padding:6px 8px; background:var(--surface-2); }
.export-blocked-row { font-size:11.5px; color:var(--ink-2); padding:2px 0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.export-blocked-reason { color:var(--warn,#C9810A); }
.export-status-row { display:flex; gap:6px; flex-wrap:wrap; margin-top:4px; }
.export-status-opt { display:flex; align-items:center; gap:6px; font-size:13px; color:var(--ink); cursor:pointer; padding:6px 12px; border:1px solid var(--border); border-radius:8px; background:var(--ground); transition:border-color .15s; }
.export-status-opt:hover { border-color:var(--accent,#6366f1); }
.export-status-opt input { margin:0; cursor:pointer; }
.export-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
.export-dot--green { background:#22c55e; }
.export-dot--yellow { background:#f59e0b; }
.export-dot--red { background:#ef4444; }
.export-no-model { display:flex; align-items:center; gap:8px; font-size:12.5px; color:var(--ink-2); padding:10px 12px; background:rgba(245,158,11,.08); border:1px solid rgba(245,158,11,.25); border-radius:8px; }
.export-no-model svg { flex-shrink:0; color:#d97706; }
.export-no-model a { color:var(--accent,#6366f1); font-weight:600; text-decoration:none; }

/* ── R1: shared tile-scroll rule — any tile whose content can outgrow it gets
   a fixed max-height and scrolls internally, everywhere, instead of pushing
   the rest of the page down or truncating to a "top N" list.

   A header row given `position: sticky` INSIDE the scrolling element stays
   visually pinned, but the native scrollbar still spans the whole element,
   including the strip behind the header — it reads as "the scrollbar covers
   the header too". The only real fix is structural: the header must be a
   sibling BEFORE the scrolling box, not sticky-positioned inside it.
   .tile-frame is that wrapper — border/radius/background live here once;
   a header row goes in first (never scrolls, no sticky needed), then a
   .tile-scroll div holds only the rows (that's the only element with its own
   scrollbar, so the scrollbar only ever runs alongside content). ── */
.tile-frame { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.tile-scroll { max-height: 360px; overflow-y: auto; scrollbar-gutter: stable; }
.tile-scroll--tall { max-height: 480px; }
.tile-scroll--short { max-height: 220px; }
/* A native scrollbar is opaque, rectangular chrome — on a rounded tile it visually
   squares off the top-right/bottom-right corners it sits against. A thin scrollbar
   with a transparent track (no solid rectangle) reads as floating near the edge
   instead of replacing the rounded corner with a square one. */
.tile-scroll { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
.tile-scroll::-webkit-scrollbar { width: 8px; }
.tile-scroll::-webkit-scrollbar-track { background: transparent; }
.tile-scroll::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
.tile-scroll::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }

/* Same principle for a REAL <table> (BOM parts list): thead and tbody become independent
   row-groups (table-layout:fixed keeps their columns the same width since both start from
   the same column count and 100% width) so only <tbody> scrolls — the header is a plain,
   non-scrolling sibling row-group, no position:sticky, no scrollbar ever touching it. */
.pd-bom-hscroll { overflow-x: auto; }
table.pd-bom { width: 100%; table-layout: fixed; }
table.pd-bom thead { display: table; width: 100%; table-layout: fixed; }
table.pd-bom tbody.pd-bom-vscroll { display: block; max-height: 420px; overflow-y: auto; scrollbar-gutter: stable; }
table.pd-bom tbody.pd-bom-vscroll tr { display: table; width: 100%; table-layout: fixed; }
table.pd-bom tbody.pd-bom-vscroll { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
table.pd-bom tbody.pd-bom-vscroll::-webkit-scrollbar { width: 8px; }
table.pd-bom tbody.pd-bom-vscroll::-webkit-scrollbar-track { background: transparent; }
table.pd-bom tbody.pd-bom-vscroll::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
table.pd-bom tbody.pd-bom-vscroll::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }
/* The card title above already has no divider of its own (border-bottom:none) — a top
   edge on the frame would just be a second, redundant separator right under it. */
.pd-bom-frame { border-top: 0; }

/* ── R4: icon-button set for inline Confirm / Override / Assign / Delete ── */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 21px; height: 21px; padding: 0; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--ink-2);
  font-size: 11px; line-height: 1;
  flex-shrink: 0; transition: background .12s, border-color .12s, color .12s;
}
.icon-btn:hover { background: var(--surface-3); color: var(--ink); }
.icon-btn--confirm:hover { border-color: var(--ok); color: var(--ok); }
.icon-btn--override:hover { border-color: var(--warn); color: var(--warn); }
.icon-btn--assign:hover { border-color: var(--accent); color: var(--accent); }
.icon-btn--ignore:hover { border-color: var(--ink-3); color: var(--ink); }
.icon-btn--reject:hover { border-color: var(--warn); color: var(--warn); }
.icon-btn--delete:hover { border-color: var(--bad); color: var(--bad); }
/* Active/engaged state — the verdict has been applied (approved, rejected, ignored).
   Same colour language as the hover, made persistent so the current state reads at rest. */
.icon-btn--confirm.active { background: var(--ok-bg); border-color: var(--ok); color: var(--ok); }
.icon-btn--reject.active { background: var(--warn-bg); border-color: var(--warn); color: var(--warn); }
.icon-btn--ignore.active { background: var(--surface-3); border-color: var(--ink-3); color: var(--ink); }
.icon-btn:disabled { opacity: .4; cursor: not-allowed; }
.btn--danger { background: var(--bad); border-color: var(--bad); color: #fff; }
.btn--danger:hover { background: #B33333; border-color: #B33333; }

/* ── R3: picker modal — a named list of clickable options, replaces
   window.prompt for choosing a category or a make/buy classification ── */
.picker-list { display: flex; flex-direction: column; gap: 6px; }
.picker-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  text-align: left; width: 100%; padding: 10px 14px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface); cursor: pointer;
  font: inherit; color: var(--ink);
}
.picker-opt:hover { border-color: var(--accent); background: var(--accent-bg); }
.picker-opt__label { font-weight: 600; font-size: 13.5px; }
.picker-opt__hint { font-size: 12px; color: var(--ink-3); }
.picker-opt--clear { margin-top: 4px; color: var(--ink-3); border-style: dashed; }

/* ── R5: left colour-stripe rule — red = blocking/critical, amber = needs
   review, no stripe = informational. One rule, applied everywhere. ── */
.tile--critical { border-left: 3px solid var(--bad); }
.tile--warn     { border-left: 3px solid var(--warn); }

/* ── R6: shared make-vs-buy block (Workbench inspector, Part Detail, the
   merged reuse/make-vs-buy view) — one implementation, mounted three places. ── */
/* Blocked — facet classification waiting on unresolved model fields */
.detail-blocked {
  display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px;
  background: rgba(217,119,6,.08); border: 1px dashed var(--warn, #d97706);
  border-radius: 6px; font-size: 11.5px; color: var(--warn, #d97706);
}
.detail-blocked__icon { font-size: 13px; flex-shrink: 0; }
.detail-blocked__fields { font-weight: 600; }

.mvb-block { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mvb-block .tree-mvb { margin-left: 0; }
.mvb-block__actions { display: inline-flex; gap: 4px; margin-left: 2px; }
.mvb-block__confirmed-mark { color: var(--ok); display: inline-flex; align-items: center; gap: 4px; }
.export-no-model a:hover { text-decoration:underline; }

/* Reusable make/buy chooser — one look on the tree popover, detail panel and bubble popover. */
.mvb-chooser { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mvb-chooser__set { display: inline-flex; align-items: center; gap: 5px; }
.mvb-chooser__lbl { font-size: 11px; color: var(--ink-3); }
.mvb-chooser__btn {
  font-size: 11px; font-weight: 600; line-height: 1; padding: 3px 8px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface); color: var(--ink-2); cursor: pointer;
}
.mvb-chooser__btn:hover { border-color: currentColor; }
.mvb-chooser__btn--buy:hover       { color: #15803d; }
.mvb-chooser__btn--make:hover      { color: #0B7FC7; }
.mvb-chooser__btn--uncertain:hover { color: #b45309; }
.mvb-chooser__btn:disabled { opacity: .5; cursor: default; }
.mvb-chooser__reset {
  font-size: 12px; line-height: 1; padding: 3px 7px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--ink-3);
}
.mvb-chooser__reset:hover { color: var(--ink); border-color: currentColor; }

/* ══ Phase 0 canonical additions — one implementation per concept ══════════
   .stamp   — decision record (who · when) chip, rendered via In2.stamp()
   .select  — the one dropdown look; apply to every <select> (replaces ad-hoc
              per-page select styling; padding reserves room for the chevron
              so text never collides with the arrow). ─────────────────────── */
.stamp {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--mono); font-size: 10.5px; color: var(--ink-3);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 10px; padding: 1px 7px; white-space: nowrap;
}

/* ---- Duplicate resolution section (part detail, Phase 2) --------------------
   Compare cards side by side + four actions + the inline rename expander
   (bordered soft-AI-blue panel — the skeleton's fix-form pattern, not a modal). */
.dup-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; padding: 10px 16px; }
.dup-card {
  border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px;
  background: var(--surface-2); display: block; position: relative;
}
.dup-card--canonical { border-color: var(--ok); box-shadow: 0 0 0 1px var(--ok) inset; }
/* Head WRAPS — radio + number + kind + id + "this item" + Drawing overflowed a narrow
   card in one non-wrapping row. Now they wrap; the internal id truncates rather than
   pushing the row wide. */
.dup-card__head { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 6px; margin-bottom: 4px; }
.dup-card__head input[type=radio] { accent-color: var(--ok, #1E9E68); margin: 0; }
.dup-card__head .mono.muted { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 130px; }
.dup-card__num { font-family: var(--mono); font-size: 12.5px; font-weight: 700; color: var(--ink); }
/* Kind chip (assembly / part) — neutral, uppercase, sits between the number and the id. */
.dup-card__kind { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-2); background: var(--surface-2, rgba(120,130,140,.14)); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 5px; line-height: 1.4; }
.dup-card__you { font-size: 10px; color: var(--ink-3); }
/* "Drawing" — preview this candidate's drawing in the CAD viewport (in place). */
.dup-card__view {
  margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); color: var(--accent, #0B7FC7); font-size: 10.5px;
  font-family: inherit; cursor: pointer; white-space: nowrap;
}
.dup-card__view:hover { border-color: var(--accent, #0B7FC7); background: var(--accent-bg, rgba(11,127,199,.07)); }
.dup-card__view svg { flex-shrink: 0; }
/* Related-item comparison banner — floats OVER the CAD viewport (the drawing is
   absolutely positioned and fills the pane, so the banner must overlay it). */
#vp-compare-banner {
  position: absolute; top: 0; left: 0; right: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 6px 12px; background: var(--accent-bg, rgba(11,127,199,.12));
  border-bottom: 1px solid var(--accent, #0B7FC7); font-size: 12px; color: var(--ink);
  backdrop-filter: blur(2px);
}
.vp-cmp__back {
  border: 1px solid var(--border); background: var(--surface); border-radius: 6px;
  padding: 3px 10px; font-size: 11.5px; cursor: pointer; font-family: inherit;
  color: var(--accent, #0B7FC7); white-space: nowrap;
}
.vp-cmp__back:hover { border-color: var(--accent, #0B7FC7); }
.dup-card__name { font-size: 12px; color: var(--ink-2); margin-bottom: 6px; line-height: 1.4; }
/* Per-member closest-match indicator: a prominent coloured pill (the % + verdict,
   never truncated) plus the peer id. Wraps rather than clipping. */
.dup-card__sim { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 1px 0 8px; cursor: help; }
.dup-card__sim-vs { color: var(--ink-2); font-size: 11.5px; white-space: normal; min-width: 0; }
.dup-card__sim-vs strong { font-weight: 700; }
.dup-card__row { display: flex; justify-content: space-between; gap: 8px; font-size: 11px; padding: 1.5px 0; }
.dup-card__row .k { color: var(--ink-3); flex-shrink: 0; }
.dup-card__row .v { color: var(--ink); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dup-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 4px 16px 14px; }
.dup-rename-panel {
  margin: 0 16px 14px; padding: 12px; border-radius: 10px;
  border: 1px solid var(--ai-border, rgba(99,102,241,.4));
  background: var(--ai-bg, rgba(99,102,241,.08));
}
.dup-rename-panel__hint { font-size: 11px; color: var(--ink-3); margin: 0 0 8px; }
.dup-rename-panel label { display: flex; align-items: center; gap: 8px; font-size: 12px; margin-bottom: 8px; color: var(--ink-2); }
.dup-rename-panel label .mono { flex-shrink: 0; min-width: 70px; }
.dup-rename-panel input[type=text] {
  flex: 1; padding: 6px 10px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--surface); color: var(--ink); font-size: 12.5px;
}
.dup-decided { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 16px 14px; font-size: 12.5px; color: var(--ink-2); }
/* Per-item (subset/mixed) resolution panel — reuses the dup-rename-panel framing. */
.dup-peritem-panel { margin: 0 16px 14px; padding: 12px; border-radius: 10px; border: 1px solid var(--ai-border, rgba(99,102,241,.4)); background: var(--ai-bg, rgba(99,102,241,.08)); }
.dup-peritem-row { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.dup-peritem-lbl { flex: 1; min-width: 0; font-size: 12px; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dup-peritem-sel { flex-shrink: 0; padding: 4px 8px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-size: 12px; }
.dup-peritem-vname { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ink-2); margin: 8px 0; }
.dup-peritem-vname input { flex: 1; padding: 6px 10px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-size: 12.5px; }

/* ── Inline fix expander (Phase 5, part detail) — the skeleton's fix-form
   pattern: a bordered soft-AI-blue panel that opens directly under the field
   row it edits. Canonical inline-expander look (same family as
   .dup-rename-panel), replacing the old fix modal. */
.fix-form {
  margin: 4px 12px 10px 24px; padding: 12px; border-radius: 10px;
  border: 1px solid var(--ai-border, rgba(99,102,241,.4));
  background: var(--ai-bg, rgba(99,102,241,.08));
}
.fix-form__issue { font-size: 12px; margin: 0 0 10px; line-height: 1.5; }
.fix-form__issue--red    { color: var(--bad); }
.fix-form__issue--yellow { color: var(--warn); }
.fix-form__block { margin-bottom: 12px; }
.fix-form__block:last-child { margin-bottom: 0; }
.fix-form__label {
  display: block; font-size: 10.5px; font-weight: 600; color: var(--ink-3);
  letter-spacing: .04em; text-transform: uppercase; margin-bottom: 6px;
}
.fix-form__ai { display: flex; align-items: flex-start; gap: 8px; flex-wrap: wrap; }
.fix-form__ai-reason { flex: 1 1 100%; font-size: 12px; color: var(--ink-2); line-height: 1.55; margin: 2px 0 6px; }
.fix-form__actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fix-form__input {
  flex: 1; min-width: 160px; padding: 6px 10px; border-radius: 6px;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--ink); font-size: 12.5px; box-sizing: border-box;
}
.fix-form__input:focus { outline: none; border-color: var(--accent); }
.fix-form__cands { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.fix-form__cand {
  font-size: 11.5px; padding: 3px 9px; border-radius: 5px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--ink-2);
}
.fix-form__cand:hover { border-color: var(--accent); color: var(--ink); background: var(--surface-3); }
.fix-form__foot {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--ai-border, rgba(99,102,241,.25));
}
.fix-form__rule-link { font-size: 12px; color: var(--accent); text-decoration: none; }
.fix-form__rule-link:hover { text-decoration: underline; }
.fix-form__divider { display: flex; align-items: center; gap: 10px; margin: 10px 0; }
.fix-form__divider span { font-family: var(--mono); font-size: 10px; color: var(--ink-3); white-space: nowrap; }
.fix-form__divider::before, .fix-form__divider::after { content: ''; flex: 1; height: 1px; background: var(--ai-border, rgba(99,102,241,.25)); }
.select {
  appearance: none; -webkit-appearance: none;
  font-family: var(--sans); font-size: 12.5px; color: var(--ink);
  background: var(--surface)
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237B8A98' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E")
    no-repeat right 8px center / 12px;
  border: 1px solid var(--border-strong); border-radius: var(--r);
  padding: 6px 26px 6px 10px; cursor: pointer; max-width: 100%;
}
.select:hover { border-color: var(--ink-3); }
.select:focus { outline: 2px solid var(--accent-bg); border-color: var(--accent); }
.select--sm { font-size: 11.5px; padding: 3px 22px 3px 8px; background-size: 10px; background-position: right 6px center; }

/* ── Taxonomy generation modal (Phase 4, shared In2.openTaxonomyGenerateModal) —
   the three source BUTTON-CARDS (published standard · own scheme · AI proposes).
   The whole card is the button (no visible radio): hover = accent border +
   lift/shadow; selected = accent border + soft bg + a small ✓ in the corner. ── */
.tax-src-cards { display: flex; gap: 8px; margin: 10px 0 4px; }
.tax-src-card {
  position: relative; flex: 1; display: flex; flex-direction: column; gap: 3px;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface-2); cursor: pointer;
  font: inherit; text-align: left; color: inherit;
  transition: border-color .12s, background .12s, box-shadow .12s, transform .12s;
}
.tax-src-card:hover { border-color: var(--accent); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.tax-src-card:focus-visible { outline: 2px solid var(--accent-bg); border-color: var(--accent); }
.tax-src-card.is-sel { border-color: var(--accent); background: var(--accent-bg); }
.tax-src-card.is-disabled { opacity: .5; cursor: not-allowed; }
.tax-src-card.is-disabled:hover { border-color: var(--border); box-shadow: none; transform: none; }
.tax-src-card__check {
  position: absolute; top: 6px; right: 6px; width: 15px; height: 15px;
  border-radius: 50%; background: var(--accent); color: #fff;
  display: none; align-items: center; justify-content: center;
}
.tax-src-card.is-sel .tax-src-card__check { display: inline-flex; }
.tax-src-card__title { font-weight: 600; font-size: 12.5px; color: var(--ink); }
.tax-src-card__hint { font-size: 11px; color: var(--ink-3); line-height: 1.45; }

/* ── Floating bulk-action bar (shared component — rendered by In2.bulkBar) —
   "N selected · ✓ Confirm · Clear" pinned bottom-centre while a checkbox
   selection exists anywhere on the page (the skeleton's bottom panel).
   Dark rail surface (#122231, same as .rail) so it reads as chrome, not
   content; actions are the existing .btn classes that already work on dark
   (.btn--hero-secondary chips, solid .btn--approve). Sits above page content
   but below modal overlays (z-index 1000+). ── */
.bulk-bar {
  position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%);
  z-index: 80; display: flex; align-items: center; gap: 10px;
  padding: 9px 14px 9px 18px;
  background: #122231; color: rgba(255,255,255,.92);
  border: 1px solid rgba(255,255,255,.08); border-radius: 12px;
  box-shadow: var(--shadow-md); font-size: 12.5px; white-space: nowrap;
}
.bulk-bar__count { font-weight: 700; font-family: var(--mono); font-size: 12px; }
.bulk-bar__sep { color: rgba(255,255,255,.28); }
.bulk-bar .btn--approve { display: inline-flex; align-items: center; gap: 5px; }

/* ── Accessibility: respect user motion preferences ────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
