/* ============================================================================
   COMPONENTS  ·  Postgres Table Browser
   ----------------------------------------------------------------------------
   The reusable UI layer. Every rule references the custom properties defined in
   design-tokens.css — no colour, size, radius, or duration is hard-coded, so all
   components re-theme automatically with [data-theme] / [data-mode].

   Load order in the app:  design-tokens.css  →  components.css
   Sections: 1 App shell · 2 Buttons · 3 Inputs · 4 Banners · 5 Pills ·
             6 Data table · 7 Pagination · 8 Row detail · 9 States · 10 Utilities
   ============================================================================ */

/* box-sizing + sensible defaults (tokens file sets body/base already) */
*, *::before, *::after { box-sizing: border-box; }

/* ============================================================================
   1 · APP SHELL
   ============================================================================ */
.app { min-height: 100vh; display: flex; flex-direction: column; background: var(--color-bg); }

.app-header {                       /* sticky top bar with brand + context + controls */
  position: sticky; top: 0; z-index: var(--z-sticky);
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
  border-bottom: var(--border-width) solid var(--color-border);
}
.brand { display: flex; align-items: center; gap: var(--space-2); font-weight: var(--fw-semibold); }
.brand-mark {                       /* small square accent mark stands in for a logo */
  width: 22px; height: 22px; border-radius: var(--radius-sm);
  background: var(--color-accent-fill); flex: none;
}
.brand-name { font-size: var(--fs-h3); letter-spacing: var(--tracking-tight); color: var(--color-text); }
.app-header .spacer { flex: 1; }    /* pushes controls to the right */
.app-controls { display: flex; align-items: center; gap: var(--space-2); }

.app-main { width: 100%; max-width: var(--container-max); margin: 0 auto; padding: var(--space-4); }

/* breadcrumb / context bar: database > schema > table, plus a mode badge */
.context { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  font-size: var(--fs-sm); color: var(--color-text-secondary); }
.context .crumb { color: var(--color-text-secondary); }
.context .crumb.current { color: var(--color-text); font-weight: var(--fw-medium); }
.context .sep { color: var(--color-text-tertiary); }

/* ============================================================================
   2 · BUTTONS
   ============================================================================ */
.btn {
  --btn-h: 33px;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--btn-h); padding: 0 var(--space-4);
  font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: var(--fw-medium);
  line-height: 1; border-radius: var(--radius-sm);
  border: var(--border-width) solid transparent; cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard),
              border-color var(--motion-fast) var(--ease-standard),
              transform var(--motion-fast) var(--ease-standard);
  white-space: nowrap; user-select: none;
}
.btn:active { transform: scale(0.98); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary { background: var(--color-accent-fill); color: var(--color-accent-fill-text); }
.btn-primary:hover:not(:disabled) { filter: brightness(0.94); }

.btn-secondary { background: var(--color-surface); color: var(--color-text);
  border-color: var(--color-border-strong); }
.btn-secondary:hover:not(:disabled) { background: var(--color-surface-2); }

.btn-ghost { background: transparent; color: var(--color-text-secondary); }
.btn-ghost:hover:not(:disabled) { background: var(--color-surface-2); color: var(--color-text); }

.btn-danger { background: var(--color-danger-text); color: #fff; }
.btn-danger:hover:not(:disabled) { filter: brightness(0.94); }

.btn-lg { --btn-h: var(--tap-min); padding: 0 var(--space-5); font-size: var(--fs-body); }
.btn-sm { --btn-h: 26px; padding: 0 var(--space-3); font-size: var(--fs-xs);
  position: relative; }
.btn-sm::after { content: ""; position: absolute; inset: -6px; }  /* 44px hit halo */
.btn-icon { padding: 0; width: var(--btn-h); }   /* square icon-only button */

/* ============================================================================
   3 · INPUTS
   ============================================================================ */
.field { display: flex; flex-direction: column; gap: var(--space-1); }
.label { font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--color-text-secondary); }
.input, .select, .textarea {
  width: 100%; min-height: var(--tap-min);
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-sans); font-size: var(--fs-body); color: var(--color-text);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  transition: border-color var(--motion-fast) var(--ease-standard);
}
.input::placeholder, .textarea::placeholder { color: var(--color-text-tertiary); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--color-text-tertiary); }
.textarea { min-height: 88px; resize: vertical; line-height: var(--lh-body); }
/* mono inputs for editing data values / IDs */
.input.mono, .textarea.mono { font-family: var(--font-mono); font-size: var(--fs-mono); }

/* search field: icon + input */
.search { position: relative; }
.search .input { padding-left: calc(var(--space-3) + 20px); }
.search .search-icon { position: absolute; left: var(--space-3); top: 50%; transform: translateY(-50%);
  color: var(--color-text-tertiary); pointer-events: none; }

/* validation */
.field.is-error .input, .field.is-error .select, .field.is-error .textarea { border-color: var(--color-danger-text); }
.hint { font-size: var(--fs-xs); color: var(--color-text-tertiary); }
.hint.error { color: var(--color-danger-text); }

/* ============================================================================
   4 · BANNERS / ALERTS
   ============================================================================ */
.banner {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-3) var(--space-4); border-radius: var(--radius-md);
  font-size: var(--fs-sm); line-height: var(--lh-sm);
  border: var(--border-width) solid transparent;
}
.banner .banner-icon { flex: none; margin-top: 1px; }
.banner-info    { background: var(--color-info-bg);    color: var(--color-info-text); }
.banner-success { background: var(--color-success-bg); color: var(--color-success-text); }
.banner-warning { background: var(--color-warning-bg); color: var(--color-warning-text); }
.banner-danger  { background: var(--color-danger-bg);  color: var(--color-danger-text); }
/* read-only mode banner — neutral, persistent */
.banner-readonly { background: var(--color-surface-2); color: var(--color-text-secondary);
  border-color: var(--color-border); }

/* ============================================================================
   5 · PILLS / TAGS  (status values, booleans, counts)
   ============================================================================ */
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px var(--space-2); border-radius: var(--radius-pill);
  font-size: var(--fs-xs); font-weight: var(--fw-medium); line-height: 1.5; white-space: nowrap;
}
.pill-success { background: var(--color-success-bg); color: var(--color-success-text); }
.pill-warning { background: var(--color-warning-bg); color: var(--color-warning-text); }
.pill-danger  { background: var(--color-danger-bg);  color: var(--color-danger-text); }
.pill-info    { background: var(--color-info-bg);    color: var(--color-info-text); }
.pill-neutral { background: var(--color-surface-2);  color: var(--color-text-secondary);
  border: var(--border-width) solid var(--color-border); }
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* ============================================================================
   6 · DATA TABLE   (horizontal-scroll grid, pinned first column, sticky header)
   ----------------------------------------------------------------------------
   Markup:
     <div class="table-wrap" data-density="comfortable">
       <table class="data"> <thead>…</thead> <tbody>…</tbody> </table>
     </div>
   ============================================================================ */
.table-wrap {
  overflow-x: auto;                 /* swipe sideways to reveal more columns */
  -webkit-overflow-scrolling: touch;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
table.data { border-collapse: separate; border-spacing: 0; width: 100%; font-size: var(--fs-sm); }

table.data th, table.data td {
  padding: var(--space-3) var(--space-4);
  text-align: left; white-space: nowrap;                 /* grid feel; no wrapping */
  border-bottom: var(--border-width) solid var(--color-border);
}
/* sticky header row */
table.data thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--color-surface-2); color: var(--color-text-secondary);
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: 0.05em;
}
/* pinned first column (the key / id) */
table.data th:first-child, table.data td:first-child {
  position: sticky; left: 0; z-index: 1;
  background: var(--color-surface);
  box-shadow: 1px 0 0 var(--color-border);               /* subtle separator while scrolling */
}
table.data thead th:first-child { z-index: 3; background: var(--color-surface-2); }  /* corner sits above both */

/* row hover (keep pinned cell in sync) */
table.data tbody tr:hover td { background: var(--color-surface-2); }
table.data tbody tr:hover td:first-child { background: var(--color-surface-2); }
table.data tbody tr:last-child td { border-bottom: none; }

/* type-aware cell helpers */
td.num  { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
td.mono { font-family: var(--font-mono); font-size: var(--fs-mono); }
.v-null { color: var(--color-text-tertiary); font-style: italic; }     /* NULL marker */
.v-muted { color: var(--color-text-tertiary); }
td a, .cell-link { color: var(--color-accent-text); text-decoration: none; }
td a:hover, .cell-link:hover { text-decoration: underline; }
/* truncated long text / JSON — clamp to a max width, reveal on tap (details) */
.v-trunc { display: inline-block; max-width: 280px; overflow: hidden; text-overflow: ellipsis;
  vertical-align: bottom; }

/* density toggle: compact tightens padding + type */
.table-wrap[data-density="compact"] table.data { font-size: var(--fs-xs); }
.table-wrap[data-density="compact"] th,
.table-wrap[data-density="compact"] td { padding: var(--space-2) var(--space-3); }

/* ============================================================================
   7 · PAGINATION
   ============================================================================ */
.pagination { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-3) var(--space-1); }
.page-info { font-size: var(--fs-sm); color: var(--color-text-secondary); }
.page-info .mono { font-family: var(--font-mono); color: var(--color-text); }
.page-controls { display: flex; align-items: center; gap: var(--space-2); }

/* ============================================================================
   8 · ROW DETAIL  (full record view — key/value list, type-aware)
   ============================================================================ */
.detail-card { background: var(--color-surface);
  border: var(--border-width) solid var(--color-border); border-radius: var(--radius-lg);
  overflow: hidden; }
.detail-head { display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-3) var(--space-4); border-bottom: var(--border-width) solid var(--color-border); }
.detail-title { font-size: var(--fs-h3); font-weight: var(--fw-semibold); color: var(--color-text); }
.detail-row { display: grid; grid-template-columns: 160px 1fr; gap: var(--space-4);
  padding: var(--space-3) var(--space-4); border-bottom: var(--border-width) solid var(--color-border); }
.detail-row:last-child { border-bottom: none; }
.detail-key { font-size: var(--fs-sm); color: var(--color-text-secondary); }
.detail-key .type { display: block; font-family: var(--font-mono); font-size: var(--fs-xs);
  color: var(--color-text-tertiary); margin-top: 2px; }     /* postgres type under the name */
.detail-val { font-size: var(--fs-body); color: var(--color-text); word-break: break-word; }
.detail-val.mono { font-family: var(--font-mono); font-size: var(--fs-mono); }
/* stack key over value on narrow screens */
@media (max-width: 640px) { .detail-row { grid-template-columns: 1fr; gap: var(--space-1); } }

/* ============================================================================
   9 · STATES  (empty · loading · error)
   ============================================================================ */
.state { display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: var(--space-3); padding: var(--space-12) var(--space-4);
  color: var(--color-text-secondary); }
.state .state-icon { color: var(--color-text-tertiary); }
.state .state-title { font-size: var(--fs-h3); font-weight: var(--fw-semibold); color: var(--color-text); }
.state .state-msg { font-size: var(--fs-sm); max-width: 380px; }

.spinner { width: 28px; height: 28px; border-radius: 50%;
  border: 3px solid var(--color-border-strong); border-top-color: var(--color-accent);
  animation: spin 0.7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 1.4s; } }

/* ============================================================================
   10 · UTILITIES
   ============================================================================ */
.card { background: var(--color-surface); border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-card); }
.stack > * + * { margin-top: var(--space-4); }     /* vertical rhythm */
.row { display: flex; align-items: center; gap: var(--space-2); }
.muted { color: var(--color-text-secondary); }
.mono { font-family: var(--font-mono); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* ============================================================================
   11 · RESPONSIVE  —  let the header and its controls wrap on small screens so
   nothing clips on a phone (the controls drop to a full-width second row).
   ============================================================================ */
.app-header { flex-wrap: wrap; }
.app-controls { flex-wrap: wrap; }
@media (max-width: 640px) {
  .app-controls { width: 100%; justify-content: space-between; }
  .app-main { padding: var(--space-3); }
}

/* ============================================================================
   12 · EXPRESSIVE LAYER COMPONENTS  (Blueprint full hierarchy)
   Uses the tokens added in design-tokens.css: inverted surfaces, accent tints,
   chart series, sentiment. Everything still references variables only.
   ============================================================================ */

/* --- inverted "punctuation" sections --- */
.section-inverted, .section-accent {
  border-radius: var(--radius-lg); padding: var(--space-6) var(--space-5);
}
.section-inverted { background: var(--color-surface-inverted); color: var(--color-on-inverted); }
.section-inverted :where(h1,h2,h3) { color: var(--color-on-inverted); }
.section-inverted .muted { color: var(--color-on-inverted-secondary); }
.section-inverted .faint { color: var(--color-on-inverted-tertiary); }
.section-inverted a, .section-inverted .link { color: var(--color-on-inverted-accent); }
.section-inverted .divider { border: none; border-top: 1px solid var(--color-on-inverted-border); }

.section-accent { background: var(--color-surface-accent); color: var(--color-on-accent); }
.section-accent :where(h1,h2,h3) { color: var(--color-on-accent); }
.section-accent .muted { color: var(--color-on-accent-secondary); }
.section-accent .faint { color: var(--color-on-accent-tertiary); }
.section-accent a, .section-accent .link { color: var(--color-on-accent); text-decoration: underline; }
.section-accent .divider { border: none; border-top: 1px solid var(--color-on-accent-border); }

/* --- accent tint: soft fills, selected rows, badges --- */
.surface-tint { background: var(--color-accent-tint); color: var(--color-on-accent-tint);
  border-radius: var(--radius-lg); padding: var(--space-4); }
table.data tbody tr.is-selected td { background: var(--color-accent-tint); }
table.data tbody tr.is-selected td:first-child { background: var(--color-accent-tint); }
.badge-accent { display: inline-flex; align-items: center; gap: 5px;
  background: var(--color-accent-tint); color: var(--color-on-accent-tint);
  border-radius: var(--radius-pill); padding: 2px var(--space-2);
  font-size: var(--fs-xs); font-weight: var(--fw-medium); }

/* stronger accent hover for the primary button */
.btn-primary:hover:not(:disabled) { background: var(--color-accent-strong); filter: none; }

/* translucent accent wash (row hover, scrims) */
.overlay-accent { background: var(--color-accent-overlay); }

/* --- chart palette: legend + swatches (SVG uses the vars directly) --- */
.legend { display: flex; flex-wrap: wrap; gap: var(--space-3);
  font-size: var(--fs-xs); color: var(--color-text-secondary); }
.legend .item { display: inline-flex; align-items: center; gap: 6px; }
.legend .dot { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.series-1 { background: var(--color-chart-1); } .series-1-fg { color: var(--color-chart-1); }
.series-2 { background: var(--color-chart-2); } .series-2-fg { color: var(--color-chart-2); }
.series-3 { background: var(--color-chart-3); } .series-3-fg { color: var(--color-chart-3); }
.series-4 { background: var(--color-chart-4); } .series-4-fg { color: var(--color-chart-4); }
.series-5 { background: var(--color-chart-5); } .series-5-fg { color: var(--color-chart-5); }
.series-6 { background: var(--color-chart-6); } .series-6-fg { color: var(--color-chart-6); }

/* --- sentiment: pills (soft) + solid dots (charts) --- */
.pill-positive { background: var(--color-sentiment-positive-bg); color: var(--color-sentiment-positive-text); }
.pill-neutral-sent { background: var(--color-sentiment-neutral-bg); color: var(--color-sentiment-neutral-text); }
.pill-negative { background: var(--color-sentiment-negative-bg); color: var(--color-sentiment-negative-text); }
.pill-positive, .pill-neutral-sent, .pill-negative {
  display: inline-flex; align-items: center; gap: 5px; border-radius: var(--radius-pill);
  padding: 2px var(--space-2); font-size: var(--fs-xs); font-weight: var(--fw-medium); }
.sent-dot-positive { background: var(--color-sentiment-positive); }
.sent-dot-neutral  { background: var(--color-sentiment-neutral); }
.sent-dot-negative { background: var(--color-sentiment-negative); }
