/* ==========================================================================
   Buffer IQ — design system
   Ported by hand from the Stitch export (stitch_buffer_iq_design_system).
   No Tailwind, no CDN, no build step: Dash serves dashboard/assets/ directly.

   Load order matters — Dash serves assets alphabetically, so this file
   (tokens + components) is followed by dash_overrides.css (third-party widget
   restyling). Keep that ordering if you rename either file.
   ========================================================================== */

/* ── Tokens ─────────────────────────────────────────────────────────────── */
:root {
  /* Brand. Company red. Used for identity, active nav, links, accents and the
     primary chart series — never on its own as a status signal, because this
     app also has to say "stockout" and "blocked" in red. */
  --brand:            #c0392b;
  --brand-strong:     #a5301f;
  --brand-soft:       #e9705f;
  --brand-wash:       #fdeceb;
  --brand-wash-2:     #f9dedb;

  /* Neutrals (from DESIGN.md's Material tonal set) */
  --canvas:           #ecf1fd;  /* page background */
  --surface:          #ffffff;  /* cards */
  --surface-low:      #f0f3ff;  /* inset panels, table rows */
  --surface-mid:      #eaeefa;  /* table headers, quiet fills */
  --surface-high:     #e4e8f4;
  --surface-top:      #f9f9ff;  /* top bar */
  --line:             #dee2ee;  /* borders */
  --line-soft:        #eef1f9;  /* row separators */
  --outline:          #727785;  /* icon grey */
  --outline-variant:  #c2c6d6;  /* input borders, dashed edges */
  --ink:              #171c24;  /* headings */
  --ink-variant:      #424754;  /* body */
  --ink-muted:        #727785;  /* captions only — never data */

  /* Dark rail */
  --rail:             #181d27;
  --rail-2:           #21273350;
  --rail-text:        #c2c6d4;
  --rail-line:        #ffffff1a;

  /* Status. Deliberately distinct from --brand: danger is a deeper crimson and
     ALWAYS appears with a wash + icon + text label, never as bare red text, so
     it cannot be confused with brand red. */
  --success:          #0f7a54;
  --success-wash:     #d7f2e5;
  --warn:             #953800;
  --warn-wash:        #ffdbcd;
  --danger:           #ba1a1a;
  --danger-wash:      #ffdad6;
  --info:             #0052b1;
  --info-wash:        #dbe6ff;

  /* Chart series — matches the Stitch export: brand red, slate, burnt orange. */
  --series-1:         #c0392b;
  --series-2:         #595e6a;
  --series-3:         #bc4902;
  --series-4:         #0052b1;
  --series-5:         #7d2d00;

  /* Type */
  --font: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;

  /* Shape */
  --r-card:  32px;
  --r-panel: 24px;
  --r-md:    16px;
  --r-sm:    8px;
  --r-pill:  9999px;

  /* Space */
  --gutter: 24px;
  --pad-card: 32px;
  --pad-card-lg: 40px;
  --max-width: 1440px;
  --rail-w: 256px;
  --topbar-h: 64px;

  /* The only shadow in the system. Buttons only — never cards. */
  --shadow-btn: 0 1px 2px rgba(10, 13, 18, 0.8);
}

/* ── Reset / base ───────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-osx-font-smoothing: grayscale;
}

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-strong); text-decoration: underline; text-underline-offset: 2px; }

::selection { background: var(--brand-wash-2); color: var(--ink); }

/* Numbers must align in columns — non-negotiable in a stock-sizing tool. */
.biq-num, .biq-stat__value, td, .dash-cell div { font-variant-numeric: tabular-nums; }

/* Scrollbars */
.biq-scroll::-webkit-scrollbar,
.dash-table-container .dash-spreadsheet-container::-webkit-scrollbar { width: 8px; height: 8px; }
.biq-scroll::-webkit-scrollbar-track,
.dash-table-container .dash-spreadsheet-container::-webkit-scrollbar-track { background: transparent; }
.biq-scroll::-webkit-scrollbar-thumb,
.dash-table-container .dash-spreadsheet-container::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: var(--r-pill);
}
.biq-scroll::-webkit-scrollbar-thumb:hover,
.dash-table-container .dash-spreadsheet-container::-webkit-scrollbar-thumb:hover { background: var(--outline-variant); }

/* Material Symbols */
.msi {
  font-family: 'Material Symbols Outlined';
  font-weight: normal; font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  -webkit-font-feature-settings: 'liga';
  -webkit-font-smoothing: antialiased;
  font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
  /* A square the size of the glyph, and clipped.

     These are ligature icons: the markup literally contains the word
     "upload_file". icon_font_guard.js hides them when the font cannot load,
     but `visibility: hidden` hides ink and keeps the box — so on a deployment
     that cannot reach fonts.googleapis.com every icon still occupied the width
     of its own name, which is ~66px for a 20px glyph. That overflowed the
     collapsed rail and put the page into horizontal scroll while showing
     nothing at all to explain why. Pinning the box makes the layout identical
     whether or not the font ever arrives. */
  width: 1em; height: 1em; overflow: hidden; flex: none;
  text-align: center;
  vertical-align: middle;
  user-select: none;
}
/* Ligature icons render their own name as text before the font resolves.
   icon_font_guard.js stamps one of these classes on <html> once it knows
   whether the font is usable; until then icons occupy space but stay blank. */
html:not(.icons-ready) .msi { visibility: hidden; }
html.icons-unavailable .msi { visibility: hidden; }

.msi--fill { font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
.msi--16 { font-size: 16px; }
.msi--18 { font-size: 18px; }
.msi--20 { font-size: 20px; }
.msi--24 { font-size: 24px; }
.msi--40 { font-size: 40px; }

/* ── Type scale ─────────────────────────────────────────────────────────── */
.biq-h1 { font-size: 32px; font-weight: 500; line-height: 1.2; letter-spacing: -0.02em; color: var(--ink); margin: 0; }
.biq-h2 { font-size: 24px; font-weight: 500; line-height: 1.3; letter-spacing: -0.02em; color: var(--ink); margin: 0; }
.biq-h3 { font-size: 20px; font-weight: 500; line-height: 1.4; letter-spacing: -0.02em; color: var(--ink); margin: 0; }
.biq-body { font-size: 16px; font-weight: 500; line-height: 1.6; }
.biq-body-sm { font-size: 14px; font-weight: 500; line-height: 1.5; color: var(--ink-variant); }
.biq-caps {
  font-size: 11px; font-weight: 500; line-height: 1.2;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-variant);
}
.biq-muted { color: var(--ink-muted); }
.biq-mono { font-family: var(--font-mono); font-size: 13px; }

/* ── Shell: rail + main ─────────────────────────────────────────────────── */
.biq-rail {
  position: fixed; left: 0; top: 0; z-index: 50;
  width: var(--rail-w); height: 100%;
  background: var(--rail); color: #fff;
  display: flex; flex-direction: column;
  padding: 24px 0;
  overflow-y: auto;
}
.biq-rail__brand { display: flex; align-items: center; gap: 12px; padding: 0 24px 24px; }
.biq-rail__mark {
  width: 36px; height: 36px; border-radius: 10px; flex: none;
  background: var(--brand); color: #fff;
  display: flex; align-items: center; justify-content: center;
}
/* "Inventory Planning Agent" wraps to two lines in the rail's ~160px of text
   column. Sized to fit that rather than to fill it. */
.biq-rail__name { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.25; }
.biq-rail__ver { font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--rail-text); opacity: .8; margin-top: 3px; }

.biq-rail__status {
  margin: 0 16px 16px; padding: 10px 16px;
  border-radius: var(--r-pill);
  background: var(--brand); color: #fff;
  font-size: 14px; font-weight: 500;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  box-shadow: var(--shadow-btn);
  border: 1px solid var(--rail);
}
.biq-rail__status--idle { background: #2a313d; color: var(--rail-text); box-shadow: none; }
.biq-rail__dot { width: 8px; height: 8px; border-radius: 50%; background: #fff; flex: none; }

.biq-rail__nav { list-style: none; margin: 0; padding: 0; flex: 1; }
.biq-rail__nav li { margin: 2px 8px; }
.biq-nav-link {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-radius: 12px;
  color: var(--rail-text); font-size: 14px; font-weight: 500;
  transition: background .15s ease, color .15s ease;
}
.biq-nav-link:hover { background: #ffffff14; color: #fff; text-decoration: none; }
.biq-nav-link--active { background: var(--brand); color: #fff; }
.biq-nav-link--active:hover { background: var(--brand); color: #fff; }

/* Rail sub-navigation — the section you are inside expands its children.
   The parent stays legible but unhighlighted so only one row reads as active;
   the rule on the left is what carries the "these belong to Master" grouping,
   because indentation alone is too weak against a dark rail. */
.biq-nav-link--section { color: #fff; }
.biq-rail__subnav-wrap { margin: 0 8px 4px !important; }
.biq-rail__subnav {
  list-style: none; margin: 2px 0 0; padding: 0 0 0 18px;
  border-left: 1px solid #ffffff26; margin-left: 18px;
}
.biq-rail__subnav li { margin: 2px 0; }
.biq-nav-link--sub {
  font-size: 13px; padding: 8px 10px; gap: 8px;
}
/* Collapsed rail: the labels are hidden, so an indented icon-only list would
   be unreadable. Show the children inline with their parent instead. */
@media (max-width: 1100px) {
  .biq-rail__subnav { padding-left: 0; margin-left: 0; border-left: none; }
  .biq-nav-link--sub { justify-content: center; padding: 10px 0; }
}

.biq-rail__foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--rail-line); }
.biq-rail__engines { padding: 4px 24px 12px; }
.biq-rail__engines-label { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: #6b7280; }
.biq-rail__engines-list { font-size: 12px; color: var(--rail-text); line-height: 1.5; margin-top: 4px; }

/* Main column */
.biq-main { margin-left: var(--rail-w); min-height: 100vh; display: flex; flex-direction: column; }

/* Three parts in normal flow — brand, stepper, account.

   They used to be a centred stepper with the brand and the account block
   absolutely positioned either side. Absolute elements reserve no space, so
   the stepper was centred in the whole bar and simply ran underneath the
   account block as soon as the two wanted the same pixels: at 1280px the word
   "Validate" printed through "Rohan Chauhan". Laying all three out in flow is
   what makes that impossible rather than merely unlikely. */
.biq-topbar {
  position: sticky; top: 0; z-index: 40;
  height: var(--topbar-h); width: 100%;
  background: var(--surface-top);
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  padding: 0 var(--gutter);
}
.biq-topbar__brand {
  flex: 0 0 auto;
  font-size: 24px; font-weight: 500; letter-spacing: -0.02em; color: var(--ink);
  display: flex; align-items: center;
}
/* The logo is ~3:1; height-constrained so the bar's 64px never changes.
   38px is the smallest height at which the "powered by Moglix Analytics"
   strapline is still legible — below that it renders as a grey smear. */
.biq-topbar__logo { height: 38px; width: auto; display: block; }
/* Never shrinks: the role chip and the sign-out control are the two things on
   this bar you must always be able to reach. The name gives way instead. */
.biq-topbar__right {
  flex: 0 0 auto; display: flex; align-items: center; gap: 16px; min-width: 0;
}
.biq-topbar__right .biq-body-sm {
  max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.biq-icon-btn {
  background: none; border: none; cursor: pointer; padding: 4px;
  color: var(--ink-variant); border-radius: var(--r-pill);
  display: flex; align-items: center; transition: color .15s ease;
}
.biq-icon-btn:hover { color: var(--brand); }

/* Stepper (lives in the top bar) */
/* Takes the middle and centres its own content, so "centred" now means
   centred between the brand and the account block rather than centred in the
   bar regardless of them. It scrolls rather than overlapping when even that is
   not enough — a stepper you can nudge sideways beats one printed on top of
   somebody's name. */
.biq-steps {
  display: flex; align-items: center; justify-content: center; gap: 4px;
  flex: 1 1 auto; min-width: 0; overflow-x: auto;
  scrollbar-width: none; -ms-overflow-style: none;
}
.biq-steps::-webkit-scrollbar { display: none; }
.biq-step {
  display: flex; align-items: center; gap: 8px; flex: none;
  padding: 4px 12px 6px;
  font-size: 14px; font-weight: 500; color: var(--ink-variant);
  border-bottom: 2px solid transparent;
  transition: color .15s ease;
}
.biq-step:hover { color: var(--brand); text-decoration: none; }
.biq-step__num {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 600;
  border: 1px solid var(--outline-variant); color: var(--ink-variant);
}
.biq-step--done .biq-step__num { background: var(--success-wash); border-color: var(--success-wash); color: var(--success); }
.biq-step--active { color: var(--brand); border-bottom-color: var(--brand); }
.biq-step--active .biq-step__num { background: var(--brand); border-color: var(--brand); color: #fff; }
.biq-step__sep { width: 24px; height: 1px; background: var(--line); flex: none; }

/* Content canvas */
.biq-content {
  flex: 1; width: 100%;
  max-width: var(--max-width); margin: 0 auto;
  padding: 32px;
  display: flex; flex-direction: column; gap: var(--gutter);
}
.biq-page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.biq-page-head > :first-child { min-width: 0; }
.biq-page-head__sub { font-size: 14px; color: var(--ink-variant); margin-top: 8px; }

/* ── Grid ───────────────────────────────────────────────────────────────── */
/* Every track is minmax(0, Nfr), never a bare Nfr. A bare `7fr` means
   `minmax(auto, 7fr)`, and `auto` there is min-content — so a column holding a
   wide table (ours are `white-space: nowrap`) refuses to shrink below its full
   width and eats the neighbouring column instead of scrolling. That is how the
   Validation and Upload map panels collapsed to ~11% and truncated their
   labels to "Pla..." while `.biq-table-wrap`'s own `overflow: auto` sat unused.
   The `minmax(0, ...)` floor lets the track shrink to its share and hands the
   overflow back to the scroll container that was built for it. */
.biq-grid { display: grid; gap: var(--gutter); }
.biq-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.biq-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.biq-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.biq-grid--5-7 { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
.biq-grid--7-5 { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
.biq-grid--4-3-5 { grid-template-columns: minmax(0, 4fr) minmax(0, 3fr) minmax(0, 5fr); }

/* ── Card ───────────────────────────────────────────────────────────────── */
.biq-card {
  background: var(--surface);
  border-radius: var(--r-card);
  padding: var(--pad-card);
  /* No border, no shadow — depth is the canvas→surface tonal shift. */
}
.biq-card--flush { padding: var(--pad-card) 0; }
.biq-card--accent { border-left: 4px solid var(--brand); }
.biq-card__hd {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding-bottom: 16px; margin-bottom: 24px;
  border-bottom: 1px solid var(--line);
}
.biq-card__hd--plain { border-bottom: none; padding-bottom: 0; margin-bottom: 20px; }
.biq-card__title { display: flex; align-items: center; gap: 10px; font-size: 20px; font-weight: 500; letter-spacing: -0.02em; color: var(--ink); }
.biq-card__title .msi { color: var(--brand); }
.biq-card__sub { font-size: 14px; color: var(--ink-variant); margin-top: 6px; font-weight: 500; }

/* ── Stat tile ──────────────────────────────────────────────────────────── */
.biq-stat { background: var(--surface); border-radius: var(--r-panel); padding: 24px; }
.biq-stat__top { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.biq-stat__icon {
  width: 40px; height: 40px; border-radius: 12px; flex: none;
  display: flex; align-items: center; justify-content: center;
}
.biq-stat__value { font-size: 36px; font-weight: 500; letter-spacing: -0.02em; line-height: 1.1; color: var(--ink); }
.biq-stat__sub { font-size: 14px; color: var(--ink-variant); margin-top: 8px; }

/* Icon-plate tints */
.tint-brand   { background: var(--brand-wash);   color: var(--brand); }
.tint-warn    { background: var(--warn-wash);    color: var(--warn); }
.tint-success { background: var(--success-wash); color: var(--success); }
.tint-info    { background: var(--info-wash);    color: var(--info); }
.tint-neutral { background: var(--surface-mid);  color: var(--ink-variant); }

/* ── Buttons ────────────────────────────────────────────────────────────── */
.biq-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font); font-size: 16px; font-weight: 500;
  padding: 12px 32px; border-radius: var(--r-pill);
  border: 1px solid transparent; cursor: pointer;
  transition: opacity .15s ease, background .15s ease, color .15s ease;
  white-space: nowrap;
}
.biq-btn--primary {
  background: var(--rail); color: #fff; border-color: var(--rail);
  box-shadow: var(--shadow-btn);
}
.biq-btn--primary:hover { opacity: .9; }
.biq-btn--outline { background: transparent; color: var(--brand); border-color: var(--brand); }
.biq-btn--outline:hover { background: var(--brand-wash); }
.biq-btn--ghost { background: var(--surface); color: var(--ink-variant); border-color: var(--line); }
.biq-btn--ghost:hover { background: var(--surface-low); border-color: var(--outline-variant); }
.biq-btn--sm { font-size: 14px; padding: 8px 20px; }
.biq-btn:disabled, .biq-btn[disabled] { opacity: .4; cursor: not-allowed; box-shadow: none; }
.biq-btn-row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }

/* ── Inputs ─────────────────────────────────────────────────────────────── */
.biq-field { display: block; }
.biq-field__label { display: block; margin-bottom: 8px; }
.biq-input {
  width: 100%; background: var(--surface);
  border: 1px solid var(--outline-variant); border-radius: var(--r-pill);
  padding: 10px 16px;
  font-family: var(--font); font-size: 14px; font-weight: 500; color: var(--ink);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.biq-input--boxed { border-radius: var(--r-md); }
.biq-input:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-wash);
}
.biq-input::placeholder { color: var(--ink-muted); font-weight: 500; }
.biq-input--invalid { border-color: var(--danger); }

.biq-input-wrap { position: relative; }
.biq-input-wrap .msi { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--outline); pointer-events: none; }
.biq-input-wrap .biq-input { padding-left: 40px; }

/* Native checkbox / radio accent */
input[type="checkbox"], input[type="radio"] { accent-color: var(--brand); width: 16px; height: 16px; cursor: pointer; }

/* Dropzone */
.biq-drop {
  border: 2px dashed var(--outline-variant); border-radius: var(--r-md);
  background: var(--surface-low);
  padding: 40px 24px; min-height: 160px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.biq-drop:hover { border-color: var(--brand); background: var(--brand-wash); }
.biq-drop__icon {
  width: 56px; height: 56px; border-radius: var(--r-pill);
  background: var(--brand-wash); color: var(--brand);
  display: flex; align-items: center; justify-content: center; margin-bottom: 16px;
}
.biq-drop__title { font-size: 16px; font-weight: 500; color: var(--ink); }
.biq-drop__hint { font-size: 14px; color: var(--ink-variant); margin-top: 4px; max-width: 60ch; }

/* ── Chips ──────────────────────────────────────────────────────────────── */
.biq-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px; border-radius: var(--r-pill);
  font-size: 11px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase;
  background: var(--surface-mid); color: var(--ink-variant);
  white-space: nowrap;
}
.biq-chip--brand   { background: var(--brand-wash);   color: var(--brand); }
.biq-chip--success { background: var(--success-wash); color: var(--success); }
.biq-chip--warn    { background: var(--warn-wash);    color: var(--warn); }
.biq-chip--danger  { background: var(--danger-wash);  color: var(--danger); }
.biq-chip--info    { background: var(--info-wash);    color: var(--info); }
.biq-chip--plain   { text-transform: none; letter-spacing: 0; font-size: 13px; }

/* Tab strip (pill group) */
.biq-tabs { display: inline-flex; padding: 4px; background: var(--surface-low); border-radius: var(--r-pill); gap: 4px; }
.biq-tab {
  padding: 6px 18px; border-radius: var(--r-pill); border: none; cursor: pointer;
  background: transparent; color: var(--ink-variant);
  font-family: var(--font); font-size: 14px; font-weight: 500;
  transition: background .15s ease, color .15s ease;
}
.biq-tab:hover { color: var(--ink); }
.biq-tab--active { background: var(--surface); color: var(--brand); }

/* ── Alerts ─────────────────────────────────────────────────────────────── */
.biq-alert {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 16px 20px; border-radius: var(--r-md);
  border-left: 4px solid var(--info);
  background: var(--info-wash); color: var(--ink);
  font-size: 14px; font-weight: 500;
}
.biq-alert__icon { flex: none; color: var(--info); }
.biq-alert__title { font-weight: 600; color: var(--ink); }
.biq-alert__body { color: var(--ink-variant); margin-top: 4px; }
.biq-alert--success { background: var(--success-wash); border-left-color: var(--success); }
.biq-alert--success .biq-alert__icon { color: var(--success); }
.biq-alert--warn { background: var(--warn-wash); border-left-color: var(--warn); }
.biq-alert--warn .biq-alert__icon { color: var(--warn); }
.biq-alert--danger { background: var(--danger-wash); border-left-color: var(--danger); }
.biq-alert--danger .biq-alert__icon { color: var(--danger); }

/* ── Mapping rows (Upload & Map) ────────────────────────────────────────── */
.biq-maprow {
  /* Same reason as .biq-grid above: the dropdown track must be allowed to
     shrink to its share. Its min-content is the longest option label — a
     header like "WH UMC (W/O MUMBAI)" — which would otherwise push the row
     wider than the card and squeeze the name column into an ellipsis. */
  display: grid; grid-template-columns: minmax(0, 4fr) auto minmax(0, 5fr) minmax(0, 2fr);
  gap: 16px; align-items: center;
  padding: 10px 16px; border-radius: var(--r-md);
  background: var(--surface-low);
  border: 1px solid transparent;
  transition: border-color .15s ease;
}
.biq-maprow:hover { border-color: var(--outline-variant); }
.biq-maprow__head {
  /* Must match .biq-maprow exactly or the header labels drift off their
     columns. */
  display: grid; grid-template-columns: minmax(0, 4fr) auto minmax(0, 5fr) minmax(0, 2fr);
  gap: 16px; padding: 4px 16px 8px;
}
.biq-maprow__name { font-size: 14px; font-weight: 500; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.biq-maprow__arrow { color: var(--outline-variant); display: flex; justify-content: center; }
.biq-maprow__status { display: flex; align-items: center; justify-content: flex-end; gap: 6px; }
.biq-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--outline-variant); }
.biq-dot--on { background: var(--success); }
.biq-dot--off { background: var(--outline-variant); }
.biq-req { color: var(--danger); margin-left: 2px; }

/* ── Key/value rows ─────────────────────────────────────────────────────── */
.biq-kv {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 10px 0; border-bottom: 1px solid var(--line-soft);
  font-size: 14px;
}
.biq-kv:last-child { border-bottom: none; }
.biq-kv__k { color: var(--ink-variant); }
.biq-kv__v { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }

/* ── Config parameter rows ──────────────────────────────────────────────── */
.biq-param {
  display: grid; grid-template-columns: 1fr auto 140px;
  gap: 16px; align-items: center;
  padding: 16px; border-radius: var(--r-md);
  background: var(--surface-low); margin-bottom: 12px;
}
.biq-param__label { display: flex; align-items: center; gap: 10px; font-size: 16px; font-weight: 500; color: var(--ink); flex-wrap: wrap; }
.biq-param__desc { font-size: 13px; color: var(--ink-variant); margin-top: 4px; font-weight: 500; }
.biq-param__default { font-size: 13px; color: var(--ink-muted); white-space: nowrap; }

/* Formula blocks */
.biq-formula { margin-bottom: 20px; }
.biq-formula__name { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-variant); margin-bottom: 8px; }
.biq-formula__code {
  font-family: var(--font-mono); font-size: 13px; color: var(--ink);
  background: var(--surface-mid); border-radius: var(--r-sm);
  padding: 12px 16px; overflow-x: auto; white-space: pre;
}
.biq-formula__note { font-size: 13px; color: var(--ink-variant); margin-top: 8px; }

/* ── Run-type radio cards (Train) ───────────────────────────────────────── */
.biq-radiocards { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.biq-radiocard {
  border: 1px solid var(--line); border-radius: var(--r-panel);
  padding: 20px; cursor: pointer; background: var(--surface);
  transition: border-color .15s ease, background .15s ease;
}
.biq-radiocard:hover { border-color: var(--outline-variant); }
.biq-radiocard--on { border-color: var(--brand); background: var(--brand-wash); }
.biq-radiocard__top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.biq-radiocard__title { font-size: 16px; font-weight: 600; color: var(--ink); }
.biq-radiocard__desc { font-size: 13px; color: var(--ink-variant); line-height: 1.5; margin-top: 6px; }

/* Model checklist rows */
.biq-modelrow { padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
.biq-modelrow:last-child { border-bottom: none; }
.biq-modelrow__name { font-size: 16px; font-weight: 500; color: var(--ink); }
.biq-modelrow__meta { font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-muted); margin-left: 26px; }

/* ── Plain HTML tables (previews) ───────────────────────────────────────── */
.biq-table-wrap {
  border: 1px solid var(--line); border-radius: var(--r-md);
  overflow: auto; max-height: 420px;
}
table.biq-table { width: 100%; border-collapse: collapse; white-space: nowrap; }
table.biq-table thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface-top);
  font-size: 11px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-variant); text-align: left;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
}
table.biq-table tbody td {
  padding: 10px 16px; font-size: 14px; font-weight: 500; color: var(--ink);
  border-bottom: 1px solid var(--line-soft);
}
table.biq-table tbody tr:nth-child(even) { background: #f6f7f8; }
table.biq-table tbody tr:hover { background: var(--surface-low); }

/* ── OTIF / progress meters ─────────────────────────────────────────────── */
.biq-meter { height: 6px; border-radius: var(--r-pill); background: var(--surface-high); overflow: hidden; }
.biq-meter__fill { height: 100%; border-radius: var(--r-pill); background: var(--brand); }
.biq-bigpct { font-size: 40px; font-weight: 500; letter-spacing: -0.02em; line-height: 1.1; color: var(--ink); }

/* ── Empty / loading states ─────────────────────────────────────────────── */
.biq-empty { text-align: center; padding: 64px 24px; }
.biq-empty__art {
  width: 96px; height: 96px; margin: 0 auto 24px;
  border-radius: var(--r-panel);
  background: var(--surface-low); color: var(--outline-variant);
  display: flex; align-items: center; justify-content: center;
}
.biq-empty__title { font-size: 24px; font-weight: 500; letter-spacing: -0.02em; color: var(--ink); }
.biq-empty__body { font-size: 16px; color: var(--ink-variant); margin: 8px 0 24px; }

.biq-skeleton {
  background: linear-gradient(90deg, var(--surface-low) 25%, var(--surface-mid) 37%, var(--surface-low) 63%);
  background-size: 400% 100%;
  animation: biq-shimmer 1.4s ease infinite;
  border-radius: var(--r-md);
}
@keyframes biq-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ── Login ──────────────────────────────────────────────────────────────── */
.biq-login { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 32px; background: var(--canvas); }
.biq-login__card { width: 100%; max-width: 400px; background: var(--surface); border-radius: var(--r-card); padding: var(--pad-card-lg); }
.biq-login__brand { display: flex; align-items: center; gap: 12px; margin-bottom: 32px; }
.biq-login__mark { width: 36px; height: 36px; border-radius: 50%; background: var(--brand); flex: none; }
.biq-login__logo {
  display: block; width: 260px; max-width: 100%; height: auto;
  margin: 0 auto 32px;
}
.biq-login__divider { display: flex; align-items: center; gap: 16px; margin: 24px 0; color: var(--ink-muted); font-size: 12px; }
.biq-login__divider::before, .biq-login__divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }

/* ── Utilities ──────────────────────────────────────────────────────────── */
.biq-stack   { display: flex; flex-direction: column; gap: var(--gutter); }
.biq-stack-8 { display: flex; flex-direction: column; gap: 8px; }
.biq-stack-16{ display: flex; flex-direction: column; gap: 16px; }
/* Wrapping, not overflowing. These hold buttons and chips, and a row of them
   that refuses to wrap pushes its last child past the edge of the card and
   puts the whole page into horizontal scroll. */
.biq-row     { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.biq-row--between { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.biq-right   { text-align: right; }
.biq-grow    { flex: 1; min-width: 0; }
.biq-mt-8  { margin-top: 8px; }  .biq-mt-16 { margin-top: 16px; }
.biq-mt-24 { margin-top: 24px; } .biq-mb-16 { margin-bottom: 16px; }
.biq-hide  { display: none !important; }

/* ── Spinner ────────────────────────────────────────────────────────────
   Inline, sized from the current font, and inheriting `currentColor` so it
   works on a primary button and on a plain surface without a second rule. */
.biq-spinner {
  display: inline-block; width: 1em; height: 1em; flex: none;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%;
  animation: biq-spin .6s linear infinite;
  vertical-align: -0.125em;
}
@keyframes biq-spin { to { transform: rotate(360deg); } }
/* A button mid-action is not a button you should be able to press again. */
.biq-btn[disabled] { opacity: .65; cursor: default; pointer-events: none; }

/* ── Running-job bar ────────────────────────────────────────────────────
   Fixed to the corner rather than in the page flow: it appears while you are
   mid-sentence on some other screen, and a bar that pushes the layout down
   moves whatever you were reading. */
.biq-jobbar {
  position: fixed; right: 24px; bottom: 24px; z-index: 60;
  max-width: 380px;
  border-radius: 14px; overflow: hidden;
  box-shadow: 0 8px 28px rgba(23, 28, 36, .18);
}

/* ── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 1400px) {
  .biq-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Tighten the stepper before anything has to be dropped or clipped. On a
     1280px laptop the five labelled steps and the account block were within
     about eighty pixels of fitting, and this is exactly that much. */
  .biq-step { padding: 4px 8px 6px; font-size: 13px; gap: 6px; }
  .biq-step__sep { width: 12px; }
  .biq-steps { gap: 2px; }
}
@media (max-width: 1200px) {
  .biq-grid--3, .biq-grid--5-7, .biq-grid--7-5, .biq-grid--4-3-5,
  .biq-grid--2 { grid-template-columns: minmax(0, 1fr); }
  .biq-radiocards { grid-template-columns: minmax(0, 1fr); }
  .biq-steps .biq-step__sep { display: none; }
}
@media (max-width: 1024px) {
  :root { --rail-w: 72px; --pad-card: 24px; }
  .biq-rail__name, .biq-rail__ver, .biq-rail__engines,
  .biq-nav-link span:not(.msi), .biq-rail__status span:not(.biq-rail__dot) { display: none; }
  .biq-rail__brand { justify-content: center; padding: 0 0 24px; }
  .biq-nav-link { justify-content: center; padding: 12px 0; }
  .biq-rail__status { margin: 0 12px 16px; padding: 10px; }
  .biq-topbar__brand { display: none; }
  .biq-step span:not(.biq-step__num) { display: none; }
  .biq-content { padding: 24px 16px; }
}

/* Below this the layout stops being a wide desktop one. Nothing existed here
   before, so a phone got the 1024px rules and then simply overflowed: the
   page heading and its action button sat on one un-wrapping row, so Export
   hung off the right edge and took the whole document into horizontal scroll
   with it. */
@media (max-width: 720px) {
  :root { --gutter: 16px; }
  /* The stepper is a duplicate of the rail, which is still there. On a screen
     this narrow it is the first thing that should give up its space. */
  .biq-steps { display: none; }
  .biq-topbar { justify-content: space-between; }
  .biq-topbar__right .biq-body-sm { max-width: 120px; }

  /* A heading and its actions stack rather than compete. */
  .biq-page-head { flex-direction: column; align-items: stretch; gap: 16px; }
  .biq-page-head .biq-row { flex-wrap: wrap; }

  .biq-grid--4, .biq-grid--5, .biq-grid--7 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .biq-content { padding: 20px 12px; }
  .biq-h1 { font-size: 28px; }

  /* The running-job bar is fixed to the corner; on a phone the corner is most
     of the screen, so it becomes a full-width strip along the bottom. */
  .biq-jobbar { left: 12px; right: 12px; bottom: 12px; max-width: none; }
}

@media (max-width: 520px) {
  :root { --rail-w: 56px; --pad-card: 16px; --pad-card-lg: 20px; }
  .biq-grid--4, .biq-grid--5, .biq-grid--7 { grid-template-columns: minmax(0, 1fr); }
  .biq-content { padding: 16px 10px; }
  .biq-h1 { font-size: 24px; }
  .biq-login { padding: 16px; }
  .biq-topbar__right { gap: 10px; }
  .biq-topbar__right .biq-body-sm { display: none; }  /* the role chip still says who you are */
}

/* ── Confirmation dialog ────────────────────────────────────────────────
   Rendered by a callback into #confirm-modal and hidden with the `hidden`
   attribute, so there is no display:none to fight and no CSS-only state to
   get out of step with the store that drives it.

   Fixed-position overlay above the rail (z-index beats .biq-rail's), centred,
   with the card capped so a long list of changes scrolls instead of pushing
   the buttons off-screen. */
#confirm-modal[hidden] { display: none !important; }
#confirm-modal {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  background: #171c2466; padding: 24px;
}
.biq-modal__card {
  background: var(--surface); border-radius: var(--r-card);
  padding: 28px; width: min(560px, 100%);
  max-height: 80vh; overflow-y: auto;
  box-shadow: 0 24px 64px #171c2440;
}
.biq-modal__head { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.biq-modal__icon { color: var(--info); }
.biq-modal__icon--danger { color: var(--danger); }
.biq-modal__title { font-size: 20px; font-weight: 600; color: var(--ink); }
.biq-modal__lines {
  margin: 0 0 24px; padding-left: 22px;
  color: var(--ink-variant); font-size: 14px; line-height: 1.7;
}
.biq-modal__lines li { margin-bottom: 4px; }
/* The destructive path never relies on colour alone — the icon above and the
   button's own wording carry it too. */
.biq-modal__actions { display: flex; justify-content: flex-end; gap: 12px; }

/* ── Login: reveal toggle, and the divider above the SSO button ────────── */
/* The eye sits inside the field rather than beside it: beside it, the field
   stops looking like one control and the button reads as a second action. */
.biq-input-with-eye { position: relative; }
.biq-input-with-eye .biq-input { padding-right: 48px; width: 100%; }
.biq-input-eye {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  background: none; border: none; border-radius: var(--r-md);
  color: var(--ink-muted); cursor: pointer;
}
.biq-input-eye:hover { background: var(--surface-mid); color: var(--ink); }
.biq-input-eye:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

.biq-rule { flex: 1; height: 1px; background: var(--line); display: block; }
