AI
Two components, Message and Prompt composer. Between them they cover a thread, an answer that is still arriving, an answer that failed, and the five states of the input underneath. Both are mobile width and both read from the same tokens as everything else.
Preview
Two surfaces an AI product cannot borrow from anything else in the system: the conversation row and the prompt input. Everything standing around them, suggestion chips, source cards, the tools menu and the model picker, is Chip, Card, Context Menu and Dropdown.
The two sets never meet inside the file. A thread is a column of Message rows and the composer is pinned under it, so neither knows what the other holds. The exchange above is the copy the file's own example screen carries, not the component defaults.
Message
One conversation row. Role decides the shape, State decides what an unfinished answer looks like. Both are on the same set, so a thread is one component repeated.
The grid is deliberately sparse: 4 of the 6 Role by State cells exist, because a user turn cannot stream and cannot fail. Two things do not line up. The Answer frame uses gap 8 in Default and gap 12 in Streaming and Error, and the Actions frame under the error carries a hardcoded 30 of left padding to line the button up with the copy rather than with the icon.
Prompt composer
The input everything else is arranged around. One shell, five states, and the state is the surface being honest about what it is doing: waiting, ready, working, carrying a file, or shut.
Empty still draws the send button, dormant in fg/disabled-400, rather than hiding it. The plus opens the tools menu, a Context Menu instance, so the tool list is not fixed here. Padding is not symmetric: 12 top and left, 10 right and bottom, which centres a 32 disc in the corner.
Anatomy
Measured in the file, not rounded to a scale. Where the file sits off its own spacing scale it is written here as it stands.
Both 1px strokes are drawn INSIDE, so a CSS border would make the shell 363 and the attachment row 55. They are reproduced as inset shadows, which add nothing.
Tokens
Nothing on either component carries a raw colour. Values are the light resolution; each has a dark counterpart inside the same variable.
In dark mode bg/white-0 becomes #0E0E0F and text/strong-950 becomes #FFFFFF, so surface and copy swap ends of the ramp together. The error tint is the one that does not simply invert: #FEF2F2 becomes red at 16 percent alpha.
Guidelines
One rule the set already decided for you, and two it cannot enforce.
Let the assistant run as plain text on the full 361. The reader scans one column and a long answer is not squeezed into a 280 bubble.
Do not give the assistant a bubble as well. Two bubbles read as two people, and the answer loses the width it was built for.
The set carries no Streaming and no Error on the User side, so a failed send is not a Message state: handle it on the composer or as a Toast. Keep Generating reachable, because Stop is the only control on either component that ends a running answer. And the composer never grows on its own: its height follows the value, so decide the ceiling yourself.