Design tokens & components
Everything on this page is rendered live from assets/tokens.css and assets/components.css. Change a token there and every prototype page follows. Admin portal is desktop-first at 1280px, light theme only in v1; the teacher portal reuses the same tokens at 360px.
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 in the requirements maps to exactly one badge. The same colour never means two things.
- Dense but calmAdmins live in tables all day. 13px 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.
- Branch is always visibleThe branch switcher never scrolls away. Every list and form implicitly belongs to it.
- Built for reviewAnything mocked or unresolved gets a yellow dashed "prototype note" so branch admins know what to comment on.
Colour
Primary is a deep plum, quiet enough for all-day use; gold accent is reserved for trials and highlights. 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, invoice numbers, IC 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 (section 3 rules)
These are global rules, not preferences. Every screen, export and log uses them. Helpers exist 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, slot history |
| Date | 2026-09-06 | .date | Lists, From/To pickers, invoice dates |
| Time | 20:30 | .time | Timetable, slot start, room bookings (:00 / :30 only) |
| Money | RM 1,234.00 | .money | Right-aligned in tables, always two decimals |
| Negative money | (RM 50.00) | .money.neg | Deposit refunds, payment reversals, deductions |
| Live clock | [data-now] | Sidebar footer, run screens |
Icons
Stroke icons at 16px (18px in the 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 (style, branch, role) with no dot. Every status word from the requirements is below; nothing else gets a badge.
Stat tiles & cards
Customer
Member- Name
- Tan Mei Ling
- IC
- 820405-10-5566
- Phone
- 012-345 6789
- Students
- Tan Jia Yi (Ballet Grade 2), Tan Jia Hao (Kids Jazz)
- Replacement count
- 2.5 credits · expire 2026-12-31
- Outstanding
- RM 240.00
Salary sheet · Ms C · 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 plum. Toolbar sits above with search and filters; pagination below.
| Slot | Class | Teacher | Status |
|---|---|---|---|
| 2026-09-05 10:00 | Ballet Grade 1 | Ms A | Pending |
| 2026-09-05 11:30 | Kids Jazz Group | Ms C | Pending |
Tabs
Used inside detail pages (Customer, Class, Salary sheet). 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 chargeable). Drawer for a record detail you peek at without leaving the list (slot, invoice, lead).
Empty & loading
No pending work
Every slot older than 24 hours has attendance marked. Salary sheets can be confirmed.
Timeline & stepper
Timeline for follow-up logs, slot history and approval history. Stepper for the salary approval state and the convert-to-client wizard.
- Booked free trial in Ballet Grade 1, 2026-09-08 10:00. Next action 2026-09-09: call after trial.
- Called. Interested in Saturday morning ballet for 6-year-old. Source: Facebook.
- Lead created from walk-in form.
Timetable primitives
Week grid in 30-minute rows (dashed half-hour lines). Slot chips are coloured by Style, striped cells are holidays or off-days, green cells are idle capacity on the room availability grid. Trial and rescheduled variants shown.
Pipeline cards (CRM)
Mobile shell (teacher portal)
360px minimum. Top bar shows the branch (switchable for multi-branch teachers), four bottom tabs, and attendance buttons at 40px height with full-width targets. Same tokens, same badges.
Phone numbers hidden (per-teacher setting).
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 show 12-hour time, month names or "ago"No "3:30 PM", no "6 Sep", no "2 hours ago". The strict formats are the only ones.
- Right-align money, left-align text, centre nothingMoney columns get
.money. Totals intfoot. - Don't put two primary buttons on one screenOne 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, flip chargeable, salary override, deposit refund.
- Don't pro-rate, auto-run or auto-fill anything in the UIFee Run and Salary Run are buttons; pro-rating is a manual open-amount invoice; attendance is marked by a person.
- Show who and when on anything approved or overriddenName · yyyy-MM-dd HH:mm:ss, inline next to the status.
- Don't mix branches in one listExcept under "All branches" for Super Admin, which is read-only and shows a Branch column.