fix(desktop): one weight and one gap for transcript scaffolding

The scaffold rows shared a colour but not a weight: tool summaries and the
ticker rendered medium against the reply's normal-weight prose, which read
as emphasis on the quietest lines in the column.

Spacing had the matching problem. The block-gap rule listed which *pairs* of
blocks qualified, so the live status line — neither tool, thinking, nor
prose — fell through every branch onto its own half-size margin. And because
a streaming turn is sealed into several bubbles as it goes but rehydrates
into fewer, two blocks are siblings inside one bubble or split across two
depending on when you look; the flex gap between bubbles is half the block
gap, so the rhythm tightened and relaxed as a turn settled. Cover every
top-level block with one rule, keep prose-to-prose on paragraph rhythm, and
top the between-bubble gap up to match.
This commit is contained in:
Brooklyn Nicholson 2026-07-27 19:35:04 -05:00
parent 46df6ca705
commit 7a10e48e2f
3 changed files with 21 additions and 12 deletions

View file

@ -234,7 +234,7 @@ export const StreamStallIndicator: FC = () => {
}
return (
<StatusRow className="mt-1.5" data-slot="aui_stream-stall" label={hint || 'Hermes is thinking'}>
<StatusRow data-slot="aui_stream-stall" label={hint || 'Hermes is thinking'}>
<span aria-hidden="true" className="dither inline-block size-3 rounded-[2px] text-midground/80 animate-pulse" />
{hint && <HintText>{hint}</HintText>}
<ActivityTimerText seconds={elapsed} />

View file

@ -13,7 +13,7 @@ import { DisclosureRow } from '@/components/chat/disclosure-row'
* different kinds of line for what is one kind of thing.
*/
export const SCAFFOLD_LABEL_CLASS =
'text-[length:var(--conversation-tool-font-size)] font-medium leading-(--conversation-line-height) text-(--conversation-scaffold-text)'
'text-[length:var(--conversation-tool-font-size)] leading-(--conversation-line-height) text-(--conversation-scaffold-text)'
/** Durations, counts and diff stats trailing a scaffold label. */
export const SCAFFOLD_META_CLASS = 'shrink-0 text-[0.625rem] tabular-nums text-(--conversation-scaffold-meta)'

View file

@ -1501,24 +1501,33 @@ text-* variant utilities. */ .btn-arc {
/* Conversation block rhythm. assistant-ui renders each range as a direct child
of the message content with no per-part wrapper, so adjacency rules cover
every pairing first block needs no reset, nested tool rows are untouched.
Two tiers: scaffolding (tool / thinking) gets a roomy block gap so it reads
as separate from the reply; consecutive prose collapses to a tight paragraph
rhythm so split-out text parts don't look like a big gap. */
/* Scaffolding adjacent to anything → roomy block gap. */
One gap between top-level blocks, whatever they are. Spelling out which
*pairs* qualified meant the live status line (not tool, thinking or prose)
fell through every branch and carried its own half-size margin instead. */
[data-slot='aui_assistant-message-content']
> :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'])
+ :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], .aui-md),
[data-slot='aui_assistant-message-content']
> .aui-md
+ :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure']) {
> :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], [data-slot='aui_stream-stall'], .aui-md)
+ :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], [data-slot='aui_stream-stall'], .aui-md) {
margin-top: var(--turn-block-gap);
}
/* Prose ↔ prose → tight paragraph rhythm, matching in-block paragraph spacing. */
/* Except prose prose: one reading column that happens to arrive as several
parts, so it keeps the in-block paragraph rhythm. Same specificity as the
rule above and deliberately after it. */
[data-slot='aui_assistant-message-content'] > .aui-md + .aui-md {
margin-top: var(--paragraph-gap);
}
/* A streaming turn is sealed into several assistant bubbles as it goes
(`message.interim`) and rehydrates into fewer, so the same two blocks are
sometimes siblings inside one bubble and sometimes split across two. The
flex gap between bubbles is the turn gap half the block gap which made
the rhythm visibly tighten and then relax as a turn settled. Top it up so
the column ticks at one interval either way. */
[data-slot='aui_turn-pair'] > [data-slot='aui_assistant-message-root'] + [data-slot='aui_assistant-message-root'] {
margin-top: calc(var(--turn-block-gap) - var(--conversation-turn-gap));
}
/* Message action bars — flat icon hits with default dim; only the hovered/focused control is full-strength. */
[data-slot='aui_msg-actions'] button {
border: 0;