Components
Buttons, inputs, cards, badges, banners, tables, tabs, navigation, modal and footer — rebuilt from tokens.
Each component is rebuilt from tokens only. Tags show what was observed on the live site versus what is proposed to close a gap found in the audit (hover, focus, error and disabled states).
Buttons observed: 33 variants · 454 instances
Six overlapping class families on the site collapse to four intents × two sizes: btn-teal/btn-primary → primary, btn-gray/btn-secondary → secondary, btn-danger → danger, btn-ghost → ghost.
States proposed
Observed: only .btn:disabled{opacity:.5}. No hover, active or author focus style exists on .btn; keyboard focus uses the browser default ring.
Inputs observed: 8 variants · 665 instances
States proposed
Observed: radius alternates 6/7/8px, heights 26–41px, 720 fields have only placeholders for labels, no :invalid/aria-invalid styling, errors are detached .err blocks.
Cards observed: 6 variants · 43 instances
Card title
bg.surface · border.default · radius.lg · shadow.card · padding space.6 (the site uses 18px).
Badges & pills observed: 22 variants · 122 instances
Fill the brand pill with primary.default (6.3:1), not accent.bright (3.68:1 — fails).
Banners observed: 6 variants · 7 instances
Tables observed: 7 variants · 33 instances
| Bill | Branch | Status |
|---|---|---|
| RC000001 | M0001 | new |
| RC000002 | M0002 | in progress |
Sample data is fictional. Add scope to every th (167 lack it) and wrap wide tables in a scroll container (6 pages overflow at 390px).
Tabs
Three tab idioms exist on the site (.btn-tab, .btn-sub, .tab); this is the primary one.
Navigation observed: 7 variants · 15 instances
Top bar: primary.default with white text; chip uses overlay.on-primary-*. The site has .topbar and .top variants and a JS-built user menu; no <nav>, <header> or <main> landmarks (this guide adds them).
Modal observed: 5 dialogs, 4 implementations
Dialog title
Body copy explaining the action.
Static render of the proposed single dialog: z-index 2000, scrim overlay.modal, 420px, radius.lg, shadow.modal, role="dialog" aria-modal="true", one primary blue, Esc + ✕ + Cancel to close, focus trap.
Observed on the site
| Dialog | z | Scrim | Width | Primary button | ARIA |
|---|---|---|---|---|---|
| First-change password (login) | 2000 | 0.5 | 420 | #1d5fb4 · 13.5px | dialog |
| POS gate (bills) | 2000 | 0.45 | 420 | #1d5fb4 · 13px | dialog + aria-modal |
| Change password (user menu) | 2000 | 0.5 | 420 | #2563eb · 13.5px | dialog + aria-modal |
| CS ticket (review) | 50 | 0.45 | 520 | #2f6fd6 · 14.5px · radius 9 | none |
| Settings confirm | 2000 | 0.45 | 480 | #1d5fb4 · 14px | dialog + aria-modal, ✕, Esc |
Errors & empty states observed: 4 error treatments, 4 empty treatments
Field error proposed
Form-level error observed (login) · restyled with tokens
Observed treatments: boxed pink message on login / first-change (#c0392b on #fdecea, border #f3c1bc), boxed on change-password at 13.5px (#b91c1c on #fef2f2), plain red text on the POS gate (#c0392b) and CS ticket (#b3261e), and a bold inline line on stock check. All pass AA (4.76–6.54:1); none is announced or tied to its field. Proposed: one boxed treatment with role="alert".
Empty state proposed
Observed: bills shows headers only (no message), orders a dash-wrapped row, audit a different dash-wrapped row, rx-lookup a plain line outside the table, user management a plain row.
Drawer observed: 1
Order history
Side panel (520px on the site), shadow.drawer, z-index 50, no scrim, no role. Opened by clicking a table row (a mouse-only onclick on tr).
Footer
The site has no footer; a fixed bottom-right version chip is the only persistent footer-like element.
Links observed: 11 variants · 124 instances
#0000ee.