@cyberskill/design 1.0.0 → 1.1.1

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 (266) hide show
  1. package/DESIGN.md +10 -9
  2. package/README.md +31 -28
  3. package/SKILL.md +13 -9
  4. package/VERSION +1 -1
  5. package/_ds_bundle.js +660 -202
  6. package/_ds_manifest.json +1 -1
  7. package/_esm/cs.mjs +14 -8
  8. package/_esm/react.d.ts +216 -0
  9. package/_esm/react.mjs +114 -0
  10. package/base/collections.css +31 -0
  11. package/base/components.css +3 -0
  12. package/base/data.css +33 -0
  13. package/base/forms.css +8 -0
  14. package/base/interaction.css +1 -0
  15. package/base/typography.css +6 -0
  16. package/components/_i18n/strings.js +8 -4
  17. package/components/ai/ai-conversation.card.html +2 -2
  18. package/components/ai/ai-lumi.card.html +2 -2
  19. package/components/ai/ai.card.html +2 -2
  20. package/components/brand/brand.card.html +2 -2
  21. package/components/button/buttons.card.html +2 -2
  22. package/components/data/AspectRatio.d.ts +16 -0
  23. package/components/data/AspectRatio.figma.tsx +12 -0
  24. package/components/data/AspectRatio.jsx +16 -0
  25. package/components/data/AspectRatio.prompt.md +7 -0
  26. package/components/data/Collapsible.d.ts +21 -0
  27. package/components/data/Collapsible.figma.tsx +12 -0
  28. package/components/data/Collapsible.jsx +49 -0
  29. package/components/data/Collapsible.prompt.md +7 -0
  30. package/components/data/Image.d.ts +4 -0
  31. package/components/data/Image.prompt.md +2 -2
  32. package/components/data/Item.d.ts +26 -0
  33. package/components/data/Item.figma.tsx +12 -0
  34. package/components/data/Item.jsx +63 -0
  35. package/components/data/Item.prompt.md +10 -0
  36. package/components/data/ScrollArea.d.ts +16 -0
  37. package/components/data/ScrollArea.figma.tsx +12 -0
  38. package/components/data/ScrollArea.jsx +25 -0
  39. package/components/data/ScrollArea.prompt.md +7 -0
  40. package/components/data/collections.card.html +15 -4
  41. package/components/data/data.card.html +15 -4
  42. package/components/datatable/datatable.card.html +2 -2
  43. package/components/dialog/dialog.card.html +2 -2
  44. package/components/feedback/feedback-2.card.html +2 -2
  45. package/components/feedback/feedback.card.html +2 -2
  46. package/components/forms/Cascader.jsx +5 -3
  47. package/components/forms/Editor.prompt.md +1 -1
  48. package/components/forms/InputGroup.d.ts +4 -0
  49. package/components/forms/InputGroup.jsx +38 -8
  50. package/components/forms/InputGroup.prompt.md +3 -3
  51. package/components/forms/NativeSelect.d.ts +22 -0
  52. package/components/forms/NativeSelect.figma.tsx +12 -0
  53. package/components/forms/NativeSelect.jsx +56 -0
  54. package/components/forms/NativeSelect.prompt.md +10 -0
  55. package/components/forms/NumberField.d.ts +5 -0
  56. package/components/forms/NumberField.jsx +51 -7
  57. package/components/forms/NumberField.prompt.md +2 -2
  58. package/components/forms/SegmentedControl.jsx +1 -1
  59. package/components/forms/TagInput.d.ts +3 -0
  60. package/components/forms/TagInput.jsx +62 -20
  61. package/components/forms/TagInput.prompt.md +2 -2
  62. package/components/forms/forms-2.card.html +2 -2
  63. package/components/forms/forms.card.html +5 -4
  64. package/components/icon/Icon.prompt.md +1 -1
  65. package/components/icon/icon.card.html +2 -2
  66. package/components/logo/Logo.jsx +2 -1
  67. package/components/logo/logo.card.html +2 -2
  68. package/components/navigation/Menu.jsx +14 -1
  69. package/components/navigation/navigation.card.html +2 -2
  70. package/components/navigation/shell.card.html +2 -2
  71. package/components/overlays/AlertDialog.d.ts +29 -0
  72. package/components/overlays/AlertDialog.figma.tsx +12 -0
  73. package/components/overlays/AlertDialog.jsx +142 -0
  74. package/components/overlays/AlertDialog.prompt.md +12 -0
  75. package/components/overlays/Drawer.jsx +1 -1
  76. package/components/overlays/Popconfirm.jsx +14 -1
  77. package/components/overlays/Popover.jsx +14 -1
  78. package/components/overlays/alertdialog.card.html +42 -0
  79. package/components/overlays/overlays.card.html +2 -2
  80. package/components/textfield/textfield.card.html +2 -2
  81. package/docs/benchmark-rubric.md +46 -0
  82. package/docs/ci-cd.md +17 -11
  83. package/docs/consumer-grant.md +37 -0
  84. package/docs/consuming.md +45 -16
  85. package/docs/contrast-report.md +91 -103
  86. package/docs/conventions.md +12 -9
  87. package/docs/decisions.md +33 -10
  88. package/docs/deploy.md +1 -1
  89. package/docs/design-styles.md +26 -8
  90. package/docs/figma.md +3 -3
  91. package/docs/live-hub.md +5 -3
  92. package/docs/products.md +13 -11
  93. package/docs/quality-gates.md +35 -21
  94. package/docs/release-notes.md +21 -3
  95. package/docs/status/assets/favicon.svg +5 -0
  96. package/docs/status/assets/status-legacy.css +399 -0
  97. package/docs/status/assets/status-legacy.js +505 -0
  98. package/docs/status/assets/status.css +644 -0
  99. package/docs/status/assets/status.js +1308 -0
  100. package/docs/status/data/status-feed.json +1 -0
  101. package/docs/status/data/task/TASK-REL-001.js +1 -0
  102. package/docs/status/data/task/TASK-REL-002.js +1 -0
  103. package/docs/status/index.html +42 -0
  104. package/docs/status/roadmap.html +4 -0
  105. package/docs/status/status-legacy.html +117 -0
  106. package/docs/storybook.md +5 -4
  107. package/docs/sync.md +3 -2
  108. package/docs/tasks/BACKLOG.md +26 -0
  109. package/docs/tasks/release/TASK-REL-001-launch-1-1-0/spec.md +55 -0
  110. package/docs/tasks/release/TASK-REL-002-republish-1-1-1/spec.md +54 -0
  111. package/docs/template-schema-v2.md +15 -3
  112. package/docs/vi/benchmark-rubric.md +46 -0
  113. package/docs/vi/ci-cd.md +17 -11
  114. package/docs/vi/consumer-grant.md +37 -0
  115. package/docs/vi/consuming.md +45 -16
  116. package/docs/vi/contrast-report.md +94 -106
  117. package/docs/vi/conventions.md +12 -9
  118. package/docs/vi/decisions.md +33 -10
  119. package/docs/vi/deploy.md +1 -1
  120. package/docs/vi/design-styles.md +26 -8
  121. package/docs/vi/figma.md +3 -3
  122. package/docs/vi/live-hub.md +5 -3
  123. package/docs/vi/products.md +13 -11
  124. package/docs/vi/quality-gates.md +35 -21
  125. package/docs/vi/release-notes.md +26 -8
  126. package/docs/vi/storybook.md +5 -4
  127. package/docs/vi/sync.md +3 -2
  128. package/docs/vi/template-schema-v2.md +15 -3
  129. package/docs/viewer.html +2 -2
  130. package/fonts/spacegrotesk-var-latin-ext.woff2 +0 -0
  131. package/fonts/spacegrotesk-var-latin.woff2 +0 -0
  132. package/fonts/spacegrotesk-var-vietnamese.woff2 +0 -0
  133. package/guidelines/atomic-view.html +40 -27
  134. package/guidelines/elements-geometry.html +69 -0
  135. package/guidelines/elements-variants.html +17 -17
  136. package/guidelines/type-families.html +16 -10
  137. package/llms.txt +17 -11
  138. package/package.json +38 -16
  139. package/styles.css +1 -0
  140. package/templates/ai-cluster-demo.html +29 -14
  141. package/templates/app-shell/support.js +4 -4
  142. package/templates/article/content-schema.json +6 -0
  143. package/templates/article/support.js +4 -4
  144. package/templates/auth/support.js +4 -4
  145. package/templates/bod-deck/support.js +4 -4
  146. package/templates/bod-investor-update/support.js +4 -4
  147. package/templates/bod-memo/support.js +4 -4
  148. package/templates/bod-minutes/content-schema.json +12 -0
  149. package/templates/bod-minutes/support.js +4 -4
  150. package/templates/bod-report/support.js +4 -4
  151. package/templates/bod-resolution/support.js +4 -4
  152. package/templates/culture-event-invite/support.js +4 -4
  153. package/templates/dashboard/support.js +4 -4
  154. package/templates/delivery-change-note/support.js +4 -4
  155. package/templates/delivery-kickoff/support.js +4 -4
  156. package/templates/delivery-qbr-deck/support.js +4 -4
  157. package/templates/delivery-runbook/content-schema.json +6 -0
  158. package/templates/delivery-runbook/support.js +4 -4
  159. package/templates/delivery-status-email/support.js +4 -4
  160. package/templates/doc-style-guide/DocStyleGuide.dc.html +2 -2
  161. package/templates/doc-style-guide/support.js +4 -4
  162. package/templates/doc-suite-index/support.js +4 -4
  163. package/templates/doc-templates/DocTemplates.dc.html +1 -1
  164. package/templates/doc-templates/support.js +4 -4
  165. package/templates/email/support.js +4 -4
  166. package/templates/email-safe/README.md +17 -4
  167. package/templates/email-safe/email-launch.html +3 -3
  168. package/templates/email-safe/email-newsletter.html +1 -1
  169. package/templates/finance-dunning-email/support.js +4 -4
  170. package/templates/finance-expense-report/support.js +4 -4
  171. package/templates/finance-invoice/support.js +4 -4
  172. package/templates/finance-quote/support.js +4 -4
  173. package/templates/hr-announcement/support.js +4 -4
  174. package/templates/hr-interview-kit/content-schema.json +12 -0
  175. package/templates/hr-interview-kit/support.js +4 -4
  176. package/templates/hr-offboarding/content-schema.json +12 -0
  177. package/templates/hr-offboarding/support.js +4 -4
  178. package/templates/hr-performance-review/content-schema.json +12 -0
  179. package/templates/hr-performance-review/support.js +4 -4
  180. package/templates/hr-pip/content-schema.json +12 -0
  181. package/templates/hr-pip/support.js +4 -4
  182. package/templates/legal-msa/content-schema.json +16 -0
  183. package/templates/legal-msa/support.js +4 -4
  184. package/templates/legal-sow/support.js +4 -4
  185. package/templates/marketing-campaign-brief/support.js +4 -4
  186. package/templates/marketing-case-study/support.js +4 -4
  187. package/templates/marketing-launch/support.js +4 -4
  188. package/templates/marketing-newsletter/support.js +4 -4
  189. package/templates/marketing-page/content-schema.json +0 -1
  190. package/templates/marketing-page/support.js +4 -4
  191. package/templates/marketing-press-release/support.js +4 -4
  192. package/templates/marketing-social-kit/support.js +4 -4
  193. package/templates/playground.html +8 -4
  194. package/templates/sales-one-pager/support.js +4 -4
  195. package/templates/sales-proposal-deck/support.js +4 -4
  196. package/templates/settings/Settings.dc.html +26 -14
  197. package/templates/settings/content-schema.json +36 -0
  198. package/templates/settings/support.js +4 -4
  199. package/templates/slide-deck/support.js +4 -4
  200. package/templates/team-meeting-agenda/content-schema.json +16 -0
  201. package/templates/team-meeting-agenda/support.js +4 -4
  202. package/templates/tech-incident-report/support.js +4 -4
  203. package/templates/tech-release-notes/support.js +4 -4
  204. package/templates/tech-retro/content-schema.json +12 -0
  205. package/templates/tech-retro/support.js +4 -4
  206. package/templates/tech-rfc/content-schema.json +6 -0
  207. package/templates/tech-rfc/support.js +4 -4
  208. package/templates/vn-appointment-transfer/support.js +4 -4
  209. package/templates/vn-certificate-of-employment/support.js +4 -4
  210. package/templates/vn-code-of-conduct/support.js +4 -4
  211. package/templates/vn-compensation-regulation/support.js +4 -4
  212. package/templates/vn-contract-amendment/support.js +4 -4
  213. package/templates/vn-contractor-agreement/support.js +4 -4
  214. package/templates/vn-data-protection-policy/support.js +4 -4
  215. package/templates/vn-disciplinary-case-file/support.js +4 -4
  216. package/templates/vn-disciplinary-schedule/content-schema.json +15 -0
  217. package/templates/vn-disciplinary-schedule/support.js +4 -4
  218. package/templates/vn-employee-request/support.js +4 -4
  219. package/templates/vn-exit-handover/support.js +4 -4
  220. package/templates/vn-foreign-employee-pack/support.js +4 -4
  221. package/templates/vn-grassroots-democracy/support.js +4 -4
  222. package/templates/vn-infosec-policy/support.js +4 -4
  223. package/templates/vn-internal-labor-regulations/support.js +4 -4
  224. package/templates/vn-internship-agreement/support.js +4 -4
  225. package/templates/vn-job-description/support.js +4 -4
  226. package/templates/vn-labor-contract/support.js +4 -4
  227. package/templates/vn-labour-management-book/content-schema.json +15 -0
  228. package/templates/vn-labour-management-book/support.js +4 -4
  229. package/templates/vn-mutual-nda/support.js +4 -4
  230. package/templates/vn-ndnca-ip/support.js +4 -4
  231. package/templates/vn-offer-letter/support.js +4 -4
  232. package/templates/vn-onboarding-checklist/support.js +4 -4
  233. package/templates/vn-pdpl-consent/support.js +4 -4
  234. package/templates/vn-performance-evaluation-regulation/support.js +4 -4
  235. package/templates/vn-performance-review-form/support.js +4 -4
  236. package/templates/vn-phantom-stock/support.js +4 -4
  237. package/templates/vn-probation-contract/support.js +4 -4
  238. package/templates/vn-receipt-acknowledgement/content-schema.json +15 -0
  239. package/templates/vn-receipt-acknowledgement/support.js +4 -4
  240. package/templates/vn-remote-work-policy/support.js +4 -4
  241. package/templates/vn-resignation-letter/support.js +4 -4
  242. package/templates/vn-salary-scale/content-schema.json +15 -0
  243. package/templates/vn-salary-scale/support.js +4 -4
  244. package/templates/vn-sow-appendix/support.js +4 -4
  245. package/templates/vn-termination-decision/support.js +4 -4
  246. package/templates/vn-total-rewards-appendix/support.js +4 -4
  247. package/templates/vn-training-commitment/support.js +4 -4
  248. package/templates/vn-travel-expense-policy/support.js +4 -4
  249. package/tokens/element-seeds.json +112 -0
  250. package/tokens/elements.css +274 -187
  251. package/tokens/fonts.css +12 -3
  252. package/tokens/native/CSTokens.kt +84 -68
  253. package/tokens/native/CSTokens.swift +84 -68
  254. package/tokens/native/cs_tokens.dart +84 -68
  255. package/tokens/provenance.json +9 -9
  256. package/tokens/styles.css +15 -0
  257. package/tokens/tokens.dtcg.json +258 -233
  258. package/tokens/tokens.js +168 -167
  259. package/tokens/tokens.json +167 -166
  260. package/tokens/typography.css +9 -1
  261. package/ui_kits/status-hub/README.md +1 -2
  262. package/ui_kits/status-hub/index.html +2 -2
  263. package/ui_kits/status-hub/settings.html +6 -3
  264. package/ui_kits/website/chat.html +2 -2
  265. package/ui_kits/website/index.html +2 -2
  266. package/ui_kits/status-hub/identity-lab.html +0 -134
@@ -29,8 +29,20 @@ Metadata thuần additive, opt-in: sidecar `templates/<slug>/content-schema.json
29
29
  | `slots[].required` | không | mặc định `false` |
30
30
  | `slots[].i18n` | không | `{"en": "...", "vi": "..."}` — cho template ship biến thể EN·VI |
31
31
 
32
- Hình dạng máy kiểm được chính thức nằm ở `templates/schema/content-schema.schema.json` (JSON Schema draft-07). `_audit/template-schema-test.html` validate mọi sidecar tồn tại — hai chiều: mọi slot id khai báo phải resolve tới hole thật trong template, và (informational) báo coverage trên toàn `templates/`.
32
+ Hình dạng máy kiểm được chính thức nằm ở `templates/schema/content-schema.schema.json` (JSON Schema draft-07). `_audit/template-schema-test.html` validate mọi sidecar tồn tại — hai chiều với content hole đủ điều kiện: mọi slot id khai báo phải là content hole trong `.dc.html`, và mọi content hole phải xuất hiện thành slot — **và ép độ phủ**.
33
33
 
34
- ## Rollout
34
+ ## Hole nào đủ điều kiện có schema
35
35
 
36
- Giống visual-diff baselines, ban đầu ship **cố ý chưa đầy đủ** — ba exemplar (một mỗi archetype lớn) chứng minh pattern end-to-end: `marketing-page` (product), `bod-report` (document), `slide-deck` (deck). Sau đó đã **quét tới mọi template hole-driven** và tiếp tục lớn dần; độ phủ sidecar hiện tại do `_audit/template-schema-test.html` báo cáo (bề mặt product traffic cao như `marketing-page`, `dashboard`, `settings`, cộng `tech-incident-report` được phủ slot nội dung đầy hơn). Hole trục / control-flow (`rootTheme`, `langAttr`, `elAttr`, `vaAttr`, `isEN`, `true`, …) nằm ngoài schema — chúng là trục runtime, không phải content author được. Phần còn lại hardcode copy bilingual trực tiếp theo nhánh `sc-if` ngôn ngữ (chưa có slot content `{{ hole }}`). Thêm sidecar cho mọi template nhận content hole-driven khi chạm tới; ưu tiên tăng measurable trên template traffic cao trước.
36
+ Một `{{ hole }}` là **content hole** (đủ điều kiện schema) trừ khi nó là:
37
+
38
+ - hole **trục / control-flow** — `rootTheme`, `langAttr`, `elAttr`, `vaAttr`, `dirAttr`, `true`, `false`, bất kỳ tên nào khớp `is<ChữHoa>` (`isEN`, `isVN`, `isBoth`, `isTable`, …), hoặc một số nguyên trần;
39
+ - hole **tweak boolean** — bất kỳ tên nào khớp `show|hide|has|enable|with` + `<ChữHoa>` (`showLogo`, `showSignatures`, `showQuote`, …);
40
+ - hole **runtime-control** — wiring chọn UI / handler: tên đúng `tabs`, `tab`, `lens`, `chatOpen`, `closeChat`, `dangerOpen`, `closeDanger`, hoặc bất kỳ tên nào khớp `set|open` + `<ChữHoa>` (`setTab`, `setLens`, `openChat`, …).
41
+
42
+ Chúng là trục runtime, không phải content slot có kiểu, nên nằm ngoài schema.
43
+
44
+ ## Rollout — đã đủ cho template đủ điều kiện, và đã có gate
45
+
46
+ Ban đầu ship **cố ý chưa đầy đủ**: ba exemplar (một mỗi archetype lớn) chứng minh pattern end-to-end — `marketing-page` (product), `bod-report` (document), `slide-deck` (deck) — rồi quét qua các template hole-driven.
47
+
48
+ Đợt quét đó nay **đã xong và được khoá**. Tính tới Jul 2026: **39 template content-hole-driven, cả 39 đều có sidecar**, và **45 template chỉ lộ hole trục/boolean** (copy song ngữ hardcode theo nhánh `sc-if`) đúng là không có sidecar. `_audit/template-schema-test.html` không còn chỉ báo cáo con số này — nó **fail** nếu có template lộ content hole mà thiếu sidecar. Nên luật cho author là cơ học: template nhận thêm một `{{ hole }}` author được thì nhận luôn sidecar trong cùng change, không thì board đỏ.
package/docs/viewer.html CHANGED
@@ -58,12 +58,12 @@
58
58
  <script>
59
59
  const DOCS_EN=[
60
60
  ['Start',[['README.md','README'],['SKILL.md','SKILL (agent rules)'],['llms.txt','llms.txt'],['CONTRIBUTING.md','Contributing']]],
61
- ['Guides',[['docs/consuming.md','Consuming & upgrading (incl. AI-agent quick path)'],['docs/deploy.md','Deploy (Vercel/VPS)'],['docs/template-schema-v2.md','Template content-schema v2'],['docs/conventions.md','Conventions'],['docs/release-notes.md','Release Notes'],['docs/storybook.md','Storybook (product at /)'],['docs/live-hub.md','Live hub (Storybook at /)'],['docs/design-styles.md','Design styles'],['docs/products.md','Products'],['docs/contrast-report.md','Contrast report'],['docs/figma.md','Figma']]],
61
+ ['Guides',[['docs/consuming.md','Consuming & upgrading (incl. AI-agent quick path)'],['docs/consumer-grant.md','Consumer grant (npm · UNLICENSED)'],['docs/deploy.md','Deploy (Vercel/VPS)'],['docs/template-schema-v2.md','Template content-schema v2'],['docs/conventions.md','Conventions'],['docs/release-notes.md','Release Notes'],['docs/storybook.md','Storybook (product at /)'],['docs/live-hub.md','Live hub (Storybook at /)'],['docs/design-styles.md','Design styles'],['docs/benchmark-rubric.md','Benchmark rubric'],['docs/products.md','Products'],['docs/contrast-report.md','Contrast report'],['docs/figma.md','Figma']]],
62
62
  ['Maintainers',[['docs/decisions.md','Decisions'],['docs/ci-cd.md','CI/CD automation'],['docs/quality-gates.md','Quality gates'],['docs/sync.md','Git sync & hygiene']]]
63
63
  ];
64
64
  const DOCS_VI=[
65
65
  ['Bắt đầu',[['README.md','README (EN)'],['SKILL.md','SKILL (EN)'],['llms.txt','llms.txt (EN)'],['CONTRIBUTING.md','Contributing (EN)']]],
66
- ['Hướng dẫn',[['docs/consuming.md','Tiêu thụ & nâng cấp'],['docs/deploy.md','Deploy (Vercel/VPS)'],['docs/template-schema-v2.md','Template schema v2'],['docs/conventions.md','Conventions'],['docs/release-notes.md','Ghi chú phát hành'],['docs/storybook.md','Storybook (sản phẩm tại /)'],['docs/live-hub.md','Live hub (Storybook tại /)'],['docs/design-styles.md','Phong cách'],['docs/products.md','Sản phẩm'],['docs/contrast-report.md','Báo cáo contrast'],['docs/figma.md','Figma']]],
66
+ ['Hướng dẫn',[['docs/consuming.md','Tiêu thụ & nâng cấp'],['docs/consumer-grant.md','Grant consumer (npm · UNLICENSED)'],['docs/deploy.md','Deploy (Vercel/VPS)'],['docs/template-schema-v2.md','Template schema v2'],['docs/conventions.md','Conventions'],['docs/release-notes.md','Ghi chú phát hành'],['docs/storybook.md','Storybook (sản phẩm tại /)'],['docs/live-hub.md','Live hub (Storybook tại /)'],['docs/design-styles.md','Phong cách'],['docs/benchmark-rubric.md','Rubric benchmark'],['docs/products.md','Sản phẩm'],['docs/contrast-report.md','Báo cáo contrast'],['docs/figma.md','Figma']]],
67
67
  ['Maintainer',[['docs/decisions.md','Quyết định'],['docs/ci-cd.md','CI/CD'],['docs/quality-gates.md','Quality gates'],['docs/sync.md','Đồng bộ Git']]]
68
68
  ];
69
69
  let lang=(localStorage.getItem('cs-docs-lang')==='vi')?'vi':'en';
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Atomic View" viewport="1280x820" name="Atomic View" subtitle="Storybook-style browser — every component + variants, live across Theme × Element × Language" -->
1
+ <!-- @dsCard group="Atomic View" viewport="1280x820" name="Atomic View" subtitle="Storybook-style browser — every component + variants, live across Theme × Element × Language × Style" -->
2
2
  <!DOCTYPE html>
3
3
  <html lang="en">
4
4
  <head>
@@ -77,8 +77,8 @@
77
77
  @media (max-width:820px){.app{grid-template-columns:1fr}.nav{display:none}.grid2{grid-template-columns:1fr}}
78
78
  </style>
79
79
  <script src="nav-model.cjs"></script>
80
- <script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
81
- <script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
80
+ <script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
81
+ <script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
82
82
  <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
83
83
  <script src="../_ds_bundle.js"></script>
84
84
  </head>
@@ -89,10 +89,10 @@ const { useState, useEffect, useRef } = React;
89
89
  const NS = window[Object.keys(window).find(k=>/^CyberSkillDesignSystem_[0-9a-f]{6}$/.test(k))] || {};
90
90
  const {
91
91
  Button, Icon, Badge, Tag, Alert, Toast, ToastStack, Spinner, ProgressBar, Skeleton, StatusIndicator, EmptyState,
92
- TextField, Select, Checkbox, RadioGroup, Switch, Textarea, SearchField, NumberField, Slider, FileUpload, SegmentedControl,
92
+ TextField, Select, NativeSelect, Checkbox, RadioGroup, Switch, Textarea, SearchField, NumberField, Slider, FileUpload, SegmentedControl,
93
93
  Tabs, Breadcrumb, Pagination, Menu, MenuItem, Sidebar, NavItem, Steps, CommandPalette,
94
- DataTable, Card, CardHeader, CardBody, CardFooter, Stat, Avatar, AvatarGroup, Tooltip, Divider,
95
- List, ListItem, DescriptionList, Timeline, Accordion, Kbd, CodeBlock, Dialog, Drawer, Popover,
94
+ DataTable, Card, CardHeader, CardBody, CardFooter, Stat, Avatar, AvatarGroup, Tooltip, Divider, ScrollArea, AspectRatio, Item,
95
+ List, ListItem, DescriptionList, Timeline, Accordion, Collapsible, Kbd, CodeBlock, Dialog, Drawer, Popover, AlertDialog,
96
96
  PromptInput, ChatMessage, ConfidenceMeter, AIDisclosureBadge, HumanReviewGate, PromptSuggestions, TypingIndicator, CitationList,
97
97
  LumiAvatar, Logo, Toggle, Rating, InputOTP, ButtonGroup, Combobox, InputGroup, TagInput, Calendar, DatePicker, TimePicker,
98
98
  HoverCard, Popconfirm, ContextMenu, FloatingActionButton, Result, InlineEdit, Link, Anchor, Image, Toolbar,
@@ -125,13 +125,14 @@ function Controlled({spec}){
125
125
  function TabsD({L}){ const [v,setV]=useState("board"); const V=L==="vi"; return has(Tabs)?<Tabs value={v} onChange={setV} tabs={[{value:"board",label:V?"Bảng công việc":"Board"},{value:"table",label:V?"Bảng dữ liệu":"Table",count:6},{value:"rel",label:V?"Phát hành":"Releases"}]}/>:<Miss n="Tabs"/>; }
126
126
  function PaginationD(){ const [p,setP]=useState(3); return has(Pagination)?<Pagination page={p} pageCount={12} onChange={setP}/>:<Miss n="Pagination"/>; }
127
127
  function SegmentedD({L}){ const [v,setV]=useState("board"); const V=L==="vi"; return has(SegmentedControl)?<SegmentedControl value={v} onChange={setV} options={[{value:"board",label:V?"Bảng công việc":"Board"},{value:"table",label:V?"Bảng dữ liệu":"Table"},{value:"rel",label:V?"Phát hành":"Releases"}]}/>:<Miss n="SegmentedControl"/>; }
128
- function SliderD(){ const [v,setV]=useState(60); return has(Slider)?<div style={{flex:1,minWidth:200}}><Slider min={0} max={100} value={v} onChange={(e)=>setV(+e.target.value)}/></div>:<Miss n="Slider"/>; }
128
+ function SliderD({L}){ const [v,setV]=useState(60); return has(Slider)?<div style={{flex:1,minWidth:200}}><Slider min={0} max={100} value={v} onChange={(e)=>setV(+e.target.value)} aria-label={L==="vi"?"Tiến độ":"Progress"}/></div>:<Miss n="Slider"/>; }
129
129
  function SearchD({L}){ const [q,setQ]=useState("Design System"); return has(SearchField)?<div style={{flex:1,minWidth:240}}><SearchField value={q} onChange={setQ} placeholder={L==="vi"?"Tìm dự án…":"Search projects…"}/></div>:<Miss n="SearchField"/>; }
130
- function NumberD(){ const [n,setN]=useState(3); return has(NumberField)?<NumberField value={n} onChange={setN} min={1} max={20}/>:<Miss n="NumberField"/>; }
130
+ function NumberD({L}){ const [n,setN]=useState(3); return has(NumberField)?<NumberField label={L==="vi"?"Số lượng":"Quantity"} value={n} onChange={setN} min={1} max={20}/>:<Miss n="NumberField"/>; }
131
131
  function DateD({L}){ const [d,setD]=useState(()=>new Date(2026,6,18)); const [tm,setTm]=useState("09:30"); return <div className="srow" style={{alignItems:"flex-start",minHeight:400}}>{has(DatePicker)?<DatePicker value={d} onChange={setD}/>:<Miss n="DatePicker"/>}{has(TimePicker)?<TimePicker value={tm} onChange={setTm} step={15}/>:<Miss n="TimePicker"/>}</div>; }
132
132
  function CalD({L}){ const [d,setD]=useState(()=>new Date(2026,6,18)); return has(Calendar)?<Calendar value={d} onChange={setD}/>:<Miss n="Calendar"/>; }
133
133
  function ColorD({L}){ const [c,setC]=useState("#F4BA17"); return has(ColorPicker)?<div style={{minHeight:210}}><ColorPicker value={c} onChange={setC}/></div>:<Miss n="ColorPicker"/>; }
134
134
  function TourD({L}){ const [on,setOn]=useState(false); return has(Tour,Button)?<div><Button size="sm" variant="secondary" onClick={()=>setOn(true)}>{L==="vi"?"Bắt đầu hướng dẫn":"Start tour"}</Button><Tour open={on} onClose={()=>setOn(false)} steps={L==="vi"?[{target:"#toggle",title:"Toggle",body:"Nút bật/tắt đứng độc lập."},{target:"#rating",title:"Rating",body:"Đánh giá sao màu Ochre."}]:[{target:"#toggle",title:"Toggle",body:"A standalone pressable button."},{target:"#rating",title:"Rating",body:"Ochre star rating."}]}/></div>:<Miss n="Tour"/>; }
135
+ function AlertDialogD({L}){ const [on,setOn]=useState(false); const V=L==="vi"; return has(AlertDialog,Button)?<div><Button variant="danger-ghost" size="sm" onClick={()=>setOn(true)}>{V?"Xoá không gian":"Delete workspace"}</Button><AlertDialog open={on} onOpenChange={setOn} title={V?"Xoá không gian làm việc?":"Delete workspace?"} description={V?"Xoá mọi dự án. Không thể hoàn tác.":"Removes every project. This cannot be undone."} tone="destructive" onConfirm={()=>{}}/></div>:<Miss n="AlertDialog"/>; }
135
136
  function GridD({L}){ const [sel,setSel]=useState(["CDS"]); const V=L==="vi"; return has(DataGrid)?<DataGrid selectable selected={sel} onSelect={setSel} rowKey="key" height={220} columns={[{key:"key",header:V?"Mã":"Key",sortable:true},{key:"name",header:V?"Dự án":"Project",sortable:true},{key:"pct",header:V?"Tiến độ":"Progress",sortable:true,render:(r)=>r.pct+"%"}]} rows={[{key:"CDS",name:"Design System",pct:72},{key:"GENIE",name:"Lumi Genie",pct:58},{key:"SITE",name:"cyberskill.world",pct:84}]}/>:<Miss n="DataGrid"/>; }
136
137
  function SortD({L}){ const [it,setIt]=useState(L==="vi"?[{key:"a",label:"Ước một điều"},{key:"b",label:"Định hình"},{key:"c",label:"Xây để ra mắt"}]:[{key:"a",label:"Make a wish"},{key:"b",label:"Shape it"},{key:"c",label:"Build to ship"}]); return has(Sortable)?<Sortable items={it} onChange={setIt}/>:<Miss n="Sortable"/>; }
137
138
  function TreeSelD({L}){ const [k,setK]=useState("ds"); return has(TreeSelect)?<TreeSelect value={k} onChange={setK} nodes={L==="vi"?[{key:"p",label:"Nền tảng",children:[{key:"ds",label:"Design System"},{key:"tok",label:"Token Pipeline"}]},{key:"ai",label:"AI",children:[{key:"lumi",label:"Lumi Genie"}]}]:[{key:"p",label:"Platform",children:[{key:"ds",label:"Design System"},{key:"tok",label:"Token Pipeline"}]},{key:"ai",label:"AI",children:[{key:"lumi",label:"Lumi Genie"}]}]}/>:<Miss n="TreeSelect"/>; }
@@ -167,21 +168,24 @@ const STORIES = [
167
168
  { tier:"Atom", name:"Spinner · ProgressBar · Skeleton", grp:"Feedback", controls:[{k:"value",type:"range",min:0,max:100,step:1,def:72},{k:"label",type:"text",def:"v1.6 progress"}], renderC:(v)=> has(ProgressBar)?<div style={{maxWidth:320}}><ProgressBar value={v.value} label={v.label}/></div>:<Miss n="ProgressBar"/>, render:()=> has(Spinner,ProgressBar,Skeleton)?<div className="srow"><Spinner size={24}/><div style={{flex:"1 1 200px"}}><ProgressBar value={72} label="v1.6 progress"/></div><div style={{flex:"1 1 160px"}}><Skeleton lines={2}/></div></div>:<Miss n="Spinner/ProgressBar/Skeleton"/> },
168
169
  { tier:"Atom", name:"Avatar", grp:"Data", controls:[{k:"name",type:"text",def:"Nguyễn Vũ"},{k:"size",type:"select",options:["sm","md","lg"],def:"lg"}], renderC:(v)=> has(Avatar)?<Avatar name={v.name} size={v.size}/>:<Miss n="Avatar"/>, render:()=> has(Avatar,AvatarGroup)?<div className="srow"><Avatar name="Nguyễn Vũ" size="lg"/><Avatar name="An Le" size="md"/><Avatar name="Bao Vu" size="sm"/><AvatarGroup><Avatar name="An Le" size="sm"/><Avatar name="Bao Vu" size="sm"/><Avatar name="Chi Tran" size="sm"/></AvatarGroup></div>:<Miss n="Avatar"/> },
169
170
  { tier:"Atom", name:"Divider", grp:"Data", render:()=> has(Divider)?<div style={{maxWidth:360}}><Divider/><Divider label="team"/></div>:<Miss n="Divider"/> },
171
+ { tier:"Atom", name:"AspectRatio", grp:"Data", controls:[{k:"ratio",type:"select",options:["16 / 9","1","4 / 3","9 / 16"],def:"16 / 9"}], renderC:(v)=> has(AspectRatio)?<div style={{maxWidth:280}}><AspectRatio ratio={v.ratio}><img src="../assets/aurora-gold.jpg" alt="Aurora"/></AspectRatio></div>:<Miss n="AspectRatio"/>, render:(L)=> has(AspectRatio)?<div style={{maxWidth:280}}><AspectRatio ratio="16 / 9"><img src="../assets/aurora-gold.jpg" alt={L==="vi"?"Aurora vàng":"Aurora gold"}/></AspectRatio></div>:<Miss n="AspectRatio"/> },
172
+ { tier:"Atom", name:"Item", grp:"Data", controls:[{k:"selected",type:"toggle",def:false},{k:"disabled",type:"toggle",def:false}], renderC:(v)=> has(Item)?<div style={{maxWidth:420}}><Item title="Release notes" description="Bilingual digest" selected={v.selected} disabled={v.disabled} trailing={has(Switch)?<Switch defaultChecked aria-label="Release notes"/>:null}/></div>:<Miss n="Item"/>, render:(L)=> has(Item)?<div style={{maxWidth:420,display:"grid",gap:8}}><Item title={L==="vi"?"Ghi chú phát hành":"Release notes"} description={L==="vi"?"Tóm tắt song ngữ":"Bilingual digest"} trailing={has(Switch)?<Switch defaultChecked aria-label={L==="vi"?"Ghi chú phát hành":"Release notes"}/>:null}/><Item title={L==="vi"?"Hồ sơ":"Profile"} href="#profile" selected/></div>:<Miss n="Item"/> },
170
173
  { tier:"Atom", name:"Kbd", grp:"Data", render:()=> has(Kbd)?<span>Press <Kbd>⌘</Kbd> <Kbd>K</Kbd> to search</span>:<Miss n="Kbd"/> },
171
174
  { tier:"Atom", name:"Logo", grp:"Brand", render:()=> has(Logo)?<div className="srow" style={{gap:24}}><Logo size={56}/><Logo size={40}/><Logo size={28}/><span style={{display:"flex",alignItems:"center",gap:10}}><Logo size={40}/><b style={{fontSize:22,letterSpacing:"-.01em",color:"var(--cs-color-text-primary)"}}>CyberSkill</b></span></div>:<Miss n="Logo"/> },
172
175
  { tier:"Atom", name:"LumiAvatar", grp:"Brand", controls:[{k:"size",type:"select",options:["sm","md","lg"],def:"lg"},{k:"ring",type:"toggle",def:true}], renderC:(v)=> has(LumiAvatar)?<LumiAvatar src="../assets/lumi-poster.webp" size={v.size} ring={v.ring}/>:<Miss n="LumiAvatar"/>, render:()=> has(LumiAvatar)?<div className="srow" style={{gap:22}}><LumiAvatar src="../assets/lumi-poster.webp" size="lg" ring/><LumiAvatar src="../assets/lumi-poster.webp" size="md"/><LumiAvatar size="md"/><LumiAvatar size="sm"/></div>:<Miss n="LumiAvatar"/> },
173
176
 
174
177
  // ============ MOLECULES ============
175
178
  { tier:"Molecule", name:"TextField", grp:"Forms", controls:[{k:"label",type:"text",def:"Work email"},{k:"error",type:"text",def:""},{k:"disabled",type:"toggle",def:false}], renderC:(v)=> has(TextField)?<div style={{maxWidth:360}}><TextField label={v.label} error={v.error||undefined} disabled={v.disabled} placeholder="you@company.com"/></div>:<Miss n="TextField"/>, render:()=> has(TextField)?<div className="grid2"><TextField label="Work email" type="email" placeholder="you@company.com"/><TextField label="Tên của bạn" description="Diacritics preserved" defaultValue="Nguyễn Hoàng Vũ"/><TextField label="Company" placeholder="Optional"/><TextField label="Email" error="Enter a valid email address." defaultValue="not-an-email"/></div>:<Miss n="TextField"/> },
176
- { tier:"Molecule", name:"Select · Radio · Checkbox · Switch · Textarea", grp:"Forms", controls:[{k:"label",type:"text",def:"Dark theme"},{k:"disabled",type:"toggle",def:false}], renderC:(v)=> has(Switch)?<Switch label={v.label} disabled={v.disabled} defaultChecked/>:<Miss n="Switch"/>, render:()=> has(Select,RadioGroup,Checkbox,Switch,Textarea)?<div className="grid2">
179
+ { tier:"Molecule", name:"Select · NativeSelect · Radio · Checkbox · Switch · Textarea", grp:"Forms", controls:[{k:"label",type:"text",def:"Squad"},{k:"disabled",type:"toggle",def:false}], renderC:(v)=> has(Select,Checkbox,RadioGroup,Switch)?<div className="scol" style={{maxWidth:360,gap:12}}><Select label={v.label} disabled={v.disabled} options={[{value:"plat",label:"Platform"},{value:"ai",label:"AI"}]} defaultValue="ai"/><Checkbox label="Email me release notes" disabled={v.disabled} defaultChecked/><RadioGroup legend="Billing" options={[{value:"mo",label:"Monthly"},{value:"yr",label:"Annual"}]} defaultValue="yr"/><Switch label="Dark theme" disabled={v.disabled} defaultChecked/></div>:<Miss n="Select"/>, render:()=> has(Select,NativeSelect,RadioGroup,Checkbox,Switch,Textarea)?<div className="grid2">
177
180
  <Select label="Squad" options={[{value:"plat",label:"Platform"},{value:"ai",label:"AI"},{value:"growth",label:"Growth"}]} defaultValue="ai"/>
181
+ <NativeSelect label="Interface" size="sm" options={[{value:"en",label:"English"},{value:"vi",label:"Tiếng Việt"}]} defaultValue="en"/>
178
182
  <RadioGroup legend="Billing" defaultValue="yr" options={[{value:"mo",label:"Monthly"},{value:"yr",label:"Annual",description:"Two months free"}]}/>
179
183
  <div className="scol"><Checkbox label="Email me release notes" defaultChecked/><Checkbox label="Bilingual export" description="Ship EN + VN together"/><Switch label="Dark theme" defaultChecked/></div>
180
184
  <Textarea label="Tell us your wish" description="A sentence or two is plenty." rows={3} defaultValue="A faster checkout for our shop."/>
181
185
  </div>:<Miss n="Form controls"/> },
182
- { tier:"Molecule", name:"Search · Number · Slider · Segmented · FileUpload", grp:"Forms", render:(L)=> <div className="scol">
186
+ { tier:"Molecule", name:"Search · Number · Slider · Segmented · FileUpload", grp:"Forms", controls:[{k:"query",type:"text",def:"design system"},{k:"qty",type:"range",min:0,max:20,step:1,def:3},{k:"level",type:"range",min:0,max:100,step:1,def:60}], renderC:(v)=> has(SearchField,NumberField,Slider,SegmentedControl,FileUpload)?<div className="scol" style={{maxWidth:420}}><SearchField value={v.query} onChange={()=>{}}/><NumberField label="Qty" value={+v.qty} onChange={()=>{}} lang="en"/><Slider aria-label="Level" value={+v.level} onChange={()=>{}}/><SegmentedControl value="board" onChange={()=>{}} options={[{value:"board",label:"Board"},{value:"list",label:"List"}]}/><FileUpload title="Drop files"/></div>:<Miss n="SearchField"/>, render:(L)=> <div className="scol">
183
187
  <div className="srow"><SearchD L={L}/></div>
184
- <div className="srow"><NumberD/><SliderD/></div>
188
+ <div className="srow"><NumberD L={L}/><SliderD L={L}/></div>
185
189
  <div className="srow"><SegmentedD L={L}/></div>
186
190
  {has(FileUpload)?<FileUpload/>:<Miss n="FileUpload"/>}
187
191
  </div> },
@@ -189,19 +193,21 @@ const STORIES = [
189
193
  { tier:"Molecule", name:"InputOTP", grp:"Forms", render:()=> has(InputOTP)?<InputOTP length={6} onComplete={()=>{}}/>:<Miss n="InputOTP"/> },
190
194
  { tier:"Molecule", name:"ButtonGroup", grp:"Core", render:(L)=> has(ButtonGroup,Button)?<ButtonGroup label="View"><Button variant="secondary" size="sm">{L==="vi"?"Bảng công việc":"Board"}</Button><Button variant="secondary" size="sm">{L==="vi"?"Danh sách":"List"}</Button><Button variant="secondary" size="sm">{L==="vi"?"Dòng thời gian":"Timeline"}</Button></ButtonGroup>:<Miss n="ButtonGroup"/> },
191
195
  { tier:"Molecule", name:"Combobox", grp:"Forms", render:(L)=> <div style={{minHeight:230}}><ComboD L={L}/></div> },
192
- { tier:"Molecule", name:"InputGroup", grp:"Forms", render:(L)=> has(InputGroup)?<div className="scol" style={{maxWidth:360}}><InputGroup prefix="https://" suffix=".world" defaultValue="cyberskill" clearable/><InputGroup password defaultValue="hunter2" placeholder={L==="vi"?"Mật khẩu":"Password"}/></div>:<Miss n="InputGroup"/> },
193
- { tier:"Molecule", name:"TagInput", grp:"Forms", render:(L)=> has(TagInput)?<div style={{maxWidth:420}}><TagInput defaultValue={L==="vi"?["Ứng dụng web","Song ngữ"]:["Web apps","Bilingual"]}/></div>:<Miss n="TagInput"/> },
194
- { tier:"Molecule", name:"HoverCard", grp:"Overlays", render:(L)=> has(HoverCard)?<div style={{minHeight:150}}><HoverCard trigger={<a href="#" onClick={(e)=>e.preventDefault()}>@anle</a>}><b>An Lê</b><br/>{L==="vi"?"Trưởng nhóm Nền tảng · Sài Gòn":"Platform lead · Saigon"}</HoverCard></div>:<Miss n="HoverCard"/> },
196
+ { tier:"Molecule", name:"InputGroup", grp:"Forms", render:(L)=> has(InputGroup)?<div className="scol" style={{maxWidth:360}}><InputGroup label={L==="vi"?"Máy chủ":"Host"} prefix="https://" suffix=".world" defaultValue="cyberskill" clearable/><InputGroup label={L==="vi"?"Mật khẩu":"Password"} password defaultValue="hunter2" placeholder={L==="vi"?"Mật khẩu":"Password"}/></div>:<Miss n="InputGroup"/> },
197
+ { tier:"Molecule", name:"TagInput", grp:"Forms", render:(L)=> has(TagInput)?<div style={{maxWidth:420}}><TagInput label={L==="vi"?"Thẻ":"Tags"} defaultValue={L==="vi"?["Ứng dụng web","Song ngữ"]:["Web apps","Bilingual"]}/></div>:<Miss n="TagInput"/> },
198
+ { tier:"Molecule", name:"HoverCard", grp:"Overlays", controls:[{k:"openDelay",type:"range",min:0,max:400,step:50,def:0}], renderC:(v)=> has(HoverCard)?<div style={{minHeight:150}}><HoverCard openDelay={+v.openDelay} closeDelay={99999} trigger={<button type="button" className="cs-button cs-button--ghost">@anle</button>}><b>An Lê</b><br/>Platform lead · Saigon</HoverCard></div>:<Miss n="HoverCard"/>, render:(L)=> has(HoverCard)?<div style={{minHeight:150}}><HoverCard trigger={<a href="#" onClick={(e)=>e.preventDefault()}>@anle</a>}><b>An Lê</b><br/>{L==="vi"?"Trưởng nhóm Nền tảng · Sài Gòn":"Platform lead · Saigon"}</HoverCard></div>:<Miss n="HoverCard"/> },
195
199
  { tier:"Molecule", name:"Popconfirm", grp:"Overlays", render:(L)=> has(Popconfirm,Button)?<div style={{minHeight:170}}><Popconfirm title={L==="vi"?"Xóa bản nháp này?":"Delete this draft?"} onConfirm={()=>{}} trigger={<Button variant="danger-ghost" size="sm">{L==="vi"?"Xóa":"Delete"}</Button>}/></div>:<Miss n="Popconfirm"/> },
196
200
  { tier:"Molecule", name:"ContextMenu", grp:"Overlays", render:(L)=> has(ContextMenu)?<ContextMenu items={L==="vi"?[{label:"Nhân bản"},{label:"Đổi tên"},"-",{label:"Xóa",danger:true}]:[{label:"Duplicate"},{label:"Rename"},"-",{label:"Delete",danger:true}]}><div style={{border:"1px dashed var(--cs-color-border-default)",borderRadius:"var(--cs-radius-md)",padding:"26px 18px",color:"var(--cs-color-text-muted)",fontSize:14,minHeight:120}}>{L==="vi"?"Nhấp chuột phải vào vùng này":"Right-click this zone"}</div></ContextMenu>:<Miss n="ContextMenu"/> },
197
201
  { tier:"Molecule", name:"FloatingActionButton", grp:"Core", render:(L)=> has(FloatingActionButton,Icon)?<FloatingActionButton position="static" icon={<Icon name="sparkle"/>} label={L==="vi"?"Ước một điều":"Make a wish"} actions={[{icon:<Icon name="chat" size="sm"/>,label:L==="vi"?"Trò chuyện với Lumi":"Talk to Lumi"},{icon:<Icon name="plus" size="sm"/>,label:L==="vi"?"Dự án mới":"New project"}]}/>:<Miss n="FloatingActionButton"/> },
198
202
  { tier:"Molecule", name:"InlineEdit", grp:"Forms", render:(L)=> has(InlineEdit)?<InlineEdit defaultValue="Design System v1.6" label={L==="vi"?"Tên dự án":"Project name"}/>:<Miss n="InlineEdit"/> },
199
203
  { tier:"Molecule", name:"Toolbar", grp:"Navigation", render:(L)=> has(Toolbar,Icon)?<Toolbar label="Editor" overflowAfter={3} items={L==="vi"?[{icon:<Icon name="edit" size="sm"/>,label:"Sửa"},{icon:<Icon name="copy" size="sm"/>,label:"Nhân bản"},"-",{icon:<Icon name="download" size="sm"/>,label:"Xuất"},{label:"Lưu trữ"},{label:"Xóa"}]:[{icon:<Icon name="edit" size="sm"/>,label:"Edit"},{icon:<Icon name="copy" size="sm"/>,label:"Duplicate"},"-",{icon:<Icon name="download" size="sm"/>,label:"Export"},{label:"Archive"},{label:"Delete"}]}/>:<Miss n="Toolbar"/> },
200
204
  { tier:"Molecule", name:"Image", grp:"Data", render:(L)=> has(Image)?<div className="srow"><Image src="../assets/aurora-gold.jpg" alt="Aurora" ratio="16/9" preview style={{width:260}}/><Image src="/broken.png" alt="" ratio="16/9" style={{width:180}}/></div>:<Miss n="Image"/> },
205
+ { tier:"Molecule", name:"ScrollArea", grp:"Data", controls:[{k:"maxHeight",type:"range",min:80,max:280,step:20,def:140}], renderC:(v)=> has(ScrollArea)?<ScrollArea maxHeight={v.maxHeight} aria-label="Notes" style={{border:"1px solid var(--cs-color-border-default)",maxWidth:360,padding:"8px 12px",fontSize:13,color:"var(--cs-color-text-muted)"}}><p>Release notes arrive bilingual.</p><p>Blocked alerts only when asked.</p><p>Weekly velocity every Monday.</p><p>Quiet by default.</p></ScrollArea>:<Miss n="ScrollArea"/>, render:(L)=> has(ScrollArea)?<ScrollArea maxHeight={140} aria-label={L==="vi"?"Ghi chú":"Notes"} style={{border:"1px solid var(--cs-color-border-default)",maxWidth:360,padding:"8px 12px",fontSize:13,color:"var(--cs-color-text-muted)"}}><p>{L==="vi"?"Ghi chú phát hành song ngữ.":"Release notes arrive bilingual."}</p><p>{L==="vi"?"Cảnh báo chỉ khi bạn yêu cầu.":"Blocked alerts only when asked."}</p><p>{L==="vi"?"Tóm tắt tốc độ mỗi thứ Hai.":"Weekly velocity every Monday."}</p><p>{L==="vi"?"Yên tĩnh theo mặc định.":"Quiet by default."}</p></ScrollArea>:<Miss n="ScrollArea"/> },
206
+ { tier:"Molecule", name:"Collapsible", grp:"Data", controls:[{k:"defaultOpen",type:"toggle",def:false}], renderC:(v)=> has(Collapsible)?<div style={{maxWidth:420}}><Collapsible title="Advanced preferences" defaultOpen={v.defaultOpen}><p style={{margin:0}}>Quiet by default — only what you opt into.</p></Collapsible></div>:<Miss n="Collapsible"/>, render:(L)=> has(Collapsible)?<div style={{maxWidth:420}}><Collapsible title={L==="vi"?"Tuỳ chọn nâng cao":"Advanced preferences"} defaultOpen={false}><p style={{margin:0}}>{L==="vi"?"Yên tĩnh theo mặc định — chỉ những gì bạn chọn.":"Quiet by default — only what you opt into."}</p></Collapsible></div>:<Miss n="Collapsible"/> },
201
207
  { tier:"Molecule", name:"Anchor", grp:"Navigation", render:(L)=> has(Anchor)?<Anchor title={L==="vi"?"Trên trang này":"On this page"} items={L==="vi"?[{id:"atoms",label:"Nguyên tử"},{id:"molecules",label:"Phân tử"},{id:"organisms",label:"Cơ quan"}]:[{id:"atoms",label:"Atoms"},{id:"molecules",label:"Molecules"},{id:"organisms",label:"Organisms"}]}/>:<Miss n="Anchor"/> },
202
- { tier:"Molecule", name:"Tabs", grp:"Navigation", render:(L)=> <TabsD L={L}/> },
208
+ { tier:"Molecule", name:"Tabs", grp:"Navigation", controls:[{k:"value",type:"select",options:["a","b","c"],def:"a"}], renderC:(v)=> has(Tabs)?<Tabs value={v.value} onChange={()=>{}} tabs={[{label:"Overview",value:"a"},{label:"Releases",value:"b"},{label:"Settings",value:"c"}]}/>:<Miss n="Tabs"/>, render:(L)=> <TabsD L={L}/> },
203
209
  { tier:"Molecule", name:"Breadcrumb", grp:"Navigation", render:(L)=> has(Breadcrumb)?<Breadcrumb items={L==="vi"?[{label:"Trung tâm",href:"#"},{label:"Nền tảng",href:"#"},{label:"Design System v1.6"}]:[{label:"Status Hub",href:"#"},{label:"Platform",href:"#"},{label:"Design System v1.6"}]}/>:<Miss n="Breadcrumb"/> },
204
- { tier:"Molecule", name:"Pagination", grp:"Navigation", render:()=> <PaginationD/> },
210
+ { tier:"Molecule", name:"Pagination", grp:"Navigation", controls:[{k:"page",type:"range",min:1,max:8,step:1,def:3}], renderC:(v)=> has(Pagination)?<Pagination page={+v.page} pageCount={8} onChange={()=>{}}/>:<Miss n="Pagination"/>, render:()=> <PaginationD/> },
205
211
  { tier:"Molecule", name:"Menu", grp:"Navigation", render:(L)=> has(Menu,MenuItem)?<Menu trigger={<button className="cs-button cs-button--secondary cs-button--sm">{L==="vi"?"Hành động ▾":"Actions ▾"}</button>}><MenuItem>{L==="vi"?"Nhân bản":"Duplicate"}</MenuItem><MenuItem>{L==="vi"?"Xuất EN + VN":"Export EN + VN"}</MenuItem><div className="cs-menu__sep"/><MenuItem danger>{L==="vi"?"Xóa":"Delete"}</MenuItem></Menu>:<Miss n="Menu"/> },
206
212
  { tier:"Molecule", name:"Stat", grp:"Data", controls:[{k:"label",type:"text",def:"Avg progress"},{k:"value",type:"text",def:"70%"},{k:"delta",type:"text",def:"+6"},{k:"trend",type:"select",options:["up","down","flat"],def:"up"}], renderC:(v)=> has(Stat)?<Stat label={v.label} value={v.value} delta={v.delta||undefined} trend={v.trend}/>:<Miss n="Stat"/>, render:(L)=> has(Stat)?<div className="srow" style={{gap:32}}><Stat label={L==="vi"?"Dự án":"Projects"} value="6"/><Stat label={L==="vi"?"Tiến độ TB":"Avg progress"} value="70%" delta="+6" trend="up"/><Stat label={L==="vi"?"Bị chặn":"Blocked"} value="1" delta="-1" trend="down"/></div>:<Miss n="Stat"/> },
207
213
  { tier:"Molecule", name:"Card", grp:"Data", controls:[{k:"title",type:"text",def:"Design System v1.6"},{k:"subtitle",type:"text",def:"Platform squad"},{k:"body",type:"text",def:"Liquid Glass bindings + 15 element packs."}], renderC:(v)=> has(Card,CardHeader,CardBody)?<div style={{maxWidth:360}}><Card><CardHeader title={v.title} subtitle={v.subtitle}/><CardBody>{v.body}</CardBody></Card></div>:<Miss n="Card"/>, render:(L)=> has(Card,CardHeader,CardBody,CardFooter)?<div style={{maxWidth:360}}><Card><CardHeader title="Design System v1.6" subtitle={L==="vi"?"Nhóm Nền tảng":"Platform squad"}/><CardBody>{L==="vi"?"Liên kết Liquid Glass + 15 gói Ngũ Hành, đã kiểm chứng.":"Liquid Glass bindings + 15 element packs, verified."}</CardBody><CardFooter>{has(Badge)&&<Badge variant="ochre">{L==="vi"?"Đang làm":"Now"}</Badge>}{has(AvatarGroup,Avatar)&&<AvatarGroup><Avatar name="An Le" size="sm"/><Avatar name="Bao Vu" size="sm"/></AvatarGroup>}</CardFooter></Card></div>:<Miss n="Card"/> },
@@ -267,7 +273,7 @@ const STORIES = [
267
273
  { tier:"Organism", name:"Tree", grp:"Data", render:(L)=> has(Tree)?<div style={{maxWidth:340}}><Tree defaultOpen nodes={L==="vi"?[{key:"p",label:"Nền tảng",children:[{key:"ds",label:"Design System"},{key:"tok",label:"Token Pipeline"}]},{key:"ai",label:"AI",children:[{key:"lumi",label:"Lumi Genie"}]}]:[{key:"p",label:"Platform",children:[{key:"ds",label:"Design System"},{key:"tok",label:"Token Pipeline"}]},{key:"ai",label:"AI",children:[{key:"lumi",label:"Lumi Genie"}]}]}/></div>:<Miss n="Tree"/> },
268
274
  { tier:"Molecule", name:"Watermark", grp:"Data", render:(L)=> has(Watermark)?<Watermark text={L==="vi"?"BẢN NHÁP":"DRAFT"}><div style={{border:"1px solid var(--cs-color-border-default)",borderRadius:"var(--cs-radius-md)",padding:"30px 22px",maxWidth:420}}>{L==="vi"?"Nội dung tài liệu được đánh dấu bản nháp.":"Document content marked as a draft."}</div></Watermark>:<Miss n="Watermark"/> },
269
275
  { tier:"Molecule", name:"BackTop", grp:"Navigation", render:(L)=> has(BackTop)?<div style={{fontSize:13,color:"var(--cs-color-text-muted)"}}>{L==="vi"?"Cuộn trang để thấy nút ở góc phải dưới.":"Scroll the page — the button appears bottom-right."}<BackTop threshold={300}/></div>:<Miss n="BackTop"/> },
270
- { tier:"Organism", name:"Menubar", grp:"Navigation", render:(L)=> has(Menubar)?<div style={{minHeight:180}}><Menubar menus={L==="vi"?[{label:"Tệp",items:[{label:"Mới"},{label:"Mở…"},"-",{label:"Xuất EN + VN"}]},{label:"Sửa",items:[{label:"Hoàn tác"},{label:"Làm lại"}]}]:[{label:"File",items:[{label:"New"},{label:"Open…"},"-",{label:"Export EN + VN"}]},{label:"Edit",items:[{label:"Undo"},{label:"Redo"}]}]}/></div>:<Miss n="Menubar"/> },
276
+ { tier:"Organism", name:"Menubar", grp:"Navigation", controls:[{k:"fileLabel",type:"text",def:"File"}], renderC:(v)=> has(Menubar)?<div style={{minHeight:180}}><Menubar menus={[{label:v.fileLabel,items:[{label:"New"},{label:"Open…"},"-",{label:"Export"}]},{label:"Edit",items:[{label:"Undo"},{label:"Redo"}]}]}/></div>:<Miss n="Menubar"/>, render:(L)=> has(Menubar)?<div style={{minHeight:180}}><Menubar menus={L==="vi"?[{label:"Tệp",items:[{label:"Mới"},{label:"Mở…"},"-",{label:"Xuất EN + VN"}]},{label:"Sửa",items:[{label:"Hoàn tác"},{label:"Làm lại"}]}]:[{label:"File",items:[{label:"New"},{label:"Open…"},"-",{label:"Export EN + VN"}]},{label:"Edit",items:[{label:"Undo"},{label:"Redo"}]}]}/></div>:<Miss n="Menubar"/> },
271
277
  { tier:"Organism", name:"NavigationMenu", grp:"Navigation", render:(L)=> has(NavigationMenu)?<div style={{minHeight:220}}><NavigationMenu items={L==="vi"?[{label:"Dịch vụ",panel:[{label:"Ứng dụng web & di động",desc:"Sản phẩm khách hàng dùng hằng ngày",href:"#"},{label:"Hệ thống nội bộ",desc:"Công cụ đội ngũ vận hành",href:"#"}]},{label:"Dự án",href:"#"},{label:"Tuyển dụng",href:"#"}]:[{label:"Services",panel:[{label:"Web & mobile apps",desc:"Products your customers reach for",href:"#"},{label:"Internal systems",desc:"The tools your team runs on",href:"#"}]},{label:"Work",href:"#"},{label:"Careers",href:"#"}]}/></div>:<Miss n="NavigationMenu"/> },
272
278
  { tier:"Organism", name:"Carousel", grp:"Data", render:(L)=> has(Carousel)?<div style={{maxWidth:460}}><Carousel label={L==="vi"?"Dự án":"Cases"}>{[1,2,3].map(n=><div key={n} style={{padding:"44px 24px",textAlign:"center",fontWeight:700}}>{(L==="vi"?"Trang ":"Slide ")+n}</div>)}</Carousel></div>:<Miss n="Carousel"/> },
273
279
  { tier:"Organism", name:"Comment", grp:"Data", render:(L)=> has(Comment,Avatar)?<div style={{maxWidth:460}}><Comment avatar={<Avatar name="An Le" size="sm"/>} author="An Lê" meta={L==="vi"?"2 giờ trước":"2h ago"} replies={<Comment avatar={<Avatar name="Bao Vu" size="sm"/>} author="Bảo Vũ" meta={L==="vi"?"1 giờ trước":"1h ago"}>{L==="vi"?"Đồng ý, giao tuần này.":"Agreed — shipping this week."}</Comment>}>{L==="vi"?"Trông ổn rồi — giao thôi.":"Looks good — ship it."}</Comment></div>:<Miss n="Comment"/> },
@@ -277,9 +283,10 @@ const STORIES = [
277
283
  { tier:"Organism", name:"Accordion", grp:"Data", controls:[{k:"allowMultiple",type:"toggle",def:false}], renderC:(v)=> has(Accordion)?<div style={{maxWidth:460}}><Accordion allowMultiple={v.allowMultiple} items={[{title:"What is a wish?",content:"A clear outcome stated in a sentence or two."},{title:"How fast do you reply?",content:"Within one business day."},{title:"Do you ship bilingual?",content:"Every deliverable ships EN + VN."}]}/></div>:<Miss n="Accordion"/>, render:(L)=> has(Accordion)?<div style={{maxWidth:460}}><Accordion items={L==="vi"?[{title:"Điều ước là gì?",content:"Một kết quả rõ ràng, nói trong một hai câu."},{title:"Bao lâu thì trả lời?",content:"Trong một ngày làm việc."},{title:"Có giao song ngữ không?",content:"Mọi sản phẩm đều giao EN + VN."}]:[{title:"What is a wish?",content:"A clear outcome stated in a sentence or two."},{title:"How fast do you reply?",content:"Within one business day."},{title:"Do you ship bilingual?",content:"Every deliverable ships EN + VN."}]}/></div>:<Miss n="Accordion"/> },
278
284
  { tier:"Organism", name:"Timeline", grp:"Data", render:(L)=> has(Timeline)?<div style={{maxWidth:420}}><Timeline items={L==="vi"?[{title:"v1.6.0",meta:"Tuần này",state:"now",body:"Liên kết Glass"},{title:"v1.5.1",meta:"04/07/2026",body:"15 gói Ngũ Hành"},{title:"v1.4.0",meta:"13/06/2026",body:"Liquid Glass trong mã"}]:[{title:"v1.6.0",meta:"This week",state:"now",body:"Glass bindings"},{title:"v1.5.1",meta:"04 Jul 2026",body:"15 element packs"},{title:"v1.4.0",meta:"13 Jun 2026",body:"Liquid Glass in code"}]}/></div>:<Miss n="Timeline"/> },
279
285
  { tier:"Organism", name:"EmptyState", grp:"Feedback", controls:[{k:"title",type:"text",def:"No projects yet"},{k:"body",type:"text",def:"Start by telling Lumi what you'd like to build."}], renderC:(v)=> has(EmptyState)?<div style={{border:"1px solid var(--cs-color-border-default)",borderRadius:"var(--cs-radius-lg)"}}><EmptyState title={v.title}>{v.body}</EmptyState></div>:<Miss n="EmptyState"/>, render:(L)=> has(EmptyState)?<div style={{border:"1px solid var(--cs-color-border-default)",borderRadius:"var(--cs-radius-lg)"}}><EmptyState title={L==="vi"?"Chưa có dự án nào":"No projects yet"} actions={has(Button)?<Button size="sm">{L==="vi"?"✦ Ước một điều":"✦ Make a wish"}</Button>:null}>{L==="vi"?"Hãy bắt đầu bằng cách nói với Lumi bạn muốn xây gì.":"Start by telling Lumi what you'd like to build."}</EmptyState></div>:<Miss n="EmptyState"/> },
280
- { tier:"Organism", name:"Dialog", grp:"Overlays", framed:true, render:()=> has(Dialog,Button)?<Dialog open={true} title="Send your wish?" onClose={()=>{}} actions={<><Button variant="secondary">Not now</Button><Button>Send wish</Button></>}>A real person on the team replies within one business day.</Dialog>:<Miss n="Dialog"/> },
281
- { tier:"Organism", name:"Drawer", grp:"Overlays", framed:true, render:(L)=> has(Drawer)?<Drawer open={true} onClose={()=>{}} title="Design System v1.6" actions={has(Button)?<Button size="sm">{L==="vi"?"Mở dự án":"Open project"}</Button>:null}>{has(Badge)&&<Badge variant="ochre">{L==="vi"?"Đang làm":"In progress"}</Badge>}<p style={{color:"var(--cs-color-text-muted)",fontSize:13}}>{L==="vi"?"Liên kết component Liquid Glass + 15 gói Ngũ Hành.":"Liquid Glass component bindings + 15 element packs."}</p>{has(DescriptionList)&&<DescriptionList items={L==="vi"?[{term:"Phụ trách",value:"An Lê"},{term:"Nhóm",value:"Nền tảng"}]:[{term:"Owner",value:"An Le"},{term:"Squad",value:"Platform"}]}/>}</Drawer>:<Miss n="Drawer"/> },
282
- { tier:"Organism", name:"Popover", grp:"Overlays", framed:true, render:(L)=> has(Popover,Button,RadioGroup)?<div style={{padding:16}}><Popover open={true} onOpenChange={()=>{}} trigger={<Button variant="secondary" size="sm">{L==="vi"?"Lọc ▾":"Filter ▾"}</Button>}><RadioGroup legend={L==="vi"?"Trạng thái":"Status"} defaultValue="active" options={L==="vi"?[{value:"active",label:"Đang làm"},{value:"done",label:"Đã ra mắt"},{value:"hold",label:"Bị chặn"}]:[{value:"active",label:"In progress"},{value:"done",label:"Shipped"},{value:"hold",label:"Blocked"}]}/></Popover></div>:<Miss n="Popover"/> },
286
+ { tier:"Organism", name:"Dialog", grp:"Overlays", framed:true, controls:[{k:"title",type:"text",def:"Send your wish?"}], renderC:(v)=> has(Dialog,Button)?<Dialog open={true} title={v.title} onClose={()=>{}} actions={<><Button variant="secondary">Not now</Button><Button>Send wish</Button></>}>A real person on the team replies within one business day.</Dialog>:<Miss n="Dialog"/>, render:()=> has(Dialog,Button)?<Dialog open={true} title="Send your wish?" onClose={()=>{}} actions={<><Button variant="secondary">Not now</Button><Button>Send wish</Button></>}>A real person on the team replies within one business day.</Dialog>:<Miss n="Dialog"/> },
287
+ { tier:"Organism", name:"AlertDialog", grp:"Overlays", controls:[{k:"tone",type:"select",options:["default","destructive"],def:"destructive"}], renderC:(v)=> has(AlertDialog)?<div style={{minHeight:200}}><AlertDialog open title="Delete workspace?" description="Removes every project. This cannot be undone." tone={v.tone} onOpenChange={()=>{}}/></div>:<Miss n="AlertDialog"/>, render:(L)=> <div style={{minHeight:120}}><AlertDialogD L={L}/></div> },
288
+ { tier:"Organism", name:"Drawer", grp:"Overlays", framed:true, controls:[{k:"title",type:"text",def:"Design System v1.6"}], renderC:(v)=> has(Drawer,Button)?<Drawer open={true} onClose={()=>{}} title={v.title} actions={<Button size="sm">Open project</Button>}><p style={{color:"var(--cs-color-text-muted)",fontSize:13}}>Liquid Glass component bindings + 15 element packs.</p></Drawer>:<Miss n="Drawer"/>, render:(L)=> has(Drawer)?<Drawer open={true} onClose={()=>{}} title="Design System v1.6" actions={has(Button)?<Button size="sm">{L==="vi"?"Mở dự án":"Open project"}</Button>:null}>{has(Badge)&&<Badge variant="ochre">{L==="vi"?"Đang làm":"In progress"}</Badge>}<p style={{color:"var(--cs-color-text-muted)",fontSize:13}}>{L==="vi"?"Liên kết component Liquid Glass + 15 gói Ngũ Hành.":"Liquid Glass component bindings + 15 element packs."}</p>{has(DescriptionList)&&<DescriptionList items={L==="vi"?[{term:"Phụ trách",value:"An Lê"},{term:"Nhóm",value:"Nền tảng"}]:[{term:"Owner",value:"An Le"},{term:"Squad",value:"Platform"}]}/>}</Drawer>:<Miss n="Drawer"/> },
289
+ { tier:"Organism", name:"Popover", grp:"Overlays", framed:true, controls:[{k:"trigger",type:"text",def:"Filter ▾"}], renderC:(v)=> has(Popover,Button,RadioGroup)?<div style={{padding:16}}><Popover open={true} onOpenChange={()=>{}} trigger={<Button variant="secondary" size="sm">{v.trigger}</Button>}><RadioGroup legend="Status" defaultValue="active" options={[{value:"active",label:"In progress"},{value:"done",label:"Shipped"}]}/></Popover></div>:<Miss n="Popover"/>, render:(L)=> has(Popover,Button,RadioGroup)?<div style={{padding:16}}><Popover open={true} onOpenChange={()=>{}} trigger={<Button variant="secondary" size="sm">{L==="vi"?"Lọc ▾":"Filter ▾"}</Button>}><RadioGroup legend={L==="vi"?"Trạng thái":"Status"} defaultValue="active" options={L==="vi"?[{value:"active",label:"Đang làm"},{value:"done",label:"Đã ra mắt"},{value:"hold",label:"Bị chặn"}]:[{value:"active",label:"In progress"},{value:"done",label:"Shipped"},{value:"hold",label:"Blocked"}]}/></Popover></div>:<Miss n="Popover"/> },
283
290
  { tier:"Organism", name:"Conversation (PromptInput + ChatMessage)", grp:"AI-native", render:(L)=> has(ChatMessage)?<div style={{maxWidth:520}}><div className="cs-chat" style={{marginBottom:12}}><ChatMessage role="lumi">{L==="vi"?"Xin chào, mình là Lumi. Hãy nói điều ước của bạn — mình sẽ tư vấn thẳng thắn trước khi hỏi bất kỳ điều gì.":"Hello, I'm Lumi. Tell me a wish, and I'll share plain advice before asking for anything."}</ChatMessage><ChatMessage role="user">{L==="vi"?"Một trang thanh toán nhanh hơn.":"A faster checkout."}</ChatMessage><ChatMessage role="lumi">{L==="vi"?"Một điều ước đáng thực hiện — mình nên gọi bạn là gì?":"A wish worth granting — what should I call you?"}</ChatMessage></div><PromptD L={L}/></div>:<Miss n="ChatMessage"/> },
284
291
  { tier:"Organism", name:"HumanReviewGate", grp:"AI-native", controls:[{k:"risk",type:"text",def:"High-stakes · billing change"},{k:"summary",type:"text",def:"Move client to annual + prorated credit."},{k:"reviewer",type:"text",def:"Ops on call"}], renderC:(v)=> has(HumanReviewGate)?<div style={{maxWidth:520}}><HumanReviewGate risk={v.risk} summary={v.summary} reviewer={v.reviewer}/></div>:<Miss n="HumanReviewGate"/>, render:()=> has(HumanReviewGate)?<div style={{maxWidth:520}}><HumanReviewGate risk="High-stakes · billing change" summary="Lumi proposes moving this client to the annual plan and issuing a prorated credit." reviewer="Ops on call"/></div>:<Miss n="HumanReviewGate"/> },
285
292
  ];
@@ -290,11 +297,11 @@ const TIERS = [
290
297
  { id:"Organism", label:"Organisms", sub:"Composite, self-contained sections." },
291
298
  ];
292
299
  const ELEMENTS = [
293
- ["tho|","Thổ · studio"],["tho|clay","Thổ · clay"],["tho|sand","Thổ · sand"],
294
- ["hoa|","Hỏa · ember"],["hoa|lava","Hỏa · lava"],["hoa|plasma","Hỏa · plasma"],
295
- ["thuy|","Thủy · river"],["thuy|ocean","Thủy · ocean"],["thuy|mist","Thủy · mist"],
296
- ["moc|","Mộc · leaf"],["moc|bamboo","Mộc · bamboo"],["moc|forest","Mộc · forest"],
297
- ["kim|","Kim · champagne"],["kim|steel","Kim · steel"],["kim|titanium","Kim · titanium"],
300
+ ["tho|","Thổ · studio (middle)"],["tho|sand","Thổ · sand (soft)"],["tho|clay","Thổ · clay (deep)"],
301
+ ["hoa|","Hỏa · ember (middle)"],["hoa|plasma","Hỏa · plasma (soft)"],["hoa|lava","Hỏa · lava (deep)"],
302
+ ["thuy|","Thủy · river (middle)"],["thuy|mist","Thủy · mist (soft)"],["thuy|ocean","Thủy · ocean (deep)"],
303
+ ["moc|","Mộc · leaf (middle)"],["moc|bamboo","Mộc · bamboo (soft)"],["moc|forest","Mộc · forest (deep)"],
304
+ ["kim|","Kim · champagne (middle)"],["kim|titanium","Kim · titanium (soft)"],["kim|steel","Kim · steel (deep)"],
298
305
  ];
299
306
  const LANGS = [["","Default"],["en","English"],["vi","Tiếng Việt"]];
300
307
  const PAGES = [
@@ -308,6 +315,7 @@ function applyAxis(ifr, ax){
308
315
  try{
309
316
  const d=ifr.contentDocument, h=d&&d.documentElement; if(!h) return;
310
317
  (ax.theme&&ax.theme!=="light")?h.setAttribute("data-theme",ax.theme):h.removeAttribute("data-theme");
318
+ if(ax.style) h.setAttribute("data-cs-style",ax.style); else h.setAttribute("data-cs-style","liquid-glass");
311
319
  ax.elm?h.setAttribute("data-cs-element",ax.elm):h.removeAttribute("data-cs-element");
312
320
  ax.elv?h.setAttribute("data-cs-variant",ax.elv):h.removeAttribute("data-cs-variant");
313
321
  if(ax.lang) h.setAttribute("lang", ax.lang);
@@ -350,6 +358,7 @@ const NM = window.__csNavModel || {};
350
358
 
351
359
  function App(){
352
360
  const [theme,setTheme]=useState("light");
361
+ const [style,setStyle]=useState("liquid-glass");
353
362
  const [el,setEl]=useState("tho|");
354
363
  const [lang,setLang]=useState("");
355
364
  const [collapsed,setCollapsed]=useState({Atom:false,Molecule:false,Organism:false,found:false,tpl:true,pages:true});
@@ -365,10 +374,11 @@ function App(){
365
374
  const [elm,elv]=el.split("|");
366
375
  const axis={};
367
376
  if(theme!=="light") axis["data-theme"]=theme;
377
+ if(style) axis["data-cs-style"]=style;
368
378
  if(elm) axis["data-cs-element"]=elm;
369
379
  if(elv) axis["data-cs-variant"]=elv;
370
380
  if(lang) axis.lang=lang;
371
- const artifactAx={theme,elm,elv,lang};
381
+ const artifactAx={theme,style,elm,elv,lang};
372
382
  const shownTpls=tpls.filter(t=>!nq||t.name.toLowerCase().includes(nq)||(NM.classifyTemplate&&NM.classifyTemplate(t.name).toLowerCase().includes(nq)));
373
383
  const tplGroups=(NM.groupTemplates||((xs)=>[{category:"All",items:xs}]))(shownTpls);
374
384
  const shownPages=PAGES.filter(t=>!nq||t.name.toLowerCase().includes(nq));
@@ -440,11 +450,14 @@ function App(){
440
450
  <div className="toolbar" data-chrome="atomic-toolbar">
441
451
  <h1>CyberSkill · Components</h1>
442
452
  <label className="ctl">Theme
443
- <select value={theme} onChange={(e)=>setTheme(e.target.value)}><option value="light">Light</option><option value="dark">Dark</option></select>
453
+ <select value={theme} onChange={(e)=>setTheme(e.target.value)}><option value="light">Light</option><option value="dark">Dark</option><option value="system">System</option></select>
444
454
  </label>
445
455
  <label className="ctl">Element
446
456
  <select value={el} onChange={(e)=>setEl(e.target.value)}>{ELEMENTS.map(([v,l])=><option key={v} value={v}>{l}</option>)}</select>
447
457
  </label>
458
+ <label className="ctl">Style
459
+ <select value={style} onChange={(e)=>setStyle(e.target.value)}><option value="liquid-glass">Liquid glass</option></select>
460
+ </label>
448
461
  <label className="ctl">Language
449
462
  <select value={lang} onChange={(e)=>setLang(e.target.value)}>{LANGS.map(([v,l])=><option key={v} value={v}>{l}</option>)}</select>
450
463
  </label>
@@ -0,0 +1,69 @@
1
+ <!-- @dsCard group="Elements" viewport="1280x720" name="Geometry · 30 sets" subtitle="Soft / middle / deep × light/dark — shared intensity · hue-locked themes" -->
2
+ <!DOCTYPE html>
3
+ <html lang="en"><head><meta charset="utf-8">
4
+ <link rel="stylesheet" href="../styles.css">
5
+ <style>
6
+ body{margin:0;background:var(--cs-color-surface-page);width:1280px;height:720px;overflow:hidden;box-sizing:border-box;padding:22px 28px;font-family:var(--cs-font-family-ui);color:var(--cs-color-text-primary)}
7
+ h1{font-size:18px;margin:0 0 4px;font-weight:800;letter-spacing:-0.01em}
8
+ .sub{font-size:12px;color:var(--cs-color-text-muted);margin:0 0 14px}
9
+ .grid{display:grid;grid-template-columns:repeat(5,1fr);gap:10px}
10
+ .el{font-weight:800;font-size:12px;margin-bottom:6px}
11
+ .card{border:1px solid var(--cs-color-border-default);border-radius:10px;overflow:hidden;background:var(--cs-color-surface-panel)}
12
+ .row{display:grid;grid-template-columns:1fr 1fr;min-height:88px}
13
+ .cell{padding:8px 10px;display:flex;flex-direction:column;justify-content:space-between;gap:6px}
14
+ .cell.dark{background:#221710;color:#f5ead9}
15
+ .slot{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.06em;opacity:0.75}
16
+ .sw{height:18px;border-radius:6px;box-shadow:inset 0 0 0 1px rgba(0,0,0,0.08)}
17
+ .meta{font-size:10px;font-family:var(--cs-font-family-mono);opacity:0.85}
18
+ .cta{display:inline-flex;align-items:center;justify-content:center;min-height:26px;padding:0 10px;border-radius:6px;font-size:11px;font-weight:700}
19
+ footer{margin-top:12px;font-size:11px;color:var(--cs-color-text-muted)}
20
+ </style></head>
21
+ <body>
22
+ <h1>Element geometry — 30 colour sets</h1>
23
+ <p class="sub">Thirty default colour sets (5 × soft/middle/deep × light/dark) — whole-set specimen, not a spot check. Soft is a washed pastel, middle the synced default, deep a clearly darker sibling in the same hue family; role ramps stay harmonious; theme flip keeps hue identity. Seeds: <code>tokens/element-seeds.json</code> · gate: <code>_audit/element-geometry.html</code>.</p>
24
+ <div class="grid" id="grid"></div>
25
+ <footer>Gate: <code>_audit/element-geometry.html</code> · Generate: <code>npm run tokens:elements</code> · Text never on mid-tone <code>-accent</code></footer>
26
+ <script type="module">
27
+ const ORDER = [
28
+ ['tho','Thổ',[['sand','soft'],[null,'middle'],['clay','deep']]],
29
+ ['hoa','Hỏa',[['plasma','soft'],[null,'middle'],['lava','deep']]],
30
+ ['thuy','Thủy',[['mist','soft'],[null,'middle'],['ocean','deep']]],
31
+ ['moc','Mộc',[['bamboo','soft'],[null,'middle'],['forest','deep']]],
32
+ ['kim','Kim',[['titanium','soft'],[null,'middle'],['steel','deep']]],
33
+ ];
34
+ const grid = document.getElementById('grid');
35
+ for (const [el, label, slots] of ORDER) {
36
+ const col = document.createElement('div');
37
+ col.innerHTML = `<div class="el">${label}</div>`;
38
+ for (const [va, slot] of slots) {
39
+ const card = document.createElement('div');
40
+ card.className = 'card';
41
+ card.style.marginBottom = '8px';
42
+ const mk = (dark) => {
43
+ const wrap = document.createElement('div');
44
+ wrap.className = 'cell' + (dark ? ' dark' : '');
45
+ if (el) wrap.setAttribute('data-cs-element', el);
46
+ if (va) wrap.setAttribute('data-cs-variant', va);
47
+ if (dark) wrap.setAttribute('data-theme', 'dark');
48
+ wrap.innerHTML = `
49
+ <div>
50
+ <div class="slot">${slot} · ${dark ? 'dark' : 'light'}${va ? ' · ' + va : ' · default'}</div>
51
+ <div class="sw" style="background:var(--cs-accent);margin-top:6px"></div>
52
+ </div>
53
+ <div style="display:flex;gap:6px;align-items:center;justify-content:space-between">
54
+ <span class="cta" style="background:var(--cs-accent-strong);color:var(--cs-accent-on)">CTA</span>
55
+ <span class="meta" style="color:var(--cs-color-text-accent)">Aa</span>
56
+ </div>`;
57
+ return wrap;
58
+ };
59
+ const row = document.createElement('div');
60
+ row.className = 'row';
61
+ row.appendChild(mk(false));
62
+ row.appendChild(mk(true));
63
+ card.appendChild(row);
64
+ col.appendChild(card);
65
+ }
66
+ grid.appendChild(col);
67
+ }
68
+ </script>
69
+ </body></html>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Elements" viewport="1280x560" name="Variants & washes" subtitle="12 variants inside 5 oklch envelopes · each element's aurora wash · Lumi stays golden in every element" -->
1
+ <!-- @dsCard group="Elements" viewport="1280x560" name="Variants & washes" subtitle="Soft / middle / deep names · aurora washes · live packs from element-seeds (see Geometry · 30 sets)" -->
2
2
  <!DOCTYPE html>
3
3
  <html lang="en"><head><meta charset="utf-8">
4
4
  <link rel="stylesheet" href="../styles.css">
@@ -18,25 +18,25 @@ a{color:var(--cs-color-link)}a:hover{color:var(--cs-color-link-hover)}
18
18
  <body>
19
19
  <div style="display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-bottom:16px">
20
20
  <div class="col"><div class="el">Mộc · Wood</div>
21
- <div class="v"><span class="sw" style="background:#7A9B57"></span><div><div class="vn">leaf ·default</div><div class="vx">#7A9B57</div></div></div>
22
- <div class="v"><span class="sw" style="background:#A9C177"></span><div><div class="vn">bamboo</div><div class="vx">#A9C177</div></div></div>
23
- <div class="v"><span class="sw" style="background:#3E5A2E"></span><div><div class="vn">forest</div><div class="vx">#3E5A2E</div></div></div></div>
21
+ <div class="v"><span class="sw" style="background:#ADD386"></span><div><div class="vn">leaf ·middle</div><div class="vx">#ADD386</div></div></div>
22
+ <div class="v"><span class="sw" style="background:#C7E2AC"></span><div><div class="vn">bamboo</div><div class="vx">#C7E2AC</div></div></div>
23
+ <div class="v"><span class="sw" style="background:#668643"></span><div><div class="vn">forest</div><div class="vx">#668643</div></div></div></div>
24
24
  <div class="col"><div class="el">Hỏa · Fire</div>
25
- <div class="v"><span class="sw" style="background:#E0632B"></span><div><div class="vn">ember ·default</div><div class="vx">#E0632B</div></div></div>
26
- <div class="v"><span class="sw" style="background:#C43D1F"></span><div><div class="vn">lava</div><div class="vx">#C43D1F</div></div></div>
27
- <div class="v"><span class="sw" style="background:#E8506E"></span><div><div class="vn">plasma</div><div class="vx">#E8506E</div></div></div></div>
25
+ <div class="v"><span class="sw" style="background:#FFAD8E"></span><div><div class="vn">ember ·middle</div><div class="vx">#FFAD8E</div></div></div>
26
+ <div class="v"><span class="sw" style="background:#BB5A32"></span><div><div class="vn">lava</div><div class="vx">#BB5A32</div></div></div>
27
+ <div class="v"><span class="sw" style="background:#FFC7CC"></span><div><div class="vn">plasma</div><div class="vx">#FFC7CC</div></div></div></div>
28
28
  <div class="col" style="outline:2px solid var(--cs-color-brand-ochre);outline-offset:2px"><div class="el">Thổ · Earth</div>
29
- <div class="v"><span class="sw" style="background:#F4BA17"></span><div><div class="vn">ochre ·studio</div><div class="vx">#F4BA17</div></div></div>
30
- <div class="v"><span class="sw" style="background:#C77B4A"></span><div><div class="vn">clay</div><div class="vx">#C77B4A</div></div></div>
31
- <div class="v"><span class="sw" style="background:#E4C98F"></span><div><div class="vn">sand</div><div class="vx">#E4C98F</div></div></div></div>
29
+ <div class="v"><span class="sw" style="background:#F4BA17"></span><div><div class="vn">ochre ·middle</div><div class="vx">#F4BA17</div></div></div>
30
+ <div class="v"><span class="sw" style="background:#98741A"></span><div><div class="vn">clay</div><div class="vx">#98741A</div></div></div>
31
+ <div class="v"><span class="sw" style="background:#F6D389"></span><div><div class="vn">sand</div><div class="vx">#F6D389</div></div></div></div>
32
32
  <div class="col"><div class="el">Kim · Metal</div>
33
- <div class="v"><span class="sw" style="background:#BFB29B"></span><div><div class="vn">champagne ·default</div><div class="vx">#BFB29B</div></div></div>
34
- <div class="v"><span class="sw" style="background:#9FA3A3"></span><div><div class="vn">steel</div><div class="vx">#9FA3A3</div></div></div>
35
- <div class="v"><span class="sw" style="background:#8A7F72"></span><div><div class="vn">titanium</div><div class="vx">#8A7F72</div></div></div></div>
33
+ <div class="v"><span class="sw" style="background:#D1C2A8"></span><div><div class="vn">champagne ·middle</div><div class="vx">#D1C2A8</div></div></div>
34
+ <div class="v"><span class="sw" style="background:#707D7E"></span><div><div class="vn">steel</div><div class="vx">#707D7E</div></div></div>
35
+ <div class="v"><span class="sw" style="background:#E1D6C3"></span><div><div class="vn">titanium</div><div class="vx">#E1D6C3</div></div></div></div>
36
36
  <div class="col"><div class="el">Thủy · Water</div>
37
- <div class="v"><span class="sw" style="background:#4E8E9B"></span><div><div class="vn">river ·default</div><div class="vx">#4E8E9B</div></div></div>
38
- <div class="v"><span class="sw" style="background:#2E5E7E"></span><div><div class="vn">ocean</div><div class="vx">#2E5E7E</div></div></div>
39
- <div class="v"><span class="sw" style="background:#A7C4C9"></span><div><div class="vn">mist</div><div class="vx">#A7C4C9</div></div></div></div>
37
+ <div class="v"><span class="sw" style="background:#87D2E1"></span><div><div class="vn">river ·middle</div><div class="vx">#87D2E1</div></div></div>
38
+ <div class="v"><span class="sw" style="background:#428693"></span><div><div class="vn">ocean</div><div class="vx">#428693</div></div></div>
39
+ <div class="v"><span class="sw" style="background:#AEE2ED"></span><div><div class="vn">mist</div><div class="vx">#AEE2ED</div></div></div></div>
40
40
  </div>
41
41
  <div style="display:grid;grid-template-columns:repeat(5,1fr);gap:14px">
42
42
  <div class="wash"><img src="../assets/aurora-moc.png" alt="Mộc aurora wash"><span class="wl">Mộc</span></div>
@@ -45,5 +45,5 @@ a{color:var(--cs-color-link)}a:hover{color:var(--cs-color-link-hover)}
45
45
  <div class="wash"><img src="../assets/aurora-kim.png" alt="Kim aurora wash"><span class="wl">Kim</span></div>
46
46
  <div class="wash"><img src="../assets/aurora-thuy.png" alt="Thủy aurora wash"><span class="wl">Thủy</span></div>
47
47
  </div>
48
- <footer style="display:flex;gap:16px;margin-top:14px;font-size:12px;color:var(--cs-color-text-muted);align-items:center"><b style="color:var(--cs-color-text-primary)">Rules</b><span>A variant is a point inside its element's oklch envelope — same 9-token contract</span><span>·</span><span>Washes apply via .cs-aurora-wash</span><span>·</span><span><b style="color:var(--cs-color-text-primary)">Lumi stays golden</b> — only the environment re-tints</span></footer>
48
+ <footer style="display:flex;gap:16px;margin-top:14px;font-size:12px;color:var(--cs-color-text-muted);align-items:center"><b style="color:var(--cs-color-text-primary)">Rules</b><span>Slots soft · middle · deep share intensity across elements — same 9-token contract (generated)</span><span>·</span><span>Washes apply via .cs-aurora-wash</span><span>·</span><span><b style="color:var(--cs-color-text-primary)">Lumi stays golden</b> — only the environment re-tints</span></footer>
49
49
  </body></html>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Type" viewport="700x230" name="Typefaces" subtitle="Be Vietnam Pro (UI) · JetBrains Mono (code)" -->
1
+ <!-- @dsCard group="Type" viewport="700x330" name="Typefaces" subtitle="Be Vietnam Pro (UI) · Space Grotesk (display) · JetBrains Mono (code)" -->
2
2
  <!DOCTYPE html>
3
3
  <html lang="en"><head><meta charset="utf-8" />
4
4
  <link rel="stylesheet" href="../styles.css" />
@@ -7,19 +7,25 @@
7
7
  .fam { margin-bottom: 18px; }
8
8
  .k { font: 600 11px/1 var(--cs-font-family-ui); text-transform: uppercase; letter-spacing: .09em; color: var(--cs-color-text-muted); margin-bottom: 6px; }
9
9
  .ui { font-family: var(--cs-font-family-ui); }
10
- .mono { font-family: var(--cs-font-family-mono); }
11
- .big { font-size: 30px; font-weight: 700; letter-spacing: -.01em; }
12
- .set { font-size: 15px; color: var(--cs-color-text-muted); margin-top: 2px; }
10
+ .cs-type-display { font-family: var(--cs-font-family-display); }
11
+ .cs-type-mono { font-family: var(--cs-font-family-mono); }
12
+ .cs-type-big { font-size: 30px; font-weight: 700; letter-spacing: -.01em; }
13
+ .cs-type-set { font-size: 15px; color: var(--cs-color-text-muted); margin-top: 2px; }
13
14
  </style></head>
14
15
  <body>
15
16
  <div class="fam">
16
- <div class="k">Be Vietnam Pro — UI / display</div>
17
- <div class="ui big">Turn Your Will Into Real</div>
18
- <div class="ui set">Hiện Thực Hoá Ý Chí · 300 400 500 600 700 800 · full Vietnamese diacritics</div>
17
+ <div class="k">Be Vietnam Pro — UI (--cs-font-family-ui)</div>
18
+ <div class="ui cs-type-big">Turn Your Will Into Real</div>
19
+ <div class="ui cs-type-set">Hiện Thực Hoá Ý Chí · 300 400 500 600 700 800 · full Vietnamese diacritics</div>
20
+ </div>
21
+ <div class="fam">
22
+ <div class="k">Space Grotesk — display / headline (--cs-font-family-display)</div>
23
+ <div class="cs-type-display cs-type-big">Turn Your Will Into Real</div>
24
+ <div class="cs-type-display cs-type-set">Hiện Thực Hoá Ý Chí · variable 300–700 · Vietnamese subset · opt-in via <span class="cs-type-mono">.cs-display-face</span></div>
19
25
  </div>
20
26
  <div class="fam" style="margin-bottom:0">
21
- <div class="k">JetBrains Mono — code / data</div>
22
- <div class="mono big" style="font-size:24px">--cs-color-brand-ochre</div>
23
- <div class="mono set">0123456789 · v1.5.1 · {} =&gt; () · 400 500 700</div>
27
+ <div class="k">JetBrains Mono — code / data (--cs-font-family-mono)</div>
28
+ <div class="cs-type-mono cs-type-big" style="font-size:24px">--cs-color-brand-ochre</div>
29
+ <div class="cs-type-mono cs-type-set">0123456789 · v1.5.1 · {} =&gt; () · 400 500 700</div>
24
30
  </div>
25
31
  </body></html>