# ThaiHao Design System

> Multi-tenant cross-border commerce platform connecting Thai SME producers with Chinese consumers through KOL/KOC live commerce.

This folder is the **distilled, designer-facing form** of the ThaiHao visual system. It contains tokens, fonts, logos, design-system preview cards, and high-fidelity UI kits for the platform's five frontends. It is a sibling to the engineering specs (`DESIGN.md`, `thaihao_component_spec.md`, master spec) — those documents remain the source of truth; this folder makes them buildable.

---

## The product, in one screen

ThaiHao is **not a single frontend** — it is five distinct surfaces sharing one design language. Mixing them up is a category error.

| Surface | Audience | Default locale | Device | Density |
|---|---|---|---|---|
| **Producer portal** (`apps/web`) | Thai SME owners + brand managers | th-TH | Mobile-first | Medium |
| **KOL portal** (`apps/kol`) | Individual KOLs/KOCs + agencies | zh-CN | Mobile-first | Medium-high |
| **Admin console** (`apps/admin`) | Platform staff (sysadmin, finance, sales, compliance, support) | en-US | Desktop-only | High |
| **Consumer storefront** (`apps/store`, Phase 5+) | Chinese end consumers | zh-CN | Mobile-first | Low |
| **Partner portal** (`apps/partner`, Phase 3+) | Logistics / payment / fulfillment partners | en-US | Desktop + tablet | High |

Brand personality: **Reliability · Authority · Clarity.** Aesthetic: **Corporate / Modern Enterprise** — clean, high-density information balanced by generous whitespace. The brand is in service of trust, not flair.

---

## Source materials

Everything here was distilled from the following inputs (read-only references; do not assume the reader has access):

- **Local codebase** mounted via File System Access API at `06-claude-design/`. Key files:
  - `06-claude-design/00-product-surfaces-master-spec.md` — authoritative product spec (personas, modules, reports, i18n)
  - `06-claude-design/01-onboarding-brief.md` — the intent statement for Claude Design
  - `06-claude-design/02-design-system-digest.md` — distilled tokens, invariants, components (primary source for this kit)
  - `06-claude-design/03-screen-prompts/phase-1/` — 10 per-screen prompts (auth, onboarding, brand switcher, admin tenant list, admin sanctions, admin audit)
  - `06-claude-design/04-handoff-to-claude-code.md` — round-trip back to Claude Code
- **Brand logo files** uploaded by the user, copied into `assets/` (see § Iconography below).
- Referenced but **not included** (kept in the engineering repo): `DESIGN.md`, `thaihao_component_spec.md`, `thaihao_wireframes_reference.md`, `thaihao_persona_analysis.md`, `thaihao_blueprint_v1_2_consolidated.md`.

If any of those external files become available, treat them as higher authority than this folder.

---

## The non-negotiable design discipline (D1–D10)

Every design decision is checked against these ten invariants. Refuse drift; offer the closest compliant alternative.

1. **D1 — Two font weights only.** 400 regular and 500 medium. **Never bold.** Hierarchy comes from size, color, and spacing.
2. **D2 — Sentence case in all UI copy.** No Title Case, no ALL CAPS. The one exception is the `label-caps` style (tracked uppercase, used only for section labels).
3. **D3 — No emoji in UI.** Tabler outline icons exclusively. The only permitted emoji is a locale flag inside a `LanguageFlag` atom.
4. **D4 — All colors via CSS variables / Tailwind tokens.** No hardcoded hex in components — per-tenant theming and dark mode depend on this.
5. **D5 — Quad-column currency display.** `amount · ISO code · trust pill · fx context if cross-currency`. Never strip to a single value. Never use `$` without disambiguation.
6. **D6 — Every estimated value carries a visible trust signal.** Users scan trust *before* value.
7. **D7 — ReasonCodeSelector gates every revoke / suspend / refund / override / force-unlock.** Submit stays disabled until a reason is chosen.
8. **D8 — Every user-visible string goes through i18n.** Producer portal opens in th-TH, KOL portal in zh-CN, admin in en-US. Switch via `LanguageFlag` in the topbar.
9. **D9 — WCAG 2.1 AA baseline.** Custom focus rings, ARIA labels for icon-only buttons, 4.5:1 body contrast, errors conveyed by more than color.
10. **D10 — Every value derived from a state transition has an inline `AuditLink`** that opens an audit trail drawer.

---

## Content fundamentals — how copy is written

The voice is **factual, calm, and specific**. ThaiHao users are entrusting the platform with money, identity documents, and cross-border compliance — the copy is the visible surface of that trust. Be plain. Avoid marketing energy.

**Tone:** Professional, declarative, never cute. No exclamation marks (with a single exception: critical security notifications). No "Oops". No "Let's get started". No second-person hype. The copy describes what the system did or will do, then names the next action.

**Casing:** Sentence case everywhere — page titles, button labels, table headers, modal titles. The single exception is `label-caps` style, a tracked-uppercase 11px Inter Medium used for table column headers and small section labels. Title Case in UI is a bug.

**Person:**

- **You** for the user: *"You can resubmit in 28 days."*
- **We** for the platform, sparingly, when accountability matters: *"We screen every signup against international sanctions lists."*
- Avoid first-person plural marketing voice (*"We're so excited…"*).

**Density:** Short, specific sentences. One idea per sentence. Use numbers; cite SLAs; cite cooldowns; cite exact thresholds. Compare:

- ❌ *"Your account needs some additional checks before you can get going."*
- ✅ *"Your information matched an entry on the international sanctions list. Our team will contact you within 2 business days."*

**Trust micro-copy.** Anywhere a user might assume worst-case (sanctions hit, KYC reject, frozen pipeline), pair the factual statement with a one-line trust note: *"This screen is part of standard international compliance. It does not mean you did anything wrong."* These notes live near the relevant card, not in a separate help page.

**Errors.** Name the field, name the rule, name the fix. *"Password must be at least 12 characters."* — never *"Password is invalid"*. Never show stacktraces; show a friendly summary plus a `reference_id` the user can share with support.

**Empty states.** Factual, single sentence, optional primary action. *"No bookings yet. Bookings appear here once a producer confirms a slot."* Never *"Oops, looks empty!"* Never illustrations of confused characters.

**Numbers + currency** follow D5. Always show ISO code (`THB`, `CNY`, `USD`), always show the trust pill, always show fx context when cross-currency. Never bare `¥` or `฿`.

**No emoji.** No emoji in copy, in buttons, in headings, in placeholders. The only emoji in the entire system is the locale flag inside `LanguageFlag`.

**Examples (drawn from the screen prompts):**

| Surface | Example | Why it works |
|---|---|---|
| Producer signup CTA | `สร้างบัญชี` ("create account") | Plain verb, sentence case, no decoration |
| Sanctions-hit notice | `ต้องตรวจสอบเพิ่มเติม` + 2-line trust note | Names the situation, names the SLA, defuses panic |
| KOL earnings cell | `¥85,000 CNY [Estimated] (≈฿404,000 THB at fx_ref 1:4.75)` | Quad-column currency in full |
| Admin bulk-suspend confirm | "Suspend 5 tenants" + dual-approver picker | Counted, explicit, gated by reason code |
| Empty state | "No tenants match these filters." + "Try removing filters or adjusting your search." | Factual + actionable |

---

## Visual foundations

**Colors.** A two-axis palette. *Brand* (ThaiHao Red `#AC0022` and its hover/pressed/tint) is for CTAs, brand marks, and the active nav state — never for status. *Surface* is a tonal layer system (`--surface` page background → `--surface-container-lowest` → `--low` → `--container` → `--high` → `--highest`) used in place of shadows for in-flow elevation. *Semantic state* (info / success / warning / danger) is its own tint family used for pills, banners, and trust signals. **Night mode** is a token swap (`[data-theme="dark"]` on `<html>`) — surfaces shift to a deep neutral, primary lifts to `#DA2C45` for AA contrast, semantic tints invert. Per-tenant theming overrides only `--thaihao-primary`.

**Type.** Three families, two weights, seven scales. **IBM Plex Sans** for display + headline (the trust-signal serif-adjacent grotesque). **Inter** for everything UI (body, titles, labels). **JetBrains Mono** for numbers, IDs, hashes, currency amounts in tables (the "data-mono" style). Co-fonts for CJK: Noto Sans Thai (th-TH) and Noto Sans SC (zh-CN) are loaded alongside so mixed-script lines align cleanly. Weights are strictly 400 and 500 — see D1.

**Spacing.** 4px base. Everything is a multiple of 4. Common gaps: 8/16/24. Page margins: 32px desktop, 16px mobile. Container max width 1440px. Gutter 24px.

**Borders.** A three-tier system whose default is unusually thin — the *signature* visual move. 0.5px (`--border-thin`) is the default on cards, dividers, and table rows; it reads as precision rather than weight. 1px is reserved for inputs and emphasized cards. 2px is reserved for the *intent bar* — a left-edge accent on the active table row or active nav item, always in `--thaihao-primary`. Border colors are tokenized; default is `--outline-variant`.

**Radii.** A descending scale. 2px for chips, 4px for buttons and inputs (the default), 6px for mid controls, 8px for cards (the signature card radius), 12px for modals and sheets, full for pills and avatars.

**Elevation.** Tonal layers do most of the work. Cards in the page flow are surfaced by going *up* one container level (e.g. an `--low` card on a `--surface` page) — not by adding shadow. Shadows are reserved for *floating* elements only: modals, dropdowns, popovers. `--shadow-floating` is a soft, low-spread shadow that signals "I am detached from the page" without being dramatic.

**Backgrounds.** Solid colors. No gradients on CTAs (refuse: see refusal patterns). No background imagery in the chrome of any portal. Photography appears only where the product domain calls for it — KOL profile photos in the KOL portal, product imagery in the catalog, live thumbnails in the live commerce flow, hero photography on the marketing site. No decorative SVG patterns. No hand-drawn illustrations. No textures.

**Hover states.** Subtle. Buttons darken to `--thaihao-primary-hover` (`#C81F35` in light, `#EC4459` in dark). Rows shift to `--surface-container-low`. Links underline. Cards do not lift on hover (no shadow change in-flow). 150ms ease-out.

**Press states.** Buttons step to `--thaihao-primary-pressed` (`#800017` in light, `#B81829` in dark) plus a 1px y-offset; no shrink, no scale transform. Tap targets on mobile are ≥44px.

**Motion.** Subtle, fast, functional — never decorative. 150ms ease-out for color/opacity, 200ms ease-out for transform. Modal entry is a 200ms fade + scale (0.96 → 1.0). Drawer entry is a 250ms slide. No page slide transitions — they break perceived performance. Skeleton loaders pulse at 800ms in 50% opacity range. Respect `prefers-reduced-motion: reduce` — replace transforms with instant changes or opacity-only fades.

**Transparency and blur.** Used **only** for floating overlay scrims (modal backdrop: `rgba(0,0,0,0.40)`) and the iOS-style topbar of mobile shells (a `backdrop-filter: blur(12px)` over a semi-opaque surface). Never used for cards, buttons, or text containers. No glass-morphism.

**Tables.** The most-used pattern in admin and producer portals. Dense rows 36–44px, internal padding 8–12px. Sticky `label-caps` header on `--surface-container-low`. Numeric columns right-aligned in `data-mono`. Hovered row: `--surface-container`. Selected/active row: 2px `--thaihao-primary` left intent bar. Action column is always last, icon-only with tooltips. Wide tables on small screens scroll horizontally within the card, not the page; first column stays sticky.

**Trust signals.** A first-class visual language. Estimated/Provisional/Locked/Final/Disputed/Pending-review are pills with their own tint family. Trust pills sit inline immediately right of the value they qualify, or in the same cell. They are *always* present on monetary values that may move.

**Iconography color.** Icons inherit text color by default. Semantic state icons use the matching `--color-text-on-{info|success|warning|danger}`. Brand red for the active nav icon. No icon in a third color.

**Imagery vibe.** When imagery appears: warm but neutral white-balance, no heavy filters, no grain, no duotone treatments. Editorial on marketing, product-catalogue clean on producer/storefront, candid-on-set for KOL profiles, none in admin.

---

## Iconography

**Library:** [Tabler Icons](https://tabler.io/icons) — outline by default. Filled variants are reserved for *active/selected* states only (e.g. the active mobile tab in the producer portal).

**Stroke widths by surface (the one place stroke weight varies):**

- 1.5px on producer portal, KOL portal, marketing site, consumer storefront
- 1.25px on admin console and partner portal (tighter for density)

**Sizes:** 16px inline-with-body, 20px button-internal, 24px standalone, 32px large emphasis.

**Color:** inherits text color by default. Semantic icons use the matching semantic palette. No tinted icons in a non-state context.

**Delivery:** consume from CDN via the official Tabler package, not as inline SVGs in components — keeps bundle size honest and ensures every icon comes from one trusted geometry.

- React: `@tabler/icons-react`
- CDN (HTML prototypes): `https://unpkg.com/@tabler/icons-webfont@latest/tabler-icons.min.css` (web font) **or** `https://cdn.jsdelivr.net/npm/@tabler/icons@latest/icons/{name}.svg` (individual SVGs)

The UI kits in this folder use the CDN web-font form so prototypes work offline-ish without a build step.

**Emoji.** None. The *one* exception is country flag emoji inside the `LanguageFlag` atom — and only there because flag emoji rendering is locale-correct on every modern OS in a way SVG flags are not.

**Unicode characters as icons.** Avoided. No `•`, `›`, `✓`, etc. used as glyphs — use the Tabler equivalent.

**Logos and brand marks** live in `assets/`:

| File | Use |
|---|---|
| `assets/thaihao-logo-mark.png` | Square app icon, mobile-launcher, favicon source, sidebar collapsed state |
| `assets/thaihao-logo-wordmark.png` | Full wordmark + tagline. Marketing site, signup screens, footer |
| `assets/thaihao-logo-wordmark-small.png` | Same wordmark, smaller render |

Per-tenant theming swaps `--thaihao-primary` to a tenant's color; the logo mark itself stays ThaiHao red because it is the *platform* mark, not the tenant's.

---

## Font substitution flag (please review)

The brand stack is **IBM Plex Sans + Inter + JetBrains Mono** for Latin, with **Noto Sans Thai** and **Noto Sans SC** as CJK companions. All five are loaded from **Google Fonts** in `colors_and_type.css`, not from local `.ttf` files in this kit.

**What this means:** If the engineering team has licensed self-hosted copies of these families (or prefers a CDN like fonts.bunny.net for privacy), please drop the font files into `fonts/` and update `@import` to a local `@font-face` block. The current Google-Fonts setup is correct for **prototyping** — it matches the official typographic specification — but production deployments often want self-hosted fonts for performance and privacy.

No substitutions were necessary — the stack is fully covered by Google Fonts.

---

## Index — what's in this folder

```
.
├── README.md                  ← you are here
├── SKILL.md                   Agent Skill manifest — usable in Claude Code
├── colors_and_type.css        All tokens — colors, type, spacing, motion, borders, radii
├── assets/                    Logos and brand marks
│   ├── thaihao-logo-mark.png
│   ├── thaihao-logo-wordmark.png
│   └── thaihao-logo-wordmark-small.png
├── preview/                   Design System tab cards (12+ small HTML files)
│   ├── colors-primary.html
│   ├── colors-surface.html
│   ├── colors-semantic.html
│   ├── colors-trust.html
│   ├── type-scale.html
│   ├── type-families.html
│   ├── type-mono.html
│   ├── spacing-scale.html
│   ├── radii.html
│   ├── borders.html
│   ├── elevation.html
│   ├── icons.html
│   ├── logo.html
│   ├── buttons.html
│   ├── pills.html
│   ├── status-dots.html
│   ├── trust-pills.html
│   ├── inputs.html
│   ├── currency-display.html
│   └── table-row.html
└── ui_kits/
    ├── producer-portal/       Thai-first, mobile-first (Khun Somchai's surface)
    ├── kol-portal/            Chinese-first, mobile-first (Li Wei's surface)
    ├── admin-console/         English, desktop-only (Sarah Tan's surface)
    ├── c-suite-portal/        English, desktop · aggregated read (Daniel Park's surface)
    ├── employee-portal/       Department-scoped, desktop (Sales / Care / Finance / Ops)
    ├── partner-portal/        Fulfillment / logistics / distributor, desktop (Phase 3+)
    ├── consumer-storefront/   Chinese-first mobile · live commerce (Phase 5+)
    └── auth-flows/            Sign-up · log-in · reset · MFA · suspicious login
```

Each UI kit has its own `README.md` and an `index.html` that boots an interactive click-thru of the most representative screens for that surface.

---

## Quick reference card

```
COLORS    #AC0022 primary · #C81F35 hover · #800017 pressed · semantic state tints
FONTS     IBM Plex Sans · Inter · JetBrains Mono (+ Noto Sans Thai/SC)
WEIGHTS   400 + 500 only
CASE      Sentence case (label-caps the only uppercase)
ICONS     Tabler outline · 1.5px stroke (1.25 admin)
BORDERS   0.5 thin · 1 default · 2 primary intent
RADIUS    4 buttons · 8 cards · 12 modals · full pills
SPACING   4px base · 24 gutter · 32/16 page margin
LOCALES   th-TH producer · zh-CN kol/consumer · en-US admin
CURRENCY  amount + ISO code + trust pill + fx context
TRUST     Estimated · Provisional · Locked · Final · Disputed · Pending review
A11Y      WCAG 2.1 AA · focus rings · ARIA labels · errors not by color alone
DENSITY   medium producer/kol · high admin · low consumer
NO        emoji · bold · ALL CAPS · raw hex · single $ symbol · gradients on CTAs
```
