agent-manager-template / web /src /conversation.css
Agent Manager
terminal ⇄ conversation: one switch, in the bottom bar, and a better answer rule
a5d1eab
Raw
History Blame
11.5 kB
/* The conversation grammar (docs/conversation-view.md §4.3), shared by the
Overview card and the pane's RENDER mode. App tokens only — --panel, --border,
--accent, --muted, --font-mono. Nothing terminal-flavoured: no --term-bg, no
uppercase role pills, no per-row chips. */
/* ---------- one exchange ---------- */
/* padding-left is the gutter the prompt's ❯ hangs into. Everything else —
answer, work, fold control — starts at the content edge, so the arrow is the
only mark outside the column and turns are findable while scrolling. */
.cx { display: flex; flex-direction: column; gap: 7px; min-width: 0; padding: 2px 0 2px 16px; }
.cx.dim { opacity: 0.72; }
.cx.dim .cx-answer { -webkit-line-clamp: 6; }
/* one meta row, under the prompt: the work on the left, which turn on the right.
Nothing sits above the prompt any more. */
.cx-meta {
display: flex; align-items: baseline; gap: 8px; min-width: 0;
font-size: 11px; color: var(--muted);
}
.cx-meta .spacer { flex: 1; min-width: 4px; }
.cx-n, .cx-time, .cx-model { flex: none; font-variant-numeric: tabular-nums; }
.cx-n { color: color-mix(in srgb, var(--accent) 65%, var(--muted)); }
.cx-model { opacity: 0.8; }
/* the prompt: a lightly tinted band between hairlines, with the chevron hanging
in the gutter — what your eye lands on when scrolling a long conversation */
.cx-prompt {
position: relative; margin-left: -16px; padding: 6px 10px 7px 16px;
background: color-mix(in srgb, var(--accent) 7%, transparent);
border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
font-size: 13px; font-weight: 550; color: var(--text);
white-space: pre-wrap; overflow-wrap: break-word;
}
.cx-prompt::before {
content: '❯'; position: absolute; left: 3px; top: 6px;
font-family: var(--font-mono); color: var(--accent); font-weight: 700;
}
/* the fold control names what it hides — never a bare caret */
.cx-fold {
display: inline-flex; align-items: baseline; gap: 6px; min-width: 0;
background: none; border: none; padding: 0; margin: 0;
font: inherit; color: var(--muted); cursor: pointer; text-align: left;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cx-fold.flat { cursor: default; padding-left: 19px; }
.cx-fold:hover { color: var(--text); }
.cx-fold.on { color: var(--text); }
.cx-fold .cs-tri { color: var(--muted); }
.cx-fold.on .cs-tri { color: var(--accent); }
/* ---------- the work: a rail of one-line steps ---------- */
.cx-steps { display: flex; flex-direction: column; padding: 1px 0; }
.cs { min-width: 0; }
.cs-head {
display: flex; align-items: baseline; gap: 6px; width: 100%; min-width: 0;
background: none; border: none; padding: 2px 4px 2px 0; margin: 0;
font: inherit; font-size: 12px; color: var(--text); text-align: left; cursor: pointer;
border-radius: var(--r-sm);
}
.cs-head:hover:not(:disabled) { background: color-mix(in srgb, var(--border) 45%, transparent); }
.cs-head:disabled { cursor: default; }
/* one column, two meanings: a tool reports its outcome, everything else offers
to open. Greyed triangle = nothing more to see. */
.cs-tri, .cs-mark {
flex: none; width: 13px; font-size: 10px; line-height: 1.6;
font-family: var(--font-mono); color: var(--muted);
}
.cs-tri.off { color: color-mix(in srgb, var(--border-strong) 65%, transparent); }
.cs-mark { font-size: 11px; }
.cs-mark.ok { color: color-mix(in srgb, var(--ok, #4b9e6a) 85%, var(--muted)); }
.cs-mark.bad { color: var(--danger, #c05353); }
.cs-label { flex: none; font-size: 11px; font-weight: 600; color: var(--muted); }
.cs.tools .cs-label { color: color-mix(in srgb, var(--accent) 70%, var(--muted)); }
.cs.think .cs-label { color: #8b73c4; }
.cs-detail {
min-width: 0; flex: 1; font-size: 11.5px; color: var(--muted);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* expanded in place: same font, same colour, just no longer cut */
.cs-detail.full { white-space: pre-wrap; overflow: visible; text-overflow: clip; overflow-wrap: break-word; }
.cs.note .cs-detail { color: var(--text); opacity: 0.78; }
.cs-more { font-size: 10px; color: var(--muted); padding: 2px 0 0; }
.cs-body { padding: 2px 0 6px 13px; }
.cs-pre {
white-space: pre-wrap; word-break: break-word; margin: 3px 0; padding: 6px 8px;
background: var(--panel-2); border-radius: var(--r-sm);
font-family: var(--font-mono); font-size: 11px; line-height: 1.5;
max-height: 20rem; overflow: auto;
}
.cs-pre.out { color: var(--muted); }
.cs-pre.out.bad {
border: 1px solid color-mix(in srgb, var(--danger, #c05353) 55%, transparent);
background: color-mix(in srgb, var(--danger, #c05353) 7%, var(--panel-2));
}
.cs-pre.think { color: color-mix(in srgb, #8b73c4 70%, var(--text)); }
.cs-img { max-width: 100%; max-height: 18rem; border-radius: var(--r-sm); }
/* ---------- the answer: the one thing written for the reader ---------- */
.cx-answer { min-width: 0; }
.markdown.cx-md { border: none; background: none; padding: 0; font-size: 12.5px; line-height: 1.55; }
.cx-md > :first-child { margin-top: 0; }
.cx-md > :last-child { margin-bottom: 0; }
.cx-md pre { font-size: 11px; }
.cx-note { font-size: 10.5px; color: var(--muted); padding-top: 4px; }
.cx-running {
display: flex; align-items: baseline; min-width: 0; font-size: 12.5px; color: var(--muted);
}
.cx-running-at { margin-left: 7px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: 0.85; }
.cx-running::before {
content: '⠋'; display: inline-block; width: 1.2em; color: var(--accent);
animation: ov-spin 0.9s steps(1) infinite;
}
/* ---------- card: history grows upward, one exchange at a time ---------- */
.cx-earlier { display: flex; align-items: center; justify-content: center; gap: 12px; font-size: 11px; }
.cx-earlier-btn {
background: none; border: none; padding: 0; font: inherit; font-size: 10.5px;
color: var(--accent); cursor: pointer;
}
.cx-earlier-btn:hover { text-decoration: underline; }
.cx-earlier-n { color: var(--muted); }
.cx-earlier-note { color: var(--muted); }
/* ---------- search hits ---------- */
mark.cx-hit {
background: color-mix(in srgb, var(--accent) 28%, transparent);
color: inherit; border-radius: 2px; padding: 0 1px;
}
mark.cx-hit.on { background: var(--accent); color: var(--panel); }
/* ---------- RENDER mode: the same thing, stacked ---------- */
.cxv { display: flex; flex-direction: column; min-height: 0; }
.cxv-bar {
/* wraps at ANY width, not behind a media query: a pane is a container, and
a 390px pane on a desktop never triggers a viewport media query */
display: flex; align-items: center; gap: 7px 8px; flex: none; flex-wrap: wrap;
padding: 5px 9px; background: var(--panel-2); border-bottom: 1px solid var(--border);
font-size: 10.5px; color: var(--muted);
}
.cxv-bar .spacer { flex: 1; }
.cxv-chip { padding: 0 5px; border: 1px solid var(--border); border-radius: var(--r-sm); white-space: nowrap; }
.cxv-count, .cxv-tok { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
.cxv-tok { flex: 0 1 auto; }
.cxv-mini {
flex: none; white-space: nowrap; background: none; border: 1px solid transparent; border-radius: var(--r-sm);
padding: 1px 5px; font: inherit; font-size: 10.5px; color: var(--muted); cursor: pointer;
}
.cxv-mini:hover { color: var(--text); border-color: var(--border); }
.cxv-mini.on { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.cxv-nav { display: inline-flex; gap: 2px; }
.cxv-hits { flex: none; font-variant-numeric: tabular-nums; color: var(--muted); }
.cxv-search {
flex: 1 1 7rem; width: auto; min-width: 4.5rem; max-width: 22rem;
padding: 2px 6px; font: inherit; font-size: 11px;
background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: var(--r-sm);
}
/* Panel background, and a column that FILLS the pane. A fixed reading width
left a gutter of nothing on each side while the prompt band — which is what
you scan for — still spanned the full width, so the two disagreed about where
the conversation began. The pane is the measure: make it narrow and the
conversation is narrow. */
.cxv-body { flex: 1; min-height: 0; overflow-y: auto; background: var(--panel); padding: 4px 14px 30px; }
.cxv-col { display: flex; flex-direction: column; min-width: 0; }
.cxv-msg { font-size: 11px; color: var(--muted); padding: 6px 0; }
.cxv-foot {
display: flex; align-items: center; gap: 8px; flex: none;
padding: 5px 10px; border-top: 1px solid var(--border); background: var(--panel);
color: var(--muted); font-size: 10.5px; overflow: hidden;
}
.cxv-foot .cxv-path { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cxv-foot .spacer { flex: 1; min-width: 4px; }
/* the prompt band sticks: deep inside a long turn, the thing you want overhead
is what you asked for — not a row of numbers */
.cxv-col .cx-prompt {
position: sticky; top: 0; z-index: 2;
background: color-mix(in srgb, var(--accent) 7%, var(--panel));
}
/* ---------- phone ---------- */
@media (max-width: 720px) {
.cxv-body { padding: 4px 8px 24px; }
.cs-detail { font-size: 12px; }
}
/* ---------- conversation mode inside a session pane ---------- */
/* Drawn over the live terminal, which stays mounted underneath. */
.pane-render { position: absolute; inset: 0; z-index: 3; display: flex; background: var(--panel); }
.pane-render > .cxv { flex: 1; min-width: 0; }
.cxv-empty { margin: auto; padding: 24px; font-size: 11.5px; color: var(--muted); text-align: center; }
.ph-modes { flex: none; }
.ph-modes button { padding: 1px 7px; font-size: 9.5px; letter-spacing: 0.06em; }
/* The overlay needs a positioned host; .term-host is otherwise plain. */
.slot .term-host { position: relative; }
/* ---------- the card inline in the Overview list ---------- */
/* There it is a summary, not a room: one turn, the answer clamped. The window
(and RENDER mode) is where a conversation gets to be long. */
.ov-card.ov-compact .cx-answer .markdown {
display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
}
/* ---------- an expanded tool call ---------- */
.cs-call { display: flex; flex-direction: column; }
.ct-cap { font-size: 10.5px; color: var(--muted); padding: 3px 0 1px; overflow-wrap: anywhere; }
.ct-note { font-size: 11px; color: var(--muted); padding: 1px 0 2px; }
.cs-pre.ct-cmd { color: var(--text); }
.cs-pre.ct-cmd::before { content: '$ '; color: var(--accent); }
/* a before and an after — tinted, not barred */
.cs-pre.ct-was { background: color-mix(in srgb, var(--danger, #c05353) 8%, var(--panel-2)); }
.cs-pre.ct-now { background: color-mix(in srgb, var(--ok, #4b9e6a) 9%, var(--panel-2)); }
.ct-fields { margin: 3px 0 0; font-size: 11px; }
.ct-row { display: grid; grid-template-columns: minmax(4.5rem, auto) 1fr; gap: 8px; padding: 1px 0; align-items: baseline; }
.ct-row dt { color: var(--muted); }
.ct-row dd { margin: 0; min-width: 0; color: var(--text); overflow-wrap: anywhere; }
.ct-row dd .cs-pre { margin: 2px 0; }
/* The reply line under a rendered conversation — the card's own composer, so
answering an agent looks the same wherever you are reading it. */
.cxv-live { flex: none; padding: 6px 12px; border-top: 1px solid var(--border); background: var(--panel); }
.cxv-note { flex: none; padding: 0 12px 6px; }