Density and states
Empty, loading, error, sonic feedback, and density.
Bare inputs, minimal lines, neutral selection
The proposal changes where the signal comes from: rest stops drawing a box, focus puts a ring in the link colour, and the error is said in the line and the letters, with no red fill.
Until 2026-09-20 the input was a line under the text, selected used the soft blue pair, and a box was separated by colour and shadow with no radius. Now the input draws nothing until focus and selected is grey.
The input does not exist until you touch it
At rest there is an icon and a placeholder over a 12% hairline — nothing else. On focus the ring appears in the link colour, which is #7aa3f0 in dark and the navy in light, with a 28% halo of the same colour. The caret takes that colour too.
The error does not paint the field: it puts the line in the system red and writes underneath what happened. A red-filled field over a dark island is a smudge, and it buries what the person typed.
The field, by state
- Width
- 240px · height 32px · pill radius
- Rest
- inset 0 0 0 1px strong hairline · no fill
- Focus
- inset 0 0 0 1px ring + 0 0 0 3px ring at 28%
- Error
- inset 0 0 0 1px --bad · text in --bad underneath
- Ring · dark
- #3B6FD1 · caret #7AA3F0
- Ring · light
- #2457A8 · caret #2457A8
Lines are minimal and only separate rows
White at 4% in dark, black at 4.5% in light. Between table and list rows, and nowhere else: they do not surround, do not divide zones, do not act as a control border.
A line that is not separating two rows of text is a box in disguise. That is the test: take it away, and if it still reads, it was not needed.
The separator
- Hairline · dark
- rgb(255 255 255 / 4%)
- Hairline · light
- rgb(0 0 0 / 4.5%)
- Thickness
- 1px
- Where
- between rows of text, never around
The box carries fill and shadow, never both plus a line
Subtle fill, a 4% line of light on top, a short shadow and a long one downwards. No hairline: the fill already separates it.
Fill and hairline together is the box inside the box. That is the rule from 08 · Geometry, said here for the concrete case: the agent trace, "next step" and the campaign card are the three objects that use it.
The filled box
- Fill · dark
- #1A1A1A
- Fill · light
- #F6F6F6
- Shadow · dark
- inset 0 1px 0 white 4% · 0 1px 2px black 40% · 0 12px 28px -16px black 70%
- Shadow · light
- 0 1px 2px black 4% · 0 12px 28px -16px black 12%
- Radius
- 16px
- Hairline
- none — never with a fill
Selected and hover are neutral
A selected row, tab or navigation entry is marked with white at 6% (black at 5% in light) and text weight. Hover is half of that. No blue: blue already has its four jobs.
If a selection state is painted with the action colour, it stops being distinguishable from the button that acts, and the view fills with blue that cannot be clicked.
The two washes
- Selected · dark
- rgb(255 255 255 / 6%)
- Selected · light
- rgb(0 0 0 / 5%)
- Hover · dark
- rgb(255 255 255 / 4%)
- Hover · light
- rgb(0 0 0 / 3%)
- Colour
- none — grey and text weight
The "New" chip is the only state in navy
It carries the navy as a fill with #dbe7ff letters in dark; in light it inverts to #e6edf8 with navy letters. It is the third of the four things that spend the blue.
Every other chip lives in its own semantic pair — success, warning, danger, person — and none of them uses the action colour.
Live canon
The states of one control
Five states, five pairs of tokens. Disabled lowers contrast and loses the hover shadow — a dead control does not react. Selected uses the soft blue pair, never a border.
Empty, loading and error are first-class screens
Empty says what is going to happen and offers the action that fills it. The error says what failed and what is safe, never a bare code. A short fetch uses signal and text on a single line. A skeleton only appears when keeping the geometry avoids a real jump.
Long work belongs to Intelligence and states elapsed time. None of these states carries an illustration: they are work states, not brand moments.
No conversations
Once you turn the campaign on, replies arrive here.
Could not send
WhatsApp rejected the message. The thread is intact.
Pending attention persists until somebody acts
An open handoff is not an ordinary unread. The row keeps a cool-warm wash, a signal rule and the explicit badge while a person still has to act. Marking everything read does not put it out.
Once taken, the loop ends and the owner appears. Once closed, it becomes quiet history. Under reduced motion, Needs action keeps the rule and the static wash: movement is lost, meaning never is.
Signal centre
Notifications
Open handoff · AltoAndes Cloud
Needs a DPA and a custom enterprise proposal.
Handoff taken · Trenque Data
Ty is agreeing the time with the contact.
Handoff resolved · Nexora
The conversation stays as history.
A toast is a short receipt, not another inbox
Sonner keeps the live region, the stack and the gesture to dismiss. Striker gives it white paper and black ink in both modes. A 2px semantic line carries the state; fog separates elements without turning every notification into a coloured card.
It lives top right, aligned under the bell, and does not scale as it stacks. A task that must stay, be opened later or be assigned lives in Notifications, not in a toast.
The title names the outcome. The second line explains what changed or what is safe. Recoverable states may offer a single action; long processes update the same receipt from loading to done or error.
The kind of toast decides its sonic answer: information, done, warning or error. The inbox keeps longer cues for milestones and human attention. Everything starts off, and the text still explains the state when sound is not on.
Meeting booked
The invite was sent and recorded on the lead.
Needs attention
The contact asked to speak with a person.
Could not send
The thread is intact. Check the connection before retrying.
An OS has a vocabulary, not one single beep
The dashboard recognises three planes. Interaction makes buttons, links, tabs, toggles and overlays tactile. Feedback accompanies Sonner states. Operation reserves the longer phrases for a commercial milestone or something that needs a person.
Hover, typing and scroll stay silent. A short click may repeat; operation signals keep the 10-second cooldown, group into bursts and never exceed three per minute.
Every control plays exactly the recipe the dashboard shares. The Brand System does not keep an approximate copy: it documents and runs the same contract.
Interaction
Tactile and very short. They build the feeling of an OS.
Feedback
They confirm the state the toast also shows.
Operation
Milestones and signals that can arrive with no immediate click.
Active sample
Tap
interaction
Buttons and simple actions
minimal/tap · 16 ms
Pick a sound to hear it.
Density is a switch, not a redesign
Both columns use the same class: h-[var(--sds-control-height)]. The compact one only adds data-density="compact" to the container and the token does the rest.
On touch screens density is ignored downwards: no control lands under 44px, not even in compact mode.
Comfortable · 40px
Compact · 36px
- Selected
- #E7EAFD / #142DB8
- Disabled
- #E9EAF1 / #8A8C99 · 0.58
- Loading
- #E7EAFD / #1E3CE6
- Error
- danger-surface / foreground
- Toast
- white / ink · fog hairlines · 2px state
- Pending attention
- wash 5.2s · ring 2.8s · persists
- Resolved attention
- no loop · stays as history
- Sound
- 14 cues · 3 planes · personal opt-in
- Compact density
- 28 / 36 / 44 px
- Touch floor
- 44px always