@cyberskill/design 1.2.0 → 1.3.8

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 (215) hide show
  1. package/DESIGN.md +4 -3
  2. package/README.md +20 -19
  3. package/SKILL.md +5 -5
  4. package/THIRD-PARTY-NOTICES.md +35 -0
  5. package/VERSION +1 -1
  6. package/_ds_bundle.js +701 -1342
  7. package/_esm/cs.mjs +2 -2
  8. package/_esm/react.mjs +6 -1
  9. package/_vendor/NOTICE.md +16 -0
  10. package/_vendor/babel/README.md +7 -0
  11. package/_vendor/babel/babel.min.js +4 -0
  12. package/_vendor/react/README.md +3 -0
  13. package/_vendor/react/react-dom.production.min.js +1 -0
  14. package/_vendor/react/react.production.min.js +1 -0
  15. package/assets/aurora-hoa.webp +0 -0
  16. package/assets/aurora-kim.webp +0 -0
  17. package/assets/aurora-moc.webp +0 -0
  18. package/assets/aurora-tho.webp +0 -0
  19. package/assets/aurora-thuy.webp +0 -0
  20. package/base/ai.css +8 -3
  21. package/base/collections.css +10 -4
  22. package/base/components.css +5 -2
  23. package/base/controls.css +58 -21
  24. package/base/data.css +1 -1
  25. package/base/feedback.css +9 -2
  26. package/base/forms.css +1 -1
  27. package/base/glass.css +1 -1
  28. package/base/interaction.css +6 -2
  29. package/base/navigation.css +1 -1
  30. package/base/reset.css +7 -1
  31. package/base/responsive.css +13 -12
  32. package/base/shell.css +8 -2
  33. package/components/_i18n/i18n.js +28 -3
  34. package/components/_i18n/strings.js +42 -24
  35. package/components/ai/ChatMessage.d.ts +2 -0
  36. package/components/ai/ChatMessage.jsx +8 -4
  37. package/components/ai/ConfidenceMeter.d.ts +2 -0
  38. package/components/ai/HumanReviewGate.d.ts +2 -0
  39. package/components/ai/PromptInput.d.ts +2 -0
  40. package/components/ai/TypingIndicator.d.ts +2 -0
  41. package/components/ai/ai-conversation.card.html +3 -3
  42. package/components/ai/ai-lumi.card.html +3 -3
  43. package/components/ai/ai.card.html +3 -3
  44. package/components/brand/brand.card.html +3 -3
  45. package/components/button/buttons.card.html +3 -3
  46. package/components/data/Image.jsx +18 -2
  47. package/components/data/Sortable.d.ts +5 -1
  48. package/components/data/Sortable.jsx +42 -9
  49. package/components/data/Sortable.prompt.md +4 -2
  50. package/components/data/Terminal.jsx +3 -2
  51. package/components/data/Tooltip.d.ts +2 -0
  52. package/components/data/Tooltip.jsx +6 -3
  53. package/components/data/Tree.d.ts +2 -1
  54. package/components/data/Tree.jsx +137 -16
  55. package/components/data/Tree.prompt.md +1 -1
  56. package/components/data/collections.card.html +3 -3
  57. package/components/data/data.card.html +3 -3
  58. package/components/datatable/DataTable.d.ts +24 -1
  59. package/components/datatable/DataTable.jsx +78 -5
  60. package/components/datatable/DataTable.prompt.md +2 -1
  61. package/components/datatable/datatable.card.html +20 -16
  62. package/components/dialog/dialog.card.html +3 -3
  63. package/components/feedback/Alert.d.ts +2 -0
  64. package/components/feedback/Alert.jsx +8 -2
  65. package/components/feedback/EmptyState.d.ts +2 -0
  66. package/components/feedback/EmptyState.jsx +6 -3
  67. package/components/feedback/ProgressBar.d.ts +2 -0
  68. package/components/feedback/ProgressBar.jsx +6 -3
  69. package/components/feedback/Toast.jsx +15 -1
  70. package/components/feedback/Toast.prompt.md +2 -1
  71. package/components/feedback/feedback-2.card.html +3 -3
  72. package/components/feedback/feedback.card.html +3 -3
  73. package/components/forms/Cascader.jsx +7 -2
  74. package/components/forms/FileUpload.d.ts +2 -0
  75. package/components/forms/Form.d.ts +3 -1
  76. package/components/forms/Form.jsx +9 -1
  77. package/components/forms/Form.prompt.md +1 -1
  78. package/components/forms/Mentions.d.ts +1 -1
  79. package/components/forms/Mentions.jsx +59 -7
  80. package/components/forms/Mentions.prompt.md +3 -1
  81. package/components/forms/Rating.d.ts +3 -2
  82. package/components/forms/Rating.jsx +34 -3
  83. package/components/forms/Rating.prompt.md +1 -1
  84. package/components/forms/Select.d.ts +2 -0
  85. package/components/forms/Select.jsx +6 -2
  86. package/components/forms/Slider.d.ts +2 -0
  87. package/components/forms/Slider.jsx +5 -2
  88. package/components/forms/Switch.d.ts +2 -0
  89. package/components/forms/Switch.jsx +7 -9
  90. package/components/forms/Toggle.d.ts +2 -0
  91. package/components/forms/Toggle.jsx +14 -2
  92. package/components/forms/forms-2.card.html +3 -3
  93. package/components/forms/forms.card.html +3 -3
  94. package/components/icon/Icon.d.ts +1 -1
  95. package/components/icon/Icon.prompt.md +1 -1
  96. package/components/icon/icon.card.html +3 -3
  97. package/components/logo/logo.card.html +3 -3
  98. package/components/navigation/CommandPalette.d.ts +2 -0
  99. package/components/navigation/Menu.d.ts +2 -0
  100. package/components/navigation/Menu.jsx +60 -6
  101. package/components/navigation/Steps.d.ts +2 -0
  102. package/components/navigation/Steps.jsx +6 -3
  103. package/components/navigation/Tabs.d.ts +2 -0
  104. package/components/navigation/Tabs.jsx +6 -3
  105. package/components/navigation/Toolbar.d.ts +3 -2
  106. package/components/navigation/Toolbar.jsx +117 -11
  107. package/components/navigation/Toolbar.prompt.md +1 -1
  108. package/components/navigation/navigation.card.html +3 -3
  109. package/components/navigation/shell.card.html +3 -3
  110. package/components/overlays/ContextMenu.d.ts +2 -0
  111. package/components/overlays/ContextMenu.jsx +6 -3
  112. package/components/overlays/Drawer.d.ts +2 -0
  113. package/components/overlays/alertdialog.card.html +3 -3
  114. package/components/overlays/overlays.card.html +3 -3
  115. package/components/textfield/textfield.card.html +3 -3
  116. package/dist/styles.min.css +312 -64
  117. package/docs/ci-cd.md +18 -13
  118. package/docs/consumer-grant.md +3 -0
  119. package/docs/consuming.md +7 -7
  120. package/docs/contrast-report.md +79 -1
  121. package/docs/conventions.md +17 -4
  122. package/docs/decisions.md +40 -2
  123. package/docs/deploy.md +17 -6
  124. package/docs/design-styles.md +1 -1
  125. package/docs/quality-gates.md +19 -11
  126. package/docs/release-runbook.md +78 -0
  127. package/docs/sync.md +1 -1
  128. package/docs/vi/ci-cd.md +16 -13
  129. package/docs/vi/consumer-grant.md +3 -0
  130. package/docs/vi/consuming.md +7 -7
  131. package/docs/vi/contrast-report.md +79 -1
  132. package/docs/vi/conventions.md +18 -5
  133. package/docs/vi/decisions.md +39 -2
  134. package/docs/vi/deploy.md +17 -6
  135. package/docs/vi/quality-gates.md +18 -11
  136. package/docs/vi/release-runbook.md +78 -0
  137. package/docs/vi/sync.md +1 -1
  138. package/docs/viewer.html +2 -2
  139. package/fonts/OFL.txt +98 -0
  140. package/guidelines/atomic-view.html +2 -2
  141. package/guidelines/brand-imagery.html +1 -1
  142. package/guidelines/elements-variants.html +5 -5
  143. package/guidelines/spacing-breakpoints.html +2 -1
  144. package/guidelines/surfaces-glass.html +1 -1
  145. package/llms.txt +4 -4
  146. package/package.json +28 -8
  147. package/templates/app-shell/AppShell.dc.html +3 -3
  148. package/templates/app-shell/content-schema.json +7 -0
  149. package/templates/article/Article.dc.html +3 -3
  150. package/templates/article/content-schema.json +7 -0
  151. package/templates/auth/Auth.dc.html +26 -10
  152. package/templates/auth/content-schema.json +25 -0
  153. package/templates/dashboard/Dashboard.dc.html +4 -4
  154. package/templates/dashboard/content-schema.json +7 -0
  155. package/templates/delivery-change-note/DeliveryChangeNote.dc.html +2 -2
  156. package/templates/delivery-runbook/DeliveryRunbook.dc.html +2 -2
  157. package/templates/email-safe/email-announcement.html +2 -2
  158. package/templates/email-safe/email-dunning.html +2 -2
  159. package/templates/email-safe/email-investor.html +2 -2
  160. package/templates/email-safe/email-launch.html +2 -2
  161. package/templates/email-safe/email-newsletter.html +2 -2
  162. package/templates/email-safe/email-status.html +2 -2
  163. package/templates/email-safe/email-transactional.html +2 -2
  164. package/templates/finance-dunning-email/FinanceDunningEmail.dc.html +2 -2
  165. package/templates/finance-expense-report/FinanceExpenseReport.dc.html +2 -2
  166. package/templates/finance-invoice/FinanceInvoice.dc.html +2 -2
  167. package/templates/finance-quote/FinanceQuote.dc.html +4 -4
  168. package/templates/hr-interview-kit/HrInterviewKit.dc.html +1 -1
  169. package/templates/marketing-case-study/MarketingCaseStudy.dc.html +1 -1
  170. package/templates/marketing-page/MarketingPage.dc.html +3 -3
  171. package/templates/marketing-page/content-schema.json +1 -0
  172. package/templates/settings/Settings.dc.html +3 -3
  173. package/templates/settings/content-schema.json +7 -0
  174. package/tokens/element-seeds.json +2 -2
  175. package/tokens/elements.css +193 -19
  176. package/tokens/native/CSTokens.kt +3 -2
  177. package/tokens/native/CSTokens.swift +3 -2
  178. package/tokens/native/cs_tokens.dart +3 -2
  179. package/tokens/provenance.json +8 -8
  180. package/tokens/spacing.css +2 -1
  181. package/tokens/tokens.dtcg.json +19 -14
  182. package/tokens/tokens.js +16 -15
  183. package/tokens/tokens.json +15 -14
  184. package/ui_kits/deck/index.html +1 -1
  185. package/ui_kits/status-hub/StatusHub.jsx +1 -1
  186. package/ui_kits/status-hub/login.html +52 -10
  187. package/ui_kits/status-hub/project.html +1 -1
  188. package/ui_kits/status-hub/settings.html +1 -1
  189. package/ui_kits/website/Website.jsx +1 -1
  190. package/ui_kits/website/careers.html +2 -2
  191. package/ui_kits/website/chat.html +1 -1
  192. package/ui_kits/website/site.css +1 -1
  193. package/ui_kits/website/work.html +2 -2
  194. package/assets/aurora-hoa.png +0 -0
  195. package/assets/aurora-kim.png +0 -0
  196. package/assets/aurora-moc.png +0 -0
  197. package/assets/aurora-thuy.png +0 -0
  198. package/docs/decisions/container-query-migration.md +0 -18
  199. package/docs/decisions/overlay-manager-design.md +0 -101
  200. package/docs/plans/cyberskill-design-system-audit-and-12-month-evolution-plan.md +0 -1490
  201. package/docs/status/assets/favicon.svg +0 -5
  202. package/docs/status/assets/status-legacy.css +0 -399
  203. package/docs/status/assets/status-legacy.js +0 -505
  204. package/docs/status/assets/status.css +0 -644
  205. package/docs/status/assets/status.js +0 -1308
  206. package/docs/status/data/status-feed.json +0 -1
  207. package/docs/status/data/task/TASK-REL-001.js +0 -1
  208. package/docs/status/data/task/TASK-REL-002.js +0 -1
  209. package/docs/status/index.html +0 -46
  210. package/docs/status/roadmap.html +0 -4
  211. package/docs/status/status-legacy.html +0 -122
  212. package/docs/tasks/BACKLOG.md +0 -26
  213. package/docs/tasks/_state/commit-links.yaml +0 -14
  214. package/docs/tasks/release/TASK-REL-001-launch-1-1-0/spec.md +0 -55
  215. package/docs/tasks/release/TASK-REL-002-republish-1-1-1/spec.md +0 -54
@@ -13,7 +13,7 @@
13
13
  <script src="./ds-base.js"></script>
14
14
  </helmet>
15
15
  <div data-theme="{{ rootTheme }}" lang="{{ langAttr }}" data-cs-element="{{ elAttr }}" data-cs-variant="{{ vaAttr }}" style="font-family:var(--cs-font-family-ui);color:var(--cs-color-text-primary);background:var(--cs-color-surface-page);min-height:100vh">
16
- <a class="cs-skip" href="#main" style="position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden">Skip to content</a>
16
+ <a class="cs-skip" href="#main" style="position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden">{{ skipLabel }}</a>
17
17
  <main id="main">
18
18
  <article style="max-width:720px;margin:0 auto;padding:56px 28px 80px">
19
19
  <div style="font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:0.12em;color:var(--cs-color-text-accent)">{{ eyebrow }}</div>
@@ -49,14 +49,14 @@ class Component extends DCLogic {
49
49
  const [elAttr, vaAttr] = EL[this.props.element] || EL["Thổ · studio"];
50
50
  const vn = this.props.language === "Tiếng Việt";
51
51
  const code = '<div class="cs-glass-card">\n <h3>Design System v1.6</h3>\n</div>';
52
- const en = {
52
+ const en = { skipLabel:"Skip to content",
53
53
  eyebrow:"Engineering · Design systems", h1:"Liquid Glass, now bound to components", meta:"18 Jul 2026 · 6 min read", badge:"New", authorTeam:"Platform",
54
54
  lede:"Five glass materials over the immutable Umber and Ochre anchors — and now they are one class away on any surface. Here's how the bindings work, and when to reach for each.",
55
55
  p1:"Liquid Glass is CyberSkill's default surface treatment: translucent, refractive layers that let warm gold light show through. The material scalars live in tokens; this release wires them to real components so a card, a nav, or a modal can opt in with a single class.",
56
56
  h2:"When to reach for glass", p2:"Keep dense content on solid surfaces. Reserve glass for nav, cards over imagery, and modals — always after an APCA check against the backdrop.",
57
57
  alertTitle:"Rule of thumb", alertBody:"If text sits directly on a busy photo, step up one glass tier or drop to a solid surface.",
58
58
  p3:"That's the whole surface. Everything paints from the same anchors — warm, honest, and Vietnamese-first by default."};
59
- const vi = {
59
+ const vi = { skipLabel:"Bỏ qua nội dung",
60
60
  eyebrow:"Kỹ thuật · Design system", h1:"Liquid Glass, nay gắn vào component", meta:"18/07/2026 · đọc 6 phút", badge:"Mới", authorTeam:"Nền tảng",
61
61
  lede:"Năm vật liệu kính trên hai màu neo bất biến Umber và Ochre — và giờ chỉ cách một class trên mọi bề mặt. Đây là cách các liên kết hoạt động, và khi nào nên dùng từng loại.",
62
62
  p1:"Liquid Glass là lớp bề mặt mặc định của CyberSkill: những lớp mờ, khúc xạ, để ánh vàng ấm hiện qua. Hệ số vật liệu nằm trong token; bản phát hành này gắn chúng vào component thật, để một card, một nav hay một modal có thể bật lên chỉ bằng một class.",
@@ -2,6 +2,13 @@
2
2
  "$schemaVersion": "2.0",
3
3
  "template": "article",
4
4
  "slots": [
5
+ {
6
+ "id": "skipLabel",
7
+ "type": "text",
8
+ "label": "Skip-to-content link label",
9
+ "maxLength": 40,
10
+ "required": true
11
+ },
5
12
  {
6
13
  "id": "eyebrow",
7
14
  "type": "text",
@@ -8,7 +8,7 @@
8
8
  </head>
9
9
  <body>
10
10
  <x-dc>
11
- <!-- @template name="Sign in" description="CyberSkill split sign-in — umber brand panel + form built from TextField, Switch, and Button. Bilingual (English · Tiếng Việt)." -->
11
+ <!-- @template name="Sign in" description="CyberSkill split sign-in — umber brand panel + form built from TextField, Switch, Button, and Alert. formState tweak: default | loading | error | invalid. Bilingual (English · Tiếng Việt)." -->
12
12
  <helmet>
13
13
  <script src="./ds-base.js"></script>
14
14
  </helmet>
@@ -25,7 +25,7 @@
25
25
  }
26
26
  </style>
27
27
  <div class="cs-auth-shell" data-theme="{{ rootTheme }}" lang="{{ langAttr }}" data-cs-element="{{ elAttr }}" data-cs-variant="{{ vaAttr }}">
28
- <a class="cs-skip" href="#main" style="position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden">Skip to content</a>
28
+ <a class="cs-skip" href="#main" style="position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden">{{ skipLabel }}</a>
29
29
  <main id="main">
30
30
  <sc-if value="{{ showBrand }}" hint-placeholder-val="{{ true }}">
31
31
  <div class="cs-auth-brand">
@@ -34,7 +34,7 @@
34
34
  <div style="position:relative;z-index:1;display:flex;align-items:center;gap:12px;font-weight:800;font-size:20px">
35
35
  <x-import component-from-global-scope="CyberSkillDS.Logo" size="40" hint-size="40px,40px"></x-import>CyberSkill
36
36
  </div>
37
- <h2 style="position:relative;z-index:1;font-size:40px;font-weight:800;letter-spacing:-0.02em;line-height:1.08;color:var(--cs-accent-bright);margin:auto 0 8px">{{ brandH }}</h2>
37
+ <p style="position:relative;z-index:1;font-size:40px;font-weight:800;letter-spacing:-0.02em;line-height:1.08;color:var(--cs-accent-bright);margin:auto 0 8px">{{ brandH }}</p>
38
38
  <p style="position:relative;z-index:1;font-size:17px;opacity:0.9;margin:0;max-width:420px">{{ brandP }}</p>
39
39
  </div>
40
40
  </sc-if>
@@ -43,10 +43,13 @@
43
43
  <h1 style="font-size:30px;font-weight:800;letter-spacing:-0.02em;margin:0 0 4px">{{ title }}</h1>
44
44
  <p style="color:var(--cs-color-text-muted);margin:0 0 28px">{{ sub }}</p>
45
45
  <div style="display:grid;gap:16px">
46
- <x-import component-from-global-scope="CyberSkillDS.TextField" label="{{ emailL }}" type="email" placeholder="you@cyberskill.world" hint-size="100%,74px"></x-import>
46
+ <sc-if value="{{ showError }}" hint-placeholder-val="{{ false }}">
47
+ <x-import component-from-global-scope="CyberSkillDS.Alert" variant="danger" title="{{ errTitle }}" hint-size="100%,64px">{{ errBody }}</x-import>
48
+ </sc-if>
49
+ <x-import component-from-global-scope="CyberSkillDS.TextField" label="{{ emailL }}" type="email" placeholder="you@cyberskill.world" error="{{ emailError }}" hint-size="100%,74px"></x-import>
47
50
  <x-import component-from-global-scope="CyberSkillDS.TextField" label="{{ pwL }}" type="password" placeholder="••••••••" hint-size="100%,74px"></x-import>
48
51
  <x-import component-from-global-scope="CyberSkillDS.Switch" label="{{ rememberL }}" checked="{{ false }}" hint-size="140px,26px"></x-import>
49
- <x-import component-from-global-scope="CyberSkillDS.Button" variant="primary" full-width="{{ true }}" hint-size="100%,44px">{{ signInBtn }}</x-import>
52
+ <x-import component-from-global-scope="CyberSkillDS.Button" variant="primary" full-width="{{ true }}" loading="{{ isLoading }}" hint-size="100%,44px">{{ signInBtn }}</x-import>
50
53
  <x-import component-from-global-scope="CyberSkillDS.Button" variant="ghost" full-width="{{ true }}" hint-size="100%,44px">{{ lumiBtn }}</x-import>
51
54
  </div>
52
55
  <p style="text-align:center;font-size:13px;color:var(--cs-color-text-muted);margin-top:16px">{{ newHere }} <a href="#">{{ askAccess }}</a></p>
@@ -60,16 +63,29 @@
60
63
  &quot;language&quot;: {&quot;editor&quot;:&quot;enum&quot;,&quot;options&quot;:[&quot;English&quot;,&quot;Tiếng Việt&quot;],&quot;default&quot;:&quot;English&quot;,&quot;tsType&quot;:&quot;\&quot;English\&quot; | \&quot;Tiếng Việt\&quot;&quot;,&quot;section&quot;:&quot;Content&quot;},
61
64
  &quot;element&quot;: {&quot;editor&quot;:&quot;enum&quot;,&quot;options&quot;:[&quot;Thổ · studio&quot;,&quot;Thổ · clay&quot;,&quot;Thổ · sand&quot;,&quot;Hỏa · ember&quot;,&quot;Hỏa · lava&quot;,&quot;Hỏa · plasma&quot;,&quot;Thủy · river&quot;,&quot;Thủy · ocean&quot;,&quot;Thủy · mist&quot;,&quot;Mộc · leaf&quot;,&quot;Mộc · bamboo&quot;,&quot;Mộc · forest&quot;,&quot;Kim · champagne&quot;,&quot;Kim · steel&quot;,&quot;Kim · titanium&quot;],&quot;default&quot;:&quot;Thổ · studio&quot;,&quot;tsType&quot;:&quot;string&quot;,&quot;section&quot;:&quot;Element (Ngũ Hành)&quot;},
62
65
  &quot;theme&quot;: {&quot;editor&quot;:&quot;enum&quot;,&quot;options&quot;:[&quot;light&quot;,&quot;dark&quot;],&quot;default&quot;:&quot;light&quot;,&quot;tsType&quot;:&quot;\&quot;light\&quot; | \&quot;dark\&quot;&quot;,&quot;section&quot;:&quot;Theme&quot;},
63
- &quot;showBrandPanel&quot;: {&quot;editor&quot;:&quot;boolean&quot;,&quot;default&quot;:true,&quot;tsType&quot;:&quot;boolean&quot;,&quot;section&quot;:&quot;Layout&quot;}
66
+ &quot;showBrandPanel&quot;: {&quot;editor&quot;:&quot;boolean&quot;,&quot;default&quot;:true,&quot;tsType&quot;:&quot;boolean&quot;,&quot;section&quot;:&quot;Layout&quot;},
67
+ &quot;formState&quot;: {&quot;editor&quot;:&quot;enum&quot;,&quot;options&quot;:[&quot;default&quot;,&quot;loading&quot;,&quot;error&quot;,&quot;invalid&quot;],&quot;default&quot;:&quot;default&quot;,&quot;tsType&quot;:&quot;\&quot;default\&quot; | \&quot;loading\&quot; | \&quot;error\&quot; | \&quot;invalid\&quot;&quot;,&quot;section&quot;:&quot;Form states&quot;}
64
68
  }">
65
69
  class Component extends DCLogic {
66
70
  renderVals() {
67
71
  const EL = {"Thổ · studio":["tho",""],"Thổ · clay":["tho","clay"],"Thổ · sand":["tho","sand"],"Hỏa · ember":["hoa",""],"Hỏa · lava":["hoa","lava"],"Hỏa · plasma":["hoa","plasma"],"Thủy · river":["thuy",""],"Thủy · ocean":["thuy","ocean"],"Thủy · mist":["thuy","mist"],"Mộc · leaf":["moc",""],"Mộc · bamboo":["moc","bamboo"],"Mộc · forest":["moc","forest"],"Kim · champagne":["kim",""],"Kim · steel":["kim","steel"],"Kim · titanium":["kim","titanium"]};
68
72
  const [elAttr, vaAttr] = EL[this.props.element] || EL["Thổ · studio"];
69
- const vn = this.props.language === "Tiếng Việt";
70
- const en = { brandH:"Turn Your Will Into Real", brandP:"Sign in to your workspace — one page, three lenses across every wish in flight.", title:"Sign in", sub:"Welcome back. Sign in to continue.", emailL:"Work email", pwL:"Password", rememberL:"Remember me", signInBtn:"Sign in", lumiBtn:"✦ Talk to Lumi instead", newHere:"New here?", askAccess:"Ask for access", resetHint:"Forgot password?", resetLink:"Email your workspace admin to reset." };
71
- const vi = { brandH:"Hiện Thực Hoá Ý Chí", brandP:"Đăng nhập vào không gian làm việc — một trang, ba lăng kính cho mọi điều ước đang chạy.", title:"Đăng nhập", sub:"Mừng bạn quay lại. Đăng nhập để tiếp tục.", emailL:"Email công việc", pwL:"Mật khẩu", rememberL:"Ghi nhớ đăng nhập", signInBtn:"Đăng nhập", lumiBtn:"✦ Trò chuyện với Lumi", newHere:"Lần đầu?", askAccess:"Xin quyền truy cập", resetHint:"Quên mật khẩu?", resetLink:"Gửi email cho quản trị không gian làm việc để đặt lại." };
72
- return Object.assign({ langAttr: (this.props.language ?? "English") === "Tiếng Việt" ? "vi" : "en", elAttr, vaAttr, rootTheme: this.props.theme === "dark" ? "dark" : "", showBrand: this.props.showBrandPanel ?? true }, vn ? vi : en);
73
+ const vn = this.props.language === "Tiếng Việt";
74
+ const state = this.props.formState || "default";
75
+ const en = { skipLabel:"Skip to content", brandH:"Turn Your Will Into Real", brandP:"Sign in to your workspace — one page, three lenses across every wish in flight.", title:"Sign in", sub:"Welcome back. Sign in to continue.", emailL:"Work email", pwL:"Password", rememberL:"Remember me", signInBtn: state === "loading" ? "Signing in…" : "Sign in", lumiBtn:"✦ Talk to Lumi instead", newHere:"New here?", askAccess:"Ask for access", resetHint:"Forgot password?", resetLink:"Email your workspace admin to reset.", errTitle:"Sign-in failed", errBody:"Check your email and password, then try again.", emailErr:"Enter a valid work email." };
76
+ const vi = { skipLabel:"Bỏ qua nội dung", brandH:"Hiện Thực Hoá Ý Chí", brandP:"Đăng nhập vào không gian làm việc — một trang, ba lăng kính cho mọi điều ước đang chạy.", title:"Đăng nhập", sub:"Mừng bạn quay lại. Đăng nhập để tiếp tục.", emailL:"Email công việc", pwL:"Mật khẩu", rememberL:"Ghi nhớ đăng nhập", signInBtn: state === "loading" ? "Đang đăng nhập…" : "Đăng nhập", lumiBtn:"✦ Trò chuyện với Lumi", newHere:"Lần đầu?", askAccess:"Xin quyền truy cập", resetHint:"Quên mật khẩu?", resetLink:"Gửi email cho quản trị không gian làm việc để đặt lại.", errTitle:"Đăng nhập thất bại", errBody:"Kiểm tra email và mật khẩu, rồi thử lại.", emailErr:"Nhập email công việc hợp lệ." };
77
+ const copy = vn ? vi : en;
78
+ return Object.assign({
79
+ langAttr: (this.props.language ?? "English") === "Tiếng Việt" ? "vi" : "en",
80
+ elAttr, vaAttr,
81
+ rootTheme: this.props.theme === "dark" ? "dark" : "",
82
+ showBrand: this.props.showBrandPanel ?? true,
83
+ showError: state === "error",
84
+ isLoading: state === "loading",
85
+ emailError: state === "invalid" ? copy.emailErr : "",
86
+ errTitle: copy.errTitle,
87
+ errBody: copy.errBody
88
+ }, copy);
73
89
  }
74
90
  }
75
91
  </script>
@@ -2,6 +2,13 @@
2
2
  "$schemaVersion": "2.0",
3
3
  "template": "auth",
4
4
  "slots": [
5
+ {
6
+ "id": "skipLabel",
7
+ "type": "text",
8
+ "label": "Skip-to-content link label",
9
+ "maxLength": 40,
10
+ "required": true
11
+ },
5
12
  {
6
13
  "id": "brandH",
7
14
  "type": "text",
@@ -81,6 +88,24 @@
81
88
  "type": "text",
82
89
  "label": "Password-reset action link",
83
90
  "maxLength": 64
91
+ },
92
+ {
93
+ "id": "errTitle",
94
+ "type": "text",
95
+ "label": "Sign-in error alert title (error/invalid states)",
96
+ "maxLength": 40
97
+ },
98
+ {
99
+ "id": "errBody",
100
+ "type": "text",
101
+ "label": "Sign-in error alert body",
102
+ "maxLength": 120
103
+ },
104
+ {
105
+ "id": "emailError",
106
+ "type": "text",
107
+ "label": "Email field validation error (invalid state)",
108
+ "maxLength": 64
84
109
  }
85
110
  ]
86
111
  }
@@ -13,7 +13,7 @@
13
13
  <script src="./ds-base.js"></script>
14
14
  </helmet>
15
15
  <div data-theme="{{ rootTheme }}" lang="{{ langAttr }}" data-cs-element="{{ elAttr }}" data-cs-variant="{{ vaAttr }}" style="font-family:var(--cs-font-family-ui);color:var(--cs-color-text-primary);background:var(--cs-color-surface-page);min-height:100vh">
16
- <a class="cs-skip" href="#main" style="position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden">Skip to content</a>
16
+ <a class="cs-skip" href="#main" style="position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden">{{ skipLabel }}</a>
17
17
  <main id="main">
18
18
  <header style="background:var(--cs-accent-strong);color:var(--cs-accent-on-strong);border-bottom:3px solid var(--cs-accent)">
19
19
  <div style="max-width:1280px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:18px 28px;flex-wrap:wrap">
@@ -23,7 +23,7 @@
23
23
  </span>
24
24
  <div>
25
25
  <h1 style="margin:0;font-size:22px;letter-spacing:0.2px">Status Hub</h1>
26
- <p style="margin:2px 0 0;font-size:13px;opacity:0.8">{{ tagline }}</p>
26
+ <p style="margin:2px 0 0;font-size:13px;color:var(--cs-accent-on-strong)">{{ tagline }}</p>
27
27
  </div>
28
28
  </div>
29
29
  <span>
@@ -105,8 +105,8 @@ class Component extends DCLogic {
105
105
  const [elAttr, vaAttr] = EL[this.props.element] || EL["Thổ · studio"];
106
106
  const lens = this.lens;
107
107
  const vn = this.props.language === "Tiếng Việt";
108
- const en = { tagline:"Portfolio · one page, three lenses", newBtn:"New project", s1:"Projects", s2:"In progress", s3:"Shipped", s4:"Avg progress", s4d:"+6 this week", boardL:"Board", tableL:"Table", c1:"Liquid Glass component bindings + 15 element packs.", c2:"Bilingual storytelling landing; lead capture live.", c3:"BRAIN memory store + human-in-the-loop gates.", stInprog:"In progress", stBlocked:"Blocked", tblCap:"Projects", cKey:"Key", cName:"Project", cSquad:"Squad", cProg:"Progress", cStatus:"Status" };
109
- const vi = { tagline:"Danh mục · một trang, ba lăng kính", newBtn:"Dự án mới", s1:"Dự án", s2:"Đang làm", s3:"Đã ra mắt", s4:"Tiến độ TB", s4d:"+6 tuần này", boardL:"Bảng", tableL:"Danh sách", c1:"Gắn component Liquid Glass + 15 element pack.", c2:"Landing kể chuyện song ngữ; thu lead đã chạy.", c3:"Kho ký ức BRAIN + cổng có con người kiểm duyệt.", stInprog:"Đang làm", stBlocked:"Bị chặn", tblCap:"Dự án", cKey:"Mã", cName:"Dự án", cSquad:"Nhóm", cProg:"Tiến độ", cStatus:"Trạng thái" };
108
+ const en = { skipLabel:"Skip to content", tagline:"Portfolio · one page, three lenses", newBtn:"New project", s1:"Projects", s2:"In progress", s3:"Shipped", s4:"Avg progress", s4d:"+6 this week", boardL:"Board", tableL:"Table", c1:"Liquid Glass component bindings + 15 element packs.", c2:"Bilingual storytelling landing; lead capture live.", c3:"BRAIN memory store + human-in-the-loop gates.", stInprog:"In progress", stBlocked:"Blocked", tblCap:"Projects", cKey:"Key", cName:"Project", cSquad:"Squad", cProg:"Progress", cStatus:"Status" };
109
+ const vi = { skipLabel:"Bỏ qua nội dung", tagline:"Danh mục · một trang, ba lăng kính", newBtn:"Dự án mới", s1:"Dự án", s2:"Đang làm", s3:"Đã ra mắt", s4:"Tiến độ TB", s4d:"+6 tuần này", boardL:"Bảng", tableL:"Danh sách", c1:"Gắn component Liquid Glass + 15 element pack.", c2:"Landing kể chuyện song ngữ; thu lead đã chạy.", c3:"Kho ký ức BRAIN + cổng có con người kiểm duyệt.", stInprog:"Đang làm", stBlocked:"Bị chặn", tblCap:"Dự án", cKey:"Mã", cName:"Dự án", cSquad:"Nhóm", cProg:"Tiến độ", cStatus:"Trạng thái" };
110
110
  const t = vn ? vi : en;
111
111
  return Object.assign({ langAttr: (this.props.language ?? "English") === "Tiếng Việt" ? "vi" : "en", elAttr, vaAttr, rootTheme: this.props.theme === "dark" ? "dark" : "", lens, isBoard: lens === "board", isTable: lens === "table",
112
112
  tabs: [{ value: "board", label: t.boardL }, { value: "table", label: t.tableL, count: 3 }],
@@ -2,6 +2,13 @@
2
2
  "$schemaVersion": "2.0",
3
3
  "template": "dashboard",
4
4
  "slots": [
5
+ {
6
+ "id": "skipLabel",
7
+ "type": "text",
8
+ "label": "Skip-to-content link label",
9
+ "maxLength": 40,
10
+ "required": true
11
+ },
5
12
  {
6
13
  "id": "tagline",
7
14
  "type": "text",
@@ -60,7 +60,7 @@ class Component extends DCLogic {
60
60
  const vn = this.props.language === "Tiếng Việt";
61
61
  const en = {
62
62
  eyebrow:"Change note · under SOW-2026-014", h1:"Add A/B experiment kit to the checkout scope",
63
- altTitle:"Văn bản thay đổi phạm vi",
63
+ altTitle:"Scope amendment note",
64
64
  intro:"Per the MSA, changes happen in writing, signed by both parties. This note states the change, why, and exactly what it does to scope, fee, and timeline — nothing else in the SOW moves.",
65
65
  changeH:"The change", changeP:"Add the optional A/B kit from quote QT-2026-0088: experiment framework on the new checkout plus the first two tests (copy variants; shipping-threshold banner).",
66
66
  whyH:"Why now", whyP:"The canary shows recoverable drop-off at the shipping step. Testing while the team is in the code is cheaper than a second engagement later. Honest trade-off: it adds a week to M3.",
@@ -70,7 +70,7 @@ const vn = this.props.language === "Tiếng Việt";
70
70
  sigMeta:"Name / title / date", clientName:"[Client Ltd]", rTimeB:"31 Oct 2026", rTimeA:"07 Nov 2026", partyA:"CyberSkill Co., Ltd"};
71
71
  const vi = {
72
72
  eyebrow:"Văn bản thay đổi · theo SOW-2026-014", h1:"Bổ sung bộ thử nghiệm A/B vào phạm vi thanh toán",
73
- altTitle:"Change note · scope amendment",
73
+ altTitle:"Văn bản thay đổi phạm vi",
74
74
  intro:"Theo Hợp đồng khung (MSA), mọi thay đổi được lập bằng văn bản, có chữ ký hai bên. Văn bản này nêu thay đổi, lý do, và tác động chính xác đến phạm vi, phí và tiến độ — không điều nào khác trong SOW thay đổi.",
75
75
  changeH:"Nội dung thay đổi", changeP:"Bổ sung bộ A/B tùy chọn từ báo giá QT-2026-0088: khung thử nghiệm trên trang thanh toán mới cùng hai test đầu tiên (biến thể nội dung; banner ngưỡng phí vận chuyển).",
76
76
  whyH:"Vì sao lúc này", whyP:"Bản canary cho thấy tỷ lệ rớt có thể thu hồi ở bước vận chuyển. Thử nghiệm khi đội còn trong mã nguồn rẻ hơn một đợt hợp tác thứ hai về sau. Đánh đổi thành thật: thêm một tuần vào M3.",
@@ -65,7 +65,7 @@ class Component extends DCLogic {
65
65
  const [elAttr, vaAttr] = EL[this.props.element] || EL["Thổ · studio"];
66
66
  const vn = this.props.language === "Tiếng Việt";
67
67
  const en = {
68
- eyebrow:"Handover · SOW-2026-014", h1:"Checkout & ops console — run it yourself", altTitle:"Sổ tay vận hành & bàn giao",
68
+ eyebrow:"Handover · SOW-2026-014", h1:"Checkout & ops console — run it yourself", altTitle:"Operations runbook & handover",
69
69
  intro:"Everything your team needs to own the system: what it is, where it runs, how to deploy, what watches it, and who to call. Built to last means you don't need us — and we're one message away if you do.",
70
70
  ovH:"System overview", ovP1:"Next.js storefront checkout (behind flag ", ovP2:") → pricing service (cache TTL 300s) → payment provider. Ops console reads the orders API with support-role auth. Recovery emails run on a nightly job.",
71
71
  envH:"Environments", thEnv:"Env", thFrom:"Deploys from", envProd:"Production", envProdFrom:"main · tagged release", envStg:"Staging", envStgFrom:"main · every merge", envSb:"Support sandbox", envSbFrom:"weekly snapshot",
@@ -75,7 +75,7 @@ const vn = this.props.language === "Tiếng Việt";
75
75
  contactsL:"Contacts", contactsBody:"Your on-call rota (primary) · CyberSkill: minh@cyberskill.world · escalation: vu@cyberskill.world · we reply within one business day",
76
76
  handedBy:"Handed over — CyberSkill Co., Ltd", acceptedBy:"Accepted — [Client Ltd]", sigMeta:"Name / title / date"};
77
77
  const vi = {
78
- eyebrow:"Bàn giao · SOW-2026-014", h1:"Thanh toán & ops console — tự vận hành", altTitle:"Runbook & handover",
78
+ eyebrow:"Bàn giao · SOW-2026-014", h1:"Thanh toán & ops console — tự vận hành", altTitle:"Sổ tay vận hành & bàn giao",
79
79
  intro:"Tất cả những gì đội bạn cần để làm chủ hệ thống: nó là gì, chạy ở đâu, triển khai thế nào, ai giám sát, và gọi ai. Làm để bền lâu nghĩa là bạn không cần đến chúng tôi — và chúng tôi luôn cách một tin nhắn nếu cần.",
80
80
  ovH:"Tổng quan hệ thống", ovP1:"Trang thanh toán Next.js (sau cờ ", ovP2:") → dịch vụ định giá (cache TTL 300s) → nhà cung cấp thanh toán. Ops console đọc API đơn hàng với quyền support. Email khôi phục chạy theo tác vụ hằng đêm.",
81
81
  envH:"Môi trường", thEnv:"Môi trường", thFrom:"Triển khai từ", envProd:"Production", envProdFrom:"main · bản gắn thẻ", envStg:"Staging", envStgFrom:"main · mỗi lần merge", envSb:"Sandbox hỗ trợ", envSbFrom:"ảnh chụp hằng tuần",
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
2
+ <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -77,7 +77,7 @@
77
77
  <tr>
78
78
  <td class="px" bgcolor="#fbf4e9" style="background:#fbf4e9;padding:22px 32px;border-top:1px solid #e7d9c6;">
79
79
  <p class="muted" style="margin:0 0 6px;font-family:Arial,Helvetica,sans-serif;font-size:13px;color:#6e5a4c;">Hiện Thực Hoá Ý Chí · Turn Your Will Into Real</p>
80
- <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;">Unsubscribe / Huỷ đăng ký</a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;">Preferences / Tuỳ chọn</a></p>
80
+ <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;"><span lang="en">Unsubscribe</span> · <span lang="vi">Huỷ đăng ký</span></a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;"><span lang="en">Preferences</span> · <span lang="vi">Tuỳ chọn</span></a></p>
81
81
  </td>
82
82
  </tr>
83
83
  </table>
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
2
+ <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -22,7 +22,7 @@
22
22
  <span style="font-family:Arial,Helvetica,sans-serif;font-size:19px;font-weight:bold;color:#ffffff;">CyberSkill</span>
23
23
  </td></tr>
24
24
  <!-- English -->
25
- <tr><td class="px card" bgcolor="#ffffff" style="background:#ffffff;padding:32px 32px 4px;">
25
+ <tr><td class="px card" lang="en" bgcolor="#ffffff" style="background:#ffffff;padding:32px 32px 4px;">
26
26
  <p style="margin:0 0 8px;font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;letter-spacing:1px;text-transform:uppercase;color:#6E3B0E;">A gentle nudge</p>
27
27
  <h1 class="ink" style="margin:0 0 14px;font-family:Arial,Helvetica,sans-serif;font-size:25px;line-height:1.25;font-weight:bold;color:#45210E;">Invoice INV-2026-0142 is 7 days past due</h1>
28
28
  <p class="ink" style="margin:0 0 18px;font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.6;color:#3d2c1e;">These things slip, no drama. If it's already on its way, thank you — please ignore this. If something about the invoice needs a look, just reply.</p>
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
2
+ <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -77,7 +77,7 @@
77
77
  <tr>
78
78
  <td class="px" bgcolor="#fbf4e9" style="background:#fbf4e9;padding:22px 32px;border-top:1px solid #e7d9c6;">
79
79
  <p class="muted" style="margin:0 0 6px;font-family:Arial,Helvetica,sans-serif;font-size:13px;color:#6e5a4c;">Hiện Thực Hoá Ý Chí · Turn Your Will Into Real</p>
80
- <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;">Unsubscribe / Huỷ đăng ký</a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;">Preferences / Tuỳ chọn</a></p>
80
+ <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;"><span lang="en">Unsubscribe</span> · <span lang="vi">Huỷ đăng ký</span></a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;"><span lang="en">Preferences</span> · <span lang="vi">Tuỳ chọn</span></a></p>
81
81
  </td>
82
82
  </tr>
83
83
  </table>
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
2
+ <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -77,7 +77,7 @@
77
77
  <tr>
78
78
  <td class="px" bgcolor="#fbf4e9" style="background:#fbf4e9;padding:22px 32px;border-top:1px solid #e7d9c6;">
79
79
  <p class="muted" style="margin:0 0 6px;font-family:Arial,Helvetica,sans-serif;font-size:13px;color:#6e5a4c;">Hiện Thực Hoá Ý Chí · Turn Your Will Into Real</p>
80
- <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;">Unsubscribe / Huỷ đăng ký</a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;">Preferences / Tuỳ chọn</a></p>
80
+ <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;"><span lang="en">Unsubscribe</span> · <span lang="vi">Huỷ đăng ký</span></a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;"><span lang="en">Preferences</span> · <span lang="vi">Tuỳ chọn</span></a></p>
81
81
  </td>
82
82
  </tr>
83
83
  </table>
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
2
+ <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -54,7 +54,7 @@
54
54
  <!-- Footer -->
55
55
  <tr><td class="px raise" bgcolor="#fbf4e9" style="background:#fbf4e9;padding:22px 32px;border-top:1px solid #e7d9c6;">
56
56
  <p class="muted" style="margin:0 0 6px;font-family:Arial,Helvetica,sans-serif;font-size:13px;color:#6e5a4c;">Hiện Thực Hoá Ý Chí · Turn Your Will Into Real</p>
57
- <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;">Unsubscribe / Huỷ đăng ký</a></p>
57
+ <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;"><span lang="en">Unsubscribe</span> · <span lang="vi">Huỷ đăng ký</span></a></p>
58
58
  </td></tr>
59
59
  </table>
60
60
  </td></tr></table>
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
2
+ <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -77,7 +77,7 @@
77
77
  <tr>
78
78
  <td class="px" bgcolor="#fbf4e9" style="background:#fbf4e9;padding:22px 32px;border-top:1px solid #e7d9c6;">
79
79
  <p class="muted" style="margin:0 0 6px;font-family:Arial,Helvetica,sans-serif;font-size:13px;color:#6e5a4c;">Hiện Thực Hoá Ý Chí · Turn Your Will Into Real</p>
80
- <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;">Unsubscribe / Huỷ đăng ký</a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;">Preferences / Tuỳ chọn</a></p>
80
+ <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;"><span lang="en">Unsubscribe</span> · <span lang="vi">Huỷ đăng ký</span></a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;"><span lang="en">Preferences</span> · <span lang="vi">Tuỳ chọn</span></a></p>
81
81
  </td>
82
82
  </tr>
83
83
  </table>
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
2
+ <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -77,7 +77,7 @@
77
77
  <tr>
78
78
  <td class="px" bgcolor="#fbf4e9" style="background:#fbf4e9;padding:22px 32px;border-top:1px solid #e7d9c6;">
79
79
  <p class="muted" style="margin:0 0 6px;font-family:Arial,Helvetica,sans-serif;font-size:13px;color:#6e5a4c;">Hiện Thực Hoá Ý Chí · Turn Your Will Into Real</p>
80
- <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;">Unsubscribe / Huỷ đăng ký</a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;">Preferences / Tuỳ chọn</a></p>
80
+ <p class="muted" style="margin:0;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.5;color:#6e5a4c;">CyberSkill Co., Ltd · 12 Nguyễn Huệ, Quận 1, Sài Gòn, Việt Nam<br><a href="https://cyberskill.world/unsubscribe" style="color:#6E3B0E;"><span lang="en">Unsubscribe</span> · <span lang="vi">Huỷ đăng ký</span></a> · <a href="https://cyberskill.world/preferences" style="color:#6E3B0E;"><span lang="en">Preferences</span> · <span lang="vi">Tuỳ chọn</span></a></p>
81
81
  </td>
82
82
  </tr>
83
83
  </table>
@@ -24,7 +24,7 @@
24
24
  <div style="font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:0.12em;color:var(--cs-color-text-accent)">A gentle reminder</div>
25
25
  <h1 style="font-size:24px;font-weight:800;letter-spacing:-0.02em;line-height:1.2;margin:8px 0 14px">Invoice INV-2026-0142 is 7 days past due</h1>
26
26
  <p style="font-size:14.5px;line-height:1.6;margin:0 0 18px">Just a nudge — these things slip, no drama. If it's already on its way, thank you and please ignore this. If something about the invoice doesn't look right, reply and a real person will sort it within one business day.</p>
27
- <div style="border:1px solid var(--cs-color-border-default);border-radius:var(--cs-radius-md);padding:16px 20px;margin-bottom:20px;font-size:13.5px;line-height:1.8"><b>Amount due</b> <span style="font-family:var(--cs-font-family-mono);font-weight:800;color:var(--cs-color-text-accent)">₫1,423,400,000</span><br><b>Was due</b> 02 Aug 2026 · <b>Ref</b> INV-2026-0142<br><b>Pay to</b> Vietcombank HCMC · CyberSkill Co., Ltd · <span style="font-family:var(--cs-font-family-mono);font-size:12.5px">0071 0000 xxxxxx</span></div>
27
+ <div style="border:1px solid var(--cs-color-border-default);border-radius:var(--cs-radius-md);padding:16px 20px;margin-bottom:20px;font-size:13.5px;line-height:1.8"><b>Currency</b> VND <span style="color:var(--cs-color-text-muted)">(transaction — independent of Language)</span><br><b>Amount due</b> <span style="font-family:var(--cs-font-family-mono);font-weight:800;color:var(--cs-color-text-accent)">₫1,423,400,000</span><br><b>Was due</b> 02 Aug 2026 · <b>Ref</b> INV-2026-0142<br><b>Pay to</b> Vietcombank HCMC · CyberSkill Co., Ltd · <span style="font-family:var(--cs-font-family-mono);font-size:12.5px">0071 0000 xxxxxx</span></div>
28
28
  <a href="#" style="display:inline-block;background:var(--cs-accent-bright);color:var(--cs-accent-on);font-weight:700;font-size:14.5px;text-decoration:none;padding:13px 24px;border-radius:var(--cs-radius-full)">View the invoice →</a>
29
29
  <p style="font-size:12.5px;line-height:1.6;margin:18px 0 0;color:var(--cs-color-text-muted)">Per our MSA, undisputed amounts accrue 1%/month after the due date — we'd genuinely rather not. A quick transfer or a quick reply keeps everything warm.</p>
30
30
  </sc-if>
@@ -33,7 +33,7 @@
33
33
  <div style="font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:0.12em;color:var(--cs-color-text-accent)">Một lời nhắc nhẹ</div>
34
34
  <h1 style="font-size:24px;font-weight:800;letter-spacing:-0.02em;line-height:1.3;margin:8px 0 14px">Hóa đơn INV-2026-0142 đã quá hạn 7 ngày</h1>
35
35
  <p style="font-size:14.5px;line-height:1.65;margin:0 0 18px">Chỉ là một lời nhắc — việc này ai cũng có lúc quên, không sao cả. Nếu khoản thanh toán đã trên đường đi, cảm ơn bạn và hãy bỏ qua email này. Nếu hóa đơn có điểm nào chưa đúng, trả lời thư và một người thật sẽ xử lý trong vòng một ngày làm việc.</p>
36
- <div style="border:1px solid var(--cs-color-border-default);border-radius:var(--cs-radius-md);padding:16px 20px;margin-bottom:20px;font-size:13.5px;line-height:1.85"><b>Số tiền phải trả</b> <span style="font-family:var(--cs-font-family-mono);font-weight:800;color:var(--cs-color-text-accent)">₫1.423.400.000</span><br><b>Hạn</b> 02/08/2026 · <b>Nội dung</b> INV-2026-0142<br><b>Chuyển đến</b> Vietcombank TP.HCM · Công ty TNHH CyberSkill · <span style="font-family:var(--cs-font-family-mono);font-size:12.5px">0071 0000 xxxxxx</span></div>
36
+ <div style="border:1px solid var(--cs-color-border-default);border-radius:var(--cs-radius-md);padding:16px 20px;margin-bottom:20px;font-size:13.5px;line-height:1.85"><b>Tiền tệ</b> VND <span style="color:var(--cs-color-text-muted)">(giao dịch — độc lập với Language)</span><br><b>Số tiền phải trả</b> <span style="font-family:var(--cs-font-family-mono);font-weight:800;color:var(--cs-color-text-accent)">₫1.423.400.000</span><br><b>Hạn</b> 02/08/2026 · <b>Nội dung</b> INV-2026-0142<br><b>Chuyển đến</b> Vietcombank TP.HCM · Công ty TNHH CyberSkill · <span style="font-family:var(--cs-font-family-mono);font-size:12.5px">0071 0000 xxxxxx</span></div>
37
37
  <a href="#" style="display:inline-block;background:var(--cs-accent-bright);color:var(--cs-accent-on);font-weight:700;font-size:14.5px;text-decoration:none;padding:13px 24px;border-radius:var(--cs-radius-full)">Xem hóa đơn →</a>
38
38
  <p style="font-size:12.5px;line-height:1.65;margin:18px 0 0;color:var(--cs-color-text-muted)">Theo Hợp đồng khung, khoản không tranh chấp chịu lãi 1%/tháng sau ngày đến hạn — chúng tôi thật lòng không muốn vậy. Một lệnh chuyển nhanh, hoặc một hồi âm nhanh, giữ mọi thứ ấm áp.</p>
39
39
  </div></sc-if>
@@ -32,7 +32,7 @@
32
32
  <tr style="border-bottom:1px solid var(--cs-color-border-default)"><td style="padding:9px 10px;font-family:var(--cs-font-family-mono);font-size:11.5px">15/07</td><td style="padding:9px 10px;font-weight:600">Client lunch (4 people)</td><td style="padding:9px 10px;color:var(--cs-color-text-muted)">Meals</td><td style="padding:9px 10px;text-align:right;font-family:var(--cs-font-family-mono)">980,000</td></tr>
33
33
  </tbody>
34
34
  </table>
35
- <div class="cs-avoid" style="display:flex;justify-content:flex-end;margin-bottom:22px"><div style="display:flex;justify-content:space-between;align-items:center;width:300px;padding:12px 14px;background:var(--cs-accent-strong);color:var(--cs-accent-on-strong);border-radius:var(--cs-radius-md)"><span style="font-weight:700;font-size:13px">Total claimed</span><span style="font-family:var(--cs-font-family-mono);font-weight:800;font-size:15px;color:var(--cs-accent-on-strong)">₫6,030,000</span></div></div>
35
+ <div class="cs-avoid" style="display:flex;justify-content:flex-end;margin-bottom:22px"><div style="display:flex;justify-content:space-between;align-items:center;width:300px;padding:12px 14px;background:var(--cs-accent-strong);color:var(--cs-accent-on-strong);border-radius:var(--cs-radius-md)"><span style="font-weight:700;font-size:13px">Total claimed <span style="font-weight:600;font-size:11px">(VND · transaction currency)</span></span><span style="font-family:var(--cs-font-family-mono);font-weight:800;font-size:15px;color:var(--cs-accent-on-strong)">₫6,030,000</span></div></div>
36
36
  <div class="cs-avoid" style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:22px">
37
37
  <div style="background:var(--cs-accent-tint);border-radius:10px;padding:13px 16px;font-size:12.5px;line-height:1.6"><b>Receipts.</b> All three attached (photos in the drive folder linked from the Hub). No receipt, no reimbursement — fair for everyone.</div>
38
38
  <div style="border:1px solid var(--cs-color-border-default);border-radius:10px;padding:13px 16px;font-size:12.5px;line-height:1.6;color:var(--cs-color-text-muted)"><b style="color:var(--cs-color-text-primary)">Policy notes.</b> Within per-diem caps · client meal pre-approved by lead · paid to salary account with next payroll.</div>
@@ -53,7 +53,7 @@
53
53
  <tr style="border-bottom:1px solid var(--cs-color-border-default)"><td style="padding:9px 10px;font-family:var(--cs-font-family-mono);font-size:11.5px">15/07</td><td style="padding:9px 10px;font-weight:600">Ăn trưa với khách (4 người)</td><td style="padding:9px 10px;color:var(--cs-color-text-muted)">Ăn uống</td><td style="padding:9px 10px;text-align:right;font-family:var(--cs-font-family-mono)">980.000</td></tr>
54
54
  </tbody>
55
55
  </table>
56
- <div class="cs-avoid" style="display:flex;justify-content:flex-end;margin-bottom:22px"><div style="display:flex;justify-content:space-between;align-items:center;width:300px;padding:12px 14px;background:var(--cs-accent-strong);color:var(--cs-accent-on-strong);border-radius:var(--cs-radius-md)"><span style="font-weight:700;font-size:13px">Tổng đề nghị</span><span style="font-family:var(--cs-font-family-mono);font-weight:800;font-size:15px;color:var(--cs-accent-on-strong)">₫6.030.000</span></div></div>
56
+ <div class="cs-avoid" style="display:flex;justify-content:flex-end;margin-bottom:22px"><div style="display:flex;justify-content:space-between;align-items:center;width:300px;padding:12px 14px;background:var(--cs-accent-strong);color:var(--cs-accent-on-strong);border-radius:var(--cs-radius-md)"><span style="font-weight:700;font-size:13px">Tổng đề nghị <span style="font-weight:600;font-size:11px">(VND · tiền tệ giao dịch)</span></span><span style="font-family:var(--cs-font-family-mono);font-weight:800;font-size:15px;color:var(--cs-accent-on-strong)">₫6.030.000</span></div></div>
57
57
  <div class="cs-avoid" style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:22px">
58
58
  <div style="background:var(--cs-accent-tint);border-radius:10px;padding:13px 16px;font-size:12.5px;line-height:1.65"><b>Hóa đơn.</b> Đủ ba chứng từ (ảnh trong thư mục drive, liên kết từ Hub). Không chứng từ, không hoàn — công bằng cho tất cả.</div>
59
59
  <div style="border:1px solid var(--cs-color-border-default);border-radius:10px;padding:13px 16px;font-size:12.5px;line-height:1.65;color:var(--cs-color-text-muted)"><b style="color:var(--cs-color-text-primary)">Ghi chú chính sách.</b> Trong hạn mức công tác phí · bữa với khách đã được lead duyệt trước · hoàn vào tài khoản lương kỳ gần nhất.</div>
@@ -27,7 +27,7 @@
27
27
  <div class="cs-avoid" style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px;margin-bottom:30px">
28
28
  <div><div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--cs-color-text-muted);margin-bottom:6px">From</div><div style="font-size:13px;line-height:1.6"><b>CyberSkill Co., Ltd</b><br>District 1, Ho Chi Minh City<br>Tax ID 0312xxxxxx</div></div>
29
29
  <div><div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--cs-color-text-muted);margin-bottom:6px">Bill to</div><div style="font-size:13px;line-height:1.6"><b>[Client Ltd]</b><br>[Address line]<br>Tax ID [number]</div></div>
30
- <div><div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--cs-color-text-muted);margin-bottom:6px">Details</div><div style="font-size:13px;line-height:1.7"><span style="color:var(--cs-color-text-muted)">Issued</span> 18 Jul 2026<br><span style="color:var(--cs-color-text-muted)">Due</span> <b>02 Aug 2026</b><br><span style="color:var(--cs-color-text-muted)">Terms</span> Net 15</div></div>
30
+ <div><div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--cs-color-text-muted);margin-bottom:6px">Details</div><div style="font-size:13px;line-height:1.7"><span style="color:var(--cs-color-text-muted)">Issued</span> 18 Jul 2026<br><span style="color:var(--cs-color-text-muted)">Due</span> <b>02 Aug 2026</b><br><span style="color:var(--cs-color-text-muted)">Terms</span> Net 15<br><span style="color:var(--cs-color-text-muted)">Currency</span> <b>VND</b> <span style="color:var(--cs-color-text-muted)">(transaction — independent of Language)</span></div></div>
31
31
  </div>
32
32
  <table style="width:100%;border-collapse:collapse;font-size:13px;margin-bottom:8px">
33
33
  <thead><tr style="border-bottom:2px solid var(--cs-color-brand-umber)"><th style="text-align:left;padding:9px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted)">Description</th><th style="text-align:right;padding:9px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted)">Qty</th><th style="text-align:right;padding:9px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted)">Rate</th><th style="text-align:right;padding:9px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted)">Amount</th></tr></thead>
@@ -54,7 +54,7 @@
54
54
  <div class="cs-avoid" style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px;margin-bottom:30px">
55
55
  <div><div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--cs-color-text-muted);margin-bottom:6px">Đơn vị bán</div><div style="font-size:13px;line-height:1.6"><b>Công ty TNHH CyberSkill</b><br>Quận 1, TP. Hồ Chí Minh<br>MST 0312xxxxxx</div></div>
56
56
  <div><div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--cs-color-text-muted);margin-bottom:6px">Gửi đến</div><div style="font-size:13px;line-height:1.6"><b>[Công ty khách hàng]</b><br>[Địa chỉ]<br>MST [số]</div></div>
57
- <div><div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--cs-color-text-muted);margin-bottom:6px">Chi tiết</div><div style="font-size:13px;line-height:1.7"><span style="color:var(--cs-color-text-muted)">Ngày lập</span> 18/07/2026<br><span style="color:var(--cs-color-text-muted)">Hạn thanh toán</span> <b>02/08/2026</b><br><span style="color:var(--cs-color-text-muted)">Điều khoản</span> Net 15</div></div>
57
+ <div><div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--cs-color-text-muted);margin-bottom:6px">Chi tiết</div><div style="font-size:13px;line-height:1.7"><span style="color:var(--cs-color-text-muted)">Ngày lập</span> 18/07/2026<br><span style="color:var(--cs-color-text-muted)">Hạn thanh toán</span> <b>02/08/2026</b><br><span style="color:var(--cs-color-text-muted)">Điều khoản</span> Net 15<br><span style="color:var(--cs-color-text-muted)">Tiền tệ</span> <b>VND</b> <span style="color:var(--cs-color-text-muted)">(giao dịch — độc lập với Language)</span></div></div>
58
58
  </div>
59
59
  <table style="width:100%;border-collapse:collapse;font-size:13px;margin-bottom:8px">
60
60
  <thead><tr style="border-bottom:2px solid var(--cs-color-brand-umber)"><th style="text-align:left;padding:9px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted)">Hạng mục</th><th style="text-align:right;padding:9px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted)">SL</th><th style="text-align:right;padding:9px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted)">Đơn giá</th><th style="text-align:right;padding:9px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted)">Thành tiền</th></tr></thead>
@@ -37,11 +37,11 @@
37
37
  </tbody>
38
38
  </table>
39
39
  <div class="cs-avoid" style="display:flex;justify-content:space-between;align-items:center;gap:24px;margin:22px 0 26px">
40
- <div style="font-size:12.5px;color:var(--cs-color-text-muted);line-height:1.6;max-width:360px">Prices exclude 10% VAT. Fixed scope; changes handled by a signed change note. This quote is valid for <b style="color:var(--cs-color-text-primary)">30 days</b>.</div>
40
+ <div style="font-size:12.5px;color:var(--cs-color-text-muted);line-height:1.6;max-width:360px">Prices exclude 10% VAT. Fixed scope; changes handled by a signed change note. This quote is valid for <b style="color:var(--cs-color-text-primary)">30 days</b>. <span style="color:var(--cs-color-text-muted)">Currency</span> <b>VND</b> <span style="color:var(--cs-color-text-muted)">(transaction — independent of Language)</span>.</div>
41
41
  <div style="text-align:right"><div style="font-size:11px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted);font-weight:700">Total (core scope)</div><div style="font-family:var(--cs-font-family-mono);font-weight:800;font-size:26px;color:var(--cs-color-brand-umber);margin-top:2px">₫3,100,000,000</div></div>
42
42
  </div>
43
43
  <div class="cs-avoid" style="display:flex;align-items:center;gap:20px;background:var(--cs-accent-strong);border-radius:12px;padding:20px 26px">
44
- <div style="flex:1"><div style="font-size:11px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-accent-bright);font-weight:700;margin-bottom:3px">Ready when you are</div><div style="color:var(--cs-accent-on-strong);font-size:14px;line-height:1.55">Say yes and we&rsquo;ll send the SOW and a start date within one business day.</div></div>
44
+ <div style="flex:1"><div style="font-size:11px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-accent-on-strong);font-weight:700;margin-bottom:3px">Ready when you are</div><div style="color:var(--cs-accent-on-strong);font-size:14px;line-height:1.55">Say yes and we&rsquo;ll send the SOW and a start date within one business day.</div></div>
45
45
  <span style="display:inline-block;background:var(--cs-accent-bright);color:var(--cs-accent-on);font-weight:700;font-size:14px;padding:12px 22px;border-radius:var(--cs-radius-full);white-space:nowrap">Accept this quote →</span>
46
46
  </div>
47
47
  <div style="font-size:12px;color:var(--cs-color-text-muted);margin-top:20px">Prepared by Minh Trần · CyberSkill · Valid until <b style="color:var(--cs-color-text-primary)">17 Aug 2026</b></div>
@@ -61,11 +61,11 @@
61
61
  </tbody>
62
62
  </table>
63
63
  <div class="cs-avoid" style="display:flex;justify-content:space-between;align-items:center;gap:24px;margin:22px 0 26px">
64
- <div style="font-size:12.5px;color:var(--cs-color-text-muted);line-height:1.65;max-width:360px">Giá chưa gồm 10% thuế GTGT. Phạm vi cố định; thay đổi qua văn bản điều chỉnh có chữ ký. Báo giá có hiệu lực <b style="color:var(--cs-color-text-primary)">30 ngày</b>.</div>
64
+ <div style="font-size:12.5px;color:var(--cs-color-text-muted);line-height:1.65;max-width:360px">Giá chưa gồm 10% thuế GTGT. Phạm vi cố định; thay đổi qua văn bản điều chỉnh có chữ ký. Báo giá có hiệu lực <b style="color:var(--cs-color-text-primary)">30 ngày. <span style="color:var(--cs-color-text-muted)">Tiền tệ</span> <b>VND</b> <span style="color:var(--cs-color-text-muted)">(giao dịch — độc lập với Language)</span></b>.</div>
65
65
  <div style="text-align:right"><div style="font-size:11px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-color-text-muted);font-weight:700">Tổng (phạm vi chính)</div><div style="font-family:var(--cs-font-family-mono);font-weight:800;font-size:26px;color:var(--cs-color-brand-umber);margin-top:2px">₫3.100.000.000</div></div>
66
66
  </div>
67
67
  <div class="cs-avoid" style="display:flex;align-items:center;gap:20px;background:var(--cs-accent-strong);border-radius:12px;padding:20px 26px">
68
- <div style="flex:1"><div style="font-size:11px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-accent-bright);font-weight:700;margin-bottom:3px">Sẵn sàng khi bạn sẵn sàng</div><div style="color:var(--cs-accent-on-strong);font-size:14px;line-height:1.6">Đồng ý, và chúng tôi sẽ gửi SOW cùng ngày bắt đầu trong vòng một ngày làm việc.</div></div>
68
+ <div style="flex:1"><div style="font-size:11px;text-transform:uppercase;letter-spacing:0.08em;color:var(--cs-accent-on-strong);font-weight:700;margin-bottom:3px">Sẵn sàng khi bạn sẵn sàng</div><div style="color:var(--cs-accent-on-strong);font-size:14px;line-height:1.6">Đồng ý, và chúng tôi sẽ gửi SOW cùng ngày bắt đầu trong vòng một ngày làm việc.</div></div>
69
69
  <span style="display:inline-block;background:var(--cs-accent-bright);color:var(--cs-accent-on);font-weight:700;font-size:14px;padding:12px 22px;border-radius:var(--cs-radius-full);white-space:nowrap">Chấp nhận báo giá →</span>
70
70
  </div>
71
71
  <div style="font-size:12px;color:var(--cs-color-text-muted);margin-top:20px">Soạn bởi Minh Trần · CyberSkill · Hiệu lực đến <b style="color:var(--cs-color-text-primary)">17/08/2026</b></div>
@@ -95,7 +95,7 @@ class Component extends DCLogic {
95
95
  const EL = {"Thổ · studio":["tho",""],"Thổ · clay":["tho","clay"],"Thổ · sand":["tho","sand"],"Hỏa · ember":["hoa",""],"Hỏa · lava":["hoa","lava"],"Hỏa · plasma":["hoa","plasma"],"Thủy · river":["thuy",""],"Thủy · ocean":["thuy","ocean"],"Thủy · mist":["thuy","mist"],"Mộc · leaf":["moc",""],"Mộc · bamboo":["moc","bamboo"],"Mộc · forest":["moc","forest"],"Kim · champagne":["kim",""],"Kim · steel":["kim","steel"],"Kim · titanium":["kim","titanium"]};
96
96
  const [elAttr, vaAttr] = EL[this.props.element] || EL["Thổ · studio"];
97
97
  const lang = this.props.language ?? "English";
98
- return { langAttr: (this.props.language ?? "English") === "Tiếng Việt" ? "vi" : "en", elAttr, vaAttr, isEN: lang !== "Tiếng Việt", isVN: lang === "Tiếng Việt", hdrLabel: lang === "Tiếng Việt" ? "Bộ phỏng vấn · Mật" : "Interview kit · Confidential" };
98
+ return { langAttr: (this.props.language ?? "English") === "Tiếng Việt" ? "vi" : "en", elAttr, vaAttr, isEN: lang !== "Tiếng Việt", isVN: lang === "Tiếng Việt", hdrLabel: lang === "Tiếng Việt" ? "Bộ phỏng vấn · Mật" : "Confidential · HR" };
99
99
  }
100
100
  }
101
101
  </script>
@@ -69,7 +69,7 @@ class Component extends DCLogic {
69
69
  quote:"\u201cWe described the outcome in two sentences. Twelve weeks later it was live — and it still runs itself.\u201d", quoteWho:"Product lead, Retailer A",
70
70
  ctaKicker:"Have a wish like this?", ctaBody:"Tell us the outcome in a sentence. We reply within one business day.", ctaBtn:"Make a wish →"};
71
71
  const vi = {
72
- kicker:"Case study", stat1:"Đơn hoàn tất", stat2:"Thời gian thanh toán", stat3v:"12 tuần", stat3:"Từ điều ước đến ra mắt",
72
+ kicker:"Nghiên cứu tình huống", stat1:"Đơn hoàn tất", stat2:"Thời gian thanh toán", stat3v:"12 tuần", stat3:"Từ điều ước đến ra mắt",
73
73
  h1:"Điều ước", p1:"Cứ ba người mua thì một bỏ giỏ ở bước thanh toán, và bộ phận hỗ trợ không thấy vì sao. Yêu cầu, gói trong một câu: một trang thanh toán cứ thế chạy — và một console để vận hành mỗi ngày.",
74
74
  h2:"Cách chúng tôi định hình", p2:"Một cặp senior dựng lại thanh toán sau một feature flag và kiểm chứng trên 10% lưu lượng trước khi cắt chuyển. Ops console ra song song, nên hỗ trợ thấy được đơn hàng từ tuần thứ ba. Đánh đổi thành thật, nói trước: giữ nguyên nhà cung cấp thanh toán và dồn ngân sách vào nơi phễu rò rỉ.",
75
75
  h3:"Điều còn lại", p3:"Email khôi phục nay kéo về một phần năm số giỏ bị bỏ. Console xử lý hoàn tiền mà không cần đến kỹ thuật. Tài liệu, runbook và analytics được bàn giao gọn gàng — làm để chạy được, làm để bền lâu.",
@@ -14,7 +14,7 @@
14
14
  <script src="../../image-slot.js"></script>
15
15
  </helmet>
16
16
  <div data-theme="{{ rootTheme }}" lang="{{ langAttr }}" data-cs-element="{{ elAttr }}" data-cs-variant="{{ vaAttr }}" style="font-family:var(--cs-font-family-ui);color:var(--cs-color-text-primary);background:var(--cs-color-surface-page);min-height:100vh">
17
- <a class="cs-skip" href="#main" style="position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden">Skip to content</a>
17
+ <a class="cs-skip" href="#main" style="position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden">{{ skipLabel }}</a>
18
18
  <main id="main">
19
19
  <header style="position:sticky;top:0;z-index:50;display:flex;align-items:center;flex-wrap:wrap;gap:10px 24px;padding:14px 32px;background:color-mix(in oklab,var(--cs-color-surface-panel) 82%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid var(--cs-color-border-default)">
20
20
  <div style="display:flex;align-items:center;gap:10px;font-weight:800;font-size:18px;color:var(--cs-color-text-primary);letter-spacing:-0.01em">
@@ -124,8 +124,8 @@ class Component extends DCLogic {
124
124
  const EL = {"Thổ · studio":["tho",""],"Thổ · clay":["tho","clay"],"Thổ · sand":["tho","sand"],"Hỏa · ember":["hoa",""],"Hỏa · lava":["hoa","lava"],"Hỏa · plasma":["hoa","plasma"],"Thủy · river":["thuy",""],"Thủy · ocean":["thuy","ocean"],"Thủy · mist":["thuy","mist"],"Mộc · leaf":["moc",""],"Mộc · bamboo":["moc","bamboo"],"Mộc · forest":["moc","forest"],"Kim · champagne":["kim",""],"Kim · steel":["kim","steel"],"Kim · titanium":["kim","titanium"]};
125
125
  const [elAttr, vaAttr] = EL[this.props.element] || EL["Thổ · studio"];
126
126
  const vn = this.props.language === "Tiếng Việt";
127
- const en = { navServices:"Services", navProcess:"Process", navContact:"Contact", talkBtn:"Talk to Lumi", heroKicker:"A Saigon studio · since 2020", heroH:"Turn Your Will Into Real", heroSub:"Hiện Thực Hoá Ý Chí", heroP:"Tell us a wish in a sentence. Lumi shares plain advice, then hands it to a real team who build software your people actually run — built to ship, built to last.", promptPh:"Make a wish… a faster checkout, an app, a tool", promptSend:"Make a wish", svcKicker:"Services", svcH:"What we build", svcP:"Three focused practices. One team that answers for the result.", c1h:"Web & mobile apps", c1p:"Product apps your customers reach for — fast, accessible, bilingual by default.", c2h:"Internal systems & automation", c2p:"The tools your team runs on: dashboards, workflows, and the automation behind them.", c3h:"Built to last", c3p:"Shipped software that keeps running — tested, documented, handed over cleanly.", ctaH:"Ready to make a wish?", ctaP:"Send a short note. We reply within one business day.", chatHello:"Hello, I’m Lumi. Tell me a wish, and I’ll share plain advice before asking for anything.", chatPh:"Type your wish…", chatSend:"Send", footer:"© 2026 CyberSkill · Saigon · Turn Your Will Into Real", genieLabel:"golden genie" };
128
- const vi = { navServices:"Dịch vụ", navProcess:"Quy trình", navContact:"Liên hệ", talkBtn:"Trò chuyện với Lumi", heroKicker:"Studio Sài Gòn · từ 2020", heroH:"Hiện Thực Hoá Ý Chí", heroSub:"Turn Your Will Into Real", heroP:"Kể cho chúng tôi một điều ước trong một câu. Lumi chia sẻ lời khuyên thẳng thắn, rồi trao cho một đội ngũ thật xây phần mềm mà người của bạn thực sự vận hành — làm để chạy được, làm để bền lâu.", promptPh:"Gửi điều ước… thanh toán nhanh hơn, một app, một công cụ", promptSend:"Gửi điều ước", svcKicker:"Dịch vụ", svcH:"Chúng tôi xây gì", svcP:"Ba mảng tập trung. Một đội ngũ chịu trách nhiệm về kết quả.", c1h:"Ứng dụng web & di động", c1p:"Sản phẩm khách hàng muốn dùng — nhanh, dễ tiếp cận, song ngữ mặc định.", c2h:"Hệ thống nội bộ & tự động hoá", c2p:"Công cụ đội bạn vận hành: dashboard, luồng công việc, và tự động hoá phía sau.", c3h:"Làm để bền lâu", c3p:"Phần mềm đã ra mắt vẫn chạy đều — kiểm thử, tài liệu, bàn giao gọn gàng.", ctaH:"Sẵn sàng gửi điều ước?", ctaP:"Gửi một ghi chú ngắn. Chúng tôi phản hồi trong một ngày làm việc.", chatHello:"Xin chào, tôi là Lumi. Kể cho tôi một điều ước, tôi sẽ chia sẻ lời khuyên thẳng thắn trước khi hỏi bất cứ điều gì.", chatPh:"Nhập điều ước của bạn…", chatSend:"Gửi", footer:"© 2026 CyberSkill · Sài Gòn · Hiện Thực Hoá Ý Chí", genieLabel:"thần đèn vàng" };
127
+ const en = { skipLabel:"Skip to content", navServices:"Services", navProcess:"Process", navContact:"Contact", talkBtn:"Talk to Lumi", heroKicker:"A Saigon studio · since 2020", heroH:"Turn Your Will Into Real", heroSub:"Hiện Thực Hoá Ý Chí", heroP:"Tell us a wish in a sentence. Lumi shares plain advice, then hands it to a real team who build software your people actually run — built to ship, built to last.", promptPh:"Make a wish… a faster checkout, an app, a tool", promptSend:"Make a wish", svcKicker:"Services", svcH:"What we build", svcP:"Three focused practices. One team that answers for the result.", c1h:"Web & mobile apps", c1p:"Product apps your customers reach for — fast, accessible, bilingual by default.", c2h:"Internal systems & automation", c2p:"The tools your team runs on: dashboards, workflows, and the automation behind them.", c3h:"Built to last", c3p:"Shipped software that keeps running — tested, documented, handed over cleanly.", ctaH:"Ready to make a wish?", ctaP:"Send a short note. We reply within one business day.", chatHello:"Hello, I’m Lumi. Tell me a wish, and I’ll share plain advice before asking for anything.", chatPh:"Type your wish…", chatSend:"Send", footer:"© 2026 CyberSkill · Saigon · Turn Your Will Into Real", genieLabel:"golden genie" };
128
+ const vi = { skipLabel:"Bỏ qua nội dung", navServices:"Dịch vụ", navProcess:"Quy trình", navContact:"Liên hệ", talkBtn:"Trò chuyện với Lumi", heroKicker:"Studio Sài Gòn · từ 2020", heroH:"Hiện Thực Hoá Ý Chí", heroSub:"Turn Your Will Into Real", heroP:"Kể cho chúng tôi một điều ước trong một câu. Lumi chia sẻ lời khuyên thẳng thắn, rồi trao cho một đội ngũ thật xây phần mềm mà người của bạn thực sự vận hành — làm để chạy được, làm để bền lâu.", promptPh:"Gửi điều ước… thanh toán nhanh hơn, một app, một công cụ", promptSend:"Gửi điều ước", svcKicker:"Dịch vụ", svcH:"Chúng tôi xây gì", svcP:"Ba mảng tập trung. Một đội ngũ chịu trách nhiệm về kết quả.", c1h:"Ứng dụng web & di động", c1p:"Sản phẩm khách hàng muốn dùng — nhanh, dễ tiếp cận, song ngữ mặc định.", c2h:"Hệ thống nội bộ & tự động hoá", c2p:"Công cụ đội bạn vận hành: dashboard, luồng công việc, và tự động hoá phía sau.", c3h:"Làm để bền lâu", c3p:"Phần mềm đã ra mắt vẫn chạy đều — kiểm thử, tài liệu, bàn giao gọn gàng.", ctaH:"Sẵn sàng gửi điều ước?", ctaP:"Gửi một ghi chú ngắn. Chúng tôi phản hồi trong một ngày làm việc.", chatHello:"Xin chào, tôi là Lumi. Kể cho tôi một điều ước, tôi sẽ chia sẻ lời khuyên thẳng thắn trước khi hỏi bất cứ điều gì.", chatPh:"Nhập điều ước của bạn…", chatSend:"Gửi", footer:"© 2026 CyberSkill · Sài Gòn · Hiện Thực Hoá Ý Chí", genieLabel:"thần đèn vàng" };
129
129
  return Object.assign({ langAttr: (this.props.language ?? "English") === "Tiếng Việt" ? "vi" : "en", elAttr, vaAttr, rootTheme: this.props.theme === "dark" ? "dark" : "",
130
130
  /* FAB omitted — header Talk to Lumi is the single secondary CTA (UX-016). */
131
131
  showLauncher: false, chatOpen: this.state.chatOpen,