/* The transcript: one reading column of prompts (a flat fill) and answers
 * (uncontained words), markdown, markers and notices, and each turn's time,
 * Copy and code-block Copy, which come in once its run settles. A run's
 * Trace group (steps, interim words, delegates): trace.css; a failure: failure.css. */

.transcript-wrap { position: relative; flex: 1; min-height: 0; display: flex; }
.transcript {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  padding: var(--sv-space-6) max(var(--sv-space-5), calc(50% - var(--reading) / 2)) var(--sv-space-8);
}
.transcript > * + * { margin-top: var(--sv-space-4); }
.transcript > .turn-user + .turn-user, .transcript > .turn-agent + .turn-agent { margin-top: var(--sv-space-2); }
.transcript > .trace + .trace { margin-top: 2px; }
.transcript > .turn-user + .trace,
.transcript > .trace + .turn-agent { margin-top: var(--sv-space-3); }
/* tool rows line up with the bubble column */
.transcript > .trace { margin-left: 36px; }
.transcript > .empty {
  color: var(--sv-ink-secondary);
  margin: auto;
  max-width: 24rem;
  text-align: center;
  display: grid;
  justify-items: center;
  gap: var(--sv-space-3);
}

.transcript > .empty p { margin: 0; }
.jump {
  position: absolute;
  bottom: var(--sv-space-4);
  left: 50%;
  transform: translateX(-50%);
  background: var(--sv-ink);
  color: var(--sv-surface);
  border: 0;
  border-radius: 999px;
  min-height: 32px;
  padding: 0 var(--sv-space-4);
  box-shadow: 0 8px 32px rgb(0 0 0 / 0.18);
  animation: sv-enter-pop var(--sv-dur-fast) var(--sv-ease-out) both;
}

/* live entrances — history paints still ([data-hydrating] while it lands,
 * [data-hydrated] on what was already there once the guard lifts) */
.turn-user, .turn-agent, .tool, .trace, .marker, .notice, .retry-note {
  animation: sv-enter-msg var(--sv-dur-base) var(--sv-ease-out) both;
}
[data-hydrated] { animation: none !important; }

/* Member prompt: a flat fill one step darker than the page, on the right. */
.turn-user {
  margin-left: auto;
  width: fit-content;
  max-width: min(80%, 36rem);
  background: var(--sv-fill-2);
  color: var(--sv-ink);
  padding: 10px 14px;
  border-radius: 16px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.turn-user .text { white-space: pre-wrap; }
.turn-user .turn-image { display: block; max-width: 100%; max-height: 20rem; border-radius: var(--sv-radius); margin-bottom: var(--sv-space-2); }
/* A file the message carried (format.js attachedFile): its name, not the pointer the model reads. */
.turn-user .turn-file { width: fit-content; max-width: 100%; margin-bottom: var(--sv-space-2); padding: var(--sv-space-1) var(--sv-space-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--ui-meta); background: var(--sv-surface-sunken); border: var(--sv-hairline-w) solid var(--sv-hairline); border-radius: var(--sv-radius); }
/* Who sent it (people.js), in a chat with someone else in it: their face at
 * the bubble's foot on the right, mirroring Share's mark on the left of an
 * answer. A chat only you write in shows none. */
.turn-user > .turn-face { display: none; }
/* Every prompt keeps the face's column, so a sending one does not shift when it lands. */
.transcript[data-together] .turn-user { margin-right: 32px; }
.transcript[data-together] .turn-user > .turn-face { display: inline-flex; position: absolute; right: -33px; bottom: -1px; cursor: default; }

/* Answer: words on the page, no container, in a reading column. The mark
 * sits beside the first line; the actions hang underneath in meta size.
 * The run's line and its rows share the words' column. */
.turn-agent {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  column-gap: 10px;
  align-items: start;
  max-width: min(100%, 46rem);
}
.turn-agent .who {
  grid-column: 1;
  grid-row: 2;
  align-self: start;
  width: 26px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0; /* the name is the title; the mark is the face */
}
/* Fixed rows, so DOM order never moves the avatar. */
.turn-agent > :not(.who) { grid-column: 2; }
.turn-agent .text { grid-row: 2; }
.turn-agent .turn-stop { grid-row: 3; }
.turn-agent .turn-tools { grid-row: 4; }
.turn-agent .text {
  justify-self: start;
  max-width: 100%;
  color: color-mix(in srgb, var(--sv-ink) 90%, var(--sv-surface));
  line-height: 1.6;
}
/* The composer is the one raised plate (the page's lightest fill, no edge);
 * a report's body is a well one fill step off the page. No glass: blur, rims,
 * sheens and cast shadows are gone (Rey, 2026-10-28: contrast from fill). */
.composer { border: 1px solid transparent; background: var(--sv-surface-raised); }
.chat-report-body { background: var(--sv-fill-2); }
.transcript-wrap { background: var(--sv-surface); }
.turn-agent .turn-stop { margin-top: var(--sv-space-1); padding-left: var(--sv-space-1); color: var(--sv-ink-tertiary); font-size: var(--ui-meta); }
.who-mark {
  /* Explicit box (16px tall at the mark's 828.3:933.4 ratio): engines
   * disagree on width:auto for a <use>d symbol, and the box is edge-tight. */
  height: 18px;
  width: 16px;
  overflow: visible;
  flex: none;
  fill: currentColor;
  stroke: none;
  color: var(--sv-brand-ink);
}
.text { overflow-wrap: anywhere; }
.text > :first-child { margin-top: 0; }
.text > :last-child { margin-bottom: 0; }
.text p { margin: var(--sv-space-2) 0; }
.text h3, .text h4, .text h5, .text h6 {
  margin: var(--sv-space-4) 0 var(--sv-space-1);
  line-height: var(--sv-leading-heading);
  font-size: var(--sv-text-body);
  font-weight: 600;
}
.text ul, .text ol { margin: var(--sv-space-2) 0; padding-left: var(--sv-space-5); }
.text li { margin: 3px 0; }
.text blockquote {
  margin: var(--sv-space-2) 0;
  padding-left: var(--sv-space-3);
  border-left: 2px solid var(--sv-hairline-strong);
  color: var(--sv-ink-secondary);
}
.text hr { border: 0; border-top: var(--sv-hairline-w) solid var(--sv-hairline); }
.text a { color: inherit; text-underline-offset: 0.15em; }
.text code {
  font-family: var(--sv-font-mono);
  font-size: 0.875em;
  background: var(--sv-surface-sunken);
  border-radius: 4px;
  padding: 0.1em 0.35em;
}
.text pre.code {
  margin: var(--sv-space-3) 0;
  padding: var(--sv-space-3);
  background: var(--sv-surface-sunken);
  border: var(--sv-hairline-w) solid var(--sv-hairline);
  border-radius: var(--sv-radius);
  overflow-x: auto;
  position: relative;
}
.text pre.code[data-lang]::before {
  content: attr(data-lang);
  position: absolute;
  top: var(--sv-space-1);
  right: var(--sv-space-2);
  color: var(--sv-ink-tertiary);
  font-size: 0.75rem;
  font-family: var(--sv-font-sans);
}
.text pre.code code { background: none; padding: 0; border-radius: 0; font-size: 0.8125rem; white-space: pre; }
/* A wide table scrolls in its box (md.js), never the page; keyboard users scroll it too. */
.text .table-wrap { margin: var(--sv-space-3) 0; max-width: 100%; overflow-x: auto; }
.text .table-wrap:focus-visible { outline: var(--sv-hairline-w) solid var(--sv-ink-tertiary); outline-offset: 2px; }
.text table { border-collapse: collapse; margin: 0; font-size: var(--ui-text); }
/* Cells wrap at words, never mid-word (the chat's overflow-wrap:anywhere
 * would let a long column squeeze the rest to a letter per line). md.js
 * names each column's shape: tight ones (codes, times, numbers) stay on one
 * line; prose keeps a reading width; a table too wide scrolls in its box. */
.text td, .text th { overflow-wrap: normal; word-break: normal; min-width: 4ch; vertical-align: top; }
.text :is(td, th).md-col-tight { white-space: nowrap; }
.text :is(td, th).md-col-prose { min-width: min(18rem, 70vw); overflow-wrap: break-word; }
.text th:not(.md-col-prose) { white-space: nowrap; }
.text del { color: var(--sv-ink-secondary); }
.text li > :is(ul, ol) { margin: 2px 0; }
.text li.task { list-style: none; margin-left: calc(-1 * var(--sv-space-4)); }
.text li.task > input { margin: 0 0.4em 0 0; vertical-align: -0.1em; }
.text th, .text td {
  border: var(--sv-hairline-w) solid var(--sv-hairline);
  padding: var(--sv-space-1) var(--sv-space-3);
  text-align: left;
}
.text th { background: var(--sv-surface-sunken); font-weight: 500; }

/* the breathing cursor while the answer streams: after the last words, not
 * on a line of its own under a list or table */
.text.streaming > :is(p, h3, h4, h5, h6):last-child::after,
.text.streaming > :is(ul, ol):last-child > li:last-child::after {
  content: "●";
  font-size: 0.6em;
  margin-left: 0.35em;
  color: var(--sv-ink-secondary);
  animation: sv-caret var(--pulse) var(--sv-ease-inout) infinite;
}
/* An answer with no words yet shows nothing: the run's line says what is
 * happening. Its words enter with the first of them (leaving display:none
 * starts the animation), and the mark fades in beside them. */
.turn-agent .text:empty { display: none; }
.turn-agent > .text { animation: sv-enter-msg var(--sv-dur-base) var(--sv-ease-out) both; }
.turn-agent .who { transition: opacity var(--sv-dur-base) var(--sv-ease-out); }
.turn-agent:has(.text:empty) .who { opacity: 0; }

/* per-turn receipt (model · duration): a quiet part of the action row */
.turn-meta {
  display: inline-flex;
  gap: var(--sv-space-3);
  padding: 0 var(--sv-space-1);
  font-variant-numeric: tabular-nums;
}
.turn-model { display: inline-flex; align-items: center; gap: var(--sv-space-1); }

/* A company's logo (dom.js vendorLogo): a model's, or the channel a message came
 * by (home.js slackTurn): a one-colour mask in the text's ink, so it stays as
 * quiet as the words beside it. */
.model-logo {
  display: inline-block;
  flex: none;
  width: 12px;
  height: 12px;
  margin-right: var(--sv-space-1);
  vertical-align: -1px;
  background: currentColor;
  -webkit-mask: center / contain no-repeat;
  mask: center / contain no-repeat;
}
.turn-model > .model-logo, .billing-limits > .model-logo { margin-right: 0; }
.model-logo.openai { -webkit-mask-image: url("assets/openai.svg"); mask-image: url("assets/openai.svg"); }
.model-logo.anthropic { -webkit-mask-image: url("assets/anthropic.svg"); mask-image: url("assets/anthropic.svg"); }
.model-logo.google { -webkit-mask-image: url("assets/google-g.png"); mask-image: url("assets/google-g.png"); }
.model-logo.meta { -webkit-mask-image: url("assets/meta.svg"); mask-image: url("assets/meta.svg"); }
.model-logo.zai { -webkit-mask-image: url("assets/zai.svg"); mask-image: url("assets/zai.svg"); }
.model-logo.kimi { -webkit-mask-image: url("assets/kimi.svg"); mask-image: url("assets/kimi.svg"); }
.model-logo.deepseek { -webkit-mask-image: url("assets/deepseek.svg"); mask-image: url("assets/deepseek.svg"); }
.model-logo.slack { -webkit-mask-image: url("assets/slack.svg"); mask-image: url("assets/slack.svg"); }
.model-logo.whatsapp { -webkit-mask-image: url("assets/whatsapp.svg"); mask-image: url("assets/whatsapp.svg"); }

.marker { color: var(--sv-ink-tertiary); font-size: var(--ui-meta); text-align: center; }
/* A run stopped before it said anything: its line says "You stopped after…"; the marker stays only for rungroup.js to read. */
.transcript > .marker.stopped { display: none; }
/* A message sent from Slack (home.js slackTurn): where it came from, the thread so far folded. */
.turn-via { display: flex; align-items: center; gap: var(--sv-space-1); margin-top: var(--sv-space-1); color: var(--sv-ink-tertiary); font-size: var(--ui-meta); }
.turn-via > .model-logo { width: 13px; height: 13px; margin-right: 0; }
.slack-thread { margin-top: var(--sv-space-1); color: var(--sv-ink-secondary); font-size: var(--ui-meta); }
.slack-thread summary { cursor: pointer; color: var(--sv-ink-tertiary); }
.slack-thread-line { padding: 2px 0 0 var(--sv-space-2); white-space: pre-wrap; }

/* Share's welcome-back brief: a quiet line where the system input would be. */
.marker.brief { margin: 1.5rem 0 0.25rem; }
/* a long chat opens on its newest turns; this fetches the ones before */
button.older { align-self: center; color: var(--sv-ink-tertiary); font-size: var(--ui-meta); }
button.older:disabled { cursor: progress; }
.notice { color: var(--sv-danger); font-size: var(--ui-text); }
.transcript > :is(.notice, .turn-error) { margin-left: 36px; }
@media (max-width: 760px) { .transcript > :is(.notice, .turn-error) { margin-left: 0; } }
.retry-note { color: var(--sv-attention); font-size: var(--ui-text); }
/* A send refused for want of a subscription (send.js subscriptionNeeded): not
 * a fault, a step to take, so ink on a neutral fill rather than danger, with
 * its ways on. No border: the fill is the contrast. */
.notice.sub-needed {
  display: grid;
  gap: var(--sv-space-2);
  padding: var(--sv-space-3) var(--sv-space-4);
  border-radius: 12px;
  background: color-mix(in srgb, var(--sv-ink) 5%, var(--sv-surface));
  color: var(--sv-ink);
}
.sub-needed-text { overflow-wrap: anywhere; }
.sub-needed-actions { display: flex; flex-wrap: wrap; gap: var(--sv-space-2); }
.sub-needed-actions button.primary { min-height: 30px; padding: 0 var(--sv-space-3); }
@media (max-width: 760px), (hover: none) and (pointer: coarse) {
  .sub-needed-actions button.primary, .sub-needed-actions button.ghost { min-height: 44px; }
}

@media (max-width: 760px) {
  .transcript { padding-left: var(--sv-space-4); padding-right: var(--sv-space-4); }
  .turn-user { max-width: 88%; }
}

/* Per-turn time + Copy. An answer's come in only once its run settles
 * (rungroup.js: data-unsettled until then), never while it streams; then
 * they stay in view under the latest answer and show on hover or focus
 * under older ones and under prompts; on touch, always. */
.turn-tools {
  display: flex;
  flex-wrap: wrap; /* the largest iOS text sizes: its items wrap, the column never scrolls sideways */
  align-items: center;
  gap: var(--sv-space-1);
  color: var(--sv-ink-tertiary);
  font-size: var(--ui-meta);
  line-height: 1;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 200ms var(--sv-ease-out);
}
:is(.turn-user, .turn-agent):is(:hover, :focus-within) > .turn-tools,
.transcript > .turn-agent:nth-last-child(1 of .turn-agent) > .turn-tools { opacity: 1; }
.turn-agent[data-unsettled] > .turn-tools { opacity: 0 !important; visibility: hidden; transition: none; }
.turn-tools .turn-time { font-variant-numeric: tabular-nums; padding: 0 var(--sv-space-1); }
/* A plain answer's settled mark (its run line folded away: trace.css). */
.trace.tr-empty[data-state="done"] + .turn-agent .turn-time::before { content: "✓ "; color: var(--ws-working-ink); }
.turn-tools button.ghost { min-height: 24px; color: var(--sv-ink-tertiary); font-size: var(--ui-meta); }
.turn-tools button.ghost:hover { color: var(--sv-ink); }
.turn-agent > .turn-tools { margin-top: var(--sv-space-1); margin-left: calc(-1 * var(--sv-space-1)); }
/* Beside the bubble, bottom-aligned, as v1's member row placed its actions. */
.turn-user { position: relative; }
.turn-user > .turn-tools { position: absolute; right: 100%; bottom: 0; padding-right: var(--sv-space-2); }
/* Sent, not yet committed: the same bubble, a shade quieter. */
.turn-user.pending { opacity: 0.6; }
/* Waiting for Share (outbox.js): the words stay quiet, the note and Cancel don't. */
.turn-user.pending.queued { opacity: 1; }
.turn-user.queued > :not(.queued-note) { opacity: 0.6; }
.queued-note { display: flex; align-items: center; justify-content: flex-end; gap: var(--sv-space-2); margin-top: var(--sv-space-1); color: var(--sv-attention); font-size: var(--ui-meta); }
.queued-note button.ghost { min-height: 24px; padding: 0 var(--sv-space-2); font-size: var(--ui-meta); }

/* Code blocks: Copy takes the language label's corner while it shows. */
.text pre > .code-copy {
  position: absolute;
  top: var(--sv-space-1);
  right: var(--sv-space-1);
  min-height: 24px;
  padding: 0 var(--sv-space-2);
  color: var(--sv-ink-secondary);
  background: var(--sv-surface);
  border: var(--sv-hairline-w) solid var(--sv-hairline);
  border-radius: calc(var(--sv-radius) * 0.75);
  font: 500 var(--ui-meta) / 1 var(--sv-font-sans);
  opacity: 0;
  transition: opacity var(--sv-dur-fast) var(--sv-ease-out);
}
.text pre > .code-copy:hover { color: var(--sv-ink); background: var(--ws-hover); }
.text pre:is(:hover, :focus-within) > .code-copy { opacity: 1; }
.text pre.code:has(> .code-copy):is(:hover, :focus-within)::before { visibility: hidden; }

@media (hover: none) {
  .turn-tools, .text pre > .code-copy { opacity: 1; }
  .text pre.code:has(> .code-copy)::before { visibility: hidden; }
}
/* No room beside a narrow bubble: the row sits inside it, under the text. */
@media (hover: none), (max-width: 760px) {
  .turn-user > .turn-tools { position: static; justify-content: flex-end; margin-top: var(--sv-space-1); padding-right: 0; }
}
