diff --git a/apps/web/src/components/app/chat/chat-entries.tsx b/apps/web/src/components/app/chat/chat-entries.tsx index 169099b68..d4d1cab63 100644 --- a/apps/web/src/components/app/chat/chat-entries.tsx +++ b/apps/web/src/components/app/chat/chat-entries.tsx @@ -243,8 +243,15 @@ function Avatar({ * reads as one block. */ export const POST_TINT: Record = { - user: "bg-primary/[0.06] hover:bg-primary/[0.09]", - peer: "bg-violet-500/[0.06] hover:bg-violet-500/[0.09]", + // Only the user's own posts get a fill. At 6% `primary` sat too close to the + // page background in several themes to notice; 10% reads everywhere. + // + // No left accent bar: a rule down the post's left edge competed with the + // connected-agent border the sidebar draws on the pane's left edge. + user: "bg-primary/[0.10] hover:bg-primary/[0.14]", + // Agent-to-agent traffic is a side conversation the user is overhearing, so + // it recedes — indent and muted body carry it, with no fill of its own. + peer: "hover:bg-muted/30", agent: "hover:bg-muted/40", }; diff --git a/apps/web/src/components/app/chat/chat-feed.test.tsx b/apps/web/src/components/app/chat/chat-feed.test.tsx index ca40bd6f9..a4d64bedd 100644 --- a/apps/web/src/components/app/chat/chat-feed.test.tsx +++ b/apps/web/src/components/app/chat/chat-feed.test.tsx @@ -14,6 +14,7 @@ import { POST_BODY_MEASURE, SIDE_POST_INDENT, peerDirectory, + POST_TINT, } from "@/components/app/chat/chat-entries"; import { ChatFeed, @@ -512,8 +513,8 @@ describe("ChatFeed", () => { // Not in the list any more: the generic agent icon. "Agent agent", ]); - // Still a peer post: violet, with the sender's name. - expect(posts[0]!.className).toContain("bg-violet-500/[0.06]"); + // Still a peer post: muted side-conversation treatment, sender's name. + expect(posts[0]!.className).toContain(POST_TINT.peer); expect( posts[0]!.querySelector('[data-testid="chat-post-author"]')?.textContent ).toBe("agt_kid"); @@ -704,18 +705,20 @@ describe("ChatFeed", () => { expect(agentPost!.getAttribute("data-rule")).toBeNull(); expect(userOne!.getAttribute("data-author-kind")).toBe("user"); - expect(userOne!.className).toContain("bg-primary/[0.06]"); + expect(userOne!.className).toContain(POST_TINT.user); + // No accent bar: it competed with the sidebar's connected-agent border. + expect(userOne!.className).not.toContain("before:w-0.5"); expect(userOne!.getAttribute("data-group-start")).toBe("true"); expect(userOne!.getAttribute("data-rule")).toBe("true"); expect(userOne!.className).toContain("border-t"); // A grouped row keeps the tint (one block) but no boundary of its own. - expect(userTwo!.className).toContain("bg-primary/[0.06]"); + expect(userTwo!.className).toContain(POST_TINT.user); expect(userTwo!.getAttribute("data-group-start")).toBeNull(); expect(userTwo!.getAttribute("data-rule")).toBeNull(); expect(userTwo!.className).not.toContain("border-t"); expect(peer.getAttribute("data-author-kind")).toBe("peer"); - expect(peer.className).toContain("bg-violet-500/[0.06]"); + expect(peer.className).toContain(POST_TINT.peer); expect(peer.getAttribute("data-rule")).toBe("true"); // Bodies stop at a reading measure; the row itself spans the pane. @@ -1140,7 +1143,7 @@ describe("ChatFeed", () => { expect(post.getAttribute("data-side")).toBe("true"); expect(post.className).toContain(SIDE_POST_INDENT); expect(post.className).not.toContain("px-4"); - expect(post.className).toContain("bg-violet-500/[0.06]"); + expect(post.className).toContain(POST_TINT.peer); const body = Array.from(post.querySelectorAll("div")).find((el) => el.className.includes(POST_BODY_MEASURE) ); diff --git a/docs/chat-surface-plan.md b/docs/chat-surface-plan.md index 50ad61d38..7e1ab669f 100644 --- a/docs/chat-surface-plan.md +++ b/docs/chat-surface-plan.md @@ -378,7 +378,7 @@ changes; the flag, routes and tools are unchanged. share a parent, otherwise **agent** — also the fallback when the sender is no longer in the list (generic bot icon). `agentRelation` in `lib/agent-lineage.ts`; the same chip sits on the Messages panel's thread - headers so the two agree. The violet tint and the outgoing "to " + headers so the two agree. The muted side-conversation treatment and the outgoing "to " line stay. - Entries that arrive after the feed first rendered — new posts, status lines, media, and posts edited in place — fade in (200 ms opacity with a