/* ==========================================================================
   turnstone — conversation.css
   Shared conversational-pane card vocabulary (step 5e.2).

   ONE neutral approval-card vocabulary (`.conv-*`) emitted by BOTH panes —
   the interactive pane (shared_static/interactive.js) and the coordinator
   pane (console/static/coordinator/coordinator.js).  Supersedes the two
   forked vocabularies it converges:
     - coordinator's `.coord-tool-*` tool-batch construct (coordinator.css)
     - interactive's `.ts-approval-*` / `.verdict-*` approval block
       (chat.css + interactive.css)

   The card is built by the shared builders in conversation.js, so both
   surfaces produce the SAME DOM and read the SAME.  Pane differences are
   AFFORDANCES layered on (parameterized), not separate machinery:
     - coordinator: per-call index pill + the parallel left-rail;
       the child-route approval block (`.approval-*`, coord-chrome.css)
       reuses the shared verdict/actions/btn pieces below.
     - interactive: the early-paint announce shell (`--announced`,
       aria-busy), the recommended-button glow, the inline feedback input,
       the auto-approved badge, and the bash `$ cmd` + diff preview rows.

   Tokens come from base.css — the DS-blessed vocabulary
   (`--ok/--warn/--err`, `--ink-*`, `--panel/--panel-2`, `--hair*`, `--r-*`,
   `--font-mono`), NOT chat.css's legacy `--green/--red/--cyan/--fg`.  This
   is the convergence: approve uses `--ok` (green), NOT `--warn` — the
   load-bearing DS hard-rule (base.css:84).  Loaded by the console
   (index.html + coordinator/index.html) and, from step 6, standalone.

   House style: programmatic DOM, no innerHTML; builders return a detached
   element and let the caller append + scroll (pane- and transport-agnostic).
   ========================================================================== */

/* ==========================================================================
   Card shell — pairs tool calls with their verdicts + results and embeds
   the approval gate.  One construct per dispatch turn:
     - solo (1 call):       .conv-batch--solo
     - parallel (>=2 calls): .conv-batch--parallel  (rows share a left rail
                            so they read as siblings of one decision)

   Sub-elements:
     .conv-batch-head     kicker + summary + tier glyph
     .conv-row            per-call row (call line + verdict + result)
       .conv-row-call     [idx] name args/cmd ellipsized
       .conv-row-diff     optional unified-diff preview (edit/write tools)
       .conv-verdict      judge verdict badge + expandable detail
       .conv-warning      output-guard finding chip
       .conv-row-result   paired tool_result block under the row
       .conv-row-status   per-row pill (auto-approved / error)
     .conv-actions        Approve / Deny / Approve all (+ feedback input)
     .conv-status         resolved status pill (replaces actions)

   States (modifiers on the batch):
     .conv-batch--pending   approval gate visible
     .conv-batch--approved  resolved approve
     .conv-batch--denied    resolved deny — rows dimmed
     .conv-batch--auto      all auto-approved, no gate ever shown
     .conv-batch--running   in-flight (dispatched, no result yet) — no actions
     .conv-batch--error     a row errored
   ========================================================================== */
.conv-batch {
  margin: 4px 0;
  background: var(--panel);
  border: 1px solid var(--hair);
  border-left: 3px solid var(--hair-2);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.5;
  overflow: hidden;
}

/* State left-stripe — neutral default; warn when gating; ok when
   resolved-approved; err when denied or any row errored.  Three stacked
   non-colour cues for WCAG 1.4.1: pill text in the head, rail colour, and
   row dimming on deny. */
.conv-batch--pending {
  border-left-color: var(--warn);
}
.conv-batch--approved {
  border-left-color: color-mix(in srgb, var(--ok) 65%, var(--hair-2));
}
.conv-batch--auto {
  border-left-color: var(--hair-2);
}
.conv-batch--running {
  /* Subtle accent stripe so an in-flight batch reads apart from a resolved
     one without screaming for attention.  Not warn (which implies a gate). */
  border-left-color: color-mix(in srgb, var(--accent) 50%, var(--hair-2));
}
.conv-batch--denied,
.conv-batch--error {
  border-left-color: var(--err);
}
.conv-batch--denied .conv-row {
  opacity: 0.6;
}

/* Header strip — small uppercase kicker + per-batch metadata. */
.conv-batch-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  padding: 6px 10px;
  background: var(--panel-2);
  border-bottom: 1px solid var(--hair);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.conv-batch-kicker {
  color: var(--ink-3);
}
.conv-batch--pending .conv-batch-kicker {
  /* The operator's primary decision cue — darken off raw --warn so it clears AA
     on the light --panel-2 (4.17:1 -> ~5.5:1).  The mix tracks the theme (--ink-2
     is light in dark, dark in light), so dark stays warm + passing too. */
  color: color-mix(in srgb, var(--warn) 78%, var(--ink-2));
}
.conv-batch--approved .conv-batch-kicker {
  color: color-mix(in srgb, var(--ok) 70%, var(--ink-2));
}
.conv-batch--denied .conv-batch-kicker {
  color: var(--err);
}
.conv-batch-summary {
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
}
.conv-batch-tier {
  margin-left: auto;
  font-family: var(--font-mono);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  /* ink-3, not ink-4: ink-4 on panel-2 fails light-mode AA (3.89:1) and
     this carries the judge-tier provenance (the thin balance glyph). */
  color: var(--ink-3);
  font-size: 10px;
}

/* Row container.  Parallel batches frame rows with a left rail so they
   read as siblings of one decision; solo batches suppress it to keep
   visual weight low. */
.conv-row {
  position: relative;
  padding: 8px 10px;
}
.conv-row + .conv-row {
  border-top: 1px solid var(--hair);
}
.conv-batch--parallel .conv-row {
  padding-left: 28px;
}
.conv-batch--parallel .conv-row::before {
  /* Vertical rail tick — connects rows as a parallel group; stops 4px
     short of the first/last row edge (class markers, not :first-of-type:
     the batch holds other <div> siblings of the same type). */
  content: "";
  position: absolute;
  left: 14px;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--hair-2);
}
.conv-batch--parallel .conv-row.conv-row--first::before {
  top: 4px;
}
.conv-batch--parallel .conv-row.conv-row--last::before {
  bottom: 4px;
}
.conv-batch--parallel .conv-row::after {
  content: "";
  position: absolute;
  left: 11px;
  top: 14px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--panel);
  border: 1.5px solid var(--hair-2);
}
.conv-batch--parallel.conv-batch--approved .conv-row::after {
  border-color: color-mix(in srgb, var(--ok) 65%, var(--hair-2));
}
.conv-batch--parallel.conv-batch--denied .conv-row::after,
.conv-row.error::after {
  border-color: var(--err);
}

/* memory/recall calls are background metadata — dim by default, full
   opacity on hover so the audit trail stays inspectable without crowding
   the tree on memory-heavy workstreams. */
.conv-row[data-tool-name="memory"],
.conv-row[data-tool-name="recall"] {
  opacity: 0.55;
  transition: opacity 120ms ease-out;
}
.conv-row[data-tool-name="memory"]:hover,
.conv-row[data-tool-name="memory"]:focus-within,
.conv-row[data-tool-name="recall"]:hover,
.conv-row[data-tool-name="recall"]:focus-within {
  opacity: 1;
}

/* Call line — index/N pill, monospace tool name, ellipsized args. */
.conv-row-call {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}
.conv-row-idx {
  flex-shrink: 0;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  background: var(--panel-2);
  border: 1px solid var(--hair);
  border-radius: 3px;
}
.conv-row-name {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--ink);
}
.conv-row.error .conv-row-name {
  color: var(--err);
}
.conv-row-args {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
  color: var(--ink-3);
}
/* Inline auto-approve tag next to the tool name — surfaces tools that
   bypassed the operator gate (skill allowlist / blanket / "Approve all"). */
.conv-row-auto {
  margin-left: 6px;
  font-size: 10px;
  font-weight: 500;
  color: color-mix(in srgb, var(--ok) 70%, var(--ink-3));
}

/* Command + diff preview (interactive tool rows — bash `$ cmd`, edit/write
   diffs).  The coordinator's args-summary and this cmd/diff render are
   mutually-exclusive second lines: a row shows whichever the item carries. */
.conv-row-cmd {
  margin-top: 4px;
  font-family: var(--font-mono);
  color: var(--ink-2);
  white-space: pre-wrap;
  word-break: break-word;
}
.conv-row-cmd .conv-row-cmd-dollar {
  color: var(--ink-4);
  user-select: none;
}
.conv-row-diff {
  margin-top: 4px;
  padding: 6px 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-3);
  background: var(--panel-2);
  border-left: 2px solid var(--hair);
  border-radius: 0 3px 3px 0;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 240px;
  overflow: auto;
}
.conv-diff-del {
  color: var(--err);
}
.conv-diff-add {
  color: color-mix(in srgb, var(--ok) 75%, var(--ink-2));
}
.conv-diff-warn {
  color: var(--warn);
}
/* Preview-omission notice — rendered as a SIBLING below the .conv-row-diff
   scroll box (never inside it, where the 240px fold hides it).  Neutral ink,
   not --warn: informational omission, and AA-safe on both themes. */
.conv-diff-omit {
  margin-top: 2px;
  padding: 2px 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-3);
}

/* Verdict badge — interactive's rich shape (risk + rec + conf, expandable
   detail) in the coordinator's neutral idiom.  Risk drives the left-stripe
   (low=ok / medium=warn / high+critical=err), matching the warning chip so
   an operator reads risk consistently across both surfaces. */
.conv-verdict {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  padding: 2px 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-3);
  background: var(--panel-2);
  border: 1px solid var(--hair);
  border-left-width: 3px;
  border-left-color: var(--hair-2);
  border-radius: 0 3px 3px 0;
  max-width: max-content;
}
.conv-verdict--low {
  border-left-color: var(--ok);
}
.conv-verdict--medium {
  border-left-color: var(--warn);
}
.conv-verdict--high,
.conv-verdict--critical {
  border-left-color: var(--err);
}
/* Judging (spinner present, no verdict yet) — keep the stripe neutral; an
   amber/red severity rail before the judge lands is a false signal and
   competes with the batch's subtle --running accent.  (5e.2b also withholds
   the --{risk} class until a verdict lands; this is the belt-and-suspenders.) */
.conv-verdict:has(.conv-verdict-spinner) {
  border-left-color: var(--hair-2);
}
.conv-verdict-risk {
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-2);
}
.conv-verdict-rec {
  color: var(--ink-3);
}
.conv-verdict-rec--approve {
  color: color-mix(in srgb, var(--ok) 70%, var(--ink-2));
}
.conv-verdict-rec--review {
  color: color-mix(in srgb, var(--warn) 70%, var(--ink-2));
}
.conv-verdict-rec--deny {
  color: color-mix(in srgb, var(--err) 70%, var(--ink-2));
}
.conv-verdict-conf {
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.conv-verdict-expand {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: 11px;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
}
.conv-verdict-expand:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* judge-pending spinner — inline in the badge until the LLM verdict lands. */
.conv-verdict-spinner {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--ink-3);
}
.conv-verdict-spinner-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1.5px solid var(--accent);
  border-top-color: transparent;
  animation: conv-spin 0.9s linear infinite;
}
/* Self-contained keyframe — coord-chrome.css's `ts-spin` isn't loaded
   everywhere this shared sheet is (the standalone interactive pane omits
   it), so namespace + define our own. */
@keyframes conv-spin {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .conv-verdict-spinner-dot {
    animation: none;
  }
}
/* Expandable detail — judge reasoning + summary + evidence + tier.  Block
   under the badge; toggled (display) by the expand button. */
.conv-verdict-detail {
  margin: 4px 0 0 14px;
  padding: 6px 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-3);
  background: var(--panel-2);
  border-left: 2px solid var(--hair);
  border-radius: 0 3px 3px 0;
}
.conv-verdict-summary {
  color: var(--ink-2);
}
.conv-verdict-reasoning {
  margin-top: 4px;
  white-space: pre-wrap;
}
.conv-verdict-evidence {
  margin-top: 4px;
  color: var(--ink-3);
}
.conv-verdict-tier {
  margin-top: 4px;
  font-size: 10px;
  color: var(--ink-3);
}

/* Recommended-button glow — highlights the judge's recommended action while
   a verdict is present (interactive affordance; attaches to the actions). */
.conv-verdict-glow--approve .conv-btn--approve {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--ok) 30%, transparent);
}
.conv-verdict-glow--deny .conv-btn--deny {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--err) 30%, transparent);
}
.conv-verdict-glow--review .conv-btn--approve,
.conv-verdict-glow--review .conv-btn--deny {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--warn) 30%, transparent);
}

/* Output-guard finding chip — anchored under the call that tripped the
   guard.  Severity drives the hue (mirrors the verdict left-stripe). */
.conv-warning {
  /* flex-wrap + baseline so the optional full-width reasoning line drops
     below the label/flag/tier row instead of cramming it (the reasoning
     child sets flex-basis:100%); width:max-content keeps short chips
     shrink-wrapped, max-width:100% caps a long reasoning to the row. */
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin-top: 4px;
  padding: 2px 8px;
  font-size: 11px;
  font-family: var(--font-mono);
  border: 1px solid var(--hair);
  border-radius: 3px;
  border-left-width: 3px;
  background: var(--panel-2);
  color: var(--ink-2);
  width: max-content;
  max-width: 100%;
}
/* Severity word — weight + uppercase to match the verdict badge's risk word
   so the two surfaces read severity the same way. */
.conv-warning-label {
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.conv-warning--low {
  color: color-mix(in srgb, var(--ok) 70%, var(--ink-2));
  border-left-color: var(--ok);
  background: color-mix(in srgb, var(--ok) 12%, var(--panel-2));
}
.conv-warning--medium {
  color: color-mix(in srgb, var(--warn) 70%, var(--ink-2));
  border-left-color: var(--warn);
  /* 12% warn mix (not the raw --warn-tint, which is a saturated mustard that
     made MEDIUM visually outweigh HIGH) so severity reads low<med<high. */
  background: color-mix(in srgb, var(--warn) 12%, var(--panel-2));
}
.conv-warning--high,
.conv-warning--critical {
  color: color-mix(in srgb, var(--err) 70%, var(--ink-2));
  border-left-color: var(--err);
  background: color-mix(in srgb, var(--err) 12%, var(--panel-2));
}
.conv-warning-redacted {
  color: var(--ink-3);
  font-size: 10px;
}
/* LLM-judge attribution badge inside the chip — weight + dimmer ink mark
   it as metadata rather than another flag. */
.conv-warning-tier {
  font-weight: 600;
  font-size: 10px;
  opacity: 0.85;
}
/* Judge rationale — muted second line so the finding explains itself. */
.conv-warning-reasoning {
  flex-basis: 100%;
  margin-top: 2px;
  font-size: 10px;
  color: var(--ink-3);
  white-space: pre-wrap;
}

/* Tool result block — paired under its row, mono pre-block.  Capped at
   240px with internal scroll so a long output doesn't push the chat
   off-screen. */
.conv-row-result {
  margin-top: 6px;
  padding: 6px 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-2);
  background: var(--panel-2);
  border-left: 2px solid var(--hair);
  border-radius: 0 3px 3px 0;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 240px;
  overflow: auto;
}
.conv-row.error .conv-row-result {
  border-left-color: var(--err);
  color: color-mix(in srgb, var(--err) 75%, var(--ink-2));
}
.conv-row-result-lead {
  display: inline-block;
  margin-right: 4px;
  color: var(--ink-4);
  font-weight: 600;
}

/* Per-row status pill (auto-approved, error). */
.conv-row-status {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 4px;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-radius: 3px;
  border: 1px solid var(--hair);
  color: var(--ink-3);
}
.conv-row-status--auto {
  color: color-mix(in srgb, var(--ok) 70%, var(--ink-2));
  border-color: color-mix(in srgb, var(--ok) 38%, var(--hair));
  background: color-mix(in srgb, var(--ok) 12%, var(--panel-2));
}
.conv-row-status--error {
  color: var(--err);
  border-color: color-mix(in srgb, var(--err) 38%, var(--hair));
  background: color-mix(in srgb, var(--err) 12%, var(--panel-2));
}

/* Action row — Approve / Deny / Approve all.  Renders inside a pending
   batch as the operator's gate.  Button vocabulary follows the DS:
   primary Approve = subtle --ok fill, Approve all = dashed --ok ghost
   (auto-approve similar going forward), Deny = danger. */
.conv-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  background: var(--panel-2);
  border-top: 1px solid var(--hair);
  flex-wrap: wrap;
}
.conv-actions .conv-actions-spacer {
  flex: 1;
}
.conv-btn {
  padding: 6px 14px;
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  background: var(--panel);
  border: 1.5px solid var(--hair-2);
  border-radius: var(--r-md);
  cursor: pointer;
  transition:
    background 120ms ease,
    border-color 120ms ease,
    color 120ms ease;
}
.conv-btn:hover {
  color: var(--ink);
  border-color: var(--ink-4);
}
.conv-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.conv-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.conv-btn--approve {
  background: color-mix(in srgb, var(--ok) 28%, var(--panel));
  color: var(--ok-text);
  border-color: color-mix(in srgb, var(--ok) 65%, var(--hair));
  font-weight: 600;
}
.conv-btn--approve:hover {
  background: color-mix(in srgb, var(--ok) 40%, var(--panel));
  color: var(--ink);
  border-color: var(--ok);
}
.conv-btn--always {
  background: transparent;
  border-style: dashed;
  border-color: color-mix(in srgb, var(--ok) 65%, var(--hair));
  color: var(--ok-text);
}
.conv-btn--always:hover {
  background: color-mix(in srgb, var(--ok) 15%, var(--panel));
  color: var(--ink);
  border-color: var(--ok);
}
.conv-btn--deny {
  color: var(--err);
  border-color: color-mix(in srgb, var(--err) 42%, var(--hair));
}
.conv-btn--deny:hover {
  background: var(--err-soft);
  color: var(--err);
  border-color: var(--err);
}
.conv-kbd {
  margin-left: 6px;
  padding: 0 3px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-3);
  border: 1px solid var(--hair);
  border-radius: 2px;
}
.conv-btn--approve .conv-kbd {
  color: color-mix(in srgb, var(--ok) 70%, var(--ink-3));
  border-color: color-mix(in srgb, var(--ok) 40%, var(--hair));
}
/* Optional feedback input (interactive affordance — the operator can attach
   a note to an approve/deny; the coordinator gate doesn't collect one). */
.conv-feedback {
  flex-basis: 100%;
  margin-top: 6px;
  padding: 4px 8px;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--hair);
  border-radius: var(--r-sm);
}
.conv-feedback:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}
.conv-feedback::placeholder {
  color: var(--ink-4);
}

/* Resolved status pill — replaces the action row after approve/deny, or
   prefills on history replay of a resolved batch. */
.conv-status {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--panel-2);
  border-top: 1px solid var(--hair);
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-3);
}
.conv-status--approved,
.conv-status--auto {
  color: color-mix(in srgb, var(--ok) 70%, var(--ink-2));
}
.conv-status--denied,
.conv-status--error {
  color: var(--err);
}
.conv-status-feedback {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-3);
}

/* Mobile (<700px) — keep action targets >=44px for WCAG 2.5.5. */
@media (max-width: 700px) {
  .conv-actions button.conv-btn {
    flex: 1 1 30%;
    min-height: 44px;
    font-size: 13px;
  }
}

/* Task-agent card — a task_agent .conv-row hosts a collapsible body of its
   sub-tool steps so they nest under the call instead of scattering top-level.
   Accent rail + inset background read as "inside" the task agent. */
.conv-agent {
  margin: 8px 0 2px;
  border-left: 2px solid color-mix(in srgb, var(--accent) 45%, var(--hair-2));
  border-radius: var(--r-sm);
  background: var(--panel-2);
}
.conv-agent-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  min-height: 28px; /* the card's primary control — a real hit target */
  padding: 4px 10px;
  background: none;
  border: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  cursor: pointer;
  text-align: left;
}
.conv-agent-toggle:hover {
  color: var(--ink-2);
  background: color-mix(in srgb, var(--ink) 5%, transparent);
}
.conv-agent-toggle:focus-visible {
  /* Match the house focus ring (.conv-btn / .conv-verdict-expand); inset
     because the toggle is full-width, flush to the card edge. */
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: var(--r-sm);
}
.conv-agent-caret {
  display: inline-block;
  font-size: 11px;
  color: var(--ink-3);
  transition: transform 0.12s ease;
}
.conv-agent[data-collapsed="true"] .conv-agent-caret {
  transform: rotate(-90deg); /* ▾ -> ▸, from the one collapse attribute */
}
.conv-agent[data-collapsed="true"] .conv-agent-body {
  display: none;
}
@media (prefers-reduced-motion: reduce) {
  .conv-agent-caret {
    transition: none;
  }
}
.conv-agent-label {
  letter-spacing: 0;
  text-transform: none;
}
/* Card-level liveness as a NON-colour cue (WCAG 1.4.1): a text suffix, not just
   a stripe — in a parallel batch the parent rail belongs to the whole group,
   not to this one task agent. */
.conv-agent[data-state="running"] .conv-agent-label::after {
  content: " · running";
  color: var(--ink-3);
}
.conv-agent[data-state="done"] .conv-agent-label::after {
  content: " · done";
  color: color-mix(in srgb, var(--ok) 70%, var(--ink-2));
}
.conv-agent[data-state="error"] .conv-agent-label::after {
  content: " · failed";
  color: var(--err);
}
.conv-agent-body {
  border-top: 1px solid var(--hair);
}
.conv-agent-body:empty {
  border-top: 0; /* no orphan hairline before the first step paints */
}
/* Nested step rows read a touch lighter than top-level tool rows. */
.conv-agent-body .conv-row {
  padding: 6px 10px;
  font-size: 11px;
}
.conv-agent-body .conv-row + .conv-row {
  border-top: 1px solid var(--hair);
}
/* The card lives inside a .conv-row; in a PARALLEL batch the rail tick + dot
   (.conv-batch--parallel .conv-row::before/::after) are descendant rules that
   would re-draw on every nested step, striking through the names.  Suppress
   them — the card's own accent rail already signals grouping. */
.conv-agent-body .conv-row::before,
.conv-agent-body .conv-row::after {
  content: none;
}
.conv-batch--parallel .conv-agent-body .conv-row {
  padding-left: 10px;
}
/* A nested sub-tool's approval gate binds to ITS step, not the whole card:
   drop the right-floating spacer so Deny/Approve sit under the step's command. */
.conv-agent-body .conv-actions {
  align-items: stretch;
}
.conv-agent-body .conv-actions .conv-actions-spacer {
  display: none;
}
/* The streaming-output box is a sibling between nested rows; match the card's
   type scale + rail, and restore the row separators it sits between. */
.conv-agent-body .tool-output-stream {
  font-size: 11px;
  border-left-color: color-mix(in srgb, var(--accent) 45%, var(--hair-2));
}
.conv-agent-body .conv-row + .tool-output-stream,
.conv-agent-body .tool-output-stream + .conv-row {
  border-top: 1px solid var(--hair);
}
@media (max-width: 700px) {
  .conv-agent-toggle {
    min-height: 44px; /* WCAG 2.5.5 touch target */
  }
}
