@fangxinyan/lumina 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 (319) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +110 -0
  3. package/dist/Accordion-GSBY5T5U.css +38 -0
  4. package/dist/Accordion.cjs +13 -0
  5. package/dist/Accordion.cjs.map +1 -0
  6. package/dist/Accordion.d.cts +21 -0
  7. package/dist/Accordion.d.ts +21 -0
  8. package/dist/Accordion.js +4 -0
  9. package/dist/Accordion.js.map +1 -0
  10. package/dist/Alert-LSKBYDRI.css +35 -0
  11. package/dist/Alert.cjs +13 -0
  12. package/dist/Alert.cjs.map +1 -0
  13. package/dist/Alert.d.cts +17 -0
  14. package/dist/Alert.d.ts +17 -0
  15. package/dist/Alert.js +4 -0
  16. package/dist/Alert.js.map +1 -0
  17. package/dist/AppShell-RCALXUCZ.css +162 -0
  18. package/dist/AppShell.cjs +24 -0
  19. package/dist/AppShell.cjs.map +1 -0
  20. package/dist/AppShell.d.cts +68 -0
  21. package/dist/AppShell.d.ts +68 -0
  22. package/dist/AppShell.js +3 -0
  23. package/dist/AppShell.js.map +1 -0
  24. package/dist/Avatar-OXDSG5Q6.css +36 -0
  25. package/dist/Avatar.cjs +12 -0
  26. package/dist/Avatar.cjs.map +1 -0
  27. package/dist/Avatar.d.cts +15 -0
  28. package/dist/Avatar.d.ts +15 -0
  29. package/dist/Avatar.js +3 -0
  30. package/dist/Avatar.js.map +1 -0
  31. package/dist/Button-5UI7QXGU.css +96 -0
  32. package/dist/Button.cjs +17 -0
  33. package/dist/Button.cjs.map +1 -0
  34. package/dist/Button.d.cts +41 -0
  35. package/dist/Button.d.ts +41 -0
  36. package/dist/Button.js +4 -0
  37. package/dist/Button.js.map +1 -0
  38. package/dist/Calendar-LHZELUDL.css +65 -0
  39. package/dist/Calendar.cjs +13 -0
  40. package/dist/Calendar.cjs.map +1 -0
  41. package/dist/Calendar.d.cts +16 -0
  42. package/dist/Calendar.d.ts +16 -0
  43. package/dist/Calendar.js +4 -0
  44. package/dist/Calendar.js.map +1 -0
  45. package/dist/Card-2CHHFD4Y.css +28 -0
  46. package/dist/Card.cjs +16 -0
  47. package/dist/Card.cjs.map +1 -0
  48. package/dist/Card.d.cts +25 -0
  49. package/dist/Card.d.ts +25 -0
  50. package/dist/Card.js +3 -0
  51. package/dist/Card.js.map +1 -0
  52. package/dist/Cascader-TO2QMSLJ.css +76 -0
  53. package/dist/Cascader.cjs +13 -0
  54. package/dist/Cascader.cjs.map +1 -0
  55. package/dist/Cascader.d.cts +23 -0
  56. package/dist/Cascader.d.ts +23 -0
  57. package/dist/Cascader.js +4 -0
  58. package/dist/Cascader.js.map +1 -0
  59. package/dist/Checkbox-SKJATVSN.css +72 -0
  60. package/dist/Checkbox.cjs +17 -0
  61. package/dist/Checkbox.cjs.map +1 -0
  62. package/dist/Checkbox.d.cts +33 -0
  63. package/dist/Checkbox.d.ts +33 -0
  64. package/dist/Checkbox.js +4 -0
  65. package/dist/Checkbox.js.map +1 -0
  66. package/dist/Divider-Z37INS5E.css +49 -0
  67. package/dist/Divider.cjs +12 -0
  68. package/dist/Divider.cjs.map +1 -0
  69. package/dist/Divider.d.cts +12 -0
  70. package/dist/Divider.d.ts +12 -0
  71. package/dist/Divider.js +3 -0
  72. package/dist/Divider.js.map +1 -0
  73. package/dist/Empty-VM23UNLQ.css +138 -0
  74. package/dist/Empty.cjs +20 -0
  75. package/dist/Empty.cjs.map +1 -0
  76. package/dist/Empty.d.cts +37 -0
  77. package/dist/Empty.d.ts +37 -0
  78. package/dist/Empty.js +3 -0
  79. package/dist/Empty.js.map +1 -0
  80. package/dist/Icon.cjs +16 -0
  81. package/dist/Icon.cjs.map +1 -0
  82. package/dist/Icon.d.cts +21 -0
  83. package/dist/Icon.d.ts +21 -0
  84. package/dist/Icon.js +3 -0
  85. package/dist/Icon.js.map +1 -0
  86. package/dist/Image-WYWORJT4.css +106 -0
  87. package/dist/Image.cjs +17 -0
  88. package/dist/Image.cjs.map +1 -0
  89. package/dist/Image.d.cts +30 -0
  90. package/dist/Image.d.ts +30 -0
  91. package/dist/Image.js +4 -0
  92. package/dist/Image.js.map +1 -0
  93. package/dist/Input-Z526ARZP.css +66 -0
  94. package/dist/Input.cjs +17 -0
  95. package/dist/Input.cjs.map +1 -0
  96. package/dist/Input.d.cts +36 -0
  97. package/dist/Input.d.ts +36 -0
  98. package/dist/Input.js +4 -0
  99. package/dist/Input.js.map +1 -0
  100. package/dist/List-W5BW4D2P.css +26 -0
  101. package/dist/List.cjs +12 -0
  102. package/dist/List.cjs.map +1 -0
  103. package/dist/List.d.cts +20 -0
  104. package/dist/List.d.ts +20 -0
  105. package/dist/List.js +3 -0
  106. package/dist/List.js.map +1 -0
  107. package/dist/Modal-AYKNIWWQ.css +79 -0
  108. package/dist/Modal.cjs +18 -0
  109. package/dist/Modal.cjs.map +1 -0
  110. package/dist/Modal.d.cts +27 -0
  111. package/dist/Modal.d.ts +27 -0
  112. package/dist/Modal.js +5 -0
  113. package/dist/Modal.js.map +1 -0
  114. package/dist/Pagination-6FFOI4NM.css +35 -0
  115. package/dist/Pagination.cjs +13 -0
  116. package/dist/Pagination.cjs.map +1 -0
  117. package/dist/Pagination.d.cts +19 -0
  118. package/dist/Pagination.d.ts +19 -0
  119. package/dist/Pagination.js +4 -0
  120. package/dist/Pagination.js.map +1 -0
  121. package/dist/Popover-WXEVUYBG.css +15 -0
  122. package/dist/Popover.cjs +12 -0
  123. package/dist/Popover.cjs.map +1 -0
  124. package/dist/Popover.d.cts +16 -0
  125. package/dist/Popover.d.ts +16 -0
  126. package/dist/Popover.js +3 -0
  127. package/dist/Popover.js.map +1 -0
  128. package/dist/Progress-IXRSO5TW.css +63 -0
  129. package/dist/Progress.cjs +16 -0
  130. package/dist/Progress.cjs.map +1 -0
  131. package/dist/Progress.d.cts +26 -0
  132. package/dist/Progress.d.ts +26 -0
  133. package/dist/Progress.js +3 -0
  134. package/dist/Progress.js.map +1 -0
  135. package/dist/Select-DDJJBQEL.css +263 -0
  136. package/dist/Select.cjs +14 -0
  137. package/dist/Select.cjs.map +1 -0
  138. package/dist/Select.d.cts +68 -0
  139. package/dist/Select.d.ts +68 -0
  140. package/dist/Select.js +5 -0
  141. package/dist/Select.js.map +1 -0
  142. package/dist/Slider-RE4HZQKF.css +59 -0
  143. package/dist/Slider.cjs +12 -0
  144. package/dist/Slider.cjs.map +1 -0
  145. package/dist/Slider.d.cts +18 -0
  146. package/dist/Slider.d.ts +18 -0
  147. package/dist/Slider.js +3 -0
  148. package/dist/Slider.js.map +1 -0
  149. package/dist/Switch-NP7KKJOX.css +44 -0
  150. package/dist/Switch.cjs +12 -0
  151. package/dist/Switch.cjs.map +1 -0
  152. package/dist/Switch.d.cts +18 -0
  153. package/dist/Switch.d.ts +18 -0
  154. package/dist/Switch.js +3 -0
  155. package/dist/Switch.js.map +1 -0
  156. package/dist/Table-ZDPGWLH3.css +139 -0
  157. package/dist/Table.cjs +18 -0
  158. package/dist/Table.cjs.map +1 -0
  159. package/dist/Table.d.cts +57 -0
  160. package/dist/Table.d.ts +57 -0
  161. package/dist/Table.js +5 -0
  162. package/dist/Table.js.map +1 -0
  163. package/dist/Tabs-A27TSZOP.css +95 -0
  164. package/dist/Tabs.cjs +16 -0
  165. package/dist/Tabs.cjs.map +1 -0
  166. package/dist/Tabs.d.cts +35 -0
  167. package/dist/Tabs.d.ts +35 -0
  168. package/dist/Tabs.js +3 -0
  169. package/dist/Tabs.js.map +1 -0
  170. package/dist/Tag-EYOY3UWG.css +49 -0
  171. package/dist/Tag.cjs +17 -0
  172. package/dist/Tag.cjs.map +1 -0
  173. package/dist/Tag.d.cts +27 -0
  174. package/dist/Tag.d.ts +27 -0
  175. package/dist/Tag.js +4 -0
  176. package/dist/Tag.js.map +1 -0
  177. package/dist/Theme.cjs +44 -0
  178. package/dist/Theme.cjs.map +1 -0
  179. package/dist/Theme.d.cts +127 -0
  180. package/dist/Theme.d.ts +127 -0
  181. package/dist/Theme.js +3 -0
  182. package/dist/Theme.js.map +1 -0
  183. package/dist/Toast-ERHDN3WG.css +45 -0
  184. package/dist/Toast.cjs +17 -0
  185. package/dist/Toast.cjs.map +1 -0
  186. package/dist/Toast.d.cts +26 -0
  187. package/dist/Toast.d.ts +26 -0
  188. package/dist/Toast.js +4 -0
  189. package/dist/Toast.js.map +1 -0
  190. package/dist/Tooltip-RT4BOVTD.css +23 -0
  191. package/dist/Tooltip.cjs +12 -0
  192. package/dist/Tooltip.cjs.map +1 -0
  193. package/dist/Tooltip.d.cts +13 -0
  194. package/dist/Tooltip.d.ts +13 -0
  195. package/dist/Tooltip.js +3 -0
  196. package/dist/Tooltip.js.map +1 -0
  197. package/dist/chunk-2VA2HSL4.cjs +121 -0
  198. package/dist/chunk-2VA2HSL4.cjs.map +1 -0
  199. package/dist/chunk-2W2AJUZW.js +118 -0
  200. package/dist/chunk-2W2AJUZW.js.map +1 -0
  201. package/dist/chunk-3QWHDCHJ.js +53 -0
  202. package/dist/chunk-3QWHDCHJ.js.map +1 -0
  203. package/dist/chunk-3WAFIUDQ.js +85 -0
  204. package/dist/chunk-3WAFIUDQ.js.map +1 -0
  205. package/dist/chunk-4AA22BOG.js +63 -0
  206. package/dist/chunk-4AA22BOG.js.map +1 -0
  207. package/dist/chunk-4GT5TOHP.js +18 -0
  208. package/dist/chunk-4GT5TOHP.js.map +1 -0
  209. package/dist/chunk-5EYI27B6.js +64 -0
  210. package/dist/chunk-5EYI27B6.js.map +1 -0
  211. package/dist/chunk-6YVW3VYL.js +51 -0
  212. package/dist/chunk-6YVW3VYL.js.map +1 -0
  213. package/dist/chunk-77NP67ML.cjs +70 -0
  214. package/dist/chunk-77NP67ML.cjs.map +1 -0
  215. package/dist/chunk-7CKHWCEA.cjs +110 -0
  216. package/dist/chunk-7CKHWCEA.cjs.map +1 -0
  217. package/dist/chunk-7H453VPW.cjs +20 -0
  218. package/dist/chunk-7H453VPW.cjs.map +1 -0
  219. package/dist/chunk-7NM5BRUX.js +91 -0
  220. package/dist/chunk-7NM5BRUX.js.map +1 -0
  221. package/dist/chunk-7U6I44RV.cjs +283 -0
  222. package/dist/chunk-7U6I44RV.cjs.map +1 -0
  223. package/dist/chunk-AAMYURWQ.cjs +87 -0
  224. package/dist/chunk-AAMYURWQ.cjs.map +1 -0
  225. package/dist/chunk-ALFDP5WX.cjs +70 -0
  226. package/dist/chunk-ALFDP5WX.cjs.map +1 -0
  227. package/dist/chunk-C5TGQ7CV.cjs +114 -0
  228. package/dist/chunk-C5TGQ7CV.cjs.map +1 -0
  229. package/dist/chunk-F3NHM4GX.js +20 -0
  230. package/dist/chunk-F3NHM4GX.js.map +1 -0
  231. package/dist/chunk-FI7QO3I5.cjs +90 -0
  232. package/dist/chunk-FI7QO3I5.cjs.map +1 -0
  233. package/dist/chunk-FMG3ZPGK.js +88 -0
  234. package/dist/chunk-FMG3ZPGK.js.map +1 -0
  235. package/dist/chunk-G3UWXSNQ.js +71 -0
  236. package/dist/chunk-G3UWXSNQ.js.map +1 -0
  237. package/dist/chunk-GEYMWUW6.js +146 -0
  238. package/dist/chunk-GEYMWUW6.js.map +1 -0
  239. package/dist/chunk-HTP6UEVR.js +48 -0
  240. package/dist/chunk-HTP6UEVR.js.map +1 -0
  241. package/dist/chunk-I2ERCHFV.cjs +58 -0
  242. package/dist/chunk-I2ERCHFV.cjs.map +1 -0
  243. package/dist/chunk-I7SSCSFH.js +253 -0
  244. package/dist/chunk-I7SSCSFH.js.map +1 -0
  245. package/dist/chunk-IGHLSNXT.cjs +109 -0
  246. package/dist/chunk-IGHLSNXT.cjs.map +1 -0
  247. package/dist/chunk-IKI5CS4L.cjs +91 -0
  248. package/dist/chunk-IKI5CS4L.cjs.map +1 -0
  249. package/dist/chunk-ITGCHU3Y.cjs +94 -0
  250. package/dist/chunk-ITGCHU3Y.cjs.map +1 -0
  251. package/dist/chunk-JNFCTYJT.cjs +31 -0
  252. package/dist/chunk-JNFCTYJT.cjs.map +1 -0
  253. package/dist/chunk-JWFVSBVX.cjs +30 -0
  254. package/dist/chunk-JWFVSBVX.cjs.map +1 -0
  255. package/dist/chunk-K5MHL732.js +81 -0
  256. package/dist/chunk-K5MHL732.js.map +1 -0
  257. package/dist/chunk-K67KIKX4.cjs +67 -0
  258. package/dist/chunk-K67KIKX4.cjs.map +1 -0
  259. package/dist/chunk-KF4MCHZL.cjs +105 -0
  260. package/dist/chunk-KF4MCHZL.cjs.map +1 -0
  261. package/dist/chunk-M6CGYGEO.js +91 -0
  262. package/dist/chunk-M6CGYGEO.js.map +1 -0
  263. package/dist/chunk-M6OTFXZA.js +48 -0
  264. package/dist/chunk-M6OTFXZA.js.map +1 -0
  265. package/dist/chunk-NWJW5KLN.js +29 -0
  266. package/dist/chunk-NWJW5KLN.js.map +1 -0
  267. package/dist/chunk-NXOAYNG2.cjs +52 -0
  268. package/dist/chunk-NXOAYNG2.cjs.map +1 -0
  269. package/dist/chunk-NZPJ7BUB.cjs +22 -0
  270. package/dist/chunk-NZPJ7BUB.cjs.map +1 -0
  271. package/dist/chunk-OUJBCNWD.js +52 -0
  272. package/dist/chunk-OUJBCNWD.js.map +1 -0
  273. package/dist/chunk-OXYFB2ZI.js +35 -0
  274. package/dist/chunk-OXYFB2ZI.js.map +1 -0
  275. package/dist/chunk-Q33V7MSK.js +79 -0
  276. package/dist/chunk-Q33V7MSK.js.map +1 -0
  277. package/dist/chunk-QESLHLTG.cjs +107 -0
  278. package/dist/chunk-QESLHLTG.cjs.map +1 -0
  279. package/dist/chunk-QPZZNSRB.js +65 -0
  280. package/dist/chunk-QPZZNSRB.js.map +1 -0
  281. package/dist/chunk-QT7SJITQ.cjs +114 -0
  282. package/dist/chunk-QT7SJITQ.cjs.map +1 -0
  283. package/dist/chunk-RMD6KQ4H.cjs +56 -0
  284. package/dist/chunk-RMD6KQ4H.cjs.map +1 -0
  285. package/dist/chunk-T5AH4FCV.js +280 -0
  286. package/dist/chunk-T5AH4FCV.js.map +1 -0
  287. package/dist/chunk-U6ODMPTI.cjs +74 -0
  288. package/dist/chunk-U6ODMPTI.cjs.map +1 -0
  289. package/dist/chunk-V2ZUOEXM.cjs +73 -0
  290. package/dist/chunk-V2ZUOEXM.cjs.map +1 -0
  291. package/dist/chunk-VJN637MT.js +49 -0
  292. package/dist/chunk-VJN637MT.js.map +1 -0
  293. package/dist/chunk-VMHNKD3N.cjs +56 -0
  294. package/dist/chunk-VMHNKD3N.cjs.map +1 -0
  295. package/dist/chunk-VXITDXLW.js +28 -0
  296. package/dist/chunk-VXITDXLW.js.map +1 -0
  297. package/dist/chunk-XFRP2MBR.js +87 -0
  298. package/dist/chunk-XFRP2MBR.js.map +1 -0
  299. package/dist/chunk-XRZ5OKZH.js +101 -0
  300. package/dist/chunk-XRZ5OKZH.js.map +1 -0
  301. package/dist/chunk-Y6FVCCUE.js +34 -0
  302. package/dist/chunk-Y6FVCCUE.js.map +1 -0
  303. package/dist/chunk-YVO7XO4W.cjs +149 -0
  304. package/dist/chunk-YVO7XO4W.cjs.map +1 -0
  305. package/dist/chunk-ZMDVK2U3.cjs +302 -0
  306. package/dist/chunk-ZMDVK2U3.cjs.map +1 -0
  307. package/dist/chunk-ZXM247EM.cjs +123 -0
  308. package/dist/chunk-ZXM247EM.cjs.map +1 -0
  309. package/dist/index.cjs +249 -0
  310. package/dist/index.cjs.map +1 -0
  311. package/dist/index.d.cts +35 -0
  312. package/dist/index.d.ts +35 -0
  313. package/dist/index.js +35 -0
  314. package/dist/index.js.map +1 -0
  315. package/dist/shared-NJHRNLRH.css +4 -0
  316. package/dist/styles.css +2068 -0
  317. package/dist/tokens-HWQ7KWPG.css +153 -0
  318. package/dist/tokens.css +153 -0
  319. package/package.json +77 -0
@@ -0,0 +1,2068 @@
1
+ /* lumina — single stylesheet entry. Cascade order matters; preserve. */
2
+ /* ============================================================================
3
+ * Lumina · Design Tokens
4
+ * Override at :root or any ancestor element (e.g. <AppShell>) via data-* attrs.
5
+ * ========================================================================== */
6
+ :root {
7
+ /* ---- Surface (light) ---- */
8
+ --bg: #e8eef5;
9
+ --bg-raised: #edf2f8;
10
+ --bg-sunken: #dde4ed;
11
+ --fg: #3a4558;
12
+ --fg-muted: #7b8599;
13
+ --fg-subtle: #9ca7ba;
14
+ --border: rgba(130, 148, 175, 0.14);
15
+ --divider: rgba(130, 148, 175, 0.18);
16
+
17
+ /* ---- Shadows ---- */
18
+ --shadow-dark: rgba(163, 177, 198, 0.55);
19
+ --shadow-light: rgba(255, 255, 255, 0.95);
20
+ --shadow-blur: 16px;
21
+ --shadow-offset: 6px;
22
+ --shadow-inset-blur: 10px;
23
+ --shadow-inset-offset: 4px;
24
+
25
+ /* Distance multiplier (tweakable at runtime) */
26
+ --d: 1;
27
+
28
+ --neu-out:
29
+ var(--shadow-offset) var(--shadow-offset) var(--shadow-blur) var(--shadow-dark),
30
+ calc(var(--shadow-offset) * -1) calc(var(--shadow-offset) * -1) var(--shadow-blur) var(--shadow-light);
31
+
32
+ --neu-out-sm:
33
+ calc(var(--shadow-offset) * 0.5) calc(var(--shadow-offset) * 0.5) calc(var(--shadow-blur) * 0.6) var(--shadow-dark),
34
+ calc(var(--shadow-offset) * -0.5) calc(var(--shadow-offset) * -0.5) calc(var(--shadow-blur) * 0.6) var(--shadow-light);
35
+
36
+ --neu-out-lg:
37
+ calc(var(--shadow-offset) * 1.6) calc(var(--shadow-offset) * 1.6) calc(var(--shadow-blur) * 1.4) var(--shadow-dark),
38
+ calc(var(--shadow-offset) * -1.6) calc(var(--shadow-offset) * -1.6) calc(var(--shadow-blur) * 1.4) var(--shadow-light);
39
+
40
+ --neu-in:
41
+ inset var(--shadow-inset-offset) var(--shadow-inset-offset) var(--shadow-inset-blur) var(--shadow-dark),
42
+ inset calc(var(--shadow-inset-offset) * -1) calc(var(--shadow-inset-offset) * -1) var(--shadow-inset-blur) var(--shadow-light);
43
+
44
+ --neu-in-sm:
45
+ inset calc(var(--shadow-inset-offset) * 0.6) calc(var(--shadow-inset-offset) * 0.6) calc(var(--shadow-inset-blur) * 0.6) var(--shadow-dark),
46
+ inset calc(var(--shadow-inset-offset) * -0.6) calc(var(--shadow-inset-offset) * -0.6) calc(var(--shadow-inset-blur) * 0.6) var(--shadow-light);
47
+
48
+ --neu-flat:
49
+ 1px 1px 2px var(--shadow-dark),
50
+ -1px -1px 2px var(--shadow-light);
51
+
52
+ /* ---- Accent (default sky) ---- */
53
+ --accent: oklch(68% 0.14 235);
54
+ --accent-ink: oklch(42% 0.12 235);
55
+ --accent-soft: oklch(92% 0.04 235);
56
+ --accent-glow: oklch(68% 0.14 235 / 0.35);
57
+
58
+ /* ---- Semantic ---- */
59
+ --info: oklch(68% 0.14 235);
60
+ --success: oklch(68% 0.14 150);
61
+ --warning: oklch(75% 0.14 75);
62
+ --danger: oklch(64% 0.18 25);
63
+
64
+ /* ---- Radius ---- */
65
+ --r-xs: 8px;
66
+ --r-sm: 12px;
67
+ --r-md: 16px;
68
+ --r-lg: 20px;
69
+ --r-xl: 28px;
70
+ --r-pill: 999px;
71
+
72
+ /* ---- Spacing ---- */
73
+ --gap-1: 4px;
74
+ --gap-2: 8px;
75
+ --gap-3: 12px;
76
+ --gap-4: 16px;
77
+ --gap-5: 20px;
78
+ --gap-6: 24px;
79
+ --gap-8: 32px;
80
+ --gap-10: 40px;
81
+
82
+ /* ---- Control sizes (density) ---- */
83
+ --ctrl-h: 40px;
84
+ --ctrl-pad-x: 18px;
85
+
86
+ /* ---- Type ---- */
87
+ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
88
+ "Hiragino Sans GB", "Microsoft YaHei", "Source Han Sans SC",
89
+ "Noto Sans CJK SC", sans-serif;
90
+ --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Consolas, monospace;
91
+ --font-display: "SF Pro Display", var(--font-sans);
92
+
93
+ /* ---- Motion ---- */
94
+ --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
95
+ --dur-fast: 140ms;
96
+ --dur: 220ms;
97
+ --dur-slow: 360ms;
98
+ }
99
+ /* ---- Dark theme ----
100
+ 深色模式的拟态不能照搬浅色思路:白色高光会变成刺眼的白圈。
101
+ 这里做法:保留深色阴影给"下沉"深度,把"上凸高光"压到很低 alpha,
102
+ 让整体更接近 flat-with-depth 而不是强烈的 3D 凸起。 */
103
+ :root[data-theme="dark"],
104
+ [data-theme="dark"] {
105
+ --bg: #1b2030;
106
+ --bg-raised: #242a3c;
107
+ --bg-sunken: #151a27;
108
+ --fg: #d8deeb;
109
+ --fg-muted: #8b94ab;
110
+ --fg-subtle: #5f6a82;
111
+ --border: rgba(0, 0, 0, 0.35);
112
+ --divider: rgba(255, 255, 255, 0.06);
113
+ /* 强 dark shadow 提供深度;light 高光几乎不可见,去掉白圈效果 */
114
+ --shadow-dark: rgba(0, 0, 0, 0.55);
115
+ --shadow-light: rgba(130, 145, 180, 0.06);
116
+ /* 同时收紧阴影尺寸,深色模式下拟态更内敛 */
117
+ --shadow-offset: 4px;
118
+ --shadow-blur: 10px;
119
+ --shadow-inset-offset: 3px;
120
+ --shadow-inset-blur: 7px;
121
+ --accent-soft: oklch(35% 0.06 235);
122
+ --accent-ink: oklch(82% 0.09 235);
123
+ --accent-glow: oklch(68% 0.14 235 / 0.18);
124
+ }
125
+ /* 深色模式的 accent-glow 统一降低强度,避免按钮外圈过亮 */
126
+ [data-theme="dark"][data-accent="sky"] { --accent-soft: oklch(35% 0.08 235); --accent-ink: oklch(82% 0.10 235); --accent-glow: oklch(68% 0.14 235 / 0.18); }
127
+ [data-theme="dark"][data-accent="coral"] { --accent-soft: oklch(38% 0.09 35); --accent-ink: oklch(84% 0.10 35); --accent-glow: oklch(72% 0.16 35 / 0.18); }
128
+ [data-theme="dark"][data-accent="mint"] { --accent-soft: oklch(36% 0.08 165); --accent-ink: oklch(83% 0.10 165); --accent-glow: oklch(72% 0.13 165 / 0.18); }
129
+ [data-theme="dark"][data-accent="violet"] { --accent-soft: oklch(36% 0.09 290); --accent-ink: oklch(82% 0.11 290); --accent-glow: oklch(66% 0.16 290 / 0.18); }
130
+ [data-theme="dark"][data-accent="amber"] { --accent-soft: oklch(38% 0.08 75); --accent-ink: oklch(85% 0.10 75); --accent-glow: oklch(76% 0.14 75 / 0.18); }
131
+ [data-theme="dark"][data-accent="rose"] { --accent-soft: oklch(38% 0.09 10); --accent-ink: oklch(84% 0.11 10); --accent-glow: oklch(68% 0.17 10 / 0.18); }
132
+ /* ---- Accent palette ---- */
133
+ [data-accent="sky"] { --accent: oklch(68% 0.14 235); --accent-ink: oklch(42% 0.12 235); --accent-soft: oklch(92% 0.04 235); --accent-glow: oklch(68% 0.14 235 / 0.35); }
134
+ [data-accent="coral"] { --accent: oklch(72% 0.16 35); --accent-ink: oklch(48% 0.14 35); --accent-soft: oklch(94% 0.04 35); --accent-glow: oklch(72% 0.16 35 / 0.35); }
135
+ [data-accent="mint"] { --accent: oklch(72% 0.13 165); --accent-ink: oklch(46% 0.11 165); --accent-soft: oklch(93% 0.04 165); --accent-glow: oklch(72% 0.13 165 / 0.35); }
136
+ [data-accent="violet"] { --accent: oklch(66% 0.16 290); --accent-ink: oklch(44% 0.14 290); --accent-soft: oklch(93% 0.04 290); --accent-glow: oklch(66% 0.16 290 / 0.35); }
137
+ [data-accent="amber"] { --accent: oklch(76% 0.14 75); --accent-ink: oklch(50% 0.12 75); --accent-soft: oklch(94% 0.05 75); --accent-glow: oklch(76% 0.14 75 / 0.35); }
138
+ [data-accent="rose"] { --accent: oklch(68% 0.17 10); --accent-ink: oklch(46% 0.15 10); --accent-soft: oklch(93% 0.04 10); --accent-glow: oklch(68% 0.17 10 / 0.35); }
139
+ /* (dark-mode per-accent overrides are defined above, with --accent-glow included) */
140
+ /* ---- Density ---- */
141
+ [data-density="compact"] {
142
+ --gap-3: 8px; --gap-4: 12px; --gap-5: 14px; --gap-6: 18px; --gap-8: 24px;
143
+ --ctrl-h: 34px; --ctrl-pad-x: 14px;
144
+ }
145
+ [data-density="spacious"] {
146
+ --gap-3: 16px; --gap-4: 20px; --gap-5: 26px; --gap-6: 32px; --gap-8: 44px;
147
+ --ctrl-h: 46px; --ctrl-pad-x: 22px;
148
+ }
149
+ /* ============================================================================
150
+ * lumina · Base styles
151
+ * ========================================================================== */
152
+ *, *::before, *::after { box-sizing: border-box; }
153
+ html, body, #root { height: 100%; }
154
+ body {
155
+ margin: 0;
156
+ background: var(--bg);
157
+ color: var(--fg);
158
+ font-family: var(--font-sans);
159
+ font-size: 14px;
160
+ line-height: 1.5;
161
+ -webkit-font-smoothing: antialiased;
162
+ -moz-osx-font-smoothing: grayscale;
163
+ font-feature-settings: "cv11", "ss01";
164
+ text-rendering: optimizeLegibility;
165
+ }
166
+ h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.01em; color: var(--fg); }
167
+ p { margin: 0; }
168
+ button { font-family: inherit; color: inherit; cursor: pointer; border: none; background: none; }
169
+ input, textarea, select { font-family: inherit; color: inherit; }
170
+ ::selection { background: var(--accent-glow); }
171
+ /* Scrollbar — slim, neumorphic, hover to highlight */
172
+ ::-webkit-scrollbar { width: 10px; height: 10px; background: transparent; }
173
+ ::-webkit-scrollbar-track { background: transparent; margin: 2px; }
174
+ ::-webkit-scrollbar-thumb {
175
+ background: color-mix(in oklch, var(--fg-muted) 28%, transparent);
176
+ border-radius: 999px;
177
+ border: 2px solid transparent;
178
+ background-clip: padding-box;
179
+ min-height: 40px;
180
+ transition: background var(--dur) var(--ease);
181
+ }
182
+ ::-webkit-scrollbar-thumb:hover {
183
+ background: color-mix(in oklch, var(--accent) 50%, var(--fg-muted));
184
+ background-clip: padding-box;
185
+ }
186
+ ::-webkit-scrollbar-thumb:active {
187
+ background: var(--accent);
188
+ background-clip: padding-box;
189
+ }
190
+ ::-webkit-scrollbar-corner { background: transparent; }
191
+ * { scrollbar-width: thin; scrollbar-color: color-mix(in oklch, var(--fg-muted) 40%, var(--bg)) var(--bg); }
192
+ *:focus { outline: none; }
193
+ :focus-visible { box-shadow: 0 0 0 3px var(--accent-glow), var(--neu-out-sm); }
194
+ /* Utility */
195
+ .row { display: flex; align-items: center; gap: var(--gap-3); }
196
+ .col { display: flex; flex-direction: column; gap: var(--gap-3); }
197
+ .muted { color: var(--fg-muted); }
198
+ .subtle { color: var(--fg-subtle); }
199
+ .small { font-size: 12px; }
200
+ .mono { font-family: var(--font-mono); }
201
+ /* lumina — 跨组件共享 keyframes */
202
+ @keyframes spin { to { transform: rotate(360deg); } }
203
+ @keyframes fadeIn { from { opacity: 0; } }
204
+ @keyframes menuIn { from { opacity: 0; transform: translateY(-4px); } }
205
+ /* Components — order mirrors the original monolithic components.css section order. */
206
+ /* ============ Button ============ */
207
+ .btn {
208
+ display: inline-flex;
209
+ align-items: center;
210
+ justify-content: center;
211
+ gap: 8px;
212
+ height: var(--ctrl-h);
213
+ padding: 0 var(--ctrl-pad-x);
214
+ border: none;
215
+ border-radius: var(--r-md);
216
+ font-size: 13px;
217
+ font-weight: 500;
218
+ font-family: inherit;
219
+ color: var(--fg);
220
+ background: var(--bg);
221
+ box-shadow: var(--neu-out-sm);
222
+ cursor: pointer;
223
+ user-select: none;
224
+ white-space: nowrap;
225
+ flex-shrink: 0;
226
+ transition: all var(--dur-fast) var(--ease);
227
+ }
228
+ .btn > svg { flex-shrink: 0; }
229
+ .btn.icon {
230
+ flex-shrink: 0;
231
+ overflow: visible;
232
+ }
233
+ .btn:hover { color: var(--accent-ink); }
234
+ .btn:active, .btn.pressed {
235
+ box-shadow: var(--neu-in-sm);
236
+ color: var(--accent-ink);
237
+ }
238
+ .btn.primary {
239
+ color: var(--accent-ink);
240
+ background:
241
+ linear-gradient(145deg,
242
+ color-mix(in oklch, var(--accent-soft) 80%, var(--shadow-light)),
243
+ color-mix(in oklch, var(--accent-soft) 92%, var(--bg)));
244
+ box-shadow:
245
+ var(--neu-out-sm),
246
+ inset 1px 1px 0 color-mix(in oklch, var(--shadow-light) 60%, transparent),
247
+ inset -1px -1px 0 color-mix(in oklch, var(--accent) 15%, transparent);
248
+ font-weight: 600;
249
+ }
250
+ .btn.primary:hover {
251
+ background:
252
+ linear-gradient(145deg,
253
+ color-mix(in oklch, var(--accent-soft) 70%, var(--shadow-light)),
254
+ color-mix(in oklch, var(--accent) 18%, var(--accent-soft)));
255
+ box-shadow:
256
+ var(--neu-out-sm),
257
+ inset 1px 1px 0 color-mix(in oklch, var(--shadow-light) 70%, transparent),
258
+ inset -1px -1px 0 color-mix(in oklch, var(--accent) 20%, transparent),
259
+ 0 0 16px -6px var(--accent-glow);
260
+ }
261
+ .btn.primary:active, .btn.primary.pressed {
262
+ box-shadow:
263
+ inset 2px 2px 4px color-mix(in oklch, var(--accent) 25%, var(--shadow-dark)),
264
+ inset -1px -1px 2px var(--shadow-light);
265
+ transform: none;
266
+ }
267
+ .btn.ghost {
268
+ background: transparent;
269
+ box-shadow: none;
270
+ color: var(--fg-muted);
271
+ }
272
+ .btn.ghost:hover { background: var(--bg); box-shadow: var(--neu-flat); color: var(--fg); }
273
+ .btn.danger { color: var(--danger); }
274
+ .btn.danger:hover { color: var(--danger); }
275
+ .btn.icon { width: var(--ctrl-h); padding: 0; }
276
+ .btn.sm { height: 30px; padding: 0 12px; font-size: 12px; border-radius: var(--r-sm); }
277
+ .btn.sm.icon { width: 30px; padding: 0; }
278
+ .btn.lg { height: 52px; padding: 0 24px; font-size: 15px; border-radius: var(--r-lg); }
279
+ .btn.lg.icon { width: 52px; padding: 0; }
280
+ .btn[disabled], .btn.disabled, .btn:disabled {
281
+ color: var(--fg-subtle);
282
+ cursor: not-allowed;
283
+ box-shadow: var(--neu-flat);
284
+ transform: none;
285
+ }
286
+ .btn[disabled]:hover, .btn:disabled:hover, .btn.disabled:hover { transform: none; color: var(--fg-subtle); background: var(--bg); }
287
+ .btn.loading { cursor: wait; }
288
+ .btn .spinner {
289
+ width: 14px; height: 14px;
290
+ border-radius: 999px;
291
+ border: 2px solid currentColor;
292
+ border-right-color: transparent;
293
+ animation: spin 0.8s linear infinite;
294
+ display: inline-block;
295
+ }
296
+ /* ============ Input / Textarea ============ */
297
+ .input-wrap {
298
+ position: relative;
299
+ display: inline-flex;
300
+ align-items: center;
301
+ width: 100%;
302
+ }
303
+ .input-wrap .lead,
304
+ .input-wrap .trail {
305
+ position: absolute;
306
+ color: var(--fg-subtle);
307
+ pointer-events: none;
308
+ }
309
+ .input-wrap .lead { left: 14px; }
310
+ .input-wrap .trail { right: 14px; pointer-events: auto; cursor: pointer; }
311
+ .input-wrap .trail:hover { color: var(--fg); }
312
+ .input,
313
+ .input-wrap > input {
314
+ width: 100%;
315
+ height: var(--ctrl-h);
316
+ padding: 0 var(--ctrl-pad-x);
317
+ border: none;
318
+ border-radius: var(--r-md);
319
+ background: var(--bg);
320
+ box-shadow: var(--neu-in-sm);
321
+ color: var(--fg);
322
+ font-size: 13px;
323
+ font-family: inherit;
324
+ outline: none;
325
+ transition: box-shadow var(--dur) var(--ease);
326
+ }
327
+ .input-wrap:has(.lead) > input,
328
+ .input-wrap.with-leading > input { padding-left: 40px; }
329
+ .input-wrap:has(.trail) > input,
330
+ .input-wrap.with-trailing > input { padding-right: 40px; }
331
+ .input:focus,
332
+ .input-wrap > input:focus { box-shadow: var(--neu-in-sm), 0 0 0 2px var(--accent-glow); }
333
+ .input::placeholder,
334
+ .input-wrap > input::placeholder { color: var(--fg-subtle); }
335
+ .input[disabled],
336
+ .input-wrap.disabled > input { opacity: 0.6; cursor: not-allowed; }
337
+ .input-wrap.invalid > input,
338
+ .input.invalid { box-shadow: var(--neu-in-sm), 0 0 0 2px color-mix(in oklch, var(--danger) 30%, transparent); }
339
+ .input-wrap.sm > input { height: 32px; padding-left: 12px; padding-right: 12px; font-size: 12px; border-radius: var(--r-sm); }
340
+ .input-wrap.lg > input { height: 48px; padding-left: 18px; padding-right: 18px; font-size: 14px; border-radius: var(--r-lg); }
341
+ .textarea {
342
+ width: 100%;
343
+ min-height: 96px;
344
+ padding: 12px 14px;
345
+ border: none;
346
+ border-radius: var(--r-md);
347
+ background: var(--bg);
348
+ box-shadow: var(--neu-in-sm);
349
+ color: var(--fg);
350
+ font-size: 13px;
351
+ font-family: inherit;
352
+ line-height: 1.55;
353
+ resize: vertical;
354
+ outline: none;
355
+ transition: box-shadow var(--dur) var(--ease);
356
+ }
357
+ .textarea:focus { box-shadow: var(--neu-in-sm), 0 0 0 2px var(--accent-glow); }
358
+ .textarea.invalid { box-shadow: var(--neu-in-sm), 0 0 0 2px color-mix(in oklch, var(--danger) 30%, transparent); }
359
+ .textarea::placeholder { color: var(--fg-subtle); }
360
+ /* ============ Switch ============ */
361
+ .switch {
362
+ --w: 46px;
363
+ --h: 26px;
364
+ display: inline-flex;
365
+ align-items: center;
366
+ gap: 10px;
367
+ font-size: 13px;
368
+ color: var(--fg);
369
+ cursor: pointer;
370
+ user-select: none;
371
+ }
372
+ .switch.disabled { opacity: 0.5; cursor: not-allowed; }
373
+ .switch-track {
374
+ position: relative;
375
+ width: var(--w);
376
+ height: var(--h);
377
+ border: none;
378
+ padding: 0;
379
+ border-radius: 999px;
380
+ background: var(--bg);
381
+ box-shadow: var(--neu-in-sm);
382
+ cursor: inherit;
383
+ flex-shrink: 0;
384
+ transition: all var(--dur) var(--ease);
385
+ }
386
+ .switch.sm { --w: 36px; --h: 20px; }
387
+ .switch.lg { --w: 58px; --h: 32px; }
388
+ .switch-thumb {
389
+ position: absolute;
390
+ top: 3px;
391
+ left: 3px;
392
+ width: calc(var(--h) - 6px);
393
+ height: calc(var(--h) - 6px);
394
+ border-radius: 999px;
395
+ background: var(--bg-raised);
396
+ box-shadow: var(--neu-out-sm);
397
+ transition: all var(--dur) var(--ease);
398
+ }
399
+ .switch.on .switch-thumb {
400
+ transform: translateX(calc(var(--w) - var(--h)));
401
+ background: var(--accent);
402
+ box-shadow: 0 2px 8px var(--accent-glow), 0 0 0 1px color-mix(in oklch, var(--accent) 40%, transparent);
403
+ }
404
+ /* ============ Checkbox & Radio ============ */
405
+ .checkbox, .radio {
406
+ display: inline-flex;
407
+ align-items: center;
408
+ gap: 10px;
409
+ cursor: pointer;
410
+ user-select: none;
411
+ font-size: 13px;
412
+ color: var(--fg);
413
+ }
414
+ .checkbox.disabled, .radio.disabled { opacity: 0.5; cursor: not-allowed; }
415
+ .checkbox-box {
416
+ width: 20px; height: 20px;
417
+ border: none;
418
+ padding: 0;
419
+ border-radius: 7px;
420
+ background: var(--bg);
421
+ box-shadow: var(--neu-in-sm);
422
+ display: grid;
423
+ place-items: center;
424
+ flex-shrink: 0;
425
+ cursor: inherit;
426
+ color: white;
427
+ transition: all var(--dur) var(--ease);
428
+ }
429
+ .checkbox-box svg { opacity: 0; transform: scale(0.6); transition: all var(--dur) var(--ease); }
430
+ .checkbox.checked .checkbox-box {
431
+ background: var(--accent);
432
+ box-shadow: var(--neu-out-sm), 0 2px 8px var(--accent-glow);
433
+ }
434
+ .checkbox.checked .checkbox-box svg { opacity: 1; transform: scale(1); }
435
+ .checkbox.indeterminate .checkbox-box {
436
+ background: var(--accent);
437
+ box-shadow: var(--neu-out-sm), 0 2px 8px var(--accent-glow);
438
+ }
439
+ .checkbox.indeterminate .checkbox-box::after {
440
+ content: "";
441
+ width: 10px; height: 2px;
442
+ background: white;
443
+ border-radius: 2px;
444
+ }
445
+ .checkbox.indeterminate .checkbox-box svg { display: none; }
446
+ .radio-dot {
447
+ width: 20px; height: 20px;
448
+ border: none;
449
+ padding: 0;
450
+ border-radius: 999px;
451
+ background: var(--bg);
452
+ box-shadow: var(--neu-in-sm);
453
+ cursor: inherit;
454
+ position: relative;
455
+ flex-shrink: 0;
456
+ transition: all var(--dur) var(--ease);
457
+ }
458
+ .radio.checked .radio-dot {
459
+ background: var(--accent);
460
+ box-shadow: var(--neu-out-sm), 0 2px 8px var(--accent-glow);
461
+ }
462
+ .radio.checked .radio-dot::after {
463
+ content: "";
464
+ position: absolute;
465
+ top: 50%; left: 50%;
466
+ transform: translate(-50%, -50%);
467
+ width: 8px; height: 8px;
468
+ border-radius: 999px;
469
+ background: white;
470
+ }
471
+ .radio-group { display: flex; gap: 14px; }
472
+ .radio-group.vertical { flex-direction: column; gap: 10px; }
473
+ .radio-group.horizontal { flex-direction: row; flex-wrap: wrap; }
474
+ /* ============ Slider ============ */
475
+ .slider {
476
+ position: relative;
477
+ height: 36px;
478
+ width: 100%;
479
+ display: flex;
480
+ align-items: center;
481
+ cursor: pointer;
482
+ }
483
+ .slider.disabled { opacity: 0.5; cursor: not-allowed; }
484
+ .slider-track {
485
+ position: relative;
486
+ width: 100%;
487
+ height: 10px;
488
+ border-radius: 999px;
489
+ background: var(--bg);
490
+ box-shadow: var(--neu-in-sm);
491
+ overflow: hidden;
492
+ }
493
+ .slider-fill {
494
+ position: absolute;
495
+ top: 0; left: 0; bottom: 0;
496
+ background: linear-gradient(90deg, color-mix(in oklch, var(--accent) 70%, white), var(--accent));
497
+ box-shadow: 0 0 12px var(--accent-glow);
498
+ border-radius: 999px;
499
+ transition: width var(--dur-fast) var(--ease);
500
+ }
501
+ .slider-thumb {
502
+ position: absolute;
503
+ top: 50%;
504
+ width: 22px; height: 22px;
505
+ border-radius: 999px;
506
+ background: var(--bg-raised);
507
+ box-shadow: var(--neu-out-sm);
508
+ transform: translate(-50%, -50%);
509
+ transition: all var(--dur-fast) var(--ease);
510
+ display: grid; place-items: center;
511
+ }
512
+ .slider-thumb::after {
513
+ content: "";
514
+ width: 6px; height: 6px;
515
+ border-radius: 999px;
516
+ background: var(--accent);
517
+ }
518
+ .slider:hover .slider-thumb { transform: translate(-50%, -50%) scale(1.08); }
519
+ .slider input[type="range"] {
520
+ position: absolute;
521
+ inset: 0;
522
+ width: 100%; height: 100%;
523
+ opacity: 0;
524
+ cursor: inherit;
525
+ }
526
+ .slider-value { font-family: var(--font-mono); font-size: 12px; color: var(--accent-ink); margin-left: 10px; }
527
+ .slider.success .slider-fill { background: linear-gradient(90deg, color-mix(in oklch, var(--success) 70%, white), var(--success)); box-shadow: 0 0 10px color-mix(in oklch, var(--success) 35%, transparent); }
528
+ .slider.success .slider-thumb::after { background: var(--success); }
529
+ .slider.warning .slider-fill { background: linear-gradient(90deg, color-mix(in oklch, var(--warning) 70%, white), var(--warning)); box-shadow: 0 0 10px color-mix(in oklch, var(--warning) 35%, transparent); }
530
+ .slider.warning .slider-thumb::after { background: var(--warning); }
531
+ .slider.danger .slider-fill { background: linear-gradient(90deg, color-mix(in oklch, var(--danger) 70%, white), var(--danger)); box-shadow: 0 0 10px color-mix(in oklch, var(--danger) 35%, transparent); }
532
+ .slider.danger .slider-thumb::after { background: var(--danger); }
533
+ /* ============ Progress ============ */
534
+ .progress {
535
+ width: 100%;
536
+ display: flex;
537
+ flex-direction: column;
538
+ gap: 6px;
539
+ }
540
+ .progress-label {
541
+ display: flex;
542
+ justify-content: space-between;
543
+ font-size: 12px;
544
+ color: var(--fg-muted);
545
+ }
546
+ .progress-label .v { font-family: var(--font-mono); }
547
+ .progress-track {
548
+ width: 100%;
549
+ height: 10px;
550
+ border-radius: 999px;
551
+ background: var(--bg);
552
+ box-shadow: var(--neu-in-sm);
553
+ overflow: hidden;
554
+ position: relative;
555
+ }
556
+ .progress.sm .progress-track { height: 6px; }
557
+ .progress.lg .progress-track { height: 14px; }
558
+ .progress-bar {
559
+ height: 100%;
560
+ background: linear-gradient(90deg, color-mix(in oklch, var(--accent) 70%, white), var(--accent));
561
+ border-radius: 999px;
562
+ box-shadow: 0 0 12px var(--accent-glow);
563
+ transition: width var(--dur-slow) var(--ease);
564
+ }
565
+ .progress.success .progress-bar { background: linear-gradient(90deg, color-mix(in oklch, var(--success) 70%, white), var(--success)); box-shadow: 0 0 10px color-mix(in oklch, var(--success) 35%, transparent); }
566
+ .progress.warning .progress-bar { background: linear-gradient(90deg, color-mix(in oklch, var(--warning) 70%, white), var(--warning)); box-shadow: 0 0 10px color-mix(in oklch, var(--warning) 35%, transparent); }
567
+ .progress.danger .progress-bar { background: linear-gradient(90deg, color-mix(in oklch, var(--danger) 70%, white), var(--danger)); box-shadow: 0 0 10px color-mix(in oklch, var(--danger) 35%, transparent); }
568
+ .ring {
569
+ --size: 72px;
570
+ --val: 50;
571
+ width: var(--size); height: var(--size);
572
+ border-radius: 999px;
573
+ background: conic-gradient(var(--accent) calc(var(--val) * 1%), var(--bg-sunken) 0);
574
+ display: grid; place-items: center;
575
+ position: relative;
576
+ box-shadow: var(--neu-out-sm);
577
+ }
578
+ .ring.success { background: conic-gradient(var(--success) calc(var(--val) * 1%), var(--bg-sunken) 0); }
579
+ .ring.warning { background: conic-gradient(var(--warning) calc(var(--val) * 1%), var(--bg-sunken) 0); }
580
+ .ring.danger { background: conic-gradient(var(--danger) calc(var(--val) * 1%), var(--bg-sunken) 0); }
581
+ .ring::before {
582
+ content: "";
583
+ position: absolute;
584
+ inset: 8px;
585
+ border-radius: 999px;
586
+ background: var(--bg);
587
+ box-shadow: var(--neu-in-sm);
588
+ }
589
+ .ring-label {
590
+ position: relative;
591
+ font-size: 13px;
592
+ font-weight: 600;
593
+ color: var(--accent-ink);
594
+ }
595
+ /* ============ Tag & Badge ============ */
596
+ .tag {
597
+ display: inline-flex;
598
+ align-items: center;
599
+ gap: 6px;
600
+ height: 24px;
601
+ padding: 0 10px;
602
+ border-radius: var(--r-pill);
603
+ font-size: 11px;
604
+ font-weight: 500;
605
+ background: var(--bg);
606
+ box-shadow: var(--neu-flat);
607
+ color: var(--fg-muted);
608
+ }
609
+ .tag.accent { color: var(--accent-ink); }
610
+ .tag.info { color: var(--info); }
611
+ .tag.success { color: var(--success); }
612
+ .tag.warning { color: var(--warning); }
613
+ .tag.danger { color: var(--danger); }
614
+ .tag.solid { background: var(--accent); color: white; box-shadow: 0 2px 6px var(--accent-glow); }
615
+ .tag.solid.info { background: var(--info); color: white; box-shadow: 0 2px 6px color-mix(in oklch, var(--info) 35%, transparent); }
616
+ .tag.solid.success { background: var(--success); color: white; box-shadow: 0 2px 6px color-mix(in oklch, var(--success) 35%, transparent); }
617
+ .tag.solid.warning { background: var(--warning); color: white; box-shadow: 0 2px 6px color-mix(in oklch, var(--warning) 35%, transparent); }
618
+ .tag.solid.danger { background: var(--danger); color: white; box-shadow: 0 2px 6px color-mix(in oklch, var(--danger) 35%, transparent); }
619
+ .tag .dot { width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
620
+ .tag .x { cursor: pointer; color: var(--fg-subtle); margin-left: 2px; display: inline-flex; }
621
+ .tag .x:hover { color: var(--fg); }
622
+ .badge {
623
+ display: inline-flex;
624
+ align-items: center; justify-content: center;
625
+ min-width: 18px; height: 18px;
626
+ padding: 0 6px;
627
+ border-radius: 999px;
628
+ font-size: 10px;
629
+ font-weight: 700;
630
+ background: var(--danger);
631
+ color: white;
632
+ box-shadow: 0 1px 4px rgba(0,0,0,0.15);
633
+ font-variant-numeric: tabular-nums;
634
+ }
635
+ .badge.dot { min-width: 10px; height: 10px; padding: 0; }
636
+ .badge.accent { background: var(--accent); box-shadow: 0 1px 4px var(--accent-glow); }
637
+ .badge.info { background: var(--info); box-shadow: 0 1px 4px color-mix(in oklch, var(--info) 35%, transparent); }
638
+ .badge.success { background: var(--success); box-shadow: 0 1px 4px color-mix(in oklch, var(--success) 35%, transparent); }
639
+ .badge.warning { background: var(--warning); box-shadow: 0 1px 4px color-mix(in oklch, var(--warning) 35%, transparent); }
640
+ .badge.neutral { background: var(--fg-muted); box-shadow: 0 1px 4px rgba(0,0,0,0.15); }
641
+ .badge-wrap { position: relative; display: inline-block; }
642
+ .badge-wrap > .badge { position: absolute; top: -4px; right: -4px; }
643
+ /* ============ Avatar ============ */
644
+ .avatar {
645
+ --size: 40px;
646
+ width: var(--size); height: var(--size);
647
+ border-radius: 999px;
648
+ background: var(--bg);
649
+ box-shadow: var(--neu-out-sm);
650
+ display: grid; place-items: center;
651
+ overflow: hidden;
652
+ color: var(--accent-ink);
653
+ font-weight: 600;
654
+ font-size: calc(var(--size) / 2.6);
655
+ position: relative;
656
+ flex-shrink: 0;
657
+ }
658
+ .avatar.sm { --size: 28px; }
659
+ .avatar.lg { --size: 56px; }
660
+ .avatar.xl { --size: 80px; }
661
+ .avatar img { width: 100%; height: 100%; object-fit: cover; }
662
+ .avatar-status {
663
+ position: absolute;
664
+ bottom: 0; right: 0;
665
+ width: 25%; height: 25%;
666
+ min-width: 8px; min-height: 8px;
667
+ border-radius: 999px;
668
+ background: var(--success);
669
+ box-shadow: 0 0 0 2px var(--bg);
670
+ }
671
+ .avatar-status.online { background: var(--success); }
672
+ .avatar-status.busy { background: var(--danger); }
673
+ .avatar-status.away { background: var(--warning); }
674
+ .avatar-status.offline { background: var(--fg-subtle); }
675
+ .avatar-group { display: inline-flex; }
676
+ .avatar-group .avatar { border: 3px solid var(--bg); box-sizing: content-box; }
677
+ .avatar-group .avatar + .avatar { margin-left: -12px; }
678
+ /* ============ Divider ============ */
679
+ .divider {
680
+ height: 1px;
681
+ background: var(--divider);
682
+ margin: var(--gap-4) 0;
683
+ border-radius: 999px;
684
+ box-shadow: 0 1px 0 var(--shadow-light);
685
+ }
686
+ .divider.vertical {
687
+ width: 1px;
688
+ height: 24px;
689
+ margin: 0 var(--gap-3);
690
+ display: inline-block;
691
+ }
692
+ .divider.sunken {
693
+ background: transparent;
694
+ height: 2px;
695
+ box-shadow: var(--neu-in-sm);
696
+ }
697
+ .divider.sunken.vertical {
698
+ width: 2px;
699
+ height: 24px;
700
+ }
701
+ .divider.sunken:has(.divider-label) { background: transparent; box-shadow: none; }
702
+ .divider.sunken:has(.divider-label)::before,
703
+ .divider.sunken:has(.divider-label)::after { height: 2px; background: transparent; box-shadow: var(--neu-in-sm); }
704
+ .divider-label {
705
+ display: flex; align-items: center; gap: 12px;
706
+ height: auto; background: transparent; box-shadow: none;
707
+ font-size: 11px; color: var(--fg-subtle);
708
+ text-transform: uppercase; letter-spacing: 0.1em;
709
+ }
710
+ .divider:has(.divider-label) {
711
+ background: transparent;
712
+ box-shadow: none;
713
+ height: auto;
714
+ display: flex;
715
+ align-items: center;
716
+ gap: 12px;
717
+ }
718
+ .divider:has(.divider-label)::before,
719
+ .divider:has(.divider-label)::after {
720
+ content: "";
721
+ flex: 1;
722
+ height: 1px;
723
+ background: var(--divider);
724
+ border-radius: 999px;
725
+ box-shadow: 0 1px 0 var(--shadow-light);
726
+ }
727
+ /* ============ Card & Panel ============ */
728
+ .card {
729
+ background: var(--bg);
730
+ border-radius: var(--r-lg);
731
+ box-shadow: var(--neu-out);
732
+ padding: var(--gap-5);
733
+ }
734
+ .card.flat { box-shadow: var(--neu-flat); }
735
+ .card.sunken { box-shadow: var(--neu-in); }
736
+ .card.pad-none { padding: 0; }
737
+ .card.pad-sm { padding: var(--gap-3); }
738
+ .card.pad-lg { padding: var(--gap-6); }
739
+ .panel {
740
+ background: var(--bg);
741
+ border-radius: var(--r-lg);
742
+ box-shadow: var(--neu-out);
743
+ padding: var(--gap-5);
744
+ }
745
+ .panel-head {
746
+ display: flex; align-items: flex-start; justify-content: space-between;
747
+ gap: var(--gap-3); margin-bottom: var(--gap-4);
748
+ }
749
+ .panel-titles { display: flex; flex-direction: column; gap: 2px; }
750
+ .panel-title { font-size: 15px; font-weight: 600; }
751
+ .panel-desc { font-size: 12px; color: var(--fg-muted); }
752
+ .panel-actions { display: flex; gap: 6px; }
753
+ .panel-body { font-size: 13px; }
754
+ /* ============ Tabs ============ */
755
+ .tabs { display: flex; flex-direction: column; gap: var(--gap-3); }
756
+ .tabs-nav {
757
+ display: inline-flex;
758
+ padding: 5px;
759
+ border-radius: var(--r-md);
760
+ background: var(--bg);
761
+ box-shadow: var(--neu-in-sm);
762
+ gap: 2px;
763
+ align-self: flex-start;
764
+ }
765
+ .tabs-nav .tab {
766
+ padding: 8px 16px;
767
+ border: none;
768
+ background: transparent;
769
+ border-radius: calc(var(--r-md) - 5px);
770
+ font-size: 12px;
771
+ font-weight: 500;
772
+ font-family: inherit;
773
+ color: var(--fg-muted);
774
+ cursor: pointer;
775
+ display: inline-flex;
776
+ align-items: center;
777
+ gap: 6px;
778
+ transition: all var(--dur-fast) var(--ease);
779
+ }
780
+ .tabs-nav .tab:hover { color: var(--fg); }
781
+ .tabs-nav .tab.active {
782
+ color: var(--accent-ink);
783
+ background: var(--bg);
784
+ box-shadow: var(--neu-out-sm);
785
+ font-weight: 600;
786
+ }
787
+ .tabs-nav .tab[disabled] { opacity: 0.4; cursor: not-allowed; }
788
+ .tabs.line .tabs-nav,
789
+ .tabs.underline .tabs-nav {
790
+ padding: 0;
791
+ background: transparent;
792
+ box-shadow: none;
793
+ border-radius: 0;
794
+ border-bottom: 1px solid var(--divider);
795
+ align-self: stretch;
796
+ }
797
+ .tabs.line .tabs-nav .tab,
798
+ .tabs.underline .tabs-nav .tab {
799
+ padding: 10px 4px;
800
+ margin-right: 22px;
801
+ border-radius: 0;
802
+ position: relative;
803
+ }
804
+ .tabs.line .tabs-nav .tab.active,
805
+ .tabs.underline .tabs-nav .tab.active { background: transparent; box-shadow: none; }
806
+ .tabs.line .tabs-nav .tab.active::after,
807
+ .tabs.underline .tabs-nav .tab.active::after {
808
+ content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
809
+ background: var(--accent); border-radius: 999px;
810
+ box-shadow: 0 0 8px var(--accent-glow);
811
+ }
812
+ .tabs-content { padding: var(--gap-2) 0; }
813
+ /* Segmented (owned by Tabs.tsx — Segmented is co-exported) */
814
+ .segmented {
815
+ display: inline-flex;
816
+ padding: 4px;
817
+ border-radius: var(--r-md);
818
+ background: var(--bg);
819
+ box-shadow: var(--neu-in-sm);
820
+ gap: 2px;
821
+ }
822
+ .segmented .seg {
823
+ padding: 6px 14px;
824
+ height: 32px;
825
+ display: inline-flex;
826
+ align-items: center;
827
+ gap: 6px;
828
+ border: none;
829
+ background: transparent;
830
+ border-radius: calc(var(--r-md) - 4px);
831
+ font-size: 12px;
832
+ font-family: inherit;
833
+ color: var(--fg-muted);
834
+ cursor: pointer;
835
+ transition: all var(--dur-fast) var(--ease);
836
+ }
837
+ .segmented .seg:hover { color: var(--fg); }
838
+ .segmented .seg.active {
839
+ color: var(--accent-ink);
840
+ background: var(--bg);
841
+ box-shadow: var(--neu-out-sm);
842
+ font-weight: 600;
843
+ }
844
+ .segmented.sm .seg { height: 26px; padding: 4px 10px; font-size: 11px; }
845
+ .segmented.lg .seg { height: 38px; padding: 8px 18px; font-size: 13px; }
846
+ /* ============ Accordion ============ */
847
+ .accordion { display: flex; flex-direction: column; gap: 10px; }
848
+ .accordion-item {
849
+ background: var(--bg);
850
+ border-radius: var(--r-md);
851
+ box-shadow: var(--neu-out-sm);
852
+ overflow: hidden;
853
+ }
854
+ .accordion-head {
855
+ width: 100%;
856
+ border: none;
857
+ background: transparent;
858
+ padding: 14px 18px;
859
+ display: flex;
860
+ align-items: center;
861
+ justify-content: space-between;
862
+ cursor: pointer;
863
+ font-size: 13px;
864
+ font-weight: 500;
865
+ font-family: inherit;
866
+ color: var(--fg);
867
+ text-align: left;
868
+ }
869
+ .accordion-body {
870
+ max-height: 0;
871
+ overflow: hidden;
872
+ transition: max-height var(--dur) var(--ease);
873
+ color: var(--fg-muted);
874
+ font-size: 13px;
875
+ }
876
+ .accordion-item.open .accordion-body { max-height: 320px; }
877
+ .accordion-body-inner { padding: 0 18px 16px; }
878
+ .accordion-chev {
879
+ transition: transform var(--dur) var(--ease);
880
+ color: var(--fg-subtle);
881
+ display: inline-flex;
882
+ }
883
+ .accordion-item.open .accordion-chev { transform: rotate(180deg); color: var(--accent); }
884
+ /* ============ Select ============ */
885
+ .select {
886
+ position: relative;
887
+ display: inline-block;
888
+ min-width: 180px;
889
+ width: 100%;
890
+ outline: none;
891
+ }
892
+ .select.disabled { opacity: 0.55; pointer-events: none; }
893
+ .select-trigger {
894
+ width: 100%;
895
+ height: var(--ctrl-h);
896
+ padding: 0 36px 0 var(--ctrl-pad-x);
897
+ border: none;
898
+ border-radius: var(--r-md);
899
+ background: var(--bg);
900
+ box-shadow: var(--neu-out-sm);
901
+ display: inline-flex;
902
+ align-items: center;
903
+ gap: 8px;
904
+ font-size: 13px;
905
+ font-family: inherit;
906
+ color: var(--fg);
907
+ cursor: pointer;
908
+ transition: all var(--dur-fast) var(--ease);
909
+ position: relative;
910
+ text-align: left;
911
+ }
912
+ .select-value {
913
+ display: inline-flex;
914
+ align-items: center;
915
+ gap: 8px;
916
+ flex: 1;
917
+ min-width: 0;
918
+ }
919
+ .select-value > span {
920
+ white-space: nowrap;
921
+ overflow: hidden;
922
+ text-overflow: ellipsis;
923
+ }
924
+ .select.invalid .select-trigger {
925
+ box-shadow: var(--neu-out-sm), 0 0 0 2px color-mix(in oklch, var(--danger) 30%, transparent);
926
+ }
927
+ .select.invalid.open .select-trigger {
928
+ box-shadow: var(--neu-in-sm), 0 0 0 2px color-mix(in oklch, var(--danger) 30%, transparent);
929
+ }
930
+ .select.sm .select-trigger { height: 30px; padding: 0 32px 0 12px; font-size: 12px; border-radius: var(--r-sm); }
931
+ .select.lg .select-trigger { height: 48px; padding: 0 36px 0 18px; font-size: 14px; border-radius: var(--r-lg); }
932
+ .select-trigger:hover { color: var(--accent-ink); }
933
+ .select.open .select-trigger { box-shadow: var(--neu-in-sm); color: var(--accent-ink); }
934
+ .select-trigger .placeholder { color: var(--fg-subtle); }
935
+ .select-caret {
936
+ position: absolute;
937
+ right: 12px; top: 50%;
938
+ transform: translateY(-50%);
939
+ color: var(--fg-subtle);
940
+ transition: transform var(--dur) var(--ease);
941
+ flex-shrink: 0;
942
+ }
943
+ .select.open .select-caret { transform: translateY(-50%) rotate(180deg); color: var(--accent); }
944
+ /* Multi-select trigger: variable height, tags inside, vertically centered */
945
+ .select.multi .select-trigger {
946
+ height: auto;
947
+ min-height: var(--ctrl-h);
948
+ padding: 4px 56px 4px 8px;
949
+ align-items: center;
950
+ flex-wrap: wrap;
951
+ }
952
+ .select.multi .select-tags {
953
+ display: inline-flex;
954
+ flex-wrap: wrap;
955
+ gap: 4px;
956
+ flex: 1;
957
+ min-width: 0;
958
+ align-items: center;
959
+ }
960
+ .select.multi .select-trigger > .placeholder {
961
+ padding-left: 6px;
962
+ line-height: calc(var(--ctrl-h) - 8px);
963
+ }
964
+ .select.multi .select-tags > .tag {
965
+ max-width: 160px;
966
+ }
967
+ .select.multi .select-tags > .tag > span:not(.dot):not(.x) {
968
+ white-space: nowrap;
969
+ overflow: hidden;
970
+ text-overflow: ellipsis;
971
+ }
972
+ .select-clear {
973
+ position: absolute;
974
+ right: 30px;
975
+ top: 50%;
976
+ transform: translateY(-50%);
977
+ width: 20px;
978
+ height: 20px;
979
+ border-radius: 999px;
980
+ background: var(--bg);
981
+ box-shadow: var(--neu-out-sm);
982
+ display: inline-grid;
983
+ place-items: center;
984
+ cursor: pointer;
985
+ color: var(--fg-subtle);
986
+ opacity: 0;
987
+ transition: all var(--dur-fast) var(--ease);
988
+ z-index: 1;
989
+ }
990
+ .select:hover .select-clear { opacity: 1; }
991
+ .select-clear:hover { color: var(--accent-ink); box-shadow: var(--neu-in-sm); }
992
+ /* Multi-select menu: leading checkbox per item */
993
+ .menu-check {
994
+ width: 16px;
995
+ height: 16px;
996
+ border-radius: 5px;
997
+ background: var(--bg);
998
+ box-shadow: var(--neu-in-sm);
999
+ display: inline-grid;
1000
+ place-items: center;
1001
+ flex-shrink: 0;
1002
+ color: white;
1003
+ transition: all var(--dur-fast) var(--ease);
1004
+ }
1005
+ .menu-check.on {
1006
+ background: var(--accent);
1007
+ box-shadow: var(--neu-out-sm), 0 1px 4px var(--accent-glow);
1008
+ }
1009
+ /* Menu search — flush with menu, single subtle separator (no nested frame) */
1010
+ .menu-search {
1011
+ display: flex;
1012
+ align-items: center;
1013
+ gap: 8px;
1014
+ height: 32px;
1015
+ padding: 0 6px;
1016
+ margin: -2px -2px 4px;
1017
+ border-bottom: 1px solid var(--divider);
1018
+ color: var(--fg-subtle);
1019
+ transition: color var(--dur) var(--ease);
1020
+ }
1021
+ .menu-search:focus-within { color: var(--accent); }
1022
+ .menu-search input {
1023
+ flex: 1;
1024
+ min-width: 0;
1025
+ border: none;
1026
+ outline: none;
1027
+ background: transparent;
1028
+ color: var(--fg);
1029
+ font-size: 13px;
1030
+ font-family: inherit;
1031
+ height: 100%;
1032
+ padding: 0;
1033
+ }
1034
+ .menu-search input::placeholder { color: var(--fg-subtle); }
1035
+ .menu-search input:focus,
1036
+ .menu-search input:focus-visible { box-shadow: none; }
1037
+ /* Menu state (loading / empty) */
1038
+ .menu-state {
1039
+ display: flex;
1040
+ flex-direction: column;
1041
+ align-items: center;
1042
+ justify-content: center;
1043
+ gap: 10px;
1044
+ padding: 26px 12px;
1045
+ font-size: 12px;
1046
+ color: var(--fg-muted);
1047
+ }
1048
+ .menu-state .menu-state-ico {
1049
+ width: 40px;
1050
+ height: 40px;
1051
+ border-radius: var(--r-md);
1052
+ background: var(--bg);
1053
+ box-shadow: var(--neu-in-sm);
1054
+ display: grid;
1055
+ place-items: center;
1056
+ color: var(--fg-subtle);
1057
+ }
1058
+ .menu-state .menu-state-ico .spinner {
1059
+ width: 16px;
1060
+ height: 16px;
1061
+ border-color: var(--accent);
1062
+ border-right-color: transparent;
1063
+ }
1064
+ /* Option body — supports description line under label */
1065
+ .menu-item-body {
1066
+ flex: 1;
1067
+ display: flex;
1068
+ flex-direction: column;
1069
+ gap: 2px;
1070
+ min-width: 0;
1071
+ text-align: left;
1072
+ }
1073
+ .menu-item-label {
1074
+ white-space: nowrap;
1075
+ overflow: hidden;
1076
+ text-overflow: ellipsis;
1077
+ }
1078
+ .menu-item-desc {
1079
+ font-size: 11px;
1080
+ color: var(--fg-subtle);
1081
+ white-space: nowrap;
1082
+ overflow: hidden;
1083
+ text-overflow: ellipsis;
1084
+ }
1085
+ .menu-item.active .menu-item-desc { color: color-mix(in oklch, var(--accent-ink) 70%, var(--fg-subtle)); }
1086
+ /* Keyboard / hover highlight — soft raised pill */
1087
+ .menu-item.highlight:not([disabled]) {
1088
+ background: var(--bg);
1089
+ box-shadow: var(--neu-out-sm);
1090
+ color: var(--accent-ink);
1091
+ }
1092
+ .menu-item[disabled] {
1093
+ opacity: 0.45;
1094
+ cursor: not-allowed;
1095
+ }
1096
+ .menu {
1097
+ position: absolute;
1098
+ top: calc(100% + 8px);
1099
+ left: 0; right: 0;
1100
+ background: var(--bg);
1101
+ border-radius: var(--r-md);
1102
+ box-shadow: var(--neu-out-lg);
1103
+ padding: 6px;
1104
+ min-width: 180px;
1105
+ z-index: 50;
1106
+ animation: menuIn var(--dur) var(--ease);
1107
+ max-height: 260px;
1108
+ overflow-y: auto;
1109
+ }
1110
+ .menu-item {
1111
+ padding: 9px 12px;
1112
+ border-radius: var(--r-sm);
1113
+ font-size: 13px;
1114
+ cursor: pointer;
1115
+ color: var(--fg);
1116
+ display: flex;
1117
+ align-items: center;
1118
+ gap: 10px;
1119
+ transition: all var(--dur-fast) var(--ease);
1120
+ border: none;
1121
+ background: transparent;
1122
+ font-family: inherit;
1123
+ width: 100%;
1124
+ text-align: left;
1125
+ }
1126
+ .menu-item:hover { background: var(--bg); box-shadow: var(--neu-flat); color: var(--accent-ink); }
1127
+ .menu-item.active { color: var(--accent-ink); font-weight: 500; }
1128
+ .menu-item .tick { margin-left: auto; color: var(--accent); opacity: 0; }
1129
+ .menu-item.active .tick { opacity: 1; }
1130
+ .menu-item.danger { color: var(--danger); }
1131
+ .menu-separator { height: 1px; background: var(--divider); margin: 6px 4px; }
1132
+ .menu-group-label {
1133
+ font-size: 10px;
1134
+ font-weight: 600;
1135
+ text-transform: uppercase;
1136
+ letter-spacing: 0.08em;
1137
+ color: var(--fg-subtle);
1138
+ padding: 8px 12px 4px;
1139
+ }
1140
+ /* ============ Modal ============ */
1141
+ .modal-overlay {
1142
+ position: fixed;
1143
+ inset: 0;
1144
+ background: color-mix(in oklch, var(--bg-sunken) 60%, transparent);
1145
+ backdrop-filter: blur(8px);
1146
+ display: grid;
1147
+ place-items: center;
1148
+ z-index: 200;
1149
+ animation: fadeIn var(--dur) var(--ease);
1150
+ }
1151
+ .modal {
1152
+ background: var(--bg);
1153
+ border-radius: var(--r-xl);
1154
+ box-shadow: var(--neu-out-lg), 0 24px 60px -20px rgba(40,55,80,0.3);
1155
+ padding: var(--gap-6);
1156
+ width: min(480px, 92vw);
1157
+ animation: modalIn var(--dur-slow) var(--ease);
1158
+ max-height: 86vh;
1159
+ display: flex;
1160
+ flex-direction: column;
1161
+ }
1162
+ @keyframes modalIn { from { opacity: 0; transform: translateY(8px) scale(0.97); } }
1163
+ .modal-head {
1164
+ display: flex; align-items: flex-start; justify-content: space-between;
1165
+ gap: var(--gap-3); margin-bottom: var(--gap-3);
1166
+ }
1167
+ .modal-titles { display: flex; flex-direction: column; gap: 4px; }
1168
+ .modal-title { font-size: 17px; font-weight: 600; }
1169
+ .modal-desc { font-size: 13px; color: var(--fg-muted); }
1170
+ .modal-body { padding: var(--gap-3) 0; color: var(--fg-muted); font-size: 13px; line-height: 1.6; flex: 1; overflow-y: auto; }
1171
+ .modal-foot {
1172
+ display: flex; gap: 10px; justify-content: flex-end;
1173
+ margin-top: var(--gap-4);
1174
+ }
1175
+ .modal-close {
1176
+ width: 28px; height: 28px;
1177
+ border: none; background: transparent;
1178
+ border-radius: var(--r-sm);
1179
+ display: grid; place-items: center;
1180
+ color: var(--fg-subtle);
1181
+ cursor: pointer;
1182
+ transition: all var(--dur-fast) var(--ease);
1183
+ }
1184
+ .modal-close:hover { color: var(--fg); background: var(--bg); box-shadow: var(--neu-flat); }
1185
+ /* ============ Drawer (co-exported from Modal.tsx) ============ */
1186
+ .drawer-overlay {
1187
+ position: fixed; inset: 0;
1188
+ background: color-mix(in oklch, var(--bg-sunken) 50%, transparent);
1189
+ backdrop-filter: blur(4px);
1190
+ z-index: 150;
1191
+ animation: fadeIn var(--dur) var(--ease);
1192
+ }
1193
+ .drawer {
1194
+ position: fixed;
1195
+ background: var(--bg);
1196
+ padding: var(--gap-5);
1197
+ z-index: 151;
1198
+ overflow-y: auto;
1199
+ display: flex;
1200
+ flex-direction: column;
1201
+ }
1202
+ .drawer.right { top: 0; right: 0; bottom: 0; width: min(420px, 92vw); animation: drawerInRight var(--dur-slow) var(--ease); box-shadow: -24px 0 60px -20px rgba(40,55,80,0.25); }
1203
+ .drawer.left { top: 0; left: 0; bottom: 0; width: min(420px, 92vw); animation: drawerInLeft var(--dur-slow) var(--ease); box-shadow: 24px 0 60px -20px rgba(40,55,80,0.25); }
1204
+ .drawer.top { top: 0; left: 0; right: 0; height: min(320px, 80vh); animation: drawerInTop var(--dur-slow) var(--ease); box-shadow: 0 24px 60px -20px rgba(40,55,80,0.25); }
1205
+ .drawer.bottom { bottom: 0; left: 0; right: 0; height: min(320px, 80vh); animation: drawerInBottom var(--dur-slow) var(--ease); box-shadow: 0 -24px 60px -20px rgba(40,55,80,0.25); }
1206
+ @keyframes drawerInRight { from { transform: translateX( 20px); opacity: 0; } }
1207
+ @keyframes drawerInLeft { from { transform: translateX(-20px); opacity: 0; } }
1208
+ @keyframes drawerInTop { from { transform: translateY(-20px); opacity: 0; } }
1209
+ @keyframes drawerInBottom { from { transform: translateY( 20px); opacity: 0; } }
1210
+ .drawer-head {
1211
+ display: flex; align-items: center; justify-content: space-between;
1212
+ margin-bottom: var(--gap-4);
1213
+ padding-bottom: var(--gap-4);
1214
+ border-bottom: 1px solid var(--divider);
1215
+ }
1216
+ .drawer-title { font-size: 16px; font-weight: 600; }
1217
+ .drawer-body { flex: 1; }
1218
+ /* ============ Tooltip ============ */
1219
+ .tip-anchor {
1220
+ position: relative;
1221
+ display: inline-flex;
1222
+ }
1223
+ .tip {
1224
+ position: absolute;
1225
+ background: var(--bg-sunken);
1226
+ color: var(--fg);
1227
+ padding: 6px 10px;
1228
+ border-radius: var(--r-sm);
1229
+ font-size: 11px;
1230
+ font-weight: 500;
1231
+ white-space: nowrap;
1232
+ box-shadow: var(--neu-out-sm);
1233
+ pointer-events: none;
1234
+ animation: fadeIn var(--dur) var(--ease);
1235
+ z-index: 100;
1236
+ }
1237
+ .tip.top { bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%); }
1238
+ .tip.bottom { top: calc(100% + 8px); left: 50%; transform: translateX(-50%); }
1239
+ .tip.left { right: calc(100% + 8px); top: 50%; transform: translateY(-50%); }
1240
+ .tip.right { left: calc(100% + 8px); top: 50%; transform: translateY(-50%); }
1241
+ /* ============ Toast ============ */
1242
+ .toast-container {
1243
+ position: fixed;
1244
+ display: flex;
1245
+ flex-direction: column;
1246
+ gap: 10px;
1247
+ z-index: 300;
1248
+ pointer-events: none;
1249
+ }
1250
+ .toast-container.top-right { top: 56px; right: 20px; }
1251
+ .toast-container.top-left { top: 56px; left: 20px; }
1252
+ .toast-container.bottom-right { bottom: 20px; right: 20px; }
1253
+ .toast-container.bottom-left { bottom: 20px; left: 20px; }
1254
+ .toast-container.top-center { top: 56px; left: 50%; transform: translateX(-50%); align-items: center; }
1255
+ .toast {
1256
+ background: var(--bg);
1257
+ border-radius: var(--r-md);
1258
+ box-shadow: var(--neu-out-lg);
1259
+ padding: 12px 16px;
1260
+ min-width: 240px;
1261
+ display: flex; align-items: flex-start; gap: 10px;
1262
+ font-size: 13px;
1263
+ pointer-events: auto;
1264
+ animation: toastIn var(--dur-slow) var(--ease);
1265
+ border-left: 3px solid var(--accent);
1266
+ }
1267
+ .toast.success { border-color: var(--success); }
1268
+ .toast.warning { border-color: var(--warning); }
1269
+ .toast.danger { border-color: var(--danger); }
1270
+ .toast .toast-icon { color: var(--accent); margin-top: 2px; }
1271
+ .toast.success .toast-icon { color: var(--success); }
1272
+ .toast.warning .toast-icon { color: var(--warning); }
1273
+ .toast.danger .toast-icon { color: var(--danger); }
1274
+ .toast-body { flex: 1; min-width: 0; }
1275
+ .toast-title { font-weight: 600; margin-bottom: 2px; }
1276
+ .toast-msg { color: var(--fg-muted); font-size: 12px; }
1277
+ .toast-close {
1278
+ background: transparent; border: none;
1279
+ color: var(--fg-subtle); cursor: pointer;
1280
+ padding: 0 2px; font-family: inherit;
1281
+ }
1282
+ .toast-close:hover { color: var(--fg); }
1283
+ .toast.leaving { animation: toastOut var(--dur) var(--ease) forwards; }
1284
+ @keyframes toastIn { from { opacity: 0; transform: translateX(20px); } }
1285
+ @keyframes toastOut { to { opacity: 0; transform: translateX(20px); } }
1286
+ /* ============ Popover ============ */
1287
+ .popover {
1288
+ position: absolute;
1289
+ z-index: 100;
1290
+ background: var(--bg);
1291
+ border-radius: var(--r-md);
1292
+ padding: var(--gap-3);
1293
+ min-width: 220px;
1294
+ box-shadow: var(--neu-out-lg);
1295
+ animation: menuIn var(--dur) var(--ease);
1296
+ }
1297
+ .popover.top { bottom: calc(100% + 10px); left: 50%; transform: translateX(-50%); }
1298
+ .popover.bottom { top: calc(100% + 10px); left: 50%; transform: translateX(-50%); }
1299
+ .popover.left { right: calc(100% + 10px); top: 50%; transform: translateY(-50%); }
1300
+ .popover.right { left: calc(100% + 10px); top: 50%; transform: translateY(-50%); }
1301
+ /* ============ Alert ============ */
1302
+ .alert {
1303
+ display: flex;
1304
+ gap: 12px;
1305
+ align-items: flex-start;
1306
+ padding: 14px 16px;
1307
+ border-radius: var(--r-md);
1308
+ background: var(--bg);
1309
+ box-shadow: var(--neu-in-sm);
1310
+ position: relative;
1311
+ }
1312
+ .alert-ico {
1313
+ width: 20px; height: 20px;
1314
+ display: grid; place-items: center;
1315
+ flex-shrink: 0;
1316
+ margin-top: 1px;
1317
+ }
1318
+ .alert.info .alert-ico { color: var(--info); }
1319
+ .alert.success .alert-ico { color: var(--success); }
1320
+ .alert.warning .alert-ico { color: var(--warning); }
1321
+ .alert.danger .alert-ico { color: var(--danger); }
1322
+ .alert-body { flex: 1; min-width: 0; }
1323
+ .alert-title { font-size: 13px; font-weight: 600; margin-bottom: 3px; line-height: 1.4; }
1324
+ .alert-desc { font-size: 12px; color: var(--fg-muted); line-height: 1.55; }
1325
+ .alert.no-title { align-items: center; }
1326
+ .alert.no-title .alert-ico { margin-top: 0; }
1327
+ .alert-close {
1328
+ position: absolute; top: 10px; right: 10px;
1329
+ width: 22px; height: 22px; border-radius: 7px;
1330
+ display: grid; place-items: center;
1331
+ color: var(--fg-subtle);
1332
+ cursor: pointer;
1333
+ border: none; background: transparent;
1334
+ }
1335
+ .alert-close:hover { color: var(--fg); background: var(--bg); box-shadow: var(--neu-flat); }
1336
+ /* ============ Table ============ */
1337
+ .table-card {
1338
+ border-radius: var(--r-lg);
1339
+ background: var(--bg);
1340
+ box-shadow: var(--neu-out-sm);
1341
+ overflow: hidden;
1342
+ }
1343
+ .table-wrap {
1344
+ border-radius: var(--r-lg);
1345
+ background: var(--bg);
1346
+ box-shadow: var(--neu-in-sm);
1347
+ overflow: auto;
1348
+ }
1349
+ .table {
1350
+ width: 100%;
1351
+ border-collapse: separate;
1352
+ border-spacing: 0;
1353
+ font-size: 13px;
1354
+ }
1355
+ .table th {
1356
+ text-align: left;
1357
+ padding: 14px 18px;
1358
+ background: var(--bg);
1359
+ font-size: 11px;
1360
+ font-weight: 700;
1361
+ letter-spacing: 0.08em;
1362
+ text-transform: uppercase;
1363
+ color: var(--fg-subtle);
1364
+ border-bottom: 1px solid var(--divider);
1365
+ position: sticky; top: 0;
1366
+ z-index: 1;
1367
+ }
1368
+ .table th.sortable { cursor: pointer; user-select: none; }
1369
+ .table th.sortable:hover { color: var(--fg); }
1370
+ .table th .sort-ind {
1371
+ display: inline-flex;
1372
+ width: 16px; height: 16px;
1373
+ border-radius: 6px;
1374
+ background: var(--bg);
1375
+ box-shadow: var(--neu-flat);
1376
+ align-items: center; justify-content: center;
1377
+ margin-left: 6px;
1378
+ color: var(--fg-subtle);
1379
+ vertical-align: middle;
1380
+ }
1381
+ .table th.sorted .sort-ind { color: var(--accent); box-shadow: var(--neu-in-sm); }
1382
+ .table td {
1383
+ padding: 12px 18px;
1384
+ border-bottom: 1px solid var(--divider);
1385
+ vertical-align: middle;
1386
+ }
1387
+ .table.hoverable tbody tr:hover td { background: color-mix(in oklch, var(--accent-soft) 40%, transparent); }
1388
+ .table tbody tr.clickable { cursor: pointer; }
1389
+ .table tbody tr.selected td { background: color-mix(in oklch, var(--accent-soft) 80%, transparent); color: var(--accent-ink); }
1390
+ .table tbody tr:last-child td { border-bottom: none; }
1391
+ .table.striped tbody tr:nth-child(even) td {
1392
+ background: color-mix(in oklch, var(--bg-sunken) 40%, transparent);
1393
+ }
1394
+ /* Embossed: each row sits on the surface */
1395
+ .table.embossed { border-spacing: 0; }
1396
+ .table.embossed tbody td {
1397
+ background: var(--bg);
1398
+ }
1399
+ /* Card-row variant: each row is its own raised pill */
1400
+ .table.cards {
1401
+ border-collapse: separate;
1402
+ border-spacing: 0 10px;
1403
+ padding: 10px;
1404
+ background: transparent;
1405
+ box-shadow: none;
1406
+ }
1407
+ .table.cards thead th {
1408
+ background: transparent;
1409
+ border-bottom: none;
1410
+ padding-top: 0;
1411
+ padding-bottom: 6px;
1412
+ }
1413
+ .table.cards tbody td {
1414
+ background: var(--bg);
1415
+ border-bottom: none;
1416
+ padding: 14px 18px;
1417
+ }
1418
+ .table.cards tbody td:first-child {
1419
+ border-radius: var(--r-md) 0 0 var(--r-md);
1420
+ box-shadow: -4px 4px 8px var(--shadow-dark), -4px -4px 8px var(--shadow-light);
1421
+ }
1422
+ .table.cards tbody td:last-child {
1423
+ border-radius: 0 var(--r-md) var(--r-md) 0;
1424
+ box-shadow: 4px 4px 8px var(--shadow-dark), 4px -4px 8px var(--shadow-light);
1425
+ }
1426
+ .table.cards tbody td:not(:first-child):not(:last-child) {
1427
+ box-shadow: 0 4px 8px var(--shadow-dark), 0 -4px 8px var(--shadow-light);
1428
+ }
1429
+ .table.cards.hoverable tbody tr:hover td { background: var(--bg); transform: translateY(-1px); }
1430
+ .table .row-check { width: 36px; }
1431
+ .table-empty { padding: 60px 20px; text-align: center; color: var(--fg-muted); }
1432
+ /* Pro: card-wrap with toolbar + table + footer */
1433
+ .table-card {
1434
+ border-radius: var(--r-lg);
1435
+ background: var(--bg);
1436
+ box-shadow: var(--neu-out-sm);
1437
+ overflow: hidden;
1438
+ }
1439
+ .table-card .table-wrap { background: transparent; box-shadow: none; border-radius: 0; }
1440
+ .table-card .table-wrap.joined { border-radius: 0; }
1441
+ .table-toolbar {
1442
+ display: flex;
1443
+ align-items: center;
1444
+ gap: var(--gap-3);
1445
+ padding: 14px 16px;
1446
+ border-bottom: 1px solid var(--divider);
1447
+ }
1448
+ .table-toolbar .table-title {
1449
+ font-size: 14px;
1450
+ font-weight: 600;
1451
+ margin-right: 8px;
1452
+ }
1453
+ .table-toolbar-main {
1454
+ flex: 1;
1455
+ display: flex;
1456
+ align-items: center;
1457
+ gap: 10px;
1458
+ min-width: 0;
1459
+ }
1460
+ .table-toolbar-actions {
1461
+ display: flex;
1462
+ align-items: center;
1463
+ gap: 8px;
1464
+ flex-shrink: 0;
1465
+ }
1466
+ .table-footer {
1467
+ padding: 10px 16px;
1468
+ border-top: 1px solid var(--divider);
1469
+ background: color-mix(in oklch, var(--bg-sunken) 30%, transparent);
1470
+ }
1471
+ /* ============ Pagination ============ */
1472
+ .pagination {
1473
+ display: flex;
1474
+ align-items: center;
1475
+ justify-content: space-between;
1476
+ padding: 12px 14px;
1477
+ font-size: 12px;
1478
+ color: var(--fg-muted);
1479
+ gap: 12px;
1480
+ flex-wrap: wrap;
1481
+ }
1482
+ .pagination .pg-controls { display: flex; gap: 4px; align-items: center; }
1483
+ .pagination .pg {
1484
+ min-width: 30px; height: 30px;
1485
+ padding: 0 10px;
1486
+ border: none;
1487
+ border-radius: var(--r-sm);
1488
+ background: var(--bg);
1489
+ box-shadow: var(--neu-out-sm);
1490
+ display: inline-flex; align-items: center; justify-content: center;
1491
+ cursor: pointer;
1492
+ font-size: 12px;
1493
+ font-family: inherit;
1494
+ font-variant-numeric: tabular-nums;
1495
+ color: var(--fg);
1496
+ transition: all var(--dur-fast) var(--ease);
1497
+ }
1498
+ .pagination .pg:hover { color: var(--accent-ink); }
1499
+ .pagination .pg.active {
1500
+ box-shadow: var(--neu-in-sm);
1501
+ color: var(--accent-ink);
1502
+ font-weight: 700;
1503
+ }
1504
+ .pagination .pg.disabled { color: var(--fg-subtle); cursor: not-allowed; box-shadow: var(--neu-flat); }
1505
+ .pagination .ellipsis { padding: 0 4px; color: var(--fg-subtle); }
1506
+ /* ============ List ============ */
1507
+ .list {
1508
+ display: flex;
1509
+ flex-direction: column;
1510
+ background: var(--bg);
1511
+ border-radius: var(--r-lg);
1512
+ box-shadow: var(--neu-in-sm);
1513
+ padding: 8px;
1514
+ }
1515
+ .list-item {
1516
+ display: flex;
1517
+ align-items: center;
1518
+ gap: 12px;
1519
+ padding: 12px;
1520
+ border-radius: var(--r-sm);
1521
+ transition: all var(--dur-fast) var(--ease);
1522
+ }
1523
+ .list-item.clickable { cursor: pointer; }
1524
+ .list-item.clickable:hover { background: var(--bg); box-shadow: var(--neu-flat); }
1525
+ .list-item.selected { box-shadow: var(--neu-out-sm); background: var(--bg); }
1526
+ .list.with-dividers .list-item + .list-item { border-top: 1px solid var(--divider); border-radius: 0; }
1527
+ .list-item-meta { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
1528
+ .list-item-title { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1529
+ .list-item-desc { font-size: 12px; color: var(--fg-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1530
+ .list-item-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 0; }
1531
+ .list-item-avatar { display: inline-flex; align-items: center; justify-content: center; color: var(--fg-muted); flex-shrink: 0; }
1532
+ /* ============ Empty / Spinner / Skeleton ============ */
1533
+ /* .spinner base — legacy border-ring used internally by Select/Button.
1534
+ The public <Spinner> component always sets a variant class (`ring`|`dots`)
1535
+ which overrides this via the more specific rules below. */
1536
+ .spinner {
1537
+ width: 14px; height: 14px;
1538
+ border-radius: 999px;
1539
+ border: 2px solid currentColor;
1540
+ border-right-color: transparent;
1541
+ animation: spin 0.8s linear infinite;
1542
+ display: inline-block;
1543
+ }
1544
+ .empty {
1545
+ padding: 60px 20px;
1546
+ display: grid; place-items: center;
1547
+ gap: 12px;
1548
+ color: var(--fg-muted);
1549
+ text-align: center;
1550
+ }
1551
+ .empty.sm { padding: 28px 16px; gap: 8px; }
1552
+ .empty.sm .empty-ico { width: 40px; height: 40px; }
1553
+ .empty.sm .empty-title { font-size: 13px; }
1554
+ .empty.sm .empty-desc { font-size: 11px; }
1555
+ .empty.lg { padding: 96px 24px; gap: 16px; }
1556
+ .empty.lg .empty-ico { width: 72px; height: 72px; }
1557
+ .empty.lg .empty-title { font-size: 16px; }
1558
+ .empty.lg .empty-desc { font-size: 13px; }
1559
+ .empty.subtle .empty-ico { background: transparent; box-shadow: none; }
1560
+ .empty-ico {
1561
+ width: 56px; height: 56px;
1562
+ border-radius: var(--r-lg);
1563
+ background: var(--bg);
1564
+ box-shadow: var(--neu-in-sm);
1565
+ display: grid; place-items: center;
1566
+ color: var(--fg-subtle);
1567
+ }
1568
+ .empty-title { font-size: 14px; font-weight: 600; color: var(--fg); }
1569
+ .empty-desc { font-size: 12px; }
1570
+ .empty-action { margin-top: 8px; }
1571
+ /* Spinner tones */
1572
+ .spinner.accent { color: var(--accent); }
1573
+ .spinner.success { color: var(--success); }
1574
+ .spinner.warning { color: var(--warning); }
1575
+ .spinner.danger { color: var(--danger); }
1576
+ /* --- Ring variant: neumorphic pressed track + rotating arc --- */
1577
+ .spinner.ring {
1578
+ position: relative;
1579
+ display: inline-block;
1580
+ border: none;
1581
+ border-radius: 50%;
1582
+ background: var(--bg);
1583
+ box-shadow: var(--neu-in-sm);
1584
+ animation: none;
1585
+ }
1586
+ .spinner.ring::before {
1587
+ content: "";
1588
+ position: absolute;
1589
+ inset: 0;
1590
+ border-radius: inherit;
1591
+ background: conic-gradient(from 0deg,
1592
+ transparent 0deg,
1593
+ color-mix(in oklch, currentColor 30%, transparent) 40deg,
1594
+ color-mix(in oklch, currentColor 70%, transparent) 100deg,
1595
+ currentColor 220deg,
1596
+ currentColor 340deg,
1597
+ transparent 360deg);
1598
+ -webkit-mask: radial-gradient(circle, transparent 60%, #000 61%);
1599
+ mask: radial-gradient(circle, transparent 60%, #000 61%);
1600
+ animation: spin 0.9s linear infinite;
1601
+ }
1602
+ .spinner.ring.accent::before,
1603
+ .spinner.ring.success::before,
1604
+ .spinner.ring.warning::before,
1605
+ .spinner.ring.danger::before {
1606
+ filter: drop-shadow(0 0 4px color-mix(in oklch, currentColor 50%, transparent));
1607
+ }
1608
+ /* --- Dots variant: raised neumorphic spheres (container is transparent) --- */
1609
+ .spinner.dots {
1610
+ display: inline-flex;
1611
+ align-items: center;
1612
+ gap: 0.34em;
1613
+ border: none;
1614
+ background: none;
1615
+ box-shadow: none;
1616
+ width: auto; height: auto;
1617
+ animation: none;
1618
+ line-height: 1;
1619
+ }
1620
+ .spinner.dots i {
1621
+ width: 0.4em; height: 0.4em;
1622
+ border-radius: 999px;
1623
+ background: radial-gradient(circle at 32% 28%,
1624
+ color-mix(in oklch, currentColor 40%, white),
1625
+ currentColor 62%,
1626
+ color-mix(in oklch, currentColor 82%, black) 100%);
1627
+ box-shadow:
1628
+ 0 0.06em 0.14em color-mix(in oklch, currentColor 45%, transparent),
1629
+ 0 0 0.35em color-mix(in oklch, currentColor 50%, transparent);
1630
+ display: inline-block;
1631
+ animation: dot-bounce 1.2s ease-in-out infinite;
1632
+ }
1633
+ .spinner.dots i:nth-child(2) { animation-delay: 0.15s; }
1634
+ .spinner.dots i:nth-child(3) { animation-delay: 0.3s; }
1635
+ @keyframes dot-bounce {
1636
+ 0%, 80%, 100% { transform: translateY(0); opacity: 0.5; }
1637
+ 40% { transform: translateY(-30%); opacity: 1; }
1638
+ }
1639
+ .spinner-wrap {
1640
+ display: inline-flex;
1641
+ align-items: center;
1642
+ gap: 8px;
1643
+ color: var(--fg-muted);
1644
+ }
1645
+ .spinner-label { font-size: 12px; }
1646
+ .skeleton {
1647
+ display: block;
1648
+ background: color-mix(in oklch, var(--accent-soft) 55%, var(--bg-sunken));
1649
+ border-radius: var(--r-sm);
1650
+ }
1651
+ .skeleton.wave {
1652
+ background: linear-gradient(90deg,
1653
+ color-mix(in oklch, var(--accent-soft) 35%, var(--bg-sunken)),
1654
+ color-mix(in oklch, var(--accent-soft) 75%, var(--bg-sunken)),
1655
+ color-mix(in oklch, var(--accent-soft) 35%, var(--bg-sunken)));
1656
+ background-size: 200% 100%;
1657
+ animation: skel-wave 1.4s ease-in-out infinite;
1658
+ }
1659
+ .skeleton.pulse { animation: skel-pulse 1.4s ease-in-out infinite; }
1660
+ .skeleton.none { animation: none; }
1661
+ .skeleton.circle { border-radius: 999px; }
1662
+ @keyframes skel-wave { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
1663
+ @keyframes skel-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
1664
+ /* ============ Calendar ============ */
1665
+ .calendar {
1666
+ background: var(--bg);
1667
+ border-radius: var(--r-lg);
1668
+ padding: var(--gap-4);
1669
+ box-shadow: var(--neu-out);
1670
+ width: 320px;
1671
+ }
1672
+ .calendar-head {
1673
+ display: flex; align-items: center; justify-content: space-between;
1674
+ padding: 4px 4px 14px;
1675
+ }
1676
+ .calendar-title {
1677
+ font-size: 14px; font-weight: 600;
1678
+ display: inline-flex; align-items: center; gap: 8px;
1679
+ cursor: pointer; padding: 6px 10px; border-radius: var(--r-sm);
1680
+ border: none; background: transparent; color: var(--fg);
1681
+ font-family: inherit;
1682
+ transition: all var(--dur-fast) var(--ease);
1683
+ }
1684
+ .calendar-title:hover { background: var(--bg); box-shadow: var(--neu-flat); }
1685
+ .calendar-grid {
1686
+ display: grid;
1687
+ grid-template-columns: repeat(7, 1fr);
1688
+ gap: 2px;
1689
+ }
1690
+ .calendar-dow {
1691
+ text-align: center;
1692
+ font-size: 10px;
1693
+ font-weight: 600;
1694
+ color: var(--fg-subtle);
1695
+ text-transform: uppercase;
1696
+ letter-spacing: 0.06em;
1697
+ padding: 8px 0;
1698
+ }
1699
+ .calendar-cell {
1700
+ position: relative;
1701
+ aspect-ratio: 1;
1702
+ display: grid; place-items: center;
1703
+ font-size: 12px;
1704
+ color: var(--fg);
1705
+ border-radius: var(--r-sm);
1706
+ cursor: pointer;
1707
+ border: none;
1708
+ background: transparent;
1709
+ font-family: inherit;
1710
+ transition: all var(--dur-fast) var(--ease);
1711
+ }
1712
+ .calendar-cell.out { color: var(--fg-subtle); opacity: 0.5; }
1713
+ .calendar-cell:hover { background: var(--bg); box-shadow: var(--neu-flat); }
1714
+ .calendar-cell.today { font-weight: 700; color: var(--accent-ink); }
1715
+ .calendar-cell.today::after {
1716
+ content: ""; position: absolute; bottom: 4px; left: 50%;
1717
+ width: 4px; height: 4px; border-radius: 999px;
1718
+ background: var(--accent);
1719
+ transform: translateX(-50%);
1720
+ }
1721
+ .calendar-cell.selected {
1722
+ background: var(--bg);
1723
+ box-shadow: var(--neu-in-sm);
1724
+ color: var(--accent-ink);
1725
+ font-weight: 600;
1726
+ }
1727
+ .calendar-cell.disabled { color: var(--fg-subtle); opacity: 0.4; cursor: not-allowed; }
1728
+ .calendar-cell.disabled:hover { background: transparent; box-shadow: none; }
1729
+ /* ============ Image ============ */
1730
+ .n-image {
1731
+ display: inline-block;
1732
+ position: relative;
1733
+ border-radius: var(--r-md);
1734
+ background: var(--bg);
1735
+ padding: 6px;
1736
+ box-shadow: var(--neu-out-sm);
1737
+ overflow: hidden;
1738
+ line-height: 0;
1739
+ }
1740
+ .n-image-frame {
1741
+ position: relative;
1742
+ overflow: hidden;
1743
+ border-radius: calc(var(--r-md) - 4px);
1744
+ box-shadow: var(--neu-in-sm);
1745
+ background: var(--bg-sunken);
1746
+ }
1747
+ .n-image img {
1748
+ display: block;
1749
+ width: 100%;
1750
+ height: 100%;
1751
+ object-fit: cover;
1752
+ transition: transform var(--dur-slow) var(--ease), opacity var(--dur) var(--ease);
1753
+ }
1754
+ .n-image.hover img:hover { transform: scale(1.04); }
1755
+ .n-image-placeholder {
1756
+ position: absolute; inset: 0;
1757
+ display: grid; place-items: center;
1758
+ color: var(--fg-subtle);
1759
+ background:
1760
+ repeating-linear-gradient(45deg,
1761
+ transparent 0 10px,
1762
+ color-mix(in oklch, var(--fg-subtle) 8%, transparent) 10px 11px);
1763
+ transition: opacity var(--dur) var(--ease);
1764
+ }
1765
+ .n-image-placeholder.loaded { opacity: 0; pointer-events: none; }
1766
+ .n-image.clickable { cursor: zoom-in; }
1767
+ .image-actions {
1768
+ position: absolute;
1769
+ top: 10px;
1770
+ right: 10px;
1771
+ display: flex;
1772
+ gap: 4px;
1773
+ padding: 4px;
1774
+ border-radius: 999px;
1775
+ background: color-mix(in oklch, black 32%, transparent);
1776
+ backdrop-filter: blur(14px) saturate(1.2);
1777
+ border: 1px solid color-mix(in oklch, white 18%, transparent);
1778
+ opacity: 0;
1779
+ transform: translateY(-4px);
1780
+ transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
1781
+ }
1782
+ .n-image:hover .image-actions { opacity: 1; transform: translateY(0); }
1783
+ .image-actions .ia-btn {
1784
+ width: 26px;
1785
+ height: 26px;
1786
+ border: 0;
1787
+ padding: 0;
1788
+ border-radius: 999px;
1789
+ display: grid;
1790
+ place-items: center;
1791
+ color: rgba(255,255,255,0.85);
1792
+ background: transparent;
1793
+ cursor: pointer;
1794
+ transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
1795
+ }
1796
+ .image-actions .ia-btn:hover {
1797
+ background: color-mix(in oklch, white 22%, transparent);
1798
+ color: white;
1799
+ }
1800
+ .image-hint {
1801
+ position: absolute;
1802
+ left: 10px;
1803
+ bottom: 10px;
1804
+ display: inline-flex;
1805
+ align-items: center;
1806
+ gap: 4px;
1807
+ padding: 4px 10px;
1808
+ font-size: 11px;
1809
+ font-weight: 500;
1810
+ color: rgba(255,255,255,0.95);
1811
+ border-radius: 999px;
1812
+ background: color-mix(in oklch, black 38%, transparent);
1813
+ backdrop-filter: blur(12px) saturate(1.2);
1814
+ border: 1px solid color-mix(in oklch, white 16%, transparent);
1815
+ opacity: 0;
1816
+ transform: translateY(4px);
1817
+ transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
1818
+ pointer-events: none;
1819
+ }
1820
+ .n-image:hover .image-hint { opacity: 1; transform: translateY(0); }
1821
+ .image-preview-overlay {
1822
+ position: fixed; inset: 0;
1823
+ background: color-mix(in oklch, var(--bg-sunken) 82%, transparent);
1824
+ backdrop-filter: blur(16px);
1825
+ display: grid; place-items: center;
1826
+ z-index: 500;
1827
+ animation: fadeIn var(--dur) var(--ease);
1828
+ }
1829
+ .image-preview-overlay img {
1830
+ max-width: 80vw;
1831
+ max-height: 80vh;
1832
+ border-radius: var(--r-lg);
1833
+ box-shadow: var(--neu-out-lg), 0 40px 80px -20px rgba(0,0,0,0.25);
1834
+ }
1835
+ /* ============ Cascader ============ */
1836
+ .cascader {
1837
+ position: relative;
1838
+ display: inline-block;
1839
+ min-width: 240px;
1840
+ width: 100%;
1841
+ }
1842
+ .cascader-trigger {
1843
+ width: 100%;
1844
+ height: var(--ctrl-h);
1845
+ padding: 0 36px 0 var(--ctrl-pad-x);
1846
+ border-radius: var(--r-md);
1847
+ background: var(--bg);
1848
+ box-shadow: var(--neu-out-sm);
1849
+ display: inline-flex;
1850
+ align-items: center;
1851
+ font-size: 13px;
1852
+ font-family: inherit;
1853
+ cursor: pointer;
1854
+ position: relative;
1855
+ border: none;
1856
+ color: var(--fg);
1857
+ text-align: left;
1858
+ }
1859
+ .cascader-trigger.placeholder { color: var(--fg-subtle); }
1860
+ .cascader.open .cascader-trigger { box-shadow: var(--neu-in-sm); color: var(--accent-ink); }
1861
+ .cascader-panel {
1862
+ position: absolute;
1863
+ top: calc(100% + 8px);
1864
+ left: 0;
1865
+ z-index: 50;
1866
+ display: flex;
1867
+ background: var(--bg);
1868
+ border-radius: var(--r-md);
1869
+ box-shadow: var(--neu-out-lg);
1870
+ padding: 6px;
1871
+ animation: menuIn var(--dur) var(--ease);
1872
+ gap: 4px;
1873
+ }
1874
+ .cascader-col {
1875
+ min-width: 160px;
1876
+ max-height: 280px;
1877
+ overflow-y: auto;
1878
+ padding: 4px;
1879
+ border-radius: var(--r-sm);
1880
+ }
1881
+ .cascader-col + .cascader-col {
1882
+ border-left: 1px solid var(--divider);
1883
+ margin-left: 2px;
1884
+ padding-left: 6px;
1885
+ }
1886
+ .cascader-item {
1887
+ padding: 8px 10px;
1888
+ border-radius: var(--r-sm);
1889
+ font-size: 13px;
1890
+ color: var(--fg);
1891
+ cursor: pointer;
1892
+ display: flex;
1893
+ align-items: center;
1894
+ gap: 8px;
1895
+ transition: all var(--dur-fast) var(--ease);
1896
+ border: none;
1897
+ background: transparent;
1898
+ font-family: inherit;
1899
+ width: 100%;
1900
+ text-align: left;
1901
+ }
1902
+ .cascader-item:hover { background: var(--bg); box-shadow: var(--neu-flat); color: var(--accent-ink); }
1903
+ .cascader-item.active {
1904
+ background: var(--bg);
1905
+ box-shadow: var(--neu-in-sm);
1906
+ color: var(--accent-ink);
1907
+ font-weight: 500;
1908
+ }
1909
+ .cascader-item .chev { margin-left: auto; color: var(--fg-subtle); display: inline-flex; }
1910
+ .cascader-item.active .chev { color: var(--accent); }
1911
+ /* ============ TitleBar (Electron) ============ */
1912
+ .titlebar {
1913
+ display: flex;
1914
+ align-items: center;
1915
+ gap: var(--gap-3);
1916
+ padding: 0 var(--gap-3);
1917
+ height: 40px;
1918
+ background: var(--bg);
1919
+ -webkit-app-region: drag;
1920
+ user-select: none;
1921
+ border-bottom: 1px solid var(--divider);
1922
+ position: relative;
1923
+ z-index: 5;
1924
+ overflow: visible;
1925
+ }
1926
+ .titlebar.windows { padding-right: 0; }
1927
+ .titlebar-title {
1928
+ display: inline-flex;
1929
+ align-items: center;
1930
+ gap: 10px;
1931
+ font-weight: 500;
1932
+ font-size: 13px;
1933
+ flex-shrink: 0;
1934
+ min-width: 0;
1935
+ }
1936
+ .titlebar-center {
1937
+ position: absolute; left: 50%; transform: translateX(-50%);
1938
+ display: inline-flex; align-items: center; gap: 8px;
1939
+ -webkit-app-region: no-drag;
1940
+ }
1941
+ .titlebar-actions {
1942
+ margin-left: auto;
1943
+ display: inline-flex; align-items: center; gap: 6px;
1944
+ -webkit-app-region: no-drag;
1945
+ flex-shrink: 0;
1946
+ }
1947
+ /* macOS traffic lights */
1948
+ .win-controls { flex-shrink: 0; }
1949
+ .win-controls.mac { display: inline-flex; gap: 8px; -webkit-app-region: no-drag; }
1950
+ .win-controls.mac .win-btn {
1951
+ width: 13px; height: 13px;
1952
+ border: none; padding: 0;
1953
+ border-radius: 999px;
1954
+ background: var(--bg);
1955
+ box-shadow: var(--neu-flat);
1956
+ position: relative;
1957
+ cursor: pointer;
1958
+ transition: transform var(--dur-fast) var(--ease);
1959
+ }
1960
+ .win-controls.mac .win-btn::after {
1961
+ content: "";
1962
+ position: absolute; inset: 2px;
1963
+ border-radius: 999px;
1964
+ background: var(--dot, var(--fg-subtle));
1965
+ opacity: 0.85;
1966
+ }
1967
+ .win-controls.mac .win-btn.close { --dot: #ff5f57; }
1968
+ .win-controls.mac .win-btn.minimize { --dot: #febc2e; }
1969
+ .win-controls.mac .win-btn.maximize { --dot: #28c840; }
1970
+ .win-controls.mac .win-btn:hover { transform: scale(1.08); }
1971
+ /* Windows controls */
1972
+ .win-controls.windows {
1973
+ display: inline-flex;
1974
+ -webkit-app-region: no-drag;
1975
+ margin-left: 8px;
1976
+ flex-shrink: 0;
1977
+ }
1978
+ .win-controls.windows .win-btn {
1979
+ width: 38px;
1980
+ height: 28px;
1981
+ border: 0;
1982
+ padding: 0;
1983
+ border-radius: 8px;
1984
+ background: transparent;
1985
+ color: var(--fg-muted);
1986
+ display: inline-grid;
1987
+ place-items: center;
1988
+ cursor: pointer;
1989
+ transition: all var(--dur-fast) var(--ease);
1990
+ margin: 0 1px;
1991
+ flex-shrink: 0;
1992
+ overflow: visible;
1993
+ }
1994
+ .win-controls.windows .win-btn svg { display: block; flex-shrink: 0; }
1995
+ .win-controls.windows .win-btn:hover { background: var(--bg); box-shadow: var(--neu-in-sm); color: var(--fg); }
1996
+ .win-controls.windows .win-btn.close:hover {
1997
+ background: var(--danger);
1998
+ color: white;
1999
+ box-shadow: 2px 2px 4px color-mix(in oklch, var(--danger) 30%, var(--shadow-dark));
2000
+ }
2001
+ /* ============ Sidebar ============ */
2002
+ .sidebar {
2003
+ display: flex;
2004
+ flex-direction: column;
2005
+ width: 220px;
2006
+ padding: 12px;
2007
+ background: var(--bg);
2008
+ border-right: 1px solid var(--divider);
2009
+ flex-shrink: 0;
2010
+ overflow-y: auto;
2011
+ gap: 4px;
2012
+ }
2013
+ .sidebar.collapsed { width: 64px; }
2014
+ .sidebar-header { padding: 4px 8px 12px; border-bottom: 1px solid var(--divider); margin-bottom: 8px; }
2015
+ .sidebar-footer { margin-top: auto; padding-top: 12px; border-top: 1px solid var(--divider); }
2016
+ .sidebar-nav { display: flex; flex-direction: column; gap: 2px; }
2017
+ .sidebar-item {
2018
+ display: flex; align-items: center; gap: 10px;
2019
+ padding: 10px 12px;
2020
+ border: none;
2021
+ border-radius: var(--r-sm);
2022
+ background: transparent;
2023
+ color: var(--fg-muted);
2024
+ font-size: 13px;
2025
+ font-family: inherit;
2026
+ text-align: left;
2027
+ cursor: pointer;
2028
+ width: 100%;
2029
+ transition: all var(--dur-fast) var(--ease);
2030
+ }
2031
+ .sidebar-item:hover { color: var(--fg); background: var(--bg); box-shadow: var(--neu-flat); }
2032
+ .sidebar-item.active {
2033
+ color: var(--accent-ink);
2034
+ background: var(--bg);
2035
+ box-shadow: var(--neu-in-sm);
2036
+ font-weight: 500;
2037
+ }
2038
+ .sidebar-icon { display: inline-flex; flex-shrink: 0; }
2039
+ .sidebar-label { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
2040
+ .sidebar-badge {
2041
+ font-size: 11px;
2042
+ padding: 1px 7px;
2043
+ border-radius: 999px;
2044
+ background: var(--accent);
2045
+ color: white;
2046
+ font-weight: 600;
2047
+ }
2048
+ /* ============ AppShell ============ */
2049
+ .app-shell {
2050
+ display: flex;
2051
+ flex-direction: column;
2052
+ width: 100%;
2053
+ height: 100vh;
2054
+ background: var(--bg);
2055
+ color: var(--fg);
2056
+ overflow: hidden;
2057
+ position: relative;
2058
+ }
2059
+ .app-shell-body {
2060
+ flex: 1;
2061
+ display: flex;
2062
+ min-height: 0;
2063
+ }
2064
+ .app-shell-main {
2065
+ flex: 1;
2066
+ min-width: 0;
2067
+ overflow: auto;
2068
+ }