:root {
  --bg: #000204;
  --bg2: #06090d;
  --bg3: #0a1015;
  --border: #11181f;
  --border2: #1b2630;
  --text: #cdd6df;
  --text2: #5d6b78;
  --text3: #37424c;
  --green: #37e07a;
  --green-dim: #37e07a22;
  --amber: #ffb000;
  --amber-dim: #ffb00022;
  --cyan: #27d3e0;
  --cyan-dim: #27d3e022;
  --red: #ff4d4d;
  --red-dim: #ff4d4d22;
  --blue: #5aa6f0;
  --blue-dim: #5aa6f022;
  --purple: #a78bfa;
  --purple-dim: #a78bfa18;
  --mono: 'Azeret Mono', 'JetBrains Mono', 'Cascadia Code', monospace;
  --sans: 'Saira Condensed', system-ui, sans-serif;
}

/* ── Light mode - "synthwave dawn" ──────────────────────────────────────────────
   Pale lavender paper with neon magenta / cyan / violet accents (the dark theme's
   gold-on-black flipped into a vaporwave daylight palette). Accent values are
   darkened just enough to stay readable as small text on the light ground. */
body.light {
  /* Backgrounds - lavender paper, layered */
  --bg:        #f4edfb;
  --bg2:       #fcf7ff;
  --bg3:       #e9ddf7;
  --border:    #ddc9f0;
  --border2:   #c3a2e2;
  /* Text - deep violet ink */
  --text:      #2a1250;
  --text2:     #6a4296;
  --text3:     #9d77c6;
  /* Accents - neon, AA on the lavender ground */
  --green:     #0a8765;   --green-dim: #0a876518;   /* teal signal */
  --amber:     #c4006d;   --amber-dim: #c4006d16;   /* primary = hot magenta */
  --cyan:      #0286ad;   --cyan-dim:  #0286ad16;   /* electric cyan */
  --red:       #e11d48;   --red-dim:   #e11d4814;   /* rose */
  --blue:      #6d28d9;   --blue-dim:  #6d28d912;   /* violet */
  --purple:    #9333ea;   --purple-dim:#9333ea16;   /* magenta-purple */
}

body.light .btn { color: var(--text2); }
body.light .btn:hover { background: var(--bg3); color: var(--text); }
body.light select, body.light input[type=number], body.light input[type=text] { color: var(--text); }
body.light .bf-bit.b0 { color: var(--text3); }
/* Byte highlights: the base rule's pale-mint hot text + dark-tuned borders are
   built for the dark ground - repaint them to the light theme's neon here. */
body.light .td-data span.byte.hot   { color: var(--green); border-color: var(--green); }
body.light .td-data span.byte.noisy { border-color: var(--amber); }
/* Connect (primary CTA): the muted teal --green reads low-contrast on lavender -
   give it a vivid emerald fill with dark text so it pops like the dark theme. */
body.light .btn.primary { background: #10d186; border-color: #10d186; color: #03130b; }
body.light .btn.primary:hover { background: #04b873; border-color: #04b873; }
/* TX badge orange has no token; darken it so it stays legible on the lavender ground. */
body.light .td-type.tx { background: #c2410c14; color: #c2410c; }

* { box-sizing: border-box; margin: 0; padding: 0; }

/* Themed scrollbars - the browser default bars render light/white and clash
   with the UI (most visible on the view-tabs horizontal scroll and any vertical
   overflow). Thin, on-palette, and adapts per theme. */
* { scrollbar-width: thin; scrollbar-color: var(--border2) transparent; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border2); border: 2px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: var(--text3); }
::-webkit-scrollbar-corner { background: transparent; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  height: 100vh;
  height: 100dvh; /* track mobile address bar so bottom panels aren't clipped */
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

header {
  background: var(--bg2);
  border-bottom: 1px solid var(--border2);
  padding: 5px 12px;
  min-height: 36px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;          /* always wrap when the controls overflow, at any width */
  gap: 6px 10px;
  position: sticky;
  top: 0;
  z-index: 100;
}

/* Narrow screens: force the stats cluster onto its own row. The base header is
   already compact + wraps, so nothing to re-tighten here. */
@media (max-width: 1200px) {
  .header-sep { flex-basis: 100%; height: 0; }
  .view-tabs { overflow-x: auto; }
}

/* Icons-only header (#4-2) - applied by reflowHeader() when the bar would wrap.
   Button text labels (in <span>) hide; SVG icons + tooltips remain. */
.header-compact .btn span { display: none; }
.header-compact .btn { padding: 0 7px; }

/* Phones (≤640px): breakage fixes only - no new layout. Desktop is unaffected. */
@media (max-width: 640px) {
  .header-stats { flex-wrap: wrap; } /* stat cluster wraps instead of overflowing */
  /* ID List: keep columns legible and scroll horizontally instead of crushing them.
     .table-wrap is already overflow:auto, so this just gives the table a width floor. */
  #frameTable { min-width: 720px; }
  /* The filter inputs have fixed/resizable widths - cap them so they can't widen
     the shared toolbar past the viewport. */
  .shared-toolbar input[type=text], .shared-toolbar .flt-resize { max-width: 100%; }
  /* Bigger tap targets for touch. */
  .pin-btn { padding: 8px; }
  .view-tab { padding: 0 14px; }
}

/* Touch momentum scrolling (harmless on desktop). */
.table-wrap, #dumpWrap, .view-tabs { -webkit-overflow-scrolling: touch; }

/* Workspace/FPS + Adapter clusters: fixed 24px so the side dividers (on
   .header-cluster-box) are inset from the 36px row, matching the mock. A fixed
   small height (not 100%/stretch) is also safe for the multi-row header wrap. */
.header-cluster { height: 24px; }

.logo-text {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--amber);
}

.logo-src {
  display: flex;
  align-items: center;
  gap: 5px;
  text-decoration: none;
  width: fit-content;
  transition: color 0.15s;
}
.logo-src:hover { color: var(--text); }
.logo-src svg { flex-shrink: 0; }

/* Larger, centred tap target for the icon-only theme toggle (a11y). Box sizing lives once on
   .theme-toggle-btn (the same button carries both id + class); only the svg sizing is id-scoped. */
#themeToggle svg { width: 14px; height: 14px; }

.header-sep { flex: 1; }

/* Ambient inline readout - no box/border so it doesn't read as clickable tiles. */
.header-stats {
  display: flex;
  gap: 14px;
  align-items: center;
  padding: 0 6px;
}

/* Collapsible counter group (#4-1) - the chevron hides the five live tiles;
   the Memory tile stays visible alongside it. */
.hstat-group { display: flex; gap: 14px; align-items: center; }
.header-stats.stats-collapsed .hstat-group { display: none; }
.hstat-toggle {
  display: flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; padding: 0;
  background: none; border: none; cursor: pointer;
  color: var(--text3); flex-shrink: 0;
}
.hstat-toggle:hover { color: var(--text); }
.hstat-toggle svg { width: 13px; height: 13px; transition: transform 0.15s; }
/* Chevron points left when collapsed, right when expanded. (base SVG points left) */
.header-stats.stats-collapsed .hstat-toggle svg { transform: rotate(0deg); }
.header-stats:not(.stats-collapsed) .hstat-toggle svg { transform: rotate(180deg); }

.hstat {
  display: flex;
  align-items: baseline;
  gap: 5px;
}

.hstat-val {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.hstat-lbl {
  font-size: 11px;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

.header-check {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text2);
  cursor: pointer;
  white-space: nowrap;
}

.header-check input {
  width: 13px;
  height: 13px;
  accent-color: var(--green);
  cursor: pointer;
  flex-shrink: 0;
}

.header-check:has(input:disabled) { opacity: 0.4; cursor: not-allowed; }

/* Pulsing dot animation (used by the PAUSED badge + other live indicators). */
@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.btn {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 22px;
  padding: 0 11px;
  border-radius: 0;
  border: 1px solid var(--border2);
  background: var(--bg2);
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  font-family: var(--sans);
  cursor: pointer;
  transition: all 0.15s;
  white-space: nowrap;
}

.btn:hover { background: var(--bg3); border-color: var(--text3); }
.btn:active { transform: scale(0.97); }

.btn.primary {
  background: var(--green);
  border-color: var(--green);
  color: #04140b;
  font-weight: 600;
}

.btn.primary:hover { background: #00cc6a; }

/* Quiet danger - red text carries the state; the border is dimmed so it
   doesn't shout next to the neutral header buttons. */
.btn.danger {
  border-color: #3a1d20;
  color: var(--red);
  background: none;
}

.btn.danger:hover { background: var(--red-dim); border-color: var(--red); }

.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}

.btn svg { width: 14px; height: 14px; flex-shrink: 0; }

/* Visible keyboard-focus ring (does not show on mouse click) */
.btn:focus-visible,
.view-tab:focus-visible,
.j1939-stab:focus-visible,
.pin-btn:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 2px;
  border-radius: 0;
}

/* Toolbar groups/labels (the old .toolbar row was removed in the redesign; the
   filters now live in .shared-toolbar - these helper classes are still used there). */
.toolbar-group {
  display: flex;
  align-items: center;
  gap: 8px;
}

.toolbar-label {
  font-size: 11px;
  font-weight: 500;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
}

select, input[type=number], input[type=text] {
  background: var(--bg3);
  border: 1px solid var(--border2);
  color: var(--text);
  font-family: var(--sans);
  font-size: 12px;
  height: 22px;
  padding: 0 7px;
  border-radius: 0;
  outline: none;
  transition: border-color 0.15s;
}
/* Text inputs carry hex/ASCII payload data - keep them monospace like the mock. */
input[type=text] { font-family: var(--mono); font-size: 11px; }

select:focus, input:focus { border-color: var(--cyan); }

/* Themed square checkbox (sharp, to match the mock) - replaces the browser
   default. Plain boxes go cyan when checked; the semantic filter boxes keep
   their red/green/blue via the .ac-* overrides further down. */
input[type=checkbox] {
  appearance: none; -webkit-appearance: none;
  width: 13px; height: 13px; flex-shrink: 0;
  border: 1px solid var(--border2);
  background: var(--bg);
  cursor: pointer;
  position: relative;
  vertical-align: middle;
}
input[type=checkbox]:hover { border-color: var(--text2); }
input[type=checkbox]:checked { background: var(--cyan); border-color: var(--cyan); }
input[type=checkbox]:checked::after {
  content: ""; position: absolute; left: 3px; top: 0;
  width: 4px; height: 8px;
  border: solid #04140b; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* Compact header selects (Workspace / FPS / Adapter / Baudrate / Buffer size) -
   one sizing token so they stop drifting from ad-hoc inline styles. */
.hdr-select {
  font-size: 11px;
  padding: 0 6px;
  background: var(--bg3);
  border: 1px solid var(--border2);
  color: var(--text2);
  border-radius: 0;
  font-family: var(--sans);
}
/* Toolbar filter selects/inputs - shared compact sizing. */
.flt-control { font-size: 11px; padding: 0 6px; }
/* User-resizable Filter IDs field: <input> ignores CSS `resize` in Chrome, so the
   wrapper carries the grip and the input fills it. */
.flt-resize { display: inline-block; overflow: hidden; resize: horizontal; vertical-align: middle;
  width: 160px; min-width: 90px; max-width: 480px; }
/* input[type=text] qualifier needed to beat input[type=text]{width:140px} below (line ~447) */
.flt-resize > input[type=text] { width: 100%; box-sizing: border-box; }

input.invalid { border-color: var(--red) !important; background: var(--red-dim); }
input.isotp-broadcast { border-color: var(--amber) !important; background: var(--amber-dim); }

/* Transient toasts (connection errors etc.) - top-right, above everything (#13). */
.toast-host {
  position: fixed;
  top: 18px;
  right: 18px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: min(360px, calc(100vw - 36px));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  background: var(--bg2);
  border: 1px solid var(--border2);
  border-left: 3px solid var(--text3);
  border-radius: 8px;
  padding: 11px 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  box-shadow: 0 8px 24px #0006;
  cursor: pointer;
  animation: toastIn 0.2s ease-out;
}
.toast.err  { border-left-color: var(--red); }
.toast.warn { border-left-color: var(--amber); }
.toast.ok   { border-left-color: var(--green); }
.toast.hide { opacity: 0; transform: translateX(8px); transition: opacity 0.2s, transform 0.2s; }
@keyframes toastIn { from { opacity: 0; transform: translateX(12px); } to { opacity: 1; transform: none; } }

/* Unified Help panel (#10) - multi-section dropdown opened by the toolbar Help button */
.help-btn { gap: 5px; }
.help-panel {
  left: 0;
  padding: 0;
  min-width: 270px; max-width: 320px;
  border-radius: 8px;
  overflow: hidden;
}
.help-sec { padding: 11px 14px; }
.help-sec + .help-sec { border-top: 1px solid var(--border); }
.help-title {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text3); margin-bottom: 8px;
}
.help-panel .fh-grid { border-collapse: collapse; font-size: 12px; }
.help-panel .fh-grid td { padding: 2px 0; color: var(--text2); }
.help-panel .fh-grid td:first-child { padding-right: 14px; white-space: nowrap; }
.help-panel code {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--green);
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 5px;
}
.help-note { font-size: 11px; line-height: 1.45; color: var(--text3); }
.help-note b { color: var(--text2); font-weight: 600; }
.help-legend { display: flex; flex-direction: column; gap: 6px; font-size: 11px; color: var(--text2); }
.help-legend .legend-item { display: flex; align-items: center; gap: 7px; }
.help-legend .legend-swatch { width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--border2); flex-shrink: 0; }
.help-legend .lg-hot    { background: #37e07a28; border-color: #37e07a66; }
.help-legend .lg-noisy  { background: #ffb00020; border-color: #ffb00066; }
.help-legend .lg-stable { background: var(--bg2); border-color: var(--border); }
.help-legend .lg-tx     { background: var(--blue-dim); border-color: var(--blue); }

/* Pulse the header settings controls after a failed connection attempt */
.settings-flash { animation: settingsFlash 0.6s ease-in-out 0s 4; }
@keyframes settingsFlash {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50% { box-shadow: 0 0 0 2px var(--amber); }
}

/* Width utilities (.w38 … .w200, .w140) - opt-in per input. Previously a global
   `input[type=text]{width:140px}` default forced every utility to be written as `input.wNN`
   (an element+attribute selector outranks a bare class), spawning a long override chain. The
   default is now the opt-in `.w140` class instead, so the utilities below stay plain classes. */
input[type=number] { width: 80px; }

.sep { width: 1px; background: var(--border); height: 24px; margin: 0 4px; }


/* Table */
.table-wrap {
  flex: 1;
  overflow: auto;
}

/* ── Traffic Dump fixed-width columns ────────────────────────────────────────
   Both #dumpHeaderTable th and #dumpTable td use the same widths and padding
   so the pinned header and virtual-scroll body stay aligned.                */
#dumpHeaderTable th,
#dumpTable td {
  padding: 4px 8px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
#dumpHeaderTable th:nth-child(1), #dumpTable td:nth-child(1) { width:80px;  min-width:80px;  max-width:80px;  }
#dumpHeaderTable th:nth-child(2), #dumpTable td:nth-child(2) { width:112px; min-width:112px; max-width:112px; }
#dumpHeaderTable th:nth-child(3), #dumpTable td:nth-child(3) { width:114px; min-width:114px; max-width:114px; }
#dumpHeaderTable th:nth-child(4), #dumpTable td:nth-child(4) { width:34px;  min-width:34px;  max-width:34px;  text-align:center; }
#dumpHeaderTable th:nth-child(6), #dumpTable td:nth-child(6) { width:160px; min-width:160px; max-width:160px; }

/* ID List: fixed-width ID column to accommodate 0x + 8-digit EXT IDs */
.td-id { min-width:112px; }

table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 11px;
}

/* No `thead { position:sticky }` rule: under `border-collapse:collapse` (Chrome) a sticky/bg on the
   <thead> element is ignored - the effective sticky header lives on `thead th` below. */
thead th {
  padding: 4px 12px;
  text-align: left;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  color: var(--text2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  /* bg AND sticky on the th cells (not just <thead>) so the header is opaque
     and stays put - `position:sticky` on a <thead> element is ignored under
     `border-collapse:collapse` in Chrome, so it must live on the cells.
     This makes every <thead> table sticky systemically - see
     sticky-table-header-gotcha. */
  background: var(--bg2);
  position: sticky;
  top: 0;
  z-index: 1;
  border-bottom: 1px solid var(--border2);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: color 0.15s;
}

thead th:hover { color: var(--text); }

thead th .sort-arrow {
  display: inline-block;
  margin-left: 4px;
  opacity: 0.3;
}

thead th.sort-asc .sort-arrow::after { content: '↑'; opacity: 1; }
thead th.sort-desc .sort-arrow::after { content: '↓'; opacity: 1; }

tbody tr {
  border-bottom: 1px solid var(--border);
  transition: background 0.15s;
}

tbody tr:hover { background: var(--bg3); }

tbody tr.changed {
  animation: row-flash 0.9s ease-out;
}

tbody tr.new-id {
  background: #27d3e018 !important;
}

tbody tr.new-id:hover {
  background: #27d3e028 !important;
}

@keyframes row-flash {
  0%   { background: var(--green-dim); }
  55%  { background: var(--green-dim); }
  100% { background: transparent; }
}

tbody td {
  padding: 3px 12px;
  vertical-align: middle;
  white-space: nowrap;
}

.td-id {
  color: var(--amber);
  font-weight: 500;
  font-size: 12px;
}

.td-type {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  padding: 1px 6px;
  border-radius: 0;
  display: inline-block;
}

.td-type.std { background: var(--blue-dim); color: var(--blue); }
.td-type.ext { background: var(--amber-dim); color: var(--amber); }
.td-type.rtr { background: var(--purple-dim); color: var(--purple); }
.td-type.tx  { background: #f9731622; color: #f97316; }  /* orange: no token; light override below */
.td-type.rx  { background: var(--blue-dim); color: var(--blue); }
.td-type.fw  { background: var(--green-dim); color: var(--green); }

.tx-row input[type=text]:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.tx-data-invalid {
  border-color: var(--red) !important;
  background: var(--red-dim) !important;
}

.note-input {
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--border2);
  color: var(--text2);
  font-family: var(--sans);
  font-size: 12px;
  outline: none;
  padding: 2px 4px;
  width: 100%;
  min-width: 80px;
}

.note-input:focus {
  border-bottom-color: var(--green);
  color: var(--text);
  background: var(--bg3);
  border-radius: 3px 3px 0 0;
}

.note-input::placeholder { color: var(--text3); font-style: italic; }

#inspectNoteArea:focus { border-color: var(--green); }

.td-data {
  color: var(--text);
  letter-spacing: 0.05em;
}

.td-data span.byte {
  display: inline-block;
  background: var(--bg3);
  border-radius: 2px;
  padding: 1px 5px;
  margin-right: 3px;
  font-size: 12px;
  border: 1px solid var(--border);
  transition: background 0.4s, border-color 0.4s, color 0.4s;
}

/* Byte states also carry a non-colour cue via border-style (solid / dashed /
   dotted) so they're distinguishable without relying on hue. */
/* "Just changed" - a filled green tint rather than a hard outline; the
   border-style (solid) is kept as a non-hue cue but its colour is softened. */
.td-data span.byte.hot {
  background: var(--green-dim);
  border-color: #37e07a44;
  border-style: solid;
  color: #bfffd6;
}

.td-data span.byte.noisy {
  background: var(--amber-dim);
  border-color: #ffb00066;
  border-style: dashed;
  color: var(--amber);
}

.td-data span.byte.stable {
  background: var(--bg2);
  border-color: var(--border);
  border-style: dotted;
  color: var(--text3);
  opacity: 0.55;
}

/* In the Traffic Dump, noisy bytes are de-emphasised (they just mean
   "this byte changes a lot" - no actionable live value to highlight).
   Slightly more visible than stable, but clearly muted. */
#dumpTable .td-data span.byte.noisy {
  background: var(--bg3);
  border-color: var(--border2);
  color: var(--text3);
  opacity: 0.75;
}

.td-len {
  color: var(--text2);
  text-align: center;
}

.td-count {
  color: var(--text2);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.td-rate {
  color: var(--text2);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.td-age {
  color: var(--text3);
  font-size: 11px;
  text-align: right;
  font-family: var(--sans);
}

.td-age.fresh { color: var(--green); }

/* Empty state */
.empty-icon {
  width: 56px;
  height: 56px;
  border: 2px dashed var(--border2);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.empty-icon svg { width: 28px; height: 28px; }

.empty-title {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 500;
  color: var(--text2);
}

.empty-sub {
  font-family: var(--sans);
  font-size: 13px;
  color: var(--text3);
  text-align: center;
  max-width: 320px;
  line-height: 1.6;
}

/* "All frames filtered out" notice - reuses .empty-state layout, amber accent */
.filter-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 80px 24px;
  color: var(--text3);
}
.filter-empty-icon { border-color: var(--amber); color: var(--amber); }
/* Dump view is virtual-scrolled - overlay the notice over the (empty) scroll area */
#dumpFilterEmpty { position: absolute; inset: 0; z-index: 1; background: var(--bg); }

/* ── Onboarding (empty ID List) ─────────────────────────────────────────────── */
.onboard {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 28px 24px 36px;
  color: var(--text3);
  font-family: var(--sans);
  overflow-y: auto;
}
.onboard-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  width: 100%;
  max-width: 780px;
}
.onboard-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
}
.onboard-title {
  font-size: 22px;
  font-weight: 600;
  color: var(--text);
}
.onboard-sub {
  font-size: 13px;
  color: var(--text2);
  max-width: 420px;
  line-height: 1.5;
}
.onboard-explainers-link { font-size: 13px; color: var(--text2); }
.onboard-explainers-link a { color: var(--amber); text-decoration: none; }
.onboard-explainers-link a:hover { text-decoration: underline; }
.onboard-cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 4px;
}
.onboard-connect { font-size: 14px; padding: 9px 16px; }
.onboard-demo    { font-size: 14px; padding: 9px 16px; }
.onboard-cta-note { font-size: 12px; color: var(--text3); }

.onboard-cols {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: stretch;
  gap: 18px;
  width: 100%;
  margin-top: 6px;
}
.onboard-card {
  flex: 1 1 260px;
  max-width: 340px;
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.onboard-shot {
  width: 100%;
  aspect-ratio: 16 / 10;
  border: 2px dashed var(--border2);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text3);
  font-size: 12px;
  letter-spacing: 0.04em;
  overflow: hidden;
}
.onboard-shot img { width: 100%; height: 100%; object-fit: cover; border-radius: 6px; }
/* When the shot holds a real screenshot, drop the dashed placeholder chrome. */
.onboard-shot.has-img { border: 1px solid var(--border); padding: 0; }
.onboard-card-title { font-size: 15px; font-weight: 600; color: var(--text); }
.onboard-card-desc  { font-size: 12px; color: var(--text2); line-height: 1.5; flex: 1; }
/* The Carlito card points an arrow at the toolbar button on hover/focus (#5). */
.onboard-card.carlito { cursor: pointer; }
.onboard-card.carlito:hover, .onboard-card.carlito:focus-visible { border-color: var(--amber); outline: none; }

.onboard-guide {
  flex: 1 1 260px;
  max-width: 360px;
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.onboard-guide-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 4px;
}
.onboard-guide-hint {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text3);
}
.onboard-chips {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px;
}
.onboard-chip {
  text-align: left;
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 9px 11px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--sans);
  transition: border-color 0.15s, background 0.15s, transform 0.1s;
}
.onboard-chip:hover,
.onboard-chip:focus-visible {
  border-color: var(--blue);
  background: var(--blue-dim);
  outline: none;
  transform: translateY(-1px);
}
.oc-name { font-size: 12.5px; font-weight: 600; color: var(--text); }
.onboard-chip:hover .oc-name,
.onboard-chip:focus-visible .oc-name { color: var(--blue); }
.oc-desc { font-size: 11px; color: var(--text3); line-height: 1.35; }

/* Spotlight arrow overlay - points from a hovered chip to the real control */
#onboardArrow {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 250;
  display: none;
  opacity: 0;
  transition: opacity 0.15s ease;
}
#onboardArrow.show { display: block; opacity: 1; }
#oaPath { stroke: var(--blue); stroke-width: 2.5; stroke-linecap: round; }
#oaHead path { fill: var(--blue); }

/* Pulsing ring on the control the hovered chip points at.
   Outline (not box-shadow) so an ancestor's overflow:hidden can't clip it. */
.onboard-pulse {
  animation: onboardPulse 1.1s ease-in-out infinite;
  border-radius: 8px;
}
@keyframes onboardPulse {
  0%, 100% { outline: 3px solid transparent;   outline-offset: 2px; }
  50%      { outline: 3px solid var(--blue);   outline-offset: 2px; }
}

/* Draw attention to whichever filter controls are currently narrowing results */
.filter-attention { border-color: var(--amber) !important; background: var(--amber-dim); }
label.filter-attention { box-shadow: 0 0 0 1px var(--amber); border-radius: 6px; background: transparent; }
/* One-shot pulse when the empty state first appears (reuses settingsFlash ring) */
.filter-pulse { animation: settingsFlash 0.6s ease-in-out 0s 3; }

/* Log panel */
.log-panel {
  background: var(--bg2);
  border-top: 1px solid var(--border);
  height: 200px;
  display: flex;
  flex-direction: column;
}

.log-header {
  padding: 6px 16px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 10px;
}

.log-title {
  font-size: 11px;
  font-weight: 500;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}

.log-title-sep { flex: 1; }

.log-body {
  flex: 1;
  overflow-y: auto;
  padding: 6px 16px;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.7;
  color: var(--text2);
}

.log-entry { display: flex; gap: 10px; }
.log-ts { color: var(--text3); flex-shrink: 0; }
.log-msg { color: var(--text2); }
.log-msg.err { color: var(--red); }
.log-msg.ok { color: var(--green); }
.log-msg.warn { color: var(--amber); }

.term-input-row {
  display: flex;
  align-items: center;
  border-top: 1px solid var(--border);
  height: 34px;
  flex-shrink: 0;
}

.btn.active-notch {
  border-color: var(--amber);
  color: var(--amber);
  background: var(--amber-dim);
}

.btn.flash-green {
  border-color: var(--green);
  color: var(--green);
  background: var(--green-dim);
}


.btn.attention {
  border-color: var(--amber);
  color: var(--amber);
  background: var(--amber-dim);
  animation: btn-pulse 0.8s ease-in-out 2 forwards;
}

@keyframes btn-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.3; }
}

.view-tabs {
  display: flex;
  align-items: stretch;
  background: var(--bg2);
  border-bottom: 1px solid var(--border2);
  padding: 0 14px;
  height: 38px;
  flex-shrink: 0;
}

.view-tab {
  position: relative;          /* anchor for the active underline-glow ::after */
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--text2);
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0.03em;
  padding: 0 16px;
  cursor: pointer;
  transition: color 0.15s;
  margin-bottom: -1px;
  white-space: nowrap;  /* keep labels single-line; .view-tabs scrolls horizontally instead */
  flex-shrink: 0;       /* don't squeeze tabs narrow enough to wrap */
}

.view-tab:hover { color: var(--text); }
.view-tab.active { color: var(--amber); }
/* underline-glow (mock 14 treatment) - amber bar with a soft halo under the active tab */
.view-tab.active::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--amber);
  box-shadow: 0 0 8px var(--amber);
}
.view-tab:disabled { opacity: 0.35; cursor: not-allowed; }
.view-tab:disabled:hover { color: var(--text2); }

/* Divider + "beta" group label: tabs to the right are still being refined. */
.view-tab-sep {
  align-self: center;
  width: 1px;
  height: 22px;
  background: var(--border2);
  margin: 0 12px;
  flex-shrink: 0;
}
.view-tab-beta {
  display: inline-flex;
  align-items: center;
  align-self: center;
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--text);
  padding: 2px 7px;
  margin-right: 4px;
  border: 1px solid var(--border2);
  border-radius: 999px;
  background: var(--bg3);
  white-space: nowrap;
  flex-shrink: 0;
  cursor: default;
}
/* The beta tabs themselves read slightly quieter than the stable ones. */
.view-tab-beta ~ .view-tab:not(.active) { color: var(--text3); opacity: 0.82; }

#dumpTable thead th {
  padding: 8px 12px;
  text-align: left;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

#dumpTable tbody td {
  padding: 3px 8px;
  font-family: var(--mono);
  font-size: 12px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  vertical-align: middle;
}

#dumpTable tbody tr:hover { background: var(--bg3); }

.inspect-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text2);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 16px;
}

.inspect-raw {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text2);
  margin-bottom: 24px;
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 14px;
}

.bitfield-wrap {
  overflow-x: auto;
  width: 100%;
  margin-bottom: 28px;
}

.bitfield {
  display: flex;
  align-items: stretch;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--border);
  /* Fill the wrap when there's room, but keep natural width when cramped so
     .bitfield-wrap's overflow-x scrolls instead of squashing the bits (#12). */
  min-width: 100%;
  width: max-content;
}

.bf-field {
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--border);
  flex-shrink: 0;
  flex: 1;
  /* No min-width:0 - fields keep their content width so the row scrolls rather than squashes (#12). */
}

.bf-field:last-child { border-right: none; }

.bf-label {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 4px 8px;
  text-align: center;
  background: var(--bg3);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  color: var(--text3);
}

.bf-bits {
  display: flex;
  flex: 1;
}

.bf-bit {
  flex: 1;
  min-width: 18px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  border-right: 1px solid var(--border2);
  flex-shrink: 0;
}

.bf-bit:last-child { border-right: none; }
.bf-bit.b1 { color: var(--green); background: var(--green-dim); }
.bf-bit.b0 { color: var(--text3); background: transparent; }
.bf-bit.bx { color: var(--text3); background: var(--bg2); font-size: 9px; }

.bf-label.sof   { color: var(--text2); }
.bf-label.id    { color: var(--blue); }
.bf-label.ctrl  { color: var(--amber); }
.bf-label.data  { color: var(--green); }
.bf-label.crc   { color: var(--purple); }
.bf-label.eof   { color: var(--text3); }

.bf-bit.id  { background: var(--blue-dim); color: var(--blue); }
.bf-bit.ctrl{ background: var(--amber-dim); color: var(--amber); }
.bf-bit.data-b { background: var(--green-dim); }
.bf-bit.crc-b  { background: var(--purple-dim); color: var(--purple); }

.inspect-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  margin-bottom: 24px;
  table-layout: fixed;
}

.inspect-table th:first-child,
.inspect-table td:first-child { width: 160px; }

.inspect-table th {
  text-align: left;
  padding: 6px 12px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text3);
  border-bottom: 1px solid var(--border);
}

.inspect-table td {
  padding: 7px 12px;
  font-family: var(--mono);
  font-size: 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.inspect-table tr:last-child td { border-bottom: none; }
.inspect-table td:first-child { color: var(--text3); font-family: var(--sans); font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; }

.inspect-close {
  float: right;
  font-size: 11px;
  color: var(--text3);
  cursor: pointer;
  font-family: var(--sans);
  padding: 2px 8px;
  border: 1px solid var(--border2);
  border-radius: 4px;
  background: none;
}

.inspect-close:hover { color: var(--text); border-color: var(--text3); }

.stuff-wrap {
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px 16px;
  margin-bottom: 24px;
  overflow-x: auto;
}

.stuff-row {
  display: flex;
  gap: 0;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.8;
  letter-spacing: 0.12em;
  white-space: nowrap;
  align-items: baseline;
}

.stuff-offset {
  color: var(--text3);
  font-size: 10px;
  margin-right: 12px;
  min-width: 28px;
  user-select: none;
  letter-spacing: 0;
  align-self: center;
}

.stuff-bit {
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.tx-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-family: var(--mono);
}

.tx-row:last-child { border-bottom: none; }

.tx-row input[type=text], .tx-row input[type=number] {
  background: var(--bg3);
  border: 1px solid var(--border2);
  color: var(--text);
  font-family: var(--mono);
  font-size: 12px;
  padding: 3px 6px;
  border-radius: 4px;
  outline: none;
}

.tx-row input[type=text]:focus,
.tx-row input[type=number]:focus { border-color: var(--green); }

.tx-row select {
  background: var(--bg3);
  border: 1px solid var(--border2);
  color: var(--text);
  font-family: var(--mono);
  font-size: 12px;
  padding: 3px 5px;
  border-radius: 4px;
  outline: none;
}

.tx-lbl {
  font-family: var(--sans);
  font-size: 10px;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

.tx-sep { width:1px; background:var(--border); height:18px; margin:0 2px; flex-shrink:0; }

/* Automatic (module-driven) message section: collapsible sub-header + rows. */
#txModuleHeader {
  display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none;
  padding: 4px 12px; background: var(--red-dim); border-bottom: 1px solid var(--red-dim);
  font-family: var(--sans); font-size: 11px; font-weight: 600; color: var(--red);
}
#txModuleHeader:hover { background: var(--red-dim); border-bottom-color: var(--red); }
.tx-module-count {
  font-family: var(--mono); font-size: 10px; font-weight: 700; color: var(--red);
  background: var(--red-dim); border-radius: 8px; padding: 0 7px; min-width: 18px; text-align: center;
}
.tx-module-subnote { font-family: var(--sans); font-size: 10px; font-weight: 400; color: var(--text3); margin-left: auto; }

/* Read-only rows mirroring frames sent by other modules (Quick Watch, Fuzzer).
   Tinted with the TX warning colour; not interactive (no inputs). */
.tx-module-row { background: var(--red-dim); border-bottom-color: var(--red-dim); }
.tx-module-row .tx-module-tag {
  font-family: var(--sans); font-size: 9px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--red); border: 1px solid var(--red);
  border-radius: 4px; padding: 1px 6px; white-space: nowrap;
}
.tx-module-row .tx-module-val  { font-family: var(--mono); font-size: 12px; color: var(--text); }
.tx-module-row .tx-module-type { font-family: var(--sans); font-size: 10px; color: var(--text2); }
.tx-module-row .tx-module-note { font-family: var(--sans); font-size: 10px; color: var(--text2);
  margin-left: auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.tx-row input[type=checkbox] {
  width:14px; height:14px; accent-color:var(--green); cursor:pointer; flex-shrink:0;
}

.tx-status {
  font-size: 10px;
  font-family: var(--sans);
  padding: 2px 6px;
  border-radius: 3px;
  white-space: nowrap;
  min-width: 40px;
  text-align: center;
}

.byte.tx-byte { color: var(--blue); opacity: 0.75; }
/* Invisible placeholder byte - reserves a byte's width so the HEX+ASCII ASCII column aligns (#11). */
.td-data span.byte.byte-pad { visibility: hidden; }

.tx-status.running { background: var(--green-dim); color: var(--green); }
.tx-status.stopped { background: var(--bg3); color: var(--text3); }
.tx-status.paused  { background: var(--amber-dim); color: var(--amber); }
.tx-status.error   { background: var(--red-dim); color: var(--red); }

.no-serial-banner {
  background: var(--amber-dim);
  border: 1px solid var(--amber);
  border-radius: 8px;
  padding: 14px 18px;
  margin: 24px;
  font-size: 13px;
  color: var(--amber);
  display: none;
}

.pin-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 5px;
  color: var(--text3);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  opacity: 0.5;
  transition: opacity 0.15s, color 0.15s;
}
.pin-btn:hover { opacity: 1; color: var(--text2); }
.pin-btn.pinned { opacity: 1; color: var(--amber); }

tbody tr.pinned-row { background: var(--amber-dim); }
tbody tr.pinned-row:hover { background: var(--amber-dim); }
tbody tr.pinned-row + tr:not(.pinned-row) {
  border-top: 2px solid var(--border2);
}

.badge-paused {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-family: var(--sans);
  color: var(--amber);
  background: var(--amber-dim);
  border: 1px solid var(--amber);
  border-radius: 20px;
  padding: 3px 10px;
  font-weight: 500;
}

.badge-paused-dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--amber);
}

/* Workspace actions dropdown menu items */
.ws-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: var(--text2);
  font-family: var(--sans);
  font-size: 12px;
  padding: 6px 10px;
  border-radius: 5px;
  cursor: pointer;
  white-space: nowrap;
}
.ws-item:hover { background: var(--bg3); color: var(--text); }

/* "Transmitting" indicator inside the TX Scheduler panel header */
.tx-active-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  font-family: var(--sans);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--red);
}

.tx-active-badge::before {
  content: '';
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 6px var(--red);
  animation: pulse-dot 1s infinite;
}

/* Tint the panel header while transmitting so the eye is drawn to the panel */
#txPanel.transmitting .log-header {
  background: var(--red-dim);
  border-bottom-color: var(--red);
}

/* ── Fuzzing tab (remove with fuzz.js to revert) ──────────────────────────────── */
.fuzz-warn {
  font-size: 12px; color: var(--amber);
  background: var(--amber-dim); border: 1px solid var(--amber);
  border-radius: 8px; padding: 8px 12px; line-height: 1.4;
}
.fuzz-sec { border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; background: var(--bg2); }
.fuzz-sec-title { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text2); margin-bottom: 10px; }
.fuzz-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 6px; }
.fuzz-row:last-child { margin-bottom: 0; }
.fuzz-radio, .fuzz-inline, .fuzz-bytechk { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text); cursor: pointer; }
.fuzz-note { font-size: 12px; color: var(--text2); }
.fuzz-sep { width: 1px; align-self: stretch; background: var(--border); margin: 0 2px; }
.fuzz-sel, .fuzz-hex, .fuzz-num {
  background: var(--bg3); border: 1px solid var(--border); color: var(--text);
  border-radius: 0; padding: 0 7px; font-size: 12px; font-family: var(--mono);
}
.fuzz-hex { width: 80px; text-transform: uppercase; }
.fuzz-num { width: 72px; }
.fuzz-sel { font-family: var(--sans); }

.fuzz-mask { border-collapse: collapse; font-size: 11px; }
.fuzz-mask th, .fuzz-mask td { padding: 3px 5px; text-align: center; }
.fuzz-mask th { color: var(--text3); font-weight: 600; }
.fuzz-mask-lbl { color: var(--text2); text-align: right !important; white-space: nowrap; }
.fuzz-mask .fuzz-hex { width: 38px; padding: 3px 4px; }
.fuzz-mask .fuzz-sel { padding: 2px 4px; }

.fuzz-grid { display: inline-flex; flex-direction: column; gap: 3px; margin-top: 8px; }
.fuzz-grid-row { display: flex; align-items: center; gap: 3px; }
.fuzz-grid-tag { width: 22px; font-size: 10px; color: var(--text3); font-family: var(--mono); }
.fuzz-cell {
  width: 22px; height: 22px; border-radius: 4px; cursor: pointer;
  border: 1px solid var(--border); box-sizing: border-box;
}
.fuzz-cell.never  { background: var(--bg); }
.fuzz-cell.always { background: var(--text2); }
.fuzz-cell.fuzz   { background: var(--green-dim); border-color: var(--green); }
.fuzz-swatch { display: inline-block; width: 12px; height: 12px; vertical-align: -2px; margin-right: 2px; }

.fuzz-bytesel { display: inline-flex; gap: 10px; }
.fuzz-counter { font-size: 12px; color: var(--text2); font-family: var(--mono); }
.btn.fuzz-start.running { background: var(--red); border-color: var(--red); color: #fff; }

/* Global fuzzing badge in the TX panel header */
.fuzz-active-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10px; font-family: var(--sans); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.07em; color: var(--amber);
}
.fuzz-active-badge::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%;
  background: var(--amber); box-shadow: 0 0 6px var(--amber);
  animation: pulse-dot 1s infinite;
}
.fuzz-stop-btn {
  font-family: var(--sans); font-size: 10px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--amber); background: transparent;
  border: 1px solid var(--amber); border-radius: 5px; padding: 1px 7px; cursor: pointer;
}
.fuzz-stop-btn:hover { background: var(--amber-dim); }

/* ── OBD-II sub-mode (ISO-TP tab) - remove with the obd2 feature to revert ──── */
.obd-proto-toggle { display: inline-flex; border: 1px solid var(--border2); border-radius: 7px; overflow: hidden; }
.obd-proto-toggle button {
  background: transparent; border: none; color: var(--text2);
  font-family: var(--sans); font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  padding: 4px 12px; cursor: pointer; transition: all 0.15s;
}
.obd-proto-toggle button.active { background: var(--green-dim); color: var(--green); }
.obd-proto-toggle button:not(.active):hover { background: var(--bg3); color: var(--text); }

.obd-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.obd-btn {
  background: transparent; border: 1px solid var(--border2); color: var(--text);
  font-family: var(--sans); font-size: 11px; padding: 4px 10px; border-radius: 6px;
  cursor: pointer; white-space: nowrap; transition: all 0.15s;
}
.obd-btn:hover:not(:disabled) { background: var(--bg3); border-color: var(--text3); }
.obd-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.obd-btn-danger { border-color: var(--red); color: var(--red); }
.obd-btn-danger:hover:not(:disabled) { background: var(--red); color: #fff; }
.obd-btn-active { background: var(--green); border-color: var(--green); color: #04140b; font-weight: 600; }
.obd-unsup { opacity: 0.35; }

/* Brief highlight when a field's value is auto-updated (e.g. Tx/Rx on proto switch) */
@keyframes fieldFlash {
  0%   { background: var(--green-dim); border-color: var(--green); }
  100% { background: transparent; }
}
.field-flash { animation: fieldFlash 1s ease-out; }

/* Split service button (▾ caret opens a param panel) - KWP/UDS palettes */
.svc-split { position: relative; display: inline-flex; }
.svc-split > .obd-btn { border-radius: 6px 0 0 6px; border-right: none; }
.svc-caret {
  background: transparent; border: 1px solid var(--border2); color: var(--text);
  font-family: var(--sans); font-size: 11px; padding: 4px 7px; border-radius: 0 6px 6px 0;
  cursor: pointer; transition: all 0.15s;
}
.svc-caret:hover { background: var(--bg3); border-color: var(--text3); }
.svc-panel {
  display: none; position: absolute; top: calc(100% + 6px); left: 0; z-index: 200;
  flex-direction: column; gap: 8px; min-width: 200px; padding: 12px 14px;
  background: var(--bg2); border: 1px solid var(--border2); border-radius: 8px;
  box-shadow: 0 8px 24px #0006;
}
.svc-panel.open { display: flex; }
.svc-prow { display: flex; align-items: center; gap: 8px; }
.svc-plabel { font-size: 11px; color: var(--text2); white-space: nowrap; }
.svc-prow select, .svc-phex { font-size: 11px; padding: 0 6px; margin-left: auto; }
.svc-phex {
  background: var(--bg); border: 1px solid var(--border2); color: var(--text);
  font-family: var(--mono); border-radius: 0; width: 90px;
}

.obd-watch-check { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--text2); cursor: pointer; }
.obd-watch-check input { accent-color: var(--green); }

.obd-pidgrid { display: flex; flex-wrap: wrap; gap: 3px; }
.obd-pidcell {
  font-family: var(--mono); font-size: 10px; width: 22px; text-align: center;
  padding: 2px 0; border-radius: 3px; border: 1px solid var(--border);
  color: var(--text3); background: var(--bg);
}
.obd-pidcell.sup { color: var(--green); border-color: var(--green); background: var(--green-dim); }

.obd-tiles { display: flex; flex-wrap: wrap; gap: 8px; }
.obd-tile {
  min-width: 96px; border: 1px solid var(--border2); border-radius: 7px;
  padding: 6px 10px; background: var(--bg);
}
.obd-tile-label { font-family: var(--sans); font-size: 10px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.05em; }
.obd-tile-val { font-family: var(--mono); font-size: 15px; color: var(--green); margin-top: 2px; }

/* ECU tag for functional-addressing (0x7DF) multi-responder rows in the ISO-TP log */
.isotp-ecu-tag {
  font-family: var(--mono); font-size: 10px; font-weight: 600;
  color: var(--blue); background: var(--blue-dim);
  border: 1px solid var(--blue); border-radius: 4px;
  padding: 0 5px; flex-shrink: 0; min-width: 30px; text-align: center;
}

/* ── Extracted from index.html static style="" attributes ─────────────────────
   Utility + component classes lifted out of inline styles. Only static styling
   moved here; JS-toggled properties (display, chevron transform, panel height)
   stay inline in index.html as behavioural state. Input/width rules are element-
   qualified (input.xxx) so they outrank the global input[type=text] defaults the
   old inline styles used to beat. */

/* Layout utilities */
.ml-auto { margin-left: auto; }
.mt6 { margin-top: 6px; }
.ml8 { margin-left: 8px; }
.gap5 { gap: 5px; }
.gap8 { gap: 8px; }
.w8 { width: 8px; }
.mono { font-family: var(--mono); }
.col-r { text-align: right; }
.col-c { text-align: center; }
.clickable { cursor: pointer; user-select: none; }
.row-between { display: flex; justify-content: space-between; align-items: center; }
.col-g10 { display: flex; flex-direction: column; gap: 10px; }
.col-g4 { display: flex; flex-direction: column; gap: 4px; }
.row-g10-mt4 { display: flex; gap: 10px; margin-top: 4px; }

/* Header brand cluster, workspace/FPS box, uppercase tag labels */
.brand-cluster { display: flex; align-items: center; gap: 8px; }
.theme-toggle-btn { width: 22px; height: 22px; min-width: 22px; padding: 0; justify-content: center; border-color: var(--border2); background: none; }
.header-cluster-box {
  display: flex; align-items: center; gap: 2px; padding: 0 10px;
  border-left: 1px solid var(--border); border-right: 1px solid var(--border); margin: 0 4px;
}
.hdr-tag {
  font-size: 10px; color: var(--text3); text-transform: uppercase;
  letter-spacing: 0.07em; white-space: nowrap;
}
.hdr-tag-gap { gap: 5px; }
.hdr-tag-gap4 { gap: 4px; }
.ws-select { max-width: 130px; }
/* Workspace actions (⋯) overflow button. */
.ws-menu-btn { padding: 0 9px; font-size: 13px; line-height: 1; color: var(--text2); }
.demo-accent { border-color: #3a2a08; color: var(--amber); background: none; }
.demo-accent:hover { border-color: var(--amber); }

/* Pop-out menu anchor + shared dropdown surface */
.menu-anchor { position: relative; }
.dropdown-menu {
  position: absolute; top: calc(100% + 6px); z-index: 200;
  background: var(--bg2); border: 1px solid var(--border2); border-radius: 0;
  box-shadow: 0 8px 24px #0006; flex-direction: column;
}
.ws-menu { left: 0; padding: 6px; min-width: 150px; gap: 2px; }
.notch-menu { left: 0; padding: 14px 16px; min-width: 260px; gap: 12px; }
.menu-divider { height: 1px; background: var(--border); margin: 4px 2px; }

/* Connect popover (#1) - all adapter settings + a confirm Connect button. */
.connect-popover { left: 0; padding: 14px 16px; min-width: 230px; gap: 11px; }
.connect-pop-title {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text3);
}
.connect-popover .header-check { justify-content: space-between; }
.connect-pop-divider { height: 1px; background: var(--border); margin: 1px 0; }
.connect-confirm { justify-content: center; margin-top: 2px; }

/* Divider sizing modifiers (on .sep) */
.sep-20 { height: 20px; }
.sep-18 { height: 18px; }
.sep-mx6 { margin: 0 6px; }

/* Toolbar + checkbox-style filter labels */
.tg-gap6 { gap: 6px; }
.chk-inline {
  display: flex; align-items: center; gap: 5px; cursor: pointer;
  font-size: 11px; color: var(--text2); white-space: nowrap;
}
.chk-sm { width: 13px; height: 13px; cursor: pointer; }
/* Semantic filter checkboxes: keep red/green/blue meaning in the themed box. */
.ac-red:checked   { background: var(--red);   border-color: var(--red);   }
.ac-green:checked { background: var(--green); border-color: var(--green); }
.ac-blue:checked  { background: var(--blue);  border-color: var(--blue);  }

/* Notch split-button group + panel controls */
.notch-btngroup { display: flex; gap: 0; }
.btn-joined-l { border-right: none; }
.btn-joined-r { padding: 0 8px; font-size: 11px; }
.mono-val { font-family: var(--mono); font-size: 12px; color: var(--text2); }
.range-green { width: 100%; accent-color: var(--green); }

/* Shared (ID List / Dump) toolbar + dump export controls */
.shared-toolbar {
  background: var(--bg2); border-bottom: 1px solid var(--border);
  padding: 5px 12px; min-height: 30px; flex-shrink: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px;
}
.dump-only-controls { align-items: center; gap: 8px; }
.btn-sm { padding: 3px 10px; font-size: 11px; }
.btn-xs { padding: 4px 10px; font-size: 11px; }
.ico-13 { width: 13px; height: 13px; }
.note-sans { font-size: 11px; color: var(--text3); font-family: var(--sans); }

/* Frame tables */
.th-checkbox { width: 32px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.fixed-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
.dump-header { flex-shrink: 0; background: var(--bg2); border-bottom: 1px solid var(--border); }
.dump-wrap { position: relative; overflow: auto; }
.dump-spacer { position: relative; width: 100%; }
.dump-body-table { position: absolute; top: 0; left: 0; }

/* Decoder tab wrappers (ISO-TP / J1939 / CHAdeMO / XCP / CANopen / Graph / Terminal) */
.tab-wrap {
  flex-direction: column; flex: 1; overflow: hidden; min-height: 0;
  border-top: 1px solid var(--border);
}
.fuzz-wrap {
  flex-direction: column; flex: 1; overflow: auto; min-height: 0;
  border-top: 1px solid var(--border); padding: 16px 20px; gap: 18px;
}

/* ISO-TP config strip */
.cfg-strip {
  background: var(--bg2); border-bottom: 1px solid var(--border); padding: 8px 16px;
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px; flex-shrink: 0;
}
.cfg-field { display: flex; align-items: center; gap: 6px; }
input.hex-input { font-family: var(--mono); font-size: 12px; padding: 0 7px; }
.stmin-label { font-size: 11px; color: var(--text2); white-space: nowrap; }
.broadcast-hint { align-items: center; gap: 5px; font-size: 10px; color: var(--amber); cursor: help; }
.hint-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 50%; border: 1px solid var(--amber);
  font-size: 9px; font-weight: 700;
}
.sel-sm { font-size: 11px; padding: 0 6px; }
.mw320 { max-width: 320px; }
.learn-link { font-size: 11px; color: var(--blue); text-decoration: none; white-space: nowrap; }
.learn-link-pad { padding: 0 10px; }

/* Diagnostic sub-mode panels (UDS / OBD / KWP) */
.submode-panel {
  flex-direction: column; gap: 10px; background: var(--bg2);
  border-bottom: 1px solid var(--border); padding: 10px 16px; flex-shrink: 0;
}
.obd-panel { max-height: 46%; overflow-y: auto; }
.tx-hint-amber { font-size: 11px; color: var(--amber); }
.quickwatch-sec {
  border-top: 1px solid var(--border); padding-top: 8px;
  display: flex; flex-direction: column; gap: 8px;
}
.qw-title { font-size: 11px; font-weight: 700; color: var(--text2); }

/* ISO-TP / terminal conversation log + input row */
.isotp-log {
  flex: 1; overflow-y: auto; padding: 14px 20px;
  font-family: var(--mono); font-size: 12px; line-height: 1.7;
}
.isotp-input-label {
  color: var(--amber); font-weight: 700; font-family: var(--mono);
  font-size: 12px; padding: 0 10px 0 14px; letter-spacing: 0.05em;
}
input.bare-input {
  flex: 1; border: none; background: transparent; color: var(--text);
  font-family: var(--mono); font-size: 12px; outline: none; padding: 0;
}
input.isotp-input { letter-spacing: 0.04em; }
input.term-input { opacity: 0.4; transition: opacity 0.2s; }
.term-prompt { color: var(--text3); font-family: var(--mono); font-size: 12px; padding: 0 8px 0 12px; }
.term-body { flex: 1; overflow-y: auto; padding: 8px 16px; }
/* Serial-tab warning banner shown while Carlito streams traffic (#9). */
.term-traffic-warn {
  flex-shrink: 0;
  background: var(--amber-dim); border-bottom: 1px solid var(--amber);
  color: var(--amber); font-size: 12px; font-weight: 500; line-height: 1.4;
  padding: 8px 16px;
}
.input-send-btn {
  padding: 4px 12px; font-size: 11px; border-radius: 0;
  border-top: none; border-bottom: none; border-right: none;
}

/* J1939 sub-tab bar + scrollable panes */
.subtab-bar {
  background: var(--bg2); border-bottom: 1px solid var(--border);
  padding: 0 12px; display: flex; align-items: center; flex-shrink: 0;
}
.j1939-badge { font-size: 10px; color: var(--text3); padding: 0 8px; font-family: var(--sans); }
.scroll-pane { flex: 1; overflow-y: auto; padding: 14px 20px; }
.log-pane { flex: 1; overflow-y: auto; min-height: 0; padding: 0 20px 14px; }

/* CHAdeMO / XCP / CANopen session panes + log section bar */
.session-scroll { flex-shrink: 0; overflow-y: auto; max-height: 55%; }
.pad-14-20 { padding: 14px 20px; }
.log-section-bar {
  background: var(--bg2); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
  padding: 6px 16px; flex-shrink: 0; font-family: var(--sans); font-size: 12px;
  font-weight: 600; color: var(--text);
}
.mono-select {
  background: var(--bg3); border: 1px solid var(--border); color: var(--text);
  border-radius: 5px; font-family: var(--mono); font-size: 11px; padding: 3px 5px;
}

/* Input width utilities. Plain classes now that the global input[type=text] width default is gone
   (.w140 is the former 140px default, opt-in). */
.w38 { width: 38px; }
.w44 { width: 44px; }
.w46 { width: 46px; }
.w48 { width: 48px; }
.w60 { width: 60px; }
.w70 { width: 70px; }
.w84 { width: 84px; }
.w104 { width: 104px; }
.w120 { width: 120px; }
.w140 { width: 140px; }
.w200 { width: 200px; }

/* Frame Inspector empty state */
.inspect-wrap { flex: 1; overflow: auto; padding: 24px; min-height: 0; }
.inspect-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 100%; min-height: 200px; gap: 14px; color: var(--text3);
}
.inspect-empty-title { font-size: 15px; font-weight: 500; color: var(--text2); }
.inspect-empty-sub { font-size: 13px; }

/* Resize handle between the main view and the TX panel */
.resize-handle {
  height: 5px; cursor: ns-resize; background: transparent;
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
  flex-shrink: 0; position: relative; z-index: 10;
}

/* TX scheduler panel + collapse chevrons */
.tx-panel { background: var(--bg2); border-bottom: 1px solid var(--border); flex-shrink: 0; }
.chevron-icon { width: 14px; height: 14px; color: var(--text3); transition: transform 0.2s; }
.chevron-icon-sm { width: 12px; height: 12px; color: var(--text3); transition: transform 0.2s; }
.tx-module-body { padding: 0 0 4px; max-height: 160px; overflow-y: auto; }
.tx-body { padding: 4px 0; max-height: 200px; overflow-y: auto; }
.device-info { font-size: 11px; color: var(--text3); font-family: var(--mono); }
