:root {
  --ink: #1a1a1a;
  --muted: #8a8a8a;
  --line: #e6e6e6;
  --bg: #fafafa;
  --card: #ffffff;
}
* { box-sizing: border-box; }

/* macOS-style overlay scrollbars: a slim rounded pill, NO arrow buttons, that
   floats inside a transparent border so it never touches the panel edge.
   Firefox uses scrollbar-width/color; WebKit uses ::-webkit-scrollbar. */
* { scrollbar-width: thin; scrollbar-color: rgba(0, 0, 0, .28) transparent; }
::-webkit-scrollbar { width: 12px; height: 12px; }
/* Kill the up/down (and left/right) arrow buttons in every variant so the
   scrollbar is JUST the thumb. */
::-webkit-scrollbar-button,
::-webkit-scrollbar-button:single-button,
::-webkit-scrollbar-button:vertical:decrement,
::-webkit-scrollbar-button:vertical:increment,
::-webkit-scrollbar-button:horizontal:decrement,
::-webkit-scrollbar-button:horizontal:increment {
  display: none; width: 0; height: 0; background: none;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-track-piece,
::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: rgba(0, 0, 0, .28);
  border-radius: 999px;
  border: 4px solid transparent;   /* floats: visible thumb ~4px, macOS-slim */
  background-clip: padding-box;
  min-height: 30px;
}
::-webkit-scrollbar-thumb:hover {
  background-color: rgba(0, 0, 0, .42); background-clip: padding-box;
}

html, body { margin: 0; height: 100%; }
/* The `hidden` attribute must always win. A class that sets `display` (e.g.
   `.mode-row{display:flex}`, `.pane-subtitle{display:...}`) is an AUTHOR rule
   and so overrides the browser's UA `[hidden]{display:none}` even at equal
   specificity — that silently un-hid template elements marked `hidden` (the
   legacy Mode / triage controls, the empty pending / failure headings). Force
   it here so `hidden` means hidden regardless of any element's display rule. */
[hidden] { display: none !important; }
/* Never let a wheel/trackpad gesture over a non-scrollable area chain into a
   page/browser scroll — matters on the graph pages where the wheel zooms the
   graph, so it must not also scroll the page. */
html, body { overscroll-behavior: none; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui,
    "PingFang SC", "Microsoft YaHei", sans-serif;
  color: var(--ink);
  background: var(--bg);
  font-size: 14px;
  line-height: 1.5;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 22px;
  background: var(--card);
  border-bottom: 1px solid var(--line);
}
.brand { font-weight: 600; font-size: 16px; color: var(--ink); text-decoration: none; }
.brand.back { font-weight: 500; color: var(--muted); }
.crumb { font-weight: 600; margin-left: 8px; }
.topbar-actions { display: flex; gap: 10px; align-items: center; }

.main { padding: 26px 22px; max-width: 1040px; margin: 0 auto; }
.page-head {
  display: flex; align-items: center; gap: 12px; margin: 0 0 18px;
}
.page-title { font-size: 18px; font-weight: 600; margin: 0; }

/* Assemblage: an infinity glyph that expands to the word on hover. Styled as a
   small button so it sits flush with Edit / +. */
.assemblage-btn { text-decoration: none; display: inline-flex; align-items: center; }
.assemblage-btn .ab-text { display: none; }
.assemblage-btn:hover .ab-icon, .assemblage-btn:focus .ab-icon { display: none; }
.assemblage-btn:hover .ab-text, .assemblage-btn:focus .ab-text { display: inline; }

/* Sort control: right-aligned in the page head, opens a small dropdown. */
.sort-wrap { position: relative; margin-left: auto; }
.sort-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 20;
  background: var(--card); border: 1px solid #d0d0d0; border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .12); padding: 4px; min-width: 150px;
  display: flex; flex-direction: column; gap: 2px;
}
.sort-menu.hidden { display: none; }
.sort-opt {
  font: inherit; font-size: 13px; text-align: left; padding: 6px 10px;
  border: none; background: none; border-radius: 6px; cursor: pointer;
  color: var(--ink);
}
.sort-opt:hover { background: #f0f0f0; }
.sort-opt.active { font-weight: 600; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
}
/* Generic card (settings sections, account, situation list, …). */
.card {
  padding: 16px 18px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: inherit;
  transition: box-shadow .12s ease, border-color .12s ease;
  min-width: 0;
}
.card:hover { border-color: #cfcfcf; box-shadow: 0 2px 12px rgba(0,0,0,.06); }
.card-link { display: block; text-decoration: none; color: inherit; }
.card-name {
  font-weight: 600; font-size: 15px; margin-bottom: 8px;
  overflow-wrap: anywhere; word-break: break-word;
}
.card-meta { font-size: 13px; color: #555; }
.card-meta.sub { color: var(--muted); margin-top: 2px; }
.card.archived { opacity: .6; }

/* Workspace card ONLY: square tile with a topology snapshot filling it and a
   slim name/counts footer. Scoped so it never touches the generic cards. */
.workspace-card {
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex; flex-direction: column;
  padding: 0; border-radius: 14px; overflow: hidden;
}
.workspace-card .card-link {
  display: flex; flex-direction: column; height: 100%;
}
.workspace-card .card-thumb {
  flex: 1; min-height: 0; background: #fbfbfb;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.workspace-card .card-thumb svg {
  width: 100%; height: 100%; display: block; pointer-events: none;
}
.workspace-card .card-thumb.empty {
  color: var(--muted); font-size: 12px;
}
.workspace-card .card-body { padding: 10px 14px 12px; border-top: 1px solid var(--line); }
.workspace-card .card-name {
  font-size: 14px; margin-bottom: 2px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.workspace-card .card-meta.sub { font-size: 12px; margin-top: 0; }

/* edit mode: three small icon buttons in the card's top-right corner. Absolute
   so entering edit mode never changes the card's size — the buttons just
   appear over the thumbnail. */
.card-actions {
  position: absolute; top: 8px; right: 8px; z-index: 3;
  display: none; gap: 5px;
}
.grid.editing .card-actions { display: flex; }
.card-act {
  width: 27px; height: 27px; padding: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  color: #3a3a3a; background: rgba(255, 255, 255, .96);
  border: 1px solid #dcdcdc; border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
}
.card-act svg { width: 15px; height: 15px; display: block; }
.card-act:hover { background: #fff; border-color: #b0b0b0; color: var(--ink); }
.card-act.danger:hover {
  background: #c0392b; color: #fff; border-color: #c0392b;
}
.btn.danger { color: var(--ink); }
.btn.danger:hover { background: var(--ink); color: #fff; border-color: var(--ink); }

.btn {
  font: inherit;
  padding: 7px 14px;
  border-radius: 8px;
  border: 1px solid #d0d0d0;
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
}
.btn.primary { background: var(--ink); color: #fff; border-color: var(--ink); }
.btn:disabled { opacity: .45; cursor: default; }

.empty { color: var(--muted); padding: 48px 0; text-align: center; }
.empty code, .detail-placeholder code {
  background: #f0f0f0; padding: 1px 6px; border-radius: 5px; font-size: 13px;
}
.muted { color: var(--muted); }
.small { font-size: 12px; }

/* ---- detail: split panes ----
   The detail page fills the viewport exactly: the top bar is a fixed
   ~49px row, so `main` takes the rest with no padding/max-width and
   never scrolls itself. Without this, `main`'s default 26px padding +
   max-width pushed the grid past 100vh, which made the body scrollbar
   oscillate (appear -> reflow -> disappear) — the "flickering" bug. */
/* Graph pages are EXACTLY one viewport — never scroll. Pinning the body to the
   viewport (position:fixed + inset:0) makes its height equal the viewport
   regardless of the topbar's height and removes it from document flow, so there
   is nothing the page/window can scroll (wheel + middle-button autoscroll then
   have nothing to fight the graph zoom over). Same treatment for the situation
   page. */
body.page-detail, body.page-situation {
  position: fixed; inset: 0; overflow: hidden;
  display: flex; flex-direction: column;
}
.page-detail > .topbar, .page-situation > .topbar { flex: none; }
.page-detail > .main, .page-situation > .main {
  padding: 0; max-width: none; margin: 0;
  flex: 1; min-height: 0; height: auto; overflow: hidden;
}
.detail { position: relative; height: 100%; --sidebar-w: 340px; --source-w: 460px; }
.pane { overflow: auto; }
/* The graph fills the whole detail area. z-index:1 gives it its OWN stacking
   context so cytoscape's internal canvas layers stay contained UNDER the
   floating panels — otherwise those canvases (which set their own z-index)
   compete in the parent context and paint over the sidebar. */
.pane-right {
  position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; padding: 0;
  /* NOT scrollable — it inherits overflow:auto from .pane, which made wheel
     events over the graph scroll THIS container (fighting cytoscape's zoom).
     The graph pans/zooms inside cytoscape; the container itself never scrolls. */
  overflow: hidden;
}
/* Ingest panel: a rounded floating window inset from every edge (24px
   corners); width is user-resizable via --sidebar-w. Sits ABOVE the graph.
   z-index MUST beat the label overlay canvas (z-index:10 in graph_labels.js):
   when the GPU promotes that canvas to its own compositing layer it can escape
   pane-right's stacking context, and at an EQUAL z-index the later-in-DOM graph
   would paint its node labels over this panel. Keeping the floating panels
   above 10 makes the sidebar win even in that case.
   overflow:hidden so the rounded corners CLIP the inner scrollbar — it can
   never poke past the 24px edge. Scrolling lives on .pane-scroll inside. */
.pane-left {
  position: absolute; top: 16px; left: 16px; bottom: 16px;
  width: var(--sidebar-w); z-index: 30;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 24px;
  box-shadow: 0 8px 34px rgba(0, 0, 0, .14);
  padding: 0; overflow: hidden;
  display: flex; flex-direction: column;
}
.pane-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 20px 22px; }

/* Overlay-style scrollbars on the floating panels: JUST the thumb (no arrow
   buttons — those are hidden globally), and it only appears while the pointer
   is over the panel, fading out when the pointer leaves. */
.pane-scroll, .source-body, .sit-scroll {
  scrollbar-color: transparent transparent;  /* Firefox: hidden until hover */
}
.pane-scroll::-webkit-scrollbar-thumb,
.source-body::-webkit-scrollbar-thumb,
.sit-scroll::-webkit-scrollbar-thumb {
  background-color: transparent;
}
.pane-left:hover .pane-scroll,
.pane-source:hover .source-body,
.sit-panel:hover .sit-scroll { scrollbar-color: rgba(0, 0, 0, .28) transparent; }
.pane-left:hover .pane-scroll::-webkit-scrollbar-thumb,
.pane-source:hover .source-body::-webkit-scrollbar-thumb,
.sit-panel:hover .sit-scroll::-webkit-scrollbar-thumb {
  background-color: rgba(0, 0, 0, .28);
}

/* Minimize / expand button at the very bottom of the sidebar. Only appears on
   hover (always visible when minimized). It is the ONLY way to minimize —
   clicking elsewhere inside the panel does nothing. */
.pane-min-toggle {
  flex-shrink: 0; height: 20px; margin-top: 4px; padding: 0;
  border: none; background: none; cursor: pointer; color: #b8b8b8;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity .15s ease, color .12s ease;
}
.pane-min-toggle::before { content: "▾"; font-size: 13px; line-height: 1; }
.pane-left:hover .pane-min-toggle { opacity: 1; }
.pane-min-toggle:hover { color: #666; }

/* Minimized sidebar: collapse to the title + the drop zone only, sized to fit.
   The minimize button stays visible (as an expand arrow) so it can be reopened. */
.detail.sidebar-min .pane-left { bottom: auto; max-height: calc(100% - 32px); }
.detail.sidebar-min .pane-resize { display: none; }
.detail.sidebar-min .pane-scroll { overflow: hidden; }
.detail.sidebar-min .pane-scroll > * { display: none; }
.detail.sidebar-min .pane-scroll > .pane-title { display: block; }
.detail.sidebar-min .pane-scroll > .dropzone { display: block; }
.detail.sidebar-min .pane-min-toggle { opacity: 1; }
.detail.sidebar-min .pane-min-toggle::before { content: "▴"; }

/* Drag handle pinned over the sidebar's right edge. */
.pane-resize {
  position: absolute; top: 16px; bottom: 16px;
  left: calc(16px + var(--sidebar-w) - 5px); width: 12px;
  z-index: 31; cursor: ew-resize;
}
.pane-resize::after {
  content: ""; position: absolute; top: 50%; left: 4px;
  width: 3px; height: 40px; transform: translateY(-50%);
  border-radius: 2px; background: transparent; transition: background .12s ease;
}
.pane-resize:hover::after, body.resizing-pane .pane-resize::after {
  background: #9a9a9a;
}
body.resizing-pane { cursor: ew-resize; user-select: none; }
/* Source (markdown) viewer: same floating-window UI, parked PARALLEL to the
   ingest sidebar (just to its right); width resizable via --source-w. */
.pane-source {
  position: absolute; top: 16px; bottom: 16px;
  left: calc(16px + var(--sidebar-w) + 14px);
  width: var(--source-w); max-width: calc(100% - var(--sidebar-w) - 60px);
  z-index: 28;  /* above the label overlay canvas (10) — see .pane-left note */
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 24px;
  box-shadow: 0 8px 34px rgba(0, 0, 0, .14);
  padding: 18px 22px; overflow: hidden;
  display: flex; flex-direction: column;
}
.pane-source.hidden { display: none; }
.pane-source-head {
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 12px;
}
.pane-source-head h2 { margin: 0; font-size: 15px; word-break: break-all; }
/* the source resize handle sits on THIS panel's right edge */
.source-resize {
  top: 0; bottom: 0; left: auto; right: 0; width: 12px;
}
.source-resize::after { left: auto; right: 4px; }
.pane-source:hover .source-resize::after { background: #d5d5d5; }
.source-resize:hover::after { background: #9a9a9a; }
.pane-title { font-size: 15px; font-weight: 600; margin: 2px 0 12px; }
.pane-subtitle { font-size: 13px; font-weight: 600; color: #666; margin: 22px 0 8px; }

/* Live ingest progress: doc name + percent on one row, then chunk blocks that
   invert (white->black) as each chunk completes, left to right. */
.ing-doc {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: 12px; font-weight: 600; overflow-wrap: anywhere;
}
.ing-pct { font-weight: 600; color: #555; font-variant-numeric: tabular-nums; flex-shrink: 0; }
.ing-blocks { display: flex; flex-wrap: wrap; gap: 3px; margin: 8px 0 4px; }
.ing-block {
  width: 18px; height: 18px; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 9px; line-height: 1; border-radius: 4px;
  border: 1px solid #dcdcdc; background: #fff; color: #444;
  transition: background-color .25s ease, color .25s ease, border-color .25s ease;
}
.ing-block.done { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
.ing-block.active { border-color: #1a1a1a; box-shadow: 0 0 0 1px #1a1a1a inset; }
.ing-block.skip { opacity: .3; }
.ing-block.deferred { background: #f4ead0; border-color: #d9c48a; color: #7a6a2f; }
.ing-block.failed { background: #f6d8d3; border-color: #c0392b; color: #a3271c; }

/* One progress bar per concurrently-ingesting document. */
.ing-bar-row { margin: 10px 0; }
.ing-bar-row:first-child { margin-top: 4px; }
.ing-bar-doc {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: 12px; margin-bottom: 5px;
}
.ing-bar-fn {
  font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ing-bar-pct {
  font-weight: 600; color: #555; font-variant-numeric: tabular-nums; flex-shrink: 0;
}
.ing-bar-eta { margin-top: 3px; font-variant-numeric: tabular-nums; }

/* Cross-doc enrichment bar — a distinct accent from the ingest bars, since it
   is a different phase (relating docs, not reading one). */
.enrich-progress { margin-top: 14px; }
.enrich-progress .ip-fill { background: #4a72b0; }

.dropzone {
  border: 1.5px dashed #cfcfcf;
  border-radius: 10px;
  padding: 28px 16px;
  text-align: center;
  cursor: pointer;
  color: #666;
  transition: border-color .12s, background .12s;
}
.dropzone:hover, .dropzone.over { border-color: var(--ink); background: #f5f5f5; }
.dz-hint { line-height: 1.7; }
.upload-status { margin-top: 12px; font-size: 13px; color: #444; min-height: 20px; }

/* ---- ingest progress bar (determinate per-chunk + in-chunk timer) ---- */
.ingest-progress { margin-top: 12px; }
.ingest-progress.hidden { display: none; }
.ip-bar {
  height: 6px; background: #eee; border-radius: 3px; overflow: hidden;
  margin-bottom: 6px;
}
.ip-fill {
  height: 100%; width: 0%; background: #6b9a1f; border-radius: 3px;
  transition: width .25s ease;
}
/* No total to fill against (within one LLM call / extraction): show motion,
   not a false percentage. */
.ip-fill.indeterminate {
  width: 30%; transition: none;
  animation: ip-indeterminate 1.2s ease-in-out infinite;
}
@keyframes ip-indeterminate {
  0%   { margin-left: -30%; }
  100% { margin-left: 100%; }
}
.ip-line { font-size: 12px; }

.source-list { list-style: none; padding: 0; margin: 0; }
.source-list li {
  font-size: 13px; margin-bottom: 6px;
}
.source-list li.muted {
  padding: 7px 10px; border: 1px solid var(--line);
  border-radius: 7px; background: #fcfcfc;
}
.source-item {
  display: block; width: 100%; text-align: left; font: inherit;
  font-size: 13px; padding: 7px 10px; border: 1px solid var(--line);
  border-radius: 7px; background: #fcfcfc; color: var(--ink);
  cursor: pointer; word-break: break-all;
  transition: border-color .12s, background .12s;
}
.source-item:hover { border-color: #bdbdbd; background: #f4f4f4; }

/* Documents list — one list that reads sources AND edits per document */
.doc-head { display: flex; justify-content: space-between; align-items: center; }
.doc-edit-toggle {
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  color: #666; background: #fff; border: 1px solid var(--line);
  border-radius: 6px; padding: 2px 9px;
}
.doc-edit-toggle:hover { color: var(--ink); border-color: #bdbdbd; }
.doc-edit-toggle.is-on {
  color: #fff; background: var(--ink); border-color: var(--ink);
}
.doc-actions.hidden { display: none; }
.source-item.doc-row {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
}
.doc-name { word-break: break-all; }
.doc-count { white-space: nowrap; flex-shrink: 0; }
.source-item.is-selected {
  border-color: var(--ink); background: #f0f0f0;
  box-shadow: 0 0 0 1px var(--ink) inset;
}
/* read-mode: the document whose nodes are highlighted on the graph */
.source-item.doc-focused {
  border-color: #c25a34; background: #fdf1ec; color: #1a1a18; font-weight: 500;
}
.doc-actions { margin-top: 10px; }
.doc-actions-hint { margin-bottom: 8px; word-break: break-all; }
.edit-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.upload-status.error { color: #c0392b; }

/* pending review (converted docs awaiting the user's OK) */
.pending-subtitle { color: #9a6b1f; }
.pending-list { margin-bottom: 4px; }
.pending-item {
  display: block; width: 100%; text-align: left; font: inherit;
  font-size: 13px; padding: 7px 10px; border: 1px solid #e7d9b8;
  border-radius: 7px; background: #fffaf0; color: var(--ink);
  cursor: pointer; word-break: break-all;
  transition: border-color .12s, background .12s;
}
.pending-item:hover { border-color: #d8c081; background: #fef4dd; }
/* Durable failure flag on a stopped ingest (e.g. a minimax chunk that errored):
   the doc is parked for the user's verdict, never silently dropped. */
.pending-item.failed { border-color: #e3b4b0; background: #fdf2f1; }
.pending-item.failed:hover { border-color: #d98b85; background: #fbe9e7; }
.fail-badge {
  display: inline-block; margin-left: 8px; font-size: 11px; font-weight: 600;
  padding: 1px 7px; border-radius: 999px; background: #fbe3e1; color: #b3261e;
  vertical-align: middle;
}
.fail-banner {
  margin-bottom: 10px; padding: 9px 11px; border-radius: 7px;
  border: 1px solid #e3b4b0; background: #fdf2f1; color: #8a1f17;
  font-size: 13px; line-height: 1.45;
}
.pending-subtitle.has-failure::after {
  content: "•"; color: #b3261e; margin-left: 6px; font-size: 18px;
  vertical-align: middle;
}
.pending-actions {
  display: flex; align-items: center; gap: 10px; margin-top: 14px;
  padding-top: 14px; border-top: 1px solid var(--line);
}
.pending-body {
  max-height: 64vh; overflow: auto; font-size: 14px; line-height: 1.6;
  background: #fff; border: 1px solid var(--line); border-radius: 8px;
  padding: 16px 20px;
}
.pending-body img { max-width: 100%; height: auto; display: block; margin: 10px 0; }
.pending-body table { border-collapse: collapse; margin: 10px 0; }
.pending-body th, .pending-body td { border: 1px solid var(--line); padding: 4px 8px; }
.pending-body h1, .pending-body h2, .pending-body h3 { line-height: 1.3; }
.pending-chunks { margin: 4px 0 12px; }
.pending-chunk-bar {
  height: 6px; background: #eee; border-radius: 3px; overflow: hidden;
  margin-bottom: 6px;
}
.pending-chunk-fill {
  height: 100%; width: 0%; background: #6b9a1f; transition: width .2s;
}
.pending-chunk-results {
  margin-top: 6px; max-height: 200px; overflow: auto;
  border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px;
}
.chunk-toolbar { display: flex; gap: 6px; margin: 6px 0 2px; }
.chunk-toolbar .btn { padding: 2px 8px; font-size: 11px; }
/* Keep the review modal inside the viewport: cap the card height and let
   the rendered-document body be the single scroll region. */
#pendingModal .modal-card.wide {
  width: 760px; max-height: 92vh; display: flex; flex-direction: column;
}
#pendingModal .source-modal-head,
#pendingModal #pendingHint,
#pendingModal #pendingWarn,
#pendingModal .pending-chunks,
#pendingModal .pending-actions { flex: 0 0 auto; }
#pendingModal .pending-body {
  flex: 1 1 auto; min-height: 70px; max-height: none;
}
.chunk-row {
  display: block; padding: 3px 2px; border-top: 1px solid #f1f1f1;
  cursor: pointer;
}
.chunk-row:first-child { border-top: none; }
.chunk-cb { margin-right: 6px; vertical-align: middle; }
.chunk-mark { display: inline-block; width: 1.2em; text-align: center; }
.chunk-done .chunk-mark { color: #4a8a2a; }
.chunk-next .chunk-mark { color: #9a6b1f; }
.chunk-todo .chunk-mark { color: #bbb; }
.chunk-skip .chunk-mark { color: #ccc; }
.chunk-deferred .chunk-mark { color: #b5792b; }
.chunk-next .chunk-label { font-weight: 600; color: #9a6b1f; }
.chunk-todo .chunk-label { color: #777; }
.chunk-skip .chunk-label { color: #bbb; text-decoration: line-through; }
.chunk-deferred .chunk-label { color: #8a5a1a; }
.chunk-deferred { background: #fdf6ec; }
.chunk-failed .chunk-mark { color: #b3261e; }
.chunk-failed .chunk-label { color: #8a2018; }
.chunk-failed { background: #fdeceb; }

/* Sidebar "Ingest failures" section */
.fail-model-row { display: flex; align-items: center; gap: 6px; margin: 4px 0 6px; }
.fail-model-row .model-select { flex: 1; min-width: 0; }
.fail-list { list-style: none; padding: 0; margin: 0; }
.fail-item {
  padding: 6px 8px; margin-bottom: 6px; border: 1px solid #f0d6d3;
  border-radius: 6px; background: #fdf4f3;
}
.fail-item-name { font-size: 13px; word-break: break-word; }
.fail-item .btn { margin-top: 5px; }
/* inline text-button used in ingest status lines (e.g. "retry deferred") */
.link-btn {
  background: none; border: none; padding: 0; cursor: pointer;
  color: #9a6b1f; text-decoration: underline; font: inherit;
}
.link-btn:disabled { color: #c4a; opacity: .6; cursor: default; }
.chunk-label { font-size: 12px; }
.chunk-meta { font-size: 11px; color: #888; }
.chunk-preview {
  font-size: 11px; color: #9a9a9a; margin-left: 1.8em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* source viewer modal */
.source-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 12px;
}
.source-modal-head h2 {
  margin: 0; font-size: 15px; word-break: break-all;
}
/* Source text fills the panel directly — no boxed-in gray frame. Scrolls
   inside the panel (the panel clips to its rounded corners). */
.source-body {
  flex: 1; min-height: 0; margin: 0; overflow: auto;
  white-space: pre-wrap; word-break: break-word;
  font-size: 13.5px; line-height: 1.6; color: var(--ink);
  background: none; border: none; border-radius: 0; padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui,
    "PingFang SC", "Microsoft YaHei", sans-serif;
}
/* Zero-plaintext placeholder: the source body the cloud tier declines to
   serve. Muted so it reads as a system note, not document text. */
.source-body.source-placeholder { color: var(--muted); font-style: italic; }

/* Very small floating node/edge counter — bottom-right, over the graph.
   Clickable: opens the reading-heat popover. */
.graph-count-badge {
  position: absolute; right: 14px; bottom: 12px; z-index: 26;
  font-size: 11px; color: var(--muted);
  background: rgba(255, 255, 255, .86);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 3px 10px; pointer-events: auto; cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .08);
  max-width: 60%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.graph-count-badge:hover { background: #fff; color: var(--fg); }

/* Reading-heat popover — what this substrate is actually being read for.
   Anchored just above the count badge, bottom-right. */
.heat-popover {
  position: absolute; right: 14px; bottom: 44px; z-index: 40;
  width: 320px; max-height: 62vh; overflow-y: auto;
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
  padding: 12px 14px; box-shadow: 0 8px 30px rgba(0, 0, 0, .16);
  font-size: 12px; color: var(--fg);
}
.heat-popover.hidden { display: none; }
.heat-sec { margin-bottom: 12px; }
.heat-sec:last-child { margin-bottom: 0; }
.heat-sec-t {
  font-size: 10px; letter-spacing: .04em; text-transform: none;
  color: var(--muted); margin-bottom: 6px; font-weight: 600;
}
.heat-row {
  display: flex; justify-content: space-between; gap: 10px;
  align-items: baseline; padding: 3px 0; line-height: 1.4;
}
.heat-main { flex: 1; min-width: 0; }
.heat-n { color: var(--muted); font-size: 11px; white-space: nowrap; flex-shrink: 0; }
.heat-sub { color: var(--muted); font-size: 11px; margin: -1px 0 4px; padding-left: 2px; }
.heat-verb { color: var(--muted); font-style: italic; padding: 0 2px; }
.heat-empty { color: var(--muted); line-height: 1.5; }

/* Graph controls bar — map view / situated overlay / audit, grouped as one
   flex row in the graph's TOP-RIGHT. The top-LEFT corner is owned by the
   ingest sidebar (z-index 30, full left column), so any control placed there
   hides behind it (and is unclickable) — the "card poking out behind the
   panel" bug. Keeping all three on the right, right of the graph's open space,
   avoids the collision and lets the labels size themselves without fragile
   fixed offsets. */
.graph-tools {
  position: absolute; top: 12px; right: 14px; z-index: 26;
  display: flex; gap: 8px; align-items: center;
  max-width: calc(100% - 32px); flex-wrap: wrap; justify-content: flex-end;
}

/* Situated overlay (R1.3): "显示我的思考" toggle + the per-node notes popover.
   Toggle lives in .graph-tools (top-right); popover bottom-left. */
.sit-overlay-toggle {
  font: inherit; font-size: 12px; color: var(--muted);
  background: rgba(255, 255, 255, .86);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 4px 14px; cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .08);
}
.sit-overlay-toggle:hover { background: #fff; color: var(--ink); }
.sit-overlay-toggle.on { background: var(--ink); color: #fff; border-color: var(--ink); }

.sit-overlay-pop {
  position: absolute; left: 14px; bottom: 44px; z-index: 40;
  width: 300px; max-height: 62vh; overflow-y: auto;
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
  padding: 12px 14px; box-shadow: 0 8px 30px rgba(0, 0, 0, .16);
  font-size: 12px; color: var(--fg);
}
.sit-overlay-pop.hidden { display: none; }
.sit-pop-head { display: flex; align-items: center; justify-content: space-between;
  font-weight: 600; font-size: 12.5px; margin-bottom: 8px; }
.sit-pop-close { border: none; background: none; font-size: 18px; line-height: 1;
  color: var(--muted); cursor: pointer; padding: 0 2px; }
.sit-pop-close:hover { color: var(--fg); }
.sit-pop-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 10px; }
.sit-pop-chip { font-size: 10px; color: #fff; border-radius: 8px; padding: 1px 7px; }
.sit-pop-note { display: flex; gap: 8px; align-items: flex-start; padding: 5px 0;
  border-top: 1px solid #f2f2f2; }
.sit-pop-note:first-of-type { border-top: none; }
.sit-pop-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; }
.sit-pop-q { line-height: 1.5; color: #23231f;
  font-family: Georgia, "Songti SC", "Noto Serif SC", serif; }
.sit-pop-at { font-size: 10.5px; color: var(--muted); margin-top: 2px; }
.sit-pop-empty { color: var(--muted); padding: 4px 0; }
.sit-pop-link { display: inline-block; margin-top: 10px; font-size: 11.5px; color: var(--ink);
  border: 1px solid var(--line); border-radius: 7px; padding: 4px 10px; }
.sit-pop-link:hover { border-color: var(--ink); }
.sit-pop-foot { margin-top: 10px; font-size: 10.5px; color: var(--muted); }

.cy { flex: 1; min-height: 0; background: #fbfbfb; touch-action: none; overscroll-behavior: contain; }

/* ---- small buttons / inputs ---- */
.btn.small { padding: 4px 10px; font-size: 12px; }
.input {
  width: 100%; font: inherit; padding: 9px 11px; border: 1px solid #d0d0d0;
  border-radius: 8px; margin-top: 4px;
}
.form-err { color: var(--ink); font-weight: 500; font-size: 12px; min-height: 16px; margin: 6px 0; }
.connect-status { font-size: 13px; color: #444; line-height: 1.6; min-height: 18px; margin: 6px 0 2px; }

/* ---- spinner ---- */
.spinner {
  display: inline-block; width: 11px; height: 11px; margin-left: 6px;
  border: 2px solid #ccc; border-top-color: var(--ink); border-radius: 50%;
  vertical-align: -1px; animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- modal ---- */
.modal {
  position: fixed; inset: 0; background: rgba(0,0,0,.35);
  display: flex; align-items: center; justify-content: center; z-index: 50;
}
.modal.hidden { display: none; }
.modal-card {
  background: var(--card); border-radius: 12px; padding: 22px 24px;
  width: 360px; max-width: 92vw; box-shadow: 0 12px 40px rgba(0,0,0,.18);
}
.modal-card.wide { width: 560px; }
.modal-card h2 { font-size: 16px; margin: 0 0 12px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 16px; }
.snippet {
  background: #1e1e1e; color: #e6e6e6; border-radius: 8px; padding: 14px 16px;
  font-size: 12px; line-height: 1.5; overflow: auto; max-height: 320px;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}
code { background: #f0f0f0; padding: 1px 6px; border-radius: 5px; font-size: 13px; }

/* ---- topbar settings link ---- */
.topbar-link {
  font-size: 13px; color: var(--muted); text-decoration: none;
  padding: 4px 8px; border-radius: 6px;
}
.topbar-link:hover { background: #f0f0f0; color: var(--ink); }

/* ---- settings page ---- */
.settings-wrap { max-width: 640px; margin: 0 auto; display: flex;
  flex-direction: column; gap: 18px; }
.page-settings .card { cursor: default; }
.page-settings .card:hover { box-shadow: none; border-color: var(--border, #e2e2e2); }
.settings-form { display: flex; flex-direction: column; gap: 16px; margin-top: 12px; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field label { font-size: 13px; font-weight: 600; display: flex;
  align-items: center; gap: 8px; }
.field input {
  font: inherit; padding: 8px 10px; border: 1px solid #d0d0d0;
  border-radius: 8px; background: #fff;
}
.badge { font-size: 11px; font-weight: 500; padding: 1px 7px; border-radius: 10px;
  background: #eee; color: #777; }
.badge.ok { background: #e6f4ea; color: #1a7f37; }
.settings-actions { display: flex; align-items: center; gap: 12px; }

/* ---- model selector (settings + ingest pane) ---- */
.model-select {
  font: inherit; padding: 7px 10px; border: 1px solid #d0d0d0;
  border-radius: 8px; background: #fff; max-width: 100%;
}
.model-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.model-row .model-select { flex: 1; min-width: 0; }
.model-warn { font-size: 12px; color: #9a6700; min-height: 16px; margin-bottom: 8px; }

/* Ingest mode controls: Smart (default) / Normal toggle; Themes triggers
   on-demand when non-empty. */
.mode-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.mode-toggle { display: inline-flex; gap: 6px; }
.mode-btn {
  font: inherit; font-size: 12px; padding: 4px 12px; cursor: pointer;
  border: 1px solid #d0d0d0; border-radius: 8px; background: var(--card);
  color: var(--ink);
}
.mode-btn.active { background: var(--ink); color: #fff; border-color: var(--ink); }
.themes-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.themes-input {
  font: inherit; padding: 7px 10px; border: 1px solid #d0d0d0;
  border-radius: 8px; background: #fff; resize: vertical; min-height: 38px;
}

/* Smart-triage per-chunk effort badge. */
.chunk-bucket {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 1px 6px; border-radius: 6px; border: 1px solid var(--line);
  color: var(--muted); background: #f2f2f2; margin-left: 2px;
}
.chunk-bucket-heavy { color: #7a1f1f; background: #fdeaea; border-color: #f3caca; }
.chunk-bucket-dense { color: #5a3a00; background: #fbf0dd; border-color: #f0dcb4; }
.chunk-bucket-standard { color: #3a3a3a; background: #f0f0f0; }
.chunk-bucket-light { color: #2a5a2a; background: #e9f4e9; border-color: #cce3cc; }
.chunk-bucket-skip { color: #8a8a8a; background: #f2f2f2; text-decoration: line-through; }

/* situated layer — recall results + related */
.recall-row { display: flex; gap: 8px; align-items: center; margin-bottom: 14px; }
.recall-row .input { margin-top: 0; }
.recall-results { display: flex; flex-direction: column; gap: 8px; }
.recall-hit { padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: #fcfcfc; cursor: pointer; transition: border-color .12s, background .12s; }
.recall-hit:hover { border-color: #bdbdbd; background: #f4f4f4; }
.recall-head { font-size: 13px; line-height: 1.45; }
.recall-score { display: inline-block; font-size: 11px; color: var(--muted); min-width: 30px; }
.related-list { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 10px; }
.related-item { font-size: 12px; color: #444; padding: 2px 0; }

/* ===== dialectical assemblage dialogue (v1) ===== */
.dlg-body .main { padding: 0; height: calc(100vh - 49px); }
.crumb { color: var(--muted); font-size: 13px; }
.dlg-grid { display: grid; grid-template-columns: 1fr minmax(0, 340px); height: 100%; }
/* Narrow screens: the 340px perspective rail would squeeze the dialogue to
   an unusable sliver. Stack it under the transcript instead of shrinking it. */
@media (max-width: 760px) {
  .dlg-grid { grid-template-columns: 1fr; grid-auto-rows: minmax(0, auto); overflow: auto; }
  .dlg-main { border-right: none; border-bottom: 1px solid var(--line); }
}
.dlg-grid .pane { overflow: auto; }
.dlg-main { display: flex; flex-direction: column; border-right: 1px solid var(--line); }
.dlg-side { background: var(--card); padding: 16px; }
.transcript { flex: 1 1 auto; overflow: auto; padding: 20px 24px; }
.turn-input { flex: 0 0 auto; display: flex; gap: 8px; padding: 12px 16px;
  border-top: 1px solid var(--line); background: var(--card); }
.turn-input textarea { flex: 1; resize: none; border: 1px solid var(--line);
  border-radius: 8px; padding: 8px 10px; font: inherit; }
.turn-input button { padding: 0 18px; border-radius: 8px; border: 1px solid var(--ink);
  background: var(--ink); color: #fff; cursor: pointer; }
.turn-input button:disabled { opacity: .4; cursor: default; }

.hint { color: var(--muted); font-size: 13px; line-height: 1.7; max-width: 640px; }
.turn { margin: 0 0 18px; max-width: 760px; }
.turn .who { font-size: 12px; color: var(--muted); margin-bottom: 4px; }
.turn .body { white-space: pre-wrap; line-height: 1.7; }
.turn.user .body { background: #f0f4ff; border-radius: 10px; padding: 10px 14px; }
.turn.voice .body { background: var(--card); border: 1px solid var(--line);
  border-radius: 10px; padding: 12px 16px; }
.turn.opening .body { background: #f7f9f5; }

.evidence { max-width: 760px; margin: 0 0 12px; border: 1px solid #e7dcc5;
  background: #fbf7ee; border-radius: 10px; padding: 10px 14px; }
.ev-h { font-size: 12px; color: #8a6d2f; font-weight: 600; margin-bottom: 6px;
  display: flex; align-items: center; gap: 8px; }
.badge { font-size: 11px; padding: 1px 7px; border-radius: 999px; font-weight: 600; }
.badge.ok { background: #e4f3e4; color: #2f7d32; }
.badge.weak { background: #f3e9e4; color: #9a5b2f; }
.ev-empty { font-size: 13px; color: #9a5b2f; }
.ev-list { margin: 0; padding-left: 0; list-style: none; }
.ev-list li { margin: 6px 0; font-size: 13px; }
.etype { font-size: 11px; font-weight: 700; padding: 0 6px; border-radius: 4px;
  background: #efe2e2; color: #a23b3b; }
.etype.questions { background: #e7e2ef; color: #5b3ba2; }
.enode { color: var(--muted); font-size: 12px; margin-left: 6px; }
.eorigin { color: var(--muted); font-size: 12px; margin-left: 6px; }
.eclaim { color: var(--ink); margin-top: 3px; line-height: 1.6; font-weight: 500; }
.erat { color: var(--muted); margin-top: 2px; line-height: 1.6; font-size: 12px; }
.thinking { color: var(--muted); font-size: 13px; font-style: italic; margin: 4px 0 14px; }
.err { color: #b23; font-size: 13px; margin: 8px 0; }

.side-block { margin-bottom: 20px; }
.side-h { font-size: 13px; font-weight: 600; margin-bottom: 8px;
  display: flex; align-items: center; gap: 8px; }
.side-h .slug { font-size: 11px; color: var(--muted); border: 1px solid var(--line);
  border-radius: 4px; padding: 0 5px; }
.dlg-side textarea { width: 100%; resize: vertical; border: 1px solid var(--line);
  border-radius: 8px; padding: 8px 10px; font: inherit; font-size: 13px; line-height: 1.6; }
.side-actions { display: flex; gap: 8px; margin-top: 8px; }
.side-actions button, #synthBtn { padding: 6px 12px; border-radius: 7px;
  border: 1px solid var(--line); background: var(--card); cursor: pointer; font-size: 13px; }
.side-actions .primary, #synthBtn { margin-top: 8px; }
.side-actions .primary { background: var(--ink); color: #fff; border-color: var(--ink); }
.muted { color: var(--muted); }
.small { font-size: 12px; line-height: 1.8; }
#lstatus { margin-top: 6px; font-size: 12px; color: var(--muted); }

/* assemblage list */
.wrap { max-width: 760px; margin: 0 auto; padding: 28px 24px; }
.page-h { font-size: 20px; margin: 0 0 6px; }
.asm-list { margin-top: 18px; display: flex; flex-direction: column; gap: 12px; }
.asm-card { border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px;
  background: var(--card); }
.asm-name { font-weight: 600; }
.asm-meta { margin-top: 4px; }
.asm-go { margin-top: 8px; }
.primary-link { color: #2f5fd0; text-decoration: none; font-size: 14px; }
.empty { margin-top: 18px; color: var(--muted); }

/* compose page */
.page-sub { font-size: 15px; margin: 28px 0 10px; color: var(--ink); }
.compose-list { margin: 16px 0; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.graph-row { display: flex; align-items: center; gap: 10px; padding: 11px 14px;
  border-bottom: 1px solid var(--line); cursor: pointer; }
.graph-row:last-child { border-bottom: none; }
.graph-row:hover { background: #f6f8ff; }
.graph-cb { width: 16px; height: 16px; }
.g-name { font-weight: 600; }
.g-meta { margin-left: auto; }
.compose-actions { display: flex; gap: 10px; margin-top: 4px; }
.compose-actions input { flex: 1; border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 12px; font: inherit; }
.compose-actions .primary { padding: 8px 16px; border-radius: 8px; border: 1px solid var(--ink);
  background: var(--ink); color: #fff; cursor: pointer; }
#composeStatus { margin-top: 8px; }

/* ---- account auth (register / login / token) ---------------------- */
.page-auth .card { cursor: default; }
.auth-wrap { max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }
.auth-error {
  background: #fdecea; border: 1px solid #f5c6c2; color: #8a1c12;
  padding: 8px 12px; border-radius: 6px; font-size: 13px; margin: 4px 0 12px;
}
.token-reveal {
  border: 1px solid #cfe3cf; background: #f3faf3; border-radius: 8px;
  padding: 12px 14px; margin: 10px 0;
}
.token-note { color: #2f6f3a; font-size: 13px; margin: 0 0 10px; }
.token-field {
  width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; padding: 8px 10px; border: 1px solid #cfcfcf;
  border-radius: 6px; box-sizing: border-box; background: #fff;
}
.token-snippet {
  white-space: pre-wrap; word-break: break-all; font-size: 12px;
  background: #1f2430; color: #e6e6e6; padding: 10px 12px; border-radius: 6px;
  margin: 6px 0 0;
}

/* ---- web Google sign-in button ----------------------------------- */
.or-sep { text-align: center; color: #aaa; font-size: 12px; margin: 14px 0 10px; }
.google-btn { display: block; text-align: center; }

/* ==================================================================== */
/* Graph audit panel + inspection card (audit.js)                       */
/* ==================================================================== */

/* audit toggle pill — sits in the .graph-tools flex bar (top-right) */
.audit-toggle {
  font: inherit; font-size: 12px; color: var(--muted);
  background: rgba(255, 255, 255, .86);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 4px 14px; cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .08);
}
.audit-toggle:hover { background: #fff; color: var(--ink); }
.audit-toggle.on { background: var(--ink); color: #fff; border-color: var(--ink); }

/* Entry to the map view (semantic-zoom renderer) — same pill language,
   first item in the .graph-tools flex bar (top-right). */
.map-link {
  font-size: 12px; color: var(--muted); text-decoration: none;
  background: rgba(255, 255, 255, .86);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 4px 14px; white-space: nowrap;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .08);
}
.map-link:hover { background: #fff; color: var(--ink); }

/* the audit sidebar: rounded floating window, right side of the graph */
.audit-panel {
  position: absolute; top: 14px; right: 14px; bottom: 44px;
  width: 424px; max-width: calc(100% - 40px); z-index: 30;
  background: var(--card); border: 1px solid var(--line);
  border-radius: 18px; box-shadow: 0 8px 34px rgba(0, 0, 0, .14);
  display: flex; flex-direction: column; overflow: hidden;
}
.audit-panel.hidden { display: none; }
.audit-head { padding: 14px 18px 0; flex: none; }
.audit-title { display: flex; align-items: baseline; gap: 8px; }
.audit-title h2 { font-size: 15px; font-weight: 600; margin: 0; }
.audit-tabs { display: flex; gap: 2px; margin-top: 10px; border-bottom: 1px solid var(--line); }
.audit-tab {
  font: inherit; font-size: 13px; color: var(--muted); cursor: pointer;
  background: none; border: none; padding: 6px 12px 8px;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.audit-tab:hover { color: var(--ink); }
.audit-tab.active { color: var(--ink); font-weight: 600; border-bottom-color: var(--ink); }
.audit-body { flex: 1; overflow-y: auto; padding: 14px 18px 24px; }
.audit-body section + section { margin-top: 20px; }
.audit-sec-title {
  font-size: 11px; font-weight: 600; letter-spacing: .1em; color: var(--muted);
  text-transform: uppercase; margin: 0 0 8px;
  display: flex; align-items: baseline; gap: 8px;
}
.audit-status { font-size: 12px; color: var(--muted); padding: 2px 0 0; min-height: 16px; }
.audit-status.err { color: #a4433a; }
.audit-loading { color: var(--muted); font-size: 12.5px; padding: 12px 0; }

/* stat strip */
.audit-stats { display: flex; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.audit-stat { flex: 1; padding: 8px 6px; text-align: center; }
.audit-stat + .audit-stat { border-left: 1px solid #f0f0ef; }
.audit-stat b { display: block; font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }
.audit-stat span { font-size: 11px; color: var(--muted); }

/* agent bars */
.agent-bar {
  display: grid; grid-template-columns: 110px 1fr 44px; align-items: center;
  gap: 10px; padding: 4px 8px; width: 100%;
  font: inherit; color: var(--ink); text-align: left; cursor: pointer;
  background: none; border: none; border-radius: 8px;
}
.agent-bar:hover { background: #f0f0ef; }
.agent-bar .a-name { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.agent-bar .a-track { height: 6px; border-radius: 99px; background: #f0f0ef; overflow: hidden; }
.agent-bar .a-fill { height: 100%; border-radius: 99px; background: var(--ink); opacity: .72; }
.agent-bar .a-val { font-size: 12px; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }

/* concept rows */
.concept-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 7px 10px; font: inherit; color: var(--ink); text-align: left;
  background: none; border: none; border-radius: 8px; cursor: pointer;
}
.concept-row:hover { background: #f0f0ef; }
.concept-row .c-rank { flex: none; width: 18px; font-size: 12px; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
.concept-row .c-main { flex: 1; min-width: 0; }
.concept-row .c-name { font-size: 13px; font-weight: 600; word-break: break-all; }
.concept-row .c-meta { font-size: 11.5px; color: var(--muted); margin-top: 1px; }
.concept-row .c-xdoc {
  flex: none; font-size: 11px; color: #9a6b1f; background: #f7efdd;
  border-radius: 99px; padding: 1px 8px; white-space: nowrap;
}
.audit-doc-group { font-size: 12px; font-weight: 600; color: var(--muted); margin: 10px 0 2px; word-break: break-all; }

/* health rows */
.health-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 10px; font: inherit; color: var(--ink); text-align: left;
  background: none; border: none; border-radius: 8px; cursor: pointer;
}
.health-row:hover { background: #f0f0ef; }
.health-dot { flex: none; width: 8px; height: 8px; border-radius: 99px; background: var(--muted); }
.health-dot.warn { background: #9a6b1f; }
.health-row .h-name { flex: 1; font-size: 13px; }
.health-pill {
  font-size: 12px; font-weight: 600; border-radius: 99px; padding: 1px 9px;
  background: #f0f0ef; color: var(--ink); font-variant-numeric: tabular-nums;
}
.health-pill.warn { background: #f7efdd; color: #9a6b1f; }
.health-chev { color: var(--muted); font-size: 12px; }

/* auto-tidy notice */
.audit-notice {
  border: 1px solid var(--line); border-radius: 10px; padding: 10px 13px;
  background: var(--bg); font-size: 12.5px;
}
.audit-notice .n-line { display: flex; align-items: baseline; gap: 6px; padding: 2px 0; flex-wrap: wrap; }
.audit-notice .n-line b { font-weight: 600; }
.undo-btn {
  font: inherit; font-size: 12px; color: var(--ink); background: none; border: none;
  padding: 0; cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}

/* queue chips */
.audit-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.audit-chip {
  font: inherit; font-size: 12px; cursor: pointer;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  border-radius: 99px; padding: 4px 11px;
}
.audit-chip:hover { border-color: var(--muted); }
.audit-chip.on { background: var(--ink); color: #fff; border-color: var(--ink); }
.audit-chip .chip-n { opacity: .65; margin-left: 4px; font-variant-numeric: tabular-nums; }
.queue-note { font-size: 12px; color: var(--muted); margin: 0 0 10px; }

/* queue cards */
.audit-card {
  border: 1px solid var(--line); border-radius: 12px; background: var(--card);
  padding: 13px 14px; box-shadow: 0 1px 3px rgba(0, 0, 0, .05);
}
.audit-card + .audit-card { margin-top: 10px; }
.audit-card.done { opacity: .55; box-shadow: none; }
.ev-row { display: flex; flex-wrap: wrap; gap: 5px; margin: 0 0 9px; }
.ev-tag { font-size: 11px; border-radius: 5px; padding: 2px 7px; background: #f0f0ef; color: var(--muted); }
.ev-tag.strong { background: #f7efdd; color: #9a6b1f; }
.sal-tag { font-size: 11px; border-radius: 5px; padding: 2px 7px; background: #f7efdd; color: #9a6b1f; }
.pair-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.pair-box { border: 1px solid #f0f0ef; border-radius: 9px; padding: 8px 10px; background: var(--bg); min-width: 0; }
.pair-box .p-name { font-size: 12.5px; font-weight: 600; word-break: break-all; cursor: pointer; }
.pair-box .p-name:hover { text-decoration: underline; }
.pair-box .p-src { font-size: 11px; color: var(--muted); margin-top: 2px; word-break: break-all; }
.pair-box .p-text { font-size: 12px; margin-top: 6px; }
.audit-quote {
  border-left: 2px solid var(--line); padding: 2px 0 2px 10px; margin: 8px 0 0;
  font-size: 12px; color: var(--muted);
}
.audit-quote b { color: var(--ink); font-weight: 500; }
.card-acts { display: flex; gap: 8px; margin-top: 11px; align-items: center; flex-wrap: wrap; }
.card-acts .btn { padding: 4px 12px; font-size: 12.5px; }
.btn.ghost { border-color: transparent; color: var(--muted); }
.btn.ghost:hover { color: var(--ink); }
.verdict-line { font-size: 12px; font-weight: 600; color: var(--muted); }
.verdict-line.ok { color: #3f7a52; }
.audit-radio { display: flex; align-items: center; gap: 8px; padding: 5px 8px; border-radius: 8px; cursor: pointer; font-size: 13px; }
.audit-radio:hover { background: #f0f0ef; }
.audit-radio .r-sub { font-size: 11.5px; color: var(--muted); }
.rename-row { display: flex; align-items: center; gap: 8px; margin-top: 9px; }
.rename-row input[type=text] {
  flex: 1; font: inherit; font-size: 12.5px; color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px; padding: 5px 10px; background: var(--bg);
  min-width: 0;
}
.audit-fold { border-top: 1px dashed var(--line); margin-top: 12px; padding-top: 9px; font-size: 12px; color: var(--muted); }

/* inspection card: floating window on the graph layer */
.insp-card {
  position: absolute; top: 14px; right: 14px; bottom: 44px;
  width: 408px; max-width: calc(100% - 40px); z-index: 42;
  background: var(--card); border: 1px solid var(--line);
  border-radius: 18px; box-shadow: 0 8px 34px rgba(0, 0, 0, .16);
  display: flex; flex-direction: column; overflow: hidden;
}
.insp-card.hidden { display: none; }
.insp-card.beside { right: 452px; }
.insp-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 16px; border-bottom: 1px solid #f0f0ef; flex: none;
}
.insp-head .insp-kind { font-size: 11px; font-weight: 600; letter-spacing: .1em; color: var(--muted); text-transform: uppercase; }
.insp-body { flex: 1; overflow-y: auto; padding: 14px 16px 22px; }
.insp-body section + section { margin-top: 18px; }
.insp-name { font-size: 16px; font-weight: 600; margin: 0; word-break: break-all; }
.insp-sub { font-size: 12px; color: var(--muted); margin: 3px 0 0; word-break: break-all; }
.insp-statement { font-size: 13.5px; margin: 10px 0 0; }
/* Edge inspection card: relation direction A → B + provisional marker. */
.edge-prov { font-size: 12px; font-weight: 400; color: var(--muted); }
.edge-dir {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px; padding: 9px 12px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
}
.edge-dir .edge-node { font-weight: 500; color: var(--ink); word-break: break-word; }
.edge-dir .edge-arrow { color: var(--muted); flex: none; }
.insp-metrics { display: flex; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; margin-top: 12px; }
.doc-line { display: flex; align-items: baseline; gap: 8px; padding: 3px 0; font-size: 12.5px; }
.doc-line .d-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-line .d-n { color: var(--muted); font-size: 12px; flex: none; font-variant-numeric: tabular-nums; }
.gen-entry { position: relative; padding: 0 0 12px 18px; border-left: 2px solid #f0f0ef; margin-left: 5px; }
.gen-entry:last-child { padding-bottom: 2px; }
.gen-entry::before {
  content: ""; position: absolute; left: -5px; top: 5px; width: 8px; height: 8px;
  border-radius: 99px; background: var(--muted);
}
.gen-entry.counter::before { background: #a4433a; }
.gen-entry .g-year { font-size: 11px; color: var(--muted); letter-spacing: .05em; }
.gen-entry .g-text { font-size: 12.5px; }
.nb-row { display: flex; align-items: center; gap: 8px; padding: 5px 8px; border-radius: 8px; }
.nb-row:hover { background: #f0f0ef; }
.nb-row .nb-name { font-size: 13px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.nb-row .nb-name:hover { text-decoration: underline; }
.nb-chip { font-size: 11px; border-radius: 99px; padding: 1px 8px; flex: none; background: #f0f0ef; color: var(--muted); }
.nb-chip.unlinked { background: #f7efdd; color: #9a6b1f; }
.nb-sim { font-size: 11.5px; color: var(--muted); flex: none; width: 34px; text-align: right; font-variant-numeric: tabular-nums; }
.rel-head { font-size: 12px; font-weight: 600; color: var(--muted); margin: 9px 0 3px; }
.rel-line { font-size: 12.5px; padding: 3px 0 3px 12px; border-left: 2px solid #f0f0ef; margin: 3px 0; }
.rel-line .muted { font-size: 11.5px; }
.rename-row.hidden { display: none; }
.bridge-line { margin: 0 0 2px; font-size: 13.5px; line-height: 1.5; }
.bridge-line .p-name { cursor: pointer; }
.bridge-line .p-name:hover { text-decoration: underline; }
.bridge-verb {
  display: inline-block; margin: 0 6px; padding: 0 8px; border-radius: 99px;
  font-size: 12px; font-weight: 600; background: #f7efdd; color: #9a6b1f;
  white-space: nowrap;
}
.bridge-meta { margin: 0; }
.bridge-details { margin-top: 7px; }
.bridge-details summary {
  font-size: 12px; color: var(--muted); cursor: pointer;
  list-style-position: inside;
}
.bridge-details summary:hover { color: var(--ink); }

/* ==================================================================== */
/* Responsive clamps — the graph page's floating panels are fixed-width */
/* windows sized for a wide desktop. Below that they must shrink (and,   */
/* when two panels can't sit side by side, stop trying to) so they don't */
/* overlap / occlude each other. The left source viewer vs. the right    */
/* audit + inspection panels are also made mutually exclusive below      */
/* 1600px in JS (detail.js / audit.js); these rules keep whatever IS     */
/* open within the viewport. Widths use min() so a panel never exceeds   */
/* the space available after its inset, on any window size or resize.    */
/* ==================================================================== */

/* Medium screens: narrow the right-side panels and the source viewer so
   a panel plus the persistent left sidebar still fit with margin. */
@media (max-width: 1500px) {
  .audit-panel { width: min(400px, calc(100vw - 32px)); }
  .insp-card { width: min(384px, calc(100vw - 32px)); }
  .insp-card.beside { right: min(428px, calc(100vw - 400px)); }
}

/* Narrow screens: two ~400px panels cannot sit side by side. The
   inspection card stops going beside the audit panel and overlays it
   instead (it already has the higher z-index, so it wins cleanly and
   the user closes one at a time). Every floating window caps to the
   viewport so nothing spills off-screen. */
@media (max-width: 1100px) {
  .pane-left { width: min(var(--sidebar-w), calc(100vw - 32px)); }
  /* Keep the source viewer docked to the right of the sidebar (never over
     it), just clamp its width to whatever room is left. */
  .pane-source {
    width: min(var(--source-w),
               calc(100vw - 16px - var(--sidebar-w) - 14px - 16px));
  }
  .audit-panel,
  .insp-card { width: min(440px, calc(100vw - 28px)); }
  .insp-card.beside { right: 14px; }
}

/* ==================================================================== */
/* Phone (≤640px): the workspace page drops the graph entirely.         */
/* The render + layout is the heavy part and janks badly on mobile /    */
/* ngrok, so tapping a workspace lands on a plain vertical scroll of the */
/* ingest + documents panel, with audit reachable through a floating     */
/* button. detail.js makes the matching cut (skips loadGraph here).      */
/* ==================================================================== */
@media (max-width: 640px) {
  /* topbar: tighten and let it wrap rather than overflow */
  .topbar { padding: 10px 14px; flex-wrap: wrap; gap: 4px 10px; }
  .brand { font-size: 15px; }
  .topbar-actions { gap: 8px; }

  /* the detail page stops being one pinned viewport and scrolls normally */
  body.page-detail {
    position: static; overflow: visible; height: auto; display: block;
  }
  .page-detail > .main { padding: 0; height: auto; overflow: visible; }
  .detail { height: auto; }

  /* ingest panel: from floating card to the full-width content column */
  .pane-left {
    position: static; width: auto;
    top: auto; left: auto; bottom: auto;
    border: none; border-radius: 0; box-shadow: none; background: transparent;
  }
  .pane-scroll { overflow: visible; padding: 18px 16px 96px; }

  /* the graph surface + everything that only makes sense over it */
  .pane-right, .pane-resize, .pane-min-toggle,
  .graph-count-badge, .heat-popover,
  .map-link, .sit-overlay-toggle, .sit-overlay-pop { display: none; }

  /* audit: a floating pill pinned to the viewport (rides along as the page
     scrolls); it opens a full-screen sheet. */
  .graph-tools {
    position: fixed; top: auto; bottom: 16px; right: 16px; left: auto;
    z-index: 45; max-width: none;
  }
  .audit-toggle { padding: 9px 18px; font-size: 13px;
    box-shadow: 0 3px 14px rgba(0, 0, 0, .18); }

  /* every floating window becomes a full-screen sheet */
  .audit-panel {
    position: fixed; inset: 0; top: 0; right: 0; bottom: 0; left: 0;
    width: auto; max-width: none; border: none; border-radius: 0; z-index: 50;
  }
  .pane-source {
    position: fixed; inset: 0; top: 0; right: 0; bottom: 0; left: 0;
    width: auto; max-width: none; border: none; border-radius: 0; z-index: 52;
  }
  .insp-card, .insp-card.beside {
    position: fixed; inset: 0; top: 0; right: 0; bottom: 0; left: 0;
    width: auto; max-width: none; border: none; border-radius: 0; z-index: 55;
  }
}

/* ---- Commons section on the main screen (mounted graphs + shelf) ---- */
.section-title { font-size: 15px; font-weight: 600; margin: 28px 0 12px; }
/* Mounted/shelf cards act on hover (a mount is not an edit); edit mode
   shows the mounted ✕ too, matching the other cards' rhythm. */
.mounted-card:hover .card-actions,
.shelf-card:hover .card-actions { display: flex; }
.card-act.act-add { width: auto; padding: 0 10px; font-size: 12.5px; }

/* ---- One Documents list (2026-07-30) ---- */
/* An un-ingested doc is ordinary library stock, not an approval alert —
   neutral row; the hover Ingest button IS its state. Failure keeps red. */
.pending-item { border-color: var(--line); background: #fff; }
.pending-item:hover { border-color: #c9c9c4; background: #fcfcfc; }
.pending-list li { display: flex; align-items: center; gap: 6px; }
.pending-list li .act-ingest { display: none; flex: none; white-space: nowrap; }
.pending-list li:hover .act-ingest { display: inline-block; }
.pending-list .pending-item { flex: 1 1 auto; min-width: 0; }
/* Edit mode: rows are selection targets — the hover Ingest button yields. */
body.doc-editing .pending-list li .act-ingest { display: none !important; }
.pending-item.is-selected { border-color: #8a8a86; background: #f4f4f2; }
