@cyberskill/design 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/DESIGN.md +25 -3
  2. package/README.md +3 -3
  3. package/SKILL.md +3 -3
  4. package/VERSION +1 -1
  5. package/_ds_bundle.js +819 -416
  6. package/_ds_manifest.json +1 -1
  7. package/_esm/cs.mjs +18 -4
  8. package/_esm/react.d.ts +2 -0
  9. package/_esm/react.mjs +1 -0
  10. package/base/a11y.css +18 -0
  11. package/base/ai.css +2 -2
  12. package/base/collections.css +8 -3
  13. package/base/components.css +11 -2
  14. package/base/controls.css +61 -48
  15. package/base/data.css +3 -3
  16. package/base/feedback.css +5 -0
  17. package/base/forms.css +9 -3
  18. package/base/glass.css +6 -0
  19. package/base/navigation.css +8 -2
  20. package/base/reset.css +1 -1
  21. package/base/responsive.css +25 -0
  22. package/base/shell.css +7 -1
  23. package/components/_i18n/i18n.js +13 -1
  24. package/components/_i18n/strings.js +52 -3
  25. package/components/ai/ConfidenceMeter.jsx +8 -6
  26. package/components/data/Watermark.jsx +11 -3
  27. package/components/datatable/DataGrid.jsx +10 -1
  28. package/components/dialog/Dialog.jsx +13 -45
  29. package/components/feedback/ProgressBar.jsx +4 -2
  30. package/components/forms/Cascader.jsx +69 -6
  31. package/components/forms/Editor.jsx +37 -2
  32. package/components/forms/FileUpload.jsx +22 -8
  33. package/components/forms/Switch.jsx +16 -2
  34. package/components/forms/TimePicker.jsx +3 -1
  35. package/components/icon/Icon.jsx +1 -0
  36. package/components/navigation/CommandPalette.jsx +22 -7
  37. package/components/navigation/Toolbar.jsx +2 -1
  38. package/components/overlays/AlertDialog.jsx +19 -49
  39. package/components/overlays/Drawer.jsx +24 -20
  40. package/components/overlays/OverlayManager.d.ts +40 -0
  41. package/components/overlays/OverlayManager.jsx +214 -0
  42. package/components/overlays/OverlayManager.prompt.md +12 -0
  43. package/components/overlays/Tour.jsx +14 -7
  44. package/dist/styles.min.css +2004 -0
  45. package/docs/benchmark-rubric.md +1 -1
  46. package/docs/ci-cd.md +3 -1
  47. package/docs/consuming.md +6 -6
  48. package/docs/conventions.md +4 -4
  49. package/docs/decisions/container-query-migration.md +18 -0
  50. package/docs/decisions/overlay-manager-design.md +101 -0
  51. package/docs/decisions.md +5 -5
  52. package/docs/design-styles.md +1 -1
  53. package/docs/plans/cyberskill-design-system-audit-and-12-month-evolution-plan.md +1490 -0
  54. package/docs/quality-gates.md +20 -8
  55. package/docs/release-notes.md +2 -2
  56. package/docs/status/data/status-feed.json +1 -1
  57. package/docs/status/index.html +9 -5
  58. package/docs/status/status-legacy.html +12 -7
  59. package/docs/sync.md +1 -1
  60. package/docs/tasks/_state/commit-links.yaml +14 -0
  61. package/docs/vi/benchmark-rubric.md +1 -1
  62. package/docs/vi/ci-cd.md +3 -1
  63. package/docs/vi/consuming.md +6 -6
  64. package/docs/vi/conventions.md +2 -2
  65. package/docs/vi/decisions.md +4 -4
  66. package/docs/vi/quality-gates.md +21 -9
  67. package/docs/vi/release-notes.md +2 -2
  68. package/docs/vi/sync.md +1 -1
  69. package/guidelines/atomic-view.html +11 -7
  70. package/llms.txt +2 -2
  71. package/package.json +14 -6
  72. package/templates/_ds-base.canonical.js +55 -0
  73. package/templates/ai-cluster-demo.html +2 -2
  74. package/templates/app-shell/AppShell.dc.html +5 -3
  75. package/templates/app-shell/ds-base.js +33 -1
  76. package/templates/app-shell/support.js +13 -20
  77. package/templates/article/Article.dc.html +5 -1
  78. package/templates/article/ds-base.js +33 -1
  79. package/templates/article/support.js +13 -20
  80. package/templates/auth/Auth.dc.html +10 -5
  81. package/templates/auth/content-schema.json +12 -0
  82. package/templates/auth/ds-base.js +33 -1
  83. package/templates/auth/support.js +13 -20
  84. package/templates/bod-deck/BodDeck.dc.html +11 -10
  85. package/templates/bod-deck/ds-base.js +33 -1
  86. package/templates/bod-deck/support.js +13 -20
  87. package/templates/bod-investor-update/BodInvestorUpdate.dc.html +4 -3
  88. package/templates/bod-investor-update/ds-base.js +33 -1
  89. package/templates/bod-investor-update/support.js +13 -20
  90. package/templates/bod-memo/BodMemo.dc.html +6 -5
  91. package/templates/bod-memo/ds-base.js +33 -1
  92. package/templates/bod-memo/support.js +13 -20
  93. package/templates/bod-minutes/BodMinutes.dc.html +2 -1
  94. package/templates/bod-minutes/ds-base.js +33 -1
  95. package/templates/bod-minutes/support.js +13 -20
  96. package/templates/bod-report/BodReport.dc.html +3 -2
  97. package/templates/bod-report/ds-base.js +33 -1
  98. package/templates/bod-report/support.js +13 -20
  99. package/templates/bod-resolution/BodResolution.dc.html +5 -4
  100. package/templates/bod-resolution/ds-base.js +33 -1
  101. package/templates/bod-resolution/support.js +13 -20
  102. package/templates/culture-event-invite/CultureEventInvite.dc.html +3 -2
  103. package/templates/culture-event-invite/ds-base.js +33 -1
  104. package/templates/culture-event-invite/support.js +13 -20
  105. package/templates/dashboard/Dashboard.dc.html +7 -3
  106. package/templates/dashboard/ds-base.js +33 -1
  107. package/templates/dashboard/support.js +13 -20
  108. package/templates/delivery-change-note/DeliveryChangeNote.dc.html +2 -1
  109. package/templates/delivery-change-note/ds-base.js +33 -1
  110. package/templates/delivery-change-note/support.js +13 -20
  111. package/templates/delivery-kickoff/DeliveryKickoff.dc.html +3 -2
  112. package/templates/delivery-kickoff/ds-base.js +33 -1
  113. package/templates/delivery-kickoff/support.js +13 -20
  114. package/templates/delivery-qbr-deck/DeliveryQbrDeck.dc.html +6 -5
  115. package/templates/delivery-qbr-deck/ds-base.js +33 -1
  116. package/templates/delivery-qbr-deck/support.js +13 -20
  117. package/templates/delivery-runbook/DeliveryRunbook.dc.html +3 -2
  118. package/templates/delivery-runbook/ds-base.js +33 -1
  119. package/templates/delivery-runbook/support.js +13 -20
  120. package/templates/delivery-status-email/DeliveryStatusEmail.dc.html +3 -2
  121. package/templates/delivery-status-email/ds-base.js +33 -1
  122. package/templates/delivery-status-email/support.js +13 -20
  123. package/templates/doc-style-guide/DocStyleGuide.dc.html +67 -64
  124. package/templates/doc-style-guide/ds-base.js +33 -1
  125. package/templates/doc-style-guide/support.js +13 -20
  126. package/templates/doc-suite-index/DocSuiteIndex.dc.html +46 -45
  127. package/templates/doc-suite-index/ds-base.js +33 -1
  128. package/templates/doc-suite-index/support.js +13 -20
  129. package/templates/doc-templates/DocTemplates.dc.html +42 -41
  130. package/templates/doc-templates/ds-base.js +33 -1
  131. package/templates/doc-templates/support.js +13 -20
  132. package/templates/email/Email.dc.html +3 -2
  133. package/templates/email/ds-base.js +33 -1
  134. package/templates/email/support.js +13 -20
  135. package/templates/finance-dunning-email/FinanceDunningEmail.dc.html +4 -3
  136. package/templates/finance-dunning-email/ds-base.js +33 -1
  137. package/templates/finance-dunning-email/support.js +13 -20
  138. package/templates/finance-expense-report/FinanceExpenseReport.dc.html +4 -3
  139. package/templates/finance-expense-report/ds-base.js +33 -1
  140. package/templates/finance-expense-report/support.js +13 -20
  141. package/templates/finance-invoice/FinanceInvoice.dc.html +4 -3
  142. package/templates/finance-invoice/ds-base.js +33 -1
  143. package/templates/finance-invoice/support.js +13 -20
  144. package/templates/finance-quote/FinanceQuote.dc.html +4 -3
  145. package/templates/finance-quote/ds-base.js +33 -1
  146. package/templates/finance-quote/support.js +13 -20
  147. package/templates/hr-announcement/HrAnnouncement.dc.html +5 -4
  148. package/templates/hr-announcement/ds-base.js +33 -1
  149. package/templates/hr-announcement/support.js +13 -20
  150. package/templates/hr-interview-kit/HrInterviewKit.dc.html +4 -3
  151. package/templates/hr-interview-kit/ds-base.js +33 -1
  152. package/templates/hr-interview-kit/support.js +13 -20
  153. package/templates/hr-offboarding/HrOffboarding.dc.html +2 -1
  154. package/templates/hr-offboarding/ds-base.js +33 -1
  155. package/templates/hr-offboarding/support.js +13 -20
  156. package/templates/hr-performance-review/HrPerformanceReview.dc.html +2 -1
  157. package/templates/hr-performance-review/ds-base.js +33 -1
  158. package/templates/hr-performance-review/support.js +13 -20
  159. package/templates/hr-pip/HrPip.dc.html +2 -1
  160. package/templates/hr-pip/ds-base.js +33 -1
  161. package/templates/hr-pip/support.js +13 -20
  162. package/templates/kitchen-sink.html +9 -4
  163. package/templates/legal-msa/LegalMsa.dc.html +2 -1
  164. package/templates/legal-msa/ds-base.js +33 -1
  165. package/templates/legal-msa/support.js +13 -20
  166. package/templates/legal-sow/LegalSow.dc.html +2 -1
  167. package/templates/legal-sow/ds-base.js +33 -1
  168. package/templates/legal-sow/support.js +13 -20
  169. package/templates/marketing-campaign-brief/MarketingCampaignBrief.dc.html +3 -2
  170. package/templates/marketing-campaign-brief/ds-base.js +33 -1
  171. package/templates/marketing-campaign-brief/support.js +13 -20
  172. package/templates/marketing-case-study/MarketingCaseStudy.dc.html +5 -4
  173. package/templates/marketing-case-study/ds-base.js +33 -1
  174. package/templates/marketing-case-study/support.js +13 -20
  175. package/templates/marketing-launch/MarketingLaunch.dc.html +6 -5
  176. package/templates/marketing-launch/ds-base.js +33 -1
  177. package/templates/marketing-launch/support.js +13 -20
  178. package/templates/marketing-newsletter/MarketingNewsletter.dc.html +13 -12
  179. package/templates/marketing-newsletter/ds-base.js +33 -1
  180. package/templates/marketing-newsletter/support.js +13 -20
  181. package/templates/marketing-page/MarketingPage.dc.html +17 -12
  182. package/templates/marketing-page/ds-base.js +33 -1
  183. package/templates/marketing-page/support.js +13 -20
  184. package/templates/marketing-press-release/MarketingPressRelease.dc.html +2 -1
  185. package/templates/marketing-press-release/ds-base.js +33 -1
  186. package/templates/marketing-press-release/support.js +13 -20
  187. package/templates/marketing-social-kit/MarketingSocialKit.dc.html +5 -4
  188. package/templates/marketing-social-kit/ds-base.js +33 -1
  189. package/templates/marketing-social-kit/support.js +13 -20
  190. package/templates/sales-one-pager/SalesOnePager.dc.html +5 -4
  191. package/templates/sales-one-pager/ds-base.js +33 -1
  192. package/templates/sales-one-pager/support.js +13 -20
  193. package/templates/sales-proposal-deck/SalesProposalDeck.dc.html +7 -6
  194. package/templates/sales-proposal-deck/ds-base.js +33 -1
  195. package/templates/sales-proposal-deck/support.js +13 -20
  196. package/templates/settings/Settings.dc.html +5 -1
  197. package/templates/settings/ds-base.js +33 -1
  198. package/templates/settings/support.js +13 -20
  199. package/templates/slide-deck/SlideDeck.dc.html +5 -4
  200. package/templates/slide-deck/ds-base.js +33 -1
  201. package/templates/slide-deck/support.js +13 -20
  202. package/templates/team-meeting-agenda/TeamMeetingAgenda.dc.html +2 -1
  203. package/templates/team-meeting-agenda/ds-base.js +33 -1
  204. package/templates/team-meeting-agenda/support.js +13 -20
  205. package/templates/tech-incident-report/TechIncidentReport.dc.html +3 -2
  206. package/templates/tech-incident-report/ds-base.js +33 -1
  207. package/templates/tech-incident-report/support.js +13 -20
  208. package/templates/tech-release-notes/TechReleaseNotes.dc.html +6 -5
  209. package/templates/tech-release-notes/ds-base.js +33 -1
  210. package/templates/tech-release-notes/support.js +13 -20
  211. package/templates/tech-retro/TechRetro.dc.html +4 -3
  212. package/templates/tech-retro/ds-base.js +33 -1
  213. package/templates/tech-retro/support.js +13 -20
  214. package/templates/tech-rfc/TechRfc.dc.html +3 -2
  215. package/templates/tech-rfc/ds-base.js +33 -1
  216. package/templates/tech-rfc/support.js +13 -20
  217. package/templates/vn-appointment-transfer/VnAppointmentTransfer.dc.html +36 -35
  218. package/templates/vn-appointment-transfer/ds-base.js +33 -1
  219. package/templates/vn-appointment-transfer/support.js +13 -20
  220. package/templates/vn-certificate-of-employment/VnCertificateOfEmployment.dc.html +27 -26
  221. package/templates/vn-certificate-of-employment/ds-base.js +33 -1
  222. package/templates/vn-certificate-of-employment/support.js +13 -20
  223. package/templates/vn-code-of-conduct/VnCodeOfConduct.dc.html +44 -43
  224. package/templates/vn-code-of-conduct/ds-base.js +33 -1
  225. package/templates/vn-code-of-conduct/support.js +13 -20
  226. package/templates/vn-compensation-regulation/VnCompensationRegulation.dc.html +53 -52
  227. package/templates/vn-compensation-regulation/ds-base.js +33 -1
  228. package/templates/vn-compensation-regulation/support.js +13 -20
  229. package/templates/vn-contract-amendment/VnContractAmendment.dc.html +41 -40
  230. package/templates/vn-contract-amendment/ds-base.js +33 -1
  231. package/templates/vn-contract-amendment/support.js +13 -20
  232. package/templates/vn-contractor-agreement/VnContractorAgreement.dc.html +50 -49
  233. package/templates/vn-contractor-agreement/ds-base.js +33 -1
  234. package/templates/vn-contractor-agreement/support.js +13 -20
  235. package/templates/vn-data-protection-policy/VnDataProtectionPolicy.dc.html +54 -53
  236. package/templates/vn-data-protection-policy/ds-base.js +33 -1
  237. package/templates/vn-data-protection-policy/support.js +13 -20
  238. package/templates/vn-disciplinary-case-file/VnDisciplinaryCaseFile.dc.html +72 -71
  239. package/templates/vn-disciplinary-case-file/ds-base.js +33 -1
  240. package/templates/vn-disciplinary-case-file/support.js +13 -20
  241. package/templates/vn-disciplinary-schedule/VnDisciplinarySchedule.dc.html +21 -20
  242. package/templates/vn-disciplinary-schedule/ds-base.js +33 -1
  243. package/templates/vn-disciplinary-schedule/support.js +13 -20
  244. package/templates/vn-employee-request/VnEmployeeRequest.dc.html +54 -53
  245. package/templates/vn-employee-request/ds-base.js +33 -1
  246. package/templates/vn-employee-request/support.js +13 -20
  247. package/templates/vn-exit-handover/VnExitHandover.dc.html +122 -121
  248. package/templates/vn-exit-handover/ds-base.js +33 -1
  249. package/templates/vn-exit-handover/support.js +13 -20
  250. package/templates/vn-foreign-employee-pack/VnForeignEmployeePack.dc.html +31 -30
  251. package/templates/vn-foreign-employee-pack/ds-base.js +33 -1
  252. package/templates/vn-foreign-employee-pack/support.js +13 -20
  253. package/templates/vn-grassroots-democracy/VnGrassrootsDemocracy.dc.html +54 -53
  254. package/templates/vn-grassroots-democracy/ds-base.js +33 -1
  255. package/templates/vn-grassroots-democracy/support.js +13 -20
  256. package/templates/vn-infosec-policy/VnInfosecPolicy.dc.html +50 -49
  257. package/templates/vn-infosec-policy/ds-base.js +33 -1
  258. package/templates/vn-infosec-policy/support.js +13 -20
  259. package/templates/vn-internal-labor-regulations/VnInternalLaborRegulations.dc.html +84 -83
  260. package/templates/vn-internal-labor-regulations/ds-base.js +33 -1
  261. package/templates/vn-internal-labor-regulations/support.js +13 -20
  262. package/templates/vn-internship-agreement/VnInternshipAgreement.dc.html +44 -43
  263. package/templates/vn-internship-agreement/ds-base.js +33 -1
  264. package/templates/vn-internship-agreement/support.js +13 -20
  265. package/templates/vn-job-description/VnJobDescription.dc.html +28 -27
  266. package/templates/vn-job-description/ds-base.js +33 -1
  267. package/templates/vn-job-description/support.js +13 -20
  268. package/templates/vn-labor-contract/VnLaborContract.dc.html +109 -108
  269. package/templates/vn-labor-contract/ds-base.js +33 -1
  270. package/templates/vn-labor-contract/support.js +13 -20
  271. package/templates/vn-labour-management-book/VnLabourManagementBook.dc.html +32 -31
  272. package/templates/vn-labour-management-book/ds-base.js +33 -1
  273. package/templates/vn-labour-management-book/support.js +13 -20
  274. package/templates/vn-mutual-nda/VnMutualNda.dc.html +45 -44
  275. package/templates/vn-mutual-nda/ds-base.js +33 -1
  276. package/templates/vn-mutual-nda/support.js +13 -20
  277. package/templates/vn-ndnca-ip/VnNdncaIp.dc.html +73 -72
  278. package/templates/vn-ndnca-ip/ds-base.js +33 -1
  279. package/templates/vn-ndnca-ip/support.js +13 -20
  280. package/templates/vn-offer-letter/VnOfferLetter.dc.html +32 -31
  281. package/templates/vn-offer-letter/ds-base.js +33 -1
  282. package/templates/vn-offer-letter/support.js +13 -20
  283. package/templates/vn-onboarding-checklist/VnOnboardingChecklist.dc.html +16 -15
  284. package/templates/vn-onboarding-checklist/ds-base.js +33 -1
  285. package/templates/vn-onboarding-checklist/support.js +13 -20
  286. package/templates/vn-pdpl-consent/VnPdplConsent.dc.html +43 -42
  287. package/templates/vn-pdpl-consent/ds-base.js +33 -1
  288. package/templates/vn-pdpl-consent/support.js +13 -20
  289. package/templates/vn-performance-evaluation-regulation/VnPerformanceEvaluationRegulation.dc.html +65 -64
  290. package/templates/vn-performance-evaluation-regulation/ds-base.js +33 -1
  291. package/templates/vn-performance-evaluation-regulation/support.js +13 -20
  292. package/templates/vn-performance-review-form/VnPerformanceReviewForm.dc.html +49 -48
  293. package/templates/vn-performance-review-form/ds-base.js +33 -1
  294. package/templates/vn-performance-review-form/support.js +13 -20
  295. package/templates/vn-phantom-stock/VnPhantomStock.dc.html +41 -40
  296. package/templates/vn-phantom-stock/ds-base.js +33 -1
  297. package/templates/vn-phantom-stock/support.js +13 -20
  298. package/templates/vn-probation-contract/VnProbationContract.dc.html +56 -55
  299. package/templates/vn-probation-contract/ds-base.js +33 -1
  300. package/templates/vn-probation-contract/support.js +13 -20
  301. package/templates/vn-receipt-acknowledgement/VnReceiptAcknowledgement.dc.html +28 -27
  302. package/templates/vn-receipt-acknowledgement/ds-base.js +33 -1
  303. package/templates/vn-receipt-acknowledgement/support.js +13 -20
  304. package/templates/vn-remote-work-policy/VnRemoteWorkPolicy.dc.html +44 -43
  305. package/templates/vn-remote-work-policy/ds-base.js +33 -1
  306. package/templates/vn-remote-work-policy/support.js +13 -20
  307. package/templates/vn-resignation-letter/VnResignationLetter.dc.html +20 -19
  308. package/templates/vn-resignation-letter/ds-base.js +33 -1
  309. package/templates/vn-resignation-letter/support.js +13 -20
  310. package/templates/vn-salary-scale/VnSalaryScale.dc.html +39 -38
  311. package/templates/vn-salary-scale/ds-base.js +33 -1
  312. package/templates/vn-salary-scale/support.js +13 -20
  313. package/templates/vn-sow-appendix/VnSowAppendix.dc.html +21 -20
  314. package/templates/vn-sow-appendix/ds-base.js +33 -1
  315. package/templates/vn-sow-appendix/support.js +13 -20
  316. package/templates/vn-termination-decision/VnTerminationDecision.dc.html +25 -24
  317. package/templates/vn-termination-decision/ds-base.js +33 -1
  318. package/templates/vn-termination-decision/support.js +13 -20
  319. package/templates/vn-total-rewards-appendix/VnTotalRewardsAppendix.dc.html +63 -62
  320. package/templates/vn-total-rewards-appendix/ds-base.js +33 -1
  321. package/templates/vn-total-rewards-appendix/support.js +13 -20
  322. package/templates/vn-training-commitment/VnTrainingCommitment.dc.html +39 -38
  323. package/templates/vn-training-commitment/ds-base.js +33 -1
  324. package/templates/vn-training-commitment/support.js +13 -20
  325. package/templates/vn-travel-expense-policy/VnTravelExpensePolicy.dc.html +50 -49
  326. package/templates/vn-travel-expense-policy/ds-base.js +33 -1
  327. package/templates/vn-travel-expense-policy/support.js +13 -20
  328. package/tokens/colors.css +19 -1
  329. package/tokens/component-tokens.css +1 -0
  330. package/tokens/elements.css +35 -2
  331. package/tokens/elevation.css +8 -2
  332. package/tokens/native/CSTokens.kt +35 -1
  333. package/tokens/native/CSTokens.swift +35 -1
  334. package/tokens/native/cs_tokens.dart +35 -1
  335. package/tokens/provenance.json +12 -12
  336. package/tokens/spacing.css +2 -0
  337. package/tokens/tokens.dtcg.json +111 -3
  338. package/tokens/tokens.js +46 -6
  339. package/tokens/tokens.json +45 -5
  340. package/tokens/typography.css +2 -0
  341. package/ui_kits/deck/index.html +4 -0
  342. package/ui_kits/status-hub/StatusHub.jsx +30 -4
  343. package/ui_kits/status-hub/index.html +3 -3
  344. package/ui_kits/status-hub/login.html +4 -0
  345. package/ui_kits/status-hub/project.html +4 -0
  346. package/ui_kits/status-hub/settings.html +35 -13
  347. package/ui_kits/status-hub/status.css +5 -1
  348. package/ui_kits/website/Website.jsx +25 -3
  349. package/ui_kits/website/careers.html +4 -0
  350. package/ui_kits/website/chat.html +5 -3
  351. package/ui_kits/website/index.html +3 -3
  352. package/ui_kits/website/site.css +2 -2
  353. package/ui_kits/website/work.html +4 -0
package/_ds_bundle.js CHANGED
@@ -1,4 +1,4 @@
1
- /* @ds-bundle: {"format":4,"namespace":"CyberSkillDesignSystem_847b3c","components":[{"name":"AIDisclosureBadge","sourcePath":"components/ai/AIDisclosureBadge.jsx"},{"name":"ChatMessage","sourcePath":"components/ai/ChatMessage.jsx"},{"name":"CitationList","sourcePath":"components/ai/CitationList.jsx"},{"name":"ConfidenceMeter","sourcePath":"components/ai/ConfidenceMeter.jsx"},{"name":"HumanReviewGate","sourcePath":"components/ai/HumanReviewGate.jsx"},{"name":"PromptInput","sourcePath":"components/ai/PromptInput.jsx"},{"name":"PromptSuggestions","sourcePath":"components/ai/PromptSuggestions.jsx"},{"name":"TypingIndicator","sourcePath":"components/ai/TypingIndicator.jsx"},{"name":"LumiAvatar","sourcePath":"components/brand/LumiAvatar.jsx"},{"name":"Button","sourcePath":"components/button/Button.jsx"},{"name":"ButtonGroup","sourcePath":"components/button/ButtonGroup.jsx"},{"name":"FloatingActionButton","sourcePath":"components/button/FloatingActionButton.jsx"},{"name":"Accordion","sourcePath":"components/data/Accordion.jsx"},{"name":"AspectRatio","sourcePath":"components/data/AspectRatio.jsx"},{"name":"Avatar","sourcePath":"components/data/Avatar.jsx"},{"name":"AvatarGroup","sourcePath":"components/data/Avatar.jsx"},{"name":"Card","sourcePath":"components/data/Card.jsx"},{"name":"CardHeader","sourcePath":"components/data/Card.jsx"},{"name":"CardBody","sourcePath":"components/data/Card.jsx"},{"name":"CardFooter","sourcePath":"components/data/Card.jsx"},{"name":"Carousel","sourcePath":"components/data/Carousel.jsx"},{"name":"Chart","sourcePath":"components/data/Chart.jsx"},{"name":"CodeBlock","sourcePath":"components/data/CodeBlock.jsx"},{"name":"Collapsible","sourcePath":"components/data/Collapsible.jsx"},{"name":"Comment","sourcePath":"components/data/Comment.jsx"},{"name":"DescriptionList","sourcePath":"components/data/DescriptionList.jsx"},{"name":"Divider","sourcePath":"components/data/Divider.jsx"},{"name":"Image","sourcePath":"components/data/Image.jsx"},{"name":"Item","sourcePath":"components/data/Item.jsx"},{"name":"Kbd","sourcePath":"components/data/Kbd.jsx"},{"name":"List","sourcePath":"components/data/List.jsx"},{"name":"ListItem","sourcePath":"components/data/List.jsx"},{"name":"Masonry","sourcePath":"components/data/Masonry.jsx"},{"name":"QRCode","sourcePath":"components/data/QRCode.jsx"},{"name":"ScrollArea","sourcePath":"components/data/ScrollArea.jsx"},{"name":"Sortable","sourcePath":"components/data/Sortable.jsx"},{"name":"Splitter","sourcePath":"components/data/Splitter.jsx"},{"name":"Stat","sourcePath":"components/data/Stat.jsx"},{"name":"Terminal","sourcePath":"components/data/Terminal.jsx"},{"name":"Timeline","sourcePath":"components/data/Timeline.jsx"},{"name":"Tooltip","sourcePath":"components/data/Tooltip.jsx"},{"name":"Tree","sourcePath":"components/data/Tree.jsx"},{"name":"Watermark","sourcePath":"components/data/Watermark.jsx"},{"name":"DataGrid","sourcePath":"components/datatable/DataGrid.jsx"},{"name":"DataTable","sourcePath":"components/datatable/DataTable.jsx"},{"name":"TreeTable","sourcePath":"components/datatable/TreeTable.jsx"},{"name":"Dialog","sourcePath":"components/dialog/Dialog.jsx"},{"name":"Alert","sourcePath":"components/feedback/Alert.jsx"},{"name":"Badge","sourcePath":"components/feedback/Badge.jsx"},{"name":"EmptyState","sourcePath":"components/feedback/EmptyState.jsx"},{"name":"ProgressBar","sourcePath":"components/feedback/ProgressBar.jsx"},{"name":"Result","sourcePath":"components/feedback/Result.jsx"},{"name":"Skeleton","sourcePath":"components/feedback/Skeleton.jsx"},{"name":"Spinner","sourcePath":"components/feedback/Spinner.jsx"},{"name":"StatusIndicator","sourcePath":"components/feedback/StatusIndicator.jsx"},{"name":"Tag","sourcePath":"components/feedback/Tag.jsx"},{"name":"ToastStack","sourcePath":"components/feedback/Toast.jsx"},{"name":"Toast","sourcePath":"components/feedback/Toast.jsx"},{"name":"Calendar","sourcePath":"components/forms/Calendar.jsx"},{"name":"Cascader","sourcePath":"components/forms/Cascader.jsx"},{"name":"Checkbox","sourcePath":"components/forms/Checkbox.jsx"},{"name":"ColorPicker","sourcePath":"components/forms/ColorPicker.jsx"},{"name":"Combobox","sourcePath":"components/forms/Combobox.jsx"},{"name":"DatePicker","sourcePath":"components/forms/DatePicker.jsx"},{"name":"Editor","sourcePath":"components/forms/Editor.jsx"},{"name":"FileUpload","sourcePath":"components/forms/FileUpload.jsx"},{"name":"Form","sourcePath":"components/forms/Form.jsx"},{"name":"FormField","sourcePath":"components/forms/Form.jsx"},{"name":"FormFieldArray","sourcePath":"components/forms/Form.jsx"},{"name":"FormWizard","sourcePath":"components/forms/Form.jsx"},{"name":"InlineEdit","sourcePath":"components/forms/InlineEdit.jsx"},{"name":"InputGroup","sourcePath":"components/forms/InputGroup.jsx"},{"name":"InputOTP","sourcePath":"components/forms/InputOTP.jsx"},{"name":"Mentions","sourcePath":"components/forms/Mentions.jsx"},{"name":"NativeSelect","sourcePath":"components/forms/NativeSelect.jsx"},{"name":"NumberField","sourcePath":"components/forms/NumberField.jsx"},{"name":"Radio","sourcePath":"components/forms/RadioGroup.jsx"},{"name":"RadioGroup","sourcePath":"components/forms/RadioGroup.jsx"},{"name":"Rating","sourcePath":"components/forms/Rating.jsx"},{"name":"SearchField","sourcePath":"components/forms/SearchField.jsx"},{"name":"SegmentedControl","sourcePath":"components/forms/SegmentedControl.jsx"},{"name":"Select","sourcePath":"components/forms/Select.jsx"},{"name":"Slider","sourcePath":"components/forms/Slider.jsx"},{"name":"Switch","sourcePath":"components/forms/Switch.jsx"},{"name":"TagInput","sourcePath":"components/forms/TagInput.jsx"},{"name":"Textarea","sourcePath":"components/forms/Textarea.jsx"},{"name":"TimePicker","sourcePath":"components/forms/TimePicker.jsx"},{"name":"Toggle","sourcePath":"components/forms/Toggle.jsx"},{"name":"Transfer","sourcePath":"components/forms/Transfer.jsx"},{"name":"TreeSelect","sourcePath":"components/forms/TreeSelect.jsx"},{"name":"CS_ICONS","sourcePath":"components/icon/Icon.jsx"},{"name":"Icon","sourcePath":"components/icon/Icon.jsx"},{"name":"Logo","sourcePath":"components/logo/Logo.jsx"},{"name":"CS_LOGO_VIEWBOX","sourcePath":"components/logo/logo-data.js"},{"name":"CS_LOGO_MARK_INNER","sourcePath":"components/logo/logo-data.js"},{"name":"Anchor","sourcePath":"components/navigation/Anchor.jsx"},{"name":"BackTop","sourcePath":"components/navigation/BackTop.jsx"},{"name":"Breadcrumb","sourcePath":"components/navigation/Breadcrumb.jsx"},{"name":"CommandPalette","sourcePath":"components/navigation/CommandPalette.jsx"},{"name":"Dock","sourcePath":"components/navigation/Dock.jsx"},{"name":"HotKeys","sourcePath":"components/navigation/HotKeys.jsx"},{"name":"Link","sourcePath":"components/navigation/Link.jsx"},{"name":"Menu","sourcePath":"components/navigation/Menu.jsx"},{"name":"MenuItem","sourcePath":"components/navigation/Menu.jsx"},{"name":"Menubar","sourcePath":"components/navigation/Menubar.jsx"},{"name":"NavigationMenu","sourcePath":"components/navigation/NavigationMenu.jsx"},{"name":"Pagination","sourcePath":"components/navigation/Pagination.jsx"},{"name":"Sidebar","sourcePath":"components/navigation/Sidebar.jsx"},{"name":"NavItem","sourcePath":"components/navigation/Sidebar.jsx"},{"name":"Steps","sourcePath":"components/navigation/Steps.jsx"},{"name":"Tabs","sourcePath":"components/navigation/Tabs.jsx"},{"name":"Tab","sourcePath":"components/navigation/Tabs.jsx"},{"name":"Toolbar","sourcePath":"components/navigation/Toolbar.jsx"},{"name":"AlertDialog","sourcePath":"components/overlays/AlertDialog.jsx"},{"name":"ContextMenu","sourcePath":"components/overlays/ContextMenu.jsx"},{"name":"Drawer","sourcePath":"components/overlays/Drawer.jsx"},{"name":"HoverCard","sourcePath":"components/overlays/HoverCard.jsx"},{"name":"Popconfirm","sourcePath":"components/overlays/Popconfirm.jsx"},{"name":"Popover","sourcePath":"components/overlays/Popover.jsx"},{"name":"Tour","sourcePath":"components/overlays/Tour.jsx"},{"name":"TextField","sourcePath":"components/textfield/TextField.jsx"}],"sourceHashes":{"components/_i18n/i18n.js":"c6c51a65bd79","components/_i18n/strings.js":"73bc5837fc8e","components/_utils/cx.js":"ad6a747ea116","components/ai/AIDisclosureBadge.jsx":"4c8954aa2d79","components/ai/ChatMessage.jsx":"84076f3488f2","components/ai/CitationList.jsx":"4d12ef868ff3","components/ai/ConfidenceMeter.jsx":"24e43b7f7a47","components/ai/HumanReviewGate.jsx":"922b278dca5c","components/ai/PromptInput.jsx":"7634643dafa5","components/ai/PromptSuggestions.jsx":"02d64117ecfa","components/ai/TypingIndicator.jsx":"149e3a0c7ef8","components/brand/LumiAvatar.jsx":"b6444360cf80","components/button/Button.jsx":"6d902a925eed","components/button/ButtonGroup.jsx":"1a1481f6fb93","components/button/FloatingActionButton.jsx":"ce49fe4129a3","components/data/Accordion.jsx":"fed81278cefd","components/data/AspectRatio.jsx":"6c1e8703891e","components/data/Avatar.jsx":"88c8f59334e6","components/data/Card.jsx":"96e1f9ef44a9","components/data/Carousel.jsx":"caf09a766c42","components/data/Chart.jsx":"1953e9fef120","components/data/CodeBlock.jsx":"04e0bd2507e2","components/data/Collapsible.jsx":"3d961fef83f8","components/data/Comment.jsx":"81469a910d80","components/data/DescriptionList.jsx":"ce50d72546bb","components/data/Divider.jsx":"2d08b4a7b18e","components/data/Image.jsx":"da5c7d4c69af","components/data/Item.jsx":"7e1ac68c4e96","components/data/Kbd.jsx":"3b3d867cbdd8","components/data/List.jsx":"5c221b19efe0","components/data/Masonry.jsx":"a65508731d79","components/data/QRCode.jsx":"6acaf577a7fc","components/data/ScrollArea.jsx":"c2e2ec304b1e","components/data/Sortable.jsx":"315b50256128","components/data/Splitter.jsx":"d231064601e9","components/data/Stat.jsx":"35734a801a71","components/data/Terminal.jsx":"3a3cd4477814","components/data/Timeline.jsx":"22058a781a98","components/data/Tooltip.jsx":"4d027aff5559","components/data/Tree.jsx":"9097456de50f","components/data/Watermark.jsx":"4be0b6230d47","components/data/qr-encode.js":"14e8de77df5f","components/datatable/DataGrid.jsx":"e4aa4a47d05e","components/datatable/DataTable.jsx":"fbfad5570592","components/datatable/TreeTable.jsx":"597c35135ebb","components/dialog/Dialog.jsx":"7af51ee28ab6","components/feedback/Alert.jsx":"0bbe4e5f467a","components/feedback/Badge.jsx":"e691ae1634f8","components/feedback/EmptyState.jsx":"9a9c00523cec","components/feedback/ProgressBar.jsx":"1a66335d5d9e","components/feedback/Result.jsx":"c168f8dcb009","components/feedback/Skeleton.jsx":"86ee345cb412","components/feedback/Spinner.jsx":"cad2ed4008a6","components/feedback/StatusIndicator.jsx":"d27a5fc3db2a","components/feedback/Tag.jsx":"13d288da9f38","components/feedback/Toast.jsx":"38cc9a82ede9","components/forms/Calendar.jsx":"8a66cbe766af","components/forms/Cascader.jsx":"ada31ccaf716","components/forms/Checkbox.jsx":"2badb7b3b72b","components/forms/ColorPicker.jsx":"d04db0ee7678","components/forms/Combobox.jsx":"3f2fb4d28922","components/forms/DatePicker.jsx":"7a6c18e1e635","components/forms/Editor.jsx":"d7bed6e52cff","components/forms/FileUpload.jsx":"e8031a109093","components/forms/Form.jsx":"f7952da4b73a","components/forms/InlineEdit.jsx":"5ffb40598769","components/forms/InputGroup.jsx":"06d6c22420d0","components/forms/InputOTP.jsx":"c3a5d02ffebc","components/forms/Mentions.jsx":"04bc4b5a4ace","components/forms/NativeSelect.jsx":"d6f6d300f75d","components/forms/NumberField.jsx":"44975fd25721","components/forms/RadioGroup.jsx":"1a64f7600e01","components/forms/Rating.jsx":"06d345ecc5f4","components/forms/SearchField.jsx":"2a12c65900ec","components/forms/SegmentedControl.jsx":"1f143c62fb56","components/forms/Select.jsx":"1b5ba905b339","components/forms/Slider.jsx":"69aa1a5f1af8","components/forms/Switch.jsx":"0b37cfa41979","components/forms/TagInput.jsx":"2d1554422097","components/forms/Textarea.jsx":"cf244fee0e37","components/forms/TimePicker.jsx":"165192c8760c","components/forms/Toggle.jsx":"338453a34669","components/forms/Transfer.jsx":"dd0c02d1014e","components/forms/TreeSelect.jsx":"a5b1b91d1d6a","components/icon/Icon.jsx":"379dc6de903e","components/logo/Logo.jsx":"445c5f5fbd40","components/logo/logo-data.js":"f1a251a50c8f","components/navigation/Anchor.jsx":"491fb330e718","components/navigation/BackTop.jsx":"5cac0081fc20","components/navigation/Breadcrumb.jsx":"45636f3b0a51","components/navigation/CommandPalette.jsx":"2b5b30906b8b","components/navigation/Dock.jsx":"3073e2870c65","components/navigation/HotKeys.jsx":"f0f707a3335d","components/navigation/Link.jsx":"d4fe3fcffd2c","components/navigation/Menu.jsx":"6786788f13f8","components/navigation/Menubar.jsx":"1aa64f59891e","components/navigation/NavigationMenu.jsx":"020279fd7f79","components/navigation/Pagination.jsx":"a1fc19bfd104","components/navigation/Sidebar.jsx":"d578b013ad33","components/navigation/Steps.jsx":"85cb20bd45da","components/navigation/Tabs.jsx":"5d5921da1644","components/navigation/Toolbar.jsx":"9727d7bdbc5f","components/overlays/AlertDialog.jsx":"2ed7fbde4a5a","components/overlays/ContextMenu.jsx":"e7e3386d89ac","components/overlays/Drawer.jsx":"8227143abbfa","components/overlays/HoverCard.jsx":"5cfabde80960","components/overlays/Popconfirm.jsx":"55f08dba5f38","components/overlays/Popover.jsx":"1582f7fa5533","components/overlays/Tour.jsx":"9901ee649da0","components/textfield/TextField.jsx":"c06bd9729f20","image-slot.js":"0394ad34f685","tokens/tokens.js":"02cfbae229ac","ui_kits/status-hub/StatusHub.jsx":"88dfd93e1664","ui_kits/status-hub/data.js":"664bbbb30cb3","ui_kits/website/Website.jsx":"c3a0938d9279","ui_kits/website/copy.js":"9d42c52c17cb"},"inlinedExternals":[],"unexposedExports":[{"name":"cx","sourcePath":"components/_utils/cx.js"},{"name":"formatCurrency","sourcePath":"components/_i18n/i18n.js"},{"name":"formatDate","sourcePath":"components/_i18n/i18n.js"},{"name":"formatNumber","sourcePath":"components/_i18n/i18n.js"},{"name":"getPath","sourcePath":"components/forms/Form.jsx"},{"name":"makeT","sourcePath":"components/_i18n/i18n.js"},{"name":"monthName","sourcePath":"components/_i18n/i18n.js"},{"name":"qrMatrix","sourcePath":"components/data/qr-encode.js"},{"name":"resolveLang","sourcePath":"components/_i18n/i18n.js"},{"name":"setPath","sourcePath":"components/forms/Form.jsx"},{"name":"strings","sourcePath":"components/_i18n/strings.js"},{"name":"tokens","sourcePath":"tokens/tokens.js"},{"name":"tr","sourcePath":"components/_i18n/i18n.js"},{"name":"useLang","sourcePath":"components/_i18n/i18n.js"}]} */
1
+ /* @ds-bundle: {"format":4,"namespace":"CyberSkillDesignSystem_847b3c","components":[{"name":"AIDisclosureBadge","sourcePath":"components/ai/AIDisclosureBadge.jsx"},{"name":"ChatMessage","sourcePath":"components/ai/ChatMessage.jsx"},{"name":"CitationList","sourcePath":"components/ai/CitationList.jsx"},{"name":"ConfidenceMeter","sourcePath":"components/ai/ConfidenceMeter.jsx"},{"name":"HumanReviewGate","sourcePath":"components/ai/HumanReviewGate.jsx"},{"name":"PromptInput","sourcePath":"components/ai/PromptInput.jsx"},{"name":"PromptSuggestions","sourcePath":"components/ai/PromptSuggestions.jsx"},{"name":"TypingIndicator","sourcePath":"components/ai/TypingIndicator.jsx"},{"name":"LumiAvatar","sourcePath":"components/brand/LumiAvatar.jsx"},{"name":"Button","sourcePath":"components/button/Button.jsx"},{"name":"ButtonGroup","sourcePath":"components/button/ButtonGroup.jsx"},{"name":"FloatingActionButton","sourcePath":"components/button/FloatingActionButton.jsx"},{"name":"Accordion","sourcePath":"components/data/Accordion.jsx"},{"name":"AspectRatio","sourcePath":"components/data/AspectRatio.jsx"},{"name":"Avatar","sourcePath":"components/data/Avatar.jsx"},{"name":"AvatarGroup","sourcePath":"components/data/Avatar.jsx"},{"name":"Card","sourcePath":"components/data/Card.jsx"},{"name":"CardHeader","sourcePath":"components/data/Card.jsx"},{"name":"CardBody","sourcePath":"components/data/Card.jsx"},{"name":"CardFooter","sourcePath":"components/data/Card.jsx"},{"name":"Carousel","sourcePath":"components/data/Carousel.jsx"},{"name":"Chart","sourcePath":"components/data/Chart.jsx"},{"name":"CodeBlock","sourcePath":"components/data/CodeBlock.jsx"},{"name":"Collapsible","sourcePath":"components/data/Collapsible.jsx"},{"name":"Comment","sourcePath":"components/data/Comment.jsx"},{"name":"DescriptionList","sourcePath":"components/data/DescriptionList.jsx"},{"name":"Divider","sourcePath":"components/data/Divider.jsx"},{"name":"Image","sourcePath":"components/data/Image.jsx"},{"name":"Item","sourcePath":"components/data/Item.jsx"},{"name":"Kbd","sourcePath":"components/data/Kbd.jsx"},{"name":"List","sourcePath":"components/data/List.jsx"},{"name":"ListItem","sourcePath":"components/data/List.jsx"},{"name":"Masonry","sourcePath":"components/data/Masonry.jsx"},{"name":"QRCode","sourcePath":"components/data/QRCode.jsx"},{"name":"ScrollArea","sourcePath":"components/data/ScrollArea.jsx"},{"name":"Sortable","sourcePath":"components/data/Sortable.jsx"},{"name":"Splitter","sourcePath":"components/data/Splitter.jsx"},{"name":"Stat","sourcePath":"components/data/Stat.jsx"},{"name":"Terminal","sourcePath":"components/data/Terminal.jsx"},{"name":"Timeline","sourcePath":"components/data/Timeline.jsx"},{"name":"Tooltip","sourcePath":"components/data/Tooltip.jsx"},{"name":"Tree","sourcePath":"components/data/Tree.jsx"},{"name":"Watermark","sourcePath":"components/data/Watermark.jsx"},{"name":"DataGrid","sourcePath":"components/datatable/DataGrid.jsx"},{"name":"DataTable","sourcePath":"components/datatable/DataTable.jsx"},{"name":"TreeTable","sourcePath":"components/datatable/TreeTable.jsx"},{"name":"Dialog","sourcePath":"components/dialog/Dialog.jsx"},{"name":"Alert","sourcePath":"components/feedback/Alert.jsx"},{"name":"Badge","sourcePath":"components/feedback/Badge.jsx"},{"name":"EmptyState","sourcePath":"components/feedback/EmptyState.jsx"},{"name":"ProgressBar","sourcePath":"components/feedback/ProgressBar.jsx"},{"name":"Result","sourcePath":"components/feedback/Result.jsx"},{"name":"Skeleton","sourcePath":"components/feedback/Skeleton.jsx"},{"name":"Spinner","sourcePath":"components/feedback/Spinner.jsx"},{"name":"StatusIndicator","sourcePath":"components/feedback/StatusIndicator.jsx"},{"name":"Tag","sourcePath":"components/feedback/Tag.jsx"},{"name":"ToastStack","sourcePath":"components/feedback/Toast.jsx"},{"name":"Toast","sourcePath":"components/feedback/Toast.jsx"},{"name":"Calendar","sourcePath":"components/forms/Calendar.jsx"},{"name":"Cascader","sourcePath":"components/forms/Cascader.jsx"},{"name":"Checkbox","sourcePath":"components/forms/Checkbox.jsx"},{"name":"ColorPicker","sourcePath":"components/forms/ColorPicker.jsx"},{"name":"Combobox","sourcePath":"components/forms/Combobox.jsx"},{"name":"DatePicker","sourcePath":"components/forms/DatePicker.jsx"},{"name":"Editor","sourcePath":"components/forms/Editor.jsx"},{"name":"FileUpload","sourcePath":"components/forms/FileUpload.jsx"},{"name":"Form","sourcePath":"components/forms/Form.jsx"},{"name":"FormField","sourcePath":"components/forms/Form.jsx"},{"name":"FormFieldArray","sourcePath":"components/forms/Form.jsx"},{"name":"FormWizard","sourcePath":"components/forms/Form.jsx"},{"name":"InlineEdit","sourcePath":"components/forms/InlineEdit.jsx"},{"name":"InputGroup","sourcePath":"components/forms/InputGroup.jsx"},{"name":"InputOTP","sourcePath":"components/forms/InputOTP.jsx"},{"name":"Mentions","sourcePath":"components/forms/Mentions.jsx"},{"name":"NativeSelect","sourcePath":"components/forms/NativeSelect.jsx"},{"name":"NumberField","sourcePath":"components/forms/NumberField.jsx"},{"name":"Radio","sourcePath":"components/forms/RadioGroup.jsx"},{"name":"RadioGroup","sourcePath":"components/forms/RadioGroup.jsx"},{"name":"Rating","sourcePath":"components/forms/Rating.jsx"},{"name":"SearchField","sourcePath":"components/forms/SearchField.jsx"},{"name":"SegmentedControl","sourcePath":"components/forms/SegmentedControl.jsx"},{"name":"Select","sourcePath":"components/forms/Select.jsx"},{"name":"Slider","sourcePath":"components/forms/Slider.jsx"},{"name":"Switch","sourcePath":"components/forms/Switch.jsx"},{"name":"TagInput","sourcePath":"components/forms/TagInput.jsx"},{"name":"Textarea","sourcePath":"components/forms/Textarea.jsx"},{"name":"TimePicker","sourcePath":"components/forms/TimePicker.jsx"},{"name":"Toggle","sourcePath":"components/forms/Toggle.jsx"},{"name":"Transfer","sourcePath":"components/forms/Transfer.jsx"},{"name":"TreeSelect","sourcePath":"components/forms/TreeSelect.jsx"},{"name":"CS_ICONS","sourcePath":"components/icon/Icon.jsx"},{"name":"Icon","sourcePath":"components/icon/Icon.jsx"},{"name":"Logo","sourcePath":"components/logo/Logo.jsx"},{"name":"CS_LOGO_VIEWBOX","sourcePath":"components/logo/logo-data.js"},{"name":"CS_LOGO_MARK_INNER","sourcePath":"components/logo/logo-data.js"},{"name":"Anchor","sourcePath":"components/navigation/Anchor.jsx"},{"name":"BackTop","sourcePath":"components/navigation/BackTop.jsx"},{"name":"Breadcrumb","sourcePath":"components/navigation/Breadcrumb.jsx"},{"name":"CommandPalette","sourcePath":"components/navigation/CommandPalette.jsx"},{"name":"Dock","sourcePath":"components/navigation/Dock.jsx"},{"name":"HotKeys","sourcePath":"components/navigation/HotKeys.jsx"},{"name":"Link","sourcePath":"components/navigation/Link.jsx"},{"name":"Menu","sourcePath":"components/navigation/Menu.jsx"},{"name":"MenuItem","sourcePath":"components/navigation/Menu.jsx"},{"name":"Menubar","sourcePath":"components/navigation/Menubar.jsx"},{"name":"NavigationMenu","sourcePath":"components/navigation/NavigationMenu.jsx"},{"name":"Pagination","sourcePath":"components/navigation/Pagination.jsx"},{"name":"Sidebar","sourcePath":"components/navigation/Sidebar.jsx"},{"name":"NavItem","sourcePath":"components/navigation/Sidebar.jsx"},{"name":"Steps","sourcePath":"components/navigation/Steps.jsx"},{"name":"Tabs","sourcePath":"components/navigation/Tabs.jsx"},{"name":"Tab","sourcePath":"components/navigation/Tabs.jsx"},{"name":"Toolbar","sourcePath":"components/navigation/Toolbar.jsx"},{"name":"AlertDialog","sourcePath":"components/overlays/AlertDialog.jsx"},{"name":"ContextMenu","sourcePath":"components/overlays/ContextMenu.jsx"},{"name":"Drawer","sourcePath":"components/overlays/Drawer.jsx"},{"name":"HoverCard","sourcePath":"components/overlays/HoverCard.jsx"},{"name":"OverlayProvider","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"Popconfirm","sourcePath":"components/overlays/Popconfirm.jsx"},{"name":"Popover","sourcePath":"components/overlays/Popover.jsx"},{"name":"Tour","sourcePath":"components/overlays/Tour.jsx"},{"name":"TextField","sourcePath":"components/textfield/TextField.jsx"}],"sourceHashes":{"components/_i18n/i18n.js":"63f973d61113","components/_i18n/strings.js":"cea7ef153e18","components/_utils/cx.js":"ad6a747ea116","components/ai/AIDisclosureBadge.jsx":"4c8954aa2d79","components/ai/ChatMessage.jsx":"84076f3488f2","components/ai/CitationList.jsx":"4d12ef868ff3","components/ai/ConfidenceMeter.jsx":"68cf2bba3a9e","components/ai/HumanReviewGate.jsx":"922b278dca5c","components/ai/PromptInput.jsx":"7634643dafa5","components/ai/PromptSuggestions.jsx":"02d64117ecfa","components/ai/TypingIndicator.jsx":"149e3a0c7ef8","components/brand/LumiAvatar.jsx":"b6444360cf80","components/button/Button.jsx":"6d902a925eed","components/button/ButtonGroup.jsx":"1a1481f6fb93","components/button/FloatingActionButton.jsx":"ce49fe4129a3","components/data/Accordion.jsx":"fed81278cefd","components/data/AspectRatio.jsx":"6c1e8703891e","components/data/Avatar.jsx":"88c8f59334e6","components/data/Card.jsx":"96e1f9ef44a9","components/data/Carousel.jsx":"caf09a766c42","components/data/Chart.jsx":"1953e9fef120","components/data/CodeBlock.jsx":"04e0bd2507e2","components/data/Collapsible.jsx":"3d961fef83f8","components/data/Comment.jsx":"81469a910d80","components/data/DescriptionList.jsx":"ce50d72546bb","components/data/Divider.jsx":"2d08b4a7b18e","components/data/Image.jsx":"da5c7d4c69af","components/data/Item.jsx":"7e1ac68c4e96","components/data/Kbd.jsx":"3b3d867cbdd8","components/data/List.jsx":"5c221b19efe0","components/data/Masonry.jsx":"a65508731d79","components/data/QRCode.jsx":"6acaf577a7fc","components/data/ScrollArea.jsx":"c2e2ec304b1e","components/data/Sortable.jsx":"315b50256128","components/data/Splitter.jsx":"d231064601e9","components/data/Stat.jsx":"35734a801a71","components/data/Terminal.jsx":"3a3cd4477814","components/data/Timeline.jsx":"22058a781a98","components/data/Tooltip.jsx":"4d027aff5559","components/data/Tree.jsx":"9097456de50f","components/data/Watermark.jsx":"66b7b71488d8","components/data/qr-encode.js":"14e8de77df5f","components/datatable/DataGrid.jsx":"c84fe5d5b8cc","components/datatable/DataTable.jsx":"fbfad5570592","components/datatable/TreeTable.jsx":"597c35135ebb","components/dialog/Dialog.jsx":"8ef7722c37c4","components/feedback/Alert.jsx":"0bbe4e5f467a","components/feedback/Badge.jsx":"e691ae1634f8","components/feedback/EmptyState.jsx":"9a9c00523cec","components/feedback/ProgressBar.jsx":"3986118b0da8","components/feedback/Result.jsx":"c168f8dcb009","components/feedback/Skeleton.jsx":"86ee345cb412","components/feedback/Spinner.jsx":"cad2ed4008a6","components/feedback/StatusIndicator.jsx":"d27a5fc3db2a","components/feedback/Tag.jsx":"13d288da9f38","components/feedback/Toast.jsx":"38cc9a82ede9","components/forms/Calendar.jsx":"8a66cbe766af","components/forms/Cascader.jsx":"7b830b11edb1","components/forms/Checkbox.jsx":"2badb7b3b72b","components/forms/ColorPicker.jsx":"d04db0ee7678","components/forms/Combobox.jsx":"3f2fb4d28922","components/forms/DatePicker.jsx":"7a6c18e1e635","components/forms/Editor.jsx":"194484fb9dc4","components/forms/FileUpload.jsx":"509dfaff8bea","components/forms/Form.jsx":"f7952da4b73a","components/forms/InlineEdit.jsx":"5ffb40598769","components/forms/InputGroup.jsx":"06d6c22420d0","components/forms/InputOTP.jsx":"c3a5d02ffebc","components/forms/Mentions.jsx":"04bc4b5a4ace","components/forms/NativeSelect.jsx":"d6f6d300f75d","components/forms/NumberField.jsx":"44975fd25721","components/forms/RadioGroup.jsx":"1a64f7600e01","components/forms/Rating.jsx":"06d345ecc5f4","components/forms/SearchField.jsx":"2a12c65900ec","components/forms/SegmentedControl.jsx":"1f143c62fb56","components/forms/Select.jsx":"1b5ba905b339","components/forms/Slider.jsx":"69aa1a5f1af8","components/forms/Switch.jsx":"ed54f4bceb60","components/forms/TagInput.jsx":"2d1554422097","components/forms/Textarea.jsx":"cf244fee0e37","components/forms/TimePicker.jsx":"abd6e54b2983","components/forms/Toggle.jsx":"338453a34669","components/forms/Transfer.jsx":"dd0c02d1014e","components/forms/TreeSelect.jsx":"a5b1b91d1d6a","components/icon/Icon.jsx":"280fba8477db","components/logo/Logo.jsx":"445c5f5fbd40","components/logo/logo-data.js":"f1a251a50c8f","components/navigation/Anchor.jsx":"491fb330e718","components/navigation/BackTop.jsx":"5cac0081fc20","components/navigation/Breadcrumb.jsx":"45636f3b0a51","components/navigation/CommandPalette.jsx":"51c25b8416eb","components/navigation/Dock.jsx":"3073e2870c65","components/navigation/HotKeys.jsx":"f0f707a3335d","components/navigation/Link.jsx":"d4fe3fcffd2c","components/navigation/Menu.jsx":"6786788f13f8","components/navigation/Menubar.jsx":"1aa64f59891e","components/navigation/NavigationMenu.jsx":"020279fd7f79","components/navigation/Pagination.jsx":"a1fc19bfd104","components/navigation/Sidebar.jsx":"d578b013ad33","components/navigation/Steps.jsx":"85cb20bd45da","components/navigation/Tabs.jsx":"5d5921da1644","components/navigation/Toolbar.jsx":"ba1e0d0578b3","components/overlays/AlertDialog.jsx":"dcfbb7f61506","components/overlays/ContextMenu.jsx":"e7e3386d89ac","components/overlays/Drawer.jsx":"a1c719da3f62","components/overlays/HoverCard.jsx":"5cfabde80960","components/overlays/OverlayManager.jsx":"6b58c4dad9da","components/overlays/Popconfirm.jsx":"55f08dba5f38","components/overlays/Popover.jsx":"1582f7fa5533","components/overlays/Tour.jsx":"707cd7464f0c","components/textfield/TextField.jsx":"c06bd9729f20","image-slot.js":"26886a229370","tokens/tokens.js":"ed883dc757ae","ui_kits/status-hub/StatusHub.jsx":"8674a9fcf8fc","ui_kits/status-hub/data.js":"664bbbb30cb3","ui_kits/website/Website.jsx":"c6a98330480b","ui_kits/website/copy.js":"9d42c52c17cb"},"inlinedExternals":[],"unexposedExports":[{"name":"attachFocusTrap","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"cx","sourcePath":"components/_utils/cx.js"},{"name":"focusableSelector","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"formatCurrency","sourcePath":"components/_i18n/i18n.js"},{"name":"formatDate","sourcePath":"components/_i18n/i18n.js"},{"name":"formatNumber","sourcePath":"components/_i18n/i18n.js"},{"name":"getOverlayManager","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"getPath","sourcePath":"components/forms/Form.jsx"},{"name":"makeT","sourcePath":"components/_i18n/i18n.js"},{"name":"monthName","sourcePath":"components/_i18n/i18n.js"},{"name":"qrMatrix","sourcePath":"components/data/qr-encode.js"},{"name":"resolveLang","sourcePath":"components/_i18n/i18n.js"},{"name":"setPath","sourcePath":"components/forms/Form.jsx"},{"name":"strings","sourcePath":"components/_i18n/strings.js"},{"name":"tokens","sourcePath":"tokens/tokens.js"},{"name":"tr","sourcePath":"components/_i18n/i18n.js"},{"name":"useLang","sourcePath":"components/_i18n/i18n.js"},{"name":"useOverlayLayer","sourcePath":"components/overlays/OverlayManager.jsx"}]} */
2
2
 
3
3
  (() => {
4
4
 
@@ -80,8 +80,8 @@ const strings = {
80
80
  vi: { input: "Ô nhập lệnh" }
81
81
  },
82
82
  DataGrid: {
83
- en: { empty: "No records", selectAll: "Select all rows", selectRow: "Select row" },
84
- vi: { empty: "Không có bản ghi", selectAll: "Chọn tất cả", selectRow: "Chọn dòng" }
83
+ en: { empty: "No records", selectAll: "Select all rows", selectRow: "Select row", pin: "Pin this column", pinNamed: "Pin column {name}" },
84
+ vi: { empty: "Không có bản ghi", selectAll: "Chọn tất cả", selectRow: "Chọn dòng", pin: "Ghim cột này", pinNamed: "Ghim cột {name}" }
85
85
  },
86
86
  Splitter: {
87
87
  en: { label: "Resize panes" },
@@ -190,6 +190,54 @@ const strings = {
190
190
  HumanReviewGate: {
191
191
  en: { aria: "Human review gate", risk: "review required", approve: "Approve", reject: "Reject", reviewer: "Reviewer" },
192
192
  vi: { aria: "Cổng kiểm duyệt của con người", risk: "cần xem xét", approve: "Phê duyệt", reject: "Từ chối", reviewer: "Người duyệt" }
193
+ },
194
+ Switch: {
195
+ en: { on: "On", off: "Off" },
196
+ vi: { on: "Bật", off: "Tắt" }
197
+ },
198
+ Tabs: {
199
+ en: { list: "Tabs" },
200
+ vi: { list: "Tab" }
201
+ },
202
+ EmptyState: {
203
+ en: { title: "Nothing here yet", action: "Get started" },
204
+ vi: { title: "Chưa có gì ở đây", action: "Bắt đầu" }
205
+ },
206
+ Alert: {
207
+ en: { dismiss: "Dismiss" },
208
+ vi: { dismiss: "Đóng" }
209
+ },
210
+ Select: {
211
+ en: { placeholder: "Select…" },
212
+ vi: { placeholder: "Chọn…" }
213
+ },
214
+ Slider: {
215
+ en: { label: "Slider" },
216
+ vi: { label: "Thanh trượt" }
217
+ },
218
+ Steps: {
219
+ en: { label: "Steps" },
220
+ vi: { label: "Các bước" }
221
+ },
222
+ Toggle: {
223
+ en: { pressed: "Pressed", unpressed: "Not pressed" },
224
+ vi: { pressed: "Đang bật", unpressed: "Chưa bật" }
225
+ },
226
+ Menu: {
227
+ en: { menu: "Menu" },
228
+ vi: { menu: "Trình đơn" }
229
+ },
230
+ ContextMenu: {
231
+ en: { menu: "Context menu" },
232
+ vi: { menu: "Trình đơn ngữ cảnh" }
233
+ },
234
+ Tooltip: {
235
+ en: { label: "Tooltip" },
236
+ vi: { label: "Chú thích" }
237
+ },
238
+ ProgressBar: {
239
+ en: { label: "Progress" },
240
+ vi: { label: "Tiến độ" }
193
241
  }
194
242
  };
195
243
  Object.assign(__ds_scope, { strings });
@@ -222,7 +270,16 @@ function useLang(propLang) {
222
270
  const ref = React.useRef(null);
223
271
  const [lang, setLang] = React.useState(() => resolveLang(propLang, null));
224
272
  React.useLayoutEffect(() => {
225
- setLang(resolveLang(propLang, ref.current));
273
+ const el = ref.current;
274
+ setLang(resolveLang(propLang, el));
275
+ if (!el || propLang) return void 0;
276
+ const obs = new MutationObserver(() => setLang(resolveLang(propLang, el)));
277
+ let node = el.parentElement;
278
+ while (node) {
279
+ obs.observe(node, { attributes: true, attributeFilter: ["lang"] });
280
+ node = node.parentElement;
281
+ }
282
+ return () => obs.disconnect();
226
283
  }, [propLang]);
227
284
  return [ref, lang];
228
285
  }
@@ -319,19 +376,21 @@ const TONE = {
319
376
  };
320
377
  function ConfidenceMeter({ value, level, segments = 5, label, lang, className }) {
321
378
  let tone, filled;
379
+ const segs = Math.max(1, Number(segments) || 5);
322
380
  if (value != null) {
323
- tone = value < 0.4 ? "low" : value < 0.75 ? "medium" : "high";
324
- filled = Math.max(1, Math.round(value * segments));
381
+ const v = Math.max(0, Math.min(1, Number(value) || 0));
382
+ tone = v < 0.4 ? "low" : v < 0.75 ? "medium" : "high";
383
+ filled = Math.max(0, Math.min(segs, Math.round(v * segs)));
325
384
  } else {
326
- tone = level || "medium";
327
- filled = Math.round(TONE[tone].fill / 5 * segments);
385
+ tone = TONE[level] ? level : "medium";
386
+ filled = Math.max(0, Math.min(segs, Math.round(TONE[tone].fill / 5 * segs)));
328
387
  }
329
388
  const meta = TONE[tone];
330
389
  const [ref, L] = useLang(lang);
331
390
  const t = makeT("ConfidenceMeter", L);
332
391
  const lbl = label != null ? label : t("label");
333
392
  const levelText = t(tone);
334
- return /* @__PURE__ */ React.createElement("div", { ref, className: cx("cs-confidence", className) }, /* @__PURE__ */ React.createElement("div", { className: "cs-confidence__head" }, /* @__PURE__ */ React.createElement("span", null, lbl), /* @__PURE__ */ React.createElement("span", { className: "cs-confidence__level", style: { color: meta.color } }, levelText)), /* @__PURE__ */ React.createElement("div", { className: "cs-confidence__track", role: "meter", "aria-valuemin": 0, "aria-valuemax": segments, "aria-valuenow": filled, "aria-label": lbl + ": " + levelText }, Array.from({ length: segments }).map((_, i) => /* @__PURE__ */ React.createElement("span", { key: i, className: "cs-confidence__seg", style: i < filled ? { background: meta.color } : void 0 }))));
393
+ return /* @__PURE__ */ React.createElement("div", { ref, className: cx("cs-confidence", className) }, /* @__PURE__ */ React.createElement("div", { className: "cs-confidence__head" }, /* @__PURE__ */ React.createElement("span", null, lbl), /* @__PURE__ */ React.createElement("span", { className: "cs-confidence__level", style: { color: meta.color } }, levelText)), /* @__PURE__ */ React.createElement("div", { className: "cs-confidence__track", role: "meter", "aria-valuemin": 0, "aria-valuemax": segs, "aria-valuenow": filled, "aria-label": lbl + ": " + levelText }, Array.from({ length: segs }).map((_, i) => /* @__PURE__ */ React.createElement("span", { key: i, className: "cs-confidence__seg", style: i < filled ? { background: meta.color } : void 0 }))));
335
394
  }
336
395
  Object.assign(__ds_scope, { ConfidenceMeter });
337
396
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/ai/ConfidenceMeter.jsx", error: String((e && e.message) || e) }); }
@@ -988,10 +1047,17 @@ Object.assign(__ds_scope, { Tree });
988
1047
  try { (() => {
989
1048
  const { cx } = __ds_scope;
990
1049
  function Watermark({ text = "CyberSkill", opacity = 0.09, gap = 140, rotate = -22, children, className }) {
1050
+ const host = React.useRef(null);
1051
+ const [fill, setFill] = React.useState("#45210E");
1052
+ React.useLayoutEffect(() => {
1053
+ if (!host.current || typeof getComputedStyle === "undefined") return;
1054
+ const c = getComputedStyle(host.current).getPropertyValue("--cs-color-text-primary").trim();
1055
+ if (c) setFill(c);
1056
+ }, []);
991
1057
  const svg = encodeURIComponent(
992
- `<svg xmlns="http://www.w3.org/2000/svg" width="${gap}" height="${gap}"><text x="50%" y="50%" font-family="Be Vietnam Pro, sans-serif" font-size="14" font-weight="700" fill="#45210E" fill-opacity="${opacity}" text-anchor="middle" transform="rotate(${rotate} ${gap / 2} ${gap / 2})">${String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;")}</text></svg>`
1058
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${gap}" height="${gap}"><text x="50%" y="50%" font-family="Be Vietnam Pro, sans-serif" font-size="14" font-weight="700" fill="${fill}" fill-opacity="${opacity}" text-anchor="middle" transform="rotate(${rotate} ${gap / 2} ${gap / 2})">${String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;")}</text></svg>`
993
1059
  );
994
- return /* @__PURE__ */ React.createElement("div", { className: cx("cs-watermark", className), style: { position: "relative" } }, children, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", style: { position: "absolute", inset: 0, pointerEvents: "none", backgroundImage: `url("data:image/svg+xml,${svg}")` } }));
1060
+ return /* @__PURE__ */ React.createElement("div", { ref: host, className: cx("cs-watermark", className), style: { position: "relative" } }, children, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", style: { position: "absolute", inset: 0, pointerEvents: "none", backgroundImage: `url("data:image/svg+xml,${svg}")` } }));
995
1061
  }
996
1062
  Object.assign(__ds_scope, { Watermark });
997
1063
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/data/Watermark.jsx", error: String((e && e.message) || e) }); }
@@ -1131,124 +1197,6 @@ function QRCode({ value = "", size = 128, color = "var(--cs-color-text-primary)"
1131
1197
  Object.assign(__ds_scope, { QRCode });
1132
1198
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/data/QRCode.jsx", error: String((e && e.message) || e) }); }
1133
1199
 
1134
- // components/datatable/DataGrid.jsx
1135
- try { (() => {
1136
- const { makeT, useLang } = __ds_scope;
1137
- const { cx } = __ds_scope;
1138
- function DataGrid({
1139
- columns = [],
1140
- rows = [],
1141
- rowKey = "id",
1142
- selectable = false,
1143
- selected = [],
1144
- onSelect,
1145
- height = 280,
1146
- caption,
1147
- empty,
1148
- lang,
1149
- className,
1150
- filterText,
1151
- filterKeys,
1152
- /** When true (or rows exceed virtualThreshold), only paint a window of rows. */
1153
- virtual = false,
1154
- /** Row threshold that auto-enables virtualization. Default 80. */
1155
- virtualThreshold = 80,
1156
- /** Approximate row height for windowing. Default 36. */
1157
- rowHeight = 36,
1158
- /** localStorage key — when set, column key order is persisted across reloads. */
1159
- persistKey
1160
- }) {
1161
- const [sort, setSort] = React.useState(null);
1162
- const [scrollTop, setScrollTop] = React.useState(0);
1163
- const [colOrder, setColOrder] = React.useState(() => {
1164
- if (!persistKey) return null;
1165
- try {
1166
- const raw = localStorage.getItem("cs:datagrid:cols:" + persistKey);
1167
- const arr = raw ? JSON.parse(raw) : null;
1168
- return Array.isArray(arr) ? arr : null;
1169
- } catch (e) {
1170
- return null;
1171
- }
1172
- });
1173
- const [ref, L] = useLang(lang);
1174
- const t = makeT("DataGrid", L);
1175
- const orderedColumns = React.useMemo(() => {
1176
- if (!colOrder || !colOrder.length) return columns;
1177
- const map = new Map(columns.map((c) => [c.key, c]));
1178
- const out = [];
1179
- for (const k of colOrder) if (map.has(k)) {
1180
- out.push(map.get(k));
1181
- map.delete(k);
1182
- }
1183
- for (const c of map.values()) out.push(c);
1184
- return out;
1185
- }, [columns, colOrder]);
1186
- const filtered = React.useMemo(() => {
1187
- const q = (filterText == null ? "" : String(filterText)).trim().toLowerCase();
1188
- if (!q) return rows;
1189
- const keys = filterKeys && filterKeys.length ? filterKeys : orderedColumns.map((c) => c.key);
1190
- return rows.filter((r) => keys.some((k) => String(r[k] == null ? "" : r[k]).toLowerCase().includes(q)));
1191
- }, [rows, filterText, filterKeys, orderedColumns]);
1192
- const sorted = React.useMemo(() => {
1193
- if (!sort) return filtered;
1194
- const col = orderedColumns.find((c) => c.key === sort.key);
1195
- const val = (r) => col && col.sortValue ? col.sortValue(r) : r[sort.key];
1196
- return [...filtered].sort((a, b) => {
1197
- const x = val(a), y = val(b);
1198
- return (x > y ? 1 : x < y ? -1 : 0) * (sort.dir === "asc" ? 1 : -1);
1199
- });
1200
- }, [filtered, sort, orderedColumns]);
1201
- const useVirtual = virtual || sorted.length >= virtualThreshold;
1202
- const bodyH = Math.max(0, height - 40);
1203
- const start = useVirtual ? Math.max(0, Math.floor(scrollTop / rowHeight) - 4) : 0;
1204
- const visibleCount = useVirtual ? Math.ceil(bodyH / rowHeight) + 8 : sorted.length;
1205
- const end = useVirtual ? Math.min(sorted.length, start + visibleCount) : sorted.length;
1206
- const slice = sorted.slice(start, end);
1207
- const padTop = useVirtual ? start * rowHeight : 0;
1208
- const padBottom = useVirtual ? Math.max(0, (sorted.length - end) * rowHeight) : 0;
1209
- const allSel = selectable && filtered.length && filtered.every((r) => selected.includes(r[rowKey]));
1210
- const toggleAll = () => onSelect && onSelect(allSel ? [] : filtered.map((r) => r[rowKey]));
1211
- const toggle = (k) => onSelect && onSelect(selected.includes(k) ? selected.filter((x) => x !== k) : [...selected, k]);
1212
- const pinColumn = (key) => {
1213
- if (!persistKey) return;
1214
- const keys = orderedColumns.map((c) => c.key);
1215
- const next = [key, ...keys.filter((k) => k !== key)];
1216
- setColOrder(next);
1217
- try {
1218
- localStorage.setItem("cs:datagrid:cols:" + persistKey, JSON.stringify(next));
1219
- } catch (e) {
1220
- }
1221
- };
1222
- return /* @__PURE__ */ React.createElement(
1223
- "div",
1224
- {
1225
- ref,
1226
- className: cx("cs-datagrid", useVirtual && "cs-datagrid--virtual", className),
1227
- style: { maxBlockSize: height, overflow: "auto" },
1228
- onScroll: useVirtual ? (e) => setScrollTop(e.currentTarget.scrollTop) : void 0,
1229
- "data-virtual": useVirtual ? "true" : "false",
1230
- "data-row-count": sorted.length
1231
- },
1232
- /* @__PURE__ */ React.createElement("table", { className: "cs-table" }, caption ? /* @__PURE__ */ React.createElement("caption", null, caption) : null, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, selectable ? /* @__PURE__ */ React.createElement("th", { scope: "col", className: "cs-datagrid__selcol" }, /* @__PURE__ */ React.createElement("input", { type: "checkbox", "aria-label": t("selectAll"), checked: !!allSel, onChange: toggleAll })) : null, orderedColumns.map((c) => /* @__PURE__ */ React.createElement(
1233
- "th",
1234
- {
1235
- key: c.key,
1236
- scope: "col",
1237
- className: c.pinned ? "cs-datagrid__pinned" : void 0,
1238
- style: c.pinned ? { position: "sticky", insetInlineStart: 0, zIndex: 1, background: "var(--cs-color-surface-panel)" } : void 0,
1239
- "aria-sort": sort && sort.key === c.key ? sort.dir === "asc" ? "ascending" : "descending" : void 0
1240
- },
1241
- c.sortable ? /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-datagrid__sort", onClick: () => setSort((s) => !s || s.key !== c.key ? { key: c.key, dir: "asc" } : s.dir === "asc" ? { key: c.key, dir: "desc" } : null) }, c.header, /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, sort && sort.key === c.key ? sort.dir === "asc" ? " ▲" : " ▼" : " ↕")) : c.header,
1242
- persistKey ? /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-datagrid__pin", title: "Pin column first", onClick: () => pinColumn(c.key), "aria-label": "Pin " + c.key }, "⟂") : null
1243
- )))), /* @__PURE__ */ React.createElement("tbody", null, sorted.length === 0 ? /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", { colSpan: orderedColumns.length + (selectable ? 1 : 0), className: "cs-table__empty" }, empty != null ? empty : t("empty"))) : /* @__PURE__ */ React.createElement(React.Fragment, null, padTop > 0 ? /* @__PURE__ */ React.createElement("tr", { "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("td", { colSpan: orderedColumns.length + (selectable ? 1 : 0), style: { height: padTop, padding: 0, border: 0 } })) : null, slice.map((r, i) => {
1244
- const k = r[rowKey] != null ? r[rowKey] : start + i;
1245
- return /* @__PURE__ */ React.createElement("tr", { key: k, className: selected.includes(k) ? "is-selected" : void 0, style: useVirtual ? { height: rowHeight } : void 0 }, selectable ? /* @__PURE__ */ React.createElement("td", { className: "cs-datagrid__selcol" }, /* @__PURE__ */ React.createElement("input", { type: "checkbox", "aria-label": t("selectRow"), checked: selected.includes(k), onChange: () => toggle(k) })) : null, orderedColumns.map((c) => /* @__PURE__ */ React.createElement("td", { key: c.key, className: c.pinned ? "cs-datagrid__pinned" : void 0, style: c.pinned ? { position: "sticky", insetInlineStart: 0, background: "var(--cs-color-surface-panel)" } : void 0 }, c.render ? c.render(r) : r[c.key])));
1246
- }), padBottom > 0 ? /* @__PURE__ */ React.createElement("tr", { "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("td", { colSpan: orderedColumns.length + (selectable ? 1 : 0), style: { height: padBottom, padding: 0, border: 0 } })) : null)))
1247
- );
1248
- }
1249
- Object.assign(__ds_scope, { DataGrid });
1250
- })(); } catch (e) { __ds_ns.__errors.push({ path: "components/datatable/DataGrid.jsx", error: String((e && e.message) || e) }); }
1251
-
1252
1200
  // components/datatable/DataTable.jsx
1253
1201
  try { (() => {
1254
1202
  const { makeT, useLang } = __ds_scope;
@@ -1328,15 +1276,17 @@ Object.assign(__ds_scope, { EmptyState });
1328
1276
  try { (() => {
1329
1277
  const { cx } = __ds_scope;
1330
1278
  function ProgressBar({ value = 0, max = 100, variant, label, className }) {
1331
- const pct = Math.max(0, Math.min(100, value / max * 100));
1279
+ const safeMax = max > 0 ? max : 100;
1280
+ const clamped = Math.max(0, Math.min(safeMax, Number(value) || 0));
1281
+ const pct = Math.max(0, Math.min(100, clamped / safeMax * 100));
1332
1282
  return /* @__PURE__ */ React.createElement(
1333
1283
  "div",
1334
1284
  {
1335
1285
  className: cx("cs-progress", variant && `cs-progress--${variant}`, className),
1336
1286
  role: "progressbar",
1337
- "aria-valuenow": Math.round(value),
1287
+ "aria-valuenow": Math.round(clamped),
1338
1288
  "aria-valuemin": 0,
1339
- "aria-valuemax": max,
1289
+ "aria-valuemax": safeMax,
1340
1290
  "aria-label": label
1341
1291
  },
1342
1292
  /* @__PURE__ */ React.createElement("span", { className: "cs-progress__fill", style: { inlineSize: pct + "%", width: pct + "%" } })
@@ -1492,7 +1442,42 @@ function Cascader({ nodes = [], value = [], onChange, placeholder, label, disabl
1492
1442
  if (wrap.current && !wrap.current.contains(e.target)) setOpen(false);
1493
1443
  };
1494
1444
  const k = (e) => {
1495
- if (e.key === "Escape") setOpen(false);
1445
+ if (e.key === "Escape") {
1446
+ setOpen(false);
1447
+ const field = wrap.current && wrap.current.querySelector(".cs-treeselect__field");
1448
+ field && field.focus && field.focus();
1449
+ return;
1450
+ }
1451
+ if (!wrap.current) return;
1452
+ const opts = [...wrap.current.querySelectorAll('[role="option"]')];
1453
+ if (!opts.length) return;
1454
+ const active = document.activeElement;
1455
+ const idx = opts.indexOf(active);
1456
+ if (e.key === "ArrowDown") {
1457
+ e.preventDefault();
1458
+ (opts[idx < 0 ? 0 : Math.min(opts.length - 1, idx + 1)] || opts[0]).focus();
1459
+ } else if (e.key === "ArrowUp") {
1460
+ e.preventDefault();
1461
+ (opts[idx < 0 ? opts.length - 1 : Math.max(0, idx - 1)] || opts[0]).focus();
1462
+ } else if (e.key === "Home") {
1463
+ e.preventDefault();
1464
+ opts[0].focus();
1465
+ } else if (e.key === "End") {
1466
+ e.preventDefault();
1467
+ opts[opts.length - 1].focus();
1468
+ } else if (e.key === "ArrowRight" && idx >= 0) {
1469
+ active.click && active.click();
1470
+ } else if (e.key === "ArrowLeft") {
1471
+ e.preventDefault();
1472
+ if (path.length) {
1473
+ const next = path.slice(0, -1);
1474
+ setPath(next);
1475
+ } else {
1476
+ setOpen(false);
1477
+ const field = wrap.current.querySelector(".cs-treeselect__field");
1478
+ field && field.focus && field.focus();
1479
+ }
1480
+ }
1496
1481
  };
1497
1482
  document.addEventListener("mousedown", d);
1498
1483
  document.addEventListener("keydown", k);
@@ -1500,7 +1485,7 @@ function Cascader({ nodes = [], value = [], onChange, placeholder, label, disabl
1500
1485
  document.removeEventListener("mousedown", d);
1501
1486
  document.removeEventListener("keydown", k);
1502
1487
  };
1503
- }, [open]);
1488
+ }, [open, path]);
1504
1489
  const cols = [];
1505
1490
  let level = nodes;
1506
1491
  for (let i = 0; level && level.length; i++) {
@@ -1521,7 +1506,27 @@ function Cascader({ nodes = [], value = [], onChange, placeholder, label, disabl
1521
1506
  return /* @__PURE__ */ React.createElement("div", { ref: (el) => {
1522
1507
  wrap.current = el;
1523
1508
  ref.current = el;
1524
- }, className: cx("cs-cascader", className) }, /* @__PURE__ */ React.createElement("button", { type: "button", id: fieldId, className: "cs-treeselect__field", disabled, "aria-haspopup": "listbox", "aria-expanded": open, "aria-label": label, onClick: () => setOpen((o) => !o) }, /* @__PURE__ */ React.createElement("span", { className: labels.length ? void 0 : "ph" }, labels.length ? labels.join(" / ") : ph), /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, "▾")), open ? /* @__PURE__ */ React.createElement("div", { className: "cs-cascader__pop" }, cols.map((col, i) => /* @__PURE__ */ React.createElement("ul", { key: i, role: "listbox", "aria-labelledby": fieldId, className: "cs-cascader__col" }, col.map((n) => (
1509
+ }, className: cx("cs-cascader", className) }, /* @__PURE__ */ React.createElement(
1510
+ "button",
1511
+ {
1512
+ type: "button",
1513
+ id: fieldId,
1514
+ className: "cs-treeselect__field",
1515
+ disabled,
1516
+ "aria-haspopup": "listbox",
1517
+ "aria-expanded": open,
1518
+ "aria-label": label,
1519
+ onClick: () => setOpen((o) => !o),
1520
+ onKeyDown: (e) => {
1521
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
1522
+ e.preventDefault();
1523
+ setOpen(true);
1524
+ }
1525
+ }
1526
+ },
1527
+ /* @__PURE__ */ React.createElement("span", { className: labels.length ? void 0 : "ph" }, labels.length ? labels.join(" / ") : ph),
1528
+ /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, "▾")
1529
+ ), open ? /* @__PURE__ */ React.createElement("div", { className: "cs-cascader__pop" }, cols.map((col, i) => /* @__PURE__ */ React.createElement("ul", { key: i, role: "listbox", "aria-labelledby": fieldId, className: "cs-cascader__col" }, col.map((n) => (
1525
1530
  // role="none" — the <li> wrapper must not sit between listbox and option.
1526
1531
  /* @__PURE__ */ React.createElement("li", { key: n.key, role: "none" }, /* @__PURE__ */ React.createElement(
1527
1532
  "button",
@@ -1530,6 +1535,7 @@ function Cascader({ nodes = [], value = [], onChange, placeholder, label, disabl
1530
1535
  role: "option",
1531
1536
  "aria-selected": path[i] === n.key,
1532
1537
  className: cx("cs-cascader__opt", path[i] === n.key && "on"),
1538
+ "data-cs-focusable": "",
1533
1539
  onClick: () => {
1534
1540
  const next = [...path.slice(0, i), n.key];
1535
1541
  setPath(next);
@@ -1759,8 +1765,24 @@ Object.assign(__ds_scope, { DatePicker });
1759
1765
  try { (() => {
1760
1766
  const { makeT, useLang } = __ds_scope;
1761
1767
  const { cx } = __ds_scope;
1768
+ function sanitizeHtml(html) {
1769
+ if (html == null || html === "") return "";
1770
+ if (typeof document === "undefined") {
1771
+ return String(html).replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, "").replace(/on\w+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, "").replace(/javascript:/gi, "");
1772
+ }
1773
+ const tpl = document.createElement("template");
1774
+ tpl.innerHTML = String(html);
1775
+ tpl.content.querySelectorAll("script,style,iframe,object,embed,link").forEach((n) => n.remove());
1776
+ tpl.content.querySelectorAll("*").forEach((n) => {
1777
+ [...n.attributes].forEach((a) => {
1778
+ if (/^on/i.test(a.name) || /javascript:/i.test(a.value)) n.removeAttribute(a.name);
1779
+ });
1780
+ });
1781
+ return tpl.innerHTML;
1782
+ }
1762
1783
  function Editor({ defaultValue = "", onChange, minHeight = 120, lang, className }) {
1763
1784
  const box = React.useRef(null);
1785
+ const seeded = React.useRef(false);
1764
1786
  const [ref, L] = useLang(lang);
1765
1787
  const t = makeT("Editor", L);
1766
1788
  const cmd = (c) => {
@@ -1771,6 +1793,11 @@ function Editor({ defaultValue = "", onChange, minHeight = 120, lang, className
1771
1793
  const emit = () => {
1772
1794
  onChange && box.current && onChange(box.current.innerHTML);
1773
1795
  };
1796
+ React.useLayoutEffect(() => {
1797
+ if (!box.current || seeded.current) return;
1798
+ box.current.innerHTML = sanitizeHtml(defaultValue);
1799
+ seeded.current = true;
1800
+ }, [defaultValue]);
1774
1801
  const B = ({ c, label, children }) => /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-toolbar__btn", "aria-label": label, onMouseDown: (e) => {
1775
1802
  e.preventDefault();
1776
1803
  cmd(c);
@@ -1786,8 +1813,7 @@ function Editor({ defaultValue = "", onChange, minHeight = 120, lang, className
1786
1813
  "aria-multiline": "true",
1787
1814
  "aria-label": t("area"),
1788
1815
  style: { minHeight },
1789
- onInput: emit,
1790
- dangerouslySetInnerHTML: { __html: defaultValue }
1816
+ onInput: emit
1791
1817
  }
1792
1818
  ));
1793
1819
  }
@@ -1800,6 +1826,7 @@ const { makeT, useLang } = __ds_scope;
1800
1826
  const { cx } = __ds_scope;
1801
1827
  function FileUpload({ title, hint, accept, multiple = false, onFiles, icon, lang, className }) {
1802
1828
  const [drag, setDrag] = React.useState(false);
1829
+ const inputRef = React.useRef(null);
1803
1830
  const pick = (files) => {
1804
1831
  if (files && files.length && onFiles) onFiles(Array.from(files));
1805
1832
  };
@@ -1807,8 +1834,9 @@ function FileUpload({ title, hint, accept, multiple = false, onFiles, icon, lang
1807
1834
  const t = makeT("FileUpload", L);
1808
1835
  const tt = title != null ? title : t("title");
1809
1836
  const hh = hint != null ? hint : t("hint");
1837
+ const id = React.useId();
1810
1838
  return /* @__PURE__ */ React.createElement(
1811
- "label",
1839
+ "div",
1812
1840
  {
1813
1841
  ref,
1814
1842
  className: cx("cs-dropzone", drag && "is-dragging", className),
@@ -1821,12 +1849,26 @@ function FileUpload({ title, hint, accept, multiple = false, onFiles, icon, lang
1821
1849
  e.preventDefault();
1822
1850
  setDrag(false);
1823
1851
  pick(e.dataTransfer.files);
1824
- }
1852
+ },
1853
+ onClick: () => inputRef.current && inputRef.current.click()
1825
1854
  },
1826
- /* @__PURE__ */ React.createElement("span", { className: "cs-dropzone__icon" }, icon ?? /* @__PURE__ */ React.createElement("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("path", { d: "M12 16V4M7 9l5-5 5 5" }), /* @__PURE__ */ React.createElement("path", { d: "M5 16v3a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-3" }))),
1827
- /* @__PURE__ */ React.createElement("span", { className: "cs-dropzone__title" }, tt),
1828
- /* @__PURE__ */ React.createElement("span", { className: "cs-dropzone__hint" }, hh),
1829
- /* @__PURE__ */ React.createElement("input", { type: "file", accept, multiple, style: { display: "none" }, onChange: (e) => pick(e.target.files) })
1855
+ /* @__PURE__ */ React.createElement("span", { className: "cs-dropzone__icon", "aria-hidden": "true" }, icon ?? /* @__PURE__ */ React.createElement("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M12 16V4M7 9l5-5 5 5" }), /* @__PURE__ */ React.createElement("path", { d: "M5 16v3a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-3" }))),
1856
+ /* @__PURE__ */ React.createElement("label", { className: "cs-dropzone__title", htmlFor: id }, tt),
1857
+ /* @__PURE__ */ React.createElement("span", { className: "cs-dropzone__hint", id: id + "-hint" }, hh),
1858
+ /* @__PURE__ */ React.createElement(
1859
+ "input",
1860
+ {
1861
+ id,
1862
+ ref: inputRef,
1863
+ type: "file",
1864
+ accept,
1865
+ multiple,
1866
+ className: "cs-sr-only",
1867
+ "aria-describedby": id + "-hint",
1868
+ onChange: (e) => pick(e.target.files),
1869
+ onClick: (e) => e.stopPropagation()
1870
+ }
1871
+ )
1830
1872
  );
1831
1873
  }
1832
1874
  Object.assign(__ds_scope, { FileUpload });
@@ -2488,8 +2530,24 @@ Object.assign(__ds_scope, { Slider });
2488
2530
  // components/forms/Switch.jsx
2489
2531
  try { (() => {
2490
2532
  const { cx } = __ds_scope;
2491
- function Switch({ label, disabled = false, className, children, ...props }) {
2492
- return /* @__PURE__ */ React.createElement("label", { className: cx("cs-switch", disabled && "is-disabled", className) }, /* @__PURE__ */ React.createElement("input", { type: "checkbox", role: "switch", disabled, ...props }), /* @__PURE__ */ React.createElement("span", { className: "cs-switch__track", "aria-hidden": "true" }), label ? /* @__PURE__ */ React.createElement("span", { className: "cs-switch__label" }, label) : null);
2533
+ let warnedNameless = false;
2534
+ function Switch({ label, disabled = false, className, children, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }) {
2535
+ const named = !!(label || ariaLabel || ariaLabelledby);
2536
+ if (!named && !warnedNameless && typeof console !== "undefined" && console.warn) {
2537
+ warnedNameless = true;
2538
+ console.warn("CyberSkill Switch: render with label, aria-label, or aria-labelledby.");
2539
+ }
2540
+ return /* @__PURE__ */ React.createElement("label", { className: cx("cs-switch", disabled && "is-disabled", className) }, /* @__PURE__ */ React.createElement(
2541
+ "input",
2542
+ {
2543
+ type: "checkbox",
2544
+ role: "switch",
2545
+ disabled,
2546
+ "aria-label": ariaLabel,
2547
+ "aria-labelledby": ariaLabelledby,
2548
+ ...props
2549
+ }
2550
+ ), /* @__PURE__ */ React.createElement("span", { className: "cs-switch__track", "aria-hidden": "true" }), label ? /* @__PURE__ */ React.createElement("span", { className: "cs-switch__label" }, label) : null);
2493
2551
  }
2494
2552
  Object.assign(__ds_scope, { Switch });
2495
2553
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/forms/Switch.jsx", error: String((e && e.message) || e) }); }
@@ -2589,8 +2647,10 @@ const CLOCK = /* @__PURE__ */ React.createElement("svg", { width: "16", height:
2589
2647
  function TimePicker({ value = "09:00", onChange, step = 30, label, disabled = false, lang, className }) {
2590
2648
  const [ref, L] = useLang(lang);
2591
2649
  const t = makeT("TimePicker", L);
2650
+ const stepMin = Number(step);
2651
+ const safeStep = Number.isFinite(stepMin) && stepMin > 0 ? stepMin : 30;
2592
2652
  const opts = [];
2593
- for (let m = 0; m < 24 * 60; m += step) {
2653
+ for (let m = 0; m < 24 * 60; m += safeStep) {
2594
2654
  opts.push(String(Math.floor(m / 60)).padStart(2, "0") + ":" + String(m % 60).padStart(2, "0"));
2595
2655
  }
2596
2656
  return /* @__PURE__ */ React.createElement("span", { ref, className: cx("cs-timepicker", className) }, CLOCK, /* @__PURE__ */ React.createElement("select", { "aria-label": label != null ? label : t("label"), disabled, value, onChange: (e) => onChange && onChange(e.target.value) }, opts.map((o) => /* @__PURE__ */ React.createElement("option", { key: o, value: o }, o))));
@@ -2730,7 +2790,8 @@ const CS_ICONS = {
2730
2790
  edit: { viewBox: "0 0 24 24", els: [["path", { d: "M4 20h4L18.5 9.5a2.12 2.12 0 0 0-3-3L5 17z" }], ["path", { d: "M13.5 6.5l3 3" }]] },
2731
2791
  copy: { viewBox: "0 0 24 24", els: [["rect", { x: 8, y: 8, width: 12, height: 12, rx: 2 }], ["path", { d: "M4 16V6a2 2 0 0 1 2-2h10" }]] },
2732
2792
  info: { viewBox: "0 0 24 24", els: [["circle", { cx: 12, cy: 12, r: 9 }], ["path", { d: "M12 11v5M12 7.75v.01" }]] },
2733
- "alert-triangle": { viewBox: "0 0 24 24", els: [["path", { d: "M12 3.5l9 16H3z" }], ["path", { d: "M12 10v4M12 17.5v.01" }]] }
2793
+ "alert-triangle": { viewBox: "0 0 24 24", els: [["path", { d: "M12 3.5l9 16H3z" }], ["path", { d: "M12 10v4M12 17.5v.01" }]] },
2794
+ pin: { viewBox: "0 0 24 24", els: [["path", { d: "M12 21v-7" }], ["path", { d: "M8.5 3.5h7l-1.2 6.5h2.7L12 14.5 6.999 10h2.7z" }]] }
2734
2795
  };
2735
2796
  function Icon({ name, size = "md", label, className, strokeWidth = 1.75, ...props }) {
2736
2797
  const def = CS_ICONS[name] || CS_ICONS.sparkle;
@@ -2791,102 +2852,134 @@ function Image({ src, alt = "", ratio, preview = false, fallback, lang, classNam
2791
2852
  Object.assign(__ds_scope, { Image });
2792
2853
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/data/Image.jsx", error: String((e && e.message) || e) }); }
2793
2854
 
2794
- // components/dialog/Dialog.jsx
2855
+ // components/datatable/DataGrid.jsx
2795
2856
  try { (() => {
2796
2857
  const { makeT, useLang } = __ds_scope;
2797
2858
  const { Icon } = __ds_scope;
2798
2859
  const { cx } = __ds_scope;
2799
- const FOCUSABLE = [
2800
- "a[href]",
2801
- "area[href]",
2802
- "button:not([disabled])",
2803
- 'input:not([disabled]):not([type="hidden"])',
2804
- "select:not([disabled])",
2805
- "textarea:not([disabled])",
2806
- "audio[controls]",
2807
- "video[controls]",
2808
- "summary",
2809
- "iframe",
2810
- '[contenteditable]:not([contenteditable="false"])',
2811
- '[tabindex]:not([tabindex="-1"])'
2812
- ].join(",");
2813
- function Dialog({
2814
- open,
2815
- title,
2816
- children,
2817
- actions,
2818
- onClose,
2819
- className,
2820
- closeLabel,
2860
+ function DataGrid({
2861
+ columns = [],
2862
+ rows = [],
2863
+ rowKey = "id",
2864
+ selectable = false,
2865
+ selected = [],
2866
+ onSelect,
2867
+ height = 280,
2868
+ caption,
2869
+ empty,
2821
2870
  lang,
2822
- ...props
2871
+ className,
2872
+ filterText,
2873
+ filterKeys,
2874
+ /** When true (or rows exceed virtualThreshold), only paint a window of rows. */
2875
+ virtual = false,
2876
+ /** Row threshold that auto-enables virtualization. Default 80. */
2877
+ virtualThreshold = 80,
2878
+ /** Approximate row height for windowing. Default 36. */
2879
+ rowHeight = 36,
2880
+ /** localStorage key — when set, column key order is persisted across reloads. */
2881
+ persistKey
2823
2882
  }) {
2824
- const baseId = React.useId();
2825
- const titleId = baseId + "-title";
2826
- const bodyId = children == null ? void 0 : baseId + "-body";
2883
+ const [sort, setSort] = React.useState(null);
2884
+ const [scrollTop, setScrollTop] = React.useState(0);
2885
+ const [colOrder, setColOrder] = React.useState(() => {
2886
+ if (!persistKey) return null;
2887
+ try {
2888
+ const raw = localStorage.getItem("cs:datagrid:cols:" + persistKey);
2889
+ const arr = raw ? JSON.parse(raw) : null;
2890
+ return Array.isArray(arr) ? arr : null;
2891
+ } catch (e) {
2892
+ return null;
2893
+ }
2894
+ });
2827
2895
  const [ref, L] = useLang(lang);
2828
- const panel = React.useRef(null);
2829
- const closeRef = React.useRef(onClose);
2830
- closeRef.current = onClose;
2831
- React.useEffect(() => {
2832
- if (!open) return;
2833
- const prev = document.activeElement;
2834
- const prevOverflow = document.body.style.overflow;
2835
- document.body.style.overflow = "hidden";
2836
- const focusables = () => panel.current ? [...panel.current.querySelectorAll(FOCUSABLE)] : [];
2837
- const first = focusables()[0];
2838
- (first || panel.current) && (first || panel.current).focus();
2839
- const k = (e) => {
2840
- if (e.key === "Escape") {
2841
- closeRef.current && closeRef.current();
2842
- return;
2843
- }
2844
- if (e.key !== "Tab" || !panel.current) return;
2845
- const f = focusables();
2846
- if (!f.length) {
2847
- e.preventDefault();
2848
- panel.current.focus();
2849
- return;
2850
- }
2851
- const a = f[0], z = f[f.length - 1];
2852
- const active = document.activeElement;
2853
- const inside = panel.current.contains(active);
2854
- if (e.shiftKey && (!inside || active === a)) {
2855
- e.preventDefault();
2856
- z.focus();
2857
- } else if (!e.shiftKey && (!inside || active === z)) {
2858
- e.preventDefault();
2859
- a.focus();
2860
- }
2861
- };
2862
- document.addEventListener("keydown", k);
2863
- return () => {
2864
- document.removeEventListener("keydown", k);
2865
- document.body.style.overflow = prevOverflow;
2866
- if (prev && prev.focus) prev.focus();
2867
- };
2868
- }, [open]);
2869
- const cl = closeLabel != null ? closeLabel : makeT("Dialog", L)("close");
2870
- if (!open) return null;
2871
- return /* @__PURE__ */ React.createElement("div", { ref, className: "cs-dialog-layer" }, /* @__PURE__ */ React.createElement("div", { className: "cs-dialog__overlay", onClick: onClose, "aria-hidden": "true" }), /* @__PURE__ */ React.createElement(
2872
- "section",
2896
+ const t = makeT("DataGrid", L);
2897
+ const orderedColumns = React.useMemo(() => {
2898
+ if (!colOrder || !colOrder.length) return columns;
2899
+ const map = new Map(columns.map((c) => [c.key, c]));
2900
+ const out = [];
2901
+ for (const k of colOrder) if (map.has(k)) {
2902
+ out.push(map.get(k));
2903
+ map.delete(k);
2904
+ }
2905
+ for (const c of map.values()) out.push(c);
2906
+ return out;
2907
+ }, [columns, colOrder]);
2908
+ const filtered = React.useMemo(() => {
2909
+ const q = (filterText == null ? "" : String(filterText)).trim().toLowerCase();
2910
+ if (!q) return rows;
2911
+ const keys = filterKeys && filterKeys.length ? filterKeys : orderedColumns.map((c) => c.key);
2912
+ return rows.filter((r) => keys.some((k) => String(r[k] == null ? "" : r[k]).toLowerCase().includes(q)));
2913
+ }, [rows, filterText, filterKeys, orderedColumns]);
2914
+ const sorted = React.useMemo(() => {
2915
+ if (!sort) return filtered;
2916
+ const col = orderedColumns.find((c) => c.key === sort.key);
2917
+ const val = (r) => col && col.sortValue ? col.sortValue(r) : r[sort.key];
2918
+ return [...filtered].sort((a, b) => {
2919
+ const x = val(a), y = val(b);
2920
+ return (x > y ? 1 : x < y ? -1 : 0) * (sort.dir === "asc" ? 1 : -1);
2921
+ });
2922
+ }, [filtered, sort, orderedColumns]);
2923
+ const useVirtual = virtual || sorted.length >= virtualThreshold;
2924
+ const bodyH = Math.max(0, height - 40);
2925
+ const start = useVirtual ? Math.max(0, Math.floor(scrollTop / rowHeight) - 4) : 0;
2926
+ const visibleCount = useVirtual ? Math.ceil(bodyH / rowHeight) + 8 : sorted.length;
2927
+ const end = useVirtual ? Math.min(sorted.length, start + visibleCount) : sorted.length;
2928
+ const slice = sorted.slice(start, end);
2929
+ const padTop = useVirtual ? start * rowHeight : 0;
2930
+ const padBottom = useVirtual ? Math.max(0, (sorted.length - end) * rowHeight) : 0;
2931
+ const allSel = selectable && filtered.length && filtered.every((r) => selected.includes(r[rowKey]));
2932
+ const toggleAll = () => onSelect && onSelect(allSel ? [] : filtered.map((r) => r[rowKey]));
2933
+ const toggle = (k) => onSelect && onSelect(selected.includes(k) ? selected.filter((x) => x !== k) : [...selected, k]);
2934
+ const pinColumn = (key) => {
2935
+ if (!persistKey) return;
2936
+ const keys = orderedColumns.map((c) => c.key);
2937
+ const next = [key, ...keys.filter((k) => k !== key)];
2938
+ setColOrder(next);
2939
+ try {
2940
+ localStorage.setItem("cs:datagrid:cols:" + persistKey, JSON.stringify(next));
2941
+ } catch (e) {
2942
+ }
2943
+ };
2944
+ return /* @__PURE__ */ React.createElement(
2945
+ "div",
2873
2946
  {
2874
- ...props,
2875
- ref: panel,
2876
- tabIndex: -1,
2877
- role: "dialog",
2878
- "aria-modal": "true",
2879
- "aria-labelledby": titleId,
2880
- "aria-describedby": bodyId != null ? bodyId : props["aria-describedby"],
2881
- className: cx("cs-dialog", className)
2947
+ ref,
2948
+ className: cx("cs-datagrid", useVirtual && "cs-datagrid--virtual", className),
2949
+ style: { maxBlockSize: height, overflow: "auto" },
2950
+ onScroll: useVirtual ? (e) => setScrollTop(e.currentTarget.scrollTop) : void 0,
2951
+ "data-virtual": useVirtual ? "true" : "false",
2952
+ "data-row-count": sorted.length
2882
2953
  },
2883
- /* @__PURE__ */ React.createElement("header", { className: "cs-dialog__header" }, /* @__PURE__ */ React.createElement("h2", { id: titleId, className: "cs-dialog__title" }, title), onClose ? /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-button cs-button--ghost cs-button--sm", onClick: onClose, "aria-label": cl }, /* @__PURE__ */ React.createElement(Icon, { name: "close", size: "sm" })) : null),
2884
- /* @__PURE__ */ React.createElement("div", { id: bodyId, className: "cs-dialog__body" }, children),
2885
- actions ? /* @__PURE__ */ React.createElement("footer", { className: "cs-dialog__actions" }, actions) : null
2886
- ));
2954
+ /* @__PURE__ */ React.createElement("table", { className: "cs-table" }, caption ? /* @__PURE__ */ React.createElement("caption", null, caption) : null, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, selectable ? /* @__PURE__ */ React.createElement("th", { scope: "col", className: "cs-datagrid__selcol" }, /* @__PURE__ */ React.createElement("input", { type: "checkbox", "aria-label": t("selectAll"), checked: !!allSel, onChange: toggleAll })) : null, orderedColumns.map((c) => /* @__PURE__ */ React.createElement(
2955
+ "th",
2956
+ {
2957
+ key: c.key,
2958
+ scope: "col",
2959
+ className: c.pinned ? "cs-datagrid__pinned" : void 0,
2960
+ style: c.pinned ? { position: "sticky", insetInlineStart: 0, zIndex: 1, background: "var(--cs-color-surface-panel)" } : void 0,
2961
+ "aria-sort": sort && sort.key === c.key ? sort.dir === "asc" ? "ascending" : "descending" : void 0
2962
+ },
2963
+ c.sortable ? /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-datagrid__sort", onClick: () => setSort((s) => !s || s.key !== c.key ? { key: c.key, dir: "asc" } : s.dir === "asc" ? { key: c.key, dir: "desc" } : null) }, c.header, /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, sort && sort.key === c.key ? sort.dir === "asc" ? " ▲" : " ▼" : " ↕")) : c.header,
2964
+ persistKey ? /* @__PURE__ */ React.createElement(
2965
+ "button",
2966
+ {
2967
+ type: "button",
2968
+ className: "cs-datagrid__pin",
2969
+ title: t("pin"),
2970
+ onClick: () => pinColumn(c.key),
2971
+ "aria-label": t("pinNamed").replace("{name}", String(c.header != null ? c.header : c.key))
2972
+ },
2973
+ /* @__PURE__ */ React.createElement(Icon, { name: "pin", size: "sm" })
2974
+ ) : null
2975
+ )))), /* @__PURE__ */ React.createElement("tbody", null, sorted.length === 0 ? /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", { colSpan: orderedColumns.length + (selectable ? 1 : 0), className: "cs-table__empty" }, empty != null ? empty : t("empty"))) : /* @__PURE__ */ React.createElement(React.Fragment, null, padTop > 0 ? /* @__PURE__ */ React.createElement("tr", { "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("td", { colSpan: orderedColumns.length + (selectable ? 1 : 0), style: { height: padTop, padding: 0, border: 0 } })) : null, slice.map((r, i) => {
2976
+ const k = r[rowKey] != null ? r[rowKey] : start + i;
2977
+ return /* @__PURE__ */ React.createElement("tr", { key: k, className: selected.includes(k) ? "is-selected" : void 0, style: useVirtual ? { height: rowHeight } : void 0 }, selectable ? /* @__PURE__ */ React.createElement("td", { className: "cs-datagrid__selcol" }, /* @__PURE__ */ React.createElement("input", { type: "checkbox", "aria-label": t("selectRow"), checked: selected.includes(k), onChange: () => toggle(k) })) : null, orderedColumns.map((c) => /* @__PURE__ */ React.createElement("td", { key: c.key, className: c.pinned ? "cs-datagrid__pinned" : void 0, style: c.pinned ? { position: "sticky", insetInlineStart: 0, background: "var(--cs-color-surface-panel)" } : void 0 }, c.render ? c.render(r) : r[c.key])));
2978
+ }), padBottom > 0 ? /* @__PURE__ */ React.createElement("tr", { "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("td", { colSpan: orderedColumns.length + (selectable ? 1 : 0), style: { height: padBottom, padding: 0, border: 0 } })) : null)))
2979
+ );
2887
2980
  }
2888
- Object.assign(__ds_scope, { Dialog });
2889
- })(); } catch (e) { __ds_ns.__errors.push({ path: "components/dialog/Dialog.jsx", error: String((e && e.message) || e) }); }
2981
+ Object.assign(__ds_scope, { DataGrid });
2982
+ })(); } catch (e) { __ds_ns.__errors.push({ path: "components/datatable/DataGrid.jsx", error: String((e && e.message) || e) }); }
2890
2983
 
2891
2984
  // components/logo/logo-data.js
2892
2985
  try { (() => {
@@ -3193,37 +3286,6 @@ function Breadcrumb({ items = [], lang, className, ...props }) {
3193
3286
  Object.assign(__ds_scope, { Breadcrumb });
3194
3287
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/navigation/Breadcrumb.jsx", error: String((e && e.message) || e) }); }
3195
3288
 
3196
- // components/navigation/CommandPalette.jsx
3197
- try { (() => {
3198
- const { makeT, useLang } = __ds_scope;
3199
- const { cx } = __ds_scope;
3200
- function CommandPalette({ open, onClose, placeholder, groups = [], lang, className }) {
3201
- const [q, setQ] = React.useState("");
3202
- React.useEffect(() => {
3203
- if (!open) return;
3204
- const onKey = (e) => {
3205
- if (e.key === "Escape") onClose && onClose();
3206
- };
3207
- document.addEventListener("keydown", onKey);
3208
- return () => document.removeEventListener("keydown", onKey);
3209
- }, [open]);
3210
- const [ref, L] = useLang(lang);
3211
- const t = makeT("CommandPalette", L);
3212
- const ph = placeholder != null ? placeholder : t("placeholder");
3213
- if (!open) return null;
3214
- const needle = q.trim().toLowerCase();
3215
- return /* @__PURE__ */ React.createElement("div", { ref, className: "cs-cmdk-scrim", onClick: onClose }, /* @__PURE__ */ React.createElement("div", { className: cx("cs-cmdk", className), role: "dialog", "aria-modal": "true", "aria-label": t("aria"), onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React.createElement("div", { className: "cs-cmdk__search" }, /* @__PURE__ */ React.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("circle", { cx: "11", cy: "11", r: "7" }), /* @__PURE__ */ React.createElement("path", { d: "M21 21l-4.3-4.3" })), /* @__PURE__ */ React.createElement("input", { autoFocus: true, value: q, onChange: (e) => setQ(e.target.value), placeholder: ph }), /* @__PURE__ */ React.createElement("span", { className: "cs-kbd" }, t("esc"))), /* @__PURE__ */ React.createElement("div", { className: "cs-cmdk__list" }, groups.map((g, gi) => {
3216
- const items = (g.items || []).filter((it) => !needle || String(it.label).toLowerCase().includes(needle));
3217
- if (!items.length) return null;
3218
- return /* @__PURE__ */ React.createElement(React.Fragment, { key: gi }, g.label ? /* @__PURE__ */ React.createElement("div", { className: "cs-cmdk__label" }, g.label) : null, items.map((it, ii) => /* @__PURE__ */ React.createElement("button", { key: ii, type: "button", className: "cs-cmdk__item", onClick: () => {
3219
- it.onSelect && it.onSelect();
3220
- onClose && onClose();
3221
- } }, it.icon ? /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, it.icon) : null, /* @__PURE__ */ React.createElement("span", null, it.label), it.shortcut ? /* @__PURE__ */ React.createElement("span", { className: "cs-kbd" }, it.shortcut) : null)));
3222
- }))));
3223
- }
3224
- Object.assign(__ds_scope, { CommandPalette });
3225
- })(); } catch (e) { __ds_ns.__errors.push({ path: "components/navigation/CommandPalette.jsx", error: String((e && e.message) || e) }); }
3226
-
3227
3289
  // components/navigation/Dock.jsx
3228
3290
  try { (() => {
3229
3291
  const { cx } = __ds_scope;
@@ -3567,7 +3629,8 @@ function Toolbar({ items = [], overflowAfter, label, lang, className }) {
3567
3629
  const [ref, L] = useLang(lang);
3568
3630
  const t = makeT("Toolbar", L);
3569
3631
  const cut = overflowAfter != null ? overflowAfter : items.length;
3570
- const head = items.slice(0, cut), tail = items.filter((x) => x !== "-").slice(cut);
3632
+ const head = items.slice(0, cut);
3633
+ const tail = items.slice(cut).filter((x) => x !== "-");
3571
3634
  React.useEffect(() => {
3572
3635
  if (!open) return;
3573
3636
  const d = (e) => {
@@ -3587,11 +3650,71 @@ function Toolbar({ items = [], overflowAfter, label, lang, className }) {
3587
3650
  Object.assign(__ds_scope, { Toolbar });
3588
3651
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/navigation/Toolbar.jsx", error: String((e && e.message) || e) }); }
3589
3652
 
3590
- // components/overlays/AlertDialog.jsx
3653
+ // components/overlays/ContextMenu.jsx
3654
+ try { (() => {
3655
+ const { cx } = __ds_scope;
3656
+ function ContextMenu({ items = [], children, className }) {
3657
+ const [pos, setPos] = React.useState(null);
3658
+ React.useEffect(() => {
3659
+ if (!pos) return;
3660
+ const close = () => setPos(null);
3661
+ const k = (e) => {
3662
+ if (e.key === "Escape") setPos(null);
3663
+ };
3664
+ document.addEventListener("click", close);
3665
+ document.addEventListener("keydown", k);
3666
+ return () => {
3667
+ document.removeEventListener("click", close);
3668
+ document.removeEventListener("keydown", k);
3669
+ };
3670
+ }, [pos]);
3671
+ return /* @__PURE__ */ React.createElement(
3672
+ "div",
3673
+ {
3674
+ className: cx("cs-ctxmenu-zone", className),
3675
+ onContextMenu: (e) => {
3676
+ e.preventDefault();
3677
+ const r = e.currentTarget.getBoundingClientRect();
3678
+ setPos({ x: e.clientX - r.left, y: e.clientY - r.top });
3679
+ }
3680
+ },
3681
+ children,
3682
+ pos ? /* @__PURE__ */ React.createElement("div", { className: "cs-menu__list", role: "menu", style: { position: "absolute", insetInlineStart: pos.x, insetBlockStart: pos.y } }, items.map((it, i) => it === "-" ? /* @__PURE__ */ React.createElement("div", { key: i, className: "cs-menu__sep" }) : /* @__PURE__ */ React.createElement("button", { key: i, type: "button", role: "menuitem", className: cx("cs-menu__item", it.danger && "cs-menu__item--danger"), onClick: () => {
3683
+ setPos(null);
3684
+ it.onSelect && it.onSelect();
3685
+ } }, it.label))) : null
3686
+ );
3687
+ }
3688
+ Object.assign(__ds_scope, { ContextMenu });
3689
+ })(); } catch (e) { __ds_ns.__errors.push({ path: "components/overlays/ContextMenu.jsx", error: String((e && e.message) || e) }); }
3690
+
3691
+ // components/overlays/HoverCard.jsx
3591
3692
  try { (() => {
3592
- const { makeT, useLang } = __ds_scope;
3593
3693
  const { cx } = __ds_scope;
3594
- const FOCUSABLE = [
3694
+ function HoverCard({ trigger, children, openDelay = 150, closeDelay = 200, className }) {
3695
+ const [open, setOpen] = React.useState(false);
3696
+ const t1 = React.useRef();
3697
+ const t2 = React.useRef();
3698
+ const show = () => {
3699
+ clearTimeout(t2.current);
3700
+ t1.current = setTimeout(() => setOpen(true), openDelay);
3701
+ };
3702
+ const hide = () => {
3703
+ clearTimeout(t1.current);
3704
+ t2.current = setTimeout(() => setOpen(false), closeDelay);
3705
+ };
3706
+ React.useEffect(() => () => {
3707
+ clearTimeout(t1.current);
3708
+ clearTimeout(t2.current);
3709
+ }, []);
3710
+ return /* @__PURE__ */ React.createElement("span", { className: cx("cs-hovercard", className), onMouseEnter: show, onMouseLeave: hide, onFocus: show, onBlur: hide }, trigger, open ? /* @__PURE__ */ React.createElement("span", { className: "cs-hovercard__panel", role: "dialog" }, children) : null);
3711
+ }
3712
+ Object.assign(__ds_scope, { HoverCard });
3713
+ })(); } catch (e) { __ds_ns.__errors.push({ path: "components/overlays/HoverCard.jsx", error: String((e && e.message) || e) }); }
3714
+
3715
+ // components/overlays/OverlayManager.jsx
3716
+ try { (() => {
3717
+ const focusableSelector = [
3595
3718
  "a[href]",
3596
3719
  "area[href]",
3597
3720
  "button:not([disabled])",
@@ -3605,6 +3728,270 @@ const FOCUSABLE = [
3605
3728
  '[contenteditable]:not([contenteditable="false"])',
3606
3729
  '[tabindex]:not([tabindex="-1"])'
3607
3730
  ].join(",");
3731
+ function attachFocusTrap(panelEl, { handleEscape = false, onEscape } = {}) {
3732
+ if (!panelEl) return () => {
3733
+ };
3734
+ const focusables = () => [...panelEl.querySelectorAll(focusableSelector)];
3735
+ const k = (e) => {
3736
+ if (handleEscape && e.key === "Escape") {
3737
+ onEscape && onEscape();
3738
+ return;
3739
+ }
3740
+ if (e.key !== "Tab") return;
3741
+ const f = focusables();
3742
+ if (!f.length) {
3743
+ e.preventDefault();
3744
+ panelEl.focus();
3745
+ return;
3746
+ }
3747
+ const a = f[0];
3748
+ const z = f[f.length - 1];
3749
+ const active = document.activeElement;
3750
+ const inside = panelEl.contains(active);
3751
+ if (e.shiftKey && (!inside || active === a)) {
3752
+ e.preventDefault();
3753
+ z.focus();
3754
+ } else if (!e.shiftKey && (!inside || active === z)) {
3755
+ e.preventDefault();
3756
+ a.focus();
3757
+ }
3758
+ };
3759
+ document.addEventListener("keydown", k);
3760
+ return () => document.removeEventListener("keydown", k);
3761
+ }
3762
+ function createOverlayManager() {
3763
+ const layers = [];
3764
+ let prevOverflow = "";
3765
+ let locked = false;
3766
+ let escapeBound = false;
3767
+ const resort = () => {
3768
+ layers.sort((a, b) => {
3769
+ const pa = a.panelEl;
3770
+ const pb = b.panelEl;
3771
+ if (pa && pb && pa !== pb) {
3772
+ if (pa.contains(pb)) return -1;
3773
+ if (pb.contains(pa)) return 1;
3774
+ }
3775
+ return (a.seq || 0) - (b.seq || 0);
3776
+ });
3777
+ };
3778
+ const applyScroll = () => {
3779
+ const need = layers.some((l) => l.kind === "modal" && l.lockScroll !== false);
3780
+ if (need && !locked) {
3781
+ prevOverflow = document.body.style.overflow;
3782
+ document.body.style.overflow = "hidden";
3783
+ locked = true;
3784
+ } else if (!need && locked) {
3785
+ document.body.style.overflow = prevOverflow;
3786
+ locked = false;
3787
+ }
3788
+ };
3789
+ const onDocEscape = (e) => {
3790
+ if (e.key !== "Escape") return;
3791
+ if (!layers.length) return;
3792
+ resort();
3793
+ const top = layers[layers.length - 1];
3794
+ if (!top || typeof top.onEscape !== "function") return;
3795
+ e.preventDefault();
3796
+ e.stopPropagation();
3797
+ top.onEscape();
3798
+ };
3799
+ const ensureEscape = () => {
3800
+ if (escapeBound) return;
3801
+ escapeBound = true;
3802
+ document.addEventListener("keydown", onDocEscape, true);
3803
+ };
3804
+ let seq = 0;
3805
+ return {
3806
+ register(layer) {
3807
+ ensureEscape();
3808
+ const id = layer.id || `cs-ov-${++seq}`;
3809
+ const entry = { ...layer, id, seq: ++seq };
3810
+ layers.push(entry);
3811
+ resort();
3812
+ applyScroll();
3813
+ return () => {
3814
+ resort();
3815
+ const i = layers.findIndex((l) => l.id === id);
3816
+ const wasTop = i === layers.length - 1;
3817
+ if (i >= 0) layers.splice(i, 1);
3818
+ applyScroll();
3819
+ if (wasTop && entry.restoreEl && typeof entry.restoreEl.focus === "function") {
3820
+ try {
3821
+ entry.restoreEl.focus();
3822
+ } catch {
3823
+ }
3824
+ }
3825
+ };
3826
+ },
3827
+ top() {
3828
+ resort();
3829
+ return layers[layers.length - 1] || null;
3830
+ },
3831
+ get scrollLocked() {
3832
+ return locked;
3833
+ },
3834
+ get depth() {
3835
+ return layers.length;
3836
+ }
3837
+ };
3838
+ }
3839
+ const defaultManager = createOverlayManager();
3840
+ const OverlayContext = React.createContext(null);
3841
+ function getOverlayManager() {
3842
+ return defaultManager;
3843
+ }
3844
+ function OverlayProvider({ children }) {
3845
+ const api = React.useMemo(() => createOverlayManager(), []);
3846
+ return /* @__PURE__ */ React.createElement(OverlayContext.Provider, { value: api }, /* @__PURE__ */ React.createElement("div", { id: "cs-overlay-root", "data-cs-overlay-root": "" }), children);
3847
+ }
3848
+ function useOverlayLayer({
3849
+ open,
3850
+ kind = "modal",
3851
+ trapFocus = false,
3852
+ lockScroll,
3853
+ onEscape,
3854
+ panelRef,
3855
+ preferFocusSelector
3856
+ }) {
3857
+ const ctx = React.useContext(OverlayContext);
3858
+ const mgr = ctx || defaultManager;
3859
+ const escapeRef = React.useRef(onEscape);
3860
+ escapeRef.current = onEscape;
3861
+ React.useLayoutEffect(() => {
3862
+ if (!open) return void 0;
3863
+ const restoreEl = typeof document !== "undefined" ? document.activeElement : null;
3864
+ const panel = panelRef && panelRef.current;
3865
+ const unregister = mgr.register({
3866
+ kind,
3867
+ lockScroll: lockScroll != null ? lockScroll : kind === "modal",
3868
+ onEscape: () => escapeRef.current && escapeRef.current(),
3869
+ restoreEl,
3870
+ panelEl: panel || null
3871
+ });
3872
+ let detachTrap = () => {
3873
+ };
3874
+ const top = mgr.top();
3875
+ const isTop = top && top.panelEl === panel;
3876
+ if (trapFocus && panel && isTop) {
3877
+ const preferred = preferFocusSelector && panel.querySelector(preferFocusSelector) || panel.querySelector(focusableSelector) || panel;
3878
+ preferred && preferred.focus && preferred.focus();
3879
+ detachTrap = attachFocusTrap(panel, { handleEscape: false });
3880
+ }
3881
+ return () => {
3882
+ detachTrap();
3883
+ unregister();
3884
+ };
3885
+ }, [open, kind, trapFocus, lockScroll, mgr, panelRef, preferFocusSelector]);
3886
+ return { manager: mgr };
3887
+ }
3888
+ Object.assign(__ds_scope, { focusableSelector, attachFocusTrap, getOverlayManager, OverlayProvider, useOverlayLayer });
3889
+ })(); } catch (e) { __ds_ns.__errors.push({ path: "components/overlays/OverlayManager.jsx", error: String((e && e.message) || e) }); }
3890
+
3891
+ // components/dialog/Dialog.jsx
3892
+ try { (() => {
3893
+ const { makeT, useLang } = __ds_scope;
3894
+ const { Icon } = __ds_scope;
3895
+ const { cx } = __ds_scope;
3896
+ const { useOverlayLayer } = __ds_scope;
3897
+ function Dialog({
3898
+ open,
3899
+ title,
3900
+ children,
3901
+ actions,
3902
+ onClose,
3903
+ className,
3904
+ closeLabel,
3905
+ lang,
3906
+ ...props
3907
+ }) {
3908
+ const baseId = React.useId();
3909
+ const titleId = baseId + "-title";
3910
+ const bodyId = children == null ? void 0 : baseId + "-body";
3911
+ const [ref, L] = useLang(lang);
3912
+ const panel = React.useRef(null);
3913
+ const closeRef = React.useRef(onClose);
3914
+ closeRef.current = onClose;
3915
+ useOverlayLayer({
3916
+ open: !!open,
3917
+ kind: "modal",
3918
+ trapFocus: true,
3919
+ onEscape: () => closeRef.current && closeRef.current(),
3920
+ panelRef: panel
3921
+ });
3922
+ const cl = closeLabel != null ? closeLabel : makeT("Dialog", L)("close");
3923
+ if (!open) return null;
3924
+ return /* @__PURE__ */ React.createElement("div", { ref, className: "cs-dialog-layer" }, /* @__PURE__ */ React.createElement("div", { className: "cs-dialog__overlay", onClick: onClose, "aria-hidden": "true" }), /* @__PURE__ */ React.createElement(
3925
+ "section",
3926
+ {
3927
+ ...props,
3928
+ ref: panel,
3929
+ tabIndex: -1,
3930
+ role: "dialog",
3931
+ "aria-modal": "true",
3932
+ "aria-labelledby": titleId,
3933
+ "aria-describedby": bodyId != null ? bodyId : props["aria-describedby"],
3934
+ className: cx("cs-dialog", className)
3935
+ },
3936
+ /* @__PURE__ */ React.createElement("header", { className: "cs-dialog__header" }, /* @__PURE__ */ React.createElement("h2", { id: titleId, className: "cs-dialog__title" }, title), onClose ? /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-button cs-button--ghost cs-button--sm", onClick: onClose, "aria-label": cl }, /* @__PURE__ */ React.createElement(Icon, { name: "close", size: "sm" })) : null),
3937
+ /* @__PURE__ */ React.createElement("div", { id: bodyId, className: "cs-dialog__body" }, children),
3938
+ actions ? /* @__PURE__ */ React.createElement("footer", { className: "cs-dialog__actions" }, actions) : null
3939
+ ));
3940
+ }
3941
+ Object.assign(__ds_scope, { Dialog });
3942
+ })(); } catch (e) { __ds_ns.__errors.push({ path: "components/dialog/Dialog.jsx", error: String((e && e.message) || e) }); }
3943
+
3944
+ // components/navigation/CommandPalette.jsx
3945
+ try { (() => {
3946
+ const { makeT, useLang } = __ds_scope;
3947
+ const { cx } = __ds_scope;
3948
+ const { useOverlayLayer } = __ds_scope;
3949
+ function CommandPalette({ open, onClose, placeholder, groups = [], lang, className }) {
3950
+ const [q, setQ] = React.useState("");
3951
+ const panel = React.useRef(null);
3952
+ const closeRef = React.useRef(onClose);
3953
+ closeRef.current = onClose;
3954
+ useOverlayLayer({
3955
+ open: !!open,
3956
+ kind: "modal",
3957
+ trapFocus: true,
3958
+ preferFocusSelector: ".cs-cmdk__search input",
3959
+ onEscape: () => closeRef.current && closeRef.current(),
3960
+ panelRef: panel
3961
+ });
3962
+ const [ref, L] = useLang(lang);
3963
+ const t = makeT("CommandPalette", L);
3964
+ const ph = placeholder != null ? placeholder : t("placeholder");
3965
+ if (!open) return null;
3966
+ const needle = q.trim().toLowerCase();
3967
+ return /* @__PURE__ */ React.createElement(
3968
+ "div",
3969
+ {
3970
+ ref: (el) => {
3971
+ ref.current = el;
3972
+ panel.current = el;
3973
+ },
3974
+ className: "cs-cmdk-scrim",
3975
+ onClick: onClose
3976
+ },
3977
+ /* @__PURE__ */ React.createElement("div", { className: cx("cs-cmdk", className), role: "dialog", "aria-modal": "true", "aria-label": t("aria"), onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React.createElement("div", { className: "cs-cmdk__search" }, /* @__PURE__ */ React.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true" }, /* @__PURE__ */ React.createElement("circle", { cx: "11", cy: "11", r: "7" }), /* @__PURE__ */ React.createElement("path", { d: "M21 21l-4.3-4.3" })), /* @__PURE__ */ React.createElement("input", { autoFocus: true, value: q, onChange: (e) => setQ(e.target.value), placeholder: ph }), /* @__PURE__ */ React.createElement("span", { className: "cs-kbd" }, t("esc"))), /* @__PURE__ */ React.createElement("div", { className: "cs-cmdk__list" }, groups.map((g, gi) => {
3978
+ const items = (g.items || []).filter((it) => !needle || String(it.label).toLowerCase().includes(needle));
3979
+ if (!items.length) return null;
3980
+ return /* @__PURE__ */ React.createElement(React.Fragment, { key: gi }, g.label ? /* @__PURE__ */ React.createElement("div", { className: "cs-cmdk__label" }, g.label) : null, items.map((it, ii) => /* @__PURE__ */ React.createElement("button", { key: ii, type: "button", className: "cs-cmdk__item", onClick: () => {
3981
+ it.onSelect && it.onSelect();
3982
+ onClose && onClose();
3983
+ } }, it.icon ? /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, it.icon) : null, /* @__PURE__ */ React.createElement("span", null, it.label), it.shortcut ? /* @__PURE__ */ React.createElement("span", { className: "cs-kbd" }, it.shortcut) : null)));
3984
+ })))
3985
+ );
3986
+ }
3987
+ Object.assign(__ds_scope, { CommandPalette });
3988
+ })(); } catch (e) { __ds_ns.__errors.push({ path: "components/navigation/CommandPalette.jsx", error: String((e && e.message) || e) }); }
3989
+
3990
+ // components/overlays/AlertDialog.jsx
3991
+ try { (() => {
3992
+ const { makeT, useLang } = __ds_scope;
3993
+ const { cx } = __ds_scope;
3994
+ const { useOverlayLayer } = __ds_scope;
3608
3995
  function AlertDialog({
3609
3996
  open,
3610
3997
  defaultOpen = false,
@@ -3640,45 +4027,19 @@ function AlertDialog({
3640
4027
  confirmRef.current = onConfirm;
3641
4028
  const cancelRef = React.useRef(onCancel);
3642
4029
  cancelRef.current = onCancel;
3643
- React.useEffect(() => {
3644
- if (!isOpen) return;
3645
- const prev = document.activeElement;
3646
- const prevOverflow = document.body.style.overflow;
3647
- document.body.style.overflow = "hidden";
3648
- const focusables = () => panel.current ? [...panel.current.querySelectorAll(FOCUSABLE)] : [];
3649
- const preferred = panel.current?.querySelector(".cs-alert-dialog__confirm") || focusables()[0];
3650
- (preferred || panel.current)?.focus?.();
3651
- const k = (e) => {
3652
- if (e.key === "Escape") {
3653
- setOpen(false);
3654
- cancelRef.current?.();
3655
- return;
3656
- }
3657
- if (e.key !== "Tab" || !panel.current) return;
3658
- const f = focusables();
3659
- if (!f.length) {
3660
- e.preventDefault();
3661
- panel.current.focus();
3662
- return;
3663
- }
3664
- const a = f[0], z = f[f.length - 1];
3665
- const active = document.activeElement;
3666
- const inside = panel.current.contains(active);
3667
- if (e.shiftKey && (!inside || active === a)) {
3668
- e.preventDefault();
3669
- z.focus();
3670
- } else if (!e.shiftKey && (!inside || active === z)) {
3671
- e.preventDefault();
3672
- a.focus();
3673
- }
3674
- };
3675
- document.addEventListener("keydown", k);
3676
- return () => {
3677
- document.removeEventListener("keydown", k);
3678
- document.body.style.overflow = prevOverflow;
3679
- if (prev && prev.focus) prev.focus();
3680
- };
3681
- }, [isOpen]);
4030
+ const setOpenRef = React.useRef(setOpen);
4031
+ setOpenRef.current = setOpen;
4032
+ useOverlayLayer({
4033
+ open: isOpen,
4034
+ kind: "modal",
4035
+ trapFocus: true,
4036
+ preferFocusSelector: ".cs-alert-dialog__confirm",
4037
+ onEscape: () => {
4038
+ setOpenRef.current(false);
4039
+ cancelRef.current?.();
4040
+ },
4041
+ panelRef: panel
4042
+ });
3682
4043
  const cl = cancelLabel != null ? cancelLabel : t("cancel");
3683
4044
  const cf = confirmLabel != null ? confirmLabel : t("confirm");
3684
4045
  const body = description ?? children;
@@ -3741,111 +4102,46 @@ function AlertDialog({
3741
4102
  Object.assign(__ds_scope, { AlertDialog });
3742
4103
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/overlays/AlertDialog.jsx", error: String((e && e.message) || e) }); }
3743
4104
 
3744
- // components/overlays/ContextMenu.jsx
3745
- try { (() => {
3746
- const { cx } = __ds_scope;
3747
- function ContextMenu({ items = [], children, className }) {
3748
- const [pos, setPos] = React.useState(null);
3749
- React.useEffect(() => {
3750
- if (!pos) return;
3751
- const close = () => setPos(null);
3752
- const k = (e) => {
3753
- if (e.key === "Escape") setPos(null);
3754
- };
3755
- document.addEventListener("click", close);
3756
- document.addEventListener("keydown", k);
3757
- return () => {
3758
- document.removeEventListener("click", close);
3759
- document.removeEventListener("keydown", k);
3760
- };
3761
- }, [pos]);
3762
- return /* @__PURE__ */ React.createElement(
3763
- "div",
3764
- {
3765
- className: cx("cs-ctxmenu-zone", className),
3766
- onContextMenu: (e) => {
3767
- e.preventDefault();
3768
- const r = e.currentTarget.getBoundingClientRect();
3769
- setPos({ x: e.clientX - r.left, y: e.clientY - r.top });
3770
- }
3771
- },
3772
- children,
3773
- pos ? /* @__PURE__ */ React.createElement("div", { className: "cs-menu__list", role: "menu", style: { position: "absolute", insetInlineStart: pos.x, insetBlockStart: pos.y } }, items.map((it, i) => it === "-" ? /* @__PURE__ */ React.createElement("div", { key: i, className: "cs-menu__sep" }) : /* @__PURE__ */ React.createElement("button", { key: i, type: "button", role: "menuitem", className: cx("cs-menu__item", it.danger && "cs-menu__item--danger"), onClick: () => {
3774
- setPos(null);
3775
- it.onSelect && it.onSelect();
3776
- } }, it.label))) : null
3777
- );
3778
- }
3779
- Object.assign(__ds_scope, { ContextMenu });
3780
- })(); } catch (e) { __ds_ns.__errors.push({ path: "components/overlays/ContextMenu.jsx", error: String((e && e.message) || e) }); }
3781
-
3782
4105
  // components/overlays/Drawer.jsx
3783
4106
  try { (() => {
3784
4107
  const { makeT, useLang } = __ds_scope;
3785
4108
  const { cx } = __ds_scope;
4109
+ const { useOverlayLayer } = __ds_scope;
3786
4110
  function Drawer({ open, onClose, title, side = "right", children, actions, lang, className }) {
3787
4111
  const [ref, L] = useLang(lang);
3788
- React.useEffect(() => {
3789
- if (!open) return;
3790
- const prev = document.activeElement;
3791
- const SEL = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
3792
- const p = ref.current;
3793
- const first = p ? p.querySelector(SEL) : null;
3794
- (first || p) && (first || p).focus();
3795
- const k = (e) => {
3796
- if (e.key === "Escape") {
3797
- onClose && onClose();
3798
- return;
3799
- }
3800
- if (e.key !== "Tab" || !ref.current) return;
3801
- const f = [...ref.current.querySelectorAll(SEL)];
3802
- if (!f.length) return;
3803
- const a = f[0], z = f[f.length - 1];
3804
- if (e.shiftKey && document.activeElement === a) {
3805
- e.preventDefault();
3806
- z.focus();
3807
- } else if (!e.shiftKey && document.activeElement === z) {
3808
- e.preventDefault();
3809
- a.focus();
3810
- }
3811
- };
3812
- document.addEventListener("keydown", k);
3813
- return () => {
3814
- document.removeEventListener("keydown", k);
3815
- if (prev && prev.focus) prev.focus();
3816
- };
3817
- }, [open]);
4112
+ const panel = React.useRef(null);
4113
+ const closeRef = React.useRef(onClose);
4114
+ closeRef.current = onClose;
4115
+ useOverlayLayer({
4116
+ open: !!open,
4117
+ kind: "modal",
4118
+ trapFocus: true,
4119
+ onEscape: () => closeRef.current && closeRef.current(),
4120
+ panelRef: panel
4121
+ });
3818
4122
  const t = makeT("Drawer", L);
3819
4123
  if (!open) return null;
3820
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "cs-drawer-scrim", onClick: onClose, "aria-hidden": "true" }), /* @__PURE__ */ React.createElement("aside", { ref, tabIndex: -1, className: cx("cs-drawer", side === "left" && "cs-drawer--left", className), role: "dialog", "aria-modal": "true", "aria-label": typeof title === "string" ? title : t("panel") }, /* @__PURE__ */ React.createElement("div", { className: "cs-drawer__header" }, title ? /* @__PURE__ */ React.createElement("h2", { className: "cs-drawer__title" }, title) : null, /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-drawer__close", "aria-label": t("close"), onClick: onClose }, /* @__PURE__ */ React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M6 6l12 12M18 6L6 18" })))), /* @__PURE__ */ React.createElement("div", { className: "cs-drawer__body", tabIndex: 0 }, children), actions ? /* @__PURE__ */ React.createElement("div", { className: "cs-drawer__footer" }, actions) : null));
4124
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "cs-drawer-scrim", onClick: onClose, "aria-hidden": "true" }), /* @__PURE__ */ React.createElement(
4125
+ "aside",
4126
+ {
4127
+ ref: (el) => {
4128
+ panel.current = el;
4129
+ ref.current = el;
4130
+ },
4131
+ tabIndex: -1,
4132
+ className: cx("cs-drawer", side === "left" && "cs-drawer--left", className),
4133
+ role: "dialog",
4134
+ "aria-modal": "true",
4135
+ "aria-label": typeof title === "string" ? title : t("panel")
4136
+ },
4137
+ /* @__PURE__ */ React.createElement("div", { className: "cs-drawer__header" }, title ? /* @__PURE__ */ React.createElement("h2", { className: "cs-drawer__title" }, title) : null, /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-drawer__close", "aria-label": t("close"), onClick: onClose }, /* @__PURE__ */ React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M6 6l12 12M18 6L6 18" })))),
4138
+ /* @__PURE__ */ React.createElement("div", { className: "cs-drawer__body", tabIndex: 0 }, children),
4139
+ actions ? /* @__PURE__ */ React.createElement("div", { className: "cs-drawer__footer" }, actions) : null
4140
+ ));
3821
4141
  }
3822
4142
  Object.assign(__ds_scope, { Drawer });
3823
4143
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/overlays/Drawer.jsx", error: String((e && e.message) || e) }); }
3824
4144
 
3825
- // components/overlays/HoverCard.jsx
3826
- try { (() => {
3827
- const { cx } = __ds_scope;
3828
- function HoverCard({ trigger, children, openDelay = 150, closeDelay = 200, className }) {
3829
- const [open, setOpen] = React.useState(false);
3830
- const t1 = React.useRef();
3831
- const t2 = React.useRef();
3832
- const show = () => {
3833
- clearTimeout(t2.current);
3834
- t1.current = setTimeout(() => setOpen(true), openDelay);
3835
- };
3836
- const hide = () => {
3837
- clearTimeout(t1.current);
3838
- t2.current = setTimeout(() => setOpen(false), closeDelay);
3839
- };
3840
- React.useEffect(() => () => {
3841
- clearTimeout(t1.current);
3842
- clearTimeout(t2.current);
3843
- }, []);
3844
- return /* @__PURE__ */ React.createElement("span", { className: cx("cs-hovercard", className), onMouseEnter: show, onMouseLeave: hide, onFocus: show, onBlur: hide }, trigger, open ? /* @__PURE__ */ React.createElement("span", { className: "cs-hovercard__panel", role: "dialog" }, children) : null);
3845
- }
3846
- Object.assign(__ds_scope, { HoverCard });
3847
- })(); } catch (e) { __ds_ns.__errors.push({ path: "components/overlays/HoverCard.jsx", error: String((e && e.message) || e) }); }
3848
-
3849
4145
  // components/overlays/Popconfirm.jsx
3850
4146
  try { (() => {
3851
4147
  const { makeT, useLang } = __ds_scope;
@@ -3937,30 +4233,37 @@ const { cx } = __ds_scope;
3937
4233
  function Tour({ steps = [], open, onClose, lang, className }) {
3938
4234
  const [i, setI] = React.useState(0);
3939
4235
  const [rect, setRect] = React.useState(null);
4236
+ const [pop, setPop] = React.useState({ top: 80, left: 40 });
3940
4237
  const [ref, L] = useLang(lang);
3941
4238
  const t = makeT("Tour", L);
3942
4239
  React.useEffect(() => {
3943
4240
  if (open) setI(0);
3944
4241
  }, [open]);
3945
4242
  React.useEffect(() => {
3946
- if (!open || !steps[i]) return;
4243
+ if (!open || !steps[i]) return void 0;
3947
4244
  const el = document.querySelector(steps[i].target);
3948
4245
  if (el) {
3949
4246
  const r = el.getBoundingClientRect();
3950
- setRect({ x: r.left - 6, y: r.top - 6, w: r.width + 12, h: r.height + 12 });
3951
- } else setRect(null);
4247
+ const next = { x: r.left - 6, y: r.top - 6, w: r.width + 12, h: r.height + 12 };
4248
+ setRect(next);
4249
+ setPop({
4250
+ top: Math.min(window.innerHeight - 170, next.y + next.h + 12),
4251
+ left: Math.max(12, Math.min(window.innerWidth - 292, next.x))
4252
+ });
4253
+ } else {
4254
+ setRect(null);
4255
+ setPop({ top: 80, left: 40 });
4256
+ }
3952
4257
  const k = (e) => {
3953
4258
  if (e.key === "Escape") onClose && onClose();
3954
4259
  };
3955
4260
  document.addEventListener("keydown", k);
3956
4261
  return () => document.removeEventListener("keydown", k);
3957
- }, [open, i, steps]);
4262
+ }, [open, i, steps, onClose]);
3958
4263
  if (!open || !steps.length) return /* @__PURE__ */ React.createElement("span", { ref, style: { display: "none" } });
3959
4264
  const s = steps[i];
3960
4265
  const last = i === steps.length - 1;
3961
- const popTop = rect ? Math.min(window.innerHeight - 170, rect.y + rect.h + 12) : 80;
3962
- const popLeft = rect ? Math.max(12, Math.min(window.innerWidth - 292, rect.x)) : 40;
3963
- return /* @__PURE__ */ React.createElement("div", { ref, className: cx("cs-tour", className) }, /* @__PURE__ */ React.createElement("div", { className: "cs-tour__scrim", onClick: onClose }), rect ? /* @__PURE__ */ React.createElement("div", { className: "cs-tour__hole", style: { left: rect.x, top: rect.y, width: rect.w, height: rect.h } }) : null, /* @__PURE__ */ React.createElement("div", { className: "cs-tour__pop", role: "dialog", "aria-label": typeof s.title === "string" ? s.title : void 0, style: { left: popLeft, top: popTop } }, /* @__PURE__ */ React.createElement("b", null, s.title), s.body ? /* @__PURE__ */ React.createElement("p", null, s.body) : null, /* @__PURE__ */ React.createElement("div", { className: "cs-tour__bar" }, /* @__PURE__ */ React.createElement("span", { className: "cs-tour__count" }, i + 1 + " / " + steps.length), /* @__PURE__ */ React.createElement("span", { className: "cs-tour__btns" }, /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-button cs-button--ghost cs-button--xs", onClick: onClose }, t("skip")), i > 0 ? /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-button cs-button--secondary cs-button--xs", onClick: () => setI(i - 1) }, t("back")) : null, /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-button cs-button--primary cs-button--xs", onClick: () => last ? onClose && onClose() : setI(i + 1) }, last ? t("done") : t("next"))))));
4266
+ return /* @__PURE__ */ React.createElement("div", { ref, className: cx("cs-tour", className) }, /* @__PURE__ */ React.createElement("div", { className: "cs-tour__scrim", onClick: onClose }), rect ? /* @__PURE__ */ React.createElement("div", { className: "cs-tour__hole", style: { left: rect.x, top: rect.y, width: rect.w, height: rect.h } }) : null, /* @__PURE__ */ React.createElement("div", { className: "cs-tour__pop", role: "dialog", "aria-label": typeof s.title === "string" ? s.title : void 0, style: { left: pop.left, top: pop.top } }, /* @__PURE__ */ React.createElement("b", null, s.title), s.body ? /* @__PURE__ */ React.createElement("p", null, s.body) : null, /* @__PURE__ */ React.createElement("div", { className: "cs-tour__bar" }, /* @__PURE__ */ React.createElement("span", { className: "cs-tour__count" }, i + 1 + " / " + steps.length), /* @__PURE__ */ React.createElement("span", { className: "cs-tour__btns" }, /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-button cs-button--ghost cs-button--xs", onClick: onClose }, t("skip")), i > 0 ? /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-button cs-button--secondary cs-button--xs", onClick: () => setI(i - 1) }, t("back")) : null, /* @__PURE__ */ React.createElement("button", { type: "button", className: "cs-button cs-button--primary cs-button--xs", onClick: () => last ? onClose && onClose() : setI(i + 1) }, last ? t("done") : t("next"))))));
3964
4267
  }
3965
4268
  Object.assign(__ds_scope, { Tour });
3966
4269
  })(); } catch (e) { __ds_ns.__errors.push({ path: "components/overlays/Tour.jsx", error: String((e && e.message) || e) }); }
@@ -4657,7 +4960,12 @@ try { (() => {
4657
4960
  y: stored && Number.isFinite(stored.y) ? stored.y : 0
4658
4961
  };
4659
4962
  }
4660
- this._cap.textContent = this.getAttribute("placeholder") || "Drop an image";
4963
+ const authoring = typeof window !== "undefined" && typeof window.__dcSetProps === "function";
4964
+ const phEn = this.getAttribute("placeholder") || "Drop an image";
4965
+ const phVi = this.getAttribute("placeholder-vi") || "Thả ảnh (không bắt buộc)";
4966
+ const lang = (document.documentElement.getAttribute("lang") || "").toLowerCase();
4967
+ this._cap.textContent = authoring ? lang.startsWith("vi") ? phVi : phEn : "";
4968
+ if (this._cap) this._cap.style.display = authoring ? "" : "none";
4661
4969
  const credit = (this.getAttribute("credit") || "").trim();
4662
4970
  const attrError = !!(!credit && !this._userUrl && srcAttr && isUnsplashHost(srcAttr));
4663
4971
  this.toggleAttribute("data-attribution-error", attrError);
@@ -4737,7 +5045,7 @@ try { (() => {
4737
5045
  const tokens = {
4738
5046
  "$meta": {
4739
5047
  "system": "CyberSkill Design System",
4740
- "version": "1.1.1",
5048
+ "version": "1.2.0",
4741
5049
  "generated": "2026-07-23",
4742
5050
  "note": "Generated from tokens/*.css. Root grouped by category; theme/element scopes carry overrides only. Regenerate after any token change (see docs/conventions.md)."
4743
5051
  },
@@ -4756,6 +5064,10 @@ const tokens = {
4756
5064
  "--cs-color-semantic-danger": "#B42318",
4757
5065
  "--cs-color-semantic-warning": "#92400E",
4758
5066
  "--cs-color-semantic-info": "#1D4ED8",
5067
+ "--cs-color-semantic-success-fg": "#FFFFFF",
5068
+ "--cs-color-semantic-danger-fg": "#FFFFFF",
5069
+ "--cs-color-semantic-warning-fg": "#FFFFFF",
5070
+ "--cs-color-semantic-info-fg": "#FFFFFF",
4759
5071
  "--cs-color-accent-ochre": "#F4BA17",
4760
5072
  "--cs-color-border-default": "#E7D9C6",
4761
5073
  "--cs-color-link": "#6E3B0E",
@@ -4785,7 +5097,8 @@ const tokens = {
4785
5097
  "--cs-component-textfield-border-default": "#BFA58F",
4786
5098
  "--cs-component-textfield-paddingY": "10px",
4787
5099
  "--cs-component-textfield-paddingX": "12px",
4788
- "--cs-component-textfield-minHeight": "44px"
5100
+ "--cs-component-textfield-minHeight": "44px",
5101
+ "--cs-focus-ring": "3px"
4789
5102
  },
4790
5103
  "accent": {
4791
5104
  "--cs-accent": "#F4BA17",
@@ -4796,7 +5109,8 @@ const tokens = {
4796
5109
  "--cs-accent-ink": "#45210E",
4797
5110
  "--cs-accent-glow": "rgba(244, 186, 23, 0.48)",
4798
5111
  "--cs-accent-grad-a": "#F4BA17",
4799
- "--cs-accent-grad-b": "#FCAF91"
5112
+ "--cs-accent-grad-b": "#FCAF91",
5113
+ "--cs-accent-on-strong": "#1A1108"
4800
5114
  },
4801
5115
  "depth": {
4802
5116
  "--cs-depth-bg": "0",
@@ -4804,7 +5118,9 @@ const tokens = {
4804
5118
  "--cs-depth-card": "10",
4805
5119
  "--cs-depth-nav": "50",
4806
5120
  "--cs-depth-modal": "100",
4807
- "--cs-depth-toast": "200"
5121
+ "--cs-depth-toast": "200",
5122
+ "--cs-depth-dropdown": "60",
5123
+ "--cs-depth-overlay": "80"
4808
5124
  },
4809
5125
  "glass": {
4810
5126
  "--cs-glass-whisper-blur": "8px",
@@ -4869,7 +5185,8 @@ const tokens = {
4869
5185
  "--cs-breakpoint-2xl": "1536px"
4870
5186
  },
4871
5187
  "container": {
4872
- "--cs-container-max": "1320px"
5188
+ "--cs-container-max": "1320px",
5189
+ "--cs-prose-measure": "45rem"
4873
5190
  },
4874
5191
  "font": {
4875
5192
  "--cs-font-family-ui": "'Be Vietnam Pro', ui-sans-serif, system-ui, sans-serif",
@@ -4883,6 +5200,7 @@ const tokens = {
4883
5200
  "--cs-font-lineHeight-body": "1.5",
4884
5201
  "--cs-font-lineHeight-heading": "1.35",
4885
5202
  "--cs-font-lineHeight-tight": "1.15",
5203
+ "--cs-font-size-2xs": "0.6875rem",
4886
5204
  "--cs-font-size-xs": "0.75rem",
4887
5205
  "--cs-font-size-sm": "0.875rem",
4888
5206
  "--cs-font-size-base": "1rem",
@@ -4903,6 +5221,7 @@ const tokens = {
4903
5221
  "--cs-text-body-lg": "var(--cs-font-size-md)",
4904
5222
  "--cs-text-body": "var(--cs-font-size-base)",
4905
5223
  "--cs-text-secondary": "var(--cs-font-size-sm)",
5224
+ "--cs-text-micro": "var(--cs-font-size-2xs)",
4906
5225
  "--cs-text-caption": "var(--cs-font-size-xs)",
4907
5226
  "--cs-text-eyebrow": "var(--cs-font-size-xs)"
4908
5227
  },
@@ -4921,6 +5240,12 @@ const tokens = {
4921
5240
  "--cs-icon-sm": "16px",
4922
5241
  "--cs-icon-md": "20px",
4923
5242
  "--cs-icon-lg": "24px"
5243
+ },
5244
+ "doc": {
5245
+ "--cs-doc-ink": "#1A1614",
5246
+ "--cs-doc-slate": "#3F4C55",
5247
+ "--cs-doc-fill": "#FDE68A",
5248
+ "--cs-doc-fill-ink": "#1A1614"
4924
5249
  }
4925
5250
  },
4926
5251
  "themes": {
@@ -4936,6 +5261,10 @@ const tokens = {
4936
5261
  "--cs-color-semantic-danger": "#F87171",
4937
5262
  "--cs-color-semantic-warning": "#FBBF24",
4938
5263
  "--cs-color-semantic-info": "#7CB2FB",
5264
+ "--cs-color-semantic-success-fg": "#1a1108",
5265
+ "--cs-color-semantic-danger-fg": "#1a1108",
5266
+ "--cs-color-semantic-warning-fg": "#1a1108",
5267
+ "--cs-color-semantic-info-fg": "#1a1108",
4939
5268
  "--cs-color-border-default": "#4a3a2c",
4940
5269
  "--cs-color-link": "#f4ba17",
4941
5270
  "--cs-color-link-hover": "#f5ead9",
@@ -4960,6 +5289,10 @@ const tokens = {
4960
5289
  "--cs-color-semantic-danger": "#F87171",
4961
5290
  "--cs-color-semantic-warning": "#FBBF24",
4962
5291
  "--cs-color-semantic-info": "#7CB2FB",
5292
+ "--cs-color-semantic-success-fg": "#1a1108",
5293
+ "--cs-color-semantic-danger-fg": "#1a1108",
5294
+ "--cs-color-semantic-warning-fg": "#1a1108",
5295
+ "--cs-color-semantic-info-fg": "#1a1108",
4963
5296
  "--cs-color-border-default": "#4a3a2c",
4964
5297
  "--cs-color-link": "#f4ba17",
4965
5298
  "--cs-color-link-hover": "#f5ead9",
@@ -4979,6 +5312,7 @@ const tokens = {
4979
5312
  "--cs-accent-strong": "#90825E",
4980
5313
  "--cs-accent-bright": "#F6EBCC",
4981
5314
  "--cs-accent-on": "#292414",
5315
+ "--cs-accent-on-strong": "#1A1108",
4982
5316
  "--cs-accent-tint": "#FBF7EA",
4983
5317
  "--cs-accent-ink": "#292414",
4984
5318
  "--cs-accent-glow": "rgba(248, 233, 192, 0.48)",
@@ -4992,6 +5326,7 @@ const tokens = {
4992
5326
  "--cs-accent-strong": "#A47D17",
4993
5327
  "--cs-accent-bright": "#F4BA17",
4994
5328
  "--cs-accent-on": "#45210E",
5329
+ "--cs-accent-on-strong": "#1A1108",
4995
5330
  "--cs-accent-tint": "#FBF4E9",
4996
5331
  "--cs-accent-ink": "#45210E",
4997
5332
  "--cs-accent-glow": "rgba(244, 186, 23, 0.48)",
@@ -5003,6 +5338,7 @@ const tokens = {
5003
5338
  "--cs-accent-strong": "#201300",
5004
5339
  "--cs-accent-bright": "#DEC7A2",
5005
5340
  "--cs-accent-on": "#2D220E",
5341
+ "--cs-accent-on-strong": "#FFFFFF",
5006
5342
  "--cs-accent-tint": "#FFF6E7",
5007
5343
  "--cs-accent-ink": "#2D220E",
5008
5344
  "--cs-accent-glow": "rgba(81, 56, 1, 0.48)",
@@ -5016,6 +5352,7 @@ const tokens = {
5016
5352
  "--cs-accent-strong": "#967C75",
5017
5353
  "--cs-accent-bright": "#FCE6DF",
5018
5354
  "--cs-accent-on": "#2C211E",
5355
+ "--cs-accent-on-strong": "#1A1108",
5019
5356
  "--cs-accent-tint": "#FEF4F2",
5020
5357
  "--cs-accent-ink": "#2C211E",
5021
5358
  "--cs-accent-glow": "rgba(255, 225, 216, 0.48)",
@@ -5029,6 +5366,7 @@ const tokens = {
5029
5366
  "--cs-accent-strong": "#B47054",
5030
5367
  "--cs-accent-bright": "#FED3C3",
5031
5368
  "--cs-accent-on": "#381B10",
5369
+ "--cs-accent-on-strong": "#1A1108",
5032
5370
  "--cs-accent-tint": "#FFF4F0",
5033
5371
  "--cs-accent-ink": "#381B10",
5034
5372
  "--cs-accent-glow": "rgba(252, 175, 145, 0.48)",
@@ -5042,6 +5380,7 @@ const tokens = {
5042
5380
  "--cs-accent-strong": "#280D00",
5043
5381
  "--cs-accent-bright": "#F1BEA4",
5044
5382
  "--cs-accent-on": "#361D0F",
5383
+ "--cs-accent-on-strong": "#FFFFFF",
5045
5384
  "--cs-accent-tint": "#FFF4EF",
5046
5385
  "--cs-accent-ink": "#361D0F",
5047
5386
  "--cs-accent-glow": "rgba(98, 43, 6, 0.48)",
@@ -5055,6 +5394,7 @@ const tokens = {
5055
5394
  "--cs-accent-strong": "#5A8A90",
5056
5395
  "--cs-accent-bright": "#CDF4F9",
5057
5396
  "--cs-accent-on": "#13282B",
5397
+ "--cs-accent-on-strong": "#1A1108",
5058
5398
  "--cs-accent-tint": "#EBFAFC",
5059
5399
  "--cs-accent-ink": "#13282B",
5060
5400
  "--cs-accent-glow": "rgba(192, 245, 252, 0.48)",
@@ -5068,6 +5408,7 @@ const tokens = {
5068
5408
  "--cs-accent-strong": "#108EA0",
5069
5409
  "--cs-accent-bright": "#99EEFF",
5070
5410
  "--cs-accent-on": "#012A30",
5411
+ "--cs-accent-on-strong": "#1A1108",
5071
5412
  "--cs-accent-tint": "#E7FBFF",
5072
5413
  "--cs-accent-ink": "#012A30",
5073
5414
  "--cs-accent-glow": "rgba(46, 219, 247, 0.48)",
@@ -5081,6 +5422,7 @@ const tokens = {
5081
5422
  "--cs-accent-strong": "#011A21",
5082
5423
  "--cs-accent-bright": "#A8D3E0",
5083
5424
  "--cs-accent-on": "#10282F",
5425
+ "--cs-accent-on-strong": "#FFFFFF",
5084
5426
  "--cs-accent-tint": "#EAFAFF",
5085
5427
  "--cs-accent-ink": "#10282F",
5086
5428
  "--cs-accent-glow": "rgba(0, 69, 84, 0.48)",
@@ -5094,6 +5436,7 @@ const tokens = {
5094
5436
  "--cs-accent-strong": "#7C8965",
5095
5437
  "--cs-accent-bright": "#E5F1D2",
5096
5438
  "--cs-accent-on": "#212617",
5439
+ "--cs-accent-on-strong": "#1A1108",
5097
5440
  "--cs-accent-tint": "#F4F9ED",
5098
5441
  "--cs-accent-ink": "#212617",
5099
5442
  "--cs-accent-glow": "rgba(225, 241, 200, 0.48)",
@@ -5107,6 +5450,7 @@ const tokens = {
5107
5450
  "--cs-accent-strong": "#629122",
5108
5451
  "--cs-accent-bright": "#C5ED9C",
5109
5452
  "--cs-accent-on": "#182A00",
5453
+ "--cs-accent-on-strong": "#1A1108",
5110
5454
  "--cs-accent-tint": "#EFFCE3",
5111
5455
  "--cs-accent-ink": "#182A00",
5112
5456
  "--cs-accent-glow": "rgba(163, 215, 104, 0.48)",
@@ -5120,6 +5464,7 @@ const tokens = {
5120
5464
  "--cs-accent-strong": "#051D00",
5121
5465
  "--cs-accent-bright": "#B0D8A3",
5122
5466
  "--cs-accent-on": "#162A0E",
5467
+ "--cs-accent-on-strong": "#FFFFFF",
5123
5468
  "--cs-accent-tint": "#ECFDE7",
5124
5469
  "--cs-accent-ink": "#162A0E",
5125
5470
  "--cs-accent-glow": "rgba(26, 74, 1, 0.48)",
@@ -5133,6 +5478,7 @@ const tokens = {
5133
5478
  "--cs-accent-strong": "#947F65",
5134
5479
  "--cs-accent-bright": "#FBE8D2",
5135
5480
  "--cs-accent-on": "#2B2217",
5481
+ "--cs-accent-on-strong": "#1A1108",
5136
5482
  "--cs-accent-tint": "#FDF5ED",
5137
5483
  "--cs-accent-ink": "#2B2217",
5138
5484
  "--cs-accent-glow": "rgba(254, 229, 199, 0.48)",
@@ -5146,6 +5492,7 @@ const tokens = {
5146
5492
  "--cs-accent-strong": "#AC780B",
5147
5493
  "--cs-accent-bright": "#FDD89F",
5148
5494
  "--cs-accent-on": "#312002",
5495
+ "--cs-accent-on-strong": "#1A1108",
5149
5496
  "--cs-accent-tint": "#FFF5E7",
5150
5497
  "--cs-accent-ink": "#312002",
5151
5498
  "--cs-accent-glow": "rgba(243, 185, 88, 0.48)",
@@ -5159,6 +5506,7 @@ const tokens = {
5159
5506
  "--cs-accent-strong": "#1F1400",
5160
5507
  "--cs-accent-bright": "#DCC8A2",
5161
5508
  "--cs-accent-on": "#2D220E",
5509
+ "--cs-accent-on-strong": "#FFFFFF",
5162
5510
  "--cs-accent-tint": "#FEF6E7",
5163
5511
  "--cs-accent-ink": "#2D220E",
5164
5512
  "--cs-accent-glow": "rgba(80, 57, 1, 0.48)",
@@ -5302,7 +5650,40 @@ function StatusHub() {
5302
5650
  }, [D, q, facet, kpi]);
5303
5651
  const maxV = Math.max(...D.velocity.map((v) => v.n));
5304
5652
  const toggleKpi = (k) => setKpi((cur) => cur === k ? null : k);
5305
- return /* @__PURE__ */ React.createElement("div", { className: "sh", lang, "data-theme": dark ? "dark" : void 0 }, /* @__PURE__ */ React.createElement("header", { className: "hd" }, /* @__PURE__ */ React.createElement("div", { className: "hd-in" }, /* @__PURE__ */ React.createElement("div", { className: "hd-id" }, /* @__PURE__ */ React.createElement("span", { className: "hd-mark" }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/logo-mark.svg", alt: "" })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h1", null, "Status Hub"), /* @__PURE__ */ React.createElement("p", { className: "hd-sub" }, t.sub))), /* @__PURE__ */ React.createElement("div", { className: "hd-side" }, /* @__PURE__ */ React.createElement("p", { className: "hd-meta" }, t.updated, /* @__PURE__ */ React.createElement("br", null), VI ? VI.updated : D.updated), /* @__PURE__ */ React.createElement("button", { className: "btn ghost", onClick: () => setLang((l) => l === "en" ? "vi" : "en"), "aria-label": "Toggle language", style: { fontWeight: 700, fontSize: 13 } }, t.langBtn), /* @__PURE__ */ React.createElement("button", { className: "btn ghost", onClick: () => setDark((v) => !v), "aria-label": t.theme }, /* @__PURE__ */ React.createElement(ThemeGlyph, { dark }))))), /* @__PURE__ */ React.createElement("div", { className: "wrap" }, /* @__PURE__ */ React.createElement("div", { className: "deck" }, /* @__PURE__ */ React.createElement("section", { className: "panel" }, /* @__PURE__ */ React.createElement("h2", null, t.portfolio), /* @__PURE__ */ React.createElement("div", { className: "kpis" }, /* @__PURE__ */ React.createElement("button", { className: "kpi", "data-on": kpi === null ? "1" : "0", onClick: () => setKpi(null) }, /* @__PURE__ */ React.createElement("b", null, counts.total), /* @__PURE__ */ React.createElement("span", null, t.projects)), /* @__PURE__ */ React.createElement("button", { className: "kpi", "data-on": kpi === "active" ? "1" : "0", onClick: () => toggleKpi("active") }, /* @__PURE__ */ React.createElement("b", null, counts.active), /* @__PURE__ */ React.createElement("span", null, t.inprog)), /* @__PURE__ */ React.createElement("button", { className: "kpi", "data-on": kpi === "done" ? "1" : "0", onClick: () => toggleKpi("done") }, /* @__PURE__ */ React.createElement("b", null, counts.done), /* @__PURE__ */ React.createElement("span", null, t.shipped)), /* @__PURE__ */ React.createElement("button", { className: "kpi", "data-on": kpi === "hold" ? "1" : "0", onClick: () => toggleKpi("hold") }, /* @__PURE__ */ React.createElement("b", null, counts.hold), /* @__PURE__ */ React.createElement("span", null, t.blocked)), /* @__PURE__ */ React.createElement("button", { className: "kpi", onClick: () => setKpi(null) }, /* @__PURE__ */ React.createElement("b", null, counts.avg, "%"), /* @__PURE__ */ React.createElement("span", null, t.avg))), /* @__PURE__ */ React.createElement(Segments, { seg: { done: 60, active: 22, hold: 6, todo: 12 }, className: "bar-seg" }), /* @__PURE__ */ React.createElement("div", { className: "legend" }, /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("i", { className: "dot", style: { background: "var(--cs-color-semantic-success)" } }), t.shipped), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("i", { className: "dot", style: { background: "var(--cs-color-brand-ochre)" } }), t.inprog), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("i", { className: "dot", style: { background: "var(--cs-color-semantic-danger)" } }), t.blocked), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("i", { className: "dot", style: { background: "var(--cs-status-todo)" } }), t.planned))), /* @__PURE__ */ React.createElement("section", { className: "panel" }, /* @__PURE__ */ React.createElement("h2", null, t.velocity), /* @__PURE__ */ React.createElement("div", { className: "spark" }, D.velocity.map((v) => /* @__PURE__ */ React.createElement("a", { key: v.wk, title: v.n + t.perShipped }, /* @__PURE__ */ React.createElement("b", null, v.n), /* @__PURE__ */ React.createElement("i", { style: { height: v.n / maxV * 72 + "px" } }), /* @__PURE__ */ React.createElement("span", null, v.wk)))))), /* @__PURE__ */ React.createElement("div", { className: "now" }, /* @__PURE__ */ React.createElement("h2", null, t.nowTitle), lang === "vi" ? /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("b", null, "v1.6.0 — Liên kết Glass + gói Ngũ Hành v2."), " Liên kết component ", /* @__PURE__ */ React.createElement("span", { className: "mono" }, ".cs-surface-*"), " (tùy chọn), trình kiểm 0 cảnh báo trên cả 15 gói, và kiểm tra lại APCA cho chế độ tối. Ra mắt tuần này.") : /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("b", null, "v1.6.0 — Glass bindings + element-pack v2."), " Opt-in ", /* @__PURE__ */ React.createElement("span", { className: "mono" }, ".cs-surface-*"), " component bindings, a zero-warning verifier across all 15 packs, and a dark-mode APCA re-check. Ships this week.")), /* @__PURE__ */ React.createElement("div", { className: "bar" }, /* @__PURE__ */ React.createElement("div", { className: "bar-top" }, /* @__PURE__ */ React.createElement("label", { className: "srch" }, /* @__PURE__ */ React.createElement(SearchGlyph, null), /* @__PURE__ */ React.createElement("input", { placeholder: t.search, value: q, onChange: (e) => setQ(e.target.value) })), /* @__PURE__ */ React.createElement("div", { className: "lenses", role: "tablist", "aria-label": t.view }, ["board", "table", "releases"].map((l) => /* @__PURE__ */ React.createElement("button", { key: l, className: "ln", role: "tab", "aria-selected": lens === l, onClick: () => setLens(l) }, t.lenses[l]))), /* @__PURE__ */ React.createElement("label", { className: "facet" }, t.status, /* @__PURE__ */ React.createElement("select", { value: kpi || facet, onChange: (e) => {
5653
+ return /* @__PURE__ */ React.createElement("div", { className: "sh", lang, "data-theme": dark ? "dark" : void 0 }, /* @__PURE__ */ React.createElement("a", { className: "cs-skip", href: "#main", style: { position: "absolute", left: -999, width: 1, height: 1, overflow: "hidden" } }, "Skip to content"), /* @__PURE__ */ React.createElement("header", { className: "hd" }, /* @__PURE__ */ React.createElement("div", { className: "hd-in" }, /* @__PURE__ */ React.createElement("div", { className: "hd-id" }, /* @__PURE__ */ React.createElement("span", { className: "hd-mark" }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/logo-mark.svg", alt: "" })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h1", null, "Status Hub"), /* @__PURE__ */ React.createElement("p", { className: "hd-sub" }, t.sub))), /* @__PURE__ */ React.createElement("div", { className: "hd-side" }, /* @__PURE__ */ React.createElement("p", { className: "hd-meta" }, t.updated, /* @__PURE__ */ React.createElement("br", null), VI ? VI.updated : D.updated), /* @__PURE__ */ React.createElement("button", { className: "btn ghost", onClick: () => setLang((l) => l === "en" ? "vi" : "en"), "aria-label": "Toggle language", style: { fontWeight: 700, fontSize: 13 } }, t.langBtn), /* @__PURE__ */ React.createElement("button", { className: "btn ghost", onClick: () => setDark((v) => !v), "aria-label": t.theme }, /* @__PURE__ */ React.createElement(ThemeGlyph, { dark }))))), /* @__PURE__ */ React.createElement("main", { id: "main", className: "wrap" }, /* @__PURE__ */ React.createElement("div", { className: "deck" }, /* @__PURE__ */ React.createElement("section", { className: "panel" }, /* @__PURE__ */ React.createElement("h2", null, t.portfolio), /* @__PURE__ */ React.createElement("div", { className: "kpis" }, /* @__PURE__ */ React.createElement("button", { className: "kpi", "data-on": kpi === null ? "1" : "0", onClick: () => setKpi(null) }, /* @__PURE__ */ React.createElement("b", null, counts.total), /* @__PURE__ */ React.createElement("span", null, t.projects)), /* @__PURE__ */ React.createElement("button", { className: "kpi", "data-on": kpi === "active" ? "1" : "0", onClick: () => toggleKpi("active") }, /* @__PURE__ */ React.createElement("b", null, counts.active), /* @__PURE__ */ React.createElement("span", null, t.inprog)), /* @__PURE__ */ React.createElement("button", { className: "kpi", "data-on": kpi === "done" ? "1" : "0", onClick: () => toggleKpi("done") }, /* @__PURE__ */ React.createElement("b", null, counts.done), /* @__PURE__ */ React.createElement("span", null, t.shipped)), /* @__PURE__ */ React.createElement("button", { className: "kpi", "data-on": kpi === "hold" ? "1" : "0", onClick: () => toggleKpi("hold") }, /* @__PURE__ */ React.createElement("b", null, counts.hold), /* @__PURE__ */ React.createElement("span", null, t.blocked)), /* @__PURE__ */ React.createElement("button", { className: "kpi", onClick: () => setKpi(null) }, /* @__PURE__ */ React.createElement("b", null, counts.avg, "%"), /* @__PURE__ */ React.createElement("span", null, t.avg))), /* @__PURE__ */ React.createElement(Segments, { seg: { done: 60, active: 22, hold: 6, todo: 12 }, className: "bar-seg" }), /* @__PURE__ */ React.createElement("div", { className: "legend" }, /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("i", { className: "dot", style: { background: "var(--cs-color-semantic-success)" } }), t.shipped), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("i", { className: "dot", style: { background: "var(--cs-color-brand-ochre)" } }), t.inprog), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("i", { className: "dot", style: { background: "var(--cs-color-semantic-danger)" } }), t.blocked), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("i", { className: "dot", style: { background: "var(--cs-status-todo)" } }), t.planned))), /* @__PURE__ */ React.createElement("section", { className: "panel" }, /* @__PURE__ */ React.createElement("h2", null, t.velocity), /* @__PURE__ */ React.createElement("div", { className: "spark" }, D.velocity.map((v) => /* @__PURE__ */ React.createElement("a", { key: v.wk, title: v.n + t.perShipped }, /* @__PURE__ */ React.createElement("b", null, v.n), /* @__PURE__ */ React.createElement("i", { style: { height: v.n / maxV * 72 + "px" } }), /* @__PURE__ */ React.createElement("span", null, v.wk)))))), /* @__PURE__ */ React.createElement("div", { className: "now" }, /* @__PURE__ */ React.createElement("h2", null, t.nowTitle), lang === "vi" ? /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("b", null, "v1.6.0 — Liên kết Glass + gói Ngũ Hành v2."), " Liên kết component ", /* @__PURE__ */ React.createElement("span", { className: "mono" }, ".cs-surface-*"), " (tùy chọn), trình kiểm 0 cảnh báo trên cả 15 gói, và kiểm tra lại APCA cho chế độ tối. Ra mắt tuần này.") : /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("b", null, "v1.6.0 — Glass bindings + element-pack v2."), " Opt-in ", /* @__PURE__ */ React.createElement("span", { className: "mono" }, ".cs-surface-*"), " component bindings, a zero-warning verifier across all 15 packs, and a dark-mode APCA re-check. Ships this week.")), /* @__PURE__ */ React.createElement("div", { className: "bar" }, /* @__PURE__ */ React.createElement("div", { className: "bar-top" }, /* @__PURE__ */ React.createElement("label", { className: "srch" }, /* @__PURE__ */ React.createElement(SearchGlyph, null), /* @__PURE__ */ React.createElement("input", { placeholder: t.search, value: q, onChange: (e) => setQ(e.target.value) })), /* @__PURE__ */ React.createElement(
5654
+ "div",
5655
+ {
5656
+ className: "lenses",
5657
+ role: "tablist",
5658
+ "aria-label": t.view,
5659
+ onKeyDown: (e) => {
5660
+ const order = ["board", "table", "releases"];
5661
+ const i = order.indexOf(lens);
5662
+ let next = i;
5663
+ if (e.key === "ArrowRight") next = (i + 1) % order.length;
5664
+ else if (e.key === "ArrowLeft") next = (i - 1 + order.length) % order.length;
5665
+ else if (e.key === "Home") next = 0;
5666
+ else if (e.key === "End") next = order.length - 1;
5667
+ else return;
5668
+ e.preventDefault();
5669
+ setLens(order[next]);
5670
+ const tabs = e.currentTarget.querySelectorAll('[role="tab"]');
5671
+ tabs[next] && tabs[next].focus && tabs[next].focus();
5672
+ }
5673
+ },
5674
+ ["board", "table", "releases"].map((l) => /* @__PURE__ */ React.createElement(
5675
+ "button",
5676
+ {
5677
+ key: l,
5678
+ className: "ln",
5679
+ role: "tab",
5680
+ "aria-selected": lens === l,
5681
+ tabIndex: lens === l ? 0 : -1,
5682
+ onClick: () => setLens(l)
5683
+ },
5684
+ t.lenses[l]
5685
+ ))
5686
+ ), /* @__PURE__ */ React.createElement("label", { className: "facet" }, t.status, /* @__PURE__ */ React.createElement("select", { value: kpi || facet, onChange: (e) => {
5306
5687
  setFacet(e.target.value);
5307
5688
  setKpi(null);
5308
5689
  } }, /* @__PURE__ */ React.createElement("option", { value: "all" }, t.all), /* @__PURE__ */ React.createElement("option", { value: "active" }, t.inprog), /* @__PURE__ */ React.createElement("option", { value: "done" }, t.shipped), /* @__PURE__ */ React.createElement("option", { value: "hold" }, t.blocked))), /* @__PURE__ */ React.createElement("span", { className: "cnt" }, shown.length, " ", t.of, " ", D.projects.length))), lens === "board" && /* @__PURE__ */ React.createElement("div", { className: "grid" }, shown.map((p0) => {
@@ -5499,15 +5880,35 @@ function Website() {
5499
5880
  const [seed, setSeed] = useState("");
5500
5881
  const [wish, setWish] = useState("");
5501
5882
  const [sent, setSent] = useState(false);
5883
+ const [fabVisible, setFabVisible] = useState(false);
5502
5884
  const t = window.SITE_COPY[loc];
5503
5885
  function openChat(s) {
5504
5886
  setSeed(s || "");
5505
5887
  setChat(true);
5506
5888
  }
5507
- return /* @__PURE__ */ React.createElement("div", { className: "site", "data-theme": dark ? "dark" : void 0 }, /* @__PURE__ */ React.createElement("header", { className: "hdr cs-surface-light" }, /* @__PURE__ */ React.createElement("div", { className: "container hdr-in" }, /* @__PURE__ */ React.createElement("a", { className: "brand", href: "#top" }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/logo-mark.svg", alt: "" }), "CyberSkill"), /* @__PURE__ */ React.createElement("nav", { className: "nav" }, t.nav.map((n, i) => /* @__PURE__ */ React.createElement("a", { key: i, href: "#" + ["services", "work", "process", "careers", "contact"][i] }, n))), /* @__PURE__ */ React.createElement("div", { className: "hdr-side" }, /* @__PURE__ */ React.createElement("button", { className: "mini", onClick: () => setLoc(loc === "en" ? "vi" : "en") }, t.langLabel), /* @__PURE__ */ React.createElement("button", { className: "mini icon", onClick: () => setDark(!dark), "aria-label": "Toggle theme" }, /* @__PURE__ */ React.createElement(I, { name: dark ? "sun" : "moon", size: 18 })), /* @__PURE__ */ React.createElement("button", { className: "mini", style: { background: "var(--cs-color-brand-umber)", color: "#fff", borderColor: "transparent" }, onClick: () => openChat("") }, t.talk)))), /* @__PURE__ */ React.createElement("section", { className: "hero", id: "top" }, /* @__PURE__ */ React.createElement("div", { className: "container hero-in" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "eyebrow" }, t.eyebrow), /* @__PURE__ */ React.createElement("h1", null, t.slogan), /* @__PURE__ */ React.createElement("div", { className: "vn" }, t.sub), /* @__PURE__ */ React.createElement("p", { className: "lead" }, t.lead), /* @__PURE__ */ React.createElement("div", { className: "wish" }, /* @__PURE__ */ React.createElement("input", { value: wish, onChange: (e) => setWish(e.target.value), onKeyDown: (e) => e.key === "Enter" && openChat(wish), placeholder: t.wishPlaceholder, "aria-label": t.wishPlaceholder }), /* @__PURE__ */ React.createElement("button", { className: "btn-gold", onClick: () => openChat(wish) }, /* @__PURE__ */ React.createElement(I, { name: "sparkle", size: 18 }), t.wishCta), /* @__PURE__ */ React.createElement("button", { className: "btn-ghost-light", onClick: () => openChat("") }, t.talk))), /* @__PURE__ */ React.createElement("div", { className: "hero-art" }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/lumi-poster.webp", alt: "Lumi, the golden genie" })))), /* @__PURE__ */ React.createElement("div", { className: "marq" }, /* @__PURE__ */ React.createElement("div", { className: "container marq-in" }, t.marquee.map((m, i) => /* @__PURE__ */ React.createElement(React.Fragment, { key: i }, i > 0 && /* @__PURE__ */ React.createElement("b", null, "·"), /* @__PURE__ */ React.createElement("span", null, m))))), /* @__PURE__ */ React.createElement("section", { className: "sec", id: "services" }, /* @__PURE__ */ React.createElement("div", { className: "container" }, /* @__PURE__ */ React.createElement("div", { className: "eyebrow" }, t.nav[0]), /* @__PURE__ */ React.createElement("h2", null, t.servicesTitle), /* @__PURE__ */ React.createElement("p", { className: "sec-lead" }, t.servicesLead), /* @__PURE__ */ React.createElement("div", { className: "svc-grid" }, t.services.map((s, i) => /* @__PURE__ */ React.createElement("article", { className: "svc cs-surface-standard", key: i }, /* @__PURE__ */ React.createElement("div", { className: "svc-ic" }, /* @__PURE__ */ React.createElement(I, { name: s.icon })), /* @__PURE__ */ React.createElement("h3", null, s.t), /* @__PURE__ */ React.createElement("p", null, s.s), /* @__PURE__ */ React.createElement("ul", null, s.o.map((o) => /* @__PURE__ */ React.createElement("li", { key: o }, o)))))))), /* @__PURE__ */ React.createElement("section", { className: "sec sec-alt", id: "process" }, /* @__PURE__ */ React.createElement("div", { className: "container" }, /* @__PURE__ */ React.createElement("div", { className: "eyebrow" }, t.nav[2]), /* @__PURE__ */ React.createElement("h2", null, t.processTitle), /* @__PURE__ */ React.createElement("p", { className: "sec-lead" }, t.processLead), /* @__PURE__ */ React.createElement("div", { className: "steps" }, t.steps.map((s) => /* @__PURE__ */ React.createElement("div", { className: "step", key: s.n }, /* @__PURE__ */ React.createElement("span", { className: "n" }, s.n), /* @__PURE__ */ React.createElement("h3", null, s.t), /* @__PURE__ */ React.createElement("p", null, s.s)))))), /* @__PURE__ */ React.createElement("section", { className: "sec", id: "careers" }, /* @__PURE__ */ React.createElement("div", { className: "container" }, /* @__PURE__ */ React.createElement("div", { className: "band" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", null, t.careersTitle), /* @__PURE__ */ React.createElement("p", null, t.careersLead)), /* @__PURE__ */ React.createElement("button", { className: "btn-gold", onClick: () => openChat("") }, t.careersCta, /* @__PURE__ */ React.createElement(I, { name: "arrow-right", size: 18 }))))), /* @__PURE__ */ React.createElement("section", { className: "sec sec-alt", id: "contact" }, /* @__PURE__ */ React.createElement("div", { className: "container contact-grid" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "eyebrow" }, t.nav[4]), /* @__PURE__ */ React.createElement("h2", null, t.contactTitle), /* @__PURE__ */ React.createElement("p", { className: "sec-lead", style: { marginBottom: 16 } }, t.contactLead), /* @__PURE__ */ React.createElement("p", { className: "trust" }, /* @__PURE__ */ React.createElement(I, { name: "check", size: 16 }), t.form.trust)), sent ? /* @__PURE__ */ React.createElement("div", { className: "sent" }, /* @__PURE__ */ React.createElement(I, { name: "check", size: 18 }), " ", loc === "vi" ? "Đã nhận được lời nhắn. Cảm ơn bạn!" : "Message received. Thank you!") : /* @__PURE__ */ React.createElement("form", { className: "form", onSubmit: (e) => {
5889
+ useEffect(() => {
5890
+ const sync = () => setFabVisible(window.scrollY > 140);
5891
+ sync();
5892
+ window.addEventListener("scroll", sync, { passive: true });
5893
+ return () => window.removeEventListener("scroll", sync);
5894
+ }, []);
5895
+ return /* @__PURE__ */ React.createElement("div", { className: "site", "data-theme": dark ? "dark" : void 0 }, /* @__PURE__ */ React.createElement("a", { className: "cs-skip", href: "#main", style: { position: "absolute", left: -999, width: 1, height: 1, overflow: "hidden" } }, "Skip to content"), /* @__PURE__ */ React.createElement("header", { className: "hdr cs-surface-light" }, /* @__PURE__ */ React.createElement("div", { className: "container hdr-in" }, /* @__PURE__ */ React.createElement("a", { className: "brand", href: "#top" }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/logo-mark.svg", alt: "" }), "CyberSkill"), /* @__PURE__ */ React.createElement("nav", { className: "nav" }, t.nav.map((n, i) => /* @__PURE__ */ React.createElement("a", { key: i, href: "#" + ["services", "work", "process", "careers", "contact"][i] }, n))), /* @__PURE__ */ React.createElement("div", { className: "hdr-side" }, /* @__PURE__ */ React.createElement("button", { className: "mini", onClick: () => setLoc(loc === "en" ? "vi" : "en") }, t.langLabel), /* @__PURE__ */ React.createElement("button", { className: "mini icon", onClick: () => setDark(!dark), "aria-label": "Toggle theme" }, /* @__PURE__ */ React.createElement(I, { name: dark ? "sun" : "moon", size: 18 })), /* @__PURE__ */ React.createElement("button", { className: "mini", style: { background: "var(--cs-color-brand-umber)", color: "var(--cs-color-text-inverse,#fff)", borderColor: "transparent" }, onClick: () => openChat("") }, t.talk)))), /* @__PURE__ */ React.createElement("main", { id: "main" }, /* @__PURE__ */ React.createElement("section", { className: "hero", id: "top" }, /* @__PURE__ */ React.createElement("div", { className: "container hero-in" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "eyebrow" }, t.eyebrow), /* @__PURE__ */ React.createElement("h1", null, t.slogan), /* @__PURE__ */ React.createElement("div", { className: "vn" }, t.sub), /* @__PURE__ */ React.createElement("p", { className: "lead" }, t.lead), /* @__PURE__ */ React.createElement("div", { className: "wish" }, /* @__PURE__ */ React.createElement("input", { value: wish, onChange: (e) => setWish(e.target.value), onKeyDown: (e) => e.key === "Enter" && openChat(wish), placeholder: t.wishPlaceholder, "aria-label": t.wishPlaceholder }), /* @__PURE__ */ React.createElement("button", { className: "btn-gold", onClick: () => openChat(wish) }, /* @__PURE__ */ React.createElement(I, { name: "sparkle", size: 18 }), t.wishCta))), /* @__PURE__ */ React.createElement("div", { className: "hero-art" }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/lumi-poster.webp", alt: "Lumi, the golden genie" })))), /* @__PURE__ */ React.createElement("div", { className: "marq" }, /* @__PURE__ */ React.createElement("div", { className: "container marq-in" }, t.marquee.map((m, i) => /* @__PURE__ */ React.createElement(React.Fragment, { key: i }, i > 0 && /* @__PURE__ */ React.createElement("b", null, "·"), /* @__PURE__ */ React.createElement("span", null, m))))), /* @__PURE__ */ React.createElement("section", { className: "sec", id: "services" }, /* @__PURE__ */ React.createElement("div", { className: "container" }, /* @__PURE__ */ React.createElement("div", { className: "eyebrow" }, t.nav[0]), /* @__PURE__ */ React.createElement("h2", null, t.servicesTitle), /* @__PURE__ */ React.createElement("p", { className: "sec-lead" }, t.servicesLead), /* @__PURE__ */ React.createElement("div", { className: "svc-grid" }, t.services.map((s, i) => /* @__PURE__ */ React.createElement("article", { className: "svc cs-surface-standard", key: i }, /* @__PURE__ */ React.createElement("div", { className: "svc-ic" }, /* @__PURE__ */ React.createElement(I, { name: s.icon })), /* @__PURE__ */ React.createElement("h3", null, s.t), /* @__PURE__ */ React.createElement("p", null, s.s), /* @__PURE__ */ React.createElement("ul", null, s.o.map((o) => /* @__PURE__ */ React.createElement("li", { key: o }, o)))))))), /* @__PURE__ */ React.createElement("section", { className: "sec sec-alt", id: "process" }, /* @__PURE__ */ React.createElement("div", { className: "container" }, /* @__PURE__ */ React.createElement("div", { className: "eyebrow" }, t.nav[2]), /* @__PURE__ */ React.createElement("h2", null, t.processTitle), /* @__PURE__ */ React.createElement("p", { className: "sec-lead" }, t.processLead), /* @__PURE__ */ React.createElement("div", { className: "steps" }, t.steps.map((s) => /* @__PURE__ */ React.createElement("div", { className: "step", key: s.n }, /* @__PURE__ */ React.createElement("span", { className: "n" }, s.n), /* @__PURE__ */ React.createElement("h3", null, s.t), /* @__PURE__ */ React.createElement("p", null, s.s)))))), /* @__PURE__ */ React.createElement("section", { className: "sec", id: "careers" }, /* @__PURE__ */ React.createElement("div", { className: "container" }, /* @__PURE__ */ React.createElement("div", { className: "band" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", null, t.careersTitle), /* @__PURE__ */ React.createElement("p", null, t.careersLead)), /* @__PURE__ */ React.createElement("button", { className: "btn-gold", onClick: () => openChat("") }, t.careersCta, /* @__PURE__ */ React.createElement(I, { name: "arrow-right", size: 18 }))))), /* @__PURE__ */ React.createElement("section", { className: "sec sec-alt", id: "contact" }, /* @__PURE__ */ React.createElement("div", { className: "container contact-grid" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "eyebrow" }, t.nav[4]), /* @__PURE__ */ React.createElement("h2", null, t.contactTitle), /* @__PURE__ */ React.createElement("p", { className: "sec-lead", style: { marginBottom: 16 } }, t.contactLead), /* @__PURE__ */ React.createElement("p", { className: "trust" }, /* @__PURE__ */ React.createElement(I, { name: "check", size: 16 }), t.form.trust)), sent ? /* @__PURE__ */ React.createElement("div", { className: "sent" }, /* @__PURE__ */ React.createElement(I, { name: "check", size: 18 }), " ", loc === "vi" ? "Đã nhận được lời nhắn. Cảm ơn bạn!" : "Message received. Thank you!") : /* @__PURE__ */ React.createElement("form", { className: "form", onSubmit: (e) => {
5508
5896
  e.preventDefault();
5509
5897
  setSent(true);
5510
- } }, /* @__PURE__ */ React.createElement("label", { className: "cs-field" }, /* @__PURE__ */ React.createElement("span", { className: "cs-field__label" }, t.form.name), /* @__PURE__ */ React.createElement("input", { className: "cs-field__control", required: true })), /* @__PURE__ */ React.createElement("label", { className: "cs-field" }, /* @__PURE__ */ React.createElement("span", { className: "cs-field__label" }, t.form.email), /* @__PURE__ */ React.createElement("input", { className: "cs-field__control", type: "email", required: true })), /* @__PURE__ */ React.createElement("label", { className: "cs-field" }, /* @__PURE__ */ React.createElement("span", { className: "cs-field__label" }, t.form.company, " ", /* @__PURE__ */ React.createElement("span", { className: "muted", style: { fontWeight: 400, color: "var(--cs-color-text-muted)" } }, "· ", t.form.optional)), /* @__PURE__ */ React.createElement("input", { className: "cs-field__control" })), /* @__PURE__ */ React.createElement("label", { className: "cs-field" }, /* @__PURE__ */ React.createElement("span", { className: "cs-field__label" }, t.form.message), /* @__PURE__ */ React.createElement("textarea", { className: "cs-field__control", rows: "3" })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("button", { type: "submit", className: "btn-gold" }, t.form.submit, /* @__PURE__ */ React.createElement(I, { name: "arrow-right", size: 18 })))))), /* @__PURE__ */ React.createElement("footer", { className: "ft" }, /* @__PURE__ */ React.createElement("div", { className: "container ft-in" }, /* @__PURE__ */ React.createElement("a", { className: "brand", href: "#top" }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/logo-mark.svg", alt: "" }), "CyberSkill"), /* @__PURE__ */ React.createElement("div", { className: "ft-links" }, t.footerLinks.map((l) => /* @__PURE__ */ React.createElement("a", { key: l, href: "#top" }, l))), /* @__PURE__ */ React.createElement("small", null, "© 2026 CyberSkill · ", t.footerRights, " · Saigon"))), !chat && /* @__PURE__ */ React.createElement("button", { className: "fab", onClick: () => openChat("") }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/lumi-poster.webp", alt: "" }), t.talk), chat && /* @__PURE__ */ React.createElement(Chat, { t, seed, onClose: () => setChat(false) }));
5898
+ } }, /* @__PURE__ */ React.createElement("label", { className: "cs-field" }, /* @__PURE__ */ React.createElement("span", { className: "cs-field__label" }, t.form.name), /* @__PURE__ */ React.createElement("input", { className: "cs-field__control", required: true })), /* @__PURE__ */ React.createElement("label", { className: "cs-field" }, /* @__PURE__ */ React.createElement("span", { className: "cs-field__label" }, t.form.email), /* @__PURE__ */ React.createElement("input", { className: "cs-field__control", type: "email", required: true })), /* @__PURE__ */ React.createElement("label", { className: "cs-field" }, /* @__PURE__ */ React.createElement("span", { className: "cs-field__label" }, t.form.company, " ", /* @__PURE__ */ React.createElement("span", { className: "muted", style: { fontWeight: 400, color: "var(--cs-color-text-muted)" } }, "· ", t.form.optional)), /* @__PURE__ */ React.createElement("input", { className: "cs-field__control" })), /* @__PURE__ */ React.createElement("label", { className: "cs-field" }, /* @__PURE__ */ React.createElement("span", { className: "cs-field__label" }, t.form.message), /* @__PURE__ */ React.createElement("textarea", { className: "cs-field__control", rows: "3" })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("button", { type: "submit", className: "btn-gold" }, t.form.submit, /* @__PURE__ */ React.createElement(I, { name: "arrow-right", size: 18 }))))))), /* @__PURE__ */ React.createElement("footer", { className: "ft" }, /* @__PURE__ */ React.createElement("div", { className: "container ft-in" }, /* @__PURE__ */ React.createElement("a", { className: "brand", href: "#top" }, /* @__PURE__ */ React.createElement("img", { src: "../../assets/logo-mark.svg", alt: "" }), "CyberSkill"), /* @__PURE__ */ React.createElement("div", { className: "ft-links" }, t.footerLinks.map((l) => /* @__PURE__ */ React.createElement("a", { key: l, href: "#top" }, l))), /* @__PURE__ */ React.createElement("small", null, "© 2026 CyberSkill · ", t.footerRights, " · Saigon"))), !chat && /* @__PURE__ */ React.createElement(
5899
+ "button",
5900
+ {
5901
+ className: "fab",
5902
+ type: "button",
5903
+ "data-fab-deferred": "1",
5904
+ onClick: () => openChat(""),
5905
+ style: { opacity: fabVisible ? 1 : 0, pointerEvents: fabVisible ? "auto" : "none", transition: "opacity 160ms ease" },
5906
+ "aria-hidden": !fabVisible,
5907
+ tabIndex: fabVisible ? 0 : -1
5908
+ },
5909
+ /* @__PURE__ */ React.createElement("img", { src: "../../assets/lumi-poster.webp", alt: "" }),
5910
+ t.talk
5911
+ ), chat && /* @__PURE__ */ React.createElement(Chat, { t, seed, onClose: () => setChat(false) }));
5511
5912
  }
5512
5913
  window.Website = Website;
5513
5914
  })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/website/Website.jsx", error: String((e && e.message) || e) }); }
@@ -5824,6 +6225,8 @@ __ds_ns.Drawer = __ds_scope.Drawer;
5824
6225
 
5825
6226
  __ds_ns.HoverCard = __ds_scope.HoverCard;
5826
6227
 
6228
+ __ds_ns.OverlayProvider = __ds_scope.OverlayProvider;
6229
+
5827
6230
  __ds_ns.Popconfirm = __ds_scope.Popconfirm;
5828
6231
 
5829
6232
  __ds_ns.Popover = __ds_scope.Popover;