cssints 0.0.0-stage → 0.2.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 (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -2
  3. package/dist/author-types-C1AhsnrT.d.mts +80 -0
  4. package/dist/check.d.mts +22 -0
  5. package/dist/check.mjs +37 -0
  6. package/dist/color-BYIxVLlS.mjs +29 -0
  7. package/dist/color-C8OzjAeg.mjs +2 -0
  8. package/dist/contrast-DhK69Xak.mjs +83 -0
  9. package/dist/derived.d.mts +14 -0
  10. package/dist/derived.mjs +391 -0
  11. package/dist/errors-D4ZbcwRo.d.mts +32 -0
  12. package/dist/frame-BoBKjgBB.mjs +92 -0
  13. package/dist/frame.d.mts +72 -0
  14. package/dist/frame.mjs +2 -0
  15. package/dist/group-common-9zpBxfUF.d.mts +1 -0
  16. package/dist/group-types-9ttphdku.d.mts +55 -0
  17. package/dist/groups/compositing-2.d.mts +20 -0
  18. package/dist/groups/css-align-3.d.mts +29 -0
  19. package/dist/groups/css-anchor-position-1.d.mts +49 -0
  20. package/dist/groups/css-anchor-position-2.d.mts +50 -0
  21. package/dist/groups/css-animations-1.d.mts +28 -0
  22. package/dist/groups/css-animations-2.d.mts +29 -0
  23. package/dist/groups/css-backgrounds-3.d.mts +27 -0
  24. package/dist/groups/css-backgrounds-4.d.mts +29 -0
  25. package/dist/groups/css-borders-4.d.mts +95 -0
  26. package/dist/groups/css-box-4.d.mts +38 -0
  27. package/dist/groups/css-break-4.d.mts +23 -0
  28. package/dist/groups/css-cascade-5.d.mts +18 -0
  29. package/dist/groups/css-cascade-6.d.mts +18 -0
  30. package/dist/groups/css-color-4.d.mts +29 -0
  31. package/dist/groups/css-color-5.d.mts +32 -0
  32. package/dist/groups/css-color-6.d.mts +32 -0
  33. package/dist/groups/css-color-adjust-1.d.mts +20 -0
  34. package/dist/groups/css-color-hdr-1.d.mts +19 -0
  35. package/dist/groups/css-conditional-3.d.mts +17 -0
  36. package/dist/groups/css-conditional-4.d.mts +17 -0
  37. package/dist/groups/css-conditional-5.d.mts +22 -0
  38. package/dist/groups/css-contain-2.d.mts +19 -0
  39. package/dist/groups/css-content-3.d.mts +23 -0
  40. package/dist/groups/css-counter-styles-3.d.mts +16 -0
  41. package/dist/groups/css-display-4.d.mts +22 -0
  42. package/dist/groups/css-easing-2.d.mts +18 -0
  43. package/dist/groups/css-env-1.d.mts +16 -0
  44. package/dist/groups/css-flexbox-1.d.mts +24 -0
  45. package/dist/groups/css-fonts-4.d.mts +46 -0
  46. package/dist/groups/css-fonts-5.d.mts +44 -0
  47. package/dist/groups/css-forms-1.d.mts +19 -0
  48. package/dist/groups/css-gaps-1.d.mts +21 -0
  49. package/dist/groups/css-gcpm-3.d.mts +20 -0
  50. package/dist/groups/css-gcpm-4.d.mts +20 -0
  51. package/dist/groups/css-grid-2.d.mts +34 -0
  52. package/dist/groups/css-grid-3.d.mts +34 -0
  53. package/dist/groups/css-images-3.d.mts +25 -0
  54. package/dist/groups/css-images-4.d.mts +32 -0
  55. package/dist/groups/css-images-5.d.mts +33 -0
  56. package/dist/groups/css-inline-3.d.mts +28 -0
  57. package/dist/groups/css-lists-3.d.mts +26 -0
  58. package/dist/groups/css-logical-1.d.mts +35 -0
  59. package/dist/groups/css-masking-1.d.mts +37 -0
  60. package/dist/groups/css-multicol-2.d.mts +24 -0
  61. package/dist/groups/css-overflow-3.d.mts +28 -0
  62. package/dist/groups/css-overflow-4.d.mts +29 -0
  63. package/dist/groups/css-overflow-5.d.mts +31 -0
  64. package/dist/groups/css-overscroll-1.d.mts +22 -0
  65. package/dist/groups/css-page-3.d.mts +18 -0
  66. package/dist/groups/css-page-floats-3.d.mts +19 -0
  67. package/dist/groups/css-position-3.d.mts +29 -0
  68. package/dist/groups/css-position-4.d.mts +30 -0
  69. package/dist/groups/css-rhythm-1.d.mts +18 -0
  70. package/dist/groups/css-round-display-1.d.mts +16 -0
  71. package/dist/groups/css-ruby-1.d.mts +21 -0
  72. package/dist/groups/css-scroll-anchoring-1.d.mts +18 -0
  73. package/dist/groups/css-scroll-snap-1.d.mts +42 -0
  74. package/dist/groups/css-scroll-snap-2.d.mts +43 -0
  75. package/dist/groups/css-scrollbars-1.d.mts +19 -0
  76. package/dist/groups/css-shapes-1.d.mts +27 -0
  77. package/dist/groups/css-shapes-2.d.mts +27 -0
  78. package/dist/groups/css-size-adjust-1.d.mts +18 -0
  79. package/dist/groups/css-sizing-3.d.mts +34 -0
  80. package/dist/groups/css-sizing-4.d.mts +33 -0
  81. package/dist/groups/css-speech-1.d.mts +18 -0
  82. package/dist/groups/css-tables-3.d.mts +22 -0
  83. package/dist/groups/css-text-3.d.mts +36 -0
  84. package/dist/groups/css-text-4.d.mts +40 -0
  85. package/dist/groups/css-text-decor-3.d.mts +30 -0
  86. package/dist/groups/css-text-decor-4.d.mts +31 -0
  87. package/dist/groups/css-transforms-1.d.mts +31 -0
  88. package/dist/groups/css-transforms-2.d.mts +48 -0
  89. package/dist/groups/css-transitions-1.d.mts +22 -0
  90. package/dist/groups/css-transitions-2.d.mts +23 -0
  91. package/dist/groups/css-ui-4.d.mts +35 -0
  92. package/dist/groups/css-values-4.d.mts +38 -0
  93. package/dist/groups/css-values-5.d.mts +43 -0
  94. package/dist/groups/css-variables-2.d.mts +6 -0
  95. package/dist/groups/css-view-transitions-2.d.mts +20 -0
  96. package/dist/groups/css-viewport.d.mts +18 -0
  97. package/dist/groups/css-will-change-1.d.mts +18 -0
  98. package/dist/groups/css-writing-modes-4.d.mts +22 -0
  99. package/dist/groups/css2.d.mts +19 -0
  100. package/dist/groups/fill-stroke-3.d.mts +27 -0
  101. package/dist/groups/filter-effects-1.d.mts +32 -0
  102. package/dist/groups/filter-effects-2.d.mts +33 -0
  103. package/dist/groups/limited-availability.d.mts +2 -0
  104. package/dist/groups/mediaqueries-4.d.mts +16 -0
  105. package/dist/groups/mediaqueries-5.d.mts +16 -0
  106. package/dist/groups/motion-1.d.mts +24 -0
  107. package/dist/groups/newly-available.d.mts +631 -0
  108. package/dist/groups/not-discouraged.d.mts +727 -0
  109. package/dist/groups/scroll-animations-1.d.mts +30 -0
  110. package/dist/groups/selectors-4.d.mts +54 -0
  111. package/dist/groups/selectors-5.d.mts +54 -0
  112. package/dist/groups/widely-available.d.mts +616 -0
  113. package/dist/index.d.mts +48 -0
  114. package/dist/index.mjs +1269 -0
  115. package/dist/instrument-gCazujmb.mjs +1624 -0
  116. package/dist/lowered-D2KusPLp.mjs +28 -0
  117. package/dist/node-OJ_w_Usj.d.mts +233 -0
  118. package/dist/parent-vars.d.mts +13 -0
  119. package/dist/parent-vars.mjs +65 -0
  120. package/dist/plugin-types.d.mts +377 -0
  121. package/dist/plugin.d.mts +3 -0
  122. package/dist/plugin.mjs +30 -0
  123. package/dist/registry-CTumHB8p.mjs +73 -0
  124. package/dist/runtime-Dt4Tm0Q7.d.mts +19 -0
  125. package/dist/runtime.d.mts +18 -0
  126. package/dist/runtime.mjs +25 -0
  127. package/dist/scope-ZVhUxQH1.d.mts +2101 -0
  128. package/dist/sheet-BKsMTa0c.mjs +757 -0
  129. package/dist/surface.d.mts +228 -0
  130. package/dist/surface.mjs +101 -0
  131. package/dist/theme-BsP2E4LB.mjs +929 -0
  132. package/dist/theme-types-Bqv0Ggz_.d.mts +1808 -0
  133. package/dist/trace-otlp-CbKFDsn9.mjs +14 -0
  134. package/dist/tui-types.d.mts +181 -0
  135. package/dist/tui.d.mts +23 -0
  136. package/dist/tui.mjs +427 -0
  137. package/dist/types.d.mts +2 -0
  138. package/dist/vite.d.mts +134 -0
  139. package/dist/vite.mjs +977 -0
  140. package/docs/API.md +1193 -0
  141. package/package.json +85 -4
  142. package/skills/cssints/SKILL.md +203 -0
  143. package/skills/cssints/references/errors.md +86 -0
  144. package/skills/cssints/references/plugins.md +91 -0
  145. package/skills/cssints/references/tokens.md +91 -0
  146. package/skills/cssints-plugin/SKILL.md +177 -0
  147. package/skills/cssints-plugin/references/table.md +124 -0
  148. package/skills/cssints-plugin/references/testing.md +122 -0
@@ -0,0 +1,929 @@
1
+ import { a as registry, d as MacroError, f as MemberError, o as warn } from "./registry-CTumHB8p.mjs";
2
+ import { D as relation, E as covers, d as requireLayer, p as standIn } from "./sheet-BKsMTa0c.mjs";
3
+ import { t as fallbackOf } from "./lowered-D2KusPLp.mjs";
4
+ import { createRequire } from "node:module";
5
+ import { checkSelector } from "@cssints/css-grammar/check";
6
+ import { browsers, supportOf } from "@cssints/css-grammar/support";
7
+ import { CSSStyleValue } from "@cssints/css-grammar/values";
8
+ import { Cause, Effect, Exit, Formatter, Predicate } from "effect";
9
+ import { createHash } from "node:crypto";
10
+ import { functions } from "@cssints/css-grammar/functions";
11
+ import { properties } from "@cssints/css-grammar/mdn";
12
+ import { relative } from "node:path";
13
+ import { DTCG_TYPES, TOKEN_TYPES, grammarOf } from "@cssints/css-grammar/token";
14
+ import { matches } from "@cssints/css-grammar/twin";
15
+ //#region src/node.ts
16
+ const plain = (method) => {
17
+ throw fail(`cssints: plain styles do not chain (.${method}); merge them with cn(...)`);
18
+ };
19
+ const node = (decls, { markers, kernels, globals, themes, layers, plugs, bare } = {}, chain = (name) => plain(name)) => new Proxy({
20
+ __cssints: decls,
21
+ markers,
22
+ kernels,
23
+ globals,
24
+ themes,
25
+ layers,
26
+ plugs,
27
+ bare
28
+ }, { get: (t, k) => k in t || typeof k === "symbol" ? t[k] : (...args) => chain(k, args, t) });
29
+ const camel = (p) => p.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
30
+ const fail = (message) => new MacroError({
31
+ message,
32
+ ...registry.at
33
+ });
34
+ const failIn = (plugin, message) => new MemberError({
35
+ message,
36
+ pluginName: plugin,
37
+ ...registry.at
38
+ });
39
+ const isNode = (v) => !!v && typeof v === "object" && Array.isArray(v.__cssints);
40
+ const VAR = /var\((--[\w-]+)\)/g;
41
+ function probed(value, properties) {
42
+ if (!value.includes("var(--")) return [value];
43
+ const probesOf = (name) => properties.get(name)?.probes ?? [];
44
+ let n = 1;
45
+ for (const [, name] of value.matchAll(VAR)) n = Math.max(n, probesOf(name).length);
46
+ return Array.from({ length: n }, (_, i) => value.replace(VAR, (m, name) => probesOf(name)[i] ?? probesOf(name)[0] ?? m));
47
+ }
48
+ //#endregion
49
+ //#region src/lib.ts
50
+ const isFallback = (v) => !!v && typeof v === "object" && "__fallback" in v;
51
+ const edge = (program) => {
52
+ const exit = Effect.runSyncExit(program);
53
+ if (Exit.isFailure(exit)) throw Cause.squash(exit.cause);
54
+ return exit.value;
55
+ };
56
+ const PROPS = {
57
+ ...Object.fromEntries(Object.keys(properties).filter((p) => p !== "--*").map((p) => [camel(p), p])),
58
+ p: "padding",
59
+ pt: "padding-top",
60
+ pr: "padding-right",
61
+ pb: "padding-bottom",
62
+ pl: "padding-left",
63
+ m: "margin",
64
+ mt: "margin-top",
65
+ mr: "margin-right",
66
+ mb: "margin-bottom",
67
+ ml: "margin-left",
68
+ bg: "background-color"
69
+ };
70
+ const CONTEXTS = {
71
+ flex: [
72
+ "flex-direction",
73
+ "flex-wrap",
74
+ "flex-flow",
75
+ "align-items",
76
+ "align-content",
77
+ "justify-content",
78
+ "place-content",
79
+ "gap",
80
+ "row-gap",
81
+ "column-gap"
82
+ ],
83
+ grid: [
84
+ "grid-template-columns",
85
+ "grid-template-rows",
86
+ "grid-template-areas",
87
+ "grid-template",
88
+ "grid-auto-flow",
89
+ "grid-auto-columns",
90
+ "grid-auto-rows",
91
+ "align-items",
92
+ "justify-items",
93
+ "place-items",
94
+ "align-content",
95
+ "justify-content",
96
+ "place-content",
97
+ "gap",
98
+ "row-gap",
99
+ "column-gap"
100
+ ]
101
+ };
102
+ const SELECTORS = createRequire(import.meta.url)("mdn-data/css/selectors.json");
103
+ const FIRST = [
104
+ "link",
105
+ "visited",
106
+ "any-link",
107
+ "focus-within",
108
+ "hover",
109
+ "focus",
110
+ "focus-visible",
111
+ "active"
112
+ ];
113
+ const pseudoNames = Object.entries(SELECTORS).filter(([k, v]) => /^:[a-z-]+$/.test(k) && v?.status === "standard" && v.groups.includes("Selectors")).map(([k]) => k.slice(1)).filter((n) => n !== "default");
114
+ const PSEUDOS = Object.fromEntries([...FIRST, ...pseudoNames.filter((n) => !FIRST.includes(n))].map((n, i) => [camel(n), {
115
+ text: `:${n}`,
116
+ rank: i
117
+ }]));
118
+ const BUILDERS = /* @__PURE__ */ new Set([
119
+ "cn",
120
+ "firstThatWorks",
121
+ "keyframes",
122
+ "flex",
123
+ "grid",
124
+ "cv",
125
+ "media",
126
+ "container",
127
+ "supports",
128
+ "attr",
129
+ "group",
130
+ "within",
131
+ "global",
132
+ "layers",
133
+ "token",
134
+ "style",
135
+ "createTokens",
136
+ "createGlobalTheme",
137
+ "check"
138
+ ]);
139
+ const FUNCTIONS = Object.fromEntries(Object.keys(functions).map((f) => {
140
+ const n = camel(f);
141
+ return [n in PROPS || n in PSEUDOS || BUILDERS.has(n) ? `${n}Fn` : n, f];
142
+ }));
143
+ const LAYER = [
144
+ "_.a",
145
+ "_.b",
146
+ "_.c",
147
+ "_.d",
148
+ "_.e"
149
+ ];
150
+ function minWidth(q) {
151
+ if (/,|\b(or|not)\b/.test(q)) return 0;
152
+ let w = 0;
153
+ for (const [, n, u] of q.matchAll(/\(\s*(?:min-)?width\s*(?::|>=?)\s*([\d.]+)(px|rem|em)\s*\)/g)) w = Math.max(w, Number(n) * (u === "px" ? 1 : 16));
154
+ return w;
155
+ }
156
+ const RAW_VAR = /var\(\s*(--[\w-]+)/g;
157
+ function checkVars(where, text) {
158
+ if (!text.includes("var(")) return;
159
+ const { properties, defs } = registry;
160
+ for (const [, name] of text.matchAll(RAW_VAR)) {
161
+ if (name.startsWith("--_") || !properties.has(name)) continue;
162
+ const path = defs.get(name)?.path;
163
+ warn(registry, `var ${where} ${name}`, `${where}: "var(${name})" is the token ${path === name ? `declared as ${name}` : path}: pass the token itself, and css.var(token, fallback) for a fallback`);
164
+ }
165
+ }
166
+ const SPACING = /^(padding|margin|inset|gap|row-gap|column-gap)(-|$)/;
167
+ const decl = (prop, name, args) => {
168
+ if (!args.length) throw fail(`cssints: ${name}() expects a value`);
169
+ if (args.some(isNode)) throw fail(`cssints: ${name}() takes values, not styles; merge styles with cn(...)`);
170
+ for (const a of args) if (typeof a === "string") checkVars(name, a);
171
+ const [fb, extra] = args.filter(isFallback);
172
+ if (extra) throw fail(`cssints: ${name}() takes one firstThatWorks(...) per declaration`);
173
+ if (fb) {
174
+ const text = (v) => args.map((a) => a === fb ? v : a).join(" ");
175
+ const [wanted, ...rest] = fb.__fallback;
176
+ return [
177
+ prop,
178
+ text(wanted),
179
+ void 0,
180
+ rest.map(text)
181
+ ];
182
+ }
183
+ const [only] = args;
184
+ return [prop, args.length === 1 && typeof only === "number" && SPACING.test(prop) ? `${only * .25}rem` : args.join(" ")];
185
+ };
186
+ function carried(nodes) {
187
+ const out = {};
188
+ for (const n of nodes) {
189
+ if (n.markers) for (const m of n.markers) {
190
+ const all = out.markers ??= [];
191
+ if (!all.some((x) => x[0] === m[0] && x[1] === m[1])) all.push(m);
192
+ }
193
+ for (const m of n.bare ?? (n.__cssints.length ? [] : n.markers ?? [])) {
194
+ const all = out.bare ??= [];
195
+ if (!all.some((x) => x[0] === m[0] && x[1] === m[1])) all.push(m);
196
+ }
197
+ if (n.kernels) for (const k of n.kernels) {
198
+ const all = out.kernels ??= [];
199
+ if (!all.includes(k)) all.push(k);
200
+ }
201
+ if (n.globals) for (const g of n.globals) {
202
+ const all = out.globals ??= [];
203
+ if (!all.includes(g)) all.push(g);
204
+ }
205
+ if (n.themes) for (const t of n.themes) {
206
+ const all = out.themes ??= [];
207
+ if (!all.includes(t)) all.push(t);
208
+ }
209
+ if (n.layers) for (const l of n.layers) {
210
+ const all = out.layers ??= [];
211
+ if (!all.some((x) => x.names.join() === l.names.join() && x.before === l.before)) all.push(l);
212
+ }
213
+ if (n.plugs) for (const p of n.plugs) {
214
+ const all = out.plugs ??= [];
215
+ if (!all.includes(p)) all.push(p);
216
+ }
217
+ }
218
+ return out;
219
+ }
220
+ function merged(decls) {
221
+ const out = [];
222
+ const at = (d) => (d[2] ?? []).map((c) => c.text).join(" > ");
223
+ for (const d of decls) {
224
+ const where = at(d);
225
+ for (let i = out.length - 1; i >= 0; i--) {
226
+ const o = out[i];
227
+ if (at(o) !== where) continue;
228
+ const r = relation(o[0], d[0]);
229
+ if (r === "same") out.splice(i, 1);
230
+ else if (r === "overlap") throw fail(`cssints: ${o[0]} and ${d[0]} overlap without one containing the other${where ? ` (under ${where})` : ""}, so the sheet cannot order them by the arguments: set one of them, or the longhands`);
231
+ }
232
+ out.push(d);
233
+ }
234
+ return out;
235
+ }
236
+ function settled(base, variants, compounds = []) {
237
+ const at = (d) => (d[2] ?? []).map((c) => c.text).join(" > ");
238
+ const under = (d) => at(d) ? ` (under ${at(d)})` : "";
239
+ const meet = (o, d, who) => {
240
+ if (at(o) !== at(d)) return "apart";
241
+ const r = relation(o[0], d[0]);
242
+ if (r === "overlap") throw fail(`cssints: cv() ${who} ${o[0]} and ${d[0]} overlap without one containing the other${under(d)}, so the sheet cannot order them: set one of them, or the longhands`);
243
+ return r;
244
+ };
245
+ const replace = (olds, d, who, gone) => {
246
+ for (const o of olds) {
247
+ const cls = hashClass(o);
248
+ if (meet(o, d, who) !== "apart" && covers(d[0], o[0]) && cls !== hashClass(d) && !gone.includes(cls)) gone.push(cls);
249
+ }
250
+ };
251
+ const together = (o, d, a, b) => {
252
+ for (const x of o) if (meet(d, x, `${a} and ${b}:`) === "same") throw fail(`cssints: cv() ${a} and ${b} both set ${x[0]}${under(d)} and can be active together, so nothing says which wins: set it in one of them, or in the base`);
253
+ };
254
+ const out = {};
255
+ const keys = Object.entries(variants);
256
+ keys.forEach(([k, vs], i) => {
257
+ for (const [n, decls] of Object.entries(vs)) {
258
+ const gone = [];
259
+ for (const d of decls) {
260
+ replace(base, d, `base and variant ${k}.${n}:`, gone);
261
+ for (const [k2, vs2] of keys.slice(i + 1)) for (const [n2, decls2] of Object.entries(vs2)) together(decls2, d, `variants ${k}.${n}`, `${k2}.${n2}`);
262
+ }
263
+ if (gone.length) (out[k] ??= {})[n] = gone.join(" ");
264
+ }
265
+ });
266
+ return {
267
+ drops: out,
268
+ compound: compounds.map(({ when, decls }, j) => {
269
+ const gone = [];
270
+ const me = `compoundVariants[${j}]`;
271
+ for (const d of decls) {
272
+ replace(base, d, `base and ${me}:`, gone);
273
+ for (const [k, vs] of keys) for (const [n, vdecls] of Object.entries(vs)) if (!(k in when)) together(vdecls, d, me, `variant ${k}.${n}`);
274
+ else if (when[k] === n) replace(vdecls, d, `variant ${k}.${n} and ${me}:`, gone);
275
+ compounds.slice(j + 1).forEach((c, i) => {
276
+ if (Object.keys(when).every((k) => !(k in c.when) || c.when[k] === when[k])) together(c.decls, d, me, `compoundVariants[${j + 1 + i}]`);
277
+ });
278
+ }
279
+ return gone.join(" ");
280
+ })
281
+ };
282
+ }
283
+ function dropsOf(parts) {
284
+ const out = /* @__PURE__ */ new Map();
285
+ const under = (d) => (d[2] ?? []).map((c) => c.text).join(" > ");
286
+ for (const o of parts) for (const n of parts) {
287
+ if (n.at <= o.at || !(n.conditional || o.conditional) || under(n.decl) !== under(o.decl)) continue;
288
+ const r = relation(o.decl[0], n.decl[0]);
289
+ if (r === "overlap") throw fail(`cssints: cn() ${o.decl[0]} and ${n.decl[0]} overlap without one containing the other${under(n.decl) ? ` (under ${under(n.decl)})` : ""}, and may be active together, so the sheet cannot order them: set one of them, or the longhands`);
290
+ const cls = hashClass(o.decl);
291
+ const by = hashClass(n.decl);
292
+ if (r !== "apart" && covers(n.decl[0], o.decl[0]) && cls !== by) {
293
+ const gone = out.get(by) ?? out.set(by, []).get(by);
294
+ if (!gone.includes(cls)) gone.push(cls);
295
+ }
296
+ }
297
+ return [...out].map(([by, gone]) => [by, gone.join(" ")]);
298
+ }
299
+ function toDecls(member, args) {
300
+ if (member === "cn") {
301
+ if (!args.every(isNode)) throw fail(`cssints: cn() takes css.* values only, got ${JSON.stringify(args.filter((a) => !isNode(a)))}`);
302
+ return merged(args.flatMap((n) => n.__cssints));
303
+ }
304
+ if (CONTEXTS[member]) return [args.length ? decl(member, member, args) : ["display", member]];
305
+ const prop = PROPS[member];
306
+ if (!prop) throw fail(`cssints: unknown css.${member}`);
307
+ return [decl(prop, member, args)];
308
+ }
309
+ const chainNames = (ctx) => CONTEXTS[ctx].map((p) => camel(p.startsWith(`${ctx}-`) ? p.slice(ctx.length + 1) : p));
310
+ function chainDecl(ctx, method, args) {
311
+ if (!ctx) throw fail(`cssints: plain styles do not chain (.${method}); merge them with cn(...)`);
312
+ const i = chainNames(ctx).indexOf(method);
313
+ if (i < 0) throw fail(`cssints: ${ctx}() has no .${method}(); it chains ${chainNames(ctx).join(", ")}`);
314
+ return decl(CONTEXTS[ctx][i], method, args);
315
+ }
316
+ function hashClass([p, v, conds, fallbacks]) {
317
+ let h = 5381;
318
+ let text = conds ? `${conds.map((c) => c.text).join(">")}|${p}:${v}` : `${p}:${v}`;
319
+ if (fallbacks) text += `|${fallbacks.join("|")}`;
320
+ for (const c of text) h = (h << 5) + h + c.charCodeAt(0) | 0;
321
+ return "_" + (h >>> 0).toString(36);
322
+ }
323
+ //#endregion
324
+ //#region src/token.ts
325
+ var CSSTokenValue = class extends CSSStyleValue {
326
+ name;
327
+ syntax;
328
+ settable;
329
+ constructor(name, syntax, settable) {
330
+ super();
331
+ this.name = name;
332
+ this.syntax = syntax;
333
+ this.settable = settable;
334
+ }
335
+ toString() {
336
+ return `var(${this.name})`;
337
+ }
338
+ toJSON() {
339
+ return this.toString();
340
+ }
341
+ };
342
+ const SUPPORT_PROPERTY = {
343
+ color: "color",
344
+ length: "width",
345
+ percentage: "width",
346
+ "length-percentage": "width",
347
+ number: "opacity",
348
+ integer: "z-index",
349
+ angle: "transform",
350
+ time: "transition-duration",
351
+ url: "background-image",
352
+ image: "background-image",
353
+ "transform-list": "transform",
354
+ "easing-function": "transition-timing-function",
355
+ shadow: "box-shadow"
356
+ };
357
+ const supportTest = (syntax, text) => `(${SUPPORT_PROPERTY[syntax]}:${text})`;
358
+ const checkSyntaxFx = Effect.fnUntraced(function* (what, syntax, text, who = what, variable) {
359
+ const grammar = grammarOf(syntax);
360
+ if (!(yield* matches(grammar, text).pipe(Effect.mapError((e) => new MacroError({
361
+ message: e.message,
362
+ cause: e,
363
+ ...registry.at
364
+ }))))) return yield* fail(`cssints: ${what} "${text}" is not a ${grammar}`);
365
+ const prop = SUPPORT_PROPERTY[syntax];
366
+ if (!prop) return;
367
+ const ws = supportOf(prop, text).filter((w) => w.feature !== prop);
368
+ const lacking = [...new Set(ws.flatMap((w) => w.lacking))];
369
+ const lowered = ws.map((w) => variable && fallbackOf(variable, text, {
370
+ ...w,
371
+ lacking
372
+ }));
373
+ if (ws.length && lowered.every(Boolean)) return lowered[0] || void 0;
374
+ for (const [i, w] of ws.entries()) if (!lowered[i]) warn(registry, `${who} ${w.key}`, `${who}: "${w.feature}" in "${text}" is not supported by ${browsers(w.lacking)} (${w.key})`);
375
+ });
376
+ const checkSyntax = (what, syntax, text) => {
377
+ edge(checkSyntaxFx(what, syntax, text));
378
+ };
379
+ const NAME = /^(?:--)?([A-Za-z_][\w-]*)$/;
380
+ const nameOf = (name) => {
381
+ const { var: v, inherit = true } = typeof name === "string" ? { var: name } : name;
382
+ const m = typeof v === "string" ? NAME.exec(v) : null;
383
+ if (!m || typeof inherit !== "boolean") throw fail(`cssints: a token name is a CSS identifier or { var, inherit }, got ${Formatter.formatJson(name)}`);
384
+ return {
385
+ name: `--${m[1]}`,
386
+ inherit
387
+ };
388
+ };
389
+ const privateName = () => {
390
+ const at = registry.at;
391
+ const key = `${relative(process.cwd(), at.file)}:${at.site}:${registry.tokens}`;
392
+ return `--_${createHash("sha1").update(key).digest("hex").slice(0, 8)}`;
393
+ };
394
+ const FONT_RELATIVE = /(\d*\.?\d+(?:e[+-]?\d+)?)(r?em|r?ex|r?ch|r?cap|r?ic|r?lh)\b/gi;
395
+ const EM = {
396
+ em: 1,
397
+ ex: .5,
398
+ ch: .5,
399
+ cap: .7,
400
+ ic: 1,
401
+ lh: 1.2
402
+ };
403
+ const inPx = (text) => text.replace(FONT_RELATIVE, (_, n, unit) => {
404
+ const u = unit.toLowerCase();
405
+ return `${Number((Number(n) * 16 * (EM[u] ?? EM[u.slice(1)])).toFixed(4))}px`;
406
+ });
407
+ const declare = Effect.fnUntraced(function* (kind, text, variable, inherit, settable, what, live = false) {
408
+ const at = registry.at;
409
+ const { syntax, probes, property = `<${syntax}>` } = TOKEN_TYPES[kind];
410
+ const name = what ?? `token.${kind}() initial value`;
411
+ const fallback = yield* checkSyntaxFx(name, syntax, text, what ?? `${name} of ${variable}`, variable);
412
+ const initial = property === "*" ? fallback ?? text : inPx(fallback ?? text);
413
+ const n = registry.tokens++;
414
+ const by = `${at.file}#${at.site}.${n}`;
415
+ const css = `@property ${variable}{syntax:"${property}";inherits:${inherit};initial-value:${initial}}`;
416
+ const prev = registry.properties.get(variable);
417
+ if (prev && prev.css !== css && prev.by !== by && !(prev.file === at.file && prev.gen !== registry.gen)) return yield* fail(`cssints: ${variable} is already declared with another @property, in ${relative(process.cwd(), prev.file)}: ${prev.css}; here: ${css}`);
418
+ registry.properties.set(variable, {
419
+ css,
420
+ probes,
421
+ by,
422
+ file: at.file,
423
+ gen: registry.gen
424
+ });
425
+ registry.defs.set(variable, {
426
+ kind,
427
+ inherit,
428
+ path: variable,
429
+ value: text,
430
+ fallback
431
+ });
432
+ if ((fallback || initial !== text) && !live) registry.themed.set(by, {
433
+ file: at.file,
434
+ key: `0:${at.file}#${String(at.site).padStart(6, "0")}.${n}`,
435
+ css: `${inherit ? ":root" : ":where(*)"}{${variable}:${text}}`,
436
+ names: [variable]
437
+ });
438
+ return new CSSTokenValue(variable, syntax, settable);
439
+ });
440
+ const make = (kind) => (...args) => {
441
+ const [initial, name] = args;
442
+ if (!registry.at || typeof initial !== "string" && typeof initial !== "number" || args.length > 2) throw fail(`cssints: token.${kind}(initial, name?) takes an initial value (a string) and an optional name`);
443
+ const { name: variable, inherit } = name === void 0 ? {
444
+ name: privateName(),
445
+ inherit: true
446
+ } : nameOf(name);
447
+ return edge(declare(kind, String(initial).trim(), variable, inherit, name !== void 0));
448
+ };
449
+ const isStyle = (v) => Predicate.hasProperty(v, "__style");
450
+ const set = (...args) => {
451
+ const [t, value] = args;
452
+ if (args.length !== 2 || !(t instanceof CSSTokenValue) || typeof value !== "string" && typeof value !== "number") throw fail("cssints: token.set(token, value) takes a token and a value");
453
+ if (!t.settable) throw fail(`cssints: ${t.name} is private, only a token with a name can be set: token.<type>(initial, "name")`);
454
+ const text = String(value).trim();
455
+ checkSyntax(`token.set() value of ${t.name}`, t.syntax, text);
456
+ return { __style: {
457
+ sets: [[t.name, text]],
458
+ decls: []
459
+ } };
460
+ };
461
+ const style = (...args) => {
462
+ if (!args.length) throw fail("cssints: style() expects css.* values or token.set(...) results");
463
+ const sets = [];
464
+ const decls = [];
465
+ for (const a of args) if (isStyle(a)) {
466
+ sets.push(...a.__style.sets);
467
+ decls.push(...a.__style.decls);
468
+ } else if (isNode(a)) {
469
+ if (a.markers || a.kernels) throw fail("cssints: style() takes plain declarations: an inline style has no marker class");
470
+ if (a.__cssints.some(([, , conds]) => conds?.length)) throw fail("cssints: style() takes styles without conditions: an inline style has no media query or :hover");
471
+ if (a.__cssints.some((d) => d[3])) throw fail("cssints: style() takes one value per property: an inline style cannot hold a firstThatWorks(...) fallback");
472
+ decls.push(...a.__cssints);
473
+ } else throw fail(`cssints: style() takes css.* values and token.set(...) results, got ${Formatter.formatJson(a)}`);
474
+ return { __style: {
475
+ sets,
476
+ decls
477
+ } };
478
+ };
479
+ const token = {
480
+ ...Object.fromEntries(Object.keys(TOKEN_TYPES).map((kind) => [kind, make(kind)])),
481
+ set
482
+ };
483
+ //#endregion
484
+ //#region src/theme.ts
485
+ const accessOf = (key) => /^\d/.test(key) ? `_${key}` : key;
486
+ const SUPPORTED = Object.keys(DTCG_TYPES).join(", ");
487
+ const COLOR_FN = {
488
+ hsl: [1, 2],
489
+ hwb: [1, 2],
490
+ lab: [],
491
+ lch: [],
492
+ oklab: [],
493
+ oklch: []
494
+ };
495
+ const COLOR_SPACES = /* @__PURE__ */ new Set([
496
+ "srgb",
497
+ "srgb-linear",
498
+ "display-p3",
499
+ "a98-rgb",
500
+ "prophoto-rgb",
501
+ "rec2020",
502
+ "xyz-d65",
503
+ "xyz-d50"
504
+ ]);
505
+ const FONT_WEIGHTS = {
506
+ thin: 100,
507
+ hairline: 100,
508
+ "extra-light": 200,
509
+ "ultra-light": 200,
510
+ light: 300,
511
+ normal: 400,
512
+ regular: 400,
513
+ book: 400,
514
+ medium: 500,
515
+ "semi-bold": 600,
516
+ "demi-bold": 600,
517
+ bold: 700,
518
+ "extra-bold": 800,
519
+ "ultra-bold": 800,
520
+ black: 900,
521
+ heavy: 900,
522
+ "extra-black": 950,
523
+ "ultra-black": 950
524
+ };
525
+ const SHADOW = [
526
+ "color",
527
+ "offsetX",
528
+ "offsetY",
529
+ "blur",
530
+ "spread"
531
+ ];
532
+ const UNITS = {
533
+ dimension: ["px", "rem"],
534
+ duration: ["ms", "s"]
535
+ };
536
+ const isNumber = (n) => typeof n === "number" && Number.isFinite(n);
537
+ const isComponent = (n) => isNumber(n) || n === "none";
538
+ const cssOf = Effect.fnUntraced(function* (type, value, what) {
539
+ if (typeof value === "string") {
540
+ const key = value.trim().toLowerCase();
541
+ return type === "fontWeight" && Object.hasOwn(FONT_WEIGHTS, key) ? String(FONT_WEIGHTS[key]) : value.trim();
542
+ }
543
+ if (isNumber(value) && (type === "number" || type === "fontWeight")) return String(value);
544
+ if (Predicate.isObject(value) && type === "color") {
545
+ const { colorSpace: space, components: c, alpha } = value;
546
+ const named = typeof space === "string" ? COLOR_FN[space] : void 0;
547
+ if (!(named || COLOR_SPACES.has(space)) || !Array.isArray(c) || c.length !== 3 || !c.every(isComponent) || alpha !== void 0 && !isNumber(alpha)) return yield* fail(`cssints: ${what} is not a DTCG colour: { colorSpace, components: [3 numbers or "none"], alpha? } with a colorSpace of hsl, hwb, lab, lch, oklab, oklch or ${[...COLOR_SPACES].join(", ")}`);
548
+ const parts = c.map((n, i) => named?.includes(i) && n !== "none" ? `${n}%` : n);
549
+ const a = alpha === void 0 ? "" : ` / ${alpha}`;
550
+ return named ? `${space}(${parts.join(" ")}${a})` : `color(${space} ${parts.join(" ")}${a})`;
551
+ }
552
+ if (type === "cubicBezier") {
553
+ if (!Array.isArray(value) || value.length !== 4 || !value.every(isNumber)) return yield* fail(`cssints: ${what} is not a DTCG cubicBezier: [x1, y1, x2, y2]`);
554
+ return `cubic-bezier(${value.join(", ")})`;
555
+ }
556
+ if (type === "shadow") {
557
+ const layers = Array.isArray(value) ? value : [value];
558
+ const out = [];
559
+ for (const l of layers) {
560
+ if (!Predicate.isObject(l) || SHADOW.some((k) => l[k] === void 0) || l.inset !== void 0 && typeof l.inset !== "boolean") return yield* fail(`cssints: ${what} is not a DTCG shadow: { color, offsetX, offsetY, blur, spread, inset? } or an array of them`);
561
+ const parts = [];
562
+ for (const k of SHADOW.slice(1)) parts.push(yield* cssOf("dimension", l[k], `${what} ${k}`));
563
+ parts.push(yield* cssOf("color", l.color, `${what} color`));
564
+ out.push(`${l.inset ? "inset " : ""}${parts.join(" ")}`);
565
+ }
566
+ return out.join(", ");
567
+ }
568
+ const units = UNITS[type];
569
+ if (Predicate.isObject(value) && units) {
570
+ const { value: n, unit } = value;
571
+ if (!isNumber(n) || typeof unit !== "string" || !units.includes(unit)) return yield* fail(`cssints: ${what} is not a DTCG ${type}: { value: number, unit: ${units.join(" | ")} }`);
572
+ return `${n}${unit}`;
573
+ }
574
+ return yield* fail(`cssints: ${what} is not a DTCG ${type} value: ${Formatter.formatJson(value)}`);
575
+ });
576
+ const PURE = /^var\(--[\w-]+\)$/;
577
+ const sets = /* @__PURE__ */ new WeakMap();
578
+ const ALIAS = /^\{([^{}]+)\}$/;
579
+ const REF = /\{([^{}]+)\}/g;
580
+ const IGNORED = /* @__PURE__ */ new Set([
581
+ "$description",
582
+ "$extensions",
583
+ "$deprecated"
584
+ ]);
585
+ const kebab = (s) => s.replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
586
+ const RECIPE = "see docs/API.md, JSON from Figma";
587
+ const STUDIO_TYPES = {
588
+ spacing: "dimension",
589
+ sizing: "dimension",
590
+ borderRadius: "dimension",
591
+ borderWidth: "dimension",
592
+ fontSizes: "dimension",
593
+ letterSpacing: "dimension",
594
+ paragraphSpacing: "dimension",
595
+ paragraphIndent: "dimension",
596
+ fontWeights: "fontWeight",
597
+ lineHeights: "number",
598
+ opacity: "number",
599
+ boxShadow: "shadow"
600
+ };
601
+ const extensionError = (token, what) => {
602
+ const ext = token["$extensions"];
603
+ if (!Predicate.isObject(ext)) return void 0;
604
+ const studio = ext["studio.tokens"];
605
+ if (Predicate.isObject(studio) && studio["modify"] !== void 0) return `cssints: ${what} has a Tokens Studio colour modifier ($extensions["studio.tokens"].modify), which cssints does not apply: write the colour as CSS (color-mix(), a relative colour) or resolve it with @tokens-studio/sd-transforms first (${RECIPE})`;
606
+ if (ext["com.figma.type"] === "boolean") return `cssints: ${what} is a Figma boolean variable (com.figma.type "boolean"), which has no CSS value: leave it out of the tokens`;
607
+ const figma = ext["com.figma"];
608
+ const modes = ext["mode"] ?? (Predicate.isObject(figma) ? figma["modes"] : void 0);
609
+ if (Predicate.isObject(modes) && Object.keys(modes).length > 1) return `cssints: ${what} has modes in $extensions (${Object.keys(modes).join(", ")}), which createTokens does not read: export one file per mode (TokensBrücke: "Split modes into separate files"; Figma: Export modes) and pass the others to createGlobalTheme (${RECIPE})`;
610
+ };
611
+ const collect = Effect.fnUntraced(function* (node, path, type, out) {
612
+ const here = path.join(".") || "the root";
613
+ const own = node["$type"];
614
+ if (own !== void 0 && typeof own !== "string") return yield* fail(`cssints: createTokens(): $type of ${here} is a string, got ${Formatter.formatJson(own)}`);
615
+ const inherited = own ?? type;
616
+ for (const [key, child] of Object.entries(node)) {
617
+ if (key === "$type" || key === "$value" || IGNORED.has(key)) continue;
618
+ if (key === "$themes" || key === "$metadata") return yield* fail(`cssints: createTokens(): ${key} of ${here} is a Tokens Studio file: convert its token sets to DTCG (${RECIPE})`);
619
+ if (key.startsWith("$")) return yield* fail(`cssints: createTokens(): ${key} of ${here} is not supported (${[
620
+ "$root",
621
+ "$extends",
622
+ "$ref"
623
+ ].join(", ")} are not, $description, $extensions and $deprecated are ignored)`);
624
+ if (/[{}.]/.test(key)) return yield* fail(`cssints: createTokens(): the name "${key}" in ${here} has a { } or . (DTCG names cannot)`);
625
+ const at = [...path, key];
626
+ if (!Predicate.isObject(child)) return yield* fail(`cssints: createTokens(): ${at.join(".")} is a group or a token ({ $value }), got ${Formatter.formatJson(child)}`);
627
+ if (typeof child["type"] === "string" && Object.hasOwn(child, "value")) return yield* fail(`cssints: createTokens(): ${at.join(".")} has value and type without $, the legacy format of Tokens Studio (and of TokensBrücke without "DTCG 2025.10 format"): convert it to DTCG (${RECIPE})`);
628
+ if (Object.hasOwn(child, "$value")) {
629
+ const stray = Object.keys(child).filter((k) => !k.startsWith("$"));
630
+ if (stray.length) return yield* fail(`cssints: createTokens(): ${at.join(".")} has a $value and so is a token; it cannot hold ${stray.join(", ")}`);
631
+ const ext = extensionError(child, `createTokens(): ${at.join(".")}`);
632
+ if (ext) return yield* fail(ext);
633
+ const t = child["$type"] ?? inherited;
634
+ out.push({
635
+ path: at,
636
+ dotted: at.join("."),
637
+ type: t,
638
+ value: child["$value"]
639
+ });
640
+ } else yield* collect(child, at, inherited, out);
641
+ }
642
+ });
643
+ const createTokens = (...args) => edge(Effect.gen(function* () {
644
+ const [tree, mapper] = args;
645
+ if (!registry.at || !Predicate.isObject(tree) || args.length > 2 || mapper !== void 0 && typeof mapper !== "function") return yield* fail("cssints: createTokens(tokens, name?) takes a DTCG-shaped object and an optional function from a path to a name");
646
+ const leaves = [];
647
+ yield* collect(tree, [], void 0, leaves);
648
+ if (!leaves.length) return yield* fail("cssints: createTokens(): the tokens have no leaf ({ $value })");
649
+ const names = /* @__PURE__ */ new Map();
650
+ const read = /* @__PURE__ */ new Map();
651
+ const inherit = /* @__PURE__ */ new Map();
652
+ for (const l of leaves) {
653
+ const given = mapper ? mapper([...l.path]) : l.path.map(kebab).join("-");
654
+ const n = yield* Effect.try({
655
+ try: () => nameOf(given),
656
+ catch: (e) => e
657
+ });
658
+ if (names.has(n.name)) return yield* fail(`cssints: createTokens(): ${names.get(n.name)} and ${l.dotted} are both ${n.name}`);
659
+ names.set(n.name, l.dotted);
660
+ inherit.set(l.dotted, n.inherit);
661
+ const as = l.path.map(accessOf).join(".");
662
+ if (read.has(as)) return yield* fail(`cssints: createTokens(): ${read.get(as)} and ${l.dotted} are both read as t.${as}`);
663
+ read.set(as, l.dotted);
664
+ }
665
+ const variable = new Map([...names].map(([v, dotted]) => [dotted, v]));
666
+ const byPath = new Map(leaves.map((l) => [l.dotted, l]));
667
+ const resolved = /* @__PURE__ */ new Map();
668
+ const resolve = Effect.fnUntraced(function* (leaf, stack) {
669
+ const done = resolved.get(leaf.dotted);
670
+ if (done) return done;
671
+ if (leaf.type !== void 0 && !Object.hasOwn(DTCG_TYPES, leaf.type)) return yield* fail(`cssints: createTokens(): ${leaf.dotted} has $type "${leaf.type}", which has no token type (no @property syntax); supported: ${SUPPORTED}${Object.hasOwn(STUDIO_TYPES, leaf.type) ? ` ("${leaf.type}" is a Tokens Studio type: its DTCG type is "${STUDIO_TYPES[leaf.type]}")` : ""}`);
672
+ const own = leaf.type;
673
+ const [, ref] = (typeof leaf.value === "string" ? ALIAS.exec(leaf.value.trim()) : null) ?? [];
674
+ let r;
675
+ if (ref !== void 0) {
676
+ const target = byPath.get(ref);
677
+ if (!target) return yield* fail(`cssints: createTokens(): ${leaf.dotted} is an alias of {${ref}}, and there is no token at ${ref}${[...byPath.keys()].some((k) => k.startsWith(`${ref}.`)) ? " (it is a group)" : ""}`);
678
+ const chain = [...stack, leaf.dotted];
679
+ if (chain.includes(target.dotted)) return yield* fail(`cssints: createTokens(): aliases go round in a circle: ${[...chain.slice(chain.indexOf(target.dotted)), target.dotted].join(" -> ")}`);
680
+ const t = yield* resolve(target, chain);
681
+ if (own !== void 0 && own !== t.dtcg) return yield* fail(`cssints: createTokens(): ${leaf.dotted} is a ${own}, and its alias {${ref}} is a ${t.dtcg}`);
682
+ r = {
683
+ dtcg: t.dtcg,
684
+ text: t.text,
685
+ alias: target.dotted
686
+ };
687
+ } else if (typeof leaf.value === "string" && leaf.value.includes("{")) {
688
+ if (own === void 0) return yield* fail(`cssints: createTokens(): ${leaf.dotted} is derived from other tokens and has no $type: give it one, or its group`);
689
+ if (/^[^(]*\s[*/+-]\s/.test(leaf.value)) return yield* fail(`cssints: createTokens(): ${leaf.dotted} value "${leaf.value}" is math outside calc() (Tokens Studio math): write "calc(${leaf.value})"`);
690
+ const refs = [];
691
+ for (const [, ref] of leaf.value.matchAll(REF)) {
692
+ const target = byPath.get(ref);
693
+ if (!target) return yield* fail(`cssints: createTokens(): ${leaf.dotted} refers to {${ref}}, and there is no token at ${ref}`);
694
+ const chain = [...stack, leaf.dotted];
695
+ if (chain.includes(target.dotted)) return yield* fail(`cssints: createTokens(): aliases go round in a circle: ${[...chain.slice(chain.indexOf(target.dotted)), target.dotted].join(" -> ")}`);
696
+ yield* resolve(target, chain);
697
+ refs.push(target.dotted);
698
+ }
699
+ r = {
700
+ dtcg: own,
701
+ text: leaf.value.replace(REF, (_, ref) => resolved.get(ref).text),
702
+ refs
703
+ };
704
+ } else {
705
+ if (own === void 0) return yield* fail(`cssints: createTokens(): ${leaf.dotted} has no $type: give it one, or its group (a type is not guessed from the value)`);
706
+ r = {
707
+ dtcg: own,
708
+ text: yield* cssOf(own, leaf.value, leaf.dotted)
709
+ };
710
+ }
711
+ resolved.set(leaf.dotted, r);
712
+ return r;
713
+ });
714
+ const root = {};
715
+ const set = {
716
+ tokens: /* @__PURE__ */ new Map(),
717
+ types: /* @__PURE__ */ new Map(),
718
+ aliases: []
719
+ };
720
+ const live = [];
721
+ const guarded = [];
722
+ for (const l of leaves) {
723
+ const r = yield* resolve(l, []);
724
+ const name = variable.get(l.dotted);
725
+ const kind = DTCG_TYPES[r.dtcg];
726
+ const token = yield* declare(kind, r.text, name, inherit.get(l.dotted), true, `createTokens(): ${l.dotted} value`, !!(r.alias ?? r.refs));
727
+ registry.defs.get(name).path = l.dotted;
728
+ const refs = r.alias === void 0 ? r.refs : [r.alias];
729
+ if (refs) {
730
+ const css = (r.alias === void 0 ? l.value : `{${r.alias}}`).replace(REF, (_, ref) => `var(${variable.get(ref)})`);
731
+ const targets = [...new Set(refs.map((d) => variable.get(d)))];
732
+ set.aliases.push({
733
+ name,
734
+ targets,
735
+ css
736
+ });
737
+ const fb = r.alias === void 0 ? registry.defs.get(name).fallback : void 0;
738
+ live.push(`${name}:${fb ?? css}`);
739
+ const def = registry.defs.get(name);
740
+ if (fb) {
741
+ guarded.push(`@supports ${supportTest(TOKEN_TYPES[kind].syntax, r.text)}{:root{${name}:${css}}}`);
742
+ if (yield* standIn(registry.at, l.dotted, kind, r.text, def.inherit, true)) def.poly = r.text;
743
+ }
744
+ Object.assign(def, {
745
+ template: css,
746
+ refs: targets
747
+ });
748
+ }
749
+ set.tokens.set(l.dotted, token);
750
+ set.types.set(name, r.dtcg);
751
+ let group = root;
752
+ for (const [i, key] of l.path.entries()) {
753
+ const k = accessOf(key);
754
+ if (i === l.path.length - 1) group[k] = token;
755
+ else if (Predicate.isObject(group[k])) group = group[k];
756
+ else {
757
+ const g = group[k] = {};
758
+ sets.set(g, set);
759
+ group = g;
760
+ }
761
+ }
762
+ }
763
+ sets.set(root, set);
764
+ if (live.length) {
765
+ const { file, site } = registry.at;
766
+ const n = registry.tokens++;
767
+ registry.themed.set(`${file}#${site}.${n}`, {
768
+ file,
769
+ key: `0:${file}#${String(site).padStart(6, "0")}.${n}`,
770
+ css: `:root{${live.join(";")}}${guarded.join("")}`,
771
+ names: set.aliases.flatMap((a) => [a.name, ...a.targets])
772
+ });
773
+ }
774
+ return root;
775
+ }));
776
+ const tokensOf = (v) => {
777
+ const set = Predicate.isObject(v) ? sets.get(v) : void 0;
778
+ if (!set) return void 0;
779
+ const text = Formatter.formatJson(v);
780
+ return set.terminal ? text.replaceAll("--", "-\\u002d") : text;
781
+ };
782
+ const DONE = Object.freeze({ __done: true });
783
+ const isDone = (v) => v === DONE;
784
+ const isCondition = (v) => typeof v === "function" && Predicate.hasProperty(v, "__cond") && Predicate.hasProperty(v, "cond");
785
+ const SCOPE = {
786
+ "@media": ":root",
787
+ "@container": ":where(*)"
788
+ };
789
+ const addTheme = (t, at) => Effect.try({
790
+ try: () => theme(at, [
791
+ t.tokens,
792
+ t.selector,
793
+ t.overrides,
794
+ {
795
+ layer: t.layer,
796
+ scope: t.scope
797
+ }
798
+ ]),
799
+ catch: (e) => e
800
+ });
801
+ const createGlobalTheme = (...args) => theme(registry.at, args);
802
+ const theme = (at, args) => edge(Effect.gen(function* () {
803
+ const [tokens, condition, overrides, options] = args;
804
+ const set = Predicate.isObject(tokens) ? sets.get(tokens) : void 0;
805
+ const asked = Predicate.isObject(options) ? options.layer : void 0;
806
+ const layer = typeof asked === "string" ? asked : void 0;
807
+ const wanted = Predicate.isObject(options) ? options.scope : void 0;
808
+ const scope = typeof wanted === "string" ? wanted.trim() : void 0;
809
+ if (!at || !set || args.length < 3 || args.length > 4 || !Predicate.isObject(overrides) || args.length === 4 && (!Predicate.isObject(options) || asked !== void 0 && layer === void 0 || wanted !== void 0 && scope === void 0)) return yield* fail("cssints: createGlobalTheme(tokens, condition | selector, overrides, { layer, scope }?) takes tokens of createTokens, a media() or container() condition or a selector, the values to set, and optionally a declared top-level layer and a selector to scope them to");
810
+ const terminal = registry.defs === registry.terminal?.defs;
811
+ if (!!set.terminal !== terminal) return yield* fail(set.terminal ? `cssints: createGlobalTheme(): these are terminal tokens of "cssints/tui": theme them with the createGlobalTheme of "cssints/tui"` : `cssints: createGlobalTheme(): these are web tokens of "cssints": theme them with the createGlobalTheme of "cssints", or make them with the createTokens of "cssints/tui"`);
812
+ if (layer !== void 0) yield* requireLayer(layer, at);
813
+ if (scope !== void 0) {
814
+ if (typeof condition !== "string") return yield* fail("cssints: createGlobalTheme(): a scope goes with a selector, not a condition");
815
+ yield* checkSelector(scope).pipe(Effect.mapError((e) => new MacroError({
816
+ message: `cssints: createGlobalTheme(): scope: ${e.message}`,
817
+ cause: e,
818
+ ...at
819
+ })));
820
+ }
821
+ let label;
822
+ let block;
823
+ if (typeof condition === "string") {
824
+ label = condition.trim();
825
+ if (!/^[^{};@]+$/.test(label)) return yield* fail(`cssints: createGlobalTheme(): "${condition}" is not a selector`);
826
+ block = (d) => `${label}{${d}}`;
827
+ } else if (isCondition(condition)) {
828
+ label = condition.cond.text;
829
+ const prelude = /^@(media|container)\b/.exec(label)?.[0];
830
+ if (!prelude) return yield* fail(`cssints: createGlobalTheme(): ${label} is not a theme, use a media() or container() condition, or a selector`);
831
+ block = (d) => `${label}{${SCOPE[prelude]}{${d}}}`;
832
+ } else return yield* fail(`cssints: createGlobalTheme(): the second argument is a media() or container() condition or a selector, got ${Formatter.formatJson(condition)}`);
833
+ const changed = /* @__PURE__ */ new Map();
834
+ const defaults = /* @__PURE__ */ new Map();
835
+ const guards = /* @__PURE__ */ new Map();
836
+ const poly = /* @__PURE__ */ new Map();
837
+ const refs = /* @__PURE__ */ new Map();
838
+ const walk = Effect.fnUntraced(function* (node, values, path) {
839
+ for (const [key, given] of Object.entries(values)) {
840
+ if (key.startsWith("$")) continue;
841
+ const leaf = Predicate.isObject(given) && Object.hasOwn(given, "$value");
842
+ const v = leaf ? given["$value"] : given;
843
+ const own = Object.hasOwn(node, key) ? key : accessOf(key);
844
+ const child = Object.hasOwn(node, own) ? node[own] : void 0;
845
+ const dotted = [...path, key].join(".");
846
+ const ext = leaf ? extensionError(given, `createGlobalTheme(): ${dotted}`) : void 0;
847
+ if (ext) return yield* fail(ext);
848
+ if (child instanceof CSSTokenValue) {
849
+ const kind = registry.defs.get(child.name).kind;
850
+ const text = yield* cssOf(set.types.get(child.name), v, dotted);
851
+ const targets = /* @__PURE__ */ new Map();
852
+ for (const [, ref] of text.matchAll(REF)) {
853
+ const target = set.tokens.get(ref);
854
+ if (!target) return yield* fail(`cssints: createGlobalTheme(): ${dotted} refers to {${ref}}, and there is no token at ${ref}`);
855
+ targets.set(ref, target);
856
+ }
857
+ const whole = ALIAS.exec(text)?.[1];
858
+ const other = whole && registry.defs.get(targets.get(whole).name).kind;
859
+ if (other && other !== kind) return yield* fail(`cssints: createGlobalTheme(): ${dotted} is a ${kind}, and its reference {${whole}} is a ${other}`);
860
+ const literal = text.replace(REF, (_, r) => registry.defs.get(targets.get(r).name).value);
861
+ const css = text.replace(REF, (_, r) => `var(${targets.get(r).name})`);
862
+ const fb = yield* checkSyntaxFx(`createGlobalTheme(): ${dotted} value`, TOKEN_TYPES[kind].syntax, literal, `createGlobalTheme(): ${dotted} value in ${label}`, child.name);
863
+ if (fb && css !== literal && !PURE.test(css)) {
864
+ const test = supportTest(TOKEN_TYPES[kind].syntax, literal);
865
+ guards.set(test, [...guards.get(test) ?? [], `${child.name}:${css}`]);
866
+ defaults.set(child.name, fb);
867
+ const { inherit } = registry.defs.get(child.name);
868
+ if (yield* standIn(at, `${dotted} in ${label}`, kind, literal, inherit, !label.startsWith("@container"))) poly.set(child.name, literal);
869
+ }
870
+ changed.set(child.name, css);
871
+ if (targets.size) refs.set(child.name, [...targets.values()].map((t) => t.name));
872
+ } else if (Predicate.isObject(child) && Predicate.isObject(v)) yield* walk(child, v, [...path, key]);
873
+ else return yield* fail(child === void 0 ? `cssints: createGlobalTheme(): there is no token at ${dotted}` : `cssints: createGlobalTheme(): ${dotted} is a group, its values are an object`);
874
+ }
875
+ });
876
+ yield* walk(tokens, overrides, []);
877
+ if (!changed.size) return yield* fail("cssints: createGlobalTheme(): the theme sets no token");
878
+ const deps = (n) => refs.get(n) ?? set.aliases.find((a) => a.name === n)?.targets ?? [];
879
+ const done = /* @__PURE__ */ new Set();
880
+ const visit = (n, stack) => {
881
+ if (stack.includes(n)) return [...stack.slice(stack.indexOf(n)), n];
882
+ if (done.has(n)) return void 0;
883
+ for (const d of deps(n)) {
884
+ const circle = visit(d, [...stack, n]);
885
+ if (circle) return circle;
886
+ }
887
+ done.add(n);
888
+ };
889
+ for (const n of refs.keys()) {
890
+ const circle = visit(n, []);
891
+ if (circle) return yield* fail(`cssints: createGlobalTheme(): references go round in a circle: ${circle.map((c) => registry.defs.get(c).path).join(" -> ")}`);
892
+ }
893
+ const stale = new Set(changed.keys());
894
+ for (let grew = true; grew;) grew = set.aliases.some((a) => a.targets.some((t) => stale.has(t)) && !stale.has(a.name) && !!stale.add(a.name));
895
+ const decls = [...[...changed].map(([name, text]) => `${name}:${defaults.get(name) ?? text}`), ...set.aliases.filter((a) => stale.has(a.name) && !changed.has(a.name)).map((a) => `${a.name}:${a.css}`)];
896
+ const n = registry.tokens++;
897
+ const rules = block(decls.join(";")) + [...guards].map(([test, live]) => `@supports ${test}{${block(live.join(";"))}}`).join("");
898
+ registry.themed.set(`${at.file}#${at.site}.${n}`, {
899
+ file: at.file,
900
+ key: `${typeof condition === "string" ? 2 : 1}:${at.file}#${String(at.site).padStart(6, "0")}.${n}`,
901
+ css: scope === void 0 ? rules : `@scope (${scope}){${rules}}`,
902
+ names: decls.map((d) => d.slice(0, d.indexOf(":"))),
903
+ ...layer === void 0 ? {} : { layer },
904
+ theme: {
905
+ label,
906
+ scope,
907
+ values: changed,
908
+ poly: poly.size ? poly : void 0
909
+ }
910
+ });
911
+ return DONE;
912
+ }));
913
+ const contrast = (...args) => edge(Effect.gen(function* () {
914
+ const [fg, bg, options] = args;
915
+ const min = options?.min;
916
+ const at = registry.at;
917
+ if (!at || args.length !== 3 || !(fg instanceof CSSTokenValue) || !(bg instanceof CSSTokenValue) || fg.syntax !== "color" || bg.syntax !== "color" || typeof min !== "number" || !(min >= 1 && min <= 21)) return yield* fail("cssints: check.contrast(fg, bg, { min }) takes two colour tokens and a minimum ratio from 1 to 21");
918
+ registry.checks.set(`${at.file}#${at.site}.${registry.tokens++}`, {
919
+ at,
920
+ fg: fg.name,
921
+ bg: bg.name,
922
+ min,
923
+ gen: registry.gen
924
+ });
925
+ return DONE;
926
+ }));
927
+ const check = { contrast };
928
+ //#endregion
929
+ export { camel as A, hashClass as C, settled as D, minWidth as E, probed as F, failIn as M, isNode as N, toDecls as O, node as P, edge as S, merged as T, PSEUDOS as _, createTokens as a, checkVars as b, tokensOf as c, style as d, token as f, PROPS as g, LAYER as h, createGlobalTheme as i, fail as j, VAR as k, CSSTokenValue as l, FUNCTIONS as m, addTheme as n, isDone as o, CONTEXTS as p, check as r, sets as s, DONE as t, isStyle as u, carried as v, isFallback as w, dropsOf as x, chainDecl as y };