:root {
  /* Opt into themed native form-control chrome (scrollbars, the open
     <select> list, file-picker button). Without this, the browser falls
     back to the OS default palette, which is what made the dialect
     dropdown's open list look mismatched in dark mode. */
  color-scheme: light;
  --bg: #f7f7f8;
  --panel: #ffffff;
  --border: #e5e5e8;
  --text: #1a1a1e;
  --muted: #6b7076;
  --accent: #3b5bdb;
  --accent-hover: #2f48b0;
  --strict: #b5451a;
  --strict-hover: #993a15;
  --err-bg: #fdecec;
  --err-fg: #8a1f1f;
  --warn-bg: #fff4d6;
  --warn-fg: #7a5300;
  --ok-bg: #e6f4ea;
  --ok-fg: #1a6b3a;
  --info-bg: #e6eefa;
  --info-fg: #1e3a8a;
  --code-bg: #f1f1f3;
  --gutter-bg: #F4F5F7;
  --radius: 8px;
}

/* Dark-mode palette — applied via a `data-theme="dark"` attribute on
   <html>. An inline script in base.html seeds the attribute from the
   user's saved preference (localStorage) or falls back to their system
   preference on first visit, so `prefers-color-scheme` is respected
   automatically but the in-page toggle button can override it. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0f1115;
  --panel: #171a21;
  --border: #2a2f3a;
  --text: #e9ecef;
  --muted: #9aa0a8;
  --accent: #6d8cff;
  --accent-hover: #8aa1ff;
  --strict: #f09066;
  --strict-hover: #ffa37c;
  --err-bg: #3a1919;
  --err-fg: #ff9090;
  --warn-bg: #3a2f12;
  --warn-fg: #ffc66b;
  --ok-bg: #1a3322;
  --ok-fg: #8de1a8;
  --info-bg: #162240;
  --info-fg: #a9c0ff;
  --code-bg: #1f232c;
  --gutter-bg: #12141a;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
}

.wrap {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 1.25rem;
}

.site-header {
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  padding: 1.1rem 0;
}
.site-header .wrap {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}
.brand {
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--text);
  text-decoration: none;
}
.site-header nav {
  display: flex;
  gap: 1rem;
  margin-left: auto;
}
.site-header nav a {
  color: var(--muted);
  text-decoration: none;
  padding: 0.25rem 0.5rem;
  border-radius: 6px;
}
.site-header nav a:hover,
.site-header nav a[aria-current="page"] {
  color: var(--text);
  background: var(--bg);
}
.site-header nav .theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  margin-left: 0.25rem;
  background: transparent;
  color: var(--muted);
  border: none;
  border-radius: 6px;
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease;
}
.site-header nav .theme-toggle:hover {
  color: var(--text);
  background: var(--bg);
}
.site-header nav .theme-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Swap the sun/moon glyph so the visible icon represents the mode you'd
   switch INTO, not the current mode (sun = click-to-go-light). */
:root[data-theme="light"] .theme-icon-sun,
:root[data-theme="dark"] .theme-icon-moon {
  display: none;
}

main.wrap {
  padding-top: 1.5rem;
  padding-bottom: 3rem;
}

.site-footer {
  color: var(--muted);
  font-size: 0.85rem;
}
.site-footer .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

/* Institutional / partner logos row — quiet, grayscale, centered. */
.site-credits {
  padding: 1.5rem 0;
  border-bottom: 1px solid var(--border);
}
.site-credits .wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1.5rem 2.5rem;
}
.site-credits-label {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.site-credits-logos {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 2rem;
}
.partner-link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  border-radius: 4px;
  padding: 0.15rem 0.25rem;
  transition: transform 150ms ease;
}
.partner-link:hover { transform: scale(1.03); }
.partner-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.partner-logo {
  max-height: 64px;
  width: auto;
  display: block;
}
@media (max-width: 640px) {
  .partner-logo { max-height: 40px; }
}

.site-footer-main {
  padding: 1rem 0;
}
@media (max-width: 640px) {
  .site-credits .wrap { gap: 1rem 1.5rem; }
  .site-credits-logos { gap: 1.25rem; }
}
.footer-link {
  display: inline-flex;
  align-items: center;
  color: var(--muted);
  text-decoration: none;
  padding: 0.25rem;
  border-radius: 4px;
  transition: color 120ms ease;
}
.footer-link:hover,
.footer-link:focus-visible {
  color: var(--text);
}
.footer-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.footer-sep {
  margin: 0 0.35rem;
  color: var(--muted);
  opacity: 0.6;
}
.footer-meta-link {
  color: var(--muted);
  text-decoration: none;
  transition: color 120ms ease;
}
.footer-meta-link:hover,
.footer-meta-link:focus-visible {
  color: var(--text);
}
.footer-meta-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.25rem;
}

h1 {
  margin: 0 0 0.25rem 0;
  font-size: 1.35rem;
  font-weight: 600;
}
h2 {
  margin: 0.5rem 0 0.25rem 0;
  font-size: 1rem;
  font-weight: 600;
}
p { margin: 0.25rem 0; }
.muted { color: var(--muted); }

form label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  margin-top: 0.75rem;
  margin-bottom: 0.25rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

textarea, input[type="search"], select {
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
}
textarea {
  resize: none;
  min-height: 220px;
}

/* --- SQL editor: Prism overlay under a transparent textarea ---------- */

/* Editor header: label on the left, action buttons on the right */
.editor-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.75rem;
  margin-bottom: 0.25rem;
}
.editor-header label {
  margin: 0;
}
.editor-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.kbd-hint {
  font-family: inherit;
  font-size: 0.75rem;
  color: var(--muted);
  background: transparent;
  border: none;
  padding: 0 0.35rem;
}

/* Small secondary action buttons used on the editor header and in
   suggested-fix rows. Neutral-palette by default; accent border on hover;
   brief flash on data-flashed after a copy succeeds. */
.icon-btn {
  appearance: none;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 0.3rem 0.6rem;
  font-size: 0.8rem;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
}
.icon-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.icon-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.icon-btn[data-flashed="1"] {
  background: var(--ok-bg);
  color: var(--ok-fg);
  border-color: var(--ok-fg);
}
.icon-btn-sm {
  padding: 0.18rem 0.5rem;
  font-size: 0.75rem;
}

.sql-editor {
  position: relative;
}

/* Floating icon buttons in the top-right corner of a code-like container.
   The Copy button lives both on the SQL editor (inside an .editor-float-actions
   wrapper alongside the Clear button) and on each per-query JSON view (standalone).
   Borderless by default; a subtle translucent background appears on hover so the
   icon stays readable over highlighted SQL or JSON text. */
.editor-copy-btn {
  position: absolute;
  top: 0.45rem;
  right: 0.55rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  padding: 0.3rem 0.4rem;
  min-width: 1.75rem;
  min-height: 1.75rem;
  background: transparent;
  color: var(--muted);
  border: 0;
  border-radius: 5px;
  cursor: pointer;
  font-size: 0.72rem;
  font-weight: 500;
  line-height: 1;
  opacity: 0.7;
  transition: opacity 120ms ease, color 120ms ease, background 120ms ease;
}
.sql-editor:hover .editor-copy-btn,
.query-view-json:hover .editor-copy-btn,
.editor-copy-btn:focus-visible {
  opacity: 1;
}
.editor-copy-btn:hover {
  opacity: 1;
  color: var(--accent);
  background: var(--code-bg);
}
.editor-copy-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.editor-copy-btn[data-flashed="1"] {
  background: var(--ok-bg);
  color: var(--ok-fg);
  opacity: 1;
  padding: 0.25rem 0.5rem;
}
.editor-copy-btn svg {
  display: block;
}

/* When Copy sits inside the floating actions group (SQL editor), drop the
   absolute positioning — the wrapper handles placement. The standalone
   copy button on the JSON view continues to use the absolute rule above. */
.editor-float-actions {
  position: absolute;
  top: 0.45rem;
  right: 0.55rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
}
.editor-float-actions .editor-copy-btn {
  position: static;
  top: auto;
  right: auto;
  z-index: auto;
}

/* Copy + Clear now live in the editor-bar above the textarea, not floating
   on top of it. Use normal flow, full opacity, and simple neutral/danger
   hover treatments. */
.editor-bar-actions .editor-copy-btn,
.editor-bar-actions .editor-clear-btn {
  position: static;
  top: auto;
  right: auto;
  z-index: auto;
  opacity: 1;
}

/* Import button — same geometry as Copy; neutral-muted by default. */
.editor-import-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.3rem 0.4rem;
  min-width: 1.75rem;
  min-height: 1.75rem;
  background: transparent;
  color: var(--muted);
  border: 0;
  border-radius: 5px;
  cursor: pointer;
  font-size: 0.72rem;
  line-height: 1;
  opacity: 1;
  transition: color 120ms ease, background 120ms ease;
}
.editor-import-btn:hover {
  color: var(--accent);
  background: var(--code-bg);
}
.editor-import-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.editor-import-btn svg { display: block; }
.editor-import-btn:disabled,
.editor-import-btn[data-importing="1"] {
  cursor: wait;
  opacity: 0.7;
}
/* Spinner replaces the upload icon while a file import is in flight. */
.editor-import-btn[data-importing="1"] svg { display: none; }
.editor-import-btn[data-importing="1"]::after {
  content: "";
  display: block;
  width: 13px;
  height: 13px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: fastssv-spin 0.7s linear infinite;
}

/* Clear (trash) button — mirrors .editor-copy-btn geometry but uses the
   danger colour so it reads as destructive. Borderless, icon-only, same
   size as the copy icon. */
.editor-clear-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.3rem 0.4rem;
  min-width: 1.75rem;
  min-height: 1.75rem;
  background: transparent;
  color: var(--err-fg);
  border: 0;
  border-radius: 5px;
  cursor: pointer;
  font-size: 0.72rem;
  line-height: 1;
  opacity: 0.7;
  transition: opacity 120ms ease, color 120ms ease, background 120ms ease;
}
.sql-editor:hover .editor-clear-btn,
.editor-clear-btn:focus-visible { opacity: 1; }
.editor-clear-btn:hover {
  opacity: 1;
  background: var(--err-bg);
}
.editor-clear-btn:focus-visible {
  outline: 2px solid var(--err-fg);
  outline-offset: 2px;
}
.editor-clear-btn svg { display: block; }
/* Both layers must share every text-layout property so the highlighted
   overlay tracks the textarea character-for-character. Switched to
   white-space: pre so line numbers in the gutter line up 1:1 with text. */
.sql-editor > textarea,
.sql-editor > .sql-highlight {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.5;
  padding: 0.6rem 0.75rem 0.6rem 3.25rem; /* left padding = gutter width + gap */
  border: 1px solid var(--border);
  border-radius: 6px;
  tab-size: 4;
  -moz-tab-size: 4;
  margin: 0;
  white-space: pre;
  word-break: normal;
  overflow-wrap: normal;
  letter-spacing: 0;
  overflow: auto;
}

/* Left gutter rendering line numbers. Sits between the highlighted overlay
   and the transparent textarea so numbers show through the textarea's
   transparent pixels without intercepting clicks. Each line number is its
   own <div> — block-level, so they stack at exactly one line-height each
   and match the textarea row-for-row regardless of CSS white-space quirks. */
.editor-gutter {
  position: absolute;
  top: 1px;   /* fit inside the 1px border of the textarea/highlight */
  left: 1px;
  bottom: 1px;
  width: 2.85rem;
  padding: 0.6rem 0.55rem 0.6rem 0.4rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
  background: var(--gutter-bg);
  border-right: 1px solid var(--border);
  border-radius: 5px 0 0 5px;
  text-align: right;
  user-select: none;
  pointer-events: none;
  overflow: hidden;
  z-index: 1;
}
.editor-gutter > div {
  margin: 0;
  padding: 0;
  line-height: 1.5;
  height: 1.5em;
}
.editor-gutter > div:last-child {
  color: var(--text);
  font-weight: 500;
}
.sql-editor > .sql-highlight {
  position: absolute;
  inset: 0;
  overflow: auto;
  background: var(--panel);
  pointer-events: none;
  color: var(--text);
}
.sql-editor > .sql-highlight > code {
  font: inherit;
  background: transparent;
  padding: 0;
  color: inherit;
  display: block;
  white-space: pre-wrap;
}
.sql-editor > textarea {
  position: relative;
  background: transparent;
  color: transparent;
  caret-color: var(--text);
  resize: none;
  min-height: 320px;
  z-index: 1;
}
.sql-editor > textarea::placeholder {
  color: var(--muted);
}
.sql-editor > textarea::selection {
  background: rgba(59, 91, 219, 0.25);
  color: transparent;
}

/* --- Prism token palette, light + dark aware ------------------------- */

.sql-editor .token.comment { color: var(--muted); font-style: italic; }
.sql-editor .token.keyword { color: #6b2fb3; font-weight: 600; }
.sql-editor .token.function { color: #0b5fae; }
.sql-editor .token.string { color: #1a6b3a; }
.sql-editor .token.number,
.sql-editor .token.boolean { color: #b5451a; }
.sql-editor .token.operator,
.sql-editor .token.punctuation { color: var(--muted); }
.sql-editor .token.variable { color: #a14a1f; }

[data-theme="dark"] .sql-editor .token.keyword { color: #c792ea; }
[data-theme="dark"] .sql-editor .token.function { color: #82aaff; }
[data-theme="dark"] .sql-editor .token.string { color: #9de07f; }
[data-theme="dark"] .sql-editor .token.number,
[data-theme="dark"] .sql-editor .token.boolean { color: #f6a878; }
[data-theme="dark"] .sql-editor .token.variable { color: #ffcc80; }
input[type="search"], select {
  font-family: inherit;
  font-size: 14px;
}

.row {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  margin-top: 0.75rem;
  flex-wrap: wrap;
}
.row label { margin: 0; }
.row select { width: auto; min-width: 180px; }

/* Toggle button — visually a pill button, semantically a checkbox so the
   form still works without JS and screen readers get the checked state. */
.toggle-btn {
  display: inline-flex;
  align-items: center;
  padding: 0.48rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--muted);
  font-size: 0.92rem;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  text-transform: none;
  letter-spacing: 0;
  transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
}
.toggle-btn input[type="checkbox"] {
  /* Visually hidden but still focusable / reachable for a11y. */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.toggle-btn:hover {
  border-color: var(--strict);
  color: var(--text);
}
.toggle-btn:has(input:checked) {
  background: var(--strict);
  color: #fff;
  border-color: var(--strict);
}
.toggle-btn:has(input:checked):hover {
  background: var(--strict-hover);
  border-color: var(--strict-hover);
}
.toggle-btn:has(input:focus-visible) {
  outline: 2px solid var(--strict);
  outline-offset: 2px;
}

button[type="submit"] {
  /* Match .toggle-btn's geometry so heights align in the row. */
  background: var(--accent);
  color: white;
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 0.48rem 1.1rem;
  font-size: 0.92rem;
  font-weight: 500;
  line-height: 1.5;
  cursor: pointer;
}

/* Icon-only Clear button — outlined red, sits just left of Validate.
   Same vertical geometry as .toggle-btn and Validate so all three align. */
.btn-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: auto;
  padding: 0.48rem 0.7rem;
  background: transparent;
  color: var(--err-fg);
  border: 1px solid var(--err-fg);
  border-radius: 6px;
  font-size: 0.92rem;
  line-height: 1.5;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.btn-clear:hover {
  background: var(--err-bg);
  border-color: var(--err-fg);
}
.btn-clear:focus-visible {
  outline: 2px solid var(--err-fg);
  outline-offset: 2px;
}
.btn-clear svg {
  display: block;
}
button[type="submit"]:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}
button[type="submit"]:disabled { opacity: 0.6; cursor: progress; }

.htmx-indicator {
  display: none;
  font-size: 0.9rem;
}
.htmx-request .htmx-indicator { display: inline; }

.results-header {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}

/* --- Stat strip: "scoreboard" row of pills at the top of #results --- */
.stat-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.stat {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.45rem 0.8rem;
  border-radius: 10px;
  border: 1px solid transparent;
  font-size: 0.82rem;
}
.stat-num {
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.stat-label { font-weight: 500; opacity: 0.85; }
.stat-neutral {
  background: var(--bg);
  color: var(--muted);
  border-color: var(--border);
}
.stat-ok {
  background: var(--ok-bg);
  color: var(--ok-fg);
  border-color: color-mix(in srgb, var(--ok-fg) 28%, var(--ok-bg));
}
.stat-bad {
  background: var(--err-bg);
  color: var(--err-fg);
  border-color: color-mix(in srgb, var(--err-fg) 28%, var(--err-bg));
}
.stat-warn {
  background: var(--warn-bg);
  color: var(--warn-fg);
  border-color: color-mix(in srgb, var(--warn-fg) 28%, var(--warn-bg));
}
.stat-time { margin-left: auto; }

/* Download-report pill in the stat strip — sits after the time pill. */
.download-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.7rem;
  background: var(--panel);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.78rem;
  font-weight: 500;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}
.download-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--panel);
}
.download-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.download-btn[data-flashed="1"] {
  background: var(--ok-bg);
  color: var(--ok-fg);
  border-color: var(--ok-fg);
}
.download-btn svg { display: block; flex: none; }

/* --- Per-query blocks: pastel-tinted, left accent stripe. Completely
   different silhouette from the editor's clean white shell. */
.query-block {
  position: relative;
  border-radius: 10px;
  padding: 1rem 1.1rem 1rem 1.2rem;
  border: 1px solid transparent;
}
.query-block.block-ok {
  background: var(--ok-bg);
  border-color: color-mix(in srgb, var(--ok-fg) 20%, var(--ok-bg));
  border-left-width: 4px;
  border-left-color: var(--ok-fg);
}
.query-block.block-bad {
  background: var(--err-bg);
  border-color: color-mix(in srgb, var(--err-fg) 20%, var(--err-bg));
  border-left-width: 4px;
  border-left-color: var(--err-fg);
}
.query-block-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}
.query-tag {
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.18rem 0.5rem;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.06);
  color: inherit;
}
[data-theme="dark"] .query-tag { background: rgba(255, 255, 255, 0.1); }
.status-pill {
  display: inline-flex;
  align-items: center;
  padding: 0.18rem 0.55rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.status-ok   { background: var(--ok-fg);   color: var(--ok-bg); }
.status-bad  { background: var(--err-fg);  color: var(--err-bg); }
.status-warn { background: var(--warn-fg); color: var(--warn-bg); }

.query-block-head .view-toggle {
  margin-left: auto;
  appearance: none;
  background: transparent;
  color: inherit;
  border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
  border-radius: 6px;
  padding: 0.22rem 0.6rem;
  font-size: 0.72rem;
  font-weight: 500;
  cursor: pointer;
  opacity: 0.75;
  transition: opacity 120ms ease, background 120ms ease;
}
.query-block-head .view-toggle:hover { opacity: 1; background: rgba(0, 0, 0, 0.05); }
[data-theme="dark"] .query-block-head .view-toggle:hover { background: rgba(255, 255, 255, 0.08); }
.query-block[data-view="formatted"] .view-toggle .view-label-formatted { display: inline; }
.query-block[data-view="formatted"] .view-toggle .view-label-json      { display: none; }
.query-block[data-view="json"]      .view-toggle .view-label-formatted { display: none; }
.query-block[data-view="json"]      .view-toggle .view-label-json      { display: inline; }

.query-block[data-view="formatted"] .query-view-json      { display: none; }
.query-block[data-view="json"]      .query-view-formatted { display: none; }
.query-block .query-view-json { position: relative; }

/* SQL + JSON preview blocks — slightly translucent so the pastel bg tints through */
.query-block .query-sql,
.query-block .query-json {
  background: rgba(255, 255, 255, 0.55);
  color: var(--text);
}
[data-theme="dark"] .query-block .query-sql,
[data-theme="dark"] .query-block .query-json {
  background: rgba(0, 0, 0, 0.28);
}

.banner {
  display: inline-block;
  padding: 0.3rem 0.7rem;
  border-radius: 6px;
  font-size: 0.9rem;
}
.banner-ok { background: var(--ok-bg); color: var(--ok-fg); }
.banner-error { background: var(--err-bg); color: var(--err-fg); }
.banner-warn { background: var(--warn-bg); color: var(--warn-fg); }
.banner p { margin-top: 0.25rem; }

.query-results {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.query-result {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.75rem 1rem;
  background: var(--bg);
}
.query-result.query-ok { border-left: 3px solid var(--ok-fg); }
.query-result.query-bad { border-left: 3px solid var(--err-fg); }
.query-header {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}
.query-idx {
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--text);
}
.query-sql,
.query-json {
  margin: 0 0 0.6rem 0;
  padding: 0.55rem 0.75rem;
  background: var(--code-bg);
  border-radius: 4px;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.8rem;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--muted);
  overflow-x: auto;
  max-height: 10rem;
}
.query-json {
  max-height: 20rem;
  color: var(--text);
}
.query-sql code,
.query-json code {
  font: inherit;
  color: inherit;
  background: transparent;
  padding: 0;
}

/* Prism SQL token colours for the formatted query preview. Mirrors the
   editor palette but re-scoped to the results area so the dark inline
   <code> rule doesn't override them. */
.query-sql .token.comment    { color: var(--muted); font-style: italic; }
.query-sql .token.keyword    { color: #6b2fb3; font-weight: 600; }
.query-sql .token.function   { color: #0b5fae; }
.query-sql .token.string     { color: #1a6b3a; }
.query-sql .token.number,
.query-sql .token.boolean    { color: #b5451a; }
.query-sql .token.operator,
.query-sql .token.punctuation { color: var(--muted); }
.query-sql .token.variable   { color: #a14a1f; }

[data-theme="dark"] .query-sql .token.keyword  { color: #c792ea; }
[data-theme="dark"] .query-sql .token.function { color: #82aaff; }
[data-theme="dark"] .query-sql .token.string   { color: #9de07f; }
[data-theme="dark"] .query-sql .token.number,
[data-theme="dark"] .query-sql .token.boolean  { color: #f6a878; }
[data-theme="dark"] .query-sql .token.variable { color: #ffcc80; }

/* Prism JSON token colours for the JSON view toggle. Scoped so they
   don't leak into the SQL editor's own SQL highlighting. */
.query-json .token.property     { color: #0b5fae; font-weight: 600; }
.query-json .token.string       { color: #1a6b3a; }
.query-json .token.number,
.query-json .token.boolean      { color: #b5451a; }
.query-json .token.null         { color: #6b2fb3; font-weight: 600; }
.query-json .token.punctuation,
.query-json .token.operator     { color: var(--muted); }
.query-json .token.comment      { color: var(--muted); font-style: italic; }

[data-theme="dark"] .query-json .token.property   { color: #82aaff; }
[data-theme="dark"] .query-json .token.string     { color: #9de07f; }
[data-theme="dark"] .query-json .token.number,
[data-theme="dark"] .query-json .token.boolean    { color: #f6a878; }
[data-theme="dark"] .query-json .token.null       { color: #c792ea; }

/* Formatted / JSON view toggle inside each query-result */
.query-result[data-view="formatted"] .query-view-json,
.query-result[data-view="json"] .query-view-formatted {
  display: none;
}
.query-view-json {
  position: relative;
}
.view-toggle {
  margin-left: auto;
}
.view-toggle .view-label-formatted,
.view-toggle .view-label-json { display: none; }
.query-result[data-view="formatted"] .view-toggle .view-label-formatted { display: inline; }
.query-result[data-view="json"] .view-toggle .view-label-json { display: inline; }

.violations {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.violation {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.75rem 1rem;
  background: var(--bg);
}
.violation header {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.4rem;
  margin-left: -0.5rem;    /* offset the sev pill's own left padding so
                              its text lines up with the issue body below */
}
.violation .issue {
  margin: 0.2rem 0 0 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--text);
}
.violation .fix {
  margin: 0.4rem 0 0 0;
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.55;
}
.violation .fix strong {
  color: var(--text);
  font-weight: 600;
  margin-right: 0.2rem;
}

.sev {
  display: inline-block;
  padding: 0.18rem 0.5rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* Error chip: distinct pastel red that stays readable on a pastel-red
   block background. Dark red text on soft salmon fill. */
.sev-error   {
  background: #F8C8C8;
  color: #7A1F1F;
}
[data-theme="dark"] .sev-error {
  background: #3D1E1E;
  color: #F8C8C8;
}
/* Warning chip stays at the original pastel treatment. */
.sev-warning { background: var(--warn-bg); color: var(--warn-fg); }

.rule-id, code {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.82rem;
  background: var(--code-bg);
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
  color: var(--text);
}

.cat {
  font-size: 0.75rem;
  color: var(--muted);
  background: var(--code-bg);
  padding: 0.1rem 0.5rem;
  border-radius: 4px;
}

/* Rules page — follows the same design vocabulary as the validator:
   hero → panel-toolbar → a list of severity-coloured blocks that mirror
   the `.query-block` pattern from the results panel. Each block is a
   native <details> so open/close needs zero JS. The example SQL inside
   reuses the existing `.query-sql` class, so its Prism palette matches
   the validator's results panel exactly — single source of truth. */

.rules-toolbar {
  margin-bottom: 1rem;
  align-items: center;
}
/* Search input + category pill + chips all share one height so the row
   reads as a single band of chrome. */
.rules-toolbar .rules-search-input,
.rules-toolbar .panel-toolbar-field,
.rules-toolbar .chip {
  height: 2.25rem;
  box-sizing: border-box;
}
/* Standalone magnifier that sits to the LEFT of the search bar — not
   inside it. Muted stroke colour to match the other toolbar glyphs. */
.rules-search-icon {
  color: var(--muted);
  flex: none;
  margin-right: -0.15rem;   /* snug against the input without extra whitespace */
}
.rules-search-input {
  appearance: none;
  -webkit-appearance: none;
  flex: 1 1 280px;
  min-width: 220px;
  padding: 0 0.8rem;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.85rem;
  outline: none;
  font-family: inherit;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.rules-search-input::placeholder { color: var(--muted); }
.rules-search-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(59, 91, 219, 0.15);
}
/* Hide WebKit's built-in search-cancel button — we don't use it, and it
   pushes the text frame around when shown. */
.rules-search-input::-webkit-search-decoration,
.rules-search-input::-webkit-search-cancel-button,
.rules-search-input::-webkit-search-results-button,
.rules-search-input::-webkit-search-results-decoration {
  -webkit-appearance: none;
  display: none;
}
.rules-toolbar-actions {
  display: inline-flex;
  gap: 0.4rem;
  margin-left: auto;
}

.rules-list {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

/* Severity-coloured accordion blocks — mirrors .query-block.block-ok /
   .block-bad in `results.html`. The left stripe is the severity colour,
   the card interior is the panel colour so the open body reads cleanly. */
.rule-block {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.rule-block::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--border);
}
/* Left-stripe colour is driven by the rule's CATEGORY (not severity), so
   the user can scan the list and see at a glance which section of the
   OMOP ruleset a card belongs to. Palette is borrowed from the existing
   Prism tokens for visual continuity with the validator results panel. */
.rule-block[data-category="anti_patterns"]::before          { background: #b5451a; }
.rule-block[data-category="concept_standardization"]::before { background: #6b2fb3; }
.rule-block[data-category="data_quality"]::before           { background: #0b5fae; }
.rule-block[data-category="domain_specific"]::before        { background: #5a6573; }
.rule-block[data-category="joins"]::before                  { background: #1a6b3a; }
.rule-block[data-category="temporal"]::before               { background: #a14a1f; }

[data-theme="dark"] .rule-block[data-category="anti_patterns"]::before          { background: #f6a878; }
[data-theme="dark"] .rule-block[data-category="concept_standardization"]::before { background: #c792ea; }
[data-theme="dark"] .rule-block[data-category="data_quality"]::before           { background: #82aaff; }
[data-theme="dark"] .rule-block[data-category="domain_specific"]::before        { background: #9aa0a8; }
[data-theme="dark"] .rule-block[data-category="joins"]::before                  { background: #9de07f; }
[data-theme="dark"] .rule-block[data-category="temporal"]::before               { background: #ffcc80; }
.rule-block[open] {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
  box-shadow: 0 1px 0 color-mix(in srgb, var(--accent) 20%, transparent);
}

.rule-block-head {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.7rem 0.9rem 0.7rem 1rem;
  cursor: pointer;
  user-select: none;
}
.rule-block-head::-webkit-details-marker { display: none; }
.rule-block-head:hover { background: color-mix(in srgb, var(--bg) 55%, transparent); }
.rule-block-head .sev { flex: none; }
.rule-block-title {
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--text);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rule-block .rule-id {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.73rem;
  color: var(--muted);
  background: transparent;
  padding: 0;
  flex: none;
}
.rule-block .cat {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.7rem;
  color: var(--muted);
  padding: 0.12rem 0.5rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  flex: none;
}
.rule-block-chevron {
  color: var(--muted);
  transition: transform 160ms ease;
  flex: none;
  display: inline-flex;
}
.rule-block[open] .rule-block-chevron { transform: rotate(180deg); }

/* Example-SQL wrapper with a play button anchored to its top-right
   corner — mirrors the copy-button placement used in the results
   panel's JSON view. Clicking the play button dispatches the SQL to
   the validator and auto-submits. */
.rule-example {
  position: relative;
}
.rule-block-play {
  position: absolute;
  top: 0.45rem;
  right: 0.45rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.7rem;
  height: 1.7rem;
  padding: 0;
  background: transparent;
  color: var(--muted);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 120ms ease, color 120ms ease;
}
.rule-example:hover .rule-block-play { opacity: 1; }
.rule-block-play:hover { color: var(--ok-fg); }
.rule-block-play:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  opacity: 1;
}

.rule-block-body {
  padding: 0.85rem 1rem 1rem;
  border-top: 1px solid var(--border);
}
.rule-block-desc {
  font-size: 0.88rem;
  color: var(--text);
  margin: 0 0 0.85rem;
  line-height: 1.55;
}
.rule-block-section {
  margin-top: 0.9rem;
}
.rule-block-section:first-child { margin-top: 0; }
.rule-block-label {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.4rem;
}
/* Colour-tinted labels for before/after example pairs so the eye can
   distinguish the buggy SQL from its corrected counterpart at a glance. */
.rule-block-label-bad  { color: var(--err-fg); }
.rule-block-label-good { color: var(--ok-fg); }
.rule-block-section p {
  margin: 0;
  font-size: 0.88rem;
  color: var(--text);
  line-height: 1.6;
}
/* Reuse the validator's .query-sql example styling verbatim for rule
   examples — same padding, same Prism palette, same dark-mode treatment. */
.rule-block .query-sql {
  max-height: none;
  margin: 0;
}
.rule-block-empty {
  margin: 0;
  font-size: 0.85rem;
}

@media (max-width: 640px) {
  .rule-block-head { flex-wrap: wrap; }
  .rule-block .rule-id,
  .rule-block .cat { font-size: 0.68rem; }
  .rules-toolbar-actions { margin-left: 0; width: 100%; }
}

/* ============================================================
   Hero, examples, FAQ — ChartDB-inspired validator layout
   ============================================================ */

.hero {
  text-align: center;
  padding: 2.5rem 1rem 2rem;
  max-width: 760px;
  margin: 0 auto;
}
.eyebrow {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  margin-bottom: 1rem;
  background: var(--panel);
}
.hero h1 {
  margin: 0 0 0.75rem 0;
  font-size: 2.15rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.hero-lead {
  margin: 0 auto 1.25rem;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--muted);
  max-width: 640px;
}
.hero-lead strong {
  color: var(--text);
  font-weight: 600;
}
.hero-trust {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.8rem;
  background: var(--ok-bg);
  color: var(--ok-fg);
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 500;
}
.hero-trust svg {
  flex: none;
}

@media (max-width: 640px) {
  .hero { padding: 1.5rem 0.5rem 1rem; }
  .hero h1 { font-size: 1.6rem; }
  .hero-lead { font-size: 0.95rem; }
}

/* --- Editor shell: a single rounded container that wraps the header bar
   and the SQL editor so they read as one unified card. No internal dividers;
   inner textarea/highlight/gutter lose their own borders since the shell
   handles the outline. */

.editor-form {
  margin-bottom: 0;
}
.editor-shell {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.editor-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.55rem 0.75rem 0.55rem 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--gutter-bg);
}
.editor-bar-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.1rem;
  flex: none;
}
.editor-title {
  margin: 0;
  font-size: 0.88rem;
  font-weight: 500;
  letter-spacing: -0.003em;
  line-height: 1.3;
  color: var(--text);
}
.editor-title-hint {
  margin-left: 0.25rem;
  font-weight: 400;
  font-size: 0.8rem;
  color: var(--muted);
}
.editor-title-hint kbd {
  display: inline-block;
  padding: 0.02rem 0.35rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.72rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 4px;
  color: var(--text);
}

/* When the editor lives inside .editor-shell, strip its own borders/radii
   — the shell provides the outer frame. */
.editor-shell .sql-editor > textarea,
.editor-shell .sql-editor > .sql-highlight {
  border: 0;
  border-radius: 0;
}
.editor-shell .editor-gutter {
  border-radius: 0;
  top: 0;
  left: 0;
  bottom: 0;
  border-right: 1px solid var(--border);
}

@media (max-width: 640px) {
  .editor-bar { flex-wrap: wrap; }
  .editor-bar-actions { align-self: flex-start; }
}

/* Floating toolbar above the editor panel (top-left).
   Holds the dialect selector and the "Try: …" example chips so the
   panel below stays focused on the SQL editor + results. The dialect
   <select> lives outside the form and is associated via the HTML5
   form="validate-form" attribute so it still posts. */
.panel-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 0.55rem 0.85rem;
  margin-bottom: 0.6rem;
  overflow-x: auto;       /* if the row is ever narrower than its content,
                             fall back to horizontal scroll rather than wrap */
}
.panel-toolbar::-webkit-scrollbar { display: none; }
.panel-toolbar { scrollbar-width: none; }
.panel-toolbar-field {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.1rem 0.55rem 0.1rem 0.7rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.panel-toolbar-field:hover {
  border-color: var(--border);
}
.panel-toolbar-field:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(59, 91, 219, 0.15);
}
.panel-toolbar-icon {
  color: var(--muted);
  flex: none;
}
.panel-toolbar-field select {
  border: 0;
  background: transparent;
  padding: 0.4rem 0.15rem;
  padding-right: 1.25rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text);
  min-width: 0;
  width: auto;
  cursor: pointer;
  /* Inline chevron (muted, 10px) */
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7076' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0 center;
  background-size: 10px;
  appearance: none;
  -webkit-appearance: none;
}
.panel-toolbar-field select:focus {
  outline: none;
}
[data-theme="dark"] .panel-toolbar-field select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239aa0a8' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
}
@media (max-width: 640px) {
  .panel-toolbar-field { width: 100%; justify-content: flex-start; }
  .panel-toolbar-field select { flex: 1; }
}
.editor-sub kbd {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.75rem;
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 4px;
  color: var(--text);
}

/* --- Example query chips --- */

.examples {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  border: 0;
}
.examples-label {
  font-size: 0.75rem;
  color: var(--muted);
  margin-right: 0.25rem;
  letter-spacing: 0.02em;
}
.chip {
  appearance: none;
  display: inline-flex;
  align-items: center;
  padding: 0.35rem 0.8rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  transition: filter 120ms ease;
}
.chip:hover { filter: brightness(0.97); }
.chip:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.08);
}

/* Same soft pastel treatment as the .hero-trust privacy badge — uses
   semantic tokens so light+dark modes stay consistent. One color per
   example, hinting at the outcome you'll see when clicked. */
/* Border uses color-mix() to soften the -fg color against the chip's bg,
   so the outline feels related to the text without being as dark. */
.chip[data-example="valid"] {
  background: var(--ok-bg);
  color: var(--ok-fg);
  border-color: color-mix(in srgb, var(--ok-fg) 28%, var(--ok-bg));
}
.chip[data-example="missing_standard"] {
  background: var(--warn-bg);
  color: var(--warn-fg);
  border-color: color-mix(in srgb, var(--warn-fg) 28%, var(--warn-bg));
}
.chip[data-example="unknown_table"] {
  background: var(--err-bg);
  color: var(--err-fg);
  border-color: color-mix(in srgb, var(--err-fg) 28%, var(--err-bg));
}
.chip[data-example="multi_statement"] {
  background: var(--info-bg);
  color: var(--info-fg);
  border-color: color-mix(in srgb, var(--info-fg) 28%, var(--info-bg));
}
.chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* --- Refined primary CTA (used on the Validate SQL button) --- */

.btn-validate {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.55rem 1.25rem;
  background: var(--ok-bg);
  color: var(--ok-fg);
  border: 1px solid color-mix(in srgb, var(--ok-fg) 32%, var(--ok-bg));
  border-radius: 8px;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, filter 120ms ease;
}
.btn-validate:hover {
  background: color-mix(in srgb, var(--ok-fg) 12%, var(--ok-bg));
  border-color: color-mix(in srgb, var(--ok-fg) 50%, var(--ok-bg));
}
.btn-validate:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.btn-validate:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Treat .btn-validate as the new primary so it overrides the older
   button[type="submit"] rule when this class is present. */
button[type="submit"].btn-validate { margin-left: auto; }
.btn-validate svg { flex: none; }

/* Primary-action bar that sits outside/below the editor panel, right-aligned.
   The submit button uses the HTML5 form="validate-form" attribute so it still
   submits the form even though it's outside the <form> element. */
.panel-footer-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.75rem;
  /* Symmetric spacing above and below the primary Validate button.
     .editor-form's own margin-bottom is set to 0 (see above) so neither
     side of this gap is affected by margin collapsing. */
  margin-top: 1.5rem;
  margin-bottom: 1.5rem;
}
.panel-footer-actions .htmx-indicator {
  color: var(--muted);
  font-size: 0.9rem;
}
@media (max-width: 640px) {
  .panel-footer-actions {
    justify-content: stretch;
  }
  .panel-footer-actions .btn-validate {
    flex: 1;
  }
}

/* --- Field group inside the toolbar row --- */

.row .field {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.row .field > label {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.row .field select {
  width: auto;
  min-width: 180px;
}

/* --- Loading spinner --- */

.htmx-indicator {
  display: none;
  align-items: center;
  gap: 0.5rem;
}
.htmx-request .htmx-indicator { display: inline-flex; }
.spinner {
  width: 13px;
  height: 13px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: fastssv-spin 0.7s linear infinite;
  flex: none;
}
@keyframes fastssv-spin { to { transform: rotate(360deg); } }

/* --- Empty state for results panel --- */

.results-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1.75rem 1rem;
  color: var(--muted);
  font-size: 0.9rem;
  text-align: center;
}
.results-empty svg {
  flex: none;
  color: var(--muted);
}

/* --- FAQ section --- */

.faq {
  max-width: none;
  margin: 2rem 0 0;
  padding: 0;
}
.faq h2 {
  font-size: 1.2rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: 0.75rem;
}
.faq details {
  border-bottom: 1px solid var(--border);
  padding: 0.1rem 0;
}
.faq details:first-of-type {
  border-top: 1px solid var(--border);
}
.faq summary {
  list-style: none;
  cursor: pointer;
  padding: 0.95rem 2rem 0.95rem 0;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--text);
  position: relative;
  transition: color 120ms ease;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  position: absolute;
  right: 0.25rem;
  top: 50%;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: translateY(-75%) rotate(45deg);
  transition: transform 150ms ease, border-color 120ms ease;
}
.faq details[open] summary::after {
  transform: translateY(-25%) rotate(-135deg);
}
.faq summary:hover {
  color: var(--accent);
}
.faq summary:hover::after {
  border-color: var(--accent);
}
.faq summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
.faq-body {
  padding: 0 0 1rem 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.6;
}
.faq-body p { margin: 0 0 0.5rem 0; }
.faq-body p:last-child { margin-bottom: 0; }
.faq-body code {
  font-size: 0.82rem;
}
.faq-body a {
  color: var(--accent);
  text-decoration: none;
}
.faq-body a:hover { text-decoration: underline; }

/* Call-to-action link — stands out from body prose so the "Open an issue"
   link reads as a real action, not ordinary inline link copy. */
.faq-body .faq-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.4rem 0.85rem;
  background: var(--accent);
  color: #ffffff;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 500;
  text-decoration: none;
  transition: background 120ms ease;
  margin-top: 0.25rem;
}
.faq-body .faq-cta:hover {
  background: var(--accent-hover);
  text-decoration: none;
}

/* Remove large default section margin from the first .panel after the hero
   so the hero + editor feel visually connected. */
.hero + .panel {
  margin-top: 0;
}
