@cyberskill/design 1.2.0 → 1.3.9

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 (232) hide show
  1. package/DESIGN.md +11 -9
  2. package/README.md +28 -24
  3. package/SKILL.md +18 -9
  4. package/THIRD-PARTY-NOTICES.md +35 -0
  5. package/VERSION +1 -1
  6. package/_ds_bundle.js +701 -1342
  7. package/_esm/cs.mjs +2 -2
  8. package/_esm/react.mjs +6 -1
  9. package/_vendor/NOTICE.md +16 -0
  10. package/_vendor/babel/README.md +7 -0
  11. package/_vendor/babel/babel.min.js +4 -0
  12. package/_vendor/react/README.md +3 -0
  13. package/_vendor/react/react-dom.production.min.js +1 -0
  14. package/_vendor/react/react.production.min.js +1 -0
  15. package/assets/aurora-hoa.webp +0 -0
  16. package/assets/aurora-kim.webp +0 -0
  17. package/assets/aurora-moc.webp +0 -0
  18. package/assets/aurora-tho.webp +0 -0
  19. package/assets/aurora-thuy.webp +0 -0
  20. package/base/ai.css +8 -3
  21. package/base/collections.css +10 -4
  22. package/base/components.css +5 -2
  23. package/base/controls.css +58 -21
  24. package/base/data.css +1 -1
  25. package/base/feedback.css +9 -2
  26. package/base/forms.css +1 -1
  27. package/base/glass.css +1 -1
  28. package/base/interaction.css +6 -2
  29. package/base/navigation.css +1 -1
  30. package/base/reset.css +7 -1
  31. package/base/responsive.css +13 -12
  32. package/base/shell.css +8 -2
  33. package/components/_i18n/i18n.js +28 -3
  34. package/components/_i18n/strings.js +42 -24
  35. package/components/ai/ChatMessage.d.ts +2 -0
  36. package/components/ai/ChatMessage.jsx +8 -4
  37. package/components/ai/ConfidenceMeter.d.ts +2 -0
  38. package/components/ai/HumanReviewGate.d.ts +2 -0
  39. package/components/ai/PromptInput.d.ts +2 -0
  40. package/components/ai/TypingIndicator.d.ts +2 -0
  41. package/components/ai/ai-conversation.card.html +3 -3
  42. package/components/ai/ai-lumi.card.html +3 -3
  43. package/components/ai/ai.card.html +3 -3
  44. package/components/brand/brand.card.html +3 -3
  45. package/components/button/buttons.card.html +3 -3
  46. package/components/data/Image.jsx +18 -2
  47. package/components/data/Sortable.d.ts +5 -1
  48. package/components/data/Sortable.jsx +42 -9
  49. package/components/data/Sortable.prompt.md +4 -2
  50. package/components/data/Terminal.jsx +3 -2
  51. package/components/data/Tooltip.d.ts +2 -0
  52. package/components/data/Tooltip.jsx +6 -3
  53. package/components/data/Tree.d.ts +2 -1
  54. package/components/data/Tree.jsx +137 -16
  55. package/components/data/Tree.prompt.md +1 -1
  56. package/components/data/collections.card.html +3 -3
  57. package/components/data/data.card.html +3 -3
  58. package/components/datatable/DataTable.d.ts +24 -1
  59. package/components/datatable/DataTable.jsx +78 -5
  60. package/components/datatable/DataTable.prompt.md +2 -1
  61. package/components/datatable/datatable.card.html +20 -16
  62. package/components/dialog/dialog.card.html +3 -3
  63. package/components/feedback/Alert.d.ts +2 -0
  64. package/components/feedback/Alert.jsx +8 -2
  65. package/components/feedback/EmptyState.d.ts +2 -0
  66. package/components/feedback/EmptyState.jsx +6 -3
  67. package/components/feedback/ProgressBar.d.ts +2 -0
  68. package/components/feedback/ProgressBar.jsx +6 -3
  69. package/components/feedback/Toast.jsx +15 -1
  70. package/components/feedback/Toast.prompt.md +2 -1
  71. package/components/feedback/feedback-2.card.html +3 -3
  72. package/components/feedback/feedback.card.html +3 -3
  73. package/components/forms/Cascader.jsx +7 -2
  74. package/components/forms/FileUpload.d.ts +2 -0
  75. package/components/forms/Form.d.ts +3 -1
  76. package/components/forms/Form.jsx +9 -1
  77. package/components/forms/Form.prompt.md +1 -1
  78. package/components/forms/Mentions.d.ts +1 -1
  79. package/components/forms/Mentions.jsx +59 -7
  80. package/components/forms/Mentions.prompt.md +3 -1
  81. package/components/forms/Rating.d.ts +3 -2
  82. package/components/forms/Rating.jsx +34 -3
  83. package/components/forms/Rating.prompt.md +1 -1
  84. package/components/forms/Select.d.ts +2 -0
  85. package/components/forms/Select.jsx +6 -2
  86. package/components/forms/Slider.d.ts +2 -0
  87. package/components/forms/Slider.jsx +5 -2
  88. package/components/forms/Switch.d.ts +2 -0
  89. package/components/forms/Switch.jsx +7 -9
  90. package/components/forms/Toggle.d.ts +2 -0
  91. package/components/forms/Toggle.jsx +14 -2
  92. package/components/forms/forms-2.card.html +3 -3
  93. package/components/forms/forms.card.html +3 -3
  94. package/components/icon/Icon.d.ts +1 -1
  95. package/components/icon/Icon.prompt.md +1 -1
  96. package/components/icon/icon.card.html +3 -3
  97. package/components/logo/logo.card.html +3 -3
  98. package/components/navigation/CommandPalette.d.ts +2 -0
  99. package/components/navigation/Menu.d.ts +2 -0
  100. package/components/navigation/Menu.jsx +60 -6
  101. package/components/navigation/Steps.d.ts +2 -0
  102. package/components/navigation/Steps.jsx +6 -3
  103. package/components/navigation/Tabs.d.ts +2 -0
  104. package/components/navigation/Tabs.jsx +6 -3
  105. package/components/navigation/Toolbar.d.ts +3 -2
  106. package/components/navigation/Toolbar.jsx +117 -11
  107. package/components/navigation/Toolbar.prompt.md +1 -1
  108. package/components/navigation/navigation.card.html +3 -3
  109. package/components/navigation/shell.card.html +3 -3
  110. package/components/overlays/ContextMenu.d.ts +2 -0
  111. package/components/overlays/ContextMenu.jsx +6 -3
  112. package/components/overlays/Drawer.d.ts +2 -0
  113. package/components/overlays/alertdialog.card.html +3 -3
  114. package/components/overlays/overlays.card.html +3 -3
  115. package/components/textfield/textfield.card.html +3 -3
  116. package/dist/styles.min.css +312 -64
  117. package/docs/benchmark-rubric.md +2 -2
  118. package/docs/ci-cd.md +18 -13
  119. package/docs/consumer-grant.md +4 -1
  120. package/docs/consuming.md +16 -12
  121. package/docs/contrast-report.md +81 -1
  122. package/docs/conventions.md +18 -5
  123. package/docs/decisions.md +41 -3
  124. package/docs/deploy.md +19 -6
  125. package/docs/design-styles.md +2 -2
  126. package/docs/doctrine.md +51 -0
  127. package/docs/figma.md +2 -0
  128. package/docs/live-hub.md +3 -1
  129. package/docs/products.md +1 -1
  130. package/docs/quality-gates.md +24 -12
  131. package/docs/release-notes.md +1 -1
  132. package/docs/release-runbook.md +78 -0
  133. package/docs/storybook.md +3 -3
  134. package/docs/sync.md +8 -8
  135. package/docs/template-schema-v2.md +1 -1
  136. package/docs/vi/benchmark-rubric.md +2 -2
  137. package/docs/vi/ci-cd.md +17 -14
  138. package/docs/vi/consumer-grant.md +4 -1
  139. package/docs/vi/consuming.md +16 -12
  140. package/docs/vi/contrast-report.md +81 -1
  141. package/docs/vi/conventions.md +19 -6
  142. package/docs/vi/decisions.md +40 -3
  143. package/docs/vi/deploy.md +19 -6
  144. package/docs/vi/design-styles.md +1 -1
  145. package/docs/vi/doctrine.md +51 -0
  146. package/docs/vi/figma.md +2 -0
  147. package/docs/vi/live-hub.md +3 -1
  148. package/docs/vi/products.md +1 -1
  149. package/docs/vi/quality-gates.md +23 -12
  150. package/docs/vi/release-notes.md +1 -1
  151. package/docs/vi/release-runbook.md +78 -0
  152. package/docs/vi/storybook.md +3 -3
  153. package/docs/vi/sync.md +7 -7
  154. package/docs/vi/template-schema-v2.md +1 -1
  155. package/docs/viewer.html +16 -5
  156. package/fonts/OFL.txt +98 -0
  157. package/guidelines/atomic-view.html +2 -2
  158. package/guidelines/brand-imagery.html +1 -1
  159. package/guidelines/elements-variants.html +5 -5
  160. package/guidelines/spacing-breakpoints.html +2 -1
  161. package/guidelines/surfaces-glass.html +1 -1
  162. package/llms.txt +18 -11
  163. package/package.json +28 -8
  164. package/templates/app-shell/AppShell.dc.html +3 -3
  165. package/templates/app-shell/content-schema.json +7 -0
  166. package/templates/article/Article.dc.html +3 -3
  167. package/templates/article/content-schema.json +7 -0
  168. package/templates/auth/Auth.dc.html +26 -10
  169. package/templates/auth/content-schema.json +25 -0
  170. package/templates/dashboard/Dashboard.dc.html +4 -4
  171. package/templates/dashboard/content-schema.json +7 -0
  172. package/templates/delivery-change-note/DeliveryChangeNote.dc.html +2 -2
  173. package/templates/delivery-runbook/DeliveryRunbook.dc.html +2 -2
  174. package/templates/email-safe/email-announcement.html +2 -2
  175. package/templates/email-safe/email-dunning.html +2 -2
  176. package/templates/email-safe/email-investor.html +2 -2
  177. package/templates/email-safe/email-launch.html +2 -2
  178. package/templates/email-safe/email-newsletter.html +2 -2
  179. package/templates/email-safe/email-status.html +2 -2
  180. package/templates/email-safe/email-transactional.html +2 -2
  181. package/templates/finance-dunning-email/FinanceDunningEmail.dc.html +2 -2
  182. package/templates/finance-expense-report/FinanceExpenseReport.dc.html +2 -2
  183. package/templates/finance-invoice/FinanceInvoice.dc.html +2 -2
  184. package/templates/finance-quote/FinanceQuote.dc.html +4 -4
  185. package/templates/hr-interview-kit/HrInterviewKit.dc.html +1 -1
  186. package/templates/marketing-case-study/MarketingCaseStudy.dc.html +1 -1
  187. package/templates/marketing-page/MarketingPage.dc.html +3 -3
  188. package/templates/marketing-page/content-schema.json +1 -0
  189. package/templates/settings/Settings.dc.html +3 -3
  190. package/templates/settings/content-schema.json +7 -0
  191. package/tokens/element-seeds.json +2 -2
  192. package/tokens/elements.css +193 -19
  193. package/tokens/native/CSTokens.kt +3 -2
  194. package/tokens/native/CSTokens.swift +3 -2
  195. package/tokens/native/cs_tokens.dart +3 -2
  196. package/tokens/provenance.json +8 -8
  197. package/tokens/spacing.css +2 -1
  198. package/tokens/tokens.dtcg.json +19 -14
  199. package/tokens/tokens.js +16 -15
  200. package/tokens/tokens.json +15 -14
  201. package/ui_kits/deck/index.html +1 -1
  202. package/ui_kits/status-hub/StatusHub.jsx +1 -1
  203. package/ui_kits/status-hub/login.html +52 -10
  204. package/ui_kits/status-hub/project.html +1 -1
  205. package/ui_kits/status-hub/settings.html +1 -1
  206. package/ui_kits/website/Website.jsx +1 -1
  207. package/ui_kits/website/careers.html +2 -2
  208. package/ui_kits/website/chat.html +1 -1
  209. package/ui_kits/website/site.css +1 -1
  210. package/ui_kits/website/work.html +2 -2
  211. package/assets/aurora-hoa.png +0 -0
  212. package/assets/aurora-kim.png +0 -0
  213. package/assets/aurora-moc.png +0 -0
  214. package/assets/aurora-thuy.png +0 -0
  215. package/docs/decisions/container-query-migration.md +0 -18
  216. package/docs/decisions/overlay-manager-design.md +0 -101
  217. package/docs/plans/cyberskill-design-system-audit-and-12-month-evolution-plan.md +0 -1490
  218. package/docs/status/assets/favicon.svg +0 -5
  219. package/docs/status/assets/status-legacy.css +0 -399
  220. package/docs/status/assets/status-legacy.js +0 -505
  221. package/docs/status/assets/status.css +0 -644
  222. package/docs/status/assets/status.js +0 -1308
  223. package/docs/status/data/status-feed.json +0 -1
  224. package/docs/status/data/task/TASK-REL-001.js +0 -1
  225. package/docs/status/data/task/TASK-REL-002.js +0 -1
  226. package/docs/status/index.html +0 -46
  227. package/docs/status/roadmap.html +0 -4
  228. package/docs/status/status-legacy.html +0 -122
  229. package/docs/tasks/BACKLOG.md +0 -26
  230. package/docs/tasks/_state/commit-links.yaml +0 -14
  231. package/docs/tasks/release/TASK-REL-001-launch-1-1-0/spec.md +0 -55
  232. package/docs/tasks/release/TASK-REL-002-republish-1-1-1/spec.md +0 -54
@@ -1,6 +1,6 @@
1
1
  # Design System Benchmark Rubric
2
2
 
3
- Self-audit checklist for evolving CyberSkill Design System — external standards plus CDS-owned rules. Pair with [`docs/quality-gates.md`](quality-gates.md) (deterministic gates) and [`docs/design-styles.md`](design-styles.md) (Element colour contract).
3
+ Self-audit checklist for evolving CyberSkill Design System — external standards plus CDS-owned rules. Pair with [`docs/quality-gates.md`](quality-gates.md) (deterministic gates) and [`docs/design-styles.md`](design-styles.md) (Element colour contract). Published on Storybook **Docs** at `design.cyberskill.world`.
4
4
 
5
5
  ## External standards
6
6
 
@@ -22,7 +22,7 @@ Self-audit checklist for evolving CyberSkill Design System — external standard
22
22
  | Text never on mid `-accent`; Ochre focus ring never remapped; status colours never remapped | `elements.css` contract · contrast-report · conventions |
23
23
  | One element per surface; Tương sinh gradients only | products registry · conventions |
24
24
  | Product→element registry locked; UI kits Thổ-faithful | [`docs/products.md`](products.md) |
25
- | Expansion Rule completeness + `_audit/run.html` green + docs EN·VI parity | CLAUDE.md · docs-consistency · docs-lang-parity |
25
+ | Expansion Rule completeness + `_audit/run.html` green + docs EN·VI parity | `docs/doctrine.md` · docs-consistency · docs-lang-parity · docs-storybook-coverage |
26
26
  | VERSION tracks file (LAUNCHED 1.1.0; auto-bump on main) | version-stamp · docs-consistency |
27
27
  | Element packs from seeds only (30 sets) | `element-geometry` · `tokens:elements` |
28
28
 
package/docs/ci-cd.md CHANGED
@@ -1,29 +1,32 @@
1
1
  # CI/CD — automating the gate board
2
2
 
3
+ **Release how-to (authoritative):** [`docs/release-runbook.md`](./release-runbook.md) — trigger → version → tag → npm OIDC → Vercel; SBOM + Scorecard; nightly failure alerting. Published on Storybook **Docs** at `design.cyberskill.world`.
4
+
3
5
  **Gate CI** (this workflow) still treats the design system as a static tree: serve the repo, open `_audit/run.html` headlessly, read verdict globals. No product bundler is required for gates.
4
6
 
5
7
  **Host deploy** (Vercel, separate from this workflow) does run `npm install` + `npm run build:site` so Storybook ships as the product surface at `/` — see `docs/deploy.md` and `docs/storybook.md`. That host packaging path is not required for consuming projects or for the gate jobs below.
6
8
 
7
9
  ## Badge
8
10
 
9
- [![Design System Gates](https://github.com/cyberskill-official/design-system/actions/workflows/design-system-gates.yml/badge.svg)](https://github.com/cyberskill-official/design-system/actions/workflows/design-system-gates.yml)
11
+ [![Design System Gates](https://github.com/cyberskill-official/design/actions/workflows/design-system-gates.yml/badge.svg)](https://github.com/cyberskill-official/design/actions/workflows/design-system-gates.yml)
10
12
 
11
13
  ## What's wired up (`.github/workflows/design-system-gates.yml`)
12
14
 
13
15
  1. **`fast-gates`** — `npm ci` + cached Playwright Chromium, serves the repo, opens `_audit/run.html` headlessly (`_audit/ci/run-gates.mjs`), fails on any hard-gate failure. Uploads import-report on failure. New rows added to the board (the Jul 2026 hardening added 8: token-format-parity, version-stamp, support-runtime-identity, package-exports-integrity, template-lang-parity, dtcg-typing, design-md-parity, bundle-freshness) are picked up automatically — the runner reads `window.__run`, not a job-side gate list.
14
16
  2. **`token-provenance`** — browser-free Node check that natives + `provenance.json` match DTCG source sha-256.
15
17
  3. **`unit-tests`** — `npm run test:unit` (11 plain-Node contract tests; wired into CI by the Jul 2026 hardening — previously local-only). Includes `test-element-packs` (`node scripts/generate-element-packs.mjs --check` freshness).
16
- 4. **`node-prechecks`** — browser-free Node authorities: `_audit/ci/check-bundle-freshness.mjs` (the bundle-freshness source of truth — full source discovery incl. new/deleted files; the board row only re-hashes header-recorded files) and `scripts/generate-design-md.mjs --check` (root `DESIGN.md` byte-equals regeneration).
18
+ 4. **`node-prechecks`** — browser-free Node authorities: `_audit/ci/check-bundle-freshness.mjs` (the bundle-freshness source of truth — full source discovery incl. new/deleted files; the board row only re-hashes header-recorded files), `scripts/generate-design-md.mjs --check` (root `DESIGN.md` byte-equals regeneration), `scripts/flatten-styles.mjs --check` + `scripts/generate-contrast-report.mjs --check` (FIND-026), and `_audit/ci/check-manifest-coverage.mjs` (FIND-078).
19
+ 4b. **`storybook-build`** — `npm run build:storybook` then `test-storybook-freshness.mjs --require` (FIND-074 / FIND-075). A Storybook break fails CI before deploy.
17
20
  5. **`docs-consistency-blocker`** — `docs-consistency` + `bilingual-parity` merge blockers.
18
21
  6. **`whole-set-audits`** — owner decision B: every push/PR, plus nightly `0 3 * * *` and `workflow_dispatch` (responsive + language + theme overflow, ~15–20 min).
19
22
  7. **`figma-variables-push`** — on `main` push + manual. **Empty `FIGMA_TOKEN` / `FIGMA_FILE_KEY` soft-skip** (exit 0 + report — same honesty as Code Connect). Owner decision A (non-Enterprise): Variables REST also **soft-skips on API 403** (and related plan/scope failures) after secrets prove file open. Soft-skip ≠ live Variables sync. See `docs/figma.md`.
20
23
  8. **`code-connect`** — on PR + `main` + manual. Decision 1C: dry-run always (config + 105 mappings); publish soft-skips when `FIGMA_TOKEN` / `FIGMA_FILE_KEY` missing or API 403/404/429. See `docs/figma.md`.
21
- 9. **`regenerate-tokens`** (pull requests) + **`regenerate-tokens-push`** (push to `main` / schedule / manual) — path filter covers element seeds/packs (`element-seeds.json`, `elements.css`, JSON/JS/DTCG mirrors, `generate-element-packs.mjs`) plus natives / `VERSION`. Regeneration runs `npm run tokens:elements` then `node _audit/ci/generate-native-tokens.mjs`. On a **pull request** the job runs with `contents: read`, never pushes, and **exits 1** on drift: run both locally and commit. Only the push/schedule/manual twin holds `contents: write` and auto-commits with `DS_PUSH_TOKEN` (or `github.token`).
22
- 10. **`npm-hello-smoke`** — registry consumer proof: `cd examples/npm-hello && npm ci && npm run smoke` (**hard fail**; package is public). Path-filtered on push/PR when `examples/npm-hello/**`, package publish surface, or this workflow changes; always on schedule / `workflow_dispatch`.
24
+ 9. **`regenerate-tokens`** (pull requests) + **`regenerate-tokens-push`** (push to `main` / schedule / manual) — path filter covers element seeds/packs (`element-seeds.json`, `elements.css`, JSON/JS/DTCG mirrors, `generate-element-packs.mjs`) plus natives / `VERSION`. Regeneration runs `npm run tokens:elements` then `node _audit/ci/generate-native-tokens.mjs`. On a **pull request** the job runs with `contents: read`, never pushes, and **exits 1** on drift: run both locally and commit (PR-required freshness). Only the push/schedule/manual twin holds `contents: write` and may auto-commit with `PUSH_TOKEN` (or `github.token`). Auto-commits **do not** use `[skip ci]` — the pushed tip re-enters the gate board (FIND-021 / TASK-IMP-008); a deterministic second pass is a no-op.
25
+ 10. **`npm-hello-smoke`** — registry consumer proof for `@cyberskill/design@$VERSION` (**fail-closed**, FIND-087): `examples/npm-hello` → registry `npm install` + `npm run smoke`. If the exact VERSION is **not** on the registry, the job **fails** (no soft-skip pack proof on `cyberskill-official/design`). Forks may opt into local-pack proof only by setting repo variable **`NPM_HELLO_ALLOW_LOCAL_PACK=true`**. Path-filtered on push/PR when `examples/npm-hello/**`, package publish surface, or this workflow changes; always on schedule / `workflow_dispatch`.
23
26
 
24
- Separate workflow **`version`** (`.github/workflows/version.yml`): on push to `main`, Conventional-Commit bump of `VERSION` + stamp shippable artifacts; commits `chore(release): X.Y.Z`, pushes, and tags `vX.Y.Z`. Skips its own release commits (loop-safe). Owner can force a level via `workflow_dispatch` or a `Release-As:` trailer. Needs `contents: write` (same `DS_PUSH_TOKEN` pattern as `regenerate-tokens-push` if branch protection blocks `github.token`).
27
+ Separate workflow **`version`** (`.github/workflows/version.yml`): on push to `main`, Conventional-Commit bump of `VERSION` + stamp shippable artifacts; then regenerates natives/provenance hashes and `npm run build:bundle` so tip stays gate-clean; commits `chore(release): X.Y.Z`, pushes, and tags `vX.Y.Z`. Skips its own release commits (loop-safe). Owner can force a level via `workflow_dispatch` or a `Release-As:` trailer. Needs `contents: write`. Checkout uses `secrets.PUSH_TOKEN || github.token` — if branch protection requires status checks (or blocks `github.token`), set repository secret **`PUSH_TOKEN`** (fine-grained PAT with Contents: Read and write); otherwise the bump computes but the push soft-warns and does not land.
25
28
 
26
- Separate workflow **`npm-publish`** (`.github/workflows/npm-publish.yml`): `workflow_dispatch` + `v*` tags (normally created by `version.yml`); pack dry-run always; publish via **npm Trusted Publishing (OIDC)** (`id-token: write`, no `NPM_TOKEN` on the publish step). Soft-skips on auth / 403 / 404 / EOTP / version conflict. License **UNLICENSED**. Trusted Publisher on npmjs must match workflow filename `npm-publish.yml`. Package Publishing access is **Require 2FA and disallow tokens** (OIDC still works; classic tokens rejected).
29
+ Separate workflow **`npm-publish`** (`.github/workflows/npm-publish.yml`): `workflow_dispatch` + `v*` tags (normally created by `version.yml`); pack dry-run always; publish via **npm Trusted Publishing (OIDC)** (`id-token: write`, no `NPM_TOKEN` on the publish step). Soft-skips only **`already_published`** and true **non-GHA** `missing_secrets`. On tag / `workflow_dispatch`, **ENEEDAUTH** / **404** / **402** / **403** / **EOTP** **fail closed**. Post-publish asserts `npm view @cyberskill/design@VERSION` **and** `dist-tags.latest === VERSION` (FIND-094). License **UNLICENSED**. Trusted Publisher on npmjs must match workflow filename `npm-publish.yml` for repo **`cyberskill-official/design`** (FIND-088). Package Publishing access is **Require 2FA and disallow tokens** (OIDC still works; classic tokens rejected).
27
30
 
28
31
  Separate workflow **`native-store`** (`.github/workflows/native-store.yml`): PR + `main` (path-filtered) + `workflow_dispatch`; scaffold dry-run always; signed-release check soft-skips without `ASC_KEY_ID` / `ASC_ISSUER_ID` / `ASC_KEY_P8` / `PLAY_SERVICE_ACCOUNT_JSON`. **Never submits** to App Store / Play — samples remain samples. See `examples/native/README.md`.
29
32
 
@@ -42,16 +45,18 @@ Node **22** on runners (avoids Node 20 action deprecation). Playwright browser c
42
45
 
43
46
  ## Token auto-commit permissions
44
47
 
45
- Only `regenerate-tokens-push` requests `permissions: contents: write`; the pull-request twin `regenerate-tokens` stays on `contents: read` and checks out without persisted credentials, so a PR can never trigger a bot push. If org locks the default token to read-only, set repository secret `DS_PUSH_TOKEN` (fine-grained PAT, Contents read/write) or unlock write at org Actions settings. See earlier notes in git history / org settings.
48
+ `regenerate-tokens-push` and `version.yml` request `permissions: contents: write` and check out with `secrets.PUSH_TOKEN || github.token`. The pull-request twin `regenerate-tokens` stays on `contents: read` and never pushes. If rulesets/branch protection require status checks before push (or lock the default Actions token), set repository secret **`PUSH_TOKEN`** (fine-grained PAT, Contents: Read and write on this repo) or allow GitHub Actions to bypass the ruleset. Without that, bot pushes soft-warn and exit 0; content drift is still hard-failed by `token-provenance` / fast-gates / `node-prechecks`.
49
+
50
+ ## Branch protection (recommended) — NV-18.1 out-of-band
46
51
 
47
- ## Branch protection (recommended)
52
+ **NV-18.1 (assessment):** which checks are **required** to merge to `main`, whether administrators are included, and whether CODEOWNERS / review / conversation-resolution are enforced are **GitHub settings, not in the repo**. Observed state from a clone alone: **unknown / confirm out-of-band**. Do not invent live ruleset values from workflow YAML.
48
53
 
49
- Require status checks on `main` before merge:
54
+ **Recommended** (documentation only — apply in GitHub Settings → Branches / Rulesets, or via admin `gh api`):
50
55
 
51
56
  - `fast-gates`
52
57
  - `docs-consistency-blocker`
53
58
 
54
- Optional: `whole-set-audits` (long). Configure under repo **Settings → Branches** or via `gh api` (admin).
59
+ Optional: `whole-set-audits` (long).
55
60
 
56
61
  ## Running locally
57
62
 
@@ -74,11 +79,11 @@ node _audit/ci/generate-native-tokens.mjs
74
79
  - **Side-by-side visual / component baseline rows** — advisory only (drift judged by eye). Playwright `%` pixel compare is a **hard** gate (`pixel-diff` job + board Pixel CI row).
75
80
  - **Figma Variables** — soft-skip when secrets missing (same honesty as Code Connect) or Variables write hits non-Enterprise / API **403**; report artifact records the skip. Soft-skip ≠ live sync.
76
81
  - **Code Connect publish** — soft-skip when secrets missing or API 403/404/429 (Decision 1C).
77
- - **npm publish** — Trusted Publishing (OIDC) on `npm-publish.yml`; soft-skip on auth / conflict (Decision 1C).
82
+ - **npm publish** — Trusted Publishing (OIDC) on `npm-publish.yml`; soft-skip on `already_published` / non-GHA `missing_secrets` only; on GHA release **ENEEDAUTH** / **404** / **402** / **403** / **EOTP** fail closed + post-publish version **and** `dist-tags.latest` check (Decision §7 / FIND-020 / FIND-094).
78
83
  - **Native store signed release** — soft-skip when `ASC_*` / `PLAY_SERVICE_ACCOUNT_JSON` absent (Decision 1C); store submit stays disabled.
79
- - **npm-hello registry smoke** — **hard fail** (`examples/npm-hello` → `npm ci` + `npm run smoke`); proves the public `@cyberskill/design` install path (not soft-skip).
84
+ - **npm-hello registry smoke** — **fail-closed** (`examples/npm-hello` → registry install + `npm run smoke`); missing `@cyberskill/design@$VERSION` fails the job (FIND-087). Local-pack proof is fork opt-in only (`NPM_HELLO_ALLOW_LOCAL_PACK`).
80
85
 
81
- A green `figma-variables-push` or `code-connect` job — and therefore a green badge or Status row — only means the job exited 0; it does **not** prove a live Figma sync, because a soft-skip and a real publish look identical from outside. Open the run's report artifact (`figma-push-report.json` / `code-connect-report.json`) to see which one happened.
86
+ A green `figma-variables-push` or `code-connect` job still exits 0 on Decision 1C soft-skip, but FIND-095 makes the outcome visible on the public run page via `$GITHUB_STEP_SUMMARY` plus a distinct annotation (`::error::` on schedule/main, `::warning::` elsewhere) — soft-skip is never identical silent green to a live publish. Report artifacts (`figma-push-report.json` / `code-connect-report.json`) still carry detail.
82
87
 
83
88
  ## Soft-skip dry-runs (local)
84
89
 
@@ -1,6 +1,6 @@
1
1
  # Consumer grant — `@cyberskill/design`
2
2
 
3
- **Status: in force** (Jul 2026). Policy text — not a secret. License on the package remains **UNLICENSED**; this grant is the approval layer for use in named products.
3
+ **Status: in force** (Jul 2026). Policy text — not a secret. License on the package remains **UNLICENSED**; this grant is the approval layer for use in named products. Published on Storybook **Docs** at `design.cyberskill.world`.
4
4
 
5
5
  ## Grant
6
6
 
@@ -19,10 +19,13 @@ CyberSkill grants **CyberSkill** (the company and its product engineering teams
19
19
 
20
20
  The package remains **UNLICENSED**. Installing from the npm registry does **not** by itself grant redistribution rights. Redistribution outside the products above — including publishing a fork, re-licensing, or shipping the package as a dependency of an unrelated third-party product — needs a **further written grant** recorded in this file (or a superseding instrument).
21
21
 
22
+ **Third-party carve-out:** OFL fonts under `fonts/`, MIT-vendored runtimes under `_vendor/`, and other assets listed in root `THIRD-PARTY-NOTICES.md` keep their **upstream** licenses. The UNLICENSED assertion and this grant do **not** supersede those terms; redistributors must comply with `fonts/OFL.txt` and the notices file.
23
+
22
24
  ## Scope notes
23
25
 
24
26
  - **Clone / subtree / static link** of this repo for the same products is covered the same way as an npm install.
25
27
  - **Host-only tooling** (Storybook, `_audit/`) is not part of the npm tarball and is not redistributable under this grant.
28
+ - **Third-party notices:** see root `THIRD-PARTY-NOTICES.md` and `fonts/OFL.txt`.
26
29
  - Adding a new CyberSkill product: update `docs/products.md` (+ VI) via a maintainer decision, then add the product row here in the same change.
27
30
  - Approving an **external** team or client: append a dated grant stanza below (team/org, named products, contact). Do not invent product → element mappings here — that stays in `docs/products.md`.
28
31
 
package/docs/consuming.md CHANGED
@@ -1,10 +1,14 @@
1
1
  # Consuming & upgrading the CyberSkill Design System
2
2
 
3
- How any project — human-driven or agent-driven — adopts this HTML-first design system, and how to take updates safely.
3
+ How any project — human-driven or agent-driven — adopts this HTML-first design system, and how to take updates safely. Published on Storybook **Docs** at `design.cyberskill.world`.
4
4
 
5
5
  **Package name:** `@cyberskill/design` (see `package.json`). Do not treat historical `@cyberskill/react` as the install path for this monolith.
6
6
 
7
- ## Claude Code vs Google Stitch
7
+ ## When to use
8
+
9
+ You are installing, linking, or upgrading the system in another product. Maintainers extending the system start at `docs/doctrine.md`.
10
+
11
+ ## Capability paths (DC-capable vs static)
8
12
 
9
13
  | Consumer | Start here | Works today | Do not |
10
14
  |---|---|---|---|
@@ -17,11 +21,11 @@ How any project — human-driven or agent-driven — adopts this HTML-first desi
17
21
 
18
22
  **Release signal:** version is LAUNCHED at **1.1.0**; **pin tracks `VERSION`** (no CHANGELOG). Treat the **git tip SHA** as technical truth; read curated product highlights in `docs/release-notes.md`.
19
23
 
20
- ## Quick path for AI agents (Claude Code, or driving one)
24
+ ## Quick path for AI agents (DC-capable authoring, or driving one)
21
25
 
22
26
  **What you get:** `styles.css` (400+ tokens + `.cs-*` classes + Liquid Glass surfaces, `@import`s `tokens/` + `base/`) · `_ds_bundle.js` (compiled React components, no build step) · `_esm/react.mjs` (bundler-native React entry — React as peerDependency; default `exports["."]`) · `_esm/cs.mjs` (browser / no-build legacy via `exports["./legacy"]`) · `_ds_manifest.json` (machine-readable inventory) · per-component `Name.d.ts` (API) + `Name.prompt.md` (usage brief) · `tokens/tokens.dtcg.json` (W3C DTCG) + `tokens.json`/`tokens.js`.
23
27
 
24
- **Repo checkout** — clone or copy the whole tree; everything is relative-path static. Entry points: Storybook on the host site (`/` / `npm run storybook`) · `guidelines/atomic-view.html` (every component live, portable) · `templates/<slug>/` (copyable starting points — DC for Claude Design; kitchen-sink / `.cs-*` for Stitch). Read `SKILL.md` before authoring anything on-brand; Stitch readers start at `DESIGN.md`. Deeper maps live in `llms.txt` (inventory) and this file (full adoption + upgrade guide below).
28
+ **Repo checkout** — clone or copy the whole tree; everything is relative-path static. Entry points: Storybook on the host site (`/` / `npm run storybook`) · `guidelines/atomic-view.html` (every component live, portable) · `templates/<slug>/` (copyable starting points — DC when a compiler is present; kitchen-sink / `.cs-*` for Stitch / static). Read `SKILL.md` before authoring anything on-brand; Stitch readers start at `DESIGN.md`. Deeper maps live in `llms.txt` (inventory) and this file (full adoption + upgrade guide below).
25
29
 
26
30
  **After import — prove health.** Open `_audit/run.html`, let the gate board finish (every fast gate). All green = the copy is internally consistent (contrast, docs, portability, tokens, consumer path, behavior, a11y, stories, bilingual parity). Full-clone only — `_audit/` is not in the npm tarball.
27
31
 
@@ -34,7 +38,7 @@ How any project — human-driven or agent-driven — adopts this HTML-first desi
34
38
 
35
39
  - Anchors (Umber/Ochre), `.cs-*` class names, `--cs-*` token names are stable contracts.
36
40
 
37
- - Extending the system? Follow `CONTRIBUTING.md` (Expansion Rule: propagate to every deliverable in one change; verify via `_audit/`).
41
+ - Extending the system? Follow `docs/doctrine.md` and `CONTRIBUTING.md` (Expansion Rule: propagate to every deliverable in one change; verify via `_audit/`).
38
42
 
39
43
  ## Adopt via npm (optional)
40
44
 
@@ -54,7 +58,7 @@ import { Button, TextField } from "@cyberskill/design";
54
58
  import "@cyberskill/design/styles.css";
55
59
  ```
56
60
 
57
- Add `transpilePackages: ["@cyberskill/design"]` in Next.js (JSX ships as source). React and react-dom are **peerDependencies** — your app provides them. Published types use `export type *` (**TypeScript 5.0+**). Do **not** import `_esm/cs.mjs` (or `@cyberskill/design/legacy`) into an SSR bundler; that path self-ensures React via CDN and side-loads `_ds_bundle.js` for browsers only.
61
+ Add `transpilePackages: ["@cyberskill/design"]` in Next.js (JSX ships as source). The default entry (`_esm/react.mjs`) is a **`"use client"` barrel** — App Router Server Components can `import { Button } from "@cyberskill/design"` without per-import client shims. React and react-dom are **peerDependencies** — your app provides them. Published types use `export type *` (**TypeScript 5.0+**). Do **not** import `_esm/cs.mjs` (or `@cyberskill/design/legacy`) into an SSR bundler; that path self-ensures React via CDN and side-loads `_ds_bundle.js` for browsers only.
58
62
 
59
63
  **Browser / no-build:** import `@cyberskill/design/legacy` (`_esm/cs.mjs`) or continue with the static tree paths below. The published tarball is the **full portable tree** (styles, tokens, components, templates, guidelines, docs, UI kits) — not a minimal “lib-only” subset. Host-only tooling (Storybook, `_audit/`) is not in `files[]`.
60
64
 
@@ -64,11 +68,11 @@ Add `transpilePackages: ["@cyberskill/design"]` in Next.js (JSX ships as source)
64
68
 
65
69
  ## Adopt (two paths, plus a module shortcut)
66
70
 
67
- **1. Static / prototypes / mocks — link the stylesheet.** Copy `styles.css` (+ the `tokens/`, `base/`, `fonts/` it `@import`s, or serve the whole tree) and link it; you now have every `--cs-*` token, the `.cs-*` component classes, and the Liquid Glass surfaces. Compose with the classes (see `templates/kitchen-sink.html`). Copy any asset you reference from `assets/`.
71
+ **1. Static / prototypes / mocks — link the stylesheet.** For **production static**, link the flattened bundle `dist/styles.min.css` (also `@cyberskill/design/styles.min.css`) — one file, no `@import` waterfall. Keep `styles.css` (+ the `tokens/`, `base/`, `fonts/` it `@import`s) as the readable source/dev path, or serve the whole tree. Either way you get every `--cs-*` token, the `.cs-*` component classes, and the Liquid Glass surfaces. Compose with the classes (see `templates/kitchen-sink.html` and `examples/static-hello/`). Copy any asset you reference from `assets/`.
68
72
 
69
- **2. Production React — load the compiled bundle.** Link `styles.css` and `<script src="_ds_bundle.js">`, then read components off the namespace. **Resolve by prefix, never hardcode:** the bundle exposes `window.CyberSkillDesignSystem_<projectId>`, and that 6-hex suffix is compiler-assigned and **changes on import into another project**:
73
+ **2. Production React — load the compiled bundle.** Link `dist/styles.min.css` (or `styles.css` in dev) and `<script src="_ds_bundle.js">`, then read components off the namespace. **Resolve by prefix, never hardcode:** the bundle exposes `window.CyberSkillDesignSystem_<projectId>`, and that 6-hex suffix is compiler-assigned and **changes on import into another project**:
70
74
  ```html
71
- <link rel="stylesheet" href="<path>/styles.css">
75
+ <link rel="stylesheet" href="<path>/dist/styles.min.css">
72
76
  <script src="<path>/_ds_bundle.js"></script>
73
77
  <script>
74
78
  const CS = window[Object.keys(window).find(k => /^CyberSkillDesignSystem_/.test(k))];
@@ -76,7 +80,7 @@ Add `transpilePackages: ["@cyberskill/design"]` in Next.js (JSX ships as source)
76
80
  </script>
77
81
  ```
78
82
  This is exactly what `_audit/consumer-smoke-test.html` exercises (and asserts green) — and the templates' `ds-base.js` does the same, publishing a stable `window.CyberSkillDS` alias.
79
- **2b. Bundler-native React (Next / Vite / SSR) — default package entry.** `import { Button, TextField } from "@cyberskill/design"` resolves to `_esm/react.mjs` (also exported as `@cyberskill/design/react`). Re-exports every component from source JSX with **React as an external peer** — no CDN, no `_ds_bundle.js` side-load. Your bundler must transpile the package (Next: `transpilePackages: ["@cyberskill/design"]`). Still link `styles.css` yourself. Regenerated with `npm run build:react-entry`; parity is gated by `package-exports-integrity` + `test:react-entry`.
83
+ **2b. Bundler-native React (Next / Vite / SSR) — default package entry.** `import { Button, TextField } from "@cyberskill/design"` resolves to `_esm/react.mjs` (also exported as `@cyberskill/design/react`). The generated file starts with `"use client"` so App Router / RSC consumers import interactive components directly. Re-exports every component from source JSX with **React as an external peer** — no CDN, no `_ds_bundle.js` side-load. Your bundler must transpile the package (Next: `transpilePackages: ["@cyberskill/design"]`). Still link styles yourself (`styles.min.css` recommended for production static sheets). Regenerated with `npm run build:react-entry`; parity is gated by `package-exports-integrity` + `test:react-entry`.
80
84
 
81
85
  **2c. Browser ESM legacy — one import, no build.** `import { Button, TextField } from "@cyberskill/design/legacy"` (or `"<path>/_esm/cs.mjs"`) — the module self-ensures React via **umd-react@19.2.8** (SRI-pinned CDN; official React 19 has no UMD; skipped when `window.React` exists), side-loads `_ds_bundle.js` once, resolves the namespace by prefix, and re-exports all components (`_audit/esm-smoke-test.html` keeps the export list in lockstep with the manifest). Still link `styles.css` yourself. **Not for Next/SSR.** Bundler apps should keep providing their own `react` / `react-dom` peers (`^18 || ^19`).
82
86
 
@@ -84,7 +88,7 @@ This is exactly what `_audit/consumer-smoke-test.html` exercises (and asserts gr
84
88
 
85
89
  **Machine-readable tokens.** `tokens/tokens.json` + `tokens/tokens.js` (ESM) + `tokens/tokens.dtcg.json` (W3C DTCG, for Tokens Studio/Style Dictionary) expose every token grouped by category + theme/element maps — for native/mobile/design-tool pipelines. **Native builds ship pre-generated** in `tokens/native/` (SwiftUI `CSTokens.swift` · Compose `CSTokens.kt` · Flutter `cs_tokens.dart`) with `tokens/provenance.json` (release, source sha-256, conversion rules, per-target sha-256); the `token-pipeline` gate keeps them in lockstep with the DTCG source.
86
90
 
87
- **Static HTML / no React / no build tooling.** Link `styles.css` and compose with `.cs-*` classes — full catalog demonstrated in `templates/kitchen-sink.html`.
91
+ **Static HTML / no React / no build tooling.** Link `dist/styles.min.css` (production) or `styles.css` (source/dev) and compose with `.cs-*` classes — full catalog demonstrated in `templates/kitchen-sink.html`.
88
92
 
89
93
  **Fonts, including a display face.** All three brand families are self-hosted in `fonts/` and declared by `tokens/fonts.css` (which `styles.css` `@import`s): **Be Vietnam Pro** (`--cs-font-family-ui`), **JetBrains Mono** (`--cs-font-family-mono`), and **Space Grotesk** (`--cs-font-family-display`, variable 300–700, Vietnamese subset included). The display face is **opt-in** — nothing in the DS points at it. A product that wants a headline face adds `class="cs-display-face"` (or sets `--cs-heading-family: var(--cs-font-family-display)`) on the scope; heading utilities follow, body copy stays on the UI face.
90
94
 
@@ -92,7 +96,7 @@ Consumers that skip `styles.css` to control font loading (`cyberskill.world` / L
92
96
 
93
97
  ## The four axes
94
98
 
95
- State Theme (`data-theme` — light / dark / system), Element (`data-cs-element` + `data-cs-variant`), Language (`lang` / template Language tweak), and Style (`data-cs-style`) on a container; everything inside re-skins with no code change (see `templates/playground.html`). Defaults: `light · tho · en · liquid-glass` (absent theme / style ≡ those defaults). Bilingual: components resolve strings from `lang` (`lang="vi"` on any container → full Vietnamese).
99
+ State Theme (`data-theme` — light / dark / system), Element (`data-cs-element` + `data-cs-variant`), Language (`lang` / template Language tweak), and Style (`data-cs-style`) on a container; everything inside re-skins with no code change (see `templates/playground.html`). Defaults: `light · tho · vi · liquid-glass` (absent theme / style ≡ those defaults; set `lang="en"` for EN surfaces). Bilingual: components resolve strings from `lang` (`lang="en"` on any container → full English; unset → Vietnamese-first fallback).
96
100
 
97
101
  ## Upgrading
98
102
 
@@ -1,6 +1,8 @@
1
1
  # Contrast report — elemental pairings (APCA)
2
2
 
3
- Generated 2026-07-27 · sweep at VERSION 1.1.1 pin.
3
+ Generated · sweep at VERSION 1.3.9.
4
+
5
+ Published on Storybook **Docs** at `design.cyberskill.world`.
4
6
 
5
7
  **Doctrine encoded by this sweep:** text sits on `-bright` or `-tint`, never on the mid-tone `-accent` — at any size. The accent is for bars, borders, progress fills, and non-text fills only. (Rule stated in `tokens/elements.css` and conventions.)
6
8
 
@@ -90,6 +92,84 @@ Packs are generated from `tokens/element-seeds.json` (soft / middle / deep ladde
90
92
 
91
93
  **Failures: 0.** All text pairings pass Lc ≥ 60.
92
94
 
95
+ ## Element-pack link contrast (WCAG AA · body text)
96
+
97
+ `--cs-color-link` is scored at **4.5:1** (regular-weight body). `--cs-color-text-accent` remains on the APCA Lc ≥ 60 bold-label floor above.
98
+ | Scope | Pairing | fg / bg | Ratio | Verdict |
99
+ |---|---|---|---|---|
100
+ | tho · sand | link on white (body) | #7B6D4A / #FFFFFF | 5.09:1 | ✓ |
101
+ | tho · sand | link on element page (body) | #7B6D4A / #FFFDF8 | 5.00:1 | ✓ |
102
+ | tho · sand | link on tint (body) | #7B6D4A / #FBF7EA | 4.75:1 | ✓ |
103
+ | tho · sand | link on raised cream (body) | #7B6D4A / #FBF4E9 | 4.66:1 | ✓ |
104
+ | tho · sand | link on dark panel (body) | #F6EBCC / #221710 | 14.75:1 | ✓ |
105
+ | tho · clay | link on white (body) | #201300 / #FFFFFF | 18.19:1 | ✓ |
106
+ | tho · clay | link on element page (body) | #201300 / #FFFDF8 | 17.89:1 | ✓ |
107
+ | tho · clay | link on tint (body) | #201300 / #FFF6E7 | 16.97:1 | ✓ |
108
+ | tho · clay | link on raised cream (body) | #201300 / #FBF4E9 | 16.65:1 | ✓ |
109
+ | tho · clay | link on dark panel (body) | #E4CDA8 / #221710 | 11.35:1 | ✓ |
110
+ | hoa | link on white (body) | #A15E43 / #FFFFFF | 5.00:1 | ✓ |
111
+ | hoa | link on element page (body) | #A15E43 / #FFFDF8 | 4.92:1 | ✓ |
112
+ | hoa | link on tint (body) | #A15E43 / #FFF4F0 | 4.63:1 | ✓ |
113
+ | hoa | link on raised cream (body) | #A15E43 / #FBF4E9 | 4.58:1 | ✓ |
114
+ | hoa | link on dark panel (body) | #FED3C3 / #221710 | 12.79:1 | ✓ |
115
+ | hoa · plasma | link on white (body) | #846B64 / #FFFFFF | 4.92:1 | ✓ |
116
+ | hoa · plasma | link on element page (body) | #846B64 / #FFFDF8 | 4.84:1 | ✓ |
117
+ | hoa · plasma | link on tint (body) | #846B64 / #FEF4F2 | 4.55:1 | ✓ |
118
+ | hoa · plasma | link on raised cream (body) | #846B64 / #FBF4E9 | 4.50:1 | ✓ |
119
+ | hoa · plasma | link on dark panel (body) | #FCE6DF / #221710 | 14.63:1 | ✓ |
120
+ | hoa · lava | link on white (body) | #280D00 / #FFFFFF | 18.30:1 | ✓ |
121
+ | hoa · lava | link on element page (body) | #280D00 / #FFFDF8 | 18.00:1 | ✓ |
122
+ | hoa · lava | link on tint (body) | #280D00 / #FFF4EF | 16.94:1 | ✓ |
123
+ | hoa · lava | link on raised cream (body) | #280D00 / #FBF4E9 | 16.74:1 | ✓ |
124
+ | hoa · lava | link on dark panel (body) | #F8C4AA / #221710 | 11.24:1 | ✓ |
125
+ | thuy | link on white (body) | #027B8B / #FFFFFF | 4.99:1 | ✓ |
126
+ | thuy | link on element page (body) | #027B8B / #FFFDF8 | 4.91:1 | ✓ |
127
+ | thuy | link on tint (body) | #027B8B / #E7FBFF | 4.67:1 | ✓ |
128
+ | thuy | link on raised cream (body) | #027B8B / #FBF4E9 | 4.57:1 | ✓ |
129
+ | thuy | link on dark panel (body) | #99EEFF / #221710 | 13.38:1 | ✓ |
130
+ | thuy · mist | link on white (body) | #48787E / #FFFFFF | 4.93:1 | ✓ |
131
+ | thuy · mist | link on element page (body) | #48787E / #FFFDF8 | 4.85:1 | ✓ |
132
+ | thuy · mist | link on tint (body) | #48787E / #EBFAFC | 4.60:1 | ✓ |
133
+ | thuy · mist | link on raised cream (body) | #48787E / #FBF4E9 | 4.51:1 | ✓ |
134
+ | thuy · mist | link on dark panel (body) | #CDF4F9 / #221710 | 14.94:1 | ✓ |
135
+ | thuy · ocean | link on white (body) | #011A21 / #FFFFFF | 17.93:1 | ✓ |
136
+ | thuy · ocean | link on element page (body) | #011A21 / #FFFDF8 | 17.64:1 | ✓ |
137
+ | thuy · ocean | link on tint (body) | #011A21 / #EAFAFF | 16.75:1 | ✓ |
138
+ | thuy · ocean | link on raised cream (body) | #011A21 / #FBF4E9 | 16.41:1 | ✓ |
139
+ | thuy · ocean | link on dark panel (body) | #ABD6E3 / #221710 | 11.23:1 | ✓ |
140
+ | moc | link on white (body) | #517B13 / #FFFFFF | 5.01:1 | ✓ |
141
+ | moc | link on element page (body) | #517B13 / #FFFDF8 | 4.93:1 | ✓ |
142
+ | moc | link on tint (body) | #517B13 / #EFFCE3 | 4.70:1 | ✓ |
143
+ | moc | link on raised cream (body) | #517B13 / #FBF4E9 | 4.58:1 | ✓ |
144
+ | moc | link on dark panel (body) | #C5ED9C / #221710 | 13.33:1 | ✓ |
145
+ | moc · bamboo | link on white (body) | #687451 / #FFFFFF | 4.99:1 | ✓ |
146
+ | moc · bamboo | link on element page (body) | #687451 / #FFFDF8 | 4.91:1 | ✓ |
147
+ | moc · bamboo | link on tint (body) | #687451 / #F4F9ED | 4.67:1 | ✓ |
148
+ | moc · bamboo | link on raised cream (body) | #687451 / #FBF4E9 | 4.57:1 | ✓ |
149
+ | moc · bamboo | link on dark panel (body) | #E5F1D2 / #221710 | 14.89:1 | ✓ |
150
+ | moc · forest | link on white (body) | #051D00 / #FFFFFF | 17.76:1 | ✓ |
151
+ | moc · forest | link on element page (body) | #051D00 / #FFFDF8 | 17.47:1 | ✓ |
152
+ | moc · forest | link on tint (body) | #051D00 / #ECFDE7 | 16.72:1 | ✓ |
153
+ | moc · forest | link on raised cream (body) | #051D00 / #FBF4E9 | 16.26:1 | ✓ |
154
+ | moc · forest | link on dark panel (body) | #B0D8A3 / #221710 | 11.02:1 | ✓ |
155
+ | kim | link on white (body) | #966700 / #FFFFFF | 4.96:1 | ✓ |
156
+ | kim | link on element page (body) | #966700 / #FFFDF8 | 4.88:1 | ✓ |
157
+ | kim | link on tint (body) | #966700 / #FFF5E7 | 4.59:1 | ✓ |
158
+ | kim | link on raised cream (body) | #966700 / #FBF4E9 | 4.54:1 | ✓ |
159
+ | kim | link on dark panel (body) | #FDD89F / #221710 | 12.94:1 | ✓ |
160
+ | kim · titanium | link on white (body) | #826D54 / #FFFFFF | 4.92:1 | ✓ |
161
+ | kim · titanium | link on element page (body) | #826D54 / #FFFDF8 | 4.84:1 | ✓ |
162
+ | kim · titanium | link on tint (body) | #826D54 / #FDF5ED | 4.56:1 | ✓ |
163
+ | kim · titanium | link on raised cream (body) | #826D54 / #FBF4E9 | 4.51:1 | ✓ |
164
+ | kim · titanium | link on dark panel (body) | #FBE8D2 / #221710 | 14.67:1 | ✓ |
165
+ | kim · steel | link on white (body) | #1F1400 / #FFFFFF | 18.13:1 | ✓ |
166
+ | kim · steel | link on element page (body) | #1F1400 / #FFFDF8 | 17.83:1 | ✓ |
167
+ | kim · steel | link on tint (body) | #1F1400 / #FEF6E7 | 16.88:1 | ✓ |
168
+ | kim · steel | link on raised cream (body) | #1F1400 / #FBF4E9 | 16.59:1 | ✓ |
169
+ | kim · steel | link on dark panel (body) | #DFCBA5 / #221710 | 11.04:1 | ✓ |
170
+
171
+ **Link failures: 0.**
172
+
93
173
  ## Dark pack APCA floors (gate twin)
94
174
 
95
175
  Targets match `_audit/apca-dark-preview.html`: bright ≥ 75 · accent ≥ 60 · on/strong ≥ 75 · ink-on-tint ≥ 75.
@@ -1,6 +1,6 @@
1
1
  # Conventions — authoring the CyberSkill DS
2
2
 
3
- For humans and agents *extending this system*. (Consumers: read `SKILL.md`.) The compiler is the source of truth for counts; prose describes shape, never numbers.
3
+ For humans and agents *extending this system*. (Consumers: read `SKILL.md`.) Expansion and verification doctrine: `docs/doctrine.md`. The compiler is the source of truth for counts; prose describes shape, never numbers. Published on Storybook **Docs** at `design.cyberskill.world`.
4
4
 
5
5
  ## The expansion rule
6
6
 
@@ -16,7 +16,7 @@ Every rendered surface resolves four orthogonal scopes — never encode one axis
16
16
  | **Language** | `lang` / Language tweak | EN · VI copy | component registry + template props |
17
17
  | **Style** | `data-cs-style` (optional; absent ≡ `liquid-glass`) | surface material pack | `tokens/styles.css` |
18
18
 
19
- Style’s sole pack today is **liquid-glass**. Immutable under all axes: Umber/Ochre anchors, voice, type families, semantic status colors, the 3px Ochre focus ring, APCA floors, ≥44px targets.
19
+ Style’s sole pack today is **liquid-glass**. Immutable under all axes: Umber/Ochre anchors, voice, type families, semantic status colors, the composite focus indicator (text-primary contour + ochre halo), APCA floors, ≥44px targets.
20
20
 
21
21
  ## Naming grammar
22
22
 
@@ -32,7 +32,7 @@ Style’s sole pack today is **liquid-glass**. Immutable under all axes: Umber/O
32
32
 
33
33
  **New component** — `Name.jsx` + `Name.d.ts` + `Name.prompt.md` in `components/<group>/`; add to the group's card html (resolve the bundle namespace **by prefix** — `const CS = window[Object.keys(window).find(k=>/^CyberSkillDesignSystem_[0-9a-f]{6}$/.test(k))]` — never a hardcoded `…_<projectId>` suffix); add to readme's group line. Consume tokens only; no hex literals except inside `tokens/`.
34
34
 
35
- **Responsive** — reflow is global (`base/responsive.css`, loaded last): media never overflows, print docs relax padding, `.cs-sheet` tables scroll, `.cs-sidebar` collapses, inline fixed-column grids collapse (3+→2 tablet, →1 phone), unbreakable long tokens (write-on `______` lines, long URLs/IDs) get `overflow-wrap: anywhere` on doc surfaces so they can't prop a phone column open, the app-shell shell grid collapses to one column with `main{min-width:0}`+`.cs-table-wrap` scroll, and fixed-geometry export canvases (`class="cs-canvas-desk"`: decks, social) **always** `overflow-x:auto` so a slide wider than the window scrolls inside the desk rather than pushing the page wide. Verified whole-set at 390 by `_audit/responsive-overflow.html` (all 84 = 0 document overflow). **Two hard gotchas:** (1) the DC runtime compiles inline `style="…"` into React objects, so the rendered attribute is *spaced* — any `[style*=…]` responsive selector must match `grid-template-columns: repeat(4, 1fr)` (colon-space, comma-space), never the authored no-space form; (2) a global CSS rule can only override a property the template sets **inline** via an **attribute** selector (`[style*="grid-template-columns: 248px 1fr"]`) — a **class** selector loses to the inline style. Prefer fixing overflow in the template source (add `min-width:0`, `flex-wrap:wrap` inline) over fighting inline from the stylesheet.
35
+ **Responsive** — reflow is global (`base/responsive.css`, loaded last): media never overflows, print docs relax padding, `.cs-sheet` tables scroll, `.cs-sidebar` collapses, inline fixed-column grids collapse (3+→2 tablet, →1 phone), unbreakable long tokens (write-on `______` lines, long URLs/IDs) get `overflow-wrap: anywhere` on doc surfaces so they can't prop a phone column open, the app-shell shell grid collapses to one column with `main{min-width:0}`+`.cs-table-wrap` scroll, and fixed-geometry export canvases (`class="cs-canvas-desk"`: decks, social) **always** `overflow-x:auto` so a slide wider than the window scrolls inside the desk rather than pushing the page wide. **Width stops must match the token scale** in `tokens/spacing.css` (`xs` · `phone` 360 · `sm` 640 · `md` 768 · `lg` 1024 · `xl` 1280 · `2xl` 1536) — `docs-consistency` fails off-scale `@media`/`@container` widths in `base/` (FIND-007). Verified whole-set at 390 by `_audit/responsive-overflow.html` (all 84 = 0 document overflow). **Two hard gotchas:** (1) the DC runtime compiles inline `style="…"` into React objects, so the rendered attribute is *spaced* — any `[style*=…]` responsive selector must match `grid-template-columns: repeat(4, 1fr)` (colon-space, comma-space), never the authored no-space form; (2) a global CSS rule can only override a property the template sets **inline** via an **attribute** selector (`[style*="grid-template-columns: 248px 1fr"]`) — a **class** selector loses to the inline style. Prefer fixing overflow in the template source (add `min-width:0`, `flex-wrap:wrap` inline) over fighting inline from the stylesheet.
36
36
 
37
37
  **New template** — `templates/<slug>/<Slug>.dc.html` with `<!-- @template name description -->` first; `ds-base.js` stays single-entry (`styles.css` only — the one-line rebind was validated end-to-end Jul 2026 from a deeper path; the test scaffold has since been removed) and publishes the id-independent `window.CyberSkillDS` alias on bundle load, so mount DS components via `component-from-global-scope="CyberSkillDS.…"` — **never** a hardcoded `CyberSkillDesignSystem_<projectId>` suffix (it changes on re-import; enforced by `_audit/namespace-portability.html`); inline styles only; 1–3 tweaks (never plain copy/color — in-place editing covers those); printable docs add the `@page` + `.cs-desk`/`.cs-sheet` print block and carry **no dark tweak** (print is light-only).
38
38
 
@@ -52,7 +52,7 @@ Style’s sole pack today is **liquid-glass**. Immutable under all axes: Umber/O
52
52
 
53
53
  - **The display face is a token role, not a second default (Jul 2026).** `--cs-font-family-display` ships Space Grotesk (variable 300–700, Vietnamese subset) self-hosted alongside Be Vietnam Pro and JetBrains Mono, so a product with a headline face — `cyberskill.world` / Lumi — consumes a DS role instead of maintaining its own `@font-face` exception. **Nothing in the DS points at it**: `--cs-heading-family` still resolves to `--cs-font-family-ui`, every template and UI kit is unchanged, and a scope opts in with `.cs-display-face` (`base/typography.css`), which retargets `--cs-heading-family` only — body copy stays on the UI face. Space Grotesk has no 800, so the extrabold heading weight clamps to 700 within that family (CSS does not hop to Be Vietnam Pro for a missing weight). Adding a family means adding its faces to `tokens/fonts.css` **and** its files to `fonts/` **and** its entries to `_ds_manifest.json` `fonts[]`/`brandFonts[]` — `_audit/font-face-integrity.html` fails on any of the three being out of step, and on any family missing the Vietnamese subset. This changes no product → element mapping; `docs/products.md` stays locked.
54
54
 
55
- - Language variants render **fully separated**: switching the Language tweak yields a complete single-language artifact — no partial translation left in headings, labels, helper text, footers, or body. The only bilingual-by-design elements are the CyberSkill name + slogan lockup (`Hiện Thực Hoá Ý Chí · Turn Your Will Into Real`, the canonical form — never a lone half) and the A4 legal identity block (company legal name + state motto). Everything else swaps with the tweak (Jul 2026).
55
+ - Language variants render **fully separated**: switching the Language tweak yields a complete single-language artifact — no partial translation left in headings, labels, helper text, footers, or body. The only bilingual-by-design elements are the CyberSkill name + slogan lockup (`Hiện Thực Hoá Ý Chí · Turn Your Will Into Real`, the canonical form — never a lone half) and the A4 legal identity block (company legal name + state motto). Everything else swaps with the tweak — including skip links and doc-type eyebrows (FIND-125). Catalog `<title>` / `@template name` strings stay English for the template index and are not language-mode chrome; `_audit/template-lang-parity.html` masks them when scanning the EN-leak lexicon (Jul 2026; FIND-125 follow-up).
56
56
 
57
57
  - **Namespace is resolved, never hardcoded** — the compiler names the bundle global `window.CyberSkillDesignSystem_<projectId>`, and that 6-hex suffix is derived from the project id, so it changes whenever the system is imported into another project. Templates read the stable `window.CyberSkillDS` alias that `ds-base.js` publishes on bundle load; cards, UI-kit pages, the standalone email, and audit harnesses resolve by prefix (`window[Object.keys(window).find(k=>/^CyberSkillDesignSystem_[0-9a-f]{6}$/.test(k))]`). `_ds_bundle.js`/`_ds_manifest.json` and the frozen `_audit/exports/` snapshot legitimately carry the real suffix (they *define* it). Enforced by `_audit/namespace-portability.html`, which scans every manifest-indexed source — keeps re-import **zero-touch** (Jul 2026).
58
58
 
@@ -70,9 +70,22 @@ Every template exports; the right path depends on the archetype. All paths prese
70
70
 
71
71
  **Font behavior on export.** Brand fonts are self-hosted (`Be Vietnam Pro` UI, `Space Grotesk` opt-in display, mono). PPTX keeps the brand-font **names** but does not embed the files — on a machine without them PowerPoint substitutes a fallback (VN Unicode text is preserved; shapes may reflow slightly). For a fully self-contained hand-off, either tell the recipient to install the fonts, or export with a web-safe swap (`fontSwaps:[{from:'Be Vietnam Pro',to:'Arial'}]` — Arial covers Vietnamese). Standalone HTML **embeds** the fonts (inlined `@font-face` from `styles.css`), so it is always faithful offline (Jul 2026).
72
72
 
73
+ ## Async data states (FIND-020 — thin pattern)
74
+
75
+ Collection surfaces that own a fetch must distinguish **loading · error · empty · idle-with-data**. Do not render the empty message while a request is in flight.
76
+
77
+ | State | Compose | Notes |
78
+ |---|---|---|
79
+ | **loading** | `Skeleton` (table rows / lines) + polite status text | `aria-busy` on the region; keep column headers when possible |
80
+ | **error** | `Result status="error"` (or a custom `errorState`) | `role="alert"`; offer retry in the host |
81
+ | **empty** | `emptyState` / `EmptyState` | Only after a successful idle response with zero rows |
82
+ | **idle** | Normal rows | Default — omit `state` for static specimens |
83
+
84
+ **Reference API:** `DataTable` accepts `state?: "idle" \| "loading" \| "error"` plus optional `loadingState` / `errorState` / `loadingRows`. Other collection components (`DataGrid`, `TreeTable`, …) should follow the same triad when they gain async ownership — do not invent a parallel loading API per surface. Long operations that are not tabular still use `Spinner` (`role="status"`) or `ProgressBar` with a real `aria-label`; pair decorative `Skeleton` (`aria-hidden`) with a live status string.
85
+
73
86
  ## Accessibility (base/a11y.css + component ARIA)
74
87
 
75
- - **Focus rings are systematic** — global `:where(:focus-visible)` ochre ring in `base/reset.css`, plus per-component 3px ochre rings (`components/forms/navigation/controls`). Never set `outline: none` on a `:focus-visible` state without replacing the ring (the menu-item regression, fixed Jul 2026). The soft 5px glow in `interaction.css` layers on the 3px ring, never replaces it.
88
+ - **Focus rings are systematic** — global `:where(:focus-visible)` in `base/reset.css` is a **composite** indicator: 2px `text-primary` contour (≥3:1 non-text contrast on light and dark) plus a 5px ochre brand halo. Wrapper controls (`SearchField`, `NumberField`, `PromptInput`, `Terminal`, `CommandPalette`) mirror that via `:focus-within`. Never set `outline: none` on a focusable control without a paired wrapper/replacement ring.
76
89
 
77
90
  - **Touch targets** — `base/a11y.css` guarantees 44px on `@media (pointer: coarse)` (tabs, pagination, menu items, stepper, checkbox/radio; segmented 40px in its padded track). Desktop mouse density is preserved. `pointer: coarse` is used deliberately over a width breakpoint — a touch laptop at 1280px still needs 44px. Button carries its own coarse block in `components.css`.
78
91
 
package/docs/decisions.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Decisions (maintainer)
2
2
 
3
- Owner choices that shape CI, Figma sync, and distribution. How-tos live in `docs/figma.md` and `docs/ci-cd.md` — this file is the decision record only. Not a consumer guide.
3
+ Owner choices that shape CI, Figma sync, and distribution. How-tos live in `docs/figma.md` and `docs/ci-cd.md` — this file is the decision record only. Not a consumer guide. Published on Storybook **Docs** at `design.cyberskill.world`.
4
4
 
5
5
  ## 1. Whole-set audits on every PR
6
6
 
@@ -53,7 +53,7 @@ Stay on the current Figma plan. Variables REST API is Enterprise-only — write
53
53
  **Status: LAUNCHED `@cyberskill/design@1.1.0`; pin tracks `VERSION` (auto-bump on main since Aug 2026); CI publish uses npm Trusted Publishing; tokens disallowed** (Jul 2026; LAUNCH 2026-07-27)
54
54
 
55
55
  - `package.json` is `private: false`; package name **`@cyberskill/design`** (`publishConfig.access: public`); `repository.url` matches this GitHub repo for provenance.
56
- - Workflow `.github/workflows/npm-publish.yml`: `id-token: write` + GitHub-hosted runner; **no** `NPM_TOKEN` / `NODE_AUTH_TOKEN` on the publish step (OIDC). npm Trusted Publisher must list workflow filename **`npm-publish.yml`** for `cyberskill-official/design-system`. Soft-skip on auth / 403 / 404 / EOTP / version conflict.
56
+ - Workflow `.github/workflows/npm-publish.yml`: `id-token: write` + GitHub-hosted runner; **no** `NPM_TOKEN` / `NODE_AUTH_TOKEN` on the publish step (OIDC). npm Trusted Publisher must list workflow filename **`npm-publish.yml`** for `cyberskill-official/design` (FIND-088). Soft-skip only for expected no-ops (`already_published` / EPUBLISHCONFLICT, and true non-GHA `missing_secrets`). On GHA tag / `workflow_dispatch`, **ENEEDAUTH** / **404** / **402** / **403** / **EOTP** fail the job; a successful publish is gated by post-publish `npm view @cyberskill/design@VERSION` **and** `dist-tags.latest === VERSION` (FIND-020 / FIND-094).
57
57
  - Package **Publishing access** on npmjs: **Require two-factor authentication and disallow tokens** (OIDC Trusted Publishing still works; classic / granular publish tokens are rejected). Long-lived `NPM_TOKEN` secrets are revoked.
58
58
  - License stays **UNLICENSED**; version tracks root `VERSION`. Approved use is recorded in **`docs/consumer-grant.md`** (CyberSkill portfolio products). Registry install alone is not a public license.
59
59
 
@@ -100,7 +100,7 @@ Operational follow-ups — not product marketing, not a backlog surface:
100
100
 
101
101
  ~~4. First registry consumer path~~ — **done** (Jul 2026): `examples/npm-hello/` installs `@cyberskill/design` for locked **Lumi** identity; documented in `docs/consuming.md` (+ VI) and `docs/release-notes.md`. Pin follows repo `VERSION`.
102
102
 
103
- 5. **Native + element-pack drift on PRs is fail-closed** (Jul 2026) — `regenerate-tokens` runs read-only on pull requests and exits 1 instead of pushing; only `regenerate-tokens-push` (main / schedule / manual) holds `contents: write`. When a PR fails it, run `npm run tokens:elements && node _audit/ci/generate-native-tokens.mjs` and commit packs + natives. See `docs/ci-cd.md`.
103
+ 5. **Native + element-pack drift on PRs is fail-closed** (Jul 2026; FIND-021 re-gate Aug 2026) — `regenerate-tokens` runs read-only on pull requests and exits 1 instead of pushing; only `regenerate-tokens-push` (main / schedule / manual) holds `contents: write`. When a PR fails it, run `npm run tokens:elements && node _audit/ci/generate-native-tokens.mjs` and commit packs + natives. Auto-commits from `regenerate-tokens-push` **must not** use `[skip ci]` so the tip re-enters the gate board (TASK-IMP-008); PR fail-closed freshness remains the primary contributor path. Branch-protection required-check reality is NV-18.1 (out-of-band). See `docs/ci-cd.md`.
104
104
 
105
105
  6. **Shadcn gap / Wave 2** (Jul 2026) — CyberSkill already covers ~53 of shadcn’s 62 primitives as CS-native (forms / overlays / nav / data). Shipped: pilot `ScrollArea`, `Collapsible`, `AspectRatio`; Wave 2 `AlertDialog` (vs Popconfirm), `Item` row primitive, `NativeSelect`. Residual shadcn gaps are intentional non-ports (blocks, Tailwind, Radix CLI). Do **not** port those — map patterns to existing `templates/` + `ui_kits/`.
106
106
 
@@ -112,6 +112,44 @@ Operational follow-ups — not product marketing, not a backlog surface:
112
112
 
113
113
  Storybook `FullMatrix` is required whenever a public primary has ≥1 of {size enums, variant enums, state keys} (contract floor ≥28 stories). Schema sidecars remain complete for content-hole templates; axis-only templates omit by design. See `docs/quality-gates.md` and `docs/storybook.md`.
114
114
 
115
+ ## 11. Audit paper trails — archive, do not delete
116
+
117
+ **Owner choice: archive-don't-delete** (Aug 2026; TASK-IMP-001 / assessment FIND-001)
118
+
119
+ - Closed UX / AT / quality-audit artifacts MUST remain reconstructable from a fresh clone. Prefer `_audit/archive/` and/or `docs/audits/` over silent deletion.
120
+ - Commit `8646dbf` deleted the Aug-8 UX audit plan, AT matrix, archive README, and `TASK-UX-AUDIT-20260808` “with no permanent record.” Those bodies are restored under `docs/audits/ux-audit-2026-08-08/` (plus `_audit/archive/ux-audit-2026-08-08/` pointer). Historical D1–D6 operator choices that drove that remediation stay in the restored plan; they do **not** authorize future deletion of audit trails.
121
+ - Status-feed / ledger edits that hide completed audit work are discouraged; if a commit must be ledger-exempted, record the exemption and the archived path in the same change.
122
+ - Claims that need provenance (e.g. “AT complete”, “lawyer-validated”) require a dated in-tree record or an explicit decision entry — not oral attestation alone.
123
+
124
+ ## 12. 12-month evolution plan — adoption status
125
+
126
+ **Owner choice: partially superseded (near-term); plan retained as long-horizon reference** (Aug 2026; TASK-IMP-001 / assessment FIND-002)
127
+
128
+ Source: `docs/plans/cyberskill-design-system-audit-and-12-month-evolution-plan.md` (audit date 2026-07-28). A prior `task-author` PLAN for that document was approved (manifest `docs/tasks/.workflow/task-author.design-system-evolution.manifest.json`) but most artefacts were never landed in `docs/tasks/`.
129
+
130
+ | Horizon | Status | Notes |
131
+ |---------|--------|-------|
132
+ | Assessment Phases 0–3 | **Adopted** (HITL 2026-08-09) | `TASK-IMP-001`…`TASK-IMP-012` |
133
+ | Assessment Phases 4–5 | **Implemented → ready_to_review** | `TASK-IMP-013`…`TASK-IMP-020` |
134
+ | Full 12-month plan phases 0–6 task materialization | **Deferred** | Do not auto-expand the pending manifest artefacts until operator triages against tip `1.2.1` / post-assessment state |
135
+ | Items already shipped outside backlog (e.g. Aug-8 UX remediation commits) | **Superseded as live tasks** | Evidence lives in `docs/audits/ux-audit-2026-08-08/` + git history; do not re-open as duplicate ready work without a fresh finding |
136
+
137
+ Phases 3–5 of the **assessment** roadmap are authored as `TASK-IMP-009`…`020`; Phase 3 accepted HITL 2026-08-09; Phases 4–5 await final HITL at `ready_to_review`.
138
+
139
+ ## 13. Product vs CyberOS boundary
140
+
141
+ **Owner choice: explicit fence** (Aug 2026; assessment area 28 / TASK-IMP-020)
142
+
143
+ | Layer | Ships to consumers? | Lives where | Purpose |
144
+ |-------|---------------------|-------------|---------|
145
+ | **Product design system** | Yes — `@cyberskill/design`, portable tree (`styles.css`, `tokens/`, `components/`, `templates/`, `_audit/` gates, Storybook host) | repo root (non-`.cyberos`) | Tokens, components, templates, kits, deterministic quality gates |
146
+ | **CyberOS orchestration** | No (gitignored / installable agent kit) | `.cyberos/`, `docs/tasks/`, BRAIN under `.cyberos/memory/` | Task lifecycle, HITL gates, agent entry, ship-tasks workflow |
147
+
148
+ Rules:
149
+ - Product acceptance criteria must not require `.cyberos/` to be present for consumers or for `npm` publish.
150
+ - Agents operating this repo follow `.cyberos/AGENT-ENTRY.md`; humans shipping the DS follow `docs/release-runbook.md`.
151
+ - Do not move product tokens/components into `.cyberos/`; do not publish CyberOS orchestration as part of the npm package.
152
+
115
153
  ## How to change a decision
116
154
 
117
155
  Edit the **Owner choice** line here. Implementer rewires CI and related docs in the same change.
package/docs/deploy.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Deploying the live Atomic site (Vercel / VPS / any static host)
2
2
 
3
+ Published on Storybook **Docs** at `design.cyberskill.world`.
4
+
3
5
  Two tracks:
4
6
 
5
7
  1. **Portable design system (consumers)** — still a static file tree: no bundler required. Link `styles.css` + optionally `_ds_bundle.js` / ESM. Claude Design, Google Stitch, and product apps never need Node or Storybook.
@@ -48,11 +50,15 @@ If you host under a **different** domain, change the absolute URLs in those meta
48
50
 
49
51
  **With Storybook at `/`:** run `npm run build:site` on the host or CI, then serve `.vercel-static/` as the webroot. Configure the same redirects as `vercel.json` (`/dashboard`, `/dashboard/`, `/dashboard.html`, `/dashboard/:path*`, `/playground`, `/playground/`, `/playground/:path*` → `/`) if your host supports them.
50
52
 
51
- Nginx example (`.vercel-static` as `root`):
53
+ Nginx example (`.vercel-static` as `root`) — **same security headers as `vercel.json`** (FIND-019):
54
+ ```nginx
52
55
  server {
53
56
  server_name design.cyberskill.world;
54
57
  root /var/www/design-system/.vercel-static;
55
58
  index index.html;
59
+ add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data: blob:; connect-src 'self'; frame-src 'self'; worker-src 'self' blob:; base-uri 'self'; form-action 'self'" always;
60
+ add_header X-Content-Type-Options "nosniff" always;
61
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
56
62
  location = /dashboard { return 301 /; }
57
63
  location = /dashboard/ { return 301 /; }
58
64
  location = /dashboard.html { return 301 /; }
@@ -60,8 +66,11 @@ server {
60
66
  location = /playground { return 301 /; }
61
67
  location /playground/ { return 301 /; }
62
68
  }
69
+ ```
63
70
  Portable paths remain real files (`guidelines/atomic-view.html`, `_audit/run.html`, `styles.css`, etc.). Storybook owns `/` and `/index.html`.
64
71
 
72
+ **Netlify / Cloudflare Pages / similar:** commit root `_headers` mirrors the same three headers for hosts that read Netlify-style `_headers` files. Keep it byte-aligned with `vercel.json`.
73
+
65
74
  ## Post-deploy checklist
66
75
  1. Open `/` — confirm Storybook loads (not a 404, directory listing, or the old dashboard shell).
67
76
  2. Open `/_audit/run.html` — let the board finish, confirm all fast gates pass on the *deployed* copy (CDN caching, MIME types, or a missed file can surface here even when local checks were clean).
@@ -86,12 +95,16 @@ After every production deploy:
86
95
 
87
96
  ## Content-Security-Policy notes
88
97
 
89
- Static hosting can ship a strict CSP. Typical allowances for this system:
90
- - `script-src 'self' https://unpkg.com` if you load React from CDN for Atomic View
91
- - `font-src 'self'`
98
+ Canonical CSP lives in `vercel.json` and is mirrored in `_headers` + the nginx snippet above (FIND-015 / FIND-019). Current policy:
99
+
100
+ `default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data: blob:; connect-src 'self'; frame-src 'self'; worker-src 'self' blob:; base-uri 'self'; form-action 'self'`
92
101
 
93
- - `img-src 'self' data:`
94
- Prefer self-hosting React next to `_ds_bundle.js` for air-gapped installs.
102
+ Rationale:
103
+ - **`unsafe-eval` removed** — React is vendored locally; Storybook static export does not need site-wide `eval`.
104
+ - **CDN script/connect origins removed** (`unpkg.com`, `cdnjs.cloudflare.com`) — local-first React / `_ds_bundle.js`.
105
+ - **`unsafe-inline` retained** — Storybook’s static shell still emits inline scripts/styles; a nonce/hash migration is a follow-on. Do not re-add open CDN allowlists without pinning.
106
+ - Prefer self-hosting React next to `_ds_bundle.js` for air-gapped installs.
107
+ - Live served-header truth confirmed 2026-08-09 via operator `curl -sSI https://design.cyberskill.world/` (OQ-003 closed — see `docs/audits/nv-rendered-inrepo-2026-08-09.md`).
95
108
 
96
109
  ## Multi-domain OG
97
110
 
@@ -1,6 +1,6 @@
1
1
  # Design styles
2
2
 
3
- The live styling axes are **Theme × Element × Language × Style**. Style’s sole pack today is **liquid-glass** (absent `data-cs-style` ≡ liquid-glass — same default pattern as light theme / Thổ middle).
3
+ The live styling axes are **Theme × Element × Language × Style**. Style’s sole pack today is **liquid-glass** (absent `data-cs-style` ≡ liquid-glass — same default pattern as light theme / Thổ middle). Published on Storybook **Docs** at `design.cyberskill.world`.
4
4
 
5
5
  | Axis | How to set it | What it changes |
6
6
  |---|---|---|
@@ -21,7 +21,7 @@ Source of truth: [`tokens/element-seeds.json`](../tokens/element-seeds.json) →
21
21
  | **Character offsets** | Small explicit `dh`/`dc` in the seed file only (e.g. Hỏa·plasma, Kim·steel) — not freehand drift |
22
22
  | **Light ↔ dark** | Same hue family (Δh locked); roles remapped + APCA-solved — 15 × 2 = **30 colour sets** |
23
23
  | **Text rule** | Text on `-bright` or `-tint` only — never on mid-tone `-accent` |
24
- | **Never remap** | `--cs-color-accent-ochre` focus ring · semantic status colours |
24
+ | **Never remap** | composite focus indicator (text-primary contour + ochre halo) · semantic status colours |
25
25
  | **Geometry gate** | [`_audit/element-geometry.html`](../_audit/element-geometry.html) — intensity sync · variant distinctness · hue identity |
26
26
 
27
27
  ## Style pack — liquid-glass