/* CSS Variables for Premium Design System
   =========================================================================
   THEME ARCHITECTURE (dark default here in :root; light overrides in the
   [data-theme="light"] block right below) - see client.js's "THEME
   SWITCHING" section for how the data-theme attribute itself gets set
   (persisted in localStorage, applied before first paint to avoid a
   flash-of-wrong-theme, and kept in sync with the Preferences modal).

   Two families of tokens:
   - The original small set (--bg-dark/--bg-card/--primary/--text-* etc.) -
     unchanged in spirit, still what most of this file uses directly.
   - A newer --surface / --overlay / --text-table set added alongside it,
     covering colors that used to be hardcoded hex/rgba literals scattered
     through specific components (the results table, the SQL/NL input
     boxes, dropdown menus, the scrollbar, etc.) - each was a dark-only
     "white wash over a dark surface" trick (e.g. rgba(255,255,255,0.05) as
     a subtle hover/border), which does NOT work unchanged on a light
     background, so those all needed their own explicit light-theme value
     rather than just being left as literals.

   --primary/--secondary/--danger keep the SAME hue in both themes (still
   unmistakably "this app's green", "error red", etc.) but the light theme
   shifts each to a slightly deeper shade - the original values were tuned
   for light text on a near-black page and don't have enough contrast for
   dark text on a light one wherever they're used as TEXT color (not just
   as a badge/button background), e.g. .status-success, .stat-card-title.
   ========================================================================= */
:root {
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: 'Fira Code', 'Courier New', Courier, monospace;

  /* Color Palette */
  --bg-dark: #080b11;
  --bg-card: rgba(15, 23, 42, 0.65);
  --bg-card-border: rgba(255, 255, 255, 0.08);
  --bg-input: rgba(5, 8, 16, 0.85);

  --primary: #10b981; /* Glowing CockroachDB green */
  --primary-hover: #34d399;
  --primary-glow: rgba(16, 185, 129, 0.15);
  /* RGB triplets (no alpha) for the rgba(var(--x-rgb), N) glow/shadow
     accents scattered through the file - lets those keep their own
     per-instance alpha while still tracking the theme's actual hue. */
  --primary-rgb: 16, 185, 129;
  --primary-hover-rgb: 52, 211, 153;

  --secondary: #6366f1; /* Modern Indigo */
  --secondary-hover: #818cf8;
  --secondary-rgb: 99, 102, 241;

  --danger: #f87171;
  --danger-hover: #ef4444;
  --danger-glow: rgba(248, 113, 113, 0.15);
  --danger-rgb: 248, 113, 113;
  --danger-hover-rgb: 239, 68, 68;

  --warning: #f59e0b;
  --warning-rgb: 245, 158, 11;
  /* Text color that would sit ON TOP of a solid --warning-colored badge -
     same reasoning as --on-primary/--on-accent-cyan above, computed
     per-theme since --warning (unlike --primary) isn't reliably
     bright/dark enough in both themes to share one constant value.
     Currently unused (#stopBtn.btn-stop moved to --accent-cyan/
     --on-accent-cyan below - see there for why) but kept defined
     alongside --warning itself for whenever a real warning-colored
     badge is needed. */
  --on-warning: #080b11;

  --text-primary: #f8fafc;
  --text-secondary: #94a3b8;
  --text-muted: #64748b;

  /* Modal/dropdown/table "surface" scale - previously hardcoded slate
     hexes (#0f172a/#1e293b/#334155/#131d31) repeated throughout the
     results table, tab bar, modal cards, and dropdown menus. */
  --surface-1: #0f172a;
  --surface-2: #1e293b;
  --surface-3: #334155;
  --surface-stripe: #131d31;

  /* Generic translucent-white "wash" tiers - borders/hovers/chip
     backgrounds that used to be one-off rgba(255,255,255,0.0N) literals.
     Named by their dark-theme alpha for readability; the light theme
     below redefines each as a dark-based wash instead (white-on-white
     would be invisible). */
  --overlay-1: rgba(255, 255, 255, 0.03);
  --overlay-2: rgba(255, 255, 255, 0.05);
  --overlay-3: rgba(255, 255, 255, 0.08);
  --overlay-4: rgba(255, 255, 255, 0.12);
  --overlay-6: rgba(255, 255, 255, 0.06);
  --overlay-18: rgba(255, 255, 255, 0.18);

  /* Results-table-specific text tones (distinct from --text-primary/
     --text-secondary, which are tuned for the app chrome, not a dense
     data grid). */
  --text-table: #e2e8f0;
  --text-table-strong: #f1f5f9;
  --chip-text: #cbd5e1;

  /* Distinct decorative accent (active tab, model-badge tagline; also
     the progress-status banner and #stopBtn.btn-stop below - the same
     blue as the header/logo mark, not a semantic "danger"/"warning"
     color) - kept separate from --primary so the two stay visually
     distinguishable in both themes. */
  --accent-cyan: #38bdf8;
  --accent-cyan-rgb: 56, 189, 248;
  /* Text color that sits ON TOP of a solid --accent-cyan-colored button
     (see #stopBtn.btn-stop) - same reasoning as --on-primary/--on-warning
     above, computed per-theme since --accent-cyan isn't reliably
     bright/dark enough in both themes to share one constant value. */
  --on-accent-cyan: #080b11;

  /* Text color that sits ON TOP of a solid --primary-colored button/badge -
     constant across themes: --primary is always bright enough that a dark
     label reads well on it, on either background. */
  --on-primary: #080b11;

  --scrollbar-thumb: rgba(255, 255, 255, 0.1);
  --scrollbar-thumb-hover: rgba(255, 255, 255, 0.2);

  /* The NL prompt textarea's own text color (not the same as
     --text-primary since it's set with !important against a hardcoded
     .speech-bubble-wrapper background - see that rule). */
  --prompt-text: #ffffff;

  /* Shared by --modal-scrim below and the guided tour's spotlight cutout
     (.tour-spotlight's box-shadow) - both are a full-page dimming scrim,
     just applied via two different CSS mechanisms. */
  --scrim-rgb: 3, 6, 12;
  --modal-scrim: rgba(var(--scrim-rgb), 0.7);

  /* .table-responsive/.stats-card-vertical's own "recessed input-like
     panel" background - same rgb as --bg-input's dark-theme value, but
     needs its own alpha so it stays valid once --bg-input goes solid
     (opaque, no alpha channel at all) in the light theme below. */
  --recessed-panel-bg: rgba(5, 8, 16, 0.45);

  --transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Light theme - see the block comment above :root. Applied via
   <html data-theme="light">, set by client.js before first paint. */
:root[data-theme="light"] {
  --bg-dark: #eef1f6;
  --bg-card: rgba(255, 255, 255, 0.75);
  --bg-card-border: rgba(15, 23, 42, 0.10);
  --bg-input: #eef2f7;

  --primary: #059669;
  --primary-hover: #047857;
  --primary-glow: rgba(5, 150, 105, 0.15);
  --primary-rgb: 5, 150, 105;
  --primary-hover-rgb: 4, 120, 87;

  --secondary: #4f46e5;
  --secondary-hover: #4338ca;
  --secondary-rgb: 79, 70, 229;

  --danger: #dc2626;
  --danger-hover: #b91c1c;
  --danger-glow: rgba(220, 38, 38, 0.12);
  --danger-rgb: 220, 38, 38;
  --danger-hover-rgb: 185, 28, 28;

  --warning: #b45309;
  --warning-rgb: 180, 83, 9;
  --on-warning: #ffffff;

  --text-primary: #0f172a;
  --text-secondary: #475569;
  --text-muted: #64748b;

  --surface-1: #ffffff;
  --surface-2: #f1f5f9;
  --surface-3: #e2e8f0;
  --surface-stripe: #f8fafc;

  --overlay-1: rgba(15, 23, 42, 0.03);
  --overlay-2: rgba(15, 23, 42, 0.05);
  --overlay-3: rgba(15, 23, 42, 0.08);
  --overlay-4: rgba(15, 23, 42, 0.12);
  --overlay-6: rgba(15, 23, 42, 0.05);
  --overlay-18: rgba(15, 23, 42, 0.16);

  --text-table: #1e293b;
  --text-table-strong: #0f172a;
  --chip-text: #334155;

  --accent-cyan: #0284c7;
  --accent-cyan-rgb: 2, 132, 199;
  --on-accent-cyan: #ffffff;

  --on-primary: #ffffff;

  --scrollbar-thumb: rgba(15, 23, 42, 0.15);
  --scrollbar-thumb-hover: rgba(15, 23, 42, 0.28);

  --prompt-text: #0f172a;

  --scrim-rgb: 15, 23, 42;
  --modal-scrim: rgba(var(--scrim-rgb), 0.4);

  --recessed-panel-bg: rgba(15, 23, 42, 0.05);
}

/* Reset & Global Styles */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  height: 100%;
  height: 100dvh; /* Dynamic viewport height lock */
  overflow: hidden; /* Lock viewport on all screen sizes */
}

body {
  background-color: var(--bg-dark);
  color: var(--text-primary);
  font-family: var(--font-sans);
  display: flex;
  flex-direction: column;
  position: relative;
}

/* Background Gradients/Decorations */
.background-decor {
  position: absolute;
  top: -10%;
  right: -5%;
  width: 500px;
  height: 500px;
  background: radial-gradient(circle, rgba(var(--primary-rgb), 0.06) 0%, rgba(0,0,0,0) 70%);
  z-index: -1;
  pointer-events: none;
}

.background-decor-2 {
  position: absolute;
  bottom: -10%;
  left: -5%;
  width: 600px;
  height: 600px;
  background: radial-gradient(circle, rgba(var(--secondary-rgb), 0.04) 0%, rgba(0,0,0,0) 70%);
  z-index: -1;
  pointer-events: none;
}

/* App Container */
.app-container {
  max-width: 1400px;
  width: 100%;
  height: 100dvh;
  margin: 0 auto;
  padding: 0.5rem 1.5rem 0.25rem 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  overflow: hidden;
}

/* DB Connection & Status Badge */
.status-badge,
.db-connection-info {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border-radius: 9999px;
  background: var(--overlay-1);
  border: 1px solid var(--bg-card-border);
  padding: 0.2rem 0.75rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  line-height: 1.2;
  min-width: 0;
  max-width: min(600px, 60vw);
  cursor: pointer; /* Ensures a hand pointer appears on hover */
}

.status-badge .conn-badge-text {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  font-weight: 500;
  padding: 0 0.05rem;
  white-space: nowrap;
  flex-shrink: 0;
}

.status-badge.connected {
  overflow: hidden;
  text-overflow: ellipsis;
}

.status-badge .conn-badge-icon {
  margin-left: 2px;
  margin-right: 3px;
  color: var(--text-secondary);
  width: clamp(10px, 1.5vw, 14px);
  height: clamp(10px, 1.5vw, 14px);
}

/* Layout Vertical */
.vertical-layout {
  display: flex;
  flex-direction: column;
  gap: 0.175rem;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

select {
  background-color: var(--bg-input);
  color: var(--text-primary);
  border: 1px solid var(--bg-card-border);
  border-radius: 6px;
  padding: 0.4rem 2rem 0.4rem 0.8rem;
  font-family: var(--font-sans);
  font-size: 0.85rem;
  cursor: pointer;
  outline: none;
  transition: var(--transition);
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.6rem center;
  background-size: 0.9rem;
}

/* The dropdown chevron above is a data-URI SVG with its stroke color baked
   in at build time (--text-secondary can't be referenced inside a
   data-URI) - this re-bakes it with the light theme's --text-secondary so
   the arrow stays visible against a light dropdown instead of rendering
   as a near-invisible dark-on-dark-ish sliver. */
:root[data-theme="light"] select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

select:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-glow);
}

/* Cards (Glassmorphism) */
.card {
  background-color: var(--bg-card);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--bg-card-border);
  border-radius: 12px;
  padding: 0.5rem 1.25rem;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
  display: flex;
  flex-direction: column;
  margin-bottom: 0;
}

.editor-card {
  margin-top: 0;
  flex-shrink: 0;
}

/* Dynamic Height Results Section */
.table-card {
  padding: 0.75rem;
  flex: 1;
  min-height: 0;
  max-height: none;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Textarea / Editor Base */
textarea {
  width: 100%;
  background-color: var(--bg-input);
  border: 1px solid var(--bg-card-border);
  border-radius: 8px;
  padding: 0.75rem 1rem;
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 0.9rem;
  line-height: 1.4;
  resize: vertical;
  transition: var(--transition);
}

textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-glow);
}

/* Buttons */
.btn {
  padding: 0.4rem 1.25rem;
  border-radius: 8px;
  font-family: var(--font-sans);
  font-size: 0.70rem;
  font-weight: 600;
  cursor: pointer;
  transition: var(--transition);
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.btn-primary {
  background-color: var(--primary);
  color: var(--on-primary);
}

.btn-primary:hover:not(:disabled) {
  background-color: var(--primary-hover);
  box-shadow: 0 0 15px rgba(var(--primary-rgb), 0.35);
}

.btn-primary:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.btn-secondary {
  background-color: var(--overlay-2);
  color: var(--text-primary);
  border: 1px solid var(--bg-card-border);
}

.btn-secondary:hover {
  background-color: var(--overlay-3);
}

/* Microphone Button Styles */
.mic-btn {
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  padding: 6px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: var(--transition);
  z-index: 5;
}

.mic-btn:hover {
  color: var(--primary);
  background: var(--overlay-2);
}

.mic-btn.listening {
  color: var(--danger);
  animation: pulse 1.5s infinite;
  background: rgba(var(--danger-rgb), 0.1);
}

.stat-label {
  font-size: 0.55rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

.stat-val {
  font-size: 0.65rem;
  font-weight: 700;
}

.status-unknown { color: var(--text-secondary); }
.status-success { color: var(--primary); text-shadow: 0 0 10px rgba(var(--primary-rgb), 0.2); }
.status-error { color: var(--danger); text-shadow: 0 0 10px rgba(var(--danger-rgb), 0.2); }

/* Tables & Results Container */
.table-responsive {
  max-height: 100%;
  overflow-y: auto;
  overflow-x: auto;
  width: 100%;
  border-radius: 8px;
  border: 1px solid var(--bg-card-border);
  background: var(--recessed-panel-bg);
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
  font-size: 0.9rem;
}

.data-table th, 
.data-table td {
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--bg-card-border);
}

.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 10;
  background-color: var(--surface-1);
  font-weight: 600;
  font-size: 0.75rem;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  box-shadow: 0 1px 0 var(--scrollbar-thumb);
}

.data-table tbody tr {
  transition: var(--transition);
}

.data-table tbody tr:hover {
  background-color: var(--overlay-1);
}

.cell-numeric {
  font-family: var(--font-mono);
  text-align: right;
}

.cell-null {
  font-style: italic;
}

.text-null {
  color: var(--text-muted);
  font-size: 0.8rem;
  letter-spacing: 0.05em;
}

.success-message {
  padding: 1.5rem;
  border-radius: 8px;
  background: rgba(var(--primary-rgb), 0.06);
  border: 1px solid rgba(var(--primary-rgb), 0.2);
  color: var(--text-primary);
}

.success-message strong {
  display: block;
  font-size: 1rem;
  color: var(--primary-hover);
  margin-bottom: 0.5rem;
}

.error-cell {
  padding: 0 !important;
}

.error-container {
  display: flex;
  gap: 1rem;
  padding: 1.5rem;
  background: rgba(var(--danger-hover-rgb), 0.06);
  border-top: 4px solid var(--danger);
  border-radius: 0 0 8px 8px;
}

.error-icon {
  font-size: 1.5rem;
}

.error-details strong {
  display: block;
  color: var(--danger);
  margin-bottom: 0.25rem;
}

.error-details p {
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 0.85rem;
  white-space: pre-wrap;
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.animate-spin {
  animation: spin 1s linear infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: .5; }
}

.animate-pulse {
  animation: pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

/* Header Section */
.crbot-header {
  margin-bottom: 0;
  padding-bottom: 0.075rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: 0.5rem;
  width: 100%;
}

.crbot-title-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0.15rem;
  min-width: max-content;
  flex-shrink: 0;
}

.crbot-title,
.header-title {
  font-size: clamp(0.9rem, 2.5vw, 1.4rem);
  font-weight: 700;
  color: #f8fafc;
  letter-spacing: -0.02em;
  margin: 0;
  margin-top: -0.15rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: linear-gradient(135deg, #ffffff 0%, #a5f3fc 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 1;
  min-width: 0;
}

.gear-btn, .help-btn, .history-btn, .more-menu-btn {
  background: var(--overlay-2);
  border: 1px solid var(--bg-card-border);
  color: var(--text-primary);
  padding: 0.35rem;
  border-radius: 50%;
  cursor: pointer;
  transition: var(--transition);
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(36px, 4vw, 50px);
  height: clamp(36px, 4vw, 50px);
  flex-shrink: 0;
}

.gear-btn svg, .help-btn svg, .history-btn svg, .more-menu-btn svg {
  width: clamp(20px, 2.2vw, 29px);
  height: clamp(20px, 2.2vw, 29px);
}

.gear-btn:hover {
  background: var(--overlay-4);
  color: var(--primary);
  transform: rotate(30deg);
}

.help-btn:hover,
.history-btn:hover,
.more-menu-btn:hover {
  background: var(--overlay-4);
  color: var(--primary);
}

/* Triple-dot "more" menu - collapses Help/History/Sign-in into one menu on
   very narrow screens (see the @media (max-width: 480px) block below) so
   the connection/model status badges stop getting squashed. Hidden by
   default; only shown under that breakpoint. Reuses the .auth-dropdown-*
   panel styling (see the Google Auth section further down) for visual
   consistency with the existing avatar dropdown. */
.more-menu-wrapper {
  position: relative;
  display: none;
  align-items: center;
  flex-shrink: 0;
}

.more-menu-dropdown {
  min-width: 160px;
}

/* .auth-dropdown-menu (this dropdown's own base class - see the Google Auth
   section further down) carries a stray `overflow: hidden` left over from
   an older, otherwise-superseded duplicate of that ruleset - harmless for
   the standalone avatar dropdown, but fatal here: renderAuthUI()'s signed-in
   markup (.auth-menu-wrapper > #authDropdown, also a .auth-dropdown-menu)
   gets reparented straight into #moreMenuAuthSlot below, so its own popup
   dropdown is nested INSIDE this one. With this box clipping its own
   overflow, that nested dropdown - including the "Log out" button - was
   being clipped down to nothing, i.e. present in the DOM and technically
   clickable in theory but invisible and unreachable in practice. An ID
   selector beats a plain class regardless of source order, so this reliably
   wins over that stray declaration without touching the standalone avatar
   dropdown's own (purely cosmetic) corner-clipping elsewhere. */
#moreMenuDropdown {
  overflow: visible;
}

.more-menu-auth-slot:not(:empty) {
  padding: 0.4rem 1rem 0.5rem;
  display: flex;
  align-items: center;
}

.more-menu-auth-slot .auth-container {
  width: 100%;
}

/* The reparented #g_id_signin div is only ever truly empty when Google
   auth isn't configured for this deployment (local dev) or hasn't
   finished loading yet - hide the slot and its divider in that case so the
   menu doesn't show a blank padded row. Reactive to renderAuthUI() filling
   or clearing the container's innerHTML, no JS wiring needed. */
.more-menu-auth-slot:has(> .auth-container:empty) {
  display: none;
}

.auth-dropdown-divider:has(+ .more-menu-auth-slot > .auth-container:empty) {
  display: none;
}

/* First-run onboarding cue: subtle glowing ring on the Help button so a
   brand-new user notices there's something to click, without being as
   disruptive as a tooltip or overlay. Removed permanently (see
   ONBOARDING_SEEN_KEY in client.js) the first time Help is opened. */
.help-btn-attention {
  color: var(--primary);
  border-color: var(--primary);
  animation: help-btn-pulse 2s ease-in-out infinite;
}

@keyframes help-btn-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--primary-glow); }
  50% { box-shadow: 0 0 0 6px var(--primary-glow); }
}

/* Generic "grayed out, not clickable right now" look, shared by two
   unrelated situations client.js triggers independently:
   - .icon-disabled on the history button: an anonymous-user restricted
     state (no verified login on this Cloud Run request) - clicking is
     meant to show an explanatory modal instead of the normal one, though
     that particular behavior isn't wired up yet.
   - .badge-disabled on the DB connection / model badges: toggled by
     setButtonsDisabled() while a query is in flight, so the active
     connection/model can't be swapped out from under it - clicking is a
     plain no-op here (see modelTriggerBadge's/configTriggerBadge's own
     'click' listeners). */
.history-btn.icon-disabled,
.status-badge.badge-disabled {
  opacity: 0.45;
  filter: grayscale(1);
  cursor: not-allowed;
}

.history-btn.icon-disabled:hover {
  background: var(--overlay-2);
  color: var(--text-primary);
}

.status-badge.badge-disabled:hover {
  background: var(--overlay-1);
}

.crbot-icon-wrapper {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  justify-content: center;
  filter: drop-shadow(0px 0px 10px rgba(56, 189, 248, 0.35));
  flex-shrink: 0;
}

.header-icon-label {
  display: flex;
  flex-direction: column;
  justify-content: center;
  line-height: 1.15;
  white-space: nowrap;
}

.header-icon-label .full-text {
  display: inline;
  color: var(--accent-cyan);
  font-size: 1.2rem;
  font-weight: 600;
}

.header-icon-label .short-text {
  display: none;
  color: var(--accent-cyan);
  font-size: 0.85rem;
  font-weight: 700;
}

@media (max-width: 768px) {
  .header-icon-label .full-text {
    display: none;
  }
  .header-icon-label .short-text {
    display: inline;
  }
}

@media (max-width: 480px) {
  .crbot-header {
    gap: 0.35rem;
  }
  .status-badge {
    max-width: 168px;
  }
  /* Collapse Help/History/Sign-in into the triple-dot menu. The ">"
     combinator matters here: it only hides #g_id_signin while it's still a
     direct child of .header-actions (its original header position).
     client.js's relocateMoreMenuAuthSlot() moves that same live node into
     #moreMenuAuthSlot (inside the dropdown below) whenever this breakpoint
     is active, at which point it's no longer a direct child here and stays
     visible in its new spot - so sign-in/sign-out keeps working on mobile
     instead of being hidden along with the header copy. */
  .header-actions > .help-btn,
  .header-actions > .history-btn,
  .header-actions > .gear-btn,
  .header-actions > .auth-container {
    display: none !important;
  }
  .more-menu-wrapper {
    display: inline-flex;
  }
}

/* Natural Language & SQL Row Layouts */
.nl-prompt-row,
.sql-prompt-row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  width: 100%;
}

/* Speech/Prompt Containers */
.speech-bubble-wrapper {
  position: relative;
  flex: 1;
  background: var(--surface-1);
  border: 3px solid var(--surface-3);
  border-radius: 0;
  transform: none;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), inset 0 0 12px rgba(var(--primary-rgb), 0.08);
  padding: 4px;
  box-sizing: border-box;
}

.speech-bubble-wrapper.sql-bubble {
  background: var(--surface-1);
  border: 3px solid var(--surface-3);
  border-radius: 0;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), inset 0 0 12px rgba(var(--primary-rgb), 0.08);
  height: 100px;
  min-height: 100px;
  max-height: 600px;
  resize: vertical;
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  padding: 6px;
}

.nl-prompt-row .speech-bubble-wrapper,
.nl-prompt-row .nl-prompt-controls,
.sql-prompt-row .sql-prompt-controls {
  height: 42px;
  min-height: 42px;
}

.inputs-column .input-row:first-child {
  min-height: auto;
  height: auto;
}

.sql-prompt-row .speech-bubble-wrapper.sql-bubble {
  height: 100px;
  min-height: 100px;
  max-height: 600px;
  resize: vertical;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Textarea Box Styles */
.speech-bubble-wrapper textarea#aiPrompt {
  width: 100%;
  height: 34px;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  color: var(--prompt-text) !important;
  font-family: var(--font-mono) !important;
  font-size: 0.85rem;
  line-height: 1.25;
  padding: 0.25rem 0.6rem;
  padding-right: 2.2rem !important;
  resize: none; 
  outline: none;
  transform: none;
  border-radius: 0;
  box-sizing: border-box;
}

.speech-bubble-wrapper textarea#aiPrompt::placeholder {
  color: var(--text-muted);
  font-weight: 400;
  font-style: italic;
  opacity: 0.8;
}

.speech-bubble-wrapper textarea#aiPrompt:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.speech-bubble-wrapper.sql-bubble textarea#sqlQuery {
  width: 100%;
  height: 100px;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  color: var(--primary-hover) !important;
  font-family: var(--font-mono) !important;
  font-size: 0.9rem;
  line-height: 1.45;
  padding: 0.5rem 0.8rem;
  resize: none;
  outline: none;
  transform: none;
  border-radius: 0;
  box-sizing: border-box;
}

/* Position the Execute button in the top-right corner */
#runBtn.sql-overlay-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.2rem 0.45rem;
  font-size: 0.65rem;
  font-weight: 500;
  line-height: 1;
  gap: 0.25rem;          /* reduced spacing between icon and text */
  border-radius: 4px;    /* scaled down radius */
  z-index: 2;
  /* z-index: 10; Ensures it renders on top of CodeMirror scroll/gutters */
  background: rgba(var(--primary-rgb), 0.85); /* Emerald accent */
  color: #ffffff;
  border: 1px solid rgba(var(--primary-hover-rgb), 0.4);
  border-radius: 6px;
  backdrop-filter: blur(4px);
  cursor: pointer;
  transition: all 0.15s ease-in-out;
}

#runBtn.sql-overlay-btn:hover:not(:disabled) {
  background: rgba(var(--primary-rgb), 1);
  box-shadow: 0 0 10px rgba(var(--primary-rgb), 0.4);
}

#runBtn.sql-overlay-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.speech-bubble-wrapper.sql-bubble .CodeMirror {
  height: 100% !important; 
  width: 100% !important;
  background: transparent !important;
  border-radius: 0;
}

.sql-bubble .CodeMirror-lines {
  padding-right: 120px;
}

.speech-bubble-wrapper.sql-bubble .CodeMirror.cm-readonly {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Stats Cards */
.stats-card-vertical {
  background: var(--recessed-panel-bg);
  border: 1px solid var(--bg-card-border);
  border-radius: 8px;
  padding: 0.15rem 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  font-size: 0.6rem;
  flex: 1;
  justify-content: center;
}

.stats-card-vertical .stat-item-inline {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.status-working {
  color: var(--warning);
  font-weight: 600;
}

/* Modal Overlay & Card */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: var(--modal-scrim);
  backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  transition: opacity 0.2s ease;
  padding: 1rem;
}

.modal-overlay.hidden {
  display: none;
}

.modal-card {
  background-color: var(--surface-1);
  border: 1px solid var(--bg-card-border);
  border-radius: 12px;
  width: 100%;
  max-width: 680px;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}

.modal-card-large {
  max-width: 1000px;
}

.modal-header {
  padding: 1.25rem;
  border-bottom: 1px solid var(--bg-card-border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.modal-header h2 {
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--text-primary);
}

.modal-close-btn {
  background: none;
  border: none;
  color: var(--text-primary);
  opacity: 0.75;
  font-size: 1.5rem;
  cursor: pointer;
}

.modal-close-btn:hover {
  color: var(--text-primary);
  opacity: 1;
}

/* ===========================================================================
   GUIDED TOUR (first-run onboarding)
   =========================================================================== */
.tour-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
}

.tour-overlay.hidden {
  display: none;
}

.tour-spotlight {
  position: fixed;
  border-radius: 10px;
  box-shadow: 0 0 0 9999px rgba(var(--scrim-rgb), 0.78);
  border: 2px solid var(--primary);
  pointer-events: none;
  transition: top 0.3s ease, left 0.3s ease, width 0.3s ease, height 0.3s ease;
}

.tour-tooltip {
  position: fixed;
  width: 300px;
  max-width: calc(100vw - 2rem);
  background: var(--surface-1);
  border: 1px solid var(--bg-card-border);
  border-radius: 12px;
  padding: 1.1rem 1.15rem 1rem;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(var(--primary-rgb), 0.15);
  transition: top 0.3s ease, left 0.3s ease;
}

.tour-tooltip-step {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--primary-hover);
  margin-bottom: 0.4rem;
}

.tour-tooltip h3 {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 0.4rem;
}

.tour-tooltip p {
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-secondary);
}

.tour-tooltip-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 1rem;
}

.tour-tooltip-actions-right {
  display: flex;
  gap: 0.5rem;
}

.tour-nav-btn {
  padding: 0.4rem 0.85rem;
  font-size: 0.82rem;
}

.tour-skip-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 0.8rem;
  cursor: pointer;
  padding: 0.4rem 0.2rem;
  transition: var(--transition);
}

.tour-skip-btn:hover {
  color: var(--text-secondary);
}

/* Shown inside the Help modal only when the "Quick prompts" row has been
   dismissed - the real UI path back to it (see restoreQuickPrompts() in
   client.js), so nobody has to reach for devtools/localStorage. */
.help-modal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.6rem 1.25rem;
  border-bottom: 1px solid var(--bg-card-border);
  background: var(--overlay-1);
}

.restore-quick-prompts-btn {
  background: transparent;
  border: 1px solid var(--bg-card-border);
  color: var(--primary-hover);
  font-size: 0.8rem;
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  cursor: pointer;
  transition: var(--transition);
}

.restore-quick-prompts-btn:hover {
  background: var(--primary-glow);
  border-color: var(--primary);
}

.modal-body {
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  overflow-y: auto;
}

/* configModal's form needs its Save button pinned below a scrolling list
   of DB connections (which can grow arbitrarily tall as custom connections
   are added) rather than scrolling away with everything else - overrides
   the generic .modal-body padding/scroll behavior above, scoped to just
   this one modal via #configForm so every other modal (.modal-body used
   directly, no split-scroll wrapper markup) keeps its original layout. */
#configForm.modal-body {
  padding: 0;
  gap: 0;
  overflow: hidden;
  min-height: 0;
}

/* The scrolling region - min-height: 0 lets it shrink within modal-card's
   capped height instead of pushing the footer off-screen; overflow-y:
   auto is what actually scrolls once content exceeds that shrunk height. */
#configForm .modal-scroll-content {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* Stays outside the scrolling region above, so it (and the Save button it
   holds) is always visible without scrolling. */
#configForm .modal-footer-fixed {
  flex-shrink: 0;
  padding: 1rem 1.25rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  border-top: 1px solid var(--bg-card-border);
}

.help-dialog-body {
  line-height: 1.6;
  color: var(--text-secondary);
  max-height: 500px;
  flex: 1;
}

.help-dialog-body h3 {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--primary);
  margin-top: 0.5rem;
}

.help-dialog-body p {
  font-size: 0.85rem;
}

.help-dialog-body ol,
.help-dialog-body ul {
  font-size: 0.85rem;
  padding-left: 1.25rem;
  margin: 0.4rem 0;
}

.help-dialog-body li {
  margin-bottom: 0.4rem;
}

.help-dialog-body .help-quickstart {
  background: var(--overlay-2);
  border: 1px solid var(--bg-card-border);
  border-radius: 8px;
  padding: 0.9rem 1rem 0.9rem 0.4rem;
  margin-bottom: 1rem;
}

.help-dialog-body .help-quickstart h3 {
  margin-top: 0;
  padding-left: 0.6rem;
}

.config-section {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.config-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-secondary);
}

.config-input, .config-select {
  width: 100%;
  padding: 0.6rem 0.8rem;
  border-radius: 6px;
  border: 1px solid var(--bg-card-border);
  background-color: var(--bg-input);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 0.85rem;
  outline: none;
}

.config-input:focus, .config-select:focus {
  border-color: var(--primary);
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.5rem;
}

.hidden {
  display: none !important;
}

.text-center { text-align: center; }
.text-muted { color: var(--text-muted); }
.py-8 { padding-top: 3rem; padding-bottom: 3rem; }

::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbar-thumb-hover);
}

.app-footer {
  flex-shrink: 0;
  text-align: center;
  padding: 0.35rem 0;
  border-top: 1px solid var(--bg-card-border);
  color: var(--text-muted);
  font-size: 0.825rem;
  margin-top: 0.25rem;
}

.radio-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  background-color: var(--bg-input);
  border: 1px solid var(--bg-card-border);
  border-radius: 6px;
  padding: 0.6rem 0.8rem;
}

/* Sub-group headings inside #modalDbRadioGroup ("Pre-configured Database
   Playgrounds" over the CONFIGURED_DBS presets, "Custom Database
   Connections" over customDbsContainer) - a plain label, not a button or
   input, so it's excluded from .radio-group's own flex gap sizing that
   the radio/custom-connection rows use for click targets. */
.radio-group-heading {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

/* No border-top of its own here for the "Custom Database Connections"
   heading, even though it visually starts a new group - #customDbsContainer
   right below it already draws that exact divider line itself (see
   .custom-dbs-list:not(:empty) below), so adding one here too would just
   double it up. */
.radio-group-heading:not(:first-child) {
  margin-top: 0.3rem;
}

/* Extra breathing room specifically above "Custom Database Connections" -
   more than a plain sub-group heading gets from the rule just above, since
   this one visually starts a whole new section (custom connections), not
   just another sub-group under the same one. Same specificity as that
   rule (two classes each) - declared after it so this wins the tie on
   source order, rather than relying on a specificity difference. */
.radio-group-heading.radio-group-heading-custom {
  margin-top: 1.1rem;
}

/* Two-column layout for the preset radio options (see renderDbRadioButtons()
   in client.js) - purely visual grouping, wraps in the same .radio-group
   flow as everything else. min-width: 0 lets each column's own content
   (radio-option's flex row) shrink below its natural width instead of
   overflowing/forcing the modal wider when a preset name is long. */
.preset-columns {
  display: flex;
  gap: 1rem;
}

.preset-column {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 1;
  min-width: 0;
}

/* Short reassurance line under the "Custom Database Connections" heading
   (see renderDbRadioButtons() in client.js) - deliberately smaller/quieter
   than .radio-group-heading itself, since it's a one-liner pointing at
   help.html for the real explanation, not a heading of its own. */
.custom-db-security-note {
  font-size: 0.72rem;
  line-height: 1.35;
  color: var(--text-muted);
  margin: -0.1rem 0 0.15rem;
}

.custom-db-security-note a {
  color: inherit;
  opacity: 0.85;
  text-decoration: underline dotted;
}

.radio-option {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.85rem;
  color: var(--text-primary);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

/* Also applies to the radio inside .custom-db-header-row (each custom
   connection card's own selector radio, right below the preset list in
   #modalDbRadioGroup - see renderCustomDbRows()) - that one isn't wrapped
   in a .radio-option label the way a preset's is (its row has a type
   select/name input/toggle/remove button alongside it, not just a label),
   so without this it rendered as a bare, unstyled native browser radio -
   a different size/color than every preset's right above it, even though
   both are options in the same db_connection_option radio group. */
.radio-option input[type="radio"],
.custom-db-header-row input[type="radio"] {
  accent-color: var(--primary);
  width: 1rem;
  height: 1rem;
  cursor: pointer;
}

.radio-option span {
  word-break: normal;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* "All configured databases" (see renderDbRadioButtons() in client.js) -
   the first option in the group, ahead of the "Pre-configured Database
   Playgrounds" heading, since it applies across both presets and custom
   connections rather than belonging to either list. Bolded like a heading
   would be, to read as a distinct top-level choice rather than just
   another item in the preset list right below it. */
.all-databases-option {
  font-weight: 600;
  white-space: normal;
  margin-bottom: 0.15rem;
}

/* Short explanation directly under the "All configured databases" option
   (see renderDbRadioButtons() in client.js) - quieter/smaller than the
   option's own label, same relationship .custom-db-security-note has to
   the "Custom Database Connections" heading above. */
.all-databases-hint {
  font-size: 0.72rem;
  line-height: 1.35;
  color: var(--text-muted);
  margin: 0 0 0.9rem;
}

.checkbox-option {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.85rem;
  color: var(--text-primary);
  cursor: pointer;
  user-select: none;
}

.checkbox-option input[type="checkbox"] {
  accent-color: var(--primary);
  width: 1rem;
  height: 1rem;
  cursor: pointer;
}

/* ===========================================================================
   CUSTOM DB CONNECTION CARDS (config modal)
   Each saved custom connection is enclosed between two horizontal lines
   (the list's own top border plus each card's bottom border, so adjacent
   cards share one line rather than doubling up), with its fields laid out
   one logical row per line instead of everything wrapping together.
   =========================================================================== */
.custom-dbs-list {
  display: flex;
  flex-direction: column;
}

.custom-dbs-list:not(:empty) {
  border-top: 1px solid var(--bg-card-border);
}

.custom-db-card {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--bg-card-border);
}

.custom-db-header-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.custom-db-header-row .custom-db-type-select {
  flex: 0 0 auto;
  width: 8.5rem;
}

.custom-db-header-row .custom-db-name-input {
  flex: 1 1 auto;
  min-width: 0;
}

.custom-db-toggle-btn,
.custom-db-remove-btn {
  /* Doubled from the original 0.15rem 0.6rem padding / 0.7rem font-size -
     these are the only way to expand/collapse or delete a saved custom
     connection, so they need to read as clearly clickable rather than
     blend into the row alongside the type/name fields. */
  flex: 0 0 auto;
  padding: 0.3rem 1.2rem;
  line-height: 1;
  font-size: 1.4rem;
}

.custom-db-field-row {
  display: flex;
  align-items: center;
  gap: 0.5rem 1rem;
  flex-wrap: wrap;
  padding-left: 1.9rem;
}

.custom-db-field-row.align-start {
  align-items: flex-start;
}

/* A field-row.align-start row (Service Account Key/Private Key - a
   multi-line textarea) needs its own field(s) top-aligned too, or the
   label-beside-input change above would vertically center the label next
   to a 3-row-tall textarea instead of sitting level with its first line. */
.custom-db-field-row.align-start .custom-db-field {
  align-items: flex-start;
}

.custom-db-field-row.align-start .custom-db-field-label {
  padding-top: 0.3rem;
}

.custom-db-field {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

/* Every field (inside a field-row or the header row alike) is
   label-beside-input, matching the header row's own Name field - not
   label-above-input the way grouped fields (e.g. Warehouse / Database /
   Schema sharing one line) used to render. Deliberately NOT given a
   min-width (or any other rule that would pad a short label out to match
   a longer one elsewhere) - fields are not meant to visually align into
   columns, each label just sits directly next to its own input. */
.custom-db-field-row .custom-db-field {
  /* Basis/min-width sized so a 3-field row (e.g. Oracle's Service Name /
     SID / Schema, Snowflake's Warehouse / Database / Schema) fits on one
     line at the modal's usual width instead of wrapping its 3rd field
     down early - flex-grow still expands each field to fill the row's
     actual leftover space once wrapping is decided, so 2-field rows (e.g.
     Host / Port) aren't left narrower than before. */
  flex: 1 1 170px;
  min-width: 150px;
  /* Very little space between a label and its input - tighter than the
     0.4rem every other field/input pairing (header row's Name, etc.)
     uses. */
  gap: 0.2rem;
}

.custom-db-header-row .custom-db-field {
  flex: 1 1 auto;
}

.custom-db-field-row .custom-db-field.wide {
  flex: 1 1 100%;
}

.custom-db-field-label {
  font-size: 0.78rem;
  color: var(--text-secondary);
  white-space: nowrap;
  flex: 0 0 auto;
}

.custom-db-field-row .custom-db-field-label {
  white-space: normal;
  /* Caps how much of the field a label can claim on its own line -
     without this, an unwrapped long label could eat the field's entire
     flex-computed width and leave its input squeezed to a sliver. Not an
     alignment device (no min-width here - see the comment above) - just
     an overflow guard. */
  max-width: 8rem;
}

.custom-db-field-label a {
  color: inherit;
  opacity: 0.85;
  text-decoration: underline dotted;
}

.custom-db-field-label .optional-hint {
  display: block;
  font-size: 0.66rem;
  opacity: 0.6;
  font-weight: 400;
}

/* Standalone hint line under the MongoDB Atlas SQL ODBC field (not nested
   inside a .custom-db-field-label, so the rule above doesn't reach it) -
   deliberately smaller/lower-contrast than even that hint style. */
.custom-db-mongo-hint {
  display: block;
  font-size: 0.6rem;
  opacity: 0.45;
  font-weight: 400;
}

.custom-db-field input,
.custom-db-field select,
.custom-db-field textarea {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
}

.custom-db-field textarea {
  resize: vertical;
}

.custom-db-add-btn {
  align-self: flex-start;
  margin-top: 0.5rem;
}

.results-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  flex: 1;
  min-height: 0;
  background-color: var(--surface-1);
  border-radius: 8px;
  overflow: hidden;
}

/* Wraps the retry-status banner and the Cancel button as siblings -
   needed because showRetryStatus()/showPhaseStatus()/etc. fully
   overwrite #resultsRetryStatus's own innerHTML on every call, so the
   Cancel button can't just live nested inside that div.
   justify-content: flex-end keeps the button pinned to the right edge
   even when #resultsRetryStatus is hidden (display: none via .hidden) -
   without it, #stopBtn was the row's only flex item at that point and
   fell back to flex-start, visibly jumping to the left every time the
   status banner disappeared. */
.results-status-row {
  flex-shrink: 0;
  display: flex;
  align-items: stretch;
  justify-content: flex-end;
}

.results-retry-status {
  /* The header/logo's own blue (--accent-cyan) - was --warning's amber
     until the light theme's specific shade (#b45309, a dark rust/brown)
     read as aggressively red rather than as a mild in-progress notice. */
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1rem;
  background: rgba(var(--accent-cyan-rgb), 0.08);
  border-bottom: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
  color: var(--accent-cyan);
  font-size: 0.85rem;
}

.results-retry-status .retry-status-icon {
  display: inline-flex;
  font-size: 0.95rem;
  line-height: 1;
}

#stopBtn.btn-stop {
  /* The header/logo's own blue (--accent-cyan), matching .results-retry-
     status's own progress-banner color above - not --danger's bright red
     (too alarming for "cancel an in-progress query"), and not --warning's
     amber either (the light theme's particular shade of it read as
     aggressively red-orange rather than as a mild notice). */
  flex-shrink: 0;
  align-self: center;
  margin: 0 0.75rem;
  background-color: var(--accent-cyan);
  color: var(--on-accent-cyan);
}

#stopBtn.btn-stop:hover {
  filter: brightness(1.1);
}

.results-tabs-nav {
  flex-shrink: 0;
  display: flex;
  align-items: flex-end;
  background-color: var(--surface-2);
  padding: 6px 8px 0 8px;
  gap: 0px;
  overflow-x: auto;
  user-select: none;
  border-bottom: 1px solid var(--surface-3);
}

.result-tab-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  min-height: 34px;
  padding: 6px 16px;
  font-size: 0.8125rem;
  font-family: inherit;
  color: var(--text-secondary);
  background: transparent;
  border: none;
  outline: none;
  cursor: pointer;
  /* Two lines - the database name (multi-database mode only - see
     buildResultsTabsNav()'s dbLabel) above the "Query N (rows)"/"Note"/
     etc. line - separated by a literal "\n" client.js puts in
     textContent, honored here instead of collapsed to a space. No
     max-width and no flex-shrink: a tab is exactly as wide as its longer
     line needs, however many tabs that adds up to - .results-tabs-nav's
     own overflow-x: auto scrolls the row instead of anything here
     truncating or wrapping either line further. */
  white-space: pre-line;
  line-height: 1.3;
  min-width: 120px;
  flex-shrink: 0;
  transition: color 0.15s ease, background-color 0.15s ease;
  z-index: 1;
}

.result-tab-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 400;
}

.result-tab-badge {
  font-size: 0.7rem;
  background: var(--surface-3);
  color: var(--chip-text);
  padding: 1px 6px;
  border-radius: 10px;
  margin-left: 6px;
}

.result-tab-btn::after {
  content: "";
  position: absolute;
  right: 0;
  top: 8px;
  bottom: 8px;
  width: 1px;
  background-color: var(--surface-3);
  transition: opacity 0.15s;
}

.result-tab-btn:hover::after,
.result-tab-btn.active::after,
.result-tab-btn.active + .result-tab-btn::after {
  opacity: 0;
}

.result-tab-btn:hover:not(.active) {
  background-color: var(--surface-3);
  border-radius: 8px 8px 0 0;
  color: var(--text-table-strong);
}

.result-tab-btn.active {
  background-color: var(--surface-1);
  color: var(--accent-cyan);
  font-weight: 500;
  border-radius: 8px 8px 0 0;
  z-index: 3;
}

/* A tab for a statement that failed (see client.js's
   renderResultsWithFailedStatement()) - colored distinctly from every
   other tab state above so it draws the eye immediately, whether or not
   it's the currently-active tab. */
.result-tab-btn--error {
  color: var(--danger);
}

.result-tab-btn--error:hover:not(.active) {
  background-color: var(--danger-glow);
  color: var(--danger-hover);
}

.result-tab-btn--error.active {
  background-color: var(--surface-1);
  color: var(--danger);
  box-shadow: inset 0 -2px 0 var(--danger);
}

/* "All databases" mode's live-streaming placeholder tab (see client.js's
   startAllModeStreaming()/handlePhaseBConnectionDone()) - a connection
   still being fetched, muted and pulsing so it reads as "in progress"
   rather than as just another result. Reuses .animate-pulse (defined
   above) rather than a new keyframe. */
.result-tab-btn--pending {
  color: var(--text-muted);
  font-style: italic;
}

.result-tab-btn--pending:not(.active) {
  animation: pulse 2s ease-in-out infinite;
}

.results-table-wrapper {
  flex: 1;
  min-height: 0;
  overflow: auto;
  position: relative;
}

.results-table-wrapper table {
  width: 100%;
  border-collapse: collapse;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: 0.8125rem;
  color: var(--text-table);
  text-align: left;
}

.results-table-wrapper th {
  position: sticky;
  top: 0;
  background-color: var(--surface-2);
  color: var(--text-secondary);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  padding: 10px 16px;
  border-bottom: 2px solid var(--surface-3);
  white-space: nowrap;
  z-index: 2;
}

.results-table-wrapper td {
  padding: 10px 16px;
  border-bottom: 1px solid var(--surface-2);
  white-space: pre-wrap;
  word-break: break-word;
}

.results-table-wrapper tbody tr:nth-child(even) {
  background-color: var(--surface-stripe);
}

.results-table-wrapper tbody tr:hover {
  background-color: var(--surface-2);
}

.results-table-wrapper th.cell-numeric,
.results-table-wrapper td.cell-numeric {
  text-align: right;
}

.results-table-wrapper td.cell-multiline {
  white-space: pre-wrap !important;
  word-break: break-word;
  line-height: 1.5;
  font-family: var(--font-mono, monospace);
}

.inputs-column {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-width: 0;
}

.input-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 52px;
}

/* Zero-state guidance: clickable example prompts shown above the SQL box
   so a first-time user with a blank prompt field has something concrete
   to click instead of guessing what the app can do. */
.example-prompts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0 0.25rem;
}

.example-prompts-label {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-right: 0.15rem;
}

.example-chip {
  background: var(--overlay-2);
  border: 1px solid var(--bg-card-border);
  color: var(--text-secondary);
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  font-size: 0.8rem;
  cursor: pointer;
  transition: var(--transition);
  white-space: nowrap;
}

.example-chip:hover {
  background: var(--primary-glow);
  border-color: var(--primary);
  color: var(--primary-hover);
}

.example-chip:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.example-chip:disabled:hover {
  background: var(--overlay-2);
  border-color: var(--bg-card-border);
  color: var(--text-secondary);
}

.example-prompts-dismiss {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.15rem 0.4rem;
  border-radius: 4px;
  transition: var(--transition);
}

.example-prompts-dismiss:hover {
  color: var(--text-primary);
  background: var(--overlay-3);
}

/* Action Buttons Column */
.action-buttons-column {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0.5rem;
  height: 100%;
  }

.action-buttons-column .btn {
  flex: none;
  height: 30px;
  padding: 0 0.5rem;
  font-size: 0.72rem;
  line-height: 1.1;
}

/* Stats Column */
.stats-column {
  width: 160px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  justify-content: space-between;
}

.stats-column #translationStats {
  margin-bottom: 0.6rem;
}

.stats-column #executionStats {
  margin-top: 0.6rem;
}

.stat-card-title {
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--primary);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.15rem;
  border-bottom: 1px solid var(--overlay-2);
  padding-bottom: 0.15rem;
}

/* Button height consistency in modals */
.modal-actions .btn-primary,
.btn-modal-secondary {
  height: 34px;
  padding: 0.4rem 1.25rem;
  font-size: 0.70rem;
  font-weight: 600;
  border-radius: 8px;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.btn-modal-secondary {
  background-color: var(--overlay-3);
  color: var(--text-primary);
}

.btn-modal-secondary:hover {
  background-color: var(--overlay-4);
}

/* --- Google Authentication & Avatar Header Styles --- */
.auth-container {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

/* Toggled by setButtonsDisabled() while a query is in flight - same
   "don't let the ground shift under an in-flight turn" reasoning as
   .badge-disabled above, for a control that can ALSO reset in-flight
   state: the signed-out button starts a Google sign-in, and its
   callback (renderAuthUI()) unconditionally calls
   clearActiveQueryState() + fetchBackendConfig() once it completes; the
   signed-in avatar's "Log out" does the exact same thing via
   handleLogout(). Either firing mid-turn was the "unpredictable result"
   this exists to prevent. pointer-events: none is what actually blocks
   it - the signed-out button is Google's own cross-origin iframe
   (google.accounts.id.renderButton()), which client.js has no script
   access to and so cannot otherwise intercept clicks on; pointer-events
   set on this ancestor stops the browser from ever delivering the click
   to it (or to the signed-in state's real DOM avatar button) in the
   first place, entirely at the hit-testing/compositing level, no
   iframe cooperation required. */
.auth-container.auth-disabled {
  pointer-events: none;
  opacity: 0.45;
  filter: grayscale(1);
}

.auth-menu-wrapper {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.auth-avatar-circle {
  background: var(--overlay-2);
  border: 1px solid var(--bg-card-border);
  color: var(--text-primary);
  padding: 0.35rem; /* Match header buttons padding */
  border-radius: 50%;
  cursor: pointer;
  transition: var(--transition);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px; 
  height: 18px; 
  /*width: clamp(32px, 3.2vw, 42px);*/ /* Reduced to match standard header buttons */
  /*height: clamp(32px, 3.2vw, 42px);*/
  flex-shrink: 0;
  overflow: hidden;
}

.auth-avatar-circle:hover {
  background: var(--overlay-4);
  border-color: var(--primary);
  color: var(--primary);
}

.auth-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

.auth-avatar-initial {
  font-size: 0.55rem;
  /*font-size: clamp(0.9rem, 1.5vw, 1.1rem);*/
  font-weight: 600;
  color: var(--primary);
}

.auth-dropdown-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  background-color: var(--surface-1);
  border: 1px solid var(--bg-card-border);
  border-radius: 8px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);
  min-width: 200px;
  z-index: 100;
  overflow: hidden;
}

.auth-dropdown-header {
  padding: 0.75rem 1rem;
}

.auth-dropdown-email {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  word-break: break-all;
}

.auth-dropdown-divider {
  height: 1px;
  background-color: var(--bg-card-border);
}

.auth-dropdown-item {
  width: 100%;
  background: transparent;
  border: none;
  color: var(--text-primary);
  padding: 0.65rem 1rem;
  font-size: 0.85rem;
  font-family: var(--font-sans);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  transition: var(--transition);
  text-align: left;
}

.auth-dropdown-item:hover {
  background-color: var(--overlay-2);
  color: var(--danger);
}

/* Auth Avatar and Menu Styles matching header buttons */
.auth-menu-wrapper {
  position: relative;
  display: inline-block;
  flex-shrink: 0;
}

.auth-avatar-circle {
  background: var(--overlay-2);
  border: 1px solid var(--bg-card-border);
  color: var(--text-primary);
  padding: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: var(--transition);
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(36px, 4vw, 50px);
  height: clamp(36px, 4vw, 50px);
  flex-shrink: 0;
  overflow: hidden;
}

.auth-avatar-circle:hover {
  background: var(--overlay-4);
  color: var(--primary);
  border-color: var(--primary);
}

.auth-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

.auth-avatar-initial {
  font-size: clamp(0.9rem, 1.5vw, 1.1rem);
  font-weight: 600;
  color: var(--text-primary);
}

/* Auth Dropdown Menu */
.auth-dropdown-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  background-color: var(--surface-1);
  border: 1px solid var(--bg-card-border);
  border-radius: 8px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
  min-width: 180px;
  z-index: 100;
  padding: 0.5rem 0;
}

.auth-dropdown-menu.hidden {
  display: none !important;
}

.auth-dropdown-header {
  padding: 0.5rem 1rem;
}

.auth-dropdown-email {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  word-break: break-all;
}

.auth-dropdown-divider {
  height: 1px;
  background-color: var(--bg-card-border);
  margin: 0.25rem 0;
}

.auth-dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.5rem 1rem;
  background: transparent;
  border: none;
  color: var(--text-primary);
  font-size: 0.85rem;
  cursor: pointer;
  text-align: left;
  transition: var(--transition);
}

.auth-dropdown-item:hover {
  background-color: var(--overlay-2);
  color: var(--primary);
}

.history-modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

.history-header-left {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: nowrap; /* Forces items to stay on the same line */
  min-width: 0;
  flex: 1;
}

.history-header-left .modal-title {
  white-space: nowrap;
  flex-shrink: 0;
}

.history-clear-wrapper {
  display: flex;
  align-items: center;
  min-width: 0;
}

@media (max-width: 600px) {
  .history-header-left {
    gap: 0.5rem;
  }
  
  .history-clear-wrapper .btn {
    padding: 0.3rem 0.6rem;
    font-size: 0.65rem;
  }
}

.history-turns-subtitle:empty {
  display: none;
}

/* History Action Buttons Sizing & Layout */

.modal-header h2,
.modal-header h5.modal-title {
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0;
}

.history-modal-header {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 1rem;
}

.history-clear-wrapper {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.history-action-btn {
  flex: 0 0 auto;
  min-width: 120px;
  height: auto; /* Allows the button to expand evenly for 2 lines */
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0.1rem 0.1rem;
  gap: 0.1rem; /* Controls spacing between the 2 lines cleanly */
  line-height: 1.2;
}

.history-action-btn .btn-purge-title {
  display: block;
  font-size: 0.68rem;
  opacity: 0.8;
  margin-top: 0; /* Clear margin so flex gap does all the spacing */
}

.modal-title {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.history-title-icon {
  width: 1.15em;
  height: 1.15em;
  stroke: currentColor;
  flex-shrink: 0;
}

.chart-wrapper {
  position: relative;
  height: 200px;
  width: 100%;
}

/* Dynamic Controls Layout Grid Base */
.controls-layout-grid {
  display: flex;
  gap: 1rem;
  align-items: stretch;
  width: 100%;
  flex-wrap: nowrap;
}

/* Wide Screen Layout (> 900px) */
@media (min-width: 901px) {
  .action-buttons-column {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.7rem;
    padding: 0.25rem 0;
    height: 100%;
  }

  .action-buttons-column .btn {
    flex: 0 0 auto;
    padding: 0.35rem 0.75rem;
    font-size: 0.78rem;
    line-height: 1.2;
    white-space: nowrap;
    width: 100%;
  }

  .stats-column {
    width: 160px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    justify-content: space-between;
  }
}

/* Narrow Screens Layout (<= 900px) */
@media (max-width: 900px) {
  .controls-layout-grid {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    width: 100%;
  }

  .inputs-column {
    width: 100%;
  }

  /* 4 Action Buttons placed side-by-side under SQL box */
  .action-buttons-column {
    width: 100%;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0;
  }

  .action-buttons-column .btn,
  .btn-control-block {
    flex: 1; /* Distributes all 4 buttons equally across row width */
    height: 36px;
    width: auto;
    font-size: 0.75rem;
    padding: 0 0.35rem;
  }

  /* 2 Stats areas placed side-by-side UNDER the 4 action buttons */
  .stats-column {
    width: 100%;
    display: flex;
    flex-direction: row;
    gap: 0.75rem;
    justify-content: space-between;
    align-items: stretch;
  }

  .stats-column #translationStats,
  .stats-column #executionStats,
  .stats-column .stats-card-vertical {
    flex: 1;
    margin: 0 !important;
    width: 50%;
  }
}
/* Empty state placeholder in results table */
#resultsBody .text-muted {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-style: italic;
  color: var(--text-muted);
  opacity: 0.8;
}

/* CodeMirror Placeholder Styling */
.CodeMirror-placeholder {
  color: var(--text-muted) !important;
  font-family: var(--font-mono) !important;
  font-size: 0.9rem !important;
  font-style: italic !important;
  opacity: 0.8 !important;
}

/* DB Connection Dot Indicator */
.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
  margin-right: 2px;
  background-color: var(--text-muted);
  transition: var(--transition);
}

.status-dot.connected,
.status-dot.success {
  background-color: var(--primary);
  box-shadow: 0 0 6px var(--primary);
}

.status-dot.disconnected,
.status-dot.failed,
.status-dot.error {
  background-color: var(--danger);
  box-shadow: 0 0 6px var(--danger);
}

/* Shown the instant a liveness check (checkDbStatus()/api/ping) starts,
   for however long it takes to actually resolve - the check itself now
   runs in the background rather than blocking the config modal's open/
   Save flow (see client.js), so this is the only visual cue that a check
   is in flight rather than the dot just sitting on a stale prior state. */
.status-dot.checking {
  background-color: var(--text-muted);
  animation: status-dot-checking-pulse 1.2s ease-in-out infinite;
}

@keyframes status-dot-checking-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

.response-cell {
  padding: 1rem 1.25rem;
}

.response-text {
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 0.9rem;
  line-height: 1.5;
  white-space: pre-wrap;
  margin: 0;
}

/* Markdown-lite emphasis inside a NO-SQL reply (see client.js's
   renderMarkdownLite()) - strong/em already inherit weight/style from the
   browser default, this just gives an inline `code` span a subtle pill so
   it reads as code rather than blending into the surrounding mono text. */
.response-text code {
  background: var(--overlay-3);
  border-radius: 4px;
  padding: 0.1em 0.35em;
  font-size: 0.85em;
}

/* Inline History Navigation Control inside NL Prompt */
.speech-bubble-wrapper .inline-history-nav {
  position: absolute;
  right: 28px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  background: var(--overlay-6);
  border: 1px solid var(--overlay-18);
  border-radius: 4px;
  overflow: hidden;
  height: 24px;
  z-index: 5;
}

.speech-bubble-wrapper .inline-history-nav button,
.speech-bubble-wrapper .inline-history-nav span {
  padding: 0 0.35rem;
  font-size: 0.7rem;
  font-weight: 700;
  height: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  color: var(--text-primary);
  user-select: none;
}

.speech-bubble-wrapper .inline-history-nav button {
  cursor: pointer;
  transition: var(--transition);
}

.speech-bubble-wrapper .inline-history-nav button:hover {
  background: var(--overlay-18);
  color: var(--text-primary);
}

.speech-bubble-wrapper .inline-history-nav button:first-child {
  border-right: 1px solid var(--overlay-18);
}

.speech-bubble-wrapper .inline-history-nav button:last-child {
  border-left: 1px solid var(--overlay-18);
}

.speech-bubble-wrapper .inline-history-nav button:disabled,
.speech-bubble-wrapper .inline-history-nav button.is-boundary {
  color: var(--text-secondary);
  opacity: 0.5;
  cursor: not-allowed;
  background: transparent;
}

.speech-bubble-wrapper .inline-history-nav button:disabled:hover,
.speech-bubble-wrapper .inline-history-nav button.is-boundary:hover {
  background: transparent;
  color: var(--text-secondary);
}

/* Adjust textarea padding to prevent text overlap with the inline controls & mic */
.speech-bubble-wrapper textarea#aiPrompt {
  padding-right: 125px !important;
}