fix: the message box's send button shows its arrow
Dean saw the message box's round send button as an empty circle: no arrow. Base is coding-agents.
Root cause
The utilities the AI Elements components are written in sit in Tailwind's utilities cascade layer, and base.css's element resets sat outside every layer. An unlayered rule outranks a layered one whatever its specificity, so button { color: inherit } beat the submit's text-primary-foreground: the arrow took the panel's primary white, the same colour as the bg-primary disc, and vanished into it. Every utility was compiled and present; none of them could win. The Stop square only showed because #1919 had added an unlayered .agent-composer-stop { color } beside it, which was this bug worked around for one of the two glyphs. The same cascade also silently beat cursor-default and the muted text-* colours on the transcript's other buttons (the copy button, the tool output's "show more", the scroll-to-bottom button).
Fix
base.cssputs its element resets (*,button,button:disabled,textarea) in@layer base, whichindex.cssimports before the Tailwind entry so it ranks underutilities, as Tailwind's own preflight would. Every other hand-written rule stays outside the layers and still wins over a utility.PromptInputSubmitis drawn like Claude's and ChatGPT's: active is theprimarydisc with the glyph inprimary-foreground(the surface's own colour, so a dark arrow on the light disc in Luke's dark palette); dim isdisabled:bg-secondary disabled:text-muted-foreground(the raised ground with a muted arrow) instead of a 45% opacity over the filled one; the button isdisabledand saysaria-disabledtoo; it has no hover. Stop is unchanged in behaviour and now reads by the same rule, so the.agent-composer-stopworkaround and its class are deleted. Size (28px) and place never change between states.- A knock-on of the layer: the textarea's own
text-[13px] leading-[1.45]now applies rather than the inherited font. The app stage is 13px already, so the size is the same; the line height is now the 1.45 the box's min/max height were already computed from.
Tests
agent-composer.test.tsholds a stylesheet contract on the sheet assembled as the build assembles it (every sheetindex.cssnames, inlined in order, the Tailwind entry compiled over the same sources): every reset-shaped rule (button,*,textarea) sits in a layer ranked underutilities; in the dim, active, and Stop states the button's resolvedcolordiffers from its resolvedbackground-color, the dim disc is not the active one, the svg carries no colour of its own and resolves to a non-zero pixel size, the button is 28px round, its class list is the same in every state, and nothing on it answers:hover. Fails oncoding-agentswith "* { box-sizing } ranks under the utilities (no layer)".- The one-button test now also holds
aria-disabledin step withdisabledin every state (dim with an empty box while idle, active with text). - The parser the transcript layout test wrote for the Tailwind sheet moves to
src/testing/css-rules.tsnow that two tests read it, and learns the layer a rule sits in.
Screenshots
Headless Chrome over the real AgentComposer and the renderer stylesheet (Linux fonts), on pr-assets.
Before (coding-agents) | After |
|---|---|
![]() | ![]() |
Top to bottom: idle and empty (dim), idle with text (active), running and empty (Stop).
Verification
./scripts/check.sh exits 0 locally. CI could not verify the Mac: no macOS job runs on a pull request, and Dean waived ./scripts/verify.sh for this work, so the Mac rendering is unverified beyond the headless captures above.
š¤ Generated with Claude Code

