@import url('./tokens.css');
@import url('./components.css');

/* Research Stack — Story // Stack shared visual language: near-white surface,
   navy text, navy header strip, sharp corners, uppercase action labels.
   All design tokens live in Brand/tokens.css (synced to ./tokens.css at build;
   see DESIGN-SYSTEM.md L5.1). Edit tokens there, not here. */

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--text-body);
  line-height: 1.5;
  min-height: 100vh;
}

/* The footer justifies to the bottom of the window on short pages and follows
   the content on long ones. Normal flow, not position:fixed — a fixed footer
   would sit on top of a long page's last rows. The body becomes the flex column
   and the footer takes the free space above it. Scoped with :has so it only
   applies to pages that actually carry a footer, leaving every workspace layout
   untouched. */
body:has(> footer) {
  display: flex;
  flex-direction: column;
}
body:has(> footer) > footer { margin-top: auto; }
/* REQUIRED, not belt-and-braces. A flex item whose cross-axis margins are `auto`
   — which is every centred `.container` in the suite (`margin: 0 auto`) — does
   NOT stretch to the container's width; it collapses to fit-content. That turned
   Suite Home's project tree into a narrow column the moment the body became a
   flex column (Joey, 2026-07-20). `width: 100%` restores the fill; `max-width`
   still caps it and the auto margins still centre it. Position:fixed children
   (the rail, side panels, modals) are not flex items and are unaffected. */
body:has(> footer) > * { width: 100%; }

a {
  color: var(--text);
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}

h1, h2, h3, h4 {
  margin: 0 0 0.5em;
  font-weight: 600;
  line-height: 1.25;
}

h1 { font-size: var(--text-h1); }
h2 { font-size: var(--text-h2); }
h3 { font-size: var(--text-h3); }

code, pre {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

/* ---------- slim header (all pages except home) ---------- */
/* Navy palette across all pages, matching the home-page hero. */

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 32px;
  background: var(--navy-bg);
  color: var(--navy-text);
  border-bottom: 1px solid var(--navy-border);
  position: sticky;
  top: 0;
  /* Above the side panels (--z-dropdown) so the user-menu dropdown — which
     opens downward into the panels' region — isn't buried under them. Safe
     because the panels start below the header (top: --rs-sources-top), so the
     header bar never covers panel content. Still below modals/toasts. */
  z-index: calc(var(--z-dropdown) + 1);
}

.app-header .brand {
  display: flex;
  align-items: center;
  gap: 14px;
  color: var(--navy-text);
}
.app-header .brand:hover {
  text-decoration: none;
}
/* Split brand block (2026-07-04): logo → Suite Home, app name → app home.
   Two anchors are flex children of .brand (14px gap) — keep them underline-free
   and color-inherit so the wordmark + label look unchanged. */
.app-header .brand > a {
  display: flex;
  align-items: center;
  color: inherit;
  text-decoration: none;
}

.app-header .brand .wordmark-slot {
  display: flex;
  align-items: center;
  color: var(--navy-text);
}
.app-header .brand .wordmark-slot svg {
  height: 22px;
  width: auto;
  display: block;
}

.app-header .brand .app-label {
  color: var(--navy-muted);
  font-size: var(--text-sm);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding-left: 14px;
  border-left: 1px solid var(--navy-border);
}

.app-header nav {
  display: flex;
  align-items: center;
  gap: 18px;
}

.app-header nav a {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--navy-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.app-header nav a:hover {
  color: var(--navy-text);
  text-decoration: none;
}

.app-header .user-menu {
  color: var(--navy-muted);
}
.app-header .user-menu .user-name {
  color: var(--navy-text);
}
.app-header .user-menu .btn-ghost {
  background: transparent;
  border-color: var(--navy-border);
  color: var(--navy-muted);
}
.app-header .user-menu .btn-ghost:hover {
  background: var(--hairline);
  border-color: var(--navy-text);
  color: var(--navy-text);
}

.user-menu {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--text-md);
  color: var(--text-muted);
}

.user-menu .user-name {
  color: var(--text);
}

/* ---------- hero header (home page only) ---------- */

.hero {
  position: relative;
  background: var(--navy-bg);
  color: var(--navy-text);
  text-align: center;
  padding: 56px 40px 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero-nav-left {
  position: absolute;
  top: 16px;
  left: 40px;
  font-size: var(--text-md);
}
.hero-nav-left a {
  color: var(--navy-muted);
  font-size: var(--text-sm);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.hero-nav-left a:hover {
  color: var(--navy-text);
  text-decoration: none;
}

.hero-controls {
  position: absolute;
  top: 16px;
  right: 40px;
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: var(--text-md);
  color: var(--navy-muted);
}

.hero-controls a {
  color: var(--navy-muted);
  font-size: var(--text-sm);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.hero-controls a:hover {
  color: var(--navy-text);
  text-decoration: none;
}

.hero-controls .user-name {
  opacity: 0.85;
}

.hero-controls button {
  background: none;
  border: 1px solid var(--navy-border);
  color: var(--navy-muted);
  font-size: var(--text-sm);
  font-weight: 600;
  padding: 4px 12px;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-family: inherit;
  transition: color 0.15s, border-color 0.15s;
}
.hero-controls button:hover {
  color: var(--navy-text);
  border-color: var(--navy-text);
}

.hero-logo-link {
  color: inherit;
  text-decoration: none;
  display: inline-block;
}
.hero-logo-link:hover {
  text-decoration: none;
}

.hero-logo {
  color: var(--navy-text);
  display: flex;
  align-items: center;
  justify-content: center;
}
.hero-logo svg {
  height: 120px;
  width: auto;
  display: block;
}

.hero-subtitle {
  font-size: var(--text-sm);
  letter-spacing: 0.25em;
  font-weight: 600;
  color: var(--navy-muted);
  margin-top: 14px;
  text-transform: uppercase;
}

/* ---------- containers ---------- */

.container {
  max-width: 1120px;
  margin: 0 auto;
  padding: 32px 24px;
}

.container-narrow {
  max-width: 720px;
  margin: 0 auto;
  padding: 32px 24px;
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
  gap: 16px;
}

.page-header .meta {
  color: var(--text-muted);
  font-size: var(--text-lg);
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 16px;
  font-size: var(--text-md);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-family: inherit;
  border-radius: 0;
  transition: background 0.15s, border-color 0.15s, opacity 0.15s;
}
.btn:hover {
  background: var(--surface-hover);
  border-color: var(--text-muted);
  text-decoration: none;
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
}
.btn-primary:hover {
  background: var(--text);
  opacity: 0.85;
  border-color: var(--text);
}

.btn-ghost {
  background: transparent;
  border-color: var(--border);
  color: var(--text-muted);
}
.btn-ghost:hover {
  background: var(--accent-bg);
  color: var(--text);
}

.btn-danger {
  background: var(--danger);
  color: var(--on-accent);
  border-color: var(--danger);
}
.btn-danger:hover { opacity: 0.85; }

.btn-sm {
  padding: 6px 12px;
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
}

/* ---------- cards / lists ---------- */

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: background 0.15s, border-color 0.15s;
}

.card-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: var(--text-h3);
  color: var(--text);
}

.card-meta {
  color: var(--text-muted);
  font-size: var(--text-lg);
}

.card-actions {
  margin-top: 8px;
  display: flex;
  gap: 8px;
}

/* Section nav (DESIGN-SYSTEM.md L2.15 sectionNav). Canonical values ported from
   the SuitePortal stylesheet — Cast Stack's first consumer (Phase 4.5 Admin area);
   not a Cast-Stack one-off. Resolution-Log note lands in Phase 7. */
.section-nav {
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-5);
}
.section-nav-item {
  appearance: none;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: var(--space-3) var(--space-4);
  font-family: inherit;
  font-size: var(--text-lg);
  font-weight: var(--weight-medium);
  color: var(--text-muted);
  cursor: pointer;
}
.section-nav-item:hover { color: var(--text); }
.section-nav-item:disabled { opacity: 0.4; cursor: not-allowed; }
.section-nav-item:disabled:hover { color: var(--text-muted); }
/* .compact (decision F2) — borderless, flex-fill, smaller scale. Serves both
   inspector-panel headers (Details/Booking/Quick) and the viewer toolbar mode
   tabs (Details/Collection/Schedule) — C6 adoption. */
.section-nav.compact {
  flex: 1;
  min-width: 0;
  border-bottom: none;
  margin-bottom: 0;
}
.section-nav.compact .section-nav-item {
  margin-bottom: 0;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-base);
  /* Four tabs (Person / Engagement / Booking / Scout) in a panel the user can drag
     narrow: without this a label breaks mid-word and the row grows a second line.
     Nowrap keeps each tab one line and the row scrolls instead (below). */
  white-space: nowrap;
  flex: none;
}
.section-nav.compact {
  overflow-x: auto;
  scrollbar-width: none;
}
.section-nav.compact::-webkit-scrollbar { display: none; }

/* Composition board (Phase 4B) — app-level kanban inside the L2.14 .side-panel.
   Not a design-system primitive; uses existing tokens. Columns are candidacy-
   status drop zones; cards are draggable candidates. */
.cast-board-cols { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; }
.cast-board-col {
  flex: 0 0 180px; min-width: 180px; display: flex; flex-direction: column;
  border: 1px solid var(--border); background: var(--accent-bg); min-height: 120px;
}
.cast-board-col-head {
  position: sticky; top: 0; padding: 6px 8px; font-weight: 600; font-size: var(--text-md);
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted);
  border-bottom: 1px solid var(--border); background: var(--surface);
}
.cast-board-col-body { flex: 1; padding: 6px; display: flex; flex-direction: column; gap: 6px; }
.cast-board-col.drop-over { outline: 2px solid var(--accent); outline-offset: -2px; }
.cast-board-card {
  border: 1px solid var(--border); background: var(--surface); padding: 6px 8px;
  cursor: grab; font-size: var(--text-base);
}
.cast-board-card:active { cursor: grabbing; }
.cast-board-card.dragging { opacity: 0.5; }
.cast-board-makeup { border-top: 1px solid var(--border); padding: 6px 8px; font-size: var(--text-md); }

/* Workspace chassis (Cast Stack Slice 1, r2). Adopts the Info Stack episode-page
   three-pane chassis verbatim — .episode-workspace + the #sources-pane /
   .viewer-pane / #info-panel primitives + body.rs-sources-open / rs-info-open are
   already in this stylesheet (seeded from Info Stack). These rules add only the
   Cast pieces: the context bar (mirrors IS's .ep-strip / .ep-tab) and the body
   mode that frees the viewport + hides the home chrome. To be canonized with the
   chassis as a DESIGN-SYSTEM L-section once it settles (CASTSTACK-POST-V1-ROADMAP §1). */
body.cast-ws { overflow: hidden; }
body.cast-ws #hero-chrome,
body.cast-ws > main.container { display: none !important; }

/* The shared chrome controls (Admin link + user menu) move between the hero and
   the thin .app-header. Keep them on one inline row in either slot — otherwise
   the block children stack (Admin above the user menu). */
#chrome-controls { display: flex; align-items: center; gap: 14px; }

/* Height LOCKED to the shared --context-bar-h (L2.22): the rail's first tool
   icon sits immediately below this row and must land at the same y in every
   tool. */
.cast-context-bar {
  display: flex; align-items: center; gap: 8px;
  height: var(--context-bar-h); box-sizing: border-box;
  padding: 0 32px; border-bottom: 1px solid var(--border); background: var(--surface);
}
/* The selects ARE the title — large text, transparent border until hover (mirrors
   IS's .ep-select-as-title). */

.cast-mode-tabs { display: flex; gap: 4px; margin-left: auto; }
.cast-mode-tab {
  display: inline-block; padding: 5px 14px; border-radius: 0; font-size: var(--text-base);
  color: var(--text-muted); text-decoration: none; border: 1px solid transparent;
  background: transparent; font-family: inherit; cursor: pointer;
}
.cast-mode-tab:hover { color: var(--text); background: var(--surface-hover); }
.cast-mode-tab.active { background: var(--surface-hover); color: var(--text); border-color: var(--border); font-weight: 600; }
.cast-mode-tab:disabled { opacity: 0.4; cursor: not-allowed; }
.cast-mode-tab:disabled:hover { background: transparent; color: var(--text-muted); }

/* Cast viewer now has its own .viewer-toolbar (reopen buttons + mode tabs), so the
   in-toolbar reopen pattern applies — the floating #open-*-btn workaround is gone. */
.cast-viewer-content { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.viewer-toolbar .cast-mode-tabs { margin-left: 0; flex: 1; }

/* People rail rows (dense list inside #sources-pane). */
/* Comfortable rows grow downward as fields are added, so the thumbnail aligns to
   the TOP — beside the name, not floating at the vertical middle of a tall row
   (Joey 2026-07-22). Compact rows are single-line and stay centred (below). */
.cast-rail-row { display: flex; gap: 10px; align-items: flex-start; padding: 8px 14px; cursor: pointer; border-bottom: 1px solid var(--border); }
.cast-rail-row:hover { background: var(--surface-hover); }
.cast-rail-row.is-active { background: var(--surface-hover); box-shadow: inset 3px 0 0 var(--text); }
.cast-rail-row .name { font-weight: 600; }
.cast-rail-row .sub { color: var(--text-muted); font-size: var(--text-dense); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Compact rail density (4a) — avatar + name on one line + a status dot; ~2× the
   names per screen for scanning. Comfortable keeps the fuller row above. */
.cast-rail-row-compact { gap: 8px; padding: var(--row-dense-y) 14px; align-items: center; }
/* Master pull-in affordances on a rail row: the ＋ Add button + the in-season ✓
   sit at the row's trailing edge (the flex:1 content pushes them right). Shown
   only in Master mode; both stay out of the row's own click/keyboard model. */
.cast-rail-add { margin-left: auto; flex: none; }
.cast-rail-inseason { margin-left: auto; flex: none; color: var(--success, var(--text-muted)); font-weight: var(--weight-semibold); padding: 0 6px; }
/* Context-bar separator between the project and the active-season picker. */

/* Stat tile (DESIGN-SYSTEM L2.19 — Cast-first, canonize on a 2nd consumer): a big
   number + a label that navigates. Problem tiles tint the number by role. Token
   only, radius 0. */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: var(--space-3); }
.stat { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-3) var(--space-4); border: 1px solid var(--border); background: var(--surface); text-align: left; cursor: pointer; font-family: inherit; }
.stat:hover:not(:disabled) { background: var(--surface-hover); }
.stat:disabled { cursor: default; }
.stat-value { font-size: var(--text-2xl); font-weight: var(--weight-bold); line-height: 1.1; color: var(--text); }
.stat-label { font-size: var(--text-sm); color: var(--text-muted); }
.stat-danger .stat-value { color: var(--danger-text); }
.stat-warning .stat-value { color: var(--warning-text); }
.stat-success .stat-value { color: var(--success-text); }

/* Overview cockpit — the season's at-a-glance launch pad (Slice 2). */
/* The center pane is overflow:hidden (Collection scrolls via its own inner body);
   the cockpit is likewise its own scroll container so a tall season scrolls. */
.cast-cockpit { flex: 1; min-height: 0; overflow-y: auto; padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-5); max-width: 920px; }
.cast-cockpit-title { display: flex; align-items: baseline; gap: var(--space-2); }
.cast-cockpit-title h2 { margin: 0; }
.cast-cockpit-section { display: flex; flex-direction: column; gap: var(--space-2); }
.cast-cockpit-head { display: flex; align-items: baseline; justify-content: space-between; font-weight: var(--weight-semibold); text-transform: uppercase; letter-spacing: .05em; font-size: var(--text-dense-xs); color: var(--text-muted); border-bottom: 1px solid var(--border); padding-bottom: var(--space-1); }
.cast-pipe { display: flex; flex-direction: column; gap: var(--space-3); }
.cast-pipe-head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1); }
.cast-pipe-card { display: flex; align-items: center; gap: var(--space-2); }
.cast-pipe-card .entity-row { flex: 1; min-width: 0; }
.cast-attn-group { margin-bottom: var(--space-3); }
.cast-attn-title { font-weight: var(--weight-semibold); font-size: var(--text-base); margin-bottom: var(--space-1); }
.cast-cov-toolbar { display: flex; justify-content: flex-end; margin-bottom: var(--space-2); }

/* Schedule / month-calendar (DESIGN-SYSTEM L2.20 — Cast-first, canonize on a 2nd
   consumer). Token only, radius 0. State tints reuse the role --tint-* tokens. */
.cast-schedule { flex: 1; min-height: 0; padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); }
.cast-cal-toolbar { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); }
.cast-cal-dateinput { font: inherit; font-size: var(--text-sm); padding: 4px 6px; border: 1px solid var(--border); background: var(--surface); color: var(--text); }
/* Month fills the remaining height: a fixed weekday header + a grid whose rows share
   the space (never below 56px, scroll if a 6-week month can't fit). */
.cast-cal-month { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 2px; }
.cast-cal-dows { flex: none; display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cast-cal-grid { flex: 1; min-height: 0; overflow-y: auto; display: grid; grid-template-columns: repeat(7, 1fr); grid-auto-rows: minmax(56px, 1fr); gap: 2px; }
.cast-cal-list { flex: 1; min-height: 0; overflow-y: auto; }
.cast-cal-listhead { position: sticky; top: 0; z-index: 1; display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); padding: 2px 0 8px; background: var(--bg); }
.cast-cal-daybody { display: flex; flex-direction: column; padding: 2px 0; }
.cast-cal-daybody .cast-cal-nm { padding: 3px 6px; }
/* List day header: date + inline non-zero counts, chevron pushed to the right. */
.cast-cal-list .disclosure-summary .disclosure-label { order: 1; }
.cast-cal-list .disclosure-summary .disclosure-chevron { order: 2; }
.cast-cal-daydate { font-weight: var(--weight-semibold); }
.cast-cal-daycount { font-weight: 400; }
/* Week view: 7 day columns (day-level; the hourly view is a later slice). */
.cast-week { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cast-week-col { border: 1px solid var(--border); background: var(--surface); min-height: 0; display: flex; flex-direction: column; cursor: pointer; }
.cast-week-col:hover { background: var(--surface-hover); }
.cast-week-col.is-selected { outline: 2px solid var(--text); outline-offset: -2px; }
.cast-week-head { display: flex; align-items: baseline; gap: 6px; padding: 6px; border-bottom: 1px solid var(--border); cursor: pointer; }
.cast-week-head:hover { background: var(--surface-hover); }
.cast-week-num { font-weight: var(--weight-bold); }
.cast-week-names { flex: 1; min-height: 0; overflow-y: auto; padding: 4px; display: flex; flex-direction: column; gap: 3px; }
.cast-week-names .cast-cal-nm { padding: 2px 5px; }
.cast-week-sep { flex: none; height: 0; border-top: 1px solid var(--border); margin: 3px 2px; }
/* Hide-weekends: 5 columns instead of 7 (Month + Week). */
.cast-cal-dows.no-weekends, .cast-cal-grid.no-weekends, .cast-week.no-weekends { grid-template-columns: repeat(5, 1fr); }
.cast-cal-dow { font-size: var(--text-dense-xs); text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); text-align: center; padding: 4px 0; font-weight: var(--weight-semibold); }
.cast-cal-cell { border: 1px solid var(--border); background: var(--surface); padding: 4px; cursor: pointer; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
.cast-cal-cell:hover { background: var(--surface-hover); }
.cast-cal-cell.drop-over { outline: 2px dashed var(--text); outline-offset: -3px; background: var(--surface-hover); }
.cast-cal-top { display: flex; align-items: center; justify-content: space-between; flex: none; }
.cast-cal-names { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; gap: 1px; }
/* One person's mark on a day (month cell + week column). Left border = state. */
.cast-cal-nm { position: relative; display: flex; align-items: center; gap: 2px; font-size: var(--text-sm); line-height: 1.35; padding: 0 2px; border-left: 3px solid var(--border); cursor: pointer; }
/* Range-paint edges: thin grab strips at the chip's left/right (Month/Week), shown on hover. */
.cast-cal-nm-edge { position: absolute; top: 0; bottom: 0; width: 6px; cursor: ew-resize; touch-action: none; opacity: 0; }
.cast-cal-nm-edge-left { left: 0; }
.cast-cal-nm-edge-right { right: 0; }
.cast-cal-nm:hover .cast-cal-nm-edge { opacity: 1; background: var(--text-placeholder); }
.cast-cal-nm-edge:hover, .cast-cal-nm-edge.dragging { background: var(--text-muted); }
.cast-cal-nm:hover { background: var(--surface-hover); }
.cast-cal-nm-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cast-cal-nm.cast-cal-available { border-left-color: var(--success-text); }
.cast-cal-nm.cast-cal-hold { border-left-color: var(--warning-text); }
.cast-cal-nm.cast-cal-booked { border-left-color: var(--info-text); }
.cast-cal-nm.cast-cal-unavailable { border-left-color: var(--danger-text); }
.cast-cal-nm[draggable="true"] { cursor: grab; }
.cast-cal-nm.dragging { opacity: 0.5; }
/* Follow-the-pointer preview for interact.js drags (Schedule gesture engine). Fixed,
   click-through, floats above the calendar so you see exactly what you're moving. */
.cast-drag-ghost { position: fixed; top: 0; left: 0; z-index: 3000; pointer-events: none; max-width: 220px; padding: 3px 8px; background: var(--navy-bg); color: var(--navy-text); font-size: var(--text-sm); border-radius: var(--radius-sm); box-shadow: var(--shadow-dropdown); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Drop-over highlight on the other day surfaces (month cell has its own rule above). */
.cast-week-col.drop-over, .cast-cal-list .disclosure.drop-over { outline: 2px dashed var(--text); outline-offset: -3px; background: var(--surface-hover); }
/* Compact icon buttons inside cells (⤢ expand-to-week, × remove-from-day). */
.cast-cal-expand, .cast-cal-nm-x { min-width: 0; width: auto; height: auto; padding: 0 3px; line-height: 1.2; font-size: var(--text-sm); }
.cast-cal-nm-x { visibility: hidden; position: relative; z-index: 1; } /* above the range-paint right edge so it stays clickable */
.cast-cal-nm:hover .cast-cal-nm-x, .cast-cal-nm:focus-within .cast-cal-nm-x { visibility: visible; }
.cast-cal-blank { background: transparent; border-color: transparent; cursor: default; }
.cast-cal-num { font-size: var(--text-sm); color: var(--text-muted); }
.cast-cal-cell.is-today .cast-cal-num { font-weight: var(--weight-bold); color: var(--text); }
.cast-cal-cell.is-selected { outline: 2px solid var(--text); outline-offset: -2px; }
.cast-cal-inwindow { background: var(--accent-bg); }
.cast-cal-available { background: var(--tint-success); border-color: var(--success-text); }
.cast-cal-hold { background: var(--tint-warning); border-color: var(--warning-text); }
.cast-cal-booked { background: var(--tint-info); border-color: var(--info-text); }
.cast-cal-unavailable { background: var(--tint-danger); border-color: var(--danger-text); }
.cast-cal-badges { margin-top: auto; display: flex; gap: 4px; flex-wrap: wrap; }
.cast-cal-badge { font-size: var(--text-dense-xs); padding: 0 4px; }
.cast-cal-badge-avail { background: var(--chip-success-bg); color: var(--success-text); }
.cast-cal-badge-booked { color: var(--info-text); font-weight: var(--weight-semibold); }
.cast-cal-list .entity-row.is-selected { background: var(--surface-hover); box-shadow: inset 3px 0 0 var(--text); }

/* Hourly per-person day view (Phase 2): roster (left) + hour grid (right). */
.cast-hour { display: grid; grid-template-columns: minmax(170px, 1fr) 2fr; grid-template-rows: 1fr auto; gap: 10px; height: 100%; min-height: 480px; }
.cast-hour-left { grid-column: 1; grid-row: 1; overflow: auto; min-height: 0; }
.cast-hour-right { grid-column: 2; grid-row: 1; display: flex; overflow: auto; min-height: 0; border: 1px solid var(--border); }
.cast-hour-log { grid-column: 1 / -1; grid-row: 2; font-size: var(--text-sm); color: var(--text-muted); }
.cast-hour-roster-head { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); font-weight: var(--weight-semibold); margin-bottom: 6px; }
.cast-hour-rostergroup { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); font-weight: var(--weight-semibold); margin: 8px 0 3px; padding-bottom: 2px; border-bottom: 1px solid var(--border); }
.cast-hour-rosterrow { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 5px 8px; border: 1px solid var(--border); background: var(--surface); margin-bottom: 4px; cursor: grab; touch-action: none; }
.cast-hour-rosterrow:hover { background: var(--surface-hover); }
.cast-hour-rosterrow.dragging { opacity: 0.5; }
.cast-hour-rostername { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-sm); }
.cast-hour-chip { flex: none; font-size: var(--text-xs); padding: 1px 6px; border: 1px solid var(--border); }
.cast-hour-gutter { width: 52px; flex: none; }
.cast-hour-tick { font-size: var(--text-xs); color: var(--text-muted); text-align: right; padding-right: 6px; box-sizing: border-box; }
.cast-hour-canvas { position: relative; flex: 1; border-left: 1px solid var(--border); min-width: 0; }
.cast-hour-canvas.drop-over { background: var(--tint-info); }
.cast-hour-lines { position: absolute; inset: 0; }
.cast-hour-line { border-top: 1px solid var(--border); box-sizing: border-box; }
.cast-hour-blocks { position: absolute; inset: 0; }
.cast-hour-block { position: absolute; box-sizing: border-box; border-radius: var(--radius-sm); color: var(--navy-text); padding: 2px 5px; overflow: hidden; cursor: grab; touch-action: none; font-size: var(--text-xs); line-height: 1.25; box-shadow: var(--shadow-dropdown); }
.cast-hour-block.dragging { opacity: 0.75; }
.cast-hour-block-name { font-weight: var(--weight-semibold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cast-hour-block-time { opacity: 0.85; }
.cast-hour-block-x { position: absolute; top: 0; right: 0; width: 16px; height: 16px; padding: 0; line-height: 14px; border: none; background: transparent; color: var(--navy-text); font-size: var(--text-base); cursor: pointer; opacity: 0; }
.cast-hour-block:hover .cast-hour-block-x { opacity: 0.85; }
.cast-hour-block-x:hover { opacity: 1; }
.cast-hour-left.drop-over { outline: 2px dashed var(--text); outline-offset: -3px; background: var(--surface-hover); }

/* Per-person week (Phase 3): people rows × 7 day columns (locked to viewer width);
   up to 3 stacked weeks; drag blocks day↔day↔week; row height is user-adjustable. */
.cast-pweek-wrap { display: flex; flex-direction: column; height: 100%; min-height: 400px; }
.cast-pweek-controls { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; }
.cast-pweek-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 14px; }
.cast-pweek-weeklabel { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text); margin-bottom: 4px; }
.cast-pweek { display: grid; grid-template-columns: 130px repeat(7, minmax(0, 1fr)); gap: 1px; background: var(--border); border: 1px solid var(--border); }
.cast-pweek-corner { background: var(--surface); padding: 6px; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); font-weight: var(--weight-semibold); }
.cast-pweek-dayhead { background: var(--surface); padding: 6px; display: flex; align-items: baseline; gap: 4px; }
.cast-pweek-dayhead.is-today .cast-pweek-daynum { font-weight: var(--weight-bold); color: var(--text); }
.cast-pweek-daynum { font-weight: var(--weight-semibold); }
.cast-pweek-name { background: var(--surface); padding: 6px; font-size: var(--text-sm); font-weight: var(--weight-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cast-pweek-emptyname { color: var(--text-muted); font-weight: var(--weight-medium); }
.cast-pweek-cell { box-sizing: border-box; background: var(--surface); min-height: var(--pweek-rowh, 54px); padding: 4px; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
/* Fill + colored left-accent, matching the Month/Week name chips (same tokens). The
   tint is translucent, so it must sit over an opaque --surface (like the white cells in
   Month/Week) — otherwise it composites over the gray gridlines and reads grayish. */
.cast-pweek-cell.cast-cal-available { background: linear-gradient(var(--tint-success), var(--tint-success)), var(--surface); border-left: 3px solid var(--success-text); }
.cast-pweek-cell.cast-cal-hold { background: linear-gradient(var(--tint-warning), var(--tint-warning)), var(--surface); border-left: 3px solid var(--warning-text); }
.cast-pweek-cell.cast-cal-booked { background: linear-gradient(var(--tint-info), var(--tint-info)), var(--surface); border-left: 3px solid var(--info-text); }
.cast-pweek-cell.cast-cal-unavailable { background: linear-gradient(var(--tint-danger), var(--tint-danger)), var(--surface); border-left: 3px solid var(--danger-text); }
.cast-pweek-status { font-size: var(--text-xs); font-weight: var(--weight-semibold); background: none; border: none; padding: 0; margin: 0; font-family: inherit; text-align: left; align-self: flex-start; cursor: pointer; }
.cast-pweek-status::after { content: ' ▾'; opacity: 0.55; }
.cast-pweek-status:hover { text-decoration: underline; }
.cast-pweek-cell.cast-cal-available .cast-pweek-status { color: var(--success-text); }
.cast-pweek-cell.cast-cal-hold .cast-pweek-status { color: var(--warning-text); }
.cast-pweek-cell.cast-cal-booked .cast-pweek-status { color: var(--info-text); }
.cast-pweek-cell.cast-cal-unavailable .cast-pweek-status { color: var(--danger-text); }
.cast-pweek-cell.drop-over { outline: 2px dashed var(--text); outline-offset: -3px; }
/* Day-column hover + selection (brightness works over the tinted cells too). */
.cast-pweek-dayhead, .cast-pweek-cell { cursor: pointer; }
.cast-pweek-dayhead.is-colhover, .cast-pweek-cell.is-colhover { filter: brightness(0.965); }
.cast-pweek-dayhead.is-colsel, .cast-pweek-cell.is-colsel { filter: brightness(0.93); }
.cast-pweek-chip { color: var(--navy-text); font-size: var(--text-xs); padding: 1px 5px; border-radius: var(--radius-sm); cursor: grab; touch-action: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cast-pweek-chip.dragging { opacity: 0.5; }
.cast-pweek-foot { display: flex; align-items: center; gap: 12px; margin-top: 6px; flex-wrap: wrap; }
/* Grab the bottom edge of a week to resize all rows (shared height). */
.cast-pweek-resize { height: 10px; cursor: ns-resize; touch-action: none; user-select: none; display: flex; align-items: center; justify-content: center; }
.cast-pweek-resize::after { content: ''; width: 44px; height: 3px; border-radius: 2px; background: var(--border); }
.cast-pweek-resize:hover::after, .cast-pweek-resize.dragging::after { background: var(--text-muted); }
.cast-cal-nm-time { font-size: var(--text-dense-xs); color: var(--text-muted); margin-left: 4px; flex: none; }
/* Day-centric inspector (Schedule right panel). */
.cast-day-mark { border: 1px solid var(--border); padding: var(--space-2); margin-bottom: var(--space-2); }
/* Rail availability dot (Schedule mode). */
.cast-rail-availdot { margin-left: auto; flex: none; width: 8px; height: 8px; border-radius: var(--radius-circle); background: var(--success-text); }
.cast-rail-availdot.is-booked { background: var(--info-text); }
/* In Schedule mode the right inspector shows the day view instead of the tabs. */
body.cast-sched-mode #info-panel .section-nav { display: none; }
body.cast-sched-mode #info-panel .info-tab-panel:not(#cast-schedule-body) { display: none !important; }
body.cast-sched-mode #cast-schedule-body { display: block !important; padding: var(--space-3); }

/* Communication log — the manual "Log a touch" history on the booking panel. */
.cast-comms { margin-top: var(--space-3); border-top: 1px solid var(--border); padding-top: var(--space-3); }
.cast-comms-input { flex: 1; min-width: 0; font: inherit; font-size: var(--text-base); padding: 6px 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text); }
.cast-comms-form { margin: var(--space-2) 0; }
.cast-comms-actions { margin: var(--space-2) 0; align-items: center; }

/* Availability quick-view (Booking tab) — a compact read of the season's marked
   days. State colours come from the .cast-cal-* classes the calendar owns. */
.cast-avail-quick { display: flex; flex-direction: column; gap: var(--space-2); }
.cast-avail-row { display: flex; flex-direction: column; gap: var(--space-1); }
.cast-avail-state { align-self: flex-start; font-size: var(--text-sm); font-weight: var(--weight-semibold); padding: 0 6px; border: 1px solid transparent; }
.cast-avail-days { display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: center; }

/* Communication timeline (Outreach Phase 1) — the log as a readable thread.
   Direction is carried by the left rule + the arrow: outgoing sits on the border
   tint, an incoming reply on the info tint so a reply reads at a glance. */
.cast-thread { margin-top: var(--space-2); display: flex; flex-direction: column; gap: var(--space-3); }
.cast-thread-item { border-left: 2px solid var(--border); padding-left: var(--space-2); }
.cast-thread-item.is-in { border-left-color: var(--tint-info-strong); }
.cast-thread-dir { color: var(--text-muted); font-size: var(--text-base); }
.cast-thread-subject { font-size: var(--text-base); font-weight: var(--weight-semibold); color: var(--text); margin-top: var(--space-1); }
.cast-thread-text { font-size: var(--text-base); color: var(--text); margin-top: var(--space-1); white-space: pre-wrap; }

/* Compose window (Outreach Phase 1) — a plain form inside the canonical modal. */
.cast-compose-input { width: 100%; font: inherit; font-size: var(--text-lg); padding: 6px 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text); }
.cast-compose-body { width: 100%; font: inherit; font-size: var(--text-lg); padding: var(--space-2); border: 1px solid var(--border); background: var(--surface); color: var(--text); resize: vertical; }
.cast-compose-from { padding: 6px 0; }
.cast-compose-tokens { margin-top: var(--space-1); }
.cast-compose-actions { margin-top: var(--space-2); }
.cast-compose-status { margin-top: var(--space-2); }

/* Stack Scout (right-panel tab, shell). Ported verbatim from Info Stack's Scout
   so the assistant reads as one across the suite (one Scout, per-app brains). The
   tab takes over the panel body as a full-height chat: the body stops scrolling as
   a block, the log scrolls, the composer pins to the bottom. Scoped to
   .scout-active so Details / Booking / Quick edit keep their normal scroll. */
.info-panel.scout-active .side-panel-body { overflow: hidden; padding: 0; display: flex; flex-direction: column; }
.info-panel.scout-active #cast-scout-body { flex: 1 1 auto; min-height: 0; display: flex; }
/* Scout inspector tab = the lens glyph (currentColor, so muted when inactive,
   navy when hovered/selected — same as the text tabs); the negative margin keeps
   the nav row height unchanged. */
.section-nav-item.scout-tab { display: inline-flex; align-items: center; }
.section-nav-item.scout-tab svg { width: 22px; height: 22px; display: block; margin: -4px 0; }
.scout-chat { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.scout-toolbar { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; padding: 8px 16px; border-bottom: 1px solid var(--border); }
.scout-scope { flex: 1 1 auto; min-width: 0; font-size: var(--text-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scout-log { flex: 1 1 auto; min-height: 0; overflow: auto; scrollbar-gutter: stable; display: flex; flex-direction: column; gap: 12px; padding: 12px 14px 12px 16px; }
.scout-log * { min-width: 0; }
.scout-empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; padding: 28px 16px; margin: auto 0; }
.scout-empty-glyph { color: var(--text-muted); line-height: 0; }
.scout-empty-glyph svg { width: 44px; height: 44px; display: block; }
.scout-empty-copy { font-size: var(--text-md); line-height: 1.5; max-width: 34ch; }
.scout-composer { flex: 0 0 auto; display: flex; gap: 6px; align-items: flex-end; padding: 8px 16px 12px; border-top: 1px solid var(--border); background: var(--surface); }
.scout-input { flex: 1 1 auto; min-width: 0; resize: vertical; min-height: 38px; max-height: 160px; font: inherit; font-size: var(--text-base); line-height: 1.4; padding: 8px 10px; border: 1px solid var(--border); background: var(--surface); color: var(--text); }
.scout-send { flex: 0 0 auto; }
.scout-composer-disabled { opacity: 0.55; }
.scout-composer-disabled .scout-input { cursor: not-allowed; }
/* Conversation turns — copied from Info Stack's Scout so the two read as one
   assistant (DESIGN-BRIEF-CASTSTACK-SCOUT-V1 §1f parity). Cast adds only
   .scout-person, the link that opens a named person's record. */
.scout-toolbar-actions { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; }
.scout-turn { font-size: var(--text-base); line-height: 1.5; }
.scout-user {
  align-self: flex-end;
  max-width: 88%;
  background: var(--accent-bg);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 7px 10px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.scout-scout { align-self: stretch; color: var(--text); }
.scout-pending { font-style: italic; }
.scout-error { color: var(--danger-text); }
/* The answer renders real blocks (see scoutAnswerNode), so pre-wrap belongs on
   the paragraphs — on the container it would add blank lines around tables. */
.scout-answer { overflow-wrap: anywhere; display: flex; flex-direction: column; gap: var(--space-2); }
.scout-p { white-space: pre-wrap; margin: 0; }
.scout-list { margin: 0; padding-left: var(--space-4); display: flex; flex-direction: column; gap: 2px; }
/* A ranked answer can outgrow a narrow inspector — scroll the table, never the panel. */
.scout-table-wrap { overflow-x: auto; }
.scout-table { width: 100%; }
.scout-table td, .scout-table th { vertical-align: top; }
.scout-person {
  color: var(--text);
  font-weight: var(--weight-semibold);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
  font-size: inherit;
  font-family: inherit;
}
.scout-person:hover { background: var(--surface-hover); }

/* Saved reports — Save / Library / the reopened report banner. Ported from Info
   Stack's Scout so the two libraries are the same surface (brief §1f parity).
   Cast omits Info's drag-to-resize handle: the inspector panel is itself
   user-resizable, so a second resize inside it is a handle too many. */
.scout-report-banner {
  align-self: stretch;
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 8px 10px;
  background: var(--accent-bg);
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
}
.scout-report-banner-info { flex: 1 1 auto; min-width: 0; }
.scout-report-title { font-size: var(--text-base); font-weight: var(--weight-bold); color: var(--text); overflow-wrap: anywhere; }
.scout-report-meta { font-size: var(--text-sm); margin-top: 2px; }
.scout-report-desc { font-size: var(--text-md); line-height: 1.45; margin-top: 5px; color: var(--text); white-space: pre-wrap; overflow-wrap: anywhere; }
.scout-library {
  flex: 0 0 auto;
  height: 240px;
  max-height: 60%;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.scout-library.hidden { display: none; }
.scout-lib-head { flex: 0 0 auto; padding: 6px 12px 0; border-bottom: 1px solid var(--border); }
.scout-lib-tabs { display: flex; gap: var(--space-1); }
.scout-lib-tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 4px 8px 6px;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  cursor: pointer;
}
.scout-lib-tab.active { color: var(--text); border-bottom-color: var(--accent); }
.scout-lib-body { flex: 1 1 auto; overflow: auto; scrollbar-gutter: stable; padding: 6px 12px 10px; display: flex; flex-direction: column; gap: var(--space-1); }
.scout-lib-empty { padding: 12px 2px; font-size: var(--text-md); }
/* The row wraps so Publish / ✕ never clip in a narrow inspector — the actions
   drop to their own right-aligned line instead of overflowing. */
.scout-lib-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; border: 1px solid var(--border); background: var(--surface); }
.scout-lib-row:hover { background: var(--surface-hover); }
.scout-lib-row-open { flex: 1 1 60%; min-width: 0; text-align: left; background: none; border: none; padding: 7px 8px; font: inherit; cursor: pointer; color: var(--text); }
.scout-lib-row-title { font-size: var(--text-md); font-weight: var(--weight-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scout-lib-row-meta { font-size: var(--text-sm); margin-top: 1px; }
.scout-lib-row-desc { font-size: var(--text-sm); margin-top: 3px; white-space: normal; overflow: hidden; overflow-wrap: anywhere; }
.scout-lib-row-actions { flex: 1 1 auto; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-1); padding: 0 6px 4px; }
.scout-lib-vis { font-size: var(--text-xs); font-weight: var(--weight-bold); text-transform: uppercase; letter-spacing: 0.03em; white-space: nowrap; color: var(--accent); }
.scout-lib-del:hover { color: var(--danger-text); }
/* Episode code shown inline after the title, smaller + muted (one-line ep rows). */
.cast-ep-code { font-size: var(--text-dense-xs); font-weight: 400; color: var(--text-muted); }
/* Shared avatar primitive (ui.js avatar(), DESIGN-SYSTEM L5.2) — image, else
   initials monogram on a tinted tile. Emits `.ui-avatar` (renamed from bare
   `.avatar` in C8 so it can't collide with the user-menu trigger's own
   `.avatar` span). */
.ui-avatar { flex: 0 0 auto; border: 1px solid var(--border); background: var(--accent-bg); color: var(--text-muted); display: inline-flex; align-items: center; justify-content: center; font-weight: 700; overflow: hidden; line-height: 1; }
.ui-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ui-avatar-fill { flex: 1; min-height: 0; width: 100%; height: 100%; font-size: var(--text-2xl); border: 0; }
.cast-rail-thumb {
  width: 32px; height: 32px; flex: 0 0 auto; border: 1px solid var(--border); background: var(--accent-bg);
  display: flex; align-items: center; justify-content: center; font-weight: 600; color: var(--text-muted); font-size: var(--text-dense);
}

/* Person mode fills the viewer pane with its own scroll. Slice-2 register pass:
   the workspace person card runs DENSE (smaller type, tight rhythm, collapsible
   small-label sections) so it carries many fields — scoped to .cast-person-scroll
   so the standalone person.html permalink keeps its comfortable reading layout. */
.cast-person-scroll { height: 100%; overflow-y: auto; padding: 14px 18px; font-size: var(--text-base); }
.cast-person-scroll > * { max-width: 820px; }
.cast-person-scroll h1 { font-size: var(--text-h3); margin: 0 0 10px; }

/* Collapsible record section — small uppercase label header (panel-header register). */
.cast-rec-section { border: 1px solid var(--border); background: var(--surface); margin-bottom: 8px; }
.cast-rec-section > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: 8px; padding: 7px 12px;
  font-size: var(--text-dense-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted);
}
.cast-rec-section > summary::-webkit-details-marker { display: none; }
.cast-rec-section > summary::before { content: '▸'; font-size: var(--text-xs); }
.cast-rec-section[open] > summary::before { content: '▾'; }
.cast-rec-section > summary:hover { color: var(--text); background: var(--surface-hover); }
.cast-rec-section-body { padding: 10px 12px; border-top: 1px solid var(--border); }
/* Dense form rows inside the workspace record: label left, control right. */
/* Details / Contact: two-column (label left, value right). */
.cast-person-scroll .form-row { display: grid; grid-template-columns: 132px 1fr; gap: 6px 12px; align-items: start; margin: 0 0 7px; }
.cast-person-scroll .form-row > label { font-size: var(--text-dense); color: var(--text-muted); padding-top: 4px; }
.cast-person-scroll .form-row .hint { grid-column: 2; }
/* Identity fields keep their label ABOVE the control (one column). */
.cast-id-fields .form-row { grid-template-columns: 1fr; gap: 2px; }
.cast-id-fields .form-row > label { padding-top: 0; }
.cast-id-fields .form-row .hint { grid-column: 1; }
.cast-person-scroll .form-row input, .cast-person-scroll .form-row textarea, .cast-person-scroll .form-row select { font-size: var(--text-base); }
.cast-person-scroll h2, .cast-person-scroll h3 { font-size: var(--text-dense); margin: 0 0 6px; }
/* Quiet danger affordance for Delete person (out of the primary action row). */
.cast-rec-danger { margin-top: 12px; }
.cast-rec-danger .btn { color: var(--danger); border-color: transparent; background: transparent; }
.cast-rec-danger .btn:hover { border-color: var(--danger); background: transparent; }
/* Read-first identity glance (workspace view) — photo + name + title/expertise +
   booking + appearances + topic chips. Uses existing tokens + the dense register;
   edit chrome (upload/name/AI) is gated behind the Edit button. */
/* Read-only view: the identity header is pinned while Details/Contact/Appearances
   scroll beneath it. (Edit mode renders the editable Identity section instead, so
   this stays scoped to the read state.) Background matches the viewer pane so
   scrolled content passes cleanly under it. */
.cast-rec-identity {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 4px 0 12px; margin-bottom: 12px; border-bottom: 1px solid var(--border);
}
/* Read header pins to the top; edit mode is static (the Save/Cancel bar pins instead).
   The box-shadow caps the scroll container's 14px top padding so rows can't peek above. */
.cast-rec-identity:not(.is-editing) { position: sticky; top: 0; z-index: var(--z-sticky); background: var(--bg); box-shadow: 0 -14px 0 var(--bg); }
.cast-id-photo { flex: 0 0 auto; }
.cast-id-photo .cast-rec-avatar { width: 128px; height: 128px; font-size: var(--text-4xl); }
.cast-id-fields { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
/* Compact photo control (edit): photo + hover-× + click-to-replace + drop. */
.cast-photo { position: relative; width: 128px; height: 128px; flex: 0 0 auto; cursor: pointer; }
.cast-photo .cast-rec-avatar { width: 128px; height: 128px; font-size: var(--text-4xl); }
.cast-photo.drag { outline: 2px dashed var(--text); outline-offset: 2px; }
.cast-photo-x { position: absolute; top: 4px; right: 4px; display: none; width: 20px; height: 20px; padding: 0; border: none; border-radius: 50%; background: rgba(0,0,0,0.6); color: var(--on-accent); font-size: var(--text-lg); line-height: 18px; cursor: pointer; }  /* ds-allow: one-off scrim */
.cast-photo.has-photo:hover .cast-photo-x { display: block; }
/* The replace panel is a popover-md (320px). The URL field + its button stack so
   neither is clipped — they were sharing one narrow row before. */
.cast-photo-replace { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.cast-photo-replace .btn { width: 100%; justify-content: center; }
.cast-photo-urlrow { display: flex; flex-direction: column; gap: 6px; }
.cast-photo-url { width: 100%; min-width: 0; }
/* Section header actions (the Contact "+") pinned to the summary's right. */
.cast-rec-sec-actions { margin-left: auto; display: flex; gap: 4px; align-items: center; }
.cast-contact-list { display: flex; flex-direction: column; gap: 8px; }
.cast-person-scroll .form-row.cast-contact-notes { margin-top: 8px; }
/* Appearances as aligned columns: Season | Status | summary. */
.cast-appearances-grid { display: grid; grid-template-columns: max-content max-content 1fr; gap: 4px 12px; align-items: center; }
.cast-appearances-proj { grid-column: 1 / -1; font-weight: 600; margin-top: 8px; }
.cast-appearance-summary { min-width: 0; }
/* Per-season episode drill-down (status-model 2026-07-18): the season name toggles a
   full-width, read-only per-episode participation list beneath the row. */
.cast-appearance-season.is-expandable { cursor: pointer; }
.cast-appear-caret { display: inline-block; width: 1em; color: var(--text-muted); font-size: var(--text-sm); }
.cast-appearance-episodes { grid-column: 1 / -1; padding: 2px 0 8px 18px; }
.cast-appearance-episodes[hidden] { display: none; }
.cast-id-fields > .form-row { margin: 0; }
.cast-id-actions { flex: 0 0 auto; display: flex; gap: 6px; align-items: center; }
.cast-id-ai { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.cast-rec-category { margin-top: 4px; }
/* Edit mode: the Save/Cancel bar is pinned the same way the read header is. */
.cast-rec-editbar {
  position: sticky; top: 0; z-index: var(--z-sticky); justify-content: flex-end; gap: 6px;
  background: var(--bg); padding: 8px 0; margin-bottom: 8px; border-bottom: 1px solid var(--border);
  box-shadow: 0 -14px 0 var(--bg); /* cap the scroll container's top padding */
}
/* ⌘K person-finder — reuses .modal-backdrop (dim + center) + .popover (surface). */
.cast-finder { width: 540px; max-width: 92vw; padding: 0; align-self: start; margin-top: 12vh; display: flex; flex-direction: column; }
.cast-finder-input { width: 100%; border: 0; border-bottom: 1px solid var(--border); padding: 12px 14px; font-size: var(--text-body); background: transparent; outline: none; }
.cast-finder-list { max-height: 50vh; overflow-y: auto; padding: 4px; }
.cast-finder-row { display: flex; flex-direction: column; gap: 2px; padding: 7px 10px; cursor: pointer; }
.cast-finder-row .name { font-weight: 600; }
.cast-finder-row.is-active { background: var(--surface-hover); }
.cast-finder-snip { font-size: var(--text-md); color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cast-finder-snip-label { text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--text-xs); font-weight: 700; }
.cast-hl { background: var(--chip-warning-border); color: var(--text); border-radius: 2px; padding: 0 1px; }
/* Add-person live dedup matches + Autofill-from-URL (7a) */
.cast-addmatch { max-height: 200px; overflow-y: auto; }
.cast-addmatch-row { border-radius: 4px; }
.cast-addmatch-row:hover { background: var(--surface-hover); }
.cast-addurl { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.cast-rec-avatar {
  width: 88px; height: 88px; flex: 0 0 auto; border: 1px solid var(--border); background: var(--accent-bg);
  display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: var(--text-3xl); color: var(--text-muted); overflow: hidden;
}
.cast-rec-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cast-rec-name { font-size: var(--text-h2); font-weight: 700; line-height: 1.2; }
.cast-rec-subtitle { color: var(--text-muted); font-size: var(--text-body); margin-top: 3px; }
/* Merged Appearances: one collapsible row per season (= engagement), expandable
   to its episodes. Mirrors the .cast-rec-section summary-marker pattern. */
.cast-rec-season { border-top: 1px solid var(--border); }
.cast-rec-season:first-of-type { border-top: 0; }
.cast-rec-season > summary {
  list-style: none; cursor: pointer; user-select: none; display: flex; align-items: center; gap: 8px; padding: 6px 0;
}
.cast-rec-season > summary::-webkit-details-marker { display: none; }
.cast-rec-season > summary::before { content: '▸'; font-size: var(--text-xs); color: var(--text-muted); flex: 0 0 auto; }
.cast-rec-season[open] > summary::before { content: '▾'; }
.cast-rec-season-body { padding: 4px 0 8px 14px; }

/* Filter system — compact field-picker rows inside the rail. */
.cast-filters { display: flex; flex-direction: column; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--border); }
.cast-filters .filter-select { width: auto; }
/* Filter rows toggle INLINE below the FILTERS button (suite standard — not a
   popover): a full-width section with a divider, hidden when collapsed. */
.cast-filters-panel { width: 100%; }
.cast-filters-panel[hidden] { display: none; }
.cast-filters > .cast-filters-panel { margin-top: 2px; border-top: 1px solid var(--border); padding-top: 8px; }
.cast-filter-rows { display: flex; flex-direction: column; gap: 6px; }
/* One filter = one line. nowrap keeps the "Filter by" picker pinned to the top
   row when its value control is a compound one (season + status); the triggers
   ellipsis rather than pushing each other onto a second line. */
.cast-filter-row { display: flex; gap: 6px; align-items: center; flex-wrap: nowrap; }
.cast-filter-row .filter-select { flex: 0 0 auto; max-width: 130px; }
.cast-filter-value { flex: 1; min-width: 0; }
/* Multi value picker = a .filter-select trigger over a floating tagPicker (never
   grows the row, unlike the inline list it replaced). Selector strength beats the
   130px cap the rule above puts on the row's field picker. */
.cast-filter-row .cast-filter-dd-trigger { flex: 1 1 auto; width: 100%; min-width: 0; max-width: none; }
.cast-filter-dd-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Season-qualified status filter (item 10): season picker + "Status:" + statuses, one line. */
.cast-filter-seasonstatus { display: flex; align-items: center; gap: 6px; width: 100%; min-width: 0; }
.cast-filter-seasonstatus .filter-select { flex: 1 1 auto; min-width: 0; max-width: none; }
.cast-filter-seasonstatus .cast-filter-dd-trigger { flex: 1 1 auto; min-width: 0; width: auto; }
.cast-filter-inline-label { flex: 0 0 auto; font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
/* Save-as-set footer + saved-set recall chips. */
.cast-filter-setname { flex: 1 1 auto; min-width: 0; font-size: var(--text-base); padding: 4px 6px; }
.cast-filter-sets { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding-bottom: 8px; margin-bottom: 2px; border-bottom: 1px dashed var(--border); }
.cast-filter-sets-label { font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); }
.cast-filter-set-chip { display: inline-flex; align-items: center; border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
.cast-filter-set { background: var(--surface); border: 0; padding: 2px 8px; font-size: var(--text-md); cursor: pointer; }
.cast-filter-set:hover { background: var(--surface-hover); }
.cast-filter-set-x { background: none; border: 0; padding: 2px 6px 2px 2px; color: var(--text-muted); cursor: pointer; font-size: var(--text-base); line-height: 1; }
.cast-filter-set-x:hover { color: var(--text); }

/* Collection mode (Slice 2) — moded center showing a set's members; whole body
   is the drop target (rail person → membership write). */
.cast-collection-header {
  display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 8px 14px; border-bottom: 1px solid var(--border); background: var(--surface); flex-shrink: 0;
}
.cast-collection-header .filter-select { width: auto; min-width: 120px; max-width: 240px; }
.cast-density-toggle { display: flex; gap: 4px; }
.cast-collection-body { flex: 1; min-height: 0; overflow: auto; padding: 14px; }
.cast-collection-body.drop-over { outline: 2px dashed var(--text-muted); outline-offset: -8px; background: var(--surface-hover); }

/* Collection config bar (Slice 2): sort/group/add-column + the reused filter. */
.cast-collection-config {
  padding: 8px 14px; border-bottom: 1px solid var(--border); background: var(--surface);
  display: flex; flex-direction: column; gap: 8px; flex-shrink: 0;
}
.cast-collection-config .filter-select { width: auto; min-width: 120px; max-width: 240px; }
/* Filters component sits inline on the sort/group row (no bar chrome of its own).
   Its rows panel is DETACHED (detachPanel) and placed as a full-width row below
   the toolbar (a direct child of the column-flex .cast-collection-config), so
   opening it never reflows the FILTERS / Fields buttons. */
.cast-collection-config .cast-filters { padding: 0; border: 0; gap: 0; }
.cast-collection-config > .cast-filters-panel { width: 100%; margin-top: 0; border-top: 1px solid var(--border); padding-top: 8px; }

/* Configurable column table (List density, first cut). */
/* min-width:max-content lets the grid grow past the pane (→ the body scrolls
   horizontally) instead of squeezing columns until cells collide. */
.cast-coltable { display: flex; flex-direction: column; font-size: var(--text-base); min-width: max-content; }
/* One track list for the whole table (set by renderColumnList as --cast-cols):
   the header and every row read the same property, so a drag-resize repaints
   them together and no row can compute a layout of its own. */
.cast-coltable-head, .cast-coltable-row { display: grid; gap: 8px; align-items: center; padding: 4px 8px; grid-template-columns: var(--cast-cols); }
.cast-coltable-head {
  position: sticky; top: 0; z-index: 1; background: var(--surface);
  border-bottom: 1px solid var(--border); font-weight: 600;
  box-shadow: 0 -14px 0 var(--surface); /* cap the scroll container's top padding */
}
.cast-coltable-head .cast-colh { display: flex; gap: 2px; align-items: center; min-width: 0; overflow: hidden; position: relative; }
/* Column resize grip — the right edge of a header cell. Sits in the gutter
   between tracks so it never covers a label; shows on hover of the header. */
/* Inside the cell, not straddling its edge: the header cell clips overflow, so a
   grip hanging outside it is invisible AND barely clickable. */
.cast-colresize {
  position: absolute; top: 0; bottom: 0; right: 0; width: 10px;
  cursor: col-resize; touch-action: none;
}
.cast-colresize::after {
  content: ''; position: absolute; top: 2px; bottom: 2px; right: 2px; width: 1px;
  background: var(--border); opacity: 0;
}
.cast-coltable-head:hover .cast-colresize::after { opacity: 1; }
.cast-colresize:hover::after, .cast-colresize.dragging::after { opacity: 1; background: var(--text); }
.cast-coltable-head .cast-colh .filter-select { width: 100%; min-width: 0; font-size: var(--text-md); }
.cast-coltable-row { border-bottom: 1px solid var(--border); cursor: default; }
.cast-coltable-row:hover { background: var(--surface-hover); }
.cast-coltable-row.is-selected { box-shadow: inset 3px 0 0 var(--text); }
.cast-colname { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
/* Off-screen twin of a name cell — measureNameColumn() sizes the Name track from
   the widest real name, so head and rows share one track list. Must keep the
   name cell's font metrics and padding-free box. */
.cast-coltable-measure {
  position: absolute; left: -9999px; top: 0; visibility: hidden; white-space: nowrap;
  font-weight: 600; font-size: var(--text-base); font-family: inherit;
}
/* The delete column is the last track and sits hard right (a 1fr spacer precedes
   it), so it lands in the same place whatever fields are showing. */
.cast-coltable-row > .cast-remove, .cast-coltable-row > .btn-icon-sm { justify-self: end; }
.cast-colcell { min-width: 0; overflow: hidden; }
.cast-colcell .cast-cell-ro, .cast-colcell .cast-cell-text { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cast-colcell .cast-cell-text { cursor: text; border-bottom: 1px dotted transparent; }
.cast-colcell .cast-cell-text:hover { border-bottom-color: var(--border); }
.cast-cell-edit { width: 100%; font-size: var(--text-dense); padding: 2px 4px; }
/* CSS-Fix-1b: the inline cell editors are .tag-picker triggers (buttons) now —
   same dense box, left-aligned value + caret. */
button.cast-cell-edit {
  display: flex; align-items: center; justify-content: space-between; gap: 4px;
  text-align: left; cursor: pointer; border-radius: 0;
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  font-family: inherit;
}
button.cast-cell-edit::after { content: '▾'; color: var(--text-muted); flex: 0 0 auto; }
button.cast-cell-edit:hover { border-color: var(--text-muted); }
button.cast-cell-edit:disabled { opacity: 0.5; cursor: default; }
.cast-colgroup { padding: 8px 8px 4px; }
.cast-colgroup-toggle { background: none; border: none; font-weight: 700; cursor: pointer; padding: 2px 0; color: var(--text); font-size: var(--text-base); }
.cast-info-seg { display: flex; gap: 6px; margin-bottom: 10px; }
.cast-eng-scope { font-weight: 600; }
.cast-appearance-season { font-weight: 600; min-width: 0; }

/* Multi-note field (item 6a) */
.cast-notes { display: flex; flex-direction: column; gap: 6px; width: 100%; }
.cast-notes-tabs { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.cast-notes-tab { background: var(--surface); border: 1px solid var(--border); border-radius: 4px; padding: 2px 8px; font-size: var(--text-md); cursor: pointer; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cast-notes-tab.is-active { background: var(--surface-hover); font-weight: 600; border-color: var(--text-muted); }
.cast-notes-add { background: none; border: 1px dashed var(--border); border-radius: 4px; padding: 2px 8px; font-size: var(--text-md); cursor: pointer; color: var(--text-muted); }
.cast-notes-add:hover { color: var(--text); border-color: var(--text-muted); }
.cast-notes-head { display: flex; gap: 6px; align-items: center; }
.cast-notes-label { flex: 1 1 auto; min-width: 0; font-size: var(--text-base); font-weight: 600; }
.cast-notes-body { width: 100%; font-size: var(--text-base); resize: vertical; }
.cast-notes-ro { display: flex; flex-direction: column; gap: 8px; }
.cast-notes-ro-label { font-weight: 600; font-size: var(--text-md); color: var(--text-muted); }
.cast-notes-ro-body { font-size: var(--text-base); white-space: pre-wrap; }
.cast-notes-body { min-height: 0; }

/* Read-only clamp-to-N-lines with a Show more/less toggle (auto-fit fields) */
.cast-clamp-wrap { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0; }
.cast-clamp { font-size: var(--text-base); line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; overflow: hidden; max-height: calc(var(--clamp-lines, 5) * 1.45em); }
/* Auto-linked URLs in read-only field/note values. */
.cast-link { color: var(--accent); text-decoration: underline; overflow-wrap: anywhere; }
.cast-link:hover { text-decoration: none; }
.cast-clamp.expanded { max-height: none; }
.cast-clamp-toggle { background: none; border: none; padding: 0; cursor: pointer; font-size: var(--text-md); color: var(--text-muted); text-decoration: underline; }
.cast-clamp-toggle:hover { color: var(--text); }

/* Reorderable field picker (item 6b) */
.cast-fieldpick { display: flex; flex-direction: column; gap: 6px; min-width: 220px; max-width: 280px; }
.cast-fieldpick-h { font-size: var(--text-sm); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); font-weight: 600; }
.cast-fieldpick-strip { display: flex; flex-direction: column; gap: 3px; }
.cast-fieldpick-chip { display: flex; gap: 6px; align-items: center; padding: 3px 6px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface); cursor: grab; }
.cast-fieldpick-chip.dragging { opacity: 0.5; }
.cast-fieldpick-grip { color: var(--text-muted); cursor: grab; font-size: var(--text-md); }
.cast-fieldpick-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-base); }
.cast-fieldpick-x { background: none; border: none; cursor: pointer; color: var(--text-muted); font-size: var(--text-body); line-height: 1; padding: 0 2px; }
.cast-fieldpick-x:hover { color: var(--text); }
.cast-fieldpick-search { width: 100%; font-size: var(--text-md); padding: 4px 6px; }
.cast-fieldpick-list { display: flex; flex-direction: column; gap: 2px; max-height: 200px; overflow-y: auto; }
.cast-fieldpick-add { background: none; border: none; text-align: left; cursor: pointer; padding: 3px 6px; font-size: var(--text-base); border-radius: 4px; color: var(--text); }
.cast-fieldpick-add:hover { background: var(--surface-hover); }

/* Person-record drag-to-reorder fields (item 6c, Supervisor+) */
.cast-fieldrow { display: flex; gap: 4px; align-items: flex-start; }
.cast-fieldrow > .form-row { flex: 1 1 auto; min-width: 0; }
.cast-fieldrow-grip { cursor: grab; color: var(--text-muted); font-size: var(--text-base); padding-top: 6px; user-select: none; }
.cast-fieldrow-grip:active { cursor: grabbing; }
.cast-fieldrow-grip:hover { color: var(--text); }
.cast-fieldrow.dragging { opacity: 0.4; }
/* Insertion line showing where the dragged field will land. */
.cast-fieldrow.drop-before { box-shadow: inset 0 2px 0 0 var(--text); }
.cast-fieldrow.drop-after { box-shadow: inset 0 -2px 0 0 var(--text); }

/* Engagement card episode list (F5 ladder): episode + per-episode status row.
   The status select is fixed-width (higher specificity than the global
   `.form-row select { width:100% }`) so the episode name keeps its space. */
.cast-eplist { display: flex; flex-direction: column; gap: 3px; }
.cast-eplist-row { display: flex; gap: 6px; align-items: center; }
.cast-eplist-row .cast-eplist-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-base); }
.cast-eplist-row.is-active { background: var(--surface-hover); border-radius: 4px; padding: 1px 4px; font-weight: 600; }
.cast-eplist .cast-eplist-row select { width: auto; flex: 0 0 auto; min-width: 96px; max-width: 130px; padding: 4px 6px; font-size: var(--text-md); }
/* The per-episode status trigger is deliberately tight — the episode NAME is what a
   producer scans; the status is a known short vocabulary (Joey 2026-07-22). */
.cast-eplist-row .cast-cell-edit { flex: 0 0 auto; max-width: 104px; padding: 3px 6px; font-size: var(--text-md); }
.cast-eplist-row .cast-cell-edit > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Fill + "add an episode" sit together at the FOOT of the list (Joey 2026-07-22) —
   both answer "what goes in this list". */
.cast-eplist-foot { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); }
.cast-eplist-fill { display: flex; gap: 6px; align-items: center; }
.cast-eplist-fill .hint { font-size: var(--text-sm); text-transform: uppercase; letter-spacing: 0.06em; }
.cast-eplist-fill select { width: auto; flex: 0 0 auto; min-width: 96px; max-width: 240px; padding: 4px 6px; font-size: var(--text-md); }
.cast-eplist-toggle { background: none; border: none; cursor: pointer; padding: 0; text-align: left; font-size: var(--text-sm); font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); }
.cast-eplist-toggle:hover { color: var(--text); }

/* Center breadcrumb (collection › person). */
.cast-breadcrumb { display: flex; gap: 6px; align-items: center; padding: 8px 14px; border-bottom: 1px solid var(--border); font-size: var(--text-base); flex-shrink: 0; }
.cast-crumb-link { background: none; border: none; color: var(--accent); cursor: pointer; padding: 0; font-size: var(--text-base); }
.cast-crumb-link:hover { text-decoration: underline; }
.cast-crumb-sep { color: var(--text-muted); }
.cast-crumb-cur { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Episodes rail — clickable season header (whole-season roster). */
.cast-rail-seasonhdr { background: var(--surface); border-top: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
.cast-rail-seasonhdr .name { font-weight: 700; }

/* LIST density = dense rows (avatar · name · status · hover-revealed remove). */
.cast-collection-list { display: flex; flex-direction: column; }
.cast-collection-row {
  display: flex; gap: 8px; align-items: center; padding: 5px 8px; cursor: pointer;
  border-bottom: 1px solid var(--border); font-size: var(--text-base);
}
.cast-collection-row:hover { background: var(--surface-hover); }
.cast-collection-row.is-selected { box-shadow: inset 3px 0 0 var(--text); }
.cast-collection-row .name { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.cast-collection-row .cast-remove { opacity: 0; flex: 0 0 auto; }
.cast-collection-row:hover .cast-remove, .cast-collection-row.is-selected .cast-remove { opacity: 1; }

/* Episode board — the all-episodes Collection grain: one drop-target card per
   episode in the active season. Drop feedback reuses the shared .drop-over the
   schedule's day cells use (schedule-drag.js sets it). */
.cast-board { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(var(--cast-tile-min, 220px), 1fr)); }
.cast-board-card { display: flex; flex-direction: column; gap: 6px; padding: 8px; border: 1px solid var(--border); background: var(--surface); }
.cast-board-card.drop-over { border-color: var(--text); background: var(--surface-hover); }
.cast-board-head { display: flex; align-items: center; gap: 6px; justify-content: space-between; }
/* The episode name leads the tile: bigger, one line, shrunk to fit by
   fitEpisodeTitles() rather than ellipsised (an episode code you can't read is
   worse than a slightly smaller one). */
.cast-board-title {
  padding: 0; border: 0; background: none; font-weight: 700; letter-spacing: 0; text-transform: none;
  font-size: var(--text-body); flex: 1; min-width: 0; display: block;
  white-space: nowrap; overflow: hidden; text-align: left;
}
.cast-board-title:hover { text-decoration: underline; }
/* One status per line — the tile is a status read, not a chip cloud. */
.cast-board-counts { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-height: 28px; }

/* Tile-size slider (ported from Info Stack's references toolbar). */
.cast-tilesize { display: flex; align-items: center; gap: 6px; }
.cast-tilesize-range { width: 110px; accent-color: var(--accent); cursor: pointer; }

/* Episode view, List density: a collapsible row per episode over its people. */
.cast-eplist-view { display: flex; flex-direction: column; gap: 6px; }
.cast-eprow { border: 1px solid var(--border); background: var(--surface); }
.cast-eprow.drop-over { border-color: var(--text); background: var(--surface-hover); }
.cast-eprow-head { display: flex; align-items: center; gap: 8px; padding: 6px 8px; }
.cast-eprow-caret {
  background: none; border: 0; padding: 0 2px; font-family: inherit; font-size: var(--text-base);
  color: var(--text-muted); flex: 0 0 auto; cursor: pointer;
}
.cast-eprow-caret:hover { color: var(--text); }
.cast-eprow-head .cast-board-title { flex: 0 1 auto; font-size: var(--text-base); }
.cast-eprow-people { border-top: 1px solid var(--border); padding: 4px 8px 6px; overflow-x: auto; }

/* Finder Sort / Group triggers: the trigger names the CONTROL, not the current
   value — the rail is narrow and the value shows the moment the picker opens. They
   are .btn buttons like SELECT / FILTERS / FIELDS beside them (uppercase, no caret)
   rather than value-showing pickers. */
.cast-rail-ctl { width: auto; flex: 0 0 auto; }
button.cast-rail-ctl::after { content: none; }
/* Group headers in the finder list. */
.cast-rail-group {
  padding: 6px 14px 2px; font-size: var(--text-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted);
  background: var(--surface); border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 1;
}

/* Appearances rows in the panel — season · status · summary, mirroring the record's
   aligned columns at panel width. */
.cast-appear-row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; padding: 3px 0; }
.cast-appear-season { font-weight: 600; font-size: var(--text-base); }
/* The summary wraps to its own line under the season + status, and lines up with
   them rather than with the caret. */
.cast-appear-summary { flex: 1 1 100%; padding-left: 18px; }
.cast-appear-caret {
  flex: 0 0 12px; width: 12px; background: none; border: 0; padding: 0;
  font-family: inherit; font-size: var(--text-xs); color: var(--text-muted); cursor: pointer;
}
.cast-appear-caret.is-empty { cursor: default; }
.cast-appear-caret:hover { color: var(--text); }
.cast-appear-episodes { padding: 2px 0 6px 18px; display: flex; flex-direction: column; gap: 2px; }
/* Panel photo control: the record's box at panel scale. */
#cast-person-body .cast-photo { width: 72px; height: 72px; }
#cast-person-body .cast-photo .cast-rec-avatar { width: 72px; height: 72px; font-size: var(--text-2xl); }

/* Inspector Details = the record's Details, in the panel (Joey 2026-07-22). The
   record scopes its two-column form rows to .cast-person-scroll; the panel gets the
   same treatment with a narrower label column, because 132px of label in a ~360px
   panel leaves nothing for the value. Sections, identity block and field widgets are
   the record's own classes, so the two surfaces can't drift apart. */
#cast-person-body .form-row { display: grid; grid-template-columns: 104px 1fr; gap: 4px 10px; align-items: start; margin: 0 0 7px; }
#cast-person-body .form-row > label { font-size: var(--text-dense); color: var(--text-muted); padding-top: 4px; }
#cast-person-body .form-row .hint { grid-column: 2; }
#cast-person-body .form-row input, #cast-person-body .form-row textarea { font-size: var(--text-base); }
/* Identity fields keep their label ABOVE the control, as in the record. */
#cast-person-body .cast-id-fields .form-row { grid-template-columns: 1fr; gap: 2px; }
#cast-person-body .cast-id-fields .form-row > label { padding-top: 0; }
#cast-person-body .cast-id-fields .form-row .hint { grid-column: 1; }
/* Identity in the panel: a smaller photo beside the fields (the record's is 128px). */
.cast-rec-identity-panel { display: flex; gap: 10px; align-items: flex-start; margin-bottom: 10px; }
.cast-rec-identity-panel .cast-id-photo { flex: 0 0 auto; }
.cast-rec-identity-panel .cast-id-fields { flex: 1; min-width: 0; }

/* Cross-app link mark (NSP: cross-link surfacing) — a small glyph on the row that
   already carries the fact: an episode a Bite transcript covers, a publication that
   is an Info Stack source. Sized down and muted so it annotates the row rather than
   competing with the status pill beside it. */
.cast-link-mark {
  margin-left: 6px; font-size: var(--text-xs); line-height: 1; opacity: 0.65;
  text-decoration: none; flex: 0 0 auto; cursor: help;
}
a.cast-link-mark { cursor: pointer; }
a.cast-link-mark:hover, .cast-link-mark:hover { opacity: 1; }

/* AI-provenance mark: a quiet ✦ after a field label whose value came from ✨ Enrich
   (fieldProvenance = 'ai-extracted'). Deliberately small and muted — it annotates
   a label, it doesn't compete with it. */
.field-ai {
  margin-left: 5px; color: var(--accent); opacity: 0.75;
  font-size: var(--text-xs); line-height: 1; cursor: help; vertical-align: super;
}

/* Inspector cockpit (Booking tab): Participation and Booking as separate,
   labeled sections in the one panel. */
.cast-cockpit-section + .cast-cockpit-section { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); }
.cast-cockpit-title { font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); margin-bottom: 6px; }

/* SMALL / LARGE density = square tiles in an auto-fill grid. */
.cast-collection-grid { display: grid; gap: 10px; }
.cast-collection-grid.tiles-tile { grid-template-columns: repeat(auto-fill, minmax(var(--cast-tile-min, 220px), 1fr)); }
.cast-tile {
  position: relative; aspect-ratio: 1; display: flex; flex-direction: column; overflow: hidden;
  border: 1px solid var(--border); background: var(--surface); cursor: pointer;
}
.cast-tile:hover { border-color: var(--text-muted); }
.cast-tile.is-selected { outline: 2px solid var(--text); outline-offset: -2px; }
.cast-tile-avatar { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; background: var(--accent-bg); color: var(--text-muted); font-weight: 700; font-size: var(--text-2xl); }
.cast-tile-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cast-tile-cap { padding: 5px 7px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 3px; }
.cast-tile-cap .name { font-size: var(--text-md); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cast-tile .cast-remove { position: absolute; top: 3px; right: 3px; opacity: 0; background: var(--surface); }
/* Tile (4c): photo + name by default; picked fields render under the name. Sizes
   to content with a fixed-height photo so fields fit without squishing the headshot
   (a tile-size slider is a future add). */
.cast-collection-grid.tiles-tile .cast-tile { aspect-ratio: auto; }
.cast-collection-grid.tiles-tile .ui-avatar-fill { flex: 0 0 auto; height: 140px; }
.cast-tile-field { font-size: var(--text-sm); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cast-tile:hover .cast-remove, .cast-tile.is-selected .cast-remove { opacity: 1; }

/* Right panel — Person peek + Quick-edit stack. */
.cast-peek-head { display: flex; gap: 10px; align-items: center; margin-bottom: 10px; }
.cast-peek-thumb { width: 44px; height: 44px; flex: 0 0 auto; border: 1px solid var(--border); background: var(--accent-bg); display: flex; align-items: center; justify-content: center; font-weight: 700; color: var(--text-muted); }
.cast-peek-thumb img { width: 100%; height: 100%; object-fit: cover; }
.cast-quick-field { border: 1px solid var(--border); padding: 8px; margin-bottom: 8px; }
.cast-quick-field-head { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.cast-quick-field-head .filter-select { width: auto; flex: 1; min-width: 0; }

.chip {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 0;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: var(--accent-bg);
  color: var(--text-muted);
  border: 1px solid var(--border);
}

.chip-accent { background: var(--accent-bg); color: var(--text); border-color: var(--text-muted); }
.chip-success { background: var(--tint-success); color: var(--success); border-color: var(--tint-success-strong); }
.chip-warning { background: var(--tint-warning); color: var(--warning); border-color: var(--tint-warning-strong); }
.chip-danger { background: var(--tint-danger); color: var(--danger); border-color: var(--tint-danger-strong); }
.chip-info { background: var(--tint-info); color: var(--info); border-color: var(--tint-info-strong); }
/* Booking axis "Booked" indicator — a chip (not a status pill), tinted with the
   same info tone the Schedule calendar uses for booked days, so the two axes read
   as distinct. Status-model refactor 2026-07-18. */
.cast-booked-chip { background: var(--tint-info); color: var(--info); border-color: var(--tint-info-strong); }
/* Tooltip (DESIGN-SYSTEM.md L2.7). Brand-styled hover/focus hint for icon buttons;
   replaces native title=. Positioned by ui.js tooltip() (position:fixed). */
.tooltip {
  position: fixed;
  z-index: var(--z-dropdown);
  max-width: 240px;
  padding: 4px 8px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-dropdown);
  border-radius: 0;
  font-size: var(--text-md);
  line-height: 1.35;
  pointer-events: none;
}
.tooltip[hidden] { display: none; }
/* Popover surface (DESIGN-SYSTEM.md L2.7). Shared dropdown/popover panel
   (same surface as .user-menu-panel); sizes 220/320/380. Positioned by
   ui.js popover() (position:fixed). */
.popover {
  position: fixed;
  z-index: var(--z-dropdown);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-dropdown);
  border-radius: 0;
}
.popover[hidden] { display: none; }
.popover-sm { width: 220px; }
.popover-md { width: 320px; }
.popover-lg { width: 380px; }
/* Empty-state variants (DESIGN-SYSTEM.md L2.8). Base .empty-state already shared. */
.empty-state .empty-state-icon { font-size: var(--text-h1); line-height: 1; display: block; margin-bottom: 8px; }
.empty-state.inline { padding: 24px 14px; border: none; background: transparent; }
.empty-state.error .empty-state-icon { color: var(--danger); }
/* Status pill (DESIGN-SYSTEM.md L2.13). One element + [data-role]; colors from L1.1 chip tokens. */
.status-pill {
  display: inline-block;
  padding: 3px 10px;
  border: 1px solid var(--border);
  border-radius: 0;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: var(--surface);
  color: var(--text-muted);
}
.status-pill[data-role="success"], .status-pill[data-role="approved"], .status-pill[data-role="deployed"] { background: var(--chip-success-bg); color: var(--success-text); border-color: var(--chip-success-border); }
.status-pill[data-role="warning"], .status-pill[data-role="draft"] { background: var(--chip-warning-bg); color: var(--warning-text); border-color: var(--chip-warning-border); }
.status-pill[data-role="danger"] { background: var(--chip-danger-bg); color: var(--danger-text); border-color: var(--chip-danger-border); }
.status-pill[data-role="info"], .status-pill[data-role="built"] { background: var(--chip-info-bg); color: var(--info-text); border-color: var(--chip-info-border); }
/* Field-level invalid state (DESIGN-SYSTEM.md L2.10). Used by formRow({error}). */
.form-row [aria-invalid="true"] { border-color: var(--danger); }
/* Removable chip (DESIGN-SYSTEM.md L2.6): .chip.is-removable + the .tag-remove × button (canonical = EH .tag-remove). Shared in Pass 5 S2. */
.chip.is-removable { padding-right: 6px; }
.tag-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: var(--text-body);
  line-height: 1;
  padding: 0;
  border-radius: 0;
}
.tag-remove:hover { color: var(--danger); background: var(--accent-bg); }

/* ---------- empty state ---------- */

.empty-state {
  text-align: center;
  padding: 48px 24px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: 0;
  color: var(--text-muted);
}

.empty-state h3 {
  color: var(--text);
  margin-bottom: 8px;
}

/* ---------- forms ---------- */

.form-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 16px;
}

.form-row label {
  font-size: var(--text-sm);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

.form-row input,
.form-row select,
.form-row textarea {
  width: 100%;
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0;
  color: var(--text);
  font-size: var(--text-lg);
  font-family: inherit;
  transition: border-color 0.15s;
}

.form-row input:focus,
.form-row select:focus,
.form-row textarea:focus {
  border-color: var(--text);
}

/* Picker trigger (CSS-Fix-1b) — the button that opens a .tag-picker where a
   native dropdown used to be. Carries the canonical field box itself so it
   works inside a .form-row AND standalone. Shared class with Project Stack +
   Info Stack; the box below deliberately matches .form-row's field box above.
   The ▾ stands in for the native arrow. */
.picker-trigger {
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0;
  color: var(--text);
  font-size: var(--text-lg);
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  transition: border-color 0.15s;
}
.picker-trigger::after { content: '\25BE'; opacity: 0.6; flex: 0 0 auto; }
.picker-trigger:hover { border-color: var(--text-muted); }
.picker-trigger:focus { border-color: var(--text); outline: none; }
.picker-trigger:disabled { opacity: 0.5; cursor: default; }
/* In a form row it fills the row, like the field it replaced. */
.form-row .picker-trigger { width: 100%; }
/* Compact variant for filter bars + inline cells (matches the old bare box). */
.picker-trigger.picker-sm { padding: 6px 8px; font-size: var(--text-md); }

/* Engagement Status workflow editor (Admin → Libraries): two reorderable, single-
   select ladders side by side + the links between them. */
.status-ladders { display: flex; gap: 16px; }
.status-ladder-col { flex: 1; min-width: 0; }
.status-ladder { display: flex; flex-direction: column; gap: 6px; }
.status-ladder-list { display: flex; flex-direction: column; gap: 4px; max-height: 260px; overflow-y: auto; }
.status-ladder-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  cursor: pointer;
}
.status-ladder-row.is-selected { border-color: var(--text); background: var(--bg); }
/* Reorder + action button clusters are intrinsic-width so a long label can't run
   under them — the label area takes the slack and wraps (at spaces, not mid-word). */
.status-ladder-grip,
.status-ladder-actions { display: flex; gap: 2px; flex: 0 0 auto; }
.status-ladder-label { flex: 1; min-width: 0; }
.status-ladder-name { overflow-wrap: break-word; line-height: 1.3; }
.status-ladder-link { font-size: var(--text-sm); opacity: 0.75; word-break: break-word; margin-top: 1px; }
.status-ladder-rename { flex: 1; min-width: 0; padding: 2px 4px; font-size: var(--text-lg); }
.status-links { display: flex; flex-direction: column; gap: 4px; }
.status-links-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

.form-row textarea {
  min-height: 80px;
  resize: vertical;
}

/* .hint moved to Brand/components.css (Gov-F3) — it was form-row-scoped here,
   so hints elsewhere rendered as body text. */

.form-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 16px;
}

/* ---------- sign-in / accept-invite ---------- */

.sign-in-shell {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--bg);
}

.sign-in-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 40px;
  width: 100%;
  max-width: 420px;
  text-align: center;
}

.sign-in-card .wordmark-slot {
  display: flex;
  justify-content: center;
  color: var(--text);
  margin-bottom: 10px;
}
.sign-in-card .wordmark-slot svg {
  display: block;
}

.sign-in-card h1 {
  text-align: center;
  margin-bottom: 4px;
  font-size: var(--text-h3);
}

.sign-in-card .subtitle {
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-md);
  text-transform: uppercase;
  letter-spacing: 0.15em;
  margin-bottom: 28px;
}

.divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 18px 0;
  color: var(--text-dim);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.divider::before, .divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

.google-btn {
  width: 100%;
  padding: 11px 16px;
  background: var(--bg);
  color: var(--text);
  font-weight: 600;
  border: 1px solid var(--border);
  border-radius: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: inherit;
  font-size: var(--text-base);
  transition: background 0.15s, border-color 0.15s;
}
.google-btn:hover {
  background: var(--surface-hover);
  border-color: var(--text-muted);
}
.google-btn:disabled { opacity: 0.6; cursor: not-allowed; }

.google-btn svg {
  width: 18px;
  height: 18px;
}

.email-form .btn-primary { width: 100%; }

.error-text {
  background: var(--tint-danger);
  color: var(--danger);
  border: 1px solid var(--tint-danger-strong);
  padding: 9px 12px;
  border-radius: 0;
  font-size: var(--text-base);
  margin-bottom: 12px;
}

.muted-link {
  color: var(--text-muted);
  font-size: var(--text-lg);
  text-decoration: underline;
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
}

/* ---------- modal ---------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: var(--scrim);
  display: grid;
  place-items: center;
  z-index: 100;
  padding: 24px;
}

.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  width: 100%;
  max-width: 520px;
  max-height: 90vh;
  overflow: auto;
}
/* Modal size tiers (DESIGN-SYSTEM.md L2.3). Default .modal = md (520). */
.modal-sm { max-width: 420px; }
.modal-lg { max-width: 720px; }
.modal-xl { max-width: 1100px; }
/* Side panel (DESIGN-SYSTEM.md L2.14). Docks left/right; slides via .open. */
.side-panel {
  position: fixed;
  top: 0;
  bottom: 0;
  /* Fluid, user-resizable width (DESIGN-SYSTEM.md L2.14 / D-L2.14.1). Per-panel
     --side-panel-width override; clamp() enforces the bounds so the resize drag
     only writes one variable. --width-side-panel (456px) is the default fallback. */
  --side-panel-width: var(--width-side-panel);
  --side-panel-min: 280px;
  --side-panel-max: 70vw;
  width: clamp(var(--side-panel-min), var(--side-panel-width), var(--side-panel-max));
  background: var(--surface);
  z-index: var(--z-dropdown);
  display: flex;
  flex-direction: column;
  transition: transform var(--motion-slow) ease;
}
/* Closed = slid fully off its docked edge via transform (self-tracks the
   variable width; no per-drag recompute). Open = translateX(0). */
.side-panel.dock-right { right: 0; border-left: 1px solid var(--border); box-shadow: var(--shadow-panel-right); transform: translateX(100%); }
.side-panel.dock-right.open { transform: translateX(0); }
/* L2.22: position:fixed ignores the body inset, so without --rail-inset the
   panel would sit UNDER the rail while its in-flow sibling's margin-left (which
   is content-box relative) double-counted the same 48px — an overlap and a dead
   gap at once. --rail-inset is 0 unless the rail is mounted. */
.side-panel.dock-left { left: var(--rail-inset); border-right: 1px solid var(--border); box-shadow: var(--shadow-panel-left); transform: translateX(-100%); }
.side-panel.dock-left.open { transform: translateX(0); }
/* Resize handle on the panel's inner edge (col-resize); makeResizable() wires the drag. */
.side-panel-resize { position: absolute; top: 0; bottom: 0; width: 6px; z-index: 1; cursor: col-resize; background: transparent; transition: background 80ms; }
.side-panel.dock-right .side-panel-resize { left: -3px; }
.side-panel.dock-left .side-panel-resize { right: -3px; }
.side-panel-resize:hover, .side-panel-resize.dragging { background: var(--text-muted); }
body.side-panel-resizing { cursor: col-resize; user-select: none; }
body.side-panel-resizing * { user-select: none !important; }
.side-panel-header { position: sticky; top: 0; display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid var(--border); background: var(--surface); }
.side-panel-header .side-panel-title { font-weight: 700; flex: 1; min-width: 0; }
.side-panel-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 16px; }
.side-panel-footer { position: sticky; bottom: 0; padding: 12px 16px; border-top: 1px solid var(--border); background: var(--surface); }

.modal-header {
  padding: 20px 24px;
  border-bottom: 1px solid var(--border);
}
.modal-header h2 {
  margin: 0;
  font-size: var(--text-base);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text);
}

.modal-body { padding: 24px; }

.modal-error {
  margin: 0 24px 14px;
  background: var(--tint-danger);
  color: var(--danger);
  border: 1px solid var(--tint-danger-strong);
  padding: 9px 12px;
  border-radius: 0;
  font-size: var(--text-base);
}

.modal-footer {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding: 16px 24px;
  border-top: 1px solid var(--border);
}

.modal-text { margin: 0; color: var(--text); }

/* ---------- toast ---------- */

#toast-container {
  position: fixed;
  bottom: 24px;
  right: 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 200;
}

.toast {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 10px 14px;
  color: var(--text);
  font-size: var(--text-base);
  animation: toast-in 200ms ease;
  min-width: 220px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.toast-info { border-left: 3px solid var(--text); }
.toast-success { border-left: 3px solid var(--success); }
.toast-error { border-left: 3px solid var(--danger); }
.toast-warning { border-left: 3px solid var(--warning); }
/* × dismiss button on every toast (DESIGN-SYSTEM.md L2.11). */
.toast-dismiss {
  margin-left: auto;
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: var(--text-body);
  line-height: 1;
  padding: 0;
}
.toast-dismiss:hover { color: var(--text); }

.toast-leaving {
  opacity: 0;
  transition: opacity 280ms;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ---------- project / season / episode views ---------- */

.tab-bar {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 24px;
}

.tab {
  padding: 12px 22px;
  cursor: pointer;
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  background: none;
  border-top: none;
  border-left: none;
  border-right: none;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  transition: color 0.15s, border-color 0.15s;
}
.tab:hover { color: var(--text); }

.tab.active {
  color: var(--text);
  border-bottom-color: var(--text);
}

.season-block {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  margin-bottom: 10px;
  overflow: hidden;
}

.season-header {
  padding: 16px 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  cursor: pointer;
  background: var(--surface);
  transition: background 0.15s;
}

.season-header:hover { background: var(--surface-hover); }

.season-header:focus-visible { outline: 2px solid var(--text); outline-offset: -2px; }

.season-header .title {
  font-weight: 600;
  font-size: var(--text-body);
  letter-spacing: 0.02em;
}
.season-header .meta {
  color: var(--text-muted);
  font-size: var(--text-lg);
}

.season-caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  color: var(--text-muted);
  font-size: var(--text-base);
  margin-right: 4px;
  user-select: none;
}

.season-body {
  padding: 0 20px 18px;
  border-top: 1px solid var(--border);
}

.season-block.collapsed .season-body {
  display: none;
}

/* Project-level collapsible block — wraps a project's season blocks on
   BS home when the user has access to more than one project. Visually
   lighter than .season-block (no card chrome — just a clickable bar with
   the project name and a caret) so the seasons inside remain the visual
   focus. */
.project-block {
  margin-bottom: 18px;
}
.project-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  margin: 0 0 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  cursor: pointer;
  user-select: none;
  transition: background 0.15s;
}
.project-toggle:hover { background: var(--surface-hover); }
.project-toggle:focus-visible { outline: 2px solid var(--text); outline-offset: -2px; }
.project-toggle .title {
  font-weight: 700;
  font-size: var(--text-base);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.project-toggle .meta {
  color: var(--text-muted);
  font-size: var(--text-base);
}
.project-block.collapsed .project-body { display: none; }

.episode-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
  gap: 12px;
}
.episode-row:last-child { border-bottom: none; }

.episode-code {
  font-family: var(--font-mono);
  color: var(--text-muted);
  margin-right: 8px;
  font-size: var(--text-lg);
}

.episode-title { color: var(--text); }

/* ---------- table ---------- */

table.list {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border);
}
table.list th,
table.list td {
  padding: 12px 14px;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
table.list tr:last-child td { border-bottom: none; }
table.list th {
  color: var(--text-muted);
  font-weight: 600;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: var(--bg);
}

/* L2.5 density modifier — compact rows for high-density tables. */
table.list.table-compact td { padding: 6px 10px; }

/* .th-sortable moved to Brand/components.css (Gov-F1) — this app's copy predated
   the shared primitive. The one local need it still carries: talent names must
   not wrap in the header. */
.th-sortable { white-space: nowrap; }

/* ---------- loading ---------- */

.loading {
  color: var(--text-muted);
  padding: 24px;
  text-align: center;
}

/* ---------- utility ---------- */

.row { display: flex; gap: 8px; align-items: center; }
.row-between { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.spacer { flex: 1; }
.muted { color: var(--text-muted); }
.dim { color: var(--text-dim); }
.mt-1 { margin-top: 8px; }

/* Secondary / metadata text — canonical muted body (L1.2 type scale).
   Context-scoped variants (.page-header .meta, .season-header .meta, etc.)
   override size where they need to; this is the default for bare .meta. */
.meta {
  font-size: var(--text-base);
  color: var(--text-muted);
  line-height: 1.5;
}
.mt-2 { margin-top: 16px; }
.mt-3 { margin-top: 24px; }
.mb-1 { margin-bottom: 8px; }
.mb-2 { margin-bottom: 16px; }
.mb-3 { margin-bottom: 24px; }

/* ---------- user-menu dropdown (BRANDING.md §6 nav ladder) ---------- */

.user-menu-dropdown {
  position: relative;
}

.user-menu-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  border: 1px solid var(--navy-border);
  color: var(--navy-text);
  font-family: inherit;
  font-size: var(--text-md);
  font-weight: 600;
  padding: 6px 12px;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  transition: border-color 0.15s;
}
.user-menu-trigger:hover { border-color: var(--navy-text); }

.user-menu-trigger .avatar {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--navy-border);
  color: var(--navy-text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  overflow: hidden;
}
.user-menu-trigger .avatar img {
  width: 100%; height: 100%; object-fit: cover;
}

.user-menu-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 220px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  z-index: 50;
  display: none;
  box-shadow: var(--shadow-dropdown);
}
.user-menu-panel.open { display: block; }

.user-menu-panel .menu-header {
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.user-menu-panel .menu-header .name { font-weight: 600; color: var(--text); }
.user-menu-panel .menu-header .email { font-size: var(--text-md); color: var(--text-muted); }

/* Current Org row — Session 3 of multi-tenant foundation (2026-05-20). */
.user-menu-panel .menu-current-org {
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-sm);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  cursor: default;
  user-select: none;
}
.user-menu-panel .menu-current-org.is-switchable { cursor: pointer; }
.user-menu-panel .menu-current-org.is-switchable:hover { background: var(--surface-hover); }
.user-menu-panel .menu-current-org .current-org-name { color: var(--text); margin-left: 2px; }
.user-menu-panel .menu-current-org .chevron { float: right; font-size: var(--text-xs); }
.user-menu-panel .menu-current-org-list { padding: 4px 0; border-bottom: 1px solid var(--border); }
.user-menu-panel .menu-current-org-list[hidden] { display: none; }
.user-menu-panel .menu-current-org-list button {
  padding-left: 28px; font-size: var(--text-sm); font-weight: 500;
}
.user-menu-panel .menu-current-org-list button.is-current::before {
  content: '✓'; margin-left: -14px; margin-right: 6px; color: var(--accent);
}

.user-menu-panel a, .user-menu-panel button {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  font-family: inherit;
  font-size: var(--text-md);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text);
  padding: 12px 16px;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s;
}
.user-menu-panel a:hover, .user-menu-panel button:hover {
  background: var(--surface-hover);
  text-decoration: none;
}
/* When the user menu sits inside `.app-header nav` (e.g. admin pages), the
   generic `.app-header nav a` colour (muted navy) would otherwise win on
   specificity and wash the dropdown links out light. Pin them to the canonical
   dark text so the menu reads the same on every page. (2026-05-29) */
.app-header nav .user-menu-panel a,
.app-header nav .user-menu-panel button {
  color: var(--text);
}

/* ---------- responsive ---------- */

@media (max-width: 768px) {
  .app-header { padding: 12px 20px; }
  .app-header .brand .app-label { display: none; }
  .hero { padding: 36px 20px 28px; }
  .hero-controls { position: static; justify-content: center; margin-bottom: 18px; }
  .hero-logo svg { height: 72px; }
  .container, .container-narrow { padding: 20px 16px; }
  .card-grid { grid-template-columns: 1fr; }
}


/* ---------- Research Stack — episode workspace (1A) ---------- */

/* The two-pane workspace fills the viewport below the slim header. */
.episode-workspace {
  display: flex;
  align-items: stretch;
  /* Fill from the workspace's actual top (below header + ep-strip) to the
     viewport bottom. --rs-sources-top is measured by JS; 100px fallback =
     56px header + 44px ep-strip. Exact height lets the PDF reader fill it. */
  height: calc(100vh - var(--rs-sources-top, 100px));
  width: 100%;
  overflow: hidden;
  background: var(--bg);
}

/* Sources pane = canonical .side-panel.dock-left (DESIGN-SYSTEM.md L2.14 /
   D-L2.14.1). The primitive owns position/width/border/surface/flex-column/
   slide + the resize handle. These are the RS-specific overrides: clear the
   56px slim header (primitive is top:0/bottom:0), the default fluid width, and
   clip the inner scroll. drop-overlay anchors to this now-fixed panel. */
#sources-pane {
  --side-panel-width: 24%;
  /* Start below ALL fixed bars (slim header 56px + ep-strip 44px = 100px).
     JS measures the workspace top into --rs-sources-top so this stays correct
     if the header stack changes height (e.g. when filters move into it).
     bottom:0 from the .side-panel primitive fills the rest. */
  top: var(--rs-sources-top, 100px);
  overflow: hidden;
}
.sources-pane-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  user-select: none;
}
.sources-pane-header .pane-title {
  font-weight: 700;
  font-size: var(--text-base);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.sources-pane-actions { display: flex; align-items: center; gap: 6px; }

/* 1c — Sources ⇄ Pages segmented toggle + page-thumbnail rail. */
.rail-toggle {
  display: flex;
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
}
.rail-toggle-btn {
  flex: 1;
  padding: 6px 10px;
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  font-family: inherit;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  cursor: pointer;
  user-select: none;
}
.rail-toggle-btn + .rail-toggle-btn { border-left: none; }
.rail-toggle-btn:hover { color: var(--text); }
.rail-toggle-btn.active { background: var(--text); color: var(--bg); border-color: var(--text); }

/* Cast finder chrome only — the context bar already names the project/season, so
   the finder drops its title row: row 1 is the collapse carat + the entity
   toggle, row 2 is search + the "+ Add" split button. Scoped to the cast-*
   classes so Info's and Bite's rails are untouched. */
.cast-finder-head { justify-content: flex-start; gap: 8px; padding: 8px 14px; }
.cast-finder-head .rail-toggle { flex: 1; min-width: 0; padding: 0; border-bottom: none; }
/* Double-class so this wins over the later .sources-search column layout. */
.sources-search.cast-finder-search { flex-direction: row; align-items: center; }
.sources-search.cast-finder-search input[type="search"] { flex: 1; min-width: 0; }
.cast-add-split { display: flex; flex-shrink: 0; }
.cast-add-split .cast-add-primary { padding-left: 10px; padding-right: 10px; font-size: var(--text-lg); }

.rail-pages {
  display: none;
  flex: 1;
  overflow-y: auto;
  padding: 12px;
}
/* In Pages mode, the sources-browsing controls give way to the thumbnails. */
.sources-pane.rail-mode-pages .rail-pages { display: block; }
.sources-pane.rail-mode-pages .url-add-box,
.sources-pane.rail-mode-pages .sources-search,
.sources-pane.rail-mode-pages .sources-controls,
.sources-pane.rail-mode-pages .sources-scope-row,
.sources-pane.rail-mode-pages .upload-tray,
.sources-pane.rail-mode-pages .sources-list { display: none !important; }

.rail-pages-empty { padding: 24px 12px; text-align: center; }
.page-thumb {
  cursor: pointer;
  margin-bottom: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  padding: 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.page-thumb:hover { border-color: var(--text-muted); }
.page-thumb.active { outline: 2px solid var(--text); outline-offset: -1px; }
.page-thumb-canvas-wrap {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 48px;
  background: var(--surface);
}
.page-thumb-canvas-wrap canvas {
  max-width: 100%;
  height: auto;
  display: block;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);  /* ds-allow: one-off shadow */
}
.page-thumb-label { font-size: var(--text-sm); color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* Small icon-weight + button — sits in the pane header */
.btn-icon {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  width: 28px;
  height: 28px;
  font-size: var(--text-body);
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.btn-icon:hover { background: var(--surface-hover); }
.btn-icon:disabled { opacity: 0.5; cursor: not-allowed; }

/* URL paste box — persistent affordance above the search */
.url-add-box {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.url-add-box input[type="url"] {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 6px 10px;
  font-size: var(--text-base);
  font-family: inherit;
}
.url-add-box input[type="url"]:focus { border-color: var(--text-muted); }
.url-add-box input[type="url"]::placeholder { color: var(--text-muted); font-style: italic; }
.url-add-box .btn-icon { flex-shrink: 0; }

/* Search + chips block, inside the sources pane */
.sources-search {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}
.sources-search input[type="search"] {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 6px 10px;
  font-size: var(--text-base);
  font-family: inherit;
}
.sources-search input[type="search"]:focus { border-color: var(--text-muted); }
.tag-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.tag-chip {
  background: var(--accent-bg);
  color: var(--text-muted);
  font-size: var(--text-sm);
  padding: 3px 8px;
  border: 1px solid transparent;
  cursor: pointer;
  user-select: none;
}
.tag-chip:hover { color: var(--text); }
.tag-chip.active {
  background: var(--accent-bg);
  color: var(--text);
  border-color: var(--text-muted);
}
.tag-chips-empty {
  font-size: var(--text-sm);
  color: var(--text-muted);
  font-style: italic;
}

/* The scrollable list of source rows in the sources pane */
.sources-list {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.source-row {
  position: relative;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  padding: 12px 14px;
  user-select: none;
  transition: background 120ms ease, border-color 120ms ease;
}
.source-row:focus-visible { outline: 2px solid var(--text); outline-offset: -2px; }
.source-row-remove {
  position: absolute;
  top: 6px;
  right: 6px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  width: 20px;
  height: 20px;
  font-size: var(--text-body);
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 80ms;
  padding: 0;
}
.source-row:hover .source-row-remove,
.source-row.selected .source-row-remove,
.source-row:focus-within .source-row-remove { opacity: 1; }
.source-row-remove:hover {
  color: var(--danger);
  border-color: var(--danger);
  background: var(--surface);
}
.source-row:hover { background: var(--surface-hover); }
.source-row.selected { background: var(--accent-bg); border-left: 3px solid var(--text); padding-left: 11px; }
.source-row-title {
  color: var(--text);
  font-weight: 600;
  font-size: var(--text-lg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 1J-b polish — AI status pill next to the Description heading in the viewer. */
.viewer-section-heading {
  display: flex;
  align-items: center;
  gap: 8px;
}
.viewer-section-heading h4 { margin: 0; }
/* .ai-pill retired Pass 5 S6 → .status-pill[data-role] + ui.js statusPill(). */

/* 1J-b polish — "(AI)" tag next to field labels in the edit modal. */
.ai-field-tag {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 0 4px;
  margin-left: 6px;
  border-radius: 0;
  background: var(--chip-success-bg);
  color: var(--success-text);
  border: 1px solid #86efac;  /* ds-allow: success-feedback tint */
  vertical-align: 1px;
}

.source-row-meta { font-size: var(--text-sm); margin-top: 2px; color: var(--text-muted); padding-right: 74px; }
/* Source-scope cascade toggle row (Phase 2). Always-visible primary control
   above the sources list. */
.sources-scope-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.sources-scope-label {
  font-size: var(--text-sm);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
/* Color-coded scope badge on each source row. Reuses the canonical
   .status-pill primitive (Episode = neutral / Season = info / Project =
   success); this rule only positions + sizes it for the row's bottom-right
   corner (the hover × lives top-right, so they never collide). */
.source-scope-badge {
  position: absolute;
  bottom: 9px;
  right: 12px;
  padding: 1px 7px;
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  pointer-events: none;
}
/* Source-scope picker (Phase 3) — canonical tag-picker single-select
   (DESIGN-SYSTEM.md L3.2). The chosen tier shows as a status-pill adjacent
   to a small "Change" trigger button. */
.scope-picker { display: flex; flex-direction: column; gap: 8px; }
.scope-picker-field { display: flex; align-items: center; gap: 8px; }
.scope-picker-field > span { font-size: var(--text-md); color: var(--text-muted); min-width: 58px; }
.scope-picker-field select { flex: 1; }
/* Archived checkbox in the edit-source modal — a plain inline checkbox + label.
   The more-specific selector beats `.form-row label` (which would otherwise
   uppercase + mute the text and break the layout). */
.form-row label.src-archived-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--text-base);
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--text);
  cursor: pointer;
}
.form-row label.src-archived-toggle input[type="checkbox"] { margin: 0; width: auto; }
/* Project-mode header in the ep-strip (source-scope Phase 4) — project title
   + season selector + "expand to episode" toggle, replacing the episode
   switcher when episode.html runs as the project research workspace. */
.project-mode-header { display: flex; align-items: center; gap: 18px; flex: 1; flex-wrap: wrap; }
.project-mode-title {
  font-size: var(--text-h3); font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.project-mode-season { font-size: var(--text-base); font-weight: 600; }
/* Control cell for the project Season/Episode filter rows (applied value +
   "Change" trigger) inside the sources-pane filter panel. */
.filter-row-control { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
/* "Project Research" entry on the Info Stack home — top of each project
   section, opens the project research workspace (source-scope Phase 4). */
.project-research-link {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 14px;
  margin-bottom: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  text-decoration: none;
  color: var(--text);
}
.project-research-link:hover { background: var(--surface-hover); border-color: var(--text-muted); }
.project-research-label { font-weight: 600; font-size: var(--text-lg); }
.project-research-hint { font-size: var(--text-md); color: var(--text-muted); }
.source-row-summary {
  font-size: var(--text-md);
  color: var(--text-muted);
  font-style: italic;
  margin-top: 4px;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.source-row.selected .source-row-summary { color: var(--text); }

.sources-empty {
  padding: 24px 14px;
  font-size: var(--text-base);
  color: var(--text-muted);
  text-align: center;
}

/* Sources panel collapse/expand (D-L2.14.1). The drag-resize divider + the
   narrow/wide preset were retired — the panel is now a .side-panel.dock-left
   with an edge resize handle (makeResizable). The viewer shifts to clear the
   open panel; its margin tracks the live (resizable) width via --rs-sources-w,
   falling back to the panel's default clamped width before JS sets it. */
body.rs-sources-open .viewer-pane {
  margin-left: var(--rs-sources-w, clamp(280px, 24%, 70vw));
}
/* Floating reopen affordance — sits just below the header stack (so it clears
   the ep-strip / episode switcher), top-left of the viewer. Only visible when
   the panel is collapsed. (Interim placement; a header-integrated control can
   come with the future header-filter work.) */
/* Vertically centered in the viewer's 28px top padding (midpoint = +14px,
   pulled back by half its own height) so the gap to the header above and the
   source title below is even, regardless of button height. */
#open-sources-btn { position: fixed; top: calc(var(--rs-sources-top, 100px) + 14px); left: 8px; transform: translateY(-50%); z-index: var(--z-dropdown); display: none; }
body:not(.rs-sources-open) #open-sources-btn { display: inline-flex; }
@media (max-width: 720px) {
  #sources-pane { --side-panel-max: calc(100vw - var(--rail-inset)); }
  body.rs-sources-open .viewer-pane { margin-left: 0; }
}

/* ---------- Right-side detail panel: Info | Highlights (1b) ----------
   Canonical .side-panel.dock-right. Mirrors #sources-pane: clears the fixed
   header stack via --rs-sources-top, fluid width, inner scroll clipped. The
   viewer-pane gains a matching margin-right when the panel is open. */
#info-panel {
  --side-panel-width: 26%;
  top: var(--rs-sources-top, 100px);
  overflow: hidden;
}
body.rs-info-open .viewer-pane {
  margin-right: var(--rs-info-w, clamp(280px, 26%, 70vw));
}
/* Floating reopen affordance, top-right of the viewer (mirrors #open-sources-btn). */
#open-info-btn {
  position: fixed;
  top: calc(var(--rs-sources-top, 100px) + 14px);
  right: 8px;
  transform: translateY(-50%);
  z-index: var(--z-dropdown);
  display: none;
}
body:not(.rs-info-open) #open-info-btn { display: inline-flex; }
@media (max-width: 720px) {
  #info-panel { --side-panel-max: calc(100vw - var(--rail-inset)); }
  body.rs-info-open .viewer-pane { margin-right: 0; }
}

/* Tabbed header — Info | Highlights span the width; close button on the end.
   min-height matches the PDF toolbar (46px) so the three column headers sit on
   one continuous band. */
.info-panel-header { padding: 0; align-items: stretch; min-height: 46px; box-sizing: border-box; }
.sources-pane-header { min-height: 46px; box-sizing: border-box; }
.info-tabs { display: flex; flex: 1; min-width: 0; }
.info-tab {
  flex: 1;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 13px 8px;
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
}
.info-tab:hover { color: var(--text); }
.info-tab.active { color: var(--text); border-bottom-color: var(--text); }
.info-tab-count { color: var(--text-muted); font-weight: 600; }
.info-tab.active .info-tab-count { color: var(--text-muted); }
#close-info-btn { align-self: center; margin: 0 8px; flex-shrink: 0; }
.info-tab-panel.hidden { display: none; }

/* Info tab — title block (source title + action buttons), leads the tab. */
.info-panel-titleblock { margin-bottom: 16px; }
.info-panel-title {
  font-size: var(--text-h3);
  font-weight: var(--weight-bold);
  line-height: 1.3;
  color: var(--text);
  margin-bottom: 10px;
  word-break: break-word;
}
.info-panel-titleblock .viewer-header-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Info tab — metadata definition grid. */
.info-meta-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 7px 12px;
  font-size: var(--text-base);
  margin: 2px 0 16px;
}
.info-meta-grid dt {
  color: var(--text-muted);
  white-space: nowrap;
}
.info-meta-grid dd { margin: 0; color: var(--text); word-break: break-word; }
.info-panel-thumb { margin: 0 0 14px; }
.info-panel-thumb img { max-width: 100%; height: auto; display: block; border: 1px solid var(--border); }

/* Highlights tab — view controls (sort / group) + mini-TOC. */
.hl-controls {
  display: flex;
  gap: 8px;
  margin: 10px 0;
}
.hl-controls .sources-toolbar-select { flex: 1; min-width: 0; }
.hl-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0 0 12px;
}
.hl-toc-label {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--text-muted);
  width: 100%;
  margin-bottom: 2px;
}
.hl-toc-chip {
  font-size: var(--text-sm);
  padding: 2px 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.hl-toc-chip:hover { color: var(--text); border-color: var(--text-muted); }
.hl-group-heading {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--text-muted);
  font-weight: var(--weight-bold);
  margin: 16px 0 8px;
}
.hl-group-heading:first-child { margin-top: 4px; }
/* Make the whole card clickable for jump-to (action buttons stopPropagation). */
.highlight-row { cursor: pointer; }
.highlight-row .highlight-actions { cursor: default; }
/* One-shot pulse for jump-to-and-pulse (cards + on-page overlay boxes). */
.highlight-row.pulse-once { animation: focus-pulse 1.6s ease-out 1; position: relative; z-index: 1; }
.pdf-highlight-box.pulse-once { animation: hl-box-pulse 1.6s ease-out 1; }
@keyframes hl-box-pulse {
  0%   { box-shadow: 0 0 0 0 var(--navy-pulse); }
  60%  { box-shadow: 0 0 0 10px var(--navy-pulse-0); }
  100% { box-shadow: 0 0 0 0 var(--navy-pulse-0); }
}
/* New-highlight slide-in (select→save lands a card in the Highlights tab). */
.highlight-row.slide-in { animation: hl-slide-in var(--motion-slow) ease-out 1; }
@keyframes hl-slide-in {
  0%   { opacity: 0; transform: translateY(-8px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* Viewer pane (right side) */
.viewer-pane {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: margin var(--motion-slow) ease;
  background: var(--bg);
}
/* Universal viewer top bar — present for every source type so the panel
   open/close affordances + header band look identical. Center holds view
   tools (PDF) or stays empty. 46px matches the panel headers (one band). */
.viewer-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  row-gap: 6px;
  padding: 8px 12px;
  min-height: 46px;
  box-sizing: border-box;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-shrink: 0;
}
.viewer-toolbar-tools {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  flex: 1;
  min-width: 0;
}
.viewer-reopen { font-size: var(--text-lg); flex-shrink: 0; }
body.rs-sources-open .viewer-reopen-sources { display: none; }
body.rs-info-open .viewer-reopen-info { display: none; }
/* The toolbar always carries the reopen buttons now — retire the floating ones. */
#open-sources-btn, #open-info-btn { display: none !important; }
/* Scroll region (second child of the pane). PDFs use .pdf-canvases directly. */
.viewer-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  scrollbar-gutter: stable; /* scrollbar toggling never shifts the reader width */
  padding: 28px 36px;
  /* Phase 5c — reading-appearance typeface cascades to the article masthead,
     body, and manual notes. Falls back to the default UI font when unset (e.g.
     book/other non-text viewers, which never set --reader-font). */
  font-family: var(--reader-font, var(--font));
}
.viewer-pane > .viewer-empty { flex: 1 1 auto; min-height: 0; }
.viewer-pane > .pdf-canvases { flex: 1 1 auto; min-height: 0; }
.viewer-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  text-align: center;
  color: var(--text-muted);
  gap: 8px;
}
.viewer-empty h3 { color: var(--text-muted); font-weight: var(--weight-semibold); font-size: var(--text-h3); }
.viewer-empty p { font-size: var(--text-base); max-width: 380px; }

.viewer-source-header {
  display: flex;
  flex-direction: column;
  gap: 6px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 14px;
  margin-bottom: 18px;
}
.viewer-source-title-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}
.viewer-source-title { font-size: var(--text-h2); font-weight: var(--weight-bold); color: var(--text); flex: 1; min-width: 0; }
.viewer-header-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.viewer-header-actions .btn-sm {
  font-size: var(--text-sm);
  padding: 4px 8px;
}
.viewer-source-meta { font-size: var(--text-md); color: var(--text-muted); display: flex; gap: 10px; flex-wrap: wrap; }
.viewer-source-meta .chip { font-size: var(--text-sm); }

/* Web source viewer (1C-1) */
/* .viewer-access-tier retired Pass 5 S6 → .status-pill[data-role] + ui.js statusPill(). */

.viewer-thumb {
  margin-top: 14px;
  max-width: 480px;
}
.viewer-thumb img {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--border);
}
.viewer-excerpt {
  font-size: var(--text-lg);
  line-height: 1.5;
  color: var(--text);
  padding: 12px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--text-muted);
}
.viewer-url-line {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.viewer-url-text {
  word-break: break-all;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

.viewer-ai-summary {
  font-size: var(--text-lg);
  font-style: italic;
  color: var(--text);
  line-height: 1.5;
  padding: 12px 16px;
  background: var(--accent-bg);
  border-left: 3px solid var(--text-muted);
}

.viewer-body-text {
  white-space: pre-wrap;
  font-family: inherit; /* 5c — inherits --reader-font from .viewer-scroll */
  font-size: var(--reader-size, var(--text-lg));
  line-height: var(--reader-leading, 1.5);
  color: var(--text);
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
}
/* In-app web body reader (Phase 4c) — a clean readable-article column over the
   stored plain-text body, with selection highlighting. */
.web-body-reader {
  max-width: 680px;
  margin: 8px auto 0;
  font-family: inherit; /* 5c — inherits --reader-font from .viewer-scroll */
  font-size: var(--reader-size, var(--text-lg));
  line-height: var(--reader-leading, 1.65);
  color: var(--text);
}
/* 4g(a) — web-article masthead (title + byline) above the body. */
.web-body-header {
  max-width: 680px;
  margin: 8px auto 0;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.web-body-hero {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 0 14px;
  border: 1px solid var(--border);
}
.web-body-title {
  font-size: 1.7em;
  line-height: 1.2;
  font-weight: 700;
  margin: 0 0 6px;
  color: var(--text);
}
.web-body-byline { font-size: var(--text-sm); color: var(--text-muted); }

/* Reading appearance (Aa) control — Phase 5c. Typeface / size / line spacing
   for the in-app text readers (web article body + manual notes). The popover
   surface comes from .popover. */
.reader-aa-btn { font-weight: 600; font-size: var(--text-md); }
.reader-aa-menu { display: flex; flex-direction: column; gap: 4px; padding: 8px 10px; }
.reader-aa-head {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 8px;
}
.reader-aa-head:first-child { margin-top: 0; }
.reader-aa-fonts { display: flex; flex-direction: column; gap: 4px; }
.reader-aa-font {
  text-align: left;
  padding: 6px 9px;
  background: var(--bg);
  border: 1px solid var(--border);
  cursor: pointer;
  font-size: var(--text-lg);
  color: var(--text);
}
.reader-aa-font:hover { border-color: var(--text-muted); }
.reader-aa-font.active { background: var(--text); color: var(--bg); border-color: var(--text); }
.reader-aa-stepper { display: flex; align-items: center; gap: 8px; }
.reader-aa-size-label {
  font-size: var(--text-md);
  color: var(--text);
  min-width: 44px;
  text-align: center;
}
.reader-aa-leadings { display: flex; gap: 4px; }
.reader-aa-lead {
  flex: 1;
  padding: 6px 4px;
  background: var(--bg);
  border: 1px solid var(--border);
  cursor: pointer;
  font-size: var(--text-md);
  color: var(--text);
}
.reader-aa-lead:hover { border-color: var(--text-muted); }
.reader-aa-lead.active { background: var(--text); color: var(--bg); border-color: var(--text); }
.reader-aa-foot { margin-top: 8px; border-top: 1px solid var(--border); padding-top: 8px; }
.reader-aa-reset {
  background: none;
  border: 0;
  cursor: pointer;
  font-size: var(--text-md);
  color: var(--text-muted);
  padding: 2px 0;
}
.reader-aa-reset:hover { color: var(--text); }
/* 4g(b) — inline placeholder shown when a hotlinked image fails to load. */
.web-body-img-failed {
  display: block;
  margin: 1em auto;
  padding: 10px 12px;
  border: 1px dashed var(--border);
  color: var(--text-muted);
  font-size: var(--text-sm);
  text-align: center;
}
.web-body-img-failed a { color: var(--text); }

.web-body-reader p { margin: 0 0 1em; }
/* 4d — reader-grade article HTML: images + structure restored. */
.web-body-reader img { max-width: 100%; height: auto; display: block; margin: 1em auto; }
.web-body-reader figure { margin: 1.25em 0; }
.web-body-reader figcaption { font-size: var(--text-sm); color: var(--text-muted); margin-top: 0.4em; text-align: center; }
.web-body-reader h1, .web-body-reader h2, .web-body-reader h3,
.web-body-reader h4, .web-body-reader h5, .web-body-reader h6 {
  line-height: 1.25; margin: 1.4em 0 0.5em; font-weight: 700;
}
.web-body-reader h1 { font-size: 1.6em; }
.web-body-reader h2 { font-size: 1.35em; }
.web-body-reader h3 { font-size: 1.15em; }
.web-body-reader ul, .web-body-reader ol { margin: 0 0 1em; padding-left: 1.5em; }
.web-body-reader li { margin: 0.25em 0; }
.web-body-reader blockquote {
  margin: 1.25em 0; padding: 0.25em 0 0.25em 1em;
  border-left: 3px solid var(--border); color: var(--text-muted); font-style: italic;
}
.web-body-reader a { color: var(--text); text-decoration: underline; }
.web-body-reader pre {
  white-space: pre-wrap; background: var(--surface); border: 1px solid var(--border);
  padding: 12px; font-size: var(--text-sm); overflow-x: auto;
}
.web-body-reader code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; }
.web-body-reader table { border-collapse: collapse; width: 100%; margin: 1em 0; font-size: var(--text-sm); }
.web-body-reader th, .web-body-reader td { border: 1px solid var(--border); padding: 6px 8px; text-align: left; }
.web-body-reader::selection,
.web-body-reader *::selection { background: rgba(11, 26, 50, 0.15); }  /* ds-allow: RS reader selection/body tint (feature) */
/* Stored-highlight overlay on the body — painted via the CSS Custom Highlight
   API (no DOM mutation), semi-transparent so text stays readable. */
::highlight(rs-body-yellow) { background-color: var(--hl-body-yellow); }
::highlight(rs-body-green)  { background-color: var(--hl-body-green); }
::highlight(rs-body-blue)   { background-color: var(--hl-body-blue); }
::highlight(rs-body-pink)   { background-color: var(--hl-body-pink); }
::highlight(rs-body-orange) { background-color: var(--hl-body-orange); }

.viewer-section { margin-top: 18px; }
/* Section-label eyebrow (L1.2 tokens). Shared treatment across the viewer's
   Description / URL / Highlights / Reference-images labels. */
.viewer-section h4 {
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 6px;
}

.viewer-actions { margin-top: 24px; display: flex; gap: 10px; }

/* Form-grid wrapper for stacked form-rows in modals */
.form-grid { display: flex; flex-direction: column; gap: 12px; }

/* ---------- Research Stack — PDF upload (1B-1) ---------- */

/* Drop overlay covers the sources pane while a file is being dragged in. */
.drop-overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  background: rgba(11, 26, 50, 0.92);  /* ds-allow: RS reader selection/body tint (feature) */
  border: 2px dashed var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none; /* prevents flicker; events bubble to .sources-pane */
}
.drop-overlay.hidden { display: none; }
.drop-overlay-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--text);
  padding: 24px;
  text-align: center;
}
.drop-overlay-icon {
  font-size: var(--text-3xl);
  line-height: 1;
}
.drop-overlay-text {
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: 0.02em;
}
.drop-overlay-hint {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Upload tray sits between the search and the sources list while uploads
   are in flight. Banner-styled so it's clearly a transient progress
   indicator, not a source row. Disappears when the last row resolves. */
.upload-tray {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--accent-bg);
}
.upload-tray.hidden { display: none; }
.upload-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px 8px;
  border: 1px solid var(--border);
  background: var(--surface);
}
.upload-row.failed { border-color: var(--danger); }
.upload-row-top {
  display: flex;
  align-items: center;
  gap: 8px;
}
.upload-row-label {
  font-size: var(--text-sm);
  color: var(--text-muted);
  font-style: italic;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
.upload-row-pct {
  font-size: var(--text-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.upload-row.failed .upload-row-pct { color: var(--danger); }
.upload-row-dismiss {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: var(--text-body);
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
}
.upload-row-dismiss:hover { color: var(--text); }
.upload-row-bar {
  height: 3px;
  background: var(--border);
  overflow: hidden;
}
.upload-row-bar-fill {
  height: 100%;
  width: 0%;
  background: var(--text);
  transition: width 120ms ease;
}
.upload-row.failed .upload-row-bar-fill { background: var(--danger); }

/* Loading / disabled states on the open-PDF link */
.btn.loading { opacity: 0.7; pointer-events: none; }
.btn.disabled { opacity: 0.5; pointer-events: none; }

/* ---------- Research Stack — highlights (1B-5) ---------- */

/* Shared color palette. Overlay variant is the on-canvas highlight (mixed
   into the page); solid variant is for chips + dots in the UI. */
.hl-color-yellow { --hl-bg: var(--hl-yellow-bg); --hl-solid: var(--hl-yellow-solid); }
.hl-color-green  { --hl-bg: var(--hl-green-bg); --hl-solid: var(--hl-green-solid); }
.hl-color-blue   { --hl-bg: var(--hl-blue-bg); --hl-solid: var(--hl-blue-solid); }
.hl-color-pink   { --hl-bg: var(--hl-pink-bg); --hl-solid: var(--hl-pink-solid); }
.hl-color-orange { --hl-bg: var(--hl-orange-bg); --hl-solid: var(--hl-orange-solid); }

/* On-canvas highlight boxes use the soft overlay variant. */
.pdf-highlight-box { background: var(--hl-bg); }

/* Floating selection toolbar appended to <body>. Pops up on selection in
   a PDF text layer. Five color swatches + close button. */
.hl-toolbar {
  position: absolute;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);  /* ds-allow: one-off shadow */
  user-select: none;
}
.hl-toolbar.hidden { display: none; }
.hl-toolbar-row { display: flex; align-items: center; gap: 4px; }
.hl-toolbar-sep { width: 1px; height: 20px; background: var(--border); margin: 0 2px; }
.hl-toolbar-swatch {
  width: 24px;
  height: 24px;
  border: 1px solid var(--border);
  background: var(--hl-solid, var(--hl-yellow-solid));
  cursor: pointer;
  padding: 0;
}
.hl-toolbar-swatch:hover { transform: scale(1.1); }
.hl-toolbar-btn {
  width: 26px;
  height: 24px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  cursor: pointer;
  font-size: var(--text-base);
  line-height: 1;
  padding: 0;
}
.hl-toolbar-btn:hover { background: var(--surface-hover); }
.hl-toolbar-cancel {
  width: 24px;
  height: 24px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  font-size: var(--text-lg);
  line-height: 1;
}
.hl-toolbar-cancel:hover { color: var(--text); }

/* Expandable annotate form (note + tags + color). */
.hl-toolbar-annotate { display: flex; flex-direction: column; gap: 6px; width: 240px; }
.hl-toolbar-annotate.hidden { display: none; }
.hl-annotate-dots { display: flex; gap: 4px; }
.hl-annotate-dot {
  width: 18px; height: 18px; border: 1px solid var(--border);
  background: var(--hl-solid, var(--hl-yellow-solid)); cursor: pointer; padding: 0;
}
.hl-annotate-dot.selected { outline: 2px solid var(--text); outline-offset: 1px; }
.hl-annotate-note, .hl-annotate-tags {
  width: 100%; box-sizing: border-box;
  border: 1px solid var(--border); background: var(--bg);
  font-family: inherit; font-size: var(--text-md); padding: 6px 8px; color: var(--text);
}
.hl-annotate-note { resize: vertical; }
.hl-annotate-actions { display: flex; justify-content: flex-end; }

/* Auto-highlight toggle in the Highlights tab. */
.hl-auto-toggle {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: var(--text-md); color: var(--text); cursor: pointer; margin: 0 0 10px;
}
.hl-auto-toggle .hl-auto-hint { flex-basis: 100%; margin-left: 22px; }

/* Tag chips on a highlight card. */
.highlight-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.highlight-tags.empty { display: none; }
.highlight-tag {
  font-size: var(--text-sm); padding: 1px 7px;
  background: var(--accent-bg); border: 1px solid var(--border); color: var(--text-muted);
}

/* ---------- References (1J-a Chunk 4a) ---------- */
.refs-section { margin-top: 20px; }
.refs-header {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 8px 0;
}
.refs-header h4 {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-muted);
}
.refs-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
}
.ref-tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ref-tile-thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--bg);
  border-radius: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ref-tile-thumb img {
  max-width: 100%;
  max-height: 100%;
  display: block;
}
.ref-tile-missing { padding: 8px; }
.ref-tile-caption {
  font-size: var(--text-base);
  font-weight: 500;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ref-tile-note {
  font-size: var(--text-md);
  background: var(--scrim-subtle);
  padding: 6px 8px;
  border-radius: 0;
}
.ref-tile-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.ref-tile-tag {
  display: inline-block;
  padding: 2px 8px;
  background: var(--glass-white-06);
  border: 1px solid var(--glass-white-12);
  border-radius: 0;
  font-size: var(--text-sm);
}
.ref-tile-meta { font-size: var(--text-sm); }

.ref-lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);  /* ds-allow: one-off scrim */
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  cursor: zoom-out;
}
.ref-lightbox img {
  max-width: 100%;
  max-height: 100%;
  display: block;
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.5);  /* ds-allow: one-off shadow */
}

/* ---------- References gallery modal (1J-a Chunk 4b) ---------- */
.ref-gallery-overlay {
  position: fixed;
  inset: 0;
  background: var(--scrim-black-strong);
  z-index: 900;
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 24px;
}
.ref-gallery-dialog {
  width: 100%;
  max-width: 1200px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.ref-gallery-header {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}
.ref-gallery-title {
  margin: 0;
  font-size: var(--text-h3);
  font-weight: 600;
}
.ref-gallery-meta { flex: 1; font-size: var(--text-base); }
.ref-gallery-close {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  font-size: var(--text-2xl);
  cursor: pointer;
  padding: 0 6px;
  line-height: 1;
}
.ref-gallery-close:hover { color: var(--text); }

.ref-gallery-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  align-items: center;
}
.ref-gallery-select {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 0;
  padding: 6px 10px;
  font: inherit;
  font-size: var(--text-md);
}
.ref-gallery-tag-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
/* .ref-gallery-tag-chip retired — now the shared .filter-chip (filterChip()). */
.ref-gallery-clear {
  background: transparent;
  border: 0;
  color: var(--accent);
  font: inherit;
  font-size: var(--text-md);
  cursor: pointer;
  text-decoration: underline;
  padding: 0;
  margin-left: auto;
}

.ref-gallery-grid {
  flex: 1;
  overflow-y: auto;
  padding: 16px 20px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}
.ref-gallery-empty {
  padding: 36px 20px;
  text-align: center;
  font-size: var(--text-lg);
}

.ref-gallery-tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ref-gallery-tile-thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--bg);
  border-radius: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ref-gallery-tile-thumb img {
  max-width: 100%;
  max-height: 100%;
  display: block;
}
.ref-gallery-tile-note {
  font-size: var(--text-md);
  background: var(--scrim-subtle);
  padding: 6px 8px;
  border-radius: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ref-gallery-tile-meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  font-size: var(--text-sm);
}
.ref-gallery-tile-cat {
  display: inline-block;
  padding: 2px 8px;
  background: rgba(88, 194, 147, 0.12);  /* ds-allow: success-feedback tint */
  color: var(--accent);
  border-radius: 0;
  font-size: var(--text-xs);
  font-weight: 600;
}
.ref-gallery-tile-source { font-size: var(--text-xs); }
.ref-gallery-tile-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.ref-gallery-tile-tag {
  display: inline-block;
  padding: 1px 7px;
  background: var(--glass-white-06);
  border: 1px solid var(--glass-white-12);
  border-radius: 0;
  font-size: var(--text-xs);
}
.ref-gallery-tile-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: var(--text-sm);
  margin-top: auto;
  padding-top: 4px;
}
.ref-gallery-tile-open {
  color: var(--accent);
  text-decoration: none;
}
.ref-gallery-tile-open:hover { text-decoration: underline; }

/* Highlights section appended below the PDF reader. */
.highlights-section {
  margin-top: 20px;
}
.highlights-section.hidden { display: none; }
/* In the detail panel the tab name already labels the section. */
.info-tab-panel .highlights-section { margin-top: 0; }
.info-tab-panel .highlights-header { padding-top: 0; }
.highlights-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 12px;
}
.highlights-header h4 {
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0;
}
.hl-color-chips {
  display: flex;
  gap: 4px;
  margin-left: auto;
}
.hl-color-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 22px;
  padding: 0 6px;
  border: 1px solid var(--border);
  background: var(--hl-solid);
  color: var(--scrim-black-strong);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  user-select: none;
}
.hl-color-chip.active { outline: 2px solid var(--text); }

.highlights-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.highlight-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--hl-solid);
}
/* Action row sits below the highlight text (1b feedback), left-aligned. */
.highlight-row .highlight-actions { justify-content: flex-start; flex-wrap: wrap; }
.highlight-swatch { display: none; } /* left border carries the color */
.highlight-body { flex: 1; min-width: 0; }
.highlight-text {
  font-size: var(--text-base);
  color: var(--text);
  line-height: 1.5;
  white-space: pre-wrap;
}
.highlight-meta {
  margin-top: 4px;
  font-size: var(--text-sm);
}
.highlight-note {
  margin-top: 6px;
  font-size: var(--text-md);
  color: var(--text);
  font-style: italic;
  padding: 6px 8px;
  background: var(--accent-bg);
  border-left: 2px solid var(--text-muted);
}
.highlight-note.empty { display: none; }

/* ── Focus mode (Milestone 1G follow-up, 2026-05-23) ────────────────
   Triggered by ?highlight=<id> in the URL — typically from a footnote
   citation click. The cited highlight gets a brief pulse + lifted
   shadow; other highlights collapse to a one-line preview so the eye
   lands on the focused one even on heavy-highlight sources.
   scroll-margin-top reserves space for the sticky .app-header so
   scrollIntoView doesn't slide the ep-strip under it. */
.highlight-row.focused {
  box-shadow: 0 0 0 2px var(--navy-bg), 0 4px 12px var(--navy-shadow);
  position: relative;
  z-index: 1;
  animation: focus-pulse 1.6s ease-out 1;
  scroll-margin-top: 140px;
}
@keyframes focus-pulse {
  0%   { box-shadow: 0 0 0 0    var(--navy-pulse), 0 0 0 2px var(--navy-bg); }
  60%  { box-shadow: 0 0 0 14px var(--navy-pulse-0), 0 0 0 2px var(--navy-bg); }
  100% { box-shadow: 0 0 0 2px var(--navy-bg), 0 4px 12px var(--navy-shadow); }
}
.highlight-row.collapsed-other {
  padding-top: 6px;
  padding-bottom: 6px;
}
.highlight-row.collapsed-other .highlight-text {
  font-size: var(--text-md);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.highlight-row.collapsed-other .highlight-meta { display: none; }
.highlight-row.collapsed-other .highlight-note { display: none; }
.highlight-row.collapsed-other .highlight-actions { opacity: 0.6; }

.focus-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--accent-bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--navy-bg);
  border-radius: 0;
  padding: 8px 12px;
  margin-bottom: 10px;
  font-size: var(--text-base);
}
.focus-banner .focus-banner-text { color: var(--text); flex: 1; min-width: 0; }
.focus-banner .focus-banner-actions { display: flex; gap: 6px; flex-shrink: 0; }
.focus-banner .focus-banner-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  font-size: var(--text-md);
  padding: 3px 10px;
  border-radius: 0;
  cursor: pointer;
  font-family: inherit;
}
.focus-banner .focus-banner-btn:hover { background: var(--surface); border-color: var(--text); }
.highlight-note-edit {
  margin-top: 6px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.highlight-note-input {
  width: 100%;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 6px 8px;
  font-family: inherit;
  font-size: var(--text-md);
  resize: vertical;
}
.highlight-note-input:focus { border-color: var(--text-muted); }

.highlight-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.btn-icon-sm {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  width: 22px;
  height: 22px;
  font-size: var(--text-md);
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.btn-icon-sm:hover { background: var(--surface-hover); color: var(--text); }
.btn-icon-sm.btn-icon-danger:hover { color: var(--danger); border-color: var(--danger); }
.btn-icon-sm:disabled { opacity: 0.5; cursor: not-allowed; }

/* Mini palette inside each highlight row (recolor without opening an edit). */
.hl-mini-palette { display: inline-flex; gap: 2px; }
.hl-mini-dot {
  width: 14px;
  height: 14px;
  background: var(--hl-solid);
  border: 1px solid var(--border);
  cursor: pointer;
  display: inline-block;
}
.hl-mini-dot:hover { transform: scale(1.15); }
.hl-mini-dot.current { outline: 2px solid var(--text); outline-offset: -1px; }

/* ---------- Research Stack — inline PDF reader (1B-2) ---------- */

/* PDF view-tool styles live in the universal .viewer-toolbar / .viewer-toolbar-tools
   (see the viewer-pane block). These are the individual control elements. */
.pdf-page-indicator {
  font-size: var(--text-md);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  min-width: 38px;
  text-align: center;
}
.pdf-page-nav {
  display: flex;
  align-items: center;
  gap: 4px;
}
.pdf-page-nav.hidden { display: none; }
.pdf-page-nav .btn-icon {
  width: 26px;
  height: 26px;
  font-size: var(--text-body);
}
/* Zoom controls — − 110% + with the % doubling as a reset-to-fit button. */
.pdf-zoom-controls {
  display: flex;
  align-items: center;
  gap: 4px;
}
.pdf-zoom-controls .btn-icon {
  width: 26px;
  height: 26px;
  font-size: var(--text-body);
  line-height: 1;
}
.pdf-zoom-label {
  min-width: 46px;
  padding: 3px 4px;
  font-size: var(--text-md);
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid transparent;
  font-family: inherit;
  cursor: pointer;
  user-select: none;
}
.pdf-zoom-label:hover { color: var(--text); border-color: var(--border); }
/* Fit width | Fit page — segmented pair. */
.pdf-fit-group { display: inline-flex; }
.pdf-fit-btn {
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  padding: 4px 10px;
  font-size: var(--text-sm);
  font-family: inherit;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.pdf-fit-btn + .pdf-fit-btn { border-left: none; }
.pdf-fit-btn:hover { color: var(--text); background: var(--surface-hover); }
.pdf-fit-btn.active {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
}
.pdf-reader-spacer { flex: 1; }
.pdf-download {
  font-size: var(--text-md);
  white-space: nowrap;
}

.pdf-canvases {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  background: var(--bg);
  overflow: auto;
  /* Reserve the scrollbar gutter so toggling the vertical scrollbar never
     changes the content width. Without this, resizing a side panel to a
     threshold width makes a Fit-width re-render cross the scrollbar on/off
     point, which changes clientWidth → the ResizeObserver re-fits → toggles
     again: a flicker of the scrollbar + repainted highlights. A stable gutter
     keeps the fit width constant and breaks the loop. */
  scrollbar-gutter: stable;
}
/* Page wrapper holds canvas + highlight overlay + text layer in stacked
   absolute positioning. Wrapper sets its own width/height in JS to match
   the rendered CSS dimensions. */
.pdf-page-wrapper {
  position: relative;
  margin: 0 auto;
  background: var(--surface);
  box-shadow: 0 1px 3px var(--scrim-subtle);
  flex-shrink: 0;
}
.pdf-page-canvas {
  display: block;
  max-width: 100%;
  background: var(--surface);
}

/* Highlight overlay layer sits between the canvas and the text layer. */
.pdf-highlight-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.pdf-highlight-box {
  position: absolute;
  pointer-events: auto;
  border-radius: 0;
  mix-blend-mode: multiply;
}

/* 7a — merge mode (highlights list) */
.hl-merge-toggle.active { background: var(--text); color: var(--bg); border-color: var(--text); }
.hl-merge-check { margin: 3px 6px 0 0; flex-shrink: 0; cursor: pointer; }
.highlight-row.merge-picked { outline: 2px solid var(--text); outline-offset: -2px; }
.hl-merge-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  margin-bottom: 8px;
  background: var(--accent-bg);
  border: 1px solid var(--border);
}
.hl-merge-bar-label { font-size: var(--text-md); color: var(--text-muted); line-height: 1.35; }
.hl-merge-bar-actions { display: flex; gap: 6px; flex-shrink: 0; }

/* 7a — boundary drag-adjust overlay (sits above the PDF text layer) */
.pdf-page-wrapper.adjusting .pdf-highlight-layer { opacity: 0.2; }
.pdf-adjust-layer {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  overflow: hidden;
}
.pdf-adjust-box {
  position: absolute;
  background: var(--hl-bg);
  mix-blend-mode: multiply;
  outline: 1px solid rgba(0, 0, 0, 0.28);  /* ds-allow: one-off shadow */
}
.pdf-adjust-handle {
  position: absolute;
  width: 14px;
  margin-left: -7px;
  pointer-events: auto;
  cursor: ew-resize;
  z-index: 5;
}
.pdf-adjust-handle::before { /* the vertical edge bar */
  content: '';
  position: absolute;
  left: 6px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--text);
}
.pdf-adjust-handle::after { /* the round knob */
  content: '';
  position: absolute;
  left: 0;
  width: 14px;
  height: 14px;
  background: var(--text);
  border: 2px solid var(--bg);
  border-radius: 50%;
}
.pdf-adjust-handle.start::after { top: -7px; }
.pdf-adjust-handle.end::after { bottom: -7px; }
.pdf-adjust-bar {
  position: fixed;
  top: 64px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: var(--z-dropdown);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-dropdown);
  padding: 6px 10px;
  max-width: 90vw;
}
.pdf-adjust-bar-text {
  font-size: var(--text-md);
  color: var(--text);
  max-width: 360px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Text layer overlay — PDF.js renders absolutely-positioned spans here. The
   text is transparent so the canvas remains visible; selection highlights it. */
.pdf-text-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  opacity: 1;
  line-height: 1;
  text-align: initial;
  forced-color-adjust: none;
  z-index: 2;
}
.pdf-text-layer > :is(span, br) {
  color: transparent;
  position: absolute;
  white-space: pre;
  cursor: text;
  transform-origin: 0% 0%;
}
.pdf-text-layer span.markedContent { top: 0; height: 0; }
.pdf-text-layer ::selection {
  background: rgba(96, 165, 250, 0.4); /* soft blue selection */  /* ds-allow: RS reader selection/body tint (feature) */
}
/* PDF.js selection-quality sentinel. Parked below the layer; while a drag is
   in progress (.selecting, toggled in JS) it expands to full height so the
   browser fills the selection line-to-line across the absolutely-positioned
   spans instead of only the lines the cursor crosses. */
.pdf-text-layer .endOfContent {
  display: block;
  position: absolute;
  inset: 100% 0 0;
  z-index: -1;
  cursor: default;
  user-select: none;
}
.pdf-text-layer.selecting .endOfContent { top: 0; }
.pdf-reader-error {
  color: var(--danger);
  font-size: var(--text-base);
  padding: 16px;
  text-align: center;
}

/* ---------- Research Stack — library controls (1D) ---------- */

/* The whole controls block sits between the search input and the source list. */
.sources-controls {
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.sources-toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
}
.sources-toolbar-select {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 4px 8px;
  font-family: inherit;
  font-size: var(--text-md);
  flex-shrink: 0;
  max-width: 130px;
}
.sources-toolbar-select:focus { border-color: var(--text-muted); }
.btn-icon.active {
  background: var(--text);
  color: var(--bg);
}

/* Saved views menu (Phase 5a) — the popover surface comes from .popover. */
.saved-views-menu {
  display: flex;
  flex-direction: column;
  padding: 6px 0;
  max-height: 60vh;
  overflow-y: auto;
}
.saved-views-head {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 4px 14px 6px;
}
.saved-views-empty {
  padding: 8px 14px;
  font-size: var(--text-md);
  color: var(--text-muted);
  line-height: 1.4;
}
.saved-view-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding-right: 6px;
}
.saved-view-row:hover { background: var(--surface-hover); }
.saved-view-row.active { background: var(--accent-bg); }
.saved-view-apply {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  padding: 7px 8px 7px 14px;
  font-family: inherit;
  font-size: var(--text-base);
  color: var(--text);
}
.saved-view-icon { flex-shrink: 0; font-size: var(--text-base); }
.saved-view-name {
  flex: 0 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.saved-view-row.active .saved-view-name { font-weight: 600; }
.saved-view-by {
  flex-shrink: 0;
  margin-left: auto;
  padding-left: 8px;
  font-size: var(--text-sm);
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 42%;
}
.saved-view-actions {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.saved-view-row:hover .saved-view-actions,
.saved-view-row:focus-within .saved-view-actions { opacity: 1; }
.saved-view-mini {
  background: none;
  border: 0;
  cursor: pointer;
  padding: 4px 5px;
  font-size: var(--text-md);
  line-height: 1;
  color: var(--text-muted);
}
.saved-view-mini:hover,
.saved-view-mini.active { color: var(--text); }
.saved-view-mini.danger:hover { color: var(--danger); }
.saved-views-foot {
  border-top: 1px solid var(--border);
  margin-top: 4px;
  padding-top: 4px;
}
.saved-views-action {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  padding: 8px 14px;
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--text);
}
.saved-views-action:hover { background: var(--surface-hover); }
.saved-views-action-icon { font-size: var(--text-lg); }

/* Save / edit-view modal form */
.saved-view-form { display: flex; flex-direction: column; }
.saved-view-form .modal-input {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 7px 9px;
  font-family: inherit;
  font-size: var(--text-base);
}
.saved-view-hint {
  font-size: var(--text-sm);
  color: var(--text-muted);
  padding: 2px 0 0 24px;
  line-height: 1.4;
}

/* Expandable filter panel (toggle via the ▾ button) */
.filter-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  background: var(--accent-bg);
}
.filter-panel.hidden { display: none; }
.filter-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.filter-row-actions { flex-direction: row; justify-content: flex-end; gap: 8px; }
.filter-label {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.filter-select {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 5px 8px;
  font-family: inherit;
  font-size: var(--text-md);
  width: 100%;
}
.filter-select:focus { border-color: var(--text-muted); }
/* CSS-Fix-1b: the filter-bar controls are .tag-picker triggers (buttons) now —
   same box, left-aligned label + caret. */
button.filter-select {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-2); text-align: left; cursor: pointer; border-radius: 0;
}
button.filter-select::after { content: '▾'; color: var(--text-muted); flex: 0 0 auto; }
button.filter-select:hover { border-color: var(--text-muted); }
button.filter-select.filter-active { border-color: var(--accent); }
.filter-chip-group {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
/* Filter toggle chip (DESIGN-SYSTEM.md L2.6) — canonical, built by ui.js
   filterChip() as <button aria-pressed>. Active state keyed on [aria-pressed],
   not a .active class. Supersedes the old .ref-gallery-tag-chip / .refs-tag-chip
   green-rounded toggle styles (Pass 5 filter-chip consolidation, 2026-05-29). */
.filter-chip {
  display: inline-block;
  background: var(--accent-bg);
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 0;
  font: inherit;
  font-size: var(--text-sm);
  padding: 3px 8px;
  cursor: pointer;
  user-select: none;
}
.filter-chip:hover { color: var(--text); }
.filter-chip[aria-pressed="true"] {

/* Segmented control (DESIGN-SYSTEM.md L2.2 / L3.2) — mutually-exclusive inline
   choice, built by ui.js segmented() as a role="radiogroup" of role="radio"
   buttons (native radios are retired, so the a11y contract is rebuilt there).
   The canonical replacement for a radio group when the options must stay
   VISIBLE: short side-by-side labels, dense per-row choices, or option cards
   whose description carries a consequence (cost, destructive overwrite).
   Use .tag-picker (single) for 1-of-many from a long vocab; .checkbox for
   independent on/off. */
.segmented { display: inline-flex; }
.segmented-option {
  font: inherit; font-size: var(--text-md); color: var(--text-muted);
  background: var(--bg); border: 1px solid var(--border); border-radius: 0;
  padding: var(--space-2) var(--space-3); cursor: pointer; margin: 0;
}
.segmented-option:hover { color: var(--text); border-color: var(--text-muted); }
.segmented-option[aria-checked="true"] {
  position: relative; z-index: 1; color: var(--text); background: var(--accent-bg);
  border-color: var(--accent); font-weight: var(--weight-semibold);
}
/* Compact: joined buttons — collapse the shared border, raise the active one. */
.segmented-compact .segmented-option + .segmented-option { margin-left: -1px; }
/* Cards: stacked options, each showing label + description. */
.segmented-cards { display: flex; flex-direction: column; gap: var(--space-2); align-items: stretch; }
.segmented-cards .segmented-option {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1);
  text-align: left; padding: var(--space-3);
}
.segmented-option-label { font-size: var(--text-base); font-weight: var(--weight-semibold); }
.segmented-option-desc { font-size: var(--text-md); font-weight: var(--weight-regular); color: var(--text-muted); line-height: 1.5; }

  color: var(--text);
  border-color: var(--text-muted);
  font-weight: 600;
}
.filter-tag-area {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.filter-toggle-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-md);
  cursor: pointer;
}
.filter-toggle-label input[type="checkbox"] { margin: 0; }

/* Active filters chip row (always rendered above the list when any active) */
.active-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 8px 14px;
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.active-filters.hidden { display: none; }
/* Active-filter pills + the match-mode indicator now use chip() / chip({removable})
   (Pass 5 filter-chip consolidation, 2026-05-29); the bespoke .active-filter-chip*
   block was retired. .active-filter-clear (the Clear-all button) stays. */
.active-filter-clear {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: var(--text-sm);
  padding: 2px 8px;
  cursor: pointer;
  margin-left: 4px;
}
.active-filter-clear:hover { color: var(--text); border-color: var(--text-muted); }

/* Group headers in the source list */
/* Collapsible grouped sections (2b). The header is a real <button> so it's
   keyboard-operable; clicking it collapses the group's rows with a smooth
   grid-rows animation. Collapsed state is remembered per episode + grouping. */
/* Compact-density source rows */
.source-row.compact {
  padding: 6px 14px;
}
.source-row.compact .source-row-title {
  font-size: var(--text-base);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.source-row.compact .source-row-meta { display: none; }

/* Archived source rows — muted to indicate they're soft-deleted */
.source-row.archived {
  opacity: 0.55;
}
.source-row.archived .source-row-title::before {
  content: '🗄 ';
  font-size: var(--text-sm);
}

/* Edit modal — long form needs vertical room */
.form-grid .form-row > input + input,
.form-grid .form-row > select + input {
  margin-top: 4px;
}

/* Tag picker — popover list body (DESIGN-SYSTEM.md L2.2 / L5.2 S8). Rendered
   inside a .popover by ui.js tagPicker(): the popover supplies the surface,
   this is the header / search / scrollable-list layout. Modeled on the Bite
   Stack dropdown picker. Replaced the 1D 3-region inline pattern (retired
   2026-05-29, Pass 5 S8) — the edit-source modal now uses tagPicker(). */
.tag-picker { display: flex; flex-direction: column; max-height: 340px; overflow: hidden; }
.tag-picker-header {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  padding: 8px; border-bottom: 1px solid var(--border);
}
.tag-picker-new {
  font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); cursor: pointer; background: none;
  border: 1px dashed var(--border); padding: 3px 8px; transition: color 0.15s, border-color 0.15s;
}
.tag-picker-new:hover { color: var(--text); border-color: var(--text-muted); }
.tag-picker-new-input {
  flex: 1; min-width: 0; box-sizing: border-box; background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 0; padding: 4px 8px; font-size: var(--text-md);
}
.tag-picker-new-input:focus { border-color: var(--text-muted); outline: none; }
.tag-picker-done {
  font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); cursor: pointer; background: none; border: none;
  padding: 3px 8px; transition: color 0.15s;
}
.tag-picker-done:hover { color: var(--text); }
.tag-picker-search { padding: 8px; border-bottom: 1px solid var(--border); }
.tag-picker-search input {
  width: 100%; box-sizing: border-box; background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 0; padding: 5px 8px; font-size: var(--text-md);
}
.tag-picker-search input:focus { border-color: var(--text-muted); outline: none; }
.tag-picker-search input::placeholder { color: var(--text-muted); opacity: 0.5; }
.tag-picker-list { overflow-y: auto; flex: 1; }
.tag-picker-group {
  font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); padding: 6px 12px 2px; opacity: 0.6;
}
.tag-picker-item {
  padding: 5px 12px; cursor: pointer; font-size: var(--text-sm); color: var(--text);
  transition: background 0.1s; border-bottom: 1px solid var(--surface-hover);
}
.tag-picker-item:hover { background: var(--accent-bg); }
.tag-picker-item.active { background: var(--accent-bg); color: var(--text-muted); }
.tag-picker-item.active::after { content: ' ✓'; opacity: 0.6; }

/* Tag input — free-text chip editor (DESIGN-SYSTEM.md L2.2 / L5.2 S9). Bordered
   box of chip() atoms + an inline field, built by ui.js tagInput(). The ×
   (.tag-remove) ships with chip(). */
.tag-input {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 6px 8px; border: 1px solid var(--border); background: var(--bg);
  min-height: 40px; cursor: text;
}
.tag-input:focus-within { border-color: var(--text); }
.tag-input-field {
  flex: 1; min-width: 140px; border: none; background: transparent;
  padding: 4px 2px; font-size: var(--text-lg); width: auto; color: var(--text);
}
.tag-empty { color: var(--text-muted); font-size: var(--text-base); padding: 4px 2px; flex: 1; }

/* Category control in the edit modal — grouped wrapper with dropdown +
   clearly-labeled "+ Create new" input. Hide the dropdown half if the
   project has no categories yet so the create path is the only option. */
.edit-category-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.edit-category-select { width: 100%; }
.edit-category-or {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  text-align: center;
  color: var(--text-muted);
}
.edit-category-create-label {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.edit-category-create-label-text {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
}
.edit-category-new-input {
  width: 100%;
}

/* 1K — Quick Capture modal (shared across Inbox page, references page,
   episodes-list home). */
.qc-backdrop {
  position: fixed; inset: 0;
  background: var(--scrim-black);
  display: flex; align-items: center; justify-content: center;
  z-index: 1000;
}
.qc-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 18px;
  width: min(480px, 92vw);
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.qc-tabs { display: flex; gap: 6px; }
.qc-tab {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 12px;
  border-radius: 0;
  cursor: pointer;
  font-size: var(--text-md);
}
.qc-tab.active {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
  font-weight: 600;
}
.qc-body { display: flex; flex-direction: column; gap: 8px; }
.qc-body label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: var(--text-md); color: var(--text-muted);
}
.qc-body input[type="text"],
.qc-body input[type="url"] {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 6px 8px;
  font-size: var(--text-base);
}
.qc-body input[type="file"] { color: var(--text); font-size: var(--text-md); }
.qc-actions { display: flex; justify-content: flex-end; gap: 8px; }
.qc-error { color: var(--danger-text); font-size: var(--text-md); }

/* ── Public citation landing page (Milestone 1G) ───────────────────── */
.cite-public-main { padding-top: 32px; padding-bottom: 64px; }
.cite-public-loading,
.cite-public-error {
  text-align: center;
  color: var(--text-muted);
  padding: 64px 16px;
  font-size: var(--text-lg);
}
.cite-public-error { color: var(--danger-text); }
.cite-public-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 28px 32px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);  /* ds-allow: one-off shadow */
}
.cite-public-eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin-bottom: 10px;
}
.cite-public-title {
  margin: 0 0 18px 0;
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: 1.3;
  color: var(--text);
}
.cite-public-cta {
  display: inline-block;
}
.cite-public-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 18px;
}
.cite-public-section { margin-top: 22px; }
.cite-public-section h2 {
  font-size: var(--text-base);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  margin: 0 0 8px 0;
  font-weight: 600;
}
.cite-public-summary {
  font-size: var(--text-lg);
  line-height: 1.55;
  color: var(--text);
  margin: 0;
}
.cite-public-highlight { /* container styling — passage gets the color */ }
.cite-public-context {
  font-size: var(--text-base);
  color: var(--text-muted);
  font-style: italic;
  margin: 4px 0;
  line-height: 1.5;
}
.cite-public-passage {
  border-left: 4px solid var(--border);
  background: var(--accent-bg);
  margin: 10px 0;
  padding: 12px 16px;
  font-size: var(--text-body);
  line-height: 1.55;
  color: var(--text);
  border-radius: 0;
}
/* When a highlight color is set, lift the swatch into the left border so
   readers see the producer's color cue without losing legibility. */
.cite-public-passage.hl-color-yellow { border-left-color: var(--hl-solid); background: var(--hl-bg); }
.cite-public-passage.hl-color-green  { border-left-color: var(--hl-solid); background: var(--hl-bg); }
.cite-public-passage.hl-color-blue   { border-left-color: var(--hl-solid); background: var(--hl-bg); }
.cite-public-passage.hl-color-pink   { border-left-color: var(--hl-solid); background: var(--hl-bg); }
.cite-public-passage.hl-color-orange { border-left-color: var(--hl-solid); background: var(--hl-bg); }
.cite-public-passage-meta { margin-top: 4px; }
.cite-public-footer { margin-top: 28px; }
.cite-public-footer .meta {
  font-size: var(--text-md);
  color: var(--text-muted);
  line-height: 1.5;
}
@media (max-width: 600px) {
  .cite-public-card { padding: 20px 18px; }
  .cite-public-title { font-size: var(--text-h2); }
}


/* Shared sub-part tag-assignment widget (Brand/field-tag-assign.js) — a labeled,
   controlled tag group (Brands on an engagement). Distinct from the engagement's
   own fields via the bold label + accent left border (FIELDS-AND-SECTIONS.md §4). */
.field-tag-assign {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 2px 0 2px 8px; border-left: 2px solid var(--text-muted); margin: 6px 0;
}
.field-tag-assign-label { font-size: var(--text-md); color: var(--text-muted); font-weight: 600; }
.field-tag-assign-label::after { content: ':'; }
.field-tag-assign-chips { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.field-tag-assign-empty { font-size: var(--text-md); color: var(--text-muted); font-style: italic; }
.field-tag-assign .chip-stale { opacity: 0.65; border-style: dashed; }

/* Shared field-definition editor (Brand/field-editor.js) — hosted inside the
   Field Library create/edit modal (showFooter:false; the modal owns Save/Cancel).
   Transparent container (the modal body is the box); compact option rows. */
.field-editor { display: flex; flex-direction: column; gap: 10px; }
.field-editor .form-row { margin: 0; }
/* Type picker trigger (Brand/field-editor.js) — the button that replaced the
   native type dropdown (DESIGN-SYSTEM.md L2.2). Matches the .form-row field box
   so the row is unchanged; the ▾ stands in for the native arrow. */
.field-editor-type-trigger {
  width: 100%;
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0;
  color: var(--text);
  font-size: var(--text-lg);
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  transition: border-color 0.15s;
}
.field-editor-type-trigger:hover { border-color: var(--text-muted); }
.field-editor-type-trigger:focus { border-color: var(--text); outline: none; }
.field-editor-type-trigger::after { content: '\25BE'; opacity: 0.6; }
.field-editor-options { display: flex; flex-direction: column; gap: 4px; }
.field-editor-option { display: flex; align-items: center; gap: 4px; }
.field-editor-option-name { flex: 1; min-width: 0; }
.field-editor-add { margin-top: 2px; }
.field-editor-add-input { width: 100%; }
.field-editor-flags { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.field-editor-toggle { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; font-size: var(--text-lg); }
.field-editor-toggle-hint { color: var(--text-muted); font-size: var(--text-md); }
.field-editor-error { color: var(--danger); font-size: var(--text-md); }

/* Tool logo in the slim header (2026-07-20). Replaces the Story // Stack
   wordmark + text label with the tool's own logo, and it is NOT a link: the
   rail's home icon is the way back, so the header logo has no job as one
   (BRANDING §6). Sized to the 22px the wordmark occupied so the header's
   vertical rhythm is unchanged. The artwork is predominantly white with two
   navy accent paths — designed for this navy strip. */
.app-header .brand .brand-logo-tool {
  display: flex;
  align-items: center;
}
.app-header .brand .brand-logo-tool img {
  height: 22px;
  width: auto;
  display: block;
}
