/* =====================================================================
 * Cell Agent — single-chat UI (Claude / OpenAI style).
 *
 * Layout: centered column, max 760px, sticky composer at bottom.
 * Messages, tool cards, plan checklists, and approval cards all live in
 * a single linear feed so the user reads one continuous conversation.
 * ===================================================================== */

* { box-sizing: border-box; }

:root {
  /* Page background is pure white now — see app-layout below for the
     thin neutral gutter that lets the cards still read as cards. */
  --bg:             #ffffff;
  --fg:             #1b1b1a;
  --fg-muted:       #6b6b68;
  --fg-faint:       #9a9a97;
  /* Cool slate greys — replace the warm cream tones that read as
     "waxy yellow" against a pure-white page. */
  --border:         #e5e7eb;
  --border-strong:  #d1d5db;
  --user-bg:        #2f6feb;
  --user-fg:        #ffffff;
  --card-bg:        #ffffff;
  --card-hover:     #f3f4f6;
  --code-bg:        #0f1115;
  --code-fg:        #d1d5db;
  --code-accent:    #7dd3fc;
  --ok:             #1a7f37;
  --err:            #9b1c1c;
  --err-bg:         #fde8e8;
  --warn:           #b45309;
  --warn-bg:        #fef6d8;
  --plan-border:    #c9e5cf;
  --plan-bg:        #f3faf4;
  --approval-border:#fcd34d;
  --approval-bg:    #fff7d6;
  --accent:         #2f6feb;
  --accent-bg:      #eff4ff;
  --accent-fg:      #1a3a80;
}

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, sans-serif;
  background: var(--bg);
  color: var(--fg);
  font-size: 15px;
  line-height: 1.55;
}

.chat-body-root {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  height: 100vh;
  overflow: hidden;
  position: relative;
}

/* ---------- top bar ---------- */

.top-bar {
  display: flex;
  align-items: center;
  /* Brand cluster on the left, session controls on the right —
     ``space-between`` once again, and now the LEFT slot is
     populated (brand + title + toggle) so the right slot anchors
     to the trailing edge as expected. */
  justify-content: space-between;
  padding: 10px 18px;
  border-bottom: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: saturate(180%) blur(12px);
  flex-shrink: 0;
  gap: 16px;
}
/* Left cluster: brand → app title → standalone toggle (only when
   sidebar is expanded). When the sidebar is COLLAPSED the brand
   button itself becomes the toggle (the standalone one is
   suppressed via ``.is-sidebar-collapsed .sidebar-toggle``), so
   the cluster's width stays the same regardless of state and the
   right-side controls don't shift on toggle.

   Width pinned to ``calc(sidebar-width − top-bar-padding-left)`` =
   202px so the cluster's right edge lands exactly where the
   sidebar column ends. ``padding-right: 4px`` keeps the collapse
   toggle near (but a few pixels further-right than) the Workspace
   refresh button below — the user judged the strict-center
   alignment to feel cramped against the column boundary, so we
   give the toggle a small breathing offset. */
.top-bar-left {
  display: flex;
  align-items: center;
  gap: 10px;
  width: calc(220px - 18px);
  padding-right: 4px;
  box-sizing: border-box;
  min-width: 0;
}
.top-bar-left .sidebar-toggle {
  /* Push the standalone toggle (only present when expanded) to the
     right edge of the cluster — that's the column the refresh
     button sits in below. */
  margin-left: auto;
}
.top-bar .app-title {
  /* Defensive: a longer future title shouldn't push the toggle
     past the sidebar's right edge. ``min-width: 0`` lets the flex
     item shrink; ``ellipsis`` clips gracefully. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.top-bar h1, .top-bar .app-title {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--fg);
}

/* Brand button — composite of an ``<img>`` (default) and the
   sidebar-toggle SVG (overlay). When the wrapper has
   ``.is-actionable`` (only set in the collapsed sidebar state) it
   becomes a clickable target: hovering swaps the visible icon to
   the overlay glyph, signalling that clicking will EXPAND the rail.
   When NOT actionable the wrapper is a passive decoration with no
   pointer cursor and no hover swap. */
.brand-toggle {
  position: relative;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: default;
  border-radius: 6px;
  flex: 0 0 auto;
}
.brand-toggle .brand-icon,
.brand-toggle .sidebar-toggle-icon {
  position: absolute;
  inset: 0;
  margin: auto;
  pointer-events: none;
  transition: opacity 120ms ease;
}
.brand-toggle .brand-icon { width: 22px; height: 22px; opacity: 1; }
.brand-toggle .sidebar-toggle-icon { width: 16px; height: 16px; opacity: 0; }

/* Actionable mode (sidebar is collapsed) — wrapper becomes a
   button. Hover swaps img → toggle glyph. */
.brand-toggle.is-actionable {
  cursor: pointer;
}
.brand-toggle.is-actionable:hover .brand-icon { opacity: 0; }
.brand-toggle.is-actionable:hover .sidebar-toggle-icon { opacity: 1; }
.brand-toggle.is-actionable:focus-visible {
  outline: 2px solid var(--ok);
  outline-offset: 2px;
}
.brand-toggle.is-actionable:focus-visible .brand-icon { opacity: 0; }
.brand-toggle.is-actionable:focus-visible .sidebar-toggle-icon { opacity: 1; }
/* Mirror the icon-pane horizontally when the rail is collapsed —
   shaded column on the right hints "the side that will appear when
   you click". */
.top-bar.is-sidebar-collapsed .brand-toggle .sidebar-toggle-icon-pane {
  transform: scaleX(-1);
  transform-origin: 8px center;
}
.mode-pill {
  font-size: 11px;
  color: var(--fg-muted);
  background: var(--card-bg);
  padding: 3px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
}
.mode-pill.ok { color: var(--ok); border-color: #bfe7c9; background: #effaf1; }

.top-bar-right {
  display: flex;
  align-items: center;
  gap: 14px;
}
.top-bar-right a {
  color: var(--fg);
  text-decoration: none;
  font-size: 13px;
  padding: 6px 10px;
  border-radius: 6px;
}
.top-bar-right a:hover { background: var(--card-hover); }

.ws-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--border-strong);
  transition: background 0.2s ease;
}
.ws-dot.ok { background: var(--ok); }
.ws-dot.err { background: var(--err); }
.ws-dot.connecting {
  background: var(--warn);
  animation: pulse-dot 1.2s ease-in-out infinite;
}
@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.ghost-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--fg);
  padding: 4px 10px;
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
}
.ghost-btn:hover { background: var(--card-hover); }

/* ---------- feed ---------- */

.feed-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  width: 100%;
}
.feed {
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
  padding: 28px 20px 28px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  box-sizing: border-box;
}

/* ---------- base message row ---------- */

.row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.row.user {
  flex-direction: row-reverse;
}
.row .avatar {
  flex: 0 0 28px;
  width: 28px; height: 28px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  color: var(--fg-muted);
  user-select: none;
}
.row.user .avatar {
  background: var(--user-bg);
  color: var(--user-fg);
  border-color: var(--user-bg);
}
.row.agent .avatar { background: #f3f4f6; border-color: #e5e7eb; color: #4b5563; }

.bubble {
  max-width: 82%;
  padding: 9px 13px;
  border-radius: 14px;
  white-space: pre-wrap;
  word-wrap: break-word;
  line-height: 1.5;
}
.row.user .bubble {
  background: var(--user-bg);
  color: var(--user-fg);
  border-bottom-right-radius: 4px;
}
.row.agent .bubble {
  background: transparent;
  padding: 0 2px;
  max-width: 100%;
  color: var(--fg);
}

/* ----- markdown rendering inside chat bubbles --------------------------
 * react-markdown emits real block elements (<p>, <h1-4>, <ul>, <pre>,
 * <table>, …). The bubble's default `white-space: pre-wrap` would
 * double every blank line between blocks. Reset it inside
 * `.markdown-body` and give each element a tight, claude.ai-style
 * rhythm.
 * --------------------------------------------------------------------- */
.markdown-body { white-space: normal; }
.markdown-body > :first-child { margin-top: 0; }
.markdown-body > :last-child { margin-bottom: 0; }

.markdown-body p {
  margin: 0 0 8px;
  line-height: 1.55;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4 {
  margin: 14px 0 6px;
  font-weight: 600;
  line-height: 1.3;
}
.markdown-body h1 { font-size: 1.25em; }
.markdown-body h2 { font-size: 1.15em; }
.markdown-body h3 { font-size: 1.05em; }
.markdown-body h4 { font-size: 1em; }

.markdown-body ul,
.markdown-body ol {
  margin: 0 0 8px;
  padding-left: 22px;
}
.markdown-body li { margin: 2px 0; line-height: 1.5; }
.markdown-body li > p { margin: 0 0 4px; }

.markdown-body strong { font-weight: 600; }
.markdown-body em { font-style: italic; }

.markdown-body a {
  color: #2563eb;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.markdown-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
  background: #f3f4f6;
  border: 1px solid #e5e7eb;
  border-radius: 4px;
  padding: 1px 5px;
}
.markdown-body pre {
  margin: 8px 0;
  padding: 10px 12px;
  background: #f6f8fa;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  overflow-x: auto;
  line-height: 1.45;
}
.markdown-body pre code {
  background: transparent;
  border: 0;
  padding: 0;
  font-size: 0.88em;
}

.markdown-body blockquote {
  margin: 8px 0;
  padding: 2px 12px;
  border-left: 3px solid #d1d5db;
  color: #4b5563;
}
.markdown-body hr {
  border: 0;
  border-top: 1px solid #e5e7eb;
  margin: 12px 0;
}

.markdown-body table {
  border-collapse: collapse;
  margin: 8px 0;
  font-size: 0.95em;
}
.markdown-body th,
.markdown-body td {
  border: 1px solid #e5e7eb;
  padding: 5px 9px;
  text-align: left;
}
.markdown-body th { background: #f9fafb; font-weight: 600; }
.markdown-body input[type="checkbox"] {
  margin-right: 6px;
  vertical-align: middle;
}

/* ----- agent work timeline (claude.ai-style) ---------------------------
 * Rows of role="work" carry NO avatar — they hold a vertical chain of
 * black dots connected by a thin line. Each dot is one phase of the
 * assistant's work (Thinking, Plan, tool call, etc.). The avatar
 * appears only when the model produces the final user-facing reply,
 * which renders as a normal `.row.agent` BELOW the timeline.
 *
 * Layout: align the timeline's left edge so the dots sit roughly under
 * where the avatar will eventually appear, giving the chat a single
 * vertical rhythm.
 * --------------------------------------------------------------------- */
.row.work {
  align-items: stretch;
  /* Avatar slot (28px) + gap (10px) reserved as the gutter where the
     dots live, so the dot column is visually under the avatar slot. */
  padding-left: 0;
}
.work-timeline {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  padding-left: 28px;       /* room for the dot gutter */
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* The connecting line — one continuous bar drawn behind the dots.
   We draw it from a touch below the first dot's center to a touch
   above the last so it tucks under the dots without overshooting. */
.work-timeline::before {
  content: "";
  position: absolute;
  /* Line centered with the dots: dot center sits at x=11 inside the
     work-timeline (padding-left 28 + dot left -22 + dot width/2 5).
     Line width 2 → left 10 puts the line center at x=11, exactly
     under the dot centers. */
  left: 10px;
  top: 12px;
  bottom: 8px;
  width: 2px;
  background: var(--border-strong);
  pointer-events: none;
}

.timeline-node {
  position: relative;
  color: var(--fg-muted);
  font-size: 13px;
  line-height: 1.5;
  min-height: 14px;
}
.node-dot {
  position: absolute;
  left: -22px;
  top: 5px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--fg);
  /* The 3px ring of background colour punches the connecting line
     out from underneath the dot so the dot reads as solid. */
  box-shadow: 0 0 0 3px var(--bg);
  z-index: 1;
}
.node-body {
  /* Body sits to the right of the dot. Children may include cards,
     pills, plan text, the active thinking line, etc. */
  min-width: 0;
}
.node-body > .node-text {
  color: var(--fg-muted);
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* Active node (the "live" pulsing dot at the bottom of the chain).
   Claude.ai-style ripple: the solid blue dot expands slightly while
   a translucent ring grows out and fades — communicates "still
   working" without spinning text. */
.timeline-node.is-active .node-dot {
  background: var(--accent);
  animation: thinking-dot-pulse 1.4s ease-in-out infinite;
}
/* Frozen / completed timeline dot — green so the chain reads as a
   ladder of green checkpoints (one per finished step) leading down
   to the active blue dot at the bottom. */
.timeline-node.is-frozen .node-dot {
  background: var(--ok);
}

/* Plan node body — flat grey list, no card chrome. The "Plan" title
   has been retired (the user reads the summary directly; a label
   row was visual noise). Each step gets a custom gray solid-circle
   bullet that turns green when the step completes — pairs with the
   line-through on the label so a finished step reads as both
   crossed-out AND ticked-off. */
.plan-body { display: flex; flex-direction: column; gap: 4px; }
.plan-title { display: none; }
.plan-summary {
  color: var(--fg);
  font-size: 13px;
  line-height: 1.45;
}
.plan-steps {
  margin: 4px 0 0 0;
  padding: 0;
  list-style: none;
  color: var(--fg-muted);
  font-size: 12.5px;
  line-height: 1.5;
}
/* Bullet is rendered as a REAL <span class="plan-bullet"> in the
   markup, not a `::before` pseudo, so the layout is pure flexbox:
   `[bullet] [12px gap] [label]`. Absolute positioning + padding-left
   was visually unreliable (when label has line-through, the strikethrough
   sometimes appeared to graze the absolute-positioned bullet). With a
   real flex item the gap is enforced by layout itself — no overlap
   possible. */
/* Bullet is an inline SVG injected at the START of the label text.
   That guarantees baseline alignment with the surrounding glyphs
   (SVG inline content uses the same line-box rules as text glyphs),
   so the circle reads as "on the same line" as the Chinese
   characters without any box-model / vertical-align hackery. The
   12px right-margin owns the gap between bullet and text. */
.plan-step {
  display: block;
  padding-left: 0;
  line-height: 1.5;
}
.plan-bullet {
  /* inline-block (not inline) creates an independent line box so the
     parent's text-decoration: line-through stops at the bullet's
     edge instead of cutting across the circle. */
  display: inline-block;
  margin-right: 12px;
  /* `vertical-align: middle` lifts the box so its center is at
     parent baseline + half x-height — reads as visually centered
     with both Latin and CJK text. */
  vertical-align: middle;
  color: var(--fg-faint);                       /* default: grey */
  /* The circle inside uses fill="currentColor", so changing color
     here re-tints the bullet without rewriting the SVG. */
  transition: color 0.18s ease, transform 0.18s ease;
}
.plan-step-meta {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 11px;
  color: var(--fg-faint);
}
.plan-step.is-running .plan-step-label { color: var(--accent); font-weight: 500; }
.plan-step.is-running .plan-bullet {
  color: var(--accent);
  animation: thinking-dot-pulse 1.4s ease-in-out infinite;
  transform-origin: center;
}
.plan-step.is-done    .plan-step-label {
  color: var(--fg-muted);
  text-decoration: line-through;
  text-decoration-color: var(--fg);             /* solid black, not the faint border grey */
  text-decoration-thickness: 2px;               /* 2x default → actually visible */
  text-underline-offset: 1px;
}
.plan-step.is-done    .plan-bullet { color: var(--ok); }
/* Failed step: red text + red strikethrough so the user immediately
   reads "agent gave up here" instead of "still spinning". Mirrors the
   line-through treatment of `is-done` but uses the error tone. */
.plan-step.is-failed  .plan-step-label {
  color: var(--err);
  text-decoration: line-through;
  text-decoration-color: var(--err);
  text-decoration-thickness: 2px;
  text-underline-offset: 1px;
}
.plan-step.is-failed  .plan-bullet { color: var(--err); }
.plan-step.is-noop    { color: var(--fg-muted); font-style: italic; }
.plan-step.is-noop    .plan-bullet { display: none; }
/* Strikethrough on the label runs across text glyphs only. We DO NOT
   want the line to also cross the SVG bullet that now lives at the
   start of the label, so explicitly opt the SVG out of the parent's
   text-decoration. */
.plan-step .plan-bullet { text-decoration: none; }

/* system + error rows (narrow, centered) */

.row.system, .row.error {
  justify-content: center;
}
.row.system .bubble, .row.error .bubble {
  font-size: 13px;
  max-width: 640px;
  text-align: center;
}
.row.system .bubble {
  background: var(--warn-bg);
  color: var(--warn);
  border: 1px solid #f7d994;
  border-radius: 10px;
  padding: 8px 12px;
}
.row.error .bubble {
  background: var(--err-bg);
  color: var(--err);
  border: 1px solid #f8b4b4;
  border-radius: 10px;
  padding: 8px 12px;
}

/* ---------- tool call card ---------- */

.card {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card-bg);
  overflow: hidden;
  font-size: 13.5px;
  max-width: 100%;
}
.card.is-running { border-color: var(--accent); }
.card.is-error   { border-color: var(--err); }

.card-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  cursor: pointer;
  background: var(--card-bg);
  user-select: none;
}
.card-header:hover { background: var(--card-hover); }

.tool-icon {
  width: 18px; height: 18px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px;
}
.tool-icon.spin { animation: spin 1s linear infinite; color: var(--accent); }
@keyframes spin { to { transform: rotate(360deg); } }
.tool-icon.ok { color: var(--ok); }
.tool-icon.err { color: var(--err); }

.tool-name {
  font-family: ui-monospace, "JetBrains Mono", "Menlo", monospace;
  font-size: 12.5px;
  color: var(--fg);
  font-weight: 500;
}
.tool-args-preview {
  color: var(--fg-muted);
  font-size: 12.5px;
  font-family: ui-monospace, "JetBrains Mono", monospace;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
}
.card-chevron {
  margin-left: auto;
  color: var(--fg-faint);
  transition: transform 0.15s ease;
  flex-shrink: 0;
}
.card.is-expanded .card-chevron { transform: rotate(90deg); }

.card-body {
  display: none;
  border-top: 1px solid var(--border);
  padding: 10px 12px;
  background: #fafafa;
}
.card.is-expanded .card-body { display: block; }

.field-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--fg-muted);
  margin: 2px 0 4px 0;
}
.field-label:not(:first-child) { margin-top: 10px; }

pre.code-block {
  margin: 0;
  padding: 10px 12px;
  background: var(--code-bg);
  color: var(--code-fg);
  border-radius: 6px;
  font-family: ui-monospace, "JetBrains Mono", monospace;
  font-size: 11.5px;
  line-height: 1.45;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 360px;
  overflow-y: auto;
}
pre.code-block.error { background: #3a0e0e; color: #fca5a5; }

/* ---------- plan checklist card ---------- */

.plan-card {
  border: 1px solid var(--plan-border);
  background: var(--plan-bg);
  border-radius: 10px;
  overflow: hidden;
  font-size: 13.5px;
}
.plan-header {
  padding: 9px 14px;
  display: flex; align-items: center; gap: 8px;
  font-size: 13px;
  font-weight: 600;
  color: #155b2a;
  border-bottom: 1px solid #d8ecdc;
}
.plan-body { padding: 10px 14px; }
.plan-step {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 5px 0;
  font-size: 13px;
  color: var(--fg);
}
.plan-step .check {
  flex: 0 0 16px;
  width: 16px; height: 16px;
  border: 1.5px solid #7fbe8f;
  border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
  color: transparent;
  font-size: 11px;
  margin-top: 3px;
}
.plan-step.done .check {
  background: #4b9c61;
  border-color: #4b9c61;
  color: #fff;
}
.plan-step.done .label {
  color: var(--fg-muted);
  text-decoration: line-through;
}
.plan-step .label {
  font-family: ui-monospace, "JetBrains Mono", monospace;
  font-size: 12.5px;
  word-break: break-word;
  flex: 1;
}
.plan-step .rationale {
  color: var(--fg-muted);
  font-size: 12px;
  font-family: inherit;
  margin-top: 2px;
}

.plan-warnings {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed #d8ecdc;
  font-size: 12px;
  color: var(--warn);
}

/* ---------- @-mention typeahead popover ---------- */

.mention-popover {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 12px;
  width: min(420px, calc(100% - 24px));
  max-height: 280px;
  overflow-y: auto;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
  z-index: 30;
  padding: 4px;
}
.mention-option {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 10px;
  align-items: baseline;
  width: 100%;
  padding: 6px 10px;
  background: transparent;
  border: 0;
  border-radius: 4px;
  font: inherit;
  cursor: pointer;
  text-align: left;
  color: var(--fg);
}
.mention-option:hover,
.mention-option.is-active {
  background: rgba(40, 140, 90, 0.10);
}
.mention-option-name {
  font-weight: 600;
  font-size: 13px;
}
.mention-option-slug {
  font-family: var(--mono-font, monospace);
  font-size: 11.5px;
  color: var(--fg-muted);
}
.mention-option-category {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-faint);
}

/* ---------- datasets matched chip ---------- */

.datasets-matched-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 4px 10px;
  font-size: 12px;
  color: var(--fg-muted);
  background: rgba(40, 140, 90, 0.08);
  border: 1px solid rgba(40, 140, 90, 0.3);
  border-radius: 999px;
  cursor: pointer;
  font-family: var(--ui-font);
  font-weight: inherit;
  letter-spacing: 0;
  text-align: left;
  flex-wrap: wrap;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.datasets-matched-chip:hover {
  background: rgba(40, 140, 90, 0.13);
}
.datasets-matched-chip-label {
  font-weight: 600;
  color: rgb(40, 140, 90);
  flex-shrink: 0;
}
.datasets-matched-chip-reason {
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}

/* ---------- datasets second-level page ---------- */

/* Sits below the TopBar, fills the rest of the viewport. Split-pane:
   left = scrollable card grid (toolbar + sections), right = sticky
   detail panel that appears when a card is selected. */
.datasets-page {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr;
  height: calc(100vh - var(--topbar-height, 48px));
  background: var(--bg);
  overflow: hidden;
}

/* ───────── Workspace data page (Phase C) ───────── */
.workspace-data-page {
  height: calc(100vh - var(--topbar-height, 48px));
  overflow-y: auto;
  padding: 24px 32px 40px;
  background: var(--bg);
}
.data-page-header { margin-bottom: 18px; }
.data-page-header h2 {
  margin: 0 0 6px;
  font-size: 22px;
  font-weight: 600;
  color: var(--fg);
}
.data-page-subtitle {
  margin: 0 0 14px;
  color: var(--fg-muted);
  font-size: 13px;
  max-width: 720px;
}
.data-page-meta {
  display: flex; gap: 24px; align-items: center;
  font-size: 13px;
  color: var(--fg-muted);
  padding: 10px 14px;
  background: var(--bg-muted);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.data-page-meta strong { color: var(--fg); font-weight: 600; }
.data-ws-root {
  margin-left: auto;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 11.5px;
  color: var(--fg-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 60%;
}
.data-page-error {
  padding: 12px 14px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
  color: #b91c1c;
  display: flex; gap: 12px; align-items: center;
  margin-bottom: 16px;
}
.data-page-filters {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin: 16px 0 12px;
}
.data-pill {
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg-muted);
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  cursor: pointer;
}
.data-pill.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.data-page-empty {
  padding: 48px 24px;
  text-align: center;
  color: var(--fg-faint);
  font-size: 13px;
}
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  background: var(--bg);
}
.data-table thead th {
  text-align: left;
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-faint);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
}
.data-table tbody td {
  padding: 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.data-table tbody tr:hover { background: var(--bg-muted); }
.data-table tbody tr.is-busy { opacity: 0.5; }
.data-table .col-source { font-weight: 600; color: var(--fg); }
.data-table .col-label {
  max-width: 220px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.data-table .col-path {
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 11.5px;
  color: var(--fg-muted);
  max-width: 260px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.data-table .col-path .muted { color: var(--fg-faint); }
.data-table .col-actions {
  display: flex; gap: 6px; justify-content: flex-end;
}
.data-kind-pill {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  text-transform: lowercase;
}
.data-kind-pill.kind-download { background: #ecfdf5; color: #047857; }
.data-kind-pill.kind-fetch    { background: #eff6ff; color: #1d4ed8; }
.datasets-page.has-detail {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
.datasets-list-pane {
  overflow-y: auto;
  padding: 24px 32px 40px;
  min-width: 0;
}

/* Toolbar: full-width search */
.datasets-toolbar {
  margin-bottom: 16px;
}
.datasets-search {
  width: 100%;
  padding: 10px 14px 10px 36px;
  font-size: 13px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface, #fff)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E")
    no-repeat 12px center;
  background-size: 14px 14px;
  box-sizing: border-box;
}
.datasets-search:focus {
  outline: none;
  border-color: var(--accent, #2a6df0);
}

/* Count line: "57 sources available" */
.datasets-count-line {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--fg-muted);
  margin-bottom: 16px;
}
.datasets-count-icon {
  color: rgb(214, 138, 0);
}

/* Sections (one per category) */
.datasets-sections {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.datasets-section-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 12px 0;
  font-size: 16px;
  font-weight: 600;
}
.datasets-section-title {
  color: var(--fg);
}
.datasets-section-count {
  font-size: 12px;
  color: var(--fg-muted);
  background: rgba(0, 0, 0, 0.05);
  padding: 1px 8px;
  border-radius: 999px;
  font-weight: 500;
}
.datasets-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}

.datasets-loading,
.datasets-empty,
.datasets-error {
  padding: 24px;
  text-align: center;
  color: var(--fg-faint);
}
.datasets-error {
  color: var(--err);
}

/* Card */
.dataset-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface, #fff);
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--fg);
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.dataset-card:hover {
  border-color: var(--accent, #2a6df0);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
}
.dataset-card.is-active {
  border-color: var(--accent, #2a6df0);
  box-shadow: 0 0 0 2px rgba(42, 109, 240, 0.15);
}
.dataset-card-head {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Blue rounded-square tile that wraps the dataset glyph. */
.dataset-icon-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 7px;
  background: rgb(219, 234, 254);
  border: 1px solid rgb(191, 219, 254);
  color: rgb(37, 99, 235);
  flex-shrink: 0;
}
.dataset-icon-tile svg {
  width: 16px;
  height: 16px;
}
.dataset-card-icon {
  /* Inherits .dataset-icon-tile when wrapped; this rule only
     applies to non-tile usage left in the code. */
  color: rgb(38, 99, 235);
  flex-shrink: 0;
}
.datasets-count-icon {
  color: rgb(38, 99, 235);
  flex-shrink: 0;
}
.dataset-card-name {
  font-weight: 600;
  font-size: 14px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dataset-card-doclink {
  color: var(--fg-faint);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  padding: 2px;
  border-radius: 3px;
}
.dataset-card-doclink:hover {
  color: var(--accent, #2a6df0);
  background: rgba(42, 109, 240, 0.08);
}
.dataset-card-desc {
  margin: 0;
  font-size: 12.5px;
  color: var(--fg-muted);
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.dataset-card-tags {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 2px;
}
.dataset-card-tag {
  font-size: 10.5px;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--fg-muted);
}
.dataset-card-tag.is-auth {
  border-color: rgba(192, 90, 30, 0.4);
  color: rgb(192, 90, 30);
}
.dataset-card-tag.is-commercial.commercial-academic_only {
  border-color: rgba(214, 138, 0, 0.50);
  color: rgb(170, 105, 0);
  background: rgba(255, 230, 175, 0.35);
}
.dataset-card-tag.is-commercial.commercial-requires_license {
  border-color: rgba(192, 30, 30, 0.50);
  color: rgb(165, 30, 30);
  background: rgba(255, 215, 215, 0.40);
}

.dataset-detail-license {
  border-radius: 6px;
  padding: 10px 14px;
  font-size: 12.5px;
}
.dataset-detail-license.commercial-academic_only {
  border: 1px solid rgba(214, 138, 0, 0.4);
  background: rgba(255, 240, 200, 0.4);
}
.dataset-detail-license.commercial-requires_license {
  border: 1px solid rgba(192, 30, 30, 0.4);
  background: rgba(255, 215, 215, 0.40);
}
.dataset-detail-license-label {
  font-weight: 600;
  display: block;
  margin-bottom: 4px;
}
.dataset-detail-license.commercial-academic_only .dataset-detail-license-label {
  color: rgb(170, 105, 0);
}
.dataset-detail-license.commercial-requires_license .dataset-detail-license-label {
  color: rgb(165, 30, 30);
}
.dataset-detail-license-body {
  color: var(--fg);
  line-height: 1.45;
}
.dataset-detail-license-hint {
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--fg-muted);
}

/* Detail panel (right side, shows when a card is selected) */
.dataset-detail {
  border-left: 1px solid var(--border);
  background: var(--surface, #fff);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}
.dataset-detail-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border-faint);
  gap: 12px;
}
.dataset-detail-title-line {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
}
.dataset-detail-icon {
  color: rgb(38, 99, 235);
  flex-shrink: 0;
}
.dataset-detail-title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dataset-detail-slug {
  font-family: var(--mono-font, monospace);
  font-size: 11.5px;
  color: var(--fg-muted);
  background: rgba(0, 0, 0, 0.04);
  padding: 1px 6px;
  border-radius: 4px;
  flex-shrink: 0;
}
.dataset-detail-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.dataset-detail-doclink {
  font-size: 12px;
  color: var(--accent, #2a6df0);
  text-decoration: none;
}
.dataset-detail-doclink:hover {
  text-decoration: underline;
}
.dataset-detail-close {
  background: transparent;
  border: 0;
  width: 28px;
  height: 28px;
  border-radius: 4px;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  color: var(--fg-muted);
}
.dataset-detail-close:hover {
  background: rgba(0, 0, 0, 0.05);
  color: var(--fg);
}
.dataset-detail-body {
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}
.dataset-detail-body > * {
  min-width: 0;
  width: 100%;
  box-sizing: border-box;
}
.dataset-detail-category {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-muted);
  align-self: flex-start;
}
.dataset-detail-desc {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--fg);
}
.dataset-detail-meta-row {
  display: flex;
  gap: 8px;
  font-size: 12px;
  align-items: baseline;
}
.dataset-detail-meta-label {
  font-weight: 600;
  color: var(--fg-muted);
  flex-shrink: 0;
}
.dataset-detail-meta-value {
  color: var(--fg);
}
.dataset-detail-meta-value.mono {
  font-family: var(--mono-font, monospace);
  font-size: 11.5px;
}
.dataset-detail-auth {
  border: 1px solid rgba(192, 90, 30, 0.3);
  background: rgba(255, 240, 220, 0.4);
  border-radius: 6px;
  padding: 10px 14px;
  font-size: 12.5px;
}
.dataset-detail-auth-label {
  font-weight: 600;
  color: rgb(192, 90, 30);
  display: block;
  margin-bottom: 4px;
}
.dataset-detail-envvar {
  background: rgba(0, 0, 0, 0.06);
  padding: 1px 6px;
  border-radius: 3px;
  font-family: var(--mono-font, monospace);
  font-size: 11.5px;
}
.dataset-detail-auth-hint {
  margin-top: 4px;
  color: var(--fg-muted);
  font-size: 11.5px;
}
.dataset-detail-section-head {
  margin: 8px 0 0 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.dataset-detail-access {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  min-width: 0;
}
.dataset-detail-access > .dataset-access {
  width: 100%;
  box-sizing: border-box;
  min-width: 0;
}
.dataset-access {
  border-left: 3px solid var(--border);
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.02);
  border-radius: 0 6px 6px 0;
}
.dataset-access.is-preferred {
  border-left-color: rgb(40, 140, 90);
  background: rgba(40, 140, 90, 0.04);
}
.dataset-access-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 12px;
}
.dataset-access-kind {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 3px;
  color: #fff;
  background: #555;
}
.dataset-access-kind.kind-cli { background: rgb(60, 100, 180); }
.dataset-access-kind.kind-python { background: rgb(50, 120, 75); }
.dataset-access-kind.kind-api { background: rgb(170, 95, 30); }
.dataset-access-kind.kind-mcp { background: rgb(110, 70, 170); }
.dataset-access-kind.kind-manual { background: #777; }
.dataset-access-preferred {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgb(40, 140, 90);
  font-weight: 700;
}
.dataset-access-install {
  color: var(--fg-muted);
}
.dataset-access-install code {
  font-family: var(--mono-font, monospace);
  font-size: 11px;
  background: rgba(0, 0, 0, 0.05);
  padding: 1px 4px;
  border-radius: 3px;
}
.dataset-access-doc {
  margin-left: auto;
  text-decoration: none;
  color: var(--accent, #2a6df0);
}
.dataset-access-desc {
  margin: 4px 0;
  font-size: 12px;
  color: var(--fg);
}
.dataset-access-base {
  margin: 2px 0;
  font-size: 11.5px;
  color: var(--fg-muted);
}
.dataset-access-base code {
  font-family: var(--mono-font, monospace);
}
.dataset-access-example {
  margin: 6px 0 0 0;
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.06);
  border-radius: 4px;
  overflow-x: auto;
  font-size: 11.5px;
  line-height: 1.4;
  width: 100%;
  box-sizing: border-box;
  min-width: 0;
}
.dataset-access-example code {
  font-family: var(--mono-font, monospace);
  white-space: pre;
  color: var(--fg);
}

/* ---------- knowhow chip ---------- */

/* KnowHow RAG hits surfaced once per turn (right after the user
   message) so the user can see which playbook the system auto-
   injected. Slightly different tint from the tool-selection chip so
   the two stack visibly when both fire. */
.knowhow-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 4px 10px;
  font-size: 12px;
  color: var(--fg-muted);
  background: rgba(72, 96, 168, 0.06);
  border: 1px solid rgba(72, 96, 168, 0.25);
  border-radius: 999px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex-wrap: wrap;
  font-family: var(--ui-font);
  letter-spacing: 0;
}
.knowhow-chip-label {
  font-weight: 600;
  flex-shrink: 0;
  color: rgb(72, 96, 168);
}
.knowhow-chip-hits {
  flex: 1 1 auto;
  min-width: 0;
}
.knowhow-chip-hit {
  color: var(--fg);
}
.knowhow-chip-score {
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}

/* ---------- tool selection chip ---------- */

/* Surfaced once per turn (right after run_started) so the user can
   see which skills the LLM tool selector pulled in. Single inline
   row, neutral color when normal, tinted when a fallback fired. */
.tool-selection-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 4px 10px;
  font-size: 12px;
  color: var(--fg-muted);
  background: rgba(0, 0, 0, 0.025);
  border: 1px solid var(--border-faint);
  border-radius: 999px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex-wrap: wrap;
  font-family: var(--ui-font);
  letter-spacing: 0;
}
.tool-selection-chip.is-fallback {
  background: rgba(214, 138, 0, 0.08);
  border-color: rgba(214, 138, 0, 0.30);
  color: #6c4500;
}
.tool-selection-chip-label {
  font-weight: 600;
  flex-shrink: 0;
}
.tool-selection-chip-empty {
  font-style: italic;
  color: var(--fg-faint);
}
.tool-selection-chip-slugs {
  flex: 1 1 auto;
  min-width: 0;
}
.tool-selection-chip-slug {
  color: var(--fg);
}
.tool-selection-chip-slug.is-pinned {
  font-weight: 600;
  color: var(--accent, #2a6df0);
}

/* ---------- verifier card ---------- */

/* Adversarial-verifier verdict, surfaced as a colored chip in the
   timeline so the user can distinguish it from main-agent activity.
   Mirrors Claude Code's red verificationAgent chip — collapsed by
   default; click to expand the issue list. PASS verdicts are
   dropped upstream so this UI never shows a green chip. */
.verifier-card {
  border-radius: 8px;
  font-size: 12.5px;
}
.verifier-fail {
  background: rgba(216, 76, 76, 0.06);
  border: 1px solid rgba(216, 76, 76, 0.30);
}
.verifier-partial {
  background: rgba(214, 138, 0, 0.06);
  border: 1px solid rgba(214, 138, 0, 0.30);
}
.verifier-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 10px;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--fg);
}
.verifier-row:hover {
  filter: brightness(0.97);
}
.verifier-chip {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 3px;
  flex-shrink: 0;
  color: #fff;
}
.verifier-fail .verifier-chip {
  background: #c0392b;
}
.verifier-partial .verifier-chip {
  background: #b07000;
}
.verifier-verdict {
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.05em;
  flex-shrink: 0;
}
.verifier-fail .verifier-verdict { color: #8b1f15; }
.verifier-partial .verifier-verdict { color: #6c4500; }
.verifier-summary {
  flex: 1;
  min-width: 0;
  color: var(--fg-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.verifier-toggle {
  flex-shrink: 0;
  color: var(--fg-faint);
}
.verifier-issues {
  margin: 0;
  padding: 4px 12px 8px 32px;
  list-style-type: disc;
  color: var(--fg);
  font-size: 12px;
  line-height: 1.5;
}
.verifier-issues li + li {
  margin-top: 2px;
}

/* ---------- file viewer modal ---------- */

/* Floating overlay for previewing CSVs / TSVs / images / text from
   the workspace tree. Same z-index tier as the existing modal
   backdrop pattern (50) so it sits above the chat / notebook
   panels but below context menus (70) and prompt dialogs. */
.file-viewer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 17, 20, 0.55);
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.file-viewer-modal {
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.28);
  max-width: 90vw;
  max-height: 88vh;
  width: 1100px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.file-viewer-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, #fafbfc, #fff);
}
.file-viewer-name {
  font-family: ui-monospace, "JetBrains Mono", monospace;
  font-size: 13px;
  font-weight: 500;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-viewer-kind {
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 1px 6px;
  flex-shrink: 0;
}
.file-viewer-download {
  font-size: 13px;
  text-decoration: none;
  padding: 4px 8px;
  flex-shrink: 0;
}
.file-viewer-close {
  background: transparent;
  border: 0;
  font-size: 16px;
  color: var(--fg-muted);
  cursor: pointer;
  padding: 2px 8px;
  flex-shrink: 0;
}
.file-viewer-close:hover {
  color: var(--fg);
}
.file-viewer-body {
  flex: 1 1 auto;
  overflow: auto;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.file-viewer-loading,
.file-viewer-error {
  padding: 16px;
  text-align: center;
  color: var(--fg-muted);
}
.file-viewer-error { color: var(--err); }
.file-viewer-banner {
  font-size: 12px;
  background: #fff7e0;
  border: 1px solid #f1d98a;
  color: #6c4500;
  border-radius: 6px;
  padding: 6px 10px;
}
.file-viewer-image-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1 1 auto;
}
.file-viewer-image {
  max-width: 100%;
  max-height: 75vh;
  object-fit: contain;
  background: #f4f5f7;
  border-radius: 4px;
}
.file-viewer-table-wrap {
  flex: 1 1 auto;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
}
.file-viewer-table {
  border-collapse: collapse;
  font-size: 12px;
  font-family: ui-monospace, "JetBrains Mono", monospace;
  white-space: nowrap;
}
.file-viewer-table th,
.file-viewer-table td {
  padding: 4px 8px;
  border-right: 1px solid #eef0f2;
  border-bottom: 1px solid #eef0f2;
}
.file-viewer-table th {
  position: sticky;
  top: 0;
  background: #fafbfc;
  text-align: left;
  font-weight: 600;
  z-index: 1;
}
.file-viewer-table tbody tr:hover {
  background: #f7f8fa;
}
.file-viewer-text {
  margin: 0;
  font-family: ui-monospace, "JetBrains Mono", monospace;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  background: #fafbfc;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  max-height: 70vh;
  overflow: auto;
}
.file-viewer-unsupported {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-direction: column;
  padding: 32px;
  color: var(--fg-muted);
}

/* ---------- approval card ---------- */

.approval-card {
  border: 1px solid var(--approval-border);
  background: var(--approval-bg);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 13.5px;
  /* Subtle pulse so the card visually stands out from regular tool
     cards — without being garish. Disabled once the user resolves
     the approval (the resolved state has its own muted look). */
  animation: approvalPulse 2.4s ease-in-out infinite;
}
@keyframes approvalPulse {
  0%, 100% {
    box-shadow: 0 0 0 0 rgba(214, 138, 0, 0.0);
  }
  50% {
    box-shadow: 0 0 0 6px rgba(214, 138, 0, 0.18);
  }
}
.approval-card.resolved {
  animation: none;
}
.approval-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}
.approval-warn {
  font-size: 16px;
  color: #d68a00;
  flex-shrink: 0;
}
.approval-title {
  font-weight: 600;
  color: #8a5a00;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.approval-tool-name {
  font-family: ui-monospace, "JetBrains Mono", monospace;
  background: #fff;
  padding: 1px 6px;
  border-radius: 4px;
  border: 1px solid #f1d98a;
  font-size: 11.5px;
  color: var(--fg-muted);
  flex-shrink: 0;
}

.approval-reason {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--fg-muted);
  margin: 0 0 8px;
}

.approval-body {
  background: #fff;
  border: 1px solid #f1d98a;
  border-radius: 6px;
  padding: 8px 10px;
  margin-bottom: 10px;
  max-height: 320px;
  overflow: auto;
}
.approval-body > * + * {
  margin-top: 6px;
}
.approval-block-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-muted);
}
.approval-block-path {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: ui-monospace, "JetBrains Mono", monospace;
  font-size: 12.5px;
}
.approval-mode {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 1px 5px;
  border-radius: 3px;
  flex-shrink: 0;
}
.approval-mode.create { background: #d4edda; color: #155724; }
.approval-mode.update { background: #fff3cd; color: #856404; }
.approval-mode.delete { background: #f8d7da; color: #721c24; }
.approval-path-text {
  word-break: break-all;
}
.approval-block-text {
  margin: 0;
  padding: 6px 8px;
  background: #fafbfc;
  border: 1px solid #eef0f2;
  border-radius: 4px;
  font-family: ui-monospace, "JetBrains Mono", monospace;
  font-size: 12px;
  color: #333;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 240px;
  overflow: auto;
}

.approval-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}
.approval-actions .always-check {
  margin-left: auto;
  font-size: 12px;
  color: var(--fg-muted);
  display: flex;
  align-items: center;
  gap: 4px;
}
.approval-actions button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.approval-card.resolved {
  background: transparent;
  border-color: #e6e8eb;
  padding: 6px 10px;
  font-size: 12.5px;
}
.approval-card.resolved .approval-resolved-line {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--fg-muted);
}
.approval-card.resolved .approval-resolved-icon {
  font-weight: 700;
}
.approval-card.resolved[data-tool-name] .approval-resolved-icon {
  color: var(--ok);
}
.approval-card.resolved .approval-resolved-verdict {
  font-weight: 600;
}
.approval-card.resolved .approval-resolved-summary {
  color: var(--fg);
}


/* ---------- composer ---------- */

.composer {
  flex: 0 0 auto;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.88) 18%, rgba(255, 255, 255, 1) 100%);
  padding: 12px 24px 18px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  box-sizing: border-box;
}
.composer-inner {
  width: 100%;
  max-width: 820px;
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: 18px;
  padding: 10px 10px 10px 14px;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.06);
  box-sizing: border-box;
}
.composer-inner:focus-within {
  border-color: #b9c0cf;
  box-shadow: 0 6px 18px rgba(47, 111, 235, 0.10);
}

/* Pending-approval banner above the composer. Mature commercial
   pattern: when an action awaits approval, the input doesn't just
   silently accept new messages — the user sees a clickable strip
   that scrolls them back to the unresolved card. */
.composer-approval-banner {
  width: 100%;
  max-width: 820px;
  margin: 0 auto 8px;
  padding: 8px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--approval-bg);
  border: 1px solid var(--approval-border);
  border-radius: 10px;
  cursor: pointer;
  font-size: 13px;
  color: #6c4500;
  transition: filter 0.12s ease;
  box-sizing: border-box;
}
.composer-approval-banner:hover {
  filter: brightness(0.97);
}
.composer-approval-icon {
  font-size: 15px;
  flex-shrink: 0;
}
.composer-approval-text {
  flex: 1;
  min-width: 0;
  font-weight: 500;
}
.composer-approval-cta {
  font-size: 12px;
  color: var(--fg-muted);
  flex-shrink: 0;
}

.composer.has-pending-approval .composer-inner {
  opacity: 0.55;
  pointer-events: none;
}
.composer.has-pending-approval .composer-inner textarea {
  cursor: not-allowed;
}
.composer-inner textarea {
  flex: 1;
  border: none;
  background: transparent;
  resize: none;
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
  padding: 6px 0;
  max-height: 200px;
  outline: none;
}
.send-btn {
  flex-shrink: 0;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  border: none;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 0.15s ease;
}
/* ---------- download job card (Phase A) ---------- */
.download-card {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
  font-size: 12.5px;
  min-width: 0;
}
.download-card.status-completed { border-color: #16a34a; background: #f0fdf4; }
.download-card.status-failed    { border-color: #b91c1c; background: #fef2f2; }
.download-card.status-cancelled { border-color: var(--border-strong); background: var(--bg-muted); }
.download-card-header {
  display: flex; align-items: center; gap: 8px;
  min-width: 0;
}
.download-card-icon {
  flex-shrink: 0;
  font-weight: 700;
  font-size: 13px;
  color: var(--accent);
}
.download-card.status-completed .download-card-icon { color: #16a34a; }
.download-card.status-failed    .download-card-icon { color: #b91c1c; }
.download-card.status-cancelled .download-card-icon { color: var(--fg-muted); }
.download-card-label {
  flex: 1 1 auto;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  font-weight: 600;
}
.download-card-cancel {
  flex-shrink: 0;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg-muted);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 11px;
  cursor: pointer;
}
.download-card-cancel:hover { color: var(--fg); border-color: var(--border-strong); }
.download-card-bar-wrap {
  height: 4px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}
.download-card-bar {
  height: 100%;
  background: var(--accent);
  transition: width 0.25s ease;
  border-radius: 2px;
}
.download-card.status-completed .download-card-bar { background: #16a34a; }
.download-card.status-failed    .download-card-bar { background: #b91c1c; }
.download-card.status-cancelled .download-card-bar { background: var(--border-strong); }
.download-card-bar.indeterminate {
  animation: dl-indeterminate 1.4s ease-in-out infinite;
}
@keyframes dl-indeterminate {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
.download-card-meta {
  display: flex; gap: 12px; flex-wrap: wrap;
  color: var(--fg-muted);
  font-size: 11.5px;
}
.download-card-speed { color: var(--accent); }
.download-card-path  { color: var(--fg-faint); }
.download-card-error { color: #b91c1c; }
.download-card-record {
  border-top: 1px dashed var(--border);
  padding-top: 6px;
  margin-top: 2px;
}
.download-card-notebook-link {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}
.download-card-notebook-link:hover { text-decoration: underline; }

/* ---------- dataset task card ---------- */
.dataset-job-card {
  display: flex; flex-direction: column; gap: 7px;
  padding: 10px 12px;
  border: 1px solid #bfdbfe;
  border-radius: 8px;
  background: #f8fbff;
  font-size: 12.5px;
  min-width: 0;
}
.dataset-job-card.status-completed { border-color: #86efac; background: #f6fef9; }
.dataset-job-card.status-failed    { border-color: #fecaca; background: #fef2f2; }
.dataset-job-card.status-cancelled { border-color: var(--border-strong); background: #f9fafb; }
.dataset-job-card-header {
  display: flex; align-items: center; gap: 8px;
  min-width: 0;
}
.dataset-job-card-icon {
  flex-shrink: 0;
  font-weight: 700;
  font-size: 13px;
  color: #2563eb;
}
.dataset-job-card.status-completed .dataset-job-card-icon { color: #16a34a; }
.dataset-job-card.status-failed    .dataset-job-card-icon { color: #b91c1c; }
.dataset-job-card.status-cancelled .dataset-job-card-icon { color: var(--fg-muted); }
.dataset-job-card-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  font-weight: 600;
}
.dataset-job-card-chip {
  flex-shrink: 0;
  border: 1px solid #bfdbfe;
  background: #eff6ff;
  color: #1d4ed8;
  border-radius: 999px;
  padding: 1px 7px;
  font-size: 10.5px;
  line-height: 1.5;
  text-transform: lowercase;
}
.dataset-job-card-cancel {
  flex-shrink: 0;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg-muted);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 11px;
  cursor: pointer;
}
.dataset-job-card-cancel:hover { color: var(--fg); border-color: var(--border-strong); }
.dataset-job-card-bar-wrap {
  height: 4px;
  border-radius: 2px;
  background: #dbeafe;
  overflow: hidden;
}
.dataset-job-card-bar {
  height: 100%;
  background: #2563eb;
  transition: width 0.25s ease;
  border-radius: 2px;
}
.dataset-job-card.status-completed .dataset-job-card-bar { background: #16a34a; }
.dataset-job-card.status-failed    .dataset-job-card-bar { background: #b91c1c; }
.dataset-job-card.status-cancelled .dataset-job-card-bar { background: var(--border-strong); }
.dataset-job-card-bar.indeterminate {
  animation: dl-indeterminate 1.4s ease-in-out infinite;
}
.dataset-job-card-meta {
  display: flex; gap: 12px; flex-wrap: wrap;
  color: var(--fg-muted);
  font-size: 11.5px;
}
.dataset-job-card-meta a {
  color: #2563eb;
  text-decoration: none;
  font-weight: 600;
}
.dataset-job-card-meta a:hover { text-decoration: underline; }
.dataset-job-card-error { color: #b91c1c; }
.dataset-job-card-artifact,
.dataset-job-card-summary {
  border-top: 1px dashed var(--border);
  padding-top: 6px;
  color: var(--fg-muted);
  display: flex;
  gap: 8px;
  min-width: 0;
}
.dataset-job-card-artifact-label {
  color: var(--fg-faint);
  flex: 0 0 auto;
}
.dataset-job-card-path {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 11.5px;
}

/* Phase D-4 manual handoff card — same chat-timeline footprint as the
 * download card, but no progress bar: it's a 1-2-3 instruction strip
 * for moving the bytes by hand. */
.manual-handoff-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  background: #fffbeb;
  font-size: 13px;
  display: flex; flex-direction: column; gap: 8px;
  max-width: 520px;
}
.manual-handoff-card.status-completed { border-color: #16a34a; background: #f0fdf4; }
.manual-handoff-card.status-failed    { border-color: #b91c1c; background: #fef2f2; }
.manual-handoff-card.status-cancelled { border-color: var(--border-strong); background: var(--bg-muted); }
.manual-handoff-card-header {
  display: flex; align-items: center; gap: 8px;
}
.manual-handoff-card-icon {
  font-size: 14px;
  color: #b45309;
}
.manual-handoff-card.status-completed .manual-handoff-card-icon { color: #16a34a; }
.manual-handoff-card.status-failed    .manual-handoff-card-icon { color: #b91c1c; }
.manual-handoff-card.status-cancelled .manual-handoff-card-icon { color: var(--fg-muted); }
.manual-handoff-card-label {
  flex: 1; min-width: 0;
  font-weight: 600; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.manual-handoff-card-deadline {
  font-size: 11px; color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
  padding: 2px 6px; border-radius: 999px;
  background: rgba(180, 83, 9, 0.1);
}
.manual-handoff-card-deadline.expired {
  background: rgba(185, 28, 28, 0.12); color: #b91c1c;
}
.manual-handoff-card-notes {
  color: var(--fg-muted); font-size: 12px;
  border-left: 2px solid #f59e0b; padding-left: 8px;
}
.manual-handoff-card-steps {
  display: flex; flex-direction: column; gap: 6px;
}
.manual-handoff-card-step {
  display: flex; gap: 8px; align-items: flex-start;
}
.manual-handoff-card-step-num {
  flex: 0 0 18px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: #f59e0b; color: #fff;
  font-size: 11px; font-weight: 700;
  margin-top: 1px;
}
.manual-handoff-card-step-body { flex: 1; min-width: 0; }
.manual-handoff-card-step-title {
  font-size: 12px; color: var(--fg);
  margin-bottom: 3px;
}
.manual-handoff-card-url-btn,
.manual-handoff-card-path-btn {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 100%;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  color: var(--accent);
  font-size: 12px;
  cursor: pointer;
}
.manual-handoff-card-url-btn:hover,
.manual-handoff-card-path-btn:hover {
  border-color: var(--accent);
}
.manual-handoff-card-url {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 380px;
}
.manual-handoff-card-url-icon,
.manual-handoff-card-copy-icon {
  color: var(--fg-muted); font-size: 11px;
}
.manual-handoff-card-path-btn code {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 11px;
  color: var(--fg);
  background: transparent;
}
.manual-handoff-card-actions {
  display: flex; justify-content: flex-end; gap: 6px;
  border-top: 1px dashed var(--border);
  padding-top: 8px;
}
.manual-handoff-card-cancel {
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 12px;
  font-size: 12px;
  color: var(--fg-muted);
  cursor: pointer;
}
.manual-handoff-card-cancel:hover { color: var(--fg); border-color: var(--border-strong); }
.manual-handoff-card-confirm {
  background: #f59e0b;
  border: 1px solid #d97706;
  border-radius: 6px;
  padding: 4px 14px;
  font-size: 12px;
  color: #fff; font-weight: 600;
  cursor: pointer;
}
.manual-handoff-card-confirm:hover { background: #d97706; }
.manual-handoff-card-confirm:disabled {
  background: var(--border); border-color: var(--border); color: var(--fg-muted);
  cursor: not-allowed;
}
.manual-handoff-card-meta {
  display: flex; gap: 12px;
  font-size: 11px; color: var(--fg-faint);
}
.manual-handoff-card-path { color: var(--fg-faint); }
.manual-handoff-card-error {
  font-size: 12px; color: #b91c1c;
  padding: 4px 8px;
  background: rgba(185, 28, 28, 0.08);
  border-radius: 4px;
}
.manual-handoff-card-record {
  border-top: 1px dashed var(--border);
  padding-top: 6px;
}
.manual-handoff-card-notebook-link {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}
.manual-handoff-card-notebook-link:hover { text-decoration: underline; }

.composer-mode-btn {
  flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 9px;
  height: 26px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  color: var(--fg-muted);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.composer-mode-btn:hover { border-color: var(--border-strong); color: var(--fg); }
.composer-mode-btn:disabled { opacity: 0.6; cursor: progress; }
.composer-mode-btn .composer-mode-icon {
  display: inline-flex; align-items: center; justify-content: center;
}
.composer-mode-btn.mode-auto {
  border-color: #d97706;
  color: #b45309;
  background: #fff7ed;
}
.composer-mode-btn.mode-auto:hover {
  background: #ffedd5;
}
.composer-mode-btn.mode-strict {
  border-color: #b91c1c;
  color: #b91c1c;
  background: #fef2f2;
}
.send-btn:hover { background: #2962d9; }
.send-btn:disabled { background: var(--border-strong); cursor: not-allowed; }
.send-btn.is-busy {
  width: auto;
  min-width: 72px;
  padding: 0 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}
.card.is-cancelling .tool-icon {
  color: var(--fg-faint);
}
.composer-hint {
  color: var(--fg-faint);
  font-size: 11.5px;
  margin-top: 6px;
  width: 100%;
  max-width: 820px;
  text-align: left;
  padding-left: 6px;
  box-sizing: border-box;
}

/* buttons */
.btn {
  padding: 6px 12px;
  border: 1px solid var(--border);
  background: var(--card-bg);
  border-radius: 7px;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.btn:hover { background: var(--card-hover); }
.btn.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn.primary:hover { background: #2962d9; }
.btn.danger-ghost { color: var(--err); border-color: #f8b4b4; }
.btn.danger-ghost:hover { background: #fde8e8; }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }

/* ---------- settings page (re-used layout, kept simple) ---------- */

.settings-root main { max-width: 760px; margin: 0 auto; padding: 18px; }
fieldset {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 18px;
  margin-bottom: 16px;
  background: var(--card-bg);
}
fieldset legend { padding: 0 6px; font-weight: 600; color: var(--fg); }

.field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 8px 0;
}
.field label { color: var(--fg-muted); font-size: 13px; }
.field input[type="text"],
.field input[type="password"],
.field input[type="number"],
.field textarea,
.field select {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border-strong);
  border-radius: 7px;
  font: inherit;
  font-size: 13px;
  background: #fff;
}
.field .hint { color: var(--fg-faint); font-size: 12px; margin-top: 2px; }
.hint { color: var(--fg-faint); font-size: 12px; line-height: 1.4; }
.actions { display: flex; gap: 6px; margin-top: 10px; align-items: center; }
.status { margin-left: 0; margin-right: auto; color: var(--fg-muted); font-size: 13px; min-height: 16px; }
.status.error { color: var(--err); }
.status.ok    { color: var(--ok); }

.modal.modal-settings {
  width: min(640px, 86vw);
  max-height: min(88vh, 980px);
  padding: 0;
  gap: 0;
  overflow: hidden;
  border-radius: 18px;
}
.modal-settings-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px 14px 18px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, #ffffff 0%, #f3f4f6 100%);
}
.modal-settings-head h3 {
  margin: 0;
  font-size: 18px;
}
.modal-close-btn {
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 999px;
  font-size: 18px;
  line-height: 1;
}
.modal-settings-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 18px;
  background: #fafafa;
}
.modal-settings #settings-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.modal-settings fieldset {
  margin-bottom: 0;
}
.modal-settings .actions {
  position: sticky;
  bottom: 0;
  padding: 12px 0 2px 0;
  margin-top: 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.96) 26%, rgba(255, 255, 255, 1) 100%);
}

/* ---------- tool output human-readable summary ---------- */

/* Shown between the card header and the collapsible body so the user
   can read the result at a glance without expanding the raw JSON. */
.tool-summary {
  padding: 6px 12px 7px 12px;
  font-size: 13px;
  color: var(--fg);
  background: #f5f5f5;
  border-top: 1px solid var(--border);
  line-height: 1.45;
}
.card.is-error .tool-summary { display: none; }

/* ---------- census_download cancel button ---------- */

/* The cancel button lives inside .card-header so it is always visible
   even when the card body is collapsed.  Push it to the far right with
   margin-left: auto so it does not crowd the tool name / preview. */
.cancel-download-btn {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 12px;
  padding: 3px 9px;
  /* Prevent the header click-to-expand handler from firing when the
     user clicks the button — stopPropagation() in JS handles this, but
     the visual cursor should still be pointer, not the default text. */
  cursor: pointer;
}

/* Hide the cancel button once the card is no longer running. */
.card:not(.is-running) .cancel-download-btn {
  display: none !important;
}

/* ---------- streaming bubble cursor ---------- */

/* While the agent is streaming tokens, append a blinking block cursor
   after the last character so the user can see output is still arriving. */
.bubble.streaming::after {
  content: "▋";
  display: inline-block;
  color: var(--accent);
  animation: blink-cursor 0.8s step-start infinite;
  margin-left: 1px;
  vertical-align: baseline;
}
@keyframes blink-cursor {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0; }
}

/* Inline "Summarizing context…" status — lightweight, no card, no
   warning icon. A small grey line with a spinning ring, centred. */
.compacting-notice {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  padding: 6px 0;
  font-size: 11.5px;
  color: var(--fg-faint);
  letter-spacing: 0.2px;
}
.compacting-spinner {
  width: 10px;
  height: 10px;
  border: 1.5px solid var(--border);
  border-top-color: var(--fg-muted);
  border-radius: 50%;
  animation: compacting-spin 0.9s linear infinite;
}
@keyframes compacting-spin {
  to { transform: rotate(360deg); }
}

/* Old plan-card chrome retired — see `.plan-body` under the work
   timeline section, which renders the planner output as a flat grey
   block hung off a timeline dot. The `.plan-card` class is kept here
   as a no-op selector so any in-page residual markup degrades to
   plain inline content rather than picking up stale styling. */
/* Old `.plan-card-step` dot+line styles retired in favour of the
   single shared work-timeline above. The `.plan-step` (no `-card-`)
   list-item rules under .plan-body now own running/done/failed
   visuals. */

/* Body text of the active "Thinking…" timeline node. The pulsing
   dot is provided by the timeline (`.timeline-node.is-active
   .node-dot`); this rule just animates the verb. The `.is-frozen`
   variant is the "Thought for Xs" breadcrumb. */
.thinking-line {
  display: inline;
  font-size: 12.5px;
  color: var(--fg-muted);
}
.thinking-line.is-active .thinking-label {
  font-style: italic;
  animation: thinking-pulse 1.6s ease-in-out infinite;
}
.thinking-line.is-frozen {
  color: var(--fg-faint);
  font-size: 11.5px;
}
@keyframes thinking-pulse {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}
@keyframes thinking-dot-pulse {
  /* Solid dot pulses larger (scale 1 → 1.45) while a translucent
     blue ring radiates outward via a second box-shadow layer.
     The first box-shadow stays as the bg-coloured punch that hides
     the connecting line behind the dot. */
  0% {
    transform: scale(1);
    box-shadow:
      0 0 0 3px var(--bg),
      0 0 0 0   rgba(59, 130, 246, 0.55);
  }
  70% {
    transform: scale(1.45);
    box-shadow:
      0 0 0 3px var(--bg),
      0 0 0 10px rgba(59, 130, 246, 0);
  }
  100% {
    transform: scale(1);
    box-shadow:
      0 0 0 3px var(--bg),
      0 0 0 0   rgba(59, 130, 246, 0);
  }
}

/* =====================================================================
 * Three-column app layout (left:center:right = 1:5:1).
 * ===================================================================== */

.app-layout {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  /* Card-style chrome on ALL three columns now (sidebar + chat +
     notebook). Equal outer padding on every side so the sidebar
     floats off the left edge with the same gutter as the right
     panels — no flush-left look. */
  gap: 12px;
  padding: 10px 12px 12px 12px;
  height: 100%;
  overflow: hidden;
  background: #ffffff;
  transition: grid-template-columns 0.22s ease;
}
/* Notebook open: center column shrinks, notebook takes the lion's share. */
.app-layout.has-notebook {
  grid-template-columns:
    220px
    minmax(320px, 0.9fr)
    minmax(420px, 1.15fr);
}
/* Sidebar collapsed: shrink the first column to ~the icon width.
   48px = 16px icon + 16px horizontal padding × 2. */
.app-layout.is-sidebar-collapsed {
  grid-template-columns: 48px minmax(0, 1fr);
}
.app-layout.is-sidebar-collapsed.has-notebook {
  grid-template-columns:
    48px
    minmax(320px, 0.9fr)
    minmax(420px, 1.15fr);
}
.notebook-panel[hidden] { display: none; }

/* Both main panels (chat + notebook) get the rounded-card chrome.
   The sidebar keeps its flush-left look so it reads as the app shell.
   On a pure-white page the border+shadow does ALL the work of saying
   "this is a card" — slightly heavier than the original so the chrome
   doesn't disappear into the white gutter. */
.center,
.notebook-panel {
  background: #fff;
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04);
  overflow: hidden;
}
/* When the notebook is open, drop its now-redundant left border —
   the card outline already provides the separation. */
.notebook-panel { border-left: 1px solid var(--border); }

/* ---- sidebar shell ---- */

/* ChatGPT-style sidebar: light grey background, compact items with
   rounded hover pills, muted secondary text, small uppercase section
   labels. The whole rail reads as "navigation chrome" against the
   bright chat + notebook cards on the right.
   Reference visual:
   - bg #f4f4f5 (matches ChatGPT's left rail)
   - section headings 11px, letter-spacing, muted, no transform
   - row items: 8px vertical padding, 8px horizontal, rounded 8px
   - hover: rgba(0,0,0,0.05); active: rgba(0,0,0,0.07)
   - icons: 14-16px, faded color
   - tighter line-height for density */
.sidebar {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: #f4f4f5;
  color: var(--fg-muted);
  padding: 10px 6px 12px 6px;
  font-size: 13px;
  border: none;
  border-radius: 14px;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04);
  /* Intentionally NOT ``overflow: hidden`` — that used to clip the
     no-session placeholder ("Pick a session to see its workspace.")
     into a 2-line wrap. Inner scroll panels (session list, tree)
     have their own per-element ``overflow`` rules, and the
     rounded corners are drawn by the background + border-radius
     alone, so removing the clip doesn't leak anything in normal
     usage. The placeholder is allowed to overflow into the chat
     column on a single line; it only renders when the chat column
     is empty too, so nothing gets visually masked. */
  transition: padding 0.18s ease;
}

/* ``.sidebar-header`` / ``.sidebar-app-title`` / ``.sidebar-toolbar``
   were brief stops on the way to the current "brand cluster lives
   in TopBar" layout. Kept as harmless no-op selectors so any stale
   markup wouldn't visually break — new code should ignore them. */
.sidebar-header { display: contents; }
.sidebar-app-title { display: none; }
.sidebar-toolbar {
  display: flex;
  justify-content: flex-end;
  padding: 2px 4px 4px 4px;
}
.sidebar-toggle {
  width: 26px;
  height: 26px;
  padding: 0;
  border: none !important;
  background: transparent !important;
  color: #6b7280;
  font-size: 18px;
  line-height: 1;
  border-radius: 6px;
  cursor: pointer;
}
.sidebar-toggle:hover { background: rgba(0, 0, 0, 0.06) !important; color: var(--fg); }

/* ---- collapsed state: just-the-icons rail ------------------------ */
.sidebar.is-collapsed {
  padding: 10px 4px 12px 4px;
}
.sidebar.is-collapsed .sidebar-toolbar { justify-content: center; }
/* Header in collapsed mode: brand icon + toggle stay; the title text
   drops out so the row fits the narrow rail. ``flex: 0 0 auto`` on
   the brand keeps it pinned even when the title's flex-grow is
   removed. */
.sidebar.is-collapsed .sidebar-header {
  padding: 8px 0;
  justify-content: center;
  gap: 4px;
}
/* Hide section-level "no session" / "no files" / "no sessions yet"
   placeholder rows when the rail is reduced to its icon-only form.
   Their full sentence wraps badly inside a 36-px rail and is
   redundant with the empty-state already implied by the absence of
   list items. */
.sidebar.is-collapsed .tree-placeholder { display: none; }
.sidebar.is-collapsed .session-item.is-empty { display: none; }
/* Single-line placeholder rendering: take just the width the text
   needs (``max-content``) and refuse to wrap. When that width
   exceeds the sidebar column it overflows rightward into the chat
   column — which is fine because the placeholder ONLY renders
   when no session is selected, i.e. when the chat itself is also
   showing its own empty-state message. */
.tree-placeholder {
  white-space: nowrap;
  width: max-content;
}
.sidebar-toggle-icon { display: block; }
/* Hide section headings + their action buttons */
.sidebar.is-collapsed .panel-head { padding: 8px 0 4px 0; justify-content: center; }
.sidebar.is-collapsed .panel-head h2 { display: none; }
.sidebar.is-collapsed .panel-head-actions { display: none; }
.sidebar.is-collapsed .panel-sub { display: none; }
/* Each row collapses to an icon-only square; the text inside drops
   out. Center the icon, drop horizontal padding so the box stays
   compact. */
.sidebar.is-collapsed .session-list,
.sidebar.is-collapsed .tree { padding: 0 2px; }
.sidebar.is-collapsed .session-item,
.sidebar.is-collapsed .tree-item {
  justify-content: center;
  padding: 6px 0;
  gap: 0;
}
.sidebar.is-collapsed .session-item .title,
.sidebar.is-collapsed .tree-item .name,
.sidebar.is-collapsed .tree-item .size,
.sidebar.is-collapsed .tree-item .tw-twisty { display: none; }
.sidebar.is-collapsed .session-icon,
.sidebar.is-collapsed .tree-item .icon {
  font-size: 16px;
  opacity: 1;
}
/* Native title attribute on each row already provides hover tooltips
   with the full name — no extra CSS-only popup needed for collapsed
   mode. */

/* Section headings ("Workspace", "Sessions") */
.sidebar .panel-head {
  padding: 10px 10px 6px 10px;
}
.sidebar .panel-head h2 {
  margin: 0;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.4px;
  color: #6b7280;
  text-transform: none;
}
.sidebar .panel-head-actions .ghost-btn.mini {
  font-size: 12px;
  padding: 2px 6px;
  border: none;
  background: transparent;
  color: #6b7280;
}
.sidebar .panel-head-actions .ghost-btn.mini:hover {
  background: rgba(0, 0, 0, 0.06);
  color: var(--fg);
}

/* Workspace path subtitle */
.sidebar .panel-sub {
  padding: 0 12px 6px 12px;
  font-size: 11px;
  color: #9ca3af;
}

/* Session list — pixel-aligned with the workspace tree below.
   The two lists must share an identical horizontal box model
   (no padding on the list container, identical padding on each
   row, identical icon width) so the icons line up at the same
   x-coord and the collapsed state reads as a single column. */
.sidebar .session-list {
  margin: 0;                       /* drop browser default <ul> margin */
  padding: 0 4px 6px 4px;
  gap: 1px;
  list-style: none;
}
.sidebar .session-item {
  box-sizing: border-box;
  margin: 0;
  width: 100%;
  min-height: 30px;
  padding: 6px 10px;
  gap: 8px;
  border-radius: 8px;
  font-size: 13.5px;
  color: var(--fg-muted);
  background: transparent;
  transition: background 0.1s ease;
  display: flex;
  align-items: center;
}
.sidebar .session-item:hover { background: rgba(0, 0, 0, 0.05); }
.sidebar .session-item.is-active {
  background: rgba(0, 0, 0, 0.08);
  color: var(--fg);
}
.sidebar .session-item .title {
  font-weight: 400;
  font-size: 13.5px;
  color: inherit;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar .session-item.is-active .title { font-weight: 500; }
.sidebar .session-icon {
  box-sizing: border-box;
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  font-size: 14px;
  color: inherit;
  opacity: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Workspace tree rows — IDENTICAL horizontal box model to
   .session-item above. Outer container padding 4px, row padding
   10px, gap 8px, icon flex-basis 16px. */
.sidebar .tree {
  margin: 0;
  padding: 0 4px;
}
.sidebar .tree-item {
  box-sizing: border-box;
  margin: 0;
  width: 100%;
  min-height: 30px;
  padding: 6px 10px;
  gap: 8px;
  border-radius: 8px;
  font-size: 13.5px;
  color: var(--fg-muted);
  display: flex;
  align-items: center;
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background 0.1s ease;
  font-family: inherit;
}
.sidebar .tree-item:hover { background: rgba(0, 0, 0, 0.05); }
.sidebar .tree-item.is-selected,
.sidebar .tree-item.is-open {
  background: rgba(0, 0, 0, 0.07);
  color: var(--fg);
}
.sidebar .tree-item .icon {
  box-sizing: border-box;
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  font-size: 14px;
  color: inherit;
  opacity: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.sidebar .tree-item .name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: inherit;
}

/* Top-bar brand icon */
.brand-icon {
  width: 22px;
  height: 22px;
  margin-right: 2px;
  display: inline-block;
  vertical-align: middle;
}
.sidebar .panel {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.sidebar .panel-history {
  flex: 1 1 56%;
}
.sidebar .panel-workspace {
  flex: 1 1 44%;
}
.sidebar .panel + .panel {
  margin-top: 12px;
}

.panel-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 8px 8px 10px;
  background: transparent;
  border: none;
}
.panel-head h2 {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--fg-faint);
  text-transform: none;
}
.panel-sub {
  flex: 0 0 auto;
  padding: 0 10px 8px 10px;
  font-size: 11.5px;
  color: var(--fg-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: transparent;
  border: none;
  cursor: default;
}
.panel-head-actions {
  display: flex;
  align-items: center;
  gap: 4px;
}
.active-session-title {
  font-size: 13px;
  color: var(--fg-muted);
  padding: 2px 8px;
  border-left: 1px solid var(--border);
  margin-left: 4px;
}

/* ---- mini button ---- */

.ghost-btn.mini,
.accent-btn.mini {
  font-size: 11.5px;
  padding: 4px 8px;
  line-height: 1.2;
  border-radius: 6px;
}
.accent-btn {
  font-size: 13px;
  color: #fff;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 8px;
  padding: 6px 12px;
  cursor: pointer;
}
.accent-btn:hover { background: #2962d9; }
.accent-btn:disabled {
  background: var(--border-strong);
  border-color: var(--border-strong);
  cursor: not-allowed;
}

/* ---- tree (shared by workspace + results + ingest modal) ---- */

.tree {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: auto;
  padding: 2px 4px 8px 4px;
  font-size: 13px;
  /* Hide the scrollbar by default. The track and thumb are pulled out
     of the layout entirely so the listing can use the full panel width. */
  scrollbar-width: none;          /* Firefox */
  -ms-overflow-style: none;       /* old IE / Edge */
}
.tree::-webkit-scrollbar {        /* WebKit / Blink (Chrome, Safari) */
  width: 0;
  height: 0;
  background: transparent;
}
/* Reveal the scrollbar only when the user is hovering the tree
   (entering the panel or any item inside it). The width animates
   in via a CSS transition so the layout barely shifts. */
.tree:hover {
  scrollbar-width: thin;
}
.tree:hover::-webkit-scrollbar {
  width: 8px;
}
.tree:hover::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 4px;
}
.tree:hover::-webkit-scrollbar-track {
  background: transparent;
}

/* VS Code-style twisty (▸ collapsed / ▾ open) at the start of every
   directory row. File rows render an empty placeholder of the same
   width so child levels stay vertically aligned. */
.tw-twisty {
  flex: 0 0 12px;
  width: 12px;
  text-align: center;
  font-size: 9px;
  color: var(--fg-faint);
  user-select: none;
}
.tw-twisty.empty { visibility: hidden; }
.tree-item.is-open > .tw-twisty { color: var(--fg); }
.tree:empty::before {
  content: attr(data-empty-text);
  display: block;
  color: var(--fg-faint);
  font-size: 12px;
  text-align: center;
  padding: 20px 12px;
}
.tree-item {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 1px 4px;
  padding: 8px 10px;
  cursor: pointer;
  user-select: none;
  color: var(--fg);
  border: none;
  background: none;
  border-radius: 12px;
  width: calc(100% - 8px);
  text-align: left;
  font: inherit;
}
.tree-item:hover { background: #f3f4f6; }
.tree-item.is-selected,
.tree-item.is-open { background: #f3f4f6; }
.tree-item .icon {
  flex: 0 0 auto;
  width: 16px;
  color: var(--fg-muted);
}
.tree-item .name {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tree-item .size {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}
.sidebar .tree-item .size {
  display: none;
}
.sidebar .tree-item {
  font-size: 14px;
}
.sidebar .tree:empty::before {
  text-align: left;
  padding: 8px 14px;
}
.tree-group {
  padding: 8px 12px 2px 12px;
  font-size: 11px;
  font-weight: 600;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.tree-children {
  padding-left: 14px;
}

/* ---- session list (left bottom) ----
 * Rendered as "pill" buttons — one per session, single-line title only
 * (full workspace path shows via the native title= tooltip on hover).
 */

.session-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 2px 4px 8px 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.session-item {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 42px;
  padding: 9px 10px;
  cursor: pointer;
  border: none;
  border-radius: 12px;
  background: transparent;
  transition: background 0.12s ease, color 0.12s ease, transform 0.02s ease;
}
.session-item:hover {
  background: #f3f4f6;
}
.session-item:active { transform: translateY(1px); }
.session-item.is-active {
  background: #f3f4f6;
}
.session-item .title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14px;
  font-weight: 500;
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.session-item.is-active .title { color: var(--fg); }
.session-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--fg);
  flex: 0 0 auto;
}
.session-icon svg {
  display: block;
}
.session-more {
  flex: 0 0 auto;
  font: inherit;
  background: none;
  border: none;
  color: var(--fg-faint);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.session-item:hover .session-more,
.session-item.is-active .session-more {
  opacity: 0.7;
}
.session-more:hover {
  opacity: 1;
  color: var(--fg);
  background: rgba(255, 255, 255, 0.8);
}

/* ---- center column ---- */

.center {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: transparent;
  overflow: hidden;
}
.center .feed-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
.center #feed {
  width: 100%;
  max-width: 820px;
  margin: 0 auto;
  padding: 30px 28px 22px 28px;
  box-sizing: border-box;
}
.composer-toolbar {
  width: 100%;
  max-width: 820px;
  display: flex;
  justify-content: flex-start;
  padding: 0 6px 6px 6px;
  box-sizing: border-box;
  gap: 8px;
}

/* ---- modals ---- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(18, 20, 24, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
}

/* ───────── JOBS center modal (Phase D-1) ───────── */
.jobs-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(18, 20, 24, 0.48);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 60;
}
.jobs-modal {
  width: min(1100px, 94vw);
  height: min(720px, 88vh);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: 0 12px 48px rgba(0,0,0,0.22);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.jobs-modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-muted);
}
.jobs-modal-header h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  display: inline-flex; align-items: center; gap: 10px;
}
.jobs-modal-running-badge {
  font-size: 11px;
  background: var(--accent);
  color: #fff;
  border-radius: 999px;
  padding: 2px 9px;
  font-weight: 600;
}
.jobs-modal-close {
  background: none;
  border: none;
  font-size: 22px;
  color: var(--fg-muted);
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
}
.jobs-modal-close:hover { color: var(--fg); }

.jobs-modal-body {
  flex: 1;
  display: grid;
  grid-template-columns: 280px 1fr;
  min-height: 0;
}
.jobs-modal-list {
  border-right: 1px solid var(--border);
  overflow-y: auto;
  background: var(--bg);
}
.jobs-modal-list ul { list-style: none; margin: 0; padding: 6px 0; }
.jobs-modal-empty {
  padding: 30px 24px;
  color: var(--fg-faint);
  font-size: 13px;
  text-align: center;
}

.jobs-row { display: block; }
.jobs-row-btn {
  display: flex; gap: 10px; align-items: flex-start;
  width: 100%;
  border: none;
  background: none;
  text-align: left;
  padding: 10px 14px;
  cursor: pointer;
  border-left: 3px solid transparent;
}
.jobs-row-btn:hover { background: var(--bg-muted); }
.jobs-row.selected .jobs-row-btn {
  background: var(--bg-muted);
  border-left-color: var(--accent);
}
.jobs-row-icon {
  flex-shrink: 0;
  width: 22px; height: 22px;
  border-radius: 999px;
  background: var(--border);
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px;
  font-weight: 700;
}
.jobs-row-icon.status-queued { background: #94a3b8; }
.jobs-row-icon.status-running { background: #2563eb; }
.jobs-row-icon.status-done { background: #16a34a; }
.jobs-row-icon.status-failed { background: #b91c1c; }
.jobs-row-icon.status-cancelled { background: #94a3b8; }
.jobs-row-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.jobs-row-title {
  font-size: 13px;
  font-weight: 500;
  color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jobs-row-sub {
  font-size: 11.5px;
  color: var(--fg-muted);
}

.jobs-modal-detail {
  overflow-y: auto;
  padding: 24px 28px;
  background: var(--bg);
}
.jobs-detail-pane { display: flex; flex-direction: column; gap: 18px; }
.jobs-detail-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px;
}
.jobs-detail-title {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--fg);
  word-break: break-word;
}
.jobs-detail-status {
  flex-shrink: 0;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}
.jobs-detail-status.status-queued    { background: #f1f5f9; color: #475569; }
.jobs-detail-status.status-running   { background: #dbeafe; color: #1d4ed8; }
.jobs-detail-status.status-done      { background: #dcfce7; color: #166534; }
.jobs-detail-status.status-failed    { background: #fee2e2; color: #b91c1c; }
.jobs-detail-status.status-cancelled { background: #f1f5f9; color: #64748b; }

.jobs-detail-progress {
  display: flex; flex-direction: column; gap: 6px;
}
.jobs-detail-bar {
  height: 8px;
  border-radius: 4px;
  background: var(--accent);
  transition: width 0.3s ease;
  position: relative;
  overflow: hidden;
}
.jobs-detail-bar.status-running { background: #2563eb; }
.jobs-detail-bar.status-done    { background: #16a34a; }
.jobs-detail-bar.status-failed  { background: #b91c1c; }
.jobs-detail-bar.status-cancelled { background: var(--border); }
.jobs-detail-bar.indeterminate {
  background: linear-gradient(90deg, var(--accent) 0%, var(--bg) 50%, var(--accent) 100%);
  background-size: 200% 100%;
  animation: jobs-bar-shimmer 1.6s linear infinite;
}
@keyframes jobs-bar-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.jobs-detail-bar-stats {
  display: flex; gap: 16px; flex-wrap: wrap;
  font-size: 12px;
  color: var(--fg-muted);
}
.jobs-detail-speed { color: var(--accent); font-weight: 600; }
.jobs-detail-elapsed { margin-left: auto; }

.jobs-detail-grid {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 6px 14px;
  font-size: 12.5px;
  margin: 0;
}
.jobs-detail-grid dt {
  color: var(--fg-muted);
  font-weight: 500;
}
.jobs-detail-grid dd {
  margin: 0;
  color: var(--fg);
  word-break: break-all;
}
.jobs-detail-grid dd.mono {
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 12px;
}
.jobs-detail-grid dd.small { font-size: 11.5px; }
.jobs-detail-warn { color: #b91c1c; font-weight: 600; }

.jobs-detail-error {
  padding: 10px 12px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
  color: #b91c1c;
  font-size: 12.5px;
  word-break: break-word;
}

.jobs-detail-actions {
  display: flex; gap: 8px;
}

.jobs-detail-trials { display: flex; flex-direction: column; gap: 6px; }
.jobs-detail-trials h4 {
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.jobs-detail-trials ol {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.jobs-detail-trials li.trial {
  display: flex; gap: 10px;
  font-size: 12.5px;
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--bg-muted);
}
.trial-icon { width: 16px; }
.trial.status-completed .trial-icon { color: #16a34a; }
.trial.status-failed    .trial-icon { color: #b91c1c; }
.trial.status-running   .trial-icon { color: #2563eb; }
.trial-text { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.trial-instr.mono { font-family: var(--mono, ui-monospace, monospace); }
.trial-summary { color: var(--fg-muted); }
.trial-error { color: #b91c1c; }
.trial-elapsed { color: var(--fg-faint); font-size: 11.5px; }

/* Top bar Jobs badge */
.topbar-jobs-badge {
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: 6px;
  min-width: 18px; height: 18px;
  background: var(--accent);
  color: #fff;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  padding: 0 5px;
}

/* Sidebar Jobs expand button */
.sidebar-section-title { display: flex; align-items: center; gap: 8px; }
.job-progress-expand-btn {
  margin-left: auto;
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1px 6px;
  font-size: 12px;
  cursor: pointer;
  color: var(--fg-muted);
}
.job-progress-expand-btn:hover { color: var(--fg); border-color: var(--border-strong); }

.modal-backdrop[hidden] { display: none; }
.modal {
  width: min(560px, 90vw);
  max-height: 88vh;
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0,0,0,0.18);
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow: hidden;
}
.modal h3 {
  margin: 0 0 6px 0;
  font-size: 16px;
}
.modal-label {
  font-size: 12px;
  color: var(--fg-muted);
  margin-top: 6px;
}
.modal input[type="text"] {
  padding: 8px 10px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  font: inherit;
  font-size: 14px;
}
.modal input[type="text"]:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.modal-hint {
  color: var(--fg-faint);
  font-size: 12px;
  margin: 0;
}
.modal-sub {
  font-size: 12px;
  color: var(--fg-muted);
  display: flex;
  gap: 6px;
  align-items: center;
}
.modal-sub code,
.ingest-selected code {
  background: var(--code-bg);
  color: var(--code-accent);
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 11.5px;
}
.modal-tree {
  flex: 1 1 auto;
  min-height: 160px;
  max-height: 320px;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0;
  overflow: auto;
  background: #fafafa;
}
.ingest-selected {
  font-size: 12px;
  display: flex;
  gap: 6px;
  align-items: center;
  padding-top: 4px;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 6px;
}

/* ---- context menu + small prompt modal ---- */

.ctx-menu {
  position: fixed;
  z-index: 70;
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.18);
  padding: 4px 0;
  min-width: 160px;
  font-size: 13px;
  user-select: none;
}
.ctx-menu[hidden] { display: none; }
.ctx-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  cursor: pointer;
  color: var(--fg);
  background: none;
  border: none;
  width: 100%;
  text-align: left;
  font: inherit;
}
.ctx-menu-item:hover { background: var(--card-hover); }
.ctx-menu-item.danger { color: var(--err); }
.ctx-menu-item.danger:hover { background: var(--err-bg); }
.ctx-menu-item[disabled] { color: var(--fg-faint); cursor: not-allowed; background: none; }
.ctx-menu-sep {
  height: 1px;
  background: var(--border);
  margin: 4px 0;
}

.modal.modal-sm { width: min(380px, 90vw); }

.panel-nav {
  flex: 0 0 auto;
  display: flex;
  gap: 4px;
  align-items: center;
  padding: 4px 8px;
  border-bottom: 1px dashed var(--border);
  background: #fafafa;
  font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  overflow-x: auto;
}
.panel-nav button {
  background: none;
  border: none;
  color: var(--accent);
  cursor: pointer;
  padding: 2px 4px;
  font: inherit;
}
.panel-nav button:hover { text-decoration: underline; }
.panel-nav .sep { color: var(--fg-faint); }
.panel-nav .up-btn { color: var(--fg-muted); padding: 0 4px; }
.panel-nav .up-btn:disabled { color: var(--fg-faint); cursor: not-allowed; }

.modal-row {
  display: flex;
  gap: 6px;
  align-items: center;
}
.modal-row input[type="text"] {
  flex: 1 1 auto;
}

.browser-bar {
  display: flex;
  gap: 6px;
  align-items: center;
}
.browser-bar .browser-path {
  flex: 1 1 auto;
  padding: 6px 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 12px;
  background: #fafafa;
}

/* ======================================================================
 * Notebook panel — mimics the Anaconda / JupyterLab cell layout.
 * Pale blue left gutter with In[N]: / Out[N]: prompts; input cells on a
 * light-gray background, outputs plain; images render inline.
 * ====================================================================== */

.notebook-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  margin: 0;
  background: #fff;
  /* border / radius / shadow live on the shared `.center, .notebook-panel`
     rule above so the chrome stays consistent. */
  overflow: hidden;
}

/* Snapshot view — the panel is showing a historical version of the
   notebook (clicked from an older chat pill). Visually distinct so
   the user can't confuse it with the live state, but textareas stay
   editable so user-tweaks auto-save into that snapshot file. */
.notebook-panel.is-snapshot {
  background: #fbfaf6;
}
.notebook-panel.is-snapshot .nb-cell {
  background: transparent;
}
.notebook-panel.is-snapshot .nb-input {
  background: rgba(255, 246, 220, 0.4);
}
/* Pre-multi-notebook history: ``is-snapshot`` (source.kind="pill")
   used to mean "viewing a read-only historical version" so we
   disabled Run. Under the current architecture EVERY agent tab has
   ``source.kind="pill"`` (set by applyAgentSnapshot on the live
   work tab itself), so that rule disables Run on the very tab the
   user wants to use. Run is always allowed — it executes against
   the shared live kernel and writes its output to ephemeral
   ``runtimeOutputs``, never persisting back. The rule is therefore
   removed entirely; if a future "frozen historical view" ever needs
   to disable Run again it should look at a dedicated flag, not at
   pill-vs-live (which no longer carries that semantic).  */
/* The banner sits between the head bar and the cell list, makes the
   "you're not on live" state impossible to miss, and carries the
   "Back to current" affordance. */
.nb-snapshot-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  background: var(--warn-bg);
  color: var(--warn);
  border-bottom: 1px solid #f7d994;
  font-size: 12.5px;
  flex: 0 0 auto;
}
.nb-snap-icon { font-size: 13px; flex: 0 0 auto; }
.nb-snap-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nb-snap-back { flex: 0 0 auto; }
/* Live-updated badge — fires when the agent edits the live notebook
   while the user is viewing a historical snapshot. Pulses softly so
   the user notices, but doesn't auto-switch their view. */
.nb-snap-live-badge {
  flex: 0 0 auto;
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
  animation: live-badge-pulse 2.0s ease-in-out infinite;
}
.nb-snap-live-badge:hover {
  background: #1d57c8;
  border-color: #1d57c8;
}
@keyframes live-badge-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(47, 111, 235, 0.4); }
  50%      { box-shadow: 0 0 0 5px rgba(47, 111, 235, 0.0); }
}

/* Compact header — only holds the right-side controls now. The
   "Notebook" title and "Kernel: ..." label that used to live on the
   left were removed; the floating × close button (top-right corner)
   already identifies this panel as the notebook. */
.notebook-head {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 12px 56px 12px 14px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, #fbfdff 0%, #f4f8fc 100%);
}
.notebook-head-controls {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* "Interpreter" label sits inline with the dropdown rather than
   stacking above it. */
.notebook-select-group {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--fg-muted);
  letter-spacing: 0.2px;
}
.notebook-select-group select,
#new-session-interpreter {
  min-width: 200px;
  padding: 4px 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: #fff;
  color: var(--fg);
  font: inherit;
  font-size: 12.5px;
}

/* Floating close button — replaces the old header bar. */
.notebook-float-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: #fff;
  color: var(--fg-muted);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 3;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.notebook-float-close:hover {
  background: var(--card-hover);
  border-color: var(--border-strong);
  color: var(--fg);
}

.notebook-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 20px 18px 40px 18px;
  scroll-behavior: smooth;
}
.notebook-body:empty::before {
  content: attr(data-empty-text);
  display: block;
  color: var(--fg-faint);
  font-size: 12.5px;
  text-align: center;
  padding: 40px 20px;
}

/* One cell = one input block + (optional) one output block, spaced
   apart from the next cell by 14px. */
.nb-cell {
  display: grid;
  /* ``minmax(0, 1fr)`` instead of bare ``1fr``: the latter resolves
     to ``minmax(auto, 1fr)`` whose ``auto`` minimum equals the
     LARGEST intrinsic min-content of any descendant. A wide HTML
     output (DataFrame `_repr_html_` with ``width: max-content``)
     would push that min-content past the panel width and visibly
     stretch the cell's code column. ``minmax(0, 1fr)`` pins the
     minimum at 0 so descendants must respect their column's actual
     width — wide content scrolls horizontally inside its OWN
     container instead of expanding the parent. */
  grid-template-columns: 64px minmax(0, 1fr);
  column-gap: 8px;
  margin-bottom: 14px;
  scroll-margin-top: 16px;
  position: relative;
}
.nb-cell.is-highlighted > .nb-input-wrap,
.nb-cell.is-highlighted > .nb-output { outline: 2px solid #b6dffc; outline-offset: 1px; }

/* Markdown cell: prose-style rendering, no execution prompt, no
   Run button. The "md" gutter is dimmed so the prose dominates the
   eye. Double-click flips the body into a plain textarea via the
   ``nb-input-markdown`` class. */
.nb-cell.is-markdown .nb-prompt {
  color: var(--fg-faint);
  font-style: italic;
  font-size: 11px;
}
.nb-markdown {
  padding: 10px 12px;
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: text;
  line-height: 1.55;
  font-size: 13px;
  background: rgba(0, 0, 0, 0.015);
}
.nb-markdown:hover { border-color: var(--border); }
.nb-markdown h1, .nb-markdown h2, .nb-markdown h3 {
  margin: 0.4em 0 0.3em;
  font-weight: 600;
}
.nb-markdown h1 { font-size: 18px; }
.nb-markdown h2 { font-size: 16px; }
.nb-markdown h3 { font-size: 14px; }
.nb-markdown p  { margin: 0.4em 0; }
.nb-markdown code {
  background: rgba(0, 0, 0, 0.06);
  padding: 1px 4px;
  border-radius: 3px;
  font-size: 12px;
}
.nb-markdown pre {
  background: rgba(0, 0, 0, 0.04);
  padding: 8px 10px;
  border-radius: 4px;
  overflow-x: auto;
}
.nb-markdown ul, .nb-markdown ol { margin: 0.4em 0 0.4em 1.4em; }
.nb-input-markdown { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; }

/* Browser-style tab strip above the notebook viewer. ----------------- */
.nb-tabbar {
  display: flex;
  flex-shrink: 0;                 /* in flex-column panel, do not squish */
  align-items: stretch;
  gap: 2px;
  padding: 6px 56px 0 8px;        /* right padding clears the floating × */
  min-height: 38px;
  border-bottom: 1px solid var(--border);
  background: #f8f9fa;
  /* Per W3C, ``overflow-x: auto`` paired with default ``overflow-y:
   * visible`` forces BOTH axes to auto — that's how a vertical
   * scrollbar showed up on the right. Pin overflow-y to hidden so
   * only the horizontal axis can scroll, and only when needed. */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}
.nb-tab {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px 6px 12px;
  background: #ececec;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  font-size: 12px;
  color: var(--fg-faint);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  transition: background 0.1s ease, color 0.1s ease;
}
.nb-tab:hover { background: #e2e4e6; color: var(--fg); }
.nb-tab.is-active {
  background: #ffffff;
  color: var(--fg);
  border-color: var(--border);
  /* Fake the merged-with-body look — sits flush with the body below. */
  margin-bottom: -1px;
  padding-bottom: 7px;
  font-weight: 500;
}
.nb-tab-name {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
}
.nb-tab-name-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 12px;
  padding: 1px 4px;
  border: 1px solid var(--accent);
  border-radius: 3px;
  background: #fff;
  color: var(--fg);
  width: 8em;
  outline: none;
}
.nb-tab-close {
  border: 0;
  background: transparent;
  color: inherit;
  font-size: 14px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
  border-radius: 3px;
  opacity: 0.45;
}
.nb-tab-close:hover {
  opacity: 1;
  background: rgba(0, 0, 0, 0.08);
}

/* "+" button at the right edge of the tab strip — opens a new
   backend notebook + tab. Subdued by default so it doesn't compete
   with the active-tab affordance. */
.nb-tab-new {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  margin-left: 4px;
  border: 0;
  border-radius: 3px;
  background: transparent;
  color: var(--fg-faint);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.55;
}
.nb-tab-new:hover {
  opacity: 1;
  background: rgba(0, 0, 0, 0.06);
  color: var(--fg);
}

/* Per-cell delete X — lives in the input toolbar's actions row,
   beside the Run button. Hover-revealed on the cell so it doesn't
   add visual noise to settled cells. */
.nb-cell-delete {
  width: 22px;
  height: 22px;
  border: 0;
  background: transparent;
  color: var(--fg-faint);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  border-radius: 4px;
  opacity: 0;
  margin-left: 2px;
  transition: opacity 0.1s ease, background 0.1s ease, color 0.1s ease;
}
.nb-cell:hover .nb-cell-delete {
  opacity: 1;
}
.nb-cell-delete:hover {
  background: #fde8e8;
  color: var(--err, #c0392b);
  opacity: 1;
}

/* "+ Add cell" inserter between cells. Sized to clear both adjacent
   cells (taller container + positive margins) so it never visually
   overlaps the next cell's toolbar. */
.nb-cell-add-after {
  display: flex;
  align-items: center;
  width: 100%;
  height: 24px;
  margin: 4px 0 6px 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: 0;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.nb-cell:hover + .nb-cell-add-after,
.nb-cell-add-after:hover {
  opacity: 1;
}
.nb-cell-add-line {
  flex: 1;
  height: 1px;
  background: var(--accent);
  opacity: 0.5;
}
.nb-cell-add-plus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin: 0 8px;
  background: var(--accent);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  border-radius: 50%;
  line-height: 1;
  flex-shrink: 0;
}

/* Trailing "+ Add cell" button below the last cell. ------------------ */
.nb-add-cell-trailing {
  display: block;
  margin: 12px auto 16px;
  padding: 6px 14px;
  background: transparent;
  color: var(--accent);
  border: 1px dashed var(--accent);
  border-radius: 14px;
  font-size: 12px;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.12s ease, background 0.12s ease;
}
.nb-add-cell-trailing:hover {
  opacity: 1;
  background: rgba(37, 99, 235, 0.06);
}

/* Prompt gutter — "In [n]:" / "Out[n]:" — matches JupyterLab colouring. */
.nb-prompt {
  grid-column: 1;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 12px;
  line-height: 1.55;
  color: #307fc1;
  padding-top: 8px;
  text-align: right;
  white-space: nowrap;
}
.nb-cell.is-error .nb-prompt-in { color: var(--err); }
.nb-cell.is-running .nb-prompt-in { color: var(--fg-faint); }

.nb-input-wrap {
  grid-column: 2;
  /* Belt-and-braces against a too-wide descendant pushing the
     wrapper past its grid column. The grid track itself is now
     ``minmax(0, 1fr)`` (see ``.nb-cell``), but ``min-width: 0``
     ensures the textarea's own ``overflow-x: auto`` is what the
     browser uses for long lines instead of letting the wrapper
     resize. */
  min-width: 0;
  border: 1px solid #ddd;
  border-left: 6px solid #307fc1;
  border-radius: 0;
  background: #f7f7f7;
}
.nb-input-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px 0 10px;
}
.nb-input-meta {
  font-size: 11.5px;
  color: var(--fg-faint);
}
.nb-input-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.nb-shortcut {
  font-size: 11px;
  color: var(--fg-faint);
}
.nb-input {
  display: block;
  width: 100%;
  min-height: 80px;
  resize: vertical;
  border: none;
  background: transparent;
  padding: 8px 10px 10px 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 12.5px;
  line-height: 1.5;
  color: #1a1a1a;
  /* Long lines: do NOT wrap (white-space:pre) AND do NOT clip
     (was overflow-x: hidden). The native textarea handles its own
     horizontal scroll inside the field, so a 200-column line is
     reachable by scrolling INSIDE the code area without stretching
     the cell's width. ``overflow-y: hidden`` stays — useAutoResize
     already grows the textarea height to fit content. */
  overflow-x: auto;
  overflow-y: hidden;
  white-space: pre;
  box-sizing: border-box;
}
.nb-input:focus {
  outline: none;
}
.nb-cell.is-running .nb-input-wrap { border-left-color: var(--fg-faint); }
.nb-cell.is-error .nb-input-wrap { border-left-color: var(--err); }
.nb-cell.is-running .nb-run-btn {
  opacity: 0.8;
  cursor: wait;
}
/* Live "model is typing into this cell" preview. Accent border +
   pulsing ring tells the user which cell is being written. The
   cell is read-only while streaming (no textarea / no run button)
   so it visually reads as "view-only, work in progress". */
.nb-cell.is-streaming .nb-input-wrap {
  border-left-color: var(--accent);
  animation: nb-streaming-pulse 1.6s ease-in-out infinite;
}
@keyframes nb-streaming-pulse {
  0%, 100% { box-shadow: inset 2px 0 0 0 var(--accent); }
  50%      { box-shadow: inset 2px 0 0 0 rgba(59, 130, 246, 0.35); }
}
.nb-cell.is-streaming .nb-prompt-in { color: var(--accent); font-weight: 500; }

/* Ghost-edit notice — emitted when the model claims notebook work
   but never called notebook_edit. Renders as a centered system row
   (so it inherits the warning palette) but is fully clickable: a
   click opens the notebook panel so the user can verify. */
.ghost-edit-notice {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 640px;
  padding: 8px 12px;
  font-size: 13px;
  color: var(--warn);
  background: var(--warn-bg);
  border: 1px solid #f7d994;
  border-radius: 10px;
  cursor: pointer;
  text-align: left;
  transition: background 0.15s ease;
}
.ghost-edit-notice:hover { background: #fdebbc; }
.ghost-edit-icon { font-size: 14px; flex: 0 0 auto; }
.ghost-edit-text { line-height: 1.4; }

/* Per-line streaming view. Each line is its own DOM node so the
   currently-being-written line can light up green + show a blinking
   cursor — that's what makes streaming actually FEEL like streaming
   instead of looking like a value swap on every delta. */
.nb-stream-pre {
  margin: 0;
  padding: 6px 10px 8px 10px;
  background: #fafcff;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 13px;
  line-height: 1.55;
  color: var(--fg);
  white-space: pre;
  overflow-x: auto;
  min-height: 28px;
}
.nb-stream-line {
  padding: 0 4px;
  margin-left: -4px;        /* compensate so non-active lines align flush */
  border-left: 2px solid transparent;
  border-radius: 2px;
  white-space: pre;
}
/* The model is currently writing into this line — green band +
   typewriter cursor at the end. */
.nb-stream-line.is-active {
  background: rgba(34, 197, 94, 0.16);
  border-left-color: var(--ok);
  padding-left: 6px;
  margin-left: -4px;
}
.nb-stream-line.is-active::after {
  content: "▌";
  display: inline-block;
  color: var(--ok);
  margin-left: 1px;
  animation: blink-cursor 0.8s step-start infinite;
}

.nb-output-prompt { color: #d84315; /* Out[] is classic red/orange */ }

.nb-output {
  grid-column: 2;
  margin-top: 4px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
  padding: 4px 10px 2px 10px;
}
.nb-section {
  display: block;
  white-space: pre-wrap;
  padding: 2px 0;
}
.nb-section.stdout { color: #1a1a1a; }
.nb-section.stderr { color: #9a3412; background: #fff7ed; padding: 4px 8px; border-radius: 3px; }
.nb-section.result { color: #1a1a1a; }
.nb-section.error  { color: var(--err); background: var(--err-bg); padding: 6px 8px; border-radius: 3px; }

/* Rich-output sections from kernel display_data / execute_result.
   HTML container scoped so the kernel-emitted styles don't leak into
   the rest of the app; tables look like Jupyter's defaults.

   Width discipline: a wide DataFrame (40+ cols) used to stretch the
   notebook panel and forced its parent flex container to scroll,
   pulling the cell out of alignment with neighbouring cells. We
   constrain the container to its parent (``max-width: 100%``) and
   put a horizontal scrollbar UNDER the HTML so the table can be
   wide-as-it-needs-to-be without pushing other elements around.
   ``max-height`` keeps a 10000-row DataFrame from drowning the page;
   the user scrolls vertically inside the box too if needed. */
.nb-html-output {
  font-family: var(--font-sans, -apple-system, system-ui, sans-serif);
  font-size: 12px;
  white-space: normal;
  max-width: 100%;
  max-height: 480px;
  overflow: auto;
  padding: 6px 0;
  /* The browser's default scrollbar inside a flex item can push the
     ascenders down by 1px which makes adjacent cells flicker. Hint
     the renderer to skip that layout adjustment. */
  contain: layout;
}
.nb-html-output table {
  border-collapse: collapse;
  font-size: 12px;
  /* DataFrames omit a width and let cells size to their content.
     Without ``width: max-content`` the table tries to fit the
     container and produces ugly wrapping; with it the table is as
     wide as the data demands and the container scrolls. */
  width: max-content;
  max-width: none;
}
.nb-html-output th, .nb-html-output td {
  padding: 3px 8px;
  border: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
  /* Keep individual cell width sane — a 4KB string in one cell
     should wrap mid-cell, not balloon the column. */
  max-width: 360px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nb-html-output th { background: rgba(0, 0, 0, 0.04); font-weight: 600; }
.nb-html-output thead { background: rgba(0, 0, 0, 0.04); font-weight: 600; }
/* Pandas' default DataFrame HTML uses an inline style on the outer
   ``<div>`` — force it to flex inside our container. */
.nb-html-output > div { max-width: 100%; }

.nb-json-output {
  background: rgba(0, 0, 0, 0.03);
  border-left: 3px solid #6b7280;
  padding: 6px 10px;
  margin: 0;
  font-size: 12px;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  overflow-x: auto;
  border-radius: 0 3px 3px 0;
}

.nb-plotly-placeholder, .nb-widget-placeholder {
  font-style: italic;
  color: var(--fg-faint);
  background: rgba(0, 0, 0, 0.025);
  padding: 8px 10px;
  border-radius: 4px;
  font-size: 12px;
  border-left: 3px solid #93c5fd;
}
.nb-section.timeout { color: var(--warn); background: var(--warn-bg); padding: 6px 8px; border-radius: 3px; }
.nb-section.muted  { color: var(--fg-faint); font-style: italic; }
.nb-images {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding-top: 6px;
}
.nb-images img {
  max-width: 100%;
  max-height: 420px;
  border: 1px solid var(--border);
  background: #fff;
}

/* Chat-feed pill that stands in for the notebook cell.
   Clicking the pill opens the notebook and scrolls to the cell. */
.nb-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  background: #f3f7fb;
  border: 1px solid #cfe2f4;
  border-left: 3px solid #307fc1;
  border-radius: 6px;
  cursor: pointer;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 12.5px;
  color: #1a1a1a;
  user-select: none;
  max-width: 100%;
}
.nb-pill:hover { background: #e7f0fa; }
.nb-pill.is-running { background: #fff8e1; border-color: #facc15; border-left-color: #d97706; }
.nb-pill.is-error   { background: var(--err-bg); border-color: #fca5a5; border-left-color: var(--err); color: var(--err); }
.nb-pill-prompt { color: #307fc1; font-weight: 600; flex: 0 0 auto; }
.nb-pill.is-error .nb-pill-prompt { color: var(--err); }
.nb-pill-code {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg-muted);
}
.nb-pill-meta {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--fg-faint);
}

/* ---- Inline hunk diff under a notebook pill ----------------------
   Mirrors claude-code's StructuredDiffList: a stack of hunks with
   green/red/context lines and a left-side line-number gutter. The
   wrapper is bounded in height so a 200-line edit doesn't dominate
   the chat — overflow scrolls inside the pill.

   Auto-collapse: when ``ui.diff_default_collapsed`` is on AND the
   diff has more than ~12 displayed lines, the body gets a
   ``max-height`` plus a ``mask-image`` linear-gradient so the
   bottom rows visually fade to transparent (实变虚) instead of
   being hard-cut. The user clicks the toggle button to expand.  */
.nb-pill-diff {
  /* Flex column so the meta header (top), body (middle, scroll /
     mask), and the toggle (bottom) each get exactly their needed
     height and the toggle is NEVER clipped. The earlier rule put
     ``max-height: 360px`` + ``overflow: hidden`` on the wrapper
     itself, which cut the toggle off whenever the body filled the
     budget. Now the wrapper has no height ceiling — only the body
     scrolls / fades. */
  display: flex;
  flex-direction: column;
  margin: 6px 0 4px 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-elevated, #fafafa);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px;
  position: relative;
}
.nb-pill-diff-body {
  position: relative;
  /* Default (expanded): cap at 360px with native scroll for very
     long diffs; the user can scroll inside the body without ever
     pushing the toggle button out of view. */
  max-height: 360px;
  overflow: auto;
}
.nb-pill-diff.is-collapsed .nb-pill-diff-body {
  max-height: 200px;
  overflow: hidden;
  /* Fade the bottom 50% of the visible region so the cutoff feels
     deliberate instead of clipped. ``mask-image`` makes the actual
     pixels transparent, not just hidden behind a CSS overlay — the
     toggle button below remains fully opaque because it lives
     OUTSIDE this body. WebKit prefix kept for Safari < 15.4. */
  -webkit-mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
  mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
}
.nb-pill-diff-toggle {
  /* ``flex: 0 0 auto`` keeps the toggle row at its natural height
     and OUTSIDE the body's mask, so the user can always click it
     even when the body fades out underneath. */
  flex: 0 0 auto;
  display: block;
  width: 100%;
  border: 0;
  border-top: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.02);
  color: var(--fg-muted);
  font-size: 11.5px;
  font-family: inherit;
  padding: 6px 10px;
  cursor: pointer;
  text-align: center;
}
.nb-pill-diff-toggle:hover {
  background: rgba(0, 0, 0, 0.05);
  color: var(--fg);
}
.nb-pill-diff-meta {
  /* ``flex: 0 0 auto`` keeps the title bar fully visible no matter
     how tall the body grows. The meta carries the cell id + line
     counts (e.g. "nb-1 +59") and the user must always see it. */
  flex: 0 0 auto;
  display: flex;
  gap: 10px;
  padding: 4px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 11px;
  color: var(--fg-faint);
  background: rgba(0, 0, 0, 0.02);
}
.nb-pill-diff-cell { font-weight: 600; color: var(--fg-muted); }
.nb-pill-diff-added   { color: #16a34a; font-weight: 600; }
.nb-pill-diff-removed { color: var(--err); font-weight: 600; }

.diff-list { padding: 4px 0; }
.diff-empty {
  padding: 6px 10px;
  font-size: 11px;
  color: var(--fg-faint);
  font-style: italic;
}
.diff-hunk-wrap + .diff-hunk-wrap {
  margin-top: 0;
}
.diff-hunk-sep {
  padding: 2px 10px;
  color: var(--fg-faint);
  font-size: 11px;
  user-select: none;
  text-align: center;
}
.diff-line {
  display: grid;
  grid-template-columns: 36px 36px 14px 1fr;
  align-items: stretch;
  padding: 0 6px 0 0;
  white-space: pre;
  line-height: 1.45;
}
.diff-gutter {
  text-align: right;
  padding-right: 6px;
  color: var(--fg-faint);
  user-select: none;
  font-size: 11px;
}
.diff-sigil {
  text-align: center;
  user-select: none;
}
.diff-line-text {
  white-space: pre-wrap;
  word-break: break-all;
}
.diff-line.is-add {
  background: rgba(22, 163, 74, 0.12);
}
.diff-line.is-add .diff-sigil,
.diff-line.is-add .diff-line-text {
  color: #166534;
}
.diff-line.is-del {
  background: rgba(220, 38, 38, 0.10);
}
.diff-line.is-del .diff-sigil,
.diff-line.is-del .diff-line-text {
  color: #991b1b;
}
.diff-line.is-ctx { color: var(--fg-muted); }

@media (max-width: 1280px) {
  .app-layout.has-notebook {
    grid-template-columns: 196px minmax(0, 1fr);
  }
  .notebook-panel {
    position: absolute;
    top: 8px;
    right: 8px;
    bottom: 8px;
    width: min(58vw, 760px);
    border: 1px solid var(--border);
    border-radius: 18px;
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.14);
  }
  .notebook-head-controls {
    flex-wrap: wrap;
  }
}

@media (max-width: 900px) {
  .top-bar {
    padding: 10px 12px;
  }
  .top-bar-right a {
    display: none;
  }
  .app-layout,
  .app-layout.has-notebook {
    grid-template-columns: minmax(0, 1fr);
  }
  .sidebar {
    display: none;
  }
  .center #feed {
    padding: 20px 14px 18px 14px;
  }
  .composer {
    padding: 10px 12px 14px 12px;
  }
  .notebook-panel {
    position: fixed;
    inset: 56px 0 0 0;
    width: auto;
    border: none;
    border-top: 1px solid var(--border);
    border-radius: 0;
    box-shadow: none;
    z-index: 20;
  }
}

/* ---- run_python tool card (notebook-cell-ish layout) ---- */

.code-python {
  background: #0f1115;
  color: #e2e8f0;
  border-radius: 6px;
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
}
.py-output {
  display: block;
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: inherit;
  white-space: normal;
}
.py-output > .py-out {
  display: block;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 12.5px;
  padding: 8px 10px;
  margin: 0 0 6px 0;
  border-radius: 6px;
  border-left: 3px solid var(--border);
}
.py-output > .py-out.stdout  { background: #f6f8fa; color: var(--fg); border-left-color: #94a3b8; }
.py-output > .py-out.stderr  { background: #fff7ed; color: #9a3412; border-left-color: #f59e0b; }
.py-output > .py-out.result  { background: #ecfdf5; color: #065f46; border-left-color: var(--ok); }
.py-output > .py-out.error   { background: var(--err-bg); color: var(--err); border-left-color: var(--err); }
.py-output > .py-out.timeout { background: var(--warn-bg); color: var(--warn); border-left-color: var(--warn); }
.py-output > .py-out.muted   { background: transparent; color: var(--fg-faint); font-style: italic; border-left-color: transparent; }
.py-images {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 4px;
}
.py-images img {
  max-width: 100%;
  max-height: 360px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
}

/* ---- empty-state hook: JS populates data-empty-text from data-empty-i18n ---- */


/* =================================================================
 * Resource bar — collapsed pill row above the chat composer.
 * Five pills (Skills / Datasets / CLI / Libraries / KnowHow), each
 * shows ``Label count``. Click → flyout pops UP above the bar with
 * the per-axis content. Skills flyout has Auto/All toggle in the
 * header; the others are read-only browsers.
 * ================================================================= */

.resource-bar {
  position: relative;
  padding: 6px 14px 0;
}

.resource-bar-pills {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: flex-start;
}

.resource-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border: 1px solid #d1d5da;
  border-radius: 14px;
  background: #fff;
  color: #1f2328;
  font-size: 11px;
  line-height: 1.4;
  cursor: pointer;
  user-select: none;
  transition: border-color 120ms ease, background 120ms ease;
}
.resource-pill:hover {
  border-color: #4477aa;
}
.resource-pill.is-open {
  border-color: #4477aa;
  background: #ebf3fb;
}
.resource-pill-label {
  font-weight: 500;
  color: #1f2328;
}
.resource-pill-count {
  color: #8a929b;             /* muted — secondary information */
  font-variant-numeric: tabular-nums;
  font-size: 10.5px;
}
.resource-pill.is-open .resource-pill-label { color: #2a5fb4; }
.resource-pill.is-open .resource-pill-count { color: #6691c5; }

/* Flyout — pops up above the bar -------------------------------- */

.resource-flyout {
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: calc(100% + 4px);   /* sit ABOVE the pills row */
  background: #fff;
  border: 1px solid #d1d5da;
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
  display: flex;
  flex-direction: column;
  max-height: 320px;
  z-index: 25;
  animation: resource-flyout-pop 140ms ease-out;
}
@keyframes resource-flyout-pop {
  from { transform: translateY(6px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}

.resource-flyout-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-bottom: 1px solid #eef0f2;
  background: #fafbfc;
}

.resource-flyout-title {
  font-weight: 600;
  font-size: 12px;
  color: #1f2328;
  flex: 0 0 auto;
}

.resource-flyout-spacer { flex: 1 1 auto; }

.resource-flyout-modes {
  margin-left: auto;
  display: inline-flex;
  gap: 4px;
}

.resource-flyout-modes .mode-btn {
  padding: 2px 9px;
  border: 1px solid #d1d5da;
  border-radius: 12px;
  background: #fff;
  color: #555;
  font-size: 10.5px;
  cursor: pointer;
}
.resource-flyout-modes .mode-btn:hover { border-color: #4477aa; color: #4477aa; }
.resource-flyout-modes .mode-btn.is-active {
  background: #4477aa;
  border-color: #4477aa;
  color: #fff;
}

.resource-flyout-close {
  margin-left: 4px;
  border: 0;
  background: transparent;
  font-size: 16px;
  line-height: 1;
  color: #6e7681;
  cursor: pointer;
  padding: 0 4px;
}
.resource-flyout-close:hover { color: #1f2328; }

.resource-flyout-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 4px 0;
}

.resource-flyout-empty {
  padding: 12px;
  font-size: 11px;
  color: #6e7681;
  font-style: italic;
}

/* Resource list rows --------------------------------------------- */

.resource-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.resource-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 5px 10px;
  border-bottom: 1px solid #f3f4f6;
  font-size: 11px;
}
.resource-row:last-child { border-bottom: none; }
.resource-row:hover { background: #f6f8fa; }

.resource-row-skill {
  /* Skills row uses checkbox + main button layout instead of grid */
  display: flex;
  align-items: center;
  gap: 0;
  padding: 0;
}
.resource-row-skill.is-checked { background: #ebf3fb; }
.resource-row-skill.is-candidate { background: #f0fbf5; }
.resource-row-skill.is-candidate.is-checked { background: #d8efe1; }

.resource-row-checkbox {
  flex: 0 0 auto;
  padding: 5px 8px 5px 10px;
  background: transparent;
  border: 0;
  font-family: monospace;
  font-size: 12px;
  color: #4477aa;
  cursor: pointer;
}

.resource-row-main {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 8px;
  align-items: center;
  padding: 5px 10px 5px 4px;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: inherit;
}
.resource-row-skill:not(.is-checked) .resource-row-main { padding-left: 10px; }

.resource-row-slug {
  font-weight: 500;
  color: #1f2328;
  white-space: nowrap;
}
.resource-row-desc {
  color: #6e7681;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.resource-row-meta {
  color: #8a929b;
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.resource-row.is-installed .resource-row-meta { color: #1f6f43; }
.resource-row.is-missing   .resource-row-meta { color: #b13a3a; }

.resource-domain-filter { width: 100%; margin: 4px 0 8px; }
.resource-domain-header { font-weight: 600; opacity: 0.7; font-size: 0.85em; margin: 8px 0 2px; }
.resource-domain-group:first-of-type .resource-domain-header { margin-top: 0; }

.resource-row-candidate-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 4px;
  border-radius: 50%;
  background: #2da44e;
  vertical-align: middle;
}


/* =================================================================
 * Resources panel — sidebar 5-tab UI (Week 4 Day 4)
 * ================================================================= */

.resources-panel {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px;
  border-top: 1px solid #e5e7ea;
}

.sidebar-section-title {
  margin: 0 0 4px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #6e7681;
}

.resources-tabs {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 3px;
}

.resources-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 4px 2px;
  border: 1px solid #e5e7ea;
  border-radius: 5px;
  background: #fff;
  cursor: pointer;
  font-size: 10px;
  color: #555;
  transition: all 100ms ease;
}
.resources-tab:hover {
  border-color: #4477aa;
  color: #4477aa;
}
.resources-tab.is-active {
  background: #4477aa;
  border-color: #4477aa;
  color: #fff;
}
.resources-tab-label {
  font-weight: 500;
}
.resources-tab-badge {
  font-size: 9px;
  opacity: 0.85;
  font-variant-numeric: tabular-nums;
}

.resources-tab-body {
  margin-top: 4px;
  max-height: 280px;
  overflow-y: auto;
}

.resources-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.resources-item {
  padding: 6px 4px;
  border-bottom: 1px solid #f3f4f6;
  font-size: 11px;
  color: #1f2328;
}
.resources-item:last-child {
  border-bottom: none;
}
.resources-item.is-installed {
  background: #f6fbf8;
}

.resources-item-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 6px;
}

.resources-item-slug {
  font-weight: 600;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 11px;
}

.resources-item-meta {
  font-size: 9px;
  color: #6e7681;
  text-transform: lowercase;
  font-variant-numeric: tabular-nums;
}
.resources-item-meta.is-ok      { color: #2da44e; }
.resources-item-meta.is-missing { color: #b13a3a; }

.resources-item-desc {
  margin-top: 2px;
  color: #555;
  font-size: 10px;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.resources-item-tags {
  margin-top: 3px;
  display: flex;
  gap: 3px;
  flex-wrap: wrap;
}

.resources-tag {
  display: inline-block;
  padding: 1px 5px;
  border-radius: 8px;
  background: #ebf3fb;
  color: #4477aa;
  font-size: 9px;
}

.resources-loading,
.resources-empty,
.resources-error {
  padding: 10px;
  font-size: 11px;
  color: #6e7681;
  font-style: italic;
}
.resources-error {
  color: #b13a3a;
  font-style: normal;
}

/* =================================================================
 * Job progress panel (Week 5 Day 4)
 * ================================================================= */

.job-progress-panel {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px;
  border-top: 1px solid #e5e7ea;
}

.job-progress-empty {
  font-size: 11px;
  color: #6e7681;
  font-style: italic;
  padding: 6px 4px;
}

.job-progress-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 180px;
  overflow-y: auto;
}

.job-progress-item {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 5px 4px;
  border-bottom: 1px solid #f3f4f6;
  font-size: 11px;
}
.job-progress-item:last-child {
  border-bottom: none;
}
.job-progress-item.is-watched {
  background: #eef4ff;
}

.job-progress-item-main {
  flex: 1;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-align: left;
  color: inherit;
  font: inherit;
}

.job-progress-item-title {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.job-progress-item-cancel {
  background: transparent;
  border: 1px solid #ddd;
  border-radius: 3px;
  font-size: 11px;
  line-height: 1;
  padding: 1px 5px;
  cursor: pointer;
  color: #999;
}
.job-progress-item-cancel:hover {
  color: #b13a3a;
  border-color: #b13a3a;
}

.job-status {
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 1px 5px;
  border-radius: 3px;
  background: #eef0f2;
  color: #555;
}
.job-status-pending { background: #f0ecda; color: #88732e; }
.job-status-running { background: #dbe9ff; color: #2a5fb4; }
.job-status-completed { background: #d8efe1; color: #1f6f43; }
.job-status-failed { background: #f6d8d8; color: #a93535; }
.job-status-cancelled { background: #e9e9e9; color: #6c6c6c; }

.job-progress-detail {
  margin-top: 4px;
  padding: 8px;
  border: 1px solid #e5e7ea;
  border-radius: 6px;
  background: #fafbfc;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.job-progress-detail-title {
  margin: 0;
  font-size: 12px;
  font-weight: 600;
}

.job-progress-detail-meta {
  display: flex;
  gap: 8px;
  align-items: center;
  font-size: 10px;
  color: #6e7681;
}

.job-elapsed {
  font-variant-numeric: tabular-nums;
}

.job-progress-error {
  font-size: 11px;
  color: #b13a3a;
}

.job-trials-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.job-trial {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  gap: 4px;
  padding: 4px 6px;
  border-radius: 4px;
  font-size: 11px;
  background: #fff;
  border: 1px solid #eef0f2;
}
.job-trial.trial-status-running { border-color: #b6d2ff; background: #f4f8ff; }
.job-trial.trial-status-completed { border-color: #cae6d4; }
.job-trial.trial-status-failed { border-color: #f0c4c4; background: #fdf6f6; }

.job-trial-marker {
  font-size: 11px;
  text-align: center;
  color: #4477aa;
}
.job-trial.trial-status-failed .job-trial-marker { color: #b13a3a; }
.job-trial.trial-status-completed .job-trial-marker { color: #1f6f43; }

.job-trial-instruction {
  font-weight: 500;
  color: #1f2328;
}
.job-trial-summary {
  margin-top: 2px;
  color: #555;
}
.job-trial-error {
  margin-top: 2px;
  color: #b13a3a;
}
.job-trial-elapsed {
  font-size: 10px;
  color: #6e7681;
  font-variant-numeric: tabular-nums;
}
.job-trial-artifacts {
  margin: 2px 0 0;
  padding-left: 14px;
  font-size: 10px;
  color: #4477aa;
}

/* =================================================================
 * Failed-attempt strip — demote-and-mute architectural rule.
 * Used by both NotebookPill and ToolCard for any tool call whose
 * output reported a failure. Keeps the attempt visible in the
 * chronological trace, but styled small / grey / collapsible so it
 * doesn't clutter or alarm. Click expands the captured error
 * payload for power-user inspection.
 * ================================================================= */

.failed-attempt {
  margin: 2px 0;
  font-size: 11px;
  color: #6e7681;
}

.failed-attempt-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  padding: 2px 8px;
  background: #f6f8fa;
  border: 1px solid #e5e7ea;
  border-radius: 4px;
  cursor: pointer;
  color: inherit;
  font: inherit;
  text-align: left;
}
.failed-attempt-row:hover {
  background: #eef0f2;
  border-color: #d1d5da;
}

.failed-attempt-icon {
  font-size: 11px;
  color: #8a929b;            /* neutral grey, NOT red */
  font-family: monospace;
}

.failed-attempt-label {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10.5px;
  color: #555;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 30em;
}

.failed-attempt-meta {
  color: #8a929b;
  font-size: 10px;
}

.failed-attempt-toggle {
  margin-left: auto;
  color: #8a929b;
  font-size: 10px;
}

.failed-attempt-detail {
  margin: 4px 0 0;
  padding: 8px 10px;
  background: #fafbfc;
  border: 1px solid #eef0f2;
  border-radius: 4px;
  font-size: 12px;
  line-height: 1.5;
  color: #555;
  word-break: break-word;
}

/* ===== Credentials card (M2 of dataset-capability-roadmap) =============
 * Inline API-key prompt rendered in the chat timeline. Inherits the
 * .approval-card frame so cardinal layout / padding / spacing match
 * approvals, then adds form-specific styling. */
.credentials-card .approval-header .approval-warn {
  /* Override the warn ⚠ from approval cards — credentials use a key 🔑. */
  filter: hue-rotate(220deg);
}
.credentials-field {
  margin: 12px 0;
}
.credentials-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--fg, #222);
  margin-bottom: 4px;
}
.credentials-input {
  display: block;
  width: 100%;
  padding: 8px 10px;
  font-family: var(--mono-font, "SFMono-Regular", Consolas, monospace);
  font-size: 13px;
  border: 1px solid var(--border, #d0d0d0);
  border-radius: 6px;
  background: var(--bg-input, #fff);
  color: var(--fg, #222);
  transition: border-color 100ms ease;
}
.credentials-input:focus {
  outline: none;
  border-color: var(--accent, #2563eb);
  box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.18);
}
.credentials-input:disabled {
  opacity: 0.6;
  background: var(--bg-faint, #f5f5f5);
}
.credentials-hint {
  margin-top: 4px;
  font-size: 12px;
  color: var(--fg-faint, #6b7280);
  line-height: 1.5;
}

/* ===== License-gate card (M3) =========================================
 * Inherits the .approval-card frame; tweaks the icon + adds chip + link
 * styling for the terms URL. */
.license-gate-card .approval-header .approval-warn {
  filter: hue-rotate(140deg) saturate(0.6); /* greenish — informational */
}
.license-chip {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 10px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  margin-left: auto;
}
.license-chip-academic_only {
  background: #fef3c7;  /* amber-100 */
  color: #92400e;       /* amber-800 */
}
.license-chip-requires_license {
  background: #fee2e2;  /* red-100 */
  color: #991b1b;       /* red-800 */
}
.license-chip-open {
  background: #d1fae5;
  color: #065f46;
}
.license-reason {
  margin: 8px 0;
  font-size: 13px;
  color: var(--fg, #222);
  line-height: 1.6;
}
.license-notice {
  margin: 6px 0;
  padding: 8px 10px;
  font-size: 12px;
  color: var(--fg-faint, #4b5563);
  background: var(--bg-faint, #f9fafb);
  border-left: 3px solid var(--border, #d1d5db);
  border-radius: 0 4px 4px 0;
}
.license-terms-link {
  margin: 10px 0;
  font-size: 13px;
}
.license-terms-link a {
  color: var(--accent, #2563eb);
  text-decoration: none;
  font-weight: 500;
}
.license-terms-link a:hover {
  text-decoration: underline;
}
.license-fine-print {
  margin: 12px 0 4px;
  font-size: 11px;
  color: var(--fg-faint, #6b7280);
  font-style: italic;
  line-height: 1.5;
}

/* ===== Credentials "Remember on this device" toggle ==================== */
.credentials-remember {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin: 12px 0;
  padding: 10px;
  background: var(--bg-faint, #f9fafb);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  cursor: pointer;
}
.credentials-remember input[type="checkbox"] {
  margin-top: 3px;
  cursor: pointer;
}
.credentials-remember-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.credentials-remember-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--fg, #222);
}
.credentials-remember-hint {
  font-size: 11px;
  color: var(--fg-faint, #6b7280);
  line-height: 1.5;
}

/* ───────────────────────── Skill Store ───────────────────────── */
/* Both levels are their own scroll container (the #root is 100vh/overflow
   hidden). The max()-based inline padding centers the content to a reading
   width while keeping the scrollbar at the viewport edge. */
.skill-store {
  height: calc(100vh - var(--topbar-height, 48px));
  overflow-y: auto; overflow-x: hidden;
  padding: 0 max(28px, calc((100% - 1240px) / 2)) 88px;
}
.skill-store__head {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--bg); padding: 20px 0 14px; margin-bottom: 18px;
  border-bottom: 1px solid var(--border);
}
.skill-store__head h1 { font-size: 17px; font-weight: 650; letter-spacing: .12em; margin: 0; color: var(--fg); }
.skill-store__search { flex: 1; min-width: 240px; padding: 9px 13px; border: 1px solid var(--border);
  border-radius: 10px; background: var(--card-bg); color: var(--fg); font-size: 14px; outline: none; }
.skill-store__search:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(47,111,235,.12); }
.skill-store__facet { padding: 9px 11px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--card-bg); color: var(--fg); font-size: 14px; cursor: pointer; }
.skill-store__status { padding: 28px 4px; color: var(--fg-muted); }
.skill-store__status--error { color: var(--err); }

.skill-store__section { margin-bottom: 30px; }
.skill-store__section-head { font-size: 13px; font-weight: 650; color: var(--fg); margin: 0 0 14px;
  letter-spacing: .02em; display: flex; align-items: baseline; gap: 8px; }
.skill-store__section-head span { color: var(--fg-faint); font-weight: 400; }
.skill-store__grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.skill-store__more { margin-top: 14px; padding: 7px 16px; border: 1px solid var(--border);
  border-radius: 9px; background: var(--card-bg); color: var(--accent); cursor: pointer; font-size: 13px; font-weight: 500; }
.skill-store__more:hover { background: var(--card-hover); border-color: var(--border-strong); }

.skill-card { border: 1px solid var(--border); border-radius: 14px; background: var(--card-bg);
  padding: 16px; display: flex; flex-direction: column; gap: 9px; min-height: 132px;
  transition: box-shadow .16s, border-color .16s, transform .16s; }
.skill-card:hover { border-color: var(--border-strong); box-shadow: 0 6px 18px rgba(15,23,42,.08); transform: translateY(-1px); }
.skill-card__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.skill-card__name { background: none; border: none; padding: 0; margin: 0; cursor: pointer; text-align: left;
  font-size: 15px; font-weight: 650; color: var(--fg); line-height: 1.3; letter-spacing: -.01em; }
.skill-card__name:hover { color: var(--accent); }
.skill-card__desc { margin: 0; color: var(--fg-muted); font-size: 13px; line-height: 1.5; cursor: pointer;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
/* Some upstream skills genuinely ship no description — collapse the gap. */
.skill-card__desc:empty { display: none; }
.skill-card__meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-top: auto; padding-top: 4px; }
.skill-card__cat { font-size: 11px; color: var(--fg-muted); background: var(--card-hover);
  border-radius: 6px; padding: 2px 8px; letter-spacing: .01em; }
.skill-card__src { font-size: 11px; color: var(--fg-faint); margin-left: auto; }
.badge { font-size: 10px; padding: 1.5px 8px; border-radius: 999px; border: 1px solid var(--border);
  color: var(--fg-muted); font-weight: 500; letter-spacing: .02em; }
.badge--verified { color: var(--ok); border-color: var(--plan-border); background: var(--plan-bg); }
.badge--runnable { color: var(--ok); border-color: var(--plan-border); background: var(--plan-bg); }
.badge--reference { color: var(--warn); border-color: var(--approval-border); background: var(--approval-bg); }

/* Pill toggle (app accent on, neutral off). */
.skill-card__toggle { position: relative; width: 38px; height: 22px; flex: 0 0 auto; border: none;
  border-radius: 999px; background: var(--border-strong); cursor: pointer; transition: background .15s; }
.skill-card__toggle::after { content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25); transition: transform .15s; }
.skill-card__toggle.is-on { background: var(--accent); }
.skill-card__toggle.is-on::after { transform: translateX(16px); }

/* Detail (level 2) */
.skill-detail {
  height: calc(100vh - var(--topbar-height, 48px));
  overflow-y: auto; overflow-x: hidden;
  padding: 22px max(28px, calc((100% - 920px) / 2)) 88px;
}
.skill-detail__back { background: none; border: none; color: var(--fg-muted); cursor: pointer;
  font-size: 13px; padding: 4px 0 14px; display: inline-flex; align-items: center; gap: 4px; }
.skill-detail__back:hover { color: var(--accent); }
.skill-detail__head { border-bottom: 1px solid var(--border); padding-bottom: 18px; margin-bottom: 18px; }
.skill-detail__title-line { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.skill-detail__title-line h1 { margin: 0; font-size: 26px; font-weight: 680; letter-spacing: -.02em; color: var(--fg); }
.skill-detail__desc { color: var(--fg-muted); font-size: 15px; line-height: 1.55; margin: 10px 0 12px; }
/* Segmented control */
.skill-detail__tabs { display: inline-flex; gap: 2px; margin-bottom: 18px;
  background: var(--card-hover); border: 1px solid var(--border); border-radius: 11px; padding: 3px; }
.skill-detail__tabs button { background: none; border: none; border-radius: 8px;
  padding: 7px 18px; cursor: pointer; color: var(--fg-muted); font-size: 13.5px; font-weight: 500; transition: background .14s, color .14s; }
.skill-detail__tabs button:hover { color: var(--fg); }
.skill-detail__tabs button.is-active { background: var(--card-bg); color: var(--fg); font-weight: 600;
  box-shadow: 0 1px 3px rgba(15,23,42,.10); }
/* Overview rendered inside a guidance card (mirrors Biomni's markdown card). */
.skill-detail__overview { border: 1px solid var(--border); border-radius: 14px; background: var(--card-bg);
  padding: 6px 26px 26px; }
.skill-detail__overview-label { font-size: 11px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--fg-faint); padding: 16px 0 4px; border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.skill-detail__overview .markdown-body { font-size: 14.5px; line-height: 1.62; }

.skill-files { display: flex; gap: 16px; align-items: stretch; min-height: 360px; }
.skill-file-tree { width: 250px; flex: 0 0 auto; border: 1px solid var(--border); border-radius: 12px;
  padding: 8px; overflow: auto; font-size: 13px; background: var(--card-bg); }
.skill-file-tree__row { display: block; width: 100%; text-align: left; background: none; border: none;
  padding: 5px 7px; cursor: pointer; color: var(--fg); border-radius: 7px; white-space: nowrap; font-size: 13px; }
.skill-file-tree__row:hover { background: var(--card-hover); }
.skill-file-tree__file.is-active { background: rgba(47,111,235,.10); color: var(--accent); font-weight: 600; }
.skill-file-tree__caret { display: inline-block; width: 14px; color: var(--fg-faint); }
.skill-file-preview { flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 12px;
  padding: 16px; overflow: auto; background: var(--card-bg); }
.skill-file-preview__status { color: var(--fg-muted); font-size: 13px; padding: 8px 2px; }
.skill-file-preview__status--error { color: var(--err); }
/* Fresh light code card (filename header + copy, atom-one-light tokens). */
.skill-code { border: 1px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--card-bg); }
.skill-code__head { display: flex; align-items: center; gap: 9px; padding: 8px 13px;
  background: #f6f8fa; border-bottom: 1px solid var(--border); }
.skill-code__name { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px; color: var(--fg); font-weight: 600; }
.skill-code__lang { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--fg-muted);
  background: var(--card-hover); border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px; }
.skill-code__copy { margin-left: auto; font-size: 11px; color: var(--accent); background: var(--card-bg);
  border: 1px solid var(--border); border-radius: 6px; padding: 3px 11px; cursor: pointer; font-weight: 500; }
.skill-code__copy:hover { background: var(--card-hover); border-color: var(--border-strong); }
.skill-code__body { margin: 0; padding: 14px 16px; overflow: auto; background: #fbfcfe;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; line-height: 1.62; }
/* Strong dark base so non-token text is crisp (not washed-out grey). */
.skill-code__body code.hljs { background: transparent; padding: 0; color: #1f2328; }

/* Overview markdown code: light pre + atom-one-light tokens on a dark base. */
.skill-detail__overview .markdown-body pre { background: #fbfcfe; }
.skill-detail__overview .markdown-body pre code,
.skill-detail__overview .markdown-body .hljs { background: transparent; color: #1f2328; }

/* Universal tool Input/Output cards (ToolIO.tsx). */
.tool-io { margin-top: 6px; }
.tool-io-toggle {
  background: none; border: none; cursor: pointer; padding: 2px 0;
  font: inherit; color: var(--muted, #888); opacity: 0.8;
}
.tool-io-card {
  border: 1px solid var(--border, #2a2a2a); border-radius: 8px;
  margin: 6px 0; overflow: hidden;
}
.tool-io-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 8px; font-weight: 600; font-size: 0.8rem;
  background: var(--panel, rgba(255,255,255,0.03));
}
.tool-io-copy {
  background: none; border: none; cursor: pointer; font-size: 0.9rem;
  color: var(--muted, #888);
}
.tool-io-body.code-block {
  margin: 0; max-height: 360px; overflow: auto; border-radius: 0;
}
.tool-io-empty { color: var(--muted, #888); }
.card.is-code-agent-step { margin-left: 16px; border-left: 2px solid var(--border, #2a2a2a); }

.bg-task-pill { display: flex; align-items: center; gap: 8px; padding: 4px 10px;
  border: 1px solid var(--border, #2a2a2a); border-radius: 999px; margin: 6px 0; font-size: 0.85rem; }
.bg-task-pill.is-running .bg-task-icon { animation: bg-task-spin 1.2s linear infinite; display: inline-block; }
.bg-task-pill.is-failed, .bg-task-pill.is-killed { opacity: 0.8; }
.bg-task-summary { color: var(--muted, #888); }
.system-divider { text-align: center; color: var(--muted, #888); font-size: 0.8rem;
  margin: 10px 0; border-top: 1px dashed var(--border, #2a2a2a); padding-top: 6px; }
@keyframes bg-task-spin { to { transform: rotate(360deg); } }

/* ===== ask_user_question card ==========================================
 * Inherits the .approval-card frame (border, background, padding, pulse).
 * Only .askq-* selectors are defined here — shared .approval-* rules are
 * not touched. */

/* Mute the ❓ icon to the same amber tone the other approval icons use. */
.askq-card .approval-warn {
  filter: hue-rotate(200deg) saturate(0.8);
}

/* ── Stepper (multi-question header) ── */
.askq-stepper {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 10px;
}
.askq-stepper-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 500;
  border: 1px solid var(--border, #e5e7eb);
  background: var(--card-bg, #fff);
  color: var(--fg-muted, #6b6b68);
  transition: background 120ms, color 120ms, border-color 120ms;
}
.askq-stepper-chip.is-active {
  background: var(--accent, #2f6feb);
  color: #fff;
  border-color: var(--accent, #2f6feb);
  font-weight: 600;
}
.askq-stepper-chip.is-done {
  background: var(--plan-bg, #f3faf4);
  color: var(--ok, #1a7f37);
  border-color: var(--plan-border, #c9e5cf);
}

/* ── Question text ── */
.askq-question-text {
  margin: 0 0 10px;
  font-size: 13.5px;
  color: var(--fg, #1b1b1a);
  line-height: 1.55;
}

/* ── Option list (no-preview mode) ── */
.askq-options {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-bottom: 6px;
}

/* ── Option button (shared by both modes) ── */
.askq-option {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 7px;
  background: var(--card-bg, #fff);
  color: var(--fg, #1b1b1a);
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  transition: background 100ms, border-color 100ms;
}
.askq-option:hover:not(:disabled) {
  background: var(--card-hover, #f3f4f6);
  border-color: var(--border-strong, #d1d5db);
}
.askq-option.is-focused:not(:disabled) {
  border-color: var(--accent, #2f6feb);
  box-shadow: 0 0 0 2px rgba(47, 111, 235, 0.14);
}
.askq-option.is-selected {
  background: var(--accent-bg, #eff4ff);
  border-color: var(--accent, #2f6feb);
  color: var(--accent-fg, #1a3a80);
}
.askq-option.is-selected.is-focused {
  box-shadow: 0 0 0 2px rgba(47, 111, 235, 0.22);
}
.askq-option:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.askq-option-check {
  flex-shrink: 0;
  font-size: 13px;
  color: var(--accent, #2f6feb);
  line-height: 1;
}
.askq-option-label {
  font-weight: 500;
  flex-shrink: 0;
}
.askq-option-desc {
  font-size: 12px;
  color: var(--fg-muted, #6b6b68);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── "其它…" row ── */
.askq-other-row {
  margin-top: 6px;
}
/* Ghost variant used by askq-other-btn and askq-notes-btn. */
.btn.ghost {
  background: transparent;
  border-color: var(--border, #e5e7eb);
  color: var(--fg-muted, #6b6b68);
}
.btn.ghost:hover:not(:disabled) {
  background: var(--card-hover, #f3f4f6);
  color: var(--fg, #1b1b1a);
}
.askq-other-btn {
  font-size: 12.5px;
  padding: 4px 10px;
}
.askq-other-input {
  display: block;
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  background: var(--bg-input, #fff);
  color: var(--fg, #1b1b1a);
  transition: border-color 100ms;
}
.askq-other-input:focus {
  outline: none;
  border-color: var(--accent, #2f6feb);
  box-shadow: 0 0 0 2px rgba(47, 111, 235, 0.18);
}

/* ── Two-column preview layout ── */
.askq-preview-layout {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  min-height: 140px;
}
.askq-preview-options {
  flex: 0 0 auto;
  width: min(38%, 220px);
  display: flex;
  flex-direction: column;
  gap: 5px;
  /* options column may scroll if there are many options */
  max-height: 320px;
  overflow-y: auto;
}
.askq-preview-panel {
  flex: 1 1 0;
  min-width: 0;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 7px;
  padding: 10px 12px;
  background: var(--card-bg, #fff);
  overflow: auto;
  max-height: 320px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--fg, #1b1b1a);
}
.askq-preview-empty {
  color: var(--fg-faint, #9a9a97);
  font-style: italic;
  text-align: center;
  padding-top: 24px;
}
/* Narrow viewport: stack the columns vertically. */
@media (max-width: 520px) {
  .askq-preview-layout { flex-direction: column; }
  .askq-preview-options { width: 100%; max-height: 180px; }
  .askq-preview-panel  { max-height: 200px; }
}

/* ── Notes button + row (preview mode) ── */
.askq-notes-btn {
  margin-top: 4px;
  font-size: 12px;
  padding: 3px 9px;
}
.askq-notes-row {
  margin-top: 6px;
}
.askq-notes-input {
  display: block;
  width: 100%;
  padding: 6px 10px;
  font: inherit;
  font-size: 12.5px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  background: var(--bg-input, #fff);
  color: var(--fg, #1b1b1a);
  transition: border-color 100ms;
}
.askq-notes-input:focus {
  outline: none;
  border-color: var(--accent, #2f6feb);
  box-shadow: 0 0 0 2px rgba(47, 111, 235, 0.18);
}
.askq-notes-saved {
  margin-top: 5px;
  padding: 5px 8px;
  font-size: 12px;
  color: var(--fg-muted, #6b6b68);
  background: var(--plan-bg, #f3faf4);
  border: 1px solid var(--plan-border, #c9e5cf);
  border-radius: 5px;
  font-style: italic;
}

/* =====================================================================
 * SP1 four-region shell: [IconRail | Sidebar | Center | RightPanel].
 * ===================================================================== */
.app-shell {
  flex: 1 1 auto;
  min-height: 0;
  height: 100%;
  display: grid;
  grid-template-columns: 64px 220px minmax(0, 1fr) minmax(300px, 0.85fr);
  gap: 12px;
  padding: 10px 12px 12px 12px;
  background: #ffffff;
  overflow: hidden;
  transition: grid-template-columns 0.22s ease;
}
.app-shell.is-sidebar-collapsed {
  grid-template-columns: 64px 48px minmax(0, 1fr) minmax(300px, 0.85fr);
}
/* Full-page views (skills / datasets / my_data) cover center+right. */
.app-shell.is-fullpage {
  grid-template-columns: 64px 220px minmax(0, 1fr);
}
.app-shell.is-fullpage.is-sidebar-collapsed {
  grid-template-columns: 64px 48px minmax(0, 1fr);
}
.shell-fullpage { min-width: 0; overflow: auto; }

/* Icon rail */
.icon-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 10px 6px;
  background: #1f2937;
  border-radius: 14px;
  color: #e5e7eb;
}
.icon-rail .rail-brand { width: 26px; height: 26px; margin-bottom: 4px; }
.icon-rail .rail-group { display: flex; flex-direction: column; gap: 12px; align-items: center; }
.icon-rail .rail-divider { width: 60%; height: 1px; background: rgba(255,255,255,0.14); }
.icon-rail .rail-bottom { margin-top: auto; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.rail-btn {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  width: 48px; padding: 6px 0; border: 0; border-radius: 10px;
  background: transparent; color: inherit; cursor: pointer;
}
.rail-btn:hover { background: rgba(255,255,255,0.08); }
.rail-btn.is-active { background: #374151; }
.rail-btn .rail-glyph { font-size: 18px; line-height: 1; }
.rail-btn .rail-label { font-size: 9px; opacity: 0.85; }

/* Right panel: tab region over file tree */
.right-panel { display: grid; grid-template-rows: 1.2fr 1fr; gap: 12px; min-height: 0; }
.right-panel-top,
.right-panel-bottom {
  background: #fff; border: 1px solid var(--border-strong); border-radius: 14px;
  display: flex; flex-direction: column; min-height: 0; overflow: hidden;
}
.rail-tabs { display: flex; gap: 2px; padding: 6px 6px 0; border-bottom: 1px solid var(--border); }
.rail-tab {
  padding: 6px 12px; border: 0; background: transparent; cursor: pointer;
  border-radius: 8px 8px 0 0; color: var(--fg-faint); font: inherit;
}
.rail-tab.is-active { background: var(--bg-subtle, #f3f4f6); color: var(--fg); font-weight: 600; }
.rail-tab-body { flex: 1 1 auto; min-height: 0; overflow: auto; }
.rail-tab-empty { padding: 24px; color: var(--fg-faint); }

@media (max-width: 1100px) {
  .app-shell,
  .app-shell.is-fullpage { grid-template-columns: 64px 48px minmax(0, 1fr); }
  .app-shell .right-panel { display: none; }
}

/* SP2 — project grouping in the session sidebar. */
.project-section-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 10px 2px; margin-top: 6px;
}
.project-section-head .label {
  font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--fg-faint);
}
.project-group { list-style: none; }
.project-row {
  display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 6px;
}
.project-row:hover { background: var(--bg-subtle, #f3f4f6); }
.project-toggle {
  flex: 1 1 auto; text-align: left; border: 0; background: transparent;
  cursor: pointer; font: inherit; color: var(--fg); padding: 2px 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.project-count { font-size: 11px; color: var(--fg-faint); }
.session-sublist { list-style: none; margin: 0; padding-left: 14px; }

/* ===== Full-page Notebook view (M1) =================================== */
.notebook-view {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  height: 100%;
  min-height: 0;
  background: var(--bg);
}
.notebook-view--empty {
  display: flex;
  align-items: center;
  justify-content: center;
}
.notebook-view-emptyhint {
  color: var(--fg-faint);
  font-size: 14px;
  padding: 32px;
  text-align: center;
}
.notebook-files {
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
.notebook-files-head {
  padding: 10px 12px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg-faint);
  border-bottom: 1px solid var(--border);
}
.notebook-files-body { flex: 1; min-height: 0; overflow: auto; }
.notebook-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}
/* The cell list scrolls inside the main column. */
.notebook-main .notebook-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 16px 20px 48px;
}
.notebook-body-hint {
  padding: 24px;
  color: var(--fg-faint);
  font-size: 13px;
  text-align: center;
}

/* CodeMirror editor inside a notebook code cell (M2). */
.nb-codemirror {
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  background: var(--bg-elev, #fff);
}
.nb-codemirror .cm-editor {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
}
.nb-codemirror .cm-editor.cm-focused { outline: none; }
.nb-codemirror .cm-gutters {
  background: transparent;
  border-right: 1px solid var(--border);
  color: var(--fg-faint);
}
.nb-codemirror .cm-content { padding: 6px 0; }

/* Notebook toolbar row (M3): global ops + save/restart in one strip. */
.notebook-toolbar-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 6px 12px;
  border-bottom: 1px solid var(--border);
}
.notebook-toolbar { display: flex; align-items: center; gap: 6px; }
.notebook-toolbar-row .notebook-head { border: 0; padding: 0; margin-left: auto; }

/* Kernel status bar at the bottom of the full-page notebook (M4). */
.nb-status-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--fg-faint);
  background: var(--bg);
}
.nb-kernel-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--fg-faint); flex: none;
}
.nb-kernel-dot.is-idle { background: #2e9e5b; }
.nb-kernel-dot.is-busy { background: #d98a00; animation: nb-pulse 1s ease-in-out infinite; }
.nb-kernel-dot.is-down { background: #b3b3b3; }
@keyframes nb-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }
.nb-status-sep { opacity: 0.5; }

/* Cell selection + toolbar cell-ops (M5). */
.nb-cell.is-selected {
  box-shadow: inset 3px 0 0 var(--accent, #4a7cff);
}
.notebook-toolbar-sep {
  width: 1px; height: 18px; background: var(--border); margin: 0 4px;
}
.nb-celltype-select {
  font-size: 12px;
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--bg);
  color: var(--fg);
}
.notebook-view:focus { outline: none; }
.notebook-view:focus-visible { outline: none; }

/* SP3 — terminal tabs + xterm host. */
.terminal-tabs { display: flex; align-items: center; gap: 2px; padding: 4px 6px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.terminal-tab { display: flex; align-items: center; gap: 4px; padding: 4px 10px; border: 0; background: transparent; cursor: pointer; border-radius: 8px 8px 0 0; color: var(--fg-faint); font: inherit; }
.terminal-tab.is-active { background: #1e1e1e; color: #eee; }
.terminal-tab .tab-close { opacity: 0.6; border: 0; background: transparent; color: inherit; cursor: pointer; padding: 0 2px; }
.terminal-tab .tab-close:hover { opacity: 1; }
.terminal-pane { flex: 1 1 auto; min-height: 0; background: #1e1e1e; padding: 4px; }
.xterm-host { width: 100%; height: 100%; }

/* --- Connect-your-AI onboarding (P2) -------------------------------------- */
.connect-ai .connect-ai-or {
  text-align: center;
  color: var(--fg-faint);
  font-size: 12px;
  margin: 14px 0;
}
.connect-ai-go {
  margin-top: 8px;
  padding: 7px 18px;
  border: 0;
  border-radius: 6px;
  background: var(--accent, #4f7cff);
  color: #fff;
  font-weight: 600;
  cursor: pointer;
}
.connect-ai-go:disabled { opacity: 0.5; cursor: default; }
.codex-tos-warn {
  color: var(--warn, #d98a00);
  font-size: 12px;
  line-height: 1.45;
  margin: 0 0 10px;
}
