/**
 * SQL Editor — CodeMirror 6 mount chrome + syntax theme.
 * ================================================================
 * Everything here targets either the static mount container
 * (`.sqled-editor-mount`) or CM6's OWN default class names
 * (`.cm-*`) plus the handful of `cm-idbe-*` classes editor.js's
 * `HighlightStyle` and decorations emit.
 *
 * Every colour is a design-system TOKEN (`var(--...)`), never a literal
 * hex. `[data-theme="light"]` in design-system.css redefines the same
 * token names, so light/dark follows the attribute automatically — no
 * JS re-theme on switch, and no light-mode overrides needed in this
 * file. Hardcoding hex here is a documented past mistake in this repo
 * (a purple accent shipped once where the brand is gold, #D39E57 /
 * var(--accent)).
 */

/* ---------------------------------------------------------------
   Task 8 review fix: the height chain down to .sqled-grid-viewport.
   `.view-container.view-fullheight.active` (styles/additions.css,
   NOT this file) only sets `min-height: 100%` -- a MINIMUM, not a
   definite size. A flex/grid child's `height: 100%` cannot resolve
   to a real pixel value against a parent whose own height is
   determined by CONTENT rather than a definite value, so every
   descendant down this whole chain (.sqled -> .sqled-center ->
   .sqled-results -> .sqled-results-body -> .sqled-grid ->
   .sqled-grid-viewport) grew to fit its CONTENT instead of being
   clamped to the viewport. Measured live before this fix: a
   10,000-row grid's `.sqled-grid-viewport.clientHeight` was 280,026
   (matching the full un-clamped spacer), `scrollTop` silently
   clamped to 0 -- non-scrollable, permanently frozen at rows 0-39.

   `#view-sqleditor` gets `height: 100%` (a REAL size, resolved
   against `.content-area`'s own definite height -- `.app-container`
   is `position: fixed; inset: 0`, which gives the whole chain above
   `.content-area` a real viewport-sized box) instead of touching the
   SHARED `.view-fullheight` class. `#view-ai-assistant` also carries
   `.view-fullheight` and was not audited as part of this fix --
   grep confirms it has no CSS of its own keyed off that class (its
   internal layout is unrelated selectors), so this is deliberately
   scoped to the one view this task actually touches rather than
   risking a reflow there. */
#view-sqleditor.view-fullheight.active {
  height: 100%;
  overflow: hidden;
}

.sqled-editor-mount {
  height: 100%;
  width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg-base);
  /* The command palette (Ctrl+Shift+P) is appended here and positioned
     absolutely. Without a positioned ancestor it resolves against the
     page and lands somewhere unrelated to the editor. */
  position: relative;
}

/* ---------------------------------------------------------------
   Degradation notice — shown only when window.CM6 failed to load.
   A blank panel with no message is the failure mode this exists to
   avoid, so it is never optional and never silent.
   --------------------------------------------------------------- */
.sqled-editor-notice {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  background: var(--warning-bg);
  border-bottom: 1px solid var(--warning-border);
  color: var(--warning);
  font-family: var(--font-ui);
  font-size: 12px;
  line-height: 1.5;
}

/* The fallback textarea reuses the pre-existing .sqled-textarea rule
   (styles/additions.css) for font/colour/padding; this only makes it
   share the flex column with the notice above it. */
.sqled-editor-mount.is-fallback .sqled-textarea {
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
}

/* ---------------------------------------------------------------
   CM6 chrome
   --------------------------------------------------------------- */
.sqled-editor-mount .cm-editor {
  flex: 1 1 auto;
  min-height: 0;
  height: 100%;
  color: var(--text-1);
  background: var(--bg-base);
}

.sqled-editor-mount .cm-editor.cm-focused {
  outline: none;
}

.sqled-editor-mount .cm-scroller {
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.8;
  overflow: auto;
}

.sqled-editor-mount .cm-content {
  padding: var(--sp-4) 0;
  caret-color: var(--accent);
}

.sqled-editor-mount .cm-line {
  padding: 0 var(--sp-5);
}

.sqled-editor-mount .cm-placeholder {
  color: var(--text-4);
  font-style: normal;
}

.sqled-editor-mount .cm-gutters {
  background: var(--bg-base);
  color: var(--text-4);
  border-right: 1px solid var(--border);
}

.sqled-editor-mount .cm-activeLine {
  background: var(--bg-card-hover);
}

.sqled-editor-mount .cm-activeLineGutter {
  background: var(--bg-card-hover);
  color: var(--text-2);
}

.sqled-editor-mount .cm-selectionBackground,
.sqled-editor-mount ::selection {
  background: var(--accent-dim) !important;
}

.sqled-editor-mount .cm-cursor,
.sqled-editor-mount .cm-dropCursor {
  border-left-color: var(--accent);
}

.sqled-editor-mount .cm-matchingBracket,
.sqled-editor-mount .cm-nonmatchingBracket {
  background: var(--accent-dim);
  outline: 1px solid var(--border-accent);
}

.sqled-editor-mount .cm-foldGutter .cm-gutterElement {
  color: var(--text-4);
  cursor: pointer;
}
.sqled-editor-mount .cm-foldGutter .cm-gutterElement:hover {
  color: var(--accent);
}
.sqled-editor-mount .cm-foldPlaceholder {
  background: var(--bg-elevated);
  border: 1px solid var(--border-mid);
  color: var(--text-3);
  border-radius: var(--r-sm);
  padding: 0 var(--sp-1);
}

.sqled-editor-mount .cm-searchMatch {
  background: var(--warning-bg);
  outline: 1px solid var(--warning-border);
}
.sqled-editor-mount .cm-searchMatch.cm-searchMatch-selected {
  background: var(--accent-dim);
  outline: 1px solid var(--border-accent);
}

.sqled-editor-mount .cm-panels {
  background: var(--bg-elevated);
  color: var(--text-1);
  border-top: 1px solid var(--border);
  font-family: var(--font-ui);
}
.sqled-editor-mount .cm-panel input,
.sqled-editor-mount .cm-panel button {
  font-family: var(--font-ui);
  color: var(--text-1);
  background: var(--bg-input);
  border: 1px solid var(--border-mid);
  border-radius: var(--r-sm);
}
.sqled-editor-mount .cm-panel button:hover {
  border-color: var(--border-accent);
}

.sqled-editor-mount .cm-tooltip {
  background: var(--bg-elevated);
  border: 1px solid var(--border-mid);
  color: var(--text-1);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-md);
  font-family: var(--font-ui);
}
.sqled-editor-mount .cm-tooltip-lint {
  padding: var(--sp-2) var(--sp-3);
  font-size: 12px;
  max-width: 320px;
}

/* Lint gutter + inline diagnostic ranges. Colour carries the severity;
   the underline style is what makes it legible without colour alone. */
.sqled-editor-mount .cm-lintRange-error {
  text-decoration: underline wavy var(--danger);
}
.sqled-editor-mount .cm-lintRange-warning {
  text-decoration: underline wavy var(--warning);
}
.sqled-editor-mount .cm-lintRange-info,
.sqled-editor-mount .cm-lintRange-hint {
  text-decoration: underline wavy var(--info);
}

/* ---------------------------------------------------------------
   Class-based syntax highlighting (HighlightStyle -> tag -> class).
   No inline styles from CM6 -- every rule below is what actually
   colours the SQL. Kept intentionally restrained: the accent is
   reserved for keywords, matching the codebase's own "accent is a
   10% rule" comment in design-system.css.
   --------------------------------------------------------------- */
.cm-idbe-keyword    { color: var(--accent); font-weight: 600; }
.cm-idbe-type        { color: var(--info); }
.cm-idbe-builtin     { color: var(--accent-light); }
.cm-idbe-string      { color: var(--success); }
.cm-idbe-number      { color: var(--warning); }
.cm-idbe-bool        { color: var(--warning); font-weight: 600; }
.cm-idbe-null        { color: var(--text-3); font-style: italic; }
.cm-idbe-comment     { color: var(--text-4); font-style: italic; }
.cm-idbe-operator    { color: var(--text-2); }
.cm-idbe-punctuation { color: var(--text-3); }
.cm-idbe-special     { color: var(--accent-light); }
.cm-idbe-invalid     { color: var(--danger); text-decoration: underline wavy var(--danger); }

/* ---------------------------------------------------------------
   Run-range visibility (Task 2 review carry-in).
   ---------------------------------------------------------------
   CM6's SQL grammar is a lenient tokenizer: an unterminated fragment
   merges FORWARD with everything up to the next ";" into one
   Statement node, so what Ctrl+Enter actually sends can be more than
   the caret's own line suggests. That text always fails loudly at the
   database rather than running silently wrong -- but the operator
   should be able to SEE the real run range before pressing anything.

   Two decorations, both applied via `Decoration.mark` from editor.js:
     - `.cm-idbe-active-stmt` is PERSISTENT, recomputed on every
       doc/selection change from `SQLEdStatements.statementAt` -- a
       standing, low-contrast marker of "this is what Ctrl+Enter would
       run right now".
     - `.cm-idbe-run-flash` is MOMENTARY, applied on Ctrl+Enter /
       Ctrl+Shift+Enter and cleared a few hundred ms later by a
       follow-up dispatch -- confirmation of exactly what was just
       claimed to run.
   --------------------------------------------------------------- */
/* 6% was the original tint and it was below the threshold at which a
   person notices anything: measured against the light theme it resolves
   to roughly a 3/255 shift off white. This marker is the ONLY thing on
   screen distinguishing "Run executes this one statement" from "Run
   executes everything I typed", and an operator with eleven statements
   in the buffer could not see it, ran once, and was told it succeeded.
   A signal nobody perceives is not a signal.

   The left border is what survives at a glance -- a full-strength accent
   rule down the run range reads as a gutter marker rather than as
   selection, so it does not compete with the real text selection the way
   a heavy fill would. */
.cm-idbe-active-stmt {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow: -3px 0 0 0 var(--accent);
}

.cm-idbe-run-flash {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
  transition: background 300ms var(--ease-out);
}

/* ---------------------------------------------------------------
   Cortex ghost text (modules/sqled/ghost.js, Ctrl+\).

   It must read as a PROPOSAL, never as text the operator typed --
   an operator who cannot tell the two apart runs a statement they
   did not write. Hence the reduced contrast and the italic: two
   independent signals, so the distinction survives a colour-blind
   reader and a low-contrast monitor alike.

   `pointer-events: none` because it is not selectable content --
   clicking it must place the caret in the real document underneath,
   not appear to place it inside a suggestion that does not exist yet.
   --------------------------------------------------------------- */
.cm-idbe-ghost {
  color: var(--text-3);
  font-style: italic;
  opacity: 0.72;
  pointer-events: none;
  white-space: pre;
}

/* The diff panel for Ctrl+K. Colour ALONE never carries the
   add/delete distinction -- the +/- gutter character does, so the
   panel is readable without colour perception. */
.sqled-diff {
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-sm);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: auto;
  max-height: 40vh;
}

.sqled-diff-line {
  display: flex;
  gap: var(--sp-2);
  padding: 1px var(--sp-2);
  white-space: pre;
}

.sqled-diff-line::before {
  content: " ";
  width: 1ch;
  flex: 0 0 auto;
  opacity: 0.6;
}

.cm-idbe-diff-del::before { content: "-"; }
.cm-idbe-diff-add::before { content: "+"; }

.cm-idbe-diff-del {
  background: var(--danger-bg);
}

.cm-idbe-diff-add {
  background: var(--success-bg);
}

/* ---------------------------------------------------------------
   Command palette (modules/sqled/palette.js, Ctrl+Shift+P).

   Positioned ABSOLUTE inside the editor container rather than fixed
   to the viewport: it belongs to the editor, and a fixed overlay
   would float over the rest of the app when the editor is scrolled
   out of view. `max-width` with no fixed `width` so a 390px
   viewport shrinks it instead of forcing the page wider.
   --------------------------------------------------------------- */
.sqled-palette {
  position: absolute;
  top: var(--sp-6);
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  width: min(560px, calc(100% - 2 * var(--sp-4)));
  max-width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.sqled-palette-input {
  width: 100%;
  box-sizing: border-box;
  padding: var(--sp-3);
  border: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
  color: var(--text-1);
  font-size: var(--fs-md);
  outline: none;
}

.sqled-palette-list {
  max-height: 46vh;
  overflow-y: auto;
}

.sqled-palette-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  cursor: pointer;
  color: var(--text-2);
}

/* The active row is marked by BACKGROUND AND a left border, so
   keyboard position is visible without relying on colour alone. */
.sqled-palette-item.is-active {
  background: var(--bg-hover, var(--bg-card));
  color: var(--text-1);
  box-shadow: inset 3px 0 0 var(--accent);
}

.sqled-palette-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* text-overflow is inert on an inline span -- a documented footgun in
     this codebase, already paid for once in the connections rail. */
  display: block;
}

.sqled-palette-hint {
  flex: 0 0 auto;
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-xs);
  color: var(--text-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0 var(--sp-1);
}

/* The completion degradation note. Warn-coloured AND prefixed by its own
   wording ("schema unavailable — …"), so it is legible as a warning without
   colour perception. */
.sqled-meta-warn {
  color: var(--warning);
  max-width: 32ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* text-overflow is inert on an inline span. */
  display: block;
}

.sqled-diff-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border-top: 1px solid var(--border);
}

.sqled-palette-empty {
  padding: var(--sp-3);
  color: var(--text-3);
  font-size: var(--fs-sm);
}

/* ---------------------------------------------------------------
   Tab strip (Task 7, modules/sqled/tabs.js). The strip itself never
   grows or shrinks the column it sits in (`flex: 0 0 auto`); the
   SCROLL happens inside `.sqled-tabs-scroll`, so a wide set of tabs
   never forces the page (or even the editor column) wider -- it
   forces a horizontal scrollbar on the strip alone. No fixed `width`
   anywhere below, only `max-width` caps that a narrow viewport is
   still free to shrink under.
   --------------------------------------------------------------- */
.sqled-tabstrip {
  display: flex;
  align-items: stretch;
  flex: 0 0 auto;
  min-width: 0;
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border);
}

.sqled-tabs-scroll {
  display: flex;
  align-items: stretch;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}

.sqled-tab {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  flex: 0 1 auto;
  min-width: 0;
  max-width: 200px;
  padding: var(--sp-2) var(--sp-2);
  border-bottom: 2px solid transparent;
  border-right: 1px solid var(--border);
  color: var(--text-3);
  font-family: var(--font-ui);
  font-size: 12px;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}

.sqled-tab:hover {
  color: var(--text-1);
  background: var(--bg-card-hover);
}

.sqled-tab.is-active {
  color: var(--text-1);
  background: var(--bg-base);
  border-bottom-color: var(--accent);
}

/* Ellipsis on an inline element is inert without an explicit block
   display -- see the standing CLAUDE.md note on the rail item /
   topology node truncation bug from the Connections rebuild. */
.sqled-tab-title {
  display: block;
  min-width: 0;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sqled-tab-dot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0;
  transition: opacity var(--t-fast);
}

.sqled-tab.is-dirty .sqled-tab-dot {
  opacity: 1;
}

.sqled-tab-close {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  padding: 0;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-4);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}

.sqled-tab-close:hover {
  color: var(--danger);
  background: var(--danger-bg);
}

.sqled-tab-add {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 28px;
  border: none;
  border-left: 1px solid var(--border);
  background: none;
  color: var(--text-3);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}

.sqled-tab-add:hover {
  color: var(--accent);
  background: var(--bg-card-hover);
}

/* ---------------------------------------------------------------
   Results grid (Task 8, modules/sqled/results.js). A virtualized
   grid, not a <table> -- CSS Grid gives every row identical column
   widths without the "columns resize as different rows scroll into
   view" jitter a native <table> would produce when only a WINDOW of
   its rows is ever present at once. `--sqled-grid-cols` is computed
   once per render() and set inline on `.sqled-grid-viewport`; the
   header row and every data row read the SAME custom property, so
   they can never drift out of alignment with each other.

   Two nested scroll boundaries, on purpose: `.sqled-results-body`
   (styles/additions.css) is the outer flex box the module renders
   INTO; `.sqled-grid-viewport` below is the actual scrolling element
   results.js measures (`clientHeight`) and listens on ('scroll') --
   keeping the header OUTSIDE that viewport (rather than a
   position:sticky row inside it) means the virtualization math never
   has to subtract a header height from scrollTop. At a narrow
   viewport a wide result set scrolls HORIZONTALLY inside
   `.sqled-grid-viewport` alone (`min-width: 0` on every ancestor in
   this chain is what makes that possible instead of the columns
   forcing the whole page wider) -- never the page itself.
   --------------------------------------------------------------- */
.sqled-grid {
  height: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  font-family: var(--font-mono);
  font-size: 12px;
}

.sqled-grid-header,
.sqled-grid-row {
  display: grid;
  grid-template-columns: var(--sqled-grid-cols, none);
}

.sqled-grid-header {
  flex: 0 0 auto;
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border);
}

.sqled-grid-hcell {
  padding: var(--sp-2) var(--sp-3);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-right: 1px solid var(--border);
}
.sqled-grid-hcell:last-child {
  border-right: none;
}

.sqled-grid-viewport {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  overflow: auto;
}

.sqled-grid-spacer {
  position: relative;
}

.sqled-grid-window {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  will-change: transform;
}

.sqled-grid-row {
  border-bottom: 1px solid var(--border);
}
.sqled-grid-row:hover {
  background: rgba(255, 255, 255, 0.015);
}

.sqled-grid-cell {
  display: flex;
  align-items: center;
  min-width: 0;
  padding: var(--sp-2) var(--sp-3);
  color: var(--text-2);
  border-right: 1px solid var(--border);
}
.sqled-grid-cell:last-child {
  border-right: none;
}

.sqled-grid-cell-inner {
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* .null-value itself is defined once in styles/additions.css (colour +
   italic) and reused verbatim here -- not redefined, so the two never
   drift apart into two different "this is NULL" looks. */

.sqled-grid-footer {
  flex: 0 0 auto;
  padding: var(--sp-2) var(--sp-3);
  text-align: center;
  font-family: var(--font-ui);
  font-size: 11px;
  color: var(--text-4);
  border-top: 1px solid var(--border);
}
/* The capped-with-UNKNOWN-total state only -- the one where the operator
   genuinely cannot tell from this screen alone whether more rows exist. */
.sqled-grid-footer.is-uncertain {
  color: var(--warning);
}

/* Error state (renderError). `.query-error`'s own background/border/colour
   come from styles/additions.css; these are just the internal layout the
   old inline `style="display:flex;..."` attributes used to carry. */
.query-error-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}
.query-error-title {
  font-weight: 600;
}
.query-error-message {
  display: block;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  color: var(--text-2);
}

/* ---------------------------------------------------------------
   Narrow viewports (375px and up). No fixed pixel widths above --
   the gutter, content and panels all size off their container, so
   there is nothing here to constrain.
   --------------------------------------------------------------- */
@media (max-width: 480px) {
  .sqled-editor-mount .cm-content,
  .sqled-editor-mount .cm-line {
    padding-left: var(--sp-2);
    padding-right: var(--sp-2);
  }
  .sqled-editor-notice {
    font-size: 11px;
    padding: var(--sp-2) var(--sp-3);
  }
  .sqled-tab {
    max-width: 120px;
    padding: var(--sp-1) var(--sp-2);
  }
  .sqled-tab-title {
    max-width: 80px;
  }
  .sqled-grid-hcell,
  .sqled-grid-cell {
    padding: var(--sp-1) var(--sp-2);
  }
}

/* ==========================================================================
   Query builder overlay (1.0.30)
   --------------------------------------------------------------------------
   Every colour is a token from design-system.css. The brand --accent is
   GOLD (#D39E57), not the generic SaaS purple, and hardcoding a hex here
   is a defect this codebase has already paid for once.
   ========================================================================== */

.sqlb-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  z-index: 20;
}

.sqlb-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
  flex: 0 0 auto;
}

.sqlb-title { font-weight: 600; color: var(--text-1); }
.sqlb-subtitle { color: var(--text-3); font-size: 12px; }
.sqlb-toolbar-r { margin-left: auto; display: flex; gap: 8px; align-items: center; }

.sqlb-body {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
}

.sqlb-rail {
  flex: 0 0 200px;
  min-width: 0;
  overflow: auto;
  border-right: 1px solid var(--border);
  padding: 8px;
}

.sqlb-table {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  color: var(--text-2);
  padding: 5px 7px;
  border-radius: 5px;
  cursor: pointer;
  /* display:block above is load-bearing: text-overflow is INERT on an
     inline element, and that is exactly what gave the Connections rail a
     horizontal scrollbar at narrow widths. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sqlb-table:hover { background: var(--bg-card-hover); color: var(--text-1); }

.sqlb-main {
  flex: 1 1 auto;
  min-width: 0;
  overflow: auto;
  padding: 12px;
  /* Container queries, NOT viewport media queries. This pane is viewport
     minus sidebar minus rail, so a viewport breakpoint fires while the
     pane is half that width -- measured on the Connections detail pane at
     1280 CSS px, where four stat cards sat at ~145px with every label
     wrapped onto four lines. */
  container-type: inline-size;
}

.sqlb-shape {
  flex: 0 0 240px;
  min-width: 0;
  overflow: auto;
  border-left: 1px solid var(--border);
  padding: 10px;
}
.sqlb-shape-section + .sqlb-shape-section {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.sqlb-canvas {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 10px;
}

.sqlb-node {
  flex: 0 1 240px;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-elevated);
  overflow: hidden;
}

.sqlb-node-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-card);
}

/* display:block so ellipsis actually applies -- see .sqlb-table. */
.sqlb-node-name {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
  color: var(--text-1);
  font-size: 12px;
}
.sqlb-node-alias {
  display: block;
  color: var(--accent);
  font-size: 11px;
  font-family: var(--font-mono, monospace);
}
.sqlb-join-kind {
  margin-left: auto;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-3);
}
.sqlb-node-drop {
  background: none; border: 0; cursor: pointer;
  color: var(--text-3); font-size: 15px; line-height: 1; padding: 0 2px;
}
.sqlb-node-drop:hover { color: var(--danger); }

.sqlb-node-cols { max-height: 190px; overflow: auto; padding: 4px 0; }
.sqlb-col {
  display: flex; align-items: center; gap: 6px;
  padding: 2px 8px; font-size: 12px; cursor: pointer;
}
.sqlb-col:hover { background: var(--bg-card-hover); }
.sqlb-col-name {
  display: block; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text-1);
}
.sqlb-col-type { color: var(--text-3); font-size: 10px; margin-left: auto; }
.sqlb-col-pk {
  color: var(--accent); font-size: 9px; font-weight: 700;
  border: 1px solid var(--border); border-radius: 3px; padding: 0 3px;
}
.sqlb-node-note { padding: 8px; color: var(--text-3); font-size: 11px; }
.sqlb-edge { flex: 0 0 10px; }

.sqlb-empty, .sqlb-where-empty, .sqlb-params-empty, .sqlb-preview-note {
  color: var(--text-3);
  font-size: 12px;
  padding: 8px 2px;
}

.sqlb-proposals { margin-top: 10px; }
.sqlb-proposal {
  display: flex; align-items: center; gap: 8px;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: var(--bg-elevated);
  padding: 6px 8px;
  font-size: 12px;
  color: var(--text-2);
  margin-bottom: 6px;
}
.sqlb-proposal button {
  margin-left: auto;
  background: var(--accent); color: var(--bg-card);
  border: 0; border-radius: 4px; padding: 3px 10px;
  font-weight: 600; cursor: pointer;
}

.sqlb-where { margin-top: 12px; }
.sqlb-group {
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: 6px;
  padding: 6px;
  margin: 6px 0;
}
.sqlb-group-head { display: flex; gap: 6px; align-items: center; }
.sqlb-group-op {
  background: var(--bg-elevated); color: var(--accent);
  border: 1px solid var(--border); border-radius: 4px;
  font-size: 11px; font-weight: 700; padding: 2px 8px; cursor: pointer;
}
.sqlb-add-rule, .sqlb-add-group, .sqlb-value-add {
  background: none; border: 1px solid var(--border); border-radius: 4px;
  color: var(--text-2); font-size: 11px; padding: 2px 8px; cursor: pointer;
}
.sqlb-remove {
  margin-left: auto; background: none; border: 0;
  color: var(--text-3); cursor: pointer; font-size: 14px; line-height: 1;
}
.sqlb-remove:hover { color: var(--danger); }
.sqlb-group-kids { padding-left: 8px; }

.sqlb-rule {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 4px 2px;
}
.sqlb-rule select, .sqlb-value {
  background: var(--bg-elevated); color: var(--text-1);
  border: 1px solid var(--border); border-radius: 4px;
  font-size: 12px; padding: 3px 6px; min-width: 0;
}
.sqlb-value { flex: 1 1 120px; }

.sqlb-param { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.sqlb-param-name { color: var(--text-1); font-size: 12px; }
.sqlb-param-type { color: var(--text-3); font-size: 10px; }
.sqlb-param input {
  flex: 1 1 60px; min-width: 0;
  background: var(--bg-elevated); color: var(--text-1);
  border: 1px solid var(--border); border-radius: 4px;
  font-size: 12px; padding: 3px 6px;
}

.sqlb-preview { margin-top: 12px; }
.sqlb-preview-scroll { max-height: 260px; overflow: auto; }
.sqlb-preview-table {
  width: 100%; border-collapse: collapse; font-size: 12px;
}
.sqlb-preview-table th, .sqlb-preview-table td {
  border-bottom: 1px solid var(--border);
  padding: 4px 8px; text-align: left; white-space: nowrap;
}
.sqlb-preview-table th { color: var(--text-3); font-weight: 600; }
.sqlb-preview-table td { color: var(--text-1); }
/* NULL is a distinct marker, never an empty cell: an empty cell asserts
   the value is an empty string, a different fact about their data. */
.sqlb-null { color: var(--text-3); font-style: italic; }

.sqlb-footer {
  flex: 0 0 auto;
  border-top: 1px solid var(--border);
  background: var(--bg-elevated);
  padding: 8px 12px;
}
/* Capped height with its own scroll, matching the .code-block posture.
   white-space: pre-wrap with max-height: none grows the pre unboundedly
   and blows out the flex parent -- that regression is already recorded. */
.sqlb-sql {
  max-height: 160px; overflow: auto;
  white-space: pre;
  margin: 0;
  font-family: var(--font-mono, monospace);
  font-size: 12px;
  color: var(--text-2);
}
.sqlb-warn {
  color: var(--warning);
  background: var(--warning-bg);
  border: 1px solid var(--warning-border);
  border-radius: 4px;
  padding: 4px 8px; font-size: 12px; margin-bottom: 6px;
}
.sqlb-error {
  color: var(--danger);
  background: var(--danger-bg);
  border: 1px solid var(--danger-border);
  border-radius: 4px;
  padding: 4px 8px; font-size: 12px; margin-bottom: 6px;
}

@container (max-width: 620px) {
  .sqlb-node { flex: 1 1 100%; }
  .sqlb-rule { gap: 4px; }
}

@media (max-width: 760px) {
  .sqlb-rail { flex-basis: 132px; }
  .sqlb-shape { flex-basis: 168px; }
}

/* ═══════════════════════════════════════════════════════════════════════
   ERD
   DOM nodes, one SVG edge layer underneath, pan and zoom as a CSS
   transform on the canvas. No diagram library.

   --erd-header-h and --erd-row-h are SHARED GEOMETRY: erd-layout.js
   computes every column anchor from the same two numbers. If they drift
   apart, each edge terminates a few pixels off the row it names, which
   reads as a rendering wobble rather than as a wrong answer.
   ═══════════════════════════════════════════════════════════════════════ */

.erd-pane {
  --erd-header-h: 30px;
  --erd-row-h: 20px;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  container-type: inline-size;   /* the pane, not the viewport, decides */
}
.erd-pane[hidden] { display: none; }

.erd-bar {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
/* The select inherits a full-width rule from the form styles, which in a
   flex row makes it eat the whole bar and push every button onto its own
   line -- most visible maximised, where the bar is widest. */
.erd-bar select { flex: 0 0 auto; width: auto; min-width: 104px; }
.erd-bar .btn { flex: 0 0 auto; }

.erd-scope {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-base);
  font-size: 11px;
  flex-shrink: 0;
}
.erd-scope-text { color: var(--text-2); }
.erd-scope-note { color: var(--text-3); }
.erd-scope-warn { color: var(--warning); }

.erd-viewport {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  background: var(--bg-base);
}

.erd-canvas {
  position: relative;
  transform-origin: 0 0;
}

.erd-edges {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
}
.erd-edge {
  fill: none;
  stroke: var(--border-strong);
  stroke-width: 1.5;
  pointer-events: stroke;
  cursor: pointer;
}
.erd-edge:hover { stroke: var(--accent); stroke-width: 2.5; }
/* An anchor that could not be placed on its column row is dashed, so the
   diagram never draws an unplaced terminus as though it had been
   measured. */
.erd-edge.is-inexact { stroke-dasharray: 4 3; opacity: 0.75; }

.erd-node {
  position: absolute;
  background: var(--bg-card);
  /* An explicit border, not a surface contrast: in light mode
     --bg-elevated and --bg-card are BOTH #ffffff. */
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
}
.erd-node.is-view { border-style: dashed; }
.erd-node.is-selected { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }

.erd-node-head {
  display: flex;
  align-items: center;
  gap: 6px;
  height: var(--erd-header-h);
  padding: 0 8px;
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--border);
}
/* display:block so the ellipsis applies -- it is inert on an inline
   span, which is what gave the Connections rail a horizontal scrollbar. */
.erd-node-name {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-1);
}
.erd-node-parts {
  flex: 0 0 auto;
  font-size: 9px;
  padding: 1px 4px;
  border-radius: 3px;
  background: var(--bg-card-hover);
  color: var(--text-3);
}

.erd-node-meta {
  display: flex;
  justify-content: space-between;
  gap: 6px;
  padding: 2px 8px;
  font-size: 10px;
  color: var(--text-3);
}

.erd-node-cols { padding: 2px 0; }
.erd-col {
  display: flex;
  align-items: center;
  gap: 6px;
  height: var(--erd-row-h);
  padding: 0 8px;
  font-size: 11px;
}
.erd-col-role {
  flex: 0 0 18px;
  font-size: 8px;
  font-weight: 700;
  color: var(--text-4);
}
.erd-col-role.is-pk { color: var(--accent); }
.erd-col-role.is-fk { color: var(--info); }
.erd-col-name {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-2);
}
.erd-col-type { flex: 0 0 auto; color: var(--text-3); font-size: 10px; }

.erd-node-note, .erd-note, .erd-detail-note {
  padding: 8px;
  font-size: 11px;
  color: var(--text-3);
}
.erd-note-error { color: var(--danger); }
.erd-note-warn { color: var(--warning); }

.erd-fallback-list { padding: 8px; font-size: 11px; font-family: var(--font-mono); }
.erd-fallback-row { color: var(--text-2); padding: 2px 0; }

.erd-detail {
  border-top: 1px solid var(--border);
  background: var(--bg-elevated);
  max-height: 45%;
  overflow: auto;
  flex-shrink: 0;
  padding: 8px;
}
.erd-detail[hidden] { display: none; }
.erd-detail-head { display: flex; align-items: center; gap: 8px; }
.erd-detail-title {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
  font-size: 12px;
  color: var(--text-1);
}
.erd-detail-meta, .erd-detail-comment { font-size: 11px; color: var(--text-3); margin-top: 4px; }
.erd-detail-cols { margin-top: 6px; }
.erd-detail-col { display: flex; gap: 6px; font-size: 11px; padding: 1px 0; }
.erd-detail-pairs { margin-top: 6px; }
.erd-detail-pair { font-family: var(--font-mono); font-size: 11px; color: var(--text-2); }

/* Maximised: the rail is too narrow for column rows, so the pane is
   promoted over the whole editor area rather than the diagram being
   squeezed into 280px. */
#view-sqleditor.erd-maximised .erd-pane {
  position: absolute;
  inset: 0;
  z-index: 40;
  background: var(--bg-base);
}
#view-sqleditor.erd-maximised .sqled-schema {
  position: static;
}

@container (max-width: 420px) {
  .erd-bar { gap: 2px; }
  .erd-bar .btn { padding: 2px 5px; }
}
