# Cowork UI Kit — Usage Guidelines

> Rules cho việc CHỌN component nào + LAYOUT thế nào + HIERARCHY ra sao. Đây là phần "ngôn ngữ thiết kế" — không phải code.
>
> File này bổ sung cho `tokens/`, `atoms/`, `molecules/`, `organisms/`, `templates/`, `pages/`. Token + component cho biết "cái gì available". Guidelines này cho biết "khi nào dùng cái nào, và xếp ra sao".
>
> Cross-link memory: [[feedback_ui_default_6_archetype_2_aesthetic]] (6 archetype × 2 aesthetic) + [[feedback_ai_engineer_not_designer]] (AI là engineer, phải compensate gap design bằng rule cứng).

---

## 1. CTA Hierarchy — Luật 1-2-3

**Why:** Mắt người scan view theo visual weight. Nếu 2 button cùng weight cạnh nhau, brain phải decide → friction, cognitive load. 1 button nổi rõ hơn = decision time giảm 40-60% (Hick's Law).

**How to apply — per view (page / screen / modal):**

- **1 primary CTA**: variant `primary`, eye-catching, là main action user nên làm.
- **2 secondary CTA tối đa**: variant `secondary` / `outline`, supporting actions (cancel, learn more, alternative path).
- **3+ tertiary CTA**: variant `ghost` / `link`, low priority (back, skip, dismiss).

**Anti-pattern:** 2 button `primary` cạnh nhau → user không biết click cái nào. Fix: 1 primary + 1 secondary.

```html
<!-- ✓ Good -->
<button class="btn primary">Đặt buổi</button>
<button class="btn secondary">Xem chi tiết</button>

<!-- ✗ Bad -->
<button class="btn primary">Đặt buổi</button>
<button class="btn primary">Xem chi tiết</button>
```

**Exception:** Form wizard cuối flow ("Next" + "Skip") — Next là primary, Skip là ghost/link, KHÔNG cùng primary.

---

## 2. Visual Priority — Where eye goes first

**Why:** Mỗi view phải có 1 "wow point" rõ ràng để mắt landing. Nếu loud everywhere = loud nowhere → flat experience, brain không biết focus chỗ nào.

**How to apply — define 1 "wow point" per view:**

- Hero title huge italic (Instrument Serif `fs-7xl`) — landing page
- Big stat number (`fs-9xl`) — slide deck, dashboard hero metric
- Featured card (gradient bg + `elevation-3` shadow) — pricing recommended tier
- Primary CTA above the fold — conversion page

**Rule cứng:** KHÔNG có >1 wow point per view → eye confused, không landing vào đâu.

**Check trước ship:** Squint test — nheo mắt nhìn screenshot 3 giây, identify ngay cái gì stand out nhất. Nếu mắt nhảy lung tung → fail.

---

## 3. Content Hierarchy

**Why:** Font scale tạo rhythm. Mắt scan headings → body theo size ratio. Nếu mọi text cùng size (all medium) → flat, không guide reading order.

**How to apply — font scale + use case:**

| Token | Pixel | Use case |
|---|---|---|
| `fs-9xl` | 128px | 1 big stat per slide (deck only) |
| `fs-7xl` | 72px | Hero title (landing) |
| `fs-5xl` | 48px | Page H1 |
| `fs-3xl` | 30px | Section H2 |
| `fs-2xl` | 24px | Subsection H3 |
| `fs-lg` | 18px | Article body / long-form reading |
| `fs-base` | 16px | UI body, form labels (also min cho iOS input — tránh auto-zoom) |
| `fs-sm` | 14px | Secondary text, dense table |
| `fs-xs` | 12px | Caption, label, WCAG min |

**Rule:** Mỗi view dùng tối đa **4-5 size cấp khác nhau**. Tránh "all medium" gây flat. Tránh "every size dùng 1 lần" gây chaos.

**Typical mix per archetype:**
- Landing: `7xl` hero + `3xl` section H2 + `lg` body + `sm` caption (4 levels)
- Dashboard: `5xl` KPI + `2xl` widget title + `base` data + `xs` label (4 levels)
- Editorial: `5xl` H1 + `2xl` H2 + `lg` body + `sm` meta (4 levels)

---

## 4. Spacing rules

**Why:** Spacing tạo grouping (Gestalt proximity). Item gần nhau = liên quan. Item xa nhau = tách biệt. Random spacing = brain không parse được structure.

**How to apply — minimum spacing per context:**

| Context | Min spacing | Token |
|---|---|---|
| Inline (giữa chip/badge) | 8px | `space-2` |
| Form fields | 16px | `space-4` |
| Card padding | 24px | `space-6` |
| Card grid gap | 16-24px | `space-4` → `space-6` |
| Section padding (mobile) | 48px | `space-12` |
| Section padding (desktop) | 64-96px | `space-16` → `space-24` |
| Page top/bottom | 64px | `space-16` |

**Rule cứng:** KHÔNG random spacing. Dùng scale, KHÔNG `padding: 22px`. Override scale = anti-pattern.

**Check:** Nếu dev viết `padding: 22px` → phải hỏi "tại sao không phải 20 (`space-5`) hay 24 (`space-6`)?". Nếu không justify được → fix về scale.

---

## 5. Max widths

**Why:** Line dài quá → mắt mỏi (optimal reading 50-75ch). Container rộng quá → cảm giác trống rỗng, lost structure.

**How to apply:**

| Content type | Max width |
|---|---|
| Reading prose | 65ch (~640px) |
| Form column | 480px |
| Card grid container | 1200px |
| Hero text container | 720px |
| Full container (dashboard) | 1400px |

**Rule:** Page width có thể 100vw (full bleed) nhưng **content width phải bounded**. Dashboard table OK rộng (data dense), nhưng paragraph text BẮT BUỘC bounded ≤65ch.

---

## 6. Component decision tree

### Button vs Link

- **Button** (`<button>` + `.btn`): action DOES something — submit, delete, open modal, toggle state.
- **Link** (`<a>` + `.link`): navigation GOES somewhere — new page, external URL, anchor.

**Anti-pattern:** `<a onClick>` triggering JS action without href → fail a11y (screen reader announce "link", user expect navigation).

### Card vs List row

- **Card**: standalone item với 3+ data points + visual emphasis (image, badge, CTA). Use cho gallery, product grid, dashboard widget.
- **List row**: dense scannable items, 1-2 data points focus, single line height. Use cho table, message inbox, settings list.

**Rule:** ≥6 item cùng loại → cân nhắc list row (Card tốn vertical space). ≤4 item → Card OK.

### Modal vs Drawer vs Sheet (mobile)

- **Modal**: critical decision, blocks all background interaction → confirmation ("Xoá đơn này?"), full form ngắn ("Login").
- **Drawer**: side panel for context, doesn't block content perception → filter, settings, sub-task detail.
- **Sheet** (mobile-only): bottom-up, dismissible by swipe-down, lighter than modal → quick action menu, picker.

**Decision:** Phải block user? → Modal. Cần see content while interact? → Drawer. Mobile + quick action? → Sheet.

### Tooltip vs Popover

- **Tooltip**: 1-line passive info on hover/focus → label cho icon-only button, định nghĩa thuật ngữ ngắn.
- **Popover**: rich content (form, list, actions) on click → user menu, date picker, detail card.

**Rule:** Tooltip KHÔNG có interactive element bên trong (no button, no input). Có button → phải dùng Popover.

### Toast vs Banner vs Alert

- **Toast**: ephemeral, auto-dismiss 3-5s, non-critical → "Đã lưu!", "Đã gửi".
- **Banner**: persistent inline, page-level context → "Trial expires in 3 days", "Maintenance 21h ICT".
- **Alert** (inline): in-context warning/error → form validation under field, action confirmation in flow.

**Rule:** Action SUCCESS → Toast. System-level ANNOUNCEMENT → Banner. CONTEXTUAL feedback → Alert.

### Tabs vs Accordion vs Segmented

- **Tabs**: 3-6 mutually exclusive views, content sibling, horizontal nav.
- **Accordion**: many sections (7+), expand on demand, FAQ pattern, vertical stack.
- **Segmented**: 2-4 small option switch, mobile-friendly, view toggle (Grid/List).

**Decision:** ≤4 option + small switch → Segmented. 3-6 view + parallel content → Tabs. 7+ section + sequential reading → Accordion.

### Empty state vs Loading vs Error

- **Empty**: zero data state. Phải có icon + 1-line message + CTA để tạo first item.
- **Loading**: data fetching state. Skeleton matches layout (KHÔNG spinner trống). Skeleton ≥3 rows nếu list.
- **Error**: action failed state. Icon đỏ + error message + retry CTA + (optional) error code.

**Anti-pattern:** Empty state là page trắng. KHÔNG bao giờ. Luôn có cái gì đó (icon emoji + "Chưa có đơn nào" + "Tạo đơn đầu tiên").

---

## 7. Color usage rules

**Why:** Primary brand color là "anchor" của visual identity. Dùng quá nhiều → loãng, không emphasize được. Dùng quá ít → mất brand recall.

**How to apply — Primary brand color:**

- **1 CTA per view** dùng primary (per § 1 CTA Hierarchy)
- **1-2 selected/active state markers** (active tab underline, selected row border)
- **Section accent** (border-left on quote, badge background)
- KHÔNG paint full backgrounds với primary — dùng `--primary-soft` hoặc `--primary-bg` cho tint

**Status colors — semantic only:**

- **Success** (`--success`): completed action, positive delta — "Đã thanh toán", "+12%"
- **Warning** (`--warning`): needs attention, non-blocking — "Trial sắp hết", "Token expire 3 ngày"
- **Danger** (`--danger`): destructive action, error — "Xoá", "Validation failed"
- **Info** (`--info`): neutral context, help text — "Tip: Dùng Cmd+K để search"

**Rule cứng:** KHÔNG dùng status color làm brand accent (vd: dùng đỏ làm CTA chính khi brand color không phải đỏ → user nghĩ "destructive").

---

## 8. Icon usage

**Why:** Icon đúng cách giảm reading load. Icon sai cách (decoration only) tăng noise.

**How to apply:**

- **Size**: 24×24 default. 16×16 inline với text. 32×32+ cho feature icon.
- **Stroke width**: 1.75 (Cowork standard) — KHÔNG mix 1 / 2 / outline / filled trong cùng view.
- **Color**: `currentColor` (inherit) — icon match màu text xung quanh.
- **Pair với text label** nếu không phổ biến. **Icon-only OK chỉ với 4 icon universal**: home, close (×), menu (☰), search (🔍).

**Anti-pattern:** Icon "Save" floppy disk + text "Lưu" + tooltip "Save" → triple-redundant. Pick 1 (text-only nếu phổ biến, hoặc icon+text nếu cần emphasize).

---

## 9. Form rules

**Why:** Form là conversion bottleneck. Mọi friction ở form = drop-off rate.

**How to apply:**

- **Label luôn visible** — KHÔNG placeholder-only (user quên field hỏi gì sau khi gõ).
- **Required field** marked với `*` đỏ + `aria-required="true"`.
- **Error message** dưới input, color `--danger`, kèm icon ⚠ nếu có space.
- **Submit button disabled** until form valid (no spammy submit attempts).
- **Loading state** replace button text với spinner ("Đang gửi..." + ⌛).
- **Input height** ≥44px (touch target, § 10).
- **Input font-size** ≥16px (`fs-base`) trên mobile — tránh iOS auto-zoom khi focus.

**Anti-pattern:** Submit button "Gửi" stay enabled khi form invalid → user click → 6 error message bung ra cùng lúc. Fix: disabled state + validate on blur, không validate on every keystroke (annoying).

---

## 10. Mobile-first decisions

**Why:** ≥60% traffic personal brand của Dang là mobile. Desktop là affordance, mobile là default.

**How to apply:**

- **Touch target ≥44px** (Apple HIG) cho mọi button/link tappable.
- **Bottom CTA sticky** với `safe-area-inset-bottom` padding (iPhone notch).
- **Avoid hover-only interactions** — mobile không có hover. Tooltip on hover → invisible on touch device. Fix: tap-to-reveal hoặc always-visible.
- **Bottom sheet > Modal** cho selection (date picker, option list) — easier thumb reach.
- **Swipe action** for delete/archive với confirm step (tránh accidental swipe).

**Anti-pattern:** Dropdown menu hover-only → mobile user không mở được. Fix: tap-to-open + close on outside-click.

---

## 11. Anti-patterns tổng

Checklist phản đối — nếu code vi phạm 1 trong số này = reject:

- ❌ Random spacing không từ scale (`padding: 22px`)
- ❌ Custom radius khác token (`border-radius: 7px`)
- ❌ Hex literal trong CSS (`color: #c9a96e`) — mọi color phải qua `var(--brand-*)`
- ❌ Variant mới không define trong system (`<button class="btn btn-pink">` không có trong tokens)
- ❌ 2+ primary CTA cùng view (xem § 1)
- ❌ Wow point dày đặc (3+ huge title, 5+ gradient card → loud everywhere = loud nowhere)
- ❌ Mix multiple visual styles (warm + dark trong cùng 1 view — pick 1 aesthetic per page)
- ❌ Override token trực tiếp ở component (`<div style="--space-4: 18px">` thay vì dùng token đúng)
- ❌ Generic preview button "Submit" / badge "Tag" thay vì brand-appropriate context — wellness phải "Đặt buổi", e-commerce "Thêm vào giỏ", dashboard "View report"
- ❌ Icon-only button không universal + không label + không aria-label → fail a11y
- ❌ Placeholder-only label
- ❌ Empty state trắng không CTA
- ❌ Tailwind dynamic class trong string variable (`bg-[${color}]`) — JIT miss, invisible

---

## 12. When to break rules

**Khi nào được phép vi phạm rule trên:**

- **User explicit request** — Dang chốt "anh muốn 2 primary cạnh nhau cho campaign này" → OK, ghi lý do vào file.
- **A11y conflict** — rule WCAG ưu tiên hơn rule trong file này. Vd: contrast ratio 4.5:1 ưu tiên hơn brand color softness.
- **Performance critical** — vd bỏ animation cho list 1000+ row, bỏ blur backdrop cho low-end device.

**Phải document trong file source:**

```html
<!-- OVERRIDE § 1 CTA hierarchy: 2 primary OK ở landing này vì A/B test 2 path bình quyền (subscribe vs trial), Dang approved 2026-05-20 -->
<button class="btn primary">Đăng ký</button>
<button class="btn primary">Dùng thử</button>
```

Nguyên tắc: **Override phải có lý do + chữ ký + ngày**. Không lý do = rollback về rule mặc định.

---

## Phụ lục — Mapping với 6 archetype

Rule trong file này áp dụng cho mọi archetype, nhưng emphasis khác nhau:

| Archetype | Rule quan trọng nhất |
|---|---|
| **A · Dashboard** (dark) | § 3 Content hierarchy (KPI fs-5xl + body fs-base), § 7 Color (status semantic cho metric +/−) |
| **B · Tool** (dark) | § 6 Modal vs Drawer (admin CRUD), § 9 Form rules (input height + validation) |
| **C · Landing** (warm) | § 1 CTA hierarchy (1 primary above fold), § 2 Wow point (hero `fs-7xl`) |
| **D · Editorial** (warm) | § 5 Max width (65ch reading), § 3 Hierarchy (H1 fs-5xl + drop cap) |
| **E · Deck** (warm) | § 2 Wow point (`fs-9xl` big stat per slide), § 4 Spacing (rộng rãi, section padding 96px+) |
| **F · PWA** (warm) | § 10 Mobile-first (touch ≥44px, bottom sheet), § 9 Form (input ≥16px) |

Khi build 1 page mới, sau khi pick archetype + aesthetic, đọc rule emphasis tương ứng trước.

---

## Reference

- Token files: `tokens/foundation.css` (primitive) + `tokens/semantic.css` (semantic)
- Brand presets: `brands/<brand>.brand.css`
- Component layers: `atoms/` → `molecules/` → `organisms/` → `templates/` → `pages/`
- Live gallery: 🌐 https://ui.dang.pm/ (6 pages × 7 brands × 7 demos)
- Memory cross-link: `feedback_ui_default_6_archetype_2_aesthetic`, `feedback_ai_engineer_not_designer`, `feedback_ui_visual_proof_required`, `feedback_tailwind_jit_dynamic_classes`
- Sister doc: `INDEX.md` (component catalog), `MAPPING-SHADCN.md` (shadcn equivalence)

---

*Last updated: 2026-05-20. Maintained by Dang + AI. Khi rule conflict với code reality → update file này TRƯỚC, sau đó fix code.*
