:root {
  --bg: #0f1115;
  --panel: #161923;
  --border: #262b3a;
  --text: #e4e6ec;
  --muted: #8a90a2;
  --accent: #5b8cff;
  --ok: #4caf7d;
  --err: #e0637a;
}

* {
  box-sizing: border-box;
}

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

header {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 1.5rem 0 1rem;
  border-bottom: 1px solid var(--border);
}

h1 {
  font-size: 1.25rem;
  margin: 0;
}

.status {
  font-size: 0.8rem;
  color: var(--muted);
}

.status.ok { color: var(--ok); }
.status.err { color: var(--err); }

/* Transient toasts (00_core/toast.js) */
.toast-host {
  position: fixed;
  bottom: 1rem;
  right: 1rem;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: flex-end;
  pointer-events: none;
}
.toast {
  background: var(--panel);
  color: var(--fg, #e6ecf5);
  border: 1px solid var(--border, #2c2c2c);
  border-left: 3px solid var(--ok);
  border-radius: 6px;
  padding: 0.5rem 0.9rem;
  font-size: 0.85rem;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.35);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.2s, transform 0.2s;
}
.toast.show { opacity: 1; transform: translateY(0); }
.toast.toast-err { border-left-color: var(--err); }
@media (prefers-reduced-motion: reduce) { .toast { transition: none; } }

.stats {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 1rem 0;
}

.stat-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.75rem 1rem;
  min-width: 120px;
}

.stat-card .value {
  font-size: 1.4rem;
  font-weight: 600;
}

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

.tabs {
  display: flex;
  gap: 0.5rem;
  margin: 1rem 0;
}

.tab {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 0.4rem 0.9rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.85rem;
}

.tab.active {
  color: var(--text);
  border-color: var(--accent);
  background: rgba(91, 140, 255, 0.1);
}

.panel.hidden {
  display: none;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}

th, td {
  text-align: left;
  padding: 0.55rem 0.8rem;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
}

th {
  color: var(--muted);
  font-weight: 500;
  text-transform: uppercase;
  font-size: 0.7rem;
  letter-spacing: 0.03em;
}

tr:last-child td {
  border-bottom: none;
}

/* Sortable data-tab headers (table.js renders th.sortable when a DataTab
   has a pageSize) */
th.sortable {
  cursor: pointer;
  user-select: none;
}
th.sortable:hover {
  color: var(--accent);
}
th.sortable[aria-sort="ascending"],
th.sortable[aria-sort="descending"] {
  color: var(--accent);
}

/* Data-tab pager bar (data_tab.js) */
.pager {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.6rem;
}
.pager-range {
  color: var(--muted);
  font-size: 0.8rem;
}

.empty-state {
  color: var(--muted);
  padding: 2rem 1rem;
  text-align: center;
  border: 1px dashed var(--border);
  border-radius: 8px;
}

code {
  background: rgba(255, 255, 255, 0.06);
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
  font-size: 0.8em;
}

/* ── Data / Schema view toggle ──────────────────────────────────────── */

.view-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  margin-bottom: 0.75rem;
}

.view-btn {
  background: transparent;
  border: none;
  color: var(--muted);
  padding: 0.3rem 0.8rem;
  font-size: 0.78rem;
  cursor: pointer;
}

.view-btn + .view-btn {
  border-left: 1px solid var(--border);
}

.view-btn.active {
  color: var(--text);
  background: rgba(91, 140, 255, 0.12);
}

.schema-heading {
  font-size: 0.95rem;
  margin: 0.25rem 0 0.6rem;
  font-weight: 500;
}

.schema-subheading {
  font-size: 0.75rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin: 1.1rem 0 0.5rem;
  font-weight: 500;
}

.badge {
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
  border: 1px solid var(--border);
  color: var(--muted);
}

.badge-pk { color: var(--accent); border-color: var(--accent); }
.badge-fk { color: var(--ok); border-color: var(--ok); }
.badge-unique { color: var(--text); }

/* ── Generator: ingest + review ─────────────────────────────────────── */

.badge.hidden { display: none; }

.action-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  padding: 0.35rem 0.8rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.8rem;
}

.action-btn:hover:not(:disabled) { border-color: var(--accent); }
.action-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.action-btn.primary { border-color: var(--accent); background: rgba(91, 140, 255, 0.15); }
.action-btn.danger { border-color: var(--err); color: var(--err); }

.upload-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

input[type="file"], input[type="text"] {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 0.35rem 0.6rem;
  font-size: 0.8rem;
}

.progress {
  display: inline-block;
  width: 90px;
  height: 8px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
  vertical-align: middle;
  margin-right: 0.4rem;
}

.progress-fill {
  display: block;
  height: 100%;
  background: var(--accent);
  transition: width 0.4s ease;
}

.doc-queued { color: var(--muted); }
.doc-processing, .doc-pending { color: var(--accent); border-color: var(--accent); }
.doc-completed { color: var(--ok); border-color: var(--ok); }
.doc-failed { color: var(--err); border-color: var(--err); }
.doc-awaiting_review { color: #e0b063; border-color: #e0b063; }
.doc-discarded { color: var(--muted); text-decoration: line-through; }

.text-ingest {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1rem;
  max-width: 760px;
}

.text-ingest textarea {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 0.6rem;
  font-size: 0.85rem;
  font-family: inherit;
  resize: vertical;
}

.badge-ok { color: var(--ok); border-color: var(--ok); }
.badge-dup { color: #e0b063; border-color: #e0b063; }

.review-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.reviewer-label {
  font-size: 0.75rem;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

/* ── Create forms (table_viewer Create sub-tab) ─────────────────────── */

.create-form {
  max-width: 760px;
}

.create-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 0.9rem 1.25rem;
  margin-top: 0.75rem;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.field-label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.field-label-text {
  font-size: 0.75rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.req { color: var(--err); }

.info-btn,
.info-btn-inline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 0.95rem;
  height: 0.95rem;
  border-radius: 50%;
  border: 1px solid var(--muted);
  color: var(--muted);
  background: transparent;
  font-size: 0.6rem;
  font-style: italic;
  font-family: Georgia, serif;
  line-height: 1;
  padding: 0;
}

.info-btn { cursor: pointer; }
.info-btn:hover,
.info-btn[aria-expanded="true"] {
  border-color: var(--accent);
  color: var(--accent);
}

.field-info {
  font-size: 0.78rem;
  color: var(--muted);
  background: rgba(91, 140, 255, 0.07);
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: 6px;
  padding: 0.45rem 0.6rem;
  line-height: 1.4;
}

.field-info.hidden,
.field-error.hidden { display: none; }

.field-error {
  font-size: 0.75rem;
  color: var(--err);
}

.create-form input[type="text"],
.create-form input[type="number"],
.create-form input[type="datetime-local"],
.create-form select,
.create-form textarea {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 0.4rem 0.6rem;
  font-size: 0.82rem;
  font-family: inherit;
  width: 100%;
}

/* A textarea fills the empty vertical space of its grid cell by default,
   the cell stretches to the row's tallest neighbor (e.g. description next
   to the source_refs struct), so the box opens at full height instead of
   shrunk. Drag-resize stays available on top of that. */
.create-form textarea {
  resize: vertical;
  flex: 1 1 auto;
  min-height: 5rem;
}

.create-form input:focus,
.create-form select:focus,
.create-form textarea:focus {
  outline: none;
  border-color: var(--accent);
}

/* "list" fields: the box holds one chip per committed item + the entry
   input, so a list<string> is visibly a list, never a comma-parsed blob. */
.list-input {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.25rem 0.35rem;
  cursor: text;
}

.list-input:focus-within { border-color: var(--accent); }

.create-form .list-input input.list-entry {
  flex: 1;
  min-width: 130px;
  width: auto;
  background: transparent;
  border: none;
  padding: 0.2rem 0.25rem;
}

.create-form .list-input input.list-entry:focus { border: none; }

/* "multiref" fields: same chip box, but items come from this select
   instead of typed text. */
.create-form .list-input select.multiref-select {
  flex: 1;
  min-width: 130px;
  width: auto;
  background: transparent;
  border: none;
  padding: 0.2rem 0.25rem;
}

.create-form .list-input select.multiref-select:focus { border: none; }

/* "ref" fields: searchable single-select combobox (searchable_select.js),
   a filter-as-you-type input over the option list, dropping down the matches.
   Replaces the plain <select> whose only search was browser prefix-typeahead. */
.searchable-select { position: relative; }

.searchable-select .ss-list {
  position: absolute;
  z-index: 20;
  left: 0;
  right: 0;
  top: calc(100% + 2px);
  max-height: 240px;
  overflow-y: auto;
  margin: 0;
  padding: 0.25rem;
  list-style: none;
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}

.searchable-select .ss-list.hidden { display: none; }

.searchable-select .ss-option {
  padding: 0.35rem 0.5rem;
  border-radius: 4px;
  font-size: 0.82rem;
  cursor: pointer;
}

.searchable-select .ss-option:hover,
.searchable-select .ss-option.ss-active {
  background: rgba(91, 140, 255, 0.16);
}

.searchable-select .ss-empty {
  padding: 0.35rem 0.5rem;
  font-size: 0.8rem;
  color: var(--muted);
}

.list-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  background: rgba(91, 140, 255, 0.12);
  border: 1px solid var(--accent);
  border-radius: 4px;
  padding: 0.1rem 0.25rem 0.1rem 0.45rem;
  font-size: 0.78rem;
}

.chip-remove {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1;
  padding: 0 0.15rem;
  cursor: pointer;
}

.chip-remove:hover { color: var(--err); }

/* "struct" fields: fixed, labelled sub-inputs submitted as one object. */
.struct-input {
  display: grid;
  gap: 0.45rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.5rem 0.6rem;
}

.struct-sub {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.struct-sub-label {
  font-size: 0.66rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.check-label {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.82rem;
  cursor: pointer;
  padding: 0.4rem 0;
}

.form-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.1rem;
  flex-wrap: wrap;
}

.form-msg.ok { color: var(--ok); }
.form-msg.err { color: var(--err); }

/* ── Modal ──────────────────────────────────────────────────────────── */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 4rem 1rem 2rem;
  z-index: 10;
  overflow-y: auto;
}

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

.modal {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.25rem 1.5rem;
  max-width: 760px;
  width: 100%;
}

.modal h2 { font-size: 1.05rem; margin: 0 0 0.75rem; }
.modal h3 {
  font-size: 0.75rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin: 1.1rem 0 0.5rem;
}

.modal-scroll { max-height: 40vh; overflow-y: auto; }

.detail {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.3rem 1rem;
  margin: 0;
  font-size: 0.85rem;
}

.detail dt { color: var(--muted); }
.detail dd { margin: 0; }
.detail .quote { font-style: italic; color: var(--muted); }
.err-text { color: var(--err); }
.muted-text { color: var(--muted); font-size: 0.82rem; }

/* Process description at the top of the Extract from Documents / Review
   panels (what the tab does and how it affects the data). */
.panel-intro {
  max-width: 760px;
  margin: 0 0 0.9rem;
  line-height: 1.45;
}

.triple { font-size: 0.95rem; }

.callout {
  border: 1px solid #e0b063;
  color: #e0b063;
  background: rgba(224, 176, 99, 0.08);
  border-radius: 6px;
  padding: 0.5rem 0.8rem;
  font-size: 0.82rem;
  margin: 0.5rem 0 0.9rem;
}

.diff-table td, .diff-table th { white-space: normal; }
.diff-table label { cursor: pointer; }
/* Conflict "both records" comparison, highlight fields that differ */
.conflict-table tr.diff td { background: rgba(224, 176, 99, 0.1); }
.conflict-table tr.diff td:first-child code { color: #e0b063; }

/* Review panel: record/edit column left, local graph column right */
.review-cols {
  display: grid;
  grid-template-columns: minmax(300px, 440px) minmax(0, 1fr); /* record fixed, graph fills */
  gap: 1.5rem;
  align-items: start;
}
.review-cols.single { grid-template-columns: 1fr; }
/* The stuck column is capped at the viewport and its parts are laid out as a
   flex column, so the svg takes exactly what is left after the controls row,
   the legend and the hint. Sizing the svg to a guessed 76vh instead left the
   whole column taller than the screen, which is why the graph read as clipped. */
.review-right {
  position: sticky;
  top: 1rem;
  max-height: calc(100vh - 2rem);
  display: flex;
  flex-direction: column;
}
@media (max-width: 900px) {
  .review-cols { grid-template-columns: 1fr; }
  /* Stacked, the column scrolls with the page, so it is not capped. */
  .review-right { position: static; max-height: none; display: block; }
}

/* Local graph view (review panel) */
.review-graph-wrap { margin: 1rem 0 0.4rem; }
.review-right .review-graph-wrap {
  margin-top: 0;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.review-right #review-graph { flex: 1; min-height: 0; }
.review-right #review-graph .gv-svg { height: 100%; }
.review-right .graph-controls,
.review-right .graph-legend,
.review-right .graph-hint { flex: 0 0 auto; }
/* Below the stacking breakpoint the column is no longer a capped flex box, so
   the svg has nothing to fill and takes the standalone height back. Kept here,
   after the rule it overrides, because the two selectors weigh the same. */
@media (max-width: 900px) {
  .review-right #review-graph .gv-svg { height: min(76vh, 820px); }
}
.graph-hint { font-size: 0.78rem; margin: 0.4rem 0 0; }
.graph-controls {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}
.graph-controls .muted-text { margin: 0; }
.hop-btn.active { border-color: #63b3ed; color: #63b3ed; }
.gv-svg {
  width: 100%;
  height: min(76vh, 820px); /* standalone use, where nothing has measured for it */
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border, #2c2c2c);
  border-radius: 6px;
  touch-action: none;
  cursor: grab; /* background pans */
}
.gv-svg:active { cursor: grabbing; }
.gv-hit { stroke: transparent; stroke-width: 12; fill: none; }
.gv-line { stroke: #4a5568; stroke-width: 1.4; }
.gv-edge-focal .gv-line { stroke: #63b3ed; stroke-width: 2.6; }
.gv-edge-focal .gv-edge-label { fill: #cbd5e0; font-weight: 600; }
.gv-edge-label { fill: #8595ab; font-size: 9px; text-anchor: middle; pointer-events: none; }
#gv-arrow path { fill: #4a5568; }
.gv-node { cursor: grab; }
.gv-body { fill: #2d3748; stroke: #5a6b8c; stroke-width: 1.5; }
.gv-focal .gv-body { fill: #2b6cb0; stroke: #63b3ed; stroke-width: 2; }
.gv-node-label { fill: #cbd5e0; font-size: 10px; text-anchor: middle; pointer-events: none; }
/* Edit affordances, revealed on hover so a dense graph stays legible. */
.gv-handle { fill: #63b3ed; stroke: #0b101a; stroke-width: 1; cursor: grab; visibility: hidden; }
.gv-remove { cursor: pointer; visibility: hidden; }
.gv-remove circle { fill: #742a2a; stroke: #fc8181; stroke-width: 1; }
.gv-remove text { fill: #fed7d7; font-size: 10px; text-anchor: middle; pointer-events: none; }
.gv-edge:hover .gv-handle,
.gv-edge:hover .gv-remove { visibility: visible; }
.gv-rubber { stroke: #63b3ed; stroke-width: 1.6; stroke-dasharray: 4 3; pointer-events: none; }
/* Search filter: dim non-matching nodes/edges */
.gv-node.gv-dim { opacity: 0.15; }
.gv-edge.gv-dim { opacity: 0.12; }
.gv-search {
  font-size: 0.78rem;
  padding: 0.25rem 0.5rem;
  background: rgba(255, 255, 255, 0.03);
  color: inherit;
  border: 1px solid var(--border, #2c2c2c);
  border-radius: 6px;
  min-width: 9rem;
}
/* Graph legend */
.graph-legend {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: center;
  margin: 0.4rem 0.1rem 0;
  font-size: 0.76rem;
  color: #8595ab;
}
.graph-legend .lg { width: 12px; height: 12px; border-radius: 50%; display: inline-block; vertical-align: -1px; }
.graph-legend .lg-focal { background: #2b6cb0; border: 2px solid #63b3ed; }
.graph-legend .lg-node { background: #2d3748; border: 1.5px solid #5a6b8c; }
.graph-legend .lg-edge { width: 16px; height: 0; border-radius: 0; border-top: 2.6px solid #63b3ed; }

/* Node-split dialog: three stacked, visually grouped node sections. */
.split-section {
  border: 1px solid var(--border, #2c2c2c);
  border-radius: 6px;
  padding: 0.4rem 0.8rem 0.8rem;
  margin: 0.7rem 0;
}
.split-section h3 { margin: 0.6rem 0 0.2rem; }

.modal-actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 1.1rem;
  flex-wrap: wrap;
}
