:root {
  --bg: #0e0f11;
  --bg2: #16181c;
  --bg3: #1e2026;
  --border: #2a2d35;
  --border2: #363a44;
  --text: #e2e4ea;
  --text2: #8b909e;
  --text3: #555b6a;
  --accent: #4a9eff;
  --accent2: #1a4a7a;
  --green: #3dba7a;
  --amber: #e8a83a;
  --coral: #e05a4e;
  --purple: #9b72e8;
  --teal: #2ec4b6;
  --sans: 'IBM Plex Sans', system-ui, -apple-system, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;
  /* Detail-pane width — set by the resize-handle drag in App.js. Default
     restored from localStorage on mount; clamped to [280, 50% window]. */
  --detail-width: 380px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  /* `100vh` (not `100%`) so the chain doesn't depend on a parent height
     percentage being honored. `overflow: hidden` at the page level forces
     all descendant containers to actually respect viewport bounds — without
     it, even with explicit grid/flex sizing, an overflowing inner element
     could expand the page (mimiron#14). */
  height: 100vh;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 12px;
  line-height: 1.5;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

/* The grid layout for the app shell goes on #app (the Vue mount point),
   not on body — body just contains #app. Earlier attempts put the grid
   on body, but #app sits in between body and the header/main panes, so
   the grid sized #app (correctly) while #app-header and #app-main were
   left in normal block flow with no constraint, free to grow to content
   size (mimiron#14). */
#app {
  display: grid;
  grid-template-rows: auto 1fr;
  height: 100vh;
  overflow: hidden;
}

::-webkit-scrollbar { width: 4px; height: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 2px; }
::-webkit-scrollbar-thumb:hover { background: var(--text3); }

/* ───── Header ───── */

#app-header {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 16px;
  height: 44px;
  background: var(--bg2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.wordmark {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
}

#search {
  flex: 1;
  max-width: 480px;
  height: 28px;
  padding: 0 10px;
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
  font-family: var(--sans);
  font-size: 12px;
  outline: none;
}

#search:focus { border-color: var(--accent); }
#search::placeholder { color: var(--text3); }

.header-link {
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text3);
  padding: 4px 10px;
  border: 1px solid transparent;
  border-radius: 3px;
  text-decoration: none;
  transition: color 100ms, border-color 100ms;
}

.header-link:hover { color: var(--text); border-color: var(--border2); }
.header-link.active { color: var(--accent); border-color: var(--accent); }

.header-nav { display: flex; gap: 4px; }

.header-meta {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
}

.api-version {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.health-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text3);
  cursor: help;
  transition: background 200ms;
}

.health-dot.health-ok { background: var(--green); box-shadow: 0 0 6px rgba(61, 186, 122, 0.6); }
.health-dot.health-degraded { background: var(--amber); box-shadow: 0 0 6px rgba(232, 168, 58, 0.6); }
.health-dot.health-down { background: var(--coral); box-shadow: 0 0 6px rgba(224, 90, 78, 0.6); }
.health-dot.health-unknown { background: var(--text3); }

/* Show-deleted toggle (#75 slice 3). Off state reads as a muted chip;
   on state borrows the coral palette already used for deletion warnings
   elsewhere so the visual link is obvious. */
.deleted-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text3);
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: color 100ms, background 100ms, border-color 100ms;
}
.deleted-toggle:hover { color: var(--text2); border-color: var(--border2); }
.deleted-toggle.active {
  color: var(--coral);
  background: rgba(224, 90, 78, 0.10);
  border-color: rgba(224, 90, 78, 0.4);
}
.deleted-toggle-icon { font-size: 11px; line-height: 1; }
.deleted-toggle-label { font-size: 10px; }

/* ───── Main layout ───── */

#app-main {
  /* Sized by body's grid (`auto 1fr` rows). Don't need flex: 1 anymore. */
  display: grid;
  /* Columns: catalog, graph (absorbs free space), resize handle, detail.
     Detail width is a CSS var set by the resize handle in App.js. */
  grid-template-columns: 240px minmax(0, 1fr) 6px var(--detail-width);
  /* Explicit row sizing — without this the implicit row defaults to
     min-content and grows to fit the tallest pane's content (e.g. a long
     markdown body), which stretched the graph-pane to match and made the
     whole page scroll (mimiron#14). minmax(0, 1fr) fills the available
     row height and lets the row shrink below content size so each pane's
     internal `overflow-y: auto` actually scrolls. */
  grid-template-rows: minmax(0, 1fr);
  /* Hard overflow cap so the grid items can't push #app-main past its
     allocated row size. */
  overflow: hidden;
  min-height: 0;
}

/* Grid items inherit min-height: auto by default, which prevents shrinking
   below their content's size — that's how a long markdown body could
   stretch its pane and the grid row through the cap above. Force min-height
   and min-width to 0 on every pane so the grid can size them down to the
   row/column and the inner overflow-y: auto kicks in. */
#app-main > .pane {
  min-height: 0;
  min-width: 0;
}

/* Templates layout — a 2-column grid (index · detail). No graph (no edges
   to render), no resize handle (the slider was useful when graph was the
   center of mass; here it'd just shuffle two text panes around). The
   index pane is fixed-width like the catalog; the detail takes the rest. */
#templates-main {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  overflow: hidden;
  min-height: 0;
}
#templates-main > .pane { min-height: 0; min-width: 0; }
.templates-index {
  background: var(--bg2);
  border-right: 1px solid var(--border);
}

.pane {
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.catalog-pane {
  background: var(--bg2);
  border-right: 1px solid var(--border);
}

.graph-pane {
  background:
    radial-gradient(circle at 1px 1px, rgba(85, 91, 106, 0.18) 1px, transparent 0)
    0 0 / 24px 24px,
    var(--bg);
  border-right: 1px solid var(--border);
  position: relative;
}

.detail-pane {
  background: var(--bg2);
  /* Border now lives on the resize-handle column, not the detail pane. */
}

/* Resize handle between graph-pane and detail-pane. The grid column is
   6px wide so the hit area is comfortable; the visible divider is
   centered inside it. */
.resize-handle {
  position: relative;
  cursor: col-resize;
  background: var(--border);
  transition: background 100ms;
  /* Prevent the browser from interpreting drags as text selection. */
  touch-action: none;
  user-select: none;
}

.resize-handle:hover,
.resize-handle:active,
body.is-resizing .resize-handle { background: var(--accent); }

/* While a resize drag is in flight, force the col-resize cursor everywhere
   so it doesn't flicker as the pointer crosses other elements, and disable
   text selection globally. */
body.is-resizing { cursor: col-resize !important; user-select: none; }
body.is-resizing * { cursor: col-resize !important; user-select: none !important; }

/* ───── Catalog ───── */

.catalog-list {
  flex: 1;
  overflow-y: auto;
  padding: 8px 0;
}

.catalog-row {
  display: block;
  padding: 8px 16px;
  border-left: 2px solid transparent;
  text-decoration: none;
  color: inherit;
  transition: background 100ms, border-color 100ms;
  cursor: pointer;
}

.catalog-row:hover { background: var(--bg3); border-left-color: var(--border2); }
.catalog-row.active { background: var(--accent2); border-left-color: var(--accent); }
/* Soft-deleted rows (#75 slice 3): muted opacity + strikethrough on the
   name so they read as 'present but retired' next to active rows. Hover
   restores opacity so the row stays clickable for audit. */
.catalog-row.deleted { opacity: 0.55; }
.catalog-row.deleted:hover { opacity: 1; }
.catalog-row.deleted .row-name { text-decoration: line-through; text-decoration-color: var(--text3); }
.deleted-chip {
  margin-left: 6px;
  font-size: 9px;
  font-family: var(--mono);
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--coral);
  background: rgba(224, 90, 78, 0.10);
  border: 1px solid rgba(224, 90, 78, 0.3);
  padding: 1px 5px;
  border-radius: 2px;
}

.row-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  margin-bottom: 4px;
}

.row-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}

.catalog-empty, .catalog-error {
  padding: 24px 16px;
  color: var(--text3);
  text-align: center;
  font-size: 11px;
}

.catalog-error { color: var(--coral); }

/* ───── Grouped sections (catalog) ───── */

.catalog-section {
  border-bottom: 1px solid var(--border);
}

.catalog-section:last-child { border-bottom: none; }

.section-header {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--text3);
  transition: color 100ms, background 100ms;
}

.section-header:hover { color: var(--text2); background: var(--bg2); }
.section-header:focus-visible { outline: 1px solid var(--accent); outline-offset: -2px; }

.section-header .chevron {
  display: inline-block;
  width: 10px;
  font-size: 10px;
  color: var(--text3);
  transition: transform 120ms;
}

.section-header .chevron.open { transform: rotate(90deg); }

.section-spacer { flex: 1; }

.section-rows {
  display: flex;
  flex-direction: column;
  padding-bottom: 6px;
}

.contract-pair {
  font-family: var(--mono);
  font-size: 12px;
}

/* ───── Chips ───── */

.version-chip, .alias-chip, .template-chip, .updated-chip, .direction-chip, .project-chip, .actor-chip, .override-chip {
  display: inline-block;
  padding: 1px 6px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 400;
  border-radius: 2px;
  border: 1px solid var(--border2);
  color: var(--text2);
  background: var(--bg3);
  white-space: nowrap;
  vertical-align: middle;
}

.version-chip { color: var(--accent); border-color: var(--accent2); }
.alias-chip { color: var(--text3); }
.template-chip { color: var(--purple); border-color: var(--purple); opacity: 0.7; text-decoration: none; }
a.template-chip:hover { opacity: 1; background: rgba(155, 114, 232, 0.1); }

/* Project chip — small slug pill near subtype/version. Click navigates to
   project detail. The "unprojected" variant is muted so users distinguish
   "no tag" from "tagged X." */
.project-chip {
  color: var(--green);
  border-color: rgba(61, 186, 122, 0.4);
  background: rgba(61, 186, 122, 0.08);
  text-decoration: none;
}
a.project-chip:hover { background: rgba(61, 186, 122, 0.18); }
.project-chip.project-none {
  color: var(--text3);
  border-color: var(--border2);
  background: transparent;
  font-style: italic;
  cursor: default;
}

/* Actor chip — surfaces X-Actor attribution (proposer/acceptor/registered).
   Anonymous variant flagged so audits can spot two-party-rule bypasses. */
.actor-chip {
  color: var(--text2);
  border-color: var(--border2);
  background: transparent;
}
.actor-chip.actor-anon { color: var(--coral); border-color: rgba(224, 90, 78, 0.4); }
.actor-chip.actor-chip-mini { font-size: 8px; padding: 1px 4px; }

/* Override chip — visible audit trail for ?single_operator=true accepts.
   Amber to read as "warning, but allowed by design." */
.override-chip {
  color: var(--amber);
  border-color: var(--amber);
  background: rgba(232, 168, 58, 0.08);
}

.proposal-chip {
  display: inline-block;
  padding: 1px 6px;
  font-family: var(--mono);
  font-size: 9px;
  border-radius: 2px;
  border: 1px solid var(--amber);
  color: var(--amber);
  background: rgba(232, 168, 58, 0.08);
  white-space: nowrap;
  vertical-align: middle;
  text-transform: lowercase;
}

.catalog-error-inline {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--coral);
}
.updated-chip { color: var(--text3); border-color: transparent; background: transparent; padding-left: 0; }

.direction-chip { font-weight: 500; text-transform: uppercase; }
.direction-chip.dir-out { color: var(--amber); border-color: var(--amber); }
.direction-chip.dir-in { color: var(--teal); border-color: var(--teal); }

/* ───── Detail pane ───── */

.detail-empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--text3);
  text-align: center;
  padding: 24px;
}

.empty-glyph {
  font-size: 56px;
  color: var(--border2);
  line-height: 1;
  font-weight: 200;
}

.empty-text {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text2);
  text-transform: lowercase;
  letter-spacing: 0.05em;
}

.empty-hint {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--text3);
  text-transform: lowercase;
  letter-spacing: 0.05em;
}

.detail-content {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.detail-loading, .detail-empty-inline {
  padding: 24px;
  color: var(--text3);
  text-align: center;
  font-size: 11px;
}

.detail-error {
  margin: 16px;
  padding: 12px 16px;
  background: rgba(224, 90, 78, 0.08);
  border: 1px solid var(--coral);
  border-radius: 3px;
}

.detail-error-status {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--coral);
  text-transform: uppercase;
  margin-bottom: 4px;
}

.detail-error-detail {
  font-size: 12px;
  color: var(--text);
}

.detail-topbar {
  padding: 14px 18px 10px;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--bg2);
  flex-shrink: 0;
}

.topbar-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.topbar-row.chips { gap: 4px; }
.topbar-row.links { gap: 6px; padding-top: 2px; }

.type-badge {
  display: inline-block;
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  border-radius: 2px;
}

.type-badge.type-part     { background: rgba(74, 158, 255, 0.15); color: var(--accent); }
.type-badge.type-contract { background: rgba(155, 114, 232, 0.15); color: var(--purple); }
.type-badge.type-graph    { background: rgba(46, 196, 182, 0.15); color: var(--teal); }
.type-badge.type-template { background: rgba(232, 168, 58, 0.15); color: var(--amber); }
.type-badge.type-project  { background: rgba(61, 186, 122, 0.15); color: var(--green); }

/* Subtype chip: smaller than type-badge; rendered next to part/contract
   type badges and in catalog/contract rows. Two part subtypes
   (software | container) and two contract subtypes (interaction | binding). */
.subtype-chip {
  display: inline-block;
  padding: 2px 6px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: lowercase;
  letter-spacing: 0.05em;
  border-radius: 2px;
  border: 1px solid transparent;
}
.subtype-chip.subtype-mini { padding: 1px 5px; font-size: 8px; }
/* Part subtype palette — five visually distinct colors. The original
   "runtime trio in teal family" idea (container/pod/compose all teal-ish)
   wasn't actually helping the user tell pod from compose; freeing up
   amber + green for them gives the 5 part subtypes maximum
   distinguishability. Contracts (below) all share purple — distinguishing
   3 contract subtypes by color is lower-signal than distinguishing the 5
   part subtypes, since contracts in the graph are uniformly-styled edges
   anyway. */
.subtype-chip.subtype-software    { background: rgba(74, 158, 255, 0.10); color: var(--accent); border-color: var(--accent2); }
.subtype-chip.subtype-image       { background: rgba(224, 90, 78, 0.10);  color: var(--coral);  border-color: rgba(224, 90, 78, 0.4); }
.subtype-chip.subtype-container   { background: rgba(46, 196, 182, 0.10); color: var(--teal);   border-color: rgba(46, 196, 182, 0.4); }
.subtype-chip.subtype-pod         { background: rgba(232, 168, 58, 0.10); color: var(--amber);  border-color: rgba(232, 168, 58, 0.4); }
.subtype-chip.subtype-compose     { background: rgba(61, 186, 122, 0.10); color: var(--green);  border-color: rgba(61, 186, 122, 0.4); }
/* K8s runtime palette (M-A / archaedas#9). Colors duplicated from GraphPane.js
   SUBTYPE_COLOR so the catalog chip and the graph node border read as the
   same hue for each subtype. Inline rather than promoted to CSS vars because
   the variable namespace is already small and these aren't reused elsewhere. */
.subtype-chip.subtype-deployment  { background: rgba(78, 205, 196, 0.10); color: #4ecdc4; border-color: rgba(78, 205, 196, 0.4); }
.subtype-chip.subtype-statefulset { background: rgba(38, 166, 154, 0.10); color: #26a69a; border-color: rgba(38, 166, 154, 0.4); }
.subtype-chip.subtype-job         { background: rgba(255, 209, 102, 0.10); color: #ffd166; border-color: rgba(255, 209, 102, 0.4); }
.subtype-chip.subtype-service     { background: rgba(17, 138, 178, 0.10); color: #118ab2; border-color: rgba(17, 138, 178, 0.4); }
.subtype-chip.subtype-ingress     { background: rgba(6, 214, 160, 0.10);  color: #06d6a0; border-color: rgba(6, 214, 160, 0.4); }
.subtype-chip.subtype-secret      { background: rgba(239, 71, 111, 0.10); color: #ef476f; border-color: rgba(239, 71, 111, 0.4); }
.subtype-chip.subtype-configmap   { background: rgba(155, 142, 181, 0.10); color: #9b8eb5; border-color: rgba(155, 142, 181, 0.4); }
/* Helm chart umbrella (#69) — mature rose, warm-family cousin to compose. */
.subtype-chip.subtype-chart       { background: rgba(163, 73, 110, 0.10); color: #a3496e; border-color: rgba(163, 73, 110, 0.4); }
/* All contract subtypes share purple — text label conveys which kind. */
.subtype-chip.subtype-interaction,
.subtype-chip.subtype-binding,
.subtype-chip.subtype-connection  { background: rgba(155, 114, 232, 0.10); color: var(--purple); border-color: rgba(155, 114, 232, 0.4); }

/* Sensitive-data banner on PartDetail for subtype=secret (M-D / archaedas#9).
   Top-level visual reminder that the template encodes a "key names only,
   never values" convention. Muted red — distinguishes from chip topbar
   without reusing the .error-banner style (this is a guideline reminder,
   not an error state). */
.sensitive-banner {
  margin: 12px 0;
  padding: 8px 12px;
  font-family: var(--mono);
  font-size: 11px;
  color: #ef476f;
  background: rgba(239, 71, 111, 0.08);
  border: 1px solid rgba(239, 71, 111, 0.4);
  border-radius: 3px;
}

/* Sub-discriminator chip for connection contracts. Renders the
   connection_type label (one of: builds-from, instantiates, runs, member-of,
   depends-on, submodule) next to the subtype chip. Visually subdued — the
   subtype chip already establishes the color, this just spells out which
   flavor of connection it is. */
.connection-type-chip {
  display: inline-block;
  padding: 1px 6px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--text2);
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 2px;
}

.connection-type-chip.connection-type-mini { padding: 1px 5px; font-size: 8px; }

/* Cross-project boundary banner — surfaces when a contract's `project`
   differs from one or both endpoints'. Cross-project contracts are allowed
   by design (they carry whichever project owns the relationship), but the
   boundary should be visible so users see the asymmetry. Amber outlines
   read as "notable, not error." */
.cross-project-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 6px 10px;
  background: rgba(232, 168, 58, 0.06);
  border: 1px solid rgba(232, 168, 58, 0.4);
  border-radius: 3px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text2);
}
.cross-project-glyph {
  color: var(--amber);
  font-size: 14px;
  font-weight: 600;
}
.cross-project-label {
  color: var(--amber);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 9px;
}
.cross-project-detail { color: var(--text3); }
.cross-project-slug { color: var(--text); }

/* Project picker — sits in the header, right of the search box. The select
   element is intentionally narrow; project slugs are short by convention. */
.project-picker {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text3);
}
.project-picker-label {
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 9px;
}
.project-picker-select {
  appearance: none;
  background: var(--bg2);
  color: var(--text);
  border: 1px solid var(--border2);
  border-radius: 3px;
  padding: 3px 24px 3px 8px;
  font-family: var(--mono);
  font-size: 10px;
  cursor: pointer;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text3) 50%),
    linear-gradient(135deg, var(--text3) 50%, transparent 50%);
  background-position:
    calc(100% - 12px) 50%,
    calc(100% - 8px) 50%;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}
.project-picker-select:hover { border-color: var(--accent2); }
.project-picker-select:focus { outline: 1px solid var(--accent); outline-offset: 1px; }

/* Agent picker (#79) — lives in the GraphPane toolbar adjacent to the view
   tabs, not in the header (it's coupled to the agent-* views and only
   visible when one of them is active). Same select-box styling as the
   project picker so the two pickers read as the same family of control. */
.agent-picker {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 8px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text3);
}
.agent-picker-label {
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 9px;
}
.agent-picker-select {
  appearance: none;
  background: var(--bg2);
  color: var(--text);
  border: 1px solid var(--border2);
  border-radius: 3px;
  padding: 3px 24px 3px 8px;
  font-family: var(--mono);
  font-size: 10px;
  cursor: pointer;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text3) 50%),
    linear-gradient(135deg, var(--text3) 50%, transparent 50%);
  background-position:
    calc(100% - 12px) 50%,
    calc(100% - 8px) 50%;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}
.agent-picker-select:hover { border-color: var(--accent2); }
.agent-picker-select:focus { outline: 1px solid var(--accent); outline-offset: 1px; }

.topbar-name {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}

.link-pill {
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text2);
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 2px;
  text-decoration: none;
  transition: border-color 100ms, color 100ms;
}

.link-pill:hover { border-color: var(--accent); color: var(--text); }

.alias-group {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--text3);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.detail-body {
  padding: 16px 18px;
  overflow-y: visible;
}

.detail-section {
  padding: 12px 18px 18px;
  border-top: 1px solid var(--border);
}

.section-title {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text3);
  margin: 0 0 12px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 8px;
}

.section-count {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--text3);
  background: var(--bg3);
  padding: 1px 6px;
  border-radius: 2px;
  border: 1px solid var(--border);
}

.contracts-list { display: flex; flex-direction: column; gap: 4px; }

.contract-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 3px;
  text-decoration: none;
  color: inherit;
  transition: border-color 100ms;
}

.contract-row:hover { border-color: var(--accent); }

.contract-other {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text);
  flex: 1;
}

.contract-meta {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--text3);
}

/* ───── History panel ───── */

.history-panel { padding: 0 18px 18px; border-top: 1px solid var(--border); }

.history-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 12px 0 8px;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text3);
  transition: color 100ms;
}

.history-toggle:hover { color: var(--text2); }
.history-toggle:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }

.history-toggle .chevron {
  display: inline-block;
  transition: transform 120ms;
  font-size: 10px;
  width: 10px;
}

.history-toggle .chevron.open { transform: rotate(90deg); }

.history-title { flex: 1; text-align: left; }

.history-body { padding-top: 10px; }

.history-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.history-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 3px;
}

.current-marker {
  display: inline-block;
  padding: 1px 6px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--green);
  border: 1px solid var(--green);
  border-radius: 2px;
  background: rgba(61, 186, 122, 0.08);
}

.history-pending {
  font-size: 11px;
  color: var(--text3);
  font-style: italic;
  padding: 8px 0;
}

.history-pending a { color: var(--accent); text-decoration: none; }
.history-pending a:hover { text-decoration: underline; }

/* History `kind` discriminator (titan-tyr v0.15.0+). Body bumps and
   subtype shifts are visually distinct so the timeline reads as
   "v1.2.0 shipped, then it shifted, then v1.3.0 shipped." Pre-v0.15.0
   responses lack kind — defaulted to body_bump in HistoryPanel. */
.kind-glyph {
  display: inline-block;
  width: 14px;
  text-align: center;
  font-size: 11px;
  font-family: var(--mono);
}
.kind-glyph.kind-bump  { color: var(--text3); }
.kind-glyph.kind-shift { color: var(--amber); }
/* Endpoint + name shifts (#75 slice 4 — titan-tyr #45 history.kind extension).
   Distinct hues from subtype shift's amber so the three shift kinds are
   immediately distinguishable in a long history list. Endpoint shift =
   accent blue (mirrors the endpoint-link color in OpenEndpointShiftsPanel);
   name shift = teal (neither blue nor amber, leaves the eye a clear
   third visual slot). */
.kind-glyph.kind-endpoint-shift { color: var(--accent); }
.kind-glyph.kind-name-shift     { color: var(--teal); }

.kind-label {
  font-family: var(--mono);
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--amber);
}
/* Override the amber on the new kinds so the kind-label color matches its
   glyph color. */
.history-row-endpoint_shift .kind-label { color: var(--accent); }
.history-row-name_shift     .kind-label { color: var(--teal); }

.history-row.history-row-subtype_shift {
  background: rgba(232, 168, 58, 0.04);
  border-color: rgba(232, 168, 58, 0.25);
}
.history-row.history-row-endpoint_shift {
  background: rgba(74, 158, 255, 0.04);
  border-color: rgba(74, 158, 255, 0.25);
}
.history-row.history-row-name_shift {
  background: rgba(46, 196, 182, 0.04);
  border-color: rgba(46, 196, 182, 0.25);
}

/* Inline before→after summary on shift-kind history rows. Code chips keep
   the identifiers readable; the arrow is the prominent delimiter. */
.shift-summary {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--mono);
  font-size: 10px;
}
.shift-summary code {
  background: var(--bg2);
  color: var(--text2);
  padding: 1px 4px;
  border-radius: 2px;
}

/* ───── Open subtype-shifts panel ───── */

.shifts-panel { padding: 0 18px 18px; border-top: 1px solid var(--border); }
.shifts-body { padding-top: 10px; }

.shifts-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.shift-row {
  padding: 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 3px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.shift-shift {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

.shift-arrow {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text3);
}

.shift-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 10px;
  color: var(--text3);
}

.shift-actor { font-family: var(--mono); }
.shift-anon { color: var(--coral); }

.shift-rationale {
  font-size: 11px;
  color: var(--text2);
  line-height: 1.5;
  font-style: italic;
  padding: 4px 0;
  border-top: 1px solid var(--border);
}

.shift-impact {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-top: 4px;
  border-top: 1px solid var(--border);
}

.impact-banner {
  font-size: 10px;
  color: var(--amber);
  background: rgba(232, 168, 58, 0.08);
  border: 1px solid rgba(232, 168, 58, 0.3);
  border-radius: 2px;
  padding: 6px 8px;
  line-height: 1.5;
}

.impact-banner code {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--text);
  background: rgba(232, 168, 58, 0.15);
  padding: 1px 4px;
  border-radius: 2px;
}

.impact-fail {
  font-size: 10px;
  color: var(--coral);
  background: rgba(224, 90, 78, 0.08);
  border: 1px solid rgba(224, 90, 78, 0.3);
  border-radius: 2px;
  padding: 6px 8px;
}

.impact-rows {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.impact-rows-title {
  font-size: 10px;
  color: var(--text3);
  font-family: var(--mono);
}

.impact-row {
  padding: 6px 8px;
  background: var(--bg2);
  border-radius: 2px;
  border-left: 2px solid var(--coral);
}

.impact-row-link {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text2);
  text-decoration: none;
}

.impact-row-link:hover { color: var(--text); }

.impact-reason {
  font-size: 10px;
  color: var(--text3);
  margin-top: 2px;
  font-style: italic;
}

.shift-accept-hint {
  font-size: 10px;
  color: var(--text3);
  padding-top: 4px;
  border-top: 1px solid var(--border);
}

.shift-accept-hint code {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--accent);
  background: rgba(74, 158, 255, 0.08);
  padding: 1px 5px;
  border-radius: 2px;
}

/* Endpoint-shift panel (#75 slice 2): renders owner→counterparty pairs
   before and after the shift. The pair itself is a sub-flex with its own
   thin arrow so the outer shift-arrow stays the prominent before/after
   delimiter. */
.endpoint-pair {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--mono);
  font-size: 11px;
}
.endpoint-arrow { color: var(--text3); font-size: 10px; }
.endpoint-link {
  color: var(--text2);
  text-decoration: none;
  border-bottom: 1px dotted var(--border);
}
.endpoint-link:hover { color: var(--text); border-bottom-color: var(--text3); }

/* Name-shift panel (#75 slice 2): inline code styling for the before/after
   slugs so they read as identifiers, not prose. */
.name-old, .name-new {
  font-family: var(--mono);
  font-size: 11px;
  padding: 1px 5px;
  border-radius: 2px;
  background: var(--bg2);
  color: var(--text2);
}
.name-new { color: var(--accent); background: rgba(74, 158, 255, 0.08); }

/* Deletion panel (#75 slice 2): visually distinct from the other shift
   panels — soft-delete is the most destructive accept, so the header
   carries a coral warning label and the rows pick up a coral left border
   to match the visual weight of impact-row. */
.deletions-panel .shift-row.deletion-row {
  border-left: 2px solid var(--coral);
}
.deletion-header {
  display: flex;
  align-items: center;
  gap: 6px;
}
.deletion-label {
  font-size: 10px;
  font-family: var(--mono);
  color: var(--coral);
  background: rgba(224, 90, 78, 0.10);
  padding: 2px 6px;
  border-radius: 2px;
  border: 1px solid rgba(224, 90, 78, 0.3);
}
.impact-note {
  font-size: 10px;
  color: var(--text3);
  font-style: italic;
}
.hint-extra {
  display: block;
  margin-top: 4px;
  color: var(--coral);
}

/* ───── Usage panel ───── */

.usage-panel { padding: 0 18px 18px; border-top: 1px solid var(--border); }

.usage-body { padding-top: 10px; }

.usage-loading {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text3);
  padding: 8px 0;
}

.usage-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding-bottom: 10px;
}

.usage-count {
  display: inline-block;
  padding: 2px 7px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border: 1px solid;
  border-radius: 2px;
}

.usage-count-active    { color: var(--green); border-color: var(--green); background: rgba(61, 186, 122, 0.08); }
.usage-count-drifted   { color: var(--amber); border-color: var(--amber); background: rgba(232, 168, 58, 0.08); }
.usage-count-unstamped { color: var(--text3); border-color: var(--border2); }
.usage-count-skipped   { color: var(--coral); border-color: var(--coral); background: rgba(224, 90, 78, 0.08); }

.usage-group { padding-top: 10px; }

.usage-group-title {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text3);
}

.usage-group-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 0 0 6px;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--text3);
  transition: color 100ms;
}

.usage-group-toggle:hover { color: var(--text2); }
.usage-group-toggle:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }

.usage-group-toggle .chevron {
  display: inline-block;
  transition: transform 120ms;
  font-size: 10px;
  width: 10px;
}

.usage-group-toggle .chevron.open { transform: rotate(90deg); }

.usage-group-count {
  font-family: var(--mono);
  font-size: 9px;
  color: var(--text3);
}

.usage-version-group { padding: 6px 0; }

.usage-version-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 0;
}

.version-chip.drift-chip { color: var(--amber); border-color: var(--amber); background: rgba(232, 168, 58, 0.08); }

.usage-list {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding-top: 4px;
}

.usage-row {
  display: flex;
  align-items: center;
  padding: 5px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 3px;
  text-decoration: none;
  color: var(--text2);
  font-size: 11px;
  transition: border-color 100ms, color 100ms;
}

.usage-row:hover { border-color: var(--accent); color: var(--text); }

.usage-name { font-family: var(--mono); }

/* ───── Markdown ───── */

.markdown-body { font-size: 12px; color: var(--text2); line-height: 1.6; }

.markdown-body h1 {
  font-size: 17px;
  font-weight: 500;
  color: var(--text);
  margin: 0 0 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

.markdown-body h2 {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin: 24px 0 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

.markdown-body h3 {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  margin: 20px 0 6px;
}

.markdown-body p { margin: 0 0 12px; }
.markdown-body strong { color: var(--text); font-weight: 500; }
.markdown-body em { color: var(--text); font-style: italic; }

.markdown-body ul, .markdown-body ol { padding-left: 18px; margin: 0 0 12px; }
.markdown-body ul li { list-style: none; position: relative; }
.markdown-body ul li::before {
  content: '—';
  color: var(--text3);
  position: absolute;
  left: -16px;
}

.markdown-body code {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--teal);
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 0 4px;
}

.markdown-body pre {
  margin: 0 0 12px;
  padding: 12px;
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 3px;
  overflow-x: auto;
}

.markdown-body pre code {
  background: transparent;
  border: none;
  padding: 0;
  color: var(--text2);
  font-size: 11px;
  line-height: 1.5;
}

.markdown-body table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 12px;
}

.markdown-body th, .markdown-body td {
  text-align: left;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 11px;
  vertical-align: top;
}

.markdown-body th {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text3);
  background: var(--bg2);
}

.markdown-body tr:hover td { background: var(--bg3); }

.markdown-body blockquote {
  margin: 0 0 12px;
  padding: 8px 12px;
  border-left: 3px solid var(--amber);
  background: var(--bg3);
  color: var(--text2);
}

.markdown-body hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 16px 0;
}

.markdown-body a {
  color: var(--accent);
  text-decoration: none;
}

.markdown-body a:hover { text-decoration: underline; }

/* External links get a small ↗ glyph so it's obvious they leave the app. */
.markdown-body a[target="_blank"]::after {
  content: ' ↗';
  font-size: 0.85em;
  color: var(--text3);
}

/* Links whose href didn't match any in-app pattern (no scheme, not a
   UUID, not a slug) — usually a relative path that won't resolve. */
.markdown-body a.md-link-broken {
  color: var(--coral);
  text-decoration: line-through dotted;
  text-decoration-color: var(--coral);
  cursor: help;
}
.markdown-body a.md-link-broken:hover { text-decoration: line-through dotted; }

/* ───── Graph pane ───── */

/* View tabs strip (All / Software / DevOps). Sits above the stage; doesn't
   scroll with overflow. flex-shrink: 0 so it always stays visible. */
.graph-tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 8px 12px;
  background: var(--bg2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.graph-tab {
  padding: 4px 12px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text3);
  transition: color 100ms, border-color 100ms, background 100ms;
}

.graph-tab:hover { color: var(--text2); border-color: var(--border2); }
.graph-tab:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.graph-tab.active {
  color: var(--accent);
  border-color: var(--accent2);
  background: rgba(74, 158, 255, 0.08);
}

.graph-tabs-spacer { flex: 1; }

/* Orientation toggle (LR ⇄ TB). Same monospace shape as the view tabs but
   set apart by sitting on the right and not participating in tab selection.
   Click cycles between the two values; the label IS the current value so
   the next click is whatever isn't shown. */
.graph-orient-toggle {
  padding: 4px 10px;
  background: transparent;
  border: 1px solid var(--border2);
  border-radius: 3px;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.05em;
  color: var(--text2);
  transition: color 100ms, border-color 100ms, background 100ms;
}
.graph-orient-toggle:hover { color: var(--accent); border-color: var(--accent2); }
.graph-orient-toggle:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }

/* Cytoscape draws on its own canvas with built-in pan/zoom, so the stage
   is a fixed flex panel and the container fills it. No outer scrolling —
   cy handles overflow internally. */
.graph-stage {
  flex: 1;
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: stretch;
  justify-content: stretch;
}

.graph-container {
  flex: 1;
  width: 100%;
  height: 100%;
  min-height: 320px;
}

.graph-loading,
.graph-empty {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text3);
  text-transform: lowercase;
  letter-spacing: 0.05em;
}

.graph-error {
  margin: 24px;
  padding: 12px 16px;
  background: rgba(224, 90, 78, 0.08);
  border: 1px solid var(--coral);
  border-radius: 3px;
}

.graph-error-status {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--coral);
  text-transform: uppercase;
  margin-bottom: 4px;
}

.graph-error-detail { font-size: 12px; color: var(--text); }

/* Cytoscape draws nodes + edges on its own canvas, so per-element styling
   (subtype tint, selected outline, focus hide, search dim) lives in the
   cytoscape stylesheet inside GraphPane.js, not here. Only the surrounding
   chrome (status messages, container size, legend) stays in CSS. */

.graph-legend {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 8px 16px;
  background: var(--bg2);
  border-top: 1px solid var(--border);
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text3);
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text2);
}

.legend-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
}

.swatch-node {
  background: var(--bg3);
  border: 1px solid var(--border2);
  border-radius: 2px;
}

.swatch-edge {
  height: 2px;
  background: var(--text3);
  position: relative;
}

.swatch-edge::after {
  content: '';
  position: absolute;
  right: -1px;
  top: 50%;
  transform: translateY(-50%);
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 5px solid var(--text3);
}

/* Per-contract-subtype edge swatches — mirror the linkStyle treatments
   applied in GraphPane.buildSource so the legend documents the encoding. */
.swatch-edge.edge-interaction { background: var(--text3); height: 2px; }
.swatch-edge.edge-binding     { background: var(--text3); height: 3px; }
.swatch-edge.edge-connection  {
  background: transparent;
  height: 0;
  border-top: 2px dashed var(--text3);
}
.swatch-edge.edge-connection::after { display: none; }

.legend-spacer { flex: 1; }
.legend-hint { color: var(--text3); }

.legend-link {
  background: transparent;
  border: 1px solid var(--accent2);
  border-radius: 2px;
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--accent);
  cursor: pointer;
  transition: border-color 100ms, color 100ms;
}

.legend-link:hover { border-color: var(--accent); color: var(--text); }
.legend-link:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }

/* ───── Error banner ───── */

.error-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 10px 16px;
  background: rgba(224, 90, 78, 0.95);
  color: white;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-size: 12px;
  z-index: 100;
}

.retry-btn {
  background: rgba(255, 255, 255, 0.2);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: white;
  padding: 4px 12px;
  font-family: var(--sans);
  font-size: 11px;
  border-radius: 3px;
  cursor: pointer;
}

.retry-btn:hover { background: rgba(255, 255, 255, 0.3); }
