:root {
  --bg: #0f1014;
  --panel: #17181d;
  --panel-2: #1e2026;
  --border: #2a2c33;
  --text: #e8e9ed;
  --muted: #8a8f98;
  --accent: #1db954;
  --accent-2: #1ed760;
  --danger: #f87171;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--text);
  font-family: 'Inter', system-ui, -apple-system, sans-serif; font-size: 14px; }
body { display: flex; flex-direction: column; }

/* ---------- Top bar (sticky, above the shell) ---------- */
.topbar {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 8px 18px;
  background: var(--panel-2);
  border-bottom: 1px solid var(--border);
  font-size: 12px;
}
.topbar__back {
  color: var(--muted); text-decoration: none; font-weight: 600;
  padding: 6px 12px; border-radius: 6px;
  transition: background 120ms ease, color 120ms ease;
  white-space: nowrap;
}
.topbar__back:hover { background: var(--panel); color: var(--text); }
.topbar__obs {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  min-width: 0;
}
.topbar__obs-label { color: var(--muted); font-size: 11px; white-space: nowrap; }
.topbar__obs-url {
  background: var(--bg); color: var(--text);
  padding: 4px 10px; border-radius: 4px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px;
  user-select: all; cursor: pointer;
  max-width: 420px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
  border: 1px solid var(--border);
  transition: border-color 120ms ease;
}
.topbar__obs-url:hover { border-color: var(--accent); }
.topbar__copy {
  background: var(--accent); color: #0a1a10; border: 0;
  border-radius: 999px; padding: 5px 14px;
  font-size: 11px; font-weight: 700; cursor: pointer;
  transition: background 120ms ease, transform 80ms ease;
}
.topbar__copy:hover { background: var(--accent-2); }
.topbar__copy:active { transform: scale(0.96); }
.topbar__copy.is-success { background: var(--accent-2); }
.topbar__obs-size {
  margin-left: 8px; padding: 4px 10px;
  background: rgba(126,249,255,0.08);
  border: 1px solid rgba(126,249,255,0.25);
  border-radius: 4px;
  color: #7ef9ff; font-size: 11px; font-weight: 600;
  white-space: nowrap;
  cursor: help;
}

.topbar__status {
  padding: 4px 10px; border-radius: 4px;
  font-size: 11px; font-weight: 600;
  white-space: nowrap;
  cursor: help;
}
.topbar__status.is-ok {
  background: rgba(29,185,84,0.12);
  border: 1px solid rgba(29,185,84,0.4);
  color: var(--accent);
}
.topbar__status.is-off {
  background: rgba(248,113,113,0.10);
  border: 1px solid rgba(248,113,113,0.4);
  color: #f87171;
  animation: status-pulse 2.4s ease-in-out infinite;
}
@keyframes status-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(248,113,113,0); }
  50%      { box-shadow: 0 0 0 4px rgba(248,113,113,0.2); }
}

/* Patreon connection badge — sits at the right end of the topbar.
   Three visual states:
     .is-cta  (signed-out)        — green call-to-action with hover lift
     .is-free (signed-in, free)   — neutral, just shows the email
     .is-pro  (signed-in, paying) — gold gradient pill with sparkle
   Click anywhere on the pill opens the Patreon modal (every feature is
   free for everyone; the modal covers sign-in + early-access info). */
.topbar__patreon {
  margin-left: auto;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 100ms ease, box-shadow 120ms ease, background 120ms ease;
  user-select: none;
}
.topbar__patreon:hover { transform: translateY(-1px); }
.topbar__patreon.is-cta {
  background: rgba(29,185,84,0.15);
  border: 1px solid rgba(29,185,84,0.5);
  color: var(--accent-2, #1ed760);
}
.topbar__patreon.is-cta:hover {
  background: rgba(29,185,84,0.25);
  box-shadow: 0 4px 12px rgba(29,185,84,0.25);
}
.topbar__patreon.is-free {
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--border);
  color: var(--muted);
}
.topbar__patreon.is-free:hover {
  background: rgba(255,255,255,0.08);
  color: var(--text);
}
.topbar__patreon.is-pro {
  background: linear-gradient(135deg, rgba(252,211,77,0.18), rgba(245,158,11,0.18));
  border: 1px solid rgba(252,211,77,0.55);
  color: #fde68a;
  box-shadow: 0 0 0 0 rgba(252,211,77,0.35);
  animation: patreon-pro-glow 3.4s ease-in-out infinite;
}
.topbar__patreon.is-pro:hover {
  background: linear-gradient(135deg, rgba(252,211,77,0.28), rgba(245,158,11,0.28));
}
@keyframes patreon-pro-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(252,211,77,0); }
  50%      { box-shadow: 0 0 0 4px rgba(252,211,77,0.18); }
}

.topbar__obs-url.is-disabled {
  color: var(--muted);
  border-style: dashed;
  font-style: italic;
  cursor: help;
}
.topbar__copy:disabled {
  opacity: 0.4; cursor: not-allowed;
  background: var(--panel-2);
  color: var(--muted);
}

.setup-banner {
  background: linear-gradient(90deg, rgba(29,185,84,0.16), rgba(29,185,84,0.05));
  border-bottom: 1px solid rgba(29,185,84,0.4);
  padding: 10px 24px;
  font-size: 13px; color: var(--text);
  text-align: center;
}
.setup-banner strong { color: var(--accent); margin-right: 6px; }

.shell {
  flex: 1 1 auto;
  display: grid;
  /* Controls pane needs enough breathing room for the role matrix
     table (Twitch tab has 6 roles × cap/cooldown/jump). The previous
     360-420px range smushed the matrix; 440-540px gives it room while
     still leaving the preview pane at least ~380px on a 1280px viewport. */
  grid-template-columns: 180px minmax(440px, 540px) 1fr;
  min-height: 0;
}
@media (max-width: 1100px) {
  /* Narrow viewport: TOC overlays instead of taking a fixed column. */
  .shell { grid-template-columns: minmax(420px, 520px) 1fr; }
}

/* ---------- Left pane: controls ---------- */
.pane-controls {
  background: var(--panel);
  border-right: 1px solid var(--border);
  overflow-y: auto;
  padding: 20px;
}
/* ---------- Cleaned-up config header ----------
   Two rows of grouped controls, each row holding logical clusters:
     Row 1: [Profile group] [Search + Advanced]
     Row 2: [Preset group]  [Data ops: Share / Export / Import / Reset]
   Groups are visually boxed with a subtle background tint so the streamer's
   eye can scan them as units instead of parsing 11 buttons in a row. */
/* Override the older .pane-controls header rule (which sets row-direction
   + space-between) so the new column layout actually stacks the rows. */
.pane-controls header.cfg-header,
.cfg-header {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 20px;
  align-items: stretch;
  justify-content: flex-start;
}
.cfg-header__title h1 {
  font-size: 18px; font-weight: 700; margin: 0; letter-spacing: -0.01em;
}
.cfg-header__sub { color: var(--mut, #8b90a0); font-weight: 500; font-size: 14px; }
.profile-label { font-weight: 500; color: var(--accent); margin-left: 4px; font-size: 13px; }
.cfg-header__row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.cfg-header__group {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 8px;
  background: rgba(255,255,255,0.025);
  border: 1px solid var(--border);
  border-radius: 8px;
  /* Slight inner glow on hover so the group reads as one clickable surface
     even though its members are individually clickable. */
  transition: border-color 120ms ease, background 120ms ease;
}
.cfg-header__group:hover { border-color: rgba(255,255,255,0.12); background: rgba(255,255,255,0.04); }
.cfg-header__group--search { flex: 1 1 auto; }
.cfg-header__group--secondary {
  /* Push secondary actions (Share / Export / Import / Reset) to the right
     end of the row so the primary preset-related controls anchor to the
     left where the eye starts. */
  margin-left: auto;
  background: transparent;
  border-color: transparent;
}
.cfg-header__group--secondary:hover { background: transparent; border-color: transparent; }
.cfg-header__label {
  font-size: 10.5px; font-weight: 700;
  color: var(--mut, #8b90a0);
  text-transform: uppercase; letter-spacing: 0.6px;
  padding-right: 4px;
  border-right: 1px solid var(--border);
  margin-right: 2px;
}
.cfg-header__group button,
.cfg-header__group select {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 10px; font-size: 12px; cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}
.cfg-header__group button:hover, .cfg-header__group select:hover { border-color: var(--accent); }
.cfg-header__group button.danger:hover { border-color: var(--danger); color: var(--danger); }
.cfg-header__group input[type="search"] {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 10px; font-size: 12px;
  min-width: 200px;
  flex: 1 1 auto;
  transition: border-color 120ms ease;
}
.cfg-header__group input[type="search"]:focus { outline: none; border-color: var(--accent); }
/* Apply Recommended is the headline action for plug-and-play streamers —
   pops out of the otherwise-uniform action row in the project's accent green. */
#apply-recommended {
  background: linear-gradient(135deg, var(--accent), var(--accent-2)) !important;
  border-color: transparent !important;
  color: #0a1a10 !important;
  font-weight: 700;
  letter-spacing: 0.01em;
}
#apply-recommended:hover {
  filter: brightness(1.08);
  border-color: transparent !important;
}

/* Legacy class kept so old .actions selectors don't break anything that's
   still referencing them — but the new .cfg-header__* layout is the
   active surface. */
.actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.actions button, .actions select {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 10px; font-size: 12px; cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}
.actions input[type="search"] {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 10px; font-size: 12px;
  min-width: 180px;
  transition: border-color 120ms ease;
}
.actions input[type="search"]:focus { outline: none; border-color: var(--accent); }
.actions button:hover, .actions select:hover { border-color: var(--accent); }
.actions button.danger:hover { border-color: var(--danger); color: var(--danger); }

/* ---------- Group cards ----------
   Each top-level config section (Layout, Effects, Music Source, etc.) renders
   as a card. Headers got a chunky redesign: bigger, brighter, with a green
   accent stripe on the left so the eye can scan section starts at a glance.
   Sub-section headers (h3, the "section" rows mid-group) are visually
   distinct from h2 — slightly smaller but still readable, with a green
   underline rather than a dashed top border, so they don't read as
   afterthoughts. */
.group {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 18px 20px 16px;
  margin-bottom: 18px;
  /* Soft shadow so cards have a subtle floating quality on the dark bg —
     helps the eye separate sections without being noisy. */
  box-shadow: 0 1px 0 rgba(255,255,255,0.02), 0 6px 14px rgba(0,0,0,0.18);
}
.group h2 {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--text);
  margin: 0 0 14px;
  padding: 4px 0 4px 12px;
  border-left: 3px solid var(--accent);
  line-height: 1.25;
}
.group h3 {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 18px 0 8px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  /* Tiny accent dot so subsection breaks visually punctuate without
     competing with the parent h2. */
  display: flex; align-items: center; gap: 8px;
}
.group h3::before {
  content: ''; flex: 0 0 auto;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
  opacity: 0.7;
}
/* First subsection in a group shouldn't get the divider line — it'd float
   right under the h2 and look like a separator-without-purpose. */
.group h3:first-of-type { padding-top: 4px; border-top: none; margin-top: 4px; }

.row {
  display: grid;
  grid-template-columns: 140px 1fr auto;
  grid-template-areas: "label input value";
  align-items: center;
  gap: 10px 12px;
  padding: 9px 0;
  border-bottom: 1px solid rgba(255,255,255,0.03);
}
.row:last-child { border-bottom: none; }
.row__label {
  grid-area: label;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  /* Slight muting only for inactive controls — labels stay readable by default. */
  line-height: 1.3;
  /* Inline-flex so the help-badge sits cleanly next to the label text. */
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.row__value {
  grid-area: value;
  font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums;
  min-width: 48px; text-align: right;
  font-weight: 600;
}

/* ---------- Help badge + hint tooltip ----------
   Hints used to render as always-visible paragraphs below each control,
   eating ~25px of vertical space per row × ~80 controls. Now they live
   inside a small "?" badge on the label and pop up on hover/focus.
   The tooltip is absolute-positioned relative to the badge so it can
   overflow the row without affecting layout. */
.row__help {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 15px; height: 15px;
  border-radius: 50%;
  background: rgba(139,144,160,0.18);
  color: var(--muted);
  font-size: 10px; font-weight: 700;
  line-height: 1;
  cursor: help;
  user-select: none;
  position: relative;
  transition: background 120ms ease, color 120ms ease;
  /* Reset since the wrapping label is itself a flex container with default
     baseline alignment — keep the badge at line-height 0 internally. */
}
.row__help:hover,
.row__help:focus {
  background: rgba(29,185,84,0.25);
  color: var(--accent);
  outline: none;
}
.row__hint {
  /* Tooltip body. Hidden until the badge gets hover/focus. Positioned
     above the badge so it doesn't get clipped by the next row below. */
  display: none;
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: #14161d;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  width: max-content;
  max-width: 320px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text);
  box-shadow: 0 8px 24px rgba(0,0,0,0.5);
  z-index: 100;
  white-space: normal;
  pointer-events: none;
  text-align: left;
  font-weight: 400;
  /* Small caret pointing down toward the badge. */
}
.row__hint::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border: 5px solid transparent;
  border-top-color: var(--border);
}
.row__help:hover .row__hint,
.row__help:focus .row__hint { display: block; }

.row input[type="text"], .row input[type="password"], .row select {
  grid-area: input;
  background: #0c0d11; color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 8px; font-size: 12px; width: 100%;
  transition: border-color 120ms ease;
}
.row input:focus, .row select:focus { outline: none; border-color: var(--accent); }

.row input[type="range"] { grid-area: input; width: 100%; accent-color: var(--accent); }
.row input[type="color"] { grid-area: input; width: 44px; height: 28px; padding: 0;
  background: transparent; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; }
.row input[type="checkbox"] { grid-area: input; justify-self: start; accent-color: var(--accent); width: 18px; height: 18px; }
.row input[type="file"] { grid-area: input; font-size: 11px; color: var(--muted); }

/* ---------- Right pane: preview ---------- */
.pane-preview {
  position: relative;
  background:
    linear-gradient(135deg, #1a1c24 0%, #0f1014 100%);
  display: grid;
  grid-template-rows: auto 1fr;
  overflow: hidden;
}
.preview-header {
  padding: 14px 20px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.preview-header h2 { margin: 0; font-size: 13px; font-weight: 600; color: var(--muted); }
.preview-header button {
  background: var(--accent); color: #0a1a10; border: 0;
  border-radius: 999px; padding: 6px 14px; font-size: 12px; font-weight: 700; cursor: pointer;
  transition: transform 120ms ease, background 120ms ease;
}
.preview-header button:hover { background: var(--accent-2); transform: translateY(-1px); }

.preview-stage {
  position: relative;
  overflow: hidden;
  background-image:
    linear-gradient(45deg, #1a1c24 25%, transparent 25%),
    linear-gradient(-45deg, #1a1c24 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #1a1c24 75%),
    linear-gradient(-45deg, transparent 75%, #1a1c24 75%);
  background-size: 24px 24px;
  background-position: 0 0, 0 12px, 12px -12px, -12px 0;
}
.preview-stage iframe {
  position: absolute; top: 24px; left: 24px;
  border: 0; width: calc(100% - 48px); height: calc(100% - 48px);
  background: transparent;
}

#flash {
  position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%) translateY(10px);
  background: var(--accent); color: #0a1a10; padding: 8px 16px;
  border-radius: 999px; font-size: 12px; font-weight: 600;
  opacity: 0; pointer-events: none; max-width: 80vw;
  transition: opacity 200ms ease, transform 200ms ease;
}
#flash.is-visible { opacity: 1; transform: translateX(-50%) translateY(0); }
#flash.is-error { background: var(--danger); color: #1a0a0a; }

/* ---------- Spotify connect box ---------- */
.row--connect {
  grid-template-columns: 140px 1fr;  /* match .row label column */
  grid-template-areas: "label box";
  align-items: start;
}
.connect-box {
  grid-area: box;
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 12px;
  background: #0c0d11;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.connect-status {
  font-size: 12px; font-weight: 600;
}
.connect-status.is-ok  { color: var(--accent); }
.connect-status.is-off { color: var(--muted); }
.connect-box .btn-primary {
  background: var(--accent); color: #0a1a10; border: 0;
  border-radius: 999px; padding: 8px 16px; font-size: 12px; font-weight: 700;
  cursor: pointer; align-self: flex-start;
  transition: background 120ms ease, transform 80ms ease;
}
.connect-box .btn-primary:hover { background: var(--accent-2); }
.connect-box .btn-primary:active { transform: scale(0.97); }
.connect-box .btn-danger {
  background: transparent; color: var(--danger); border: 1px solid var(--border);
  border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600;
  cursor: pointer; align-self: flex-start;
  transition: border-color 120ms ease;
}
.connect-box .btn-danger:hover { border-color: var(--danger); }
.connect-box code {
  background: rgba(255,255,255,0.06); padding: 1px 4px; border-radius: 3px;
  font-size: 10.5px; word-break: break-all;
}

/* ---------- Stream-platforms picker ----------
   Top-of-form panel where streamers select which platforms they
   broadcast to. Hides the per-role limit sections for unused
   platforms so the dashboard isn't cluttered with knobs they don't
   need. Lives between the warnings strip and the first GROUPS
   section, visually distinct from both. */
.platform-picker {
  margin-bottom: 18px;
  padding: 18px 20px;
  background: var(--panel-2, #14161d);
  border: 1px solid var(--border, #2a2d38);
  border-radius: 14px;
}
.platform-picker__intro {
  margin-bottom: 14px;
}
.platform-picker__title {
  margin: 0 0 4px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text, #e8eaf0);
  letter-spacing: -0.01em;
}
.platform-picker__hint {
  margin: 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted, #8b90a0);
}
.platform-picker__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}
@media (max-width: 480px) {
  .platform-picker__grid { grid-template-columns: repeat(2, 1fr); }
}
/* Each tile: vertically stacked icon → label → check.
   - Inactive: dim background, muted border, faded icon
   - Active:   panel background, accent border, full-color icon, checkmark
   Big click target — whole tile is the button. */
.platform-pick {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px 8px 10px;
  background: rgba(255,255,255,0.02);
  border: 1px solid var(--border, #2a2d38);
  border-radius: 10px;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, transform 80ms ease;
  position: relative;
  /* Reset the default button text-size + family so it matches the form. */
  font-family: inherit;
  color: var(--muted, #8b90a0);
}
.platform-pick:hover {
  background: rgba(255,255,255,0.05);
  border-color: rgba(255,255,255,0.15);
}
.platform-pick:active {
  transform: scale(0.98);
}
.platform-pick.is-active {
  background: rgba(29,185,84,0.08);
  border-color: rgba(29,185,84,0.55);
  color: var(--text, #e8eaf0);
}
.platform-pick__icon {
  display: flex; align-items: center; justify-content: center;
  /* Inactive icons are desaturated so the active picks pop visually. */
  filter: grayscale(0.6) opacity(0.6);
  transition: filter 150ms ease;
}
.platform-pick.is-active .platform-pick__icon {
  filter: none;
}
/* TikTok's brand color is black, which is invisible on the dark
   dashboard. Render as white in the picker so the icon is visible. */
.platform-pick[data-platform="tiktok"] svg.platform-icon { fill: #fff; }
.platform-pick__label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.2px;
}
.platform-pick__check {
  position: absolute;
  top: 6px; right: 8px;
  width: 16px; height: 16px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px;
  font-weight: 800;
  color: #fff;
  background: var(--accent, #1db954);
  /* Hidden when text content is empty (inactive tile). */
}
.platform-pick:not(.is-active) .platform-pick__check {
  display: none;
}
/* "Recent activity" badge — appears on tiles for platforms the widget
   has actually received chat events from in the last 7 days. Helps
   streamers confidently hide platforms they don't use. */
.platform-pick__seen {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: rgba(29,185,84,0.85);
  margin-top: 2px;
  white-space: nowrap;
}

/* Auto-detect suggestion strip — appears below the picker grid when
   recent activity disagrees with the current selection. One-click
   bulk-update. */
.platform-picker__autodetect {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
  padding: 10px 14px;
  background: rgba(29,185,84,0.06);
  border: 1px solid rgba(29,185,84,0.25);
  border-radius: 8px;
  font-size: 12.5px;
  color: var(--text, #e8eaf0);
}
.platform-picker__autodetect-text { flex: 1; line-height: 1.4; }
.platform-picker__autodetect strong { color: var(--accent, #1db954); }

/* ---------- Theme conflict warnings ---------- */
.config-warnings {
  display: flex; flex-direction: column; gap: 6px;
  margin-bottom: 14px;
}
.config-warning {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 8px 12px;
  border-radius: 6px;
  border: 1px solid var(--border);
  font-size: 12px;
  line-height: 1.4;
  background: var(--panel-2);
}
.config-warning.is-error  { border-color: rgba(248,113,113,0.4); background: rgba(248,113,113,0.08); }
.config-warning.is-warn   { border-color: rgba(251,191,36,0.4);  background: rgba(251,191,36,0.06); }
.config-warning.is-info   { border-color: rgba(126,249,255,0.3); background: rgba(126,249,255,0.04); }
.config-warning__icon {
  flex: 0 0 auto;
  width: 18px; height: 18px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800;
  background: rgba(255,255,255,0.06);
}
.config-warning.is-error .config-warning__icon { color: var(--danger); }
.config-warning.is-warn  .config-warning__icon { color: #fbbf24; }
.config-warning.is-info  .config-warning__icon { color: #7ef9ff; }
.config-warning__msg { flex: 1; color: var(--text); }

/* ---------- Static note ----------
   Inline explanatory text within a group. Bumped contrast + size so the
   note actually reads as setup guidance instead of fading into the gap
   between rows. */
/* Was: full-width green note paragraph eating ~70px per occurrence.
   Now: tiny "ⓘ Note" pill (~22px tall) that reveals the full text as a
   tooltip on hover/focus. Same info, much denser config. */
.row--note {
  display: block;
  grid-template-columns: 1fr;
  grid-template-areas: "note";
  padding: 0 0 6px 0;
  border-bottom: none;
}
.note-pill {
  display: inline-flex;
  align-items: center; gap: 4px;
  background: rgba(29,185,84,0.10);
  border: 1px solid rgba(29,185,84,0.28);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 10.5px; font-weight: 600;
  color: var(--accent-2);
  cursor: help;
  position: relative;
  user-select: none;
}
.note-pill .note {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  background: #14161d;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  width: max-content;
  max-width: 360px;
  font-size: 12px; font-weight: 400;
  color: var(--text);
  line-height: 1.5;
  box-shadow: 0 8px 24px rgba(0,0,0,0.5);
  z-index: 100;
  white-space: normal;
  pointer-events: none;
  text-align: left;
}
.note-pill:hover .note,
.note-pill:focus .note { display: block; }
/* Legacy .row--note .note rule kept below as fallback (some widgets may
   still ship the old paragraph form during transition); the tooltip
   form above wins via specificity for new renders. */
.row--note .note-block-fallback {
  grid-area: note;
  background: rgba(29,185,84,0.08);
  border: 1px solid rgba(29,185,84,0.28);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 12.5px;
  color: var(--text);
  line-height: 1.5;
}
.row--note .note strong { color: var(--accent-2); }

/* ---------- Collab list ---------- */
.row--collab { grid-template-columns: 140px 1fr; grid-template-areas: "label box"; align-items: start; }
.collab-box {
  grid-area: box;
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px;
  background: #0c0d11;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.collab-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.collab-item {
  display: grid;
  grid-template-columns: 1fr 1.4fr auto;
  gap: 6px;
}
.collab-item input {
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 8px; font-size: 12px;
  font-family: inherit;
}
.collab-item input:focus { outline: none; border-color: var(--accent); }
.collab-remove {
  background: transparent; color: var(--muted); border: 1px solid var(--border);
  border-radius: 6px; padding: 0 10px; font-size: 12px; cursor: pointer;
  transition: all 120ms ease;
}
.collab-remove:hover { color: var(--danger); border-color: var(--danger); }
.collab-empty { color: var(--muted); font-size: 12px; font-style: italic; padding: 4px 0; }
.collab-box .btn-primary {
  background: var(--accent); color: #0a1a10; border: 0;
  padding: 8px 14px; border-radius: 6px; font-size: 12px; font-weight: 700;
  cursor: pointer; align-self: flex-start;
}

/* ---------- List (textarea) input ---------- */
.row--list {
  grid-template-columns: 120px 1fr;
  grid-template-areas: "label input";
  align-items: start;
}
.row--list textarea {
  grid-area: input;
  background: #0c0d11; color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 8px; font-size: 12px; width: 100%;
  font-family: ui-monospace, monospace;
  resize: vertical;
  transition: border-color 120ms ease;
}
.row--list textarea:focus { outline: none; border-color: var(--accent); }

/* ---------- Spotify "Connected as" profile badge ----------
   Sits between the Connected pill and the action buttons in the Spotify
   connect row. Two variants — green-tinted for happy path, amber-tinted
   when /me failed (Dev Mode allowlist miss is the canonical case). The
   sub-line shows extra metadata (Spotify ID, premium status, country)
   so streamers can verify against the Users and Access dashboard at a
   glance. */
.sp-profile-badge {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 12.5px;
  line-height: 1.4;
  margin: 6px 0;
}
.sp-profile-badge__label { color: var(--text); }
.sp-profile-badge__sub   { color: var(--muted); font-size: 11.5px; }
.sp-profile-badge__sub code {
  background: rgba(255,255,255,0.06);
  padding: 1px 5px;
  border-radius: 4px;
  font-family: ui-monospace, monospace;
  font-size: 11px;
}
.sp-profile-badge--ok {
  background: rgba(29,185,84,0.10);
  border: 1px solid rgba(29,185,84,0.30);
}
.sp-profile-badge--err {
  background: rgba(251,191,36,0.10);
  border: 1px solid rgba(251,191,36,0.40);
}
.sp-profile-badge--err .sp-profile-badge__label { color: #fbbf24; font-weight: 600; }

/* ---------- Collapsible groups ----------
   Each .group section's <h2> is a click target — toggles .is-collapsed
   on the parent which hides every direct child except the heading
   itself. Chevron rotates 90deg when collapsed for the affordance
   cue. The "click to collapse" hint fades in on hover so it's not
   busy the rest of the time. */
.group h2 {
  display: flex;
  align-items: center;
  gap: 8px;
  user-select: none;
  transition: color 120ms ease;
}
.group h2:hover { color: var(--accent-2); }
.group__chevron {
  display: inline-block;
  font-size: 12px;
  color: var(--muted);
  transition: transform 200ms ease, color 120ms ease;
  width: 14px; text-align: center;
}
.group__hint {
  font-size: 10.5px;
  color: var(--muted);
  font-weight: 400;
  letter-spacing: 0;
  margin-left: auto;
  opacity: 0;
  transition: opacity 160ms ease;
}
.group h2:hover .group__hint { opacity: 0.8; }
.group.is-collapsed .group__chevron { transform: rotate(-90deg); }
.group.is-collapsed .group__hint::before { content: 'click to expand'; }
.group.is-collapsed .group__hint { opacity: 0.5; }
/* Hide everything in the group except the heading when collapsed.
   The heading itself stays visible + clickable for re-expand. */
.group.is-collapsed > *:not(h2) { display: none; }

/* ---------- Preview-header Test ▾ dropdown ----------
   Lives in the preview pane's header next to "Live preview" — same
   spot the original "Trigger Requested by popup" button occupied.
   Streamers explicitly asked for the buttons here (not in the main
   topbar) so they're co-located with the iframe they affect. The
   dropdown closes on outside click and after each trigger fire. */
.preview-header__test-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  background: #14161d;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px;
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.55);
  display: grid;
  grid-template-columns: repeat(2, minmax(140px, 1fr));
  gap: 6px;
  z-index: 200;
  min-width: 320px;
}
.preview-header__test-menu[hidden] { display: none; }
.preview-header__test-menu button {
  background: #0c0d11;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  padding: 7px 10px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: border-color 120ms ease, background 120ms ease;
  text-align: left;
}
.preview-header__test-menu button:hover {
  border-color: var(--accent);
  background: rgba(29, 185, 84, 0.08);
}
.preview-header__test-menu button.btn-danger {
  border-color: rgba(239, 68, 68, 0.35);
  color: #fecaca;
}
.preview-header__test-menu button.btn-danger:hover {
  border-color: #ef4444;
  background: rgba(239, 68, 68, 0.12);
}

/* ---------- Auto-save indicator ----------
   Tiny pill that fades in on save and fades out 1.5s later. Anchored
   bottom-right so it doesn't fight with the topbar / scroll position.
   Pure visual reassurance — the underlying saveWithHistory was always
   eager. */
.autosave-indicator {
  position: fixed;
  bottom: 16px;
  right: 16px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  background: rgba(15, 16, 22, 0.92);
  border: 1px solid rgba(29, 185, 84, 0.45);
  border-radius: 999px;
  color: var(--text);
  font-size: 12px;
  font-weight: 600;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 200ms ease, transform 200ms ease;
  pointer-events: none;
  z-index: 1000;
}
.autosave-indicator.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.autosave-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px rgba(29, 185, 84, 0.6);
}

/* ---------- Test triggers panel ----------
   Grid of buttons that fire mock events into the preview iframe so
   streamers can verify popup positioning / styling without real chat
   traffic. */
.row--test-triggers {
  grid-template-columns: 120px 1fr;
  grid-template-areas: "label box";
  align-items: start;
}
.test-triggers-box {
  grid-area: box;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.test-triggers-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 6px;
}
.test-triggers-grid button {
  background: #14161d;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  padding: 7px 10px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
  font-family: inherit;
}
.test-triggers-grid button:hover {
  border-color: var(--accent);
  background: rgba(29, 185, 84, 0.08);
}
.test-triggers-grid button.btn-danger {
  border-color: rgba(239, 68, 68, 0.35);
  color: #fecaca;
}
.test-triggers-grid button.btn-danger:hover {
  border-color: #ef4444;
  background: rgba(239, 68, 68, 0.12);
}

/* ---------- Loadout connect ---------- */
.row--loadout-connect {
  grid-template-columns: 120px 1fr;
  grid-template-areas: "label box";
  align-items: start;
}
.loadout-connect-box {
  grid-area: box;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.loadout-test-status {
  font-size: 12px;
  font-weight: 600;
  padding: 6px 10px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: #0c0d11;
  color: var(--muted);
}
.loadout-test-status.is-ok      { color: var(--accent-2); border-color: rgba(29,185,84,0.4); background: rgba(29,185,84,0.08); }
.loadout-test-status.is-err     { color: #fecaca;        border-color: rgba(239,68,68,0.4);  background: rgba(239,68,68,0.08); }
.loadout-test-status.is-pending { color: #93c5fd;        border-color: rgba(59,130,246,0.4);  background: rgba(59,130,246,0.08); }

/* ---------- Streamer.bot rewards picker ---------- */
.row--sb-rewards { grid-template-columns: 120px 1fr; grid-template-areas: "label box"; align-items: start; }
.sb-rewards-box { grid-area: box; display: flex; flex-direction: column; gap: 10px; }
.sb-rewards-controls { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.sb-rewards-status {
  font-size: 12px; font-weight: 600;
  color: var(--muted);
}
.sb-rewards-status.is-ok      { color: var(--accent-2); }
.sb-rewards-status.is-err     { color: #fecaca; }
.sb-rewards-status.is-pending { color: #93c5fd; }
.sb-rewards-list:empty { display: none; }
.sb-rewards-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: #0c0d11;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px;
  max-height: 280px;
  overflow-y: auto;
}
.sb-reward-item {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  gap: 10px;
  align-items: center;
  padding: 6px 10px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 80ms ease;
  font-size: 13px;
}
.sb-reward-item:hover { background: rgba(255,255,255,0.04); }
.sb-reward-item.is-disabled { opacity: 0.55; }
.sb-reward-item input { margin: 0; }
.sb-reward-item__title { color: var(--text); font-weight: 600; }
.sb-reward-item__cost  { color: var(--muted); font-size: 11px; font-weight: 600; font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace; }
.sb-reward-item__disabled {
  font-size: 10px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
  color: var(--muted);
  background: rgba(255,255,255,0.06);
  padding: 2px 6px; border-radius: 4px;
}

/* ---------- Canvas resolver test ---------- */
.row--canvas-test { grid-template-columns: 120px 1fr; grid-template-areas: "label box"; align-items: start; }
.canvas-test-box { grid-area: box; display: flex; flex-direction: column; gap: 8px; }
.canvas-test-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.canvas-test-status {
  font-size: 12px; font-weight: 600;
  color: var(--muted);
  flex: 1; min-width: 0;
}
.canvas-test-status.is-ok      { color: var(--accent-2); }
.canvas-test-status.is-err     { color: #fecaca; }
.canvas-test-status.is-pending { color: #93c5fd; }

/* ---------- Discord pre-queue puller ---------- */
.row--prequeue-pull { grid-template-columns: 120px 1fr; grid-template-areas: "label box"; align-items: start; }
.prequeue-pull-box { grid-area: box; display: flex; flex-direction: column; gap: 8px; }
.prequeue-pull-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.prequeue-pull-status {
  font-size: 12px; font-weight: 600;
  color: var(--muted);
}
.prequeue-pull-status.is-ok      { color: var(--accent-2); }
.prequeue-pull-status.is-err     { color: #fecaca; }
.prequeue-pull-status.is-pending { color: #93c5fd; }

/* ---------- Pre-stream Discord poll ---------- */
.row--prestream-options,
.row--prestream-btns { grid-template-columns: 120px 1fr; grid-template-areas: "label box"; align-items: start; }
.prestream-options-box,
.prestream-btns-box { grid-area: box; display: flex; flex-direction: column; gap: 8px; }
.prestream-options-list {
  list-style: none;
  margin: 0;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: #0c0d11;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.prestream-option {
  display: grid;
  grid-template-columns: 64px 1fr 28px;
  gap: 8px;
  align-items: center;
}
.prestream-option input {
  background: #14161d;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  padding: 6px 8px;
  font: inherit;
  font-size: 13px;
}
.prestream-option .prestream-emoji {
  text-align: center;
  font-size: 16px;
}
.prestream-remove {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--muted);
  width: 28px; height: 28px;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 14px;
}
.prestream-remove:hover { color: #fecaca; border-color: rgba(239,68,68,0.4); background: rgba(239,68,68,0.08); }
.prestream-btns-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.prestream-status { font-size: 12px; font-weight: 600; color: var(--muted); }
.prestream-status.is-ok      { color: var(--accent-2); }
.prestream-status.is-err     { color: #fecaca; }
.prestream-status.is-pending { color: #93c5fd; }

/* ---------- Live Discord status manual buttons ---------- */
.row--live-status { grid-template-columns: 120px 1fr; grid-template-areas: "label box"; align-items: start; }
.live-status-box { grid-area: box; display: flex; flex-direction: column; gap: 8px; }
.live-status-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.live-status-text {
  font-size: 12px; font-weight: 600;
  color: var(--muted);
}
.live-status-text.is-ok      { color: var(--accent-2); }
.live-status-text.is-err     { color: #fecaca; }
.live-status-text.is-pending { color: #93c5fd; }

/* ---------- Mod link copy button ---------- */
.row--mod-link { grid-template-columns: 120px 1fr; grid-template-areas: "label box"; align-items: start; }
.mod-link-box { grid-area: box; display: flex; flex-direction: column; gap: 8px; }
.mod-link-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.mod-link-status {
  font-size: 12px; font-weight: 600;
  color: var(--muted);
}
.mod-link-status.is-ok  { color: var(--accent-2); }
.mod-link-status.is-err { color: #fecaca; }

/* ---------- Discord test ---------- */
.row--discord-test { grid-template-columns: 120px 1fr; grid-template-areas: "label box"; align-items: start; }
.discord-test-box  { grid-area: box; display: flex; flex-direction: column; gap: 8px; }
.discord-test-status {
  font-size: 12px; font-weight: 600;
  padding: 6px 10px; border-radius: 6px;
  border: 1px solid var(--border); background: #0c0d11;
  color: var(--muted);
  min-height: 28px; box-sizing: border-box;
}
.discord-test-status.is-ok      { color: var(--accent-2); border-color: rgba(29,185,84,0.4); background: rgba(29,185,84,0.08); }
.discord-test-status.is-err     { color: #fecaca;        border-color: rgba(239,68,68,0.4);  background: rgba(239,68,68,0.08); }
.discord-test-status.is-pending { color: #93c5fd;        border-color: rgba(59,130,246,0.4);  background: rgba(59,130,246,0.08); }
/* Empty state — collapse the status row when nothing has been said yet
   so the box doesn't look broken. :empty matches when textContent ''. */
.discord-test-status:empty { display: none; }
.loadout-test-status:empty { display: none; }

/* ---------- Quotas list ----------
   Structured editor for genre/mood quotas — name, comma-separated keywords,
   max-per-stream, remove. Mirrors the .row--collab pattern so the visual
   weight reads as the same kind of "list of records" control. */
.row--quotas {
  grid-template-columns: 120px 1fr;
  grid-template-areas: "label box";
  align-items: start;
}
.quotas-box { grid-area: box; }
.quotas-list {
  list-style: none; padding: 0; margin: 0 0 8px 0;
  display: flex; flex-direction: column; gap: 6px;
}
.quotas-item {
  display: grid;
  grid-template-columns: 1fr 2fr 70px 28px;
  gap: 6px;
  align-items: center;
}
.quotas-item input {
  background: #0c0d11; color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 8px; font-size: 12px; min-width: 0;
  transition: border-color 120ms ease;
}
.quotas-item input:focus { outline: none; border-color: var(--accent); }
.quotas-name        { font-weight: 600; }
.quotas-keywords    { font-family: ui-monospace, monospace; font-size: 11.5px; }
.quotas-max         { text-align: center; }
.quotas-remove {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--muted);
  font-size: 13px; line-height: 1; cursor: pointer;
  width: 28px; height: 28px;
  transition: border-color 120ms ease, color 120ms ease;
}
.quotas-remove:hover { border-color: #ef4444; color: #fecaca; }
.quotas-empty {
  font-size: 11.5px; color: var(--muted);
  font-style: italic;
  padding: 8px 0;
}

/* ---------- Censor preview ----------
   Side-by-side sample-input / live-output showing what viewers will see
   on stream. Pairs visually with .row--list above it (same label column,
   same hint span) so it reads as part of the censor cluster, not a
   separate concept. */
.row--censor-preview {
  grid-template-columns: 120px 1fr;
  grid-template-areas: "label preview";
  align-items: start;
}
.row--censor-preview .censor-preview {
  grid-area: preview;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.censor-preview__sub {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}
.censor-preview__input {
  width: 100%;
  background: #0c0d11; color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 8px 10px;
  font-family: inherit; font-size: 12.5px; line-height: 1.4;
  resize: vertical;
  transition: border-color 120ms ease;
}
.censor-preview__input:focus { outline: none; border-color: var(--accent); }
.censor-preview__output {
  min-height: 100%;
  background: rgba(15,15,18,0.6);
  border: 1px dashed rgba(29,185,84,0.35);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 12.5px; line-height: 1.4;
  color: var(--text);
  white-space: pre-wrap;
  word-break: break-word;
}

/* ---------- Analytics panel ---------- */
.row--analytics {
  grid-template-columns: 120px 1fr;
  grid-template-areas: "label box";
  align-items: start;
}
.analytics-box {
  grid-area: box;
  display: flex; flex-direction: column; gap: 14px;
  padding: 12px;
  background: #0c0d11;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.analytics-section__title {
  font-size: 10px; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--muted); font-weight: 700; margin-bottom: 6px;
}
.analytics-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 2px;
  counter-reset: analytics;
}
.analytics-list li {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 0;
  font-size: 12px;
  border-bottom: 1px dashed rgba(255,255,255,0.05);
}
.analytics-list li:last-child { border-bottom: 0; }
.analytics-list strong {
  font-weight: 500; color: var(--text);
  max-width: 180px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.analytics-list span { color: var(--muted); font-variant-numeric: tabular-nums; }
.analytics-empty { color: var(--muted); font-size: 12px; font-style: italic; }
.analytics-box .btn-small {
  background: transparent; color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 5px 10px; font-size: 11px; cursor: pointer;
  align-self: flex-start;
  transition: border-color 120ms ease;
}
.analytics-box .btn-small:hover { border-color: var(--accent); }
.analytics-box .btn-small.btn-danger { color: var(--danger); }
.analytics-box .btn-small.btn-danger:hover { border-color: var(--danger); }

/* ---------- Topbar row split (2026-06 reflow) ----------
   The topbar now holds a single launch row by default; legacy `.topbar__obs`
   wrapper has been replaced by an inline flex layout so the OBS URL never
   gets squashed against the StreamFusion/Refresh buttons. Setup-only
   actions (Connect to StreamFusion, Refresh OBS sources) moved into a
   "More ▾" menu so they're discoverable without crowding the row. */
.topbar__row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  width: 100%;
}
.topbar__more { position: relative; margin-left: 4px; }
.topbar__kebab {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 5px 10px; font-size: 11.5px; font-weight: 600;
  cursor: pointer;
  transition: border-color 120ms ease;
}
.topbar__kebab:hover, .topbar__kebab[aria-expanded="true"] { border-color: var(--accent); }
.topbar__menu {
  position: absolute; right: 0; top: calc(100% + 6px);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px;
  box-shadow: 0 12px 28px rgba(0,0,0,0.35);
  display: flex; flex-direction: column; min-width: 220px;
  z-index: 80;
}
.topbar__menu button {
  background: transparent; color: var(--text);
  border: 0; text-align: left;
  padding: 8px 10px; font-size: 12px; font-weight: 500;
  border-radius: 4px; cursor: pointer;
  transition: background 120ms ease;
}
.topbar__menu button:hover { background: rgba(29,185,84,0.12); color: var(--accent); }
.topbar__menu button:disabled { color: var(--muted); cursor: not-allowed; opacity: 0.6; }
.topbar__menu button:disabled:hover { background: transparent; color: var(--muted); }

/* Patreon pill stops auto-pushing right since the row now wraps cleanly. */
.topbar__row .topbar__patreon { margin-left: auto; }

/* ---------- Left TOC rail ---------- */
.pane-toc {
  background: var(--panel);
  border-right: 1px solid var(--border);
  overflow-y: auto;
  padding: 14px 8px 24px;
}
.pane-toc__close {
  display: none;
  background: transparent; color: var(--muted);
  border: 0; font-size: 18px; padding: 4px 8px;
  cursor: pointer;
}
.toc-rail__heading {
  font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.8px;
  color: var(--muted);
  margin: 6px 10px 10px;
}
.toc-rail__nav { display: flex; flex-direction: column; gap: 2px; }
.toc__group { display: flex; flex-direction: column; gap: 1px; margin-bottom: 4px; }
.toc__link {
  display: block;
  padding: 6px 10px;
  color: var(--muted);
  text-decoration: none;
  font-size: 12px;
  border-radius: 6px;
  border-left: 2px solid transparent;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
  cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.toc__link--group { font-weight: 600; color: var(--text); }
.toc__link--sub {
  padding-left: 22px;
  font-size: 11.5px;
}
.toc__link:hover { background: rgba(255,255,255,0.04); color: var(--text); }
.toc__link.is-active {
  background: rgba(29,185,84,0.12);
  color: var(--accent);
  border-left-color: var(--accent);
}
.toc__subs { display: flex; flex-direction: column; gap: 1px; }

/* Floating TOC button — appears on narrow viewports where the rail is
   off-canvas; opens the rail as an overlay. */
.toc-fab {
  position: fixed; bottom: 18px; left: 18px;
  background: var(--accent); color: #0a1a10;
  border: 0; border-radius: 999px;
  padding: 10px 16px; font-size: 12px; font-weight: 700;
  cursor: pointer; z-index: 70;
  box-shadow: 0 6px 18px rgba(0,0,0,0.4);
}
@media (max-width: 1100px) {
  .pane-toc {
    position: fixed; inset: 0 auto 0 0;
    width: 240px; max-width: 80vw;
    transform: translateX(-100%);
    transition: transform 200ms ease;
    z-index: 75;
    box-shadow: 0 0 40px rgba(0,0,0,0.5);
  }
  .pane-toc.is-open { transform: translateX(0); }
  .pane-toc__close { display: block; margin-left: auto; }
  .toc-fab { display: block; }
}
@media (min-width: 1101px) {
  .toc-fab { display: none !important; }
}

/* ---------- Subgroup accordions ----------
   Each `{ section: 'X' }` marker inside a group is now its own collapsible
   card. The h3 head looks intentionally smaller than the parent h2 so the
   visual hierarchy stays clear, and the chevron rotates 90deg when
   collapsed (same gesture as the parent group). */
.subgroup {
  margin: 14px 0 0;
  padding: 12px 14px 4px;
  background: rgba(255,255,255,0.018);
  border: 1px solid rgba(255,255,255,0.05);
  border-radius: 10px;
  transition: background 120ms ease, border-color 120ms ease;
}
.subgroup:first-of-type { margin-top: 6px; }
.subgroup:hover { background: rgba(255,255,255,0.03); }
.subgroup__head {
  margin: 0 -4px 6px;
  padding: 6px 6px 6px 4px;
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 700;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--accent);
  border-top: none;        /* override .group h3 dashed border */
  user-select: none;
  border-radius: 6px;
  transition: background 120ms ease;
}
.subgroup__head:hover { background: rgba(29,185,84,0.08); }
.subgroup__head::before {
  /* Hide the inherited .group h3::before bullet — chevron does the work. */
  display: none !important;
}
.subgroup__chevron {
  display: inline-block;
  width: 12px; text-align: center;
  font-size: 10px;
  color: var(--muted);
  transition: transform 200ms ease;
}
.subgroup.is-collapsed .subgroup__chevron { transform: rotate(-90deg); }
.subgroup__label { flex: 1 1 auto; }
.subgroup__body {
  padding-bottom: 6px;
  display: block;
}
.subgroup.is-collapsed .subgroup__body { display: none; }

/* Drop the legacy "click to collapse" hint span. We removed the span from
   the heading template but keep the rule scoped so any cached HTML still
   has the cue hidden. */
.group__hint { display: none !important; }

/* ---------- Setup checklist card ---------- */
.setup-card {
  background: linear-gradient(135deg, rgba(29,185,84,0.08), rgba(29,185,84,0.02));
  border: 1px solid rgba(29,185,84,0.25);
  border-radius: 12px;
  padding: 14px 16px 12px;
  margin-bottom: 16px;
  transition: background 200ms ease, border-color 200ms ease;
}
.setup-card.is-complete {
  background: rgba(29,185,84,0.04);
  border-color: rgba(29,185,84,0.18);
  padding: 8px 14px;
}
.setup-card.is-complete .setup-card__list { display: none; }
.setup-card__header {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 10px;
}
.setup-card.is-complete .setup-card__header { margin-bottom: 0; }
.setup-card__title { display: flex; align-items: center; gap: 10px; flex: 1 1 auto; }
.setup-card__badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--accent); color: #0a1a10;
  font-size: 11px; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.setup-card.is-complete .setup-card__badge { background: rgba(29,185,84,0.3); color: var(--accent); }
.setup-card__heading { font-size: 14px; font-weight: 700; color: var(--text); }
.setup-card__dismiss {
  background: transparent; color: var(--muted);
  border: 0; font-size: 18px; line-height: 1; padding: 2px 8px;
  cursor: pointer; border-radius: 6px;
  transition: background 120ms ease, color 120ms ease;
}
.setup-card__dismiss:hover { background: rgba(255,255,255,0.05); color: var(--text); }
.setup-card__list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.setup-card__item {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: rgba(255,255,255,0.02);
  border-radius: 8px;
  font-size: 12.5px;
  color: var(--text);
}
.setup-card__item.is-done { color: var(--muted); }
.setup-card__check {
  display: inline-block; text-align: center;
  width: 18px; height: 18px;
  line-height: 18px;
  font-weight: 800;
  color: var(--accent);
}
.setup-card__item:not(.is-done) .setup-card__check { color: var(--muted); }
.setup-card__label { font-weight: 500; }
.setup-card__item.is-done .setup-card__label { text-decoration: line-through; opacity: 0.7; }
.setup-card__jump {
  background: var(--accent); color: #0a1a10;
  border: 0; border-radius: 999px;
  padding: 4px 10px; font-size: 11px; font-weight: 700;
  cursor: pointer;
  transition: filter 120ms ease;
}
.setup-card__jump:hover { filter: brightness(1.1); }
.setup-card__hint {
  grid-column: 2 / -1;
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 2px;
}

/* ---------- Search hit count ---------- */
.cfg-search-meta {
  font-size: 10.5px;
  color: var(--muted);
  margin-left: 6px;
  white-space: nowrap;
}
.cfg-search-meta.is-warning { color: var(--danger); }

/* Search force-open — when a search query matches a control inside a
   collapsed group/subgroup, transparently expand it so the streamer
   doesn't have to manually un-collapse every section to see hits. */
.group.is-collapsed.search-force-open > *:not(h2) { display: revert; }
.subgroup.is-collapsed.search-force-open > .subgroup__body { display: block; }

/* ---------- Theme-mode segmented cards ---------- */
.row--theme-mode {
  grid-template-columns: 140px 1fr;
  grid-template-areas: "label box";
  align-items: start;
}
.theme-mode {
  grid-area: box;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
@media (max-width: 760px) {
  .theme-mode { grid-template-columns: 1fr; }
}
.theme-mode__card {
  background: rgba(255,255,255,0.025);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  text-align: left;
  cursor: pointer;
  display: flex; flex-direction: column; gap: 6px;
  transition: border-color 120ms ease, background 120ms ease, transform 80ms ease;
}
.theme-mode__card:hover {
  border-color: rgba(29,185,84,0.4);
  background: rgba(29,185,84,0.05);
}
.theme-mode__card:active { transform: scale(0.98); }
.theme-mode__card.is-active {
  border-color: var(--accent);
  background: rgba(29,185,84,0.12);
  box-shadow: 0 0 0 1px rgba(29,185,84,0.35) inset;
}
.theme-mode__label {
  font-weight: 700; font-size: 13px;
  color: var(--text);
}
.theme-mode__card.is-active .theme-mode__label { color: var(--accent); }
.theme-mode__blurb {
  font-size: 11.5px;
  color: var(--muted);
  line-height: 1.45;
}

/* ---------- Per-platform role matrix ---------- */
.row--role-matrix {
  /* Role matrix is wide; give the box more horizontal room by collapsing
     the row label to a slim column. The label is still readable but the
     matrix table reclaims ~50px. */
  grid-template-columns: 90px 1fr;
  grid-template-areas: "label box";
  align-items: start;
}
.role-matrix {
  grid-area: box;
  display: flex; flex-direction: column; gap: 10px;
  background: rgba(255,255,255,0.02);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
}
.role-matrix__empty {
  grid-area: box;
  color: var(--muted);
  font-size: 12px;
  font-style: italic;
}
.role-matrix__tabs {
  display: flex; flex-wrap: wrap; gap: 4px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
}
.role-matrix__tab {
  background: transparent;
  color: var(--muted);
  border: 1px solid transparent;
  border-radius: 6px 6px 0 0;
  padding: 6px 12px;
  font-size: 12px; font-weight: 600;
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
}
.role-matrix__tab:hover { color: var(--text); background: rgba(255,255,255,0.03); }
.role-matrix__tab.is-active {
  color: var(--accent);
  background: rgba(29,185,84,0.10);
  border-color: rgba(29,185,84,0.35);
  border-bottom-color: transparent;
}
.role-matrix__enable {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 4px 8px;
  font-size: 12.5px;
  color: var(--text);
  padding: 4px 0;
  cursor: pointer;
}
.role-matrix__enable input { margin: 0; accent-color: var(--accent); width: 16px; height: 16px; }
.role-matrix__enable-hint {
  grid-column: 2;
  font-size: 11px;
  color: var(--muted);
  font-weight: 400;
  line-height: 1.4;
}
.role-matrix__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}
.role-matrix__table.is-disabled { opacity: 0.45; }
.role-matrix__table thead th {
  text-align: left;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--muted);
  font-weight: 700;
  padding: 6px 4px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.role-matrix__table thead th:not(:first-child) { text-align: center; }
.role-matrix__table tbody td,
.role-matrix__table tbody th {
  padding: 6px 4px;
  border-bottom: 1px solid rgba(255,255,255,0.03);
}
.role-matrix__table tbody tr:last-child td,
.role-matrix__table tbody tr:last-child th { border-bottom: 0; }
.role-matrix__role {
  text-align: left;
  font-weight: 600;
  color: var(--text);
  display: flex; align-items: center; gap: 6px;
}
.role-matrix__row.is-blocked .role-matrix__role { color: var(--danger); }
.role-matrix__blocked-tag {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-weight: 700;
  color: var(--danger);
  background: rgba(248,113,113,0.12);
  border: 1px solid rgba(248,113,113,0.3);
  border-radius: 4px;
  padding: 1px 6px;
}
.role-matrix__cell {
  text-align: center;
  vertical-align: middle;
}
.role-matrix__cell--cap input,
.role-matrix__cell--cd input {
  width: 48px;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 4px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.role-matrix__cell--cd input { width: 52px; }
.role-matrix__cell--cap input:focus,
.role-matrix__cell--cd input:focus {
  outline: none; border-color: var(--accent);
}
.role-matrix__cell--cd { white-space: nowrap; }
.role-matrix__suffix {
  margin-left: 4px;
  font-size: 10.5px;
  color: var(--muted);
}
.role-matrix__cell--prio input[type="checkbox"] {
  width: 18px; height: 18px;
  accent-color: var(--accent);
}
.role-matrix__hint-note {
  font-size: 11px;
  color: var(--muted);
  font-style: italic;
  padding: 2px 0 0;
}
.role-matrix__row.is-disabled .role-matrix__cell input {
  cursor: not-allowed;
  opacity: 0.55;
}

/* ---------- Auto-detect button + status ---------- */
.row--detect {
  grid-template-columns: 140px 1fr;
  grid-template-areas: "label box";
  align-items: center;
}
.detect-box {
  grid-area: box;
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap;
}
.detect-btn {
  background: var(--accent); color: #0a1a10;
  border: 0; border-radius: 999px;
  padding: 6px 14px; font-size: 12px; font-weight: 700;
  cursor: pointer;
  transition: filter 120ms ease, transform 80ms ease;
}
.detect-btn:hover:not(:disabled) { filter: brightness(1.1); }
.detect-btn:active:not(:disabled) { transform: scale(0.97); }
.detect-btn:disabled {
  background: var(--panel-2); color: var(--muted);
  cursor: progress;
  opacity: 0.7;
}
.detect-status {
  font-size: 11.5px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--muted);
}
.detect-status[data-status="probing"] {
  color: var(--accent);
  border-color: rgba(29,185,84,0.35);
  background: rgba(29,185,84,0.08);
}
.detect-status[data-status="ok"] {
  color: var(--accent);
  border-color: rgba(29,185,84,0.5);
  background: rgba(29,185,84,0.14);
}
.detect-status[data-status="err"] {
  color: var(--danger);
  border-color: rgba(248,113,113,0.4);
  background: rgba(248,113,113,0.08);
}

/* ---------- Setlist export ---------- */
.row--setlist {
  grid-template-columns: 140px 1fr;
  grid-template-areas: "label box";
  align-items: start;
}
.setlist-box {
  grid-area: box;
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px 14px;
  background: rgba(255,255,255,0.02);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.setlist-box__counts {
  font-size: 12.5px;
  color: var(--text);
  line-height: 1.5;
}
.setlist-box__counts strong {
  color: var(--accent);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.setlist-box__counts em {
  display: block;
  color: var(--muted);
  font-style: italic;
  font-size: 11.5px;
  margin-top: 2px;
}
.setlist-box__btns {
  display: flex; flex-wrap: wrap; gap: 8px;
}
.setlist-box__btns .btn-primary {
  background: var(--accent); color: #0a1a10;
  border: 0; border-radius: 999px;
  padding: 7px 16px; font-size: 12.5px; font-weight: 700;
  cursor: pointer;
  transition: filter 120ms ease, transform 80ms ease;
}
.setlist-box__btns .btn-primary:hover:not(:disabled) { filter: brightness(1.1); }
.setlist-box__btns .btn-primary:active:not(:disabled) { transform: scale(0.97); }
.setlist-box__btns .btn-primary:disabled {
  background: var(--panel-2); color: var(--muted);
  cursor: not-allowed; opacity: 0.6;
}
.setlist-box__status {
  font-size: 11.5px;
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--panel-2);
  color: var(--muted);
  min-height: 22px;
}
.setlist-box__status:empty { display: none; }
.setlist-box__status[data-state="working"] { color: var(--accent); background: rgba(29,185,84,0.08); }
.setlist-box__status[data-state="ok"]      { color: var(--accent); background: rgba(29,185,84,0.14); }
.setlist-box__status[data-state="err"]     { color: var(--danger); background: rgba(248,113,113,0.10); }
.setlist-box__last {
  font-size: 11.5px;
  color: var(--muted);
  word-break: break-all;
}
.setlist-box__last span { color: var(--text); font-weight: 600; margin-right: 4px; }
.setlist-box__last a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px dashed rgba(29,185,84,0.4);
}
.setlist-box__last a:hover { border-bottom-color: var(--accent); }

/* ---------- Streamer.bot import buttons ---------- */
.row--sb-import {
  grid-template-columns: 140px 1fr;
  grid-template-areas: "label box";
  align-items: start;
}
.sb-import-box {
  grid-area: box;
  display: flex; flex-direction: column; gap: 8px;
}
.sb-import-box__btns { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.sb-import-box .btn-primary {
  background: var(--accent); color: #0a1a10;
  border: 0; border-radius: 999px;
  padding: 7px 16px; font-size: 12.5px; font-weight: 700;
  cursor: pointer; transition: filter 120ms ease, transform 80ms ease;
}
.sb-import-box .btn-primary:hover { filter: brightness(1.1); }
.sb-import-box .btn-primary:active { transform: scale(0.97); }
.sb-import-box .btn-ghost {
  background: transparent; color: var(--text);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 6px 14px; font-size: 12.5px; font-weight: 600;
  cursor: pointer; text-decoration: none;
  transition: border-color 120ms ease;
}
.sb-import-box .btn-ghost:hover { border-color: var(--accent); }
.sb-import-box__status {
  font-size: 11.5px; padding: 5px 10px; border-radius: 6px;
  background: var(--panel-2); color: var(--muted);
}
.sb-import-box__status:empty { display: none; }
.sb-import-box__status[data-state="working"] { color: var(--accent); background: rgba(29,185,84,0.08); }
.sb-import-box__status[data-state="ok"]      { color: var(--accent); background: rgba(29,185,84,0.14); }
.sb-import-box__status[data-state="err"]     { color: var(--danger); background: rgba(248,113,113,0.10); }

/* ---------- Streamer.bot test-send ---------- */
.row--sb-test {
  grid-template-columns: 140px 1fr;
  grid-template-areas: "label box";
  align-items: center;
}
.sb-test-box { grid-area: box; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.sb-test-box .btn-primary {
  background: var(--accent); color: #0a1a10;
  border: 0; border-radius: 999px;
  padding: 7px 16px; font-size: 12.5px; font-weight: 700;
  cursor: pointer; transition: filter 120ms ease, transform 80ms ease;
}
.sb-test-box .btn-primary:hover:not(:disabled) { filter: brightness(1.1); }
.sb-test-box .btn-primary:active:not(:disabled) { transform: scale(0.97); }
.sb-test-box .btn-primary:disabled { background: var(--panel-2); color: var(--muted); cursor: progress; opacity: 0.7; }
.sb-test-status {
  font-size: 11.5px; padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--muted);
}
.sb-test-status[data-state="working"] { color: var(--accent); border-color: rgba(29,185,84,0.35); background: rgba(29,185,84,0.08); }
.sb-test-status[data-state="ok"]      { color: var(--accent); border-color: rgba(29,185,84,0.5);  background: rgba(29,185,84,0.14); }
.sb-test-status[data-state="err"]     { color: var(--danger); border-color: rgba(248,113,113,0.4); background: rgba(248,113,113,0.08); }

/* ---------- Diagnostics modal ---------- */
#dx-modal {
  position: fixed; inset: 0; z-index: 99998;
  background: rgba(6,8,14,0.92);
  display: flex; align-items: center; justify-content: center;
  font-family: 'Inter', system-ui, sans-serif; color: var(--text);
  backdrop-filter: blur(10px);
}
.dx-modal__box {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 24px 28px 20px;
  width: min(560px, 92vw);
  max-height: 80vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0,0,0,0.6);
}
.dx-modal__pill {
  display: inline-block;
  background: linear-gradient(135deg, #4f46e5, #7c3aed);
  color: #fff;
  font-size: 10px; font-weight: 700; letter-spacing: 0.5px;
  padding: 3px 8px; border-radius: 4px; margin-bottom: 10px;
  text-transform: uppercase;
}
.dx-modal__title { margin: 0 0 4px; font-size: 18px; font-weight: 700; }
.dx-modal__lede { margin: 0 0 14px; font-size: 12.5px; color: var(--muted); }
.dx-modal__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.dx-row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "name status" "detail detail";
  gap: 4px 8px;
  padding: 10px 12px;
  background: rgba(255,255,255,0.02);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12.5px;
}
.dx-row__name { grid-area: name; font-weight: 600; }
.dx-row__status {
  grid-area: status;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--muted);
  white-space: nowrap;
}
.dx-row__status[data-state="probing"] {
  color: var(--accent);
  background: rgba(29,185,84,0.10);
  border-color: rgba(29,185,84,0.35);
}
.dx-row__status[data-state="ok"] {
  color: var(--accent);
  background: rgba(29,185,84,0.16);
  border-color: rgba(29,185,84,0.5);
}
.dx-row__status[data-state="err"] {
  color: var(--danger);
  background: rgba(248,113,113,0.12);
  border-color: rgba(248,113,113,0.45);
}
.dx-row__status[data-state="skipped"] {
  color: var(--muted);
  background: rgba(255,255,255,0.03);
  border-color: var(--border);
}
.dx-row__detail {
  grid-area: detail;
  font-size: 11.5px;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  word-break: break-all;
}
.dx-modal__footer {
  display: flex; justify-content: flex-end; gap: 8px;
  margin-top: 16px; padding-top: 14px;
  border-top: 1px dashed var(--border);
}
.dx-modal__copy,
.dx-modal__close {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 16px;
  font-size: 12.5px; font-weight: 600;
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}
.dx-modal__copy { background: var(--accent); color: #0a1a10; border-color: transparent; }
.dx-modal__copy:hover { filter: brightness(1.1); }
.dx-modal__close:hover { border-color: var(--accent); }
