/* ------------------------------------------------------------------------- */
/* roy-plugin-task-show — visualization frontend styles                       */
/* ------------------------------------------------------------------------- */

:root {
  --bg: #0b1220;
  --panel: #111a2e;
  --panel-2: #182442;
  --text: #e6eefc;
  --muted: #94a3b8;
  --accent: #60a5fa;
  --good: #22c55e;
  --bad: #ef4444;
  --warn: #f59e0b;
  --code-bg: #0f172a;
  --border: #1e293b;
  --link: #38bdf8;
  /* v2.3.0: mermaid 占位倍数 (Task #2771).
     --mermaid-base-width / --mermaid-base-height 是 mermaid SVG
     默认 viewBox 尺寸。乘以 --mermaid-placeholder-multiplier 后
     得到 .mermaid / .mermaid-zoom-stage 的 min-*。
     直接改这三个变量就能调节占位大小，无需碰 rule。 */
  --mermaid-base-width: 1280px;
  --mermaid-base-height: 480px;
  --mermaid-placeholder-multiplier: 5;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Helvetica Neue", "PingFang SC", "Microsoft Yahei", Arial,
    sans-serif;
  font-size: 14px;
  line-height: 1.55;
}

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

code, pre {
  font-family: "JetBrains Mono", Menlo, Monaco, "Cascadia Code",
    "Source Code Pro", Consolas, monospace;
  font-size: 12.5px;
}

code {
  background: rgba(148, 163, 184, 0.18);
  padding: 1px 5px;
  border-radius: 4px;
}

pre {
  background: var(--code-bg);
  padding: 12px 14px;
  border-radius: 6px;
  border: 1px solid var(--border);
  overflow-x: auto;
}

.topbar {
  padding: 22px 28px;
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  border-bottom: 1px solid var(--border);
}
.topbar h1 {
  margin: 0;
  font-size: 22px;
  display: flex;
  gap: 12px;
  align-items: center;
}
.topbar .meta {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 12.5px;
}
.topbar .task-title {
  margin: 8px 0 0;
  font-size: 15px;
  color: #cbd5f5;
}
.topbar .back {
  display: inline-block;
  font-size: 12px;
  color: var(--muted);
  margin-bottom: 8px;
}

/* v2.0.3: progress bar in the topbar showing tool-call success rate. */
.topbar .progress-bar {
  position: relative;
  display: flex;
  width: 100%;
  max-width: 480px;
  height: 18px;
  margin: 10px 0 0;
  border-radius: 999px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.topbar .progress-bar-fill {
  height: 100%;
  transition: width 0.3s ease;
}
.topbar .progress-bar-fill--ok {
  background: linear-gradient(90deg, #22c55e, #16a34a);
}
.topbar .progress-bar-fill--fail {
  background: linear-gradient(90deg, #ef4444, #dc2626);
}
.topbar .progress-bar-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 600;
  color: #ffffff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  letter-spacing: 0.02em;
}

/* v2.0.3: file-link with truncated path + hover tooltip. */
.file-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 4px;
  background: rgba(59, 130, 246, 0.08);
  border: 1px solid rgba(59, 130, 246, 0.18);
  color: var(--link, #3b82f6);
  text-decoration: none;
  max-width: 280px;
  overflow: hidden;
  white-space: nowrap;
}
.file-link:hover {
  background: rgba(59, 130, 246, 0.14);
  text-decoration: underline;
}
.file-link-icon {
  flex-shrink: 0;
}
.file-link-path {
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* ---------- Connection status indicator ---------- */
.connection-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 8px 0 0 !important;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(148, 163, 184, 0.1);
  border: 1px solid var(--border);
  font-size: 12px !important;
  color: var(--muted) !important;
}
.conn-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.04);
  transition: background 0.2s, box-shadow 0.2s;
}
.conn-connected {
  background: var(--good);
  box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.25), 0 0 8px rgba(34, 197, 94, 0.4);
  animation: pulse 1.6s ease-in-out infinite;
}
.conn-fallback {
  background: var(--warn);
  box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.25);
}
.conn-disconnected {
  background: var(--bad);
  box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.25);
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

/* ---------- Status badges ---------- */
.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  background: rgba(148, 163, 184, 0.2);
  color: var(--text);
}
.badge-running {
  background: rgba(59, 130, 246, 0.25);
  color: #93c5fd;
}
.badge-completed {
  background: rgba(34, 197, 94, 0.2);
  color: #86efac;
}
.badge-failed {
  background: rgba(239, 68, 68, 0.25);
  color: #fca5a5;
}
.badge-cancelled {
  background: rgba(148, 163, 184, 0.25);
  color: #cbd5e1;
}
.badge-paused {
  background: rgba(245, 158, 11, 0.25);
  color: #fcd34d;
}
.badge-unknown {
  background: rgba(148, 163, 184, 0.18);
  color: #cbd5e1;
}

/* ---------- Panels ---------- */
.panel {
  margin: 22px 28px;
  padding: 18px 22px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
}
.panel h2 {
  margin: 0 0 12px;
  font-size: 16px;
  letter-spacing: 0.2px;
  color: #c7d2fe;
}

/* ---------- Tables ---------- */
table {
  width: 100%;
  border-collapse: collapse;
}
table thead th {
  text-align: left;
  font-size: 11.5px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
}
table tbody td {
  padding: 8px 10px;
  border-bottom: 1px solid rgba(148, 163, 184, 0.1);
  vertical-align: top;
}
table tbody tr:hover {
  background: rgba(96, 165, 250, 0.06);
}

table.stats td,
table.stats th {
  text-align: right;
}
table.stats td:first-child,
table.stats th:first-child {
  text-align: left;
}

table.toolcalls .args,
table.toolcalls .result {
  font-family: "JetBrains Mono", Menlo, monospace;
  font-size: 12px;
  max-width: 360px;
  word-break: break-all;
}

/* v0.8.0+ tool-row collapsed / expanded / highlight states. The row
   starts in `.collapsed` (input/output <details> closed) and gets
   toggled to `.expanded` on click. The `.highlight` class is added
   for 2s by the Mermaid `__toolClick` callback so the user sees a
   yellow flash pointing at the target row. */
table.toolcalls tr.tool-row {
  transition: background 0.3s ease-out;
}
table.toolcalls tr.tool-row.collapsed .tool-detail summary {
  color: var(--muted);
}
table.toolcalls tr.tool-row.expanded .tool-detail summary {
  color: var(--link);
}
table.toolcalls tr.tool-row.highlight {
  background: rgba(255, 200, 0, 0.30) !important;
  transition: background 0.3s ease-out;
}
table.toolcalls tr.tool-row.highlight:hover {
  background: rgba(255, 200, 0, 0.36) !important;
}

.status {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  border-radius: 4px;
  padding: 2px 8px;
}
.status-ok {
  background: rgba(34, 197, 94, 0.25);
  color: #86efac;
}
.status-fail {
  background: rgba(239, 68, 68, 0.25);
  color: #fca5a5;
}

.attach {
  margin-left: 4px;
  font-size: 11px;
  color: var(--link);
}

.mermaid {
  background: #f8fafc;
  border-radius: 6px;
  padding: 14px;
  color: #0f172a;
  overflow-x: auto;
  /* v2.3.0: placeholder 至少扩大到原来的 5 倍 (Task #2771).
     Base = mermaid SVG 默认 viewBox 高度 (≈480px) × multiplier (5) = 2400px。
     设为 min-height 而不是 height，避免 zoom in 后被裁剪。
     通过 :root 自定义属性调节，详见 --mermaid-* 变量定义。 */
  min-height: calc(
    var(--mermaid-base-height) * var(--mermaid-placeholder-multiplier)
  );
}

/* v0.6.11: error fallback when Mermaid rendering fails (or Mermaid library
   is unavailable). The error block replaces the bare raw `flowchart TD`
   source so the user always sees a clear, actionable state. */
.mermaid-error {
  background: #fef2f2;
  border: 1px solid #fca5a5;
  border-radius: 6px;
  padding: 12px 14px;
  color: #7f1d1d;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

.mermaid-error-header {
  font-weight: 600;
  margin-bottom: 6px;
}

.mermaid-error-msg {
  font-size: 13px;
  margin-bottom: 8px;
  word-break: break-word;
}

.mermaid-error-source {
  margin-top: 6px;
}

.mermaid-error-source summary {
  cursor: pointer;
  font-size: 12px;
  color: #991b1b;
}

.mermaid-error-source pre {
  background: #fff;
  border: 1px solid #fca5a5;
  border-radius: 4px;
  padding: 8px;
  font-size: 11px;
  color: #1f2937;
  max-height: 240px;
  overflow: auto;
  white-space: pre-wrap;
}

/* v2.0.8 (feat/mermaid-zoom): zoom toolbar + stage styles.
   The toolbar is a small inline control set the user clicks to
   scale the rendered diagram up or down. The .mermaid-zoom-stage
   wrapper is what carries the CSS transform — the underlying
   SVG keeps its own viewBox so the diagram does not reflow on
   every zoom step. */
.mermaid-zoom-toolbar {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 4px 0;
  padding: 2px 6px;
  background: var(--panel, #f8fafc);
  border: 1px solid var(--border, #cbd5e1);
  border-radius: 4px;
  font-size: 12px;
  user-select: none;
}
.mermaid-zoom-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 24px;
  padding: 0 6px;
  background: #fff;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: 3px;
  font-family: inherit;
  font-size: 12px;
  color: #0f172a;
  cursor: pointer;
  transition: background 0.1s ease-in-out;
}
.mermaid-zoom-btn:hover {
  background: #e2e8f0;
}
.mermaid-zoom-btn:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 1px;
}
.mermaid-zoom-btn:active {
  background: #cbd5e1;
}
.mermaid-zoom-stage {
  /* The wrapper that carries the transform. `transform-origin:
     top left` ensures the diagram grows down-right rather than
     re-centering (which would look jumpy). The transform itself
     is set inline by `MermaidRenderer.applyTransform` so the JS
     state is the single source of truth. */
  display: inline-block;
  transform-origin: top left;
  transition: transform 0.12s ease-out;
  /* Allow the zoomed content to overflow horizontally; the
     surrounding container will get its own scroll bar if needed. */
  max-width: 100%;
  /* v2.3.0: placeholder 至少扩大到原来的 5 倍 (Task #2771).
     min-width = 1280px × multiplier (5) = 6400px（zoom in 后能装下更大画布）
     min-height = 480px × multiplier (5) = 2400px
     用 min-* 而不是 *：避免实际内容 < 占位时被压缩。
     通过 :root 自定义属性调节，详见 --mermaid-* 变量定义。 */
  min-width: calc(
    var(--mermaid-base-width) * var(--mermaid-placeholder-multiplier)
  );
  min-height: calc(
    var(--mermaid-base-height) * var(--mermaid-placeholder-multiplier)
  );
  /* v2.4.1 (feat/task-show-v241-mermaid-pan): the stage is
     grabbable so the user can drag to pan around a zoomed-in
     diagram. `cursor: grab` is the canonical CSS hint for
     "this thing is draggable" — combined with `cursor:
     grabbing` set while a drag is in flight (see
     `.mermaid-zoom-stage.is-dragging`). `touch-action: none`
     disables the browser's default pan/zoom gestures on
     touchscreens so our pointer handlers stay in charge. */
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

/* v2.4.1 (feat/task-show-v241-mermaid-pan): the dragging
   variant is set on the stage while a pointer drag is in
   flight. `cursor: grabbing` is the conventional "currently
   dragging" cursor, and we drop the transition so the
   transform tracks the pointer 1:1 (otherwise the diagram
   lags behind the cursor). */
.mermaid-zoom-stage.is-dragging {
  cursor: grabbing;
  transition: none;
}

.hint {
  margin-top: 8px;
  font-size: 12px;
  color: var(--muted);
}

.empty {
  color: var(--muted);
  font-style: italic;
}

details summary {
  cursor: pointer;
  color: var(--link);
  font-size: 12.5px;
  margin-bottom: 8px;
}

.json {
  background: var(--code-bg);
  color: #e2e8f0;
}

@media (max-width: 800px) {
  table.toolcalls .args,
  table.toolcalls .result {
    max-width: 200px;
  }
  .panel,
  .topbar {
    padding: 14px 14px;
    margin: 14px 10px;
  }
}
/* ------------------------------------------------------------------------- */
/* Task lifecycle pipeline (v0.7.0+)                                         */
/* ------------------------------------------------------------------------- */

.panel-pipeline {
  /* keeps the existing panel rhythm */
}

.panel-lifecycle {
  /* The "Task lifecycle + tools" Mermaid section in the detail page. */
}

.lifecycle-hint {
  margin-left: 8px;
  font-size: 11.5px;
  color: var(--muted);
  font-weight: normal;
}

/* ------------------------------------------------------------------------- */
/* v2.0.9: collapse/expand toggle for pipeline + lifecycle sections         */
/* ------------------------------------------------------------------------- */

.collapse-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin-left: 8px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--panel-2);
  color: var(--text);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  vertical-align: middle;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.collapse-toggle:hover {
  background: var(--bg);
  border-color: var(--muted);
}

.collapse-toggle:focus-visible {
  outline: 2px solid var(--accent, #4a9);
  outline-offset: 1px;
}

.toggle-icon {
  display: inline-block;
  font-size: 10px;
  line-height: 1;
}

/* When a section has the `collapsed` class, hide its body container. */
[data-pipeline-root].collapsed [data-pipeline-body],
[data-lifecycle-root].collapsed [data-lifecycle-body] {
  display: none;
}

.op-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

.op-timeline::before {
  content: "";
  position: absolute;
  left: 11px;
  top: 6px;
  bottom: 6px;
  width: 2px;
  background: var(--border);
}

.op-node {
  position: relative;
  padding: 6px 0 14px 36px;
  list-style: none;
}

.op-bullet {
  position: absolute;
  left: 4px;
  top: 12px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--panel-2);
  border: 2px solid var(--border);
  box-shadow: 0 0 0 3px var(--bg);
}

.op-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.op-row1 {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  /* v0.9.8: ensure long titles wrap cleanly without pushing the
     timestamp off the right edge of the panel. `min-width: 0` lets
     flex children shrink below their content size so very long CJK
     titles wrap instead of overflowing the panel. */
  min-width: 0;
}

.op-row1 > * {
  min-width: 0;
}

.op-seq {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 2.5em;
}

.op-time {
  margin-left: auto;
  color: var(--muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.op-title {
  font-weight: 600;
  /* v0.9.8: avoid right-side truncation when a title is very long
     (CJK titles without spaces can otherwise overflow the flex row
     and get clipped by the panel edge). */
  overflow-wrap: anywhere;
  word-break: break-word;
  flex: 1 1 auto;
}

.op-badge {
  display: inline-block;
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.op-details {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  /* v0.9.8: clamp the legacy <details> wrapper so very long
     descriptions inside the fallback collapse do not bleed past the
     panel edge. The inner `.op-desc-block` / `.op-proc-block`
     continue to be the canonical always-visible layout. */
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
}

.op-details summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 12px;
}

.op-desc {
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 13px;
  line-height: 1.5;
  margin-top: 6px;
}

.op-proc {
  margin-top: 6px;
  font-size: 12px;
  color: var(--muted);
}

.op-proc-label {
  display: inline-block;
  background: var(--panel);
  border: 1px solid var(--border);
  padding: 0 6px;
  border-radius: 4px;
  margin-right: 4px;
}

/* v0.8.0+ always-visible description / process blocks (no <details>
   collapse unless the description is > 600 chars, in which case the
   legacy details fallback kicks in). The two blocks share a panel
   rhythm and use a left-border accent so the eye can separate them
   at a glance. */
.op-desc-block,
.op-proc-block {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px 8px;
  margin-top: 6px;
  font-size: 13px;
  line-height: 1.5;
}

.op-desc-block {
  border-left-color: var(--accent);
}

.op-proc-block {
  border-left-color: var(--muted);
}

.op-block-label {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
  text-transform: uppercase;
  margin-bottom: 4px;
}

.op-desc-block .op-desc {
  margin: 0;
}

.op-proc-block .op-proc-body {
  font-size: 12.5px;
  color: var(--text);
  white-space: pre-wrap;
  word-break: break-word;
}

.op-desc-empty,
.op-proc-empty {
  color: var(--muted);
  font-style: italic;
  font-size: 12px;
}

/* Status colors per canonical milestone type */
.op-status-create .op-bullet { background: #1e40af; border-color: #3b82f6; }
.op-status-create .op-badge { background: #1e3a8a; color: #dbeafe; border-color: #3b82f6; }

.op-status-progress .op-bullet { background: #0e7490; border-color: #06b6d4; }
.op-status-progress .op-badge { background: #164e63; color: #cffafe; border-color: #06b6d4; }

.op-status-milestone .op-bullet { background: #15803d; border-color: #22c55e; }
.op-status-milestone .op-badge { background: #14532d; color: #dcfce7; border-color: #22c55e; }

.op-status-problem .op-bullet { background: #b91c1c; border-color: #ef4444; }
.op-status-problem .op-badge { background: #7f1d1d; color: #fee2e2; border-color: #ef4444; }

.op-status-solution .op-bullet { background: #a16207; border-color: #f59e0b; }
.op-status-solution .op-badge { background: #78350f; color: #fef3c7; border-color: #f59e0b; }

.op-status-decision .op-bullet { background: #6d28d9; border-color: #8b5cf6; }
.op-status-decision .op-badge { background: #4c1d95; color: #ede9fe; border-color: #8b5cf6; }

.op-status-review .op-bullet { background: #0f766e; border-color: #14b8a6; }
.op-status-review .op-badge { background: #134e4a; color: #ccfbf1; border-color: #14b8a6; }

.op-status-completed .op-bullet { background: #166534; border-color: #22c55e; }
.op-status-completed .op-badge { background: #14532d; color: #dcfce7; border-color: #22c55e; }

.op-status-unknown .op-bullet { background: #475569; border-color: #94a3b8; }
.op-status-unknown .op-badge { background: #334155; color: #e2e8f0; border-color: #94a3b8; }

.pipeline-stale {
  display: inline-block;
  background: var(--warn);
  color: #1f2937;
  padding: 1px 8px;
  border-radius: 8px;
  font-size: 11px;
  margin-left: 8px;
}

/* ---------- v1.1.0+ SSE state badge (5 states) ---------- */
/* All `.pipeline-badge` variants share the same shape so the header
 * stays balanced; only the colour + animation differ. */
.pipeline-badge {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 8px;
  font-size: 11px;
  margin-left: 8px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.pipeline-stale {
  /* legacy alias — same orange as the v0.9.x pill */
  background: var(--warn);
  color: #1f2937;
}
.pipeline-connecting {
  background: #fde68a;
  color: #78350f;
  animation: badge-pulse 1.4s ease-in-out infinite;
}
.pipeline-live {
  background: #22c55e;
  color: #052e16;
  animation: badge-pulse 1.8s ease-in-out infinite;
}
.pipeline-reconnecting {
  background: #fde68a;
  color: #78350f;
  animation: badge-pulse 0.9s ease-in-out infinite;
}
.pipeline-error {
  background: var(--bad);
  color: #fff5f5;
}
@keyframes badge-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.pipeline-error {
  background: rgba(239, 68, 68, 0.08);
  border: 1px solid var(--bad);
  border-radius: 6px;
  padding: 10px 12px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.btn {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 12px;
  cursor: pointer;
  font-size: 13px;
}

.btn-retry:hover {
  border-color: var(--accent);
  color: var(--accent);
}

@media (max-width: 800px) {
  .op-row1 {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }
  .op-time {
    margin-left: 0;
  }
}

/* ------------------------------------------------------------------------- */
/* Tasks tree (v0.8.0+)                                                       */
/* ------------------------------------------------------------------------- */

.tree-controls {
  border-left: 3px solid var(--accent);
}
.tree-controls-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.tree-search {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 10px;
  flex: 1 1 240px;
  min-width: 220px;
  max-width: 380px;
}
.tree-search input {
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 13px;
  outline: none;
  flex: 1;
  min-width: 0;
}
.tree-search input::placeholder {
  color: var(--muted);
  opacity: 0.7;
}
.tree-filter-group {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 3px;
}
.tree-filter-btn {
  background: transparent;
  color: var(--muted);
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 4px 10px;
  cursor: pointer;
  font-size: 12px;
  line-height: 1.4;
  transition: all 120ms ease;
}
.tree-filter-btn:hover {
  color: var(--text);
  border-color: var(--border);
}
.tree-filter-btn.is-active {
  background: var(--accent);
  color: #0b1220;
  font-weight: 600;
  border-color: var(--accent);
}

.tree-summary {
  margin-top: 8px;
  font-size: 12.5px;
}
.tree-summary .stale-pill {
  display: inline-block;
  background: var(--warn);
  color: #1a1300;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 10.5px;
  margin-left: 4px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.tree-panel {
  border-left: 3px solid var(--good);
}
.tasks-tree {
  min-height: 80px;
  font-size: 13px;
}
.tree-list,
.tree-children {
  list-style: none;
  margin: 0;
  padding: 0;
}
.tree-children {
  margin-left: 0;
}

.tree-item {
  position: relative;
  margin: 2px 0;
}
.tree-item.tree-item-hidden {
  display: none;
}
.tree-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px 6px 8px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.015);
  border: 1px solid transparent;
  transition: background 120ms ease, border-color 120ms ease;
}
.tree-row:hover {
  background: rgba(96, 165, 250, 0.06);
  border-color: rgba(96, 165, 250, 0.25);
}
.tree-row-meta {
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--muted);
  font-style: italic;
}

.tree-toggler {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
  font-size: 11px;
  padding: 0;
  flex-shrink: 0;
  transition: background 120ms ease;
}
.tree-toggler:hover {
  background: rgba(96, 165, 250, 0.12);
}
.tree-toggler-leaf {
  border-color: transparent;
  color: var(--muted);
  cursor: default;
}

.tree-id {
  font-family: "JetBrains Mono", Menlo, Monaco, monospace;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent);
  flex-shrink: 0;
  min-width: 52px;
}
.tree-id:hover {
  text-decoration: underline;
}

.tree-type-badge {
  display: inline-block;
  font-size: 10.5px;
  font-family: "JetBrains Mono", Menlo, Monaco, monospace;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 5px;
  flex-shrink: 0;
  letter-spacing: 0.04em;
}

.tree-title {
  color: var(--text);
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tree-title:hover {
  text-decoration: underline;
  color: var(--accent);
}

.tree-tags {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 3px;
  flex-shrink: 0;
}
.tree-tag {
  display: inline-block;
  font-size: 10.5px;
  background: rgba(96, 165, 250, 0.12);
  color: #bfdbfe;
  border: 1px solid rgba(96, 165, 250, 0.3);
  border-radius: 999px;
  padding: 1px 7px;
  white-space: nowrap;
}

.tree-progress {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 10.5px;
  color: var(--muted);
  min-width: 80px;
  position: relative;
  overflow: hidden;
}
.tree-progress-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: rgba(34, 197, 94, 0.22);
  border-right: 1px solid rgba(34, 197, 94, 0.45);
}
.tree-progress-label {
  position: relative;
  z-index: 1;
  font-family: "JetBrains Mono", Menlo, Monaco, monospace;
  font-weight: 600;
  color: var(--text);
}

.tree-updated {
  font-size: 10.5px;
  color: var(--muted);
  font-family: "JetBrains Mono", Menlo, Monaco, monospace;
  flex-shrink: 0;
  white-space: nowrap;
}

/* Branch lines — drawn as left borders on each child item so the tree
   stays legible even with deep nesting. Each level offsets the lines by
   the same 22px we use for indentation. v0.8.3: bumped the line weight
   and contrast so the hierarchy is visible without squinting. */
.tree-children .tree-item {
  border-left: 2px solid rgba(148, 163, 184, 0.45);
  margin-left: 11px;
  padding-left: 0;
}
.tree-children .tree-item .tree-row {
  border-left: 2px solid transparent;
  margin-left: -2px;
  padding-left: 2px;
}

/* v0.8.3: render-time indent is computed as `depth * 22` in JS, but we
   also bump the depth-0 row padding so it lines up with the toggler
   size — without this the leaf dots look detached from their row. */
.tree-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px 6px 8px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.015);
  border: 1px solid transparent;
  transition: background 120ms ease, border-color 120ms ease;
}

/* v0.8.3: parent rows get a subtle accent so the user can immediately
   tell which rows have children — even before they click the chevron. */
.tree-item-branch > .tree-row {
  background: rgba(96, 165, 250, 0.04);
  border-color: rgba(96, 165, 250, 0.18);
}

/* v0.8.3: depth-based indentation for visual scanning. We tag each
   tree-row with its depth so the CSS can add a coloured left rail —
   darker for roots, fading toward the leaves. */
.tree-row[data-depth="0"] {
  box-shadow: inset 3px 0 0 rgba(96, 165, 250, 0.55);
}
.tree-row[data-depth="1"] {
  box-shadow: inset 3px 0 0 rgba(96, 165, 250, 0.30);
}
.tree-row[data-depth="2"] {
  box-shadow: inset 3px 0 0 rgba(96, 165, 250, 0.18);
}
.tree-row[data-depth="3"] {
  box-shadow: inset 3px 0 0 rgba(148, 163, 184, 0.30);
}
.tree-row[data-depth="4"],
.tree-row[data-depth="5"],
.tree-row[data-depth="6"] {
  box-shadow: inset 3px 0 0 rgba(148, 163, 184, 0.20);
}

/* v0.8.3: per-depth depth pill in the summary line. */
.tree-depth-breakdown {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-left: 4px;
}
.tree-depth-pill {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 11px;
  border: 1px solid rgba(148, 163, 184, 0.35);
  background: rgba(96, 165, 250, 0.08);
  color: #cbd5e1;
}
.tree-depth-pill[data-depth="0"] {
  background: rgba(96, 165, 250, 0.18);
  color: #bfdbfe;
  border-color: rgba(96, 165, 250, 0.55);
}
.tree-depth-pill[data-depth="1"] {
  background: rgba(96, 165, 250, 0.10);
  color: #cbd5e1;
  border-color: rgba(96, 165, 250, 0.30);
}
.tree-depth-pill[data-depth="2"] {
  background: rgba(96, 165, 250, 0.06);
  color: #cbd5e1;
  border-color: rgba(96, 165, 250, 0.22);
}

/* v0.8.3: legacy sections stay hidden. The id="legacy-sessions" hook
   lets a future debug toggle restore them without code changes. */
.tree-legacy-hidden,
.tree-legacy-hidden[hidden] {
  display: none !important;
}

/* v0.8.3: condensed legend so it doesn't dominate the page above the
   fold. Keeps the same content, tighter padding. */
.tree-legend {
  padding-top: 8px;
  padding-bottom: 8px;
  font-size: 12.5px;
}
.tree-legend h2 {
  font-size: 13px;
  margin-bottom: 4px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.tree-legend ul {
  margin: 0;
  padding-left: 18px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 2px 16px;
}
.tree-legend li {
  margin: 0;
}

/* Status badge color tweaks — keep the existing palette, just make the
   ones we use most in the tree (active / completed / todo) more vivid. */
.badge.badge-active {
  background: rgba(59, 130, 246, 0.18);
  color: #93c5fd;
  border: 1px solid rgba(59, 130, 246, 0.5);
}
.badge.badge-completed {
  background: rgba(34, 197, 94, 0.18);
  color: #86efac;
  border: 1px solid rgba(34, 197, 94, 0.5);
}
.badge.badge-todo {
  background: rgba(148, 163, 184, 0.18);
  color: #cbd5e1;
  border: 1px solid rgba(148, 163, 184, 0.4);
}
.badge.badge-paused {
  background: rgba(245, 158, 11, 0.18);
  color: #fcd34d;
  border: 1px solid rgba(245, 158, 11, 0.45);
}
.badge.badge-cancelled {
  background: rgba(239, 68, 68, 0.18);
  color: #fca5a5;
  border: 1px solid rgba(239, 68, 68, 0.45);
}
.badge.badge-priority-high {
  background: rgba(239, 68, 68, 0.18);
  color: #fca5a5;
  border: 1px solid rgba(239, 68, 68, 0.45);
}
.badge.badge-priority-medium {
  background: rgba(245, 158, 11, 0.18);
  color: #fcd34d;
  border: 1px solid rgba(245, 158, 11, 0.45);
}
.badge.badge-priority-low {
  background: rgba(148, 163, 184, 0.18);
  color: #cbd5e1;
  border: 1px solid rgba(148, 163, 184, 0.4);
}

/* ---------- Session forest metadata ---------- */
.session-forest > ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* v2.5.4 (Task #2826): when the session forest is empty (no tasks
 * yet recorded in this session), the empty-state hint inside the
 * <ul> needs a friendlier look than a default <li>. Tone down the
 * row rhythm and use the muted color so it reads as guidance, not
 * as data. */
.session-empty {
  list-style: none;
  margin: 8px 0;
  padding: 14px 16px;
  border: 1px dashed var(--border, #1e293b);
  border-radius: 8px;
  color: var(--muted, #94a3b8);
  font-size: 13px;
  font-style: italic;
  background: rgba(148, 163, 184, 0.05);
}
.session-row {
  min-width: 0;
  margin: 8px 0;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(24, 36, 66, 0.45);
}
/* v2.2.0+: tree indentation for session-row based on data-depth.
   Depth 0 = session root task; depth 1+ = children of ancestors
   pulled in via the session-scope ancestor walk. Each level gets
   a left border + padding so the hierarchy reads as a tree. */
.session-row[data-depth="0"] {
  border-left: 3px solid var(--accent, #6ec1ff);
  margin-left: 0;
}
.session-row[data-depth="1"] {
  border-left: 3px solid var(--accent-soft, #4a8ec0);
  margin-left: 1.5rem;
}
.session-row[data-depth="2"] {
  border-left: 3px solid var(--accent-softer, #2e6080);
  margin-left: 3rem;
}
.session-row[data-depth="3"] {
  border-left: 3px solid var(--border);
  margin-left: 4.5rem;
}
.session-row[data-depth="4"],
.session-row[data-depth="5"],
.session-row[data-depth="6"] {
  border-left: 3px solid var(--border);
  margin-left: 6rem;
}
/* Subtree container — nested ul that holds children of a session row */
.session-forest > ul > li > ul {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  border-left: 1px dashed var(--border);
  margin-left: 0.75rem;
  padding-left: 0.75rem;
}
/* v2.2.0+: nested children container — gives each subtree a dashed
   vertical rail so the hierarchy reads as a tree */
.session-children {
  list-style: none;
  margin: 8px 0 0 1.25rem;
  padding: 0 0 0 0.75rem;
  border-left: 1px dashed var(--border);
}
.session-children > .session-row {
  margin-top: 6px;
}
.session-row[data-leaf="1"] {
  outline: 2px solid var(--accent, #6ec1ff);
  outline-offset: -2px;
}
.session-row .session-title {
  display: inline-block;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.session-toggle {
  margin-left: 10px;
}
.session-details {
  margin-top: 8px;
}
.session-details dl {
  display: grid;
  grid-template-columns: minmax(10rem, 15rem) minmax(0, 1fr);
  gap: 6px 12px;
  margin: 10px 0 0;
}
.session-details dt {
  color: var(--muted);
  font-weight: 600;
  overflow-wrap: anywhere;
}
.session-details dd {
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
}
.session-details pre.metadata-json,
.session-details pre.metadata-text {
  max-height: 24rem;
  margin: 0;
  white-space: pre-wrap;
  overflow: auto;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.session-operations {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
}
@media (max-width: 700px) {
  .session-details dl {
    grid-template-columns: 1fr;
    gap: 2px;
  }
  .session-details dd {
    margin-bottom: 8px;
  }
}

/* ============================================================================
 * v2.0.0: Monaco Editor + File Tree + Diff + Mermaid jump
 *
 * Sections (search for the header to navigate):
 *   - .task-v2-layout        — sidebar + main grid
 *   - .file-tree-panel       — left sidebar
 *   - .file-tree             — collapsible nested list
 *   - .file-tree-node        — individual rows
 *   - .file-tree-chevron     — directory expand/collapse
 *   - .tool-call-detail      — right-hand detail panel
 *   - .monaco-editor         — Monaco container
 *   - .diff-body / .diff-line — LCS diff rendering
 *   - .v2-hint               — small inline hints
 * ========================================================================== */

/* ---------- v2.0.0 layout (sidebar + main) ---------- */
.task-v2-layout {
  display: grid;
  grid-template-columns: minmax(220px, 280px) 1fr;
  gap: 16px;
  margin: 0 auto;
  max-width: 1400px;
  padding: 0 16px;
}
.task-v2-layout > .task-v2-main {
  min-width: 0; /* allow grid item to shrink */
}
.file-tree-panel {
  position: sticky;
  top: 12px;
  align-self: start;
  max-height: calc(100vh - 24px);
  overflow: auto;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  padding: 12px 14px;
  background: var(--bg-panel, #fafafa);
}
.file-tree-panel h2 {
  font-size: 14px;
  margin: 0 0 6px;
  letter-spacing: 0.02em;
}
.file-tree-summary {
  font-size: 11px;
  color: var(--fg-muted, #6b7280);
  margin: 0 0 8px;
}
@media (max-width: 900px) {
  .task-v2-layout {
    grid-template-columns: 1fr;
  }
  .file-tree-panel {
    position: static;
    max-height: none;
  }
}

/* ---------- file tree sidebar ---------- */
.file-tree {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, monospace;
  font-size: 12px;
  line-height: 1.5;
}
.file-tree-node {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 1px 4px 1px calc(4px + var(--depth, 0) * 12px);
  border-radius: 3px;
  cursor: pointer;
  user-select: none;
}
.file-tree-node[data-collapsed="true"] {
  display: none;
}
.file-tree-node:hover {
  background: rgba(99, 102, 241, 0.08);
}
.file-tree-node.is-active {
  background: rgba(99, 102, 241, 0.18);
  outline: 1px solid rgba(99, 102, 241, 0.45);
  font-weight: 600;
}
.file-tree-node.is-affected .file-tree-name::after {
  content: " ●";
  color: rgba(220, 38, 38, 0.8);
  font-size: 10px;
}
.file-tree-chevron {
  display: inline-block;
  width: 12px;
  text-align: center;
  font-size: 9px;
  color: var(--fg-muted, #6b7280);
  flex: 0 0 12px;
}
.file-tree-spacer {
  display: inline-block;
  width: 12px;
  flex: 0 0 12px;
}
.file-tree-name {
  flex: 1 1 auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.file-tree-empty {
  list-style: none;
  color: var(--fg-muted, #6b7280);
  font-style: italic;
  padding: 4px;
}

/* ---------- tool-call detail panel ---------- */
.tool-call-detail-panel {
  border-left: 4px solid rgba(99, 102, 241, 0.55);
  padding-left: 14px;
  margin-top: 18px;
}
.tool-call-detail-panel .v2-hint {
  font-size: 12px;
  font-weight: 400;
  color: var(--fg-muted, #6b7280);
  margin-left: 8px;
}
.tool-call-detail {
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  padding: 10px 12px;
  margin-top: 8px;
  background: #ffffff;
}
.tool-call-header {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  margin-bottom: 6px;
}
.tool-call-header .tool-name code {
  background: rgba(99, 102, 241, 0.08);
  padding: 1px 6px;
  border-radius: 3px;
}
.tool-call-header .tool-path {
  color: var(--fg-muted, #6b7280);
  font-family: ui-monospace, Menlo, monospace;
  font-size: 11px;
  margin-left: auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
}
/* v2.0.3 Bug E: explicit title attr on tool-path so hover shows the
   full path even when truncated visually. */
.tool-call-header .tool-path[title] {
  cursor: help;
}
.tool-call-detail-empty {
  color: var(--fg-muted, #6b7280);
  font-style: italic;
  padding: 8px 0;
}

/* ---------- Monaco container ---------- */
.monaco-editor {
  width: 100%;
  height: 280px;
  border: 1px solid var(--border, #d1d5db);
  border-radius: 4px;
  margin: 6px 0 0;
  position: relative;
  background: #fafafa;
  overflow: hidden;
}
.monaco-editor .monaco-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--fg-muted, #6b7280);
  font-family: ui-monospace, Menlo, monospace;
  font-size: 12px;
}
.monaco-editor .monaco-error {
  color: rgba(220, 38, 38, 0.9);
  background: rgba(254, 226, 226, 0.5);
}
.monaco-editor .monaco-truncation-note {
  position: absolute;
  bottom: 4px;
  right: 8px;
  font-size: 10px;
  color: var(--fg-muted, #6b7280);
  background: rgba(255, 255, 255, 0.85);
  padding: 1px 6px;
  border-radius: 3px;
}

/* v2.0.3: animated skeleton shown while Monaco is loading. */
.monaco-editor .monaco-skeleton {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 18px;
  height: 100%;
  background: linear-gradient(90deg, #f1f5f9 0%, #e2e8f0 50%, #f1f5f9 100%);
  background-size: 200% 100%;
  animation: monaco-skeleton-shimmer 1.4s ease-in-out infinite;
  border-radius: 4px;
}
.monaco-editor .monaco-skeleton-bar {
  height: 12px;
  border-radius: 6px;
  background: rgba(15, 23, 42, 0.12);
}
.monaco-editor .monaco-skeleton-bar--lg { width: 80%; }
.monaco-editor .monaco-skeleton-bar--md { width: 60%; }
.monaco-editor .monaco-skeleton-bar--sm { width: 40%; }
.monaco-editor .monaco-skeleton-hint {
  margin-top: auto;
  font-size: 11px;
  color: rgba(15, 23, 42, 0.55);
  font-family: ui-monospace, Menlo, monospace;
}
@keyframes monaco-skeleton-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* v2.0.3: plain-text fallback shown when Monaco fails to load. */
.monaco-editor .monaco-fallback {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--bg, #ffffff);
}
.monaco-editor .monaco-fallback-notice {
  font-size: 11px;
  font-family: ui-monospace, Menlo, monospace;
  color: #b45309;
  background: #fef3c7;
  padding: 6px 12px;
  border-bottom: 1px solid #fde68a;
}
.monaco-editor .monaco-fallback-pre {
  flex: 1;
  margin: 0;
  padding: 10px 14px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre;
  overflow: auto;
  color: var(--fg, #0f172a);
  background: var(--bg, #ffffff);
}

/* ---------- LCS diff body ---------- */
.diff-body {
  list-style: none;
  margin: 6px 0 0;
  padding: 6px 8px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 4px;
  background: #fafafa;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  line-height: 1.5;
  max-height: 320px;
  overflow: auto;
}
.diff-line {
  display: flex;
  gap: 8px;
  padding: 0 4px;
  white-space: pre;
}
.diff-line .diff-gutter {
  flex: 0 0 14px;
  text-align: center;
  font-weight: 600;
}
.diff-line.diff-line-added {
  background: rgba(220, 252, 231, 0.6);
}
.diff-line.diff-line-added .diff-gutter {
  color: #15803d;
}
.diff-line.diff-line-removed {
  background: rgba(254, 226, 226, 0.6);
}
.diff-line.diff-line-removed .diff-gutter {
  color: #b91c1c;
}
.diff-line.diff-line-context .diff-gutter {
  color: var(--fg-muted, #9ca3af);
}
.diff-line .diff-text {
  flex: 1 1 auto;
  white-space: pre;
}

/* ---------- v2 small inline hint ---------- */
.v2-hint {
  font-size: 11px;
  color: var(--fg-muted, #6b7280);
}

/* ============================================================================
 * v2.0.0: Monaco Editor + File Tree + Diff + Mermaid jump
 *
 * Sections (search for the header to navigate):
 *   - .task-v2-layout        — sidebar + main grid
 *   - .file-tree-panel       — left sidebar
 *   - .file-tree             — collapsible nested list
 *   - .file-tree-node        — individual rows
 *   - .file-tree-chevron     — directory expand/collapse
 *   - .tool-call-detail      — right-hand detail panel
 *   - .monaco-editor         — Monaco container
 *   - .diff-body / .diff-line — LCS diff rendering
 *   - .v2-hint               — small inline hints
 * ========================================================================== */

/* ---------- v2.0.0 layout (sidebar + main) ---------- */
.task-v2-layout {
  display: grid;
  grid-template-columns: minmax(220px, 280px) 1fr;
  gap: 16px;
  margin: 0 auto;
  max-width: 1400px;
  padding: 0 16px;
}
.task-v2-layout > .task-v2-main {
  min-width: 0; /* allow grid item to shrink */
}
.file-tree-panel {
  position: sticky;
  top: 12px;
  align-self: start;
  max-height: calc(100vh - 24px);
  overflow: auto;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  padding: 12px 14px;
  background: var(--bg-panel, #fafafa);
}
.file-tree-panel h2 {
  font-size: 14px;
  margin: 0 0 6px;
  letter-spacing: 0.02em;
}
.file-tree-summary {
  font-size: 11px;
  color: var(--fg-muted, #6b7280);
  margin: 0 0 8px;
}
@media (max-width: 900px) {
  .task-v2-layout {
    grid-template-columns: 1fr;
  }
  .file-tree-panel {
    position: static;
    max-height: none;
  }
}

/* ---------- file tree sidebar ---------- */
.file-tree {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, monospace;
  font-size: 12px;
  line-height: 1.5;
}
.file-tree-node {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 1px 4px 1px calc(4px + var(--depth, 0) * 12px);
  border-radius: 3px;
  cursor: pointer;
  user-select: none;
}
.file-tree-node[data-collapsed="true"] {
  display: none;
}
.file-tree-node:hover {
  background: rgba(99, 102, 241, 0.08);
}
.file-tree-node.is-active {
  background: rgba(99, 102, 241, 0.18);
  outline: 1px solid rgba(99, 102, 241, 0.45);
  font-weight: 600;
}
.file-tree-node.is-affected .file-tree-name::after {
  content: " ●";
  color: rgba(220, 38, 38, 0.8);
  font-size: 10px;
}
.file-tree-chevron {
  display: inline-block;
  width: 12px;
  text-align: center;
  font-size: 9px;
  color: var(--fg-muted, #6b7280);
  flex: 0 0 12px;
}
.file-tree-spacer {
  display: inline-block;
  width: 12px;
  flex: 0 0 12px;
}
.file-tree-name {
  flex: 1 1 auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.file-tree-empty {
  list-style: none;
  color: var(--fg-muted, #6b7280);
  font-style: italic;
  padding: 4px;
}

/* ---------- tool-call detail panel ---------- */
.tool-call-detail-panel {
  border-left: 4px solid rgba(99, 102, 241, 0.55);
  padding-left: 14px;
  margin-top: 18px;
}
.tool-call-detail-panel .v2-hint {
  font-size: 12px;
  font-weight: 400;
  color: var(--fg-muted, #6b7280);
  margin-left: 8px;
}
.tool-call-detail {
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  padding: 10px 12px;
  margin-top: 8px;
  background: #ffffff;
}
.tool-call-header {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  margin-bottom: 6px;
}
.tool-call-header .tool-name code {
  background: rgba(99, 102, 241, 0.08);
  padding: 1px 6px;
  border-radius: 3px;
}
.tool-call-header .tool-path {
  color: var(--fg-muted, #6b7280);
  font-family: ui-monospace, Menlo, monospace;
  font-size: 11px;
  margin-left: auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
}
.tool-call-detail-empty {
  color: var(--fg-muted, #6b7280);
  font-style: italic;
  padding: 8px 0;
}

/* ---------- Monaco container ---------- */
.monaco-editor {
  width: 100%;
  height: 280px;
  border: 1px solid var(--border, #d1d5db);
  border-radius: 4px;
  margin: 6px 0 0;
  position: relative;
  background: #fafafa;
  overflow: hidden;
}
.monaco-editor .monaco-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--fg-muted, #6b7280);
  font-family: ui-monospace, Menlo, monospace;
  font-size: 12px;
}
.monaco-editor .monaco-error {
  color: rgba(220, 38, 38, 0.9);
  background: rgba(254, 226, 226, 0.5);
}
.monaco-editor .monaco-truncation-note {
  position: absolute;
  bottom: 4px;
  right: 8px;
  font-size: 10px;
  color: var(--fg-muted, #6b7280);
  background: rgba(255, 255, 255, 0.85);
  padding: 1px 6px;
  border-radius: 3px;
}

/* ---------- LCS diff body ---------- */
.diff-body {
  list-style: none;
  margin: 6px 0 0;
  padding: 6px 8px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 4px;
  background: #fafafa;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  line-height: 1.5;
  max-height: 320px;
  overflow: auto;
}
.diff-line {
  display: flex;
  gap: 8px;
  padding: 0 4px;
  white-space: pre;
}
.diff-line .diff-gutter {
  flex: 0 0 14px;
  text-align: center;
  font-weight: 600;
}
.diff-line.diff-line-added {
  background: rgba(220, 252, 231, 0.6);
}
.diff-line.diff-line-added .diff-gutter {
  color: #15803d;
}
.diff-line.diff-line-removed {
  background: rgba(254, 226, 226, 0.6);
}
.diff-line.diff-line-removed .diff-gutter {
  color: #b91c1c;
}
.diff-line.diff-line-context .diff-gutter {
  color: var(--fg-muted, #9ca3af);
}
.diff-line .diff-text {
  flex: 1 1 auto;
  white-space: pre;
}

/* ---------- v2 small inline hint ---------- */
.v2-hint {
  font-size: 11px;
  color: var(--fg-muted, #6b7280);
}

/* ============================================================
 * v2.5.0+ REQ-2: home-page chat panel
 * ============================================================
 *
 * v2.5.4 (Task #2826): the chat panel is now used on the dark
 * session-forest home page (Task #2811) and the dark task detail
 * page (Task #2809). The pre-v2.5.4 light-theme colors (white
 * `.chat-messages` + light grey `.chat-message--assistant`) made
 * the bubbles invisible because the body inherits
 * `color: var(--text) = #e6eefc` (near-white) — light text on
 * light bubble = unreadable. The fix re-skins the panel with the
 * existing dark-theme CSS variables and adds an explicit `color`
 * declaration on every bubble so contrast is enforced locally,
 * not inherited. WCAG contrast verified by
 * `test/chat-panel-display-v254.test.ts` (>= 4.5:1 on every
 * bubble against its background).
 */

.chat-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 12px;
}

.chat-panel-header h2 {
  margin: 0 0 4px;
  font-size: 18px;
}

.chat-panel-meta {
  margin: 0;
  font-size: 12px;
  color: var(--muted, #94a3b8);
}

.chat-messages {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 80px;
  max-height: 360px;
  overflow-y: auto;
  padding: 12px;
  border: 1px solid var(--border, #1e293b);
  border-radius: 8px;
  background: var(--panel-2, #182442);
  color: var(--text, #e6eefc);
  font-size: 14px;
}

.chat-empty {
  margin: 0;
  color: var(--muted, #94a3b8);
  font-style: italic;
}

.chat-message {
  padding: 8px 10px;
  border-radius: 6px;
  border: 1px solid transparent;
  color: var(--text, #e6eefc);
}

.chat-message-meta {
  font-size: 11px;
  color: var(--muted, #94a3b8);
  margin-bottom: 2px;
}

.chat-message-text {
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.4;
  color: var(--text, #e6eefc);
}

.chat-message--user {
  align-self: flex-end;
  background: #1d4ed8;
  border-color: #2563eb;
  color: #ffffff;
  max-width: 80%;
}

.chat-message--assistant {
  align-self: flex-start;
  background: #1e2a47;
  border-color: var(--border, #1e293b);
  color: var(--text, #e6eefc);
  max-width: 80%;
}

.chat-message--error {
  align-self: stretch;
  background: #7f1d1d;
  border-color: #b91c1c;
  color: #fee2e2;
}

.chat-form {
  display: flex;
  gap: 8px;
}

.chat-input {
  flex: 1 1 auto;
  padding: 8px 10px;
  border: 1px solid var(--border, #1e293b);
  border-radius: 6px;
  font-size: 14px;
  font-family: inherit;
  background: var(--panel, #111a2e);
  color: var(--text, #e6eefc);
}

.chat-input::placeholder {
  color: var(--muted, #94a3b8);
}

.chat-input:focus {
  outline: 2px solid #3b82f6;
  outline-offset: -1px;
  border-color: #3b82f6;
}

.chat-send {
  padding: 8px 16px;
  background: #2563eb;
  color: #fff;
  border: 1px solid #1d4ed8;
  border-radius: 6px;
  cursor: pointer;
  font-weight: 500;
}

.chat-send:hover:not(:disabled) {
  background: #1d4ed8;
}

.chat-send:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.chat-banner {
  padding: 8px 12px;
  margin: 0;
  background: rgba(245, 158, 11, 0.12);
  border: 1px solid #f59e0b;
  border-radius: 6px;
  color: #fcd34d;
  font-size: 13px;
}

.chat-scope-badge {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 8px;
  background: rgba(96, 165, 250, 0.18);
  color: #93c5fd;
  border: 1px solid rgba(96, 165, 250, 0.35);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  vertical-align: middle;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

/* ---------------------------------------------------------------------------
 * v2.5.x REQ-4 — Markdown styling for assistant chat bubbles.
 *
 * The assistant bubble (role="assistant") carries the rendered markdown
 * HTML produced by `public/markdown-renderer.js` (marked + DOMPurify).
 * User bubbles stay `textContent` literal — those rules below target
 * the `.chat-message-text` element regardless of role, but only the
 * assistant role actually contains HTML, so the styles are visually
 * inert on user bubbles.
 *
 * Design notes:
 *  - Headings are visually nested (1.4 / 1.2 / 1.05 rem) so a multi-level
 *    document stays scannable without screaming at the reader.
 *  - `pre` is a horizontal-scroll container with a subtle grey background,
 *    so a 200-char line does not blow up the bubble layout.
 *  - `code` (inline) gets a soft tinted background + monospace font.
 *    We deliberately do NOT add a border so it still reads as inline.
 *  - `blockquote` mirrors the help-text aesthetic elsewhere on the page.
 *  - `a` is the only place we paint blue — keeps the assistant bubble
 *    consistent with the rest of the app.
 *  - `table` is intentionally minimal (no zebra striping) — most LLM
 *    tables are 2-4 rows and zebra would just add noise.
 * ------------------------------------------------------------------------- */

.chat-message-text h1,
.chat-message-text h2,
.chat-message-text h3,
.chat-message-text h4,
.chat-message-text h5,
.chat-message-text h6 {
  margin: 0.6em 0 0.35em 0;
  line-height: 1.25;
  font-weight: 600;
  color: var(--text, #e6eefc);
}

.chat-message-text > h1:first-child,
.chat-message-text > h2:first-child,
.chat-message-text > h3:first-child,
.chat-message-text > h4:first-child,
.chat-message-text > h5:first-child,
.chat-message-text > h6:first-child {
  margin-top: 0;
}

.chat-message-text h1 { font-size: 1.4rem; }
.chat-message-text h2 { font-size: 1.2rem; }
.chat-message-text h3 { font-size: 1.05rem; }
.chat-message-text h4 { font-size: 1rem; }
.chat-message-text h5 { font-size: 0.95rem; }
.chat-message-text h6 { font-size: 0.9rem; color: var(--muted, #94a3b8); }

.chat-message-text p {
  margin: 0.4em 0;
}

.chat-message-text p:first-child { margin-top: 0; }
.chat-message-text p:last-child { margin-bottom: 0; }

.chat-message-text strong { font-weight: 700; }
.chat-message-text em { font-style: italic; }

.chat-message-text code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
  font-size: 0.92em;
  background: rgba(148, 163, 184, 0.18);
  padding: 1px 4px;
  border-radius: 3px;
  color: var(--text, #e6eefc);
}

.chat-message-text pre {
  margin: 0.5em 0;
  padding: 10px 12px;
  background: var(--code-bg, #0f172a);
  color: #f9fafb;
  border: 1px solid var(--border, #1e293b);
  border-radius: 6px;
  overflow-x: auto;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
  font-size: 0.88rem;
  line-height: 1.45;
  max-width: 100%;
}

.chat-message-text pre code {
  background: transparent;
  padding: 0;
  color: inherit;
  font-size: inherit;
  border-radius: 0;
}

.chat-message-text ul,
.chat-message-text ol {
  margin: 0.4em 0;
  padding-left: 1.5em;
}

.chat-message-text ul { list-style: disc; }
.chat-message-text ol { list-style: decimal; }

.chat-message-text li {
  margin: 0.15em 0;
}

.chat-message-text li > ul,
.chat-message-text li > ol {
  margin: 0.15em 0;
}

.chat-message-text blockquote {
  margin: 0.5em 0;
  padding: 4px 12px;
  border-left: 3px solid #60a5fa;
  background: rgba(96, 165, 250, 0.10);
  color: var(--text, #e6eefc);
  font-style: italic;
}

.chat-message-text blockquote > :first-child { margin-top: 0; }
.chat-message-text blockquote > :last-child { margin-bottom: 0; }

.chat-message-text a {
  color: #60a5fa;
  text-decoration: underline;
  text-underline-offset: 1px;
  word-break: break-word;
}

.chat-message-text a:hover {
  color: #93c5fd;
  text-decoration-thickness: 2px;
}

.chat-message-text hr {
  border: 0;
  border-top: 1px solid var(--border, #1e293b);
  margin: 0.8em 0;
}

.chat-message-text table {
  border-collapse: collapse;
  margin: 0.5em 0;
  width: 100%;
  font-size: 0.92em;
  color: var(--text, #e6eefc);
}

.chat-message-text th,
.chat-message-text td {
  border: 1px solid var(--border, #1e293b);
  padding: 4px 8px;
  text-align: left;
  vertical-align: top;
}

.chat-message-text th {
  background: rgba(148, 163, 184, 0.10);
  font-weight: 600;
}

.chat-message-text img {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
}

/* When the assistant bubble is currently streaming chunks (the JS marks
 * it via .is-streaming), tone down the borders a touch so the
 * re-rendered DOM doesn't flicker visually between chunks. */
/* (no streaming-specific styles yet — appendChunk uses
 * innerHTML replacement + a tiny render-time debounce in
 * public/markdown-renderer.js, which is below flicker threshold.) */

/* ============================================================================
 * v2.5.12 (Task #2952): full-content file viewer for write_file / write /
 * create_file + unified-diff rendering for edit_file / multi_edit_file /
 * apply_patch.
 *
 * Contract: the right-hand tool-call detail panel MUST render the FULL
 * payload for write_file (no max-height truncation) and a git-style diff
 * for edit_file (no Monaco fallback). The classes below scope the styles
 * tightly so the legacy `.diff-body` rules (which still cap at 320px) are
 * unaffected for any pre-existing inline consumers.
 * ========================================================================== */

.file-viewer.write-file,
.file-viewer.edit-file {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  line-height: 1.55;
  margin: 6px 0 0;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 4px;
  background: #fafafa;
}

.file-viewer .file-header {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border, #e5e7eb);
  background: #f3f4f6;
  font-size: 11px;
}

.file-viewer .file-icon {
  font-size: 13px;
  flex: 0 0 auto;
}

.file-viewer .file-path {
  font-weight: 600;
  color: var(--fg, #0f172a);
  word-break: break-all;
}

.file-viewer .file-meta {
  color: var(--fg-muted, #6b7280);
  margin-left: auto;
  flex: 0 0 auto;
  white-space: nowrap;
}

.file-viewer .code-block {
  margin: 0;
  padding: 6px 0 6px 0;
  /* Task #2952: NO max-height — full content must be visible. */
  max-height: none !important;
  overflow-y: visible;
  background: transparent;
}

.file-viewer .code-line,
.file-viewer .diff-line {
  display: flex;
  white-space: pre;
  padding: 0 8px;
  min-height: 1.55em;
}

.file-viewer .code-line .ln,
.file-viewer .diff-line .ln {
  flex: 0 0 4ch;
  text-align: right;
  margin-right: 8px;
  color: var(--fg-muted, #9ca3af);
  user-select: none;
}

.file-viewer .diff-line .marker {
  flex: 0 0 1ch;
  text-align: center;
  font-weight: 600;
  margin-right: 4px;
}

.file-viewer .diff-line[data-kind="add"] {
  background: rgba(46, 160, 67, 0.12);
}
.file-viewer .diff-line[data-kind="add"] .marker {
  color: #2ea043;
}
.file-viewer .diff-line[data-kind="remove"] {
  background: rgba(248, 81, 73, 0.12);
}
.file-viewer .diff-line[data-kind="remove"] .marker {
  color: #f85149;
}
.file-viewer .diff-line[data-kind="context"] {
  opacity: 0.7;
}
.file-viewer .diff-line[data-kind="context"] .marker {
  color: var(--fg-muted, #9ca3af);
}

.file-viewer .code-line .content,
.file-viewer .diff-line .content {
  flex: 1 1 auto;
  white-space: pre;
}
