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