@blurrow/ui 0.1.0 → 0.2.1

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 (272) hide show
  1. package/README.md +60 -20
  2. package/dist/Accordion.d.ts +17 -0
  3. package/dist/Accordion.js +138 -0
  4. package/dist/Accordion.js.map +1 -0
  5. package/dist/Alert.d.ts +13 -0
  6. package/dist/Alert.js +69 -0
  7. package/dist/Alert.js.map +1 -0
  8. package/dist/AuthorCard.d.ts +12 -0
  9. package/dist/AuthorCard.js +57 -0
  10. package/dist/AuthorCard.js.map +1 -0
  11. package/dist/Avatar.d.ts +21 -0
  12. package/dist/Avatar.js +96 -0
  13. package/dist/Avatar.js.map +1 -0
  14. package/dist/Badge.d.ts +12 -0
  15. package/dist/Badge.js +46 -0
  16. package/dist/Badge.js.map +1 -0
  17. package/dist/Banner.d.ts +15 -0
  18. package/dist/Banner.js +68 -0
  19. package/dist/Banner.js.map +1 -0
  20. package/dist/Breadcrumb.d.ts +13 -0
  21. package/dist/Breadcrumb.js +45 -0
  22. package/dist/Breadcrumb.js.map +1 -0
  23. package/dist/Button.d.ts +19 -0
  24. package/dist/Button.js +282 -0
  25. package/dist/Button.js.map +1 -0
  26. package/dist/ButtonGroup.d.ts +19 -0
  27. package/dist/ButtonGroup.js +62 -0
  28. package/dist/ButtonGroup.js.map +1 -0
  29. package/dist/Card.d.ts +40 -0
  30. package/dist/Card.js +175 -0
  31. package/dist/Card.js.map +1 -0
  32. package/dist/CardShell.d.ts +18 -0
  33. package/dist/CardShell.js +58 -0
  34. package/dist/CardShell.js.map +1 -0
  35. package/dist/Carousel.d.ts +22 -0
  36. package/dist/Carousel.js +247 -0
  37. package/dist/Carousel.js.map +1 -0
  38. package/dist/Checkbox.d.ts +15 -0
  39. package/dist/Checkbox.js +84 -0
  40. package/dist/Checkbox.js.map +1 -0
  41. package/dist/CloseButton.d.ts +12 -0
  42. package/dist/CloseButton.js +63 -0
  43. package/dist/CloseButton.js.map +1 -0
  44. package/dist/CodeBlock.d.ts +12 -0
  45. package/dist/CodeBlock.js +221 -0
  46. package/dist/CodeBlock.js.map +1 -0
  47. package/dist/ColorPicker.d.ts +24 -0
  48. package/dist/ColorPicker.js +366 -0
  49. package/dist/ColorPicker.js.map +1 -0
  50. package/dist/Combobox.d.ts +34 -0
  51. package/dist/Combobox.js +255 -0
  52. package/dist/Combobox.js.map +1 -0
  53. package/dist/CommandPalette.d.ts +25 -0
  54. package/dist/CommandPalette.js +304 -0
  55. package/dist/CommandPalette.js.map +1 -0
  56. package/dist/ContextMenu.d.ts +16 -0
  57. package/dist/ContextMenu.js +209 -0
  58. package/dist/ContextMenu.js.map +1 -0
  59. package/dist/DataList.d.ts +15 -0
  60. package/dist/DataList.js +42 -0
  61. package/dist/DataList.js.map +1 -0
  62. package/dist/DatePicker.d.ts +65 -0
  63. package/dist/DatePicker.js +391 -0
  64. package/dist/DatePicker.js.map +1 -0
  65. package/dist/DateRangePicker.d.ts +34 -0
  66. package/dist/DateRangePicker.js +180 -0
  67. package/dist/DateRangePicker.js.map +1 -0
  68. package/dist/Drawer.d.ts +17 -0
  69. package/dist/Drawer.js +132 -0
  70. package/dist/Drawer.js.map +1 -0
  71. package/dist/DropdownMenu.d.ts +23 -0
  72. package/dist/DropdownMenu.js +185 -0
  73. package/dist/DropdownMenu.js.map +1 -0
  74. package/dist/EmptyState.d.ts +13 -0
  75. package/dist/EmptyState.js +55 -0
  76. package/dist/EmptyState.js.map +1 -0
  77. package/dist/FieldMessage.d.ts +26 -0
  78. package/dist/FieldMessage.js +95 -0
  79. package/dist/FieldMessage.js.map +1 -0
  80. package/dist/FileUpload.d.ts +32 -0
  81. package/dist/FileUpload.js +253 -0
  82. package/dist/FileUpload.js.map +1 -0
  83. package/dist/Floating.d.ts +32 -0
  84. package/dist/Floating.js +95 -0
  85. package/dist/Floating.js.map +1 -0
  86. package/dist/HoverCard.d.ts +18 -0
  87. package/dist/HoverCard.js +90 -0
  88. package/dist/HoverCard.js.map +1 -0
  89. package/dist/Input.d.ts +17 -0
  90. package/dist/Input.js +96 -0
  91. package/dist/Input.js.map +1 -0
  92. package/dist/Kbd.d.ts +9 -0
  93. package/dist/Kbd.js +24 -0
  94. package/dist/Kbd.js.map +1 -0
  95. package/dist/Modal.d.ts +15 -0
  96. package/dist/Modal.js +109 -0
  97. package/dist/Modal.js.map +1 -0
  98. package/dist/NumberInput.d.ts +23 -0
  99. package/dist/NumberInput.js +162 -0
  100. package/dist/NumberInput.js.map +1 -0
  101. package/dist/OtpInput.d.ts +26 -0
  102. package/dist/OtpInput.js +173 -0
  103. package/dist/OtpInput.js.map +1 -0
  104. package/dist/Pagination.d.ts +11 -0
  105. package/dist/Pagination.js +148 -0
  106. package/dist/Pagination.js.map +1 -0
  107. package/dist/Popover.d.ts +13 -0
  108. package/dist/Popover.js +98 -0
  109. package/dist/Popover.js.map +1 -0
  110. package/dist/Progress.d.ts +12 -0
  111. package/dist/Progress.js +61 -0
  112. package/dist/Progress.js.map +1 -0
  113. package/dist/QuoteCard.d.ts +13 -0
  114. package/dist/QuoteCard.js +92 -0
  115. package/dist/QuoteCard.js.map +1 -0
  116. package/dist/Radio.d.ts +19 -0
  117. package/dist/Radio.js +161 -0
  118. package/dist/Radio.js.map +1 -0
  119. package/dist/RadioCards.d.ts +27 -0
  120. package/dist/RadioCards.js +205 -0
  121. package/dist/RadioCards.js.map +1 -0
  122. package/dist/ReactionBar.d.ts +15 -0
  123. package/dist/ReactionBar.js +92 -0
  124. package/dist/ReactionBar.js.map +1 -0
  125. package/dist/ReadingProgress.d.ts +8 -0
  126. package/dist/ReadingProgress.js +51 -0
  127. package/dist/ReadingProgress.js.map +1 -0
  128. package/dist/ReadingTime.d.ts +9 -0
  129. package/dist/ReadingTime.js +39 -0
  130. package/dist/ReadingTime.js.map +1 -0
  131. package/dist/Select.d.ts +20 -0
  132. package/dist/Select.js +244 -0
  133. package/dist/Select.js.map +1 -0
  134. package/dist/Separator.d.ts +14 -0
  135. package/dist/Separator.js +33 -0
  136. package/dist/Separator.js.map +1 -0
  137. package/dist/ShareButtons.d.ts +10 -0
  138. package/dist/ShareButtons.js +107 -0
  139. package/dist/ShareButtons.js.map +1 -0
  140. package/dist/Sidebar.d.ts +30 -0
  141. package/dist/Sidebar.js +140 -0
  142. package/dist/Sidebar.js.map +1 -0
  143. package/dist/Skeleton.d.ts +15 -0
  144. package/dist/Skeleton.js +67 -0
  145. package/dist/Skeleton.js.map +1 -0
  146. package/dist/Slider.d.ts +27 -0
  147. package/dist/Slider.js +182 -0
  148. package/dist/Slider.js.map +1 -0
  149. package/dist/Spinner.d.ts +12 -0
  150. package/dist/Spinner.js +24 -0
  151. package/dist/Spinner.js.map +1 -0
  152. package/dist/SpotlightCard.d.ts +17 -0
  153. package/dist/SpotlightCard.js +87 -0
  154. package/dist/SpotlightCard.js.map +1 -0
  155. package/dist/Stat.d.ts +19 -0
  156. package/dist/Stat.js +71 -0
  157. package/dist/Stat.js.map +1 -0
  158. package/dist/StatCard.d.ts +24 -0
  159. package/dist/StatCard.js +212 -0
  160. package/dist/StatCard.js.map +1 -0
  161. package/dist/Steps.d.ts +14 -0
  162. package/dist/Steps.js +94 -0
  163. package/dist/Steps.js.map +1 -0
  164. package/dist/Table.d.ts +21 -0
  165. package/dist/Table.js +93 -0
  166. package/dist/Table.js.map +1 -0
  167. package/dist/TableOfContents.d.ts +17 -0
  168. package/dist/TableOfContents.js +92 -0
  169. package/dist/TableOfContents.js.map +1 -0
  170. package/dist/Tabs.d.ts +17 -0
  171. package/dist/Tabs.js +123 -0
  172. package/dist/Tabs.js.map +1 -0
  173. package/dist/TagInput.d.ts +16 -0
  174. package/dist/TagInput.js +169 -0
  175. package/dist/TagInput.js.map +1 -0
  176. package/dist/Textarea.d.ts +13 -0
  177. package/dist/Textarea.js +74 -0
  178. package/dist/Textarea.js.map +1 -0
  179. package/dist/TimePicker.d.ts +28 -0
  180. package/dist/TimePicker.js +264 -0
  181. package/dist/TimePicker.js.map +1 -0
  182. package/dist/Timeline.d.ts +19 -0
  183. package/dist/Timeline.js +76 -0
  184. package/dist/Timeline.js.map +1 -0
  185. package/dist/Toast.d.ts +18 -0
  186. package/dist/Toast.js +318 -0
  187. package/dist/Toast.js.map +1 -0
  188. package/dist/Toggle.d.ts +13 -0
  189. package/dist/Toggle.js +84 -0
  190. package/dist/Toggle.js.map +1 -0
  191. package/dist/Tooltip.d.ts +13 -0
  192. package/dist/Tooltip.js +138 -0
  193. package/dist/Tooltip.js.map +1 -0
  194. package/dist/cli.js +1644 -0
  195. package/dist/index.d.ts +68 -631
  196. package/dist/index.js +67 -5558
  197. package/dist/index.js.map +1 -1
  198. package/dist/registry/Accordion.tsx +140 -0
  199. package/dist/registry/Alert.tsx +95 -0
  200. package/dist/registry/AuthorCard.tsx +67 -0
  201. package/dist/registry/Avatar.tsx +116 -0
  202. package/dist/registry/Badge.tsx +55 -0
  203. package/dist/registry/Banner.tsx +86 -0
  204. package/dist/registry/Breadcrumb.tsx +60 -0
  205. package/dist/registry/Button.tsx +361 -0
  206. package/dist/registry/ButtonGroup.tsx +82 -0
  207. package/dist/registry/Card.tsx +241 -0
  208. package/dist/registry/CardShell.tsx +78 -0
  209. package/dist/registry/Carousel.tsx +296 -0
  210. package/dist/registry/Checkbox.tsx +104 -0
  211. package/dist/registry/CloseButton.tsx +68 -0
  212. package/dist/registry/CodeBlock.tsx +202 -0
  213. package/dist/registry/ColorPicker.tsx +404 -0
  214. package/dist/registry/Combobox.tsx +318 -0
  215. package/dist/registry/CommandPalette.tsx +356 -0
  216. package/dist/registry/ContextMenu.tsx +241 -0
  217. package/dist/registry/DataList.tsx +49 -0
  218. package/dist/registry/DatePicker.tsx +494 -0
  219. package/dist/registry/DateRangePicker.tsx +232 -0
  220. package/dist/registry/Drawer.tsx +166 -0
  221. package/dist/registry/DropdownMenu.tsx +219 -0
  222. package/dist/registry/EmptyState.tsx +55 -0
  223. package/dist/registry/FieldMessage.tsx +123 -0
  224. package/dist/registry/FileUpload.tsx +318 -0
  225. package/dist/registry/Floating.tsx +134 -0
  226. package/dist/registry/HoverCard.tsx +113 -0
  227. package/dist/registry/Input.tsx +108 -0
  228. package/dist/registry/Kbd.tsx +23 -0
  229. package/dist/registry/Modal.tsx +130 -0
  230. package/dist/registry/NumberInput.tsx +183 -0
  231. package/dist/registry/OtpInput.tsx +219 -0
  232. package/dist/registry/Pagination.tsx +160 -0
  233. package/dist/registry/Popover.tsx +116 -0
  234. package/dist/registry/Progress.tsx +66 -0
  235. package/dist/registry/QuoteCard.tsx +93 -0
  236. package/dist/registry/Radio.tsx +205 -0
  237. package/dist/registry/RadioCards.tsx +247 -0
  238. package/dist/registry/ReactionBar.tsx +101 -0
  239. package/dist/registry/ReadingProgress.tsx +51 -0
  240. package/dist/registry/ReadingTime.tsx +35 -0
  241. package/dist/registry/Select.tsx +265 -0
  242. package/dist/registry/Separator.tsx +52 -0
  243. package/dist/registry/ShareButtons.tsx +134 -0
  244. package/dist/registry/Sidebar.tsx +182 -0
  245. package/dist/registry/Skeleton.tsx +83 -0
  246. package/dist/registry/Slider.tsx +229 -0
  247. package/dist/registry/Spinner.tsx +32 -0
  248. package/dist/registry/SpotlightCard.tsx +106 -0
  249. package/dist/registry/Stat.tsx +82 -0
  250. package/dist/registry/StatCard.tsx +256 -0
  251. package/dist/registry/Steps.tsx +109 -0
  252. package/dist/registry/Table.tsx +123 -0
  253. package/dist/registry/TableOfContents.tsx +116 -0
  254. package/dist/registry/Tabs.tsx +136 -0
  255. package/dist/registry/TagInput.tsx +191 -0
  256. package/dist/registry/Textarea.tsx +84 -0
  257. package/dist/registry/TimePicker.tsx +315 -0
  258. package/dist/registry/Timeline.tsx +102 -0
  259. package/dist/registry/Toast.tsx +388 -0
  260. package/dist/registry/Toggle.tsx +96 -0
  261. package/dist/registry/Tooltip.tsx +160 -0
  262. package/dist/registry/styles.css +1207 -0
  263. package/dist/registry/useFloatingPanel.ts +112 -0
  264. package/dist/registry/useModalBehavior.ts +77 -0
  265. package/dist/styles.css +868 -62
  266. package/dist/useFloatingPanel.d.ts +24 -0
  267. package/dist/useFloatingPanel.js +89 -0
  268. package/dist/useFloatingPanel.js.map +1 -0
  269. package/dist/useModalBehavior.d.ts +15 -0
  270. package/dist/useModalBehavior.js +57 -0
  271. package/dist/useModalBehavior.js.map +1 -0
  272. package/package.json +23 -6
@@ -0,0 +1,1207 @@
1
+ /* blurrow/ui: design tokens, materials and keyframes.
2
+ Import after tailwindcss: @import "tailwindcss"; @import "@blurrow/ui/styles.css";
3
+ The kit is set in Archivo; load it as the --font-archivo variable.
4
+
5
+ Light is the default. For dark, set data-theme="dark" on <html> (the
6
+ class "dark" works too), or on any element to darken just that part.
7
+ data-theme="system" follows the visitor's OS setting, and
8
+ data-theme="light" keeps a part of the page light inside a dark one. */
9
+
10
+ @theme {
11
+ --font-sans: var(--font-archivo), ui-sans-serif, system-ui, sans-serif;
12
+ }
13
+
14
+ /* The theme's colours as Tailwind utilities: text-ink, bg-panel-face,
15
+ border-line… `inline` keeps the var() in every class, so a colour is
16
+ read where it's used and follows whichever theme that element is in. */
17
+ @theme inline {
18
+ --color-page: var(--page);
19
+ --color-panel-face: var(--panel-face);
20
+ --color-surface-hover: var(--surface-hover);
21
+ --color-surface-active: var(--surface-active);
22
+ --color-line: var(--line);
23
+ --color-line-strong: var(--line-strong);
24
+ --color-groove: var(--groove);
25
+ --color-track: var(--track);
26
+ --color-track-on: var(--track-on);
27
+
28
+ --color-ink-strong: var(--ink-strong);
29
+ --color-ink: var(--ink);
30
+ --color-ink-soft: var(--ink-soft);
31
+ --color-ink-label: var(--ink-label);
32
+ --color-ink-body: var(--ink-body);
33
+ --color-ink-muted: var(--ink-muted);
34
+ --color-ink-faint: var(--ink-faint);
35
+ --color-ink-ghost: var(--ink-ghost);
36
+ --color-ink-inverse: var(--ink-inverse);
37
+
38
+ --color-danger: var(--danger);
39
+ --color-danger-soft: var(--danger-soft);
40
+ --color-danger-wash: var(--danger-wash);
41
+ --color-success: var(--success);
42
+ --color-success-soft: var(--success-soft);
43
+ --color-warning: var(--warning);
44
+ --color-warning-ink: var(--warning-ink);
45
+ --color-accent: var(--accent);
46
+ --color-accent-soft: var(--accent-soft);
47
+
48
+ --color-code-keyword: var(--code-keyword);
49
+ --color-code-string: var(--code-string);
50
+ --color-code-tag: var(--code-tag);
51
+ --color-code-number: var(--code-number);
52
+ }
53
+
54
+ /* ── Materials ───────────────────────────────────────────────────── */
55
+ /* One light source from above: highlights live on top edges, shade on
56
+ bottom edges, and every raised face casts onto whatever holds it.
57
+ Materials are fixed: light is always light, dark is always dark.
58
+ Components read the theme roles further down, which point at these. */
59
+ :root {
60
+ --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
61
+ --ease-out-soft: cubic-bezier(0.16, 1, 0.3, 1);
62
+
63
+ /* Light material */
64
+ --bezel-light: linear-gradient(180deg, #f7f7f7 0%, #dedede 100%);
65
+ --bezel-light-shadow:
66
+ 0 0 0 0.5px rgba(17, 17, 17, 0.054), 0 1px 1px rgba(17, 17, 17, 0.06),
67
+ 0 4px 10px -4px rgba(17, 17, 17, 0.14), inset 0 2px 3px -2px rgba(255, 255, 255, 1),
68
+ inset 0 -2px 3px -2px rgba(17, 17, 17, 0.04);
69
+ --face-light: linear-gradient(180deg, #ffffff 0%, #fafafa 55%, #f3f3f3 100%);
70
+ --face-light-shadow:
71
+ 0 0 3px rgba(17, 17, 17, 0.119),
72
+ 0 1px 4px -1px rgba(17, 17, 17, 0.1), inset 0 2px 3px -2px rgba(255, 255, 255, 1),
73
+ inset 0 -2px 3px -2px rgba(17, 17, 17, 0.035);
74
+ --face-light-shadow-hover:
75
+ 0 0 3px rgba(17, 17, 17, 0.136), 0 2px 3px rgba(17, 17, 17, 0.1),
76
+ 0 4px 8px -2px rgba(17, 17, 17, 0.08), inset 0 2px 3px -2px rgba(255, 255, 255, 1),
77
+ inset 0 -2px 3px -2px rgba(17, 17, 17, 0.035);
78
+ /* A face with no bezel casts further when it lifts */
79
+ --face-light-float-shadow:
80
+ 0 0 3px rgba(17, 17, 17, 0.136), 0 2px 4px rgba(17, 17, 17, 0.08),
81
+ 0 6px 14px -4px rgba(17, 17, 17, 0.1), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
82
+
83
+ /* Dark material */
84
+ --bezel-dark: linear-gradient(180deg, #2c2c2c 0%, #0c0c0c 100%);
85
+ --bezel-dark-shadow:
86
+ 0 0 0 0.5px rgba(0, 0, 0, 0.33), 0 1px 1px rgba(0, 0, 0, 0.2),
87
+ 0 4px 12px -4px rgba(0, 0, 0, 0.45), inset 0 2px 3px -2px rgba(255, 255, 255, 0.075);
88
+ --face-dark: linear-gradient(180deg, #2e2e2e 0%, #1f1f1f 55%, #181818 100%);
89
+ --face-dark-shadow:
90
+ 0 0 3px rgba(0, 0, 0, 0.35),
91
+ 0 1px 4px -1px rgba(0, 0, 0, 0.3), inset 0 2px 3px -2px rgba(255, 255, 255, 0.105),
92
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.25);
93
+ --face-dark-shadow-hover:
94
+ 0 0 3px rgba(0, 0, 0, 0.35), 0 2px 3px rgba(0, 0, 0, 0.45),
95
+ 0 4px 8px -2px rgba(0, 0, 0, 0.35), inset 0 2px 3px -2px rgba(255, 255, 255, 0.135),
96
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.25);
97
+ --face-dark-float-shadow:
98
+ 0 0 3px rgba(0, 0, 0, 0.35), 0 2px 4px rgba(0, 0, 0, 0.4),
99
+ 0 6px 14px -4px rgba(0, 0, 0, 0.35), inset 0 2px 3px -2px rgba(255, 255, 255, 0.135);
100
+
101
+ /* Mid material: a raised face a few steps lighter than a dark surface —
102
+ present, but in the same family of tones (secondary on dark) */
103
+ --bezel-mid: linear-gradient(180deg, #2a2a2a 0%, #161616 100%);
104
+ --bezel-mid-shadow:
105
+ 0 0 0 0.5px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.35),
106
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.053);
107
+ --face-mid: linear-gradient(180deg, #353535 0%, #2a2a2a 55%, #242424 100%);
108
+ --face-mid-shadow:
109
+ 0 0 3px rgba(0, 0, 0, 0.35), 0 1px 1.5px rgba(0, 0, 0, 0.4),
110
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.09), inset 0 -2px 3px -2px rgba(0, 0, 0, 0.2);
111
+ --face-mid-shadow-hover:
112
+ 0 0 3px rgba(0, 0, 0, 0.35), 0 2px 3px rgba(0, 0, 0, 0.45),
113
+ 0 4px 8px -2px rgba(0, 0, 0, 0.35), inset 0 2px 3px -2px rgba(255, 255, 255, 0.12),
114
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.2);
115
+ --face-mid-float-shadow:
116
+ 0 0 3px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.4),
117
+ 0 6px 14px -4px rgba(0, 0, 0, 0.4), inset 0 2px 3px -2px rgba(255, 255, 255, 0.12);
118
+
119
+ /* Sunken face (pressed) — the face drops flush with its bezel */
120
+ --face-light-pressed:
121
+ 0 0 3px rgba(17, 17, 17, 0.136), inset 0 1px 2px rgba(17, 17, 17, 0.08);
122
+ --face-dark-pressed:
123
+ 0 0 3px rgba(0, 0, 0, 0.35), inset 0 1px 2px rgba(0, 0, 0, 0.45);
124
+
125
+ /* Cards — the largest surfaces; pair with .rim */
126
+ --card-light: linear-gradient(180deg, #ffffff 0%, #fefefe 40%, #fafafa 100%);
127
+ --card-light-shadow:
128
+ 0 1px 3px rgba(17, 17, 17, 0.02), 0 4px 12px -2px rgba(17, 17, 17, 0.05),
129
+ 0 8px 24px -4px rgba(17, 17, 17, 0.04), 0 0 0 0.5px rgba(17, 17, 17, 0.036),
130
+ inset 0 2.5px 3px -2px rgba(255, 255, 255, 0.712);
131
+ --card-light-shadow-hover:
132
+ 0 2px 6px rgba(17, 17, 17, 0.03), 0 8px 24px -4px rgba(17, 17, 17, 0.08),
133
+ 0 16px 48px -8px rgba(17, 17, 17, 0.1), 0 32px 96px -16px rgba(17, 17, 17, 0.08),
134
+ 0 0 0 0.5px rgba(17, 17, 17, 0.048), inset 0 3px 3px -2px rgba(255, 255, 255, 1);
135
+ --card-dark:
136
+ radial-gradient(90% 60% at 50% 0%, rgba(255, 255, 255, 0.06), transparent 75%),
137
+ radial-gradient(140% 100% at 30% 0%, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0) 65%),
138
+ linear-gradient(180deg, #121212 0%, #0a0a0a 100%);
139
+ /* Same lift as the light card — only the material changes, not the height */
140
+ --card-dark-shadow:
141
+ 0 0 0 0.5px rgba(0, 0, 0, 0.33), 0 1px 3px rgba(17, 17, 17, 0.12),
142
+ 0 4px 12px -2px rgba(17, 17, 17, 0.14), 0 12px 28px -8px rgba(17, 17, 17, 0.2),
143
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.075);
144
+ --card-dark-shadow-hover:
145
+ 0 0 0 0.5px rgba(0, 0, 0, 0.54), 0 2px 6px rgba(17, 17, 17, 0.14),
146
+ 0 10px 28px -6px rgba(17, 17, 17, 0.22), 0 28px 64px -16px rgba(17, 17, 17, 0.22),
147
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.09);
148
+
149
+ /* Card chassis is nearly the face's own tone — the hairline separator
150
+ between them does the dividing, not a change of colour. */
151
+ --card-bezel-light: linear-gradient(180deg, #fdfdfd 0%, #f7f7f7 100%);
152
+ --card-face-light-shadow:
153
+ 0 0 0 0.5px rgba(17, 17, 17, 0.042), 0 1px 2px rgba(17, 17, 17, 0.04),
154
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1);
155
+ --card-bezel-dark: linear-gradient(180deg, #151515 0%, #0e0e0e 100%);
156
+ --card-face-dark-shadow:
157
+ 0 0 0 0.5px rgba(255, 255, 255, 0.042), 0 1px 2px rgba(0, 0, 0, 0.4),
158
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.045);
159
+
160
+ /* Empty media slots: a whisper darker than the face they sit in */
161
+ --media-well-light: linear-gradient(180deg, rgba(17, 17, 17, 0.025) 0%, rgba(17, 17, 17, 0.04) 100%);
162
+ --media-well-dark: linear-gradient(180deg, rgba(0, 0, 0, 0.18) 0%, rgba(0, 0, 0, 0.26) 100%);
163
+
164
+ /* Icon tiles on cards — small raised faces */
165
+ --tile-light-shadow:
166
+ 0 0 3px rgba(17, 17, 17, 0.102), 0 1px 2px rgba(17, 17, 17, 0.08),
167
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1);
168
+ --tile-dark: linear-gradient(180deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.04) 100%);
169
+ --tile-dark-shadow:
170
+ 0 0 0 0.5px rgba(255, 255, 255, 0.048), 0 2px 6px rgba(0, 0, 0, 0.35),
171
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.09);
172
+
173
+ /* The dark card's own details (what theme="dark" wears on any page) */
174
+ --card-dark-rim: rgba(255, 255, 255, 0.1);
175
+ --divider-dark: rgba(255, 255, 255, 0.07);
176
+ --media-dots-dark: rgba(255, 255, 255, 0.09);
177
+ --media-dots-on-colour: rgba(255, 255, 255, 0.22);
178
+ --spark-dark: #ffffff;
179
+ --spark-dark-halo: rgba(255, 255, 255, 0.14);
180
+ --photo-edge-dark: rgba(255, 255, 255, 0.084);
181
+
182
+ /* Status tiles: coloured faces, lit like every other face */
183
+ --tile-success: linear-gradient(180deg, #10b981 0%, #059669 100%);
184
+ --tile-warning: linear-gradient(180deg, #fbbf24 0%, #f59e0b 100%);
185
+ --tile-error: linear-gradient(180deg, #f87171 0%, #dc2626 100%);
186
+ --tile-status-shadow:
187
+ 0 0 3px rgba(0, 0, 0, 0.212), 0 1px 2px rgba(0, 0, 0, 0.15),
188
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.188);
189
+ --lamp-success: #10b981;
190
+ --lamp-warning: #f59e0b;
191
+ --lamp-accent: #8b5cf6;
192
+ --lamp-lip: inset 0 1px 1px rgba(255, 255, 255, 0.35);
193
+
194
+ /* Violet: the accent banner, in the same build as the primary key */
195
+ --bezel-violet: linear-gradient(180deg, #4c2a99 0%, #2e1065 100%);
196
+ --bezel-violet-shadow:
197
+ 0 0 0 0.5px rgba(46, 16, 101, 0.36), 0 4px 12px -4px rgba(76, 29, 149, 0.45),
198
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.09);
199
+ --face-violet: linear-gradient(180deg, #7c3aed 0%, #6d28d9 100%);
200
+ --face-violet-shadow:
201
+ 0 0 3px rgba(46, 16, 101, 0.35), 0 1px 2px rgba(46, 16, 101, 0.4),
202
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.165);
203
+ }
204
+
205
+ /* ── Theme roles ─────────────────────────────────────────────────── */
206
+ /* What the components read. Light points each role at a material above;
207
+ dark (below) gives each its own value. To re-brand, override these on
208
+ :root (and in the dark block); the materials can stay as they are. */
209
+ :root,
210
+ .light,
211
+ [data-theme='light'] {
212
+ /* Surfaces */
213
+ --page: #ebebeb;
214
+ --panel-face: #ffffff;
215
+ --panel-tray: linear-gradient(180deg, #fafafa 0%, #f6f6f6 100%);
216
+ --palette-tray: linear-gradient(180deg, #fcfcfc 0%, #f8f8f8 100%);
217
+ --surface-hover: oklch(98.5% 0 0);
218
+ --surface-active: oklch(97% 0 0);
219
+ --line: oklch(97% 0 0);
220
+ --line-strong: oklch(92.2% 0 0);
221
+ --hairline: rgba(17, 17, 17, 0.06);
222
+ --divider: rgba(17, 17, 17, 0.07);
223
+ --groove: color-mix(in oklab, oklch(20.5% 0 0) 8%, transparent);
224
+ --groove-lip: 1px 0 0 rgba(255, 255, 255, 0.9);
225
+ --groove-lip-below: 0 1px 0 rgba(255, 255, 255, 0.9);
226
+ --scrollbar: rgba(17, 17, 17, 0.15);
227
+ --dots: rgba(17, 17, 17, 0.07);
228
+ --shimmer: rgba(255, 255, 255, 0.55);
229
+ --sheen: rgba(255, 255, 255, 0.75);
230
+ --halo: 0 0 0 4px rgba(17, 17, 17, 0.06), 0 0 0 5px rgba(17, 17, 17, 0.03);
231
+ --focus-ring-inset: inset 0 0 0 2px rgba(17, 17, 17, 0.85);
232
+
233
+ /* Ink: text and icons, strongest to faintest */
234
+ --ink-strong: oklch(14.5% 0 0);
235
+ --ink: oklch(20.5% 0 0);
236
+ --ink-soft: oklch(26.9% 0 0);
237
+ --ink-label: oklch(37.1% 0 0);
238
+ --ink-body: oklch(43.9% 0 0);
239
+ --ink-muted: oklch(55.6% 0 0);
240
+ --ink-faint: oklch(70.8% 0 0);
241
+ --ink-ghost: oklch(87% 0 0);
242
+ /* Ink on the inverse face: primary keys, checked boxes, tooltips */
243
+ --ink-inverse: #ffffff;
244
+ /* Letterpress: text pressed into a raised face, lit from above */
245
+ --emboss: 0 1px 0 rgba(255, 255, 255, 0.9);
246
+ --emboss-soft: 0 1px 0 rgba(255, 255, 255, 0.7);
247
+ --emboss-inverse: 0 -1px 0 rgba(0, 0, 0, 0.4);
248
+ --emboss-inverse-deep: 0 -1px 0 rgba(0, 0, 0, 0.45);
249
+
250
+ /* Status */
251
+ --danger: oklch(57.7% 0.245 27.325);
252
+ --danger-soft: oklch(63.7% 0.237 25.331);
253
+ --danger-wash: oklch(97.1% 0.013 17.38);
254
+ --success: oklch(50.8% 0.118 165.612);
255
+ --success-soft: oklch(59.6% 0.145 163.225);
256
+ --success-strong: #047857;
257
+ --warning: oklch(66.6% 0.179 58.318);
258
+ --warning-ink: oklch(41.4% 0.112 45.904);
259
+ --accent: oklch(49.1% 0.27 292.581);
260
+ --accent-soft: oklch(54.1% 0.281 293.009);
261
+ --code-keyword: oklch(54.1% 0.281 293.009);
262
+ --code-string: oklch(50.8% 0.118 165.612);
263
+ --code-tag: oklch(50% 0.134 242.749);
264
+ --code-number: oklch(55.5% 0.163 48.998);
265
+ --lamp-default: #262626;
266
+
267
+ /* Raised: the everyday key (secondary buttons, thumbs, knobs, tiles) */
268
+ --bezel: var(--bezel-light);
269
+ --bezel-shadow: var(--bezel-light-shadow);
270
+ --face: var(--face-light);
271
+ --face-shadow: var(--face-light-shadow);
272
+ --face-shadow-hover: var(--face-light-shadow-hover);
273
+ --face-pressed: var(--face-light-pressed);
274
+ --face-float-shadow: var(--face-light-float-shadow);
275
+ --face-drop: 0 6px 16px -6px rgba(17, 17, 17, 0.15);
276
+ --tile: var(--face-light);
277
+ --tile-shadow: var(--tile-light-shadow);
278
+ --thumb-shadow:
279
+ 0 0 3px rgba(17, 17, 17, 0.102), 0 1px 2px rgba(17, 17, 17, 0.1),
280
+ 0 2px 6px -2px rgba(17, 17, 17, 0.08), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
281
+ --key-shadow:
282
+ 0 0 3px rgba(17, 17, 17, 0.136), 0 1.5px 1px rgba(17, 17, 17, 0.12),
283
+ 0 2px 3px -1px rgba(17, 17, 17, 0.1), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
284
+ --knob-shadow:
285
+ 0 0 3px rgba(17, 17, 17, 0.119), 0 1px 2px rgba(0, 0, 0, 0.14),
286
+ 0 3px 6px -1px rgba(0, 0, 0, 0.12), inset 0 2px 3px -2px rgba(255, 255, 255, 1),
287
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.04);
288
+
289
+ /* Inverse: the opposite of the page (primary, checked, selected) */
290
+ --bezel-inverse: var(--bezel-dark);
291
+ --bezel-inverse-shadow: var(--bezel-dark-shadow);
292
+ --face-inverse: var(--face-dark);
293
+ --face-inverse-shadow: var(--face-dark-shadow);
294
+ --face-inverse-shadow-hover: var(--face-dark-shadow-hover);
295
+ --face-inverse-pressed: var(--face-dark-pressed);
296
+ --face-inverse-float-shadow: var(--face-dark-float-shadow);
297
+ --inverse-lip: rgba(255, 255, 255, 0.12);
298
+ --dot-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);
299
+ --fill-shadow: inset 0 2px 3px -2px rgba(255, 255, 255, 0.135), 0 0 2px rgba(0, 0, 0, 0.2);
300
+ --tooltip-shadow:
301
+ 0 0 3px rgba(0, 0, 0, 0.35), 0 2px 6px rgba(0, 0, 0, 0.22),
302
+ 0 8px 24px -4px rgba(0, 0, 0, 0.3), inset 0 2px 3px -2px rgba(255, 255, 255, 0.105);
303
+ --badge-inverse-shadow:
304
+ 0 0 3px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.2),
305
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.105);
306
+ --progress-bar: linear-gradient(90deg, #0a0a0a 0%, #262626 100%);
307
+ --banner-bezel: var(--bezel-dark);
308
+ --banner-bezel-shadow: var(--bezel-dark-shadow);
309
+ --banner-face: var(--face-dark);
310
+ --banner-face-shadow: var(--face-dark-shadow);
311
+ --progress-bar-glow: 0 0 8px rgba(17, 17, 17, 0.3);
312
+
313
+ /* Outline and ghost keys */
314
+ --outline-bezel: linear-gradient(180deg, rgba(255, 255, 255, 0.5) 0%, rgba(17, 17, 17, 0.04) 100%);
315
+ --outline-bezel-shadow: 0 0 0 0.5px rgba(17, 17, 17, 0.048), inset 0 2px 3px -2px rgba(255, 255, 255, 0.45);
316
+ --outline-face-shadow:
317
+ 0 0 3px rgba(17, 17, 17, 0.102), 0 1px 1px rgba(17, 17, 17, 0.06),
318
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1);
319
+ --outline-face-shadow-hover:
320
+ 0 0 3px rgba(17, 17, 17, 0.136), 0 1px 2px rgba(17, 17, 17, 0.08),
321
+ 0 3px 6px -2px rgba(17, 17, 17, 0.06), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
322
+ --outline-shadow: inset 0 0 2px rgba(17, 17, 17, 0.15);
323
+ --outline-shadow-hover: inset 0 0 2px rgba(17, 17, 17, 0.24), 0 1px 2px rgba(17, 17, 17, 0.05);
324
+ --outline-shadow-pressed: inset 0 0 2px rgba(17, 17, 17, 0.24), inset 0 1px 2px rgba(17, 17, 17, 0.06);
325
+ --ghost-shadow-hover: inset 0 0 2px rgba(17, 17, 17, 0.09);
326
+ --ghost-shadow-pressed: inset 0 1px 2px rgba(17, 17, 17, 0.08);
327
+
328
+ /* Badges */
329
+ --badge: linear-gradient(180deg, #ffffff 0%, #f1f1f1 100%);
330
+ --badge-shadow:
331
+ 0 0 3px rgba(17, 17, 17, 0.119), 0 1px 1.5px rgba(17, 17, 17, 0.07),
332
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1);
333
+ --badge-accent: linear-gradient(180deg, #f5f0ff 0%, #ebe1ff 100%);
334
+ --badge-accent-shadow:
335
+ 0 0 3px rgba(124, 58, 237, 0.255), 0 1px 1.5px rgba(124, 58, 237, 0.12),
336
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.637);
337
+
338
+ /* The warning banner: an amber bezel holding a pale amber face */
339
+ --bezel-warning: linear-gradient(180deg, #fde68a 0%, #f5c84b 100%);
340
+ --bezel-warning-shadow:
341
+ 0 0 0 0.5px rgba(180, 83, 9, 0.15), 0 4px 12px -4px rgba(217, 119, 6, 0.3),
342
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.45);
343
+ --face-warning: linear-gradient(180deg, #fffbeb 0%, #fef3c7 100%);
344
+ --face-warning-shadow:
345
+ 0 0 3px rgba(180, 83, 9, 0.255), 0 1px 2px rgba(180, 83, 9, 0.12),
346
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1);
347
+
348
+ /* Fields — sunken: darker at the top, shade inside, a lit lip below.
349
+ Raised means "press me", sunken means "fill me".
350
+
351
+ Every state has the same five layers (edge, shade, lip, border, halo)
352
+ so box-shadow interpolates between them instead of snapping: hover
353
+ hints at the halo, focus lifts the well flush and draws the border. */
354
+ --field-from: #f2f2f2;
355
+ --field-to: #f8f8f8;
356
+ --field-hover-from: #eeeeee;
357
+ --field-hover-to: #f5f5f5;
358
+ --field-focus: #ffffff;
359
+ --field: linear-gradient(180deg, #f2f2f2 0%, #f8f8f8 100%);
360
+ --field-hover: linear-gradient(180deg, #eeeeee 0%, #f5f5f5 100%);
361
+ --field-shadow:
362
+ inset 0 0 2px rgba(17, 17, 17, 0.15), inset 0 1px 2px rgba(17, 17, 17, 0.06),
363
+ 0 1px 2px -1px rgba(255, 255, 255, 0.72), inset 0 0 0 1px rgba(17, 17, 17, 0),
364
+ 0 0 0 0 rgba(17, 17, 17, 0);
365
+ --field-shadow-hover:
366
+ inset 0 0 2px rgba(17, 17, 17, 0.25), inset 0 1px 2px rgba(17, 17, 17, 0.07),
367
+ 0 1px 2px -1px rgba(255, 255, 255, 0.72), inset 0 0 0 1px rgba(17, 17, 17, 0.04),
368
+ 0 0 0 3px rgba(17, 17, 17, 0.025);
369
+ --field-shadow-focus:
370
+ inset 0 0 2px rgba(17, 17, 17, 0.06), inset 0 1px 2px rgba(17, 17, 17, 0.02),
371
+ 0 1px 2px -1px rgba(255, 255, 255, 0), inset 0 0 0 1px rgba(17, 17, 17, 0.42),
372
+ 0 0 0 4px rgba(17, 17, 17, 0.07);
373
+ --field-shadow-error:
374
+ inset 0 0 2px rgba(220, 38, 38, 0.3), inset 0 1px 2px rgba(220, 38, 38, 0.06),
375
+ 0 1px 2px -1px rgba(255, 255, 255, 0.72), inset 0 0 0 1px rgba(220, 38, 38, 0),
376
+ 0 0 0 0 rgba(220, 38, 38, 0);
377
+ --field-shadow-error-hover:
378
+ inset 0 0 2px rgba(220, 38, 38, 0.4), inset 0 1px 2px rgba(220, 38, 38, 0.08),
379
+ 0 1px 2px -1px rgba(255, 255, 255, 0.72), inset 0 0 0 1px rgba(220, 38, 38, 0.08),
380
+ 0 0 0 3px rgba(220, 38, 38, 0.04);
381
+ --field-shadow-error-focus:
382
+ inset 0 0 2px rgba(220, 38, 38, 0.1), inset 0 1px 2px rgba(220, 38, 38, 0.02),
383
+ 0 1px 2px -1px rgba(255, 255, 255, 0), inset 0 0 0 1px rgba(220, 38, 38, 0.7),
384
+ 0 0 0 4px rgba(220, 38, 38, 0.1);
385
+ /* A switch's channel: recessed when off, filled with the inverse when on */
386
+ --track: color-mix(in oklab, oklch(92.2% 0 0) 70%, transparent);
387
+ --track-shadow:
388
+ inset 0 1px 2px rgba(17, 17, 17, 0.12), inset 0 0 2px rgba(17, 17, 17, 0.12),
389
+ 0 1px 2px -1px rgba(255, 255, 255, 0.64);
390
+ --track-on: oklch(20.5% 0 0);
391
+ --track-on-shadow:
392
+ inset 0 1px 3px rgba(0, 0, 0, 0.5), inset 0 0 2px rgba(0, 0, 0, 0.3),
393
+ 0 1px 2px -1px rgba(255, 255, 255, 0.48);
394
+
395
+ /* Wells hold a sliding thumb (tabs, pagination, segmented controls) */
396
+ --well: linear-gradient(180deg, #ebebeb 0%, #f1f1f1 100%);
397
+ --well-shadow:
398
+ inset 0 0 2px rgba(17, 17, 17, 0.09), inset 0 1px 2px rgba(17, 17, 17, 0.08),
399
+ 0 1px 2px -1px rgba(255, 255, 255, 0.72);
400
+
401
+ /* Panels — a soft bezel holding a white face (lists, menus, alerts) */
402
+ --panel-bezel: linear-gradient(180deg, #fbfbfb 0%, #f0f0f0 100%);
403
+ --panel-shadow:
404
+ 0 0 0 0.5px rgba(17, 17, 17, 0.036), 0 1px 2px rgba(17, 17, 17, 0.04),
405
+ 0 4px 12px -4px rgba(17, 17, 17, 0.08), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
406
+ --panel-face-shadow:
407
+ 0 0 3px rgba(17, 17, 17, 0.076), 0 1px 2px rgba(17, 17, 17, 0.05),
408
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1);
409
+ /* Panels that float above the page cast further */
410
+ --overlay-shadow:
411
+ 0 0 0 0.5px rgba(17, 17, 17, 0.048), 0 4px 12px -4px rgba(17, 17, 17, 0.12),
412
+ 0 16px 40px -12px rgba(17, 17, 17, 0.2), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
413
+ --modal-shadow:
414
+ 0 0 0 0.5px rgba(17, 17, 17, 0.048), 0 8px 24px -8px rgba(17, 17, 17, 0.2),
415
+ 0 32px 80px -16px rgba(17, 17, 17, 0.32), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
416
+ --scrim: rgba(10, 10, 10, 0.4);
417
+
418
+ /* Cards */
419
+ --card: var(--card-light);
420
+ --card-bezel: var(--card-bezel-light);
421
+ --card-shadow: var(--card-light-shadow);
422
+ --card-shadow-hover: var(--card-light-shadow-hover);
423
+ --card-face-shadow: var(--card-face-light-shadow);
424
+ --card-rim: rgba(255, 255, 255, 1);
425
+ --rim-default: rgba(255, 255, 255, 0.9);
426
+ --media-well: var(--media-well-light);
427
+ --media-dots: rgba(17, 17, 17, 0.09);
428
+ --slide-dots: rgba(17, 17, 17, 0.08);
429
+ --spark: #171717;
430
+ --spark-halo: rgba(17, 17, 17, 0.08);
431
+ --photo-edge: rgba(17, 17, 17, 0.048);
432
+ --cover:
433
+ radial-gradient(130% 90% at 25% 0%, rgba(255, 255, 255, 0.7), transparent 60%),
434
+ linear-gradient(180deg, #ececeb 0%, #f4f4f3 100%);
435
+ --cover-shadow: inset 0 1px 3px rgba(17, 17, 17, 0.06), inset 0 -2px 3px -2px rgba(17, 17, 17, 0.05);
436
+ --avatar-lift: 0 3px 12px -2px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05);
437
+ --avatar-rim:
438
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.45), inset 0 0 2px rgba(17, 17, 17, 0.12),
439
+ inset 0 -2px 3px -2px rgba(17, 17, 17, 0.04);
440
+ }
441
+
442
+ /* Dark: the same objects under the same lamp, in darker materials.
443
+ Primary: data-theme="dark". The class "dark" does the same, for setups
444
+ (next-themes, Tailwind's class strategy) that toggle a class.
445
+ Keep this block and the system one below in step. */
446
+ .dark,
447
+ [data-theme='dark'] {
448
+ color-scheme: dark;
449
+ /* Surfaces: the page is the deepest layer (never pure black); each
450
+ thing raised off it is a step lighter, each well cut into it a step
451
+ darker. The lamp hasn't moved: highlights stay on top edges. */
452
+ --page: #111111;
453
+ --panel-face: #202020;
454
+ --panel-tray: linear-gradient(180deg, #1b1b1b 0%, #191919 100%);
455
+ --palette-tray: linear-gradient(180deg, #1d1d1d 0%, #1b1b1b 100%);
456
+ --surface-hover: #262626;
457
+ --surface-active: #2b2b2b;
458
+ --line: rgba(255, 255, 255, 0.06);
459
+ --line-strong: rgba(255, 255, 255, 0.1);
460
+ --hairline: rgba(255, 255, 255, 0.06);
461
+ --divider: rgba(255, 255, 255, 0.07);
462
+ --groove: rgba(0, 0, 0, 0.45);
463
+ --groove-lip: 1px 0 0 rgba(255, 255, 255, 0.06);
464
+ --groove-lip-below: 0 1px 0 rgba(255, 255, 255, 0.06);
465
+ --scrollbar: rgba(255, 255, 255, 0.16);
466
+ --dots: rgba(255, 255, 255, 0.07);
467
+ --shimmer: rgba(255, 255, 255, 0.07);
468
+ --sheen: rgba(255, 255, 255, 0.06);
469
+ --halo: 0 0 0 4px rgba(255, 255, 255, 0.07), 0 0 0 5px rgba(255, 255, 255, 0.035);
470
+ --focus-ring-inset: inset 0 0 0 2px rgba(245, 245, 245, 0.8);
471
+
472
+ /* Ink */
473
+ --ink-strong: #ffffff;
474
+ --ink: oklch(97% 0 0);
475
+ --ink-soft: oklch(92.2% 0 0);
476
+ --ink-label: oklch(87% 0 0);
477
+ --ink-body: oklch(80% 0 0);
478
+ --ink-muted: oklch(70.8% 0 0);
479
+ --ink-faint: oklch(58% 0 0);
480
+ --ink-ghost: oklch(42% 0 0);
481
+ --ink-inverse: oklch(20.5% 0 0);
482
+ --emboss: 0 -1px 0 rgba(0, 0, 0, 0.4);
483
+ --emboss-soft: 0 -1px 0 rgba(0, 0, 0, 0.3);
484
+ --emboss-inverse: 0 1px 0 rgba(255, 255, 255, 0.55);
485
+ --emboss-inverse-deep: 0 1px 0 rgba(255, 255, 255, 0.6);
486
+
487
+ /* Status: the same hues, a few steps lighter to read on dark */
488
+ --danger: oklch(70.4% 0.191 22.216);
489
+ --danger-soft: oklch(70.4% 0.191 22.216);
490
+ --danger-wash: rgba(239, 68, 68, 0.12);
491
+ --success: oklch(76.5% 0.177 163.223);
492
+ --success-soft: oklch(76.5% 0.177 163.223);
493
+ --success-strong: oklch(76.5% 0.177 163.223);
494
+ --warning: oklch(82.8% 0.189 84.429);
495
+ --warning-ink: oklch(92.4% 0.12 95.746);
496
+ --accent: oklch(81.1% 0.111 293.571);
497
+ --accent-soft: oklch(70.2% 0.183 293.541);
498
+ --code-keyword: oklch(76% 0.14 293.5);
499
+ --code-string: oklch(78% 0.15 163);
500
+ --code-tag: oklch(78% 0.12 232.7);
501
+ --code-number: oklch(80% 0.15 70);
502
+ --lamp-default: #e5e5e5;
503
+
504
+ /* Raised: the mid material — the secondary key he drew for dark cards */
505
+ --bezel: var(--bezel-mid);
506
+ --bezel-shadow: var(--bezel-mid-shadow);
507
+ --face: var(--face-mid);
508
+ --face-shadow: var(--face-mid-shadow);
509
+ --face-shadow-hover: var(--face-mid-shadow-hover);
510
+ --face-pressed: var(--face-dark-pressed);
511
+ --face-float-shadow: var(--face-mid-float-shadow);
512
+ --face-drop: 0 6px 16px -6px rgba(0, 0, 0, 0.6);
513
+ --tile: var(--tile-dark);
514
+ --tile-shadow: var(--tile-dark-shadow);
515
+ --thumb-shadow:
516
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.45),
517
+ 0 2px 6px -2px rgba(0, 0, 0, 0.45), inset 0 2px 3px -2px rgba(255, 255, 255, 0.1);
518
+ --key-shadow:
519
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 1.5px 1px rgba(0, 0, 0, 0.55),
520
+ 0 2px 3px -1px rgba(0, 0, 0, 0.45), inset 0 2px 3px -2px rgba(255, 255, 255, 0.1);
521
+ --knob-shadow:
522
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.45),
523
+ 0 3px 6px -1px rgba(0, 0, 0, 0.35), inset 0 2px 3px -2px rgba(255, 255, 255, 0.14),
524
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.2);
525
+
526
+ /* Inverse: a pale key on the dark page, toned down so it doesn't glare */
527
+ --bezel-inverse: linear-gradient(180deg, #e4e4e4 0%, #a9a9a9 100%);
528
+ --bezel-inverse-shadow:
529
+ 0 0 0 0.5px rgba(0, 0, 0, 0.6), 0 1px 1px rgba(0, 0, 0, 0.4),
530
+ 0 4px 12px -4px rgba(0, 0, 0, 0.6), inset 0 2px 3px -2px rgba(255, 255, 255, 0.9),
531
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.12);
532
+ --face-inverse: linear-gradient(180deg, #f2f2f2 0%, #e6e6e6 55%, #d9d9d9 100%);
533
+ --face-inverse-shadow:
534
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 4px -1px rgba(0, 0, 0, 0.4),
535
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1), inset 0 -2px 3px -2px rgba(0, 0, 0, 0.1);
536
+ --face-inverse-shadow-hover:
537
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 2px 3px rgba(0, 0, 0, 0.45),
538
+ 0 4px 8px -2px rgba(0, 0, 0, 0.4), inset 0 2px 3px -2px rgba(255, 255, 255, 1),
539
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.1);
540
+ --face-inverse-pressed: 0 0 3px rgba(0, 0, 0, 0.5), inset 0 1px 2px rgba(0, 0, 0, 0.22);
541
+ --face-inverse-float-shadow:
542
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 2px 4px rgba(0, 0, 0, 0.45),
543
+ 0 6px 14px -4px rgba(0, 0, 0, 0.45), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
544
+ --inverse-lip: rgba(255, 255, 255, 0.6);
545
+ --dot-shadow: 0 1px 0 rgba(255, 255, 255, 0.45);
546
+ --fill-shadow: inset 0 2px 3px -2px rgba(255, 255, 255, 0.9), 0 0 2px rgba(0, 0, 0, 0.5);
547
+ --tooltip-shadow:
548
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.45),
549
+ 0 8px 24px -4px rgba(0, 0, 0, 0.55), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
550
+ --badge-inverse-shadow:
551
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4),
552
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1);
553
+ --progress-bar: linear-gradient(90deg, #8a8a8a 0%, #ededed 100%);
554
+ --banner-bezel: var(--bezel-mid);
555
+ --banner-bezel-shadow: var(--bezel-mid-shadow);
556
+ --banner-face: var(--face-mid);
557
+ --banner-face-shadow: var(--face-mid-shadow);
558
+ --progress-bar-glow: 0 0 8px rgba(255, 255, 255, 0.18);
559
+
560
+ /* Outline and ghost keys */
561
+ --outline-bezel: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(0, 0, 0, 0.3) 100%);
562
+ --outline-bezel-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.5), inset 0 2px 3px -2px rgba(255, 255, 255, 0.06);
563
+ --outline-face-shadow:
564
+ 0 0 3px rgba(0, 0, 0, 0.4), 0 1px 1px rgba(0, 0, 0, 0.35),
565
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.09);
566
+ --outline-face-shadow-hover:
567
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.4),
568
+ 0 3px 6px -2px rgba(0, 0, 0, 0.35), inset 0 2px 3px -2px rgba(255, 255, 255, 0.12);
569
+ --outline-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1), inset 0 0 2px rgba(0, 0, 0, 0.5);
570
+ --outline-shadow-hover:
571
+ inset 0 0 0 1px rgba(255, 255, 255, 0.16), inset 0 0 2px rgba(0, 0, 0, 0.5),
572
+ 0 1px 2px rgba(0, 0, 0, 0.3);
573
+ --outline-shadow-pressed:
574
+ inset 0 0 0 1px rgba(255, 255, 255, 0.12), inset 0 1px 2px rgba(0, 0, 0, 0.5);
575
+ --ghost-shadow-hover: inset 0 0 2px rgba(0, 0, 0, 0.5);
576
+ --ghost-shadow-pressed: inset 0 1px 2px rgba(0, 0, 0, 0.55);
577
+
578
+ /* Badges */
579
+ --badge: linear-gradient(180deg, #333333 0%, #2a2a2a 100%);
580
+ --badge-shadow:
581
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 1.5px rgba(0, 0, 0, 0.4),
582
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.1);
583
+ --badge-accent: linear-gradient(180deg, #33245c 0%, #2a1e4c 100%);
584
+ --badge-accent-shadow:
585
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 0 0 0.5px rgba(167, 139, 250, 0.22),
586
+ 0 1px 1.5px rgba(0, 0, 0, 0.4), inset 0 2px 3px -2px rgba(196, 181, 253, 0.25);
587
+
588
+ /* The warning banner, as a dark amber face */
589
+ --bezel-warning: linear-gradient(180deg, #5c4310 0%, #33240a 100%);
590
+ --bezel-warning-shadow:
591
+ 0 0 0 0.5px rgba(0, 0, 0, 0.5), 0 4px 12px -4px rgba(0, 0, 0, 0.55),
592
+ inset 0 2px 3px -2px rgba(253, 230, 138, 0.18);
593
+ --face-warning: linear-gradient(180deg, #3d2e0f 0%, #33260b 100%);
594
+ --face-warning-shadow:
595
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.4),
596
+ inset 0 2px 3px -2px rgba(253, 230, 138, 0.16);
597
+
598
+ /* Fields: a step darker than whatever holds them */
599
+ --field-from: #090909;
600
+ --field-to: #0d0d0d;
601
+ --field-hover-from: #070707;
602
+ --field-hover-to: #0b0b0b;
603
+ --field-focus: #151515;
604
+ --field: linear-gradient(180deg, #090909 0%, #0d0d0d 100%);
605
+ --field-hover: linear-gradient(180deg, #070707 0%, #0b0b0b 100%);
606
+ --field-shadow:
607
+ inset 0 0 2px rgba(0, 0, 0, 0.7), inset 0 1px 2px rgba(0, 0, 0, 0.5),
608
+ 0 1px 2px -1px rgba(255, 255, 255, 0.1), inset 0 0 0 1px rgba(255, 255, 255, 0.09),
609
+ 0 0 0 0 rgba(255, 255, 255, 0);
610
+ --field-shadow-hover:
611
+ inset 0 0 2px rgba(0, 0, 0, 0.8), inset 0 1px 2px rgba(0, 0, 0, 0.55),
612
+ 0 1px 2px -1px rgba(255, 255, 255, 0.1), inset 0 0 0 1px rgba(255, 255, 255, 0.12),
613
+ 0 0 0 3px rgba(255, 255, 255, 0.025);
614
+ --field-shadow-focus:
615
+ inset 0 0 2px rgba(0, 0, 0, 0.3), inset 0 1px 2px rgba(0, 0, 0, 0.2),
616
+ 0 1px 2px -1px rgba(255, 255, 255, 0), inset 0 0 0 1px rgba(255, 255, 255, 0.42),
617
+ 0 0 0 4px rgba(255, 255, 255, 0.07);
618
+ --field-shadow-error:
619
+ inset 0 0 2px rgba(248, 113, 113, 0.45), inset 0 1px 2px rgba(0, 0, 0, 0.5),
620
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09), inset 0 0 0 1px rgba(248, 113, 113, 0),
621
+ 0 0 0 0 rgba(248, 113, 113, 0);
622
+ --field-shadow-error-hover:
623
+ inset 0 0 2px rgba(248, 113, 113, 0.6), inset 0 1px 2px rgba(0, 0, 0, 0.55),
624
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09), inset 0 0 0 1px rgba(248, 113, 113, 0.12),
625
+ 0 0 0 3px rgba(248, 113, 113, 0.05);
626
+ --field-shadow-error-focus:
627
+ inset 0 0 2px rgba(248, 113, 113, 0.15), inset 0 1px 2px rgba(0, 0, 0, 0.2),
628
+ 0 1px 2px -1px rgba(255, 255, 255, 0), inset 0 0 0 1px rgba(248, 113, 113, 0.7),
629
+ 0 0 0 4px rgba(248, 113, 113, 0.12);
630
+ --track: rgba(0, 0, 0, 0.4);
631
+ --track-shadow:
632
+ inset 0 1px 2px rgba(0, 0, 0, 0.6), inset 0 0 2px rgba(0, 0, 0, 0.6),
633
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09);
634
+ --track-on: #e6e6e6;
635
+ --track-on-shadow:
636
+ inset 0 1px 3px rgba(0, 0, 0, 0.35), inset 0 0 2px rgba(0, 0, 0, 0.25),
637
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09);
638
+
639
+ /* Wells */
640
+ --well: linear-gradient(180deg, #0a0a0a 0%, #0e0e0e 100%);
641
+ --well-shadow:
642
+ inset 0 0 2px rgba(0, 0, 0, 0.7), inset 0 1px 2px rgba(0, 0, 0, 0.6),
643
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09), inset 0 0 0 1px rgba(255, 255, 255, 0.03);
644
+
645
+ /* Panels */
646
+ --panel-bezel: linear-gradient(180deg, #1c1c1c 0%, #161616 100%);
647
+ --panel-shadow:
648
+ 0 0 0 0.5px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.4),
649
+ 0 4px 12px -4px rgba(0, 0, 0, 0.5), inset 0 2px 3px -2px rgba(255, 255, 255, 0.07);
650
+ --panel-face-shadow:
651
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4),
652
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.08);
653
+ --overlay-shadow:
654
+ 0 0 0 0.5px rgba(0, 0, 0, 0.7), 0 4px 12px -4px rgba(0, 0, 0, 0.55),
655
+ 0 16px 40px -12px rgba(0, 0, 0, 0.7), inset 0 2px 3px -2px rgba(255, 255, 255, 0.07);
656
+ --modal-shadow:
657
+ 0 0 0 0.5px rgba(0, 0, 0, 0.7), 0 8px 24px -8px rgba(0, 0, 0, 0.6),
658
+ 0 32px 80px -16px rgba(0, 0, 0, 0.8), inset 0 2px 3px -2px rgba(255, 255, 255, 0.07);
659
+ --scrim: rgba(0, 0, 0, 0.6);
660
+
661
+ /* Cards: his dark card, lifted a few steps so it rises off the page */
662
+ --card:
663
+ radial-gradient(90% 60% at 50% 0%, rgba(255, 255, 255, 0.05), transparent 75%),
664
+ radial-gradient(140% 100% at 30% 0%, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0) 65%),
665
+ linear-gradient(180deg, #1a1a1a 0%, #141414 100%);
666
+ --card-bezel: linear-gradient(180deg, #1d1d1d 0%, #161616 100%);
667
+ --card-shadow:
668
+ 0 0 0 0.5px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.3),
669
+ 0 4px 12px -2px rgba(0, 0, 0, 0.35), 0 12px 28px -8px rgba(0, 0, 0, 0.45),
670
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.075);
671
+ --card-shadow-hover:
672
+ 0 0 0 0.5px rgba(0, 0, 0, 0.7), 0 2px 6px rgba(0, 0, 0, 0.35),
673
+ 0 10px 28px -6px rgba(0, 0, 0, 0.45), 0 28px 64px -16px rgba(0, 0, 0, 0.5),
674
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.09);
675
+ --card-face-shadow: var(--card-face-dark-shadow);
676
+ --card-rim: rgba(255, 255, 255, 0.1);
677
+ --rim-default: rgba(255, 255, 255, 0.1);
678
+ --media-well: var(--media-well-dark);
679
+ --media-dots: rgba(255, 255, 255, 0.09);
680
+ --slide-dots: rgba(255, 255, 255, 0.08);
681
+ --spark: #f5f5f5;
682
+ --spark-halo: rgba(255, 255, 255, 0.14);
683
+ --photo-edge: rgba(255, 255, 255, 0.084);
684
+ --cover:
685
+ radial-gradient(130% 90% at 25% 0%, rgba(255, 255, 255, 0.06), transparent 60%),
686
+ linear-gradient(180deg, #181818 0%, #1c1c1c 100%);
687
+ --cover-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.45), inset 0 -2px 3px -2px rgba(0, 0, 0, 0.3);
688
+ --avatar-lift: 0 3px 12px -2px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.3);
689
+ --avatar-rim:
690
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.5),
691
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.2);
692
+ }
693
+
694
+ /* Opt-in system preference: data-theme="system" follows the OS. An
695
+ explicit data-theme="light" (or "dark") on the page wins, so a toggle
696
+ can always override it. A copy of the dark block above. */
697
+ @media (prefers-color-scheme: dark) {
698
+ [data-theme='system'] {
699
+ color-scheme: dark;
700
+ /* Surfaces: the page is the deepest layer (never pure black); each
701
+ thing raised off it is a step lighter, each well cut into it a step
702
+ darker. The lamp hasn't moved: highlights stay on top edges. */
703
+ --page: #111111;
704
+ --panel-face: #202020;
705
+ --panel-tray: linear-gradient(180deg, #1b1b1b 0%, #191919 100%);
706
+ --palette-tray: linear-gradient(180deg, #1d1d1d 0%, #1b1b1b 100%);
707
+ --surface-hover: #262626;
708
+ --surface-active: #2b2b2b;
709
+ --line: rgba(255, 255, 255, 0.06);
710
+ --line-strong: rgba(255, 255, 255, 0.1);
711
+ --hairline: rgba(255, 255, 255, 0.06);
712
+ --divider: rgba(255, 255, 255, 0.07);
713
+ --groove: rgba(0, 0, 0, 0.45);
714
+ --groove-lip: 1px 0 0 rgba(255, 255, 255, 0.06);
715
+ --groove-lip-below: 0 1px 0 rgba(255, 255, 255, 0.06);
716
+ --scrollbar: rgba(255, 255, 255, 0.16);
717
+ --dots: rgba(255, 255, 255, 0.07);
718
+ --shimmer: rgba(255, 255, 255, 0.07);
719
+ --sheen: rgba(255, 255, 255, 0.06);
720
+ --halo: 0 0 0 4px rgba(255, 255, 255, 0.07), 0 0 0 5px rgba(255, 255, 255, 0.035);
721
+ --focus-ring-inset: inset 0 0 0 2px rgba(245, 245, 245, 0.8);
722
+
723
+ /* Ink */
724
+ --ink-strong: #ffffff;
725
+ --ink: oklch(97% 0 0);
726
+ --ink-soft: oklch(92.2% 0 0);
727
+ --ink-label: oklch(87% 0 0);
728
+ --ink-body: oklch(80% 0 0);
729
+ --ink-muted: oklch(70.8% 0 0);
730
+ --ink-faint: oklch(58% 0 0);
731
+ --ink-ghost: oklch(42% 0 0);
732
+ --ink-inverse: oklch(20.5% 0 0);
733
+ --emboss: 0 -1px 0 rgba(0, 0, 0, 0.4);
734
+ --emboss-soft: 0 -1px 0 rgba(0, 0, 0, 0.3);
735
+ --emboss-inverse: 0 1px 0 rgba(255, 255, 255, 0.55);
736
+ --emboss-inverse-deep: 0 1px 0 rgba(255, 255, 255, 0.6);
737
+
738
+ /* Status: the same hues, a few steps lighter to read on dark */
739
+ --danger: oklch(70.4% 0.191 22.216);
740
+ --danger-soft: oklch(70.4% 0.191 22.216);
741
+ --danger-wash: rgba(239, 68, 68, 0.12);
742
+ --success: oklch(76.5% 0.177 163.223);
743
+ --success-soft: oklch(76.5% 0.177 163.223);
744
+ --success-strong: oklch(76.5% 0.177 163.223);
745
+ --warning: oklch(82.8% 0.189 84.429);
746
+ --warning-ink: oklch(92.4% 0.12 95.746);
747
+ --accent: oklch(81.1% 0.111 293.571);
748
+ --accent-soft: oklch(70.2% 0.183 293.541);
749
+ --code-keyword: oklch(76% 0.14 293.5);
750
+ --code-string: oklch(78% 0.15 163);
751
+ --code-tag: oklch(78% 0.12 232.7);
752
+ --code-number: oklch(80% 0.15 70);
753
+ --lamp-default: #e5e5e5;
754
+
755
+ /* Raised: the mid material — the secondary key he drew for dark cards */
756
+ --bezel: var(--bezel-mid);
757
+ --bezel-shadow: var(--bezel-mid-shadow);
758
+ --face: var(--face-mid);
759
+ --face-shadow: var(--face-mid-shadow);
760
+ --face-shadow-hover: var(--face-mid-shadow-hover);
761
+ --face-pressed: var(--face-dark-pressed);
762
+ --face-float-shadow: var(--face-mid-float-shadow);
763
+ --face-drop: 0 6px 16px -6px rgba(0, 0, 0, 0.6);
764
+ --tile: var(--tile-dark);
765
+ --tile-shadow: var(--tile-dark-shadow);
766
+ --thumb-shadow:
767
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.45),
768
+ 0 2px 6px -2px rgba(0, 0, 0, 0.45), inset 0 2px 3px -2px rgba(255, 255, 255, 0.1);
769
+ --key-shadow:
770
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 1.5px 1px rgba(0, 0, 0, 0.55),
771
+ 0 2px 3px -1px rgba(0, 0, 0, 0.45), inset 0 2px 3px -2px rgba(255, 255, 255, 0.1);
772
+ --knob-shadow:
773
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.45),
774
+ 0 3px 6px -1px rgba(0, 0, 0, 0.35), inset 0 2px 3px -2px rgba(255, 255, 255, 0.14),
775
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.2);
776
+
777
+ /* Inverse: a pale key on the dark page, toned down so it doesn't glare */
778
+ --bezel-inverse: linear-gradient(180deg, #e4e4e4 0%, #a9a9a9 100%);
779
+ --bezel-inverse-shadow:
780
+ 0 0 0 0.5px rgba(0, 0, 0, 0.6), 0 1px 1px rgba(0, 0, 0, 0.4),
781
+ 0 4px 12px -4px rgba(0, 0, 0, 0.6), inset 0 2px 3px -2px rgba(255, 255, 255, 0.9),
782
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.12);
783
+ --face-inverse: linear-gradient(180deg, #f2f2f2 0%, #e6e6e6 55%, #d9d9d9 100%);
784
+ --face-inverse-shadow:
785
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 4px -1px rgba(0, 0, 0, 0.4),
786
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1), inset 0 -2px 3px -2px rgba(0, 0, 0, 0.1);
787
+ --face-inverse-shadow-hover:
788
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 2px 3px rgba(0, 0, 0, 0.45),
789
+ 0 4px 8px -2px rgba(0, 0, 0, 0.4), inset 0 2px 3px -2px rgba(255, 255, 255, 1),
790
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.1);
791
+ --face-inverse-pressed: 0 0 3px rgba(0, 0, 0, 0.5), inset 0 1px 2px rgba(0, 0, 0, 0.22);
792
+ --face-inverse-float-shadow:
793
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 2px 4px rgba(0, 0, 0, 0.45),
794
+ 0 6px 14px -4px rgba(0, 0, 0, 0.45), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
795
+ --inverse-lip: rgba(255, 255, 255, 0.6);
796
+ --dot-shadow: 0 1px 0 rgba(255, 255, 255, 0.45);
797
+ --fill-shadow: inset 0 2px 3px -2px rgba(255, 255, 255, 0.9), 0 0 2px rgba(0, 0, 0, 0.5);
798
+ --tooltip-shadow:
799
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.45),
800
+ 0 8px 24px -4px rgba(0, 0, 0, 0.55), inset 0 2px 3px -2px rgba(255, 255, 255, 1);
801
+ --badge-inverse-shadow:
802
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4),
803
+ inset 0 2px 3px -2px rgba(255, 255, 255, 1);
804
+ --progress-bar: linear-gradient(90deg, #8a8a8a 0%, #ededed 100%);
805
+ --banner-bezel: var(--bezel-mid);
806
+ --banner-bezel-shadow: var(--bezel-mid-shadow);
807
+ --banner-face: var(--face-mid);
808
+ --banner-face-shadow: var(--face-mid-shadow);
809
+ --progress-bar-glow: 0 0 8px rgba(255, 255, 255, 0.18);
810
+
811
+ /* Outline and ghost keys */
812
+ --outline-bezel: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(0, 0, 0, 0.3) 100%);
813
+ --outline-bezel-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.5), inset 0 2px 3px -2px rgba(255, 255, 255, 0.06);
814
+ --outline-face-shadow:
815
+ 0 0 3px rgba(0, 0, 0, 0.4), 0 1px 1px rgba(0, 0, 0, 0.35),
816
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.09);
817
+ --outline-face-shadow-hover:
818
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.4),
819
+ 0 3px 6px -2px rgba(0, 0, 0, 0.35), inset 0 2px 3px -2px rgba(255, 255, 255, 0.12);
820
+ --outline-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1), inset 0 0 2px rgba(0, 0, 0, 0.5);
821
+ --outline-shadow-hover:
822
+ inset 0 0 0 1px rgba(255, 255, 255, 0.16), inset 0 0 2px rgba(0, 0, 0, 0.5),
823
+ 0 1px 2px rgba(0, 0, 0, 0.3);
824
+ --outline-shadow-pressed:
825
+ inset 0 0 0 1px rgba(255, 255, 255, 0.12), inset 0 1px 2px rgba(0, 0, 0, 0.5);
826
+ --ghost-shadow-hover: inset 0 0 2px rgba(0, 0, 0, 0.5);
827
+ --ghost-shadow-pressed: inset 0 1px 2px rgba(0, 0, 0, 0.55);
828
+
829
+ /* Badges */
830
+ --badge: linear-gradient(180deg, #333333 0%, #2a2a2a 100%);
831
+ --badge-shadow:
832
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 1.5px rgba(0, 0, 0, 0.4),
833
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.1);
834
+ --badge-accent: linear-gradient(180deg, #33245c 0%, #2a1e4c 100%);
835
+ --badge-accent-shadow:
836
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 0 0 0.5px rgba(167, 139, 250, 0.22),
837
+ 0 1px 1.5px rgba(0, 0, 0, 0.4), inset 0 2px 3px -2px rgba(196, 181, 253, 0.25);
838
+
839
+ /* The warning banner, as a dark amber face */
840
+ --bezel-warning: linear-gradient(180deg, #5c4310 0%, #33240a 100%);
841
+ --bezel-warning-shadow:
842
+ 0 0 0 0.5px rgba(0, 0, 0, 0.5), 0 4px 12px -4px rgba(0, 0, 0, 0.55),
843
+ inset 0 2px 3px -2px rgba(253, 230, 138, 0.18);
844
+ --face-warning: linear-gradient(180deg, #3d2e0f 0%, #33260b 100%);
845
+ --face-warning-shadow:
846
+ 0 0 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.4),
847
+ inset 0 2px 3px -2px rgba(253, 230, 138, 0.16);
848
+
849
+ /* Fields: a step darker than whatever holds them */
850
+ --field-from: #090909;
851
+ --field-to: #0d0d0d;
852
+ --field-hover-from: #070707;
853
+ --field-hover-to: #0b0b0b;
854
+ --field-focus: #151515;
855
+ --field: linear-gradient(180deg, #090909 0%, #0d0d0d 100%);
856
+ --field-hover: linear-gradient(180deg, #070707 0%, #0b0b0b 100%);
857
+ --field-shadow:
858
+ inset 0 0 2px rgba(0, 0, 0, 0.7), inset 0 1px 2px rgba(0, 0, 0, 0.5),
859
+ 0 1px 2px -1px rgba(255, 255, 255, 0.1), inset 0 0 0 1px rgba(255, 255, 255, 0.09),
860
+ 0 0 0 0 rgba(255, 255, 255, 0);
861
+ --field-shadow-hover:
862
+ inset 0 0 2px rgba(0, 0, 0, 0.8), inset 0 1px 2px rgba(0, 0, 0, 0.55),
863
+ 0 1px 2px -1px rgba(255, 255, 255, 0.1), inset 0 0 0 1px rgba(255, 255, 255, 0.12),
864
+ 0 0 0 3px rgba(255, 255, 255, 0.025);
865
+ --field-shadow-focus:
866
+ inset 0 0 2px rgba(0, 0, 0, 0.3), inset 0 1px 2px rgba(0, 0, 0, 0.2),
867
+ 0 1px 2px -1px rgba(255, 255, 255, 0), inset 0 0 0 1px rgba(255, 255, 255, 0.42),
868
+ 0 0 0 4px rgba(255, 255, 255, 0.07);
869
+ --field-shadow-error:
870
+ inset 0 0 2px rgba(248, 113, 113, 0.45), inset 0 1px 2px rgba(0, 0, 0, 0.5),
871
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09), inset 0 0 0 1px rgba(248, 113, 113, 0),
872
+ 0 0 0 0 rgba(248, 113, 113, 0);
873
+ --field-shadow-error-hover:
874
+ inset 0 0 2px rgba(248, 113, 113, 0.6), inset 0 1px 2px rgba(0, 0, 0, 0.55),
875
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09), inset 0 0 0 1px rgba(248, 113, 113, 0.12),
876
+ 0 0 0 3px rgba(248, 113, 113, 0.05);
877
+ --field-shadow-error-focus:
878
+ inset 0 0 2px rgba(248, 113, 113, 0.15), inset 0 1px 2px rgba(0, 0, 0, 0.2),
879
+ 0 1px 2px -1px rgba(255, 255, 255, 0), inset 0 0 0 1px rgba(248, 113, 113, 0.7),
880
+ 0 0 0 4px rgba(248, 113, 113, 0.12);
881
+ --track: rgba(0, 0, 0, 0.4);
882
+ --track-shadow:
883
+ inset 0 1px 2px rgba(0, 0, 0, 0.6), inset 0 0 2px rgba(0, 0, 0, 0.6),
884
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09);
885
+ --track-on: #e6e6e6;
886
+ --track-on-shadow:
887
+ inset 0 1px 3px rgba(0, 0, 0, 0.35), inset 0 0 2px rgba(0, 0, 0, 0.25),
888
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09);
889
+
890
+ /* Wells */
891
+ --well: linear-gradient(180deg, #0a0a0a 0%, #0e0e0e 100%);
892
+ --well-shadow:
893
+ inset 0 0 2px rgba(0, 0, 0, 0.7), inset 0 1px 2px rgba(0, 0, 0, 0.6),
894
+ 0 1px 2px -1px rgba(255, 255, 255, 0.09), inset 0 0 0 1px rgba(255, 255, 255, 0.03);
895
+
896
+ /* Panels */
897
+ --panel-bezel: linear-gradient(180deg, #1c1c1c 0%, #161616 100%);
898
+ --panel-shadow:
899
+ 0 0 0 0.5px rgba(0, 0, 0, 0.6), 0 1px 2px rgba(0, 0, 0, 0.4),
900
+ 0 4px 12px -4px rgba(0, 0, 0, 0.5), inset 0 2px 3px -2px rgba(255, 255, 255, 0.07);
901
+ --panel-face-shadow:
902
+ 0 0 3px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4),
903
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.08);
904
+ --overlay-shadow:
905
+ 0 0 0 0.5px rgba(0, 0, 0, 0.7), 0 4px 12px -4px rgba(0, 0, 0, 0.55),
906
+ 0 16px 40px -12px rgba(0, 0, 0, 0.7), inset 0 2px 3px -2px rgba(255, 255, 255, 0.07);
907
+ --modal-shadow:
908
+ 0 0 0 0.5px rgba(0, 0, 0, 0.7), 0 8px 24px -8px rgba(0, 0, 0, 0.6),
909
+ 0 32px 80px -16px rgba(0, 0, 0, 0.8), inset 0 2px 3px -2px rgba(255, 255, 255, 0.07);
910
+ --scrim: rgba(0, 0, 0, 0.6);
911
+
912
+ /* Cards: his dark card, lifted a few steps so it rises off the page */
913
+ --card:
914
+ radial-gradient(90% 60% at 50% 0%, rgba(255, 255, 255, 0.05), transparent 75%),
915
+ radial-gradient(140% 100% at 30% 0%, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0) 65%),
916
+ linear-gradient(180deg, #1a1a1a 0%, #141414 100%);
917
+ --card-bezel: linear-gradient(180deg, #1d1d1d 0%, #161616 100%);
918
+ --card-shadow:
919
+ 0 0 0 0.5px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.3),
920
+ 0 4px 12px -2px rgba(0, 0, 0, 0.35), 0 12px 28px -8px rgba(0, 0, 0, 0.45),
921
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.075);
922
+ --card-shadow-hover:
923
+ 0 0 0 0.5px rgba(0, 0, 0, 0.7), 0 2px 6px rgba(0, 0, 0, 0.35),
924
+ 0 10px 28px -6px rgba(0, 0, 0, 0.45), 0 28px 64px -16px rgba(0, 0, 0, 0.5),
925
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.09);
926
+ --card-face-shadow: var(--card-face-dark-shadow);
927
+ --card-rim: rgba(255, 255, 255, 0.1);
928
+ --rim-default: rgba(255, 255, 255, 0.1);
929
+ --media-well: var(--media-well-dark);
930
+ --media-dots: rgba(255, 255, 255, 0.09);
931
+ --slide-dots: rgba(255, 255, 255, 0.08);
932
+ --spark: #f5f5f5;
933
+ --spark-halo: rgba(255, 255, 255, 0.14);
934
+ --photo-edge: rgba(255, 255, 255, 0.084);
935
+ --cover:
936
+ radial-gradient(130% 90% at 25% 0%, rgba(255, 255, 255, 0.06), transparent 60%),
937
+ linear-gradient(180deg, #181818 0%, #1c1c1c 100%);
938
+ --cover-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.45), inset 0 -2px 3px -2px rgba(0, 0, 0, 0.3);
939
+ --avatar-lift: 0 3px 12px -2px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.3);
940
+ --avatar-rim:
941
+ inset 0 2px 3px -2px rgba(255, 255, 255, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.5),
942
+ inset 0 -2px 3px -2px rgba(0, 0, 0, 0.2);
943
+ }
944
+ }
945
+
946
+ /* ── Scrollbars inside panels ────────────────────────────────────── */
947
+ .scroll-thin {
948
+ scrollbar-width: thin;
949
+ scrollbar-color: var(--scrollbar) transparent;
950
+ }
951
+
952
+ /* ── Rim light ───────────────────────────────────────────────────── */
953
+ /* A hairline border that is bright at the top and fades by the middle,
954
+ like light catching the edge of a surface. Set --rim to tune it. */
955
+ .rim {
956
+ position: relative;
957
+ }
958
+ .rim::before {
959
+ content: '';
960
+ position: absolute;
961
+ inset: 0;
962
+ border-radius: inherit;
963
+ padding: 1px;
964
+ background: linear-gradient(180deg, var(--rim, var(--rim-default)) 0%, transparent 55%);
965
+ -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
966
+ -webkit-mask-composite: xor;
967
+ mask-composite: exclude;
968
+ pointer-events: none;
969
+ z-index: 1;
970
+ }
971
+
972
+ /* ── Field ───────────────────────────────────────────────────────── */
973
+ /* Gradients can't transition, but registered colours can — so the well's
974
+ two stops are animatable properties and focus fades it up to its lit
975
+ colour rather than swapping it in a single frame. The stops come from
976
+ the theme (--field-from/-to, --field-hover-from/-to, --field-focus). */
977
+ @property --field-top {
978
+ syntax: '<color>';
979
+ inherits: false;
980
+ initial-value: #f2f2f2;
981
+ }
982
+ @property --field-bottom {
983
+ syntax: '<color>';
984
+ inherits: false;
985
+ initial-value: #f8f8f8;
986
+ }
987
+ @layer components {
988
+ .field {
989
+ --field-top: var(--field-from);
990
+ --field-bottom: var(--field-to);
991
+ background: linear-gradient(180deg, var(--field-top) 0%, var(--field-bottom) 100%);
992
+ box-shadow: var(--field-shadow);
993
+ transition:
994
+ --field-top 260ms var(--ease-out-soft),
995
+ --field-bottom 260ms var(--ease-out-soft),
996
+ box-shadow 260ms var(--ease-out-soft);
997
+ }
998
+ .field:hover {
999
+ --field-top: var(--field-hover-from);
1000
+ --field-bottom: var(--field-hover-to);
1001
+ box-shadow: var(--field-shadow-hover);
1002
+ }
1003
+ .field:focus-visible,
1004
+ .field:is(input, textarea):focus,
1005
+ .field[data-open] {
1006
+ --field-top: var(--field-focus);
1007
+ --field-bottom: var(--field-focus);
1008
+ outline: none;
1009
+ box-shadow: var(--field-shadow-focus);
1010
+ }
1011
+ .field[aria-invalid='true'],
1012
+ .field[data-invalid] {
1013
+ box-shadow: var(--field-shadow-error);
1014
+ }
1015
+ .field[aria-invalid='true']:hover,
1016
+ .field[data-invalid]:hover {
1017
+ box-shadow: var(--field-shadow-error-hover);
1018
+ }
1019
+ .field[aria-invalid='true']:focus,
1020
+ .field[data-invalid][data-open] {
1021
+ box-shadow: var(--field-shadow-error-focus);
1022
+ }
1023
+ }
1024
+
1025
+ /* ── Button ──────────────────────────────────────────────────────── */
1026
+ /* Trailing icons lean toward where the button is taking you. */
1027
+ .btn-icon-nudge > svg:last-child:not(:first-child) {
1028
+ transition: transform 320ms var(--ease-spring);
1029
+ }
1030
+ [data-btn]:hover .btn-icon-nudge > svg:last-child:not(:first-child) {
1031
+ transform: translateX(2px);
1032
+ }
1033
+
1034
+ /* Motion is decoration; when someone asks for less, every component
1035
+ still lands in its final state, just without the journey. */
1036
+ @media (prefers-reduced-motion: reduce) {
1037
+ *,
1038
+ *::before,
1039
+ *::after {
1040
+ animation-duration: 1ms !important;
1041
+ animation-iteration-count: 1 !important;
1042
+ transition-duration: 1ms !important;
1043
+ }
1044
+ }
1045
+
1046
+ /* ── Carousel ────────────────────────────────────────────────────── */
1047
+ @keyframes carousel-progress {
1048
+ from { transform: scaleX(0); }
1049
+ to { transform: scaleX(1); }
1050
+ }
1051
+ .carousel-progress { animation: carousel-progress linear both; }
1052
+
1053
+ /* ── Checkbox / Radio mark ──────────────────────────────────── */
1054
+ @keyframes checkbox-in {
1055
+ 0% { transform: scale(0); opacity: 0; }
1056
+ 55% { transform: scale(1.25); opacity: 1; }
1057
+ 100% { transform: scale(1); opacity: 1; }
1058
+ }
1059
+ .animate-checkbox-in {
1060
+ animation: checkbox-in 220ms cubic-bezier(0.34, 1.2, 0.64, 1) both;
1061
+ display: flex;
1062
+ align-items: center;
1063
+ justify-content: center;
1064
+ }
1065
+
1066
+ @keyframes draw-checkmark {
1067
+ from { stroke-dashoffset: 15; }
1068
+ to { stroke-dashoffset: 0; }
1069
+ }
1070
+ .animate-draw-check {
1071
+ stroke-dasharray: 15;
1072
+ stroke-dashoffset: 15;
1073
+ animation: draw-checkmark 200ms cubic-bezier(0.65, 0, 0.35, 1) 80ms both;
1074
+ }
1075
+
1076
+ /* ── Tab panel ───────────────────────────────────────────────────── */
1077
+ @keyframes tab-slide-right {
1078
+ from { opacity: 0; transform: translateX(20px); }
1079
+ to { opacity: 1; transform: translateX(0); }
1080
+ }
1081
+ @keyframes tab-slide-left {
1082
+ from { opacity: 0; transform: translateX(-20px); }
1083
+ to { opacity: 1; transform: translateX(0); }
1084
+ }
1085
+ .animate-tab-slide-right {
1086
+ animation: tab-slide-right 280ms cubic-bezier(0.16, 1, 0.3, 1) both;
1087
+ }
1088
+ .animate-tab-slide-left {
1089
+ animation: tab-slide-left 280ms cubic-bezier(0.16, 1, 0.3, 1) both;
1090
+ }
1091
+
1092
+ /* ── Modal ───────────────────────────────────────────────────────── */
1093
+ @keyframes modal-in {
1094
+ from { opacity: 0; transform: scale(0.94) translateY(12px); }
1095
+ to { opacity: 1; transform: scale(1) translateY(0); }
1096
+ }
1097
+ @keyframes modal-out {
1098
+ from { opacity: 1; transform: scale(1) translateY(0); }
1099
+ to { opacity: 0; transform: scale(0.96) translateY(8px); }
1100
+ }
1101
+ .animate-modal-in { animation: modal-in 300ms cubic-bezier(0.34,1.4,0.64,1) both; }
1102
+ .animate-modal-out { animation: modal-out 220ms ease-in both; }
1103
+
1104
+ @keyframes backdrop-in { from { opacity: 0; } to { opacity: 1; } }
1105
+ @keyframes backdrop-out { from { opacity: 1; } to { opacity: 0; } }
1106
+ .animate-backdrop-in { animation: backdrop-in 260ms ease-out both; }
1107
+ .animate-backdrop-out { animation: backdrop-out 220ms ease-in both; }
1108
+
1109
+ /* ── Tooltip (handled via inline transitions) ────────────────────── */
1110
+
1111
+ /* ── Input / Select shimmer sweep ────────────────────────────────── */
1112
+ @keyframes input-shimmer {
1113
+ 0% { transform: translateX(0%); opacity: 0; }
1114
+ 12% { opacity: 1; }
1115
+ 88% { opacity: 1; }
1116
+ 100% { transform: translateX(420%); opacity: 0; }
1117
+ }
1118
+ .animate-input-shimmer {
1119
+ animation: input-shimmer 850ms cubic-bezier(0.4, 0, 0.2, 1) both;
1120
+ }
1121
+
1122
+ /* ── OTP slot caret ──────────────────────────────────────────────── */
1123
+ @keyframes otp-caret {
1124
+ 0%, 100% { opacity: 1; }
1125
+ 50% { opacity: 0; }
1126
+ }
1127
+ .animate-otp-caret {
1128
+ animation: otp-caret 1s steps(1, end) infinite;
1129
+ }
1130
+
1131
+ @keyframes select-in {
1132
+ from { opacity: 0; transform: scale(0.97) translateY(-4px); }
1133
+ to { opacity: 1; transform: scale(1) translateY(0); }
1134
+ }
1135
+
1136
+ @keyframes select-option-in {
1137
+ from { opacity: 0; transform: translateY(-3px); }
1138
+ to { opacity: 1; transform: translateY(0); }
1139
+ }
1140
+
1141
+ /* ── Pagination number shift ─────────────────────────────────────── */
1142
+ @keyframes page-in-up {
1143
+ from { opacity: 0; transform: translateY(7px); filter: blur(2px); }
1144
+ to { opacity: 1; transform: translateY(0); filter: blur(0); }
1145
+ }
1146
+ @keyframes page-in-down {
1147
+ from { opacity: 0; transform: translateY(-7px); filter: blur(2px); }
1148
+ to { opacity: 1; transform: translateY(0); filter: blur(0); }
1149
+ }
1150
+ .animate-page-in-up {
1151
+ animation: page-in-up 260ms cubic-bezier(0.16,1,0.3,1) both;
1152
+ }
1153
+ .animate-page-in-down {
1154
+ animation: page-in-down 260ms cubic-bezier(0.16,1,0.3,1) both;
1155
+ }
1156
+
1157
+ /* ── Toast ───────────────────────────────────────────────────────── */
1158
+ @keyframes toast-in {
1159
+ from { opacity: 0; transform: translateY(-14px) scale(0.97); }
1160
+ to { opacity: 1; transform: translateY(0) scale(1); }
1161
+ }
1162
+ @keyframes toast-out {
1163
+ from { opacity: 1; transform: translateY(0) scale(1); }
1164
+ to { opacity: 0; transform: translateY(-10px) scale(0.97); }
1165
+ }
1166
+ .animate-toast-in {
1167
+ animation: toast-in 320ms cubic-bezier(0.34, 1.4, 0.64, 1) both;
1168
+ }
1169
+ .animate-toast-out {
1170
+ animation: toast-out 180ms cubic-bezier(0.4, 0, 1, 1) both;
1171
+ }
1172
+
1173
+ /* ── Popover (handled via inline transitions) ────────────────────── */
1174
+
1175
+ /* ── Skeleton ────────────────────────────────────────────────────── */
1176
+ @keyframes skeleton-pulse {
1177
+ 0%, 100% { opacity: 1; }
1178
+ 50% { opacity: 0.4; }
1179
+ }
1180
+ .animate-skeleton-pulse {
1181
+ animation: skeleton-pulse 1.8s cubic-bezier(0.4, 0, 0.6, 1) infinite;
1182
+ }
1183
+
1184
+ /* A band of light crossing the empty well, fixed to the viewport so
1185
+ every placeholder on screen sweeps in sync. */
1186
+ @keyframes skeleton-sheen {
1187
+ from { background-position: -60vw 0; }
1188
+ to { background-position: 60vw 0; }
1189
+ }
1190
+ .skeleton-sheen::after {
1191
+ content: '';
1192
+ position: absolute;
1193
+ inset: 0;
1194
+ background-image: linear-gradient(
1195
+ 90deg,
1196
+ transparent 0%,
1197
+ var(--sheen) 50%,
1198
+ transparent 100%
1199
+ );
1200
+ background-size: 40vw 100%;
1201
+ background-repeat: no-repeat;
1202
+ background-attachment: fixed;
1203
+ animation: skeleton-sheen 1.6s cubic-bezier(0.4, 0, 0.2, 1) infinite;
1204
+ }
1205
+ @media (prefers-reduced-motion: reduce) {
1206
+ .skeleton-sheen::after { animation: none; display: none; }
1207
+ }