@font-face {
  font-family: 'Google Sans';
  src: url('../fonts/GoogleSans-VariableFont_GRAD,opsz,wght.ttf') format('truetype');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Google Sans';
  src: url('../fonts/GoogleSans-Italic-VariableFont_GRAD,opsz,wght.ttf') format('truetype');
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

:root {
  /* Flat 2D theme — white surface everywhere, no drop shadows on
     page-level elements. Floating elements (modals, popovers, FAB)
     keep their own inline shadows defined on each rule. */
  --bg: #ffffff;
  --surface: #ffffff;
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --secondary: #64748b;
  --success: #16a34a;
  --warning: #d97706;
  --danger: #dc2626;
  --border: #cbd5e1;
  --text: #1e293b;
  --text-muted: #64748b;
  --radius: 8px;
  --shadow: none;
  --shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
  /* Lock the page to the visual viewport so iOS Safari's address bar
   * doesn't cause the whole HTML to scroll/inset. The inner panes
   * (#content, sidebar nav, etc.) own their own scrolling. */
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-overflow-scrolling: touch;
}
body { font-family: 'Google Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); font-size: 14px; }

/* Layout */
/* Use dynamic viewport units so the app fits exactly the visible area
 * on mobile browsers where the toolbar grows/shrinks. Falls back to
 * 100vh on browsers that don't support dvh. */
#app { display: flex; height: 100vh; height: 100dvh; overflow: hidden; }
#sidebar { width: var(--sidebar-width, 220px); background: #111827; color: #cbd5e1; display: flex; flex-direction: column; flex-shrink: 0; transition: width 0.2s ease; overflow: hidden; position: relative; height: 100vh; height: 100dvh; }
#sidebar.collapsed { width: 48px; }
#sidebar.resizing { transition: none; }
#sidebar-resizer {
  position: absolute; right: 0; top: 0; height: 100%; width: 5px;
  cursor: col-resize; z-index: 20; background: transparent;
}
#sidebar-resizer:hover, #sidebar-resizer.dragging { background: rgba(255,255,255,0.15); }
#sidebar .logo { padding: 12px 14px; min-height: 60px; font-size: 17px; font-weight: 700; color: #fff; border-bottom: 1px solid #1f2937; display: flex; align-items: center; gap: 10px; flex-shrink: 0; cursor: pointer; transition: background 0.15s; }
#sidebar .logo:hover { background: #1f2937; }
#sidebar .logo .logo-mark { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
#sidebar .logo .logo-mark svg { display: block; }
#sidebar .logo .logo-text { white-space: nowrap; overflow: hidden; letter-spacing: -0.01em; }
#sidebar .logo .logo-text span { color: #60a5fa; }
#sidebar.collapsed .logo .logo-text { display: none; }
#sidebar nav { padding: 8px; flex: 1; overflow-y: auto; overflow-x: hidden; scrollbar-width: thin; scrollbar-color: #374151 transparent; }
#sidebar nav::-webkit-scrollbar { width: 6px; }
#sidebar nav::-webkit-scrollbar-track { background: transparent; }
#sidebar nav::-webkit-scrollbar-thumb { background: #374151; border-radius: 3px; }
#sidebar nav::-webkit-scrollbar-thumb:hover { background: #4b5563; }
.nav-section { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: #475569; padding: 8px 8px 4px; white-space: nowrap; overflow: hidden; }
#sidebar.collapsed .nav-section { opacity: 0; height: 0; padding: 0; margin: 8px 12px; border-top: 1px solid #1f2937; }
#sidebar.collapsed .nav-section:first-of-type { display: none; }
#sidebar.collapsed .logo { padding: 12px 0; justify-content: center; }
#sidebar.collapsed nav { padding: 12px 0; }
#sidebar.collapsed .nav-item { padding: 8px 14px; gap: 0; font-size: 0; }
#sidebar.collapsed .nav-item .icon { width: 20px; margin: 0; font-size: 16px; }
.nav-item { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 6px; cursor: pointer; font-size: 13.5px; margin-bottom: 2px; transition: background 0.15s; white-space: nowrap; }
.nav-item:hover { background: #1f2937; color: #f1f5f9; }
.nav-item.active { background: #2563eb; color: #fff; }
/* Entity-count chip on the right side of nav items. At-a-glance "how
   much do I have of each thing" without opening every page. Updated
   on each navigate() so the count stays fresh. Hidden on collapsed
   sidebar (no room) and when the count is 0 (would just be noise). */
.nav-item .nav-count {
  margin-left: auto;
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  color: #64748b;
  background: rgba(148, 163, 184, 0.12);
  border-radius: 9999px;
  padding: 1px 7px;
  min-width: 18px;
  text-align: center;
  flex-shrink: 0;
  transition: color 0.15s, background 0.15s;
}
.nav-item:hover .nav-count { color: #cbd5e1; background: rgba(148, 163, 184, 0.2); }
.nav-item.active .nav-count { color: rgba(255, 255, 255, 0.85); background: rgba(255, 255, 255, 0.18); }
#sidebar.collapsed .nav-count { display: none; }
.nav-item .icon { font-size: 16px; width: 20px; text-align: center; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; }
.nav-item .icon img { width: 18px; height: 18px; object-fit: contain; }
.btn .print-icon { width: 14px; height: 14px; vertical-align: -2px; object-fit: contain; display: inline-block; padding: 0; }
.btn .dl-icon { width: 14px; height: 14px; vertical-align: -2px; object-fit: contain; display: inline-block; padding: 0; }
.btn .search-icon { width: 13px; height: 13px; vertical-align: -2px; object-fit: contain; display: inline-block; padding: 0; }
/* Sort icon — pair of up/down arrows on the toolbar Sort button.
   Slightly taller than .dl-icon because the glyph is vertical. */
.btn .sort-icon { width: 12px; height: 14px; vertical-align: -2px; object-fit: contain; display: inline-block; padding: 0; }
/* Formula reference inside a list cell — reads as text by default,
   only adopts link styling on hover. Reduces "every cell looks
   clickable" visual noise in dense tables while keeping one-click
   drill-in for users who deliberately want it. */
.formula-cell-link {
  color: var(--text);
  cursor: pointer;
  text-decoration: none;
  border-bottom: 1px dotted transparent;
  transition: color 0.12s, border-color 0.12s;
}
.formula-cell-link:hover {
  color: var(--primary);
  border-bottom-color: var(--primary);
}

/* Hover-popover preview card — single global element re-used for
   every formula-cell-link. Positioned via JS, fades in/out. */
.formula-popover {
  position: fixed;
  z-index: 200;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: 12px 14px;
  width: 280px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
}
.formula-popover.on { opacity: 1; pointer-events: auto; }
.formula-popover-title {
  font-weight: 600;
  font-size: 13.5px;
  margin-bottom: 4px;
  color: #0f172a;
  word-break: break-word;
}
.formula-popover-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 6px 0;
}
.formula-popover-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px 12px;
  font-size: 11.5px;
  color: #64748b;
  margin: 8px 0 4px;
  padding-top: 8px;
  border-top: 1px solid #f1f5f9;
}
.formula-popover-stats strong { color: var(--text); font-weight: 600; }
.formula-popover-footer {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid #f1f5f9;
  display: flex;
  justify-content: flex-end;
  font-size: 12px;
}
.formula-popover-footer a {
  color: var(--primary);
  text-decoration: none;
  cursor: pointer;
}
.formula-popover-footer a:hover { text-decoration: underline; }

/* Inline replacement for an emoji glyph in body text — same visual
   weight as a 13-14px emoji. Used wherever we swap 🧪 / 📊 / 📈 etc.
   for a proper PNG (card-view counts, section headers, workspace
   buttons). The smaller .emoji-icon-sm version matches 11.5-12px
   text contexts (card-view badge rows). */
.emoji-icon    { width: 14px; height: 14px; vertical-align: -3px; object-fit: contain; display: inline-block; }
.emoji-icon-sm { width: 12px; height: 12px; vertical-align: -2px; object-fit: contain; display: inline-block; }
/* The h2 section headers (16px) deserve a slightly larger glyph */
.emoji-icon-lg { width: 18px; height: 18px; vertical-align: -4px; object-fit: contain; display: inline-block; margin-right: 4px; }
/* clipboard.png and file.png are intentionally WHITE-on-transparent
   (their primary use is the dark navy sidebar nav icons). When
   re-used as inline .emoji-icon* glyphs on light-background buttons
   / headers / dropdowns, they'd be invisible without inversion.
   filter: brightness(0) knocks all luminosity to zero, turning the
   white pixels black while leaving the transparent background alone.
   Sidebar usage is bare <img> with no .emoji-icon* class so this
   selector doesn't touch it. */
.emoji-icon[src$="clipboard.png"],
.emoji-icon-sm[src$="clipboard.png"],
.emoji-icon-lg[src$="clipboard.png"],
.emoji-icon[src$="file.png"],
.emoji-icon-sm[src$="file.png"],
.emoji-icon-lg[src$="file.png"] { filter: brightness(0); }
/* Column-header sort indicators — three states (none/up/down). Sized
   to match the height of the header text so they sit on the baseline. */
.th-sort-icon { width: 12px; height: 14px; vertical-align: -3px; object-fit: contain; display: inline-block; margin-left: 4px; flex-shrink: 0; }
/* The printer / download PNG assets are dark-on-transparent (designed   */
/* for light .btn-secondary backgrounds). On .btn-print (dark navy bg)  */
/* the dark icon was invisible. Invert to white in that context so the  */
/* icon shows on the dark button. Same trick for .dl-icon in case any   */
/* download buttons ever pair with .btn-print.                           */
.btn-print .print-icon,
.btn-print .dl-icon,
.btn-print .sort-icon { filter: brightness(0) invert(1); }
/* Inline SVG icons — uses stroke:currentColor so they adapt to text */
/* color (dark-mode aware for free). 14px matches the PNG icon size. */
.svg-icon { width: 14px; height: 14px; vertical-align: -3px; display: inline-block; flex-shrink: 0; }
.btn .svg-icon { width: 14px; height: 14px; vertical-align: -3px; }
/* Sidebar nav uses a larger icon to match the 18px PNG nav glyphs. */
.nav-item .icon .svg-icon { width: 18px; height: 18px; vertical-align: middle; }
/* Card kebab menu items have a touch more breathing room. */
.ing-card-kebab-menu .svg-icon { margin-right: 4px; }
#sidebar .sidebar-footer { padding: 8px; border-top: 1px solid #1f2937; flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; gap: 6px; }
#sidebar.collapsed .sidebar-footer { justify-content: center; padding: 8px 0; flex-direction: column; gap: 6px; }
#sidebar .sidebar-footer .sidebar-toggle { background: none; border: none; color: #94a3b8; cursor: pointer; font-size: 16px; width: 36px; height: 32px; display: flex; align-items: center; justify-content: center; line-height: 1; border-radius: 6px; transition: color 0.15s, background 0.15s; flex-shrink: 0; }
#sidebar .sidebar-footer .sidebar-toggle:hover { color: #fff; background: #1f2937; }
#sidebar .sidebar-footer .sidebar-account {
  background: none; border: none; color: #cbd5e1; cursor: pointer;
  display: flex; align-items: center; gap: 8px; padding: 4px 8px;
  border-radius: 6px; font-family: inherit; font-size: 13px;
  min-width: 0; flex: 1 1 auto; transition: background 0.15s, color 0.15s;
}
#sidebar .sidebar-footer .sidebar-account:hover { background: #1f2937; color: #fff; }
.sidebar-account-avatar {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--primary); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; flex-shrink: 0;
}
.sidebar-account-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#sidebar.collapsed .sidebar-account-label { display: none; }
#sidebar.collapsed .sidebar-account { padding: 4px; }

/* ============================================================
 * DOE Matrix toolbar — grouped, workflow-ordered controls
 * ============================================================ */
/* Top-of-page tab bar for the DOE Matrix view — switches between
 * the Analyze (matrix table) and Generate (design generator) modes.
 * Two big peer buttons with icon, label, and a one-line subtitle. */
.asm-matrix-tabs {
  display: flex; gap: 6px;
  /* Tab bar bottoms out flush against the colored accent strip below.
   * No bottom border, no rounded bottom corners — accent strip takes
   * over so the active tab's color "flows" into the page area. */
  margin-bottom: 0;
  padding: 4px;
  background: #f1f5f9;
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: 10px 10px 0 0;
}
/* Thin colored strip rendered immediately after the tab bar. Picks
 * up the active tab's color so the eye connects "this page belongs
 * to that tab". Stands alone so anything below (guide, toolbar card,
 * Generate page) can render normally without needing accent-aware
 * classes of their own. */
.asm-matrix-page-accent {
  height: 4px;
  margin-bottom: 12px;
  background: var(--border);
  border-radius: 0 0 6px 6px;
}
.asm-matrix-page-accent.analyze  { background: var(--primary); }
.asm-matrix-page-accent.generate { background: #059669; }
.asm-matrix-tab {
  flex: 1;
  display: flex; flex-direction: row; align-items: center; gap: 10px;
  padding: 10px 16px;
  background: transparent; color: #475569;
  border: 1px solid transparent;
  border-radius: 7px;
  font-family: inherit; font-size: 13.5px; font-weight: 600;
  cursor: pointer;
  text-align: left;
  transition: background 0.12s, color 0.12s, box-shadow 0.12s;
}
.asm-matrix-tab:hover { background: rgba(255,255,255,0.6); color: #0f172a; }
/* Per-tab active colors — blue for Analyze, emerald for Generate.
 * Mirrors the headline-CTA palette so the same visual identity
 * follows each mode whether it's an active button or an active tab. */
.asm-matrix-tab-analyze.on {
  background: var(--primary); color: #fff;
  border-color: var(--primary);
  box-shadow: 0 1px 3px rgba(37, 99, 235, 0.28);
}
.asm-matrix-tab-generate.on {
  background: #059669; color: #fff;
  border-color: #059669;
  box-shadow: 0 1px 3px rgba(5, 150, 105, 0.30);
}
.asm-matrix-tab-icon  { font-size: 16px; line-height: 1; }
.asm-matrix-tab-label { font-size: 14px; font-weight: 700; }
.asm-matrix-tab-sub   { font-size: 11px; font-weight: 400; color: #94a3b8; }
.asm-matrix-tab.on .asm-matrix-tab-sub { color: rgba(255, 255, 255, 0.82); }

/* Dismiss button on the DOE Matrix "HOW TO BUILD" guide banner.       */
/* Made more discoverable than a plain text × with no affordance: rest */
/* state shows a subtle 1px border so it reads as a button, hover      */
/* brightens it to make the click target obvious. Recovery is via the  */
/* "? Help" button that appears in the topbar after dismiss.           */
.asm-guide-dismiss {
  position: absolute; top: 8px; right: 8px;
  width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid #c7d2fe;
  color: #4338ca;
  border-radius: 6px;
  cursor: pointer;
  font-size: 18px; line-height: 1;
  padding: 0;
  transition: background 0.12s, border-color 0.12s, color 0.12s, transform 0.12s;
}
.asm-guide-dismiss:hover {
  background: #fff;
  border-color: #6366f1;
  color: #312e81;
  transform: translateY(-1px);
}

.asm-toolbar-card { margin-bottom: 12px; padding: 12px 16px; }
.asm-toolbar {
  display: flex; align-items: flex-start; justify-content: space-between;
  flex-wrap: wrap; gap: 12px;
}
.asm-toolbar-left {
  display: flex; flex-wrap: wrap;
  align-items: stretch;
  gap: 0; row-gap: 10px;
  flex: 1; min-width: 0;
}
.asm-toolbar-right { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
/* Each workflow step row: [step] [LABEL] [controls]
 * Step + label have fixed widths so the controls start at the same X
 * position across every row when the toolbar wraps vertically. */
.asm-toolbar-group {
  display: flex; align-items: center; gap: 8px;
  padding: 0 14px;
  min-height: 34px;
}
.asm-toolbar-group:first-child { padding-left: 0; }
.asm-toolbar-divider {
  width: 1px; background: var(--border);
  margin: 4px 0; align-self: stretch; flex-shrink: 0;
}
.asm-toolbar-step {
  font-size: 11px; font-weight: 700;
  width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #f1f5f9; color: #64748b;
  border-radius: 50%;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.asm-toolbar-grouplbl {
  font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: #475569;
  flex-shrink: 0;
}
.asm-toolbar-controls {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}
/* Beat the global "input, select, textarea { width: 100% }" rule */
.asm-toolbar select.asm-toolbar-select,
.asm-toolbar-controls select.asm-toolbar-select {
  width: auto; max-width: 280px;
  padding: 5px 8px; border: 1px solid var(--border);
  border-radius: 5px; font-size: 12.5px; background: #fff;
  font-family: inherit; color: var(--text);
  text-transform: none; letter-spacing: normal;
  min-height: 28px;
}
/* When toolbar wraps to stacked vertical rows, align every row's
 * controls at the same X by giving step+label a fixed reserved width. */
@media (min-width: 769px) {
  .asm-toolbar-left { flex-direction: column; align-items: stretch; }
  .asm-toolbar-group {
    width: 100%; padding: 0;
    display: grid;
    grid-template-columns: 26px 88px 1fr;
    gap: 8px;
    align-items: center;
  }
  .asm-toolbar-divider { display: none; }
}
.asm-toolbar-toggle.on {
  background: #dbeafe !important;
  border-color: #3b82f6 !important;
  color: #1d4ed8 !important;
}

/* The headline Analyze CTA — primary-colored, with subtitle, prominent */
.btn-doe-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 16px;
  background: var(--primary); color: #fff;
  border: none; border-radius: 7px;
  font-family: inherit; font-size: 13.5px; font-weight: 600;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(37, 99, 235, 0.25), 0 0 0 0 rgba(37, 99, 235, 0);
  transition: background 0.15s, transform 0.1s, box-shadow 0.15s;
  position: relative;
}
.btn-doe-cta:hover {
  background: var(--primary-dark);
  box-shadow: 0 3px 8px rgba(37, 99, 235, 0.35), 0 0 0 4px rgba(37, 99, 235, 0.10);
  transform: translateY(-1px);
}
.btn-doe-cta:active { transform: translateY(0); }
.btn-doe-cta-icon { font-size: 16px; line-height: 1; }
.btn-doe-cta-sub {
  font-size: 10px; font-weight: 500; opacity: 0.85;
  margin-left: 4px; padding-left: 8px;
  border-left: 1px solid rgba(255, 255, 255, 0.3);
}
/* Alt variant — paired with the primary Analyze CTA. Same shape +
 * elevation so it reads as a peer action, but emerald-green to
 * differentiate "generate a new experiment" from "analyze results". */
.btn-doe-cta-alt {
  background: #059669;   /* emerald-600 */
  box-shadow: 0 1px 3px rgba(5, 150, 105, 0.28), 0 0 0 0 rgba(5, 150, 105, 0);
}
.btn-doe-cta-alt:hover {
  background: #047857;   /* emerald-700 */
  box-shadow: 0 3px 8px rgba(5, 150, 105, 0.38), 0 0 0 4px rgba(5, 150, 105, 0.12);
}

/* Zoom pill */
.asm-zoom-pill {
  display: inline-flex; align-items: center; gap: 4px;
  background: #fff; border: 1px solid var(--border);
  border-radius: 6px; padding: 2px 6px;
}
.asm-zoom-btn {
  background: none; border: none; cursor: pointer;
  padding: 2px 6px; font-size: 14px; line-height: 1;
  color: #64748b; font-weight: 600; font-family: inherit;
}
.asm-zoom-btn:hover { color: var(--primary); }
.asm-zoom-range { width: 90px; cursor: pointer; }
.asm-zoom-reset {
  background: none; border: none; cursor: pointer;
  padding: 2px 6px; font-size: 11px; line-height: 1;
  color: #64748b; border-left: 1px solid var(--border);
  font-family: inherit; min-width: 42px;
}
.asm-zoom-reset:hover { color: var(--primary); }

@media (max-width: 1100px) {
  /* On medium screens, hide subtitles to keep CTA compact */
  .btn-doe-cta-sub { display: none; }
  .asm-toolbar-grouplbl { display: none; }
}
@media (max-width: 768px) {
  .asm-toolbar-divider { display: none; }
  .asm-toolbar-group { padding: 0; width: 100%; flex-wrap: wrap; }
  .asm-toolbar-step { display: none; }
}

/* ============================================================
 * DOE Matrix status bar — bottom strip with counts + zoom + export
 * ============================================================ */
.asm-statusbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 8px 14px;
  background: #f8fafc;
  border: 1px solid var(--border);
  border-top: 1px solid #e2e8f0;
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  font-size: 11.5px; color: #475569;
}
.asm-statusbar-left {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
}
.asm-statusbar-left strong { color: #0f172a; font-weight: 600; }
.asm-statusbar-sep { color: #cbd5e1; }
.asm-statusbar-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

/* Mini dot-plot strip rendered inside the column header band when the
 * "Distributions" toolbar toggle is on. One dot per row at its value's
 * relative position along the column's min–max range. */
.asm-col-dist {
  margin-top: 6px;
  padding-top: 4px;
  border-top: 1px dashed rgba(0, 0, 0, 0.08);
  user-select: none;
}
.asm-col-dist-empty {
  height: 24px;
}
.asm-col-dist-track {
  position: relative;
  height: 12px;
  background: rgba(0, 0, 0, 0.03);
  border-radius: 2px;
}
.asm-col-dist-dot {
  position: absolute;
  top: 50%;
  width: 5px; height: 5px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  opacity: 0.7;
}
.asm-col-dist-dot:hover { opacity: 1; outline: 1.5px solid #0f172a; }
.asm-col-dist-range {
  display: flex; justify-content: space-between;
  font-size: 9.5px; color: rgba(0, 0, 0, 0.45);
  font-variant-numeric: tabular-nums; font-weight: 500;
  margin-top: 2px; padding: 0 1px;
  text-transform: none; letter-spacing: normal;
}
.asm-col-dist-nodata {
  font-size: 9.5px; color: #cbd5e1; font-weight: 500;
  font-style: italic;
}

/* ============================================================
 * DOE Matrix table — user-resizable column widths
 * ============================================================ */
.asm-col-resizer {
  position: absolute;
  top: 0; bottom: 0;
  right: -3px;
  width: 6px;
  cursor: col-resize;
  z-index: 4;
  background: transparent;
  transition: background 0.12s ease;
}
.asm-col-resizer:hover,
.asm-col-resizer:active {
  background: rgba(37, 99, 235, 0.35);
}
/* While a drag is in progress, lock everyone to the resize cursor */
body.asm-resizing, body.asm-resizing * { cursor: col-resize !important; user-select: none !important; }

/* ============================================================
 * DOE Filter-by-Formula modal — same workflow numbering as the
 * toolbar: ① Find → ② Filter → ③ Select
 * ============================================================ */
.asm-filter-grid {
  display: grid;
  grid-template-columns: 26px 88px 1fr;
  gap: 10px 12px;
  align-items: start;
}
.asm-filter-step {
  font-size: 11px; font-weight: 700;
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #f1f5f9; color: #64748b;
  border-radius: 50%;
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}
.asm-filter-title {
  font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: #475569;
  padding-top: 4px;
}
.asm-filter-body {
  display: flex; flex-direction: column; gap: 8px;
  min-width: 0;
}
/* Step ① row: search input + group dropdown side-by-side */
.asm-filter-body .asm-filter-search,
.asm-filter-grid input.asm-filter-search {
  flex: 1; min-width: 200px;
  padding: 7px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font-size: 13px; font-family: inherit;
  width: auto;
}
.asm-filter-body > .asm-filter-search { flex: 0 0 auto; }
.asm-filter-grid .asm-filter-body:first-of-type {
  /* The Find row is single-line: search input + group label inline */
  flex-direction: row; align-items: center; gap: 10px; flex-wrap: wrap;
}
.asm-filter-inline-lbl {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
  color: #64748b;
  white-space: nowrap;
}
.asm-filter-grid select.asm-filter-mini-select {
  width: auto;
  padding: 5px 8px; border: 1px solid var(--border);
  border-radius: 5px; font-size: 12.5px; background: #fff;
  font-family: inherit; color: var(--text);
  text-transform: none; letter-spacing: normal;
}
/* Step ② sub-rows: PROJECT / TYPE / DOE FACTOR / RANGE labels in a sub-grid */
.asm-filter-subrow {
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: 8px;
  align-items: start;
}
.asm-filter-subrow-range {
  padding-top: 8px;
  border-top: 1px dashed var(--border);
}
.asm-filter-sublbl {
  font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: #64748b;
  padding-top: 5px;
}
.asm-filter-subchips {
  display: flex; flex-wrap: wrap; gap: 6px;
  align-items: center;
  min-width: 0;
}
.asm-filter-grid select.asm-filter-range-col {
  width: auto; max-width: 240px;
  padding: 4px 8px; border: 1px solid var(--border);
  border-radius: 4px; font-size: 12px;
  font-family: inherit; background: #fff;
  text-transform: none; letter-spacing: normal;
}
.asm-filter-grid input.asm-filter-range-num {
  width: 70px;
  padding: 4px 6px; border: 1px solid var(--border);
  border-radius: 4px; font-size: 12px;
  font-family: inherit;
  text-transform: none; letter-spacing: normal;
}
.asm-filter-similar-banner {
  display: flex; align-items: center; gap: 8px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 12px;
  grid-column: 1 / -1;  /* span all columns when inside the subrows body */
}
/* Step ③: bulk action row + list */
.asm-filter-bulk-row {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.asm-filter-count {
  font-size: 11.5px; color: #64748b;
  margin-left: auto;
}
.asm-filter-list {
  max-height: 440px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 6px;
  background: #fafafa;
  padding: 6px;
}
@media (max-width: 600px) {
  .asm-filter-grid { grid-template-columns: 22px 1fr; }
  .asm-filter-title { grid-column: 2; }
  .asm-filter-body  { grid-column: 1 / -1; }
  .asm-filter-subrow { grid-template-columns: 1fr; }
  .asm-filter-sublbl { padding-top: 0; }
}

/* ============================================================
 * DOE Analyze workspace — full-screen overlay with chart + stats
 * ============================================================ */
.asm-analyze-overlay {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 200;
  padding: 24px;
}
.asm-analyze-panel {
  background: #fff;
  width: 100%; max-width: 1400px; height: 92vh;
  border-radius: 10px; overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
  border: 1px solid var(--border);
}
.asm-analyze-header {
  padding: 12px 16px; background: #f8fafc; color: #0f172a;
  display: flex; align-items: center; justify-content: space-between;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}
.asm-analyze-header strong { color: #0f172a; }
.asm-analyze-tabs { display: flex; gap: 4px; }
.asm-analyze-tabs .asm-tab {
  background: transparent; color: #475569;
  border: 1px solid var(--border); border-radius: 6px;
  padding: 5px 12px; font-size: 12.5px; font-weight: 500;
  cursor: pointer; transition: background 0.15s, color 0.15s;
  font-family: inherit;
}
.asm-analyze-tabs .asm-tab:hover { background: #e2e8f0; color: #0f172a; }
.asm-analyze-tabs .asm-tab.on { background: #0f172a; color: #fff; border-color: #0f172a; }
.asm-analyze-close {
  background: transparent; color: #475569; border: none;
  font-size: 18px; cursor: pointer; padding: 4px 8px; border-radius: 4px;
}
.asm-analyze-close:hover { background: #e2e8f0; color: #0f172a; }
/* Presentation-mode toggles in the workspace header (top-right).
 * Available from any tab — dark mode and color-blind palette. */
.asm-header-toggle {
  background: transparent; color: #475569;
  border: 1px solid var(--border); border-radius: 6px;
  padding: 4px 10px; font-size: 11.5px; font-weight: 500;
  cursor: pointer; font-family: inherit;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.asm-header-toggle:hover { background: #e2e8f0; color: #0f172a; }
.asm-header-toggle.on {
  background: #0f172a; color: #fff; border-color: #0f172a;
}
.asm-analyze-body { flex: 1; display: flex; min-height: 0; }
.asm-analyze-sidebar {
  position: relative;
  width: 260px; flex-shrink: 0;
  background: #f8fafc; border-right: 1px solid var(--border);
  /* Extra bottom padding so the last section (currently Diagnostics)
     doesn't butt against the scroll edge — gives a comfortable
     breathing room at the end of the scrollable area. */
  padding: 12px 14px 32px 14px; overflow-y: auto;
  transition: width 0.18s ease, padding 0.18s ease;
}
/* Collapse-to-strip: keeps the toggle button visible so the panel
 * stays discoverable instead of disappearing entirely. The contents
 * stay in the DOM (just hidden) so the mobile breakpoint can re-show
 * them without re-rendering. */
.asm-analyze-sidebar.asm-sidebar-collapsed {
  width: 36px;
  padding: 10px 0;
  overflow: hidden;
}
.asm-analyze-sidebar.asm-sidebar-collapsed .asm-sidebar-contents { display: none; }
/* Toggle button — small chevron floating at top-right of the sidebar
 * when expanded; centers in the strip when collapsed. */
.asm-sidebar-toggle {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: #fff;
  color: #475569;
  font-size: 14px; line-height: 1; padding: 0;
  cursor: pointer;
  z-index: 2;
  font-family: inherit;
  transition: background 0.15s, color 0.15s;
}
.asm-sidebar-toggle:hover { background: #e2e8f0; color: #0f172a; }
.asm-sidebar-collapsed .asm-sidebar-toggle {
  position: static;
  margin: 0 auto;
}
body.asm-darkplots .asm-sidebar-toggle {
  background: #1f2937; border-color: #374151; color: #cbd5e1;
}
body.asm-darkplots .asm-sidebar-toggle:hover { background: #374151; color: #fff; }
.asm-analyze-main {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  padding: 14px;
  background: #fff;
  overflow: hidden;
}
/* When the heatmap view is showing, allow the main pane to scroll so the
 * correlations list below the grid is reachable. (Scatter view stays
 * non-scrolling because its chart sizes to flex available space.) */
.asm-analyze-main:has(#asm-heatmap-wrap),
.asm-analyze-main:has(.asm-heatmap-wrap) {
  overflow-y: auto;
}
.asm-side-section { padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px dashed var(--border); }
.asm-side-section:last-child { border-bottom: none; }
.asm-side-title {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: #64748b; margin-bottom: 8px;
}
/* Field labels: keep uppercase styling that matches the global label rule,
 * but lock down the size + spacing so they fit our narrow sidebar. */
.asm-analyze-sidebar label.asm-side-label {
  display: block; font-size: 11px; color: #475569; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
  margin-bottom: 8px;
}
/* Select inside a labelled field — beat the global input/select rule */
.asm-analyze-sidebar .asm-side-label select,
.asm-analyze-sidebar select.asm-side-select {
  width: 100%; margin-top: 4px;
  padding: 6px 8px; border: 1px solid var(--border);
  border-radius: 5px; font-size: 12.5px; font-family: inherit;
  font-weight: 400; letter-spacing: normal; text-transform: none;
  color: var(--text); background: #fff;
}
/* Numeric inputs (X min, X max, …) — also beat the global rule */
.asm-analyze-sidebar input.asm-side-input {
  width: 100%; padding: 6px 8px; border: 1px solid var(--border);
  border-radius: 5px; font-size: 12px; font-family: inherit;
  font-weight: 400; letter-spacing: normal; text-transform: none;
}
.asm-analyze-sidebar input.asm-side-input::placeholder {
  text-transform: none; letter-spacing: normal; color: #94a3b8;
}
/* Inline checkbox labels: keep them sentence case so the checkbox reads
 * naturally next to its text. Also constrain the checkbox to its native
 * size — the global input rule was stretching it to 100% width. */
.asm-analyze-sidebar label.asm-side-check {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: #475569; cursor: pointer; margin-top: 6px;
  font-weight: 500;
  text-transform: none; letter-spacing: normal;
  white-space: nowrap;
}
.asm-analyze-sidebar label.asm-side-check input[type="checkbox"] {
  width: 14px; height: 14px; padding: 0; margin: 0; flex-shrink: 0;
  accent-color: var(--primary);
}
/* Range-input grids (X min/max, Y min/max) — make sure the two columns
 * actually let inputs shrink to fit instead of overflowing. */
.asm-analyze-sidebar .asm-side-grid-2 {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 6px;
}
/* Help text boxes — same recessed-card design as the 3D stats panel
 * (same bg, border, radius, padding) so the sidebar reads consistently. */
.asm-side-help {
  font-size: 11.5px; color: #475569; line-height: 1.45;
  background: #f8fafc; border: 1px solid var(--border);
  border-radius: 6px; padding: 10px 12px;
}
.asm-toggle-group {
  display: flex; gap: 4px; margin-bottom: 8px;
  border: 1px solid var(--border); background: #f8fafc;
  border-radius: 6px; padding: 2px;
}
.asm-toggle {
  flex: 1; background: transparent; border: none;
  padding: 5px 8px; font-size: 11.5px; font-weight: 500;
  cursor: pointer; border-radius: 4px; color: #475569; font-family: inherit;
}
.asm-toggle:hover:not(.on) { background: #f1f5f9; }
.asm-toggle.on { background: var(--primary); color: #fff; }

/* Chart + stats */
.asm-chart-wrap {
  flex: 1; min-height: 0;
  position: relative; background: #fff;
  border: 1px solid var(--border); border-radius: 6px;
  padding: 8px;
}
.asm-stats-panel {
  flex-shrink: 0; max-height: 38%; overflow-y: auto;
  margin-top: 10px; padding: 10px 12px;
  background: #f8fafc; border: 1px solid var(--border); border-radius: 6px;
  font-size: 12px; color: #1e293b;
}
.asm-stats-title {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: #64748b; margin-bottom: 6px;
}
.asm-stat-line {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 6px; padding: 3px 0;
}
.asm-stat-chip {
  background: #fff; border: 1px solid var(--border);
  border-radius: 4px; padding: 2px 7px; font-size: 11.5px;
  font-variant-numeric: tabular-nums;
}
.asm-series-dot {
  display: inline-block; width: 10px; height: 10px;
  border-radius: 50%; flex-shrink: 0;
}

/* 3D-surface canvas fills the wrap exactly via absolute inset. The
 * absolute positioning decouples the canvas display-size from the
 * wrap's own layout so the canvas can't push the wrap taller (the
 * hand-rolled 3D canvas hit this feedback loop; Chart.js handles
 * its own sizing for the scatter view). */
.asm-3d-wrap { overflow: hidden; }
.asm-3d-canvas {
  position: absolute;
  top: 8px; left: 8px;
  /* width/height in pixels minus the 8px padding on each side. Canvas
   * elements don't stretch with width/height: auto + inset because their
   * intrinsic 300x150 size acts as the default. Explicit calc() wins. */
  width: calc(100% - 16px) !important;
  height: calc(100% - 16px) !important;
  display: block;
}

/* Axis-range sliders (X / Y in the scatter sidebar) */
.asm-range-group { margin-top: 8px; padding-top: 6px; border-top: 1px dashed var(--border); }
.asm-range-label {
  font-size: 11px; font-weight: 600; color: #475569;
  text-transform: uppercase; letter-spacing: 0.05em;
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 4px;
}
.asm-range-reset {
  background: none; border: none; cursor: pointer;
  font-size: 14px; color: #94a3b8; padding: 0 4px;
  font-family: inherit;
}
.asm-range-reset:hover { color: var(--primary); }
.asm-range-row {
  display: grid;
  grid-template-columns: 28px 1fr 56px;
  align-items: center; gap: 6px;
  margin-bottom: 4px;
}
.asm-range-handle-label {
  font-size: 10.5px; color: #94a3b8; text-transform: uppercase;
  letter-spacing: 0.04em; font-weight: 600;
}
.asm-range-slider { width: 100%; padding: 0; min-height: 0; cursor: pointer; }
.asm-range-num {
  width: 56px; padding: 4px 5px; border: 1px solid var(--border);
  border-radius: 4px; font-size: 11px; font-family: inherit;
  text-transform: none; letter-spacing: normal;
}

/* Sidebar slider rows (3D rotation/tilt/zoom) */
.asm-side-slider-row {
  display: grid;
  grid-template-columns: 56px 1fr 44px;
  align-items: center; gap: 6px;
  margin-bottom: 6px;
  font-size: 11.5px; color: #475569;
}
.asm-side-slider-label {
  font-size: 10.5px; font-weight: 600; color: #475569;
  text-transform: uppercase; letter-spacing: 0.04em;
}
.asm-side-slider { width: 100%; padding: 0; min-height: 0; cursor: pointer; }
.asm-side-slider-val {
  font-size: 11px; color: #0f172a; font-variant-numeric: tabular-nums;
  text-align: right;
}

/* Dark mode for plots — toggled via body.asm-darkplots class. Applies to
 * the analyze workspace only so the rest of the app stays light.
 * Window/header/sidebar all match FormLab's main sidebar (#111827).
 * Inner cards/panels step up one shade (#1f2937) so they pop without
 * fighting the window. Text uses lighter slate-200 / slate-300. */
body.asm-darkplots .asm-analyze-panel,
body.asm-darkplots .asm-analyze-header,
body.asm-darkplots .asm-analyze-sidebar,
body.asm-darkplots .asm-analyze-main,
body.asm-darkplots .asm-chart-wrap,
body.asm-darkplots .asm-hm-scroll,
body.asm-darkplots .asm-hm-grid,
body.asm-darkplots .asm-3d-wrap { background: #111827 !important; color: #f1f5f9; }
body.asm-darkplots .asm-chart-wrap,
body.asm-darkplots .asm-hm-scroll { border-color: #374151 !important; }
body.asm-darkplots .asm-hm-corner,
body.asm-darkplots .asm-hm-rowhdr,
body.asm-darkplots .asm-hm-colhdr-bot { background: #1f2937 !important; color: #e5e7eb !important; border-color: #374151 !important; }
body.asm-darkplots .asm-hm-title,
body.asm-darkplots .asm-hm-subtitle,
body.asm-darkplots .asm-hm-notes { color: #f1f5f9; }
body.asm-darkplots .asm-hm-titlebar { border-bottom-color: #374151; }
body.asm-darkplots .asm-stats-panel { background: #1f2937 !important; color: #e5e7eb; border-color: #374151 !important; }
body.asm-darkplots .asm-stats-panel strong { color: #fff; }
body.asm-darkplots .asm-stat-chip { background: #111827 !important; border-color: #374151 !important; color: #e5e7eb; }

/* Workspace header — dark-mode tabs / close / toggles. Header itself is
 * the same dark as the panel; tab styles flip back to dark-on-fill. */
body.asm-darkplots .asm-analyze-header { border-bottom-color: #1f2937; color: #f1f5f9; }
body.asm-darkplots .asm-analyze-header strong { color: #fff; }
body.asm-darkplots .asm-analyze-tabs .asm-tab {
  color: #e5e7eb;
  border-color: #374151;
}
body.asm-darkplots .asm-analyze-tabs .asm-tab:hover { background: #1f2937; color: #fff; border-color: #4b5563; }
body.asm-darkplots .asm-analyze-tabs .asm-tab.on { background: #fff; color: #0f172a; border-color: #fff; }
body.asm-darkplots .asm-analyze-close { color: #e5e7eb; }
body.asm-darkplots .asm-analyze-close:hover { background: #1f2937; color: #fff; }
body.asm-darkplots .asm-header-toggle { color: #e5e7eb; border-color: #374151; }
body.asm-darkplots .asm-header-toggle:hover { background: #1f2937; color: #fff; border-color: #4b5563; }
body.asm-darkplots .asm-header-toggle.on { background: #fff; color: #0f172a; border-color: #fff; }

/* Analyze sidebar — gets dark theme too. Same window color, separated
 * from main by a subtle border; controls inside get dark-mode fills. */
body.asm-darkplots .asm-analyze-sidebar { border-right-color: #1f2937; color: #e5e7eb; }
body.asm-darkplots .asm-side-section { border-bottom-color: #1f2937; }
body.asm-darkplots .asm-side-title { color: #cbd5e1; }
/* Scoped to the analyze sidebar so this dark fill doesn't bleed into
 * modals (DOE generator etc.) that reuse .asm-side-help but render
 * outside the analyze workspace context. */
body.asm-darkplots .asm-analyze-sidebar .asm-side-help {
  background: #1f2937; border-color: #374151; color: #cbd5e1;
}
body.asm-darkplots .asm-analyze-sidebar .asm-side-help strong { color: #f1f5f9; }
body.asm-darkplots .asm-toggle-group {
  background: #1f2937; border-color: #374151;
}
body.asm-darkplots .asm-analyze-sidebar label.asm-side-label { color: #e5e7eb; }
body.asm-darkplots .asm-analyze-sidebar label.asm-side-check { color: #e5e7eb; }
body.asm-darkplots .asm-analyze-sidebar select,
body.asm-darkplots .asm-analyze-sidebar input[type="text"],
body.asm-darkplots .asm-analyze-sidebar input[type="number"],
body.asm-darkplots .asm-analyze-sidebar input.asm-side-input,
body.asm-darkplots .asm-analyze-sidebar input.asm-toolbar-select,
body.asm-darkplots .asm-analyze-sidebar textarea {
  background: #1f2937 !important;
  border-color: #374151 !important;
  color: #f1f5f9 !important;
}
body.asm-darkplots .asm-analyze-sidebar input::placeholder,
body.asm-darkplots .asm-analyze-sidebar textarea::placeholder { color: #94a3b8; }
body.asm-darkplots .asm-analyze-sidebar .asm-toggle {
  background: #1f2937; color: #e5e7eb; border-color: #374151;
}
body.asm-darkplots .asm-analyze-sidebar .asm-toggle:hover:not(.on) { background: #374151; color: #fff; }
body.asm-darkplots .asm-analyze-sidebar .asm-toggle.on { background: var(--primary); color: #fff; border-color: var(--primary); }
/* Slider rows in sidebar (3D rotation, etc.) */
body.asm-darkplots .asm-side-slider-label { color: #cbd5e1; }
body.asm-darkplots .asm-side-slider-val   { color: #cbd5e1; }
/* Buttons inside the analyze sidebar — dark theme so they blend */
body.asm-darkplots .asm-analyze-sidebar .btn-secondary {
  background: #1f2937; color: #e5e7eb; border-color: #374151;
}
body.asm-darkplots .asm-analyze-sidebar .btn-secondary:hover {
  background: #374151; color: #fff;
}
/* Same dark treatment for the analyze HEADER action buttons (Add note,
   Save image) so they blend with the dark page background instead of
   popping as bright white chips. Print PDF already uses .btn-print
   (dark navy bg) so it's unaffected by this rule. */
body.asm-darkplots .asm-hm-actions .btn-secondary:not(.btn-print) {
  background: #1f2937; color: #e5e7eb; border-color: #374151;
}
body.asm-darkplots .asm-hm-actions .btn-secondary:not(.btn-print):hover {
  background: #374151; color: #fff;
}

/* Equation pill overlay on the scatter canvas — replaces the
 * canvas-drawn version so it can have proper padding and be dragged. */
.asm-eq-overlay {
  position: absolute;
  z-index: 6;
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid rgba(15, 23, 42, 0.18);
  border-radius: 6px;
  padding: 8px 12px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
  cursor: grab;
  font-size: 12px;
  line-height: 1.4;
  user-select: none;
  max-width: 360px;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.asm-eq-overlay.asm-eq-dragging { cursor: grabbing; box-shadow: 0 4px 12px rgba(0,0,0,0.18); }
.asm-eq-body { flex: 1; min-width: 0; }
.asm-eq-line {
  display: flex; align-items: center; gap: 8px;
  padding: 2px 0;
  font-variant-numeric: tabular-nums;
}
.asm-eq-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.asm-eq-text { color: #0f172a; }
/* Minimize / expand toggle (top-right of the equation pill). */
.asm-eq-toggle {
  background: rgba(0, 0, 0, 0.06);
  border: none;
  border-radius: 4px;
  padding: 0 6px;
  font-size: 14px;
  font-family: inherit; color: #475569;
  cursor: pointer;
  line-height: 1.4;
  margin-left: 2px;
  flex-shrink: 0;
}
.asm-eq-toggle:hover { background: rgba(0, 0, 0, 0.12); color: #0f172a; }
.asm-eq-toggle-mini {
  font-weight: 700; font-style: italic;
  font-size: 13px;
  padding: 2px 8px;
  background: transparent;
}
.asm-eq-overlay.asm-eq-minimized {
  padding: 2px 4px;
  cursor: grab;
}
body.asm-darkplots .asm-eq-overlay {
  background: rgba(15, 23, 42, 0.85);
  border-color: rgba(226, 232, 240, 0.25);
}
body.asm-darkplots .asm-eq-text { color: #e2e8f0; }
body.asm-darkplots .asm-eq-toggle { background: rgba(255,255,255,0.10); color: #cbd5e1; }
body.asm-darkplots .asm-eq-toggle:hover { background: rgba(255,255,255,0.18); color: #fff; }

/* Annotation overlay on top of the scatter canvas / 3D wrap. The layer
 * itself is absolutely positioned to fill the chart-wrap; each note is
 * an absolutely-positioned div inside. */
.asm-annot-layer {
  position: absolute; inset: 8px;   /* matches chart-wrap padding */
  pointer-events: none;
  z-index: 7;
}
.asm-annot {
  position: absolute;
  transform: translate(-50%, -50%);
  font-size: 12px; color: #0f172a; line-height: 1.35;
  font-family: inherit;
  max-width: 260px;
  max-height: 200px;
  overflow: hidden;
  padding: 4px 8px;
  border-radius: 4px;
  pointer-events: auto;
  cursor: grab;
  user-select: none;
  word-break: break-word;
  overflow-wrap: anywhere;
}
/* Render rich text consistently with the editor — bullets stay inside
   the box, paragraphs/lists get sensible spacing, inline color and
   font-size from execCommand are preserved. */
.asm-annot p { margin: 0 0 4px; }
.asm-annot p:last-child { margin-bottom: 0; }
.asm-annot ul, .asm-annot ol { margin: 2px 0; padding-left: 18px; }
.asm-annot li { margin: 1px 0; }
.asm-annot b, .asm-annot strong { font-weight: 700; }
.asm-annot i, .asm-annot em       { font-style: italic; }
.asm-annot u                      { text-decoration: underline; }
.asm-annot:hover { outline: 1.5px dashed var(--primary); outline-offset: 2px; }
.asm-annot.asm-annot-dragging { cursor: grabbing; opacity: 0.9; box-shadow: 0 4px 12px rgba(0,0,0,0.18); }
.asm-annot-bg { background: rgba(255, 255, 255, 0.92); border: 1px solid var(--border); box-shadow: 0 1px 2px rgba(0,0,0,0.08); }
.asm-annot-transparent { background: transparent; }
body.asm-darkplots .asm-annot { color: #e2e8f0; }
body.asm-darkplots .asm-annot-bg { background: rgba(15, 23, 42, 0.85); border-color: #334155; }
/* Placement mode — show crosshair on hovered chart */
.asm-chart-wrap.asm-annot-placing { cursor: crosshair !important; }
.asm-chart-wrap.asm-annot-placing canvas { cursor: crosshair !important; }
.asm-annot-editor {
  font-family: inherit;
}
.asm-annot-editor:focus { outline: 2px solid var(--primary); outline-offset: -2px; }
/* Keep bullets / numbered lists inside the editor's padding box —
   default <ul>/<ol> padding-inline-start of 40px puts the marker
   to the left of the editor border when the editor itself only has
   10px of left padding. */
.asm-annot-editor ul,
.asm-annot-editor ol {
  margin: 4px 0;
  padding-left: 22px;
}
.asm-annot-editor li { margin: 2px 0; }

/* Brush-selection rectangle drawn on the scatter canvas */
.asm-brush-rect {
  position: absolute;
  pointer-events: none;
  border: 1.5px dashed var(--primary);
  background: rgba(37, 99, 235, 0.10);
  z-index: 6;
}

/* ============================================================
   Designer (Predictor) — Phase 1: per-output regression with
   live input sliders. Two-column main pane: inputs (sliders) on
   the left, predicted outputs table on the right.
   ============================================================ */
.asm-designer-wrap {
  padding: 16px 18px 20px;
  overflow: auto;
  background: #f8fafc;
  flex: 1 1 auto;
  min-height: 0;
}
body.asm-darkplots .asm-designer-wrap { background: #111827; color: #f1f5f9; }

.asm-designer-empty {
  max-width: 520px;
  margin: 48px auto;
  padding: 24px 28px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  text-align: left;
}
.asm-designer-empty h3 {
  margin: 0 0 10px;
  font-size: 16px;
  color: #0f172a;
}
body.asm-darkplots .asm-designer-empty {
  background: #1f2937;
  border-color: #374151;
}
body.asm-darkplots .asm-designer-empty h3 { color: #f1f5f9; }

.asm-designer-grid {
  display: grid;
  grid-template-columns: minmax(280px, 1fr) minmax(360px, 1.2fr);
  gap: 20px;
  align-items: start;
}
@media (max-width: 900px) {
  .asm-designer-grid { grid-template-columns: 1fr; }
}

.asm-designer-inputs,
.asm-designer-outputs {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px 16px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
  /* min-width:0 lets the grid item shrink to its column track so the
   * prediction table can never push its panel past the right edge of
   * the workspace; overflow-x:auto then scrolls the table inside the
   * card if it still needs more width on narrow viewports. */
  min-width: 0;
  overflow-x: auto;
}
body.asm-darkplots .asm-designer-inputs,
body.asm-darkplots .asm-designer-outputs {
  background: #1f2937;
  border-color: #374151;
}

.asm-designer-section-title {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #334155;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}
body.asm-darkplots .asm-designer-section-title {
  color: #e5e7eb;
  border-bottom-color: #374151;
}

/* Slider row: label on top, range + numeric + observed-range below */
.asm-designer-slider-row {
  margin-bottom: 14px;
}
.asm-designer-slider-row:last-child { margin-bottom: 4px; }

.asm-designer-slider-label {
  display: block;
  font-size: 12.5px;
  font-weight: 500;
  color: #0f172a;
  margin-bottom: 6px;
  text-transform: none;
  letter-spacing: 0;
}
body.asm-darkplots .asm-designer-slider-label { color: #f1f5f9; }

.asm-designer-slider-bar {
  display: grid;
  grid-template-columns: 1fr 80px auto;
  align-items: center;
  gap: 8px;
}
.asm-designer-slider-bar input[type="range"] {
  width: 100%;
  cursor: pointer;
  accent-color: var(--primary);
}
.asm-designer-slider-bar input.asm-designer-slider-num {
  width: 80px;
  padding: 4px 6px;
  font-size: 12px;
  font-family: inherit;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: #fff;
  text-align: right;
}
.asm-designer-slider-bar input.asm-designer-slider-num:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px rgba(37,99,235,0.18);
}
body.asm-darkplots .asm-designer-slider-bar input.asm-designer-slider-num {
  background: #111827;
  border-color: #374151;
  color: #f1f5f9;
}

.asm-designer-slider-range {
  font-size: 10.5px;
  color: #94a3b8;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.asm-designer-help {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
  font-size: 11px;
  color: #64748b;
  line-height: 1.5;
}
body.asm-darkplots .asm-designer-help {
  color: #cbd5e1;
  border-top-color: #374151;
}

/* Prediction table */
.asm-designer-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}
.asm-designer-table thead th {
  text-align: left;
  padding: 6px 10px 8px;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #64748b;
  border-bottom: 1px solid var(--border);
  background: transparent;
}
.asm-designer-table tbody td {
  padding: 10px;
  border-bottom: 1px solid #f1f5f9;
  vertical-align: middle;
}
.asm-designer-table tbody tr:last-child td { border-bottom: none; }
body.asm-darkplots .asm-designer-table thead th { color: #cbd5e1; border-bottom-color: #374151; }
body.asm-darkplots .asm-designer-table tbody td { border-bottom-color: #374151; }

.asm-designer-out-name {
  font-weight: 500;
  color: #0f172a;
}
body.asm-darkplots .asm-designer-out-name { color: #f1f5f9; }

.asm-designer-out-pred {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.asm-designer-out-pred strong {
  font-size: 14px;
  font-weight: 600;
  color: var(--primary);
}
body.asm-darkplots .asm-designer-out-pred strong { color: #60a5fa; }
.asm-designer-pi {
  font-size: 11px;
  color: #94a3b8;
  margin-left: 4px;
}

.asm-designer-out-range {
  font-variant-numeric: tabular-nums;
  color: #64748b;
  font-size: 11.5px;
  white-space: nowrap;
}
body.asm-darkplots .asm-designer-out-range { color: #cbd5e1; }
body.asm-darkplots .asm-designer-pi { color: #cbd5e1; }
body.asm-darkplots .asm-designer-target-dash { color: #cbd5e1; }

.asm-designer-out-r2 {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-start;
}
.asm-designer-r2 {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: help;
}
.asm-designer-r2.r2-strong { background: #dcfce7; color: #166534; }
.asm-designer-r2.r2-medium { background: #fef9c3; color: #854d0e; }
.asm-designer-r2.r2-weak   { background: #fee2e2; color: #991b1b; }
body.asm-darkplots .asm-designer-r2.r2-strong { background: rgba(34,197,94,0.18);  color: #86efac; }
body.asm-darkplots .asm-designer-r2.r2-medium { background: rgba(234,179,8,0.18);  color: #fde68a; }
body.asm-darkplots .asm-designer-r2.r2-weak   { background: rgba(239,68,68,0.18);  color: #fca5a5; }

.asm-designer-r2.asm-designer-loo {
  font-weight: 500;
  font-size: 10.5px;
  opacity: 0.92;
}

/* Sidebar column-picker list — scrollable when many columns */
.asm-designer-collist {
  max-height: 220px;
  overflow-y: auto;
  padding: 4px 4px 4px 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fafbfc;
}
.asm-designer-collist label.asm-side-check {
  padding: 3px 8px !important;
  font-size: 11.5px;
}
body.asm-darkplots .asm-designer-collist {
  background: #111827;
  border-color: #374151;
}

/* Inverse-design controls — sit below the input sliders */
.asm-designer-invdesign {
  border-top: 1px dashed var(--border);
  margin-top: 14px;
  padding-top: 0;
}
body.asm-darkplots .asm-designer-invdesign { border-top-color: #374151; }

/* Target column: dropdown + 1-2 small numeric inputs inline */
.asm-designer-out-target {
  white-space: nowrap;
}
.asm-designer-target-row {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.asm-designer-target-mode {
  font-size: 11px;
  font-family: inherit;
  padding: 3px 4px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
  text-transform: none;
  letter-spacing: 0;
  width: auto;
}
.asm-designer-target-num {
  width: 58px !important;
  padding: 3px 5px;
  font-size: 11px;
  font-family: inherit;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: #fff;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.asm-designer-target-num:focus,
.asm-designer-target-mode:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px rgba(37,99,235,0.18);
}
.asm-designer-target-dash {
  font-size: 11px;
  color: #94a3b8;
}
body.asm-darkplots .asm-designer-target-mode,
body.asm-darkplots .asm-designer-target-num {
  background: #111827;
  border-color: #374151;
  color: #f1f5f9;
}

/* Hit indicator inside the predicted cell */
.asm-designer-hit {
  display: inline-block;
  font-weight: 700;
  font-size: 12px;
  width: 16px;
  height: 16px;
  line-height: 16px;
  text-align: center;
  border-radius: 50%;
  margin-left: 4px;
  vertical-align: middle;
  cursor: help;
}
.asm-designer-hit-yes  { background: #dcfce7; color: #166534; }
.asm-designer-hit-near { background: #fef9c3; color: #854d0e; }
.asm-designer-hit-no   { background: #fee2e2; color: #991b1b; }
body.asm-darkplots .asm-designer-hit-yes  { background: rgba(34,197,94,0.22); color: #86efac; }
body.asm-darkplots .asm-designer-hit-near { background: rgba(234,179,8,0.22); color: #fde68a; }
body.asm-darkplots .asm-designer-hit-no   { background: rgba(239,68,68,0.22); color: #fca5a5; }

/* Candidates panel — top-K results from grid search */
.asm-designer-candidates {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
body.asm-darkplots .asm-designer-candidates { border-top-color: #374151; }

.asm-designer-cand-scroll {
  overflow-x: auto;
  max-height: 360px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fafbfc;
}
body.asm-darkplots .asm-designer-cand-scroll {
  background: #111827;
  border-color: #374151;
}

.asm-designer-cand-table {
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  min-width: 100%;
  width: max-content;
}
.asm-designer-cand-table thead th {
  position: sticky;
  top: 0;
  background: #f1f5f9;
  z-index: 1;
  white-space: nowrap;
  padding: 5px 8px;
}
.asm-designer-cand-table tbody td {
  padding: 4px 8px;
  white-space: nowrap;
}
.asm-designer-cand-table tbody tr:hover {
  background: rgba(37,99,235,0.05);
}
body.asm-darkplots .asm-designer-cand-table thead th { background: #1f2937; color: #e5e7eb; }
body.asm-darkplots .asm-designer-cand-table tbody tr:hover { background: rgba(96,165,250,0.08); }
body.asm-darkplots .asm-designer-cand-table tbody td { color: #e5e7eb; }

.asm-designer-cand-rank {
  font-weight: 600;
  color: #334155;
}
body.asm-darkplots .asm-designer-cand-rank { color: #e5e7eb; }
.asm-designer-cand-score {
  font-weight: 600;
  color: var(--primary);
}
body.asm-darkplots .asm-designer-cand-score { color: #60a5fa; }

/* Pareto-optimal badge on candidate rank */
.asm-designer-pareto-badge {
  display: inline-block;
  margin-left: 3px;
  padding: 1px 5px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  border-radius: 8px;
  background: #ede9fe;
  color: #5b21b6;
  vertical-align: middle;
  cursor: help;
}
body.asm-darkplots .asm-designer-pareto-badge {
  background: rgba(139,92,246,0.22);
  color: #c4b5fd;
}

/* Per-point color picker popup */
.asm-color-menu {
  position: fixed; z-index: 300;
  background: #fff; border: 1px solid var(--border); border-radius: 6px;
  padding: 8px; box-shadow: 0 8px 22px rgba(0, 0, 0, 0.18);
  min-width: 180px;
}
.asm-color-menu-title {
  font-size: 11px; font-weight: 600; color: #475569;
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 6px;
}
.asm-color-swatches {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px; margin-bottom: 8px;
}
.asm-color-swatch {
  width: 26px; height: 22px; border-radius: 4px; border: 1px solid rgba(0,0,0,0.1);
  cursor: pointer; padding: 0;
}
.asm-color-swatch:hover { transform: scale(1.08); }
.asm-color-clear {
  width: 100%; background: #f1f5f9; border: 1px solid var(--border);
  border-radius: 4px; padding: 5px 8px; font-size: 11.5px;
  cursor: pointer; font-family: inherit;
}

/* Correlation heatmap */
.asm-hm-titlebar {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--border);
  margin-bottom: 14px;
}
.asm-hm-title { font-size: 17px; font-weight: 700; color: #0f172a; line-height: 1.2; }
.asm-hm-subtitle { font-size: 11.5px; color: #64748b; margin-top: 3px; font-variant-numeric: tabular-nums; }
.asm-hm-notes {
  font-size: 11.5px; color: #334155; margin-top: 6px;
  line-height: 1.45; font-style: italic;
  max-width: 70ch;
  white-space: pre-wrap;
}
.asm-hm-actions { display: flex; gap: 6px; flex-shrink: 0; }
.asm-hm-legend {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 11.5px; color: #475569;
  margin-bottom: 10px;
}
.asm-hm-legend-text {
  font-variant-numeric: tabular-nums; font-weight: 600;
  color: #334155;
}
.asm-hm-bar {
  flex: 0 0 180px; height: 12px; border-radius: 3px;
  background: linear-gradient(to right, rgb(220, 38, 38), #ffffff, rgb(37, 99, 235));
  border: 1px solid var(--border);
}
.asm-hm-sigkey { color: #94a3b8; }
.asm-hm-rangetxt {
  color: #475569; font-style: italic;
  padding-left: 8px; margin-left: 4px;
  border-left: 1px solid var(--border);
}
.asm-hm-scroll {
  flex: 1; min-height: 0; overflow: auto;
  border: 1px solid var(--border); border-radius: 8px;
  background: #fff;
}
.asm-hm-grid {
  display: grid;
  gap: 0;
  background: #fff;
}
.asm-hm-cell {
  font-size: 11px; padding: 6px 8px;
  border-right: 1px solid #e2e8f0; border-bottom: 1px solid #e2e8f0;
  display: flex; align-items: center; justify-content: center;
  text-align: center; min-height: 32px;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  transition: background 0.08s ease, box-shadow 0.08s ease;
}
.asm-hm-corner {
  background: #f8fafc;
  border-right: 1px solid #cbd5e1;
}
/* Row labels — left side. Allow wrapping to 2 lines for long names. */
.asm-hm-rowhdr {
  background: #f8fafc;
  font-weight: 600; color: #334155;
  font-size: 11px; padding: 6px 10px;
  border-right: 1px solid #cbd5e1;
  text-align: right; justify-content: flex-end; align-items: center;
  min-width: 160px; max-width: 220px;
  white-space: normal;
  line-height: 1.25;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
/* Column labels — bottom. Wrap horizontally as needed, no fixed height
 * (the row sizes to its tallest label, so short labels don't waste space). */
.asm-hm-colhdr-bot {
  background: #f8fafc;
  font-weight: 600; color: #334155;
  font-size: 10.5px; padding: 6px 4px;
  border-top: 1px solid #cbd5e1;
  border-right: 1px solid #e2e8f0;
  min-height: auto;
  align-items: flex-start;
  justify-content: center;
  white-space: normal;
  line-height: 1.25;
  text-align: center;
  word-break: break-word;
  overflow: hidden;
}
.asm-hm-data {
  background: #fff; border: none; cursor: pointer;
  font-weight: 600; font-family: inherit;
  border-right: 1px solid rgba(0,0,0,0.05);
  border-bottom: 1px solid rgba(0,0,0,0.05);
  display: flex; flex-direction: column; gap: 0;
  padding: 4px 6px; min-height: 36px;
}
.asm-hm-data:hover:not(.asm-hm-diag) {
  outline: 2px solid #0f172a; outline-offset: -2px;
  z-index: 2; position: relative;
}
.asm-hm-diag { cursor: default; opacity: 0.55; }
/* Fade out cells where p ≥ 0.05 so significant pairs stand out. */
.asm-hm-insig { opacity: 0.22; }
.asm-hm-insig:hover { opacity: 0.85; }
.asm-hm-val { font-size: 11.5px; line-height: 1.2; }
.asm-hm-stars { font-size: 9px; opacity: 0.85; line-height: 1; }
/* Hover highlight for whole row + column */
.asm-hm-hl-row, .asm-hm-hl-col {
  box-shadow: inset 0 0 0 1px rgba(37, 99, 235, 0.35);
}
.asm-hm-rowhdr.asm-hm-hl-row,
.asm-hm-colhdr-bot.asm-hm-hl-col {
  background: #dbeafe; color: #1e3a8a;
}
/* Briefly flashes when the user returns to the heatmap from a scatter
 * drill-down — shows them exactly which cell the scatter came from.
 *
 * Pattern: three quick on/off pulses (≈900 ms each) with a brief rest
 * between, ≈2.7 s total. Catches the eye like a notification badge
 * instead of one slow fade. */
@keyframes asmHmFlash {
  0%   { box-shadow: 0 0 0 0  rgba(251, 191, 36, 0),    inset 0 0 0 0 rgba(180, 83, 9, 0); }
  20%  { box-shadow: 0 0 0 6px rgba(251, 191, 36, 0.85), inset 0 0 0 3px rgba(180, 83, 9, 0.90); }
  55%  { box-shadow: 0 0 0 4px rgba(251, 191, 36, 0.55), inset 0 0 0 2px rgba(180, 83, 9, 0.55); }
  85%  { box-shadow: 0 0 0 0  rgba(251, 191, 36, 0),    inset 0 0 0 0 rgba(180, 83, 9, 0); }
  100% { box-shadow: 0 0 0 0  rgba(251, 191, 36, 0),    inset 0 0 0 0 rgba(180, 83, 9, 0); }
}
.asm-hm-flash {
  animation: asmHmFlash 0.9s ease-out 3;
  z-index: 5; position: relative;
}

/* Drill-down navigation strip on the Scatter view when the user opens it
 * from a heatmap cell or list row. */
.asm-scatter-nav {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 10px;
  margin-bottom: 8px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  border-radius: 6px;
  font-size: 12px;
}
.asm-scatter-nav-crumb { color: #475569; flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.asm-scatter-nav-crumb strong { color: #0f172a; font-weight: 600; }
.asm-scatter-nav-spacer { flex: 0 1 8px; }
.asm-scatter-nav-pos {
  font-variant-numeric: tabular-nums;
  font-size: 11px; color: #64748b;
  min-width: 50px; text-align: center;
}
.asm-scatter-nav-arrow:disabled { opacity: 0.45; cursor: not-allowed; }
body.asm-darkplots .asm-scatter-nav { background: #1f2937; border-color: #374151; }
body.asm-darkplots .asm-scatter-nav-crumb { color: #cbd5e1; }
body.asm-darkplots .asm-scatter-nav-crumb strong { color: #fff; }
body.asm-darkplots .asm-scatter-nav-pos { color: #cbd5e1; }

/* Correlations list table — sits below the heatmap grid */
.asm-hm-list-section {
  margin-top: 16px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.asm-hm-list-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 10px 14px;
  background: #f8fafc;
  border-bottom: 1px solid var(--border);
}
.asm-hm-list-title {
  font-size: 13px; font-weight: 600; color: #0f172a;
}
.asm-hm-list-count {
  font-size: 11.5px; font-weight: 500; color: #64748b;
  margin-left: 8px;
}
.asm-hm-list-print-title {
  font-size: 13px; font-weight: 600; color: #0f172a;
  padding: 10px 14px;
  background: #f8fafc;
  border-bottom: 1px solid var(--border);
}
.asm-hm-list-filter-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: #475569;
  text-transform: none; letter-spacing: normal; font-weight: 500;
}
.asm-hm-list-filter-input {
  width: 70px; padding: 4px 6px;
  border: 1px solid var(--border); border-radius: 4px;
  font-size: 12px; font-family: inherit;
}
.asm-hm-list-tablewrap { overflow-x: auto; }
.asm-hm-list-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  table-layout: fixed;
}
.asm-hm-list-table thead th {
  background: #f1f5f9; color: #475569;
  font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em;
  padding: 8px 10px;
  border-bottom: 1px solid #cbd5e1;
  white-space: nowrap;
  overflow: hidden;
}
.asm-hm-list-table thead th:hover { background: #e2e8f0; }
.asm-hm-list-sort-arrow { color: #cbd5e1; font-size: 9px; margin-left: 4px; }
.asm-hm-list-sort-arrow.on { color: var(--primary); }
.asm-hm-list-resizer {
  position: absolute; top: 0; bottom: 0; right: -3px;
  width: 6px; cursor: col-resize; z-index: 4; background: transparent;
  transition: background 0.12s;
}
.asm-hm-list-resizer:hover,
.asm-hm-list-resizer:active { background: rgba(37, 99, 235, 0.35); }
.asm-hm-list-table tbody td {
  padding: 6px 10px;
  border-bottom: 1px solid #f1f5f9;
  /* Inherit alignment from the <col> via the th's text-align won't cascade
   * to td. Instead apply per-column classes below. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.asm-hm-list-row { cursor: pointer; transition: background 0.1s; }
.asm-hm-list-row:hover { background: #eff6ff; }
.asm-hm-list-rank {
  text-align: right; color: #94a3b8; font-weight: 600;
}
.asm-hm-list-num { text-align: right; white-space: nowrap; }
.asm-hm-list-r.pos { color: #1d4ed8; font-weight: 600; }
.asm-hm-list-r.neg { color: #dc2626; font-weight: 600; }
.asm-hm-list-sig { text-align: center; font-weight: 700; color: #64748b; }
.asm-hm-list-sig.sig-1 { color: #d97706; }
.asm-hm-list-sig.sig-2 { color: #d97706; }
.asm-hm-list-sig.sig-3 { color: #b45309; }

/* Correlations list — dark mode coverage */
body.asm-darkplots .asm-hm-list-section { background: #1f2937 !important; border-color: #374151; }
body.asm-darkplots .asm-hm-list-toolbar { background: #111827; border-bottom-color: #374151; }
body.asm-darkplots .asm-hm-list-title { color: #f1f5f9; }
body.asm-darkplots .asm-hm-list-count { color: #cbd5e1; }
body.asm-darkplots .asm-hm-list-print-title { background: #111827; border-bottom-color: #374151; color: #f1f5f9; }
body.asm-darkplots .asm-hm-list-filter-label { color: #cbd5e1; }
body.asm-darkplots .asm-hm-list-filter-input { background: #111827; border-color: #374151; color: #f1f5f9; }
body.asm-darkplots .asm-hm-list-table thead th { background: #111827; color: #e5e7eb; border-bottom-color: #374151; }
body.asm-darkplots .asm-hm-list-table thead th:hover { background: #1f2937; }
body.asm-darkplots .asm-hm-list-table tbody td { color: #e5e7eb; border-bottom-color: #1f2937; }
body.asm-darkplots .asm-hm-list-row:hover { background: rgba(96,165,250,0.10); }
body.asm-darkplots .asm-hm-list-rank { color: #cbd5e1; }
body.asm-darkplots .asm-hm-list-r.pos { color: #60a5fa; }
body.asm-darkplots .asm-hm-list-r.neg { color: #fca5a5; }
body.asm-darkplots .asm-hm-list-sig { color: #cbd5e1; }
body.asm-darkplots .asm-hm-list-sort-arrow { color: #94a3b8; }

/* Print-only / screen-only helpers */
.asm-hm-print-only { display: none !important; }
@media print {
  .asm-hm-screen-only { display: none !important; }
  .asm-hm-print-only { display: block !important; }
}
/* When the user clicks Save image, hide on-screen-only controls (action
 * buttons, list toolbar) so they don't appear in the captured PNG.
 * Also reveal the print-only list-title so the table has a header in
 * the saved image. */
body.asm-exporting-image .asm-hm-screen-only { display: none !important; }
body.asm-exporting-image .asm-hm-print-only { display: block !important; }

/* When the user clicks Print PDF, body gets .asm-printing-heatmap. The
 * rules below override the iOS viewport-fix height locks, hide every
 * chrome element, and let the analyze overlay flow as page content.
 *
 * Critical: we DON'T use `body > *:not(#app)` here — the :not() id bumps
 * specificity above the overlay-restore rule and would keep the overlay
 * hidden. Explicit ID list instead. */
@media print {
  html:has(body.asm-printing-heatmap),
  body.asm-printing-heatmap {
    height: auto !important;
    overflow: visible !important;
    background: #fff !important;
  }
  body.asm-printing-heatmap #sidebar,
  body.asm-printing-heatmap #sidebar-backdrop,
  body.asm-printing-heatmap #mobile-menu-btn,
  body.asm-printing-heatmap #topbar,
  body.asm-printing-heatmap #content,
  body.asm-printing-heatmap #feedback-fab,
  body.asm-printing-heatmap #modal-backdrop,
  body.asm-printing-heatmap #account-popup,
  body.asm-printing-heatmap .asm-hm-screen-only { display: none !important; }
  body.asm-printing-heatmap #app,
  body.asm-printing-heatmap #main {
    display: block !important;
    height: auto !important;
    overflow: visible !important;
  }
  body.asm-printing-heatmap .asm-analyze-overlay {
    display: block !important;
    position: static !important;
    inset: auto !important;
    background: #fff !important;
    padding: 0 !important;
    z-index: auto !important;
  }
  body.asm-printing-heatmap .asm-analyze-panel {
    display: flex !important;
    flex-direction: column !important;
    height: auto !important; max-width: none !important;
    width: 100% !important;
    box-shadow: none !important; border: none !important;
    border-radius: 0 !important;
    overflow: visible !important;
  }
  body.asm-printing-heatmap .asm-analyze-header,
  body.asm-printing-heatmap .asm-analyze-sidebar { display: none !important; }
  body.asm-printing-heatmap .asm-analyze-body {
    display: block !important;
    height: auto !important;
    overflow: visible !important;
  }
  body.asm-printing-heatmap .asm-analyze-main {
    display: block !important;
    overflow: visible !important;
    height: auto !important;
    padding: 8mm !important;
    background: #fff !important;
  }
  body.asm-printing-heatmap .asm-hm-scroll {
    overflow: visible !important;
    max-height: none !important;
    border: 1px solid #cbd5e1 !important;
    page-break-inside: avoid;
  }
  body.asm-printing-heatmap .asm-hm-list-section {
    page-break-before: auto;
    margin-top: 14px;
  }
  body.asm-printing-heatmap .asm-hm-list-tablewrap { overflow: visible !important; }
  body.asm-printing-heatmap .asm-hm-list-table { font-size: 10px; }
  body.asm-printing-heatmap .asm-hm-list-row { cursor: default; }
  body.asm-printing-heatmap .asm-hm-data { cursor: default; }
  body.asm-printing-heatmap .asm-hm-print-only { display: block !important; }

  /* ---- Print DOE matrix mode ---- */
  html:has(body.asm-printing-matrix),
  body.asm-printing-matrix {
    height: auto !important;
    overflow: visible !important;
    background: #fff !important;
  }
  body.asm-printing-matrix #sidebar,
  body.asm-printing-matrix #sidebar-backdrop,
  body.asm-printing-matrix #mobile-menu-btn,
  body.asm-printing-matrix #topbar,
  body.asm-printing-matrix #feedback-fab,
  body.asm-printing-matrix #modal-backdrop,
  body.asm-printing-matrix #account-popup,
  body.asm-printing-matrix .asm-toolbar,
  body.asm-printing-matrix .asm-toolbar-card { display: none !important; }
  body.asm-printing-matrix #app,
  body.asm-printing-matrix #main,
  body.asm-printing-matrix #content {
    display: block !important;
    height: auto !important;
    overflow: visible !important;
  }
  /* The matrix table itself — let it flow at full width with small page margins */
  body.asm-printing-matrix #asm-table-wrap,
  body.asm-printing-matrix .asm-table-wrap {
    overflow: visible !important;
    max-height: none !important;
    page-break-inside: auto;
  }
  body.asm-printing-matrix table { font-size: 9px !important; }

  /* Don't force an orientation — let the user pick portrait/landscape
   * in the print dialog. A wide rectangular matrix often prints best in
   * landscape, but tall matrices and reports work fine in portrait. */
  @page { margin: 10mm; }
}

@media (max-width: 768px) {
  .asm-analyze-overlay { padding: 0; }
  .asm-analyze-panel { height: 100vh; height: 100dvh; max-width: none; border-radius: 0; }
  .asm-analyze-body { flex-direction: column; }
  .asm-analyze-sidebar,
  .asm-analyze-sidebar.asm-sidebar-collapsed {
    width: 100%; max-height: 35%; padding: 12px 14px;
    border-right: none; border-bottom: 1px solid var(--border);
    overflow-y: auto;
  }
  /* No collapse toggle on mobile — the panel already stacks above main. */
  .asm-sidebar-toggle { display: none; }
  .asm-analyze-sidebar.asm-sidebar-collapsed .asm-sidebar-contents { display: block; }
}

/* Account popup — floats above the account button when toggled */
.sidebar-account-wrap { position: relative; flex: 1 1 auto; min-width: 0; display: flex; }
.sidebar-account-popup {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  min-width: 180px;
  background: #1f2937;
  color: #f1f5f9;
  border: 1px solid #374151;
  border-radius: 6px;
  padding: 8px 12px;
  font-size: 12px;
  font-weight: 500;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
  display: none;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
  z-index: 60;
}
.sidebar-account-popup.open { display: inline-flex; }
.sidebar-account-popup::after {
  /* Arrow pointing down at the account button */
  content: "";
  position: absolute;
  top: 100%;
  left: 14px;
  border: 6px solid transparent;
  border-top-color: #1f2937;
}
.sidebar-account-popup-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--warning);
  flex-shrink: 0;
}

#main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
#topbar { background: var(--surface); border-bottom: 1px solid var(--border); padding: 0 24px; height: 56px; display: flex; align-items: center; justify-content: space-between; box-shadow: var(--shadow); }
#topbar h1 { font-size: 17px; font-weight: 600; }
#back-btn:hover { background: #f1f5f9; color: #1e293b; }
#topbar .actions { display: flex; gap: 8px; }
#content { flex: 1; padding: 24px; overflow-y: auto; }

/* Cards / panels */
.card { background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow); border: 1px solid var(--border); }
.card-header { padding: 14px 18px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; }
.card-header h2 { font-size: 15px; font-weight: 600; }
.card-body { padding: 18px; }

/* Ingredient filter row */
.ing-filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 20px;
  align-items: flex-start;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  background: #f8fafc;
}
.ing-filter-group { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ing-filter-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}
.ing-filter-chips { display: flex; flex-wrap: wrap; gap: 4px; max-width: 320px; }

/* Compact filter row: each filter group is one horizontal line
 * (label on the left, chips inline to the right) so the panel
 * doesn't grow tall with many chip values. */
.test-filter-row-compact { flex-direction: column; gap: 8px; }
.ing-filter-group-h {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  width: 100%;
}
.ing-filter-group-h .ing-filter-label {
  flex: 0 0 100px;
  text-align: right;
}
.ing-filter-group-h .ing-filter-chips {
  flex: 1 1 auto;
  max-width: none;
  min-width: 0;
}
.ing-filter-row-clear { align-self: flex-end; }
@media (max-width: 768px) {
  .ing-filter-group-h { flex-wrap: wrap; }
  .ing-filter-group-h .ing-filter-label { flex-basis: auto; text-align: left; }
}
.ing-filter-chip {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 12px;
  color: #1e293b;
  cursor: pointer;
  transition: all 0.15s;
  white-space: nowrap;
}
.ing-filter-chip:hover:not(.on) { background: #f1f5f9; border-color: #94a3b8; }
.ing-filter-chip.on { background: var(--primary); color: #fff; border-color: var(--primary); }
.ing-filter-chip-picto { display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px 2px 4px; }
.ing-filter-chip-picto .picto-mini { display: inline-flex; align-items: center; justify-content: center; }
.ing-filter-chip-picto .picto-mini svg { display: block; }
.ing-filter-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--primary);
  color: #fff;
  border-radius: 999px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  font-size: 11px;
  font-weight: 600;
  margin-left: 4px;
}

/* View mode toggle (Table / Cards / Group) */
.view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; flex-shrink: 0; }
.view-toggle-btn { background: #fff; border: none; padding: 5px 12px; font-size: 12px; color: var(--text-muted); cursor: pointer; transition: background 0.15s, color 0.15s; border-right: 1px solid var(--border); white-space: nowrap; }
.view-toggle-btn:last-child { border-right: none; }
.view-toggle-btn:hover:not(.on) { background: #f1f5f9; color: var(--text); }
.view-toggle-btn.on { background: var(--primary); color: #fff; }

/* Cards view */
.ing-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; padding: 14px; }
.ing-card { background: #fff; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s; display: flex; flex-direction: column; position: relative; }
.ing-card:hover { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); }
/* Always-visible kebab menu used by every list card variant
 * (Projects / Ingredients / Formulations / Batches / Samples).
 * Tucks into the top-right corner; opens a popup menu on click. */
.card-kebab-wrap {
  position: absolute;
  top: 6px; left: 6px;
  z-index: 3;
}
.card-kebab {
  width: 22px; height: 22px;
  padding: 0;
  background: rgba(255, 255, 255, 0.85);
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-muted);
  font-size: 17px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: color 0.12s, background 0.12s, border-color 0.12s;
}
.card-kebab:hover,
.card-kebab.open { color: var(--text); background: #fff; border-color: var(--border); }
.card-kebab-menu {
  display: none;
  position: absolute;
  top: calc(100% + 4px); left: 0;
  min-width: 140px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  padding: 4px;
  flex-direction: column;
  z-index: 10;
}
.card-kebab-menu.open { display: flex; }
.card-kebab-menu button {
  display: flex; align-items: center; gap: 8px;
  width: 100%;
  padding: 6px 10px;
  background: none; border: none;
  font-size: 12.5px; text-align: left;
  color: var(--text);
  cursor: pointer; border-radius: 4px;
  white-space: nowrap;
  font-family: inherit;
}
.card-kebab-menu button:hover { background: #f1f5f9; }
.card-kebab-menu button.danger { color: var(--danger); }
.card-kebab-menu button.danger:hover { background: #fee2e2; }
/* Push the first content row right so it doesn't collide with the
 * kebab in the top-left corner. The kebab-wrap itself is absolute-
 * positioned, so we want the padding on the next sibling. */
.ing-card .ing-card-body > div:first-child,
.ing-group-card > .card-kebab-wrap + div { padding-left: 28px; }
.ing-card-thumb { background: #f8fafc; padding: 4px; height: 120px; display: flex; align-items: center; justify-content: center; border-bottom: 1px solid var(--border); }
.ing-card-body { padding: 10px 12px 12px; }

/* Group / kanban view */
.ing-group-board { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); align-items: start; gap: 12px; padding: 14px; }
.ing-group-col { background: #f8fafc; border: 1px solid var(--border); border-radius: 8px; display: flex; flex-direction: column; max-height: 70vh; min-width: 0; }
.ing-group-head { padding: 10px 12px; border-bottom: 1px solid #1f2937; background: #111827; color: #fff; border-radius: 8px 8px 0 0; }
.ing-group-list { padding: 8px; overflow-y: auto; display: flex; flex-direction: column; gap: 6px; }
.ing-group-card { background: #fff; border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; cursor: pointer; transition: border-color 0.15s; position: relative; }
.ing-group-card:hover { border-color: var(--primary); }

/* Data view */
.data-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  max-width: 900px;
}
.data-grid > .card:first-child { grid-column: 1 / -1; }
.data-grid > .data-danger-card {
  grid-column: 1 / -1;
  border: 2px solid var(--danger);
}

/* Chart-type selector in arrange-mode panel headers */
.dash-chart-type {
  display: none;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 2px 6px;
  font-size: 11px;
  font-family: inherit;
  color: var(--text);
  cursor: pointer;
}
.dash-edit .dash-chart-type { display: inline-block; }

/* Cost basis selector — sits inline in the composition table header */
.cost-basis-select {
  font-family: inherit;
  font-size: 12px;
  padding: 1px 4px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: #fff;
  color: var(--primary);
  font-weight: 600;
  cursor: pointer;
  width: auto;          /* don't stretch inside flex containers */
}
.cost-basis-select:focus { outline: 2px solid var(--primary); outline-offset: 1px; }

/* Pricing & Margin — single-line basis bar above the input grid */
.pricing-basis-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 16px;
  background: #f8fafc;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  flex-wrap: wrap;     /* graceful wrap only if absolutely needed */
}
.pricing-basis-bar .pbb-label  { color: var(--text-muted); }
.pricing-basis-bar .pbb-value  { color: var(--primary); font-weight: 700; }
.pricing-basis-bar .pbb-select {
  flex: 0 0 auto;
  width: auto;
  min-width: 80px;
  padding: 3px 8px;
}
.pricing-basis-bar .pbb-hint {
  margin-left: auto;
  color: var(--text-muted);
  font-size: 11px;
  font-style: italic;
}

/* Cost change indicator */
.cost-change-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
}
.cost-change-chip.up   { background: #fef2f2; color: var(--danger); }
.cost-change-chip.down { background: #f0fdf4; color: #16a34a; }

/* Sort panel — popover anchored to ⇅ Sort button */
.sort-panel {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.14);
  z-index: 90;
  font-family: inherit;
}
.sort-panel-header {
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 600;
  border-bottom: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.sort-panel-close {
  background: none;
  border: none;
  font-size: 14px;
  cursor: pointer;
  color: #94a3b8;
  padding: 0 4px;
  line-height: 1;
}
.sort-panel-close:hover { color: var(--text); }
.sort-panel-body { padding: 6px 14px; }
.sort-panel-footer {
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 8px;
}
.sort-key-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 0;
}
.sort-key-num {
  font-size: 11px;
  font-weight: 700;
  color: var(--primary);
  background: #eff6ff;
  border-radius: 4px;
  padding: 2px 0;
  width: 22px;
  text-align: center;
  flex-shrink: 0;
}
.sort-key-col {
  flex: 1;
  min-width: 0;
  padding: 5px 8px;
  font-size: 13px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: #fff;
}
.sort-dir-toggle {
  display: inline-flex;
  flex-shrink: 0;
}
.sort-dir-btn {
  border: 1px solid var(--border);
  background: #fff;
  font-size: 11px;
  padding: 4px 8px;
  cursor: pointer;
  line-height: 1.4;
  color: var(--text);
}
.sort-dir-btn:first-child { border-radius: 5px 0 0 5px; }
.sort-dir-btn:last-child  { border-radius: 0 5px 5px 0; margin-left: -1px; }
.sort-dir-btn.on { background: var(--primary); color: #fff; border-color: var(--primary); z-index: 1; position: relative; }
.sort-key-move,
.sort-key-remove {
  width: 24px;
  height: 24px;
  font-size: 11px;
  background: #f1f5f9;
  color: #475569;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  flex-shrink: 0;
}
.sort-key-move:hover:not(:disabled),
.sort-key-remove:hover { background: #e2e8f0; }
.sort-key-move:disabled { opacity: 0.35; cursor: not-allowed; }
.sort-key-remove:hover { background: #fee2e2; color: var(--danger); }
.sort-empty {
  padding: 14px 4px;
  font-size: 13px;
  color: var(--text-muted);
  font-style: italic;
  text-align: center;
}

/* Floating Feedback button — collapsed icon by default, expands on hover/focus */
.feedback-fab {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: 40px;
  height: 40px;
  padding: 0;
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: 20px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  overflow: hidden;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.14);
  z-index: 50;
  transition:
    width 0.28s cubic-bezier(0.4, 0, 0.2, 1),
    padding 0.28s cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 0.2s ease,
    background 0.15s ease,
    transform 0.15s ease;
}
.feedback-fab-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
}
.feedback-fab-label {
  opacity: 0;
  margin-right: 14px;
  transition: opacity 0.18s ease 0.06s;
}
.feedback-fab:hover,
.feedback-fab:focus-visible {
  width: 132px;
  background: #1d4ed8;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
  transform: translateY(-1px);
}
.feedback-fab:hover .feedback-fab-label,
.feedback-fab:focus-visible .feedback-fab-label { opacity: 1; }
.feedback-fab:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 3px; }
.feedback-fab:active { transform: translateY(0); }
.data-snapshot {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px 24px;
}
.data-section-title {
  grid-column: 1 / -1;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  padding: 6px 4px 0 4px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
  margin-top: 4px;
}
.data-section-title.danger { color: var(--danger); border-bottom-color: #fecaca; }
.data-grid .card .card-body p:last-of-type { margin-bottom: 14px; }
.data-grid .card .demo-bullets {
  color: var(--text-muted);
  font-size: 12.5px;
  margin: 0 0 12px 18px;
  line-height: 1.65;
}
.data-snapshot > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.data-snapshot .label { font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
.data-snapshot .value { font-size: 16px; font-weight: 600; }

/* Dashboard */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 16px; margin-bottom: 24px; }
.stat-card { background: var(--surface); border-radius: var(--radius); padding: 18px; box-shadow: var(--shadow); border: 1px solid var(--border); }
.stat-card .label { font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 6px; }
.stat-card .value { font-size: 28px; font-weight: 700; }
.stat-card.blue .value { color: var(--primary); }
.stat-card.green .value { color: var(--success); }
.stat-card.amber .value { color: var(--warning); }

/* Dashboard draggable grid */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 220px;
  grid-auto-flow: row dense;
  gap: 16px;
  align-items: stretch;
}
.dash-panel { min-width: 0; min-height: 0; position: relative; }
.dash-panel > .card { height: 100%; overflow: hidden; }

/* Drag handle — hidden until Arrange mode */
.dash-drag-handle {
  display: none; cursor: grab; font-size: 18px; color: #94a3b8;
  line-height: 1; flex-shrink: 0; padding: 2px;
  border-radius: 4px; transition: color 0.15s;
}
.dash-drag-handle:active { cursor: grabbing; }
.dash-edit .dash-drag-handle { display: block; }
.dash-edit .dash-drag-handle:hover { color: var(--primary); }

/* Close button — floats top-right of panel, only in arrange mode */
.dash-close {
  position: absolute;
  top: -8px; right: -8px;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: #fff;
  border: 1px solid var(--border);
  color: #64748b;
  font-size: 15px; line-height: 1;
  cursor: pointer;
  display: none;
  align-items: center; justify-content: center;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12);
  transition: all 0.15s;
  z-index: 2;
}
.dash-close:hover { background: var(--danger); color: #fff; border-color: var(--danger); transform: scale(1.05); }
.dash-edit .dash-close { display: inline-flex; }

/* Resize handle — bottom-right corner, only in arrange mode */
.dash-resize-handle {
  position: absolute;
  bottom: 2px; right: 2px;
  width: 16px; height: 16px;
  cursor: nwse-resize;
  display: none;
  z-index: 2;
  background:
    linear-gradient(135deg,
      transparent 0%, transparent 55%,
      #94a3b8 55%, #94a3b8 65%,
      transparent 65%, transparent 75%,
      #94a3b8 75%, #94a3b8 85%,
      transparent 85%);
  border-radius: 0 0 var(--radius) 0;
  opacity: 0.7;
  transition: opacity 0.15s;
}
.dash-resize-handle:hover { opacity: 1; }
.dash-edit .dash-resize-handle { display: block; }
.dash-panel.dash-resizing { user-select: none; }
.dash-panel.dash-resizing > .card { outline: 2px solid var(--primary); outline-offset: 1px; }

/* Add-panel tile — sibling below the grid, only in arrange mode */
.dash-add-tile {
  display: none;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin-top: 16px;
  padding: 14px 20px;
  background: transparent;
  border: 2px dashed #cbd5e1;
  border-radius: var(--radius);
  color: #64748b;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s;
}
.dash-add-tile:hover { border-color: var(--primary); color: var(--primary); background: #f8fafc; }
.dash-add-plus { font-size: 22px; line-height: 1; font-weight: 300; }
.dash-grid.dash-edit + .dash-add-tile { display: flex; }

.dash-add-menu {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 4px 16px rgba(0,0,0,0.12);
  min-width: 220px;
  padding: 6px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.dash-add-item {
  background: transparent;
  border: none;
  padding: 8px 12px;
  text-align: left;
  font-size: 13px;
  border-radius: 4px;
  cursor: pointer;
  color: #1e293b;
}
.dash-add-item:hover { background: #f1f5f9; color: var(--primary); }
.dash-add-empty { padding: 10px 12px; font-size: 13px; color: #94a3b8; font-style: italic; }

/* Drag states */
.dash-panel.dash-dragging { opacity: 0.3; }
.dash-panel.dash-over > .card {
  outline: 2px dashed var(--primary);
  outline-offset: 3px;
  background: #eff6ff;
}

/* Edit mode — highlight panels */
.dash-edit .dash-panel > .card {
  outline: 1px dashed #cbd5e1;
  outline-offset: 2px;
}
.dash-edit .dash-panel:hover > .card { outline-color: #94a3b8; }
.stat-card.red .value { color: var(--danger); }

/* Table */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
thead th { background: #f8fafc; text-align: left; padding: 10px 14px; font-weight: 400; font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); border-bottom: 2px solid var(--border); white-space: nowrap; }
tbody tr { border-bottom: 1px solid var(--border); transition: background 0.1s; }
tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: #f8fafc; }
tbody td { padding: 10px 14px; vertical-align: middle; }
.empty-row td { text-align: center; color: var(--text-muted); padding: 32px; font-style: italic; }

/* Buttons */
.btn { display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border-radius: 6px; font-size: 13px; font-weight: 500; cursor: pointer; border: none; transition: all 0.15s; white-space: nowrap; }
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-dark); }
.btn-secondary { background: #fff; color: var(--text); border: 1px solid var(--border); }
.btn-secondary:hover { background: #f1f5f9; }
.btn-print { background: #0f172a; color: #fff; border-color: #0f172a; }
.btn-print:hover { background: #1e293b; }
.btn-danger { background: #fee2e2; color: var(--danger); }
.btn-danger:hover { background: #fecaca; }
.btn-success { background: #dcfce7; color: var(--success); }
.btn-success:hover { background: #bbf7d0; }
.btn-sm { padding: 4px 10px; font-size: 12px; }

/* Workspace launcher buttons — used in the Test Results topbar (and
 * eventually any topbar that links into a dedicated workspace).
 * Each variant carries its workspace's identity color so the same
 * visual language follows the user once they land:
 *   stability     → blue   (matches stability.js modeColor)
 *   compare       → violet (neutral; Compare's own mode color flips
 *                            tests/samples/formulations once inside)
 * Sized to sit next to .btn-sm in the topbar without dominating
 * primary actions (which stay on .btn-primary blue). */
.btn-workspace {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px; font-size: 12px; font-weight: 600;
  border-radius: 6px; border: none; color: #fff; cursor: pointer;
  transition: background 0.12s, box-shadow 0.12s, transform 0.12s;
}
.btn-workspace:hover { transform: translateY(-1px); }
.btn-workspace-stability {
  background: #2563eb;
  box-shadow: 0 1px 3px rgba(37, 99, 235, 0.28);
}
.btn-workspace-stability:hover { background: #1d4ed8; }
.btn-workspace-compare {
  background: #6366f1;
  box-shadow: 0 1px 3px rgba(99, 102, 241, 0.28);
}
.btn-workspace-compare:hover { background: #4f46e5; }
/* Icon-only action buttons (View, Edit, Duplicate, Delete in row    */
/* action columns). Enforce a consistent box + alignment so all four  */
/* buttons in the row line up flush regardless of:                    */
/*   - content width (narrow ✕ glyph vs wider PNG icons)              */
/*   - parent variant border (.btn-secondary has 1px border,          */
/*     .btn-danger doesn't — would make Delete 2px shorter without    */
/*     min-height + transparent border below)                          */
/*   - inline baseline: button-with-image and button-with-text have    */
/*     different inline baselines, which made the ✕ Delete sit 3px    */
/*     lower than its siblings in the table cell. vertical-align +    */
/*     forcing the same border on btn-danger fixes that.              */
.btn-icon { padding: 5px 8px; min-width: 32px; min-height: 26px; box-sizing: border-box; justify-content: center; vertical-align: middle; }
.btn-icon.btn-danger { border: 1px solid transparent; }

/* Forms */
.modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 300; display: flex; align-items: center; justify-content: center; padding: 16px; }
.modal { background: var(--surface); border-radius: 10px; width: 100%; max-width: 640px; max-height: 90vh; display: flex; flex-direction: column; box-shadow: 0 20px 25px rgba(0,0,0,0.15); }
.modal.wide { max-width: 1000px; }
.modal-header { padding: 16px 20px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; }
.modal-header h3 { font-size: 16px; font-weight: 600; }
.modal-body { padding: 20px; overflow-y: auto; flex: 1; }
.modal-footer { padding: 14px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 8px; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.form-grid.cols-3 { grid-template-columns: 1fr 1fr 1fr; }
.form-group { display: flex; flex-direction: column; gap: 4px; }
.form-group.span-2 { grid-column: span 2; }
.form-group.span-3 { grid-column: span 3; }
label { font-size: 12px; font-weight: 500; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
input, select, textarea { width: 100%; padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; font-size: 14px; font-family: inherit; color: var(--text); background: #fff; transition: border-color 0.15s; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37,99,235,0.1); }
textarea { resize: vertical; min-height: 70px; }
.section-divider { margin: 16px 0; border: none; border-top: 1px solid var(--border); }
.section-title { font-size: 13px; font-weight: 600; color: var(--text); margin-bottom: 10px; padding-bottom: 6px; border-bottom: 2px solid var(--primary); display: inline-block; }

/* Audit badge — small pill used in the audit log table */
.audit-badge { display: inline-block; padding: 2px 8px; border-radius: 9999px; font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em; }

/* Notebook entry — Quill HTML is rendered raw, so re-apply the formatting
   styles outside the editor's own scoped CSS. */
.notebook-entry p          { margin: 0 0 6px; }
.notebook-entry p:last-child { margin-bottom: 0; }
.notebook-entry h2         { font-size: 16px; font-weight: 700; margin: 8px 0 6px; }
.notebook-entry h3         { font-size: 14px; font-weight: 600; margin: 8px 0 6px; }
.notebook-entry ul, .notebook-entry ol { margin: 4px 0 6px 22px; padding: 0; }
.notebook-entry li         { margin-bottom: 2px; }
.notebook-entry blockquote { border-left: 3px solid var(--border); padding: 2px 10px; margin: 6px 0; color: var(--text-muted); }
.notebook-entry pre, .notebook-entry .ql-code-block { background: #f1f5f9; padding: 8px 10px; border-radius: 4px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; white-space: pre-wrap; margin: 6px 0; }
.notebook-entry a          { color: var(--primary); text-decoration: underline; }

/* Grouped form / detail sections (Ingredient modal + detail view) */
.form-section { display: flex; flex-direction: column; gap: 8px; padding-top: 14px; margin-top: 10px; border-top: 1px solid var(--border); }
.form-section:first-of-type { padding-top: 0; margin-top: 0; border-top: none; }
.ing-section-h { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin: 0 0 10px; padding-bottom: 4px; border-bottom: 1px solid var(--border); }

/* GHS pictograms + H/P code pills */
.ghs-pictogram { display: inline-flex; flex-direction: column; align-items: center; gap: 2px; }
.ghs-code-pill { display: inline-block; padding: 2px 8px; border-radius: 9999px; font-size: 11.5px; font-weight: 600; border: 1px solid; background: #fff; cursor: help; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* Badges */
.badge { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 9999px; font-size: 11.5px; font-weight: 500; }
.badge-blue { background: #dbeafe; color: #1d4ed8; }
.badge-green { background: #dcfce7; color: #15803d; }
.badge-amber { background: #fef3c7; color: #b45309; }
.badge-red { background: #fee2e2; color: #b91c1c; }
.badge-gray { background: #f1f5f9; color: #475569; }
.badge-purple { background: #ede9fe; color: #6d28d9; }

/* Composition table */
.comp-row { display: grid; grid-template-columns: 2fr 1fr 1fr 1.5fr 36px; gap: 6px; align-items: center; margin-bottom: 6px; }
.comp-header { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); padding-bottom: 4px; border-bottom: 1px solid var(--border); margin-bottom: 8px; }
.step-row { display: grid; grid-template-columns: 40px 1fr 80px 80px 100px 36px; gap: 6px; align-items: start; margin-bottom: 8px; }
.step-num { background: var(--primary); color: #fff; width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 12px; flex-shrink: 0; margin-top: 2px; }

/* Detail view */
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.detail-field { }
.detail-field .label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 3px; }
.detail-field .value { font-size: 14px; }
.tabs { display: flex; gap: 0; border-bottom: 2px solid var(--border); margin-bottom: 18px; }
.tab { padding: 8px 16px; font-size: 13.5px; font-weight: 500; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -2px; color: var(--text-muted); }
.tab.active { color: var(--primary); border-bottom-color: var(--primary); }
.tab:hover:not(.active) { color: var(--text); }

/* Alerts */
.alert { padding: 12px 14px; border-radius: 6px; font-size: 13.5px; margin-bottom: 16px; }
.alert-info { background: #eff6ff; color: #1d4ed8; border-left: 3px solid var(--primary); }

/* Breadcrumb */
.breadcrumb { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-muted); margin-bottom: 16px; }
.breadcrumb a { color: var(--primary); cursor: pointer; }
.breadcrumb a:hover { text-decoration: underline; }
.breadcrumb .sep { color: var(--border); }

/* Legacy responsive block removed — the mobile drawer + media query
 * below now handle sidebar / form-grid layout on narrow viewports. */

/* Tier 3 mobile-utility classes:
 *   .desktop-only — hidden below 768px (mobile)
 *   .mobile-warn  — a small banner that's hidden on desktop and
 *                   shown above content that doesn't translate well
 *                   to mobile (DOE Matrix, Composition editor, etc.) */
.mobile-warn { display: none; }
.mobile-warn-banner {
  align-items: flex-start; gap: 10px;
  background: #fffbeb; border: 1px solid #f59e0b; border-radius: 8px;
  padding: 10px 12px; margin: 0 0 14px 0;
  font-size: 13px; color: #92400e; line-height: 1.45;
}
.mobile-warn-banner .icon { font-size: 16px; flex-shrink: 0; line-height: 1; }
@media (max-width: 768px) {
  .desktop-only { display: none !important; }
  .mobile-warn { display: flex; }
}
thead th { position: relative; }
.col-rh { position: absolute; right: 0; top: 0; height: 100%; width: 5px; cursor: col-resize; z-index: 2; user-select: none; }
.col-rh:hover, .col-rh:active { background: var(--primary); opacity: 0.4; border-radius: 2px; }
.col-picker-item:hover { background: #f1f5f9; }
.col-picker-item .col-drag-grip { opacity: 0.4; }
/* Column drag-to-reorder — data tables and compare table */
thead th[draggable="true"] { cursor: grab; }
thead th[draggable="true"]:active { cursor: grabbing; }
thead th.col-drag-over { box-shadow: -3px 0 0 var(--primary); }
.col-picker-item:hover .col-drag-grip { opacity: 1; }

/* Formula Analysis tabs */
.fa-tab {
  background: none; border: 1px solid var(--border); border-radius: 6px;
  padding: 5px 14px; cursor: pointer; font-size: 13px; color: var(--text-muted);
  transition: background 0.15s, color 0.15s, border-color 0.15s;
  white-space: nowrap;
}
.fa-tab:hover { background: #f1f5f9; color: var(--text); }
.fa-tab-on { background: var(--primary); color: #fff; border-color: var(--primary); }
.fa-tab-on:hover { background: var(--primary-dark); }

/* ============================================================
   COLUMN HEADER FILTERS
   ============================================================ */
tr.filter-row th {
  background: #f1f5f9; padding: 5px 8px; border-bottom: 2px solid var(--border);
}
.col-filter {
  width: 100%; padding: 3px 6px; font-size: 12px;
  border: 1px solid #cbd5e1; border-radius: 4px;
  font-family: inherit; color: var(--text); background: #fff;
}
.col-filter:focus { outline: none; border-color: var(--primary); }
.col-filter-clear {
  background: none; border: none; cursor: pointer;
  color: #94a3b8; font-size: 14px; padding: 2px 4px;
  border-radius: 4px; line-height: 1;
}
.col-filter-clear:hover { color: var(--danger); background: #fee2e2; }

/* ============================================================
   BULK SELECTION
   ============================================================ */
.bulk-check-col { width: 36px; padding: 0 8px !important; text-align: center; }
.bulk-check-col input[type="checkbox"] {
  cursor: pointer; width: 15px; height: 15px;
  accent-color: var(--primary); vertical-align: middle;
}
.bulk-bar {
  display: none; align-items: center; gap: 10px;
  padding: 8px 18px; background: #eff6ff;
  border-bottom: 1px solid #bfdbfe; font-size: 13px; color: #1d4ed8;
}
.bulk-bar .bulk-count { font-weight: 600; flex: 1; }

/* ============================================================
   PRINT / PDF — shared helpers
   ============================================================ */

/* .print-only — hidden on screen, revealed during print. Used for
   page-1 report headers on test detail (and any future detail view
   that wants its own print header). */
.print-only { display: none !important; }

/* Test report print-header layout. The header is hidden on screen
   and only flows into the printed PDF. Keep it simple and dense —
   one block at the top of page 1, with key identifying fields in a
   compact 3×2 grid. */
.test-print-header {
  border-bottom: 2px solid #0f172a;
  padding-bottom: 12px;
  margin-bottom: 16px;
}
.test-print-brand {
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #64748b;
  margin-bottom: 4px;
}
.test-print-title {
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 10px 0;
  color: #0f172a;
}
.test-print-meta {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px 24px;
  font-size: 11.5px;
  color: #1e293b;
}
.test-print-meta > div span {
  display: inline-block;
  min-width: 90px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #64748b;
  margin-right: 4px;
}

/* ============================================================
   PRINT / PDF — Dashboard + Test Detail
   ============================================================ */
@media print {
  /* Reveal print-only blocks (e.g. test report header) */
  .print-only { display: block !important; }
}
@media print {
  /* Force color printing */
  *, *::before, *::after {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  /* Hide all chrome except the dashboard content */
  #sidebar,
  #topbar,
  .breadcrumb,
  #import-file { display: none !important; }

  /* Remove arrange/print controls from output */
  #dash-arrange-btn,
  .dash-drag-handle,
  .dash-close,
  .dash-resize-handle,
  .dash-add-tile,
  .dash-add-menu,
  .feedback-fab,
  .sort-panel,
  .btn { display: none !important; }

  /* Make layout take full page width */
  body, #app, #main { display: block !important; width: 100% !important; }
  #content { padding: 0 !important; overflow: visible !important; }
  #main { overflow: visible !important; }

  /* Print header — date + title */
  #dash-grid::before {
    content: "FormLab Dashboard  ·  " attr(data-print-date);
    display: block;
    font-size: 11px;
    color: #64748b;
    text-align: right;
    margin-bottom: 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid #e2e8f0;
    grid-column: 1 / -1;
  }

  /* Keep grid structure, allow wrapping across pages */
  .dash-grid {
    display: grid !important;
    grid-template-columns: repeat(3, 1fr) !important;
    grid-auto-rows: auto !important;
    gap: 12px !important;
  }

  /* Avoid splitting a panel card across a page break */
  .dash-panel { break-inside: avoid; }

  /* Stat grid */
  .stat-grid {
    display: grid !important;
    grid-template-columns: repeat(7, 1fr) !important;
    gap: 8px !important;
    margin-bottom: 14px !important;
  }
  .stat-card { padding: 10px 12px !important; }
  .stat-card .value { font-size: 20px !important; }

  /* Tables */
  .table-wrap { overflow: visible !important; }
  table { page-break-inside: auto; }
  tr { page-break-inside: avoid; }

  /* Cards */
  .card { box-shadow: none !important; border: 1px solid #e2e8f0 !important; }
  .card-header { padding: 8px 12px !important; }

  /* ---- Test report PDF specifics ----
     Hide interactive bits that don't make sense in a static PDF:
     attachment chips + "+ Attach" buttons, the "View history →" link
     in the audit footer, the "Pivot to broader view" links in the
     performance card footer, and the breadcrumb (the print header at
     the top already names the report). */
  .breadcrumb { display: none !important; }
  /* Attachment cell in measurements table — keep the chips visible
     (they document evidence files) but drop the "+ Attach" button. */
  button[onclick^="addMeasAttachmentClick"],
  button[onclick^="addTestAttachmentClick"],
  input[type="file"] { display: none !important; }
  /* Test-attachment drop zone (whole drag-drop area) — useless in print */
  [id^="test-attach-drop-"] { display: none !important; }
  /* Notebook composer (the "Log a note" input + editor) — useless in print.
     The list of saved notes below still renders normally. */
  #nb-composer { display: none !important; }
  /* Audit footer right-aligned "View history →" link — pointless in
     a PDF (no navigation context). */
  a[onclick="navigate('audit')"] { display: none !important; }
  /* Performance card pivot links — same reason. */
  a[onclick^="_formulaOpenInStability"],
  a[onclick^="_formulaOpenInCompare"],
  a[onclick^="navigate('formulation-detail'"],
  a[onclick^="navigate('samples')"],
  a[onclick^="navigate('test-detail'"] { color: inherit !important; text-decoration: none !important; cursor: default !important; }

  /* Topbar back/forward arrows — already hidden via #topbar rule
     above, but listing here for documentation. */
}

/* ============================================================
 * Mobile (Tier 1) — viewport <= 768px
 * Sidebar becomes a slide-in drawer, modals go full-screen,
 * form grids stack, topbar actions scroll horizontally.
 * ============================================================ */

/* Backdrop + burger are off by default; the @media block below
 * makes the burger visible and lets the backdrop show when the
 * sidebar's .mobile-open class is on. */
#sidebar-backdrop { display: none; }
#mobile-menu-btn {
  display: none;
  background: none; border: none; cursor: pointer;
  color: var(--text); padding: 4px 8px;
  font-size: 22px; line-height: 1;
  border-radius: 6px;
}
#mobile-menu-btn:hover { background: #f1f5f9; }

@media (max-width: 768px) {
  #mobile-menu-btn { display: inline-flex; }

  /* Sidebar becomes a fixed drawer that slides in from the left */
  #sidebar {
    position: fixed; top: 0; left: 0;
    width: 240px !important;
    height: 100vh;
    height: 100dvh;
    z-index: 120;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    box-shadow: 0 0 24px rgba(0, 0, 0, 0.3);
  }
  #sidebar.mobile-open { transform: translateX(0); }
  /* On mobile, ignore desktop "collapsed" mode — drawer is binary */
  #sidebar.collapsed { width: 240px !important; }
  #sidebar.collapsed .logo-text,
  #sidebar.collapsed .nav-section,
  #sidebar.collapsed .nav-item { font-size: inherit; opacity: 1; height: auto; }
  #sidebar.collapsed .nav-item { padding: 8px 14px; gap: 10px; }
  #sidebar.collapsed .nav-item .icon { font-size: 16px; margin-right: 6px; }
  #sidebar-resizer { display: none; }
  /* Hide the collapse toggle on mobile (drawer is binary) but keep
   * the account button visible at the bottom of the drawer. */
  #sidebar .sidebar-footer { justify-content: flex-start; }
  #sidebar .sidebar-footer .sidebar-toggle { display: none; }

  /* Backdrop — visible whenever the drawer is open */
  #sidebar-backdrop {
    display: block;
    position: fixed; inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 110;
    opacity: 0; pointer-events: none;
    transition: opacity 0.25s ease;
  }
  body.sidebar-open #sidebar-backdrop { opacity: 1; pointer-events: auto; }

  /* Main takes the full viewport — sidebar overlays it */
  #main { width: 100%; }
  #topbar { padding: 0 12px; gap: 8px; }
  #topbar h1 { font-size: 15px; }

  /* Topbar actions: scroll horizontally instead of wrapping */
  #topbar .actions {
    overflow-x: auto; overflow-y: hidden;
    flex-wrap: nowrap;
    scrollbar-width: thin;
    margin-left: 8px;
    padding: 4px 0;
  }
  #topbar .actions::-webkit-scrollbar { height: 4px; }
  #topbar .actions .btn { flex-shrink: 0; }

  /* Modal: full-screen */
  .modal-backdrop { padding: 0; }
  .modal, .modal.wide {
    width: 100%; max-width: none;
    height: 100vh; max-height: 100vh;
    border-radius: 0;
  }
  .modal-body { padding: 14px; }
  .modal-header { padding: 12px 14px; }
  .modal-footer { padding: 12px 14px; }

  /* Form grids collapse to single column */
  .form-grid, .form-grid.cols-3 { grid-template-columns: 1fr; }
  .form-group.span-2, .form-group.span-3 { grid-column: span 1; }

  /* Bigger tap targets for primary interactive elements */
  .btn { padding: 9px 14px; min-height: 36px; }
  .btn-sm { padding: 6px 10px; min-height: 32px; }
  .btn-icon { min-width: 32px; min-height: 32px; padding: 4px 8px; }
  input, select, textarea { padding: 10px 12px; font-size: 15px; }
  .nav-item { min-height: 40px; }

  /* Data view grid collapses */
  .data-grid { grid-template-columns: 1fr; }

  /* ---- Tier 2: read-optimized detail / dashboard / table layouts ---- */

  /* Detail panel grids (info / stats / etc.) → single column. Several
   * call sites set grid-template-columns inline (e.g., "repeat(3,1fr)")
   * so we use !important to win the cascade. */
  .detail-grid { grid-template-columns: 1fr !important; }
  .detail-field[style*="grid-column"] { grid-column: span 1 !important; }

  /* Tabs scroll horizontally instead of wrapping */
  .tabs {
    overflow-x: auto; overflow-y: hidden;
    flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }
  .tabs::-webkit-scrollbar { height: 3px; }
  .tab { flex-shrink: 0; white-space: nowrap; padding: 8px 12px; font-size: 13px; }

  /* Dashboard draggable grid → stack panels vertically */
  .dash-grid {
    grid-template-columns: 1fr !important;
    grid-auto-rows: auto !important;
    gap: 12px;
  }
  .dash-panel {
    grid-column: span 1 !important;
    grid-row: auto !important;
  }
  .dash-panel > .card { height: auto; min-height: 180px; overflow: visible; }
  /* Hide arrange/resize affordances on mobile — desktop-only workflow */
  .dash-resize-handle, .dash-close { display: none !important; }

  /* Stat grid: 2 columns instead of auto-fill minmax-180 (which leaves
   * too much padding on narrow viewports) */
  .stat-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .stat-card { padding: 14px; }
  .stat-card .value { font-size: 22px; }

  /* Breadcrumb tighter */
  .breadcrumb { font-size: 12px; margin-bottom: 12px; }

  /* Tables already scroll horizontally via .table-wrap, but we add a
   * shadow hint at the right edge so users see they can swipe. */
  .table-wrap { position: relative; }
  .table-wrap::after {
    content: ''; position: absolute; top: 0; right: 0; bottom: 0; width: 12px;
    background: linear-gradient(to left, rgba(0,0,0,0.07), transparent);
    pointer-events: none;
  }
}

/* ===================================================================
   Print / Save-as-PDF — Test Compare workspace
   -------------------------------------------------------------------
   Triggered by the "🖨 Print / PDF" export option (which calls
   window.print()). When printing, hide everything that isn't part
   of the report — sidebar, topbar, controls bar, Smart Picks
   strip, picker rail, resize handle, viz controls — and let the
   report content flow naturally as a printable document:
     - Print header (config summary)
     - Selected items strip
     - Insights panel
     - Comparison table
     - Visualization (canvas snapshot of current plot)
   =================================================================== */
@media print {
  /* Page setup — leave room for browser-added headers/footers */
  @page { margin: 12mm; }

  /* Reset body / app shell to a flat printable canvas */
  html, body, #app, #main, #content {
    height: auto !important;
    overflow: visible !important;
    background: #fff !important;
    color: #000 !important;
  }

  /* Hide everything that isn't the comparison report */
  #sidebar,
  #topbar,
  #feedback-fab,
  #sidebar-backdrop,
  #mobile-menu-btn,
  .test-compare-resizer,
  #test-compare-picker-card,
  [data-tc-controls],
  [data-tc-suggestions],
  [data-tc-viz-chrome],
  .modal-backdrop { display: none !important; }

  /* Main column stretches edge-to-edge for print */
  #main { width: 100% !important; max-width: 100% !important; }
  #content { padding: 0 !important; }

  /* Workspace: collapse to a vertical document flow */
  #test-compare-workspace {
    display: block !important;
    min-height: 0 !important;
    height: auto !important;
    gap: 0 !important;
  }
  #test-compare-workspace > div { display: block !important; }

  /* The table-card row was a flex row in screen; flatten it for print */
  #test-compare-workspace > div[style*="display:flex"] {
    display: block !important;
    max-height: none !important;
  }
  #test-compare-workspace > div > div {
    max-height: none !important;
    overflow: visible !important;
    border-top: none !important;
    margin-bottom: 12px;
  }

  /* The comparison table needs to print as an actual table (no scroll) */
  #test-compare-table {
    overflow: visible !important;
    max-height: none !important;
  }
  #test-compare-table table {
    border-collapse: collapse !important;
    page-break-inside: auto;
  }
  #test-compare-table thead { display: table-header-group; }
  #test-compare-table tr { page-break-inside: avoid; }

  /* Viz panel — keep canvases visible, drop the chrome */
  #test-compare-viz-wrap {
    page-break-inside: avoid;
    border-top: 1px solid #ccc !important;
    margin-top: 16px !important;
    padding-top: 12px !important;
  }

  /* Print header — visible only in print, shows config summary */
  #test-compare-print-header { display: block !important; }
  #test-compare-print-header h1 {
    font-size: 18pt !important;
    margin-bottom: 6pt !important;
  }
  #test-compare-print-header .summary {
    font-size: 10pt !important;
    color: #444 !important;
    line-height: 1.5;
  }

  /* Color overrides — keep semantic chip backgrounds but force readable text */
  .test-compare-resizer, [class*="resizer"] { display: none !important; }

  /* ---- Stability workspace mirrors the same print scope ---- */
  #stab-picker-card,
  [data-stab-controls] { display: none !important; }
  #stability-workspace {
    display: block !important;
    min-height: 0 !important;
    height: auto !important;
    gap: 0 !important;
  }
  #stability-workspace > div { display: block !important; }
  #stability-workspace > div[style*="display:flex"] {
    display: block !important;
    max-height: none !important;
  }
  #stability-workspace > div > div {
    max-height: none !important;
    overflow: visible !important;
    border-top: none !important;
    margin-bottom: 12px;
  }
  #stab-chart-mount { overflow: visible !important; max-height: none !important; min-height: 400px !important; }
  #stab-print-header { display: block !important; }
  #stab-print-header h1 { font-size: 18pt !important; margin-bottom: 6pt !important; }
}

/* Compare workspace topbar dropdown buttons (Saved + Export).
   Locks both to the same width so the Compare topbar reads as a
   consistent row, regardless of the live (N) count in "Saved (N)".
   Maximum specificity + all width constraints — defeats stale-
   cache rendering, flex-shrink, AND padding-eats-width. */
#topbar #topbar-actions .btn.tc-topbar-pill {
  display: inline-flex !important;
  width: 150px !important;
  min-width: 150px !important;
  max-width: 150px !important;
  flex-shrink: 0 !important;
  justify-content: center !important;
  box-sizing: border-box !important;
  padding-left: 10px !important;
  padding-right: 10px !important;
}

/* ===================================================================
   Test Compare — clickable table headers (viz scope picker)
   -------------------------------------------------------------------
   The cells with onclick="_tcVizToggleRowFilter / _tcVizToggleColFilter"
   need a stronger hover signal than just cursor:pointer so the
   "click to scope the chart below" affordance is obvious. Subtle
   blue tint on hover; bolder when already in scope.
   =================================================================== */
#test-compare-table th[onclick],
#test-compare-table td[onclick] {
  transition: background-color 0.12s, box-shadow 0.12s;
}
#test-compare-table th[onclick]:hover,
#test-compare-table td[onclick]:hover {
  background: #eff6ff !important;
  box-shadow: inset 0 -2px 0 #2563eb;
}
body.testing-dark[data-view="test-compare"] #test-compare-table th[onclick]:hover,
body.testing-dark[data-view="test-compare"] #test-compare-table td[onclick]:hover {
  background: #1e3a8a !important;
  box-shadow: inset 0 -2px 0 #60a5fa;
}

/* ===================================================================
   Test Compare — on-plot annotations (DOE-Matrix-style overlay)
   -------------------------------------------------------------------
   Draggable rich-text notes positioned directly on top of the chart.
   The layer fills #tc-viz-canvas-wrap, sits above the chart with
   pointer-events:none so chart hover keeps working; per-note
   pointer-events:auto re-enables interaction on the notes themselves.
   Scoped tightly to .tc-viz-annot* so the page-level dark-mode
   broad selectors can't bleed into the editor / notes.
   =================================================================== */
.tc-viz-annot-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 5;
  /* Don't expand the layout — purely overlay */
  overflow: visible;
}
.tc-viz-annot {
  position: absolute;
  pointer-events: auto;
  transform: translate(-50%, -50%);
  max-width: 260px;
  background: rgba(255, 255, 255, 0.96);
  border: 1px solid #cbd5e1;
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 11.5px;
  line-height: 1.45;
  color: #0f172a;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
  cursor: move;
  user-select: none;
  transition: box-shadow 0.12s, opacity 0.12s;
  white-space: normal;
}
.tc-viz-annot.tc-viz-annot-transparent {
  background: transparent;
  border: 1px dashed rgba(15, 23, 42, 0.4);
  box-shadow: none;
}
.tc-viz-annot:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18); }
.tc-viz-annot.tc-viz-annot-dragging {
  opacity: 0.85;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.22);
  cursor: grabbing;
}
.tc-viz-annot .tc-viz-annot-content > * { margin: 0; }
.tc-viz-annot .tc-viz-annot-content p { margin: 0 0 4px; }
.tc-viz-annot .tc-viz-annot-content p:last-child { margin-bottom: 0; }
.tc-viz-annot .tc-viz-annot-content ul,
.tc-viz-annot .tc-viz-annot-content ol { margin: 4px 0 0 16px; padding: 0; }
.tc-viz-annot .tc-viz-annot-del {
  position: absolute;
  top: -8px; right: -8px;
  width: 18px; height: 18px;
  border-radius: 9999px;
  background: #fff;
  border: 1px solid #cbd5e1;
  color: #dc2626;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
}
.tc-viz-annot:hover .tc-viz-annot-del { display: inline-flex; }

/* Dark mode — readable note bg + light text, scoped so the page's
   broad #0f172a → light rule doesn't rewrite our annotation text
   incorrectly. */
body.testing-dark[data-view="test-compare"] .tc-viz-annot {
  background: rgba(31, 41, 55, 0.96);
  border-color: #475569;
  color: #f1f5f9;
}
body.testing-dark[data-view="test-compare"] .tc-viz-annot.tc-viz-annot-transparent {
  background: transparent;
  border-color: rgba(241, 245, 249, 0.5);
}
body.testing-dark[data-view="test-compare"] .tc-viz-annot .tc-viz-annot-del {
  background: #1f2937;
  border-color: #475569;
  color: #fca5a5;
}

/* Print: annotations stay visible on the printed report, drop the
   delete button (not useful on paper). */
@media print {
  .tc-viz-annot .tc-viz-annot-del { display: none !important; }
  .tc-viz-annot { box-shadow: none !important; border-color: #999 !important; color: #000 !important; }
}

/* The annotation EDITOR modal: scope Quill rules tightly so we don't
   bleed into the notebook editor or the notes-panel editor. */
.tc-viz-annot-editor-host .ql-toolbar.ql-snow {
  border-radius: 6px 6px 0 0;
  background: #f8fafc;
}
.tc-viz-annot-editor-host .ql-container.ql-snow {
  border-radius: 0 0 6px 6px;
  font-family: inherit;
}
.tc-viz-annot-editor-host .ql-editor {
  min-height: 120px;
  color: #0f172a;
}
body.testing-dark[data-view="test-compare"] .tc-viz-annot-editor-host .ql-toolbar.ql-snow {
  background: #111827 !important;
  border-color: #374151 !important;
}
body.testing-dark[data-view="test-compare"] .tc-viz-annot-editor-host .ql-container.ql-snow {
  background: #1f2937 !important;
  border-color: #374151 !important;
}
body.testing-dark[data-view="test-compare"] .tc-viz-annot-editor-host .ql-editor {
  color: #f1f5f9 !important;
  background: #1f2937 !important;
}

/* ===================================================================
   Test Compare — picker resize handle
   -------------------------------------------------------------------
   Vertical strip between the picker rail and the comparison table.
   Generous hit area (16 px wide) with an always-visible grip — the
   picker's right-edge content (PASS / FAIL chips) sits very close,
   so the grip needs to read clearly without forcing the user to
   hunt for it. The grip uses the active mode's accent color via the
   --tc-accent custom property the JS sets at workspace render time,
   tying it visually to the mode pills + card top accents.
   =================================================================== */
.test-compare-resizer {
  flex: 0 0 16px;
  margin: 0 2px;
  align-self: stretch;
  cursor: col-resize;
  background: transparent;
  position: relative;
  user-select: none;
}
.test-compare-resizer::before {
  /* Always-visible grip — a ⋮⋮ pair of dashes rendered with two
     adjacent gradients so we don't need an extra DOM node. */
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 4px; height: 60px;
  background: var(--tc-accent, #94a3b8);
  border-radius: 2px;
  opacity: 0.55;
  transition: opacity 0.15s, height 0.15s, width 0.15s;
}
.test-compare-resizer::after {
  /* Tiny "drag" arrow indicators above + below the bar so the
     vertical line reads as "drag horizontally," not "border." */
  content: '⇔';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  font-size: 10px;
  color: var(--tc-accent, #64748b);
  opacity: 0;
  pointer-events: none;
  background: var(--surface, #fff);
  padding: 1px 3px;
  border-radius: 4px;
  transition: opacity 0.15s;
}
.test-compare-resizer:hover::before {
  opacity: 1;
  width: 5px;
  height: 80px;
}
.test-compare-resizer:hover::after {
  opacity: 1;
}
body.testing-dark[data-view="test-compare"] .test-compare-resizer::after {
  background: #1f2937;
  color: var(--tc-accent, #94a3b8);
}

/* ===================================================================
   Dark mode for the Test Results workflow
   -------------------------------------------------------------------
   Triggered by `body.testing-dark`. Scoped to the test-related views
   via `[data-view="..."]` so it never bleeds onto Dashboard /
   Ingredients / etc. even though the body class persists globally.
   Covers: Test Results list, Test Detail, Test Compare workspace,
   and any modal opened while on those views (Stability view).

   Strategy: override CSS custom properties so anything using
   var(--surface) / var(--text) / var(--border) flips automatically.
   Then a targeted set of !important rules covers the inline-styled
   light backgrounds (#fff, #f8fafc) that are common in compare /
   stability templates.
   =================================================================== */
body.testing-dark[data-view="testing"],
body.testing-dark[data-view="test-detail"],
body.testing-dark[data-view="test-compare"],
body.testing-dark[data-view="stability"] {
  --bg: #0f172a;
  --surface: #1f2937;
  --border: #374151;
  --text: #f1f5f9;
  --text-muted: #94a3b8;
}
body.testing-dark[data-view="testing"] #content,
body.testing-dark[data-view="test-detail"] #content,
body.testing-dark[data-view="test-compare"] #content {
  background: #0f172a;
}
body.testing-dark[data-view="testing"] #topbar,
body.testing-dark[data-view="test-detail"] #topbar,
body.testing-dark[data-view="test-compare"] #topbar {
  background: #0f172a;
  border-bottom-color: #374151;
}
body.testing-dark[data-view="testing"] #page-title,
body.testing-dark[data-view="test-detail"] #page-title,
body.testing-dark[data-view="test-compare"] #page-title { color: #f1f5f9; }

/* Card frames + tables (page-level) */
body.testing-dark[data-view="testing"] .card,
body.testing-dark[data-view="test-detail"] .card,
body.testing-dark[data-view="test-compare"] .card {
  background: #1f2937 !important;
  border-color: #374151 !important;
  color: #f1f5f9;
}
body.testing-dark[data-view="testing"] table,
body.testing-dark[data-view="test-detail"] table,
body.testing-dark[data-view="test-compare"] table {
  color: #f1f5f9;
}
body.testing-dark[data-view="testing"] thead th,
body.testing-dark[data-view="test-detail"] thead th,
body.testing-dark[data-view="test-compare"] thead th {
  background: #111827 !important;
  color: #e5e7eb !important;
  border-bottom-color: #374151 !important;
}
body.testing-dark[data-view="testing"] tbody td,
body.testing-dark[data-view="test-detail"] tbody td,
body.testing-dark[data-view="test-compare"] tbody td {
  border-bottom-color: #374151 !important;
}

/* Inline-styled #fff backgrounds inside the Test Compare workspace */
body.testing-dark[data-view="test-compare"] #test-compare-workspace > div[style*="background:#f8fafc"],
body.testing-dark[data-view="test-compare"] #test-compare-workspace [style*="background:#fff"] {
  background: #1f2937 !important;
  color: #f1f5f9;
  border-color: #374151 !important;
}
body.testing-dark[data-view="test-compare"] #test-compare-workspace td[style*="background:#fff"],
body.testing-dark[data-view="test-compare"] #test-compare-workspace th[style*="background:#f8fafc"] {
  background: #111827 !important;
  color: #e5e7eb !important;
}
/* Yellow diff highlight gets a darker amber on dark bg so it stays
   visible without burning out the eyes. */
body.testing-dark[data-view="test-compare"] [style*="background:#fffbeb"] {
  background: #3f2d0a !important;
  color: #fde68a !important;
}
/* Pass / fail / untested chips and tiles look fine on dark — leave
   the colored swatches alone but lighten the text where it was dark
   navy by default. */
body.testing-dark[data-view="testing"] .card *,
body.testing-dark[data-view="test-detail"] .card *,
body.testing-dark[data-view="test-compare"] #test-compare-workspace * {
  color: inherit;
}
/* But: re-allow muted hint text to stay grey */
body.testing-dark[data-view="testing"] .card [style*="color:#94a3b8"],
body.testing-dark[data-view="test-compare"] #test-compare-workspace [style*="color:#94a3b8"],
body.testing-dark[data-view="testing"] .card [style*="color:#64748b"],
body.testing-dark[data-view="test-compare"] #test-compare-workspace [style*="color:#64748b"] {
  color: #94a3b8 !important;
}
/* Headings and labels that were dark navy → light slate */
body.testing-dark[data-view="testing"] .card [style*="color:#0f172a"],
body.testing-dark[data-view="test-detail"] .card [style*="color:#0f172a"],
body.testing-dark[data-view="test-compare"] #test-compare-workspace [style*="color:#0f172a"] {
  color: #f1f5f9 !important;
}
/* Mid-grey text (used by inactive mode pills, etc.) → light slate */
body.testing-dark[data-view="test-compare"] #test-compare-workspace [style*="color:#334155"] {
  color: #e5e7eb !important;
}

/* Standard buttons inside dark testing views.
   ----------------------------------------------------------------
   .btn-secondary is hardcoded `background:#fff; color: var(--text)`.
   The page-level --text override flips text to light slate, which
   would leave a white pill with light text on it (invisible). Flip
   the button background + border to dark surface so the same
   --text color reads correctly. We DON'T touch buttons that already
   have an inline background (selected period chips, mode pills,
   layout pills, dark-mode toggle when on) — inline style wins via
   specificity, so their per-state styling is preserved. */
body.testing-dark[data-view="testing"] .btn-secondary,
body.testing-dark[data-view="test-detail"] .btn-secondary,
body.testing-dark[data-view="test-compare"] .btn-secondary {
  background: #1f2937;
  color: #e5e7eb;
  border-color: #374151;
}
body.testing-dark[data-view="testing"] .btn-secondary:hover,
body.testing-dark[data-view="test-detail"] .btn-secondary:hover,
body.testing-dark[data-view="test-compare"] .btn-secondary:hover {
  background: #374151;
  color: #f8fafc;
}
/* Danger / success / primary keep their semantic colors but get
   text-color overrides so the label reads on the colored fill in
   either mode (these already work in light mode; this is just a
   safety net). */
body.testing-dark[data-view="testing"] .btn-danger,
body.testing-dark[data-view="test-detail"] .btn-danger,
body.testing-dark[data-view="test-compare"] .btn-danger {
  background: #7f1d1d;
  color: #fecaca;
  border-color: #b91c1c;
}
body.testing-dark[data-view="testing"] .btn-primary,
body.testing-dark[data-view="test-detail"] .btn-primary,
body.testing-dark[data-view="test-compare"] .btn-primary {
  color: #fff;
}
/* Disabled state — keep the dimmed look but on the dark palette */
body.testing-dark[data-view="testing"] .btn:disabled,
body.testing-dark[data-view="test-detail"] .btn:disabled,
body.testing-dark[data-view="test-compare"] .btn:disabled {
  background: #1f2937;
  color: #64748b;
  border-color: #374151;
  opacity: 0.6;
}
/* Inputs / selects in dark testing views — same problem: they
   default to `background:#fff; color: var(--text)` and the
   --text override breaks them. */
body.testing-dark[data-view="testing"] input[type="text"],
body.testing-dark[data-view="testing"] input[type="search"],
body.testing-dark[data-view="testing"] input[type="number"],
body.testing-dark[data-view="testing"] input[type="email"],
body.testing-dark[data-view="testing"] input[type="date"],
body.testing-dark[data-view="testing"] input[type="datetime-local"],
body.testing-dark[data-view="testing"] textarea,
body.testing-dark[data-view="testing"] select,
body.testing-dark[data-view="test-detail"] input[type="text"],
body.testing-dark[data-view="test-detail"] input[type="search"],
body.testing-dark[data-view="test-detail"] input[type="number"],
body.testing-dark[data-view="test-detail"] input[type="email"],
body.testing-dark[data-view="test-detail"] input[type="date"],
body.testing-dark[data-view="test-detail"] input[type="datetime-local"],
body.testing-dark[data-view="test-detail"] textarea,
body.testing-dark[data-view="test-detail"] select,
body.testing-dark[data-view="test-compare"] input[type="text"],
body.testing-dark[data-view="test-compare"] input[type="search"],
body.testing-dark[data-view="test-compare"] input[type="number"],
body.testing-dark[data-view="test-compare"] input[type="email"],
body.testing-dark[data-view="test-compare"] input[type="date"],
body.testing-dark[data-view="test-compare"] input[type="datetime-local"],
body.testing-dark[data-view="test-compare"] textarea,
body.testing-dark[data-view="test-compare"] select {
  background: #1f2937 !important;
  color: #e5e7eb !important;
  border-color: #374151 !important;
}
body.testing-dark[data-view="testing"] input::placeholder,
body.testing-dark[data-view="test-detail"] input::placeholder,
body.testing-dark[data-view="test-compare"] input::placeholder,
body.testing-dark[data-view="testing"] textarea::placeholder,
body.testing-dark[data-view="test-detail"] textarea::placeholder,
body.testing-dark[data-view="test-compare"] textarea::placeholder {
  color: #94a3b8;
}
body.testing-dark[data-view="testing"] select option,
body.testing-dark[data-view="test-detail"] select option,
body.testing-dark[data-view="test-compare"] select option,
body.testing-dark[data-view="stability"] select option {
  background: #1f2937;
  color: #e5e7eb;
}

/* ---- Stability workspace dark-mode focused overrides ----
   The page-level --bg / --surface / --text overrides at the top of
   the dark block already apply (we added [data-view="stability"]
   to the master selector list). These rules catch the inline-styled
   light backgrounds + text that show up in the stability picker /
   chart card / insights / chip strip. */
body.testing-dark[data-view="stability"] #stability-workspace [style*="background:#fff"] {
  background: #1f2937 !important;
  border-color: #374151 !important;
}
body.testing-dark[data-view="stability"] #stability-workspace [style*="background:#f8fafc"] {
  background: #111827 !important;
  color: #e5e7eb !important;
}
body.testing-dark[data-view="stability"] #stability-workspace [style*="color:#0f172a"] {
  color: #f1f5f9 !important;
}
body.testing-dark[data-view="stability"] #stability-workspace [style*="color:#334155"],
body.testing-dark[data-view="stability"] #stability-workspace [style*="color:#475569"] {
  color: #cbd5e1 !important;
}
body.testing-dark[data-view="stability"] #stab-picker-list label[style*="background:#eff6ff"] {
  background: #1e3a8a !important;
}
/* Picker list row borders */
body.testing-dark[data-view="test-compare"] #test-compare-list label {
  border-bottom-color: #374151 !important;
}
body.testing-dark[data-view="test-compare"] #test-compare-list label[style*="background:#eff6ff"] {
  background: #1e3a8a !important;
}

/* Stability modal — the modal frame itself when opened from testing */
body.testing-dark[data-view="testing"] .modal,
body.testing-dark[data-view="test-detail"] .modal,
body.testing-dark[data-view="test-compare"] .modal {
  background: #1f2937;
  color: #f1f5f9;
}
body.testing-dark[data-view="testing"] .modal-header,
body.testing-dark[data-view="testing"] .modal-footer,
body.testing-dark[data-view="test-detail"] .modal-header,
body.testing-dark[data-view="test-detail"] .modal-footer,
body.testing-dark[data-view="test-compare"] .modal-header,
body.testing-dark[data-view="test-compare"] .modal-footer {
  border-color: #374151;
}
body.testing-dark[data-view="testing"] .modal [style*="background:#fff"],
body.testing-dark[data-view="testing"] .modal [style*="background:#f8fafc"] {
  background: #111827 !important;
  border-color: #374151 !important;
}
/* The Stability chart's <canvas> sits inside a white box — flip it. */
body.testing-dark[data-view="testing"] #stab-chart {
  background: transparent !important;
}
