@haposoft/cafekit 0.16.7 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +14 -22
  2. package/bin/__tests__/codex-hooks-ownership.test.js +2 -2
  3. package/bin/__tests__/codex-hooks.test.js +0 -36
  4. package/bin/__tests__/codex-native.test.js +46 -88
  5. package/bin/__tests__/develop-contract.test.js +26 -57
  6. package/bin/__tests__/docs-sync-on-demand.test.js +93 -0
  7. package/bin/__tests__/grok-envelope.test.js +0 -56
  8. package/bin/__tests__/hook-payload.test.js +4 -6
  9. package/bin/__tests__/legacy-authority-decoupled.test.js +159 -0
  10. package/bin/__tests__/legacy-hooks-retired.test.js +221 -0
  11. package/bin/__tests__/omp-bridge.test.js +20 -17
  12. package/bin/__tests__/omp-hooks.test.js +0 -19
  13. package/bin/__tests__/optional-skill-inventory.test.js +112 -4
  14. package/bin/__tests__/orca-session.test.js +0 -2
  15. package/bin/__tests__/package-inventory.test.js +100 -541
  16. package/bin/__tests__/runtime-dir.test.js +0 -3
  17. package/bin/__tests__/runtime-schema.test.js +3 -2
  18. package/bin/__tests__/skill-routing-source.test.js +27 -15
  19. package/bin/__tests__/spec-narrowing.test.js +0 -27
  20. package/bin/__tests__/specs-v2-execution-closeout.test.js +4 -69
  21. package/bin/__tests__/ui-ux-skill.test.js +101 -0
  22. package/bin/__tests__/usage-hook-retired.test.js +114 -0
  23. package/bin/__tests__/validator-grounding.test.js +9 -28
  24. package/bin/phases/codex-runtime.js +24 -0
  25. package/bin/phases/omp-runtime.js +22 -0
  26. package/package.json +1 -1
  27. package/src/claude/CLAUDE.md +3 -10
  28. package/src/claude/agents/brainstormer.md +7 -3
  29. package/src/claude/agents/code-auditor.md +35 -50
  30. package/src/claude/agents/debugger.md +5 -79
  31. package/src/claude/agents/deployer.md +3 -5
  32. package/src/claude/agents/docs-keeper.md +2 -7
  33. package/src/claude/agents/implementer.md +6 -9
  34. package/src/claude/agents/inspector.md +2 -3
  35. package/src/claude/agents/project-manager.md +7 -15
  36. package/src/claude/agents/researcher.md +9 -3
  37. package/src/claude/agents/spec-maker.md +11 -11
  38. package/src/claude/hooks/__tests__/fixtures/statusline-default.golden +1 -1
  39. package/src/claude/hooks/__tests__/spec-gate.test.js +74 -3
  40. package/src/claude/hooks/__tests__/spec-state-touched.test.js +134 -0
  41. package/src/claude/hooks/__tests__/state.test.js +68 -0
  42. package/src/claude/hooks/__tests__/statusline.test.js +140 -11
  43. package/src/claude/hooks/agent.cjs +2 -1
  44. package/src/claude/hooks/lib/context.cjs +0 -89
  45. package/src/claude/hooks/lib/hook-payload.cjs +2 -2
  46. package/src/claude/hooks/rules.cjs +2 -1
  47. package/src/claude/hooks/session.cjs +0 -1
  48. package/src/claude/hooks/spec-gate.cjs +17 -28
  49. package/src/claude/hooks/spec-state.cjs +95 -1
  50. package/src/claude/hooks/state.cjs +21 -2
  51. package/src/claude/migration-manifest.json +30 -15
  52. package/src/claude/rules/ai-dev-rules.md +1 -1
  53. package/src/claude/rules/hook-protocols.md +8 -15
  54. package/src/claude/rules/manage-docs.md +9 -23
  55. package/src/claude/rules/orchestrator.md +3 -4
  56. package/src/claude/rules/review-audit-self-decision.md +3 -3
  57. package/src/claude/rules/skill-domain-routing.md +1 -3
  58. package/src/claude/rules/skill-workflow-routing.md +4 -5
  59. package/src/claude/rules/state-sync.md +3 -12
  60. package/src/claude/rules/workflow.md +10 -18
  61. package/src/claude/runtime.schema.json +5 -3
  62. package/src/claude/scripts/generate-skill-catalog.cjs +7 -6
  63. package/src/claude/scripts/provenance.cjs +23 -5
  64. package/src/claude/scripts/spec-receipt.cjs +24 -7
  65. package/src/claude/scripts/spec-resolver.cjs +1 -2
  66. package/src/claude/scripts/validate-spec-output.cjs +5 -32
  67. package/src/claude/settings/settings.json +1 -32
  68. package/src/claude/skills/{question → ask}/SKILL.md +9 -75
  69. package/src/claude/skills/brainstorm/SKILL.md +43 -131
  70. package/src/claude/skills/code-review/SKILL.md +48 -17
  71. package/src/claude/skills/code-review/references/spec-compliance-review.md +2 -3
  72. package/src/claude/skills/code-review/references/verification-gate.md +22 -27
  73. package/src/claude/skills/debug/SKILL.md +29 -149
  74. package/src/claude/skills/develop/SKILL.md +27 -36
  75. package/src/claude/skills/develop/references/parallel-waves.md +0 -8
  76. package/src/claude/skills/develop/references/quality-gate.md +15 -13
  77. package/src/claude/skills/docs/SKILL.md +2 -2
  78. package/src/claude/skills/docs/references/update-workflow.md +1 -1
  79. package/src/claude/skills/fix/SKILL.md +153 -0
  80. package/src/claude/skills/{hotfix → fix}/references/diagnosis-protocol.md +2 -2
  81. package/src/claude/skills/{hotfix → fix}/references/parallel-patterns.md +2 -2
  82. package/src/claude/skills/{hotfix → fix}/references/prevention-gate.md +3 -3
  83. package/src/claude/skills/{hotfix → fix}/references/review-cycle.md +1 -1
  84. package/src/claude/skills/git/SKILL.md +48 -9
  85. package/src/claude/skills/git/references/commit-protocols.md +35 -16
  86. package/src/claude/skills/git/references/worktree-blueprint.md +42 -6
  87. package/src/claude/skills/orca/SKILL.md +9 -8
  88. package/src/claude/skills/research/SKILL.md +2 -0
  89. package/src/claude/skills/scout/SKILL.md +61 -0
  90. package/src/claude/skills/{inspect → scout}/references/internal-inspection.md +26 -10
  91. package/src/claude/skills/specs/SKILL.md +22 -29
  92. package/src/claude/skills/specs/references/review.md +8 -6
  93. package/src/claude/skills/specs/references/templates.md +34 -41
  94. package/src/claude/skills/sync/SKILL.md +8 -15
  95. package/src/claude/skills/sync/references/rebind-and-audit.md +59 -0
  96. package/src/claude/skills/sync/references/sync-protocols.md +4 -13
  97. package/src/claude/skills/test/SKILL.md +22 -3
  98. package/src/claude/skills/test/references/execution-strategy.md +83 -0
  99. package/src/claude/skills/test/references/failure-triage.md +1 -1
  100. package/src/claude/skills/ui-ux/LICENSE +21 -0
  101. package/src/claude/skills/ui-ux/SKILL.md +497 -0
  102. package/src/claude/skills/ui-ux/references/brand-tokens.md +90 -0
  103. package/src/claude/skills/ui-ux/references/budgets.md +113 -0
  104. package/src/claude/skills/ui-ux/references/checklist.md +271 -0
  105. package/src/claude/skills/ui-ux/references/components/accordion.md +246 -0
  106. package/src/claude/skills/ui-ux/references/components/avatar.md +153 -0
  107. package/src/claude/skills/ui-ux/references/components/banner.md +43 -0
  108. package/src/claude/skills/ui-ux/references/components/breadcrumb.md +201 -0
  109. package/src/claude/skills/ui-ux/references/components/button.md +142 -0
  110. package/src/claude/skills/ui-ux/references/components/card.md +113 -0
  111. package/src/claude/skills/ui-ux/references/components/charts.md +376 -0
  112. package/src/claude/skills/ui-ux/references/components/chat.md +132 -0
  113. package/src/claude/skills/ui-ux/references/components/choice-controls.md +369 -0
  114. package/src/claude/skills/ui-ux/references/components/comment-thread.md +17 -0
  115. package/src/claude/skills/ui-ux/references/components/description-list.md +116 -0
  116. package/src/claude/skills/ui-ux/references/components/empty-state.md +98 -0
  117. package/src/claude/skills/ui-ux/references/components/file-upload.md +107 -0
  118. package/src/claude/skills/ui-ux/references/components/inline-edit.md +128 -0
  119. package/src/claude/skills/ui-ux/references/components/input.md +161 -0
  120. package/src/claude/skills/ui-ux/references/components/list-row.md +56 -0
  121. package/src/claude/skills/ui-ux/references/components/loading.md +198 -0
  122. package/src/claude/skills/ui-ux/references/components/logo.md +147 -0
  123. package/src/claude/skills/ui-ux/references/components/otp-input.md +43 -0
  124. package/src/claude/skills/ui-ux/references/components/quantity-input.md +100 -0
  125. package/src/claude/skills/ui-ux/references/components/range-slider.md +16 -0
  126. package/src/claude/skills/ui-ux/references/components/small-controls.md +340 -0
  127. package/src/claude/skills/ui-ux/references/components/sortable-header.md +86 -0
  128. package/src/claude/skills/ui-ux/references/components/tag-input.md +14 -0
  129. package/src/claude/skills/ui-ux/references/components/timeline.md +38 -0
  130. package/src/claude/skills/ui-ux/references/components/tree.md +30 -0
  131. package/src/claude/skills/ui-ux/references/design-process.md +650 -0
  132. package/src/claude/skills/ui-ux/references/layouts/app-kanban.html +303 -0
  133. package/src/claude/skills/ui-ux/references/layouts/app.md +1369 -0
  134. package/src/claude/skills/ui-ux/references/layouts/form.md +430 -0
  135. package/src/claude/skills/ui-ux/references/layouts/overlay.md +552 -0
  136. package/src/claude/skills/ui-ux/references/layouts/pricing.md +204 -0
  137. package/src/claude/skills/ui-ux/references/locked-rules.md +35 -0
  138. package/src/claude/skills/ui-ux/references/principles.md +408 -0
  139. package/src/claude/skills/ui-ux/references/refactor.md +245 -0
  140. package/src/claude/skills/ui-ux/references/responsive.md +195 -0
  141. package/src/claude/skills/ui-ux/references/review.md +528 -0
  142. package/src/claude/skills/ui-ux/references/rules-color.md +623 -0
  143. package/src/claude/skills/ui-ux/references/rules-form.md +235 -0
  144. package/src/claude/skills/ui-ux/references/rules-state.md +680 -0
  145. package/src/claude/skills/ui-ux/references/rules-type.md +369 -0
  146. package/src/claude/skills/ui-ux/references/styles.md +311 -0
  147. package/src/claude/skills/ui-ux/references/system.md +219 -0
  148. package/src/claude/skills/ui-ux/references/tailwind-v4-traps.md +237 -0
  149. package/src/claude/skills/ui-ux/references/tokens.css +362 -0
  150. package/src/claude/skills/ui-ux/scripts/lint-skill.mjs +216 -0
  151. package/src/claude/skills/ui-ux/scripts/package.json +9 -0
  152. package/src/claude/skills/ui-ux/scripts/probe.mjs +4447 -0
  153. package/src/claude/skills/ui-ux-pro-max/SKILL.md +1 -1
  154. package/src/claude/status.cjs +149 -144
  155. package/src/codex/AGENTS.md +8 -13
  156. package/src/codex/hooks/agent.cjs +2 -1
  157. package/src/codex/hooks/lib/spec-receipt.cjs +2 -2
  158. package/src/codex/hooks/lib/spec-utils.cjs +0 -7
  159. package/src/codex/hooks/rules.cjs +2 -1
  160. package/src/codex/hooks/session.cjs +0 -2
  161. package/src/codex/hooks/spec-gate.cjs +7 -18
  162. package/src/codex/hooks.json +0 -20
  163. package/src/codex/rules/state-sync.md +3 -12
  164. package/src/common/AGENTS.md +2 -2
  165. package/src/omp/extensions/cafekit-bridge.mjs +6 -6
  166. package/src/claude/hooks/__tests__/completion-authority.test.js +0 -990
  167. package/src/claude/hooks/__tests__/semantic-review-authority.test.js +0 -259
  168. package/src/claude/hooks/completion-authority-check.cjs +0 -56
  169. package/src/claude/hooks/completion-authority-state.cjs +0 -527
  170. package/src/claude/hooks/completion-authority.cjs +0 -163
  171. package/src/claude/hooks/semantic-review-authority.cjs +0 -154
  172. package/src/claude/hooks/task-scaffold-guard.cjs +0 -114
  173. package/src/claude/hooks/usage.cjs +0 -197
  174. package/src/claude/skills/delegate/SKILL.md +0 -124
  175. package/src/claude/skills/delegate/references/codex-delegation.md +0 -71
  176. package/src/claude/skills/delegate/references/grok-delegation.md +0 -84
  177. package/src/claude/skills/hotfix/SKILL.md +0 -289
  178. package/src/claude/skills/inspect/SKILL.md +0 -142
  179. package/src/claude/skills/loop/SKILL.md +0 -114
  180. package/src/claude/skills/loop/references/bounded-loop-protocol.md +0 -104
  181. package/src/claude/skills/loop/references/metric-and-guard-contract.md +0 -76
  182. package/src/claude/skills/route/SKILL.md +0 -94
  183. package/src/claude/skills/route/references/agent-timing.md +0 -46
  184. package/src/claude/skills/route/references/chaining-patterns.md +0 -53
  185. package/src/claude/skills/route/references/task-taxonomy.md +0 -48
  186. package/src/codex/hooks/completion-authority-check.cjs +0 -67
  187. package/src/codex/hooks/completion-authority-state.cjs +0 -527
  188. package/src/codex/hooks/completion-authority.cjs +0 -109
  189. package/src/codex/hooks/semantic-review-authority.cjs +0 -130
  190. package/src/codex/hooks/task-scaffold-guard.cjs +0 -63
  191. /package/src/claude/skills/{question → ask}/templates/question.md +0 -0
  192. /package/src/claude/skills/{hotfix → fix}/references/escalation-tactics.md +0 -0
  193. /package/src/claude/skills/{hotfix → fix}/references/workflow-specialized.md +0 -0
@@ -0,0 +1,311 @@
1
+ # Phong cách thị giác — luật P
2
+
3
+ Nguồn duy nhất cho: nhận ra dự án đang dùng phong cách gì, phong cách đó được đè
4
+ luật nào, và bẫy riêng của từng phong cách. Lệnh audit nằm ở `SKILL.md` câu 2,
5
+ tầng 3. File này dạy cách **đọc** kết quả.
6
+
7
+ ---
8
+
9
+ ## Hai tầng
10
+
11
+ **P1. Mặc định là flat. Dự án đã có phong cách riêng thì theo dự án. Không hỏi.**
12
+
13
+ Ba ca, chọn đúng một:
14
+
15
+ | Ca | Làm gì |
16
+ | --- | --- |
17
+ | **Người dùng tự nêu phong cách** ("làm trang giá kiểu glassmorphism") | Làm theo phong cách đó, **không hỏi lại** |
18
+ | **Audit thấy dự án có phong cách khác flat** (`P4`) | **Theo phong cách dự án**, dựng luôn, báo một dòng lúc giao (mẫu bên dưới) |
19
+ | **Dự án flat hoặc trống**, người dùng không nêu gì | Flat (`P6`). Không hỏi về phong cách. Có màu (`P12`) chỉ khi người dùng tự xin trong đề; hai chế độ dựng lại: dòng Có màu (`V1d`), không chọn sẵn. Wireframe không còn nấc Có màu |
20
+
21
+ Vì sao theo dự án chứ không theo flat: một màn flat giữa app glass là màn lạc
22
+ loài, người dùng thấy ngay. Nhất quán thắng gu.
23
+
24
+ Mẫu dòng báo lúc giao:
25
+
26
+ > Dự án đang dùng **glass** (thấy ở 7 file: card, modal, sidebar), màn này làm
27
+ > glass cho khớp. Muốn flat theo mặc định của skill thì nói, mình đổi.
28
+
29
+ Người dùng đã chọn thì giữ cho các màn sau trong cùng dự án.
30
+
31
+ **Chọn phong cách nào thì cũng không theo lỗi của dự án.** Phong cách với lỗi là
32
+ hai thứ khác nhau. Dự án làm trang giá ba cột, mỗi cột một nút một màu (tím,
33
+ trắng, xanh), mà người dùng chọn theo phong cách dự án thì:
34
+
35
+ - **Theo:** gradient tím, bo góc lớn, nền tối. Đó là phong cách.
36
+ - **Không theo:** ba nút ba màu cùng nặng như nhau. Đó là lỗi `I3`. Chỉ một nút được là nút chính, dù phong cách là gì.
37
+
38
+ Phép thử: *bỏ thứ này đi thì màn hình trông **khác**, hay trông **tệ hơn**?*
39
+ Khác là phong cách, cứ theo. Tệ hơn là nguyên tắc, không được bỏ.
40
+
41
+ **P2. Luật nào phong cách được đè, luật nào không.**
42
+
43
+ | Loại | Luật | Phong cách đã chọn theo `P1` được đè không |
44
+ | --- | --- | --- |
45
+ | **Gu flat** | `M1` nền xám nhạt · `M2` tỉ lệ 95/5 · `M12` không gradient · `M13` tách bằng viền · `M15` bóng chỉ cho lớp nổi · `M20` mặc định sáng · `M23` tối là navy · `M29` card một mình không viền · `F19` không glass · `F20` không phát sáng · `F22` không animate hình khối | **Được**, theo đúng khối của phong cách đó bên dưới |
46
+ | **Nguyên tắc** | Toàn bộ `N` `S` `T` `I` `R` · `M3` một màu nhấn · `M4` màu báo trạng thái (ngoại lệ hẹp: `P12` công thức B đè chỉ ở ô icon card số liệu, ô icon đầu dòng theo loại và chuỗi biểu đồ) · `M11` ba sắc độ chữ · `M19` bo lồng · `M24`–`M28` token · `M30` hai sắc đỏ · bố cục `F1`–`F18`, `F21`, `F23`–`F25` · **`P3` tương phản** | **Không bao giờ** |
47
+
48
+ Mỗi luật gu flat có dòng *"Gu flat"* ngay tại chỗ. Thấy dòng đó mà phong cách
49
+ đã chọn không phải flat thì quay về đây.
50
+
51
+ **P3. Tương phản chữ: con số cứng, ở mọi phong cách.**
52
+
53
+ | Thứ | Tối thiểu |
54
+ | --- | --- |
55
+ | Chữ thường | **4.5 : 1** so với nền ngay phía sau |
56
+ | Chữ lớn (từ 24px, hoặc từ 18.66px đậm) | **3 : 1** |
57
+ | Icon mang nghĩa; viền **ô nhập, checkbox, radio chưa chọn** | **3 : 1** so với nền kề bên. Nút có nhãn chữ **không** cần viền đạt 3:1 (WCAG 1.4.11: chữ đã nhận diện được nút) |
58
+
59
+ Token mặc định:
60
+
61
+ | Token | Nền sáng | Nền tối | Đạt |
62
+ | --- | --- | --- | --- |
63
+ | `--muted` (chữ phụ, placeholder) | 4.95 : 1 trên card, 4.51 : 1 trên nền trang | 6.1 : 1 | ✅ 4.5 |
64
+ | `--border-focus` | 16.8 : 1 | 3.6 : 1 | ✅ 3 |
65
+ | **Viền ô nhập, select, nút outline, checkbox, radio** (`--border-strong`) | ~1.2 : 1 | ~1.5 : 1 | ❌ 3 |
66
+ | **Track công tắc lúc tắt** (`muted/40`) | ~1.6 : 1 | | ❌ 3 |
67
+
68
+ **`--muted` chỉ đạt trên ba nền sáng nhất**: card `--surface`, `--surface-hover`, nền trang
69
+ `--background`. Trên nền xám đậm hơn nó trượt: `--secondary` 4.04, `--background-hover`
70
+ 4.01, lớp phủ `foreground/5` trên nền trang 4.12, `foreground/8` trên dòng đang rê 4.05.
71
+ Chữ phụ nằm trên những nền đó (số đếm trong tab đang chọn, chữ trong ô sửa tại chỗ lúc rê)
72
+ thì dùng **`text-foreground/70`**: lớp phủ theo màu chữ nên đậm theo nền, đạt từ 4.82 : 1
73
+ trên mọi nền xám của skill. Đừng nhạt hơn `/70`: `/65` đã trượt trên `--secondary` (4.17).
74
+ Icon phụ `text-muted` thì cứ giữ, icon chỉ cần 3 : 1.
75
+
76
+ ⚠️ **Viền điều khiển KHÔNG đạt 3 : 1, và đó là đánh đổi có chủ ý.** Đạt thì cần viền
77
+ xám cỡ `#8a8a91`; chủ dự án thấy đậm và xấu, bác.
78
+ `#f2f2f2` (1.1:1) thì lại mờ quá, radio chưa chọn gần như vô hình; `#e4e4e7` (1.27:1) thì
79
+ đường kẻ sidebar đậm. Chốt `#eaeaea` (~1.2:1). Đừng đổi mà không hỏi. Skill
80
+ bù bằng ba thứ khác để người dùng nhận ra ô nhập: nhãn luôn hiện phía trên
81
+ (`I26`), placeholder, và viền + ring khi focus.
82
+
83
+ Dự án **phải đạt WCAG AA đầy đủ** (cơ quan nhà nước, y tế, ngân hàng) thì thêm
84
+ token riêng cho viền điều khiển (`--border-control: #8a8a91`, nền tối `#5e6578`)
85
+ và đổi class của ô nhập, select, checkbox, radio sang nó (nút outline thì không cần); track
86
+ công tắc lúc tắt lên `muted/75`. **Đừng** đổi thẳng
87
+ `--border-strong`: đường kẻ sidebar, tab, badge dùng chung token đó sẽ đậm theo.
88
+
89
+ Flat hiếm khi trượt con số của chữ, vì chữ đậm nằm trên nền trắng đặc. Glass,
90
+ gradient và tối thì **trượt đầu tiên**. Nên luật này được viết ở đây, cạnh các
91
+ phong cách làm nó trượt.
92
+
93
+ **Đo ở chỗ tệ nhất**, không đo ở giữa:
94
+
95
+ - Trên gradient, đo ở **đầu gần màu chữ nhất**.
96
+ - Trên glass, đo ở chỗ phía sau **gây bất lợi nhất**: chữ trắng thì đo trên vùng ảnh sáng nhất phía sau, chữ đen thì đo trên vùng tối nhất.
97
+ - Placeholder và chữ phụ cũng tính. Chữ phụ `text-white/50` trên nền kính thường là thứ trượt trước tiên.
98
+
99
+ ---
100
+
101
+ ## Nhận diện
102
+
103
+ **P4. Tự tìm phong cách của dự án, để biết có theo hay không. Một phong
104
+ cách chỉ là "của dự án" khi nó có mặt trên bề mặt chính.**
105
+
106
+ Chạy lệnh tầng 3 ở `SKILL.md` câu 2, rồi đọc số:
107
+
108
+ | Kết quả | Kết luận |
109
+ | --- | --- |
110
+ | Tín hiệu có ở **từ 3 file component trở lên**, trên card, modal, header, sidebar | Đó là phong cách của dự án → **theo**, báo theo mẫu `P1` |
111
+ | Chỉ 1–2 file | Ngoại lệ cục bộ: một banner, một trang quảng bá. **Không** tính là phong cách của dự án, làm flat |
112
+ | Có token riêng cho nó (`--glass-bg`, `--gradient-*`, `--shadow-card`) | Tính là phong cách của dự án **dù đếm file ra ít**, vì có token là có chủ đích → **theo** |
113
+ | **Tối**: layout gốc có nền tối | Tính là phong cách của dự án **chỉ với một file đó**, vì nền tối chỉ nằm ở gốc → **theo** |
114
+ | **Màu**: nền, viền, chữ có sắc (chip tô màu nhấn nhạt, khối nền xanh nhạt, pill màu) ở **từ 3 file trở lên** | Dự án có ngôn ngữ màu → **theo**: màn mới dùng đúng những cách tô đó, không rút về xám (nguyên tắc "dự án đã có ngôn ngữ màu" ở đầu `principles.md`). Luật về nghĩa và đọc được vẫn giữ |
115
+ | Có token thang màu biểu đồ (`--chart-1`…) | Biểu đồ phân loại dùng thang đó (`components/charts.md`) |
116
+ | Không tín hiệu nào đáng kể | Flat hoặc dự án trống → flat (`P6`) |
117
+
118
+ Đếm ra để **quyết định theo dự án hay flat**. Ngưỡng 3 file là để một banner lẻ
119
+ không kéo cả màn sang phong cách khác.
120
+
121
+ Người dùng gửi **ảnh tham chiếu** thì đó là ca "tự nêu phong cách" của `P1`: nhận
122
+ diện bằng mắt theo dòng "Nhận ra từ ảnh" ở từng khối bên dưới, rồi làm theo luôn,
123
+ không hỏi. Có ảnh thì ảnh thắng code.
124
+
125
+ **P5. Phong cách chồng nhau thì áp cả hai khối. Codebase lẫn lộn thì theo phần
126
+ mới nhất.**
127
+
128
+ - **Glass + tối** là cặp rất hay gặp. Áp cả `P8` lẫn `P10`.
129
+ - **Nổi + gradient ở một điểm**: card nổi, chỉ gói đề xuất có gradient. Áp `P7`, còn `P9` chỉ áp cho đúng điểm đó.
130
+ - **Codebase lẫn lộn** (trang cũ flat, trang mới glass): theo phần **mới nhất** (xem ngày sửa file trong git), vì đó thường là hướng dự án đang đi tới. Lúc giao nói rõ khu nào đang dùng gì và mình đã theo bên nào.
131
+
132
+ ---
133
+
134
+ ## Từng phong cách
135
+
136
+ Mỗi khối có bốn phần: nhận ra, luật được đè, công thức, bẫy.
137
+
138
+ ### P6. Flat đường tóc — mặc định của skill
139
+
140
+ **Luôn là mặc định**, trừ khi người dùng chọn khác theo `P1`. Toàn bộ các luật
141
+ `M` và `F` viết cho phong cách này. Không đè gì cả.
142
+
143
+ - **Nhận ra từ code:** không có `backdrop-blur`, không có gradient trên bề mặt, bóng không vượt `shadow-sm`, card có `border`.
144
+ - **Nhận ra từ ảnh:** nền xám nhạt, card trắng viền rất mảnh, gần như không có bóng.
145
+
146
+ ### P7. Nổi — thứ bậc bằng bóng
147
+
148
+ - **Nhận ra từ code:** `shadow-md` trở lên trên card thường, card ít hoặc không có `border`.
149
+ - **Nhận ra từ ảnh:** card nổi lên khỏi nền bằng bóng mềm, gói đề xuất nổi cao hơn các gói còn lại.
150
+ - **Được đè:** `M13`, `M15`, `M29`. `F22` được đè một phần: card bấm được thì hover **tăng bóng** một bậc, vẫn không `scale`.
151
+
152
+ ```html
153
+ <div class="rounded-2xl bg-surface shadow-sm ring-1 ring-black/5 hover:shadow-md">
154
+ ```
155
+
156
+ **Thang bóng, mỗi tầng một bậc, không hai tầng trùng nhau:**
157
+
158
+ | Tầng | Bóng |
159
+ | --- | --- |
160
+ | Card | `shadow-sm` |
161
+ | Card bấm được, khi hover | `shadow-md` |
162
+ | Dropdown, popover | `shadow-popover` (= `shadow-lg`, `M15`) |
163
+ | Modal, panel trượt, **gồm sidebar trượt ở màn hẹp** | `shadow-modal` (= `shadow-xl`) |
164
+
165
+ **Bẫy**
166
+
167
+ - **Card với modal cùng bóng thì modal không còn nổi.** Thang trên tồn tại để lớp cao hơn luôn nổi hơn. Tăng bóng card lên `shadow-lg` là modal phải lên theo, và dropdown cũng vậy.
168
+ - **Bộ token bóng đủ bốn bậc, kể cả khi trang chưa có modal.** Sidebar trượt dưới `lg` là tầng modal, và nó chỉ hiện ở màn hẹp nên hay bị quên. Chỉ định ba token (card, card khi rê, popover) thì sidebar trượt nằm phẳng trên lớp phủ, không bóng, thấp hơn cả card phía sau. Probe báo "Panel, modal mở ra không nổi hơn trang".
169
+ - **`ring-1 ring-black/5` đi cùng bóng là hợp lệ ở đây.** Nó vạch mép card cho sắc nét trên nền trắng. Đây là chỗ đè `M29`: ở flat thì viền với bóng không đi cùng nhau, ở phong cách nổi thì được.
170
+ - **Ở nền tối, bóng một mình khó thấy.** Dự án nổi mà có dark mode thì ở chế độ tối giữ thang bóng, đậm hơn, thêm viền 1px (`ring-1 ring-white/10`), và bề mặt sáng dần theo tầng (`M21`, `M23`). Ba thứ đi cùng nhau; đừng chỉ tăng bóng lên cho bằng được.
171
+ - `scale-105` khi hover làm chữ bị mờ trong lúc chuyển động. Chỉ tăng bóng, không phóng to.
172
+
173
+ ### P8. Glass — kính mờ
174
+
175
+ - **Nhận ra từ code:** `backdrop-blur`, `backdrop-filter`, nền bán trong suốt `bg-white/10`, `bg-black/20`, viền `border-white/10`.
176
+ - **Nhận ra từ ảnh:** bề mặt trong mờ, thấy thấp thoáng màu hoặc ảnh phía sau, mép có một đường sáng mảnh.
177
+ - **Được đè:** `F19`, `M13` (viền chuyển thành viền trắng mờ), `M15`, `M1`.
178
+
179
+ ```html
180
+ <!-- Nền tối -->
181
+ <div class="rounded-2xl border border-white/10 bg-white/5 backdrop-blur-xl">
182
+
183
+ <!-- Nền sáng -->
184
+ <div class="rounded-2xl border border-white/50 bg-white/60 shadow-sm backdrop-blur-xl">
185
+
186
+ <!-- Trình duyệt không hỗ trợ blur thì rơi về nền gần đặc -->
187
+ <div class="bg-white/90 supports-[backdrop-filter]:bg-white/60 supports-[backdrop-filter]:backdrop-blur-xl">
188
+ ```
189
+
190
+ **Bẫy**
191
+
192
+ - **Kính mà phía sau không có gì thì chỉ là một card xám.** Đây là phần của `F19` vẫn còn nguyên giá trị: blur chỉ có nghĩa khi phía sau có ảnh, gradient hay nội dung cuộn qua. Dự án glass mà màn mới có nền trơn thì **phải có thứ gì đó phía sau**, thường là lớp gradient nền của dự án. Đừng đặt kính lên nền phẳng.
193
+ - **Tương phản trượt theo thứ nằm phía sau** (`P3`). Kính của mình có thể đạt chuẩn trên nền tối nhưng trượt khi người dùng cuộn qua một ảnh sáng. Đo ở chỗ tệ nhất. Không đạt thì tăng độ đục của nền kính, đừng tăng độ đậm chữ.
194
+ - **Blur tốn GPU, nhất là trên mobile.** Chi phí tăng theo diện tích nhân với số lớp chồng nhau. Dùng cho header, sidebar, modal, và một đến ba card nổi bật. **Không** dùng cho từng dòng trong một danh sách dài đang cuộn, vì trang sẽ giật.
195
+ - **Luôn có fallback** như dòng thứ ba ở trên. Không hỗ trợ blur mà nền vẫn `/5` thì chữ nằm trên nền gần như trong suốt.
196
+ - Viền trắng mờ là **bắt buộc**. Thiếu nó thì mép kính tan vào nền và khối không có hình.
197
+
198
+ ### P9. Gradient và màu thương hiệu đặc
199
+
200
+ - **Nhận ra từ code:** `bg-gradient-*`, `bg-linear-*` (Tailwind v4), `linear-gradient`, `radial-gradient` trên card hay nút; hoặc cả card đổ màu thương hiệu đặc.
201
+ - **Nhận ra từ ảnh:** gói đề xuất đổ gradient hoặc màu thương hiệu cả khối, nút có chuyển màu.
202
+ - **Được đè:** `M12`, và tỉ lệ `M2`.
203
+
204
+ **Không đè `M3`.** Gradient vẫn đi từ **màu nhấn của dự án**. Ba gói ba gradient
205
+ ba màu là ba màu nhấn, tức là trượt `M3` và `I3` cùng lúc.
206
+
207
+ ```html
208
+ <!-- Gói đề xuất: đổ màu cả khối, nút đảo màu -->
209
+ <div class="rounded-2xl bg-linear-to-br from-primary to-primary-hover text-primary-foreground">
210
+ <button class="bg-surface text-foreground">Chọn gói này</button>
211
+ </div>
212
+ ```
213
+
214
+ **Bẫy**
215
+
216
+ - **Gradient ở mọi nơi thì không nơi nào nổi.** Gradient là cách nói "chỗ này quan trọng nhất". Dùng cho **một** loại bề mặt: gói đề xuất, hoặc nút chính. Không phải cả hai, và không phải mọi card. Đây là phần của `M2` vẫn còn nguyên.
217
+ - **Gradient không `transition` được.** `transition-colors` không nội suy được `background-image`, nên hover sẽ nhảy cái rụp hoặc không đổi gì. Làm hover bằng `hover:brightness-110` kèm `transition-[filter]`, hoặc bằng một lớp phủ đổi độ đục.
218
+ - **Chữ trên gradient đo ở đầu nhạt nhất** (`P3`). Đạt ở giữa không có nghĩa là đạt ở góc.
219
+ - **Nút nằm trên khối đã đổ màu thì đảo màu**: nền `--surface`, chữ `--foreground`. Nút màu nhấn đặt trên nền màu nhấn thì biến mất.
220
+ - Gradient trải trên diện tích lớn dễ bị **sọc** (banding). Giữ hai điểm màu gần nhau, hoặc thu vùng gradient nhỏ lại.
221
+
222
+ ### P10. Tối là chính
223
+
224
+ - **Nhận ra từ code:** nền gốc tối (`bg-zinc-950`, `bg-black`, `bg-neutral-900`) trên `body` hoặc layout, ít hoặc không có biến thể `dark:`, hoặc có `color-scheme: dark`.
225
+ - **Nhận ra từ ảnh:** nền đen hoặc gần đen là mặc định, không phải một chế độ bật lên.
226
+ - **Được đè:** `M1`, `M20`, `M23`. Dự án dùng xám kẽm thì giữ xám kẽm, đừng đổi sang navy.
227
+ - **Vẫn áp:** `M21`, `M22`. Hai luật đó viết cho nền tối, và nền tối ở đây là nền chính.
228
+
229
+ **Bẫy**
230
+
231
+ - **Đừng đen tuyệt đối với trắng tuyệt đối.** `#000` với `#fff` chênh nhau quá gắt, chữ bị nhoè sáng khi đọc lâu. Dùng nền gần đen (`zinc-950`) và chữ gần trắng (`zinc-100`).
232
+ - **Độ đậm chữ giữ nguyên như bản sáng.** Thứ bậc chữ ở nền tối đi bằng **độ sáng**: chữ chính gần trắng, chữ phụ xám sáng hơn tỉ lệ so với bản sáng (`--muted` tối `#8b93a7`, 6.6:1). Không bộ thiết kế lớn nào hạ độ đậm ở nền tối; font nào trông dày quá thì đo bằng mắt trên chính font đó, không hạ theo luật.
233
+ - **Thứ bậc bằng bề mặt sáng dần theo tầng, cộng viền và bóng.** Nền trang tối nhất, card sáng hơn một bậc, lớp nổi sáng hơn nữa (`M21`). Bóng vẫn giữ nhưng đậm hơn và đi cặp viền 1px, vì một mình bóng ở nền tối khó thấy (`M23`).
234
+ - Viền `border-white/10` gánh việc tách khối (`M23`), vì các bề mặt tối chênh nhau quá ít.
235
+ - Vùng tô (nút phụ, mục đang chọn, nền rê) là trắng phủ mờ, sáng hơn card (`M21`).
236
+ - Ảnh và avatar cần `ring-1 ring-white/10`. Thiếu nó thì ảnh tối tan vào nền.
237
+
238
+ ### P11. Neumorphism và 3D — nhận ra, theo, nhưng vá tương phản
239
+
240
+ - **Nhận ra neumorphism:** mỗi khối có **hai** bóng ngược hướng (một sáng một tối) trên nền **cùng màu** với chính nó.
241
+ - **Nhận ra 3D:** icon và minh hoạ dựng hình khối, kiểu clay, có ánh sáng và đổ bóng.
242
+
243
+ **Neumorphism trượt `P3` theo cấu trúc.** Khối cùng màu với nền nên nút gần như
244
+ vô hình, và trạng thái bấm với không bấm khó phân biệt. Theo phong cách của họ,
245
+ nhưng **nút chính phải có màu nhấn hoặc viền đạt 3 : 1**, và trạng thái đang
246
+ chọn phải khác bằng một thứ ngoài bóng.
247
+
248
+ **3D thường nằm ở minh hoạ, không phải ở khung giao diện.** Coi icon 3D như ảnh,
249
+ cùng lý do với ngoại lệ avatar của `M12`. Khung (card, nút, ô nhập) theo phong
250
+ cách nền của dự án. Đừng tự dựng nút 3D vì thấy dự án có icon 3D.
251
+
252
+ ---
253
+
254
+ ### P12. Có màu — hai công thức: trang lướt để chọn, và dashboard
255
+
256
+ Flat thuần đọc ra "buồn màu" ở hai chỗ: trang người dùng cuối lướt để chọn (tìm việc, tìm
257
+ phòng, sản phẩm, khoá học), trang nào cũng như trang quản trị (chủ dự án thấy); và dashboard dự án mới chưa có brand, màu nhấn
258
+ gần đen nên chọn "Màu" vẫn trắng đen. Hai chế độ dựng lại đưa nó thành dòng Có màu
259
+ (`review.md`, `V1d`); người dùng tự xin trong đề thì dựng theo công thức dưới; ngoài hai chỗ đó thì
260
+ theo `P1`. Wireframe không có nấc Có màu (`design-process.md`, `U3`).
261
+
262
+ - **Nhận ra từ ảnh:** đầu trang là một dải màu đậm (đặc hoặc chuyển màu) ôm header và ô tìm,
263
+ chân trang cùng màu; vài mục trong danh sách có nền nhạt màu nhấn kèm nhãn "Gấp", "Hot";
264
+ tiêu đề mục đậm.
265
+ - **Được đè:** `M2` (tỉ lệ 95/5), `M12` (chỉ ở dải), `M4` (chỉ ô icon và chuỗi biểu đồ của
266
+ công thức B). Nguyên tắc `P2` giữ nguyên, nhất là `M3` một màu nhấn cho hành động và `P3`
267
+ tương phản.
268
+
269
+ **Công thức A, trang lướt để chọn**, đúng năm chỗ, không thêm chỗ thứ sáu:
270
+
271
+ | Chỗ | Làm gì |
272
+ | --- | --- |
273
+ | Dải đầu trang | Khối bọc header + ô tìm (hay hàng tên trang) nền màu nhấn đậm: `bg-primary`, hoặc `bg-linear-to-r from-primary to-primary-hover` (hai điểm gần nhau, `P9`). Chữ, link header trắng; ô tìm nền trắng; nút Tìm đảo màu (`bg-surface text-foreground`, `P9`). Dải hết ở dưới hàng tìm, nội dung bắt đầu trên nền trang như cũ, không kéo card lấn lên dải bằng số âm (`N11`) |
274
+ | Chân trang | Cùng màu dải, chữ trắng. Trang không có chân thì bỏ |
275
+ | Mục nổi bật | **Chỉ khi dữ liệu có trường đó** (gấp, hot, được tài trợ): nền `bg-primary/5`, viền `border-primary/25`, nhãn đặc `bg-primary text-primary-foreground` ở góc. Không có trường thì không bịa, lúc giao ghi "cần trường … để làm mục nổi bật" |
276
+ | Chữ | Tiêu đề mục `font-semibold`; tên trang giữ `text-xl` (luật đã chốt 11) mà lên `font-semibold`, từ khoá hay con số trong tên trang tô `text-primary`; tiêu đề khối trong panel chi tiết `text-lg font-semibold`. Giá, lương giữ `font-semibold` như cũ |
277
+ | Điểm nhỏ | Chấm đầu dòng danh sách trong chi tiết `marker:text-primary`; ô chữ viết tắt thay logo nền `bg-primary/10 text-primary` thay cho xám |
278
+
279
+ **Công thức B, dashboard và trang làm việc trong app**: không dải màu, không mục "hot" (lạc loài
280
+ ở trang báo cáo). Đè thêm `M4` (màu để phân loại) **chỉ ở ô icon và chuỗi biểu đồ**:
281
+
282
+ | Chỗ | Làm gì |
283
+ | --- | --- |
284
+ | Ô icon card số liệu | Ô `size-8 rounded-lg`, icon lucide `size-4`; mỗi card một sắc nhạt (`bg-indigo-50 text-indigo-600`, `bg-teal-50 text-teal-600`, `bg-violet-50 text-violet-600`, `bg-sky-50 text-sky-600`), tối đa bốn sắc một màn. Con số vẫn `text-foreground`, không tô |
285
+ | Ô icon đầu dòng theo loại | Bộ phận, nhà cung cấp, loại giao dịch: cùng bộ sắc nhạt, **một loại một sắc cố định** trên mọi màn (Kỹ thuật luôn teal). Không có loại thì không ô |
286
+ | Biểu đồ | Chuỗi chính màu nhấn; nhiều chuỗi thì lấy bộ sắc trên theo cùng thứ tự; kỳ chưa trọn nét đứt hay gạch (`charts.md`) |
287
+ | Trạng thái | Như nấc Màu: `M4` trên thanh tiến độ, số vượt, quá hạn. Sắc phân loại không trùng sắc trạng thái trên cùng một thứ (thanh ngân sách không tô teal vì bộ phận là teal) |
288
+ | Badge trạng thái (người dùng xin "badge có màu") | Đỏ, hổ phách, xanh lá giữ nghĩa `M7`. Các trạng thái xám (đang chạy đúng luồng) mới được lấy sắc phân loại, và **các sắc trong một bảng trạng thái cách nhau từ ~45° trên vòng màu**, không lấy hai sắc kề nhau: `sky`–`blue` (~23°), `blue`–`indigo`, `indigo`–`violet`, `emerald`–`teal`. Không trùng sắc màu nhấn (nút chính teal thì không badge teal). Không đủ sắc cách xa thì trạng thái nhiều dòng nhất (thường là bước bình thường nhất, vd "Đã xác nhận") giữ xám: một danh sách toàn một màu badge là mảng màu, không còn phân biệt. Sai: "Đã xác nhận" `sky-700` cạnh "Đang khám" `blue-700`, liếc ra một màu xanh |
289
+
290
+ **Bẫy**
291
+
292
+ - **Sắc phân loại không mang nghĩa trạng thái**: đỏ, hổ phách, xanh lá để dành cho `M4`. Ô icon
293
+ "Chờ duyệt" không tô hổ phách chỉ vì "chờ"; tô theo bộ sắc phân loại.
294
+ - **Chip lọc đang chọn không đặc màu nhấn** khi đã có dải: sáu chip đặc cam dưới một dải cam là
295
+ hai mảng cùng nặng tranh nhau. Chip theo `layouts/overlay.md` (nền `foreground/10` + `inset-ring`).
296
+ - **Nổi bật tối đa khoảng một phần năm danh sách.** Mục nào cũng hot thì không mục nào hot (`M2`).
297
+ - **Mục nổi bật vẫn khác mục đang chọn**: đang chọn giữ nền của `I10`, không trùng `bg-primary/5`.
298
+ - Tương phản chữ trắng trên dải đo ở đầu nhạt nhất (`P3`); màu nhấn nhạt (vàng, cam sáng) thì dải
299
+ dùng `primary-hover` hay một bậc đậm hơn, chữ vẫn trắng.
300
+
301
+ ## Không có trong bảng
302
+
303
+ Gặp phong cách không khớp khối nào (brutalism, retro, skeuomorphism...):
304
+
305
+ 1. **Đo trước khi đoán.** Mở ba component chính (card, nút, ô nhập) ra đọc class thật, đừng suy từ tên file hay từ một ảnh.
306
+ 2. **Theo những gì đo được**, đè đúng những luật gu flat mà phong cách đó chạm vào.
307
+ 3. **Giữ nguyên toàn bộ cột "Nguyên tắc" của `P2`.** Phong cách lạ đến đâu cũng không đè được `I3`, `P3`, hay 375px.
308
+ 4. **Báo trong dòng `Audit:`** rằng đây là phong cách ngoài bảng, và mình đã đè những luật nào.
309
+
310
+ Phong cách ngoài bảng mà người dùng **chưa chọn** thì vẫn theo `P1`: dự án có
311
+ thì theo dự án, không thì flat; báo lúc giao.
@@ -0,0 +1,219 @@
1
+ # Nhiều màn hình — luật D
2
+
3
+ Mở file này khi đề bài **nhiều hơn một bề mặt**, hoặc đề đòi dựng design system trước
4
+ (`D9`). Một câu như *"dựng kanban board
5
+ quản lý công việc và table quản lý project, có đủ CRUD"* không phải hai màn, mà
6
+ là khoảng **tám bề mặt**: board, thẻ, cột rỗng, bảng, dòng bảng, form tạo, form
7
+ sửa, hộp xác nhận xoá, bộ lọc.
8
+
9
+ **Chẩn đoán gốc:** design system quy định màu và cỡ chữ. Nó **không** quy định
10
+ rằng thẻ kanban và dòng bảng phải nói cùng một ngôn ngữ. Từng màn đều hợp lệ,
11
+ ghép lại thành hai app khác nhau.
12
+
13
+ Phàn nàn thật từ một người dùng: *có config design system sẵn mà output vẫn không
14
+ đồng bộ giữa các màn · không đẹp, AI cứ chọn màu xám tối · phải prompt chỉnh
15
+ nhiều lần.*
16
+
17
+ ---
18
+
19
+ ## D1. Định nghĩa hợp đồng nguyên tố TRƯỚC, một lần, cho cả bộ
20
+
21
+ Trước khi dựng màn đầu tiên, khai ra bảy nguyên tố dưới đây. Mọi màn sau dùng
22
+ đúng bộ đó. **Cấm đẻ biến thể giữa chừng.**
23
+
24
+ | Nguyên tố | Phải chốt |
25
+ | --- | --- |
26
+ | Nút | bốn dạng ở `I1`, cỡ, có icon hay không |
27
+ | Badge trạng thái | hình dạng, nền hay chỉ chữ màu, cỡ chữ |
28
+ | Ô nhập | chiều cao, viền, hành vi lúc focus |
29
+ | Card | padding, bo góc, có viền hay không |
30
+ | Dòng danh sách | chiều cao, padding, hành vi hover |
31
+ | Modal | bề rộng, chỗ đặt nút, có cho bấm ra ngoài không |
32
+ | Trạng thái rỗng | icon, tiêu đề, câu phụ, có nút không |
33
+
34
+ Viết bảy dòng này ra **trong lượt trả lời**, trước khi viết HTML. Nó dài chưa tới
35
+ mười lăm dòng và nó cứu cả đợt dựng.
36
+
37
+ Project đã có thư viện component thì bảng này chính là **danh sách component
38
+ phải đi tìm**, không phải danh sách phải viết. Xem `S9`.
39
+
40
+ ---
41
+
42
+ ## D2. Một bảng ánh xạ trạng thái duy nhất
43
+
44
+ `todo` / `doing` / `done`, mức ưu tiên, vai trò — khai **một chỗ** thành cặp
45
+ *nhãn + màu*, dùng y hệt ở mọi bề mặt.
46
+
47
+ Cấm board dùng badge nền màu còn bảng dùng chấm tròn. Cùng một trạng thái mà hai
48
+ hình dạng thì người dùng phải học hai lần.
49
+
50
+ ```
51
+ STATUS = {
52
+ todo: { nhãn: "Cần làm", màu: xám, icon: "circle" },
53
+ doing: { nhãn: "Đang làm", màu: xám, icon: "circle-dot" },
54
+ review: { nhãn: "Chờ duyệt", màu: hổ phách, icon: "circle-ellipsis" },
55
+ done: { nhãn: "Xong", màu: xanh lá, icon: "circle-check" },
56
+ }
57
+ ```
58
+
59
+ Màu vẫn theo `M4`: đây là trạng thái thật, nên được dùng màu. Bốn tông và hình
60
+ badge lấy đúng bảng trong `M7`; "Đang làm" xám chứ không hổ phách, vì hổ phách là
61
+ "cần chú ý" và xanh để dành cho "xong". Hai trạng
62
+ thái cùng tông thì tách bằng icon, bảng icon cũng ở `M7`.
63
+
64
+ **Trạng thái làm tiêu đề thì cùng một hình ở mọi view.** Hàng nhóm của bảng và đầu
65
+ cột kanban là **icon + tên + số đếm**, không pill; trạng thái làm giá trị một ô thì
66
+ mới là pill. Bảng nhóm dùng pill còn kanban chỉ chữ trơn là cùng một trạng thái hai
67
+ hình.
68
+
69
+ ---
70
+
71
+ ## D3. CRUD dùng một bộ khuôn
72
+
73
+ - **Tạo và sửa dùng CÙNG một form.** Chỉ khác tiêu đề và chữ trên nút. Hai form
74
+ riêng là hai chỗ để lệch nhau.
75
+ - **Xoá mà khôi phục được** (thùng rác, xoá mềm) thì **xoá ngay + toast "Hoàn tác"**, như
76
+ Các app lớn: hộp xác nhận cho mọi thùng rác dạy người ta bấm "Đồng ý" không
77
+ đọc. **Hộp xác nhận** chỉ khi không lấy lại được, hoặc xoá nhiều dòng một lúc. Khôi
78
+ phục được hay không là logic, người dùng quyết (`N10`); đề không nói thì hỏi một dòng
79
+ lúc giao. Xem `layouts/overlay.md`.
80
+ - Hộp xác nhận bắt **gõ lại một cụm từ** chỉ dựng khi đề yêu cầu (quyết định sản
81
+ phẩm, không phải mặc định), **trừ việc xoá cả không gian** (workspace, tổ chức): việc đó
82
+ mất dữ liệu của mọi thành viên, nên mặc định bắt gõ lại tên, nút xoá mở khoá khi khớp.
83
+ Các sản phẩm lớn đều thêm một bước ngoài hộp hỏi thường cho việc này (gõ
84
+ tên là cách hay gặp nhất; có nơi gửi mã qua email hoặc hỏi mật khẩu). Khi có ô gõ đó thì
85
+ không cho bấm ra ngoài để đóng (`I20`). Khuôn hộp và ô ở `layouts/overlay.md`.
86
+
87
+ ---
88
+
89
+ ## D4. Nhiều màn thì báo bố cục MỘT LẦN cho cả bộ
90
+
91
+ Đề nhiều màn vào nhánh `U` như mọi đề dựng (`SKILL.md` câu 1): `U2` mỗi màn một dòng,
92
+ wireframe cho cả bộ, rồi hợp đồng nguyên tố `D1` chốt ở `U4` trước khi dựng màn đầu tiên.
93
+ Bố cục mặc định của từng loại màn chỉ dùng thẳng ở lối "dựng luôn" hoặc việc nhỏ hơn một
94
+ màn. Lúc giao báo **một** đoạn: liệt kê các bề mặt đã dựng, màn chính theo phương án nào,
95
+ bề mặt phụ (form, hộp xác nhận, trạng thái rỗng) theo khuôn chung nào. Muốn đổi thì người
96
+ dùng nói.
97
+
98
+ ---
99
+
100
+ ## D5. Màu nhấn phải thật sự xuất hiện
101
+
102
+ Liệt kê ra nó được dùng ở đâu. Cả bộ màn không có chỗ nào dùng màu nhấn thì đó
103
+ là **chưa quyết định**, không phải tối giản.
104
+
105
+ Khác biệt nằm đúng ở đây: xám tối **có chủ ý** thì màu nhấn vẫn xuất hiện ở nút
106
+ chính, ở trạng thái đang chọn, ở link. Xám tối **vì chưa quyết định** thì cả
107
+ trang không có chỗ nào dùng màu nhấn, và nó đọc ra là một bản nháp.
108
+
109
+ `M2` nói 5% điểm nhấn. **5% không phải 0%.**
110
+
111
+ ---
112
+
113
+ ## D6. Đặt tên khu vực rồi dùng đúng tên đó suốt
114
+
115
+ Hệ thống nhiều màn luôn có một khung chung: cột trái, vùng nội dung, cột phải,
116
+ thanh trên mobile, thanh dưới mobile. Đặt tên một lần, ghi ra, rồi dùng đúng tên
117
+ đó trong mọi câu trả lời sau.
118
+
119
+ Nghe như chuyện nhỏ, nhưng ở một dự án thật đây là mục **đầu tiên** của `AGENTS.md`,
120
+ vì không có nó thì mỗi lượt lại phải mô tả lại "cái cột bên trái ấy" và mỗi lần
121
+ mô tả lại lệch một chút.
122
+
123
+ Kèm theo tên thì ghi luôn **code chết**: component nào không được import ở đâu
124
+ nữa, để lượt sau không hồi sinh nó.
125
+
126
+ ---
127
+
128
+ ## D7. Khung chung thì sửa sau cùng, hoặc không sửa
129
+
130
+ Thứ tự đụng vào, từ ít liên đới nhất tới nhiều nhất:
131
+
132
+ 1. Khối đã tự gom theo feature
133
+ 2. Trang có ít selector
134
+ 3. Trang lớn
135
+ 4. Thứ dùng chung khắp nơi — shell, sidebar, modal
136
+
137
+ Xem `refactor.md` luật `L8` để biết cách đếm quy mô trước khi chọn.
138
+
139
+ ---
140
+
141
+ ## D8. Nội dung lặp lại ở nhiều màn phải có một component
142
+
143
+ Dấu hiệu: cùng một "thẻ khoá học" xuất hiện ở trang danh sách, trang tìm kiếm,
144
+ và cột phải. Ba chỗ đó mà ba lần viết thì chắc chắn ba lần lệch.
145
+
146
+ Tách thành một component nhận prop, rồi mỗi chỗ chỉ đổi kích thước qua
147
+ `className`. Cỡ chữ tên thẻ phải **giống nhau ở mọi breakpoint và mọi chỗ đặt** —
148
+ xem `T8`, vì tiêu đề khối được tính theo nó.
149
+
150
+ ---
151
+
152
+ ## D9. Đề "dựng design system trước": nền trước, màn sau ⚑
153
+
154
+ Đề nói **"design system"**, "dựng component trước", "UI kit", "chốt token, spacing,
155
+ typography rồi mới dựng màn", "build a design system", "component library first" thì vào
156
+ đây (`SKILL.md` câu 1), **không vào nhánh `U`**: design system không có bố cục để vẽ
157
+ wireframe, thứ cần duyệt là hình của từng nguyên tố. Hợp đồng `D1` ở lối này không còn là
158
+ bảy dòng chữ trong lượt trả lời, mà thành code thật và một trang xem được.
159
+
160
+ 1. **Audit câu 2 như mọi lối.** Dự án đã có token hay thư viện component (shadcn, MUI, bộ
161
+ nội bộ) thì design system là **xếp lại cái đang có**: token của họ vào hai vai viền
162
+ `M14`, component của họ chỉnh token cho khớp (`S9`). Không dựng bộ thứ hai cạnh bộ cũ.
163
+ Với shadcn: **giữ tên token của shadcn, trỏ giá trị về token của skill**, để component shadcn
164
+ thêm sau vẫn đúng màu. Tên trùng mà khác nghĩa thì theo shadcn: `--muted` của shadcn là
165
+ *nền*, nên chữ phụ của skill (`text-muted`) viết thành `text-muted-foreground` trong cả dự
166
+ án.
167
+ 2. **Brief một khối, không dừng**: sản phẩm, người dùng, màu nhấn, font, phong cách (`P1`),
168
+ chỉ sáng hay có tối (`M20`), ngôn ngữ của copy (`T24`). Đề không nói thì lấy mặc định
169
+ của `brand-tokens.md` (gần đen, Inter, flat, chỉ sáng) và ghi vào brief. Dự án chưa có
170
+ màu brand thì trang design system có nhóm ba màu gợi ý, như nhóm Nhấn trên thanh
171
+ wireframe (`design-process.md`, `U3`).
172
+ 3. **Token**: chép `tokens.css` vào file token của dự án theo `brand-tokens.md`, chỉ sửa
173
+ khối font và màu nhấn. Thang cỡ chữ, nhịp, chiều cao control lấy từ `budgets.md`; bo
174
+ góc theo `F1`, `M19`. **Không đẻ thang hay token mới** (`M14`, `M16`): bộ của skill đã
175
+ qua test, nghĩ lại từ đầu là mất phần đó.
176
+ 4. **Component: bảy nguyên tố của `D1`** (nút, badge trạng thái, ô nhập, card, dòng danh
177
+ sách, modal, trạng thái rỗng), **cộng những gì đề nêu tên**. Mỗi cái chép công thức từ
178
+ file mẫu của nó (bảng "Mở khi dựng đúng khối đó", mục 2 của `SKILL.md`), đặt theo quy
179
+ ước thư mục của dự án. Không dựng hết các mẫu cho "đủ bộ" (`S1`); lúc giao liệt kê
180
+ những mẫu còn sẵn, cần cái nào thì gọi tên.
181
+ 5. **Một trang xem design system**: route `/design-system` (dự án có Storybook thì viết
182
+ story thay cho trang; không có app thì một file HTML). Dự án có dark mode thì trang có
183
+ nút đổi theme ở đầu trang (`M31`) để duyệt cả hai bản, và bảng màu ghi mã cả hai theme.
184
+ Thứ tự khối:
185
+ - **Màu**: ô màu kèm tên token và mã; cặp chữ trên nền chính kèm tỉ lệ tương phản. Cột
186
+ tỉ lệ chỉ ghi số; **chỉ cặp trượt mới có nhãn** ("Dưới 4.5:1", màu cảnh báo), cặp đạt
187
+ để trống. Mười một dòng "Đạt AA" xanh giống nhau là một ý nói mười một lần, mắt phải dò
188
+ hết cột mới biết có cặp nào trượt không.
189
+ - **Chữ**: từng bậc của thang cỡ chữ, viết bằng câu thật theo ngôn ngữ của dự án (tiếng
190
+ Việt thì có đủ dấu, `T5`), ghi cỡ và độ đậm.
191
+ - **Khoảng cách, bo góc, viền, bóng**: các bậc đang dùng, hai vai viền đặt cạnh nhau,
192
+ bóng của lớp nổi.
193
+ - **Từng component**, mỗi trạng thái một ví dụ tĩnh đặt cạnh nhau (thường, rê, focus,
194
+ khoá, đang tải, lỗi), không bắt bấm mới thấy. Trang dùng **chính component vừa
195
+ dựng**, không vẽ lại cho đẹp: trang đẹp mà component lệch thì duyệt nhầm.
196
+ **Nhãn trạng thái ("Thường", "Rê", "Đang gõ", "Lỗi", "Khoá") nằm cùng một chỗ ở mọi
197
+ khối**: chữ nhỏ `text-xs text-muted` ngay trên ví dụ. Không đặt nhãn vào chỗ câu gợi ý
198
+ hay câu lỗi dưới ô nhập: "Đang gõ" nằm dưới ô trông y như câu gợi ý thật của ô đó. Ô
199
+ nhập bày cạnh nhau thì cách nhau như trong form thật (`gap-y-5` trở lên), không `gap-y-2`:
200
+ câu gợi ý của ô trên chỉ cách nhãn ô dưới 10px, đọc ra là nhãn của ô dưới.
201
+
202
+ **Ví dụ ép trạng thái** (nút tô sẵn nền rê, ô vẽ sẵn viền focus, select và modal mở sẵn trong
203
+ khung tĩnh, nút nhãn dài trong khung hẹp) bọc trong `<div inert data-demo-state="hover">` (giá
204
+ trị là tên trạng thái). `inert`: Tab không dừng ở ô giả focus, rê vào không đổi gì. Probe bỏ
205
+ qua các khối này ở phép đo rê, lớp nổi, viền trang trí, nút xuống dòng; không bọc thì mỗi
206
+ ví dụ thành một mục Hỏng giả. Ví dụ "Thường" thì **không** bọc,
207
+ đó là component thật để probe đo.
208
+
209
+ Trang là công cụ để duyệt: flat như gu skill, không hero, không lời quảng cáo.
210
+ 6. **Probe trang đó** (`--sweep`) tới khi danh sách `P` trống, tối đa ba vòng.
211
+ 7. **Cổng duy nhất của lối này**: gửi link, kèm một dòng *"Duyệt thì trả lời `ok`. Muốn đổi
212
+ màu nhấn, font, bo góc thì nói: đổi ở token, mọi component đổi theo."* Dừng chờ.
213
+
214
+ Duyệt xong thì ghi màu nhấn đang hiện trên trang (màu người dùng chọn trong nhóm gợi ý, không
215
+ chọn thì màu đầu) vào file token trước khi làm màn. Màn sau đi lối bình thường (mặc định nhánh
216
+ `U`): wireframe `U3` dán file token của dự án, chép class từ component vừa duyệt, không hiện
217
+ nhóm Nhấn; `U4` ráp từ đúng các component đó; bảng `D1` coi như đã chốt, không khai lại. Đề vừa đòi design system vừa
218
+ đòi màn ("dựng design system rồi dựng màn đơn hàng") thì làm hết lối này, qua cổng, rồi mới
219
+ vào `U1` cho màn.