/* teiCrafter Editor (Editor path) -- styles built only on the shared design tokens
   from style.css (--color-*, --space-*, --font-*, --radius-*). Tokens only; the
   violet family appears exclusively on AI-origin content (generated banner, AI
   actions, unverified entities and their mentions), per design.md. */

/* Flex column so the main grid always fills the space between toolbar and
   footer, with or without the generated-edition banner. */
.ed-body { margin: 0; height: 100vh; display: flex; flex-direction: column; overflow: hidden; }

/* Header and logo conventions come from .site-head (style.css). The document
   name moved out of the site header into the document strip under the toolbar. */

.ed-toolbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--color-secondary); border-bottom: 1px solid var(--color-border);
}
.ed-toolbar .group { display: flex; align-items: center; gap: var(--space-xs); }
.ed-toolbar .sep { width: 1px; height: 22px; background: var(--color-border); margin: 0 var(--space-xs); }
/* Page-position label in the pane head: navigation chrome, on the neutral
   control scale (secondary weight 500, font-ui), so it never reads bolder or
   greyer than the tabs beside it. It carries prose ("page", "pages"), not a
   bare identifier, so it is not mono. */
.ed-folio-label { font-family: var(--font-ui); font-size: var(--font-size-sm);
  font-weight: 500; color: var(--color-text-secondary); white-space: nowrap;
  font-variant-numeric: tabular-nums; }

.ed-btn {
  font-family: var(--font-ui); font-size: var(--font-size-sm); cursor: pointer;
  padding: var(--space-xs) var(--space-sm); border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-panel); color: var(--color-text);
}
.ed-btn:hover { border-color: var(--color-gold); }
/* Primary action: black on TEI yellow, the contrast pair of the TEI logo itself. */
.ed-btn-primary { background: var(--color-gold); border-color: var(--color-gold); color: var(--color-text); font-weight: 600; }
.ed-btn-primary:hover { background: var(--color-gold-hover); border-color: var(--color-gold-hover); }
.ed-btn:disabled { opacity: .5; cursor: not-allowed; }
/* A disabled button never carries the primary accent: the strongest visual
   weight on the page must not sit on an unusable control. */
.ed-btn-primary:disabled { background: var(--color-panel); border-color: var(--color-border); color: var(--color-text); }

/* Keyboard focus is always visible (triple-coding stance: never hover-only). */
:is(.ed-btn, .ed-dd-item, .ed-crit-btn, .ed-act-btn, .ed-menu-item,
    .ed-idx-btn, .ed-idx-rowbody, .ed-idx-authlink, .ed-recent-row, .ed-logo, .ed-val-chip):focus-visible {
  outline: 2px solid var(--color-gold); outline-offset: 1px;
}
.ed-btn-ai:focus-visible { outline-color: var(--color-ai); }

/* Shared form-control surface: the text inputs, selects and textareas across
   the index panel, the annotate popover, the source find bar and the LLM modal
   sit on one field surface (token-only). Each control adds only its own font,
   size and padding; focus colours stay with the control (gold in the human
   editor, violet in the LLM modal). */
.ed-idx-filter, .ed-idx-add-input, .ed-idx-authinput, .ed-idx-authtypesel,
.ed-sel-filter, .ed-modal textarea, .ed-modal select, .ed-modal input,
.ed-src-find input, .ed-meta-field input, .ed-meta-field textarea {
  color: var(--color-text); background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
}

/* Examples dropdown menu in the toolbar (a real menu, not a select-as-action). */
.ed-dd-wrap { position: relative; display: inline-flex; }
.ed-dd {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 60; min-width: 320px;
  display: flex; flex-direction: column; padding: var(--space-xs);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-panel); box-shadow: var(--shadow-pop);
}
.ed-dd-item { font-family: var(--font-ui); font-size: var(--font-size-sm); text-align: left;
  cursor: pointer; border: none; background: none; color: var(--color-text);
  padding: var(--space-xs) var(--space-sm); border-radius: var(--radius-sm); white-space: nowrap; }
.ed-dd-item:hover { background: var(--color-gold-light); }
.ed-dd-sep { height: 1px; background: var(--color-border); margin: var(--space-xs) 0; }
/* AI-assisted action (violet family, per design.md) */
.ed-btn-ai { border-color: var(--color-ai); color: var(--color-ai); }
.ed-btn-ai:hover { background: var(--color-ai-tint); border-color: var(--color-ai); }

/* AI-generated, unreviewed edition banner */
.ed-genbanner {
  display: flex; align-items: center; gap: var(--space-sm);
  padding: var(--space-xs) var(--space-md);
  background: var(--color-ai-tint); border-bottom: 1px solid var(--color-ai);
  font-size: var(--font-size-xs); color: var(--color-ai);
}
.ed-genbanner b { color: var(--color-ai); }

/* Plaintext-draft banner: deterministic transport, not AI, so it stays neutral
   (no violet). Sunken surface band, like the other full-width bands. */
.ed-draftbanner {
  display: flex; align-items: center; gap: var(--space-sm);
  padding: var(--space-xs) var(--space-md);
  background: var(--color-surface-sunken); border-bottom: 1px solid var(--color-border);
  font-size: var(--font-size-xs); color: var(--color-text-body);
}
.ed-draftbanner-dismiss { margin-left: auto; }

/* Document strip: a slim factual line under the toolbar, visible only while a
   document is loaded. Sunken band, small font, clear hierarchy, no shouting. */
.ed-docstrip {
  display: flex; flex: 1 1 28rem; align-items: baseline; gap: var(--space-xs);
  margin-left: auto; min-width: 0; white-space: nowrap;
  overflow: hidden;
  padding: 2px var(--space-sm); background: transparent; border: none;
  font-family: var(--font-ui); font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
}
.ed-docstrip-name { font-family: var(--font-mono); font-size: var(--font-size-sm);
  color: var(--color-text); min-width: 4rem; overflow: hidden; text-overflow: ellipsis; }
.ed-docstrip-name.dirty::after { content: " *"; color: var(--color-gold-hover); }
.ed-docstrip-sep { color: var(--color-text-muted); }
.ed-docstrip-fact { color: var(--color-text-secondary); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 1400px) {
  .ed-docstrip { flex-basis: 100%; margin-left: 0; padding-left: 0; }
}

/* Live-checks term definitions in the validation popover (muted, not hover-only). */
.ed-val-note { font-size: var(--font-size-xs); color: var(--color-text-muted);
  margin-top: var(--space-xs); }
.ed-val-actions { display: flex; flex-wrap: wrap; gap: var(--space-xs);
  margin-top: var(--space-sm); }

/* LLM-input modal */
.ed-modal {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: center; justify-content: center;
  background: var(--scrim-modal); padding: var(--space-md);
}
.ed-modal-card {
  width: min(640px, 100%); max-height: 90vh; overflow: auto;
  background: var(--color-panel); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-modal);
}
.ed-modal-head, .ed-modal-foot {
  display: flex; align-items: center; gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md); background: var(--color-secondary);
}
.ed-modal-head { justify-content: space-between; border-bottom: 1px solid var(--color-border);
  font-weight: 600; color: var(--color-text); }
.ed-modal-foot { justify-content: flex-end; border-top: 1px solid var(--color-border); }
.ed-modal-body { padding: var(--space-md); display: flex; flex-direction: column; gap: var(--space-sm); }
.ed-field { display: flex; flex-direction: column; gap: 2px; font-size: var(--font-size-sm); color: var(--color-text-secondary); }
.ed-field > span { font-weight: 500; }
.ed-field-row { display: flex; gap: var(--space-sm); }
.ed-field-row .ed-field { flex: 1; min-width: 0; }
.ed-modal textarea, .ed-modal select, .ed-modal input {
  font-family: var(--font-ui); font-size: var(--font-size-sm);
  padding: var(--space-xs) var(--space-sm);
}
.ed-modal textarea { font-family: var(--font-mono); resize: vertical; }
.ed-modal textarea:focus, .ed-modal select:focus, .ed-modal input:focus { outline: 2px solid var(--color-ai); border-color: var(--color-ai); }
#onramp-modal textarea:focus, #onramp-modal select:focus, #onramp-modal input:focus { outline-color: var(--color-link); border-color: var(--color-link); }
#onramp-modal .ed-modal-card { display: flex; flex-direction: column; overflow: hidden; }
#onramp-modal .ed-modal-body { min-height: 0; overflow-y: auto; }
#onramp-modal .ed-modal-head, #onramp-modal .ed-modal-foot { flex-shrink: 0; }
#onramp-modal .ed-modal-status.busy { color: var(--color-text-secondary); }
.ed-modal-status { font-size: var(--font-size-xs); color: var(--color-text-secondary); min-height: 1.2em; }
.ed-modal-status.err { color: var(--color-problem); }
.ed-modal-status.busy { color: var(--color-ai); }

/* Deterministic on-ramp (image-onramp.js): the page-image drop zone, the page
   strip whose order is the page order, and the page/image reconciliation line. */
.ed-field > span > .ed-btn { margin-left: var(--space-sm); padding: 0 var(--space-xs); font-weight: 400; }
.onramp-drop {
  display: flex; align-items: center; justify-content: center; gap: var(--space-sm);
  padding: var(--space-md); border: 1px dashed var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-surface-sunken); color: var(--color-text-muted); font-size: var(--font-size-sm); }
.onramp-drop-hint { color: var(--color-text-body); }
.onramp-drop.over { border-color: var(--color-link); color: var(--color-link); }
.onramp-thumbs { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.onramp-thumbs:empty { display: none; }
.onramp-thumb {
  display: flex; flex-direction: column; gap: 2px; width: 7.5em; padding: var(--space-xs);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-panel); }
.onramp-thumb img { width: 100%; height: 5em; object-fit: contain; background: var(--color-surface-sunken); border-radius: 2px; }
.onramp-thumb-page { font-size: var(--font-size-xs); font-weight: 600; color: var(--color-text-secondary); }
.onramp-thumb-name { font-size: var(--font-size-xs); color: var(--color-text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.onramp-thumb-ctl { display: flex; gap: 2px; }
.onramp-mini { flex: 1; padding: 0; min-width: 0; line-height: 1.6; }
.onramp-reconcile { font-size: var(--font-size-xs); color: var(--color-text-secondary); min-height: 1.2em; }
.onramp-reconcile.ok { color: var(--color-text-secondary); }
.onramp-reconcile.warn { color: var(--color-review); }

/* Dual view: two panes, always. Left is the text work surface (reading
   text or XML source, the view tabs switch it); right is the context panel
   (facsimile, entity index, project panels; the panel tabs switch it). */
.ed-main {
  display: grid;
  grid-template-columns: var(--ed-split, 52%) 6px minmax(0, 1fr);
  flex: 1; min-height: 0;
}/* Collapsed: the context pane folds away and the text pane takes the full
   width. The @facs click sync then has no visible target. */
.ed-main.right-collapsed { grid-template-columns: 1fr 12px; }
.ed-main.right-collapsed > #ed-pane-right { display: none; }
/* Collapsed: the splitter stays as a visible, tinted right-edge rail that both
   restores the pane (click anywhere on it) and reopens it by drag (pull left to
   size it in one gesture), so the collapse control lives on the boundary it acts
   on. The centred grip is hidden here; the chevron handle carries the cue. */
.ed-main.right-collapsed > #ed-splitter {
  background: var(--color-secondary);
  border-left: 1px solid var(--color-border);
  cursor: col-resize;
}
.ed-main.right-collapsed > #ed-splitter:hover { background: var(--color-panel); }
.ed-main.right-collapsed > #ed-splitter::before { opacity: 0; }
.ed-main.right-collapsed > #ed-splitter::after { content: "\2039"; background: var(--color-secondary); }
/* min-height: 0 on the pane AND its body breaks the min-height:auto chain, so
   tall content (the XML source gutter) scrolls INSIDE the pane instead of
   growing the pane past the viewport. */
.ed-pane { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
/* Draggable splitter between the panes: a thin rule whose 6px column widens the
   hit area, with a centred grip that signals it can be dragged. Resizable by
   pointer drag, double-click reset, or arrow keys when focused; each pane stays
   at least 320px wide (clamped in editor-app.js). */
.ed-splitter {
  background: var(--color-border); cursor: col-resize; position: relative;
  transition: background 0.12s ease;
}
.ed-splitter:hover { background: var(--color-gold); }
.ed-splitter:focus-visible { background: var(--color-gold); outline: 2px solid var(--color-gold); outline-offset: -1px; }
/* Grip: three short vertical lines centred on the rail, faint until hover, so the
   rule reads as a handle rather than a border. */
.ed-splitter::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 2px; height: 26px; border-radius: 1px;
  background: var(--color-text-secondary); opacity: 0.35;
  box-shadow: -3px 0 0 var(--color-text-secondary), 3px 0 0 var(--color-text-secondary);
  transition: opacity 0.12s ease, background 0.12s ease, box-shadow 0.12s ease;
}
.ed-splitter:hover::before {
  background: var(--color-gold); opacity: 0.9;
  box-shadow: -3px 0 0 var(--color-gold), 3px 0 0 var(--color-gold);
}
/* The separator remains one interactive control. Its generated chevron extends
   the hit area to the left without nesting a second button inside the range widget. */
.ed-splitter::after {
  content: "\203A";
  position: absolute; top: 50%; right: 100%; transform: translateY(-50%);
  width: 16px; height: 48px; padding: 0; cursor: pointer; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: var(--color-panel); color: var(--color-text-secondary);
  font-size: var(--font-size-sm); line-height: 1;
  transition: border-color 0.12s ease, color 0.12s ease, background 0.12s ease;
}
.ed-splitter:hover::after { border-color: var(--color-gold); color: var(--color-text); }
/* Below 900px the panes stack vertically (a splitter makes no sense there): the
   text pane on top, the context pane beneath it. */
@media (max-width: 900px) {
  .ed-main { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }
  .ed-main > #ed-splitter { display: none; }
  .ed-main.right-collapsed { grid-template-rows: 1fr; }
  #ed-pane-right { border-top: 1px solid var(--color-border); }
}
.ed-pane-head {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md); background: var(--color-secondary);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--font-size-sm); font-weight: 600; color: var(--color-text);
}
.ed-pane-head > .ed-tabs { flex: 0 0 auto; }
.ed-pane-head-right {
  display: inline-flex; flex: 1 1 28rem; min-width: min(100%, 28rem);
  align-items: center; justify-content: flex-end; flex-wrap: wrap;
  gap: var(--space-xs) var(--space-sm);
}
.ed-pane-head-right > * { flex: 0 0 auto; }

/* View / panel tabs in the pane heads: a small segmented switcher.
   The active tab reads as the pane's title; exactly one is active per pane. */
.ed-tabs { display: inline-flex; align-items: center; gap: var(--space-xs); }
.ed-tab {
  font-family: var(--font-ui); font-size: var(--font-size-sm); font-weight: 500;
  cursor: pointer; padding: 2px var(--space-sm); border-radius: var(--radius-sm);
  border: 1px solid transparent; background: none; color: var(--color-text-secondary);
}
.ed-tab:hover { color: var(--color-text); border-color: var(--color-border); }
.ed-tab.active {
  background: var(--color-panel); border-color: var(--color-border);
  color: var(--color-text); font-weight: 600;
}
.ed-tab:disabled { opacity: .5; cursor: not-allowed; }
.ed-tab:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }

/* Context panels in the right pane: exactly the active one is shown. */
.ed-panel { height: 100%; min-height: 0; }
.ed-pane-body { flex: 1; min-height: 0; overflow: auto; padding: var(--space-md); }
/* XML source view fills the pane exactly: the editor frame brings its own
   spacing, and height:100% plus the body padding would otherwise overflow. */
.ed-pane-body.src { padding: 0; }
.ed-pane-body.src :is(.ed-src-root, .ed-meta-root) {
  box-sizing: border-box; padding: var(--space-sm) var(--space-md);
}

/* Page turning lives in the reading-pane header, where one expects it. */
.ed-pager {
  display: inline-flex; flex: 0 0 auto; align-items: center;
  gap: var(--space-xs); white-space: nowrap;
}
.ed-pager-btn { font-size: var(--font-size-sm); line-height: 1; padding: 2px 10px; }
.ed-ann-wrap { position: relative; display: inline-flex; }
.ed-ann-summary { position: relative; font-size: var(--font-size-xs); padding: 2px var(--space-sm); }
.ed-ann-summary.current { border-color: var(--color-blue); color: var(--color-blue); }
.ed-ann-summary.current::before { content: ""; display: inline-block; width: .55em; height: .55em;
  margin-right: var(--space-xs); border-radius: 50%; background: var(--color-blue); }
.ed-ann-popover:not([hidden]) {
  position: fixed; z-index: 45; box-sizing: border-box;
  width: min(360px, calc(100vw - 16px)); max-height: 320px; overflow: auto;
  display: flex; flex-direction: column; gap: var(--space-sm);
  padding: var(--space-sm); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); background: var(--color-panel); box-shadow: var(--shadow-pop);
}
.ed-ann-filters { display: inline-flex; align-self: flex-start; gap: var(--space-xs); }
.ed-ann-filter {
  padding: 2px var(--space-sm); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); background: var(--color-panel); color: var(--color-text-secondary);
  cursor: pointer; font-family: var(--font-ui); font-size: var(--font-size-xs);
}
.ed-ann-filter:hover { border-color: var(--color-blue); color: var(--color-text); }
.ed-ann-filter[aria-pressed="true"] {
  border-color: var(--color-blue); background: var(--color-blue-light); color: var(--color-text);
  font-weight: 600;
}
.ed-ann-filter:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }
.ed-ann-caption { font-size: var(--font-size-xs); font-weight: 500; color: var(--color-text-secondary);
  white-space: normal; }
.ed-ann-pages { display: grid; grid-template-columns: repeat(auto-fill, minmax(3.2em, 1fr)); gap: var(--space-xs); }
.ed-ann-page {
  padding: 2px var(--space-xs); border: 1px solid var(--color-blue); border-radius: var(--radius-sm);
  background: var(--color-blue-light); color: var(--color-text); cursor: pointer;
  font-family: var(--font-mono); font-size: var(--font-size-xs); font-variant-numeric: tabular-nums;
}
.ed-ann-page:hover, .ed-ann-page.active { border-color: var(--color-gold); background: var(--color-gold-light); }
.ed-ann-page:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }
.ed-ann-empty { grid-column: 1 / -1; font-size: var(--font-size-xs); color: var(--color-text-secondary); }

/* View controls at the right edge of the text-pane header: text zoom and the
   context-pane collapse toggle (the collapse button sits last, the edge). */
.ed-view-controls { display: inline-flex; align-items: center; gap: var(--space-xs); }
.ed-icon-btn { font-family: var(--font-mono); font-size: var(--font-size-xs); line-height: 1; padding: 3px 6px; }
.ed-zoom-level { min-width: 3.4em; text-align: center; }

/* Empty editor state: no separate welcome screen. The editor opens on its
   empty two-pane layout; the reading pane shows a lean prompt to load a
   document or project, with the recent files for re-entry. */
.ed-empty-start { max-width: 720px; margin: 0 auto; padding: var(--space-xl) var(--space-md); }
.ed-empty-lead { font-family: var(--font-ui); font-size: var(--font-size-sm);
  color: var(--color-text-secondary); margin: 0 0 var(--space-xs); }
.ed-empty-hint { font-family: var(--font-ui); font-size: var(--font-size-sm);
  color: var(--color-text-muted); margin: 0; }
.ed-recent { margin-top: var(--space-xl); }
.ed-recent h2 { font-family: var(--font-ui); font-size: var(--font-size-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: .08em; color: var(--color-text-muted);
  margin: 0 0 var(--space-sm); }

/* Recent files (persisted File System Access handles). */
.ed-recent-list { display: flex; flex-direction: column; gap: 2px; max-width: 620px; }
.ed-recent-row {
  display: flex; align-items: baseline; gap: var(--space-sm); text-align: left;
  font-family: var(--font-ui); font-size: var(--font-size-sm); cursor: pointer;
  padding: var(--space-xs) var(--space-sm); border-radius: var(--radius-sm);
  border: 1px solid transparent; background: none; color: var(--color-text);
}
.ed-recent-row:hover { background: var(--color-gold-light); }
.ed-recent-name { font-family: var(--font-mono); }
.ed-recent-when { font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ed-recent-forget { margin-left: auto; border: none; background: none; cursor: pointer;
  font-size: var(--font-size-xs); color: var(--color-text-muted); padding: 0 var(--space-xs); }
.ed-recent-forget:hover { color: var(--color-problem); }

/* Full-page drop indicator while a file drag is over the window. */
.ed-drop {
  position: fixed; inset: 0; z-index: 80; display: flex; align-items: center; justify-content: center;
  background: var(--scrim-drop); pointer-events: none;
}
.ed-drop span {
  font-family: var(--font-ui); font-size: var(--font-size-lg); font-weight: 600;
  color: var(--color-text); background: var(--color-panel);
  border: 2px dashed var(--color-gold); border-radius: var(--radius-sm);
  padding: var(--space-md) var(--space-xl);
}

/* Loading overlay for large documents: an opaque surface with a spinner while
   the synchronous parse runs (shown only above BIG_DOC_CHARS). */
.ed-loading {
  position: fixed; inset: 0; z-index: 90;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-md);
  background: var(--color-surface);
  font-family: var(--font-ui); font-size: var(--font-size-sm); color: var(--color-text-secondary);
}
.ed-spinner {
  width: 32px; height: 32px; border-radius: var(--radius-pill);
  border: 3px solid var(--color-border); border-top-color: var(--color-blue);
  animation: ed-spin .8s linear infinite;
}
@keyframes ed-spin { to { transform: rotate(360deg); } }
/* Respect reduced-motion: slow the spin rather than freeze it (it still signals work). */
@media (prefers-reduced-motion: reduce) { .ed-spinner { animation-duration: 2s; } }

/* Reading text (diplomatic). position:relative anchors the selection-annotate
   popover inside the scrolling pane. */
.ed-reading { --ed-read-size: calc(1.05rem * var(--ed-zoom, 1));
  font-family: var(--font-serif); font-size: var(--ed-read-size); line-height: 1.9; color: var(--color-text);
  background: var(--color-surface); position: relative; }
.ed-reading:focus-visible { outline: 2px solid var(--color-gold); outline-offset: -2px; }
/* Line rows carry an IDE-style gutter: the document's own line label (@n) in a
   fixed, right-aligned mono channel set off by a continuous rule, then the text.
   The label is the edition's @n. When a folio numbers no line at all, the gutter
   falls back to a display-only 1-based position (.pos), rendered faint and italic
   so it reads as a navigation aid, not encoded data, and is never serialised. A
   folio that does carry @n keeps it and leaves unnumbered lines blank, so a real
   label never sits beside a synthetic one. The rule runs unbroken either way. */
.ed-line { display: flex; align-items: stretch; }
.ed-line.linked { background: var(--color-gold-light); border-radius: var(--radius-sm); }
.ed-line-n { flex: 0 0 3.4em; text-align: right;
  padding: 2px var(--space-sm) 2px 0; margin-right: var(--space-sm);
  border-right: 1px solid var(--color-border);
  font-family: var(--font-mono); font-size: var(--font-size-xs);
  line-height: calc(1.9 * var(--ed-read-size)); color: var(--color-text-muted);
  user-select: none; white-space: nowrap; }
.ed-line-n.pos { font-style: italic; color: var(--color-text-secondary); }
.ed-line-body { flex: 1 1 auto; min-width: 0; padding: 2px 0; }
/* Continuous view: a labelled rule marks each page break; clicking it makes the
   facsimile track that page. The first separator needs no top gap. */
.ed-page-sep { display: flex; align-items: center; gap: var(--space-sm);
  margin: var(--space-lg) 0 var(--space-sm); cursor: pointer;
  font-family: var(--font-ui); font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ed-page-sep::before, .ed-page-sep::after { content: ""; flex: 1; height: 1px; background: var(--color-border); }
.ed-page-sep:hover { color: var(--color-text-secondary); }
.ed-page-sep:hover::before, .ed-page-sep:hover::after { background: var(--color-gold); }
.ed-page-sep-label { white-space: nowrap; }
.ed-reading.continuous > .ed-page-sep:first-child { margin-top: 0; }
/* Reading-text interaction: two modes, two gestures, two colour families.
     - READ / ANNOTATE (default): hover gives a faint blue affordance (the text is
       live and selectable); selecting it tints in the strong blue annotation
       family and opens the annotate popover. Blue is the reading-text interaction
       family throughout (this hover and selection, mentions, semantic wraps).
     - EDIT (double-click): the cell becomes the gold-outlined .ed-w-input field
       below. Gold is the action/edit family, so blue reads "annotate", gold "write".
   The gesture pair is named in each cell's tooltip (critTitle), since help is
   tooltip-only. A line-level cell is one span, so a whole line tints uniformly. */
.ed-w { cursor: text; padding: 0 1px; border-radius: 2px; }
.ed-w:hover { background: var(--color-blue-light); }
.ed-w::selection { background: var(--color-selection-read); }
.ed-w::-moz-selection { background: var(--color-selection-read); }
/* Persistent annotate highlight (CSS Custom Highlight API, set in annotation-ui).
   The native selection stops painting once the popover takes focus, so the marked
   range is repainted here, focus-independent: a blue fill plus a solid blue
   underline mark the exact region while the popover is open, cleared on close or
   commit. The fill matches the live selection so the marking does not jump. */
::highlight(ed-annotate) {
  background-color: var(--color-selection-read);
  text-decoration-line: underline;
  text-decoration-color: var(--color-blue);
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
}
::highlight(ed-collected) {
  background-color: var(--color-gold-light);
  text-decoration-line: underline;
  text-decoration-color: var(--color-gold);
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
}
:is(.ed-w, .ed-legend-chip).has-note { box-shadow: inset 0 -2px 0 var(--color-review); }
.ed-w.ed-note-target:focus { outline: 2px solid var(--color-gold); outline-offset: 2px; }
.ed-w.linked { background: var(--color-gold-light); }

/* Textual-critical markup: editorial (not AI), so it uses the human
   editorial colour families, never the violet AI family. The :is() selector
   covers the reading text and the legend chips with one rule, so the legend
   always shows exactly the code it names. */
:is(.ed-w, .ed-legend-chip).crit-unclear { text-decoration: underline dotted var(--color-review); text-underline-offset: 3px; }
:is(.ed-w, .ed-legend-chip).crit-del { text-decoration: line-through; text-decoration-color: var(--color-problem); color: var(--color-problem); }
:is(.ed-w, .ed-legend-chip).crit-add { text-decoration: underline; text-decoration-color: var(--color-blue); color: var(--color-blue); }
:is(.ed-w, .ed-legend-chip).crit-gap { font-family: var(--font-mono); font-size: var(--font-size-xs); color: var(--color-text-secondary);
  background: var(--color-secondary); border: 1px dashed var(--color-border); border-radius: var(--radius-sm);
  padding: 0 4px; cursor: pointer; }

/* The inline textual-critical chooser shown in place of a clicked cell. */
.ed-crit-pick { display: inline-flex; gap: var(--space-xs); align-items: center; vertical-align: baseline; }
.ed-crit-btn { font-family: var(--font-ui); font-size: var(--font-size-xs); line-height: 1.4;
  padding: 1px 6px; border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-panel); color: var(--color-text); cursor: pointer; }
.ed-crit-btn:hover { border-color: var(--color-review); color: var(--color-review); background: var(--color-review-tint); }
.ed-w-input { font-family: var(--font-serif); font-size: 1.05rem; line-height: 1.9;
  color: var(--color-text); background: var(--color-panel);
  border: none; outline: 2px solid var(--color-gold); border-radius: 2px;
  padding: 0 1px; margin: 0; min-width: 2ch; }
/* Line/paragraph cell edit: a wrapping textarea grown to its content, so a whole
   paragraph stays visible at once instead of scrolling past a single-line field. */
.ed-line-input { display: block; width: 100%; box-sizing: border-box;
  resize: vertical; white-space: pre-wrap; overflow-wrap: break-word;
  overflow: hidden; padding: 0 var(--space-xs); }

/* Two-field dual-reading edit: the diplomatic core and the normalized
   reading side by side, quiet labels, inputs sized like .ed-w-input, inline so
   the line layout survives. */
.ed-readings-form { display: inline-flex; gap: var(--space-sm); align-items: baseline; vertical-align: baseline; }
.ed-readings-field { display: inline-flex; gap: var(--space-xs); align-items: baseline; }
.ed-readings-label { font-family: var(--font-ui); font-size: var(--font-size-xs);
  color: var(--color-text-secondary); user-select: none; }

/* Facsimile (OpenSeadragon viewer with zone overlays) */
.ed-osd { position: relative; width: 100%; min-height: 60vh; height: 100%;
  background: var(--color-secondary); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); overflow: hidden; }
/* Per-zone overlay: hittable but invisible by default (transparent border), so
   the layout does not clutter the image. The reading-text hover reveals the
   linked zone; the panel's "Zones" toggle (.ed-zones-shown) shows them all. */
.ed-osd-zone { position: absolute; border: 1px solid transparent;
  background: transparent; cursor: pointer; border-radius: 2px; }
.ed-zones-shown .ed-osd-zone { border-color: var(--color-blue); }
.ed-osd-zone:hover, .ed-osd-zone.linked {
  border-color: var(--color-gold-hover); background: var(--color-gold-light);
  opacity: .35; box-shadow: 0 0 0 1px var(--color-gold-hover); }
/* Zones show/hide control, top-right of the facsimile panel. */
.ed-zones-toggle { position: absolute; top: var(--space-sm); right: var(--space-sm); z-index: 30;
  font-family: var(--font-ui); font-size: var(--font-size-xs); cursor: pointer;
  padding: 2px var(--space-sm); border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-panel); color: var(--color-text-secondary); }
.ed-zones-toggle:hover { border-color: var(--color-gold); }
.ed-zones-toggle.active { border-color: var(--color-blue); color: var(--color-blue); }
.ed-zones-toggle:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }

/* Validation / info side pane */
.ed-section { margin-bottom: var(--space-md); }
.ed-section h4 { margin: 0 0 var(--space-xs); font-size: var(--font-size-sm); font-weight: 600; color: var(--color-text); }
.ed-kv { display: flex; justify-content: space-between; font-size: var(--font-size-sm);
  padding: 2px 0; color: var(--color-text-secondary); }
.ed-kv b { color: var(--color-text); font-family: var(--font-mono); }
#ed-panel-source { min-width: 0; overflow-x: hidden; }
#ed-panel-source .ed-section { min-width: 0; }
#ed-panel-source .ed-kv {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(7rem, auto);
  gap: var(--space-sm);
  align-items: baseline;
}
#ed-panel-source .ed-kv b,
#ed-panel-source .ed-kv-value { min-width: 0; overflow-wrap: anywhere; }
#ed-panel-source .ed-kv-value { text-align: right; }
.ed-source-capabilities { display: flex; flex-wrap: wrap; gap: var(--space-xs); min-width: 0; }
#ed-panel-source .ed-val-chip { cursor: default; }
.ed-val-row { display: flex; gap: var(--space-xs); align-items: baseline; font-size: var(--font-size-sm);
  padding: 3px var(--space-xs); border-radius: var(--radius-sm); margin-bottom: 2px; }
.ed-val-ok { background: var(--color-confident-tint); color: var(--color-confident); }
.ed-val-warn { background: var(--color-review-tint); color: var(--color-review); }
.ed-val-info { background: var(--color-secondary); color: var(--color-text-secondary); }
.ed-val-err { background: var(--color-problem-tint); color: var(--color-problem); }
.ed-val-icon { font-family: var(--font-mono); }

.ed-empty { color: var(--color-text-secondary); font-size: var(--font-size-sm); text-align: center; padding: var(--space-xl); }

/* Entity index panel (a right-pane context panel);
   inputs focus gold here (violet is AI-only). */
#ed-panel-index input:focus, #ed-panel-index select:focus { outline: 2px solid var(--color-gold); border-color: var(--color-gold); }
.ed-idx-filter {
  display: block; box-sizing: border-box; width: 100%;
  margin: 0 0 var(--space-sm);
  font-family: var(--font-ui); font-size: var(--font-size-sm);
  padding: var(--space-xs) var(--space-sm);
}
.ed-idx-occ { font-family: var(--font-mono); font-size: var(--font-size-xs); color: var(--color-text-muted); }

/* "Needs work" segmented filter: restrict the index to the entries still missing
   an authority id or a mention. Single-select; the active button reads as pressed. */
.ed-idx-workfilter { display: flex; gap: 2px; margin: 0 0 var(--space-sm); }
.ed-idx-wfbtn {
  font-family: var(--font-ui); font-size: var(--font-size-xs); cursor: pointer;
  padding: 1px var(--space-sm); border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-panel); color: var(--color-text-secondary);
}
.ed-idx-wfbtn:hover { border-color: var(--color-gold); color: var(--color-text); }
.ed-idx-wfbtn:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }
.ed-idx-wfbtn[aria-pressed="true"] {
  border-color: var(--color-gold); color: var(--color-text);
  background: var(--color-gold-light); font-weight: 600;
}

/* Entity index list (persons / places / organisations / works / events),
   rendered by index-panel.js inside the index panel. */
.ed-idx { display: flex; flex-direction: column; gap: var(--space-md); }
.ed-idx-section { display: flex; flex-direction: column; gap: var(--space-xs); }
/* Section heading is a disclosure toggle: a chevron driven by aria-expanded, the
   label, then the count (refreshed to "shown / total" while filtering). */
.ed-idx-heading {
  display: flex; align-items: center; gap: var(--space-xs); width: 100%;
  margin: 0; padding: 2px 0; text-align: left; cursor: pointer;
  font-family: var(--font-ui); font-size: var(--font-size-sm); font-weight: 600; color: var(--color-text);
  background: none; border: none;
}
.ed-idx-heading:hover { color: var(--color-gold-hover); }
.ed-idx-heading:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }
.ed-idx-heading::before { content: "\25B8"; font-size: .85em; color: var(--color-text-muted); }
.ed-idx-heading[aria-expanded="true"]::before { content: "\25BE"; }
.ed-idx-heading-label { flex: 1; }
.ed-idx-count { font-family: var(--font-mono); font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ed-idx-section-body { display: flex; flex-direction: column; gap: var(--space-xs); }
.ed-idx-list { display: flex; flex-direction: column; gap: 2px; }
.ed-idx-empty { font-size: var(--font-size-xs); color: var(--color-text-muted); padding: 2px 0; }
/* One honest empty state for a document with no entities of any type. */
.ed-idx-allempty { font-size: var(--font-size-xs); color: var(--color-text-secondary);
  padding: var(--space-xs) 0; line-height: 1.5; }
/* Editorial-gap flags (review/amber family, never violet): a quiet tag for an
   entry with no authority id, and a tint on the zero mention-count badge. */
.ed-idx-flag { font-family: var(--font-ui); font-size: var(--font-size-xs); line-height: 1.2;
  padding: 0 4px; border-radius: var(--radius-sm); color: var(--color-review);
  background: color-mix(in srgb, var(--color-review) 12%, transparent); }
.ed-idx-occ-zero { color: var(--color-review); }
/* Filter match highlight (gold search family) and the "N of M shown" line. */
.ed-idx-hit { background: var(--color-gold-light); color: inherit; border-radius: 2px; }
.ed-idx-filter-count { display: block; font-family: var(--font-ui); font-size: var(--font-size-xs);
  color: var(--color-text-muted); padding: 2px 0; }
.ed-idx-row {
  display: flex; flex-direction: column; align-items: stretch; gap: 2px;
  padding: 2px var(--space-xs); border-radius: var(--radius-sm);
}
.ed-idx-rowmain { display: flex; align-items: center; gap: var(--space-xs); }
.ed-idx-row:hover { background: var(--color-blue-light); }
.ed-idx-row-active { background: var(--color-gold-light); }
/* AI-proposed, unverified entity (violet family, per design.md) */
.ed-idx-row-ai { background: var(--color-ai-tint); box-shadow: inset 2px 0 0 var(--color-ai); }
.ed-idx-row-ai .ed-idx-id { color: var(--color-ai); }
.ed-idx-row-ai-origin { border-left: 2px solid var(--color-ai); }
.ed-idx-origin { color: var(--color-ai); font-size: 0.8em; }
.ed-idx-confirm { border-color: var(--color-ai); color: var(--color-ai); }
.ed-idx-confirm:hover { background: var(--color-ai); color: var(--color-panel); border-color: var(--color-ai); }
.ed-idx-rowbody {
  flex: 1; min-width: 0; display: flex; align-items: baseline; gap: var(--space-sm);
  text-align: left; cursor: pointer; border: none; background: none;
  font-family: var(--font-ui); font-size: var(--font-size-sm); color: var(--color-text);
  padding: 2px 0;
}
.ed-idx-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ed-idx-id { font-family: var(--font-mono); font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ed-idx-rename {
  flex: 1; min-width: 0; font-family: var(--font-ui); font-size: var(--font-size-sm);
  color: var(--color-text); background: var(--color-panel);
  border: none; outline: 2px solid var(--color-gold); border-radius: 2px; padding: 0 2px;
}
/* Row actions rest quiet so the panel scans as an overview, and come forward on
   hover or keyboard focus (focus-within keeps them reachable by tab). */
.ed-idx-actions { display: flex; gap: 2px; flex-shrink: 0; opacity: .4; transition: opacity .12s ease; }
.ed-idx-row:hover .ed-idx-actions,
.ed-idx-row:focus-within .ed-idx-actions { opacity: 1; }
.ed-idx-btn {
  font-family: var(--font-ui); font-size: var(--font-size-xs); cursor: pointer;
  padding: 1px var(--space-xs); border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-panel); color: var(--color-text-secondary);
}
.ed-idx-btn:hover { border-color: var(--color-gold); color: var(--color-text); }
.ed-idx-delete:hover { border-color: var(--color-problem); color: var(--color-problem); }
/* Armed two-step delete (entity still has mentions): problem family, not hover-only. */
.ed-idx-delete-armed, .ed-idx-delete-armed:hover {
  border-color: var(--color-problem); color: var(--color-problem);
  background: var(--color-problem-tint);
}
.ed-idx-addrow { display: flex; gap: var(--space-xs); align-items: center; }
.ed-idx-add-input {
  flex: 1; min-width: 0; font-family: var(--font-ui); font-size: var(--font-size-sm);
  padding: 2px var(--space-xs);
}
.ed-idx-add-input:focus { outline: none; border-color: var(--color-gold); }

/* Authority identifiers (idno) under each entity row */
.ed-idx-auth { display: flex; flex-direction: column; gap: 2px; padding: 0 0 2px var(--space-md); }
.ed-idx-authlist { display: flex; flex-wrap: wrap; gap: 2px; }
.ed-idx-authid {
  display: inline-flex; align-items: center; gap: var(--space-xs);
  font-family: var(--font-mono); font-size: var(--font-size-xs);
  color: var(--color-text-secondary); background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: 0 var(--space-xs);
}
.ed-idx-authtype { color: var(--color-text-muted); }
/* The id value verifies against the register record: a link in the accessible
   orange link family, underlined on hover; keyboard focus takes the shared gold
   outline above (navigation, never the gold action fill). */
.ed-idx-authlink { color: var(--color-link); text-decoration: none; cursor: pointer; }
.ed-idx-authlink:hover { text-decoration: underline; }
.ed-idx-authdel {
  border: none; background: none; cursor: pointer;
  color: var(--color-text-muted); padding: 0 2px; font-size: var(--font-size-xs);
}
.ed-idx-authdel:hover { color: var(--color-problem); }
.ed-idx-authadd { display: flex; gap: 2px; align-items: center; }
.ed-idx-authtypesel {
  font-family: var(--font-ui); font-size: var(--font-size-xs);
  padding: 1px 2px;
}
.ed-idx-authinput {
  flex: 1; min-width: 0; font-family: var(--font-ui); font-size: var(--font-size-xs);
  padding: 1px var(--space-xs);
}
.ed-idx-authinput:focus { outline: none; border-color: var(--color-gold); }

/* Live authority lookup: results popover under the id form */
.ed-idx-authadd { position: relative; flex-wrap: wrap; }
.ed-idx-lookupresults {
  width: 100%; margin-top: 2px; display: flex; flex-direction: column; gap: 1px;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-panel); max-height: 180px; overflow: auto;
}
.ed-idx-lookupmsg {
  font-size: var(--font-size-xs); color: var(--color-text-muted); padding: 2px var(--space-xs);
}
.ed-idx-lookuphit {
  display: flex; align-items: baseline; gap: var(--space-xs); flex-wrap: wrap;
  text-align: left; cursor: pointer; border: none; background: none;
  font-family: var(--font-ui); font-size: var(--font-size-xs); color: var(--color-text);
  padding: 2px var(--space-xs);
}
.ed-idx-lookuphit:hover { background: var(--color-blue-light); }
.ed-idx-lookuplabel { color: var(--color-text); font-weight: 600; }
.ed-idx-lookupid { font-family: var(--font-mono); color: var(--color-text-muted); }
.ed-idx-lookupdesc { color: var(--color-text-muted); width: 100%; }

/* Annotation visibility layer: every linked mention is visible in the
   reading text, coloured by entity type (the annotation token family). The
   generic .mention rule stays as the fallback for a mention whose target id has
   no index entry (dangling ref). A mention of an AI-proposed, unconfirmed entity
   uses the violet AI family so machine output stays separable (design.md). */
:is(.ed-w, .ed-legend-chip).mention { background: var(--color-blue-light); box-shadow: inset 0 -2px 0 var(--color-blue); }
:is(.ed-w, .ed-legend-chip).mention-pers { background: var(--color-persName-bg); box-shadow: inset 0 -2px 0 var(--color-persName); }
:is(.ed-w, .ed-legend-chip).mention-plc { background: var(--color-placeName-bg); box-shadow: inset 0 -2px 0 var(--color-placeName); }
:is(.ed-w, .ed-legend-chip).mention-org { background: var(--color-orgName-bg); box-shadow: inset 0 -2px 0 var(--color-orgName); }
:is(.ed-w, .ed-legend-chip).mention-wrk { background: var(--color-workName-bg); box-shadow: inset 0 -2px 0 var(--color-workName); }
:is(.ed-w, .ed-legend-chip).mention-evt { background: var(--color-eventName-bg); box-shadow: inset 0 -2px 0 var(--color-eventName); }
/* AI-proposed construct: violet family plus a dashed outline as the second,
   non-colour channel, so machine origin never hangs on hue alone (design.md
   triple-coding rule; the tooltip is the third channel). mention-ai marks an
   AI-proposed entity mention; ed-w-ai is the general case (any proposed construct,
   markup or criticism, carrying the @resp responsibility id) so all AI output reads
   as one family. */
.ed-review-dialog { color: var(--color-text); background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-lg); max-width: min(36rem, 90vw); }
.ed-review-dialog form, .ed-review-dialog label { display: flex; flex-direction: column; gap: var(--space-sm); }
.ed-review-dialog input, .ed-review-dialog textarea { font: inherit; padding: var(--space-sm); color: var(--color-text); background: var(--color-surface); border: 1px solid var(--color-border); }
.ed-review-dialog input:focus, .ed-review-dialog textarea:focus { outline: 2px solid var(--color-link); }
.ed-review-hint { color: var(--color-text-secondary); font-size: var(--font-size-sm); }
.ed-review-actions { display: flex; justify-content: flex-end; gap: var(--space-sm); }
.ed-w.ed-w-ai-origin { border-bottom: 1px solid var(--color-ai); }
:is(.ed-w, .ed-legend-chip).mention-ai, .ed-w.ed-w-ai { background: var(--color-ai-tint); box-shadow: inset 0 -2px 0 var(--color-ai);
  outline: 1px dashed var(--color-ai); outline-offset: -1px; }

/* Semantic-wrap visibility: text inside a scholarly inline element (date, ref,
   salute, signed, ...) that is neither a linked mention nor critical markup.
   A subtle dotted underline in the cool blue family (NOT the violet AI hue, NOT
   the mention background), with the element and its attributes in the tooltip.
   Underline only, so it adds no bold and changes no text metrics. */
.ed-w.ed-w-sem { text-decoration: underline dotted var(--color-blue); text-decoration-thickness: 1px; text-underline-offset: 3px; }
/* Overlapping / nested annotations (cell.layers >= 2, e.g. a persName inside a
   seg): two stacked underline bands in the blue interaction family say "more than
   one annotation here". The exact stack and its per-layer actions live in the
   inspector (a click opens it). The compound selector outweighs the single
   .mention band so the stack shows through; an entity background, if any, stays. */
.ed-w.ed-w-stacked { box-shadow: inset 0 -2px 0 var(--color-blue), inset 0 -5px 0 var(--color-blue); padding-bottom: 3px; }

/* Temporary "show this entity's mentions" highlight (index-panel selection).
   Its own class, so clearing it never strips the permanent visibility layer.
   An outline (not an underline), so the selection state and the annotation
   codes use different positions and can never be confused. */
.ed-w.mention-hit { background: var(--color-gold-light); outline: 1px solid var(--color-gold); outline-offset: 0; }

/* Note marker, triple-coded: colour (review family) + icon (degree sign
   after the word) + position (the existing underline via .has-note). */
:is(.ed-w, .ed-legend-chip).has-note::after {
  content: "\00B0";
  color: var(--color-review);
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: var(--font-size-xs);
  vertical-align: super;
}

/* Legend strip under the reading-pane header: names every visual code
   present in the current document. Hosted on the reading surface (not the
   secondary tone), so the chips' background tints stay clearly visible. */
.ed-legend {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-sm);
  padding: var(--space-xs) var(--space-md);
  background: var(--color-surface); border-bottom: 1px solid var(--color-border);
  font-size: var(--font-size-xs); color: var(--color-text-secondary);
}
.ed-legend-chips { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-sm); }
.ed-legend-title { text-transform: uppercase; letter-spacing: .08em; color: var(--color-text-secondary); }
.ed-legend-chip { font-family: var(--font-serif); padding: 0 3px; border-radius: 2px; white-space: nowrap; }
/* Chips are labels, not affordances: neutralise interactive cursors inherited
   from the shared code rules (e.g. the gap marker's pointer). */
.ed-legend .ed-legend-chip { cursor: default; }

/* Action buttons shared by the popovers (annotate, annotation editor) and the
   critical chooser; descended from the proven .ed-crit-btn pattern. */
.ed-act-btn { font-family: var(--font-ui); font-size: var(--font-size-xs); line-height: 1.4;
  padding: 1px 6px; border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-panel); color: var(--color-text); cursor: pointer; }
/* Hover/focus keep the text at full contrast (--color-text on gold-light passes
   WCAG AA at this size; the gold accent carries the state via the border). */
.ed-act-btn:hover, .ed-act-btn:focus-visible { border-color: var(--color-gold); color: var(--color-text); background: var(--color-gold-light); }
.ed-act-group { width: 100%; font-family: var(--font-ui); font-size: var(--font-size-xs);
  color: var(--color-text-muted); text-transform: uppercase; letter-spacing: .08em; }
/* Annotate popover, TEI-role colour logic: its actions create TEI elements, so
   they carry the blue family (AI proposals keep their violet, untouched); an
   attribute field for a markup wrap's @attr carries the gold/attribute accent. The
   group headings stay neutral grey (structure and navigation, not an action). The
   gold default of .ed-act-btn is left for the attribute-side surfaces. */
.ed-annotate-pop .ed-act-btn:not(.ed-btn-ai) { border-color: var(--color-blue); color: var(--color-blue); }
.ed-annotate-pop .ed-act-btn:not(.ed-btn-ai):hover,
.ed-annotate-pop .ed-act-btn:not(.ed-btn-ai):focus-visible {
  background: var(--color-blue-light); border-color: var(--color-blue); color: var(--color-blue); }
.ed-annotate-pop .ed-attr-input { border-color: var(--color-gold); }
.ed-annotate-pop .ed-attr-input:focus { outline: 2px solid var(--color-gold); border-color: var(--color-gold); }
/* Overlap inspector: the stack of annotations on one text, innermost first. Each
   row reads by colour family (entity and markup are TEI elements -> blue,
   criticism -> review), names the element, and carries the per-layer actions.
   Reuses the popover surface (.ed-sel-pop). */
.ed-layers-row { display: flex; align-items: baseline; gap: var(--space-xs); padding: 2px 0; }
.ed-layer-label { font-family: var(--font-mono); font-size: var(--font-size-xs); flex: 1 1 auto; min-width: 0; }
.ed-layer-mention .ed-layer-label, .ed-layer-markup .ed-layer-label { color: var(--color-blue); }
.ed-layer-critical .ed-layer-label { color: var(--color-review); }
.ed-act-empty { font-family: var(--font-ui); font-size: var(--font-size-xs); color: var(--color-text-muted); }

/* Selection-annotate popover: select words in a line, annotate exactly
   that text. Anchored inside the reading pane, panel surface, token-only. */
.ed-sel-pop {
  position: absolute; z-index: 20; max-width: 420px;
  display: flex; flex-direction: column; gap: var(--space-xs);
  padding: var(--space-sm); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); background: var(--color-panel);
  box-shadow: var(--shadow-pop);
}
/* Title row: the selection label and a quiet top-right close button. */
.ed-sel-pop-titlerow { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); }
.ed-sel-pop-title { font-family: var(--font-ui); font-size: var(--font-size-xs);
  font-weight: 600; color: var(--color-text); }
.ed-sel-pop-close { font-family: var(--font-ui); font-size: var(--font-size-sm); line-height: 1;
  border: none; background: none; color: var(--color-text-muted); cursor: pointer;
  padding: 0 var(--space-xs); border-radius: var(--radius-sm); }
.ed-sel-pop-close:hover { color: var(--color-text); }
.ed-sel-pop-close:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }
.ed-sel-pop-row { display: flex; flex-wrap: wrap; gap: var(--space-xs); align-items: center;
  max-height: 140px; overflow: auto; }
/* Disclosure header for the "link to an existing entity" section: a real toggle
   button with a chevron driven by aria-expanded. */
.ed-sel-sec-head { display: flex; align-items: center; gap: var(--space-xs); width: 100%;
  font-family: var(--font-ui); font-size: var(--font-size-xs); text-align: left;
  cursor: pointer; border: none; background: none; padding: 2px 0;
  color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: .08em; }
.ed-sel-sec-head:hover { color: var(--color-text); }
.ed-sel-sec-head:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }
.ed-sel-sec-head::before { content: "\25B8"; font-size: .9em; color: var(--color-text-muted); }
.ed-sel-sec-head[aria-expanded="true"]::before { content: "\25BE"; }
/* The disclosure body indents and quiets its provenance sub-headings so they
   read as a sub-level, not a peer of Markup/Criticism/Note. */
.ed-sel-sec-body { display: flex; flex-direction: column; gap: var(--space-xs);
  padding-left: var(--space-sm); border-left: 1px solid var(--color-border); margin-left: 2px; }
.ed-sel-sec-body .ed-sel-prov-group { text-transform: none; letter-spacing: 0; color: var(--color-text-muted); }
/* A subtle separator between the top-level groups (Entities/Markup/Criticism/Note)
   for scannability; scoped to the popover list so the shared .ed-act-group is
   untouched elsewhere. */
.ed-sel-list > .ed-act-group:not(:first-child) {
  border-top: 1px solid var(--color-border); padding-top: var(--space-xs); margin-top: var(--space-xs); }
.ed-sel-filter { font-family: var(--font-ui); font-size: var(--font-size-xs);
  padding: 2px var(--space-xs); }
.ed-sel-filter:focus { outline: none; border-color: var(--color-gold); }
/* The flat, filterable action list of the annotate popover: group headings and
   action rows stacked, scrolling inside the popover when long. */
.ed-sel-list { display: flex; flex-direction: column; gap: var(--space-xs); max-height: 320px; overflow: auto; }
/* The shared authority form (.ed-idx-auth) inside the annotation editor:
   no index-row indent, quiet separators, roomier input. */
.ed-sel-auth.ed-idx-auth {
  padding: var(--space-xs) 0; border-top: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
}
.ed-sel-auth .ed-idx-authadd { min-width: 220px; }
.ed-sel-auth .ed-idx-authinput { flex: 1; min-width: 100px; }

/* Oxygen-style right-click context menu on the reading text. */
.ed-menu {
  position: fixed; z-index: 60; min-width: 180px;
  display: flex; flex-direction: column;
  padding: var(--space-xs); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); background: var(--color-panel);
  box-shadow: var(--shadow-pop);
}
.ed-menu-item { font-family: var(--font-ui); font-size: var(--font-size-sm); text-align: left;
  cursor: pointer; border: none; background: none; color: var(--color-text);
  padding: var(--space-xs) var(--space-sm); border-radius: var(--radius-sm); }
.ed-menu-item:hover { background: var(--color-gold-light); }

/* Editable XML source view (text mode): action bar, line-number gutter, and
   a highlight overlay (a <pre> with the coloured tokens under a transparent
   textarea, kept in scroll lockstep; metrics MUST stay identical). */
.ed-src-root { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.ed-src-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-sm); padding-bottom: var(--space-sm); }
.ed-src-scope {
  flex: 0 0 auto; font-family: var(--font-mono); font-size: var(--font-size-xs);
  font-weight: 600; color: var(--color-text-secondary);
}
/* Find / replace / go-to-line bar in the XML source view: toggled with the Find
   button or Ctrl/Cmd+F, closed with Escape. Edits stage in the textarea and
   commit only on Apply, like every other source edit. */
.ed-src-find { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-xs); padding-bottom: var(--space-sm); }
.ed-src-find input { font-family: var(--font-mono); font-size: var(--font-size-xs);
  padding: 2px var(--space-xs); }
.ed-src-find input:focus { outline: 2px solid var(--color-gold); border-color: var(--color-gold); }
.ed-find-q, .ed-find-r { width: 16ch; }
.ed-find-ln { width: 5ch; text-align: right; }
.ed-src-find-count { font-family: var(--font-mono); font-size: var(--font-size-xs); color: var(--color-text-muted); min-width: 6ch; }
.ed-src-find-sep { width: 1px; height: 18px; background: var(--color-border); margin: 0 var(--space-xs); }
.ed-src-result { flex: 1 1 10ch; min-width: 6ch; font-family: var(--font-mono); font-size: var(--font-size-xs);
  min-height: 1.2em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ed-src-result.ok { color: var(--color-confident); }
.ed-src-result.err { color: var(--color-problem); }
.ed-src-validation {
  flex: 0 1 auto; font-family: var(--font-ui); font-size: var(--font-size-xs);
  color: var(--color-text-muted); padding: 1px var(--space-xs);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
}
.ed-src-completions:not([hidden]) {
  display: flex; align-items: center; gap: var(--space-xs); overflow-x: auto;
  padding: 0 0 var(--space-sm); scrollbar-width: thin;
}
.ed-src-completion-label {
  flex: 0 0 auto; font-size: var(--font-size-xs); color: var(--color-text-muted);
}
.ed-src-completion {
  flex: 0 0 auto; cursor: pointer; padding: 2px var(--space-xs);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-panel); color: var(--color-blue);
  font-family: var(--font-mono); font-size: var(--font-size-xs);
}
.ed-src-completion:hover, .ed-src-completion.active {
  border-color: var(--color-gold); background: var(--color-gold-light);
}
.ed-src-completion:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }
.ed-src-wrap { flex: 1; min-height: 0; display: flex;
  font-family: var(--font-mono); font-size: calc(var(--font-size-sm) * var(--ed-zoom, 1)); line-height: 1.5;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-panel); overflow: hidden; }
.ed-src-gutter { padding: var(--space-sm) var(--space-xs); min-width: 3.5ch; text-align: right;
  color: var(--color-text-muted); background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  overflow: hidden; white-space: pre; user-select: none; }
.ed-src-stack { position: relative; flex: 1; min-width: 0; }
.ed-src-hl, .ed-src-ta {
  position: absolute; inset: 0; margin: 0; padding: var(--space-sm);
  font: inherit; line-height: inherit; white-space: pre; tab-size: 2;
  box-sizing: border-box; border: none;
}
.ed-src-hl { pointer-events: none; overflow: hidden; color: var(--color-text); }
.ed-src-hl code { font: inherit; }
.ed-src-ta { resize: none; overflow: auto; outline: none;
  background: transparent; color: transparent; caret-color: var(--color-text); }
.ed-src-ta::selection { background: var(--color-selection); color: transparent; }
/* Error-line band: faint problem-colour tint with a left accent, behind the text
   overlay, marking the line a failed well-formedness check reported. */
.ed-src-errband {
  position: absolute; left: 0; right: 0; z-index: 0; pointer-events: none;
  background: color-mix(in srgb, var(--color-problem) 14%, transparent);
  border-left: 2px solid var(--color-problem);
}
/* Syntax palette: deterministic families only (violet stays AI-only). */
.xs-punc { color: var(--color-text-muted); }
.xs-tag { color: var(--color-blue); }
.xs-attr, .xs-val { color: var(--color-review); }
.xs-comment { color: var(--color-text-muted); font-style: italic; }
.xs-pi { color: var(--color-text-secondary); font-style: italic; }
.xs-ent { color: var(--color-gold-hover); }

/* Structured teiHeader fields. Mixed XML remains visible but routes to the raw
   Metadata view, so the form never flattens project-specific header markup. */
.ed-meta-root { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.ed-meta-form {
  flex: 1; min-height: 0; overflow: auto; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  align-content: start; gap: var(--space-sm); padding-right: var(--space-xs);
}
.ed-meta-section {
  display: flex; flex-direction: column; gap: var(--space-sm);
  padding: var(--space-sm); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); background: var(--color-panel);
}
.ed-meta-section h2 {
  margin: 0; font-family: var(--font-ui); font-size: var(--font-size-sm);
  font-weight: 600; color: var(--color-blue);
}
.ed-meta-field { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ed-meta-label { font-size: var(--font-size-xs); font-weight: 500; color: var(--color-text-secondary); }
.ed-meta-field input, .ed-meta-field textarea {
  width: 100%; box-sizing: border-box; padding: var(--space-xs);
  font-family: var(--font-ui); font-size: var(--font-size-sm); resize: vertical;
}
.ed-meta-field input:focus, .ed-meta-field textarea:focus {
  outline: 2px solid var(--color-gold); border-color: var(--color-gold);
}
.ed-meta-readonly {
  min-height: 1.5em; padding: var(--space-xs); border-left: 2px solid var(--color-review);
  background: var(--color-surface-sunken); color: var(--color-text-secondary);
  font-size: var(--font-size-sm); overflow-wrap: anywhere;
}
.ed-meta-empty { grid-column: 1 / -1; color: var(--color-text-muted); font-size: var(--font-size-sm); }

/* "Open in index": flash the row the overlay was opened on. A keyframe from
   the full gold accent fading into the steady active gold-light, so the
   flash reads even though setActive() highlights the same row simultaneously. */
@keyframes ed-idx-flash { from { background: var(--color-gold); } to { background: var(--color-gold-light); } }
.ed-idx-row-flash { animation: ed-idx-flash 1.2s ease; }

/* Footer content conventions come from .site-foot (style.css); the editor
   adds only its strip geometry and the status line. */
.ed-footer { height: var(--footer-height); padding: 0 var(--space-md); background: var(--color-panel); }
.ed-status-dot { color: var(--color-confident); }
.ed-status-dot.dirty { color: var(--color-review); }

/* Live-check status chip in the footer (triple-coded: colour + icon-bg + text);
   the detail rows live in the click popover above it. */
.ed-val-chip {
  font-family: var(--font-ui); font-size: var(--font-size-xs); cursor: pointer;
  padding: 1px var(--space-sm); border-radius: var(--radius-sm); border: 1px solid;
}
.ed-val-chip.ok { color: var(--color-text); background: var(--color-confident-tint); border-color: var(--color-confident); }
.ed-val-chip.warn { color: var(--color-text); background: var(--color-review-tint); border-color: var(--color-review); }
.ed-val-chip.err { color: var(--color-text); background: var(--color-problem-tint); border-color: var(--color-problem); }
/* Position is clamped to the viewport when opened from the validation chip. */
.ed-val-pop {
  position: fixed; z-index: 40;
  width: 340px; max-width: calc(100vw - 16px); max-height: 60vh; overflow: auto;
  padding: var(--space-md); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); background: var(--color-panel);
  box-shadow: var(--shadow-pop);
}
/* Project panel: the open project folder's file list. */
.ed-proj-headrow { display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-sm); margin-bottom: var(--space-xs); }
.ed-proj-head { font-size: var(--font-size-sm); color: var(--color-text); font-weight: 600; }
.ed-proj-scan { padding: 1px var(--space-xs); font-size: var(--font-size-xs); }
.ed-proj-vocab { font-size: var(--font-size-xs); color: var(--color-text-muted); margin-bottom: var(--space-sm); }
.ed-attr-row { display: flex; align-items: center; gap: var(--space-xs); }
/* Attributes carry the gold accent (attributes = gold), matching the gold border
   the annotate popover already gives its attribute field. The name is an
   identifier, so it stays mono, in the legible small-text gold (the bright
   --color-gold is fill/border only). */
.ed-attr-name { font-family: var(--font-mono); font-size: var(--font-size-xs); color: var(--color-gold-hover); min-width: 7ch; }
.ed-attr-input { flex: 1 1 auto; min-width: 6ch; font-family: var(--font-mono); font-size: var(--font-size-xs);
  padding: 2px 4px; border: 1px solid var(--color-gold); border-radius: var(--radius-sm); }
.ed-attr-input:focus { outline: 2px solid var(--color-gold); border-color: var(--color-gold); }
.ed-attr-key { flex: 0 1 12ch; }
.ed-attr-caption { font-size: var(--font-size-xs); color: var(--color-text-muted); max-width: 36ch; }
.ed-attr-warn { font-size: var(--font-size-xs); color: var(--color-problem); max-width: 36ch; }
.ed-proj-empty { font-size: var(--font-size-xs); color: var(--color-text-muted); }
.ed-proj-list { display: flex; flex-direction: column; gap: 2px; }
.ed-starter-help { color: var(--color-text-body); margin: 0 0 var(--space-md); line-height: 1.5; }
.ed-starter-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-sm); }
.ed-starter-fields[hidden] { display: none; }
.ed-proj-directory > summary { padding: var(--space-xs) var(--space-sm); cursor: pointer; font-weight: 600; }
.ed-proj-directory > summary:focus-visible { outline: 2px solid var(--color-link); }
.ed-proj-children { display: flex; flex-direction: column; padding-left: var(--space-md); }
.ed-proj-file {
  display: flex; align-items: center; gap: var(--space-xs);
  padding: 4px var(--space-xs); border: none; background: none; text-align: left;
  font: inherit; font-size: var(--font-size-sm); color: var(--color-text);
  border-radius: var(--radius-sm); cursor: pointer;
}
.ed-proj-file:hover { background: var(--color-blue-light); }
.ed-proj-file.active { background: var(--color-gold-light); }
.ed-proj-file:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 1px; }
.ed-proj-file-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ed-proj-file-type, .ed-proj-file-kind {
  font-family: var(--font-mono); font-size: var(--font-size-xs); color: var(--color-text-muted);
}
.ed-proj-ann {
  flex: 0 0 auto; padding: 1px var(--space-xs); border-radius: var(--radius-sm);
  font-family: var(--font-mono); font-size: var(--font-size-xs); white-space: nowrap;
}
.ed-proj-ann.annotated { color: var(--color-blue); background: var(--color-blue-light); }
.ed-proj-ann.empty, .ed-proj-ann.pending { color: var(--color-text-muted); background: var(--color-surface-sunken); }
.ed-proj-ann.error { color: var(--color-problem); background: var(--color-problem-tint); }
