@almadar/shell-web 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/bundling.d.mts +18 -0
  2. package/bundling.mjs +28 -0
  3. package/dist/ArbitraryClassCompiler-Mzabq-UB.d.ts +100 -0
  4. package/dist/AvlGlyph-JKJOAH23.js +6 -0
  5. package/dist/AvlStateMachine-PI4YGREK.js +8 -0
  6. package/dist/AvlTransitionDetail-ZH7V24UG.js +12 -0
  7. package/dist/AvlTransitionExplainer-ZSRT7L6Y.js +13 -0
  8. package/dist/BehaviorValueFrame-6RUJXT4A.js +29 -0
  9. package/dist/BehaviorValueFrame-SSEMEBTG.css +1756 -0
  10. package/dist/BehaviorView-RFEE5J6E.js +10 -0
  11. package/dist/Canvas3DHost-_Y-5uLM_.d.ts +552 -0
  12. package/dist/EventBusProvider-CVwjkV_2.d.ts +284 -0
  13. package/dist/FileTree-BCFnBEuQ.d.ts +254 -0
  14. package/dist/FlowCanvas-3JRMNJLV.css +1756 -0
  15. package/dist/FlowCanvas-STDC4OWK.js +27 -0
  16. package/dist/GameAudioProvider-Cm9BnvmP.d.ts +93 -0
  17. package/dist/KaTeX_AMS-Regular-CYEKBG2K.woff +0 -0
  18. package/dist/KaTeX_AMS-Regular-JKX5W2C4.ttf +0 -0
  19. package/dist/KaTeX_AMS-Regular-U6PRYMIZ.woff2 +0 -0
  20. package/dist/KaTeX_Caligraphic-Bold-5QL5CMTE.woff2 +0 -0
  21. package/dist/KaTeX_Caligraphic-Bold-WZ3QSGD3.woff +0 -0
  22. package/dist/KaTeX_Caligraphic-Bold-ZTS3R3HK.ttf +0 -0
  23. package/dist/KaTeX_Caligraphic-Regular-3LKEU76G.woff +0 -0
  24. package/dist/KaTeX_Caligraphic-Regular-A7XRTZ5Q.ttf +0 -0
  25. package/dist/KaTeX_Caligraphic-Regular-KX5MEWCF.woff2 +0 -0
  26. package/dist/KaTeX_Fraktur-Bold-2QVFK6NQ.woff2 +0 -0
  27. package/dist/KaTeX_Fraktur-Bold-T4SWXBMT.woff +0 -0
  28. package/dist/KaTeX_Fraktur-Bold-WGHVTYOR.ttf +0 -0
  29. package/dist/KaTeX_Fraktur-Regular-2PEIFJSJ.woff2 +0 -0
  30. package/dist/KaTeX_Fraktur-Regular-5U4OPH2X.ttf +0 -0
  31. package/dist/KaTeX_Fraktur-Regular-PQMHCIK6.woff +0 -0
  32. package/dist/KaTeX_Main-Bold-2GA4IZIN.woff +0 -0
  33. package/dist/KaTeX_Main-Bold-W5FBVCZM.ttf +0 -0
  34. package/dist/KaTeX_Main-Bold-YP5VVQRP.woff2 +0 -0
  35. package/dist/KaTeX_Main-BoldItalic-4P4C7HJH.woff +0 -0
  36. package/dist/KaTeX_Main-BoldItalic-N4V3DX7S.woff2 +0 -0
  37. package/dist/KaTeX_Main-BoldItalic-ODMLBJJQ.ttf +0 -0
  38. package/dist/KaTeX_Main-Italic-I43T2HSR.ttf +0 -0
  39. package/dist/KaTeX_Main-Italic-RELBIK7M.woff2 +0 -0
  40. package/dist/KaTeX_Main-Italic-SASNQFN2.woff +0 -0
  41. package/dist/KaTeX_Main-Regular-ARRPAO67.woff2 +0 -0
  42. package/dist/KaTeX_Main-Regular-P5I74A2A.woff +0 -0
  43. package/dist/KaTeX_Main-Regular-W74P5G27.ttf +0 -0
  44. package/dist/KaTeX_Math-BoldItalic-6EBV3DK5.woff +0 -0
  45. package/dist/KaTeX_Math-BoldItalic-K4WTGH3J.woff2 +0 -0
  46. package/dist/KaTeX_Math-BoldItalic-VB447A4D.ttf +0 -0
  47. package/dist/KaTeX_Math-Italic-6KGCHLFN.woff2 +0 -0
  48. package/dist/KaTeX_Math-Italic-KKK3USB2.woff +0 -0
  49. package/dist/KaTeX_Math-Italic-SON4MRCA.ttf +0 -0
  50. package/dist/KaTeX_SansSerif-Bold-RRNVJFFW.woff2 +0 -0
  51. package/dist/KaTeX_SansSerif-Bold-STQ6RXC7.ttf +0 -0
  52. package/dist/KaTeX_SansSerif-Bold-X5M5EMOD.woff +0 -0
  53. package/dist/KaTeX_SansSerif-Italic-HMPFTM52.woff2 +0 -0
  54. package/dist/KaTeX_SansSerif-Italic-PSN4QKYX.woff +0 -0
  55. package/dist/KaTeX_SansSerif-Italic-WTBAZBGY.ttf +0 -0
  56. package/dist/KaTeX_SansSerif-Regular-2TL3USAE.ttf +0 -0
  57. package/dist/KaTeX_SansSerif-Regular-OQCII6EP.woff +0 -0
  58. package/dist/KaTeX_SansSerif-Regular-XIQ62X4E.woff2 +0 -0
  59. package/dist/KaTeX_Script-Regular-72OLXYNA.ttf +0 -0
  60. package/dist/KaTeX_Script-Regular-A5IFOEBS.woff +0 -0
  61. package/dist/KaTeX_Script-Regular-APUWIHLP.woff2 +0 -0
  62. package/dist/KaTeX_Size1-Regular-4HRHTS65.woff +0 -0
  63. package/dist/KaTeX_Size1-Regular-5LRUTBFT.woff2 +0 -0
  64. package/dist/KaTeX_Size1-Regular-7K6AASVL.ttf +0 -0
  65. package/dist/KaTeX_Size2-Regular-222HN3GT.ttf +0 -0
  66. package/dist/KaTeX_Size2-Regular-K5ZHAIS6.woff +0 -0
  67. package/dist/KaTeX_Size2-Regular-LELKET5D.woff2 +0 -0
  68. package/dist/KaTeX_Size3-Regular-TLFPAHDE.woff +0 -0
  69. package/dist/KaTeX_Size3-Regular-UFCO6WCA.ttf +0 -0
  70. package/dist/KaTeX_Size3-Regular-WQRQ47UD.woff2 +0 -0
  71. package/dist/KaTeX_Size4-Regular-7PGNVPQK.ttf +0 -0
  72. package/dist/KaTeX_Size4-Regular-CDMV7U5C.woff2 +0 -0
  73. package/dist/KaTeX_Size4-Regular-PKMWZHNC.woff +0 -0
  74. package/dist/KaTeX_Typewriter-Regular-3F5K6SQ6.ttf +0 -0
  75. package/dist/KaTeX_Typewriter-Regular-MJMFSK64.woff +0 -0
  76. package/dist/KaTeX_Typewriter-Regular-VBYJ4NRC.woff2 +0 -0
  77. package/dist/KernelEngineContext-BOCQoFwk.d.ts +43 -0
  78. package/dist/LayersPanel-BBQ54IVG.js +7 -0
  79. package/dist/ModuleCard-3TT2X7IW.js +7 -0
  80. package/dist/OrbInspector-K6T6O7GI.js +27 -0
  81. package/dist/OrbInspector-MHLJ6OEE.css +1756 -0
  82. package/dist/Select-mDZIwNqN.d.ts +199 -0
  83. package/dist/ServerBridge-Cm1On51b.d.ts +233 -0
  84. package/dist/ThemeContext-DJmO59xd.d.ts +147 -0
  85. package/dist/TraitValueFrame-2PJGLLVI.js +28 -0
  86. package/dist/TraitValueFrame-4G3KOUBR.css +1756 -0
  87. package/dist/UISlotContext-Dl_ewwCI.d.ts +79 -0
  88. package/dist/UISlotRenderer-JKFSX24W.js +27 -0
  89. package/dist/UISlotRenderer-KVFO6J7R.css +1756 -0
  90. package/dist/UserContext-DqWeZkUZ.d.ts +100 -0
  91. package/dist/auth/browser/index.d.ts +2 -0
  92. package/dist/auth/browser/index.js +1 -0
  93. package/dist/auth/react/index.d.ts +49 -0
  94. package/dist/auth/react/index.js +119 -0
  95. package/dist/avl/index.css +1756 -0
  96. package/dist/avl/index.d.ts +2238 -0
  97. package/dist/avl/index.js +2693 -0
  98. package/dist/avl-3d-context-BIRKWpaL.d.ts +204 -0
  99. package/dist/avl-schema-parser-CtJxJ9KU.d.ts +132 -0
  100. package/dist/avl-zoom-state-CKMVuBFg.d.ts +17 -0
  101. package/dist/chunk-2PY54Z44.js +227 -0
  102. package/dist/chunk-2QOH2HWM.js +95 -0
  103. package/dist/chunk-3BBUBJFF.js +339 -0
  104. package/dist/chunk-42FY4RYA.js +191 -0
  105. package/dist/chunk-5QTYQTPS.js +15 -0
  106. package/dist/chunk-6P3MWXYE.js +440 -0
  107. package/dist/chunk-73SRAB4P.js +1053 -0
  108. package/dist/chunk-A2LR6VQQ.js +349 -0
  109. package/dist/chunk-AILY3XPS.js +562 -0
  110. package/dist/chunk-B4BU77LT.js +432 -0
  111. package/dist/chunk-DFNZUYX4.js +378 -0
  112. package/dist/chunk-DJ433ET5.js +1327 -0
  113. package/dist/chunk-DLZF4PVE.js +24 -0
  114. package/dist/chunk-DYEKAA4L.js +787 -0
  115. package/dist/chunk-DZ42OJQC.js +176 -0
  116. package/dist/chunk-EOWMARUB.js +16 -0
  117. package/dist/chunk-EQAMU2ZC.js +14 -0
  118. package/dist/chunk-FAJDTHWC.js +98 -0
  119. package/dist/chunk-FIW6WN23.js +508 -0
  120. package/dist/chunk-FP3WIKTC.js +303 -0
  121. package/dist/chunk-G7DCAZ22.js +19 -0
  122. package/dist/chunk-GAR5TQ5B.js +199 -0
  123. package/dist/chunk-GKIFONTE.js +131 -0
  124. package/dist/chunk-GYTPOFVC.js +47155 -0
  125. package/dist/chunk-KVQS4GXU.js +328 -0
  126. package/dist/chunk-L2DEKY4J.js +97 -0
  127. package/dist/chunk-L677XGY3.js +701 -0
  128. package/dist/chunk-MBQAMMSE.js +11877 -0
  129. package/dist/chunk-P4LNHAFI.js +1051 -0
  130. package/dist/chunk-P4ZFUQFF.js +93 -0
  131. package/dist/chunk-PC7K4SK7.js +1384 -0
  132. package/dist/chunk-R5O5AUPI.js +573 -0
  133. package/dist/chunk-SGM3FASH.js +672 -0
  134. package/dist/chunk-SJGJJKBY.js +502 -0
  135. package/dist/chunk-TESBIVUA.js +11 -0
  136. package/dist/chunk-TZZBINQY.js +82 -0
  137. package/dist/chunk-U6QRZASX.js +280 -0
  138. package/dist/chunk-VFF5OO47.js +319 -0
  139. package/dist/chunk-YDNJLLG6.js +516 -0
  140. package/dist/chunk-YHMRX6YA.js +455 -0
  141. package/dist/chunk-ZO6MXAS3.js +69 -0
  142. package/dist/components/index.css +1756 -0
  143. package/dist/components/index.d.ts +11093 -0
  144. package/dist/components/index.js +1110 -0
  145. package/dist/context/index.d.ts +9 -0
  146. package/dist/context/index.js +7 -0
  147. package/dist/core.d.ts +2523 -0
  148. package/dist/core.js +2 -0
  149. package/dist/design-classes/index.cjs +429 -0
  150. package/dist/design-classes/index.d.cts +165 -0
  151. package/dist/design-classes/index.d.ts +165 -0
  152. package/dist/design-classes/index.js +397 -0
  153. package/dist/emojiItems-QGSNAABW.js +20 -0
  154. package/dist/fx-CmQjnHmT.d.ts +371 -0
  155. package/dist/hooks/index.d.ts +936 -0
  156. package/dist/hooks/index.js +7 -0
  157. package/dist/index.d.ts +486 -0
  158. package/dist/index.js +38 -0
  159. package/dist/katexPlugin-FA7NX4PE.css +1161 -0
  160. package/dist/katexPlugin-NCDKOOQY.js +2 -0
  161. package/dist/kernel-client-ZH4PSMCN.js +367 -0
  162. package/dist/kernel-wire-B4S8pnP3.d.ts +65 -0
  163. package/dist/lib/index.d.ts +602 -0
  164. package/dist/lib/index.js +1288 -0
  165. package/dist/paintDispatch-ChW5mVuK.d.ts +698 -0
  166. package/dist/parseLessonSegments-GpCeMrb2.d.ts +334 -0
  167. package/dist/perf-CKiBKbkw.d.ts +22 -0
  168. package/dist/perf-Dr28-AgT.d.ts +57 -0
  169. package/dist/prism-AIWGN2X5.js +134 -0
  170. package/dist/providers/index.css +1756 -0
  171. package/dist/providers/index.d.ts +340 -0
  172. package/dist/providers/index.js +30 -0
  173. package/dist/renderer/index.d.ts +467 -0
  174. package/dist/renderer/index.js +3 -0
  175. package/dist/runtime/index.css +1756 -0
  176. package/dist/runtime/index.d.ts +440 -0
  177. package/dist/runtime/index.js +31 -0
  178. package/dist/slot-host-CPzrxLo9.d.ts +48 -0
  179. package/dist/ssr/index.cjs +7631 -0
  180. package/dist/ssr/index.d.cts +487 -0
  181. package/dist/ssr/index.d.ts +487 -0
  182. package/dist/ssr/index.js +7599 -0
  183. package/dist/storage/browser/index.d.ts +1 -0
  184. package/dist/storage/browser/index.js +1 -0
  185. package/dist/test-support.d.ts +35 -0
  186. package/dist/test-support.js +114 -0
  187. package/dist/themeTokens-CRd8AEDF.d.ts +125 -0
  188. package/dist/three/index.css +503 -0
  189. package/dist/three/index.d.ts +1185 -0
  190. package/dist/three/index.js +3896 -0
  191. package/dist/useKeyboardRouter-Dsq553Ur.d.ts +42 -0
  192. package/dist/useUISlots-CiobNFGb.d.ts +211 -0
  193. package/dist/verification-C5pTeMJv.d.ts +66 -0
  194. package/dist/verificationRegistry-CabxhfTv.d.ts +122 -0
  195. package/dist/wrapCallbackForEvent-B9QLbhxX.d.ts +19 -0
  196. package/index.css +199 -0
  197. package/package.json +269 -3
  198. package/src/core/locales/ar.json +1263 -0
  199. package/src/core/locales/en.json +1263 -0
  200. package/src/core/locales/index.ts +54 -0
  201. package/src/core/locales/sl.json +1263 -0
  202. package/src/core/tokens/native-tokens.json +369 -0
  203. package/tailwind-compile.cjs +29 -0
  204. package/tailwind-preset.cjs +991 -0
  205. package/themes/_base.css +451 -0
  206. package/themes/_contract.md +307 -0
  207. package/themes/_fonts-kenney.css +11 -0
  208. package/themes/_fonts.css +12 -0
  209. package/themes/_foundation.css +105 -0
  210. package/themes/_head.css +22 -0
  211. package/themes/_presets.css +67 -0
  212. package/themes/almadar-heritage.css +455 -0
  213. package/themes/almadar-website.css +269 -0
  214. package/themes/almadar.css +269 -0
  215. package/themes/aqua.css +455 -0
  216. package/themes/arabesque.css +459 -0
  217. package/themes/art-deco.css +457 -0
  218. package/themes/art-nouveau.css +459 -0
  219. package/themes/atelier.css +463 -0
  220. package/themes/bauhaus.css +461 -0
  221. package/themes/bloomberg-dense.css +463 -0
  222. package/themes/blueprint.css +457 -0
  223. package/themes/clay.css +449 -0
  224. package/themes/comic.css +453 -0
  225. package/themes/constructivist.css +457 -0
  226. package/themes/corporate.css +449 -0
  227. package/themes/cyberpunk.css +453 -0
  228. package/themes/frutiger-aero.css +458 -0
  229. package/themes/game-adventure.css +201 -0
  230. package/themes/game-rpg.css +203 -0
  231. package/themes/game-sci-fi.css +201 -0
  232. package/themes/game-ui-pack.css +200 -0
  233. package/themes/gazette.css +449 -0
  234. package/themes/glass.css +457 -0
  235. package/themes/gothic.css +453 -0
  236. package/themes/index.css +21 -0
  237. package/themes/ink-wash.css +459 -0
  238. package/themes/kawaii.css +459 -0
  239. package/themes/kflow.css +310 -0
  240. package/themes/kiosk.css +449 -0
  241. package/themes/linear-clean.css +463 -0
  242. package/themes/luxury.css +451 -0
  243. package/themes/mac-classic.css +455 -0
  244. package/themes/material.css +463 -0
  245. package/themes/memphis.css +453 -0
  246. package/themes/mid-century.css +455 -0
  247. package/themes/minimalist.css +449 -0
  248. package/themes/mudcloth.css +459 -0
  249. package/themes/nata.css +310 -0
  250. package/themes/neon.css +453 -0
  251. package/themes/neumorphic.css +451 -0
  252. package/themes/newsprint.css +455 -0
  253. package/themes/notion-editorial.css +463 -0
  254. package/themes/orb.css +465 -0
  255. package/themes/pixel.css +449 -0
  256. package/themes/prism.css +309 -0
  257. package/themes/rawi.css +310 -0
  258. package/themes/retro.css +452 -0
  259. package/themes/risograph.css +463 -0
  260. package/themes/scandi.css +469 -0
  261. package/themes/sketch.css +455 -0
  262. package/themes/solarpunk.css +469 -0
  263. package/themes/steampunk.css +451 -0
  264. package/themes/swiss.css +455 -0
  265. package/themes/terminal.css +466 -0
  266. package/themes/trait-wars.css +487 -0
  267. package/themes/ukiyo-e.css +459 -0
  268. package/themes/vaporwave.css +455 -0
  269. package/themes/victorian.css +453 -0
  270. package/themes/wabi-sabi.css +459 -0
  271. package/themes/win95.css +455 -0
  272. package/themes/wireframe.css +439 -0
  273. package/themes/zine.css +455 -0
  274. package/README.md +0 -3
@@ -0,0 +1,991 @@
1
+ /**
2
+ * @almadar/ui Tailwind Preset
3
+ *
4
+ * Provides the complete Almadar design token system as a Tailwind preset.
5
+ * Includes a safelist for CSS-variable-based arbitrary classes that use
6
+ * bracket notation (Tailwind can't extract these from source scanning).
7
+ *
8
+ * Note: @almadar/ui dist content scanning is handled by tailwind.config.js
9
+ * in the shell template, not here. The config resolves the dist path via
10
+ * require.resolve('./src/components') which works regardless of hoisting.
11
+ *
12
+ * Usage in tailwind.config.js:
13
+ * presets: [require('@almadar/shell-web/tailwind-preset')]
14
+ */
15
+
16
+ // The one definition of the container breakpoints and the modal min widths; the native shells read the same file.
17
+ const nativeTokens = require('./src/core/tokens/native-tokens.json');
18
+
19
+ // Tailwind can only apply an opacity modifier (`bg-primary/50`) to a color it
20
+ // can compute alpha for itself — a bare `var(--color-x)` string is opaque to
21
+ // it, so every semantic token below must resolve through this function or its
22
+ // `/NN` utilities silently generate no CSS rule at all (not even with the
23
+ // class safelisted — confirmed via a standalone `tailwindcss` CLI build).
24
+ function withOpacity(varName) {
25
+ return ({ opacityValue }) =>
26
+ opacityValue === undefined
27
+ ? `var(${varName})`
28
+ : `color-mix(in srgb, var(${varName}) calc(${opacityValue} * 100%), transparent)`;
29
+ }
30
+
31
+ // The class vocabulary visual editors write onto `className` (@almadar/core
32
+ // `design-classes`, in this package). Safelisted whole so any class an editor picks compiles.
33
+ const { allDesignClasses } = require('./dist/design-classes/index.cjs');
34
+
35
+ /** @type {import('tailwindcss').Config} */
36
+ module.exports = {
37
+ darkMode: 'class',
38
+ safelist: [
39
+ 'proof-marquee', 'proof-marquee-track', 'animate-almadar-marquee',
40
+ 'hover:[animation-play-state:paused]', 'motion-reduce:animate-none', 'motion-reduce:w-auto',
41
+ 'motion-reduce:flex-wrap', 'motion-reduce:justify-center', 'motion-reduce:hidden', 'motion-reduce:[mask-image:none]',
42
+ ...allDesignClasses(),
43
+ // Standard utilities used via dynamic className from .orb schemas
44
+ 'contents',
45
+ 'p-4', 'p-6', 'p-8',
46
+ 'px-4', 'px-6', 'py-4', 'py-6',
47
+ 'mx-auto',
48
+ 'w-full',
49
+ 'max-w-sm', 'max-w-md', 'max-w-lg', 'max-w-xl', 'max-w-2xl', 'max-w-3xl', 'max-w-4xl', 'max-w-5xl', 'max-w-6xl', 'max-w-7xl',
50
+ 'min-h-screen',
51
+ 'gap-1', 'gap-2', 'gap-3', 'gap-4', 'gap-6', 'gap-8',
52
+ 'grid-cols-1', 'grid-cols-2', 'grid-cols-3', 'grid-cols-4',
53
+ 'sm:grid-cols-2', 'md:grid-cols-2', 'md:grid-cols-3', 'lg:grid-cols-3', 'lg:grid-cols-4',
54
+ 'text-center', 'text-left', 'text-right',
55
+ // Split composes its stacking classes as `${containerBreakpoint}${cls}` at runtime
56
+ ...['@sm:', '@md:', '@lg:', '@xl:'].flatMap((bp) => [
57
+ 'w-1/2', 'w-1/3', 'w-2/3', 'w-1/4', 'w-3/4', 'w-1/5', 'w-4/5', 'w-2/5', 'w-3/5', 'flex-row', 'flex-row-reverse',
58
+ ].map((cls) => `${bp}${cls}`)),
59
+ // Container-query layout a .lolo body composes (a behavior sized by the room it is given)
60
+ ...['@sm:', '@md:'].flatMap((bp) => ['block', 'hidden', 'flex', 'flex-row', 'w-16', 'basis-auto', 'text-base', 'text-xl', 'text-2xl', 'text-3xl'].map((cls) => `${bp}${cls}`)),
61
+ // Flex shares a .lolo composes from knobs (e.g. a split whose hovered panel grows)
62
+ ...['', '@sm:', '@md:', '@lg:', '@xl:'].flatMap((bp) => ['', 'hover:', 'focus-within:'].flatMap((state) =>
63
+ ['w-auto', 'basis-0', 'grow', 'grow-0', ...[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12].map((n) => `grow-[${n}]`)]
64
+ .map((cls) => `${bp}${state}${cls}`))),
65
+ 'basis-full', 'min-w-0', 'transition-[flex-grow]', 'duration-500', 'ease-out', 'motion-reduce:transition-none',
66
+ // Non-theme CSS variable classes (no semantic equivalent in theme config)
67
+ 'active:scale-[var(--active-scale)]',
68
+ 'border-b-[length:var(--border-width)]',
69
+ 'border-[length:var(--border-width)]',
70
+ 'border-[length:var(--border-width-thin)]',
71
+ 'border-l-[length:var(--border-width)]',
72
+ 'border-r-[length:var(--border-width)]',
73
+ 'border-t-[length:var(--border-width)]',
74
+ 'border-x-[length:var(--border-width)]',
75
+ 'duration-[var(--transition-fast)]',
76
+ 'duration-[var(--transition-normal)]',
77
+ 'focus:ring-[length:var(--focus-ring-width)]',
78
+ 'focus:ring-offset-[length:var(--focus-ring-offset)]',
79
+ 'text-[var(--icon-color,currentColor)]',
80
+ 'placeholder:text-[var(--color-placeholder)]',
81
+ // Table-specific tokens
82
+ 'bg-[var(--color-table-header)]',
83
+ 'border-[var(--color-table-border)]',
84
+ 'hover:bg-[var(--color-table-row-hover)]',
85
+ 'hover:bg-[var(--color-surface-hover)]',
86
+ 'hover:border-[var(--color-border-hover)]',
87
+ 'hover:border-l-[var(--color-muted)]',
88
+ // Gradient partials with opacity
89
+ // Opacity variants on semantic colors (used in components)
90
+ 'bg-primary/10', 'bg-accent/10',
91
+ 'bg-muted/20', 'bg-muted/30', 'bg-muted/50', 'bg-muted/60',
92
+ 'bg-surface/60', 'bg-surface/80',
93
+ 'bg-background/10', 'bg-background/80',
94
+ 'bg-card/80', 'bg-foreground/0', 'bg-foreground/50',
95
+ 'bg-error/10', 'bg-info/10', 'bg-success/10', 'bg-warning/10',
96
+ 'border-accent/30', 'border-border/40',
97
+ 'border-error/30', 'border-error/50',
98
+ 'border-info/30', 'border-success/30', 'border-warning/30',
99
+ 'ring-accent/20', 'ring-error/20', 'ring-info/20',
100
+ 'ring-muted-foreground/20', 'ring-primary/30',
101
+ 'ring-success/20', 'ring-warning/20',
102
+ 'text-foreground/30', 'text-foreground/60',
103
+ 'text-muted-foreground/50',
104
+ 'hover:bg-error/10', 'hover:bg-muted/50', 'hover:bg-muted/80',
105
+ 'hover:bg-muted-foreground/15', 'hover:bg-primary/10',
106
+ 'dark:bg-foreground/70', 'dark:hover:bg-error/20',
107
+ 'group-hover:bg-foreground/20', 'group-hover:text-primary',
108
+ 'peer-focus:ring-error/20', 'peer-focus:ring-ring/20',
109
+ // Hover elevation & micro-interactions
110
+ 'hover:-translate-y-0.5',
111
+ 'hover:-translate-y-1',
112
+ 'hover:scale-105',
113
+ 'scale-[1.05]',
114
+ 'transition-all',
115
+ 'duration-200',
116
+ 'ring-2',
117
+ 'ring-primary',
118
+
119
+ // Motion utilities (applied conditionally on open/close state)
120
+ 'animate-modal-in',
121
+ 'animate-modal-out',
122
+ 'animate-overlay-in',
123
+ 'animate-overlay-out',
124
+ 'animate-slide-up',
125
+ 'animate-drawer-in',
126
+ 'animate-drawer-out',
127
+ 'animate-popover-in',
128
+ 'animate-popover-out',
129
+ 'animate-toast-in',
130
+ 'animate-toast-out',
131
+ 'animate-fade-in',
132
+ 'animate-fade-out',
133
+ 'animate-page-in',
134
+ 'animate-page-out',
135
+ 'animate-shimmer',
136
+
137
+ // Auto-added by audit-tailwind-safelist.ts (2026-03-28)
138
+ 'active:scale-[var(--active-scale)]',
139
+ 'animate-[combat-flash_0.2s_ease-in-out_2]',
140
+ 'animate-[combat-heal-glow_0.8s_ease-in-out]',
141
+ 'animate-[combat-pulse-red_0.5s_ease-in-out]',
142
+ 'animate-[combat-shake_0.3s_ease-in-out]',
143
+ 'animate-[shake_0.3s_ease-in-out]',
144
+ 'aspect-[3/4]',
145
+ 'bg-[radial-gradient(circle_at_center,rgba(34,197,94,0.2),transparent_70%)]',
146
+ 'bg-[radial-gradient(ellipse_at_top,var(--color-primary)/0.08,transparent_60%),radial-gradient(ellipse_at_bottom_right,var(--color-accent)/0.06,transparent_50%)]',
147
+ 'bg-[var(--color-background)]',
148
+ 'bg-[var(--color-card)]',
149
+ 'bg-[var(--color-table-header)]',
150
+ 'bg-accent/10',
151
+ 'bg-accent/20',
152
+ 'bg-background/80',
153
+ 'bg-card/80',
154
+ 'bg-error/10',
155
+ 'bg-foreground/0',
156
+ 'bg-foreground/50',
157
+ 'bg-info/10',
158
+ 'bg-muted/20',
159
+ 'bg-muted/30',
160
+ 'bg-muted/50',
161
+ 'bg-muted/60',
162
+ 'bg-primary/10',
163
+ 'bg-primary/20',
164
+ 'bg-success/10',
165
+ 'bg-success/20',
166
+ 'bg-surface/60',
167
+ 'bg-surface/80',
168
+ 'bg-warning/10',
169
+ 'border-[length:2px]',
170
+ 'border-[length:var(--border-width-thin)]',
171
+ 'border-[length:var(--border-width)]',
172
+ 'border-[var(--color-border)]',
173
+ 'border-[var(--color-table-border)]',
174
+ 'border-accent/30',
175
+ 'border-b-[length:var(--border-width)]',
176
+ 'border-border/40',
177
+ 'border-error/30',
178
+ 'border-error/50',
179
+ 'border-info/30',
180
+ 'border-l-[3px]',
181
+ 'border-l-[length:var(--border-width)]',
182
+ 'border-primary/30',
183
+ 'border-r-[length:var(--border-width)]',
184
+ 'border-success/30',
185
+ 'border-t-[length:var(--border-width)]',
186
+ 'border-warning/30',
187
+ 'border-x-[length:var(--border-width)]',
188
+ 'dark:bg-foreground/70',
189
+ 'dark:hover:bg-error/20',
190
+ 'duration-[var(--transition-fast)]',
191
+ 'duration-[var(--transition-normal)]',
192
+ 'focus:ring-[length:var(--focus-ring-width)]',
193
+ 'focus:ring-offset-[length:var(--focus-ring-offset)]',
194
+ 'from-[var(--color-primary)]',
195
+ 'group-hover:bg-foreground/20',
196
+ 'h-[18px]',
197
+ 'h-[1em]',
198
+ 'h-[80px]',
199
+ 'hover:bg-[var(--color-card)]',
200
+ 'hover:bg-[var(--color-surface-hover)]',
201
+ 'hover:bg-[var(--color-table-row-hover)]',
202
+ 'hover:bg-error/10',
203
+ 'hover:bg-error/80',
204
+ 'hover:bg-muted/50',
205
+ 'hover:bg-muted/80',
206
+ 'hover:bg-primary/10',
207
+ 'hover:border-[var(--color-border-hover)]',
208
+ 'hover:border-l-[var(--color-muted)]',
209
+ 'left-[-5px]',
210
+ 'lg:max-w-[50%]',
211
+ 'lg:min-w-[45%]',
212
+ 'max-h-[1000px]',
213
+ 'max-h-[280px]',
214
+ 'max-h-[500px]',
215
+ 'max-h-[80vh]',
216
+ 'max-w-[120px]',
217
+ 'max-w-[160px]',
218
+ 'max-w-[180px]',
219
+ 'max-w-[200px]',
220
+ 'max-w-[280px]',
221
+ 'max-w-[300px]',
222
+ 'max-w-[400px]',
223
+ 'max-w-[60%]',
224
+ 'max-w-[75%]',
225
+ 'max-w-[80%]',
226
+ 'min-h-[200px]',
227
+ 'min-h-[240px]',
228
+ 'min-h-[24px]',
229
+ 'min-h-[2rem]',
230
+ 'min-h-[400px]',
231
+ 'min-h-[44px]',
232
+ 'min-h-[4px]',
233
+ 'min-h-[600px]',
234
+ 'min-h-[60px]',
235
+ 'min-h-[60vh]',
236
+ 'min-h-[80px]',
237
+ 'min-h-[80vh]',
238
+ 'min-h-[85vh]',
239
+ 'min-w-[100px]',
240
+ 'min-w-[120px]',
241
+ 'min-w-[130px]',
242
+ 'min-w-[140px]',
243
+ 'min-w-[160px]',
244
+ 'min-w-[18px]',
245
+ 'min-w-[2.5rem]',
246
+ 'min-w-[200px]',
247
+ 'min-w-[20px]',
248
+ 'min-w-[2rem]',
249
+ 'min-w-[300px]',
250
+ 'min-w-[3ch]',
251
+ 'min-w-[3rem]',
252
+ 'min-w-[40px]',
253
+ 'min-w-[44px]',
254
+ 'min-w-[60px]',
255
+ 'min-w-[65px]',
256
+ 'min-w-[800px]',
257
+ 'min-w-[80px]',
258
+ 'ml-[1px]',
259
+ 'ml-[calc(1.5rem)]',
260
+ 'peer-focus:ring-error/20',
261
+ 'peer-focus:ring-ring/20',
262
+ 'placeholder:text-[var(--color-placeholder)]',
263
+ 'ring-accent/20',
264
+ 'ring-accent/50',
265
+ 'ring-error/20',
266
+ 'ring-info/20',
267
+ 'ring-muted-foreground/20',
268
+ 'ring-primary/30',
269
+ 'ring-success/20',
270
+ 'ring-warning/20',
271
+ 'rounded-[var(--radius-md)]',
272
+ 'scale-[1.05]',
273
+ 'shadow-[0_-4px_6px_-1px_rgb(0,0,0,0.05)]',
274
+ 'shadow-[0_0_10px_rgba(251,191,36,0.5)]',
275
+ 'shadow-[0_0_6px_rgba(59,130,246,0.3)]',
276
+ 'shadow-[0_0_8px_rgba(168,85,247,0.4)]',
277
+ 'text-[0.65rem]',
278
+ 'text-[9px]',
279
+ 'text-[var(--color-foreground)]',
280
+ 'text-[var(--color-muted-foreground)]',
281
+ 'text-[var(--icon-color,currentColor)]',
282
+ 'text-foreground/30',
283
+ 'text-foreground/60',
284
+ 'text-foreground/70',
285
+ 'text-foreground/80',
286
+ 'text-muted-foreground/50',
287
+ 'to-[var(--color-secondary)]',
288
+ 'w-[280px]',
289
+ 'w-[2px]',
290
+ 'w-[480px]',
291
+ 'w-[640px]',
292
+ 'will-change-[opacity,transform]',
293
+ 'z-[1000]',
294
+ 'z-[1001]',
295
+ 'z-[60]',
296
+
297
+ // Auto-added by audit-tailwind-safelist.ts (2026-09-19)
298
+ 'bg-[var(--color-border)]',
299
+ 'bg-[var(--color-muted)]',
300
+ 'bg-[var(--color-primary)]',
301
+ 'bg-[var(--color-surface-subtle)]',
302
+ 'bg-[var(--color-surface)]',
303
+ 'bg-[var(--color-warning)]',
304
+ 'bg-accent/15',
305
+ 'bg-background/60',
306
+ 'bg-background/95',
307
+ 'bg-card/40',
308
+ 'bg-card/50',
309
+ 'bg-card/90',
310
+ 'bg-card/95',
311
+ 'bg-error/15',
312
+ 'bg-error/70',
313
+ 'bg-error/80',
314
+ 'bg-foreground/40',
315
+ 'bg-muted-foreground/50',
316
+ 'bg-muted/10',
317
+ 'bg-muted/40',
318
+ 'bg-primary/15',
319
+ 'bg-primary/80',
320
+ 'bg-secondary/10',
321
+ 'bg-success/15',
322
+ 'bg-success/80',
323
+ 'bg-warning/15',
324
+ 'bg-warning/80',
325
+ 'border-[length:var(--border-width-thick)]',
326
+ 'border-[var(--color-primary)]',
327
+ 'border-[var(--color-warning)]',
328
+ 'border-border/10',
329
+ 'border-border/20',
330
+ 'border-border/50',
331
+ 'border-error/40',
332
+ 'border-error/70',
333
+ 'border-info/70',
334
+ 'border-l-[length:var(--border-width-thin)]',
335
+ 'border-primary/20',
336
+ 'border-primary/40',
337
+ 'border-success/40',
338
+ 'border-success/50',
339
+ 'border-success/70',
340
+ 'border-warning/40',
341
+ 'border-warning/60',
342
+ 'border-y-[length:var(--border-width)]',
343
+ 'bottom-[15%]',
344
+ 'focus-visible:ring-[length:var(--focus-ring-width)]',
345
+ 'focus-visible:ring-offset-[length:var(--focus-ring-offset)]',
346
+ 'focus-within:border-[var(--color-primary)]',
347
+ 'from-primary/90',
348
+ 'group-hover:bg-[var(--color-surface-subtle)]',
349
+ 'h-[1.25rem]',
350
+ 'h-[1.5rem]',
351
+ 'hover:bg-[var(--color-card-hover,transparent)]',
352
+ 'hover:bg-[var(--color-muted)]',
353
+ 'hover:bg-[var(--color-surface-subtle)]',
354
+ 'hover:bg-[var(--color-surface)]',
355
+ 'hover:bg-foreground/10',
356
+ 'hover:bg-muted-foreground/70',
357
+ 'hover:bg-muted/30',
358
+ 'hover:bg-muted/40',
359
+ 'hover:bg-primary-foreground/15',
360
+ 'hover:bg-primary-foreground/20',
361
+ 'hover:text-[var(--color-foreground)]',
362
+ 'hover:text-info/80',
363
+ 'hover:translate-y-[var(--hover-translate-y)]',
364
+ 'left-[15%]',
365
+ 'max-h-[36rem]',
366
+ 'max-h-[60vh]',
367
+ 'max-w-[calc(100vw-1.5rem)]',
368
+ 'max-w-[calc(100vw-1rem)]',
369
+ 'max-w-[calc(100vw-2rem)]',
370
+ 'md:grid-cols-[var(--master-detail-cols)]',
371
+ 'md:max-w-[50%]',
372
+ 'md:min-w-[160px]',
373
+ 'md:min-w-[45%]',
374
+ 'min-h-[16rem]',
375
+ 'min-h-[3rem]',
376
+ 'min-h-[8rem]',
377
+ 'min-w-[10rem]',
378
+ 'min-w-[16rem]',
379
+ 'min-w-[2px]',
380
+ 'min-w-[400px]',
381
+ 'min-w-[520px]',
382
+ 'min-w-[600px]',
383
+ 'min-w-[700px]',
384
+ 'min-w-[8rem]',
385
+ 'pt-[10vh]',
386
+ 'py-[1px]',
387
+ 'right-[15%]',
388
+ 'ring-primary/40',
389
+ 'scale-[var(--hover-scale)]',
390
+ 'sm:min-w-[200px]',
391
+ 'sm:min-w-[300px]',
392
+ 'sm:w-[28rem]',
393
+ 'sm:w-[340px]',
394
+ 'sm:w-[480px]',
395
+ 'sm:w-[640px]',
396
+ 'text-[10px]',
397
+ 'text-[11px]',
398
+ 'text-[var(--color-danger)]',
399
+ 'text-[var(--color-primary)]',
400
+ 'text-[var(--color-success)]',
401
+ 'text-[var(--color-warning-foreground)]',
402
+ 'text-[var(--color-warning)]',
403
+ 'text-foreground/50',
404
+ 'top-[15%]',
405
+ 'translate-x-[1.25rem]',
406
+ 'w-[1.25rem]',
407
+ 'w-[2.75rem]',
408
+ 'w-[400px]',
409
+ 'z-[1]',
410
+ 'z-[45]',
411
+
412
+ // Auto-added by audit-tailwind-safelist.ts (2026-09-24)
413
+ 'border-border/60',
414
+ 'hover:bg-accent/40',
415
+ 'w-[243px]',
416
+
417
+ // Auto-added by audit-tailwind-safelist.ts (2026-09-25)
418
+ 'aspect-[21/9]',
419
+ 'aspect-[3/2]',
420
+ 'aspect-[4/3]',
421
+ 'max-w-[55%]',
422
+
423
+ // Auto-added by audit-tailwind-safelist.ts (2026-09-26)
424
+ 'max-w-[12rem]',
425
+
426
+ // Auto-added by audit-tailwind-safelist.ts (2026-09-27)
427
+ 'bg-error/5',
428
+ 'bg-success/5',
429
+ 'border-error/20',
430
+ 'border-success/20',
431
+
432
+ // Auto-added by audit-tailwind-safelist.ts (2026-09-30)
433
+ 'bg-error/30',
434
+ 'bg-info/80',
435
+ 'bg-primary-foreground/20',
436
+ 'bg-primary-foreground/5',
437
+ 'bg-primary/25',
438
+ 'bg-secondary/80',
439
+ 'border-e-[length:var(--border-width)]',
440
+ 'border-s-[length:var(--border-width)]',
441
+ 'grid-cols-[repeat(auto-fit,minmax(min(10rem,100%),1fr))]',
442
+ 'max-h-[80%]',
443
+ 'max-w-[1440px]',
444
+ 'max-w-[16rem]',
445
+ 'min-w-[min(theme(minWidth.modal-sm),100%)]',
446
+ 'min-w-[min(theme(minWidth.modal-md),100%)]',
447
+ 'min-w-[min(theme(minWidth.modal-lg),100%)]',
448
+ 'min-w-[min(theme(minWidth.modal-xl),100%)]',
449
+ 'pb-[calc(5rem+env(safe-area-inset-bottom))]',
450
+ 'pb-[env(safe-area-inset-bottom)]',
451
+ 'pt-[10%]',
452
+ 'pt-[env(safe-area-inset-top)]',
453
+ 'rounded-[calc(var(--radius-xl)*1.5)]',
454
+ 'text-primary-foreground/80',
455
+
456
+ // Auto-added by audit-tailwind-safelist.ts (2026-10-01)
457
+ 'max-w-[18rem]',
458
+
459
+ // Auto-added by audit-tailwind-safelist.ts (2026-10-01)
460
+ 'lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]',
461
+
462
+ // Auto-added by audit-tailwind-safelist.ts (2026-10-02)
463
+ 'bg-primary/5',
464
+ 'from-[var(--color-background)]',
465
+ 'max-w-[90%]',
466
+ 'rounded-[inherit]',
467
+ 'rounded-[var(--radius-lg)]',
468
+ 'shadow-[var(--shadow-lg)]',
469
+ 'text-[var(--color-primary-foreground)]',
470
+ 'z-[850]',
471
+
472
+ // Auto-added by audit-tailwind-safelist.ts (2026-10-03)
473
+ '[justify-content:inherit]',
474
+ 'bg-primary/[0.08]',
475
+
476
+ // Auto-added by audit-tailwind-safelist.ts (2026-10-04)
477
+ 'bg-[var(--surface-diagram)]',
478
+
479
+ // Auto-added by audit-tailwind-safelist.ts (2026-10-05)
480
+ 'hover:bg-accent/15',
481
+
482
+ // Auto-added by audit-tailwind-safelist.ts (2026-10-21)
483
+ "after:content-['']",
484
+ 'after:rounded-[inherit]',
485
+ 'grow-[1.6]',
486
+ ],
487
+ theme: {
488
+ fontFamily: {
489
+ // `sans` continues to read --font-family for backward compat.
490
+ sans: ['var(--font-family)', 'ui-sans-serif', 'system-ui', 'sans-serif'],
491
+ mono: ['var(--font-family-mono, ui-monospace)', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'monospace'],
492
+ // Layer 1 Type axis: display + body family slots fall back to --font-family
493
+ // so existing themes that don't define them keep their current look.
494
+ display: ['var(--font-family-display, var(--font-family))', 'ui-sans-serif', 'system-ui', 'sans-serif'],
495
+ body: ['var(--font-family-body, var(--font-family))', 'ui-sans-serif', 'system-ui', 'sans-serif'],
496
+ },
497
+ extend: {
498
+ // MarkdownContent draws its own inline-code chip; drop the plugin's literal backticks
499
+ typography: {
500
+ DEFAULT: {
501
+ css: {
502
+ 'code::before': { content: 'none' },
503
+ 'code::after': { content: 'none' },
504
+ },
505
+ },
506
+ },
507
+ colors: {
508
+ primary: {
509
+ DEFAULT: withOpacity('--color-primary'),
510
+ foreground: withOpacity('--color-primary-foreground'),
511
+ hover: withOpacity('--color-primary-hover'),
512
+ },
513
+ secondary: {
514
+ DEFAULT: withOpacity('--color-secondary'),
515
+ foreground: withOpacity('--color-secondary-foreground'),
516
+ hover: withOpacity('--color-secondary-hover'),
517
+ },
518
+ muted: {
519
+ DEFAULT: withOpacity('--color-muted'),
520
+ foreground: withOpacity('--color-muted-foreground'),
521
+ },
522
+ accent: {
523
+ DEFAULT: withOpacity('--color-accent'),
524
+ foreground: withOpacity('--color-accent-foreground'),
525
+ },
526
+ background: withOpacity('--color-background'),
527
+ foreground: withOpacity('--color-foreground'),
528
+ card: {
529
+ DEFAULT: withOpacity('--color-card'),
530
+ foreground: withOpacity('--color-card-foreground'),
531
+ },
532
+ surface: withOpacity('--color-surface'),
533
+ // Backdrop dimming behind modals/drawers; themes set --color-scrim.
534
+ scrim: 'var(--color-scrim, rgba(0, 0, 0, 0.6))',
535
+ border: withOpacity('--color-border'),
536
+ input: withOpacity('--color-input'),
537
+ ring: withOpacity('--color-ring'),
538
+ error: {
539
+ DEFAULT: withOpacity('--color-error'),
540
+ foreground: withOpacity('--color-error-foreground'),
541
+ },
542
+ success: {
543
+ DEFAULT: withOpacity('--color-success'),
544
+ foreground: withOpacity('--color-success-foreground'),
545
+ },
546
+ warning: {
547
+ DEFAULT: withOpacity('--color-warning'),
548
+ foreground: withOpacity('--color-warning-foreground'),
549
+ },
550
+ info: {
551
+ DEFAULT: withOpacity('--color-info'),
552
+ foreground: withOpacity('--color-info-foreground'),
553
+ },
554
+ },
555
+ borderRadius: {
556
+ none: 'var(--radius-none, 0)',
557
+ sm: 'var(--radius-sm)',
558
+ md: 'var(--radius-md)',
559
+ lg: 'var(--radius-lg)',
560
+ xl: 'var(--radius-xl)',
561
+ full: 'var(--radius-full)',
562
+ // Geometry-axis intent overlay. Codemod targets these for `rounded-*` by component intent:
563
+ // Card / containers → rounded-container
564
+ // Button / interactive → rounded-interactive
565
+ // Avatar / Badge → rounded-pill
566
+ container: 'var(--radius-container, var(--radius-md))',
567
+ interactive: 'var(--radius-interactive, var(--radius-md))',
568
+ pill: 'var(--radius-pill, var(--radius-full))',
569
+ },
570
+ borderWidth: {
571
+ // Geometry-axis border rhythm with intent. Existing literal `border` / `border-2` keep working.
572
+ hairline: 'var(--border-hairline, 1px)',
573
+ standard: 'var(--border-standard, var(--border-width, 1px))',
574
+ heavy: 'var(--border-heavy, var(--border-width-thick, 2px))',
575
+ },
576
+ boxShadow: {
577
+ sm: 'var(--shadow-sm)',
578
+ DEFAULT: 'var(--shadow-main)',
579
+ lg: 'var(--shadow-lg)',
580
+ inner: 'var(--shadow-inner)',
581
+ // Elevation-axis per-layer intent. Codemod targets:
582
+ // Card → shadow-elevation-card
583
+ // Popover / Tooltip → shadow-elevation-popover
584
+ // Dialog → shadow-elevation-dialog
585
+ // Toast → shadow-elevation-toast
586
+ 'elevation-card': 'var(--elevation-card, var(--shadow-sm))',
587
+ 'elevation-popover': 'var(--elevation-popover, var(--shadow-main))',
588
+ 'elevation-dialog': 'var(--elevation-dialog, var(--shadow-lg))',
589
+ 'elevation-toast': 'var(--elevation-toast, var(--shadow-main))',
590
+ // Button resting / pressed → shadow-elevation-interactive / shadow-elevation-pressed
591
+ 'elevation-interactive': 'var(--elevation-interactive, var(--shadow-sm))',
592
+ 'elevation-pressed': 'var(--elevation-pressed, var(--shadow-sm))',
593
+ },
594
+ fontWeight: {
595
+ normal: 'var(--font-weight-normal, 400)',
596
+ medium: 'var(--font-weight-medium, 500)',
597
+ bold: 'var(--font-weight-bold, 600)',
598
+ },
599
+ transitionDuration: {
600
+ // DEFAULT drives every bare `transition-*` utility (transition-all /
601
+ // transition-colors / ...) so its duration is theme-token-driven too —
602
+ // not Tailwind's hardcoded 150ms. Existing aliases resolve through the
603
+ // Motion-axis tokens with the legacy `--transition-*` as fallback.
604
+ DEFAULT: 'var(--duration-fast, var(--transition-fast, 150ms))',
605
+ fast: 'var(--duration-fast, var(--transition-fast, 150ms))',
606
+ normal: 'var(--duration-normal, var(--transition-normal, 250ms))',
607
+ slow: 'var(--duration-slow, var(--transition-slow, 400ms))',
608
+ instant: 'var(--duration-instant, 0ms)',
609
+ dramatic: 'var(--duration-dramatic, 600ms)',
610
+ },
611
+ transitionTimingFunction: {
612
+ // DEFAULT drives every bare `transition-*` utility so its easing is
613
+ // theme-token-driven — not Tailwind's hardcoded cubic-bezier. `standard`
614
+ // falls back to legacy `--transition-timing` for backward compat.
615
+ DEFAULT: 'var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1)))',
616
+ linear: 'var(--easing-linear, linear)',
617
+ standard: 'var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1)))',
618
+ emphasized: 'var(--easing-emphasized, cubic-bezier(0.2, 0, 0, 1))',
619
+ spring: 'var(--easing-spring, cubic-bezier(0.34, 1.56, 0.64, 1))',
620
+ },
621
+ keyframes: {
622
+ 'almadar-marquee': {
623
+ from: { transform: 'translateX(0)' },
624
+ to: { transform: 'translateX(var(--marquee-shift, -50%))' },
625
+ },
626
+ 'modal-in': {
627
+ '0%': {
628
+ opacity: 'var(--motion-modal-enter-from-opacity, 0)',
629
+ transform: 'var(--motion-modal-enter-from-transform, scale(0.96) translateY(8px))',
630
+ },
631
+ '100%': {
632
+ opacity: 'var(--motion-modal-enter-to-opacity, 1)',
633
+ transform: 'var(--motion-modal-enter-to-transform, translateZ(0))',
634
+ },
635
+ },
636
+ shimmer: {
637
+ '0%': { backgroundPosition: '200% 0' },
638
+ '100%': { backgroundPosition: '-200% 0' },
639
+ },
640
+ 'modal-out': {
641
+ '0%': {
642
+ opacity: 'var(--motion-modal-exit-from-opacity, 1)',
643
+ transform: 'var(--motion-modal-exit-from-transform, translateZ(0))',
644
+ },
645
+ '100%': {
646
+ opacity: 'var(--motion-modal-exit-to-opacity, 0)',
647
+ transform: 'var(--motion-modal-exit-to-transform, scale(0.96) translateY(8px))',
648
+ },
649
+ },
650
+ 'overlay-in': {
651
+ '0%': { opacity: 'var(--motion-overlay-enter-from-opacity, var(--motion-overlay-from-opacity, 0))' },
652
+ '100%': { opacity: '1' },
653
+ },
654
+ 'overlay-out': {
655
+ '0%': { opacity: '1' },
656
+ '100%': { opacity: 'var(--motion-overlay-exit-to-opacity, var(--motion-overlay-from-opacity, 0))' },
657
+ },
658
+ 'slide-up': {
659
+ '0%': {
660
+ opacity: 'var(--motion-slide-up-from-opacity, 0)',
661
+ transform: 'var(--motion-slide-up-from-transform, translateY(16px))',
662
+ },
663
+ '100%': {
664
+ opacity: '1',
665
+ transform: 'translateZ(0)',
666
+ },
667
+ },
668
+ 'drawer-in': {
669
+ '0%': {
670
+ opacity: 'var(--motion-drawer-enter-from-opacity, 0)',
671
+ transform: 'var(--motion-drawer-enter-from-transform, translateX(calc(100% * var(--motion-drawer-sign, 1))))',
672
+ },
673
+ '100%': {
674
+ opacity: 'var(--motion-drawer-enter-to-opacity, 1)',
675
+ transform: 'var(--motion-drawer-enter-to-transform, translateZ(0))',
676
+ },
677
+ },
678
+ 'drawer-out': {
679
+ '0%': {
680
+ opacity: 'var(--motion-drawer-exit-from-opacity, 1)',
681
+ transform: 'var(--motion-drawer-exit-from-transform, translateZ(0))',
682
+ },
683
+ '100%': {
684
+ opacity: 'var(--motion-drawer-exit-to-opacity, 0)',
685
+ transform: 'var(--motion-drawer-exit-to-transform, translateX(calc(100% * var(--motion-drawer-sign, 1))))',
686
+ },
687
+ },
688
+ 'popover-in': {
689
+ '0%': {
690
+ opacity: 'var(--motion-popover-enter-from-opacity, 0)',
691
+ transform: 'var(--motion-popover-enter-from-transform, scale(0.95))',
692
+ },
693
+ '100%': {
694
+ opacity: 'var(--motion-popover-enter-to-opacity, 1)',
695
+ transform: 'var(--motion-popover-enter-to-transform, scale(1))',
696
+ },
697
+ },
698
+ 'popover-out': {
699
+ '0%': {
700
+ opacity: 'var(--motion-popover-exit-from-opacity, 1)',
701
+ transform: 'var(--motion-popover-exit-from-transform, scale(1))',
702
+ },
703
+ '100%': {
704
+ opacity: 'var(--motion-popover-exit-to-opacity, 0)',
705
+ transform: 'var(--motion-popover-exit-to-transform, scale(0.95))',
706
+ },
707
+ },
708
+ 'toast-in': {
709
+ '0%': {
710
+ opacity: 'var(--motion-toast-enter-from-opacity, 0)',
711
+ transform: 'var(--motion-toast-enter-from-transform, translateY(16px))',
712
+ },
713
+ '100%': {
714
+ opacity: 'var(--motion-toast-enter-to-opacity, 1)',
715
+ transform: 'var(--motion-toast-enter-to-transform, translateZ(0))',
716
+ },
717
+ },
718
+ 'toast-out': {
719
+ '0%': {
720
+ opacity: 'var(--motion-toast-exit-from-opacity, 1)',
721
+ transform: 'var(--motion-toast-exit-from-transform, translateZ(0))',
722
+ },
723
+ '100%': {
724
+ opacity: 'var(--motion-toast-exit-to-opacity, 0)',
725
+ transform: 'var(--motion-toast-exit-to-transform, translateY(16px))',
726
+ },
727
+ },
728
+ 'fade-in': {
729
+ '0%': { opacity: 'var(--motion-fade-enter-from-opacity, 0)' },
730
+ '100%': { opacity: 'var(--motion-fade-enter-to-opacity, 1)' },
731
+ },
732
+ 'fade-out': {
733
+ '0%': { opacity: 'var(--motion-fade-exit-from-opacity, 1)' },
734
+ '100%': { opacity: 'var(--motion-fade-exit-to-opacity, 0)' },
735
+ },
736
+ 'page-in': {
737
+ '0%': {
738
+ opacity: 'var(--motion-page-enter-from-opacity, 0)',
739
+ transform: 'var(--motion-page-enter-from-transform, translateY(8px))',
740
+ },
741
+ '100%': {
742
+ opacity: 'var(--motion-page-enter-to-opacity, 1)',
743
+ transform: 'var(--motion-page-enter-to-transform, translateZ(0))',
744
+ },
745
+ },
746
+ 'page-out': {
747
+ '0%': {
748
+ opacity: 'var(--motion-page-exit-from-opacity, 1)',
749
+ transform: 'var(--motion-page-exit-from-transform, translateZ(0))',
750
+ },
751
+ '100%': {
752
+ opacity: 'var(--motion-page-exit-to-opacity, 0)',
753
+ transform: 'var(--motion-page-exit-to-transform, translateY(-8px))',
754
+ },
755
+ },
756
+ },
757
+ animation: {
758
+ 'almadar-marquee': 'almadar-marquee 40s linear infinite',
759
+ // Motion-token-driven durations/easings (fall back to legacy
760
+ // --transition-* so themes that haven't migrated keep working).
761
+ 'modal-in': 'modal-in var(--duration-normal, var(--transition-normal, 250ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1)))',
762
+ 'modal-out': 'modal-out var(--duration-normal, var(--transition-normal, 250ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1))) forwards',
763
+ 'overlay-in': 'overlay-in var(--duration-normal, var(--transition-normal, 250ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1)))',
764
+ 'overlay-out': 'overlay-out var(--duration-fast, var(--transition-fast, 150ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1))) forwards',
765
+ 'slide-up': 'slide-up var(--duration-slow, var(--transition-slow, 400ms)) var(--easing-emphasized, cubic-bezier(0.2, 0, 0, 1))',
766
+ 'drawer-in': 'drawer-in var(--duration-normal, var(--transition-normal, 250ms)) var(--easing-emphasized, cubic-bezier(0.2, 0, 0, 1))',
767
+ 'drawer-out': 'drawer-out var(--duration-normal, var(--transition-normal, 250ms)) var(--easing-emphasized, cubic-bezier(0.2, 0, 0, 1)) forwards',
768
+ 'popover-in': 'popover-in var(--duration-fast, var(--transition-fast, 150ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1)))',
769
+ 'popover-out': 'popover-out var(--duration-fast, var(--transition-fast, 150ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1))) forwards',
770
+ 'toast-in': 'toast-in var(--duration-normal, var(--transition-normal, 250ms)) var(--easing-emphasized, cubic-bezier(0.2, 0, 0, 1))',
771
+ 'toast-out': 'toast-out var(--duration-normal, var(--transition-normal, 250ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1))) forwards',
772
+ 'fade-in': 'fade-in var(--duration-fast, var(--transition-fast, 150ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1)))',
773
+ 'fade-out': 'fade-out var(--duration-fast, var(--transition-fast, 150ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1))) forwards',
774
+ 'page-in': 'page-in var(--duration-normal, var(--transition-normal, 250ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1)))',
775
+ 'page-out': 'page-out var(--duration-fast, var(--transition-fast, 150ms)) var(--easing-standard, var(--transition-timing, cubic-bezier(0.4, 0, 0.2, 1))) forwards',
776
+ 'shimmer': 'shimmer var(--duration-shimmer, 1.5s) var(--easing-linear, linear) infinite',
777
+ },
778
+ // Density-axis spacing scale. Tailwind's default `p-3` / `gap-4` resolve
779
+ // here so existing classes keep working — but now read from tokens.
780
+ // Defaults match Tailwind's default (12px / 16px / 24px for 3 / 4 / 6),
781
+ // so post-migration visual output is identical until a theme overrides.
782
+ spacing: {
783
+ 0: 'var(--space-0, 0px)',
784
+ 1: 'var(--space-1, 4px)',
785
+ 2: 'var(--space-2, 8px)',
786
+ 3: 'var(--space-3, 12px)',
787
+ 4: 'var(--space-4, 16px)',
788
+ 5: 'var(--space-5, 20px)',
789
+ 6: 'var(--space-6, 24px)',
790
+ 7: 'var(--space-7, 28px)',
791
+ 8: 'var(--space-8, 32px)',
792
+ 9: 'var(--space-9, 36px)',
793
+ 10: 'var(--space-10, 40px)',
794
+ 11: 'var(--space-11, 44px)',
795
+ 12: 'var(--space-12, 48px)',
796
+ // Component-intent spacing (codemod targets for padding-by-intent)
797
+ 'card-sm': 'var(--card-padding-sm, 12px)',
798
+ 'card-md': 'var(--card-padding-md, 16px)',
799
+ 'card-lg': 'var(--card-padding-lg, 24px)',
800
+ 'dialog': 'var(--dialog-padding, 24px)',
801
+ 'section': 'var(--section-gap, 32px)',
802
+ },
803
+ // Type-axis size scale. Each step pairs a size with a line-height,
804
+ // both read from tokens with Tailwind-default fallbacks so existing
805
+ // `text-sm` resolves to the same 14px/20px until a theme overrides.
806
+ fontSize: {
807
+ xs: ['var(--text-xs, 12px)', { lineHeight: 'var(--leading-xs, 16px)' }],
808
+ sm: ['var(--text-sm, 14px)', { lineHeight: 'var(--leading-sm, 20px)' }],
809
+ base: ['var(--text-base, 16px)', { lineHeight: 'var(--leading-base, 24px)' }],
810
+ lg: ['var(--text-lg, 18px)', { lineHeight: 'var(--leading-lg, 28px)' }],
811
+ xl: ['var(--text-xl, 20px)', { lineHeight: 'var(--leading-xl, 28px)' }],
812
+ '2xl': ['var(--text-2xl, 24px)', { lineHeight: 'var(--leading-2xl, 32px)' }],
813
+ '3xl': ['var(--text-3xl, 30px)', { lineHeight: 'var(--leading-3xl, 36px)' }],
814
+ '4xl': ['var(--text-4xl, 36px)', { lineHeight: 'var(--leading-4xl, 40px)' }],
815
+ 'display-1': ['var(--text-display-1, 48px)', { lineHeight: 'var(--leading-display-1, 52px)' }],
816
+ 'display-2': ['var(--text-display-2, 60px)', { lineHeight: 'var(--leading-display-2, 64px)' }],
817
+ },
818
+ // Density-axis per-element heights (codemod targets for `h-{px}` on
819
+ // buttons / inputs / rows / icons).
820
+ height: {
821
+ 'button-sm': 'var(--button-height-sm, 28px)',
822
+ 'button-md': 'var(--button-height-md, 36px)',
823
+ 'button-lg': 'var(--button-height-lg, 44px)',
824
+ 'input-sm': 'var(--input-height-sm, 28px)',
825
+ 'input-md': 'var(--input-height-md, 36px)',
826
+ 'input-lg': 'var(--input-height-lg, 44px)',
827
+ 'row-compact': 'var(--row-height-compact, 32px)',
828
+ 'row-normal': 'var(--row-height-normal, 40px)',
829
+ 'row-spacious': 'var(--row-height-spacious, 48px)',
830
+ 'icon-default': 'var(--icon-default-size, 16px)',
831
+ },
832
+ minHeight: {
833
+ 'button-sm': 'var(--button-height-sm, 28px)',
834
+ 'button-md': 'var(--button-height-md, 36px)',
835
+ 'button-lg': 'var(--button-height-lg, 44px)',
836
+ 'input-sm': 'var(--input-height-sm, 28px)',
837
+ 'input-md': 'var(--input-height-md, 36px)',
838
+ 'input-lg': 'var(--input-height-lg, 44px)',
839
+ 'row-compact': 'var(--row-height-compact, 32px)',
840
+ 'row-normal': 'var(--row-height-normal, 40px)',
841
+ 'row-spacious': 'var(--row-height-spacious, 48px)',
842
+ },
843
+ minWidth: Object.fromEntries(
844
+ nativeTokens.sizes.minWidth.filter((e) => e.key.startsWith('modal-')).map((e) => [e.key, `${e.value / 16}rem`]),
845
+ ),
846
+ width: {
847
+ 'icon-default': 'var(--icon-default-size, 16px)',
848
+ },
849
+ // Geometry-axis radius rhythm (codemod targets for `rounded-*` by intent).
850
+ // The existing sm/md/lg/xl/full keys above continue to work as-is.
851
+ // Codemod converts `rounded-md` on Card → `rounded-container`, on Button → `rounded-interactive`, on Avatar/Badge → `rounded-pill`.
852
+ // borderRadius is extended below alongside the existing radius tokens.
853
+ // Elevation-axis per-layer shadow mapping.
854
+ // Codemod converts `shadow-sm` on Card → `shadow-elevation-card`, etc.
855
+ // boxShadow is extended below.
856
+ // Container-query breakpoints aligned 1:1 with Tailwind's default
857
+ // viewport breakpoints (sm 640 / md 768 / lg 1024 / xl 1280 /
858
+ // 2xl 1536). Lets components use `@lg/foo:hidden` as a drop-in
859
+ // replacement for `lg:hidden` when they're rendered inside a
860
+ // CSS Container (the Studio preview, embedded iframes, etc.) so
861
+ // the layout responds to the container's width, not the viewport.
862
+ containers: {
863
+ sm: `${nativeTokens.breakpoints.sm / 16}rem`,
864
+ md: `${nativeTokens.breakpoints.md / 16}rem`,
865
+ lg: `${nativeTokens.breakpoints.lg / 16}rem`,
866
+ xl: `${nativeTokens.breakpoints.xl / 16}rem`,
867
+ '2xl': `${nativeTokens.breakpoints.xxl / 16}rem`,
868
+ },
869
+ },
870
+ },
871
+ plugins: [
872
+ // MarkdownContent styles itself with `prose`, themed via its --tw-prose-* vars
873
+ require('@tailwindcss/typography'),
874
+ // Chrome-skin utilities: sprite-driven panel/button chrome, opt-in per theme.
875
+ // No-op (`none`) unless the active theme defines the backing --game-* vars —
876
+ // zero visual change for every theme that doesn't set them.
877
+ require('tailwindcss/plugin')(({ addBase, addUtilities }) => {
878
+ // AnimatedReveal marks a band away from the viewport; nothing inside it needs to animate.
879
+ addBase({ '[data-on-screen="false"] *': { 'animation-play-state': 'paused !important' } });
880
+ addUtilities({
881
+ '.chrome-panel': {
882
+ 'border-image-source': 'var(--game-panel-border-image, none)',
883
+ 'border-image-slice': 'var(--game-panel-border-image-slice, 30 fill)',
884
+ 'border-image-width': 'var(--game-panel-border-image-width, 30px)',
885
+ 'border-image-repeat': 'stretch',
886
+ },
887
+ // Heading voice: every heading reads the theme's display family + voice tokens.
888
+ '.heading-voice': {
889
+ 'font-family': 'var(--font-family-display, var(--font-family))',
890
+ 'font-weight': 'var(--heading-weight, var(--font-weight-bold, 700))',
891
+ 'text-transform': 'var(--heading-transform, none)',
892
+ 'letter-spacing': 'var(--heading-tracking, var(--letter-spacing, normal))',
893
+ 'font-style': 'var(--heading-style, normal)',
894
+ 'text-shadow': 'var(--heading-shadow, none)',
895
+ },
896
+ // Surface material on panels (cards, dialogs, popovers, drawers).
897
+ '.surface-material': {
898
+ 'background-image': 'var(--surface-card-image, none)',
899
+ 'backdrop-filter': 'var(--surface-backdrop, none)',
900
+ '-webkit-backdrop-filter': 'var(--surface-backdrop, none)',
901
+ },
902
+ // Content surface: the box behind a content block (table, calendar, list,
903
+ // chart …). Every value is a theme hook with a paint-site fallback, so a
904
+ // [data-theme] subtree's colors apply (never alias these on :root).
905
+ '.surface-content': {
906
+ 'background-color': 'var(--surface-content-bg, var(--color-card))',
907
+ 'background-image': 'var(--surface-card-image, none)',
908
+ 'backdrop-filter': 'var(--surface-backdrop, none)',
909
+ '-webkit-backdrop-filter': 'var(--surface-backdrop, none)',
910
+ 'border-width': 'var(--surface-content-border-width, var(--border-width, 1px))',
911
+ 'border-color': 'var(--surface-content-border-color, var(--color-border))',
912
+ 'border-radius': 'var(--surface-content-radius, var(--radius-container, var(--radius-md)))',
913
+ 'box-shadow': 'var(--surface-content-shadow, var(--elevation-card, var(--shadow-sm)))',
914
+ },
915
+ // Logo / wordmark marquee (std-proof `proofLook: marquee`): two copies of the strip scroll as one loop.
916
+ '.proof-marquee': {
917
+ overflow: 'hidden',
918
+ 'mask-image': 'linear-gradient(to right, transparent, black 8%, black 92%, transparent)',
919
+ '-webkit-mask-image': 'linear-gradient(to right, transparent, black 8%, black 92%, transparent)',
920
+ },
921
+ '.proof-marquee-track': { display: 'flex', width: 'max-content' },
922
+ // An RTL strip starts at the right edge, so the loop slides right.
923
+ '[dir="rtl"] .proof-marquee-track': { '--marquee-shift': '50%' },
924
+ // Full-width band layers (Box edgeTop/edgeBottom/texture/backdrop, std-hero scrim).
925
+ '.band': { position: 'relative', overflow: 'hidden', isolation: 'isolate' },
926
+ // Zero specificity: a child's own position utility (std-hero's absolute backdrop) must win.
927
+ ':where(.band > :not([data-band-layer]))': { position: 'relative', 'z-index': '1' },
928
+ '.band-backdrop': { position: 'absolute', inset: '0', 'pointer-events': 'none', 'z-index': '0' },
929
+ '.band-backdrop img': { width: '100%', height: '100%', 'object-fit': 'cover' },
930
+ '.band-scrim': {
931
+ position: 'absolute', inset: '0', 'pointer-events': 'none', 'z-index': '0',
932
+ 'background-image': 'var(--surface-scrim, linear-gradient(to top, rgb(0 0 0 / 0.55), rgb(0 0 0 / 0.15)))',
933
+ },
934
+ '.band-texture': {
935
+ position: 'absolute', inset: '0', 'pointer-events': 'none', 'z-index': '0',
936
+ 'background-color': 'color-mix(in oklab, var(--color-primary) 14%, transparent)',
937
+ 'mask-image': "var(--surface-texture-mask, url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><circle cx='3' cy='3' r='1.5'/></svg>\"))",
938
+ '-webkit-mask-image': "var(--surface-texture-mask, url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><circle cx='3' cy='3' r='1.5'/></svg>\"))",
939
+ 'mask-size': 'var(--surface-texture-size, 24px 24px)',
940
+ '-webkit-mask-size': 'var(--surface-texture-size, 24px 24px)',
941
+ 'mask-repeat': 'repeat',
942
+ '-webkit-mask-repeat': 'repeat',
943
+ },
944
+ '.band-edge': {
945
+ position: 'absolute', left: '0', right: '0', 'pointer-events': 'none', 'z-index': '0',
946
+ 'mask-size': '100% 100%', '-webkit-mask-size': '100% 100%',
947
+ 'mask-repeat': 'no-repeat', '-webkit-mask-repeat': 'no-repeat',
948
+ },
949
+ '.band-edge-top': { top: '0' },
950
+ '.band-edge-bottom': { bottom: '0' },
951
+ '.band-gradient': {
952
+ 'background-color': 'var(--color-muted)',
953
+ 'background-image': 'var(--surface-accent-image, linear-gradient(180deg, color-mix(in oklab, var(--color-primary) 12%, var(--color-background)), var(--color-background)))',
954
+ color: 'var(--color-foreground)',
955
+ },
956
+ '.band-inverse': {
957
+ '--band-fg': 'var(--color-foreground)',
958
+ '--band-bg': 'var(--color-background)',
959
+ 'background-color': 'var(--color-foreground)',
960
+ color: 'var(--color-background)',
961
+ },
962
+ '.band-inverse > :not([data-band-layer])': {
963
+ '--color-foreground': 'var(--band-bg)',
964
+ '--color-background': 'var(--band-fg)',
965
+ '--color-card': 'color-mix(in oklab, var(--band-fg) 90%, var(--band-bg))',
966
+ '--color-muted': 'color-mix(in oklab, var(--band-fg) 85%, var(--band-bg))',
967
+ '--color-muted-foreground': 'color-mix(in oklab, var(--band-bg) 72%, var(--band-fg))',
968
+ '--color-border': 'color-mix(in oklab, var(--band-bg) 22%, var(--band-fg))',
969
+ },
970
+ // Surface material on the page background (app shell / themed root).
971
+ '.surface-page': {
972
+ 'background-image': 'var(--surface-page-image, none)',
973
+ 'background-size': 'var(--surface-page-image-size, auto)',
974
+ 'background-attachment': 'fixed',
975
+ },
976
+ // Interactive-control geometry: border style (outset bevel for Win95-style
977
+ // chrome) and corner shape (round controls inside a scoop/notch frame).
978
+ '.interactive-border': {
979
+ 'border-style': 'var(--border-style-interactive, var(--border-style, solid))',
980
+ 'corner-shape': 'var(--corner-shape-interactive, var(--corner-shape, round))',
981
+ },
982
+ '.chrome-button': {
983
+ 'background-image': 'var(--game-button-bg-image, none)',
984
+ 'background-size': 'var(--game-button-bg-size, 100% 100%)',
985
+ 'background-repeat': 'no-repeat',
986
+ 'background-position': 'center',
987
+ },
988
+ });
989
+ }),
990
+ ],
991
+ };