fix(rag): stop the per-run blocks from folding — the container is the one disclosure
The owner refinement (2026-10-06): the per-run thinking and tool-call blocks inside the Reasoning bubble were individually collapsible details elements — a fold inside the fold. A tool frame closed the previous thinking block, so the visible thinking vanished mid-turn; and the pinned-tail follow died on the append of every run after the first (the pin was captured AFTER the new block's height growth contaminated the 32px reading). - app.js: the in-container runs are now plain divs — createThinkingRunEl (div.thinking + static .thinking-summary label + .thinking-text) and createToolRunEl (div.tool-calls-disclosure + static .tool-calls-summary label + the .tool-calls list); they never open or fold (the container is the ONE open/fold control, open through the turn, folded at settle — unchanged); the pin capture moves BEFORE ensureThinkingRun/ensureToolRun append (plus the first-frame edge: no container yet -> always pinned); closeCurrentRun just ends the run; closeAllRuns stays the defensive legacy guard; restoreTimeline/addSegments (shared.js) use the div builders; the legacy no-segments restore path keeps the old details-based blocks byte-identical - styles.css: the in-container runs are distinct by label + rail (brand-ink Thinking label on a brand-soft rail; accent-ink Tool call(s) (N) label on a neutral rail); the interactive treatment (cursor + chevron) is scoped to the legacy <summary>; the inner windows stay disabled (the container's .reasoning-body is the ONE live scroll surface) - unit + E2E: the D5-refinement contract is pinned — one details.reasoning disclosure, per-run blocks as plain divs, zero nested <details> inside the container, the container as the only open/fold control, the .reasoning-body window auto-follows the tail while streaming unit+integration 3738 passed (coverage 99%), ruff + pyright clean, all five affected E2E suites pass in isolation (reasoning_bubble 6, thinking_timeline 6, thinking_display 5, thinking_scroll 8, tool_call_compact 4), verified live: the follow holds through a long thinking stream, the tool-frame transition, and the second thinking run; restore renders the div structure without client-side errors LLM-Generated: true
This commit is contained in:
+61
-24
@@ -753,27 +753,53 @@ summary.reasoning-summary:focus-visible {
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
/* D3 inner-run compacting: the per-run blocks nest de-bordered inside
|
||||
the container — the nested border weight is removed (a 2px line
|
||||
indent keeps the family rhythm) and the inner 320px windows are
|
||||
disabled (max-height: none) so the container's window is the single
|
||||
scroll surface (the phase-17 per-block follow in app.js no-ops on
|
||||
the now-unscrollable .thinking-text). */
|
||||
details.reasoning details.thinking {
|
||||
border: 0;
|
||||
border-left: 2px solid var(--line);
|
||||
border-radius: 0;
|
||||
margin: 0.25rem 0;
|
||||
background: transparent;
|
||||
/* D3 inner-run compacting + the D5 refinement (owner 2026-10-06):
|
||||
the per-run blocks nest as plain divs inside the container —
|
||||
NEVER collapsible (the container is the ONE disclosure; a nested
|
||||
fold inside the fold was the defect). The blocks are distinct
|
||||
from each other by LABEL + RAIL: the thinking run carries the
|
||||
family's brand-soft rail + the brand-ink "Thinking" label; the
|
||||
tool run carries the neutral --line rail + the accent-ink
|
||||
"Tool call(s) (N)" label (the phase-117 accent pairing). The
|
||||
inner 320px windows are disabled (max-height: none) so the
|
||||
container's window is the single scroll surface (the phase-17
|
||||
per-block follow in app.js no-ops on the now-unscrollable
|
||||
.thinking-text). */
|
||||
details.reasoning .thinking {
|
||||
border-left: 2px solid var(--brand-soft);
|
||||
padding-left: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
details.reasoning details.thinking .thinking-text {
|
||||
/* The static (non-interactive) "Thinking" label — brand-ink on the
|
||||
surface ≈8.7:1 (the family's summary pairing, AA); no cursor, no
|
||||
focus target (it is not a control — the container's summary is).
|
||||
*/
|
||||
details.reasoning .thinking .thinking-summary {
|
||||
display: block;
|
||||
color: var(--brand-ink);
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
details.reasoning .thinking .thinking-text {
|
||||
padding: 0 0 0.75rem;
|
||||
color: var(--ink-soft); /* 6.9:1 on --surface — the scratchpad pairing */
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.55;
|
||||
max-height: none;
|
||||
overflow-y: visible;
|
||||
}
|
||||
/* The nested tool-calls disclosure is already compact — the rule
|
||||
documents the intent (one window, one rhythm) without a visual
|
||||
change. */
|
||||
details.reasoning .tool-calls-disclosure { margin: 0.25rem 0; }
|
||||
details.reasoning .thinking .thinking-text p,
|
||||
details.reasoning .thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
/* The tool run — the neutral rail (distinct from the thinking run's
|
||||
brand-soft rail) + the phase-117 accent-ink label (≈10.4:1 on the
|
||||
surface, AA). The .tool-calls rows keep the exact phase-37/117
|
||||
treatment below (the shared rule — no new bytes). */
|
||||
details.reasoning .tool-calls-disclosure {
|
||||
border-left: 2px solid var(--line);
|
||||
padding-left: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
/* Phase 117: the tool-call record folds into a single disclosure line,
|
||||
reusing the Thinking block's native <details> convention. Open while
|
||||
@@ -787,24 +813,33 @@ details.reasoning .tool-calls-disclosure { margin: 0.25rem 0; }
|
||||
label either way. */
|
||||
.tool-calls-disclosure { margin: 0.25rem 0; }
|
||||
.tool-calls-summary {
|
||||
cursor: pointer;
|
||||
color: var(--accent-ink);
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.4;
|
||||
padding: 0.15rem 0;
|
||||
}
|
||||
/* The legacy (out-of-container) disclosure's summary is a native
|
||||
focusable toggle — the interactive treatment is scoped to the
|
||||
<summary> element: the in-container run's label is a plain span
|
||||
(the D5 refinement — the container is the ONE disclosure, so the
|
||||
run's label is not a control). */
|
||||
summary.tool-calls-summary {
|
||||
cursor: pointer;
|
||||
list-style: none; /* the native marker is redundant with the count text */
|
||||
}
|
||||
.tool-calls-summary::-webkit-details-marker { display: none; }
|
||||
summary.tool-calls-summary::-webkit-details-marker { display: none; }
|
||||
/* CSS chevron: ▸ rotates 90° when open — the same family treatment as
|
||||
details.thinking summary::before (the transition stills under
|
||||
prefers-reduced-motion — see the reduced-motion block below). */
|
||||
.tool-calls-summary::before {
|
||||
prefers-reduced-motion — see the reduced-motion block below). Scoped
|
||||
to the <summary> element: the in-container run's label (a span with
|
||||
the same class) carries no chevron. */
|
||||
summary.tool-calls-summary::before {
|
||||
content: "▸";
|
||||
display: inline-block;
|
||||
margin-right: 0.5rem;
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
.tool-calls-disclosure[open] .tool-calls-summary::before {
|
||||
details.tool-calls-disclosure[open] summary.tool-calls-summary::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
@@ -1733,8 +1768,10 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und
|
||||
.typing span.typing-elapsed { opacity: 1; }
|
||||
/* Phase 17 thinking block: the chevron stills (no rotation motion). */
|
||||
details.thinking summary::before { transition: none; }
|
||||
/* Phase 117 tool-calls disclosure: the same chevron, the same still. */
|
||||
.tool-calls-summary::before { transition: none; }
|
||||
/* Phase 117 tool-calls disclosure: the same chevron, the same still
|
||||
(scoped to the <summary> — the in-container span label has no
|
||||
chevron to still). */
|
||||
summary.tool-calls-summary::before { transition: none; }
|
||||
/* Phase 161 reasoning bubble: the family chevron, the family still. */
|
||||
summary.reasoning-summary::before { transition: none; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user