:root {
  --bg: #ffffff;
  --bg-alt: #f6f8fa;
  --border: #d8dee4;
  --text: #1f2328;
  --muted: #656d76;
  --accent: #0969da;
  --accent-weak: #ddf4ff;
  --danger: #cf222e;
  --get: #1f883d;
  --post: #0969da;
  --put: #9a6700;
  --patch: #8250df;
  --delete: #cf222e;
  --ok-bg: #dafbe1;
  --err-bg: #ffebe9;
  --warn-bg: #fff8c5;
  --warn-border: #d4a72c66;
  --warn-text: #7d5e00;
  --on-accent: #ffffff;            /* text on the saturated method/response/send badges */
  --shadow: rgba(31, 35, 40, .12); /* editor tooltip / autocomplete / lint drop shadow */
  /* White-on-colour fills (method + response badges, Send button, active tabs, redirect chip) need a
     fixed background that keeps white text at >=4.5:1 (WCAG-AA) in BOTH themes. The --get/--post/...
     and --accent vars can't serve this: dark mode brightens them for text legibility, which drops white
     text on a fill to ~2.5-3.7:1. These fill vars are therefore theme-independent and dark enough for
     white. */
  --method-get: #1a7f37;
  --method-post: #0969da;
  --method-put: #9a6700;
  --method-patch: #8250df;
  --method-delete: #cf222e;
  --method-other: #656d76;
  --accent-strong: #0969da;
  /* Stacking scale: dropdowns/lists below viewport-fixed tooltips. (CodeMirror injects its own
     higher z-index for editor tooltips, which sit above both.) */
  --z-dropdown: 50;
  --z-tooltip: 1000;
  --z-toast: 1100;   /* the update toast sits above tooltips so its Reload/Dismiss stay clickable */
  /* Raw-JSON editor syntax tokens (CodeMirror); see JsonEditor.js. The light values are
     CodeMirror's own defaults (string=#a11, number=#164, bool=#219, null=#708 via keyword),
     restored so light mode is unchanged; the dark values are brightened, equally
     differentiated analogues. Keys and punctuation are left to inherit the editor text color. */
  --cm-string: #a11;
  --cm-number: #164;
  --cm-bool: #219;
  --cm-null: #708;
  /* Text-selection background for the code viewer/editor. */
  --cm-selection: rgba(9, 105, 218, .25);
  /* Active-line highlight: the same accent hue for the line body and (a touch stronger) the gutter, so
     the two read as one continuous band. The body alpha stays low enough that a selection on the
     cursor's line — drawn beneath it — shows through. */
  --cm-active-line: rgba(9, 105, 218, .1);
  --cm-active-gutter: rgba(9, 105, 218, .18);
  color-scheme: light;             /* native inputs, selects, scrollbars */
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* Dark palette. The two rules below MUST stay identical — update them together.
   Plain CSS can't share one declaration block between an attribute selector and a
   media query, so the values are duplicated.
     :root[data-theme="dark"]            -> the user forced dark.
     OS prefers dark + not forced light  -> "system" follows the OS (also covers the
                                            no-JS case, where data-theme is absent). */
:root[data-theme="dark"] {
  --bg: #0d1117;
  --bg-alt: #161b22;
  --border: #30363d;
  --text: #e6edf3;
  --muted: #8b949e;
  --accent: #2f81f7;
  --accent-weak: rgba(56, 139, 253, .15);
  --danger: #f85149;
  --get: #3fb950;
  --post: #2f81f7;
  --put: #d29922;
  --patch: #a371f7;
  --delete: #f85149;
  --ok-bg: rgba(46, 160, 67, .15);
  --err-bg: rgba(248, 81, 73, .12);
  --warn-bg: rgba(187, 128, 9, .15);
  --warn-border: #d4a72c66;
  --warn-text: #d29922;
  --on-accent: #ffffff;
  --shadow: rgba(1, 4, 9, .5);
  --cm-string: #ff7b72;
  --cm-number: #7ee787;
  --cm-bool: #79c0ff;
  --cm-null: #d2a8ff;
  --cm-selection: rgba(56, 139, 253, .4);
  --cm-active-line: rgba(56, 139, 253, .12);
  --cm-active-gutter: rgba(56, 139, 253, .22);
  color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    --bg: #0d1117;
    --bg-alt: #161b22;
    --border: #30363d;
    --text: #e6edf3;
    --muted: #8b949e;
    --accent: #2f81f7;
    --accent-weak: rgba(56, 139, 253, .15);
    --danger: #f85149;
    --get: #3fb950;
    --post: #2f81f7;
    --put: #d29922;
    --patch: #a371f7;
    --delete: #f85149;
    --ok-bg: rgba(46, 160, 67, .15);
    --err-bg: rgba(248, 81, 73, .12);
    --warn-bg: rgba(187, 128, 9, .15);
    --warn-border: #d4a72c66;
    --warn-text: #d29922;
    --on-accent: #ffffff;
    --shadow: rgba(1, 4, 9, .5);
    --cm-string: #ff7b72;
    --cm-number: #7ee787;
    --cm-bool: #79c0ff;
    --cm-null: #d2a8ff;
    --cm-selection: rgba(56, 139, 253, .4);
    --cm-active-line: rgba(56, 139, 253, .12);
    --cm-active-gutter: rgba(56, 139, 253, .22);
    color-scheme: dark;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  color: var(--text);
  background: var(--bg);
  font-size: 14px;
}

.layout { display: flex; height: 100vh; }

/* --- sidebar --- */
.sidebar {
  flex: 0 0 320px;
  border-right: 1px solid var(--border);
  background: var(--bg-alt);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.divider {
  flex: 0 0 5px;
  cursor: col-resize;
  background: var(--border);
}
.divider:hover, .divider:focus-visible { background: var(--accent); }
.divider:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
/* The brand is the page's <h1>; reset the UA heading size/margin to the original chrome look. */
.brand { margin: 0; padding: 14px 16px; font-size: 14px; font-weight: 600; border-bottom: 1px solid var(--border); }
.filter-wrap { position: relative; margin: 10px; }
.filter {
  width: 100%; box-sizing: border-box; padding: 7px 28px 7px 9px;
  border: 1px solid var(--border); border-radius: 6px; font-size: 13px;
}
.filter-clear {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  border: none; background: none; cursor: pointer; color: var(--muted);
  font-size: 13px; line-height: 1; padding: 4px; border-radius: 4px;
}
.filter-clear:hover { color: var(--text); background: var(--accent-weak); }
.op-list { overflow-y: auto; overflow-x: auto; padding: 0 8px 16px; flex: 1; }
/* Explorer (Spyglass) branding, pinned at the very bottom of the rail — distinct from the API title
   at the top (.brand), which is the spec's info.title. */
.sidebar-foot {
  flex: 0 0 auto; border-top: 1px solid var(--border);
  padding: 8px 12px; font-size: 11px; color: var(--muted);
  display: flex; flex-direction: column; gap: 2px;
}
.foot-brand { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.foot-name { font-weight: 600; color: var(--text); }
.foot-meta { display: flex; align-items: baseline; gap: 6px; }
.foot-version { font-family: var(--mono); }
.foot-link { color: var(--accent); text-decoration: none; }
.foot-link:hover { text-decoration: underline; }
/* Extension-contributed footer items (registerFooterItem): inherit the footer's muted style; links
   within them pick up the .foot-link treatment by adding that class. */
.foot-item { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Both the unfiltered (tag) and filtered (matched-field) groupings share the same box: sized to
   their widest row so a long path can scroll horizontally without clipping the selection bar. */
.tag-group, .match-group { margin-top: 12px; min-width: 100%; width: max-content; }
.tag-name, .match-name {
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); padding: 4px 8px; font-weight: 600;
}
.op-link {
  display: flex; align-items: center; gap: 8px; width: 100%;
  text-align: left; background: none; border: none; cursor: pointer;
  padding: 5px 8px; border-radius: 6px; color: var(--text); font-size: 13px;
}
/* The only sidebar highlight is the selection — a full-row bar whose colour signals focus
   (IntelliJ-style): neutral grey when the sidebar isn't the active keyboard region (focus is in the
   panel, etc.), accent when it is. No hover highlight: it competed confusingly with the selection. */
.op-link.active { background: var(--border); }
.op-list.kb-active .op-link.active { background: var(--accent-weak); }
/* The selection bar signals the open op; whenever a row actually holds focus it also draws an inset
   outline (the bar alone is too low-contrast as a focus cue). Uses :focus, not :focus-visible, so the
   cue is consistent however focus arrived — a click leaves the row focused, and waiting for the first
   keystroke to paint the ring (the :focus-visible heuristic) looked like a glitch. */
.op-link:focus { outline: 2px solid var(--accent); outline-offset: -2px; }
.op-method {
  flex: 0 0 52px; font-family: var(--mono); font-size: 11px; font-weight: 700;
  text-align: center; padding: 2px 0; border-radius: 4px; color: var(--on-accent);
}
.op-link .op-path { font-family: var(--mono); font-size: 12px; white-space: nowrap; }

/* Filtered view: a row stacks the method+path line above an optional match snippet, so the button
   becomes a block with an inner flex line rather than a single flex row. */
.match-group .op-link { display: block; }
.op-line { display: flex; align-items: center; gap: 8px; }
/* Second line explaining a summary/operationId match (text not otherwise visible in the row).
   width:0 + min-width:100% keeps a long snippet from widening the column (which is sized by the
   paths); the snippet then ellipsizes at that width and never wraps. */
.op-snippet {
  display: block; width: 0; min-width: 100%; margin-top: 2px;
  color: var(--muted); font-size: 11px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Filter-match highlight: bold accent TEXT, no background tint. Weight + colour alone reads cleanly
   and — unlike a tint — doesn't clash with the selection bar (itself --accent-weak). The coloured
   method badge is already bold, so bold-on-bold wouldn't register there; it keeps a translucent dark
   patch so a method match still stands out while the white badge text stays legible. */
.op-link mark { background: none; color: var(--accent); font-weight: 700; padding: 0; }
.op-method mark { background: rgba(0, 0, 0, .25); color: var(--on-accent); border-radius: 2px; padding: 0 1px; }

.m-get .op-method, .method.m-get { background: var(--method-get); }
.m-post .op-method, .method.m-post { background: var(--method-post); }
.m-put .op-method, .method.m-put { background: var(--method-put); }
.m-patch .op-method, .method.m-patch { background: var(--method-patch); }
.m-delete .op-method, .method.m-delete { background: var(--method-delete); }
.m-head .op-method, .m-options .op-method { background: var(--method-other); }

/* --- main --- */
.main { flex: 1; overflow-y: auto; }
/* The topbar reacts to the pane's own width (the sidebar is resizable, so a viewport media query
   wouldn't track it). Wide: the global actions sit top-right in their own grid column, beside the
   request controls — no wasted row. Narrow: they stack onto a right-aligned row above the controls,
   which avoids the collision the side-by-side layout would cause when there isn't room. */
.topbar-wrap { container: topbar / inline-size; }
.topbar {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "main actions"; align-items: start; gap: 12px 24px;
  padding: 12px 20px; border-bottom: 1px solid var(--border); background: var(--bg-alt);
}
.topbar-main { grid-area: main; display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; min-width: 0; }

/* Global controls (Clear all + the Light/System/Dark theme toggle), pinned to the top-right. */
.topbar-actions { grid-area: actions; display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }

@container topbar (max-width: 700px) {
  .topbar { display: flex; flex-direction: column; gap: 12px; }
}
.theme-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.theme-toggle button {
  display: flex; align-items: center; gap: 4px;
  background: var(--bg); border: none; cursor: pointer;
  padding: 5px 10px; font-size: 12px; color: var(--muted);
}
.theme-toggle button + button { border-left: 1px solid var(--border); }
.theme-toggle button:hover { color: var(--text); }
.theme-toggle button.active { background: var(--accent-strong); color: var(--on-accent); font-weight: 600; }

.topbar-left { display: flex; flex-direction: column; gap: 10px; }
.base-url, .accept-field { display: flex; flex-direction: column; gap: 4px; }
.base-url span, .accept-field span { font-size: 11px; color: var(--muted); font-weight: 600; }
.base-url input { padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; min-width: 320px; font-family: var(--mono); font-size: 12px; }
.accept-field .combobox, .accept-field .combobox-input { width: 320px; }
.accept-field .combobox-input { padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; font-family: var(--mono); font-size: 12px; }
input[readonly] { background: var(--bg-alt); color: var(--muted); cursor: default; }

.headers-editor { display: flex; flex-direction: column; gap: 4px; flex: 1 1 360px; min-width: 0; max-width: 600px; }
.he-title { font-size: 11px; color: var(--muted); font-weight: 600; }
.he-row { display: flex; gap: 6px; }
.he-key, .he-val { padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px; font-family: var(--mono); font-size: 12px; }
.he-key { flex: 0 1 180px; min-width: 90px; }
.he-val { flex: 1 1 200px; min-width: 0; }
.he-actions { display: flex; gap: 8px; align-items: center; margin-top: 2px; }
.he-platform { padding: 4px 6px; border: 1px solid var(--border); border-radius: 6px; font-size: 12px; max-width: 230px; }

.status-msg { padding: 40px 20px; color: var(--muted); }
.status-msg.error { color: var(--danger); }

/* --- operation panel --- */
.op-panel { padding: 18px 22px 60px; max-width: 920px; }
.op-header { display: flex; align-items: center; gap: 10px; }
.method { font-family: var(--mono); font-size: 12px; font-weight: 700; color: var(--on-accent); padding: 3px 10px; border-radius: 5px; }
.op-header .op-path { font-family: var(--mono); font-size: 16px; }
/* Operation ID: a small, copyable identity line under the method/path header — a muted label plus a
   monospace value. Shown only when the spec declares an operationId; it is also a filter field, so it
   gets a clear, scannable home here. */
.op-id { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 8px; font-size: 12px; }
.op-id-label { color: var(--muted); text-transform: uppercase; letter-spacing: .04em; font-size: 11px; font-weight: 600; }
.op-id-value { font-family: var(--mono); color: var(--text); }
.op-id-copy { display: inline-flex; align-items: center; border: none; background: none; cursor: pointer; color: var(--accent); padding: 2px; border-radius: 4px; line-height: 0; }
.op-id-copy:hover { background: var(--accent-weak); }
/* The operation title is the panel's <h2>; keep it at body size (UA would blow it up). */
.op-summary { font-size: 15px; font-weight: 600; margin: 10px 0 2px; }
.op-desc { color: var(--muted); margin: 2px 0 8px; line-height: 1.45; }
.op-desc p { margin: 4px 0; }

/* Section headings under the operation title (Parameters, Request body, Responses, …). Promoted from
   <h4> to <h3> so the document heading scale is continuous (h1 brand → h2 op title → h3 sections); the
   compact size is kept. */
h3 { margin: 18px 0 8px; font-size: 13px; }

/* --- operation tabs --- */
.op-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin: 14px 0 4px; }
.op-tabs button {
  background: none; border: none; border-bottom: 2px solid transparent; cursor: pointer;
  padding: 8px 14px; font-size: 13px; color: var(--muted); margin-bottom: -1px;
}
.op-tabs button:hover { color: var(--text); }
.op-tabs button.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }

/* --- schema documentation --- */
.schema-doc .schema-toggle { width: max-content; margin: 12px 0; }
.schema-block { margin: 6px 0 16px; }
.resp-line { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.resp-code {
  font-family: var(--mono); font-size: 12px; font-weight: 700; color: var(--on-accent);
  padding: 2px 8px; border-radius: 5px;
}
.resp-code.ok { background: var(--method-get); }
.resp-code.redirect { background: var(--accent-strong); }
.resp-code.err { background: var(--method-delete); }
.resp-text { color: var(--muted); font-size: 13px; }
.example-json {
  margin: 0; padding: 12px; background: var(--bg-alt); border: 1px solid var(--border); border-radius: 6px;
  font-family: var(--mono); font-size: 12px; overflow-x: auto; max-height: 460px;
}

.stree { font-size: 13px; }
.stree-row { display: flex; align-items: baseline; gap: 10px; padding: 3px 0; flex-wrap: wrap; }
.stree-name { font-family: var(--mono); font-size: 12px; }
.stree-type { font-family: var(--mono); font-size: 12px; color: var(--accent); }
.stree-req { font-size: 11px; color: var(--danger); }
.stree-constraint { font-size: 11px; color: var(--muted); }
.stree-desc { color: var(--muted); font-size: 12px; }
.stree-rootdesc { color: var(--muted); font-size: 12px; margin: 4px 0 12px; line-height: 1.45; }
.stree-rootdesc p { margin: 4px 0; }
.stree-children { margin-left: 16px; border-left: 1px solid var(--border); padding-left: 12px; }
.stree-children.root { margin-left: 0; border-left: none; padding-left: 0; }

.stree-variants { margin-left: 16px; border-left: 1px solid var(--border); padding-left: 12px; }
.stree-variants.root { margin-left: 0; border-left: none; padding-left: 0; }
.stree-variant { margin: 6px 0; }
.stree-variant-label { font-size: 11px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }

.param-group { margin-bottom: 10px; }

/* --- fields --- */
.field { margin: 4px 0; }
.field-row { display: flex; align-items: center; gap: 10px; margin: 5px 0; }
.field-label { flex: 0 0 200px; font-family: var(--mono); font-size: 12px; word-break: break-word; }
.req { color: var(--danger); margin-left: 2px; }
.type-tag {
  font-size: 10px; color: var(--muted); font-weight: 600;
  background: var(--border); border-radius: 4px; padding: 1px 6px;
  text-transform: uppercase; letter-spacing: .03em; cursor: help;
}

/* themed hover/focus tooltip (see js/tooltip.js, v-tip directive) */
.app-tooltip {
  position: fixed; z-index: var(--z-tooltip); max-width: 280px;
  background: var(--bg-alt); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 9px; font-size: 12px; line-height: 1.45;
  box-shadow: 0 4px 14px var(--shadow);
  opacity: 0; transform: translateY(2px); pointer-events: none;
  transition: opacity .1s ease, transform .1s ease;
  white-space: normal; overflow-wrap: anywhere;
}
.app-tooltip.visible { opacity: 1; transform: none; }
.control { display: flex; align-items: center; gap: 8px; flex: 1; }
.control .combobox-input, .control select {
  padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; min-width: 240px;
}
.control .combobox-input:disabled { background: var(--bg-alt); color: var(--muted); }
.control input.include { min-width: 0; }

.object-body.nested {
  border-left: 2px solid var(--border); padding-left: 14px; margin: 4px 0 8px;
}
.object-body.inactive { opacity: .5; pointer-events: none; }

/* oneOf/anyOf variant selector + selected branch (form) */
.variant-body.nested {
  border-left: 2px solid var(--border); padding-left: 14px; margin: 4px 0 8px;
}
.variant-body.inactive { opacity: .5; pointer-events: none; }
.variant-select { display: flex; align-items: center; gap: 8px; margin: 4px 0 8px; }
.variant-select-label { font-size: 12px; color: var(--muted); font-weight: 600; }
.variant-note { color: var(--muted); font-size: 11px; margin: -2px 0 8px; line-height: 1.45; }
/* multi-branch anyOf: a checkbox per object branch, each revealing its own form when checked */
.variant-multi { display: flex; flex-direction: column; gap: 8px; }
.variant-branch-head { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; cursor: pointer; }
.variant-branch-body { border-left: 2px solid var(--border); padding-left: 14px; margin: 4px 0 4px; }
.field-label input.include { margin-right: 5px; vertical-align: middle; }
.hint { color: var(--muted); font-size: 12px; margin: 4px 0; }
.field-desc { color: var(--muted); font-size: 12px; margin: 2px 0 8px; line-height: 1.45; }
.field-desc p { margin: 4px 0; }
.constraint { font-size: 11px; color: var(--muted); cursor: default; word-break: break-word; }

/* inline markdown */
.field-desc code, .stree-desc code, .stree-rootdesc code, .resp-text code, .op-desc code {
  font-family: var(--mono); font-size: .92em; color: var(--text);
}
.field-desc a, .stree-desc a, .stree-rootdesc a, .op-desc a { color: var(--accent); }

.array-body {
  background: var(--bg-alt); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: 6px; padding: 10px 12px; margin: 4px 0 10px;
}
.array-item {
  background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
  padding: 8px 10px; margin: 6px 0;
}
.array-item:first-child { margin-top: 0; }
.array-item-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.array-index { font-family: var(--mono); font-size: 11px; color: var(--muted); }

.array-text {
  width: 100%; font-family: var(--mono); font-size: 13px; padding: 8px;
  border: 1px solid var(--border); border-radius: 6px; resize: vertical;
}
/* Array query/header params: label + `array` tag on top, full-width one-per-line textarea below —
   the body's array control without the tree-only accent box (params are flat, not nested). */
.param-array { margin: 5px 0; }
.param-array .field-label { flex: none; margin-bottom: 3px; }
.param-array .array-text { margin: 0; }

.map-body {
  background: var(--bg-alt); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: 6px; padding: 10px 12px; margin: 4px 0 10px;
}
.map-entry { display: flex; align-items: center; gap: 8px; margin: 6px 0; }
.map-key {
  flex: 0 0 240px; width: 240px; padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px;
  font-family: var(--mono); font-size: 13px;
}
.map-value { flex: 1 1 auto; min-width: 0; }
.map-value .field-row { margin: 0; }
.map-value .control input, .map-value .control select { width: 100%; min-width: 0; }
.map-value .combobox { width: 100%; }

.unsupported {
  background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn-text);
  padding: 8px 10px; border-radius: 6px; font-size: 13px; margin: 6px 0;
}

/* --- body section --- */
.body-section { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 8px; }
/* No params above it (operation has no path/query/header params): the op-tabs border already
   separates it, so drop the redundant second divider. */
.body-section:first-child { border-top: none; padding-top: 0; }
.body-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.body-head h3 { margin: 0; margin-right: auto; }
.body-tabs button {
  border: 1px solid var(--border); background: var(--bg); padding: 5px 12px; cursor: pointer;
  font-size: 12px; color: var(--text);
}
.body-tabs button:first-child { border-radius: 6px 0 0 6px; }
.body-tabs button:last-child { border-radius: 0 6px 6px 0; border-left: none; }
.body-tabs button.active { background: var(--accent-strong); color: var(--on-accent); border-color: var(--accent-strong); }
.body-tabs button:disabled { opacity: .5; cursor: not-allowed; }

/* request-body media-type selector + non-JSON body controls */
.media-select {
  font-size: 12px; padding: 4px 8px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); color: var(--text); font-family: var(--mono);
}
.body-encoding-note { margin: 6px 0; }

/* spec-provided example cards (Schema → Examples tab) */
.example-card { margin: 0 0 12px; }
.example-card:last-child { margin-bottom: 0; }
.example-card-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.example-name { font-weight: 600; font-size: 13px; }
.example-summary { font-size: 12px; color: var(--muted); }
/* The flash sits to the LEFT of the right-anchored button so the button never shifts when it toggles. */
.example-apply-cluster { margin-left: auto; display: inline-flex; align-items: center; gap: 8px; }
.example-desc { font-size: 12px; color: var(--muted); margin: 0 0 4px; }
.example-ext { display: inline-block; font-family: var(--mono); font-size: 12px; word-break: break-all; }
/* Compact parameter example: name · value pill · inline summary · Apply, on one line. */
.example-card-compact { margin-bottom: 8px; }
.example-inline { display: flex; align-items: center; gap: 10px; }
.example-inline .example-name { flex: 0 0 auto; min-width: 96px; font-family: var(--mono); font-size: 12px; }
.example-pill {
  flex: 0 1 auto; min-width: 0; font-family: var(--mono); font-size: 12px;
  background: var(--bg-alt); border: 1px solid var(--border); border-radius: 6px;
  padding: 2px 7px; white-space: nowrap; overflow-x: auto;
}
.example-inline .example-summary { flex: 1 1 auto; }
.example-card-compact .example-desc { margin: 3px 0 0; }
.example-group-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.example-applied { color: var(--get); font-size: 12px; }
/* Static JSON highlighting for example cards — reuses the Raw editor's token palette (keys inherit). */
.example-json .tok-str { color: var(--cm-string); }
.example-json .tok-num { color: var(--cm-number); }
.example-json .tok-bool { color: var(--cm-bool); }
.example-json .tok-null { color: var(--cm-null); }
/* The native file input is visually hidden (its un-stylable "no file chosen" text is replaced by the
   file list below); a label-wrapped custom button triggers it. */
.file-picker { display: inline-flex; }
.file-picker .file-input {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); border: 0;
}
.file-btn {
  display: inline-block; border: 1px solid var(--border); background: var(--bg); color: var(--text);
  padding: 5px 12px; border-radius: 6px; font-size: 12px; cursor: pointer;
}
.file-picker:hover .file-btn { border-color: var(--accent); }
.file-picker:focus-within .file-btn { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Sized to its widest row so the remove ✕ trails the longest filename rather than the panel edge. */
.file-list { list-style: none; margin: 4px 0 8px; padding: 0; display: flex; flex-direction: column; gap: 3px; width: max-content; max-width: 100%; }
.file-list li { display: flex; align-items: center; gap: 8px; font-size: 12px; }
.file-list .file-name { word-break: break-all; }
.file-list .file-size { color: var(--muted); }
.file-list .btn-mini { margin-left: auto; }
.raw-other {
  width: 100%; box-sizing: border-box; min-height: 140px; resize: vertical;
  font-family: var(--mono); font-size: 12px; line-height: 1.5; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px; background: var(--bg); color: var(--text);
}

.json-editor { margin-bottom: 6px; }
.json-editor .cm-editor { width: 100%; }

/* Editor tooltips: schema hover docs, autocomplete info and lint diagnostics. The
   codemirror-json-schema package ships no CSS, so style its markup here. Two-class
   selectors keep priority over CodeMirror's runtime-injected base theme. */
.cm-tooltip.cm-tooltip-hover {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  box-shadow: 0 2px 8px var(--shadow);
}
.cm6-json-schema-hover {
  max-width: 360px;
  padding: 8px 12px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text);
}
/* Divider only when a description precedes the type block (no stray line when type-only). */
.cm6-json-schema-hover--description + .cm6-json-schema-hover--code-wrapper {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
/* marked wraps blocks in <p>; drop the default 1em margins inside the compact tooltip. */
.cm6-json-schema-hover p { margin: 0; }
.cm6-json-schema-hover p + p { margin-top: 6px; }
/* Type-info line: muted monospace, not a chip. */
.cm6-json-schema-hover--code { font-family: var(--mono); font-size: 11px; color: var(--muted); }

/* Completion dropdown list. CodeMirror only themes its option list for its own built-in light/dark
   themes; our surfaceTheme isn't registered as dark, so in dark mode the list keeps the light base
   background while our completion text uses the (light) --text — light-on-light, unreadable. Repaint
   the container and options with the app palette so the list follows the theme. The two-class
   .cm-tooltip.cm-tooltip-autocomplete prefix keeps priority over CodeMirror's runtime-injected base
   theme, whose option/selected rules otherwise tie on specificity and win by injection order. */
.cm-tooltip.cm-tooltip-autocomplete {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  box-shadow: 0 2px 8px var(--shadow);
}
.cm-tooltip.cm-tooltip-autocomplete > ul {
  font-family: var(--mono);
  font-size: 12px;
}
.cm-tooltip.cm-tooltip-autocomplete > ul > li {
  padding: 2px 8px;
  color: var(--text);
}
.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] {
  background: var(--accent);
  color: var(--on-accent);
}
/* The value-type hint (string/boolean/…) shown after each name: muted, but flips to readable on the
   selected row's accent fill. */
.cm-tooltip.cm-tooltip-autocomplete .cm-completionDetail { color: var(--muted); }
.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completionDetail { color: var(--on-accent); }
/* Matched-characters highlight as the user types. */
.cm-tooltip.cm-tooltip-autocomplete .cm-completionMatchedText {
  text-decoration: none;
  font-weight: 700;
  color: var(--accent);
}
.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completionMatchedText { color: var(--on-accent); }

/* Hide CodeMirror's code-oriented completion type glyphs (□/ƒ/𝑥/…): in a JSON body the value type
   shown next to each name (string/array) already conveys the kind, so the icon is redundant. */
.cm-tooltip-autocomplete .cm-completionIcon { display: none; }

/* Autocomplete documentation panel. */
.cm-tooltip-autocomplete .cm-completionInfo {
  max-width: 320px;
  padding: 8px 12px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  box-shadow: 0 2px 8px var(--shadow);
}
.cm-completionInfo p { margin: 0; }
.cm-completionInfo p + p { margin-top: 6px; }
/* Hide the empty panel for completions whose description is blank. */
.cm-tooltip-autocomplete .cm-completionInfo:has(> div:empty:only-child) { display: none; }

/* Inline code chips inside prose (descriptions / autocomplete docs / diagnostics). */
.cm6-json-schema-hover--description code,
.cm-completionInfo code,
.cm-diagnostic code {
  font-family: var(--mono);
  font-size: 11px;
  background: var(--bg-alt);
  padding: 1px 4px;
  border-radius: 4px;
}

/* Lint diagnostics (schema + JSON syntax errors). */
.cm-tooltip.cm-tooltip-lint {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  box-shadow: 0 2px 8px var(--shadow);
  overflow: hidden;
}
.cm-tooltip-lint .cm-diagnostic {
  padding: 7px 11px;
  font-size: 12px;
  line-height: 1.45;
  border-left-width: 3px;
}
.cm-diagnostic p { margin: 0; }
.cm-diagnostic p + p { margin-top: 6px; }

/* Lint gutter markers. CodeMirror bakes fixed, light-oriented fills into these (e.g. a bright
   #f87/#f43 error circle) that don't adapt to dark mode and clash with the dark gutter. Repaint
   each as a masked shape tinted with a palette color, so it follows the theme. Two-class
   selectors keep priority over CodeMirror's runtime-injected base theme. */
.cm-lint-marker.cm-lint-marker-error,
.cm-lint-marker.cm-lint-marker-warning,
.cm-lint-marker.cm-lint-marker-info {
  content: normal;                 /* drop the default replaced-content SVG */
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain;
}
.cm-lint-marker.cm-lint-marker-error {
  background-color: var(--danger);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Ccircle cx='20' cy='20' r='16'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Ccircle cx='20' cy='20' r='16'/%3E%3C/svg%3E");
}
.cm-lint-marker.cm-lint-marker-warning {
  background-color: var(--warn-text);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M20 5L38 36L2 36Z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M20 5L38 36L2 36Z'/%3E%3C/svg%3E");
}
.cm-lint-marker.cm-lint-marker-info {
  background-color: var(--accent);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Crect x='6' y='6' width='28' height='28' rx='3'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Crect x='6' y='6' width='28' height='28' rx='3'/%3E%3C/svg%3E");
}
.raw-tools { display: flex; align-items: center; gap: 12px; margin-top: 6px; }
.raw-error { color: var(--danger); font-size: 12px; }

/* --- buttons --- */
.btn-mini {
  border: 1px solid var(--border); background: var(--bg); cursor: pointer;
  padding: 4px 9px; border-radius: 6px; font-size: 12px; color: var(--text);
}
.btn-mini:hover { background: var(--bg-alt); }
.btn-mini.add { color: var(--accent); }
.btn-mini.danger { color: var(--danger); }

/* Two stacked rows: the execute action (Send/Cancel) and the form utilities (Copy/Reset). Reversed so
   the utilities render on top while Send stays first in DOM/tab order. */
.send-bar { display: flex; flex-direction: column-reverse; gap: 14px; align-items: flex-start; margin: 20px 0; }
.util-row { display: flex; gap: 10px; align-items: center; }
/* Send (and its in-flight Cancel sibling) with the shortcut caption stacked beneath. */
.send-cta { display: inline-flex; flex-direction: column; align-items: center; gap: 4px; }
.send-row { display: inline-flex; align-items: center; gap: 8px; }
.kbd-hint {
  font-size: 11px; color: var(--muted); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 5px; font-family: var(--mono); user-select: none;
}
.copied-note { color: var(--get); font-size: 12px; }
.btn-send, .btn-cancel {
  border: none; cursor: pointer;
  padding: 8px 22px; border-radius: 6px; font-size: 14px; font-weight: 600;
}
/* Pinned width so the label swap Send → Sending… doesn't resize the button. */
.btn-send { background: var(--method-get); color: var(--on-accent); min-width: 7rem; text-align: center; }
/* Once a request has been in flight past the debounce, Send recedes to a quiet disabled "Sending…" ghost
   (no bright fill); the inset box-shadow draws the border without changing the button's size. */
.btn-send:disabled { cursor: default; background: var(--bg-alt); color: var(--muted); box-shadow: inset 0 0 0 1px var(--border); }
/* Before the debounce elapses Send is already disabled but keeps its full green look — a request that
   settles within the window shows no grey morph and no Cancel, so a fast request never flashes.
   Overrides the grey .btn-send:disabled above. */
.btn-send.pre-cancel:disabled { cursor: default; background: var(--method-get); color: var(--on-accent); box-shadow: none; }
/* Separate, deliberately low-key Cancel shown beside the disabled Send once a request outlasts the
   debounce. An outline (not a solid red slab) keeps it from flashing; it fills in on hover. */
.btn-cancel { background: transparent; color: var(--method-delete); box-shadow: inset 0 0 0 1px var(--method-delete); }
.btn-cancel:hover { background: var(--method-delete); color: var(--on-accent); }

/* --- response --- */
.response { margin-top: 14px; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.resp-status { display: flex; gap: 16px; padding: 8px 12px; font-family: var(--mono); font-size: 13px; }
.resp-status.ok { background: var(--ok-bg); }
.resp-status.redirect { background: var(--accent-weak); }
.resp-status.err { background: var(--err-bg); }
.resp-status .dur { color: var(--muted); }
/* Note shown when the browser transparently followed a 3xx (the 30x itself isn't visible to JS). */
.resp-redirect { padding: 6px 12px; font-size: 12px; border-top: 1px solid var(--border); }
.resp-redirect code { font-family: var(--mono); word-break: break-all; }
.response details { border-top: 1px solid var(--border); }
.response summary { cursor: pointer; padding: 8px 12px; font-size: 12px; color: var(--muted); user-select: none; }
.response summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 4px; }
.response pre {
  margin: 0; padding: 12px; background: var(--bg-alt); font-family: var(--mono);
  font-size: 12px; overflow-x: auto; max-height: 460px;
}
.resp-headers { background: var(--bg-alt); font-family: var(--mono); font-size: 12px; max-height: 460px; overflow: auto; padding-bottom: 12px; }
.resp-headers-toolbar { display: flex; justify-content: flex-end; padding: 6px 12px 0; }
.resp-headers-row { display: flex; gap: 6px; padding: 1px 12px; white-space: pre-wrap; word-break: break-all; }
.resp-headers-row:first-of-type { padding-top: 4px; }
.resp-headers-row .rh-name { color: var(--muted); }
.resp-headers-row .rh-name::after { content: ':'; }
.resp-headers-row .rh-link { color: var(--accent); text-decoration: underline; }
.resp-status .resp-ct { color: var(--muted); margin-left: auto; }
.resp-toolbar { display: flex; gap: 8px; align-items: center; padding: 6px 12px; border-top: 1px solid var(--border); }
.resp-pretty, .resp-decoded { display: flex; gap: 5px; align-items: center; font-size: 12px; color: var(--muted); }
/* The last toggle in the left group carries the auto spacer that pushes the hint/buttons to the
   right edge. When the Decoded toggle is shown it sits right after Pretty-print and takes over. */
.resp-pretty { margin-right: auto; }
.resp-pretty:has(+ .resp-decoded) { margin-right: 0; }
.resp-decoded { margin-right: auto; }
.resp-image { padding: 8px 12px 12px; }
/* Fixed thumbnail box so an extreme aspect ratio (e.g. 10000x200) can't blow out the layout. */
.resp-thumb {
  display: block; max-width: 240px; max-height: 240px; object-fit: contain;
  border: 1px solid var(--border); border-radius: 6px; background: var(--bg-alt);
}
.resp-image .hint { margin-top: 6px; }
.resp-binary { padding: 8px 12px 12px; color: var(--muted); font-size: 12px; }
.resp-binary code, .resp-image code { font-family: var(--mono); color: var(--text); }
/* The network-error box sits directly under the status banner; inset it from the panel edges. */
.response > .unsupported { margin: 10px 12px; }
.code-viewer { padding: 8px 12px 12px; }
.code-viewer .cm-editor { width: 100%; }
.resp-headers-doc { padding: 4px 12px 8px; }
.resp-headers-doc-title { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin: 4px 0; }
.resp-headers-doc-row { display: flex; gap: 8px; align-items: baseline; font-size: 12px; padding: 1px 0; }

/* --- request log ---
   The current operation's own past executions, newest-first, below the response. A folded list of rows
   (timestamp · status · size) that expand in place to the stored request/response. The expanded view
   mirrors the live response view — same status bar (.resp-status/.ok/.redirect/.err), body toolbar
   (.resp-pretty), header rows (.resp-headers-row) and code viewer — rather than its own look. */
.request-log { margin-top: 18px; }
.rl-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.rl-head h3 { margin: 0; }
.btn-clear-log { margin-left: auto; }
.rl-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.rl-entry + .rl-entry { border-top: 1px solid var(--border); }
/* The clickable summary row toggles the entry open/closed (caret · timestamp · status badge · size),
   with a ~44px min height so it's a comfortable tap target (forward-compatible with the mobile layout). */
.rl-row {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 44px;
  padding: 6px 12px; background: none; border: 0; cursor: pointer; text-align: left;
  font-family: var(--mono); font-size: 12px; color: var(--text);
}
.rl-row:hover { background: var(--bg-alt); }
.rl-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Keep the open row visually attached to its detail. */
.rl-entry.expanded .rl-row { background: var(--bg-alt); }
.rl-caret { color: var(--muted); flex: 0 0 auto; }
.rl-time { color: var(--muted); flex: 0 0 auto; }
/* Small status badge carrying the same 2xx/3xx/4xx–5xx colour as the response bar. */
.rl-status { flex: 0 1 auto; padding: 1px 6px; border-radius: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rl-status.ok { background: var(--ok-bg); }
.rl-status.redirect { background: var(--accent-weak); }
.rl-status.err { background: var(--err-bg); }
.rl-size { margin-left: auto; color: var(--muted); flex: 0 0 auto; }
/* Expanded detail: plain surface (no accent fill), with the Request and Response blocks each set off by
   a rule and a prominent heading. */
.rl-detail { border-top: 1px solid var(--border); }
.rl-actions { display: flex; gap: 8px; padding: 8px 12px; }
.rl-block { border-top: 1px solid var(--border); padding-bottom: 8px; }
.rl-block-head { margin: 0; padding: 10px 12px 6px; font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text); }
.rl-line { display: flex; align-items: baseline; gap: 8px; padding: 0 12px 6px; }
.rl-target { font-family: var(--mono); font-size: 12px; word-break: break-all; }
/* Body toolbar (Pretty-print + Copy) above a stored text body — the same affordance row as the live view. */
.rl-body-toolbar { display: flex; gap: 8px; align-items: center; justify-content: flex-end; padding: 4px 12px; }
/* An elided-body note (over-cap / binary) and the multipart parts list — plain text, never an editor. */
.rl-body-note { padding: 4px 12px 8px; color: var(--muted); font-size: 12px; }
.rl-parts { padding: 4px 12px 8px; font-family: var(--mono); font-size: 12px; }
.rl-part { display: flex; gap: 8px; padding: 1px 0; white-space: pre-wrap; word-break: break-all; }
.rl-part-name { color: var(--muted); flex: 0 0 auto; }
.rl-part-name::after { content: ':'; }
.rl-part-meta { color: var(--muted); }
/* HTTP headers tucked in a collapsed details, like the live response view's Headers section. */
.rl-headers-details > summary { cursor: pointer; padding: 6px 12px; font-size: 12px; color: var(--muted); user-select: none; }
.rl-headers-details > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 4px; }
/* The display fold's "… +X more" control — opens the rest of the retained list (never eviction). */
.rl-more {
  display: block; width: 100%; margin-top: 6px; padding: 6px 12px; text-align: center;
  background: none; border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
  font-size: 12px; color: var(--muted);
}
.rl-more:hover { background: var(--bg-alt); color: var(--text); }
.rl-more:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* --- non-blocking validation warnings --- */
.warnings {
  margin: 14px 0; padding: 8px 12px; border: 1px solid var(--warn-border);
  background: var(--warn-bg); color: var(--warn-text); border-radius: 6px; font-size: 12px;
}
.warnings-head { font-weight: 600; margin-bottom: 4px; }
.warnings ul { margin: 0; padding-left: 18px; }
.warnings li { margin: 2px 0; }
.warnings code { font-family: var(--mono); }

/* --- deprecated / metadata --- */
.deprecated-banner {
  margin: 8px 0; padding: 6px 10px; border: 1px solid var(--warn-border);
  background: var(--warn-bg); color: var(--warn-text); border-radius: 6px; font-size: 13px;
}
.op-extdocs { margin: 6px 0; font-size: 13px; }
.op-extdocs a { color: var(--accent); }
/* Deprecated op: grey the path (strikethrough makes it unreadable) + a compact "dep" badge. */
.op-link.deprecated .op-path { color: var(--muted); }
.sidebar-dep { margin-left: 0; flex: 0 0 auto; }
/* Keyboard highlight (which row Enter opens) — distinct from .active (the currently-open op). */
.op-tabs button:focus-visible, .body-tabs button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.dep-tag {
  margin-left: 6px; padding: 0 6px; border-radius: 9px; font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .03em; background: var(--warn-bg);
  color: var(--warn-text); border: 1px solid var(--warn-border);
}

/* --- combobox (themed editable dropdown; replaces the native, unstyleable <datalist>) --- */
.combobox { position: relative; display: inline-flex; align-items: stretch; }
.combobox-input { min-width: 0; }
.combobox-caret {
  position: absolute; right: 1px; top: 1px; bottom: 1px; width: 26px;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted); cursor: pointer; user-select: none;
}
/* CSS-drawn triangle: the ▾ glyph renders too small regardless of font-size. */
.combobox-caret::after {
  content: ''; width: 0; height: 0;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
}
.combobox-caret.disabled { cursor: default; opacity: .4; }
/* Reserve room for the caret only when one is shown (no dead space / spinner clash otherwise). */
.combobox.has-caret > .combobox-input { padding-right: 30px; }
/* When the caret is shown on a number field, drop the native spinner so they don't share the edge. */
.combobox.has-caret > .combobox-input[type=number] { -moz-appearance: textfield; appearance: textfield; }
.combobox.has-caret > .combobox-input[type=number]::-webkit-outer-spin-button,
.combobox.has-caret > .combobox-input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.combobox-list {
  position: absolute; top: calc(100% + 2px); left: 0; z-index: var(--z-dropdown); min-width: 100%;
  margin: 0; padding: 4px; list-style: none; background: var(--bg);
  border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 4px 12px var(--shadow);
  max-height: 240px; overflow-y: auto;
}
.combobox-list li {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 8px; border-radius: 4px; font-family: var(--mono); font-size: 12px;
  white-space: nowrap; cursor: pointer; color: var(--text);
}
.combobox-list li.active { background: var(--accent-weak); }
.combobox-opt { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }
.combobox-del { flex: 0 0 auto; color: var(--muted); opacity: 0; cursor: pointer; font-size: 11px; padding: 0 2px; }
.combobox-list li:hover .combobox-del, .combobox-list li.active .combobox-del { opacity: .55; }
.combobox-del:hover { color: var(--danger); opacity: 1; }

/* "A new version is available" toast (see useUpdateCheck.js). A single unobtrusive bottom-right card;
   role=status, so it announces without stealing focus. The slide-in is flattened by the reduced-motion
   block below. */
.update-toast {
  position: fixed; bottom: 16px; right: 16px; z-index: var(--z-toast);
  display: flex; align-items: center; gap: 12px;
  max-width: 360px; padding: 10px 12px;
  background: var(--bg-alt); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 4px 14px var(--shadow); font-size: 13px;
  animation: update-toast-in .18s ease;
}
@keyframes update-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
.update-toast-msg { flex: 1 1 auto; line-height: 1.4; }
.update-toast-reload {
  flex: 0 0 auto; padding: 4px 10px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--accent); background: var(--accent); color: var(--on-accent);
  font-size: 12px; font-weight: 600;
}
.update-toast-dismiss {
  flex: 0 0 auto; padding: 4px; border: none; background: none; cursor: pointer;
  color: var(--muted); font-size: 14px; line-height: 1;
}
.update-toast-dismiss:hover { color: var(--text); }

/* Respect a reduced-motion preference: near-instant transitions/animations (the tooltip fade, the
   theme/tab color transitions) and no smooth scrolling. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
