The atoms
of the surface.
Buttons, fields, cards, chips, marquees. Every component has a paper and an ink form, both governed by the same colour and contrast rules. None of them use a third surface.
Pill, hairline, uppercase, tracked.
Anatomy
Euclid Flex 500 · 13px · letter-spacing 0.16em · uppercase · 14×22 padding · min-height 44px · 999px radius · 1px hairline border · 0.4s silk transition.
Hover
Background swaps to the opposite ground; text inverts; arrow translates +4px. Never a transform, never a glow, never a colour shift on the text alone.
No box. A hairline. Fraunces as the input voice.
Fields are hairline-underlined and never boxed. The label sits above in tracked smallcaps. Focus shifts the underline to clay and stamps a 1px clay outline at 4px offset.
Hairline grouped. Shadow only when floating.
Library card
The default. Hairline frame, no shadow. Used in audit grids and journal indexes.
Resting card
Same as editorial + --sh-card. Used in the admin app where lift is helpful.
Lift card
--sh-lift. Just perceptible. Never adds a transform.
Ink card
--br-ink-2 ground, 1px ink-line border. The dark sibling.
Four states. Each maps to a reserved colour.
Product success. In-policy. Never on marketing.
Soft warning. Brand-aligned. Not error red.
Quoted by AI engines. Bordered, not filled.
Inert. Awaiting input. No status colour.
A pill, sticky, with a backdrop blur. Exactly one of these on a page.
A grid of measured statements.
First-party language quoted by ChatGPT, Perplexity, Claude and Google AI Overviews.
One review by a verified buyer can answer four queries in four engines on the same day.
Scans your store, takes your fonts, switches over in sixty seconds.
Hairline rows, numbered, on hover the title slides in.
The brand's only signature lift, ready to drop in.
This is not
a review tool.
/* The Magritte frame */ background: var(--br-paper); color: var(--br-ink); padding: 36px; border: 1px solid rgba(11, 16, 24, 0.10); box-shadow: var(--sh-frame); /* The inner picture-frame line */ ::after { inset: 14px; border: 1px solid rgba(11, 16, 24, 0.09); }
Labels above. Hairline underlines. One column.
Smallcaps, tracked 0.22em, paper-text-3
InputFraunces 400 · opsz 36 · 20–22px · ink colour
Underline1px paper-line resting; clay on focus
Spacing28px between fields (--sp-md)
LayoutOne column. No left/right field pairs. Reading width is form width.
ErrorIcon + sentence below the field. Clay text. role="alert".
RequiredNamed in the label as “· required”, not asterisked.
SubmitRight-aligned pill. After submit, focus moves to the confirmation region.
Three sizes. One trap-focus contract.
Quoted by ChatGPT, Perplexity, Claude, and Google AI Overviews this week.
Anchored to its trigger. No focus trap.
Send Eleanor's reply?
It'll go out from maud@maudsapothecary.com. The widget updates on the next page load.
Traps focus. Esc returns to trigger.
Verified buyers only
Limits the queue to reviews from confirmed orders.
Drag-handle. Swipe-down or Esc to dismiss.
Information, not celebration.
Reply sent. Eleanor will see it within the hour.
Toast · success · 5sShopify rejected the install. The store has a different review app active.
Toast · attention · sticky until acknowledgedIndexing 247 reviews into language clusters. About forty seconds.
Toast · progress · dismissible at completionReview approved. Undo
Toast · undo · 8s windowToasts sit bottom-right, 16px from the edge. Stack vertically; max three at once. Never use confetti, never use exclamation marks, never use emoji.
Empty is information, not failure.
No reviews yet.
We'll send the first request when an order is forty-eight hours old.
No matches.
No reviews mention “rosemary cleanser”. Try a broader phrase.
No citations this week.
We re-index every Monday. Last update was 12 May.
Hairline rows. Tabular figures. No zebra striping.
| Review | Buyer | Submitted | Cited | CTR | Status |
|---|---|---|---|---|---|
| “doesn't strip everything, smells like rosemary not perfume” | Eleanor M. | 14 May 2026 | 4× | 12.4% | Approved |
| “I'd been searching for a gentle cleanser for ages…” | Priya K. | 12 May 2026 | 2× | 9.1% | Needs reply |
| “the scent is too herbal for me · still effective” | Daniel A. | 11 May 2026 | 3.2% | Pending | |
| “my face wasn't tight at all… happy purchase” | Frances L. | 09 May 2026 | 1× | 7.4% | Approved |
Row separators
1px hairline only. No zebra striping. The hairline is enough.
Header
Smallcaps, tracked, paper-text-3 on paper-2. Sticky on scroll.
Numerals
font-variant-numeric: tabular-nums. Always right-aligned.
⌘ K. The keyboard becomes the product.
“smells like rosemary, not perfume”
Eleanor M. · 14 May
“the scent is too herbal…”
Rosemary cluster · 12 reviews
Opens with ⌘ + K on Mac, Ctrl + K on Windows. Searches reviews, keywords, settings, navigation. No fuzzy nonsense · prefix match on word boundaries.
Every component, every state, in one grid.
A specimen is a single state. A product is every state. The grid below shows the same four components across the seven states the brand needs to ship. Use it as a punch-list: if a state is missing from a new component, the component is not finished.
| Component | Default | Hover | Active | Loading | Error | Disabled |
|---|---|---|---|---|---|---|
| Button | ||||||
| Field | email … |
eleanor@ |
eleanor@ |
checking… |
eleanor@ Already on file. |
read-only |
| Card | REVIEW 12 cited |
REVIEW 12 cited |
REVIEW 12 cited |
DEGRADED Data stale |
REVIEW Locked |
|
| Row / list item | Eleanor M. |
Eleanor M. |
Eleanor M. |
Failed to load |
Locked row |
Empty state lives separately
Empty is a page-level state, not a component-level one. See §12 of this chapter for the three empty-state patterns. A component never renders its own “empty card.”
Loading uses skeletons, not spinners
Skeletons match the resting shape of the component (greyed paper-2 blocks). Spinners only appear inside the button itself; never as a centred page-level wheel.
Error states stay quiet
A 1px clay hairline + one sentence below. No red wall. No icon flood. The error is information; the component still reads as itself.