Design system · @bebshai/ui
Foundations
Tokens and rules from docs/design/admin-monitoring.md, as defined in packages/ui/src/styles/globals.css. Switch the theme in the header to compare light and dark.
Backgrounds (bg/*)
Separated by tone and border, never by shadow. In dark mode surfaces sit just above the canvas.
--bg-canvasbg-canvas · page--bg-surfacebg-surface · cards, panels, sheets--bg-surface-raisedbg-surface-raised · menus, dialogs--bg-surface-sunkenbg-surface-sunken · wells--bg-mutedbg-muted · tracks, code--bg-hoverbg-hover · pointer and keyboard highlight--bg-selectedbg-selected · selected row, current item--bg-disabledbg-disabled--hover-canvashover on the canvas (automatic)--muted-canvastracks on the canvas (automatic)--hover-raisedhover in menus (automatic)--sidebarbg-sidebar · white / canvas--inversebg-inverse · tooltips, kbdStrokes (border/*)
Close to the background. Row separators are the quietest, card and input borders one step up.
--separatorborder-separator · table rows, dividers--border-defaultborder-default · cards, menus--border-inputborder-input · inputs, selects--border-strongborder-strong · dashboard cards, switch track--border-controlborder-control · checkbox and radio--border-focusring-focus · focusText and icons (text/*)
Icons are muted and smaller than the text beside them; only the active nav icon is full ink.
--text-defaulttext-default · on the canvas--text-on-surfacetext-on-surface · on surfaces--text-mutedtext-muted--text-selectedtext-selected--text-disabledtext-disabled--icontext-icon--linktext-linkBrand (brand/*)
Accent is brand decoration, never state: state uses hover and selected.
--brand-primarybg-primary / text-on-primary--brand-secondarybg-secondary / text-on-secondary--brand-accentbg-accent / text-on-accentStatus (status/*)
Solid for dots, bars, icons and filled badges (ink: on-solid); subtle fills carry on-subtle ink. Always pair colour with an icon or a label.
--status-success-solidbg-success-solid / text-success-on-solid--status-success-subtlebg-success-subtle / text-success-on-subtle--status-warning-solidbg-warning-solid / text-warning-on-solid--status-warning-subtlebg-warning-subtle / text-warning-on-subtle--status-error-solidbg-error-solid / text-error-on-solid--status-error-subtlebg-error-subtle / text-error-on-subtle--status-info-solidbg-info-solid / text-info-on-solid--status-info-subtlebg-info-subtle / text-info-on-subtleCharts (chart/*)
Figma series, estimate, ordinal ramp, grid and baseline, then the app's extra categorical hues. Use hues in sequence, not by meaning.
--chart-series-1--chart-series-2--chart-estimated--chart-muted--chart-ordinal-1--chart-ordinal-2--chart-ordinal-3--chart-negative--chart-grid--chart-baseline--chart-3--chart-4--chart-5--chart-6--chart-7--chart-8Severity
Log levels in badges and histogram stacks.
--severity-debug--severity-info--severity-warn--severity-error--severity-fatalScrims and tints
Sheets and dialogs dim the page with overlay; popovers and menus with overlay-soft. Tints mark diff lines.
--overlay--overlay-soft--tint-add--tint-delPrimitives
The Figma palette, exact hex. Only globals.css and this page name them; feature code uses the tokens above.
--green-50--green-100--green-200--green-300--green-400--green-500--green-600--green-700--green-800--green-900--green-950--olive-50--olive-100--olive-200--olive-300--olive-400--olive-500--olive-600--olive-700--olive-800--olive-900--olive-950--slate-50--slate-100--slate-200--slate-300--slate-400--slate-500--slate-600--slate-700--slate-800--slate-900--slate-950--stone-50--stone-100--stone-200--stone-300--stone-400--stone-500--stone-600--stone-700--stone-800--stone-900--stone-950--blue-50--blue-100--blue-200--blue-300--blue-400--blue-500--blue-600--blue-700--blue-800--blue-900--blue-950--sky-50--sky-100--sky-200--sky-300--sky-400--sky-500--sky-600--sky-700--sky-800--sky-900--sky-950--teal-50--teal-100--teal-200--teal-300--teal-400--teal-500--teal-600--teal-700--teal-800--teal-900--teal-950--red-50--red-100--red-200--red-300--red-400--red-500--red-600--red-700--red-800--red-900--red-950--amber-50--amber-100--amber-200--amber-300--amber-400--amber-500--amber-600--amber-700--amber-800--amber-900--amber-950--purple-50--purple-100--purple-200--purple-300--purple-400--purple-500--purple-600--purple-700--purple-800--purple-900--purple-950--rose-50--rose-100--rose-200--rose-300--rose-400--rose-500--rose-600--rose-700--rose-800--rose-900--rose-950--lime-50--lime-100--lime-200--lime-300--lime-400--lime-500--lime-600--lime-700--lime-800--lime-900--lime-950--white--neutral-canvas--neutral-subtle--neutral-border--neutral-ink--neutral-text-mutedStrokes in use
The three stroke tokens stacked the way a list page uses them.
Icon scale
Tabler icons, muted by default (text-icon). Always smaller than the text next to them.
| Context | Size | Stroke | Example |
|---|---|---|---|
| Beside 14px text (nav, page) | size-4 · 16px | 1.75 | Search |
| Inside buttons and inputs (13px) | size-3.5 · 14px | 1.75 | Filters |
| Chips and facets (the +) | size-3 · 12px | 2 | Level |
| Inside badges | ≈11px | 2.2, currentColor | See Components → Status badges |
Type
Inter for everything, Geist Mono for ids, routes and code. Every size is a rem token in globals.css, so it follows the root font size.
text-title1.25rem · 20px 600Page title
text-metric1.375rem · 22px 600৳12,480
text-fact0.9375rem · 15px 600৳999 / month
text-heading0.9375rem · 15px 600Sheet and dialog title
text-panel0.8125rem · 13px 600Panel and card title
text-body0.8125rem · 13pxBody, tables and controls: the main UI default
text-label0.75rem · 12px 500Form label
text-small0.75rem · 12pxGroups and metadata labels
text-code0.75rem · 12px mono01a0e7e8-83bf-7b62 · /v1/admin/tenants/{id}
text-overline0.6875rem · 11px 500Table header
text-caption0.6875rem · 11pxHelper and secondary text
text-badge0.6875rem · 11px 500Status and version chips
Motion
One duration (--duration-base, 200ms) and one curve (ease-out: cubic-bezier(.2,.7,.2,1)). prefers-reduced-motion sets the duration to zero.