/* chat.css — `.thread` and its descendants (SPEC §4.4), plus the surfaces that
 * only exist on the chat screen: the composer, the question / approval cards,
 * the Connect strip and the inspector.
 * Cascade position: fourth. No custom property, no literal colour.
 *
 * Every visual state is read from the attributes §4.4 declares normative:
 *   .turn[data-state]         streaming | done | aborted | error | truncated
 *   .tool[data-state]         running | ok | waiting | error | held | notrun | interrupted
 *   .tool__status[data-verdict]   the same seven
 *   .subagent[data-status]    running | done | failed | aborted | interrupted
 *   .plan__step[data-status]  pending | in_progress | done | skipped
 *   .note[data-kind]          the runner_message kinds
 */

@keyframes blink {
  0%,
  45% {
    opacity: 1;
  }

  55%,
  100% {
    opacity: 0;
  }
}

/* ══ the scroll region ═════════════════════════════════════════════════════ */

.chat {
  flex: 1 1 auto;
  min-block-size: 0;
  overflow-y: auto;
  overflow-x: clip;
  overscroll-behavior-y: contain;
  scroll-padding-block-end: var(--sp-7);
  /* the room a coach mark reserves below the last line while it is up or
     waiting (chat/coach.js reserveRoom): padding, not an element, so nothing
     walking "what follows the turn" takes the room for content */
  padding-block-end: var(--coach-room);
}

.chat__sentinel {
  block-size: 1px;
}

/* ══ thread ════════════════════════════════════════════════════════════════ */

.thread {
  list-style: none;
  inline-size: 100%;
  max-inline-size: 900px;
  margin-inline: auto;
  padding-inline: var(--sp-4);
  padding-block: var(--sp-5) var(--sp-6);
}

/* the first-run strip's place below 720 px (chat/index.js placeFirstRun):
   the transcript's column, right after the list — which already ends in its
   own padding, so this one adds none above, and nothing at all while empty */
.thread--after {
  padding-block: 0 var(--sp-5);
}

.thread:has(+ .thread--after:not(:empty)) {
  padding-block-end: var(--sp-3);
}

.thread--after:empty {
  display: none;
}

.turn {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding-block: var(--sp-5);
  border-block-start: 1px solid var(--border);
  /* off-screen history costs nothing (§4.4, §5.6) */
  content-visibility: auto;
  contain-intrinsic-size: 0 480px;
}

.turn:first-child {
  border-block-start: 0;
  padding-block-start: 0;
}

.turn[data-state="error"] {
  border-inline-start: 3px solid var(--danger);
  padding-inline-start: var(--sp-3);
}

.turn[data-state="aborted"],
.turn[data-state="truncated"] {
  border-inline-start: 3px solid var(--border-strong);
  padding-inline-start: var(--sp-3);
}

/* wide: the rule hangs in the thread's own gutter, so the turn's content —
   the user's bubble included — stays on the column every other turn uses
   instead of sitting 15 px to its right. --sp-2 + 3 px fits inside the
   thread's padding at both densities (--sp-4 is 12 px when compact). */
@media (min-width: 720px) {
  .turn[data-state="error"],
  .turn[data-state="aborted"],
  .turn[data-state="truncated"] {
    margin-inline-start: calc(-1 * (var(--sp-2) + 3px));
    padding-inline-start: var(--sp-2);
  }
}

/* ── the human's message ─────────────────────────────────────────────────── */

.msg {
  min-inline-size: 0;
}

.msg--user .msg__body {
  max-inline-size: var(--measure);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--bg-subtle);
  overflow-wrap: anywhere;
}

.msg--user .msg__body p + p {
  margin-block-start: var(--sp-3);
}

.msg__meta {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-block-start: var(--sp-1);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

/* ── the chip row: model / agent / thinking ──────────────────────────────── */

.turn__chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  /* the row is held to the column, so a chip's own max-inline-size and
     ellipsis resolve against it: a long model ref is cut with "…" at the
     column edge (its title carries the rest) instead of running off screen */
  min-inline-size: 0;
  max-inline-size: 100%;
}

/* block, not the chip's inline-flex: text-overflow does nothing on a flex
   container, so a flex chip is cut mid-letter with no ellipsis */
.turn__chips > .chip {
  display: block;
  min-inline-size: 0;
  text-overflow: ellipsis;
}

/* ── the working line: something moves within one RTT (§4.3) ─────────────── */

.turn__status {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.turn__elapsed {
  font-variant-numeric: tabular-nums;
}

.turn__hint {
  color: var(--text-faint);
}

.turn__hint:empty {
  display: none;
}

/* ── the plan strip, pinned to the top of a running turn ─────────────────── */

.plan-strip {
  position: sticky;
  inset-block-start: var(--sp-2);
  z-index: var(--z-sticky);
  align-self: flex-start;
  max-inline-size: 100%;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--accent);
  border-radius: var(--r-full);
  background: var(--accent-subtle);
  color: var(--text);
  box-shadow: var(--sh-1);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* narrow: a band, not a pill floating over the card beneath it */
@media (max-width: 720px) {
  .plan-strip {
    align-self: stretch;
    border-radius: var(--r-md);
  }
}

/* ── the interleaved stream ──────────────────────────────────────────────── */

.turn__stream {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-inline-size: 0;
}

/* ══ prose — the assistant's text, and the only markdown-rendered surface ══ */

.prose {
  max-inline-size: var(--measure);
  font-size: var(--fs-base);
  line-height: var(--lh-prose);
  overflow-wrap: anywhere;
}

.prose > * + * {
  margin-block-start: var(--sp-3);
}

/* bidi: every paragraph of running text takes its direction from its own
   first strong character, so an Arabic or Hebrew sentence with `src/app.js`
   in it reads in its own clause order. lib/md.js and the user bubble set
   dir="auto" on these blocks; this is the backstop for one that arrives
   without it. Code blocks keep the inherited left-to-right. */
.msg__body p,
.prose p,
.prose li,
.prose blockquote {
  unicode-bidi: plaintext;
  text-align: start;
}

.prose h4,
.prose h5,
.prose h6 {
  margin-block-start: var(--sp-5);
  line-height: var(--lh-tight);
}

.prose h4 {
  font-size: var(--fs-md);
}

.prose h5 {
  font-size: var(--fs-base);
}

.prose h6 {
  font-size: var(--fs-sm);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-muted);
}

.prose ul,
.prose ol {
  padding-inline-start: var(--sp-5);
}

/* the thread is an <ol> and every turn an <li> (§5.5), so the UA's depth-based
   marker rules would start prose lists at `circle` / `lower-alpha`. Restate the
   first two levels explicitly. */
.prose ul {
  list-style-type: disc;
}

.prose ul ul {
  list-style-type: circle;
}

.prose ul ul ul {
  list-style-type: square;
}

.prose ol {
  list-style-type: decimal;
}

.prose ol ol {
  list-style-type: lower-alpha;
}

.prose li + li {
  margin-block-start: var(--sp-1);
}

.prose li > ul,
.prose li > ol {
  margin-block-start: var(--sp-1);
}

.prose li > p + p {
  margin-block-start: var(--sp-2);
}

/* GFM task items render as a disabled checkbox + label */
.prose li:has(> input[type="checkbox"]) {
  list-style: none;
  margin-inline-start: calc(-1 * var(--sp-5));
  padding-inline-start: var(--sp-1);
}

.prose li > input[type="checkbox"] {
  accent-color: var(--accent);
  margin-inline-end: var(--sp-2);
}

.prose blockquote {
  padding: var(--sp-1) var(--sp-4);
  border-inline-start: 3px solid var(--border-strong);
  color: var(--text-muted);
}

.prose hr {
  margin-block: var(--sp-4);
}

.prose a {
  overflow-wrap: anywhere;
}

.prose :not(pre) > code {
  padding: 1px var(--sp-1);
  border: 1px solid var(--code-border);
  border-radius: var(--r-sm);
  background: var(--code-bg);
  overflow-wrap: anywhere;
}

.prose table {
  inline-size: 100%;
  font-size: var(--fs-sm);
}

.prose th,
.prose td {
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--border);
  text-align: start;
}

.prose th {
  background: var(--bg-subtle);
  font-weight: var(--fw-semibold);
}

.prose .scroll-x > table {
  min-inline-size: max-content;
}

/* a guardrail took something out before it reached the reader (§4.7 rule 5) */
.redacted {
  background: var(--warn-subtle);
  color: var(--warn);
  border: 1px dashed var(--warn);
  border-radius: var(--r-sm);
  padding-inline: var(--sp-1);
  font-size: 0.9em;
  cursor: help;
}

/* the streaming caret */
.caret {
  display: inline-block;
  inline-size: 2px;
  block-size: 1em;
  margin-inline-start: 2px;
  vertical-align: -0.15em;
  background: var(--accent);
  animation: blink 1.1s step-end infinite;
}

/* ══ the reasoning lane ════════════════════════════════════════════════════ */

.reason {
  max-inline-size: var(--measure);
  padding-inline-start: var(--sp-3);
  border-inline-start: 2px dotted var(--border-strong);
  color: var(--text-muted);
}

.reason__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-block-size: 28px;
  padding-inline-end: var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-faint);
}

.reason__toggle:hover {
  color: var(--text);
}

.reason__toggle::before {
  content: "▸";
  display: inline-block;
  transition: transform var(--dur-fast) var(--ease-out);
}

.reason__toggle[aria-expanded="true"]::before {
  transform: rotate(90deg);
}

.reason__text {
  margin: 0;
  padding-block: var(--sp-1) var(--sp-2);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: var(--lh-base);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--text-muted);
}

/* reasoning read back from history is a stub until it is asked for (D15) */
.reason[data-source="history"] .reason__text {
  color: var(--text-faint);
}

/* ══ tool cards ════════════════════════════════════════════════════════════ */

.tool {
  border: 1px solid var(--border);
  border-inline-start-width: 3px;
  border-radius: var(--r-md);
  background: var(--surface);
  min-inline-size: 0;
  overflow: hidden;
}

/* flex, not grid: the head has a variable number of children (the ::before
   caret, the icon, the name, an optional origin badge, the summary, the status)
   and only the summary is elastic */
.tool__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  inline-size: 100%;
  min-block-size: var(--tap);
  padding: var(--sp-2) var(--sp-3);
  text-align: start;
}

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

.tool__icon {
  color: var(--text-muted);
}

.tool__head::before {
  content: "▸";
  color: var(--text-faint);
  font-size: var(--fs-xs);
  transition: transform var(--dur-fast) var(--ease-out);
}

.tool__head[aria-expanded="true"]::before {
  transform: rotate(90deg);
}

.tool__name {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  white-space: nowrap;
}

.tool__summary {
  flex: 1 1 auto;
  min-inline-size: 0;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tool__status {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  flex: none;
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  white-space: nowrap;
}

/* the seven verdicts. Colour is never the only signal: the markup carries an
   icon and a word, this only tints them. */
.tool[data-state="running"] {
  border-inline-start-color: var(--accent);
}

.tool[data-state="running"] .tool__status,
.tool__status[data-verdict="running"] {
  color: var(--accent);
}

.tool[data-state="ok"] {
  border-inline-start-color: var(--ok);
}

.tool__status[data-verdict="ok"] {
  color: var(--ok);
}

/* ask_user handed the turn to the human: something to act on, not a success */
.tool[data-state="waiting"] {
  border-inline-start-color: var(--info);
}

.tool__status[data-verdict="waiting"] {
  color: var(--info);
  font-weight: var(--fw-semibold);
}

.tool[data-state="error"] {
  border-inline-start-color: var(--danger);
  background: var(--danger-subtle);
}

.tool__status[data-verdict="error"] {
  color: var(--danger);
  font-weight: var(--fw-semibold);
}

.tool[data-state="held"] {
  border-inline-start-color: var(--warn);
  background: var(--warn-subtle);
}

.tool__status[data-verdict="held"] {
  color: var(--warn);
  font-weight: var(--fw-semibold);
}

.tool[data-state="notrun"],
.tool[data-state="interrupted"] {
  border-inline-start-color: var(--border-strong);
  background: var(--bg-subtle);
}

.tool[data-state="notrun"] .tool__name,
.tool[data-state="interrupted"] .tool__name {
  color: var(--text-muted);
}

.tool__status[data-verdict="notrun"],
.tool__status[data-verdict="interrupted"] {
  color: var(--text-faint);
}

/* the origin badge is real markup, not generated content: its word belongs to
   copy.js, and a badge CSS invented could not be translated or announced */
.tool--mcp .tool__icon {
  color: var(--info);
}

.tool__origin {
  flex: none;
  padding-inline: var(--sp-1);
  border: 1px solid var(--info);
  border-radius: var(--r-sm);
  background: var(--info-subtle);
  color: var(--info);
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}

.tool__body {
  padding: 0 var(--sp-3) var(--sp-3);
  border-block-start: 1px solid var(--border);
  padding-block-start: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-inline-size: 0;
}

.tool__input,
.tool__result {
  min-inline-size: 0;
}

/* §4.4's normative DOM has no element for these two words, so CSS supplies
   them — but steps aside the moment a view renders its own `.tool__label`,
   whose text can come from copy.js and be translated. */
.tool__input:not(:has(.tool__label))::before,
.tool__result:not(:has(.tool__label))::before,
.tool__label {
  display: block;
  margin-block-end: var(--sp-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-faint);
}

.tool__input:not(:has(.tool__label))::before {
  content: "Input";
}

.tool__result:not(:has(.tool__label))::before {
  content: "Result";
}

.tool__input pre,
.tool__result pre {
  margin: 0;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--code-border);
  border-radius: var(--r-sm);
  background: var(--code-bg);
  font-size: var(--fs-sm);
  line-height: var(--lh-base);
  white-space: pre;
  overflow: auto;
  overscroll-behavior: contain;
}

/* clamped to 14 lines until Show all (§4.3) */
.tool__result pre {
  max-block-size: calc(14 * 1lh + 2 * var(--sp-2));
}

.tool__result[data-expanded] pre {
  max-block-size: 60vh;
}

.tool__trunc {
  margin-block-start: var(--sp-1);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

.tool__more {
  align-self: flex-start;
  min-block-size: 28px;
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--r-sm);
  font-size: var(--fs-xs);
  color: var(--accent);
}

.tool__more:hover {
  background: var(--accent-subtle);
}

/* run_shell: the command reads the way it runs */
.tool__cmd {
  margin: 0;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--code-border);
  border-radius: var(--r-sm);
  background: var(--code-bg);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  white-space: pre;
  overflow-x: auto;
}

.tool__cmd::before {
  content: "$ ";
  color: var(--text-faint);
}

/* fetch_web: the host is the fact that matters */
.tool__host {
  font-weight: var(--fw-semibold);
}

.tool__url {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

.tool__foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-block-start: 1px solid var(--border);
  background: var(--bg-subtle);
}

/* a footer with nothing visible in it — a turn tool's hidden Why chip and no
   fix to offer — takes no room at any width (the ≤640 px rule below does the
   same for every collapsed card) */
.tool__foot:not(:has(> :not([hidden]))) {
  display: none;
}

/* ══ sub-agent panel ═══════════════════════════════════════════════════════ */

.subagent {
  margin-inline-start: var(--sp-4);
  padding: var(--sp-2) var(--sp-3);
  border-inline-start: 2px solid var(--border-strong);
  background: var(--bg-subtle);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: var(--fs-sm);
}

.subagent__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.subagent__slug {
  font-family: var(--font-mono);
  font-weight: var(--fw-medium);
}

.subagent__meta {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.subagent__note {
  margin-block-start: var(--sp-1);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

.subagent[data-status="running"] {
  border-inline-start-color: var(--accent);
}

.subagent[data-status="done"] {
  border-inline-start-color: var(--ok);
}

.subagent[data-status="failed"] {
  border-inline-start-color: var(--danger);
}

.subagent[data-status="aborted"],
.subagent[data-status="interrupted"] {
  border-inline-start-color: var(--border-strong);
  color: var(--text-muted);
}

/* ══ runtime notes — a band, never a chat bubble ═══════════════════════════ */

.note {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-inline-start-width: 3px;
  border-radius: var(--r-md);
  background: var(--bg-subtle);
  font-size: var(--fs-sm);
}

.note__kind {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}

.note__lead {
  margin: 0;
  overflow-wrap: anywhere;
}

.note__raw {
  grid-column: 1 / -1;
  margin-block-start: var(--sp-1);
}

.note__raw summary {
  cursor: pointer;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  min-block-size: 28px;
  padding-block: var(--sp-1);
}

.note__raw summary:hover {
  color: var(--text);
}

.note__raw pre {
  margin-block-start: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--code-border);
  border-radius: var(--r-sm);
  background: var(--code-bg);
  font-size: var(--fs-xs);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-block-size: 40vh;
  overflow: auto;
}

.note[data-kind="loop_detected"],
.note[data-kind="tool_errors"],
.note[data-kind="budget"] {
  border-color: var(--warn);
  border-inline-start-color: var(--warn);
  background: var(--warn-subtle);
}

.note[data-kind="loop_detected"] .note__kind,
.note[data-kind="tool_errors"] .note__kind,
.note[data-kind="budget"] .note__kind {
  color: var(--warn);
}

.note[data-kind="wrap_up"],
.note[data-kind="verification_gate"],
.note[data-kind="verification_run"] {
  border-color: var(--info);
  border-inline-start-color: var(--info);
  background: var(--info-subtle);
}

.note[data-kind="wrap_up"] .note__kind,
.note[data-kind="verification_gate"] .note__kind,
.note[data-kind="verification_run"] .note__kind {
  color: var(--info);
}

/* ══ plan ══════════════════════════════════════════════════════════════════ */

.plan {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-inline-size: 0;
}

.plan__step {
  display: grid;
  grid-template-columns: 1.4em minmax(0, 1fr);
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
}

.plan__mark {
  justify-self: center;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.plan__title {
  overflow-wrap: anywhere;
}

.plan__step[data-status="in_progress"] {
  background: var(--accent-subtle);
  font-weight: var(--fw-medium);
}

.plan__step[data-status="in_progress"] .plan__mark {
  color: var(--accent);
  animation: pulse 1.6s var(--ease-in-out) infinite;
}

.plan__step[data-status="done"] .plan__mark {
  color: var(--ok);
}

.plan__step[data-status="done"] .plan__title {
  color: var(--text-muted);
}

.plan__step[data-status="skipped"] .plan__title {
  text-decoration: line-through;
  color: var(--text-faint);
}

/* a step the last plan_update changed */
.plan__step[data-changed] {
  box-shadow: inset 2px 0 0 var(--info);
}

/* the plan's own note, set off from the steps it is about */
.plan__note {
  margin-block-start: var(--sp-3);
  padding-block-start: var(--sp-2);
  border-block-start: 1px solid var(--border);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* every row is one tap tall with its text centred in it, so the tinted
   in-progress step is the same box as the others instead of a band whose
   title sticks to its top edge */
.plan--list .plan__step {
  min-block-size: var(--tap);
  align-content: center;
}

/* the inspector's Plan head: the count, and the ? at the end of the row even
   while there is no count to show */
.plan__head > .btn--icon {
  margin-inline-start: auto;
}

/* ══ turn footer ═══════════════════════════════════════════════════════════ */

.turn__foot {
  position: relative;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding-block-start: var(--sp-1);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* "Read the answer" is visually hidden until it takes keyboard focus. Revealed,
   it overlays the footer row it lives in rather than inserting a line, so the
   thread does not jump under the reader who is tabbing through it (§5.5). */
.turn__read.vh:focus-visible {
  position: absolute !important;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 1;
  background: var(--surface);
}

.turn__gloss {
  color: var(--text);
}

.turn__sep {
  color: var(--text-faint);
}

/* a figure and the "·" in front of it wrap as one, so a row never ends on a
   dangling separator */
.turn__stat {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  white-space: nowrap;
}

.turn__copy {
  margin-inline-start: auto;
}

/* ══ question and approval cards ═══════════════════════════════════════════ */

.ask {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--info);
  border-radius: var(--r-lg);
  background: var(--info-subtle);
  box-shadow: var(--sh-1);
  min-inline-size: 0;
}

.ask__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--info);
}

.ask__q {
  margin: 0;
  max-inline-size: var(--measure);
  font-size: var(--fs-md);
  line-height: var(--lh-base);
  overflow-wrap: anywhere;
}

.ask__options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.ask__opt {
  min-block-size: var(--tap);
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  font-size: var(--fs-base);
  text-align: start;
  max-inline-size: 100%;
  overflow-wrap: anywhere;
}

.ask__opt:hover {
  border-color: var(--accent);
  background: var(--accent-subtle);
}

.ask__or {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

.ask__or::before,
.ask__or::after {
  content: "";
  flex: 1 1 auto;
  block-size: 1px;
  background: var(--border);
}

.ask__note {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.ask__actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.ask__binding {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-faint);
  margin-inline-end: auto;
}

/* the approval card: a different colour, a different shape, no free-text path */
.ask--confirm {
  border-color: var(--warn);
  border-inline-start-width: 4px;
  background: var(--warn-subtle);
}

.ask--confirm .ask__head {
  color: var(--warn);
}

/* the summary is attacker-influenced text: mono, verbatim, its own scroll */
.ask__cmd {
  margin: 0;
  padding: var(--sp-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  white-space: pre;
  overflow-x: auto;
}

/* a word whose Cyrillic or Greek letters pass for Latin ones (lib/safe.js
   mixedScriptTokens). The characters are left exactly as they are, so a copy
   copies what runs; the mark is a wavy underline — a shape, never colour
   alone — plus a title naming each lookalike letter. */
.lookalike {
  text-decoration-line: underline;
  text-decoration-style: wavy;
  text-decoration-color: var(--warn);
  text-decoration-thickness: 1px;
  text-decoration-skip-ink: none;
  text-underline-offset: 3px;
  cursor: help;
}

.ask[data-busy] {
  cursor: progress;
}

/* muted with tokens, not with opacity: §5.4 rule 5 rules out transparency */
.ask[data-busy] .ask__opt,
.ask[data-busy] .ask__actions .btn {
  pointer-events: none;
  background: var(--bg-subtle);
  border-color: var(--border);
  color: var(--text-faint);
}

.ask[data-stale] {
  border-color: var(--border-strong);
  background: var(--bg-subtle);
}

.ask[data-stale] .ask__head {
  color: var(--text-muted);
}

/* ══ composer ══════════════════════════════════════════════════════════════ */

.composer {
  flex: none;
  position: sticky;
  inset-block-end: 0;
  z-index: var(--z-sticky);
  padding-inline: var(--sp-4);
  padding-block: var(--sp-3);
  padding-block-end: max(var(--sp-3), env(safe-area-inset-bottom));
  border-block-start: 1px solid var(--border);
  background: var(--bg);
}

/* the composer is a stack. Every host above the input that holds something
   (Jump to latest, the notices, the Connect strip, the first-run strip, the
   question card) takes the input's column — 900 px, centred — and keeps a gap
   from what follows; the input's own host is the last child. The setup
   strip's host (below 720 px) ends in a spacer of its own. */
.composer > :not(:last-child):not(:has(.chat__setup)):has(> :not([hidden])) {
  inline-size: 100%;
  max-inline-size: 900px;
  margin-inline: auto;
  margin-block-end: var(--sp-2);
}

.composer__inner {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  inline-size: 100%;
  max-inline-size: 900px;
  margin-inline: auto;
  padding: var(--sp-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  background: var(--surface);
  transition: border-color var(--dur-fast) var(--ease-out);
}

.composer__inner:focus-within {
  border-color: var(--accent);
}

.composer__input {
  flex: 1 1 auto;
  min-inline-size: 0;
  min-block-size: calc(var(--rows) * 1lh);
  max-block-size: 40vh;
  padding: var(--sp-1) var(--sp-2);
  border: 0;
  background: none;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  resize: none;
  field-sizing: content;
  /* a message typed in Arabic or Hebrew runs right to left as it is typed,
     each paragraph by its own first strong character */
  unicode-bidi: plaintext;
  text-align: start;
}

.composer__input:focus-visible {
  outline: none;
}

.composer__input::placeholder {
  color: var(--text-faint);
}

.composer__input:disabled {
  color: var(--text-faint);
  cursor: not-allowed;
}

.composer__send {
  inline-size: var(--tap);
  block-size: var(--tap);
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--accent);
  border-radius: var(--r-md);
  background: var(--accent);
  color: var(--accent-fg);
}

.composer__send:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

.composer__send:disabled {
  background: var(--bg-inset);
  border-color: var(--border);
  color: var(--text-faint);
  cursor: not-allowed;
}

/* while a turn runs the same control is Stop; its accessible name changes too */
.composer__send[data-mode="stop"] {
  background: var(--surface);
  border-color: var(--danger);
  color: var(--danger);
}

.composer__send[data-mode="stop"]:hover {
  background: var(--danger-subtle);
}

.composer__foot {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  inline-size: 100%;
  max-inline-size: 900px;
  margin-inline: auto;
  padding-block-start: var(--sp-1);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

.composer__hint {
  flex: 1 1 auto;
  min-inline-size: 0;
}

.composer__count {
  font-variant-numeric: tabular-nums;
}

.composer__count[data-level="near"] {
  color: var(--warn);
}

.composer__count[data-level="over"] {
  color: var(--danger);
  font-weight: var(--fw-semibold);
}

/* a message typed before there was a model to answer it */
.composer__queued {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  inline-size: 100%;
  max-inline-size: 900px;
  margin-inline: auto;
  margin-block-end: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-md);
  background: var(--bg-subtle);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

@media (max-width: 640px) {
  .composer {
    padding-inline: var(--sp-3);
  }
}

/* ══ the empty chat: a centred composer and three examples ═════════════════ */

.newchat {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-4);
  min-block-size: 100%;
  inline-size: 100%;
  max-inline-size: 640px;
  margin-inline: auto;
  padding-inline: var(--sp-4);
  padding-block: var(--sp-7);
  text-align: center;
}

.newchat__examples {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-2);
}

.newchat__example {
  min-block-size: var(--tap);
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-full);
  background: var(--surface);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  max-inline-size: 100%;
  overflow-wrap: anywhere;
}

.newchat__example:hover {
  border-color: var(--accent);
  background: var(--accent-subtle);
  color: var(--text);
}

/* ══ the Connect strip (§3.6) ══════════════════════════════════════════════ */

.connect {
  inline-size: 100%;
  max-inline-size: 900px;
  margin-inline: auto;
  margin-block-end: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--accent);
  border-radius: var(--r-lg);
  background: var(--accent-subtle);
}

.connect__head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
}

.connect__providers {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.connect__provider {
  min-block-size: var(--tap);
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-full);
  background: var(--surface);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
}

.connect__provider[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-fg);
}

.connect__provider:disabled {
  color: var(--text-faint);
  cursor: not-allowed;
}

.connect__row {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.connect__row > .field {
  flex: 1 1 22ch;
}

/* in the composer the stack spaces the strip (.composer > …); elsewhere — the
   checklist on /welcome — its own margin still does */
.composer .connect {
  margin-block-end: 0;
}

/* an OpenAI-compatible model: its fields share one grid, so the last field
   never wraps onto a full-width row of its own. 24ch keeps every label on one
   line: four columns in the strip's 900 px, one on a phone. */
.connect__model {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 24ch), 1fr));
  gap: var(--sp-2);
  align-items: start;
}

/* a second model starts under a rule: where its fields wrap into three
   columns or one, its "Model id" otherwise sat 8 px under the first model's
   last field and read as a fifth field of the same model */
.connect__model + .connect__model {
  padding-block-start: var(--sp-3);
  border-block-start: 1px solid var(--border);
}

/* Remove (two models or more) ends the model's last row, level with its
   inputs, instead of taking a field's column and squeezing the labels */
.connect__model > .btn {
  grid-column: -2 / -1;
  justify-self: end;
  align-self: end;
}

/* a phone: the key field takes the whole width and Connect goes under it, so
   the placeholder is read whole instead of cut beside a disabled button */
@media (max-width: 560px) {
  .connect__row {
    flex-direction: column;
    align-items: stretch;
  }

  .connect__row > .field {
    flex: none;
  }
}

.connect__note {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* ══ the inspector ═════════════════════════════════════════════════════════ */

.inspector {
  display: flex;
  flex-direction: column;
  block-size: 100%;
  min-block-size: 0;
}

.inspector__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-block-end: 1px solid var(--border);
}

.inspector__title {
  flex: 1 1 auto;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-muted);
}

.inspector__body {
  flex: 1 1 auto;
  min-block-size: 0;
  display: flex;
  flex-direction: column;
}

.inspector__section + .inspector__section {
  margin-block-start: var(--sp-5);
}

.inspector__pre {
  margin: 0;
  padding: var(--sp-3);
  border: 1px solid var(--code-border);
  border-radius: var(--r-sm);
  background: var(--code-bg);
  font-size: var(--fs-xs);
  line-height: var(--lh-base);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-block-size: 50vh;
  overflow: auto;
}

/* ── the Activity ledger ─────────────────────────────────────────────────── */

.activity {
  list-style: none;
  display: flex;
  flex-direction: column;
}

.activity__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-2);
  inline-size: 100%;
  min-block-size: var(--tap);
  padding: var(--sp-2);
  border-block-end: 1px solid var(--border);
  text-align: start;
  font-size: var(--fs-sm);
}

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

.activity__kind {
  grid-column: 1 / -1;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-faint);
}

.activity__what {
  min-inline-size: 0;
  overflow-wrap: anywhere;
}

.activity__when {
  font-size: var(--fs-xs);
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.activity__row[data-verdict="error"] .activity__what,
.activity__row[data-verdict="denied"] .activity__what {
  color: var(--danger);
}

.activity__row[data-verdict="held"] .activity__what {
  color: var(--warn);
}

.activity__row[data-verdict="notrun"] .activity__what {
  color: var(--text-faint);
}

/* ══ narrow ════════════════════════════════════════════════════════════════ */

@media (max-width: 720px) {
  .thread {
    padding-inline: var(--sp-3);
  }

  .turn {
    gap: var(--sp-2);
    padding-block: var(--sp-4);
  }
}

@media (max-width: 640px) {
  /* §3.5's 360 wireframe: a collapsed tool card is ONE line —
     "▸ read_file main.go  142ms". The name keeps its width, the summary takes
     what is left and ellipsises, and the verdict is its glyph: the word is
     still in the text and in the head's accessible name, and the footer with
     the Why chip waits until the card is opened. */
  .tool__head {
    flex-wrap: nowrap;
    min-block-size: var(--tap);
  }

  .tool__name {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .tool__summary {
    flex: 1 1 0;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* run_shell keeps its own scroll box (§5.3): a command is never cut. Inside
     the one-line head the box is slimmer, so the head stays one tap tall. */
  .tool__summary.tool__cmd {
    overflow-x: auto;
    text-overflow: clip;
    white-space: pre;
    padding-block: var(--sp-1);
  }

  /* fetch_web: the host and the URL share the one line */
  .tool__summary .tool__url {
    display: inline;
    margin-inline-start: var(--sp-1);
  }

  .tool__status .tool__word,
  .tool__status .tool__time {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* collapsed: no Why chip, and no footer at all — unless the footer holds
     the fix for this very failure, which is the point of the card (§4.6) */
  .tool__head[aria-expanded="false"] ~ .tool__foot .chip--why {
    display: none;
  }

  .tool__head[aria-expanded="false"] ~ .tool__foot:not(:has(.tool__fix:not([hidden]), .tool__retry)) {
    display: none;
  }

  /* the turn footer is one wrapping row: the stop chip and the numbers, and
     Copy answer as a compact control at the end of the row. The row does not
     grow to a 44 px button; the button's hit area still reaches 44 px (§5.3)
     through ::after, over the row's own padding. */
  .turn__foot {
    gap: var(--sp-1) var(--sp-2);
    padding-block-start: 0;
  }

  .turn__foot .turn__copy {
    min-block-size: 28px;
    margin-inline-start: auto;
    padding-block: 0;
    padding-inline: var(--sp-2);
    font-size: var(--fs-sm);
  }

  .turn__foot .turn__copy::after {
    content: "";
    position: absolute;
    inset-block: -8px;
    inset-inline: 0;
  }
}
