The booking widget ships in clean greyscale. Every salon's brand drops in through a handful of tokens — so the system stays one codebase and every salon still feels like itself.
Four rules that decide every visual call in the product.
The platform never competes with the salon. Color is the tenant's, not ours.
Color, radius, and font are tokens. A salon's look is data, not a fork of the code.
Nothing on screen that doesn't move the booking forward. Square/Fresha-clean.
Small, fast, embeddable. It behaves the same on every salon site we build.
A cool-biased greyscale — picked, not defaulted. Primary action is solid ink; there is no brand color in the neutral system.
Status only — kept separate from the accent so meaning never depends on the salon's theme.
A clean grotesque carries the UI; a monospace handles times, prices, tokens and code — the engineered, embeddable signal.
Headings, labels, body. No webfont in the neutral default — fast and dependency-free. A salon can override the display face via a token.
Times, prices, slugs, tokens, the embed snippet. Tabular figures keep columns aligned.
An 8px base grid. Three radii. Three elevations. Restraint is the point.
Radius is a token — Dolce softens to 6px, a modern barber might square to 4px.
One line family — 1.5px stroke, round caps, 24px grid, currentColor so icons take the theme. Ported from the Dolce set.
The widget serves more than nails — hair salons, barbershops, and spas too. Each salon type gets sensible default icons, and individual services can carry their own.
The building blocks of the widget and the dashboard. All neutral here; all token-aware so they reskin per salon.
We text/email a 6-digit code — no passwords, no magic links.
Who → what → when → confirm. Step 3 of 4.
| Time | Client | Service | Staff | Status |
|---|---|---|---|---|
| 10:45 | Maria Alvarez | Gel Manicure | Tina L. | Confirmed |
| 11:30 | J. Chen | Spa Pedicure + gel | Kim P. | Pending |
| 2:00 | R. Okafor | Acrylic Full Set | Tina L. | Completed |
Onboarding a salon swaps a small set of tokens — never the components. The toggle at the top of this page is exactly this mechanism.
| Token | Neutral default | Dolce override | Drives |
|---|---|---|---|
| --accent | #17191C | #6B2737 | Buttons, selected states |
| --on-accent | #FFFFFF | #FFF6F0 | Text on accent |
| --bg | #FFFFFF | #FFFAF5 | Widget background |
| --surface | #FBFBFC | #FAF6F1 | Rows, fields |
| --line | #E3E5E8 | #ECE0D4 | Borders |
| --radius | 10px | 6px | Corner softness |
| --display | System UI | Fraunces serif | Headings, salon name |
Stored as a small theme record on each salon and injected as a :root block at load. Components only ever read tokens — so a new salon is data, not code.
Plain, confident, and on the customer's side of the screen. A control says exactly what it does.