Design System

Tokens, primitives and composition patterns powering MDX Engage. Single source of truth in apps/web/src/components/ui/.

How to use

Import primitives from @/components/ui/primitives and the page chrome from @/components/ui/shell. Stick to the StatusTone token for semantic color instead of hand-picked Tailwind shades.

import { Button, Card, Pill } from "@/components/ui/primitives";
import { AppShell } from "@/components/ui/shell";
// Surface tokens live in
primitives.statusToneClass
// (neutral | blue | green | red | amber)

01 · Tokens

Status tones

Semantic color scale. Use via tone prop on Pill, Dot, Stat, Banner. Never hand-roll color for status.

neutral
Pill label
tone="neutral"
blue
Pill label
tone="blue"
green
Pill label
tone="green"
red
Pill label
tone="red"
amber
Pill label
tone="amber"

02 · Tokens

Surfaces & dividers

Layered dark surfaces and border alphas. Hex values should NOT appear outside ui/ and layout.tsx.

app bg#08090c
sidebar bg#0a0b0e
card bg#0e1014
surface /02rgba(255,255,255,0.02)
surface /04rgba(255,255,255,0.04)
surface /08rgba(255,255,255,0.08)
divider /08rgba(255,255,255,0.08)
divider /10rgba(255,255,255,0.10)

03 · Tokens

Radii

Rounded scale used across chrome. Cards default to xl; hero-style Metric/Section cards use [1.5rem]/[1.9rem].

rounded-md
rounded-lg
rounded-xl
rounded-[1.5rem]
rounded-[1.9rem]

04 · Tokens

Typography

Geist Sans + Geist Mono. Compact scale optimized for information density on an operator console.

ReviewPage title
Continue learningSection title
Watchlist accountsCard title
Normal paragraph copy.Body
Description under a title.Muted body
Helper caption.Small / hint
Today publishedEyebrow

05 · Primitives

Button

primary = emphasized action · secondary = default · ghost = low-emphasis · danger = destructive.

Size md (default)

Size sm

06 · Primitives

Pill & Dot

Inline status markers. Combine Pill + Dot for list rows where a glanceable indicator sits next to context.

QueuedIn reviewApprovedRejectedRate blocked publisher · ready cooldown 69s failed × 3

07 · Primitives

Banner

Inline notifications placed above a panel or toolbar. Prefer Banner to hand-made alert divs.

Feed sync degraded. Latest review snapshot in use.
Candidate published. Event #127 recorded.
Daily cap reached. Publishing paused until 08:00 America/Caracas.
Publish adapter returned HTTP 500 after 2 retries.
No active filters. Showing all 24 candidates.

08 · Primitives

Card & CardHeader

Primary container. Pass padding=none|sm|md|lg to control internal spacing. Use CardHeader for title rows.

padding="sm"

Tight container for list rows.

padding="md" · default

Standard panel spacing.

padding="lg"

Breathing room for empty/hero states.

With CardHeader

Dense title + description + action slot, optimized for panel tops.

Body content sits under the header with a consistent 16px gap.

09 · Primitives

Forms: Field + input tokens

Form controls use shared class strings (inputClass, selectClass, textareaClass) to stay visually uniform.

Anatomy

Field renders the label + hint row; inputs bring the border, focus ring and placeholder color.

  • inputClass — base text/number/email/time inputs
  • selectClass — adds appearance-none
  • textareaClass — adds resize-y + leading
  • • Focus ring is always blue-500/40 — do not override per field.

10 · Data display

Stat (primitive) vs MetricCard (composed)

Both render KPI tiles. Stat is compact and tone-ring based; MetricCard is taller with a gradient glow. Prefer Stat for dense grids, MetricCard for hero headers.

Stat — 4×

In review

12

Approved today

7

Rate blocked

3

Failed

1

MetricCard — 3×

Today published

12 / 20

Cap resets at midnight America/Caracas.

Success rate

94%

Trailing 7 days across 189 publishes.

Cooldown

69s

Next publish eligible in just over a minute.

11 · Patterns

Empty state + list composition

Use Empty for zero-state surfaces. Compose Card rows inside a SectionCard to match the existing operator screens.

No watchlist accounts yet

Import a handle list or add accounts one by one to start discovering opportunities.

Queue preview

Composition example — 3 rows, real spacing.

@marcelocedeno

Wireframes matter more than pixels early on.

In review

@richmtz

Design systems lose value without adoption metrics.

Approved

@mdx_inc

Shipped rate-limit Phase 2 this morning.

Rate blocked

12 · Guardrails

Do / Don't

Keep new screens on-brand by following these rules.

Do

  • Use StatusTone for all semantic color.
  • Reach for Card before rolling a new panel div.
  • Keep hex values inside ui/ and layout.tsx.
  • Wrap forms with Field for label + hint alignment.
  • Use Stat in dense grids, MetricCard in hero rows.

Don't

  • Don't hand-pick Tailwind colors per component — pass a tone.
  • Don't duplicate rounded-xl border border-white/8 inline — use Card.
  • Don't introduce new radius values outside the scale.
  • Don't override focus rings; the blue ring is intentional.
  • Don't create yet another KPI tile variant — extend Stat/MetricCard.