Colour
Read live from config/brand.php, so a swatch
can never claim a value the site is not using.
Brand
--void
#0E0A0B
The default surface. Roughly four screens in five.
--oxblood
#5C1F1B
A surface, not an accent. Whole panels, rarely.
--signal
#FF4A2E
Alert only, brand layer. Three per viewport, maximum.
--bone
#E8E2D6
Warm off-white. One or two sections at most.
--ash
#8A7F7C
Muted text on dark.
--hairline
#2E2224
Rules and dividers.
Interactive
--interactive
#FF4A2E
Primary actions, links, focus rings. No budget.
--interactive-hover
#FF6347
Hover on a primary action.
--interactive-press
#E03A20
Active — the moment of the press.
State
--success
#4A9D5F
Confirmed, attended, active.
--warning
#D9A441
Expiring, nearly full, pending.
--danger
#D14545
Cancel, delete, expired, no-show.
Surfaces
--surface-raised
#1A1315
Cards, panels, table headers.
--surface-input
#150F11
Form fields.
--border
#3A2C2E
Default control border.
--border-strong
#5A4548
Emphasis, secondary buttons, hover.
--disabled-bg
#1A1315
A switched-off control.
--disabled-fg
#5A4F4C
Text on a switched-off control.
The three-per-viewport budget applies to --signal used as an alert in the brand layer. --interactive has no budget: every actionable thing has to look actionable.
Type roles
One row per role. Big Shoulders appears in the first two rows and nowhere else on this page — it is a marketing display face, and the application layer never uses it.
| Role | Face | Case and size | Specimen |
|---|---|---|---|
| Marketing display | Big Shoulders 800 | UPPER · 48–200px | Strength is a practice |
| Section eyebrow | Big Shoulders / mono | UPPER · 11px, 0.18em | What we run |
| Page title (app) | Instrument Sans 600 | Sentence · 24–32px | Your bookings |
| Section heading (app) | Instrument Sans 600 | Sentence · 18–20px | Credit history |
| Body | Instrument Sans 400 | Sentence · 16–18px | Small groups, qualified coaches, programming that progresses. |
| Button | Instrument Sans 600 | Sentence · 15px | Book this class |
| Form label | Instrument Sans 500 | Sentence · 14px | Email address |
| Helper / error | Instrument Sans 400 | Sentence · 13px | Confirmations are sent here. |
| Table header | Instrument Sans 500 | Sentence · 13px | Balance |
| Numbers and codes | Martian Mono | 13–15px | 06:00 · 24/24 · AED 1,200 |
| Board time | Martian Mono | 20–28px | 18:30 |
Buttons
Every label carries a verb and an object. Every variant clears a 44px target. Tab through this section to see the focus ring — 2px, --interactive, 2px offset.
Primary
The one decision on a screen. Solid --interactive.
Secondary
Everything else that is still a real action.
Tertiary
In-flow, low weight. The underline is permanent.
Danger
Destructive. Outlined until it is the confirm.
Danger, confirming
The second press, inside a dialog.
Ghost
Chrome only — sign out, close, dismiss.
States
Default
At rest.
Loading
Set on submit, so a slow request cannot be double-pressed.
Disabled
Hover or focus it — the reason is in the title. The component cannot render disabled without one.
Full width
Forms on narrow screens.
Labels
Not this
- Book
- Cancel
- Submit
- OK
This
- Book this class
- Cancel booking
- Request my free session
- Save changes
Form fields
Visible border on --surface-input, label above the field, helper text where the label cannot carry it. No field is ever labelled by its placeholder.
Status badges
One component for every status in the product. A coloured dot and a word, always — colour alone fails for roughly one man in twelve and for anyone reading over a shoulder.
Tables
Distinct header row, hover on every row, numeric columns right-aligned in mono, and an explicit action per row — a clickable row is never the only way in.
| Date | Reason | Status | Change | Balance | Action |
|---|---|---|---|---|---|
| 12.07.2026 | Booked Olympic Lifting, Thursday 18:00 | Booked | -1 | 7 | |
| 10.07.2026 | Cancelled Conditioning, Tuesday 06:00 | Cancelled | +1 | 8 | |
| 08.07.2026 | Booked Strength, Sunday 07:00 | Attended | -1 | 7 |
Alerts and explanations
An alert is something that happened. A note explains a decision the system made that the user did not — and it sits in the flow, because a tooltip is not a label.
Booked
Olympic Lifting, Thursday 3 August 18:00. One credit used, seven left.
You do not need to sign in
This is a demonstration build — the sign-in page puts you into any role without a password.
Your membership renews soon
Committed runs out on 1 August — five days from now. Renewals happen at the desk.
That booking did not go through
You already have a class at that time. Cancel the other one first, or pick a different slot.
Waitlist 2 — you move up when someone cancels, and a credit is only taken at that point.
All 24 places are taken. Joining the waitlist costs nothing.
Empty states
Never a blank area. A rule, a sentence saying why it is empty, and the button that fills it.
No upcoming bookings
You have nothing in the diary. Pick a class from the week and it will appear here straight away.
No credits have moved yet
Book a class and it will appear here, with the balance it left you on.
Confirmations
Every destructive action states its consequence before the confirm button, in the dialog rather than on the page behind it. Press one — they are live.
Cancel this booking?
Olympic Lifting · Thursday 3 August at 18:00, Al Quoz.
Your credit goes straight back onto your account, and the place is offered to the first person on the waitlist.
Cancel this booking?
Conditioning · today at 18:00, Dubai Marina.
Your credit will not be returned. This class starts in under four hours, and inside that window the place cannot be resold.
Pagination
The first and last pages disable the control they cannot use, and say why on hover.
In place
The same parts assembled the way the portal uses them, so a change here is visible in context rather than only in isolation.
Book a class
The whole week, with the places left in each room. Booking takes one credit; joining a waitlist takes none.
Mon 3 Aug — Sun 9 Aug
-
18:00Olympic Lifting2 left
-
19:00ConditioningFull
All 24 places are taken. Joining the waitlist costs nothing — you are only charged a credit if a place comes free.
Keyboard
Tab from here. Every control on this page takes focus in document order and shows the same ring. The skip link at the very top is the first stop.