@master/css-runtime 0.0.0-site.1793659883.g69c9aebcf628

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.
package/dist/index.js ADDED
@@ -0,0 +1,1723 @@
1
+ import { MASTER_CSS_DIAGNOSTIC_VERSION, MasterCSSError } from "@master/css-schema";
2
+ import { MASTER_CSS_RUNTIME_STYLE_ID } from "@master/css-schema/runtime-style";
3
+ import { MASTER_CSS_HYDRATION_MANIFEST_ATTR, MASTER_CSS_HYDRATION_MANIFEST_SCRIPT_ID } from "@master/css-schema/hydration-manifest";
4
+ // src/class-tracker.ts
5
+ function isElement(node) {
6
+ return node.nodeType === 1;
7
+ }
8
+ function updateClassDelta(deltaCounts, className, delta) {
9
+ const nextDelta = (deltaCounts.get(className) || 0) + delta;
10
+ if (nextDelta) deltaCounts.set(className, nextDelta);
11
+ else deltaCounts.delete(className);
12
+ }
13
+ function traverseElementSubtree(root, visited, callback) {
14
+ const stack = [root];
15
+ while (stack.length) {
16
+ const el = stack.pop();
17
+ if (visited.has(el)) continue;
18
+ visited.add(el);
19
+ callback(el);
20
+ for (let child = el.lastElementChild; child; child = child.previousElementSibling) stack.push(child);
21
+ }
22
+ }
23
+ var RuntimeClassTracker = class {
24
+ snapshots = /* @__PURE__ */ new WeakMap();
25
+ reset() {
26
+ this.snapshots = /* @__PURE__ */ new WeakMap();
27
+ }
28
+ collectConnected(root, classCounts) {
29
+ this.reset();
30
+ const connectedNames = /* @__PURE__ */ new Set();
31
+ for (const el of root.querySelectorAll("[class]")) {
32
+ const classNames = this.snapshotElement(el);
33
+ if (!classNames) continue;
34
+ for (const className of classNames) {
35
+ const count = classCounts.get(className) || 0;
36
+ if (!count) connectedNames.add(className);
37
+ classCounts.set(className, count + 1);
38
+ }
39
+ }
40
+ return connectedNames;
41
+ }
42
+ collectMutations(records, root) {
43
+ const deltaCounts = /* @__PURE__ */ new Map();
44
+ const nodeCounts = /* @__PURE__ */ new Map();
45
+ const attrRecords = /* @__PURE__ */ new Set();
46
+ const visited = /* @__PURE__ */ new WeakSet();
47
+ const belongsToRoot = (node) => node.getRootNode() === root;
48
+ const updateNodeCount = (el, delta) => {
49
+ const nextCount = (nodeCounts.get(el) || 0) + delta;
50
+ if (nextCount) nodeCounts.set(el, nextCount);
51
+ else nodeCounts.delete(el);
52
+ };
53
+ for (const record of records) if (record.type === "childList") {
54
+ for (const node of record.addedNodes) if (isElement(node) && belongsToRoot(node)) updateNodeCount(node, 1);
55
+ for (const node of record.removedNodes) if (isElement(node) && !belongsToRoot(node)) updateNodeCount(node, -1);
56
+ } else if (record.type === "attributes" && record.attributeName === "class") {
57
+ const target = record.target;
58
+ if (isElement(target)) attrRecords.add(target);
59
+ }
60
+ for (const [node, count] of nodeCounts) if (count > 0) traverseElementSubtree(node, visited, (el) => this.diffElement(el, deltaCounts));
61
+ else if (count < 0 && !belongsToRoot(node)) traverseElementSubtree(node, visited, (el) => this.removeElement(el, deltaCounts));
62
+ for (const el of attrRecords) {
63
+ if (visited.has(el)) continue;
64
+ if (belongsToRoot(el)) this.diffElement(el, deltaCounts);
65
+ else this.removeElement(el, deltaCounts);
66
+ }
67
+ return deltaCounts;
68
+ }
69
+ snapshotElement(el) {
70
+ const classList = el.classList;
71
+ if (!classList.length) {
72
+ this.snapshots.delete(el);
73
+ return;
74
+ }
75
+ const classNames = /* @__PURE__ */ new Set();
76
+ for (let i = 0; i < classList.length; i++) classNames.add(classList.item(i));
77
+ this.snapshots.set(el, classNames);
78
+ return classNames;
79
+ }
80
+ diffElement(el, deltaCounts) {
81
+ const previousClassNames = this.snapshots.get(el);
82
+ const classList = el.classList;
83
+ let nextClassNames;
84
+ for (let i = 0; i < classList.length; i++) {
85
+ const className = classList.item(i);
86
+ if (!previousClassNames?.has(className)) updateClassDelta(deltaCounts, className, 1);
87
+ (nextClassNames ??= /* @__PURE__ */ new Set()).add(className);
88
+ }
89
+ if (previousClassNames) {
90
+ for (const className of previousClassNames) if (!nextClassNames?.has(className)) updateClassDelta(deltaCounts, className, -1);
91
+ }
92
+ if (nextClassNames) this.snapshots.set(el, nextClassNames);
93
+ else this.snapshots.delete(el);
94
+ }
95
+ removeElement(el, deltaCounts) {
96
+ const previousClassNames = this.snapshots.get(el);
97
+ if (!previousClassNames) return;
98
+ for (const className of previousClassNames) updateClassDelta(deltaCounts, className, -1);
99
+ this.snapshots.delete(el);
100
+ }
101
+ };
102
+ // src/debuggers/log.ts
103
+ const createLogger = (type) => {
104
+ return (message, ...args) => {
105
+ if (!type) return console.log(message, ...args);
106
+ if (console[type]) console[type](`%c[Master CSS]%c ${message}`, "color: gray;", "color: inherit;", ...args);
107
+ };
108
+ };
109
+ const loggers = {
110
+ info: createLogger("info"),
111
+ debug: createLogger("debug"),
112
+ warn: console.warn,
113
+ error: console.error,
114
+ trace: console.trace,
115
+ table: console.table,
116
+ group: console.group,
117
+ groupCollapsed: console.group,
118
+ groupEnd: console.groupEnd,
119
+ time: console.time,
120
+ timeEnd: console.timeEnd
121
+ };
122
+ const log = createLogger();
123
+ Object.assign(log, loggers);
124
+ // src/debuggers/class-count.ts
125
+ function debugRuntimeMutation(records, classCounts, root, host, snapshot) {
126
+ const actualClassCounts = {};
127
+ let errored = false;
128
+ const resolveClass = (className) => {
129
+ if (Object.prototype.hasOwnProperty.call(actualClassCounts, className)) actualClassCounts[className]++;
130
+ else actualClassCounts[className] = 1;
131
+ };
132
+ (root.constructor.name === "HTMLDocument" ? host : root).querySelectorAll("[class]").forEach((element) => {
133
+ element.classList.forEach(resolveClass);
134
+ });
135
+ host.classList.forEach(resolveClass);
136
+ for (const className in actualClassCounts) {
137
+ const eachCount = snapshot.usageCounts[className];
138
+ const eachActualCount = actualClassCounts[className];
139
+ if (eachCount !== eachActualCount) {
140
+ log.error(`Class count mismatch for \`${className}\` (expected ${eachActualCount}) (received ${eachCount})`);
141
+ errored = true;
142
+ }
143
+ }
144
+ for (const [className, eachCount] of Object.entries(snapshot.usageCounts)) if (!Object.prototype.hasOwnProperty.call(actualClassCounts, className)) {
145
+ log.error(`Class count mismatch for \`${className}\` (expected 0) (received ${eachCount})`);
146
+ errored = true;
147
+ }
148
+ if (errored) {
149
+ log.debug("Records:", records);
150
+ log.debug("Serialized Records:", serializeMutations(records));
151
+ log.debug("Counts:", classCounts);
152
+ }
153
+ }
154
+ function serializeMutations(mutations) {
155
+ return mutations.map((m) => {
156
+ const target = m.target;
157
+ return {
158
+ type: m.type,
159
+ attributeName: m.attributeName,
160
+ oldValue: m.oldValue,
161
+ target: {
162
+ tagName: target.tagName,
163
+ id: target.id,
164
+ classList: Array.from(target.classList)
165
+ },
166
+ added: Array.from(m.addedNodes).filter((n) => n.nodeType === 1).map((el) => ({
167
+ tagName: el.tagName,
168
+ id: el.id,
169
+ classList: Array.from(el.classList)
170
+ })),
171
+ removed: Array.from(m.removedNodes).filter((n) => n.nodeType === 1).map((el) => ({
172
+ tagName: el.tagName,
173
+ id: el.id,
174
+ classList: Array.from(el.classList)
175
+ }))
176
+ };
177
+ });
178
+ }
179
+ // src/debuggers/lifecycle.ts
180
+ function debugRuntimeCreated(cssRuntime) {
181
+ log.debug("created", cssRuntime);
182
+ }
183
+ function debugRuntimeHydrated(cssRuntime, result) {
184
+ log.debug("hydrated", cssRuntime, result);
185
+ }
186
+ function debugRuntimeObserved(cssRuntime) {
187
+ log.debug("observed", cssRuntime);
188
+ if (cssRuntime.snapshot().hydration.state === "progressive") {
189
+ log.info("Progressive rendering is adopted.");
190
+ log.debug("pre-rendered CSS", cssRuntime.snapshot().cssText);
191
+ } else log.info("Runtime rendering is adopted.");
192
+ }
193
+ function debugRuntimeRefreshed(cssRuntime, program) {
194
+ log.debug("refreshed", cssRuntime, program);
195
+ }
196
+ function debugRuntimeDisconnected(cssRuntime) {
197
+ log.debug("disconnected", cssRuntime);
198
+ }
199
+ function debugRuntimeDestroyed(cssRuntime) {
200
+ log.debug("destroyed", cssRuntime);
201
+ }
202
+ // src/generated-rule.ts
203
+ var HydratedGeneratedRuleNode = class {
204
+ text;
205
+ native;
206
+ constructor(text) {
207
+ this.text = text;
208
+ }
209
+ };
210
+ var HydratedGeneratedRule = class {
211
+ ir;
212
+ layer;
213
+ native;
214
+ nativeNodeCount;
215
+ name;
216
+ key;
217
+ layerName;
218
+ type;
219
+ sortTier;
220
+ priority;
221
+ text;
222
+ valid = true;
223
+ fixedClass;
224
+ nodeCount;
225
+ nodes;
226
+ variableNames;
227
+ selectorText;
228
+ constructor(ir, layer) {
229
+ this.ir = ir;
230
+ this.layer = layer;
231
+ this.nodeCount = ir.nodes?.length || 1;
232
+ this.name = ir.className;
233
+ this.key = ir.key;
234
+ this.layerName = ir.layer;
235
+ this.type = ir.type;
236
+ this.sortTier = ir.sortTier;
237
+ this.priority = ir.priority;
238
+ this.text = ir.text;
239
+ this.selectorText = ir.selectorText;
240
+ if (ir.nodes?.length) this.nodes = ir.nodes.map((node) => new HydratedGeneratedRuleNode(node.text));
241
+ if (ir.variableNames?.length) this.variableNames = new Set(ir.variableNames);
242
+ }
243
+ };
244
+ // src/register-global.ts
245
+ function registerGlobal(Runtime) {
246
+ if (!globalThis.MasterCSSRuntime) globalThis.MasterCSSRuntime = Runtime;
247
+ }
248
+ // src/keyframe-host.ts
249
+ const isKeyframesRule = (rule) => rule.constructor.name === "CSSKeyframesRule" || rule.constructor.name === "WebKitCSSKeyframesRule";
250
+ /**
251
+ * Places the keyframes the engine emits in the runtime stylesheet, after its layers
252
+ * and wrapped in the containers each definition was declared in.
253
+ */
254
+ var KeyframeHost = class {
255
+ sheet;
256
+ definitions;
257
+ containers = /* @__PURE__ */ new Map();
258
+ order = /* @__PURE__ */ new Map();
259
+ constructor(sheet, definitions) {
260
+ this.sheet = sheet;
261
+ this.definitions = definitions;
262
+ }
263
+ reset() {
264
+ this.containers.clear();
265
+ this.order.clear();
266
+ }
267
+ definition(id) {
268
+ return this.definitions().find((definition) => definition.id === id);
269
+ }
270
+ insertionIndex(parent, order) {
271
+ const next = [...parent.cssRules].findIndex((rule) => (this.order.get(rule) ?? -1) > order);
272
+ return next < 0 ? parent.cssRules.length : next;
273
+ }
274
+ parent(definition, order) {
275
+ let parent = this.sheet();
276
+ if (!parent) return;
277
+ for (const container of definition.containers || []) {
278
+ let native = this.containers.get(container.id);
279
+ if (!native) {
280
+ const index = parent.insertRule(`${container.prelude}{}`, this.insertionIndex(parent, order));
281
+ native = parent.cssRules[index];
282
+ this.containers.set(container.id, native);
283
+ this.order.set(native, order);
284
+ }
285
+ parent = native;
286
+ }
287
+ return parent;
288
+ }
289
+ insert(id, text) {
290
+ const definition = this.definition(id);
291
+ if (!definition) return;
292
+ const order = this.definitions().indexOf(definition);
293
+ const parent = this.parent(definition, order);
294
+ if (!parent) return;
295
+ const index = parent.insertRule(text, this.insertionIndex(parent, order));
296
+ const native = parent.cssRules[index];
297
+ this.order.set(native, order);
298
+ return native;
299
+ }
300
+ contains(native) {
301
+ if (!native || native.parentStyleSheet !== this.sheet()) return false;
302
+ const parent = native.parentRule || native.parentStyleSheet;
303
+ return !!parent && [...parent.cssRules].includes(native);
304
+ }
305
+ remove(native) {
306
+ if (!native) return;
307
+ const parent = native.parentRule || native.parentStyleSheet;
308
+ if (!parent) return;
309
+ const index = [...parent.cssRules].indexOf(native);
310
+ if (index >= 0) parent.deleteRule(index);
311
+ this.order.delete(native);
312
+ }
313
+ /** Claims the pre-rendered rule of `id`, with its containers, from the runtime stylesheet. */
314
+ adopt(id, claimed) {
315
+ const definition = this.definition(id);
316
+ const sheet = this.sheet();
317
+ if (!definition || !sheet) return;
318
+ const candidates = [];
319
+ const walk = (parent) => {
320
+ for (const rule of parent.cssRules) if (isKeyframesRule(rule)) {
321
+ if (rule.name === definition.name && !claimed.has(rule)) candidates.push(rule);
322
+ } else if ("cssRules" in rule) walk(rule);
323
+ };
324
+ walk(sheet);
325
+ const native = candidates[0];
326
+ if (!native) return;
327
+ claimed.add(native);
328
+ const order = this.definitions().indexOf(definition);
329
+ this.order.set(native, order);
330
+ let parent = native.parentRule;
331
+ for (const container of [...definition.containers || []].reverse()) {
332
+ if (!parent || !("cssRules" in parent)) break;
333
+ this.containers.set(container.id, parent);
334
+ this.order.set(parent, order);
335
+ parent = parent.parentRule;
336
+ }
337
+ return native;
338
+ }
339
+ };
340
+ // src/layer.ts
341
+ function getRuleNodeCount(rule) {
342
+ return rule.nativeNodeCount ?? ("nodeCount" in rule ? rule.nodeCount : 1);
343
+ }
344
+ var RuntimeLayer = class {
345
+ name;
346
+ insertRule;
347
+ deleteRule;
348
+ rules = [];
349
+ tokenCounts = /* @__PURE__ */ new Map();
350
+ byKey = /* @__PURE__ */ new Map();
351
+ offsets;
352
+ nodeCount = 0;
353
+ native = null;
354
+ constructor(name, insertRule, deleteRule) {
355
+ this.name = name;
356
+ this.insertRule = insertRule;
357
+ this.deleteRule = deleteRule;
358
+ }
359
+ get text() {
360
+ return this.rules.length ? `@layer ${this.name}{${this.rules.map(({ text }) => text).join("")}}` : "";
361
+ }
362
+ get(key) {
363
+ return this.byKey.get(key);
364
+ }
365
+ /** Single-node layers and tail operations need no prefix traversal. */
366
+ nativeIndex(index) {
367
+ return index === this.rules.length ? this.nodeCount : this.offsets?.[index] ?? index;
368
+ }
369
+ track(rule, index) {
370
+ const count = getRuleNodeCount(rule);
371
+ const nativeIndex = this.nativeIndex(index);
372
+ if (count !== 1) this.offsets ??= Array.from({ length: this.rules.length }, (_, index) => index);
373
+ if (this.offsets) {
374
+ this.offsets.splice(index, 0, nativeIndex);
375
+ for (let next = index + 1; next < this.offsets.length; next++) this.offsets[next] += count;
376
+ }
377
+ this.nodeCount += count;
378
+ this.rules.splice(index, 0, rule);
379
+ this.byKey.set(rule.key, rule);
380
+ return nativeIndex;
381
+ }
382
+ /** Track an already hydrated rule without mutating the stylesheet. */
383
+ adopt(rule) {
384
+ if (!this.byKey.has(rule.key)) this.track(rule, this.rules.length);
385
+ }
386
+ insert(rule, index = this.rules.length) {
387
+ if (this.byKey.has(rule.key)) return;
388
+ const boundedIndex = Math.max(0, Math.min(index, this.rules.length));
389
+ const nativeIndex = this.nativeIndex(boundedIndex);
390
+ this.insertRule(this, rule, nativeIndex);
391
+ this.track(rule, boundedIndex);
392
+ return boundedIndex;
393
+ }
394
+ delete(key, index) {
395
+ const rule = this.byKey.get(key);
396
+ if (!rule) return;
397
+ const foundIndex = index !== void 0 && this.rules[index] === rule ? index : this.rules.indexOf(rule);
398
+ const nativeIndex = this.nativeIndex(foundIndex);
399
+ const count = getRuleNodeCount(rule);
400
+ this.rules.splice(foundIndex, 1);
401
+ this.byKey.delete(key);
402
+ this.nodeCount -= count;
403
+ if (this.nodeCount === this.rules.length) this.offsets = void 0;
404
+ if (this.offsets) {
405
+ this.offsets.splice(foundIndex, 1);
406
+ for (let next = foundIndex; next < this.offsets.length; next++) this.offsets[next] -= count;
407
+ }
408
+ this.deleteRule(this, rule, nativeIndex);
409
+ return rule;
410
+ }
411
+ clearRules() {
412
+ this.rules.length = 0;
413
+ this.byKey.clear();
414
+ this.offsets = void 0;
415
+ this.nodeCount = 0;
416
+ }
417
+ reset() {
418
+ this.clearRules();
419
+ this.tokenCounts.clear();
420
+ this.native = null;
421
+ }
422
+ };
423
+ // src/theme-layer.ts
424
+ var RuntimeThemeLayer = class extends RuntimeLayer {
425
+ resourceText = "";
426
+ get text() {
427
+ return this.resourceText ? `@layer theme{${this.resourceText}}` : "";
428
+ }
429
+ reset() {
430
+ super.reset();
431
+ this.resourceText = "";
432
+ }
433
+ };
434
+ // src/utility-layer.ts
435
+ /**
436
+ * CSSOM host state for one generated utility layer. Class matching, ordering,
437
+ * resources, and lifecycle are owned by the Rust engine session.
438
+ */
439
+ var RuntimeUtilityLayer = class extends RuntimeLayer {};
440
+ // src/hydration.ts
441
+ function isDocumentRoot(root) {
442
+ const rootConstructorName = root?.constructor.name;
443
+ return rootConstructorName === "HTMLDocument" || rootConstructorName === "Document";
444
+ }
445
+ function findElementById(root, id) {
446
+ return isDocumentRoot(root) ? root.getElementById(id) : root.querySelector(`#${id}`);
447
+ }
448
+ function getRootHost(root) {
449
+ return isDocumentRoot(root) ? root.documentElement : root.host;
450
+ }
451
+ /** Classes the server rendered, so the progressive stylesheet already holds their CSS, if any. */
452
+ function getRenderedClassNames(hydrationManifest) {
453
+ return new Set(hydrationManifest?.classNames);
454
+ }
455
+ function validateHydrationManifest(hydrationManifest) {
456
+ const candidate = hydrationManifest;
457
+ return candidate?.version === 5 && candidate.languageVersion === 18 && Array.isArray(candidate.classNames) && candidate.classNames.every((className) => typeof className === "string") && Array.isArray(candidate.resourceOrder?.variables) && Array.isArray(candidate.resourceOrder?.keyframes) ? candidate : void 0;
458
+ }
459
+ function invalidHydrationManifest(message, cause) {
460
+ return new MasterCSSError({
461
+ code: "INVALID_HYDRATION_MANIFEST",
462
+ domain: "runtime",
463
+ message
464
+ }, { cause });
465
+ }
466
+ function parseHydrationManifest(source) {
467
+ try {
468
+ const hydrationManifest = validateHydrationManifest(JSON.parse(source));
469
+ if (hydrationManifest) return hydrationManifest;
470
+ } catch (cause) {
471
+ throw invalidHydrationManifest("Cannot parse the Master CSS hydration manifest.", cause);
472
+ }
473
+ throw invalidHydrationManifest("Unsupported Master CSS hydration manifest. Expected version 5 and languageVersion 18. Recompile with matching packages.");
474
+ }
475
+ function readInlineHydrationManifest(root) {
476
+ const source = findElementById(root, MASTER_CSS_HYDRATION_MANIFEST_SCRIPT_ID)?.textContent?.trim();
477
+ return source ? parseHydrationManifest(source) : void 0;
478
+ }
479
+ function readExternalHydrationManifestSource(root) {
480
+ return findElementById(root, MASTER_CSS_RUNTIME_STYLE_ID)?.getAttribute(MASTER_CSS_HYDRATION_MANIFEST_ATTR) || void 0;
481
+ }
482
+ function resolveExternalHydrationManifestURL(root, source) {
483
+ const ownerDocument = isDocumentRoot(root) ? root : root.ownerDocument;
484
+ return new URL(source, ownerDocument.baseURI).href;
485
+ }
486
+ async function importHydrationManifest(url) {
487
+ try {
488
+ const value = (await import(
489
+ /* @vite-ignore */
490
+ /* webpackIgnore: true */
491
+ url,
492
+ { with: { type: "json" } }
493
+ )).default;
494
+ const hydrationManifest = validateHydrationManifest(value);
495
+ if (hydrationManifest) return hydrationManifest;
496
+ throw invalidHydrationManifest(`Invalid Master CSS hydration manifest loaded from ${url}.`);
497
+ } catch (cause) {
498
+ if (cause instanceof MasterCSSError) throw cause;
499
+ throw invalidHydrationManifest(`Cannot load the Master CSS hydration manifest from ${url}.`, cause);
500
+ }
501
+ }
502
+ async function resolveHydrationManifest$1(root, explicit) {
503
+ if (explicit !== void 0) {
504
+ const hydrationManifest = validateHydrationManifest(explicit);
505
+ if (!hydrationManifest) throw invalidHydrationManifest("Unsupported Master CSS hydration manifest. Expected version 5 and languageVersion 18. Recompile with matching packages.");
506
+ return hydrationManifest;
507
+ }
508
+ const inline = readInlineHydrationManifest(root);
509
+ if (inline) return inline;
510
+ const source = readExternalHydrationManifestSource(root);
511
+ return source ? await importHydrationManifest(resolveExternalHydrationManifestURL(root, source)) : void 0;
512
+ }
513
+ // src/host.ts
514
+ const LAYER_ORDER = [
515
+ "theme",
516
+ "base",
517
+ "defaults",
518
+ "components",
519
+ "utilities"
520
+ ];
521
+ function isLayerBlockRule(rule) {
522
+ return rule.constructor.name === "CSSLayerBlockRule";
523
+ }
524
+ function getGeneratedRuleNodeTexts(rule) {
525
+ const nodes = "nodes" in rule ? rule.nodes : void 0;
526
+ return nodes?.length ? nodes.map(({ text }) => text) : [rule.text];
527
+ }
528
+ function cloneEmittedGlobals(emittedGlobals) {
529
+ return {
530
+ variables: { ...emittedGlobals?.variables || {} },
531
+ keyframes: { ...emittedGlobals?.keyframes || {} }
532
+ };
533
+ }
534
+ function addEmittedGlobals(target, source) {
535
+ for (const kind of ["variables", "keyframes"]) for (const [name, count] of Object.entries(source[kind] || {})) if (count) target[kind][name] = Math.min(4294967295, (target[kind][name] || 0) + count);
536
+ }
537
+ function missingEmittedGlobals(current, source) {
538
+ const missing = cloneEmittedGlobals();
539
+ let found = false;
540
+ for (const kind of ["variables", "keyframes"]) for (const [name, count] of Object.entries(source[kind] || {})) if (count && !current[kind][name]) {
541
+ missing[kind][name] = count;
542
+ found = true;
543
+ }
544
+ return found ? missing : void 0;
545
+ }
546
+ var RuntimeHost = class {
547
+ root;
548
+ hydrationManifest;
549
+ host;
550
+ container;
551
+ insertRuntimeLayerRule = (layer, rule, nativeIndex) => this.insertLayerRule(layer, rule, nativeIndex);
552
+ deleteRuntimeLayerRule = (layer, rule, nativeIndex) => this.deleteLayerRule(layer, rule, nativeIndex);
553
+ baseLayer = new RuntimeUtilityLayer("base", this.insertRuntimeLayerRule, this.deleteRuntimeLayerRule);
554
+ themeLayer = new RuntimeThemeLayer("theme", this.insertRuntimeLayerRule, this.deleteRuntimeLayerRule);
555
+ defaultsLayer = new RuntimeUtilityLayer("defaults", this.insertRuntimeLayerRule, this.deleteRuntimeLayerRule);
556
+ componentsLayer = new RuntimeUtilityLayer("components", this.insertRuntimeLayerRule, this.deleteRuntimeLayerRule);
557
+ utilitiesLayer = new RuntimeUtilityLayer("utilities", this.insertRuntimeLayerRule, this.deleteRuntimeLayerRule);
558
+ keyframeHost;
559
+ keyframes = new RuntimeLayer("keyframes", (_layer, rule) => {
560
+ rule.nativeNodeCount = 0;
561
+ try {
562
+ rule.native = this.keyframeHost.insert(rule.key, rule.text);
563
+ rule.nativeNodeCount = rule.native ? 1 : 0;
564
+ } catch (error) {
565
+ console.error(error, rule);
566
+ }
567
+ }, (_layer, rule) => this.keyframeHost.remove(rule.native));
568
+ classUtilities = /* @__PURE__ */ new Map();
569
+ ruleClasses = /* @__PURE__ */ new Map();
570
+ emittedGlobals;
571
+ /** Set when the engine starts; progressive pages defer both. */
572
+ keyframeDefinitions = [];
573
+ bindingEngine;
574
+ style = null;
575
+ progressive = false;
576
+ hydrationFailureReason;
577
+ get rules() {
578
+ return LAYER_ORDER.map((name) => this.getLayerByName(name)).filter((layer) => Boolean(layer?.text));
579
+ }
580
+ constructor(root, emittedGlobals, hydrationManifest) {
581
+ this.root = root;
582
+ this.hydrationManifest = hydrationManifest;
583
+ this.keyframeHost = new KeyframeHost(() => this.getStyleSheet(), () => this.keyframeDefinitions);
584
+ this.emittedGlobals = cloneEmittedGlobals(emittedGlobals);
585
+ this.host = isDocumentRoot(root) ? root.documentElement : root.host;
586
+ this.container = isDocumentRoot(root) ? root.head : root;
587
+ this.resetResourceCounts();
588
+ }
589
+ /** Rule and resource changes run only after the engine starts. */
590
+ get engine() {
591
+ if (!this.bindingEngine) throw new MasterCSSError({
592
+ code: "INTERNAL",
593
+ domain: "runtime",
594
+ message: "The Master CSS engine has not started."
595
+ });
596
+ return this.bindingEngine;
597
+ }
598
+ registerEmittedGlobals(emittedGlobals) {
599
+ if (!emittedGlobals) return;
600
+ const transition = this.bindingEngine?.registerEmittedGlobals(emittedGlobals);
601
+ addEmittedGlobals(this.emittedGlobals, emittedGlobals);
602
+ if (transition) this.applyTransition(transition);
603
+ }
604
+ /** Count resources another host emitted without changing rendered CSS; callers adopt a snapshot next. */
605
+ registerMissingEmittedGlobals(emittedGlobals) {
606
+ const missing = emittedGlobals && missingEmittedGlobals(this.emittedGlobals, emittedGlobals);
607
+ if (!missing) return false;
608
+ this.engine.registerEmittedGlobals(missing);
609
+ addEmittedGlobals(this.emittedGlobals, missing);
610
+ return true;
611
+ }
612
+ adoptEmittedGlobals(emittedGlobals) {
613
+ Object.assign(this.emittedGlobals, cloneEmittedGlobals(emittedGlobals));
614
+ }
615
+ replaceEmittedGlobals(emittedGlobals) {
616
+ const transition = this.engine.replaceEmittedGlobals(emittedGlobals);
617
+ Object.assign(this.emittedGlobals, cloneEmittedGlobals(emittedGlobals));
618
+ this.applyTransition(transition);
619
+ }
620
+ setHydrationManifest(hydrationManifest) {
621
+ this.hydrationManifest = hydrationManifest;
622
+ return this;
623
+ }
624
+ getOwnerDocument() {
625
+ return isDocumentRoot(this.root) ? this.root : this.root.ownerDocument;
626
+ }
627
+ createRuntimeStyle() {
628
+ this.style = this.getOwnerDocument().createElement("style");
629
+ this.style.id = MASTER_CSS_RUNTIME_STYLE_ID;
630
+ this.style.setAttribute("blocking", "render");
631
+ this.container.append(this.style);
632
+ }
633
+ getStyleSheet() {
634
+ return this.style?.sheet || void 0;
635
+ }
636
+ findTopLevelRuleIndex(rule) {
637
+ const sheet = this.getStyleSheet();
638
+ if (!sheet) return -1;
639
+ for (let index = 0; index < sheet.cssRules.length; index++) if (sheet.cssRules.item(index) === rule) return index;
640
+ return -1;
641
+ }
642
+ getLayerInsertIndex(name) {
643
+ const sheet = this.getStyleSheet();
644
+ if (!sheet) return 0;
645
+ const rank = LAYER_ORDER.indexOf(name);
646
+ for (let index = 0; index < sheet.cssRules.length; index++) {
647
+ const rule = sheet.cssRules.item(index);
648
+ if (rule.constructor.name === "CSSKeyframesRule") return index;
649
+ if (isLayerBlockRule(rule)) {
650
+ if (LAYER_ORDER.indexOf(rule.name) > rank) return index;
651
+ }
652
+ }
653
+ return sheet.cssRules.length;
654
+ }
655
+ ensureNativeLayer(layer) {
656
+ const sheet = this.getStyleSheet();
657
+ if (!sheet) return;
658
+ if (layer.native?.parentStyleSheet) return layer.native;
659
+ const insertedIndex = sheet.insertRule(`@layer ${layer.name}{}`, this.getLayerInsertIndex(layer.name));
660
+ layer.native = sheet.cssRules.item(insertedIndex);
661
+ return layer.native;
662
+ }
663
+ insertLayerRule(layer, rule, nativeIndex) {
664
+ rule.nativeNodeCount = 0;
665
+ const nativeLayer = this.ensureNativeLayer(layer);
666
+ if (!nativeLayer) return;
667
+ const nodes = "nodes" in rule ? rule.nodes : void 0;
668
+ for (const [nodeIndex, text] of getGeneratedRuleNodeTexts(rule).entries()) try {
669
+ const insertedIndex = nativeLayer.insertRule(text, nativeIndex + rule.nativeNodeCount);
670
+ rule.nativeNodeCount++;
671
+ const native = nativeLayer.cssRules.item(insertedIndex) || void 0;
672
+ if (nodes?.[nodeIndex]) nodes[nodeIndex].native = native;
673
+ else rule.native = native;
674
+ } catch (error) {
675
+ console.error(error, rule);
676
+ }
677
+ }
678
+ deleteLayerRule(layer, rule, nativeIndex) {
679
+ const nativeLayer = layer.native;
680
+ if (!nativeLayer) return;
681
+ for (let count = getRuleNodeCount(rule); count > 0; count--) if (nativeIndex < nativeLayer.cssRules.length) nativeLayer.deleteRule(nativeIndex);
682
+ if (!layer.rules.length) {
683
+ const sheet = this.getStyleSheet();
684
+ const topIndex = this.findTopLevelRuleIndex(nativeLayer);
685
+ if (sheet && topIndex !== -1) sheet.deleteRule(topIndex);
686
+ layer.native = null;
687
+ }
688
+ }
689
+ getLayerByName(name) {
690
+ switch (name) {
691
+ case "theme": return this.themeLayer;
692
+ case "base": return this.baseLayer;
693
+ case "defaults": return this.defaultsLayer;
694
+ case "components": return this.componentsLayer;
695
+ case "utilities": return this.utilitiesLayer;
696
+ }
697
+ }
698
+ getUtilityLayerByName(name) {
699
+ return this.getLayerByName(name);
700
+ }
701
+ getUtilityLayers() {
702
+ return [
703
+ this.baseLayer,
704
+ this.defaultsLayer,
705
+ this.componentsLayer,
706
+ this.utilitiesLayer
707
+ ];
708
+ }
709
+ setThemeResource(text) {
710
+ const sheet = this.getStyleSheet();
711
+ if (sheet && this.themeLayer.native) {
712
+ const index = this.findTopLevelRuleIndex(this.themeLayer.native);
713
+ if (index !== -1) sheet.deleteRule(index);
714
+ }
715
+ this.themeLayer.native = null;
716
+ this.themeLayer.resourceText = text;
717
+ if (sheet && text) {
718
+ const index = sheet.insertRule(`@layer theme{${text}}`, this.getLayerInsertIndex("theme"));
719
+ this.themeLayer.native = sheet.cssRules.item(index);
720
+ }
721
+ }
722
+ clearKeyframeRules() {
723
+ for (const rule of this.keyframes.rules) this.keyframeHost.remove(rule.native);
724
+ }
725
+ /** Places keyframes rules the runtime stylesheet lost or could not take yet. */
726
+ reconcileKeyframeRules() {
727
+ if (!this.bindingEngine) return;
728
+ const claimed = /* @__PURE__ */ new Set();
729
+ for (const rule of this.keyframes.rules) if (this.keyframeHost.contains(rule.native)) claimed.add(rule.native);
730
+ for (const rule of this.keyframes.rules) {
731
+ if (rule.native && claimed.has(rule.native)) continue;
732
+ this.keyframeHost.remove(rule.native);
733
+ rule.native = this.keyframeHost.adopt(rule.key, claimed) || this.keyframeHost.insert(rule.key, rule.text);
734
+ if (rule.native) claimed.add(rule.native);
735
+ rule.nativeNodeCount = rule.native ? 1 : 0;
736
+ }
737
+ }
738
+ resetHostRuleState() {
739
+ this.clearClassReferences();
740
+ this.baseLayer.reset();
741
+ this.themeLayer.reset();
742
+ this.defaultsLayer.reset();
743
+ this.componentsLayer.reset();
744
+ this.utilitiesLayer.reset();
745
+ this.keyframes.reset();
746
+ this.keyframeHost.reset();
747
+ this.resetResourceCounts();
748
+ }
749
+ resetResourceCounts() {
750
+ this.themeLayer.tokenCounts.clear();
751
+ for (const [name, count] of Object.entries(this.emittedGlobals.variables)) if (count) this.themeLayer.tokenCounts.set(name, count);
752
+ }
753
+ syncResourceSnapshot(resources) {
754
+ this.themeLayer.resourceText = resources.themeText || "";
755
+ this.themeLayer.clearRules();
756
+ this.resetResourceCounts();
757
+ for (const { name, refCount } of resources.variables) {
758
+ const rule = {
759
+ key: name,
760
+ name,
761
+ text: ""
762
+ };
763
+ this.themeLayer.adopt(rule);
764
+ if (refCount) this.themeLayer.tokenCounts.set(name, (this.themeLayer.tokenCounts.get(name) || 0) + refCount);
765
+ }
766
+ }
767
+ clearClassReferences() {
768
+ this.classUtilities.clear();
769
+ this.ruleClasses.clear();
770
+ }
771
+ setClassRules(className, rules) {
772
+ const previous = this.classUtilities.get(className);
773
+ if (previous?.length === rules.length && previous.every((rule, index) => rule === rules[index])) return;
774
+ for (const rule of previous || []) {
775
+ const classes = this.ruleClasses.get(rule);
776
+ if (typeof classes === "string") {
777
+ if (classes === className) this.ruleClasses.delete(rule);
778
+ } else if (classes) {
779
+ classes.delete(className);
780
+ if (classes.size === 1) this.ruleClasses.set(rule, classes.values().next().value);
781
+ else if (!classes.size) this.ruleClasses.delete(rule);
782
+ }
783
+ }
784
+ if (!rules.length) {
785
+ this.classUtilities.delete(className);
786
+ return;
787
+ }
788
+ this.classUtilities.set(className, rules);
789
+ for (const rule of rules) {
790
+ const classes = this.ruleClasses.get(rule);
791
+ if (classes === void 0) this.ruleClasses.set(rule, className);
792
+ else if (typeof classes === "string") {
793
+ if (classes !== className) this.ruleClasses.set(rule, /* @__PURE__ */ new Set([classes, className]));
794
+ } else classes.add(className);
795
+ }
796
+ }
797
+ registerClassRule(rule) {
798
+ this.setClassRules(rule.name, [...this.classUtilities.get(rule.name) || [], rule]);
799
+ }
800
+ unregisterLayerRule(rule) {
801
+ if (!(rule instanceof HydratedGeneratedRule)) return;
802
+ const classes = this.ruleClasses.get(rule);
803
+ if (!classes) return;
804
+ this.ruleClasses.delete(rule);
805
+ for (const className of typeof classes === "string" ? [classes] : classes) this.setClassRules(className, (this.classUtilities.get(className) || []).filter((candidate) => candidate !== rule));
806
+ }
807
+ syncClassReferences(classes) {
808
+ for (const { className, references } of classes) {
809
+ const rules = references.map(({ layer, key }) => this.getUtilityLayerByName(layer).get(key)).filter((rule) => rule instanceof HydratedGeneratedRule);
810
+ this.setClassRules(className, rules);
811
+ }
812
+ }
813
+ applyTransition(transition, classNames = []) {
814
+ for (const mutation of transition.mutations) {
815
+ if (mutation.target === "theme") {
816
+ this.setThemeResource(mutation.op === "insert" ? mutation.text : "");
817
+ continue;
818
+ }
819
+ if (mutation.target === "keyframes") {
820
+ if (mutation.op === "insert") this.keyframes.insert({
821
+ key: mutation.key,
822
+ name: mutation.key,
823
+ text: mutation.text
824
+ }, mutation.index);
825
+ else this.keyframes.delete(mutation.key, mutation.index);
826
+ continue;
827
+ }
828
+ const layer = this.getUtilityLayerByName(mutation.target);
829
+ if (mutation.op === "insert") {
830
+ if (!mutation.rule) throw new MasterCSSError({
831
+ code: "INTERNAL",
832
+ domain: "runtime",
833
+ message: `Missing generated rule contract for ${mutation.key}.`
834
+ });
835
+ const rule = new HydratedGeneratedRule(mutation.rule, layer);
836
+ if (layer.insert(rule, mutation.index) !== void 0) this.registerClassRule(rule);
837
+ } else {
838
+ const rule = layer.delete(mutation.key, mutation.index);
839
+ if (rule) this.unregisterLayerRule(rule);
840
+ }
841
+ }
842
+ const state = this.engine.executionState(classNames);
843
+ this.syncResourceSnapshot(state.resources);
844
+ this.syncClassReferences(state.classes);
845
+ }
846
+ adoptSnapshot(snapshot, preserveStyle = false) {
847
+ if (!preserveStyle) this.clearKeyframeRules();
848
+ this.resetHostRuleState();
849
+ if (!this.style) return;
850
+ if (!preserveStyle) this.style.textContent = snapshot.text;
851
+ const sheet = this.getStyleSheet();
852
+ if (!sheet) return;
853
+ const nativeLayers = /* @__PURE__ */ new Map();
854
+ for (const rule of sheet.cssRules) if (isLayerBlockRule(rule)) nativeLayers.set(rule.name, rule);
855
+ this.themeLayer.native = nativeLayers.get("theme") || null;
856
+ this.themeLayer.resourceText = snapshot.resources.themeText || "";
857
+ const layerNativeIndexes = /* @__PURE__ */ new Map();
858
+ for (const ir of snapshot.rules) {
859
+ const layer = this.getUtilityLayerByName(ir.layer);
860
+ layer.native ||= nativeLayers.get(ir.layer) || null;
861
+ const rule = new HydratedGeneratedRule(ir, layer);
862
+ const nativeIndex = layerNativeIndexes.get(ir.layer) || 0;
863
+ const nodes = rule.nodes;
864
+ if (nodes?.length) for (let index = 0; index < nodes.length; index++) nodes[index].native = layer.native?.cssRules.item(nativeIndex + index) || void 0;
865
+ else rule.native = layer.native?.cssRules.item(nativeIndex) || void 0;
866
+ layerNativeIndexes.set(ir.layer, nativeIndex + (nodes?.length || 1));
867
+ layer.adopt(rule);
868
+ this.registerClassRule(rule);
869
+ }
870
+ const claimed = /* @__PURE__ */ new Set();
871
+ for (const resource of snapshot.resources.keyframes) {
872
+ const native = this.keyframeHost.adopt(resource.id, claimed);
873
+ if (native) this.keyframes.adopt({
874
+ key: resource.id,
875
+ name: resource.name,
876
+ text: resource.text,
877
+ native,
878
+ nativeNodeCount: 1
879
+ });
880
+ else this.keyframes.insert({
881
+ key: resource.id,
882
+ name: resource.name,
883
+ text: resource.text
884
+ });
885
+ }
886
+ this.syncResourceSnapshot(snapshot.resources);
887
+ }
888
+ };
889
+ // src/mutation.ts
890
+ function countMutationDelta(deltaCounts, classCounts) {
891
+ const added = [];
892
+ const removed = [];
893
+ for (const [className, change] of deltaCounts) {
894
+ const current = classCounts.get(className) || 0;
895
+ const next = current + change;
896
+ if (next > 0) {
897
+ classCounts.set(className, next);
898
+ if (current === 0) added.push(className);
899
+ } else {
900
+ classCounts.delete(className);
901
+ removed.push(className);
902
+ }
903
+ }
904
+ return {
905
+ added,
906
+ removed
907
+ };
908
+ }
909
+ /** Counts class changes while the engine is deferred; returns newly connected classes. */
910
+ function applyDeferredMutationDelta(deltaCounts, classCounts) {
911
+ return countMutationDelta(deltaCounts, classCounts).added;
912
+ }
913
+ function applyRuntimeMutationDelta(records, deltaCounts, context) {
914
+ const { added, removed: removedClassNames } = countMutationDelta(deltaCounts, context.classCounts);
915
+ const warmClassNames = added.filter((className) => context.isWarm(className));
916
+ const queuedClassNames = added.filter((className) => !context.isWarm(className));
917
+ if (warmClassNames.length) context.ensure(warmClassNames);
918
+ if (queuedClassNames.length) context.queueAdded(queuedClassNames);
919
+ if (removedClassNames.length) {
920
+ context.cancelAdded(removedClassNames);
921
+ context.queueRemoved(removedClassNames);
922
+ }
923
+ {
924
+ const [root, host, snapshot] = context.debug();
925
+ debugRuntimeMutation(records, deltaCounts, root, host, snapshot);
926
+ }
927
+ }
928
+ // src/retention-config.ts
929
+ const RETAINED_CLASS_RULE_MIN_AGE_MS = 1e3;
930
+ const RETAINED_CLASS_RULE_IDLE_TIMEOUT_MS = 5e3;
931
+ // src/startup.ts
932
+ const MASTER_CSS_RUNTIME_STARTUP_TIMEOUT_MS = 3e3;
933
+ /** Races startup steps against one deadline; `subject` names what failed to start. */
934
+ function createStartupTimeout(view, timeoutMs, subject) {
935
+ let handle;
936
+ const expired = new Promise((_, reject) => {
937
+ handle = view.setTimeout(() => reject(new MasterCSSError({
938
+ code: "RUNTIME_STARTUP_TIMEOUT",
939
+ domain: "runtime",
940
+ message: `Master CSS ${subject} did not start within ${timeoutMs}ms.`
941
+ })), timeoutMs);
942
+ });
943
+ return {
944
+ race: (step) => Promise.race([step, expired]),
945
+ clear: () => view.clearTimeout(handle)
946
+ };
947
+ }
948
+ function toStartupDiagnostic(error) {
949
+ if (error instanceof MasterCSSError && error.diagnostics[0]) return error.diagnostics[0];
950
+ return Object.freeze({
951
+ version: MASTER_CSS_DIAGNOSTIC_VERSION,
952
+ code: "INTERNAL",
953
+ domain: "runtime",
954
+ severity: "error",
955
+ message: error instanceof Error ? error.message : String(error)
956
+ });
957
+ }
958
+ // src/core.ts
959
+ const MASTER_CSS_RUNTIME_STYLE_SELECTOR = `style#${MASTER_CSS_RUNTIME_STYLE_ID}`;
960
+ function programBytes(program) {
961
+ return ArrayBuffer.isView(program) ? new Uint8Array(program.buffer, program.byteOffset, program.byteLength) : new Uint8Array(program);
962
+ }
963
+ async function resolveProgram$1(program) {
964
+ return programBytes(typeof program === "function" ? await program() : program);
965
+ }
966
+ /** `@master/css` stays out of the entry chunk, so deferred pages never download it. */
967
+ async function loadEngine(program, emittedGlobals, binding) {
968
+ const { createEngine } = await import("@master/css");
969
+ const resolvedProgram = await program;
970
+ return {
971
+ engine: await createEngine({
972
+ program: resolvedProgram,
973
+ emittedGlobals,
974
+ binding
975
+ }),
976
+ program: resolvedProgram
977
+ };
978
+ }
979
+ function runtimeDisposedError() {
980
+ return new MasterCSSError({
981
+ code: "RUNTIME_DISPOSED",
982
+ domain: "runtime",
983
+ message: "The Master CSS runtime has been disposed."
984
+ });
985
+ }
986
+ var MasterCSSRuntime = class MasterCSSRuntime extends RuntimeHost {
987
+ static #instances = /* @__PURE__ */ new WeakMap();
988
+ static #starts = /* @__PURE__ */ new WeakMap();
989
+ classCounts = /* @__PURE__ */ new Map();
990
+ retainedClassNames = /* @__PURE__ */ new Set();
991
+ observer;
992
+ observing = false;
993
+ disposed = false;
994
+ globalFacade;
995
+ classTracker = new RuntimeClassTracker();
996
+ pendingAddedClassNames = /* @__PURE__ */ new Set();
997
+ pendingRemovedClassNames = /* @__PURE__ */ new Set();
998
+ retainedClassRules = /* @__PURE__ */ new Map();
999
+ pendingAdditionFrame;
1000
+ pendingRemovalFrame;
1001
+ pendingRemovalFlushFrame;
1002
+ retainedCleanupIdleHandle;
1003
+ retainedCleanupTimeoutHandle;
1004
+ engineState;
1005
+ engineStart;
1006
+ programSource;
1007
+ programRequest;
1008
+ /** The program the engine executes; refresh() without one re-executes it. */
1009
+ program;
1010
+ /** Engine calls made while it loads, replayed in order once it is installed or fails. */
1011
+ pendingEngineCalls = [];
1012
+ renderedClassNames;
1013
+ engineBinding;
1014
+ startupTimeoutMs;
1015
+ onDiagnostic;
1016
+ constructor(root, options, hydrationManifest, loaded) {
1017
+ super(root, options.emittedGlobals, hydrationManifest);
1018
+ this.programSource = options.program;
1019
+ this.renderedClassNames = getRenderedClassNames(hydrationManifest);
1020
+ this.engineBinding = options.binding || "auto";
1021
+ this.startupTimeoutMs = options.startupTimeoutMs ?? 3e3;
1022
+ this.onDiagnostic = options.onDiagnostic;
1023
+ if (loaded) {
1024
+ this.bindingEngine = loaded.engine;
1025
+ this.program = loaded.program;
1026
+ this.keyframeDefinitions = loaded.engine.keyframeDefinitions();
1027
+ this.engineState = "ready";
1028
+ } else {
1029
+ this.engineState = "deferred";
1030
+ if (options.enginePrefetch === "idle") this.startEngineWhenIdle();
1031
+ }
1032
+ }
1033
+ get binding() {
1034
+ return this.bindingEngine?.binding;
1035
+ }
1036
+ static async start(options) {
1037
+ const root = options.root || document;
1038
+ const current = MasterCSSRuntime.#instances.get(root);
1039
+ if (current) {
1040
+ current.registerEmittedGlobals(options.emittedGlobals);
1041
+ if (options.hydrationManifest !== void 0) current.setHydrationManifest(options.hydrationManifest);
1042
+ current.retryEngine();
1043
+ return current;
1044
+ }
1045
+ const pending = MasterCSSRuntime.#starts.get(root);
1046
+ if (pending) {
1047
+ if (options.emittedGlobals) pending.emittedGlobals.push(options.emittedGlobals);
1048
+ if (options.hydrationManifest !== void 0) pending.hydrationManifest = options.hydrationManifest;
1049
+ return await pending.promise;
1050
+ }
1051
+ let pendingStart;
1052
+ const startup = MasterCSSRuntime.startNew(root, options).then((runtime) => {
1053
+ try {
1054
+ for (const emittedGlobals of pendingStart.emittedGlobals) runtime.registerEmittedGlobals(emittedGlobals);
1055
+ if (pendingStart.hydrationManifest !== void 0) runtime.setHydrationManifest(pendingStart.hydrationManifest);
1056
+ return runtime;
1057
+ } catch (error) {
1058
+ runtime.dispose();
1059
+ throw error;
1060
+ }
1061
+ }).finally(() => MasterCSSRuntime.#starts.delete(root));
1062
+ pendingStart = {
1063
+ promise: startup,
1064
+ emittedGlobals: []
1065
+ };
1066
+ MasterCSSRuntime.#starts.set(root, pendingStart);
1067
+ return await startup;
1068
+ }
1069
+ static async startNew(root, options) {
1070
+ const { binding = "auto", startupTimeoutMs = MASTER_CSS_RUNTIME_STARTUP_TIMEOUT_MS, onDiagnostic } = options;
1071
+ const timeout = createStartupTimeout((isDocumentRoot(root) ? root : root.ownerDocument).defaultView || globalThis, startupTimeoutMs, "runtime");
1072
+ let abandoned = false;
1073
+ let ownedEngine;
1074
+ let startupRuntime;
1075
+ const startEngine = () => loadEngine(resolveProgram$1(options.program), options.emittedGlobals, binding).then((loaded) => {
1076
+ if (abandoned) loaded.engine.dispose();
1077
+ else ownedEngine = loaded.engine;
1078
+ return loaded;
1079
+ });
1080
+ const enginePromise = options.engine !== "eager" && Boolean(findElementById(root, MASTER_CSS_RUNTIME_STYLE_ID)) ? void 0 : startEngine();
1081
+ const hydrationPromise = resolveHydrationManifest$1(root, options.hydrationManifest);
1082
+ try {
1083
+ let loaded;
1084
+ let hydrationManifest;
1085
+ if (enginePromise) [loaded, hydrationManifest] = await timeout.race(Promise.all([enginePromise, hydrationPromise]));
1086
+ else {
1087
+ hydrationManifest = await timeout.race(hydrationPromise);
1088
+ if (!hydrationManifest?.classNames.length) loaded = await timeout.race(startEngine());
1089
+ }
1090
+ timeout.clear();
1091
+ startupRuntime = new MasterCSSRuntime(root, options, hydrationManifest, loaded);
1092
+ return startupRuntime.register();
1093
+ } catch (error) {
1094
+ abandoned = true;
1095
+ (startupRuntime || ownedEngine)?.dispose();
1096
+ timeout.clear();
1097
+ getRootHost(root).removeAttribute("hidden");
1098
+ onDiagnostic?.(toStartupDiagnostic(error));
1099
+ throw error;
1100
+ }
1101
+ }
1102
+ /** Starts the engine of a deferred progressive page, resolving once it executes rules. */
1103
+ ready() {
1104
+ if (this.disposed) return Promise.reject(runtimeDisposedError());
1105
+ return this.engineState === "ready" ? Promise.resolve(this) : this.startEngine();
1106
+ }
1107
+ startEngine() {
1108
+ this.engineStart ??= this.loadDeferredEngine();
1109
+ return this.engineStart;
1110
+ }
1111
+ async loadDeferredEngine() {
1112
+ this.engineState = "loading";
1113
+ const timeout = createStartupTimeout(this.getAnimationFrameWindow(), this.startupTimeoutMs, "engine");
1114
+ const loading = loadEngine(this.loadProgram(), this.emittedGlobals, this.engineBinding);
1115
+ try {
1116
+ const { engine, program } = await timeout.race(loading);
1117
+ if (this.disposed) throw runtimeDisposedError();
1118
+ this.installEngine(engine, program);
1119
+ return this;
1120
+ } catch (error) {
1121
+ if (!this.disposed) {
1122
+ this.engineState = "failed";
1123
+ this.programRequest = void 0;
1124
+ this.host.removeAttribute("hidden");
1125
+ this.onDiagnostic?.(toStartupDiagnostic(error));
1126
+ this.replayPendingEngineCalls();
1127
+ }
1128
+ loading.then(({ engine }) => {
1129
+ if (this.engineState === "ready" && this.bindingEngine === engine) return;
1130
+ if (this.bindingEngine === engine) this.bindingEngine = void 0;
1131
+ engine.dispose();
1132
+ }, () => {});
1133
+ throw error;
1134
+ } finally {
1135
+ timeout.clear();
1136
+ }
1137
+ }
1138
+ loadProgram() {
1139
+ this.programRequest ??= resolveProgram$1(this.programSource);
1140
+ return this.programRequest;
1141
+ }
1142
+ installEngine(engine, program) {
1143
+ this.bindingEngine = engine;
1144
+ this.program = program;
1145
+ this.keyframeDefinitions = engine.keyframeDefinitions();
1146
+ this.engineState = "ready";
1147
+ if (this.observing) {
1148
+ this.adoptConnectedClasses(new Set(this.classCounts.keys()));
1149
+ this.reconcileKeyframeRules();
1150
+ }
1151
+ this.replayPendingEngineCalls();
1152
+ }
1153
+ replayPendingEngineCalls() {
1154
+ for (const call of this.pendingEngineCalls.splice(0)) call();
1155
+ }
1156
+ startEngineWhenIdle() {
1157
+ const view = this.getCleanupWindow();
1158
+ const start = () => this.requestEngine();
1159
+ if (view.requestIdleCallback) view.requestIdleCallback(start);
1160
+ else view.setTimeout(start, 0);
1161
+ }
1162
+ /** Starts a deferred engine for a class pre-rendered CSS lacks; a failed one waits for a retry. */
1163
+ requestEngine() {
1164
+ if (this.engineState === "deferred" && !this.disposed) this.startEngine().catch(() => {});
1165
+ }
1166
+ retryEngine() {
1167
+ if (this.engineState !== "failed") return;
1168
+ this.engineStart = void 0;
1169
+ this.engineState = "deferred";
1170
+ this.requestEngine();
1171
+ }
1172
+ requireEngine() {
1173
+ if (this.engineState === "ready") return this.engine;
1174
+ this.requestEngine();
1175
+ throw new MasterCSSError({
1176
+ code: "RUNTIME_ENGINE_NOT_READY",
1177
+ domain: "runtime",
1178
+ message: "The Master CSS engine has not started. Await runtime.ready() before changing class rules."
1179
+ });
1180
+ }
1181
+ registerEmittedGlobals(emittedGlobals) {
1182
+ if (emittedGlobals && this.engineState === "loading") this.pendingEngineCalls.push(() => super.registerEmittedGlobals(emittedGlobals));
1183
+ else super.registerEmittedGlobals(emittedGlobals);
1184
+ }
1185
+ setHydrationManifest(hydrationManifest) {
1186
+ this.renderedClassNames = getRenderedClassNames(hydrationManifest);
1187
+ return super.setHydrationManifest(hydrationManifest);
1188
+ }
1189
+ register() {
1190
+ const registered = MasterCSSRuntime.#instances.get(this.root) === this;
1191
+ MasterCSSRuntime.#instances.set(this.root, this);
1192
+ if (isDocumentRoot(this.root)) this.root.defaultView.globalThis.masterCSSRuntime = this.getGlobalFacade();
1193
+ if (!registered && true) debugRuntimeCreated(this);
1194
+ return this;
1195
+ }
1196
+ unregister() {
1197
+ MasterCSSRuntime.#instances.delete(this.root);
1198
+ if (isDocumentRoot(this.root) && this.root.defaultView.globalThis.masterCSSRuntime === this.globalFacade) this.root.defaultView.globalThis.masterCSSRuntime = void 0;
1199
+ return this;
1200
+ }
1201
+ getGlobalFacade() {
1202
+ if (this.globalFacade) return this.globalFacade;
1203
+ let facade;
1204
+ const getBinding = () => this.binding;
1205
+ facade = Object.freeze({
1206
+ get binding() {
1207
+ return getBinding();
1208
+ },
1209
+ ready: async () => {
1210
+ await this.ready();
1211
+ return facade;
1212
+ },
1213
+ observe: () => {
1214
+ this.observe();
1215
+ return facade;
1216
+ },
1217
+ disconnect: () => {
1218
+ this.disconnect();
1219
+ return facade;
1220
+ },
1221
+ refresh: (program, emittedGlobals) => {
1222
+ this.refresh(program, emittedGlobals);
1223
+ return facade;
1224
+ },
1225
+ ensureClassRules: (classNames) => this.ensureClassRules(classNames),
1226
+ deleteClassRules: (classNames) => this.deleteClassRules(classNames),
1227
+ snapshot: () => this.snapshot(),
1228
+ dispose: () => this.dispose(),
1229
+ [Symbol.dispose]: () => this.dispose()
1230
+ });
1231
+ this.globalFacade = facade;
1232
+ return facade;
1233
+ }
1234
+ warnHydrationFallback(reason) {
1235
+ console.warn(`Master CSS progressive hydration requires a matching hydration manifest. ${reason} Rebuilding ${MASTER_CSS_RUNTIME_STYLE_SELECTOR} with the runtime.`);
1236
+ }
1237
+ useRuntimeStyle(connectedNames, reason) {
1238
+ if (reason) this.warnHydrationFallback(reason);
1239
+ this.style?.remove();
1240
+ this.style = null;
1241
+ this.progressive = false;
1242
+ this.createRuntimeStyle();
1243
+ this.adoptSnapshot(this.engine.snapshot());
1244
+ this.ensureClassRules([...connectedNames]);
1245
+ }
1246
+ detectRuntimeStyle() {
1247
+ const style = findElementById(this.root, MASTER_CSS_RUNTIME_STYLE_ID);
1248
+ if (style?.constructor.name === "HTMLStyleElement") {
1249
+ this.style = style;
1250
+ this.progressive = true;
1251
+ }
1252
+ }
1253
+ collectConnectedClasses() {
1254
+ return this.classTracker.collectConnected(this.root, this.classCounts);
1255
+ }
1256
+ failHydration(reason, ensuredClassNames = []) {
1257
+ this.hydrationFailureReason = reason;
1258
+ if (ensuredClassNames.length) this.engine.deleteClassRules(ensuredClassNames);
1259
+ this.resetHostRuleState();
1260
+ }
1261
+ matchesEngineSnapshotText(snapshot) {
1262
+ const sheet = this.getStyleSheet();
1263
+ if (!sheet) return false;
1264
+ const expectedStyle = this.getOwnerDocument().createElement("style");
1265
+ expectedStyle.media = "not all";
1266
+ expectedStyle.textContent = snapshot.text;
1267
+ this.container.append(expectedStyle);
1268
+ try {
1269
+ const expectedRules = expectedStyle.sheet?.cssRules;
1270
+ if (!expectedRules) return false;
1271
+ const checkedLayers = /* @__PURE__ */ new Set();
1272
+ for (const layer of expectedRules) {
1273
+ if (!isLayerBlockRule(layer) || layer.name === "theme" || checkedLayers.has(layer.name) || !snapshot.rules.some((rule) => rule.layer === layer.name)) continue;
1274
+ checkedLayers.add(layer.name);
1275
+ const nodeCount = snapshot.rules.filter((rule) => rule.layer === layer.name).reduce((count, rule) => count + (rule.nodes?.length || 1), 0);
1276
+ if (layer.cssRules.length !== nodeCount) return false;
1277
+ }
1278
+ const actualRules = [...sheet.cssRules];
1279
+ return actualRules.length === expectedRules.length && actualRules.every((rule, index) => rule.cssText === expectedRules[index].cssText);
1280
+ } finally {
1281
+ expectedStyle.remove();
1282
+ }
1283
+ }
1284
+ hydrate(nativeLayerRules) {
1285
+ this.hydrationFailureReason = void 0;
1286
+ const manifest = this.hydrationManifest;
1287
+ if (manifest?.version !== 5 || !Array.isArray(manifest.classNames)) return this.failHydration("Missing or invalid hydration manifest.");
1288
+ if (!manifest.classNames.length) return this.failHydration(`Hydration manifest has no rendered classes for ${MASTER_CSS_RUNTIME_STYLE_SELECTOR}.`);
1289
+ const classNames = [...manifest.classNames];
1290
+ this.engine.ensureClassRules(classNames);
1291
+ let snapshot = this.engine.snapshot();
1292
+ if (this.registerMissingEmittedGlobals(manifest.emittedGlobals)) snapshot = this.engine.snapshot();
1293
+ const resourceOrder = {
1294
+ variables: snapshot.resources.variables.map((resource) => resource.name),
1295
+ keyframes: snapshot.resources.keyframes.map((resource) => resource.id)
1296
+ };
1297
+ if (JSON.stringify(resourceOrder) !== JSON.stringify(manifest.resourceOrder)) return this.failHydration("Generated resources do not match the hydration manifest.", classNames);
1298
+ if (!this.matchesEngineSnapshotText(snapshot)) return this.failHydration(`${MASTER_CSS_RUNTIME_STYLE_SELECTOR} does not match the Rust engine snapshot.`, classNames);
1299
+ if (nativeLayerRules.length !== this.style?.sheet?.cssRules.length) return this.failHydration(`Cannot read ${MASTER_CSS_RUNTIME_STYLE_SELECTOR} CSS rules.`, classNames);
1300
+ this.adoptSnapshot(snapshot, true);
1301
+ const result = { allUtilities: this.getUtilityLayers().flatMap(({ rules }) => rules.filter((rule) => rule instanceof HydratedGeneratedRule)) };
1302
+ debugRuntimeHydrated(this, result);
1303
+ return result;
1304
+ }
1305
+ hydrateRuntimeStyle(connectedNames) {
1306
+ const hydrateResult = this.style?.sheet && this.hydrate(this.style.sheet.cssRules);
1307
+ if (!hydrateResult) {
1308
+ this.useRuntimeStyle(connectedNames, this.hydrationFailureReason || `Cannot read ${MASTER_CSS_RUNTIME_STYLE_SELECTOR} CSS rules.`);
1309
+ return;
1310
+ }
1311
+ const hydratedClassNames = new Set(hydrateResult.allUtilities.map(({ name }) => name));
1312
+ const missing = [...connectedNames].filter((className) => !hydratedClassNames.has(className));
1313
+ if (missing.length) this.ensureClassRules(missing);
1314
+ this.queueRemovedClassNames(hydratedClassNames);
1315
+ }
1316
+ renderRuntimeStyle(connectedNames) {
1317
+ this.createRuntimeStyle();
1318
+ this.adoptSnapshot(this.engine.snapshot());
1319
+ this.ensureClassRules([...connectedNames]);
1320
+ }
1321
+ adoptConnectedClasses(connectedNames) {
1322
+ if (this.progressive) this.hydrateRuntimeStyle(connectedNames);
1323
+ else this.renderRuntimeStyle(connectedNames);
1324
+ if (!this.progressive) this.host.removeAttribute("hidden");
1325
+ }
1326
+ getAnimationFrameWindow() {
1327
+ return this.getOwnerDocument().defaultView || globalThis;
1328
+ }
1329
+ cancelPendingRemovalFrames() {
1330
+ const view = this.getAnimationFrameWindow();
1331
+ if (this.pendingRemovalFrame !== void 0) view.cancelAnimationFrame(this.pendingRemovalFrame);
1332
+ if (this.pendingRemovalFlushFrame !== void 0) view.cancelAnimationFrame(this.pendingRemovalFlushFrame);
1333
+ this.pendingRemovalFrame = void 0;
1334
+ this.pendingRemovalFlushFrame = void 0;
1335
+ }
1336
+ cancelPendingAdditionFrame() {
1337
+ if (this.pendingAdditionFrame === void 0) return;
1338
+ this.getAnimationFrameWindow().cancelAnimationFrame(this.pendingAdditionFrame);
1339
+ this.pendingAdditionFrame = void 0;
1340
+ }
1341
+ clearPendingAddedClassNames() {
1342
+ this.pendingAddedClassNames.clear();
1343
+ this.cancelPendingAdditionFrame();
1344
+ }
1345
+ clearPendingRemovedClassNames() {
1346
+ this.pendingRemovedClassNames.clear();
1347
+ this.cancelPendingRemovalFrames();
1348
+ }
1349
+ getCleanupWindow() {
1350
+ return this.getAnimationFrameWindow();
1351
+ }
1352
+ cancelRetainedClassRuleCleanup() {
1353
+ const view = this.getCleanupWindow();
1354
+ if (this.retainedCleanupIdleHandle !== void 0) {
1355
+ view.cancelIdleCallback?.(this.retainedCleanupIdleHandle);
1356
+ this.retainedCleanupIdleHandle = void 0;
1357
+ }
1358
+ if (this.retainedCleanupTimeoutHandle !== void 0) {
1359
+ view.clearTimeout(this.retainedCleanupTimeoutHandle);
1360
+ this.retainedCleanupTimeoutHandle = void 0;
1361
+ }
1362
+ }
1363
+ clearRetainedClassRules() {
1364
+ this.retainedClassNames.clear();
1365
+ this.retainedClassRules.clear();
1366
+ this.cancelRetainedClassRuleCleanup();
1367
+ }
1368
+ cancelPendingRemovedClassNames(classNames) {
1369
+ for (const className of classNames) this.pendingRemovedClassNames.delete(className);
1370
+ if (!this.pendingRemovedClassNames.size) this.cancelPendingRemovalFrames();
1371
+ }
1372
+ cancelPendingAddedClassNames(classNames) {
1373
+ for (const className of classNames) this.pendingAddedClassNames.delete(className);
1374
+ if (!this.pendingAddedClassNames.size) this.cancelPendingAdditionFrame();
1375
+ }
1376
+ cancelRetainedClassNames(classNames) {
1377
+ for (const className of classNames) {
1378
+ this.retainedClassNames.delete(className);
1379
+ this.retainedClassRules.delete(className);
1380
+ }
1381
+ if (!this.retainedClassNames.size) this.cancelRetainedClassRuleCleanup();
1382
+ }
1383
+ schedulePendingRemovalFlush() {
1384
+ if (!this.pendingRemovedClassNames.size || this.pendingRemovalFrame !== void 0 || this.pendingRemovalFlushFrame !== void 0) return;
1385
+ const view = this.getAnimationFrameWindow();
1386
+ this.pendingRemovalFrame = view.requestAnimationFrame(() => {
1387
+ this.pendingRemovalFrame = void 0;
1388
+ this.pendingRemovalFlushFrame = view.requestAnimationFrame(() => {
1389
+ this.pendingRemovalFlushFrame = void 0;
1390
+ this.flushPendingRemovedClassNames();
1391
+ });
1392
+ });
1393
+ }
1394
+ queueRemovedClassNames(classNames) {
1395
+ for (const className of classNames) if (!this.classCounts.has(className)) this.pendingRemovedClassNames.add(className);
1396
+ this.schedulePendingRemovalFlush();
1397
+ }
1398
+ schedulePendingAdditionFlush() {
1399
+ if (!this.pendingAddedClassNames.size || this.pendingAdditionFrame !== void 0) return;
1400
+ this.pendingAdditionFrame = this.getAnimationFrameWindow().requestAnimationFrame(() => {
1401
+ this.pendingAdditionFrame = void 0;
1402
+ this.flushPendingAddedClassNames();
1403
+ });
1404
+ }
1405
+ queueAddedClassNames(classNames) {
1406
+ for (const className of classNames) if (this.classCounts.has(className)) this.pendingAddedClassNames.add(className);
1407
+ this.schedulePendingAdditionFlush();
1408
+ }
1409
+ estimateRetainedClassRule(className) {
1410
+ const rules = this.classUtilities.get(className);
1411
+ if (!rules?.length) return;
1412
+ let rawBytes = 0;
1413
+ let ruleCount = 0;
1414
+ for (const rule of rules) {
1415
+ const texts = getGeneratedRuleNodeTexts(rule);
1416
+ rawBytes += texts.reduce((length, text) => length + text.length, 0);
1417
+ ruleCount += texts.length;
1418
+ }
1419
+ return {
1420
+ retainedAt: Date.now(),
1421
+ rawBytes,
1422
+ ruleCount
1423
+ };
1424
+ }
1425
+ getRetainedClassRuleRawBytes() {
1426
+ let rawBytes = 0;
1427
+ for (const retainedRule of this.retainedClassRules.values()) rawBytes += retainedRule.rawBytes;
1428
+ return rawBytes;
1429
+ }
1430
+ exceedsRetainedClassRuleHardLimits() {
1431
+ return this.retainedClassNames.size > 512 || this.getRetainedClassRuleRawBytes() > 262144;
1432
+ }
1433
+ scheduleRetainedClassRuleCleanup() {
1434
+ if (!this.retainedClassNames.size || this.retainedCleanupIdleHandle !== void 0 || this.retainedCleanupTimeoutHandle !== void 0) return;
1435
+ const view = this.getCleanupWindow();
1436
+ const timeout = this.exceedsRetainedClassRuleHardLimits() ? 0 : RETAINED_CLASS_RULE_IDLE_TIMEOUT_MS;
1437
+ const cleanup = () => {
1438
+ this.retainedCleanupIdleHandle = void 0;
1439
+ this.retainedCleanupTimeoutHandle = void 0;
1440
+ this.cleanupRetainedClassRules();
1441
+ };
1442
+ if (view.requestIdleCallback) this.retainedCleanupIdleHandle = view.requestIdleCallback(cleanup, { timeout });
1443
+ else this.retainedCleanupTimeoutHandle = view.setTimeout(cleanup, timeout);
1444
+ }
1445
+ retainRemovedClassRules(classNames) {
1446
+ const release = [];
1447
+ for (const className of classNames) {
1448
+ if (this.classCounts.has(className)) continue;
1449
+ if (this.classUtilities.get(className)?.some(({ ir }) => ir.retainAllKeyframes || ir.keyframeNames?.length)) {
1450
+ release.push(className);
1451
+ continue;
1452
+ }
1453
+ const retainedRule = this.retainedClassRules.get(className) || this.estimateRetainedClassRule(className);
1454
+ if (!retainedRule) continue;
1455
+ this.retainedClassNames.add(className);
1456
+ this.retainedClassRules.set(className, retainedRule);
1457
+ }
1458
+ if (release.length) this.deleteClassRules(release);
1459
+ this.scheduleRetainedClassRuleCleanup();
1460
+ }
1461
+ getRetainedClassRuleCleanupCandidates(force = false) {
1462
+ const now = Date.now();
1463
+ const hardLimitExceeded = this.exceedsRetainedClassRuleHardLimits();
1464
+ const entries = [];
1465
+ for (const className of this.retainedClassNames) {
1466
+ if (this.classCounts.has(className)) {
1467
+ this.retainedClassNames.delete(className);
1468
+ this.retainedClassRules.delete(className);
1469
+ continue;
1470
+ }
1471
+ const retainedRule = this.retainedClassRules.get(className);
1472
+ if (!retainedRule) continue;
1473
+ const oldEnough = now - retainedRule.retainedAt >= RETAINED_CLASS_RULE_MIN_AGE_MS;
1474
+ if (force || hardLimitExceeded || oldEnough && this.retainedClassNames.size > 128) entries.push([className, retainedRule]);
1475
+ }
1476
+ entries.sort(([, left], [, right]) => left.retainedAt - right.retainedAt);
1477
+ const cleanupCount = hardLimitExceeded ? Math.max(64, this.retainedClassNames.size - 128) : 64;
1478
+ return entries.slice(0, force ? entries.length : cleanupCount).map(([className]) => className);
1479
+ }
1480
+ removeRetainedClassRules(classNames) {
1481
+ const removedClassNames = [];
1482
+ for (const className of classNames) {
1483
+ if (!this.retainedClassNames.has(className)) continue;
1484
+ this.retainedClassNames.delete(className);
1485
+ this.retainedClassRules.delete(className);
1486
+ if (!this.classCounts.has(className)) removedClassNames.push(className);
1487
+ }
1488
+ if (removedClassNames.length) this.deleteClassRules(removedClassNames);
1489
+ return removedClassNames.length;
1490
+ }
1491
+ cleanupRetainedClassRules(force = false) {
1492
+ const removedCount = this.removeRetainedClassRules(this.getRetainedClassRuleCleanupCandidates(force));
1493
+ if (this.retainedClassNames.size && (force || this.retainedClassNames.size > 128 || this.exceedsRetainedClassRuleHardLimits())) this.scheduleRetainedClassRuleCleanup();
1494
+ return removedCount;
1495
+ }
1496
+ flushPendingRemovedClassNames() {
1497
+ const classNames = [...this.pendingRemovedClassNames].filter((className) => !this.classCounts.has(className));
1498
+ this.pendingRemovedClassNames.clear();
1499
+ if (classNames.length) this.retainRemovedClassRules(classNames);
1500
+ }
1501
+ flushPendingAddedClassNames() {
1502
+ const classNames = [...this.pendingAddedClassNames].filter((className) => this.classCounts.has(className));
1503
+ this.pendingAddedClassNames.clear();
1504
+ if (classNames.length) this.ensureClassRules(classNames);
1505
+ }
1506
+ handleMutationRecords(records) {
1507
+ const deltaCounts = this.classTracker.collectMutations(records, this.root);
1508
+ if (this.engineState !== "ready") {
1509
+ if (applyDeferredMutationDelta(deltaCounts, this.classCounts).some((className) => !this.renderedClassNames.has(className))) this.requestEngine();
1510
+ return;
1511
+ }
1512
+ applyRuntimeMutationDelta(records, deltaCounts, {
1513
+ classCounts: this.classCounts,
1514
+ isWarm: (className) => this.classUtilities.has(className) || this.retainedClassNames.has(className),
1515
+ ensure: (classNames) => this.ensureClassRules(classNames),
1516
+ queueAdded: (classNames) => this.queueAddedClassNames(classNames),
1517
+ queueRemoved: (classNames) => this.queueRemovedClassNames(classNames),
1518
+ cancelAdded: (classNames) => this.cancelPendingAddedClassNames(classNames),
1519
+ debug: () => [
1520
+ this.root,
1521
+ this.host,
1522
+ this.snapshot()
1523
+ ]
1524
+ });
1525
+ }
1526
+ ensureClassRules(classNames) {
1527
+ this.cancelPendingAddedClassNames(classNames);
1528
+ this.cancelPendingRemovedClassNames(classNames);
1529
+ const engine = this.requireEngine();
1530
+ this.cancelRetainedClassNames(classNames);
1531
+ const transition = engine.ensureClassRules(classNames);
1532
+ this.applyTransition(transition, classNames);
1533
+ return transition;
1534
+ }
1535
+ deleteClassRules(classNames) {
1536
+ this.cancelPendingAddedClassNames(classNames);
1537
+ this.cancelPendingRemovedClassNames(classNames);
1538
+ const engine = this.requireEngine();
1539
+ this.cancelRetainedClassNames(classNames);
1540
+ const transition = engine.deleteClassRules(classNames);
1541
+ this.applyTransition(transition, classNames);
1542
+ return transition;
1543
+ }
1544
+ startMutationObserver() {
1545
+ this.observer = new MutationObserver((records) => this.handleMutationRecords(records));
1546
+ this.observer.observe(this.root, {
1547
+ childList: true,
1548
+ attributes: true,
1549
+ attributeFilter: ["class"],
1550
+ subtree: true
1551
+ });
1552
+ }
1553
+ observe() {
1554
+ if (this.observing) return this;
1555
+ this.detectRuntimeStyle();
1556
+ const connectedNames = this.collectConnectedClasses();
1557
+ if (this.engineState === "ready") this.adoptConnectedClasses(connectedNames);
1558
+ else if (!this.progressive || [...connectedNames].some((className) => !this.renderedClassNames.has(className))) this.requestEngine();
1559
+ this.startMutationObserver();
1560
+ this.observing = true;
1561
+ debugRuntimeObserved(this);
1562
+ return this;
1563
+ }
1564
+ disconnect() {
1565
+ this.clearPendingAddedClassNames();
1566
+ this.clearPendingRemovedClassNames();
1567
+ this.clearRetainedClassRules();
1568
+ if (!this.observing) return this;
1569
+ this.observer?.disconnect();
1570
+ this.observer = void 0;
1571
+ this.observing = false;
1572
+ const activeClassNames = [...this.classUtilities.keys()];
1573
+ if (activeClassNames.length) this.bindingEngine?.deleteClassRules(activeClassNames);
1574
+ this.classCounts.clear();
1575
+ this.classTracker.reset();
1576
+ this.clearKeyframeRules();
1577
+ this.resetHostRuleState();
1578
+ if (!this.progressive) {
1579
+ this.style?.remove();
1580
+ this.style = null;
1581
+ }
1582
+ debugRuntimeDisconnected(this);
1583
+ return this;
1584
+ }
1585
+ refresh(program, emittedGlobals) {
1586
+ if (this.engineState === "loading") {
1587
+ this.pendingEngineCalls.push(() => this.refresh(program, emittedGlobals));
1588
+ return this;
1589
+ }
1590
+ if (this.engineState !== "ready") {
1591
+ if (program) {
1592
+ this.programSource = program;
1593
+ this.programRequest = void 0;
1594
+ }
1595
+ if (emittedGlobals) this.adoptEmittedGlobals(emittedGlobals);
1596
+ this.retryEngine();
1597
+ this.requestEngine();
1598
+ return this;
1599
+ }
1600
+ const next = program ? programBytes(program) : this.program;
1601
+ const releasedClassNames = [.../* @__PURE__ */ new Set([...this.pendingRemovedClassNames, ...this.retainedClassNames])].filter((className) => !this.classCounts.has(className));
1602
+ if (releasedClassNames.length) this.deleteClassRules(releasedClassNames);
1603
+ const transition = this.engine.refresh(next, emittedGlobals);
1604
+ if (emittedGlobals) this.adoptEmittedGlobals(emittedGlobals);
1605
+ this.clearPendingAddedClassNames();
1606
+ this.clearPendingRemovedClassNames();
1607
+ this.clearRetainedClassRules();
1608
+ this.program = next;
1609
+ this.keyframeDefinitions = this.engine.keyframeDefinitions();
1610
+ this.clearClassReferences();
1611
+ this.applyTransition(transition);
1612
+ this.reconcileKeyframeRules();
1613
+ this.ensureClassRules([...this.classCounts.keys()]);
1614
+ debugRuntimeRefreshed(this, next);
1615
+ return this;
1616
+ }
1617
+ /** Rules come from the engine; until it starts, classes report usage only. */
1618
+ getClassRuleSnapshots() {
1619
+ const ruleSnapshots = /* @__PURE__ */ new Map();
1620
+ for (const [className, rules] of this.classUtilities) ruleSnapshots.set(className, rules.map((rule) => Object.freeze({
1621
+ key: rule.key,
1622
+ layer: rule.layer.name,
1623
+ text: rule.text
1624
+ })));
1625
+ return ruleSnapshots;
1626
+ }
1627
+ snapshot() {
1628
+ const usageCounts = Object.freeze(Object.fromEntries(this.classCounts));
1629
+ const ruleSnapshots = this.getClassRuleSnapshots();
1630
+ const classNames = /* @__PURE__ */ new Set([
1631
+ ...ruleSnapshots.keys(),
1632
+ ...this.classCounts.keys(),
1633
+ ...this.retainedClassNames
1634
+ ]);
1635
+ const classRules = Object.create(null);
1636
+ for (const className of [...classNames].sort()) classRules[className] = Object.freeze({
1637
+ usageCount: this.classCounts.get(className) || 0,
1638
+ retained: this.retainedClassNames.has(className),
1639
+ rules: Object.freeze(ruleSnapshots.get(className) || [])
1640
+ });
1641
+ const layers = [...LAYER_ORDER.map((name) => {
1642
+ const layer = this.getLayerByName(name);
1643
+ return Object.freeze({
1644
+ name,
1645
+ cssText: layer.text,
1646
+ ruleCount: layer.rules.length
1647
+ });
1648
+ })];
1649
+ return Object.freeze({
1650
+ binding: this.binding,
1651
+ engine: this.engineState,
1652
+ cssText: this.engineState === "ready" ? this.engine.snapshot().text : this.style?.textContent || "",
1653
+ observing: this.observing,
1654
+ classRules: Object.freeze(classRules),
1655
+ usageCounts,
1656
+ layers: Object.freeze(layers),
1657
+ hydration: Object.freeze({
1658
+ state: this.progressive ? "progressive" : this.style ? "runtime" : "none",
1659
+ manifestLoaded: this.hydrationManifest !== void 0,
1660
+ ...this.hydrationFailureReason ? { failureReason: this.hydrationFailureReason } : {}
1661
+ })
1662
+ });
1663
+ }
1664
+ dispose() {
1665
+ if (this.disposed) return;
1666
+ this.disconnect();
1667
+ this.bindingEngine?.dispose();
1668
+ this.unregister();
1669
+ this.disposed = true;
1670
+ debugRuntimeDestroyed(this);
1671
+ }
1672
+ [Symbol.dispose]() {
1673
+ this.dispose();
1674
+ }
1675
+ };
1676
+ registerGlobal(MasterCSSRuntime);
1677
+ // src/css-runtime.ts
1678
+ function resolveProgram(host, program) {
1679
+ return typeof program === "function" ? async () => await program(host) : program;
1680
+ }
1681
+ function resolveRoot(host, root) {
1682
+ return typeof root === "function" ? root(host) : root || host.shadowRoot;
1683
+ }
1684
+ function resolveEmittedGlobals(host, emittedGlobals) {
1685
+ return typeof emittedGlobals === "function" ? emittedGlobals(host) : emittedGlobals;
1686
+ }
1687
+ function resolveHydrationManifest(host, hydrationManifest) {
1688
+ return typeof hydrationManifest === "function" ? hydrationManifest(host) : hydrationManifest;
1689
+ }
1690
+ function withMasterCSSRuntime(options) {
1691
+ return function(target) {
1692
+ const connectedCallback = target.prototype.connectedCallback;
1693
+ const disconnectedCallback = target.prototype.disconnectedCallback;
1694
+ return class extends target {
1695
+ masterCSSRuntime;
1696
+ connectedCallback() {
1697
+ connectedCallback?.call(this);
1698
+ const root = resolveRoot(this, options.root);
1699
+ if (!root) throw new Error("withMasterCSSRuntime() requires a shadow root. Provide options.root or create a shadow root before connectedCallback() finishes.");
1700
+ MasterCSSRuntime.start({
1701
+ program: resolveProgram(this, options.program),
1702
+ root,
1703
+ emittedGlobals: resolveEmittedGlobals(this, options.emittedGlobals),
1704
+ hydrationManifest: resolveHydrationManifest(this, options.hydrationManifest),
1705
+ onDiagnostic: (diagnostic) => console.error(diagnostic)
1706
+ }).then((runtime) => {
1707
+ if (!this.isConnected) {
1708
+ runtime.dispose();
1709
+ return;
1710
+ }
1711
+ this.masterCSSRuntime = runtime;
1712
+ runtime.observe();
1713
+ }).catch(() => {});
1714
+ }
1715
+ disconnectedCallback() {
1716
+ disconnectedCallback?.call(this);
1717
+ this.masterCSSRuntime?.dispose();
1718
+ this.masterCSSRuntime = void 0;
1719
+ }
1720
+ };
1721
+ };
1722
+ }
1723
+ export { MasterCSSRuntime, withMasterCSSRuntime };