---
url: https://docs.nemo12.com/design-system/hierarchy.md
description: >-
  Luật Information Hierarchy và Visual Hierarchy (08.10.2026): bỏ chữ lặp và
  chồng lớp trên màn lesson AI Teen, mỗi ý nói đúng một lần.
---

# Information Hierarchy và Visual Hierarchy (SRC-1294)

Chủ dự án 08.10.2026: màn lesson của AI Teen (AI Teen 2 · Unit 1 · Lesson 2) nói cùng một điều hai ba
lần (danh sách activity ở card giữa trang VÀ ở thẻ trái, kicker lặp câu hỏi của lesson, dòng "Tìm hiểu
sâu: ..." lặp tên activity) và chồng bảy lớp chữ lên đầu trang. Trang này là **chuẩn** cho mọi màn
AI Teen (chương trình, course, unit, lesson) và cho mọi màn mới dùng [Guided Journey](./guided-journey/index.md).
Nó là một phần của [DS-001](./index.md); chỗ nào nói khác guided-journey.md thì trang này thắng về thứ
bậc, guided-journey.md thắng về cấu trúc journey.

Luật có mã (`H-I*` thông tin, `H-V*` thị giác, `H-S*` thẻ bên) để test, review và commit trỏ tới. Luật
nào đo được thì có cột "Đo bằng".

## 1. Information Hierarchy: nói gì, theo thứ tự nào

**Bốn bậc quan trọng, luôn theo thứ tự này từ trên xuống:**

| Bậc | Câu learner đang hỏi | Ở đâu trên màn | Ví dụ ở lesson |
| --- | --- | --- | --- |
| 1. Em đang ở đâu? | "Đây là màn gì?" | header (breadcrumb cấp) + h1 | `Lesson 2/4` · **1 Bắt đầu** |
| 2. Làm gì bây giờ? | "Bước kế của mình là gì?" | ngay dưới h1; bước hiện tại sáng; đúng một nút chính | bước đang đọc, nút "Xong bước này" |
| 3. Thông tin hỗ trợ | "Mình cần biết gì để làm?" | thân màn, mở sẵn nhưng gọn | outcomes, sản phẩm, concept |
| 4. Tra cứu | "Muốn xem kỹ thì xem ở đâu?" | thu gọn mặc định hoặc một link | Skills của course, Learning Cycle |

| Mã | Luật | Đo bằng |
| --- | --- | --- |
| H-I1 | **Một thông điệp chính mỗi màn**, và nó là h1. Màn nào cần hai h1 là màn đang chứa hai màn. | e2e: đúng 1 `h1` trong `[data-part=journey-content]` |
| H-I2 | **Thứ tự bốn bậc** ở bảng trên. Tra cứu không đứng trên việc cần làm (trang course: danh sách unit trước, outcomes sau, Skills thu gọn cuối). | review |
| H-I3 | **Header của nội dung tối đa ba lớp**: một kicker (tuỳ chọn), h1, một dòng phụ. Câu hỏi, tóm tắt, chặng vòng học không chồng thêm lên đó. | e2e: tối đa 1 `[data-kicker]` |
| H-I4 | **Mở sẵn hay thu gọn.** Bậc 1-2 luôn hiện. Bậc 3 hiện nhưng gọn: danh sách ngắn, không card riêng cho mỗi mẩu. Bậc 4 thu gọn mặc định (Accordion) hoặc nằm sau một link. | review; e2e: outcomes của lesson không có viền card |
| H-I5 | **Không nói một điều hai lần trên cùng màn.** Danh sách activity chỉ ở thẻ trái; câu hỏi của lesson chỉ ở một tiêu đề; concept chỉ một chỗ; tên activity không lặp trong dòng giải thích. | e2e: không `[data-activity]` trong vùng chính; câu hỏi xuất hiện đúng 1 lần |
| H-I6 | **Số mục mỗi bậc**: tối đa 7 mục cùng cấp trong một danh sách điều hướng (activity, journey, bước của một activity); tối đa 5 mục hỗ trợ (outcomes) hiện cùng lúc, hơn nữa thì thu gọn phần dư. | test thuần đếm activity và bước (`journeys.test.ts`) |
| H-I7 | **Nhãn ngắn**: tên trong thẻ bên và menu 1-3 chữ (đã có test); kicker 1-4 chữ (§2b); nhãn nút 1-4 chữ cộng mũi tên. | `journeys.test.ts`, review |

## 2. Visual Hierarchy: trông thế nào

### 2a. Thang chữ: đúng năm cấp, không cấp thứ sáu

Hằng số ở `apps/learn/src/components/hierarchy.ts` (`T.page`, `T.section`, ...). Màn dùng hằng số,
không tự viết `text-3xl font-bold`.

| Cấp | Thẻ | Class Tailwind | Cỡ / đậm | Dùng cho |
| --- | --- | --- | --- | --- |
| Page title | `h1` | `text-2xl sm:text-3xl font-bold leading-tight` | 24/30px, 700 | thông điệp chính, đúng một |
| Section title | `h2` | `text-xl font-semibold leading-snug` | 20px, 600 | một bước của lesson, một khối của trang |
| Card title | `h3` | `text-base font-semibold` | 16px, 600 | tiêu đề trong khối, nhãn trên một danh sách ngắn |
| Body | `p` | `text-base` | 16px, 400 | chữ thường |
| Meta | `p`, `span` | `text-sm text-muted-foreground` | 14px, 400 (600 khi là nhãn) | dòng phụ, số đếm, gợi ý |
| Kicker | `p[data-kicker]` | `text-sm font-semibold uppercase tracking-wider text-muted-foreground` | 14px, 600 (sàn chữ 14px của SRC-1293) | xem §2b |

| Mã | Luật | Đo bằng |
| --- | --- | --- |
| H-V1 | **Tối đa ba cấp tiêu đề** (h1, h2, h3). Cần h4 là khối đang lồng quá sâu: hạ thành nhãn Meta đậm. | e2e: không `h4`-`h6` hiện trong nội dung |
| H-V2 | **Một chỗ dùng accent mỗi màn** cho hành động chính hoặc mục hiện tại: tối đa MỘT nút tô đầy (`data-variant` = `accent` hay `default`) trong tầm nhìn. Trang lesson là một trang cuộn nhiều bước: chỉ bước đang đọc (scroll-spy) mang nút tô đầy, bước khác dùng `outline`. Mục hiện tại ở thẻ bên tô accent; đó là chỗ thứ hai DUY NHẤT được tô, vì nó là "em đang ở đâu". | e2e: đếm nút tô đầy giao với khung nhìn ≤ 1 |
| H-V3 | **Vai màu**: `foreground` cho chữ chính; `muted-foreground` cho Meta, kicker, số thứ tự; `accent` cho hiện tại và hành động chính; `destructive` chỉ cho lỗi hệ thống (DS-001 §7.3). Không dùng màu để phân cấp chữ ngoài hai mức foreground / muted. Tương phản chữ ≥ 4.5:1 (Meta cũng vậy). | DS-001 §2·1, review |
| H-V4 | **Thang khoảng cách** (Tailwind, bội số 4px): trong một khối `gap-1`/`space-y-1` (4px) giữa tiêu đề và dòng phụ; `space-y-3`/`4` (12-16px) giữa các phần của một khối; `space-y-10` (40px) giữa các bước của lesson và các khối lớn của trang. Không giá trị lẻ (`mt-[13px]`). | review |
| H-V5 | **Card lồng tối đa một cấp**: một card không chứa card. Trong card dùng đường kẻ (`border-t`), nền nhạt hoặc danh sách. | review |
| H-V6 | **Icon**: chỉ lucide, `aria-hidden` khi đã có chữ; 14-16px trong thẻ bên và nhãn, 16px trong nút; một icon mỗi hàng; không icon trang trí đứng một mình không có chữ (trừ nút icon có `aria-label`). Không còn icon ổ khoá trong lesson (§3). | e2e: không `svg.lucide-lock` trong lesson |

### 2b. Kicker (eyebrow)

| Mã | Luật |
| --- | --- |
| H-V7 | **Tối đa một kicker mỗi màn**, chỉ đứng trên h1, 1-4 chữ, nói VỊ TRÍ (`Lesson 2/4`, `Unit 1 · Mục tiêu`, `Practice`), không nói lại tiêu đề hay câu hỏi. h2 không có kicker; số "Phần 2/4" của một phần đọc là dòng Meta dưới h2. |
| H-V8 | Nhãn trong card không viết HOA kiểu kicker: dùng Card title hoặc Meta đậm, chữ thường. |

## 3. Thẻ bên (sidebar) của trang lesson

Áp cho thẻ Activity bên trái (guided-journey §12, SDD-043 §14). Chủ dự án 08.10.2026: thẻ cũ quá to,
mọi nhóm mở cùng lúc, có thanh cuộn riêng.

| Mã | Luật | Đo bằng |
| --- | --- | --- |
| H-S1 | **Cột hẹp**: 14rem (224px), tối đa 240px; không lề ngoài thừa (`p-2`, cột lưới sát mép trái của khung nội dung). | e2e: bề rộng thẻ ≤ 240px |
| H-S2 | **Hàng gọn**: activity 36px, bước 32px trên máy lớn (`lg`); chữ 14px cho activity và bước (sàn chữ SRC-1293), số muted; thụt 12px với một đường kẻ trái. Dưới `lg` (sheet) mọi vùng chạm ≥ 40px. | e2e 375px: mọi nút hiện ≥ 40px |
| H-S3 | **Đúng một nhóm mở**: nhóm của activity hiện tại; bấm tiêu đề nhóm khác thì mở nhóm ấy (và đi tới activity ấy), nhóm kia gập. Nút tiêu đề có `aria-expanded` + `aria-controls`; nhóm gập vẫn trong DOM (`hidden`). | e2e: đúng 1 `[data-step-list]:not([hidden])` sau mỗi lần bấm |
| H-S4 | **Không thanh cuộn trong**: thẻ cao bằng nội dung, cuộn theo trang; chỉ `sticky` khi nó vừa khung nhìn dưới header (đo lúc chạy). | e2e: `overflow-y` không phải `auto`/`scroll`, `scrollHeight ≤ clientHeight` |
| H-S5 | **Một chỗ tô**: bước hiện tại nền accent; activity hiện tại chỉ đậm, không viền, không nền. Xong = dấu tick nhỏ, không đổi màu cả hàng (đây là card trái của lesson; NavBar và hàng bước thì KHÔNG có tick từ SRC-1300, xem guided-journey §9). | review |
| H-S6 | **375px**: thẻ thành sheet gọn mở từ thanh dính "Activity · Bước"; cùng component, cùng luật một nhóm mở. | e2e 375px |

## 4. Áp vào bốn cấp AI Teen (08.10.2026)

| Màn | h1 | Kicker | Thứ tự dưới h1 | Đã bỏ |
| --- | --- | --- | --- | --- |
| Chương trình (Learning) | đích của em | `Lộ trình của em` | nút Tiếp tục (nút tô duy nhất) → từng course với unit | nút Ghi danh tô đầy ở mỗi course (nay `outline`) |
| Course | tên course | không | danh sách unit → Course Outcomes (gọn, không card) → Skills (thu gọn) → link Learning Cycle | card bao outcomes; nút Learning Cycle đứng trên danh sách unit |
| Unit | Compelling Question | `Unit n · Mục tiêu` / `Unit n · Học` / `Practice` ... | khối skill → học gì / làm ra gì → nút chính | kicker hai vế ("Mục tiêu · Khi xong unit này"), nhãn HOA trong card, đoạn giải thích dài trên danh sách lesson |
| Lesson | `{n} {Activity}` | `Lesson m/N` | mỗi bước một h2; bước Câu hỏi: h2 = câu hỏi, một dòng tóm tắt, outcomes gọn, sản phẩm một dòng, concept | card "Learning Activities" (lặp thẻ trái), câu hỏi trong kicker, dòng chặng vòng học, card "Concept của lesson", chip concept lặp ở Mang theo, card "Sản phẩm của lesson", kicker trên mọi h2, ổ khoá |

## 4b. Nội dung trong card: Card patterns (SRC-1298)

Nội dung học (khối bài đọc, outcomes, sản phẩm, câu hỏi, kết quả) không vẽ tuỳ hứng: mỗi loại thông
tin dùng đúng một pattern trong [Card patterns](./card-patterns.md), mỗi card một ý, `gap-6`/`gap-8`
giữa card. Nhãn trên card là `T.meta`, tiêu đề card là h3 `T.card`, nên luật một kicker và tối đa ba
cấp tiêu đề ở trên vẫn giữ.

## 5. Hiện thực và kiểm chứng

* Thang chữ: `apps/learn/src/components/hierarchy.ts`; tiêu đề màn và bước: `apps/learn/src/aiTeen/StageHead.tsx`
  (kicker chỉ khi `as="h1"`).
* Thẻ bên: `LessonOutline` + `FitSticky` trong `apps/learn/src/aiTeen/LessonPage.tsx`.
* e2e `apps/learn/e2e/aiTeen.spec.ts`, khối "Information + Visual Hierarchy": một h1, h1-h3, một kicker,
  một nút tô đầy trong tầm nhìn ở chương trình, course, unit, lesson; lesson không lặp danh sách activity;
  thẻ ≤ 240px, không cuộn trong, đúng một nhóm mở, không ổ khoá; 375px sheet gọn, vùng chạm ≥ 40px.
* Màn mới: skill `journey-design` §3c bắt buộc đi qua bảng luật trên trước khi dựng.
