@hoardodile/ui 0.0.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 (356) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +70 -0
  3. package/dist/components/alert.d.ts +13 -0
  4. package/dist/components/alert.js +97 -0
  5. package/dist/components/alert.js.map +1 -0
  6. package/dist/components/app-dialog.d.ts +62 -0
  7. package/dist/components/app-dialog.js +656 -0
  8. package/dist/components/app-dialog.js.map +1 -0
  9. package/dist/components/badge.d.ts +11 -0
  10. package/dist/components/badge.js +70 -0
  11. package/dist/components/badge.js.map +1 -0
  12. package/dist/components/breadcrumb.d.ts +12 -0
  13. package/dist/components/breadcrumb.js +617 -0
  14. package/dist/components/breadcrumb.js.map +1 -0
  15. package/dist/components/button.d.ts +17 -0
  16. package/dist/components/button.js +78 -0
  17. package/dist/components/button.js.map +1 -0
  18. package/dist/components/caption-bar.d.ts +44 -0
  19. package/dist/components/caption-bar.js +827 -0
  20. package/dist/components/caption-bar.js.map +1 -0
  21. package/dist/components/chart-card.d.ts +15 -0
  22. package/dist/components/chart-card.js +27 -0
  23. package/dist/components/chart-card.js.map +1 -0
  24. package/dist/components/checkbox.d.ts +6 -0
  25. package/dist/components/checkbox.js +76 -0
  26. package/dist/components/checkbox.js.map +1 -0
  27. package/dist/components/chip-button.d.ts +28 -0
  28. package/dist/components/chip-button.js +87 -0
  29. package/dist/components/chip-button.js.map +1 -0
  30. package/dist/components/close-confirm-dialog.d.ts +19 -0
  31. package/dist/components/close-confirm-dialog.js +743 -0
  32. package/dist/components/close-confirm-dialog.js.map +1 -0
  33. package/dist/components/color-picker.d.ts +32 -0
  34. package/dist/components/color-picker.js +667 -0
  35. package/dist/components/color-picker.js.map +1 -0
  36. package/dist/components/combobox.d.ts +32 -0
  37. package/dist/components/combobox.js +1211 -0
  38. package/dist/components/combobox.js.map +1 -0
  39. package/dist/components/confirm-by-typing-dialog.d.ts +48 -0
  40. package/dist/components/confirm-by-typing-dialog.js +759 -0
  41. package/dist/components/confirm-by-typing-dialog.js.map +1 -0
  42. package/dist/components/confirm-dialog.d.ts +34 -0
  43. package/dist/components/confirm-dialog.js +710 -0
  44. package/dist/components/confirm-dialog.js.map +1 -0
  45. package/dist/components/count-badge.d.ts +13 -0
  46. package/dist/components/count-badge.js +39 -0
  47. package/dist/components/count-badge.js.map +1 -0
  48. package/dist/components/dialog.d.ts +40 -0
  49. package/dist/components/dialog.js +571 -0
  50. package/dist/components/dialog.js.map +1 -0
  51. package/dist/components/dropdown-menu.d.ts +45 -0
  52. package/dist/components/dropdown-menu.js +1003 -0
  53. package/dist/components/dropdown-menu.js.map +1 -0
  54. package/dist/components/dropdown-select.d.ts +29 -0
  55. package/dist/components/dropdown-select.js +1036 -0
  56. package/dist/components/dropdown-select.js.map +1 -0
  57. package/dist/components/empty.d.ts +15 -0
  58. package/dist/components/empty.js +119 -0
  59. package/dist/components/empty.js.map +1 -0
  60. package/dist/components/filter-rail.d.ts +48 -0
  61. package/dist/components/filter-rail.js +231 -0
  62. package/dist/components/filter-rail.js.map +1 -0
  63. package/dist/components/fixed-action-bar.d.ts +24 -0
  64. package/dist/components/fixed-action-bar.js +48 -0
  65. package/dist/components/fixed-action-bar.js.map +1 -0
  66. package/dist/components/font-picker.d.ts +45 -0
  67. package/dist/components/font-picker.js +759 -0
  68. package/dist/components/font-picker.js.map +1 -0
  69. package/dist/components/form.d.ts +17 -0
  70. package/dist/components/form.js +150 -0
  71. package/dist/components/form.js.map +1 -0
  72. package/dist/components/group-label.d.ts +12 -0
  73. package/dist/components/group-label.js +10 -0
  74. package/dist/components/group-label.js.map +1 -0
  75. package/dist/components/icon-tile.d.ts +16 -0
  76. package/dist/components/icon-tile.js +67 -0
  77. package/dist/components/icon-tile.js.map +1 -0
  78. package/dist/components/icon-toggle.d.ts +24 -0
  79. package/dist/components/icon-toggle.js +81 -0
  80. package/dist/components/icon-toggle.js.map +1 -0
  81. package/dist/components/icon.d.ts +2 -0
  82. package/dist/components/icon.js +49 -0
  83. package/dist/components/icon.js.map +1 -0
  84. package/dist/components/image-crop-panel.d.ts +80 -0
  85. package/dist/components/image-crop-panel.js +1104 -0
  86. package/dist/components/image-crop-panel.js.map +1 -0
  87. package/dist/components/image-cropper.d.ts +63 -0
  88. package/dist/components/image-cropper.js +166 -0
  89. package/dist/components/image-cropper.js.map +1 -0
  90. package/dist/components/input-group.d.ts +22 -0
  91. package/dist/components/input-group.js +270 -0
  92. package/dist/components/input-group.js.map +1 -0
  93. package/dist/components/input.d.ts +16 -0
  94. package/dist/components/input.js +60 -0
  95. package/dist/components/input.js.map +1 -0
  96. package/dist/components/label.d.ts +5 -0
  97. package/dist/components/label.js +40 -0
  98. package/dist/components/label.js.map +1 -0
  99. package/dist/components/list-empty-row.d.ts +16 -0
  100. package/dist/components/list-empty-row.js +40 -0
  101. package/dist/components/list-empty-row.js.map +1 -0
  102. package/dist/components/management-empty.d.ts +14 -0
  103. package/dist/components/management-empty.js +40 -0
  104. package/dist/components/management-empty.js.map +1 -0
  105. package/dist/components/management-skeleton.d.ts +11 -0
  106. package/dist/components/management-skeleton.js +72 -0
  107. package/dist/components/management-skeleton.js.map +1 -0
  108. package/dist/components/meta-chip.d.ts +17 -0
  109. package/dist/components/meta-chip.js +49 -0
  110. package/dist/components/meta-chip.js.map +1 -0
  111. package/dist/components/mobile-drawer.d.ts +29 -0
  112. package/dist/components/mobile-drawer.js +331 -0
  113. package/dist/components/mobile-drawer.js.map +1 -0
  114. package/dist/components/page-header.d.ts +20 -0
  115. package/dist/components/page-header.js +44 -0
  116. package/dist/components/page-header.js.map +1 -0
  117. package/dist/components/page-scaffold.d.ts +34 -0
  118. package/dist/components/page-scaffold.js +157 -0
  119. package/dist/components/page-scaffold.js.map +1 -0
  120. package/dist/components/pagination-bar.d.ts +22 -0
  121. package/dist/components/pagination-bar.js +703 -0
  122. package/dist/components/pagination-bar.js.map +1 -0
  123. package/dist/components/pagination.d.ts +22 -0
  124. package/dist/components/pagination.js +680 -0
  125. package/dist/components/pagination.js.map +1 -0
  126. package/dist/components/panel-toolbar.d.ts +37 -0
  127. package/dist/components/panel-toolbar.js +781 -0
  128. package/dist/components/panel-toolbar.js.map +1 -0
  129. package/dist/components/pill-tabs.d.ts +33 -0
  130. package/dist/components/pill-tabs.js +66 -0
  131. package/dist/components/pill-tabs.js.map +1 -0
  132. package/dist/components/plugin-download-consent.d.ts +52 -0
  133. package/dist/components/plugin-download-consent.js +780 -0
  134. package/dist/components/plugin-download-consent.js.map +1 -0
  135. package/dist/components/popover.d.ts +26 -0
  136. package/dist/components/popover.js +343 -0
  137. package/dist/components/popover.js.map +1 -0
  138. package/dist/components/progress.d.ts +10 -0
  139. package/dist/components/progress.js +103 -0
  140. package/dist/components/progress.js.map +1 -0
  141. package/dist/components/query-state-view.d.ts +36 -0
  142. package/dist/components/query-state-view.js +17 -0
  143. package/dist/components/query-state-view.js.map +1 -0
  144. package/dist/components/radio-group.d.ts +8 -0
  145. package/dist/components/radio-group.js +60 -0
  146. package/dist/components/radio-group.js.map +1 -0
  147. package/dist/components/scroll-area.d.ts +7 -0
  148. package/dist/components/scroll-area.js +80 -0
  149. package/dist/components/scroll-area.js.map +1 -0
  150. package/dist/components/search-field.d.ts +49 -0
  151. package/dist/components/search-field.js +586 -0
  152. package/dist/components/search-field.js.map +1 -0
  153. package/dist/components/secondary-stat.d.ts +13 -0
  154. package/dist/components/secondary-stat.js +56 -0
  155. package/dist/components/secondary-stat.js.map +1 -0
  156. package/dist/components/section-header.d.ts +23 -0
  157. package/dist/components/section-header.js +76 -0
  158. package/dist/components/section-header.js.map +1 -0
  159. package/dist/components/section-label.d.ts +20 -0
  160. package/dist/components/section-label.js +46 -0
  161. package/dist/components/section-label.js.map +1 -0
  162. package/dist/components/section-tabs.d.ts +47 -0
  163. package/dist/components/section-tabs.js +145 -0
  164. package/dist/components/section-tabs.js.map +1 -0
  165. package/dist/components/separator.d.ts +14 -0
  166. package/dist/components/separator.js +49 -0
  167. package/dist/components/separator.js.map +1 -0
  168. package/dist/components/sheet.d.ts +22 -0
  169. package/dist/components/sheet.js +469 -0
  170. package/dist/components/sheet.js.map +1 -0
  171. package/dist/components/sidebar.d.ts +69 -0
  172. package/dist/components/sidebar.js +1645 -0
  173. package/dist/components/sidebar.js.map +1 -0
  174. package/dist/components/skeleton.d.ts +8 -0
  175. package/dist/components/skeleton.js +41 -0
  176. package/dist/components/skeleton.js.map +1 -0
  177. package/dist/components/slider.d.ts +6 -0
  178. package/dist/components/slider.js +75 -0
  179. package/dist/components/slider.js.map +1 -0
  180. package/dist/components/sortable-chip-list.d.ts +26 -0
  181. package/dist/components/sortable-chip-list.js +59 -0
  182. package/dist/components/sortable-chip-list.js.map +1 -0
  183. package/dist/components/spinner.d.ts +5 -0
  184. package/dist/components/spinner.js +65 -0
  185. package/dist/components/spinner.js.map +1 -0
  186. package/dist/components/surface.d.ts +13 -0
  187. package/dist/components/surface.js +51 -0
  188. package/dist/components/surface.js.map +1 -0
  189. package/dist/components/switch.d.ts +8 -0
  190. package/dist/components/switch.js +53 -0
  191. package/dist/components/switch.js.map +1 -0
  192. package/dist/components/table.d.ts +12 -0
  193. package/dist/components/table.js +129 -0
  194. package/dist/components/table.js.map +1 -0
  195. package/dist/components/textarea.d.ts +15 -0
  196. package/dist/components/textarea.js +58 -0
  197. package/dist/components/textarea.js.map +1 -0
  198. package/dist/components/toast.d.ts +19 -0
  199. package/dist/components/toast.js +805 -0
  200. package/dist/components/toast.js.map +1 -0
  201. package/dist/components/toggle.d.ts +12 -0
  202. package/dist/components/toggle.js +63 -0
  203. package/dist/components/toggle.js.map +1 -0
  204. package/dist/components/tooltip.d.ts +9 -0
  205. package/dist/components/tooltip.js +82 -0
  206. package/dist/components/tooltip.js.map +1 -0
  207. package/dist/hooks/use-dialog-footer-actions.d.ts +18 -0
  208. package/dist/hooks/use-dialog-footer-actions.js +11 -0
  209. package/dist/hooks/use-dialog-footer-actions.js.map +1 -0
  210. package/dist/hooks/use-form-field.d.ts +33 -0
  211. package/dist/hooks/use-form-field.js +36 -0
  212. package/dist/hooks/use-form-field.js.map +1 -0
  213. package/dist/hooks/use-mobile.d.ts +34 -0
  214. package/dist/hooks/use-mobile.js +29 -0
  215. package/dist/hooks/use-mobile.js.map +1 -0
  216. package/dist/hooks/use-pinch-pan.d.ts +56 -0
  217. package/dist/hooks/use-pinch-pan.js +223 -0
  218. package/dist/hooks/use-pinch-pan.js.map +1 -0
  219. package/dist/hooks/useMobileBackToClose.d.ts +61 -0
  220. package/dist/hooks/useMobileBackToClose.js +234 -0
  221. package/dist/hooks/useMobileBackToClose.js.map +1 -0
  222. package/dist/icon-BOgL5bpL.d.ts +85 -0
  223. package/dist/icons/actions.d.ts +4 -0
  224. package/dist/icons/actions.js +520 -0
  225. package/dist/icons/actions.js.map +1 -0
  226. package/dist/icons/icon-style.d.ts +2 -0
  227. package/dist/icons/icon-style.js +51 -0
  228. package/dist/icons/icon-style.js.map +1 -0
  229. package/dist/icons/marks.d.ts +15 -0
  230. package/dist/icons/marks.js +48 -0
  231. package/dist/icons/marks.js.map +1 -0
  232. package/dist/icons/registry.d.ts +177 -0
  233. package/dist/icons/registry.js +1180 -0
  234. package/dist/icons/registry.js.map +1 -0
  235. package/dist/index.d.ts +6 -0
  236. package/dist/index.js +653 -0
  237. package/dist/index.js.map +1 -0
  238. package/dist/lib/merge-config.d.ts +15 -0
  239. package/dist/lib/merge-config.js +20 -0
  240. package/dist/lib/merge-config.js.map +1 -0
  241. package/dist/lib/pagination.d.ts +19 -0
  242. package/dist/lib/pagination.js +26 -0
  243. package/dist/lib/pagination.js.map +1 -0
  244. package/dist/lib/utils.d.ts +5 -0
  245. package/dist/lib/utils.js +26 -0
  246. package/dist/lib/utils.js.map +1 -0
  247. package/dist/styles/theme.css +480 -0
  248. package/dist/styles/theme.css.map +1 -0
  249. package/dist/styles/theme.d.ts +2 -0
  250. package/dist/viewport.d.ts +64 -0
  251. package/dist/viewport.js +13 -0
  252. package/dist/viewport.js.map +1 -0
  253. package/package.json +122 -0
  254. package/src/components/alert.tsx +76 -0
  255. package/src/components/app-dialog.tsx +187 -0
  256. package/src/components/badge.tsx +52 -0
  257. package/src/components/breadcrumb.tsx +129 -0
  258. package/src/components/button.tsx +70 -0
  259. package/src/components/caption-bar.test.tsx +151 -0
  260. package/src/components/caption-bar.tsx +392 -0
  261. package/src/components/chart-card.tsx +31 -0
  262. package/src/components/checkbox.tsx +28 -0
  263. package/src/components/chip-button.tsx +69 -0
  264. package/src/components/close-confirm-dialog.tsx +99 -0
  265. package/src/components/color-picker.tsx +186 -0
  266. package/src/components/combobox.tsx +335 -0
  267. package/src/components/confirm-by-typing-dialog.tsx +130 -0
  268. package/src/components/confirm-dialog.test.tsx +39 -0
  269. package/src/components/confirm-dialog.tsx +98 -0
  270. package/src/components/count-badge.tsx +23 -0
  271. package/src/components/dialog.tsx +315 -0
  272. package/src/components/dropdown-menu.tsx +311 -0
  273. package/src/components/dropdown-select.tsx +211 -0
  274. package/src/components/empty.tsx +104 -0
  275. package/src/components/filter-rail.tsx +139 -0
  276. package/src/components/fixed-action-bar.tsx +46 -0
  277. package/src/components/font-picker.tsx +257 -0
  278. package/src/components/form.tsx +127 -0
  279. package/src/components/group-label.tsx +13 -0
  280. package/src/components/icon-tile.tsx +35 -0
  281. package/src/components/icon-toggle.tsx +57 -0
  282. package/src/components/icon.tsx +66 -0
  283. package/src/components/image-crop-panel.test.tsx +167 -0
  284. package/src/components/image-crop-panel.tsx +465 -0
  285. package/src/components/image-cropper.test.tsx +144 -0
  286. package/src/components/image-cropper.tsx +265 -0
  287. package/src/components/input-group.tsx +156 -0
  288. package/src/components/input.tsx +45 -0
  289. package/src/components/label.tsx +20 -0
  290. package/src/components/list-empty-row.tsx +27 -0
  291. package/src/components/management-empty.tsx +25 -0
  292. package/src/components/management-skeleton.tsx +23 -0
  293. package/src/components/meta-chip.tsx +40 -0
  294. package/src/components/mobile-drawer.test.tsx +52 -0
  295. package/src/components/mobile-drawer.tsx +98 -0
  296. package/src/components/page-header.tsx +47 -0
  297. package/src/components/page-scaffold.test.tsx +24 -0
  298. package/src/components/page-scaffold.tsx +131 -0
  299. package/src/components/pagination-bar.test.tsx +87 -0
  300. package/src/components/pagination-bar.tsx +139 -0
  301. package/src/components/pagination.tsx +139 -0
  302. package/src/components/panel-toolbar.tsx +99 -0
  303. package/src/components/pill-tabs.test.tsx +84 -0
  304. package/src/components/pill-tabs.tsx +77 -0
  305. package/src/components/plugin-download-consent.test.tsx +90 -0
  306. package/src/components/plugin-download-consent.tsx +183 -0
  307. package/src/components/popover.tsx +133 -0
  308. package/src/components/progress.tsx +88 -0
  309. package/src/components/query-state-view.tsx +47 -0
  310. package/src/components/radio-group.tsx +36 -0
  311. package/src/components/scroll-area.tsx +52 -0
  312. package/src/components/search-field.test.tsx +86 -0
  313. package/src/components/search-field.tsx +119 -0
  314. package/src/components/secondary-stat.tsx +24 -0
  315. package/src/components/section-header.tsx +54 -0
  316. package/src/components/section-label.tsx +40 -0
  317. package/src/components/section-tabs.test.tsx +154 -0
  318. package/src/components/section-tabs.tsx +190 -0
  319. package/src/components/separator.tsx +38 -0
  320. package/src/components/sheet.tsx +170 -0
  321. package/src/components/sidebar.tsx +725 -0
  322. package/src/components/skeleton.tsx +18 -0
  323. package/src/components/slider.tsx +52 -0
  324. package/src/components/sortable-chip-list.tsx +56 -0
  325. package/src/components/spinner.tsx +35 -0
  326. package/src/components/surface.tsx +37 -0
  327. package/src/components/switch.tsx +30 -0
  328. package/src/components/table.tsx +116 -0
  329. package/src/components/textarea.tsx +41 -0
  330. package/src/components/toast.tsx +239 -0
  331. package/src/components/toggle.tsx +45 -0
  332. package/src/components/tooltip.tsx +64 -0
  333. package/src/hooks/use-dialog-footer-actions.ts +23 -0
  334. package/src/hooks/use-form-field.ts +62 -0
  335. package/src/hooks/use-mobile.ts +54 -0
  336. package/src/hooks/use-pinch-pan.test.tsx +42 -0
  337. package/src/hooks/use-pinch-pan.ts +340 -0
  338. package/src/hooks/useMobileBackToClose.test.tsx +140 -0
  339. package/src/hooks/useMobileBackToClose.ts +508 -0
  340. package/src/icons/actions.ts +10 -0
  341. package/src/icons/icon-style.test.tsx +69 -0
  342. package/src/icons/icon-style.ts +104 -0
  343. package/src/icons/marks.tsx +72 -0
  344. package/src/icons/registry.test.ts +65 -0
  345. package/src/icons/registry.ts +1163 -0
  346. package/src/index.ts +22 -0
  347. package/src/lib/merge-config.test.ts +109 -0
  348. package/src/lib/merge-config.ts +22 -0
  349. package/src/lib/pagination.test.ts +55 -0
  350. package/src/lib/pagination.ts +42 -0
  351. package/src/lib/utils.ts +6 -0
  352. package/src/styles/scan-contract.test.ts +74 -0
  353. package/src/styles/theme.css +798 -0
  354. package/src/test/i18n.tsx +22 -0
  355. package/src/test/setup.ts +104 -0
  356. package/src/viewport.ts +69 -0
@@ -0,0 +1,798 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+ @import "shadcn/tailwind.css";
4
+
5
+ @custom-variant dark (&:is(.dark *));
6
+ /* Same shape as `dark`, so it stacks (`desktop-shell:sidebar:`,
7
+ `desktop-shell:md:`). Electron app minWidth is 800px, so `max-md:`
8
+ never matches in the shell. */
9
+ @custom-variant desktop-shell (&:is(html.desktop-shell *));
10
+
11
+ @theme inline {
12
+ /* Type scale (DESIGN.md — Typography) — layout constants. */
13
+ --text-tiny: 0.6875rem;
14
+ --text-tiny--line-height: 1rem;
15
+ --text-ui: 0.8125rem;
16
+ --text-ui--line-height: 1.25rem;
17
+ --text-doc: 1.1875rem;
18
+ --text-doc--line-height: 1.9;
19
+ --text-doc-title: 3rem;
20
+ --text-doc-title--line-height: 1.15;
21
+ --text-doc-heading: 1.75rem;
22
+ --text-doc-heading--line-height: 1.3;
23
+ --text-quote: 1.125rem;
24
+ --text-quote--line-height: 1.65;
25
+ --tracking-label: 0.1em;
26
+ --font-heading: var(--font-sans);
27
+ /* Doc serif — the documents feature's reading serif; per-slot overrides
28
+ (user font prefs) live in the app's CSS variables. */
29
+ --font-doc: Georgia, "Times New Roman", serif;
30
+ /* UI stack (-apple-system … Arial) plus CJK fallbacks. Keep in sync
31
+ with SYSTEM_FONT_TAGS in apps/web/src/lib/fonts.ts. */
32
+ --font-sans:
33
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
34
+ Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
35
+ "Hiragino Sans", "Yu Gothic UI", "Meiryo", sans-serif;
36
+ --color-sidebar-ring: var(--sidebar-ring);
37
+ --color-sidebar-border: var(--sidebar-border);
38
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
39
+ --color-sidebar-accent: var(--sidebar-accent);
40
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
41
+ --color-sidebar-primary: var(--sidebar-primary);
42
+ --color-sidebar-foreground: var(--sidebar-foreground);
43
+ --color-sidebar: var(--sidebar);
44
+ --color-ring: var(--ring);
45
+ --color-input: var(--input);
46
+ --color-border: var(--border);
47
+ --color-border-strong: var(--border-strong);
48
+ --color-destructive: var(--destructive);
49
+ --color-accent-foreground: var(--accent-foreground);
50
+ --color-accent: var(--accent);
51
+ --color-muted-foreground: var(--muted-foreground);
52
+ --color-muted: var(--muted);
53
+ --color-secondary-foreground: var(--secondary-foreground);
54
+ --color-secondary: var(--secondary);
55
+ --color-primary-foreground: var(--primary-foreground);
56
+ --color-primary: var(--primary);
57
+ --color-popover-foreground: var(--popover-foreground);
58
+ --color-popover: var(--popover);
59
+ --color-card-foreground: var(--card-foreground);
60
+ --color-card: var(--card);
61
+ --color-foreground: var(--foreground);
62
+ --color-background: var(--background);
63
+ /* Chart ink — data ink follows the palette hue (--icon-tone), falling
64
+ back to plain foreground ink in mono, which defines no hue. Same
65
+ fallback chain as the duotone icon second tone (`--color-icon-tone`). */
66
+ --color-chart: var(--icon-tone, var(--foreground));
67
+ --color-icon-tone: var(--icon-tone, var(--foreground));
68
+ --radius: 0.625rem;
69
+ --radius-sm: calc(var(--radius) * 0.6);
70
+ --radius-md: calc(var(--radius) * 0.8);
71
+ --radius-lg: var(--radius);
72
+ --radius-xl: calc(var(--radius) * 1.2);
73
+ --radius-2xl: calc(var(--radius) * 1.8);
74
+ --radius-3xl: calc(var(--radius) * 2.2);
75
+ --radius-4xl: calc(var(--radius) * 2.6);
76
+ --shadow-card: 0 1px 3px rgb(0 0 0 / 0.04);
77
+ /* Dialog float — the one shadow deeper than `card`: dialogs hover on a
78
+ taller surface (scrim + blur below), so the drop has two steps. */
79
+ --shadow-dialog:
80
+ 0 1px 2px rgb(0 0 0 / 0.04), 0 24px 48px -16px rgb(0 0 0 / 0.16);
81
+
82
+ /* Content widths (DESIGN.md — Layout) — `--container-*` powers
83
+ max-w-reading / max-w-medium / max-w-content. */
84
+ --container-reading: 680px;
85
+ --container-medium: 800px;
86
+ --container-content: 1200px;
87
+
88
+ /* Control heights (DESIGN.md — Layout) — the three interactive
89
+ families; spacing theme keys also power the height and size
90
+ utilities. */
91
+ --spacing-chip: 1.75rem;
92
+ --spacing-control: 2rem;
93
+ --spacing-nav: 2.375rem;
94
+
95
+ /* Chrome widths (DESIGN.md — Layout) — `--spacing-*` keys power
96
+ the width utilities: sidebar 264 fixed left rail, panel 320
97
+ contextual right panel (also the 1fr+panel grid columns). */
98
+ --spacing-sidebar: 16.5rem;
99
+ --spacing-panel: 20rem;
100
+
101
+ /* Motion (DESIGN.md) — four durations, three easings. Faster than
102
+ the mainstream OS defaults; chrome lives in 1–3, media gets 4.
103
+ `--ease-*` keys also (re)define the matching ease utilities. */
104
+ --duration-1: 100ms;
105
+ --duration-2: 160ms;
106
+ --duration-3: 240ms;
107
+ --duration-4: 320ms;
108
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
109
+ --ease-in: cubic-bezier(0.7, 0, 0.84, 0);
110
+ --ease-standard: cubic-bezier(0.2, 0, 0, 1);
111
+
112
+ /* Loading shimmer (skeletons) — a quiet opacity pulse. */
113
+ --animate-skel: skel 1.6s ease-in-out infinite;
114
+ @keyframes skel {
115
+ 0%,
116
+ 100% {
117
+ opacity: 1;
118
+ }
119
+ 50% {
120
+ opacity: 0.55;
121
+ }
122
+ }
123
+
124
+ /* Completion confirmation (DESIGN.md — upload ritual): a quiet
125
+ pop, opacity + scale only, no bounce. */
126
+ --animate-pop: pop 240ms cubic-bezier(0.16, 1, 0.3, 1);
127
+ @keyframes pop {
128
+ from {
129
+ opacity: 0;
130
+ transform: scale(0.8);
131
+ }
132
+ }
133
+
134
+ /* Breakpoints are declared explicitly so the JS mobile detection and
135
+ Tailwind responsive prefixes stay in sync. viewport.ts must match:
136
+ `MOBILE_BREAKPOINT_PX` ↔ `--breakpoint-md`, `SIDEBAR_BREAKPOINT_PX`
137
+ ↔ `--breakpoint-sidebar`, `PANEL_BREAKPOINT_PX` ↔ `--breakpoint-panel`. */
138
+ --breakpoint-sm: 40rem;
139
+ --breakpoint-md: 48rem;
140
+ --breakpoint-lg: 64rem;
141
+ --breakpoint-xl: 80rem;
142
+ --breakpoint-2xl: 96rem;
143
+ --breakpoint-sidebar: 1150px;
144
+ --breakpoint-panel: 1440px;
145
+ }
146
+
147
+ /* ── Mono (default palette) ─────────────────────────────
148
+ Pure black-and-white typography palette: no hue anywhere,
149
+ surfaces stepped only in lightness. Primary is ink black in
150
+ light mode and paper white in dark mode. This is the default
151
+ palette: it lives in `:root` / `.dark` with no class, and the
152
+ `.theme-mono` block further down mirrors it so a local scope
153
+ can explicitly opt back in. */
154
+
155
+ :root {
156
+ --background: #fbfbfb;
157
+ --foreground: #101010;
158
+ --card: #ffffff;
159
+ --card-foreground: #101010;
160
+ --popover: #ffffff;
161
+ --popover-foreground: #101010;
162
+ --primary: #101010;
163
+ --primary-foreground: #ffffff;
164
+ --secondary: #f1f0f1;
165
+ --secondary-foreground: #4a4a48;
166
+ --muted: #f1f0f1;
167
+ --muted-foreground: #9a9a96;
168
+ --accent: #e7e7e9;
169
+ --accent-foreground: #101010;
170
+ --destructive: oklch(0.577 0.245 27.325);
171
+ --destructive-foreground: oklch(1 0 0);
172
+ --border: #eaeaeb;
173
+ --border-strong: #d6d6d8;
174
+ --input: #eaeaeb;
175
+ --ring: oklch(0.4 0 0);
176
+ --sidebar: #fbfbfb;
177
+ --sidebar-foreground: #101010;
178
+ --sidebar-primary: #101010;
179
+ --sidebar-primary-foreground: #ffffff;
180
+ --sidebar-accent: #f1f0f1;
181
+ --sidebar-accent-foreground: #101010;
182
+ --sidebar-border: #eaeaeb;
183
+ --sidebar-ring: oklch(0.4 0 0);
184
+ --shadow-color: oklch(0 0 0);
185
+ }
186
+
187
+ .dark {
188
+ --background: oklch(0.12 0 0);
189
+ --foreground: oklch(0.96 0 0);
190
+ --card: oklch(0.16 0 0);
191
+ --card-foreground: oklch(0.96 0 0);
192
+ --popover: oklch(0.18 0 0);
193
+ --popover-foreground: oklch(0.96 0 0);
194
+ --primary: oklch(0.95 0 0);
195
+ --primary-foreground: oklch(0.13 0 0);
196
+ --secondary: oklch(0.18 0 0);
197
+ --secondary-foreground: oklch(0.95 0 0);
198
+ --muted: oklch(0.18 0 0);
199
+ --muted-foreground: oklch(0.65 0 0);
200
+ --accent: oklch(0.22 0 0);
201
+ --accent-foreground: oklch(0.96 0 0);
202
+ --destructive: oklch(0.704 0.191 22.216);
203
+ --destructive-foreground: oklch(0.96 0 0);
204
+ --border: oklch(0.24 0 0);
205
+ --border-strong: oklch(0.28 0 0);
206
+ --input: oklch(0.28 0 0);
207
+ --ring: oklch(0.7 0 0);
208
+ --sidebar: oklch(0.08 0 0);
209
+ --sidebar-foreground: oklch(0.96 0 0);
210
+ --sidebar-primary: oklch(0.95 0 0);
211
+ --sidebar-primary-foreground: oklch(0.13 0 0);
212
+ --sidebar-accent: oklch(0.18 0 0);
213
+ --sidebar-accent-foreground: oklch(0.96 0 0);
214
+ --sidebar-border: oklch(0.24 0 0);
215
+ --sidebar-ring: oklch(0.7 0 0);
216
+ --shadow-color: oklch(0 0 0);
217
+ }
218
+
219
+ /* ── Sage ─────────────────────────────────────────────────
220
+ Quiet sage-green journal palette. Light values anchor on the settings swatches (canvas #f5f6f0,
221
+ ink #212920, accent #5f6d5b); fills are tonal steps of the canvas —
222
+ cards and the sidebar sit slightly deeper than the content area.
223
+ Primary is the accent hue one step deeper, so actions read sage
224
+ instead of ink. Dark flips to warm cream ink on green-black, with a
225
+ light-sage primary.
226
+ ─────────────────────────────────────────────────────────────────── */
227
+
228
+ .theme-sage {
229
+ --background: #f5f6f0;
230
+ --foreground: #212920;
231
+ --card: #eef0ea;
232
+ --card-foreground: #212920;
233
+ --popover: #eef0ea;
234
+ --popover-foreground: #212920;
235
+ --primary: #525f4c;
236
+ --primary-foreground: #f2f4ec;
237
+ --secondary: #e7eae1;
238
+ --secondary-foreground: #55604f;
239
+ --muted: #e7eae1;
240
+ --muted-foreground: #8a9083;
241
+ --accent: #dee2d6;
242
+ --accent-foreground: #212920;
243
+ --destructive: oklch(0.55 0.18 28);
244
+ --destructive-foreground: #fbfbf8;
245
+ --border: #e0e4d9;
246
+ --border-strong: #cdd3c1;
247
+ --input: #e0e4d9;
248
+ --ring: #525f4c;
249
+ --sidebar: #e7eae1;
250
+ --sidebar-foreground: #212920;
251
+ --sidebar-primary: #525f4c;
252
+ --sidebar-primary-foreground: #f2f4ec;
253
+ --sidebar-accent: #dee2d6;
254
+ --sidebar-accent-foreground: #212920;
255
+ --sidebar-border: #e0e4d9;
256
+ --sidebar-ring: #525f4c;
257
+ --icon-tone: #5f6d5b;
258
+ }
259
+
260
+ html.dark.theme-sage,
261
+ .dark .theme-sage {
262
+ --background: #0a100e;
263
+ --foreground: #d8cfbf;
264
+ --card: #101a15;
265
+ --card-foreground: #d8cfbf;
266
+ --popover: #152019;
267
+ --popover-foreground: #d8cfbf;
268
+ --primary: #a8bd96;
269
+ --primary-foreground: #101a15;
270
+ --secondary: #152019;
271
+ --secondary-foreground: #a9a79b;
272
+ --muted: #152019;
273
+ --muted-foreground: #7d7e74;
274
+ --accent: #1b2a20;
275
+ --accent-foreground: #ddd7c8;
276
+ --destructive: oklch(0.63 0.155 25);
277
+ --destructive-foreground: #e4e9e0;
278
+ --border: #1d2a22;
279
+ --border-strong: #28392d;
280
+ --input: #1d2a22;
281
+ --ring: #a8bd96;
282
+ --sidebar: #070d0b;
283
+ --sidebar-foreground: #d8cfbf;
284
+ --sidebar-primary: #a8bd96;
285
+ --sidebar-primary-foreground: #101a15;
286
+ --sidebar-accent: #1b2a20;
287
+ --sidebar-accent-foreground: #ddd7c8;
288
+ --sidebar-border: #1d2a22;
289
+ --sidebar-ring: #a8bd96;
290
+ --icon-tone: #75855a;
291
+ }
292
+
293
+ /* ── Parchment ───────────────────────────────────────────────
294
+ Straw-paper reader palette — the documents area's default. Light values anchor on the settings
295
+ swatches (canvas #d9c7a3, ink #302202, accent #966500); cards sit
296
+ deeper than the canvas, like panels on paper. Primary is the bronze
297
+ accent deepened for contrast. Dark is the reader's night mode —
298
+ gray surfaces, a light-bronze primary, the accent shifts to red.
299
+ ─────────────────────────────────────────────────────────────────── */
300
+
301
+ .theme-parchment {
302
+ --background: #d9c7a3;
303
+ --foreground: #302202;
304
+ --card: #ccb991;
305
+ --card-foreground: #302202;
306
+ --popover: #ccb991;
307
+ --popover-foreground: #302202;
308
+ --primary: #7d5600;
309
+ --primary-foreground: #f3e8ce;
310
+ --secondary: #c0ac87;
311
+ --secondary-foreground: #6a5a39;
312
+ --muted: #c0ac87;
313
+ --muted-foreground: #9e8c63;
314
+ --accent: #bfa87a;
315
+ --accent-foreground: #302202;
316
+ --destructive: oklch(0.577 0.245 27.325);
317
+ --destructive-foreground: oklch(1 0 0);
318
+ --border: #b7a175;
319
+ --border-strong: #a38c5c;
320
+ --input: #b7a175;
321
+ --ring: #7d5600;
322
+ --sidebar: #c0ac87;
323
+ --sidebar-foreground: #302202;
324
+ --sidebar-primary: #7d5600;
325
+ --sidebar-primary-foreground: #f3e8ce;
326
+ --sidebar-accent: #bfa87a;
327
+ --sidebar-accent-foreground: #302202;
328
+ --sidebar-border: #b7a175;
329
+ --sidebar-ring: #7d5600;
330
+ --icon-tone: #966500;
331
+ }
332
+
333
+ html.dark.theme-parchment,
334
+ .dark .theme-parchment {
335
+ --background: #181818;
336
+ --foreground: #b8b8b8;
337
+ --card: #262626;
338
+ --card-foreground: #b8b8b8;
339
+ --popover: #2e2e2e;
340
+ --popover-foreground: #b8b8b8;
341
+ --primary: #d9a856;
342
+ --primary-foreground: #302202;
343
+ --secondary: #2e2e2e;
344
+ --secondary-foreground: #969696;
345
+ --muted: #2e2e2e;
346
+ --muted-foreground: #717171;
347
+ --accent: #3d2a2b;
348
+ --accent-foreground: #b8b8b8;
349
+ --destructive: oklch(0.704 0.191 22.216);
350
+ --destructive-foreground: oklch(0.96 0 0);
351
+ --border: #333333;
352
+ --border-strong: #454545;
353
+ --input: #333333;
354
+ --ring: #d9a856;
355
+ --sidebar: #101010;
356
+ --sidebar-foreground: #b8b8b8;
357
+ --sidebar-primary: #d9a856;
358
+ --sidebar-primary-foreground: #302202;
359
+ --sidebar-accent: #3d2a2b;
360
+ --sidebar-accent-foreground: #b8b8b8;
361
+ --sidebar-border: #333333;
362
+ --sidebar-ring: #d9a856;
363
+ --icon-tone: #966500;
364
+ }
365
+
366
+ /* ── Azure ──────────────────────────────────────────────────
367
+ Cool paper-white surfaces with a sky-blue accent. Light values anchor
368
+ on the settings swatches
369
+ (canvas #fbfbfc, ink #161718, accent #02aeee); fills lean cool.
370
+ Primary is the sky blue deepened enough to carry white text; dark
371
+ mode runs the accent blue itself with dark ink.
372
+ ─────────────────────────────────────────────────────────────────── */
373
+
374
+ .theme-azure {
375
+ --background: #fbfbfc;
376
+ --foreground: #161718;
377
+ --card: #ffffff;
378
+ --card-foreground: #161718;
379
+ --popover: #ffffff;
380
+ --popover-foreground: #161718;
381
+ --primary: #0277bd;
382
+ --primary-foreground: #ffffff;
383
+ --secondary: #f0f1f6;
384
+ --secondary-foreground: #5e6267;
385
+ --muted: #f0f1f6;
386
+ --muted-foreground: #95979a;
387
+ --accent: #e3f4fb;
388
+ --accent-foreground: #161718;
389
+ --destructive: oklch(0.577 0.245 27.325);
390
+ --destructive-foreground: oklch(1 0 0);
391
+ --border: #e4e5e7;
392
+ --border-strong: #d0d2d8;
393
+ --input: #e4e5e7;
394
+ --ring: #0277bd;
395
+ --sidebar: #f0f1f6;
396
+ --sidebar-foreground: #161718;
397
+ --sidebar-primary: #0277bd;
398
+ --sidebar-primary-foreground: #ffffff;
399
+ --sidebar-accent: #e3f4fb;
400
+ --sidebar-accent-foreground: #161718;
401
+ --sidebar-border: #e4e5e7;
402
+ --sidebar-ring: #0277bd;
403
+ --icon-tone: #02aeee;
404
+ }
405
+
406
+ html.dark.theme-azure,
407
+ .dark .theme-azure {
408
+ --background: #191a1c;
409
+ --foreground: #d7d4d0;
410
+ --card: #202224;
411
+ --card-foreground: #d7d4d0;
412
+ --popover: #292b2d;
413
+ --popover-foreground: #d7d4d0;
414
+ --primary: #02aeee;
415
+ --primary-foreground: #0d1f26;
416
+ --secondary: #292b2d;
417
+ --secondary-foreground: #a7a097;
418
+ --muted: #292b2d;
419
+ --muted-foreground: #8a857d;
420
+ --accent: #1d2c38;
421
+ --accent-foreground: #d7d4d0;
422
+ --destructive: oklch(0.704 0.191 22.216);
423
+ --destructive-foreground: oklch(0.96 0 0);
424
+ --border: #2c2f32;
425
+ --border-strong: #3a3e42;
426
+ --input: #2c2f32;
427
+ --ring: #02aeee;
428
+ --sidebar: #121316;
429
+ --sidebar-foreground: #d7d4d0;
430
+ --sidebar-primary: #02aeee;
431
+ --sidebar-primary-foreground: #0d1f26;
432
+ --sidebar-accent: #1d2c38;
433
+ --sidebar-accent-foreground: #d7d4d0;
434
+ --sidebar-border: #2c2f32;
435
+ --sidebar-ring: #02aeee;
436
+ --icon-tone: #008dc0;
437
+ }
438
+
439
+ /* ── Hoardodile ─────────────────────────────────────────────
440
+ The logo palette on mono's bones: the light canvas is mono's neutral #fbfbfb (matching the settings
441
+ swatch; the croc-belly tint survives only as the ink on primary),
442
+ with identity carried by the outline-olive icon tone #758a23 and a
443
+ soft croc-lime selection tint (body #bcd03b; the hat-band gold
444
+ #dcc06f stays in the artwork). Primary is the olive deepened for text
445
+ contrast. Dark mode is olive-black, flipping primary to the raw logo
446
+ lime and the icon tone with it.
447
+ ─────────────────────────────────────────────────────────────────── */
448
+
449
+ .theme-hoardodile {
450
+ --background: #fbfbfb;
451
+ --foreground: #272822;
452
+ --card: #ffffff;
453
+ --card-foreground: #272822;
454
+ --popover: #ffffff;
455
+ --popover-foreground: #272822;
456
+ --primary: #5f721f;
457
+ --primary-foreground: #f8f8f2;
458
+ --secondary: #edede3;
459
+ --secondary-foreground: #5c5d50;
460
+ --muted: #edede3;
461
+ --muted-foreground: #93917e;
462
+ --accent: #e9f4ce;
463
+ --accent-foreground: #272822;
464
+ --destructive: oklch(0.577 0.245 27.325);
465
+ --destructive-foreground: oklch(1 0 0);
466
+ --border: #e3e3d4;
467
+ --border-strong: #cfcfba;
468
+ --input: #e3e3d4;
469
+ --ring: #5f721f;
470
+ --sidebar: #edede3;
471
+ --sidebar-foreground: #272822;
472
+ --sidebar-primary: #5f721f;
473
+ --sidebar-primary-foreground: #f8f8f2;
474
+ --sidebar-accent: #e9f4ce;
475
+ --sidebar-accent-foreground: #272822;
476
+ --sidebar-border: #e3e3d4;
477
+ --sidebar-ring: #5f721f;
478
+ --icon-tone: #758a23;
479
+ }
480
+
481
+ html.dark.theme-hoardodile,
482
+ .dark .theme-hoardodile {
483
+ --background: #272822;
484
+ --foreground: #f8f8f2;
485
+ --card: #2f3028;
486
+ --card-foreground: #f8f8f2;
487
+ --popover: #34352c;
488
+ --popover-foreground: #f8f8f2;
489
+ --primary: #bcd03b;
490
+ --primary-foreground: #272822;
491
+ --secondary: #34352c;
492
+ --secondary-foreground: #bcbfb0;
493
+ --muted: #34352c;
494
+ --muted-foreground: #75715e;
495
+ --accent: #49483e;
496
+ --accent-foreground: #f8f8f2;
497
+ --destructive: oklch(0.704 0.191 22.216);
498
+ --destructive-foreground: oklch(0.96 0 0);
499
+ --border: #3a3b32;
500
+ --border-strong: #4c4d41;
501
+ --input: #3a3b32;
502
+ --ring: #bcd03b;
503
+ --sidebar: #1f201b;
504
+ --sidebar-foreground: #f8f8f2;
505
+ --sidebar-primary: #bcd03b;
506
+ --sidebar-primary-foreground: #272822;
507
+ --sidebar-accent: #49483e;
508
+ --sidebar-accent-foreground: #f8f8f2;
509
+ --sidebar-border: #3a3b32;
510
+ --sidebar-ring: #bcd03b;
511
+ --icon-tone: #bcd03b;
512
+ }
513
+
514
+ /* ── Mono palette class ───────────────────────────────────────
515
+ Mirrors :root / .dark so a local scope can explicitly opt back
516
+ into the mono palette even when the global theme uses another
517
+ palette.
518
+ ─────────────────────────────────────────────────────────────── */
519
+
520
+ .theme-mono {
521
+ --background: #fbfbfb;
522
+ --foreground: #101010;
523
+ --card: #ffffff;
524
+ --card-foreground: #101010;
525
+ --popover: #ffffff;
526
+ --popover-foreground: #101010;
527
+ --primary: #101010;
528
+ --primary-foreground: #ffffff;
529
+ --secondary: #f1f0f1;
530
+ --secondary-foreground: #4a4a48;
531
+ --muted: #f1f0f1;
532
+ --muted-foreground: #9a9a96;
533
+ --accent: #e7e7e9;
534
+ --accent-foreground: #101010;
535
+ --destructive: oklch(0.577 0.245 27.325);
536
+ --destructive-foreground: oklch(1 0 0);
537
+ --border: #eaeaeb;
538
+ --border-strong: #d6d6d8;
539
+ --input: #eaeaeb;
540
+ --ring: oklch(0.4 0 0);
541
+ --sidebar: #fbfbfb;
542
+ --sidebar-foreground: #101010;
543
+ --sidebar-primary: #101010;
544
+ --sidebar-primary-foreground: #ffffff;
545
+ --sidebar-accent: #f1f0f1;
546
+ --sidebar-accent-foreground: #101010;
547
+ --sidebar-border: #eaeaeb;
548
+ --sidebar-ring: oklch(0.4 0 0);
549
+ --shadow-color: oklch(0 0 0);
550
+ }
551
+
552
+ html.dark.theme-mono,
553
+ .dark .theme-mono {
554
+ --background: oklch(0.12 0 0);
555
+ --foreground: oklch(0.96 0 0);
556
+ --card: oklch(0.16 0 0);
557
+ --card-foreground: oklch(0.96 0 0);
558
+ --popover: oklch(0.18 0 0);
559
+ --popover-foreground: oklch(0.96 0 0);
560
+ --primary: oklch(0.95 0 0);
561
+ --primary-foreground: oklch(0.13 0 0);
562
+ --secondary: oklch(0.18 0 0);
563
+ --secondary-foreground: oklch(0.95 0 0);
564
+ --muted: oklch(0.18 0 0);
565
+ --muted-foreground: oklch(0.65 0 0);
566
+ --accent: oklch(0.22 0 0);
567
+ --accent-foreground: oklch(0.96 0 0);
568
+ --destructive: oklch(0.704 0.191 22.216);
569
+ --destructive-foreground: oklch(0.96 0 0);
570
+ --border: oklch(0.24 0 0);
571
+ --border-strong: oklch(0.28 0 0);
572
+ --input: oklch(0.28 0 0);
573
+ --ring: oklch(0.7 0 0);
574
+ --sidebar: oklch(0.08 0 0);
575
+ --sidebar-foreground: oklch(0.96 0 0);
576
+ --sidebar-primary: oklch(0.95 0 0);
577
+ --sidebar-primary-foreground: oklch(0.13 0 0);
578
+ --sidebar-accent: oklch(0.18 0 0);
579
+ --sidebar-accent-foreground: oklch(0.96 0 0);
580
+ --sidebar-border: oklch(0.24 0 0);
581
+ --sidebar-ring: oklch(0.7 0 0);
582
+ }
583
+
584
+ @layer base {
585
+ * {
586
+ @apply border-border;
587
+
588
+ /* Thin, quiet scrollbar everywhere (previously doc.css scoped).
589
+ Chromium styling goes through the ::-webkit-scrollbar pseudos
590
+ below; the standard `scrollbar-width`/`scrollbar-color` props
591
+ must NOT be set here — since Chrome 121 they disable all
592
+ ::-webkit-scrollbar styling on the element, which resurrects
593
+ the classic Windows scrollbar with arrow buttons. They are
594
+ applied to Firefox only via the @supports block further down. */
595
+ &::-webkit-scrollbar {
596
+ width: 10px;
597
+ height: 10px;
598
+ }
599
+
600
+ &::-webkit-scrollbar-track {
601
+ background: transparent;
602
+ }
603
+
604
+ &::-webkit-scrollbar-thumb {
605
+ background: color-mix(in oklab, var(--muted-foreground) 28%, transparent);
606
+ border-radius: 8px;
607
+ border: 3px solid transparent;
608
+ background-clip: padding-box;
609
+ }
610
+
611
+ &::-webkit-scrollbar-thumb:hover {
612
+ background: color-mix(in oklab, var(--muted-foreground) 45%, transparent);
613
+ background-clip: padding-box;
614
+ }
615
+ }
616
+
617
+ /* Element-scoped selectors above never match the Chromium viewport
618
+ scrollbar (it lives outside any element's scope), so the same styling
619
+ is repeated on bare pseudo-element selectors — without them the
620
+ viewport bar keeps the classic look with arrow buttons. */
621
+ ::-webkit-scrollbar {
622
+ width: 10px;
623
+ height: 10px;
624
+ }
625
+
626
+ ::-webkit-scrollbar-track {
627
+ background: transparent;
628
+ }
629
+
630
+ ::-webkit-scrollbar-thumb {
631
+ background: color-mix(in oklab, var(--muted-foreground) 28%, transparent);
632
+ border-radius: 8px;
633
+ border: 3px solid transparent;
634
+ background-clip: padding-box;
635
+ }
636
+
637
+ ::-webkit-scrollbar-thumb:hover {
638
+ background: color-mix(in oklab, var(--muted-foreground) 45%, transparent);
639
+ background-clip: padding-box;
640
+ }
641
+
642
+ ::-webkit-scrollbar-button {
643
+ display: none;
644
+ }
645
+
646
+ /* Firefox-only: the standard props are the only styling Firefox
647
+ understands, and on `*` they inherit to the root viewport bar.
648
+ Chromium must not receive them (see the note on `*` above). */
649
+ @supports not selector(::-webkit-scrollbar) {
650
+ * {
651
+ scrollbar-width: thin;
652
+ scrollbar-color: color-mix(
653
+ in oklab,
654
+ var(--muted-foreground) 28%,
655
+ transparent
656
+ )
657
+ transparent;
658
+ }
659
+ }
660
+
661
+ body {
662
+ @apply text-foreground;
663
+ }
664
+
665
+ html {
666
+ @apply font-sans;
667
+ }
668
+
669
+ /* CJK glyphs are denser than Latin — tiny text reads at 12px instead
670
+ of the 11px base so stroke detail survives (DESIGN.md —
671
+ Typography). The 12px rule out-ranks the `.text-tiny` utility. */
672
+ html:lang(zh) .text-tiny {
673
+ font-size: 0.75rem;
674
+ }
675
+
676
+ /* Buttons start clean: UA chrome (appearance, border, background,
677
+ padding, centered text) is fully reset so component classes own the
678
+ look. The pointer cursor is the base behavior; disabled flips to
679
+ the default arrow. */
680
+ button {
681
+ appearance: none;
682
+ border: 0;
683
+ background: transparent;
684
+ padding: 0;
685
+ color: inherit;
686
+ font: inherit;
687
+ text-align: inherit;
688
+ border-radius: 0;
689
+ cursor: pointer;
690
+ }
691
+
692
+ button:disabled {
693
+ cursor: default;
694
+ }
695
+ }
696
+
697
+ /* Hide scrollbars while keeping overflow scrollable — carousel strips,
698
+ tab bars, and command palettes rely on it (tabs.tsx, combobox.tsx,
699
+ command.tsx, sidebar.tsx, the overview marquee). */
700
+ @utility no-scrollbar {
701
+ scrollbar-width: none;
702
+ &::-webkit-scrollbar {
703
+ display: none;
704
+ }
705
+ }
706
+
707
+ /* Strip scrollbar — the rail's chip clouds and settings lists: a 4px
708
+ quiet thumb instead of the 10px base bar (DESIGN.md —
709
+ Scrollbars). Chromium goes through the pseudos; Firefox gets the
710
+ standard props via the @supports block (see the `*` note above). */
711
+ @utility strip-scroll {
712
+ &::-webkit-scrollbar {
713
+ width: 4px;
714
+ height: 4px;
715
+ }
716
+ &::-webkit-scrollbar-track {
717
+ background: transparent;
718
+ }
719
+ &::-webkit-scrollbar-thumb {
720
+ background: var(--border-strong);
721
+ border-radius: 2px;
722
+ }
723
+ &::-webkit-scrollbar-button {
724
+ display: none;
725
+ }
726
+ @supports not selector(::-webkit-scrollbar) {
727
+ scrollbar-width: thin;
728
+ scrollbar-color: var(--border-strong) transparent;
729
+ }
730
+ }
731
+
732
+ /* Duotone icons pick up the palette hue (DESIGN.md — Iconography):
733
+ solar v2 BoldDuotone renders its second tone via the
734
+ `--solar-secondary-color` CSS variable (falling back to currentColor) —
735
+ recolor just that tone per theme by pinning the variable to the palette
736
+ hue on the wrapper's `hd-icon` hook. Mono themes define no --icon-tone,
737
+ so the variable is invalid and the accent falls back to plain ink; the
738
+ Bold (selected) and Linear (monochrome) weights are untouched. */
739
+ :root {
740
+ /* solar v2 sizes icons as `1em` × `var(--solar-size, 24px)` — pin the
741
+ default to 1em so icon-less sizing matches v1 (class-based tiers rule
742
+ everywhere the design system has an opinion). */
743
+ --solar-size: 1em;
744
+ }
745
+
746
+ .hd-icon {
747
+ --solar-secondary-color: var(--icon-tone);
748
+ }
749
+
750
+ /* Grayscale icon mode (Settings → Icons): BoldDuotone keeps its two-tone
751
+ structure, but the second tone never takes the palette hue — it falls
752
+ back to plain ink, whose built-in half opacity reads as gray. Black and
753
+ gray in both light and dark, no extra tokens needed. */
754
+ [data-icon-style="grayscale"] .hd-icon {
755
+ --solar-secondary-color: currentColor;
756
+ }
757
+
758
+ /* Consumers resolve this file from dist/styles/, so the glob must cover the
759
+ tsup ESM outputs in dist/ (plain string literals — class names survive).
760
+ `.tsx` is kept for setups that compile the source tree directly. The
761
+ scan-contract test pins this against the built artifacts. */
762
+ @source "../**/*.{js,ts,tsx}";
763
+
764
+ /* ── Override tw-animate-css keyframes to remove filter:blur which forces
765
+ extra compositor work on mobile WebKit even when blur(0) ── */
766
+ @keyframes enter {
767
+ from {
768
+ opacity: var(--tw-enter-opacity, 1);
769
+ transform: translate3d(
770
+ var(--tw-enter-translate-x, 0),
771
+ var(--tw-enter-translate-y, 0),
772
+ 0
773
+ )
774
+ scale3d(
775
+ var(--tw-enter-scale, 1),
776
+ var(--tw-enter-scale, 1),
777
+ var(--tw-enter-scale, 1)
778
+ )
779
+ rotate(var(--tw-enter-rotate, 0));
780
+ }
781
+ }
782
+
783
+ @keyframes exit {
784
+ to {
785
+ opacity: var(--tw-exit-opacity, 1);
786
+ transform: translate3d(
787
+ var(--tw-exit-translate-x, 0),
788
+ var(--tw-exit-translate-y, 0),
789
+ 0
790
+ )
791
+ scale3d(
792
+ var(--tw-exit-scale, 1),
793
+ var(--tw-exit-scale, 1),
794
+ var(--tw-exit-scale, 1)
795
+ )
796
+ rotate(var(--tw-exit-rotate, 0));
797
+ }
798
+ }