@hraness/design-kit 0.31.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 (345) hide show
  1. package/ARTICLE_COPY.md +208 -0
  2. package/HERO_FIELDS.md +55 -0
  3. package/ICONS.md +56 -0
  4. package/LANTERN_MATERIAL.md +60 -0
  5. package/LICENSE +21 -0
  6. package/MARKETING_COPY.md +49 -0
  7. package/MARKETING_PRESET.md +108 -0
  8. package/PALETTES.md +90 -0
  9. package/PAPER_THEME.md +128 -0
  10. package/README.md +745 -0
  11. package/STATUS_PAGES.md +67 -0
  12. package/STYLE.md +245 -0
  13. package/WRITING.md +72 -0
  14. package/dist/browser/index.js +2345 -0
  15. package/dist/chunk-44djxk16.js +6872 -0
  16. package/dist/chunk-5gtx3pza.js +9 -0
  17. package/dist/chunk-77391vmq.js +454 -0
  18. package/dist/chunk-7b1586eb.js +1209 -0
  19. package/dist/chunk-8834fh4n.js +6 -0
  20. package/dist/chunk-9t8xyqte.js +870 -0
  21. package/dist/chunk-cejpzyfh.js +446 -0
  22. package/dist/chunk-eh71jz57.js +429 -0
  23. package/dist/chunk-evb02bc1.js +516 -0
  24. package/dist/chunk-h4k7yv6x.js +368 -0
  25. package/dist/chunk-he8eznb1.js +760 -0
  26. package/dist/chunk-mr1vdcjq.js +404 -0
  27. package/dist/chunk-wzvdn8ey.js +116 -0
  28. package/dist/fonts/nebula-sans/social-fonts.generated.js +53 -0
  29. package/dist/icons.js +48 -0
  30. package/dist/index.js +237 -0
  31. package/dist/launch.js +41 -0
  32. package/dist/mockups/client.js +422 -0
  33. package/dist/mockups/index.js +1850 -0
  34. package/dist/portfolio.js +1549 -0
  35. package/dist/provider-marks.js +19 -0
  36. package/dist/react/charts.js +11 -0
  37. package/dist/react/hero-backdrop.js +8 -0
  38. package/dist/react/index.js +7252 -0
  39. package/dist/react/platform-install.js +10 -0
  40. package/dist/react/server.js +137 -0
  41. package/dist/stylex-manifest.json +1 -0
  42. package/dist/stylex.css +5392 -0
  43. package/dist/syntax-highlighting.js +15 -0
  44. package/dist/testing.js +250 -0
  45. package/package.json +377 -0
  46. package/portfolio-inventory.json +31 -0
  47. package/scripts/check-lantern-material-snapshot.d.mts +26 -0
  48. package/scripts/check-lantern-material-snapshot.mjs +126 -0
  49. package/scripts/check-marketing-snapshot.d.mts +12 -0
  50. package/scripts/check-marketing-snapshot.mjs +58 -0
  51. package/scripts/lantern-material-snapshot.ts +101 -0
  52. package/scripts/marketing-textures.ts +48 -0
  53. package/scripts/paper-theme-snapshot.ts +97 -0
  54. package/scripts/product-marketing-snapshot.ts +149 -0
  55. package/src/appearance-menu.css +266 -0
  56. package/src/appearance.ts +32 -0
  57. package/src/article-html.ts +269 -0
  58. package/src/article.ts +686 -0
  59. package/src/browser/appearance-menu.ts +604 -0
  60. package/src/browser/artifact-share.ts +164 -0
  61. package/src/browser/design-palette.ts +197 -0
  62. package/src/browser/foil.ts +124 -0
  63. package/src/browser/hero-light.ts +11 -0
  64. package/src/browser/index.ts +29 -0
  65. package/src/browser/status-field.ts +432 -0
  66. package/src/browser/status-page.ts +100 -0
  67. package/src/browser/sticky-offset.ts +82 -0
  68. package/src/browser/theme-color-sync.ts +213 -0
  69. package/src/charts.css +7 -0
  70. package/src/compiler-components.css +34 -0
  71. package/src/compiler-foundation.css +18 -0
  72. package/src/compiler-palettes.css +7 -0
  73. package/src/compiler-tokens.css +342 -0
  74. package/src/components.css +3 -0
  75. package/src/design-gallery.css +431 -0
  76. package/src/effects.css +14 -0
  77. package/src/fonts/geist-mono/GeistMono[wght].woff2 +0 -0
  78. package/src/fonts/geist-mono/OFL.txt +93 -0
  79. package/src/fonts/geist-mono/PROVENANCE.md +12 -0
  80. package/src/fonts/instrument-serif/OFL.txt +93 -0
  81. package/src/fonts/instrument-serif/UPSTREAM.md +14 -0
  82. package/src/fonts/instrument-serif/instrument-serif-latin-400.woff2 +0 -0
  83. package/src/fonts/nebula-sans/LICENSE.txt +96 -0
  84. package/src/fonts/nebula-sans/NebulaSans-Black.woff2 +0 -0
  85. package/src/fonts/nebula-sans/NebulaSans-BlackItalic.woff2 +0 -0
  86. package/src/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
  87. package/src/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
  88. package/src/fonts/nebula-sans/NebulaSans-BoldItalic.woff2 +0 -0
  89. package/src/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
  90. package/src/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
  91. package/src/fonts/nebula-sans/NebulaSans-BookItalic.woff2 +0 -0
  92. package/src/fonts/nebula-sans/NebulaSans-Light.woff2 +0 -0
  93. package/src/fonts/nebula-sans/NebulaSans-LightItalic.woff2 +0 -0
  94. package/src/fonts/nebula-sans/NebulaSans-Medium.woff2 +0 -0
  95. package/src/fonts/nebula-sans/NebulaSans-MediumItalic.woff2 +0 -0
  96. package/src/fonts/nebula-sans/NebulaSans-Semibold.woff2 +0 -0
  97. package/src/fonts/nebula-sans/NebulaSans-SemiboldItalic.woff2 +0 -0
  98. package/src/fonts/nebula-sans/PROVENANCE.md +14 -0
  99. package/src/fonts/nebula-sans/social-fonts.generated.ts +3873 -0
  100. package/src/fonts.css +106 -0
  101. package/src/icons/act60/act60.svg +5 -0
  102. package/src/icons/act60/application.svg +9 -0
  103. package/src/icons/act60/chapter-compare.svg +3 -0
  104. package/src/icons/act60/decree-residence.svg +6 -0
  105. package/src/icons/act60/estimate.svg +7 -0
  106. package/src/icons/act60/export-services.svg +4 -0
  107. package/src/icons/act60/investor.svg +13 -0
  108. package/src/icons/act60/presence.svg +7 -0
  109. package/src/icons/aicharts/aicharts.svg +6 -0
  110. package/src/icons/aicharts/cost-compare.svg +4 -0
  111. package/src/icons/aicharts/task-audio.svg +7 -0
  112. package/src/icons/aicharts/task-coding.svg +6 -0
  113. package/src/icons/aicharts/task-images.svg +3 -0
  114. package/src/icons/aicharts/task-reasoning.svg +9 -0
  115. package/src/icons/aicharts/task-research.svg +5 -0
  116. package/src/icons/aicharts/task-video.svg +4 -0
  117. package/src/icons/manifest.json +1371 -0
  118. package/src/icons/platonik/conversation.svg +3 -0
  119. package/src/icons/platonik/creature.svg +7 -0
  120. package/src/icons/platonik/economy.svg +4 -0
  121. package/src/icons/platonik/keep-light.svg +6 -0
  122. package/src/icons/platonik/platonik.svg +7 -0
  123. package/src/icons/platonik/spark-route.svg +15 -0
  124. package/src/icons/receipts/act60-retry.receipt.json +888 -0
  125. package/src/icons/receipts/act60.receipt.json +1366 -0
  126. package/src/icons/receipts/aicharts.receipt.json +1546 -0
  127. package/src/icons/receipts/platonik.receipt.json +1011 -0
  128. package/src/icons/receipts/roughday.receipt.json +770 -0
  129. package/src/icons/receipts/shared.receipt.json +1296 -0
  130. package/src/icons/receipts/slopcamera.receipt.json +1495 -0
  131. package/src/icons/receipts/soundfish-retry.receipt.json +460 -0
  132. package/src/icons/receipts/soundfish.receipt.json +1709 -0
  133. package/src/icons/receipts/sponge.receipt.json +1743 -0
  134. package/src/icons/receipts/stripe-history-retry.receipt.json +145 -0
  135. package/src/icons/receipts/stripe-history.receipt.json +1202 -0
  136. package/src/icons/receipts/wordcell.receipt.json +1924 -0
  137. package/src/icons/roughday/finance.svg +7 -0
  138. package/src/icons/roughday/roughday.svg +6 -0
  139. package/src/icons/roughday/technology.svg +4 -0
  140. package/src/icons/roughday/world.svg +4 -0
  141. package/src/icons/sets/act60.json +63 -0
  142. package/src/icons/sets/aicharts.json +63 -0
  143. package/src/icons/sets/platonik.json +39 -0
  144. package/src/icons/sets/roughday.json +25 -0
  145. package/src/icons/sets/shared.json +12 -0
  146. package/src/icons/sets/slopcamera.json +47 -0
  147. package/src/icons/sets/soundfish.json +43 -0
  148. package/src/icons/sets/sponge.json +51 -0
  149. package/src/icons/sets/stripe-history.json +39 -0
  150. package/src/icons/sets/wordcell.json +51 -0
  151. package/src/icons/shared/agent-skill.svg +4 -0
  152. package/src/icons/shared/cli.svg +5 -0
  153. package/src/icons/shared/privacy.svg +3 -0
  154. package/src/icons/shared/research.svg +7 -0
  155. package/src/icons/shared/sdk.svg +3 -0
  156. package/src/icons/slopcamera/diagram.svg +3 -0
  157. package/src/icons/slopcamera/direct-scene.svg +5 -0
  158. package/src/icons/slopcamera/edit-video.svg +17 -0
  159. package/src/icons/slopcamera/mcp.svg +3 -0
  160. package/src/icons/slopcamera/native-world.svg +3 -0
  161. package/src/icons/slopcamera/slopcamera.svg +11 -0
  162. package/src/icons/soundfish/agent-ui.svg +7 -0
  163. package/src/icons/soundfish/collaborate.svg +5 -0
  164. package/src/icons/soundfish/compose.svg +3 -0
  165. package/src/icons/soundfish/hear.svg +6 -0
  166. package/src/icons/soundfish/human-ui.svg +6 -0
  167. package/src/icons/soundfish/share.svg +3 -0
  168. package/src/icons/soundfish/soundfish.svg +6 -0
  169. package/src/icons/sponge/api.svg +3 -0
  170. package/src/icons/sponge/documents.svg +3 -0
  171. package/src/icons/sponge/library.svg +3 -0
  172. package/src/icons/sponge/one-question.svg +5 -0
  173. package/src/icons/sponge/people-direct.svg +5 -0
  174. package/src/icons/sponge/read.svg +3 -0
  175. package/src/icons/sponge/save.svg +4 -0
  176. package/src/icons/sponge/sponge.svg +7 -0
  177. package/src/icons/stripe-history/company-history.svg +3 -0
  178. package/src/icons/stripe-history/evidence.svg +4 -0
  179. package/src/icons/stripe-history/independence.svg +7 -0
  180. package/src/icons/stripe-history/publications.svg +11 -0
  181. package/src/icons/stripe-history/sources.svg +6 -0
  182. package/src/icons/stripe-history/stripe-history.svg +3 -0
  183. package/src/icons/wordcell/backlinks.svg +6 -0
  184. package/src/icons/wordcell/capture.svg +6 -0
  185. package/src/icons/wordcell/git-provenance.svg +4 -0
  186. package/src/icons/wordcell/kb.svg +4 -0
  187. package/src/icons/wordcell/markdown.svg +4 -0
  188. package/src/icons/wordcell/scopes.svg +3 -0
  189. package/src/icons/wordcell/search.svg +7 -0
  190. package/src/icons.generated.ts +734 -0
  191. package/src/icons.ts +51 -0
  192. package/src/index.ts +275 -0
  193. package/src/lantern-material.css +213 -0
  194. package/src/launch.ts +624 -0
  195. package/src/marketing-assets/UPSTREAM.md +18 -0
  196. package/src/marketing-assets/cells.svg +1 -0
  197. package/src/marketing-assets/grain.svg +1 -0
  198. package/src/marketing-forced-colors.css +12 -0
  199. package/src/mockups/client.tsx +415 -0
  200. package/src/mockups/core.tsx +318 -0
  201. package/src/mockups/frames.tsx +368 -0
  202. package/src/mockups/index.ts +14 -0
  203. package/src/mockups/surfaces.tsx +681 -0
  204. package/src/mockups.css +2607 -0
  205. package/src/palette-appearance.ts +45 -0
  206. package/src/palette-bridge.css +124 -0
  207. package/src/palette-color.ts +41 -0
  208. package/src/palette-system.css +721 -0
  209. package/src/palette-themes.ts +23 -0
  210. package/src/palette-tokens.stylex.ts +519 -0
  211. package/src/palettes.css +3 -0
  212. package/src/palettes.ts +161 -0
  213. package/src/paper-theme.css +244 -0
  214. package/src/plain-publication.css +1241 -0
  215. package/src/plain-site.css +397 -0
  216. package/src/platforms.ts +151 -0
  217. package/src/portfolio.generated.json +1595 -0
  218. package/src/portfolio.generated.ts +1596 -0
  219. package/src/portfolio.ts +226 -0
  220. package/src/product-marketing-foundation.css +433 -0
  221. package/src/product-marketing-preset.css +261 -0
  222. package/src/product-marketing.css +2186 -0
  223. package/src/provider-marks.generated.ts +112 -0
  224. package/src/provider-marks.ts +143 -0
  225. package/src/react/animated-rail-stage.stylex.ts +15 -0
  226. package/src/react/animated-rail-stage.tsx +51 -0
  227. package/src/react/app-shell.stylex.ts +104 -0
  228. package/src/react/app-shell.tsx +121 -0
  229. package/src/react/article.tsx +602 -0
  230. package/src/react/aurora-dots-background.tsx +34 -0
  231. package/src/react/charts.stylex.ts +563 -0
  232. package/src/react/charts.tsx +610 -0
  233. package/src/react/chat.stylex.ts +34 -0
  234. package/src/react/chat.tsx +155 -0
  235. package/src/react/design-gallery.tsx +943 -0
  236. package/src/react/design-palette.stylex.ts +124 -0
  237. package/src/react/design-palette.tsx +196 -0
  238. package/src/react/design-theme-context.tsx +41 -0
  239. package/src/react/effects.stylex.ts +325 -0
  240. package/src/react/fader.stylex.ts +71 -0
  241. package/src/react/fader.tsx +151 -0
  242. package/src/react/foil-card-math.ts +100 -0
  243. package/src/react/foil-card-surface.stylex.ts +326 -0
  244. package/src/react/foil-card-surface.tsx +742 -0
  245. package/src/react/foil-mark.tsx +35 -0
  246. package/src/react/foil.stylex.ts +163 -0
  247. package/src/react/haptics.ts +228 -0
  248. package/src/react/hero-backdrop.tsx +22 -0
  249. package/src/react/index.ts +38 -0
  250. package/src/react/keyboard-shortcuts.ts +228 -0
  251. package/src/react/lantern-material-gallery.tsx +166 -0
  252. package/src/react/lantern-material.stylex.ts +39 -0
  253. package/src/react/launch-beats.tsx +73 -0
  254. package/src/react/navigation-rail.stylex.ts +130 -0
  255. package/src/react/navigation-rail.tsx +228 -0
  256. package/src/react/particle-halo.tsx +115 -0
  257. package/src/react/phaser-dots.tsx +501 -0
  258. package/src/react/platform-icons.tsx +94 -0
  259. package/src/react/platform-install.stylex.ts +385 -0
  260. package/src/react/platform-install.tsx +389 -0
  261. package/src/react/playback-transport.stylex.ts +14 -0
  262. package/src/react/playback-transport.tsx +112 -0
  263. package/src/react/procedural-backdrop.tsx +192 -0
  264. package/src/react/procedural-recipe.ts +323 -0
  265. package/src/react/product-marketing.stylex.ts +4469 -0
  266. package/src/react/product-marketing.tsx +1611 -0
  267. package/src/react/production-data-preview-notice.stylex.ts +40 -0
  268. package/src/react/production-data-preview-notice.tsx +34 -0
  269. package/src/react/provider-mark.stylex.ts +132 -0
  270. package/src/react/provider-mark.tsx +120 -0
  271. package/src/react/relative-time.tsx +117 -0
  272. package/src/react/route-state.stylex.ts +39 -0
  273. package/src/react/route-state.tsx +350 -0
  274. package/src/react/server.ts +11 -0
  275. package/src/react/social-kit-panel.tsx +103 -0
  276. package/src/react/sticky-offset.tsx +33 -0
  277. package/src/react/surfaces.stylex.ts +179 -0
  278. package/src/react/surfaces.tsx +330 -0
  279. package/src/react/syntax-code.tsx +33 -0
  280. package/src/react/theme-color-sync.ts +1 -0
  281. package/src/react/theme-resolution.ts +11 -0
  282. package/src/react/theme.stylex.ts +276 -0
  283. package/src/react/theme.tsx +402 -0
  284. package/src/reading.css +72 -0
  285. package/src/relative-time.ts +185 -0
  286. package/src/reset.css +2 -0
  287. package/src/site-shell.css +16 -0
  288. package/src/status-page-html.ts +63 -0
  289. package/src/status-page.css +276 -0
  290. package/src/status-page.ts +323 -0
  291. package/src/styles.css +21 -0
  292. package/src/syntax-code-lexers.ts +303 -0
  293. package/src/syntax-highlighting.css +78 -0
  294. package/src/syntax-highlighting.ts +477 -0
  295. package/src/syntax-tokens.ts +33 -0
  296. package/src/testing.ts +307 -0
  297. package/src/tokens.css +3 -0
  298. package/src/typography.css +86 -0
  299. package/vendor/evilcharts/LICENSE +21 -0
  300. package/vendor/evilcharts/UPSTREAM.md +14 -0
  301. package/vendor/platform-marks/LICENSE +30 -0
  302. package/vendor/platform-marks/UPSTREAM.md +15 -0
  303. package/vendor/platform-marks/apple.svg +1 -0
  304. package/vendor/platform-marks/linux.svg +1 -0
  305. package/vendor/provider-marks/CRUSH-LICENSE.md +134 -0
  306. package/vendor/provider-marks/LICENSE +21 -0
  307. package/vendor/provider-marks/UPSTREAM.md +27 -0
  308. package/vendor/provider-marks/aider.svg +3 -0
  309. package/vendor/provider-marks/crush-heartbit.svg +8 -0
  310. package/vendor/provider-marks/lobehub/alibabacloud-color.svg +1 -0
  311. package/vendor/provider-marks/lobehub/alibabacloud.svg +1 -0
  312. package/vendor/provider-marks/lobehub/amp-color.svg +1 -0
  313. package/vendor/provider-marks/lobehub/amp.svg +1 -0
  314. package/vendor/provider-marks/lobehub/anthropic.svg +1 -0
  315. package/vendor/provider-marks/lobehub/claude-color.svg +1 -0
  316. package/vendor/provider-marks/lobehub/claude.svg +1 -0
  317. package/vendor/provider-marks/lobehub/claudecode-color.svg +1 -0
  318. package/vendor/provider-marks/lobehub/claudecode.svg +1 -0
  319. package/vendor/provider-marks/lobehub/codex-color.svg +1 -0
  320. package/vendor/provider-marks/lobehub/codex.svg +1 -0
  321. package/vendor/provider-marks/lobehub/cursor.svg +1 -0
  322. package/vendor/provider-marks/lobehub/deepseek-color.svg +1 -0
  323. package/vendor/provider-marks/lobehub/deepseek.svg +1 -0
  324. package/vendor/provider-marks/lobehub/devin-color.svg +1 -0
  325. package/vendor/provider-marks/lobehub/devin.svg +1 -0
  326. package/vendor/provider-marks/lobehub/gemini-color.svg +1 -0
  327. package/vendor/provider-marks/lobehub/gemini.svg +1 -0
  328. package/vendor/provider-marks/lobehub/geminicli-color.svg +1 -0
  329. package/vendor/provider-marks/lobehub/geminicli.svg +1 -0
  330. package/vendor/provider-marks/lobehub/goose.svg +1 -0
  331. package/vendor/provider-marks/lobehub/meta-color.svg +1 -0
  332. package/vendor/provider-marks/lobehub/meta.svg +1 -0
  333. package/vendor/provider-marks/lobehub/mistral-color.svg +1 -0
  334. package/vendor/provider-marks/lobehub/mistral.svg +1 -0
  335. package/vendor/provider-marks/lobehub/moonshot.svg +1 -0
  336. package/vendor/provider-marks/lobehub/nvidia-color.svg +1 -0
  337. package/vendor/provider-marks/lobehub/nvidia.svg +1 -0
  338. package/vendor/provider-marks/lobehub/openai.svg +1 -0
  339. package/vendor/provider-marks/lobehub/opencode.svg +1 -0
  340. package/vendor/provider-marks/lobehub/perplexity-color.svg +1 -0
  341. package/vendor/provider-marks/lobehub/perplexity.svg +1 -0
  342. package/vendor/provider-marks/lobehub/qwen-color.svg +1 -0
  343. package/vendor/provider-marks/lobehub/qwen.svg +1 -0
  344. package/vendor/provider-marks/lobehub/xai.svg +1 -0
  345. package/vendor/provider-marks/lobehub/zai.svg +1 -0
@@ -0,0 +1,124 @@
1
+ import * as stylex from "@stylexjs/stylex";
2
+
3
+ const forcedColors = "@media (forced-colors: active)";
4
+ const reducedMotion = "@media (prefers-reduced-motion: reduce)";
5
+ const pressed = ":is([data-pressed], :active)";
6
+
7
+ export const paletteMenuStyles = stylex.create({
8
+ icon: {
9
+ alignItems: "center",
10
+ display: "inline-flex",
11
+ justifyContent: "center",
12
+ lineHeight: 0,
13
+ },
14
+ root: {
15
+ display: "inline-flex",
16
+ position: "relative",
17
+ "min-inline-size": 0,
18
+ },
19
+ trigger: {
20
+ alignItems: "center",
21
+ // Lantern tokens exist only inside a data-hraness-material="lantern"
22
+ // island, so each chain falls through to the palette outside one.
23
+ backgroundColor: "var(--hraness-material-plane, var(--background, Canvas))",
24
+ borderColor: {
25
+ default: "var(--hraness-material-seam, var(--control-border, GrayText))",
26
+ [forcedColors]: "CanvasText",
27
+ },
28
+ borderRadius: "var(--radius-md, 0.5rem)",
29
+ borderStyle: "solid",
30
+ borderWidth: 1,
31
+ boxShadow: {
32
+ default: "var(--hraness-material-raised, none)",
33
+ [pressed]: "var(--hraness-material-inset, none)",
34
+ [forcedColors]: "none",
35
+ },
36
+ color: "var(--hraness-material-ink, var(--foreground, CanvasText))",
37
+ cursor: "pointer",
38
+ display: "inline-flex",
39
+ justifyContent: "center",
40
+ listStyleType: "none",
41
+ "min-block-size": "var(--interactive-target-compact, 2.75rem)",
42
+ "min-inline-size": "var(--interactive-target-compact, 2.75rem)",
43
+ outlineColor: "var(--hraness-material-focus, var(--focus, Highlight))",
44
+ outlineOffset: 3,
45
+ paddingBlock: "0.5rem",
46
+ paddingInline: "0.625rem",
47
+ transitionDuration: {
48
+ default: "120ms",
49
+ [reducedMotion]: "0.01ms",
50
+ },
51
+ transitionProperty: "box-shadow",
52
+ transitionTimingFunction: "cubic-bezier(0.2, 0, 0, 1)",
53
+ userSelect: "none",
54
+ },
55
+ triggerDefault: {
56
+ "min-block-size": "var(--interactive-target-min, 3rem)",
57
+ "min-inline-size": "var(--interactive-target-min, 3rem)",
58
+ },
59
+ panel: {
60
+ backgroundColor: "var(--hraness-material-plane, var(--popover, Canvas))",
61
+ borderColor: {
62
+ default: "var(--hraness-material-seam, var(--control-border, GrayText))",
63
+ [forcedColors]: "CanvasText",
64
+ },
65
+ borderRadius: "var(--radius-lg, 0.75rem)",
66
+ borderStyle: "solid",
67
+ borderWidth: 1,
68
+ boxShadow: {
69
+ default:
70
+ "var(--hraness-material-lift, var(--elevation-overlay, 0 18px 48px -18px rgb(0 0 0 / 32%)))",
71
+ [forcedColors]: "none",
72
+ },
73
+ color: "var(--hraness-material-ink, var(--popover-foreground, CanvasText))",
74
+ display: "grid",
75
+ gap: "0.75rem",
76
+ "inset-block-start": "calc(100% + 0.5rem)",
77
+ "inset-inline-end": 0,
78
+ "inline-size": "min(16rem, calc(100vw - 2rem))",
79
+ "max-block-size": "min(38rem, 75dvh)",
80
+ overflow: "auto",
81
+ paddingBlock: "0.75rem",
82
+ paddingInline: "0.75rem",
83
+ position: "absolute",
84
+ "z-index": "var(--z-tooltip, 3000)",
85
+ },
86
+ group: {
87
+ borderWidth: 0,
88
+ display: "grid",
89
+ gap: "0.125rem",
90
+ marginBlock: 0,
91
+ marginInline: 0,
92
+ "min-inline-size": 0,
93
+ paddingBlock: 0,
94
+ paddingInline: 0,
95
+ },
96
+ legend: {
97
+ color: "var(--muted, GrayText)",
98
+ fontSize: "0.875rem",
99
+ fontWeight: 550,
100
+ lineHeight: 1.5,
101
+ marginBlockEnd: "0.375rem",
102
+ paddingInline: "0.5rem",
103
+ },
104
+ choice: {
105
+ alignItems: "center",
106
+ borderRadius: "var(--radius-md, 0.5rem)",
107
+ cursor: "pointer",
108
+ display: "flex",
109
+ fontSize: "1rem",
110
+ gap: "0.625rem",
111
+ lineHeight: 1.4,
112
+ "min-block-size": "2.75rem",
113
+ paddingBlock: "0.375rem",
114
+ paddingInline: "0.5rem",
115
+ },
116
+ radio: {
117
+ accentColor: "var(--primary, Highlight)",
118
+ flexShrink: 0,
119
+ "block-size": "1rem",
120
+ "inline-size": "1rem",
121
+ marginBlock: 0,
122
+ marginInline: 0,
123
+ },
124
+ });
@@ -0,0 +1,196 @@
1
+ "use client";
2
+
3
+ import { AppearanceIcon, cn } from "@hraness/ui";
4
+ import * as stylex from "@stylexjs/stylex";
5
+ import { createContext, type ReactNode, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
+
7
+ import { designThemeLabel, designThemes, type DesignTheme } from "../appearance.js";
8
+ import { designPaletteSnapshot, initDesignPalette, type DesignPaletteController, type DesignPaletteSnapshot } from "../browser/design-palette.js";
9
+ import { defaultDesignPalettePreference, normalizeDesignPalettePreference, type ConcreteDesignPalettePreference, type DesignPalettePreference } from "../palette-appearance.js";
10
+ import { designPaletteLabels, designPalettes, type DesignPalette } from "../palettes.js";
11
+ import { DesignPortalThemeProvider } from "./design-theme-context.js";
12
+ import { paletteMenuStyles } from "./design-palette.stylex.js";
13
+ import type { ThemeMenuButtonProps } from "./theme.js";
14
+
15
+ export interface DesignPaletteContextValue extends DesignPaletteSnapshot {
16
+ readonly ready: boolean;
17
+ readonly setPreference: (preference: DesignPalettePreference) => void;
18
+ readonly setPalette: (palette: DesignPalette) => void;
19
+ readonly setMode: (mode: DesignTheme) => void;
20
+ }
21
+
22
+ const DesignPaletteContext = createContext<DesignPaletteContextValue | null>(null);
23
+ const noSubscribe = (): (() => void) => () => undefined;
24
+
25
+ function isNode(target: EventTarget | null): target is Node {
26
+ return target !== null && "nodeType" in target;
27
+ }
28
+
29
+ export interface DesignPaletteProviderProps {
30
+ readonly children: ReactNode;
31
+ readonly defaultPreference?: DesignPalettePreference;
32
+ readonly forcedPreference?: ConcreteDesignPalettePreference;
33
+ readonly storageKey?: string;
34
+ readonly legacyStorageKey?: string | null;
35
+ }
36
+
37
+ /** Opt-in appearance boundary. A product may call initDesignPalette in an external head script before hydration. */
38
+ export function DesignPaletteProvider({
39
+ children,
40
+ defaultPreference = defaultDesignPalettePreference,
41
+ forcedPreference,
42
+ storageKey,
43
+ legacyStorageKey,
44
+ }: DesignPaletteProviderProps) {
45
+ const fallback = useMemo(() => normalizeDesignPalettePreference(defaultPreference), [defaultPreference.palette, defaultPreference.mode]);
46
+ const forced = useMemo(() => forcedPreference === undefined ? undefined : { ...forcedPreference }, [forcedPreference?.palette, forcedPreference?.mode]);
47
+ const serverSnapshot = useMemo(() => designPaletteSnapshot(forced ?? fallback, false, forced !== undefined), [fallback, forced]);
48
+ const [controller, setController] = useState<DesignPaletteController | null>(null);
49
+ useEffect(() => {
50
+ const current = initDesignPalette({
51
+ defaultPreference: fallback,
52
+ ...(forced === undefined ? {} : { forcedPreference: forced }),
53
+ ...(storageKey === undefined ? {} : { storageKey }),
54
+ ...(legacyStorageKey === undefined ? {} : { legacyStorageKey }),
55
+ });
56
+ setController(current);
57
+ return () => { current.dispose(); };
58
+ }, [fallback, forced, storageKey, legacyStorageKey]);
59
+ const snapshot = useSyncExternalStore(
60
+ controller?.subscribe ?? noSubscribe,
61
+ controller?.getSnapshot ?? (() => serverSnapshot),
62
+ () => serverSnapshot,
63
+ );
64
+ const value = useMemo<DesignPaletteContextValue>(() => ({
65
+ ...snapshot,
66
+ ready: controller !== null,
67
+ setPreference: (preference) => { controller?.setPreference(preference); },
68
+ setPalette: (palette) => { controller?.setPreference({ ...controller.getSnapshot().preference, palette }); },
69
+ setMode: (mode) => { controller?.setPreference({ ...controller.getSnapshot().preference, mode }); },
70
+ }), [snapshot, controller]);
71
+ return <DesignPaletteContext.Provider value={value}>
72
+ <DesignPortalThemeProvider portalClassName={snapshot.className} theme={snapshot.resolvedMode}>
73
+ {children}
74
+ </DesignPortalThemeProvider>
75
+ </DesignPaletteContext.Provider>;
76
+ }
77
+
78
+ /** Returns null outside the opt-in provider; legacy appearance remains independent. */
79
+ export function useDesignPalette(): DesignPaletteContextValue | null {
80
+ return useContext(DesignPaletteContext);
81
+ }
82
+
83
+ export function DesignPaletteMenuButton({
84
+ "aria-label": ariaLabel = "Appearance",
85
+ className,
86
+ labels,
87
+ size = "compact",
88
+ onChange,
89
+ value: controlledMode,
90
+ }: ThemeMenuButtonProps) {
91
+ const palette = useDesignPalette();
92
+ const detailsRef = useRef<HTMLDetailsElement>(null);
93
+ const pointerInside = useRef(false);
94
+ const groupId = useId();
95
+ useEffect(() => {
96
+ const details = detailsRef.current;
97
+ if (details === null) return;
98
+ const document = details.ownerDocument;
99
+ let settlement: ReturnType<typeof setTimeout> | undefined;
100
+ const clearSettlement = (): void => { clearTimeout(settlement); settlement = undefined; };
101
+ const outside = (event: PointerEvent): void => {
102
+ clearSettlement();
103
+ pointerInside.current = isNode(event.target) && details.contains(event.target);
104
+ if (details.open && !pointerInside.current) details.open = false;
105
+ };
106
+ const settlePointer = (): void => {
107
+ if (!pointerInside.current) return;
108
+ clearSettlement();
109
+ // A label first focuses its focusable ancestor, then its input during
110
+ // native activation. Keep the disclosure mounted through that sequence.
111
+ settlement = setTimeout(() => {
112
+ settlement = undefined;
113
+ pointerInside.current = false;
114
+ if (details.open && !details.contains(document.activeElement)) details.open = false;
115
+ }, 0);
116
+ };
117
+ const releasePointer = (event: PointerEvent): void => {
118
+ // Touch compatibility mouse events may follow pointerup in a later task.
119
+ // An inside release stays guarded until native click activation completes.
120
+ if (event.button !== 0 || !isNode(event.target) || !details.contains(event.target)) settlePointer();
121
+ };
122
+ const escape = (event: KeyboardEvent): void => {
123
+ if (event.key === "Tab") {
124
+ clearSettlement();
125
+ pointerInside.current = false;
126
+ return;
127
+ }
128
+ if (event.key !== "Escape" || !details.open) return;
129
+ event.preventDefault();
130
+ clearSettlement();
131
+ pointerInside.current = false;
132
+ details.open = false;
133
+ details.querySelector("summary")?.focus();
134
+ };
135
+ document.addEventListener("pointerdown", outside, true);
136
+ document.addEventListener("pointerup", releasePointer, true);
137
+ document.addEventListener("click", settlePointer, true);
138
+ document.addEventListener("pointercancel", settlePointer, true);
139
+ document.defaultView?.addEventListener("blur", settlePointer);
140
+ details.addEventListener("keydown", escape);
141
+ return () => {
142
+ clearSettlement();
143
+ pointerInside.current = false;
144
+ document.removeEventListener("pointerdown", outside, true);
145
+ document.removeEventListener("pointerup", releasePointer, true);
146
+ document.removeEventListener("click", settlePointer, true);
147
+ document.removeEventListener("pointercancel", settlePointer, true);
148
+ document.defaultView?.removeEventListener("blur", settlePointer);
149
+ details.removeEventListener("keydown", escape);
150
+ };
151
+ }, []);
152
+ if (palette === null) throw new Error("DesignPaletteMenuButton requires DesignPaletteProvider.");
153
+ const mode = controlledMode ?? palette.preference.mode;
154
+ const ready = palette.ready && !palette.isForced;
155
+ const title = `${ariaLabel}: ${designPaletteLabels[palette.preference.palette]}, ${designThemeLabel(mode, labels)}`;
156
+ return <details
157
+ {...stylex.props(paletteMenuStyles.root)}
158
+ className={cn("hraness-design-theme-toggle", "hraness-design-palette-menu", stylex.props(paletteMenuStyles.root).className, className)}
159
+ data-hraness-appearance-menu=""
160
+ data-presentation="menu"
161
+ data-ready={ready ? "true" : "false"}
162
+ ref={detailsRef}
163
+ onBlur={(event) => {
164
+ if (!pointerInside.current && isNode(event.relatedTarget)
165
+ && !event.currentTarget.contains(event.relatedTarget)) event.currentTarget.open = false;
166
+ }}
167
+ >
168
+ <summary
169
+ {...stylex.props(paletteMenuStyles.trigger, size === "default" && paletteMenuStyles.triggerDefault)}
170
+ aria-disabled={!ready || undefined}
171
+ aria-label={title}
172
+ onClick={(event) => { if (!ready) event.preventDefault(); }}
173
+ tabIndex={ready ? 0 : -1}
174
+ title={title}
175
+ ><AppearanceIcon name={mode} xstyle={paletteMenuStyles.icon} /></summary>
176
+ <div {...stylex.props(paletteMenuStyles.panel)}>
177
+ <fieldset {...stylex.props(paletteMenuStyles.group)} disabled={!ready}>
178
+ <legend {...stylex.props(paletteMenuStyles.legend)}>Theme</legend>
179
+ {designPalettes.map((id) => <label {...stylex.props(paletteMenuStyles.choice)} key={id}>
180
+ <input {...stylex.props(paletteMenuStyles.radio)} checked={palette.preference.palette === id} name={`${groupId}-palette`} onChange={() => palette.setPalette(id)} type="radio" value={id} />
181
+ <span>{designPaletteLabels[id]}</span>
182
+ </label>)}
183
+ </fieldset>
184
+ <fieldset {...stylex.props(paletteMenuStyles.group)} disabled={!ready}>
185
+ <legend {...stylex.props(paletteMenuStyles.legend)}>Appearance</legend>
186
+ {designThemes.map((id) => <label {...stylex.props(paletteMenuStyles.choice)} key={id}>
187
+ <input {...stylex.props(paletteMenuStyles.radio)} checked={mode === id} name={`${groupId}-mode`} onChange={() => {
188
+ if (onChange === undefined) palette.setMode(id);
189
+ else onChange(id);
190
+ }} type="radio" value={id} />
191
+ <span>{designThemeLabel(id, labels)}</span>
192
+ </label>)}
193
+ </fieldset>
194
+ </div>
195
+ </details>;
196
+ }
@@ -0,0 +1,41 @@
1
+ "use client";
2
+
3
+ import { createContext, type ReactNode, useContext, useMemo } from "react";
4
+
5
+ export type PortalDesignTheme = "dark" | "light";
6
+
7
+ interface DesignThemeContextValue {
8
+ readonly portalClassName?: string;
9
+ readonly theme?: PortalDesignTheme;
10
+ }
11
+
12
+ const DesignThemeContext = createContext<DesignThemeContextValue>({});
13
+
14
+ /** Keeps portalled overlays in the same explicit theme as their trigger subtree. */
15
+ export function DesignPortalThemeProvider({
16
+ children,
17
+ portalClassName,
18
+ theme,
19
+ }: Readonly<{
20
+ children: ReactNode;
21
+ portalClassName?: string;
22
+ theme: PortalDesignTheme | undefined;
23
+ }>) {
24
+ const value = useMemo(
25
+ () => ({
26
+ ...(portalClassName === undefined ? {} : { portalClassName }),
27
+ ...(theme === undefined ? {} : { theme }),
28
+ }),
29
+ [portalClassName, theme],
30
+ );
31
+ return <DesignThemeContext.Provider value={value}>{children}</DesignThemeContext.Provider>;
32
+ }
33
+
34
+ export function useDesignPortalTheme(): PortalDesignTheme | undefined {
35
+ return useContext(DesignThemeContext).theme;
36
+ }
37
+
38
+ /** Reapplies a product palette selector when an overlay leaves its trigger subtree. */
39
+ export function useDesignPortalClassName(): string | undefined {
40
+ return useContext(DesignThemeContext).portalClassName;
41
+ }
@@ -0,0 +1,325 @@
1
+ import * as stylex from "@stylexjs/stylex";
2
+
3
+ const proceduralCloudDrift = stylex.keyframes({
4
+ "0%": {
5
+ transform:
6
+ "translate3d(-50%, -50%, 0) rotate(var(--hraness-design-procedural-layer-rotation))",
7
+ },
8
+ "100%": {
9
+ transform:
10
+ "translate3d(calc(-50% + var(--hraness-design-procedural-layer-drift-x)), calc(-50% + var(--hraness-design-procedural-layer-drift-y)), 0) rotate(calc(var(--hraness-design-procedural-layer-rotation) + 3deg)) scale(var(--hraness-design-procedural-layer-scale))",
11
+ },
12
+ });
13
+
14
+ const proceduralGridDrift = stylex.keyframes({
15
+ "0%": {
16
+ backgroundPosition:
17
+ "var(--hraness-design-procedural-grid-offset-x) var(--hraness-design-procedural-grid-offset-y), var(--hraness-design-procedural-grid-offset-x) var(--hraness-design-procedural-grid-offset-y)",
18
+ },
19
+ "100%": {
20
+ backgroundPosition:
21
+ "calc(var(--hraness-design-procedural-grid-offset-x) + var(--hraness-design-procedural-grid-size)) calc(var(--hraness-design-procedural-grid-offset-y) + var(--hraness-design-procedural-grid-size)), calc(var(--hraness-design-procedural-grid-offset-x) + var(--hraness-design-procedural-grid-size)) calc(var(--hraness-design-procedural-grid-offset-y) + var(--hraness-design-procedural-grid-size))",
22
+ },
23
+ });
24
+
25
+ const proceduralRippleBreathe = stylex.keyframes({
26
+ "0%": {
27
+ transform: "translate3d(-50%, -50%, 0) scale(0.98)",
28
+ },
29
+ "100%": {
30
+ transform: "translate3d(-50%, -50%, 0) scale(1.025)",
31
+ },
32
+ });
33
+
34
+ const particleHaloDrift = stylex.keyframes({
35
+ "0%": {
36
+ transform: "translate3d(-50%, -50%, 0)",
37
+ },
38
+ "100%": {
39
+ transform:
40
+ "translate3d(calc(-50% + var(--hraness-design-particle-drift-x)), calc(-50% + var(--hraness-design-particle-drift-y)), 0) scale(1.08)",
41
+ },
42
+ });
43
+
44
+ export const effectsStyles = stylex.create({
45
+ auroraBackground: {
46
+ backgroundAttachment: "scroll",
47
+ backgroundClip: "border-box",
48
+ backgroundColor:
49
+ "color-mix(in srgb, var(--background) var(--hraness-design-aurora-background-mix, 86%), transparent)",
50
+ backgroundImage:
51
+ "radial-gradient(ellipse 54% 40% at 16% 24%, color-mix(in srgb, var(--aurora-cyan) var(--hraness-design-aurora-cyan-mix, 26%), transparent) 0%, transparent 62%), radial-gradient(ellipse 52% 38% at 82% 20%, color-mix(in srgb, var(--aurora-gold) var(--hraness-design-aurora-gold-mix, 24%), transparent) 0%, transparent 60%), radial-gradient(ellipse 58% 42% at 58% 76%, color-mix(in srgb, var(--aurora-violet) var(--hraness-design-aurora-violet-mix, 22%), transparent) 0%, transparent 62%), radial-gradient(ellipse 48% 34% at 24% 78%, color-mix(in srgb, var(--aurora-mint) var(--hraness-design-aurora-mint-mix, 20%), transparent) 0%, transparent 58%), none",
52
+ backgroundOrigin: "padding-box",
53
+ backgroundPosition: "0% 0%",
54
+ backgroundRepeat: "repeat",
55
+ backgroundSize: "auto auto",
56
+ display: {
57
+ default: null,
58
+ "@media (forced-colors: active)": "none",
59
+ },
60
+ filter: "saturate(1.08)",
61
+ inset: 0,
62
+ overflow: "hidden",
63
+ pointerEvents: "none",
64
+ position: "fixed",
65
+ zIndex: 0,
66
+ "::before": {
67
+ backgroundAttachment: "scroll",
68
+ backgroundClip: "border-box",
69
+ backgroundColor: "transparent",
70
+ backgroundImage:
71
+ "radial-gradient(ellipse 44% 78% at 10% 54%, oklch(0.92 0.07 22 / 0.2) 0%, transparent 78%), radial-gradient(ellipse 44% 78% at 32% 44%, oklch(0.95 0.06 80 / 0.18) 0%, transparent 78%), radial-gradient(ellipse 44% 78% at 54% 54%, oklch(0.94 0.07 158 / 0.18) 0%, transparent 78%), radial-gradient(ellipse 44% 78% at 74% 44%, oklch(0.92 0.07 230 / 0.18) 0%, transparent 78%), radial-gradient(ellipse 44% 78% at 92% 54%, oklch(0.9 0.07 304 / 0.18) 0%, transparent 78%)",
72
+ backgroundOrigin: "padding-box",
73
+ backgroundPosition: "0% 0%",
74
+ backgroundRepeat: "repeat",
75
+ backgroundSize: "auto auto",
76
+ content: '""',
77
+ filter: "blur(56px) saturate(0.98)",
78
+ inset: "-18%",
79
+ opacity: "var(--hraness-design-aurora-before-opacity, 0.84)",
80
+ position: "absolute",
81
+ transform: "translate3d(0, -4vh, 0)",
82
+ },
83
+ "::after": {
84
+ backgroundAttachment: "scroll",
85
+ backgroundClip: "border-box",
86
+ backgroundColor: "transparent",
87
+ backgroundImage:
88
+ "linear-gradient(136deg, transparent 0%, rgb(255 255 255 / 0.16) 18%, transparent 34%), radial-gradient(ellipse 42% 32% at 76% 26%, color-mix(in srgb, var(--aurora-rose) 16%, transparent) 0%, transparent 62%), radial-gradient(ellipse 46% 32% at 22% 54%, color-mix(in srgb, white 16%, transparent) 0%, transparent 64%)",
89
+ backgroundOrigin: "padding-box",
90
+ backgroundPosition: "0% 0%",
91
+ backgroundRepeat: "repeat",
92
+ backgroundSize: "auto auto",
93
+ content: '""',
94
+ filter: "blur(44px)",
95
+ inset: "-10%",
96
+ mixBlendMode: "soft-light",
97
+ opacity: "var(--hraness-design-aurora-after-opacity, 0.36)",
98
+ position: "absolute",
99
+ },
100
+ },
101
+ auroraDots: {
102
+ "--phaser-dots-static-color": "color-mix(in srgb, var(--phaser-dots-accent, oklch(0.572 0.1561 254.537)) 20%, transparent)",
103
+ "--phaser-dots-static-opacity": "0.3",
104
+ "--phaser-dots-trail-color": "var(--phaser-dots-accent, oklch(0.572 0.1561 254.537))",
105
+ "--phaser-dots-trail-opacity": "1",
106
+ display: {
107
+ default: null,
108
+ "@media (forced-colors: active)": "none",
109
+ },
110
+ inset: 0,
111
+ pointerEvents: "none",
112
+ position: "fixed",
113
+ zIndex: 0,
114
+ },
115
+ phaserSlot: {
116
+ inset: 0,
117
+ pointerEvents: "none",
118
+ position: "absolute",
119
+ },
120
+ phaserRoot: {
121
+ zIndex: 0,
122
+ },
123
+ phaserStatic: {
124
+ backgroundImage: "radial-gradient(currentcolor 1px, transparent 1px)",
125
+ backgroundSize: "6px 6px",
126
+ },
127
+ phaserStaticDefault: {
128
+ color: "var(--phaser-dots-static-color, var(--foreground))",
129
+ opacity: "var(--phaser-dots-static-opacity, 0.025)",
130
+ },
131
+ phaserTrail: {
132
+ height: "100%",
133
+ width: "100%",
134
+ },
135
+ phaserTrailDefault: {
136
+ color: "var(--phaser-dots-trail-color, var(--foreground))",
137
+ opacity: "var(--phaser-dots-trail-opacity, 0.25)",
138
+ },
139
+ proceduralRoot: {
140
+ backgroundAttachment: "scroll",
141
+ backgroundClip: "border-box",
142
+ backgroundColor: "var(--background)",
143
+ backgroundImage: "none",
144
+ backgroundOrigin: "padding-box",
145
+ backgroundPosition: "0% 0%",
146
+ backgroundRepeat: "repeat",
147
+ backgroundSize: "auto auto",
148
+ color: "var(--foreground)",
149
+ inset: 0,
150
+ isolation: "isolate",
151
+ overflow: "hidden",
152
+ pointerEvents: "none",
153
+ position: "absolute",
154
+ userSelect: "none",
155
+ zIndex: 0,
156
+ },
157
+ proceduralSlot: {
158
+ inset: 0,
159
+ pointerEvents: "none",
160
+ position: "absolute",
161
+ },
162
+ proceduralAtmosphere: {
163
+ display: {
164
+ default: null,
165
+ "@media (forced-colors: active)": "none",
166
+ },
167
+ zIndex: 0,
168
+ },
169
+ proceduralCloud: {
170
+ animationDelay: "var(--hraness-design-procedural-layer-delay)",
171
+ animationDirection: "alternate",
172
+ animationDuration: "var(--hraness-design-procedural-layer-duration)",
173
+ animationIterationCount: "infinite",
174
+ animationFillMode: "none",
175
+ animationPlayState: "running",
176
+ animationName: {
177
+ default: proceduralCloudDrift,
178
+ "@media (prefers-reduced-motion: reduce)": "none",
179
+ },
180
+ animationTimingFunction: "var(--motion-easing-emphasized)",
181
+ backgroundAttachment: "scroll",
182
+ backgroundClip: "border-box",
183
+ backgroundColor: "transparent",
184
+ backgroundImage:
185
+ "radial-gradient(ellipse at center, color-mix(in srgb, var(--hraness-design-procedural-layer-color) 58%, transparent) 0%, color-mix(in srgb, var(--hraness-design-procedural-layer-color) 24%, transparent) 48%, transparent 74%)",
186
+ backgroundOrigin: "padding-box",
187
+ backgroundPosition: "0% 0%",
188
+ backgroundRepeat: "repeat",
189
+ backgroundSize: "auto auto",
190
+ borderRadius: "46% 54% 52% 48% / 58% 44% 56% 42%",
191
+ filter: "blur(var(--hraness-design-procedural-layer-blur))",
192
+ height: "var(--hraness-design-procedural-layer-height)",
193
+ left: "var(--hraness-design-procedural-layer-x)",
194
+ opacity: "var(--hraness-design-procedural-layer-opacity)",
195
+ position: "absolute",
196
+ top: "var(--hraness-design-procedural-layer-y)",
197
+ transform:
198
+ "translate3d(-50%, -50%, 0) rotate(var(--hraness-design-procedural-layer-rotation))",
199
+ width: "var(--hraness-design-procedural-layer-width)",
200
+ },
201
+ proceduralGrid: {
202
+ animationDuration: "18s",
203
+ animationIterationCount: "infinite",
204
+ animationFillMode: "none",
205
+ animationPlayState: "running",
206
+ animationDelay: "0s",
207
+ animationDirection: "normal",
208
+ animationName: {
209
+ default: proceduralGridDrift,
210
+ "@media (prefers-reduced-motion: reduce)": "none",
211
+ },
212
+ animationTimingFunction: "linear",
213
+ backgroundImage:
214
+ "linear-gradient(color-mix(in srgb, var(--hraness-design-procedural-support) 44%, transparent) 1px, transparent 1px), linear-gradient(90deg, color-mix(in srgb, var(--hraness-design-procedural-shadow) 38%, transparent) 1px, transparent 1px)",
215
+ backgroundPosition:
216
+ "var(--hraness-design-procedural-grid-offset-x) var(--hraness-design-procedural-grid-offset-y), var(--hraness-design-procedural-grid-offset-x) var(--hraness-design-procedural-grid-offset-y)",
217
+ backgroundSize:
218
+ "var(--hraness-design-procedural-grid-size) var(--hraness-design-procedural-grid-size)",
219
+ display: {
220
+ default: null,
221
+ "@media (forced-colors: active)": "none",
222
+ },
223
+ inset: "-8%",
224
+ maskImage: "radial-gradient(ellipse at center, black 8%, transparent 78%)",
225
+ opacity: "var(--hraness-design-procedural-grid-opacity)",
226
+ transform:
227
+ "rotate(var(--hraness-design-procedural-grid-rotation)) scale(1.04)",
228
+ WebkitMaskImage:
229
+ "radial-gradient(ellipse at center, black 8%, transparent 78%)",
230
+ zIndex: 1,
231
+ },
232
+ proceduralRipples: {
233
+ display: {
234
+ default: null,
235
+ "@media (forced-colors: active)": "none",
236
+ },
237
+ transform: "rotate(var(--hraness-design-procedural-ripple-rotation))",
238
+ zIndex: 2,
239
+ },
240
+ proceduralRipple: {
241
+ borderImageSource: "none",
242
+ borderImageSlice: "100%",
243
+ borderImageWidth: "1",
244
+ borderImageOutset: "0",
245
+ borderImageRepeat: "stretch",
246
+ animationDelay: "var(--hraness-design-procedural-ripple-delay)",
247
+ animationDirection: "alternate",
248
+ animationDuration: "var(--hraness-design-procedural-ripple-duration)",
249
+ animationIterationCount: "infinite",
250
+ animationFillMode: "none",
251
+ animationPlayState: "running",
252
+ animationName: {
253
+ default: proceduralRippleBreathe,
254
+ "@media (prefers-reduced-motion: reduce)": "none",
255
+ },
256
+ animationTimingFunction: "var(--motion-easing-standard)",
257
+ aspectRatio: "1 / var(--hraness-design-procedural-ripple-aspect)",
258
+ borderColor:
259
+ "color-mix(in srgb, var(--hraness-design-procedural-ripple-color) 46%, transparent)",
260
+ borderRadius: "50%",
261
+ borderStyle: "solid",
262
+ borderWidth: 1,
263
+ boxShadow:
264
+ "inset 0 0 24px color-mix(in srgb, var(--hraness-design-procedural-ripple-color) 8%, transparent), 0 0 28px color-mix(in srgb, var(--hraness-design-procedural-ripple-color) 6%, transparent)",
265
+ left: "var(--hraness-design-procedural-ripple-x)",
266
+ opacity: "var(--hraness-design-procedural-ripple-opacity)",
267
+ position: "absolute",
268
+ top: "var(--hraness-design-procedural-ripple-y)",
269
+ transform: "translate3d(-50%, -50%, 0) scale(0.98)",
270
+ width: "var(--hraness-design-procedural-ripple-size)",
271
+ },
272
+ particleRoot: {
273
+ display: "inline-grid",
274
+ isolation: "isolate",
275
+ placeItems: "center",
276
+ position: "relative",
277
+ },
278
+ particleField: {
279
+ display: {
280
+ default: null,
281
+ "@media (forced-colors: active)": "none",
282
+ },
283
+ inset: "-18%",
284
+ overflow: "visible",
285
+ pointerEvents: "none",
286
+ position: "absolute",
287
+ zIndex: 0,
288
+ },
289
+ particle: {
290
+ animationDelay: "var(--hraness-design-particle-delay)",
291
+ animationDirection: "alternate",
292
+ animationDuration: "var(--hraness-design-particle-duration)",
293
+ animationIterationCount: "infinite",
294
+ animationFillMode: "none",
295
+ animationPlayState: "running",
296
+ animationName: {
297
+ default: particleHaloDrift,
298
+ "@media (prefers-reduced-motion: reduce)": "none",
299
+ },
300
+ animationTimingFunction: "var(--motion-easing-emphasized)",
301
+ backgroundAttachment: "scroll",
302
+ backgroundClip: "border-box",
303
+ backgroundColor: "var(--hraness-design-particle-color)",
304
+ backgroundImage: "none",
305
+ backgroundOrigin: "padding-box",
306
+ backgroundPosition: "0% 0%",
307
+ backgroundRepeat: "repeat",
308
+ backgroundSize: "auto auto",
309
+ borderRadius: "var(--radius-round)",
310
+ boxShadow:
311
+ "0 0 calc(var(--hraness-design-particle-size) + var(--hraness-design-particle-size)) color-mix(in srgb, var(--hraness-design-particle-color) 34%, transparent)",
312
+ height: "var(--hraness-design-particle-size)",
313
+ left: "var(--hraness-design-particle-x)",
314
+ opacity: "var(--hraness-design-particle-opacity)",
315
+ position: "absolute",
316
+ top: "var(--hraness-design-particle-y)",
317
+ transform: "translate3d(-50%, -50%, 0)",
318
+ width: "var(--hraness-design-particle-size)",
319
+ },
320
+ particleContent: {
321
+ minWidth: 0,
322
+ position: "relative",
323
+ zIndex: 1,
324
+ },
325
+ });