ui: the document, all-in — card-color bands and the 6px rail

Owner round two on user-vs-agent clarity (the chat-comeback was tried
and set aside): we go all in on documents. No chat sides. User messages
and every transcript user-thinking row are full-width CARD-COLOR BANDS
- the band is the authorship mark against the agent's transparent
prose. No rounded corners, no borders besides the rail.

The rail keeps its muted color but is now 6px wide (was 2px): the
artificially wide 3ch inset (the chevron-alignment law with the agent's
flush rows) is re-split - rail eats the air, the rail-to-text gap drops
from 3ch-2px to a natural 3ch-6px, and the total inset stays 3ch so the
chevrons still align. The 'You' label stays on messages - one register
with the thinking labels.

In-card thinking (inside answered cards) takes the rail but NO band:
card-color on card-color would be invisible; geometry alone carries it.
Transcript rows arrive expanded (clearly sent) - the reading lift now
opens on arrival too; the in-card row stays collapsed. Cmd+T still
rules all rows.

Also this round: the answered-card last-child rhythm law
([&>*:last-child]:mb-0) - on ask cards the thinking row's my-3 stacked
with the card's p-4 into a 28px void below (12px above); the card's own
padding is the bottom rhythm when a row ends the card.
This commit is contained in:
amosblomqvist
2026-10-08 18:17:11 +03:00
parent 8cb5e14691
commit 3691e07118
7 changed files with 79 additions and 54 deletions
+12 -6
View File
@@ -295,9 +295,13 @@ describe("render smoke tests", () => {
// trigger row only — the thinking text is one click away, never loud.
assert.ok(html.includes('data-testid="your-thinking-trigger"'), "the trigger row");
assert.ok(html.includes('aria-expanded="false"'), "arrives collapsed");
// IN-CARD = RAIL ONLY (owner round two, 2026-10-07): no band on the
// card's own background; geometry alone carries it there.
const yourRow = html.slice(html.indexOf('data-testid="your-thinking"'));
assert.ok(!yourRow.slice(0, 400).includes("bg-card"), "no band inside the card");
// THE RAIL GROUPS (owner correction): the label sits INSIDE the rail —
// ownership readable from the rail alone, collapsed or expanded.
const railAt = html.indexOf("border-l-2");
const railAt = html.indexOf("border-l-[6px]");
const trigAt = html.indexOf("your-thinking-trigger");
assert.ok(railAt !== -1 && railAt < trigAt, "the rail opens before the label (same quote)");
assert.ok(!html.includes("brightness isn&#x27;t distance"), "the text is hidden until expanded");
@@ -591,9 +595,9 @@ describe("predict vs check rendering", () => {
readingThinking: "was unsure mid-paragraph",
});
const html = renderToStaticMarkup(<AnsweredCard answer={withReading} />);
// The unified ThinkingBlock (owner round, 2026-10-05): the reading
// thoughts render BEFORE the card as the collapsed user-thinking row
// — same trigger, same 50%-italic quote block on expand.
// The unified ThinkingBlock (owner round, 2026-10-05; round two
// 2026-10-07): the reading thoughts render BEFORE the card as the
// banded user-thinking row, arriving EXPANDED (clearly sent).
const blockAt = html.indexOf("reading-thinking-block");
const cardAt = html.indexOf("answered-card");
assert.ok(blockAt !== -1, "the lifted block renders");
@@ -601,9 +605,11 @@ describe("predict vs check rendering", () => {
assert.ok(html.includes("YOUR THINKING"), "the plain label");
assert.ok(!html.includes("Your thinking while reading"), "the old verbose label is gone");
assert.ok(!html.includes("your-reading-thinking"), "the in-card inset is gone");
// COLLAPSED ARRIVAL: SSR shows the triggers, not the texts.
// EXPANDED ARRIVAL (owner round two, 2026-10-07): transcript rows
// render their text; the in-card answer thinking stays collapsed.
assert.ok(html.includes('data-testid="your-thinking-trigger"'), "the answer thinking stays inside the card");
assert.ok(!html.includes("answering thought") && !html.includes("was unsure mid-paragraph"), "texts hidden until expanded");
assert.ok(html.includes("was unsure mid-paragraph"), "the lifted row arrives expanded");
assert.ok(!html.includes("answering thought"), "the in-card row stays collapsed");
const legacy = { ...buildAnswer(quizQD(), { values: ["Mercury"] }), note: "a 2026-09 answer" };
const legacyHtml = renderToStaticMarkup(<AnsweredCard answer={legacy} />);
assert.ok(legacyHtml.includes("a 2026-09 answer") || legacyHtml.includes('data-testid="your-thinking-trigger"'), "records from before the rename still render");
+13 -11
View File
@@ -243,19 +243,21 @@ describe("md-blocks — the restored plain blockquote (owner round, 2026-10-07)"
});
describe("ThinkingBlock — side-based authorship + ⌘T sync (owner round, 2026-10-07)", () => {
it("the default row stays left with the my-3 rhythm", () => {
const html = renderToStaticMarkup(<ThinkingBlock text="left side" />);
assert.ok(html.includes("border-l-2"), "left rail");
assert.ok(html.includes("my-3"), "the 12px rhythm (was my-1)");
it("the banded row is the document band — full-width card color, 6px rail", () => {
const html = renderToStaticMarkup(<ThinkingBlock text="banded" defaultOpen />);
assert.ok(html.includes("bg-card"), "the card-color band");
assert.ok(html.includes("border-l-[6px]"), "the 6px rail");
assert.ok(html.includes("pl-[calc(3ch-6px)]"), "natural gap, 3ch total inset preserved");
assert.ok(html.includes("w-full"), "full width — no chat side");
assert.match(html, /aria-expanded="true"/);
assert.ok(html.includes("banded"), "text visible on arrival");
});
it("mirrored rows hug the right edge, rail flipped, arriving open", () => {
const html = renderToStaticMarkup(<ThinkingBlock text="right side" mirror defaultOpen />);
assert.ok(html.includes('data-side="right"'));
assert.ok(html.includes("ml-auto"), "pushed to the right edge");
assert.ok(html.includes("border-r-2") && !html.includes("border-l-2"), "rail on the right");
assert.match(html, /aria-expanded="true"/);
assert.ok(html.includes("right side"), "text visible on arrival");
it("in-card rows take the rail but no band", () => {
const html = renderToStaticMarkup(<ThinkingBlock text="in card" banded={false} />);
assert.ok(!html.includes("bg-card"), "no band on the card's own background");
assert.ok(html.includes("border-l-[6px]"), "the rail stays");
assert.ok(html.includes("my-3"), "the 12px in-card rhythm");
});
it("⌘T sets every row — explicit sets stomp individual state, late mounts honor the last set", () => {
+5 -4
View File
@@ -179,12 +179,13 @@ describe("the practice transcript cards", () => {
it("ThinkingCard: one label, right side, expanded arrival (owner round, 2026-10-07)", () => {
const trace = renderToStaticMarkup(<ThinkingCard data={{ problemCallId: "c", commit: false, text: "stuck at step two" }} />);
assert.match(trace, /YOUR THINKING/);
// Transcript rows arrive EXPANDED (clearly conveyed as sent) and
// MIRRORED right (side-based authorship).
// Transcript rows arrive EXPANDED (clearly conveyed as sent) as
// full-width card-color bands with the 6px rail (the document,
// all-in — owner round two, 2026-10-07).
assert.match(trace, /aria-expanded="true"/);
assert.ok(trace.includes("stuck at step two"), "the text is visible on arrival");
assert.ok(trace.includes('data-side="right"'), "mirrored to the right side");
assert.ok(trace.includes("border-r-2"), "the rail is on the right");
assert.ok(trace.includes("bg-card"), "the card-color band");
assert.ok(trace.includes("border-l-[6px]"), "the 6px rail, left side");
const legacy = renderToStaticMarkup(<ThinkingCard data={{ problemCallId: "c", commit: true, text: "It is 42." }} />);
assert.match(legacy, /YOUR THINKING/);
assert.doesNotMatch(legacy, /Your solution/);