/* ============================================================
   Portal-local overrides on top of the vendored design system.
   Keep this file thin. Anything that grows here is a candidate
   for upstream contribution back to the design system bundle.
   ============================================================ */

/* Shell-demo is built as a contained demo widget (min-height 560px,
   border, radius). For the real portal we want it to fill the
   viewport without a card frame. */
.shell-demo.shell-full {
  min-height: 100vh;
  border: 0;
  border-radius: 0;
}

/* Disabled nav placeholders for apps that aren't live yet (FIP,
   Repricer, Feedback in slice 1). Greyed out, no hover, no pointer. */
.shell-demo .s-subitem[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

/* Sub-items rendered as <a> for real navigation lose the browser-default
   underline; the design system base rule keeps colour but not text-decoration. */
.shell-demo a.s-subitem,
.shell-demo a.s-item { text-decoration: none; }

/* "Preview" hint badge for apps that aren't operational yet (Idealytics,
   DataOps). Quiet, low-emphasis rounded rectangle tuned for the always-dark
   sidebar — subtle white fill + muted light text, never the danger treatment.
   Right-aligns so it sits by the group chevron (.s-app) / at the row edge
   (.s-item), and hides with the labels when the sidebar collapses. */
.shell-demo .s-side .s-nav-badge {
  margin-left: auto;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  font-size: 10px;
  font-weight: var(--fw-medium);
  line-height: 14px;
  letter-spacing: 0.02em;
  color: #C4CCD9;
  background: rgba(255, 255, 255, 0.08);
  white-space: nowrap;
}
.shell-demo.collapsed .s-nav-badge { display: none; }

/* Centre the sub-section guide line under the parent icon column.
   Parent .s-item icon centre sits at x = nav-padding 8 + item-padding 10 + icon-half 8 = 26px.
   The design system default margin-left of 12px puts the guide at x=20 — shift to 18 so the
   1px border-left lands on x=26. */
.shell-demo .s-sub { margin-left: 18px; }

/* Sign-in centered-card layout. The design spec puts the card on
   the page background; we just center it vertically + horizontally
   and reserve a footer slot for legal links. */
.signin-page {
  min-height: 100vh;
  background: var(--app-bg);
  display: grid;
  grid-template-rows: 1fr auto;
  place-items: center;
  padding: 32px;
}
.signin-card {
  width: 380px;
  max-width: 100%;
  background: var(--app-bg-elev);
  border: 1px solid var(--app-border);
  border-radius: var(--radius-lg);
  padding: 32px;
}
.signin-card .brand-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 24px;
}
.signin-card .brand-row img {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-pill);
}
.signin-card .brand-row span {
  font-weight: var(--fw-bold);
  font-size: 14px;
  color: var(--app-fg);
}
.signin-card h1 {
  font-size: 24px;
  line-height: 1.1;
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
  margin: 0;
}
.signin-card .lead {
  font-size: 13px;
  line-height: 1.4;
  color: var(--app-fg-3);
  margin: 6px 0 24px;
}
.signin-card .legal {
  font-size: 11px;
  color: var(--app-fg-3);
  text-align: center;
  margin: 24px 0 0;
}
.signin-foot {
  font-size: 11px;
  color: var(--app-fg-3);
  text-align: center;
}

/* Back link rendered as the FIRST element of a detail page's body,
   above any sections. Replaces breadcrumbs — the portal does not use
   breadcrumb trails. Style is a quiet text+chevron link, distinct from
   surrounding content but not a button. */
.page-back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  line-height: 1;
  color: var(--app-fg-muted);
  text-decoration: none;
  margin: 0 0 16px;
  padding: 4px 6px 4px 0;
}
.page-back:hover { color: var(--app-fg-2); }
.page-back .ic { width: 13px; height: 13px; }

/* Section title sitting above a card (not inside .card-head). Sized
   to match the page-head H1 (20px / 28px / -0.015em) so each section
   reads as a first-class page section, not a card subhead. */
h1.section-title,
h2.section-title,
.section-title {
  font-size: 20px;
  line-height: 28px;
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
  color: var(--app-fg);
  margin: 0 0 8px;
}
.section-title + .card { margin-top: 0; }

/* The base .btn doesn't reset anchor underlines, so <a class="btn">
   inherits the browser default. Kill it here. */
a.btn { text-decoration: none; }

/* Busy state — stamped on the clicked submit button by app.js while the
   form round-trips, so slow actions (ClickUp pushes, bulk moves) show
   progress instead of a dead button. */
.btn.is-loading { pointer-events: none; opacity: 0.75; }
.btn.is-loading::after {
  content: "";
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: idx-spin 0.7s linear infinite;
}

/* Form layout utilities. The design system uses inline flex styles in
   its spec; portal templates use these named utilities so spacing is
   consistent across forms. */
.row { display: flex; align-items: flex-start; gap: 12px; }
.row.row-center { align-items: center; }
.row > .field { flex: 1; min-width: 0; }

/* Vertical rhythm inside a card form. Every direct child after the
   first gets 14px above. Use on the form or a wrapping div. */
.form-stack > * + * { margin-top: 14px; }

/* Switch + label paired horizontally for boolean settings (Active,
   Enabled, etc.). The .switch widget itself comes from the design
   system; this is just the inline-row layout. */
.switch-row {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--app-fg);
  cursor: pointer;
}
.switch-row:has(input:disabled) { cursor: not-allowed; opacity: 0.7; }

/* Grid of checkbox options for entity/brand multi-select. Native browser
   checkboxes here — the design system's .check is heavier and not worth
   the markup overhead at 10-20 options. */
.scope-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 8px 16px;
}
.scope-option {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--app-fg);
  cursor: pointer;
  user-select: none;
}
.scope-option input[type="checkbox"] {
  width: 14px;
  height: 14px;
  accent-color: var(--app-fg-accent);
  cursor: pointer;
}

/* Brand-toggle grid: a switch per brand, labelled to its right.
   Replaces the checkbox grid for app-access management — switches
   read as "this user can / cannot access this brand". */
.brand-toggle-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px 24px;
  margin-top: 4px;
}
.brand-toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--app-fg);
  cursor: pointer;
  user-select: none;
}

/* House rule: active pagination page uses a light tinted background
   instead of the upstream filled-navy. Reads more like a "selected
   chip" than a primary CTA. */
.pagination button.active {
  background: var(--app-bg-active);
  color: var(--app-fg);
  font-weight: var(--fw-medium);
}
:root[data-theme="dark"] .pagination button.active {
  background: rgba(255, 255, 255, 0.10);
  color: var(--app-fg);
}

/* Upstream .table-wrap uses overflow:hidden to clip the rounded corners,
   which also clips any popover anchored to a button in the toolbar.
   Switch to overflow:visible and round the toolbar/foot directly so the
   wrapper's curve still appears intact. */
.table-wrap { overflow: visible; }
.table-wrap > .table-toolbar:first-child {
  border-top-left-radius: calc(var(--radius-lg) - 1px);
  border-top-right-radius: calc(var(--radius-lg) - 1px);
}
.table-wrap > .table-foot:last-child {
  border-bottom-left-radius: calc(var(--radius-lg) - 1px);
  border-bottom-right-radius: calc(var(--radius-lg) - 1px);
}

/* Account-menu trigger in the page-head right side. Borderless pill —
   avatar + name + chevron. Clicking opens the account popover. */
.page-head-user {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}
.account-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 4px;
  background: transparent;
  border: 0;
  border-radius: var(--radius-pill);
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: var(--fw-medium);
  color: var(--app-fg);
  transition: background var(--t-fast);
}
.account-trigger:hover { background: var(--app-bg-hover); }
.account-trigger .avatar.sm { width: 28px; height: 28px; font-size: 11px; }
.account-trigger-chev {
  width: 14px;
  height: 14px;
  color: var(--app-fg-3);
  margin-left: 2px;
}
.account-menu { padding: 6px; }

/* Anchor for absolutely-positioned popovers. The design-system markup
   wraps the trigger + popover in <span class="popover-anchor">, but
   the bundle never styles it, so the popover's `position:absolute`
   would escape to the viewport. */
.popover-anchor {
  position: relative;
  display: inline-block;
}

/* Required-field marker. Pair with a .field-label as `<label>SKU
   <span class="required">*</span></label>`. */
.field-label .required {
  color: var(--app-danger, #dc3545);
  margin-left: 2px;
  font-weight: var(--fw-medium);
}

/* Numeric cell emphasis — used for the B2B discount % column. */
table.data .cell-emphasis {
  font-size: 12px;
  font-weight: var(--fw-medium);
  color: var(--app-fg-accent);
}

/* Table per-row checkbox column + per-row actions column. Tight widths
   so the data cells get the breathing room. Shared across Repricer + FIP. */
table.data .rep-col-check,
table.data .fip-col-check {
  width: 28px;
  min-width: 28px;
  max-width: 28px;
  padding-left: 10px;
  padding-right: 0;
}
/* `.dense` sets td padding via a higher-specificity selector that would
   otherwise clobber the tight checkbox column and clip the box — restore a
   snug-but-clear inset (and a little right room) for the dense variant. */
table.data.dense td.fip-col-check, table.data.dense th.fip-col-check,
table.data.dense td.rep-col-check, table.data.dense th.rep-col-check {
  padding-left: 8px;
  padding-right: 6px;
}
table.data .rep-col-check input[type="checkbox"],
table.data .fip-col-check input[type="checkbox"] {
  width: 14px;
  height: 14px;
  accent-color: var(--app-fg-accent);
  cursor: pointer;
}

/* Status tabs (FIP Logistics: Request / Shipped / Archived). Sits
   between the toolbar and the table inside the same .table-wrap card. */
.fip-tabs {
  display: flex;
  gap: 2px;
  padding: 0 16px;
  border-bottom: 1px solid var(--app-border);
  background: var(--app-bg-elev);
}
.fip-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: var(--fw-medium);
  color: var(--app-fg-3);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.fip-tab:hover { color: var(--app-fg); }
/* --app-focus, not --app-fg-accent — the same trap documented on
   .fip-rail-home:focus-visible below. The accent is a fixed navy that becomes
   Midnight in dark, so the selected tab and its 2px underline sat at 1.77:1
   against the tab bar: in dark mode you could not see which tab you were on.
   --app-focus is navy in light (identical to what this rendered before) and
   near-white in dark. */
.fip-tab.active {
  color: var(--app-focus);
  border-bottom-color: var(--app-focus);
}
/* Tabs are links, so the browser's own ring is suppressed by the kit's reset;
   without this the tab strip is not keyboard-navigable in any visible sense. */
.fip-tab:focus-visible {
  outline: 2px solid var(--app-focus);
  outline-offset: -2px;
}
.fip-tab-count {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--app-fg-3);
  background: var(--app-bg-sunken);
  border-radius: var(--radius-pill);
  padding: 1px 7px;
}
/* info-fg on info-bg: the designed pairing. It was accent-on-info-bg, which is
   the same Midnight-in-dark problem one selector up. */
.fip-tab.active .fip-tab-count {
  color: var(--app-info-fg);
  background: var(--app-info-bg);
}

/* Brand quick-switch rail — clickable avatars on the brand planner page to jump
   between brands. Scrolls horizontally when a manager owns many brands. */
.fip-brand-rail {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 2px 14px;
  margin-bottom: 4px;
  overflow-x: auto;
  scrollbar-width: thin;
}
/* Home chip leading the rail. Same 38px circle as an avatar so the row of
   round targets reads as one row, but outlined rather than filled — it's
   navigation, not a brand. align-self + margin-top pin its top to the
   avatars' (the brand items are taller: avatar + label), since the rail's
   align-items:center would otherwise float it down between the two lines. */
.fip-rail-home {
  flex: none;
  align-self: flex-start;
  margin-top: 2px;
  /* A touch more air than the inter-brand gap, separating the way out from the
     ways across without drawing a divider. */
  margin-right: 6px;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--app-border);
  background: var(--app-bg-elev);
  color: var(--app-fg-3);
  text-decoration: none;
  transition: color 0.12s ease, border-color 0.12s ease, transform 0.12s ease;
}
.fip-rail-home:hover {
  color: var(--app-fg);
  border-color: var(--app-fg-3);
  transform: translateY(-1px);
}
/* --app-focus, not --app-fg-accent: the accent is a fixed navy that becomes
   Midnight in dark, where a ring measures 1.77:1 against the page — invisible.
   --app-focus is the kit's theme-aware focus token (navy / near-white), which
   measures 15.8:1 light and 16.3:1 dark. */
.fip-rail-home:focus-visible {
  outline: 2px solid var(--app-focus);
  outline-offset: 2px;
}
.fip-rail-home .ic { width: 17px; height: 17px; }
.fip-rail-brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  flex: none;
  width: 62px;
  padding: 2px 4px;
  text-decoration: none;
}
.fip-rail-av {
  position: relative;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: #fff;
  font-size: 13px;
  font-weight: var(--fw-bold);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  transition: transform 0.12s ease;
}
.fip-rail-brand:hover .fip-rail-av { transform: translateY(-1px); }
.fip-rail-label {
  max-width: 60px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11px;
  font-weight: var(--fw-medium);
  color: var(--app-fg-3);
}
.fip-rail-brand:hover .fip-rail-label { color: var(--app-fg-2); }
.fip-rail-brand.active .fip-rail-av {
  box-shadow: 0 0 0 2px var(--app-bg), 0 0 0 4px var(--app-fg-accent);
}
.fip-rail-brand.active .fip-rail-label { color: var(--app-fg); font-weight: var(--fw-bold); }
.fip-rail-badge {
  position: absolute;
  top: -3px; right: -3px;
  box-sizing: border-box;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1;
  border-radius: var(--radius-pill);
  background: var(--app-danger);
  color: #fff;
  font-size: 10px;
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  border: 2px solid var(--app-bg);
}

/* Brand landing card thumb rendered as the same brand avatar (initials on the
   brand's colour) — more specific than `.list-card .thumb` so it wins. */
.list-card .thumb.fip-brand-thumb {
  color: #fff;
  font-weight: var(--fw-bold);
  font-size: 16px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
}

/* The FIP brand-landing card carries five stat columns (Urgent · Attention ·
   Replenish · OK · SKUs), one more than the shared .list-card 6-track grid
   accounts for — so the last (SKUs) count wraps onto a second row. Give the
   FIP card its own 7-track template above the design-system's 900px collapse
   point; at/below it the base .list-card mobile rule still hides the stats. */
@media (min-width: 901px) {
  .list-card.fip-brand-card {
    grid-template-columns: 48px minmax(0, 1.6fr) repeat(5, minmax(84px, max-content));
  }
}

table.data .rep-col-actions {
  width: 72px;
  text-align: right;
}

/* Repricer rules table only: a vertical rule after the SKU/identity+actions
   column, separating it from the data columns. Scoped to .rep-rules-table so
   no other data table picks it up. Border sits on the cell, so it survives row
   hover bg and any first-column stickiness. */
.rep-rules-table th.rep-col-sku,
.rep-rules-table td.rep-col-sku {
  border-right: 1px solid var(--app-border);
}

/* Inline status toggle pair (switch + label text). The switch comes
   from the design system; this just keeps them aligned in a row. */
.rep-status-cell {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.rep-status-text {
  font-size: 12px;
  color: var(--app-fg-2);
  font-weight: var(--fw-medium);
}
.rep-stock-guard-note {
  font-size: 11px;
  color: var(--app-fg-3);
  margin-top: 4px;
  line-height: 1.2;
}
.rep-stock-guard-state {
  font-weight: var(--fw-medium);
  color: var(--app-fg-2);
}

/* Disabled form row styling — used when stock-guard toggle is off so
   Auto-reactivate + FBA SKU read as inactive. */
.switch-row.is-disabled,
.field.is-disabled {
  opacity: 0.55;
  pointer-events: none;
}

/* Paired AM/PM price cell with optional struck-through list price.
   Both rows aligned, AM and PM tags as colored chips at the left. */
.price-pair {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.price-row {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
}
.price-tag {
  display: inline-block;
  min-width: 22px;
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.05em;
  color: var(--app-fg-accent);
}
.price-tag.pm { color: var(--app-fg-3); }
.price-now { color: var(--app-fg); font-weight: var(--fw-medium); }
.price-was {
  color: var(--app-fg-3);
  text-decoration: line-through;
  font-size: 11px;
}

/* Destructive action icon (Delete). Quiet by default, red on hover. */
.icon-btn.icon-btn-danger { color: var(--app-fg-3); }
.icon-btn.icon-btn-danger:hover {
  color: var(--app-danger, #dc3545);
  background: var(--app-bg-hover);
}

/* Inline delete form has zero height contribution; reset margins. */
form[data-rep-delete-form] {
  display: inline;
  margin: 0;
  padding: 0;
}

/* Page-head right-side context chip used in the dashboard header. */
.s-page-head .context-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--app-fg-2);
  font-weight: var(--fw-medium);
  flex-shrink: 0;
}
.s-page-head .context-chip .ic-wrap {
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  background: var(--app-bg-sunken);
  color: var(--app-fg);
}
.s-page-head .context-chip .ic-wrap i {
  width: 14px;
  height: 14px;
}

/* App summary bar — lives under the table. Left group is scope
   totals, right group is the last scheduled-run outcome. Shared across
   Repricer and FIP. */
.rep-summary,
.fip-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 10px 16px;
  border-bottom: 1px solid var(--app-border);
  background: var(--app-bg-elev);
  font-size: 12px;
}
.rep-summary-group {
  display: inline-flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  /* Carry the 12px stat size on the group itself so the planner's bare group
     (in the table-toolbar, no .rep-summary wrapper) matches logistics. */
  font-size: var(--app-fs-xs);
}
.rep-summary-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.rep-summary-label { color: var(--app-fg-3); }
.rep-summary-value {
  color: var(--app-fg);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}
.rep-summary-muted { color: var(--app-fg-3); font-weight: normal; }

/* "Select all" row styling is now in the design system (saas/styles.css)
   under .combobox-item[data-value=""] / .combobox-item-reset. */
.rep-summary-ic,
.fip-summary-ic { width: 14px; height: 14px; color: var(--app-fg-3); }
.rep-summary-ic-info,    .fip-summary-ic-info    { color: var(--app-info-fg); }
.rep-summary-ic-success, .fip-summary-ic-success { color: var(--app-success-fg); }
.rep-summary-ic-warn,    .fip-summary-ic-warn    { color: var(--app-warning-fg); }
.rep-summary-ic-danger,  .fip-summary-ic-danger  { color: var(--app-danger-fg); }

/* FIP summary cell — simple label/value pair (the planner shows 4 cells:
   Total, Urgent, Replenish, OK, plus latest run timestamp on the right). */
.fip-summary-cell {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.fip-summary-label { color: var(--app-fg-3); }
.fip-summary-value {
  color: var(--app-fg);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}

/* Result cell — coloured status icon + mode + timestamp on one line. */
.rep-last-run {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  white-space: nowrap;
}
.rep-last-run-ic { width: 16px; height: 16px; }
.rep-last-run-ic-success { color: var(--app-success-fg); }
.rep-last-run-ic-danger  { color: var(--app-danger-fg); }
.rep-last-run-ic-warn    { color: var(--app-warning-fg); }
.rep-last-run-meta {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.25;
}
.rep-last-run-mode {
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.05em;
  color: var(--app-fg-3);
}
.rep-last-run-price {
  color: var(--app-fg);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
}
.rep-last-run-sep { color: var(--app-border-strong); }
.rep-last-run-when {
  color: var(--app-fg-3);
  font-variant-numeric: tabular-nums;
}

/* Run-in-progress overlay (Run All / Run Selected). Reuses .modal.confirm for
   the orb + heading; adds an indeterminate bar since the synchronous run
   reports no per-SKU progress. */
.rep-run-progress .progress { margin-top: var(--sp-2); }
.progress.rep-indeterminate .bar {
  width: 40%;
  animation: rep-indeterminate 1.15s ease-in-out infinite;
}
@keyframes rep-indeterminate {
  0%   { margin-left: -45%; }
  100% { margin-left: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .progress.rep-indeterminate .bar { animation: none; width: 100%; margin-left: 0; }
}

/* Resizable data-table columns. JS in portal app.js appends a
   .col-resize-handle to every <th> (except the last) so it can be
   dragged horizontally. Widths persist per-page in localStorage.
   NOTE: no `position` override here — the kit's `position: sticky`
   on thead th (which pins headers in scroll containers) is itself a
   containing block for the handle's absolute positioning. A previous
   `position: relative` here silently broke sticky headers. */
table.data thead th .col-resize-handle {
  position: absolute;
  top: 0;
  right: -2px;
  bottom: 0;
  width: 5px;
  cursor: col-resize;
  user-select: none;
  z-index: 2;
  background: transparent;
  transition: background var(--t-fast);
}
table.data thead th .col-resize-handle:hover,
table.data.is-resizing thead th .col-resize-handle {
  background: var(--app-fg-accent);
}
table.data.is-resizing,
table.data.is-resizing * {
  cursor: col-resize !important;
  user-select: none !important;
}

/* Per-row Run icon: spinner-ish busy state when fetching. */
.icon-btn.is-busy { opacity: 0.5; pointer-events: none; }

/* Toolbar right-side swap groups. .rep-right-default is the steady state
   (Add SKU + Run Repricer); .rep-right-bulk replaces it when any row is
   checked. Both stack their children horizontally with the same gap as
   .table-toolbar .right (8px). */
.rep-right-default,
.rep-right-bulk {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.rep-right-default[hidden],
.rep-right-bulk[hidden] { display: none; }
.rep-bulkbar-count {
  font-size: 12px;
  color: var(--app-fg-3);
  font-weight: var(--fw-medium);
  padding-right: 4px;
  border-right: 1px solid var(--app-border);
  margin-right: 4px;
}
.rep-bulkbar-count #rep-bulkbar-n {
  color: var(--app-fg);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}

/* Split-button pattern: primary action + caret that opens a popover of
   secondary options. Reused by the Repricer bulk-action toolbar. */
.run-split {
  display: inline-flex;
  align-items: stretch;
}
.run-split .run-split-main {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: 0;
}
.run-split .run-split-caret {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  padding-left: 8px;
  padding-right: 8px;
  border-left: 1px solid rgba(255, 255, 255, 0.18);
}
.run-split .run-split-caret .ic { width: 14px; height: 14px; }

/* Destructive menu item inside a popover. */
.menu-item.menu-item-danger { color: var(--app-danger-fg); }
.menu-item.menu-item-danger:hover { background: var(--app-danger-bg); }
.menu-item.menu-item-danger .ic { color: currentColor; }

/* The brand stylesheet ships h3 with a 72px line-height (display heading
   defaults), which the design-system overrides for .modal-head /
   .drawer-head don't reset — leaving a big vertical gap above any
   sibling. Tighten the leading on small heading variants. */
.modal-head h3,
.drawer-head h3 { line-height: 1.2; }

/* The design-system .drawer-head ships with a bottom border, but
   .modal-head doesn't — visually they should match. */
.modal-head { border-bottom: 1px solid var(--app-border); }
.modal-body { padding-top: 20px; }

/* Drawer/modal-head eyebrow. Bare `.eyebrow` is the BRAND (marketing) eyebrow
   from colors_and_type.css — Montserrat, bold, `color: var(--accent)`, i.e.
   vermillion. That breaks hard rule 1 (red = critical only) on every drawer
   head that uses it. Product chrome wants the quiet meta label instead; these
   are the values .rep-history-eyebrow already uses. */
.drawer-head .eyebrow,
.modal-head .eyebrow {
  font-family: var(--app-font);
  font-size: 11px;
  font-weight: var(--fw-medium);
  letter-spacing: 0.05em;
  color: var(--app-fg-3);
}

/* Run confirmation modal — two-up radio cards (AM Price / PM Price)
   above the summary card. The radio default is the auto-detected
   session; users can override before confirming. */
.rep-run-modes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 16px;
}
.rep-run-mode { display: block; cursor: pointer; }
.rep-run-mode input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.rep-run-mode-card {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--app-border);
  border-radius: var(--radius-md);
  background: var(--app-bg-elev);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.rep-run-mode-card:hover { border-color: var(--app-border-strong); }
.rep-run-mode input:checked + .rep-run-mode-card {
  border-color: var(--app-fg-accent);
  background: var(--app-bg-sunken);
  box-shadow: inset 0 0 0 1px var(--app-fg-accent);
}
.rep-run-mode-ic {
  width: 18px;
  height: 18px;
  color: var(--app-fg-3);
}
.rep-run-mode input:checked + .rep-run-mode-card .rep-run-mode-ic {
  color: var(--app-fg-accent);
}
.rep-run-mode-label {
  font-size: 13px;
  font-weight: var(--fw-medium);
  color: var(--app-fg);
}
/* History drawer chrome. "History" as a small uppercase eyebrow above
   the SKU heading (h2). Events themselves use the design-system
   .timeline / .timeline-item pattern. */
.rep-history-eyebrow {
  font-size: 11px;
  color: var(--app-fg-3);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: var(--fw-medium);
  margin-bottom: 2px;
}
.rep-history-title {
  font-size: 18px;
  font-weight: var(--fw-bold);
  color: var(--app-fg);
  margin: 0;
  line-height: 1.2;
}
.rep-history-empty {
  padding: 32px 8px;
  text-align: center;
  color: var(--app-fg-3);
  font-size: 13px;
}

/* Repricer + FIP action columns inherit the kit's row-action treatment
   (`table.data .row-actions` — the Idealytics model: compact, low-contrast
   at rest, accent on hover). No per-app override, so the three apps stay
   consistent; the design system owns the gap/size/contrast. */

/* Row actions embedded at the right edge of the first (SKU) column, so they
   stay visible without horizontal scroll. .cell-main holds the SKU content;
   .row-actions is pushed to the right and shown on row hover (the shared
   table.data .row-actions treatment handles icon size/opacity). */
table.data td .cell-actions-host {
  display: flex;
  align-items: center;
  gap: 8px;
}
table.data td .cell-actions-host .cell-main {
  min-width: 0;
  flex: 1 1 auto;
}
table.data td .cell-actions-host .row-actions {
  flex: 0 0 auto;
  margin-left: auto;
}

/* ============================================================
   Analytics — the CEO brief. Editorial single column: one pulse
   figure, then the ranked insight cards. Layout + motion only —
   every colour/typeface comes from the design-system tokens.
   Red is reserved for genuinely critical findings (data quality);
   ordinary negative movers use navy emphasis + direction arrows.
   ============================================================ */
.brief-wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 8px 0 48px;
}

/* Entrance — one quick staggered fade-up per block, driven by --i.
   Subtle cue that the brief is "assembling", not decoration. */
@keyframes brief-enter {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.brief-masthead,
.brief-card,
.brief-foot {
  animation: brief-enter 420ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--i, 0) * 80ms);
}

.brief-masthead { padding: 24px 0 28px; }
.brief-eyebrow {
  font-size: 11px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--app-fg-3);
  margin-bottom: 18px;
}
.brief-pulse {
  display: flex;
  align-items: baseline;
  gap: 16px;
  flex-wrap: wrap;
}
.brief-pulse-figure {
  font-family: var(--font-display);
  font-size: 56px;
  line-height: 1.02;
  font-weight: var(--fw-bold);
  letter-spacing: -0.03em;
  color: var(--app-fg);
  font-variant-numeric: tabular-nums;
}
.brief-pulse-delta {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
}
.brief-pulse-delta .ic { width: 15px; height: 15px; }
.brief-pulse-delta.up   { color: var(--app-success); }
.brief-pulse-delta.down { color: var(--app-fg-2); }   /* navy, not red */
.brief-pulse-label {
  margin-top: 6px;
  font-size: 12px;
  color: var(--app-fg-3);
}
.brief-lede {
  margin: 16px 0 0;
  font-size: 15px;
  line-height: 24px;
  color: var(--app-fg-2);
  max-width: 60ch;
}
.brief-substats {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  margin-top: 18px;
  font-size: 12px;
  color: var(--app-fg-3);
}
.brief-substats b {
  color: var(--app-fg);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
}

.brief-cards {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.brief-card { padding: 20px 24px; }
.brief-card-critical { border-left: 3px solid var(--app-danger); }
.brief-card-top {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}
.brief-rank {
  font-size: 11px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  color: var(--app-fg-muted);
  font-variant-numeric: tabular-nums;
}
.brief-impact {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.brief-impact .ic { width: 14px; height: 14px; }
.brief-impact.tone-neg  { color: var(--app-fg); }       /* navy emphasis */
.brief-impact.tone-pos  { color: var(--app-success-fg); }
.brief-impact.tone-risk { color: var(--app-danger-fg); }
.brief-impact.tone-ok   { color: var(--app-success-fg); }
.brief-headline {
  font-size: 16px;
  line-height: 1.4;
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  color: var(--app-fg);
  margin: 0;
}
.brief-narrative {
  margin: 8px 0 0;
  font-size: 13px;
  line-height: 20px;
  color: var(--app-fg-2);
}

/* Relative-impact bar — aligned comparison across cards (length encodes
   |GBP impact| vs the week's largest finding). Grows in on load. */
.brief-impact-bar {
  margin-top: 14px;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--app-bg-sunken);
  overflow: hidden;
}
.brief-impact-bar span {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  transform-origin: left;
  animation: brief-bar 600ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--i, 0) * 80ms + 260ms);
}
@keyframes brief-bar {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
.brief-impact-bar .tone-neg  { background: var(--app-info); }   /* navy */
.brief-impact-bar .tone-pos  { background: var(--app-success); }
.brief-impact-bar .tone-risk { background: var(--app-danger); }

.brief-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 14px;
}
.brief-chips {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.brief-chips-more { font-size: 11px; color: var(--app-fg-3); white-space: nowrap; }
.brief-explore { flex-shrink: 0; }
.brief-explore .ic { width: 14px; height: 14px; }

.brief-quiet-row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}
.brief-quiet-dot {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--app-success);
  margin-top: 6px;
  flex-shrink: 0;
}

.brief-foot {
  margin-top: 28px;
  padding-top: 16px;
  border-top: 1px solid var(--app-border);
  font-size: 12px;
  line-height: 18px;
  color: var(--app-fg-3);
}

@media (prefers-reduced-motion: reduce) {
  .brief-masthead,
  .brief-card,
  .brief-foot,
  .brief-impact-bar span {
    animation: none;
  }
}

/* Idealytics Overview — design-handoff alignment (main/main.css is the
   source for every value below; tokens stay the kit's --app-* set). */

/* Delta tag (handoff: ui.jsx's IdxDelta + main.css's .dtag) — colored by
   favourability, not raw direction: a falling cost reads green. */
.dtag {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: 11px;
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.dtag.good { color: var(--app-success-fg, #1F8A5B); }
.dtag.bad { color: var(--app-danger); }
.dtag.flat { color: var(--app-fg-3); }
.dtag .ic { width: 12px; height: 12px; }

.idx-breadcrumb {
  font-size: 12px;
  color: var(--app-fg-3);
  margin-bottom: 10px;
}

/* Shared filter bar (all apps — spec 2026-07-08-filter-bar-alignment).
   Handoff: main.css's .fbar — filters sit straight on the page
   background with only a bottom hairline, no panel box. Items are flat flex
   children so Reset/Hide float to the end of the last row via
   .fbar-right's margin-left:auto. .idx-fbar-controls exists only so the
   Hide/Show toggle can collapse every filter item in one move;
   display:contents keeps it invisible to layout. */
.idx-fbar {
  position: sticky;
  top: 0;
  z-index: 9;
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 10px 12px;
  padding: 10px 0 12px;
  margin-bottom: 16px;
  background: var(--app-bg);
}
/* Tighten the header-to-filter gap on filter-bar pages. The fbar is sticky
   (top:0), which clamps its negative margin-top to the scroll container's
   edge — so the real lever is .s-body's own top padding, trimmed here only
   when a filter bar sits directly inside it. Other pages keep the 24px. */
.s-body:has(> .idx-fbar) { padding-top: 12px; }
.idx-fbar-controls { display: contents; }
.idx-fbar-controls.hidden { display: none; }
.idx-fitem { display: flex; flex-direction: column; gap: 4px; }
.flabel {
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--app-fg-3);
}
.fsel { width: auto; min-width: 150px; }
.fbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 12px;
}
/* Collapsed: chips share one row with the buttons (handoff .fbar.collapsed). */
.idx-fbar.collapsed { padding: 8px 0; align-items: center; }
.idx-fbar.collapsed .fchips {
  flex: 1;
  flex-basis: 0;
  order: -1;
  padding-top: 0;
  min-width: 0;
}

/* Active-filter chips — a child of the same .fbar (handoff: ActiveFilters),
   forced onto its own row via flex-basis:100%, visible whether the filter
   controls above are expanded or collapsed. */
.fchips {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  padding-top: 2px;
}
.fchips-label {
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--app-fg-3);
  margin-right: 2px;
}
.fchip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 6px 3px 9px;
  background: var(--app-bg-sunken);
  border: 1px solid var(--app-border);
  border-radius: var(--radius-pill);
  font-size: 11.5px;
  color: var(--app-fg-2);
  white-space: nowrap;
}
.fchip b { font-weight: var(--fw-medium); color: var(--app-fg); }
.fchip-x {
  width: 16px;
  height: 16px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  color: var(--app-fg-3);
}
.fchip-x:hover { background: var(--app-bg-active); color: var(--app-fg); }
.fchip-x .ic { width: 11px; height: 11px; }

/* Viewport-fit table scroll (FIP planner, Repricer). The kit's sticky
   thead binds to this scroll context instead of the viewport. Offset
   ≈ topbar + page head + filter bar + toolbar + footer; tune per page
   with a style attribute if a page's chrome differs. */
.table-scroll {
  overflow: auto;
  max-height: calc(100vh - 340px);
  min-height: 240px;
}

/* Second line inside a composite table cell (ASIN, A/R/I, source…). Tight
   leading (--app-lh-tiny, no top margin) so the sub-line hugs the main line
   and the pair reads as one unit. */
table.data .cell-sub,
table.data thead th .cell-sub {
  font-size: 11px;
  line-height: var(--app-lh-tiny);
  font-weight: 400;
  color: var(--app-fg-3);
  margin-top: 0;
}
/* Velocity trend chip — a tinted circle with a small lucide arrow, sitting
   on the 7d/30d sub-line. */
.fip-trend {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-pill);
  vertical-align: -4px;
  margin-left: 2px;
}
.fip-trend .ic,
.fip-trend svg {
  width: 10px !important;
  height: 10px !important;
}
.fip-trend-up { background: var(--app-success-bg); color: var(--app-success); }
.fip-trend-down { background: var(--app-danger-bg); color: var(--app-danger); }
.fip-trend-flat { background: var(--app-bg-active); color: var(--app-fg-3); }

/* Planner urgency-tab count bubbles carry the severity tint (the second
   selector outranks .fip-tab.active's neutral recolour). */
.fip-tab-count-danger,
.fip-tab.active .fip-tab-count.fip-tab-count-danger { background: var(--app-danger-bg); color: var(--app-danger-fg); }
.fip-tab-count-warning,
.fip-tab.active .fip-tab-count.fip-tab-count-warning { background: var(--app-warning-bg); color: var(--app-warning-fg); }
.fip-tab-count-success,
.fip-tab.active .fip-tab-count.fip-tab-count-success { background: var(--app-success-bg); color: var(--app-success-fg); }
/* Latest-run stamp riding the far-right of the planner tabs bar. */
.fip-tabs-meta {
  margin-left: auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--app-fg-3);
  white-space: nowrap;
  padding-right: 4px;
}
/* Right-hand action slot in a .fip-tabs strip — the buttons that belong to the
   view the tabs select (shipments list, orders route, shipment detail). It was
   the same six declarations inline in three templates. */
.fip-tabs-actions {
  margin-left: auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-right: 4px;
}
.fip-tabs-meta .ic { width: 13px; height: 13px; }
.fip-tabs-meta-value { color: var(--app-fg-2); font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }
/* Scenario-override variance ("orig …" sub-lines). Scoped under
   table.data .cell-sub so they win over the sub-line's muted colour. */
.fip-var-up, table.data .cell-sub.fip-var-up { color: var(--app-success); }
.fip-var-down, table.data .cell-sub.fip-var-down { color: var(--app-danger); }

/* Route group-header row (approval queue): a muted band + bold label
   dividing the flat row list into its routes, matching the divider shape
   already used for period breaks in dense tables elsewhere in the app.
   One <td colspan> per row, not per-column, so it needs no colgroup and
   ignores the sticky first-column offsets that apply to data rows only. */
table.data tr.fip-group-row td {
  background: var(--app-bg-sunken);
  padding: 6px 16px;
  font-size: var(--app-fs-tiny);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--app-fg-3);
}

/* Brand-owners table (fip/brand_owners.html): the Manager/Director controls are
   the standard single-select combobox (styled .ssel-pop menu), made "quiet until
   hover". The .drbtn trigger reads as plain inline text at rest (transparent
   border/bg, chevron hidden; "— None —" muted) and reveals the full trigger
   chrome on row hover, focus, or while the menu is open. The 1px border stays but
   goes transparent at rest, so revealing it never shifts the row. */
.brand-owner-selects .combobox { width: 100%; }
.brand-owner-selects .combobox .drbtn {
  width: 100%;
  min-width: 0;
  border-color: transparent;
  background: transparent;
  transition: border-color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}
.brand-owner-selects .combobox .drbtn .ic { opacity: 0; transition: opacity var(--t-fast); }  /* hide chevron at rest */
/* "— None —" (no member row selected) reads as muted placeholder text. Keys off
   the .selected row the shared JS toggles, so it tracks picks live. */
.brand-owner-selects .combobox:not(:has(.combobox-item.selected)) .drbtn-label { color: var(--app-fg-3); }
/* Reveal trigger chrome on row hover, focus, or while the menu is open. */
.brand-owner-selects tbody tr:hover .combobox .drbtn,
.brand-owner-selects .combobox:has(.combobox-list:not(.hidden)) .drbtn {
  border-color: var(--app-border-strong);
  background: var(--app-bg-elev);
}
.brand-owner-selects tbody tr:hover .combobox .drbtn .ic,
.brand-owner-selects .combobox .drbtn:focus .ic,
.brand-owner-selects .combobox .drbtn:focus-visible .ic,
.brand-owner-selects .combobox:has(.combobox-list:not(.hidden)) .drbtn .ic { opacity: 0.6; }
/* Focus gets the standard accent border + ring (already on .drbtn:focus, but the
   transparent resting border out-specifies it, so restate at higher specificity). */
.brand-owner-selects .combobox .drbtn:focus,
.brand-owner-selects .combobox .drbtn:focus-visible {
  background: var(--app-bg-elev);
  border-color: var(--app-focus);
  box-shadow: 0 0 0 3px var(--app-focus-ring);
}

/* Planner row-action states (legacy cues):
   - calculator tinted when the row carries a live modification
   - cloud-upload red when a modification hasn't been synced to ClickUp */
table.data .row-actions .icon-btn.fip-has-override {
  color: var(--app-success);
}
table.data .row-actions .icon-btn.fip-unsynced { color: var(--app-danger); }
table.data .row-actions .icon-btn.fip-unsynced:hover {
  background: var(--app-danger-bg);
  color: var(--app-danger);
}

/* Header info icons — muted, small, sit between the label and sort glyph. */
th .fip-th-info,
th svg.fip-th-info {
  width: 12px !important;
  height: 12px !important;
  margin-left: 4px;
  vertical-align: -1px;
  color: var(--app-fg-muted);
}
th:hover .fip-th-info { color: var(--app-fg-3); }

/* Frozen selection + identity columns on the planner, logistics and UK + EU
   boards. Offsets assume the fixed 28px checkbox column (border-box). Header
   corner cells are sticky on BOTH axes (kit gives thead th top:0/z1) and must
   layer above the other headers and the frozen body cells.

   All three boards freeze the SAME two columns: on each of them column 2 is
   the row's whole identity. The UK + EU table used to need a third (its
   identity was split across two columns by level) — since those merged into
   one (2026-08-04) it needs no more than the other two. */
#fip-planner-table th.fip-col-check,
#fip-logi-table th.fip-col-check,
#fip-dual-table th.fip-col-check,
#fip-planner-table td.fip-col-check,
#fip-logi-table td.fip-col-check,
#fip-dual-table td.fip-col-check {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--app-bg-elev);
  cursor: pointer; /* whole cell toggles the checkbox */
}
#fip-planner-table th.fip-col-sku,
#fip-logi-table th.fip-col-sku,
#fip-dual-table th.fip-col-sku,
#fip-planner-table td.fip-col-sku,
#fip-logi-table td.fip-col-sku,
#fip-dual-table td.fip-col-sku {
  position: sticky;
  left: 28px;
  z-index: 2;
  background: var(--app-bg-elev);
}
/* The LAST frozen column on all three boards, so it carries the frozen-region
   divider (same treatment as the Idealytics details table). On the dual table
   it regained that role when its two identity columns merged into this one
   (2026-08-04) — nothing to its right is frozen any more. */
#fip-planner-table th.fip-col-sku,
#fip-logi-table th.fip-col-sku,
#fip-dual-table th.fip-col-sku,
#fip-planner-table td.fip-col-sku,
#fip-logi-table td.fip-col-sku,
#fip-dual-table td.fip-col-sku {
  border-right: 1px solid var(--app-border);
}
/* This column carries BOTH identity levels — a product SKU on the main line, a
   region plus its (indented) platform SKU on each child — so it needs more
   floor than the planner's platform-SKU column: 240px fits an ~18-character
   platform SKU (e.g. PXP-BAIT-R-2X-FBA) after the child indent below, over the
   kit's 16px+16px cell padding.

   A floor only, deliberately: no `width`, no `max-width`, no `!important`. The
   earlier fixed 168px width existed so a THIRD frozen column could compute its
   `left` from it; that column is gone, so nothing downstream depends on this
   one's width and app.js's resize drag can move it freely (a hard pin would
   beat the drag's inline style while the handler still resized the neighbour —
   the failure .fip-col-deals' own comment warns about). */
#fip-dual-table th.fip-col-sku,
#fip-dual-table td.fip-col-sku {
  min-width: 240px;
}
/* The parent's expand caret shares the tick-box column with the child rows'
   checkboxes, so the two line up as one strip of controls. Sized to the 18px the
   column's own padding leaves (28px wide, 10px left inset) — a wider button
   would overflow a column pinned at 28px, and the glyph matches the 14px
   checkbox beside it. */
#fip-dual-table td.fip-col-check .fip-wl-chevron {
  width: 18px;
  height: 18px;
  padding: 0;
}
#fip-dual-table td.fip-col-check .fip-wl-chevron .ic {
  width: 14px;
  height: 14px;
}
/* Child lines sit under their parent's SKU, not beside it — the indent is what
   makes the column read as one expanding hierarchy rather than two kinds of row
   sharing a cell. Padding (not a margin on the content) so the sticky cell's
   own background still fills the indented strip. */
#fip-dual-table tbody tr.fip-dual-child td.fip-col-sku {
  padding-left: 34px;
}
/* A platform SKU longer than that headroom truncates with an ellipsis rather
   than wrapping (which would grow the row) or overflowing into column 3 (which
   would read as broken). The ASIN sub-line below is unaffected — real ASINs
   are a fixed 10 characters and never approach this cap. */
#fip-dual-table td.fip-col-sku .fip-dual-line {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
#fip-planner-table thead th.fip-col-check,
#fip-logi-table thead th.fip-col-check,
#fip-dual-table thead th.fip-col-check,
#fip-planner-table thead th.fip-col-sku,
#fip-logi-table thead th.fip-col-sku,
#fip-dual-table thead th.fip-col-sku {
  z-index: 3;
  background: var(--app-bg-sunken);
}
#fip-planner-table tbody tr:hover td.fip-col-check,
#fip-logi-table tbody tr:hover td.fip-col-check,
#fip-dual-table tbody tr:hover td.fip-col-check,
#fip-planner-table tbody tr:hover td.fip-col-sku,
#fip-logi-table tbody tr:hover td.fip-col-sku,
#fip-dual-table tbody tr:hover td.fip-col-sku { background: var(--app-bg-hover); }
/* Product spec table: frozen SKU column at the left edge (no checkbox
   column), same divider + left alignment as the other FIP boards. */
#fip-spec-table th.fip-col-sku,
#fip-spec-table td.fip-col-sku {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--app-bg-elev);
  border-right: 1px solid var(--app-border);
}
#fip-spec-table thead th.fip-col-sku {
  z-index: 3;
  background: var(--app-bg-sunken);
}
#fip-spec-table tbody tr:hover td.fip-col-sku { background: var(--app-bg-hover); }
#fip-spec-table th,
#fip-spec-table td { text-align: left; }

/* Planner UK + EU tab — the same two-level shape as the worklist (product
   parent, per-region children), rebuilt onto the route table's own column set
   (`fip-col-*`, extended into the freeze rules above) so the two read alike.
   Only what's still specific to this tab's two-level shape lives here. */
/* A hairline above each product group so a parent reads as the start of a block
   rather than one more row in a flat list. */
#fip-dual-table tbody tr.fip-dual-parent:not(:first-child) td {
  border-top: 1px solid var(--app-border);
}
/* The child row's platform SKU: quieter than the parent's product SKU, so the
   column reads parent-first. The indent that sets a child apart is the cell's
   own padding (see the .fip-col-sku child rule above), not a margin here — the
   chevron on the parent's line has to stay flush with the column edge. */
#fip-dual-table .fip-dual-line {
  color: var(--app-fg-2);
  text-decoration: none;
}
#fip-dual-table .fip-dual-line:hover {
  color: var(--app-fg);
  text-decoration: underline;
}
/* Theme-aware focus token — the fixed accent fails contrast on a dark row (see
   .fip-rail-home:focus-visible). */
#fip-dual-table .fip-dual-line:focus-visible {
  outline: 2px solid var(--app-focus);
  outline-offset: 2px;
  border-radius: 3px;
}
/* The region is the child row's identity, so it carries the weight the parent's
   SKU does — at tiny size, since the label is two letters. It now LEADS the
   line, with the platform SKU after it, hence the gap. */
#fip-dual-table .fip-dual-region {
  font-weight: var(--fw-medium);
  color: var(--app-fg);
  margin-right: 8px;
}
/* Approved-column badges ("Pending BD Approval" is the longest) must not wrap —
   a two-line badge cost the parent row a second line under the old layout, and
   nothing about this column is wide enough to rule that out on its own. */
#fip-dual-table .badge { white-space: nowrap; }

/* Planner landing worklist — a two-level checklist (brand parent, route
   children) on the kit's default table view. Everything below is either the
   identity-column freeze the other FIP boards already use, or the minimum
   needed to read parent vs child; no new component. */
#fip-worklist-table th.fip-wl-col-name,
#fip-worklist-table td.fip-wl-col-name {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--app-bg-elev);
  border-right: 1px solid var(--app-border);
  /* Without a floor the numeric columns (sized by their own headers) starve
     this one and brand names / route labels wrap onto a second line, so rows
     land at 45-61px instead of the kit's dense 32px. Measured: the widest
     column set still fits 1105px at 1440 with no horizontal scroll. */
  min-width: 320px;
}
#fip-worklist-table thead th.fip-wl-col-name {
  z-index: 3;
  background: var(--app-bg-sunken);
}
#fip-worklist-table tbody tr:hover td.fip-wl-col-name { background: var(--app-bg-hover); }
#fip-worklist-table th,
#fip-worklist-table td { text-align: left; }
/* A hairline above each brand group so the parent reads as the start of a
   block rather than one more row in a flat list. */
#fip-worklist-table tbody tr.fip-wl-parent:not(:first-child) td {
  border-top: 1px solid var(--app-border);
}
/* Child rows sit under the parent's brand name: the indent puts the route
   TEXT exactly where the brand name starts, so a sub-task reads as nested
   under its parent rather than shifted left of it. The parent name begins at
   chevron 32 + gap 8 + avatar 24 + gap 8 = 72px; the child spends 13px on its
   corner glyph plus a 6px gap before its text, so the indent is the remainder.
   Measured with elementFromPoint/getBoundingClientRect: delta 0px. */
#fip-worklist-table td.fip-wl-col-name .fip-wl-route {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: calc(32px + 8px + 24px + 8px - 13px - 6px);
  color: var(--app-fg-2);
  /* It's a link (to the route's planner tab) but it lives in a checklist, so
     it stays undecorated until hover — an always-underlined route in every
     child row would read as noise down a long list. */
  text-decoration: none;
}
#fip-worklist-table td.fip-wl-col-name a.fip-wl-route:hover {
  color: var(--app-fg);
  text-decoration: underline;
}
/* Theme-aware focus token — see .fip-rail-home:focus-visible for why the fixed
   accent can't be used here (1.58:1 on a dark row). */
#fip-worklist-table td.fip-wl-col-name a.fip-wl-route:focus-visible {
  outline: 2px solid var(--app-focus);
  outline-offset: 2px;
  border-radius: 3px;
}
/* Per-region run times on a parent row. Each region is one atomic chip, so a
   two-region brand wraps BETWEEN regions instead of mid-timestamp (which cost
   a third line and a 61px row). */
.fip-wl-runs {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-size: 11px;
  /* Tiny text needs the tiny leading — inheriting the 21px body line-height
     made a two-region brand a 61px row. Same treatment as .cell-sub. */
  line-height: var(--app-lh-tiny);
  color: var(--app-fg-3);
}
.fip-wl-runs > span { white-space: nowrap; }
.fip-wl-chevron .ic { transition: transform var(--t-fast); }
.fip-wl-chevron[aria-expanded="false"] .ic { transform: rotate(-90deg); }
/* Staleness hint — deliberately quiet: it informs, it doesn't warn. */
.fip-wl-stale {
  width: 13px;
  height: 13px;
  color: var(--app-fg-3);
}
/* Days-remaining bullet (planner, and the UK + EU tab's own child rows) —
   days-cover design from the data-viz doc: the fill runs to the days left,
   colored by the threshold it clears; S/R/T tick marks (solid strong / solid
   light / dashed) carry their day counts under the track. Value + KPI icon on
   the LEFT; the track stretches with the column so every bar is the same
   width. The dual table's PARENT row carries no bar at all (its cell is
   empty — see that template's own comment on why), so this floor only ever
   bites on a child row there. */
#fip-planner-table .fip-col-days,
#fip-dual-table .fip-col-days { min-width: 240px; }
/* Deals column — up to three stacked lines (ended / live / next), each the
   deal's name plus its type and that phase's own day count. Plain text, no
   badges. min-width is the floor for a board where no SKU has a deal (it would
   otherwise collapse to the header). There is deliberately NO max-width here:
   this class sits on the <th> as well as the <td>, and the column-resize
   handler works by writing an inline width onto that <th> — a stylesheet
   max-width clamps the used value of an inline width, so a cap here would let
   a drag past the cap shrink the right-hand neighbour while this column
   refused to grow, and persist a width to localStorage that never renders.
   The ceiling that stops one long deal name from pushing every other column
   off-screen lives on .fip-deal-name instead (see below). */
#fip-planner-table .fip-col-deals,
#fip-dual-table .fip-col-deals {
  min-width: 168px;
}
/* Three stacked lines want list leading, not paragraph leading: inheriting the
   table's body line-height gave each line 22px, so a 3-deal cell ran 74px and
   the block read as three separate things rather than one SKU's deal history.
   --app-lh-sm is the on-system leading for this 13px text (same reasoning as
   .fip-wl-runs and .cell-sub, which take --app-lh-tiny for their 11px), and the
   2px gap is enough to separate lines once the leading is tight. */
.fip-deal-lines {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.fip-deal-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  line-height: var(--app-lh-sm);
  /* Nowrap keeps a day count off a second line, where it would read as a
     separate deal. The name is the only elastic part (see below). */
  white-space: nowrap;
}
/* The name leads the line. It's the one unbounded-length field in the cell, so
   it — and only it — shrinks and ellipsises; the type + day count are short,
   fixed-shape, and must stay fully readable. min-width:0 is required for
   ellipsis to engage on a flex child.
   flex-grow stays 0: letting the name grow into the column's spare width pushed
   each day count out to the right edge, opening a river between the two halves
   of the line that measured up to 81px within a single cell — a ragged mid-line
   gap where the name and its day count stopped reading as one phrase.
   Shrink-only keeps every line tight-packed against the left.
   max-width is the column's real ceiling (see .fip-col-deals above for why it
   can't live on the cell): it bounds the one field with no natural length
   limit, so a 90-character deal name can't push the columns to its right off
   the board. It bites in both table layout modes because this is an ordinary
   flex item, not a table cell. The full name stays in the row tooltip. */
.fip-deal-name {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--app-fg-2);
}
/* The live deal is the one that may be distorting velocity right now, so it
   carries the weight; ended and upcoming deals stay quiet. Weight + full-
   strength foreground, no colour tone — this cell is information, not status. */
.fip-deal-line.is-current .fip-deal-name {
  font-weight: var(--fw-bold);
  color: var(--app-fg);
}
/* Type + day count are the detail, the name is the headline — a step down in
   both size and contrast, and never shrunk. */
.fip-deal-when {
  flex: none;
  font-size: 11px;
  color: var(--app-fg-3);
  font-variant-numeric: tabular-nums;
}
/* Total FBA's sub-line (A / R / I). The column is sized by its own header
   (measured 103.9px → 71.9px of content), which is narrow enough that a
   four-figure component wraps: a value dropped onto a second line reads as a
   different number — and costs the row 14px. Nowrap lets the column take the
   few px it needs instead; the board already scrolls horizontally. (The
   in-production figure used to be a fourth component here — "0 / 2 / 0 / 1100"
   was the shape that broke — until it moved out of Total FBA entirely.) */
#fip-planner-table .fip-col-fba .cell-sub,
#fip-dual-table .fip-col-fba .cell-sub { white-space: nowrap; }
/* The FIP boards read left→right — every header + value left-aligned
   (overrides the kit's right-aligned .num). */
#fip-planner-table th,
#fip-planner-table td,
#fip-logi-table th,
#fip-logi-table td { text-align: left; }
/* Reset-column-widths icon rides quiet until hovered. */
.icon-btn[data-col-reset] { opacity: 0.45; }
.icon-btn[data-col-reset]:hover { opacity: 1; }
.fip-bullet-wrap {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.fip-bullet-val {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-width: 42px;
  padding-top: 1px;
  font-variant-numeric: tabular-nums;
}
.fip-bullet-plot {
  position: relative;
  flex: 1;
  min-width: 140px;
  height: 30px;
}
.fip-bullet-track {
  position: absolute;
  top: 2px;
  left: 0;
  right: 0;
  height: 12px;
  border: 1px solid var(--app-border);
  border-radius: 3px;
  background: var(--app-bg-sunken);
  overflow: hidden;
}
/* The measure is a circle at the days-left position, colored by
   urgency — the grey track stays whole underneath it. */
.fip-bullet-dot {
  position: absolute;
  top: 8px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
.fip-bullet-dot.ok { background: #2fa36a; }
.fip-bullet-dot.warn { background: #d6a62c; }
.fip-bullet-dot.crit { background: #c13a2b; }
/* Threshold captions only — no tick lines. */
.fip-bullet-thr {
  position: absolute;
  top: 0;
  width: 0;
}
.fip-bullet-thr .cap {
  position: absolute;
  top: 17px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--app-fg-3);
  opacity: 0.75;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.fip-bullet-thr .cap b { color: inherit; }

/* Selection count inside a toolbar button (planner Approve, logistics
   Bulk actions) — a small navy circle; :empty hides it at zero. */
.btn .fip-count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  margin-left: 2px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: var(--fw-bold);
  background: var(--app-fg-accent);
  color: #fff;
}
.btn .fip-count-badge:empty { display: none; }
/* On a navy primary button the badge inverts so it stays visible. */
.btn-primary .fip-count-badge {
  background: #fff;
  color: var(--app-fg-accent);
}

/* Hover tooltip for row-action icon buttons. A CSS-only ::after used to sit
   inside the cell, but once actions moved into the (mid-table) SKU cell it
   got trapped under .table-scroll's overflow and later rows. It's now a
   single fixed-positioned bubble driven by JS (see app.js `[data-tooltip]`),
   so it escapes every overflow/stacking context. */
.rowtip {
  position: fixed;
  z-index: 3000;
  background: var(--app-fg);
  color: var(--app-fg-inverse);
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  font-size: 11px;
  line-height: 14px;
  font-weight: var(--fw-medium);
  white-space: nowrap;
  box-shadow: var(--app-shadow-md);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--t-fast);
}
.rowtip.show { opacity: 1; }
/* Multi-line variant — honour newlines in data-tooltip (one item per line)
   instead of collapsing them. app.js toggles this only when the tooltip
   text contains a newline, so single-line tips keep their nowrap layout. */
.rowtip--multiline { white-space: pre-line; text-align: left; }

/* ClickUp task link on the SKU cell — inherits colour, tiny quiet glyph. */
.fip-cu-link { color: inherit; text-decoration: none; }
.fip-cu-link:hover { text-decoration: underline; }
.fip-cu-link .fip-cu-ic,
.fip-cu-link svg.fip-cu-ic {
  width: 10px !important;
  height: 10px !important;
  margin-left: 3px;
  opacity: 0.45;
  vertical-align: baseline;
}

/* Urgency KPI icon inline with the Days Remaining value (the stat strip
   reuses the same icons via rep-summary-ic). */
td .fip-kpi-ic,
td svg.fip-kpi-ic {
  width: 14px !important;
  height: 14px !important;
  margin-left: 4px;
  vertical-align: -2px;
}

/* Stat strip lifted out of the table card — a flat line of figures on the
   page background between the filter bar and the table (repricer run
   summary, planner latest-run, feedback totals). No box chrome; horizontal
   padding dropped so it aligns with the filter bar's left edge. */
.rep-summary-standalone {
  background: transparent;
  border: 0;
  padding: 10px 0;
  margin-bottom: 4px;
}

/* Data-quality banner (handoff: main.css's .dq-banner). */
.dq-banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 14px;
  margin-bottom: 16px;
  background: var(--app-info-bg, #EDF3FC);
  color: var(--app-info-fg, #2C5282);
  border: 1px solid var(--app-border);
  border-radius: var(--radius-md);
  font-size: 12.5px;
  line-height: 18px;
}
.dq-banner .ic { width: 15px; height: 15px; margin-top: 1px; flex-shrink: 0; }
.dq-txt { flex: 1; min-width: 0; }
.dq-txt strong { font-weight: var(--fw-bold); }

/* Section heads (handoff: main.css's .sec-head/.sec-title). */
.sec-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 10px;
}
.sec-head-l { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sec-title {
  font-family: var(--font-display, inherit);
  font-size: 18px;
  line-height: 1.3;
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  color: var(--app-fg);
  margin: 0;
}
.khead-r { display: flex; align-items: center; gap: 8px; }

/* Segmented control (handoff: ui.jsx's Seg / main.css's .seg) — Day/Week/
   Month. Rendered as <a> (server-side navigation) or <button>. */
.seg {
  display: inline-flex;
  background: var(--app-bg-sunken);
  border-radius: var(--radius-md);
  padding: 2px;
  gap: 2px;
}
.seg a,
.seg button {
  border: 0;
  background: transparent;
  font-family: inherit;
  font-size: 12px;
  color: var(--app-fg-3);
  padding: 4px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--t-fast), color var(--t-fast);
}
.seg a:hover,
.seg button:hover { color: var(--app-fg); }
.seg a.active,
.seg button.active {
  background: var(--app-bg-elev);
  color: var(--app-fg);
  font-weight: var(--fw-medium);
  box-shadow: var(--app-shadow-xs, 0 1px 2px rgba(14, 33, 51, 0.06));
}

/* KPI carousel (handoff: Kpis.jsx's KpiStrip/KpiCard) — a horizontal-scroll
   track of cards with responsive perRow sizing and overflow nav arrows,
   replacing the earlier plain CSS-grid `.kpi-strip`. `.trend`'s base layout
   (flex/gap/up-down colour) is defined scoped to `.kpi` in saas/styles.css;
   since the card container here is `.kcard` not `.kpi`, that base rule is
   re-declared under `.kcard` (and `.im-fig`, the zoom modal's headline row)
   so a trend tag looks identical wherever `metric_trend()` renders one. */
.kstrip-body { position: relative; margin-bottom: 24px; }
.ktrack {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.ktrack::-webkit-scrollbar { display: none; }
.kcard {
  flex: 0 0 calc((100% - (var(--kpi-n, 5) - 1) * 12px) / var(--kpi-n, 5));
  scroll-snap-align: start;
  background: var(--app-bg-elev);
  border: 1px solid var(--app-border);
  border-radius: var(--radius-lg);
  padding: 14px 16px 10px;
  cursor: grab;
  transition: border-color var(--t-fast), box-shadow var(--t-fast), opacity var(--t-fast);
}
.kcard:hover { border-color: var(--app-border-strong); }
.kcard.dragging { opacity: 0.4; cursor: grabbing; }
.kcard-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.kcard-label {
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--app-fg-3);
}
.kcard-actions { display: inline-flex; align-items: center; gap: 2px; }
.kzoom {
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--app-fg-3);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-fast), background var(--t-fast);
}
.kcard:hover .kzoom { opacity: 1; }
.kzoom:hover { background: var(--app-bg-active); color: var(--app-fg); }
.kzoom .ic { width: 12px; height: 12px; }
.kcard-grip { color: var(--app-fg-muted); opacity: 0; transition: opacity var(--t-fast); display: flex; }
.kcard:hover .kcard-grip { opacity: 1; }
.kcard-grip .ic { width: 13px; height: 13px; }
.kcard-fig {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 6px;
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  color: var(--app-fg);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.kcard-sub {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 5px;
  min-width: 0;
  font-size: 12px;
}
.kcard-pri {
  font-size: 11px;
  color: var(--app-fg-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Carousel nav arrows — floating circular buttons at the track's edges,
   only shown (toggled via JS) once the visible pool overflows the row. */
.knav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 5;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  border: 1px solid var(--app-border-strong);
  background: var(--app-bg-elev);
  color: var(--app-fg-2);
  cursor: pointer;
  box-shadow: var(--app-shadow-pop);
}
.knav:hover { color: var(--app-fg); background: var(--app-bg-hover); }
.knav.l { left: -12px; }
.knav.r { right: -12px; }
.knav .ic { width: 16px; height: 16px; }

/* KPI zoom modal (handoff: Zoom.jsx's KpiZoomModal) — one shared instance,
   populated per-card by JS; the headline figure/trend/prior are cloned
   straight from the clicked card's own already-rendered DOM (never
   reformatted client-side) so the modal can never disagree with its card. */
.idx-mback {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--app-overlay);
  display: grid;
  place-items: center;
  padding: 24px;
}
.idx-modal {
  width: min(920px, 94vw);
  background: var(--app-bg-elev);
  border: 1px solid var(--app-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--app-shadow-lg);
  padding: 20px 24px 18px;
}
.im-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 10px; }
.im-title {
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.3;
  font-weight: var(--fw-bold);
  color: var(--app-fg);
}
.im-sub { font-size: 12px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; margin-top: 1px; }
.im-actions { display: flex; align-items: center; gap: 8px; }
.im-fig { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
.im-num {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  color: var(--app-fg);
  font-variant-numeric: tabular-nums;
}
.im-num .metric-dot { margin-right: 6px; }
.im-pri { font-size: 12px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; }
.im-legend { display: flex; justify-content: center; gap: 18px; margin-top: 10px; }
.im-legend .lg { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--app-fg-3); }
.im-legend .dot { width: 7px; height: 7px; border-radius: 999px; }
.im-legend .dot.pri { background: var(--app-fg-muted); }
.im-legend .dot.cur { background: var(--app-fg-accent); opacity: 0.75; }
.im-legend .tdash { width: 14px; border-top: 2px dashed var(--app-success-fg); }

/* Zoom modal's big chart (handoff: Zoom.jsx's BigChart) — gridlines/target
   line/area+line paths drawn server-data-driven, hover crosshair + tooltip
   built client-side since only the mouse position is client state. */
.bigchart { position: relative; }
.bigchart svg { width: 100%; display: block; }
.bc-grid { stroke: var(--app-border); stroke-width: 1; }
.bc-ylab, .bc-xlab {
  font-size: 11px;
  fill: var(--app-fg-3);
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
}
.bc-zero { stroke: var(--app-border-strong); stroke-width: 1.25; }
.bc-target { stroke: var(--app-success-fg); stroke-width: 1; stroke-dasharray: 4 4; }
.bc-tlab { font-size: 10px; fill: var(--app-success-fg); font-weight: 500; font-family: var(--font-sans); }
.bc-area { fill: var(--app-fg-accent); opacity: 0.04; stroke: none; }
.bc-cur { fill: none; stroke: var(--app-fg-accent); stroke-opacity: 0.65; stroke-width: 1.75; }
.bc-pri { fill: none; stroke: var(--app-fg-muted); stroke-width: 1.5; }
.bc-hover { stroke: var(--app-border-strong); stroke-width: 1; }
.bc-dot-cur { fill: var(--app-fg-accent); }
.bc-dot-pri { fill: var(--app-fg-muted); }
.bc-tip {
  position: absolute;
  transform: translate(12px, -50%);
  background: var(--app-bg-elev);
  border: 1px solid var(--app-border);
  border-radius: var(--radius-md);
  box-shadow: var(--app-shadow-pop);
  padding: 8px 10px;
  pointer-events: none;
  white-space: nowrap;
  z-index: 5;
}
.bc-tip.flip { transform: translate(calc(-100% - 12px), -50%); }
.bc-tip-date { font-size: 11px; font-weight: var(--fw-medium); color: var(--app-fg); margin-bottom: 4px; font-variant-numeric: tabular-nums; }
.bc-tip-row { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--app-fg-3); }
.bc-tip-row + .bc-tip-row { margin-top: 2px; }
.bc-tip-row b { margin-left: auto; padding-left: 12px; color: var(--app-fg); font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }
.bc-tip-row .dot { width: 6px; height: 6px; border-radius: 999px; }
.bc-tip-row .dot.cur { background: var(--app-fg-accent); opacity: 0.75; }
.bc-tip-row .dot.pri { background: var(--app-fg-muted); }

/* KPI card trend chart (handoff: ui.jsx's KpiChart / main.css's .kchart) —
   prior + current lines over a soft area fill, y labels on the RIGHT rail
   (max top / target / min bottom), month ticks, tiny legend. */
.kchart { margin-top: 10px; }
.kchart-plot { display: flex; align-items: stretch; gap: 5px; }
.kchart-svgwrap { position: relative; flex: 1; min-width: 0; }
.kchart-svgwrap svg { width: 100%; display: block; }
.kchart-y {
  position: relative;
  width: 28px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  font-size: 9px;
  line-height: 10px;
  color: var(--app-fg-muted);
  font-variant-numeric: tabular-nums;
  text-align: left;
  padding: 1px 0;
}
.kchart-cur { fill: none; stroke: var(--app-fg-accent); stroke-opacity: 0.6; stroke-width: 1.5; vector-effect: non-scaling-stroke; }
:root[data-theme="dark"] .kchart-cur { stroke: var(--app-fg-link); }
.kchart-pri { fill: none; stroke: var(--app-fg-muted); stroke-width: 1.25; vector-effect: non-scaling-stroke; }
.kchart-area { fill: var(--app-fg-accent); opacity: 0.05; stroke: none; }
:root[data-theme="dark"] .kchart-area { fill: var(--app-fg-link); }
.kchart-zero { stroke: var(--app-border-strong); stroke-width: 1; vector-effect: non-scaling-stroke; }
.kchart-target {
  stroke: var(--app-success-fg, #1F8A5B);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  vector-effect: non-scaling-stroke;
}
.kchart-tlabel {
  position: absolute;
  left: 0;
  transform: translateY(-50%);
  font-size: 8px;
  font-weight: var(--fw-medium);
  color: var(--app-success-fg, #1F8A5B);
  background: var(--app-bg-elev);
  padding-right: 2px;
}
.kchart-x {
  position: relative;
  height: 13px;
  margin-top: 2px;
  margin-right: 33px;
}
.kchart-x span {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  font-size: 9px;
  color: var(--app-fg-muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.kchart-x span.first { transform: none; }
.kchart-x span.last { transform: translateX(-100%); }
.kchart-legend {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 3px;
}
.kchart-legend .lg {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 9.5px;
  color: var(--app-fg-3);
}
.kchart-legend .dot { width: 6px; height: 6px; border-radius: 999px; }
.kchart-legend .dot.pri { background: var(--app-fg-muted); }
.kchart-legend .dot.cur { background: var(--app-fg-accent); }
:root[data-theme="dark"] .kchart-legend .dot.cur { background: var(--app-fg-link); }

/* Threshold status dot — small colored indicator next to a KPI figure or
   table cell (handoff: ThrDot, 8px). Table cells place it AFTER the value. */
.metric-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  margin-right: 7px;
  vertical-align: middle;
  flex-shrink: 0;
}
.metric-dot[data-status="good"] { background: var(--app-success-fg, #1F8A5B); }
.metric-dot[data-status="ok"] { background: var(--app-fg-muted); }
.metric-dot[data-status="bad"] { background: var(--app-danger); }
table.data td.num .metric-dot { margin-right: 0; margin-left: 6px; vertical-align: 1px; }

/* Unit badge shown once in a currency column's header (house space-saving
   rule from the design handoff: cells are bare numbers, the ISO code lives
   on the header instead). */
table.data .tt-unit {
  margin-left: 4px;
  font-size: 10px;
  font-weight: var(--fw-regular);
  color: var(--app-fg-3);
  text-transform: none;
}

/* Muted sub-caption under a details-table row's group label (e.g. the
   marketplace a Product SKU row belongs to). */
table.data .g-sub {
  font-size: 11px;
  font-weight: var(--fw-regular);
  color: var(--app-fg-3);
  margin-top: 2px;
}

/* KPI/column customise picker (handoff's MetricPicker: main.css's .picker/
   .pick-row) — a .popover body with a drag-to-reorder, tick-to-show list.
   Driven by initMetricPicker() in app.js; reused as-is for the Phase 3
   table-column picker. */
.idx-picker { width: 260px; padding: 0; }
.idx-picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  border-bottom: 1px solid var(--app-border);
  font-size: 12px;
  font-weight: var(--fw-medium);
  color: var(--app-fg);
}
.idx-picker-reset {
  border: 0;
  background: transparent;
  color: var(--app-fg-accent);
  font-size: 12px;
  cursor: pointer;
  padding: 0;
}
.idx-picker-reset:hover { text-decoration: underline; }
.idx-picker-list {
  max-height: 320px;
  overflow-y: auto;
  padding: 4px;
}
.idx-pick-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  cursor: grab;
}
.idx-pick-row:hover { background: var(--app-bg-hover); }
.idx-pick-row.dragging { opacity: 0.5; }
.idx-pick-grip { color: var(--app-fg-3); display: flex; flex-shrink: 0; }
.idx-pick-grip .ic { width: 13px; height: 13px; }
.idx-pick-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--app-fg);
  cursor: pointer;
  flex: 1;
}
.idx-picker-hint {
  padding: 6px 12px;
  font-size: 11px;
  color: var(--app-fg-3);
  border-top: 1px solid var(--app-border);
}
.idx-picker-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--app-border);
}

/* Date-range trigger button — same anatomy as .select, matching the
   handoff's .drbtn (main.css). */
.drbtn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  /* One toolbar-trigger height (34px) — matches .combobox .select and the
     .table-search input so a trigger and a search box sitting together line
     up. The .idx-fbar/.gby height override below is now belt-and-braces. */
  height: 34px;
  padding: 0 12px;
  box-sizing: border-box;
  background: var(--app-bg-elev);
  border: 1px solid var(--app-border-strong);
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: 13px;
  line-height: 20px;
  color: var(--app-fg);
  cursor: pointer;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.drbtn:hover { border-color: var(--app-fg-3); }
/* One focus/open treatment for every control: the navy focus border + the
   --app-focus-ring, NO elevation shadow (that's reserved for floating menus).
   The trigger stays focused while its menu is open, so this doubles as the
   open-state ring — matching .input / .select / .combobox .select / search. */
.drbtn:focus,
.drbtn:focus-visible {
  outline: none;
  border-color: var(--app-focus);
  box-shadow: 0 0 0 3px var(--app-focus-ring);
}
.drbtn .ic { width: 14px; height: 14px; color: var(--app-fg-3); }
.drbtn-label { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Date-range popover: presets on the left, two navigable month calendars on
   the right (handoff: main/Filters.jsx's DateRangeControl + main.css's
   .idr-*/.cal-* — ported verbatim, .popover supplies the panel chrome). */
.idr-pop { padding: 0; width: auto; }
.idr-body { display: flex; }
.idr-presets {
  width: 136px;
  flex-shrink: 0;
  border-right: 1px solid var(--app-border);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.idr-preset {
  border: 0;
  background: transparent;
  text-align: left;
  font-family: inherit;
  font-size: 12.5px;
  color: var(--app-fg-2);
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
}
.idr-preset:hover { background: var(--app-bg-hover); color: var(--app-fg); }
.idr-preset.active {
  background: var(--app-bg-active);
  color: var(--app-fg);
  font-weight: var(--fw-medium);
}
.idr-cals { display: flex; gap: 20px; padding: 12px 16px 14px; }
.cal { width: 218px; }
.cal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.cal-title { font-size: 12.5px; font-weight: var(--fw-medium); color: var(--app-fg); }
.cal-nav {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--app-fg-3);
  cursor: pointer;
}
.cal-nav:hover { background: var(--app-bg-hover); color: var(--app-fg); }
.cal-nav .ic { width: 14px; height: 14px; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px 0; }
.cal-dow {
  font-size: 10px;
  font-weight: var(--fw-medium);
  color: var(--app-fg-3);
  text-align: center;
  padding: 3px 0 5px;
}
.cal-day {
  height: 27px;
  border: 0;
  background: transparent;
  font-family: inherit;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--app-fg-2);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.cal-day:hover:not(:disabled):not(.blank) { background: var(--app-bg-hover); color: var(--app-fg); }
.cal-day:disabled { color: var(--app-fg-muted); cursor: default; }
.cal-day.blank { pointer-events: none; }
.cal-day.in-range { background: var(--app-bg-active); border-radius: 0; color: var(--app-fg); }
.cal-day.r-start, .cal-day.r-end {
  background: var(--app-fg-accent);
  color: var(--app-fg-inverse);
  font-weight: var(--fw-medium);
}
.cal-day.r-start { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.cal-day.r-end { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.cal-day.r-start.r-end { border-radius: var(--radius-sm); }
.idr-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 16px;
  border-top: 1px solid var(--app-border);
}
.idr-sum { font-size: 12px; color: var(--app-fg-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.idr-actions { display: flex; gap: 8px; }

/* Search box inside a searchable filter combobox's dropdown (Parent SKU /
   Product SKU — handoff's MultiSelect `searchable` prop / .ms-search). */
.combobox-search-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--app-border);
  color: var(--app-fg-3);
}
.combobox-search-row .ic { width: 13px; height: 13px; flex-shrink: 0; }
.combobox-search-row input {
  border: 0;
  outline: none;
  background: transparent;
  font-family: inherit;
  font-size: 12.5px;
  color: var(--app-fg);
  width: 100%;
}
.combobox-search-row input::placeholder { color: var(--app-fg-3); }

/* Multi-select filter dropdowns (handoff: main.css's .msel-btn/.msel-pop/
   .ms-row) — drbtn-anatomy trigger, visible checkboxes, "Select all" head
   row, optional search + sub-captions. */
.msel-btn { min-width: 150px; justify-content: space-between; }
.combobox-list.msel-pop { left: 0; right: auto; width: 208px; padding: 0; }
.combobox-list.msel-pop.wide { width: 264px; }
.ms-list { max-height: 240px; overflow-y: auto; padding: 4px 0; }
.combobox-item.ms-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 12px;
  font-size: 12.5px;
  color: var(--app-fg-2);
  cursor: pointer;
}
.combobox-item.ms-row:hover { background: var(--app-bg-hover); color: var(--app-fg); }
/* Selected rows read via weight + tick, not a fill — matches .ssel-row.selected. */
.combobox-item.ms-row.selected { background: transparent; font-weight: var(--fw-medium); color: var(--app-fg); }
.ms-row input[type="checkbox"] {
  width: 14px;
  height: 14px;
  accent-color: var(--app-fg-accent);
  cursor: pointer;
  flex-shrink: 0;
  margin: 0;
}
.ms-all {
  border-bottom: 1px solid var(--app-border);
  font-weight: var(--fw-medium);
  color: var(--app-fg);
}
.ms-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--app-border);
  color: var(--app-fg-3);
}
.ms-search .ic { width: 13px; height: 13px; flex-shrink: 0; }
.ms-search input {
  border: 0;
  outline: none;
  background: transparent;
  font-family: inherit;
  font-size: 12.5px;
  color: var(--app-fg);
  width: 100%;
}
.ms-search input::placeholder { color: var(--app-fg-3); }
.ms-txt { display: flex; flex-direction: column; min-width: 0; line-height: 16px; }
.ms-txt .ms-sub {
  font-size: 10.5px;
  color: var(--app-fg-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Details-table row label cell: an optional tier badge next to the
   label/sub-caption stack (handoff's .g-cell/.g-txt/.tier, parent-SKU
   grouping only). */
.g-cell { display: flex; align-items: center; gap: 10px; min-width: 0; }
.g-txt { min-width: 0; }
.tier {
  width: 20px;
  height: 20px;
  display: inline-grid;
  place-items: center;
  border-radius: var(--radius-sm);
  background: var(--app-bg-sunken);
  border: 1px solid var(--app-border);
  font-size: 10px;
  font-weight: var(--fw-bold);
  color: var(--app-fg-2);
  flex-shrink: 0;
}

/* Details-table pagination footer (handoff's .pager/.pgno). */
.pager { display: flex; align-items: center; gap: 6px; }
.pgno { font-size: 12px; color: var(--app-fg-2); font-variant-numeric: tabular-nums; }

/* Details table (handoff: Table.jsx + main.css) — group-by control, sticky
   first column, hover tint, per-column filters, totals row. */
.gby { display: flex; align-items: center; gap: 8px; }
.gby .flabel { white-space: nowrap; }
.dt-scroll { overflow-x: auto; }
table.data thead th { white-space: nowrap; }
table.data th.stick,
table.data td.stick {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--app-bg-elev);
  border-right: 1px solid var(--app-border);
  min-width: 230px;
}
table.data thead th.stick { z-index: 3; background: var(--app-bg-sunken); }
table.data tbody tr:hover td { background: #F5F9FD; }
table.data tbody tr:hover td.stick { background: #F5F9FD; }
:root[data-theme="dark"] table.data tbody tr:hover td,
:root[data-theme="dark"] table.data tbody tr:hover td.stick { background: rgba(155, 184, 227, 0.07); }
.neg { color: var(--app-danger); }
.empty-cell { color: var(--app-fg-3); font-size: 12.5px; padding: 24px 16px !important; }
table.data tfoot td {
  padding: 11px 16px;
  background: var(--app-bg-elev);
  border-top: 1px solid var(--app-border);
  box-shadow: 0 -2px 4px -2px rgba(14, 33, 51, 0.06);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  color: var(--app-fg);
}
table.data tfoot td.stick { background: var(--app-bg-elev); z-index: 2; }
:root[data-theme="dark"] table.data tfoot td { box-shadow: 0 -2px 4px -2px rgba(0, 0, 0, 0.28); }
table.data tfoot td.num { text-align: right; }

/* Per-column vs-prior delta, shown only when that column's toggle is on. */
table.data td .cell-delta { display: none; }
table.data td.delta-on .cell-delta {
  display: flex;
  justify-content: flex-end;
  margin-top: 2px;
}

/* Per-column value filter: funnel button in each metric header + the
   fixed-position condition editor (handoff: .col-flt/.cf-pop). */
.col-flt {
  display: inline-block;
  width: 14px;
  height: 14px;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: var(--radius-sm);
  color: currentColor;
  cursor: pointer;
  vertical-align: -2px;
  margin-left: 4px;
  opacity: 0.4;
  transition: opacity var(--t-fast), background var(--t-fast), color var(--t-fast);
}
.col-flt .ic { width: 12px; height: 12px; display: inline-flex; }
.col-flt.on { opacity: 1; color: var(--app-fg-accent); }
.col-flt:hover { opacity: 1; background: var(--app-bg-active); }
.cf-pop {
  position: fixed;
  z-index: 220;
  width: 240px;
  background: var(--app-bg-elev);
  border: 1px solid var(--app-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--app-shadow-pop);
  padding: 12px;
}
.cf-title {
  font-size: 12px;
  font-weight: var(--fw-bold);
  color: var(--app-fg);
  margin-bottom: 8px;
}
.cf-unit { font-weight: var(--fw-regular); color: var(--app-fg-3); }
.cf-row { margin-bottom: 8px; }
.cf-row .select,
.cf-row .input {
  width: 100%;
  height: 36px;
  padding-top: 0;
  padding-bottom: 0;
  font-size: 13px;
  line-height: normal;
}
.cf-vals { display: flex; gap: 8px; }
.cf-actions { display: flex; justify-content: space-between; gap: 8px; margin-top: 2px; }
.colf-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 8px 16px;
  border-bottom: 1px solid var(--app-border);
  background: var(--app-bg-sunken);
}
.colf-clear {
  border: 0;
  background: transparent;
  font-family: inherit;
  font-size: 12px;
  font-weight: var(--fw-medium);
  color: var(--app-fg-link, #393E77);
  cursor: pointer;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
}
.colf-clear:hover { background: var(--app-bg-hover); text-decoration: underline; }

/* Extra per-row toggle in the column picker (handoff: .pick-spark — here
   the "% vs prior" switch). */
.idx-pick-extra {
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--app-fg-muted);
  cursor: pointer;
  flex-shrink: 0;
  margin-left: auto;
  transition: background var(--t-fast), color var(--t-fast);
}
.idx-pick-extra:hover { background: var(--app-bg-active); color: var(--app-fg); }
.idx-pick-extra.on { color: var(--app-fg); }
.idx-pick-extra .ic { width: 13px; height: 13px; }

/* ---- Overview UI polish (2026-07-05 punch list) ------------------------- */

/* 1. One control height across the filter bar + table toolbar, matching the
   table search input (34px). */
.idx-fbar .drbtn,
.idx-fbar .btn-sm,
.gby .drbtn,
.gby .fsel,
.idx-fbar .fsel {
  height: 34px;
  padding-top: 0;
  padding-bottom: 0;
  box-sizing: border-box;
}

/* 2. Dropdown scrolling lives on the option list, never the whole panel —
   the search row stays put and the scrollbar is always visible. */
.combobox-list.msel-pop {
  max-height: none;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.msel-pop .ms-list { flex: 1 1 auto; max-height: 240px; overflow-y: auto; }
.msel-pop .ms-list::-webkit-scrollbar { width: 8px; }
.msel-pop .ms-list::-webkit-scrollbar-thumb {
  background: var(--app-border-strong);
  border-radius: 4px;
}
.msel-pop .ms-list { scrollbar-width: thin; }

/* 3./15. Single-select dropdowns share the multiselect's anatomy: drbtn
   trigger, soft-shadow panel, checkmark on the left of the picked item
   instead of a highlighted row. */
.combobox-list.ssel-pop { left: 0; right: auto; min-width: 100%; width: max-content; padding: 4px 0; }
.combobox-item.ssel-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 12px;
  font-size: 12.5px;
  color: var(--app-fg-2);
  cursor: pointer;
  white-space: nowrap;
}
.combobox-item.ssel-row:hover { background: var(--app-bg-hover); color: var(--app-fg); }
.combobox-item.ssel-row.selected { background: transparent; font-weight: var(--fw-medium); color: var(--app-fg); }
/* Per-option lock (select_field()'s disabled_values) — e.g. a non-superadmin
   can't promote a user to admin/superadmin. pointer-events:none backs up
   the JS click-guard, and also means this row can never match :hover, so
   it never picks up the hover fill above it. */
.combobox-item.ssel-row[aria-disabled="true"] {
  color: var(--app-fg-muted);
  cursor: not-allowed;
  pointer-events: none;
}
/* Beat the kit's right-aligned, opacity-driven check (margin-left:auto) —
   the handoff wants the mark on the LEFT of the picked option. */
.combobox .combobox-item.ssel-row .check-ic {
  margin-left: 0;
  order: -1;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: var(--app-fg-accent);
}

/* 6. Loading veil while a filter submit / navigation round-trips. */
.kstrip, .details { position: relative; }
.idx-loading::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 5;
  background: color-mix(in srgb, var(--app-bg) 60%, transparent);
  backdrop-filter: blur(1px);
}
.idx-loading::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  z-index: 6;
  border-radius: 50%;
  border: 2.5px solid var(--app-border-strong);
  border-top-color: var(--app-fg-accent);
  animation: idx-spin 0.7s linear infinite;
}
@keyframes idx-spin { to { transform: rotate(360deg); } }

/* 10./11. Breadcrumb header: App > Page, at real heading size; the filter
   bar tucks up under the page head instead of drifting away from it. */
.idx-crumb {
  display: flex;
  align-items: center;
  gap: 6px;
  /* On the type scale (h3). Was an off-scale 16px; 15px keeps page titles on
     the same ramp as the rest of the page (15 title / 13 body / 12 meta / 11 micro). */
  font-size: var(--app-fs-h3);
  font-weight: var(--fw-bold);
  color: var(--app-fg);
}
.idx-crumb-app { color: var(--app-fg-3); font-weight: var(--fw-medium); }
.idx-crumb-sep { width: 15px; height: 15px; color: var(--app-fg-muted); }
.idx-fbar { padding-top: 2px; margin-top: -8px; }

/* 7. Per-row trend sparkline (handoff: Table.jsx's TinySpark). */
.cell-spark { display: flex; justify-content: flex-end; margin-top: 3px; }
.tspark path {
  fill: none;
  stroke: var(--app-fg-3);
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
}

/* 17. Metric cells never wrap — columns take their natural width and the
   .dt-scroll wrapper handles the horizontal overflow. */
[data-idx-table] th,
[data-idx-table] td.num { white-space: nowrap; }

/* ---- Overview UI polish, round 2 (2026-07-05) -------------------------- */

/* 3. The details search box keeps only a border-colour cue on focus — the
   kit's 3px focus-ring shadow reads as a heavy drop shadow here. */
.details .table-search input:focus {
  box-shadow: none;
  border-color: var(--app-focus);
}

/* 5. Column-picker "toggle all" header — bulk on/off for each per-column
   extra (sparkline, variance). Sits above the draggable rows. */
.idx-pick-bulk {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 8px 8px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--app-border);
}
.idx-pick-bulk-label {
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--app-fg-3);
}
.idx-pick-bulk-btns { display: inline-flex; gap: 2px; }

/* Chip staged for clearing — dimmed until Apply Filters commits it. */
.fchip.idx-chip-cleared { opacity: 0.45; text-decoration: line-through; }
.fchip.idx-chip-cleared .fchip-x { pointer-events: none; }

/* ---- Idealytics Trends controls (2026-07-05) -------------------------- */

/* View toggle — labelled "Metric / Segment" segmented switch (reuses .seg). */
.idx-viewswitch { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; }
.idx-viewswitch .flabel { font-size: 12px; color: var(--app-fg-3); font-weight: var(--fw-medium); }

/* Variance toggle switch (show/hide per-cell delta figures). */
.idx-switch { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; user-select: none; }
.idx-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.idx-switch-track {
  position: relative;
  width: 32px;
  height: 18px;
  border-radius: 999px;
  background: var(--app-bg-sunken);
  border: 1px solid var(--app-border);
  transition: background 0.15s;
}
.idx-switch-track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--app-fg-3);
  transition: transform 0.15s, background 0.15s;
}
.idx-switch input:checked + .idx-switch-track { background: var(--app-fg-accent); border-color: var(--app-fg-accent); }
.idx-switch input:checked + .idx-switch-track::after { transform: translateX(14px); background: #fff; }
.idx-switch input:focus-visible + .idx-switch-track { outline: 2px solid var(--app-fg-accent); outline-offset: 1px; }
.idx-switch-label { font-size: 12px; color: var(--app-fg-2); font-weight: var(--fw-medium); }
/* Trend cells show their per-bucket variance by default (the Overview's
   column-gated `td .cell-delta { display:none }` would otherwise hide them);
   the Variance switch toggles it off via .hide-variance. */
table.data.trend-table td .cell-delta { display: flex; justify-content: flex-end; margin-top: 2px; }
table.data.trend-table.hide-variance td .cell-delta { display: none; }

/* Metric-view row actions (reorder grip + drill menu), right-aligned. Both are
   always visible but subtle, lifting to full strength on row/icon hover. */
.trend-table .g-cell { display: flex; align-items: center; gap: 8px; }
.trend-table .g-cell .g-txt { min-width: 0; flex: 1; }
.idx-row-actions { margin-left: auto; display: inline-flex; align-items: center; gap: 2px; flex: none; }
/* The drill button is wrapped in a .popover-anchor; make it a flex box too so
   its icon shares the same centre line as the chart button beside it. */
.idx-row-actions .popover-anchor { display: inline-flex; align-items: center; }
.idx-row-grip {
  display: inline-flex;
  align-items: center;
  color: var(--app-fg-4, var(--app-fg-3));
  cursor: grab;
  opacity: 0.35;
  transition: opacity 0.12s;
}
.idx-row-grip .ic { width: 14px; height: 14px; }
.idx-drill-btn {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  color: var(--app-fg-3);
  cursor: pointer;
  padding: 2px;
  border-radius: var(--radius-sm);
  opacity: 0.4;
  transition: opacity 0.12s, color 0.12s, background 0.12s;
}
.idx-drill-btn .ic { width: 15px; height: 15px; }
/* Row → chart button — same subtle-then-hover treatment as the drill button. */
.idx-chart-btn {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  color: var(--app-fg-3);
  cursor: pointer;
  padding: 2px;
  border-radius: var(--radius-sm);
  opacity: 0.4;
  transition: opacity 0.12s, color 0.12s, background 0.12s;
}
.idx-chart-btn .ic { width: 15px; height: 15px; }
.trend-table tbody tr:hover .idx-row-grip { opacity: 0.7; }
.trend-table tbody tr:hover .idx-drill-btn { opacity: 0.8; }
.trend-table tbody tr:hover .idx-chart-btn { opacity: 0.8; }
.idx-row-grip:hover { opacity: 1; }
.idx-drill-btn:hover { opacity: 1; color: var(--app-fg-accent); background: var(--app-bg-sunken); }
.idx-chart-btn:hover { opacity: 1; color: var(--app-fg-accent); background: var(--app-bg-sunken); }
.trend-table tbody tr.idx-row-dragging { opacity: 0.4; background: var(--app-bg-sunken); }

/* Drill menu — segment picker anchored beside the drill button (JS lifts it to
   fixed positioning so the scroll container can't clip it). */
.idx-drill-menu { min-width: 176px; padding: 5px; }
.idx-drill-head {
  padding: 4px 8px 6px;
  font-size: 11px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--app-fg-3);
}
.idx-drill-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 8px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--app-fg);
  text-decoration: none;
}
.idx-drill-item .ic { width: 14px; height: 14px; color: var(--app-fg-3); }
.idx-drill-item:hover { background: var(--app-bg-sunken); color: var(--app-fg-accent); }
.idx-drill-item:hover .ic { color: var(--app-fg-accent); }

/* Segment-view reverse drill: the group label links back to the Metric view
   pinned to that segment. Chevron affordance reveals on row hover. */
.idx-drill { display: block; color: inherit; text-decoration: none; min-width: 0; }
.idx-drill .g-label { display: inline-flex; align-items: center; gap: 4px; }
.idx-drill:hover .g-label { color: var(--app-fg-accent); }
.idx-drill-ic {
  width: 13px;
  height: 13px;
  opacity: 0;
  color: var(--app-fg-accent);
  transition: opacity 0.12s;
}
.trend-table tbody tr:hover .idx-drill-ic { opacity: 0.8; }

/* Segment-view sortable + filterable column headers. */
.idx-col-h { display: inline-flex; align-items: center; gap: 4px; }
.idx-col-h-num { justify-content: flex-end; }
.idx-sort {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border: 0;
  background: transparent;
  font: inherit;
  font-weight: inherit;
  color: inherit;
  cursor: pointer;
  padding: 0;
}
.idx-sort:hover { color: var(--app-fg-accent); }
.idx-sort.sorted { color: var(--app-fg-accent); }
.idx-sort-ic { width: 13px; height: 13px; opacity: 0.55; }
.idx-sort.sorted .idx-sort-ic { opacity: 1; }
.idx-colf-btn {
  display: inline-flex;
  border: 0;
  background: transparent;
  color: var(--app-fg-3);
  cursor: pointer;
  padding: 2px;
  border-radius: var(--radius-sm);
}
.idx-colf-btn:hover { color: var(--app-fg-accent); background: var(--app-bg-sunken); }
.idx-colf-btn .ic { width: 13px; height: 13px; }
.idx-colf {
  min-width: 160px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.idx-colf-row { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--app-fg-2); }
.idx-colf-row .idx-colf-num { flex: 1; }
.idx-colf .input { width: 100%; }

/* Trend table (handoff: main.css .trend-table) — metrics as rows, buckets as
   columns, with Total/Avg/Trend summary columns and a per-row heat map. */
.trend-table th.stick, .trend-table td.stick { min-width: 200px; }
.trend-table th.num, .trend-table td.num { min-width: 92px; }
.trend-table .tt-sum { border-right: 1px solid var(--app-border); }
.trend-table td.tt-sum b { font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }
.trend-table th.tt-trend, .trend-table td.tt-trend { text-align: center; min-width: 148px; }
.trend-table th.tt-part { color: var(--app-warning-fg, #8A6D1F); }
.tt-partmark { width: 11px; height: 11px; color: var(--app-warning-fg, #8A6D1F); vertical-align: -1px; }
.tt-unit {
  font-size: 9px;
  font-weight: var(--fw-bold);
  color: var(--app-fg-3);
  margin-left: 4px;
  letter-spacing: 0.04em;
}
/* Per-row heat: intensity from --h, green above the row midpoint, red below. */
.tt-heat.tt-hi { background: rgb(31 138 91 / var(--h, 0)); }
.tt-heat.tt-lo { background: rgb(198 54 31 / var(--h, 0)); }
:root[data-theme="dark"] .tt-heat.tt-hi { background: rgb(96 200 150 / var(--h, 0)); }
:root[data-theme="dark"] .tt-heat.tt-lo { background: rgb(235 130 110 / var(--h, 0)); }
/* On row hover, the flat highlight (`tr:hover td { background }`) would paint
   over the semi-transparent heat cells. Keep the heat on those cells and lift
   its contrast/brightness instead, so the hovered row still reads its heat. */
table.data.trend-table tbody tr:hover td.tt-heat.tt-hi { background: rgb(31 138 91 / var(--h, 0)); }
table.data.trend-table tbody tr:hover td.tt-heat.tt-lo { background: rgb(198 54 31 / var(--h, 0)); }
:root[data-theme="dark"] table.data.trend-table tbody tr:hover td.tt-heat.tt-hi { background: rgb(96 200 150 / var(--h, 0)); }
:root[data-theme="dark"] table.data.trend-table tbody tr:hover td.tt-heat.tt-lo { background: rgb(235 130 110 / var(--h, 0)); }
table.data.trend-table tbody tr:hover td.tt-heat { filter: saturate(1.55) contrast(1.12); }
/* Trend bar sparkline. */
.ttspark { display: inline-flex; }
/* Each bar coloured by its move vs the previous bucket — up green, down red —
   at a low saturation so the row still reads calmly. */
.ttspark-svg rect { fill: var(--app-fg-3, #6B7688); opacity: 0.4; }
.ttspark-svg rect.bar-up { fill: var(--app-success-fg, #1F8A5B); opacity: 0.6; }
.ttspark-svg rect.bar-down { fill: var(--app-danger, #C6361F); opacity: 0.55; }

/* Product master SKU chips. */
.ml-sku-chip {
  display: inline-block;
  padding: 2px 7px;
  margin: 1px 3px 1px 0;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  background: var(--app-bg-sunken);
  border: 1px solid var(--app-border);
  border-radius: var(--radius-sm);
  color: var(--app-fg-2);
}
.ml-sku-more { font-size: 11px; color: var(--app-fg-3); }

/* ---- DataOps observability (2026-07-13) --------------------------------- */
/* Ported from the DataDev design handoff (datadev.css), shipped tabs only. */

.dd-page { max-width: none; width: 100%; }
.dd-stack { display: flex; flex-direction: column; gap: 16px; }

/* Section titles */
.dd-sect { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-top: 8px; }
.dd-sect-title { margin: 0; font-size: 16px; line-height: 22px; font-weight: var(--fw-bold); color: var(--app-fg); }
.dd-sect-hint { font-size: 12px; color: var(--app-fg-3); }

/* Status atoms */
.dd-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; display: inline-block; }
.dd-dot.tone-success { background: var(--app-success); }
.dd-dot.tone-warning { background: var(--app-warning); }
.dd-dot.tone-danger  { background: var(--app-danger); }
.dd-dot.tone-info    { background: var(--app-info); }
.dd-dot.tone-neutral { background: transparent; border: 1.5px dashed var(--app-fg-3); }
.dd-badge-sm { font-size: 10px; padding: 2px 7px; gap: 4px; }

.dd-pulse {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--app-info); display: inline-block;
  animation: dd-pulse 1.4s ease-out infinite;
}
@keyframes dd-pulse { 0% { box-shadow: 0 0 0 0 var(--app-info-bg); } 70% { box-shadow: 0 0 0 5px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
@media (prefers-reduced-motion: reduce) { .dd-pulse { animation: none; } }

/* KPI row */
.dd-kpis { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; }
.dd-kpi { display: flex; flex-direction: column; gap: 6px; }
.dd-kpi-label {
  display: flex; align-items: center; gap: 6px;
  font-size: 10px; font-weight: var(--fw-bold);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--app-fg-3);
}
.dd-kpi-num { font-family: var(--font-display); font-size: 28px; line-height: 32px; font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; color: var(--app-fg); }
.dd-kpi.clickable { cursor: pointer; transition: border-color var(--t-fast), box-shadow var(--t-fast); }
.dd-kpi.clickable:hover { border-color: var(--app-border-strong); box-shadow: var(--app-shadow-sm); }
.dd-kpi.selected { border-color: var(--app-fg-accent); }

/* Banners */
.dd-banner { display: flex; align-items: flex-start; gap: 10px; }
.dd-banner .btn { flex-shrink: 0; align-self: center; }

/* Fleet table */
.dd-fleet-count { font-size: 12px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.dd-fleet-table td { vertical-align: middle; }
.dd-fleet-row { cursor: pointer; }
.dd-fleet-name { display: flex; align-items: center; gap: 9px; }
.dd-fleet-label { font-size: 13px; font-weight: var(--fw-bold); color: var(--app-fg); white-space: nowrap; }
.dd-fleet-key { font-size: 11px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; }
.dd-fleet-freshcol { min-width: 170px; }
.dd-fleet-freshcol .dd-fresh { max-width: 190px; }
.dd-fleet-rows { font-size: 13px; font-weight: var(--fw-bold); color: var(--app-fg); }
.dd-fleet-rows.warn { color: var(--app-warning-fg); }
.dd-fleet-rows .danger-text { color: var(--app-danger); font-weight: var(--fw-bold); }
.dd-fleet-when { font-size: 11px; color: var(--app-fg-3); white-space: nowrap; }
.dd-fleet-sparkcol { width: 150px; }
.dd-runbars { display: block; }
.dd-runbar { fill: var(--app-success); opacity: 0.35; }
.dd-runbar.warning { fill: var(--app-info); opacity: 0.9; }
.dd-runbar.danger { fill: var(--app-danger); opacity: 1; }
.dd-fleet-issuecol { max-width: 260px; }
.dd-fleet-issue { font-size: 11px; line-height: 16px; display: block; }
.dd-fleet-issue.tone-danger { color: var(--app-danger-fg); }
.dd-fleet-issue.tone-warning { color: var(--app-warning-fg); }
.dd-fleet-issue.tone-info { color: var(--app-fg-2); }
.dd-fleet-issue.tone-neutral, .dd-fleet-issue.tone-success { color: var(--app-fg-2); }
.dd-fleet-na { color: var(--app-fg-3); font-size: 11px; }
.dd-fleet-empty { text-align: center; color: var(--app-fg-3); padding: 28px 16px !important; font-size: 12px; }

/* Run schedule rows (pipeline detail) */
.dd-sched-list { display: flex; flex-direction: column; gap: 8px; }
.dd-sched-row { display: grid; grid-template-columns: 150px 150px 1fr 1fr 100px auto; gap: 12px; align-items: center; font-size: 12px; color: var(--app-fg-2); }
.dd-sched-cron { white-space: nowrap; }
.dd-sched-kv { font-variant-numeric: tabular-nums; white-space: nowrap; }
.dd-sched-kv .k { font-size: 10px; color: var(--app-fg-3); margin-right: 4px; }
@media (max-width: 1100px) { .dd-sched-row { grid-template-columns: 1fr 1fr; } }

/* Event log toolbar + compressed timeline rows */
.dd-log-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dd-log-search { flex: 0 1 260px; min-width: 180px; }
.dd-log-toolbar .dd-fleet-count { margin-left: auto; }
.dd-tl { display: flex; flex-direction: column; gap: 20px; }
.dd-tl-day { display: flex; flex-direction: column; gap: 10px; }
.dd-tl-daylabel { font-size: 10px; font-weight: var(--fw-bold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--app-fg-3); }
.dd-tl-item { display: grid; grid-template-columns: 34px 1fr; gap: 0; }
.dd-tl-rail { position: relative; display: flex; justify-content: center; }
.dd-tl-rail::before { content: ""; position: absolute; top: 0; bottom: -10px; width: 1px; background: var(--app-border); }
.dd-tl-day .dd-tl-item:last-child .dd-tl-rail::before { bottom: auto; height: 14px; }
.dd-tl-orb {
  position: relative; z-index: 1;
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center; margin-top: 8px;
  border: 1px solid var(--app-border); background: var(--app-bg-elev);
}
/* Lucide emits width/height=24 attributes and there is no global .ic size
   rule — every context must size its own icons (reference: orb 13, src 11). */
.dd-tl-orb .ic { width: 13px; height: 13px; }
.dd-tl-orb.tone-success { color: var(--app-success); background: var(--app-success-bg); border-color: transparent; }
.dd-tl-orb.tone-warning { color: var(--app-warning); background: var(--app-warning-bg); border-color: transparent; }
.dd-tl-orb.tone-danger  { color: var(--app-danger); background: var(--app-danger-bg); border-color: transparent; }
.dd-tl-orb.tone-info    { color: var(--app-info); background: var(--app-info-bg); border-color: transparent; }
.dd-tl-card { margin-left: 8px; display: flex; flex-direction: column; gap: 4px; }
.dd-tl-time { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--app-fg-3); }
.dd-tl-pipe { font-size: 11px; color: var(--app-fg-2); text-decoration: underline; cursor: pointer; }
.dd-tl-pipe:hover { color: var(--app-fg); }
.dd-tl-desc { font-size: 12px; line-height: 18px; color: var(--app-fg-2); }
.dd-tl-src { display: flex; align-items: center; gap: 5px; font-size: 10px; color: var(--app-fg-3); margin-top: 2px; }
.dd-tl-src .ic { width: 11px; height: 11px; flex-shrink: 0; }
.dd-tl-card.dd-tl-wide { display: grid; grid-template-columns: 72px 92px 200px minmax(0, 1fr) 210px; align-items: center; gap: 12px; padding: 5px 0 5px 8px; border: 0; background: transparent; box-shadow: none; border-radius: 0; }
.dd-tl-wide .dd-tl-time { flex-shrink: 0; }
.dd-tl-wide .badge { justify-self: start; }
.dd-tl-wide .dd-tl-pipe { justify-self: start; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; }
.dd-tl-wide .dd-tl-text { font-size: 12px; line-height: 17px; min-width: 0; }
.dd-tl-wide .dd-tl-text strong { color: var(--app-fg); }
.dd-tl-wide .dd-tl-src { min-width: 0; display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--app-fg-3); justify-self: start; max-width: 100%; }
@media (max-width: 1200px) { .dd-tl-card.dd-tl-wide { grid-template-columns: 72px 92px 200px minmax(0, 1fr); } .dd-tl-wide .dd-tl-text { grid-column: 1 / -1; } .dd-tl-wide .dd-tl-src { grid-column: 4; grid-row: 1; justify-self: end; } }

/* Run-health heatmap */
.dd-hm-card { display: flex; flex-direction: column; gap: 14px; }
.dd-hm-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.dd-hm-title { font-size: 15px; font-weight: var(--fw-bold); color: var(--app-fg); }
.dd-hm-sub { font-size: 12px; color: var(--app-fg-3); margin-top: 2px; }
.dd-hm-controls { display: flex; gap: 8px; flex-wrap: wrap; }
.dd-hm-wrap { position: relative; }
.dd-hm { display: grid; gap: 3px 2px; align-items: stretch; }
.dd-hm-label {
  display: flex; align-items: center; gap: 7px; min-width: 0;
  padding-right: 10px; font-size: 12px; color: var(--app-fg-2);
  cursor: pointer; text-decoration: none;
}
.dd-hm-label span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-hm-label:hover { color: var(--app-fg); text-decoration: underline; }
.dd-hm-cell { height: 22px; border-radius: 2px; min-width: 0; }
.dd-hm-cell.fail  { background: var(--app-danger); }
.dd-hm-cell.stale { background: var(--app-warning); }
.dd-hm-cell.anom  { background: var(--app-info); opacity: 0.6; }
.dd-hm-cell.ok    { background: var(--app-success); opacity: 0.35; }
.dd-hm-cell.none  { background: var(--app-bg-sunken); }
.dd-hm-axis-pad { grid-column: 1; }
.dd-hm-tick {
  font-size: 9px; color: var(--app-fg-3); font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: visible; padding-top: 3px;
  display: flex; flex-direction: column; gap: 1px;
}
.dd-hm-tick-date { color: var(--app-fg-3); opacity: 0.75; }
.dd-hm-legend { display: flex; gap: 16px; flex-wrap: wrap; font-size: 11px; color: var(--app-fg-3); }
.dd-hm-legend > span { display: inline-flex; align-items: center; gap: 6px; }
.dd-hm-sw { width: 12px; height: 10px; border-radius: 2px; display: inline-block; flex-shrink: 0; }
.dd-hm-sw.fail  { background: var(--app-danger); }
.dd-hm-sw.stale { background: var(--app-warning); }
.dd-hm-sw.anom  { background: var(--app-info); opacity: 0.6; }
.dd-hm-sw.ok    { background: var(--app-success); opacity: 0.35; }
.dd-hm-sw.none  { background: var(--app-bg-sunken); border: 1px solid var(--app-border); }
.dd-hm-tip {
  position: absolute; z-index: 5; transform: translate(-50%, calc(-100% - 8px));
  width: 260px; background: var(--app-bg-elev);
  border: 1px solid var(--app-border); border-radius: var(--radius-md);
  box-shadow: var(--app-shadow-pop); padding: 10px 12px;
  pointer-events: none; display: flex; flex-direction: column; gap: 6px;
}
.dd-hm-tip-head { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--app-fg); }
.dd-hm-tip-head .t { margin-left: auto; font-size: 10px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.dd-hm-tip-runs { display: flex; flex-direction: column; gap: 3px; }
.dd-hm-tip-run { display: flex; align-items: center; gap: 7px; font-size: 11px; color: var(--app-fg-2); font-variant-numeric: tabular-nums; }
.dd-hm-tip-run .t { color: var(--app-fg-3); }
.dd-hm-tip-none { font-size: 11px; color: var(--app-fg-3); }
.dd-hm-tip-issue { font-size: 11px; line-height: 16px; border-radius: var(--radius-sm); padding: 5px 7px; }
.dd-hm-tip-issue.fail  { background: var(--app-danger-bg); color: var(--app-danger-fg); }
.dd-hm-tip-issue.stale { background: var(--app-warning-bg); color: var(--app-warning-fg); }
.dd-hm-tip-issue.anom  { background: var(--app-info-bg); color: var(--app-info-fg, var(--app-fg)); }

/* Freshness bar */
.dd-fresh { display: flex; flex-direction: column; gap: 4px; }
.dd-fresh-track { position: relative; height: 6px; border-radius: var(--radius-pill); background: var(--app-bg-sunken); overflow: hidden; }
/* Named so it can't collide with the kit's `.empty` empty-state component
   (padding: 56px 24px + dashed border), which blew the 6px track up into a
   ~114px bubble on never-run rows. */
.dd-fresh-track-empty { background: repeating-linear-gradient(90deg, var(--app-bg-sunken) 0 6px, transparent 6px 10px); border: 1px dashed var(--app-border-strong); }
.dd-fresh-fill { height: 100%; border-radius: var(--radius-pill); }
.dd-fresh-fill.ok { background: var(--app-success); }
.dd-fresh-fill.warning { background: var(--app-warning); }
.dd-fresh-fill.danger { background: var(--app-danger); }
.dd-fresh-sla { position: absolute; right: 0; top: 0; bottom: 0; width: 2px; background: var(--app-border-strong); }
.dd-fresh-label { font-size: 11px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; }
.dd-fresh-label strong { color: var(--app-fg-2); font-weight: var(--fw-medium); }

/* Volume chart (pipeline detail) */
.dd-vol { display: flex; flex-direction: column; gap: 10px; }
.dd-vol-svg { width: 100%; height: 180px; display: block; }
.dd-vol-grid { stroke: var(--app-border); stroke-width: 1; }
.dd-vol-axis { stroke: var(--app-border-strong); stroke-width: 1; }
.dd-vol-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.dd-vol-title { font-size: 13px; font-weight: var(--fw-bold); color: var(--app-fg); }
.dd-vol-band-label { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--app-fg-3); }
.dd-vol-band-label .swatch { width: 12px; height: 8px; background: var(--app-info-bg); border-radius: 2px; display: inline-block; }
.dd-vol-bar { fill: var(--app-success); opacity: 0.35; }
.dd-vol-bar.warning { fill: var(--app-info); opacity: 0.9; }
.dd-vol-bar.danger { fill: var(--app-danger); opacity: 1; }
.dd-vol-mean { stroke: var(--app-fg-3); stroke-width: 1; stroke-dasharray: 3 3; }
.dd-vol-tick { font-size: 9px; fill: var(--app-fg-3); }

/* Footnote cards */
.dd-untracked {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 12px; line-height: 18px; color: var(--app-fg-2);
  background: var(--app-bg-sunken);
}
.dd-untracked .ic { width: 14px; height: 14px; color: var(--app-fg-3); flex-shrink: 0; margin-top: 1px; }
.dd-untracked a { color: var(--app-fg); text-decoration: underline; cursor: pointer; white-space: nowrap; }

/* Scheduler registry table */
.dd-jobs td, .dd-runlog td { font-size: 12px; }
.mono-num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.dd-job-name { font-weight: var(--fw-bold); color: var(--app-fg); white-space: nowrap; }
.dd-job-tz { font-size: 10px; color: var(--app-fg-3); }
.dd-job-feeds { color: var(--app-fg-2); max-width: 210px; }
.dd-job-untracked { font-size: 11px; color: var(--app-fg-3); font-style: normal; }
.dd-row-running td { background: var(--app-info-bg); }

/* Pipeline detail */
.dd-detail-head { display: flex; flex-direction: column; gap: 16px; }
.dd-detail-title { display: flex; align-items: center; gap: 12px; }
.dd-detail-title > div { flex: 1; }
.dd-detail-title h2 { margin: 0; font-size: 20px; line-height: 26px; }
.dd-detail-meta { display: grid; grid-template-columns: repeat(5, 1fr) 1.4fr; gap: 16px; }
.dd-meta { display: flex; flex-direction: column; gap: 3px; }
.dd-meta .k { font-size: 10px; font-weight: var(--fw-bold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--app-fg-3); }
.dd-meta .v { font-size: 15px; font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; color: var(--app-fg); }
.dd-tile-key { font-size: 11px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; }
.dd-run-detail { max-width: 260px; color: var(--app-fg-2); }
.dd-run-detail .danger-text { color: var(--app-danger); }
.dd-recon { display: flex; flex-direction: column; gap: 10px; }

/* Links (house rule: define defaults) */
.dd-page a { color: var(--app-fg); }
.dd-page a:hover { color: var(--app-fg); }

@media (max-width: 1100px) {
  .dd-kpis { grid-template-columns: repeat(3, 1fr); }
  .dd-detail-meta { grid-template-columns: repeat(2, 1fr); }
}

/* ── DataOps lineage graph ───────────────────────────────────────────── */
.dd-lin-page { max-width: none; width: 100%; }

/* critical-spine ribbon */
.dd-lin-spine-card { display: flex; flex-direction: column; gap: 10px; }
.dd-lin-spine-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.dd-lin-spine-title { font-size: 13px; font-weight: var(--fw-bold); color: var(--app-fg); }
.dd-lin-spine-hint { font-size: 11px; color: var(--app-fg-3); }
.dd-lin-spine { display: flex; align-items: stretch; gap: 6px; flex-wrap: wrap; }
.dd-lin-spine-step { display: flex; flex-direction: column; gap: 2px; padding: 7px 11px; border: 1px solid var(--app-fg-accent); border-radius: var(--radius-md); background: var(--app-bg-elev); min-width: 0; }
.dd-lin-spine-step .k { font-size: 9px; font-weight: var(--fw-bold); letter-spacing: .07em; text-transform: uppercase; color: var(--app-fg-3); }
.dd-lin-spine-step .v { font-size: 12px; font-weight: var(--fw-medium); color: var(--app-fg); white-space: nowrap; }
.dd-lin-spine-arrow { display: flex; align-items: center; color: var(--app-fg-accent); }
.dd-lin-spine-arrow .ic { width: 14px; height: 14px; }

/* canvas + columns */
.dd-lin-scroll { overflow-x: auto; overflow-y: visible; padding-bottom: 4px; }
.dd-lin-canvas { position: relative; min-width: 1180px; }
.dd-lin-cols { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(150px, 1fr); align-items: start; }
.dd-lin-col { display: flex; flex-direction: column; gap: 8px; padding: 0 9px; border-right: 1px solid var(--app-border); min-width: 0; }
.dd-lin-col:last-child { border-right: 0; }
.dd-lin-col-head { display: flex; align-items: center; gap: 7px; padding: 0 2px 6px; }
.dd-lin-col-num { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: var(--radius-xs); background: var(--app-bg-active); color: var(--app-fg-2); font-size: 10px; font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; flex-shrink: 0; }
.dd-lin-col-title { font-size: 11px; font-weight: var(--fw-bold); letter-spacing: .04em; text-transform: uppercase; color: var(--app-fg-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* node card */
.dd-lin-node { position: relative; z-index: 1; display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; padding: 7px 9px; cursor: pointer; border: 1px solid var(--app-border); border-radius: var(--radius-md); background: var(--app-bg-elev); transition: border-color var(--t-fast), box-shadow var(--t-fast), opacity var(--t-fast); }
.dd-lin-node:hover { border-color: var(--app-border-strong); box-shadow: var(--app-shadow-sm); }
.dd-lin-node:focus-visible { outline: none; border-color: var(--app-fg-accent); box-shadow: 0 0 0 3px var(--app-focus-ring); }
.dd-lin-node-ic { display: inline-flex; color: var(--app-fg-3); flex-shrink: 0; }
.dd-lin-node-ic .ic { width: 15px; height: 15px; }
.dd-lin-node-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.dd-lin-node-name { font-size: 12px; font-weight: var(--fw-medium); color: var(--app-fg); line-height: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-lin-node-sub { font-size: 10px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-lin-node .dd-dot { margin-left: auto; }

/* type accents */
.dd-lin-node[data-type="source"] { border-style: dashed; background: var(--app-bg-sunken); }
.dd-lin-node[data-type="blob"] .dd-lin-node-ic,
.dd-lin-node[data-type="fact"] .dd-lin-node-ic,
.dd-lin-node[data-type="cube"] .dd-lin-node-ic { color: var(--app-fg-2); }

/* critical-spine emphasis */
.dd-lin-node[data-spine] { border-color: var(--app-fg-accent); box-shadow: inset 3px 0 0 var(--app-fg-accent); }
.dd-lin-node[data-spine] .dd-lin-node-name { font-weight: var(--fw-bold); }

/* focus / dim states (JS toggles .has-focus / .adj / .focused) */
.dd-lin-canvas.has-focus .dd-lin-node { opacity: .32; }
.dd-lin-canvas.has-focus .dd-lin-node.adj,
.dd-lin-canvas.has-focus .dd-lin-node.focused { opacity: 1; }
.dd-lin-node.focused { border-color: var(--app-fg-accent); box-shadow: 0 0 0 3px var(--app-focus-ring); }

/* edge overlay */
.dd-lin-edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; overflow: visible; }
.dd-lin-edge { fill: none; stroke: var(--app-border-strong); stroke-width: 1.25; opacity: .5; }
.dd-lin-edge.down { stroke: var(--app-fg-accent); stroke-width: 1.75; opacity: .95; }
.dd-lin-edge.up { stroke: var(--app-fg-3); stroke-width: 1.5; opacity: .8; stroke-dasharray: 4 3; }

/* control band */
.dd-lin-control { display: flex; flex-direction: column; gap: 10px; }
.dd-lin-control-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.dd-lin-control-title { font-size: 13px; font-weight: var(--fw-bold); color: var(--app-fg); }
.dd-lin-control-hint { font-size: 11px; color: var(--app-fg-3); }
.dd-lin-ctl-row { display: flex; gap: 8px; flex-wrap: wrap; }
.dd-lin-ctl { display: flex; align-items: center; gap: 7px; padding: 6px 10px; cursor: pointer; border: 1px solid var(--app-border); border-radius: var(--radius-md); background: var(--app-bg-sunken); }
.dd-lin-ctl:hover { border-color: var(--app-border-strong); }
.dd-lin-ctl .ic { width: 14px; height: 14px; color: var(--app-fg-3); flex-shrink: 0; }
.dd-lin-ctl-name { font-size: 11px; font-weight: var(--fw-medium); color: var(--app-fg-2); white-space: nowrap; }

/* legend */
.dd-lin-legend { display: flex; gap: 16px; flex-wrap: wrap; font-size: 11px; color: var(--app-fg-3); align-items: center; }
.dd-lin-legend > span { display: inline-flex; align-items: center; gap: 6px; }
.dd-lin-legend .sw { width: 22px; height: 0; border-top: 2px solid var(--app-fg-accent); display: inline-block; }
.dd-lin-legend .sw.down { border-top: 1.75px solid var(--app-fg-accent); }
.dd-lin-legend .sw.up { border-top: 1.5px dashed var(--app-fg-3); }

/* detail-drawer body bits (reuses .drawer / .overlay-backdrop) */
.dd-lin-dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; font-size: 12px; }
.dd-lin-dl dt { color: var(--app-fg-3); }
.dd-lin-dl dd { margin: 0; color: var(--app-fg); font-variant-numeric: tabular-nums; }
.dd-lin-neigh { display: flex; flex-direction: column; gap: 5px; }
.dd-lin-neigh a { font-size: 12px; color: var(--app-fg); text-decoration: none; display: flex; align-items: center; gap: 6px; }
.dd-lin-neigh a:hover { text-decoration: underline; }
.dd-lin-neigh .ic { width: 12px; height: 12px; color: var(--app-fg-3); }

/* ---- Data catalog (inventory + detail) ---- */
.dd-cat-row { cursor: pointer; }
.dd-cat-name { display: flex; flex-direction: column; gap: 1px; }
.dd-cat-table-name { font-size: 13px; font-weight: var(--fw-bold); color: var(--app-fg); }
.dd-cat-schema { font-size: 11px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; }
.dd-cat-verified .ic { width: 15px; height: 15px; color: var(--app-fg-accent); vertical-align: middle; }

/* Filter bar + table as one connected surface: collapse the fbar's own bottom
   margin (dd-stack already spaces siblings) so the table sits tight under it. */
.dd-cat-controls { display: flex; flex-direction: column; }
.dd-cat-controls .idx-fbar { margin-bottom: 0; }
.dd-cat-controls .dd-cat-wrap { margin-top: 8px; }

/* Sticky-header scroll region — long inventories scroll internally instead of
   pushing the page. table.data th is already position:sticky, so it binds to
   this container's top. overflow-x guards wide content from scrolling the body. */
.dd-cat-scroll { max-height: 60vh; overflow-y: auto; overflow-x: auto; }
.dd-cat-foot-meta { color: var(--app-fg-3); font-variant-numeric: tabular-nums; }

/* detail header */
.dd-cat-badges { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 8px; }
.dd-cat-link { display: inline-flex; align-items: center; gap: 5px; color: var(--app-fg-accent); text-decoration: none; font-weight: var(--fw-medium); }
.dd-cat-link:hover { text-decoration: underline; }
.dd-cat-link .ic { width: 14px; height: 14px; }

/* about (description + tags) */
.dd-cat-about { display: grid; grid-template-columns: 1.6fr 1fr; gap: 24px; padding-top: 16px; border-top: 1px solid var(--app-border); }
.dd-cat-about-block { display: flex; flex-direction: column; gap: 6px; }
.dd-cat-about-block .k { font-size: 10px; font-weight: var(--fw-bold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--app-fg-3); }
.dd-cat-descbody { margin: 0; font-size: 13px; line-height: 20px; color: var(--app-fg-2); }
.dd-cat-tags { display: flex; flex-wrap: wrap; gap: 6px; }

/* columns table */
.dd-cat-colname { font-family: var(--font-mono, monospace); font-size: 12px; font-weight: var(--fw-medium); color: var(--app-fg); }
.dd-cat-notnull { font-size: 12px; color: var(--app-fg-2); }

/* drift section — visually secondary */
.dd-cat-drift-sect { margin-top: 8px; }
.dd-cat-drift { opacity: 0.85; }
.dd-cat-desc { font-size: 12px; color: var(--app-fg-2); }

/* edit drawer: form fills the drawer so the body scrolls, footer pins */
.drawer-form { display: flex; flex-direction: column; flex: 1; min-height: 0; }

/* ---- Business glossary (list + detail) — reuses the catalog table shell ---- */
.dd-gloss-term { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dd-gloss-dev { flex-shrink: 0; }
.dd-gloss-def { font-size: 12px; color: var(--app-fg-2); line-height: 18px; max-width: 40ch; }
.dd-gloss-src { font-family: var(--font-mono, monospace); font-size: 12px; color: var(--app-fg-2); }
.dd-gloss-tables { display: flex; flex-wrap: wrap; gap: 4px; }
.dd-gloss-tbl { font-family: var(--font-mono, monospace); font-size: 11px; color: var(--app-fg-2); background: var(--app-bg-sunken); border-radius: var(--radius-sm); padding: 1px 6px; }
/* formula callout — the gross-vs-net wording lives here; keep it readable */
.dd-gloss-callout { align-items: flex-start; }
.dd-gloss-callout .desc { white-space: pre-line; }
/* related-table / business-term links, wrapping */
.dd-gloss-links { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.dd-cat-terms { padding-top: 16px; border-top: 1px solid var(--app-border); }

@media (max-width: 900px) {
  .dd-cat-about { grid-template-columns: 1fr; gap: 16px; }
}

/* ---- Data quality (scorecard + detail) — reuses the catalog table shell ---- */
/* Scorecard: count cells recolour only when something is failing (a plain 0/N
   count stays neutral; the status badge already carries the row's severity). */
.dd-q-num { font-weight: var(--fw-bold); }
.dd-q-num.tone-warning { color: var(--app-warning-fg); }
.dd-q-num.tone-danger  { color: var(--app-danger); }

/* Detail: one card per check + a compact pass/fail history timeline. */
.dd-q-check { display: flex; flex-direction: column; gap: 12px; }
.dd-q-check-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.dd-q-check-id { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dd-q-check-name { font-family: var(--font-mono, monospace); font-size: 13px; font-weight: var(--fw-bold); color: var(--app-fg); }
.dd-q-check-detail { margin: 0; font-size: 13px; line-height: 20px; color: var(--app-fg-2); }
.dd-q-tl { display: flex; align-items: center; gap: 12px; padding-top: 12px; border-top: 1px solid var(--app-border); }
.dd-q-tl-label { font-size: 10px; font-weight: var(--fw-bold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--app-fg-3); flex-shrink: 0; }
.dd-q-tl-dots { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; flex: 1; }
.dd-q-tl-dot { width: 12px; height: 12px; border-radius: var(--radius-sm); flex-shrink: 0; cursor: default; }
.dd-q-tl-dot.tone-success { background: var(--app-success); }
.dd-q-tl-dot.tone-warning { background: var(--app-warning); }
.dd-q-tl-dot.tone-danger  { background: var(--app-danger); }
.dd-q-tl-when { font-size: 11px; color: var(--app-fg-3); font-variant-numeric: tabular-nums; white-space: nowrap; flex-shrink: 0; }
