@better-forge/ui 0.0.0-stage → 0.1.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 (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -3
  3. package/dist/api/client.d.ts +42 -0
  4. package/dist/api/client.d.ts.map +1 -0
  5. package/dist/api/client.js +130 -0
  6. package/dist/api/client.js.map +1 -0
  7. package/dist/components/ConfirmIdentityModal.d.ts +18 -0
  8. package/dist/components/ConfirmIdentityModal.d.ts.map +1 -0
  9. package/dist/components/ConfirmIdentityModal.js +30 -0
  10. package/dist/components/ConfirmIdentityModal.js.map +1 -0
  11. package/dist/components/ConfirmModal.d.ts +18 -0
  12. package/dist/components/ConfirmModal.d.ts.map +1 -0
  13. package/dist/components/ConfirmModal.js +11 -0
  14. package/dist/components/ConfirmModal.js.map +1 -0
  15. package/dist/components/CopyButton.d.ts +11 -0
  16. package/dist/components/CopyButton.d.ts.map +1 -0
  17. package/dist/components/CopyButton.js +44 -0
  18. package/dist/components/CopyButton.js.map +1 -0
  19. package/dist/components/CredentialSection.d.ts +38 -0
  20. package/dist/components/CredentialSection.d.ts.map +1 -0
  21. package/dist/components/CredentialSection.js +69 -0
  22. package/dist/components/CredentialSection.js.map +1 -0
  23. package/dist/components/ErrorBoundary.d.ts +18 -0
  24. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  25. package/dist/components/ErrorBoundary.js +25 -0
  26. package/dist/components/ErrorBoundary.js.map +1 -0
  27. package/dist/components/ModalShell.d.ts +58 -0
  28. package/dist/components/ModalShell.d.ts.map +1 -0
  29. package/dist/components/ModalShell.js +92 -0
  30. package/dist/components/ModalShell.js.map +1 -0
  31. package/dist/components/ResetTwoFactorModal.d.ts +14 -0
  32. package/dist/components/ResetTwoFactorModal.d.ts.map +1 -0
  33. package/dist/components/ResetTwoFactorModal.js +16 -0
  34. package/dist/components/ResetTwoFactorModal.js.map +1 -0
  35. package/dist/components/SidePanel.d.ts +35 -0
  36. package/dist/components/SidePanel.d.ts.map +1 -0
  37. package/dist/components/SidePanel.js +19 -0
  38. package/dist/components/SidePanel.js.map +1 -0
  39. package/dist/components/SingleSignOnModal.d.ts +4 -0
  40. package/dist/components/SingleSignOnModal.d.ts.map +1 -0
  41. package/dist/components/SingleSignOnModal.js +64 -0
  42. package/dist/components/SingleSignOnModal.js.map +1 -0
  43. package/dist/components/SsoConfirmation.d.ts +22 -0
  44. package/dist/components/SsoConfirmation.d.ts.map +1 -0
  45. package/dist/components/SsoConfirmation.js +87 -0
  46. package/dist/components/SsoConfirmation.js.map +1 -0
  47. package/dist/components/VaultTypePicker.d.ts +13 -0
  48. package/dist/components/VaultTypePicker.d.ts.map +1 -0
  49. package/dist/components/VaultTypePicker.js +62 -0
  50. package/dist/components/VaultTypePicker.js.map +1 -0
  51. package/dist/components/WhatsNew.d.ts +18 -0
  52. package/dist/components/WhatsNew.d.ts.map +1 -0
  53. package/dist/components/WhatsNew.js +50 -0
  54. package/dist/components/WhatsNew.js.map +1 -0
  55. package/dist/components/formParts.d.ts +40 -0
  56. package/dist/components/formParts.d.ts.map +1 -0
  57. package/dist/components/formParts.js +31 -0
  58. package/dist/components/formParts.js.map +1 -0
  59. package/dist/components/ui/Alert.d.ts +15 -0
  60. package/dist/components/ui/Alert.d.ts.map +1 -0
  61. package/dist/components/ui/Alert.js +14 -0
  62. package/dist/components/ui/Alert.js.map +1 -0
  63. package/dist/components/ui/DataTable.d.ts +52 -0
  64. package/dist/components/ui/DataTable.d.ts.map +1 -0
  65. package/dist/components/ui/DataTable.js +112 -0
  66. package/dist/components/ui/DataTable.js.map +1 -0
  67. package/dist/components/ui/Field.d.ts +27 -0
  68. package/dist/components/ui/Field.d.ts.map +1 -0
  69. package/dist/components/ui/Field.js +25 -0
  70. package/dist/components/ui/Field.js.map +1 -0
  71. package/dist/components/ui/PageHeader.d.ts +18 -0
  72. package/dist/components/ui/PageHeader.d.ts.map +1 -0
  73. package/dist/components/ui/PageHeader.js +10 -0
  74. package/dist/components/ui/PageHeader.js.map +1 -0
  75. package/dist/components/ui/Pagination.d.ts +21 -0
  76. package/dist/components/ui/Pagination.d.ts.map +1 -0
  77. package/dist/components/ui/Pagination.js +10 -0
  78. package/dist/components/ui/Pagination.js.map +1 -0
  79. package/dist/components/ui/QuickStartPanel.d.ts +21 -0
  80. package/dist/components/ui/QuickStartPanel.d.ts.map +1 -0
  81. package/dist/components/ui/QuickStartPanel.js +11 -0
  82. package/dist/components/ui/QuickStartPanel.js.map +1 -0
  83. package/dist/components/ui/StateViews.d.ts +50 -0
  84. package/dist/components/ui/StateViews.d.ts.map +1 -0
  85. package/dist/components/ui/StateViews.js +33 -0
  86. package/dist/components/ui/StateViews.js.map +1 -0
  87. package/dist/components/ui/Switch.d.ts +16 -0
  88. package/dist/components/ui/Switch.d.ts.map +1 -0
  89. package/dist/components/ui/Switch.js +15 -0
  90. package/dist/components/ui/Switch.js.map +1 -0
  91. package/dist/components/ui/Toast.d.ts +20 -0
  92. package/dist/components/ui/Toast.d.ts.map +1 -0
  93. package/dist/components/ui/Toast.js +46 -0
  94. package/dist/components/ui/Toast.js.map +1 -0
  95. package/dist/components/ui/index.d.ts +10 -0
  96. package/dist/components/ui/index.d.ts.map +1 -0
  97. package/dist/components/ui/index.js +10 -0
  98. package/dist/components/ui/index.js.map +1 -0
  99. package/dist/config.d.ts +46 -0
  100. package/dist/config.d.ts.map +1 -0
  101. package/dist/config.js +12 -0
  102. package/dist/config.js.map +1 -0
  103. package/dist/hooks/useDarkMode.d.ts +2 -0
  104. package/dist/hooks/useDarkMode.d.ts.map +1 -0
  105. package/dist/hooks/useDarkMode.js +37 -0
  106. package/dist/hooks/useDarkMode.js.map +1 -0
  107. package/dist/hooks/useDebouncedValue.d.ts +6 -0
  108. package/dist/hooks/useDebouncedValue.d.ts.map +1 -0
  109. package/dist/hooks/useDebouncedValue.js +19 -0
  110. package/dist/hooks/useDebouncedValue.js.map +1 -0
  111. package/dist/index.d.ts +36 -0
  112. package/dist/index.d.ts.map +1 -0
  113. package/dist/index.js +36 -0
  114. package/dist/index.js.map +1 -0
  115. package/dist/lib/changelog.d.ts +32 -0
  116. package/dist/lib/changelog.d.ts.map +1 -0
  117. package/dist/lib/changelog.js +71 -0
  118. package/dist/lib/changelog.js.map +1 -0
  119. package/dist/lib/dateFormat.d.ts +24 -0
  120. package/dist/lib/dateFormat.d.ts.map +1 -0
  121. package/dist/lib/dateFormat.js +67 -0
  122. package/dist/lib/dateFormat.js.map +1 -0
  123. package/dist/navigation.d.ts +5 -0
  124. package/dist/navigation.d.ts.map +1 -0
  125. package/dist/navigation.js +7 -0
  126. package/dist/navigation.js.map +1 -0
  127. package/dist/pages/ApiTokens.d.ts +9 -0
  128. package/dist/pages/ApiTokens.d.ts.map +1 -0
  129. package/dist/pages/ApiTokens.js +116 -0
  130. package/dist/pages/ApiTokens.js.map +1 -0
  131. package/dist/pages/AuditLog.d.ts +14 -0
  132. package/dist/pages/AuditLog.d.ts.map +1 -0
  133. package/dist/pages/AuditLog.js +104 -0
  134. package/dist/pages/AuditLog.js.map +1 -0
  135. package/dist/pages/Backups.d.ts +2 -0
  136. package/dist/pages/Backups.d.ts.map +1 -0
  137. package/dist/pages/Backups.js +118 -0
  138. package/dist/pages/Backups.js.map +1 -0
  139. package/dist/pages/ChangePassword.d.ts +2 -0
  140. package/dist/pages/ChangePassword.d.ts.map +1 -0
  141. package/dist/pages/ChangePassword.js +40 -0
  142. package/dist/pages/ChangePassword.js.map +1 -0
  143. package/dist/pages/Login.d.ts +12 -0
  144. package/dist/pages/Login.d.ts.map +1 -0
  145. package/dist/pages/Login.js +69 -0
  146. package/dist/pages/Login.js.map +1 -0
  147. package/dist/pages/Settings.d.ts +2 -0
  148. package/dist/pages/Settings.d.ts.map +1 -0
  149. package/dist/pages/Settings.js +149 -0
  150. package/dist/pages/Settings.js.map +1 -0
  151. package/dist/pages/Setup.d.ts +2 -0
  152. package/dist/pages/Setup.d.ts.map +1 -0
  153. package/dist/pages/Setup.js +113 -0
  154. package/dist/pages/Setup.js.map +1 -0
  155. package/dist/pages/SsoConfirm.d.ts +3 -0
  156. package/dist/pages/SsoConfirm.d.ts.map +1 -0
  157. package/dist/pages/SsoConfirm.js +20 -0
  158. package/dist/pages/SsoConfirm.js.map +1 -0
  159. package/dist/pages/SsoTestResult.d.ts +2 -0
  160. package/dist/pages/SsoTestResult.d.ts.map +1 -0
  161. package/dist/pages/SsoTestResult.js +49 -0
  162. package/dist/pages/SsoTestResult.js.map +1 -0
  163. package/dist/pages/Users.d.ts +22 -0
  164. package/dist/pages/Users.d.ts.map +1 -0
  165. package/dist/pages/Users.js +124 -0
  166. package/dist/pages/Users.js.map +1 -0
  167. package/dist/pages/Vault.d.ts +2 -0
  168. package/dist/pages/Vault.d.ts.map +1 -0
  169. package/dist/pages/Vault.js +372 -0
  170. package/dist/pages/Vault.js.map +1 -0
  171. package/dist/shell/AdminShell.d.ts +46 -0
  172. package/dist/shell/AdminShell.d.ts.map +1 -0
  173. package/dist/shell/AdminShell.js +76 -0
  174. package/dist/shell/AdminShell.js.map +1 -0
  175. package/dist/shell/guards.d.ts +28 -0
  176. package/dist/shell/guards.d.ts.map +1 -0
  177. package/dist/shell/guards.js +71 -0
  178. package/dist/shell/guards.js.map +1 -0
  179. package/icons.json +170 -0
  180. package/package.json +71 -6
  181. package/src/api/client.ts +139 -0
  182. package/src/components/ConfirmIdentityModal.tsx +82 -0
  183. package/src/components/ConfirmModal.tsx +83 -0
  184. package/src/components/CopyButton.tsx +71 -0
  185. package/src/components/CredentialSection.tsx +270 -0
  186. package/src/components/ErrorBoundary.tsx +47 -0
  187. package/src/components/ModalShell.tsx +160 -0
  188. package/src/components/ResetTwoFactorModal.tsx +74 -0
  189. package/src/components/SidePanel.tsx +96 -0
  190. package/src/components/SingleSignOnModal.tsx +161 -0
  191. package/src/components/SsoConfirmation.tsx +96 -0
  192. package/src/components/VaultTypePicker.tsx +131 -0
  193. package/src/components/WhatsNew.tsx +84 -0
  194. package/src/components/formParts.tsx +59 -0
  195. package/src/components/ui/Alert.tsx +45 -0
  196. package/src/components/ui/DataTable.tsx +225 -0
  197. package/src/components/ui/Field.tsx +63 -0
  198. package/src/components/ui/PageHeader.tsx +36 -0
  199. package/src/components/ui/Pagination.tsx +37 -0
  200. package/src/components/ui/QuickStartPanel.tsx +57 -0
  201. package/src/components/ui/StateViews.tsx +135 -0
  202. package/src/components/ui/Switch.tsx +65 -0
  203. package/src/components/ui/Toast.tsx +104 -0
  204. package/src/components/ui/index.ts +9 -0
  205. package/src/config.ts +46 -0
  206. package/src/hooks/useDarkMode.ts +38 -0
  207. package/src/hooks/useDebouncedValue.ts +22 -0
  208. package/src/index.ts +42 -0
  209. package/src/lib/changelog.ts +93 -0
  210. package/src/lib/dateFormat.ts +90 -0
  211. package/src/navigation.ts +6 -0
  212. package/src/pages/ApiTokens.tsx +361 -0
  213. package/src/pages/AuditLog.tsx +388 -0
  214. package/src/pages/Backups.tsx +170 -0
  215. package/src/pages/ChangePassword.tsx +84 -0
  216. package/src/pages/Login.tsx +275 -0
  217. package/src/pages/Settings.tsx +264 -0
  218. package/src/pages/Setup.tsx +438 -0
  219. package/src/pages/SsoConfirm.tsx +26 -0
  220. package/src/pages/SsoTestResult.tsx +104 -0
  221. package/src/pages/Users.tsx +426 -0
  222. package/src/pages/Vault.tsx +1036 -0
  223. package/src/shell/AdminShell.tsx +256 -0
  224. package/src/shell/guards.tsx +88 -0
  225. package/styles/base.css +521 -0
  226. package/styles/fonts/inter-latin-1.woff2 +0 -0
  227. package/styles/fonts/inter-latin-ext.woff2 +0 -0
  228. package/styles/fonts/jetbrains-mono-latin-3.woff2 +0 -0
  229. package/styles/fonts/jetbrains-mono-latin-ext-2.woff2 +0 -0
  230. package/styles/fonts/manrope-latin-5.woff2 +0 -0
  231. package/styles/fonts/manrope-latin-ext-4.woff2 +0 -0
  232. package/styles/fonts/material-symbols-outlined-fill.woff2 +0 -0
  233. package/styles/icons.css +4 -0
  234. package/tailwind-preset.js +79 -0
@@ -0,0 +1,521 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ /* Fonts are bundled with the app (Manrope, Inter, JetBrains Mono: SIL OFL; Material Symbols: Apache 2.0),
6
+ so opening the interface makes no request to Google. */
7
+ @font-face { font-family: 'Manrope'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/manrope-latin-ext-4.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
8
+ @font-face { font-family: 'Manrope'; font-style: normal; font-weight: 600; font-display: swap; src: url('./fonts/manrope-latin-ext-4.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
9
+ @font-face { font-family: 'Manrope'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/manrope-latin-ext-4.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
10
+ @font-face { font-family: 'Manrope'; font-style: normal; font-weight: 800; font-display: swap; src: url('./fonts/manrope-latin-ext-4.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
11
+ @font-face { font-family: 'Manrope'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/manrope-latin-5.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
12
+ @font-face { font-family: 'Manrope'; font-style: normal; font-weight: 600; font-display: swap; src: url('./fonts/manrope-latin-5.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
13
+ @font-face { font-family: 'Manrope'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/manrope-latin-5.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
14
+ @font-face { font-family: 'Manrope'; font-style: normal; font-weight: 800; font-display: swap; src: url('./fonts/manrope-latin-5.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
15
+ @font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/inter-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
16
+ @font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('./fonts/inter-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
17
+ @font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('./fonts/inter-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
18
+ @font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/inter-latin-1.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
19
+ @font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('./fonts/inter-latin-1.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
20
+ @font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('./fonts/inter-latin-1.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
21
+ @font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/jetbrains-mono-latin-ext-2.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
22
+ @font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('./fonts/jetbrains-mono-latin-ext-2.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
23
+ @font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/jetbrains-mono-latin-3.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
24
+ @font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('./fonts/jetbrains-mono-latin-3.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
25
+
26
+ /* ── M3 Color Tokens — Light (exact from mockup) ─────────────────── */
27
+ :root {
28
+ --m3-surface: #f5f6f9;
29
+ --m3-surface-dim: #d7dce5;
30
+ --m3-surface-bright: #f5f6f9;
31
+ --m3-surface-container-lowest: #fafbfc;
32
+ --m3-surface-container-low: #eef0f5;
33
+ --m3-surface-container: #e7eaf0;
34
+ --m3-surface-container-high: #dfe3ea;
35
+ --m3-surface-container-highest:#d7dce5;
36
+ --m3-on-surface: #1c2333;
37
+ --m3-on-surface-variant: #45464d;
38
+ --m3-secondary: #566174;
39
+ --m3-outline: #7c828e;
40
+ --m3-outline-variant: #d3d7df;
41
+ --m3-primary: #000000;
42
+ --m3-on-primary: #ffffff;
43
+ --m3-on-primary-container: #497cff;
44
+ --m3-primary-fixed: #dbe7ff;
45
+ --m3-primary-fixed-dim: #b4c5ff;
46
+ --m3-primary-container: #00174b;
47
+ --m3-surface-tint: #0053db;
48
+ --m3-inverse-primary: #b4c5ff;
49
+ --m3-secondary-container: #d0e1fb;
50
+ --m3-on-secondary-container: #54647a;
51
+ --m3-secondary-fixed: #b7c8e1;
52
+ --m3-error: #ba1a1a;
53
+ --m3-error-container: #ffdad6;
54
+ --m3-on-error-container: #93000a;
55
+
56
+ /* Status colors matching mockup badges */
57
+ --m3-up: #166534;
58
+ --m3-up-bg: rgba(34, 197, 94, 0.12);
59
+ --m3-up-bar: #22c55e;
60
+ --m3-down: #ba1a1a;
61
+ --m3-down-bg: #ffdad6;
62
+ --m3-degraded: #854d0e;
63
+ --m3-degraded-bg: rgba(234, 179, 8, 0.12);
64
+ --m3-degraded-bar: #eab308;
65
+ --m3-partial: #9a3412;
66
+ --m3-partial-bg: rgba(249, 115, 22, 0.12);
67
+ --m3-partial-bar: #f97316;
68
+
69
+ /* Branding colours; an application may point them at its own tokens. */
70
+ --color-primary: var(--m3-primary);
71
+ --color-accent: var(--m3-on-primary-container);
72
+
73
+ /* Semantic action colors stay neutral and consistent across admin pages. */
74
+ --admin-action-primary: #dbe7ff;
75
+ --admin-action-primary-hover: #c9d9ff;
76
+ --admin-on-action-primary: #172033;
77
+ --admin-action-focus: rgba(73, 124, 255, 0.28);
78
+ --admin-selection: var(--m3-primary-fixed);
79
+ --admin-selection-hover: #c9d9ff;
80
+ --admin-on-selection: var(--m3-primary);
81
+ --admin-selection-border: #a9bfe6;
82
+ --admin-control-accent: #4b5563;
83
+ --admin-control-on: #ffffff;
84
+ --admin-icon-container: #e4e7ec;
85
+ --admin-icon-color: #4b5563;
86
+ --audit-create-bg: #d1fae5;
87
+ --audit-create-text: #065f46;
88
+ --audit-update-bg: #e0e7ff;
89
+ --audit-update-text: #3730a3;
90
+ --audit-delete-bg: #fee2e2;
91
+ --audit-delete-text: #991b1b;
92
+ }
93
+
94
+ /* ── M3 Color Tokens — Dark ───────────────────────────────────────── */
95
+ html.dark {
96
+ --m3-surface: #20232a;
97
+ --m3-surface-dim: #1a1c22;
98
+ --m3-surface-bright: #383c46;
99
+ --m3-surface-container-lowest: #252830;
100
+ --m3-surface-container-low: #1a1c22;
101
+ --m3-surface-container: #282b33;
102
+ --m3-surface-container-high: #30343d;
103
+ --m3-surface-container-highest:#383c46;
104
+ --m3-on-surface: #e3e5ea;
105
+ --m3-on-surface-variant: #c5cad3;
106
+ --m3-secondary: #aab0bb;
107
+ --m3-outline: #80868f;
108
+ --m3-outline-variant: #3a3e48;
109
+ --m3-primary: #b4c5ff;
110
+ --m3-on-primary: #111318;
111
+ --m3-on-primary-container: #aac7ff;
112
+ --m3-primary-container: #30333b;
113
+ --m3-secondary-container: #2a3a4d;
114
+ --m3-on-secondary-container: #c0cedd;
115
+ --m3-secondary-fixed: #3a4d62;
116
+ --m3-error: #ffb4ab;
117
+ --m3-error-container: #93000a;
118
+ --m3-on-error-container: #ffdad6;
119
+ --m3-primary-fixed: #3a3d46;
120
+ --m3-primary-fixed-dim: #30333b;
121
+ --m3-surface-tint: #b4c5ff;
122
+ --m3-inverse-primary: #0053db;
123
+
124
+ --admin-action-primary: #e5e7eb;
125
+ --admin-action-primary-hover: #ffffff;
126
+ --admin-on-action-primary: #111318;
127
+ --admin-action-focus: rgba(229, 231, 235, 0.28);
128
+ --admin-selection: #3a3d46;
129
+ --admin-selection-hover: #454953;
130
+ --admin-on-selection: #f0f1f3;
131
+ --admin-selection-border: #777e8b;
132
+ --admin-control-accent: #c3c8d1;
133
+ --admin-control-on: #1a1c22;
134
+ --admin-icon-container: #30343d;
135
+ --admin-icon-color: #d6d9df;
136
+ --audit-create-bg: #164e3b;
137
+ --audit-create-text: #a7f3d0;
138
+ --audit-update-bg: #37366d;
139
+ --audit-update-text: #d8d7ff;
140
+ --audit-delete-bg: #692d32;
141
+ --audit-delete-text: #fecaca;
142
+
143
+ --m3-up: #4ade80;
144
+ --m3-up-bg: rgba(74, 222, 128, 0.12);
145
+ --m3-up-bar: #4ade80;
146
+ --m3-down: #ffb4ab;
147
+ --m3-down-bg: rgba(147, 0, 10, 0.25);
148
+ --m3-degraded: #ffb950;
149
+ --m3-degraded-bg: rgba(234, 179, 8, 0.15);
150
+ --m3-degraded-bar: #fbbf24;
151
+ --m3-partial: #fb923c;
152
+ --m3-partial-bg: rgba(249, 115, 22, 0.15);
153
+ --m3-partial-bar: #f97316;
154
+ }
155
+
156
+ /* ── Base ─────────────────────────────────────────────────────────── */
157
+ * { box-sizing: border-box; }
158
+
159
+ body {
160
+ margin: 0;
161
+ font-family: 'Inter', system-ui, sans-serif;
162
+ background: var(--m3-surface);
163
+ color: var(--m3-on-surface);
164
+ }
165
+
166
+ input[type='checkbox'],
167
+ input[type='radio'] {
168
+ accent-color: var(--admin-control-accent);
169
+ }
170
+
171
+ /*
172
+ * Button system. Compose a shape with a variant: `btn btn-primary`, `btn btn-secondary`,
173
+ * `btn btn-ghost`, `btn btn-outline`, `btn btn-danger` (filled, for confirmations) or
174
+ * `btn btn-danger-outline`; add `btn-sm` for compact rows.
175
+ * `btn-icon` is a standalone square icon button. These live in the components layer so page-level
176
+ * utilities (e.g. `px-5`, `rounded-full`, `w-full`) still win.
177
+ */
178
+ @layer components {
179
+ .btn {
180
+ display: inline-flex;
181
+ align-items: center;
182
+ justify-content: center;
183
+ gap: 0.5rem;
184
+ border: 1px solid transparent;
185
+ border-radius: 0.75rem;
186
+ padding: 0.625rem 1rem;
187
+ font-size: 0.875rem;
188
+ line-height: 1.25rem;
189
+ font-weight: 600;
190
+ white-space: nowrap;
191
+ cursor: pointer;
192
+ transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease,
193
+ box-shadow 0.18s ease, opacity 0.18s ease, transform 0.18s ease;
194
+ }
195
+ .btn:active:not(:disabled) { transform: scale(0.98); }
196
+ .btn:disabled { opacity: 0.5; cursor: not-allowed; }
197
+ .btn .material-symbols-outlined { font-size: 18px; }
198
+
199
+ .btn-sm {
200
+ gap: 0.375rem;
201
+ border-radius: 0.5rem;
202
+ padding: 0.375rem 0.75rem;
203
+ font-size: 0.75rem;
204
+ line-height: 1rem;
205
+ }
206
+ .btn-sm .material-symbols-outlined { font-size: 16px; }
207
+
208
+ /* Outlined in light mode so the filled primary button is the only filled action. */
209
+ .btn-secondary {
210
+ background: transparent;
211
+ border-color: var(--m3-outline-variant);
212
+ color: var(--m3-on-surface);
213
+ }
214
+ .btn-secondary:hover:not(:disabled) { background: var(--m3-surface-container); }
215
+ html.dark .btn-secondary {
216
+ background: var(--m3-surface-container-high);
217
+ border-color: transparent;
218
+ }
219
+ html.dark .btn-secondary:hover:not(:disabled) { background: var(--m3-surface-container-highest); }
220
+
221
+ .btn-ghost {
222
+ background: transparent;
223
+ color: var(--m3-secondary);
224
+ }
225
+ .btn-ghost:hover:not(:disabled) {
226
+ background: var(--m3-surface-container);
227
+ color: var(--m3-on-surface);
228
+ }
229
+
230
+ .btn-outline {
231
+ background: transparent;
232
+ color: var(--m3-secondary);
233
+ border-color: var(--m3-outline-variant);
234
+ }
235
+ .btn-outline:hover:not(:disabled) {
236
+ background: var(--m3-surface-container);
237
+ color: var(--m3-on-surface);
238
+ }
239
+
240
+ .btn-danger {
241
+ background: var(--m3-error-container);
242
+ color: var(--m3-on-error-container);
243
+ border-color: color-mix(in srgb, var(--m3-error) 45%, transparent);
244
+ }
245
+ .btn-danger:hover:not(:disabled) {
246
+ border-color: var(--m3-error);
247
+ }
248
+ .btn-danger:focus-visible {
249
+ outline: none;
250
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--m3-down) 25%, transparent);
251
+ }
252
+
253
+ .btn-icon {
254
+ display: inline-flex;
255
+ align-items: center;
256
+ justify-content: center;
257
+ flex-shrink: 0;
258
+ width: 2rem;
259
+ height: 2rem;
260
+ border-radius: 0.5rem;
261
+ color: var(--m3-secondary);
262
+ background: transparent;
263
+ cursor: pointer;
264
+ transition: background-color 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
265
+ }
266
+ .btn-icon:hover:not(:disabled) {
267
+ background: var(--m3-surface-container);
268
+ color: var(--m3-on-surface);
269
+ }
270
+ .btn-icon:disabled { opacity: 0.5; cursor: not-allowed; }
271
+ .btn-icon .material-symbols-outlined { font-size: 20px; }
272
+
273
+ .focus-ring:focus-visible,
274
+ .btn-secondary:focus-visible,
275
+ .btn-ghost:focus-visible,
276
+ .btn-outline:focus-visible,
277
+ .btn-icon:focus-visible {
278
+ outline: none;
279
+ box-shadow: 0 0 0 3px var(--admin-action-focus);
280
+ }
281
+ }
282
+
283
+ /* Primary admin action: one contrast-safe appearance in every feature. */
284
+ .btn-primary {
285
+ background: var(--admin-action-primary) !important;
286
+ color: var(--admin-on-action-primary) !important;
287
+ border-color: transparent !important;
288
+ transition: background-color 0.18s ease, box-shadow 0.18s ease,
289
+ opacity 0.18s ease, transform 0.18s ease;
290
+ }
291
+ .btn-primary:hover:not(:disabled) {
292
+ background: var(--admin-action-primary-hover) !important;
293
+ }
294
+ .btn-primary:focus-visible {
295
+ outline: none;
296
+ box-shadow: 0 0 0 3px var(--admin-action-focus);
297
+ }
298
+ .btn-primary:disabled {
299
+ opacity: 0.5 !important;
300
+ cursor: not-allowed !important;
301
+ }
302
+
303
+ .btn-danger-outline {
304
+ color: var(--m3-down);
305
+ border: 1px solid var(--m3-outline-variant);
306
+ transition: background-color 0.18s ease, border-color 0.18s ease,
307
+ box-shadow 0.18s ease, transform 0.18s ease;
308
+ }
309
+ .btn-danger-outline:hover:not(:disabled) {
310
+ background: var(--m3-down-bg);
311
+ border-color: color-mix(in srgb, var(--m3-down) 45%, var(--m3-outline-variant));
312
+ }
313
+ .btn-danger-outline:focus-visible {
314
+ outline: none;
315
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--m3-down) 25%, transparent);
316
+ }
317
+ .btn-danger-outline:active:not(:disabled) {
318
+ transform: scale(0.98);
319
+ }
320
+ .btn-danger-outline:disabled {
321
+ cursor: not-allowed;
322
+ opacity: 0.5;
323
+ }
324
+
325
+ .copy-feedback-button {
326
+ background: var(--m3-surface-container-high);
327
+ color: var(--m3-on-surface);
328
+ border: 1px solid var(--m3-outline-variant);
329
+ transition: background-color 0.18s ease, border-color 0.18s ease,
330
+ color 0.18s ease, transform 0.18s ease;
331
+ }
332
+ .copy-feedback-button:hover {
333
+ background: var(--m3-surface-container-highest);
334
+ }
335
+ .copy-feedback-button[data-copied] {
336
+ background: var(--m3-up-bg);
337
+ border-color: color-mix(in srgb, var(--m3-up) 35%, var(--m3-outline-variant));
338
+ color: var(--m3-up);
339
+ }
340
+ .copy-feedback-button[data-failed] {
341
+ background: var(--m3-down-bg);
342
+ border-color: color-mix(in srgb, var(--m3-down) 35%, var(--m3-outline-variant));
343
+ color: var(--m3-down);
344
+ }
345
+ .copy-feedback-button:focus-visible {
346
+ outline: none;
347
+ box-shadow: 0 0 0 3px var(--admin-action-focus);
348
+ }
349
+ .copy-feedback-button:active {
350
+ transform: scale(0.98);
351
+ }
352
+
353
+ .selection-active {
354
+ background: var(--admin-selection) !important;
355
+ color: var(--admin-on-selection) !important;
356
+ border-color: var(--admin-selection-border) !important;
357
+ }
358
+ .selection-active:hover {
359
+ background: var(--admin-selection-hover) !important;
360
+ }
361
+
362
+ html.dark .side-tab-active {
363
+ background: var(--admin-selection) !important;
364
+ color: var(--admin-on-selection) !important;
365
+ }
366
+
367
+ html.dark .side-tab-badge-active {
368
+ background: var(--admin-on-selection) !important;
369
+ color: var(--admin-selection) !important;
370
+ }
371
+
372
+ /* ── Navigation (sidebar + mobile drawer) ─────────────────────────── */
373
+ .admin-nav-item {
374
+ display: flex;
375
+ width: 100%;
376
+ align-items: center;
377
+ gap: 0.75rem;
378
+ padding: 0.625rem 1rem;
379
+ border-radius: 0.75rem;
380
+ font-size: 0.875rem;
381
+ line-height: 1.25rem;
382
+ color: var(--m3-secondary);
383
+ text-align: left;
384
+ transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
385
+ }
386
+ .admin-nav-item:hover { transform: translateX(0.25rem); }
387
+ .admin-nav-item:not([aria-current='page']):hover {
388
+ background: rgba(0, 0, 0, 0.04);
389
+ color: var(--m3-on-surface);
390
+ }
391
+ html.dark .admin-nav-item:not([aria-current='page']):hover { background: rgba(255, 255, 255, 0.08); }
392
+ .admin-nav-item[aria-current='page'] {
393
+ background: var(--m3-surface-container-lowest);
394
+ color: var(--m3-on-surface);
395
+ font-weight: 600;
396
+ box-shadow: 0 1px 4px rgba(19, 27, 46, 0.08);
397
+ }
398
+ .admin-nav-item.admin-nav-danger:hover,
399
+ html.dark .admin-nav-item.admin-nav-danger:hover {
400
+ background: var(--m3-error-container);
401
+ color: var(--m3-on-error-container);
402
+ }
403
+ .admin-nav-item:focus-visible {
404
+ outline: none;
405
+ box-shadow: 0 0 0 3px var(--admin-action-focus);
406
+ }
407
+
408
+ @keyframes drawer-in {
409
+ from { transform: translateX(-100%); }
410
+ to { transform: translateX(0); }
411
+ }
412
+ @keyframes overlay-in {
413
+ from { opacity: 0; }
414
+ to { opacity: 1; }
415
+ }
416
+ .admin-drawer-panel { animation: drawer-in 0.22s ease-out; }
417
+ .admin-drawer-overlay { animation: overlay-in 0.22s ease-out; }
418
+
419
+ @keyframes toast-in {
420
+ from { opacity: 0; transform: translateY(8px); }
421
+ to { opacity: 1; transform: translateY(0); }
422
+ }
423
+ .admin-toast { animation: toast-in 0.2s ease-out; }
424
+
425
+ @media (prefers-reduced-motion: reduce) {
426
+ .admin-drawer-panel, .admin-drawer-overlay, .admin-toast { animation: none; }
427
+ .admin-nav-item:hover { transform: none; }
428
+ }
429
+
430
+ /* ── Input style ──────────────────────────────────────────────────── */
431
+ .input-m3 {
432
+ width: 100%;
433
+ background: var(--m3-surface-container-lowest);
434
+ border: 1.5px solid var(--m3-outline-variant);
435
+ border-radius: 10px;
436
+ padding: 9px 13px;
437
+ color: var(--m3-on-surface);
438
+ font-family: 'Inter', system-ui, sans-serif;
439
+ font-size: 14px;
440
+ outline: none;
441
+ transition: border-color 0.18s ease, box-shadow 0.18s ease;
442
+ }
443
+ .input-m3::placeholder { color: var(--m3-secondary); }
444
+ .input-m3:focus {
445
+ border-color: var(--m3-primary);
446
+ box-shadow: 0 0 0 3px rgba(0, 83, 219, 0.12);
447
+ }
448
+ html.dark .input-m3:focus {
449
+ box-shadow: 0 0 0 3px rgba(180, 197, 255, 0.15);
450
+ }
451
+ .input-m3:disabled { opacity: 0.45; cursor: not-allowed; }
452
+ select.input-m3 {
453
+ appearance: none;
454
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2376777d' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
455
+ background-repeat: no-repeat;
456
+ background-position: right 12px center;
457
+ padding-right: 32px;
458
+ }
459
+
460
+ input.input-m3:is([type='date'], [type='time'], [type='datetime-local']),
461
+ input.input-sig:is([type='date'], [type='time'], [type='datetime-local']) {
462
+ color-scheme: light;
463
+ }
464
+
465
+ html.dark input.input-m3:is([type='date'], [type='time'], [type='datetime-local']),
466
+ html.dark input.input-sig:is([type='date'], [type='time'], [type='datetime-local']) {
467
+ color-scheme: dark;
468
+ }
469
+
470
+ input.input-m3:is([type='date'], [type='time'], [type='datetime-local'])::-webkit-calendar-picker-indicator,
471
+ input.input-sig:is([type='date'], [type='time'], [type='datetime-local'])::-webkit-calendar-picker-indicator {
472
+ cursor: pointer;
473
+ opacity: 1;
474
+ }
475
+
476
+ /* Legacy alias */
477
+ .input-sig { @apply input-m3; }
478
+
479
+ /* ── Entrance animation ───────────────────────────────────────────── */
480
+ @keyframes fadeUp {
481
+ from { opacity: 0; transform: translateY(10px); }
482
+ to { opacity: 1; transform: translateY(0); }
483
+ }
484
+ .fade-up { opacity: 0; animation: fadeUp 0.4s ease forwards; }
485
+
486
+ /* ── Card hover ───────────────────────────────────────────────────── */
487
+ .card-hover {
488
+ transition: box-shadow 0.2s ease, border-color 0.2s ease;
489
+ }
490
+ .card-hover:hover {
491
+ box-shadow: 0 2px 12px rgba(0, 83, 219, 0.08);
492
+ border-color: var(--m3-outline);
493
+ }
494
+ html.dark .card-hover:hover {
495
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
496
+ }
497
+
498
+ /* ── Material Symbols ─────────────────────────────────────────────── */
499
+ .material-symbols-outlined {
500
+ font-family: 'Material Symbols Outlined';
501
+ font-weight: normal;
502
+ font-style: normal;
503
+ display: inline-block;
504
+ letter-spacing: normal;
505
+ text-transform: none;
506
+ white-space: nowrap;
507
+ word-wrap: normal;
508
+ direction: ltr;
509
+ font-feature-settings: 'liga';
510
+ -webkit-font-smoothing: antialiased;
511
+ font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
512
+ font-size: inherit;
513
+ line-height: 1;
514
+ vertical-align: middle;
515
+ }
516
+
517
+ /* ── Scrollbar ────────────────────────────────────────────────────── */
518
+ ::-webkit-scrollbar { width: 6px; }
519
+ ::-webkit-scrollbar-track { background: transparent; }
520
+ ::-webkit-scrollbar-thumb { background: var(--m3-outline-variant); border-radius: 3px; }
521
+
Binary file
@@ -0,0 +1,4 @@
1
+ /* The Material Symbols font cut down to the icons the shared interface (and the template) use. A product that draws
2
+ icons of its own builds a font that also holds the names listed in `@better-forge/ui/icons.json` and declares it
3
+ instead of importing this file. */
4
+ @font-face { font-family: 'Material Symbols Outlined'; font-style: normal; font-weight: 400; font-display: block; src: url('./fonts/material-symbols-outlined-fill.woff2') format('woff2'); }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The look of the Better interfaces as a Tailwind preset: colours are CSS variables (so branding and dark mode can swap
3
+ * them at runtime), the type faces and the entrance animation. Wrapping each colour in color-mix with Tailwind's
4
+ * <alpha-value> placeholder keeps opacity modifiers such as `bg-primary/10` working; without a modifier the mix is
5
+ * 100% and renders the variable unchanged.
6
+ */
7
+ import { fileURLToPath, URL } from 'node:url'
8
+
9
+ const token = (name) => `color-mix(in srgb, var(${name}) calc(<alpha-value> * 100%), transparent)`
10
+
11
+ /** @type {import('tailwindcss').Config} */
12
+ export default {
13
+ darkMode: 'class',
14
+ theme: {
15
+ extend: {
16
+ colors: {
17
+ // Branding aliases (runtime overrideable)
18
+ primary: token('--color-primary'),
19
+ accent: token('--color-accent'),
20
+ // M3 surface tokens (CSS-var backed → respond to dark mode)
21
+ surface: token('--m3-surface'),
22
+ 'surface-dim': token('--m3-surface-dim'),
23
+ 'surface-bright': token('--m3-surface-bright'),
24
+ 'surface-container-lowest': token('--m3-surface-container-lowest'),
25
+ 'surface-container-low': token('--m3-surface-container-low'),
26
+ 'surface-container': token('--m3-surface-container'),
27
+ 'surface-container-high': token('--m3-surface-container-high'),
28
+ 'surface-container-highest': token('--m3-surface-container-highest'),
29
+ // M3 on-surface tokens
30
+ 'on-surface': token('--m3-on-surface'),
31
+ 'on-surface-variant': token('--m3-on-surface-variant'),
32
+ // M3 misc
33
+ secondary: token('--m3-secondary'),
34
+ outline: token('--m3-outline'),
35
+ 'outline-variant': token('--m3-outline-variant'),
36
+ 'on-primary': token('--m3-on-primary'),
37
+ 'on-primary-container': token('--m3-on-primary-container'),
38
+ 'primary-fixed': token('--m3-primary-fixed'),
39
+ 'primary-container': token('--m3-primary-container'),
40
+ 'surface-tint': token('--m3-surface-tint'),
41
+ 'secondary-container': token('--m3-secondary-container'),
42
+ 'on-secondary-container': token('--m3-on-secondary-container'),
43
+ 'secondary-fixed': token('--m3-secondary-fixed'),
44
+ error: token('--m3-error'),
45
+ 'error-container': token('--m3-error-container'),
46
+ 'on-error-container': token('--m3-on-error-container'),
47
+ // Status colors
48
+ 'status-up': token('--m3-up'),
49
+ 'status-down': token('--m3-down'),
50
+ 'status-degraded': token('--m3-degraded'),
51
+ 'status-partial': token('--m3-partial'),
52
+ },
53
+ fontFamily: {
54
+ headline: ['Manrope', 'system-ui', 'sans-serif'],
55
+ display: ['Manrope', 'system-ui', 'sans-serif'],
56
+ sans: ['Inter', 'system-ui', 'sans-serif'],
57
+ // Small uppercase eyebrow labels (Dashboard, Setup); same face as body text.
58
+ label: ['Inter', 'system-ui', 'sans-serif'],
59
+ mono: ['JetBrains Mono', 'Menlo', 'monospace'],
60
+ },
61
+ animation: {
62
+ 'fade-up': 'fadeUp 0.45s ease forwards',
63
+ },
64
+ keyframes: {
65
+ fadeUp: {
66
+ '0%': { opacity: '0', transform: 'translateY(12px)' },
67
+ '100%': { opacity: '1', transform: 'translateY(0)' },
68
+ },
69
+ },
70
+ borderRadius: {
71
+ '3xl': '1.5rem',
72
+ '4xl': '2rem',
73
+ },
74
+ },
75
+ },
76
+ }
77
+
78
+ /** Where the classes of the shared components are written, to add to a product's `content`. */
79
+ export const uiContent = `${fileURLToPath(new URL('./dist', import.meta.url)).replaceAll('\\', '/')}/**/*.js`