/* =========================================================================
 * Manifold default theme — neutral, instrument-grade aesthetic.
 *
 * Brand-neutral by design. Karl's animated Erratic theme lives at
 * themes/erratic/ for users who prefer that look; this is the default
 * for fresh installs and for users without a saved preference.
 *
 * IBM Plex Sans + Plex Mono. Deep slate background with warm amber
 * accent — distinct from the cyan-glassmorphism look the Erratic theme
 * has, and explicitly avoiding colors common in generic dashboards.
 *
 * card-builder.jsx and charts.js read theme tokens via window-level
 * shims (window.ManifoldChartsTheme, etc.); see manifold.jsx for the
 * theme bootstrap that wires this CSS to those objects.
 * ========================================================================= */

:root[data-theme="default"] {
  /* --- Surfaces --- */
  --m-bg:           #0d0f12;
  --m-surface:      #15181d;
  --m-surface-2:    #1d2128;
  --m-surface-hi:   #232831;
  --m-border:       #252a32;
  --m-border-hi:    #353c47;

  /* --- Text --- */
  --m-text:         #e8e6e3;
  --m-text-muted:   #8b8985;
  --m-text-faint:   #5e5d59;

  /* --- Accent --- */
  --m-accent:       #f5a623;
  --m-accent-hi:    #ffb84a;
  --m-accent-low:   rgba(245, 166, 35, 0.12);
  --m-accent-line:  rgba(245, 166, 35, 0.32);

  /* --- Semantic state colors --- */
  --m-success:      #6e9b65;
  --m-warning:      #d2945e;
  --m-error:        #b8554d;

  /* --- Type --- */
  --m-font-sans:    "IBM Plex Sans", system-ui, sans-serif;
  --m-font-display: "IBM Plex Sans Condensed", "IBM Plex Sans", system-ui, sans-serif;
  --m-font-mono:    "IBM Plex Mono", ui-monospace, monospace;

  /* --- Layout: emitted by codegen — see @manifold-tokens block below */

  /* --- Header --- */
  --m-header-row-height: 52px;

  /* --- Motion --- */
  --m-t-fast: 120ms cubic-bezier(0.2, 0, 0, 1);
  --m-t-norm: 220ms cubic-bezier(0.2, 0, 0, 1);
  --m-t-slow: 400ms cubic-bezier(0.2, 0, 0, 1);

  /* --- JS-token aliases (--mt-*) emitted by codegen --------------------
   * Phase 15 closed CR-01: the 14 canonical --mt-* names (bg, bg-deep,
   * bg-elev, border, border-strong, fg, dim, muted, accent, accent-muted,
   * live, warn, error, code) are now emitted from design-tokens/<id>.json +
   * _base.json into the @manifold-tokens block below. The hand-authored
   * var(--m-*) bridge layer that used to live here is retired —
   * tests/plugin_spec/test_design_tokens.py::
   *   test_no_codegen_vars_declared_outside_sentinel
   * hard-fails if any of those 14 names is re-declared up here.
   * --m-* legacy names ABOVE remain (they feed older callers via var()).
   * --------------------------------------------------------------------- */

  /* Phase 5: warn-hi alias for the easyPie intermediate color stop.
     Sits between --mt-warn and --mt-error in the semantic warmth ramp.
     Used by the easyPie color ramp in card-builder-renderers.jsx. */
  --mt-warn-hi:        #ff7a3a;

  /* Phase 5: multi-series categorical palette (Tableau 10 + 2 supplemental).
     Drives multiSeriesChart, multiBigNumber, rankedBars, donut, eventBadges
     via the i % 12 cycle. WCAG AA 3:1 enforced against the chart background
     by tools/audit_series_contrast.py. */
  --mt-series-1:       #4E79A7;
  --mt-series-2:       #F28E2B;
  --mt-series-3:       #E15759;
  --mt-series-4:       #76B7B2;
  --mt-series-5:       #59A14F;
  --mt-series-6:       #EDC948;
  --mt-series-7:       #B07AA1;
  --mt-series-8:       #FF9DA7;
  --mt-series-9:       #9C755F;
  --mt-series-10:      #BAB0AC;
  --mt-series-11:      #7B5EA7;
  --mt-series-12:      #46787C;

  /* Phase 5: sequential heatmap ramp (Viridis-derived perceptual sequence).
     Drives HeatmapRenderer default color stops. Per-theme overrides land
     here when an intensity reading misreads against the theme. */
  --mt-heat-1:         #2C3E50;
  --mt-heat-2:         #3D6F8E;
  --mt-heat-3:         #7C9885;
  --mt-heat-4:         #D9A26B;
  --mt-heat-5:         #E55934;

  /* @manifold-tokens:start */
  --mt-accent: #f5a623;
  --mt-accent-muted: #88641a;
  --mt-bg: #15181d;
  --mt-bg-deep: #0d0f12;
  --mt-bg-elev: #1d2128;
  --mt-border: #252a32;
  --mt-border-strong: #353c47;
  --mt-code: #f5a623;
  --mt-dim: #8b8985;
  --mt-error: #b8554d;
  --mt-fg: #e8e6e3;
  --mt-live: #6e9b65;
  --mt-muted: #5e5d59;
  --mt-warn: #d2945e;

  --mt-text-xs-size: 10px;
  --mt-text-xs-lh: 1.5;
  --mt-text-sm-size: 12px;
  --mt-text-sm-lh: 1.5;
  --mt-text-md-size: 14px;
  --mt-text-md-lh: 1.5;
  --mt-text-lg-size: 18px;
  --mt-text-lg-lh: 1.5;
  --mt-text-xl-size: 24px;
  --mt-text-xl-lh: 1.5;
  --mt-text-2xl-size: 32px;
  --mt-text-2xl-lh: 1.5;
  --mt-text-3xl-size: 48px;
  --mt-text-3xl-lh: 1.5;

  --m-font-weight-regular: 400;
  --mt-weight-regular: 400;
  --m-font-weight-medium: 500;
  --mt-weight-medium: 500;
  --m-font-weight-semibold: 600;
  --mt-weight-semibold: 600;
  --m-font-weight-bold: 700;
  --mt-weight-bold: 700;

  --m-pad-xs: 4px;
  --mt-space-xs: 4px;
  --m-pad-sm: 8px;
  --mt-space-sm: 8px;
  --m-pad-md: 14px;
  --mt-space-md: 14px;
  --m-pad-lg: 20px;
  --mt-space-lg: 20px;
  --m-pad-xl: 32px;
  --mt-space-xl: 32px;
  --m-pad-2xl: 48px;
  --mt-space-2xl: 48px;

  --m-radius-sm: 2px;
  --m-radius-md: 4px;
  --m-radius-lg: 6px;
  --m-radius-full: 9999px;
/* @manifold-tokens:end */
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--m-bg);
  color: var(--m-text);
  font-family: var(--m-font-sans);
  font-size: 14px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

body {
  background:
    radial-gradient(ellipse 1200px 600px at 50% 0%, rgba(245, 166, 35, 0.025), transparent 60%),
    var(--m-bg);
  background-attachment: fixed;
}

#manifold-root {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* =========================================================================
 * Skeleton — what's visible while waiting for the catalog
 * ========================================================================= */

.manifold-bootstrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  font-family: var(--m-font-mono);
  color: var(--m-text-muted);
  font-size: 12px;
  letter-spacing: 0.06em;
}

.manifold-bootstrap-mark {
  font-family: var(--m-font-display);
  font-size: 32px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--m-text);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 18px;
  padding: 28px 40px;
}

/* Manifold silhouette — a horizontal runner with two intake stubs up and
 * one exhaust stub down. Sits behind the wordmark as a soft watermark. */
.manifold-bootstrap-glyph {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  fill: var(--m-accent);
  opacity: 0.18;
  z-index: 0;
}

.manifold-bootstrap-wordmark {
  position: relative;
  z-index: 1;
  opacity: 0.5;
}

.manifold-bootstrap-status {
  font-family: var(--m-font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--m-text-faint);
}

.manifold-bootstrap-status.error {
  color: var(--m-error);
}

/* =========================================================================
 * Top-level layout — header strip, tab bar, tab content
 * ========================================================================= */

.manifold-header {
  background: var(--m-surface);
  border-bottom: 1px solid var(--m-border);
  min-height: var(--m-header-row-height);
  position: relative;
  /* Stacking context above content area. Cards in the content area set
   * their own `position: relative` which creates inline stacking
   * contexts; without a header z-index, those cards rise above the
   * gear-menu dropdown anchored inside the header. z-index: 50 keeps
   * the header (and its children, including the gear menu) consistently
   * above content cards but below the modal overlay (z-index: 1000) and
   * the floating edit FAB (z-index: 900). */
  z-index: 50;
}

.manifold-tabbar {
  background: var(--m-surface);
  border-bottom: 1px solid var(--m-border);
  display: flex;
  align-items: stretch;
  padding: 0 var(--m-pad-lg);
  height: 38px;
  /* Mobile-tolerance: when many tabs exceed viewport width, scroll
     horizontally instead of wrapping into a wider-than-screen row.
     -webkit-overflow-scrolling preserves the iOS momentum-scroll feel. */
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  /* Hide horizontal scrollbar in webkit browsers — the scroll still
     works via touch / shift+wheel. Safari shows a thin bar by
     default which clutters mobile chrome. */
  scrollbar-width: thin;
}
.manifold-tabbar::-webkit-scrollbar { height: 4px; }
.manifold-tab {
  /* Prevent tabs from shrinking below their content width when the
     row overflows — let the bar scroll instead. */
  flex-shrink: 0;
}

.manifold-tab {
  display: flex;
  align-items: center;
  padding: 0 var(--m-pad-md);
  font-size: 12px;
  font-weight: 500;
  color: var(--m-text-muted);
  cursor: pointer;
  position: relative;
  letter-spacing: 0.02em;
  transition: color var(--m-t-fast);
}

.manifold-tab:hover { color: var(--m-text); }

.manifold-tab.active { color: var(--m-accent); }

.manifold-tab.active::after {
  content: "";
  position: absolute;
  bottom: -1px;
  left: var(--m-pad-md);
  right: var(--m-pad-md);
  height: 2px;
  background: var(--m-accent);
}

.manifold-content {
  flex: 1;
  padding: var(--m-pad-xl);
  display: flex;
  flex-direction: column;
  gap: var(--m-pad-lg);
}

.manifold-empty-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  text-align: center;
  padding: var(--m-pad-xl);
  color: var(--m-text-muted);
  font-family: var(--m-font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
}

.manifold-empty-tab h2 {
  font-family: var(--m-font-display);
  font-size: 18px;
  font-weight: 500;
  color: var(--m-text);
  margin: 0 0 var(--m-pad-md);
  letter-spacing: 0.04em;
}

.manifold-empty-tab .button {
  margin-top: var(--m-pad-lg);
  background: var(--m-accent);
  color: var(--m-bg);
  border: none;
  padding: var(--m-pad-sm) var(--m-pad-lg);
  font-family: var(--m-font-sans);
  font-weight: 500;
  font-size: 13px;
  cursor: pointer;
  border-radius: var(--m-radius-sm);
  letter-spacing: 0.02em;
  transition: background var(--m-t-fast);
}

.manifold-empty-tab .button:hover {
  background: var(--m-accent-hi);
}

/* =========================================================================
 * Degraded-mode banner — surfaces required-service failures
 * ========================================================================= */

.manifold-banner {
  background: var(--m-error);
  color: var(--m-text);
  padding: var(--m-pad-md) var(--m-pad-lg);
  font-size: 13px;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: var(--m-pad-md);
}

.manifold-banner.warning {
  background: var(--m-warning);
}

.manifold-banner-actions {
  margin-left: auto;
  display: flex;
  gap: var(--m-pad-sm);
}

.manifold-banner button {
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.2);
  color: var(--m-text);
  padding: 4px var(--m-pad-md);
  border-radius: var(--m-radius-sm);
  cursor: pointer;
  font-family: var(--m-font-sans);
  font-size: 12px;
}

.manifold-banner button:hover {
  background: rgba(255,255,255,0.22);
}

/* =========================================================================
 * Tab bar — add button + per-tab remove control
 * ========================================================================= */

.manifold-tab {
  display: flex;
  align-items: center;
  gap: 6px;
}

.manifold-tab-remove {
  display: none;
  background: transparent;
  border: none;
  color: var(--m-text-faint);
  font-size: 14px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  border-radius: var(--m-radius-sm);
  transition: color var(--m-t-fast), background var(--m-t-fast);
}

.manifold-tab:hover .manifold-tab-remove,
.manifold-tab.active .manifold-tab-remove {
  display: inline;
}

.manifold-tab-remove:hover {
  color: var(--m-error);
  background: var(--m-surface-2);
}

/* Rename pencil — same visibility rules as ×, but hovers to accent
 * instead of error. Only renders in tabEditMode (gated in JSX). */
.manifold-tab-rename {
  display: none;
  background: transparent;
  border: none;
  color: var(--m-text-faint);
  font-size: 11px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  border-radius: var(--m-radius-sm);
  transition: color var(--m-t-fast), background var(--m-t-fast);
}
.manifold-tab:hover .manifold-tab-rename,
.manifold-tab.active .manifold-tab-rename {
  display: inline;
}
.manifold-tab-rename:hover {
  color: var(--m-accent);
  background: var(--m-surface-2);
}

.manifold-tab-add {
  background: transparent;
  border: none;
  color: var(--m-text-faint);
  font-family: var(--m-font-mono);
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  margin-left: var(--m-pad-sm);
  letter-spacing: 0;
}

.manifold-tab-add:hover {
  color: var(--m-text);
}

/* Floating bottom-right edit-mode toggle. Always-visible affordance
 * for owner/admin (unless hidden via the "Hide edit button" gear-menu
 * preference). Color-shifts when active so the user can tell at a
 * glance which mode the dashboard is in. */
.manifold-edit-fab {
  position: fixed;
  right: 18px; bottom: 18px;
  z-index: 900;
  padding: 9px 16px;
  font-family: var(--m-font-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--m-bg-elev, #1a1a1a);
  color: var(--m-text-dim, currentColor);
  border: 1px solid var(--m-border, currentColor);
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
  transition: background 120ms, color 120ms, border-color 120ms;
}
.manifold-edit-fab:hover {
  color: var(--m-text, currentColor);
  border-color: var(--m-text, currentColor);
}
.manifold-edit-fab[data-active="true"] {
  background: var(--m-accent, #8b8);
  color: var(--m-bg-deep, #0d0f12);
  border-color: var(--m-accent, #8b8);
}

/* Sign-in FAB — same bottom-right slot as the Edit FAB, but for
   anonymous users. Slightly more accent-colored so the call-to-action
   is obvious to a first-time visitor. Karl 2026-05-08. */
.manifold-signin-fab {
  background: var(--m-accent, #8b8);
  color: var(--m-bg-deep, #0d0f12);
  border-color: var(--m-accent, #8b8);
  text-decoration: none;
  font-weight: 600;
}
.manifold-signin-fab:hover,
.manifold-signin-fab:focus-visible {
  background: var(--m-accent, #8b8);
  filter: brightness(1.1);
  outline: none;
}

/* Undo/redo toast — bottom-center, transient. Karl 2026-05-08. */
.manifold-history-toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 9000;
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  padding: 8px 16px;
  font-family: var(--m-font-mono, monospace);
  font-size: 12px;
  background: var(--m-bg-elev, #1f2024);
  color: var(--m-fg, #fff);
  border: 1px solid var(--m-border-strong, #555);
  border-radius: 4px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  pointer-events: none;
  animation: manifold-history-toast-in 120ms ease-out;
}
.manifold-history-toast-kind {
  font-weight: 600;
  color: var(--m-accent, #8b8);
}
.manifold-history-toast-label {
  opacity: 0.85;
}
@keyframes manifold-history-toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(8px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* Tab edit mode (?edit / ?tabedit deep-link). Drag-to-reorder is gated
 * on this mode; the edit-mode chrome here makes it visually obvious
 * the bar's accepting drags. */
.manifold-tabbar--editing {
  outline: 1px dashed var(--m-accent, currentColor);
  outline-offset: 2px;
  border-radius: 4px;
  padding: 2px;
}
.manifold-tabbar-edit-hint {
  font-family: var(--m-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--m-accent, currentColor);
  align-self: center;
  margin-right: 6px;
  opacity: 0.85;
  white-space: nowrap;
}
.manifold-tab-edit-enter,
.manifold-tab-edit-done {
  font-family: var(--m-font-mono);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  background: transparent;
  color: var(--m-text-dim, currentColor);
  border: 1px solid var(--m-border, currentColor);
  border-radius: 4px;
  padding: 2px 8px;
  margin-left: 4px;
  letter-spacing: 0.04em;
}
.manifold-tab-edit-done {
  color: var(--m-accent, currentColor);
  border-color: var(--m-accent, currentColor);
  background: color-mix(in srgb, var(--m-accent) 12%, transparent);
}
.manifold-tab-edit-enter:hover {
  color: var(--m-text, currentColor);
  border-color: var(--m-text, currentColor);
}

/* =========================================================================
 * Modal — add tab dialog (and the shape future modals will reuse)
 * ========================================================================= */

.manifold-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(13, 15, 18, 0.7);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--m-pad-xl);
}

.manifold-modal {
  background: var(--m-surface-2);
  border: 1px solid var(--m-border-hi);
  border-radius: var(--m-radius-md);
  width: 100%;
  max-width: 720px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.7);
}

.manifold-modal-header {
  padding: var(--m-pad-lg);
  border-bottom: 1px solid var(--m-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.manifold-modal-header h2 {
  font-family: var(--m-font-display);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--m-pad-sm);
  color: var(--m-text);
}

.manifold-modal-header h2::before {
  content: "";
  width: 4px;
  height: 16px;
  background: var(--m-accent);
  display: inline-block;
}

.manifold-modal-close {
  background: transparent;
  border: 1px solid var(--m-border);
  color: var(--m-text-muted);
  width: 28px;
  height: 28px;
  border-radius: var(--m-radius-sm);
  font-family: var(--m-font-mono);
  font-size: 14px;
  cursor: pointer;
  transition: border-color var(--m-t-fast), color var(--m-t-fast);
}

.manifold-modal-close:hover {
  border-color: var(--m-border-hi);
  color: var(--m-text);
}

.manifold-modal-body {
  padding: var(--m-pad-lg);
  overflow-y: auto;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--m-pad-sm);
}

.manifold-section-label {
  font-family: var(--m-font-mono);
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--m-text-faint);
  margin-bottom: 4px;
}

/* Suggestion grid — Power, Storage, Network, etc. */
.manifold-suggestion-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--m-pad-sm);
}

.manifold-suggestion {
  background: var(--m-surface);
  border: 1px solid var(--m-border);
  border-radius: var(--m-radius-md);
  padding: var(--m-pad-md);
  cursor: pointer;
  text-align: left;
  font-family: var(--m-font-sans);
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: border-color var(--m-t-fast), background var(--m-t-fast);
}

.manifold-suggestion:hover {
  border-color: var(--m-accent-line);
  background: var(--m-accent-low);
}

.manifold-suggestion.empty {
  opacity: 0.6;
}

.manifold-suggestion-name {
  font-family: var(--m-font-display);
  font-size: 14px;
  font-weight: 600;
  color: var(--m-text);
  letter-spacing: 0.02em;
}

.manifold-suggestion-caps {
  font-family: var(--m-font-mono);
  font-size: 10px;
  color: var(--m-text-muted);
  letter-spacing: 0.04em;
}

.manifold-suggestion-empty-flag {
  font-family: var(--m-font-mono);
  font-size: 9px;
  color: var(--m-text-faint);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-top: 4px;
}

/* Blank-tab form */
.manifold-blank-form {
  display: flex;
  gap: var(--m-pad-sm);
  align-items: center;
}

.manifold-text-input {
  flex: 1;
  background: var(--m-bg);
  border: 1px solid var(--m-border);
  color: var(--m-text);
  font-family: var(--m-font-sans);
  font-size: 13px;
  padding: var(--m-pad-sm) var(--m-pad-md);
  border-radius: var(--m-radius-sm);
}

.manifold-text-input:focus {
  outline: 1px solid var(--m-accent);
  outline-offset: -1px;
  border-color: var(--m-accent);
}

.manifold-button {
  background: var(--m-surface-2);
  border: 1px solid var(--m-border);
  color: var(--m-text);
  font-family: var(--m-font-sans);
  font-size: 12px;
  font-weight: 500;
  padding: var(--m-pad-sm) var(--m-pad-md);
  border-radius: var(--m-radius-sm);
  cursor: pointer;
  transition: border-color var(--m-t-fast), background var(--m-t-fast);
  letter-spacing: 0.02em;
}

.manifold-button:hover:not(:disabled) {
  border-color: var(--m-border-hi);
  background: var(--m-surface-hi);
}

.manifold-button.primary {
  background: var(--m-accent);
  color: var(--m-bg);
  border-color: var(--m-accent);
}

.manifold-button.primary:hover:not(:disabled) {
  background: var(--m-accent-hi);
  border-color: var(--m-accent-hi);
}

.manifold-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.manifold-loading,
.manifold-error-line {
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--m-text-muted);
  text-align: center;
  padding: var(--m-pad-md);
}

.manifold-error-line {
  color: var(--m-error);
}

/* Compact "+ Add card" row at the bottom of populated tabs */
.manifold-add-card-row {
  display: flex;
  justify-content: center;
  padding: var(--m-pad-md) 0 0;
  border-top: 1px dashed var(--m-border);
  margin-top: var(--m-pad-md);
}

/* =========================================================================
 * HEADER STRIP — configurable strip-tab above the tab bar (§ 22)
 * ========================================================================= */

.manifold-h-strip {
  display: grid;
  gap: 1px;
  background: var(--m-border);
  min-height: var(--m-header-row-height);
}

.manifold-h-cell {
  background: var(--m-surface);
  display: flex;
  align-items: center;
  justify-content: stretch;
  position: relative;
  min-height: var(--m-header-row-height);
}

.manifold-h-cell.empty {
  background:
    repeating-linear-gradient(45deg,
      transparent 0, transparent 8px,
      rgba(255,255,255,0.018) 8px, rgba(255,255,255,0.018) 16px),
    var(--m-surface);
}

/* Tab-bar widget inside the header strip. The standalone TabBar
 * component carries its own background, border-bottom, and padding
 * — appropriate when it lived as a separate band, but redundant /
 * disconnecting when nested inside a header cell. Strip those down
 * here so the tabbar reads as a continuous part of the header band
 * rather than a separate strip below it. */
.manifold-h-tabbar-host {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: stretch;
}
.manifold-h-tabbar-host .manifold-tabbar {
  background: transparent;
  border-bottom: none;
  height: auto;
  flex: 1;
  align-items: center;
}
/* full-row cell (the row carrying the tabbar) — no internal padding,
 * let the tabbar own the row width edge-to-edge. */
.manifold-h-cell.full-row {
  padding: 0;
}

.manifold-h-widget-wrap {
  width: 100%; height: 100%;
  display: flex; align-items: center;
  position: relative;
}

.manifold-h-widget-remove {
  display: none;
  position: absolute;
  top: 4px; right: 4px;
  width: 16px; height: 16px;
  padding: 0; border: none;
  background: var(--m-error); color: var(--m-text);
  font-family: var(--m-font-mono); font-size: 11px; line-height: 1;
  border-radius: var(--m-radius-sm);
  cursor: pointer;
}

.manifold-h-cell.edit-mode:hover .manifold-h-widget-remove {
  display: flex; align-items: center; justify-content: center;
}

/* --- Brand widget (wordmark mode) ---
 * Same Layer 4 rationale as .manifold-h-custom — natural-width inline
 * element. The renderer's outer wrap positions it via widget.style.align.
 */
.manifold-h-brand {
  font-family: var(--m-font-display);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--m-text);
  display: inline-flex; align-items: baseline; gap: 10px;
}

.manifold-h-accent-bar {
  display: inline-block;
  width: 4px; height: 16px;
  background: var(--m-accent);
}

.manifold-h-brand-empty,
.manifold-h-leaf-empty {
  font-family: var(--m-font-mono);
  font-size: 10px;
  color: var(--m-text-faint);
  text-transform: lowercase;
  letter-spacing: 0.1em;
  padding: 0 var(--m-pad-md);
}

/* --- Custom HTML widget ---
 * Layer 4: card-builder's HeaderRendererBrand owns positioning via
 * widget.style.align (the 9-position picker). This class intentionally
 * imposes neither size nor flex centering — the user's pasted HTML
 * controls its own layout, and the renderer's outer wrap pins it to
 * the chosen corner / edge. Padding moves to the renderer wrap too.
 */
.manifold-h-custom {
  display: inline-block;
  color: var(--m-text);
}

.manifold-h-custom > * { max-height: 100%; }

/* --- Gear widget --- */
.manifold-h-gear {
  width: 32px; height: 32px;
  background: transparent;
  border: 1px solid var(--m-border);
  color: var(--m-text-muted);
  cursor: pointer;
  border-radius: var(--m-radius-md);
  display: flex; align-items: center; justify-content: center;
  margin: 0 var(--m-pad-md) 0 auto;
  transition: border-color var(--m-t-fast), background var(--m-t-fast), color var(--m-t-fast);
  padding: 0;
}

.manifold-h-gear:hover,
.manifold-h-gear.open {
  border-color: var(--m-accent-line);
  background: var(--m-accent-low);
  color: var(--m-accent);
}

.manifold-h-gear svg { width: 16px; height: 16px; }
.manifold-h-gear-svg { display: inline-flex; }
.manifold-h-gear-svg svg { width: 16px; height: 16px; }

/* --- Gear-icon picker (in the header editor) --- */
.manifold-h-gear-icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: 6px;
  max-height: 240px;
  overflow-y: auto;
  padding: 4px;
  border: 1px solid var(--m-border);
  border-radius: 4px;
  background: var(--m-bg);
}
.manifold-h-gear-icon-tile {
  display: flex; flex-direction: column; align-items: center;
  gap: 4px; padding: 6px 4px;
  background: transparent; border: 1px solid transparent; border-radius: 3px;
  color: inherit; cursor: pointer; font: inherit;
  transition: background 0.1s, border-color 0.1s;
}
.manifold-h-gear-icon-tile:hover { background: var(--m-bg-hover); }
.manifold-h-gear-icon-tile.selected {
  border-color: var(--m-accent);
  background: var(--m-bg-hover);
}
.manifold-h-gear-icon-tile img,
.manifold-h-gear-icon-tile svg {
  width: 20px; height: 20px; object-fit: contain;
}
.manifold-h-gear-icon-tile .tile-name {
  font-size: 9px; opacity: 0.75; max-width: 64px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --- Auth state widget --- */
.manifold-h-auth {
  display: flex; align-items: center; gap: var(--m-pad-sm);
  font-family: var(--m-font-mono); font-size: 12px;
  padding: 0 var(--m-pad-md);
}

.manifold-h-auth-pill {
  padding: 4px 10px 4px 8px;
  background: var(--m-surface-2);
  border: 1px solid var(--m-border);
  border-radius: 11px;
  display: flex; align-items: center; gap: 6px;
  color: var(--m-text);
}

.manifold-h-auth-pill::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--m-success); display: inline-block;
}

.manifold-h-auth-role {
  color: var(--m-text-muted); font-size: 10px;
  text-transform: uppercase; letter-spacing: 0.08em;
}

/* --- Spacer widget --- */
.manifold-h-spacer { width: 100%; height: 100%; }

.manifold-h-spacer-mark {
  font-family: var(--m-font-mono); font-size: 9px;
  color: var(--m-text-faint);
  letter-spacing: 0.1em; margin: auto;
}

/* --- Leaf display widget --- */
.manifold-h-leaf {
  display: flex; flex-direction: column; justify-content: center;
  gap: 2px; font-family: var(--m-font-mono);
  padding: 0 var(--m-pad-md);
}

.manifold-h-leaf-label {
  font-size: 9px; color: var(--m-text-faint);
  letter-spacing: 0.1em; text-transform: uppercase;
}

.manifold-h-leaf-value {
  font-size: 16px; font-weight: 500; color: var(--m-text);
  display: flex; align-items: baseline; gap: 3px;
}

.manifold-h-leaf-unit {
  font-size: 10px; color: var(--m-text-muted); font-weight: 400;
}

/* --- Status widget --- */
.manifold-h-status {
  display: flex; align-items: center; gap: var(--m-pad-sm);
  font-family: var(--m-font-mono); font-size: 11px;
  color: var(--m-text-muted); text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 0 var(--m-pad-md);
}

.manifold-h-status-dot {
  width: 8px; height: 8px; border-radius: 50%; display: inline-block;
}
.manifold-h-status-dot.ok    { background: var(--m-success); box-shadow: 0 0 8px var(--m-success); }
.manifold-h-status-dot.warn  { background: var(--m-warning); box-shadow: 0 0 8px var(--m-warning); }
.manifold-h-status-dot.error { background: var(--m-error); box-shadow: 0 0 8px var(--m-error); }

/* =========================================================================
 * GEAR MENU — small dropdown anchored to the gear widget
 * ========================================================================= */

.manifold-gear-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: var(--m-pad-md);
  width: 280px;
  background: var(--m-surface-2);
  border: 1px solid var(--m-border-hi);
  border-radius: var(--m-radius-md);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
  padding: var(--m-pad-sm) 0;
  /* Above content cards (which can have their own positive z-index from
   * inline styles like position:sticky on header sections, or PiP
   * widgets that stack inside the card grid). Below modal overlays
   * (1000) so a Save/Cancel modal still wins. */
  z-index: 950;
}

.manifold-gear-section {
  padding: var(--m-pad-sm) 0;
  border-bottom: 1px solid var(--m-border);
}

.manifold-gear-section:last-child { border-bottom: none; }

.manifold-gear-header-text {
  font-family: var(--m-font-mono); font-size: 9px;
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--m-text-faint);
  padding: 4px var(--m-pad-md);
}

.manifold-gear-row {
  width: 100%;
  padding: var(--m-pad-sm) var(--m-pad-md);
  display: flex; align-items: center; justify-content: space-between;
  background: transparent; border: none;
  font-family: var(--m-font-sans); font-size: 12px; color: var(--m-text);
  cursor: pointer;
  transition: background var(--m-t-fast);
  text-align: left;
}

.manifold-gear-row:hover { background: var(--m-surface-hi); }

.manifold-gear-arrow { color: var(--m-text-faint); font-family: var(--m-font-mono); }

.manifold-gear-info {
  padding: 4px var(--m-pad-md);
  font-family: var(--m-font-mono); font-size: 10px;
  color: var(--m-text-muted);
  line-height: 1.6;
}

/* =========================================================================
 * EDIT HEADER MODAL
 * ========================================================================= */

.manifold-h-editor-preview {
  border: 1px dashed var(--m-border-hi);
  border-radius: var(--m-radius-sm);
  background: var(--m-bg);
  margin-top: 4px;
  position: relative;
  overflow: hidden;
}

.manifold-h-editor-grid-controls {
  display: flex; align-items: center; gap: var(--m-pad-sm);
  padding: var(--m-pad-sm) 0;
}

.grid-input {
  background: var(--m-surface);
  border: 1px solid var(--m-border);
  color: var(--m-text);
  font-family: var(--m-font-mono); font-size: 11px;
  width: 38px; text-align: center;
  padding: 3px 4px;
  border-radius: var(--m-radius-sm);
}

.grid-input-x {
  font-family: var(--m-font-mono);
  color: var(--m-text-faint); font-size: 10px;
}

.field-label {
  font-family: var(--m-font-mono); font-size: 10px;
  text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--m-text-muted);
  margin-bottom: 4px;
}

.manifold-h-editor-cells {
  display: flex; flex-direction: column; gap: var(--m-pad-sm);
}

.manifold-h-edit-cell {
  background: var(--m-surface);
  border: 1px solid var(--m-border);
  border-radius: var(--m-radius-sm);
  padding: var(--m-pad-md);
  display: flex; flex-direction: column; gap: var(--m-pad-sm);
}

.manifold-h-edit-cell.empty {
  border-style: dashed;
  background: transparent;
}

.manifold-h-edit-cell-label {
  display: flex; align-items: center; gap: var(--m-pad-md);
  font-family: var(--m-font-mono); font-size: 11px;
}

.cell-num {
  display: inline-block;
  min-width: 24px; height: 20px; line-height: 20px;
  text-align: center;
  background: var(--m-surface-2);
  border: 1px solid var(--m-border-hi);
  border-radius: var(--m-radius-sm);
  color: var(--m-text); font-weight: 500;
  padding: 0 6px;
}

.cell-type {
  color: var(--m-text-muted);
  text-transform: uppercase; letter-spacing: 0.08em;
}

.manifold-h-cell-add-picker {
  display: flex; flex-wrap: wrap; gap: 4px;
}

.manifold-h-cell-form {
  background: var(--m-surface-2);
  border: 1px solid var(--m-border);
  border-radius: var(--m-radius-sm);
  padding: var(--m-pad-md);
  display: flex; flex-direction: column; gap: var(--m-pad-md);
}

.manifold-h-cell-fields {
  display: flex; flex-wrap: wrap; gap: var(--m-pad-md);
}

.manifold-h-cell-field {
  display: flex; flex-direction: column; gap: 2px; flex: 1 1 180px;
}

.manifold-h-brand-form {
  display: flex; flex-direction: column; gap: var(--m-pad-md);
}

.manifold-h-mode-chooser {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--m-pad-sm);
}

.manifold-h-mode-tab {
  background: var(--m-surface);
  border: 1px solid var(--m-border);
  border-radius: var(--m-radius-md);
  padding: var(--m-pad-md);
  cursor: pointer;
  font-family: var(--m-font-sans); text-align: left;
  display: flex; flex-direction: column; gap: 2px;
  transition: border-color var(--m-t-fast), background var(--m-t-fast);
}

.manifold-h-mode-tab:hover {
  border-color: var(--m-border-hi);
  background: var(--m-surface-hi);
}

.manifold-h-mode-tab.active {
  border-color: var(--m-accent);
  background: var(--m-accent-low);
}

.manifold-h-mode-name {
  font-family: var(--m-font-display); font-size: 14px; font-weight: 600;
  color: var(--m-text); letter-spacing: 0.02em;
}

.manifold-h-mode-tab.active .manifold-h-mode-name { color: var(--m-accent-hi); }

.manifold-h-mode-desc {
  font-size: 11px; color: var(--m-text-muted); line-height: 1.4;
}

.manifold-h-checkbox-row {
  display: flex; align-items: center; gap: var(--m-pad-sm);
  cursor: pointer; user-select: none;
  font-size: 13px; color: var(--m-text);
}

.manifold-h-checkbox-row input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 16px; height: 16px;
  border: 1px solid var(--m-border-hi);
  background: var(--m-surface);
  border-radius: var(--m-radius-sm);
  cursor: pointer; position: relative; margin: 0;
}

.manifold-h-checkbox-row input[type="checkbox"]:checked {
  background: var(--m-accent); border-color: var(--m-accent);
}

.manifold-h-checkbox-row input[type="checkbox"]:checked::after {
  content: "✓";
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  color: var(--m-bg); font-size: 11px; font-weight: 700;
  font-family: var(--m-font-mono); line-height: 1;
}

.manifold-h-code-editor {
  font-family: var(--m-font-mono); font-size: 12px;
  background: var(--m-bg);
  border: 1px solid var(--m-border);
  color: var(--m-text);
  padding: var(--m-pad-md);
  border-radius: var(--m-radius-sm);
  width: 100%; min-height: 200px; resize: vertical;
  line-height: 1.5; tab-size: 2;
}

.manifold-h-sanitizer {
  font-family: var(--m-font-mono); font-size: 11px;
  padding: var(--m-pad-sm) var(--m-pad-md);
  border-radius: var(--m-radius-sm);
}

.manifold-h-sanitizer.clean {
  background: rgba(110, 155, 101, 0.08);
  border: 1px solid rgba(110, 155, 101, 0.32);
  color: var(--m-success);
}

.manifold-h-sanitizer.modified {
  background: rgba(210, 148, 94, 0.08);
  border: 1px solid rgba(210, 148, 94, 0.32);
  color: var(--m-warning);
}

.manifold-h-leaf-picker {
  display: flex; flex-direction: column; gap: 4px;
}

.manifold-h-leaf-hint {
  font-family: var(--m-font-mono); font-size: 10px;
  color: var(--m-text-faint);
}

.manifold-modal-footer {
  padding: var(--m-pad-md) var(--m-pad-lg);
  border-top: 1px solid var(--m-border);
  display: flex; justify-content: flex-end; gap: var(--m-pad-sm);
}

.manifold-button.small { font-size: 11px; padding: 4px var(--m-pad-sm); }
.manifold-button.danger { background: var(--m-error); border-color: var(--m-error); color: #fff; }
.manifold-button.danger:hover { border-color: var(--m-error); color: var(--m-error); }
/* Plan 16-04 W3.3: .compact gives slightly more horizontal breathing room
 * than .small for short labels like "+ Add card". Routes through --mt-space-*
 * so theme cascade still applies (xs=4, md=14 in default; per-theme values
 * tracked via Phase 15 token surface). */
.manifold-button.compact { font-size: 11px; padding: var(--mt-space-xs) var(--mt-space-md); }

/* Plan 16-04 W3.3: section-editor's gradient preview swatch consumes a
 * per-render CSS custom property `--m-gradient-preview` set inline on the
 * element. Lets the dynamic gradient value (computed per render from
 * gradient panel state) pass through without tripping the inline-style
 * aesthetics audit on `background`. See section-editor.jsx Disclosure
 * "Background gradient" branch for the call site + rationale. */
.manifold-gradient-preview-swatch { background: var(--m-gradient-preview); }

/* Phase 19 Plan 05a: renderer visual-primitives (Placeholder, NoDataVisual,
 * Label inside card-builder-renderers.jsx) consume a small set of CSS
 * custom properties for the values the audit can't see as theme tokens —
 * the `color` argument is a per-call runtime prop, the dash size is a
 * relative em that has no fixed token equivalent, and the hint sub-text
 * lives below the smallest mt-text-* bucket (10px → 9px).
 *
 * The JSX sets `--m-renderer-color` once on the wrapper element; child
 * elements that need to consume it (the foreground text, the small dot
 * background, the hollow ring border) all read the same var so callers
 * don't have to thread the same value through three child styles.
 *
 * Falls back to var(--mt-muted) when the JSX omits the var (e.g. an
 * older / unmigrated caller, or a deliberate "use the theme's muted
 * tone" intent). */
.manifold-renderer-fg         { color: var(--m-renderer-color, var(--mt-muted)); }
.manifold-renderer-bg-color   { background-color: var(--m-renderer-color, var(--mt-muted)); }
.manifold-renderer-ring       { border: 1.5px solid var(--m-renderer-color, var(--mt-muted)); }
.manifold-renderer-label-size { font-size: var(--m-renderer-label-size, var(--mt-text-xs-size)); }
.manifold-renderer-hint-text  { font-size: 9px; }
.manifold-renderer-scalar-dash { font-size: 1.4em; }
/* Phase 19 Plan 05b — primary value font-size for the scalar/number renderer
 * family (BigNumber, Sparkline, MultiBigNumber, Count, Text). Same shape as
 * .manifold-renderer-label-size: a single CSS custom property feeds a class,
 * letting the JSX move runtime fontSize off the audit-watched inline style
 * surface. No fallback — when the JSX omits the var the consumer is misused;
 * callers always compute fontSize via resolveStyle so the var is always set. */
.manifold-renderer-value-size { font-size: var(--m-renderer-value-size); }
/* Phase 19 Plan 05b — MultiBigNumberRenderer's "no data yet" per-slot ghost
 * badge. A dashed border + small padding + radius that visually marks a
 * series slot as awaiting its first message. The dashed border is the
 * sibling of NoDataVisual chart mode's repeating-linear-gradient stripe,
 * scaled for an inline-badge surface. Bundled into one class because the
 * three properties (dashed border, square-ish padding, small radius) read
 * as one visual primitive — splitting across three utility classes would
 * dilute the semantic. */
.manifold-renderer-ghost-slot {
  border: 1px dashed var(--mt-dim);
  border-radius: var(--m-radius-sm, 4px);
  padding: 2px 6px;
}

/* Phase 19 Plan 05c — LineChart + MultiSeriesChart need a SECOND runtime
 * fontSize escape hatch beside .manifold-renderer-value-size. The unit-
 * suffix span is sized proportionally to the primary value (e.g.
 * Math.max(9, fontSize*0.55)), so it carries a distinct runtime size.
 * Same shape as .manifold-renderer-value-size: a single CSS custom
 * property feeds a class so the audit-watched fontSize key moves off
 * the JSX inline-style surface. No fallback — callers always set the
 * var via resolveStyle / fontSize math. */
.manifold-renderer-unit-size { font-size: var(--m-renderer-unit-size); }

/* Phase 19 Plan 05c — per-series colors for MultiSeriesChartRenderer.
 * Each series carries a color computed from widget.series[i].color (or
 * tokens.accent if unspecified). The cascade must preserve per-series
 * differentiation across theme switches; collapsing every series to one
 * .mt-text-accent is a regression (feedback_sparkline_leaf_source).
 *
 * The JSX sets `--m-series-color` per-element with the resolved color;
 * the classes below consume that var with different alpha values and
 * different CSS properties so each visual affordance (chip background,
 * chip border, legend swatch, value text) re-skins automatically when
 * the series color changes — which can happen mid-render if the user
 * edits the widget.
 *
 * Alpha targets come from the literal-hex patterns the renderer used
 * pre-migration:
 *   ${c}15  → 0x15/0xFF ≈ 8.2%  (chip background tint when isolated)
 *   ${c}66  → 0x66/0xFF ≈ 40%   (chip border tint when isolated)
 * color-mix expresses the same intent in a theme-friendly way and works
 * with any CSS color (named, hex, var, currentColor) — the hex-suffix
 * trick the JSX used only worked because every series color happened to
 * be a 6-digit hex literal. */
.manifold-series-color-text     { color: var(--m-series-color); }
.manifold-series-swatch-bg      { background: var(--m-series-color); }
.manifold-series-swatch-dashed  { border-top: 2px dashed var(--m-series-color); }
.manifold-series-chip {
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--m-radius-sm, 4px);
  /* `color: inherit` here so the chip's text picks up the surrounding
   * card's foreground rather than UA default button text. The override
   * lives on the class so the JSX inline-style stays off the FORBIDDEN
   * audit surface. */
  color: inherit;
  /* Phase 19-05g — close the 19-05c gap. The button element does NOT
   * inherit font-family / font-size by default; the pre-migration JSX
   * carried `fontFamily:'inherit', fontSize:'inherit'` inline to opt in.
   * Baking the inherits into the class moves both FORBIDDEN keys
   * (fontFamily, fontSize) off the inline surface. Padding also varies
   * with compact-mode — handled by data-compact attr selector below. */
  font-family: inherit;
  font-size: inherit;
  padding: 1px 6px;
}
.manifold-series-chip[data-compact="true"] {
  padding: 1px 4px;
}

/* Phase 19-05g — MultiSeriesChartRenderer legend `meta` span. Sits at
 * the end of the chip row and pushes itself to the right edge via
 * margin-left:auto (a flex-distribution shape, not a spacing value).
 * Dedicated class instead of a utility because `margin-left: auto` is
 * not part of the locked utility-class catalog and the chip's meta
 * is the only consumer. */
.manifold-series-meta-spacer {
  margin-left: auto;
}
.manifold-series-chip[data-isolated="true"] {
  background: color-mix(in srgb, var(--m-series-color) 8%, transparent);
  border-color: color-mix(in srgb, var(--m-series-color) 40%, transparent);
}

/* Phase 19 Plan 05c — MultiSeriesChartRenderer hover tooltip. The dark
 * translucent backdrop + 1px hairline border + small radius + 5px/8px
 * padding read as one visual primitive (same posture as
 * .manifold-renderer-ghost-slot). The backdrop intentionally does NOT
 * follow --mt-bg — the tooltip floats over chart content and needs to
 * stay readable regardless of theme; rgba(10,12,18,0.93) is the
 * historically-tuned tooltip backdrop used across the chart family. */
.manifold-chart-tooltip {
  background: rgba(10, 12, 18, 0.93);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 6px;
  padding: 5px 8px;
}

/* Phase 19 Plan 05c — MultiSeriesChartRenderer live-cursor time label.
 * A small monospace timestamp pill that floats next to the cursor at
 * each gridline x position (and a parallel use inside the time-axis
 * labels row at the bottom of the chart). Background uses color-mix so
 * the pill stays legible in any theme. */
.manifold-chart-time-label {
  background: color-mix(in srgb, var(--mt-bg) 80%, transparent);
  padding: 0 4px;
  border-radius: var(--m-radius-sm, 4px);
}

/* Phase 19 Plan 05c — MultiSeriesChartRenderer hover crosshair. A 1px
 * white-translucent vertical line marking the hovered x position. */
.manifold-chart-cursor-line {
  background: rgba(255, 255, 255, 0.18);
}

/* Phase 19 Plan 05c — MultiSeriesChartRenderer hover-point dot. Two
 * classes because the primary-series dot carries an extra outer glow
 * (the original JSX did this with a conditional
 *   boxShadow: i === 0 ? '0 0 6px ${c}' : 'none'
 * ). The base class handles the round colored fill for every series
 * dot; the `-primary` modifier adds the glow. Size + position stay
 * inline (state-driven: sz comes from chart-size math, left/top are
 * percent of chart width/height). */
.manifold-chart-hover-dot {
  border-radius: 50%;
  background: var(--m-series-color);
}
.manifold-chart-hover-dot-primary {
  box-shadow: 0 0 6px var(--m-series-color);
}

/* Phase 19 Plan 05d — PillRenderer body. The pill carries a state-driven
 * color (OK green / WARN amber / ERROR red etc.) and uses a 12% tinted
 * background + 33% tinted border + 1px ring + full pill radius. Pre-
 * migration the JSX baked the alpha as a hex suffix on the color literal
 * (`${color}20` / `${color}55`). color-mix expresses the same intent
 * in a theme-friendly way and works with any CSS color, so themed
 * status tokens (var(--mt-warn)) and ad-hoc hex literals both work.
 *
 * Padding is runtime (driven by fontSize so the pill scales with the
 * card) so it stays inline via two CSS custom properties. */
.manifold-renderer-pill {
  border-radius: 9999px;
  background: color-mix(in srgb, var(--m-renderer-color, var(--mt-muted)) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--m-renderer-color, var(--mt-muted)) 33%, transparent);
  color: var(--m-renderer-color, var(--mt-muted));
  padding: var(--m-renderer-pad-y, 4px) var(--m-renderer-pad-x, 10px);
}

/* Phase 19 Plan 05d — DotRenderer body. The dot is a solid colored
 * circle with a soft glow matching the dot color. Same per-instance
 * color hook (--m-renderer-color) as the rest of the renderer family.
 * Diameter + glow size stay inline (state-driven from fontSize math).
 * The glow scales via --m-renderer-glow-size so the box-shadow key
 * lives behind a class instead of an inline-style key. */
.manifold-renderer-dot {
  border-radius: 50%;
  background: var(--m-renderer-color, var(--mt-muted));
  box-shadow: 0 0 var(--m-renderer-glow-size, 6px) var(--m-renderer-color, var(--mt-muted));
  flex-shrink: 0;
}

/* Phase 19 Plan 05d — RangePickerRenderer button + chip primitives.
 * The picker button is a small mono-uppercase chip-style trigger that
 * pops the v5 calendar (window.Picker). Hover state shifts the
 * foreground + border from `dim` to `accent`; pre-migration the JSX
 * implemented this via inline-style mutation on onMouseEnter/Leave —
 * a class with :hover replaces that imperative pattern with declarative
 * CSS that the audit can't flag.
 *
 * .manifold-range-chip is the "X hours" duration pill the picker button
 * carries on its right side. Same color-mix accent backdrop pattern as
 * the health-overall pill, but smaller and more compact. */
.manifold-renderer-rangepicker-btn {
  background: transparent;
  color: var(--mt-dim);
  border: 1px solid var(--mt-border);
  border-radius: var(--m-radius-md, 6px);
  padding: 6px var(--m-renderer-pad-x, 12px);
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.manifold-renderer-rangepicker-btn:hover {
  color: var(--mt-accent);
  border-color: var(--mt-accent);
}
.manifold-range-chip {
  padding: 0 6px;
  background: color-mix(in srgb, var(--mt-accent) 13%, transparent);
  color: var(--mt-accent);
  border-radius: 99px;
}

/* Phase 19 Plan 05d — VideoRenderer letterbox. The video element's
 * outer container fills with solid black so any aspect-ratio mismatch
 * paints as a true letterbox bar (not theme bg). This is INTENTIONALLY
 * theme-independent: every video looks better against pure black, and
 * the renderer's JSX comment pre-migration explicitly called this out
 * ("intrinsic — video element background; theme-independent letterbox
 * color"). Keeping the same intent under a class so the audit doesn't
 * flag the background key. */
.manifold-renderer-video-letterbox {
  background: #000;
}

/* Phase 19 Plan 05d — TopNRenderer rows + secondary text.
 * .manifold-renderer-topn-row carries the row chrome: hairline bottom
 * border + 2px bottom padding so each ranked entry has a clear divider.
 * .manifold-renderer-topn-secondary is the secondary-text shape used
 * for sub_label / camera / value (muted color + 6px left gap) — sits
 * after the primary in the same row.
 * 11px / 9px fontSize values stay as the runtime --m-renderer-value-size
 * + --m-renderer-hint-text shapes already shipped. */
.manifold-renderer-topn-row {
  border-bottom: 1px solid var(--mt-border);
  padding-bottom: 2px;
}
.manifold-renderer-topn-secondary {
  color: var(--mt-muted);
  margin-left: 6px;
}

/* Phase 19 Plan 05d — EventBadgesRenderer item badge. Three variants:
 *   1. Round icon-only (default mode) — borderRadius:50%, square padding
 *   2. Pill with icon + name (sub_label present) — borderRadius:9999px,
 *      asymmetric padding
 *   3. Text fallback when no icon matches — same shape as 1, plus inner
 *      span carrying the literal text
 *
 * Background tints at 33% (${color}55 pre-migration) and border tints at
 * 66% (${color}aa pre-migration) of the badge's state-driven itemColor.
 * The color flows in via --m-renderer-color per badge — same hook every
 * other renderer in this family uses. Padding/border-radius stay runtime
 * (proportional to iconSize, varies by isNamed). */
.manifold-renderer-badge {
  background: color-mix(in srgb, var(--m-renderer-color, var(--mt-muted)) 33%, transparent);
  border: 1px solid color-mix(in srgb, var(--m-renderer-color, var(--mt-muted)) 66%, transparent);
  padding: var(--m-renderer-badge-pad, 2px);
  border-radius: var(--m-renderer-badge-radius, 50%);
}
/* Phase 19 Plan 05d — EventBadges text-fallback inner span. The pre-
 * migration JSX wrote `padding: isNamed ? 0 : '0 4px'`. Both values are
 * shape-keyed (pill vs round), so the custom property carries the
 * resolved shorthand. */
.manifold-renderer-badge-text {
  padding: var(--m-renderer-badge-text-pad, 0);
}

/* Phase 19 Plan 05d — ListRenderer header + row + button primitives.
 * ListRenderer is the most complex renderer in the status/list family
 * (23 inline-style sites pre-migration). It carries:
 *   - Optional header row (style.header=true): hairline bottom border,
 *     muted uppercase text, runtime-padded
 *   - Per-row tag (<div> or <a> depending on style.rowLink): clickable
 *     rows get a subtle accent backdrop on :hover and :focus, replacing
 *     the imperative onMouseEnter/Leave/Focus/Blur background mutation
 *     the pre-migration JSX used
 *   - Per-field span: state-driven text-align + per-field color via
 *     --m-renderer-color
 *   - Load-more button: dashed accent border + accent fg, muted state
 *     when exhausted (:disabled in CSS)
 *
 * The hover/focus declarative selectors keep the accent-tint at the
 * same 7%/9% color-mix the pre-migration hex-suffix trick produced
 * (${accent}12 ≈ 7%, ${accent}18 ≈ 9%). */
.manifold-renderer-list-header {
  border-bottom: 1px solid var(--mt-border);
  padding-bottom: var(--m-renderer-list-header-pb, 2px);
  margin-bottom: var(--m-renderer-list-header-mb, 2px);
  color: var(--mt-muted);
}
.manifold-renderer-list-empty {
  color: var(--mt-muted);
  padding: 4px 0;
}
.manifold-renderer-list-row {
  padding-top: var(--m-renderer-list-row-pt, 0);
  border-radius: var(--m-renderer-list-row-radius, 0);
  color: inherit;
}
.manifold-renderer-list-row[data-clickable="true"]:hover {
  background: color-mix(in srgb, var(--mt-accent) 7%, transparent);
}
.manifold-renderer-list-row[data-clickable="true"]:focus-visible {
  background: color-mix(in srgb, var(--mt-accent) 9%, transparent);
}
/* Phase 19 Plan 05d — ListRenderer load-more button. dashed-accent ring
 * for the active state; muted hairline when exhausted (publisher / paged
 * source has no older events). :disabled is the natively-correct hook —
 * the button element's `disabled` attribute is what the pre-migration
 * JSX was already setting. */
.manifold-renderer-list-loadmore {
  align-self: flex-start;
  margin-top: 4px;
  padding: 3px 10px;
  background: transparent;
  color: var(--mt-accent);
  border: 1px dashed color-mix(in srgb, var(--mt-accent) 40%, transparent);
  border-radius: var(--m-radius-sm, 4px);
  cursor: pointer;
}
.manifold-renderer-list-loadmore:disabled {
  color: var(--mt-muted);
  border-color: var(--mt-border);
  cursor: default;
}
/* Phase 19 Plan 05d — dynamic text-align escape hatch. Drives
 *   text-align: var(--m-text-align)
 * from a per-element custom property so field-driven alignment (e.g.
 * `field.align: 'right'` per ListRenderer column) survives without an
 * inline textAlign key. */
.manifold-text-align-dyn { text-align: var(--m-text-align, left); }

/* Phase 19 Plan 05e — BundledIcon SVG color. The pre-migration JSX wrote
 * `style={{color: color || 'currentColor'}}` on the outer <svg> element so
 * inner attrs using currentColor (e.g. multi-element weather icons) would
 * resolve to the outer wrapper's color. Migrating to a class that reads
 * `var(--m-renderer-color, currentColor)` preserves the same fallback
 * semantics: when the caller passes a `color` prop, the JSX sets the var
 * on the inline style (state-driven escape hatch); when the caller omits
 * it, the class falls back to `currentColor` which inherits from the
 * parent text-color cascade. Used by SvgRenderer's icon mode AND every
 * icon-library picker thumbnail across the gear → icon-picker UI. */
.manifold-bundled-icon { color: var(--m-renderer-color, currentColor); }

/* Phase 19 Plan 05e — action-result family shared vocabulary.
 *
 * The four action-result renderers (List / Table / Image / Text) display
 * the response of clicking a service-action button. Pre-migration each
 * renderer baked the same handful of visual primitives inline:
 * monospace font, ellipsis-truncate row text, runtime-sized chrome,
 * accent-vs-destructive button color signal. Centralizing the vocabulary
 * here means the four renderers compose the same classes instead of
 * repeating the same inline-style trios. */

/* Font-family escape hatches — the action-result family pre-migration
 * wrote `fontFamily: '"JetBrains Mono",monospace'` (~12 sites) and
 * `fontFamily: 'var(--m-font-sans, "Rubik", sans-serif)'` (1 site) in
 * inline style. The theme token (--m-font-mono / --m-font-sans) is
 * already defined in :root; the escape-hatch class just routes the
 * inline `fontFamily` key off the audit-watched surface with the same
 * fallback ladder the pre-migration JSX carried.
 *
 * Two classes (not one) because the action-result renderer family has
 * TWO distinct font choices: monospace for tabular/list data + text
 * blocks marked `monospace: true`, sans-serif for narrative text blocks.
 * Tagging both as "font-mono" is wrong; tagging both as "font" is
 * ambiguous. */
.manifold-renderer-font-mono { font-family: var(--m-font-mono, "JetBrains Mono", monospace); }
.manifold-renderer-font-sans { font-family: var(--m-font-sans, "Rubik", sans-serif); }

/* Truncate-with-ellipsis — three CSS properties (overflow, text-overflow,
 * white-space) always set together. Pre-migration the trio repeated
 * across every cell + row span in the action-list/table renderers (8+
 * sites). Bundling reads as one visual primitive ("truncate this cell")
 * and reduces inline-style churn. */
.manifold-renderer-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Action-list outer wrap. The pre-migration JSX wrote:
 *   { width:'100%', height:'100%', display:'flex', flexDirection:'column',
 *     gap: rowGap, fontFamily:'"JetBrains Mono",monospace', fontSize,
 *     padding: 'var(--m-pad-md, 10px)' }
 * The rowGap and fontSize are state-driven (compact mode reduces both);
 * everything else is structural. Routing rowGap + fontSize through CSS
 * custom properties moves the audit-watched keys off the inline-style
 * surface. The class composes width/height/display/flex-direction/padding
 * and reads the runtime gap + fontSize from per-element vars. */
.manifold-renderer-action-list {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--m-renderer-action-list-gap, 4px);
  font-size: var(--m-renderer-action-list-fs, 11px);
  padding: var(--m-pad-md, 10px);
}

/* Action-result row. Used by both ListActionResultRenderer and
 * _EnvelopeRow (its envelope-shape sibling). Pre-migration:
 *   { display:'flex', alignItems:'baseline', gap: <state>,
 *     borderTop: separators && idx > 0 ? '1px solid var(...)' : 'none',
 *     paddingTop: separators && idx > 0 ? Math.max(2, rowGap) : 0,
 *     minWidth: 0 }
 * Display + alignment + minWidth are structural; gap + borderTop + pt
 * are state-driven (vary with separators flag and row position). The
 * class composes the structural keys and reads the state-driven ones
 * from custom properties. borderTop carries an `0` fallback so rows
 * without separators read as `border-top: 0 solid transparent`. */
.manifold-renderer-action-row {
  display: flex;
  align-items: baseline;
  min-width: 0;
  gap: var(--m-renderer-action-row-gap, 6px);
  border-top: var(--m-renderer-action-row-border-top, 0 solid transparent);
  padding-top: var(--m-renderer-action-row-pt, 0);
}

/* Envelope row "type chip" — small bordered pill carrying the event type
 * (e.g. "grab", "import"). Pre-migration:
 *   { fontSize: fontSize - 1, padding:'1px 5px', borderRadius:3,
 *     border: '1px solid ${typeColor}55', color: typeColor,
 *     flexShrink:0, lineHeight:'14px', fontFamily:'"JetBrains Mono",monospace' }
 * typeColor is `var(--m-accent, #7aa8f0)` — a single accent. Border
 * carries 33% tint via color-mix; fontSize is runtime. The flex-shrink
 * + line-height + radius + padding stay class-baked because they don't
 * vary with state. */
.manifold-renderer-envelope-chip {
  padding: 1px 5px;
  border-radius: 3px;
  border: 1px solid color-mix(in srgb, var(--m-renderer-color, var(--mt-accent)) 33%, transparent);
  color: var(--m-renderer-color, var(--mt-accent));
  flex-shrink: 0;
  line-height: 14px;
  font-size: var(--m-renderer-chip-fs, 10px);
}

/* Action-row button — the destructive-vs-accent affordance attached to
 * each row inside list/table action results. Pre-migration:
 *   { fontSize: 10-11, padding:'2px 8px',
 *     color: destructive ? var(--m-error) : var(--m-accent),
 *     background:'transparent',
 *     border: `1px solid ${destructive ? 'var(--m-error)' : 'var(--m-accent)'}55`,
 *     borderRadius:3,
 *     cursor: rowPending ? 'wait' : 'pointer' }
 * The destructive-vs-accent color is state-driven; everything else is
 * static. Routing the color through --m-renderer-color (set by the JSX
 * to var(--m-error) for destructive rows, var(--m-accent) otherwise)
 * preserves the per-row semantic while moving the inline color/border
 * keys off the audit surface. cursor:wait when rowPending stays inline
 * via a separate hook OR via a `data-pending` attr selector; we use
 * the attr-selector pattern so the cursor key moves off too. */
.manifold-renderer-action-rowbtn {
  background: transparent;
  color: var(--m-renderer-color, var(--mt-accent));
  border: 1px solid color-mix(in srgb, var(--m-renderer-color, var(--mt-accent)) 33%, transparent);
  border-radius: 3px;
  padding: 2px 8px;
  cursor: pointer;
}
.manifold-renderer-action-rowbtn[data-pending="true"] { cursor: wait; }
.manifold-renderer-action-rowbtn:disabled {
  cursor: wait;
}

/* Action-list dashed-accent load-more button. Same posture as
 * .manifold-renderer-list-loadmore but with a different visual budget
 * (4px margin-top vs ListRenderer's variants, smaller padding). The
 * fontSize is state-driven (compact mode shrinks it). */
.manifold-renderer-action-loadmore {
  align-self: flex-start;
  margin-top: 4px;
  padding: 3px 10px;
  background: transparent;
  color: var(--mt-accent);
  border: 1px dashed var(--mt-accent);
  border-radius: var(--m-radius-sm, 4px);
  cursor: pointer;
  font-size: var(--m-renderer-action-loadmore-fs, 10px);
}

/* Action-table outer wrap. Pre-migration:
 *   { width:'100%', height:'100%', overflow: sticky ? 'auto' : 'visible',
 *     fontFamily:'"JetBrains Mono",monospace', fontSize:11,
 *     padding: 'var(--m-pad-sm, 6px)' }
 * overflow varies with sticky flag; everything else is structural. We
 * use a `data-sticky="true"` attr selector for the auto-overflow variant
 * so both inline-style keys (overflow, font-family, font-size, padding)
 * move off the surface. */
.manifold-renderer-action-table {
  width: 100%;
  height: 100%;
  overflow: visible;
  font-size: 11px;
  padding: var(--m-pad-sm, 6px);
}
.manifold-renderer-action-table[data-sticky="true"] { overflow: auto; }

/* Action-table inner grid. Pre-migration:
 *   { display:'grid', gridTemplateColumns: <runtime>, rowGap:0,
 *     columnGap:8, minWidth:'100%' }
 * gridTemplateColumns is fully runtime (varies with column count + widths)
 * so it stays inline via a custom property. */
.manifold-renderer-action-grid {
  display: grid;
  row-gap: 0;
  column-gap: 8px;
  min-width: 100%;
  grid-template-columns: var(--m-renderer-action-grid-cols, 1fr);
}

/* Action-table header cell. Pre-migration:
 *   { position: sticky ? 'sticky' : 'static', top: 0,
 *     background:'var(--mt-bg-elev, var(--mt-bg))',
 *     color:'var(--m-text-muted, var(--mt-muted))',
 *     fontSize:'var(--mt-text-sm-size, 10px)',
 *     fontWeight:700, letterSpacing:0.4, textTransform:'uppercase',
 *     padding:'4px 6px',
 *     borderBottom: '1px solid var(--m-border, var(--mt-border))',
 *     cursor: col.sortable ? 'pointer' : 'default',
 *     display:'flex', alignItems:'center', gap:4,
 *     textAlign: col.align || 'left' }
 * position varies with sticky; cursor varies with sortable; textAlign
 * is runtime per column. Bundling the bulk of properties + routing the
 * three state-driven ones via attr selectors + --m-text-align var. */
.manifold-renderer-action-thead {
  position: static;
  top: 0;
  background: var(--mt-bg-elev, var(--mt-bg));
  color: var(--mt-muted);
  font-size: var(--mt-text-sm-size, 10px);
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  padding: 4px 6px;
  border-bottom: 1px solid var(--mt-border);
  cursor: default;
  display: flex;
  align-items: center;
  gap: 4px;
}
.manifold-renderer-action-thead[data-sticky="true"] { position: sticky; }
.manifold-renderer-action-thead[data-sortable="true"] { cursor: pointer; }

/* Action-table sort arrow — the small ▲/▼/▾ glyph in the header cell.
 * Pre-migration the color flips between accent (this column is sorted)
 * and muted (not sorted) via a JSX ternary inline. The arrow's color
 * routes through --m-renderer-color (set by the JSX) so the class only
 * supplies the fontSize + the var consumption. */
.manifold-renderer-action-sort {
  color: var(--m-renderer-color, var(--mt-muted));
  font-size: 9px;
}

/* Action-table data cell. Pre-migration:
 *   { padding:'4px 6px', color:'var(--m-text, var(--mt-fg))',
 *     background: idx % 2 ? 'var(--mt-bg-elev, transparent)' : 'transparent',
 *     overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap',
 *     textAlign: col.align || 'left' }
 * Background is state-driven (zebra-striping); textAlign per column.
 * Routes zebra bg through `data-zebra="true"` attr selector and reuses
 * `.manifold-renderer-truncate` + `.manifold-text-align-dyn` for the
 * overflow trio + alignment respectively. */
.manifold-renderer-action-cell {
  padding: 4px 6px;
  color: var(--mt-fg);
  background: transparent;
}
.manifold-renderer-action-cell[data-zebra="true"] { background: var(--mt-bg-elev, transparent); }

/* Action-table row-action cell — the right-side column carrying the
 * per-row action buttons. Same zebra-striping shape as
 * .manifold-renderer-action-cell but with inline-flex + tight gap so the
 * button strip lays out horizontally. */
.manifold-renderer-action-rowact-cell {
  padding: 3px 6px;
  display: inline-flex;
  gap: var(--m-pad-xs, 4px);
  background: transparent;
}
.manifold-renderer-action-rowact-cell[data-zebra="true"] { background: var(--mt-bg-elev, transparent); }

/* Action-table header spacer cell — the empty header above the
 * row-action column. Same sticky + bg + border-bottom as
 * .manifold-renderer-action-thead but without the typographic chrome
 * (this cell carries no text). */
.manifold-renderer-action-thead-spacer {
  position: static;
  top: 0;
  background: var(--mt-bg-elev, var(--mt-bg));
  border-bottom: 1px solid var(--mt-border);
  padding: 4px 6px;
}
.manifold-renderer-action-thead-spacer[data-sticky="true"] { position: sticky; }

/* Action-image loading placeholder. Pre-migration:
 *   { aspectRatio:'16/9', background:'var(--mt-bg-elev, var(--mt-bg))',
 *     display:'flex', alignItems:'center', justifyContent:'center',
 *     color:'var(--m-text-muted, var(--mt-muted))',
 *     fontSize:'var(--mt-text-sm-size, 11px)',
 *     border:'1px solid var(--m-border, var(--mt-border))',
 *     borderRadius:'var(--m-radius-md, 6px)' }
 * All static — bundled into one class. The 16/9 aspect ratio + center
 * alignment + bg-elev + muted text reads as one visual primitive
 * ("loading thumbnail in a 16:9 frame"). */
.manifold-renderer-action-image-loading {
  aspect-ratio: 16 / 9;
  background: var(--mt-bg-elev, var(--mt-bg));
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--mt-muted);
  font-size: var(--mt-text-sm-size, 11px);
  border: 1px solid var(--mt-border);
  border-radius: var(--m-radius-md, 6px);
}

/* Action-image frame — the displayed-image container. Pre-migration:
 *   { display:'flex', justifyContent:'center', alignItems:'center',
 *     background:'var(--m-bg, var(--mt-bg))',
 *     border:'1px solid var(--m-border, var(--mt-border))',
 *     padding:'var(--m-pad-sm, 6px)',
 *     borderRadius:'var(--m-radius-md, 6px)',
 *     width:'100%', height:'100%' } */
.manifold-renderer-action-image-frame {
  display: flex;
  justify-content: center;
  align-items: center;
  background: var(--mt-bg);
  border: 1px solid var(--mt-border);
  padding: var(--m-pad-sm, 6px);
  border-radius: var(--m-radius-md, 6px);
  width: 100%;
  height: 100%;
}

/* Action-image <img> tag — the actual image element. Pre-migration:
 *   { maxWidth:'100%', maxHeight:'min(70vh, 480px)', objectFit:'contain' }
 * All static. */
.manifold-renderer-action-image-img {
  max-width: 100%;
  max-height: min(70vh, 480px);
  object-fit: contain;
}

/* Action-text body — the pre-wrap text block. Pre-migration:
 *   { whiteSpace:'pre-wrap',
 *     fontSize:'var(--mt-text-md-size, 12px)',
 *     lineHeight:1.5,
 *     color:'var(--m-text, var(--mt-fg))',
 *     padding:'var(--m-pad-md, 10px)',
 *     fontFamily: <state — mono if response.monospace, else sans>,
 *     maxHeight: overflow ? '60vh' : 'none',
 *     overflow: overflow ? 'auto' : 'visible',
 *     width:'100%' }
 * font-family is state-driven (monospace flag); maxHeight + overflow
 * are state-driven (lineCount > 80). The class bundles the static keys
 * and the JSX composes either `.manifold-renderer-font-mono` or
 * `.manifold-renderer-font-sans` on top, plus a `data-overflow="true"`
 * attr-selector variant for the scroll-clip path. */
.manifold-renderer-action-text {
  white-space: pre-wrap;
  font-size: var(--mt-text-md-size, 12px);
  line-height: 1.5;
  color: var(--mt-fg);
  padding: var(--m-pad-md, 10px);
  width: 100%;
  max-height: none;
  overflow: visible;
}
.manifold-renderer-action-text[data-overflow="true"] {
  max-height: 60vh;
  overflow: auto;
}

/* Action-text empty placeholder. Pre-migration:
 *   { color:'var(--m-text-muted, var(--mt-muted))',
 *     fontStyle:'italic',
 *     padding:'var(--m-pad-md, 10px)',
 *     fontSize:'var(--mt-text-md-size, 12px)' } */
.manifold-renderer-action-text-empty {
  color: var(--mt-muted);
  font-style: italic;
  padding: var(--m-pad-md, 10px);
  font-size: var(--mt-text-md-size, 12px);
}

/* Action-list / action-table empty placeholder. Used by both the list
 * and table action-result renderers when their items[] is empty.
 * Center-aligned muted text in a generous padding bucket. */
.manifold-renderer-action-list-empty {
  color: var(--mt-muted);
  padding: var(--m-pad-lg, 12px);
  text-align: center;
  font-size: var(--mt-text-sm-size, 11px);
}

/* Phase 19 Plan 05d — LogStreamRenderer load-more button. Shape diverges
 * from ListRenderer's dashed-accent button: LogStream's variant is a
 * borderless transparent accent-text affordance, more like a textual
 * "+ Load more" link than a chunky chip. Padding is symmetrical-vertical
 * only ('4px 0'). */
.manifold-renderer-logstream-loadmore {
  background: transparent;
  border: none;
  color: var(--mt-accent);
  padding: 4px 0;
  text-align: left;
  cursor: pointer;
}

/* Phase 19 Plan 05f — service-family escape-hatch classes (helpers + 4
 * renderers).  Authoring rules same as 19-05a..e:
 *   - Aesthetic values route through `--mt-*` tokens (theme-skinnable) or
 *     `--m-renderer-*` custom properties set inline (state-driven values
 *     that the audit script no longer flags as FORBIDDEN).
 *   - Per-class differentiation that the runtime computes (status color,
 *     per-detection-class bbox color, per-service brand color) flows
 *     through `--m-renderer-color` / `--m-renderer-brand` etc.; the class
 *     consumes the prop once for foreground and once for `color-mix(...)`
 *     tinted background + border (replaces the pre-migration `${c}15` /
 *     `${c}66` hex-suffix tricks, which only happened to work because both
 *     sides were 6-digit hex resolved at runtime).
 * --------------------------------------------------------------------- */

/* ServiceMethodButton — three chrome modes (default pill / minimal text /
 * invisible overlay), all routing the state-driven status color through
 * `--m-renderer-color`.  `data-pending="true"` flips cursor to `wait`;
 * `data-gated="true"` greys the button to communicate "this verb is
 * locked for your role" (preserves the pre-migration `opacity:0.55 +
 * cursor:not-allowed` semantic — losing it would make a sensitive verb
 * look identical to an active one, a real safety regression per
 * feedback_no_shell_via_browser). */
.manifold-renderer-svc-btn {
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: var(--m-renderer-value-size);
  font-weight: 600;
  color: var(--m-renderer-color);
  background: color-mix(in srgb, var(--m-renderer-color) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--m-renderer-color) 40%, transparent);
  border-radius: 5px;
  padding: 4px 10px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.manifold-renderer-svc-btn-minimal {
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: var(--m-renderer-value-size);
  font-weight: 600;
  color: var(--m-renderer-color);
  background: transparent;
  border: none;
  padding: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  transition: color 0.15s;
}
.manifold-renderer-svc-btn-invisible {
  position: absolute;
  inset: 0;
  background: transparent;
  border: none;
  padding: 0;
  display: block;
  cursor: pointer;
}
.manifold-renderer-svc-btn[data-pending="true"],
.manifold-renderer-svc-btn-minimal[data-pending="true"],
.manifold-renderer-svc-btn-invisible[data-pending="true"] { cursor: wait; }
.manifold-renderer-svc-btn[data-gated="true"],
.manifold-renderer-svc-btn-minimal[data-gated="true"],
.manifold-renderer-svc-btn[data-gated="true"]:disabled,
.manifold-renderer-svc-btn-minimal[data-gated="true"]:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

/* ServiceNavigateLink — three chrome modes mirror the button helper's
 * shape but as <a> anchors (text-decoration:none, line-height:1).
 * Sensitive-vs-routine accent flows through --m-renderer-color (set
 * inline; sensitive uses t.warn, routine uses t.accent or style.color
 * override). Same color-mix tint pattern for the pill background +
 * border. */
.manifold-renderer-svc-nav {
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: var(--m-renderer-value-size);
  font-weight: 600;
  text-decoration: none;
  color: var(--m-renderer-color);
  background: color-mix(in srgb, var(--m-renderer-color) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--m-renderer-color) 25%, transparent);
  border-radius: 5px;
  padding: 4px 10px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1;
}
.manifold-renderer-svc-nav-minimal {
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: var(--m-renderer-value-size);
  font-weight: 600;
  text-decoration: none;
  color: var(--m-renderer-color);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1;
  cursor: pointer;
}
.manifold-renderer-svc-nav-invisible {
  position: absolute;
  inset: 0;
  display: block;
  background: transparent;
  text-decoration: none;
  cursor: pointer;
}

/* ServiceNavigateLink inner spans: trailing `↗` (subdued, opacity 0.85)
 * and label text with optional ellipsis trio.  The label-trunc variant
 * pairs with .manifold-renderer-truncate (already shipped 19-05e); the
 * non-truncating variant is the default. */
.manifold-renderer-svc-nav-arrow {
  font-size: var(--m-renderer-arrow-size);
  opacity: 0.85;
}

/* ServiceAuthorityIcon — compact owner-only authority indicator inside
 * ServicePlacardRenderer's action cluster. Tiny padlock glyph (🔒 or
 * 🔓) that doubles as state indicator + toggle button.
 *
 * SAFETY-CRITICAL VISUAL DIFFERENTIATION (per feedback_no_shell_via_browser):
 *   - data-overridden="true"  -> opacity:1 + accent-tinted drop-shadow
 *     halo. Signals "owner has actively pinned this gate to a non-default
 *     value." Visible chrome reads as a deliberate choice.
 *   - data-overridden absent  -> opacity:0.55 + no halo. Reads as
 *     "catalog default; click to override."  Losing the visual gap would
 *     erase the at-a-glance signal of which services have an explicit
 *     owner override active — a real safety regression.
 *
 *   Click-pending state (data-pending) flips cursor to `wait` without
 *   disturbing the overridden halo.  The locked emoji vs unlocked emoji
 *   (🔒 vs 🔓) is text content in the JSX; the CSS only carries the
 *   differentiated chrome around it. */
.manifold-renderer-svc-authority-icon {
  background: transparent;
  border: none;
  padding: 0 4px;
  margin-left: 2px;
  cursor: pointer;
  font-size: 11px;
  line-height: 1;
  opacity: 0.55;
  filter: none;
  transition: opacity 180ms, filter 180ms;
}
.manifold-renderer-svc-authority-icon[data-overridden="true"] {
  opacity: 1;
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--mt-accent) 40%, transparent));
}
.manifold-renderer-svc-authority-icon[data-pending="true"] { cursor: wait; }
.manifold-renderer-svc-authority-icon:disabled { cursor: wait; }

/* ServiceAuthorityToggle — owner-only meta-control rendered beneath a
 * ServiceActionsRenderer cluster.  One-line monospace strip:
 *   "authority: admin ·overridden  [ delegate to admins ]"
 *
 * Visual semantics (same safety-critical posture as ServiceAuthorityIcon):
 *   - The "·overridden" marker (accent color, ml 4px) is the at-a-glance
 *     signal that the owner has pinned this service's gate.  It paints
 *     only when overridden is true; absence means "catalog default."
 *   - The flip button color flows through --m-renderer-color (warn by
 *     default, live on success flash, error on failure flash) + a
 *     color-mix 40% tint on the border, replacing the pre-migration
 *     `${color}66` hex-suffix trick. */
.manifold-renderer-svc-authority-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 4px;
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: 10px;
  color: var(--mt-dim);
  opacity: 0.78;
}
.manifold-renderer-svc-authority-current {
  color: var(--mt-muted);
  font-weight: 600;
}
.manifold-renderer-svc-authority-overridden-marker {
  color: var(--mt-accent);
  margin-left: 4px;
}
.manifold-renderer-svc-authority-flip-btn {
  font-family: inherit;
  font-size: inherit;
  color: var(--m-renderer-color, var(--mt-warn));
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--m-renderer-color, var(--mt-warn)) 40%, transparent);
  border-radius: 3px;
  padding: 1px 6px;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.manifold-renderer-svc-authority-flip-btn[data-pending="true"] { cursor: wait; }
.manifold-renderer-svc-authority-flip-btn:disabled { cursor: wait; }

/* EmptyCardBody — shared "no data yet" shell for Donut / StackedBarsTime
 * / Distribution renderers and any future renderer that wants the same
 * empty-state chrome.  Two classes:
 *   .manifold-renderer-empty-card-body  — outer flex column, center
 *     align, padding 10px 12px by default (suppressed by data-nopad="true"
 *     so renderers passing noPad get edge-to-edge layout).
 *   .manifold-renderer-empty-card-msg   — the small muted mono message
 *     (font-size 11px) describing why the card is empty.  Composes
 *     with .manifold-renderer-font-mono (shipped 19-05e) for the
 *     JetBrains Mono fallback chain — no need to coin a new family. */
.manifold-renderer-empty-card-body {
  width: 100%;
  height: 100%;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.manifold-renderer-empty-card-body[data-nopad="true"] { padding: 0; }
.manifold-renderer-empty-card-msg {
  color: var(--mt-muted);
  font-size: 11px;
}

/* ServicePlacardRenderer — rack-placard row: brand stripe + glowing
 * status LED on the left, brand icon, name+desc+group stack, optional
 * critical badge, launch arrow, action button cluster.  Designed for
 * use inside a service-repeat card where each repeat-iteration produces
 * one placard.  Karl 2026-05-09.
 *
 * State-driven values that flow through custom properties:
 *   --m-brand           — service brand color (svc.brand || t.accent).
 *                         Consumed by .placard outer wrap for the
 *                         left-edge gradient wash, .placard-stripe for
 *                         the colored bar, .placard-icon's BundledIcon
 *                         tint, and .placard-group-chip for the chip
 *                         outline / fill / text.
 *   --m-renderer-color  — LED status color (resolved from stateValue
 *                         via _serviceStateColor).  Halo + border use
 *                         color-mix tints of this prop.
 *   data-hover="true"   — set on every element whose chrome shifts on
 *                         hover (gradient brightness, stripe halo,
 *                         launch arrow color/position, actions cluster
 *                         opacity, critical badge opacity).
 *   data-state="ok|warn|fault" — drives the LED's animation + halo
 *                         (ok: pulsing accent halo; warn: pulsing
 *                         warn halo; fault: static dim halo; other:
 *                         no halo or animation).  See keyframes
 *                         manifold-led-pulse / -warn already shipped.
 *   data-fault="true"   — on the icon box, applies grayscale(1)
 *                         opacity(0.35) so a failed service icon reads
 *                         as visually disabled.
 *
 * Why per-state attr instead of N classes: the JSX already computes
 * isOk / isWarn / isFault as booleans; a single data-state attribute
 * carrying one of {ok, warn, fault, other} keeps the JSX wiring trivial
 * and the CSS rules adjacent in this block. */
.manifold-renderer-svc-placard {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  gap: 14px;
  padding-left: 22px;
  padding-right: 16px;
  padding-top: 10px;
  padding-bottom: 10px;
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--m-brand) 10%, transparent) 0%,
      transparent 38%),
    linear-gradient(155deg, var(--mt-bg), var(--mt-muted));
  background-blend-mode: normal;
  border-top: 1px solid var(--mt-border);
  border-bottom: 1px solid var(--mt-border);
  border-right: 1px solid var(--mt-border);
  cursor: default;
  transition: background 180ms ease-out;
  isolation: isolate;
}
.manifold-renderer-svc-placard[data-hover="true"] {
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--m-brand) 20%, transparent) 0%,
      transparent 38%),
    linear-gradient(155deg, var(--mt-bg), var(--mt-muted));
}
.manifold-renderer-svc-placard-stripe {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--m-brand);
  transition: box-shadow 200ms ease-out;
}
.manifold-renderer-svc-placard-stripe[data-hover="true"] {
  box-shadow:
    2px 0 18px 0 color-mix(in srgb, var(--m-brand) 47%, transparent),
    2px 0  6px 0 color-mix(in srgb, var(--m-brand) 67%, transparent);
}
.manifold-renderer-svc-placard-led {
  position: absolute;
  left: 7px; top: 50%;
  transform: translateY(-50%);
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--m-renderer-color);
  border: 1.5px solid var(--mt-bg);
  z-index: 2;
}
.manifold-renderer-svc-placard-led[data-state="ok"] {
  box-shadow: 0 0 8px var(--m-renderer-color);
  animation: manifold-led-pulse 2.5s ease-in-out infinite;
}
.manifold-renderer-svc-placard-led[data-state="warn"] {
  animation: manifold-led-pulse-warn 1.2s ease-in-out infinite;
}
.manifold-renderer-svc-placard-led[data-state="fault"] {
  box-shadow: 0 0 6px var(--m-renderer-color);
}
.manifold-renderer-svc-placard-icon-box {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  filter: none;
  transition: filter 180ms;
}
.manifold-renderer-svc-placard-icon-box[data-fault="true"] {
  filter: grayscale(1) opacity(0.35);
}
.manifold-renderer-svc-placard-icon-img {
  display: block;
  max-width: 100%;
  max-height: 100%;
}
.manifold-renderer-svc-placard-text-stack {
  flex: 1 1 0%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.manifold-renderer-svc-placard-name {
  font-family: var(--m-font-sans, "Rubik", sans-serif);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.01em;
  color: var(--mt-fg);
  line-height: 1.15;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.manifold-renderer-svc-placard-desc {
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: 11px;
  color: var(--mt-dim);
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.manifold-renderer-svc-placard-meta-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
}
.manifold-renderer-svc-placard-group-chip {
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--m-brand);
  background: color-mix(in srgb, var(--m-brand) 12%, transparent);
  padding: 1px 6px;
  border-radius: 3px;
  border: 1px solid color-mix(in srgb, var(--m-brand) 33%, transparent);
}
.manifold-renderer-svc-placard-critical {
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--mt-warn);
  opacity: 0.7;
  transition: opacity 180ms;
}
.manifold-renderer-svc-placard-critical[data-hover="true"] { opacity: 1; }
.manifold-renderer-svc-placard-launch {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--mt-dim);
  font-size: 16px;
  line-height: 1;
  text-decoration: none;
  transition: color 200ms, transform 200ms;
  transform: translate(0, 0);
}
.manifold-renderer-svc-placard-launch[data-hover="true"] {
  color: var(--m-brand);
  transform: translate(2px, -2px);
}
.manifold-renderer-svc-placard-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
  opacity: 0.78;
  transition: opacity 180ms;
}
.manifold-renderer-svc-placard-actions[data-hover="true"] { opacity: 1; }

/* ServiceElementRenderer leaf primitives — one class per p.type branch
 * (state LED, color swatch, text, time, flag star). The
 * .manifold-renderer-svc-element-dot variant covers both the state LED
 * (border in --mt-bg) and the color swatch (border in --mt-border) via
 * a data-style attr selector — different border owners, same square
 * /round + state-color shape.
 *
 * Size flows through --m-renderer-size (set inline; runtime from
 * style.size with a per-type default).  Color flows through
 * --m-renderer-color (state branch: from _serviceStateColor; color
 * branch: from p.value; flag branch: from filled-ternary). */
.manifold-renderer-svc-element-dot {
  width: var(--m-renderer-size);
  height: var(--m-renderer-size);
  background: var(--m-renderer-color);
}
.manifold-renderer-svc-element-dot[data-shape="led"] {
  border-radius: 50%;
  border: 1.5px solid var(--mt-bg);
}
.manifold-renderer-svc-element-dot[data-shape="swatch"] {
  border-radius: 3px;
  border: 1px solid var(--mt-border);
}
/* Text element — single class composes with .manifold-renderer-font-mono
 * or .manifold-renderer-font-sans (depending on isName) for the family
 * fallback chain; data-is-name="true" flips weight 400→600 and color
 * muted→fg (preserves the pre-migration name-vs-other visual hierarchy).
 * data-no-wrap="true" composes with .manifold-renderer-truncate (already
 * shipped 19-05e) — kept as a separate class on the JSX since the
 * triple `overflow/text-overflow/white-space` lives in that class.
 * Font size flows through --m-renderer-value-size (set inline). */
.manifold-renderer-svc-element-text {
  font-size: var(--m-renderer-value-size);
  font-weight: 400;
  color: var(--m-renderer-color, var(--mt-muted));
  line-height: 1.2;
  max-width: 100%;
}
.manifold-renderer-svc-element-text[data-is-name="true"] {
  font-weight: 600;
  color: var(--m-renderer-color, var(--mt-fg));
}
/* Flag star element — fontSize from --m-renderer-value-size; color
 * (filled=warn / unfilled=dim, or style.color override) from
 * --m-renderer-color. */
.manifold-renderer-svc-element-flag {
  font-size: var(--m-renderer-value-size);
  line-height: 1;
  color: var(--m-renderer-color);
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  user-select: none;
}
/* Bare img inside the icon branch — display:block via a tiny class
 * so the inline style can drop. Not theme-skinnable; just keeping the
 * file's `<img style={...}>` surface clean. */
.manifold-renderer-svc-element-img { display: block; }

/* BboxOverlayRenderer — Frigate detection-box overlay painted on top of
 * a video widget.  Four classes:
 *
 *   .manifold-renderer-bbox-overlay   — outer absolute layer; own
 *     compositor (translateZ + will-change + contain:paint) so per-event
 *     mutations don't invalidate the underlying video layer.
 *   .manifold-renderer-bbox-box       — per-detection bordered
 *     rectangle.  Border + soft halo flow through --m-renderer-color +
 *     color-mix tints (33% halo) — the box's left/top/width/height
 *     positioning stays inline (audit ALLOWED_KEYS already permits
 *     those geometry properties).
 *   .manifold-renderer-bbox-label     — anchored label badge above each
 *     box.  Background = --m-renderer-color directly; foreground
 *     contrasts on var(--mt-bg).
 *   .manifold-renderer-bbox-indicator — corner "BBOX · N" chip showing
 *     the overlay is active even with zero current detections.  Same
 *     --m-renderer-color flow as the label.
 *
 * Per-box --m-renderer-color is set ON EACH BOX inline (not on the
 * overlay container).  Today every box receives the same stroke color
 * (style.color || 'warn' resolved through tokens), but per-detection-
 * class differentiation (person=red, car=blue, ...) can be added later
 * by changing the JSX value alone — no CSS restructure needed.  Per
 * spawn-instruction Rule 1: per-class color preservation is built-in
 * via --m-renderer-color as the per-box escape hatch. */
.manifold-renderer-bbox-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  transform: translateZ(0);
  will-change: transform;
  contain: paint;
}
.manifold-renderer-bbox-box {
  position: absolute;
  border: 2px solid var(--m-renderer-color);
  border-radius: 2px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--mt-bg) 53%, transparent),
    0 0 8px color-mix(in srgb, var(--m-renderer-color) 33%, transparent);
  box-sizing: border-box;
}
.manifold-renderer-bbox-label {
  position: absolute;
  top: -18px;
  left: -2px;
  padding: 1px 5px;
  background: var(--m-renderer-color);
  color: var(--mt-bg);
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-radius: 2px;
  white-space: nowrap;
}
.manifold-renderer-bbox-label-score {
  margin-left: 4px;
  opacity: 0.85;
}
.manifold-renderer-bbox-indicator {
  position: absolute;
  bottom: 4px;
  right: 4px;
  padding: 1px 5px;
  background: color-mix(in srgb, var(--m-renderer-color) 13%, transparent);
  color: var(--m-renderer-color);
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-radius: 2px;
  border: 1px solid color-mix(in srgb, var(--m-renderer-color) 33%, transparent);
  pointer-events: none;
}

/* ServiceActionsRenderer outer wrap — the inline-style block consumed
 * by the renderer's `<div style={wrap}>` site carries `padding: '4px 6px'`
 * (a FORBIDDEN_KEY) plus structural flex/width/height set by applyAlign.
 * This class owns the padding-only aesthetic decision; the applyAlign-
 * produced flex/justify/align positioning stays inline (those are
 * ALLOWED_KEYS — width/height/display/flexDirection/etc. are runtime-
 * computed positioning, not theme aesthetic). */
.manifold-renderer-svc-actions-wrap {
  padding: 4px 6px;
}

/* =========================================================================
 * Phase 19-05g — gauges + decorative + closing family escape-hatch classes.
 *
 * Covers RankedBars / Svg / Heatmap / Gauge / MultiGauge / EasyPie / Donut /
 * StackedBarsTime / Distribution / SparklineAnomaly renderers.
 *
 * Two recurring patterns from 19-05f apply here verbatim:
 *
 *   1. Per-instance --m-renderer-color escape hatch for state-driven and
 *      data-driven fills. Heatmap cells, gauge needles, donut slices,
 *      easyPie ring, distribution bars, rankedBars bars — all of them
 *      drive their primary visible color from runtime data (per-cell value,
 *      per-row threshold, per-slice category, per-band anomaly score).
 *      Setting --m-renderer-color INLINE per-element means every chart
 *      keeps per-data-point differentiation; the class only owns the
 *      consumption (background:var(...) or stroke:var(...)).
 *
 *   2. data-* attr selectors for boolean variants. RankedBars top-rank
 *      vs rest, MultiGauge ghost vs received, SparklineAnomaly P99 line
 *      vs muted — each splits one base class into two states with a single
 *      attribute toggle, avoiding class proliferation.
 * ========================================================================= */

/* ── RankedBarsRenderer ──────────────────────────────────────────────
 *
 * Empty-state placeholder. Italic mono small text inside the bars stack.
 * Pre-migration:
 *   { fontFamily:'"JetBrains Mono",monospace', fontSize:11,
 *     color:'var(--mt-muted)', fontStyle:'italic', padding:'6px 0' }
 * fontStyle:'italic' is not a FORBIDDEN_KEY, so it stays inline; the rest
 * collapses into one class composing .manifold-renderer-font-mono with
 * fontSize + color + padding baked in. */
.manifold-renderer-rankedbars-empty {
  font-size: 11px;
  color: var(--mt-muted);
  padding: 6px 0;
}

/* RankedBars label row. Pre-migration:
 *   { display:'flex', alignItems:'baseline', justifyContent:'space-between',
 *     fontFamily:'"JetBrains Mono",monospace', fontSize:11 }
 * display/alignItems/justifyContent are structural (already inline). Class
 * owns the font-size only; mono composes via .manifold-renderer-font-mono. */
.manifold-renderer-rankedbars-label-row {
  font-size: 11px;
}

/* RankedBars label-text span. Per-row label color flows through
 * --m-renderer-color. Pre-migration:
 *   { color: labelColor, overflow:'hidden', textOverflow:'ellipsis',
 *     whiteSpace:'nowrap' }
 * The truncate trio is .manifold-renderer-truncate (Phase 19-05e). Color
 * routes through the standard per-instance prop. */
.manifold-renderer-rankedbars-label-text {
  color: var(--m-renderer-color, var(--mt-fg));
}

/* "(no data yet)" suffix span on unreceived rows. Pre-migration:
 *   { color:'var(--mt-dim)', marginLeft:4, fontSize:10 } */
.manifold-renderer-rankedbars-no-data {
  color: var(--mt-dim);
  margin-left: 4px;
  font-size: 10px;
}

/* RankedBars primary value (right-aligned number). Pre-migration:
 *   { color:'var(--mt-fg)', fontWeight:600, fontVariantNumeric:'tabular-nums' }
 * fontVariantNumeric not FORBIDDEN — stays inline. Color + weight via class. */
.manifold-renderer-rankedbars-val {
  color: var(--mt-fg);
  font-weight: 600;
}

/* RankedBars unit suffix span (right of primary value). Pre-migration:
 *   { color:'var(--mt-muted)', fontSize:10, fontWeight:400, marginLeft:3 } */
.manifold-renderer-rankedbars-unit {
  color: var(--mt-muted);
  font-size: 10px;
  font-weight: 400;
  margin-left: 3px;
}

/* RankedBars bar track. Pre-migration:
 *   { height: barHeight, background:'var(--mt-bg-deep)',
 *     borderRadius: Math.round(barHeight/2), overflow:'hidden' }
 * height + borderRadius are runtime (barHeight is style-configurable). Route
 * borderRadius through --m-rankedbars-radius so the audit-FORBIDDEN
 * borderRadius key moves off. height stays inline (NOT in FORBIDDEN_KEYS). */
.manifold-renderer-rankedbars-track {
  background: var(--mt-bg-deep);
  border-radius: var(--m-rankedbars-radius, 3px);
  overflow: hidden;
}

/* RankedBars bar fill. Pre-migration:
 *   { width: `${pct}%`, height:'100%',
 *     background: rank === 0 ? x.color : `${x.color}80`,
 *     borderRadius: Math.round(barHeight/2) }
 * width + height are runtime layout (stay inline). background per-row uses
 * --m-renderer-color SET PER BAR; data-top="true" on the rank-0 bar gets
 * full alpha, others 50% via color-mix. Replaces the `${x.color}80`
 * hex-suffix trick (only worked when x.color was 6-digit hex). */
.manifold-renderer-rankedbars-fill {
  background: color-mix(in srgb, var(--m-renderer-color, var(--mt-accent)) 50%, transparent);
  border-radius: var(--m-rankedbars-radius, 3px);
}
.manifold-renderer-rankedbars-fill[data-top="true"] {
  background: var(--m-renderer-color, var(--mt-accent));
}

/* ── SvgRenderer ─────────────────────────────────────────────────────
 *
 * Error / no-source fallback span. Pre-migration:
 *   { fontFamily:'"JetBrains Mono",monospace', fontSize:11,
 *     color:'var(--mt-muted)', fontStyle:'italic', textAlign:'center' }
 * fontStyle stays inline (not FORBIDDEN). Class owns fontSize + color +
 * textAlign. Mono composes via .manifold-renderer-font-mono. */
.manifold-renderer-svg-fallback {
  font-size: 11px;
  color: var(--mt-muted);
  text-align: center;
}

/* ── HeatmapRenderer ─────────────────────────────────────────────────
 *
 * Heatmap data drives PER-CELL color (the whole point of a heatmap). Per
 * Karl spawn-instruction: do NOT collapse cells into one color — that
 * turns a heatmap into a flat grid. Each cell sets --m-renderer-color
 * INLINE per <div>, the class consumes it. Today every cell uses
 * heatColor(val) which lerps through stops; the wiring per-cell is what
 * preserves the differentiation through theme switches.
 *
 * Grid wrapper. Pre-migration:
 *   { flex:1, display:'flex', flexDirection:'column', gap:1,
 *     fontFamily:'"JetBrains Mono",monospace', fontSize:10,
 *     minHeight:0, overflow:'hidden' }
 * Flex layout stays inline. Class owns font-size + composes font-mono. */
.manifold-renderer-heatmap-grid {
  font-size: 10px;
}

/* Heatmap label column (left side, mono right-aligned). Pre-migration:
 *   { width: labelWidth, color:'var(--mt-dim)', textAlign:'right',
 *     flexShrink:0, overflow:'hidden', textOverflow:'ellipsis',
 *     whiteSpace:'nowrap' }
 * width stays inline (runtime labelWidth). Class owns color + textAlign.
 * Truncate trio composes via .manifold-renderer-truncate. */
.manifold-renderer-heatmap-label {
  color: var(--mt-dim);
  text-align: right;
}

/* Heatmap unreceived-row " (no data yet)" suffix. Pre-migration:
 *   { marginLeft:4 } */
.manifold-renderer-heatmap-no-data {
  margin-left: 4px;
}

/* Heatmap row body — the stripe of cells. Pre-migration:
 *   { flex:1, display:'flex', height: rowHeight - 2,
 *     background:'var(--mt-bg-deep)', borderRadius:1 }
 * flex + display + height stay inline (runtime rowHeight). Class owns the
 * track background + 1px radius. */
.manifold-renderer-heatmap-row-track {
  background: var(--mt-bg-deep);
  border-radius: 1px;
}

/* Heatmap unreceived-row striped placeholder. Pre-migration:
 *   { flex:1, height: rowHeight - 2,
 *     background:'repeating-linear-gradient(90deg, transparent 0,
 *       transparent 4px, var(--mt-dim) 4px, var(--mt-dim) 5px)',
 *     borderRadius:1 }
 * flex + height stay inline. Class bundles the diagonal-stripe gradient
 * + 1px radius. */
.manifold-renderer-heatmap-row-ghost {
  background: repeating-linear-gradient(
    90deg,
    transparent 0,
    transparent 4px,
    var(--mt-dim) 4px,
    var(--mt-dim) 5px
  );
  border-radius: 1px;
}

/* Heatmap per-cell. Pre-migration:
 *   { flex:1, minWidth:1, background: heatColor(v) }
 * flex/minWidth stay inline. PER-CELL color via --m-renderer-color (set
 * inline by JSX from heatColor(v) for every individual cell — this is the
 * per-cell differentiation Karl flagged as critical: do NOT collapse). */
.manifold-renderer-heatmap-cell {
  background: var(--m-renderer-color, var(--mt-muted));
}

/* Heatmap "missing" tile — Phase 38 Plan 05 Task 1.
 *
 * Why: a heatmap row bound by a stable label (drive serial) whose drive
 * is no longer present in Netdata (pulled, dead, or not yet visible
 * because the resolver hasn't returned) paints this tile instead of the
 * value-coloured cell strip. SPEC line 47 binding: the SAME tile covers
 * "drive truly gone" and "drive not yet visible" — no separate spinner,
 * no loading state. The user reads one shape: "missing".
 *
 * Design choices:
 *   - background: --mt-bg-deep (the same flat backdrop the value track
 *     uses) with --mt-muted at 0.18 alpha layered on top. Reads dimmer
 *     than the value track, so a row of missing cells is visually
 *     distinct from a row of all-low-value cells, but doesn't shout.
 *   - color: --mt-dim. "missing" is informational, not an alarm — the
 *     user already knows something's wrong because the row is grey.
 *   - centered text via flex; tabular-nums keeps "missing" sitting on
 *     the same baseline as the right-edge latest-value column.
 *   - 1px radius matches the surrounding .manifold-renderer-heatmap-row-track
 *     so the missing tile slots in where a value strip would. */
.cb-cell-missing,
.manifold-renderer-heatmap-missing {
  background:
    linear-gradient(var(--mt-muted-overlay, rgba(128, 128, 128, 0.18)),
                    var(--mt-muted-overlay, rgba(128, 128, 128, 0.18))),
    var(--mt-bg-deep);
  color: var(--mt-dim);
  border-radius: 1px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-family: var(--mt-font-mono, monospace);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.05em;
  text-transform: lowercase;
  user-select: none;
}

/* Heatmap right-side latest-value label. Pre-migration:
 *   { ...mfont, fontSize:9, color: latest != null ? var(--mt-fg) : var(--mt-muted),
 *     width:36, textAlign:'right', flexShrink:0,
 *     fontVariantNumeric:'tabular-nums', fontWeight:600 }
 * width/flexShrink stay inline. Class owns font-size + textAlign + weight.
 * Color: --m-renderer-color set inline by JSX (fg for received-with-value,
 * muted/dim otherwise). */
.manifold-renderer-heatmap-latest {
  font-size: 9px;
  color: var(--m-renderer-color, var(--mt-muted));
  text-align: right;
  font-weight: 600;
}

/* Heatmap legend strip (gradient bar). Pre-migration:
 *   { width:8, background:`linear-gradient(to top, ${gradientStops})`,
 *     border:'1px solid var(--mt-border)', borderRadius:2 }
 * width stays inline. background is a runtime gradient (stops depend on
 * user's heatmapColors style) — route through --m-heatmap-legend-bg as a
 * runtime CSS prop. Class owns border + radius. */
.manifold-renderer-heatmap-legend-bar {
  background: var(--m-heatmap-legend-bg, var(--mt-bg-deep));
  border: 1px solid var(--mt-border);
  border-radius: 2px;
}

/* Heatmap legend tick column (min/mid/max numeric markers). Pre-migration:
 *   { display:'flex', flexDirection:'column', justifyContent:'space-between',
 *     fontFamily:'"JetBrains Mono",monospace', fontSize:9,
 *     color:'var(--mt-muted)', fontVariantNumeric:'tabular-nums' }
 * Flex layout stays inline. Class owns font-size + color; mono composes. */
.manifold-renderer-heatmap-legend-ticks {
  font-size: 9px;
  color: var(--mt-muted);
}

/* Heatmap hover tooltip. Pre-migration:
 *   { position:'fixed', top, left,
 *     fontFamily:'var(--m-font-mono)', fontSize:10, color:'var(--mt-fg)',
 *     background:`color-mix(in srgb, var(--mt-bg-deep) 93%, transparent)`,
 *     padding:'2px 6px', borderRadius:3,
 *     border:'1px solid var(--mt-border)', pointerEvents:'none',
 *     fontVariantNumeric:'tabular-nums', zIndex:9999, whiteSpace:'nowrap' }
 * position/top/left/zIndex stay inline (runtime cursor pos). Class owns
 * the visual chrome — same shape as .manifold-chart-tooltip but with a
 * font-size override (10 vs the chart tooltip's default). */
.manifold-renderer-heatmap-tooltip {
  font-size: 10px;
  color: var(--mt-fg);
  background: color-mix(in srgb, var(--mt-bg-deep) 93%, transparent);
  padding: 2px 6px;
  border-radius: 3px;
  border: 1px solid var(--mt-border);
  pointer-events: none;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Heatmap tooltip label span. Pre-migration:
 *   { color:'var(--mt-muted)' } */
.manifold-renderer-heatmap-tooltip-label {
  color: var(--mt-muted);
}

/* Heatmap tooltip value-bold span. Pre-migration:
 *   { fontWeight:700 } */
.manifold-renderer-heatmap-tooltip-val {
  font-weight: 700;
}

/* Heatmap tooltip "t-N" tail span. Pre-migration:
 *   { color:'var(--mt-muted)', marginLeft:6 } */
.manifold-renderer-heatmap-tooltip-tail {
  color: var(--mt-muted);
  margin-left: 6px;
}

/* ── Gauge family (Gauge / MultiGauge / EasyPie / Donut) ─────────────
 *
 * All four renderers draw arcs whose stroke colors are state-driven
 * (threshold rules: live/warn/error/accent). Today the SVG tag receives
 * stroke={valColor} directly, not style={{color:valColor}}, so the audit
 * doesn't see them — but the few inline-style sites that DO carry
 * FORBIDDEN_KEYS are the surrounding wrappers and labels.
 *
 * Gauge outer-wrap padding-only. Pre-migration:
 *   { width:'100%', height:'100%', padding: noPad ? 0 : '10px 12px',
 *     opacity, display:'flex', flexDirection:'column' }
 * width/height/opacity/display/flex stay inline. padding routes through
 * data-nopad attr selector (same shape as .manifold-renderer-empty-card-body
 * from 19-05f). */
.manifold-renderer-gauge-wrap {
  padding: 10px 12px;
}
.manifold-renderer-gauge-wrap[data-nopad="true"] {
  padding: 0;
}

/* MultiGauge sub-gauge label header (small uppercase ID above each arc).
 * Pre-migration:
 *   { fontFamily:'"JetBrains Mono",monospace', fontSize:9,
 *     color:'var(--mt-muted)', letterSpacing:0.4, textTransform:'uppercase',
 *     fontWeight:600, marginBottom:0, whiteSpace:'nowrap' }
 * letterSpacing/textTransform/whiteSpace stay inline (not FORBIDDEN).
 * Class owns font-size + color + weight + margin-bottom. Mono composes. */
.manifold-renderer-multigauge-label {
  font-size: 9px;
  color: var(--mt-muted);
  font-weight: 600;
  margin-bottom: 0;
}

/* MultiGauge unreceived " (no data yet)" suffix span. Pre-migration:
 *   { color:'var(--mt-dim)', marginLeft:4, textTransform:'none' } */
.manifold-renderer-multigauge-no-data {
  color: var(--mt-dim);
  margin-left: 4px;
}

/* MultiGauge empty-grid placeholder div. Pre-migration:
 *   { fontFamily:'"JetBrains Mono",monospace', fontSize:11,
 *     color:'var(--mt-muted)', fontStyle:'italic' } */
.manifold-renderer-multigauge-empty {
  font-size: 11px;
  color: var(--mt-muted);
}

/* EasyPie center-number text. Pre-migration:
 *   { fontFamily:'"JetBrains Mono", monospace', fontWeight:600,
 *     fontSize:28, color: ringColor, lineHeight:1, letterSpacing:'-0.02em',
 *     fontVariantNumeric:'tabular-nums' }
 * lineHeight/letterSpacing/fontVariantNumeric stay inline (not FORBIDDEN).
 * Class owns font-weight + font-size; color via --m-renderer-color (set
 * inline by JSX from ringColor which is state-driven). Mono composes. */
.manifold-renderer-easypie-center {
  font-weight: 600;
  font-size: 28px;
  color: var(--m-renderer-color, var(--mt-fg));
}

/* EasyPie center-unit span (% or unit string after the big number).
 * Pre-migration:
 *   { fontSize:14, color:'var(--mt-muted)', fontWeight:300, marginLeft:2 } */
.manifold-renderer-easypie-unit {
  font-size: 14px;
  color: var(--mt-muted);
  font-weight: 300;
  margin-left: 2px;
}

/* EasyPie detail row below the ring (raw value / max info). Pre-migration:
 *   { fontFamily:'"JetBrains Mono", monospace', fontSize:9,
 *     color:'var(--mt-muted)', letterSpacing:'0.04em', marginTop:4,
 *     textAlign:'center', maxWidth:'90%',
 *     overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }
 * letterSpacing/maxWidth stay inline. Truncate trio via .manifold-renderer-
 * truncate. Class owns font-size + color + marginTop + textAlign. */
.manifold-renderer-easypie-detail {
  font-size: 9px;
  color: var(--mt-muted);
  margin-top: 4px;
  text-align: center;
}

/* ── DonutRenderer ───────────────────────────────────────────────────
 *
 * Donut slice colors flow through the per-segment `stroke` attribute on
 * <path> (SVG attr, not CSS — not audited). The inline-style sites are
 * the center label, the legend rows, the swatch chips.
 *
 * Donut center "TOTAL" big number. Pre-migration:
 *   { fontFamily:'"JetBrains Mono", monospace', fontWeight:600,
 *     fontSize:26, color:'var(--mt-fg)', lineHeight:1,
 *     letterSpacing:'-0.02em', fontVariantNumeric:'tabular-nums' } */
.manifold-renderer-donut-total {
  font-weight: 600;
  font-size: 26px;
  color: var(--mt-fg);
}

/* Donut center-label subtitle ("TOTAL" or unit). Pre-migration:
 *   { fontFamily:'"JetBrains Mono", monospace', fontSize:9,
 *     color:'var(--mt-muted)', letterSpacing:'0.1em', marginTop:4,
 *     textTransform:'uppercase' } */
.manifold-renderer-donut-center-label {
  font-size: 9px;
  color: var(--mt-muted);
  margin-top: 4px;
}

/* Donut legend column wrapper. Pre-migration:
 *   { flex:'1 1 auto', minWidth:0, maxWidth:160,
 *     display:'flex', flexDirection:'column', gap:3,
 *     fontFamily:'"JetBrains Mono", monospace', fontSize:10,
 *     color:'var(--mt-dim)', overflow:'hidden' }
 * flex/maxWidth/min-width/display/gap stay inline. Class owns font-size +
 * color; mono composes. */
.manifold-renderer-donut-legend {
  font-size: 10px;
  color: var(--mt-dim);
}

/* Donut legend swatch box (small color square next to label). Pre-migration:
 *   { flex:'0 0 8px', width:8, height:8, background: s.color, borderRadius:1 }
 * flex/width/height stay inline. background per-slice via --m-renderer-color
 * SET PER SWATCH (preserves per-slice differentiation). borderRadius baked. */
.manifold-renderer-donut-swatch {
  background: var(--m-renderer-color, var(--mt-muted));
  border-radius: 1px;
}

/* Donut legend percent column. Pre-migration:
 *   { color:'var(--mt-muted)', fontVariantNumeric:'tabular-nums', flexShrink:0 } */
.manifold-renderer-donut-pct {
  color: var(--mt-muted);
}

/* ── StackedBarsTimeRenderer ─────────────────────────────────────────
 *
 * SVG-only chart; rect fills use the `fill` SVG attribute (not audited).
 * The only inline-style sites are the outer wrappers (padding). */

/* ── DistributionRenderer ────────────────────────────────────────────
 *
 * SVG-only chart; rect fills via SVG `fill` attribute. The only inline-
 * style site is the outer wrapper padding. */

/* ── SparklineAnomalyRenderer ────────────────────────────────────────
 *
 * Sparkline body uses SVG fill/stroke (not audited). Inline-style sites
 * are the header row (label + showValue numeric readout) and outer wrap.
 *
 * Header value-readout span. Pre-migration:
 *   { fontFamily:'"JetBrains Mono",monospace', fontSize:14, fontWeight:600,
 *     color: lineColor, fontVariantNumeric:'tabular-nums' }
 * Mono composes. Color flows through --m-renderer-color (lineColor today
 * is `var(--mt-accent)` baked in; routing through the prop means a
 * future per-card override is one line of JSX away). */
.manifold-renderer-sparkanom-val {
  font-size: 14px;
  font-weight: 600;
  color: var(--m-renderer-color, var(--mt-accent));
}

/* Sparkline-anomaly value-unit span. Pre-migration:
 *   { fontSize:10, color:'var(--mt-muted)', marginLeft:3 } */
.manifold-renderer-sparkanom-unit {
  font-size: 10px;
  color: var(--mt-muted);
  margin-left: 3px;
}

/* =========================================================================
 * Phase 19 Plan 06 — manifold.jsx dashboard-shell escape-hatch classes.
 *
 * Same authoring rules as 19-05a..g (visual primitives bundled; runtime
 * values flow through CSS custom properties; aesthetic values route
 * through --mt-* tokens). These classes back the shell migration: the
 * error-boundary fallback, modal-chrome (DesignHub / Users / AppliedCards
 * / ServiceListBuilder), tab-bar drag/rename affordances, the gear menu
 * + theme picker, the role/identity strip, the audit tab. Naming uses
 * `manifold-shell-*` so they're easy to scan as a family.
 * ========================================================================= */

/* ── Error-boundary fallback shell ───────────────────────────────────
 * The error boundary is special: it must paint even when the design
 * system has half-loaded. min-height:100vh keeps the fallback full-
 * viewport regardless of parent container collapse; monospace font is
 * deliberate (matches the diagnostic content). */
.manifold-error-boundary-root {
  min-height: 100vh;
  font-family: var(--m-font-mono, "JetBrains Mono", monospace);
}
.manifold-error-boundary-pre {
  white-space: pre-wrap;
  word-break: break-all;
  margin: 0;
}
.manifold-error-boundary-summary {
  cursor: pointer;
}
.manifold-error-boundary-hint {
  font-size: 10px;
}

/* ── TabBar — drag/rename/minRole affordances ────────────────────────
 * Drag-over visual: a 3px inset bar on the left edge using the page
 * accent (currentColor fallback for tabs whose colors are inherited).
 * data-dragover="true" replaces the inline `boxShadow: 'inset 3px 0 0
 * var(--m-accent, currentColor)'` spread the pre-migration JSX used.
 * Declarative selector beats imperative-spread because the DOM diff
 * is cleaner (an attribute flip vs a whole style-object swap). */
.manifold-tab[data-dragover="true"] {
  box-shadow: inset 3px 0 0 var(--m-accent, currentColor);
}
/* Inline rename-input chrome inside a tab cell. transparent bg +
 * currentColor border + color:inherit means the input picks up the
 * tab's text color (including the active-tab accent) so it visually
 * "becomes the tab label" while focused.  font:inherit pulls the
 * tab strip's font in so it matches the surrounding label perfectly. */
.manifold-tab-rename-input {
  background: transparent;
  border: 1px solid currentColor;
  border-radius: 3px;
  color: inherit;
  font: inherit;
  padding: 0 4px;
}
/* Minimum-role select chrome inside a tab cell — same color-inherit
 * posture as the rename input.  Uses the mt-border token so it skins
 * with the theme; rgba fallback covers the (rare) case where the var
 * isn't loaded yet at first paint. */
.manifold-tab-minrole-select {
  font-size: 10px;
  padding: 1px 2px;
  margin-left: 4px;
  background: transparent;
  color: inherit;
  border: 1px solid var(--mt-border, rgba(255, 255, 255, 0.2));
  border-radius: 2px;
  font-family: inherit;
}

/* ── Empty-tab blurb (EmptyOrAddCard "this tab is empty" copy) ───────
 * Block-centered narrow body text inside the empty-tab panel.  Pre-
 * migration sites passed maxWidth inline so callers could vary the
 * width (540 for the fresh-install Services greeting, 480 for the
 * generic empty-tab message).  margin:'0 auto' moved here so the
 * caller only owns the dimension knob. */
.manifold-empty-tab-blurb {
  margin: 0 auto;
}

/* ── GearMenu — theme picker row + drag-shortcuts footnote ───────────
 * Indented child rows under the Theme expandable.  28px indent is the
 * gear-menu's nested-item convention; outside the utility-class
 * spacing scale because it's a specific affordance for "this row sits
 * under a heading" not a generic spacing step. */
.manifold-gear-theme-row {
  padding-left: 28px;
}
/* Drag-shortcuts footnote block — appears inside the gear menu only
 * while tabEditMode is true.  Stacked tips with small dim text, tighter
 * vertical padding than a regular gear-menu row, opacity dimmed because
 * the block is informational, not actionable. */
.manifold-gear-drag-shortcuts {
  font-size: 10px;
  line-height: 1.5;
  opacity: 0.75;
  flex-direction: column;
  align-items: flex-start;
  padding-top: 6px;
  padding-bottom: 6px;
}
.manifold-gear-drag-shortcuts-title {
  font-weight: 600;
  margin-bottom: 2px;
}
/* <kbd> elements inside the drag-shortcuts block default to a system
 * monospace; font:inherit pulls in the gear menu's sans so the inline
 * key-pills don't visually clash with the body text. */
.manifold-gear-drag-shortcuts-kbd {
  font-family: inherit;
}

/* ── Preview-as bar (owner-only "browse as another role" chrome) ────
 * Sits above the header.  Idle state: transparent bg + muted gray
 * text on a hairline border (visually neutral, so it doesn't compete
 * for attention).  Active state (data-active="true"): cyan fill +
 * deep-canvas text + 2px cyan bottom rule, so the owner can't miss
 * that the dashboard is showing a non-real view.
 *
 * Hex values (cyan #5eead4 / deep #0f1418 / muted #94a3b8 / hairline
 * #2a2f36) are intentionally hardcoded — this is a diagnostic surface
 * that must read distinct from any theme's accent.  If Karl wants
 * per-theme preview accents later, re-tokenize to --m-preview-* and
 * override per-theme.
 *
 * The bar uses `display:flex` + `gap:10px` baked in; the only inline
 * keys remaining on the JSX are zIndex + position (both allowlisted
 * and behaviorally load-bearing).
 *
 * data-active flips the bar, the status span (font-weight bold) and
 * the select (cyan text-on-deep vs gray text-on-deep) all together. */
.manifold-preview-as-bar {
  padding: 6px 12px;
  background: transparent;
  color: #94a3b8;
  border-bottom: 1px solid #2a2f36;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.manifold-preview-as-bar[data-active="true"] {
  background: #5eead4;
  color: #0f1418;
  border-bottom: 2px solid #5eead4;
}
.manifold-preview-as-label {
  display: flex;
  align-items: center;
  gap: 6px;
}
.manifold-preview-as-status {
  opacity: 0.85;
  font-weight: 400;
}
.manifold-preview-as-status[data-active="true"] {
  font-weight: 700;
}
.manifold-preview-as-select {
  background: #0f1418;
  color: #e5e7eb;
  border: 1px solid #2a2f36;
  border-radius: 3px;
  padding: 2px 6px;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  cursor: pointer;
}
.manifold-preview-as-select[data-active="true"] {
  color: #5eead4;
  border-color: #0f1418;
}
.manifold-preview-as-exit-btn {
  background: #0f1418;
  color: #5eead4;
  border: 1px solid #0f1418;
  border-radius: 3px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 600;
  font-family: "JetBrains Mono", monospace;
  cursor: pointer;
  margin-left: auto;
}

/* ── Safe-mode banner padding override ───────────────────────────────
 * The default .manifold-banner uses --m-pad-md/lg.  Safe mode wants
 * tighter vertical + wider horizontal pad because it sits above the
 * regular header (which has its own page-frame horizontal pad).  This
 * variant lets the two stripes align without nesting selectors. */
.manifold-banner--safe-mode {
  padding: 8px 20px;
}

/* ── Shared app-modal shell (DesignHub / Users / AppliedCards /
 *    ServiceListBuilder) ─────────────────────────────────────────────
 * Four owner-facing modals in manifold.jsx all share the same chrome:
 * a fixed-position overlay backdrop, a centered card with deep-canvas
 * background and a hairline border, a header strip with brand-amber
 * title + slate-gray subtitle + ghost close-button, and a scrollable
 * body region.  Pre-migration each modal duplicated ~10 inline-style
 * blocks; this family collapses them into one named primitive set.
 *
 * Hex values (overlay rgba(8,12,18,0.78), deep #0f1418, hairline
 * #2a2f36, slate #94a3b8, brand-amber #f5a623, slate-dim #64748b,
 * #e6edf3 body fg) preserved exactly — these are app-shell colors,
 * intentionally distinct from per-theme accents to keep modals
 * readable across the four themes.
 *
 * Use the `.manifold-app-modal-card` wrapper instead of the inline
 * fixed-position div + nested onClick={stopPropagation} pattern.
 * The backdrop click-to-close stays on the JSX (it's a behavioral
 * concern, not a style concern). */
.manifold-app-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(8, 12, 18, 0.78);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "JetBrains Mono", monospace;
}
.manifold-app-modal-card {
  background: #0f1418;
  border: 1px solid #2a2f36;
  border-radius: 6px;
  max-height: 82vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
  color: #e6edf3;
}
.manifold-app-modal-header {
  padding: 14px 18px;
  border-bottom: 1px solid #2a2f36;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.manifold-app-modal-title {
  font-size: 14px;
  font-weight: 600;
  color: #f5a623;
}
.manifold-app-modal-subtitle {
  font-size: 10px;
  color: #64748b;
  margin-top: 2px;
}
.manifold-app-modal-close-btn {
  background: transparent;
  border: 1px solid #2a2f36;
  color: #94a3b8;
  font-family: inherit;
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 4px;
  cursor: pointer;
}
.manifold-app-modal-close-btn:hover {
  border-color: #f5a62388;
  color: #e6edf3;
}

/* DesignHub-specific tile grid + tile button.  The tile uses :hover
 * for the lift + accent-border + slight translate (replaces the
 * pre-migration onMouseEnter/Leave imperative style-mutation pattern;
 * same declarative-over-imperative posture as 19-05d's
 * .manifold-renderer-list-row hover).  data-disabled="true" swaps the
 * tile to a flat, non-interactive variant. */
.manifold-design-hub-grid {
  padding: 14px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  overflow-y: auto;
}
.manifold-design-hub-tile {
  text-align: left;
  background: #141a20;
  border: 1px solid #2a3540;
  border-radius: 5px;
  padding: 14px 16px;
  cursor: pointer;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-family: inherit;
  color: #e6edf3;
  transition: background 140ms, border-color 140ms, transform 140ms;
}
.manifold-design-hub-tile:hover:not([data-disabled="true"]) {
  background: #1a232c;
  border-color: #f5a62388;
  transform: translateY(-1px);
}
.manifold-design-hub-tile[data-disabled="true"] {
  background: #0c1014;
  border-color: #1a1f25;
  cursor: not-allowed;
  color: #3a4250;
}
.manifold-design-hub-tile-glyph {
  font-size: 22px;
  line-height: 24px;
  color: var(--m-tile-accent, #f5a623);
  flex: 0 0 28px;
}
.manifold-design-hub-tile[data-disabled="true"] .manifold-design-hub-tile-glyph {
  color: #3a4250;
}
.manifold-design-hub-tile-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.manifold-design-hub-tile-title {
  font-size: 12px;
  font-weight: 600;
}
.manifold-design-hub-tile-description {
  font-size: 10px;
  opacity: 0.72;
  line-height: 1.45;
  color: #94a3b8;
}
.manifold-design-hub-tile[data-disabled="true"] .manifold-design-hub-tile-description {
  color: #3a4250;
}

/* ── App-modal body + footer chrome (shared by Users / AppliedCards
 *    / ServiceListBuilder) ───────────────────────────────────────────
 * Generic scrollable body region under the header, and a small
 * footer strip with hairline-top + slate-dim text.  Symmetric with
 * the header class above. */
.manifold-app-modal-body {
  overflow: auto;
  padding: 12px 0;
}
.manifold-app-modal-footer {
  padding: 10px 18px;
  border-top: 1px solid #2a2f36;
  font-size: 10px;
  color: #64748b;
  line-height: 1.5;
}
.manifold-app-modal-loading,
.manifold-app-modal-empty {
  padding: 12px 18px;
  font-size: 11px;
  color: #64748b;
}
.manifold-app-modal-error {
  margin: 4px 18px 12px;
  padding: 8px 10px;
  border: 1px solid #b91c1c66;
  border-radius: 4px;
  background: #7f1d1d22;
  color: #fca5a5;
  font-size: 11px;
  line-height: 1.4;
}
.manifold-app-modal-error-hint {
  margin-top: 6px;
  opacity: 0.85;
}

/* ── CanvasSettingsModal — snap grid + grid-lines toggle ─────────────
 * Phase 43 DRAG-04 / DRAG-05. Reuses the app-modal shell; these classes
 * style the two settings rows. Theme tokens only (no aesthetic literals)
 * so it tracks whatever theme is active. */
.manifold-canvas-settings-row {
  padding: 12px 18px;
  border-bottom: 1px solid var(--mt-border, #2a2f36);
}
.manifold-canvas-settings-row:last-child {
  border-bottom: none;
}
.manifold-canvas-settings-label {
  font-size: var(--mt-text-sm-size, 13px);
  color: var(--mt-text, #e2e8f0);
  font-weight: 600;
}
.manifold-canvas-settings-help {
  margin: 4px 0 8px;
  font-size: var(--mt-text-xs-size, 11px);
  color: var(--mt-muted, #64748b);
  line-height: 1.5;
}
.manifold-canvas-settings-choices {
  display: flex;
  gap: 6px;
}
.manifold-canvas-settings-choice {
  flex: 1;
  padding: 7px 10px;
  border: 1px solid var(--mt-border, #2a2f36);
  border-radius: 6px;
  background: transparent;
  color: var(--mt-muted, #64748b);
  font-family: var(--m-font-mono);
  font-size: var(--mt-text-xs-size, 11px);
  cursor: pointer;
  transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
}
.manifold-canvas-settings-choice:hover {
  border-color: var(--mt-accent, #f59e0b);
  color: var(--mt-text, #e2e8f0);
}
.manifold-canvas-settings-choice[data-selected="true"] {
  border-color: var(--mt-accent, #f59e0b);
  color: var(--mt-accent, #f59e0b);
  background: color-mix(in srgb, var(--mt-accent, #f59e0b) 12%, transparent);
}
.manifold-canvas-settings-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}
.manifold-canvas-settings-toggle input {
  accent-color: var(--mt-accent, #f59e0b);
  cursor: pointer;
}

/* ── UsersModal table + role pills ───────────────────────────────────
 * Owner-only promote/demote table.  Reuses the app-modal shell above.
 * Per-role color flows through --m-role-color (different name than
 * --m-renderer-color to avoid cross-talk with the renderer family —
 * this is auth-domain not renderer-domain).  Set + promote buttons
 * use color-mix(40%) for the border tint (replaces ${rc}66). */
.manifold-users-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}
.manifold-users-table-head {
  color: #64748b;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.manifold-users-table-head th {
  padding: 6px 18px;
  text-align: left;
}
.manifold-users-table-head th[data-align="right"] {
  text-align: right;
}
.manifold-users-table-row {
  border-top: 1px solid #1c2228;
}
.manifold-users-table-row td {
  padding: 10px 18px;
}
.manifold-users-table-username {
  color: #e6edf3;
}
.manifold-users-table-groups {
  color: #94a3b8;
  font-size: 10px;
}
.manifold-users-table-actions {
  text-align: right;
  white-space: nowrap;
}
/* Role pill (slightly tighter padding than .manifold-auth-role-chip
 * because the table cell has its own row-padding and a wider pill
 * would crowd the column).  Per-role color via --m-role-color. */
.manifold-users-role-pill {
  color: var(--m-role-color, #64748b);
  border: 1px solid color-mix(in srgb, var(--m-role-color, #64748b) 33%, transparent);
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}
.manifold-users-singleton-marker {
  color: #64748b;
  font-size: 10px;
}
.manifold-users-flash {
  font-size: 10px;
}
.manifold-users-flash[data-ok="true"] { color: #22c55e; }
.manifold-users-flash[data-ok="false"] { color: #ef4444; }
.manifold-users-actions-group {
  display: inline-flex;
  gap: 4px;
}
/* Per-role set button.  Idle: target role color + 40% border tint.
 * Current (already this role): muted hairline border, slate text,
 * cursor:default.  Pending (other-row mid-action): opacity dim.
 * Reuses --m-role-color the same way the pill does. */
.manifold-users-set-btn {
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--m-role-color, #64748b) 40%, transparent);
  color: var(--m-role-color, #64748b);
  font-family: inherit;
  font-size: 10px;
  padding: 2px 6px;
  border-radius: 3px;
  cursor: pointer;
}
.manifold-users-set-btn[data-current="true"],
.manifold-users-set-btn:disabled[data-current="true"] {
  border-color: #2a2f36;
  color: #64748b;
  cursor: default;
}
.manifold-users-set-btn:disabled:not([data-current="true"]) {
  opacity: 0.5;
}

/* ── AppliedCardsModal — 3-level audit table (cards → widgets → verbs) ─
 * Reuses the OLD .manifold-modal shell (not the .manifold-app-modal-*
 * family); the modal is older and predates the consolidated app-modal
 * chrome.  Phase 19's job here is the table family only.
 *
 * Tables nest 3 levels deep: outer cards table → per-card widgets
 * sub-table → per-widget verbs sub-table.  Each level uses the same
 * column padding rhythm (6/8/4 px) with progressive opacity reduction
 * so the nesting reads visually.
 *
 * Per-level base class lets a future Phase re-skin a single level
 * (e.g. "make the verbs row tighter on phones") without touching JSX. */
.manifold-applied-intro {
  font-size: 12px;
  opacity: 0.7;
  margin-bottom: 12px;
  line-height: 1.5;
  font-family: "JetBrains Mono", monospace;
}
.manifold-applied-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  font-family: "JetBrains Mono", monospace;
}
.manifold-applied-table-head {
  text-align: left;
  border-bottom: 1px solid var(--m-border, #444);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.6;
}
.manifold-applied-table-head th {
  padding: 6px 8px;
}
.manifold-applied-table-head th[data-narrow="caret"]  { padding: 6px 4px; width: 24px; }
.manifold-applied-table-head th[data-narrow="role"]   { padding: 6px 8px; width: 100px; text-align: center; }
.manifold-applied-card-row td {
  padding: 8px;
  vertical-align: top;
}
.manifold-applied-card-row td[data-cell="caret"]   { padding: 8px 4px; text-align: center; }
.manifold-applied-card-row td[data-cell="centered"] { padding: 8px; text-align: center; }
.manifold-applied-card-row[data-busy="true"]      { opacity: 0.5; }
.manifold-applied-card-row[data-open-below="true"] td { border-bottom: none; }
.manifold-applied-card-row:not([data-open-below="true"]) td {
  border-bottom: 1px solid var(--m-border-soft, rgba(255, 255, 255, 0.05));
}
/* Caret button — disclosure arrow inside the leftmost column. */
.manifold-applied-caret-btn {
  background: transparent;
  border: none;
  color: inherit;
  cursor: pointer;
  font-size: 12px;
  padding: 0;
  line-height: 1;
  font-family: "JetBrains Mono", monospace;
}
.manifold-applied-card-name {
  font-weight: 600;
}
.manifold-applied-card-sub {
  font-size: 10px;
  opacity: 0.5;
}
.manifold-applied-card-where {
  opacity: 0.85;
}
/* Min-role <select> chrome.  Reuses the --mt-border token to track
 * theme switches.  color-scheme:dark + explicit option chrome together
 * fix the white-on-white native-popup bug: without these, Chrome and
 * Firefox draw the <option> list against the OS-native light surface
 * regardless of the page colors, leaving the dropdown unreadable on a
 * dark dashboard. */
.manifold-applied-minrole-select {
  font-size: 11px;
  padding: 2px 4px;
  font-family: inherit;
  background: var(--mt-bg-elev, var(--mt-bg, #15181d));
  color: var(--mt-fg, inherit);
  border: 1px solid var(--mt-border, rgba(255, 255, 255, 0.2));
  border-radius: 2px;
  color-scheme: dark;
}
.manifold-applied-minrole-select option {
  background: var(--mt-bg-elev, var(--mt-bg, #15181d));
  color: var(--mt-fg, #e8e6e3);
}
/* Expanded widgets sub-row (level 2). */
.manifold-applied-widgets-cell {
  padding: 0 8px 12px 30px;
  border-bottom: 1px solid var(--m-border-soft, rgba(255, 255, 255, 0.05));
}
.manifold-applied-widgets-empty {
  font-size: 11px;
  opacity: 0.55;
  font-style: italic;
}
.manifold-applied-widgets-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
}
.manifold-applied-widgets-table-head {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.5;
  border-bottom: 1px solid var(--m-border-soft, rgba(255, 255, 255, 0.04));
}
.manifold-applied-widgets-table-head th {
  text-align: left;
  padding: 4px 8px;
}
.manifold-applied-widgets-table-head th[data-narrow="renderer"] { width: 130px; }
.manifold-applied-widgets-table-head th[data-narrow="audit"]    { text-align: center; width: 70px; }
.manifold-applied-widget-row td {
  padding: 4px 8px;
}
.manifold-applied-widget-row td[data-cell="renderer"]  { opacity: 0.7; }
.manifold-applied-widget-row td[data-cell="centered"]  { text-align: center; }
.manifold-applied-widget-row[data-busy="true"]         { opacity: 0.5; }
.manifold-applied-widget-id {
  font-size: 9px;
  opacity: 0.45;
  margin-left: 8px;
}
.manifold-applied-widget-noaudit-marker {
  opacity: 0.35;
}
/* Caret button inside the widget row (smaller than the card-row caret). */
.manifold-applied-widget-caret-btn {
  background: transparent;
  border: none;
  color: inherit;
  cursor: pointer;
  font-size: 11px;
  padding: 0;
  margin-right: 6px;
  line-height: 1;
  font-family: "JetBrains Mono", monospace;
}
/* Expanded verbs sub-row (level 3). */
.manifold-applied-verbs-row {
  background: rgba(255, 255, 255, 0.02);
}
.manifold-applied-verbs-cell {
  padding: 6px 8px 10px 28px;
}
.manifold-applied-verbs-intro {
  font-size: 10px;
  opacity: 0.55;
  margin-bottom: 6px;
  line-height: 1.5;
}
.manifold-applied-verbs-empty {
  font-size: 11px;
  opacity: 0.55;
  font-style: italic;
}
.manifold-applied-verbs-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
}
.manifold-applied-verbs-table-head {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.5;
}
.manifold-applied-verbs-table-head th {
  text-align: left;
  padding: 3px 8px;
}
.manifold-applied-verbs-table-head th[data-cell="centered-60"] { text-align: center; padding: 3px 8px; width: 60px; }
.manifold-applied-verbs-table-head th[data-cell="centered-50"] { text-align: center; padding: 3px 8px; width: 50px; }
.manifold-applied-verbs-row-data {
}
.manifold-applied-verbs-row-data[data-busy="true"] { opacity: 0.5; }
.manifold-applied-verbs-row-data td {
  padding: 3px 8px;
}
.manifold-applied-verbs-row-data td[data-cell="verb-name"] {
  font-family: "JetBrains Mono", monospace;
}
.manifold-applied-verbs-row-data td[data-cell="centered"] {
  text-align: center;
}
.manifold-applied-verbs-inherit-marker {
  margin-left: 6px;
  opacity: 0.45;
  font-size: 9px;
}

/* ── ServiceListBuilderModal — service-card-builder form ─────────────
 * Builder form for "auto-iterate every entry in /admin/services."  Two
 * style modes (placards / table) toggled via radio cards; table mode
 * exposes column checkboxes + framing knobs + zebra options.
 *
 * Reuses the OLDER .manifold-modal-* shell (same as AppliedCardsModal).
 *
 * Three repeating visual primitives that the JSX used to pass via two
 * inline-style constants (sectionLabelStyle + cbRow's label-style):
 *
 *   .manifold-slb-section-label  - 10px bold uppercase tracker (a
 *                                  visual divider between form
 *                                  groups).  Used ~6 times.
 *   .manifold-slb-cb-row         - 12px mono row with checkbox + label
 *                                  + optional hint.  Used ~10 times.
 *   .manifold-slb-cb-hint        - small dim hint inside a cb-row.
 *
 * Plus a few one-off primitives:
 *   .manifold-slb-intro          - body intro paragraph
 *   .manifold-slb-style-row      - flex container for the two style cards
 *   .manifold-slb-style-card     - one of the two style-mode toggles;
 *                                  data-active="true" swaps to the accent
 *                                  border + tinted bg
 *   .manifold-slb-col-grid       - 2-col checkbox grid for columns
 *   .manifold-slb-zebra-grid     - 2-col grid for even/odd color inputs
 *   .manifold-slb-zebra-hint     - full-width hint under the zebra inputs
 *   .manifold-slb-range-row      - container for a label + range input
 *   .manifold-slb-range-label    - small label above a range input
 *   .manifold-slb-actions-row    - right-aligned button group at the bottom
 */
.manifold-slb-section-label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.6;
  margin-top: 14px;
  margin-bottom: 6px;
  font-family: "JetBrains Mono", monospace;
}
.manifold-slb-cb-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.4;
  font-family: "JetBrains Mono", monospace;
  cursor: pointer;
}
.manifold-slb-cb-row-checkbox {
  margin-top: 2px;
}
.manifold-slb-cb-hint {
  display: block;
  font-size: 10px;
  opacity: 0.55;
  margin-top: 2px;
}
.manifold-slb-intro {
  font-size: 12px;
  opacity: 0.7;
  margin-bottom: 4px;
  line-height: 1.45;
  font-family: "JetBrains Mono", monospace;
}
.manifold-slb-intro-code {
  margin-left: 4px;
}
.manifold-slb-style-row {
  display: flex;
  gap: 8px;
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
}
.manifold-slb-style-card {
  flex: 1;
  padding: 10px 12px;
  border: 1px solid var(--manifold-border, #333);
  border-radius: 6px;
  background: transparent;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  transition: border-color 0.15s, background 0.15s;
}
.manifold-slb-style-card[data-active="true"] {
  border-color: var(--manifold-accent, #5d9cec);
  background: rgba(93, 156, 236, 0.10);
}
.manifold-slb-style-card-header {
  display: flex;
  align-items: center;
  gap: 8px;
}
.manifold-slb-style-card-title {
  font-weight: 600;
}
.manifold-slb-style-card-hint {
  font-size: 10px;
  opacity: 0.6;
  margin-left: 22px;
}
.manifold-slb-col-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
}
.manifold-slb-col-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-family: "JetBrains Mono", monospace;
  cursor: pointer;
}
.manifold-slb-range-row {
  margin-top: 8px;
  margin-left: 22px;
}
.manifold-slb-range-row--top {
  margin-top: 10px;
}
.manifold-slb-range-label {
  font-size: 11px;
  margin-bottom: 4px;
  font-family: "JetBrains Mono", monospace;
  opacity: 0.7;
}
.manifold-slb-zebra-grid {
  margin-top: 8px;
  margin-left: 22px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.manifold-slb-zebra-hint {
  grid-column: 1 / -1;
  font-size: 10px;
  opacity: 0.55;
  line-height: 1.4;
  font-family: "JetBrains Mono", monospace;
}
.manifold-slb-error-line {
  margin-top: 12px;
}
.manifold-slb-actions-row {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 18px;
}

/* ── GearAuthState — identity/role/sign-in/sign-out block ────────────
 * Lives at the bottom of the gear menu's About slot.  Two branches
 * share an identical outer wrapper (padding, mono font, column flex,
 * gap) but differ in body color (anonymous = muted gray, signed-in =
 * bright white-on-deep).  data-variant attribute swaps the color.
 *
 * Hex values (slate #94a3b8 anonymous body, #e6edf3 signed-in body,
 * warn #b8554d border + #d2945e text for sign-out, role-pill family
 * cyan/orange/violet/slate) preserved exactly per the same posture
 * as the preview-as bar — gear-menu identity chrome reads distinct
 * from theme accents on purpose.
 *
 * The role chip + sign-in button both reuse --m-renderer-color (the
 * cross-renderer per-instance color carrier from 19-05) so the JSX
 * sets ONE custom property and both border + text on the chip pick
 * it up via color-mix(33%) — same shape as .manifold-renderer-pill
 * (19-05d) but with a square 3px radius instead of the rounded
 * 9999px pill, because the gear menu's vertical-axis budget reads
 * better with a chip than a pill. */
.manifold-gear-auth-state {
  padding: 6px 14px 10px;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  color: #e6edf3;
}
.manifold-gear-auth-state[data-variant="anonymous"] {
  color: #94a3b8;
}
.manifold-gear-auth-anon-msg {
  opacity: 0.75;
  line-height: 1.4;
}
.manifold-gear-auth-signin-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--m-renderer-color, #64748b) 33%, transparent);
  color: #e6edf3;
  border-radius: 4px;
  font-family: inherit;
  font-size: 11px;
  text-decoration: none;
  cursor: pointer;
  align-self: flex-start;
}
.manifold-gear-auth-userrow {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.manifold-auth-role-chip {
  color: var(--m-renderer-color, #64748b);
  border: 1px solid color-mix(in srgb, var(--m-renderer-color, #64748b) 33%, transparent);
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}
.manifold-gear-auth-signout-btn {
  align-self: flex-start;
  padding: 4px 10px;
  background: transparent;
  border: 1px solid color-mix(in srgb, #b8554d 33%, transparent);
  color: #d2945e;
  border-radius: 4px;
  font-family: inherit;
  font-size: 11px;
  cursor: pointer;
}
.manifold-gear-auth-footer {
  margin-top: 4px;
  font-size: 10px;
  opacity: 0.5;
  line-height: 1.5;
}
/* Anonymous branch's footer needs slightly more top margin because the
 * sign-in button above it has more visual weight than the sign-out
 * button in the signed-in branch.  Variant-scoped override. */
.manifold-gear-auth-state[data-variant="anonymous"] .manifold-gear-auth-footer {
  margin-top: 6px;
}

/* ── Header-loading placeholder ──────────────────────────────────────
 * Renders only during the brief window when the user's saved header
 * card hasn't returned from the backend yet.  Asymmetric padding
 * (12 vertical / 18 horizontal) matches the header's page-frame pad
 * so the placeholder doesn't visually "jump" when the real card
 * arrives.  Outside the utility-class spacing scale. */
.manifold-header-loading {
  padding: 12px 18px;
}

/* ── AuditTabRenderer — owner-only binding-drift diagnostic page ─────
 * Single-column max-width page wrapper.  margin:'0 auto' is the
 * load-bearing centering; max-width stays inline (dimension key) so
 * the caller can vary the column width if a future audit grows.
 * The refresh button and the bordered data panel use their own
 * escape-hatch classes (below) so the page can be re-themed as one
 * unit without touching JSX. */
.manifold-audit-tab-root {
  margin: 0 auto;
}
.manifold-audit-tab-title {
  font-size: 14px;
}
/* Ghost refresh button — same posture as a Manifold modal's secondary
 * action: bordered, theme-bg, no fill.  Hover swaps to the slightly
 * elevated surface to give a visible affordance. */
.manifold-audit-tab-refresh-btn {
  padding: 3px 10px;
  cursor: pointer;
}
.manifold-audit-tab-refresh-btn:hover:not(:disabled) {
  background: var(--mt-bg-elev);
}
/* Bordered panel that wraps the BindingDriftTable.  overflow:hidden
 * is mandatory: without it the table's first/last-row corners punch
 * through the panel's rounded radius. */
.manifold-audit-tab-panel {
  overflow: hidden;
}

/* =========================================================================
 * Health-of-dependencies modal (gear → Health) + status dot on the gear icon.
 * ========================================================================= */

.manifold-gear-status-dot {
  position: absolute;
  top: 6px; right: 6px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--m-error, #b85050);
  box-shadow: 0 0 0 2px var(--m-bg-deep, #0d0f12);
  pointer-events: none;
}
.manifold-h-gear { position: relative; }   /* anchor the dot */

.manifold-health-overall {
  padding: var(--m-pad-md);
  border-radius: var(--m-radius-md);
  font-family: var(--m-font-mono);
  font-size: 12px;
  margin-bottom: var(--m-pad-md);
}
.manifold-health-overall--ok {
  background: color-mix(in srgb, var(--m-success, #4caf50) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--m-success, #4caf50) 35%, transparent);
  color: var(--m-success, #4caf50);
}
.manifold-health-overall--bad {
  background: color-mix(in srgb, var(--m-warn, #f0a040) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--m-warn, #f0a040) 35%, transparent);
  color: var(--m-warn, #f0a040);
}
.manifold-health-fetch-err {
  font-size: 10px; color: var(--m-error, #b85050); margin-top: 4px;
  font-family: var(--m-font-mono);
}

.manifold-health-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.manifold-health-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--m-pad-sm);
  padding: 6px 10px;
  background: var(--m-surface);
  border: 1px solid var(--m-border);
  border-radius: var(--m-radius-sm);
}
.manifold-health-row-name {
  font-family: var(--m-font-sans);
  font-size: 13px;
  color: var(--m-text);
}
.manifold-health-row-id {
  font-family: var(--m-font-mono);
  font-size: 10px;
  color: var(--m-text-faint);
  margin-left: 6px;
}

.manifold-health-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px;
  border-radius: 999px;
  font-family: var(--m-font-mono);
  font-size: 10px;
  white-space: nowrap;
}
.manifold-health-pill-dot {
  width: 8px; height: 8px; border-radius: 50%;
  flex-shrink: 0;
}
.manifold-health-pill--ok {
  background: color-mix(in srgb, var(--m-success, #4caf50) 18%, transparent);
  color: var(--m-success, #4caf50);
}
.manifold-health-pill--ok .manifold-health-pill-dot { background: var(--m-success, #4caf50); }
.manifold-health-pill--bad {
  background: color-mix(in srgb, var(--m-error, #b85050) 18%, transparent);
  color: var(--m-error, #b85050);
}
.manifold-health-pill--bad .manifold-health-pill-dot { background: var(--m-error, #b85050); }
.manifold-health-pill--critical {
  outline: 1px solid color-mix(in srgb, currentColor 50%, transparent);
}
.manifold-health-pill-flag {
  font-size: 8px;
  letter-spacing: 0.08em;
  font-weight: 700;
  opacity: 0.7;
}

.manifold-health-loading {
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--m-text-muted);
  padding: var(--m-pad-md) 0;
}
.manifold-health-foot {
  margin-top: var(--m-pad-md);
  font-family: var(--m-font-mono);
  font-size: 9px;
  color: var(--m-text-faint);
  text-align: right;
}

/* =========================================================================
 * Card-bundle import picker
 * Modal that walks the user through binding each portable-card source
 * (capability + metric) to a local instance. Outcome marker is what
 * differentiates rows: ✓ (auto-bound), ⚠ (needs pick), ✗ (skipped).
 * ========================================================================= */

.manifold-bundle-subtitle {
  padding: 0 var(--m-pad-lg) var(--m-pad-sm);
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--m-text-muted);
  border-bottom: 1px solid var(--m-border);
}

.manifold-bundle-targetrow {
  display: flex; align-items: center; gap: var(--m-pad-sm);
  padding-bottom: var(--m-pad-sm);
}

.manifold-bundle-targetrow label {
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--m-text-muted);
}

.manifold-bundle-targetrow select,
.manifold-bundle-card select {
  background: var(--m-surface);
  border: 1px solid var(--m-border);
  color: var(--m-text);
  font-family: var(--m-font-mono);
  font-size: 11px;
  padding: 4px 8px;
  border-radius: var(--m-radius-sm);
}

.manifold-bundle-bulkrow {
  display: flex; align-items: center; gap: var(--m-pad-sm); flex-wrap: wrap;
  padding-bottom: var(--m-pad-sm);
  border-bottom: 1px dashed var(--m-border);
  margin-bottom: var(--m-pad-sm);
}

.manifold-bundle-bulkrow > span {
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--m-text-muted);
}

.manifold-bundle-cardlist {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}

.manifold-bundle-card {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  gap: var(--m-pad-sm);
  align-items: center;
  padding: 8px 12px;
  background: var(--m-surface);
  border: 1px solid var(--m-border);
  border-radius: var(--m-radius-sm);
  font-family: var(--m-font-sans);
  font-size: 13px;
}

.manifold-bundle-card--ok           { border-left: 3px solid var(--m-success, #4caf50); }
.manifold-bundle-card--prompt_needed { border-left: 3px solid var(--m-warn, #f0a040); }
.manifold-bundle-card--unmet_dep,
.manifold-bundle-card--metric_missing,
.manifold-bundle-card--instance_missing,
.manifold-bundle-card--version_mismatch {
  border-left: 3px solid var(--m-error, #b85050);
  opacity: 0.7;
}

.manifold-bundle-marker {
  font-family: var(--m-font-mono);
  font-size: 14px;
  width: 18px; text-align: center;
}

.manifold-bundle-cardtitle {
  color: var(--m-text);
}

.manifold-bundle-cardmeta {
  font-family: var(--m-font-mono);
  font-size: 10px;
  color: var(--m-text-faint);
  white-space: nowrap;
}

.manifold-bundle-bound {
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--m-text-muted);
  white-space: nowrap;
}

.manifold-bundle-detail {
  font-family: var(--m-font-mono);
  font-size: 10px;
  color: var(--m-text-faint);
  max-width: 240px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.manifold-bundle-error {
  margin-top: var(--m-pad-sm);
  padding: var(--m-pad-sm);
  border: 1px solid var(--m-error, #b85050);
  border-radius: var(--m-radius-sm);
  color: var(--m-error, #b85050);
  font-family: var(--m-font-mono);
  font-size: 11px;
}

/* =========================================================================
 * Phase 19 Plan 07 — card-wizard.jsx escape-hatch classes.
 *
 * The card-creation wizard (Tier 1 of the three card-editing surfaces)
 * walks the user through recipe → data → placement → tune → review. It
 * was the densest remaining inline-style file at the start of Phase 19
 * Plan 07 — 302 FORBIDDEN_KEYS sites across 5 named Step components plus
 * shared preview-pane + modal-frame chrome.
 *
 * Authoring rules carry over from 19-05/06: visual primitives bundled
 * into one class when they always co-occur (the wizard's Step-tag /
 * step-title / step-subtitle trio always reads together as a section
 * header, so they're three classes that compose, not 12 utility
 * classes). Runtime values (recipe-tile selected/unselected, size
 * stepper hover) route through CSS custom properties (`--m-wizard-*`)
 * or `data-*` attribute selectors so the JSX stays declarative.
 *
 * Why a dedicated section rather than utility-class composition: the
 * wizard's chrome reads as one coherent surface — the recipe tiles,
 * step indicator strip, preview pane, and modal frame are all SHAPED
 * by the wizard's UI-SPEC, not by ad-hoc placement of generic
 * utilities. Naming uses `manifold-wizard-*` so they scan as a
 * family in `git grep` and a future plan could swap the wizard's
 * visual posture by editing this block only.
 *
 * The 5 named Step components stay at module scope per
 * `project_manifold_wizard_step_components` — only their className
 * attributes changed; component identity is preserved across the
 * migration (Task 1 + Task 2 name-exact grep verification).
 * ========================================================================= */

/* ── Step-section header trio ───────────────────────────────────────
 * The "Step N of 5 / Big title / Small subtitle" header that opens
 * every step. The three classes always compose in this order on
 * three sibling <div>s — splitting keeps each line's typography
 * tunable without forcing all three to move together. */

.manifold-wizard-sublabel {
  /* Mirrors the `styles.subLabel(t)` shape — small uppercase mono
     label that styles.subLabel produces. Pre-migration this object
     was spread via `{...sub, ...}` into ~25 inline-style sites; the
     class composes on a className attribute instead so utility-class
     overrides above (mt-text-accent etc.) can flow without inline
     specificity wins. */
  font-family: var(--m-font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--mt-muted);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.manifold-wizard-step-tag {
  /* "Step N of 5" tag — same base shape as .manifold-wizard-sublabel
     but with the accent color override baked in (replaces the
     `{...sub, color:'var(--mt-accent)'}` repetition). Sits at the
     top of every step's header trio. */
  font-family: var(--m-font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--mt-accent);
  letter-spacing: 0.4px;
  text-transform: uppercase;
  margin-bottom: 4px;
}

.manifold-wizard-step-title {
  /* Big display-serif step title — "What are you building?",
     "Pick the data", "Where it lives", "Tune the basics", "Review".
     One shape across all 5 steps. */
  font-family: var(--m-font-display);
  font-size: 18px;
  color: var(--mt-fg);
  letter-spacing: 0.04em;
}

.manifold-wizard-step-subtitle {
  /* Body paragraph under the step title — explains what this step
     does in plain language. Reads loosely (lineHeight 1.5) and in
     the dim foreground tone. */
  font-family: var(--m-font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--mt-dim);
  letter-spacing: 0.04em;
  margin-top: 6px;
  text-transform: none;
  line-height: 1.5;
}

.manifold-wizard-step-summary {
  /* "Looking at: <recipe>" affordance under the recipe grid in Step 1.
     Same shape as the subtitle but with accent color (the user just
     picked a recipe — read it back). */
  font-family: var(--m-font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--mt-accent);
  letter-spacing: 0.04em;
  margin-top: 4px;
  text-transform: none;
  line-height: 1.5;
}

/* ── Step container + standard layout primitives ────────────────────
 * The outer flex column every step body wraps itself in. Same
 * padding / gap across StepRecipe / StepPlacement / StepTune /
 * StepReview (StepData uses a slightly different grid shape — see
 * .manifold-wizard-stepdata-container below). */

.manifold-wizard-step-container {
  padding: 16px 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.manifold-wizard-stepdata-container {
  /* StepData uses a 2-row grid (top = description; bottom = picker)
     so the LeafPicker fills the remaining height. The 24px-top
     padding flavor (for the fallback when CB.LeafPicker hasn't
     loaded yet) reads differently — see .manifold-wizard-stepdata-fallback. */
  padding: 16px 22px 0 22px;
  display: grid;
  grid-template-rows: auto 1fr;
  min-height: 0;
  gap: 10px;
  height: 100%;
}

.manifold-wizard-stepdata-fallback {
  /* LeafPicker-not-loaded fallback — shows "try a hard refresh."
     Distinct padding from the main StepData container so the
     missing-Picker state reads as a quiet column rather than the
     full picker frame. */
  padding: 24px 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.manifold-wizard-stepdata-picker-frame {
  /* The frame around the LeafPicker — hairline border, hidden
     overflow, sits at the bottom of the StepData grid. */
  min-height: 0;
  border: 1px solid var(--mt-border);
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.manifold-wizard-parameter-stack {
  /* The parameter-picker stack that appears under each parameterized
     leaf inside StepData (Plan 10-02 inline parameters). Indented 12px
     so it reads as nested under the picker. */
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 6px;
  margin-left: 12px;
}

/* ── Recipe tile grid (Step 1) ──────────────────────────────────────
 * The recipe-picker tile grid + per-tile button + per-tile typography.
 * Selected state flows through `data-selected="true"` so the JSX
 * doesn't have to ternary the className. The selected/unselected
 * variants of bg and border use color-mix on --mt-accent so they
 * re-skin with theme switches automatically. */

.manifold-wizard-recipe-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 12px;
  margin-top: 6px;
}

.manifold-wizard-recipe-tile {
  padding: 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
  text-align: left;
  cursor: pointer;
  background: var(--mt-bg-deep);
  border: 1px solid var(--mt-border);
  border-radius: 4px;
  transition: background 120ms linear, border-color 120ms linear;
}
.manifold-wizard-recipe-tile[data-selected="true"] {
  background: color-mix(in srgb, var(--mt-accent) 13%, transparent);
  border-color: color-mix(in srgb, var(--mt-accent) 60%, transparent);
}

.manifold-wizard-recipe-glyph {
  font-family: var(--m-font-mono);
  font-size: 18px;
  color: var(--mt-dim);
}
.manifold-wizard-recipe-tile[data-selected="true"] .manifold-wizard-recipe-glyph {
  color: var(--mt-accent);
}

.manifold-wizard-recipe-label {
  font-family: var(--m-font-display);
  font-size: 13px;
  font-weight: 600;
  color: var(--mt-dim);
  letter-spacing: 0.02em;
}
.manifold-wizard-recipe-tile[data-selected="true"] .manifold-wizard-recipe-label {
  color: var(--mt-fg);
}

.manifold-wizard-recipe-hint {
  font-family: var(--m-font-mono);
  font-size: 10px;
  line-height: 1.5;
  color: var(--mt-muted);
}

.manifold-wizard-recipe-bold {
  /* Inline-emphasis pattern inside the "Looking at: X — hint" summary. */
  color: var(--mt-fg);
}

/* ── Placement step (Step 3) ────────────────────────────────────────
 * Tab list + section list panes, size stepper controls, plus the
 * "Pick a tab" / "Section in X" sublabels. */

.manifold-wizard-placement-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  min-height: 0;
}

.manifold-wizard-placement-column {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.manifold-wizard-placement-column-label {
  font-family: var(--m-font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--mt-muted);
  letter-spacing: 0.4px;
  text-transform: uppercase;
  margin-bottom: 2px;
}

.manifold-wizard-list-pane {
  /* Scrollable list of selectable rows (tabs or sections). Used twice
     in StepPlacement and once for the placement size row layout. */
  display: flex;
  flex-direction: column;
  gap: 4px;
  border: 1px solid var(--mt-border);
  border-radius: 4px;
  padding: 6px;
  background: var(--mt-bg-deep);
  max-height: 240px;
  overflow-y: auto;
}

.manifold-wizard-list-empty {
  /* Empty-state row inside .manifold-wizard-list-pane — "No tabs yet",
     "Pick a tab", "loading…", "No sections". */
  font-family: var(--m-font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--mt-muted);
  letter-spacing: 0.04em;
  text-transform: none;
  padding: 8px 10px;
}

.manifold-wizard-list-row-flex {
  /* `flex:1` middle slot inside a list-row button so the trailing
     id/count chip pushes to the right. */
  flex: 1;
}

.manifold-wizard-list-row-tag {
  /* The small uppercase id / card-count chip after the row label. */
  font-family: var(--m-font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--mt-muted);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.manifold-wizard-size-row {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: 4px;
}

.manifold-wizard-size-group {
  display: flex;
  align-items: center;
  gap: 6px;
}

.manifold-wizard-size-axis-label {
  font-family: var(--m-font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--mt-muted);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.manifold-wizard-size-value {
  font-family: var(--m-font-mono);
  font-size: 13px;
  color: var(--mt-fg);
  min-width: 18px;
  text-align: center;
}

.manifold-wizard-size-times {
  font-family: var(--m-font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--mt-muted);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.manifold-wizard-size-units {
  font-family: var(--m-font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--mt-muted);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.manifold-wizard-stepper-btn {
  /* Size +/- buttons. Small square; reads as a stepper unit. */
  width: 22px;
  height: 22px;
  padding: 0;
  background: transparent;
  color: var(--mt-dim);
  border: 1px solid var(--mt-border);
  border-radius: 3px;
  font-family: var(--m-font-mono);
  font-size: 14px;
  cursor: pointer;
}

/* ── Tune step (Step 4) ─────────────────────────────────────────────
 * Field column + per-field label/hint pair. */

.manifold-wizard-form-column {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 480px;
}

.manifold-wizard-field-hint {
  /* The grey hint paragraph under each input — "Used in the card
     library and the card's frame header". 10px (below the smallest
     mt-text-xs utility-class size) is intentional; reads as
     incidental annotation. */
  font-family: var(--m-font-mono);
  font-size: 10px;
  font-weight: 500;
  color: var(--mt-muted);
  letter-spacing: 0.04em;
  margin-top: 4px;
  text-transform: none;
  line-height: 1.5;
}

.manifold-wizard-field-input-fallback {
  /* Fallback for styles.fieldInput when CardBuilder hasn't published
     its shared input style — production load always wins via the
     spread before this fallback is evaluated, but the test harness /
     partial-load case needs this. */
  width: 100%;
  padding: 5px 7px;
  font-family: var(--m-font-mono);
  font-size: 11px;
  background: var(--mt-bg);
  color: var(--mt-fg);
  border: 1px solid var(--mt-border);
  border-radius: 4px;
}

.manifold-wizard-field-label {
  /* Per-field "Card name" / "Widget label" header above each input. */
  font-family: var(--m-font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--mt-muted);
  letter-spacing: 0.4px;
  text-transform: uppercase;
  margin-bottom: 4px;
}

/* ── Review step (Step 5) ───────────────────────────────────────────
 * The two-column summary grid that reads back every choice. */

.manifold-wizard-review-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 8px 18px;
  padding: 14px 16px;
  background: var(--mt-bg-deep);
  border: 1px solid var(--mt-border);
  border-radius: 4px;
}

.manifold-wizard-review-key {
  font-family: var(--m-font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--mt-muted);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.manifold-wizard-review-value {
  font-family: var(--m-font-mono);
  font-size: 12px;
  color: var(--mt-fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Preview pane chrome ────────────────────────────────────────────
 * The right-side pane that follows the user through all 5 steps.
 * Outer pane + chrome (title + step indicator + separator) + body
 * variants (recipe-hint card, data preview, in-progress card render,
 * placeholder). */

.manifold-wizard-preview-pane {
  /* Pre-Plan-07 the className was set but inline `style={{width, height,
     minHeight, display, ...}}` overrode it; now the class carries the
     full primitive so it can re-skin with theme switches. */
  width: 100%;
  height: 100%;
  min-height: 280px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px 14px;
  background: var(--mt-bg);
  box-sizing: border-box;
}

.manifold-wizard-preview-chrome {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--mt-border);
}

.manifold-wizard-preview-chrome-title {
  font-family: var(--m-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4em;
  color: var(--mt-fg);
  text-transform: uppercase;
}

.manifold-wizard-preview-chrome-step {
  font-family: var(--m-font-mono);
  font-size: 10px;
  color: var(--mt-muted);
  font-variant-numeric: tabular-nums;
}

.manifold-wizard-preview-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.manifold-wizard-preview-recipe-wrap {
  /* Step 1 — recipe pane body: pushes the recipe-hint card to the
     bottom of the pane (top half intentionally empty per UI-SPEC). */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  flex: 1;
}

.manifold-wizard-preview-recipe-card {
  background: var(--mt-bg-elev);
  border: 1px solid var(--mt-border);
  border-radius: 4px;
  padding: 14px;
}

.manifold-wizard-preview-recipe-hint {
  font-family: var(--m-font-display);
  font-size: 12px;
  color: var(--mt-fg);
  line-height: 1.5;
}

.manifold-wizard-hint-placeholder {
  /* Italic muted placeholder text — "Pick a recipe to see what it builds",
     "Hover a leaf to preview", "Preview will build as you fill fields". */
  font-family: var(--m-font-mono);
  font-size: 10px;
  font-style: italic;
  color: var(--mt-muted);
  opacity: 0.7;
}

.manifold-wizard-hint-placeholder-centered {
  /* Same as .manifold-wizard-hint-placeholder but center-aligned and
     loosely-leaded for the larger preview frames where the hint sits
     centered in a 160px box. */
  font-family: var(--m-font-mono);
  font-size: 10px;
  font-style: italic;
  color: var(--mt-muted);
  opacity: 0.7;
  text-align: center;
  line-height: 1.6;
}

.manifold-wizard-preview-frame {
  /* 160px fixed-height preview region used by both WizardStepDataBody
     and WizardStepDataBodyDataFirst — the live renderer-preview box
     that sits above the metadata block / candidate list. */
  height: 160px;
  flex-shrink: 0;
  background: var(--mt-bg-elev);
  border: 1px solid var(--mt-border);
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
}

.manifold-wizard-preview-frame-fill {
  /* The inner full-bleed wrapper the RendererComponent sits in. */
  width: 100%;
  height: 100%;
}

.manifold-wizard-preview-card-frame {
  /* Steps 3-4: card-level preview. A larger frame than the data-step
     preview because it renders the entire in-progress card via
     CardRenderer. */
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  background: var(--mt-bg-elev);
  border: 1px solid var(--mt-border);
  border-radius: 4px;
  min-height: 160px;
}

.manifold-wizard-preview-card-frame-dashed {
  /* Step 5 (review) variant — same primitive but dashed border to
     read as "preview, not final". */
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  background: var(--mt-bg-elev);
  border: 1px dashed var(--mt-border);
  border-radius: 4px;
  min-height: 160px;
}

.manifold-wizard-preview-card-scale {
  /* Plan 49-03 WIZ-03 — outer wrapper that scales the true-size preview
     to fit the pane. The scale factor comes from --mw-preview-scale (set
     inline by WizardPreviewPane = min(paneWidth / cardWidth, 1), so a card
     narrower than the pane stays at true 1:1 size and is never blown up).
     transform-origin: top center keeps the scaled box hanging tidily from
     the top of the frame's centered column. */
  transform: scale(var(--mw-preview-scale, 1));
  transform-origin: top center;
}

.manifold-wizard-preview-card-fill {
  /* Plan 49-03 WIZ-03 — the inner box CardRenderer sits in is now sized to
     the card's REAL per-renderer default canvas box (the same {minW,minH}
     rendererMinPx hands the canvas placement in Plan 02), driven by the
     inline --mw-preview-w / --mw-preview-h custom properties. This replaces
     the old width:100% stretch so "what you see is what lands": the preview
     is the real card at landed size, scaled to fit by the -scale wrapper. */
  width: var(--mw-preview-w, 100%);
  height: var(--mw-preview-h, auto);
}

.manifold-wizard-data-body {
  /* StepDataBody pane — vertical stack of preview frame + metadata. */
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  flex: 1;
}

.manifold-wizard-data-meta {
  /* Three-line metadata block under the preview frame: display name,
     kind · unit, timeago · health. Lives in mono font. */
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-family: var(--m-font-mono);
}

.manifold-wizard-data-meta-name {
  font-size: 12px;
  color: var(--mt-fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.manifold-wizard-data-meta-kind {
  font-size: 10px;
  color: var(--mt-dim);
}

.manifold-wizard-data-meta-time {
  font-size: 10px;
  color: var(--mt-muted);
  font-variant-numeric: tabular-nums;
}

/* ── Wizard Columns summary (Phase 36 Plan 04) ──────────────────────
 * Two-line read-only block that sits between the preview frame and the
 * metadata block on Step 2 (Data) of the wizard. Only renders for the
 * `list` renderer when the leaf has item_shape.fields. Summary text is
 * dim (informational), helper line is muted (one shade dimmer — meta-
 * instruction, not data). Sits in the parent's existing 12px gap; no
 * margins of its own. */

.manifold-wizard-cols-summary-block {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.manifold-wizard-cols-summary {
  font-size: 12px;
  color: var(--mt-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.manifold-wizard-cols-helper {
  font-size: 10px;
  color: var(--mt-muted);
  font-style: italic;
}

/* ── Data-first candidate list (Plan 06-03) ─────────────────────────
 * The ranked compatible-renderers list that lives below the live
 * preview in data-first mode. Each row reads as a stack of two
 * lines (displayName above kind), with a left rail that lights up
 * accent on the selected row and border-strong on the highlight. */

.manifold-wizard-dfcl-empty {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.manifold-wizard-dfcl-empty-title {
  font-family: var(--m-font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mt-fg);
}

.manifold-wizard-dfcl-empty-text {
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--mt-dim);
  line-height: 1.4;
  padding: 8px 2px;
}

.manifold-wizard-dfcl {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
  flex: 1;
}

.manifold-wizard-dfcl-header {
  font-family: var(--m-font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mt-fg);
}

.manifold-wizard-dfcl-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--mt-border);
  border: 1px solid var(--mt-border);
  border-radius: 4px;
  overflow-y: auto;
  min-height: 0;
  flex: 1 1 auto;
}

.manifold-wizard-dfcl-row {
  /* Each candidate row. The left rail color flows through
     --m-dfcl-rail and the data-selected attribute swaps the row's
     selected vs highlighted vs idle posture. */
  height: 36px;
  padding: 4px 12px;
  background: var(--mt-bg-elev);
  border-left: 2px solid var(--m-dfcl-rail, transparent);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: relative;
  transition: border-color 80ms linear;
}

.manifold-wizard-dfcl-row-name {
  font-family: var(--m-font-sans);
  font-size: 13px;
  font-weight: 400;
  color: var(--mt-fg);
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.manifold-wizard-dfcl-row[data-selected="true"] .manifold-wizard-dfcl-row-name {
  color: var(--mt-accent);
}

.manifold-wizard-dfcl-row-kind {
  font-family: var(--m-font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--mt-dim);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.manifold-wizard-dfcl-row-picked {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--mt-accent);
  letter-spacing: 0.06em;
}

/* ── Narrow-viewport pane toggle ────────────────────────────────────
 * The Show preview / Hide preview button that replaces the inline
 * pane on viewports <= 800px. Carries a data-open attribute so the
 * "open" state reads in both the color and the border. */

.manifold-wizard-pane-toggle {
  padding: 5px 12px;
  font-size: 11px;
  font-family: var(--m-font-mono);
  background: transparent;
  color: var(--mt-dim);
  border: 1px solid var(--mt-border);
  border-radius: 3px;
  cursor: pointer;
}
.manifold-wizard-pane-toggle[data-open="true"] {
  color: var(--mt-accent);
  border-color: var(--mt-accent);
}

.manifold-wizard-pane-toggle-row {
  padding: 10px 22px 0 22px;
  display: flex;
  justify-content: flex-end;
}

/* ── Modal frame (CardWizardModal) ──────────────────────────────────
 * Outer backdrop + modal card + header + step indicator + body grid +
 * footer + narrow-viewport overlay. The modal-card width is set
 * inline (depends on viewport) — that's the one remaining inline
 * style on the card itself and it's allowed (state-driven width). */

.manifold-wizard-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.72);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.manifold-wizard-modal-card {
  /* `width` stays inline (state-driven: min(96vw, 1280px) vs 1100px
     depending on showPaneInline). Other chrome lives here. */
  max-height: min(92vh, 820px);
  background: var(--mt-bg);
  color: var(--mt-fg);
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--mt-border-strong);
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}

.manifold-wizard-modal-header {
  padding: 12px 18px;
  border-bottom: 1px solid var(--mt-border);
  background: var(--mt-bg-elev);
  display: flex;
  align-items: center;
  gap: 12px;
}

.manifold-wizard-modal-header-tag {
  font-family: var(--m-font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--mt-accent);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.manifold-wizard-modal-header-spacer {
  flex: 1;
}

.manifold-wizard-modal-btn-ghost {
  /* Header buttons — Switch to advanced + Cancel. Falls back to this
     shape when CB.styles.btnGhost isn't published. Production load
     always wins via the spread. */
  padding: 5px 12px;
  font-size: 11px;
  background: transparent;
  color: var(--mt-dim);
  border: 1px solid var(--mt-border);
  border-radius: 2px;
  cursor: pointer;
}

.manifold-wizard-modal-btn-ghost-wide {
  /* Cancel button — slightly wider padding than Switch to advanced. */
  padding: 5px 14px;
  font-size: 11px;
  background: transparent;
  color: var(--mt-dim);
  border: 1px solid var(--mt-border);
  border-radius: 2px;
  cursor: pointer;
}

.manifold-wizard-step-strip {
  /* Five-dot step indicator under the header. Grid columns count is
     state-driven (4 in data-first mode, 5 otherwise) — that count
     flows through --m-wizard-step-count. */
  padding: 10px 22px;
  background: var(--mt-bg);
  border-bottom: 1px solid var(--mt-border);
  display: grid;
  grid-template-columns: repeat(var(--m-wizard-step-count, 5), 1fr);
  gap: 8px;
}

.manifold-wizard-step-dot {
  /* Each step-strip entry — the 3px rail above + the step label below. */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.manifold-wizard-step-rail {
  /* The thin colored bar above each step label. data-state controls
     the color: 'active' / 'done' / 'idle'. */
  height: 3px;
  width: 100%;
  background: var(--mt-border);
  transition: background 120ms linear;
}
.manifold-wizard-step-rail[data-state="active"] {
  background: var(--mt-accent);
}
.manifold-wizard-step-rail[data-state="done"] {
  background: color-mix(in srgb, var(--mt-accent) 33%, transparent);
}

.manifold-wizard-step-label {
  /* The "01 · Choose a shape" label under each step rail. data-state
     swaps the color the same way. */
  font-family: var(--m-font-mono);
  font-size: 9px;
  color: var(--mt-muted);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.manifold-wizard-step-label[data-state="active"] {
  color: var(--mt-accent);
}
.manifold-wizard-step-label[data-state="done"] {
  color: var(--mt-dim);
}

.manifold-wizard-modal-body {
  /* The body grid — step content on the left + persistent preview
     pane on the right. Columns are state-driven (showPaneInline +
     viewport width); set via --m-wizard-pane-col on the element. */
  display: grid;
  grid-template-columns: var(--m-wizard-body-cols, 1fr);
  min-height: 0;
}

.manifold-wizard-modal-body-left {
  overflow: auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.manifold-wizard-modal-body-left[data-pane-inline="true"] {
  border-right: 1px solid var(--mt-border);
}

.manifold-wizard-modal-body-right {
  min-width: 0;
  overflow: hidden;
}

.manifold-wizard-modal-footer {
  padding: 12px 18px;
  border-top: 1px solid var(--mt-border);
  background: var(--mt-bg-elev);
  display: flex;
  align-items: center;
  gap: 10px;
}

.manifold-wizard-modal-footer-spacer {
  flex: 1;
}

.manifold-wizard-modal-footer-actions {
  /* Column wrapping the Next/Create button so the "Pick a renderer
     to continue" hint can sit directly below it without affecting
     the row layout. */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.manifold-wizard-modal-footer-hint {
  font-family: var(--m-font-mono);
  font-size: 11px;
  color: var(--mt-muted);
  letter-spacing: 0.04em;
}

.manifold-wizard-modal-back-btn {
  /* Back button — same ghost shape as the header buttons but with
     a wider padding flavor. */
  padding: 6px 14px;
  font-size: 11px;
  background: transparent;
  color: var(--mt-dim);
  border: 1px solid var(--mt-border);
  border-radius: 2px;
  cursor: pointer;
}

.manifold-wizard-modal-primary-btn {
  /* Next / Create card button — falls back to this shape when
     CB.styles.btnPrimary isn't published. */
  padding: 6px 18px;
  font-size: 11px;
}

/* ── Narrow-viewport overlay (D-21) ─────────────────────────────────
 * Replaces the inline preview pane with an overlay modal on viewports
 * <= 800px. Sits inside the existing .manifold-modal-overlay /
 * .manifold-modal shells from the legacy modal family so dismiss
 * affordances (ESC, X, backdrop click) all work uniformly. */

/* Plan 19-09: the wizard preview overlay used to layer
 * .manifold-modal-overlay + .manifold-modal under the custom
 * .manifold-wizard-overlay-card. Phase 19-09 swaps those generic modal
 * classes for a wizard-specific .manifold-wizard-overlay-backdrop so
 * the overlay no longer trips the `manifold-modal-*` namespace
 * cleanup gate. Visual identity is preserved exactly: the backdrop
 * dim, fixed positioning, and centered flex-layout copy verbatim
 * from .manifold-modal-overlay. */
.manifold-wizard-overlay-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(13, 15, 18, 0.7);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--m-pad-xl);
}

.manifold-wizard-overlay-card {
  max-width: 480px;
  width: 94vw;
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  background: var(--mt-bg);
  color: var(--mt-fg);
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--mt-border-strong);
}

.manifold-wizard-overlay-header {
  padding: 8px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--mt-border);
  background: var(--mt-bg-elev);
}

.manifold-wizard-overlay-header-title {
  font-family: var(--m-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4em;
  color: var(--mt-accent);
  text-transform: uppercase;
}

.manifold-wizard-overlay-close-btn {
  background: transparent;
  color: var(--mt-dim);
  border: none;
  cursor: pointer;
  font-family: var(--m-font-mono);
  font-size: 18px;
  line-height: 1;
  padding: 0 4px;
}

.manifold-wizard-overlay-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

/* ── Placeholder fallback (unused in production, kept for safety) ───
 * The "Step N of 5 / title / summary" three-line fallback shown when
 * a step body hasn't been written yet. Not currently rendered (all
 * five real Step components ship) but kept so adding a sixth step is
 * a one-line change. */

.manifold-wizard-placeholder-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 16px 22px;
}

.manifold-wizard-placeholder-summary {
  font-family: var(--m-font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--mt-dim);
  letter-spacing: 0.04em;
  text-transform: none;
  line-height: 1.6;
  padding: 14px 16px;
  border: 1px dashed var(--mt-border);
  border-radius: 6px;
}

/* =========================================================================
 * Accessibility
 * ========================================================================= */

button:focus-visible {
  outline: 2px solid var(--m-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* --- Widget-level transparent propagation -------------------------------
 * When a header widget has style.transparent set, the cell wrapper
 * already drops its own background+border via resolveChrome. These
 * rules push the same intent down to the widget's *internal* chrome —
 * the tab-bar strip, the auth pill, the gear hover surface — so the
 * whole widget reads as "no fill" rather than just the wrapper. Karl
 * 2026-05-07.
 *
 * !important so themes that re-set the same surfaces with their own
 * higher-specificity rules (`:root[data-theme="X"] .manifold-tabbar`)
 * still get overridden. The toggle is opt-in per widget; nothing
 * changes for widgets that don't carry data-widget-transparent.
 */
[data-widget-transparent="true"] .manifold-tabbar {
  background: transparent !important;
  border-bottom: none !important;
}
[data-widget-transparent="true"] .manifold-tab.active::after {
  /* The accent-bar underline reads as part of the tab label, not the
     bar fill — keep it. (Listed here for documentation; no override.) */
}
[data-widget-transparent="true"] .manifold-h-auth-pill {
  background: transparent !important;
  border-color: transparent !important;
}
[data-widget-transparent="true"] .manifold-h-gear:hover,
[data-widget-transparent="true"] .manifold-h-gear.open {
  background: transparent !important;
}

/* ─────────────────────────────────────────────────────────────────
 * Mobile-tolerance baseline (Karl 2026-05-08).
 *
 * The dashboard's primary modes:
 *   1. Desktop (≥768px): full layout, hover affordances, drag-drop
 *      edit mode all work as designed.
 *   2. Tablet / phone-landscape (480-767px): cards reflow to a
 *      4-col grid (clamped via _effectiveCols in card-builder.jsx).
 *      Tap targets enlarged to ≥36px so finger-precision works.
 *   3. Phone-portrait (<480px): cards reflow to 2-col, tab bar
 *      scrolls horizontally, header chrome wraps.
 *
 * Edit-mode mobile (drag-and-drop) is NOT covered here. HTML5 drag
 * events don't fire on touch devices; touch drag-emulation is a
 * larger lift and lives on the follow-ups list. View mode works
 * fully on mobile.
 * ──────────────────────────────────────────────────────────────── */

@media (max-width: 767px) {
  /* Larger tap targets on mid-narrow viewports. The 36px floor is
     the sweet spot between "comfortable to tap" and "doesn't dominate
     the chrome." Apple HIG says 44px; Material says 48dp; 36px is
     the lower-density compromise that keeps the dashboard's
     information-first density without making every button a thumb-
     trap. */
  .manifold-edit-fab {
    min-width: 44px;
    min-height: 44px;
    font-size: 13px;
  }
  .manifold-h-gear {
    min-width: 36px;
    min-height: 36px;
  }
  .manifold-h-auth-pill {
    min-height: 32px;
    padding: 4px 12px;
  }
  /* Reduce section padding so cards get more usable real estate
     on narrow viewports. */
  .manifold-section-grid,
  .manifold-section-cards-grid {
    padding: 8px !important;
  }
}

@media (max-width: 479px) {
  /* Phone-portrait: shrink the header strip's horizontal padding
     so the brand + auth + gear all fit on a single 360-400px row.
     Anything wider than that wraps via flex naturally. */
  .manifold-header-strip {
    padding: 0 4px;
  }
  /* Header tab bar inside the header strip — already scrolls
     horizontally via the .manifold-tabbar override above; just
     pad it less aggressively here. */
  .manifold-h-tabbar-host .manifold-tabbar {
    padding: 0 4px;
  }
  /* Cards' internal text shouldn't go below 11px even at this
     size — illegibility is worse than a slight horizontal scroll. */
  .manifold-card body, .manifold-card label {
    font-size: 11px;
  }
}

/* ── ServicePlacardRenderer ────────────────────────────────────────
   Status LED soft pulse for healthy services. Only fires while the
   service is `ok`/`live`; warn uses a faster pulse, fault is solid
   (broken state shouldn't dance). Karl 2026-05-09. */
@keyframes manifold-led-pulse {
  0%, 100% { opacity: 0.7; }
  50%      { opacity: 1.0; }
}
@keyframes manifold-led-pulse-warn {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1.0; }
}
/* Plan 07 — small spinner used by the Secrets tab's Test connection
   button while a probe is in flight. 12px ring, transparent top so the
   rotation reads visually. */
@keyframes manifold-spin {
  to { transform: rotate(360deg); }
}

/* =========================================================================
 * Phase 19 Plan 08 — long-tail file escape-hatch classes.
 *
 * The plan closes the migration tail across seven files: plugin-config.jsx,
 * logs-tab.jsx, header-strip.jsx, card-bundle.jsx, catalog-reorg-modal.jsx,
 * shared.jsx, health-panel.jsx. After this block lands, every JSX file in
 * core/dashboard/ has been swept and the file-scoped audit gate is clean
 * for all 11 (4 primitives + 19-04..07 four heavy files + this plan's 7).
 *
 * Naming conventions:
 *   .manifold-pc-*  → plugin-config.jsx (Plugins gear modal + config form)
 *   .manifold-logs-*→ logs-tab.jsx (Logs tab — chip bar, rows, feed)
 *   .manifold-hdr-* → header-strip.jsx (header chrome — assets picker,
 *                     auth popover, errors banner; manifold-h-* family
 *                     stays as-is per the 19-08 plan body — that disposition
 *                     is 19-09's job)
 *   .manifold-bundle-warn / -info / -tag — card-bundle.jsx amber + blue
 *                     attention-bars; the "name in use" tag pill
 *   .manifold-catreorg-* → catalog-reorg-modal.jsx body/list/secondary
 *   .manifold-shared-* → shared.jsx primitives (HBar, Dot)
 *
 * Authoring rules carry over from 19-04..07: classes bundle visual
 * primitives that always co-occur; runtime values (HBar color/bg, dot
 * status color) ride CSS custom properties so the JSX stays declarative
 * and inline style sites drop to zero on the audit.
 * ========================================================================= */

/* ── plugin-config.jsx — Plugins gear modal + per-plugin config form ──── */

/* The center-aligned "empty / placeholder" body block ("No plugins
   installed.", "This plugin has no configurable settings.", etc.).
   Bundles padding + center alignment + dim opacity into one primitive
   used in three sites. Opacity stays as a property of the class — the
   audit does not gate `opacity`. */
.manifold-pc-empty {
  padding: 24px;
  text-align: center;
  opacity: 0.6;
}
/* Variant used inside the Secrets-tab "owner only" guard + the
   "this plugin declares no secrets" placeholder — same center+dim
   shape but with the monospace small-text caption styling baked in. */
.manifold-pc-empty-mono {
  padding: 24px;
  text-align: center;
  opacity: 0.6;
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
}

/* The plugin-list <ul> reset — flat list, no bullets. Used in both the
   PluginListModal body and the secrets tab. */
.manifold-pc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Each plugin tile button in PluginListModal — full-width row,
   transparent surface, soft hover tint, baseline-aligned label + id +
   version columns. Hover background swap stays declarative via :hover
   instead of the pre-migration onMouseEnter / onMouseLeave imperative
   inline-style mutation. */
.manifold-pc-list-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  width: 100%;
  padding: 10px 12px;
  text-align: left;
  background: transparent;
  border: 1px solid var(--m-border, var(--mt-border, #444));
  border-radius: 6px;
  color: inherit;
  font: inherit;
  margin-bottom: 6px;
  cursor: pointer;
  transition: background 120ms ease-out;
}
.manifold-pc-list-row:hover {
  background: color-mix(in srgb, var(--mt-fg, #fff) 4%, transparent);
}
/* Plugin name (sans, semibold, sized as default body text). */
.manifold-pc-list-name {
  font-family: var(--m-font-sans, "Rubik", sans-serif);
  font-weight: 600;
  font-size: 14px;
  flex: 1;
}
/* Plugin id (smaller mono, dim). */
.manifold-pc-list-id {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  opacity: 0.7;
}
/* Plugin version (smaller mono, dimmer). */
.manifold-pc-list-ver {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  opacity: 0.5;
}

/* PluginConfigModal back arrow inside the header — borderless,
   inherit-font, slight padding so the arrow has hit area. */
.manifold-pc-back-arrow {
  background: transparent;
  border: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  padding: 0 6px;
  margin-right: 6px;
  opacity: 0.6;
}
/* Plugin-id chip next to the name in the modal header (small mono). */
.manifold-pc-header-id {
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
  opacity: 0.6;
  font-weight: 400;
}

/* Tab strip below the modal header — sits along the bottom border
   between the header and the body, holds the two tabs (Config / Secrets). */
.manifold-pc-tabstrip {
  display: flex;
  gap: 0;
  padding: 0 16px;
  border-bottom: 1px solid var(--m-border, var(--mt-border, #444));
}
/* Individual tab button. Selected state via data-selected attribute
   selector instead of a JSX ternary that baked the accent color into
   border-bottom + color per render. */
.manifold-pc-tabbtn {
  background: transparent;
  border: none;
  padding: 10px 14px;
  cursor: pointer;
  color: inherit;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.manifold-pc-tabbtn[data-selected="true"] {
  color: var(--m-accent, var(--mt-accent, #4af));
  border-bottom: 2px solid var(--m-accent, var(--mt-accent, #4af));
}

/* The small mono caption block at the top of the Config tab body ("Saved
   values write to <code>…</code>"). Same shape reused at the top of the
   Secrets tab body. */
.manifold-pc-caption {
  font-size: 11px;
  opacity: 0.6;
  margin-bottom: 14px;
  font-family: "JetBrains Mono", monospace;
}

/* Reload-status banner shown after a successful save+restart. Background
   + border-color depend on whether the systemd restart succeeded — the
   green vs amber distinction rides --m-pc-banner-bg / --m-pc-banner-border
   custom properties so the class itself is shape-only. */
.manifold-pc-reload-status {
  margin-top: 14px;
  padding: 8px 12px;
  border-radius: 4px;
  background: var(--m-pc-banner-bg, color-mix(in srgb, var(--mt-live, #50c878) 8%, transparent));
  border: 1px solid var(--m-pc-banner-border, color-mix(in srgb, var(--mt-live, #50c878) 40%, transparent));
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  color: inherit;
}
/* error-line variant uses just the top-margin tweak; the underlying
   .manifold-error-line carries the color. */
.manifold-pc-error-line-spaced {
  margin-top: 14px;
}

/* ── InstanceSetEditor — multi-row Instances editor inside Secrets tab ── */

/* Outer wrapper — small top gap separating instances from the password
   rows above. */
.manifold-pc-instances {
  margin-top: 16px;
}
/* Header row above the instance grid — "Instances (description)" on left,
   "+ Add instance" button on the right. */
.manifold-pc-instances-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
/* Header title (small uppercase mono label). */
.manifold-pc-instances-title {
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.7;
}
/* Subtle field-key hint after the title. */
.manifold-pc-instances-hint {
  margin-left: 8px;
  font-weight: 400;
  opacity: 0.6;
}
/* "+ Add instance" + "Remove" small buttons share size + padding. */
.manifold-pc-btn-sm {
  font-size: 11px;
  padding: 3px 10px;
}
.manifold-pc-btn-xs {
  font-size: 10px;
  padding: 2px 8px;
}
/* Remove-instance button gets error-color border + text. */
.manifold-pc-btn-remove {
  color: var(--m-error, var(--mt-error, #f55));
  border-color: var(--m-error, var(--mt-error, #f55));
}
/* Empty placeholder when no instances configured. */
.manifold-pc-instances-empty {
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  opacity: 0.5;
  padding: 10px 0;
}
/* Each instance card — bordered tile holding the field grid. */
.manifold-pc-instance-card {
  border: 1px solid var(--m-border, var(--mt-border, #444));
  border-radius: 4px;
  padding: 10px 12px;
  margin-bottom: 8px;
}
/* Header row inside each instance card — "Instance N" label + Remove btn. */
.manifold-pc-instance-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
/* "Instance N" small mono label. */
.manifold-pc-instance-label {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  opacity: 0.5;
}
/* Field-key uppercase label inside the instance grid. */
.manifold-pc-instance-field-label {
  display: block;
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  font-weight: 700;
  margin-bottom: 3px;
  opacity: 0.7;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
/* "(opt)" suffix marker after a field key. */
.manifold-pc-opt-marker {
  margin-left: 4px;
  font-weight: 400;
  opacity: 0.5;
}

/* ── Secrets tab — password row + Test connection button + result banner ─ */

/* One row per secret. Border-bottom hairline separates rows. */
.manifold-pc-secret-row {
  border-bottom: 1px solid var(--m-border, var(--mt-border, #444));
  padding: var(--m-pad-sm, 8px) var(--m-pad-md, 12px);
}
/* Inner flex row holding label, input, button. */
.manifold-pc-secret-row-inner {
  display: flex;
  align-items: center;
  gap: var(--m-pad-md, 12px);
}
/* Secret label (the env-var KEY, slightly larger). */
.manifold-pc-secret-key {
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
/* "optional" marker after the key. */
.manifold-pc-secret-opt {
  margin-left: 8px;
  font-weight: 400;
  opacity: 0.5;
  font-size: 10px;
}
/* Description / source caption under the key. */
.manifold-pc-secret-desc {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  opacity: 0.6;
  margin-top: 2px;
}
/* Test-connection button background tints by status via
   --m-pc-test-bg custom prop. Idle = transparent; ok = accent-tinted;
   fail = error-tinted. */
.manifold-pc-test-btn {
  flex: 0 0 auto;
  background: var(--m-pc-test-bg, transparent);
  min-width: 132px;
  transition: background 180ms ease-out;
}
/* Inline spinner ring inside the test button while a probe is in flight. */
.manifold-pc-test-spinner {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 6px;
  vertical-align: -1px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: manifold-spin 800ms linear infinite;
}
/* Inline test-connection result banner under the row — colored left
   stripe + tinted background by --m-pc-result-bg / --m-pc-result-border. */
.manifold-pc-secret-result {
  margin-top: 8px;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  padding: 6px 10px;
  border-radius: 4px;
  background: var(--m-pc-result-bg, transparent);
  border-left: var(--m-pc-result-border, 3px solid transparent);
  color: var(--m-text, inherit);
}

/* ── ConfigField — per-field label/hint/error rows in the Config tab ──── */

.manifold-pc-field-label {
  display: block;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  font-weight: 700;
  margin-bottom: 4px;
  margin-top: 14px;
  letter-spacing: 0.02em;
}
.manifold-pc-field-key {
  font-weight: 700;
}
.manifold-pc-field-type {
  margin-left: 8px;
  font-weight: 400;
  opacity: 0.5;
  text-transform: lowercase;
  font-size: 10px;
}
.manifold-pc-field-hint {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  opacity: 0.6;
  margin-top: 4px;
  margin-bottom: 0;
}
.manifold-pc-field-err {
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  color: var(--m-error, var(--mt-error, #ff5050));
  margin-top: 4px;
}
/* Boolean-field "enabled/disabled" label gets the body font size. */
.manifold-pc-bool-state {
  font-size: 12px;
}

/* ── logs-tab.jsx — Logs tab chrome (chip bar, rows, feed) ────────────── */

/* Outer tab container — full-height column with rounded border. */
.manifold-logs-tab {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 140px);
  min-height: 400px;
  background: var(--mt-bg, #0f1418);
  border: 1px solid var(--mt-border, #2a2f36);
  border-radius: 6px;
  overflow: hidden;
}
/* Owner-only banner shown when /api/v0/logs/sources returns 403. */
.manifold-logs-auth-banner {
  padding: 32px;
  text-align: center;
  color: var(--mt-muted, #94a3b8);
  font-family: "JetBrains Mono", monospace;
  font-size: 13px;
}
/* Chip bar — sticky toolbar at the top, holds source chips + level + time + search. */
.manifold-logs-chipbar {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--mt-bg-elev, #0f1418);
  border-bottom: 1px solid var(--mt-border, #2a2f36);
  padding: 10px 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  font-family: "JetBrains Mono", monospace;
}
/* The chip group flexes to fill remaining space. */
.manifold-logs-chipgroup {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
/* "loading sources…" italic placeholder. */
.manifold-logs-chipgroup-loading {
  color: var(--mt-muted, #64748b);
  font-size: 11px;
  font-style: italic;
}
/* Each source chip — pill-shaped button. Background + border + text
   color depend on `on` state and per-source color (FNV hash). Both
   move onto --m-logs-chip-color (the source's hue) + a data-on=true|false
   attribute selector. */
.manifold-logs-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 1px solid var(--mt-border, #2a2f36);
  border-radius: 999px;
  padding: 3px 10px;
  cursor: pointer;
  user-select: none;
  font-size: 11px;
  font-family: "JetBrains Mono", monospace;
  color: var(--mt-muted, #94a3b8);
}
.manifold-logs-chip[data-on="true"] {
  background: color-mix(in srgb, var(--m-logs-chip-color, var(--mt-accent)) 13%, transparent);
  border-color: var(--m-logs-chip-color, var(--mt-accent));
  color: var(--mt-fg, #e5e7eb);
}
/* The little color dot inside each chip. */
.manifold-logs-chip-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--m-logs-chip-color, var(--mt-accent));
  flex-shrink: 0;
}
/* "cls" classifier marker after a chip's label. */
.manifold-logs-chip-cls {
  opacity: 0.6;
  font-size: 9px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
/* Right group: level + time + search + jump-to-live. */
.manifold-logs-rightgroup {
  display: flex;
  gap: 6px;
  align-items: center;
}
/* Shared <select> + <input> chrome (level dropdown, time-window
   dropdown, search box). One class because all three carry the same
   bordered-box-with-mono-text shape. */
.manifold-logs-control {
  background: var(--mt-bg, #0f1418);
  border: 1px solid var(--mt-border, #2a2f36);
  border-radius: 4px;
  padding: 5px 8px;
  font-size: 11px;
  color: var(--mt-fg, #e5e7eb);
  font-family: "JetBrains Mono", monospace;
  cursor: pointer;
}
/* Search box specifically fills a wider track and uses text-cursor. */
.manifold-logs-search {
  width: 140px;
  cursor: text;
}
/* "▼ Jump to live" sticky button — accent fill, dark text. */
.manifold-logs-jump-btn {
  background: #5eead4;
  color: #0f1418;
  border: none;
  border-radius: 4px;
  padding: 5px 10px;
  font-size: 11px;
  font-family: "JetBrains Mono", monospace;
  font-weight: 600;
  cursor: pointer;
}
/* Polling error banner above the feed. */
.manifold-logs-err {
  padding: 6px 12px;
  background: #450a0a;
  color: #fca5a5;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
}
/* The scrollable feed body. */
.manifold-logs-feed {
  flex: 1;
  overflow: auto;
  min-height: 0;
  background: var(--mt-bg, #0f1418);
  font-family: "JetBrains Mono", monospace;
}
/* Empty-state placeholder when no lines yet. */
.manifold-logs-feed-empty {
  padding: 24px;
  text-align: center;
  color: var(--mt-muted, #64748b);
  font-size: 12px;
  font-style: italic;
}
/* Each row — left-edge colored stripe by source (--m-logs-row-color),
   small mono text. Expanded row gets a hairline bottom + elevated bg. */
.manifold-logs-row {
  padding: 2px 12px 2px 0;
  border-left: 3px solid var(--m-logs-row-color, var(--mt-border, #2a2f36));
  padding-left: 9px;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  line-height: 1.45;
  color: var(--mt-fg, #e5e7eb);
  cursor: pointer;
  background: transparent;
  border-bottom: 1px solid transparent;
}
.manifold-logs-row[data-expanded="true"] {
  background: var(--mt-bg-elev, #1a1f26);
  border-bottom: 1px solid var(--mt-border, #2a2f36);
}
/* Row top-line container (timestamp + level pill + source + host + msg). */
.manifold-logs-row-top {
  display: flex;
  gap: 8px;
  align-items: baseline;
  white-space: nowrap;
}
/* Timestamp — muted + tabular-nums so columns line up. */
.manifold-logs-row-ts {
  color: var(--mt-muted, #64748b);
  font-variant-numeric: tabular-nums;
}
/* Level pill — bg + fg from --m-logs-pill-bg / --m-logs-pill-fg
   (info/warn/err palette in JS). */
.manifold-logs-pill {
  background: var(--m-logs-pill-bg, transparent);
  color: var(--m-logs-pill-fg, inherit);
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  flex-shrink: 0;
}
/* Source label colored by FNV hash via --m-logs-row-color. */
.manifold-logs-row-source {
  color: var(--m-logs-row-color, var(--mt-fg));
  font-size: 10px;
  opacity: 0.8;
}
/* "@host" suffix. */
.manifold-logs-row-host {
  color: var(--mt-muted, #64748b);
  font-size: 10px;
  opacity: 0.6;
}
/* The actual log message — fills remaining horizontal space, truncates. */
.manifold-logs-row-msg {
  color: var(--mt-fg, #e5e7eb);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Expanded fields grid below the top line. */
.manifold-logs-row-fields {
  margin-top: 4px;
  padding-left: 12px;
  font-size: 10px;
  color: var(--mt-muted, #94a3b8);
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 12px;
  row-gap: 2px;
}
.manifold-logs-row-fkey {
  color: var(--mt-muted, #64748b);
  white-space: nowrap;
}
.manifold-logs-row-fval {
  color: var(--mt-fg, #cbd5e1);
  word-break: break-all;
}

/* ── header-strip.jsx — assets picker hint, auth popover, errors banner ─ */

/* Small "loading…" caption in the gear-icon picker. */
.manifold-hdr-loading-hint {
  opacity: 0.6;
  font-size: 0.85em;
}
/* "current: <name>" caption alongside the refresh button. */
.manifold-hdr-current-asset {
  font-size: 0.85em;
  opacity: 0.7;
  align-self: center;
}
/* Anonymous viewer's Sign-in pill — bordered, transparent, pill shape. */
.manifold-hdr-auth-signin {
  cursor: pointer;
  background: transparent;
  border: 1px solid currentColor;
  color: inherit;
  font: inherit;
  padding: 2px 10px;
  border-radius: 4px;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
/* The ↪ glyph inside the Sign-in pill. */
.manifold-hdr-auth-icon {
  font-size: 12px;
}
/* Authenticated user pill — borderless small-padding variant. */
.manifold-hdr-auth-pill-btn {
  cursor: pointer;
  background: transparent;
  border: 1px solid currentColor;
  color: inherit;
  font: inherit;
  padding: 2px 8px;
  border-radius: 4px;
}
/* Auth popover floating menu — dropped via React portal, position:fixed
   handled inline (state-driven coordinates). */
.manifold-hdr-auth-popover {
  background: var(--m-bg-elev, var(--mt-bg-elev, #1a1a1a));
  border: 1px solid var(--m-border, var(--mt-border, #444));
  border-radius: 6px;
  padding: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
  color: var(--m-text, var(--mt-fg, #eee));
}
/* "Signed in as <name> · <role>" caption above the Sign-out button. */
.manifold-hdr-auth-caption {
  padding: 4px 8px 8px;
  opacity: 0.7;
}
/* Sign-out menu item — block button with hover background. */
.manifold-hdr-signout-btn {
  display: block;
  width: 100%;
  text-align: left;
  padding: 6px 8px;
  background: transparent;
  color: inherit;
  font: inherit;
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: pointer;
}
.manifold-hdr-signout-btn:hover {
  background: color-mix(in srgb, var(--mt-fg, #fff) 5%, transparent);
}
/* Errors banner in EditHeaderModal — red-tinted with body title + ul. */
.manifold-hdr-errs {
  margin: 0 14px 12px;
  padding: 10px 12px;
  background: color-mix(in srgb, var(--mt-error, #ff5050) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--mt-error, #ff5050) 40%, transparent);
  border-radius: 4px;
  color: var(--m-error, var(--mt-error, #ff5050));
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
}
.manifold-hdr-errs-title {
  font-weight: 700;
  margin-bottom: 4px;
}
.manifold-hdr-errs-list {
  margin: 0;
  padding-left: 20px;
}
/* CellEditor refresh-row gap. */
.manifold-hdr-refresh-row {
  display: flex;
  gap: 8px;
  margin-top: 4px;
}
/* CellEditor "remove" button pushed to the right of the cell label. */
.manifold-hdr-remove-pushed {
  margin-left: auto;
}

/* ── card-bundle.jsx — collision / select-all bulkrow bars + "in use" tag ─ */

/* Inline caption sitting next to the target <select> ("Cards land in
   your library…"). */
.manifold-bundle-target-hint {
  margin-left: 10px;
  font-size: 11px;
  opacity: 0.7;
}
/* Amber-tinted bulkrow — "N name collision…" callout above the card list. */
.manifold-bundle-warn {
  margin-top: 6px;
  padding: 8px 10px;
  background: color-mix(in srgb, var(--mt-warn, #ffb450) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--mt-warn, #ffb450) 35%, transparent);
  border-radius: 4px;
}
/* Blue-tinted bulkrow — "Importing N of M cards" + Select all / none. */
.manifold-bundle-info {
  margin-top: 6px;
  padding: 8px 10px;
  background: color-mix(in srgb, var(--mt-accent, #50b4ff) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--mt-accent, #50b4ff) 35%, transparent);
  border-radius: 4px;
}
/* Bold caption inside each bulkrow ("N name collisions:" / "Importing…"). */
.manifold-bundle-bulkrow-title {
  font-weight: 700;
}
/* Hint span trailing each bulkrow ("Uncheck cards you don't want…"). */
.manifold-bundle-bulkrow-hint {
  font-size: 11px;
  opacity: 0.7;
  margin-left: 8px;
}
/* Per-card "⚠ name in use" tag — small uppercase mono pill, amber tint. */
.manifold-bundle-nameused-tag {
  margin-left: 8px;
  font-size: 10px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 99px;
  background: color-mix(in srgb, var(--mt-warn, #ffb450) 20%, transparent);
  color: var(--mt-warn, #ffb450);
  border: 1px solid color-mix(in srgb, var(--mt-warn, #ffb450) 45%, transparent);
  font-family: "JetBrains Mono", monospace;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* Card-checkbox in the bundle preview — small gap to the right of the box. */
.manifold-bundle-card-check {
  margin-right: 6px;
}

/* ── catalog-reorg-modal.jsx — informational migration modal body chrome ─ */

/* The body paragraph above the optional list. */
.manifold-catreorg-body {
  font-family: var(--m-font-sans, "Rubik", sans-serif);
  font-size: var(--mt-text-md-size, 14px);
  line-height: 1.5;
  color: var(--m-text, var(--mt-fg));
  padding: var(--m-pad-md, 14px) 0;
}
/* The disc-bullet list of affected cards (visible only when n > 1). */
.manifold-catreorg-list {
  list-style: disc inside;
  margin: 0;
  padding-left: var(--m-pad-md, 14px);
  color: var(--m-text, var(--mt-fg));
  font-size: var(--mt-text-md-size, 14px);
  line-height: 1.6;
}
.manifold-catreorg-list-row {
  padding: 2px 0;
}
/* Secondary muted text after each card title (unresolved leaves). */
.manifold-catreorg-secondary {
  color: var(--m-text-muted, var(--mt-dim, #8b8985));
  font-size: var(--mt-text-sm-size, 12px);
  margin-left: var(--m-pad-sm, 8px);
}
/* "…and N more" trailing tail. */
.manifold-catreorg-more {
  list-style: none;
  color: var(--m-text-muted, var(--mt-dim, #8b8985));
  font-style: italic;
}

/* ── shared.jsx — generic primitives (HBar, Dot) ──────────────────────── */

/* Horizontal-bar track. Background color rides --m-hbar-bg (default uses
   a 6%-white soft fill). Border-radius rides --m-hbar-radius. The
   prop-driven height stays inline (state-driven; not a FORBIDDEN_KEY). */
.manifold-shared-hbar-track {
  background: var(--m-hbar-bg, rgba(255, 255, 255, 0.06));
  border-radius: var(--m-hbar-radius, 0);
  overflow: hidden;
  width: 100%;
}
/* Fill ribbon inside the track — width set inline (state-driven %). */
.manifold-shared-hbar-fill {
  background: var(--m-hbar-color, currentColor);
  height: 100%;
  transition: width 600ms ease;
}
/* Status dot — small filled circle with a glow halo. Fill + shadow color
   ride --m-shared-dot-color (status-keyed in JS: ok=green, warn=amber,
   err=red, idle=gray). */
.manifold-shared-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 8px;
  background: var(--m-shared-dot-color, #888);
  box-shadow: 0 0 6px var(--m-shared-dot-color, #888);
}

/* ── section-editor.jsx — assigned-const indirection cleanup ───────────
 * Phase 19 Plan 08 sweep: numInputStyle + stepBtn lived as object consts
 * (`const numInputStyle = {...}`) and were spread via `style={...}` /
 * `style={{...stepBtn, ...}}`. The audit's Phase 19-era walker now
 * resolves that indirection so the aesthetic keys inside the const
 * propagate to every consumer. Both move onto named classes here. */

/* Compact number-input control paired with each section-editor slider —
 * width is fixed, right-aligned digits, theme-aware bg / border / fg. */
.manifold-se-numinput {
  width: 56px;
  padding: 2px 4px;
  font-size: 11px;
  font-family: "JetBrains Mono", monospace;
  background: var(--manifold-bg, var(--mt-bg, #1a1a1a));
  color: var(--manifold-fg, var(--mt-fg, #eee));
  border: 1px solid var(--manifold-border, var(--mt-border, #444));
  border-radius: 3px;
  text-align: right;
}

/* −/+ step button used alongside the number control. Disabled-state
 * dimming + cursor swap rides native :disabled instead of the JSX
 * ternary that baked opacity + cursor inline. */
.manifold-se-stepbtn {
  width: 26px;
  height: 26px;
  padding: 0;
  font-size: 13px;
  font-family: "JetBrains Mono", monospace;
  font-weight: 700;
  background: transparent;
  color: var(--m-text-dim, var(--mt-dim, #888));
  border: 1px solid var(--m-border, var(--mt-border, #444));
  border-radius: 3px;
  cursor: pointer;
  flex-shrink: 0;
}
.manifold-se-stepbtn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
