Design tokens & components
Everything on this page is rendered live from assets/tokens.css and assets/components.css. Change a token there and every page using this kit follows. Desktop-first at 1280px min-width, light theme only in v1; the same tokens also cover a 360px+ mobile shell (see below).
Principles
- Money and dates are never ambiguousOne format each, fixed GMT+8, tabular figures, right-aligned money. See Formats.
- Status has one colourEvery status word maps to exactly one badge colour. The same colour never means two things.
- Dense but calm13px table text, 36px controls, generous row hover, no decorative colour.
- Action lives top-rightPage-level primary action sits in the page header; row-level actions appear on hover; destructive actions are outlined red and confirm first.
- One primary per regionOne primary button per page region (page header, modal footer). Everything else is secondary or ghost.
- Built for reviewAnything mocked or unresolved gets a yellow dashed
.proto-noteso reviewers know what to comment on.
Colour
Primary is a deep plum, quiet enough for all-day use; gold accent is reserved for highlights and trial/attention states. Semantic colours are shared between badges, alerts, stat tiles and table rows.
Aliases used in components
Typography
Inter for UI, JetBrains Mono for anything a human might copy: date-times in inputs, reference numbers, ID numbers. All numerals use tabular figures so columns line up.
Spacing, radius, shadow
4px base. Components use 8 / 12 / 16 internally; page sections use 24 / 32. Radius: 4 inputs and tags, 6 buttons and menus, 10 cards and tables.
Date, time, money
These are global rules, not preferences — pick them once per app and apply everywhere. Helpers live in app.js: WOW.fmtDateTime, WOW.fmtDate, WOW.fmtTime, WOW.fmtMoney.
| Kind | Rendered | Class | Where |
|---|---|---|---|
| Date-time | 2026-09-06 20:31:00 | .datetime | Audit lines, run timestamps, approvals, history |
| Date | 2026-09-06 | .date | Lists, From/To pickers, document dates |
| Time | 20:30 | .time | Schedules, slot start, bookings |
| Money | RM 1,234.00 | .money | Right-aligned in tables, always two decimals |
| Negative money | (RM 50.00) | .money.neg | Refunds, reversals, deductions |
| Live clock | [data-now] | Sidebar footer, run screens |
Icons
Stroke icons at 16px (18px in a sidebar, 22px in mobile tabs), injected as an SVG sprite by app.js. Use <svg class="icon"><use href="#i-name"/></svg>.
Forms
Two-column grid on desktop. Labels above inputs, hints below. Required marked with a red asterisk. Errors inline in red. Selects are native for speed.
Status badges & tags
Badges carry status and always show a dot. Tags are plain labels with no dot. Give every status word in your app exactly one badge colour — add it to tokens.css, don't reuse someone else's.
Stat tiles & cards
Customer
Member- Name
- Tan Mei Ling
- ID
- 820405-10-5566
- Phone
- 012-345 6789
- Outstanding
- RM 240.00
Approval · Aug 2026
DraftTables
Sticky uppercase header, 13px rows, hover reveals row actions, money right-aligned, totals in a footer. A flagged row is tinted red; a selected row is tinted brand. Toolbar sits above with search and filters; pagination below.
Tabs
Used inside detail pages. Counts are optional. Click to switch below.
Alerts & toasts
Alerts are inline and persistent (blockers, warnings, run summaries). Toasts are transient confirmations at bottom-right and never carry a decision.
Modal & drawer
Modal for a decision that needs a reason (void, reject, flip a flag). Drawer for a record detail you peek at without leaving the list.
Empty & loading
Nothing pending
Everything older than 24 hours has been actioned.
Timeline & stepper
Timeline for follow-up logs and history. Stepper for approval state and multi-step wizards.
- Booked trial. Next action 2026-09-09.
- Record created.
Mobile shell primitives
360px minimum width. .phone, .m-topbar, .m-body, .m-tabbar, .m-card, .m-list-item and .att-btn live in components.css alongside the desktop set — same tokens, same badges. Touch targets are 44px minimum via .touch.
Do / don't
- Use the status badge component for every statusNever a coloured word, never a custom colour. If a new status appears, add it to tokens first.
- Don't invent a second date/time/money formatPick one per kind for the app and use it everywhere.
- Right-align money, left-align text, centre nothingMoney columns get
.money. Totals intfoot. - Don't put two primary buttons on one screen regionOne primary in the page header, one in a modal footer. Everything else is secondary or ghost.
- Every destructive or money-changing action needs a reason fieldVoid, reject, override, refund.
- Don't restyle a component per appIf it doesn't fit, extend tokens/components here and re-copy — don't fork with inline styles.
Using this kit in a new app
- Copy the whole
assets/folder (tokens.css,components.css,app.js) into the new app. - Load Google Fonts Inter + JetBrains Mono, then
tokens.css, thencomponents.cssin<head>. - Load
app.jsat the end of<body>— it injects the icon sprite and wires up tabs, modals, toasts and the live clock automatically. - Build screens with the classes documented on this page. Don't edit the copied files in place — see
README.mdfor how changes flow back.