decantr 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/AGENTS.md +868 -0
  2. package/CHANGELOG.md +255 -0
  3. package/CLAUDE.md +178 -0
  4. package/LICENSE +21 -0
  5. package/README.md +229 -0
  6. package/cli/art.js +127 -0
  7. package/cli/commands/a11y.js +61 -0
  8. package/cli/commands/audit.js +225 -0
  9. package/cli/commands/build.js +38 -0
  10. package/cli/commands/dev.js +18 -0
  11. package/cli/commands/doctor.js +197 -0
  12. package/cli/commands/figma-sync.js +48 -0
  13. package/cli/commands/figma-tokens.js +55 -0
  14. package/cli/commands/generate.js +26 -0
  15. package/cli/commands/init.js +116 -0
  16. package/cli/commands/lint.js +209 -0
  17. package/cli/commands/mcp.js +530 -0
  18. package/cli/commands/migrate.js +175 -0
  19. package/cli/commands/test.js +38 -0
  20. package/cli/commands/validate.js +354 -0
  21. package/cli/index.js +113 -0
  22. package/package.json +95 -0
  23. package/reference/atoms.md +517 -0
  24. package/reference/behaviors.md +384 -0
  25. package/reference/build-tooling.md +275 -0
  26. package/reference/color-guidelines.md +965 -0
  27. package/reference/component-lifecycle.md +137 -0
  28. package/reference/compound-spacing.md +95 -0
  29. package/reference/decantation-process.md +499 -0
  30. package/reference/dev-server-routes.md +93 -0
  31. package/reference/form-system.md +253 -0
  32. package/reference/i18n.md +336 -0
  33. package/reference/icons.md +576 -0
  34. package/reference/llm-primer.md +953 -0
  35. package/reference/plugins.md +252 -0
  36. package/reference/registry-consumption.md +76 -0
  37. package/reference/router.md +217 -0
  38. package/reference/shells.md +116 -0
  39. package/reference/spatial-guidelines.md +541 -0
  40. package/reference/ssr.md +234 -0
  41. package/reference/state-data.md +215 -0
  42. package/reference/state-patterns.md +166 -0
  43. package/reference/state.md +194 -0
  44. package/reference/style-system.md +110 -0
  45. package/reference/tokens.md +460 -0
  46. package/src/app.js +19 -0
  47. package/src/chart/_animate.js +266 -0
  48. package/src/chart/_base.js +109 -0
  49. package/src/chart/_data.js +209 -0
  50. package/src/chart/_format.js +106 -0
  51. package/src/chart/_interact.js +364 -0
  52. package/src/chart/_palette.js +105 -0
  53. package/src/chart/_renderer.js +52 -0
  54. package/src/chart/_scene.js +262 -0
  55. package/src/chart/_shared.js +371 -0
  56. package/src/chart/index.js +637 -0
  57. package/src/chart/layouts/_layout-base.js +328 -0
  58. package/src/chart/layouts/cartesian.js +148 -0
  59. package/src/chart/layouts/hierarchy.js +562 -0
  60. package/src/chart/layouts/polar.js +101 -0
  61. package/src/chart/renderers/canvas.js +179 -0
  62. package/src/chart/renderers/svg.js +256 -0
  63. package/src/chart/renderers/webgpu.js +715 -0
  64. package/src/chart/types/_type-base.js +26 -0
  65. package/src/chart/types/area.js +134 -0
  66. package/src/chart/types/bar.js +173 -0
  67. package/src/chart/types/box-plot.js +125 -0
  68. package/src/chart/types/bubble.js +63 -0
  69. package/src/chart/types/candlestick.js +115 -0
  70. package/src/chart/types/chord.js +85 -0
  71. package/src/chart/types/combination.js +108 -0
  72. package/src/chart/types/funnel.js +68 -0
  73. package/src/chart/types/gauge.js +163 -0
  74. package/src/chart/types/heatmap.js +98 -0
  75. package/src/chart/types/histogram.js +71 -0
  76. package/src/chart/types/line.js +111 -0
  77. package/src/chart/types/org-chart.js +93 -0
  78. package/src/chart/types/pie.js +81 -0
  79. package/src/chart/types/radar.js +96 -0
  80. package/src/chart/types/radial.js +68 -0
  81. package/src/chart/types/range-area.js +55 -0
  82. package/src/chart/types/range-bar.js +61 -0
  83. package/src/chart/types/sankey.js +73 -0
  84. package/src/chart/types/scatter.js +66 -0
  85. package/src/chart/types/sparkline.js +81 -0
  86. package/src/chart/types/sunburst.js +69 -0
  87. package/src/chart/types/swimlane.js +88 -0
  88. package/src/chart/types/treemap.js +62 -0
  89. package/src/chart/types/waterfall.js +100 -0
  90. package/src/components/_base.js +1658 -0
  91. package/src/components/_behaviors.js +1140 -0
  92. package/src/components/_primitives.js +534 -0
  93. package/src/components/_qr-encoder.js +539 -0
  94. package/src/components/accordion.js +207 -0
  95. package/src/components/affix.js +62 -0
  96. package/src/components/alert-dialog.js +75 -0
  97. package/src/components/alert.js +47 -0
  98. package/src/components/aspect-ratio.js +24 -0
  99. package/src/components/avatar-group.js +55 -0
  100. package/src/components/avatar.js +38 -0
  101. package/src/components/back-top.js +75 -0
  102. package/src/components/badge.js +74 -0
  103. package/src/components/banner.js +68 -0
  104. package/src/components/breadcrumb.js +162 -0
  105. package/src/components/button.js +115 -0
  106. package/src/components/calendar.js +131 -0
  107. package/src/components/card.js +192 -0
  108. package/src/components/carousel.js +98 -0
  109. package/src/components/cascader.js +261 -0
  110. package/src/components/checkbox.js +80 -0
  111. package/src/components/chip.js +81 -0
  112. package/src/components/code-block.js +82 -0
  113. package/src/components/collapsible.js +50 -0
  114. package/src/components/color-palette.js +438 -0
  115. package/src/components/color-picker.js +314 -0
  116. package/src/components/combobox.js +181 -0
  117. package/src/components/command.js +174 -0
  118. package/src/components/comment.js +206 -0
  119. package/src/components/context-menu.js +76 -0
  120. package/src/components/data-table.js +724 -0
  121. package/src/components/date-picker.js +217 -0
  122. package/src/components/date-range-picker.js +244 -0
  123. package/src/components/datetime-picker.js +271 -0
  124. package/src/components/descriptions.js +68 -0
  125. package/src/components/drawer.js +179 -0
  126. package/src/components/dropdown.js +88 -0
  127. package/src/components/empty.js +41 -0
  128. package/src/components/float-button.js +90 -0
  129. package/src/components/form.js +106 -0
  130. package/src/components/hover-card.js +49 -0
  131. package/src/components/icon.js +87 -0
  132. package/src/components/image.js +97 -0
  133. package/src/components/index.js +117 -0
  134. package/src/components/input-group.js +75 -0
  135. package/src/components/input-number.js +155 -0
  136. package/src/components/input-otp.js +178 -0
  137. package/src/components/input.js +91 -0
  138. package/src/components/kbd.js +36 -0
  139. package/src/components/label.js +25 -0
  140. package/src/components/list.js +118 -0
  141. package/src/components/masked-input.js +236 -0
  142. package/src/components/mentions.js +165 -0
  143. package/src/components/menu.js +259 -0
  144. package/src/components/message.js +80 -0
  145. package/src/components/modal.js +147 -0
  146. package/src/components/navigation-menu.js +166 -0
  147. package/src/components/notification.js +84 -0
  148. package/src/components/pagination.js +104 -0
  149. package/src/components/placeholder.js +132 -0
  150. package/src/components/popconfirm.js +70 -0
  151. package/src/components/popover.js +58 -0
  152. package/src/components/progress.js +61 -0
  153. package/src/components/qrcode.js +251 -0
  154. package/src/components/radiogroup.js +120 -0
  155. package/src/components/range-slider.js +176 -0
  156. package/src/components/rate.js +186 -0
  157. package/src/components/resizable.js +83 -0
  158. package/src/components/result.js +57 -0
  159. package/src/components/scroll-area.js +43 -0
  160. package/src/components/segmented.js +97 -0
  161. package/src/components/select.js +165 -0
  162. package/src/components/separator.js +31 -0
  163. package/src/components/shell.js +407 -0
  164. package/src/components/skeleton.js +39 -0
  165. package/src/components/slider.js +141 -0
  166. package/src/components/sortable-list.js +176 -0
  167. package/src/components/space.js +42 -0
  168. package/src/components/spinner.js +112 -0
  169. package/src/components/splitter.js +147 -0
  170. package/src/components/statistic.js +136 -0
  171. package/src/components/steps.js +99 -0
  172. package/src/components/switch.js +95 -0
  173. package/src/components/table.js +44 -0
  174. package/src/components/tabs.js +216 -0
  175. package/src/components/tag.js +115 -0
  176. package/src/components/textarea.js +82 -0
  177. package/src/components/time-picker.js +153 -0
  178. package/src/components/time-range-picker.js +170 -0
  179. package/src/components/timeline.js +226 -0
  180. package/src/components/toast.js +71 -0
  181. package/src/components/toggle.js +213 -0
  182. package/src/components/tooltip.js +57 -0
  183. package/src/components/tour.js +159 -0
  184. package/src/components/transfer.js +163 -0
  185. package/src/components/tree-select.js +274 -0
  186. package/src/components/tree.js +141 -0
  187. package/src/components/typography.js +136 -0
  188. package/src/components/upload.js +118 -0
  189. package/src/components/visually-hidden.js +20 -0
  190. package/src/components/watermark.js +124 -0
  191. package/src/core/index.js +539 -0
  192. package/src/core/lifecycle.js +69 -0
  193. package/src/css/atoms.js +651 -0
  194. package/src/css/components.js +940 -0
  195. package/src/css/derive.js +1296 -0
  196. package/src/css/index.js +265 -0
  197. package/src/css/runtime.js +268 -0
  198. package/src/css/styles/addons/bioluminescent.js +93 -0
  199. package/src/css/styles/addons/clay.js +70 -0
  200. package/src/css/styles/addons/clean.js +57 -0
  201. package/src/css/styles/addons/command-center.js +143 -0
  202. package/src/css/styles/addons/dopamine.js +83 -0
  203. package/src/css/styles/addons/editorial.js +80 -0
  204. package/src/css/styles/addons/glassmorphism.js +99 -0
  205. package/src/css/styles/addons/liquid-glass.js +105 -0
  206. package/src/css/styles/addons/prismatic.js +100 -0
  207. package/src/css/styles/addons/retro.js +63 -0
  208. package/src/css/styles/auradecantism.js +96 -0
  209. package/src/css/theme-registry.js +444 -0
  210. package/src/data/entity.js +281 -0
  211. package/src/data/index.js +13 -0
  212. package/src/data/persist.js +225 -0
  213. package/src/data/query.js +839 -0
  214. package/src/data/realtime.js +299 -0
  215. package/src/data/url.js +177 -0
  216. package/src/data/worker.js +134 -0
  217. package/src/explorer/archetypes.js +243 -0
  218. package/src/explorer/atoms.js +228 -0
  219. package/src/explorer/charts.js +497 -0
  220. package/src/explorer/components.js +129 -0
  221. package/src/explorer/foundations.js +949 -0
  222. package/src/explorer/icons.js +178 -0
  223. package/src/explorer/patterns.js +247 -0
  224. package/src/explorer/recipes.js +194 -0
  225. package/src/explorer/shared/pattern-examples.js +1337 -0
  226. package/src/explorer/shared/showcase-renderer.js +958 -0
  227. package/src/explorer/shared/spec-table.js +41 -0
  228. package/src/explorer/shared/usage-links.js +87 -0
  229. package/src/explorer/shell-config.js +10 -0
  230. package/src/explorer/shells.js +551 -0
  231. package/src/explorer/styles.js +161 -0
  232. package/src/explorer/tokens.js +262 -0
  233. package/src/explorer/tools.js +525 -0
  234. package/src/form/index.js +804 -0
  235. package/src/i18n/index.js +251 -0
  236. package/src/icons/essential.js +479 -0
  237. package/src/icons/index.js +53 -0
  238. package/src/plugins/index.js +282 -0
  239. package/src/registry/archetypes/content-site.json +71 -0
  240. package/src/registry/archetypes/docs-explorer.json +23 -0
  241. package/src/registry/archetypes/ecommerce.json +104 -0
  242. package/src/registry/archetypes/financial-dashboard.json +77 -0
  243. package/src/registry/archetypes/index.json +41 -0
  244. package/src/registry/archetypes/portfolio.json +82 -0
  245. package/src/registry/archetypes/recipe-community.json +159 -0
  246. package/src/registry/archetypes/saas-dashboard.json +86 -0
  247. package/src/registry/architect/cross-cutting.json +45 -0
  248. package/src/registry/architect/domains/ecommerce.json +294 -0
  249. package/src/registry/architect/domains/financial-services.json +302 -0
  250. package/src/registry/architect/index.json +26 -0
  251. package/src/registry/architect/traits.json +379 -0
  252. package/src/registry/atoms.json +16 -0
  253. package/src/registry/chart-showcase.json +160 -0
  254. package/src/registry/chart.json +136 -0
  255. package/src/registry/components.json +8616 -0
  256. package/src/registry/core.json +216 -0
  257. package/src/registry/css.json +319 -0
  258. package/src/registry/data.json +135 -0
  259. package/src/registry/foundations.json +11 -0
  260. package/src/registry/icons.json +463 -0
  261. package/src/registry/index.json +101 -0
  262. package/src/registry/patterns/activity-feed.json +37 -0
  263. package/src/registry/patterns/article-content.json +27 -0
  264. package/src/registry/patterns/auth-form.json +37 -0
  265. package/src/registry/patterns/author-card.json +20 -0
  266. package/src/registry/patterns/card-grid.json +127 -0
  267. package/src/registry/patterns/category-nav.json +26 -0
  268. package/src/registry/patterns/chart-grid.json +36 -0
  269. package/src/registry/patterns/chat-interface.json +37 -0
  270. package/src/registry/patterns/checklist-card.json +55 -0
  271. package/src/registry/patterns/comparison-panel.json +27 -0
  272. package/src/registry/patterns/component-showcase.json +24 -0
  273. package/src/registry/patterns/contact-form.json +31 -0
  274. package/src/registry/patterns/cta-section.json +20 -0
  275. package/src/registry/patterns/data-table.json +37 -0
  276. package/src/registry/patterns/detail-header.json +83 -0
  277. package/src/registry/patterns/detail-panel.json +27 -0
  278. package/src/registry/patterns/explorer-shell.json +22 -0
  279. package/src/registry/patterns/filter-bar.json +33 -0
  280. package/src/registry/patterns/filter-sidebar.json +27 -0
  281. package/src/registry/patterns/form-sections.json +110 -0
  282. package/src/registry/patterns/goal-tracker.json +27 -0
  283. package/src/registry/patterns/hero.json +107 -0
  284. package/src/registry/patterns/index.json +47 -0
  285. package/src/registry/patterns/kpi-grid.json +36 -0
  286. package/src/registry/patterns/media-gallery.json +20 -0
  287. package/src/registry/patterns/order-history.json +20 -0
  288. package/src/registry/patterns/pagination.json +19 -0
  289. package/src/registry/patterns/photo-to-recipe.json +36 -0
  290. package/src/registry/patterns/pipeline-tracker.json +28 -0
  291. package/src/registry/patterns/post-list.json +27 -0
  292. package/src/registry/patterns/pricing-table.json +32 -0
  293. package/src/registry/patterns/scorecard.json +28 -0
  294. package/src/registry/patterns/search-bar.json +20 -0
  295. package/src/registry/patterns/specimen-grid.json +19 -0
  296. package/src/registry/patterns/stat-card.json +55 -0
  297. package/src/registry/patterns/stats-bar.json +55 -0
  298. package/src/registry/patterns/steps-card.json +55 -0
  299. package/src/registry/patterns/table-of-contents.json +19 -0
  300. package/src/registry/patterns/testimonials.json +21 -0
  301. package/src/registry/patterns/timeline.json +27 -0
  302. package/src/registry/patterns/token-inspector.json +21 -0
  303. package/src/registry/patterns/wizard.json +27 -0
  304. package/src/registry/recipe-auradecantism.json +69 -0
  305. package/src/registry/recipe-clean.json +65 -0
  306. package/src/registry/recipe-command-center.json +78 -0
  307. package/src/registry/router.json +73 -0
  308. package/src/registry/schema/README.md +197 -0
  309. package/src/registry/skeletons.json +259 -0
  310. package/src/registry/state.json +137 -0
  311. package/src/registry/tokens.json +40 -0
  312. package/src/router/hash.js +17 -0
  313. package/src/router/history.js +18 -0
  314. package/src/router/index.js +598 -0
  315. package/src/ssr/index.js +922 -0
  316. package/src/state/arrays.js +181 -0
  317. package/src/state/devtools.js +647 -0
  318. package/src/state/index.js +498 -0
  319. package/src/state/middleware.js +288 -0
  320. package/src/state/scheduler.js +206 -0
  321. package/src/state/store.js +300 -0
  322. package/src/tags/index.js +19 -0
  323. package/src/tannins/auth.js +396 -0
  324. package/src/test/dom.js +352 -0
  325. package/src/test/index.js +62 -0
  326. package/src/test/state.js +306 -0
  327. package/tools/a11y-audit.js +487 -0
  328. package/tools/analyzer.js +315 -0
  329. package/tools/audit.js +706 -0
  330. package/tools/builder.js +1422 -0
  331. package/tools/css-extract.js +188 -0
  332. package/tools/dev-server.js +316 -0
  333. package/tools/dts-gen.js +1260 -0
  334. package/tools/figma-components.js +329 -0
  335. package/tools/figma-patterns.js +516 -0
  336. package/tools/figma-plugin/code.js +453 -0
  337. package/tools/figma-plugin/manifest.json +14 -0
  338. package/tools/figma-plugin/ui.html +268 -0
  339. package/tools/figma-render.js +293 -0
  340. package/tools/figma-tokens.js +712 -0
  341. package/tools/figma-upload.js +318 -0
  342. package/tools/generate.js +738 -0
  343. package/tools/icons.js +133 -0
  344. package/tools/init-templates.js +265 -0
  345. package/tools/install-hooks.sh +5 -0
  346. package/tools/migrations/0.5.0.js +53 -0
  347. package/tools/migrations/0.6.0.js +95 -0
  348. package/tools/minify.js +170 -0
  349. package/tools/pre-commit +4 -0
  350. package/tools/registry.js +662 -0
  351. package/tools/reset-playground.js +61 -0
  352. package/tools/starter-templates/content-site/app.js +49 -0
  353. package/tools/starter-templates/content-site/essence.js +19 -0
  354. package/tools/starter-templates/content-site/pages.js +31 -0
  355. package/tools/starter-templates/ecommerce/app.js +50 -0
  356. package/tools/starter-templates/ecommerce/essence.js +19 -0
  357. package/tools/starter-templates/ecommerce/pages.js +31 -0
  358. package/tools/starter-templates/landing-page/app.js +38 -0
  359. package/tools/starter-templates/landing-page/essence.js +18 -0
  360. package/tools/starter-templates/landing-page/pages.js +21 -0
  361. package/tools/starter-templates/portfolio/app.js +45 -0
  362. package/tools/starter-templates/portfolio/essence.js +19 -0
  363. package/tools/starter-templates/portfolio/pages.js +33 -0
  364. package/tools/starter-templates/saas-dashboard/app.js +70 -0
  365. package/tools/starter-templates/saas-dashboard/essence.js +19 -0
  366. package/tools/starter-templates/saas-dashboard/pages.js +31 -0
  367. package/tools/verify-pack.js +203 -0
  368. package/types/chart.d.ts +77 -0
  369. package/types/components.d.ts +587 -0
  370. package/types/core.d.ts +89 -0
  371. package/types/css.d.ts +149 -0
  372. package/types/data.d.ts +238 -0
  373. package/types/form.d.ts +164 -0
  374. package/types/i18n.d.ts +51 -0
  375. package/types/icons.d.ts +27 -0
  376. package/types/index.d.ts +13 -0
  377. package/types/router.d.ts +116 -0
  378. package/types/ssr.d.ts +102 -0
  379. package/types/state.d.ts +83 -0
  380. package/types/tags.d.ts +62 -0
  381. package/types/tannins.d.ts +63 -0
  382. package/types/test.d.ts +48 -0
@@ -0,0 +1,265 @@
1
+ import { resolveAtomDecl } from './atoms.js';
2
+ import { inject, injectResponsive, injectResponsivePseudo, injectContainer, injectGroupPeer, injectPseudo, BREAKPOINTS, CQ_WIDTHS } from './runtime.js';
3
+ export { extractCSS, reset, BREAKPOINTS, CQ_WIDTHS } from './runtime.js';
4
+ export {
5
+ setTheme, getTheme, getThemeMeta, registerTheme, getThemeList,
6
+ getActiveCSS, resetStyles, setAnimations, getAnimations,
7
+ setStyle, getStyle, getStyleList, registerStyle, mergePluginStyles,
8
+ setMode, getMode, getResolvedMode, onModeChange,
9
+ setShape, getShape, getShapeList,
10
+ setColorblindMode, getColorblindMode
11
+ } from './theme-registry.js';
12
+
13
+ /** @type {Map<string, string>} */
14
+ const customAtoms = new Map();
15
+
16
+ /** Regex to detect responsive prefix: _sm:, _md:, _lg:, _xl: */
17
+ const BP_RE = /^_(sm|md|lg|xl):(.+)$/;
18
+
19
+ /** Regex to detect container query prefix: _cq320:, _cq480:, _cq640:, _cq768:, _cq1024: */
20
+ const CQ_RE = /^_cq(\d+):(.+)$/;
21
+
22
+ /** Regex to detect group/peer state prefix: _gh:, _gf:, _ga:, _ph:, _pf:, _pa: */
23
+ const GP_RE = /^_(gh|gf|ga|ph|pf|pa):(.+)$/;
24
+
25
+ /** Regex to detect pseudo-class prefix: _h:, _f:, _fv:, _a:, _fw: */
26
+ const PSEUDO_RE = /^_(h|f|fv|a|fw):(.+)$/;
27
+
28
+ /** Valid pseudo-class prefixes */
29
+ const PSEUDO_SET = new Set(['h', 'f', 'fv', 'a', 'fw']);
30
+
31
+ /** Regex to detect opacity modifier: _bgprimary/50, _fgaccent/30 */
32
+ const ALPHA_RE = /^(_[a-zA-Z0-9]+)\/(\d+)$/;
33
+
34
+ /** Regex to detect arbitrary value: _w[512px], _bg[#1a1d24] */
35
+ const ARB_RE = /^_([a-zA-Z]+)\[([^\]]+)\]$/;
36
+
37
+ /** Valid container query widths as a Set for fast lookup */
38
+ const CQ_SET = new Set(CQ_WIDTHS);
39
+
40
+ /** Valid group/peer prefixes */
41
+ const GP_SET = new Set(['gh', 'gf', 'ga', 'ph', 'pf', 'pa']);
42
+
43
+ /** Property prefix map for arbitrary values */
44
+ const ARB_PROPS = {
45
+ w: 'width', h: 'height', mw: 'max-width', mh: 'max-height',
46
+ minw: 'min-width', minh: 'min-height',
47
+ p: 'padding', pt: 'padding-top', pr: 'padding-right', pb: 'padding-bottom', pl: 'padding-left',
48
+ px: 'padding-inline', py: 'padding-block',
49
+ m: 'margin', mt: 'margin-top', mr: 'margin-right', mb: 'margin-bottom', ml: 'margin-left',
50
+ mx: 'margin-inline', my: 'margin-block',
51
+ gap: 'gap', gx: 'column-gap', gy: 'row-gap',
52
+ t: 'font-size', fs: 'font-size', lh: 'line-height', fw: 'font-weight', ls: 'letter-spacing',
53
+ r: 'border-radius', bg: 'background', fg: 'color', bc: 'border-color',
54
+ bw: 'border-width', bt: 'border-top', bb: 'border-bottom', br: 'border-right', bl: 'border-left',
55
+ z: 'z-index', op: 'opacity',
56
+ top: 'top', right: 'right', bottom: 'bottom', left: 'left', inset: 'inset',
57
+ shadow: 'box-shadow', bf: 'backdrop-filter',
58
+ outline: 'outline', trans: 'transition', object: 'object-fit',
59
+ };
60
+
61
+ /**
62
+ * Resolve an atom name to its CSS declaration.
63
+ * Handles: standard atoms, opacity modifiers (/N), and arbitrary values ([val]).
64
+ * @param {string} atomPart — e.g. '_p4', '_bgprimary/50', '_w[512px]'
65
+ * @returns {{ className: string, decl: string }|null}
66
+ */
67
+ function resolveAtom(atomPart) {
68
+ // 1. Custom atoms first (user-defined via define())
69
+ const custom = customAtoms.get(atomPart);
70
+ if (custom) return { className: atomPart, decl: custom };
71
+
72
+ // 2. Algorithmic resolution (handles aliases, direct, patterns, residual)
73
+ const decl = resolveAtomDecl(atomPart);
74
+ if (decl) return { className: atomPart, decl };
75
+
76
+ // 3. Opacity modifier: _bgprimary/50
77
+ const alphaMatch = atomPart.match(ALPHA_RE);
78
+ if (alphaMatch) {
79
+ const [, base, alphaStr] = alphaMatch;
80
+ const baseDecl = customAtoms.get(base) || resolveAtomDecl(base);
81
+ if (baseDecl) {
82
+ const alpha = Number(alphaStr);
83
+ if (alpha >= 0 && alpha <= 100) {
84
+ // Extract property:var(--d-*) pattern for color-mix
85
+ const colorMatch = baseDecl.match(/^(background|color|border-color):(var\(--[^)]+\))$/);
86
+ if (colorMatch) {
87
+ const [, prop, varRef] = colorMatch;
88
+ return {
89
+ className: atomPart,
90
+ decl: `${prop}:color-mix(in srgb,${varRef} ${alpha}%,transparent)`,
91
+ };
92
+ }
93
+ }
94
+ }
95
+ return null;
96
+ }
97
+
98
+ // 3. Arbitrary value: _w[512px]
99
+ const arbMatch = atomPart.match(ARB_RE);
100
+ if (arbMatch) {
101
+ const [, propPrefix, rawValue] = arbMatch;
102
+ const cssProp = ARB_PROPS[propPrefix] || ARB_PROPS[propPrefix.toLowerCase()];
103
+ if (cssProp) {
104
+ // Convert underscores to spaces in value (e.g., 0_4px_6px → 0 4px 6px)
105
+ const value = rawValue.replace(/_/g, ' ');
106
+ return { className: atomPart, decl: `${cssProp}:${value}` };
107
+ }
108
+ return null;
109
+ }
110
+
111
+ // Dev-mode warning for unresolved atoms (atoms start with _)
112
+ if (atomPart.startsWith('_') && typeof globalThis !== 'undefined' && globalThis.__DECANTR_DEV__) {
113
+ console.warn(`[decantr] Unknown atom: "${atomPart}" — no CSS will be generated. Check reference/atoms.md`);
114
+ }
115
+
116
+ return null;
117
+ }
118
+
119
+ /**
120
+ * Escape special characters in a CSS class name for use in selectors.
121
+ * @param {string} cls
122
+ * @returns {string}
123
+ */
124
+ function escapeClass(cls) {
125
+ return cls.replace(/:/g, '\\:').replace(/\//g, '\\/').replace(/\[/g, '\\[').replace(/\]/g, '\\]').replace(/#/g, '\\#').replace(/%/g, '\\%').replace(/\(/g, '\\(').replace(/\)/g, '\\)').replace(/,/g, '\\,').replace(/\+/g, '\\+');
126
+ }
127
+
128
+ /**
129
+ * @param {...string} classes
130
+ * @returns {string}
131
+ */
132
+ export function css(...classes) {
133
+ const result = [];
134
+ for (let i = 0; i < classes.length; i++) {
135
+ const cls = classes[i];
136
+ if (!cls) continue;
137
+ // Support space-separated classes in a single string
138
+ const parts = cls.split(/\s+/);
139
+ for (const part of parts) {
140
+ if (!part) continue;
141
+
142
+ // Special handling: _group → d-group, _peer → d-peer
143
+ if (part === '_group') { result.push('d-group'); continue; }
144
+ if (part === '_peer') { result.push('d-peer'); continue; }
145
+ // Component-class atoms: _prose → d-prose, _divideY → d-divide-y, _divideX → d-divide-x
146
+ if (part === '_prose') { result.push('d-prose'); continue; }
147
+ if (part === '_divideY') { result.push('d-divide-y'); continue; }
148
+ if (part === '_divideX') { result.push('d-divide-x'); continue; }
149
+
150
+ // Check for responsive prefix: _sm:gc3 → atom _gc3 at breakpoint sm
151
+ const bpMatch = part.match(BP_RE);
152
+ if (bpMatch) {
153
+ const [, bp, innerAtom] = bpMatch;
154
+ // The inner atom may itself be a group/peer, opacity, or arbitrary
155
+ const gpInner = innerAtom.match(/^(gh|gf|ga|ph|pf|pa):(.+)$/);
156
+ if (gpInner) {
157
+ // Responsive + group/peer: not supported (too complex), pass through
158
+ result.push(part);
159
+ continue;
160
+ }
161
+ // Check for responsive + pseudo: _sm:h:bgmuted
162
+ const pseudoInner = innerAtom.match(/^(h|f|fv|a|fw):(.+)$/);
163
+ if (pseudoInner) {
164
+ const [, pseudoPrefix, atomName] = pseudoInner;
165
+ const resolved = resolveAtom(`_${atomName}`);
166
+ if (resolved) {
167
+ const PSEUDO_NAMES = { h: 'hover', f: 'focus', fv: 'focus-visible', a: 'active', fw: 'focus-within' };
168
+ injectResponsivePseudo(part, resolved.decl, bp, PSEUDO_NAMES[pseudoPrefix]);
169
+ result.push(part);
170
+ } else {
171
+ result.push(part);
172
+ }
173
+ continue;
174
+ }
175
+ const resolved = resolveAtom(`_${innerAtom}`);
176
+ if (resolved) {
177
+ injectResponsive(part, resolved.decl, bp);
178
+ result.push(part);
179
+ } else {
180
+ result.push(part);
181
+ }
182
+ continue;
183
+ }
184
+
185
+ // Check for container query prefix: _cq640:gc3
186
+ const cqMatch = part.match(CQ_RE);
187
+ if (cqMatch) {
188
+ const width = Number(cqMatch[1]);
189
+ const innerAtom = cqMatch[2];
190
+ if (CQ_SET.has(width)) {
191
+ const resolved = resolveAtom(`_${innerAtom}`);
192
+ if (resolved) {
193
+ injectContainer(part, resolved.decl, width);
194
+ result.push(part);
195
+ } else {
196
+ result.push(part);
197
+ }
198
+ } else {
199
+ result.push(part);
200
+ }
201
+ continue;
202
+ }
203
+
204
+ // Check for group/peer state prefix: _gh:fgprimary
205
+ const gpMatch = part.match(GP_RE);
206
+ if (gpMatch) {
207
+ const [, prefix, atomName] = gpMatch;
208
+ const resolved = resolveAtom(`_${atomName}`);
209
+ if (resolved) {
210
+ injectGroupPeer(part, resolved.decl, prefix);
211
+ result.push(part);
212
+ } else {
213
+ result.push(part);
214
+ }
215
+ continue;
216
+ }
217
+
218
+ // Check for pseudo-class prefix: _h:bgprimary, _fv:ring2, _a:scale95
219
+ const pseudoMatch = part.match(PSEUDO_RE);
220
+ if (pseudoMatch) {
221
+ const [, prefix, innerAtom] = pseudoMatch;
222
+ const resolved = resolveAtom(`_${innerAtom}`);
223
+ if (resolved) {
224
+ injectPseudo(part, resolved.decl, prefix);
225
+ result.push(part);
226
+ } else {
227
+ result.push(part);
228
+ }
229
+ continue;
230
+ }
231
+
232
+ // Try to resolve (handles direct, opacity, and arbitrary)
233
+ const resolved = resolveAtom(part);
234
+ if (resolved) {
235
+ // Pass escaped class name if it contains special CSS selector characters
236
+ const needsEscape = /[/\[\]#%(),+]/.test(resolved.className);
237
+ inject(resolved.className, resolved.decl, needsEscape ? escapeClass(resolved.className) : undefined);
238
+ result.push(part);
239
+ } else {
240
+ // Pass through unknown classes (user CSS)
241
+ result.push(part);
242
+ }
243
+ }
244
+ }
245
+ return result.join(' ');
246
+ }
247
+
248
+ /**
249
+ * @param {string} name
250
+ * @param {string} declaration
251
+ */
252
+ export function define(name, declaration) {
253
+ customAtoms.set(name, declaration);
254
+ }
255
+
256
+ /**
257
+ * Sanitizes a string for safe use in HTML attributes.
258
+ * Escapes <, >, ", ', & characters.
259
+ * @param {string} str
260
+ * @returns {string}
261
+ */
262
+ export function sanitize(str) {
263
+ if (typeof str !== 'string') return '';
264
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;');
265
+ }
@@ -0,0 +1,268 @@
1
+ /** @type {Set<string>} */
2
+ const injected = new Set();
3
+
4
+ /** @type {HTMLStyleElement|null} */
5
+ let styleEl = null;
6
+
7
+ /** @type {HTMLStyleElement|null} */
8
+ let layerEl = null;
9
+
10
+ /** Responsive breakpoints (mobile-first, min-width) */
11
+ export const BREAKPOINTS = { sm: 640, md: 768, lg: 1024, xl: 1280 };
12
+ const BP_ORDER = ['sm', 'md', 'lg', 'xl'];
13
+
14
+ /** Container query breakpoints */
15
+ export const CQ_WIDTHS = [320, 480, 640, 768, 1024];
16
+
17
+ /** @type {Record<string, HTMLStyleElement>|null} */
18
+ let bpEls = null;
19
+
20
+ /** @type {HTMLStyleElement|null} */
21
+ let cqEl = null;
22
+
23
+ /** CSS cascade layer order declaration */
24
+ const LAYER_ORDER = '@layer d.base,d.theme,d.atoms,d.user;';
25
+
26
+ // ─── Buffered injection ─────────────────────────────────────────
27
+ // Rules are buffered in arrays and flushed to DOM in batches via
28
+ // microtask, avoiding O(n²) string concatenation on textContent.
29
+
30
+ /** @type {string[]} */
31
+ let atomBuffer = [];
32
+ /** @type {Record<string, string[]>} */
33
+ let bpBuffers = {};
34
+ /** @type {string[]} */
35
+ let cqBuffer = [];
36
+ /** @type {boolean} */
37
+ let flushScheduled = false;
38
+
39
+ function scheduleFlush() {
40
+ if (flushScheduled) return;
41
+ flushScheduled = true;
42
+ if (typeof queueMicrotask === 'function') {
43
+ queueMicrotask(flushBuffers);
44
+ } else {
45
+ Promise.resolve().then(flushBuffers);
46
+ }
47
+ }
48
+
49
+ function flushBuffers() {
50
+ flushScheduled = false;
51
+ if (atomBuffer.length) {
52
+ const el = getStyleElement();
53
+ if (el) el.textContent = (el.textContent || '') + atomBuffer.join('');
54
+ atomBuffer.length = 0;
55
+ }
56
+ if (Object.keys(bpBuffers).length) {
57
+ const els = ensureBpElements();
58
+ if (els) {
59
+ for (const bp of BP_ORDER) {
60
+ if (bpBuffers[bp] && bpBuffers[bp].length) {
61
+ els[bp].textContent = (els[bp].textContent || '') + bpBuffers[bp].join('');
62
+ bpBuffers[bp].length = 0;
63
+ }
64
+ }
65
+ }
66
+ bpBuffers = {};
67
+ }
68
+ if (cqBuffer.length) {
69
+ const el = ensureCqElement();
70
+ if (el) el.textContent = (el.textContent || '') + cqBuffer.join('');
71
+ cqBuffer.length = 0;
72
+ }
73
+ }
74
+
75
+ function ensureLayerOrder() {
76
+ if (layerEl) return;
77
+ if (typeof document === 'undefined') return;
78
+ layerEl = document.createElement('style');
79
+ layerEl.setAttribute('data-decantr-layers', '');
80
+ layerEl.textContent = LAYER_ORDER;
81
+ document.head.prepend(layerEl);
82
+ }
83
+
84
+ function getStyleElement() {
85
+ if (!styleEl) {
86
+ if (typeof document === 'undefined') return null;
87
+ ensureLayerOrder();
88
+ styleEl = document.createElement('style');
89
+ styleEl.setAttribute('data-decantr', '');
90
+ document.head.appendChild(styleEl);
91
+ }
92
+ return styleEl;
93
+ }
94
+
95
+ function ensureBpElements() {
96
+ if (bpEls) return bpEls;
97
+ if (typeof document === 'undefined') return null;
98
+ bpEls = {};
99
+ getStyleElement();
100
+ for (const bp of BP_ORDER) {
101
+ const el = document.createElement('style');
102
+ el.setAttribute(`data-decantr-${bp}`, '');
103
+ document.head.appendChild(el);
104
+ bpEls[bp] = el;
105
+ }
106
+ return bpEls;
107
+ }
108
+
109
+ /**
110
+ * @param {string} className
111
+ * @param {string} declaration
112
+ * @param {string} [escapedName] — pre-escaped class name for special chars (/, [, ], etc.)
113
+ */
114
+ export function inject(className, declaration, escapedName) {
115
+ if (injected.has(className)) return;
116
+ injected.add(className);
117
+ if (typeof document === 'undefined') return;
118
+ const sel = escapedName || className;
119
+ atomBuffer.push(`@layer d.atoms{.${sel}{${declaration}}}`);
120
+ scheduleFlush();
121
+ }
122
+
123
+ /**
124
+ * Inject a responsive (breakpoint-wrapped) atom.
125
+ * @param {string} className — e.g. '_sm:gc3'
126
+ * @param {string} declaration — CSS declaration(s)
127
+ * @param {string} bp — breakpoint key (sm|md|lg|xl)
128
+ */
129
+ export function injectResponsive(className, declaration, bp) {
130
+ if (injected.has(className)) return;
131
+ injected.add(className);
132
+ if (typeof document === 'undefined') return;
133
+ const escaped = className.replace(/:/g, '\\:');
134
+ if (!bpBuffers[bp]) bpBuffers[bp] = [];
135
+ bpBuffers[bp].push(`@layer d.atoms{@media(min-width:${BREAKPOINTS[bp]}px){.${escaped}{${declaration}}}}`);
136
+ scheduleFlush();
137
+ }
138
+
139
+ function ensureCqElement() {
140
+ if (cqEl) return cqEl;
141
+ if (typeof document === 'undefined') return null;
142
+ getStyleElement();
143
+ cqEl = document.createElement('style');
144
+ cqEl.setAttribute('data-decantr-cq', '');
145
+ document.head.appendChild(cqEl);
146
+ return cqEl;
147
+ }
148
+
149
+ /**
150
+ * Inject a container query-wrapped atom.
151
+ * @param {string} className — e.g. '_cq640:gc3'
152
+ * @param {string} declaration — CSS declaration(s)
153
+ * @param {number} width — container min-width in px
154
+ */
155
+ export function injectContainer(className, declaration, width) {
156
+ if (injected.has(className)) return;
157
+ injected.add(className);
158
+ if (typeof document === 'undefined') return;
159
+ const escaped = className.replace(/:/g, '\\:');
160
+ cqBuffer.push(`@layer d.atoms{@container(min-width:${width}px){.${escaped}{${declaration}}}}`);
161
+ scheduleFlush();
162
+ }
163
+
164
+ /** State map for group/peer prefix → CSS pseudo selector */
165
+ const GP_STATE = {
166
+ gh: ['group', 'hover'], gf: ['group', 'focus-within'], ga: ['group', 'active'],
167
+ ph: ['peer', 'hover'], pf: ['peer', 'focus'], pa: ['peer', 'active'],
168
+ };
169
+
170
+ /**
171
+ * Inject a group/peer state atom.
172
+ * @param {string} className — e.g. '_gh:fgprimary'
173
+ * @param {string} declaration — CSS declaration(s)
174
+ * @param {string} prefix — 'gh'|'gf'|'ga'|'ph'|'pf'|'pa'
175
+ */
176
+ export function injectGroupPeer(className, declaration, prefix) {
177
+ if (injected.has(className)) return;
178
+ injected.add(className);
179
+ if (typeof document === 'undefined') return;
180
+ const escaped = className.replace(/:/g, '\\:').replace(/\//g, '\\/');
181
+ const [kind, state] = GP_STATE[prefix];
182
+ const combinator = kind === 'group' ? ' ' : ' ~ ';
183
+ atomBuffer.push(`@layer d.atoms{.d-${kind}:${state}${combinator}.${escaped}{${declaration}}}`);
184
+ scheduleFlush();
185
+ }
186
+
187
+ /** Pseudo-class prefix map */
188
+ const PSEUDO_MAP = {
189
+ h: 'hover', f: 'focus', fv: 'focus-visible', a: 'active', fw: 'focus-within',
190
+ };
191
+
192
+ /**
193
+ * Inject a pseudo-class atom.
194
+ * @param {string} className — e.g. '_h:bgprimary'
195
+ * @param {string} declaration — CSS declaration(s)
196
+ * @param {string} prefix — 'h'|'f'|'fv'|'a'|'fw'
197
+ */
198
+ export function injectPseudo(className, declaration, prefix) {
199
+ if (injected.has(className)) return;
200
+ injected.add(className);
201
+ if (typeof document === 'undefined') return;
202
+ const escaped = className.replace(/:/g, '\\:').replace(/\//g, '\\/').replace(/\[/g, '\\[').replace(/\]/g, '\\]').replace(/#/g, '\\#').replace(/%/g, '\\%').replace(/\(/g, '\\(').replace(/\)/g, '\\)').replace(/,/g, '\\,').replace(/\+/g, '\\+');
203
+ const pseudo = PSEUDO_MAP[prefix];
204
+ atomBuffer.push(`@layer d.atoms{.${escaped}:${pseudo}{${declaration}}}`);
205
+ scheduleFlush();
206
+ }
207
+
208
+ /**
209
+ * Inject a responsive + pseudo-class atom.
210
+ * @param {string} className — e.g. '_sm:h:bgprimary'
211
+ * @param {string} declaration — CSS declaration(s)
212
+ * @param {string} bp — breakpoint key (sm|md|lg|xl)
213
+ * @param {string} pseudo — pseudo-class name (hover|focus|focus-visible|active|focus-within)
214
+ */
215
+ export function injectResponsivePseudo(className, declaration, bp, pseudo) {
216
+ if (injected.has(className)) return;
217
+ injected.add(className);
218
+ if (typeof document === 'undefined') return;
219
+ const escaped = className.replace(/:/g, '\\:').replace(/\//g, '\\/').replace(/\[/g, '\\[').replace(/\]/g, '\\]').replace(/#/g, '\\#').replace(/%/g, '\\%').replace(/\(/g, '\\(').replace(/\)/g, '\\)').replace(/,/g, '\\,').replace(/\+/g, '\\+');
220
+ if (!bpBuffers[bp]) bpBuffers[bp] = [];
221
+ bpBuffers[bp].push(`@layer d.atoms{@media(min-width:${BREAKPOINTS[bp]}px){.${escaped}:${pseudo}{${declaration}}}}`);
222
+ scheduleFlush();
223
+ }
224
+
225
+ /**
226
+ * @returns {string}
227
+ */
228
+ export function extractCSS() {
229
+ flushBuffers();
230
+ let css = layerEl ? layerEl.textContent || '' : '';
231
+ css += styleEl ? styleEl.textContent || '' : '';
232
+ if (bpEls) {
233
+ for (const bp of BP_ORDER) {
234
+ if (bpEls[bp]) css += bpEls[bp].textContent || '';
235
+ }
236
+ }
237
+ if (cqEl) css += cqEl.textContent || '';
238
+ return css;
239
+ }
240
+
241
+ /**
242
+ * @returns {Set<string>}
243
+ */
244
+ export function getInjectedClasses() {
245
+ return new Set(injected);
246
+ }
247
+
248
+ export function reset() {
249
+ injected.clear();
250
+ atomBuffer.length = 0;
251
+ bpBuffers = {};
252
+ cqBuffer.length = 0;
253
+ flushScheduled = false;
254
+ if (layerEl) {
255
+ layerEl.textContent = LAYER_ORDER;
256
+ }
257
+ if (styleEl) {
258
+ styleEl.textContent = '';
259
+ }
260
+ if (bpEls) {
261
+ for (const bp of BP_ORDER) {
262
+ if (bpEls[bp]) bpEls[bp].textContent = '';
263
+ }
264
+ }
265
+ if (cqEl) {
266
+ cqEl.textContent = '';
267
+ }
268
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Bioluminescent — Deep ocean aesthetic. Organic glow.
3
+ * Luminescent edges on dark backgrounds, living and breathing UI.
4
+ * Glowing borders, pulsing animations, deep abyss backgrounds.
5
+ */
6
+ export const bioluminescent = {
7
+ id: 'bioluminescent',
8
+ name: 'Bioluminescent',
9
+ seed: {
10
+ primary: '#00ffd5',
11
+ accent: '#7b61ff',
12
+ tertiary: '#ff6b9d',
13
+ neutral: '#6b8299',
14
+ success: '#00e676',
15
+ warning: '#ffab40',
16
+ error: '#ff5252',
17
+ info: '#40c4ff',
18
+ bg: '#f0fdf4',
19
+ bgDark: '#020817',
20
+ },
21
+ personality: {
22
+ radius: 'pill',
23
+ elevation: 'glow',
24
+ motion: 'smooth',
25
+ borders: 'none',
26
+ density: 'comfortable',
27
+ gradient: 'vivid',
28
+ },
29
+ typography: {
30
+ '--d-fw-heading': '500',
31
+ '--d-fw-title': '400',
32
+ '--d-ls-heading': '0.03em',
33
+ },
34
+ overrides: {
35
+ light: {
36
+ '--d-border': 'rgba(0,255,213,0.12)',
37
+ '--d-border-strong': 'rgba(0,255,213,0.22)',
38
+ '--d-field-bg': 'rgba(255,255,255,0.6)',
39
+ '--d-field-border': 'rgba(0,255,213,0.15)',
40
+ '--d-field-border-hover': 'rgba(0,255,213,0.3)',
41
+ '--d-item-hover-bg': 'rgba(0,255,213,0.06)',
42
+ },
43
+ dark: {
44
+ '--d-bg': '#020817',
45
+ '--d-fg': '#c8e6df',
46
+ '--d-muted-fg': '#5a8a7d',
47
+ '--d-border': 'rgba(0,255,213,0.1)',
48
+ '--d-border-strong': 'rgba(0,255,213,0.2)',
49
+ '--d-field-bg': 'rgba(0,255,213,0.04)',
50
+ '--d-field-border': 'rgba(0,255,213,0.12)',
51
+ '--d-field-border-hover': 'rgba(0,255,213,0.25)',
52
+ '--d-item-hover-bg': 'rgba(0,255,213,0.06)',
53
+ '--d-chart-0': '#00ffd5',
54
+ '--d-chart-1': '#7b61ff',
55
+ '--d-chart-2': '#ff6b9d',
56
+ '--d-chart-3': '#00e676',
57
+ '--d-chart-4': '#ffab40',
58
+ '--d-chart-5': '#40c4ff',
59
+ '--d-chart-6': '#e040fb',
60
+ '--d-chart-7': '#76ff03',
61
+ },
62
+ },
63
+ components: [
64
+ 'body{font-family:var(--d-font);background:var(--d-bg);color:var(--d-fg);line-height:var(--d-lh-normal);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}',
65
+ '::selection{background:rgba(0,255,213,0.25);color:var(--d-fg)}',
66
+ // Scrollbar — dark with glowing thumb
67
+ '::-webkit-scrollbar{width:6px;height:6px}',
68
+ '::-webkit-scrollbar-track{background:transparent}',
69
+ '::-webkit-scrollbar-thumb{background:rgba(0,255,213,0.2);border-radius:var(--d-radius-full)}',
70
+ '::-webkit-scrollbar-thumb:hover{background:rgba(0,255,213,0.4);box-shadow:0 0 8px rgba(0,255,213,0.3)}',
71
+ // Card — glowing edges
72
+ '.d-card{border:none;box-shadow:var(--d-elevation-1),0 0 1px rgba(0,255,213,0.2)}',
73
+ '.d-card-inner{box-shadow:none}',
74
+ // Modal — intense glow
75
+ '.d-modal-content{border:none;box-shadow:var(--d-elevation-3),0 0 2px rgba(0,255,213,0.3)}',
76
+ // Button — bioluminescent glow
77
+ '.d-btn-primary{box-shadow:0 0 12px rgba(0,255,213,0.25),0 0 4px rgba(0,255,213,0.15)}',
78
+ '.d-btn-primary:hover{box-shadow:0 0 20px rgba(0,255,213,0.35),0 0 8px rgba(0,255,213,0.2)}',
79
+ // Bioluminescent utilities
80
+ '@keyframes d-biolum-pulse{0%,100%{box-shadow:0 0 8px rgba(0,255,213,0.15)}50%{box-shadow:0 0 20px rgba(0,255,213,0.3),0 0 4px rgba(0,255,213,0.15)}}',
81
+ '.d-biolum-pulse{animation:d-biolum-pulse 3s ease-in-out infinite}',
82
+ '.d-biolum-edge{box-shadow:0 0 8px rgba(0,255,213,0.2),inset 0 0 8px rgba(0,255,213,0.05)}',
83
+ '.d-biolum-trail{transition:box-shadow var(--d-tr-normal) var(--d-ease-standard)}',
84
+ '.d-biolum-trail:hover{box-shadow:0 0 16px rgba(0,255,213,0.25),4px 0 12px rgba(123,97,255,0.15),-4px 0 12px rgba(255,107,157,0.15)}',
85
+ // Gradient text — oceanic
86
+ '.d-gradient-text{background:linear-gradient(135deg,var(--d-primary),var(--d-accent),var(--d-tertiary));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}',
87
+ '.d-gradient-text-alt{background:linear-gradient(135deg,var(--d-accent),var(--d-primary));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}',
88
+ // Mesh — underwater glow
89
+ '.d-mesh{background:radial-gradient(ellipse at 30% 60%,rgba(0,255,213,0.08) 0%,transparent 50%),radial-gradient(ellipse at 70% 30%,rgba(123,97,255,0.06) 0%,transparent 50%),radial-gradient(ellipse at 50% 90%,rgba(255,107,157,0.04) 0%,transparent 50%),var(--d-bg)}',
90
+ // Frosted dialog
91
+ 'dialog::backdrop{background:rgba(2,8,23,0.6);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}',
92
+ ].join(''),
93
+ };